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
path: root/source
diff options
context:
space:
mode:
Diffstat (limited to 'source')
-rw-r--r--source/blender/blenfont/BLF_api.h21
-rw-r--r--source/blender/blenfont/intern/blf.c40
-rw-r--r--source/blender/blenfont/intern/blf_font.c114
-rw-r--r--source/blender/blenfont/intern/blf_glyph.c78
-rw-r--r--source/blender/blenfont/intern/blf_internal.h14
-rw-r--r--source/blender/blenfont/intern/blf_internal_types.h16
-rw-r--r--source/blender/blenfont/intern/blf_thumbs.c4
-rw-r--r--source/blender/blenfont/intern/blf_util.c4
-rw-r--r--source/blender/blenkernel/BKE_action.h4
-rw-r--r--source/blender/blenkernel/BKE_addon.h2
-rw-r--r--source/blender/blenkernel/BKE_anim_data.h98
-rw-r--r--source/blender/blenkernel/BKE_anim_path.h51
-rw-r--r--source/blender/blenkernel/BKE_anim_visualization.h56
-rw-r--r--source/blender/blenkernel/BKE_animsys.h60
-rw-r--r--source/blender/blenkernel/BKE_armature.h5
-rw-r--r--source/blender/blenkernel/BKE_blender.h6
-rw-r--r--source/blender/blenkernel/BKE_blender_version.h40
-rw-r--r--source/blender/blenkernel/BKE_brush.h16
-rw-r--r--source/blender/blenkernel/BKE_bvhutils.h84
-rw-r--r--source/blender/blenkernel/BKE_camera.h2
-rw-r--r--source/blender/blenkernel/BKE_cdderivedmesh.h2
-rw-r--r--source/blender/blenkernel/BKE_collection.h4
-rw-r--r--source/blender/blenkernel/BKE_colorband.h2
-rw-r--r--source/blender/blenkernel/BKE_context.h5
-rw-r--r--source/blender/blenkernel/BKE_curve.h14
-rw-r--r--source/blender/blenkernel/BKE_customdata.h10
-rw-r--r--source/blender/blenkernel/BKE_data_transfer.h6
-rw-r--r--source/blender/blenkernel/BKE_duplilist.h (renamed from source/blender/blenkernel/BKE_anim.h)37
-rw-r--r--source/blender/blenkernel/BKE_dynamicpaint.h4
-rw-r--r--source/blender/blenkernel/BKE_editmesh_cache.h5
-rw-r--r--source/blender/blenkernel/BKE_fcurve.h139
-rw-r--r--source/blender/blenkernel/BKE_fcurve_driver.h106
-rw-r--r--source/blender/blenkernel/BKE_fluid.h4
-rw-r--r--source/blender/blenkernel/BKE_gpencil.h22
-rw-r--r--source/blender/blenkernel/BKE_gpencil_curve.h47
-rw-r--r--source/blender/blenkernel/BKE_gpencil_geom.h8
-rw-r--r--source/blender/blenkernel/BKE_gpencil_modifier.h28
-rw-r--r--source/blender/blenkernel/BKE_idprop.h11
-rw-r--r--source/blender/blenkernel/BKE_idtype.h12
-rw-r--r--source/blender/blenkernel/BKE_image.h6
-rw-r--r--source/blender/blenkernel/BKE_keyconfig.h2
-rw-r--r--source/blender/blenkernel/BKE_layer.h1
-rw-r--r--source/blender/blenkernel/BKE_lib_id.h6
-rw-r--r--source/blender/blenkernel/BKE_lib_override.h22
-rw-r--r--source/blender/blenkernel/BKE_lib_query.h44
-rw-r--r--source/blender/blenkernel/BKE_lib_remap.h4
-rw-r--r--source/blender/blenkernel/BKE_library.h4
-rw-r--r--source/blender/blenkernel/BKE_light.h8
-rw-r--r--source/blender/blenkernel/BKE_main.h15
-rw-r--r--source/blender/blenkernel/BKE_mask.h6
-rw-r--r--source/blender/blenkernel/BKE_material.h1
-rw-r--r--source/blender/blenkernel/BKE_mesh.h23
-rw-r--r--source/blender/blenkernel/BKE_modifier.h211
-rw-r--r--source/blender/blenkernel/BKE_multires.h25
-rw-r--r--source/blender/blenkernel/BKE_nla.h3
-rw-r--r--source/blender/blenkernel/BKE_node.h42
-rw-r--r--source/blender/blenkernel/BKE_object.h11
-rw-r--r--source/blender/blenkernel/BKE_paint.h41
-rw-r--r--source/blender/blenkernel/BKE_particle.h4
-rw-r--r--source/blender/blenkernel/BKE_pbvh.h138
-rw-r--r--source/blender/blenkernel/BKE_pointcache.h2
-rw-r--r--source/blender/blenkernel/BKE_report.h8
-rw-r--r--source/blender/blenkernel/BKE_rigidbody.h12
-rw-r--r--source/blender/blenkernel/BKE_scene.h1
-rw-r--r--source/blender/blenkernel/BKE_screen.h113
-rw-r--r--source/blender/blenkernel/BKE_sequencer.h33
-rw-r--r--source/blender/blenkernel/BKE_sequencer_offscreen.h2
-rw-r--r--source/blender/blenkernel/BKE_shader_fx.h22
-rw-r--r--source/blender/blenkernel/BKE_simulation.h38
-rw-r--r--source/blender/blenkernel/BKE_sound.h10
-rw-r--r--source/blender/blenkernel/BKE_subdiv.h8
-rw-r--r--source/blender/blenkernel/BKE_subdiv_ccg.h13
-rw-r--r--source/blender/blenkernel/BKE_subdiv_deform.h4
-rw-r--r--source/blender/blenkernel/BKE_subdiv_eval.h9
-rw-r--r--source/blender/blenkernel/BKE_subdiv_foreach.h4
-rw-r--r--source/blender/blenkernel/BKE_subsurf.h9
-rw-r--r--source/blender/blenkernel/BKE_text_suggestions.h4
-rw-r--r--source/blender/blenkernel/BKE_texture.h5
-rw-r--r--source/blender/blenkernel/BKE_tracking.h16
-rw-r--r--source/blender/blenkernel/BKE_undo_system.h2
-rw-r--r--source/blender/blenkernel/BKE_volume.h1
-rw-r--r--source/blender/blenkernel/BKE_workspace.h10
-rw-r--r--source/blender/blenkernel/CMakeLists.txt33
-rw-r--r--source/blender/blenkernel/intern/CCGSubSurf.c80
-rw-r--r--source/blender/blenkernel/intern/CCGSubSurf.h53
-rw-r--r--source/blender/blenkernel/intern/CCGSubSurf_intern.h65
-rw-r--r--source/blender/blenkernel/intern/CCGSubSurf_opensubdiv.c970
-rw-r--r--source/blender/blenkernel/intern/CCGSubSurf_opensubdiv_converter.c777
-rw-r--r--source/blender/blenkernel/intern/DerivedMesh.c134
-rw-r--r--source/blender/blenkernel/intern/action.c26
-rw-r--r--source/blender/blenkernel/intern/anim_data.c1462
-rw-r--r--source/blender/blenkernel/intern/anim_path.c (renamed from source/blender/blenkernel/intern/anim.c)226
-rw-r--r--source/blender/blenkernel/intern/anim_sys.c1419
-rw-r--r--source/blender/blenkernel/intern/anim_visualization.c228
-rw-r--r--source/blender/blenkernel/intern/appdir.c14
-rw-r--r--source/blender/blenkernel/intern/armature.c59
-rw-r--r--source/blender/blenkernel/intern/armature_update.c2
-rw-r--r--source/blender/blenkernel/intern/blender.c52
-rw-r--r--source/blender/blenkernel/intern/blender_undo.c3
-rw-r--r--source/blender/blenkernel/intern/blender_user_menu.c2
-rw-r--r--source/blender/blenkernel/intern/blendfile.c35
-rw-r--r--source/blender/blenkernel/intern/boids.c2
-rw-r--r--source/blender/blenkernel/intern/bpath.c8
-rw-r--r--source/blender/blenkernel/intern/brush.c374
-rw-r--r--source/blender/blenkernel/intern/bvhutils.c451
-rw-r--r--source/blender/blenkernel/intern/cachefile.c2
-rw-r--r--source/blender/blenkernel/intern/camera.c56
-rw-r--r--source/blender/blenkernel/intern/cdderivedmesh.c2
-rw-r--r--source/blender/blenkernel/intern/cloth.c16
-rw-r--r--source/blender/blenkernel/intern/collection.c103
-rw-r--r--source/blender/blenkernel/intern/collision.c14
-rw-r--r--source/blender/blenkernel/intern/colortools.c70
-rw-r--r--source/blender/blenkernel/intern/constraint.c537
-rw-r--r--source/blender/blenkernel/intern/context.c130
-rw-r--r--source/blender/blenkernel/intern/crazyspace.c36
-rw-r--r--source/blender/blenkernel/intern/curve.c106
-rw-r--r--source/blender/blenkernel/intern/customdata.c179
-rw-r--r--source/blender/blenkernel/intern/displist.c78
-rw-r--r--source/blender/blenkernel/intern/displist_tangent.c2
-rw-r--r--source/blender/blenkernel/intern/dynamicpaint.c53
-rw-r--r--source/blender/blenkernel/intern/editmesh.c7
-rw-r--r--source/blender/blenkernel/intern/editmesh_cache.c44
-rw-r--r--source/blender/blenkernel/intern/editmesh_tangent.c10
-rw-r--r--source/blender/blenkernel/intern/effect.c16
-rw-r--r--source/blender/blenkernel/intern/fcurve.c2092
-rw-r--r--source/blender/blenkernel/intern/fcurve_driver.c1294
-rw-r--r--source/blender/blenkernel/intern/fluid.c994
-rw-r--r--source/blender/blenkernel/intern/fmodifier.c2
-rw-r--r--source/blender/blenkernel/intern/font.c9
-rw-r--r--source/blender/blenkernel/intern/gpencil.c72
-rw-r--r--source/blender/blenkernel/intern/gpencil_curve.c450
-rw-r--r--source/blender/blenkernel/intern/gpencil_geom.c406
-rw-r--r--source/blender/blenkernel/intern/gpencil_modifier.c47
-rw-r--r--source/blender/blenkernel/intern/hair.c202
-rw-r--r--source/blender/blenkernel/intern/idprop.c43
-rw-r--r--source/blender/blenkernel/intern/idprop_utils.c3
-rw-r--r--source/blender/blenkernel/intern/idtype.c21
-rw-r--r--source/blender/blenkernel/intern/image.c40
-rw-r--r--source/blender/blenkernel/intern/image_save.c47
-rw-r--r--source/blender/blenkernel/intern/ipo.c10
-rw-r--r--source/blender/blenkernel/intern/key.c11
-rw-r--r--source/blender/blenkernel/intern/keyconfig.c2
-rw-r--r--source/blender/blenkernel/intern/lattice.c17
-rw-r--r--source/blender/blenkernel/intern/layer.c209
-rw-r--r--source/blender/blenkernel/intern/lib_id.c162
-rw-r--r--source/blender/blenkernel/intern/lib_id_delete.c66
-rw-r--r--source/blender/blenkernel/intern/lib_override.c154
-rw-r--r--source/blender/blenkernel/intern/lib_query.c1191
-rw-r--r--source/blender/blenkernel/intern/lib_remap.c2
-rw-r--r--source/blender/blenkernel/intern/library.c8
-rw-r--r--source/blender/blenkernel/intern/light.c108
-rw-r--r--source/blender/blenkernel/intern/lightprobe.c67
-rw-r--r--source/blender/blenkernel/intern/linestyle.c49
-rw-r--r--source/blender/blenkernel/intern/main.c3
-rw-r--r--source/blender/blenkernel/intern/mask.c22
-rw-r--r--source/blender/blenkernel/intern/material.c37
-rw-r--r--source/blender/blenkernel/intern/mball.c34
-rw-r--r--source/blender/blenkernel/intern/mball_tessellate.c11
-rw-r--r--source/blender/blenkernel/intern/mesh.c41
-rw-r--r--source/blender/blenkernel/intern/mesh_convert.c20
-rw-r--r--source/blender/blenkernel/intern/mesh_evaluate.c32
-rw-r--r--source/blender/blenkernel/intern/mesh_iterators.c272
-rw-r--r--source/blender/blenkernel/intern/mesh_mirror.c20
-rw-r--r--source/blender/blenkernel/intern/mesh_remap.c2
-rw-r--r--source/blender/blenkernel/intern/mesh_runtime.c6
-rw-r--r--source/blender/blenkernel/intern/mesh_tangent.c11
-rw-r--r--source/blender/blenkernel/intern/mesh_validate.c11
-rw-r--r--source/blender/blenkernel/intern/mesh_wrapper.c166
-rw-r--r--source/blender/blenkernel/intern/modifier.c324
-rw-r--r--source/blender/blenkernel/intern/movieclip.c65
-rw-r--r--source/blender/blenkernel/intern/multires.c51
-rw-r--r--source/blender/blenkernel/intern/multires_reshape.c92
-rw-r--r--source/blender/blenkernel/intern/multires_reshape.h42
-rw-r--r--source/blender/blenkernel/intern/multires_reshape_apply_base.c11
-rw-r--r--source/blender/blenkernel/intern/multires_reshape_ccg.c2
-rw-r--r--source/blender/blenkernel/intern/multires_reshape_smooth.c434
-rw-r--r--source/blender/blenkernel/intern/multires_reshape_subdivide.c106
-rw-r--r--source/blender/blenkernel/intern/multires_reshape_util.c115
-rw-r--r--source/blender/blenkernel/intern/multires_reshape_vertcos.c5
-rw-r--r--source/blender/blenkernel/intern/multires_subdiv.c2
-rw-r--r--source/blender/blenkernel/intern/multires_unsubdivide.c1297
-rw-r--r--source/blender/blenkernel/intern/multires_unsubdivide.h94
-rw-r--r--source/blender/blenkernel/intern/nla.c28
-rw-r--r--source/blender/blenkernel/intern/node.c255
-rw-r--r--source/blender/blenkernel/intern/object.c376
-rw-r--r--source/blender/blenkernel/intern/object_deform.c2
-rw-r--r--source/blender/blenkernel/intern/object_dupli.c3
-rw-r--r--source/blender/blenkernel/intern/object_update.c5
-rw-r--r--source/blender/blenkernel/intern/ocean.c67
-rw-r--r--source/blender/blenkernel/intern/paint.c112
-rw-r--r--source/blender/blenkernel/intern/paint_toolslots.c43
-rw-r--r--source/blender/blenkernel/intern/particle.c103
-rw-r--r--source/blender/blenkernel/intern/particle_distribute.c16
-rw-r--r--source/blender/blenkernel/intern/particle_system.c29
-rw-r--r--source/blender/blenkernel/intern/pbvh.c913
-rw-r--r--source/blender/blenkernel/intern/pbvh_bmesh.c437
-rw-r--r--source/blender/blenkernel/intern/pbvh_intern.h6
-rw-r--r--source/blender/blenkernel/intern/pointcache.c13
-rw-r--r--source/blender/blenkernel/intern/pointcloud.c150
-rw-r--r--source/blender/blenkernel/intern/rigidbody.c6
-rw-r--r--source/blender/blenkernel/intern/scene.c240
-rw-r--r--source/blender/blenkernel/intern/screen.c401
-rw-r--r--source/blender/blenkernel/intern/seqcache.c40
-rw-r--r--source/blender/blenkernel/intern/seqeffects.c95
-rw-r--r--source/blender/blenkernel/intern/seqprefetch.c171
-rw-r--r--source/blender/blenkernel/intern/sequencer.c419
-rw-r--r--source/blender/blenkernel/intern/shader_fx.c34
-rw-r--r--source/blender/blenkernel/intern/shrinkwrap.c2
-rw-r--r--source/blender/blenkernel/intern/simulation.cc132
-rw-r--r--source/blender/blenkernel/intern/softbody.c6
-rw-r--r--source/blender/blenkernel/intern/sound.c29
-rw-r--r--source/blender/blenkernel/intern/speaker.c10
-rw-r--r--source/blender/blenkernel/intern/studiolight.c8
-rw-r--r--source/blender/blenkernel/intern/subdiv.c12
-rw-r--r--source/blender/blenkernel/intern/subdiv_ccg.c95
-rw-r--r--source/blender/blenkernel/intern/subdiv_deform.c42
-rw-r--r--source/blender/blenkernel/intern/subdiv_eval.c13
-rw-r--r--source/blender/blenkernel/intern/subdiv_foreach.c93
-rw-r--r--source/blender/blenkernel/intern/subdiv_mesh.c122
-rw-r--r--source/blender/blenkernel/intern/subsurf_ccg.c277
-rw-r--r--source/blender/blenkernel/intern/text.c7
-rw-r--r--source/blender/blenkernel/intern/texture.c25
-rw-r--r--source/blender/blenkernel/intern/tracking.c28
-rw-r--r--source/blender/blenkernel/intern/tracking_solver.c2
-rw-r--r--source/blender/blenkernel/intern/tracking_stabilize.c4
-rw-r--r--source/blender/blenkernel/intern/tracking_util.c108
-rw-r--r--source/blender/blenkernel/intern/undo_system.c63
-rw-r--r--source/blender/blenkernel/intern/unit.c111
-rw-r--r--source/blender/blenkernel/intern/volume.cc136
-rw-r--r--source/blender/blenkernel/intern/workspace.c79
-rw-r--r--source/blender/blenkernel/intern/world.c74
-rw-r--r--source/blender/blenkernel/intern/writeffmpeg.c5
-rw-r--r--source/blender/blenlib/BLI_allocator.hh (renamed from source/blender/blenlib/BLI_allocator.h)6
-rw-r--r--source/blender/blenlib/BLI_array.hh (renamed from source/blender/blenlib/BLI_array_cxx.h)28
-rw-r--r--source/blender/blenlib/BLI_array_ref.hh (renamed from source/blender/blenlib/BLI_array_ref.h)20
-rw-r--r--source/blender/blenlib/BLI_asan.h45
-rw-r--r--source/blender/blenlib/BLI_assert.h8
-rw-r--r--source/blender/blenlib/BLI_bitmap.h4
-rw-r--r--source/blender/blenlib/BLI_blenlib.h8
-rw-r--r--source/blender/blenlib/BLI_color.hh92
-rw-r--r--source/blender/blenlib/BLI_compiler_typecheck.h2
-rw-r--r--source/blender/blenlib/BLI_dot_export.hh290
-rw-r--r--source/blender/blenlib/BLI_dot_export_attribute_enums.hh125
-rw-r--r--source/blender/blenlib/BLI_fileops.h8
-rw-r--r--source/blender/blenlib/BLI_float2.hh86
-rw-r--r--source/blender/blenlib/BLI_float3.hh218
-rw-r--r--source/blender/blenlib/BLI_float4x4.hh115
-rw-r--r--source/blender/blenlib/BLI_gsqueue.h2
-rw-r--r--source/blender/blenlib/BLI_hash.h6
-rw-r--r--source/blender/blenlib/BLI_hash.hh (renamed from source/blender/blenlib/BLI_hash_cxx.h)36
-rw-r--r--source/blender/blenlib/BLI_heap.h4
-rw-r--r--source/blender/blenlib/BLI_index_range.hh (renamed from source/blender/blenlib/BLI_index_range.h)6
-rw-r--r--source/blender/blenlib/BLI_lasso_2d.h10
-rw-r--r--source/blender/blenlib/BLI_linear_allocator.hh220
-rw-r--r--source/blender/blenlib/BLI_link_utils.h2
-rw-r--r--source/blender/blenlib/BLI_listbase_wrapper.hh (renamed from source/blender/blenlib/BLI_listbase_wrapper.h)12
-rw-r--r--source/blender/blenlib/BLI_map.hh (renamed from source/blender/blenlib/BLI_map.h)68
-rw-r--r--source/blender/blenlib/BLI_math_base.h12
-rw-r--r--source/blender/blenlib/BLI_math_bits.h4
-rw-r--r--source/blender/blenlib/BLI_math_color.h4
-rw-r--r--source/blender/blenlib/BLI_math_color_blend.h4
-rw-r--r--source/blender/blenlib/BLI_math_geom.h8
-rw-r--r--source/blender/blenlib/BLI_math_matrix.h6
-rw-r--r--source/blender/blenlib/BLI_math_solvers.h6
-rw-r--r--source/blender/blenlib/BLI_math_statistics.h6
-rw-r--r--source/blender/blenlib/BLI_math_vector.h14
-rw-r--r--source/blender/blenlib/BLI_memarena.h4
-rw-r--r--source/blender/blenlib/BLI_memblock.h4
-rw-r--r--source/blender/blenlib/BLI_memiter.h8
-rw-r--r--source/blender/blenlib/BLI_memory_utils.hh (renamed from source/blender/blenlib/BLI_memory_utils_cxx.h)6
-rw-r--r--source/blender/blenlib/BLI_mempool.h6
-rw-r--r--source/blender/blenlib/BLI_open_addressing.hh (renamed from source/blender/blenlib/BLI_open_addressing.h)185
-rw-r--r--source/blender/blenlib/BLI_optional.hh (renamed from source/blender/blenlib/BLI_optional.h)8
-rw-r--r--source/blender/blenlib/BLI_path_util.h36
-rw-r--r--source/blender/blenlib/BLI_rand.h1
-rw-r--r--source/blender/blenlib/BLI_scanfill.h8
-rw-r--r--source/blender/blenlib/BLI_set.hh (renamed from source/blender/blenlib/BLI_set.h)49
-rw-r--r--source/blender/blenlib/BLI_stack.h2
-rw-r--r--source/blender/blenlib/BLI_stack.hh (renamed from source/blender/blenlib/BLI_stack_cxx.h)13
-rw-r--r--source/blender/blenlib/BLI_string.h6
-rw-r--r--source/blender/blenlib/BLI_string_map.hh (renamed from source/blender/blenlib/BLI_string_map.h)105
-rw-r--r--source/blender/blenlib/BLI_string_ref.hh (renamed from source/blender/blenlib/BLI_string_ref.h)26
-rw-r--r--source/blender/blenlib/BLI_string_utf8.h6
-rw-r--r--source/blender/blenlib/BLI_string_utils.h6
-rw-r--r--source/blender/blenlib/BLI_sys_types.h2
-rw-r--r--source/blender/blenlib/BLI_system.h4
-rw-r--r--source/blender/blenlib/BLI_task.h199
-rw-r--r--source/blender/blenlib/BLI_threads.h12
-rw-r--r--source/blender/blenlib/BLI_timeit.hh62
-rw-r--r--source/blender/blenlib/BLI_utildefines.h8
-rw-r--r--source/blender/blenlib/BLI_utility_mixins.hh (renamed from source/blender/blenlib/BLI_utility_mixins.h)6
-rw-r--r--source/blender/blenlib/BLI_vector.hh (renamed from source/blender/blenlib/BLI_vector.h)56
-rw-r--r--source/blender/blenlib/BLI_vector_set.hh (renamed from source/blender/blenlib/BLI_vector_set.h)120
-rw-r--r--source/blender/blenlib/CMakeLists.txt66
-rw-r--r--source/blender/blenlib/intern/BLI_filelist.c2
-rw-r--r--source/blender/blenlib/intern/BLI_ghash.c2
-rw-r--r--source/blender/blenlib/intern/BLI_index_range.cc8
-rw-r--r--source/blender/blenlib/intern/BLI_kdopbvh.c4
-rw-r--r--source/blender/blenlib/intern/BLI_memarena.c21
-rw-r--r--source/blender/blenlib/intern/BLI_memiter.c21
-rw-r--r--source/blender/blenlib/intern/array_store.c18
-rw-r--r--source/blender/blenlib/intern/boxpack_2d.c2
-rw-r--r--source/blender/blenlib/intern/delaunay_2d.c15
-rw-r--r--source/blender/blenlib/intern/dot_export.cc305
-rw-r--r--source/blender/blenlib/intern/fileops.c26
-rw-r--r--source/blender/blenlib/intern/fnmatch.c3
-rw-r--r--source/blender/blenlib/intern/lasso_2d.c48
-rw-r--r--source/blender/blenlib/intern/math_base_inline.c25
-rw-r--r--source/blender/blenlib/intern/math_color.c3
-rw-r--r--source/blender/blenlib/intern/math_geom.c33
-rw-r--r--source/blender/blenlib/intern/math_solvers.c2
-rw-r--r--source/blender/blenlib/intern/math_vector.c31
-rw-r--r--source/blender/blenlib/intern/math_vector_inline.c21
-rw-r--r--source/blender/blenlib/intern/noise.c7
-rw-r--r--source/blender/blenlib/intern/path_util.c89
-rw-r--r--source/blender/blenlib/intern/quadric.c11
-rw-r--r--source/blender/blenlib/intern/stack.c2
-rw-r--r--source/blender/blenlib/intern/storage.c64
-rw-r--r--source/blender/blenlib/intern/storage_apple.mm6
-rw-r--r--source/blender/blenlib/intern/system.c52
-rw-r--r--source/blender/blenlib/intern/system_win32.c410
-rw-r--r--source/blender/blenlib/intern/task.c1930
-rw-r--r--source/blender/blenlib/intern/task_graph.cc166
-rw-r--r--source/blender/blenlib/intern/task_iterator.c423
-rw-r--r--source/blender/blenlib/intern/task_pool.cc546
-rw-r--r--source/blender/blenlib/intern/task_range.cc (renamed from source/blender/blenkernel/intern/pbvh_parallel.cc)116
-rw-r--r--source/blender/blenlib/intern/task_scheduler.cc78
-rw-r--r--source/blender/blenlib/intern/threads.c71
-rw-r--r--source/blender/blenlib/intern/timeit.cc36
-rw-r--r--source/blender/blenloader/BLO_read_write.h207
-rw-r--r--source/blender/blenloader/BLO_undofile.h27
-rw-r--r--source/blender/blenloader/CMakeLists.txt2
-rw-r--r--source/blender/blenloader/intern/readblenentry.c35
-rw-r--r--source/blender/blenloader/intern/readfile.c1679
-rw-r--r--source/blender/blenloader/intern/readfile.h9
-rw-r--r--source/blender/blenloader/intern/undofile.c62
-rw-r--r--source/blender/blenloader/intern/versioning_250.c259
-rw-r--r--source/blender/blenloader/intern/versioning_260.c120
-rw-r--r--source/blender/blenloader/intern/versioning_270.c100
-rw-r--r--source/blender/blenloader/intern/versioning_280.c682
-rw-r--r--source/blender/blenloader/intern/versioning_290.c270
-rw-r--r--source/blender/blenloader/intern/versioning_cycles.c48
-rw-r--r--source/blender/blenloader/intern/versioning_defaults.c332
-rw-r--r--source/blender/blenloader/intern/versioning_legacy.c184
-rw-r--r--source/blender/blenloader/intern/versioning_userdef.c28
-rw-r--r--source/blender/blenloader/intern/writefile.c833
-rw-r--r--source/blender/blentranslation/BLT_translation.h8
-rw-r--r--source/blender/blentranslation/intern/blt_lang.c15
-rw-r--r--source/blender/blentranslation/intern/blt_translation.c2
-rw-r--r--source/blender/bmesh/CMakeLists.txt6
-rw-r--r--source/blender/bmesh/bmesh.h10
-rw-r--r--source/blender/bmesh/intern/bmesh_construct.c4
-rw-r--r--source/blender/bmesh/intern/bmesh_edgeloop.h2
-rw-r--r--source/blender/bmesh/intern/bmesh_marking.c6
-rw-r--r--source/blender/bmesh/intern/bmesh_mesh.c33
-rw-r--r--source/blender/bmesh/intern/bmesh_mesh.h1
-rw-r--r--source/blender/bmesh/intern/bmesh_mesh_convert.c (renamed from source/blender/bmesh/intern/bmesh_mesh_conv.c)4
-rw-r--r--source/blender/bmesh/intern/bmesh_mesh_convert.h (renamed from source/blender/bmesh/intern/bmesh_mesh_conv.h)0
-rw-r--r--source/blender/bmesh/intern/bmesh_opdefines.c11
-rw-r--r--source/blender/bmesh/intern/bmesh_operator_api.h8
-rw-r--r--source/blender/bmesh/intern/bmesh_operators.c2
-rw-r--r--source/blender/bmesh/intern/bmesh_polygon.c25
-rw-r--r--source/blender/bmesh/intern/bmesh_polygon.h8
-rw-r--r--source/blender/bmesh/intern/bmesh_query.c60
-rw-r--r--source/blender/bmesh/intern/bmesh_query.h12
-rw-r--r--source/blender/bmesh/operators/bmo_extrude.c65
-rw-r--r--source/blender/bmesh/operators/bmo_fill_grid.c9
-rw-r--r--source/blender/bmesh/operators/bmo_mesh_convert.c (renamed from source/blender/bmesh/operators/bmo_mesh_conv.c)0
-rw-r--r--source/blender/bmesh/operators/bmo_mirror.c17
-rw-r--r--source/blender/bmesh/operators/bmo_primitive.c57
-rw-r--r--source/blender/bmesh/tools/bmesh_bevel.c21
-rw-r--r--source/blender/bmesh/tools/bmesh_bevel.h1
-rw-r--r--source/blender/bmesh/tools/bmesh_intersect.c45
-rw-r--r--source/blender/bmesh/tools/bmesh_intersect_edges.c62
-rw-r--r--source/blender/bmesh/tools/bmesh_path.c2
-rw-r--r--source/blender/compositor/COM_compositor.h8
-rw-r--r--source/blender/compositor/intern/COM_Converter.cpp2
-rw-r--r--source/blender/compositor/intern/COM_ExecutionSystem.cpp3
-rw-r--r--source/blender/compositor/intern/COM_MemoryBuffer.h2
-rw-r--r--source/blender/compositor/intern/COM_Node.cpp2
-rw-r--r--source/blender/compositor/intern/COM_NodeConverter.cpp2
-rw-r--r--source/blender/compositor/intern/COM_NodeGraph.cpp2
-rw-r--r--source/blender/compositor/intern/COM_NodeGraph.h2
-rw-r--r--source/blender/compositor/intern/COM_NodeOperation.h2
-rw-r--r--source/blender/compositor/intern/COM_NodeOperationBuilder.cpp2
-rw-r--r--source/blender/compositor/intern/COM_WorkScheduler.h4
-rw-r--r--source/blender/compositor/intern/COM_compositor.cpp4
-rw-r--r--source/blender/compositor/nodes/COM_CornerPinNode.h2
-rw-r--r--source/blender/compositor/nodes/COM_ImageNode.h3
-rw-r--r--source/blender/compositor/nodes/COM_KeyingScreenNode.cpp2
-rw-r--r--source/blender/compositor/nodes/COM_MaskNode.cpp2
-rw-r--r--source/blender/compositor/nodes/COM_MovieClipNode.cpp4
-rw-r--r--source/blender/compositor/nodes/COM_PlaneTrackDeformNode.cpp2
-rw-r--r--source/blender/compositor/nodes/COM_PlaneTrackDeformNode.h2
-rw-r--r--source/blender/compositor/nodes/COM_Stabilize2dNode.cpp3
-rw-r--r--source/blender/compositor/nodes/COM_TimeNode.cpp4
-rw-r--r--source/blender/compositor/nodes/COM_TrackPositionNode.cpp2
-rw-r--r--source/blender/compositor/operations/COM_AntiAliasOperation.cpp2
-rw-r--r--source/blender/compositor/operations/COM_BilateralBlurOperation.cpp2
-rw-r--r--source/blender/compositor/operations/COM_BlurBaseOperation.cpp2
-rw-r--r--source/blender/compositor/operations/COM_BokehBlurOperation.cpp2
-rw-r--r--source/blender/compositor/operations/COM_CalculateMeanOperation.cpp2
-rw-r--r--source/blender/compositor/operations/COM_CalculateStandardDeviationOperation.cpp2
-rw-r--r--source/blender/compositor/operations/COM_ColorCorrectionOperation.cpp2
-rw-r--r--source/blender/compositor/operations/COM_ColorCurveOperation.cpp9
-rw-r--r--source/blender/compositor/operations/COM_ColorRampOperation.cpp6
-rw-r--r--source/blender/compositor/operations/COM_CompositorOperation.cpp5
-rw-r--r--source/blender/compositor/operations/COM_ConvertColorProfileOperation.cpp3
-rw-r--r--source/blender/compositor/operations/COM_ConvertOperation.cpp2
-rw-r--r--source/blender/compositor/operations/COM_CurveBaseOperation.cpp6
-rw-r--r--source/blender/compositor/operations/COM_DirectionalBlurOperation.cpp6
-rw-r--r--source/blender/compositor/operations/COM_DoubleEdgeMaskOperation.cpp2
-rw-r--r--source/blender/compositor/operations/COM_GaussianAlphaXBlurOperation.cpp2
-rw-r--r--source/blender/compositor/operations/COM_GaussianAlphaYBlurOperation.cpp2
-rw-r--r--source/blender/compositor/operations/COM_GaussianBokehBlurOperation.cpp3
-rw-r--r--source/blender/compositor/operations/COM_GaussianXBlurOperation.cpp2
-rw-r--r--source/blender/compositor/operations/COM_GaussianYBlurOperation.cpp2
-rw-r--r--source/blender/compositor/operations/COM_GlareThresholdOperation.cpp2
-rw-r--r--source/blender/compositor/operations/COM_HueSaturationValueCorrectOperation.cpp6
-rw-r--r--source/blender/compositor/operations/COM_ImageOperation.cpp2
-rw-r--r--source/blender/compositor/operations/COM_ImageOperation.h3
-rw-r--r--source/blender/compositor/operations/COM_KeyingScreenOperation.cpp2
-rw-r--r--source/blender/compositor/operations/COM_KeyingScreenOperation.h2
-rw-r--r--source/blender/compositor/operations/COM_LuminanceMatteOperation.cpp2
-rw-r--r--source/blender/compositor/operations/COM_MaskOperation.cpp2
-rw-r--r--source/blender/compositor/operations/COM_MathBaseOperation.cpp3
-rw-r--r--source/blender/compositor/operations/COM_MixOperation.cpp2
-rw-r--r--source/blender/compositor/operations/COM_MovieClipAttributeOperation.cpp4
-rw-r--r--source/blender/compositor/operations/COM_MovieClipOperation.cpp6
-rw-r--r--source/blender/compositor/operations/COM_MovieDistortionOperation.cpp6
-rw-r--r--source/blender/compositor/operations/COM_MovieDistortionOperation.h2
-rw-r--r--source/blender/compositor/operations/COM_MultilayerImageOperation.cpp3
-rw-r--r--source/blender/compositor/operations/COM_OutputFileMultiViewOperation.cpp2
-rw-r--r--source/blender/compositor/operations/COM_OutputFileOperation.cpp2
-rw-r--r--source/blender/compositor/operations/COM_PlaneCornerPinOperation.cpp2
-rw-r--r--source/blender/compositor/operations/COM_PlaneDistortCommonOperation.cpp2
-rw-r--r--source/blender/compositor/operations/COM_PlaneTrackOperation.cpp2
-rw-r--r--source/blender/compositor/operations/COM_PreviewOperation.cpp3
-rw-r--r--source/blender/compositor/operations/COM_RenderLayersProg.cpp2
-rw-r--r--source/blender/compositor/operations/COM_RenderLayersProg.h5
-rw-r--r--source/blender/compositor/operations/COM_ScreenLensDistortionOperation.cpp3
-rw-r--r--source/blender/compositor/operations/COM_SplitOperation.cpp2
-rw-r--r--source/blender/compositor/operations/COM_TextureOperation.cpp6
-rw-r--r--source/blender/compositor/operations/COM_TextureOperation.h3
-rw-r--r--source/blender/compositor/operations/COM_TonemapOperation.cpp2
-rw-r--r--source/blender/compositor/operations/COM_TrackPositionOperation.cpp2
-rw-r--r--source/blender/compositor/operations/COM_VariableSizeBokehBlurOperation.cpp2
-rw-r--r--source/blender/compositor/operations/COM_VectorBlurOperation.cpp23
-rw-r--r--source/blender/compositor/operations/COM_VectorCurveOperation.cpp6
-rw-r--r--source/blender/compositor/operations/COM_ViewerOperation.cpp2
-rw-r--r--source/blender/depsgraph/DEG_depsgraph.h2
-rw-r--r--source/blender/depsgraph/DEG_depsgraph_build.h8
-rw-r--r--source/blender/depsgraph/DEG_depsgraph_query.h8
-rw-r--r--source/blender/depsgraph/intern/builder/deg_builder.cc8
-rw-r--r--source/blender/depsgraph/intern/builder/deg_builder_cache.cc2
-rw-r--r--source/blender/depsgraph/intern/builder/deg_builder_nodes.cc162
-rw-r--r--source/blender/depsgraph/intern/builder/deg_builder_nodes.h9
-rw-r--r--source/blender/depsgraph/intern/builder/deg_builder_nodes_rig.cc7
-rw-r--r--source/blender/depsgraph/intern/builder/deg_builder_nodes_scene.cc1
-rw-r--r--source/blender/depsgraph/intern/builder/deg_builder_nodes_view_layer.cc2
-rw-r--r--source/blender/depsgraph/intern/builder/deg_builder_pchanmap.cc73
-rw-r--r--source/blender/depsgraph/intern/builder/deg_builder_pchanmap.h16
-rw-r--r--source/blender/depsgraph/intern/builder/deg_builder_relations.cc167
-rw-r--r--source/blender/depsgraph/intern/builder/deg_builder_relations.h6
-rw-r--r--source/blender/depsgraph/intern/builder/deg_builder_relations_impl.h2
-rw-r--r--source/blender/depsgraph/intern/builder/deg_builder_relations_rig.cc10
-rw-r--r--source/blender/depsgraph/intern/builder/deg_builder_relations_scene.cc1
-rw-r--r--source/blender/depsgraph/intern/builder/deg_builder_relations_view_layer.cc2
-rw-r--r--source/blender/depsgraph/intern/builder/deg_builder_remove_noop.cc4
-rw-r--r--source/blender/depsgraph/intern/builder/deg_builder_rna.cc45
-rw-r--r--source/blender/depsgraph/intern/builder/deg_builder_rna.h3
-rw-r--r--source/blender/depsgraph/intern/builder/deg_builder_transitive.cc21
-rw-r--r--source/blender/depsgraph/intern/debug/deg_debug_relations_graphviz.cc16
-rw-r--r--source/blender/depsgraph/intern/debug/deg_debug_stats_gnuplot.cc2
-rw-r--r--source/blender/depsgraph/intern/depsgraph.cc25
-rw-r--r--source/blender/depsgraph/intern/depsgraph.h8
-rw-r--r--source/blender/depsgraph/intern/depsgraph_build.cc14
-rw-r--r--source/blender/depsgraph/intern/depsgraph_debug.cc14
-rw-r--r--source/blender/depsgraph/intern/depsgraph_eval.cc7
-rw-r--r--source/blender/depsgraph/intern/depsgraph_physics.cc70
-rw-r--r--source/blender/depsgraph/intern/depsgraph_query.cc14
-rw-r--r--source/blender/depsgraph/intern/depsgraph_query_foreach.cc88
-rw-r--r--source/blender/depsgraph/intern/depsgraph_query_iter.cc12
-rw-r--r--source/blender/depsgraph/intern/depsgraph_registry.cc35
-rw-r--r--source/blender/depsgraph/intern/depsgraph_registry.h2
-rw-r--r--source/blender/depsgraph/intern/depsgraph_relation.cc14
-rw-r--r--source/blender/depsgraph/intern/depsgraph_tag.cc15
-rw-r--r--source/blender/depsgraph/intern/depsgraph_type.cc1
-rw-r--r--source/blender/depsgraph/intern/depsgraph_type.h16
-rw-r--r--source/blender/depsgraph/intern/eval/deg_eval.cc61
-rw-r--r--source/blender/depsgraph/intern/eval/deg_eval_copy_on_write.cc3
-rw-r--r--source/blender/depsgraph/intern/eval/deg_eval_flush.cc29
-rw-r--r--source/blender/depsgraph/intern/eval/deg_eval_runtime_backup.cc2
-rw-r--r--source/blender/depsgraph/intern/eval/deg_eval_runtime_backup_object.cc2
-rw-r--r--source/blender/depsgraph/intern/eval/deg_eval_runtime_backup_scene.cc4
-rw-r--r--source/blender/depsgraph/intern/eval/deg_eval_stats.cc4
-rw-r--r--source/blender/depsgraph/intern/node/deg_node.cc4
-rw-r--r--source/blender/depsgraph/intern/node/deg_node.h4
-rw-r--r--source/blender/depsgraph/intern/node/deg_node_component.cc71
-rw-r--r--source/blender/depsgraph/intern/node/deg_node_component.h21
-rw-r--r--source/blender/depsgraph/intern/node/deg_node_id.cc54
-rw-r--r--source/blender/depsgraph/intern/node/deg_node_id.h18
-rw-r--r--source/blender/depsgraph/intern/node/deg_node_operation.cc7
-rw-r--r--source/blender/depsgraph/intern/node/deg_node_operation.h5
-rw-r--r--source/blender/draw/CMakeLists.txt8
-rw-r--r--source/blender/draw/DRW_engine.h16
-rw-r--r--source/blender/draw/engines/basic/basic_engine.c33
-rw-r--r--source/blender/draw/engines/basic/shaders/depth_frag.glsl (renamed from source/blender/draw/engines/basic/shaders/conservative_depth_frag.glsl)0
-rw-r--r--source/blender/draw/engines/basic/shaders/depth_vert.glsl (renamed from source/blender/draw/engines/basic/shaders/conservative_depth_vert.glsl)4
-rw-r--r--source/blender/draw/engines/eevee/eevee_bloom.c4
-rw-r--r--source/blender/draw/engines/eevee/eevee_data.c15
-rw-r--r--source/blender/draw/engines/eevee/eevee_depth_of_field.c12
-rw-r--r--source/blender/draw/engines/eevee/eevee_effects.c3
-rw-r--r--source/blender/draw/engines/eevee/eevee_engine.c16
-rw-r--r--source/blender/draw/engines/eevee/eevee_lightcache.c13
-rw-r--r--source/blender/draw/engines/eevee/eevee_lightprobes.c95
-rw-r--r--source/blender/draw/engines/eevee/eevee_lookdev.c44
-rw-r--r--source/blender/draw/engines/eevee/eevee_lut_gen.c198
-rw-r--r--source/blender/draw/engines/eevee/eevee_materials.c2369
-rw-r--r--source/blender/draw/engines/eevee/eevee_mist.c3
-rw-r--r--source/blender/draw/engines/eevee/eevee_motion_blur.c3
-rw-r--r--source/blender/draw/engines/eevee/eevee_occlusion.c12
-rw-r--r--source/blender/draw/engines/eevee/eevee_private.h171
-rw-r--r--source/blender/draw/engines/eevee/eevee_render.c19
-rw-r--r--source/blender/draw/engines/eevee/eevee_renderpasses.c48
-rw-r--r--source/blender/draw/engines/eevee/eevee_screen_raytrace.c6
-rw-r--r--source/blender/draw/engines/eevee/eevee_shaders.c488
-rw-r--r--source/blender/draw/engines/eevee/eevee_shadows.c44
-rw-r--r--source/blender/draw/engines/eevee/eevee_subsurface.c137
-rw-r--r--source/blender/draw/engines/eevee/eevee_temporal_sampling.c7
-rw-r--r--source/blender/draw/engines/eevee/eevee_volumes.c41
-rw-r--r--source/blender/draw/engines/eevee/shaders/ambient_occlusion_lib.glsl10
-rw-r--r--source/blender/draw/engines/eevee/shaders/bsdf_common_lib.glsl8
-rw-r--r--source/blender/draw/engines/eevee/shaders/effect_dof_frag.glsl2
-rw-r--r--source/blender/draw/engines/eevee/shaders/lit_surface_frag.glsl2
-rw-r--r--source/blender/draw/engines/eevee/shaders/lit_surface_vert.glsl27
-rw-r--r--source/blender/draw/engines/eevee/shaders/prepass_frag.glsl21
-rw-r--r--source/blender/draw/engines/external/external_engine.c40
-rw-r--r--source/blender/draw/engines/gpencil/gpencil_antialiasing.c7
-rw-r--r--source/blender/draw/engines/gpencil/gpencil_cache_utils.c35
-rw-r--r--source/blender/draw/engines/gpencil/gpencil_draw_data.c28
-rw-r--r--source/blender/draw/engines/gpencil/gpencil_engine.c22
-rw-r--r--source/blender/draw/engines/gpencil/gpencil_engine.h2
-rw-r--r--source/blender/draw/engines/gpencil/gpencil_render.c3
-rw-r--r--source/blender/draw/engines/gpencil/gpencil_shader.c34
-rw-r--r--source/blender/draw/engines/gpencil/shaders/gpencil_common_lib.glsl35
-rw-r--r--source/blender/draw/engines/gpencil/shaders/gpencil_frag.glsl4
-rw-r--r--source/blender/draw/engines/gpencil/shaders/gpencil_vert.glsl2
-rw-r--r--source/blender/draw/engines/overlay/overlay_antialiasing.c17
-rw-r--r--source/blender/draw/engines/overlay/overlay_armature.c56
-rw-r--r--source/blender/draw/engines/overlay/overlay_background.c7
-rw-r--r--source/blender/draw/engines/overlay/overlay_edit_curve.c10
-rw-r--r--source/blender/draw/engines/overlay/overlay_edit_mesh.c28
-rw-r--r--source/blender/draw/engines/overlay/overlay_edit_text.c3
-rw-r--r--source/blender/draw/engines/overlay/overlay_engine.c42
-rw-r--r--source/blender/draw/engines/overlay/overlay_extra.c51
-rw-r--r--source/blender/draw/engines/overlay/overlay_facing.c36
-rw-r--r--source/blender/draw/engines/overlay/overlay_gpencil.c25
-rw-r--r--source/blender/draw/engines/overlay/overlay_grid.c19
-rw-r--r--source/blender/draw/engines/overlay/overlay_image.c76
-rw-r--r--source/blender/draw/engines/overlay/overlay_motion_path.c7
-rw-r--r--source/blender/draw/engines/overlay/overlay_outline.c18
-rw-r--r--source/blender/draw/engines/overlay/overlay_paint.c23
-rw-r--r--source/blender/draw/engines/overlay/overlay_particle.c10
-rw-r--r--source/blender/draw/engines/overlay/overlay_pointcloud.c2
-rw-r--r--source/blender/draw/engines/overlay/overlay_private.h21
-rw-r--r--source/blender/draw/engines/overlay/overlay_sculpt.c2
-rw-r--r--source/blender/draw/engines/overlay/overlay_shader.c37
-rw-r--r--source/blender/draw/engines/overlay/overlay_wireframe.c80
-rw-r--r--source/blender/draw/engines/overlay/shaders/edit_curve_handle_geom.glsl21
-rw-r--r--source/blender/draw/engines/overlay/shaders/edit_curve_point_vert.glsl19
-rw-r--r--source/blender/draw/engines/overlay/shaders/edit_gpencil_vert.glsl10
-rw-r--r--source/blender/draw/engines/overlay/shaders/edit_mesh_common_lib.glsl4
-rw-r--r--source/blender/draw/engines/overlay/shaders/edit_mesh_normal_vert.glsl4
-rw-r--r--source/blender/draw/engines/overlay/shaders/edit_mesh_vert.glsl8
-rw-r--r--source/blender/draw/engines/overlay/shaders/extra_vert.glsl7
-rw-r--r--source/blender/draw/engines/overlay/shaders/extra_wire_vert.glsl13
-rw-r--r--source/blender/draw/engines/overlay/shaders/grid_frag.glsl9
-rw-r--r--source/blender/draw/engines/overlay/shaders/sculpt_mask_frag.glsl10
-rw-r--r--source/blender/draw/engines/overlay/shaders/sculpt_mask_vert.glsl7
-rw-r--r--source/blender/draw/engines/overlay/shaders/wireframe_vert.glsl17
-rw-r--r--source/blender/draw/engines/select/select_engine.c3
-rw-r--r--source/blender/draw/engines/workbench/shaders/workbench_curvature_lib.glsl4
-rw-r--r--source/blender/draw/engines/workbench/shaders/workbench_effect_dof_frag.glsl1
-rw-r--r--source/blender/draw/engines/workbench/shaders/workbench_image_lib.glsl24
-rw-r--r--source/blender/draw/engines/workbench/shaders/workbench_merge_infront_frag.glsl2
-rw-r--r--source/blender/draw/engines/workbench/shaders/workbench_world_light_lib.glsl2
-rw-r--r--source/blender/draw/engines/workbench/workbench_data.c13
-rw-r--r--source/blender/draw/engines/workbench/workbench_effect_antialiasing.c50
-rw-r--r--source/blender/draw/engines/workbench/workbench_effect_cavity.c8
-rw-r--r--source/blender/draw/engines/workbench/workbench_engine.c16
-rw-r--r--source/blender/draw/engines/workbench/workbench_materials.c7
-rw-r--r--source/blender/draw/engines/workbench/workbench_opaque.c18
-rw-r--r--source/blender/draw/engines/workbench/workbench_private.h5
-rw-r--r--source/blender/draw/engines/workbench/workbench_render.c4
-rw-r--r--source/blender/draw/engines/workbench/workbench_shader.c33
-rw-r--r--source/blender/draw/engines/workbench/workbench_shadow.c5
-rw-r--r--source/blender/draw/engines/workbench/workbench_transparent.c12
-rw-r--r--source/blender/draw/engines/workbench/workbench_volume.c3
-rw-r--r--source/blender/draw/intern/DRW_render.h47
-rw-r--r--source/blender/draw/intern/draw_cache.c13
-rw-r--r--source/blender/draw/intern/draw_cache.h2
-rw-r--r--source/blender/draw/intern/draw_cache_extract.h6
-rw-r--r--source/blender/draw/intern/draw_cache_extract_mesh.c781
-rw-r--r--source/blender/draw/intern/draw_cache_impl.h7
-rw-r--r--source/blender/draw/intern/draw_cache_impl_curve.c79
-rw-r--r--source/blender/draw/intern/draw_cache_impl_displist.c25
-rw-r--r--source/blender/draw/intern/draw_cache_impl_gpencil.c33
-rw-r--r--source/blender/draw/intern/draw_cache_impl_mesh.c105
-rw-r--r--source/blender/draw/intern/draw_cache_impl_particles.c20
-rw-r--r--source/blender/draw/intern/draw_cache_impl_pointcloud.c2
-rw-r--r--source/blender/draw/intern/draw_cache_impl_volume.c4
-rw-r--r--source/blender/draw/intern/draw_common.h12
-rw-r--r--source/blender/draw/intern/draw_hair.c61
-rw-r--r--source/blender/draw/intern/draw_hair_private.h2
-rw-r--r--source/blender/draw/intern/draw_manager.c118
-rw-r--r--source/blender/draw/intern/draw_manager.h64
-rw-r--r--source/blender/draw/intern/draw_manager_data.c335
-rw-r--r--source/blender/draw/intern/draw_manager_exec.c249
-rw-r--r--source/blender/draw/intern/draw_manager_profiling.c3
-rw-r--r--source/blender/draw/intern/draw_manager_shader.c34
-rw-r--r--source/blender/draw/intern/draw_manager_text.c127
-rw-r--r--source/blender/draw/intern/draw_manager_texture.c6
-rw-r--r--source/blender/draw/intern/shaders/common_globals_lib.glsl1
-rw-r--r--source/blender/draw/intern/shaders/common_view_lib.glsl6
-rw-r--r--source/blender/editors/animation/anim_channels_defines.c92
-rw-r--r--source/blender/editors/animation/anim_channels_edit.c58
-rw-r--r--source/blender/editors/animation/anim_deps.c2
-rw-r--r--source/blender/editors/animation/anim_draw.c106
-rw-r--r--source/blender/editors/animation/anim_filter.c54
-rw-r--r--source/blender/editors/animation/anim_ipo_utils.c2
-rw-r--r--source/blender/editors/animation/anim_markers.c46
-rw-r--r--source/blender/editors/animation/anim_motion_paths.c10
-rw-r--r--source/blender/editors/animation/anim_ops.c29
-rw-r--r--source/blender/editors/animation/drivers.c19
-rw-r--r--source/blender/editors/animation/fmodifier_ui.c56
-rw-r--r--source/blender/editors/animation/keyframes_draw.c31
-rw-r--r--source/blender/editors/animation/keyframes_edit.c4
-rw-r--r--source/blender/editors/animation/keyframes_general.c2
-rw-r--r--source/blender/editors/animation/keyframing.c29
-rw-r--r--source/blender/editors/animation/keyingsets.c4
-rw-r--r--source/blender/editors/animation/time_scrub_ui.c2
-rw-r--r--source/blender/editors/armature/armature_add.c571
-rw-r--r--source/blender/editors/armature/armature_edit.c222
-rw-r--r--source/blender/editors/armature/armature_intern.h52
-rw-r--r--source/blender/editors/armature/armature_naming.c66
-rw-r--r--source/blender/editors/armature/armature_ops.c3
-rw-r--r--source/blender/editors/armature/armature_relations.c24
-rw-r--r--source/blender/editors/armature/armature_select.c803
-rw-r--r--source/blender/editors/armature/armature_skinning.c4
-rw-r--r--source/blender/editors/armature/armature_utils.c35
-rw-r--r--source/blender/editors/armature/editarmature_undo.c3
-rw-r--r--source/blender/editors/armature/meshlaplacian.c6
-rw-r--r--source/blender/editors/armature/pose_edit.c13
-rw-r--r--source/blender/editors/armature/pose_group.c3
-rw-r--r--source/blender/editors/armature/pose_lib.c24
-rw-r--r--source/blender/editors/armature/pose_select.c84
-rw-r--r--source/blender/editors/armature/pose_slide.c182
-rw-r--r--source/blender/editors/armature/pose_transform.c23
-rw-r--r--source/blender/editors/armature/pose_utils.c2
-rw-r--r--source/blender/editors/curve/CMakeLists.txt1
-rw-r--r--source/blender/editors/curve/curve_intern.h19
-rw-r--r--source/blender/editors/curve/editcurve.c843
-rw-r--r--source/blender/editors/curve/editcurve_add.c4
-rw-r--r--source/blender/editors/curve/editcurve_paint.c20
-rw-r--r--source/blender/editors/curve/editcurve_query.c253
-rw-r--r--source/blender/editors/curve/editcurve_select.c18
-rw-r--r--source/blender/editors/curve/editcurve_undo.c18
-rw-r--r--source/blender/editors/curve/editfont.c2
-rw-r--r--source/blender/editors/curve/editfont_undo.c2
-rw-r--r--source/blender/editors/datafiles/CMakeLists.txt3
-rw-r--r--source/blender/editors/gizmo_library/CMakeLists.txt1
-rw-r--r--source/blender/editors/gizmo_library/geometry/geom_arrow_gizmo.c2
-rw-r--r--source/blender/editors/gizmo_library/geometry/geom_cube_gizmo.c2
-rw-r--r--source/blender/editors/gizmo_library/geometry/geom_dial_gizmo.c2
-rw-r--r--source/blender/editors/gizmo_library/gizmo_draw_utils.c2
-rw-r--r--source/blender/editors/gizmo_library/gizmo_geometry.h4
-rw-r--r--source/blender/editors/gizmo_library/gizmo_types/arrow3d_gizmo.c15
-rw-r--r--source/blender/editors/gizmo_library/gizmo_types/button2d_gizmo.c38
-rw-r--r--source/blender/editors/gizmo_library/gizmo_types/cage2d_gizmo.c57
-rw-r--r--source/blender/editors/gizmo_library/gizmo_types/cage3d_gizmo.c52
-rw-r--r--source/blender/editors/gizmo_library/gizmo_types/dial3d_gizmo.c52
-rw-r--r--source/blender/editors/gizmo_library/gizmo_types/move3d_gizmo.c21
-rw-r--r--source/blender/editors/gizmo_library/gizmo_types/snap3d_gizmo.c560
-rw-r--r--source/blender/editors/gpencil/annotate_draw.c574
-rw-r--r--source/blender/editors/gpencil/annotate_paint.c568
-rw-r--r--source/blender/editors/gpencil/drawgpencil.c534
-rw-r--r--source/blender/editors/gpencil/gpencil_armature.c30
-rw-r--r--source/blender/editors/gpencil/gpencil_convert.c32
-rw-r--r--source/blender/editors/gpencil/gpencil_data.c100
-rw-r--r--source/blender/editors/gpencil/gpencil_edit.c354
-rw-r--r--source/blender/editors/gpencil/gpencil_fill.c147
-rw-r--r--source/blender/editors/gpencil/gpencil_intern.h39
-rw-r--r--source/blender/editors/gpencil/gpencil_interpolate.c37
-rw-r--r--source/blender/editors/gpencil/gpencil_merge.c18
-rw-r--r--source/blender/editors/gpencil/gpencil_ops.c7
-rw-r--r--source/blender/editors/gpencil/gpencil_ops_versioning.c11
-rw-r--r--source/blender/editors/gpencil/gpencil_paint.c321
-rw-r--r--source/blender/editors/gpencil/gpencil_primitive.c156
-rw-r--r--source/blender/editors/gpencil/gpencil_sculpt_paint.c23
-rw-r--r--source/blender/editors/gpencil/gpencil_select.c156
-rw-r--r--source/blender/editors/gpencil/gpencil_utils.c306
-rw-r--r--source/blender/editors/gpencil/gpencil_uv.c172
-rw-r--r--source/blender/editors/gpencil/gpencil_vertex_ops.c2
-rw-r--r--source/blender/editors/gpencil/gpencil_vertex_paint.c3
-rw-r--r--source/blender/editors/gpencil/gpencil_weight_paint.c3
-rw-r--r--source/blender/editors/include/ED_anim_api.h31
-rw-r--r--source/blender/editors/include/ED_armature.h14
-rw-r--r--source/blender/editors/include/ED_datafiles.h3
-rw-r--r--source/blender/editors/include/ED_gizmo_library.h38
-rw-r--r--source/blender/editors/include/ED_gpencil.h46
-rw-r--r--source/blender/editors/include/ED_image.h14
-rw-r--r--source/blender/editors/include/ED_info.h6
-rw-r--r--source/blender/editors/include/ED_keyframes_edit.h8
-rw-r--r--source/blender/editors/include/ED_keyframing.h14
-rw-r--r--source/blender/editors/include/ED_mask.h19
-rw-r--r--source/blender/editors/include/ED_mesh.h29
-rw-r--r--source/blender/editors/include/ED_node.h15
-rw-r--r--source/blender/editors/include/ED_object.h47
-rw-r--r--source/blender/editors/include/ED_outliner.h4
-rw-r--r--source/blender/editors/include/ED_particle.h4
-rw-r--r--source/blender/editors/include/ED_render.h4
-rw-r--r--source/blender/editors/include/ED_screen.h65
-rw-r--r--source/blender/editors/include/ED_screen_types.h10
-rw-r--r--source/blender/editors/include/ED_sculpt.h5
-rw-r--r--source/blender/editors/include/ED_transform.h29
-rw-r--r--source/blender/editors/include/ED_transform_snap_object_context.h7
-rw-r--r--source/blender/editors/include/ED_util.h2
-rw-r--r--source/blender/editors/include/ED_util_imbuf.h52
-rw-r--r--source/blender/editors/include/ED_uvedit.h17
-rw-r--r--source/blender/editors/include/ED_view3d.h14
-rw-r--r--source/blender/editors/include/UI_icons.h2
-rw-r--r--source/blender/editors/include/UI_interface.h123
-rw-r--r--source/blender/editors/include/UI_resources.h8
-rw-r--r--source/blender/editors/include/UI_view2d.h25
-rw-r--r--source/blender/editors/interface/CMakeLists.txt3
-rw-r--r--source/blender/editors/interface/interface.c170
-rw-r--r--source/blender/editors/interface/interface_align.c10
-rw-r--r--source/blender/editors/interface/interface_anim.c58
-rw-r--r--source/blender/editors/interface/interface_context_menu.c10
-rw-r--r--source/blender/editors/interface/interface_eyedropper.c12
-rw-r--r--source/blender/editors/interface/interface_eyedropper_color.c65
-rw-r--r--source/blender/editors/interface/interface_eyedropper_colorband.c5
-rw-r--r--source/blender/editors/interface/interface_eyedropper_datablock.c31
-rw-r--r--source/blender/editors/interface/interface_eyedropper_depth.c21
-rw-r--r--source/blender/editors/interface/interface_eyedropper_driver.c5
-rw-r--r--source/blender/editors/interface/interface_eyedropper_gpencil_color.c3
-rw-r--r--source/blender/editors/interface/interface_handlers.c356
-rw-r--r--source/blender/editors/interface/interface_icons.c43
-rw-r--r--source/blender/editors/interface/interface_intern.h131
-rw-r--r--source/blender/editors/interface/interface_layout.c415
-rw-r--r--source/blender/editors/interface/interface_ops.c27
-rw-r--r--source/blender/editors/interface/interface_panel.c1148
-rw-r--r--source/blender/editors/interface/interface_query.c34
-rw-r--r--source/blender/editors/interface/interface_region_color_picker.c2
-rw-r--r--source/blender/editors/interface/interface_region_hud.c85
-rw-r--r--source/blender/editors/interface/interface_region_menu_popup.c39
-rw-r--r--source/blender/editors/interface/interface_region_popover.c8
-rw-r--r--source/blender/editors/interface/interface_region_popup.c34
-rw-r--r--source/blender/editors/interface/interface_region_search.c152
-rw-r--r--source/blender/editors/interface/interface_region_tooltip.c20
-rw-r--r--source/blender/editors/interface/interface_regions.c10
-rw-r--r--source/blender/editors/interface/interface_regions_intern.h4
-rw-r--r--source/blender/editors/interface/interface_style.c12
-rw-r--r--source/blender/editors/interface/interface_template_search_menu.c1139
-rw-r--r--source/blender/editors/interface/interface_template_search_operator.c151
-rw-r--r--source/blender/editors/interface/interface_templates.c1314
-rw-r--r--source/blender/editors/interface/interface_undo.c139
-rw-r--r--source/blender/editors/interface/interface_utils.c80
-rw-r--r--source/blender/editors/interface/interface_widgets.c298
-rw-r--r--source/blender/editors/interface/resources.c2
-rw-r--r--source/blender/editors/interface/view2d.c115
-rw-r--r--source/blender/editors/interface/view2d_draw.c15
-rw-r--r--source/blender/editors/interface/view2d_ops.c26
-rw-r--r--source/blender/editors/io/io_alembic.c4
-rw-r--r--source/blender/editors/io/io_alembic.h2
-rw-r--r--source/blender/editors/io/io_cache.c2
-rw-r--r--source/blender/editors/io/io_cache.h2
-rw-r--r--source/blender/editors/io/io_usd.c2
-rw-r--r--source/blender/editors/io/io_usd.h2
-rw-r--r--source/blender/editors/mask/mask_add.c23
-rw-r--r--source/blender/editors/mask/mask_draw.c60
-rw-r--r--source/blender/editors/mask/mask_edit.c23
-rw-r--r--source/blender/editors/mask/mask_ops.c55
-rw-r--r--source/blender/editors/mask/mask_query.c110
-rw-r--r--source/blender/editors/mask/mask_relationships.c9
-rw-r--r--source/blender/editors/mask/mask_select.c81
-rw-r--r--source/blender/editors/mask/mask_shapekey.c16
-rw-r--r--source/blender/editors/mesh/editface.c12
-rw-r--r--source/blender/editors/mesh/editmesh_add.c113
-rw-r--r--source/blender/editors/mesh/editmesh_bevel.c10
-rw-r--r--source/blender/editors/mesh/editmesh_extrude.c68
-rw-r--r--source/blender/editors/mesh/editmesh_extrude_spin_gizmo.c3
-rw-r--r--source/blender/editors/mesh/editmesh_inset.c12
-rw-r--r--source/blender/editors/mesh/editmesh_intersect.c10
-rw-r--r--source/blender/editors/mesh/editmesh_knife.c10
-rw-r--r--source/blender/editors/mesh/editmesh_loopcut.c26
-rw-r--r--source/blender/editors/mesh/editmesh_mask_extract.c6
-rw-r--r--source/blender/editors/mesh/editmesh_rip.c6
-rw-r--r--source/blender/editors/mesh/editmesh_select.c26
-rw-r--r--source/blender/editors/mesh/editmesh_select_similar.c2
-rw-r--r--source/blender/editors/mesh/editmesh_tools.c594
-rw-r--r--source/blender/editors/mesh/editmesh_undo.c10
-rw-r--r--source/blender/editors/mesh/editmesh_utils.c64
-rw-r--r--source/blender/editors/mesh/mesh_intern.h2
-rw-r--r--source/blender/editors/mesh/mesh_mirror.c108
-rw-r--r--source/blender/editors/mesh/mesh_ops.c14
-rw-r--r--source/blender/editors/mesh/meshtools.c124
-rw-r--r--source/blender/editors/metaball/mball_edit.c6
-rw-r--r--source/blender/editors/object/CMakeLists.txt2
-rw-r--r--source/blender/editors/object/object_add.c119
-rw-r--r--source/blender/editors/object/object_bake.c2
-rw-r--r--source/blender/editors/object/object_bake_api.c71
-rw-r--r--source/blender/editors/object/object_collection.c18
-rw-r--r--source/blender/editors/object/object_constraint.c37
-rw-r--r--source/blender/editors/object/object_data_transform.c4
-rw-r--r--source/blender/editors/object/object_edit.c321
-rw-r--r--source/blender/editors/object/object_gpencil_modifier.c16
-rw-r--r--source/blender/editors/object/object_hook.c8
-rw-r--r--source/blender/editors/object/object_intern.h3
-rw-r--r--source/blender/editors/object/object_modes.c94
-rw-r--r--source/blender/editors/object/object_modifier.c220
-rw-r--r--source/blender/editors/object/object_ops.c4
-rw-r--r--source/blender/editors/object/object_random.c4
-rw-r--r--source/blender/editors/object/object_relations.c45
-rw-r--r--source/blender/editors/object/object_remesh.c436
-rw-r--r--source/blender/editors/object/object_select.c4
-rw-r--r--source/blender/editors/object/object_shader_fx.c8
-rw-r--r--source/blender/editors/object/object_shapekey.c4
-rw-r--r--source/blender/editors/object/object_transform.c69
-rw-r--r--source/blender/editors/object/object_utils.c5
-rw-r--r--source/blender/editors/object/object_vgroup.c2
-rw-r--r--source/blender/editors/object/object_volume.c18
-rw-r--r--source/blender/editors/physics/dynamicpaint_ops.c10
-rw-r--r--source/blender/editors/physics/particle_edit.c147
-rw-r--r--source/blender/editors/physics/particle_edit_undo.c2
-rw-r--r--source/blender/editors/physics/particle_object.c6
-rw-r--r--source/blender/editors/physics/physics_fluid.c27
-rw-r--r--source/blender/editors/render/render_internal.c96
-rw-r--r--source/blender/editors/render/render_opengl.c38
-rw-r--r--source/blender/editors/render/render_preview.c56
-rw-r--r--source/blender/editors/render/render_shading.c17
-rw-r--r--source/blender/editors/render/render_update.c36
-rw-r--r--source/blender/editors/render/render_view.c122
-rw-r--r--source/blender/editors/scene/scene_edit.c4
-rw-r--r--source/blender/editors/screen/area.c609
-rw-r--r--source/blender/editors/screen/area_query.c14
-rw-r--r--source/blender/editors/screen/area_utils.c2
-rw-r--r--source/blender/editors/screen/glutil.c12
-rw-r--r--source/blender/editors/screen/screen_context.c72
-rw-r--r--source/blender/editors/screen/screen_draw.c178
-rw-r--r--source/blender/editors/screen/screen_edit.c658
-rw-r--r--source/blender/editors/screen/screen_geometry.c89
-rw-r--r--source/blender/editors/screen/screen_intern.h26
-rw-r--r--source/blender/editors/screen/screen_ops.c582
-rw-r--r--source/blender/editors/screen/screen_user_menu.c8
-rw-r--r--source/blender/editors/screen/screendump.c8
-rw-r--r--source/blender/editors/screen/workspace_edit.c21
-rw-r--r--source/blender/editors/screen/workspace_layout_edit.c12
-rw-r--r--source/blender/editors/sculpt_paint/CMakeLists.txt9
-rw-r--r--source/blender/editors/sculpt_paint/paint_cursor.c84
-rw-r--r--source/blender/editors/sculpt_paint/paint_curve_undo.c1
-rw-r--r--source/blender/editors/sculpt_paint/paint_hide.c2
-rw-r--r--source/blender/editors/sculpt_paint/paint_image.c234
-rw-r--r--source/blender/editors/sculpt_paint/paint_image_2d.c109
-rw-r--r--source/blender/editors/sculpt_paint/paint_image_proj.c95
-rw-r--r--source/blender/editors/sculpt_paint/paint_intern.h5
-rw-r--r--source/blender/editors/sculpt_paint/paint_mask.c28
-rw-r--r--source/blender/editors/sculpt_paint/paint_ops.c27
-rw-r--r--source/blender/editors/sculpt_paint/paint_stroke.c36
-rw-r--r--source/blender/editors/sculpt_paint/paint_utils.c37
-rw-r--r--source/blender/editors/sculpt_paint/paint_vertex.c110
-rw-r--r--source/blender/editors/sculpt_paint/paint_vertex_color_ops.c2
-rw-r--r--source/blender/editors/sculpt_paint/paint_vertex_weight_ops.c4
-rw-r--r--source/blender/editors/sculpt_paint/paint_vertex_weight_utils.c2
-rw-r--r--source/blender/editors/sculpt_paint/sculpt.c5166
-rw-r--r--source/blender/editors/sculpt_paint/sculpt_automasking.c304
-rw-r--r--source/blender/editors/sculpt_paint/sculpt_cloth.c375
-rw-r--r--source/blender/editors/sculpt_paint/sculpt_detail.c428
-rw-r--r--source/blender/editors/sculpt_paint/sculpt_dyntopo.c439
-rw-r--r--source/blender/editors/sculpt_paint/sculpt_face_set.c980
-rw-r--r--source/blender/editors/sculpt_paint/sculpt_filter_mask.c502
-rw-r--r--source/blender/editors/sculpt_paint/sculpt_filter_mesh.c660
-rw-r--r--source/blender/editors/sculpt_paint/sculpt_intern.h270
-rw-r--r--source/blender/editors/sculpt_paint/sculpt_mask_expand.c526
-rw-r--r--source/blender/editors/sculpt_paint/sculpt_multiplane_scrape.c16
-rw-r--r--source/blender/editors/sculpt_paint/sculpt_pose.c587
-rw-r--r--source/blender/editors/sculpt_paint/sculpt_smooth.c608
-rw-r--r--source/blender/editors/sculpt_paint/sculpt_transform.c381
-rw-r--r--source/blender/editors/sculpt_paint/sculpt_undo.c465
-rw-r--r--source/blender/editors/sculpt_paint/sculpt_uv.c15
-rw-r--r--source/blender/editors/sound/sound_ops.c4
-rw-r--r--source/blender/editors/space_action/action_data.c54
-rw-r--r--source/blender/editors/space_action/action_draw.c23
-rw-r--r--source/blender/editors/space_action/action_edit.c10
-rw-r--r--source/blender/editors/space_action/action_select.c12
-rw-r--r--source/blender/editors/space_action/space_action.c96
-rw-r--r--source/blender/editors/space_api/spacetypes.c5
-rw-r--r--source/blender/editors/space_buttons/buttons_context.c10
-rw-r--r--source/blender/editors/space_buttons/buttons_ops.c6
-rw-r--r--source/blender/editors/space_buttons/buttons_texture.c8
-rw-r--r--source/blender/editors/space_buttons/space_buttons.c104
-rw-r--r--source/blender/editors/space_clip/clip_buttons.c2
-rw-r--r--source/blender/editors/space_clip/clip_dopesheet_draw.c8
-rw-r--r--source/blender/editors/space_clip/clip_dopesheet_ops.c2
-rw-r--r--source/blender/editors/space_clip/clip_draw.c78
-rw-r--r--source/blender/editors/space_clip/clip_editor.c44
-rw-r--r--source/blender/editors/space_clip/clip_graph_draw.c49
-rw-r--r--source/blender/editors/space_clip/clip_graph_ops.c2
-rw-r--r--source/blender/editors/space_clip/clip_intern.h2
-rw-r--r--source/blender/editors/space_clip/clip_ops.c35
-rw-r--r--source/blender/editors/space_clip/clip_toolbar.c8
-rw-r--r--source/blender/editors/space_clip/clip_utils.c3
-rw-r--r--source/blender/editors/space_clip/space_clip.c242
-rw-r--r--source/blender/editors/space_clip/tracking_select.c25
-rw-r--r--source/blender/editors/space_console/console_draw.c15
-rw-r--r--source/blender/editors/space_console/console_ops.c8
-rw-r--r--source/blender/editors/space_console/space_console.c10
-rw-r--r--source/blender/editors/space_file/file_draw.c87
-rw-r--r--source/blender/editors/space_file/file_ops.c118
-rw-r--r--source/blender/editors/space_file/file_panels.c18
-rw-r--r--source/blender/editors/space_file/filelist.c179
-rw-r--r--source/blender/editors/space_file/filesel.c13
-rw-r--r--source/blender/editors/space_file/fsmenu.c7
-rw-r--r--source/blender/editors/space_file/space_file.c80
-rw-r--r--source/blender/editors/space_graph/graph_buttons.c132
-rw-r--r--source/blender/editors/space_graph/graph_draw.c12
-rw-r--r--source/blender/editors/space_graph/graph_edit.c33
-rw-r--r--source/blender/editors/space_graph/graph_select.c8
-rw-r--r--source/blender/editors/space_graph/graph_utils.c50
-rw-r--r--source/blender/editors/space_graph/space_graph.c58
-rw-r--r--source/blender/editors/space_image/image_buttons.c6
-rw-r--r--source/blender/editors/space_image/image_draw.c11
-rw-r--r--source/blender/editors/space_image/image_edit.c11
-rw-r--r--source/blender/editors/space_image/image_ops.c425
-rw-r--r--source/blender/editors/space_image/image_sequence.c23
-rw-r--r--source/blender/editors/space_image/image_undo.c41
-rw-r--r--source/blender/editors/space_image/space_image.c97
-rw-r--r--source/blender/editors/space_info/info_draw.c1
-rw-r--r--source/blender/editors/space_info/info_report.c4
-rw-r--r--source/blender/editors/space_info/info_stats.c299
-rw-r--r--source/blender/editors/space_info/space_info.c10
-rw-r--r--source/blender/editors/space_info/textview.c38
-rw-r--r--source/blender/editors/space_info/textview.h2
-rw-r--r--source/blender/editors/space_nla/nla_buttons.c69
-rw-r--r--source/blender/editors/space_nla/nla_channels.c7
-rw-r--r--source/blender/editors/space_nla/nla_draw.c14
-rw-r--r--source/blender/editors/space_nla/nla_edit.c36
-rw-r--r--source/blender/editors/space_nla/nla_select.c2
-rw-r--r--source/blender/editors/space_nla/space_nla.c41
-rw-r--r--source/blender/editors/space_node/CMakeLists.txt4
-rw-r--r--source/blender/editors/space_node/drawnode.c954
-rw-r--r--source/blender/editors/space_node/node_add.c2
-rw-r--r--source/blender/editors/space_node/node_buttons.c10
-rw-r--r--source/blender/editors/space_node/node_draw.c262
-rw-r--r--source/blender/editors/space_node/node_edit.c34
-rw-r--r--source/blender/editors/space_node/node_group.c19
-rw-r--r--source/blender/editors/space_node/node_intern.h16
-rw-r--r--source/blender/editors/space_node/node_relationships.c27
-rw-r--r--source/blender/editors/space_node/node_select.c89
-rw-r--r--source/blender/editors/space_node/node_templates.c118
-rw-r--r--source/blender/editors/space_node/node_view.c14
-rw-r--r--source/blender/editors/space_node/space_node.c112
-rw-r--r--source/blender/editors/space_outliner/outliner_collections.c77
-rw-r--r--source/blender/editors/space_outliner/outliner_dragdrop.c16
-rw-r--r--source/blender/editors/space_outliner/outliner_draw.c92
-rw-r--r--source/blender/editors/space_outliner/outliner_edit.c258
-rw-r--r--source/blender/editors/space_outliner/outliner_intern.h14
-rw-r--r--source/blender/editors/space_outliner/outliner_ops.c3
-rw-r--r--source/blender/editors/space_outliner/outliner_select.c37
-rw-r--r--source/blender/editors/space_outliner/outliner_sync.c14
-rw-r--r--source/blender/editors/space_outliner/outliner_tools.c298
-rw-r--r--source/blender/editors/space_outliner/outliner_tree.c33
-rw-r--r--source/blender/editors/space_outliner/outliner_utils.c11
-rw-r--r--source/blender/editors/space_outliner/space_outliner.c18
-rw-r--r--source/blender/editors/space_script/script_edit.c2
-rw-r--r--source/blender/editors/space_script/space_script.c4
-rw-r--r--source/blender/editors/space_sequencer/sequencer_add.c246
-rw-r--r--source/blender/editors/space_sequencer/sequencer_buttons.c2
-rw-r--r--source/blender/editors/space_sequencer/sequencer_draw.c372
-rw-r--r--source/blender/editors/space_sequencer/sequencer_edit.c812
-rw-r--r--source/blender/editors/space_sequencer/sequencer_intern.h21
-rw-r--r--source/blender/editors/space_sequencer/sequencer_modifier.c2
-rw-r--r--source/blender/editors/space_sequencer/sequencer_ops.c2
-rw-r--r--source/blender/editors/space_sequencer/sequencer_preview.c16
-rw-r--r--source/blender/editors/space_sequencer/sequencer_scopes.c159
-rw-r--r--source/blender/editors/space_sequencer/sequencer_select.c167
-rw-r--r--source/blender/editors/space_sequencer/sequencer_view.c229
-rw-r--r--source/blender/editors/space_sequencer/space_sequencer.c221
-rw-r--r--source/blender/editors/space_statusbar/space_statusbar.c6
-rw-r--r--source/blender/editors/space_text/space_text.c30
-rw-r--r--source/blender/editors/space_text/text_autocomplete.c6
-rw-r--r--source/blender/editors/space_text/text_draw.c8
-rw-r--r--source/blender/editors/space_text/text_format.c2
-rw-r--r--source/blender/editors/space_text/text_header.c12
-rw-r--r--source/blender/editors/space_text/text_intern.h6
-rw-r--r--source/blender/editors/space_text/text_ops.c3
-rw-r--r--source/blender/editors/space_topbar/space_topbar.c8
-rw-r--r--source/blender/editors/space_userpref/space_userpref.c10
-rw-r--r--source/blender/editors/space_userpref/userpref_ops.c69
-rw-r--r--source/blender/editors/space_view3d/CMakeLists.txt1
-rw-r--r--source/blender/editors/space_view3d/space_view3d.c104
-rw-r--r--source/blender/editors/space_view3d/view3d_buttons.c22
-rw-r--r--source/blender/editors/space_view3d/view3d_draw.c32
-rw-r--r--source/blender/editors/space_view3d/view3d_edit.c104
-rw-r--r--source/blender/editors/space_view3d/view3d_fly.c4
-rw-r--r--source/blender/editors/space_view3d/view3d_gizmo_navigate.c8
-rw-r--r--source/blender/editors/space_view3d/view3d_gizmo_navigate_type.c22
-rw-r--r--source/blender/editors/space_view3d/view3d_gizmo_ruler.c430
-rw-r--r--source/blender/editors/space_view3d/view3d_header.c46
-rw-r--r--source/blender/editors/space_view3d/view3d_intern.h12
-rw-r--r--source/blender/editors/space_view3d/view3d_iterators.c21
-rw-r--r--source/blender/editors/space_view3d/view3d_ops.c5
-rw-r--r--source/blender/editors/space_view3d/view3d_placement.c1153
-rw-r--r--source/blender/editors/space_view3d/view3d_select.c362
-rw-r--r--source/blender/editors/space_view3d/view3d_utils.c68
-rw-r--r--source/blender/editors/space_view3d/view3d_view.c75
-rw-r--r--source/blender/editors/space_view3d/view3d_walk.c30
-rw-r--r--source/blender/editors/transform/transform.c503
-rw-r--r--source/blender/editors/transform/transform.h139
-rw-r--r--source/blender/editors/transform/transform_constraints.c287
-rw-r--r--source/blender/editors/transform/transform_constraints.h5
-rw-r--r--source/blender/editors/transform/transform_convert.c424
-rw-r--r--source/blender/editors/transform/transform_convert.h12
-rw-r--r--source/blender/editors/transform/transform_convert_action.c5
-rw-r--r--source/blender/editors/transform/transform_convert_armature.c106
-rw-r--r--source/blender/editors/transform/transform_convert_cursor.c2
-rw-r--r--source/blender/editors/transform/transform_convert_curve.c19
-rw-r--r--source/blender/editors/transform/transform_convert_graph.c11
-rw-r--r--source/blender/editors/transform/transform_convert_mask.c6
-rw-r--r--source/blender/editors/transform/transform_convert_mesh.c144
-rw-r--r--source/blender/editors/transform/transform_convert_nla.c5
-rw-r--r--source/blender/editors/transform/transform_convert_node.c4
-rw-r--r--source/blender/editors/transform/transform_convert_object.c20
-rw-r--r--source/blender/editors/transform/transform_convert_sequencer.c18
-rw-r--r--source/blender/editors/transform/transform_convert_tracking.c2
-rw-r--r--source/blender/editors/transform/transform_draw_cursors.c2
-rw-r--r--source/blender/editors/transform/transform_generics.c287
-rw-r--r--source/blender/editors/transform/transform_gizmo_2d.c38
-rw-r--r--source/blender/editors/transform/transform_gizmo_3d.c175
-rw-r--r--source/blender/editors/transform/transform_mode.c20
-rw-r--r--source/blender/editors/transform/transform_mode.h1
-rw-r--r--source/blender/editors/transform/transform_mode_align.c6
-rw-r--r--source/blender/editors/transform/transform_mode_baketime.c6
-rw-r--r--source/blender/editors/transform/transform_mode_bbone_resize.c6
-rw-r--r--source/blender/editors/transform/transform_mode_bend.c9
-rw-r--r--source/blender/editors/transform/transform_mode_boneenvelope.c6
-rw-r--r--source/blender/editors/transform/transform_mode_boneroll.c6
-rw-r--r--source/blender/editors/transform/transform_mode_curveshrinkfatten.c6
-rw-r--r--source/blender/editors/transform/transform_mode_edge_bevelweight.c6
-rw-r--r--source/blender/editors/transform/transform_mode_edge_crease.c6
-rw-r--r--source/blender/editors/transform/transform_mode_edge_rotate_normal.c4
-rw-r--r--source/blender/editors/transform/transform_mode_edge_seq_slide.c9
-rw-r--r--source/blender/editors/transform/transform_mode_edge_slide.c10
-rw-r--r--source/blender/editors/transform/transform_mode_gpopacity.c6
-rw-r--r--source/blender/editors/transform/transform_mode_gpshrinkfatten.c6
-rw-r--r--source/blender/editors/transform/transform_mode_maskshrinkfatten.c10
-rw-r--r--source/blender/editors/transform/transform_mode_mirror.c14
-rw-r--r--source/blender/editors/transform/transform_mode_push_pull.c6
-rw-r--r--source/blender/editors/transform/transform_mode_resize.c6
-rw-r--r--source/blender/editors/transform/transform_mode_rotate.c9
-rw-r--r--source/blender/editors/transform/transform_mode_shear.c15
-rw-r--r--source/blender/editors/transform/transform_mode_shrink_fatten.c6
-rw-r--r--source/blender/editors/transform/transform_mode_skin_resize.c7
-rw-r--r--source/blender/editors/transform/transform_mode_tilt.c6
-rw-r--r--source/blender/editors/transform/transform_mode_timescale.c2
-rw-r--r--source/blender/editors/transform/transform_mode_timeslide.c6
-rw-r--r--source/blender/editors/transform/transform_mode_timetranslate.c2
-rw-r--r--source/blender/editors/transform/transform_mode_tosphere.c6
-rw-r--r--source/blender/editors/transform/transform_mode_trackball.c6
-rw-r--r--source/blender/editors/transform/transform_mode_translate.c51
-rw-r--r--source/blender/editors/transform/transform_mode_vert_slide.c2
-rw-r--r--source/blender/editors/transform/transform_ops.c34
-rw-r--r--source/blender/editors/transform/transform_orientations.c258
-rw-r--r--source/blender/editors/transform/transform_snap.c131
-rw-r--r--source/blender/editors/transform/transform_snap_object.c401
-rw-r--r--source/blender/editors/undo/ed_undo.c53
-rw-r--r--source/blender/editors/undo/memfile_undo.c38
-rw-r--r--source/blender/editors/util/CMakeLists.txt3
-rw-r--r--source/blender/editors/util/ed_transverts.c2
-rw-r--r--source/blender/editors/util/ed_util.c17
-rw-r--r--source/blender/editors/util/ed_util_imbuf.c571
-rw-r--r--source/blender/editors/util/gizmo_utils.c4
-rw-r--r--source/blender/editors/uvedit/CMakeLists.txt1
-rw-r--r--source/blender/editors/uvedit/uvedit_buttons.c25
-rw-r--r--source/blender/editors/uvedit/uvedit_draw.c72
-rw-r--r--source/blender/editors/uvedit/uvedit_intern.h31
-rw-r--r--source/blender/editors/uvedit/uvedit_ops.c3780
-rw-r--r--source/blender/editors/uvedit/uvedit_parametrizer.c26
-rw-r--r--source/blender/editors/uvedit/uvedit_parametrizer.h4
-rw-r--r--source/blender/editors/uvedit/uvedit_select.c3371
-rw-r--r--source/blender/editors/uvedit/uvedit_smart_stitch.c47
-rw-r--r--source/blender/editors/uvedit/uvedit_unwrap_ops.c10
-rw-r--r--source/blender/freestyle/FRS_precomp.h31
-rw-r--r--source/blender/freestyle/intern/application/AppCanvas.cpp11
-rw-r--r--source/blender/freestyle/intern/application/AppConfig.h5
-rw-r--r--source/blender/freestyle/intern/application/AppView.cpp9
-rw-r--r--source/blender/freestyle/intern/application/AppView.h5
-rw-r--r--source/blender/freestyle/intern/application/Controller.cpp25
-rw-r--r--source/blender/freestyle/intern/blender_interface/BlenderFileLoader.cpp5
-rw-r--r--source/blender/freestyle/intern/blender_interface/BlenderFileLoader.h6
-rw-r--r--source/blender/freestyle/intern/blender_interface/BlenderStrokeRenderer.cpp32
-rw-r--r--source/blender/freestyle/intern/blender_interface/BlenderStrokeRenderer.h6
-rw-r--r--source/blender/freestyle/intern/blender_interface/BlenderStyleModule.h2
-rw-r--r--source/blender/freestyle/intern/geometry/BBox.h4
-rw-r--r--source/blender/freestyle/intern/geometry/FitCurve.cpp4
-rw-r--r--source/blender/freestyle/intern/geometry/GeomCleaner.cpp4
-rw-r--r--source/blender/freestyle/intern/geometry/Grid.h2
-rw-r--r--source/blender/freestyle/intern/geometry/normal_cycle.cpp4
-rw-r--r--source/blender/freestyle/intern/image/GaussianFilter.h2
-rw-r--r--source/blender/freestyle/intern/scene_graph/NodeViewLayer.h2
-rw-r--r--source/blender/freestyle/intern/stroke/Canvas.cpp8
-rw-r--r--source/blender/freestyle/intern/stroke/Chain.cpp4
-rw-r--r--source/blender/freestyle/intern/stroke/ChainingIterators.h4
-rw-r--r--source/blender/freestyle/intern/stroke/Curve.cpp4
-rw-r--r--source/blender/freestyle/intern/stroke/CurveAdvancedIterators.h1
-rw-r--r--source/blender/freestyle/intern/stroke/Operators.cpp6
-rw-r--r--source/blender/freestyle/intern/stroke/PSStrokeRenderer.cpp4
-rw-r--r--source/blender/freestyle/intern/stroke/Predicates1D.h4
-rw-r--r--source/blender/freestyle/intern/stroke/Stroke.cpp4
-rw-r--r--source/blender/freestyle/intern/stroke/StrokeAdvancedIterators.h1
-rw-r--r--source/blender/freestyle/intern/stroke/StrokeLayer.cpp4
-rw-r--r--source/blender/freestyle/intern/stroke/StrokeRenderer.h4
-rw-r--r--source/blender/freestyle/intern/stroke/StrokeRep.cpp6
-rw-r--r--source/blender/freestyle/intern/stroke/StrokeRep.h2
-rw-r--r--source/blender/freestyle/intern/stroke/StrokeTesselator.cpp6
-rw-r--r--source/blender/freestyle/intern/stroke/TextStrokeRenderer.h6
-rw-r--r--source/blender/freestyle/intern/system/PythonInterpreter.h4
-rw-r--r--source/blender/freestyle/intern/system/StringUtils.cpp6
-rw-r--r--source/blender/freestyle/intern/system/StringUtils.h4
-rw-r--r--source/blender/freestyle/intern/view_map/GridDensityProvider.h4
-rw-r--r--source/blender/freestyle/intern/view_map/Silhouette.h8
-rw-r--r--source/blender/freestyle/intern/view_map/SilhouetteGeomEngine.cpp4
-rw-r--r--source/blender/freestyle/intern/view_map/SphericalGrid.h4
-rw-r--r--source/blender/freestyle/intern/view_map/SteerableViewMap.cpp6
-rw-r--r--source/blender/freestyle/intern/view_map/ViewMap.cpp4
-rw-r--r--source/blender/freestyle/intern/view_map/ViewMapAdvancedIterators.h1
-rw-r--r--source/blender/freestyle/intern/view_map/ViewMapBuilder.cpp6
-rw-r--r--source/blender/freestyle/intern/view_map/ViewMapTesselator.h4
-rw-r--r--source/blender/freestyle/intern/winged_edge/Curvature.cpp40
-rw-r--r--source/blender/freestyle/intern/winged_edge/WFillGrid.cpp4
-rw-r--r--source/blender/freestyle/intern/winged_edge/WSFillGrid.cpp4
-rw-r--r--source/blender/freestyle/intern/winged_edge/WXEdgeBuilder.cpp4
-rw-r--r--source/blender/gpencil_modifiers/CMakeLists.txt1
-rw-r--r--source/blender/gpencil_modifiers/MOD_gpencil_modifiertypes.h1
-rw-r--r--source/blender/gpencil_modifiers/intern/MOD_gpencil_util.c11
-rw-r--r--source/blender/gpencil_modifiers/intern/MOD_gpencil_util.h2
-rw-r--r--source/blender/gpencil_modifiers/intern/MOD_gpencilarmature.c6
-rw-r--r--source/blender/gpencil_modifiers/intern/MOD_gpencilarray.c18
-rw-r--r--source/blender/gpencil_modifiers/intern/MOD_gpencilbuild.c12
-rw-r--r--source/blender/gpencil_modifiers/intern/MOD_gpencilcolor.c20
-rw-r--r--source/blender/gpencil_modifiers/intern/MOD_gpencilhook.c21
-rw-r--r--source/blender/gpencil_modifiers/intern/MOD_gpencillattice.c21
-rw-r--r--source/blender/gpencil_modifiers/intern/MOD_gpencilmirror.c95
-rw-r--r--source/blender/gpencil_modifiers/intern/MOD_gpencilmultiply.c18
-rw-r--r--source/blender/gpencil_modifiers/intern/MOD_gpencilnoise.c26
-rw-r--r--source/blender/gpencil_modifiers/intern/MOD_gpenciloffset.c21
-rw-r--r--source/blender/gpencil_modifiers/intern/MOD_gpencilopacity.c25
-rw-r--r--source/blender/gpencil_modifiers/intern/MOD_gpencilsimplify.c20
-rw-r--r--source/blender/gpencil_modifiers/intern/MOD_gpencilsmooth.c21
-rw-r--r--source/blender/gpencil_modifiers/intern/MOD_gpencilsubdiv.c20
-rw-r--r--source/blender/gpencil_modifiers/intern/MOD_gpenciltexture.c172
-rw-r--r--source/blender/gpencil_modifiers/intern/MOD_gpencilthick.c23
-rw-r--r--source/blender/gpencil_modifiers/intern/MOD_gpenciltime.c5
-rw-r--r--source/blender/gpencil_modifiers/intern/MOD_gpenciltint.c21
-rw-r--r--source/blender/gpu/CMakeLists.txt11
-rw-r--r--source/blender/gpu/GPU_batch_presets.h4
-rw-r--r--source/blender/gpu/GPU_buffers.h11
-rw-r--r--source/blender/gpu/GPU_context.h8
-rw-r--r--source/blender/gpu/GPU_draw.h15
-rw-r--r--source/blender/gpu/GPU_immediate_util.h7
-rw-r--r--source/blender/gpu/GPU_init_exit.h4
-rw-r--r--source/blender/gpu/GPU_material.h14
-rw-r--r--source/blender/gpu/GPU_shader.h73
-rw-r--r--source/blender/gpu/GPU_shader_interface.h58
-rw-r--r--source/blender/gpu/GPU_state.h6
-rw-r--r--source/blender/gpu/GPU_texture.h32
-rw-r--r--source/blender/gpu/GPU_vertex_format.h11
-rw-r--r--source/blender/gpu/intern/gpu_batch.c52
-rw-r--r--source/blender/gpu/intern/gpu_batch_presets.c150
-rw-r--r--source/blender/gpu/intern/gpu_batch_private.h8
-rw-r--r--source/blender/gpu/intern/gpu_buffers.c347
-rw-r--r--source/blender/gpu/intern/gpu_codegen.c26
-rw-r--r--source/blender/gpu/intern/gpu_context_private.h4
-rw-r--r--source/blender/gpu/intern/gpu_draw.c104
-rw-r--r--source/blender/gpu/intern/gpu_extensions.c10
-rw-r--r--source/blender/gpu/intern/gpu_framebuffer.c11
-rw-r--r--source/blender/gpu/intern/gpu_immediate.c136
-rw-r--r--source/blender/gpu/intern/gpu_immediate_util.c26
-rw-r--r--source/blender/gpu/intern/gpu_material.c12
-rw-r--r--source/blender/gpu/intern/gpu_matrix.c44
-rw-r--r--source/blender/gpu/intern/gpu_node_graph.c34
-rw-r--r--source/blender/gpu/intern/gpu_select_pick.c18
-rw-r--r--source/blender/gpu/intern/gpu_shader.c236
-rw-r--r--source/blender/gpu/intern/gpu_shader_interface.c486
-rw-r--r--source/blender/gpu/intern/gpu_state.c40
-rw-r--r--source/blender/gpu/intern/gpu_texture.c471
-rw-r--r--source/blender/gpu/intern/gpu_uniformbuffer.c6
-rw-r--r--source/blender/gpu/intern/gpu_vertex_buffer.c2
-rw-r--r--source/blender/gpu/intern/gpu_vertex_format.c125
-rw-r--r--source/blender/gpu/intern/gpu_viewport.c209
-rw-r--r--source/blender/gpu/shaders/gpu_shader_2D_smooth_color_dithered_frag.glsl18
-rw-r--r--source/blender/gpu/shaders/gpu_shader_2D_smooth_color_frag.glsl1
-rw-r--r--source/blender/gpu/shaders/gpu_shader_2D_widget_base_frag.glsl2
-rw-r--r--source/blender/gpu/shaders/gpu_shader_2D_widget_base_vert.glsl57
-rw-r--r--source/blender/gpu/shaders/gpu_shader_3D_normal_smooth_color_vert.glsl22
-rw-r--r--source/blender/gpu/shaders/gpu_shader_3D_polyline_frag.glsl24
-rw-r--r--source/blender/gpu/shaders/gpu_shader_3D_polyline_geom.glsl68
-rw-r--r--source/blender/gpu/shaders/gpu_shader_3D_polyline_vert.glsl28
-rw-r--r--source/blender/gpu/shaders/gpu_shader_3D_smooth_color_frag.glsl1
-rw-r--r--source/blender/gpu/shaders/gpu_shader_colorspace_lib.glsl16
-rw-r--r--source/blender/gpu/shaders/gpu_shader_flat_color_frag.glsl1
-rw-r--r--source/blender/gpu/shaders/gpu_shader_image_depth_copy_frag.glsl12
-rw-r--r--source/blender/gpu/shaders/gpu_shader_image_depth_linear_frag.glsl16
-rw-r--r--source/blender/gpu/shaders/gpu_shader_image_multisample_resolve_frag.glsl119
-rw-r--r--source/blender/gpu/shaders/gpu_shader_simple_lighting_smooth_color_alpha_frag.glsl14
-rw-r--r--source/blender/gpu/shaders/gpu_shader_simple_lighting_smooth_color_frag.glsl16
-rw-r--r--source/blender/gpu/shaders/gpu_shader_uniform_color_frag.glsl5
-rw-r--r--source/blender/gpu/shaders/material/gpu_shader_material_fractal_noise.glsl52
-rw-r--r--source/blender/gpu/shaders/material/gpu_shader_material_output_material.glsl10
-rw-r--r--source/blender/gpu/shaders/material/gpu_shader_material_tex_environment.glsl7
-rw-r--r--source/blender/gpu/shaders/material/gpu_shader_material_tex_image.glsl168
-rw-r--r--source/blender/gpu/shaders/material/gpu_shader_material_tex_noise.glsl64
-rw-r--r--source/blender/gpu/shaders/material/gpu_shader_material_tex_wave.glsl5
-rw-r--r--source/blender/ikplugin/intern/iksolver_plugin.c2
-rw-r--r--source/blender/ikplugin/intern/itasc_plugin.cpp2
-rw-r--r--source/blender/imbuf/IMB_colormanagement.h1
-rw-r--r--source/blender/imbuf/intern/IMB_allocimbuf.h8
-rw-r--r--source/blender/imbuf/intern/IMB_colormanagement_intern.h8
-rw-r--r--source/blender/imbuf/intern/allocimbuf.c2
-rw-r--r--source/blender/imbuf/intern/anim_movie.c2
-rw-r--r--source/blender/imbuf/intern/cache.c4
-rw-r--r--source/blender/imbuf/intern/cineon/cineonlib.h4
-rw-r--r--source/blender/imbuf/intern/cineon/dpxlib.h4
-rw-r--r--source/blender/imbuf/intern/colormanagement.c17
-rw-r--r--source/blender/imbuf/intern/dds/dds_api.cpp6
-rw-r--r--source/blender/imbuf/intern/dds/dds_api.h4
-rw-r--r--source/blender/imbuf/intern/divers.c2
-rw-r--r--source/blender/imbuf/intern/imageprocess.c25
-rw-r--r--source/blender/imbuf/intern/oiio/openimageio_api.cpp2
-rw-r--r--source/blender/imbuf/intern/oiio/openimageio_api.h4
-rw-r--r--source/blender/imbuf/intern/openexr/openexr_api.cpp20
-rw-r--r--source/blender/imbuf/intern/openexr/openexr_api.h4
-rw-r--r--source/blender/imbuf/intern/png.c54
-rw-r--r--source/blender/imbuf/intern/thumbs.c105
-rw-r--r--source/blender/io/alembic/CMakeLists.txt2
-rw-r--r--source/blender/io/alembic/intern/abc_axis_conversion.cc166
-rw-r--r--source/blender/io/alembic/intern/abc_axis_conversion.h99
-rw-r--r--source/blender/io/alembic/intern/abc_customdata.cc17
-rw-r--r--source/blender/io/alembic/intern/abc_customdata.h17
-rw-r--r--source/blender/io/alembic/intern/abc_exporter.cc6
-rw-r--r--source/blender/io/alembic/intern/abc_reader_archive.cc4
-rw-r--r--source/blender/io/alembic/intern/abc_reader_archive.h2
-rw-r--r--source/blender/io/alembic/intern/abc_reader_camera.cc2
-rw-r--r--source/blender/io/alembic/intern/abc_reader_curves.cc5
-rw-r--r--source/blender/io/alembic/intern/abc_reader_curves.h2
-rw-r--r--source/blender/io/alembic/intern/abc_reader_mesh.cc32
-rw-r--r--source/blender/io/alembic/intern/abc_reader_nurbs.cc5
-rw-r--r--source/blender/io/alembic/intern/abc_reader_object.cc5
-rw-r--r--source/blender/io/alembic/intern/abc_reader_object.h2
-rw-r--r--source/blender/io/alembic/intern/abc_reader_points.cc4
-rw-r--r--source/blender/io/alembic/intern/abc_reader_points.h2
-rw-r--r--source/blender/io/alembic/intern/abc_reader_transform.cc2
-rw-r--r--source/blender/io/alembic/intern/abc_util.cc141
-rw-r--r--source/blender/io/alembic/intern/abc_util.h69
-rw-r--r--source/blender/io/alembic/intern/abc_writer_archive.cc7
-rw-r--r--source/blender/io/alembic/intern/abc_writer_archive.h2
-rw-r--r--source/blender/io/alembic/intern/abc_writer_camera.cc2
-rw-r--r--source/blender/io/alembic/intern/abc_writer_curves.cc5
-rw-r--r--source/blender/io/alembic/intern/abc_writer_curves.h2
-rw-r--r--source/blender/io/alembic/intern/abc_writer_hair.cc4
-rw-r--r--source/blender/io/alembic/intern/abc_writer_mball.cc2
-rw-r--r--source/blender/io/alembic/intern/abc_writer_mesh.cc17
-rw-r--r--source/blender/io/alembic/intern/abc_writer_nurbs.cc4
-rw-r--r--source/blender/io/alembic/intern/abc_writer_object.cc2
-rw-r--r--source/blender/io/alembic/intern/abc_writer_object.h2
-rw-r--r--source/blender/io/alembic/intern/abc_writer_points.cc4
-rw-r--r--source/blender/io/alembic/intern/abc_writer_points.h2
-rw-r--r--source/blender/io/alembic/intern/abc_writer_transform.cc4
-rw-r--r--source/blender/io/alembic/intern/alembic_capi.cc5
-rw-r--r--source/blender/io/avi/intern/avi_mjpeg.c37
-rw-r--r--source/blender/io/collada/AnimationExporter.h3
-rw-r--r--source/blender/io/collada/AnimationImporter.cpp8
-rw-r--r--source/blender/io/collada/AnimationImporter.h4
-rw-r--r--source/blender/io/collada/ArmatureExporter.cpp3
-rw-r--r--source/blender/io/collada/ArmatureImporter.cpp4
-rw-r--r--source/blender/io/collada/ArmatureImporter.h2
-rw-r--r--source/blender/io/collada/BCAnimationCurve.cpp4
-rw-r--r--source/blender/io/collada/BCAnimationCurve.h3
-rw-r--r--source/blender/io/collada/BCAnimationSampler.cpp7
-rw-r--r--source/blender/io/collada/BCAnimationSampler.h4
-rw-r--r--source/blender/io/collada/BCMath.h3
-rw-r--r--source/blender/io/collada/BCSampleData.h4
-rw-r--r--source/blender/io/collada/BlenderContext.h9
-rw-r--r--source/blender/io/collada/CameraExporter.cpp3
-rw-r--r--source/blender/io/collada/CameraExporter.h2
-rw-r--r--source/blender/io/collada/ControllerExporter.cpp3
-rw-r--r--source/blender/io/collada/DocumentExporter.cpp21
-rw-r--r--source/blender/io/collada/DocumentExporter.h2
-rw-r--r--source/blender/io/collada/DocumentImporter.cpp2
-rw-r--r--source/blender/io/collada/EffectExporter.cpp2
-rw-r--r--source/blender/io/collada/ErrorHandler.h2
-rw-r--r--source/blender/io/collada/ExportSettings.h6
-rw-r--r--source/blender/io/collada/GeometryExporter.cpp2
-rw-r--r--source/blender/io/collada/ImageExporter.cpp4
-rw-r--r--source/blender/io/collada/InstanceWriter.cpp3
-rw-r--r--source/blender/io/collada/MaterialExporter.h3
-rw-r--r--source/blender/io/collada/Materials.h2
-rw-r--r--source/blender/io/collada/MeshImporter.cpp2
-rw-r--r--source/blender/io/collada/MeshImporter.h3
-rw-r--r--source/blender/io/collada/SceneExporter.cpp2
-rw-r--r--source/blender/io/collada/SceneExporter.h3
-rw-r--r--source/blender/io/collada/collada.cpp3
-rw-r--r--source/blender/io/collada/collada.h8
-rw-r--r--source/blender/io/collada/collada_utils.cpp2
-rw-r--r--source/blender/io/collada/collada_utils.h2
-rw-r--r--source/blender/io/usd/intern/abstract_hierarchy_iterator.cc109
-rw-r--r--source/blender/io/usd/intern/abstract_hierarchy_iterator.h18
-rw-r--r--source/blender/io/usd/intern/usd_capi.cc7
-rw-r--r--source/blender/io/usd/intern/usd_hierarchy_iterator.cc4
-rw-r--r--source/blender/io/usd/intern/usd_writer_abstract.h3
-rw-r--r--source/blender/io/usd/intern/usd_writer_camera.cc2
-rw-r--r--source/blender/io/usd/intern/usd_writer_hair.cc2
-rw-r--r--source/blender/io/usd/intern/usd_writer_light.cc2
-rw-r--r--source/blender/io/usd/intern/usd_writer_mesh.cc11
-rw-r--r--source/blender/io/usd/intern/usd_writer_metaball.cc2
-rw-r--r--source/blender/io/usd/intern/usd_writer_transform.cc4
-rw-r--r--source/blender/io/usd/usd.h4
-rw-r--r--source/blender/makesdna/DNA_ID.h56
-rw-r--r--source/blender/makesdna/DNA_action_types.h8
-rw-r--r--source/blender/makesdna/DNA_anim_types.h8
-rw-r--r--source/blender/makesdna/DNA_armature_types.h18
-rw-r--r--source/blender/makesdna/DNA_brush_types.h67
-rw-r--r--source/blender/makesdna/DNA_constraint_types.h36
-rw-r--r--source/blender/makesdna/DNA_curve_types.h4
-rw-r--r--source/blender/makesdna/DNA_customdata_types.h12
-rw-r--r--source/blender/makesdna/DNA_defaults.h4
-rw-r--r--source/blender/makesdna/DNA_dynamicpaint_types.h2
-rw-r--r--source/blender/makesdna/DNA_fluid_types.h73
-rw-r--r--source/blender/makesdna/DNA_gpencil_modifier_types.h118
-rw-r--r--source/blender/makesdna/DNA_gpencil_types.h55
-rw-r--r--source/blender/makesdna/DNA_layer_types.h8
-rw-r--r--source/blender/makesdna/DNA_lightprobe_types.h2
-rw-r--r--source/blender/makesdna/DNA_material_types.h22
-rw-r--r--source/blender/makesdna/DNA_mesh_types.h33
-rw-r--r--source/blender/makesdna/DNA_meshdata_types.h4
-rw-r--r--source/blender/makesdna/DNA_modifier_types.h79
-rw-r--r--source/blender/makesdna/DNA_movieclip_types.h8
-rw-r--r--source/blender/makesdna/DNA_node_types.h44
-rw-r--r--source/blender/makesdna/DNA_object_force_types.h11
-rw-r--r--source/blender/makesdna/DNA_object_types.h1
-rw-r--r--source/blender/makesdna/DNA_rigidbody_types.h42
-rw-r--r--source/blender/makesdna/DNA_scene_types.h68
-rw-r--r--source/blender/makesdna/DNA_screen_types.h24
-rw-r--r--source/blender/makesdna/DNA_sequence_types.h3
-rw-r--r--source/blender/makesdna/DNA_shader_fx_types.h1
-rw-r--r--source/blender/makesdna/DNA_simulation_defaults.h40
-rw-r--r--source/blender/makesdna/DNA_simulation_types.h41
-rw-r--r--source/blender/makesdna/DNA_sound_types.h11
-rw-r--r--source/blender/makesdna/DNA_space_types.h17
-rw-r--r--source/blender/makesdna/DNA_tracking_types.h4
-rw-r--r--source/blender/makesdna/DNA_userdef_types.h34
-rw-r--r--source/blender/makesdna/DNA_view3d_defaults.h4
-rw-r--r--source/blender/makesdna/DNA_view3d_types.h25
-rw-r--r--source/blender/makesdna/DNA_volume_types.h6
-rw-r--r--source/blender/makesdna/intern/CMakeLists.txt5
-rw-r--r--source/blender/makesdna/intern/dna_defaults.c8
-rw-r--r--source/blender/makesdna/intern/makesdna.c6
-rw-r--r--source/blender/makesrna/RNA_access.h9
-rw-r--r--source/blender/makesrna/RNA_define.h3
-rw-r--r--source/blender/makesrna/RNA_enum_types.h10
-rw-r--r--source/blender/makesrna/intern/CMakeLists.txt16
-rw-r--r--source/blender/makesrna/intern/makesrna.c44
-rw-r--r--source/blender/makesrna/intern/rna_ID.c18
-rw-r--r--source/blender/makesrna/intern/rna_access.c125
-rw-r--r--source/blender/makesrna/intern/rna_access_compare_override.c42
-rw-r--r--source/blender/makesrna/intern/rna_action.c21
-rw-r--r--source/blender/makesrna/intern/rna_animation.c47
-rw-r--r--source/blender/makesrna/intern/rna_armature.c22
-rw-r--r--source/blender/makesrna/intern/rna_brush.c218
-rw-r--r--source/blender/makesrna/intern/rna_camera.c16
-rw-r--r--source/blender/makesrna/intern/rna_cloth.c7
-rw-r--r--source/blender/makesrna/intern/rna_collection.c27
-rw-r--r--source/blender/makesrna/intern/rna_constraint.c142
-rw-r--r--source/blender/makesrna/intern/rna_define.c210
-rw-r--r--source/blender/makesrna/intern/rna_depsgraph.c13
-rw-r--r--source/blender/makesrna/intern/rna_fcurve.c7
-rw-r--r--source/blender/makesrna/intern/rna_fcurve_api.c1
-rw-r--r--source/blender/makesrna/intern/rna_fluid.c388
-rw-r--r--source/blender/makesrna/intern/rna_gpencil.c38
-rw-r--r--source/blender/makesrna/intern/rna_gpencil_modifier.c275
-rw-r--r--source/blender/makesrna/intern/rna_image.c4
-rw-r--r--source/blender/makesrna/intern/rna_internal.h11
-rw-r--r--source/blender/makesrna/intern/rna_key.c3
-rw-r--r--source/blender/makesrna/intern/rna_layer.c17
-rw-r--r--source/blender/makesrna/intern/rna_light.c60
-rw-r--r--source/blender/makesrna/intern/rna_main.c11
-rw-r--r--source/blender/makesrna/intern/rna_main_api.c57
-rw-r--r--source/blender/makesrna/intern/rna_material.c19
-rw-r--r--source/blender/makesrna/intern/rna_modifier.c566
-rw-r--r--source/blender/makesrna/intern/rna_nla.c4
-rw-r--r--source/blender/makesrna/intern/rna_nodetree.c532
-rw-r--r--source/blender/makesrna/intern/rna_object.c115
-rw-r--r--source/blender/makesrna/intern/rna_object_api.c22
-rw-r--r--source/blender/makesrna/intern/rna_object_force.c28
-rw-r--r--source/blender/makesrna/intern/rna_particle.c6
-rw-r--r--source/blender/makesrna/intern/rna_pose.c13
-rw-r--r--source/blender/makesrna/intern/rna_render.c147
-rw-r--r--source/blender/makesrna/intern/rna_scene.c116
-rw-r--r--source/blender/makesrna/intern/rna_scene_api.c7
-rw-r--r--source/blender/makesrna/intern/rna_screen.c72
-rw-r--r--source/blender/makesrna/intern/rna_sculpt_paint.c46
-rw-r--r--source/blender/makesrna/intern/rna_sequencer.c170
-rw-r--r--source/blender/makesrna/intern/rna_sequencer_api.c4
-rw-r--r--source/blender/makesrna/intern/rna_shader_fx.c2
-rw-r--r--source/blender/makesrna/intern/rna_simulation.c56
-rw-r--r--source/blender/makesrna/intern/rna_sound_api.c2
-rw-r--r--source/blender/makesrna/intern/rna_space.c277
-rw-r--r--source/blender/makesrna/intern/rna_space_api.c20
-rw-r--r--source/blender/makesrna/intern/rna_texture.c6
-rw-r--r--source/blender/makesrna/intern/rna_tracking.c15
-rw-r--r--source/blender/makesrna/intern/rna_ui.c175
-rw-r--r--source/blender/makesrna/intern/rna_ui_api.c48
-rw-r--r--source/blender/makesrna/intern/rna_userdef.c78
-rw-r--r--source/blender/makesrna/intern/rna_vfont_api.c2
-rw-r--r--source/blender/makesrna/intern/rna_volume.c27
-rw-r--r--source/blender/makesrna/intern/rna_wm.c136
-rw-r--r--source/blender/makesrna/intern/rna_wm_api.c5
-rw-r--r--source/blender/makesrna/intern/rna_wm_gizmo.c122
-rw-r--r--source/blender/makesrna/intern/rna_workspace.c2
-rw-r--r--source/blender/makesrna/intern/rna_xr.c18
-rw-r--r--source/blender/modifiers/CMakeLists.txt1
-rw-r--r--source/blender/modifiers/MOD_modifiertypes.h1
-rw-r--r--source/blender/modifiers/intern/MOD_armature.c18
-rw-r--r--source/blender/modifiers/intern/MOD_array.c47
-rw-r--r--source/blender/modifiers/intern/MOD_bevel.c13
-rw-r--r--source/blender/modifiers/intern/MOD_boolean.c13
-rw-r--r--source/blender/modifiers/intern/MOD_build.c11
-rw-r--r--source/blender/modifiers/intern/MOD_cast.c20
-rw-r--r--source/blender/modifiers/intern/MOD_cloth.c7
-rw-r--r--source/blender/modifiers/intern/MOD_collision.c9
-rw-r--r--source/blender/modifiers/intern/MOD_correctivesmooth.c31
-rw-r--r--source/blender/modifiers/intern/MOD_curve.c16
-rw-r--r--source/blender/modifiers/intern/MOD_datatransfer.c20
-rw-r--r--source/blender/modifiers/intern/MOD_decimate.c15
-rw-r--r--source/blender/modifiers/intern/MOD_displace.c43
-rw-r--r--source/blender/modifiers/intern/MOD_dynamicpaint.c13
-rw-r--r--source/blender/modifiers/intern/MOD_edgesplit.c11
-rw-r--r--source/blender/modifiers/intern/MOD_explode.c11
-rw-r--r--source/blender/modifiers/intern/MOD_fluid.c11
-rw-r--r--source/blender/modifiers/intern/MOD_hook.c11
-rw-r--r--source/blender/modifiers/intern/MOD_laplaciandeform.c29
-rw-r--r--source/blender/modifiers/intern/MOD_laplaciansmooth.c14
-rw-r--r--source/blender/modifiers/intern/MOD_lattice.c16
-rw-r--r--source/blender/modifiers/intern/MOD_mask.cc22
-rw-r--r--source/blender/modifiers/intern/MOD_meshcache.c17
-rw-r--r--source/blender/modifiers/intern/MOD_meshdeform.c30
-rw-r--r--source/blender/modifiers/intern/MOD_meshsequencecache.c14
-rw-r--r--source/blender/modifiers/intern/MOD_mirror.c11
-rw-r--r--source/blender/modifiers/intern/MOD_multires.c19
-rw-r--r--source/blender/modifiers/intern/MOD_none.c5
-rw-r--r--source/blender/modifiers/intern/MOD_normal_edit.c15
-rw-r--r--source/blender/modifiers/intern/MOD_ocean.c13
-rw-r--r--source/blender/modifiers/intern/MOD_particleinstance.c13
-rw-r--r--source/blender/modifiers/intern/MOD_particlesystem.c15
-rw-r--r--source/blender/modifiers/intern/MOD_remesh.c95
-rw-r--r--source/blender/modifiers/intern/MOD_screw.c20
-rw-r--r--source/blender/modifiers/intern/MOD_shapekey.c9
-rw-r--r--source/blender/modifiers/intern/MOD_shrinkwrap.c16
-rw-r--r--source/blender/modifiers/intern/MOD_simpledeform.c16
-rw-r--r--source/blender/modifiers/intern/MOD_simulation.cc109
-rw-r--r--source/blender/modifiers/intern/MOD_skin.c23
-rw-r--r--source/blender/modifiers/intern/MOD_smooth.c12
-rw-r--r--source/blender/modifiers/intern/MOD_softbody.c9
-rw-r--r--source/blender/modifiers/intern/MOD_solidify.c20
-rw-r--r--source/blender/modifiers/intern/MOD_solidify_extrude.c324
-rw-r--r--source/blender/modifiers/intern/MOD_solidify_nonmanifold.c260
-rw-r--r--source/blender/modifiers/intern/MOD_solidify_util.h12
-rw-r--r--source/blender/modifiers/intern/MOD_subsurf.c15
-rw-r--r--source/blender/modifiers/intern/MOD_surface.c9
-rw-r--r--source/blender/modifiers/intern/MOD_surfacedeform.c159
-rw-r--r--source/blender/modifiers/intern/MOD_triangulate.c11
-rw-r--r--source/blender/modifiers/intern/MOD_util.c48
-rw-r--r--source/blender/modifiers/intern/MOD_util.h4
-rw-r--r--source/blender/modifiers/intern/MOD_uvproject.c11
-rw-r--r--source/blender/modifiers/intern/MOD_uvwarp.c31
-rw-r--r--source/blender/modifiers/intern/MOD_warp.c67
-rw-r--r--source/blender/modifiers/intern/MOD_wave.c39
-rw-r--r--source/blender/modifiers/intern/MOD_weighted_normal.c13
-rw-r--r--source/blender/modifiers/intern/MOD_weightvg_util.c35
-rw-r--r--source/blender/modifiers/intern/MOD_weightvg_util.h6
-rw-r--r--source/blender/modifiers/intern/MOD_weightvgedit.c40
-rw-r--r--source/blender/modifiers/intern/MOD_weightvgmix.c64
-rw-r--r--source/blender/modifiers/intern/MOD_weightvgproximity.c40
-rw-r--r--source/blender/modifiers/intern/MOD_weld.c116
-rw-r--r--source/blender/modifiers/intern/MOD_wireframe.c13
-rw-r--r--source/blender/nodes/CMakeLists.txt29
-rw-r--r--source/blender/nodes/NOD_common.h8
-rw-r--r--source/blender/nodes/NOD_function.h34
-rw-r--r--source/blender/nodes/NOD_simulation.h47
-rw-r--r--source/blender/nodes/NOD_static_types.h20
-rw-r--r--source/blender/nodes/composite/node_composite_tree.c2
-rw-r--r--source/blender/nodes/composite/nodes/node_composite_common.c6
-rw-r--r--source/blender/nodes/composite/nodes/node_composite_image.c9
-rw-r--r--source/blender/nodes/function/node_function_util.cc30
-rw-r--r--source/blender/nodes/function/node_function_util.h40
-rw-r--r--source/blender/nodes/function/nodes/node_fn_boolean_math.cc62
-rw-r--r--source/blender/nodes/function/nodes/node_fn_combine_strings.cc21
-rw-r--r--source/blender/nodes/function/nodes/node_fn_float_compare.cc66
-rw-r--r--source/blender/nodes/function/nodes/node_fn_group_instance_id.cc15
-rw-r--r--source/blender/nodes/function/nodes/node_fn_switch.cc76
-rw-r--r--source/blender/nodes/intern/node_common.h8
-rw-r--r--source/blender/nodes/intern/node_socket.c54
-rw-r--r--source/blender/nodes/intern/node_util.h8
-rw-r--r--source/blender/nodes/shader/node_shader_tree.c26
-rw-r--r--source/blender/nodes/shader/node_shader_util.c11
-rw-r--r--source/blender/nodes/shader/node_shader_util.h2
-rw-r--r--source/blender/nodes/shader/nodes/node_shader_brightness.c2
-rw-r--r--source/blender/nodes/shader/nodes/node_shader_clamp.c2
-rw-r--r--source/blender/nodes/shader/nodes/node_shader_common.c6
-rw-r--r--source/blender/nodes/shader/nodes/node_shader_displacement.c2
-rw-r--r--source/blender/nodes/shader/nodes/node_shader_gamma.c2
-rw-r--r--source/blender/nodes/shader/nodes/node_shader_hueSatVal.c2
-rw-r--r--source/blender/nodes/shader/nodes/node_shader_invert.c2
-rw-r--r--source/blender/nodes/shader/nodes/node_shader_map_range.c2
-rw-r--r--source/blender/nodes/shader/nodes/node_shader_math.c2
-rw-r--r--source/blender/nodes/shader/nodes/node_shader_mixRgb.c2
-rw-r--r--source/blender/nodes/shader/nodes/node_shader_output_material.c13
-rw-r--r--source/blender/nodes/shader/nodes/node_shader_sepcombHSV.c4
-rw-r--r--source/blender/nodes/shader/nodes/node_shader_sepcombRGB.c4
-rw-r--r--source/blender/nodes/shader/nodes/node_shader_sepcombXYZ.c4
-rw-r--r--source/blender/nodes/shader/nodes/node_shader_tex_brick.c2
-rw-r--r--source/blender/nodes/shader/nodes/node_shader_tex_environment.c56
-rw-r--r--source/blender/nodes/shader/nodes/node_shader_tex_image.c159
-rw-r--r--source/blender/nodes/shader/nodes/node_shader_tex_musgrave.c3
-rw-r--r--source/blender/nodes/shader/nodes/node_shader_tex_noise.c3
-rw-r--r--source/blender/nodes/shader/nodes/node_shader_tex_wave.c1
-rw-r--r--source/blender/nodes/shader/nodes/node_shader_tex_white_noise.c3
-rw-r--r--source/blender/nodes/shader/nodes/node_shader_valToRgb.c2
-rw-r--r--source/blender/nodes/shader/nodes/node_shader_vector_math.c2
-rw-r--r--source/blender/nodes/shader/nodes/node_shader_volume_principled.c4
-rw-r--r--source/blender/nodes/simulation/node_simulation_tree.cc45
-rw-r--r--source/blender/nodes/simulation/node_simulation_util.cc29
-rw-r--r--source/blender/nodes/simulation/node_simulation_util.h40
-rw-r--r--source/blender/nodes/simulation/nodes/node_sim_common.cc45
-rw-r--r--source/blender/nodes/simulation/nodes/node_sim_emit_particles.cc38
-rw-r--r--source/blender/nodes/simulation/nodes/node_sim_execute_condition.cc39
-rw-r--r--source/blender/nodes/simulation/nodes/node_sim_force.cc36
-rw-r--r--source/blender/nodes/simulation/nodes/node_sim_multi_execute.cc38
-rw-r--r--source/blender/nodes/simulation/nodes/node_sim_particle_attribute.cc52
-rw-r--r--source/blender/nodes/simulation/nodes/node_sim_particle_birth_event.cc37
-rw-r--r--source/blender/nodes/simulation/nodes/node_sim_particle_mesh_collision_event.cc40
-rw-r--r--source/blender/nodes/simulation/nodes/node_sim_particle_mesh_emitter.cc40
-rw-r--r--source/blender/nodes/simulation/nodes/node_sim_particle_simulation.cc39
-rw-r--r--source/blender/nodes/simulation/nodes/node_sim_particle_time_step_event.cc37
-rw-r--r--source/blender/nodes/simulation/nodes/node_sim_set_particle_attribute.cc57
-rw-r--r--source/blender/nodes/simulation/nodes/node_sim_simulation_time.cc31
-rw-r--r--source/blender/nodes/texture/node_texture_tree.c4
-rw-r--r--source/blender/nodes/texture/nodes/node_texture_common.c6
-rw-r--r--source/blender/physics/intern/BPH_mass_spring.cpp2
-rw-r--r--source/blender/physics/intern/hair_volume.cpp2
-rw-r--r--source/blender/python/BPY_extern.h4
-rw-r--r--source/blender/python/generic/idprop_py_api.c71
-rw-r--r--source/blender/python/gpu/gpu_py_offscreen.c10
-rw-r--r--source/blender/python/gpu/gpu_py_shader.c12
-rw-r--r--source/blender/python/intern/CMakeLists.txt2
-rw-r--r--source/blender/python/intern/bpy.c10
-rw-r--r--source/blender/python/intern/bpy_app.c12
-rw-r--r--source/blender/python/intern/bpy_app_handlers.c12
-rw-r--r--source/blender/python/intern/bpy_capi_utils.c3
-rw-r--r--source/blender/python/intern/bpy_driver.c2
-rw-r--r--source/blender/python/intern/bpy_gizmo_wrap.c20
-rw-r--r--source/blender/python/intern/bpy_interface.c5
-rw-r--r--source/blender/python/intern/bpy_library.h6
-rw-r--r--source/blender/python/intern/bpy_library_load.c16
-rw-r--r--source/blender/python/intern/bpy_library_write.c19
-rw-r--r--source/blender/python/intern/bpy_operator_wrap.c18
-rw-r--r--source/blender/python/intern/bpy_rna.c135
-rw-r--r--source/blender/python/intern/bpy_rna.h5
-rw-r--r--source/blender/python/intern/bpy_rna_anim.c10
-rw-r--r--source/blender/python/intern/bpy_rna_callback.c8
-rw-r--r--source/blender/python/intern/bpy_rna_driver.c2
-rw-r--r--source/blender/python/intern/bpy_rna_id_collection.c47
-rw-r--r--source/blender/python/intern/bpy_rna_id_collection.h4
-rw-r--r--source/blender/python/intern/bpy_rna_types_capi.c216
-rw-r--r--source/blender/python/intern/bpy_rna_types_capi.h26
-rw-r--r--source/blender/python/mathutils/mathutils_Vector.c2
-rw-r--r--source/blender/python/mathutils/mathutils_geometry.c2
-rw-r--r--source/blender/render/CMakeLists.txt2
-rw-r--r--source/blender/render/extern/include/RE_bake.h3
-rw-r--r--source/blender/render/extern/include/RE_engine.h18
-rw-r--r--source/blender/render/extern/include/RE_pipeline.h13
-rw-r--r--source/blender/render/extern/include/RE_render_ext.h22
-rw-r--r--source/blender/render/extern/include/RE_shader_ext.h8
-rw-r--r--source/blender/render/intern/include/render_result.h11
-rw-r--r--source/blender/render/intern/source/bake_api.c13
-rw-r--r--source/blender/render/intern/source/external_engine.c154
-rw-r--r--source/blender/render/intern/source/initrender.c5
-rw-r--r--source/blender/render/intern/source/pipeline.c109
-rw-r--r--source/blender/render/intern/source/render_result.c36
-rw-r--r--source/blender/render/intern/source/render_texture.c78
-rw-r--r--source/blender/shader_fx/intern/FX_shader_blur.c4
-rw-r--r--source/blender/shader_fx/intern/FX_shader_colorize.c4
-rw-r--r--source/blender/shader_fx/intern/FX_shader_flip.c4
-rw-r--r--source/blender/shader_fx/intern/FX_shader_glow.c4
-rw-r--r--source/blender/shader_fx/intern/FX_shader_light.c4
-rw-r--r--source/blender/shader_fx/intern/FX_shader_pixel.c4
-rw-r--r--source/blender/shader_fx/intern/FX_shader_rim.c4
-rw-r--r--source/blender/shader_fx/intern/FX_shader_shadow.c4
-rw-r--r--source/blender/shader_fx/intern/FX_shader_swirl.c4
-rw-r--r--source/blender/shader_fx/intern/FX_shader_wave.c4
-rw-r--r--source/blender/windowmanager/CMakeLists.txt20
-rw-r--r--source/blender/windowmanager/WM_api.h38
-rw-r--r--source/blender/windowmanager/WM_keymap.h10
-rw-r--r--source/blender/windowmanager/WM_toolsystem.h8
-rw-r--r--source/blender/windowmanager/WM_types.h18
-rw-r--r--source/blender/windowmanager/gizmo/WM_gizmo_api.h2
-rw-r--r--source/blender/windowmanager/gizmo/WM_gizmo_types.h21
-rw-r--r--source/blender/windowmanager/gizmo/intern/wm_gizmo_group.c48
-rw-r--r--source/blender/windowmanager/gizmo/intern/wm_gizmo_group_type.c2
-rw-r--r--source/blender/windowmanager/gizmo/intern/wm_gizmo_map.c72
-rw-r--r--source/blender/windowmanager/gizmo/intern/wm_gizmo_type.c12
-rw-r--r--source/blender/windowmanager/intern/wm.c32
-rw-r--r--source/blender/windowmanager/intern/wm_cursors.c20
-rw-r--r--source/blender/windowmanager/intern/wm_draw.c192
-rw-r--r--source/blender/windowmanager/intern/wm_event_query.c10
-rw-r--r--source/blender/windowmanager/intern/wm_event_system.c402
-rw-r--r--source/blender/windowmanager/intern/wm_files.c346
-rw-r--r--source/blender/windowmanager/intern/wm_files_link.c2
-rw-r--r--source/blender/windowmanager/intern/wm_gesture.c22
-rw-r--r--source/blender/windowmanager/intern/wm_gesture_ops.c16
-rw-r--r--source/blender/windowmanager/intern/wm_init_exit.c27
-rw-r--r--source/blender/windowmanager/intern/wm_jobs.c6
-rw-r--r--source/blender/windowmanager/intern/wm_keymap.c30
-rw-r--r--source/blender/windowmanager/intern/wm_keymap_utils.c3
-rw-r--r--source/blender/windowmanager/intern/wm_menu_type.c4
-rw-r--r--source/blender/windowmanager/intern/wm_operator_type.c8
-rw-r--r--source/blender/windowmanager/intern/wm_operator_utils.c8
-rw-r--r--source/blender/windowmanager/intern/wm_operators.c143
-rw-r--r--source/blender/windowmanager/intern/wm_playanim.c14
-rw-r--r--source/blender/windowmanager/intern/wm_splash_screen.c332
-rw-r--r--source/blender/windowmanager/intern/wm_surface.c2
-rw-r--r--source/blender/windowmanager/intern/wm_toolsystem.c126
-rw-r--r--source/blender/windowmanager/intern/wm_tooltip.c16
-rw-r--r--source/blender/windowmanager/intern/wm_uilist_type.c4
-rw-r--r--source/blender/windowmanager/intern/wm_window.c249
-rw-r--r--source/blender/windowmanager/intern/wm_xr.c765
-rw-r--r--source/blender/windowmanager/message_bus/intern/wm_message_bus.c11
-rw-r--r--source/blender/windowmanager/wm.h11
-rw-r--r--source/blender/windowmanager/wm_draw.h2
-rw-r--r--source/blender/windowmanager/wm_event_system.h5
-rw-r--r--source/blender/windowmanager/wm_event_types.h1
-rw-r--r--source/blender/windowmanager/wm_files.h2
-rw-r--r--source/blender/windowmanager/wm_surface.h2
-rw-r--r--source/blender/windowmanager/wm_window.h12
-rw-r--r--source/blender/windowmanager/xr/intern/wm_xr.c168
-rw-r--r--source/blender/windowmanager/xr/intern/wm_xr_draw.c162
-rw-r--r--source/blender/windowmanager/xr/intern/wm_xr_intern.h96
-rw-r--r--source/blender/windowmanager/xr/intern/wm_xr_session.c430
-rw-r--r--source/blender/windowmanager/xr/wm_xr.h35
-rw-r--r--source/creator/CMakeLists.txt57
-rw-r--r--source/creator/blender.map119
-rw-r--r--source/creator/creator.c8
-rw-r--r--source/creator/creator_args.c49
-rw-r--r--source/creator/creator_intern.h6
-rw-r--r--source/creator/creator_signals.c86
-rw-r--r--source/creator/osx_locals.map68
m---------source/tools0
1668 files changed, 72771 insertions, 50810 deletions
diff --git a/source/blender/blenfont/BLF_api.h b/source/blender/blenfont/BLF_api.h
index 9aee8c9b78b..ddb88cf61ed 100644
--- a/source/blender/blenfont/BLF_api.h
+++ b/source/blender/blenfont/BLF_api.h
@@ -37,6 +37,7 @@ extern "C" {
struct ColorManagedDisplay;
struct ResultBLF;
struct rctf;
+struct rcti;
int BLF_init(void);
void BLF_exit(void);
@@ -115,6 +116,26 @@ void BLF_draw_ascii_ex(int fontid, const char *str, size_t len, struct ResultBLF
void BLF_draw_ascii(int fontid, const char *str, size_t len) ATTR_NONNULL(2);
int BLF_draw_mono(int fontid, const char *str, size_t len, int cwidth) ATTR_NONNULL(2);
+typedef bool (*BLF_GlyphBoundsFn)(const char *str,
+ const size_t str_step_ofs,
+ const struct rcti *glyph_step_bounds,
+ const int glyph_advance_x,
+ const struct rctf *glyph_bounds,
+ const int glyph_bearing[2],
+ void *user_data);
+
+void BLF_boundbox_foreach_glyph_ex(int fontid,
+ const char *str,
+ size_t len,
+ BLF_GlyphBoundsFn user_fn,
+ void *user_data,
+ struct ResultBLF *r_info) ATTR_NONNULL(2);
+void BLF_boundbox_foreach_glyph(int fontid,
+ const char *str,
+ size_t len,
+ BLF_GlyphBoundsFn user_fn,
+ void *user_data) ATTR_NONNULL(2);
+
/* Get the string byte offset that fits within a given width */
size_t BLF_width_to_strlen(int fontid, const char *str, size_t len, float width, float *r_width)
ATTR_NONNULL(2);
diff --git a/source/blender/blenfont/intern/blf.c b/source/blender/blenfont/intern/blf.c
index 520456653d1..2f7d5a60a6f 100644
--- a/source/blender/blenfont/intern/blf.c
+++ b/source/blender/blenfont/intern/blf.c
@@ -682,6 +682,42 @@ int BLF_draw_mono(int fontid, const char *str, size_t len, int cwidth)
return columns;
}
+/**
+ * Run \a user_fn for each character, with the bound-box that would be used for drawing.
+ *
+ * \param user_fn: Callback that runs on each glyph, returning false early exits.
+ * \param user_data: User argument passed to \a user_fn.
+ *
+ * \note The font position, clipping, matrix and rotation are not applied.
+ */
+void BLF_boundbox_foreach_glyph_ex(int fontid,
+ const char *str,
+ size_t len,
+ BLF_GlyphBoundsFn user_fn,
+ void *user_data,
+ struct ResultBLF *r_info)
+{
+ FontBLF *font = blf_get(fontid);
+
+ BLF_RESULT_CHECK_INIT(r_info);
+
+ if (font) {
+ if (font->flags & BLF_WORD_WRAP) {
+ /* TODO: word-wrap support. */
+ BLI_assert(0);
+ }
+ else {
+ blf_font_boundbox_foreach_glyph(font, str, len, user_fn, user_data, r_info);
+ }
+ }
+}
+
+void BLF_boundbox_foreach_glyph(
+ int fontid, const char *str, size_t len, BLF_GlyphBoundsFn user_fn, void *user_data)
+{
+ BLF_boundbox_foreach_glyph_ex(fontid, str, len, user_fn, user_data, NULL);
+}
+
size_t BLF_width_to_strlen(int fontid, const char *str, size_t len, float width, float *r_width)
{
FontBLF *font = blf_get(fontid);
@@ -910,8 +946,8 @@ void BLF_buffer(int fontid,
if (font) {
font->buf_info.fbuf = fbuf;
font->buf_info.cbuf = cbuf;
- font->buf_info.w = w;
- font->buf_info.h = h;
+ font->buf_info.dims[0] = w;
+ font->buf_info.dims[1] = h;
font->buf_info.ch = nch;
font->buf_info.display = display;
}
diff --git a/source/blender/blenfont/intern/blf_font.c b/source/blender/blenfont/intern/blf_font.c
index 4d56f6f868f..e5e03418073 100644
--- a/source/blender/blenfont/intern/blf_font.c
+++ b/source/blender/blenfont/intern/blf_font.c
@@ -99,7 +99,7 @@ static void blf_batch_draw_init(void)
GPU_vertbuf_attr_get_raw_data(g_batch.verts, g_batch.glyph_size_loc, &g_batch.glyph_size_step);
g_batch.glyph_len = 0;
- /* A dummy vbo containing 4 points, attribs are not used. */
+ /* A dummy VBO containing 4 points, attributes are not used. */
GPUVertBuf *vbo = GPU_vertbuf_create_with_format(&format);
GPU_vertbuf_data_alloc(vbo, 4);
@@ -613,28 +613,28 @@ static void blf_font_draw_buffer_ex(FontBLF *font,
BLF_KERNING_STEP_FAST(font, kern_mode, g_prev, g, c_prev, c, pen_x);
}
- chx = pen_x + ((int)g->pos_x);
- chy = pen_y_basis + g->height;
+ chx = pen_x + ((int)g->pos[0]);
+ chy = pen_y_basis + g->dims[1];
if (g->pitch < 0) {
- pen_y = pen_y_basis + (g->height - (int)g->pos_y);
+ pen_y = pen_y_basis + (g->dims[1] - g->pos[1]);
}
else {
- pen_y = pen_y_basis - (g->height - (int)g->pos_y);
+ pen_y = pen_y_basis - (g->dims[1] - g->pos[1]);
}
- if ((chx + g->width) >= 0 && chx < buf_info->w && (pen_y + g->height) >= 0 &&
- pen_y < buf_info->h) {
+ if ((chx + g->dims[0]) >= 0 && chx < buf_info->dims[0] && (pen_y + g->dims[1]) >= 0 &&
+ pen_y < buf_info->dims[1]) {
/* don't draw beyond the buffer bounds */
- int width_clip = g->width;
- int height_clip = g->height;
- int yb_start = g->pitch < 0 ? 0 : g->height - 1;
+ int width_clip = g->dims[0];
+ int height_clip = g->dims[1];
+ int yb_start = g->pitch < 0 ? 0 : g->dims[1] - 1;
- if (width_clip + chx > buf_info->w) {
- width_clip -= chx + width_clip - buf_info->w;
+ if (width_clip + chx > buf_info->dims[0]) {
+ width_clip -= chx + width_clip - buf_info->dims[0];
}
- if (height_clip + pen_y > buf_info->h) {
- height_clip -= pen_y + height_clip - buf_info->h;
+ if (height_clip + pen_y > buf_info->dims[1]) {
+ height_clip -= pen_y + height_clip - buf_info->dims[1];
}
/* drawing below the image? */
@@ -652,7 +652,7 @@ static void blf_font_draw_buffer_ex(FontBLF *font,
if (a_byte) {
const float a = (a_byte / 255.0f) * b_col_float[3];
const size_t buf_ofs = (((size_t)(chx + x) +
- ((size_t)(pen_y + y) * (size_t)buf_info->w)) *
+ ((size_t)(pen_y + y) * (size_t)buf_info->dims[0])) *
(size_t)buf_info->ch);
float *fbuf = buf_info->fbuf + buf_ofs;
@@ -689,7 +689,7 @@ static void blf_font_draw_buffer_ex(FontBLF *font,
if (a_byte) {
const float a = (a_byte / 255.0f) * b_col_float[3];
const size_t buf_ofs = (((size_t)(chx + x) +
- ((size_t)(pen_y + y) * (size_t)buf_info->w)) *
+ ((size_t)(pen_y + y) * (size_t)buf_info->dims[0])) *
(size_t)buf_info->ch);
unsigned char *cbuf = buf_info->cbuf + buf_ofs;
@@ -1201,6 +1201,84 @@ float blf_font_fixed_width(FontBLF *font)
return g->advance;
}
+/* -------------------------------------------------------------------- */
+/** \name Glyph Bound Box with Callback
+ * \{ */
+
+static void blf_font_boundbox_foreach_glyph_ex(FontBLF *font,
+ GlyphCacheBLF *gc,
+ const char *str,
+ size_t len,
+ BLF_GlyphBoundsFn user_fn,
+ void *user_data,
+ struct ResultBLF *r_info,
+ int pen_y)
+{
+ unsigned int c, c_prev = BLI_UTF8_ERR;
+ GlyphBLF *g, *g_prev = NULL;
+ int pen_x = 0;
+ size_t i = 0, i_curr;
+ rcti gbox;
+
+ if (len == 0) {
+ /* early output. */
+ return;
+ }
+
+ GlyphBLF **glyph_ascii_table = blf_font_ensure_ascii_table(font, gc);
+
+ BLF_KERNING_VARS(font, has_kerning, kern_mode);
+
+ blf_font_ensure_ascii_kerning(font, gc, kern_mode);
+
+ while ((i < len) && str[i]) {
+ i_curr = i;
+ BLF_UTF8_NEXT_FAST(font, gc, g, str, i, c, glyph_ascii_table);
+
+ if (UNLIKELY(c == BLI_UTF8_ERR)) {
+ break;
+ }
+ if (UNLIKELY(g == NULL)) {
+ continue;
+ }
+ if (has_kerning) {
+ BLF_KERNING_STEP_FAST(font, kern_mode, g_prev, g, c_prev, c, pen_x);
+ }
+
+ gbox.xmin = pen_x;
+ gbox.xmax = gbox.xmin + MIN2(g->advance_i, g->dims[0]);
+ gbox.ymin = pen_y;
+ gbox.ymax = gbox.ymin - g->dims[1];
+
+ pen_x += g->advance_i;
+
+ if (user_fn(str, i_curr, &gbox, g->advance_i, &g->box, g->pos, user_data) == false) {
+ break;
+ }
+
+ g_prev = g;
+ c_prev = c;
+ }
+
+ if (r_info) {
+ r_info->lines = 1;
+ r_info->width = pen_x;
+ }
+}
+void blf_font_boundbox_foreach_glyph(FontBLF *font,
+ const char *str,
+ size_t len,
+ BLF_GlyphBoundsFn user_fn,
+ void *user_data,
+ struct ResultBLF *r_info)
+{
+ GlyphCacheBLF *gc = blf_glyph_cache_acquire(font);
+ blf_font_boundbox_foreach_glyph_ex(font, gc, str, len, user_fn, user_data, r_info, 0);
+ blf_glyph_cache_release(font);
+}
+
+/** \} */
+
int blf_font_count_missing_chars(FontBLF *font,
const char *str,
const size_t len,
@@ -1287,8 +1365,8 @@ static void blf_font_fill(FontBLF *font)
font->buf_info.fbuf = NULL;
font->buf_info.cbuf = NULL;
- font->buf_info.w = 0;
- font->buf_info.h = 0;
+ font->buf_info.dims[0] = 0;
+ font->buf_info.dims[1] = 0;
font->buf_info.ch = 0;
font->buf_info.col_init[0] = 0;
font->buf_info.col_init[1] = 0;
diff --git a/source/blender/blenfont/intern/blf_glyph.c b/source/blender/blenfont/intern/blf_glyph.c
index a38cb323777..ce17069e53f 100644
--- a/source/blender/blenfont/intern/blf_glyph.c
+++ b/source/blender/blenfont/intern/blf_glyph.c
@@ -212,7 +212,7 @@ void blf_glyph_cache_free(GlyphCacheBLF *gc)
GlyphBLF *g;
unsigned int i;
- for (i = 0; i < 257; i++) {
+ for (i = 0; i < ARRAY_SIZE(gc->bucket); i++) {
while ((g = BLI_pophead(&gc->bucket[i]))) {
blf_glyph_free(g);
}
@@ -327,26 +327,27 @@ GlyphBLF *blf_glyph_add(FontBLF *font, GlyphCacheBLF *gc, unsigned int index, un
g->c = c;
g->idx = (FT_UInt)index;
bitmap = slot->bitmap;
- g->width = (int)bitmap.width;
- g->height = (int)bitmap.rows;
+ g->dims[0] = (int)bitmap.width;
+ g->dims[1] = (int)bitmap.rows;
- if (g->width && g->height) {
+ const int buffer_size = g->dims[0] * g->dims[1];
+
+ if (buffer_size != 0) {
if (font->flags & BLF_MONOCHROME) {
/* Font buffer uses only 0 or 1 values, Blender expects full 0..255 range */
- int i;
- for (i = 0; i < (g->width * g->height); i++) {
+ for (int i = 0; i < buffer_size; i++) {
bitmap.buffer[i] = bitmap.buffer[i] ? 255 : 0;
}
}
- g->bitmap = (unsigned char *)MEM_mallocN((size_t)g->width * (size_t)g->height, "glyph bitmap");
- memcpy((void *)g->bitmap, (void *)bitmap.buffer, (size_t)g->width * (size_t)g->height);
+ g->bitmap = MEM_mallocN((size_t)buffer_size, "glyph bitmap");
+ memcpy(g->bitmap, bitmap.buffer, (size_t)buffer_size);
}
g->advance = ((float)slot->advance.x) / 64.0f;
g->advance_i = (int)g->advance;
- g->pos_x = (float)slot->bitmap_left;
- g->pos_y = (float)slot->bitmap_top;
+ g->pos[0] = slot->bitmap_left;
+ g->pos[1] = slot->bitmap_top;
g->pitch = slot->bitmap.pitch;
FT_Outline_Get_CBox(&(slot->outline), &bbox);
@@ -431,10 +432,10 @@ static void blf_texture3_draw(const unsigned char color_in[4],
static void blf_glyph_calc_rect(rctf *rect, GlyphBLF *g, float x, float y)
{
- rect->xmin = floorf(x + g->pos_x);
- rect->xmax = rect->xmin + (float)g->width;
- rect->ymin = floorf(y + g->pos_y);
- rect->ymax = rect->ymin - (float)g->height;
+ rect->xmin = floorf(x + (float)g->pos[0]);
+ rect->xmax = rect->xmin + (float)g->dims[0];
+ rect->ymin = floorf(y + (float)g->pos[1]);
+ rect->ymax = rect->ymin - (float)g->dims[1];
}
static void blf_glyph_calc_rect_test(rctf *rect, GlyphBLF *g, float x, float y)
@@ -443,9 +444,9 @@ static void blf_glyph_calc_rect_test(rctf *rect, GlyphBLF *g, float x, float y)
* width used by BLF_width. This allows that the text slightly
* overlaps the clipping border to achieve better alignment. */
rect->xmin = floorf(x);
- rect->xmax = rect->xmin + MIN2(g->advance, (float)g->width);
+ rect->xmax = rect->xmin + MIN2(g->advance, (float)g->dims[0]);
rect->ymin = floorf(y);
- rect->ymax = rect->ymin - (float)g->height;
+ rect->ymax = rect->ymin - (float)g->dims[1];
}
static void blf_glyph_calc_rect_shadow(rctf *rect, GlyphBLF *g, float x, float y, FontBLF *font)
@@ -455,7 +456,7 @@ static void blf_glyph_calc_rect_shadow(rctf *rect, GlyphBLF *g, float x, float y
void blf_glyph_render(FontBLF *font, GlyphCacheBLF *gc, GlyphBLF *g, float x, float y)
{
- if ((!g->width) || (!g->height)) {
+ if ((!g->dims[0]) || (!g->dims[1])) {
return;
}
@@ -466,7 +467,7 @@ void blf_glyph_render(FontBLF *font, GlyphCacheBLF *gc, GlyphBLF *g, float x, fl
g->offset = gc->bitmap_len;
- int buff_size = g->width * g->height;
+ int buff_size = g->dims[0] * g->dims[1];
int bitmap_len = gc->bitmap_len + buff_size;
if (bitmap_len > gc->bitmap_len_alloc) {
@@ -514,7 +515,7 @@ void blf_glyph_render(FontBLF *font, GlyphCacheBLF *gc, GlyphBLF *g, float x, fl
if (font->shadow == 0) {
blf_texture_draw(font->shadow_color,
- (int[2]){g->width, g->height},
+ g->dims,
g->offset,
rect_ofs.xmin,
rect_ofs.ymin,
@@ -523,7 +524,7 @@ void blf_glyph_render(FontBLF *font, GlyphCacheBLF *gc, GlyphBLF *g, float x, fl
}
else if (font->shadow <= 4) {
blf_texture3_draw(font->shadow_color,
- (int[2]){g->width, g->height},
+ g->dims,
g->offset,
rect_ofs.xmin,
rect_ofs.ymin,
@@ -532,7 +533,7 @@ void blf_glyph_render(FontBLF *font, GlyphCacheBLF *gc, GlyphBLF *g, float x, fl
}
else {
blf_texture5_draw(font->shadow_color,
- (int[2]){g->width, g->height},
+ g->dims,
g->offset,
rect_ofs.xmin,
rect_ofs.ymin,
@@ -547,39 +548,18 @@ void blf_glyph_render(FontBLF *font, GlyphCacheBLF *gc, GlyphBLF *g, float x, fl
#if BLF_BLUR_ENABLE
switch (font->blur) {
case 3:
- blf_texture3_draw(font->color,
- (int[2]){g->width, g->height},
- g->offset,
- rect.xmin,
- rect.ymin,
- rect.xmax,
- rect.ymax);
+ blf_texture3_draw(
+ font->color, g->dims, g->offset, rect.xmin, rect.ymin, rect.xmax, rect.ymax);
break;
case 5:
- blf_texture5_draw(font->color,
- (int[2]){g->width, g->height},
- g->offset,
- rect.xmin,
- rect.ymin,
- rect.xmax,
- rect.ymax);
+ blf_texture5_draw(
+ font->color, g->dims, g->offset, rect.xmin, rect.ymin, rect.xmax, rect.ymax);
break;
default:
- blf_texture_draw(font->color,
- (int[2]){g->width, g->height},
- g->offset,
- rect.xmin,
- rect.ymin,
- rect.xmax,
- rect.ymax);
+ blf_texture_draw(
+ font->color, g->dims, g->offset, rect.xmin, rect.ymin, rect.xmax, rect.ymax);
}
#else
- blf_texture_draw(font->color,
- (int[2]){g->width, g->height},
- g->offset,
- rect.xmin,
- rect.ymin,
- rect.xmax,
- rect.ymax);
+ blf_texture_draw(font->color, g->dims, g->offset, rect.xmin, rect.ymin, rect.xmax, rect.ymax);
#endif
}
diff --git a/source/blender/blenfont/intern/blf_internal.h b/source/blender/blenfont/intern/blf_internal.h
index efcf9e15100..4ae592d323f 100644
--- a/source/blender/blenfont/intern/blf_internal.h
+++ b/source/blender/blenfont/intern/blf_internal.h
@@ -29,6 +29,7 @@ struct GlyphBLF;
struct GlyphCacheBLF;
struct ResultBLF;
struct rctf;
+struct rcti;
void blf_batch_draw_vao_clear(void);
void blf_batch_draw_begin(struct FontBLF *font);
@@ -98,6 +99,19 @@ int blf_font_width_max(struct FontBLF *font);
float blf_font_descender(struct FontBLF *font);
float blf_font_ascender(struct FontBLF *font);
+void blf_font_boundbox_foreach_glyph(struct FontBLF *font,
+ const char *str,
+ size_t len,
+ bool (*user_fn)(const char *str,
+ const size_t str_step_ofs,
+ const struct rcti *glyph_step_bounds,
+ const int glyph_advance_x,
+ const struct rctf *glyph_bounds,
+ const int glyph_bearing[2],
+ void *user_data),
+ void *user_data,
+ struct ResultBLF *r_info);
+
int blf_font_count_missing_chars(struct FontBLF *font,
const char *str,
const size_t len,
diff --git a/source/blender/blenfont/intern/blf_internal_types.h b/source/blender/blenfont/intern/blf_internal_types.h
index 6fae3eb4376..362cbf6730f 100644
--- a/source/blender/blenfont/intern/blf_internal_types.h
+++ b/source/blender/blenfont/intern/blf_internal_types.h
@@ -119,17 +119,16 @@ typedef struct GlyphBLF {
*/
unsigned char *bitmap;
- /* glyph width and height. */
- int width;
- int height;
+ /* Glyph width and height. */
+ int dims[2];
int pitch;
- /* X and Y bearing of the glyph.
+ /**
+ * X and Y bearing of the glyph.
* The X bearing is from the origin to the glyph left bbox edge.
* The Y bearing is from the baseline to the top of the glyph edge.
*/
- float pos_x;
- float pos_y;
+ int pos[2];
struct GlyphCacheBLF *glyph_cache;
} GlyphBLF;
@@ -141,9 +140,8 @@ typedef struct FontBufInfoBLF {
/* the same but unsigned char */
unsigned char *cbuf;
- /* buffer size, keep signed so comparisons with negative values work */
- int w;
- int h;
+ /** Buffer size, keep signed so comparisons with negative values work. */
+ int dims[2];
/* number of channels. */
int ch;
diff --git a/source/blender/blenfont/intern/blf_thumbs.c b/source/blender/blenfont/intern/blf_thumbs.c
index b7308d47d71..37eed29f6fe 100644
--- a/source/blender/blenfont/intern/blf_thumbs.c
+++ b/source/blender/blenfont/intern/blf_thumbs.c
@@ -78,8 +78,8 @@ void BLF_thumb_preview(const char *filename,
/* Would be done via the BLF API, but we're not using a fontid here */
font->buf_info.cbuf = buf;
font->buf_info.ch = channels;
- font->buf_info.w = w;
- font->buf_info.h = h;
+ font->buf_info.dims[0] = w;
+ font->buf_info.dims[1] = h;
/* Always create the image with a white font,
* the caller can theme how it likes */
diff --git a/source/blender/blenfont/intern/blf_util.c b/source/blender/blenfont/intern/blf_util.c
index e55759199a2..a70a9ea6819 100644
--- a/source/blender/blenfont/intern/blf_util.c
+++ b/source/blender/blenfont/intern/blf_util.c
@@ -27,10 +27,10 @@
#include <stdlib.h>
#include <string.h>
-#include "blf_internal.h"
-
#include "BLI_utildefines.h"
+#include "blf_internal.h"
+
unsigned int blf_next_p2(unsigned int x)
{
x -= 1;
diff --git a/source/blender/blenkernel/BKE_action.h b/source/blender/blenkernel/BKE_action.h
index 5f4f3f35b82..104582be932 100644
--- a/source/blender/blenkernel/BKE_action.h
+++ b/source/blender/blenkernel/BKE_action.h
@@ -25,12 +25,12 @@
* \brief Blender kernel action and pose functionality.
*/
+#include "DNA_listBase.h"
+
#ifdef __cplusplus
extern "C" {
#endif
-#include "DNA_listBase.h"
-
/* The following structures are defined in DNA_action_types.h, and DNA_anim_types.h */
struct FCurve;
struct Main;
diff --git a/source/blender/blenkernel/BKE_addon.h b/source/blender/blenkernel/BKE_addon.h
index 7bb1761dfbe..741be17bb25 100644
--- a/source/blender/blenkernel/BKE_addon.h
+++ b/source/blender/blenkernel/BKE_addon.h
@@ -33,7 +33,7 @@ typedef struct bAddonPrefType {
char idname[64]; // best keep the same size as BKE_ST_MAXNAME
/* RNA integration */
- ExtensionRNA ext;
+ ExtensionRNA rna_ext;
} bAddonPrefType;
#else
diff --git a/source/blender/blenkernel/BKE_anim_data.h b/source/blender/blenkernel/BKE_anim_data.h
new file mode 100644
index 00000000000..5aeaf4405f5
--- /dev/null
+++ b/source/blender/blenkernel/BKE_anim_data.h
@@ -0,0 +1,98 @@
+/*
+ * 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) 2009 Blender Foundation, Joshua Leung
+ * All rights reserved.
+ */
+
+#ifndef __BKE_ANIM_DATA_H__
+#define __BKE_ANIM_DATA_H__
+
+/** \file
+ * \ingroup bke
+ */
+
+#include "BLI_sys_types.h" /* for bool */
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+struct AnimData;
+struct ID;
+struct LibraryForeachIDData;
+struct Main;
+struct ReportList;
+struct bAction;
+
+/* ************************************* */
+/* AnimData API */
+
+/* Check if the given ID-block can have AnimData */
+bool id_type_can_have_animdata(const short id_type);
+bool id_can_have_animdata(const struct ID *id);
+
+/* Get AnimData from the given ID-block */
+struct AnimData *BKE_animdata_from_id(struct ID *id);
+
+/* Add AnimData to the given ID-block */
+struct AnimData *BKE_animdata_add_id(struct ID *id);
+
+/* Set active action used by AnimData from the given ID-block */
+bool BKE_animdata_set_action(struct ReportList *reports, struct ID *id, struct bAction *act);
+
+/* Free AnimData */
+void BKE_animdata_free(struct ID *id, const bool do_id_user);
+
+/* Return true if the ID-block has non-empty AnimData. */
+bool BKE_animdata_id_is_animated(const struct ID *id);
+
+void BKE_animdata_foreach_id(struct AnimData *adt, struct LibraryForeachIDData *data);
+
+/* Copy AnimData */
+struct AnimData *BKE_animdata_copy(struct Main *bmain, struct AnimData *adt, const int flag);
+
+/* Copy AnimData */
+bool BKE_animdata_copy_id(struct Main *bmain,
+ struct ID *id_to,
+ struct ID *id_from,
+ const int flag);
+
+/* Copy AnimData Actions */
+void BKE_animdata_copy_id_action(struct Main *bmain, struct ID *id, const bool set_newid);
+
+/* Merge copies of data from source AnimData block */
+typedef enum eAnimData_MergeCopy_Modes {
+ /* Keep destination action */
+ ADT_MERGECOPY_KEEP_DST = 0,
+
+ /* Use src action (make a new copy) */
+ ADT_MERGECOPY_SRC_COPY = 1,
+
+ /* Use src action (but just reference the existing version) */
+ ADT_MERGECOPY_SRC_REF = 2,
+} eAnimData_MergeCopy_Modes;
+
+void BKE_animdata_merge_copy(struct Main *bmain,
+ struct ID *dst_id,
+ struct ID *src_id,
+ eAnimData_MergeCopy_Modes action_mode,
+ bool fix_drivers);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* __BKE_ANIM_DATA_H__*/
diff --git a/source/blender/blenkernel/BKE_anim_path.h b/source/blender/blenkernel/BKE_anim_path.h
new file mode 100644
index 00000000000..64bcedefa58
--- /dev/null
+++ b/source/blender/blenkernel/BKE_anim_path.h
@@ -0,0 +1,51 @@
+/*
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV.
+ * All rights reserved.
+ */
+#ifndef __BKE_ANIM_PATH_H__
+#define __BKE_ANIM_PATH_H__
+
+/** \file
+ * \ingroup bke
+ */
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+struct ListBase;
+struct Object;
+struct Path;
+
+/* ---------------------------------------------------- */
+/* Curve Paths */
+
+void free_path(struct Path *path);
+void calc_curvepath(struct Object *ob, struct ListBase *nurbs);
+int where_on_path(struct Object *ob,
+ float ctime,
+ float vec[4],
+ float dir[3],
+ float quat[4],
+ float *radius,
+ float *weight);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
diff --git a/source/blender/blenkernel/BKE_anim_visualization.h b/source/blender/blenkernel/BKE_anim_visualization.h
new file mode 100644
index 00000000000..5dcbfa0919e
--- /dev/null
+++ b/source/blender/blenkernel/BKE_anim_visualization.h
@@ -0,0 +1,56 @@
+/*
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV.
+ * All rights reserved.
+ */
+#ifndef __BKE_ANIM_VISUALIZATION_H__
+#define __BKE_ANIM_VISUALIZATION_H__
+
+/** \file
+ * \ingroup bke
+ */
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+struct Object;
+struct ReportList;
+struct Scene;
+struct bAnimVizSettings;
+struct bMotionPath;
+struct bPoseChannel;
+
+/* ---------------------------------------------------- */
+/* Animation Visualization */
+
+void animviz_settings_init(struct bAnimVizSettings *avs);
+
+struct bMotionPath *animviz_copy_motionpath(const struct bMotionPath *mpath_src);
+
+void animviz_free_motionpath_cache(struct bMotionPath *mpath);
+void animviz_free_motionpath(struct bMotionPath *mpath);
+
+struct bMotionPath *animviz_verify_motionpaths(struct ReportList *reports,
+ struct Scene *scene,
+ struct Object *ob,
+ struct bPoseChannel *pchan);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
diff --git a/source/blender/blenkernel/BKE_animsys.h b/source/blender/blenkernel/BKE_animsys.h
index 9da17d777cd..4a2ad28f90f 100644
--- a/source/blender/blenkernel/BKE_animsys.h
+++ b/source/blender/blenkernel/BKE_animsys.h
@@ -24,6 +24,8 @@
* \ingroup bke
*/
+#include "BLI_sys_types.h" /* for bool */
+
#ifdef __cplusplus
extern "C" {
#endif
@@ -47,58 +49,6 @@ struct bActionGroup;
struct bContext;
/* ************************************* */
-/* AnimData API */
-
-/* Check if the given ID-block can have AnimData */
-bool id_type_can_have_animdata(const short id_type);
-bool id_can_have_animdata(const struct ID *id);
-
-/* Get AnimData from the given ID-block */
-struct AnimData *BKE_animdata_from_id(struct ID *id);
-
-/* Add AnimData to the given ID-block */
-struct AnimData *BKE_animdata_add_id(struct ID *id);
-
-/* Set active action used by AnimData from the given ID-block */
-bool BKE_animdata_set_action(struct ReportList *reports, struct ID *id, struct bAction *act);
-
-/* Free AnimData */
-void BKE_animdata_free(struct ID *id, const bool do_id_user);
-
-/* Return true if the ID-block has non-empty AnimData. */
-bool BKE_animdata_id_is_animated(const struct ID *id);
-
-/* Copy AnimData */
-struct AnimData *BKE_animdata_copy(struct Main *bmain, struct AnimData *adt, const int flag);
-
-/* Copy AnimData */
-bool BKE_animdata_copy_id(struct Main *bmain,
- struct ID *id_to,
- struct ID *id_from,
- const int flag);
-
-/* Copy AnimData Actions */
-void BKE_animdata_copy_id_action(struct Main *bmain, struct ID *id, const bool set_newid);
-
-/* Merge copies of data from source AnimData block */
-typedef enum eAnimData_MergeCopy_Modes {
- /* Keep destination action */
- ADT_MERGECOPY_KEEP_DST = 0,
-
- /* Use src action (make a new copy) */
- ADT_MERGECOPY_SRC_COPY = 1,
-
- /* Use src action (but just reference the existing version) */
- ADT_MERGECOPY_SRC_REF = 2,
-} eAnimData_MergeCopy_Modes;
-
-void BKE_animdata_merge_copy(struct Main *bmain,
- struct ID *dst_id,
- struct ID *src_id,
- eAnimData_MergeCopy_Modes action_mode,
- bool fix_drivers);
-
-/* ************************************* */
/* KeyingSets API */
/* Used to create a new 'custom' KeyingSet for the user,
@@ -257,17 +207,15 @@ bool BKE_animsys_read_rna_setting(struct PathResolvedRNA *anim_rna, float *r_val
bool BKE_animsys_write_rna_setting(struct PathResolvedRNA *anim_rna, const float value);
/* Evaluation loop for evaluating animation data */
-void BKE_animsys_evaluate_animdata(struct Scene *scene,
- struct ID *id,
+void BKE_animsys_evaluate_animdata(struct ID *id,
struct AnimData *adt,
float ctime,
- short recalc,
+ eAnimData_Recalc recalc,
const bool flush_to_original);
/* Evaluation of all ID-blocks with Animation Data blocks - Animation Data Only */
void BKE_animsys_evaluate_all_animation(struct Main *main,
struct Depsgraph *depsgraph,
- struct Scene *scene,
float ctime);
/* ------------ Specialized API --------------- */
diff --git a/source/blender/blenkernel/BKE_armature.h b/source/blender/blenkernel/BKE_armature.h
index cd4733a4e62..c22e7a24afe 100644
--- a/source/blender/blenkernel/BKE_armature.h
+++ b/source/blender/blenkernel/BKE_armature.h
@@ -22,6 +22,7 @@
/** \file
* \ingroup bke
*/
+#include "BLI_listbase.h"
#ifdef __cplusplus
extern "C" {
@@ -61,7 +62,7 @@ typedef struct PoseTree {
int stretch; /* disable stretching */
} PoseTree;
-/* Core armature functionality */
+/* Core armature functionality. */
struct bArmature *BKE_armature_add(struct Main *bmain, const char *name);
struct bArmature *BKE_armature_from_object(struct Object *ob);
@@ -89,7 +90,7 @@ void BKE_armature_bone_hash_free(struct bArmature *arm);
bool BKE_armature_bone_flag_test_recursive(const struct Bone *bone, int flag);
-void BKE_armature_refresh_layer_used(struct bArmature *arm);
+void BKE_armature_refresh_layer_used(struct Depsgraph *depsgraph, struct bArmature *arm);
float distfactor_to_bone(
const float vec[3], const float b1[3], const float b2[3], float r1, float r2, float rdist);
diff --git a/source/blender/blenkernel/BKE_blender.h b/source/blender/blenkernel/BKE_blender.h
index 59c7a1dfd2b..3feba4b3a66 100644
--- a/source/blender/blenkernel/BKE_blender.h
+++ b/source/blender/blenkernel/BKE_blender.h
@@ -34,12 +34,6 @@ void BKE_blender_free(void);
void BKE_blender_globals_init(void);
void BKE_blender_globals_clear(void);
-void BKE_blender_version_string(char *version_str,
- size_t maxncpy,
- short version,
- short subversion,
- bool v_prefix,
- bool include_subversion);
void BKE_blender_userdef_data_swap(struct UserDef *userdef_dst, struct UserDef *userdef_src);
void BKE_blender_userdef_data_set(struct UserDef *userdef);
diff --git a/source/blender/blenkernel/BKE_blender_version.h b/source/blender/blenkernel/BKE_blender_version.h
index 78e0e12355b..9d948dfd57b 100644
--- a/source/blender/blenkernel/BKE_blender_version.h
+++ b/source/blender/blenkernel/BKE_blender_version.h
@@ -16,6 +16,10 @@
#ifndef __BKE_BLENDER_VERSION_H__
#define __BKE_BLENDER_VERSION_H__
+#ifdef __cplusplus
+extern "C" {
+#endif
+
/** \file
* \ingroup bke
*/
@@ -26,21 +30,29 @@
*
* \note Use #STRINGIFY() rather than defining with quotes.
*/
-#define BLENDER_VERSION 283
-#define BLENDER_SUBVERSION 11
-/** Several breakages with 280, e.g. collections vs layers. */
-#define BLENDER_MINVERSION 280
-#define BLENDER_MINSUBVERSION 0
-
-/** Used by packaging tools. */
-/** Can be left blank, otherwise a,b,c... etc with no quotes. */
-#define BLENDER_VERSION_CHAR
-/** alpha/beta/rc/release, docs use this. */
+
+/* Blender major and minor version. */
+#define BLENDER_VERSION 290
+/* Blender patch version for bugfix releases. */
+#define BLENDER_VERSION_PATCH 0
+/** Blender release cycle stage: alpha/beta/rc/release. */
#define BLENDER_VERSION_CYCLE alpha
-/** Optionally set to 1,2,... for example to get alpha1 or rc2. */
-#define BLENDER_VERSION_CYCLE_NUMBER
-/** Defined in from blender.c */
-extern char versionstr[];
+/* Blender file format version. */
+#define BLENDER_FILE_VERSION BLENDER_VERSION
+#define BLENDER_FILE_SUBVERSION 4
+
+/* Minimum Blender version that supports reading file written with the current
+ * version. Older Blender versions will test this and show a warning if the file
+ * was written with too new a version. */
+#define BLENDER_FILE_MIN_VERSION 280
+#define BLENDER_FILE_MIN_SUBVERSION 0
+
+/** User readable version string. */
+const char *BKE_blender_version_string(void);
+
+#ifdef __cplusplus
+}
+#endif
#endif /* __BKE_BLENDER_VERSION_H__ */
diff --git a/source/blender/blenkernel/BKE_brush.h b/source/blender/blenkernel/BKE_brush.h
index a97263a6523..4e9430ab3e1 100644
--- a/source/blender/blenkernel/BKE_brush.h
+++ b/source/blender/blenkernel/BKE_brush.h
@@ -57,10 +57,18 @@ struct Brush *BKE_brush_copy(struct Main *bmain, const struct Brush *brush);
void BKE_brush_sculpt_reset(struct Brush *brush);
-void BKE_brush_gpencil_paint_presets(struct Main *bmain, struct ToolSettings *ts);
-void BKE_brush_gpencil_vertex_presets(struct Main *bmain, struct ToolSettings *ts);
-void BKE_brush_gpencil_sculpt_presets(struct Main *bmain, struct ToolSettings *ts);
-void BKE_brush_gpencil_weight_presets(struct Main *bmain, struct ToolSettings *ts);
+void BKE_brush_gpencil_paint_presets(struct Main *bmain,
+ struct ToolSettings *ts,
+ const bool reset);
+void BKE_brush_gpencil_vertex_presets(struct Main *bmain,
+ struct ToolSettings *ts,
+ const bool reset);
+void BKE_brush_gpencil_sculpt_presets(struct Main *bmain,
+ struct ToolSettings *ts,
+ const bool reset);
+void BKE_brush_gpencil_weight_presets(struct Main *bmain,
+ struct ToolSettings *ts,
+ const bool reset);
void BKE_gpencil_brush_preset_set(struct Main *bmain, struct Brush *brush, const short type);
/* image icon function */
diff --git a/source/blender/blenkernel/BKE_bvhutils.h b/source/blender/blenkernel/BKE_bvhutils.h
index b83ebf8ce09..5d7e8fe743e 100644
--- a/source/blender/blenkernel/BKE_bvhutils.h
+++ b/source/blender/blenkernel/BKE_bvhutils.h
@@ -25,6 +25,7 @@
#include "BLI_bitmap.h"
#include "BLI_kdopbvh.h"
+#include "BLI_threads.h"
#ifdef __cplusplus
extern "C" {
@@ -39,7 +40,7 @@ struct MFace;
struct MVert;
struct Mesh;
-typedef struct LinkNode BVHCache;
+struct BVHCache;
/**
* Struct that stores basic information about a BVHTree built from a edit-mesh.
@@ -85,6 +86,24 @@ typedef struct BVHTreeFromMesh {
} BVHTreeFromMesh;
+typedef enum BVHCacheType {
+ BVHTREE_FROM_VERTS,
+ BVHTREE_FROM_EDGES,
+ BVHTREE_FROM_FACES,
+ BVHTREE_FROM_LOOPTRI,
+ BVHTREE_FROM_LOOPTRI_NO_HIDDEN,
+
+ BVHTREE_FROM_LOOSEVERTS,
+ BVHTREE_FROM_LOOSEEDGES,
+
+ BVHTREE_FROM_EM_VERTS,
+ BVHTREE_FROM_EM_EDGES,
+ BVHTREE_FROM_EM_LOOPTRI,
+
+ /* Keep `BVHTREE_MAX_ITEM` as last item. */
+ BVHTREE_MAX_ITEM,
+} BVHCacheType;
+
/**
* Builds a bvh tree where nodes are the relevant elements of the given mesh.
* Configures #BVHTreeFromMesh.
@@ -106,8 +125,9 @@ BVHTree *bvhtree_from_editmesh_verts_ex(BVHTreeFromEditMesh *data,
float epsilon,
int tree_type,
int axis,
- const int bvh_cache_type,
- BVHCache **bvh_cache);
+ const BVHCacheType bvh_cache_type,
+ struct BVHCache **bvh_cache_p,
+ ThreadMutex *mesh_eval_mutex);
BVHTree *bvhtree_from_mesh_verts_ex(struct BVHTreeFromMesh *data,
const struct MVert *vert,
@@ -118,8 +138,9 @@ BVHTree *bvhtree_from_mesh_verts_ex(struct BVHTreeFromMesh *data,
float epsilon,
int tree_type,
int axis,
- const int bvh_cache_type,
- BVHCache **bvh_cache);
+ const BVHCacheType bvh_cache_type,
+ struct BVHCache **bvh_cache_p,
+ ThreadMutex *mesh_eval_mutex);
BVHTree *bvhtree_from_editmesh_edges(
BVHTreeFromEditMesh *data, struct BMEditMesh *em, float epsilon, int tree_type, int axis);
@@ -131,8 +152,9 @@ BVHTree *bvhtree_from_editmesh_edges_ex(BVHTreeFromEditMesh *data,
float epsilon,
int tree_type,
int axis,
- const int bvh_cache_type,
- BVHCache **bvh_cache);
+ const BVHCacheType bvh_cache_type,
+ struct BVHCache **bvh_cache_p,
+ ThreadMutex *mesh_eval_mutex);
BVHTree *bvhtree_from_mesh_edges_ex(struct BVHTreeFromMesh *data,
const struct MVert *vert,
@@ -145,8 +167,9 @@ BVHTree *bvhtree_from_mesh_edges_ex(struct BVHTreeFromMesh *data,
float epsilon,
int tree_type,
int axis,
- const int bvh_cache_type,
- BVHCache **bvh_cache);
+ const BVHCacheType bvh_cache_type,
+ struct BVHCache **bvh_cache_p,
+ ThreadMutex *mesh_eval_mutex);
BVHTree *bvhtree_from_mesh_faces_ex(struct BVHTreeFromMesh *data,
const struct MVert *vert,
@@ -159,8 +182,9 @@ BVHTree *bvhtree_from_mesh_faces_ex(struct BVHTreeFromMesh *data,
float epsilon,
int tree_type,
int axis,
- const int bvh_cache_type,
- BVHCache **bvh_cache);
+ const BVHCacheType bvh_cache_type,
+ struct BVHCache **bvh_cache_p,
+ ThreadMutex *mesh_eval_mutex);
BVHTree *bvhtree_from_editmesh_looptri(
BVHTreeFromEditMesh *data, struct BMEditMesh *em, float epsilon, int tree_type, int axis);
@@ -172,8 +196,9 @@ BVHTree *bvhtree_from_editmesh_looptri_ex(BVHTreeFromEditMesh *data,
float epsilon,
int tree_type,
int axis,
- const int bvh_cache_type,
- BVHCache **bvh_cache);
+ const BVHCacheType bvh_cache_type,
+ struct BVHCache **bvh_cache_p,
+ ThreadMutex *mesh_eval_mutex);
BVHTree *bvhtree_from_mesh_looptri_ex(struct BVHTreeFromMesh *data,
const struct MVert *vert,
@@ -188,19 +213,21 @@ BVHTree *bvhtree_from_mesh_looptri_ex(struct BVHTreeFromMesh *data,
float epsilon,
int tree_type,
int axis,
- const int bvh_cache_type,
- BVHCache **bvh_cache);
+ const BVHCacheType bvh_cache_type,
+ struct BVHCache **bvh_cache_p,
+ ThreadMutex *mesh_eval_mutex);
BVHTree *BKE_bvhtree_from_mesh_get(struct BVHTreeFromMesh *data,
struct Mesh *mesh,
- const int type,
+ const BVHCacheType bvh_cache_type,
const int tree_type);
BVHTree *BKE_bvhtree_from_editmesh_get(BVHTreeFromEditMesh *data,
struct BMEditMesh *em,
const int tree_type,
- const int bvh_cache_type,
- BVHCache **bvh_cache);
+ const BVHCacheType bvh_cache_type,
+ struct BVHCache **bvh_cache_p,
+ ThreadMutex *mesh_eval_mutex);
/**
* Frees data allocated by a call to bvhtree_from_mesh_*.
@@ -228,25 +255,10 @@ float bvhtree_sphereray_tri_intersection(const BVHTreeRay *ray,
*/
/* Using local coordinates */
-enum {
- BVHTREE_FROM_VERTS,
- BVHTREE_FROM_EDGES,
- BVHTREE_FROM_FACES,
- BVHTREE_FROM_LOOPTRI,
- BVHTREE_FROM_LOOPTRI_NO_HIDDEN,
-
- BVHTREE_FROM_LOOSEVERTS,
- BVHTREE_FROM_LOOSEEDGES,
-
- BVHTREE_FROM_EM_VERTS,
- BVHTREE_FROM_EM_EDGES,
- BVHTREE_FROM_EM_LOOPTRI,
-};
-bool bvhcache_find(const BVHCache *cache, int type, BVHTree **r_tree);
-bool bvhcache_has_tree(const BVHCache *cache, const BVHTree *tree);
-void bvhcache_insert(BVHCache **cache_p, BVHTree *tree, int type);
-void bvhcache_free(BVHCache **cache_p);
+bool bvhcache_has_tree(const struct BVHCache *bvh_cache, const BVHTree *tree);
+struct BVHCache *bvhcache_init(void);
+void bvhcache_free(struct BVHCache *bvh_cache);
#ifdef __cplusplus
}
diff --git a/source/blender/blenkernel/BKE_camera.h b/source/blender/blenkernel/BKE_camera.h
index f93003dc423..812f5d520d7 100644
--- a/source/blender/blenkernel/BKE_camera.h
+++ b/source/blender/blenkernel/BKE_camera.h
@@ -22,7 +22,7 @@
/** \file
* \ingroup bke
- * \brief Camera datablock and utility functions.
+ * \brief Camera data-block and utility functions.
*/
#ifdef __cplusplus
extern "C" {
diff --git a/source/blender/blenkernel/BKE_cdderivedmesh.h b/source/blender/blenkernel/BKE_cdderivedmesh.h
index 1d6db319eb7..dd7d20c0407 100644
--- a/source/blender/blenkernel/BKE_cdderivedmesh.h
+++ b/source/blender/blenkernel/BKE_cdderivedmesh.h
@@ -10,7 +10,7 @@
* 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,
+ * 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) 2006 Blender Foundation.
diff --git a/source/blender/blenkernel/BKE_collection.h b/source/blender/blenkernel/BKE_collection.h
index a314008f715..f4b56aa152f 100644
--- a/source/blender/blenkernel/BKE_collection.h
+++ b/source/blender/blenkernel/BKE_collection.h
@@ -50,6 +50,10 @@ typedef struct CollectionParent {
struct Collection *BKE_collection_add(struct Main *bmain,
struct Collection *parent,
const char *name);
+void BKE_collection_add_from_object(struct Main *bmain,
+ struct Scene *scene,
+ const struct Object *ob_src,
+ struct Collection *collection_dst);
void BKE_collection_free(struct Collection *collection);
bool BKE_collection_delete(struct Main *bmain, struct Collection *collection, bool hierarchy);
diff --git a/source/blender/blenkernel/BKE_colorband.h b/source/blender/blenkernel/BKE_colorband.h
index 6e03f4db3d2..355682671fe 100644
--- a/source/blender/blenkernel/BKE_colorband.h
+++ b/source/blender/blenkernel/BKE_colorband.h
@@ -29,7 +29,7 @@ extern "C" {
struct ColorBand;
-/* in ColorBand struct */
+/** #ColorBand.data length. */
#define MAXCOLORBAND 32
void BKE_colorband_init(struct ColorBand *coba, bool rangetype);
diff --git a/source/blender/blenkernel/BKE_context.h b/source/blender/blenkernel/BKE_context.h
index 9e2a124491c..70ca29d5795 100644
--- a/source/blender/blenkernel/BKE_context.h
+++ b/source/blender/blenkernel/BKE_context.h
@@ -25,6 +25,7 @@
*/
#include "DNA_listBase.h"
+#include "DNA_object_enums.h"
#include "RNA_types.h"
#ifdef __cplusplus
@@ -66,8 +67,6 @@ struct bScreen;
struct wmWindow;
struct wmWindowManager;
-#include "DNA_object_enums.h"
-
/* Structs */
struct bContext;
@@ -178,7 +177,7 @@ struct SpaceTopBar *CTX_wm_space_topbar(const bContext *C);
void CTX_wm_manager_set(bContext *C, struct wmWindowManager *wm);
void CTX_wm_window_set(bContext *C, struct wmWindow *win);
void CTX_wm_screen_set(bContext *C, struct bScreen *screen); /* to be removed */
-void CTX_wm_area_set(bContext *C, struct ScrArea *sa);
+void CTX_wm_area_set(bContext *C, struct ScrArea *area);
void CTX_wm_region_set(bContext *C, struct ARegion *region);
void CTX_wm_menu_set(bContext *C, struct ARegion *menu);
void CTX_wm_gizmo_group_set(bContext *C, struct wmGizmoGroup *gzgroup);
diff --git a/source/blender/blenkernel/BKE_curve.h b/source/blender/blenkernel/BKE_curve.h
index 164867b228b..40f73ccfe84 100644
--- a/source/blender/blenkernel/BKE_curve.h
+++ b/source/blender/blenkernel/BKE_curve.h
@@ -23,12 +23,12 @@
* \ingroup bke
*/
+#include "DNA_scene_types.h"
+
#ifdef __cplusplus
extern "C" {
#endif
-#include "DNA_scene_types.h"
-
struct BezTriple;
struct Curve;
struct Depsgraph;
@@ -111,6 +111,8 @@ void BKE_curve_material_index_clear(struct Curve *cu);
bool BKE_curve_material_index_validate(struct Curve *cu);
void BKE_curve_material_remap(struct Curve *cu, const unsigned int *remap, unsigned int remap_len);
+void BKE_curve_smooth_flag_set(struct Curve *cu, const bool use_smooth);
+
ListBase *BKE_curve_nurbs_get(struct Curve *cu);
int BKE_curve_nurb_vert_index_get(const struct Nurb *nu, const void *vert);
@@ -171,7 +173,8 @@ void BKE_nurbList_handles_recalculate(struct ListBase *editnurb,
const char flag);
void BKE_nurbList_handles_autocalc(ListBase *editnurb, int flag);
-void BKE_nurbList_flag_set(ListBase *editnurb, short flag);
+void BKE_nurbList_flag_set(ListBase *editnurb, short flag, bool set);
+bool BKE_nurbList_flag_set_from_flag(ListBase *editnurb, short from_flag, short flag);
void BKE_nurb_free(struct Nurb *nu);
struct Nurb *BKE_nurb_duplicate(const struct Nurb *nu);
@@ -259,8 +262,9 @@ void BKE_nurb_handles_calc(struct Nurb *nu);
void BKE_nurb_handles_autocalc(struct Nurb *nu, int flag);
void BKE_nurb_bezt_handle_test(struct BezTriple *bezt,
const eBezTriple_Flag__Alias sel_flag,
- const bool use_handle);
-void BKE_nurb_handles_test(struct Nurb *nu, const bool use_handles);
+ const bool use_handle,
+ const bool use_around_local);
+void BKE_nurb_handles_test(struct Nurb *nu, const bool use_handles, const bool use_around_local);
/* **** Depsgraph evaluation **** */
diff --git a/source/blender/blenkernel/BKE_customdata.h b/source/blender/blenkernel/BKE_customdata.h
index a4a36343ca3..42beda352f5 100644
--- a/source/blender/blenkernel/BKE_customdata.h
+++ b/source/blender/blenkernel/BKE_customdata.h
@@ -10,7 +10,7 @@
* 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,
+ * 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) 2006 Blender Foundation.
@@ -25,15 +25,15 @@
#ifndef __BKE_CUSTOMDATA_H__
#define __BKE_CUSTOMDATA_H__
-#ifdef __cplusplus
-extern "C" {
-#endif
-
#include "BLI_sys_types.h"
#include "BLI_utildefines.h"
#include "DNA_customdata_types.h"
+#ifdef __cplusplus
+extern "C" {
+#endif
+
struct BMesh;
struct CustomData;
struct CustomData_MeshMasks;
diff --git a/source/blender/blenkernel/BKE_data_transfer.h b/source/blender/blenkernel/BKE_data_transfer.h
index 79ef512bc1f..a723a9ed38c 100644
--- a/source/blender/blenkernel/BKE_data_transfer.h
+++ b/source/blender/blenkernel/BKE_data_transfer.h
@@ -10,7 +10,7 @@
* 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,
+ * 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) 2014 Blender Foundation.
@@ -24,12 +24,12 @@
#ifndef __BKE_DATA_TRANSFER_H__
#define __BKE_DATA_TRANSFER_H__
+#include "BKE_customdata.h"
+
#ifdef __cplusplus
extern "C" {
#endif
-#include "BKE_customdata.h"
-
struct Depsgraph;
struct Object;
struct ReportList;
diff --git a/source/blender/blenkernel/BKE_anim.h b/source/blender/blenkernel/BKE_duplilist.h
index 38af96c2ff0..71b6d06b450 100644
--- a/source/blender/blenkernel/BKE_anim.h
+++ b/source/blender/blenkernel/BKE_duplilist.h
@@ -16,8 +16,8 @@
* The Original Code is Copyright (C) 2001-2002 by NaN Holding BV.
* All rights reserved.
*/
-#ifndef __BKE_ANIM_H__
-#define __BKE_ANIM_H__
+#ifndef __BKE_DUPLILIST_H__
+#define __BKE_DUPLILIST_H__
/** \file
* \ingroup bke
@@ -31,40 +31,7 @@ struct Depsgraph;
struct ListBase;
struct Object;
struct ParticleSystem;
-struct Path;
-struct ReportList;
struct Scene;
-struct bAnimVizSettings;
-struct bMotionPath;
-struct bPoseChannel;
-
-/* ---------------------------------------------------- */
-/* Animation Visualization */
-
-void animviz_settings_init(struct bAnimVizSettings *avs);
-
-struct bMotionPath *animviz_copy_motionpath(const struct bMotionPath *mpath_src);
-
-void animviz_free_motionpath_cache(struct bMotionPath *mpath);
-void animviz_free_motionpath(struct bMotionPath *mpath);
-
-struct bMotionPath *animviz_verify_motionpaths(struct ReportList *reports,
- struct Scene *scene,
- struct Object *ob,
- struct bPoseChannel *pchan);
-
-/* ---------------------------------------------------- */
-/* Curve Paths */
-
-void free_path(struct Path *path);
-void calc_curvepath(struct Object *ob, struct ListBase *nurbs);
-int where_on_path(struct Object *ob,
- float ctime,
- float vec[4],
- float dir[3],
- float quat[4],
- float *radius,
- float *weight);
/* ---------------------------------------------------- */
/* Dupli-Geometry */
diff --git a/source/blender/blenkernel/BKE_dynamicpaint.h b/source/blender/blenkernel/BKE_dynamicpaint.h
index 0dc133e34b3..5e3603a8339 100644
--- a/source/blender/blenkernel/BKE_dynamicpaint.h
+++ b/source/blender/blenkernel/BKE_dynamicpaint.h
@@ -21,12 +21,12 @@
* \ingroup bke
*/
+#include "BLI_utildefines.h"
+
#ifdef __cplusplus
extern "C" {
#endif
-#include "BLI_utildefines.h"
-
struct Depsgraph;
struct DynamicPaintCanvasSettings;
struct DynamicPaintModifierData;
diff --git a/source/blender/blenkernel/BKE_editmesh_cache.h b/source/blender/blenkernel/BKE_editmesh_cache.h
index c6a2541e0a7..6c812098b2e 100644
--- a/source/blender/blenkernel/BKE_editmesh_cache.h
+++ b/source/blender/blenkernel/BKE_editmesh_cache.h
@@ -33,6 +33,11 @@ void BKE_editmesh_cache_ensure_vert_normals(struct BMEditMesh *em, struct EditMe
void BKE_editmesh_cache_ensure_poly_centers(struct BMEditMesh *em, struct EditMeshData *emd);
+bool BKE_editmesh_cache_calc_minmax(struct BMEditMesh *em,
+ struct EditMeshData *emd,
+ float min[3],
+ float max[3]);
+
#ifdef __cplusplus
}
#endif
diff --git a/source/blender/blenkernel/BKE_fcurve.h b/source/blender/blenkernel/BKE_fcurve.h
index d389b557503..c3a597e29b9 100644
--- a/source/blender/blenkernel/BKE_fcurve.h
+++ b/source/blender/blenkernel/BKE_fcurve.h
@@ -24,19 +24,20 @@
* \ingroup bke
*/
+#include "DNA_curve_types.h"
+
#ifdef __cplusplus
extern "C" {
#endif
struct ChannelDriver;
-struct DriverTarget;
-struct DriverVar;
struct FCM_EnvelopeData;
struct FCurve;
struct FModifier;
struct AnimData;
struct BezTriple;
+struct LibraryForeachIDData;
struct PathResolvedRNA;
struct PointerRNA;
struct PropertyRNA;
@@ -44,8 +45,6 @@ struct StructRNA;
struct bAction;
struct bContext;
-#include "DNA_curve_types.h"
-
/* ************** Keyframe Tools ***************** */
typedef struct CfraElem {
@@ -56,67 +55,6 @@ typedef struct CfraElem {
void bezt_add_to_cfra_elem(ListBase *lb, struct BezTriple *bezt);
-/* ************** F-Curve Drivers ***************** */
-
-/* With these iterators for convenience, the variables "tarIndex" and "dtar" can be
- * accessed directly from the code using them, but it is not recommended that their
- * values be changed to point at other slots...
- */
-
-/* convenience looper over ALL driver targets for a given variable (even the unused ones) */
-#define DRIVER_TARGETS_LOOPER_BEGIN(dvar) \
- { \
- DriverTarget *dtar = &dvar->targets[0]; \
- int tarIndex = 0; \
- for (; tarIndex < MAX_DRIVER_TARGETS; tarIndex++, dtar++)
-
-/* convenience looper over USED driver targets only */
-#define DRIVER_TARGETS_USED_LOOPER_BEGIN(dvar) \
- { \
- DriverTarget *dtar = &dvar->targets[0]; \
- int tarIndex = 0; \
- for (; tarIndex < dvar->num_targets; tarIndex++, dtar++)
-
-/* tidy up for driver targets loopers */
-#define DRIVER_TARGETS_LOOPER_END \
- } \
- ((void)0)
-
-/* ---------------------- */
-
-void fcurve_free_driver(struct FCurve *fcu);
-struct ChannelDriver *fcurve_copy_driver(const struct ChannelDriver *driver);
-
-void driver_variables_copy(struct ListBase *dst_vars, const struct ListBase *src_vars);
-
-void BKE_driver_target_matrix_to_rot_channels(
- float mat[4][4], int auto_order, int rotation_mode, int channel, bool angles, float r_buf[4]);
-
-void driver_free_variable(struct ListBase *variables, struct DriverVar *dvar);
-void driver_free_variable_ex(struct ChannelDriver *driver, struct DriverVar *dvar);
-
-void driver_change_variable_type(struct DriverVar *dvar, int type);
-void driver_variable_name_validate(struct DriverVar *dvar);
-struct DriverVar *driver_add_new_variable(struct ChannelDriver *driver);
-
-float driver_get_variable_value(struct ChannelDriver *driver, struct DriverVar *dvar);
-bool driver_get_variable_property(struct ChannelDriver *driver,
- struct DriverTarget *dtar,
- struct PointerRNA *r_ptr,
- struct PropertyRNA **r_prop,
- int *r_index);
-
-bool BKE_driver_has_simple_expression(struct ChannelDriver *driver);
-bool BKE_driver_expression_depends_on_time(struct ChannelDriver *driver);
-void BKE_driver_invalidate_expression(struct ChannelDriver *driver,
- bool expr_changed,
- bool varname_changed);
-
-float evaluate_driver(struct PathResolvedRNA *anim_rna,
- struct ChannelDriver *driver,
- struct ChannelDriver *driver_orig,
- const float evaltime);
-
/* ************** F-Curve Modifiers *************** */
/* F-Curve Modifier Type-Info (fmi):
@@ -241,17 +179,19 @@ int BKE_fcm_envelope_find_index(struct FCM_EnvelopeData *array,
#define BEZT_BINARYSEARCH_THRESH 0.01f /* was 0.00001, but giving errors */
/* -------- Data Management -------- */
+struct FCurve *BKE_fcurve_create(void);
+void BKE_fcurve_free(struct FCurve *fcu);
+struct FCurve *BKE_fcurve_copy(const struct FCurve *fcu);
-void free_fcurve(struct FCurve *fcu);
-struct FCurve *copy_fcurve(const struct FCurve *fcu);
+void BKE_fcurves_free(ListBase *list);
+void BKE_fcurves_copy(ListBase *dst, ListBase *src);
-void free_fcurves(ListBase *list);
-void copy_fcurves(ListBase *dst, ListBase *src);
+void BKE_fcurve_foreach_id(struct FCurve *fcu, struct LibraryForeachIDData *data);
/* find matching F-Curve in the given list of F-Curves */
-struct FCurve *list_find_fcurve(ListBase *list, const char rna_path[], const int array_index);
+struct FCurve *BKE_fcurve_find(ListBase *list, const char rna_path[], const int array_index);
-struct FCurve *iter_step_fcurve(struct FCurve *fcu_iter, const char rna_path[]);
+struct FCurve *BKE_fcurve_iter_step(struct FCurve *fcu_iter, const char rna_path[]);
/* high level function to get an fcurve from C without having the rna */
struct FCurve *id_data_find_fcurve(
@@ -259,31 +199,28 @@ struct FCurve *id_data_find_fcurve(
/* Get list of LinkData's containing pointers to the F-Curves which control the types of data
* indicated
- * e.g. numMatches = list_find_data_fcurves(matches, &act->curves, "pose.bones[", "MyFancyBone");
+ * e.g. numMatches = BKE_fcurves_filter(matches, &act->curves, "pose.bones[", "MyFancyBone");
*/
-int list_find_data_fcurves(ListBase *dst,
- ListBase *src,
- const char *dataPrefix,
- const char *dataName);
+int BKE_fcurves_filter(ListBase *dst, ListBase *src, const char *dataPrefix, const char *dataName);
/* Find an f-curve based on an rna property. */
-struct FCurve *rna_get_fcurve(struct PointerRNA *ptr,
- struct PropertyRNA *prop,
- int rnaindex,
- struct AnimData **r_adt,
- struct bAction **r_action,
- bool *r_driven,
- bool *r_special);
+struct FCurve *BKE_fcurve_find_by_rna(struct PointerRNA *ptr,
+ struct PropertyRNA *prop,
+ int rnaindex,
+ struct AnimData **r_adt,
+ struct bAction **r_action,
+ bool *r_driven,
+ bool *r_special);
/* Same as above, but takes a context data,
* temp hack needed for complex paths like texture ones. */
-struct FCurve *rna_get_fcurve_context_ui(struct bContext *C,
- struct PointerRNA *ptr,
- struct PropertyRNA *prop,
- int rnaindex,
- struct AnimData **r_animdata,
- struct bAction **r_action,
- bool *r_driven,
- bool *r_special);
+struct FCurve *BKE_fcurve_find_by_rna_context_ui(struct bContext *C,
+ struct PointerRNA *ptr,
+ struct PropertyRNA *prop,
+ int rnaindex,
+ struct AnimData **r_animdata,
+ struct bAction **r_action,
+ bool *r_driven,
+ bool *r_special);
/* Binary search algorithm for finding where to 'insert' BezTriple with given frame number.
* Returns the index to insert at (data already at that index will be offset if replace is 0)
@@ -291,25 +228,25 @@ struct FCurve *rna_get_fcurve_context_ui(struct bContext *C,
int binarysearch_bezt_index(struct BezTriple array[], float frame, int arraylen, bool *r_replace);
/* get the time extents for F-Curve */
-bool calc_fcurve_range(
+bool BKE_fcurve_calc_range(
struct FCurve *fcu, float *min, float *max, const bool do_sel_only, const bool do_min_length);
/* get the bounding-box extents for F-Curve */
-bool calc_fcurve_bounds(struct FCurve *fcu,
- float *xmin,
- float *xmax,
- float *ymin,
- float *ymax,
- const bool do_sel_only,
- const bool include_handles);
+bool BKE_fcurve_calc_bounds(struct FCurve *fcu,
+ float *xmin,
+ float *xmax,
+ float *ymin,
+ float *ymax,
+ const bool do_sel_only,
+ const bool include_handles);
/* .............. */
/* Are keyframes on F-Curve of any use (to final result, and to show in editors)? */
-bool fcurve_are_keyframes_usable(struct FCurve *fcu);
+bool BKE_fcurve_are_keyframes_usable(struct FCurve *fcu);
/* Can keyframes be added to F-Curve? */
-bool fcurve_is_keyframable(struct FCurve *fcu);
+bool BKE_fcurve_is_keyframable(struct FCurve *fcu);
bool BKE_fcurve_is_protected(struct FCurve *fcu);
/* The curve is an infinite cycle via Cycles modifier */
diff --git a/source/blender/blenkernel/BKE_fcurve_driver.h b/source/blender/blenkernel/BKE_fcurve_driver.h
new file mode 100644
index 00000000000..563ed408ed7
--- /dev/null
+++ b/source/blender/blenkernel/BKE_fcurve_driver.h
@@ -0,0 +1,106 @@
+/*
+ * 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) 2009 Blender Foundation, Joshua Leung
+ * All rights reserved.
+ */
+
+#ifndef __BKE_FCURVE_DRIVER_H__
+#define __BKE_FCURVE_DRIVER_H__
+
+/** \file
+ * \ingroup bke
+ */
+
+#include "DNA_curve_types.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+struct ChannelDriver;
+struct DriverTarget;
+struct DriverVar;
+struct FCurve;
+struct PathResolvedRNA;
+struct PointerRNA;
+struct PropertyRNA;
+
+/* ************** F-Curve Drivers ***************** */
+
+/* With these iterators for convenience, the variables "tarIndex" and "dtar" can be
+ * accessed directly from the code using them, but it is not recommended that their
+ * values be changed to point at other slots...
+ */
+
+/* convenience looper over ALL driver targets for a given variable (even the unused ones) */
+#define DRIVER_TARGETS_LOOPER_BEGIN(dvar) \
+ { \
+ DriverTarget *dtar = &dvar->targets[0]; \
+ int tarIndex = 0; \
+ for (; tarIndex < MAX_DRIVER_TARGETS; tarIndex++, dtar++)
+
+/* convenience looper over USED driver targets only */
+#define DRIVER_TARGETS_USED_LOOPER_BEGIN(dvar) \
+ { \
+ DriverTarget *dtar = &dvar->targets[0]; \
+ int tarIndex = 0; \
+ for (; tarIndex < dvar->num_targets; tarIndex++, dtar++)
+
+/* tidy up for driver targets loopers */
+#define DRIVER_TARGETS_LOOPER_END \
+ } \
+ ((void)0)
+
+/* ---------------------- */
+
+void fcurve_free_driver(struct FCurve *fcu);
+struct ChannelDriver *fcurve_copy_driver(const struct ChannelDriver *driver);
+
+void driver_variables_copy(struct ListBase *dst_vars, const struct ListBase *src_vars);
+
+void BKE_driver_target_matrix_to_rot_channels(
+ float mat[4][4], int auto_order, int rotation_mode, int channel, bool angles, float r_buf[4]);
+
+void driver_free_variable(struct ListBase *variables, struct DriverVar *dvar);
+void driver_free_variable_ex(struct ChannelDriver *driver, struct DriverVar *dvar);
+
+void driver_change_variable_type(struct DriverVar *dvar, int type);
+void driver_variable_name_validate(struct DriverVar *dvar);
+struct DriverVar *driver_add_new_variable(struct ChannelDriver *driver);
+
+float driver_get_variable_value(struct ChannelDriver *driver, struct DriverVar *dvar);
+bool driver_get_variable_property(struct ChannelDriver *driver,
+ struct DriverTarget *dtar,
+ struct PointerRNA *r_ptr,
+ struct PropertyRNA **r_prop,
+ int *r_index);
+
+bool BKE_driver_has_simple_expression(struct ChannelDriver *driver);
+bool BKE_driver_expression_depends_on_time(struct ChannelDriver *driver);
+void BKE_driver_invalidate_expression(struct ChannelDriver *driver,
+ bool expr_changed,
+ bool varname_changed);
+
+float evaluate_driver(struct PathResolvedRNA *anim_rna,
+ struct ChannelDriver *driver,
+ struct ChannelDriver *driver_orig,
+ const float evaltime);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* __BKE_FCURVE_DRIVER_H__*/
diff --git a/source/blender/blenkernel/BKE_fluid.h b/source/blender/blenkernel/BKE_fluid.h
index 2c5742d3dc7..e06a1a9fb92 100644
--- a/source/blender/blenkernel/BKE_fluid.h
+++ b/source/blender/blenkernel/BKE_fluid.h
@@ -61,6 +61,7 @@ void BKE_fluid_reallocate_copy_fluid(struct FluidDomainSettings *mds,
int o_max[3],
int o_shift[3],
int n_shift[3]);
+void BKE_fluid_cache_free_all(struct FluidDomainSettings *mds, struct Object *ob);
void BKE_fluid_cache_free(struct FluidDomainSettings *mds, struct Object *ob, int cache_map);
void BKE_fluid_cache_new_name_for_current_session(int maxlen, char *r_name);
@@ -75,6 +76,9 @@ void BKE_fluid_particle_system_create(struct Main *bmain,
const int psys_type);
void BKE_fluid_particle_system_destroy(struct Object *ob, const int particle_type);
+void BKE_fluid_cache_startframe_set(struct FluidDomainSettings *settings, int value);
+void BKE_fluid_cache_endframe_set(struct FluidDomainSettings *settings, int value);
+
void BKE_fluid_cachetype_mesh_set(struct FluidDomainSettings *settings, int cache_mesh_format);
void BKE_fluid_cachetype_data_set(struct FluidDomainSettings *settings, int cache_data_format);
void BKE_fluid_cachetype_particle_set(struct FluidDomainSettings *settings,
diff --git a/source/blender/blenkernel/BKE_gpencil.h b/source/blender/blenkernel/BKE_gpencil.h
index 8cd3081389e..85ba8175143 100644
--- a/source/blender/blenkernel/BKE_gpencil.h
+++ b/source/blender/blenkernel/BKE_gpencil.h
@@ -41,6 +41,7 @@ struct Object;
struct Scene;
struct SpaceImage;
struct ToolSettings;
+struct ViewLayer;
struct bDeformGroup;
struct bGPDframe;
struct bGPDlayer;
@@ -68,21 +69,21 @@ struct bGPdata;
/* Vertex Color macros. */
#define GPENCIL_USE_VERTEX_COLOR(toolsettings) \
- ((toolsettings->gp_paint->mode == GPPAINT_FLAG_USE_VERTEXCOLOR))
+ (((toolsettings)->gp_paint->mode == GPPAINT_FLAG_USE_VERTEXCOLOR))
#define GPENCIL_USE_VERTEX_COLOR_STROKE(toolsettings, brush) \
((GPENCIL_USE_VERTEX_COLOR(toolsettings) && \
- ((brush->gpencil_settings->vertex_mode == GPPAINT_MODE_STROKE) || \
- (brush->gpencil_settings->vertex_mode == GPPAINT_MODE_BOTH))))
+ (((brush)->gpencil_settings->vertex_mode == GPPAINT_MODE_STROKE) || \
+ ((brush)->gpencil_settings->vertex_mode == GPPAINT_MODE_BOTH))))
#define GPENCIL_USE_VERTEX_COLOR_FILL(toolsettings, brush) \
((GPENCIL_USE_VERTEX_COLOR(toolsettings) && \
- ((brush->gpencil_settings->vertex_mode == GPPAINT_MODE_FILL) || \
- (brush->gpencil_settings->vertex_mode == GPPAINT_MODE_BOTH))))
+ (((brush)->gpencil_settings->vertex_mode == GPPAINT_MODE_FILL) || \
+ ((brush)->gpencil_settings->vertex_mode == GPPAINT_MODE_BOTH))))
#define GPENCIL_TINT_VERTEX_COLOR_STROKE(brush) \
- ((brush->gpencil_settings->vertex_mode == GPPAINT_MODE_STROKE) || \
- (brush->gpencil_settings->vertex_mode == GPPAINT_MODE_BOTH))
+ (((brush)->gpencil_settings->vertex_mode == GPPAINT_MODE_STROKE) || \
+ ((brush)->gpencil_settings->vertex_mode == GPPAINT_MODE_BOTH))
#define GPENCIL_TINT_VERTEX_COLOR_FILL(brush) \
- ((brush->gpencil_settings->vertex_mode == GPPAINT_MODE_FILL) || \
- (brush->gpencil_settings->vertex_mode == GPPAINT_MODE_BOTH))
+ (((brush)->gpencil_settings->vertex_mode == GPPAINT_MODE_FILL) || \
+ ((brush)->gpencil_settings->vertex_mode == GPPAINT_MODE_BOTH))
/* ------------ Grease-Pencil API ------------------ */
@@ -253,7 +254,8 @@ typedef void (*gpIterCb)(struct bGPDlayer *layer,
struct bGPDstroke *stroke,
void *thunk);
-void BKE_gpencil_visible_stroke_iter(struct Object *ob,
+void BKE_gpencil_visible_stroke_iter(struct ViewLayer *view_layer,
+ struct Object *ob,
gpIterCb layer_cb,
gpIterCb stroke_cb,
void *thunk,
diff --git a/source/blender/blenkernel/BKE_gpencil_curve.h b/source/blender/blenkernel/BKE_gpencil_curve.h
new file mode 100644
index 00000000000..cf6f9074bda
--- /dev/null
+++ b/source/blender/blenkernel/BKE_gpencil_curve.h
@@ -0,0 +1,47 @@
+/*
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * The Original Code is Copyright (C) 2008, Blender Foundation
+ * This is a new part of Blender
+ */
+
+#ifndef __BKE_GPENCIL_CURVE_H__
+#define __BKE_GPENCIL_CURVE_H__
+
+/** \file
+ * \ingroup bke
+ */
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+struct Main;
+struct Object;
+struct Scene;
+
+void BKE_gpencil_convert_curve(struct Main *bmain,
+ struct Scene *scene,
+ struct Object *ob_gp,
+ struct Object *ob_cu,
+ const bool gpencil_lines,
+ const bool use_collections,
+ const bool only_stroke);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* __BKE_GPENCIL_CURVE_H__ */
diff --git a/source/blender/blenkernel/BKE_gpencil_geom.h b/source/blender/blenkernel/BKE_gpencil_geom.h
index 8c52e6d458b..b26016aa26c 100644
--- a/source/blender/blenkernel/BKE_gpencil_geom.h
+++ b/source/blender/blenkernel/BKE_gpencil_geom.h
@@ -98,14 +98,6 @@ bool BKE_gpencil_stroke_shrink(struct bGPDstroke *gps, const float dist);
float BKE_gpencil_stroke_length(const struct bGPDstroke *gps, bool use_3d);
-void BKE_gpencil_convert_curve(struct Main *bmain,
- struct Scene *scene,
- struct Object *ob_gp,
- struct Object *ob_cu,
- const bool gpencil_lines,
- const bool use_collections,
- const bool only_stroke);
-
#ifdef __cplusplus
}
#endif
diff --git a/source/blender/blenkernel/BKE_gpencil_modifier.h b/source/blender/blenkernel/BKE_gpencil_modifier.h
index b48a6284567..966d3a98234 100644
--- a/source/blender/blenkernel/BKE_gpencil_modifier.h
+++ b/source/blender/blenkernel/BKE_gpencil_modifier.h
@@ -260,28 +260,28 @@ typedef struct GpencilModifierTypeInfo {
/* Initialize modifier's global data (type info and some common global storages). */
void BKE_gpencil_modifier_init(void);
-const GpencilModifierTypeInfo *BKE_gpencil_modifierType_getInfo(GpencilModifierType type);
+const GpencilModifierTypeInfo *BKE_gpencil_modifier_get_info(GpencilModifierType type);
struct GpencilModifierData *BKE_gpencil_modifier_new(int type);
void BKE_gpencil_modifier_free_ex(struct GpencilModifierData *md, const int flag);
void BKE_gpencil_modifier_free(struct GpencilModifierData *md);
bool BKE_gpencil_modifier_unique_name(struct ListBase *modifiers, struct GpencilModifierData *gmd);
-bool BKE_gpencil_modifier_dependsOnTime(struct GpencilModifierData *md);
-struct GpencilModifierData *BKE_gpencil_modifiers_findByType(struct Object *ob,
- GpencilModifierType type);
-struct GpencilModifierData *BKE_gpencil_modifiers_findByName(struct Object *ob, const char *name);
-void BKE_gpencil_modifier_copyData_generic(const struct GpencilModifierData *md_src,
+bool BKE_gpencil_modifier_depends_ontime(struct GpencilModifierData *md);
+struct GpencilModifierData *BKE_gpencil_modifiers_findby_type(struct Object *ob,
+ GpencilModifierType type);
+struct GpencilModifierData *BKE_gpencil_modifiers_findby_name(struct Object *ob, const char *name);
+void BKE_gpencil_modifier_copydata_generic(const struct GpencilModifierData *md_src,
struct GpencilModifierData *md_dst);
-void BKE_gpencil_modifier_copyData(struct GpencilModifierData *md,
+void BKE_gpencil_modifier_copydata(struct GpencilModifierData *md,
struct GpencilModifierData *target);
-void BKE_gpencil_modifier_copyData_ex(struct GpencilModifierData *md,
+void BKE_gpencil_modifier_copydata_ex(struct GpencilModifierData *md,
struct GpencilModifierData *target,
const int flag);
-void BKE_gpencil_modifiers_foreachIDLink(struct Object *ob,
- GreasePencilIDWalkFunc walk,
- void *userData);
-void BKE_gpencil_modifiers_foreachTexLink(struct Object *ob,
- GreasePencilTexWalkFunc walk,
- void *userData);
+void BKE_gpencil_modifiers_foreach_ID_link(struct Object *ob,
+ GreasePencilIDWalkFunc walk,
+ void *userData);
+void BKE_gpencil_modifiers_foreach_tex_link(struct Object *ob,
+ GreasePencilTexWalkFunc walk,
+ void *userData);
bool BKE_gpencil_has_geometry_modifiers(struct Object *ob);
bool BKE_gpencil_has_time_modifiers(struct Object *ob);
diff --git a/source/blender/blenkernel/BKE_idprop.h b/source/blender/blenkernel/BKE_idprop.h
index 2b02895043f..1272127daa0 100644
--- a/source/blender/blenkernel/BKE_idprop.h
+++ b/source/blender/blenkernel/BKE_idprop.h
@@ -179,6 +179,17 @@ void IDP_Reset(IDProperty *prop, const IDProperty *reference);
# define IDP_Id(prop) ((ID *)(prop)->data.pointer)
#endif
+/**
+ * Call a callback for each idproperty in the hierarchy under given root one (included).
+ *
+ */
+typedef void (*IDPForeachPropertyCallback)(IDProperty *id_property, void *user_data);
+
+void IDP_foreach_property(struct IDProperty *id_property_root,
+ const int type_filter,
+ IDPForeachPropertyCallback callback,
+ void *user_data);
+
/* Format IDProperty as strings */
char *IDP_reprN(const struct IDProperty *prop, uint *r_len);
void IDP_repr_fn(const IDProperty *prop,
diff --git a/source/blender/blenkernel/BKE_idtype.h b/source/blender/blenkernel/BKE_idtype.h
index 93bcfe5323d..b6dfadd3b2a 100644
--- a/source/blender/blenkernel/BKE_idtype.h
+++ b/source/blender/blenkernel/BKE_idtype.h
@@ -33,6 +33,7 @@ extern "C" {
#endif
struct ID;
+struct LibraryForeachIDData;
struct Main;
/** IDTypeInfo.flags. */
@@ -60,6 +61,8 @@ typedef void (*IDTypeFreeDataFunction)(struct ID *id);
/** \param flag: See BKE_lib_id.h's LIB_ID_MAKELOCAL_... flags. */
typedef void (*IDTypeMakeLocalFunction)(struct Main *bmain, struct ID *id, const int flags);
+typedef void (*IDTypeForeachIDFunction)(struct ID *id, struct LibraryForeachIDData *data);
+
typedef struct IDTypeInfo {
/* ********** General IDType data. ********** */
@@ -121,6 +124,12 @@ typedef struct IDTypeInfo {
* `BKE_lib_id_make_local_generic()` is enough.
*/
IDTypeMakeLocalFunction make_local;
+
+ /**
+ * Called by `BKE_library_foreach_ID_link()` to apply a callback over all other ID usages (ID
+ * pointers) of given data-block.
+ */
+ IDTypeForeachIDFunction foreach_id;
} IDTypeInfo;
/* ********** Declaration of each IDTypeInfo. ********** */
@@ -165,6 +174,7 @@ extern IDTypeInfo IDType_ID_LP;
extern IDTypeInfo IDType_ID_HA;
extern IDTypeInfo IDType_ID_PT;
extern IDTypeInfo IDType_ID_VO;
+extern IDTypeInfo IDType_ID_SIM;
extern IDTypeInfo IDType_ID_LINK_PLACEHOLDER;
@@ -183,7 +193,7 @@ const char *BKE_idtype_idcode_to_translation_context(const short idcode);
bool BKE_idtype_idcode_is_linkable(const short idcode);
bool BKE_idtype_idcode_is_valid(const short idcode);
-short BKE_idtype_idcode_from_name(const char *name);
+short BKE_idtype_idcode_from_name(const char *idtype_name);
uint64_t BKE_idtype_idcode_to_idfilter(const short idcode);
short BKE_idtype_idcode_from_idfilter(const uint64_t idfilter);
diff --git a/source/blender/blenkernel/BKE_image.h b/source/blender/blenkernel/BKE_image.h
index 0d8b6efb4b1..1e5573ab014 100644
--- a/source/blender/blenkernel/BKE_image.h
+++ b/source/blender/blenkernel/BKE_image.h
@@ -23,12 +23,12 @@
* \ingroup bke
*/
+#include "BLI_utildefines.h"
+
#ifdef __cplusplus
extern "C" {
#endif
-#include "BLI_utildefines.h"
-
struct Depsgraph;
struct ID;
struct ImBuf;
@@ -318,7 +318,7 @@ bool BKE_image_fill_tile(struct Image *ima,
bool is_float);
struct ImageTile *BKE_image_get_tile(struct Image *ima, int tile_number);
-struct ImageTile *BKE_image_get_tile_from_iuser(struct Image *ima, struct ImageUser *iuser);
+struct ImageTile *BKE_image_get_tile_from_iuser(struct Image *ima, const struct ImageUser *iuser);
int BKE_image_get_tile_from_pos(struct Image *ima,
const float uv[2],
diff --git a/source/blender/blenkernel/BKE_keyconfig.h b/source/blender/blenkernel/BKE_keyconfig.h
index 711d0292f75..bc33cc2669e 100644
--- a/source/blender/blenkernel/BKE_keyconfig.h
+++ b/source/blender/blenkernel/BKE_keyconfig.h
@@ -37,7 +37,7 @@ typedef struct wmKeyConfigPrefType_Runtime {
char idname[64];
/* RNA integration */
- ExtensionRNA ext;
+ ExtensionRNA rna_ext;
} wmKeyConfigPrefType_Runtime;
#else
diff --git a/source/blender/blenkernel/BKE_layer.h b/source/blender/blenkernel/BKE_layer.h
index 7059675ec7d..7a0252e6813 100644
--- a/source/blender/blenkernel/BKE_layer.h
+++ b/source/blender/blenkernel/BKE_layer.h
@@ -137,6 +137,7 @@ void BKE_layer_collection_set_visible(struct ViewLayer *view_layer,
struct LayerCollection *lc,
const bool visible,
const bool hierarchy);
+void BKE_layer_collection_set_flag(struct LayerCollection *lc, const int flag, const bool value);
/* evaluation */
diff --git a/source/blender/blenkernel/BKE_lib_id.h b/source/blender/blenkernel/BKE_lib_id.h
index 9f36798fbd5..18ca5629d07 100644
--- a/source/blender/blenkernel/BKE_lib_id.h
+++ b/source/blender/blenkernel/BKE_lib_id.h
@@ -46,12 +46,12 @@
* specific cases requiring advanced (and potentially dangerous) handling.
*/
+#include "BLI_compiler_attrs.h"
+
#ifdef __cplusplus
extern "C" {
#endif
-#include "BLI_compiler_attrs.h"
-
struct GHash;
struct ID;
struct Library;
@@ -72,8 +72,8 @@ void BKE_libblock_init_empty(struct ID *id) ATTR_NONNULL(1);
/* When an ID's uuid is of that value, it is unset/invalid (e.g. for runtime IDs, etc.). */
#define MAIN_ID_SESSION_UUID_UNSET 0
-void BKE_lib_libblock_session_uuid_reset(void);
void BKE_lib_libblock_session_uuid_ensure(struct ID *id);
+void BKE_lib_libblock_session_uuid_renew(struct ID *id);
void *BKE_id_new(struct Main *bmain, const short type, const char *name);
void *BKE_id_new_nomain(const short type, const char *name);
diff --git a/source/blender/blenkernel/BKE_lib_override.h b/source/blender/blenkernel/BKE_lib_override.h
index 6f2882f3565..fb49f60d8b5 100644
--- a/source/blender/blenkernel/BKE_lib_override.h
+++ b/source/blender/blenkernel/BKE_lib_override.h
@@ -48,6 +48,8 @@ struct IDOverrideLibrary;
struct IDOverrideLibraryProperty;
struct IDOverrideLibraryPropertyOperation;
struct Main;
+struct PointerRNA;
+struct PropertyRNA;
void BKE_lib_override_library_enable(const bool do_enable);
bool BKE_lib_override_library_is_enabled(void);
@@ -92,6 +94,15 @@ void BKE_lib_override_library_property_operation_delete(
struct IDOverrideLibraryProperty *override_property,
struct IDOverrideLibraryPropertyOperation *override_property_operation);
+bool BKE_lib_override_library_property_operation_operands_validate(
+ struct IDOverrideLibraryPropertyOperation *override_property_operation,
+ struct PointerRNA *ptr_dst,
+ struct PointerRNA *ptr_src,
+ struct PointerRNA *ptr_storage,
+ struct PropertyRNA *prop_dst,
+ struct PropertyRNA *prop_src,
+ struct PropertyRNA *prop_storage);
+
bool BKE_lib_override_library_status_check_local(struct Main *bmain, struct ID *local);
bool BKE_lib_override_library_status_check_reference(struct Main *bmain, struct ID *local);
@@ -100,6 +111,17 @@ bool BKE_lib_override_library_operations_create(struct Main *bmain,
const bool force_auto);
void BKE_lib_override_library_main_operations_create(struct Main *bmain, const bool force_auto);
+void BKE_lib_override_library_operations_tag(struct IDOverrideLibraryProperty *override_property,
+ const short tag,
+ const bool do_set);
+void BKE_lib_override_library_properties_tag(struct IDOverrideLibrary *override,
+ const short tag,
+ const bool do_set);
+void BKE_lib_override_library_main_tag(struct Main *bmain, const short tag, const bool do_set);
+
+void BKE_lib_override_library_id_unused_cleanup(struct ID *local);
+void BKE_lib_override_library_main_unused_cleanup(struct Main *bmain);
+
void BKE_lib_override_library_update(struct Main *bmain, struct ID *local);
void BKE_lib_override_library_main_update(struct Main *bmain);
diff --git a/source/blender/blenkernel/BKE_lib_query.h b/source/blender/blenkernel/BKE_lib_query.h
index f3e15529f77..c5a25e8e7af 100644
--- a/source/blender/blenkernel/BKE_lib_query.h
+++ b/source/blender/blenkernel/BKE_lib_query.h
@@ -40,6 +40,7 @@ extern "C" {
#endif
struct ID;
+struct IDProperty;
struct Main;
/* Tips for the callback for cases it's gonna to modify the pointer. */
@@ -71,11 +72,15 @@ enum {
IDWALK_CB_OVERRIDE_LIBRARY_REFERENCE = (1 << 5),
/**
- * Adjusts #ID.us reference-count.
- * \note keep in sync with 'newlibadr_us' use in readfile.c
+ * This ID usage is fully refcounted.
+ * Callback is responsible to deal accordingly with #ID.us if needed.
*/
IDWALK_CB_USER = (1 << 8),
- /** Ensure #ID.us is at least 1 on use. */
+ /**
+ * This ID usage is not refcounted, but at least one user should be generated by it (to avoid
+ * e.g. loosing the used ID on save/reload).
+ * Callback is responsible to deal accordingly with #ID.us if needed.
+ */
IDWALK_CB_USER_ONE = (1 << 9),
};
@@ -89,6 +94,8 @@ enum {
typedef struct LibraryIDLinkCallbackData {
void *user_data;
+ /** Main database used to call `BKE_library_foreach_ID_link()`. */
+ struct Main *bmain;
/**
* 'Real' ID, the one that might be in bmain, only differs from self_id when the later is an
* embedded one.
@@ -122,6 +129,37 @@ enum {
IDWALK_NO_INDIRECT_PROXY_DATA_USAGE = (1 << 8), /* Ugly special case :(((( */
};
+typedef struct LibraryForeachIDData LibraryForeachIDData;
+
+bool BKE_lib_query_foreachid_process(struct LibraryForeachIDData *data,
+ struct ID **id_pp,
+ int cb_flag);
+int BKE_lib_query_foreachid_process_flags_get(struct LibraryForeachIDData *data);
+int BKE_lib_query_foreachid_process_callback_flag_override(struct LibraryForeachIDData *data,
+ const int cb_flag,
+ const bool do_replace);
+
+#define BKE_LIB_FOREACHID_PROCESS_ID(_data, _id, _cb_flag) \
+ { \
+ CHECK_TYPE_ANY((_id), ID *, void *); \
+ if (!BKE_lib_query_foreachid_process((_data), (ID **)&(_id), (_cb_flag))) { \
+ return; \
+ } \
+ } \
+ ((void)0)
+
+#define BKE_LIB_FOREACHID_PROCESS(_data, _id_super, _cb_flag) \
+ { \
+ CHECK_TYPE(&((_id_super)->id), ID *); \
+ if (!BKE_lib_query_foreachid_process((_data), (ID **)&(_id_super), (_cb_flag))) { \
+ return; \
+ } \
+ } \
+ ((void)0)
+
+bool BKE_library_foreach_ID_embedded(struct LibraryForeachIDData *data, struct ID **id_pp);
+void BKE_lib_query_idpropertiesForeachIDLink_callback(struct IDProperty *id_prop, void *user_data);
+
/* Loop over all of the ID's this datablock links to. */
void BKE_library_foreach_ID_link(
struct Main *bmain, struct ID *id, LibraryIDLinkCallback callback, void *user_data, int flag);
diff --git a/source/blender/blenkernel/BKE_lib_remap.h b/source/blender/blenkernel/BKE_lib_remap.h
index 72c5f1d1b0e..8129b9dbafb 100644
--- a/source/blender/blenkernel/BKE_lib_remap.h
+++ b/source/blender/blenkernel/BKE_lib_remap.h
@@ -33,12 +33,12 @@
* - `BKE_lib_remap_callback_` should be used for functions managing remapping callbacks.
*/
+#include "BLI_compiler_attrs.h"
+
#ifdef __cplusplus
extern "C" {
#endif
-#include "BLI_compiler_attrs.h"
-
struct wmWindowManager;
/* BKE_libblock_free, delete are declared in BKE_lib_id.h for convenience. */
diff --git a/source/blender/blenkernel/BKE_library.h b/source/blender/blenkernel/BKE_library.h
index 5bc3d50bf8d..7883d740b0a 100644
--- a/source/blender/blenkernel/BKE_library.h
+++ b/source/blender/blenkernel/BKE_library.h
@@ -25,12 +25,12 @@
* API to manage `Library` data-blocks.
*/
+#include "BLI_compiler_attrs.h"
+
#ifdef __cplusplus
extern "C" {
#endif
-#include "BLI_compiler_attrs.h"
-
struct Library;
struct Main;
diff --git a/source/blender/blenkernel/BKE_light.h b/source/blender/blenkernel/BKE_light.h
index a6f0fdbc8a3..ead27ec8002 100644
--- a/source/blender/blenkernel/BKE_light.h
+++ b/source/blender/blenkernel/BKE_light.h
@@ -24,12 +24,14 @@
* \ingroup bke
* \brief General operations, lookup, etc. for blender lights.
*/
+
+#include "BLI_compiler_attrs.h"
+
#ifdef __cplusplus
extern "C" {
#endif
-#include "BLI_compiler_attrs.h"
-
+struct Depsgraph;
struct Light;
struct Main;
@@ -37,6 +39,8 @@ struct Light *BKE_light_add(struct Main *bmain, const char *name) ATTR_WARN_UNUS
struct Light *BKE_light_copy(struct Main *bmain, const struct Light *la) ATTR_WARN_UNUSED_RESULT;
struct Light *BKE_light_localize(struct Light *la) ATTR_WARN_UNUSED_RESULT;
+void BKE_light_eval(struct Depsgraph *depsgraph, struct Light *la);
+
#ifdef __cplusplus
}
#endif
diff --git a/source/blender/blenkernel/BKE_main.h b/source/blender/blenkernel/BKE_main.h
index 306d889fba4..516148728d2 100644
--- a/source/blender/blenkernel/BKE_main.h
+++ b/source/blender/blenkernel/BKE_main.h
@@ -87,7 +87,7 @@ enum {
typedef struct Main {
struct Main *next, *prev;
char name[1024]; /* 1024 = FILE_MAX */
- short versionfile, subversionfile; /* see BLENDER_VERSION, BLENDER_SUBVERSION */
+ short versionfile, subversionfile; /* see BLENDER_FILE_VERSION, BLENDER_FILE_SUBVERSION */
short minversionfile, minsubversionfile;
uint64_t build_commit_timestamp; /* commit's timestamp from buildinfo */
char build_hash[16]; /* hash from buildinfo */
@@ -105,6 +105,12 @@ typedef struct Main {
*/
char use_memfile_full_barrier;
+ /**
+ * When linking, disallow creation of new data-blocks.
+ * Make sure we don't do this by accident, see T76738.
+ */
+ char is_locked_for_linking;
+
BlendThumbnail *blen_thumb;
struct Library *curlib;
@@ -147,6 +153,7 @@ typedef struct Main {
ListBase hairs;
ListBase pointclouds;
ListBase volumes;
+ ListBase simulations;
/**
* Must be generated, used and freed by same code - never assume this is valid data unless you
@@ -220,16 +227,16 @@ const char *BKE_main_blendfile_path_from_global(void);
struct ListBase *which_libbase(struct Main *mainlib, short type);
-#define MAX_LIBARRAY 40
+#define MAX_LIBARRAY 41
int set_listbasepointers(struct Main *main, struct ListBase *lb[MAX_LIBARRAY]);
#define MAIN_VERSION_ATLEAST(main, ver, subver) \
((main)->versionfile > (ver) || \
- (main->versionfile == (ver) && (main)->subversionfile >= (subver)))
+ ((main)->versionfile == (ver) && (main)->subversionfile >= (subver)))
#define MAIN_VERSION_OLDER(main, ver, subver) \
((main)->versionfile < (ver) || \
- (main->versionfile == (ver) && (main)->subversionfile < (subver)))
+ ((main)->versionfile == (ver) && (main)->subversionfile < (subver)))
#define BLEN_THUMB_SIZE 128
diff --git a/source/blender/blenkernel/BKE_mask.h b/source/blender/blenkernel/BKE_mask.h
index cef26345980..dca677343ce 100644
--- a/source/blender/blenkernel/BKE_mask.h
+++ b/source/blender/blenkernel/BKE_mask.h
@@ -238,10 +238,10 @@ void BKE_mask_clipboard_paste_to_layer(struct Main *bmain, struct MaskLayer *mas
#define MASKPOINT_ISSEL_KNOT(p) (((p)->bezt.f2 & SELECT) != 0)
#define MASKPOINT_ISSEL_HANDLE(point, which_handle) \
- (((which_handle == MASK_WHICH_HANDLE_STICK) ? \
+ ((((which_handle) == MASK_WHICH_HANDLE_STICK) ? \
((((point)->bezt.f1 | (point)->bezt.f3) & SELECT)) : \
- ((which_handle == MASK_WHICH_HANDLE_LEFT) ? ((point)->bezt.f1 & SELECT) : \
- ((point)->bezt.f3 & SELECT))) != 0)
+ (((which_handle) == MASK_WHICH_HANDLE_LEFT) ? ((point)->bezt.f1 & SELECT) : \
+ ((point)->bezt.f3 & SELECT))) != 0)
#define MASKPOINT_SEL_ALL(p) \
{ \
diff --git a/source/blender/blenkernel/BKE_material.h b/source/blender/blenkernel/BKE_material.h
index ffa1970d8c6..225d966a51a 100644
--- a/source/blender/blenkernel/BKE_material.h
+++ b/source/blender/blenkernel/BKE_material.h
@@ -119,6 +119,7 @@ void BKE_material_copybuf_paste(struct Main *bmain, struct Material *ma);
/* Default Materials */
struct Material *BKE_material_default_empty(void);
+struct Material *BKE_material_default_holdout(void);
struct Material *BKE_material_default_surface(void);
struct Material *BKE_material_default_volume(void);
struct Material *BKE_material_default_gpencil(void);
diff --git a/source/blender/blenkernel/BKE_mesh.h b/source/blender/blenkernel/BKE_mesh.h
index f14b9a30d99..52d458c108d 100644
--- a/source/blender/blenkernel/BKE_mesh.h
+++ b/source/blender/blenkernel/BKE_mesh.h
@@ -85,12 +85,6 @@ struct Mesh *BKE_mesh_from_bmesh_for_eval_nomain(struct BMesh *bm,
const struct CustomData_MeshMasks *cd_mask_extra,
const struct Mesh *me_settings);
-struct Mesh *BKE_mesh_from_editmesh_with_coords_thin_wrap(
- struct BMEditMesh *em,
- const struct CustomData_MeshMasks *cd_mask_extra,
- float (*vertexCos)[3],
- const struct Mesh *me_settings);
-
int poly_find_loop_from_vert(const struct MPoly *poly, const struct MLoop *loopstart, uint vert);
int poly_get_adj_loops_from_vert(const struct MPoly *poly,
const struct MLoop *mloop,
@@ -673,6 +667,23 @@ void BKE_mesh_calc_edges_loose(struct Mesh *mesh);
void BKE_mesh_calc_edges(struct Mesh *mesh, bool update, const bool select);
void BKE_mesh_calc_edges_tessface(struct Mesh *mesh);
+/* *** mesh_geomtype.c *** */
+struct Mesh *BKE_mesh_wrapper_from_editmesh_with_coords(
+ struct BMEditMesh *em,
+ const struct CustomData_MeshMasks *cd_mask_extra,
+ float (*vertexCos)[3],
+ const struct Mesh *me_settings);
+struct Mesh *BKE_mesh_wrapper_from_editmesh(struct BMEditMesh *em,
+ const struct CustomData_MeshMasks *cd_mask_extra,
+ const struct Mesh *me_settings);
+void BKE_mesh_wrapper_ensure_mdata(struct Mesh *me);
+bool BKE_mesh_wrapper_minmax(const struct Mesh *me, float min[3], float max[3]);
+void BKE_mesh_wrapper_normals_update(struct Mesh *me);
+
+/* In DerivedMesh.c */
+void BKE_mesh_wrapper_deferred_finalize(struct Mesh *me_eval,
+ const CustomData_MeshMasks *final_datamask);
+
/* **** Depsgraph evaluation **** */
void BKE_mesh_eval_geometry(struct Depsgraph *depsgraph, struct Mesh *mesh);
diff --git a/source/blender/blenkernel/BKE_modifier.h b/source/blender/blenkernel/BKE_modifier.h
index c37e56149eb..ad67ee290b0 100644
--- a/source/blender/blenkernel/BKE_modifier.h
+++ b/source/blender/blenkernel/BKE_modifier.h
@@ -100,7 +100,10 @@ typedef enum {
/* For modifiers that use CD_PREVIEW_MCOL for preview. */
eModifierTypeFlag_UsesPreview = (1 << 9),
- eModifierTypeFlag_AcceptsLattice = (1 << 10),
+ eModifierTypeFlag_AcceptsVertexCosOnly = (1 << 10),
+
+ /** Accepts #BMesh input (without conversion). */
+ eModifierTypeFlag_AcceptsBMesh = (1 << 11),
} ModifierTypeFlag;
/* IMPORTANT! Keep ObjectWalkFunc and IDWalkFunc signatures compatible. */
@@ -211,18 +214,28 @@ typedef struct ModifierTypeInfo {
/********************* Non-deform modifier functions *********************/
- /* For non-deform types: apply the modifier and return a mesh object.
+ /* For non-deform types: apply the modifier and return a mesh data-block.
*
- * The mesh argument should always be non-NULL; the modifier
- * should read the object data from the mesh object instead of the
- * actual object data.
+ * The mesh argument should always be non-NULL; the modifier should use the
+ * passed in mesh data-block rather than object->data, as it contains the mesh
+ * with modifier applied up to this point.
*
- * The modifier may reuse the mesh argument (i.e. return it in
- * modified form), but must not release it.
+ * The modifier may modify and return the mesh argument, but must not free it
+ * and must ensure any referenced data layers are converted to non-referenced
+ * before modification.
*/
- struct Mesh *(*applyModifier)(struct ModifierData *md,
- const struct ModifierEvalContext *ctx,
- struct Mesh *mesh);
+ struct Mesh *(*modifyMesh)(struct ModifierData *md,
+ const struct ModifierEvalContext *ctx,
+ struct Mesh *mesh);
+ struct Hair *(*modifyHair)(struct ModifierData *md,
+ const struct ModifierEvalContext *ctx,
+ struct Hair *hair);
+ struct PointCloud *(*modifyPointCloud)(struct ModifierData *md,
+ const struct ModifierEvalContext *ctx,
+ struct PointCloud *pointcloud);
+ struct Volume *(*modifyVolume)(struct ModifierData *md,
+ const struct ModifierEvalContext *ctx,
+ struct Volume *volume);
/********************* Optional functions *********************/
@@ -343,60 +356,64 @@ typedef struct ModifierTypeInfo {
/* Initialize modifier's global data (type info and some common global storages). */
void BKE_modifier_init(void);
-const ModifierTypeInfo *modifierType_getInfo(ModifierType type);
+const ModifierTypeInfo *BKE_modifier_get_info(ModifierType type);
/* Modifier utility calls, do call through type pointer and return
* default values if pointer is optional.
*/
-struct ModifierData *modifier_new(int type);
-void modifier_free_ex(struct ModifierData *md, const int flag);
-void modifier_free(struct ModifierData *md);
-
-bool modifier_unique_name(struct ListBase *modifiers, struct ModifierData *md);
-
-void modifier_copyData_generic(const struct ModifierData *md,
- struct ModifierData *target,
- const int flag);
-void modifier_copyData(struct ModifierData *md, struct ModifierData *target);
-void modifier_copyData_ex(struct ModifierData *md, struct ModifierData *target, const int flag);
-bool modifier_dependsOnTime(struct ModifierData *md);
-bool modifier_supportsMapping(struct ModifierData *md);
-bool modifier_supportsCage(struct Scene *scene, struct ModifierData *md);
-bool modifier_couldBeCage(struct Scene *scene, struct ModifierData *md);
-bool modifier_isCorrectableDeformed(struct ModifierData *md);
-bool modifier_isSameTopology(ModifierData *md);
-bool modifier_isNonGeometrical(ModifierData *md);
-bool modifier_isEnabled(const struct Scene *scene, struct ModifierData *md, int required_mode);
-void modifier_setError(struct ModifierData *md, const char *format, ...) ATTR_PRINTF_FORMAT(2, 3);
-bool modifier_isPreview(struct ModifierData *md);
-
-void modifiers_foreachObjectLink(struct Object *ob, ObjectWalkFunc walk, void *userData);
-void modifiers_foreachIDLink(struct Object *ob, IDWalkFunc walk, void *userData);
-void modifiers_foreachTexLink(struct Object *ob, TexWalkFunc walk, void *userData);
-
-struct ModifierData *modifiers_findByType(struct Object *ob, ModifierType type);
-struct ModifierData *modifiers_findByName(struct Object *ob, const char *name);
-void modifiers_clearErrors(struct Object *ob);
-int modifiers_getCageIndex(struct Scene *scene,
- struct Object *ob,
- int *r_lastPossibleCageIndex,
- bool is_virtual);
-
-bool modifiers_isModifierEnabled(struct Object *ob, int modifierType);
-bool modifiers_isSoftbodyEnabled(struct Object *ob);
-bool modifiers_isClothEnabled(struct Object *ob);
-bool modifiers_isParticleEnabled(struct Object *ob);
-
-struct Object *modifiers_isDeformedByArmature(struct Object *ob);
-struct Object *modifiers_isDeformedByMeshDeform(struct Object *ob);
-struct Object *modifiers_isDeformedByLattice(struct Object *ob);
-struct Object *modifiers_isDeformedByCurve(struct Object *ob);
-bool modifiers_usesMultires(struct Object *ob);
-bool modifiers_usesArmature(struct Object *ob, struct bArmature *arm);
-bool modifiers_usesSubsurfFacedots(struct Scene *scene, struct Object *ob);
-bool modifiers_isCorrectableDeformed(struct Scene *scene, struct Object *ob);
-void modifier_freeTemporaryData(struct ModifierData *md);
-bool modifiers_isPreview(struct Object *ob);
+struct ModifierData *BKE_modifier_new(int type);
+void BKE_modifier_free_ex(struct ModifierData *md, const int flag);
+void BKE_modifier_free(struct ModifierData *md);
+
+bool BKE_modifier_unique_name(struct ListBase *modifiers, struct ModifierData *md);
+
+void BKE_modifier_copydata_generic(const struct ModifierData *md,
+ struct ModifierData *target,
+ const int flag);
+void BKE_modifier_copydata(struct ModifierData *md, struct ModifierData *target);
+void BKE_modifier_copydata_ex(struct ModifierData *md,
+ struct ModifierData *target,
+ const int flag);
+bool BKE_modifier_depends_ontime(struct ModifierData *md);
+bool BKE_modifier_supports_mapping(struct ModifierData *md);
+bool BKE_modifier_supports_cage(struct Scene *scene, struct ModifierData *md);
+bool BKE_modifier_couldbe_cage(struct Scene *scene, struct ModifierData *md);
+bool BKE_modifier_is_correctable_deformed(struct ModifierData *md);
+bool BKE_modifier_is_same_topology(ModifierData *md);
+bool BKE_modifier_is_non_geometrical(ModifierData *md);
+bool BKE_modifier_is_enabled(const struct Scene *scene,
+ struct ModifierData *md,
+ int required_mode);
+void BKE_modifier_set_error(struct ModifierData *md, const char *format, ...)
+ ATTR_PRINTF_FORMAT(2, 3);
+bool BKE_modifier_is_preview(struct ModifierData *md);
+
+void BKE_modifiers_foreach_object_link(struct Object *ob, ObjectWalkFunc walk, void *userData);
+void BKE_modifiers_foreach_ID_link(struct Object *ob, IDWalkFunc walk, void *userData);
+void BKE_modifiers_foreach_tex_link(struct Object *ob, TexWalkFunc walk, void *userData);
+
+struct ModifierData *BKE_modifiers_findby_type(struct Object *ob, ModifierType type);
+struct ModifierData *BKE_modifiers_findby_name(struct Object *ob, const char *name);
+void BKE_modifiers_clear_errors(struct Object *ob);
+int BKE_modifiers_get_cage_index(struct Scene *scene,
+ struct Object *ob,
+ int *r_lastPossibleCageIndex,
+ bool is_virtual);
+
+bool BKE_modifiers_is_modifier_enabled(struct Object *ob, int modifierType);
+bool BKE_modifiers_is_softbody_enabled(struct Object *ob);
+bool BKE_modifiers_is_cloth_enabled(struct Object *ob);
+bool BKE_modifiers_is_particle_enabled(struct Object *ob);
+
+struct Object *BKE_modifiers_is_deformed_by_armature(struct Object *ob);
+struct Object *BKE_modifiers_is_deformed_by_meshdeform(struct Object *ob);
+struct Object *BKE_modifiers_is_deformed_by_lattice(struct Object *ob);
+struct Object *BKE_modifiers_is_deformed_by_curve(struct Object *ob);
+bool BKE_modifiers_uses_multires(struct Object *ob);
+bool BKE_modifiers_uses_armature(struct Object *ob, struct bArmature *arm);
+bool BKE_modifiers_uses_subsurf_facedots(struct Scene *scene, struct Object *ob);
+bool BKE_modifiers_is_correctable_deformed(struct Scene *scene, struct Object *ob);
+void BKE_modifier_free_temporary_data(struct ModifierData *md);
typedef struct CDMaskLink {
struct CDMaskLink *next;
@@ -408,16 +425,16 @@ typedef struct CDMaskLink {
* pointed to by md for correct evaluation, assuming the data indicated by
* final_datamask is required at the end of the stack.
*/
-struct CDMaskLink *modifiers_calcDataMasks(struct Scene *scene,
- struct Object *ob,
- struct ModifierData *md,
- struct CustomData_MeshMasks *final_datamask,
- int required_mode,
- ModifierData *previewmd,
- const struct CustomData_MeshMasks *previewmask);
-struct ModifierData *modifiers_getLastPreview(struct Scene *scene,
- struct ModifierData *md,
- int required_mode);
+struct CDMaskLink *BKE_modifier_calc_data_masks(struct Scene *scene,
+ struct Object *ob,
+ struct ModifierData *md,
+ struct CustomData_MeshMasks *final_datamask,
+ int required_mode,
+ ModifierData *previewmd,
+ const struct CustomData_MeshMasks *previewmask);
+struct ModifierData *BKE_modifier_get_last_preview(struct Scene *scene,
+ struct ModifierData *md,
+ int required_mode);
typedef struct VirtualModifierData {
ArmatureModifierData amd;
@@ -426,46 +443,46 @@ typedef struct VirtualModifierData {
ShapeKeyModifierData smd;
} VirtualModifierData;
-struct ModifierData *modifiers_getVirtualModifierList(const struct Object *ob,
- struct VirtualModifierData *data);
+struct ModifierData *BKE_modifiers_get_virtual_modifierlist(const struct Object *ob,
+ struct VirtualModifierData *data);
/* ensure modifier correctness when changing ob->data */
-void test_object_modifiers(struct Object *ob);
+void BKE_modifiers_test_object(struct Object *ob);
/* here for do_versions */
-void modifier_mdef_compact_influences(struct ModifierData *md);
+void BKE_modifier_mdef_compact_influences(struct ModifierData *md);
-void modifier_path_init(char *path, int path_maxlen, const char *name);
-const char *modifier_path_relbase(struct Main *bmain, struct Object *ob);
-const char *modifier_path_relbase_from_global(struct Object *ob);
+void BKE_modifier_path_init(char *path, int path_maxlen, const char *name);
+const char *BKE_modifier_path_relbase(struct Main *bmain, struct Object *ob);
+const char *BKE_modifier_path_relbase_from_global(struct Object *ob);
/* Accessors of original/evaluated modifiers. */
/* For a given modifier data, get corresponding original one.
* If the modifier data is already original, return it as-is. */
-struct ModifierData *modifier_get_original(struct ModifierData *md);
-struct ModifierData *modifier_get_evaluated(struct Depsgraph *depsgraph,
- struct Object *object,
- struct ModifierData *md);
+struct ModifierData *BKE_modifier_get_original(struct ModifierData *md);
+struct ModifierData *BKE_modifier_get_evaluated(struct Depsgraph *depsgraph,
+ struct Object *object,
+ struct ModifierData *md);
/* wrappers for modifier callbacks that ensure valid normals */
-struct Mesh *modwrap_applyModifier(ModifierData *md,
- const struct ModifierEvalContext *ctx,
- struct Mesh *me);
-
-void modwrap_deformVerts(ModifierData *md,
- const struct ModifierEvalContext *ctx,
- struct Mesh *me,
- float (*vertexCos)[3],
- int numVerts);
-
-void modwrap_deformVertsEM(ModifierData *md,
- const struct ModifierEvalContext *ctx,
- struct BMEditMesh *em,
- struct Mesh *me,
- float (*vertexCos)[3],
- int numVerts);
+struct Mesh *BKE_modifier_modify_mesh(ModifierData *md,
+ const struct ModifierEvalContext *ctx,
+ struct Mesh *me);
+
+void BKE_modifier_deform_verts(ModifierData *md,
+ const struct ModifierEvalContext *ctx,
+ struct Mesh *me,
+ float (*vertexCos)[3],
+ int numVerts);
+
+void BKE_modifier_deform_vertsEM(ModifierData *md,
+ const struct ModifierEvalContext *ctx,
+ struct BMEditMesh *em,
+ struct Mesh *me,
+ float (*vertexCos)[3],
+ int numVerts);
struct Mesh *BKE_modifier_get_evaluated_mesh_from_evaluated_object(struct Object *ob_eval,
const bool get_cage_mesh);
diff --git a/source/blender/blenkernel/BKE_multires.h b/source/blender/blenkernel/BKE_multires.h
index fe5b8cff31c..15ba72ef5b5 100644
--- a/source/blender/blenkernel/BKE_multires.h
+++ b/source/blender/blenkernel/BKE_multires.h
@@ -10,7 +10,7 @@
* 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,
+ * 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) 2007 by Nicholas Bishop
@@ -110,6 +110,11 @@ void multiresModifier_del_levels(struct MultiresModifierData *mmd,
void multiresModifier_base_apply(struct Depsgraph *depsgraph,
struct Object *object,
struct MultiresModifierData *mmd);
+int multiresModifier_rebuild_subdiv(struct Depsgraph *depsgraph,
+ struct Object *object,
+ struct MultiresModifierData *mmd,
+ int rebuild_limit,
+ bool switch_view_to_lower_level);
void multiresModifier_subdivide_legacy(struct MultiresModifierData *mmd,
struct Scene *scene,
struct Object *ob,
@@ -175,13 +180,25 @@ bool multiresModifier_reshapeFromCCG(const int tot_level,
struct SubdivCCG *subdiv_ccg);
/* Subdivide multires displacement once. */
-void multiresModifier_subdivide(struct Object *object, struct MultiresModifierData *mmd);
+
+typedef enum eMultiresSubdivideModeType {
+ MULTIRES_SUBDIVIDE_CATMULL_CLARK,
+ MULTIRES_SUBDIVIDE_SIMPLE,
+ MULTIRES_SUBDIVIDE_LINEAR,
+} eMultiresSubdivideModeType;
+
+void multiresModifier_subdivide(struct Object *object,
+ struct MultiresModifierData *mmd,
+ const eMultiresSubdivideModeType mode);
+void multires_subdivide_create_tangent_displacement_linear_grids(struct Object *object,
+ struct MultiresModifierData *mmd);
/* Subdivide displacement to the given level.
* If level is lower than the current top level nothing happens. */
void multiresModifier_subdivide_to_level(struct Object *object,
struct MultiresModifierData *mmd,
- const int top_level);
+ const int top_level,
+ const eMultiresSubdivideModeType mode);
/* Subdivision integration, defined in multires_subdiv.c */
@@ -213,8 +230,6 @@ BLI_INLINE void BKE_multires_construct_tangent_matrix(float tangent_matrix[3][3]
const float dPdv[3],
const int corner);
-int BKE_multires_sculpt_level_get(const struct MultiresModifierData *mmd);
-
#ifdef __cplusplus
}
#endif
diff --git a/source/blender/blenkernel/BKE_nla.h b/source/blender/blenkernel/BKE_nla.h
index e5a77bce0e6..2be8d657bf4 100644
--- a/source/blender/blenkernel/BKE_nla.h
+++ b/source/blender/blenkernel/BKE_nla.h
@@ -29,6 +29,7 @@ extern "C" {
#endif
struct AnimData;
+struct LibraryForeachIDData;
struct Main;
struct NlaStrip;
struct NlaTrack;
@@ -63,6 +64,8 @@ struct NlaStrip *BKE_nla_add_soundstrip(struct Main *bmain,
struct Scene *scene,
struct Speaker *spk);
+void BKE_nla_strip_foreach_id(struct NlaStrip *strip, struct LibraryForeachIDData *data);
+
/* ----------------------------- */
/* API */
diff --git a/source/blender/blenkernel/BKE_node.h b/source/blender/blenkernel/BKE_node.h
index dc06f56861a..536d04f8bd3 100644
--- a/source/blender/blenkernel/BKE_node.h
+++ b/source/blender/blenkernel/BKE_node.h
@@ -268,7 +268,7 @@ typedef struct bNodeType {
NodeGPUExecFunction gpufunc;
/* RNA integration */
- ExtensionRNA ext;
+ ExtensionRNA rna_ext;
} bNodeType;
/* nodetype->nclass, for add-menu and themes */
@@ -350,7 +350,7 @@ typedef struct bNodeTreeType {
void (*node_add_init)(struct bNodeTree *ntree, struct bNode *bnode);
/* RNA integration */
- ExtensionRNA ext;
+ ExtensionRNA rna_ext;
} bNodeTreeType;
/** \} */
@@ -385,8 +385,8 @@ struct bNodeTree *ntreeAddTree(struct Main *bmain, const char *name, const char
/* copy/free funcs, need to manage ID users */
void ntreeFreeTree(struct bNodeTree *ntree);
-/* Free tree which is owned byt another datablock. */
-void ntreeFreeNestedTree(struct bNodeTree *ntree);
+/* Free tree which is embedded into another datablock. */
+void ntreeFreeEmbeddedTree(struct bNodeTree *ntree);
struct bNodeTree *ntreeCopyTree_ex(const struct bNodeTree *ntree,
struct Main *bmain,
const bool do_id_user);
@@ -852,6 +852,7 @@ struct NodeTreeIterStore {
struct Light *light;
struct World *world;
struct FreestyleLineStyle *linestyle;
+ struct Simulation *simulation;
};
void BKE_node_tree_iter_init(struct NodeTreeIterStore *ntreeiter, struct Main *bmain);
@@ -1275,13 +1276,44 @@ int ntreeTexExecTree(struct bNodeTree *ntree,
float dyt[3],
int osatex,
const short thread,
- struct Tex *tex,
+ const struct Tex *tex,
short which_output,
int cfra,
int preview,
struct MTex *mtex);
/** \} */
+/* -------------------------------------------------------------------- */
+/** \name Simulation Nodes
+ * \{ */
+
+#define SIM_NODE_PARTICLE_SIMULATION 1000
+#define SIM_NODE_FORCE 1001
+#define SIM_NODE_SET_PARTICLE_ATTRIBUTE 1002
+#define SIM_NODE_PARTICLE_BIRTH_EVENT 1003
+#define SIM_NODE_PARTICLE_TIME_STEP_EVENT 1004
+#define SIM_NODE_EXECUTE_CONDITION 1005
+#define SIM_NODE_MULTI_EXECUTE 1006
+#define SIM_NODE_PARTICLE_MESH_EMITTER 1007
+#define SIM_NODE_PARTICLE_MESH_COLLISION_EVENT 1008
+#define SIM_NODE_EMIT_PARTICLES 1009
+#define SIM_NODE_TIME 1010
+#define SIM_NODE_PARTICLE_ATTRIBUTE 1011
+
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Function Nodes
+ * \{ */
+
+#define FN_NODE_BOOLEAN_MATH 1200
+#define FN_NODE_SWITCH 1201
+#define FN_NODE_FLOAT_COMPARE 1202
+#define FN_NODE_GROUP_INSTANCE_ID 1203
+#define FN_NODE_COMBINE_STRINGS 1204
+
+/** \} */
+
void init_nodesystem(void);
void free_nodesystem(void);
diff --git a/source/blender/blenkernel/BKE_object.h b/source/blender/blenkernel/BKE_object.h
index 75198cd3f63..3710ec810ce 100644
--- a/source/blender/blenkernel/BKE_object.h
+++ b/source/blender/blenkernel/BKE_object.h
@@ -21,12 +21,15 @@
* \ingroup bke
* \brief General operations, lookup, etc. for blender objects.
*/
+
+#include "BLI_compiler_attrs.h"
+
+#include "DNA_object_enums.h"
+
#ifdef __cplusplus
extern "C" {
#endif
-#include "BLI_compiler_attrs.h"
-
struct Base;
struct BoundBox;
struct Depsgraph;
@@ -46,8 +49,6 @@ struct ShaderFxData;
struct View3D;
struct ViewLayer;
-#include "DNA_object_enums.h"
-
void BKE_object_workob_clear(struct Object *workob);
void BKE_object_workob_calc_parent(struct Depsgraph *depsgraph,
struct Scene *scene,
@@ -277,7 +278,7 @@ void BKE_object_eval_uber_data(struct Depsgraph *depsgraph,
void BKE_object_eval_assign_data(struct Object *object, struct ID *data, bool is_owned);
void BKE_object_eval_boundbox(struct Depsgraph *depsgraph, struct Object *object);
-void BKE_object_synchronize_to_original(struct Depsgraph *depsgraph, struct Object *object);
+void BKE_object_sync_to_original(struct Depsgraph *depsgraph, struct Object *object);
void BKE_object_eval_ptcache_reset(struct Depsgraph *depsgraph,
struct Scene *scene,
diff --git a/source/blender/blenkernel/BKE_paint.h b/source/blender/blenkernel/BKE_paint.h
index 881f3356a86..26ffd1bbfef 100644
--- a/source/blender/blenkernel/BKE_paint.h
+++ b/source/blender/blenkernel/BKE_paint.h
@@ -10,7 +10,7 @@
* 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,
+ * 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) 2009 by Nicholas Bishop
@@ -24,6 +24,9 @@
* \ingroup bke
*/
+#include "BLI_utildefines.h"
+#include "DNA_object_enums.h"
+
#ifdef __cplusplus
extern "C" {
#endif
@@ -65,9 +68,6 @@ struct tPaletteColorHSV;
enum eOverlayFlags;
-#include "BLI_utildefines.h"
-#include "DNA_object_enums.h"
-
extern const char PAINT_CURSOR_SCULPT[3];
extern const char PAINT_CURSOR_VERTEX_PAINT[3];
extern const char PAINT_CURSOR_WEIGHT_PAINT[3];
@@ -239,6 +239,7 @@ typedef struct SculptPoseIKChainSegment {
float initial_orig[3];
float initial_head[3];
float len;
+ float scale;
float rot[4];
float *weights;
@@ -252,6 +253,7 @@ typedef struct SculptPoseIKChainSegment {
typedef struct SculptPoseIKChain {
SculptPoseIKChainSegment *segments;
int tot_segments;
+ float grab_delta_offset[3];
} SculptPoseIKChain;
/* Cloth Brush */
@@ -279,15 +281,30 @@ typedef struct SculptClothSimulation {
} SculptClothSimulation;
+typedef struct SculptLayerPersistentBase {
+ float co[3];
+ float no[3];
+ float disp;
+} SculptLayerPersistentBase;
+
/* Session data (mode-specific) */
typedef struct SculptSession {
/* Mesh data (not copied) can come either directly from a Mesh, or from a MultiresDM */
- struct MultiresModifierData *multires; /* Special handling for multires meshes */
+ struct { /* Special handling for multires meshes */
+ bool active;
+ struct MultiresModifierData *modifier;
+ int level;
+ } multires;
+
+ /* These are always assigned to base mesh data when using PBVH_FACES and PBVH_GRIDS. */
struct MVert *mvert;
struct MPoly *mpoly;
struct MLoop *mloop;
+
+ /* These contain the vertex and poly counts of the final mesh. */
int totvert, totpoly;
+
struct KeyBlock *shapekey_active;
float *vmask;
@@ -296,6 +313,8 @@ typedef struct SculptSession {
int *pmap_mem;
/* Mesh Face Sets */
+ /* Total number of polys of the base mesh. */
+ int totfaces;
int *face_sets;
/* BMesh for dynamic topology sculpting */
@@ -324,15 +343,15 @@ typedef struct SculptSession {
unsigned int texcache_side, *texcache, texcache_actual;
struct ImagePool *tex_pool;
- /* Layer brush persistence between strokes */
- float (*layer_co)[3]; /* Copy of the mesh vertices' locations */
-
struct StrokeCache *cache;
struct FilterCache *filter_cache;
/* Cursor data and active vertex for tools */
int active_vertex_index;
+ int active_face_index;
+ int active_grid_index;
+
float cursor_radius;
float cursor_location[3];
float cursor_normal[3];
@@ -351,6 +370,10 @@ typedef struct SculptSession {
float pose_origin[3];
SculptPoseIKChain *pose_ik_chain_preview;
+ /* Layer brush persistence between strokes */
+ /* This is freed with the PBVH, so it is always in sync with the mesh. */
+ SculptLayerPersistentBase *layer_base;
+
/* Transform operator */
float pivot_pos[3];
float pivot_rot[4];
@@ -381,7 +404,7 @@ typedef struct SculptSession {
/* TODO: identify sculpt-only fields */
// struct { ... } sculpt;
} mode;
- int mode_type;
+ eObjectMode mode_type;
/* This flag prevents PBVH from being freed when creating the vp_handle for texture paint. */
bool building_vp_handle;
diff --git a/source/blender/blenkernel/BKE_particle.h b/source/blender/blenkernel/BKE_particle.h
index eff546a7c55..00d010cd6d9 100644
--- a/source/blender/blenkernel/BKE_particle.h
+++ b/source/blender/blenkernel/BKE_particle.h
@@ -270,7 +270,7 @@ BLI_INLINE float psys_frand(ParticleSystem *psys, unsigned int seed)
/* XXX far from ideal, this simply scrambles particle random numbers a bit
* to avoid obvious correlations.
* Can't use previous psys->frand arrays because these require initialization
- * inside psys_check_enabled, which wreaks havoc in multi-threaded depgraph updates.
+ * inside psys_check_enabled, which wreaks havoc in multi-threaded depsgraph updates.
*/
unsigned int offset = PSYS_FRAND_SEED_OFFSET[psys->seed % PSYS_FRAND_COUNT];
unsigned int multiplier = PSYS_FRAND_SEED_MULTIPLIER[psys->seed % PSYS_FRAND_COUNT];
@@ -430,7 +430,7 @@ void psys_apply_child_modifiers(struct ParticleThreadContext *ctx,
const float parent_orco[3]);
void psys_sph_init(struct ParticleSimulationData *sim, struct SPHData *sphdata);
-void psys_sph_finalise(struct SPHData *sphdata);
+void psys_sph_finalize(struct SPHData *sphdata);
void psys_sph_density(struct BVHTree *tree, struct SPHData *data, float co[3], float vars[2]);
/* for anim.c */
diff --git a/source/blender/blenkernel/BKE_pbvh.h b/source/blender/blenkernel/BKE_pbvh.h
index 16a7e4d38d0..8fb6f140822 100644
--- a/source/blender/blenkernel/BKE_pbvh.h
+++ b/source/blender/blenkernel/BKE_pbvh.h
@@ -48,6 +48,7 @@ struct Mesh;
struct PBVH;
struct PBVHNode;
struct SubdivCCG;
+struct TaskParallelSettings;
struct TaskParallelTLS;
typedef struct PBVH PBVH;
@@ -81,6 +82,9 @@ typedef struct PBVHFrustumPlanes {
int num_planes;
} PBVHFrustumPlanes;
+void BKE_pbvh_set_frustum_planes(PBVH *pbvh, PBVHFrustumPlanes *planes);
+void BKE_pbvh_get_frustum_planes(PBVH *pbvh, PBVHFrustumPlanes *planes);
+
/* Callbacks */
/* returns 1 if the search should continue from this node, 0 otherwise */
@@ -94,7 +98,7 @@ typedef void (*BKE_pbvh_SearchNearestCallback)(PBVHNode *node, void *data, float
/* Building */
PBVH *BKE_pbvh_new(void);
-void BKE_pbvh_build_mesh(PBVH *bvh,
+void BKE_pbvh_build_mesh(PBVH *pbvh,
const struct Mesh *mesh,
const struct MPoly *mpoly,
const struct MLoop *mloop,
@@ -105,48 +109,47 @@ void BKE_pbvh_build_mesh(PBVH *bvh,
struct CustomData *pdata,
const struct MLoopTri *looptri,
int looptri_num);
-void BKE_pbvh_build_grids(PBVH *bvh,
+void BKE_pbvh_build_grids(PBVH *pbvh,
struct CCGElem **grid_elems,
int totgrid,
struct CCGKey *key,
void **gridfaces,
struct DMFlagMat *flagmats,
unsigned int **grid_hidden);
-void BKE_pbvh_build_bmesh(PBVH *bvh,
+void BKE_pbvh_build_bmesh(PBVH *pbvh,
struct BMesh *bm,
bool smooth_shading,
struct BMLog *log,
const int cd_vert_node_offset,
const int cd_face_node_offset);
-void BKE_pbvh_free(PBVH *bvh);
-void BKE_pbvh_free_layer_disp(PBVH *bvh);
+void BKE_pbvh_free(PBVH *pbvh);
/* Hierarchical Search in the BVH, two methods:
* - for each hit calling a callback
* - gather nodes in an array (easy to multithread) */
-void BKE_pbvh_search_callback(PBVH *bvh,
+void BKE_pbvh_search_callback(PBVH *pbvh,
BKE_pbvh_SearchCallback scb,
void *search_data,
BKE_pbvh_HitCallback hcb,
void *hit_data);
void BKE_pbvh_search_gather(
- PBVH *bvh, BKE_pbvh_SearchCallback scb, void *search_data, PBVHNode ***array, int *tot);
+ PBVH *pbvh, BKE_pbvh_SearchCallback scb, void *search_data, PBVHNode ***array, int *tot);
/* Raycast
* the hit callback is called for all leaf nodes intersecting the ray;
* it's up to the callback to find the primitive within the leaves that is
* hit first */
-void BKE_pbvh_raycast(PBVH *bvh,
+void BKE_pbvh_raycast(PBVH *pbvh,
BKE_pbvh_HitOccludedCallback cb,
void *data,
const float ray_start[3],
const float ray_normal[3],
bool original);
-bool BKE_pbvh_node_raycast(PBVH *bvh,
+bool BKE_pbvh_node_raycast(PBVH *pbvh,
PBVHNode *node,
float (*origco)[3],
bool use_origco,
@@ -155,6 +158,7 @@ bool BKE_pbvh_node_raycast(PBVH *bvh,
struct IsectRayPrecalc *isect_precalc,
float *depth,
int *active_vertex_index,
+ int *active_face_grid_index,
float *face_normal);
bool BKE_pbvh_bmesh_node_raycast_detail(PBVHNode *node,
@@ -166,16 +170,16 @@ bool BKE_pbvh_bmesh_node_raycast_detail(PBVHNode *node,
/* for orthographic cameras, project the far away ray segment points to the root node so
* we can have better precision. */
void BKE_pbvh_raycast_project_ray_root(
- PBVH *bvh, bool original, float ray_start[3], float ray_end[3], float ray_normal[3]);
+ PBVH *pbvh, bool original, float ray_start[3], float ray_end[3], float ray_normal[3]);
-void BKE_pbvh_find_nearest_to_ray(PBVH *bvh,
+void BKE_pbvh_find_nearest_to_ray(PBVH *pbvh,
BKE_pbvh_HitOccludedCallback cb,
void *data,
const float ray_start[3],
const float ray_normal[3],
bool original);
-bool BKE_pbvh_node_find_nearest_to_ray(PBVH *bvh,
+bool BKE_pbvh_node_find_nearest_to_ray(PBVH *pbvh,
PBVHNode *node,
float (*origco)[3],
bool use_origco,
@@ -186,15 +190,15 @@ bool BKE_pbvh_node_find_nearest_to_ray(PBVH *bvh,
/* Drawing */
-void BKE_pbvh_draw_cb(PBVH *bvh,
- bool show_vcol,
+void BKE_pbvh_draw_cb(PBVH *pbvh,
bool update_only_visible,
- PBVHFrustumPlanes *frustum,
+ PBVHFrustumPlanes *update_frustum,
+ PBVHFrustumPlanes *draw_frustum,
void (*draw_fn)(void *user_data, struct GPU_PBVH_Buffers *buffers),
void *user_data);
void BKE_pbvh_draw_debug_cb(
- PBVH *bvh,
+ PBVH *pbvh,
void (*draw_fn)(void *user_data, const float bmin[3], const float bmax[3], PBVHNodeFlags flag),
void *user_data);
@@ -205,24 +209,27 @@ typedef enum {
PBVH_BMESH,
} PBVHType;
-PBVHType BKE_pbvh_type(const PBVH *bvh);
-bool BKE_pbvh_has_faces(const PBVH *bvh);
+PBVHType BKE_pbvh_type(const PBVH *pbvh);
+bool BKE_pbvh_has_faces(const PBVH *pbvh);
/* Get the PBVH root's bounding box */
-void BKE_pbvh_bounding_box(const PBVH *bvh, float min[3], float max[3]);
+void BKE_pbvh_bounding_box(const PBVH *pbvh, float min[3], float max[3]);
/* multires hidden data, only valid for type == PBVH_GRIDS */
-unsigned int **BKE_pbvh_grid_hidden(const PBVH *bvh);
+unsigned int **BKE_pbvh_grid_hidden(const PBVH *pbvh);
int BKE_pbvh_count_grid_quads(BLI_bitmap **grid_hidden,
int *grid_indices,
int totgrid,
int gridsize);
+void BKE_pbvh_sync_face_sets_to_grids(PBVH *pbvh);
+
/* multires level, only valid for type == PBVH_GRIDS */
const struct CCGKey *BKE_pbvh_get_grid_key(const PBVH *pbvh);
struct CCGElem **BKE_pbvh_get_grids(const PBVH *pbvh);
+BLI_bitmap **BKE_pbvh_get_grid_visibility(const PBVH *pbvh);
int BKE_pbvh_get_grid_num_vertices(const PBVH *pbvh);
/* Only valid for type == PBVH_BMESH */
@@ -233,7 +240,7 @@ typedef enum {
PBVH_Subdivide = 1,
PBVH_Collapse = 2,
} PBVHTopologyUpdateMode;
-bool BKE_pbvh_bmesh_update_topology(PBVH *bvh,
+bool BKE_pbvh_bmesh_update_topology(PBVH *pbvh,
PBVHTopologyUpdateMode mode,
const float center[3],
const float view_normal[3],
@@ -256,15 +263,15 @@ bool BKE_pbvh_node_fully_masked_get(PBVHNode *node);
void BKE_pbvh_node_fully_unmasked_set(PBVHNode *node, int fully_masked);
bool BKE_pbvh_node_fully_unmasked_get(PBVHNode *node);
-void BKE_pbvh_node_get_grids(PBVH *bvh,
+void BKE_pbvh_node_get_grids(PBVH *pbvh,
PBVHNode *node,
int **grid_indices,
int *totgrid,
int *maxgrid,
int *gridsize,
struct CCGElem ***grid_elems);
-void BKE_pbvh_node_num_verts(PBVH *bvh, PBVHNode *node, int *r_uniquevert, int *r_totvert);
-void BKE_pbvh_node_get_verts(PBVH *bvh,
+void BKE_pbvh_node_num_verts(PBVH *pbvh, PBVHNode *node, int *r_uniquevert, int *r_totvert);
+void BKE_pbvh_node_get_verts(PBVH *pbvh,
PBVHNode *node,
const int **r_vert_indices,
struct MVert **r_verts);
@@ -283,31 +290,27 @@ struct GSet *BKE_pbvh_bmesh_node_unique_verts(PBVHNode *node);
struct GSet *BKE_pbvh_bmesh_node_other_verts(PBVHNode *node);
struct GSet *BKE_pbvh_bmesh_node_faces(PBVHNode *node);
void BKE_pbvh_bmesh_node_save_orig(struct BMesh *bm, PBVHNode *node);
-void BKE_pbvh_bmesh_after_stroke(PBVH *bvh);
+void BKE_pbvh_bmesh_after_stroke(PBVH *pbvh);
/* Update Bounding Box/Redraw and clear flags */
-void BKE_pbvh_update_bounds(PBVH *bvh, int flags);
-void BKE_pbvh_update_vertex_data(PBVH *bvh, int flags);
-void BKE_pbvh_update_visibility(PBVH *bvh);
-void BKE_pbvh_update_normals(PBVH *bvh, struct SubdivCCG *subdiv_ccg);
-void BKE_pbvh_redraw_BB(PBVH *bvh, float bb_min[3], float bb_max[3]);
-void BKE_pbvh_get_grid_updates(PBVH *bvh, bool clear, void ***r_gridfaces, int *r_totface);
-void BKE_pbvh_grids_update(PBVH *bvh,
+void BKE_pbvh_update_bounds(PBVH *pbvh, int flags);
+void BKE_pbvh_update_vertex_data(PBVH *pbvh, int flags);
+void BKE_pbvh_update_visibility(PBVH *pbvh);
+void BKE_pbvh_update_normals(PBVH *pbvh, struct SubdivCCG *subdiv_ccg);
+void BKE_pbvh_redraw_BB(PBVH *pbvh, float bb_min[3], float bb_max[3]);
+void BKE_pbvh_get_grid_updates(PBVH *pbvh, bool clear, void ***r_gridfaces, int *r_totface);
+void BKE_pbvh_grids_update(PBVH *pbvh,
struct CCGElem **grid_elems,
void **gridfaces,
struct DMFlagMat *flagmats,
unsigned int **grid_hidden);
+void BKE_pbvh_subdiv_cgg_set(PBVH *pbvh, struct SubdivCCG *subdiv_ccg);
+void BKE_pbvh_face_sets_set(PBVH *pbvh, int *face_sets);
-void BKE_pbvh_face_sets_color_set(PBVH *bvh, int seed, int color_default);
-
-/* Layer displacement */
+void BKE_pbvh_face_sets_color_set(PBVH *pbvh, int seed, int color_default);
-/* Get the node's displacement layer, creating it if necessary */
-float *BKE_pbvh_node_layer_disp_get(PBVH *pbvh, PBVHNode *node);
-
-/* If the node has a displacement layer, free it and set to null */
-void BKE_pbvh_node_layer_disp_free(PBVHNode *node);
+void BKE_pbvh_respect_hide_set(PBVH *pbvh, bool respect_hide);
/* vertex deformer */
float (*BKE_pbvh_vert_coords_alloc(struct PBVH *pbvh))[3];
@@ -334,6 +337,7 @@ typedef struct PBVHVertexIter {
int gy;
int i;
int index;
+ bool respect_hide;
/* grid */
struct CCGKey key;
@@ -367,10 +371,10 @@ typedef struct PBVHVertexIter {
bool visible;
} PBVHVertexIter;
-void pbvh_vertex_iter_init(PBVH *bvh, PBVHNode *node, PBVHVertexIter *vi, int mode);
+void pbvh_vertex_iter_init(PBVH *pbvh, PBVHNode *node, PBVHVertexIter *vi, int mode);
-#define BKE_pbvh_vertex_iter_begin(bvh, node, vi, mode) \
- pbvh_vertex_iter_init(bvh, node, &vi, mode); \
+#define BKE_pbvh_vertex_iter_begin(pbvh, node, vi, mode) \
+ pbvh_vertex_iter_init(pbvh, node, &vi, mode); \
\
for (vi.i = 0, vi.g = 0; vi.g < vi.totgrid; vi.g++) { \
if (vi.grids) { \
@@ -402,9 +406,15 @@ void pbvh_vertex_iter_init(PBVH *bvh, PBVHNode *node, PBVHVertexIter *vi, int mo
} \
else if (vi.mverts) { \
vi.mvert = &vi.mverts[vi.vert_indices[vi.gx]]; \
- vi.visible = !(vi.mvert->flag & ME_HIDE); \
- if (mode == PBVH_ITER_UNIQUE && !vi.visible) \
- continue; \
+ if (vi.respect_hide) { \
+ vi.visible = !(vi.mvert->flag & ME_HIDE); \
+ if (mode == PBVH_ITER_UNIQUE && !vi.visible) { \
+ continue; \
+ } \
+ } \
+ else { \
+ BLI_assert(vi.visible); \
+ } \
vi.co = vi.mvert->co; \
vi.no = vi.mvert->no; \
vi.index = vi.vert_indices[vi.i]; \
@@ -437,50 +447,30 @@ void pbvh_vertex_iter_init(PBVH *bvh, PBVHNode *node, PBVHVertexIter *vi, int mo
void BKE_pbvh_node_get_proxies(PBVHNode *node, PBVHProxyNode **proxies, int *proxy_count);
void BKE_pbvh_node_free_proxies(PBVHNode *node);
-PBVHProxyNode *BKE_pbvh_node_add_proxy(PBVH *bvh, PBVHNode *node);
+PBVHProxyNode *BKE_pbvh_node_add_proxy(PBVH *pbvh, PBVHNode *node);
void BKE_pbvh_gather_proxies(PBVH *pbvh, PBVHNode ***nodes, int *totnode);
void BKE_pbvh_node_get_bm_orco_data(PBVHNode *node,
int (**r_orco_tris)[3],
int *r_orco_tris_num,
float (**r_orco_coords)[3]);
-bool BKE_pbvh_node_vert_update_check_any(PBVH *bvh, PBVHNode *node);
+bool BKE_pbvh_node_vert_update_check_any(PBVH *pbvh, PBVHNode *node);
// void BKE_pbvh_node_BB_reset(PBVHNode *node);
// void BKE_pbvh_node_BB_expand(PBVHNode *node, float co[3]);
-bool pbvh_has_mask(PBVH *bvh);
-void pbvh_show_mask_set(PBVH *bvh, bool show_mask);
+bool pbvh_has_mask(PBVH *pbvh);
+void pbvh_show_mask_set(PBVH *pbvh, bool show_mask);
-bool pbvh_has_face_sets(PBVH *bvh);
-void pbvh_show_face_sets_set(PBVH *bvh, bool show_face_sets);
+bool pbvh_has_face_sets(PBVH *pbvh);
+void pbvh_show_face_sets_set(PBVH *pbvh, bool show_face_sets);
/* Parallelization */
-typedef void (*PBVHParallelRangeFunc)(void *__restrict userdata,
- const int iter,
- const struct TaskParallelTLS *__restrict tls);
-typedef void (*PBVHParallelReduceFunc)(const void *__restrict userdata,
- void *__restrict chunk_join,
- void *__restrict chunk);
-
-typedef struct PBVHParallelSettings {
- bool use_threading;
- void *userdata_chunk;
- size_t userdata_chunk_size;
- PBVHParallelReduceFunc func_reduce;
-} PBVHParallelSettings;
-
-void BKE_pbvh_parallel_range_settings(struct PBVHParallelSettings *settings,
+void BKE_pbvh_parallel_range_settings(struct TaskParallelSettings *settings,
bool use_threading,
int totnode);
-void BKE_pbvh_parallel_range(const int start,
- const int stop,
- void *userdata,
- PBVHParallelRangeFunc func,
- const struct PBVHParallelSettings *settings);
-
-struct MVert *BKE_pbvh_get_verts(const PBVH *bvh);
+struct MVert *BKE_pbvh_get_verts(const PBVH *pbvh);
#ifdef __cplusplus
}
diff --git a/source/blender/blenkernel/BKE_pointcache.h b/source/blender/blenkernel/BKE_pointcache.h
index c2fad6db314..164783f4d14 100644
--- a/source/blender/blenkernel/BKE_pointcache.h
+++ b/source/blender/blenkernel/BKE_pointcache.h
@@ -10,7 +10,7 @@
* 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,
+ * 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) 2006 Blender Foundation.
diff --git a/source/blender/blenkernel/BKE_report.h b/source/blender/blenkernel/BKE_report.h
index d7ce9625548..063c0831a0d 100644
--- a/source/blender/blenkernel/BKE_report.h
+++ b/source/blender/blenkernel/BKE_report.h
@@ -21,16 +21,16 @@
* \ingroup bke
*/
-#ifdef __cplusplus
-extern "C" {
-#endif
-
#include <stdio.h>
#include "BLI_compiler_attrs.h"
#include "BLI_utildefines.h"
#include "DNA_windowmanager_types.h"
+#ifdef __cplusplus
+extern "C" {
+#endif
+
/* Reporting Information and Errors
*
* These functions also accept NULL in case no error reporting
diff --git a/source/blender/blenkernel/BKE_rigidbody.h b/source/blender/blenkernel/BKE_rigidbody.h
index 9d4d53bf27f..b4aa0ac2b93 100644
--- a/source/blender/blenkernel/BKE_rigidbody.h
+++ b/source/blender/blenkernel/BKE_rigidbody.h
@@ -121,16 +121,16 @@ void BKE_rigidbody_remove_constraint(struct Main *bmain,
/* get mass of Rigid Body Object to supply to RigidBody simulators */
#define RBO_GET_MASS(rbo) \
- ((rbo && ((rbo->type == RBO_TYPE_PASSIVE) || (rbo->flag & RBO_FLAG_KINEMATIC) || \
- (rbo->flag & RBO_FLAG_DISABLED))) ? \
+ (((rbo) && (((rbo)->type == RBO_TYPE_PASSIVE) || ((rbo)->flag & RBO_FLAG_KINEMATIC) || \
+ ((rbo)->flag & RBO_FLAG_DISABLED))) ? \
(0.0f) : \
- (rbo->mass))
+ ((rbo)->mass))
/* Get collision margin for Rigid Body Object, triangle mesh and cone shapes cannot embed margin,
* convex hull always uses custom margin. */
#define RBO_GET_MARGIN(rbo) \
- ((rbo->flag & RBO_FLAG_USE_MARGIN || rbo->shape == RB_SHAPE_CONVEXH || \
- rbo->shape == RB_SHAPE_TRIMESH || rbo->shape == RB_SHAPE_CONE) ? \
- (rbo->margin) : \
+ (((rbo)->flag & RBO_FLAG_USE_MARGIN || (rbo)->shape == RB_SHAPE_CONVEXH || \
+ (rbo)->shape == RB_SHAPE_TRIMESH || (rbo)->shape == RB_SHAPE_CONE) ? \
+ ((rbo)->margin) : \
(0.04f))
/* -------------- */
diff --git a/source/blender/blenkernel/BKE_scene.h b/source/blender/blenkernel/BKE_scene.h
index c10f8d39bb2..dca6f569e25 100644
--- a/source/blender/blenkernel/BKE_scene.h
+++ b/source/blender/blenkernel/BKE_scene.h
@@ -141,6 +141,7 @@ int BKE_scene_orientation_slot_get_index(const struct TransformOrientationSlot *
/* ** Scene evaluation ** */
void BKE_scene_update_sound(struct Depsgraph *depsgraph, struct Main *bmain);
+void BKE_scene_update_tag_audio_volume(struct Depsgraph *, struct Scene *scene);
void BKE_scene_graph_update_tagged(struct Depsgraph *depsgraph, struct Main *bmain);
void BKE_scene_graph_evaluated_ensure(struct Depsgraph *depsgraph, struct Main *bmain);
diff --git a/source/blender/blenkernel/BKE_screen.h b/source/blender/blenkernel/BKE_screen.h
index b394d822164..ccb5e0b69b6 100644
--- a/source/blender/blenkernel/BKE_screen.h
+++ b/source/blender/blenkernel/BKE_screen.h
@@ -34,6 +34,7 @@ extern "C" {
struct ARegion;
struct Header;
struct ID;
+struct LibraryForeachIDData;
struct ListBase;
struct Menu;
struct Panel;
@@ -76,25 +77,25 @@ typedef struct SpaceType {
/* Initial allocation, after this WM will call init() too. Some editors need
* area and scene data (e.g. frame range) to set their initial scrolling. */
- struct SpaceLink *(*new)(const struct ScrArea *sa, const struct Scene *scene);
+ struct SpaceLink *(*new)(const struct ScrArea *area, const struct Scene *scene);
/* not free spacelink itself */
void (*free)(struct SpaceLink *sl);
/* init is to cope with file load, screen (size) changes, check handlers */
- void (*init)(struct wmWindowManager *wm, struct ScrArea *sa);
+ void (*init)(struct wmWindowManager *wm, struct ScrArea *area);
/* exit is called when the area is hidden or removed */
- void (*exit)(struct wmWindowManager *wm, struct ScrArea *sa);
+ void (*exit)(struct wmWindowManager *wm, struct ScrArea *area);
/* Listeners can react to bContext changes */
void (*listener)(struct wmWindow *win,
- struct ScrArea *sa,
+ struct ScrArea *area,
struct wmNotifier *wmn,
struct Scene *scene);
/* called when the mouse moves out of the area */
- void (*deactivate)(struct ScrArea *sa);
+ void (*deactivate)(struct ScrArea *area);
/* refresh context, called after filereads, ED_area_tag_refresh() */
- void (*refresh)(const struct bContext *C, struct ScrArea *sa);
+ void (*refresh)(const struct bContext *C, struct ScrArea *area);
/* after a spacedata copy, an init should result in exact same situation */
struct SpaceLink *(*duplicate)(struct SpaceLink *sl);
@@ -111,10 +112,13 @@ typedef struct SpaceType {
int (*context)(const struct bContext *C, const char *member, struct bContextDataResult *result);
/* Used when we want to replace an ID by another (or NULL). */
- void (*id_remap)(struct ScrArea *sa, struct SpaceLink *sl, struct ID *old_id, struct ID *new_id);
+ void (*id_remap)(struct ScrArea *area,
+ struct SpaceLink *sl,
+ struct ID *old_id,
+ struct ID *new_id);
- int (*space_subtype_get)(struct ScrArea *sa);
- void (*space_subtype_set)(struct ScrArea *sa, int value);
+ int (*space_subtype_get)(struct ScrArea *area);
+ void (*space_subtype_set)(struct ScrArea *area, int value);
void (*space_subtype_item_extend)(struct bContext *C, EnumPropertyItem **item, int *totitem);
/* get drop target for data */
@@ -152,7 +156,7 @@ typedef struct ARegionType {
int (*snap_size)(const struct ARegion *region, int size, int axis);
/* contextual changes should be handled here */
void (*listener)(struct wmWindow *win,
- struct ScrArea *sa,
+ struct ScrArea *area,
struct ARegion *region,
struct wmNotifier *wmn,
const struct Scene *scene);
@@ -160,8 +164,8 @@ typedef struct ARegionType {
void (*message_subscribe)(const struct bContext *C,
struct WorkSpace *workspace,
struct Scene *scene,
- struct bScreen *sc,
- struct ScrArea *sa,
+ struct bScreen *screen,
+ struct ScrArea *area,
struct ARegion *region,
struct wmMsgBus *mbus);
@@ -175,7 +179,7 @@ typedef struct ARegionType {
/* add own items to keymap */
void (*keymap)(struct wmKeyConfig *keyconf);
/* allows default cursor per region */
- void (*cursor)(struct wmWindow *win, struct ScrArea *sa, struct ARegion *region);
+ void (*cursor)(struct wmWindow *win, struct ScrArea *area, struct ARegion *region);
/* return context data */
int (*context)(const struct bContext *C, const char *member, struct bContextDataResult *result);
@@ -227,18 +231,37 @@ typedef struct PanelType {
/* verify if the panel should draw or not */
bool (*poll)(const struct bContext *C, struct PanelType *pt);
/* draw header (optional) */
- void (*draw_header)(const struct bContext *C, struct Panel *pa);
+ void (*draw_header)(const struct bContext *C, struct Panel *panel);
/* draw header preset (optional) */
- void (*draw_header_preset)(const struct bContext *C, struct Panel *pa);
+ void (*draw_header_preset)(const struct bContext *C, struct Panel *panel);
/* draw entirely, view changes should be handled here */
- void (*draw)(const struct bContext *C, struct Panel *pa);
+ void (*draw)(const struct bContext *C, struct Panel *panel);
+
+ /* For instanced panels corresponding to a list: */
+
+ /** Reorder function, called when drag and drop finishes. */
+ void (*reorder)(struct bContext *C, struct Panel *pa, int new_index);
+ /**
+ * Get the panel and sub-panel's expansion state from the expansion flag in the corresponding
+ * data item. Called on draw updates.
+ * \note Sub-panels are indexed in depth first order,
+ * the visual order you would see if all panels were expanded.
+ */
+ short (*get_list_data_expand_flag)(const struct bContext *C, struct Panel *pa);
+ /**
+ * Set the expansion bit-field from the closed / open state of this panel and its sub-panels.
+ * Called when the expansion state of the panel changes with user input.
+ * \note Sub-panels are indexed in depth first order,
+ * the visual order you would see if all panels were expanded.
+ */
+ void (*set_list_data_expand_flag)(const struct bContext *C, struct Panel *pa, short expand_flag);
/* sub panels */
struct PanelType *parent;
ListBase children;
/* RNA integration */
- ExtensionRNA ext;
+ ExtensionRNA rna_ext;
} PanelType;
/* uilist types */
@@ -276,7 +299,7 @@ typedef struct uiListType {
uiListFilterItemsFunc filter_items;
/* RNA integration */
- ExtensionRNA ext;
+ ExtensionRNA rna_ext;
} uiListType;
/* header types */
@@ -293,7 +316,7 @@ typedef struct HeaderType {
void (*draw)(const struct bContext *C, struct Header *header);
/* RNA integration */
- ExtensionRNA ext;
+ ExtensionRNA rna_ext;
} HeaderType;
typedef struct Header {
@@ -318,7 +341,7 @@ typedef struct MenuType {
void (*draw)(const struct bContext *C, struct Menu *menu);
/* RNA integration */
- ExtensionRNA ext;
+ ExtensionRNA rna_ext;
} MenuType;
typedef struct Menu {
@@ -341,44 +364,48 @@ void BKE_spacedata_copylist(ListBase *lb1, ListBase *lb2);
void BKE_spacedata_draw_locks(int set);
struct ARegion *BKE_spacedata_find_region_type(const struct SpaceLink *slink,
- const struct ScrArea *sa,
+ const struct ScrArea *area,
int region_type) ATTR_WARN_UNUSED_RESULT
ATTR_NONNULL();
-void BKE_spacedata_callback_id_remap_set(
- void (*func)(struct ScrArea *sa, struct SpaceLink *sl, struct ID *old_id, struct ID *new_id));
-void BKE_spacedata_id_unref(struct ScrArea *sa, struct SpaceLink *sl, struct ID *id);
+void BKE_spacedata_callback_id_remap_set(void (*func)(
+ struct ScrArea *area, struct SpaceLink *sl, struct ID *old_id, struct ID *new_id));
+void BKE_spacedata_id_unref(struct ScrArea *area, struct SpaceLink *sl, struct ID *id);
/* area/regions */
struct ARegion *BKE_area_region_copy(struct SpaceType *st, struct ARegion *region);
void BKE_area_region_free(struct SpaceType *st, struct ARegion *region);
void BKE_area_region_panels_free(struct ListBase *panels);
-void BKE_screen_area_free(struct ScrArea *sa);
+void BKE_screen_area_free(struct ScrArea *area);
/* Gizmo-maps of a region need to be freed with the region.
* Uses callback to avoid low-level call. */
void BKE_region_callback_free_gizmomap_set(void (*callback)(struct wmGizmoMap *));
void BKE_region_callback_refresh_tag_gizmomap_set(void (*callback)(struct wmGizmoMap *));
-struct ARegion *BKE_area_find_region_type(const struct ScrArea *sa, int type);
-struct ARegion *BKE_area_find_region_active_win(struct ScrArea *sa);
-struct ARegion *BKE_area_find_region_xy(struct ScrArea *sa, const int regiontype, int x, int y);
-struct ARegion *BKE_screen_find_region_xy(struct bScreen *sc, const int regiontype, int x, int y)
- ATTR_WARN_UNUSED_RESULT ATTR_NONNULL(1);
+struct ARegion *BKE_area_find_region_type(const struct ScrArea *area, int type);
+struct ARegion *BKE_area_find_region_active_win(struct ScrArea *area);
+struct ARegion *BKE_area_find_region_xy(struct ScrArea *area, const int regiontype, int x, int y);
+struct ARegion *BKE_screen_find_region_xy(struct bScreen *screen,
+ const int regiontype,
+ int x,
+ int y) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL(1);
-struct ScrArea *BKE_screen_find_area_from_space(struct bScreen *sc,
+struct ScrArea *BKE_screen_find_area_from_space(struct bScreen *screen,
struct SpaceLink *sl) ATTR_WARN_UNUSED_RESULT
ATTR_NONNULL(1, 2);
-struct ScrArea *BKE_screen_find_big_area(struct bScreen *sc, const int spacetype, const short min);
+struct ScrArea *BKE_screen_find_big_area(struct bScreen *screen,
+ const int spacetype,
+ const short min);
struct ScrArea *BKE_screen_area_map_find_area_xy(const struct ScrAreaMap *areamap,
const int spacetype,
int x,
int y);
-struct ScrArea *BKE_screen_find_area_xy(struct bScreen *sc, const int spacetype, int x, int y);
+struct ScrArea *BKE_screen_find_area_xy(struct bScreen *screen, const int spacetype, int x, int y);
-void BKE_screen_gizmo_tag_refresh(struct bScreen *sc);
+void BKE_screen_gizmo_tag_refresh(struct bScreen *screen);
void BKE_screen_view3d_sync(struct View3D *v3d, struct Scene *scene);
-void BKE_screen_view3d_scene_sync(struct bScreen *sc, struct Scene *scene);
+void BKE_screen_view3d_scene_sync(struct bScreen *screen, struct Scene *scene);
bool BKE_screen_is_fullscreen_area(const struct bScreen *screen) ATTR_WARN_UNUSED_RESULT
ATTR_NONNULL();
bool BKE_screen_is_used(const struct bScreen *screen) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL();
@@ -390,15 +417,19 @@ float BKE_screen_view3d_zoom_from_fac(float zoomfac);
void BKE_screen_view3d_shading_init(struct View3DShading *shading);
/* screen */
-void BKE_screen_free(struct bScreen *sc);
+void BKE_screen_foreach_id_screen_area(struct LibraryForeachIDData *data, struct ScrArea *area);
+
+void BKE_screen_free(struct bScreen *screen);
void BKE_screen_area_map_free(struct ScrAreaMap *area_map) ATTR_NONNULL();
-struct ScrEdge *BKE_screen_find_edge(struct bScreen *sc, struct ScrVert *v1, struct ScrVert *v2);
+struct ScrEdge *BKE_screen_find_edge(struct bScreen *screen,
+ struct ScrVert *v1,
+ struct ScrVert *v2);
void BKE_screen_sort_scrvert(struct ScrVert **v1, struct ScrVert **v2);
-void BKE_screen_remove_double_scrverts(struct bScreen *sc);
-void BKE_screen_remove_double_scredges(struct bScreen *sc);
-void BKE_screen_remove_unused_scredges(struct bScreen *sc);
-void BKE_screen_remove_unused_scrverts(struct bScreen *sc);
+void BKE_screen_remove_double_scrverts(struct bScreen *screen);
+void BKE_screen_remove_double_scredges(struct bScreen *screen);
+void BKE_screen_remove_unused_scredges(struct bScreen *screen);
+void BKE_screen_remove_unused_scrverts(struct bScreen *screen);
void BKE_screen_header_alignment_reset(struct bScreen *screen);
diff --git a/source/blender/blenkernel/BKE_sequencer.h b/source/blender/blenkernel/BKE_sequencer.h
index 556cd7105a9..a50f9b24c61 100644
--- a/source/blender/blenkernel/BKE_sequencer.h
+++ b/source/blender/blenkernel/BKE_sequencer.h
@@ -35,6 +35,7 @@ struct GSet;
struct ImBuf;
struct Main;
struct Mask;
+struct ReportList;
struct Scene;
struct Sequence;
struct SequenceModifierData;
@@ -218,6 +219,15 @@ struct ImBuf *BKE_sequencer_give_ibuf_seqbase(const SeqRenderData *context,
float cfra,
int chan_shown,
struct ListBase *seqbasep);
+struct ImBuf *BKE_sequencer_effect_execute_threaded(struct SeqEffectHandle *sh,
+ const SeqRenderData *context,
+ struct Sequence *seq,
+ float cfra,
+ float facf0,
+ float facf1,
+ struct ImBuf *ibuf1,
+ struct ImBuf *ibuf2,
+ struct ImBuf *ibuf3);
/* **********************************************************************
* sequencer.c
@@ -265,7 +275,7 @@ void BKE_sequencer_base_clipboard_pointers_free(struct ListBase *seqbase);
void BKE_sequencer_base_clipboard_pointers_store(struct Main *bmain, struct ListBase *seqbase);
void BKE_sequencer_base_clipboard_pointers_restore(struct ListBase *seqbase, struct Main *bmain);
-void BKE_sequence_free(struct Scene *scene, struct Sequence *seq);
+void BKE_sequence_free(struct Scene *scene, struct Sequence *seq, const bool do_clean_animdata);
void BKE_sequence_free_anim(struct Sequence *seq);
const char *BKE_sequence_give_name(struct Sequence *seq);
ListBase *BKE_sequence_seqbase_get(struct Sequence *seq, int *r_offset);
@@ -276,6 +286,10 @@ void BKE_sequence_reload_new_file(struct Main *bmain,
struct Sequence *seq,
const bool lock_range);
int BKE_sequencer_evaluate_frame(struct Scene *scene, int cfra);
+int BKE_sequencer_get_shown_sequences(struct ListBase *seqbasep,
+ int cfra,
+ int chanshown,
+ struct Sequence **seq_arr_out);
struct StripElem *BKE_sequencer_give_stripelem(struct Sequence *seq, int cfra);
@@ -336,7 +350,8 @@ void BKE_sequencer_cache_cleanup(struct Scene *scene);
void BKE_sequencer_cache_cleanup_sequence(struct Scene *scene,
struct Sequence *seq,
struct Sequence *seq_changed,
- int invalidate_types);
+ int invalidate_types,
+ bool force_seq_changed_range);
void BKE_sequencer_cache_iterate(struct Scene *scene,
void *userdata,
bool callback_init(void *userdata, size_t item_count),
@@ -354,6 +369,7 @@ bool BKE_sequencer_cache_is_full(struct Scene *scene);
* ********************************************************************** */
void BKE_sequencer_prefetch_start(const SeqRenderData *context, float cfra, float cost);
+void BKE_sequencer_prefetch_stop_all(void);
void BKE_sequencer_prefetch_stop(struct Scene *scene);
void BKE_sequencer_prefetch_free(struct Scene *scene);
bool BKE_sequencer_prefetch_need_redraw(struct Main *bmain, struct Scene *scene);
@@ -373,6 +389,10 @@ struct Sequence *BKE_sequencer_prefetch_get_original_sequence(struct Sequence *s
/* intern */
struct SeqEffectHandle BKE_sequence_get_blend(struct Sequence *seq);
void BKE_sequence_effect_speed_rebuild_map(struct Scene *scene, struct Sequence *seq, bool force);
+float BKE_sequencer_speed_effect_target_frame_get(const SeqRenderData *context,
+ struct Sequence *seq,
+ float cfra,
+ int input);
/* extern */
struct SeqEffectHandle BKE_sequence_get_effect(struct Sequence *seq);
@@ -434,6 +454,10 @@ void BKE_sequence_invalidate_cache_composite(struct Scene *scene, struct Sequenc
void BKE_sequence_invalidate_dependent(struct Scene *scene, struct Sequence *seq);
void BKE_sequence_invalidate_scene_strips(struct Main *bmain, struct Scene *scene_target);
void BKE_sequence_invalidate_movieclip_strips(struct Main *bmain, struct MovieClip *clip_target);
+void BKE_sequence_invalidate_cache_in_range(struct Scene *scene,
+ struct Sequence *seq,
+ struct Sequence *range_mask,
+ int invalidate_types);
void BKE_sequencer_update_sound_bounds_all(struct Scene *scene);
void BKE_sequencer_update_sound_bounds(struct Scene *scene, struct Sequence *seq);
@@ -491,9 +515,10 @@ typedef struct SeqLoadInfo {
#define SEQ_DUPE_CONTEXT (1 << 1)
#define SEQ_DUPE_ANIM (1 << 2)
#define SEQ_DUPE_ALL (1 << 3) /* otherwise only selected are copied */
+#define SEQ_DUPE_IS_RECURSIVE_CALL (1 << 4)
/* use as an api function */
-typedef struct Sequence *(*SeqLoadFunc)(struct bContext *, ListBase *, struct SeqLoadInfo *);
+typedef struct Sequence *(*SeqLoadFn)(struct bContext *, ListBase *, struct SeqLoadInfo *);
struct Sequence *BKE_sequence_alloc(ListBase *lb, int cfra, int machine, int type);
@@ -501,6 +526,7 @@ void BKE_sequence_alpha_mode_from_extension(struct Sequence *seq);
void BKE_sequence_init_colorspace(struct Sequence *seq);
float BKE_sequence_get_fps(struct Scene *scene, struct Sequence *seq);
+float BKE_sequencer_give_stripelem_index(struct Sequence *seq, float cfra);
/* RNA enums, just to be more readable */
enum {
@@ -592,6 +618,7 @@ void BKE_sequencer_color_balance_apply(struct StripColorBalance *cb,
struct ImBuf *mask_input);
void BKE_sequencer_all_free_anim_ibufs(struct Scene *scene, int cfra);
+bool BKE_sequencer_check_scene_recursion(struct Scene *scene, struct ReportList *reports);
#ifdef __cplusplus
}
diff --git a/source/blender/blenkernel/BKE_sequencer_offscreen.h b/source/blender/blenkernel/BKE_sequencer_offscreen.h
index c753b4b566f..cc822e97270 100644
--- a/source/blender/blenkernel/BKE_sequencer_offscreen.h
+++ b/source/blender/blenkernel/BKE_sequencer_offscreen.h
@@ -47,7 +47,7 @@ typedef struct ImBuf *(*SequencerDrawView)(struct Depsgraph *depsgraph,
const char *viewname,
struct GPUOffScreen *ofs,
char err_out[256]);
-extern SequencerDrawView sequencer_view3d_cb;
+extern SequencerDrawView sequencer_view3d_fn;
#ifdef __cplusplus
}
diff --git a/source/blender/blenkernel/BKE_shader_fx.h b/source/blender/blenkernel/BKE_shader_fx.h
index d6d0f0f71de..bdc782a606e 100644
--- a/source/blender/blenkernel/BKE_shader_fx.h
+++ b/source/blender/blenkernel/BKE_shader_fx.h
@@ -35,9 +35,9 @@ struct Object;
struct ShaderFxData;
#define SHADER_FX_ACTIVE(_fx, _is_render) \
- (((_fx->mode & eShaderFxMode_Realtime) && (_is_render == false)) || \
- ((_fx->mode & eShaderFxMode_Render) && (_is_render == true)))
-#define SHADER_FX_EDIT(_fx, _is_edit) (((_fx->mode & eShaderFxMode_Editmode) == 0) && (_is_edit))
+ ((((_fx)->mode & eShaderFxMode_Realtime) && (_is_render == false)) || \
+ (((_fx)->mode & eShaderFxMode_Render) && (_is_render == true)))
+#define SHADER_FX_EDIT(_fx, _is_edit) ((((_fx)->mode & eShaderFxMode_Editmode) == 0) && (_is_edit))
typedef enum {
/* Should not be used, only for None type */
@@ -162,20 +162,20 @@ typedef struct ShaderFxTypeInfo {
/* Initialize global data (type info and some common global storages). */
void BKE_shaderfx_init(void);
-const ShaderFxTypeInfo *BKE_shaderfxType_getInfo(ShaderFxType type);
+const ShaderFxTypeInfo *BKE_shaderfx_get_info(ShaderFxType type);
struct ShaderFxData *BKE_shaderfx_new(int type);
void BKE_shaderfx_free_ex(struct ShaderFxData *fx, const int flag);
void BKE_shaderfx_free(struct ShaderFxData *fx);
bool BKE_shaderfx_unique_name(struct ListBase *shaderfx, struct ShaderFxData *fx);
-bool BKE_shaderfx_dependsOnTime(struct ShaderFxData *fx);
-struct ShaderFxData *BKE_shaderfx_findByType(struct Object *ob, ShaderFxType type);
-struct ShaderFxData *BKE_shaderfx_findByName(struct Object *ob, const char *name);
-void BKE_shaderfx_copyData_generic(const struct ShaderFxData *fx_src, struct ShaderFxData *fx_dst);
-void BKE_shaderfx_copyData(struct ShaderFxData *fx, struct ShaderFxData *target);
-void BKE_shaderfx_copyData_ex(struct ShaderFxData *fx,
+bool BKE_shaderfx_depends_ontime(struct ShaderFxData *fx);
+struct ShaderFxData *BKE_shaderfx_findby_type(struct Object *ob, ShaderFxType type);
+struct ShaderFxData *BKE_shaderfx_findby_name(struct Object *ob, const char *name);
+void BKE_shaderfx_copydata_generic(const struct ShaderFxData *fx_src, struct ShaderFxData *fx_dst);
+void BKE_shaderfx_copydata(struct ShaderFxData *fx, struct ShaderFxData *target);
+void BKE_shaderfx_copydata_ex(struct ShaderFxData *fx,
struct ShaderFxData *target,
const int flag);
-void BKE_shaderfx_foreachIDLink(struct Object *ob, ShaderFxIDWalkFunc walk, void *userData);
+void BKE_shaderfx_foreach_ID_link(struct Object *ob, ShaderFxIDWalkFunc walk, void *userData);
bool BKE_shaderfx_has_gpencil(struct Object *ob);
diff --git a/source/blender/blenkernel/BKE_simulation.h b/source/blender/blenkernel/BKE_simulation.h
new file mode 100644
index 00000000000..ff6aaa5e30e
--- /dev/null
+++ b/source/blender/blenkernel/BKE_simulation.h
@@ -0,0 +1,38 @@
+/*
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+
+#ifndef __BKE_SIMULATION_H__
+#define __BKE_SIMULATION_H__
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+struct Depsgraph;
+struct Main;
+struct Simulation;
+
+void *BKE_simulation_add(struct Main *bmain, const char *name);
+
+void BKE_simulation_data_update(struct Depsgraph *depsgraph,
+ struct Scene *scene,
+ struct Simulation *simulation);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* __BKE_SIMULATION_H__ */
diff --git a/source/blender/blenkernel/BKE_sound.h b/source/blender/blenkernel/BKE_sound.h
index af50e61eb2d..b93591b7b60 100644
--- a/source/blender/blenkernel/BKE_sound.h
+++ b/source/blender/blenkernel/BKE_sound.h
@@ -117,8 +117,8 @@ void BKE_sound_ensure_scene(struct Scene *scene);
void BKE_sound_destroy_scene(struct Scene *scene);
-void BKE_sound_lock_scene(struct Scene *scene);
-void BKE_sound_unlock_scene(struct Scene *scene);
+void BKE_sound_lock(void);
+void BKE_sound_unlock(void);
void BKE_sound_reset_scene_specs(struct Scene *scene);
@@ -164,7 +164,7 @@ void BKE_sound_stop_scene(struct Scene *scene);
void BKE_sound_seek_scene(struct Main *bmain, struct Scene *scene);
-float BKE_sound_sync_scene(struct Scene *scene);
+double BKE_sound_sync_scene(struct Scene *scene);
int BKE_sound_scene_playing(struct Scene *scene);
@@ -180,10 +180,10 @@ float BKE_sound_get_length(struct Main *bmain, struct bSound *sound);
char **BKE_sound_get_device_names(void);
-typedef void (*SoundJackSyncCallback)(struct Main *bmain, int mode, float time);
+typedef void (*SoundJackSyncCallback)(struct Main *bmain, int mode, double time);
void BKE_sound_jack_sync_callback_set(SoundJackSyncCallback callback);
-void BKE_sound_jack_scene_update(struct Scene *scene, int mode, float time);
+void BKE_sound_jack_scene_update(struct Scene *scene, int mode, double time);
/* Dependency graph evaluation. */
diff --git a/source/blender/blenkernel/BKE_subdiv.h b/source/blender/blenkernel/BKE_subdiv.h
index 3b342402ecb..1323938e479 100644
--- a/source/blender/blenkernel/BKE_subdiv.h
+++ b/source/blender/blenkernel/BKE_subdiv.h
@@ -66,7 +66,7 @@ typedef struct SubdivSettings {
/* This refers to an adaptive isolation when creating patches for the subdivided surface.
*
- * When is set to to false (aka uniform subdivision) fixed depth of isolation is used, which
+ * When is set to false (aka uniform subdivision) fixed depth of isolation is used, which
* allows to iteratively add more subdivisions (uniform subdivision level 2 = uniform subdivision
* level 1 + uniform subdivision level 1). Uniform subdivisions will progressively go to a limit
* surface.
@@ -194,6 +194,12 @@ typedef struct Subdiv {
} cache_;
} Subdiv;
+/* =================----====--===== MODULE ==========================------== */
+
+/* (De)initialize the entire subdivision surface module. */
+void BKE_subdiv_init(void);
+void BKE_subdiv_exit(void);
+
/* ========================== CONVERSION HELPERS ============================ */
/* NOTE: uv_smooth is eSubsurfUVSmooth. */
diff --git a/source/blender/blenkernel/BKE_subdiv_ccg.h b/source/blender/blenkernel/BKE_subdiv_ccg.h
index 7d612f293ab..8d2565c31f7 100644
--- a/source/blender/blenkernel/BKE_subdiv_ccg.h
+++ b/source/blender/blenkernel/BKE_subdiv_ccg.h
@@ -40,7 +40,7 @@ struct DMFlagMat;
struct Mesh;
struct Subdiv;
-/* =============================================================================
+/* --------------------------------------------------------------------
* Masks.
*/
@@ -61,7 +61,7 @@ typedef struct SubdivCCGMaskEvaluator {
bool BKE_subdiv_ccg_mask_init_from_paint(SubdivCCGMaskEvaluator *mask_evaluator,
const struct Mesh *mesh);
-/* =============================================================================
+/* --------------------------------------------------------------------
* Materials.
*/
@@ -80,7 +80,7 @@ typedef struct SubdivCCGMaterialFlagsEvaluator {
void BKE_subdiv_ccg_material_flags_init_from_mesh(
SubdivCCGMaterialFlagsEvaluator *material_flags_evaluator, const struct Mesh *mesh);
-/* =============================================================================
+/* --------------------------------------------------------------------
* SubdivCCG.
*/
@@ -216,7 +216,10 @@ typedef struct SubdivCCG {
} dirty;
} SubdivCCG;
-/* Create real hi-res CCG from subdivision.
+/* Create CCG representation of subdivision surface.
+ *
+ * NOTE: CCG stores dense vertices in a grid-like storage. There is no edges or
+ * polygons information's for the high-poly surface.
*
* NOTE: Subdiv is expected to be refined and ready for evaluation.
* NOTE: CCG becomes an owner of subdiv.
@@ -302,6 +305,8 @@ void BKE_subdiv_ccg_neighbor_coords_get(const SubdivCCG *subdiv_ccg,
const bool include_duplicates,
SubdivCCGNeighbors *r_neighbors);
+int BKE_subdiv_ccg_grid_to_face_index(const SubdivCCG *subdiv_ccg, const int grid_index);
+
#ifdef __cplusplus
}
#endif
diff --git a/source/blender/blenkernel/BKE_subdiv_deform.h b/source/blender/blenkernel/BKE_subdiv_deform.h
index 72d2b252cf7..735cd20a6c8 100644
--- a/source/blender/blenkernel/BKE_subdiv_deform.h
+++ b/source/blender/blenkernel/BKE_subdiv_deform.h
@@ -34,6 +34,10 @@ struct Mesh;
struct Subdiv;
/* Special version of subdivision surface which calculates final positions for coarse vertices.
+ * Effectively is pushing the coarse positions to the limit surface.
+ *
+ * One of the usage examples is calculation of crazy space of subdivision modifier, allowing to
+ * paint on a deformed mesh with sub-surf on it.
*
* vertex_cos are supposed to hold coordinates of the coarse mesh. */
void BKE_subdiv_deform_coarse_vertices(struct Subdiv *subdiv,
diff --git a/source/blender/blenkernel/BKE_subdiv_eval.h b/source/blender/blenkernel/BKE_subdiv_eval.h
index 095d3c17d63..aa27df88be8 100644
--- a/source/blender/blenkernel/BKE_subdiv_eval.h
+++ b/source/blender/blenkernel/BKE_subdiv_eval.h
@@ -38,7 +38,10 @@ bool BKE_subdiv_eval_begin(struct Subdiv *subdiv);
/* coarse_vertex_cos is an optional argument which allows to override coordinates of the coarse
* mesh. */
-bool BKE_subdiv_eval_update_from_mesh(struct Subdiv *subdiv,
+bool BKE_subdiv_eval_begin_from_mesh(struct Subdiv *subdiv,
+ const struct Mesh *mesh,
+ const float (*coarse_vertex_cos)[3]);
+bool BKE_subdiv_eval_refine_from_mesh(struct Subdiv *subdiv,
const struct Mesh *mesh,
const float (*coarse_vertex_cos)[3]);
@@ -50,6 +53,8 @@ void BKE_subdiv_eval_init_displacement(struct Subdiv *subdiv);
/* Single point queries. */
+/* Evaluate point at a limit surface, with optional derivatives and normal. */
+
void BKE_subdiv_eval_limit_point(
struct Subdiv *subdiv, const int ptex_face_index, const float u, const float v, float r_P[3]);
void BKE_subdiv_eval_limit_point_and_derivatives(struct Subdiv *subdiv,
@@ -72,6 +77,7 @@ void BKE_subdiv_eval_limit_point_and_short_normal(struct Subdiv *subdiv,
float r_P[3],
short r_N[3]);
+/* Evaluate face-varying layer (such as UV). */
void BKE_subdiv_eval_face_varying(struct Subdiv *subdiv,
const int face_varying_channel,
const int ptex_face_index,
@@ -93,6 +99,7 @@ void BKE_subdiv_eval_displacement(struct Subdiv *subdiv,
const float dPdv[3],
float r_D[3]);
+/* Evaluate point on a limit surface with displacement applied to it. */
void BKE_subdiv_eval_final_point(
struct Subdiv *subdiv, const int ptex_face_index, const float u, const float v, float r_P[3]);
diff --git a/source/blender/blenkernel/BKE_subdiv_foreach.h b/source/blender/blenkernel/BKE_subdiv_foreach.h
index f1d4adda37c..bef141b5ac5 100644
--- a/source/blender/blenkernel/BKE_subdiv_foreach.h
+++ b/source/blender/blenkernel/BKE_subdiv_foreach.h
@@ -160,6 +160,10 @@ typedef struct SubdivForeachContext {
/* Invokes callbacks in the order and with values which corresponds to creation
* of final subdivided mesh.
*
+ * Main goal is to abstract all the traversal routines to give geometry element
+ * indices (for vertices, edges, loops, polygons) in the same way as subdivision
+ * modifier will do for a dense mesh.
+ *
* Returns truth if the whole topology was traversed, without any early exits.
*
* TODO(sergey): Need to either get rid of subdiv or of coarse_mesh.
diff --git a/source/blender/blenkernel/BKE_subsurf.h b/source/blender/blenkernel/BKE_subsurf.h
index 16013034823..2dee8de4dc7 100644
--- a/source/blender/blenkernel/BKE_subsurf.h
+++ b/source/blender/blenkernel/BKE_subsurf.h
@@ -103,7 +103,7 @@ typedef struct CCGDerivedMesh {
struct CCGSubSurf *ss;
int freeSS;
- int drawInteriorEdges, useSubsurfUv, useGpuBackend;
+ int drawInteriorEdges, useSubsurfUv;
struct {
int startVert;
@@ -156,13 +156,6 @@ typedef struct CCGDerivedMesh {
ThreadRWMutex origindex_cache_rwlock;
} CCGDerivedMesh;
-#ifdef WITH_OPENSUBDIV
-/* TODO(sergey): Not really ideal place, but we don't currently have better one. */
-void BKE_subsurf_osd_init(void);
-void BKE_subsurf_free_unused_buffers(void);
-void BKE_subsurf_osd_cleanup(void);
-#endif
-
#ifdef __cplusplus
}
#endif
diff --git a/source/blender/blenkernel/BKE_text_suggestions.h b/source/blender/blenkernel/BKE_text_suggestions.h
index dc908ee5232..d618fcd6d11 100644
--- a/source/blender/blenkernel/BKE_text_suggestions.h
+++ b/source/blender/blenkernel/BKE_text_suggestions.h
@@ -23,12 +23,12 @@
* \ingroup bke
*/
+#include "DNA_text_types.h"
+
#ifdef __cplusplus
extern "C" {
#endif
-#include "DNA_text_types.h"
-
/* ****************************************************************************
* Suggestions should be added in sorted order although a linear sorting method is
* implemented. The list is then divided up based on the prefix provided by
diff --git a/source/blender/blenkernel/BKE_texture.h b/source/blender/blenkernel/BKE_texture.h
index 0f852bdc64d..43ef2b1ba7f 100644
--- a/source/blender/blenkernel/BKE_texture.h
+++ b/source/blender/blenkernel/BKE_texture.h
@@ -31,6 +31,7 @@ struct Brush;
struct ColorBand;
struct FreestyleLineStyle;
struct ImagePool;
+struct LibraryForeachIDData;
struct MTex;
struct Main;
struct ParticleSettings;
@@ -39,9 +40,11 @@ struct Tex;
struct TexMapping;
struct TexResult;
-/* in ColorBand struct */
+/** #ColorBand.data length. */
#define MAXCOLORBAND 32
+void BKE_texture_mtex_foreach_id(struct LibraryForeachIDData *data, struct MTex *mtex);
+
void BKE_texture_default(struct Tex *tex);
struct Tex *BKE_texture_copy(struct Main *bmain, const struct Tex *tex);
struct Tex *BKE_texture_add(struct Main *bmain, const char *name);
diff --git a/source/blender/blenkernel/BKE_tracking.h b/source/blender/blenkernel/BKE_tracking.h
index 00498e30abc..bb88fbf863b 100644
--- a/source/blender/blenkernel/BKE_tracking.h
+++ b/source/blender/blenkernel/BKE_tracking.h
@@ -261,8 +261,16 @@ void BKE_tracking_distortion_undistort_v2(struct MovieDistortion *distortion,
float r_co[2]);
void BKE_tracking_distortion_free(struct MovieDistortion *distortion);
-void BKE_tracking_distort_v2(struct MovieTracking *tracking, const float co[2], float r_co[2]);
-void BKE_tracking_undistort_v2(struct MovieTracking *tracking, const float co[2], float r_co[2]);
+void BKE_tracking_distort_v2(struct MovieTracking *tracking,
+ int image_width,
+ int image_height,
+ const float co[2],
+ float r_co[2]);
+void BKE_tracking_undistort_v2(struct MovieTracking *tracking,
+ int image_width,
+ int image_height,
+ const float co[2],
+ float r_co[2]);
struct ImBuf *BKE_tracking_undistort_frame(struct MovieTracking *tracking,
struct ImBuf *ibuf,
@@ -276,6 +284,8 @@ struct ImBuf *BKE_tracking_distort_frame(struct MovieTracking *tracking,
float overscan);
void BKE_tracking_max_distortion_delta_across_bound(struct MovieTracking *tracking,
+ int image_width,
+ int image_height,
struct rcti *rect,
bool undistort,
float delta[2]);
@@ -462,7 +472,7 @@ void BKE_tracking_get_rna_path_prefix_for_plane_track(
#define MARKER_VISIBLE(sc, track, marker) \
(((marker)->flag & MARKER_DISABLED) == 0 || ((sc)->flag & SC_HIDE_DISABLED) == 0 || \
- (sc->clip->tracking.act_track == track))
+ ((sc)->clip->tracking.act_track == track))
#define TRACK_CLEAR_UPTO 0
#define TRACK_CLEAR_REMAINED 1
diff --git a/source/blender/blenkernel/BKE_undo_system.h b/source/blender/blenkernel/BKE_undo_system.h
index 4870b19fe1d..f462a7fab71 100644
--- a/source/blender/blenkernel/BKE_undo_system.h
+++ b/source/blender/blenkernel/BKE_undo_system.h
@@ -152,6 +152,8 @@ void BKE_undosys_stack_init_from_context(UndoStack *ustack, struct bContext *C);
UndoStep *BKE_undosys_stack_active_with_type(UndoStack *ustack, const UndoType *ut);
UndoStep *BKE_undosys_stack_init_or_active_with_type(UndoStack *ustack, const UndoType *ut);
void BKE_undosys_stack_limit_steps_and_memory(UndoStack *ustack, int steps, size_t memory_limit);
+#define BKE_undosys_stack_limit_steps_and_memory_defaults(ustack) \
+ BKE_undosys_stack_limit_steps_and_memory(ustack, U.undosteps, (size_t)U.undomemory * 1024 * 1024)
/* Only some UndoType's require init. */
UndoStep *BKE_undosys_step_push_init_with_type(UndoStack *ustack,
diff --git a/source/blender/blenkernel/BKE_volume.h b/source/blender/blenkernel/BKE_volume.h
index 3125ad0326e..224f3ede45d 100644
--- a/source/blender/blenkernel/BKE_volume.h
+++ b/source/blender/blenkernel/BKE_volume.h
@@ -85,6 +85,7 @@ bool BKE_volume_is_loaded(const struct Volume *volume);
int BKE_volume_num_grids(const struct Volume *volume);
const char *BKE_volume_grids_error_msg(const struct Volume *volume);
+const char *BKE_volume_grids_frame_filepath(const struct Volume *volume);
VolumeGrid *BKE_volume_grid_get(const struct Volume *volume, int grid_index);
VolumeGrid *BKE_volume_grid_active_get(const struct Volume *volume);
VolumeGrid *BKE_volume_grid_find(const struct Volume *volume, const char *name);
diff --git a/source/blender/blenkernel/BKE_workspace.h b/source/blender/blenkernel/BKE_workspace.h
index 8582996108a..8a6afd8a753 100644
--- a/source/blender/blenkernel/BKE_workspace.h
+++ b/source/blender/blenkernel/BKE_workspace.h
@@ -84,6 +84,7 @@ void BKE_workspace_active_set(struct WorkSpaceInstanceHook *hook,
struct WorkSpaceLayout *BKE_workspace_active_layout_get(const struct WorkSpaceInstanceHook *hook)
GETTER_ATTRS;
void BKE_workspace_active_layout_set(struct WorkSpaceInstanceHook *hook,
+ struct WorkSpace *workspace,
struct WorkSpaceLayout *layout) SETTER_ATTRS;
struct bScreen *BKE_workspace_active_screen_get(const struct WorkSpaceInstanceHook *hook)
GETTER_ATTRS;
@@ -91,21 +92,14 @@ void BKE_workspace_active_screen_set(struct WorkSpaceInstanceHook *hook,
struct WorkSpace *workspace,
struct bScreen *screen) 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;
void BKE_workspace_layout_name_set(struct WorkSpace *workspace,
struct WorkSpaceLayout *layout,
const char *new_name) ATTR_NONNULL();
struct bScreen *BKE_workspace_layout_screen_get(const struct WorkSpaceLayout *layout) GETTER_ATTRS;
-void BKE_workspace_layout_screen_set(struct WorkSpaceLayout *layout,
- struct bScreen *screen) SETTER_ATTRS;
-struct WorkSpaceLayout *BKE_workspace_hook_layout_for_workspace_get(
+struct WorkSpaceLayout *BKE_workspace_active_layout_for_workspace_get(
const struct WorkSpaceInstanceHook *hook, const struct WorkSpace *workspace) GETTER_ATTRS;
-void BKE_workspace_hook_layout_for_workspace_set(struct WorkSpaceInstanceHook *hook,
- struct WorkSpace *workspace,
- struct WorkSpaceLayout *layout) ATTR_NONNULL();
bool BKE_workspace_owner_id_check(const struct WorkSpace *workspace, const char *owner_id)
ATTR_NONNULL();
diff --git a/source/blender/blenkernel/CMakeLists.txt b/source/blender/blenkernel/CMakeLists.txt
index 1e230e5af3a..817fe849eab 100644
--- a/source/blender/blenkernel/CMakeLists.txt
+++ b/source/blender/blenkernel/CMakeLists.txt
@@ -64,14 +64,14 @@ set(SRC
${CMAKE_SOURCE_DIR}/release/datafiles/userdef/userdef_default.c
intern/CCGSubSurf.c
intern/CCGSubSurf_legacy.c
- intern/CCGSubSurf_opensubdiv.c
- intern/CCGSubSurf_opensubdiv_converter.c
intern/CCGSubSurf_util.c
intern/DerivedMesh.c
intern/action.c
intern/addon.c
- intern/anim.c
+ intern/anim_data.c
+ intern/anim_path.c
intern/anim_sys.c
+ intern/anim_visualization.c
intern/appdir.c
intern/armature.c
intern/armature_update.c
@@ -114,11 +114,13 @@ set(SRC
intern/editmesh_tangent.c
intern/effect.c
intern/fcurve.c
+ intern/fcurve_driver.c
intern/fluid.c
intern/fmodifier.c
intern/font.c
intern/freestyle.c
intern/gpencil.c
+ intern/gpencil_curve.c
intern/gpencil_geom.c
intern/gpencil_modifier.c
intern/hair.c
@@ -166,6 +168,7 @@ set(SRC
intern/mesh_runtime.c
intern/mesh_tangent.c
intern/mesh_validate.c
+ intern/mesh_wrapper.c
intern/modifier.c
intern/movieclip.c
intern/multires.c
@@ -173,9 +176,11 @@ set(SRC
intern/multires_reshape_apply_base.c
intern/multires_reshape_ccg.c
intern/multires_reshape_smooth.c
+ intern/multires_reshape_subdivide.c
intern/multires_reshape_util.c
intern/multires_reshape_vertcos.c
intern/multires_subdiv.c
+ intern/multires_unsubdivide.c
intern/nla.c
intern/node.c
intern/object.c
@@ -195,7 +200,6 @@ set(SRC
intern/particle_system.c
intern/pbvh.c
intern/pbvh_bmesh.c
- intern/pbvh_parallel.cc
intern/pointcache.c
intern/pointcloud.c
intern/report.c
@@ -209,6 +213,7 @@ set(SRC
intern/sequencer.c
intern/shader_fx.c
intern/shrinkwrap.c
+ intern/simulation.cc
intern/softbody.c
intern/sound.c
intern/speaker.c
@@ -250,7 +255,9 @@ set(SRC
BKE_DerivedMesh.h
BKE_action.h
BKE_addon.h
- BKE_anim.h
+ BKE_anim_data.h
+ BKE_anim_path.h
+ BKE_anim_visualization.h
BKE_animsys.h
BKE_appdir.h
BKE_armature.h
@@ -286,6 +293,7 @@ set(SRC
BKE_deform.h
BKE_displist.h
BKE_displist_tangent.h
+ BKE_duplilist.h
BKE_dynamicpaint.h
BKE_editlattice.h
BKE_editmesh.h
@@ -294,11 +302,13 @@ set(SRC
BKE_editmesh_tangent.h
BKE_effect.h
BKE_fcurve.h
+ BKE_fcurve_driver.h
BKE_fluid.h
BKE_font.h
BKE_freestyle.h
BKE_global.h
BKE_gpencil.h
+ BKE_gpencil_curve.h
BKE_gpencil_geom.h
BKE_gpencil_modifier.h
BKE_hair.h
@@ -357,6 +367,7 @@ set(SRC
BKE_sequencer.h
BKE_shader_fx.h
BKE_shrinkwrap.h
+ BKE_simulation.h
BKE_softbody.h
BKE_sound.h
BKE_speaker.h
@@ -391,6 +402,7 @@ set(SRC
intern/lib_intern.h
intern/multires_inline.h
intern/multires_reshape.h
+ intern/multires_unsubdivide.h
intern/pbvh_intern.h
intern/subdiv_converter.h
intern/subdiv_inline.h
@@ -661,17 +673,6 @@ if(WITH_QUADRIFLOW)
add_definitions(-DWITH_QUADRIFLOW)
endif()
-if(WITH_TBB)
- add_definitions(-DWITH_TBB)
-
- list(APPEND INC_SYS
- ${TBB_INCLUDE_DIRS}
- )
- list(APPEND LIB
- ${TBB_LIBRARIES}
- )
-endif()
-
if(WITH_XR_OPENXR)
add_definitions(-DWITH_XR_OPENXR)
endif()
diff --git a/source/blender/blenkernel/intern/CCGSubSurf.c b/source/blender/blenkernel/intern/CCGSubSurf.c
index d76a4d8f859..98deddb4316 100644
--- a/source/blender/blenkernel/intern/CCGSubSurf.c
+++ b/source/blender/blenkernel/intern/CCGSubSurf.c
@@ -32,13 +32,6 @@
#include "CCGSubSurf.h"
#include "CCGSubSurf_intern.h"
-#ifdef WITH_OPENSUBDIV
-# include "opensubdiv_capi.h"
-# include "opensubdiv_converter_capi.h"
-# include "opensubdiv_evaluator_capi.h"
-# include "opensubdiv_topology_refiner_capi.h"
-#endif
-
#include "GPU_glew.h"
/***/
@@ -305,21 +298,6 @@ CCGSubSurf *ccgSubSurf_new(CCGMeshIFC *ifc,
ss->tempVerts = NULL;
ss->tempEdges = NULL;
-#ifdef WITH_OPENSUBDIV
- ss->osd_evaluator = NULL;
- ss->osd_mesh = NULL;
- ss->osd_topology_refiner = NULL;
- ss->osd_mesh_invalid = false;
- ss->osd_coarse_coords_invalid = false;
- ss->osd_vao = 0;
- ss->skip_grids = false;
- ss->osd_compute = 0;
- ss->osd_next_face_ptex_index = 0;
- ss->osd_coarse_coords = NULL;
- ss->osd_num_coarse_coords = 0;
- ss->osd_subdiv_uvs = false;
-#endif
-
return ss;
}
}
@@ -328,23 +306,6 @@ void ccgSubSurf_free(CCGSubSurf *ss)
{
CCGAllocatorIFC allocatorIFC = ss->allocatorIFC;
CCGAllocatorHDL allocator = ss->allocator;
-#ifdef WITH_OPENSUBDIV
- if (ss->osd_evaluator != NULL) {
- openSubdiv_deleteEvaluator(ss->osd_evaluator);
- }
- if (ss->osd_mesh != NULL) {
- ccgSubSurf__delete_osdGLMesh(ss->osd_mesh);
- }
- if (ss->osd_vao != 0) {
- ccgSubSurf__delete_vertex_array(ss->osd_vao);
- }
- if (ss->osd_coarse_coords != NULL) {
- MEM_freeN(ss->osd_coarse_coords);
- }
- if (ss->osd_topology_refiner != NULL) {
- openSubdiv_deleteTopologyRefiner(ss->osd_topology_refiner);
- }
-#endif
if (ss->syncState) {
ccg_ehash_free(ss->oldFMap, (EHEntryFreeFP)_face_free, ss);
@@ -529,9 +490,6 @@ CCGError ccgSubSurf_initFullSync(CCGSubSurf *ss)
ss->tempEdges = MEM_mallocN(sizeof(*ss->tempEdges) * ss->lenTempArrays, "CCGSubsurf tempEdges");
ss->syncState = eSyncState_Vert;
-#ifdef WITH_OPENSUBDIV
- ss->osd_next_face_ptex_index = 0;
-#endif
return eCCGError_None;
}
@@ -671,9 +629,6 @@ CCGError ccgSubSurf_syncVert(
ccg_ehash_insert(ss->vMap, (EHEntry *)v);
v->flags = 0;
}
-#ifdef WITH_OPENSUBDIV
- v->osd_index = ss->vMap->numEntries - 1;
-#endif
}
if (v_r) {
@@ -874,15 +829,6 @@ CCGError ccgSubSurf_syncFace(
}
}
}
-#ifdef WITH_OPENSUBDIV
- f->osd_index = ss->osd_next_face_ptex_index;
- if (numVerts == 4) {
- ss->osd_next_face_ptex_index++;
- }
- else {
- ss->osd_next_face_ptex_index += numVerts;
- }
-#endif
}
if (f_r) {
@@ -893,15 +839,7 @@ CCGError ccgSubSurf_syncFace(
static void ccgSubSurf__sync(CCGSubSurf *ss)
{
-#ifdef WITH_OPENSUBDIV
- if (ss->skip_grids) {
- ccgSubSurf__sync_opensubdiv(ss);
- }
- else
-#endif
- {
- ccgSubSurf__sync_legacy(ss);
- }
+ ccgSubSurf__sync_legacy(ss);
}
CCGError ccgSubSurf_processSync(CCGSubSurf *ss)
@@ -1615,12 +1553,6 @@ int ccgSubSurf_getNumFinalVerts(const CCGSubSurf *ss)
ss->fMap->numEntries +
ss->numGrids * ((gridSize - 2) + ((gridSize - 2) * (gridSize - 2))));
-#ifdef WITH_OPENSUBDIV
- if (ss->skip_grids) {
- return 0;
- }
-#endif
-
return numFinalVerts;
}
int ccgSubSurf_getNumFinalEdges(const CCGSubSurf *ss)
@@ -1629,22 +1561,12 @@ int ccgSubSurf_getNumFinalEdges(const CCGSubSurf *ss)
int gridSize = ccg_gridsize(ss->subdivLevels);
int numFinalEdges = (ss->eMap->numEntries * (edgeSize - 1) +
ss->numGrids * ((gridSize - 1) + 2 * ((gridSize - 2) * (gridSize - 1))));
-#ifdef WITH_OPENSUBDIV
- if (ss->skip_grids) {
- return 0;
- }
-#endif
return numFinalEdges;
}
int ccgSubSurf_getNumFinalFaces(const CCGSubSurf *ss)
{
int gridSize = ccg_gridsize(ss->subdivLevels);
int numFinalFaces = ss->numGrids * ((gridSize - 1) * (gridSize - 1));
-#ifdef WITH_OPENSUBDIV
- if (ss->skip_grids) {
- return 0;
- }
-#endif
return numFinalFaces;
}
diff --git a/source/blender/blenkernel/intern/CCGSubSurf.h b/source/blender/blenkernel/intern/CCGSubSurf.h
index 83b59941ac7..2e5100db6de 100644
--- a/source/blender/blenkernel/intern/CCGSubSurf.h
+++ b/source/blender/blenkernel/intern/CCGSubSurf.h
@@ -211,57 +211,4 @@ CCGFace *ccgFaceIterator_getCurrent(CCGFaceIterator *fi);
int ccgFaceIterator_isStopped(CCGFaceIterator *fi);
void ccgFaceIterator_next(CCGFaceIterator *fi);
-#ifdef WITH_OPENSUBDIV
-struct DerivedMesh;
-
-/* Check if topology changed and evaluators are to be re-created. */
-void ccgSubSurf_checkTopologyChanged(CCGSubSurf *ss, struct DerivedMesh *dm);
-
-/* Create topology refiner from give derived mesh which then later will be
- * used for GL mesh creation.
- */
-void ccgSubSurf_prepareTopologyRefiner(CCGSubSurf *ss, struct DerivedMesh *dm);
-
-/* Make sure GL mesh exists, up to date and ready to draw. */
-bool ccgSubSurf_prepareGLMesh(CCGSubSurf *ss, bool use_osd_glsl, int active_uv_index);
-
-/* Draw given partitions of the GL mesh.
- *
- * TODO(sergey): fill_quads is actually an invariant and should be part
- * of the prepare routine.
- */
-void ccgSubSurf_drawGLMesh(CCGSubSurf *ss,
- bool fill_quads,
- int start_partition,
- int num_partitions);
-
-/* Get number of base faces in a particular GL mesh. */
-int ccgSubSurf_getNumGLMeshBaseFaces(CCGSubSurf *ss);
-
-/* Get number of vertices in base faces in a particular GL mesh. */
-int ccgSubSurf_getNumGLMeshBaseFaceVerts(CCGSubSurf *ss, int face);
-
-/* Controls whether CCG are needed (Cmeaning CPU evaluation) or fully GPU compute
- * and draw is allowed.
- */
-void ccgSubSurf_setSkipGrids(CCGSubSurf *ss, bool skip_grids);
-bool ccgSubSurf_needGrids(CCGSubSurf *ss);
-
-/* Set evaluator's face varying data from UV coordinates.
- * Used for CPU evaluation.
- */
-void ccgSubSurf_evaluatorSetFVarUV(CCGSubSurf *ss, struct DerivedMesh *dm, int layer_index);
-
-/* TODO(sergey): Temporary call to test things. */
-void ccgSubSurf_evaluatorFVarUV(
- CCGSubSurf *ss, int face_index, int S, float grid_u, float grid_v, float uv[2]);
-
-void ccgSubSurf_free_osd_mesh(CCGSubSurf *ss);
-
-void ccgSubSurf_getMinMax(CCGSubSurf *ss, float r_min[3], float r_max[3]);
-
-void ccgSubSurf__sync_subdivUvs(CCGSubSurf *ss, bool subsurf_uvs);
-
-#endif
-
#endif /* __CCGSUBSURF_H__ */
diff --git a/source/blender/blenkernel/intern/CCGSubSurf_intern.h b/source/blender/blenkernel/intern/CCGSubSurf_intern.h
index 51486db1bdc..7c35d2ccfce 100644
--- a/source/blender/blenkernel/intern/CCGSubSurf_intern.h
+++ b/source/blender/blenkernel/intern/CCGSubSurf_intern.h
@@ -157,9 +157,6 @@ typedef enum {
eSyncState_Edge,
eSyncState_Face,
eSyncState_Partial,
-#ifdef WITH_OPENSUBDIV
- eSyncState_OpenSubdiv,
-#endif
} SyncState;
struct CCGSubSurf {
@@ -202,58 +199,6 @@ struct CCGSubSurf {
int lenTempArrays;
CCGVert **tempVerts;
CCGEdge **tempEdges;
-
-#ifdef WITH_OPENSUBDIV
- /* Skip grids means no CCG geometry is created and subsurf is possible
- * to be completely done on GPU.
- */
- bool skip_grids;
-
- /* ** GPU backend. ** */
-
- /* Compute device used by GL mesh. */
- short osd_compute;
- /* Coarse (base mesh) vertex coordinates.
- *
- * Filled in from the modifier stack and passed to OpenSubdiv compute
- * on mesh display.
- */
- float (*osd_coarse_coords)[3];
- int osd_num_coarse_coords;
- /* Denotes whether coarse positions in the GL mesh are invalid.
- * Used to avoid updating GL mesh coords on every redraw.
- */
- bool osd_coarse_coords_invalid;
-
- /* GL mesh descriptor, used for refinement and draw. */
- struct OpenSubdiv_GLMesh *osd_mesh;
- /* Refiner which is used to create GL mesh.
- *
- * Refiner is created from the modifier stack and used later from the main
- * thread to construct GL mesh to avoid threaded access to GL.
- */
- struct OpenSubdiv_TopologyRefiner
- *osd_topology_refiner; /* Only used at synchronization stage. */
- /* Denotes whether osd_mesh is invalid now due to topology changes and needs
- * to be reconstructed.
- *
- * Reconstruction happens from main thread due to OpenGL communication.
- */
- bool osd_mesh_invalid;
- /* Vertex array used for osd_mesh draw. */
- unsigned int osd_vao;
-
- /* ** CPU backend. ** */
-
- /* Limit evaluator, used to evaluate CCG. */
- struct OpenSubdiv_Evaluator *osd_evaluator;
- /* Next PTex face index, used while CCG synchronization
- * to fill in PTex index of CCGFace.
- */
- int osd_next_face_ptex_index;
-
- bool osd_subdiv_uvs;
-#endif
};
/* ** Utility macros ** */
@@ -322,16 +267,6 @@ void ccgSubSurf__sync_legacy(CCGSubSurf *ss);
void ccgSubSurf__sync_opensubdiv(CCGSubSurf *ss);
-/* Delayed free routines. Will do actual free if called from
- * main thread and schedule free for later free otherwise.
- */
-
-#ifdef WITH_OPENSUBDIV
-void ccgSubSurf__delete_osdGLMesh(struct OpenSubdiv_GLMesh *osd_mesh);
-void ccgSubSurf__delete_vertex_array(unsigned int vao);
-void ccgSubSurf__delete_pending(void);
-#endif
-
/* * CCGSubSurf_opensubdiv_converter.c * */
struct OpenSubdiv_Converter;
diff --git a/source/blender/blenkernel/intern/CCGSubSurf_opensubdiv.c b/source/blender/blenkernel/intern/CCGSubSurf_opensubdiv.c
deleted file mode 100644
index 3257dd2334c..00000000000
--- a/source/blender/blenkernel/intern/CCGSubSurf_opensubdiv.c
+++ /dev/null
@@ -1,970 +0,0 @@
-/*
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License
- * as published by the Free Software Foundation; either version 2
- * of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-
-/** \file
- * \ingroup bke
- */
-
-#ifdef WITH_OPENSUBDIV
-
-# include "BLI_sys_types.h" // for intptr_t support
-# include "MEM_guardedalloc.h"
-
-# include "BLI_listbase.h"
-# include "BLI_math.h"
-# include "BLI_threads.h"
-# include "BLI_utildefines.h" /* for BLI_assert */
-
-# include "CCGSubSurf.h"
-# include "CCGSubSurf_intern.h"
-
-# include "BKE_DerivedMesh.h"
-# include "BKE_subsurf.h"
-
-# include "DNA_userdef_types.h"
-
-# include "opensubdiv_capi.h"
-# include "opensubdiv_converter_capi.h"
-# include "opensubdiv_evaluator_capi.h"
-# include "opensubdiv_gl_mesh_capi.h"
-# include "opensubdiv_topology_refiner_capi.h"
-
-# include "GPU_extensions.h"
-# include "GPU_glew.h"
-
-# define OSD_LOG \
- if (false) \
- printf
-
-static bool compare_ccg_derivedmesh_topology(CCGSubSurf *ss, DerivedMesh *dm)
-{
- const int num_verts = dm->getNumVerts(dm);
- const int num_edges = dm->getNumEdges(dm);
- const int num_polys = dm->getNumPolys(dm);
- const MEdge *medge = dm->getEdgeArray(dm);
- const MLoop *mloop = dm->getLoopArray(dm);
- const MPoly *mpoly = dm->getPolyArray(dm);
-
- /* Quick preliminary tests based on the number of verts and facces. */
- {
- if (num_verts != ss->vMap->numEntries || num_edges != ss->eMap->numEntries ||
- num_polys != ss->fMap->numEntries) {
- return false;
- }
- }
-
- /* Rather slow check for faces topology change. */
- {
- CCGFaceIterator ccg_face_iter;
- for (ccgSubSurf_initFaceIterator(ss, &ccg_face_iter);
- !ccgFaceIterator_isStopped(&ccg_face_iter);
- ccgFaceIterator_next(&ccg_face_iter)) {
- /*const*/ CCGFace *ccg_face = ccgFaceIterator_getCurrent(&ccg_face_iter);
- const int poly_index = POINTER_AS_INT(ccgSubSurf_getFaceFaceHandle(ccg_face));
- const MPoly *mp = &mpoly[poly_index];
- int corner;
- if (ccg_face->numVerts != mp->totloop) {
- return false;
- }
- for (corner = 0; corner < ccg_face->numVerts; corner++) {
- /*const*/ CCGVert *ccg_vert = FACE_getVerts(ccg_face)[corner];
- const int vert_index = POINTER_AS_INT(ccgSubSurf_getVertVertHandle(ccg_vert));
- if (vert_index != mloop[mp->loopstart + corner].v) {
- return false;
- }
- }
- }
- }
-
- /* Check for edge topology change. */
- {
- CCGEdgeIterator ccg_edge_iter;
- for (ccgSubSurf_initEdgeIterator(ss, &ccg_edge_iter);
- !ccgEdgeIterator_isStopped(&ccg_edge_iter);
- ccgEdgeIterator_next(&ccg_edge_iter)) {
- /* const */ CCGEdge *ccg_edge = ccgEdgeIterator_getCurrent(&ccg_edge_iter);
- /* const */ CCGVert *ccg_vert1 = ccg_edge->v0;
- /* const */ CCGVert *ccg_vert2 = ccg_edge->v1;
- const int ccg_vert1_index = POINTER_AS_INT(ccgSubSurf_getVertVertHandle(ccg_vert1));
- const int ccg_vert2_index = POINTER_AS_INT(ccgSubSurf_getVertVertHandle(ccg_vert2));
- const int edge_index = POINTER_AS_INT(ccgSubSurf_getEdgeEdgeHandle(ccg_edge));
- const MEdge *me = &medge[edge_index];
- if (me->v1 != ccg_vert1_index || me->v2 != ccg_vert2_index) {
- return false;
- }
- }
- }
-
- /* TODO(sergey): Crease topology changes detection. */
- {
- CCGEdgeIterator ccg_edge_iter;
- for (ccgSubSurf_initEdgeIterator(ss, &ccg_edge_iter);
- !ccgEdgeIterator_isStopped(&ccg_edge_iter);
- ccgEdgeIterator_next(&ccg_edge_iter)) {
- /* const */ CCGEdge *ccg_edge = ccgEdgeIterator_getCurrent(&ccg_edge_iter);
- const int edge_index = POINTER_AS_INT(ccgSubSurf_getEdgeEdgeHandle(ccg_edge));
- if (ccg_edge->crease != medge[edge_index].crease) {
- return false;
- }
- }
- }
-
- return true;
-}
-
-static bool compare_osd_derivedmesh_topology(CCGSubSurf *ss, DerivedMesh *dm)
-{
- OpenSubdiv_Converter converter;
- bool result;
- if (ss->osd_mesh == NULL && ss->osd_topology_refiner == NULL) {
- return true;
- }
- /* TODO(sergey): De-duplicate with topology counter at the bottom of
- * the file.
- */
- ccgSubSurf_converter_setup_from_derivedmesh(ss, dm, &converter);
- result = openSubdiv_topologyRefinerCompareWithConverter(ss->osd_topology_refiner, &converter);
- ccgSubSurf_converter_free(&converter);
- return result;
-}
-
-static bool opensubdiv_is_topology_changed(CCGSubSurf *ss, DerivedMesh *dm)
-{
- if (ss->osd_compute != U.opensubdiv_compute_type) {
- return true;
- }
- if (ss->osd_topology_refiner != NULL) {
- const int levels = ss->osd_topology_refiner->getSubdivisionLevel(ss->osd_topology_refiner);
- BLI_assert(ss->osd_mesh_invalid == true);
- if (levels != ss->subdivLevels) {
- return true;
- }
- }
- if (ss->skip_grids == false) {
- return compare_ccg_derivedmesh_topology(ss, dm) == false;
- }
- else {
- return compare_osd_derivedmesh_topology(ss, dm) == false;
- }
- return false;
-}
-
-void ccgSubSurf_checkTopologyChanged(CCGSubSurf *ss, DerivedMesh *dm)
-{
- if (opensubdiv_is_topology_changed(ss, dm)) {
- /* ** Make sure both GPU and CPU backends are properly reset. ** */
-
- ss->osd_coarse_coords_invalid = true;
-
- /* Reset GPU part. */
- ss->osd_mesh_invalid = true;
- if (ss->osd_topology_refiner != NULL) {
- openSubdiv_deleteTopologyRefiner(ss->osd_topology_refiner);
- ss->osd_topology_refiner = NULL;
- }
-
- /* Reset CPU side. */
- if (ss->osd_evaluator != NULL) {
- openSubdiv_deleteEvaluator(ss->osd_evaluator);
- ss->osd_evaluator = NULL;
- }
- }
-}
-
-static void ccgSubSurf__updateGLMeshCoords(CCGSubSurf *ss)
-{
- BLI_assert(ss->meshIFC.numLayers == 3);
- ss->osd_mesh->setCoarsePositions(
- ss->osd_mesh, (float *)ss->osd_coarse_coords, 0, ss->osd_num_coarse_coords);
-}
-
-bool ccgSubSurf_prepareGLMesh(CCGSubSurf *ss, bool use_osd_glsl, int active_uv_index)
-{
- int compute_type;
-
- switch (U.opensubdiv_compute_type) {
-# define CHECK_COMPUTE_TYPE(type) \
- case USER_OPENSUBDIV_COMPUTE_##type: \
- compute_type = OPENSUBDIV_EVALUATOR_##type; \
- break;
- CHECK_COMPUTE_TYPE(CPU)
- CHECK_COMPUTE_TYPE(OPENMP)
- CHECK_COMPUTE_TYPE(OPENCL)
- CHECK_COMPUTE_TYPE(CUDA)
- CHECK_COMPUTE_TYPE(GLSL_TRANSFORM_FEEDBACK)
- CHECK_COMPUTE_TYPE(GLSL_COMPUTE)
- default:
- compute_type = OPENSUBDIV_EVALUATOR_CPU;
- break;
-# undef CHECK_COMPUTE_TYPE
- }
-
- if (ss->osd_vao == 0) {
- glGenVertexArrays(1, &ss->osd_vao);
- }
-
- if (ss->osd_mesh_invalid) {
- if (ss->osd_mesh != NULL) {
- ccgSubSurf__delete_osdGLMesh(ss->osd_mesh);
- ss->osd_mesh = NULL;
- }
- ss->osd_mesh_invalid = false;
- }
-
- if (ss->osd_mesh == NULL) {
- if (ss->osd_topology_refiner == NULL) {
- /* Happens with empty meshes. */
- /* TODO(sergey): Add assert that mesh is indeed empty. */
- return false;
- }
-
- ss->osd_mesh = openSubdiv_createOsdGLMeshFromTopologyRefiner(ss->osd_topology_refiner,
- compute_type);
-
- if (UNLIKELY(ss->osd_mesh == NULL)) {
- /* Most likely compute device is not available. */
- return false;
- }
-
- ccgSubSurf__updateGLMeshCoords(ss);
- ss->osd_mesh->refine(ss->osd_mesh);
- ss->osd_mesh->synchronize(ss->osd_mesh);
- ss->osd_coarse_coords_invalid = false;
-
- glBindVertexArray(ss->osd_vao);
- ss->osd_mesh->bindVertexBuffer(ss->osd_mesh);
-
- glEnableVertexAttribArray(0);
- glEnableVertexAttribArray(1);
- glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, sizeof(GLfloat) * 6, 0);
- glVertexAttribPointer(1, 3, GL_FLOAT, GL_FALSE, sizeof(GLfloat) * 6, (float *)12);
-
- glBindBuffer(GL_ARRAY_BUFFER, 0);
- glBindVertexArray(0);
- }
- else if (ss->osd_coarse_coords_invalid) {
- ccgSubSurf__updateGLMeshCoords(ss);
- ss->osd_mesh->refine(ss->osd_mesh);
- ss->osd_mesh->synchronize(ss->osd_mesh);
- ss->osd_coarse_coords_invalid = false;
- }
-
- ss->osd_mesh->prepareDraw(ss->osd_mesh, use_osd_glsl, active_uv_index);
-
- return true;
-}
-
-void ccgSubSurf_drawGLMesh(CCGSubSurf *ss,
- bool fill_quads,
- int start_partition,
- int num_partitions)
-{
- if (LIKELY(ss->osd_mesh != NULL)) {
- glBindVertexArray(ss->osd_vao);
- glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, ss->osd_mesh->getPatchIndexBuffer(ss->osd_mesh));
-
- ss->osd_mesh->bindVertexBuffer(ss->osd_mesh);
- glBindVertexArray(ss->osd_vao);
- ss->osd_mesh->drawPatches(ss->osd_mesh, fill_quads, start_partition, num_partitions);
- glBindVertexArray(0);
- glBindBuffer(GL_ARRAY_BUFFER, 0);
- glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0);
- }
-}
-
-int ccgSubSurf_getNumGLMeshBaseFaces(CCGSubSurf *ss)
-{
- if (ss->osd_topology_refiner != NULL) {
- return ss->osd_topology_refiner->getNumFaces(ss->osd_topology_refiner);
- }
- return 0;
-}
-
-/* Get number of vertices in base faces in a particular GL mesh. */
-int ccgSubSurf_getNumGLMeshBaseFaceVerts(CCGSubSurf *ss, int face)
-{
- if (ss->osd_topology_refiner != NULL) {
- return ss->osd_topology_refiner->getNumFaceVertices(ss->osd_topology_refiner, face);
- }
- return 0;
-}
-
-void ccgSubSurf_setSkipGrids(CCGSubSurf *ss, bool skip_grids)
-{
- ss->skip_grids = skip_grids;
-}
-
-bool ccgSubSurf_needGrids(CCGSubSurf *ss)
-{
- return ss->skip_grids == false;
-}
-
-BLI_INLINE void ccgSubSurf__mapGridToFace(
- int S, float grid_u, float grid_v, float *face_u, float *face_v)
-{
- float u, v;
-
- /* - Each grid covers half of the face along the edges.
- * - Grid's (0, 0) starts from the middle of the face.
- */
- u = 0.5f - 0.5f * grid_u;
- v = 0.5f - 0.5f * grid_v;
-
- if (S == 0) {
- *face_u = v;
- *face_v = u;
- }
- else if (S == 1) {
- *face_u = 1.0f - u;
- *face_v = v;
- }
- else if (S == 2) {
- *face_u = 1.0f - v;
- *face_v = 1.0f - u;
- }
- else {
- *face_u = u;
- *face_v = 1.0f - v;
- }
-}
-
-BLI_INLINE void ccgSubSurf__mapEdgeToFace(
- int S, int edge_segment, bool inverse_edge, int edgeSize, float *face_u, float *face_v)
-{
- int t = inverse_edge ? edgeSize - edge_segment - 1 : edge_segment;
- if (S == 0) {
- *face_u = (float)t / (edgeSize - 1);
- *face_v = 0.0f;
- }
- else if (S == 1) {
- *face_u = 1.0f;
- *face_v = (float)t / (edgeSize - 1);
- }
- else if (S == 2) {
- *face_u = 1.0f - (float)t / (edgeSize - 1);
- *face_v = 1.0f;
- }
- else {
- *face_u = 0.0f;
- *face_v = 1.0f - (float)t / (edgeSize - 1);
- }
-}
-
-void ccgSubSurf_evaluatorSetFVarUV(CCGSubSurf *ss, DerivedMesh *dm, int layer_index)
-{
- MPoly *mpoly = dm->getPolyArray(dm);
- MLoopUV *mloopuv = CustomData_get_layer_n(&dm->loopData, CD_MLOOPUV, layer_index);
- int num_polys = dm->getNumPolys(dm);
- int index, poly;
- BLI_assert(ss->osd_evaluator != NULL);
- for (poly = 0, index = 0; poly < num_polys; poly++) {
- int loop;
- MPoly *mp = &mpoly[poly];
- for (loop = 0; loop < mp->totloop; loop++, index++) {
- MLoopUV *mluv = &mloopuv[loop + mp->loopstart];
- (void)mluv;
- /* TODO(sergey): Send mluv->uv to the evaluator's face varying
- * buffer.
- */
- }
- }
- (void)ss;
-}
-
-void ccgSubSurf_evaluatorFVarUV(
- CCGSubSurf *ss, int face_index, int S, float grid_u, float grid_v, float uv[2])
-{
- float face_u, face_v;
- ccgSubSurf__mapGridToFace(S, grid_u, grid_v, &face_u, &face_v);
- (void)ss;
- (void)face_index;
- /* TODO(sergey): Evaluate face varying coordinate. */
- zero_v2(uv);
-}
-
-static bool opensubdiv_createEvaluator(CCGSubSurf *ss)
-{
- OpenSubdiv_Converter converter;
- OpenSubdiv_TopologyRefiner *topology_refiner;
- if (ss->fMap->numEntries == 0) {
- /* OpenSubdiv doesn't support meshes without faces. */
- return false;
- }
- ccgSubSurf_converter_setup_from_ccg(ss, &converter);
- OpenSubdiv_TopologyRefinerSettings settings;
- settings.level = ss->subdivLevels;
- settings.is_adaptive = false;
- topology_refiner = openSubdiv_createTopologyRefinerFromConverter(&converter, &settings);
- ccgSubSurf_converter_free(&converter);
- ss->osd_evaluator = openSubdiv_createEvaluatorFromTopologyRefiner(topology_refiner);
- if (ss->osd_evaluator == NULL) {
- BLI_assert(!"OpenSubdiv initialization failed, should not happen.");
- return false;
- }
- return true;
-}
-
-static bool opensubdiv_ensureEvaluator(CCGSubSurf *ss)
-{
- if (ss->osd_evaluator == NULL) {
- OSD_LOG("Allocating new evaluator, %d verts\n", ss->vMap->numEntries);
- opensubdiv_createEvaluator(ss);
- }
- return ss->osd_evaluator != NULL;
-}
-
-static void opensubdiv_updateEvaluatorCoarsePositions(CCGSubSurf *ss)
-{
- float(*positions)[3];
- int vertDataSize = ss->meshIFC.vertDataSize;
- int num_basis_verts = ss->vMap->numEntries;
- int i;
-
- /* TODO(sergey): Avoid allocation on every update. We could either update
- * coordinates in chunks of 1K vertices (which will only use stack memory)
- * or do some callback magic for OSD evaluator can invoke it and fill in
- * buffer directly.
- */
- if (ss->meshIFC.numLayers == 3) {
- /* If all the components are to be initialized, no need to memset the
- * new memory block.
- */
- positions = MEM_mallocN(3 * sizeof(float) * num_basis_verts, "OpenSubdiv coarse points");
- }
- else {
- /* Calloc in order to have z component initialized to 0 for Uvs */
- positions = MEM_callocN(3 * sizeof(float) * num_basis_verts, "OpenSubdiv coarse points");
- }
-# pragma omp parallel for
- for (i = 0; i < ss->vMap->curSize; i++) {
- CCGVert *v = (CCGVert *)ss->vMap->buckets[i];
- for (; v; v = v->next) {
- float *co = VERT_getCo(v, 0);
- BLI_assert(v->osd_index < ss->vMap->numEntries);
- VertDataCopy(positions[v->osd_index], co, ss);
- OSD_LOG("Point %d has value %f %f %f\n",
- v->osd_index,
- positions[v->osd_index][0],
- positions[v->osd_index][1],
- positions[v->osd_index][2]);
- }
- }
-
- ss->osd_evaluator->setCoarsePositions(ss->osd_evaluator, (float *)positions, 0, num_basis_verts);
- ss->osd_evaluator->refine(ss->osd_evaluator);
-
- MEM_freeN(positions);
-}
-
-static void opensubdiv_evaluateQuadFaceGrids(CCGSubSurf *ss,
- CCGFace *face,
- const int osd_face_index)
-{
- int normalDataOffset = ss->normalDataOffset;
- int subdivLevels = ss->subdivLevels;
- int gridSize = ccg_gridsize(subdivLevels);
- int edgeSize = ccg_edgesize(subdivLevels);
- int vertDataSize = ss->meshIFC.vertDataSize;
- int S;
- bool do_normals = ss->meshIFC.numLayers == 3;
-
-# pragma omp parallel for
- for (S = 0; S < face->numVerts; S++) {
- int x, y, k;
- CCGEdge *edge = NULL;
- bool inverse_edge = false;
-
- for (x = 0; x < gridSize; x++) {
- for (y = 0; y < gridSize; y++) {
- float *co = FACE_getIFCo(face, subdivLevels, S, x, y);
- float *no = FACE_getIFNo(face, subdivLevels, S, x, y);
- float grid_u = (float)x / (gridSize - 1), grid_v = (float)y / (gridSize - 1);
- float face_u, face_v;
- float P[3], dPdu[3], dPdv[3];
-
- ccgSubSurf__mapGridToFace(S, grid_u, grid_v, &face_u, &face_v);
-
- /* TODO(sergey): Need proper port. */
- ss->osd_evaluator->evaluateLimit(ss->osd_evaluator,
- osd_face_index,
- face_u,
- face_v,
- P,
- do_normals ? dPdu : NULL,
- do_normals ? dPdv : NULL);
-
- OSD_LOG("face=%d, corner=%d, grid_u=%f, grid_v=%f, face_u=%f, face_v=%f, P=(%f, %f, %f)\n",
- osd_face_index,
- S,
- grid_u,
- grid_v,
- face_u,
- face_v,
- P[0],
- P[1],
- P[2]);
-
- VertDataCopy(co, P, ss);
- if (do_normals) {
- cross_v3_v3v3(no, dPdu, dPdv);
- normalize_v3(no);
- }
-
- if (x == gridSize - 1 && y == gridSize - 1) {
- float *vert_co = VERT_getCo(FACE_getVerts(face)[S], subdivLevels);
- VertDataCopy(vert_co, co, ss);
- if (do_normals) {
- float *vert_no = VERT_getNo(FACE_getVerts(face)[S], subdivLevels);
- VertDataCopy(vert_no, no, ss);
- }
- }
- if (S == 0 && x == 0 && y == 0) {
- float *center_co = (float *)FACE_getCenterData(face);
- VertDataCopy(center_co, co, ss);
- if (do_normals) {
- float *center_no = (float *)((byte *)FACE_getCenterData(face) + normalDataOffset);
- VertDataCopy(center_no, no, ss);
- }
- }
- }
- }
-
- for (x = 0; x < gridSize; x++) {
- VertDataCopy(
- FACE_getIECo(face, subdivLevels, S, x), FACE_getIFCo(face, subdivLevels, S, x, 0), ss);
- if (do_normals) {
- VertDataCopy(
- FACE_getIENo(face, subdivLevels, S, x), FACE_getIFNo(face, subdivLevels, S, x, 0), ss);
- }
- }
-
- for (k = 0; k < face->numVerts; k++) {
- CCGEdge *current_edge = FACE_getEdges(face)[k];
- CCGVert **face_verts = FACE_getVerts(face);
- if (current_edge->v0 == face_verts[S] &&
- current_edge->v1 == face_verts[(S + 1) % face->numVerts]) {
- edge = current_edge;
- inverse_edge = false;
- break;
- }
- if (current_edge->v1 == face_verts[S] &&
- current_edge->v0 == face_verts[(S + 1) % face->numVerts]) {
- edge = current_edge;
- inverse_edge = true;
- break;
- }
- }
-
- BLI_assert(edge != NULL);
-
- for (x = 0; x < edgeSize; x++) {
- float u = 0, v = 0;
- float *co = EDGE_getCo(edge, subdivLevels, x);
- float *no = EDGE_getNo(edge, subdivLevels, x);
- float P[3], dPdu[3], dPdv[3];
- ccgSubSurf__mapEdgeToFace(S, x, inverse_edge, edgeSize, &u, &v);
-
- /* TODO(sergey): Ideally we will re-use grid here, but for now
- * let's just re-evaluate for simplicity.
- */
- /* TODO(sergey): Need proper port. */
- ss->osd_evaluator->evaluateLimit(ss->osd_evaluator, osd_face_index, u, v, P, dPdu, dPdv);
- VertDataCopy(co, P, ss);
- if (do_normals) {
- cross_v3_v3v3(no, dPdu, dPdv);
- normalize_v3(no);
- }
- }
- }
-}
-
-static void opensubdiv_evaluateNGonFaceGrids(CCGSubSurf *ss,
- CCGFace *face,
- const int osd_face_index)
-{
- CCGVert **all_verts = FACE_getVerts(face);
- int normalDataOffset = ss->normalDataOffset;
- int subdivLevels = ss->subdivLevels;
- int gridSize = ccg_gridsize(subdivLevels);
- int edgeSize = ccg_edgesize(subdivLevels);
- int vertDataSize = ss->meshIFC.vertDataSize;
- int S;
- bool do_normals = ss->meshIFC.numLayers == 3;
-
- /* Note about handling non-quad faces.
- *
- * In order to deal with non-quad faces we need to split them
- * into a quads in the following way:
- *
- * |
- * (vert_next)
- * |
- * |
- * |
- * (face_center) ------------------- (v2)
- * | (o)--------------------> |
- * | | v |
- * | | |
- * | | |
- * | | |
- * | | y ^ |
- * | | | |
- * | v u x | |
- * | <---(o) |
- * ---- (vert_prev) ---- (v1) -------------------- (vert)
- *
- * This is how grids are expected to be stored and it's how
- * OpenSubdiv deals with non-quad faces using ptex face indices.
- * We only need to convert ptex (x, y) to grid (u, v) by some
- * simple flips and evaluate the ptex face.
- */
-
- /* Evaluate face grids. */
-# pragma omp parallel for
- for (S = 0; S < face->numVerts; S++) {
- int x, y;
- for (x = 0; x < gridSize; x++) {
- for (y = 0; y < gridSize; y++) {
- float *co = FACE_getIFCo(face, subdivLevels, S, x, y);
- float *no = FACE_getIFNo(face, subdivLevels, S, x, y);
- float u = 1.0f - (float)y / (gridSize - 1), v = 1.0f - (float)x / (gridSize - 1);
- float P[3], dPdu[3], dPdv[3];
-
- /* TODO(sergey): Need proper port. */
- ss->osd_evaluator->evaluateLimit(
- ss->osd_evaluator, osd_face_index + S, u, v, P, dPdu, dPdv);
-
- OSD_LOG("face=%d, corner=%d, u=%f, v=%f, P=(%f, %f, %f)\n",
- osd_face_index + S,
- S,
- u,
- v,
- P[0],
- P[1],
- P[2]);
-
- VertDataCopy(co, P, ss);
- if (do_normals) {
- cross_v3_v3v3(no, dPdu, dPdv);
- normalize_v3(no);
- }
-
- /* TODO(sergey): De-dpuplicate with the quad case. */
- if (x == gridSize - 1 && y == gridSize - 1) {
- float *vert_co = VERT_getCo(FACE_getVerts(face)[S], subdivLevels);
- VertDataCopy(vert_co, co, ss);
- if (do_normals) {
- float *vert_no = VERT_getNo(FACE_getVerts(face)[S], subdivLevels);
- VertDataCopy(vert_no, no, ss);
- }
- }
- if (S == 0 && x == 0 && y == 0) {
- float *center_co = (float *)FACE_getCenterData(face);
- VertDataCopy(center_co, co, ss);
- if (do_normals) {
- float *center_no = (float *)((byte *)FACE_getCenterData(face) + normalDataOffset);
- VertDataCopy(center_no, no, ss);
- }
- }
- }
- }
- for (x = 0; x < gridSize; x++) {
- VertDataCopy(
- FACE_getIECo(face, subdivLevels, S, x), FACE_getIFCo(face, subdivLevels, S, x, 0), ss);
- if (do_normals) {
- VertDataCopy(
- FACE_getIENo(face, subdivLevels, S, x), FACE_getIFNo(face, subdivLevels, S, x, 0), ss);
- }
- }
- }
-
- /* Evaluate edges. */
- for (S = 0; S < face->numVerts; S++) {
- CCGEdge *edge = FACE_getEdges(face)[S];
- int x, S0 = 0, S1 = 0;
- bool flip;
-
- for (x = 0; x < face->numVerts; x++) {
- if (all_verts[x] == edge->v0) {
- S0 = x;
- }
- else if (all_verts[x] == edge->v1) {
- S1 = x;
- }
- }
- if (S == face->numVerts - 1) {
- flip = S0 > S1;
- }
- else {
- flip = S0 < S1;
- }
-
- for (x = 0; x <= edgeSize / 2; x++) {
- float *edge_co = EDGE_getCo(edge, subdivLevels, x);
- float *edge_no = EDGE_getNo(edge, subdivLevels, x);
- float *face_edge_co;
- float *face_edge_no;
- if (flip) {
- face_edge_co = FACE_getIFCo(face, subdivLevels, S0, gridSize - 1, gridSize - 1 - x);
- face_edge_no = FACE_getIFNo(face, subdivLevels, S0, gridSize - 1, gridSize - 1 - x);
- }
- else {
- face_edge_co = FACE_getIFCo(face, subdivLevels, S0, gridSize - 1 - x, gridSize - 1);
- face_edge_no = FACE_getIFNo(face, subdivLevels, S0, gridSize - 1 - x, gridSize - 1);
- }
- VertDataCopy(edge_co, face_edge_co, ss);
- if (do_normals) {
- VertDataCopy(edge_no, face_edge_no, ss);
- }
- }
- for (x = edgeSize / 2 + 1; x < edgeSize; x++) {
- float *edge_co = EDGE_getCo(edge, subdivLevels, x);
- float *edge_no = EDGE_getNo(edge, subdivLevels, x);
- float *face_edge_co;
- float *face_edge_no;
- if (flip) {
- face_edge_co = FACE_getIFCo(face, subdivLevels, S1, x - edgeSize / 2, gridSize - 1);
- face_edge_no = FACE_getIFNo(face, subdivLevels, S1, x - edgeSize / 2, gridSize - 1);
- }
- else {
- face_edge_co = FACE_getIFCo(face, subdivLevels, S1, gridSize - 1, x - edgeSize / 2);
- face_edge_no = FACE_getIFNo(face, subdivLevels, S1, gridSize - 1, x - edgeSize / 2);
- }
- VertDataCopy(edge_co, face_edge_co, ss);
- if (do_normals) {
- VertDataCopy(edge_no, face_edge_no, ss);
- }
- }
- }
-}
-
-static void opensubdiv_evaluateGrids(CCGSubSurf *ss)
-{
- int i;
- for (i = 0; i < ss->fMap->curSize; i++) {
- CCGFace *face = (CCGFace *)ss->fMap->buckets[i];
- for (; face; face = face->next) {
- if (face->numVerts == 4) {
- /* For quads we do special magic with converting face coords
- * into corner coords and interpolating grids from it.
- */
- opensubdiv_evaluateQuadFaceGrids(ss, face, face->osd_index);
- }
- else {
- /* NGons and tris are split into separate osd faces which
- * evaluates onto grids directly.
- */
- opensubdiv_evaluateNGonFaceGrids(ss, face, face->osd_index);
- }
- }
- }
-}
-
-CCGError ccgSubSurf_initOpenSubdivSync(CCGSubSurf *ss)
-{
- if (ss->syncState != eSyncState_None) {
- return eCCGError_InvalidSyncState;
- }
- ss->syncState = eSyncState_OpenSubdiv;
- return eCCGError_None;
-}
-
-void ccgSubSurf_prepareTopologyRefiner(CCGSubSurf *ss, DerivedMesh *dm)
-{
- if (ss->osd_mesh == NULL || ss->osd_mesh_invalid) {
- if (dm->getNumPolys(dm) != 0) {
- OpenSubdiv_Converter converter;
- ccgSubSurf_converter_setup_from_derivedmesh(ss, dm, &converter);
- /* TODO(sergey): Remove possibly previously allocated refiner. */
- OpenSubdiv_TopologyRefinerSettings settings;
- settings.level = ss->subdivLevels;
- settings.is_adaptive = false;
- ss->osd_topology_refiner = openSubdiv_createTopologyRefinerFromConverter(&converter,
- &settings);
- ccgSubSurf_converter_free(&converter);
- }
- }
-
- /* Update number of grids, needed for things like final faces
- * counter, used by display drawing.
- */
- {
- const int num_polys = dm->getNumPolys(dm);
- const MPoly *mpoly = dm->getPolyArray(dm);
- int poly;
- ss->numGrids = 0;
- for (poly = 0; poly < num_polys; poly++) {
- ss->numGrids += mpoly[poly].totloop;
- }
- }
-
- {
- const int num_verts = dm->getNumVerts(dm);
- const MVert *mvert = dm->getVertArray(dm);
- int vert;
- if (ss->osd_coarse_coords != NULL && num_verts != ss->osd_num_coarse_coords) {
- MEM_freeN(ss->osd_coarse_coords);
- ss->osd_coarse_coords = NULL;
- }
- if (ss->osd_coarse_coords == NULL) {
- ss->osd_coarse_coords = MEM_mallocN(sizeof(float) * 6 * num_verts, "osd coarse positions");
- }
- for (vert = 0; vert < num_verts; vert++) {
- copy_v3_v3(ss->osd_coarse_coords[vert * 2 + 0], mvert[vert].co);
- normal_short_to_float_v3(ss->osd_coarse_coords[vert * 2 + 1], mvert[vert].no);
- }
- ss->osd_num_coarse_coords = num_verts;
- ss->osd_coarse_coords_invalid = true;
- }
-}
-
-void ccgSubSurf__sync_opensubdiv(CCGSubSurf *ss)
-{
- BLI_assert(ss->meshIFC.numLayers == 2 || ss->meshIFC.numLayers == 3);
-
- /* Common synchronization steps */
- ss->osd_compute = U.opensubdiv_compute_type;
-
- if (ss->skip_grids == false) {
- /* Make sure OSD evaluator is up-to-date. */
- if (opensubdiv_ensureEvaluator(ss)) {
- /* Update coarse points in the OpenSubdiv evaluator. */
- opensubdiv_updateEvaluatorCoarsePositions(ss);
-
- /* Evaluate opensubdiv mesh into the CCG grids. */
- opensubdiv_evaluateGrids(ss);
- }
- }
- else {
- BLI_assert(ss->meshIFC.numLayers == 3);
- }
-
-# ifdef DUMP_RESULT_GRIDS
- ccgSubSurf__dumpCoords(ss);
-# endif
-}
-
-void ccgSubSurf_free_osd_mesh(CCGSubSurf *ss)
-{
- if (ss->osd_mesh != NULL) {
- ccgSubSurf__delete_osdGLMesh(ss->osd_mesh);
- ss->osd_mesh = NULL;
- }
- if (ss->osd_vao != 0) {
- glDeleteVertexArrays(1, &ss->osd_vao);
- ss->osd_vao = 0;
- }
-}
-
-void ccgSubSurf_getMinMax(CCGSubSurf *ss, float r_min[3], float r_max[3])
-{
- int i;
- BLI_assert(ss->skip_grids == true);
- if (ss->osd_num_coarse_coords == 0) {
- zero_v3(r_min);
- zero_v3(r_max);
- }
- for (i = 0; i < ss->osd_num_coarse_coords; i++) {
- /* Coarse coordinates has normals interleaved into the array. */
- DO_MINMAX(ss->osd_coarse_coords[2 * i], r_min, r_max);
- }
-}
-
-/* ** Delayed delete routines ** */
-
-typedef struct OsdDeletePendingItem {
- struct OsdDeletePendingItem *next, *prev;
- OpenSubdiv_GLMesh *osd_mesh;
- unsigned int vao;
-} OsdDeletePendingItem;
-
-static SpinLock delete_spin;
-static ListBase delete_pool = {NULL, NULL};
-
-static void delete_pending_push(OpenSubdiv_GLMesh *osd_mesh, unsigned int vao)
-{
- OsdDeletePendingItem *new_entry = MEM_mallocN(sizeof(OsdDeletePendingItem),
- "opensubdiv delete entry");
- new_entry->osd_mesh = osd_mesh;
- new_entry->vao = vao;
- BLI_spin_lock(&delete_spin);
- BLI_addtail(&delete_pool, new_entry);
- BLI_spin_unlock(&delete_spin);
-}
-
-void ccgSubSurf__delete_osdGLMesh(OpenSubdiv_GLMesh *osd_mesh)
-{
- if (BLI_thread_is_main()) {
- openSubdiv_deleteOsdGLMesh(osd_mesh);
- }
- else {
- delete_pending_push(osd_mesh, 0);
- }
-}
-
-void ccgSubSurf__delete_vertex_array(unsigned int vao)
-{
- if (BLI_thread_is_main()) {
- glDeleteVertexArrays(1, &vao);
- }
- else {
- delete_pending_push(NULL, vao);
- }
-}
-
-void ccgSubSurf__delete_pending(void)
-{
- OsdDeletePendingItem *entry;
- BLI_assert(BLI_thread_is_main());
- BLI_spin_lock(&delete_spin);
- for (entry = delete_pool.first; entry != NULL; entry = entry->next) {
- if (entry->osd_mesh != NULL) {
- openSubdiv_deleteOsdGLMesh(entry->osd_mesh);
- }
- if (entry->vao != 0) {
- glDeleteVertexArrays(1, &entry->vao);
- }
- }
- BLI_freelistN(&delete_pool);
- BLI_spin_unlock(&delete_spin);
-}
-
-void ccgSubSurf__sync_subdivUvs(CCGSubSurf *ss, bool subdiv_uvs)
-{
- ss->osd_subdiv_uvs = subdiv_uvs;
-}
-
-/* ** Public API ** */
-
-void BKE_subsurf_osd_init(void)
-{
- openSubdiv_init();
- BLI_spin_init(&delete_spin);
-}
-
-void BKE_subsurf_free_unused_buffers(void)
-{
- ccgSubSurf__delete_pending();
-}
-
-void BKE_subsurf_osd_cleanup(void)
-{
- openSubdiv_cleanup();
- ccgSubSurf__delete_pending();
- BLI_spin_end(&delete_spin);
-}
-
-#endif /* WITH_OPENSUBDIV */
diff --git a/source/blender/blenkernel/intern/CCGSubSurf_opensubdiv_converter.c b/source/blender/blenkernel/intern/CCGSubSurf_opensubdiv_converter.c
deleted file mode 100644
index 16766d52e57..00000000000
--- a/source/blender/blenkernel/intern/CCGSubSurf_opensubdiv_converter.c
+++ /dev/null
@@ -1,777 +0,0 @@
-/*
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License
- * as published by the Free Software Foundation; either version 2
- * of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-
-/** \file
- * \ingroup bke
- */
-
-#ifdef WITH_OPENSUBDIV
-
-# include <stdlib.h>
-
-# include "BLI_sys_types.h" // for intptr_t support
-# include "MEM_guardedalloc.h"
-
-# include "BLI_math.h"
-# include "BLI_utildefines.h" /* for BLI_assert */
-
-# include "CCGSubSurf.h"
-# include "CCGSubSurf_intern.h"
-
-# include "BKE_DerivedMesh.h"
-# include "BKE_mesh_mapping.h"
-
-# include "opensubdiv_capi.h"
-# include "opensubdiv_converter_capi.h"
-
-/* Use mesh element mapping structures during conversion.
- * Uses more memory but is much faster than naive algorithm.
- */
-# define USE_MESH_ELEMENT_MAPPING
-
-/**
- * Converter from DerivedMesh.
- */
-
-typedef struct ConvDMStorage {
- CCGSubSurf *ss;
- DerivedMesh *dm;
-
-# ifdef USE_MESH_ELEMENT_MAPPING
- MeshElemMap *vert_edge_map, *vert_poly_map, *edge_poly_map;
- int *vert_edge_mem, *vert_poly_mem, *edge_poly_mem;
-# endif
-
- MVert *mvert;
- MEdge *medge;
- MLoop *mloop;
- MPoly *mpoly;
-
- MeshIslandStore island_store;
- int num_uvs;
- float *uvs;
- int *face_uvs;
-} ConvDMStorage;
-
-static OpenSubdiv_SchemeType conv_dm_get_type(const OpenSubdiv_Converter *converter)
-{
- ConvDMStorage *storage = converter->user_data;
- if (storage->ss->meshIFC.simpleSubdiv) {
- return OSD_SCHEME_BILINEAR;
- }
- else {
- return OSD_SCHEME_CATMARK;
- }
-}
-
-static OpenSubdiv_VtxBoundaryInterpolation conv_dm_get_vtx_boundary_interpolation(
- const OpenSubdiv_Converter *UNUSED(converter))
-{
- return OSD_VTX_BOUNDARY_EDGE_ONLY;
-}
-
-static OpenSubdiv_FVarLinearInterpolation conv_dm_get_fvar_linear_interpolation(
- const OpenSubdiv_Converter *converter)
-{
- ConvDMStorage *storage = converter->user_data;
- if (storage->ss->osd_subdiv_uvs) {
- return OSD_FVAR_LINEAR_INTERPOLATION_CORNERS_ONLY;
- }
- return OSD_FVAR_LINEAR_INTERPOLATION_ALL;
-}
-
-static bool conv_dm_specifies_full_topology(const OpenSubdiv_Converter *UNUSED(converter))
-{
- return true;
-}
-
-static int conv_dm_get_num_faces(const OpenSubdiv_Converter *converter)
-{
- ConvDMStorage *storage = converter->user_data;
- DerivedMesh *dm = storage->dm;
- return dm->getNumPolys(dm);
-}
-
-static int conv_dm_get_num_edges(const OpenSubdiv_Converter *converter)
-{
- ConvDMStorage *storage = converter->user_data;
- DerivedMesh *dm = storage->dm;
- return dm->getNumEdges(dm);
-}
-
-static int conv_dm_get_num_verts(const OpenSubdiv_Converter *converter)
-{
- ConvDMStorage *storage = converter->user_data;
- DerivedMesh *dm = storage->dm;
- return dm->getNumVerts(dm);
-}
-
-static int conv_dm_get_num_face_verts(const OpenSubdiv_Converter *converter, int face)
-{
- ConvDMStorage *storage = converter->user_data;
- const MPoly *mpoly = &storage->mpoly[face];
- return mpoly->totloop;
-}
-
-static void conv_dm_get_face_verts(const OpenSubdiv_Converter *converter,
- int face,
- int *face_verts)
-{
- ConvDMStorage *storage = converter->user_data;
- const MPoly *mpoly = &storage->mpoly[face];
- int loop;
- for (loop = 0; loop < mpoly->totloop; loop++) {
- face_verts[loop] = storage->mloop[mpoly->loopstart + loop].v;
- }
-}
-
-static void conv_dm_get_face_edges(const OpenSubdiv_Converter *converter,
- int face,
- int *face_edges)
-{
- ConvDMStorage *storage = converter->user_data;
- const MPoly *mpoly = &storage->mpoly[face];
- int loop;
- for (loop = 0; loop < mpoly->totloop; loop++) {
- face_edges[loop] = storage->mloop[mpoly->loopstart + loop].e;
- }
-}
-
-static void conv_dm_get_edge_verts(const OpenSubdiv_Converter *converter,
- int edge,
- int *edge_verts)
-{
- ConvDMStorage *storage = converter->user_data;
- const MEdge *medge = &storage->medge[edge];
- edge_verts[0] = medge->v1;
- edge_verts[1] = medge->v2;
-}
-
-static int conv_dm_get_num_edge_faces(const OpenSubdiv_Converter *converter, int edge)
-{
- ConvDMStorage *storage = converter->user_data;
-# ifndef USE_MESH_ELEMENT_MAPPING
- DerivedMesh *dm = storage->dm;
- int num = 0, poly;
- for (poly = 0; poly < dm->getNumPolys(dm); poly++) {
- const MPoly *mpoly = &user_data->mpoly[poly];
- int loop;
- for (loop = 0; loop < mpoly->totloop; loop++) {
- const MLoop *mloop = &storage->mloop[mpoly->loopstart + loop];
- if (mloop->e == edge) {
- num++;
- break;
- }
- }
- }
- return num;
-# else
- return storage->edge_poly_map[edge].count;
-# endif
-}
-
-static void conv_dm_get_edge_faces(const OpenSubdiv_Converter *converter,
- int edge,
- int *edge_faces)
-{
- ConvDMStorage *storage = converter->user_data;
-# ifndef USE_MESH_ELEMENT_MAPPING
- DerivedMesh *dm = storage->dm;
- int num = 0, poly;
- for (poly = 0; poly < dm->getNumPolys(dm); poly++) {
- const MPoly *mpoly = &user_data->mpoly[poly];
- int loop;
- for (loop = 0; loop < mpoly->totloop; loop++) {
- const MLoop *mloop = &storage->mloop[mpoly->loopstart + loop];
- if (mloop->e == edge) {
- edge_faces[num++] = poly;
- break;
- }
- }
- }
-# else
- memcpy(edge_faces,
- storage->edge_poly_map[edge].indices,
- sizeof(int) * storage->edge_poly_map[edge].count);
-# endif
-}
-
-static float conv_dm_get_edge_sharpness(const OpenSubdiv_Converter *converter, int edge)
-{
- ConvDMStorage *storage = converter->user_data;
- CCGSubSurf *ss = storage->ss;
- const MEdge *medge = storage->medge;
- return (float)medge[edge].crease / 255.0f * ss->subdivLevels;
-}
-
-static int conv_dm_get_num_vert_edges(const OpenSubdiv_Converter *converter, int vert)
-{
- ConvDMStorage *storage = converter->user_data;
-# ifndef USE_MESH_ELEMENT_MAPPING
- DerivedMesh *dm = storage->dm;
- int num = 0, edge;
- for (edge = 0; edge < dm->getNumEdges(dm); edge++) {
- const MEdge *medge = &user_data->medge[edge];
- if (medge->v1 == vert || medge->v2 == vert) {
- num++;
- }
- }
- return num;
-# else
- return storage->vert_edge_map[vert].count;
-# endif
-}
-
-static void conv_dm_get_vert_edges(const OpenSubdiv_Converter *converter,
- int vert,
- int *vert_edges)
-{
- ConvDMStorage *storage = converter->user_data;
-# ifndef USE_MESH_ELEMENT_MAPPING
- DerivedMesh *dm = storage->dm;
- int num = 0, edge;
- for (edge = 0; edge < dm->getNumEdges(dm); edge++) {
- const MEdge *medge = &user_data->medge[edge];
- if (medge->v1 == vert || medge->v2 == vert) {
- vert_edges[num++] = edge;
- }
- }
-# else
- memcpy(vert_edges,
- storage->vert_edge_map[vert].indices,
- sizeof(int) * storage->vert_edge_map[vert].count);
-# endif
-}
-
-static int conv_dm_get_num_vert_faces(const OpenSubdiv_Converter *converter, int vert)
-{
- ConvDMStorage *storage = converter->user_data;
-# ifndef USE_MESH_ELEMENT_MAPPING
- DerivedMesh *dm = storage->dm;
- int num = 0, poly;
- for (poly = 0; poly < dm->getNumPolys(dm); poly++) {
- const MPoly *mpoly = &user_data->mpoly[poly];
- int loop;
- for (loop = 0; loop < mpoly->totloop; loop++) {
- const MLoop *mloop = &storage->mloop[mpoly->loopstart + loop];
- if (mloop->v == vert) {
- num++;
- break;
- }
- }
- }
- return num;
-# else
- return storage->vert_poly_map[vert].count;
-# endif
-}
-
-static void conv_dm_get_vert_faces(const OpenSubdiv_Converter *converter,
- int vert,
- int *vert_faces)
-{
- ConvDMStorage *storage = converter->user_data;
-# ifndef USE_MESH_ELEMENT_MAPPING
- DerivedMesh *dm = storage->dm;
- int num = 0, poly;
- for (poly = 0; poly < dm->getNumPolys(dm); poly++) {
- const MPoly *mpoly = &storage->mpoly[poly];
- int loop;
- for (loop = 0; loop < mpoly->totloop; loop++) {
- const MLoop *mloop = &storage->mloop[mpoly->loopstart + loop];
- if (mloop->v == vert) {
- vert_faces[num++] = poly;
- break;
- }
- }
- }
-# else
- memcpy(vert_faces,
- storage->vert_poly_map[vert].indices,
- sizeof(int) * storage->vert_poly_map[vert].count);
-# endif
-}
-
-static bool conv_dm_is_infinite_sharp_vertex(const OpenSubdiv_Converter *UNUSED(converter),
- int UNUSED(manifold_vertex_index))
-{
- return false;
-}
-
-static float conv_dm_get_vertex_sharpness(const OpenSubdiv_Converter *UNUSED(converter),
- int UNUSED(manifold_vertex_index))
-{
- return 0.0f;
-}
-
-static int conv_dm_get_num_uv_layers(const OpenSubdiv_Converter *converter)
-{
- ConvDMStorage *storage = converter->user_data;
- DerivedMesh *dm = storage->dm;
- int num_uv_layers = CustomData_number_of_layers(&dm->loopData, CD_MLOOPUV);
- return num_uv_layers;
-}
-
-static void conv_dm_precalc_uv_layer(const OpenSubdiv_Converter *converter, int layer)
-{
- ConvDMStorage *storage = converter->user_data;
- DerivedMesh *dm = storage->dm;
-
- const MLoopUV *mloopuv = CustomData_get_layer_n(&dm->loopData, CD_MLOOPUV, layer);
- const int num_loops = dm->getNumLoops(dm);
-
- /* Initialize memory required for the operations. */
- if (storage->uvs == NULL) {
- storage->uvs = MEM_mallocN(sizeof(float) * 2 * num_loops, "osd uvs");
- }
- if (storage->face_uvs == NULL) {
- storage->face_uvs = MEM_mallocN(sizeof(int) * num_loops, "osd face uvs");
- }
-
- /* Calculate islands connectivity of the UVs. */
- BKE_mesh_calc_islands_loop_poly_uvmap(storage->mvert,
- dm->getNumVerts(dm),
- storage->medge,
- dm->getNumEdges(dm),
- storage->mpoly,
- dm->getNumPolys(dm),
- storage->mloop,
- dm->getNumLoops(dm),
- mloopuv,
- &storage->island_store);
-
- /* Here we "weld" duplicated vertices from island to the same UV value.
- * The idea here is that we need to pass individual islands to OpenSubdiv.
- */
- storage->num_uvs = 0;
- for (int island = 0; island < storage->island_store.islands_num; island++) {
- MeshElemMap *island_poly_map = storage->island_store.islands[island];
- for (int poly = 0; poly < island_poly_map->count; poly++) {
- int poly_index = island_poly_map->indices[poly];
- /* Within the same UV island we should share UV points across
- * loops. Otherwise each poly will be subdivided individually
- * which we don't really want.
- */
- const MPoly *mpoly = &storage->mpoly[poly_index];
- for (int loop = 0; loop < mpoly->totloop; loop++) {
- const MLoopUV *luv = &mloopuv[mpoly->loopstart + loop];
- bool found = false;
- /* TODO(sergey): Quite bad loop, which gives us O(N^2)
- * complexity here. But how can we do it smarter, hopefully
- * without requiring lots of additional memory.
- */
- for (int i = 0; i < storage->num_uvs; i++) {
- if (equals_v2v2(luv->uv, &storage->uvs[2 * i])) {
- storage->face_uvs[mpoly->loopstart + loop] = i;
- found = true;
- break;
- }
- }
- if (!found) {
- copy_v2_v2(&storage->uvs[2 * storage->num_uvs], luv->uv);
- storage->face_uvs[mpoly->loopstart + loop] = storage->num_uvs;
- ++storage->num_uvs;
- }
- }
- }
- }
-}
-
-static void conv_dm_finish_uv_layer(const OpenSubdiv_Converter *converter)
-{
- ConvDMStorage *storage = converter->user_data;
- BKE_mesh_loop_islands_free(&storage->island_store);
-}
-
-static int conv_dm_get_num_uvs(const OpenSubdiv_Converter *converter)
-{
- ConvDMStorage *storage = converter->user_data;
- return storage->num_uvs;
-}
-
-static int conv_dm_get_face_corner_uv_index(const OpenSubdiv_Converter *converter,
- int face,
- int corner)
-{
- ConvDMStorage *storage = converter->user_data;
- const MPoly *mpoly = &storage->mpoly[face];
- return storage->face_uvs[mpoly->loopstart + corner];
-}
-
-static void conv_dm_free_user_data(const OpenSubdiv_Converter *converter)
-{
- ConvDMStorage *user_data = converter->user_data;
- if (user_data->uvs != NULL) {
- MEM_freeN(user_data->uvs);
- }
- if (user_data->face_uvs != NULL) {
- MEM_freeN(user_data->face_uvs);
- }
-
-# ifdef USE_MESH_ELEMENT_MAPPING
- MEM_freeN(user_data->vert_edge_map);
- MEM_freeN(user_data->vert_edge_mem);
- MEM_freeN(user_data->vert_poly_map);
- MEM_freeN(user_data->vert_poly_mem);
- MEM_freeN(user_data->edge_poly_map);
- MEM_freeN(user_data->edge_poly_mem);
-# endif
- MEM_freeN(user_data);
-}
-
-void ccgSubSurf_converter_setup_from_derivedmesh(CCGSubSurf *ss,
- DerivedMesh *dm,
- OpenSubdiv_Converter *converter)
-{
- ConvDMStorage *user_data;
-
- converter->getSchemeType = conv_dm_get_type;
-
- converter->getVtxBoundaryInterpolation = conv_dm_get_vtx_boundary_interpolation;
- converter->getFVarLinearInterpolation = conv_dm_get_fvar_linear_interpolation;
- converter->specifiesFullTopology = conv_dm_specifies_full_topology;
-
- converter->getNumFaces = conv_dm_get_num_faces;
- converter->getNumEdges = conv_dm_get_num_edges;
- converter->getNumVertices = conv_dm_get_num_verts;
-
- converter->getNumFaceVertices = conv_dm_get_num_face_verts;
- converter->getFaceVertices = conv_dm_get_face_verts;
- converter->getFaceEdges = conv_dm_get_face_edges;
-
- converter->getEdgeVertices = conv_dm_get_edge_verts;
- converter->getNumEdgeFaces = conv_dm_get_num_edge_faces;
- converter->getEdgeFaces = conv_dm_get_edge_faces;
- converter->getEdgeSharpness = conv_dm_get_edge_sharpness;
-
- converter->getNumVertexEdges = conv_dm_get_num_vert_edges;
- converter->getVertexEdges = conv_dm_get_vert_edges;
- converter->getNumVertexFaces = conv_dm_get_num_vert_faces;
- converter->getVertexFaces = conv_dm_get_vert_faces;
- converter->isInfiniteSharpVertex = conv_dm_is_infinite_sharp_vertex;
- converter->getVertexSharpness = conv_dm_get_vertex_sharpness;
-
- converter->getNumUVLayers = conv_dm_get_num_uv_layers;
- converter->precalcUVLayer = conv_dm_precalc_uv_layer;
- converter->finishUVLayer = conv_dm_finish_uv_layer;
- converter->getNumUVCoordinates = conv_dm_get_num_uvs;
- converter->getFaceCornerUVIndex = conv_dm_get_face_corner_uv_index;
-
- user_data = MEM_mallocN(sizeof(ConvDMStorage), __func__);
- user_data->ss = ss;
- user_data->dm = dm;
-
- user_data->mvert = dm->getVertArray(dm);
- user_data->medge = dm->getEdgeArray(dm);
- user_data->mloop = dm->getLoopArray(dm);
- user_data->mpoly = dm->getPolyArray(dm);
-
- memset(&user_data->island_store, 0, sizeof(user_data->island_store));
-
- user_data->uvs = NULL;
- user_data->face_uvs = NULL;
-
- converter->freeUserData = conv_dm_free_user_data;
- converter->user_data = user_data;
-
-# ifdef USE_MESH_ELEMENT_MAPPING
- {
- const MEdge *medge = dm->getEdgeArray(dm);
- const MLoop *mloop = dm->getLoopArray(dm);
- const MPoly *mpoly = dm->getPolyArray(dm);
- const int num_vert = dm->getNumVerts(dm), num_edge = dm->getNumEdges(dm),
- num_loop = dm->getNumLoops(dm), num_poly = dm->getNumPolys(dm);
- BKE_mesh_vert_edge_map_create(
- &user_data->vert_edge_map, &user_data->vert_edge_mem, medge, num_vert, num_edge);
-
- BKE_mesh_vert_poly_map_create(&user_data->vert_poly_map,
- &user_data->vert_poly_mem,
- mpoly,
- mloop,
- num_vert,
- num_poly,
- num_loop);
-
- BKE_mesh_edge_poly_map_create(&user_data->edge_poly_map,
- &user_data->edge_poly_mem,
- medge,
- num_edge,
- mpoly,
- num_poly,
- mloop,
- num_loop);
- }
-# endif /* USE_MESH_ELEMENT_MAPPING */
-}
-
-/**
- * Converter from CCGSubSurf
- */
-
-static OpenSubdiv_SchemeType conv_ccg_get_bilinear_type(const OpenSubdiv_Converter *converter)
-{
- CCGSubSurf *ss = converter->user_data;
- if (ss->meshIFC.simpleSubdiv) {
- return OSD_SCHEME_BILINEAR;
- }
- else {
- return OSD_SCHEME_CATMARK;
- }
-}
-
-static OpenSubdiv_VtxBoundaryInterpolation conv_ccg_get_vtx_boundary_interpolation(
- const OpenSubdiv_Converter *UNUSED(converter))
-{
- return OSD_VTX_BOUNDARY_EDGE_ONLY;
-}
-
-static OpenSubdiv_FVarLinearInterpolation conv_ccg_get_fvar_linear_interpolation(
- const OpenSubdiv_Converter *converter)
-{
- CCGSubSurf *ss = converter->user_data;
- if (ss->osd_subdiv_uvs) {
- return OSD_FVAR_LINEAR_INTERPOLATION_CORNERS_ONLY;
- }
- return OSD_FVAR_LINEAR_INTERPOLATION_ALL;
-}
-
-static bool conv_ccg_specifies_full_topology(const OpenSubdiv_Converter *UNUSED(converter))
-{
- return true;
-}
-
-static int conv_ccg_get_num_faces(const OpenSubdiv_Converter *converter)
-{
- CCGSubSurf *ss = converter->user_data;
- return ss->fMap->numEntries;
-}
-
-static int conv_ccg_get_num_edges(const OpenSubdiv_Converter *converter)
-{
- CCGSubSurf *ss = converter->user_data;
- return ss->eMap->numEntries;
-}
-
-static int conv_ccg_get_num_verts(const OpenSubdiv_Converter *converter)
-{
- CCGSubSurf *ss = converter->user_data;
- return ss->vMap->numEntries;
-}
-
-static int conv_ccg_get_num_face_verts(const OpenSubdiv_Converter *converter, int face)
-{
- CCGSubSurf *ss = converter->user_data;
- CCGFace *ccg_face = ccgSubSurf_getFace(ss, POINTER_FROM_INT(face));
- return ccgSubSurf_getFaceNumVerts(ccg_face);
-}
-
-static void conv_ccg_get_face_verts(const OpenSubdiv_Converter *converter,
- int face,
- int *face_verts)
-{
- CCGSubSurf *ss = converter->user_data;
- CCGFace *ccg_face = ccgSubSurf_getFace(ss, POINTER_FROM_INT(face));
- int num_face_verts = ccgSubSurf_getFaceNumVerts(ccg_face);
- int loop;
- for (loop = 0; loop < num_face_verts; loop++) {
- CCGVert *ccg_vert = ccgSubSurf_getFaceVert(ccg_face, loop);
- face_verts[loop] = POINTER_AS_INT(ccgSubSurf_getVertVertHandle(ccg_vert));
- }
-}
-
-static void conv_ccg_get_face_edges(const OpenSubdiv_Converter *converter,
- int face,
- int *face_edges)
-{
- CCGSubSurf *ss = converter->user_data;
- CCGFace *ccg_face = ccgSubSurf_getFace(ss, POINTER_FROM_INT(face));
- int num_face_verts = ccgSubSurf_getFaceNumVerts(ccg_face);
- int loop;
- for (loop = 0; loop < num_face_verts; loop++) {
- CCGEdge *ccg_edge = ccgSubSurf_getFaceEdge(ccg_face, loop);
- face_edges[loop] = POINTER_AS_INT(ccgSubSurf_getEdgeEdgeHandle(ccg_edge));
- }
-}
-
-static void conv_ccg_get_edge_verts(const OpenSubdiv_Converter *converter,
- int edge,
- int *edge_verts)
-{
- CCGSubSurf *ss = converter->user_data;
- CCGEdge *ccg_edge = ccgSubSurf_getEdge(ss, POINTER_FROM_INT(edge));
- CCGVert *ccg_vert0 = ccgSubSurf_getEdgeVert0(ccg_edge);
- CCGVert *ccg_vert1 = ccgSubSurf_getEdgeVert1(ccg_edge);
- edge_verts[0] = POINTER_AS_INT(ccgSubSurf_getVertVertHandle(ccg_vert0));
- edge_verts[1] = POINTER_AS_INT(ccgSubSurf_getVertVertHandle(ccg_vert1));
-}
-
-static int conv_ccg_get_num_edge_faces(const OpenSubdiv_Converter *converter, int edge)
-{
- CCGSubSurf *ss = converter->user_data;
- CCGEdge *ccg_edge = ccgSubSurf_getEdge(ss, POINTER_FROM_INT(edge));
- return ccgSubSurf_getEdgeNumFaces(ccg_edge);
-}
-
-static void conv_ccg_get_edge_faces(const OpenSubdiv_Converter *converter,
- int edge,
- int *edge_faces)
-{
- CCGSubSurf *ss = converter->user_data;
- CCGEdge *ccg_edge = ccgSubSurf_getEdge(ss, POINTER_FROM_INT(edge));
- int num_edge_faces = ccgSubSurf_getEdgeNumFaces(ccg_edge);
- int face;
- for (face = 0; face < num_edge_faces; face++) {
- CCGFace *ccg_face = ccgSubSurf_getEdgeFace(ccg_edge, face);
- edge_faces[face] = POINTER_AS_INT(ccgSubSurf_getFaceFaceHandle(ccg_face));
- }
-}
-
-static float conv_ccg_get_edge_sharpness(const OpenSubdiv_Converter *converter, int edge)
-{
- CCGSubSurf *ss = converter->user_data;
- CCGEdge *ccg_edge = ccgSubSurf_getEdge(ss, POINTER_FROM_INT(edge));
- /* TODO(sergey): Multiply by subdivision level once CPU evaluator
- * is switched to uniform subdivision type.
- */
- return ccg_edge->crease;
-}
-
-static int conv_ccg_get_num_vert_edges(const OpenSubdiv_Converter *converter, int vert)
-{
- CCGSubSurf *ss = converter->user_data;
- CCGVert *ccg_vert = ccgSubSurf_getVert(ss, POINTER_FROM_INT(vert));
- return ccgSubSurf_getVertNumEdges(ccg_vert);
-}
-
-static void conv_ccg_get_vert_edges(const OpenSubdiv_Converter *converter,
- int vert,
- int *vert_edges)
-{
- CCGSubSurf *ss = converter->user_data;
- CCGVert *ccg_vert = ccgSubSurf_getVert(ss, POINTER_FROM_INT(vert));
- int num_vert_edges = ccgSubSurf_getVertNumEdges(ccg_vert);
- int edge;
- for (edge = 0; edge < num_vert_edges; edge++) {
- CCGEdge *ccg_edge = ccgSubSurf_getVertEdge(ccg_vert, edge);
- vert_edges[edge] = POINTER_AS_INT(ccgSubSurf_getEdgeEdgeHandle(ccg_edge));
- }
-}
-
-static int conv_ccg_get_num_vert_faces(const OpenSubdiv_Converter *converter, int vert)
-{
- CCGSubSurf *ss = converter->user_data;
- CCGVert *ccg_vert = ccgSubSurf_getVert(ss, POINTER_FROM_INT(vert));
- return ccgSubSurf_getVertNumFaces(ccg_vert);
-}
-
-static void conv_ccg_get_vert_faces(const OpenSubdiv_Converter *converter,
- int vert,
- int *vert_faces)
-{
- CCGSubSurf *ss = converter->user_data;
- CCGVert *ccg_vert = ccgSubSurf_getVert(ss, POINTER_FROM_INT(vert));
- int num_vert_faces = ccgSubSurf_getVertNumFaces(ccg_vert);
- int face;
- for (face = 0; face < num_vert_faces; face++) {
- CCGFace *ccg_face = ccgSubSurf_getVertFace(ccg_vert, face);
- vert_faces[face] = POINTER_AS_INT(ccgSubSurf_getFaceFaceHandle(ccg_face));
- }
-}
-
-static bool conv_ccg_is_infinite_sharp_vertex(const OpenSubdiv_Converter *UNUSED(converter),
- int UNUSED(manifold_vertex_index))
-{
- return false;
-}
-
-static float conv_ccg_get_vertex_sharpness(const OpenSubdiv_Converter *UNUSED(converter),
- int UNUSED(manifold_vertex_index))
-{
- return 0.0f;
-}
-
-static int conv_ccg_get_num_uv_layers(const OpenSubdiv_Converter *UNUSED(converter))
-{
- return 0;
-}
-
-static void conv_ccg_precalc_uv_layer(const OpenSubdiv_Converter *UNUSED(converter),
- int UNUSED(layer))
-{
-}
-
-static void conv_ccg_finish_uv_layer(const OpenSubdiv_Converter *UNUSED(converter))
-{
-}
-
-static int conv_ccg_get_num_uvs(const OpenSubdiv_Converter *UNUSED(converter))
-{
- return 0;
-}
-
-static int conv_ccg_get_face_corner_uv_index(const OpenSubdiv_Converter *UNUSED(converter),
- int UNUSED(face),
- int UNUSED(corner_))
-{
- return 0;
-}
-
-void ccgSubSurf_converter_setup_from_ccg(CCGSubSurf *ss, OpenSubdiv_Converter *converter)
-{
- converter->getSchemeType = conv_ccg_get_bilinear_type;
-
- converter->getVtxBoundaryInterpolation = conv_ccg_get_vtx_boundary_interpolation;
- converter->getFVarLinearInterpolation = conv_ccg_get_fvar_linear_interpolation;
- converter->specifiesFullTopology = conv_ccg_specifies_full_topology;
-
- converter->getNumFaces = conv_ccg_get_num_faces;
- converter->getNumEdges = conv_ccg_get_num_edges;
- converter->getNumVertices = conv_ccg_get_num_verts;
-
- converter->getNumFaceVertices = conv_ccg_get_num_face_verts;
- converter->getFaceVertices = conv_ccg_get_face_verts;
- converter->getFaceEdges = conv_ccg_get_face_edges;
-
- converter->getEdgeVertices = conv_ccg_get_edge_verts;
- converter->getNumEdgeFaces = conv_ccg_get_num_edge_faces;
- converter->getEdgeFaces = conv_ccg_get_edge_faces;
- converter->getEdgeSharpness = conv_ccg_get_edge_sharpness;
-
- converter->getNumVertexEdges = conv_ccg_get_num_vert_edges;
- converter->getVertexEdges = conv_ccg_get_vert_edges;
- converter->getNumVertexFaces = conv_ccg_get_num_vert_faces;
- converter->getVertexFaces = conv_ccg_get_vert_faces;
- converter->isInfiniteSharpVertex = conv_ccg_is_infinite_sharp_vertex;
- converter->getVertexSharpness = conv_ccg_get_vertex_sharpness;
-
- converter->getNumUVLayers = conv_ccg_get_num_uv_layers;
- converter->precalcUVLayer = conv_ccg_precalc_uv_layer;
- converter->finishUVLayer = conv_ccg_finish_uv_layer;
- converter->getNumUVCoordinates = conv_ccg_get_num_uvs;
- converter->getFaceCornerUVIndex = conv_ccg_get_face_corner_uv_index;
-
- converter->freeUserData = NULL;
- converter->user_data = ss;
-}
-
-void ccgSubSurf_converter_free(struct OpenSubdiv_Converter *converter)
-{
- if (converter->freeUserData) {
- converter->freeUserData(converter);
- }
-}
-
-#endif /* WITH_OPENSUBDIV */
diff --git a/source/blender/blenkernel/intern/DerivedMesh.c b/source/blender/blenkernel/intern/DerivedMesh.c
index baef2b2290e..8f820a873fe 100644
--- a/source/blender/blenkernel/intern/DerivedMesh.c
+++ b/source/blender/blenkernel/intern/DerivedMesh.c
@@ -90,6 +90,8 @@
static ThreadRWMutex loops_cache_lock = PTHREAD_RWLOCK_INITIALIZER;
static void mesh_init_origspace(Mesh *mesh);
+static void editbmesh_calc_modifier_final_normals(Mesh *mesh_final,
+ const CustomData_MeshMasks *final_datamask);
/* -------------------------------------------------------------------- */
@@ -698,7 +700,8 @@ static float (*get_orco_coords(Object *ob, BMEditMesh *em, int layer, int *free)
/* apply shape key for cloth, this should really be solved
* by a more flexible customdata system, but not simple */
if (!em) {
- ClothModifierData *clmd = (ClothModifierData *)modifiers_findByType(ob, eModifierType_Cloth);
+ ClothModifierData *clmd = (ClothModifierData *)BKE_modifiers_findby_type(
+ ob, eModifierType_Cloth);
KeyBlock *kb = BKE_keyblock_from_key(BKE_key_from_object(ob),
clmd->sim_parms->shapekey_rest);
@@ -860,6 +863,16 @@ static void mesh_calc_finalize(const Mesh *mesh_input, Mesh *mesh_eval)
mesh_eval->edit_mesh = mesh_input->edit_mesh;
}
+void BKE_mesh_wrapper_deferred_finalize(Mesh *me_eval,
+ const CustomData_MeshMasks *cd_mask_finalize)
+{
+ if (me_eval->runtime.wrapper_type_finalize & (1 << ME_WRAPPER_TYPE_BMESH)) {
+ editbmesh_calc_modifier_final_normals(me_eval, cd_mask_finalize);
+ me_eval->runtime.wrapper_type_finalize &= ~(1 << ME_WRAPPER_TYPE_BMESH);
+ }
+ BLI_assert(me_eval->runtime.wrapper_type_finalize == 0);
+}
+
static void mesh_calc_modifiers(struct Depsgraph *depsgraph,
Scene *scene,
Object *ob,
@@ -901,21 +914,21 @@ static void mesh_calc_modifiers(struct Depsgraph *depsgraph,
/* Sculpt can skip certain modifiers. */
MultiresModifierData *mmd = get_multires_modifier(scene, ob, 0);
- const bool has_multires = (mmd && BKE_multires_sculpt_level_get(mmd) != 0);
+ const bool has_multires = (mmd && mmd->sculptlvl != 0);
bool multires_applied = false;
const bool sculpt_mode = ob->mode & OB_MODE_SCULPT && ob->sculpt && !use_render;
const bool sculpt_dyntopo = (sculpt_mode && ob->sculpt->bm) && !use_render;
/* Modifier evaluation contexts for different types of modifiers. */
- ModifierApplyFlag app_render = use_render ? MOD_APPLY_RENDER : 0;
- ModifierApplyFlag app_cache = use_cache ? MOD_APPLY_USECACHE : 0;
- const ModifierEvalContext mectx = {depsgraph, ob, app_render | app_cache};
- const ModifierEvalContext mectx_orco = {depsgraph, ob, app_render | MOD_APPLY_ORCO};
+ ModifierApplyFlag apply_render = use_render ? MOD_APPLY_RENDER : 0;
+ ModifierApplyFlag apply_cache = use_cache ? MOD_APPLY_USECACHE : 0;
+ const ModifierEvalContext mectx = {depsgraph, ob, apply_render | apply_cache};
+ const ModifierEvalContext mectx_orco = {depsgraph, ob, apply_render | MOD_APPLY_ORCO};
/* Get effective list of modifiers to execute. Some effects like shape keys
* are added as virtual modifiers before the user created modifiers. */
VirtualModifierData virtualModifierData;
- ModifierData *firstmd = modifiers_getVirtualModifierList(ob, &virtualModifierData);
+ ModifierData *firstmd = BKE_modifiers_get_virtual_modifierlist(ob, &virtualModifierData);
ModifierData *md = firstmd;
/* Preview colors by modifiers such as dynamic paint, to show the results
@@ -929,7 +942,7 @@ static void mesh_calc_modifiers(struct Depsgraph *depsgraph,
/* XXX Currently, DPaint modifier just ignores this.
* Needs a stupid hack...
* The whole "modifier preview" thing has to be (re?)designed, anyway! */
- previewmd = modifiers_getLastPreview(scene, md, required_mode);
+ previewmd = BKE_modifier_get_last_preview(scene, md, required_mode);
}
/* Compute accumulated datamasks needed by each modifier. It helps to do
@@ -937,21 +950,21 @@ static void mesh_calc_modifiers(struct Depsgraph *depsgraph,
* an armature modifier, but not through a following subsurf modifier where
* subdividing them is expensive. */
CustomData_MeshMasks final_datamask = *dataMask;
- CDMaskLink *datamasks = modifiers_calcDataMasks(
+ CDMaskLink *datamasks = BKE_modifier_calc_data_masks(
scene, ob, md, &final_datamask, required_mode, previewmd, &previewmask);
CDMaskLink *md_datamask = datamasks;
/* XXX Always copying POLYINDEX, else tessellated data are no more valid! */
CustomData_MeshMasks append_mask = CD_MASK_BAREMESH_ORIGINDEX;
/* Clear errors before evaluation. */
- modifiers_clearErrors(ob);
+ BKE_modifiers_clear_errors(ob);
/* Apply all leading deform modifiers. */
if (useDeform) {
for (; md; md = md->next, md_datamask = md_datamask->next) {
- const ModifierTypeInfo *mti = modifierType_getInfo(md->type);
+ const ModifierTypeInfo *mti = BKE_modifier_get_info(md->type);
- if (!modifier_isEnabled(scene, md, required_mode)) {
+ if (!BKE_modifier_is_enabled(scene, md, required_mode)) {
continue;
}
@@ -971,7 +984,7 @@ static void mesh_calc_modifiers(struct Depsgraph *depsgraph,
BKE_mesh_vert_coords_apply(mesh_final, deformed_verts);
}
- modwrap_deformVerts(md, &mectx, mesh_final, deformed_verts, num_deformed_verts);
+ BKE_modifier_deform_verts(md, &mectx, mesh_final, deformed_verts, num_deformed_verts);
isPrevDeform = true;
}
@@ -1001,9 +1014,9 @@ static void mesh_calc_modifiers(struct Depsgraph *depsgraph,
/* Apply all remaining constructive and deforming modifiers. */
bool have_non_onlydeform_modifiers_appled = false;
for (; md; md = md->next, md_datamask = md_datamask->next) {
- const ModifierTypeInfo *mti = modifierType_getInfo(md->type);
+ const ModifierTypeInfo *mti = BKE_modifier_get_info(md->type);
- if (!modifier_isEnabled(scene, md, required_mode)) {
+ if (!BKE_modifier_is_enabled(scene, md, required_mode)) {
continue;
}
@@ -1013,15 +1026,14 @@ static void mesh_calc_modifiers(struct Depsgraph *depsgraph,
if ((mti->flags & eModifierTypeFlag_RequiresOriginalData) &&
have_non_onlydeform_modifiers_appled) {
- modifier_setError(md, "Modifier requires original data, bad stack position");
+ BKE_modifier_set_error(md, "Modifier requires original data, bad stack position");
continue;
}
if (sculpt_mode && (!has_multires || multires_applied || sculpt_dyntopo)) {
bool unsupported = false;
- if (md->type == eModifierType_Multires &&
- BKE_multires_sculpt_level_get((MultiresModifierData *)md) == 0) {
+ if (md->type == eModifierType_Multires && ((MultiresModifierData *)md)->sculptlvl == 0) {
/* If multires is on level 0 skip it silently without warning message. */
if (!sculpt_dyntopo) {
continue;
@@ -1040,19 +1052,19 @@ static void mesh_calc_modifiers(struct Depsgraph *depsgraph,
if (unsupported) {
if (sculpt_dyntopo) {
- modifier_setError(md, "Not supported in dyntopo");
+ BKE_modifier_set_error(md, "Not supported in dyntopo");
}
else {
- modifier_setError(md, "Not supported in sculpt mode");
+ BKE_modifier_set_error(md, "Not supported in sculpt mode");
}
continue;
}
else {
- modifier_setError(md, "Sculpt: Hide, Mask and optimized display disabled");
+ BKE_modifier_set_error(md, "Sculpt: Hide, Mask and optimized display disabled");
}
}
- if (need_mapping && !modifier_supportsMapping(md)) {
+ if (need_mapping && !BKE_modifier_supports_mapping(md)) {
continue;
}
@@ -1094,7 +1106,7 @@ static void mesh_calc_modifiers(struct Depsgraph *depsgraph,
}
BKE_mesh_vert_coords_apply(mesh_final, deformed_verts);
}
- modwrap_deformVerts(md, &mectx, mesh_final, deformed_verts, num_deformed_verts);
+ BKE_modifier_deform_verts(md, &mectx, mesh_final, deformed_verts, num_deformed_verts);
}
else {
have_non_onlydeform_modifiers_appled = true;
@@ -1176,7 +1188,7 @@ static void mesh_calc_modifiers(struct Depsgraph *depsgraph,
}
}
- Mesh *mesh_next = modwrap_applyModifier(md, &mectx, mesh_final);
+ Mesh *mesh_next = BKE_modifier_modify_mesh(md, &mectx, mesh_final);
ASSERT_IS_VALID_MESH(mesh_next);
if (mesh_next) {
@@ -1212,7 +1224,7 @@ static void mesh_calc_modifiers(struct Depsgraph *depsgraph,
CustomData_MeshMasks_update(&temp_cddata_masks, &nextmask);
mesh_set_only_copy(mesh_orco, &temp_cddata_masks);
- mesh_next = modwrap_applyModifier(md, &mectx_orco, mesh_orco);
+ mesh_next = BKE_modifier_modify_mesh(md, &mectx_orco, mesh_orco);
ASSERT_IS_VALID_MESH(mesh_next);
if (mesh_next) {
@@ -1238,7 +1250,7 @@ static void mesh_calc_modifiers(struct Depsgraph *depsgraph,
nextmask.pmask |= CD_MASK_ORIGINDEX;
mesh_set_only_copy(mesh_orco_cloth, &nextmask);
- mesh_next = modwrap_applyModifier(md, &mectx_orco, mesh_orco_cloth);
+ mesh_next = BKE_modifier_modify_mesh(md, &mectx_orco, mesh_orco_cloth);
ASSERT_IS_VALID_MESH(mesh_next);
if (mesh_next) {
@@ -1276,7 +1288,7 @@ static void mesh_calc_modifiers(struct Depsgraph *depsgraph,
BLI_linklist_free((LinkNode *)datamasks, NULL);
for (md = firstmd; md; md = md->next) {
- modifier_freeTemporaryData(md);
+ BKE_modifier_free_temporary_data(md);
}
/* Yay, we are done. If we have a Mesh and deformed vertices,
@@ -1376,26 +1388,31 @@ float (*editbmesh_vert_coords_alloc(BMEditMesh *em, int *r_vert_len))[3]
bool editbmesh_modifier_is_enabled(Scene *scene, ModifierData *md, bool has_prev_mesh)
{
- const ModifierTypeInfo *mti = modifierType_getInfo(md->type);
+ const ModifierTypeInfo *mti = BKE_modifier_get_info(md->type);
const int required_mode = eModifierMode_Realtime | eModifierMode_Editmode;
- if (!modifier_isEnabled(scene, md, required_mode)) {
+ if (!BKE_modifier_is_enabled(scene, md, required_mode)) {
return false;
}
if ((mti->flags & eModifierTypeFlag_RequiresOriginalData) && has_prev_mesh) {
- modifier_setError(md, "Modifier requires original data, bad stack position");
+ BKE_modifier_set_error(md, "Modifier requires original data, bad stack position");
return false;
}
return true;
}
-static void editbmesh_calc_modifier_final_normals(const Mesh *mesh_input,
- const CustomData_MeshMasks *final_datamask,
- Mesh *mesh_final)
+static void editbmesh_calc_modifier_final_normals(Mesh *mesh_final,
+ const CustomData_MeshMasks *final_datamask)
{
- const bool do_loop_normals = ((mesh_input->flag & ME_AUTOSMOOTH) != 0 ||
+ if (mesh_final->runtime.wrapper_type != ME_WRAPPER_TYPE_MDATA) {
+ /* Generated at draw time. */
+ mesh_final->runtime.wrapper_type_finalize = (1 << mesh_final->runtime.wrapper_type);
+ return;
+ }
+
+ const bool do_loop_normals = ((mesh_final->flag & ME_AUTOSMOOTH) != 0 ||
(final_datamask->lmask & CD_MASK_NORMAL) != 0);
/* Some modifiers may need this info from their target (other) object,
* simpler to generate it here as well. */
@@ -1486,30 +1503,30 @@ static void editbmesh_calc_modifiers(struct Depsgraph *depsgraph,
/* Get effective list of modifiers to execute. Some effects like shape keys
* are added as virtual modifiers before the user created modifiers. */
VirtualModifierData virtualModifierData;
- ModifierData *md = modifiers_getVirtualModifierList(ob, &virtualModifierData);
+ ModifierData *md = BKE_modifiers_get_virtual_modifierlist(ob, &virtualModifierData);
/* Compute accumulated datamasks needed by each modifier. It helps to do
* this fine grained so that for example vertex groups are preserved up to
* an armature modifier, but not through a following subsurf modifier where
* subdividing them is expensive. */
CustomData_MeshMasks final_datamask = *dataMask;
- CDMaskLink *datamasks = modifiers_calcDataMasks(
+ CDMaskLink *datamasks = BKE_modifier_calc_data_masks(
scene, ob, md, &final_datamask, required_mode, NULL, NULL);
CDMaskLink *md_datamask = datamasks;
CustomData_MeshMasks append_mask = CD_MASK_BAREMESH;
/* Evaluate modifiers up to certain index to get the mesh cage. */
- int cageIndex = modifiers_getCageIndex(scene, ob, NULL, 1);
+ int cageIndex = BKE_modifiers_get_cage_index(scene, ob, NULL, 1);
if (r_cage && cageIndex == -1) {
- mesh_cage = BKE_mesh_from_editmesh_with_coords_thin_wrap(
+ mesh_cage = BKE_mesh_wrapper_from_editmesh_with_coords(
em_input, &final_datamask, NULL, mesh_input);
}
/* Clear errors before evaluation. */
- modifiers_clearErrors(ob);
+ BKE_modifiers_clear_errors(ob);
for (int i = 0; md; i++, md = md->next, md_datamask = md_datamask->next) {
- const ModifierTypeInfo *mti = modifierType_getInfo(md->type);
+ const ModifierTypeInfo *mti = BKE_modifier_get_info(md->type);
if (!editbmesh_modifier_is_enabled(scene, md, mesh_final != NULL)) {
continue;
@@ -1550,11 +1567,11 @@ static void editbmesh_calc_modifiers(struct Depsgraph *depsgraph,
}
if (mti->deformVertsEM) {
- modwrap_deformVertsEM(
+ BKE_modifier_deform_vertsEM(
md, &mectx, em_input, mesh_final, deformed_verts, num_deformed_verts);
}
else {
- modwrap_deformVerts(md, &mectx, mesh_final, deformed_verts, num_deformed_verts);
+ BKE_modifier_deform_verts(md, &mectx, mesh_final, deformed_verts, num_deformed_verts);
}
}
else {
@@ -1574,12 +1591,9 @@ static void editbmesh_calc_modifiers(struct Depsgraph *depsgraph,
}
}
else {
- mesh_final = BKE_mesh_from_bmesh_for_eval_nomain(em_input->bm, NULL, mesh_input);
- ASSERT_IS_VALID_MESH(mesh_final);
-
- if (deformed_verts) {
- BKE_mesh_vert_coords_apply(mesh_final, deformed_verts);
- }
+ mesh_final = BKE_mesh_wrapper_from_editmesh_with_coords(
+ em_input, NULL, deformed_verts, mesh_input);
+ deformed_verts = NULL;
}
/* create an orco derivedmesh in parallel */
@@ -1595,7 +1609,7 @@ static void editbmesh_calc_modifiers(struct Depsgraph *depsgraph,
mask.pmask |= CD_MASK_ORIGINDEX;
mesh_set_only_copy(mesh_orco, &mask);
- Mesh *mesh_next = modwrap_applyModifier(md, &mectx_orco, mesh_orco);
+ Mesh *mesh_next = BKE_modifier_modify_mesh(md, &mectx_orco, mesh_orco);
ASSERT_IS_VALID_MESH(mesh_next);
if (mesh_next) {
@@ -1626,7 +1640,7 @@ static void editbmesh_calc_modifiers(struct Depsgraph *depsgraph,
}
}
- Mesh *mesh_next = modwrap_applyModifier(md, &mectx, mesh_final);
+ Mesh *mesh_next = BKE_modifier_modify_mesh(md, &mectx, mesh_final);
ASSERT_IS_VALID_MESH(mesh_next);
if (mesh_next) {
@@ -1657,7 +1671,7 @@ static void editbmesh_calc_modifiers(struct Depsgraph *depsgraph,
BKE_mesh_runtime_ensure_edit_data(me_orig);
me_orig->runtime.edit_data->vertexCos = MEM_dupallocN(deformed_verts);
}
- mesh_cage = BKE_mesh_from_editmesh_with_coords_thin_wrap(
+ mesh_cage = BKE_mesh_wrapper_from_editmesh_with_coords(
em_input,
&final_datamask,
deformed_verts ? MEM_dupallocN(deformed_verts) : NULL,
@@ -1689,7 +1703,7 @@ static void editbmesh_calc_modifiers(struct Depsgraph *depsgraph,
}
else {
/* this is just a copy of the editmesh, no need to calc normals */
- mesh_final = BKE_mesh_from_editmesh_with_coords_thin_wrap(
+ mesh_final = BKE_mesh_wrapper_from_editmesh_with_coords(
em_input, &final_datamask, deformed_verts, mesh_input);
deformed_verts = NULL;
}
@@ -1700,6 +1714,9 @@ static void editbmesh_calc_modifiers(struct Depsgraph *depsgraph,
/* Add orco coordinates to final and deformed mesh if requested. */
if (final_datamask.vmask & CD_MASK_ORCO) {
+ /* FIXME(Campbell): avoid the need to convert to mesh data just to add an orco layer. */
+ BKE_mesh_wrapper_ensure_mdata(mesh_final);
+
add_orco_mesh(ob, em_input, mesh_final, mesh_orco, CD_ORCO);
}
@@ -1707,10 +1724,15 @@ static void editbmesh_calc_modifiers(struct Depsgraph *depsgraph,
BKE_id_free(NULL, mesh_orco);
}
+ /* Ensure normals calculation below is correct. */
+ BLI_assert((mesh_input->flag & ME_AUTOSMOOTH) == (mesh_final->flag & ME_AUTOSMOOTH));
+ BLI_assert(mesh_input->smoothresh == mesh_final->smoothresh);
+ BLI_assert(mesh_input->smoothresh == mesh_cage->smoothresh);
+
/* Compute normals. */
- editbmesh_calc_modifier_final_normals(mesh_input, &final_datamask, mesh_final);
+ editbmesh_calc_modifier_final_normals(mesh_final, &final_datamask);
if (mesh_cage && (mesh_cage != mesh_final)) {
- editbmesh_calc_modifier_final_normals(mesh_input, &final_datamask, mesh_cage);
+ editbmesh_calc_modifier_final_normals(mesh_cage, &final_datamask);
}
/* Return final mesh. */
@@ -1798,9 +1820,7 @@ static void mesh_build_data(struct Depsgraph *depsgraph,
}
}
- if (mesh_eval != NULL) {
- mesh_runtime_check_normals_valid(mesh_eval);
- }
+ mesh_runtime_check_normals_valid(mesh_eval);
mesh_build_extra_data(depsgraph, ob, mesh_eval);
}
diff --git a/source/blender/blenkernel/intern/action.c b/source/blender/blenkernel/intern/action.c
index c332939e906..c776f0d077d 100644
--- a/source/blender/blenkernel/intern/action.c
+++ b/source/blender/blenkernel/intern/action.c
@@ -43,7 +43,7 @@
#include "BLT_translation.h"
#include "BKE_action.h"
-#include "BKE_anim.h"
+#include "BKE_anim_visualization.h"
#include "BKE_animsys.h"
#include "BKE_armature.h"
#include "BKE_constraint.h"
@@ -52,6 +52,7 @@
#include "BKE_idprop.h"
#include "BKE_idtype.h"
#include "BKE_lib_id.h"
+#include "BKE_lib_query.h"
#include "BKE_main.h"
#include "BKE_object.h"
@@ -115,7 +116,7 @@ static void action_copy_data(Main *UNUSED(bmain),
/* XXX TODO pass subdata flag?
* But surprisingly does not seem to be doing any ID refcounting... */
- fcurve_dst = copy_fcurve(fcurve_src);
+ fcurve_dst = BKE_fcurve_copy(fcurve_src);
BLI_addtail(&action_dst->curves, fcurve_dst);
@@ -145,7 +146,7 @@ static void action_free_data(struct ID *id)
/* No animdata here. */
/* Free F-Curves. */
- free_fcurves(&action->curves);
+ BKE_fcurves_free(&action->curves);
/* Free groups. */
BLI_freelistN(&action->groups);
@@ -154,6 +155,19 @@ static void action_free_data(struct ID *id)
BLI_freelistN(&action->markers);
}
+static void action_foreach_id(ID *id, LibraryForeachIDData *data)
+{
+ bAction *act = (bAction *)id;
+
+ LISTBASE_FOREACH (FCurve *, fcu, &act->curves) {
+ BKE_fcurve_foreach_id(fcu, data);
+ }
+
+ LISTBASE_FOREACH (TimeMarker *, marker, &act->markers) {
+ BKE_LIB_FOREACHID_PROCESS(data, marker->camera, IDWALK_CB_NOP);
+ }
+}
+
IDTypeInfo IDType_ID_AC = {
.id_code = ID_AC,
.id_filter = FILTER_ID_AC,
@@ -168,6 +182,7 @@ IDTypeInfo IDType_ID_AC = {
.copy_data = action_copy_data,
.free_data = action_free_data,
.make_local = NULL,
+ .foreach_id = action_foreach_id,
};
/* ***************** Library data level operations on action ************** */
@@ -925,6 +940,7 @@ void BKE_pose_channel_free_ex(bPoseChannel *pchan, bool do_id_user)
if (pchan->prop) {
IDP_FreeProperty(pchan->prop);
+ pchan->prop = NULL;
}
/* Cached data, for new draw manager rendering code. */
@@ -1294,7 +1310,7 @@ void calc_action_range(const bAction *act, float *start, float *end, short incl_
* single-keyframe curves will increase the overall length by
* a phantom frame (T50354)
*/
- calc_fcurve_range(fcu, &nmin, &nmax, false, false);
+ BKE_fcurve_calc_range(fcu, &nmin, &nmax, false, false);
/* compare to the running tally */
min = min_ff(min, nmin);
@@ -1664,6 +1680,6 @@ void what_does_obaction(
adt.action = act;
/* execute effects of Action on to workob (or it's PoseChannels) */
- BKE_animsys_evaluate_animdata(NULL, &workob->id, &adt, cframe, ADT_RECALC_ANIM, false);
+ BKE_animsys_evaluate_animdata(&workob->id, &adt, cframe, ADT_RECALC_ANIM, false);
}
}
diff --git a/source/blender/blenkernel/intern/anim_data.c b/source/blender/blenkernel/intern/anim_data.c
new file mode 100644
index 00000000000..9ab4e5c028d
--- /dev/null
+++ b/source/blender/blenkernel/intern/anim_data.c
@@ -0,0 +1,1462 @@
+/*
+ * 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) 2009 Blender Foundation, Joshua Leung
+ * All rights reserved.
+ */
+
+/** \file
+ * \ingroup bke
+ */
+#include "MEM_guardedalloc.h"
+
+#include <string.h>
+
+#include "BKE_action.h"
+#include "BKE_anim_data.h"
+#include "BKE_animsys.h"
+#include "BKE_context.h"
+#include "BKE_fcurve.h"
+#include "BKE_fcurve_driver.h"
+#include "BKE_global.h"
+#include "BKE_lib_id.h"
+#include "BKE_lib_query.h"
+#include "BKE_main.h"
+#include "BKE_nla.h"
+#include "BKE_node.h"
+#include "BKE_report.h"
+
+#include "DNA_ID.h"
+#include "DNA_anim_types.h"
+#include "DNA_light_types.h"
+#include "DNA_node_types.h"
+#include "DNA_space_types.h"
+#include "DNA_windowmanager_types.h"
+#include "DNA_world_types.h"
+
+#include "BLI_alloca.h"
+#include "BLI_dynstr.h"
+#include "BLI_listbase.h"
+#include "BLI_string.h"
+#include "BLI_utildefines.h"
+
+#include "DEG_depsgraph.h"
+
+#include "RNA_access.h"
+
+#include "CLG_log.h"
+
+static CLG_LogRef LOG = {"bke.anim_sys"};
+
+/* ***************************************** */
+/* AnimData API */
+
+/* Getter/Setter -------------------------------------------- */
+
+/* Check if ID can have AnimData */
+bool id_type_can_have_animdata(const short id_type)
+{
+ /* Only some ID-blocks have this info for now */
+ /* TODO: finish adding this for the other blocktypes */
+ switch (id_type) {
+ /* has AnimData */
+ case ID_OB:
+ case ID_ME:
+ case ID_MB:
+ case ID_CU:
+ case ID_AR:
+ case ID_LT:
+ case ID_KE:
+ case ID_PA:
+ case ID_MA:
+ case ID_TE:
+ case ID_NT:
+ case ID_LA:
+ case ID_CA:
+ case ID_WO:
+ case ID_LS:
+ case ID_LP:
+ case ID_SPK:
+ case ID_SCE:
+ case ID_MC:
+ case ID_MSK:
+ case ID_GD:
+ case ID_CF:
+ case ID_HA:
+ case ID_PT:
+ case ID_VO:
+ case ID_SIM:
+ return true;
+
+ /* no AnimData */
+ default:
+ return false;
+ }
+}
+
+bool id_can_have_animdata(const ID *id)
+{
+ /* sanity check */
+ if (id == NULL) {
+ return false;
+ }
+
+ return id_type_can_have_animdata(GS(id->name));
+}
+
+/* Get AnimData from the given ID-block. In order for this to work, we assume that
+ * the AnimData pointer is stored immediately after the given ID-block in the struct,
+ * as per IdAdtTemplate.
+ */
+AnimData *BKE_animdata_from_id(ID *id)
+{
+ /* only some ID-blocks have this info for now, so we cast the
+ * types that do to be of type IdAdtTemplate, and extract the
+ * AnimData that way
+ */
+ if (id_can_have_animdata(id)) {
+ IdAdtTemplate *iat = (IdAdtTemplate *)id;
+ return iat->adt;
+ }
+ else {
+ return NULL;
+ }
+}
+
+/* Add AnimData to the given ID-block. In order for this to work, we assume that
+ * the AnimData pointer is stored immediately after the given ID-block in the struct,
+ * as per IdAdtTemplate. Also note that
+ */
+AnimData *BKE_animdata_add_id(ID *id)
+{
+ /* Only some ID-blocks have this info for now, so we cast the
+ * types that do to be of type IdAdtTemplate, and add the AnimData
+ * to it using the template
+ */
+ if (id_can_have_animdata(id)) {
+ IdAdtTemplate *iat = (IdAdtTemplate *)id;
+
+ /* check if there's already AnimData, in which case, don't add */
+ if (iat->adt == NULL) {
+ AnimData *adt;
+
+ /* add animdata */
+ adt = iat->adt = MEM_callocN(sizeof(AnimData), "AnimData");
+
+ /* set default settings */
+ adt->act_influence = 1.0f;
+ }
+
+ return iat->adt;
+ }
+ else {
+ return NULL;
+ }
+}
+
+/* Action Setter --------------------------------------- */
+
+/**
+ * Called when user tries to change the active action of an AnimData block
+ * (via RNA, Outliner, etc.)
+ */
+bool BKE_animdata_set_action(ReportList *reports, ID *id, bAction *act)
+{
+ AnimData *adt = BKE_animdata_from_id(id);
+ bool ok = false;
+
+ /* animdata validity check */
+ if (adt == NULL) {
+ BKE_report(reports, RPT_WARNING, "No AnimData to set action on");
+ return ok;
+ }
+
+ /* active action is only editable when it is not a tweaking strip
+ * see rna_AnimData_action_editable() in rna_animation.c
+ */
+ if ((adt->flag & ADT_NLA_EDIT_ON) || (adt->actstrip) || (adt->tmpact)) {
+ /* cannot remove, otherwise things turn to custard */
+ BKE_report(reports, RPT_ERROR, "Cannot change action, as it is still being edited in NLA");
+ return ok;
+ }
+
+ /* manage usercount for current action */
+ if (adt->action) {
+ id_us_min((ID *)adt->action);
+ }
+
+ /* assume that AnimData's action can in fact be edited... */
+ if (act) {
+ /* action must have same type as owner */
+ if (ELEM(act->idroot, 0, GS(id->name))) {
+ /* can set */
+ adt->action = act;
+ id_us_plus((ID *)adt->action);
+ ok = true;
+ }
+ else {
+ /* cannot set */
+ BKE_reportf(
+ reports,
+ RPT_ERROR,
+ "Could not set action '%s' onto ID '%s', as it does not have suitably rooted paths "
+ "for this purpose",
+ act->id.name + 2,
+ id->name);
+ /* ok = false; */
+ }
+ }
+ else {
+ /* just clearing the action... */
+ adt->action = NULL;
+ ok = true;
+ }
+
+ return ok;
+}
+
+/* Freeing -------------------------------------------- */
+
+/* Free AnimData used by the nominated ID-block, and clear ID-block's AnimData pointer */
+void BKE_animdata_free(ID *id, const bool do_id_user)
+{
+ /* Only some ID-blocks have this info for now, so we cast the
+ * types that do to be of type IdAdtTemplate
+ */
+ if (id_can_have_animdata(id)) {
+ IdAdtTemplate *iat = (IdAdtTemplate *)id;
+ AnimData *adt = iat->adt;
+
+ /* check if there's any AnimData to start with */
+ if (adt) {
+ if (do_id_user) {
+ /* unlink action (don't free, as it's in its own list) */
+ if (adt->action) {
+ id_us_min(&adt->action->id);
+ }
+ /* same goes for the temporarily displaced action */
+ if (adt->tmpact) {
+ id_us_min(&adt->tmpact->id);
+ }
+ }
+
+ /* free nla data */
+ BKE_nla_tracks_free(&adt->nla_tracks, do_id_user);
+
+ /* free drivers - stored as a list of F-Curves */
+ BKE_fcurves_free(&adt->drivers);
+
+ /* free driver array cache */
+ MEM_SAFE_FREE(adt->driver_array);
+
+ /* free overrides */
+ /* TODO... */
+
+ /* free animdata now */
+ MEM_freeN(adt);
+ iat->adt = NULL;
+ }
+ }
+}
+
+bool BKE_animdata_id_is_animated(const struct ID *id)
+{
+ if (id == NULL) {
+ return false;
+ }
+
+ const AnimData *adt = BKE_animdata_from_id((ID *)id);
+ if (adt == NULL) {
+ return false;
+ }
+
+ if (adt->action != NULL && !BLI_listbase_is_empty(&adt->action->curves)) {
+ return true;
+ }
+
+ return !BLI_listbase_is_empty(&adt->drivers) || !BLI_listbase_is_empty(&adt->nla_tracks) ||
+ !BLI_listbase_is_empty(&adt->overrides);
+}
+
+/** Callback used by lib_query to walk over all ID usages (mimics `foreach_id` callback of
+ * `IDTypeInfo` structure). */
+void BKE_animdata_foreach_id(AnimData *adt, LibraryForeachIDData *data)
+{
+ LISTBASE_FOREACH (FCurve *, fcu, &adt->drivers) {
+ BKE_fcurve_foreach_id(fcu, data);
+ }
+
+ BKE_LIB_FOREACHID_PROCESS(data, adt->action, IDWALK_CB_USER);
+ BKE_LIB_FOREACHID_PROCESS(data, adt->tmpact, IDWALK_CB_USER);
+
+ LISTBASE_FOREACH (NlaTrack *, nla_track, &adt->nla_tracks) {
+ LISTBASE_FOREACH (NlaStrip *, nla_strip, &nla_track->strips) {
+ BKE_nla_strip_foreach_id(nla_strip, data);
+ }
+ }
+}
+
+/* Copying -------------------------------------------- */
+
+/**
+ * Make a copy of the given AnimData - to be used when copying data-blocks.
+ * \param flag: Control ID pointers management,
+ * see LIB_ID_CREATE_.../LIB_ID_COPY_... flags in BKE_lib_id.h
+ * \return The copied animdata.
+ */
+AnimData *BKE_animdata_copy(Main *bmain, AnimData *adt, const int flag)
+{
+ AnimData *dadt;
+
+ const bool do_action = (flag & LIB_ID_COPY_ACTIONS) != 0 && (flag & LIB_ID_CREATE_NO_MAIN) == 0;
+ const bool do_id_user = (flag & LIB_ID_CREATE_NO_USER_REFCOUNT) == 0;
+
+ /* sanity check before duplicating struct */
+ if (adt == NULL) {
+ return NULL;
+ }
+ dadt = MEM_dupallocN(adt);
+
+ /* make a copy of action - at worst, user has to delete copies... */
+ if (do_action) {
+ BLI_assert(bmain != NULL);
+ BLI_assert(dadt->action == NULL || dadt->action != dadt->tmpact);
+ BKE_id_copy_ex(bmain, (ID *)dadt->action, (ID **)&dadt->action, flag);
+ BKE_id_copy_ex(bmain, (ID *)dadt->tmpact, (ID **)&dadt->tmpact, flag);
+ }
+ else if (do_id_user) {
+ id_us_plus((ID *)dadt->action);
+ id_us_plus((ID *)dadt->tmpact);
+ }
+
+ /* duplicate NLA data */
+ BKE_nla_tracks_copy(bmain, &dadt->nla_tracks, &adt->nla_tracks, flag);
+
+ /* duplicate drivers (F-Curves) */
+ BKE_fcurves_copy(&dadt->drivers, &adt->drivers);
+ dadt->driver_array = NULL;
+
+ /* don't copy overrides */
+ BLI_listbase_clear(&dadt->overrides);
+
+ /* return */
+ return dadt;
+}
+
+/**
+ * \param flag: Control ID pointers management,
+ * see LIB_ID_CREATE_.../LIB_ID_COPY_... flags in BKE_lib_id.h
+ * \return true is successfully copied.
+ */
+bool BKE_animdata_copy_id(Main *bmain, ID *id_to, ID *id_from, const int flag)
+{
+ AnimData *adt;
+
+ if ((id_to && id_from) && (GS(id_to->name) != GS(id_from->name))) {
+ return false;
+ }
+
+ BKE_animdata_free(id_to, (flag & LIB_ID_CREATE_NO_USER_REFCOUNT) == 0);
+
+ adt = BKE_animdata_from_id(id_from);
+ if (adt) {
+ IdAdtTemplate *iat = (IdAdtTemplate *)id_to;
+ iat->adt = BKE_animdata_copy(bmain, adt, flag);
+ }
+
+ return true;
+}
+
+void BKE_animdata_copy_id_action(Main *bmain, ID *id, const bool set_newid)
+{
+ AnimData *adt = BKE_animdata_from_id(id);
+ if (adt) {
+ if (adt->action) {
+ id_us_min((ID *)adt->action);
+ adt->action = set_newid ? ID_NEW_SET(adt->action, BKE_action_copy(bmain, adt->action)) :
+ BKE_action_copy(bmain, adt->action);
+ }
+ if (adt->tmpact) {
+ id_us_min((ID *)adt->tmpact);
+ adt->tmpact = set_newid ? ID_NEW_SET(adt->tmpact, BKE_action_copy(bmain, adt->tmpact)) :
+ BKE_action_copy(bmain, adt->tmpact);
+ }
+ }
+ bNodeTree *ntree = ntreeFromID(id);
+ if (ntree) {
+ BKE_animdata_copy_id_action(bmain, &ntree->id, set_newid);
+ }
+}
+
+/* Merge copies of the data from the src AnimData into the destination AnimData */
+void BKE_animdata_merge_copy(
+ Main *bmain, ID *dst_id, ID *src_id, eAnimData_MergeCopy_Modes action_mode, bool fix_drivers)
+{
+ AnimData *src = BKE_animdata_from_id(src_id);
+ AnimData *dst = BKE_animdata_from_id(dst_id);
+
+ /* sanity checks */
+ if (ELEM(NULL, dst, src)) {
+ return;
+ }
+
+ // TODO: we must unset all "tweakmode" flags
+ if ((src->flag & ADT_NLA_EDIT_ON) || (dst->flag & ADT_NLA_EDIT_ON)) {
+ CLOG_ERROR(
+ &LOG,
+ "Merging AnimData blocks while editing NLA is dangerous as it may cause data corruption");
+ return;
+ }
+
+ /* handle actions... */
+ if (action_mode == ADT_MERGECOPY_SRC_COPY) {
+ /* make a copy of the actions */
+ dst->action = BKE_action_copy(bmain, src->action);
+ dst->tmpact = BKE_action_copy(bmain, src->tmpact);
+ }
+ else if (action_mode == ADT_MERGECOPY_SRC_REF) {
+ /* make a reference to it */
+ dst->action = src->action;
+ id_us_plus((ID *)dst->action);
+
+ dst->tmpact = src->tmpact;
+ id_us_plus((ID *)dst->tmpact);
+ }
+
+ /* duplicate NLA data */
+ if (src->nla_tracks.first) {
+ ListBase tracks = {NULL, NULL};
+
+ BKE_nla_tracks_copy(bmain, &tracks, &src->nla_tracks, 0);
+ BLI_movelisttolist(&dst->nla_tracks, &tracks);
+ }
+
+ /* duplicate drivers (F-Curves) */
+ if (src->drivers.first) {
+ ListBase drivers = {NULL, NULL};
+
+ BKE_fcurves_copy(&drivers, &src->drivers);
+
+ /* Fix up all driver targets using the old target id
+ * - This assumes that the src ID is being merged into the dst ID
+ */
+ if (fix_drivers) {
+ FCurve *fcu;
+
+ for (fcu = drivers.first; fcu; fcu = fcu->next) {
+ ChannelDriver *driver = fcu->driver;
+ DriverVar *dvar;
+
+ for (dvar = driver->variables.first; dvar; dvar = dvar->next) {
+ DRIVER_TARGETS_USED_LOOPER_BEGIN (dvar) {
+ if (dtar->id == src_id) {
+ dtar->id = dst_id;
+ }
+ }
+ DRIVER_TARGETS_LOOPER_END;
+ }
+ }
+ }
+
+ BLI_movelisttolist(&dst->drivers, &drivers);
+ }
+}
+
+/* Sub-ID Regrouping ------------------------------------------- */
+
+/**
+ * Helper heuristic for determining if a path is compatible with the basepath
+ *
+ * \param path: Full RNA-path from some data (usually an F-Curve) to compare
+ * \param basepath: Shorter path fragment to look for
+ * \return Whether there is a match
+ */
+static bool animpath_matches_basepath(const char path[], const char basepath[])
+{
+ /* we need start of path to be basepath */
+ return (path && basepath) && STRPREFIX(path, basepath);
+}
+
+/* Move F-Curves in src action to dst action, setting up all the necessary groups
+ * for this to happen, but only if the F-Curves being moved have the appropriate
+ * "base path".
+ * - This is used when data moves from one data-block to another, causing the
+ * F-Curves to need to be moved over too
+ */
+void action_move_fcurves_by_basepath(bAction *srcAct, bAction *dstAct, const char basepath[])
+{
+ FCurve *fcu, *fcn = NULL;
+
+ /* sanity checks */
+ if (ELEM(NULL, srcAct, dstAct, basepath)) {
+ if (G.debug & G_DEBUG) {
+ CLOG_ERROR(&LOG,
+ "srcAct: %p, dstAct: %p, basepath: %p has insufficient info to work with",
+ (void *)srcAct,
+ (void *)dstAct,
+ (void *)basepath);
+ }
+ return;
+ }
+
+ /* clear 'temp' flags on all groups in src, as we'll be needing them later
+ * to identify groups that we've managed to empty out here
+ */
+ action_groups_clear_tempflags(srcAct);
+
+ /* iterate over all src F-Curves, moving over the ones that need to be moved */
+ for (fcu = srcAct->curves.first; fcu; fcu = fcn) {
+ /* store next pointer in case we move stuff */
+ fcn = fcu->next;
+
+ /* should F-Curve be moved over?
+ * - we only need the start of the path to match basepath
+ */
+ if (animpath_matches_basepath(fcu->rna_path, basepath)) {
+ bActionGroup *agrp = NULL;
+
+ /* if grouped... */
+ if (fcu->grp) {
+ /* make sure there will be a matching group on the other side for the migrants */
+ agrp = BKE_action_group_find_name(dstAct, fcu->grp->name);
+
+ if (agrp == NULL) {
+ /* add a new one with a similar name (usually will be the same though) */
+ agrp = action_groups_add_new(dstAct, fcu->grp->name);
+ }
+
+ /* old groups should be tagged with 'temp' flags so they can be removed later
+ * if we remove everything from them
+ */
+ fcu->grp->flag |= AGRP_TEMP;
+ }
+
+ /* perform the migration now */
+ action_groups_remove_channel(srcAct, fcu);
+
+ if (agrp) {
+ action_groups_add_channel(dstAct, agrp, fcu);
+ }
+ else {
+ BLI_addtail(&dstAct->curves, fcu);
+ }
+ }
+ }
+
+ /* cleanup groups (if present) */
+ if (srcAct->groups.first) {
+ bActionGroup *agrp, *grp = NULL;
+
+ for (agrp = srcAct->groups.first; agrp; agrp = grp) {
+ grp = agrp->next;
+
+ /* only tagged groups need to be considered - clearing these tags or removing them */
+ if (agrp->flag & AGRP_TEMP) {
+ /* if group is empty and tagged, then we can remove as this operation
+ * moved out all the channels that were formerly here
+ */
+ if (BLI_listbase_is_empty(&agrp->channels)) {
+ BLI_freelinkN(&srcAct->groups, agrp);
+ }
+ else {
+ agrp->flag &= ~AGRP_TEMP;
+ }
+ }
+ }
+ }
+}
+
+/* Transfer the animation data from srcID to dstID where the srcID
+ * animation data is based off "basepath", creating new AnimData and
+ * associated data as necessary
+ */
+void BKE_animdata_separate_by_basepath(Main *bmain, ID *srcID, ID *dstID, ListBase *basepaths)
+{
+ AnimData *srcAdt = NULL, *dstAdt = NULL;
+ LinkData *ld;
+
+ /* sanity checks */
+ if (ELEM(NULL, srcID, dstID)) {
+ if (G.debug & G_DEBUG) {
+ CLOG_ERROR(&LOG, "no source or destination ID to separate AnimData with");
+ }
+ return;
+ }
+
+ /* get animdata from src, and create for destination (if needed) */
+ srcAdt = BKE_animdata_from_id(srcID);
+ dstAdt = BKE_animdata_add_id(dstID);
+
+ if (ELEM(NULL, srcAdt, dstAdt)) {
+ if (G.debug & G_DEBUG) {
+ CLOG_ERROR(&LOG, "no AnimData for this pair of ID's");
+ }
+ return;
+ }
+
+ /* active action */
+ if (srcAdt->action) {
+ /* Set up an action if necessary,
+ * and name it in a similar way so that it can be easily found again. */
+ if (dstAdt->action == NULL) {
+ dstAdt->action = BKE_action_add(bmain, srcAdt->action->id.name + 2);
+ }
+ else if (dstAdt->action == srcAdt->action) {
+ CLOG_WARN(&LOG,
+ "Argh! Source and Destination share animation! "
+ "('%s' and '%s' both use '%s') Making new empty action",
+ srcID->name,
+ dstID->name,
+ srcAdt->action->id.name);
+
+ /* TODO: review this... */
+ id_us_min(&dstAdt->action->id);
+ dstAdt->action = BKE_action_add(bmain, dstAdt->action->id.name + 2);
+ }
+
+ /* loop over base paths, trying to fix for each one... */
+ for (ld = basepaths->first; ld; ld = ld->next) {
+ const char *basepath = (const char *)ld->data;
+ action_move_fcurves_by_basepath(srcAdt->action, dstAdt->action, basepath);
+ }
+ }
+
+ /* drivers */
+ if (srcAdt->drivers.first) {
+ FCurve *fcu, *fcn = NULL;
+
+ /* check each driver against all the base paths to see if any should go */
+ for (fcu = srcAdt->drivers.first; fcu; fcu = fcn) {
+ fcn = fcu->next;
+
+ /* try each basepath in turn, but stop on the first one which works */
+ for (ld = basepaths->first; ld; ld = ld->next) {
+ const char *basepath = (const char *)ld->data;
+
+ if (animpath_matches_basepath(fcu->rna_path, basepath)) {
+ /* just need to change lists */
+ BLI_remlink(&srcAdt->drivers, fcu);
+ BLI_addtail(&dstAdt->drivers, fcu);
+
+ /* TODO: add depsgraph flushing calls? */
+
+ /* can stop now, as moved already */
+ break;
+ }
+ }
+ }
+ }
+}
+
+/**
+ * Temporary wrapper for driver operators for buttons to make it easier to create
+ * such drivers by rerouting all paths through the active object instead so that
+ * they will get picked up by the dependency system.
+ *
+ * \param C: Context pointer - for getting active data
+ * \param[in,out] ptr: RNA pointer for property's data-block.
+ * May be modified as result of path remapping.
+ * \param prop: RNA definition of property to add for
+ * \return MEM_alloc'd string representing the path to the property from the given #PointerRNA
+ */
+char *BKE_animdata_driver_path_hack(bContext *C,
+ PointerRNA *ptr,
+ PropertyRNA *prop,
+ char *base_path)
+{
+ ID *id = ptr->owner_id;
+ ScrArea *area = CTX_wm_area(C);
+
+ /* get standard path which may be extended */
+ char *basepath = base_path ? base_path : RNA_path_from_ID_to_property(ptr, prop);
+ char *path = basepath; /* in case no remapping is needed */
+
+ /* Remapping will only be performed in the Properties Editor, as only this
+ * restricts the subspace of options to the 'active' data (a manageable state)
+ */
+ /* TODO: watch out for pinned context? */
+ if ((area) && (area->spacetype == SPACE_PROPERTIES)) {
+ Object *ob = CTX_data_active_object(C);
+
+ if (ob && id) {
+ /* TODO: after material textures were removed, this function serves
+ * no purpose anymore, but could be used again so was not removed. */
+
+ /* fix RNA pointer, as we've now changed the ID root by changing the paths */
+ if (basepath != path) {
+ /* rebase provided pointer so that it starts from object... */
+ RNA_pointer_create(&ob->id, ptr->type, ptr->data, ptr);
+ }
+ }
+ }
+
+ /* the path should now have been corrected for use */
+ return path;
+}
+
+/* Path Validation -------------------------------------------- */
+
+/* Check if a given RNA Path is valid, by tracing it from the given ID,
+ * and seeing if we can resolve it. */
+static bool check_rna_path_is_valid(ID *owner_id, const char *path)
+{
+ PointerRNA id_ptr, ptr;
+ PropertyRNA *prop = NULL;
+
+ /* make initial RNA pointer to start resolving from */
+ RNA_id_pointer_create(owner_id, &id_ptr);
+
+ /* try to resolve */
+ return RNA_path_resolve_property(&id_ptr, path, &ptr, &prop);
+}
+
+/* Check if some given RNA Path needs fixing - free the given path and set a new one as appropriate
+ * NOTE: we assume that oldName and newName have [" "] padding around them
+ */
+static char *rna_path_rename_fix(ID *owner_id,
+ const char *prefix,
+ const char *oldName,
+ const char *newName,
+ char *oldpath,
+ bool verify_paths)
+{
+ char *prefixPtr = strstr(oldpath, prefix);
+ char *oldNamePtr = strstr(oldpath, oldName);
+ int prefixLen = strlen(prefix);
+ int oldNameLen = strlen(oldName);
+
+ /* only start fixing the path if the prefix and oldName feature in the path,
+ * and prefix occurs immediately before oldName
+ */
+ if ((prefixPtr && oldNamePtr) && (prefixPtr + prefixLen == oldNamePtr)) {
+ /* if we haven't aren't able to resolve the path now, try again after fixing it */
+ if (!verify_paths || check_rna_path_is_valid(owner_id, oldpath) == 0) {
+ DynStr *ds = BLI_dynstr_new();
+ const char *postfixPtr = oldNamePtr + oldNameLen;
+ char *newPath = NULL;
+
+ /* add the part of the string that goes up to the start of the prefix */
+ if (prefixPtr > oldpath) {
+ BLI_dynstr_nappend(ds, oldpath, prefixPtr - oldpath);
+ }
+
+ /* add the prefix */
+ BLI_dynstr_append(ds, prefix);
+
+ /* add the new name (complete with brackets) */
+ BLI_dynstr_append(ds, newName);
+
+ /* add the postfix */
+ BLI_dynstr_append(ds, postfixPtr);
+
+ /* create new path, and cleanup old data */
+ newPath = BLI_dynstr_get_cstring(ds);
+ BLI_dynstr_free(ds);
+
+ /* check if the new path will solve our problems */
+ /* TODO: will need to check whether this step really helps in practice */
+ if (!verify_paths || check_rna_path_is_valid(owner_id, newPath)) {
+ /* free the old path, and return the new one, since we've solved the issues */
+ MEM_freeN(oldpath);
+ return newPath;
+ }
+ else {
+ /* still couldn't resolve the path... so, might as well just leave it alone */
+ MEM_freeN(newPath);
+ }
+ }
+ }
+
+ /* the old path doesn't need to be changed */
+ return oldpath;
+}
+
+/* Check RNA-Paths for a list of F-Curves */
+static bool fcurves_path_rename_fix(ID *owner_id,
+ const char *prefix,
+ const char *oldName,
+ const char *newName,
+ const char *oldKey,
+ const char *newKey,
+ ListBase *curves,
+ bool verify_paths)
+{
+ FCurve *fcu;
+ bool is_changed = false;
+ /* We need to check every curve. */
+ for (fcu = curves->first; fcu; fcu = fcu->next) {
+ if (fcu->rna_path == NULL) {
+ continue;
+ }
+ const char *old_path = fcu->rna_path;
+ /* Firstly, handle the F-Curve's own path. */
+ fcu->rna_path = rna_path_rename_fix(
+ owner_id, prefix, oldKey, newKey, fcu->rna_path, verify_paths);
+ /* if path changed and the F-Curve is grouped, check if its group also needs renaming
+ * (i.e. F-Curve is first of a bone's F-Curves;
+ * hence renaming this should also trigger rename) */
+ if (fcu->rna_path != old_path) {
+ bActionGroup *agrp = fcu->grp;
+ is_changed = true;
+ if ((agrp != NULL) && STREQ(oldName, agrp->name)) {
+ BLI_strncpy(agrp->name, newName, sizeof(agrp->name));
+ }
+ }
+ }
+ return is_changed;
+}
+
+/* Check RNA-Paths for a list of Drivers */
+static bool drivers_path_rename_fix(ID *owner_id,
+ ID *ref_id,
+ const char *prefix,
+ const char *oldName,
+ const char *newName,
+ const char *oldKey,
+ const char *newKey,
+ ListBase *curves,
+ bool verify_paths)
+{
+ bool is_changed = false;
+ FCurve *fcu;
+ /* We need to check every curve - drivers are F-Curves too. */
+ for (fcu = curves->first; fcu; fcu = fcu->next) {
+ /* firstly, handle the F-Curve's own path */
+ if (fcu->rna_path != NULL) {
+ const char *old_rna_path = fcu->rna_path;
+ fcu->rna_path = rna_path_rename_fix(
+ owner_id, prefix, oldKey, newKey, fcu->rna_path, verify_paths);
+ is_changed |= (fcu->rna_path != old_rna_path);
+ }
+ if (fcu->driver == NULL) {
+ continue;
+ }
+ ChannelDriver *driver = fcu->driver;
+ DriverVar *dvar;
+ /* driver variables */
+ for (dvar = driver->variables.first; dvar; dvar = dvar->next) {
+ /* only change the used targets, since the others will need fixing manually anyway */
+ DRIVER_TARGETS_USED_LOOPER_BEGIN (dvar) {
+ /* rename RNA path */
+ if (dtar->rna_path && dtar->id) {
+ const char *old_rna_path = dtar->rna_path;
+ dtar->rna_path = rna_path_rename_fix(
+ dtar->id, prefix, oldKey, newKey, dtar->rna_path, verify_paths);
+ is_changed |= (dtar->rna_path != old_rna_path);
+ }
+ /* also fix the bone-name (if applicable) */
+ if (strstr(prefix, "bones")) {
+ if (((dtar->id) && (GS(dtar->id->name) == ID_OB) &&
+ (!ref_id || ((Object *)(dtar->id))->data == ref_id)) &&
+ (dtar->pchan_name[0]) && STREQ(oldName, dtar->pchan_name)) {
+ is_changed = true;
+ BLI_strncpy(dtar->pchan_name, newName, sizeof(dtar->pchan_name));
+ }
+ }
+ }
+ DRIVER_TARGETS_LOOPER_END;
+ }
+ }
+ return is_changed;
+}
+
+/* Fix all RNA-Paths for Actions linked to NLA Strips */
+static bool nlastrips_path_rename_fix(ID *owner_id,
+ const char *prefix,
+ const char *oldName,
+ const char *newName,
+ const char *oldKey,
+ const char *newKey,
+ ListBase *strips,
+ bool verify_paths)
+{
+ NlaStrip *strip;
+ bool is_changed = false;
+ /* Recursively check strips, fixing only actions. */
+ for (strip = strips->first; strip; strip = strip->next) {
+ /* fix strip's action */
+ if (strip->act != NULL) {
+ is_changed |= fcurves_path_rename_fix(
+ owner_id, prefix, oldName, newName, oldKey, newKey, &strip->act->curves, verify_paths);
+ }
+ /* Ignore own F-Curves, since those are local. */
+ /* Check sub-strips (if metas) */
+ is_changed |= nlastrips_path_rename_fix(
+ owner_id, prefix, oldName, newName, oldKey, newKey, &strip->strips, verify_paths);
+ }
+ return is_changed;
+}
+
+/* Rename Sub-ID Entities in RNA Paths ----------------------- */
+
+/* Fix up the given RNA-Path
+ *
+ * This is just an external wrapper for the RNA-Path fixing function,
+ * with input validity checks on top of the basic method.
+ *
+ * NOTE: it is assumed that the structure we're replacing is <prefix><["><name><"]>
+ * i.e. pose.bones["Bone"]
+ */
+char *BKE_animsys_fix_rna_path_rename(ID *owner_id,
+ char *old_path,
+ const char *prefix,
+ const char *oldName,
+ const char *newName,
+ int oldSubscript,
+ int newSubscript,
+ bool verify_paths)
+{
+ char *oldN, *newN;
+ char *result;
+
+ /* if no action, no need to proceed */
+ if (ELEM(NULL, owner_id, old_path)) {
+ if (G.debug & G_DEBUG) {
+ CLOG_WARN(&LOG, "early abort");
+ }
+ return old_path;
+ }
+
+ /* Name sanitation logic - copied from BKE_animdata_fix_paths_rename() */
+ if ((oldName != NULL) && (newName != NULL)) {
+ /* pad the names with [" "] so that only exact matches are made */
+ const size_t name_old_len = strlen(oldName);
+ const size_t name_new_len = strlen(newName);
+ char *name_old_esc = BLI_array_alloca(name_old_esc, (name_old_len * 2) + 1);
+ char *name_new_esc = BLI_array_alloca(name_new_esc, (name_new_len * 2) + 1);
+
+ BLI_strescape(name_old_esc, oldName, (name_old_len * 2) + 1);
+ BLI_strescape(name_new_esc, newName, (name_new_len * 2) + 1);
+ oldN = BLI_sprintfN("[\"%s\"]", name_old_esc);
+ newN = BLI_sprintfN("[\"%s\"]", name_new_esc);
+ }
+ else {
+ oldN = BLI_sprintfN("[%d]", oldSubscript);
+ newN = BLI_sprintfN("[%d]", newSubscript);
+ }
+
+ /* fix given path */
+ if (G.debug & G_DEBUG) {
+ printf("%s | %s | oldpath = %p ", oldN, newN, old_path);
+ }
+ result = rna_path_rename_fix(owner_id, prefix, oldN, newN, old_path, verify_paths);
+ if (G.debug & G_DEBUG) {
+ printf("path rename result = %p\n", result);
+ }
+
+ /* free the temp names */
+ MEM_freeN(oldN);
+ MEM_freeN(newN);
+
+ /* return the resulting path - may be the same path again if nothing changed */
+ return result;
+}
+
+/* Fix all RNA_Paths in the given Action, relative to the given ID block
+ *
+ * This is just an external wrapper for the F-Curve fixing function,
+ * with input validity checks on top of the basic method.
+ *
+ * NOTE: it is assumed that the structure we're replacing is <prefix><["><name><"]>
+ * i.e. pose.bones["Bone"]
+ */
+void BKE_action_fix_paths_rename(ID *owner_id,
+ bAction *act,
+ const char *prefix,
+ const char *oldName,
+ const char *newName,
+ int oldSubscript,
+ int newSubscript,
+ bool verify_paths)
+{
+ char *oldN, *newN;
+
+ /* if no action, no need to proceed */
+ if (ELEM(NULL, owner_id, act)) {
+ return;
+ }
+
+ /* Name sanitation logic - copied from BKE_animdata_fix_paths_rename() */
+ if ((oldName != NULL) && (newName != NULL)) {
+ /* pad the names with [" "] so that only exact matches are made */
+ const size_t name_old_len = strlen(oldName);
+ const size_t name_new_len = strlen(newName);
+ char *name_old_esc = BLI_array_alloca(name_old_esc, (name_old_len * 2) + 1);
+ char *name_new_esc = BLI_array_alloca(name_new_esc, (name_new_len * 2) + 1);
+
+ BLI_strescape(name_old_esc, oldName, (name_old_len * 2) + 1);
+ BLI_strescape(name_new_esc, newName, (name_new_len * 2) + 1);
+ oldN = BLI_sprintfN("[\"%s\"]", name_old_esc);
+ newN = BLI_sprintfN("[\"%s\"]", name_new_esc);
+ }
+ else {
+ oldN = BLI_sprintfN("[%d]", oldSubscript);
+ newN = BLI_sprintfN("[%d]", newSubscript);
+ }
+
+ /* fix paths in action */
+ fcurves_path_rename_fix(
+ owner_id, prefix, oldName, newName, oldN, newN, &act->curves, verify_paths);
+
+ /* free the temp names */
+ MEM_freeN(oldN);
+ MEM_freeN(newN);
+}
+
+/* Fix all RNA-Paths in the AnimData block used by the given ID block
+ * NOTE: it is assumed that the structure we're replacing is <prefix><["><name><"]>
+ * i.e. pose.bones["Bone"]
+ */
+void BKE_animdata_fix_paths_rename(ID *owner_id,
+ AnimData *adt,
+ ID *ref_id,
+ const char *prefix,
+ const char *oldName,
+ const char *newName,
+ int oldSubscript,
+ int newSubscript,
+ bool verify_paths)
+{
+ NlaTrack *nlt;
+ char *oldN, *newN;
+ /* If no AnimData, no need to proceed. */
+ if (ELEM(NULL, owner_id, adt)) {
+ return;
+ }
+ bool is_self_changed = false;
+ /* Name sanitation logic - shared with BKE_action_fix_paths_rename(). */
+ if ((oldName != NULL) && (newName != NULL)) {
+ /* Pad the names with [" "] so that only exact matches are made. */
+ const size_t name_old_len = strlen(oldName);
+ const size_t name_new_len = strlen(newName);
+ char *name_old_esc = BLI_array_alloca(name_old_esc, (name_old_len * 2) + 1);
+ char *name_new_esc = BLI_array_alloca(name_new_esc, (name_new_len * 2) + 1);
+
+ BLI_strescape(name_old_esc, oldName, (name_old_len * 2) + 1);
+ BLI_strescape(name_new_esc, newName, (name_new_len * 2) + 1);
+ oldN = BLI_sprintfN("[\"%s\"]", name_old_esc);
+ newN = BLI_sprintfN("[\"%s\"]", name_new_esc);
+ }
+ else {
+ oldN = BLI_sprintfN("[%d]", oldSubscript);
+ newN = BLI_sprintfN("[%d]", newSubscript);
+ }
+ /* Active action and temp action. */
+ if (adt->action != NULL) {
+ if (fcurves_path_rename_fix(
+ owner_id, prefix, oldName, newName, oldN, newN, &adt->action->curves, verify_paths)) {
+ DEG_id_tag_update(&adt->action->id, ID_RECALC_COPY_ON_WRITE);
+ }
+ }
+ if (adt->tmpact) {
+ if (fcurves_path_rename_fix(
+ owner_id, prefix, oldName, newName, oldN, newN, &adt->tmpact->curves, verify_paths)) {
+ DEG_id_tag_update(&adt->tmpact->id, ID_RECALC_COPY_ON_WRITE);
+ }
+ }
+ /* Drivers - Drivers are really F-Curves */
+ is_self_changed |= drivers_path_rename_fix(
+ owner_id, ref_id, prefix, oldName, newName, oldN, newN, &adt->drivers, verify_paths);
+ /* NLA Data - Animation Data for Strips */
+ for (nlt = adt->nla_tracks.first; nlt; nlt = nlt->next) {
+ is_self_changed |= nlastrips_path_rename_fix(
+ owner_id, prefix, oldName, newName, oldN, newN, &nlt->strips, verify_paths);
+ }
+ /* Tag owner ID if it */
+ if (is_self_changed) {
+ DEG_id_tag_update(owner_id, ID_RECALC_COPY_ON_WRITE);
+ }
+ /* free the temp names */
+ MEM_freeN(oldN);
+ MEM_freeN(newN);
+}
+
+/* Remove FCurves with Prefix -------------------------------------- */
+
+/* Check RNA-Paths for a list of F-Curves */
+static bool fcurves_path_remove_fix(const char *prefix, ListBase *curves)
+{
+ FCurve *fcu, *fcn;
+ bool any_removed = false;
+ if (!prefix) {
+ return any_removed;
+ }
+
+ /* we need to check every curve... */
+ for (fcu = curves->first; fcu; fcu = fcn) {
+ fcn = fcu->next;
+
+ if (fcu->rna_path) {
+ if (STRPREFIX(fcu->rna_path, prefix)) {
+ BLI_remlink(curves, fcu);
+ BKE_fcurve_free(fcu);
+ any_removed = true;
+ }
+ }
+ }
+ return any_removed;
+}
+
+/* Check RNA-Paths for a list of F-Curves */
+static bool nlastrips_path_remove_fix(const char *prefix, ListBase *strips)
+{
+ NlaStrip *strip;
+ bool any_removed = false;
+
+ /* recursively check strips, fixing only actions... */
+ for (strip = strips->first; strip; strip = strip->next) {
+ /* fix strip's action */
+ if (strip->act) {
+ any_removed |= fcurves_path_remove_fix(prefix, &strip->act->curves);
+ }
+
+ /* check sub-strips (if metas) */
+ any_removed |= nlastrips_path_remove_fix(prefix, &strip->strips);
+ }
+ return any_removed;
+}
+
+bool BKE_animdata_fix_paths_remove(ID *id, const char *prefix)
+{
+ /* Only some ID-blocks have this info for now, so we cast the
+ * types that do to be of type IdAdtTemplate
+ */
+ if (!id_can_have_animdata(id)) {
+ return false;
+ }
+ bool any_removed = false;
+ IdAdtTemplate *iat = (IdAdtTemplate *)id;
+ AnimData *adt = iat->adt;
+ /* check if there's any AnimData to start with */
+ if (adt) {
+ /* free fcurves */
+ if (adt->action != NULL) {
+ any_removed |= fcurves_path_remove_fix(prefix, &adt->action->curves);
+ }
+ if (adt->tmpact != NULL) {
+ any_removed |= fcurves_path_remove_fix(prefix, &adt->tmpact->curves);
+ }
+ /* free drivers - stored as a list of F-Curves */
+ any_removed |= fcurves_path_remove_fix(prefix, &adt->drivers);
+ /* NLA Data - Animation Data for Strips */
+ LISTBASE_FOREACH (NlaTrack *, nlt, &adt->nla_tracks) {
+ any_removed |= nlastrips_path_remove_fix(prefix, &nlt->strips);
+ }
+ }
+ return any_removed;
+}
+
+/* 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);
+ }
+}
+
+void BKE_fcurves_id_cb(ID *id, ID_FCurve_Edit_Callback func, void *user_data)
+{
+ AnimData *adt = BKE_animdata_from_id(id);
+ if (adt != NULL) {
+ AllFCurvesCbWrapper wrapper = {func, user_data};
+ adt_apply_all_fcurves_cb(id, adt, &wrapper);
+ }
+}
+
+/* apply the given callback function on all F-Curves attached to data in main database */
+void BKE_fcurves_main_cb(Main *bmain, 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(bmain, adt_apply_all_fcurves_cb, &wrapper);
+}
+
+/* Whole Database Ops -------------------------------------------- */
+
+/* apply the given callback function on all data in main database */
+void BKE_animdata_main_cb(Main *bmain, ID_AnimData_Edit_Callback func, void *user_data)
+{
+ ID *id;
+
+ /* standard data version */
+#define ANIMDATA_IDS_CB(first) \
+ for (id = first; id; id = id->next) { \
+ AnimData *adt = BKE_animdata_from_id(id); \
+ if (adt) \
+ func(id, adt, user_data); \
+ } \
+ (void)0
+
+ /* "embedded" nodetree cases (i.e. scene/material/texture->nodetree) */
+#define ANIMDATA_NODETREE_IDS_CB(first, NtId_Type) \
+ for (id = first; id; id = id->next) { \
+ AnimData *adt = BKE_animdata_from_id(id); \
+ NtId_Type *ntp = (NtId_Type *)id; \
+ if (ntp->nodetree) { \
+ AnimData *adt2 = BKE_animdata_from_id((ID *)ntp->nodetree); \
+ if (adt2) \
+ func(id, adt2, user_data); \
+ } \
+ if (adt) \
+ func(id, adt, user_data); \
+ } \
+ (void)0
+
+ /* nodes */
+ ANIMDATA_IDS_CB(bmain->nodetrees.first);
+
+ /* textures */
+ ANIMDATA_NODETREE_IDS_CB(bmain->textures.first, Tex);
+
+ /* lights */
+ ANIMDATA_NODETREE_IDS_CB(bmain->lights.first, Light);
+
+ /* materials */
+ ANIMDATA_NODETREE_IDS_CB(bmain->materials.first, Material);
+
+ /* cameras */
+ ANIMDATA_IDS_CB(bmain->cameras.first);
+
+ /* shapekeys */
+ ANIMDATA_IDS_CB(bmain->shapekeys.first);
+
+ /* metaballs */
+ ANIMDATA_IDS_CB(bmain->metaballs.first);
+
+ /* curves */
+ ANIMDATA_IDS_CB(bmain->curves.first);
+
+ /* armatures */
+ ANIMDATA_IDS_CB(bmain->armatures.first);
+
+ /* lattices */
+ ANIMDATA_IDS_CB(bmain->lattices.first);
+
+ /* meshes */
+ ANIMDATA_IDS_CB(bmain->meshes.first);
+
+ /* particles */
+ ANIMDATA_IDS_CB(bmain->particles.first);
+
+ /* speakers */
+ ANIMDATA_IDS_CB(bmain->speakers.first);
+
+ /* movie clips */
+ ANIMDATA_IDS_CB(bmain->movieclips.first);
+
+ /* objects */
+ ANIMDATA_IDS_CB(bmain->objects.first);
+
+ /* masks */
+ ANIMDATA_IDS_CB(bmain->masks.first);
+
+ /* worlds */
+ ANIMDATA_NODETREE_IDS_CB(bmain->worlds.first, World);
+
+ /* scenes */
+ ANIMDATA_NODETREE_IDS_CB(bmain->scenes.first, Scene);
+
+ /* line styles */
+ ANIMDATA_IDS_CB(bmain->linestyles.first);
+
+ /* grease pencil */
+ ANIMDATA_IDS_CB(bmain->gpencils.first);
+
+ /* palettes */
+ ANIMDATA_IDS_CB(bmain->palettes.first);
+
+ /* cache files */
+ ANIMDATA_IDS_CB(bmain->cachefiles.first);
+
+ /* hairs */
+ ANIMDATA_IDS_CB(bmain->hairs.first);
+
+ /* pointclouds */
+ ANIMDATA_IDS_CB(bmain->pointclouds.first);
+
+ /* volumes */
+ ANIMDATA_IDS_CB(bmain->volumes.first);
+
+ /* simulations */
+ ANIMDATA_IDS_CB(bmain->simulations.first);
+}
+
+/* Fix all RNA-Paths throughout the database (directly access the Global.main version)
+ * NOTE: it is assumed that the structure we're replacing is <prefix><["><name><"]>
+ * i.e. pose.bones["Bone"]
+ */
+/* TODO: use BKE_animdata_main_cb for looping over all data */
+void BKE_animdata_fix_paths_rename_all(ID *ref_id,
+ const char *prefix,
+ const char *oldName,
+ const char *newName)
+{
+ Main *bmain = G.main; /* XXX UGLY! */
+ ID *id;
+
+ /* macro for less typing
+ * - whether animdata exists is checked for by the main renaming callback, though taking
+ * this outside of the function may make things slightly faster?
+ */
+#define RENAMEFIX_ANIM_IDS(first) \
+ for (id = first; id; id = id->next) { \
+ AnimData *adt = BKE_animdata_from_id(id); \
+ BKE_animdata_fix_paths_rename(id, adt, ref_id, prefix, oldName, newName, 0, 0, 1); \
+ } \
+ (void)0
+
+ /* another version of this macro for nodetrees */
+#define RENAMEFIX_ANIM_NODETREE_IDS(first, NtId_Type) \
+ for (id = first; id; id = id->next) { \
+ AnimData *adt = BKE_animdata_from_id(id); \
+ NtId_Type *ntp = (NtId_Type *)id; \
+ if (ntp->nodetree) { \
+ AnimData *adt2 = BKE_animdata_from_id((ID *)ntp->nodetree); \
+ BKE_animdata_fix_paths_rename( \
+ (ID *)ntp->nodetree, adt2, ref_id, prefix, oldName, newName, 0, 0, 1); \
+ } \
+ BKE_animdata_fix_paths_rename(id, adt, ref_id, prefix, oldName, newName, 0, 0, 1); \
+ } \
+ (void)0
+
+ /* nodes */
+ RENAMEFIX_ANIM_IDS(bmain->nodetrees.first);
+
+ /* textures */
+ RENAMEFIX_ANIM_NODETREE_IDS(bmain->textures.first, Tex);
+
+ /* lights */
+ RENAMEFIX_ANIM_NODETREE_IDS(bmain->lights.first, Light);
+
+ /* materials */
+ RENAMEFIX_ANIM_NODETREE_IDS(bmain->materials.first, Material);
+
+ /* cameras */
+ RENAMEFIX_ANIM_IDS(bmain->cameras.first);
+
+ /* shapekeys */
+ RENAMEFIX_ANIM_IDS(bmain->shapekeys.first);
+
+ /* metaballs */
+ RENAMEFIX_ANIM_IDS(bmain->metaballs.first);
+
+ /* curves */
+ RENAMEFIX_ANIM_IDS(bmain->curves.first);
+
+ /* armatures */
+ RENAMEFIX_ANIM_IDS(bmain->armatures.first);
+
+ /* lattices */
+ RENAMEFIX_ANIM_IDS(bmain->lattices.first);
+
+ /* meshes */
+ RENAMEFIX_ANIM_IDS(bmain->meshes.first);
+
+ /* particles */
+ RENAMEFIX_ANIM_IDS(bmain->particles.first);
+
+ /* speakers */
+ RENAMEFIX_ANIM_IDS(bmain->speakers.first);
+
+ /* movie clips */
+ RENAMEFIX_ANIM_IDS(bmain->movieclips.first);
+
+ /* objects */
+ RENAMEFIX_ANIM_IDS(bmain->objects.first);
+
+ /* masks */
+ RENAMEFIX_ANIM_IDS(bmain->masks.first);
+
+ /* worlds */
+ RENAMEFIX_ANIM_NODETREE_IDS(bmain->worlds.first, World);
+
+ /* linestyles */
+ RENAMEFIX_ANIM_IDS(bmain->linestyles.first);
+
+ /* grease pencil */
+ RENAMEFIX_ANIM_IDS(bmain->gpencils.first);
+
+ /* cache files */
+ RENAMEFIX_ANIM_IDS(bmain->cachefiles.first);
+
+ /* hairs */
+ RENAMEFIX_ANIM_IDS(bmain->hairs.first);
+
+ /* pointclouds */
+ RENAMEFIX_ANIM_IDS(bmain->pointclouds.first);
+
+ /* volumes */
+ RENAMEFIX_ANIM_IDS(bmain->volumes.first);
+
+ /* simulations */
+ RENAMEFIX_ANIM_IDS(bmain->simulations.first);
+
+ /* scenes */
+ RENAMEFIX_ANIM_NODETREE_IDS(bmain->scenes.first, Scene);
+}
diff --git a/source/blender/blenkernel/intern/anim.c b/source/blender/blenkernel/intern/anim_path.c
index 8804e7ae26c..e073bd6fc82 100644
--- a/source/blender/blenkernel/intern/anim.c
+++ b/source/blender/blenkernel/intern/anim_path.c
@@ -23,236 +23,22 @@
#include "MEM_guardedalloc.h"
-#include <stdlib.h>
+#include <float.h>
-#include "BLI_dlrbTree.h"
-#include "BLI_listbase.h"
-#include "BLI_math.h"
-
-#include "BLT_translation.h"
-
-#include "DNA_anim_types.h"
-#include "DNA_armature_types.h"
+#include "DNA_curve_types.h"
#include "DNA_key_types.h"
-#include "DNA_scene_types.h"
+#include "DNA_object_types.h"
+
+#include "BLI_math_vector.h"
-#include "BKE_action.h"
-#include "BKE_anim.h"
-#include "BKE_animsys.h"
+#include "BKE_anim_path.h"
#include "BKE_curve.h"
#include "BKE_key.h"
-#include "BKE_main.h"
-#include "BKE_object.h"
-#include "BKE_particle.h"
-#include "BKE_report.h"
-#include "BKE_scene.h"
-
-#include "DEG_depsgraph.h"
-#include "DEG_depsgraph_build.h"
-#include "DEG_depsgraph_query.h"
-
-#include "GPU_batch.h"
#include "CLG_log.h"
static CLG_LogRef LOG = {"bke.anim"};
-/* --------------------- */
-/* forward declarations */
-
-/* ******************************************************************** */
-/* Animation Visualization */
-
-/* Initialize the default settings for animation visualization */
-void animviz_settings_init(bAnimVizSettings *avs)
-{
- /* sanity check */
- if (avs == NULL) {
- return;
- }
-
- /* path settings */
- avs->path_bc = avs->path_ac = 10;
-
- avs->path_sf = 1; /* xxx - take from scene instead? */
- avs->path_ef = 250; /* xxx - take from scene instead? */
-
- avs->path_viewflag = (MOTIONPATH_VIEW_KFRAS | MOTIONPATH_VIEW_KFNOS);
-
- avs->path_step = 1;
-
- avs->path_bakeflag |= MOTIONPATH_BAKE_HEADS;
-}
-
-/* ------------------- */
-
-/* Free the given motion path's cache */
-void animviz_free_motionpath_cache(bMotionPath *mpath)
-{
- /* sanity check */
- if (mpath == NULL) {
- return;
- }
-
- /* free the path if necessary */
- if (mpath->points) {
- MEM_freeN(mpath->points);
- }
-
- GPU_VERTBUF_DISCARD_SAFE(mpath->points_vbo);
- GPU_BATCH_DISCARD_SAFE(mpath->batch_line);
- GPU_BATCH_DISCARD_SAFE(mpath->batch_points);
-
- /* reset the relevant parameters */
- mpath->points = NULL;
- mpath->length = 0;
-}
-
-/* Free the given motion path instance and its data
- * NOTE: this frees the motion path given!
- */
-void animviz_free_motionpath(bMotionPath *mpath)
-{
- /* sanity check */
- if (mpath == NULL) {
- return;
- }
-
- /* free the cache first */
- animviz_free_motionpath_cache(mpath);
-
- /* now the instance itself */
- MEM_freeN(mpath);
-}
-
-/* ------------------- */
-
-/* Make a copy of motionpath data, so that viewing with copy on write works */
-bMotionPath *animviz_copy_motionpath(const bMotionPath *mpath_src)
-{
- bMotionPath *mpath_dst;
-
- if (mpath_src == NULL) {
- return NULL;
- }
-
- mpath_dst = MEM_dupallocN(mpath_src);
- mpath_dst->points = MEM_dupallocN(mpath_src->points);
-
- /* should get recreated on draw... */
- mpath_dst->points_vbo = NULL;
- mpath_dst->batch_line = NULL;
- mpath_dst->batch_points = NULL;
-
- return mpath_dst;
-}
-
-/* ------------------- */
-
-/**
- * Setup motion paths for the given data.
- * \note Only used when explicitly calculating paths on bones which may/may not be consider already
- *
- * \param scene: Current scene (for frame ranges, etc.)
- * \param ob: Object to add paths for (must be provided)
- * \param pchan: Posechannel to add paths for (optional; if not provided, object-paths are assumed)
- */
-bMotionPath *animviz_verify_motionpaths(ReportList *reports,
- Scene *scene,
- Object *ob,
- bPoseChannel *pchan)
-{
- bAnimVizSettings *avs;
- bMotionPath *mpath, **dst;
-
- /* sanity checks */
- if (ELEM(NULL, scene, ob)) {
- return NULL;
- }
-
- /* get destination data */
- if (pchan) {
- /* paths for posechannel - assume that posechannel belongs to the object */
- avs = &ob->pose->avs;
- dst = &pchan->mpath;
- }
- else {
- /* paths for object */
- avs = &ob->avs;
- dst = &ob->mpath;
- }
-
- /* avoid 0 size allocs */
- if (avs->path_sf >= avs->path_ef) {
- BKE_reportf(reports,
- RPT_ERROR,
- "Motion path frame extents invalid for %s (%d to %d)%s",
- (pchan) ? pchan->name : ob->id.name,
- avs->path_sf,
- avs->path_ef,
- (avs->path_sf == avs->path_ef) ? TIP_(", cannot have single-frame paths") : "");
- return NULL;
- }
-
- /* if there is already a motionpath, just return that,
- * provided it's settings are ok (saves extra free+alloc)
- */
- if (*dst != NULL) {
- int expected_length = avs->path_ef - avs->path_sf;
-
- mpath = *dst;
-
- /* Path is "valid" if length is valid,
- * but must also be of the same length as is being requested. */
- if ((mpath->start_frame != mpath->end_frame) && (mpath->length > 0)) {
- /* outer check ensures that we have some curve data for this path */
- if (mpath->length == expected_length) {
- /* return/use this as it is already valid length */
- return mpath;
- }
- else {
- /* clear the existing path (as the range has changed), and reallocate below */
- animviz_free_motionpath_cache(mpath);
- }
- }
- }
- else {
- /* create a new motionpath, and assign it */
- mpath = MEM_callocN(sizeof(bMotionPath), "bMotionPath");
- *dst = mpath;
- }
-
- /* set settings from the viz settings */
- mpath->start_frame = avs->path_sf;
- mpath->end_frame = avs->path_ef;
-
- mpath->length = mpath->end_frame - mpath->start_frame;
-
- if (avs->path_bakeflag & MOTIONPATH_BAKE_HEADS) {
- mpath->flag |= MOTIONPATH_FLAG_BHEAD;
- }
- else {
- mpath->flag &= ~MOTIONPATH_FLAG_BHEAD;
- }
-
- /* set default custom values */
- mpath->color[0] = 1.0; /* Red */
- mpath->color[1] = 0.0;
- mpath->color[2] = 0.0;
-
- mpath->line_thickness = 2;
- mpath->flag |= MOTIONPATH_FLAG_LINES; /* draw lines by default */
-
- /* allocate a cache */
- mpath->points = MEM_callocN(sizeof(bMotionPathVert) * mpath->length, "bMotionPathVerts");
-
- /* tag viz settings as currently having some path(s) which use it */
- avs->path_bakeflag |= MOTIONPATH_BAKE_HAS_PATHS;
-
- /* return it */
- return mpath;
-}
-
/* ******************************************************************** */
/* Curve Paths - for curve deforms and/or curve following */
diff --git a/source/blender/blenkernel/intern/anim_sys.c b/source/blender/blenkernel/intern/anim_sys.c
index 2027dbe6c23..5e4b280d0d0 100644
--- a/source/blender/blenkernel/intern/anim_sys.c
+++ b/source/blender/blenkernel/intern/anim_sys.c
@@ -51,6 +51,7 @@
#include "DNA_world_types.h"
#include "BKE_action.h"
+#include "BKE_anim_data.h"
#include "BKE_animsys.h"
#include "BKE_context.h"
#include "BKE_fcurve.h"
@@ -76,1382 +77,6 @@
static CLG_LogRef LOG = {"bke.anim_sys"};
-/* ***************************************** */
-/* AnimData API */
-
-/* Getter/Setter -------------------------------------------- */
-
-/* Check if ID can have AnimData */
-bool id_type_can_have_animdata(const short id_type)
-{
- /* Only some ID-blocks have this info for now */
- /* TODO: finish adding this for the other blocktypes */
- switch (id_type) {
- /* has AnimData */
- case ID_OB:
- case ID_ME:
- case ID_MB:
- case ID_CU:
- case ID_AR:
- case ID_LT:
- case ID_KE:
- case ID_PA:
- case ID_MA:
- case ID_TE:
- case ID_NT:
- case ID_LA:
- case ID_CA:
- case ID_WO:
- case ID_LS:
- case ID_LP:
- case ID_SPK:
- case ID_SCE:
- case ID_MC:
- case ID_MSK:
- case ID_GD:
- case ID_CF:
- case ID_HA:
- case ID_PT:
- case ID_VO:
- return true;
-
- /* no AnimData */
- default:
- return false;
- }
-}
-
-bool id_can_have_animdata(const ID *id)
-{
- /* sanity check */
- if (id == NULL) {
- return false;
- }
-
- return id_type_can_have_animdata(GS(id->name));
-}
-
-/* Get AnimData from the given ID-block. In order for this to work, we assume that
- * the AnimData pointer is stored immediately after the given ID-block in the struct,
- * as per IdAdtTemplate.
- */
-AnimData *BKE_animdata_from_id(ID *id)
-{
- /* only some ID-blocks have this info for now, so we cast the
- * types that do to be of type IdAdtTemplate, and extract the
- * AnimData that way
- */
- if (id_can_have_animdata(id)) {
- IdAdtTemplate *iat = (IdAdtTemplate *)id;
- return iat->adt;
- }
- else {
- return NULL;
- }
-}
-
-/* Add AnimData to the given ID-block. In order for this to work, we assume that
- * the AnimData pointer is stored immediately after the given ID-block in the struct,
- * as per IdAdtTemplate. Also note that
- */
-AnimData *BKE_animdata_add_id(ID *id)
-{
- /* Only some ID-blocks have this info for now, so we cast the
- * types that do to be of type IdAdtTemplate, and add the AnimData
- * to it using the template
- */
- if (id_can_have_animdata(id)) {
- IdAdtTemplate *iat = (IdAdtTemplate *)id;
-
- /* check if there's already AnimData, in which case, don't add */
- if (iat->adt == NULL) {
- AnimData *adt;
-
- /* add animdata */
- adt = iat->adt = MEM_callocN(sizeof(AnimData), "AnimData");
-
- /* set default settings */
- adt->act_influence = 1.0f;
- }
-
- return iat->adt;
- }
- else {
- return NULL;
- }
-}
-
-/* Action Setter --------------------------------------- */
-
-/**
- * Called when user tries to change the active action of an AnimData block
- * (via RNA, Outliner, etc.)
- */
-bool BKE_animdata_set_action(ReportList *reports, ID *id, bAction *act)
-{
- AnimData *adt = BKE_animdata_from_id(id);
- bool ok = false;
-
- /* animdata validity check */
- if (adt == NULL) {
- BKE_report(reports, RPT_WARNING, "No AnimData to set action on");
- return ok;
- }
-
- /* active action is only editable when it is not a tweaking strip
- * see rna_AnimData_action_editable() in rna_animation.c
- */
- if ((adt->flag & ADT_NLA_EDIT_ON) || (adt->actstrip) || (adt->tmpact)) {
- /* cannot remove, otherwise things turn to custard */
- BKE_report(reports, RPT_ERROR, "Cannot change action, as it is still being edited in NLA");
- return ok;
- }
-
- /* manage usercount for current action */
- if (adt->action) {
- id_us_min((ID *)adt->action);
- }
-
- /* assume that AnimData's action can in fact be edited... */
- if (act) {
- /* action must have same type as owner */
- if (ELEM(act->idroot, 0, GS(id->name))) {
- /* can set */
- adt->action = act;
- id_us_plus((ID *)adt->action);
- ok = true;
- }
- else {
- /* cannot set */
- BKE_reportf(
- reports,
- RPT_ERROR,
- "Could not set action '%s' onto ID '%s', as it does not have suitably rooted paths "
- "for this purpose",
- act->id.name + 2,
- id->name);
- /* ok = false; */
- }
- }
- else {
- /* just clearing the action... */
- adt->action = NULL;
- ok = true;
- }
-
- return ok;
-}
-
-/* Freeing -------------------------------------------- */
-
-/* Free AnimData used by the nominated ID-block, and clear ID-block's AnimData pointer */
-void BKE_animdata_free(ID *id, const bool do_id_user)
-{
- /* Only some ID-blocks have this info for now, so we cast the
- * types that do to be of type IdAdtTemplate
- */
- if (id_can_have_animdata(id)) {
- IdAdtTemplate *iat = (IdAdtTemplate *)id;
- AnimData *adt = iat->adt;
-
- /* check if there's any AnimData to start with */
- if (adt) {
- if (do_id_user) {
- /* unlink action (don't free, as it's in its own list) */
- if (adt->action) {
- id_us_min(&adt->action->id);
- }
- /* same goes for the temporarily displaced action */
- if (adt->tmpact) {
- id_us_min(&adt->tmpact->id);
- }
- }
-
- /* free nla data */
- BKE_nla_tracks_free(&adt->nla_tracks, do_id_user);
-
- /* free drivers - stored as a list of F-Curves */
- free_fcurves(&adt->drivers);
-
- /* free driver array cache */
- MEM_SAFE_FREE(adt->driver_array);
-
- /* free overrides */
- /* TODO... */
-
- /* free animdata now */
- MEM_freeN(adt);
- iat->adt = NULL;
- }
- }
-}
-
-bool BKE_animdata_id_is_animated(const struct ID *id)
-{
- if (id == NULL) {
- return false;
- }
-
- const AnimData *adt = BKE_animdata_from_id((ID *)id);
- if (adt == NULL) {
- return false;
- }
-
- if (adt->action != NULL && !BLI_listbase_is_empty(&adt->action->curves)) {
- return true;
- }
-
- return !BLI_listbase_is_empty(&adt->drivers) || !BLI_listbase_is_empty(&adt->nla_tracks) ||
- !BLI_listbase_is_empty(&adt->overrides);
-}
-
-/* Copying -------------------------------------------- */
-
-/**
- * Make a copy of the given AnimData - to be used when copying data-blocks.
- * \param flag: Control ID pointers management,
- * see LIB_ID_CREATE_.../LIB_ID_COPY_... flags in BKE_lib_id.h
- * \return The copied animdata.
- */
-AnimData *BKE_animdata_copy(Main *bmain, AnimData *adt, const int flag)
-{
- AnimData *dadt;
-
- const bool do_action = (flag & LIB_ID_COPY_ACTIONS) != 0 && (flag & LIB_ID_CREATE_NO_MAIN) == 0;
- const bool do_id_user = (flag & LIB_ID_CREATE_NO_USER_REFCOUNT) == 0;
-
- /* sanity check before duplicating struct */
- if (adt == NULL) {
- return NULL;
- }
- dadt = MEM_dupallocN(adt);
-
- /* make a copy of action - at worst, user has to delete copies... */
- if (do_action) {
- BLI_assert(bmain != NULL);
- BLI_assert(dadt->action == NULL || dadt->action != dadt->tmpact);
- BKE_id_copy_ex(bmain, (ID *)dadt->action, (ID **)&dadt->action, flag);
- BKE_id_copy_ex(bmain, (ID *)dadt->tmpact, (ID **)&dadt->tmpact, flag);
- }
- else if (do_id_user) {
- id_us_plus((ID *)dadt->action);
- id_us_plus((ID *)dadt->tmpact);
- }
-
- /* duplicate NLA data */
- BKE_nla_tracks_copy(bmain, &dadt->nla_tracks, &adt->nla_tracks, flag);
-
- /* duplicate drivers (F-Curves) */
- copy_fcurves(&dadt->drivers, &adt->drivers);
- dadt->driver_array = NULL;
-
- /* don't copy overrides */
- BLI_listbase_clear(&dadt->overrides);
-
- /* return */
- return dadt;
-}
-
-/**
- * \param flag: Control ID pointers management,
- * see LIB_ID_CREATE_.../LIB_ID_COPY_... flags in BKE_lib_id.h
- * \return true is successfully copied.
- */
-bool BKE_animdata_copy_id(Main *bmain, ID *id_to, ID *id_from, const int flag)
-{
- AnimData *adt;
-
- if ((id_to && id_from) && (GS(id_to->name) != GS(id_from->name))) {
- return false;
- }
-
- BKE_animdata_free(id_to, (flag & LIB_ID_CREATE_NO_USER_REFCOUNT) == 0);
-
- adt = BKE_animdata_from_id(id_from);
- if (adt) {
- IdAdtTemplate *iat = (IdAdtTemplate *)id_to;
- iat->adt = BKE_animdata_copy(bmain, adt, flag);
- }
-
- return true;
-}
-
-void BKE_animdata_copy_id_action(Main *bmain, ID *id, const bool set_newid)
-{
- AnimData *adt = BKE_animdata_from_id(id);
- if (adt) {
- if (adt->action) {
- id_us_min((ID *)adt->action);
- adt->action = set_newid ? ID_NEW_SET(adt->action, BKE_action_copy(bmain, adt->action)) :
- BKE_action_copy(bmain, adt->action);
- }
- if (adt->tmpact) {
- id_us_min((ID *)adt->tmpact);
- adt->tmpact = set_newid ? ID_NEW_SET(adt->tmpact, BKE_action_copy(bmain, adt->tmpact)) :
- BKE_action_copy(bmain, adt->tmpact);
- }
- }
- bNodeTree *ntree = ntreeFromID(id);
- if (ntree) {
- BKE_animdata_copy_id_action(bmain, &ntree->id, set_newid);
- }
-}
-
-/* Merge copies of the data from the src AnimData into the destination AnimData */
-void BKE_animdata_merge_copy(
- Main *bmain, ID *dst_id, ID *src_id, eAnimData_MergeCopy_Modes action_mode, bool fix_drivers)
-{
- AnimData *src = BKE_animdata_from_id(src_id);
- AnimData *dst = BKE_animdata_from_id(dst_id);
-
- /* sanity checks */
- if (ELEM(NULL, dst, src)) {
- return;
- }
-
- // TODO: we must unset all "tweakmode" flags
- if ((src->flag & ADT_NLA_EDIT_ON) || (dst->flag & ADT_NLA_EDIT_ON)) {
- CLOG_ERROR(
- &LOG,
- "Merging AnimData blocks while editing NLA is dangerous as it may cause data corruption");
- return;
- }
-
- /* handle actions... */
- if (action_mode == ADT_MERGECOPY_SRC_COPY) {
- /* make a copy of the actions */
- dst->action = BKE_action_copy(bmain, src->action);
- dst->tmpact = BKE_action_copy(bmain, src->tmpact);
- }
- else if (action_mode == ADT_MERGECOPY_SRC_REF) {
- /* make a reference to it */
- dst->action = src->action;
- id_us_plus((ID *)dst->action);
-
- dst->tmpact = src->tmpact;
- id_us_plus((ID *)dst->tmpact);
- }
-
- /* duplicate NLA data */
- if (src->nla_tracks.first) {
- ListBase tracks = {NULL, NULL};
-
- BKE_nla_tracks_copy(bmain, &tracks, &src->nla_tracks, 0);
- BLI_movelisttolist(&dst->nla_tracks, &tracks);
- }
-
- /* duplicate drivers (F-Curves) */
- if (src->drivers.first) {
- ListBase drivers = {NULL, NULL};
-
- copy_fcurves(&drivers, &src->drivers);
-
- /* Fix up all driver targets using the old target id
- * - This assumes that the src ID is being merged into the dst ID
- */
- if (fix_drivers) {
- FCurve *fcu;
-
- for (fcu = drivers.first; fcu; fcu = fcu->next) {
- ChannelDriver *driver = fcu->driver;
- DriverVar *dvar;
-
- for (dvar = driver->variables.first; dvar; dvar = dvar->next) {
- DRIVER_TARGETS_USED_LOOPER_BEGIN (dvar) {
- if (dtar->id == src_id) {
- dtar->id = dst_id;
- }
- }
- DRIVER_TARGETS_LOOPER_END;
- }
- }
- }
-
- BLI_movelisttolist(&dst->drivers, &drivers);
- }
-}
-
-/* Sub-ID Regrouping ------------------------------------------- */
-
-/**
- * Helper heuristic for determining if a path is compatible with the basepath
- *
- * \param path: Full RNA-path from some data (usually an F-Curve) to compare
- * \param basepath: Shorter path fragment to look for
- * \return Whether there is a match
- */
-static bool animpath_matches_basepath(const char path[], const char basepath[])
-{
- /* we need start of path to be basepath */
- return (path && basepath) && STRPREFIX(path, basepath);
-}
-
-/* Move F-Curves in src action to dst action, setting up all the necessary groups
- * for this to happen, but only if the F-Curves being moved have the appropriate
- * "base path".
- * - This is used when data moves from one data-block to another, causing the
- * F-Curves to need to be moved over too
- */
-void action_move_fcurves_by_basepath(bAction *srcAct, bAction *dstAct, const char basepath[])
-{
- FCurve *fcu, *fcn = NULL;
-
- /* sanity checks */
- if (ELEM(NULL, srcAct, dstAct, basepath)) {
- if (G.debug & G_DEBUG) {
- CLOG_ERROR(&LOG,
- "srcAct: %p, dstAct: %p, basepath: %p has insufficient info to work with",
- (void *)srcAct,
- (void *)dstAct,
- (void *)basepath);
- }
- return;
- }
-
- /* clear 'temp' flags on all groups in src, as we'll be needing them later
- * to identify groups that we've managed to empty out here
- */
- action_groups_clear_tempflags(srcAct);
-
- /* iterate over all src F-Curves, moving over the ones that need to be moved */
- for (fcu = srcAct->curves.first; fcu; fcu = fcn) {
- /* store next pointer in case we move stuff */
- fcn = fcu->next;
-
- /* should F-Curve be moved over?
- * - we only need the start of the path to match basepath
- */
- if (animpath_matches_basepath(fcu->rna_path, basepath)) {
- bActionGroup *agrp = NULL;
-
- /* if grouped... */
- if (fcu->grp) {
- /* make sure there will be a matching group on the other side for the migrants */
- agrp = BKE_action_group_find_name(dstAct, fcu->grp->name);
-
- if (agrp == NULL) {
- /* add a new one with a similar name (usually will be the same though) */
- agrp = action_groups_add_new(dstAct, fcu->grp->name);
- }
-
- /* old groups should be tagged with 'temp' flags so they can be removed later
- * if we remove everything from them
- */
- fcu->grp->flag |= AGRP_TEMP;
- }
-
- /* perform the migration now */
- action_groups_remove_channel(srcAct, fcu);
-
- if (agrp) {
- action_groups_add_channel(dstAct, agrp, fcu);
- }
- else {
- BLI_addtail(&dstAct->curves, fcu);
- }
- }
- }
-
- /* cleanup groups (if present) */
- if (srcAct->groups.first) {
- bActionGroup *agrp, *grp = NULL;
-
- for (agrp = srcAct->groups.first; agrp; agrp = grp) {
- grp = agrp->next;
-
- /* only tagged groups need to be considered - clearing these tags or removing them */
- if (agrp->flag & AGRP_TEMP) {
- /* if group is empty and tagged, then we can remove as this operation
- * moved out all the channels that were formerly here
- */
- if (BLI_listbase_is_empty(&agrp->channels)) {
- BLI_freelinkN(&srcAct->groups, agrp);
- }
- else {
- agrp->flag &= ~AGRP_TEMP;
- }
- }
- }
- }
-}
-
-/* Transfer the animation data from srcID to dstID where the srcID
- * animation data is based off "basepath", creating new AnimData and
- * associated data as necessary
- */
-void BKE_animdata_separate_by_basepath(Main *bmain, ID *srcID, ID *dstID, ListBase *basepaths)
-{
- AnimData *srcAdt = NULL, *dstAdt = NULL;
- LinkData *ld;
-
- /* sanity checks */
- if (ELEM(NULL, srcID, dstID)) {
- if (G.debug & G_DEBUG) {
- CLOG_ERROR(&LOG, "no source or destination ID to separate AnimData with");
- }
- return;
- }
-
- /* get animdata from src, and create for destination (if needed) */
- srcAdt = BKE_animdata_from_id(srcID);
- dstAdt = BKE_animdata_add_id(dstID);
-
- if (ELEM(NULL, srcAdt, dstAdt)) {
- if (G.debug & G_DEBUG) {
- CLOG_ERROR(&LOG, "no AnimData for this pair of ID's");
- }
- return;
- }
-
- /* active action */
- if (srcAdt->action) {
- /* Set up an action if necessary,
- * and name it in a similar way so that it can be easily found again. */
- if (dstAdt->action == NULL) {
- dstAdt->action = BKE_action_add(bmain, srcAdt->action->id.name + 2);
- }
- else if (dstAdt->action == srcAdt->action) {
- CLOG_WARN(&LOG,
- "Argh! Source and Destination share animation! "
- "('%s' and '%s' both use '%s') Making new empty action",
- srcID->name,
- dstID->name,
- srcAdt->action->id.name);
-
- /* TODO: review this... */
- id_us_min(&dstAdt->action->id);
- dstAdt->action = BKE_action_add(bmain, dstAdt->action->id.name + 2);
- }
-
- /* loop over base paths, trying to fix for each one... */
- for (ld = basepaths->first; ld; ld = ld->next) {
- const char *basepath = (const char *)ld->data;
- action_move_fcurves_by_basepath(srcAdt->action, dstAdt->action, basepath);
- }
- }
-
- /* drivers */
- if (srcAdt->drivers.first) {
- FCurve *fcu, *fcn = NULL;
-
- /* check each driver against all the base paths to see if any should go */
- for (fcu = srcAdt->drivers.first; fcu; fcu = fcn) {
- fcn = fcu->next;
-
- /* try each basepath in turn, but stop on the first one which works */
- for (ld = basepaths->first; ld; ld = ld->next) {
- const char *basepath = (const char *)ld->data;
-
- if (animpath_matches_basepath(fcu->rna_path, basepath)) {
- /* just need to change lists */
- BLI_remlink(&srcAdt->drivers, fcu);
- BLI_addtail(&dstAdt->drivers, fcu);
-
- /* TODO: add depsgraph flushing calls? */
-
- /* can stop now, as moved already */
- break;
- }
- }
- }
- }
-}
-
-/**
- * Temporary wrapper for driver operators for buttons to make it easier to create
- * such drivers by rerouting all paths through the active object instead so that
- * they will get picked up by the dependency system.
- *
- * \param C: Context pointer - for getting active data
- * \param[in,out] ptr: RNA pointer for property's data-block.
- * May be modified as result of path remapping.
- * \param prop: RNA definition of property to add for
- * \return MEM_alloc'd string representing the path to the property from the given #PointerRNA
- */
-char *BKE_animdata_driver_path_hack(bContext *C,
- PointerRNA *ptr,
- PropertyRNA *prop,
- char *base_path)
-{
- ID *id = ptr->owner_id;
- ScrArea *sa = CTX_wm_area(C);
-
- /* get standard path which may be extended */
- char *basepath = base_path ? base_path : RNA_path_from_ID_to_property(ptr, prop);
- char *path = basepath; /* in case no remapping is needed */
-
- /* Remapping will only be performed in the Properties Editor, as only this
- * restricts the subspace of options to the 'active' data (a manageable state)
- */
- /* TODO: watch out for pinned context? */
- if ((sa) && (sa->spacetype == SPACE_PROPERTIES)) {
- Object *ob = CTX_data_active_object(C);
-
- if (ob && id) {
- /* TODO: after material textures were removed, this function serves
- * no purpose anymore, but could be used again so was not removed. */
-
- /* fix RNA pointer, as we've now changed the ID root by changing the paths */
- if (basepath != path) {
- /* rebase provided pointer so that it starts from object... */
- RNA_pointer_create(&ob->id, ptr->type, ptr->data, ptr);
- }
- }
- }
-
- /* the path should now have been corrected for use */
- return path;
-}
-
-/* Path Validation -------------------------------------------- */
-
-/* Check if a given RNA Path is valid, by tracing it from the given ID,
- * and seeing if we can resolve it. */
-static bool check_rna_path_is_valid(ID *owner_id, const char *path)
-{
- PointerRNA id_ptr, ptr;
- PropertyRNA *prop = NULL;
-
- /* make initial RNA pointer to start resolving from */
- RNA_id_pointer_create(owner_id, &id_ptr);
-
- /* try to resolve */
- return RNA_path_resolve_property(&id_ptr, path, &ptr, &prop);
-}
-
-/* Check if some given RNA Path needs fixing - free the given path and set a new one as appropriate
- * NOTE: we assume that oldName and newName have [" "] padding around them
- */
-static char *rna_path_rename_fix(ID *owner_id,
- const char *prefix,
- const char *oldName,
- const char *newName,
- char *oldpath,
- bool verify_paths)
-{
- char *prefixPtr = strstr(oldpath, prefix);
- char *oldNamePtr = strstr(oldpath, oldName);
- int prefixLen = strlen(prefix);
- int oldNameLen = strlen(oldName);
-
- /* only start fixing the path if the prefix and oldName feature in the path,
- * and prefix occurs immediately before oldName
- */
- if ((prefixPtr && oldNamePtr) && (prefixPtr + prefixLen == oldNamePtr)) {
- /* if we haven't aren't able to resolve the path now, try again after fixing it */
- if (!verify_paths || check_rna_path_is_valid(owner_id, oldpath) == 0) {
- DynStr *ds = BLI_dynstr_new();
- const char *postfixPtr = oldNamePtr + oldNameLen;
- char *newPath = NULL;
-
- /* add the part of the string that goes up to the start of the prefix */
- if (prefixPtr > oldpath) {
- BLI_dynstr_nappend(ds, oldpath, prefixPtr - oldpath);
- }
-
- /* add the prefix */
- BLI_dynstr_append(ds, prefix);
-
- /* add the new name (complete with brackets) */
- BLI_dynstr_append(ds, newName);
-
- /* add the postfix */
- BLI_dynstr_append(ds, postfixPtr);
-
- /* create new path, and cleanup old data */
- newPath = BLI_dynstr_get_cstring(ds);
- BLI_dynstr_free(ds);
-
- /* check if the new path will solve our problems */
- /* TODO: will need to check whether this step really helps in practice */
- if (!verify_paths || check_rna_path_is_valid(owner_id, newPath)) {
- /* free the old path, and return the new one, since we've solved the issues */
- MEM_freeN(oldpath);
- return newPath;
- }
- else {
- /* still couldn't resolve the path... so, might as well just leave it alone */
- MEM_freeN(newPath);
- }
- }
- }
-
- /* the old path doesn't need to be changed */
- return oldpath;
-}
-
-/* Check RNA-Paths for a list of F-Curves */
-static bool fcurves_path_rename_fix(ID *owner_id,
- const char *prefix,
- const char *oldName,
- const char *newName,
- const char *oldKey,
- const char *newKey,
- ListBase *curves,
- bool verify_paths)
-{
- FCurve *fcu;
- bool is_changed = false;
- /* We need to check every curve. */
- for (fcu = curves->first; fcu; fcu = fcu->next) {
- if (fcu->rna_path == NULL) {
- continue;
- }
- const char *old_path = fcu->rna_path;
- /* Firstly, handle the F-Curve's own path. */
- fcu->rna_path = rna_path_rename_fix(
- owner_id, prefix, oldKey, newKey, fcu->rna_path, verify_paths);
- /* if path changed and the F-Curve is grouped, check if its group also needs renaming
- * (i.e. F-Curve is first of a bone's F-Curves;
- * hence renaming this should also trigger rename) */
- if (fcu->rna_path != old_path) {
- bActionGroup *agrp = fcu->grp;
- is_changed = true;
- if ((agrp != NULL) && STREQ(oldName, agrp->name)) {
- BLI_strncpy(agrp->name, newName, sizeof(agrp->name));
- }
- }
- }
- return is_changed;
-}
-
-/* Check RNA-Paths for a list of Drivers */
-static bool drivers_path_rename_fix(ID *owner_id,
- ID *ref_id,
- const char *prefix,
- const char *oldName,
- const char *newName,
- const char *oldKey,
- const char *newKey,
- ListBase *curves,
- bool verify_paths)
-{
- bool is_changed = false;
- FCurve *fcu;
- /* We need to check every curve - drivers are F-Curves too. */
- for (fcu = curves->first; fcu; fcu = fcu->next) {
- /* firstly, handle the F-Curve's own path */
- if (fcu->rna_path != NULL) {
- const char *old_rna_path = fcu->rna_path;
- fcu->rna_path = rna_path_rename_fix(
- owner_id, prefix, oldKey, newKey, fcu->rna_path, verify_paths);
- is_changed |= (fcu->rna_path != old_rna_path);
- }
- if (fcu->driver == NULL) {
- continue;
- }
- ChannelDriver *driver = fcu->driver;
- DriverVar *dvar;
- /* driver variables */
- for (dvar = driver->variables.first; dvar; dvar = dvar->next) {
- /* only change the used targets, since the others will need fixing manually anyway */
- DRIVER_TARGETS_USED_LOOPER_BEGIN (dvar) {
- /* rename RNA path */
- if (dtar->rna_path && dtar->id) {
- const char *old_rna_path = dtar->rna_path;
- dtar->rna_path = rna_path_rename_fix(
- dtar->id, prefix, oldKey, newKey, dtar->rna_path, verify_paths);
- is_changed |= (dtar->rna_path != old_rna_path);
- }
- /* also fix the bone-name (if applicable) */
- if (strstr(prefix, "bones")) {
- if (((dtar->id) && (GS(dtar->id->name) == ID_OB) &&
- (!ref_id || ((Object *)(dtar->id))->data == ref_id)) &&
- (dtar->pchan_name[0]) && STREQ(oldName, dtar->pchan_name)) {
- is_changed = true;
- BLI_strncpy(dtar->pchan_name, newName, sizeof(dtar->pchan_name));
- }
- }
- }
- DRIVER_TARGETS_LOOPER_END;
- }
- }
- return is_changed;
-}
-
-/* Fix all RNA-Paths for Actions linked to NLA Strips */
-static bool nlastrips_path_rename_fix(ID *owner_id,
- const char *prefix,
- const char *oldName,
- const char *newName,
- const char *oldKey,
- const char *newKey,
- ListBase *strips,
- bool verify_paths)
-{
- NlaStrip *strip;
- bool is_changed = false;
- /* Recursively check strips, fixing only actions. */
- for (strip = strips->first; strip; strip = strip->next) {
- /* fix strip's action */
- if (strip->act != NULL) {
- is_changed |= fcurves_path_rename_fix(
- owner_id, prefix, oldName, newName, oldKey, newKey, &strip->act->curves, verify_paths);
- }
- /* Ignore own F-Curves, since those are local. */
- /* Check sub-strips (if metas) */
- is_changed |= nlastrips_path_rename_fix(
- owner_id, prefix, oldName, newName, oldKey, newKey, &strip->strips, verify_paths);
- }
- return is_changed;
-}
-
-/* Rename Sub-ID Entities in RNA Paths ----------------------- */
-
-/* Fix up the given RNA-Path
- *
- * This is just an external wrapper for the RNA-Path fixing function,
- * with input validity checks on top of the basic method.
- *
- * NOTE: it is assumed that the structure we're replacing is <prefix><["><name><"]>
- * i.e. pose.bones["Bone"]
- */
-char *BKE_animsys_fix_rna_path_rename(ID *owner_id,
- char *old_path,
- const char *prefix,
- const char *oldName,
- const char *newName,
- int oldSubscript,
- int newSubscript,
- bool verify_paths)
-{
- char *oldN, *newN;
- char *result;
-
- /* if no action, no need to proceed */
- if (ELEM(NULL, owner_id, old_path)) {
- if (G.debug & G_DEBUG) {
- CLOG_WARN(&LOG, "early abort");
- }
- return old_path;
- }
-
- /* Name sanitation logic - copied from BKE_animdata_fix_paths_rename() */
- if ((oldName != NULL) && (newName != NULL)) {
- /* pad the names with [" "] so that only exact matches are made */
- const size_t name_old_len = strlen(oldName);
- const size_t name_new_len = strlen(newName);
- char *name_old_esc = BLI_array_alloca(name_old_esc, (name_old_len * 2) + 1);
- char *name_new_esc = BLI_array_alloca(name_new_esc, (name_new_len * 2) + 1);
-
- BLI_strescape(name_old_esc, oldName, (name_old_len * 2) + 1);
- BLI_strescape(name_new_esc, newName, (name_new_len * 2) + 1);
- oldN = BLI_sprintfN("[\"%s\"]", name_old_esc);
- newN = BLI_sprintfN("[\"%s\"]", name_new_esc);
- }
- else {
- oldN = BLI_sprintfN("[%d]", oldSubscript);
- newN = BLI_sprintfN("[%d]", newSubscript);
- }
-
- /* fix given path */
- if (G.debug & G_DEBUG) {
- printf("%s | %s | oldpath = %p ", oldN, newN, old_path);
- }
- result = rna_path_rename_fix(owner_id, prefix, oldN, newN, old_path, verify_paths);
- if (G.debug & G_DEBUG) {
- printf("path rename result = %p\n", result);
- }
-
- /* free the temp names */
- MEM_freeN(oldN);
- MEM_freeN(newN);
-
- /* return the resulting path - may be the same path again if nothing changed */
- return result;
-}
-
-/* Fix all RNA_Paths in the given Action, relative to the given ID block
- *
- * This is just an external wrapper for the F-Curve fixing function,
- * with input validity checks on top of the basic method.
- *
- * NOTE: it is assumed that the structure we're replacing is <prefix><["><name><"]>
- * i.e. pose.bones["Bone"]
- */
-void BKE_action_fix_paths_rename(ID *owner_id,
- bAction *act,
- const char *prefix,
- const char *oldName,
- const char *newName,
- int oldSubscript,
- int newSubscript,
- bool verify_paths)
-{
- char *oldN, *newN;
-
- /* if no action, no need to proceed */
- if (ELEM(NULL, owner_id, act)) {
- return;
- }
-
- /* Name sanitation logic - copied from BKE_animdata_fix_paths_rename() */
- if ((oldName != NULL) && (newName != NULL)) {
- /* pad the names with [" "] so that only exact matches are made */
- const size_t name_old_len = strlen(oldName);
- const size_t name_new_len = strlen(newName);
- char *name_old_esc = BLI_array_alloca(name_old_esc, (name_old_len * 2) + 1);
- char *name_new_esc = BLI_array_alloca(name_new_esc, (name_new_len * 2) + 1);
-
- BLI_strescape(name_old_esc, oldName, (name_old_len * 2) + 1);
- BLI_strescape(name_new_esc, newName, (name_new_len * 2) + 1);
- oldN = BLI_sprintfN("[\"%s\"]", name_old_esc);
- newN = BLI_sprintfN("[\"%s\"]", name_new_esc);
- }
- else {
- oldN = BLI_sprintfN("[%d]", oldSubscript);
- newN = BLI_sprintfN("[%d]", newSubscript);
- }
-
- /* fix paths in action */
- fcurves_path_rename_fix(
- owner_id, prefix, oldName, newName, oldN, newN, &act->curves, verify_paths);
-
- /* free the temp names */
- MEM_freeN(oldN);
- MEM_freeN(newN);
-}
-
-/* Fix all RNA-Paths in the AnimData block used by the given ID block
- * NOTE: it is assumed that the structure we're replacing is <prefix><["><name><"]>
- * i.e. pose.bones["Bone"]
- */
-void BKE_animdata_fix_paths_rename(ID *owner_id,
- AnimData *adt,
- ID *ref_id,
- const char *prefix,
- const char *oldName,
- const char *newName,
- int oldSubscript,
- int newSubscript,
- bool verify_paths)
-{
- NlaTrack *nlt;
- char *oldN, *newN;
- /* If no AnimData, no need to proceed. */
- if (ELEM(NULL, owner_id, adt)) {
- return;
- }
- bool is_self_changed = false;
- /* Name sanitation logic - shared with BKE_action_fix_paths_rename(). */
- if ((oldName != NULL) && (newName != NULL)) {
- /* Pad the names with [" "] so that only exact matches are made. */
- const size_t name_old_len = strlen(oldName);
- const size_t name_new_len = strlen(newName);
- char *name_old_esc = BLI_array_alloca(name_old_esc, (name_old_len * 2) + 1);
- char *name_new_esc = BLI_array_alloca(name_new_esc, (name_new_len * 2) + 1);
-
- BLI_strescape(name_old_esc, oldName, (name_old_len * 2) + 1);
- BLI_strescape(name_new_esc, newName, (name_new_len * 2) + 1);
- oldN = BLI_sprintfN("[\"%s\"]", name_old_esc);
- newN = BLI_sprintfN("[\"%s\"]", name_new_esc);
- }
- else {
- oldN = BLI_sprintfN("[%d]", oldSubscript);
- newN = BLI_sprintfN("[%d]", newSubscript);
- }
- /* Active action and temp action. */
- if (adt->action != NULL) {
- if (fcurves_path_rename_fix(
- owner_id, prefix, oldName, newName, oldN, newN, &adt->action->curves, verify_paths)) {
- DEG_id_tag_update(&adt->action->id, ID_RECALC_COPY_ON_WRITE);
- }
- }
- if (adt->tmpact) {
- if (fcurves_path_rename_fix(
- owner_id, prefix, oldName, newName, oldN, newN, &adt->tmpact->curves, verify_paths)) {
- DEG_id_tag_update(&adt->tmpact->id, ID_RECALC_COPY_ON_WRITE);
- }
- }
- /* Drivers - Drivers are really F-Curves */
- is_self_changed |= drivers_path_rename_fix(
- owner_id, ref_id, prefix, oldName, newName, oldN, newN, &adt->drivers, verify_paths);
- /* NLA Data - Animation Data for Strips */
- for (nlt = adt->nla_tracks.first; nlt; nlt = nlt->next) {
- is_self_changed |= nlastrips_path_rename_fix(
- owner_id, prefix, oldName, newName, oldN, newN, &nlt->strips, verify_paths);
- }
- /* Tag owner ID if it */
- if (is_self_changed) {
- DEG_id_tag_update(owner_id, ID_RECALC_COPY_ON_WRITE);
- }
- /* free the temp names */
- MEM_freeN(oldN);
- MEM_freeN(newN);
-}
-
-/* Remove FCurves with Prefix -------------------------------------- */
-
-/* Check RNA-Paths for a list of F-Curves */
-static bool fcurves_path_remove_fix(const char *prefix, ListBase *curves)
-{
- FCurve *fcu, *fcn;
- bool any_removed = false;
- if (!prefix) {
- return any_removed;
- }
-
- /* we need to check every curve... */
- for (fcu = curves->first; fcu; fcu = fcn) {
- fcn = fcu->next;
-
- if (fcu->rna_path) {
- if (STRPREFIX(fcu->rna_path, prefix)) {
- BLI_remlink(curves, fcu);
- free_fcurve(fcu);
- any_removed = true;
- }
- }
- }
- return any_removed;
-}
-
-/* Check RNA-Paths for a list of F-Curves */
-static bool nlastrips_path_remove_fix(const char *prefix, ListBase *strips)
-{
- NlaStrip *strip;
- bool any_removed = false;
-
- /* recursively check strips, fixing only actions... */
- for (strip = strips->first; strip; strip = strip->next) {
- /* fix strip's action */
- if (strip->act) {
- any_removed |= fcurves_path_remove_fix(prefix, &strip->act->curves);
- }
-
- /* check sub-strips (if metas) */
- any_removed |= nlastrips_path_remove_fix(prefix, &strip->strips);
- }
- return any_removed;
-}
-
-bool BKE_animdata_fix_paths_remove(ID *id, const char *prefix)
-{
- /* Only some ID-blocks have this info for now, so we cast the
- * types that do to be of type IdAdtTemplate
- */
- if (!id_can_have_animdata(id)) {
- return false;
- }
- bool any_removed = false;
- IdAdtTemplate *iat = (IdAdtTemplate *)id;
- AnimData *adt = iat->adt;
- /* check if there's any AnimData to start with */
- if (adt) {
- /* free fcurves */
- if (adt->action != NULL) {
- any_removed |= fcurves_path_remove_fix(prefix, &adt->action->curves);
- }
- if (adt->tmpact != NULL) {
- any_removed |= fcurves_path_remove_fix(prefix, &adt->tmpact->curves);
- }
- /* free drivers - stored as a list of F-Curves */
- any_removed |= fcurves_path_remove_fix(prefix, &adt->drivers);
- /* NLA Data - Animation Data for Strips */
- for (NlaTrack *nlt = adt->nla_tracks.first; nlt; nlt = nlt->next) {
- any_removed |= nlastrips_path_remove_fix(prefix, &nlt->strips);
- }
- }
- return any_removed;
-}
-
-/* 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);
- }
-}
-
-void BKE_fcurves_id_cb(ID *id, ID_FCurve_Edit_Callback func, void *user_data)
-{
- AnimData *adt = BKE_animdata_from_id(id);
- if (adt != NULL) {
- AllFCurvesCbWrapper wrapper = {func, user_data};
- adt_apply_all_fcurves_cb(id, adt, &wrapper);
- }
-}
-
-/* apply the given callback function on all F-Curves attached to data in main database */
-void BKE_fcurves_main_cb(Main *bmain, 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(bmain, adt_apply_all_fcurves_cb, &wrapper);
-}
-
-/* Whole Database Ops -------------------------------------------- */
-
-/* apply the given callback function on all data in main database */
-void BKE_animdata_main_cb(Main *bmain, ID_AnimData_Edit_Callback func, void *user_data)
-{
- ID *id;
-
- /* standard data version */
-#define ANIMDATA_IDS_CB(first) \
- for (id = first; id; id = id->next) { \
- AnimData *adt = BKE_animdata_from_id(id); \
- if (adt) \
- func(id, adt, user_data); \
- } \
- (void)0
-
- /* "embedded" nodetree cases (i.e. scene/material/texture->nodetree) */
-#define ANIMDATA_NODETREE_IDS_CB(first, NtId_Type) \
- for (id = first; id; id = id->next) { \
- AnimData *adt = BKE_animdata_from_id(id); \
- NtId_Type *ntp = (NtId_Type *)id; \
- if (ntp->nodetree) { \
- AnimData *adt2 = BKE_animdata_from_id((ID *)ntp->nodetree); \
- if (adt2) \
- func(id, adt2, user_data); \
- } \
- if (adt) \
- func(id, adt, user_data); \
- } \
- (void)0
-
- /* nodes */
- ANIMDATA_IDS_CB(bmain->nodetrees.first);
-
- /* textures */
- ANIMDATA_NODETREE_IDS_CB(bmain->textures.first, Tex);
-
- /* lights */
- ANIMDATA_NODETREE_IDS_CB(bmain->lights.first, Light);
-
- /* materials */
- ANIMDATA_NODETREE_IDS_CB(bmain->materials.first, Material);
-
- /* cameras */
- ANIMDATA_IDS_CB(bmain->cameras.first);
-
- /* shapekeys */
- ANIMDATA_IDS_CB(bmain->shapekeys.first);
-
- /* metaballs */
- ANIMDATA_IDS_CB(bmain->metaballs.first);
-
- /* curves */
- ANIMDATA_IDS_CB(bmain->curves.first);
-
- /* armatures */
- ANIMDATA_IDS_CB(bmain->armatures.first);
-
- /* lattices */
- ANIMDATA_IDS_CB(bmain->lattices.first);
-
- /* meshes */
- ANIMDATA_IDS_CB(bmain->meshes.first);
-
- /* particles */
- ANIMDATA_IDS_CB(bmain->particles.first);
-
- /* speakers */
- ANIMDATA_IDS_CB(bmain->speakers.first);
-
- /* movie clips */
- ANIMDATA_IDS_CB(bmain->movieclips.first);
-
- /* objects */
- ANIMDATA_IDS_CB(bmain->objects.first);
-
- /* masks */
- ANIMDATA_IDS_CB(bmain->masks.first);
-
- /* worlds */
- ANIMDATA_NODETREE_IDS_CB(bmain->worlds.first, World);
-
- /* scenes */
- ANIMDATA_NODETREE_IDS_CB(bmain->scenes.first, Scene);
-
- /* line styles */
- ANIMDATA_IDS_CB(bmain->linestyles.first);
-
- /* grease pencil */
- ANIMDATA_IDS_CB(bmain->gpencils.first);
-
- /* palettes */
- ANIMDATA_IDS_CB(bmain->palettes.first);
-
- /* cache files */
- ANIMDATA_IDS_CB(bmain->cachefiles.first);
-
- /* hairs */
- ANIMDATA_IDS_CB(bmain->hairs.first);
-
- /* pointclouds */
- ANIMDATA_IDS_CB(bmain->pointclouds.first);
-
- /* volumes */
- ANIMDATA_IDS_CB(bmain->volumes.first);
-}
-
-/* Fix all RNA-Paths throughout the database (directly access the Global.main version)
- * NOTE: it is assumed that the structure we're replacing is <prefix><["><name><"]>
- * i.e. pose.bones["Bone"]
- */
-/* TODO: use BKE_animdata_main_cb for looping over all data */
-void BKE_animdata_fix_paths_rename_all(ID *ref_id,
- const char *prefix,
- const char *oldName,
- const char *newName)
-{
- Main *bmain = G.main; /* XXX UGLY! */
- ID *id;
-
- /* macro for less typing
- * - whether animdata exists is checked for by the main renaming callback, though taking
- * this outside of the function may make things slightly faster?
- */
-#define RENAMEFIX_ANIM_IDS(first) \
- for (id = first; id; id = id->next) { \
- AnimData *adt = BKE_animdata_from_id(id); \
- BKE_animdata_fix_paths_rename(id, adt, ref_id, prefix, oldName, newName, 0, 0, 1); \
- } \
- (void)0
-
- /* another version of this macro for nodetrees */
-#define RENAMEFIX_ANIM_NODETREE_IDS(first, NtId_Type) \
- for (id = first; id; id = id->next) { \
- AnimData *adt = BKE_animdata_from_id(id); \
- NtId_Type *ntp = (NtId_Type *)id; \
- if (ntp->nodetree) { \
- AnimData *adt2 = BKE_animdata_from_id((ID *)ntp->nodetree); \
- BKE_animdata_fix_paths_rename( \
- (ID *)ntp->nodetree, adt2, ref_id, prefix, oldName, newName, 0, 0, 1); \
- } \
- BKE_animdata_fix_paths_rename(id, adt, ref_id, prefix, oldName, newName, 0, 0, 1); \
- } \
- (void)0
-
- /* nodes */
- RENAMEFIX_ANIM_IDS(bmain->nodetrees.first);
-
- /* textures */
- RENAMEFIX_ANIM_NODETREE_IDS(bmain->textures.first, Tex);
-
- /* lights */
- RENAMEFIX_ANIM_NODETREE_IDS(bmain->lights.first, Light);
-
- /* materials */
- RENAMEFIX_ANIM_NODETREE_IDS(bmain->materials.first, Material);
-
- /* cameras */
- RENAMEFIX_ANIM_IDS(bmain->cameras.first);
-
- /* shapekeys */
- RENAMEFIX_ANIM_IDS(bmain->shapekeys.first);
-
- /* metaballs */
- RENAMEFIX_ANIM_IDS(bmain->metaballs.first);
-
- /* curves */
- RENAMEFIX_ANIM_IDS(bmain->curves.first);
-
- /* armatures */
- RENAMEFIX_ANIM_IDS(bmain->armatures.first);
-
- /* lattices */
- RENAMEFIX_ANIM_IDS(bmain->lattices.first);
-
- /* meshes */
- RENAMEFIX_ANIM_IDS(bmain->meshes.first);
-
- /* particles */
- RENAMEFIX_ANIM_IDS(bmain->particles.first);
-
- /* speakers */
- RENAMEFIX_ANIM_IDS(bmain->speakers.first);
-
- /* movie clips */
- RENAMEFIX_ANIM_IDS(bmain->movieclips.first);
-
- /* objects */
- RENAMEFIX_ANIM_IDS(bmain->objects.first);
-
- /* masks */
- RENAMEFIX_ANIM_IDS(bmain->masks.first);
-
- /* worlds */
- RENAMEFIX_ANIM_NODETREE_IDS(bmain->worlds.first, World);
-
- /* linestyles */
- RENAMEFIX_ANIM_IDS(bmain->linestyles.first);
-
- /* grease pencil */
- RENAMEFIX_ANIM_IDS(bmain->gpencils.first);
-
- /* cache files */
- RENAMEFIX_ANIM_IDS(bmain->cachefiles.first);
-
- /* hairs */
- RENAMEFIX_ANIM_IDS(bmain->hairs.first);
-
- /* pointclouds */
- RENAMEFIX_ANIM_IDS(bmain->pointclouds.first);
-
- /* volumes */
- RENAMEFIX_ANIM_IDS(bmain->volumes.first);
-
- /* scenes */
- RENAMEFIX_ANIM_NODETREE_IDS(bmain->scenes.first, Scene);
-}
-
/* *********************************** */
/* KeyingSet API */
@@ -1917,7 +542,7 @@ static void animsys_evaluate_fcurves(PointerRNA *ptr,
bool flush_to_original)
{
/* Calculate then execute each curve. */
- for (FCurve *fcu = list->first; fcu; fcu = fcu->next) {
+ LISTBASE_FOREACH (FCurve *, fcu, list) {
/* Check if this F-Curve doesn't belong to a muted group. */
if ((fcu->grp != NULL) && (fcu->grp->flag & AGRP_MUTED)) {
continue;
@@ -2470,7 +1095,7 @@ static void nlaeval_free(NlaEvalData *nlaeval)
nlaeval_snapshot_free_data(&nlaeval->eval_snapshot);
/* Delete channels. */
- for (NlaEvalChannel *nec = nlaeval->channels.first; nec; nec = nec->next) {
+ LISTBASE_FOREACH (NlaEvalChannel *, nec, &nlaeval->channels) {
nlaevalchan_free_data(nec);
}
@@ -3329,7 +1954,7 @@ void nladata_flush_channels(PointerRNA *ptr,
}
/* for each channel with accumulated values, write its value on the property it affects */
- for (NlaEvalChannel *nec = channels->channels.first; nec; nec = nec->next) {
+ LISTBASE_FOREACH (NlaEvalChannel *, nec, &channels->channels) {
NlaEvalChannelSnapshot *nec_snapshot = nlaeval_snapshot_find_channel(snapshot, nec);
PathResolvedRNA rna = {nec->key.ptr, nec->key.prop, -1};
@@ -3360,7 +1985,7 @@ static void nla_eval_domain_action(PointerRNA *ptr,
return;
}
- for (FCurve *fcu = act->curves.first; fcu; fcu = fcu->next) {
+ LISTBASE_FOREACH (FCurve *, fcu, &act->curves) {
/* check if this curve should be skipped */
if (fcu->flag & (FCURVE_MUTED | FCURVE_DISABLED)) {
continue;
@@ -3395,7 +2020,7 @@ static void nla_eval_domain_strips(PointerRNA *ptr,
ListBase *strips,
GSet *touched_actions)
{
- for (NlaStrip *strip = strips->first; strip; strip = strip->next) {
+ LISTBASE_FOREACH (NlaStrip *, strip, strips) {
/* check strip's action */
if (strip->act) {
nla_eval_domain_action(ptr, channels, strip->act, touched_actions);
@@ -3419,7 +2044,7 @@ static void animsys_evaluate_nla_domain(PointerRNA *ptr, NlaEvalData *channels,
}
/* NLA Data - Animation Data for Strips */
- for (NlaTrack *nlt = adt->nla_tracks.first; nlt; nlt = nlt->next) {
+ LISTBASE_FOREACH (NlaTrack *, nlt, &adt->nla_tracks) {
/* solo and muting are mutually exclusive... */
if (adt->flag & ADT_NLA_SOLO_TRACK) {
/* skip if there is a solo track, but this isn't it */
@@ -3805,7 +2430,7 @@ bool BKE_animsys_nla_remap_keyframe_values(struct NlaKeyframingContext *context,
*/
void BKE_animsys_free_nla_keyframing_context_cache(struct ListBase *cache)
{
- for (NlaKeyframingContext *ctx = cache->first; ctx; ctx = ctx->next) {
+ LISTBASE_FOREACH (NlaKeyframingContext *, ctx, cache) {
MEM_SAFE_FREE(ctx->eval_strip);
nlaeval_free(&ctx->nla_channels);
}
@@ -3875,7 +2500,7 @@ static void animsys_evaluate_overrides(PointerRNA *ptr, AnimData *adt)
* have been set already by the depsgraph. Now, we use the recalc
*/
void BKE_animsys_evaluate_animdata(
- Scene *scene, ID *id, AnimData *adt, float ctime, short recalc, const bool flush_to_original)
+ ID *id, AnimData *adt, float ctime, eAnimData_Recalc recalc, const bool flush_to_original)
{
PointerRNA id_ptr;
@@ -3922,13 +2547,6 @@ void BKE_animsys_evaluate_animdata(
* - It is best that we execute this every time, so that no errors are likely to occur.
*/
animsys_evaluate_overrides(&id_ptr, adt);
-
- /* execute and clear all cached property update functions */
- if (scene) {
- Main *bmain = G.main; // xxx - to get passed in!
- RNA_property_update_cache_flush(bmain, scene);
- RNA_property_update_cache_free();
- }
}
/* Evaluation of all ID-blocks with Animation Data blocks - Animation Data Only
@@ -3938,10 +2556,7 @@ void BKE_animsys_evaluate_animdata(
* 'local' (i.e. belonging in the nearest ID-block that setting is related to, not a
* standard 'root') block are overridden by a larger 'user'
*/
-void BKE_animsys_evaluate_all_animation(Main *main,
- Depsgraph *depsgraph,
- Scene *scene,
- float ctime)
+void BKE_animsys_evaluate_all_animation(Main *main, Depsgraph *depsgraph, float ctime)
{
ID *id;
@@ -3960,7 +2575,7 @@ void BKE_animsys_evaluate_all_animation(Main *main,
for (id = first; id; id = id->next) { \
if (ID_REAL_USERS(id) > 0) { \
AnimData *adt = BKE_animdata_from_id(id); \
- BKE_animsys_evaluate_animdata(scene, id, adt, ctime, aflag, flush_to_original); \
+ BKE_animsys_evaluate_animdata(id, adt, ctime, aflag, flush_to_original); \
} \
} \
(void)0
@@ -3979,9 +2594,9 @@ void BKE_animsys_evaluate_all_animation(Main *main,
if (ntp->nodetree) { \
AnimData *adt2 = BKE_animdata_from_id((ID *)ntp->nodetree); \
BKE_animsys_evaluate_animdata( \
- scene, (ID *)ntp->nodetree, adt2, ctime, ADT_RECALC_ANIM, flush_to_original); \
+ &ntp->nodetree->id, adt2, ctime, ADT_RECALC_ANIM, flush_to_original); \
} \
- BKE_animsys_evaluate_animdata(scene, id, adt, ctime, aflag, flush_to_original); \
+ BKE_animsys_evaluate_animdata(id, adt, ctime, aflag, flush_to_original); \
} \
} \
(void)0
@@ -4065,6 +2680,9 @@ void BKE_animsys_evaluate_all_animation(Main *main,
/* volumes */
EVAL_ANIM_IDS(main->volumes.first, ADT_RECALC_ANIM);
+ /* simulations */
+ EVAL_ANIM_IDS(main->simulations.first, ADT_RECALC_ANIM);
+
/* objects */
/* ADT_RECALC_ANIM doesn't need to be supplied here, since object AnimData gets
* this tagged by Depsgraph on framechange. This optimization means that objects
@@ -4093,10 +2711,9 @@ void BKE_animsys_eval_animdata(Depsgraph *depsgraph, ID *id)
AnimData *adt = BKE_animdata_from_id(id);
/* XXX: this is only needed for flushing RNA updates,
* which should get handled as part of the dependency graph instead. */
- Scene *scene = NULL;
DEG_debug_print_eval_time(depsgraph, __func__, id->name, id, ctime);
const bool flush_to_original = DEG_is_active(depsgraph);
- BKE_animsys_evaluate_animdata(scene, id, adt, ctime, ADT_RECALC_ANIM, flush_to_original);
+ BKE_animsys_evaluate_animdata(id, adt, ctime, ADT_RECALC_ANIM, flush_to_original);
}
void BKE_animsys_update_driver_array(ID *id)
@@ -4113,7 +2730,7 @@ void BKE_animsys_update_driver_array(ID *id)
adt->driver_array = MEM_mallocN(sizeof(FCurve *) * num_drivers, "adt->driver_array");
int driver_index = 0;
- for (FCurve *fcu = adt->drivers.first; fcu; fcu = fcu->next) {
+ LISTBASE_FOREACH (FCurve *, fcu, &adt->drivers) {
adt->driver_array[driver_index++] = fcu;
}
}
diff --git a/source/blender/blenkernel/intern/anim_visualization.c b/source/blender/blenkernel/intern/anim_visualization.c
new file mode 100644
index 00000000000..04dbe4102cc
--- /dev/null
+++ b/source/blender/blenkernel/intern/anim_visualization.c
@@ -0,0 +1,228 @@
+/*
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV.
+ * All rights reserved.
+ */
+
+/** \file
+ * \ingroup bke
+ */
+#include "MEM_guardedalloc.h"
+
+#include "DNA_action_types.h"
+#include "DNA_anim_types.h"
+#include "DNA_object_types.h"
+#include "DNA_scene_types.h"
+
+#include "BLT_translation.h"
+
+#include "BKE_anim_visualization.h"
+#include "BKE_report.h"
+
+#include "GPU_batch.h"
+
+/* ******************************************************************** */
+/* Animation Visualization */
+
+/* Initialize the default settings for animation visualization */
+void animviz_settings_init(bAnimVizSettings *avs)
+{
+ /* sanity check */
+ if (avs == NULL) {
+ return;
+ }
+
+ /* path settings */
+ avs->path_bc = avs->path_ac = 10;
+
+ avs->path_sf = 1; /* xxx - take from scene instead? */
+ avs->path_ef = 250; /* xxx - take from scene instead? */
+
+ avs->path_viewflag = (MOTIONPATH_VIEW_KFRAS | MOTIONPATH_VIEW_KFNOS);
+
+ avs->path_step = 1;
+
+ avs->path_bakeflag |= MOTIONPATH_BAKE_HEADS;
+}
+
+/* ------------------- */
+
+/* Free the given motion path's cache */
+void animviz_free_motionpath_cache(bMotionPath *mpath)
+{
+ /* sanity check */
+ if (mpath == NULL) {
+ return;
+ }
+
+ /* free the path if necessary */
+ if (mpath->points) {
+ MEM_freeN(mpath->points);
+ }
+
+ GPU_VERTBUF_DISCARD_SAFE(mpath->points_vbo);
+ GPU_BATCH_DISCARD_SAFE(mpath->batch_line);
+ GPU_BATCH_DISCARD_SAFE(mpath->batch_points);
+
+ /* reset the relevant parameters */
+ mpath->points = NULL;
+ mpath->length = 0;
+}
+
+/* Free the given motion path instance and its data
+ * NOTE: this frees the motion path given!
+ */
+void animviz_free_motionpath(bMotionPath *mpath)
+{
+ /* sanity check */
+ if (mpath == NULL) {
+ return;
+ }
+
+ /* free the cache first */
+ animviz_free_motionpath_cache(mpath);
+
+ /* now the instance itself */
+ MEM_freeN(mpath);
+}
+
+/* ------------------- */
+
+/* Make a copy of motionpath data, so that viewing with copy on write works */
+bMotionPath *animviz_copy_motionpath(const bMotionPath *mpath_src)
+{
+ bMotionPath *mpath_dst;
+
+ if (mpath_src == NULL) {
+ return NULL;
+ }
+
+ mpath_dst = MEM_dupallocN(mpath_src);
+ mpath_dst->points = MEM_dupallocN(mpath_src->points);
+
+ /* should get recreated on draw... */
+ mpath_dst->points_vbo = NULL;
+ mpath_dst->batch_line = NULL;
+ mpath_dst->batch_points = NULL;
+
+ return mpath_dst;
+}
+
+/* ------------------- */
+
+/**
+ * Setup motion paths for the given data.
+ * \note Only used when explicitly calculating paths on bones which may/may not be consider already
+ *
+ * \param scene: Current scene (for frame ranges, etc.)
+ * \param ob: Object to add paths for (must be provided)
+ * \param pchan: Posechannel to add paths for (optional; if not provided, object-paths are assumed)
+ */
+bMotionPath *animviz_verify_motionpaths(ReportList *reports,
+ Scene *scene,
+ Object *ob,
+ bPoseChannel *pchan)
+{
+ bAnimVizSettings *avs;
+ bMotionPath *mpath, **dst;
+
+ /* sanity checks */
+ if (ELEM(NULL, scene, ob)) {
+ return NULL;
+ }
+
+ /* get destination data */
+ if (pchan) {
+ /* paths for posechannel - assume that posechannel belongs to the object */
+ avs = &ob->pose->avs;
+ dst = &pchan->mpath;
+ }
+ else {
+ /* paths for object */
+ avs = &ob->avs;
+ dst = &ob->mpath;
+ }
+
+ /* avoid 0 size allocs */
+ if (avs->path_sf >= avs->path_ef) {
+ BKE_reportf(reports,
+ RPT_ERROR,
+ "Motion path frame extents invalid for %s (%d to %d)%s",
+ (pchan) ? pchan->name : ob->id.name,
+ avs->path_sf,
+ avs->path_ef,
+ (avs->path_sf == avs->path_ef) ? TIP_(", cannot have single-frame paths") : "");
+ return NULL;
+ }
+
+ /* if there is already a motionpath, just return that,
+ * provided it's settings are ok (saves extra free+alloc)
+ */
+ if (*dst != NULL) {
+ int expected_length = avs->path_ef - avs->path_sf;
+
+ mpath = *dst;
+
+ /* Path is "valid" if length is valid,
+ * but must also be of the same length as is being requested. */
+ if ((mpath->start_frame != mpath->end_frame) && (mpath->length > 0)) {
+ /* outer check ensures that we have some curve data for this path */
+ if (mpath->length == expected_length) {
+ /* return/use this as it is already valid length */
+ return mpath;
+ }
+ else {
+ /* clear the existing path (as the range has changed), and reallocate below */
+ animviz_free_motionpath_cache(mpath);
+ }
+ }
+ }
+ else {
+ /* create a new motionpath, and assign it */
+ mpath = MEM_callocN(sizeof(bMotionPath), "bMotionPath");
+ *dst = mpath;
+ }
+
+ /* set settings from the viz settings */
+ mpath->start_frame = avs->path_sf;
+ mpath->end_frame = avs->path_ef;
+
+ mpath->length = mpath->end_frame - mpath->start_frame;
+
+ if (avs->path_bakeflag & MOTIONPATH_BAKE_HEADS) {
+ mpath->flag |= MOTIONPATH_FLAG_BHEAD;
+ }
+ else {
+ mpath->flag &= ~MOTIONPATH_FLAG_BHEAD;
+ }
+
+ /* set default custom values */
+ mpath->color[0] = 1.0; /* Red */
+ mpath->color[1] = 0.0;
+ mpath->color[2] = 0.0;
+
+ mpath->line_thickness = 2;
+ mpath->flag |= MOTIONPATH_FLAG_LINES; /* draw lines by default */
+
+ /* allocate a cache */
+ mpath->points = MEM_callocN(sizeof(bMotionPathVert) * mpath->length, "bMotionPathVerts");
+
+ /* tag viz settings as currently having some path(s) which use it */
+ avs->path_bakeflag |= MOTIONPATH_BAKE_HAS_PATHS;
+
+ /* return it */
+ return mpath;
+}
diff --git a/source/blender/blenkernel/intern/appdir.c b/source/blender/blenkernel/intern/appdir.c
index 0e578250b39..8189385a69d 100644
--- a/source/blender/blenkernel/intern/appdir.c
+++ b/source/blender/blenkernel/intern/appdir.c
@@ -232,7 +232,7 @@ static bool get_path_local(char *targetpath,
char osx_resourses[FILE_MAX];
BLI_snprintf(osx_resourses, sizeof(osx_resourses), "%s../Resources", bprogdir);
/* Remove the '/../' added above. */
- BLI_cleanup_path(NULL, osx_resourses);
+ BLI_path_normalize(NULL, osx_resourses);
return test_path(
targetpath, targetpath_len, osx_resourses, blender_version_decimal(ver), relfolder);
#else
@@ -359,7 +359,7 @@ static bool get_path_user(char *targetpath,
* \param folder_name: default name of folder within installation area
* \param subfolder_name: optional name of subfolder within folder
* \param ver: Blender version, used to construct a subdirectory name
- * \return true if it was able to construct such a path.
+ * \return true if it was able to construct such a path.
*/
static bool get_path_system(char *targetpath,
size_t targetpath_len,
@@ -687,12 +687,12 @@ static void where_am_i(char *fullname, const size_t maxlen, const char *name)
BLI_strncpy(fullname, name, maxlen);
if (name[0] == '.') {
- BLI_path_cwd(fullname, maxlen);
+ BLI_path_abs_from_cwd(fullname, maxlen);
#ifdef _WIN32
BLI_path_program_extensions_add_win32(fullname, maxlen);
#endif
}
- else if (BLI_last_slash(name)) {
+ else if (BLI_path_slash_rfind(name)) {
// full path
BLI_strncpy(fullname, name, maxlen);
#ifdef _WIN32
@@ -703,7 +703,7 @@ static void where_am_i(char *fullname, const size_t maxlen, const char *name)
BLI_path_program_search(fullname, maxlen, name);
}
/* Remove "/./" and "/../" so string comparisons can be used on the path. */
- BLI_cleanup_path(NULL, fullname);
+ BLI_path_normalize(NULL, fullname);
#if defined(DEBUG)
if (!STREQ(name, fullname)) {
@@ -939,7 +939,7 @@ static void where_is_temp(char *fullname, char *basename, const size_t maxlen, c
}
else {
/* add a trailing slash if needed */
- BLI_add_slash(fullname);
+ BLI_path_slash_ensure(fullname);
#ifdef WIN32
if (userdir && userdir != fullname) {
/* also set user pref to show %TEMP%. /tmp/ is just plain confusing for Windows users. */
@@ -967,7 +967,7 @@ static void where_is_temp(char *fullname, char *basename, const size_t maxlen, c
if (BLI_is_dir(tmp_name)) {
BLI_strncpy(basename, fullname, maxlen);
BLI_strncpy(fullname, tmp_name, maxlen);
- BLI_add_slash(fullname);
+ BLI_path_slash_ensure(fullname);
}
else {
CLOG_WARN(&LOG,
diff --git a/source/blender/blenkernel/intern/armature.c b/source/blender/blenkernel/intern/armature.c
index 9c88ffb5d52..36921bd2662 100644
--- a/source/blender/blenkernel/intern/armature.c
+++ b/source/blender/blenkernel/intern/armature.c
@@ -51,8 +51,7 @@
#include "DNA_scene_types.h"
#include "BKE_action.h"
-#include "BKE_anim.h"
-#include "BKE_animsys.h"
+#include "BKE_anim_visualization.h"
#include "BKE_armature.h"
#include "BKE_constraint.h"
#include "BKE_curve.h"
@@ -62,11 +61,13 @@
#include "BKE_idtype.h"
#include "BKE_lattice.h"
#include "BKE_lib_id.h"
+#include "BKE_lib_query.h"
#include "BKE_main.h"
#include "BKE_object.h"
#include "BKE_scene.h"
#include "DEG_depsgraph_build.h"
+#include "DEG_depsgraph_query.h"
#include "BIK_api.h"
@@ -151,13 +152,31 @@ static void armature_free_data(struct ID *id)
}
}
+static void armature_foreach_id_bone(Bone *bone, LibraryForeachIDData *data)
+{
+ IDP_foreach_property(
+ bone->prop, IDP_TYPE_FILTER_ID, BKE_lib_query_idpropertiesForeachIDLink_callback, data);
+
+ LISTBASE_FOREACH (Bone *, curbone, &bone->childbase) {
+ armature_foreach_id_bone(curbone, data);
+ }
+}
+
+static void armature_foreach_id(ID *id, LibraryForeachIDData *data)
+{
+ bArmature *arm = (bArmature *)id;
+ LISTBASE_FOREACH (Bone *, bone, &arm->bonebase) {
+ armature_foreach_id_bone(bone, data);
+ }
+}
+
IDTypeInfo IDType_ID_AR = {
.id_code = ID_AR,
.id_filter = FILTER_ID_AR,
.main_listbase_index = INDEX_ID_AR,
.struct_size = sizeof(bArmature),
.name = "Armature",
- .name_plural = "armature",
+ .name_plural = "armatures",
.translation_context = BLT_I18NCONTEXT_ID_ARMATURE,
.flags = 0,
@@ -165,6 +184,7 @@ IDTypeInfo IDType_ID_AR = {
.copy_data = armature_copy_data,
.free_data = armature_free_data,
.make_local = NULL,
+ .foreach_id = armature_foreach_id,
};
/* **************** Generic Functions, data level *************** */
@@ -191,7 +211,7 @@ bArmature *BKE_armature_from_object(Object *ob)
int BKE_armature_bonelist_count(ListBase *lb)
{
int i = 0;
- for (Bone *bone = lb->first; bone; bone = bone->next) {
+ LISTBASE_FOREACH (Bone *, bone, lb) {
i += 1 + BKE_armature_bonelist_count(&bone->childbase);
}
@@ -304,7 +324,7 @@ static void armature_transform_recurse(ListBase *bonebase,
const Bone *bone_parent,
const float arm_mat_parent_inv[4][4])
{
- for (Bone *bone = bonebase->first; bone; bone = bone->next) {
+ LISTBASE_FOREACH (Bone *, bone, bonebase) {
/* Store the initial bone roll in a matrix, this is needed even for child bones
* so any change in head/tail doesn't cause the roll to change.
@@ -425,7 +445,7 @@ Bone *BKE_armature_find_bone_name(bArmature *arm, const char *name)
static void armature_bone_from_name_insert_recursive(GHash *bone_hash, ListBase *lb)
{
- for (Bone *bone = lb->first; bone; bone = bone->next) {
+ LISTBASE_FOREACH (Bone *, bone, lb) {
BLI_ghash_insert(bone_hash, bone->name, bone);
armature_bone_from_name_insert_recursive(bone_hash, &bone->childbase);
}
@@ -475,20 +495,27 @@ bool BKE_armature_bone_flag_test_recursive(const Bone *bone, int flag)
static void armature_refresh_layer_used_recursive(bArmature *arm, ListBase *bones)
{
- for (Bone *bone = bones->first; bone; bone = bone->next) {
+ LISTBASE_FOREACH (Bone *, bone, bones) {
arm->layer_used |= bone->layer;
armature_refresh_layer_used_recursive(arm, &bone->childbase);
}
}
-/* Update the layers_used variable after bones are moved between layer
- * NOTE: Used to be done in drawing code in 2.7, but that won't work with
- * Copy-on-Write, as drawing uses evaluated copies.
- */
-void BKE_armature_refresh_layer_used(bArmature *arm)
+void BKE_armature_refresh_layer_used(struct Depsgraph *depsgraph, struct bArmature *arm)
{
+ if (arm->edbo != NULL) {
+ /* Don't perform this update when the armature is in edit mode. In that case it should be
+ * handled by ED_armature_edit_refresh_layer_used(). */
+ return;
+ }
+
arm->layer_used = 0;
armature_refresh_layer_used_recursive(arm, &arm->bonebase);
+
+ if (depsgraph == NULL || DEG_is_active(depsgraph)) {
+ bArmature *arm_orig = (bArmature *)DEG_get_original_id(&arm->id);
+ arm_orig->layer_used = arm->layer_used;
+ }
}
/* Finds the best possible extension to the name on a particular axis. (For renaming, check for
@@ -2523,7 +2550,7 @@ void BKE_armature_where_is(bArmature *arm)
/* if bone layer is protected, copy the data from from->pose
* when used with linked libraries this copies from the linked pose into the local pose */
-static void pose_proxy_synchronize(Object *ob, Object *from, int layer_protected)
+static void pose_proxy_sync(Object *ob, Object *from, int layer_protected)
{
bPose *pose = ob->pose, *frompose = from->pose;
bPoseChannel *pchan, *pchanp;
@@ -2702,7 +2729,7 @@ static int rebuild_pose_bone(bPose *pose, Bone *bone, bPoseChannel *parchan, int
*/
void BKE_pose_clear_pointers(bPose *pose)
{
- for (bPoseChannel *pchan = pose->chanbase.first; pchan; pchan = pchan->next) {
+ LISTBASE_FOREACH (bPoseChannel *, pchan, &pose->chanbase) {
pchan->bone = NULL;
pchan->child = NULL;
}
@@ -2710,7 +2737,7 @@ void BKE_pose_clear_pointers(bPose *pose)
void BKE_pose_remap_bone_pointers(bArmature *armature, bPose *pose)
{
- for (bPoseChannel *pchan = pose->chanbase.first; pchan; pchan = pchan->next) {
+ LISTBASE_FOREACH (bPoseChannel *, pchan, &pose->chanbase) {
pchan->bone = BKE_armature_find_bone_name(armature, pchan->name);
}
}
@@ -2786,7 +2813,7 @@ void BKE_pose_rebuild(Main *bmain, Object *ob, bArmature *arm, const bool do_id_
* using COW tag was working this morning, but not anymore... */
if (ob->proxy != NULL && (ob->id.tag & LIB_TAG_NO_MAIN) == 0) {
BKE_object_copy_proxy_drivers(ob, ob->proxy);
- pose_proxy_synchronize(ob, ob->proxy, arm->layer_protected);
+ pose_proxy_sync(ob, ob->proxy, arm->layer_protected);
}
BKE_pose_update_constraint_flags(pose); /* for IK detection for example */
diff --git a/source/blender/blenkernel/intern/armature_update.c b/source/blender/blenkernel/intern/armature_update.c
index e51b9ea85d1..d0a5e4348b9 100644
--- a/source/blender/blenkernel/intern/armature_update.c
+++ b/source/blender/blenkernel/intern/armature_update.c
@@ -35,7 +35,7 @@
#include "DNA_scene_types.h"
#include "BKE_action.h"
-#include "BKE_anim.h"
+#include "BKE_anim_path.h"
#include "BKE_armature.h"
#include "BKE_curve.h"
#include "BKE_displist.h"
diff --git a/source/blender/blenkernel/intern/blender.c b/source/blender/blenkernel/intern/blender.c
index 70ab52828f2..e8aa13a8beb 100644
--- a/source/blender/blenkernel/intern/blender.c
+++ b/source/blender/blenkernel/intern/blender.c
@@ -66,7 +66,7 @@
Global G;
UserDef U;
-char versionstr[48] = "";
+static char blender_version_string[48] = "";
/* ********** free ********** */
@@ -102,26 +102,43 @@ void BKE_blender_free(void)
free_nodesystem();
}
-void BKE_blender_version_string(char *version_str,
- size_t maxncpy,
- short version,
- short subversion,
- bool v_prefix,
- bool include_subversion)
+static void blender_version_init(void)
{
- const char *prefix = v_prefix ? "v" : "";
-
- if (include_subversion && subversion > 0) {
- BLI_snprintf(
- version_str, maxncpy, "%s%d.%02d.%d", prefix, version / 100, version % 100, subversion);
+ const char *version_cycle = "";
+ if (STREQ(STRINGIFY(BLENDER_VERSION_CYCLE), "alpha")) {
+ version_cycle = " Alpha";
+ }
+ else if (STREQ(STRINGIFY(BLENDER_VERSION_CYCLE), "beta")) {
+ version_cycle = " Beta";
+ }
+ else if (STREQ(STRINGIFY(BLENDER_VERSION_CYCLE), "rc")) {
+ version_cycle = " Release Candidate";
+ }
+ else if (STREQ(STRINGIFY(BLENDER_VERSION_CYCLE), "release")) {
+ version_cycle = "";
}
else {
- BLI_snprintf(version_str, maxncpy, "%s%d.%02d", prefix, version / 100, version % 100);
+ BLI_assert(!"Invalid Blender version cycle");
}
+
+ BLI_snprintf(blender_version_string,
+ ARRAY_SIZE(blender_version_string),
+ "%d.%02d.%d%s",
+ BLENDER_VERSION / 100,
+ BLENDER_VERSION % 100,
+ BLENDER_VERSION_PATCH,
+ version_cycle);
+}
+
+const char *BKE_blender_version_string(void)
+{
+ return blender_version_string;
}
void BKE_blender_globals_init(void)
{
+ blender_version_init();
+
memset(&G, 0, sizeof(Global));
U.savetime = 1;
@@ -130,9 +147,6 @@ void BKE_blender_globals_init(void)
strcpy(G.ima, "//");
- BKE_blender_version_string(
- versionstr, sizeof(versionstr), BLENDER_VERSION, BLENDER_SUBVERSION, true, true);
-
#ifndef WITH_PYTHON_SECURITY /* default */
G.f |= G_FLAG_SCRIPT_AUTOEXEC;
#else
@@ -182,7 +196,7 @@ static void userdef_free_keymaps(UserDef *userdef)
{
for (wmKeyMap *km = userdef->user_keymaps.first, *km_next; km; km = km_next) {
km_next = km->next;
- for (wmKeyMapDiffItem *kmdi = km->diff_items.first; kmdi; kmdi = kmdi->next) {
+ LISTBASE_FOREACH (wmKeyMapDiffItem *, kmdi, &km->diff_items) {
if (kmdi->add_item) {
keymap_item_free(kmdi->add_item);
MEM_freeN(kmdi->add_item);
@@ -193,7 +207,7 @@ static void userdef_free_keymaps(UserDef *userdef)
}
}
- for (wmKeyMapItem *kmi = km->items.first; kmi; kmi = kmi->next) {
+ LISTBASE_FOREACH (wmKeyMapItem *, kmi, &km->items) {
keymap_item_free(kmi);
}
@@ -250,7 +264,7 @@ void BKE_blender_userdef_data_free(UserDef *userdef, bool clear_fonts)
userdef_free_addons(userdef);
if (clear_fonts) {
- for (uiFont *font = userdef->uifonts.first; font; font = font->next) {
+ LISTBASE_FOREACH (uiFont *, font, &userdef->uifonts) {
BLF_unload_id(font->blf_id);
}
BLF_default_set(-1);
diff --git a/source/blender/blenkernel/intern/blender_undo.c b/source/blender/blenkernel/intern/blender_undo.c
index 99eb4dc9122..ab382d0e8ff 100644
--- a/source/blender/blenkernel/intern/blender_undo.c
+++ b/source/blender/blenkernel/intern/blender_undo.c
@@ -124,6 +124,9 @@ MemFileUndoData *BKE_memfile_undo_encode(Main *bmain, MemFileUndoData *mfu_prev)
}
else {
MemFile *prevfile = (mfu_prev) ? &(mfu_prev->memfile) : NULL;
+ if (prevfile) {
+ BLO_memfile_clear_future(prevfile);
+ }
/* success = */ /* UNUSED */ BLO_write_file_mem(bmain, prevfile, &mfu->memfile, G.fileflags);
mfu->undo_size = mfu->memfile.size;
}
diff --git a/source/blender/blenkernel/intern/blender_user_menu.c b/source/blender/blenkernel/intern/blender_user_menu.c
index ad34ef03e04..edd89357fd5 100644
--- a/source/blender/blenkernel/intern/blender_user_menu.c
+++ b/source/blender/blenkernel/intern/blender_user_menu.c
@@ -38,7 +38,7 @@
bUserMenu *BKE_blender_user_menu_find(ListBase *lb, char space_type, const char *context)
{
- for (bUserMenu *um = lb->first; um; um = um->next) {
+ LISTBASE_FOREACH (bUserMenu *, um, lb) {
if ((space_type == um->space_type) && (STREQ(context, um->context))) {
return um;
}
diff --git a/source/blender/blenkernel/intern/blendfile.c b/source/blender/blenkernel/intern/blendfile.c
index 6bf47a8c280..ef474022f19 100644
--- a/source/blender/blenkernel/intern/blendfile.c
+++ b/source/blender/blenkernel/intern/blendfile.c
@@ -76,7 +76,7 @@
static bool clean_paths_visit_cb(void *UNUSED(userdata), char *path_dst, const char *path_src)
{
strcpy(path_dst, path_src);
- BLI_path_native_slash(path_dst);
+ BLI_path_slash_native(path_dst);
return !STREQ(path_dst, path_src);
}
@@ -88,7 +88,7 @@ static void clean_paths(Main *main)
BKE_bpath_traverse_main(main, clean_paths_visit_cb, BKE_BPATH_TRAVERSE_SKIP_MULTIFILE, NULL);
for (scene = main->scenes.first; scene; scene = scene->id.next) {
- BLI_path_native_slash(scene->r.pic);
+ BLI_path_slash_native(scene->r.pic);
}
}
@@ -201,6 +201,27 @@ static void setup_app_data(bContext *C,
SWAP(ListBase, bmain->workspaces, bfd->main->workspaces);
SWAP(ListBase, bmain->screens, bfd->main->screens);
+ /* In case of actual new file reading without loading UI, we need to regenerate the session
+ * uuid of the UI-related datablocks we are keeping from previous session, otherwise their uuid
+ * will collide with some generated for newly read data. */
+ if (mode != LOAD_UNDO) {
+ ID *id;
+ FOREACH_MAIN_LISTBASE_ID_BEGIN (&bfd->main->wm, id) {
+ BKE_lib_libblock_session_uuid_renew(id);
+ }
+ FOREACH_MAIN_LISTBASE_ID_END;
+
+ FOREACH_MAIN_LISTBASE_ID_BEGIN (&bfd->main->workspaces, id) {
+ BKE_lib_libblock_session_uuid_renew(id);
+ }
+ FOREACH_MAIN_LISTBASE_ID_END;
+
+ FOREACH_MAIN_LISTBASE_ID_BEGIN (&bfd->main->screens, id) {
+ BKE_lib_libblock_session_uuid_renew(id);
+ }
+ FOREACH_MAIN_LISTBASE_ID_END;
+ }
+
/* we re-use current window and screen */
win = CTX_wm_window(C);
curscreen = CTX_wm_screen(C);
@@ -258,9 +279,6 @@ static void setup_app_data(bContext *C,
// CTX_wm_manager_set(C, NULL);
BKE_blender_globals_clear();
- /* clear old property update cache, in case some old references are left dangling */
- RNA_property_update_cache_free();
-
bmain = G_MAIN = bfd->main;
bfd->main = NULL;
@@ -345,7 +363,7 @@ static void setup_app_data(bContext *C,
wmWindowManager *wm = bmain->wm.first;
if (wm) {
- for (wmWindow *win = wm->windows.first; win; win = win->next) {
+ LISTBASE_FOREACH (wmWindow *, win, &wm->windows) {
if (win->scene && win->scene != curscene) {
BKE_scene_set_background(bmain, win->scene);
}
@@ -397,8 +415,9 @@ static void setup_app_blend_file_data(bContext *C,
static int handle_subversion_warning(Main *main, ReportList *reports)
{
- if (main->minversionfile > BLENDER_VERSION ||
- (main->minversionfile == BLENDER_VERSION && main->minsubversionfile > BLENDER_SUBVERSION)) {
+ if (main->minversionfile > BLENDER_FILE_VERSION ||
+ (main->minversionfile == BLENDER_FILE_VERSION &&
+ main->minsubversionfile > BLENDER_FILE_SUBVERSION)) {
BKE_reportf(reports,
RPT_ERROR,
"File written by newer Blender binary (%d.%d), expect loss of data!",
diff --git a/source/blender/blenkernel/intern/boids.c b/source/blender/blenkernel/intern/boids.c
index a493d5f49c8..6197b9dbefd 100644
--- a/source/blender/blenkernel/intern/boids.c
+++ b/source/blender/blenkernel/intern/boids.c
@@ -861,7 +861,7 @@ static Object *boid_find_ground(BoidBrainData *bbd,
SurfaceModifierData *surmd = NULL;
float x[3], v[3];
- surmd = (SurfaceModifierData *)modifiers_findByType(bpa->ground, eModifierType_Surface);
+ surmd = (SurfaceModifierData *)BKE_modifiers_findby_type(bpa->ground, eModifierType_Surface);
/* take surface velocity into account */
closest_point_on_surface(surmd, pa->state.co, x, NULL, v);
diff --git a/source/blender/blenkernel/intern/bpath.c b/source/blender/blenkernel/intern/bpath.c
index 5891a0361d8..d179bfbedfd 100644
--- a/source/blender/blenkernel/intern/bpath.c
+++ b/source/blender/blenkernel/intern/bpath.c
@@ -137,7 +137,7 @@ static bool bpath_relative_rebase_visit_cb(void *userdata, char *path_dst, const
char filepath[(FILE_MAXDIR * 2) + FILE_MAXFILE];
BLI_strncpy(filepath, path_src, FILE_MAX);
if (BLI_path_abs(filepath, data->basedir_src)) {
- BLI_cleanup_path(NULL, filepath);
+ BLI_path_normalize(NULL, filepath);
/* This may fail, if so it's fine to leave absolute since the path is still valid. */
BLI_path_rel(filepath, data->basedir_dst);
@@ -815,13 +815,13 @@ bool BKE_bpath_relocate_visitor(void *pathbase_v, char *path_dst, const char *pa
}
/* Make referenced file absolute. This would be a side-effect of
- * BLI_cleanup_path, but we do it explicitly so we know if it changed. */
+ * BLI_path_normalize, but we do it explicitly so we know if it changed. */
BLI_strncpy(filepath, path_src, FILE_MAX);
if (BLI_path_abs(filepath, base_old)) {
/* Path was relative and is now absolute. Remap.
- * Important BLI_cleanup_path runs before the path is made relative
+ * Important BLI_path_normalize runs before the path is made relative
* because it wont work for paths that start with "//../" */
- BLI_cleanup_path(base_new, filepath);
+ BLI_path_normalize(base_new, filepath);
BLI_path_rel(filepath, base_new);
BLI_strncpy(path_dst, filepath, FILE_MAX);
return true;
diff --git a/source/blender/blenkernel/intern/brush.c b/source/blender/blenkernel/intern/brush.c
index 2306b046026..3241518cae5 100644
--- a/source/blender/blenkernel/intern/brush.c
+++ b/source/blender/blenkernel/intern/brush.c
@@ -49,7 +49,7 @@
#include "IMB_imbuf.h"
#include "IMB_imbuf_types.h"
-#include "RE_render_ext.h" /* externtex */
+#include "RE_render_ext.h" /* RE_texture_evaluate */
static void brush_init_data(ID *id)
{
@@ -89,6 +89,19 @@ static void brush_copy_data(Main *UNUSED(bmain), ID *id_dst, const ID *id_src, c
brush_src->gpencil_settings->curve_strength);
brush_dst->gpencil_settings->curve_jitter = BKE_curvemapping_copy(
brush_src->gpencil_settings->curve_jitter);
+
+ brush_dst->gpencil_settings->curve_rand_pressure = BKE_curvemapping_copy(
+ brush_src->gpencil_settings->curve_rand_pressure);
+ brush_dst->gpencil_settings->curve_rand_strength = BKE_curvemapping_copy(
+ brush_src->gpencil_settings->curve_rand_strength);
+ brush_dst->gpencil_settings->curve_rand_uv = BKE_curvemapping_copy(
+ brush_src->gpencil_settings->curve_rand_uv);
+ brush_dst->gpencil_settings->curve_rand_hue = BKE_curvemapping_copy(
+ brush_src->gpencil_settings->curve_rand_hue);
+ brush_dst->gpencil_settings->curve_rand_saturation = BKE_curvemapping_copy(
+ brush_src->gpencil_settings->curve_rand_saturation);
+ brush_dst->gpencil_settings->curve_rand_value = BKE_curvemapping_copy(
+ brush_src->gpencil_settings->curve_rand_value);
}
/* enable fake user by default */
@@ -107,6 +120,14 @@ static void brush_free_data(ID *id)
BKE_curvemapping_free(brush->gpencil_settings->curve_sensitivity);
BKE_curvemapping_free(brush->gpencil_settings->curve_strength);
BKE_curvemapping_free(brush->gpencil_settings->curve_jitter);
+
+ BKE_curvemapping_free(brush->gpencil_settings->curve_rand_pressure);
+ BKE_curvemapping_free(brush->gpencil_settings->curve_rand_strength);
+ BKE_curvemapping_free(brush->gpencil_settings->curve_rand_uv);
+ BKE_curvemapping_free(brush->gpencil_settings->curve_rand_hue);
+ BKE_curvemapping_free(brush->gpencil_settings->curve_rand_saturation);
+ BKE_curvemapping_free(brush->gpencil_settings->curve_rand_value);
+
MEM_SAFE_FREE(brush->gpencil_settings);
}
@@ -160,6 +181,20 @@ static void brush_make_local(Main *bmain, ID *id, const int flags)
}
}
+static void brush_foreach_id(ID *id, LibraryForeachIDData *data)
+{
+ Brush *brush = (Brush *)id;
+
+ BKE_LIB_FOREACHID_PROCESS(data, brush->toggle_brush, IDWALK_CB_NOP);
+ BKE_LIB_FOREACHID_PROCESS(data, brush->clone.image, IDWALK_CB_NOP);
+ BKE_LIB_FOREACHID_PROCESS(data, brush->paint_curve, IDWALK_CB_USER);
+ if (brush->gpencil_settings) {
+ BKE_LIB_FOREACHID_PROCESS(data, brush->gpencil_settings->material, IDWALK_CB_USER);
+ }
+ BKE_texture_mtex_foreach_id(data, &brush->mtex);
+ BKE_texture_mtex_foreach_id(data, &brush->mask_mtex);
+}
+
IDTypeInfo IDType_ID_BR = {
.id_code = ID_BR,
.id_filter = FILTER_ID_BR,
@@ -174,6 +209,7 @@ IDTypeInfo IDType_ID_BR = {
.copy_data = brush_copy_data,
.free_data = brush_free_data,
.make_local = brush_make_local,
+ .foreach_id = brush_foreach_id,
};
static RNG *brush_rng;
@@ -280,6 +316,13 @@ void BKE_brush_init_gpencil_settings(Brush *brush)
brush->gpencil_settings->curve_sensitivity = BKE_curvemapping_add(1, 0.0f, 0.0f, 1.0f, 1.0f);
brush->gpencil_settings->curve_strength = BKE_curvemapping_add(1, 0.0f, 0.0f, 1.0f, 1.0f);
brush->gpencil_settings->curve_jitter = BKE_curvemapping_add(1, 0.0f, 0.0f, 1.0f, 1.0f);
+
+ brush->gpencil_settings->curve_rand_pressure = BKE_curvemapping_add(1, 0.0f, 0.0f, 1.0f, 1.0f);
+ brush->gpencil_settings->curve_rand_strength = BKE_curvemapping_add(1, 0.0f, 0.0f, 1.0f, 1.0f);
+ brush->gpencil_settings->curve_rand_uv = BKE_curvemapping_add(1, 0.0f, 0.0f, 1.0f, 1.0f);
+ brush->gpencil_settings->curve_rand_hue = BKE_curvemapping_add(1, 0.0f, 0.0f, 1.0f, 1.0f);
+ brush->gpencil_settings->curve_rand_saturation = BKE_curvemapping_add(1, 0.0f, 0.0f, 1.0f, 1.0f);
+ brush->gpencil_settings->curve_rand_value = BKE_curvemapping_add(1, 0.0f, 0.0f, 1.0f, 1.0f);
}
/* add a new gp-brush */
@@ -344,6 +387,8 @@ typedef enum eGPCurveMappingPreset {
GPCURVE_PRESET_INK = 1,
GPCURVE_PRESET_INKNOISE = 2,
GPCURVE_PRESET_MARKER = 3,
+ GPCURVE_PRESET_CHISEL_SENSIVITY = 4,
+ GPCURVE_PRESET_CHISEL_STRENGTH = 5,
} eGPCurveMappingPreset;
static void brush_gpencil_curvemap_reset(CurveMap *cuma, int tot, int preset)
@@ -375,9 +420,9 @@ static void brush_gpencil_curvemap_reset(CurveMap *cuma, int tot, int preset)
case GPCURVE_PRESET_INKNOISE:
cuma->curve[0].x = 0.0f;
cuma->curve[0].y = 0.0f;
- cuma->curve[1].x = 0.63134f;
- cuma->curve[1].y = 0.3625f;
- cuma->curve[2].x = 1.0f;
+ cuma->curve[1].x = 0.55f;
+ cuma->curve[1].y = 0.45f;
+ cuma->curve[2].x = 0.85f;
cuma->curve[2].y = 1.0f;
break;
case GPCURVE_PRESET_MARKER:
@@ -390,6 +435,26 @@ static void brush_gpencil_curvemap_reset(CurveMap *cuma, int tot, int preset)
cuma->curve[3].x = 1.0f;
cuma->curve[3].y = 1.0f;
break;
+ case GPCURVE_PRESET_CHISEL_SENSIVITY:
+ cuma->curve[0].x = 0.0f;
+ cuma->curve[0].y = 0.0f;
+ cuma->curve[1].x = 0.25f;
+ cuma->curve[1].y = 0.40f;
+ cuma->curve[2].x = 1.0f;
+ cuma->curve[2].y = 1.0f;
+ break;
+ case GPCURVE_PRESET_CHISEL_STRENGTH:
+ cuma->curve[0].x = 0.0f;
+ cuma->curve[0].y = 0.0f;
+ cuma->curve[1].x = 0.31f;
+ cuma->curve[1].y = 0.22f;
+ cuma->curve[2].x = 0.61f;
+ cuma->curve[2].y = 0.88f;
+ cuma->curve[3].x = 1.0f;
+ cuma->curve[3].y = 1.0f;
+ break;
+ default:
+ break;
}
if (cuma->table) {
@@ -455,6 +520,7 @@ void BKE_gpencil_brush_preset_set(Main *bmain, Brush *brush, const short type)
Material *ma = BLI_findstring(&bmain->materials, "Dots Stroke", offsetof(ID, name) + 2);
if (ma == NULL) {
ma = BKE_gpencil_material_add(bmain, "Dots Stroke");
+ ma->gp_style->mode = GP_MATERIAL_MODE_DOT;
}
brush->gpencil_settings->material = ma;
/* Pin the matterial to the brush. */
@@ -519,7 +585,7 @@ void BKE_gpencil_brush_preset_set(Main *bmain, Brush *brush, const short type)
brush->gpencil_settings->simplify_f = 0.000f;
brush->gpencil_settings->flag |= GP_BRUSH_GROUP_RANDOM;
- brush->gpencil_settings->draw_random_press = 1.0f;
+ brush->gpencil_settings->draw_random_press = 0.6f;
brush->gpencil_settings->draw_random_strength = 0.0f;
brush->gpencil_settings->draw_jitter = 0.0f;
brush->gpencil_settings->flag |= GP_BRUSH_USE_JITTER_PRESSURE;
@@ -574,15 +640,15 @@ void BKE_gpencil_brush_preset_set(Main *bmain, Brush *brush, const short type)
break;
}
case GP_BRUSH_PRESET_MARKER_CHISEL: {
- brush->size = 80.0f;
+ brush->size = 150.0f;
brush->gpencil_settings->flag |= GP_BRUSH_USE_PRESSURE;
brush->gpencil_settings->draw_strength = 1.0f;
brush->gpencil_settings->input_samples = 10;
- brush->gpencil_settings->active_smooth = ACTIVE_SMOOTH;
- brush->gpencil_settings->draw_angle = DEG2RAD(20.0f);
- brush->gpencil_settings->draw_angle_factor = 1.0f;
+ brush->gpencil_settings->active_smooth = 0.3f;
+ brush->gpencil_settings->draw_angle = DEG2RAD(35.0f);
+ brush->gpencil_settings->draw_angle_factor = 0.5f;
brush->gpencil_settings->hardeness = 1.0f;
copy_v2_fl(brush->gpencil_settings->aspect_ratio, 1.0f);
@@ -597,6 +663,17 @@ void BKE_gpencil_brush_preset_set(Main *bmain, Brush *brush, const short type)
brush->gpencil_settings->draw_jitter = 0.0f;
brush->gpencil_settings->flag |= GP_BRUSH_USE_JITTER_PRESSURE;
+ /* Curve. */
+ custom_curve = brush->gpencil_settings->curve_sensitivity;
+ BKE_curvemapping_set_defaults(custom_curve, 0, 0.0f, 0.0f, 1.0f, 1.0f);
+ BKE_curvemapping_initialize(custom_curve);
+ brush_gpencil_curvemap_reset(custom_curve->cm, 3, GPCURVE_PRESET_CHISEL_SENSIVITY);
+
+ custom_curve = brush->gpencil_settings->curve_strength;
+ BKE_curvemapping_set_defaults(custom_curve, 0, 0.0f, 0.0f, 1.0f, 1.0f);
+ BKE_curvemapping_initialize(custom_curve);
+ brush_gpencil_curvemap_reset(custom_curve->cm, 4, GPCURVE_PRESET_CHISEL_STRENGTH);
+
brush->gpencil_settings->icon_id = GP_BRUSH_ICON_CHISEL;
brush->gpencil_tool = GPAINT_TOOL_DRAW;
@@ -604,11 +681,11 @@ void BKE_gpencil_brush_preset_set(Main *bmain, Brush *brush, const short type)
break;
}
case GP_BRUSH_PRESET_PEN: {
- brush->size = 30.0f;
- brush->gpencil_settings->flag |= GP_BRUSH_USE_PRESSURE;
+ brush->size = 25.0f;
+ brush->gpencil_settings->flag &= ~GP_BRUSH_USE_PRESSURE;
brush->gpencil_settings->draw_strength = 1.0f;
- brush->gpencil_settings->flag |= GP_BRUSH_USE_STENGTH_PRESSURE;
+ brush->gpencil_settings->flag &= ~GP_BRUSH_USE_STENGTH_PRESSURE;
brush->gpencil_settings->input_samples = 10;
brush->gpencil_settings->active_smooth = ACTIVE_SMOOTH;
@@ -662,11 +739,23 @@ void BKE_gpencil_brush_preset_set(Main *bmain, Brush *brush, const short type)
brush->gpencil_settings->icon_id = GP_BRUSH_ICON_PENCIL;
brush->gpencil_tool = GPAINT_TOOL_DRAW;
+ /* Create and link Black Dots material to brush.
+ * This material is required because the brush uses the material to define how the stroke is
+ * drawn. */
+ Material *ma = BLI_findstring(&bmain->materials, "Dots Stroke", offsetof(ID, name) + 2);
+ if (ma == NULL) {
+ ma = BKE_gpencil_material_add(bmain, "Dots Stroke");
+ ma->gp_style->mode = GP_MATERIAL_MODE_DOT;
+ }
+ brush->gpencil_settings->material = ma;
+ /* Pin the matterial to the brush. */
+ brush->gpencil_settings->flag |= GP_BRUSH_MATERIAL_PINNED;
+
zero_v3(brush->secondary_rgb);
break;
}
case GP_BRUSH_PRESET_PENCIL: {
- brush->size = 25.0f;
+ brush->size = 20.0f;
brush->gpencil_settings->flag |= GP_BRUSH_USE_PRESSURE;
brush->gpencil_settings->draw_strength = 0.6f;
@@ -976,14 +1065,20 @@ void BKE_gpencil_brush_preset_set(Main *bmain, Brush *brush, const short type)
}
}
-static Brush *gpencil_brush_ensure(Main *bmain,
- ToolSettings *ts,
- const char *brush_name,
- eObjectMode mode)
+static Brush *gpencil_brush_ensure(
+ Main *bmain, ToolSettings *ts, const char *brush_name, eObjectMode mode, bool *r_new)
{
+ *r_new = false;
Brush *brush = BLI_findstring(&bmain->brushes, brush_name, offsetof(ID, name) + 2);
+
+ /* If the brush exist, but the type is not GPencil or the mode is wrong, create a new one. */
+ if ((brush != NULL) && ((brush->gpencil_settings == NULL) || (brush->ob_mode != mode))) {
+ brush = NULL;
+ }
+
if (brush == NULL) {
brush = BKE_brush_add_gpencil(bmain, ts, brush_name, mode);
+ *r_new = true;
}
if (brush->gpencil_settings == NULL) {
@@ -994,164 +1089,235 @@ static Brush *gpencil_brush_ensure(Main *bmain,
}
/* Create a set of grease pencil Drawing presets. */
-void BKE_brush_gpencil_paint_presets(Main *bmain, ToolSettings *ts)
+void BKE_brush_gpencil_paint_presets(Main *bmain, ToolSettings *ts, const bool reset)
{
+ bool r_new = false;
Paint *paint = &ts->gp_paint->paint;
-
+ Brush *brush_prev = paint->brush;
Brush *brush, *deft_draw;
/* Airbrush brush. */
- brush = gpencil_brush_ensure(bmain, ts, "Airbrush", OB_MODE_PAINT_GPENCIL);
- BKE_gpencil_brush_preset_set(bmain, brush, GP_BRUSH_PRESET_AIRBRUSH);
+ brush = gpencil_brush_ensure(bmain, ts, "Airbrush", OB_MODE_PAINT_GPENCIL, &r_new);
+ if ((reset) || (r_new)) {
+ BKE_gpencil_brush_preset_set(bmain, brush, GP_BRUSH_PRESET_AIRBRUSH);
+ }
/* Ink Pen brush. */
- brush = gpencil_brush_ensure(bmain, ts, "Ink Pen", OB_MODE_PAINT_GPENCIL);
- BKE_gpencil_brush_preset_set(bmain, brush, GP_BRUSH_PRESET_INK_PEN);
+ brush = gpencil_brush_ensure(bmain, ts, "Ink Pen", OB_MODE_PAINT_GPENCIL, &r_new);
+ if ((reset) || (r_new)) {
+ BKE_gpencil_brush_preset_set(bmain, brush, GP_BRUSH_PRESET_INK_PEN);
+ }
/* Ink Pen Rough brush. */
- brush = gpencil_brush_ensure(bmain, ts, "Ink Pen Rough", OB_MODE_PAINT_GPENCIL);
- BKE_gpencil_brush_preset_set(bmain, brush, GP_BRUSH_PRESET_INK_PEN_ROUGH);
+ brush = gpencil_brush_ensure(bmain, ts, "Ink Pen Rough", OB_MODE_PAINT_GPENCIL, &r_new);
+ if ((reset) || (r_new)) {
+ BKE_gpencil_brush_preset_set(bmain, brush, GP_BRUSH_PRESET_INK_PEN_ROUGH);
+ }
/* Marker Bold brush. */
- brush = gpencil_brush_ensure(bmain, ts, "Marker Bold", OB_MODE_PAINT_GPENCIL);
- BKE_gpencil_brush_preset_set(bmain, brush, GP_BRUSH_PRESET_MARKER_BOLD);
+ brush = gpencil_brush_ensure(bmain, ts, "Marker Bold", OB_MODE_PAINT_GPENCIL, &r_new);
+ if ((reset) || (r_new)) {
+ BKE_gpencil_brush_preset_set(bmain, brush, GP_BRUSH_PRESET_MARKER_BOLD);
+ }
/* Marker Chisel brush. */
- brush = gpencil_brush_ensure(bmain, ts, "Marker Chisel", OB_MODE_PAINT_GPENCIL);
- BKE_gpencil_brush_preset_set(bmain, brush, GP_BRUSH_PRESET_MARKER_CHISEL);
+ brush = gpencil_brush_ensure(bmain, ts, "Marker Chisel", OB_MODE_PAINT_GPENCIL, &r_new);
+ if ((reset) || (r_new)) {
+ BKE_gpencil_brush_preset_set(bmain, brush, GP_BRUSH_PRESET_MARKER_CHISEL);
+ }
/* Pen brush. */
- brush = gpencil_brush_ensure(bmain, ts, "Pen", OB_MODE_PAINT_GPENCIL);
- BKE_gpencil_brush_preset_set(bmain, brush, GP_BRUSH_PRESET_PEN);
+ brush = gpencil_brush_ensure(bmain, ts, "Pen", OB_MODE_PAINT_GPENCIL, &r_new);
+ if ((reset) || (r_new)) {
+ BKE_gpencil_brush_preset_set(bmain, brush, GP_BRUSH_PRESET_PEN);
+ }
/* Pencil Soft brush. */
- brush = gpencil_brush_ensure(bmain, ts, "Pencil Soft", OB_MODE_PAINT_GPENCIL);
- BKE_gpencil_brush_preset_set(bmain, brush, GP_BRUSH_PRESET_PENCIL_SOFT);
+ brush = gpencil_brush_ensure(bmain, ts, "Pencil Soft", OB_MODE_PAINT_GPENCIL, &r_new);
+ if ((reset) || (r_new)) {
+ BKE_gpencil_brush_preset_set(bmain, brush, GP_BRUSH_PRESET_PENCIL_SOFT);
+ }
/* Pencil brush. */
- brush = gpencil_brush_ensure(bmain, ts, "Pencil", OB_MODE_PAINT_GPENCIL);
- BKE_gpencil_brush_preset_set(bmain, brush, GP_BRUSH_PRESET_PENCIL);
+ brush = gpencil_brush_ensure(bmain, ts, "Pencil", OB_MODE_PAINT_GPENCIL, &r_new);
+ if ((reset) || (r_new)) {
+ BKE_gpencil_brush_preset_set(bmain, brush, GP_BRUSH_PRESET_PENCIL);
+ }
deft_draw = brush; /* save default brush. */
/* Fill brush. */
- brush = gpencil_brush_ensure(bmain, ts, "Fill Area", OB_MODE_PAINT_GPENCIL);
- BKE_gpencil_brush_preset_set(bmain, brush, GP_BRUSH_PRESET_FILL_AREA);
+ brush = gpencil_brush_ensure(bmain, ts, "Fill Area", OB_MODE_PAINT_GPENCIL, &r_new);
+ if ((reset) || (r_new)) {
+ BKE_gpencil_brush_preset_set(bmain, brush, GP_BRUSH_PRESET_FILL_AREA);
+ }
/* Soft Eraser brush. */
- brush = gpencil_brush_ensure(bmain, ts, "Eraser Soft", OB_MODE_PAINT_GPENCIL);
- BKE_gpencil_brush_preset_set(bmain, brush, GP_BRUSH_PRESET_ERASER_SOFT);
+ brush = gpencil_brush_ensure(bmain, ts, "Eraser Soft", OB_MODE_PAINT_GPENCIL, &r_new);
+ if ((reset) || (r_new)) {
+ BKE_gpencil_brush_preset_set(bmain, brush, GP_BRUSH_PRESET_ERASER_SOFT);
+ }
/* Hard Eraser brush. */
- brush = gpencil_brush_ensure(bmain, ts, "Eraser Hard", OB_MODE_PAINT_GPENCIL);
- BKE_gpencil_brush_preset_set(bmain, brush, GP_BRUSH_PRESET_ERASER_HARD);
+ brush = gpencil_brush_ensure(bmain, ts, "Eraser Hard", OB_MODE_PAINT_GPENCIL, &r_new);
+ if ((reset) || (r_new)) {
+ BKE_gpencil_brush_preset_set(bmain, brush, GP_BRUSH_PRESET_ERASER_HARD);
+ }
/* Point Eraser brush. */
- brush = gpencil_brush_ensure(bmain, ts, "Eraser Point", OB_MODE_PAINT_GPENCIL);
- BKE_gpencil_brush_preset_set(bmain, brush, GP_BRUSH_PRESET_ERASER_POINT);
+ brush = gpencil_brush_ensure(bmain, ts, "Eraser Point", OB_MODE_PAINT_GPENCIL, &r_new);
+ if ((reset) || (r_new)) {
+ BKE_gpencil_brush_preset_set(bmain, brush, GP_BRUSH_PRESET_ERASER_POINT);
+ }
/* Stroke Eraser brush. */
- brush = gpencil_brush_ensure(bmain, ts, "Eraser Stroke", OB_MODE_PAINT_GPENCIL);
- BKE_gpencil_brush_preset_set(bmain, brush, GP_BRUSH_PRESET_ERASER_STROKE);
+ brush = gpencil_brush_ensure(bmain, ts, "Eraser Stroke", OB_MODE_PAINT_GPENCIL, &r_new);
+ if ((reset) || (r_new)) {
+ BKE_gpencil_brush_preset_set(bmain, brush, GP_BRUSH_PRESET_ERASER_STROKE);
+ }
/* Tint brush. */
- brush = gpencil_brush_ensure(bmain, ts, "Tint", OB_MODE_PAINT_GPENCIL);
- BKE_gpencil_brush_preset_set(bmain, brush, GP_BRUSH_PRESET_TINT);
+ brush = gpencil_brush_ensure(bmain, ts, "Tint", OB_MODE_PAINT_GPENCIL, &r_new);
+ if ((reset) || (r_new)) {
+ BKE_gpencil_brush_preset_set(bmain, brush, GP_BRUSH_PRESET_TINT);
+ }
/* Set default Draw brush. */
- BKE_paint_brush_set(paint, deft_draw);
+ if (reset || brush_prev == NULL) {
+ BKE_paint_brush_set(paint, deft_draw);
+ }
}
/* Create a set of grease pencil Vertex Paint presets. */
-void BKE_brush_gpencil_vertex_presets(Main *bmain, ToolSettings *ts)
+void BKE_brush_gpencil_vertex_presets(Main *bmain, ToolSettings *ts, const bool reset)
{
- Paint *vertexpaint = &ts->gp_vertexpaint->paint;
+ bool r_new = false;
+ Paint *vertexpaint = &ts->gp_vertexpaint->paint;
+ Brush *brush_prev = vertexpaint->brush;
Brush *brush, *deft_vertex;
/* Vertex Draw brush. */
- brush = gpencil_brush_ensure(bmain, ts, "Vertex Draw", OB_MODE_VERTEX_GPENCIL);
- BKE_gpencil_brush_preset_set(bmain, brush, GP_BRUSH_PRESET_VERTEX_DRAW);
+ brush = gpencil_brush_ensure(bmain, ts, "Vertex Draw", OB_MODE_VERTEX_GPENCIL, &r_new);
+ if ((reset) || (r_new)) {
+ BKE_gpencil_brush_preset_set(bmain, brush, GP_BRUSH_PRESET_VERTEX_DRAW);
+ }
deft_vertex = brush; /* save default brush. */
/* Vertex Blur brush. */
- brush = gpencil_brush_ensure(bmain, ts, "Vertex Blur", OB_MODE_VERTEX_GPENCIL);
- BKE_gpencil_brush_preset_set(bmain, brush, GP_BRUSH_PRESET_VERTEX_BLUR);
-
+ brush = gpencil_brush_ensure(bmain, ts, "Vertex Blur", OB_MODE_VERTEX_GPENCIL, &r_new);
+ if ((reset) || (r_new)) {
+ BKE_gpencil_brush_preset_set(bmain, brush, GP_BRUSH_PRESET_VERTEX_BLUR);
+ }
/* Vertex Average brush. */
- brush = gpencil_brush_ensure(bmain, ts, "Vertex Average", OB_MODE_VERTEX_GPENCIL);
- BKE_gpencil_brush_preset_set(bmain, brush, GP_BRUSH_PRESET_VERTEX_AVERAGE);
-
+ brush = gpencil_brush_ensure(bmain, ts, "Vertex Average", OB_MODE_VERTEX_GPENCIL, &r_new);
+ if ((reset) || (r_new)) {
+ BKE_gpencil_brush_preset_set(bmain, brush, GP_BRUSH_PRESET_VERTEX_AVERAGE);
+ }
/* Vertex Smear brush. */
- brush = gpencil_brush_ensure(bmain, ts, "Vertex Smear", OB_MODE_VERTEX_GPENCIL);
- BKE_gpencil_brush_preset_set(bmain, brush, GP_BRUSH_PRESET_VERTEX_SMEAR);
-
+ brush = gpencil_brush_ensure(bmain, ts, "Vertex Smear", OB_MODE_VERTEX_GPENCIL, &r_new);
+ if ((reset) || (r_new)) {
+ BKE_gpencil_brush_preset_set(bmain, brush, GP_BRUSH_PRESET_VERTEX_SMEAR);
+ }
/* Vertex Replace brush. */
- brush = gpencil_brush_ensure(bmain, ts, "Vertex Replace", OB_MODE_VERTEX_GPENCIL);
- BKE_gpencil_brush_preset_set(bmain, brush, GP_BRUSH_PRESET_VERTEX_REPLACE);
+ brush = gpencil_brush_ensure(bmain, ts, "Vertex Replace", OB_MODE_VERTEX_GPENCIL, &r_new);
+ if ((reset) || (r_new)) {
+ BKE_gpencil_brush_preset_set(bmain, brush, GP_BRUSH_PRESET_VERTEX_REPLACE);
+ }
/* Set default Vertex brush. */
- BKE_paint_brush_set(vertexpaint, deft_vertex);
+ if (reset || brush_prev == NULL) {
+ BKE_paint_brush_set(vertexpaint, deft_vertex);
+ }
}
/* Create a set of grease pencil Sculpt Paint presets. */
-void BKE_brush_gpencil_sculpt_presets(Main *bmain, ToolSettings *ts)
+void BKE_brush_gpencil_sculpt_presets(Main *bmain, ToolSettings *ts, const bool reset)
{
+ bool r_new = false;
+
Paint *sculptpaint = &ts->gp_sculptpaint->paint;
+ Brush *brush_prev = sculptpaint->brush;
Brush *brush, *deft_sculpt;
/* Smooth brush. */
- brush = gpencil_brush_ensure(bmain, ts, "Smooth Stroke", OB_MODE_SCULPT_GPENCIL);
- BKE_gpencil_brush_preset_set(bmain, brush, GP_BRUSH_PRESET_SMOOTH_STROKE);
+ brush = gpencil_brush_ensure(bmain, ts, "Smooth Stroke", OB_MODE_SCULPT_GPENCIL, &r_new);
+ if ((reset) || (r_new)) {
+ BKE_gpencil_brush_preset_set(bmain, brush, GP_BRUSH_PRESET_SMOOTH_STROKE);
+ }
deft_sculpt = brush;
/* Strength brush. */
- brush = gpencil_brush_ensure(bmain, ts, "Strength Stroke", OB_MODE_SCULPT_GPENCIL);
- BKE_gpencil_brush_preset_set(bmain, brush, GP_BRUSH_PRESET_STRENGTH_STROKE);
+ brush = gpencil_brush_ensure(bmain, ts, "Strength Stroke", OB_MODE_SCULPT_GPENCIL, &r_new);
+ if ((reset) || (r_new)) {
+ BKE_gpencil_brush_preset_set(bmain, brush, GP_BRUSH_PRESET_STRENGTH_STROKE);
+ }
/* Thickness brush. */
- brush = gpencil_brush_ensure(bmain, ts, "Thickness Stroke", OB_MODE_SCULPT_GPENCIL);
- BKE_gpencil_brush_preset_set(bmain, brush, GP_BRUSH_PRESET_THICKNESS_STROKE);
+ brush = gpencil_brush_ensure(bmain, ts, "Thickness Stroke", OB_MODE_SCULPT_GPENCIL, &r_new);
+ if ((reset) || (r_new)) {
+ BKE_gpencil_brush_preset_set(bmain, brush, GP_BRUSH_PRESET_THICKNESS_STROKE);
+ }
/* Grab brush. */
- brush = gpencil_brush_ensure(bmain, ts, "Grab Stroke", OB_MODE_SCULPT_GPENCIL);
- BKE_gpencil_brush_preset_set(bmain, brush, GP_BRUSH_PRESET_GRAB_STROKE);
+ brush = gpencil_brush_ensure(bmain, ts, "Grab Stroke", OB_MODE_SCULPT_GPENCIL, &r_new);
+ if ((reset) || (r_new)) {
+ BKE_gpencil_brush_preset_set(bmain, brush, GP_BRUSH_PRESET_GRAB_STROKE);
+ }
/* Push brush. */
- brush = gpencil_brush_ensure(bmain, ts, "Push Stroke", OB_MODE_SCULPT_GPENCIL);
- BKE_gpencil_brush_preset_set(bmain, brush, GP_BRUSH_PRESET_PUSH_STROKE);
+ brush = gpencil_brush_ensure(bmain, ts, "Push Stroke", OB_MODE_SCULPT_GPENCIL, &r_new);
+ if ((reset) || (r_new)) {
+ BKE_gpencil_brush_preset_set(bmain, brush, GP_BRUSH_PRESET_PUSH_STROKE);
+ }
/* Twist brush. */
- brush = gpencil_brush_ensure(bmain, ts, "Twist Stroke", OB_MODE_SCULPT_GPENCIL);
- BKE_gpencil_brush_preset_set(bmain, brush, GP_BRUSH_PRESET_TWIST_STROKE);
+ brush = gpencil_brush_ensure(bmain, ts, "Twist Stroke", OB_MODE_SCULPT_GPENCIL, &r_new);
+ if ((reset) || (r_new)) {
+ BKE_gpencil_brush_preset_set(bmain, brush, GP_BRUSH_PRESET_TWIST_STROKE);
+ }
/* Pinch brush. */
- brush = gpencil_brush_ensure(bmain, ts, "Pinch Stroke", OB_MODE_SCULPT_GPENCIL);
- BKE_gpencil_brush_preset_set(bmain, brush, GP_BRUSH_PRESET_PINCH_STROKE);
+ brush = gpencil_brush_ensure(bmain, ts, "Pinch Stroke", OB_MODE_SCULPT_GPENCIL, &r_new);
+ if ((reset) || (r_new)) {
+ BKE_gpencil_brush_preset_set(bmain, brush, GP_BRUSH_PRESET_PINCH_STROKE);
+ }
/* Randomize brush. */
- brush = gpencil_brush_ensure(bmain, ts, "Randomize Stroke", OB_MODE_SCULPT_GPENCIL);
- BKE_gpencil_brush_preset_set(bmain, brush, GP_BRUSH_PRESET_RANDOMIZE_STROKE);
+ brush = gpencil_brush_ensure(bmain, ts, "Randomize Stroke", OB_MODE_SCULPT_GPENCIL, &r_new);
+ if ((reset) || (r_new)) {
+ BKE_gpencil_brush_preset_set(bmain, brush, GP_BRUSH_PRESET_RANDOMIZE_STROKE);
+ }
/* Clone brush. */
- brush = gpencil_brush_ensure(bmain, ts, "Clone Stroke", OB_MODE_SCULPT_GPENCIL);
- BKE_gpencil_brush_preset_set(bmain, brush, GP_BRUSH_PRESET_CLONE_STROKE);
+ brush = gpencil_brush_ensure(bmain, ts, "Clone Stroke", OB_MODE_SCULPT_GPENCIL, &r_new);
+ if ((reset) || (r_new)) {
+ BKE_gpencil_brush_preset_set(bmain, brush, GP_BRUSH_PRESET_CLONE_STROKE);
+ }
/* Set default brush. */
- BKE_paint_brush_set(sculptpaint, deft_sculpt);
+ if (reset || brush_prev == NULL) {
+ BKE_paint_brush_set(sculptpaint, deft_sculpt);
+ }
}
/* Create a set of grease pencil Weight Paint presets. */
-void BKE_brush_gpencil_weight_presets(Main *bmain, ToolSettings *ts)
+void BKE_brush_gpencil_weight_presets(Main *bmain, ToolSettings *ts, const bool reset)
{
- Paint *weightpaint = &ts->gp_weightpaint->paint;
+ bool r_new = false;
+ Paint *weightpaint = &ts->gp_weightpaint->paint;
+ Brush *brush_prev = weightpaint->brush;
Brush *brush, *deft_weight;
/* Vertex Draw brush. */
- brush = gpencil_brush_ensure(bmain, ts, "Draw Weight", OB_MODE_WEIGHT_GPENCIL);
- BKE_gpencil_brush_preset_set(bmain, brush, GP_BRUSH_PRESET_DRAW_WEIGHT);
+ brush = gpencil_brush_ensure(bmain, ts, "Draw Weight", OB_MODE_WEIGHT_GPENCIL, &r_new);
+ if ((reset) || (r_new)) {
+ BKE_gpencil_brush_preset_set(bmain, brush, GP_BRUSH_PRESET_DRAW_WEIGHT);
+ }
deft_weight = brush; /* save default brush. */
/* Set default brush. */
- BKE_paint_brush_set(weightpaint, deft_weight);
+ if (reset || brush_prev == NULL) {
+ BKE_paint_brush_set(weightpaint, deft_weight);
+ }
}
struct Brush *BKE_brush_first_search(struct Main *bmain, const eObjectMode ob_mode)
@@ -1398,6 +1564,12 @@ void BKE_brush_sculpt_reset(Brush *br)
br->cloth_deform_type = BRUSH_CLOTH_DEFORM_DRAG;
br->flag &= ~(BRUSH_ALPHA_PRESSURE | BRUSH_SIZE_PRESSURE);
break;
+ case SCULPT_TOOL_LAYER:
+ br->flag &= ~BRUSH_SPACE_ATTEN;
+ br->hardness = 0.35f;
+ br->alpha = 1.0f;
+ br->height = 0.05f;
+ break;
default:
break;
}
@@ -1522,8 +1694,7 @@ float BKE_brush_sample_tex_3d(const Scene *scene,
else if (mtex->brush_map_mode == MTEX_MAP_MODE_3D) {
/* Get strength by feeding the vertex
* location directly into a texture */
- hasrgb = externtex(
- mtex, point, &intensity, rgba, rgba + 1, rgba + 2, rgba + 3, thread, pool, false, false);
+ hasrgb = RE_texture_evaluate(mtex, point, thread, pool, false, false, &intensity, rgba);
}
else if (mtex->brush_map_mode == MTEX_MAP_MODE_STENCIL) {
float rotation = -mtex->rot;
@@ -1553,8 +1724,7 @@ float BKE_brush_sample_tex_3d(const Scene *scene,
co[1] = y;
co[2] = 0.0f;
- hasrgb = externtex(
- mtex, co, &intensity, rgba, rgba + 1, rgba + 2, rgba + 3, thread, pool, false, false);
+ hasrgb = RE_texture_evaluate(mtex, co, thread, pool, false, false, &intensity, rgba);
}
else {
float rotation = -mtex->rot;
@@ -1610,8 +1780,7 @@ float BKE_brush_sample_tex_3d(const Scene *scene,
co[1] = y;
co[2] = 0.0f;
- hasrgb = externtex(
- mtex, co, &intensity, rgba, rgba + 1, rgba + 2, rgba + 3, thread, pool, false, false);
+ hasrgb = RE_texture_evaluate(mtex, co, thread, pool, false, false, &intensity, rgba);
}
intensity += br->texture_sample_bias;
@@ -1668,8 +1837,7 @@ float BKE_brush_sample_masktex(
co[1] = y;
co[2] = 0.0f;
- externtex(
- mtex, co, &intensity, rgba, rgba + 1, rgba + 2, rgba + 3, thread, pool, false, false);
+ RE_texture_evaluate(mtex, co, thread, pool, false, false, &intensity, rgba);
}
else {
float rotation = -mtex->rot;
@@ -1725,8 +1893,7 @@ float BKE_brush_sample_masktex(
co[1] = y;
co[2] = 0.0f;
- externtex(
- mtex, co, &intensity, rgba, rgba + 1, rgba + 2, rgba + 3, thread, pool, false, false);
+ RE_texture_evaluate(mtex, co, thread, pool, false, false, &intensity, rgba);
}
CLAMP(intensity, 0.0f, 1.0f);
@@ -2030,7 +2197,7 @@ unsigned int *BKE_brush_gen_texture_cache(Brush *br, int half_side, bool use_sec
unsigned int *texcache = NULL;
MTex *mtex = (use_secondary) ? &br->mask_mtex : &br->mtex;
float intensity;
- float rgba[4];
+ float rgba_dummy[4];
int ix, iy;
int side = half_side * 2;
@@ -2048,11 +2215,8 @@ unsigned int *BKE_brush_gen_texture_cache(Brush *br, int half_side, bool use_sec
/* This is copied from displace modifier code */
/* TODO(sergey): brush are always caching with CM enabled for now. */
- externtex(mtex, co, &intensity, rgba, rgba + 1, rgba + 2, rgba + 3, 0, NULL, false, false);
-
- ((char *)texcache)[(iy * side + ix) * 4] = ((char *)texcache)[(iy * side + ix) * 4 + 1] =
- ((char *)texcache)[(iy * side + ix) * 4 + 2] = ((
- char *)texcache)[(iy * side + ix) * 4 + 3] = (char)(intensity * 255.0f);
+ RE_texture_evaluate(mtex, co, 0, NULL, false, false, &intensity, rgba_dummy);
+ copy_v4_uchar((uchar *)&texcache[iy * side + ix], (char)(intensity * 255.0f));
}
}
}
diff --git a/source/blender/blenkernel/intern/bvhutils.c b/source/blender/blenkernel/intern/bvhutils.c
index 8f6b8bd6980..93794eb9709 100644
--- a/source/blender/blenkernel/intern/bvhutils.c
+++ b/source/blender/blenkernel/intern/bvhutils.c
@@ -41,8 +41,126 @@
#include "MEM_guardedalloc.h"
-static ThreadRWMutex cache_rwlock = BLI_RWLOCK_INITIALIZER;
+/* -------------------------------------------------------------------- */
+/** \name BVHCache
+ * \{ */
+
+typedef struct BVHCacheItem {
+ bool is_filled;
+ BVHTree *tree;
+} BVHCacheItem;
+
+typedef struct BVHCache {
+ BVHCacheItem items[BVHTREE_MAX_ITEM];
+ ThreadMutex mutex;
+} BVHCache;
+
+/**
+ * Queries a bvhcache for the cache bvhtree of the request type
+ *
+ * When the `r_locked` is filled and the tree could not be found the caches mutex will be
+ * locked. This mutex can be unlocked by calling `bvhcache_unlock`.
+ *
+ * When `r_locked` is used the `mesh_eval_mutex` must contain the `Mesh_Runtime.eval_mutex`.
+ */
+static bool bvhcache_find(BVHCache **bvh_cache_p,
+ BVHCacheType type,
+ BVHTree **r_tree,
+ bool *r_locked,
+ ThreadMutex *mesh_eval_mutex)
+{
+ bool do_lock = r_locked;
+ if (r_locked) {
+ *r_locked = false;
+ }
+ if (*bvh_cache_p == NULL) {
+ if (!do_lock) {
+ /* Cache does not exist and no lock is requested. */
+ return false;
+ }
+ /* Lazy initialization of the bvh_cache using the `mesh_eval_mutex`. */
+ BLI_mutex_lock(mesh_eval_mutex);
+ if (*bvh_cache_p == NULL) {
+ *bvh_cache_p = bvhcache_init();
+ }
+ BLI_mutex_unlock(mesh_eval_mutex);
+ }
+ BVHCache *bvh_cache = *bvh_cache_p;
+ if (bvh_cache->items[type].is_filled) {
+ *r_tree = bvh_cache->items[type].tree;
+ return true;
+ }
+ if (do_lock) {
+ BLI_mutex_lock(&bvh_cache->mutex);
+ bool in_cache = bvhcache_find(bvh_cache_p, type, r_tree, NULL, NULL);
+ if (in_cache) {
+ BLI_mutex_unlock(&bvh_cache->mutex);
+ return in_cache;
+ }
+ *r_locked = true;
+ }
+ return false;
+}
+
+static void bvhcache_unlock(BVHCache *bvh_cache, bool lock_started)
+{
+ if (lock_started) {
+ BLI_mutex_unlock(&bvh_cache->mutex);
+ }
+}
+
+bool bvhcache_has_tree(const BVHCache *bvh_cache, const BVHTree *tree)
+{
+ if (bvh_cache == NULL) {
+ return false;
+ }
+
+ for (BVHCacheType i = 0; i < BVHTREE_MAX_ITEM; i++) {
+ if (bvh_cache->items[i].tree == tree) {
+ return true;
+ }
+ }
+ return false;
+}
+
+BVHCache *bvhcache_init(void)
+{
+ BVHCache *cache = MEM_callocN(sizeof(BVHCache), __func__);
+ BLI_mutex_init(&cache->mutex);
+ return cache;
+}
+/**
+ * Inserts a BVHTree of the given type under the cache
+ * After that the caller no longer needs to worry when to free the BVHTree
+ * as that will be done when the cache is freed.
+ *
+ * A call to this assumes that there was no previous cached tree of the given type
+ * \warning The #BVHTree can be NULL.
+ */
+static void bvhcache_insert(BVHCache *bvh_cache, BVHTree *tree, BVHCacheType type)
+{
+ BVHCacheItem *item = &bvh_cache->items[type];
+ BLI_assert(!item->is_filled);
+ item->tree = tree;
+ item->is_filled = true;
+}
+
+/**
+ * frees a bvhcache
+ */
+void bvhcache_free(BVHCache *bvh_cache)
+{
+ for (BVHCacheType index = 0; index < BVHTREE_MAX_ITEM; index++) {
+ BVHCacheItem *item = &bvh_cache->items[index];
+ BLI_bvhtree_free(item->tree);
+ item->tree = NULL;
+ }
+ BLI_mutex_end(&bvh_cache->mutex);
+ MEM_freeN(bvh_cache);
+}
+
+/** \} */
/* -------------------------------------------------------------------- */
/** \name Local Callbacks
* \{ */
@@ -517,30 +635,27 @@ BVHTree *bvhtree_from_editmesh_verts_ex(BVHTreeFromEditMesh *data,
float epsilon,
int tree_type,
int axis,
- const int bvh_cache_type,
- BVHCache **bvh_cache)
+ const BVHCacheType bvh_cache_type,
+ BVHCache **bvh_cache_p,
+ ThreadMutex *mesh_eval_mutex)
{
BVHTree *tree = NULL;
- if (bvh_cache) {
- BLI_rw_mutex_lock(&cache_rwlock, THREAD_LOCK_READ);
- data->cached = bvhcache_find(*bvh_cache, bvh_cache_type, &data->tree);
- BLI_rw_mutex_unlock(&cache_rwlock);
+ if (bvh_cache_p) {
+ bool lock_started = false;
+ data->cached = bvhcache_find(
+ bvh_cache_p, bvh_cache_type, &data->tree, &lock_started, mesh_eval_mutex);
if (data->cached == false) {
- BLI_rw_mutex_lock(&cache_rwlock, THREAD_LOCK_WRITE);
- data->cached = bvhcache_find(*bvh_cache, bvh_cache_type, &data->tree);
- if (data->cached == false) {
- tree = bvhtree_from_editmesh_verts_create_tree(
- epsilon, tree_type, axis, em, verts_mask, verts_num_active);
-
- /* Save on cache for later use */
- /* printf("BVHTree built and saved on cache\n"); */
- bvhcache_insert(bvh_cache, tree, bvh_cache_type);
- data->cached = true;
- }
- BLI_rw_mutex_unlock(&cache_rwlock);
+ tree = bvhtree_from_editmesh_verts_create_tree(
+ epsilon, tree_type, axis, em, verts_mask, verts_num_active);
+
+ /* Save on cache for later use */
+ /* printf("BVHTree built and saved on cache\n"); */
+ bvhcache_insert(*bvh_cache_p, tree, bvh_cache_type);
+ data->cached = true;
}
+ bvhcache_unlock(*bvh_cache_p, lock_started);
}
else {
tree = bvhtree_from_editmesh_verts_create_tree(
@@ -553,7 +668,7 @@ BVHTree *bvhtree_from_editmesh_verts_ex(BVHTreeFromEditMesh *data,
data->em = em;
data->nearest_callback = NULL;
data->raycast_callback = editmesh_verts_spherecast;
- data->cached = bvh_cache != NULL;
+ data->cached = bvh_cache_p != NULL;
}
return tree;
@@ -562,7 +677,8 @@ BVHTree *bvhtree_from_editmesh_verts_ex(BVHTreeFromEditMesh *data,
BVHTree *bvhtree_from_editmesh_verts(
BVHTreeFromEditMesh *data, BMEditMesh *em, float epsilon, int tree_type, int axis)
{
- return bvhtree_from_editmesh_verts_ex(data, em, NULL, -1, epsilon, tree_type, axis, 0, NULL);
+ return bvhtree_from_editmesh_verts_ex(
+ data, em, NULL, -1, epsilon, tree_type, axis, 0, NULL, NULL);
}
/**
@@ -581,33 +697,27 @@ BVHTree *bvhtree_from_mesh_verts_ex(BVHTreeFromMesh *data,
float epsilon,
int tree_type,
int axis,
- const int bvh_cache_type,
- BVHCache **bvh_cache)
+ const BVHCacheType bvh_cache_type,
+ BVHCache **bvh_cache_p,
+ ThreadMutex *mesh_eval_mutex)
{
bool in_cache = false;
+ bool lock_started = false;
BVHTree *tree = NULL;
- if (bvh_cache) {
- BLI_rw_mutex_lock(&cache_rwlock, THREAD_LOCK_READ);
- in_cache = bvhcache_find(*bvh_cache, bvh_cache_type, &tree);
- BLI_rw_mutex_unlock(&cache_rwlock);
- if (in_cache == false) {
- BLI_rw_mutex_lock(&cache_rwlock, THREAD_LOCK_WRITE);
- in_cache = bvhcache_find(*bvh_cache, bvh_cache_type, &tree);
- if (in_cache) {
- BLI_rw_mutex_unlock(&cache_rwlock);
- }
- }
+ if (bvh_cache_p) {
+ in_cache = bvhcache_find(bvh_cache_p, bvh_cache_type, &tree, &lock_started, mesh_eval_mutex);
}
if (in_cache == false) {
tree = bvhtree_from_mesh_verts_create_tree(
epsilon, tree_type, axis, vert, verts_num, verts_mask, verts_num_active);
- if (bvh_cache) {
+ if (bvh_cache_p) {
/* Save on cache for later use */
/* printf("BVHTree built and saved on cache\n"); */
+ BVHCache *bvh_cache = *bvh_cache_p;
bvhcache_insert(bvh_cache, tree, bvh_cache_type);
- BLI_rw_mutex_unlock(&cache_rwlock);
+ bvhcache_unlock(bvh_cache, lock_started);
in_cache = true;
}
}
@@ -734,30 +844,27 @@ BVHTree *bvhtree_from_editmesh_edges_ex(BVHTreeFromEditMesh *data,
float epsilon,
int tree_type,
int axis,
- const int bvh_cache_type,
- BVHCache **bvh_cache)
+ const BVHCacheType bvh_cache_type,
+ BVHCache **bvh_cache_p,
+ ThreadMutex *mesh_eval_mutex)
{
BVHTree *tree = NULL;
- if (bvh_cache) {
- BLI_rw_mutex_lock(&cache_rwlock, THREAD_LOCK_READ);
- data->cached = bvhcache_find(*bvh_cache, bvh_cache_type, &data->tree);
- BLI_rw_mutex_unlock(&cache_rwlock);
-
+ if (bvh_cache_p) {
+ bool lock_started = false;
+ data->cached = bvhcache_find(
+ bvh_cache_p, bvh_cache_type, &data->tree, &lock_started, mesh_eval_mutex);
+ BVHCache *bvh_cache = *bvh_cache_p;
if (data->cached == false) {
- BLI_rw_mutex_lock(&cache_rwlock, THREAD_LOCK_WRITE);
- data->cached = bvhcache_find(*bvh_cache, bvh_cache_type, &data->tree);
- if (data->cached == false) {
- tree = bvhtree_from_editmesh_edges_create_tree(
- epsilon, tree_type, axis, em, edges_mask, edges_num_active);
-
- /* Save on cache for later use */
- /* printf("BVHTree built and saved on cache\n"); */
- bvhcache_insert(bvh_cache, tree, bvh_cache_type);
- data->cached = true;
- }
- BLI_rw_mutex_unlock(&cache_rwlock);
+ tree = bvhtree_from_editmesh_edges_create_tree(
+ epsilon, tree_type, axis, em, edges_mask, edges_num_active);
+
+ /* Save on cache for later use */
+ /* printf("BVHTree built and saved on cache\n"); */
+ bvhcache_insert(bvh_cache, tree, bvh_cache_type);
+ data->cached = true;
}
+ bvhcache_unlock(bvh_cache, lock_started);
}
else {
tree = bvhtree_from_editmesh_edges_create_tree(
@@ -770,7 +877,7 @@ BVHTree *bvhtree_from_editmesh_edges_ex(BVHTreeFromEditMesh *data,
data->em = em;
data->nearest_callback = NULL; /* TODO */
data->raycast_callback = NULL; /* TODO */
- data->cached = bvh_cache != NULL;
+ data->cached = bvh_cache_p != NULL;
}
return tree;
@@ -779,7 +886,8 @@ BVHTree *bvhtree_from_editmesh_edges_ex(BVHTreeFromEditMesh *data,
BVHTree *bvhtree_from_editmesh_edges(
BVHTreeFromEditMesh *data, BMEditMesh *em, float epsilon, int tree_type, int axis)
{
- return bvhtree_from_editmesh_edges_ex(data, em, NULL, -1, epsilon, tree_type, axis, 0, NULL);
+ return bvhtree_from_editmesh_edges_ex(
+ data, em, NULL, -1, epsilon, tree_type, axis, 0, NULL, NULL);
}
/**
@@ -801,33 +909,27 @@ BVHTree *bvhtree_from_mesh_edges_ex(BVHTreeFromMesh *data,
float epsilon,
int tree_type,
int axis,
- const int bvh_cache_type,
- BVHCache **bvh_cache)
+ const BVHCacheType bvh_cache_type,
+ BVHCache **bvh_cache_p,
+ ThreadMutex *mesh_eval_mutex)
{
bool in_cache = false;
+ bool lock_started = false;
BVHTree *tree = NULL;
- if (bvh_cache) {
- BLI_rw_mutex_lock(&cache_rwlock, THREAD_LOCK_READ);
- in_cache = bvhcache_find(*bvh_cache, bvh_cache_type, &tree);
- BLI_rw_mutex_unlock(&cache_rwlock);
- if (in_cache == false) {
- BLI_rw_mutex_lock(&cache_rwlock, THREAD_LOCK_WRITE);
- in_cache = bvhcache_find(*bvh_cache, bvh_cache_type, &tree);
- if (in_cache) {
- BLI_rw_mutex_unlock(&cache_rwlock);
- }
- }
+ if (bvh_cache_p) {
+ in_cache = bvhcache_find(bvh_cache_p, bvh_cache_type, &tree, &lock_started, mesh_eval_mutex);
}
if (in_cache == false) {
tree = bvhtree_from_mesh_edges_create_tree(
vert, edge, edges_num, edges_mask, edges_num_active, epsilon, tree_type, axis);
- if (bvh_cache) {
+ if (bvh_cache_p) {
+ BVHCache *bvh_cache = *bvh_cache_p;
/* Save on cache for later use */
/* printf("BVHTree built and saved on cache\n"); */
bvhcache_insert(bvh_cache, tree, bvh_cache_type);
- BLI_rw_mutex_unlock(&cache_rwlock);
+ bvhcache_unlock(bvh_cache, lock_started);
in_cache = true;
}
}
@@ -936,33 +1038,27 @@ BVHTree *bvhtree_from_mesh_faces_ex(BVHTreeFromMesh *data,
float epsilon,
int tree_type,
int axis,
- const int bvh_cache_type,
- BVHCache **bvh_cache)
+ const BVHCacheType bvh_cache_type,
+ BVHCache **bvh_cache_p,
+ ThreadMutex *mesh_eval_mutex)
{
bool in_cache = false;
+ bool lock_started = false;
BVHTree *tree = NULL;
- if (bvh_cache) {
- BLI_rw_mutex_lock(&cache_rwlock, THREAD_LOCK_READ);
- in_cache = bvhcache_find(*bvh_cache, bvh_cache_type, &tree);
- BLI_rw_mutex_unlock(&cache_rwlock);
- if (in_cache == false) {
- BLI_rw_mutex_lock(&cache_rwlock, THREAD_LOCK_WRITE);
- in_cache = bvhcache_find(*bvh_cache, bvh_cache_type, &tree);
- if (in_cache) {
- BLI_rw_mutex_unlock(&cache_rwlock);
- }
- }
+ if (bvh_cache_p) {
+ in_cache = bvhcache_find(bvh_cache_p, bvh_cache_type, &tree, &lock_started, mesh_eval_mutex);
}
if (in_cache == false) {
tree = bvhtree_from_mesh_faces_create_tree(
epsilon, tree_type, axis, vert, face, numFaces, faces_mask, faces_num_active);
- if (bvh_cache) {
+ if (bvh_cache_p) {
/* Save on cache for later use */
/* printf("BVHTree built and saved on cache\n"); */
+ BVHCache *bvh_cache = *bvh_cache_p;
bvhcache_insert(bvh_cache, tree, bvh_cache_type);
- BLI_rw_mutex_unlock(&cache_rwlock);
+ bvhcache_unlock(bvh_cache, lock_started);
in_cache = true;
}
}
@@ -1112,30 +1208,29 @@ BVHTree *bvhtree_from_editmesh_looptri_ex(BVHTreeFromEditMesh *data,
float epsilon,
int tree_type,
int axis,
- const int bvh_cache_type,
- BVHCache **bvh_cache)
+ const BVHCacheType bvh_cache_type,
+ BVHCache **bvh_cache_p,
+ ThreadMutex *mesh_eval_mutex)
{
/* BMESH specific check that we have tessfaces,
* we _could_ tessellate here but rather not - campbell */
BVHTree *tree = NULL;
- if (bvh_cache) {
- BLI_rw_mutex_lock(&cache_rwlock, THREAD_LOCK_READ);
- bool in_cache = bvhcache_find(*bvh_cache, bvh_cache_type, &tree);
- BLI_rw_mutex_unlock(&cache_rwlock);
+ if (bvh_cache_p) {
+ bool lock_started = false;
+ bool in_cache = bvhcache_find(
+ bvh_cache_p, bvh_cache_type, &tree, &lock_started, mesh_eval_mutex);
+ BVHCache *bvh_cache = *bvh_cache_p;
+
if (in_cache == false) {
- BLI_rw_mutex_lock(&cache_rwlock, THREAD_LOCK_WRITE);
- in_cache = bvhcache_find(*bvh_cache, bvh_cache_type, &tree);
- if (in_cache == false) {
- tree = bvhtree_from_editmesh_looptri_create_tree(
- epsilon, tree_type, axis, em, looptri_mask, looptri_num_active);
-
- /* Save on cache for later use */
- /* printf("BVHTree built and saved on cache\n"); */
- bvhcache_insert(bvh_cache, tree, bvh_cache_type);
- }
- BLI_rw_mutex_unlock(&cache_rwlock);
+ tree = bvhtree_from_editmesh_looptri_create_tree(
+ epsilon, tree_type, axis, em, looptri_mask, looptri_num_active);
+
+ /* Save on cache for later use */
+ /* printf("BVHTree built and saved on cache\n"); */
+ bvhcache_insert(bvh_cache, tree, bvh_cache_type);
}
+ bvhcache_unlock(bvh_cache, lock_started);
}
else {
tree = bvhtree_from_editmesh_looptri_create_tree(
@@ -1147,7 +1242,7 @@ BVHTree *bvhtree_from_editmesh_looptri_ex(BVHTreeFromEditMesh *data,
data->nearest_callback = editmesh_looptri_nearest_point;
data->raycast_callback = editmesh_looptri_spherecast;
data->em = em;
- data->cached = bvh_cache != NULL;
+ data->cached = bvh_cache_p != NULL;
}
return tree;
}
@@ -1155,7 +1250,8 @@ BVHTree *bvhtree_from_editmesh_looptri_ex(BVHTreeFromEditMesh *data,
BVHTree *bvhtree_from_editmesh_looptri(
BVHTreeFromEditMesh *data, BMEditMesh *em, float epsilon, int tree_type, int axis)
{
- return bvhtree_from_editmesh_looptri_ex(data, em, NULL, -1, epsilon, tree_type, axis, 0, NULL);
+ return bvhtree_from_editmesh_looptri_ex(
+ data, em, NULL, -1, epsilon, tree_type, axis, 0, NULL, NULL);
}
/**
@@ -1176,22 +1272,15 @@ BVHTree *bvhtree_from_mesh_looptri_ex(BVHTreeFromMesh *data,
float epsilon,
int tree_type,
int axis,
- const int bvh_cache_type,
- BVHCache **bvh_cache)
+ const BVHCacheType bvh_cache_type,
+ BVHCache **bvh_cache_p,
+ ThreadMutex *mesh_eval_mutex)
{
bool in_cache = false;
+ bool lock_started = false;
BVHTree *tree = NULL;
- if (bvh_cache) {
- BLI_rw_mutex_lock(&cache_rwlock, THREAD_LOCK_READ);
- in_cache = bvhcache_find(*bvh_cache, bvh_cache_type, &tree);
- BLI_rw_mutex_unlock(&cache_rwlock);
- if (in_cache == false) {
- BLI_rw_mutex_lock(&cache_rwlock, THREAD_LOCK_WRITE);
- in_cache = bvhcache_find(*bvh_cache, bvh_cache_type, &tree);
- if (in_cache) {
- BLI_rw_mutex_unlock(&cache_rwlock);
- }
- }
+ if (bvh_cache_p) {
+ in_cache = bvhcache_find(bvh_cache_p, bvh_cache_type, &tree, &lock_started, mesh_eval_mutex);
}
if (in_cache == false) {
@@ -1206,9 +1295,10 @@ BVHTree *bvhtree_from_mesh_looptri_ex(BVHTreeFromMesh *data,
looptri_mask,
looptri_num_active);
- if (bvh_cache) {
+ if (bvh_cache_p) {
+ BVHCache *bvh_cache = *bvh_cache_p;
bvhcache_insert(bvh_cache, tree, bvh_cache_type);
- BLI_rw_mutex_unlock(&cache_rwlock);
+ bvhcache_unlock(bvh_cache, lock_started);
in_cache = true;
}
}
@@ -1311,15 +1401,14 @@ static BLI_bitmap *looptri_no_hidden_map_get(const MPoly *mpoly,
*/
BVHTree *BKE_bvhtree_from_mesh_get(struct BVHTreeFromMesh *data,
struct Mesh *mesh,
- const int bvh_cache_type,
+ const BVHCacheType bvh_cache_type,
const int tree_type)
{
BVHTree *tree = NULL;
- BVHCache **bvh_cache = &mesh->runtime.bvh_cache;
+ BVHCache **bvh_cache_p = (BVHCache **)&mesh->runtime.bvh_cache;
+ ThreadMutex *mesh_eval_mutex = (ThreadMutex *)mesh->runtime.eval_mutex;
- BLI_rw_mutex_lock(&cache_rwlock, THREAD_LOCK_READ);
- bool is_cached = bvhcache_find(*bvh_cache, bvh_cache_type, &tree);
- BLI_rw_mutex_unlock(&cache_rwlock);
+ bool is_cached = bvhcache_find(bvh_cache_p, bvh_cache_type, &tree, NULL, NULL);
if (is_cached && tree == NULL) {
memset(data, 0, sizeof(*data));
@@ -1351,7 +1440,8 @@ BVHTree *BKE_bvhtree_from_mesh_get(struct BVHTreeFromMesh *data,
tree_type,
6,
bvh_cache_type,
- bvh_cache);
+ bvh_cache_p,
+ mesh_eval_mutex);
if (loose_verts_mask != NULL) {
MEM_freeN(loose_verts_mask);
@@ -1386,7 +1476,8 @@ BVHTree *BKE_bvhtree_from_mesh_get(struct BVHTreeFromMesh *data,
tree_type,
6,
bvh_cache_type,
- bvh_cache);
+ bvh_cache_p,
+ mesh_eval_mutex);
if (loose_edges_mask != NULL) {
MEM_freeN(loose_edges_mask);
@@ -1416,7 +1507,8 @@ BVHTree *BKE_bvhtree_from_mesh_get(struct BVHTreeFromMesh *data,
tree_type,
6,
bvh_cache_type,
- bvh_cache);
+ bvh_cache_p,
+ mesh_eval_mutex);
}
else {
/* Setup BVHTreeFromMesh */
@@ -1452,7 +1544,8 @@ BVHTree *BKE_bvhtree_from_mesh_get(struct BVHTreeFromMesh *data,
tree_type,
6,
bvh_cache_type,
- bvh_cache);
+ bvh_cache_p,
+ mesh_eval_mutex);
}
else {
/* Setup BVHTreeFromMesh */
@@ -1464,6 +1557,7 @@ BVHTree *BKE_bvhtree_from_mesh_get(struct BVHTreeFromMesh *data,
case BVHTREE_FROM_EM_VERTS:
case BVHTREE_FROM_EM_EDGES:
case BVHTREE_FROM_EM_LOOPTRI:
+ case BVHTREE_MAX_ITEM:
BLI_assert(false);
break;
}
@@ -1492,18 +1586,17 @@ BVHTree *BKE_bvhtree_from_mesh_get(struct BVHTreeFromMesh *data,
BVHTree *BKE_bvhtree_from_editmesh_get(BVHTreeFromEditMesh *data,
struct BMEditMesh *em,
const int tree_type,
- const int bvh_cache_type,
- BVHCache **bvh_cache)
+ const BVHCacheType bvh_cache_type,
+ BVHCache **bvh_cache_p,
+ ThreadMutex *mesh_eval_mutex)
{
BVHTree *tree = NULL;
bool is_cached = false;
memset(data, 0, sizeof(*data));
- if (bvh_cache) {
- BLI_rw_mutex_lock(&cache_rwlock, THREAD_LOCK_READ);
- is_cached = bvhcache_find(*bvh_cache, bvh_cache_type, &tree);
- BLI_rw_mutex_unlock(&cache_rwlock);
+ if (bvh_cache_p) {
+ is_cached = bvhcache_find(bvh_cache_p, bvh_cache_type, &tree, NULL, NULL);
if (is_cached && tree == NULL) {
return tree;
@@ -1517,7 +1610,7 @@ BVHTree *BKE_bvhtree_from_editmesh_get(BVHTreeFromEditMesh *data,
case BVHTREE_FROM_EM_VERTS:
if (is_cached == false) {
tree = bvhtree_from_editmesh_verts_ex(
- data, em, NULL, -1, 0.0f, tree_type, 6, bvh_cache_type, bvh_cache);
+ data, em, NULL, -1, 0.0f, tree_type, 6, bvh_cache_type, bvh_cache_p, mesh_eval_mutex);
}
else {
data->nearest_callback = NULL;
@@ -1528,7 +1621,7 @@ BVHTree *BKE_bvhtree_from_editmesh_get(BVHTreeFromEditMesh *data,
case BVHTREE_FROM_EM_EDGES:
if (is_cached == false) {
tree = bvhtree_from_editmesh_edges_ex(
- data, em, NULL, -1, 0.0f, tree_type, 6, bvh_cache_type, bvh_cache);
+ data, em, NULL, -1, 0.0f, tree_type, 6, bvh_cache_type, bvh_cache_p, mesh_eval_mutex);
}
else {
/* Setup BVHTreeFromMesh */
@@ -1540,7 +1633,7 @@ BVHTree *BKE_bvhtree_from_editmesh_get(BVHTreeFromEditMesh *data,
case BVHTREE_FROM_EM_LOOPTRI:
if (is_cached == false) {
tree = bvhtree_from_editmesh_looptri_ex(
- data, em, NULL, -1, 0.0f, tree_type, 6, bvh_cache_type, bvh_cache);
+ data, em, NULL, -1, 0.0f, tree_type, 6, bvh_cache_type, bvh_cache_p, mesh_eval_mutex);
}
else {
/* Setup BVHTreeFromMesh */
@@ -1555,6 +1648,7 @@ BVHTree *BKE_bvhtree_from_editmesh_get(BVHTreeFromEditMesh *data,
case BVHTREE_FROM_LOOPTRI_NO_HIDDEN:
case BVHTREE_FROM_LOOSEVERTS:
case BVHTREE_FROM_LOOSEEDGES:
+ case BVHTREE_MAX_ITEM:
BLI_assert(false);
break;
}
@@ -1615,82 +1709,3 @@ void free_bvhtree_from_mesh(struct BVHTreeFromMesh *data)
memset(data, 0, sizeof(*data));
}
-
-/* -------------------------------------------------------------------- */
-/** \name BVHCache
- * \{ */
-
-typedef struct BVHCacheItem {
- int type;
- BVHTree *tree;
-
-} BVHCacheItem;
-
-/**
- * Queries a bvhcache for the cache bvhtree of the request type
- */
-bool bvhcache_find(const BVHCache *cache, int type, BVHTree **r_tree)
-{
- while (cache) {
- const BVHCacheItem *item = cache->link;
- if (item->type == type) {
- *r_tree = item->tree;
- return true;
- }
- cache = cache->next;
- }
- return false;
-}
-
-bool bvhcache_has_tree(const BVHCache *cache, const BVHTree *tree)
-{
- while (cache) {
- const BVHCacheItem *item = cache->link;
- if (item->tree == tree) {
- return true;
- }
- cache = cache->next;
- }
- return false;
-}
-
-/**
- * Inserts a BVHTree of the given type under the cache
- * After that the caller no longer needs to worry when to free the BVHTree
- * as that will be done when the cache is freed.
- *
- * A call to this assumes that there was no previous cached tree of the given type
- * \warning The #BVHTree can be NULL.
- */
-void bvhcache_insert(BVHCache **cache_p, BVHTree *tree, int type)
-{
- BVHCacheItem *item = NULL;
-
- BLI_assert(bvhcache_find(*cache_p, type, &(BVHTree *){0}) == false);
-
- item = MEM_mallocN(sizeof(BVHCacheItem), "BVHCacheItem");
-
- item->type = type;
- item->tree = tree;
-
- BLI_linklist_prepend(cache_p, item);
-}
-
-/**
- * frees a bvhcache
- */
-static void bvhcacheitem_free(void *_item)
-{
- BVHCacheItem *item = (BVHCacheItem *)_item;
-
- BLI_bvhtree_free(item->tree);
- MEM_freeN(item);
-}
-
-void bvhcache_free(BVHCache **cache_p)
-{
- BLI_linklist_free(*cache_p, (LinkNodeFreeFP)bvhcacheitem_free);
- *cache_p = NULL;
-}
-
-/** \} */
diff --git a/source/blender/blenkernel/intern/cachefile.c b/source/blender/blenkernel/intern/cachefile.c
index 605fba18d89..da9dab36044 100644
--- a/source/blender/blenkernel/intern/cachefile.c
+++ b/source/blender/blenkernel/intern/cachefile.c
@@ -39,7 +39,6 @@
#include "BLT_translation.h"
-#include "BKE_animsys.h"
#include "BKE_cachefile.h"
#include "BKE_idtype.h"
#include "BKE_lib_id.h"
@@ -98,6 +97,7 @@ IDTypeInfo IDType_ID_CF = {
.copy_data = cache_file_copy_data,
.free_data = cache_file_free_data,
.make_local = NULL,
+ .foreach_id = NULL,
};
/* TODO: make this per cache file to avoid global locks. */
diff --git a/source/blender/blenkernel/intern/camera.c b/source/blender/blenkernel/intern/camera.c
index 30c2822e08b..5ec4c84c013 100644
--- a/source/blender/blenkernel/intern/camera.c
+++ b/source/blender/blenkernel/intern/camera.c
@@ -38,11 +38,11 @@
#include "BLI_string.h"
#include "BLI_utildefines.h"
-#include "BKE_animsys.h"
#include "BKE_camera.h"
#include "BKE_idtype.h"
#include "BKE_layer.h"
#include "BKE_lib_id.h"
+#include "BKE_lib_query.h"
#include "BKE_main.h"
#include "BKE_object.h"
#include "BKE_scene.h"
@@ -64,17 +64,6 @@ static void camera_init_data(ID *id)
MEMCPY_STRUCT_AFTER(cam, DNA_struct_default_get(Camera), id);
}
-void *BKE_camera_add(Main *bmain, const char *name)
-{
- Camera *cam;
-
- cam = BKE_libblock_alloc(bmain, ID_CA, name, 0);
-
- camera_init_data(&cam->id);
-
- return cam;
-}
-
/**
* Only copy internal data of Camera ID from source
* to already allocated/initialized destination.
@@ -95,13 +84,6 @@ static void camera_copy_data(Main *UNUSED(bmain),
BLI_duplicatelist(&cam_dst->bg_images, &cam_src->bg_images);
}
-Camera *BKE_camera_copy(Main *bmain, const Camera *cam)
-{
- Camera *cam_copy;
- BKE_id_copy(bmain, &cam->id, (ID **)&cam_copy);
- return cam_copy;
-}
-
static void camera_make_local(Main *bmain, ID *id, const int flags)
{
BKE_lib_id_make_local_generic(bmain, id, flags);
@@ -114,6 +96,21 @@ static void camera_free_data(ID *id)
BLI_freelistN(&cam->bg_images);
}
+static void camera_foreach_id(ID *id, LibraryForeachIDData *data)
+{
+ Camera *camera = (Camera *)id;
+
+ BKE_LIB_FOREACHID_PROCESS(data, camera->dof.focus_object, IDWALK_CB_NOP);
+ LISTBASE_FOREACH (CameraBGImage *, bgpic, &camera->bg_images) {
+ if (bgpic->source == CAM_BGIMG_SOURCE_IMAGE) {
+ BKE_LIB_FOREACHID_PROCESS(data, bgpic->ima, IDWALK_CB_USER);
+ }
+ else if (bgpic->source == CAM_BGIMG_SOURCE_MOVIE) {
+ BKE_LIB_FOREACHID_PROCESS(data, bgpic->clip, IDWALK_CB_USER);
+ }
+ }
+}
+
IDTypeInfo IDType_ID_CA = {
.id_code = ID_CA,
.id_filter = FILTER_ID_CA,
@@ -128,10 +125,29 @@ IDTypeInfo IDType_ID_CA = {
.copy_data = camera_copy_data,
.free_data = camera_free_data,
.make_local = camera_make_local,
+ .foreach_id = camera_foreach_id,
};
/******************************** Camera Usage *******************************/
+void *BKE_camera_add(Main *bmain, const char *name)
+{
+ Camera *cam;
+
+ cam = BKE_libblock_alloc(bmain, ID_CA, name, 0);
+
+ camera_init_data(&cam->id);
+
+ return cam;
+}
+
+Camera *BKE_camera_copy(Main *bmain, const Camera *cam)
+{
+ Camera *cam_copy;
+ BKE_id_copy(bmain, &cam->id, (ID **)&cam_copy);
+ return cam_copy;
+}
+
/* get the camera's dof value, takes the dof object into account */
float BKE_camera_object_dof_distance(Object *ob)
{
@@ -913,7 +929,7 @@ static Object *camera_multiview_advanced(const Scene *scene, Object *camera, con
name[0] = '\0';
/* we need to take the better match, thus the len_suffix_max test */
- for (const SceneRenderView *srv = scene->r.views.first; srv; srv = srv->next) {
+ LISTBASE_FOREACH (const SceneRenderView *, srv, &scene->r.views) {
const int len_suffix = strlen(srv->suffix);
if ((len_suffix < len_suffix_max) || (len_name < len_suffix)) {
diff --git a/source/blender/blenkernel/intern/cdderivedmesh.c b/source/blender/blenkernel/intern/cdderivedmesh.c
index 8a0df6375be..879313783d9 100644
--- a/source/blender/blenkernel/intern/cdderivedmesh.c
+++ b/source/blender/blenkernel/intern/cdderivedmesh.c
@@ -10,7 +10,7 @@
* 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,
+ * 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) 2006 Blender Foundation.
diff --git a/source/blender/blenkernel/intern/cloth.c b/source/blender/blenkernel/intern/cloth.c
index 0a35c9879b7..0b9780ac81c 100644
--- a/source/blender/blenkernel/intern/cloth.c
+++ b/source/blender/blenkernel/intern/cloth.c
@@ -333,13 +333,13 @@ static int do_init_cloth(Object *ob, ClothModifierData *clmd, Mesh *result, int
if (clmd->clothObject == NULL) {
if (!cloth_from_object(ob, clmd, result, framenr, 1)) {
BKE_ptcache_invalidate(cache);
- modifier_setError(&(clmd->modifier), "Can't initialize cloth");
+ BKE_modifier_set_error(&(clmd->modifier), "Can't initialize cloth");
return 0;
}
if (clmd->clothObject == NULL) {
BKE_ptcache_invalidate(cache);
- modifier_setError(&(clmd->modifier), "Null cloth object");
+ BKE_modifier_set_error(&(clmd->modifier), "Null cloth object");
return 0;
}
@@ -394,7 +394,7 @@ static int do_step_cloth(
cloth_apply_vgroup(clmd, result);
if ((clmd->sim_parms->flags & CLOTH_SIMSETTINGS_FLAG_DYNAMIC_BASEMESH) ||
- (clmd->sim_parms->vgroup_shrink > 0) || (clmd->sim_parms->shrink_min > 0.0f)) {
+ (clmd->sim_parms->vgroup_shrink > 0) || (clmd->sim_parms->shrink_min != 0.0f)) {
cloth_update_spring_lengths(clmd, result);
}
@@ -841,7 +841,7 @@ static int cloth_from_object(
clmd->clothObject->edgeset = NULL;
}
else {
- modifier_setError(&(clmd->modifier), "Out of memory on allocating clmd->clothObject");
+ BKE_modifier_set_error(&(clmd->modifier), "Out of memory on allocating clmd->clothObject");
return 0;
}
@@ -913,7 +913,7 @@ static int cloth_from_object(
if (!cloth_build_springs(clmd, mesh)) {
cloth_free_modifier(clmd);
- modifier_setError(&(clmd->modifier), "Cannot build springs");
+ BKE_modifier_set_error(&(clmd->modifier), "Cannot build springs");
return 0;
}
@@ -943,7 +943,8 @@ static void cloth_from_mesh(ClothModifierData *clmd, Mesh *mesh)
"clothVertex");
if (clmd->clothObject->verts == NULL) {
cloth_free_modifier(clmd);
- modifier_setError(&(clmd->modifier), "Out of memory on allocating clmd->clothObject->verts");
+ BKE_modifier_set_error(&(clmd->modifier),
+ "Out of memory on allocating clmd->clothObject->verts");
printf("cloth_free_modifier clmd->clothObject->verts\n");
return;
}
@@ -959,7 +960,8 @@ static void cloth_from_mesh(ClothModifierData *clmd, Mesh *mesh)
clmd->clothObject->tri = MEM_mallocN(sizeof(MVertTri) * looptri_num, "clothLoopTris");
if (clmd->clothObject->tri == NULL) {
cloth_free_modifier(clmd);
- modifier_setError(&(clmd->modifier), "Out of memory on allocating clmd->clothObject->looptri");
+ BKE_modifier_set_error(&(clmd->modifier),
+ "Out of memory on allocating clmd->clothObject->looptri");
printf("cloth_free_modifier clmd->clothObject->looptri\n");
return;
}
diff --git a/source/blender/blenkernel/intern/collection.c b/source/blender/blenkernel/intern/collection.c
index d39df4cc6a3..e8e3e61ced4 100644
--- a/source/blender/blenkernel/intern/collection.c
+++ b/source/blender/blenkernel/intern/collection.c
@@ -34,6 +34,7 @@
#include "BKE_idtype.h"
#include "BKE_layer.h"
#include "BKE_lib_id.h"
+#include "BKE_lib_query.h"
#include "BKE_lib_remap.h"
#include "BKE_main.h"
#include "BKE_object.h"
@@ -106,10 +107,10 @@ static void collection_copy_data(Main *bmain, ID *id_dst, const ID *id_src, cons
BLI_listbase_clear(&collection_dst->children);
BLI_listbase_clear(&collection_dst->parents);
- for (CollectionChild *child = collection_src->children.first; child; child = child->next) {
+ LISTBASE_FOREACH (CollectionChild *, child, &collection_src->children) {
collection_child_add(collection_dst, child->collection, flag, false);
}
- for (CollectionObject *cob = collection_src->gobject.first; cob; cob = cob->next) {
+ LISTBASE_FOREACH (CollectionObject *, cob, &collection_src->gobject) {
collection_object_add(bmain, collection_dst, cob->ob, flag, false);
}
}
@@ -128,6 +129,28 @@ static void collection_free_data(ID *id)
BKE_collection_object_cache_free(collection);
}
+static void collection_foreach_id(ID *id, LibraryForeachIDData *data)
+{
+ Collection *collection = (Collection *)id;
+
+ LISTBASE_FOREACH (CollectionObject *, cob, &collection->gobject) {
+ BKE_LIB_FOREACHID_PROCESS(data, cob->ob, IDWALK_CB_USER);
+ }
+ LISTBASE_FOREACH (CollectionChild *, child, &collection->children) {
+ BKE_LIB_FOREACHID_PROCESS(data, child->collection, IDWALK_CB_NEVER_SELF | IDWALK_CB_USER);
+ }
+ LISTBASE_FOREACH (CollectionParent *, parent, &collection->parents) {
+ /* XXX This is very weak. The whole idea of keeping pointers to private IDs is very bad
+ * anyway... */
+ const int cb_flag = ((parent->collection != NULL &&
+ (parent->collection->id.flag & LIB_EMBEDDED_DATA) != 0) ?
+ IDWALK_CB_EMBEDDED :
+ IDWALK_CB_NOP);
+ BKE_LIB_FOREACHID_PROCESS(
+ data, parent->collection, IDWALK_CB_NEVER_SELF | IDWALK_CB_LOOPBACK | cb_flag);
+ }
+}
+
IDTypeInfo IDType_ID_GR = {
.id_code = ID_GR,
.id_filter = FILTER_ID_GR,
@@ -142,6 +165,7 @@ IDTypeInfo IDType_ID_GR = {
.copy_data = collection_copy_data,
.free_data = collection_free_data,
.make_local = NULL,
+ .foreach_id = collection_foreach_id,
};
/***************************** Add Collection *******************************/
@@ -186,6 +210,34 @@ Collection *BKE_collection_add(Main *bmain, Collection *collection_parent, const
return collection;
}
+/**
+ * Add \a collection_dst to all scene collections that reference object \a ob_src is in.
+ * Used to replace an instance object with a collection (library override operator).
+ *
+ * Logic is very similar to #BKE_collection_object_add_from().
+ */
+void BKE_collection_add_from_object(Main *bmain,
+ Scene *scene,
+ const Object *ob_src,
+ Collection *collection_dst)
+{
+ bool is_instantiated = false;
+
+ FOREACH_SCENE_COLLECTION_BEGIN (scene, collection) {
+ if (!ID_IS_LINKED(collection) && BKE_collection_has_object(collection, ob_src)) {
+ collection_child_add(collection, collection_dst, 0, true);
+ is_instantiated = true;
+ }
+ }
+ FOREACH_SCENE_COLLECTION_END;
+
+ if (!is_instantiated) {
+ collection_child_add(scene->master_collection, collection_dst, 0, true);
+ }
+
+ BKE_main_collection_sync(bmain);
+}
+
/*********************** Free and Delete Collection ****************************/
/** Free (or release) any data used by this collection (does not free the collection itself). */
@@ -223,9 +275,8 @@ bool BKE_collection_delete(Main *bmain, Collection *collection, bool hierarchy)
}
else {
/* Link child collections into parent collection. */
- for (CollectionChild *child = collection->children.first; child; child = child->next) {
- for (CollectionParent *cparent = collection->parents.first; cparent;
- cparent = cparent->next) {
+ LISTBASE_FOREACH (CollectionChild *, child, &collection->children) {
+ LISTBASE_FOREACH (CollectionParent *, cparent, &collection->parents) {
Collection *parent = cparent->collection;
collection_child_add(parent, child->collection, 0, true);
}
@@ -234,8 +285,7 @@ bool BKE_collection_delete(Main *bmain, Collection *collection, bool hierarchy)
CollectionObject *cob = collection->gobject.first;
while (cob != NULL) {
/* Link child object into parent collections. */
- for (CollectionParent *cparent = collection->parents.first; cparent;
- cparent = cparent->next) {
+ LISTBASE_FOREACH (CollectionParent *, cparent, &collection->parents) {
Collection *parent = cparent->collection;
collection_object_add(bmain, parent, cob->ob, 0, true);
}
@@ -305,7 +355,7 @@ static Collection *collection_duplicate_recursive(Main *bmain,
if (do_objects) {
/* We can loop on collection_old's objects, that list is currently identical the collection_new
* objects, and won't be changed here. */
- for (CollectionObject *cob = collection_old->gobject.first; cob; cob = cob->next) {
+ LISTBASE_FOREACH (CollectionObject *, cob, &collection_old->gobject) {
Object *ob_old = cob->ob;
Object *ob_new = (Object *)ob_old->id.newid;
@@ -321,7 +371,7 @@ static Collection *collection_duplicate_recursive(Main *bmain,
/* We can loop on collection_old's children,
* that list is currently identical the collection_new' children, and won't be changed here. */
- for (CollectionChild *child = collection_old->children.first; child; child = child->next) {
+ LISTBASE_FOREACH (CollectionChild *, child, &collection_old->children) {
Collection *child_collection_old = child->collection;
collection_duplicate_recursive(
@@ -440,7 +490,7 @@ static void collection_object_cache_fill(ListBase *lb, Collection *collection, i
{
int child_restrict = collection->flag | parent_restrict;
- for (CollectionObject *cob = collection->gobject.first; cob; cob = cob->next) {
+ LISTBASE_FOREACH (CollectionObject *, cob, &collection->gobject) {
Base *base = BLI_findptr(lb, cob->ob, offsetof(Base, object));
if (base == NULL) {
@@ -460,7 +510,7 @@ static void collection_object_cache_fill(ListBase *lb, Collection *collection, i
}
}
- for (CollectionChild *child = collection->children.first; child; child = child->next) {
+ LISTBASE_FOREACH (CollectionChild *, child, &collection->children) {
collection_object_cache_fill(lb, child->collection, child_restrict);
}
}
@@ -487,7 +537,7 @@ static void collection_object_cache_free(Collection *collection)
collection->flag &= ~COLLECTION_HAS_OBJECT_CACHE;
BLI_freelistN(&collection->object_cache);
- for (CollectionParent *parent = collection->parents.first; parent; parent = parent->next) {
+ LISTBASE_FOREACH (CollectionParent *, parent, &collection->parents) {
collection_object_cache_free(parent->collection);
}
}
@@ -645,8 +695,7 @@ static void collection_tag_update_parent_recursive(Main *bmain,
DEG_id_tag_update_ex(bmain, &collection->id, flag);
- for (CollectionParent *collection_parent = collection->parents.first; collection_parent;
- collection_parent = collection_parent->next) {
+ LISTBASE_FOREACH (CollectionParent *, collection_parent, &collection->parents) {
if (collection_parent->collection->flag & COLLECTION_IS_MASTER) {
/* We don't care about scene/master collection here. */
continue;
@@ -660,7 +709,8 @@ static bool collection_object_add(
{
if (ob->instance_collection) {
/* Cyclic dependency check. */
- if (collection_find_child_recursive(ob->instance_collection, collection)) {
+ if (collection_find_child_recursive(ob->instance_collection, collection) ||
+ ob->instance_collection == collection) {
return false;
}
}
@@ -736,8 +786,10 @@ bool BKE_collection_object_add(Main *bmain, Collection *collection, Object *ob)
}
/**
- * Add object to all scene collections that reference object is in
- * (used to copy objects).
+ * Add \a ob_dst to all scene collections that reference object \a ob_src is in.
+ * Used for copying objects.
+ *
+ * Logic is very similar to #BKE_collection_add_from_object()
*/
void BKE_collection_object_add_from(Main *bmain, Scene *scene, Object *ob_src, Object *ob_dst)
{
@@ -952,7 +1004,7 @@ bool BKE_collection_is_in_scene(Collection *collection)
return true;
}
- for (CollectionParent *cparent = collection->parents.first; cparent; cparent = cparent->next) {
+ LISTBASE_FOREACH (CollectionParent *, cparent, &collection->parents) {
if (BKE_collection_is_in_scene(cparent->collection)) {
return true;
}
@@ -977,7 +1029,7 @@ bool BKE_collection_find_cycle(Collection *new_ancestor, Collection *collection)
return true;
}
- for (CollectionParent *parent = new_ancestor->parents.first; parent; parent = parent->next) {
+ LISTBASE_FOREACH (CollectionParent *, parent, &new_ancestor->parents) {
if (BKE_collection_find_cycle(parent->collection, collection)) {
return true;
}
@@ -993,7 +1045,7 @@ static CollectionChild *collection_find_child(Collection *parent, Collection *co
static bool collection_find_child_recursive(Collection *parent, Collection *collection)
{
- for (CollectionChild *child = parent->children.first; child; child = child->next) {
+ LISTBASE_FOREACH (CollectionChild *, child, &parent->children) {
if (child->collection == collection) {
return true;
}
@@ -1168,7 +1220,7 @@ static Collection *collection_from_index_recursive(Collection *collection,
(*index_current)++;
- for (CollectionChild *child = collection->children.first; child; child = child->next) {
+ LISTBASE_FOREACH (CollectionChild *, child, &collection->children) {
Collection *nested = collection_from_index_recursive(child->collection, index, index_current);
if (nested != NULL) {
return nested;
@@ -1197,7 +1249,7 @@ static bool collection_objects_select(ViewLayer *view_layer, Collection *collect
return false;
}
- for (CollectionObject *cob = collection->gobject.first; cob; cob = cob->next) {
+ LISTBASE_FOREACH (CollectionObject *, cob, &collection->gobject) {
Base *base = BKE_view_layer_base_find(view_layer, cob->ob);
if (base) {
@@ -1216,7 +1268,7 @@ static bool collection_objects_select(ViewLayer *view_layer, Collection *collect
}
}
- for (CollectionChild *child = collection->children.first; child; child = child->next) {
+ LISTBASE_FOREACH (CollectionChild *, child, &collection->children) {
if (collection_objects_select(view_layer, collection, deselect)) {
changed = true;
}
@@ -1289,8 +1341,7 @@ bool BKE_collection_move(Main *bmain,
GHash *view_layer_hash = BLI_ghash_new(BLI_ghashutil_ptrhash, BLI_ghashutil_ptrcmp, __func__);
for (Scene *scene = bmain->scenes.first; scene; scene = scene->id.next) {
- for (ViewLayer *view_layer = scene->view_layers.first; view_layer;
- view_layer = view_layer->next) {
+ LISTBASE_FOREACH (ViewLayer *, view_layer, &scene->view_layers) {
LayerCollection *layer_collection = BKE_layer_collection_first_from_scene_collection(
view_layer, collection);
@@ -1352,7 +1403,7 @@ static void scene_collection_callback(Collection *collection,
{
callback(collection, data);
- for (CollectionChild *child = collection->children.first; child; child = child->next) {
+ LISTBASE_FOREACH (CollectionChild *, child, &collection->children) {
scene_collection_callback(child->collection, callback, data);
}
}
diff --git a/source/blender/blenkernel/intern/collision.c b/source/blender/blenkernel/intern/collision.c
index 9230746cd1d..daf1602319f 100644
--- a/source/blender/blenkernel/intern/collision.c
+++ b/source/blender/blenkernel/intern/collision.c
@@ -1307,7 +1307,7 @@ static void add_collision_object(ListBase *relations,
/* only get objects with collision modifier */
if (((modifier_type == eModifierType_Collision) && ob->pd && ob->pd->deflect) ||
(modifier_type != eModifierType_Collision)) {
- cmd = (CollisionModifierData *)modifiers_findByType(ob, modifier_type);
+ cmd = (CollisionModifierData *)BKE_modifiers_findby_type(ob, modifier_type);
}
if (cmd) {
@@ -1380,7 +1380,7 @@ Object **BKE_collision_objects_create(Depsgraph *depsgraph,
int num = 0;
Object **objects = MEM_callocN(sizeof(Object *) * maxnum, __func__);
- for (CollisionRelation *relation = relations->first; relation; relation = relation->next) {
+ LISTBASE_FOREACH (CollisionRelation *, relation, relations) {
/* Get evaluated object. */
Object *ob = (Object *)DEG_get_evaluated_id(depsgraph, &relation->ob->id);
@@ -1418,7 +1418,7 @@ ListBase *BKE_collider_cache_create(Depsgraph *depsgraph, Object *self, Collecti
return NULL;
}
- for (CollisionRelation *relation = relations->first; relation; relation = relation->next) {
+ LISTBASE_FOREACH (CollisionRelation *, relation, relations) {
/* Get evaluated object. */
Object *ob = (Object *)DEG_get_evaluated_id(depsgraph, &relation->ob->id);
@@ -1426,7 +1426,7 @@ ListBase *BKE_collider_cache_create(Depsgraph *depsgraph, Object *self, Collecti
continue;
}
- CollisionModifierData *cmd = (CollisionModifierData *)modifiers_findByType(
+ CollisionModifierData *cmd = (CollisionModifierData *)BKE_modifiers_findby_type(
ob, eModifierType_Collision);
if (cmd && cmd->bvhtree) {
if (cache == NULL) {
@@ -1527,7 +1527,7 @@ static int cloth_bvh_objcollisions_resolve(ClothModifierData *clmd,
for (i = 0; i < numcollobj; i++) {
Object *collob = collobjs[i];
- CollisionModifierData *collmd = (CollisionModifierData *)modifiers_findByType(
+ CollisionModifierData *collmd = (CollisionModifierData *)BKE_modifiers_findby_type(
collob, eModifierType_Collision);
if (collmd->bvhtree) {
@@ -1658,7 +1658,7 @@ int cloth_bvh_collision(
for (i = 0; i < numcollobj; i++) {
Object *collob = collobjs[i];
- CollisionModifierData *collmd = (CollisionModifierData *)modifiers_findByType(
+ CollisionModifierData *collmd = (CollisionModifierData *)BKE_modifiers_findby_type(
collob, eModifierType_Collision);
if (!collmd->bvhtree) {
@@ -1693,7 +1693,7 @@ int cloth_bvh_collision(
for (i = 0; i < numcollobj; i++) {
Object *collob = collobjs[i];
- CollisionModifierData *collmd = (CollisionModifierData *)modifiers_findByType(
+ CollisionModifierData *collmd = (CollisionModifierData *)BKE_modifiers_findby_type(
collob, eModifierType_Collision);
if (!collmd->bvhtree) {
diff --git a/source/blender/blenkernel/intern/colortools.c b/source/blender/blenkernel/intern/colortools.c
index 315035c1bc2..3da384a2745 100644
--- a/source/blender/blenkernel/intern/colortools.c
+++ b/source/blender/blenkernel/intern/colortools.c
@@ -1383,8 +1383,6 @@ typedef struct ScopesUpdateData {
struct ColormanageProcessor *cm_processor;
const unsigned char *display_buffer;
const int ycc_mode;
-
- unsigned int *bin_lum, *bin_r, *bin_g, *bin_b, *bin_a;
} ScopesUpdateData;
typedef struct ScopesUpdateDataChunk {
@@ -1495,23 +1493,24 @@ static void scopes_update_cb(void *__restrict userdata,
}
}
-static void scopes_update_finalize(void *__restrict userdata, void *__restrict userdata_chunk)
+static void scopes_update_reduce(const void *__restrict UNUSED(userdata),
+ void *__restrict chunk_join,
+ void *__restrict chunk)
{
- const ScopesUpdateData *data = userdata;
- const ScopesUpdateDataChunk *data_chunk = userdata_chunk;
-
- unsigned int *bin_lum = data->bin_lum;
- unsigned int *bin_r = data->bin_r;
- unsigned int *bin_g = data->bin_g;
- unsigned int *bin_b = data->bin_b;
- unsigned int *bin_a = data->bin_a;
+ ScopesUpdateDataChunk *join_chunk = chunk_join;
+ const ScopesUpdateDataChunk *data_chunk = chunk;
+
+ unsigned int *bin_lum = join_chunk->bin_lum;
+ unsigned int *bin_r = join_chunk->bin_r;
+ unsigned int *bin_g = join_chunk->bin_g;
+ unsigned int *bin_b = join_chunk->bin_b;
+ unsigned int *bin_a = join_chunk->bin_a;
const unsigned int *bin_lum_c = data_chunk->bin_lum;
const unsigned int *bin_r_c = data_chunk->bin_r;
const unsigned int *bin_g_c = data_chunk->bin_g;
const unsigned int *bin_b_c = data_chunk->bin_b;
const unsigned int *bin_a_c = data_chunk->bin_a;
- float(*minmax)[2] = data->scopes->minmax;
const float *min = data_chunk->min;
const float *max = data_chunk->max;
@@ -1524,11 +1523,11 @@ static void scopes_update_finalize(void *__restrict userdata, void *__restrict u
}
for (int c = 3; c--;) {
- if (min[c] < minmax[c][0]) {
- minmax[c][0] = min[c];
+ if (min[c] < join_chunk->min[c]) {
+ join_chunk->min[c] = min[c];
}
- if (max[c] > minmax[c][1]) {
- minmax[c][1] = max[c];
+ if (max[c] > join_chunk->max[c]) {
+ join_chunk->max[c] = max[c];
}
}
}
@@ -1542,7 +1541,6 @@ void BKE_scopes_update(Scopes *scopes,
unsigned int nl, na, nr, ng, nb;
double divl, diva, divr, divg, divb;
const unsigned char *display_buffer = NULL;
- uint bin_lum[256] = {0}, bin_r[256] = {0}, bin_g[256] = {0}, bin_b[256] = {0}, bin_a[256] = {0};
int ycc_mode = -1;
void *cache_handle = NULL;
struct ColormanageProcessor *cm_processor = NULL;
@@ -1638,11 +1636,6 @@ void BKE_scopes_update(Scopes *scopes,
.cm_processor = cm_processor,
.display_buffer = display_buffer,
.ycc_mode = ycc_mode,
- .bin_lum = bin_lum,
- .bin_r = bin_r,
- .bin_g = bin_g,
- .bin_b = bin_b,
- .bin_a = bin_a,
};
ScopesUpdateDataChunk data_chunk = {{0}};
INIT_MINMAX(data_chunk.min, data_chunk.max);
@@ -1652,26 +1645,26 @@ void BKE_scopes_update(Scopes *scopes,
settings.use_threading = (ibuf->y > 256);
settings.userdata_chunk = &data_chunk;
settings.userdata_chunk_size = sizeof(data_chunk);
- settings.func_finalize = scopes_update_finalize;
+ settings.func_reduce = scopes_update_reduce;
BLI_task_parallel_range(0, ibuf->y, &data, scopes_update_cb, &settings);
/* convert hist data to float (proportional to max count) */
nl = na = nr = nb = ng = 0;
for (a = 0; a < 256; a++) {
- if (bin_lum[a] > nl) {
- nl = bin_lum[a];
+ if (data_chunk.bin_lum[a] > nl) {
+ nl = data_chunk.bin_lum[a];
}
- if (bin_r[a] > nr) {
- nr = bin_r[a];
+ if (data_chunk.bin_r[a] > nr) {
+ nr = data_chunk.bin_r[a];
}
- if (bin_g[a] > ng) {
- ng = bin_g[a];
+ if (data_chunk.bin_g[a] > ng) {
+ ng = data_chunk.bin_g[a];
}
- if (bin_b[a] > nb) {
- nb = bin_b[a];
+ if (data_chunk.bin_b[a] > nb) {
+ nb = data_chunk.bin_b[a];
}
- if (bin_a[a] > na) {
- na = bin_a[a];
+ if (data_chunk.bin_a[a] > na) {
+ na = data_chunk.bin_a[a];
}
}
divl = nl ? 1.0 / (double)nl : 1.0;
@@ -1681,11 +1674,11 @@ void BKE_scopes_update(Scopes *scopes,
divb = nb ? 1.0 / (double)nb : 1.0;
for (a = 0; a < 256; a++) {
- scopes->hist.data_luma[a] = bin_lum[a] * divl;
- scopes->hist.data_r[a] = bin_r[a] * divr;
- scopes->hist.data_g[a] = bin_g[a] * divg;
- scopes->hist.data_b[a] = bin_b[a] * divb;
- scopes->hist.data_a[a] = bin_a[a] * diva;
+ scopes->hist.data_luma[a] = data_chunk.bin_lum[a] * divl;
+ scopes->hist.data_r[a] = data_chunk.bin_r[a] * divr;
+ scopes->hist.data_g[a] = data_chunk.bin_g[a] * divg;
+ scopes->hist.data_b[a] = data_chunk.bin_b[a] * divb;
+ scopes->hist.data_a[a] = data_chunk.bin_a[a] * diva;
}
if (cm_processor) {
@@ -1805,6 +1798,7 @@ void BKE_color_managed_view_settings_free(ColorManagedViewSettings *settings)
{
if (settings->curve_mapping) {
BKE_curvemapping_free(settings->curve_mapping);
+ settings->curve_mapping = NULL;
}
}
diff --git a/source/blender/blenkernel/intern/constraint.c b/source/blender/blenkernel/intern/constraint.c
index 45e2ff10ba4..050e8d434ae 100644
--- a/source/blender/blenkernel/intern/constraint.c
+++ b/source/blender/blenkernel/intern/constraint.c
@@ -52,7 +52,7 @@
#include "DNA_tracking_types.h"
#include "BKE_action.h"
-#include "BKE_anim.h" /* for the curve calculation part */
+#include "BKE_anim_path.h"
#include "BKE_armature.h"
#include "BKE_bvhutils.h"
#include "BKE_cachefile.h"
@@ -62,7 +62,7 @@
#include "BKE_deform.h"
#include "BKE_displist.h"
#include "BKE_editmesh.h"
-#include "BKE_fcurve.h"
+#include "BKE_fcurve_driver.h"
#include "BKE_global.h"
#include "BKE_idprop.h"
#include "BKE_lib_id.h"
@@ -472,9 +472,9 @@ static void contarget_get_mesh_mat(Object *ob, const char *substring, float mat[
/* derive the rotation from the average normal:
* - code taken from transform_gizmo.c,
- * calc_gizmo_stats, V3D_ORIENT_NORMAL case
- */
- /* we need the transpose of the inverse for a normal... */
+ * calc_gizmo_stats, V3D_ORIENT_NORMAL case */
+
+ /* We need the transpose of the inverse for a normal. */
copy_m3_m4(imat, ob->obmat);
invert_m3_m3(tmat, imat);
@@ -577,7 +577,7 @@ static void constraint_target_to_mat4(Object *ob,
copy_m4_m4(mat, ob->obmat);
BKE_constraint_mat_convertspace(ob, NULL, mat, from, to, false);
}
- /* Case VERTEXGROUP */
+ /* Case VERTEXGROUP */
/* Current method just takes the average location of all the points in the
* VertexGroup, and uses that as the location value of the targets. Where
* possible, the orientation will also be calculated, by calculating an
@@ -894,55 +894,68 @@ static void childof_evaluate(bConstraint *con, bConstraintOb *cob, ListBase *tar
}
float parmat[4][4];
+ float inverse_matrix[4][4];
/* Simple matrix parenting. */
if ((data->flag & CHILDOF_ALL) == CHILDOF_ALL) {
copy_m4_m4(parmat, ct->matrix);
+ copy_m4_m4(inverse_matrix, data->invmat);
}
/* Filter the parent matrix by channel. */
else {
float loc[3], eul[3], size[3];
+ float loco[3], eulo[3], sizeo[3];
/* extract components of both matrices */
copy_v3_v3(loc, ct->matrix[3]);
mat4_to_eulO(eul, ct->rotOrder, ct->matrix);
mat4_to_size(size, ct->matrix);
- /* disable channels not enabled */
+ copy_v3_v3(loco, data->invmat[3]);
+ mat4_to_eulO(eulo, cob->rotOrder, data->invmat);
+ mat4_to_size(sizeo, data->invmat);
+
+ /* Reset the locked channels to their no-op values. */
if (!(data->flag & CHILDOF_LOCX)) {
- loc[0] = 0.0f;
+ loc[0] = loco[0] = 0.0f;
}
if (!(data->flag & CHILDOF_LOCY)) {
- loc[1] = 0.0f;
+ loc[1] = loco[1] = 0.0f;
}
if (!(data->flag & CHILDOF_LOCZ)) {
- loc[2] = 0.0f;
+ loc[2] = loco[2] = 0.0f;
}
if (!(data->flag & CHILDOF_ROTX)) {
- eul[0] = 0.0f;
+ eul[0] = eulo[0] = 0.0f;
}
if (!(data->flag & CHILDOF_ROTY)) {
- eul[1] = 0.0f;
+ eul[1] = eulo[1] = 0.0f;
}
if (!(data->flag & CHILDOF_ROTZ)) {
- eul[2] = 0.0f;
+ eul[2] = eulo[2] = 0.0f;
}
if (!(data->flag & CHILDOF_SIZEX)) {
- size[0] = 1.0f;
+ size[0] = sizeo[0] = 1.0f;
}
if (!(data->flag & CHILDOF_SIZEY)) {
- size[1] = 1.0f;
+ size[1] = sizeo[1] = 1.0f;
}
if (!(data->flag & CHILDOF_SIZEZ)) {
- size[2] = 1.0f;
+ size[2] = sizeo[2] = 1.0f;
}
- /* make new target mat and offset mat */
+ /* Construct the new matrices given the disabled channels. */
loc_eulO_size_to_mat4(parmat, loc, eul, size, ct->rotOrder);
+ loc_eulO_size_to_mat4(inverse_matrix, loco, eulo, sizeo, cob->rotOrder);
}
- /* Compute the inverse matrix if requested. */
+ /* If requested, compute the inverse matrix from the computed parent matrix. */
if (data->flag & CHILDOF_SET_INVERSE) {
invert_m4_m4(data->invmat, parmat);
+ if (cob->pchan != NULL) {
+ mul_m4_series(data->invmat, data->invmat, cob->ob->obmat);
+ }
+
+ copy_m4_m4(inverse_matrix, data->invmat);
data->flag &= ~CHILDOF_SET_INVERSE;
@@ -962,7 +975,7 @@ static void childof_evaluate(bConstraint *con, bConstraintOb *cob, ListBase *tar
* (i.e. owner is 'parented' to parent). */
float orig_cob_matrix[4][4];
copy_m4_m4(orig_cob_matrix, cob->matrix);
- mul_m4_series(cob->matrix, parmat, data->invmat, orig_cob_matrix);
+ mul_m4_series(cob->matrix, parmat, inverse_matrix, orig_cob_matrix);
/* Without this, changes to scale and rotation can change location
* of a parentless bone or a disconnected bone. Even though its set
@@ -1000,8 +1013,8 @@ static void trackto_new_data(void *cdata)
{
bTrackToConstraint *data = (bTrackToConstraint *)cdata;
- data->reserved1 = TRACK_Y;
- data->reserved2 = UP_Z;
+ data->reserved1 = TRACK_nZ;
+ data->reserved2 = UP_Y;
}
static void trackto_id_looper(bConstraint *con, ConstraintIDFunc func, void *userdata)
@@ -2513,7 +2526,7 @@ static void armdef_evaluate(bConstraint *con, bConstraintOb *cob, ListBase *targ
/* Process all targets. This can't use ct->matrix, as armdef_get_tarmat is not
* called in solve for efficiency because the constraint needs bone data anyway. */
- for (bConstraintTarget *ct = targets->first; ct; ct = ct->next) {
+ LISTBASE_FOREACH (bConstraintTarget *, ct, targets) {
if (ct->weight <= 0.0f) {
continue;
}
@@ -4581,230 +4594,390 @@ static void followtrack_id_looper(bConstraint *con, ConstraintIDFunc func, void
func(con, (ID **)&data->depth_ob, false, userdata);
}
-static void followtrack_evaluate(bConstraint *con, bConstraintOb *cob, ListBase *UNUSED(targets))
+static MovieClip *followtrack_tracking_clip_get(bConstraint *con, bConstraintOb *cob)
{
- Depsgraph *depsgraph = cob->depsgraph;
- Scene *scene = cob->scene;
bFollowTrackConstraint *data = con->data;
- MovieClip *clip = data->clip;
+
+ if (data->flag & FOLLOWTRACK_ACTIVECLIP) {
+ Scene *scene = cob->scene;
+ return scene->clip;
+ }
+
+ return data->clip;
+}
+
+static MovieTrackingObject *followtrack_tracking_object_get(bConstraint *con, bConstraintOb *cob)
+{
+ MovieClip *clip = followtrack_tracking_clip_get(con, cob);
+ MovieTracking *tracking = &clip->tracking;
+ bFollowTrackConstraint *data = con->data;
+
+ if (data->object[0]) {
+ return BKE_tracking_object_get_named(tracking, data->object);
+ }
+ return BKE_tracking_object_get_camera(tracking);
+}
+
+static Object *followtrack_camera_object_get(bConstraint *con, bConstraintOb *cob)
+{
+ bFollowTrackConstraint *data = con->data;
+
+ if (data->camera == NULL) {
+ Scene *scene = cob->scene;
+ return scene->camera;
+ }
+
+ return data->camera;
+}
+
+typedef struct FollowTrackContext {
+ int flag;
+ int frame_method;
+
+ Depsgraph *depsgraph;
+ Scene *scene;
+
+ MovieClip *clip;
+ Object *camera_object;
+ Object *depth_object;
+
MovieTracking *tracking;
- MovieTrackingTrack *track;
MovieTrackingObject *tracking_object;
- Object *camob = data->camera ? data->camera : scene->camera;
+ MovieTrackingTrack *track;
- float ctime = DEG_get_ctime(depsgraph);
- float framenr;
+ float depsgraph_time;
+ float clip_frame;
+} FollowTrackContext;
- if (data->flag & FOLLOWTRACK_ACTIVECLIP) {
- clip = scene->clip;
- }
+static bool followtrack_context_init(FollowTrackContext *context,
+ bConstraint *con,
+ bConstraintOb *cob)
+{
+ bFollowTrackConstraint *data = con->data;
- if (!clip || !data->track[0] || !camob) {
- return;
+ context->flag = data->flag;
+ context->frame_method = data->frame_method;
+
+ context->depsgraph = cob->depsgraph;
+ context->scene = cob->scene;
+
+ context->clip = followtrack_tracking_clip_get(con, cob);
+ context->camera_object = followtrack_camera_object_get(con, cob);
+ if (context->clip == NULL || context->camera_object == NULL) {
+ return false;
}
+ context->depth_object = data->depth_ob;
- tracking = &clip->tracking;
+ context->tracking = &context->clip->tracking;
+ context->tracking_object = followtrack_tracking_object_get(con, cob);
+ if (context->tracking_object == NULL) {
+ return false;
+ }
- if (data->object[0]) {
- tracking_object = BKE_tracking_object_get_named(tracking, data->object);
+ context->track = BKE_tracking_track_get_named(
+ context->tracking, context->tracking_object, data->track);
+ if (context->track == NULL) {
+ return false;
}
- else {
- tracking_object = BKE_tracking_object_get_camera(tracking);
+
+ context->depsgraph_time = DEG_get_ctime(context->depsgraph);
+ context->clip_frame = BKE_movieclip_remap_scene_to_clip_frame(context->clip,
+ context->depsgraph_time);
+
+ return true;
+}
+
+static void followtrack_evaluate_using_3d_position_object(FollowTrackContext *context,
+ bConstraintOb *cob)
+{
+ Object *camera_object = context->camera_object;
+ MovieTracking *tracking = context->tracking;
+ MovieTrackingTrack *track = context->track;
+ MovieTrackingObject *tracking_object = context->tracking_object;
+
+ /* Matrix of the object which is being solved prior to this constraint. */
+ float obmat[4][4];
+ copy_m4_m4(obmat, cob->matrix);
+
+ /* Object matrix of the camera. */
+ float camera_obmat[4][4];
+ copy_m4_m4(camera_obmat, camera_object->obmat);
+
+ /* Calculate inverted matrix of the solved camera at the current time. */
+ float reconstructed_camera_mat[4][4];
+ BKE_tracking_camera_get_reconstructed_interpolate(
+ tracking, tracking_object, context->clip_frame, reconstructed_camera_mat);
+ float reconstructed_camera_mat_inv[4][4];
+ invert_m4_m4(reconstructed_camera_mat_inv, reconstructed_camera_mat);
+
+ mul_m4_series(cob->matrix, obmat, camera_obmat, reconstructed_camera_mat_inv);
+ translate_m4(cob->matrix, track->bundle_pos[0], track->bundle_pos[1], track->bundle_pos[2]);
+}
+
+static void followtrack_evaluate_using_3d_position_camera(FollowTrackContext *context,
+ bConstraintOb *cob)
+{
+ Object *camera_object = context->camera_object;
+ MovieTrackingTrack *track = context->track;
+
+ /* Matrix of the object which is being solved prior to this constraint. */
+ float obmat[4][4];
+ copy_m4_m4(obmat, cob->matrix);
+
+ float reconstructed_camera_mat[4][4];
+ BKE_tracking_get_camera_object_matrix(camera_object, reconstructed_camera_mat);
+
+ mul_m4_m4m4(cob->matrix, obmat, reconstructed_camera_mat);
+ translate_m4(cob->matrix, track->bundle_pos[0], track->bundle_pos[1], track->bundle_pos[2]);
+}
+
+static void followtrack_evaluate_using_3d_position(FollowTrackContext *context, bConstraintOb *cob)
+{
+ MovieTrackingTrack *track = context->track;
+ if ((track->flag & TRACK_HAS_BUNDLE) == 0) {
+ return;
}
- if (!tracking_object) {
+ if ((context->tracking_object->flag & TRACKING_OBJECT_CAMERA) == 0) {
+ followtrack_evaluate_using_3d_position_object(context, cob);
return;
}
- track = BKE_tracking_track_get_named(tracking, tracking_object, data->track);
+ followtrack_evaluate_using_3d_position_camera(context, cob);
+}
- if (!track) {
+/* Apply undistortion if it is enabled in constraint settings. */
+static void followtrack_undistort_if_needed(FollowTrackContext *context,
+ const int clip_width,
+ const int clip_height,
+ float marker_position[2])
+{
+ if ((context->flag & FOLLOWTRACK_USE_UNDISTORTION) == 0) {
return;
}
- framenr = BKE_movieclip_remap_scene_to_clip_frame(clip, ctime);
+ /* Undistortion need to happen in pixel space. */
+ marker_position[0] *= clip_width;
+ marker_position[1] *= clip_height;
- if (data->flag & FOLLOWTRACK_USE_3D_POSITION) {
- if (track->flag & TRACK_HAS_BUNDLE) {
- float obmat[4][4], mat[4][4];
+ BKE_tracking_undistort_v2(
+ context->tracking, clip_width, clip_height, marker_position, marker_position);
- copy_m4_m4(obmat, cob->matrix);
+ /* Normalize pixel coordinates back. */
+ marker_position[0] /= clip_width;
+ marker_position[1] /= clip_height;
+}
- if ((tracking_object->flag & TRACKING_OBJECT_CAMERA) == 0) {
- float imat[4][4];
+/* Modify the marker position matching the frame fitting method. */
+static void followtrack_fit_frame(FollowTrackContext *context,
+ const int clip_width,
+ const int clip_height,
+ float marker_position[2])
+{
+ if (context->frame_method == FOLLOWTRACK_FRAME_STRETCH) {
+ return;
+ }
- copy_m4_m4(mat, camob->obmat);
+ Scene *scene = context->scene;
+ MovieClip *clip = context->clip;
- BKE_tracking_camera_get_reconstructed_interpolate(
- tracking, tracking_object, framenr, imat);
- invert_m4(imat);
+ /* apply clip display aspect */
+ const float w_src = clip_width * clip->aspx;
+ const float h_src = clip_height * clip->aspy;
- mul_m4_series(cob->matrix, obmat, mat, imat);
- translate_m4(
- cob->matrix, track->bundle_pos[0], track->bundle_pos[1], track->bundle_pos[2]);
- }
- else {
- BKE_tracking_get_camera_object_matrix(camob, mat);
+ const float w_dst = scene->r.xsch * scene->r.xasp;
+ const float h_dst = scene->r.ysch * scene->r.yasp;
- mul_m4_m4m4(cob->matrix, obmat, mat);
- translate_m4(
- cob->matrix, track->bundle_pos[0], track->bundle_pos[1], track->bundle_pos[2]);
- }
- }
+ const float asp_src = w_src / h_src;
+ const float asp_dst = w_dst / h_dst;
+
+ if (fabsf(asp_src - asp_dst) < FLT_EPSILON) {
+ return;
+ }
+
+ if ((asp_src > asp_dst) == (context->frame_method == FOLLOWTRACK_FRAME_CROP)) {
+ /* fit X */
+ float div = asp_src / asp_dst;
+ float cent = (float)clip_width / 2.0f;
+
+ marker_position[0] = (((marker_position[0] * clip_width - cent) * div) + cent) / clip_width;
}
else {
- float vec[3], disp[3], axis[3], mat[4][4];
- float aspect = (scene->r.xsch * scene->r.xasp) / (scene->r.ysch * scene->r.yasp);
- float len, d;
+ /* fit Y */
+ float div = asp_dst / asp_src;
+ float cent = (float)clip_height / 2.0f;
- BKE_object_where_is_calc_mat4(camob, mat);
+ marker_position[1] = (((marker_position[1] * clip_height - cent) * div) + cent) / clip_height;
+ }
+}
- /* camera axis */
- vec[0] = 0.0f;
- vec[1] = 0.0f;
- vec[2] = 1.0f;
- mul_v3_m4v3(axis, mat, vec);
+/* Effectively this is a Z-depth of the object form the movie clip camera.
+ * The idea is to preserve this depth while moving the object in 2D. */
+static float followtrack_distance_from_viewplane_get(FollowTrackContext *context,
+ bConstraintOb *cob)
+{
+ Object *camera_object = context->camera_object;
- /* distance to projection plane */
- copy_v3_v3(vec, cob->matrix[3]);
- sub_v3_v3(vec, mat[3]);
- project_v3_v3v3(disp, vec, axis);
+ float camera_matrix[4][4];
+ BKE_object_where_is_calc_mat4(camera_object, camera_matrix);
- len = len_v3(disp);
+ const float z_axis[3] = {0.0f, 0.0f, 1.0f};
- if (len > FLT_EPSILON) {
- CameraParams params;
- int width, height;
- float pos[2], rmat[4][4];
+ /* Direction of camera's local Z axis in the world space. */
+ float camera_axis[3];
+ mul_v3_mat3_m4v3(camera_axis, camera_matrix, z_axis);
- BKE_movieclip_get_size(clip, NULL, &width, &height);
- BKE_tracking_marker_get_subframe_position(track, framenr, pos);
+ /* Distance to projection plane. */
+ float vec[3];
+ copy_v3_v3(vec, cob->matrix[3]);
+ sub_v3_v3(vec, camera_matrix[3]);
- if (data->flag & FOLLOWTRACK_USE_UNDISTORTION) {
- /* Undistortion need to happen in pixel space. */
- pos[0] *= width;
- pos[1] *= height;
+ float projection[3];
+ project_v3_v3v3(projection, vec, camera_axis);
- BKE_tracking_undistort_v2(tracking, pos, pos);
+ return len_v3(projection);
+}
- /* Normalize pixel coordinates back. */
- pos[0] /= width;
- pos[1] /= height;
- }
+/* For the evaluated constraint object project it to the surface of the depth object. */
+static void followtrack_project_to_depth_object_if_needed(FollowTrackContext *context,
+ bConstraintOb *cob)
+{
+ if (context->depth_object == NULL) {
+ return;
+ }
- /* aspect correction */
- if (data->frame_method != FOLLOWTRACK_FRAME_STRETCH) {
- float w_src, h_src, w_dst, h_dst, asp_src, asp_dst;
+ Object *depth_object = context->depth_object;
+ Mesh *depth_mesh = BKE_object_get_evaluated_mesh(depth_object);
+ if (depth_mesh == NULL) {
+ return;
+ }
- /* apply clip display aspect */
- w_src = width * clip->aspx;
- h_src = height * clip->aspy;
+ float depth_object_mat_inv[4][4];
+ invert_m4_m4(depth_object_mat_inv, depth_object->obmat);
- w_dst = scene->r.xsch * scene->r.xasp;
- h_dst = scene->r.ysch * scene->r.yasp;
+ float ray_start[3], ray_end[3];
+ mul_v3_m4v3(ray_start, depth_object_mat_inv, context->camera_object->obmat[3]);
+ mul_v3_m4v3(ray_end, depth_object_mat_inv, cob->matrix[3]);
- asp_src = w_src / h_src;
- asp_dst = w_dst / h_dst;
+ float ray_direction[3];
+ sub_v3_v3v3(ray_direction, ray_end, ray_start);
+ normalize_v3(ray_direction);
- if (fabsf(asp_src - asp_dst) >= FLT_EPSILON) {
- if ((asp_src > asp_dst) == (data->frame_method == FOLLOWTRACK_FRAME_CROP)) {
- /* fit X */
- float div = asp_src / asp_dst;
- float cent = (float)width / 2.0f;
+ BVHTreeFromMesh tree_data = NULL_BVHTreeFromMesh;
+ BKE_bvhtree_from_mesh_get(&tree_data, depth_mesh, BVHTREE_FROM_LOOPTRI, 4);
- pos[0] = (((pos[0] * width - cent) * div) + cent) / width;
- }
- else {
- /* fit Y */
- float div = asp_dst / asp_src;
- float cent = (float)height / 2.0f;
+ BVHTreeRayHit hit;
+ hit.dist = BVH_RAYCAST_DIST_MAX;
+ hit.index = -1;
- pos[1] = (((pos[1] * height - cent) * div) + cent) / height;
- }
- }
- }
+ const int result = BLI_bvhtree_ray_cast(tree_data.tree,
+ ray_start,
+ ray_direction,
+ 0.0f,
+ &hit,
+ tree_data.raycast_callback,
+ &tree_data);
- BKE_camera_params_init(&params);
- BKE_camera_params_from_object(&params, camob);
+ if (result != -1) {
+ mul_v3_m4v3(cob->matrix[3], depth_object->obmat, hit.co);
+ }
- if (params.is_ortho) {
- vec[0] = params.ortho_scale * (pos[0] - 0.5f + params.shiftx);
- vec[1] = params.ortho_scale * (pos[1] - 0.5f + params.shifty);
- vec[2] = -len;
+ free_bvhtree_from_mesh(&tree_data);
+}
- if (aspect > 1.0f) {
- vec[1] /= aspect;
- }
- else {
- vec[0] *= aspect;
- }
+static void followtrack_evaluate_using_2d_position(FollowTrackContext *context, bConstraintOb *cob)
+{
+ Scene *scene = context->scene;
+ MovieClip *clip = context->clip;
+ MovieTrackingTrack *track = context->track;
+ Object *camera_object = context->camera_object;
+ const float clip_frame = context->clip_frame;
+ const float aspect = (scene->r.xsch * scene->r.xasp) / (scene->r.ysch * scene->r.yasp);
- mul_v3_m4v3(disp, camob->obmat, vec);
+ const float object_depth = followtrack_distance_from_viewplane_get(context, cob);
+ if (object_depth < FLT_EPSILON) {
+ return;
+ }
- copy_m4_m4(rmat, camob->obmat);
- zero_v3(rmat[3]);
- mul_m4_m4m4(cob->matrix, cob->matrix, rmat);
+ int clip_width, clip_height;
+ BKE_movieclip_get_size(clip, NULL, &clip_width, &clip_height);
- copy_v3_v3(cob->matrix[3], disp);
- }
- else {
- d = (len * params.sensor_x) / (2.0f * params.lens);
+ float marker_position[2];
+ BKE_tracking_marker_get_subframe_position(track, clip_frame, marker_position);
- vec[0] = d * (2.0f * (pos[0] + params.shiftx) - 1.0f);
- vec[1] = d * (2.0f * (pos[1] + params.shifty) - 1.0f);
- vec[2] = -len;
+ followtrack_undistort_if_needed(context, clip_width, clip_height, marker_position);
+ followtrack_fit_frame(context, clip_width, clip_height, marker_position);
- if (aspect > 1.0f) {
- vec[1] /= aspect;
- }
- else {
- vec[0] *= aspect;
- }
+ float rmat[4][4];
+ CameraParams params;
+ BKE_camera_params_init(&params);
+ BKE_camera_params_from_object(&params, camera_object);
- mul_v3_m4v3(disp, camob->obmat, vec);
+ if (params.is_ortho) {
+ float vec[3];
+ vec[0] = params.ortho_scale * (marker_position[0] - 0.5f + params.shiftx);
+ vec[1] = params.ortho_scale * (marker_position[1] - 0.5f + params.shifty);
+ vec[2] = -object_depth;
- /* apply camera rotation so Z-axis would be co-linear */
- copy_m4_m4(rmat, camob->obmat);
- zero_v3(rmat[3]);
- mul_m4_m4m4(cob->matrix, cob->matrix, rmat);
+ if (aspect > 1.0f) {
+ vec[1] /= aspect;
+ }
+ else {
+ vec[0] *= aspect;
+ }
- copy_v3_v3(cob->matrix[3], disp);
- }
+ float disp[3];
+ mul_v3_m4v3(disp, camera_object->obmat, vec);
- if (data->depth_ob) {
- Object *depth_ob = data->depth_ob;
- Mesh *target_eval = BKE_object_get_evaluated_mesh(depth_ob);
- if (target_eval) {
- BVHTreeFromMesh treeData = NULL_BVHTreeFromMesh;
- BVHTreeRayHit hit;
- float ray_start[3], ray_end[3], ray_nor[3], imat[4][4];
- int result;
+ copy_m4_m4(rmat, camera_object->obmat);
+ zero_v3(rmat[3]);
+ mul_m4_m4m4(cob->matrix, cob->matrix, rmat);
- invert_m4_m4(imat, depth_ob->obmat);
+ copy_v3_v3(cob->matrix[3], disp);
+ }
+ else {
+ const float d = (object_depth * params.sensor_x) / (2.0f * params.lens);
- mul_v3_m4v3(ray_start, imat, camob->obmat[3]);
- mul_v3_m4v3(ray_end, imat, cob->matrix[3]);
+ float vec[3];
+ vec[0] = d * (2.0f * (marker_position[0] + params.shiftx) - 1.0f);
+ vec[1] = d * (2.0f * (marker_position[1] + params.shifty) - 1.0f);
+ vec[2] = -object_depth;
- sub_v3_v3v3(ray_nor, ray_end, ray_start);
- normalize_v3(ray_nor);
+ if (aspect > 1.0f) {
+ vec[1] /= aspect;
+ }
+ else {
+ vec[0] *= aspect;
+ }
- BKE_bvhtree_from_mesh_get(&treeData, target_eval, BVHTREE_FROM_LOOPTRI, 4);
+ float disp[3];
+ mul_v3_m4v3(disp, camera_object->obmat, vec);
- hit.dist = BVH_RAYCAST_DIST_MAX;
- hit.index = -1;
+ /* apply camera rotation so Z-axis would be co-linear */
+ copy_m4_m4(rmat, camera_object->obmat);
+ zero_v3(rmat[3]);
+ mul_m4_m4m4(cob->matrix, cob->matrix, rmat);
- result = BLI_bvhtree_ray_cast(
- treeData.tree, ray_start, ray_nor, 0.0f, &hit, treeData.raycast_callback, &treeData);
+ copy_v3_v3(cob->matrix[3], disp);
+ }
- if (result != -1) {
- mul_v3_m4v3(cob->matrix[3], depth_ob->obmat, hit.co);
- }
+ followtrack_project_to_depth_object_if_needed(context, cob);
+}
- free_bvhtree_from_mesh(&treeData);
- }
- }
- }
+static void followtrack_evaluate(bConstraint *con, bConstraintOb *cob, ListBase *UNUSED(targets))
+{
+ FollowTrackContext context;
+ if (!followtrack_context_init(&context, con, cob)) {
+ return;
+ }
+
+ bFollowTrackConstraint *data = con->data;
+ if (data->flag & FOLLOWTRACK_USE_3D_POSITION) {
+ followtrack_evaluate_using_3d_position(&context, cob);
+ return;
}
+
+ followtrack_evaluate_using_2d_position(&context, cob);
}
static bConstraintTypeInfo CTI_FOLLOWTRACK = {
@@ -5497,7 +5670,7 @@ void BKE_constraints_active_set(ListBase *list, bConstraint *con)
static bConstraint *constraint_list_find_from_target(ListBase *constraints, bConstraintTarget *tgt)
{
- for (bConstraint *con = constraints->first; con; con = con->next) {
+ LISTBASE_FOREACH (bConstraint *, con, constraints) {
ListBase *targets = NULL;
if (con->type == CONSTRAINT_TYPE_PYTHON) {
@@ -5531,7 +5704,7 @@ bConstraint *BKE_constraint_find_from_target(Object *ob,
}
if (ob->pose != NULL) {
- for (bPoseChannel *pchan = ob->pose->chanbase.first; pchan; pchan = pchan->next) {
+ LISTBASE_FOREACH (bPoseChannel *, pchan, &ob->pose->chanbase) {
result = constraint_list_find_from_target(&pchan->constraints, tgt);
if (result != NULL) {
diff --git a/source/blender/blenkernel/intern/context.c b/source/blender/blenkernel/intern/context.c
index f6db23111a1..8de12139306 100644
--- a/source/blender/blenkernel/intern/context.c
+++ b/source/blender/blenkernel/intern/context.c
@@ -278,8 +278,8 @@ static void *ctx_wm_python_context_get(const bContext *C,
static int ctx_data_get(bContext *C, const char *member, bContextDataResult *result)
{
- bScreen *sc;
- ScrArea *sa;
+ bScreen *screen;
+ ScrArea *area;
ARegion *region;
int done = 0, recursion = C->data.recursion;
int ret = 0;
@@ -327,17 +327,17 @@ static int ctx_data_get(bContext *C, const char *member, bContextDataResult *res
}
}
}
- if (done != 1 && recursion < 3 && (sa = CTX_wm_area(C))) {
+ if (done != 1 && recursion < 3 && (area = CTX_wm_area(C))) {
C->data.recursion = 3;
- if (sa->type && sa->type->context) {
- ret = sa->type->context(C, member, result);
+ if (area->type && area->type->context) {
+ ret = area->type->context(C, member, result);
if (ret) {
done = -(-ret | -done);
}
}
}
- if (done != 1 && recursion < 4 && (sc = CTX_wm_screen(C))) {
- bContextDataCallback cb = sc->context;
+ if (done != 1 && recursion < 4 && (screen = CTX_wm_screen(C))) {
+ bContextDataCallback cb = screen->context;
C->data.recursion = 4;
if (cb) {
ret = cb(C, member, result);
@@ -543,8 +543,8 @@ ListBase CTX_data_dir_get_ex(const bContext *C,
{
bContextDataResult result;
ListBase lb;
- bScreen *sc;
- ScrArea *sa;
+ bScreen *screen;
+ ScrArea *area;
ARegion *region;
int a;
@@ -588,9 +588,9 @@ ListBase CTX_data_dir_get_ex(const bContext *C,
}
}
}
- if ((sa = CTX_wm_area(C)) && sa->type && sa->type->context) {
+ if ((area = CTX_wm_area(C)) && area->type && area->type->context) {
memset(&result, 0, sizeof(result));
- sa->type->context(C, "", &result);
+ area->type->context(C, "", &result);
if (result.dir) {
for (a = 0; result.dir[a]; a++) {
@@ -598,8 +598,8 @@ ListBase CTX_data_dir_get_ex(const bContext *C,
}
}
}
- if ((sc = CTX_wm_screen(C)) && sc->context) {
- bContextDataCallback cb = sc->context;
+ if ((screen = CTX_wm_screen(C)) && screen->context) {
+ bContextDataCallback cb = screen->context;
memset(&result, 0, sizeof(result));
cb(C, "", &result);
@@ -716,8 +716,8 @@ ScrArea *CTX_wm_area(const bContext *C)
SpaceLink *CTX_wm_space_data(const bContext *C)
{
- ScrArea *sa = CTX_wm_area(C);
- return (sa) ? sa->spacedata.first : NULL;
+ ScrArea *area = CTX_wm_area(C);
+ return (area) ? area->spacedata.first : NULL;
}
ARegion *CTX_wm_region(const bContext *C)
@@ -757,19 +757,19 @@ struct ReportList *CTX_wm_reports(const bContext *C)
View3D *CTX_wm_view3d(const bContext *C)
{
- ScrArea *sa = CTX_wm_area(C);
- if (sa && sa->spacetype == SPACE_VIEW3D) {
- return sa->spacedata.first;
+ ScrArea *area = CTX_wm_area(C);
+ if (area && area->spacetype == SPACE_VIEW3D) {
+ return area->spacedata.first;
}
return NULL;
}
RegionView3D *CTX_wm_region_view3d(const bContext *C)
{
- ScrArea *sa = CTX_wm_area(C);
+ ScrArea *area = CTX_wm_area(C);
ARegion *region = CTX_wm_region(C);
- if (sa && sa->spacetype == SPACE_VIEW3D) {
+ if (area && area->spacetype == SPACE_VIEW3D) {
if (region && region->regiontype == RGN_TYPE_WINDOW) {
return region->regiondata;
}
@@ -779,135 +779,135 @@ RegionView3D *CTX_wm_region_view3d(const bContext *C)
struct SpaceText *CTX_wm_space_text(const bContext *C)
{
- ScrArea *sa = CTX_wm_area(C);
- if (sa && sa->spacetype == SPACE_TEXT) {
- return sa->spacedata.first;
+ ScrArea *area = CTX_wm_area(C);
+ if (area && area->spacetype == SPACE_TEXT) {
+ return area->spacedata.first;
}
return NULL;
}
struct SpaceConsole *CTX_wm_space_console(const bContext *C)
{
- ScrArea *sa = CTX_wm_area(C);
- if (sa && sa->spacetype == SPACE_CONSOLE) {
- return sa->spacedata.first;
+ ScrArea *area = CTX_wm_area(C);
+ if (area && area->spacetype == SPACE_CONSOLE) {
+ return area->spacedata.first;
}
return NULL;
}
struct SpaceImage *CTX_wm_space_image(const bContext *C)
{
- ScrArea *sa = CTX_wm_area(C);
- if (sa && sa->spacetype == SPACE_IMAGE) {
- return sa->spacedata.first;
+ ScrArea *area = CTX_wm_area(C);
+ if (area && area->spacetype == SPACE_IMAGE) {
+ return area->spacedata.first;
}
return NULL;
}
struct SpaceProperties *CTX_wm_space_properties(const bContext *C)
{
- ScrArea *sa = CTX_wm_area(C);
- if (sa && sa->spacetype == SPACE_PROPERTIES) {
- return sa->spacedata.first;
+ ScrArea *area = CTX_wm_area(C);
+ if (area && area->spacetype == SPACE_PROPERTIES) {
+ return area->spacedata.first;
}
return NULL;
}
struct SpaceFile *CTX_wm_space_file(const bContext *C)
{
- ScrArea *sa = CTX_wm_area(C);
- if (sa && sa->spacetype == SPACE_FILE) {
- return sa->spacedata.first;
+ ScrArea *area = CTX_wm_area(C);
+ if (area && area->spacetype == SPACE_FILE) {
+ return area->spacedata.first;
}
return NULL;
}
struct SpaceSeq *CTX_wm_space_seq(const bContext *C)
{
- ScrArea *sa = CTX_wm_area(C);
- if (sa && sa->spacetype == SPACE_SEQ) {
- return sa->spacedata.first;
+ ScrArea *area = CTX_wm_area(C);
+ if (area && area->spacetype == SPACE_SEQ) {
+ return area->spacedata.first;
}
return NULL;
}
struct SpaceOutliner *CTX_wm_space_outliner(const bContext *C)
{
- ScrArea *sa = CTX_wm_area(C);
- if (sa && sa->spacetype == SPACE_OUTLINER) {
- return sa->spacedata.first;
+ ScrArea *area = CTX_wm_area(C);
+ if (area && area->spacetype == SPACE_OUTLINER) {
+ return area->spacedata.first;
}
return NULL;
}
struct SpaceNla *CTX_wm_space_nla(const bContext *C)
{
- ScrArea *sa = CTX_wm_area(C);
- if (sa && sa->spacetype == SPACE_NLA) {
- return sa->spacedata.first;
+ ScrArea *area = CTX_wm_area(C);
+ if (area && area->spacetype == SPACE_NLA) {
+ return area->spacedata.first;
}
return NULL;
}
struct SpaceNode *CTX_wm_space_node(const bContext *C)
{
- ScrArea *sa = CTX_wm_area(C);
- if (sa && sa->spacetype == SPACE_NODE) {
- return sa->spacedata.first;
+ ScrArea *area = CTX_wm_area(C);
+ if (area && area->spacetype == SPACE_NODE) {
+ return area->spacedata.first;
}
return NULL;
}
struct SpaceGraph *CTX_wm_space_graph(const bContext *C)
{
- ScrArea *sa = CTX_wm_area(C);
- if (sa && sa->spacetype == SPACE_GRAPH) {
- return sa->spacedata.first;
+ ScrArea *area = CTX_wm_area(C);
+ if (area && area->spacetype == SPACE_GRAPH) {
+ return area->spacedata.first;
}
return NULL;
}
struct SpaceAction *CTX_wm_space_action(const bContext *C)
{
- ScrArea *sa = CTX_wm_area(C);
- if (sa && sa->spacetype == SPACE_ACTION) {
- return sa->spacedata.first;
+ ScrArea *area = CTX_wm_area(C);
+ if (area && area->spacetype == SPACE_ACTION) {
+ return area->spacedata.first;
}
return NULL;
}
struct SpaceInfo *CTX_wm_space_info(const bContext *C)
{
- ScrArea *sa = CTX_wm_area(C);
- if (sa && sa->spacetype == SPACE_INFO) {
- return sa->spacedata.first;
+ ScrArea *area = CTX_wm_area(C);
+ if (area && area->spacetype == SPACE_INFO) {
+ return area->spacedata.first;
}
return NULL;
}
struct SpaceUserPref *CTX_wm_space_userpref(const bContext *C)
{
- ScrArea *sa = CTX_wm_area(C);
- if (sa && sa->spacetype == SPACE_USERPREF) {
- return sa->spacedata.first;
+ ScrArea *area = CTX_wm_area(C);
+ if (area && area->spacetype == SPACE_USERPREF) {
+ return area->spacedata.first;
}
return NULL;
}
struct SpaceClip *CTX_wm_space_clip(const bContext *C)
{
- ScrArea *sa = CTX_wm_area(C);
- if (sa && sa->spacetype == SPACE_CLIP) {
- return sa->spacedata.first;
+ ScrArea *area = CTX_wm_area(C);
+ if (area && area->spacetype == SPACE_CLIP) {
+ return area->spacedata.first;
}
return NULL;
}
struct SpaceTopBar *CTX_wm_space_topbar(const bContext *C)
{
- ScrArea *sa = CTX_wm_area(C);
- if (sa && sa->spacetype == SPACE_TOPBAR) {
- return sa->spacedata.first;
+ ScrArea *area = CTX_wm_area(C);
+ if (area && area->spacetype == SPACE_TOPBAR) {
+ return area->spacedata.first;
}
return NULL;
}
diff --git a/source/blender/blenkernel/intern/crazyspace.c b/source/blender/blenkernel/intern/crazyspace.c
index 7ec1da8eab4..6c8438e478e 100644
--- a/source/blender/blenkernel/intern/crazyspace.c
+++ b/source/blender/blenkernel/intern/crazyspace.c
@@ -84,7 +84,7 @@ static void set_crazy_vertex_quat(float r_quat[4],
static bool modifiers_disable_subsurf_temporary(struct Scene *scene, Object *ob)
{
bool disabled = false;
- int cageIndex = modifiers_getCageIndex(scene, ob, NULL, 1);
+ int cageIndex = BKE_modifiers_get_cage_index(scene, ob, NULL, 1);
ModifierData *md = ob->modifiers.first;
for (int i = 0; md && i <= cageIndex; i++, md = md->next) {
@@ -265,20 +265,20 @@ int BKE_crazyspace_get_first_deform_matrices_editbmesh(struct Depsgraph *depsgra
Mesh *me_input = ob->data;
Mesh *me = NULL;
int i, a, numleft = 0, numVerts = 0;
- int cageIndex = modifiers_getCageIndex(scene, ob, NULL, 1);
+ int cageIndex = BKE_modifiers_get_cage_index(scene, ob, NULL, 1);
float(*defmats)[3][3] = NULL, (*deformedVerts)[3] = NULL;
VirtualModifierData virtualModifierData;
ModifierEvalContext mectx = {depsgraph, ob, 0};
- modifiers_clearErrors(ob);
+ BKE_modifiers_clear_errors(ob);
- md = modifiers_getVirtualModifierList(ob, &virtualModifierData);
+ md = BKE_modifiers_get_virtual_modifierlist(ob, &virtualModifierData);
/* compute the deformation matrices and coordinates for the first
* modifiers with on cage editing that are enabled and support computing
* deform matrices */
for (i = 0; md && i <= cageIndex; i++, md = md->next) {
- const ModifierTypeInfo *mti = modifierType_getInfo(md->type);
+ const ModifierTypeInfo *mti = BKE_modifier_get_info(md->type);
if (!editbmesh_modifier_is_enabled(scene, md, me != NULL)) {
continue;
@@ -288,12 +288,12 @@ int BKE_crazyspace_get_first_deform_matrices_editbmesh(struct Depsgraph *depsgra
if (!defmats) {
const int required_mode = eModifierMode_Realtime | eModifierMode_Editmode;
CustomData_MeshMasks cd_mask_extra = CD_MASK_BAREMESH;
- CDMaskLink *datamasks = modifiers_calcDataMasks(
+ CDMaskLink *datamasks = BKE_modifier_calc_data_masks(
scene, ob, md, &cd_mask_extra, required_mode, NULL, NULL);
cd_mask_extra = datamasks->mask;
BLI_linklist_free((LinkNode *)datamasks, NULL);
- me = BKE_mesh_from_editmesh_with_coords_thin_wrap(em, &cd_mask_extra, NULL, me_input);
+ me = BKE_mesh_wrapper_from_editmesh_with_coords(em, &cd_mask_extra, NULL, me_input);
deformedVerts = editbmesh_vert_coords_alloc(em, &numVerts);
defmats = MEM_mallocN(sizeof(*defmats) * numVerts, "defmats");
@@ -310,7 +310,7 @@ int BKE_crazyspace_get_first_deform_matrices_editbmesh(struct Depsgraph *depsgra
for (; md && i <= cageIndex; md = md->next, i++) {
if (editbmesh_modifier_is_enabled(scene, md, me != NULL) &&
- modifier_isCorrectableDeformed(md)) {
+ BKE_modifier_is_correctable_deformed(md)) {
numleft++;
}
}
@@ -361,13 +361,13 @@ static bool crazyspace_modifier_supports_deform_matrices(ModifierData *md)
if (ELEM(md->type, eModifierType_Subsurf, eModifierType_Multires)) {
return true;
}
- const ModifierTypeInfo *mti = modifierType_getInfo(md->type);
+ const ModifierTypeInfo *mti = BKE_modifier_get_info(md->type);
return (mti->type == eModifierTypeType_OnlyDeform);
}
static bool crazyspace_modifier_supports_deform(ModifierData *md)
{
- const ModifierTypeInfo *mti = modifierType_getInfo(md->type);
+ const ModifierTypeInfo *mti = BKE_modifier_get_info(md->type);
return (mti->type == eModifierTypeType_OnlyDeform);
}
@@ -386,7 +386,7 @@ int BKE_sculpt_get_first_deform_matrices(struct Depsgraph *depsgraph,
crazyspace_init_object_for_eval(depsgraph, object, &object_eval);
MultiresModifierData *mmd = get_multires_modifier(scene, &object_eval, 0);
const bool is_sculpt_mode = (object->mode & OB_MODE_SCULPT) != 0;
- const bool has_multires = mmd != NULL && BKE_multires_sculpt_level_get(mmd) > 0;
+ const bool has_multires = mmd != NULL && mmd->sculptlvl > 0;
const ModifierEvalContext mectx = {depsgraph, &object_eval, 0};
if (is_sculpt_mode && has_multires) {
@@ -395,15 +395,15 @@ int BKE_sculpt_get_first_deform_matrices(struct Depsgraph *depsgraph,
return numleft;
}
- md = modifiers_getVirtualModifierList(&object_eval, &virtualModifierData);
+ md = BKE_modifiers_get_virtual_modifierlist(&object_eval, &virtualModifierData);
for (; md; md = md->next) {
- if (!modifier_isEnabled(scene, md, eModifierMode_Realtime)) {
+ if (!BKE_modifier_is_enabled(scene, md, eModifierMode_Realtime)) {
continue;
}
if (crazyspace_modifier_supports_deform_matrices(md)) {
- const ModifierTypeInfo *mti = modifierType_getInfo(md->type);
+ const ModifierTypeInfo *mti = BKE_modifier_get_info(md->type);
if (defmats == NULL) {
/* NOTE: Evaluated object si re-set to its original undeformed
* state. */
@@ -425,7 +425,7 @@ int BKE_sculpt_get_first_deform_matrices(struct Depsgraph *depsgraph,
}
for (; md; md = md->next) {
- if (!modifier_isEnabled(scene, md, eModifierMode_Realtime)) {
+ if (!BKE_modifier_is_enabled(scene, md, eModifierMode_Realtime)) {
continue;
}
@@ -471,16 +471,16 @@ void BKE_crazyspace_build_sculpt(struct Depsgraph *depsgraph,
VirtualModifierData virtualModifierData;
Object object_eval;
crazyspace_init_object_for_eval(depsgraph, object, &object_eval);
- ModifierData *md = modifiers_getVirtualModifierList(&object_eval, &virtualModifierData);
+ ModifierData *md = BKE_modifiers_get_virtual_modifierlist(&object_eval, &virtualModifierData);
const ModifierEvalContext mectx = {depsgraph, &object_eval, 0};
for (; md; md = md->next) {
- if (!modifier_isEnabled(scene, md, eModifierMode_Realtime)) {
+ if (!BKE_modifier_is_enabled(scene, md, eModifierMode_Realtime)) {
continue;
}
if (crazyspace_modifier_supports_deform(md)) {
- const ModifierTypeInfo *mti = modifierType_getInfo(md->type);
+ const ModifierTypeInfo *mti = BKE_modifier_get_info(md->type);
/* skip leading modifiers which have been already
* handled in sculpt_get_first_deform_matrices */
diff --git a/source/blender/blenkernel/intern/curve.c b/source/blender/blenkernel/intern/curve.c
index ba1c75196db..e67cf8573f3 100644
--- a/source/blender/blenkernel/intern/curve.c
+++ b/source/blender/blenkernel/intern/curve.c
@@ -46,13 +46,13 @@
#include "DNA_scene_types.h"
#include "DNA_vfont_types.h"
-#include "BKE_animsys.h"
#include "BKE_curve.h"
#include "BKE_displist.h"
#include "BKE_font.h"
#include "BKE_idtype.h"
#include "BKE_key.h"
#include "BKE_lib_id.h"
+#include "BKE_lib_query.h"
#include "BKE_main.h"
#include "BKE_material.h"
#include "BKE_object.h"
@@ -118,6 +118,22 @@ static void curve_free_data(ID *id)
MEM_SAFE_FREE(curve->tb);
}
+static void curve_foreach_id(ID *id, LibraryForeachIDData *data)
+{
+ Curve *curve = (Curve *)id;
+ BKE_LIB_FOREACHID_PROCESS(data, curve->bevobj, IDWALK_CB_NOP);
+ BKE_LIB_FOREACHID_PROCESS(data, curve->taperobj, IDWALK_CB_NOP);
+ BKE_LIB_FOREACHID_PROCESS(data, curve->textoncurve, IDWALK_CB_NOP);
+ BKE_LIB_FOREACHID_PROCESS(data, curve->key, IDWALK_CB_USER);
+ for (int i = 0; i < curve->totcol; i++) {
+ BKE_LIB_FOREACHID_PROCESS(data, curve->mat[i], IDWALK_CB_USER);
+ }
+ BKE_LIB_FOREACHID_PROCESS(data, curve->vfont, IDWALK_CB_USER);
+ BKE_LIB_FOREACHID_PROCESS(data, curve->vfontb, IDWALK_CB_USER);
+ BKE_LIB_FOREACHID_PROCESS(data, curve->vfonti, IDWALK_CB_USER);
+ BKE_LIB_FOREACHID_PROCESS(data, curve->vfontbi, IDWALK_CB_USER);
+}
+
IDTypeInfo IDType_ID_CU = {
.id_code = ID_CU,
.id_filter = FILTER_ID_CU,
@@ -132,6 +148,7 @@ IDTypeInfo IDType_ID_CU = {
.copy_data = curve_copy_data,
.free_data = curve_free_data,
.make_local = NULL,
+ .foreach_id = curve_foreach_id,
};
static int cu_isectLL(const float v1[3],
@@ -1878,7 +1895,10 @@ void BKE_curve_bevel_make(Object *ob, ListBase *disp)
}
/* Don't duplicate the last back vertex. */
angle = (cu->ext1 == 0.0f && (cu->flag & CU_BACK)) ? dangle : 0;
- for (a = 0; a < cu->bevresol + 2; a++) {
+ int front_len = (cu->ext1 == 0.0f && ((cu->flag & CU_BACK) || !(cu->flag & CU_FRONT))) ?
+ cu->bevresol + 1 :
+ cu->bevresol + 2;
+ for (a = 0; a < front_len; a++) {
fp[0] = 0.0;
fp[1] = (float)(cosf(angle) * (cu->ext2));
fp[2] = (float)(sinf(angle) * (cu->ext2)) + cu->ext1;
@@ -4149,7 +4169,8 @@ void BKE_nurb_handle_calc_simple_auto(Nurb *nu, BezTriple *bezt)
*/
void BKE_nurb_bezt_handle_test(BezTriple *bezt,
const eBezTriple_Flag__Alias sel_flag,
- const bool use_handle)
+ const bool use_handle,
+ const bool use_around_local)
{
short flag = 0;
@@ -4172,6 +4193,10 @@ void BKE_nurb_bezt_handle_test(BezTriple *bezt,
flag = (bezt->f2 & sel_flag) ? (SEL_F1 | SEL_F2 | SEL_F3) : 0;
}
+ if (use_around_local) {
+ flag &= ~SEL_F2;
+ }
+
/* check for partial selection */
if (!ELEM(flag, 0, SEL_F1 | SEL_F2 | SEL_F3)) {
if (ELEM(bezt->h1, HD_AUTO, HD_AUTO_ANIM)) {
@@ -4198,7 +4223,7 @@ void BKE_nurb_bezt_handle_test(BezTriple *bezt,
#undef SEL_F3
}
-void BKE_nurb_handles_test(Nurb *nu, const bool use_handle)
+void BKE_nurb_handles_test(Nurb *nu, const bool use_handle, const bool use_around_local)
{
BezTriple *bezt;
int a;
@@ -4210,7 +4235,7 @@ void BKE_nurb_handles_test(Nurb *nu, const bool use_handle)
bezt = nu->bezt;
a = nu->pntsu;
while (a--) {
- BKE_nurb_bezt_handle_test(bezt, SELECT, use_handle);
+ BKE_nurb_bezt_handle_test(bezt, SELECT, use_handle, use_around_local);
bezt++;
}
@@ -4460,7 +4485,7 @@ void BKE_nurbList_handles_recalculate(ListBase *editnurb, const bool calc_length
}
}
-void BKE_nurbList_flag_set(ListBase *editnurb, short flag)
+void BKE_nurbList_flag_set(ListBase *editnurb, short flag, bool set)
{
Nurb *nu;
BezTriple *bezt;
@@ -4472,7 +4497,16 @@ void BKE_nurbList_flag_set(ListBase *editnurb, short flag)
a = nu->pntsu;
bezt = nu->bezt;
while (a--) {
- bezt->f1 = bezt->f2 = bezt->f3 = flag;
+ if (set) {
+ bezt->f1 |= flag;
+ bezt->f2 |= flag;
+ bezt->f3 |= flag;
+ }
+ else {
+ bezt->f1 &= ~flag;
+ bezt->f2 &= ~flag;
+ bezt->f3 &= ~flag;
+ }
bezt++;
}
}
@@ -4480,13 +4514,47 @@ void BKE_nurbList_flag_set(ListBase *editnurb, short flag)
a = nu->pntsu * nu->pntsv;
bp = nu->bp;
while (a--) {
- bp->f1 = flag;
+ SET_FLAG_FROM_TEST(bp->f1, set, flag);
bp++;
}
}
}
}
+/**
+ * Set \a flag for every point that already has \a from_flag set.
+ */
+bool BKE_nurbList_flag_set_from_flag(ListBase *editnurb, short from_flag, short flag)
+{
+ bool changed = false;
+
+ for (Nurb *nu = editnurb->first; nu; nu = nu->next) {
+ if (nu->type == CU_BEZIER) {
+ for (int i = 0; i < nu->pntsu; i++) {
+ BezTriple *bezt = &nu->bezt[i];
+ int old_f1 = bezt->f1, old_f2 = bezt->f2, old_f3 = bezt->f3;
+
+ SET_FLAG_FROM_TEST(bezt->f1, bezt->f1 & from_flag, flag);
+ SET_FLAG_FROM_TEST(bezt->f2, bezt->f2 & from_flag, flag);
+ SET_FLAG_FROM_TEST(bezt->f3, bezt->f3 & from_flag, flag);
+
+ changed |= (old_f1 != bezt->f1) || (old_f2 != bezt->f2) || (old_f3 != bezt->f3);
+ }
+ }
+ else {
+ for (int i = 0; i < nu->pntsu * nu->pntsv; i++) {
+ BPoint *bp = &nu->bp[i];
+ int old_f1 = bp->f1;
+
+ SET_FLAG_FROM_TEST(bp->f1, bp->f1 & from_flag, flag);
+ changed |= (old_f1 != bp->f1);
+ }
+ }
+ }
+
+ return changed;
+}
+
void BKE_nurb_direction_switch(Nurb *nu)
{
BezTriple *bezt1, *bezt2;
@@ -4613,7 +4681,7 @@ void BKE_nurb_direction_switch(Nurb *nu)
void BKE_curve_nurbs_vert_coords_get(ListBase *lb, float (*vert_coords)[3], int vert_len)
{
float *co = vert_coords[0];
- for (Nurb *nu = lb->first; nu; nu = nu->next) {
+ LISTBASE_FOREACH (Nurb *, nu, lb) {
if (nu->type == CU_BEZIER) {
BezTriple *bezt = nu->bezt;
for (int i = 0; i < nu->pntsu; i++, bezt++) {
@@ -4693,7 +4761,7 @@ void BKE_curve_nurbs_vert_coords_apply(ListBase *lb,
{
const float *co = vert_coords[0];
- for (Nurb *nu = lb->first; nu; nu = nu->next) {
+ LISTBASE_FOREACH (Nurb *, nu, lb) {
if (nu->type == CU_BEZIER) {
BezTriple *bezt = nu->bezt;
@@ -4731,7 +4799,7 @@ float (*BKE_curve_nurbs_key_vert_coords_alloc(ListBase *lb, float *key, int *r_v
float(*cos)[3] = MEM_malloc_arrayN(vert_len, sizeof(*cos), __func__);
float *co = cos[0];
- for (Nurb *nu = lb->first; nu; nu = nu->next) {
+ LISTBASE_FOREACH (Nurb *, nu, lb) {
if (nu->type == CU_BEZIER) {
BezTriple *bezt = nu->bezt;
@@ -5169,7 +5237,7 @@ bool BKE_curve_minmax(Curve *cu, bool use_radius, float min[3], float max[3])
use_radius = false;
}
/* Do bounding box based on splines. */
- for (Nurb *nu = nurb_lb->first; nu; nu = nu->next) {
+ LISTBASE_FOREACH (Nurb *, nu, nurb_lb) {
BKE_nurb_minmax(nu, use_radius, min, max);
}
const bool result = (BLI_listbase_is_empty(nurb_lb) == false);
@@ -5504,6 +5572,20 @@ void BKE_curve_material_remap(Curve *cu, const unsigned int *remap, unsigned int
#undef MAT_NR_REMAP
}
+void BKE_curve_smooth_flag_set(Curve *cu, const bool use_smooth)
+{
+ if (use_smooth) {
+ for (Nurb *nu = cu->nurb.first; nu; nu = nu->next) {
+ nu->flag |= CU_SMOOTH;
+ }
+ }
+ else {
+ for (Nurb *nu = cu->nurb.first; nu; nu = nu->next) {
+ nu->flag &= ~CU_SMOOTH;
+ }
+ }
+}
+
void BKE_curve_rect_from_textbox(const struct Curve *cu,
const struct TextBox *tb,
struct rctf *r_rect)
diff --git a/source/blender/blenkernel/intern/customdata.c b/source/blender/blenkernel/intern/customdata.c
index 87a5ac80bc7..b0007c2a598 100644
--- a/source/blender/blenkernel/intern/customdata.c
+++ b/source/blender/blenkernel/intern/customdata.c
@@ -10,7 +10,7 @@
* 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,
+ * 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) 2006 Blender Foundation.
@@ -315,6 +315,9 @@ static void layerInterp_mdeformvert(const void **sources,
if (totweight) {
dvert->totweight = totweight;
for (i = 0, node = dest_dwlink; node; node = node->next, i++) {
+ if (node->dw.weight > 1.0f) {
+ node->dw.weight = 1.0f;
+ }
dvert->dw[i] = node->dw;
}
}
@@ -696,6 +699,24 @@ static size_t layerFilesize_mdisps(CDataFile *UNUSED(cdf), const void *data, int
return size;
}
+static void layerInterp_paint_mask(
+ const void **sources, const float *weights, const float *sub_weights, int count, void *dest)
+{
+ float mask = 0.0f;
+ const float *sub_weight = sub_weights;
+ for (int i = 0; i < count; i++) {
+ float weight = weights ? weights[i] : 1.0f;
+ const float *src = sources[i];
+ if (sub_weights) {
+ mask += (*src) * (*sub_weight) * weight;
+ sub_weight++;
+ }
+ else {
+ mask += (*src) * weight;
+ }
+ }
+ *(float *)dest = mask;
+}
static void layerCopy_grid_paint_mask(const void *source, void *dest, int count)
{
@@ -1318,6 +1339,132 @@ static void layerDefault_fmap(void *data, int count)
}
}
+static void layerCopyValue_propcol(const void *source,
+ void *dest,
+ const int mixmode,
+ const float mixfactor)
+{
+ const MPropCol *m1 = source;
+ MPropCol *m2 = dest;
+ float tmp_col[4];
+
+ if (ELEM(mixmode,
+ CDT_MIX_NOMIX,
+ CDT_MIX_REPLACE_ABOVE_THRESHOLD,
+ CDT_MIX_REPLACE_BELOW_THRESHOLD)) {
+ /* Modes that do a full copy or nothing. */
+ if (ELEM(mixmode, CDT_MIX_REPLACE_ABOVE_THRESHOLD, CDT_MIX_REPLACE_BELOW_THRESHOLD)) {
+ /* TODO: Check for a real valid way to get 'factor' value of our dest color? */
+ const float f = (m2->col[0] + m2->col[1] + m2->col[2]) / 3.0f;
+ if (mixmode == CDT_MIX_REPLACE_ABOVE_THRESHOLD && f < mixfactor) {
+ return; /* Do Nothing! */
+ }
+ else if (mixmode == CDT_MIX_REPLACE_BELOW_THRESHOLD && f > mixfactor) {
+ return; /* Do Nothing! */
+ }
+ }
+ copy_v3_v3(m2->col, m1->col);
+ }
+ else { /* Modes that support 'real' mix factor. */
+ if (mixmode == CDT_MIX_MIX) {
+ blend_color_mix_float(tmp_col, m2->col, m1->col);
+ }
+ else if (mixmode == CDT_MIX_ADD) {
+ blend_color_add_float(tmp_col, m2->col, m1->col);
+ }
+ else if (mixmode == CDT_MIX_SUB) {
+ blend_color_sub_float(tmp_col, m2->col, m1->col);
+ }
+ else if (mixmode == CDT_MIX_MUL) {
+ blend_color_mul_float(tmp_col, m2->col, m1->col);
+ }
+ else {
+ memcpy(tmp_col, m1->col, sizeof(tmp_col));
+ }
+ blend_color_interpolate_float(m2->col, m2->col, tmp_col, mixfactor);
+
+ copy_v3_v3(m2->col, m1->col);
+ }
+ m2->col[3] = m1->col[3];
+}
+
+static bool layerEqual_propcol(const void *data1, const void *data2)
+{
+ const MPropCol *m1 = data1, *m2 = data2;
+ float tot = 0;
+
+ for (int i = 0; i < 4; i++) {
+ float c = (m1->col[i] - m2->col[i]);
+ tot += c * c;
+ }
+
+ return tot < 0.001f;
+}
+
+static void layerMultiply_propcol(void *data, float fac)
+{
+ MPropCol *m = data;
+ mul_v4_fl(m->col, fac);
+}
+
+static void layerAdd_propcol(void *data1, const void *data2)
+{
+ MPropCol *m = data1;
+ const MPropCol *m2 = data2;
+ add_v4_v4(m->col, m2->col);
+}
+
+static void layerDoMinMax_propcol(const void *data, void *vmin, void *vmax)
+{
+ const MPropCol *m = data;
+ MPropCol *min = vmin, *max = vmax;
+ minmax_v4v4_v4(min->col, max->col, m->col);
+}
+
+static void layerInitMinMax_propcol(void *vmin, void *vmax)
+{
+ MPropCol *min = vmin, *max = vmax;
+
+ copy_v4_fl(min->col, FLT_MAX);
+ copy_v4_fl(max->col, FLT_MIN);
+}
+
+static void layerDefault_propcol(void *data, int count)
+{
+ /* Default to white, full alpha. */
+ MPropCol default_propcol = {{1.0f, 1.0f, 1.0f, 1.0f}};
+ MPropCol *pcol = (MPropCol *)data;
+ int i;
+ for (i = 0; i < count; i++) {
+ copy_v4_v4(pcol[i].col, default_propcol.col);
+ }
+}
+
+static void layerInterp_propcol(
+ const void **sources, const float *weights, const float *sub_weights, int count, void *dest)
+{
+ MPropCol *mc = dest;
+ float col[4] = {0.0f, 0.0f, 0.0f, 0.0f};
+ const float *sub_weight = sub_weights;
+ for (int i = 0; i < count; i++) {
+ float weight = weights ? weights[i] : 1.0f;
+ const MPropCol *src = sources[i];
+ if (sub_weights) {
+ madd_v4_v4fl(col, src->col, (*sub_weight) * weight);
+ sub_weight++;
+ }
+ else {
+ madd_v4_v4fl(col, src->col, weight);
+ }
+ }
+ copy_v4_v4(mc->col, col);
+}
+
+static int layerMaxNum_propcol(void)
+{
+ return MAX_MCOL;
+}
+
static const LayerTypeInfo LAYERTYPEINFO[CD_NUMTYPES] = {
/* 0: CD_MVERT */
{sizeof(MVert), "MVert", 1, NULL, NULL, NULL, NULL, NULL, NULL},
@@ -1592,7 +1739,7 @@ static const LayerTypeInfo LAYERTYPEINFO[CD_NUMTYPES] = {
/* END BMESH ONLY */
/* 34: CD_PAINT_MASK */
- {sizeof(float), "", 0, NULL, NULL, NULL, NULL, NULL, NULL},
+ {sizeof(float), "", 0, NULL, NULL, NULL, layerInterp_paint_mask, NULL, NULL},
/* 35: CD_GRID_PAINT_MASK */
{sizeof(GridPaintMask),
"GridPaintMask",
@@ -1633,7 +1780,27 @@ static const LayerTypeInfo LAYERTYPEINFO[CD_NUMTYPES] = {
{sizeof(HairCurve), "HairCurve", 1, NULL, NULL, NULL, NULL, NULL, NULL},
/* 46: CD_HAIR_MAPPING */
{sizeof(HairMapping), "HairMapping", 1, NULL, NULL, NULL, NULL, NULL, NULL},
-};
+ /* 47: CD_PROP_COL */
+ {sizeof(MPropCol),
+ "MPropCol",
+ 1,
+ N_("Col"),
+ NULL,
+ NULL,
+ layerInterp_propcol,
+ NULL,
+ layerDefault_propcol,
+ NULL,
+ layerEqual_propcol,
+ layerMultiply_propcol,
+ layerInitMinMax_propcol,
+ layerAdd_propcol,
+ layerDoMinMax_propcol,
+ layerCopyValue_propcol,
+ NULL,
+ NULL,
+ NULL,
+ layerMaxNum_propcol}};
static const char *LAYERTYPENAMES[CD_NUMTYPES] = {
/* 0-4 */ "CDMVert",
@@ -1685,6 +1852,7 @@ static const char *LAYERTYPENAMES[CD_NUMTYPES] = {
"CDHairCurve",
"CDHairMapping",
"CDPoint",
+ "CDPropCol",
};
const CustomData_MeshMasks CD_MASK_BAREMESH = {
@@ -3556,10 +3724,9 @@ void CustomData_bmesh_copy_data_exclude_by_type(const CustomData *source,
/* if we found a matching layer, copy the data */
if (dest->layers[dest_i].type == source->layers[src_i].type &&
STREQ(dest->layers[dest_i].name, source->layers[src_i].name)) {
- const void *src_data = POINTER_OFFSET(src_block, source->layers[src_i].offset);
- void *dest_data = POINTER_OFFSET(*dest_block, dest->layers[dest_i].offset);
-
if (no_mask || ((CD_TYPE_AS_MASK(dest->layers[dest_i].type) & mask_exclude) == 0)) {
+ const void *src_data = POINTER_OFFSET(src_block, source->layers[src_i].offset);
+ void *dest_data = POINTER_OFFSET(*dest_block, dest->layers[dest_i].offset);
const LayerTypeInfo *typeInfo = layerType_getInfo(source->layers[src_i].type);
if (typeInfo->copy) {
typeInfo->copy(src_data, dest_data, 1);
diff --git a/source/blender/blenkernel/intern/displist.c b/source/blender/blenkernel/intern/displist.c
index dc2f603aa5c..a3e1eeb89c7 100644
--- a/source/blender/blenkernel/intern/displist.c
+++ b/source/blender/blenkernel/intern/displist.c
@@ -42,7 +42,7 @@
#include "BLI_string.h"
#include "BLI_utildefines.h"
-#include "BKE_anim.h"
+#include "BKE_anim_path.h"
#include "BKE_curve.h"
#include "BKE_displist.h"
#include "BKE_font.h"
@@ -805,7 +805,7 @@ static ModifierData *curve_get_tessellate_point(Scene *scene,
const bool editmode)
{
VirtualModifierData virtualModifierData;
- ModifierData *md = modifiers_getVirtualModifierList(ob, &virtualModifierData);
+ ModifierData *md = BKE_modifiers_get_virtual_modifierlist(ob, &virtualModifierData);
ModifierData *pretessellatePoint;
int required_mode;
@@ -822,9 +822,9 @@ static ModifierData *curve_get_tessellate_point(Scene *scene,
pretessellatePoint = NULL;
for (; md; md = md->next) {
- const ModifierTypeInfo *mti = modifierType_getInfo(md->type);
+ const ModifierTypeInfo *mti = BKE_modifier_get_info(md->type);
- if (!modifier_isEnabled(scene, md, required_mode)) {
+ if (!BKE_modifier_is_enabled(scene, md, required_mode)) {
continue;
}
if (mti->type == eModifierTypeType_Constructive) {
@@ -848,34 +848,36 @@ static ModifierData *curve_get_tessellate_point(Scene *scene,
return pretessellatePoint;
}
-static void curve_calc_modifiers_pre(
+/* Return true if any modifier was applied. */
+static bool curve_calc_modifiers_pre(
Depsgraph *depsgraph, Scene *scene, Object *ob, ListBase *nurb, const bool for_render)
{
VirtualModifierData virtualModifierData;
- ModifierData *md = modifiers_getVirtualModifierList(ob, &virtualModifierData);
+ ModifierData *md = BKE_modifiers_get_virtual_modifierlist(ob, &virtualModifierData);
ModifierData *pretessellatePoint;
Curve *cu = ob->data;
int numElems = 0, numVerts = 0;
const bool editmode = (!for_render && (cu->editnurb || cu->editfont));
- ModifierApplyFlag app_flag = 0;
+ ModifierApplyFlag apply_flag = 0;
float(*deformedVerts)[3] = NULL;
float *keyVerts = NULL;
int required_mode;
+ bool modified = false;
- modifiers_clearErrors(ob);
+ BKE_modifiers_clear_errors(ob);
if (editmode) {
- app_flag |= MOD_APPLY_USECACHE;
+ apply_flag |= MOD_APPLY_USECACHE;
}
if (for_render) {
- app_flag |= MOD_APPLY_RENDER;
+ apply_flag |= MOD_APPLY_RENDER;
required_mode = eModifierMode_Render;
}
else {
required_mode = eModifierMode_Realtime;
}
- const ModifierEvalContext mectx = {depsgraph, ob, app_flag};
+ const ModifierEvalContext mectx = {depsgraph, ob, apply_flag};
pretessellatePoint = curve_get_tessellate_point(scene, ob, for_render, editmode);
@@ -899,9 +901,9 @@ static void curve_calc_modifiers_pre(
if (pretessellatePoint) {
for (; md; md = md->next) {
- const ModifierTypeInfo *mti = modifierType_getInfo(md->type);
+ const ModifierTypeInfo *mti = BKE_modifier_get_info(md->type);
- if (!modifier_isEnabled(scene, md, required_mode)) {
+ if (!BKE_modifier_is_enabled(scene, md, required_mode)) {
continue;
}
if (mti->type != eModifierTypeType_OnlyDeform) {
@@ -913,6 +915,7 @@ static void curve_calc_modifiers_pre(
}
mti->deformVerts(md, &mectx, NULL, deformedVerts, numVerts);
+ modified = true;
if (md == pretessellatePoint) {
break;
@@ -931,6 +934,7 @@ static void curve_calc_modifiers_pre(
if (keyVerts) {
MEM_freeN(keyVerts);
}
+ return modified;
}
static float (*displist_vert_coords_alloc(ListBase *dispbase, int *r_vert_len))[3]
@@ -974,10 +978,11 @@ static void curve_calc_modifiers_post(Depsgraph *depsgraph,
ListBase *nurb,
ListBase *dispbase,
Mesh **r_final,
- const bool for_render)
+ const bool for_render,
+ const bool force_mesh_conversion)
{
VirtualModifierData virtualModifierData;
- ModifierData *md = modifiers_getVirtualModifierList(ob, &virtualModifierData);
+ ModifierData *md = BKE_modifiers_get_virtual_modifierlist(ob, &virtualModifierData);
ModifierData *pretessellatePoint;
Curve *cu = ob->data;
int required_mode = 0, totvert = 0;
@@ -985,10 +990,10 @@ static void curve_calc_modifiers_post(Depsgraph *depsgraph,
Mesh *modified = NULL, *mesh_applied;
float(*vertCos)[3] = NULL;
int useCache = !for_render;
- ModifierApplyFlag app_flag = 0;
+ ModifierApplyFlag apply_flag = 0;
if (for_render) {
- app_flag |= MOD_APPLY_RENDER;
+ apply_flag |= MOD_APPLY_RENDER;
required_mode = eModifierMode_Render;
}
else {
@@ -996,9 +1001,9 @@ static void curve_calc_modifiers_post(Depsgraph *depsgraph,
}
const ModifierEvalContext mectx_deform = {
- depsgraph, ob, editmode ? app_flag | MOD_APPLY_USECACHE : app_flag};
+ depsgraph, ob, editmode ? apply_flag | MOD_APPLY_USECACHE : apply_flag};
const ModifierEvalContext mectx_apply = {
- depsgraph, ob, useCache ? app_flag | MOD_APPLY_USECACHE : app_flag};
+ depsgraph, ob, useCache ? apply_flag | MOD_APPLY_USECACHE : apply_flag};
pretessellatePoint = curve_get_tessellate_point(scene, ob, for_render, editmode);
@@ -1015,9 +1020,9 @@ static void curve_calc_modifiers_post(Depsgraph *depsgraph,
}
for (; md; md = md->next) {
- const ModifierTypeInfo *mti = modifierType_getInfo(md->type);
+ const ModifierTypeInfo *mti = BKE_modifier_get_info(md->type);
- if (!modifier_isEnabled(scene, md, required_mode)) {
+ if (!BKE_modifier_is_enabled(scene, md, required_mode)) {
continue;
}
@@ -1095,7 +1100,7 @@ static void curve_calc_modifiers_post(Depsgraph *depsgraph,
if (need_normal) {
BKE_mesh_ensure_normals(modified);
}
- mesh_applied = mti->applyModifier(md, &mectx_apply, modified);
+ mesh_applied = mti->modifyMesh(md, &mectx_apply, modified);
if (mesh_applied) {
/* Modifier returned a new derived mesh */
@@ -1128,6 +1133,23 @@ static void curve_calc_modifiers_post(Depsgraph *depsgraph,
}
if (r_final) {
+ if (force_mesh_conversion && !modified) {
+ /* XXX 2.8 : This is a workaround for by some deeper technical debts:
+ * - DRW Batch cache is stored inside the ob->data.
+ * - Curve data is not COWed for instances that use different modifiers.
+ * This can causes the modifiers to be applied on all user of the same data-block
+ * (see T71055)
+ *
+ * The easy workaround is to force to generate a Mesh that will be used for display data
+ * since a Mesh output is already used for generative modifiers.
+ * However it does not fix problems with actual edit data still being shared.
+ *
+ * The right solution would be to COW the Curve data block at the input of the modifier
+ * stack just like what the mesh modifier does.
+ * */
+ modified = BKE_mesh_new_nomain_from_curve_displist(ob, dispbase);
+ }
+
if (modified) {
/* XXX2.8(Sybren): make sure the face normals are recalculated as well */
@@ -1202,6 +1224,7 @@ void BKE_displist_make_surf(Depsgraph *depsgraph,
DispList *dl;
float *data;
int len;
+ bool force_mesh_conversion = false;
if (!for_render && cu->editnurb) {
BKE_nurbList_duplicate(&nubase, BKE_curve_editNurbs_get(cu));
@@ -1211,7 +1234,7 @@ void BKE_displist_make_surf(Depsgraph *depsgraph,
}
if (!for_orco) {
- curve_calc_modifiers_pre(depsgraph, scene, ob, &nubase, for_render);
+ force_mesh_conversion = curve_calc_modifiers_pre(depsgraph, scene, ob, &nubase, for_render);
}
for (nu = nubase.first; nu; nu = nu->next) {
@@ -1289,7 +1312,8 @@ void BKE_displist_make_surf(Depsgraph *depsgraph,
if (!for_orco) {
BKE_nurbList_duplicate(&ob->runtime.curve_cache->deformed_nurbs, &nubase);
- curve_calc_modifiers_post(depsgraph, scene, ob, &nubase, dispbase, r_final, for_render);
+ curve_calc_modifiers_post(
+ depsgraph, scene, ob, &nubase, dispbase, r_final, for_render, force_mesh_conversion);
}
BKE_nurbList_free(&nubase);
@@ -1537,6 +1561,7 @@ static void do_makeDispListCurveTypes(Depsgraph *depsgraph,
else if (ELEM(ob->type, OB_CURVE, OB_FONT)) {
ListBase dlbev;
ListBase nubase = {NULL, NULL};
+ bool force_mesh_conversion = false;
BKE_curve_bevelList_free(&ob->runtime.curve_cache->bev);
@@ -1559,7 +1584,7 @@ static void do_makeDispListCurveTypes(Depsgraph *depsgraph,
}
if (!for_orco) {
- curve_calc_modifiers_pre(depsgraph, scene, ob, &nubase, for_render);
+ force_mesh_conversion = curve_calc_modifiers_pre(depsgraph, scene, ob, &nubase, for_render);
}
BKE_curve_bevelList_make(ob, &nubase, for_render);
@@ -1769,7 +1794,8 @@ static void do_makeDispListCurveTypes(Depsgraph *depsgraph,
if (!for_orco) {
BKE_nurbList_duplicate(&ob->runtime.curve_cache->deformed_nurbs, &nubase);
- curve_calc_modifiers_post(depsgraph, scene, ob, &nubase, dispbase, r_final, for_render);
+ curve_calc_modifiers_post(
+ depsgraph, scene, ob, &nubase, dispbase, r_final, for_render, force_mesh_conversion);
}
if (cu->flag & CU_DEFORM_FILL && !ob->runtime.data_eval) {
diff --git a/source/blender/blenkernel/intern/displist_tangent.c b/source/blender/blenkernel/intern/displist_tangent.c
index 4ac8d47feba..88fef1a4cfd 100644
--- a/source/blender/blenkernel/intern/displist_tangent.c
+++ b/source/blender/blenkernel/intern/displist_tangent.c
@@ -144,7 +144,7 @@ static int face_to_vert_index(SGLSLDisplistToTangent *dlt,
v += 1;
}
- /* Cyclic correction. */
+ /* Cyclic correction. */
u = u % dlt->dl->nr;
v = v % dlt->dl->parts;
diff --git a/source/blender/blenkernel/intern/dynamicpaint.c b/source/blender/blenkernel/intern/dynamicpaint.c
index 1054988f22f..dae8a59fe43 100644
--- a/source/blender/blenkernel/intern/dynamicpaint.c
+++ b/source/blender/blenkernel/intern/dynamicpaint.c
@@ -46,7 +46,6 @@
#include "DNA_scene_types.h"
#include "DNA_texture_types.h"
-#include "BKE_animsys.h"
#include "BKE_armature.h"
#include "BKE_bvhutils.h" /* bvh tree */
#include "BKE_collection.h"
@@ -541,7 +540,7 @@ static int surface_getBrushFlags(DynamicPaintSurface *surface, Depsgraph *depsgr
for (int i = 0; i < numobjects; i++) {
Object *brushObj = objects[i];
- ModifierData *md = modifiers_findByType(brushObj, eModifierType_DynamicPaint);
+ ModifierData *md = BKE_modifiers_findby_type(brushObj, eModifierType_DynamicPaint);
if (md && md->mode & (eModifierMode_Realtime | eModifierMode_Render)) {
DynamicPaintModifierData *pmd2 = (DynamicPaintModifierData *)md;
@@ -654,15 +653,15 @@ static void grid_bound_insert_cb_ex(void *__restrict userdata,
boundInsert(grid_bound, bData->realCoord[bData->s_pos[i]].v);
}
-static void grid_bound_insert_finalize(void *__restrict userdata, void *__restrict userdata_chunk)
+static void grid_bound_insert_reduce(const void *__restrict UNUSED(userdata),
+ void *__restrict chunk_join,
+ void *__restrict chunk)
{
- PaintBakeData *bData = userdata;
- VolumeGrid *grid = bData->grid;
+ Bounds3D *join = chunk_join;
+ Bounds3D *grid_bound = chunk;
- Bounds3D *grid_bound = userdata_chunk;
-
- boundInsert(&grid->grid_bounds, grid_bound->min);
- boundInsert(&grid->grid_bounds, grid_bound->max);
+ boundInsert(join, grid_bound->min);
+ boundInsert(join, grid_bound->max);
}
static void grid_cell_points_cb_ex(void *__restrict userdata,
@@ -686,17 +685,20 @@ static void grid_cell_points_cb_ex(void *__restrict userdata,
s_num[temp_t_index[i]]++;
}
-static void grid_cell_points_finalize(void *__restrict userdata, void *__restrict userdata_chunk)
+static void grid_cell_points_reduce(const void *__restrict userdata,
+ void *__restrict chunk_join,
+ void *__restrict chunk)
{
- PaintBakeData *bData = userdata;
- VolumeGrid *grid = bData->grid;
+ const PaintBakeData *bData = userdata;
+ const VolumeGrid *grid = bData->grid;
const int grid_cells = grid->dim[0] * grid->dim[1] * grid->dim[2];
- int *s_num = userdata_chunk;
+ int *join_s_num = chunk_join;
+ int *s_num = chunk;
/* calculate grid indexes */
for (int i = 0; i < grid_cells; i++) {
- grid->s_num[i] += s_num[i];
+ join_s_num[i] += s_num[i];
}
}
@@ -754,7 +756,7 @@ static void surfaceGenerateGrid(struct DynamicPaintSurface *surface)
settings.use_threading = (sData->total_points > 1000);
settings.userdata_chunk = &grid->grid_bounds;
settings.userdata_chunk_size = sizeof(grid->grid_bounds);
- settings.func_finalize = grid_bound_insert_finalize;
+ settings.func_reduce = grid_bound_insert_reduce;
BLI_task_parallel_range(0, sData->total_points, bData, grid_bound_insert_cb_ex, &settings);
}
/* get dimensions */
@@ -815,7 +817,7 @@ static void surfaceGenerateGrid(struct DynamicPaintSurface *surface)
settings.use_threading = (sData->total_points > 1000);
settings.userdata_chunk = grid->s_num;
settings.userdata_chunk_size = sizeof(*grid->s_num) * grid_cells;
- settings.func_finalize = grid_cell_points_finalize;
+ settings.func_reduce = grid_cell_points_reduce;
BLI_task_parallel_range(0, sData->total_points, bData, grid_cell_points_cb_ex, &settings);
}
@@ -1097,7 +1099,7 @@ DynamicPaintSurface *dynamicPaint_createNewSurface(DynamicPaintCanvasSettings *c
surface->wave_spring = 0.20f;
surface->wave_smoothness = 1.0f;
- modifier_path_init(
+ BKE_modifier_path_init(
surface->image_output_path, sizeof(surface->image_output_path), "cache_dynamicpaint");
/* Using ID_BRUSH i18n context, as we have no physics/dpaint one for now... */
@@ -2430,6 +2432,8 @@ static float dist_squared_to_looptri_uv_edges(const MLoopTri *mlooptri,
int tri_index,
const float point[2])
{
+ BLI_assert(tri_index >= 0);
+
float min_distance = FLT_MAX;
for (int i = 0; i < 3; i++) {
@@ -2700,15 +2704,16 @@ static void dynamic_paint_find_island_border(const DynamicPaintCreateUVSurfaceDa
}
}
+ const int final_tri_index = tempPoints[final_index].tri_index;
/* If found pixel still lies on wrong face ( mesh has smaller than pixel sized faces) */
- if (tempPoints[final_index].tri_index != target_tri) {
+ if (final_tri_index != target_tri && final_tri_index != -1) {
/* Check if it's close enough to likely touch the intended triangle. Any triangle
* becomes thinner than a pixel at its vertices, so robustness requires some margin. */
const float final_pt[2] = {((final_index % w) + 0.5f) / w, ((final_index / w) + 0.5f) / h};
const float threshold = square_f(0.7f) / (w * h);
- if (dist_squared_to_looptri_uv_edges(
- mlooptri, mloopuv, tempPoints[final_index].tri_index, final_pt) > threshold) {
+ if (dist_squared_to_looptri_uv_edges(mlooptri, mloopuv, final_tri_index, final_pt) >
+ threshold) {
continue;
}
}
@@ -4642,9 +4647,6 @@ static int dynamicPaint_paintParticles(DynamicPaintSurface *surface,
return 1;
}
- /* begin thread safe malloc */
- BLI_threaded_malloc_begin();
-
/* only continue if particle bb is close enough to canvas bb */
if (boundsIntersectDist(&grid->grid_bounds, &part_bb, range)) {
int c_index;
@@ -4680,7 +4682,6 @@ static int dynamicPaint_paintParticles(DynamicPaintSurface *surface,
&settings);
}
}
- BLI_threaded_malloc_end();
BLI_kdtree_3d_free(tree);
return 1;
@@ -4881,7 +4882,7 @@ static void dynamicPaint_prepareAdjacencyData(DynamicPaintSurface *surface, cons
0, sData->total_points, sData, dynamic_paint_prepare_adjacency_cb, &settings);
/* calculate average values (single thread).
- * Note: tried to put this in threaded callback (using _finalize feature),
+ * Note: tried to put this in threaded callback (using _reduce feature),
* but gave ~30% slower result! */
bData->average_dist = 0.0;
for (index = 0; index < sData->total_points; index++) {
@@ -6244,7 +6245,7 @@ static int dynamicPaint_doStep(Depsgraph *depsgraph,
Object *brushObj = objects[i];
/* check if target has an active dp modifier */
- ModifierData *md = modifiers_findByType(brushObj, eModifierType_DynamicPaint);
+ ModifierData *md = BKE_modifiers_findby_type(brushObj, eModifierType_DynamicPaint);
if (md && md->mode & (eModifierMode_Realtime | eModifierMode_Render)) {
DynamicPaintModifierData *pmd2 = (DynamicPaintModifierData *)md;
/* make sure we're dealing with a brush */
diff --git a/source/blender/blenkernel/intern/editmesh.c b/source/blender/blenkernel/intern/editmesh.c
index 94976ed0c96..c4160d6d253 100644
--- a/source/blender/blenkernel/intern/editmesh.c
+++ b/source/blender/blenkernel/intern/editmesh.c
@@ -32,6 +32,7 @@
#include "BKE_DerivedMesh.h"
#include "BKE_editmesh.h"
+#include "BKE_editmesh_cache.h"
#include "BKE_lib_id.h"
#include "BKE_mesh.h"
#include "BKE_mesh_iterators.h"
@@ -67,6 +68,10 @@ BMEditMesh *BKE_editmesh_copy(BMEditMesh *em)
* tessellation only when/if that copy ends up getting used. */
em_copy->looptris = NULL;
+ /* Copy various settings. */
+ em_copy->selectmode = em->selectmode;
+ em_copy->mat_nr = em->mat_nr;
+
return em_copy;
}
@@ -262,7 +267,7 @@ BoundBox *BKE_editmesh_cage_boundbox_get(BMEditMesh *em)
float min[3], max[3];
INIT_MINMAX(min, max);
if (em->mesh_eval_cage) {
- BKE_mesh_minmax(em->mesh_eval_cage, min, max);
+ BKE_mesh_wrapper_minmax(em->mesh_eval_cage, min, max);
}
em->bb_cage = MEM_callocN(sizeof(BoundBox), "BMEditMesh.bb_cage");
diff --git a/source/blender/blenkernel/intern/editmesh_cache.c b/source/blender/blenkernel/intern/editmesh_cache.c
index 8d3f1e84bcd..5017a48d14e 100644
--- a/source/blender/blenkernel/intern/editmesh_cache.c
+++ b/source/blender/blenkernel/intern/editmesh_cache.c
@@ -22,11 +22,17 @@
#include "MEM_guardedalloc.h"
+#include "BLI_math_vector.h"
+
#include "DNA_mesh_types.h"
#include "BKE_editmesh.h"
#include "BKE_editmesh_cache.h" /* own include */
+/* -------------------------------------------------------------------- */
+/** \name Ensure Data (derived from coords)
+ * \{ */
+
void BKE_editmesh_cache_ensure_poly_normals(BMEditMesh *em, EditMeshData *emd)
{
if (!(emd->vertexCos && (emd->polyNos == NULL))) {
@@ -112,3 +118,41 @@ void BKE_editmesh_cache_ensure_poly_centers(BMEditMesh *em, EditMeshData *emd)
emd->polyCos = (const float(*)[3])polyCos;
}
+
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Calculate Min/Max
+ * \{ */
+
+bool BKE_editmesh_cache_calc_minmax(struct BMEditMesh *em,
+ struct EditMeshData *emd,
+ float min[3],
+ float max[3])
+{
+ BMesh *bm = em->bm;
+ BMVert *eve;
+ BMIter iter;
+ int i;
+
+ if (bm->totvert) {
+ if (emd->vertexCos) {
+ BM_ITER_MESH_INDEX (eve, &iter, bm, BM_VERTS_OF_MESH, i) {
+ minmax_v3v3_v3(min, max, emd->vertexCos[i]);
+ }
+ }
+ else {
+ BM_ITER_MESH (eve, &iter, bm, BM_VERTS_OF_MESH) {
+ minmax_v3v3_v3(min, max, eve->co);
+ }
+ }
+ return true;
+ }
+ else {
+ zero_v3(min);
+ zero_v3(max);
+ return false;
+ }
+}
+
+/** \} */
diff --git a/source/blender/blenkernel/intern/editmesh_tangent.c b/source/blender/blenkernel/intern/editmesh_tangent.c
index e291a68a4b1..6fcaf84d4ca 100644
--- a/source/blender/blenkernel/intern/editmesh_tangent.c
+++ b/source/blender/blenkernel/intern/editmesh_tangent.c
@@ -251,9 +251,7 @@ finally:
pRes[3] = fSign;
}
-static void emDM_calc_loop_tangents_thread(TaskPool *__restrict UNUSED(pool),
- void *taskdata,
- int UNUSED(threadid))
+static void emDM_calc_loop_tangents_thread(TaskPool *__restrict UNUSED(pool), void *taskdata)
{
struct SGLSLEditMeshToTangent *mesh2tangent = taskdata;
/* new computation method */
@@ -362,9 +360,8 @@ void BKE_editmesh_loop_tangent_calc(BMEditMesh *em,
#endif
/* Calculation */
if (em->tottri != 0) {
- TaskScheduler *scheduler = BLI_task_scheduler_get();
TaskPool *task_pool;
- task_pool = BLI_task_pool_create(scheduler, NULL);
+ task_pool = BLI_task_pool_create(NULL, TASK_PRIORITY_LOW);
tangent_mask_curr = 0;
/* Calculate tangent layers */
@@ -417,8 +414,7 @@ void BKE_editmesh_loop_tangent_calc(BMEditMesh *em,
mesh2tangent->looptris = (const BMLoop *(*)[3])em->looptris;
mesh2tangent->tangent = loopdata_out->layers[index].data;
- BLI_task_pool_push(
- task_pool, emDM_calc_loop_tangents_thread, mesh2tangent, false, TASK_PRIORITY_LOW);
+ BLI_task_pool_push(task_pool, emDM_calc_loop_tangents_thread, mesh2tangent, false, NULL);
}
BLI_assert(tangent_mask_curr == tangent_mask);
diff --git a/source/blender/blenkernel/intern/effect.c b/source/blender/blenkernel/intern/effect.c
index f7ddc4385ac..fe2c9ed51b8 100644
--- a/source/blender/blenkernel/intern/effect.c
+++ b/source/blender/blenkernel/intern/effect.c
@@ -49,7 +49,7 @@
#include "PIL_time.h"
-#include "BKE_anim.h" /* needed for where_on_path */
+#include "BKE_anim_path.h" /* needed for where_on_path */
#include "BKE_bvhutils.h"
#include "BKE_collection.h"
#include "BKE_collision.h"
@@ -113,7 +113,7 @@ PartDeflect *BKE_partdeflect_new(int type)
case PFIELD_TEXTURE:
pd->f_size = 1.0f;
break;
- case PFIELD_SMOKEFLOW:
+ case PFIELD_FLUIDFLOW:
pd->f_flow = 1.0f;
break;
}
@@ -177,7 +177,7 @@ static void precalculate_effector(struct Depsgraph *depsgraph, EffectorCache *ef
}
}
else if (eff->pd->shape == PFIELD_SHAPE_SURFACE) {
- eff->surmd = (SurfaceModifierData *)modifiers_findByType(eff->ob, eModifierType_Surface);
+ eff->surmd = (SurfaceModifierData *)BKE_modifiers_findby_type(eff->ob, eModifierType_Surface);
if (eff->ob->type == OB_CURVE) {
eff->flag |= PE_USE_NORMAL_DATA;
}
@@ -247,7 +247,7 @@ ListBase *BKE_effector_relations_create(Depsgraph *depsgraph,
add_effector_relation(relations, ob, NULL, ob->pd);
}
- for (ParticleSystem *psys = ob->particlesystem.first; psys; psys = psys->next) {
+ LISTBASE_FOREACH (ParticleSystem *, psys, &ob->particlesystem) {
ParticleSettings *part = psys->part;
if (psys_check_enabled(ob, psys, for_render)) {
@@ -286,7 +286,7 @@ ListBase *BKE_effectors_create(Depsgraph *depsgraph,
return NULL;
}
- for (EffectorRelation *relation = relations->first; relation; relation = relation->next) {
+ LISTBASE_FOREACH (EffectorRelation *, relation, relations) {
/* Get evaluated object. */
Object *ob = (Object *)DEG_get_evaluated_id(depsgraph, &relation->ob->id);
@@ -329,7 +329,7 @@ ListBase *BKE_effectors_create(Depsgraph *depsgraph,
void BKE_effectors_free(ListBase *lb)
{
if (lb) {
- for (EffectorCache *eff = lb->first; eff; eff = eff->next) {
+ LISTBASE_FOREACH (EffectorCache *, eff, lb) {
if (eff->guide_data) {
MEM_freeN(eff->guide_data);
}
@@ -1024,7 +1024,7 @@ static void do_physical_effector(EffectorCache *eff,
mul_v3_fl(force, -efd->falloff * fac * (strength * fac + damp));
break;
- case PFIELD_SMOKEFLOW:
+ case PFIELD_FLUIDFLOW:
zero_v3(force);
#ifdef WITH_FLUID
if (pd->f_source) {
@@ -1046,7 +1046,7 @@ static void do_physical_effector(EffectorCache *eff,
if (pd->flag & PFIELD_DO_LOCATION) {
madd_v3_v3fl(total_force, force, 1.0f / point->vel_to_sec);
- if (ELEM(pd->forcefield, PFIELD_HARMONIC, PFIELD_DRAG, PFIELD_SMOKEFLOW) == 0 &&
+ if (ELEM(pd->forcefield, PFIELD_HARMONIC, PFIELD_DRAG, PFIELD_FLUIDFLOW) == 0 &&
pd->f_flow != 0.0f) {
madd_v3_v3fl(total_force, point->vel, -pd->f_flow * efd->falloff);
}
diff --git a/source/blender/blenkernel/intern/fcurve.c b/source/blender/blenkernel/intern/fcurve.c
index 4bd55c3c2ca..d4754615c7f 100644
--- a/source/blender/blenkernel/intern/fcurve.c
+++ b/source/blender/blenkernel/intern/fcurve.c
@@ -30,56 +30,43 @@
#include "MEM_guardedalloc.h"
#include "DNA_anim_types.h"
-#include "DNA_constraint_types.h"
#include "DNA_object_types.h"
+#include "DNA_text_types.h"
-#include "BLI_alloca.h"
#include "BLI_blenlib.h"
#include "BLI_easing.h"
-#include "BLI_expr_pylike_eval.h"
#include "BLI_math.h"
-#include "BLI_string_utils.h"
-#include "BLI_threads.h"
-#include "BLI_utildefines.h"
-#include "BLT_translation.h"
-
-#include "BKE_action.h"
+#include "BKE_anim_data.h"
#include "BKE_animsys.h"
-#include "BKE_armature.h"
-#include "BKE_constraint.h"
#include "BKE_context.h"
#include "BKE_curve.h"
#include "BKE_fcurve.h"
+#include "BKE_fcurve_driver.h"
#include "BKE_global.h"
+#include "BKE_idprop.h"
+#include "BKE_lib_query.h"
#include "BKE_nla.h"
-#include "BKE_object.h"
#include "RNA_access.h"
-#include "atomic_ops.h"
-
#include "CLG_log.h"
-#ifdef WITH_PYTHON
-# include "BPY_extern.h"
-#endif
-
#define SMALL -1.0e-10
#define SELECT 1
-#ifdef WITH_PYTHON
-static ThreadMutex python_driver_lock = BLI_MUTEX_INITIALIZER;
-#endif
-
static CLG_LogRef LOG = {"bke.fcurve"};
/* ************************** Data-Level Functions ************************* */
-
+FCurve *BKE_fcurve_create(void)
+{
+ FCurve *fcu = MEM_callocN(sizeof(FCurve), __func__);
+ return fcu;
+}
/* ---------------------- Freeing --------------------------- */
/* Frees the F-Curve itself too, so make sure BLI_remlink is called before calling this... */
-void free_fcurve(FCurve *fcu)
+void BKE_fcurve_free(FCurve *fcu)
{
if (fcu == NULL) {
return;
@@ -101,7 +88,7 @@ void free_fcurve(FCurve *fcu)
}
/* Frees a list of F-Curves */
-void free_fcurves(ListBase *list)
+void BKE_fcurves_free(ListBase *list)
{
FCurve *fcu, *fcn;
@@ -116,7 +103,7 @@ void free_fcurves(ListBase *list)
*/
for (fcu = list->first; fcu; fcu = fcn) {
fcn = fcu->next;
- free_fcurve(fcu);
+ BKE_fcurve_free(fcu);
}
/* clear pointers just in case */
@@ -126,7 +113,7 @@ void free_fcurves(ListBase *list)
/* ---------------------- Copy --------------------------- */
/* duplicate an F-Curve */
-FCurve *copy_fcurve(const FCurve *fcu)
+FCurve *BKE_fcurve_copy(const FCurve *fcu)
{
FCurve *fcu_d;
@@ -159,7 +146,7 @@ FCurve *copy_fcurve(const FCurve *fcu)
}
/* duplicate a list of F-Curves */
-void copy_fcurves(ListBase *dst, ListBase *src)
+void BKE_fcurves_copy(ListBase *dst, ListBase *src)
{
FCurve *dfcu, *sfcu;
@@ -173,11 +160,43 @@ void copy_fcurves(ListBase *dst, ListBase *src)
/* copy one-by-one */
for (sfcu = src->first; sfcu; sfcu = sfcu->next) {
- dfcu = copy_fcurve(sfcu);
+ dfcu = BKE_fcurve_copy(sfcu);
BLI_addtail(dst, dfcu);
}
}
+/** Callback used by lib_query to walk over all ID usages (mimics `foreach_id` callback of
+ * `IDTypeInfo` structure). */
+void BKE_fcurve_foreach_id(FCurve *fcu, LibraryForeachIDData *data)
+{
+ ChannelDriver *driver = fcu->driver;
+
+ if (driver != NULL) {
+ LISTBASE_FOREACH (DriverVar *, dvar, &driver->variables) {
+ /* only used targets */
+ DRIVER_TARGETS_USED_LOOPER_BEGIN (dvar) {
+ BKE_LIB_FOREACHID_PROCESS_ID(data, dtar->id, IDWALK_CB_NOP);
+ }
+ DRIVER_TARGETS_LOOPER_END;
+ }
+ }
+
+ LISTBASE_FOREACH (FModifier *, fcm, &fcu->modifiers) {
+ switch (fcm->type) {
+ case FMODIFIER_TYPE_PYTHON: {
+ FMod_Python *fcm_py = (FMod_Python *)fcm->data;
+ BKE_LIB_FOREACHID_PROCESS(data, fcm_py->script, IDWALK_CB_NOP);
+
+ IDP_foreach_property(fcm_py->prop,
+ IDP_TYPE_FILTER_ID,
+ BKE_lib_query_idpropertiesForeachIDLink_callback,
+ data);
+ break;
+ }
+ }
+ }
+}
+
/* ----------------- Finding F-Curves -------------------------- */
/* high level function to get an fcurve from C without having the rna */
@@ -215,12 +234,12 @@ FCurve *id_data_find_fcurve(
/* animation takes priority over drivers */
if (adt->action && adt->action->curves.first) {
- fcu = list_find_fcurve(&adt->action->curves, path, index);
+ fcu = BKE_fcurve_find(&adt->action->curves, path, index);
}
/* if not animated, check if driven */
if (fcu == NULL && adt->drivers.first) {
- fcu = list_find_fcurve(&adt->drivers, path, index);
+ fcu = BKE_fcurve_find(&adt->drivers, path, index);
if (fcu && r_driven) {
*r_driven = true;
}
@@ -234,7 +253,7 @@ FCurve *id_data_find_fcurve(
/* Find the F-Curve affecting the given RNA-access path + index,
* in the list of F-Curves provided. */
-FCurve *list_find_fcurve(ListBase *list, const char rna_path[], const int array_index)
+FCurve *BKE_fcurve_find(ListBase *list, const char rna_path[], const int array_index)
{
FCurve *fcu;
@@ -259,7 +278,7 @@ FCurve *list_find_fcurve(ListBase *list, const char rna_path[], const int array_
}
/* quick way to loop over all fcurves of a given 'path' */
-FCurve *iter_step_fcurve(FCurve *fcu_iter, const char rna_path[])
+FCurve *BKE_fcurve_iter_step(FCurve *fcu_iter, const char rna_path[])
{
FCurve *fcu;
@@ -292,10 +311,7 @@ FCurve *iter_step_fcurve(FCurve *fcu_iter, const char rna_path[])
* - dataPrefix: i.e. 'pose.bones[' or 'nodes['
* - dataName: name of entity within "" immediately following the prefix
*/
-int list_find_data_fcurves(ListBase *dst,
- ListBase *src,
- const char *dataPrefix,
- const char *dataName)
+int BKE_fcurves_filter(ListBase *dst, ListBase *src, const char *dataPrefix, const char *dataName)
{
FCurve *fcu;
int matches = 0;
@@ -337,26 +353,26 @@ int list_find_data_fcurves(ListBase *dst,
return matches;
}
-FCurve *rna_get_fcurve(PointerRNA *ptr,
- PropertyRNA *prop,
- int rnaindex,
- AnimData **r_adt,
- bAction **r_action,
- bool *r_driven,
- bool *r_special)
+FCurve *BKE_fcurve_find_by_rna(PointerRNA *ptr,
+ PropertyRNA *prop,
+ int rnaindex,
+ AnimData **r_adt,
+ bAction **r_action,
+ bool *r_driven,
+ bool *r_special)
{
- return rna_get_fcurve_context_ui(
+ return BKE_fcurve_find_by_rna_context_ui(
NULL, ptr, prop, rnaindex, r_adt, r_action, r_driven, r_special);
}
-FCurve *rna_get_fcurve_context_ui(bContext *C,
- PointerRNA *ptr,
- PropertyRNA *prop,
- int rnaindex,
- AnimData **r_animdata,
- bAction **r_action,
- bool *r_driven,
- bool *r_special)
+FCurve *BKE_fcurve_find_by_rna_context_ui(bContext *C,
+ PointerRNA *ptr,
+ PropertyRNA *prop,
+ int rnaindex,
+ AnimData **r_animdata,
+ bAction **r_action,
+ bool *r_driven,
+ bool *r_special)
{
FCurve *fcu = NULL;
PointerRNA tptr = *ptr;
@@ -381,7 +397,7 @@ FCurve *rna_get_fcurve_context_ui(bContext *C,
*r_special = true;
/* The F-Curve either exists or it doesn't here... */
- fcu = list_find_fcurve(&strip->fcurves, RNA_property_identifier(prop), rnaindex);
+ fcu = BKE_fcurve_find(&strip->fcurves, RNA_property_identifier(prop), rnaindex);
return fcu;
}
@@ -417,7 +433,7 @@ FCurve *rna_get_fcurve_context_ui(bContext *C,
// XXX: the logic here is duplicated with a function up above
/* animation takes priority over drivers */
if (adt->action && adt->action->curves.first) {
- fcu = list_find_fcurve(&adt->action->curves, path, rnaindex);
+ fcu = BKE_fcurve_find(&adt->action->curves, path, rnaindex);
if (fcu && r_action) {
*r_action = adt->action;
@@ -426,7 +442,7 @@ FCurve *rna_get_fcurve_context_ui(bContext *C,
/* if not animated, check if driven */
if (!fcu && (adt->drivers.first)) {
- fcu = list_find_fcurve(&adt->drivers, path, rnaindex);
+ fcu = BKE_fcurve_find(&adt->drivers, path, rnaindex);
if (fcu) {
if (r_animdata) {
@@ -616,13 +632,13 @@ static short get_fcurve_end_keyframes(FCurve *fcu,
}
/* Calculate the extents of F-Curve's data */
-bool calc_fcurve_bounds(FCurve *fcu,
- float *xmin,
- float *xmax,
- float *ymin,
- float *ymax,
- const bool do_sel_only,
- const bool include_handles)
+bool BKE_fcurve_calc_bounds(FCurve *fcu,
+ float *xmin,
+ float *xmax,
+ float *ymin,
+ float *ymax,
+ const bool do_sel_only,
+ const bool include_handles)
{
float xminv = 999999999.0f, xmaxv = -999999999.0f;
float yminv = 999999999.0f, ymaxv = -999999999.0f;
@@ -746,7 +762,7 @@ bool calc_fcurve_bounds(FCurve *fcu,
}
/* Calculate the extents of F-Curve's keyframes */
-bool calc_fcurve_range(
+bool BKE_fcurve_calc_range(
FCurve *fcu, float *start, float *end, const bool do_sel_only, const bool do_min_length)
{
float min = 999999999.0f, max = -999999999.0f;
@@ -799,7 +815,7 @@ bool calc_fcurve_range(
* Usability of keyframes refers to whether they should be displayed,
* and also whether they will have any influence on the final result.
*/
-bool fcurve_are_keyframes_usable(FCurve *fcu)
+bool BKE_fcurve_are_keyframes_usable(FCurve *fcu)
{
/* F-Curve must exist */
if (fcu == NULL) {
@@ -867,10 +883,10 @@ bool BKE_fcurve_is_protected(FCurve *fcu)
/* Can keyframes be added to F-Curve?
* Keyframes can only be added if they are already visible
*/
-bool fcurve_is_keyframable(FCurve *fcu)
+bool BKE_fcurve_is_keyframable(FCurve *fcu)
{
/* F-Curve's keyframes must be "usable" (i.e. visible + have an effect on final result) */
- if (fcurve_are_keyframes_usable(fcu) == 0) {
+ if (BKE_fcurve_are_keyframes_usable(fcu) == 0) {
return false;
}
@@ -1167,7 +1183,7 @@ void testhandles_fcurve(FCurve *fcu, eBezTriple_Flag sel_flag, const bool use_ha
/* loop over beztriples */
for (a = 0, bezt = fcu->bezt; a < fcu->totvert; a++, bezt++) {
- BKE_nurb_bezt_handle_test(bezt, sel_flag, use_handle);
+ BKE_nurb_bezt_handle_test(bezt, sel_flag, use_handle, false);
}
/* recalculate handles */
@@ -1255,1236 +1271,6 @@ short test_time_fcurve(FCurve *fcu)
return 0;
}
-/* ***************************** Drivers ********************************* */
-
-/* Driver Variables --------------------------- */
-
-/* TypeInfo for Driver Variables (dvti) */
-typedef struct DriverVarTypeInfo {
- /* evaluation callback */
- float (*get_value)(ChannelDriver *driver, DriverVar *dvar);
-
- /* allocation of target slots */
- int num_targets; /* number of target slots required */
- const char *target_names[MAX_DRIVER_TARGETS]; /* UI names that should be given to the slots */
- short target_flags[MAX_DRIVER_TARGETS]; /* flags defining the requirements for each slot */
-} DriverVarTypeInfo;
-
-/* Macro to begin definitions */
-#define BEGIN_DVAR_TYPEDEF(type) {
-
-/* Macro to end definitions */
-#define END_DVAR_TYPEDEF }
-
-/* ......... */
-
-static ID *dtar_id_ensure_proxy_from(ID *id)
-{
- if (id && GS(id->name) == ID_OB && ((Object *)id)->proxy_from) {
- return (ID *)(((Object *)id)->proxy_from);
- }
- return id;
-}
-
-/**
- * Helper function to obtain a value using RNA from the specified source
- * (for evaluating drivers).
- */
-static float dtar_get_prop_val(ChannelDriver *driver, DriverTarget *dtar)
-{
- PointerRNA id_ptr, ptr;
- PropertyRNA *prop;
- ID *id;
- int index = -1;
- float value = 0.0f;
-
- /* sanity check */
- if (ELEM(NULL, driver, dtar)) {
- return 0.0f;
- }
-
- id = dtar_id_ensure_proxy_from(dtar->id);
-
- /* error check for missing pointer... */
- if (id == NULL) {
- if (G.debug & G_DEBUG) {
- CLOG_ERROR(&LOG, "driver has an invalid target to use (path = %s)", dtar->rna_path);
- }
-
- driver->flag |= DRIVER_FLAG_INVALID;
- dtar->flag |= DTAR_FLAG_INVALID;
- return 0.0f;
- }
-
- /* get RNA-pointer for the ID-block given in target */
- RNA_id_pointer_create(id, &id_ptr);
-
- /* get property to read from, and get value as appropriate */
- if (!RNA_path_resolve_property_full(&id_ptr, dtar->rna_path, &ptr, &prop, &index)) {
- /* path couldn't be resolved */
- if (G.debug & G_DEBUG) {
- CLOG_ERROR(&LOG,
- "Driver Evaluation Error: cannot resolve target for %s -> %s",
- id->name,
- dtar->rna_path);
- }
-
- driver->flag |= DRIVER_FLAG_INVALID;
- dtar->flag |= DTAR_FLAG_INVALID;
- return 0.0f;
- }
-
- if (RNA_property_array_check(prop)) {
- /* array */
- if (index < 0 || index >= RNA_property_array_length(&ptr, prop)) {
- /* out of bounds */
- if (G.debug & G_DEBUG) {
- CLOG_ERROR(&LOG,
- "Driver Evaluation Error: array index is out of bounds for %s -> %s (%d)",
- id->name,
- dtar->rna_path,
- index);
- }
-
- driver->flag |= DRIVER_FLAG_INVALID;
- dtar->flag |= DTAR_FLAG_INVALID;
- return 0.0f;
- }
-
- switch (RNA_property_type(prop)) {
- case PROP_BOOLEAN:
- value = (float)RNA_property_boolean_get_index(&ptr, prop, index);
- break;
- case PROP_INT:
- value = (float)RNA_property_int_get_index(&ptr, prop, index);
- break;
- case PROP_FLOAT:
- value = RNA_property_float_get_index(&ptr, prop, index);
- break;
- default:
- break;
- }
- }
- else {
- /* not an array */
- switch (RNA_property_type(prop)) {
- case PROP_BOOLEAN:
- value = (float)RNA_property_boolean_get(&ptr, prop);
- break;
- case PROP_INT:
- value = (float)RNA_property_int_get(&ptr, prop);
- break;
- case PROP_FLOAT:
- value = RNA_property_float_get(&ptr, prop);
- break;
- case PROP_ENUM:
- value = (float)RNA_property_enum_get(&ptr, prop);
- break;
- default:
- break;
- }
- }
-
- /* if we're still here, we should be ok... */
- dtar->flag &= ~DTAR_FLAG_INVALID;
- return value;
-}
-
-/**
- * Same as 'dtar_get_prop_val'. but get the RNA property.
- */
-bool driver_get_variable_property(ChannelDriver *driver,
- DriverTarget *dtar,
- PointerRNA *r_ptr,
- PropertyRNA **r_prop,
- int *r_index)
-{
- PointerRNA id_ptr;
- PointerRNA ptr;
- PropertyRNA *prop;
- ID *id;
- int index = -1;
-
- /* sanity check */
- if (ELEM(NULL, driver, dtar)) {
- return false;
- }
-
- id = dtar_id_ensure_proxy_from(dtar->id);
-
- /* error check for missing pointer... */
- if (id == NULL) {
- if (G.debug & G_DEBUG) {
- CLOG_ERROR(&LOG, "driver has an invalid target to use (path = %s)", dtar->rna_path);
- }
-
- driver->flag |= DRIVER_FLAG_INVALID;
- dtar->flag |= DTAR_FLAG_INVALID;
- return false;
- }
-
- /* get RNA-pointer for the ID-block given in target */
- RNA_id_pointer_create(id, &id_ptr);
-
- /* get property to read from, and get value as appropriate */
- if (dtar->rna_path == NULL || dtar->rna_path[0] == '\0') {
- ptr = PointerRNA_NULL;
- prop = NULL; /* ok */
- }
- else if (RNA_path_resolve_property_full(&id_ptr, dtar->rna_path, &ptr, &prop, &index)) {
- /* ok */
- }
- else {
- /* path couldn't be resolved */
- if (G.debug & G_DEBUG) {
- CLOG_ERROR(&LOG,
- "Driver Evaluation Error: cannot resolve target for %s -> %s",
- id->name,
- dtar->rna_path);
- }
-
- ptr = PointerRNA_NULL;
- *r_prop = NULL;
- *r_index = -1;
-
- driver->flag |= DRIVER_FLAG_INVALID;
- dtar->flag |= DTAR_FLAG_INVALID;
- return false;
- }
-
- *r_ptr = ptr;
- *r_prop = prop;
- *r_index = index;
-
- /* if we're still here, we should be ok... */
- dtar->flag &= ~DTAR_FLAG_INVALID;
- return true;
-}
-
-static short driver_check_valid_targets(ChannelDriver *driver, DriverVar *dvar)
-{
- short valid_targets = 0;
-
- DRIVER_TARGETS_USED_LOOPER_BEGIN (dvar) {
- Object *ob = (Object *)dtar_id_ensure_proxy_from(dtar->id);
-
- /* check if this target has valid data */
- if ((ob == NULL) || (GS(ob->id.name) != ID_OB)) {
- /* invalid target, so will not have enough targets */
- driver->flag |= DRIVER_FLAG_INVALID;
- dtar->flag |= DTAR_FLAG_INVALID;
- }
- else {
- /* target seems to be OK now... */
- dtar->flag &= ~DTAR_FLAG_INVALID;
- valid_targets++;
- }
- }
- DRIVER_TARGETS_LOOPER_END;
-
- return valid_targets;
-}
-
-/* ......... */
-
-/* evaluate 'single prop' driver variable */
-static float dvar_eval_singleProp(ChannelDriver *driver, DriverVar *dvar)
-{
- /* just evaluate the first target slot */
- return dtar_get_prop_val(driver, &dvar->targets[0]);
-}
-
-/* evaluate 'rotation difference' driver variable */
-static float dvar_eval_rotDiff(ChannelDriver *driver, DriverVar *dvar)
-{
- short valid_targets = driver_check_valid_targets(driver, dvar);
-
- /* make sure we have enough valid targets to use - all or nothing for now... */
- if (driver_check_valid_targets(driver, dvar) != 2) {
- if (G.debug & G_DEBUG) {
- CLOG_WARN(&LOG,
- "RotDiff DVar: not enough valid targets (n = %d) (a = %p, b = %p)",
- valid_targets,
- dvar->targets[0].id,
- dvar->targets[1].id);
- }
- return 0.0f;
- }
-
- float(*mat[2])[4];
-
- /* NOTE: for now, these are all just worldspace */
- for (int i = 0; i < 2; i++) {
- /* get pointer to loc values to store in */
- DriverTarget *dtar = &dvar->targets[i];
- Object *ob = (Object *)dtar_id_ensure_proxy_from(dtar->id);
- bPoseChannel *pchan;
-
- /* after the checks above, the targets should be valid here... */
- BLI_assert((ob != NULL) && (GS(ob->id.name) == ID_OB));
-
- /* try to get posechannel */
- pchan = BKE_pose_channel_find_name(ob->pose, dtar->pchan_name);
-
- /* check if object or bone */
- if (pchan) {
- /* bone */
- mat[i] = pchan->pose_mat;
- }
- else {
- /* object */
- mat[i] = ob->obmat;
- }
- }
-
- float q1[4], q2[4], quat[4], angle;
-
- /* use the final posed locations */
- mat4_to_quat(q1, mat[0]);
- mat4_to_quat(q2, mat[1]);
-
- invert_qt_normalized(q1);
- mul_qt_qtqt(quat, q1, q2);
- angle = 2.0f * (saacos(quat[0]));
- angle = fabsf(angle);
-
- return (angle > (float)M_PI) ? (float)((2.0f * (float)M_PI) - angle) : (float)(angle);
-}
-
-/* evaluate 'location difference' driver variable */
-/* TODO: this needs to take into account space conversions... */
-static float dvar_eval_locDiff(ChannelDriver *driver, DriverVar *dvar)
-{
- float loc1[3] = {0.0f, 0.0f, 0.0f};
- float loc2[3] = {0.0f, 0.0f, 0.0f};
- short valid_targets = driver_check_valid_targets(driver, dvar);
-
- /* make sure we have enough valid targets to use - all or nothing for now... */
- if (valid_targets < dvar->num_targets) {
- if (G.debug & G_DEBUG) {
- CLOG_WARN(&LOG,
- "LocDiff DVar: not enough valid targets (n = %d) (a = %p, b = %p)",
- valid_targets,
- dvar->targets[0].id,
- dvar->targets[1].id);
- }
- return 0.0f;
- }
-
- /* SECOND PASS: get two location values */
- /* NOTE: for now, these are all just worldspace */
- DRIVER_TARGETS_USED_LOOPER_BEGIN (dvar) {
- /* get pointer to loc values to store in */
- Object *ob = (Object *)dtar_id_ensure_proxy_from(dtar->id);
- bPoseChannel *pchan;
- float tmp_loc[3];
-
- /* after the checks above, the targets should be valid here... */
- BLI_assert((ob != NULL) && (GS(ob->id.name) == ID_OB));
-
- /* try to get posechannel */
- pchan = BKE_pose_channel_find_name(ob->pose, dtar->pchan_name);
-
- /* check if object or bone */
- if (pchan) {
- /* bone */
- if (dtar->flag & DTAR_FLAG_LOCALSPACE) {
- if (dtar->flag & DTAR_FLAG_LOCAL_CONSTS) {
- float mat[4][4];
-
- /* extract transform just like how the constraints do it! */
- copy_m4_m4(mat, pchan->pose_mat);
- BKE_constraint_mat_convertspace(
- ob, pchan, mat, CONSTRAINT_SPACE_POSE, CONSTRAINT_SPACE_LOCAL, false);
-
- /* ... and from that, we get our transform */
- copy_v3_v3(tmp_loc, mat[3]);
- }
- else {
- /* transform space (use transform values directly) */
- copy_v3_v3(tmp_loc, pchan->loc);
- }
- }
- else {
- /* convert to worldspace */
- copy_v3_v3(tmp_loc, pchan->pose_head);
- mul_m4_v3(ob->obmat, tmp_loc);
- }
- }
- else {
- /* object */
- if (dtar->flag & DTAR_FLAG_LOCALSPACE) {
- if (dtar->flag & DTAR_FLAG_LOCAL_CONSTS) {
- /* XXX: this should practically be the same as transform space... */
- float mat[4][4];
-
- /* extract transform just like how the constraints do it! */
- copy_m4_m4(mat, ob->obmat);
- BKE_constraint_mat_convertspace(
- ob, NULL, mat, CONSTRAINT_SPACE_WORLD, CONSTRAINT_SPACE_LOCAL, false);
-
- /* ... and from that, we get our transform */
- copy_v3_v3(tmp_loc, mat[3]);
- }
- else {
- /* transform space (use transform values directly) */
- copy_v3_v3(tmp_loc, ob->loc);
- }
- }
- else {
- /* worldspace */
- copy_v3_v3(tmp_loc, ob->obmat[3]);
- }
- }
-
- /* copy the location to the right place */
- if (tarIndex) {
- copy_v3_v3(loc2, tmp_loc);
- }
- else {
- copy_v3_v3(loc1, tmp_loc);
- }
- }
- DRIVER_TARGETS_LOOPER_END;
-
- /* if we're still here, there should now be two targets to use,
- * so just take the length of the vector between these points
- */
- return len_v3v3(loc1, loc2);
-}
-
-/* evaluate 'transform channel' driver variable */
-static float dvar_eval_transChan(ChannelDriver *driver, DriverVar *dvar)
-{
- DriverTarget *dtar = &dvar->targets[0];
- Object *ob = (Object *)dtar_id_ensure_proxy_from(dtar->id);
- bPoseChannel *pchan;
- float mat[4][4];
- float oldEul[3] = {0.0f, 0.0f, 0.0f};
- bool use_eulers = false;
- short rot_order = ROT_MODE_EUL;
-
- /* check if this target has valid data */
- if ((ob == NULL) || (GS(ob->id.name) != ID_OB)) {
- /* invalid target, so will not have enough targets */
- driver->flag |= DRIVER_FLAG_INVALID;
- dtar->flag |= DTAR_FLAG_INVALID;
- return 0.0f;
- }
- else {
- /* target should be valid now */
- dtar->flag &= ~DTAR_FLAG_INVALID;
- }
-
- /* try to get posechannel */
- pchan = BKE_pose_channel_find_name(ob->pose, dtar->pchan_name);
-
- /* check if object or bone, and get transform matrix accordingly
- * - "useEulers" code is used to prevent the problems associated with non-uniqueness
- * of euler decomposition from matrices [#20870]
- * - localspace is for [#21384], where parent results are not wanted
- * but local-consts is for all the common "corrective-shapes-for-limbs" situations
- */
- if (pchan) {
- /* bone */
- if (pchan->rotmode > 0) {
- copy_v3_v3(oldEul, pchan->eul);
- rot_order = pchan->rotmode;
- use_eulers = true;
- }
-
- if (dtar->flag & DTAR_FLAG_LOCALSPACE) {
- if (dtar->flag & DTAR_FLAG_LOCAL_CONSTS) {
- /* just like how the constraints do it! */
- copy_m4_m4(mat, pchan->pose_mat);
- BKE_constraint_mat_convertspace(
- ob, pchan, mat, CONSTRAINT_SPACE_POSE, CONSTRAINT_SPACE_LOCAL, false);
- }
- else {
- /* specially calculate local matrix, since chan_mat is not valid
- * since it stores delta transform of pose_mat so that deforms work
- * so it cannot be used here for "transform" space
- */
- BKE_pchan_to_mat4(pchan, mat);
- }
- }
- else {
- /* worldspace matrix */
- mul_m4_m4m4(mat, ob->obmat, pchan->pose_mat);
- }
- }
- else {
- /* object */
- if (ob->rotmode > 0) {
- copy_v3_v3(oldEul, ob->rot);
- rot_order = ob->rotmode;
- use_eulers = true;
- }
-
- if (dtar->flag & DTAR_FLAG_LOCALSPACE) {
- if (dtar->flag & DTAR_FLAG_LOCAL_CONSTS) {
- /* just like how the constraints do it! */
- copy_m4_m4(mat, ob->obmat);
- BKE_constraint_mat_convertspace(
- ob, NULL, mat, CONSTRAINT_SPACE_WORLD, CONSTRAINT_SPACE_LOCAL, false);
- }
- else {
- /* transforms to matrix */
- BKE_object_to_mat4(ob, mat);
- }
- }
- else {
- /* worldspace matrix - just the good-old one */
- copy_m4_m4(mat, ob->obmat);
- }
- }
-
- /* check which transform */
- if (dtar->transChan >= MAX_DTAR_TRANSCHAN_TYPES) {
- /* not valid channel */
- return 0.0f;
- }
- else if (dtar->transChan == DTAR_TRANSCHAN_SCALE_AVG) {
- /* Cubic root of the change in volume, equal to the geometric mean
- * of scale over all three axes unless the matrix includes shear. */
- return cbrtf(mat4_to_volume_scale(mat));
- }
- else if (ELEM(dtar->transChan,
- DTAR_TRANSCHAN_SCALEX,
- DTAR_TRANSCHAN_SCALEY,
- DTAR_TRANSCHAN_SCALEZ)) {
- /* Extract scale, and choose the right axis,
- * inline 'mat4_to_size'. */
- return len_v3(mat[dtar->transChan - DTAR_TRANSCHAN_SCALEX]);
- }
- else if (dtar->transChan >= DTAR_TRANSCHAN_ROTX) {
- /* extract rotation as eulers (if needed)
- * - definitely if rotation order isn't eulers already
- * - if eulers, then we have 2 options:
- * a) decompose transform matrix as required, then try to make eulers from
- * there compatible with original values
- * b) [NOT USED] directly use the original values (no decomposition)
- * - only an option for "transform space", if quality is really bad with a)
- */
- float quat[4];
- int channel;
-
- if (dtar->transChan == DTAR_TRANSCHAN_ROTW) {
- channel = 0;
- }
- else {
- channel = 1 + dtar->transChan - DTAR_TRANSCHAN_ROTX;
- BLI_assert(channel < 4);
- }
-
- BKE_driver_target_matrix_to_rot_channels(
- mat, rot_order, dtar->rotation_mode, channel, false, quat);
-
- if (use_eulers && dtar->rotation_mode == DTAR_ROTMODE_AUTO) {
- compatible_eul(quat + 1, oldEul);
- }
-
- return quat[channel];
- }
- else {
- /* extract location and choose right axis */
- return mat[3][dtar->transChan];
- }
-}
-
-/* Convert a quaternion to pseudo-angles representing the weighted amount of rotation. */
-static void quaternion_to_angles(float quat[4], int channel)
-{
- if (channel < 0) {
- quat[0] = 2.0f * saacosf(quat[0]);
-
- for (int i = 1; i < 4; i++) {
- quat[i] = 2.0f * saasinf(quat[i]);
- }
- }
- else if (channel == 0) {
- quat[0] = 2.0f * saacosf(quat[0]);
- }
- else {
- quat[channel] = 2.0f * saasinf(quat[channel]);
- }
-}
-
-/* Compute channel values for a rotational Transform Channel driver variable. */
-void BKE_driver_target_matrix_to_rot_channels(
- float mat[4][4], int auto_order, int rotation_mode, int channel, bool angles, float r_buf[4])
-{
- float *const quat = r_buf;
- float *const eul = r_buf + 1;
-
- zero_v4(r_buf);
-
- if (rotation_mode == DTAR_ROTMODE_AUTO) {
- mat4_to_eulO(eul, auto_order, mat);
- }
- else if (rotation_mode >= DTAR_ROTMODE_EULER_MIN && rotation_mode <= DTAR_ROTMODE_EULER_MAX) {
- mat4_to_eulO(eul, rotation_mode, mat);
- }
- else if (rotation_mode == DTAR_ROTMODE_QUATERNION) {
- mat4_to_quat(quat, mat);
-
- /* For Transformation constraint convenience, convert to pseudo-angles. */
- if (angles) {
- quaternion_to_angles(quat, channel);
- }
- }
- else if (rotation_mode >= DTAR_ROTMODE_SWING_TWIST_X &&
- rotation_mode <= DTAR_ROTMODE_SWING_TWIST_Z) {
- int axis = rotation_mode - DTAR_ROTMODE_SWING_TWIST_X;
- float raw_quat[4], twist;
-
- mat4_to_quat(raw_quat, mat);
-
- if (channel == axis + 1) {
- /* If only the twist angle is needed, skip computing swing. */
- twist = quat_split_swing_and_twist(raw_quat, axis, NULL, NULL);
- }
- else {
- twist = quat_split_swing_and_twist(raw_quat, axis, quat, NULL);
-
- quaternion_to_angles(quat, channel);
- }
-
- quat[axis + 1] = twist;
- }
- else {
- BLI_assert(false);
- }
-}
-
-/* ......... */
-
-/* Table of Driver Variable Type Info Data */
-static DriverVarTypeInfo dvar_types[MAX_DVAR_TYPES] = {
- BEGIN_DVAR_TYPEDEF(DVAR_TYPE_SINGLE_PROP) dvar_eval_singleProp, /* eval callback */
- 1, /* number of targets used */
- {"Property"}, /* UI names for targets */
- {0} /* flags */
- END_DVAR_TYPEDEF,
-
- BEGIN_DVAR_TYPEDEF(DVAR_TYPE_ROT_DIFF) dvar_eval_rotDiff, /* eval callback */
- 2, /* number of targets used */
- {"Object/Bone 1", "Object/Bone 2"}, /* UI names for targets */
- {DTAR_FLAG_STRUCT_REF | DTAR_FLAG_ID_OB_ONLY,
- DTAR_FLAG_STRUCT_REF | DTAR_FLAG_ID_OB_ONLY} /* flags */
- END_DVAR_TYPEDEF,
-
- BEGIN_DVAR_TYPEDEF(DVAR_TYPE_LOC_DIFF) dvar_eval_locDiff, /* eval callback */
- 2, /* number of targets used */
- {"Object/Bone 1", "Object/Bone 2"}, /* UI names for targets */
- {DTAR_FLAG_STRUCT_REF | DTAR_FLAG_ID_OB_ONLY,
- DTAR_FLAG_STRUCT_REF | DTAR_FLAG_ID_OB_ONLY} /* flags */
- END_DVAR_TYPEDEF,
-
- BEGIN_DVAR_TYPEDEF(DVAR_TYPE_TRANSFORM_CHAN) dvar_eval_transChan, /* eval callback */
- 1, /* number of targets used */
- {"Object/Bone"}, /* UI names for targets */
- {DTAR_FLAG_STRUCT_REF | DTAR_FLAG_ID_OB_ONLY} /* flags */
- END_DVAR_TYPEDEF,
-};
-
-/* Get driver variable typeinfo */
-static const DriverVarTypeInfo *get_dvar_typeinfo(int type)
-{
- /* check if valid type */
- if ((type >= 0) && (type < MAX_DVAR_TYPES)) {
- return &dvar_types[type];
- }
- else {
- return NULL;
- }
-}
-
-/* Driver API --------------------------------- */
-
-/* Perform actual freeing driver variable and remove it from the given list */
-void driver_free_variable(ListBase *variables, DriverVar *dvar)
-{
- /* sanity checks */
- if (dvar == NULL) {
- return;
- }
-
- /* free target vars
- * - need to go over all of them, not just up to the ones that are used
- * currently, since there may be some lingering RNA paths from
- * previous users needing freeing
- */
- DRIVER_TARGETS_LOOPER_BEGIN (dvar) {
- /* free RNA path if applicable */
- if (dtar->rna_path) {
- MEM_freeN(dtar->rna_path);
- }
- }
- DRIVER_TARGETS_LOOPER_END;
-
- /* remove the variable from the driver */
- BLI_freelinkN(variables, dvar);
-}
-
-/* Free the driver variable and do extra updates */
-void driver_free_variable_ex(ChannelDriver *driver, DriverVar *dvar)
-{
- /* remove and free the driver variable */
- driver_free_variable(&driver->variables, dvar);
-
- /* since driver variables are cached, the expression needs re-compiling too */
- BKE_driver_invalidate_expression(driver, false, true);
-}
-
-/* Copy driver variables from src_vars list to dst_vars list */
-void driver_variables_copy(ListBase *dst_vars, const ListBase *src_vars)
-{
- BLI_assert(BLI_listbase_is_empty(dst_vars));
- BLI_duplicatelist(dst_vars, src_vars);
-
- for (DriverVar *dvar = dst_vars->first; dvar; dvar = dvar->next) {
- /* need to go over all targets so that we don't leave any dangling paths */
- DRIVER_TARGETS_LOOPER_BEGIN (dvar) {
- /* make a copy of target's rna path if available */
- if (dtar->rna_path) {
- dtar->rna_path = MEM_dupallocN(dtar->rna_path);
- }
- }
- DRIVER_TARGETS_LOOPER_END;
- }
-}
-
-/* Change the type of driver variable */
-void driver_change_variable_type(DriverVar *dvar, int type)
-{
- const DriverVarTypeInfo *dvti = get_dvar_typeinfo(type);
-
- /* sanity check */
- if (ELEM(NULL, dvar, dvti)) {
- return;
- }
-
- /* set the new settings */
- dvar->type = type;
- dvar->num_targets = dvti->num_targets;
-
- /* make changes to the targets based on the defines for these types
- * NOTE: only need to make sure the ones we're using here are valid...
- */
- DRIVER_TARGETS_USED_LOOPER_BEGIN (dvar) {
- short flags = dvti->target_flags[tarIndex];
-
- /* store the flags */
- dtar->flag = flags;
-
- /* object ID types only, or idtype not yet initialized */
- if ((flags & DTAR_FLAG_ID_OB_ONLY) || (dtar->idtype == 0)) {
- dtar->idtype = ID_OB;
- }
- }
- DRIVER_TARGETS_LOOPER_END;
-}
-
-/* Validate driver name (after being renamed) */
-void driver_variable_name_validate(DriverVar *dvar)
-{
- /* Special character blacklist */
- const char special_char_blacklist[] = {
- '~', '`', '!', '@', '#', '$', '%', '^', '&', '*', '+', '=', '-', '/', '\\',
- '?', ':', ';', '<', '>', '{', '}', '[', ']', '|', ' ', '.', '\t', '\n', '\r',
- };
-
- /* sanity checks */
- if (dvar == NULL) {
- return;
- }
-
- /* clear all invalid-name flags */
- dvar->flag &= ~DVAR_ALL_INVALID_FLAGS;
-
- /* 0) Zero-length identifiers are not allowed */
- if (dvar->name[0] == '\0') {
- dvar->flag |= DVAR_FLAG_INVALID_EMPTY;
- }
-
- /* 1) Must start with a letter */
- /* XXX: We assume that valid unicode letters in other languages are ok too,
- * hence the blacklisting. */
- if (IN_RANGE_INCL(dvar->name[0], '0', '9')) {
- dvar->flag |= DVAR_FLAG_INVALID_START_NUM;
- }
- else if (dvar->name[0] == '_') {
- /* NOTE: We don't allow names to start with underscores
- * (i.e. it helps when ruling out security risks) */
- dvar->flag |= DVAR_FLAG_INVALID_START_CHAR;
- }
-
- /* 2) Must not contain invalid stuff in the middle of the string */
- if (strchr(dvar->name, ' ')) {
- dvar->flag |= DVAR_FLAG_INVALID_HAS_SPACE;
- }
- if (strchr(dvar->name, '.')) {
- dvar->flag |= DVAR_FLAG_INVALID_HAS_DOT;
- }
-
- /* 3) Check for special characters - Either at start, or in the middle */
- for (int i = 0; i < sizeof(special_char_blacklist); i++) {
- char *match = strchr(dvar->name, special_char_blacklist[i]);
-
- if (match == dvar->name) {
- dvar->flag |= DVAR_FLAG_INVALID_START_CHAR;
- }
- else if (match != NULL) {
- dvar->flag |= DVAR_FLAG_INVALID_HAS_SPECIAL;
- }
- }
-
- /* 4) Check if the name is a reserved keyword
- * NOTE: These won't confuse Python, but it will be impossible to use the variable
- * in an expression without Python misinterpreting what these are for
- */
-#ifdef WITH_PYTHON
- if (BPY_string_is_keyword(dvar->name)) {
- dvar->flag |= DVAR_FLAG_INVALID_PY_KEYWORD;
- }
-#endif
-
- /* If any these conditions match, the name is invalid */
- if (dvar->flag & DVAR_ALL_INVALID_FLAGS) {
- dvar->flag |= DVAR_FLAG_INVALID_NAME;
- }
-}
-
-/* Add a new driver variable */
-DriverVar *driver_add_new_variable(ChannelDriver *driver)
-{
- DriverVar *dvar;
-
- /* sanity checks */
- if (driver == NULL) {
- return NULL;
- }
-
- /* make a new variable */
- dvar = MEM_callocN(sizeof(DriverVar), "DriverVar");
- BLI_addtail(&driver->variables, dvar);
-
- /* give the variable a 'unique' name */
- strcpy(dvar->name, CTX_DATA_(BLT_I18NCONTEXT_ID_ACTION, "var"));
- BLI_uniquename(&driver->variables,
- dvar,
- CTX_DATA_(BLT_I18NCONTEXT_ID_ACTION, "var"),
- '_',
- offsetof(DriverVar, name),
- sizeof(dvar->name));
-
- /* set the default type to 'single prop' */
- driver_change_variable_type(dvar, DVAR_TYPE_SINGLE_PROP);
-
- /* since driver variables are cached, the expression needs re-compiling too */
- BKE_driver_invalidate_expression(driver, false, true);
-
- /* return the target */
- return dvar;
-}
-
-/* This frees the driver itself */
-void fcurve_free_driver(FCurve *fcu)
-{
- ChannelDriver *driver;
- DriverVar *dvar, *dvarn;
-
- /* sanity checks */
- if (ELEM(NULL, fcu, fcu->driver)) {
- return;
- }
- driver = fcu->driver;
-
- /* free driver targets */
- for (dvar = driver->variables.first; dvar; dvar = dvarn) {
- dvarn = dvar->next;
- driver_free_variable_ex(driver, dvar);
- }
-
-#ifdef WITH_PYTHON
- /* free compiled driver expression */
- if (driver->expr_comp) {
- BPY_DECREF(driver->expr_comp);
- }
-#endif
-
- BLI_expr_pylike_free(driver->expr_simple);
-
- /* Free driver itself, then set F-Curve's point to this to NULL
- * (as the curve may still be used). */
- MEM_freeN(driver);
- fcu->driver = NULL;
-}
-
-/* This makes a copy of the given driver */
-ChannelDriver *fcurve_copy_driver(const ChannelDriver *driver)
-{
- ChannelDriver *ndriver;
-
- /* sanity checks */
- if (driver == NULL) {
- return NULL;
- }
-
- /* copy all data */
- ndriver = MEM_dupallocN(driver);
- ndriver->expr_comp = NULL;
- ndriver->expr_simple = NULL;
-
- /* copy variables */
-
- /* to get rid of refs to non-copied data (that's still used on original) */
- BLI_listbase_clear(&ndriver->variables);
- driver_variables_copy(&ndriver->variables, &driver->variables);
-
- /* return the new driver */
- return ndriver;
-}
-
-/* Driver Expression Evaluation --------------- */
-
-/* Index constants for the expression parameter array. */
-enum {
- /* Index of the 'frame' variable. */
- VAR_INDEX_FRAME = 0,
- /* Index of the first user-defined driver variable. */
- VAR_INDEX_CUSTOM
-};
-
-static ExprPyLike_Parsed *driver_compile_simple_expr_impl(ChannelDriver *driver)
-{
- /* Prepare parameter names. */
- int names_len = BLI_listbase_count(&driver->variables);
- const char **names = BLI_array_alloca(names, names_len + VAR_INDEX_CUSTOM);
- int i = VAR_INDEX_CUSTOM;
-
- names[VAR_INDEX_FRAME] = "frame";
-
- for (DriverVar *dvar = driver->variables.first; dvar; dvar = dvar->next) {
- names[i++] = dvar->name;
- }
-
- return BLI_expr_pylike_parse(driver->expression, names, names_len + VAR_INDEX_CUSTOM);
-}
-
-static bool driver_check_simple_expr_depends_on_time(ExprPyLike_Parsed *expr)
-{
- /* Check if the 'frame' parameter is actually used. */
- return BLI_expr_pylike_is_using_param(expr, VAR_INDEX_FRAME);
-}
-
-static bool driver_evaluate_simple_expr(ChannelDriver *driver,
- ExprPyLike_Parsed *expr,
- float *result,
- float time)
-{
- /* Prepare parameter values. */
- int vars_len = BLI_listbase_count(&driver->variables);
- double *vars = BLI_array_alloca(vars, vars_len + VAR_INDEX_CUSTOM);
- int i = VAR_INDEX_CUSTOM;
-
- vars[VAR_INDEX_FRAME] = time;
-
- for (DriverVar *dvar = driver->variables.first; dvar; dvar = dvar->next) {
- vars[i++] = driver_get_variable_value(driver, dvar);
- }
-
- /* Evaluate expression. */
- double result_val;
- eExprPyLike_EvalStatus status = BLI_expr_pylike_eval(
- expr, vars, vars_len + VAR_INDEX_CUSTOM, &result_val);
- const char *message;
-
- switch (status) {
- case EXPR_PYLIKE_SUCCESS:
- if (isfinite(result_val)) {
- *result = (float)result_val;
- }
- return true;
-
- case EXPR_PYLIKE_DIV_BY_ZERO:
- case EXPR_PYLIKE_MATH_ERROR:
- message = (status == EXPR_PYLIKE_DIV_BY_ZERO) ? "Division by Zero" : "Math Domain Error";
- CLOG_ERROR(&LOG, "%s in Driver: '%s'", message, driver->expression);
-
- driver->flag |= DRIVER_FLAG_INVALID;
- return true;
-
- default:
- /* arriving here means a bug, not user error */
- CLOG_ERROR(&LOG, "simple driver expression evaluation failed: '%s'", driver->expression);
- return false;
- }
-}
-
-/* Compile and cache the driver expression if necessary, with thread safety. */
-static bool driver_compile_simple_expr(ChannelDriver *driver)
-{
- if (driver->expr_simple != NULL) {
- return true;
- }
-
- if (driver->type != DRIVER_TYPE_PYTHON) {
- return false;
- }
-
- /* It's safe to parse in multiple threads; at worst it'll
- * waste some effort, but in return avoids mutex contention. */
- ExprPyLike_Parsed *expr = driver_compile_simple_expr_impl(driver);
-
- /* Store the result if the field is still NULL, or discard
- * it if another thread got here first. */
- if (atomic_cas_ptr((void **)&driver->expr_simple, NULL, expr) != NULL) {
- BLI_expr_pylike_free(expr);
- }
-
- return true;
-}
-
-/* Try using the simple expression evaluator to compute the result of the driver.
- * On success, stores the result and returns true; on failure result is set to 0. */
-static bool driver_try_evaluate_simple_expr(ChannelDriver *driver,
- ChannelDriver *driver_orig,
- float *result,
- float time)
-{
- *result = 0.0f;
-
- return driver_compile_simple_expr(driver_orig) &&
- BLI_expr_pylike_is_valid(driver_orig->expr_simple) &&
- driver_evaluate_simple_expr(driver, driver_orig->expr_simple, result, time);
-}
-
-/* Check if the expression in the driver conforms to the simple subset. */
-bool BKE_driver_has_simple_expression(ChannelDriver *driver)
-{
- return driver_compile_simple_expr(driver) && BLI_expr_pylike_is_valid(driver->expr_simple);
-}
-
-/* TODO(sergey): This is somewhat weak, but we don't want neither false-positive
- * time dependencies nor special exceptions in the depsgraph evaluation. */
-static bool python_driver_exression_depends_on_time(const char *expression)
-{
- if (expression[0] == '\0') {
- /* Empty expression depends on nothing. */
- return false;
- }
- if (strchr(expression, '(') != NULL) {
- /* Function calls are considered dependent on a time. */
- return true;
- }
- if (strstr(expression, "frame") != NULL) {
- /* Variable `frame` depends on time. */
- /* TODO(sergey): This is a bit weak, but not sure about better way of handling this. */
- return true;
- }
- /* Possible indirect time relation s should be handled via variable targets. */
- return false;
-}
-
-/* Check if the expression in the driver may depend on the current frame. */
-bool BKE_driver_expression_depends_on_time(ChannelDriver *driver)
-{
- if (driver->type != DRIVER_TYPE_PYTHON) {
- return false;
- }
-
- if (BKE_driver_has_simple_expression(driver)) {
- /* Simple expressions can be checked exactly. */
- return driver_check_simple_expr_depends_on_time(driver->expr_simple);
- }
- else {
- /* Otherwise, heuristically scan the expression string for certain patterns. */
- return python_driver_exression_depends_on_time(driver->expression);
- }
-}
-
-/* Reset cached compiled expression data */
-void BKE_driver_invalidate_expression(ChannelDriver *driver,
- bool expr_changed,
- bool varname_changed)
-{
- if (expr_changed || varname_changed) {
- BLI_expr_pylike_free(driver->expr_simple);
- driver->expr_simple = NULL;
- }
-
-#ifdef WITH_PYTHON
- if (expr_changed) {
- driver->flag |= DRIVER_FLAG_RECOMPILE;
- }
-
- if (varname_changed) {
- driver->flag |= DRIVER_FLAG_RENAMEVAR;
- }
-#endif
-}
-
-/* Driver Evaluation -------------------------- */
-
-/* Evaluate a Driver Variable to get a value that contributes to the final */
-float driver_get_variable_value(ChannelDriver *driver, DriverVar *dvar)
-{
- const DriverVarTypeInfo *dvti;
-
- /* sanity check */
- if (ELEM(NULL, driver, dvar)) {
- return 0.0f;
- }
-
- /* call the relevant callbacks to get the variable value
- * using the variable type info, storing the obtained value
- * in dvar->curval so that drivers can be debugged
- */
- dvti = get_dvar_typeinfo(dvar->type);
-
- if (dvti && dvti->get_value) {
- dvar->curval = dvti->get_value(driver, dvar);
- }
- else {
- dvar->curval = 0.0f;
- }
-
- return dvar->curval;
-}
-
-static void evaluate_driver_sum(ChannelDriver *driver)
-{
- DriverVar *dvar;
-
- /* check how many variables there are first (i.e. just one?) */
- if (BLI_listbase_is_single(&driver->variables)) {
- /* just one target, so just use that */
- dvar = driver->variables.first;
- driver->curval = driver_get_variable_value(driver, dvar);
- return;
- }
-
- /* more than one target, so average the values of the targets */
- float value = 0.0f;
- int tot = 0;
-
- /* loop through targets, adding (hopefully we don't get any overflow!) */
- for (dvar = driver->variables.first; dvar; dvar = dvar->next) {
- value += driver_get_variable_value(driver, dvar);
- tot++;
- }
-
- /* perform operations on the total if appropriate */
- if (driver->type == DRIVER_TYPE_AVERAGE) {
- driver->curval = tot ? (value / (float)tot) : 0.0f;
- }
- else {
- driver->curval = value;
- }
-}
-
-static void evaluate_driver_min_max(ChannelDriver *driver)
-{
- DriverVar *dvar;
- float value = 0.0f;
-
- /* loop through the variables, getting the values and comparing them to existing ones */
- for (dvar = driver->variables.first; dvar; dvar = dvar->next) {
- /* get value */
- float tmp_val = driver_get_variable_value(driver, dvar);
-
- /* store this value if appropriate */
- if (dvar->prev) {
- /* check if greater/smaller than the baseline */
- if (driver->type == DRIVER_TYPE_MAX) {
- /* max? */
- if (tmp_val > value) {
- value = tmp_val;
- }
- }
- else {
- /* min? */
- if (tmp_val < value) {
- value = tmp_val;
- }
- }
- }
- else {
- /* first item - make this the baseline for comparisons */
- value = tmp_val;
- }
- }
-
- /* store value in driver */
- driver->curval = value;
-}
-
-static void evaluate_driver_python(PathResolvedRNA *anim_rna,
- ChannelDriver *driver,
- ChannelDriver *driver_orig,
- const float evaltime)
-{
- /* check for empty or invalid expression */
- if ((driver_orig->expression[0] == '\0') || (driver_orig->flag & DRIVER_FLAG_INVALID)) {
- driver->curval = 0.0f;
- }
- else if (!driver_try_evaluate_simple_expr(driver, driver_orig, &driver->curval, evaltime)) {
-#ifdef WITH_PYTHON
- /* this evaluates the expression using Python, and returns its result:
- * - on errors it reports, then returns 0.0f
- */
- BLI_mutex_lock(&python_driver_lock);
-
- driver->curval = BPY_driver_exec(anim_rna, driver, driver_orig, evaltime);
-
- BLI_mutex_unlock(&python_driver_lock);
-#else /* WITH_PYTHON*/
- UNUSED_VARS(anim_rna, evaltime);
-#endif /* WITH_PYTHON*/
- }
-}
-
-/* Evaluate an Channel-Driver to get a 'time' value to use instead of "evaltime"
- * - "evaltime" is the frame at which F-Curve is being evaluated
- * - has to return a float value
- * - driver_orig is where we cache Python expressions, in case of COW
- */
-float evaluate_driver(PathResolvedRNA *anim_rna,
- ChannelDriver *driver,
- ChannelDriver *driver_orig,
- const float evaltime)
-{
- /* check if driver can be evaluated */
- if (driver_orig->flag & DRIVER_FLAG_INVALID) {
- return 0.0f;
- }
-
- switch (driver->type) {
- case DRIVER_TYPE_AVERAGE: /* average values of driver targets */
- case DRIVER_TYPE_SUM: /* sum values of driver targets */
- evaluate_driver_sum(driver);
- break;
- case DRIVER_TYPE_MIN: /* smallest value */
- case DRIVER_TYPE_MAX: /* largest value */
- evaluate_driver_min_max(driver);
- break;
- case DRIVER_TYPE_PYTHON: /* expression */
- evaluate_driver_python(anim_rna, driver, driver_orig, evaltime);
- break;
- default:
- /* special 'hack' - just use stored value
- * This is currently used as the mechanism which allows animated settings to be able
- * to be changed via the UI.
- */
- break;
- }
-
- /* return value for driver */
- return driver->curval;
-}
-
/* ***************************** Curve Calculations ********************************* */
/* The total length of the handles is not allowed to be more
@@ -2665,437 +1451,327 @@ static void berekeny(float f1, float f2, float f3, float f4, float *o, int b)
/* -------------------------- */
-/* Calculate F-Curve value for 'evaltime' using BezTriple keyframes */
-static float fcurve_eval_keyframes(FCurve *fcu, BezTriple *bezts, float evaltime)
+static float fcurve_eval_keyframes_extrapolate(
+ FCurve *fcu, BezTriple *bezts, float evaltime, int endpoint_offset, int direction_to_neighbor)
+{
+ BezTriple *endpoint_bezt = bezts + endpoint_offset; /* The first/last keyframe. */
+ BezTriple *neighbor_bezt = endpoint_bezt +
+ direction_to_neighbor; /* The second (to last) keyframe. */
+
+ if (endpoint_bezt->ipo == BEZT_IPO_CONST || fcu->extend == FCURVE_EXTRAPOLATE_CONSTANT ||
+ (fcu->flag & FCURVE_DISCRETE_VALUES) != 0) {
+ /* Constant (BEZT_IPO_HORIZ) extrapolation or constant interpolation, so just extend the
+ * endpoint's value. */
+ return endpoint_bezt->vec[1][1];
+ }
+
+ if (endpoint_bezt->ipo == BEZT_IPO_LIN) {
+ /* Use the next center point instead of our own handle for linear interpolated extrapolate. */
+ if (fcu->totvert == 1) {
+ return endpoint_bezt->vec[1][1];
+ }
+
+ float dx = endpoint_bezt->vec[1][0] - evaltime;
+ float fac = neighbor_bezt->vec[1][0] - endpoint_bezt->vec[1][0];
+
+ /* Prevent division by zero. */
+ if (fac == 0.0f) {
+ return endpoint_bezt->vec[1][1];
+ }
+
+ fac = (neighbor_bezt->vec[1][1] - endpoint_bezt->vec[1][1]) / fac;
+ return endpoint_bezt->vec[1][1] - (fac * dx);
+ }
+
+ /* Use the gradient of the second handle (later) of neighbor to calculate the gradient and thus
+ * the value of the curve at evaluation time. */
+ int handle = direction_to_neighbor > 0 ? 0 : 2;
+ float dx = endpoint_bezt->vec[1][0] - evaltime;
+ float fac = endpoint_bezt->vec[1][0] - endpoint_bezt->vec[handle][0];
+
+ /* Prevent division by zero. */
+ if (fac == 0.0f) {
+ return endpoint_bezt->vec[1][1];
+ }
+
+ fac = (endpoint_bezt->vec[1][1] - endpoint_bezt->vec[handle][1]) / fac;
+ return endpoint_bezt->vec[1][1] - (fac * dx);
+}
+
+static float fcurve_eval_keyframes_interpolate(FCurve *fcu, BezTriple *bezts, float evaltime)
{
const float eps = 1.e-8f;
- BezTriple *bezt, *prevbezt, *lastbezt;
- float v1[2], v2[2], v3[2], v4[2], opl[32], dx, fac;
+ BezTriple *bezt, *prevbezt;
unsigned int a;
- int b;
- float cvalue = 0.0f;
- /* get pointers */
- a = fcu->totvert - 1;
- prevbezt = bezts;
- bezt = prevbezt + 1;
- lastbezt = prevbezt + a;
+ /* evaltime occurs somewhere in the middle of the curve */
+ bool exact = false;
+
+ /* Use binary search to find appropriate keyframes...
+ *
+ * The threshold here has the following constraints:
+ * - 0.001 is too coarse:
+ * We get artifacts with 2cm driver movements at 1BU = 1m (see T40332)
+ *
+ * - 0.00001 is too fine:
+ * Weird errors, like selecting the wrong keyframe range (see T39207), occur.
+ * This lower bound was established in b888a32eee8147b028464336ad2404d8155c64dd.
+ */
+ a = binarysearch_bezt_index_ex(bezts, evaltime, fcu->totvert, 0.0001, &exact);
+ bezt = bezts + a;
- /* evaluation time at or past endpoints? */
- if (prevbezt->vec[1][0] >= evaltime) {
- /* before or on first keyframe */
- if ((fcu->extend == FCURVE_EXTRAPOLATE_LINEAR) && (prevbezt->ipo != BEZT_IPO_CONST) &&
- !(fcu->flag & FCURVE_DISCRETE_VALUES)) {
- /* linear or bezier interpolation */
- if (prevbezt->ipo == BEZT_IPO_LIN) {
- /* Use the next center point instead of our own handle for
- * linear interpolated extrapolate
- */
- if (fcu->totvert == 1) {
- cvalue = prevbezt->vec[1][1];
- }
- else {
- bezt = prevbezt + 1;
- dx = prevbezt->vec[1][0] - evaltime;
- fac = bezt->vec[1][0] - prevbezt->vec[1][0];
-
- /* prevent division by zero */
- if (fac) {
- fac = (bezt->vec[1][1] - prevbezt->vec[1][1]) / fac;
- cvalue = prevbezt->vec[1][1] - (fac * dx);
- }
- else {
- cvalue = prevbezt->vec[1][1];
- }
- }
- }
- else {
- /* Use the first handle (earlier) of first BezTriple to calculate the
- * gradient and thus the value of the curve at evaltime
- */
- dx = prevbezt->vec[1][0] - evaltime;
- fac = prevbezt->vec[1][0] - prevbezt->vec[0][0];
+ if (exact) {
+ /* index returned must be interpreted differently when it sits on top of an existing keyframe
+ * - that keyframe is the start of the segment we need (see action_bug_2.blend in T39207)
+ */
+ return bezt->vec[1][1];
+ }
- /* prevent division by zero */
- if (fac) {
- fac = (prevbezt->vec[1][1] - prevbezt->vec[0][1]) / fac;
- cvalue = prevbezt->vec[1][1] - (fac * dx);
- }
- else {
- cvalue = prevbezt->vec[1][1];
- }
- }
- }
- else {
- /* constant (BEZT_IPO_HORIZ) extrapolation or constant interpolation,
- * so just extend first keyframe's value
- */
- cvalue = prevbezt->vec[1][1];
+ /* index returned refers to the keyframe that the eval-time occurs *before*
+ * - hence, that keyframe marks the start of the segment we're dealing with
+ */
+ prevbezt = (a > 0) ? (bezt - 1) : bezt;
+
+ /* Use if the key is directly on the frame, in rare cases this is needed else we get 0.0 instead.
+ * XXX: consult T39207 for examples of files where failure of these checks can cause issues */
+ if (fabsf(bezt->vec[1][0] - evaltime) < eps) {
+ return bezt->vec[1][1];
+ }
+
+ if (evaltime < prevbezt->vec[1][0] || bezt->vec[1][0] < evaltime) {
+ if (G.debug & G_DEBUG) {
+ printf(" ERROR: failed eval - p=%f b=%f, t=%f (%f)\n",
+ prevbezt->vec[1][0],
+ bezt->vec[1][0],
+ evaltime,
+ fabsf(bezt->vec[1][0] - evaltime));
}
+ return 0.0f;
}
- else if (lastbezt->vec[1][0] <= evaltime) {
- /* after or on last keyframe */
- if ((fcu->extend == FCURVE_EXTRAPOLATE_LINEAR) && (lastbezt->ipo != BEZT_IPO_CONST) &&
- !(fcu->flag & FCURVE_DISCRETE_VALUES)) {
- /* linear or bezier interpolation */
- if (lastbezt->ipo == BEZT_IPO_LIN) {
- /* Use the next center point instead of our own handle for
- * linear interpolated extrapolate
+
+ /* Evaltime occurs within the interval defined by these two keyframes. */
+ const float begin = prevbezt->vec[1][1];
+ const float change = bezt->vec[1][1] - prevbezt->vec[1][1];
+ const float duration = bezt->vec[1][0] - prevbezt->vec[1][0];
+ const float time = evaltime - prevbezt->vec[1][0];
+ const float amplitude = prevbezt->amplitude;
+ const float period = prevbezt->period;
+
+ /* value depends on interpolation mode */
+ if ((prevbezt->ipo == BEZT_IPO_CONST) || (fcu->flag & FCURVE_DISCRETE_VALUES) ||
+ (duration == 0)) {
+ /* constant (evaltime not relevant, so no interpolation needed) */
+ return prevbezt->vec[1][1];
+ }
+
+ switch (prevbezt->ipo) {
+ /* interpolation ...................................... */
+ case BEZT_IPO_BEZ: {
+ float v1[2], v2[2], v3[2], v4[2], opl[32];
+
+ /* bezier interpolation */
+ /* (v1, v2) are the first keyframe and its 2nd handle */
+ v1[0] = prevbezt->vec[1][0];
+ v1[1] = prevbezt->vec[1][1];
+ v2[0] = prevbezt->vec[2][0];
+ v2[1] = prevbezt->vec[2][1];
+ /* (v3, v4) are the last keyframe's 1st handle + the last keyframe */
+ v3[0] = bezt->vec[0][0];
+ v3[1] = bezt->vec[0][1];
+ v4[0] = bezt->vec[1][0];
+ v4[1] = bezt->vec[1][1];
+
+ if (fabsf(v1[1] - v4[1]) < FLT_EPSILON && fabsf(v2[1] - v3[1]) < FLT_EPSILON &&
+ fabsf(v3[1] - v4[1]) < FLT_EPSILON) {
+ /* Optimization: If all the handles are flat/at the same values,
+ * the value is simply the shared value (see T40372 -> F91346)
*/
- if (fcu->totvert == 1) {
- cvalue = lastbezt->vec[1][1];
- }
- else {
- prevbezt = lastbezt - 1;
- dx = evaltime - lastbezt->vec[1][0];
- fac = lastbezt->vec[1][0] - prevbezt->vec[1][0];
-
- /* prevent division by zero */
- if (fac) {
- fac = (lastbezt->vec[1][1] - prevbezt->vec[1][1]) / fac;
- cvalue = lastbezt->vec[1][1] + (fac * dx);
- }
- else {
- cvalue = lastbezt->vec[1][1];
- }
+ return v1[1];
+ }
+ /* adjust handles so that they don't overlap (forming a loop) */
+ correct_bezpart(v1, v2, v3, v4);
+
+ /* try to get a value for this position - if failure, try another set of points */
+ if (!findzero(evaltime, v1[0], v2[0], v3[0], v4[0], opl)) {
+ if (G.debug & G_DEBUG) {
+ printf(" ERROR: findzero() failed at %f with %f %f %f %f\n",
+ evaltime,
+ v1[0],
+ v2[0],
+ v3[0],
+ v4[0]);
}
+ return 0.0;
}
- else {
- /* Use the gradient of the second handle (later) of last BezTriple to calculate the
- * gradient and thus the value of the curve at evaltime
- */
- dx = evaltime - lastbezt->vec[1][0];
- fac = lastbezt->vec[2][0] - lastbezt->vec[1][0];
- /* prevent division by zero */
- if (fac) {
- fac = (lastbezt->vec[2][1] - lastbezt->vec[1][1]) / fac;
- cvalue = lastbezt->vec[1][1] + (fac * dx);
- }
- else {
- cvalue = lastbezt->vec[1][1];
- }
+ berekeny(v1[1], v2[1], v3[1], v4[1], opl, 1);
+ return opl[0];
+ }
+ case BEZT_IPO_LIN:
+ /* linear - simply linearly interpolate between values of the two keyframes */
+ return BLI_easing_linear_ease(time, begin, change, duration);
+
+ /* easing ............................................ */
+ case BEZT_IPO_BACK:
+ switch (prevbezt->easing) {
+ case BEZT_IPO_EASE_IN:
+ return BLI_easing_back_ease_in(time, begin, change, duration, prevbezt->back);
+ case BEZT_IPO_EASE_OUT:
+ return BLI_easing_back_ease_out(time, begin, change, duration, prevbezt->back);
+ case BEZT_IPO_EASE_IN_OUT:
+ return BLI_easing_back_ease_in_out(time, begin, change, duration, prevbezt->back);
+
+ default: /* default/auto: same as ease out */
+ return BLI_easing_back_ease_out(time, begin, change, duration, prevbezt->back);
}
- }
- else {
- /* constant (BEZT_IPO_HORIZ) extrapolation or constant interpolation,
- * so just extend last keyframe's value
- */
- cvalue = lastbezt->vec[1][1];
- }
- }
- else {
- /* evaltime occurs somewhere in the middle of the curve */
- bool exact = false;
-
- /* Use binary search to find appropriate keyframes...
- *
- * The threshold here has the following constraints:
- * - 0.001 is too coarse:
- * We get artifacts with 2cm driver movements at 1BU = 1m (see T40332)
- *
- * - 0.00001 is too fine:
- * Weird errors, like selecting the wrong keyframe range (see T39207), occur.
- * This lower bound was established in b888a32eee8147b028464336ad2404d8155c64dd.
- */
- a = binarysearch_bezt_index_ex(bezts, evaltime, fcu->totvert, 0.0001, &exact);
+ break;
- if (exact) {
- /* index returned must be interpreted differently when it sits on top of an existing keyframe
- * - that keyframe is the start of the segment we need (see action_bug_2.blend in T39207)
- */
- prevbezt = bezts + a;
- bezt = (a < fcu->totvert - 1) ? (prevbezt + 1) : prevbezt;
- }
- else {
- /* index returned refers to the keyframe that the eval-time occurs *before*
- * - hence, that keyframe marks the start of the segment we're dealing with
- */
- bezt = bezts + a;
- prevbezt = (a > 0) ? (bezt - 1) : bezt;
- }
+ case BEZT_IPO_BOUNCE:
+ switch (prevbezt->easing) {
+ case BEZT_IPO_EASE_IN:
+ return BLI_easing_bounce_ease_in(time, begin, change, duration);
+ case BEZT_IPO_EASE_OUT:
+ return BLI_easing_bounce_ease_out(time, begin, change, duration);
+ case BEZT_IPO_EASE_IN_OUT:
+ return BLI_easing_bounce_ease_in_out(time, begin, change, duration);
+
+ default: /* default/auto: same as ease out */
+ return BLI_easing_bounce_ease_out(time, begin, change, duration);
+ }
+ break;
- /* use if the key is directly on the frame,
- * rare cases this is needed else we get 0.0 instead. */
- /* XXX: consult T39207 for examples of files where failure of these checks can cause issues */
- if (exact) {
- cvalue = prevbezt->vec[1][1];
- }
- else if (fabsf(bezt->vec[1][0] - evaltime) < eps) {
- cvalue = bezt->vec[1][1];
- }
- /* evaltime occurs within the interval defined by these two keyframes */
- else if ((prevbezt->vec[1][0] <= evaltime) && (bezt->vec[1][0] >= evaltime)) {
- const float begin = prevbezt->vec[1][1];
- const float change = bezt->vec[1][1] - prevbezt->vec[1][1];
- const float duration = bezt->vec[1][0] - prevbezt->vec[1][0];
- const float time = evaltime - prevbezt->vec[1][0];
- const float amplitude = prevbezt->amplitude;
- const float period = prevbezt->period;
-
- /* value depends on interpolation mode */
- if ((prevbezt->ipo == BEZT_IPO_CONST) || (fcu->flag & FCURVE_DISCRETE_VALUES) ||
- (duration == 0)) {
- /* constant (evaltime not relevant, so no interpolation needed) */
- cvalue = prevbezt->vec[1][1];
+ case BEZT_IPO_CIRC:
+ switch (prevbezt->easing) {
+ case BEZT_IPO_EASE_IN:
+ return BLI_easing_circ_ease_in(time, begin, change, duration);
+ case BEZT_IPO_EASE_OUT:
+ return BLI_easing_circ_ease_out(time, begin, change, duration);
+ case BEZT_IPO_EASE_IN_OUT:
+ return BLI_easing_circ_ease_in_out(time, begin, change, duration);
+
+ default: /* default/auto: same as ease in */
+ return BLI_easing_circ_ease_in(time, begin, change, duration);
}
- else {
- switch (prevbezt->ipo) {
- /* interpolation ...................................... */
- case BEZT_IPO_BEZ:
- /* bezier interpolation */
- /* (v1, v2) are the first keyframe and its 2nd handle */
- v1[0] = prevbezt->vec[1][0];
- v1[1] = prevbezt->vec[1][1];
- v2[0] = prevbezt->vec[2][0];
- v2[1] = prevbezt->vec[2][1];
- /* (v3, v4) are the last keyframe's 1st handle + the last keyframe */
- v3[0] = bezt->vec[0][0];
- v3[1] = bezt->vec[0][1];
- v4[0] = bezt->vec[1][0];
- v4[1] = bezt->vec[1][1];
-
- if (fabsf(v1[1] - v4[1]) < FLT_EPSILON && fabsf(v2[1] - v3[1]) < FLT_EPSILON &&
- fabsf(v3[1] - v4[1]) < FLT_EPSILON) {
- /* Optimization: If all the handles are flat/at the same values,
- * the value is simply the shared value (see T40372 -> F91346)
- */
- cvalue = v1[1];
- }
- else {
- /* adjust handles so that they don't overlap (forming a loop) */
- correct_bezpart(v1, v2, v3, v4);
-
- /* try to get a value for this position - if failure, try another set of points */
- b = findzero(evaltime, v1[0], v2[0], v3[0], v4[0], opl);
- if (b) {
- berekeny(v1[1], v2[1], v3[1], v4[1], opl, 1);
- cvalue = opl[0];
- /* break; */
- }
- else {
- if (G.debug & G_DEBUG) {
- printf(" ERROR: findzero() failed at %f with %f %f %f %f\n",
- evaltime,
- v1[0],
- v2[0],
- v3[0],
- v4[0]);
- }
- }
- }
- break;
-
- case BEZT_IPO_LIN:
- /* linear - simply linearly interpolate between values of the two keyframes */
- cvalue = BLI_easing_linear_ease(time, begin, change, duration);
- break;
-
- /* easing ............................................ */
- case BEZT_IPO_BACK:
- switch (prevbezt->easing) {
- case BEZT_IPO_EASE_IN:
- cvalue = BLI_easing_back_ease_in(time, begin, change, duration, prevbezt->back);
- break;
- case BEZT_IPO_EASE_OUT:
- cvalue = BLI_easing_back_ease_out(time, begin, change, duration, prevbezt->back);
- break;
- case BEZT_IPO_EASE_IN_OUT:
- cvalue = BLI_easing_back_ease_in_out(
- time, begin, change, duration, prevbezt->back);
- break;
-
- default: /* default/auto: same as ease out */
- cvalue = BLI_easing_back_ease_out(time, begin, change, duration, prevbezt->back);
- break;
- }
- break;
-
- case BEZT_IPO_BOUNCE:
- switch (prevbezt->easing) {
- case BEZT_IPO_EASE_IN:
- cvalue = BLI_easing_bounce_ease_in(time, begin, change, duration);
- break;
- case BEZT_IPO_EASE_OUT:
- cvalue = BLI_easing_bounce_ease_out(time, begin, change, duration);
- break;
- case BEZT_IPO_EASE_IN_OUT:
- cvalue = BLI_easing_bounce_ease_in_out(time, begin, change, duration);
- break;
-
- default: /* default/auto: same as ease out */
- cvalue = BLI_easing_bounce_ease_out(time, begin, change, duration);
- break;
- }
- break;
-
- case BEZT_IPO_CIRC:
- switch (prevbezt->easing) {
- case BEZT_IPO_EASE_IN:
- cvalue = BLI_easing_circ_ease_in(time, begin, change, duration);
- break;
- case BEZT_IPO_EASE_OUT:
- cvalue = BLI_easing_circ_ease_out(time, begin, change, duration);
- break;
- case BEZT_IPO_EASE_IN_OUT:
- cvalue = BLI_easing_circ_ease_in_out(time, begin, change, duration);
- break;
-
- default: /* default/auto: same as ease in */
- cvalue = BLI_easing_circ_ease_in(time, begin, change, duration);
- break;
- }
- break;
-
- case BEZT_IPO_CUBIC:
- switch (prevbezt->easing) {
- case BEZT_IPO_EASE_IN:
- cvalue = BLI_easing_cubic_ease_in(time, begin, change, duration);
- break;
- case BEZT_IPO_EASE_OUT:
- cvalue = BLI_easing_cubic_ease_out(time, begin, change, duration);
- break;
- case BEZT_IPO_EASE_IN_OUT:
- cvalue = BLI_easing_cubic_ease_in_out(time, begin, change, duration);
- break;
-
- default: /* default/auto: same as ease in */
- cvalue = BLI_easing_cubic_ease_in(time, begin, change, duration);
- break;
- }
- break;
-
- case BEZT_IPO_ELASTIC:
- switch (prevbezt->easing) {
- case BEZT_IPO_EASE_IN:
- cvalue = BLI_easing_elastic_ease_in(
- time, begin, change, duration, amplitude, period);
- break;
- case BEZT_IPO_EASE_OUT:
- cvalue = BLI_easing_elastic_ease_out(
- time, begin, change, duration, amplitude, period);
- break;
- case BEZT_IPO_EASE_IN_OUT:
- cvalue = BLI_easing_elastic_ease_in_out(
- time, begin, change, duration, amplitude, period);
- break;
-
- default: /* default/auto: same as ease out */
- cvalue = BLI_easing_elastic_ease_out(
- time, begin, change, duration, amplitude, period);
- break;
- }
- break;
-
- case BEZT_IPO_EXPO:
- switch (prevbezt->easing) {
- case BEZT_IPO_EASE_IN:
- cvalue = BLI_easing_expo_ease_in(time, begin, change, duration);
- break;
- case BEZT_IPO_EASE_OUT:
- cvalue = BLI_easing_expo_ease_out(time, begin, change, duration);
- break;
- case BEZT_IPO_EASE_IN_OUT:
- cvalue = BLI_easing_expo_ease_in_out(time, begin, change, duration);
- break;
-
- default: /* default/auto: same as ease in */
- cvalue = BLI_easing_expo_ease_in(time, begin, change, duration);
- break;
- }
- break;
-
- case BEZT_IPO_QUAD:
- switch (prevbezt->easing) {
- case BEZT_IPO_EASE_IN:
- cvalue = BLI_easing_quad_ease_in(time, begin, change, duration);
- break;
- case BEZT_IPO_EASE_OUT:
- cvalue = BLI_easing_quad_ease_out(time, begin, change, duration);
- break;
- case BEZT_IPO_EASE_IN_OUT:
- cvalue = BLI_easing_quad_ease_in_out(time, begin, change, duration);
- break;
-
- default: /* default/auto: same as ease in */
- cvalue = BLI_easing_quad_ease_in(time, begin, change, duration);
- break;
- }
- break;
-
- case BEZT_IPO_QUART:
- switch (prevbezt->easing) {
- case BEZT_IPO_EASE_IN:
- cvalue = BLI_easing_quart_ease_in(time, begin, change, duration);
- break;
- case BEZT_IPO_EASE_OUT:
- cvalue = BLI_easing_quart_ease_out(time, begin, change, duration);
- break;
- case BEZT_IPO_EASE_IN_OUT:
- cvalue = BLI_easing_quart_ease_in_out(time, begin, change, duration);
- break;
-
- default: /* default/auto: same as ease in */
- cvalue = BLI_easing_quart_ease_in(time, begin, change, duration);
- break;
- }
- break;
-
- case BEZT_IPO_QUINT:
- switch (prevbezt->easing) {
- case BEZT_IPO_EASE_IN:
- cvalue = BLI_easing_quint_ease_in(time, begin, change, duration);
- break;
- case BEZT_IPO_EASE_OUT:
- cvalue = BLI_easing_quint_ease_out(time, begin, change, duration);
- break;
- case BEZT_IPO_EASE_IN_OUT:
- cvalue = BLI_easing_quint_ease_in_out(time, begin, change, duration);
- break;
-
- default: /* default/auto: same as ease in */
- cvalue = BLI_easing_quint_ease_in(time, begin, change, duration);
- break;
- }
- break;
-
- case BEZT_IPO_SINE:
- switch (prevbezt->easing) {
- case BEZT_IPO_EASE_IN:
- cvalue = BLI_easing_sine_ease_in(time, begin, change, duration);
- break;
- case BEZT_IPO_EASE_OUT:
- cvalue = BLI_easing_sine_ease_out(time, begin, change, duration);
- break;
- case BEZT_IPO_EASE_IN_OUT:
- cvalue = BLI_easing_sine_ease_in_out(time, begin, change, duration);
- break;
-
- default: /* default/auto: same as ease in */
- cvalue = BLI_easing_sine_ease_in(time, begin, change, duration);
- break;
- }
- break;
+ break;
- default:
- cvalue = prevbezt->vec[1][1];
- break;
- }
+ case BEZT_IPO_CUBIC:
+ switch (prevbezt->easing) {
+ case BEZT_IPO_EASE_IN:
+ return BLI_easing_cubic_ease_in(time, begin, change, duration);
+ case BEZT_IPO_EASE_OUT:
+ return BLI_easing_cubic_ease_out(time, begin, change, duration);
+ case BEZT_IPO_EASE_IN_OUT:
+ return BLI_easing_cubic_ease_in_out(time, begin, change, duration);
+
+ default: /* default/auto: same as ease in */
+ return BLI_easing_cubic_ease_in(time, begin, change, duration);
}
- }
- else {
- if (G.debug & G_DEBUG) {
- printf(" ERROR: failed eval - p=%f b=%f, t=%f (%f)\n",
- prevbezt->vec[1][0],
- bezt->vec[1][0],
- evaltime,
- fabsf(bezt->vec[1][0] - evaltime));
+ break;
+
+ case BEZT_IPO_ELASTIC:
+ switch (prevbezt->easing) {
+ case BEZT_IPO_EASE_IN:
+ return BLI_easing_elastic_ease_in(time, begin, change, duration, amplitude, period);
+ case BEZT_IPO_EASE_OUT:
+ return BLI_easing_elastic_ease_out(time, begin, change, duration, amplitude, period);
+ case BEZT_IPO_EASE_IN_OUT:
+ return BLI_easing_elastic_ease_in_out(time, begin, change, duration, amplitude, period);
+
+ default: /* default/auto: same as ease out */
+ return BLI_easing_elastic_ease_out(time, begin, change, duration, amplitude, period);
}
- }
+ break;
+
+ case BEZT_IPO_EXPO:
+ switch (prevbezt->easing) {
+ case BEZT_IPO_EASE_IN:
+ return BLI_easing_expo_ease_in(time, begin, change, duration);
+ case BEZT_IPO_EASE_OUT:
+ return BLI_easing_expo_ease_out(time, begin, change, duration);
+ case BEZT_IPO_EASE_IN_OUT:
+ return BLI_easing_expo_ease_in_out(time, begin, change, duration);
+
+ default: /* default/auto: same as ease in */
+ return BLI_easing_expo_ease_in(time, begin, change, duration);
+ }
+ break;
+
+ case BEZT_IPO_QUAD:
+ switch (prevbezt->easing) {
+ case BEZT_IPO_EASE_IN:
+ return BLI_easing_quad_ease_in(time, begin, change, duration);
+ case BEZT_IPO_EASE_OUT:
+ return BLI_easing_quad_ease_out(time, begin, change, duration);
+ case BEZT_IPO_EASE_IN_OUT:
+ return BLI_easing_quad_ease_in_out(time, begin, change, duration);
+
+ default: /* default/auto: same as ease in */
+ return BLI_easing_quad_ease_in(time, begin, change, duration);
+ }
+ break;
+
+ case BEZT_IPO_QUART:
+ switch (prevbezt->easing) {
+ case BEZT_IPO_EASE_IN:
+ return BLI_easing_quart_ease_in(time, begin, change, duration);
+ case BEZT_IPO_EASE_OUT:
+ return BLI_easing_quart_ease_out(time, begin, change, duration);
+ case BEZT_IPO_EASE_IN_OUT:
+ return BLI_easing_quart_ease_in_out(time, begin, change, duration);
+
+ default: /* default/auto: same as ease in */
+ return BLI_easing_quart_ease_in(time, begin, change, duration);
+ }
+ break;
+
+ case BEZT_IPO_QUINT:
+ switch (prevbezt->easing) {
+ case BEZT_IPO_EASE_IN:
+ return BLI_easing_quint_ease_in(time, begin, change, duration);
+ case BEZT_IPO_EASE_OUT:
+ return BLI_easing_quint_ease_out(time, begin, change, duration);
+ case BEZT_IPO_EASE_IN_OUT:
+ return BLI_easing_quint_ease_in_out(time, begin, change, duration);
+
+ default: /* default/auto: same as ease in */
+ return BLI_easing_quint_ease_in(time, begin, change, duration);
+ }
+ break;
+
+ case BEZT_IPO_SINE:
+ switch (prevbezt->easing) {
+ case BEZT_IPO_EASE_IN:
+ return BLI_easing_sine_ease_in(time, begin, change, duration);
+ case BEZT_IPO_EASE_OUT:
+ return BLI_easing_sine_ease_out(time, begin, change, duration);
+ case BEZT_IPO_EASE_IN_OUT:
+ return BLI_easing_sine_ease_in_out(time, begin, change, duration);
+
+ default: /* default/auto: same as ease in */
+ return BLI_easing_sine_ease_in(time, begin, change, duration);
+ }
+ break;
+
+ default:
+ return prevbezt->vec[1][1];
}
- /* return value */
- return cvalue;
+ return 0.0f;
+}
+
+/* Calculate F-Curve value for 'evaltime' using BezTriple keyframes */
+static float fcurve_eval_keyframes(FCurve *fcu, BezTriple *bezts, float evaltime)
+{
+ if (evaltime <= bezts->vec[1][0]) {
+ return fcurve_eval_keyframes_extrapolate(fcu, bezts, evaltime, 0, +1);
+ }
+
+ BezTriple *lastbezt = bezts + fcu->totvert - 1;
+ if (lastbezt->vec[1][0] <= evaltime) {
+ return fcurve_eval_keyframes_extrapolate(fcu, bezts, evaltime, fcu->totvert - 1, -1);
+ }
+
+ return fcurve_eval_keyframes_interpolate(fcu, bezts, evaltime);
}
/* Calculate F-Curve value for 'evaltime' using FPoint samples */
diff --git a/source/blender/blenkernel/intern/fcurve_driver.c b/source/blender/blenkernel/intern/fcurve_driver.c
new file mode 100644
index 00000000000..78a6cf28824
--- /dev/null
+++ b/source/blender/blenkernel/intern/fcurve_driver.c
@@ -0,0 +1,1294 @@
+/*
+ * 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) 2009 Blender Foundation, Joshua Leung
+ * All rights reserved.
+ */
+
+/** \file
+ * \ingroup bke
+ */
+
+// #include <float.h>
+// #include <math.h>
+// #include <stddef.h>
+// #include <stdio.h>
+// #include <string.h>
+
+#include "MEM_guardedalloc.h"
+
+#include "DNA_anim_types.h"
+#include "DNA_constraint_types.h"
+#include "DNA_object_types.h"
+
+#include "BLI_alloca.h"
+#include "BLI_expr_pylike_eval.h"
+#include "BLI_math.h"
+#include "BLI_string_utils.h"
+#include "BLI_threads.h"
+#include "BLI_utildefines.h"
+
+#include "BLT_translation.h"
+
+#include "BKE_action.h"
+#include "BKE_armature.h"
+#include "BKE_constraint.h"
+#include "BKE_fcurve_driver.h"
+#include "BKE_global.h"
+#include "BKE_object.h"
+
+#include "RNA_access.h"
+
+#include "atomic_ops.h"
+
+#include "CLG_log.h"
+
+#ifdef WITH_PYTHON
+# include "BPY_extern.h"
+#endif
+
+#ifdef WITH_PYTHON
+static ThreadMutex python_driver_lock = BLI_MUTEX_INITIALIZER;
+#endif
+
+static CLG_LogRef LOG = {"bke.fcurve"};
+
+/* Driver Variables --------------------------- */
+
+/* TypeInfo for Driver Variables (dvti) */
+typedef struct DriverVarTypeInfo {
+ /* evaluation callback */
+ float (*get_value)(ChannelDriver *driver, DriverVar *dvar);
+
+ /* allocation of target slots */
+ int num_targets; /* number of target slots required */
+ const char *target_names[MAX_DRIVER_TARGETS]; /* UI names that should be given to the slots */
+ short target_flags[MAX_DRIVER_TARGETS]; /* flags defining the requirements for each slot */
+} DriverVarTypeInfo;
+
+/* Macro to begin definitions */
+#define BEGIN_DVAR_TYPEDEF(type) {
+
+/* Macro to end definitions */
+#define END_DVAR_TYPEDEF }
+
+/* ......... */
+
+static ID *dtar_id_ensure_proxy_from(ID *id)
+{
+ if (id && GS(id->name) == ID_OB && ((Object *)id)->proxy_from) {
+ return (ID *)(((Object *)id)->proxy_from);
+ }
+ return id;
+}
+
+/**
+ * Helper function to obtain a value using RNA from the specified source
+ * (for evaluating drivers).
+ */
+static float dtar_get_prop_val(ChannelDriver *driver, DriverTarget *dtar)
+{
+ PointerRNA id_ptr, ptr;
+ PropertyRNA *prop;
+ ID *id;
+ int index = -1;
+ float value = 0.0f;
+
+ /* sanity check */
+ if (ELEM(NULL, driver, dtar)) {
+ return 0.0f;
+ }
+
+ id = dtar_id_ensure_proxy_from(dtar->id);
+
+ /* error check for missing pointer... */
+ if (id == NULL) {
+ if (G.debug & G_DEBUG) {
+ CLOG_ERROR(&LOG, "driver has an invalid target to use (path = %s)", dtar->rna_path);
+ }
+
+ driver->flag |= DRIVER_FLAG_INVALID;
+ dtar->flag |= DTAR_FLAG_INVALID;
+ return 0.0f;
+ }
+
+ /* get RNA-pointer for the ID-block given in target */
+ RNA_id_pointer_create(id, &id_ptr);
+
+ /* get property to read from, and get value as appropriate */
+ if (!RNA_path_resolve_property_full(&id_ptr, dtar->rna_path, &ptr, &prop, &index)) {
+ /* path couldn't be resolved */
+ if (G.debug & G_DEBUG) {
+ CLOG_ERROR(&LOG,
+ "Driver Evaluation Error: cannot resolve target for %s -> %s",
+ id->name,
+ dtar->rna_path);
+ }
+
+ driver->flag |= DRIVER_FLAG_INVALID;
+ dtar->flag |= DTAR_FLAG_INVALID;
+ return 0.0f;
+ }
+
+ if (RNA_property_array_check(prop)) {
+ /* array */
+ if (index < 0 || index >= RNA_property_array_length(&ptr, prop)) {
+ /* out of bounds */
+ if (G.debug & G_DEBUG) {
+ CLOG_ERROR(&LOG,
+ "Driver Evaluation Error: array index is out of bounds for %s -> %s (%d)",
+ id->name,
+ dtar->rna_path,
+ index);
+ }
+
+ driver->flag |= DRIVER_FLAG_INVALID;
+ dtar->flag |= DTAR_FLAG_INVALID;
+ return 0.0f;
+ }
+
+ switch (RNA_property_type(prop)) {
+ case PROP_BOOLEAN:
+ value = (float)RNA_property_boolean_get_index(&ptr, prop, index);
+ break;
+ case PROP_INT:
+ value = (float)RNA_property_int_get_index(&ptr, prop, index);
+ break;
+ case PROP_FLOAT:
+ value = RNA_property_float_get_index(&ptr, prop, index);
+ break;
+ default:
+ break;
+ }
+ }
+ else {
+ /* not an array */
+ switch (RNA_property_type(prop)) {
+ case PROP_BOOLEAN:
+ value = (float)RNA_property_boolean_get(&ptr, prop);
+ break;
+ case PROP_INT:
+ value = (float)RNA_property_int_get(&ptr, prop);
+ break;
+ case PROP_FLOAT:
+ value = RNA_property_float_get(&ptr, prop);
+ break;
+ case PROP_ENUM:
+ value = (float)RNA_property_enum_get(&ptr, prop);
+ break;
+ default:
+ break;
+ }
+ }
+
+ /* if we're still here, we should be ok... */
+ dtar->flag &= ~DTAR_FLAG_INVALID;
+ return value;
+}
+
+/**
+ * Same as 'dtar_get_prop_val'. but get the RNA property.
+ */
+bool driver_get_variable_property(ChannelDriver *driver,
+ DriverTarget *dtar,
+ PointerRNA *r_ptr,
+ PropertyRNA **r_prop,
+ int *r_index)
+{
+ PointerRNA id_ptr;
+ PointerRNA ptr;
+ PropertyRNA *prop;
+ ID *id;
+ int index = -1;
+
+ /* sanity check */
+ if (ELEM(NULL, driver, dtar)) {
+ return false;
+ }
+
+ id = dtar_id_ensure_proxy_from(dtar->id);
+
+ /* error check for missing pointer... */
+ if (id == NULL) {
+ if (G.debug & G_DEBUG) {
+ CLOG_ERROR(&LOG, "driver has an invalid target to use (path = %s)", dtar->rna_path);
+ }
+
+ driver->flag |= DRIVER_FLAG_INVALID;
+ dtar->flag |= DTAR_FLAG_INVALID;
+ return false;
+ }
+
+ /* get RNA-pointer for the ID-block given in target */
+ RNA_id_pointer_create(id, &id_ptr);
+
+ /* get property to read from, and get value as appropriate */
+ if (dtar->rna_path == NULL || dtar->rna_path[0] == '\0') {
+ ptr = PointerRNA_NULL;
+ prop = NULL; /* ok */
+ }
+ else if (RNA_path_resolve_property_full(&id_ptr, dtar->rna_path, &ptr, &prop, &index)) {
+ /* ok */
+ }
+ else {
+ /* path couldn't be resolved */
+ if (G.debug & G_DEBUG) {
+ CLOG_ERROR(&LOG,
+ "Driver Evaluation Error: cannot resolve target for %s -> %s",
+ id->name,
+ dtar->rna_path);
+ }
+
+ ptr = PointerRNA_NULL;
+ *r_prop = NULL;
+ *r_index = -1;
+
+ driver->flag |= DRIVER_FLAG_INVALID;
+ dtar->flag |= DTAR_FLAG_INVALID;
+ return false;
+ }
+
+ *r_ptr = ptr;
+ *r_prop = prop;
+ *r_index = index;
+
+ /* if we're still here, we should be ok... */
+ dtar->flag &= ~DTAR_FLAG_INVALID;
+ return true;
+}
+
+static short driver_check_valid_targets(ChannelDriver *driver, DriverVar *dvar)
+{
+ short valid_targets = 0;
+
+ DRIVER_TARGETS_USED_LOOPER_BEGIN (dvar) {
+ Object *ob = (Object *)dtar_id_ensure_proxy_from(dtar->id);
+
+ /* check if this target has valid data */
+ if ((ob == NULL) || (GS(ob->id.name) != ID_OB)) {
+ /* invalid target, so will not have enough targets */
+ driver->flag |= DRIVER_FLAG_INVALID;
+ dtar->flag |= DTAR_FLAG_INVALID;
+ }
+ else {
+ /* target seems to be OK now... */
+ dtar->flag &= ~DTAR_FLAG_INVALID;
+ valid_targets++;
+ }
+ }
+ DRIVER_TARGETS_LOOPER_END;
+
+ return valid_targets;
+}
+
+/* ......... */
+
+/* evaluate 'single prop' driver variable */
+static float dvar_eval_singleProp(ChannelDriver *driver, DriverVar *dvar)
+{
+ /* just evaluate the first target slot */
+ return dtar_get_prop_val(driver, &dvar->targets[0]);
+}
+
+/* evaluate 'rotation difference' driver variable */
+static float dvar_eval_rotDiff(ChannelDriver *driver, DriverVar *dvar)
+{
+ short valid_targets = driver_check_valid_targets(driver, dvar);
+
+ /* make sure we have enough valid targets to use - all or nothing for now... */
+ if (driver_check_valid_targets(driver, dvar) != 2) {
+ if (G.debug & G_DEBUG) {
+ CLOG_WARN(&LOG,
+ "RotDiff DVar: not enough valid targets (n = %d) (a = %p, b = %p)",
+ valid_targets,
+ dvar->targets[0].id,
+ dvar->targets[1].id);
+ }
+ return 0.0f;
+ }
+
+ float(*mat[2])[4];
+
+ /* NOTE: for now, these are all just worldspace */
+ for (int i = 0; i < 2; i++) {
+ /* get pointer to loc values to store in */
+ DriverTarget *dtar = &dvar->targets[i];
+ Object *ob = (Object *)dtar_id_ensure_proxy_from(dtar->id);
+ bPoseChannel *pchan;
+
+ /* after the checks above, the targets should be valid here... */
+ BLI_assert((ob != NULL) && (GS(ob->id.name) == ID_OB));
+
+ /* try to get posechannel */
+ pchan = BKE_pose_channel_find_name(ob->pose, dtar->pchan_name);
+
+ /* check if object or bone */
+ if (pchan) {
+ /* bone */
+ mat[i] = pchan->pose_mat;
+ }
+ else {
+ /* object */
+ mat[i] = ob->obmat;
+ }
+ }
+
+ float q1[4], q2[4], quat[4], angle;
+
+ /* use the final posed locations */
+ mat4_to_quat(q1, mat[0]);
+ mat4_to_quat(q2, mat[1]);
+
+ invert_qt_normalized(q1);
+ mul_qt_qtqt(quat, q1, q2);
+ angle = 2.0f * (saacos(quat[0]));
+ angle = fabsf(angle);
+
+ return (angle > (float)M_PI) ? (float)((2.0f * (float)M_PI) - angle) : (float)(angle);
+}
+
+/* evaluate 'location difference' driver variable */
+/* TODO: this needs to take into account space conversions... */
+static float dvar_eval_locDiff(ChannelDriver *driver, DriverVar *dvar)
+{
+ float loc1[3] = {0.0f, 0.0f, 0.0f};
+ float loc2[3] = {0.0f, 0.0f, 0.0f};
+ short valid_targets = driver_check_valid_targets(driver, dvar);
+
+ /* make sure we have enough valid targets to use - all or nothing for now... */
+ if (valid_targets < dvar->num_targets) {
+ if (G.debug & G_DEBUG) {
+ CLOG_WARN(&LOG,
+ "LocDiff DVar: not enough valid targets (n = %d) (a = %p, b = %p)",
+ valid_targets,
+ dvar->targets[0].id,
+ dvar->targets[1].id);
+ }
+ return 0.0f;
+ }
+
+ /* SECOND PASS: get two location values */
+ /* NOTE: for now, these are all just worldspace */
+ DRIVER_TARGETS_USED_LOOPER_BEGIN (dvar) {
+ /* get pointer to loc values to store in */
+ Object *ob = (Object *)dtar_id_ensure_proxy_from(dtar->id);
+ bPoseChannel *pchan;
+ float tmp_loc[3];
+
+ /* after the checks above, the targets should be valid here... */
+ BLI_assert((ob != NULL) && (GS(ob->id.name) == ID_OB));
+
+ /* try to get posechannel */
+ pchan = BKE_pose_channel_find_name(ob->pose, dtar->pchan_name);
+
+ /* check if object or bone */
+ if (pchan) {
+ /* bone */
+ if (dtar->flag & DTAR_FLAG_LOCALSPACE) {
+ if (dtar->flag & DTAR_FLAG_LOCAL_CONSTS) {
+ float mat[4][4];
+
+ /* extract transform just like how the constraints do it! */
+ copy_m4_m4(mat, pchan->pose_mat);
+ BKE_constraint_mat_convertspace(
+ ob, pchan, mat, CONSTRAINT_SPACE_POSE, CONSTRAINT_SPACE_LOCAL, false);
+
+ /* ... and from that, we get our transform */
+ copy_v3_v3(tmp_loc, mat[3]);
+ }
+ else {
+ /* transform space (use transform values directly) */
+ copy_v3_v3(tmp_loc, pchan->loc);
+ }
+ }
+ else {
+ /* convert to worldspace */
+ copy_v3_v3(tmp_loc, pchan->pose_head);
+ mul_m4_v3(ob->obmat, tmp_loc);
+ }
+ }
+ else {
+ /* object */
+ if (dtar->flag & DTAR_FLAG_LOCALSPACE) {
+ if (dtar->flag & DTAR_FLAG_LOCAL_CONSTS) {
+ /* XXX: this should practically be the same as transform space... */
+ float mat[4][4];
+
+ /* extract transform just like how the constraints do it! */
+ copy_m4_m4(mat, ob->obmat);
+ BKE_constraint_mat_convertspace(
+ ob, NULL, mat, CONSTRAINT_SPACE_WORLD, CONSTRAINT_SPACE_LOCAL, false);
+
+ /* ... and from that, we get our transform */
+ copy_v3_v3(tmp_loc, mat[3]);
+ }
+ else {
+ /* transform space (use transform values directly) */
+ copy_v3_v3(tmp_loc, ob->loc);
+ }
+ }
+ else {
+ /* worldspace */
+ copy_v3_v3(tmp_loc, ob->obmat[3]);
+ }
+ }
+
+ /* copy the location to the right place */
+ if (tarIndex) {
+ copy_v3_v3(loc2, tmp_loc);
+ }
+ else {
+ copy_v3_v3(loc1, tmp_loc);
+ }
+ }
+ DRIVER_TARGETS_LOOPER_END;
+
+ /* if we're still here, there should now be two targets to use,
+ * so just take the length of the vector between these points
+ */
+ return len_v3v3(loc1, loc2);
+}
+
+/* evaluate 'transform channel' driver variable */
+static float dvar_eval_transChan(ChannelDriver *driver, DriverVar *dvar)
+{
+ DriverTarget *dtar = &dvar->targets[0];
+ Object *ob = (Object *)dtar_id_ensure_proxy_from(dtar->id);
+ bPoseChannel *pchan;
+ float mat[4][4];
+ float oldEul[3] = {0.0f, 0.0f, 0.0f};
+ bool use_eulers = false;
+ short rot_order = ROT_MODE_EUL;
+
+ /* check if this target has valid data */
+ if ((ob == NULL) || (GS(ob->id.name) != ID_OB)) {
+ /* invalid target, so will not have enough targets */
+ driver->flag |= DRIVER_FLAG_INVALID;
+ dtar->flag |= DTAR_FLAG_INVALID;
+ return 0.0f;
+ }
+ else {
+ /* target should be valid now */
+ dtar->flag &= ~DTAR_FLAG_INVALID;
+ }
+
+ /* try to get posechannel */
+ pchan = BKE_pose_channel_find_name(ob->pose, dtar->pchan_name);
+
+ /* check if object or bone, and get transform matrix accordingly
+ * - "useEulers" code is used to prevent the problems associated with non-uniqueness
+ * of euler decomposition from matrices [#20870]
+ * - localspace is for [#21384], where parent results are not wanted
+ * but local-consts is for all the common "corrective-shapes-for-limbs" situations
+ */
+ if (pchan) {
+ /* bone */
+ if (pchan->rotmode > 0) {
+ copy_v3_v3(oldEul, pchan->eul);
+ rot_order = pchan->rotmode;
+ use_eulers = true;
+ }
+
+ if (dtar->flag & DTAR_FLAG_LOCALSPACE) {
+ if (dtar->flag & DTAR_FLAG_LOCAL_CONSTS) {
+ /* just like how the constraints do it! */
+ copy_m4_m4(mat, pchan->pose_mat);
+ BKE_constraint_mat_convertspace(
+ ob, pchan, mat, CONSTRAINT_SPACE_POSE, CONSTRAINT_SPACE_LOCAL, false);
+ }
+ else {
+ /* specially calculate local matrix, since chan_mat is not valid
+ * since it stores delta transform of pose_mat so that deforms work
+ * so it cannot be used here for "transform" space
+ */
+ BKE_pchan_to_mat4(pchan, mat);
+ }
+ }
+ else {
+ /* worldspace matrix */
+ mul_m4_m4m4(mat, ob->obmat, pchan->pose_mat);
+ }
+ }
+ else {
+ /* object */
+ if (ob->rotmode > 0) {
+ copy_v3_v3(oldEul, ob->rot);
+ rot_order = ob->rotmode;
+ use_eulers = true;
+ }
+
+ if (dtar->flag & DTAR_FLAG_LOCALSPACE) {
+ if (dtar->flag & DTAR_FLAG_LOCAL_CONSTS) {
+ /* just like how the constraints do it! */
+ copy_m4_m4(mat, ob->obmat);
+ BKE_constraint_mat_convertspace(
+ ob, NULL, mat, CONSTRAINT_SPACE_WORLD, CONSTRAINT_SPACE_LOCAL, false);
+ }
+ else {
+ /* transforms to matrix */
+ BKE_object_to_mat4(ob, mat);
+ }
+ }
+ else {
+ /* worldspace matrix - just the good-old one */
+ copy_m4_m4(mat, ob->obmat);
+ }
+ }
+
+ /* check which transform */
+ if (dtar->transChan >= MAX_DTAR_TRANSCHAN_TYPES) {
+ /* not valid channel */
+ return 0.0f;
+ }
+ else if (dtar->transChan == DTAR_TRANSCHAN_SCALE_AVG) {
+ /* Cubic root of the change in volume, equal to the geometric mean
+ * of scale over all three axes unless the matrix includes shear. */
+ return cbrtf(mat4_to_volume_scale(mat));
+ }
+ else if (ELEM(dtar->transChan,
+ DTAR_TRANSCHAN_SCALEX,
+ DTAR_TRANSCHAN_SCALEY,
+ DTAR_TRANSCHAN_SCALEZ)) {
+ /* Extract scale, and choose the right axis,
+ * inline 'mat4_to_size'. */
+ return len_v3(mat[dtar->transChan - DTAR_TRANSCHAN_SCALEX]);
+ }
+ else if (dtar->transChan >= DTAR_TRANSCHAN_ROTX) {
+ /* extract rotation as eulers (if needed)
+ * - definitely if rotation order isn't eulers already
+ * - if eulers, then we have 2 options:
+ * a) decompose transform matrix as required, then try to make eulers from
+ * there compatible with original values
+ * b) [NOT USED] directly use the original values (no decomposition)
+ * - only an option for "transform space", if quality is really bad with a)
+ */
+ float quat[4];
+ int channel;
+
+ if (dtar->transChan == DTAR_TRANSCHAN_ROTW) {
+ channel = 0;
+ }
+ else {
+ channel = 1 + dtar->transChan - DTAR_TRANSCHAN_ROTX;
+ BLI_assert(channel < 4);
+ }
+
+ BKE_driver_target_matrix_to_rot_channels(
+ mat, rot_order, dtar->rotation_mode, channel, false, quat);
+
+ if (use_eulers && dtar->rotation_mode == DTAR_ROTMODE_AUTO) {
+ compatible_eul(quat + 1, oldEul);
+ }
+
+ return quat[channel];
+ }
+ else {
+ /* extract location and choose right axis */
+ return mat[3][dtar->transChan];
+ }
+}
+
+/* Convert a quaternion to pseudo-angles representing the weighted amount of rotation. */
+static void quaternion_to_angles(float quat[4], int channel)
+{
+ if (channel < 0) {
+ quat[0] = 2.0f * saacosf(quat[0]);
+
+ for (int i = 1; i < 4; i++) {
+ quat[i] = 2.0f * saasinf(quat[i]);
+ }
+ }
+ else if (channel == 0) {
+ quat[0] = 2.0f * saacosf(quat[0]);
+ }
+ else {
+ quat[channel] = 2.0f * saasinf(quat[channel]);
+ }
+}
+
+/* Compute channel values for a rotational Transform Channel driver variable. */
+void BKE_driver_target_matrix_to_rot_channels(
+ float mat[4][4], int auto_order, int rotation_mode, int channel, bool angles, float r_buf[4])
+{
+ float *const quat = r_buf;
+ float *const eul = r_buf + 1;
+
+ zero_v4(r_buf);
+
+ if (rotation_mode == DTAR_ROTMODE_AUTO) {
+ mat4_to_eulO(eul, auto_order, mat);
+ }
+ else if (rotation_mode >= DTAR_ROTMODE_EULER_MIN && rotation_mode <= DTAR_ROTMODE_EULER_MAX) {
+ mat4_to_eulO(eul, rotation_mode, mat);
+ }
+ else if (rotation_mode == DTAR_ROTMODE_QUATERNION) {
+ mat4_to_quat(quat, mat);
+
+ /* For Transformation constraint convenience, convert to pseudo-angles. */
+ if (angles) {
+ quaternion_to_angles(quat, channel);
+ }
+ }
+ else if (rotation_mode >= DTAR_ROTMODE_SWING_TWIST_X &&
+ rotation_mode <= DTAR_ROTMODE_SWING_TWIST_Z) {
+ int axis = rotation_mode - DTAR_ROTMODE_SWING_TWIST_X;
+ float raw_quat[4], twist;
+
+ mat4_to_quat(raw_quat, mat);
+
+ if (channel == axis + 1) {
+ /* If only the twist angle is needed, skip computing swing. */
+ twist = quat_split_swing_and_twist(raw_quat, axis, NULL, NULL);
+ }
+ else {
+ twist = quat_split_swing_and_twist(raw_quat, axis, quat, NULL);
+
+ quaternion_to_angles(quat, channel);
+ }
+
+ quat[axis + 1] = twist;
+ }
+ else {
+ BLI_assert(false);
+ }
+}
+
+/* ......... */
+
+/* Table of Driver Variable Type Info Data */
+static DriverVarTypeInfo dvar_types[MAX_DVAR_TYPES] = {
+ BEGIN_DVAR_TYPEDEF(DVAR_TYPE_SINGLE_PROP) dvar_eval_singleProp, /* eval callback */
+ 1, /* number of targets used */
+ {"Property"}, /* UI names for targets */
+ {0} /* flags */
+ END_DVAR_TYPEDEF,
+
+ BEGIN_DVAR_TYPEDEF(DVAR_TYPE_ROT_DIFF) dvar_eval_rotDiff, /* eval callback */
+ 2, /* number of targets used */
+ {"Object/Bone 1", "Object/Bone 2"}, /* UI names for targets */
+ {DTAR_FLAG_STRUCT_REF | DTAR_FLAG_ID_OB_ONLY,
+ DTAR_FLAG_STRUCT_REF | DTAR_FLAG_ID_OB_ONLY} /* flags */
+ END_DVAR_TYPEDEF,
+
+ BEGIN_DVAR_TYPEDEF(DVAR_TYPE_LOC_DIFF) dvar_eval_locDiff, /* eval callback */
+ 2, /* number of targets used */
+ {"Object/Bone 1", "Object/Bone 2"}, /* UI names for targets */
+ {DTAR_FLAG_STRUCT_REF | DTAR_FLAG_ID_OB_ONLY,
+ DTAR_FLAG_STRUCT_REF | DTAR_FLAG_ID_OB_ONLY} /* flags */
+ END_DVAR_TYPEDEF,
+
+ BEGIN_DVAR_TYPEDEF(DVAR_TYPE_TRANSFORM_CHAN) dvar_eval_transChan, /* eval callback */
+ 1, /* number of targets used */
+ {"Object/Bone"}, /* UI names for targets */
+ {DTAR_FLAG_STRUCT_REF | DTAR_FLAG_ID_OB_ONLY} /* flags */
+ END_DVAR_TYPEDEF,
+};
+
+/* Get driver variable typeinfo */
+static const DriverVarTypeInfo *get_dvar_typeinfo(int type)
+{
+ /* check if valid type */
+ if ((type >= 0) && (type < MAX_DVAR_TYPES)) {
+ return &dvar_types[type];
+ }
+ else {
+ return NULL;
+ }
+}
+
+/* Driver API --------------------------------- */
+
+/* Perform actual freeing driver variable and remove it from the given list */
+void driver_free_variable(ListBase *variables, DriverVar *dvar)
+{
+ /* sanity checks */
+ if (dvar == NULL) {
+ return;
+ }
+
+ /* free target vars
+ * - need to go over all of them, not just up to the ones that are used
+ * currently, since there may be some lingering RNA paths from
+ * previous users needing freeing
+ */
+ DRIVER_TARGETS_LOOPER_BEGIN (dvar) {
+ /* free RNA path if applicable */
+ if (dtar->rna_path) {
+ MEM_freeN(dtar->rna_path);
+ }
+ }
+ DRIVER_TARGETS_LOOPER_END;
+
+ /* remove the variable from the driver */
+ BLI_freelinkN(variables, dvar);
+}
+
+/* Free the driver variable and do extra updates */
+void driver_free_variable_ex(ChannelDriver *driver, DriverVar *dvar)
+{
+ /* remove and free the driver variable */
+ driver_free_variable(&driver->variables, dvar);
+
+ /* since driver variables are cached, the expression needs re-compiling too */
+ BKE_driver_invalidate_expression(driver, false, true);
+}
+
+/* Copy driver variables from src_vars list to dst_vars list */
+void driver_variables_copy(ListBase *dst_vars, const ListBase *src_vars)
+{
+ BLI_assert(BLI_listbase_is_empty(dst_vars));
+ BLI_duplicatelist(dst_vars, src_vars);
+
+ LISTBASE_FOREACH (DriverVar *, dvar, dst_vars) {
+ /* need to go over all targets so that we don't leave any dangling paths */
+ DRIVER_TARGETS_LOOPER_BEGIN (dvar) {
+ /* make a copy of target's rna path if available */
+ if (dtar->rna_path) {
+ dtar->rna_path = MEM_dupallocN(dtar->rna_path);
+ }
+ }
+ DRIVER_TARGETS_LOOPER_END;
+ }
+}
+
+/* Change the type of driver variable */
+void driver_change_variable_type(DriverVar *dvar, int type)
+{
+ const DriverVarTypeInfo *dvti = get_dvar_typeinfo(type);
+
+ /* sanity check */
+ if (ELEM(NULL, dvar, dvti)) {
+ return;
+ }
+
+ /* set the new settings */
+ dvar->type = type;
+ dvar->num_targets = dvti->num_targets;
+
+ /* make changes to the targets based on the defines for these types
+ * NOTE: only need to make sure the ones we're using here are valid...
+ */
+ DRIVER_TARGETS_USED_LOOPER_BEGIN (dvar) {
+ short flags = dvti->target_flags[tarIndex];
+
+ /* store the flags */
+ dtar->flag = flags;
+
+ /* object ID types only, or idtype not yet initialized */
+ if ((flags & DTAR_FLAG_ID_OB_ONLY) || (dtar->idtype == 0)) {
+ dtar->idtype = ID_OB;
+ }
+ }
+ DRIVER_TARGETS_LOOPER_END;
+}
+
+/* Validate driver name (after being renamed) */
+void driver_variable_name_validate(DriverVar *dvar)
+{
+ /* Special character blacklist */
+ const char special_char_blacklist[] = {
+ '~', '`', '!', '@', '#', '$', '%', '^', '&', '*', '+', '=', '-', '/', '\\',
+ '?', ':', ';', '<', '>', '{', '}', '[', ']', '|', ' ', '.', '\t', '\n', '\r',
+ };
+
+ /* sanity checks */
+ if (dvar == NULL) {
+ return;
+ }
+
+ /* clear all invalid-name flags */
+ dvar->flag &= ~DVAR_ALL_INVALID_FLAGS;
+
+ /* 0) Zero-length identifiers are not allowed */
+ if (dvar->name[0] == '\0') {
+ dvar->flag |= DVAR_FLAG_INVALID_EMPTY;
+ }
+
+ /* 1) Must start with a letter */
+ /* XXX: We assume that valid unicode letters in other languages are ok too,
+ * hence the blacklisting. */
+ if (IN_RANGE_INCL(dvar->name[0], '0', '9')) {
+ dvar->flag |= DVAR_FLAG_INVALID_START_NUM;
+ }
+ else if (dvar->name[0] == '_') {
+ /* NOTE: We don't allow names to start with underscores
+ * (i.e. it helps when ruling out security risks) */
+ dvar->flag |= DVAR_FLAG_INVALID_START_CHAR;
+ }
+
+ /* 2) Must not contain invalid stuff in the middle of the string */
+ if (strchr(dvar->name, ' ')) {
+ dvar->flag |= DVAR_FLAG_INVALID_HAS_SPACE;
+ }
+ if (strchr(dvar->name, '.')) {
+ dvar->flag |= DVAR_FLAG_INVALID_HAS_DOT;
+ }
+
+ /* 3) Check for special characters - Either at start, or in the middle */
+ for (int i = 0; i < sizeof(special_char_blacklist); i++) {
+ char *match = strchr(dvar->name, special_char_blacklist[i]);
+
+ if (match == dvar->name) {
+ dvar->flag |= DVAR_FLAG_INVALID_START_CHAR;
+ }
+ else if (match != NULL) {
+ dvar->flag |= DVAR_FLAG_INVALID_HAS_SPECIAL;
+ }
+ }
+
+ /* 4) Check if the name is a reserved keyword
+ * NOTE: These won't confuse Python, but it will be impossible to use the variable
+ * in an expression without Python misinterpreting what these are for
+ */
+#ifdef WITH_PYTHON
+ if (BPY_string_is_keyword(dvar->name)) {
+ dvar->flag |= DVAR_FLAG_INVALID_PY_KEYWORD;
+ }
+#endif
+
+ /* If any these conditions match, the name is invalid */
+ if (dvar->flag & DVAR_ALL_INVALID_FLAGS) {
+ dvar->flag |= DVAR_FLAG_INVALID_NAME;
+ }
+}
+
+/* Add a new driver variable */
+DriverVar *driver_add_new_variable(ChannelDriver *driver)
+{
+ DriverVar *dvar;
+
+ /* sanity checks */
+ if (driver == NULL) {
+ return NULL;
+ }
+
+ /* make a new variable */
+ dvar = MEM_callocN(sizeof(DriverVar), "DriverVar");
+ BLI_addtail(&driver->variables, dvar);
+
+ /* give the variable a 'unique' name */
+ strcpy(dvar->name, CTX_DATA_(BLT_I18NCONTEXT_ID_ACTION, "var"));
+ BLI_uniquename(&driver->variables,
+ dvar,
+ CTX_DATA_(BLT_I18NCONTEXT_ID_ACTION, "var"),
+ '_',
+ offsetof(DriverVar, name),
+ sizeof(dvar->name));
+
+ /* set the default type to 'single prop' */
+ driver_change_variable_type(dvar, DVAR_TYPE_SINGLE_PROP);
+
+ /* since driver variables are cached, the expression needs re-compiling too */
+ BKE_driver_invalidate_expression(driver, false, true);
+
+ /* return the target */
+ return dvar;
+}
+
+/* This frees the driver itself */
+void fcurve_free_driver(FCurve *fcu)
+{
+ ChannelDriver *driver;
+ DriverVar *dvar, *dvarn;
+
+ /* sanity checks */
+ if (ELEM(NULL, fcu, fcu->driver)) {
+ return;
+ }
+ driver = fcu->driver;
+
+ /* free driver targets */
+ for (dvar = driver->variables.first; dvar; dvar = dvarn) {
+ dvarn = dvar->next;
+ driver_free_variable_ex(driver, dvar);
+ }
+
+#ifdef WITH_PYTHON
+ /* free compiled driver expression */
+ if (driver->expr_comp) {
+ BPY_DECREF(driver->expr_comp);
+ }
+#endif
+
+ BLI_expr_pylike_free(driver->expr_simple);
+
+ /* Free driver itself, then set F-Curve's point to this to NULL
+ * (as the curve may still be used). */
+ MEM_freeN(driver);
+ fcu->driver = NULL;
+}
+
+/* This makes a copy of the given driver */
+ChannelDriver *fcurve_copy_driver(const ChannelDriver *driver)
+{
+ ChannelDriver *ndriver;
+
+ /* sanity checks */
+ if (driver == NULL) {
+ return NULL;
+ }
+
+ /* copy all data */
+ ndriver = MEM_dupallocN(driver);
+ ndriver->expr_comp = NULL;
+ ndriver->expr_simple = NULL;
+
+ /* copy variables */
+
+ /* to get rid of refs to non-copied data (that's still used on original) */
+ BLI_listbase_clear(&ndriver->variables);
+ driver_variables_copy(&ndriver->variables, &driver->variables);
+
+ /* return the new driver */
+ return ndriver;
+}
+
+/* Driver Expression Evaluation --------------- */
+
+/* Index constants for the expression parameter array. */
+enum {
+ /* Index of the 'frame' variable. */
+ VAR_INDEX_FRAME = 0,
+ /* Index of the first user-defined driver variable. */
+ VAR_INDEX_CUSTOM
+};
+
+static ExprPyLike_Parsed *driver_compile_simple_expr_impl(ChannelDriver *driver)
+{
+ /* Prepare parameter names. */
+ int names_len = BLI_listbase_count(&driver->variables);
+ const char **names = BLI_array_alloca(names, names_len + VAR_INDEX_CUSTOM);
+ int i = VAR_INDEX_CUSTOM;
+
+ names[VAR_INDEX_FRAME] = "frame";
+
+ LISTBASE_FOREACH (DriverVar *, dvar, &driver->variables) {
+ names[i++] = dvar->name;
+ }
+
+ return BLI_expr_pylike_parse(driver->expression, names, names_len + VAR_INDEX_CUSTOM);
+}
+
+static bool driver_check_simple_expr_depends_on_time(ExprPyLike_Parsed *expr)
+{
+ /* Check if the 'frame' parameter is actually used. */
+ return BLI_expr_pylike_is_using_param(expr, VAR_INDEX_FRAME);
+}
+
+static bool driver_evaluate_simple_expr(ChannelDriver *driver,
+ ExprPyLike_Parsed *expr,
+ float *result,
+ float time)
+{
+ /* Prepare parameter values. */
+ int vars_len = BLI_listbase_count(&driver->variables);
+ double *vars = BLI_array_alloca(vars, vars_len + VAR_INDEX_CUSTOM);
+ int i = VAR_INDEX_CUSTOM;
+
+ vars[VAR_INDEX_FRAME] = time;
+
+ LISTBASE_FOREACH (DriverVar *, dvar, &driver->variables) {
+ vars[i++] = driver_get_variable_value(driver, dvar);
+ }
+
+ /* Evaluate expression. */
+ double result_val;
+ eExprPyLike_EvalStatus status = BLI_expr_pylike_eval(
+ expr, vars, vars_len + VAR_INDEX_CUSTOM, &result_val);
+ const char *message;
+
+ switch (status) {
+ case EXPR_PYLIKE_SUCCESS:
+ if (isfinite(result_val)) {
+ *result = (float)result_val;
+ }
+ return true;
+
+ case EXPR_PYLIKE_DIV_BY_ZERO:
+ case EXPR_PYLIKE_MATH_ERROR:
+ message = (status == EXPR_PYLIKE_DIV_BY_ZERO) ? "Division by Zero" : "Math Domain Error";
+ CLOG_ERROR(&LOG, "%s in Driver: '%s'", message, driver->expression);
+
+ driver->flag |= DRIVER_FLAG_INVALID;
+ return true;
+
+ default:
+ /* arriving here means a bug, not user error */
+ CLOG_ERROR(&LOG, "simple driver expression evaluation failed: '%s'", driver->expression);
+ return false;
+ }
+}
+
+/* Compile and cache the driver expression if necessary, with thread safety. */
+static bool driver_compile_simple_expr(ChannelDriver *driver)
+{
+ if (driver->expr_simple != NULL) {
+ return true;
+ }
+
+ if (driver->type != DRIVER_TYPE_PYTHON) {
+ return false;
+ }
+
+ /* It's safe to parse in multiple threads; at worst it'll
+ * waste some effort, but in return avoids mutex contention. */
+ ExprPyLike_Parsed *expr = driver_compile_simple_expr_impl(driver);
+
+ /* Store the result if the field is still NULL, or discard
+ * it if another thread got here first. */
+ if (atomic_cas_ptr((void **)&driver->expr_simple, NULL, expr) != NULL) {
+ BLI_expr_pylike_free(expr);
+ }
+
+ return true;
+}
+
+/* Try using the simple expression evaluator to compute the result of the driver.
+ * On success, stores the result and returns true; on failure result is set to 0. */
+static bool driver_try_evaluate_simple_expr(ChannelDriver *driver,
+ ChannelDriver *driver_orig,
+ float *result,
+ float time)
+{
+ *result = 0.0f;
+
+ return driver_compile_simple_expr(driver_orig) &&
+ BLI_expr_pylike_is_valid(driver_orig->expr_simple) &&
+ driver_evaluate_simple_expr(driver, driver_orig->expr_simple, result, time);
+}
+
+/* Check if the expression in the driver conforms to the simple subset. */
+bool BKE_driver_has_simple_expression(ChannelDriver *driver)
+{
+ return driver_compile_simple_expr(driver) && BLI_expr_pylike_is_valid(driver->expr_simple);
+}
+
+/* TODO(sergey): This is somewhat weak, but we don't want neither false-positive
+ * time dependencies nor special exceptions in the depsgraph evaluation. */
+static bool python_driver_exression_depends_on_time(const char *expression)
+{
+ if (expression[0] == '\0') {
+ /* Empty expression depends on nothing. */
+ return false;
+ }
+ if (strchr(expression, '(') != NULL) {
+ /* Function calls are considered dependent on a time. */
+ return true;
+ }
+ if (strstr(expression, "frame") != NULL) {
+ /* Variable `frame` depends on time. */
+ /* TODO(sergey): This is a bit weak, but not sure about better way of handling this. */
+ return true;
+ }
+ /* Possible indirect time relation s should be handled via variable targets. */
+ return false;
+}
+
+/* Check if the expression in the driver may depend on the current frame. */
+bool BKE_driver_expression_depends_on_time(ChannelDriver *driver)
+{
+ if (driver->type != DRIVER_TYPE_PYTHON) {
+ return false;
+ }
+
+ if (BKE_driver_has_simple_expression(driver)) {
+ /* Simple expressions can be checked exactly. */
+ return driver_check_simple_expr_depends_on_time(driver->expr_simple);
+ }
+ else {
+ /* Otherwise, heuristically scan the expression string for certain patterns. */
+ return python_driver_exression_depends_on_time(driver->expression);
+ }
+}
+
+/* Reset cached compiled expression data */
+void BKE_driver_invalidate_expression(ChannelDriver *driver,
+ bool expr_changed,
+ bool varname_changed)
+{
+ if (expr_changed || varname_changed) {
+ BLI_expr_pylike_free(driver->expr_simple);
+ driver->expr_simple = NULL;
+ }
+
+#ifdef WITH_PYTHON
+ if (expr_changed) {
+ driver->flag |= DRIVER_FLAG_RECOMPILE;
+ }
+
+ if (varname_changed) {
+ driver->flag |= DRIVER_FLAG_RENAMEVAR;
+ }
+#endif
+}
+
+/* Driver Evaluation -------------------------- */
+
+/* Evaluate a Driver Variable to get a value that contributes to the final */
+float driver_get_variable_value(ChannelDriver *driver, DriverVar *dvar)
+{
+ const DriverVarTypeInfo *dvti;
+
+ /* sanity check */
+ if (ELEM(NULL, driver, dvar)) {
+ return 0.0f;
+ }
+
+ /* call the relevant callbacks to get the variable value
+ * using the variable type info, storing the obtained value
+ * in dvar->curval so that drivers can be debugged
+ */
+ dvti = get_dvar_typeinfo(dvar->type);
+
+ if (dvti && dvti->get_value) {
+ dvar->curval = dvti->get_value(driver, dvar);
+ }
+ else {
+ dvar->curval = 0.0f;
+ }
+
+ return dvar->curval;
+}
+
+static void evaluate_driver_sum(ChannelDriver *driver)
+{
+ DriverVar *dvar;
+
+ /* check how many variables there are first (i.e. just one?) */
+ if (BLI_listbase_is_single(&driver->variables)) {
+ /* just one target, so just use that */
+ dvar = driver->variables.first;
+ driver->curval = driver_get_variable_value(driver, dvar);
+ return;
+ }
+
+ /* more than one target, so average the values of the targets */
+ float value = 0.0f;
+ int tot = 0;
+
+ /* loop through targets, adding (hopefully we don't get any overflow!) */
+ for (dvar = driver->variables.first; dvar; dvar = dvar->next) {
+ value += driver_get_variable_value(driver, dvar);
+ tot++;
+ }
+
+ /* perform operations on the total if appropriate */
+ if (driver->type == DRIVER_TYPE_AVERAGE) {
+ driver->curval = tot ? (value / (float)tot) : 0.0f;
+ }
+ else {
+ driver->curval = value;
+ }
+}
+
+static void evaluate_driver_min_max(ChannelDriver *driver)
+{
+ DriverVar *dvar;
+ float value = 0.0f;
+
+ /* loop through the variables, getting the values and comparing them to existing ones */
+ for (dvar = driver->variables.first; dvar; dvar = dvar->next) {
+ /* get value */
+ float tmp_val = driver_get_variable_value(driver, dvar);
+
+ /* store this value if appropriate */
+ if (dvar->prev) {
+ /* check if greater/smaller than the baseline */
+ if (driver->type == DRIVER_TYPE_MAX) {
+ /* max? */
+ if (tmp_val > value) {
+ value = tmp_val;
+ }
+ }
+ else {
+ /* min? */
+ if (tmp_val < value) {
+ value = tmp_val;
+ }
+ }
+ }
+ else {
+ /* first item - make this the baseline for comparisons */
+ value = tmp_val;
+ }
+ }
+
+ /* store value in driver */
+ driver->curval = value;
+}
+
+static void evaluate_driver_python(PathResolvedRNA *anim_rna,
+ ChannelDriver *driver,
+ ChannelDriver *driver_orig,
+ const float evaltime)
+{
+ /* check for empty or invalid expression */
+ if ((driver_orig->expression[0] == '\0') || (driver_orig->flag & DRIVER_FLAG_INVALID)) {
+ driver->curval = 0.0f;
+ }
+ else if (!driver_try_evaluate_simple_expr(driver, driver_orig, &driver->curval, evaltime)) {
+#ifdef WITH_PYTHON
+ /* this evaluates the expression using Python, and returns its result:
+ * - on errors it reports, then returns 0.0f
+ */
+ BLI_mutex_lock(&python_driver_lock);
+
+ driver->curval = BPY_driver_exec(anim_rna, driver, driver_orig, evaltime);
+
+ BLI_mutex_unlock(&python_driver_lock);
+#else /* WITH_PYTHON*/
+ UNUSED_VARS(anim_rna, evaltime);
+#endif /* WITH_PYTHON*/
+ }
+}
+
+/* Evaluate an Channel-Driver to get a 'time' value to use instead of "evaltime"
+ * - "evaltime" is the frame at which F-Curve is being evaluated
+ * - has to return a float value
+ * - driver_orig is where we cache Python expressions, in case of COW
+ */
+float evaluate_driver(PathResolvedRNA *anim_rna,
+ ChannelDriver *driver,
+ ChannelDriver *driver_orig,
+ const float evaltime)
+{
+ /* check if driver can be evaluated */
+ if (driver_orig->flag & DRIVER_FLAG_INVALID) {
+ return 0.0f;
+ }
+
+ switch (driver->type) {
+ case DRIVER_TYPE_AVERAGE: /* average values of driver targets */
+ case DRIVER_TYPE_SUM: /* sum values of driver targets */
+ evaluate_driver_sum(driver);
+ break;
+ case DRIVER_TYPE_MIN: /* smallest value */
+ case DRIVER_TYPE_MAX: /* largest value */
+ evaluate_driver_min_max(driver);
+ break;
+ case DRIVER_TYPE_PYTHON: /* expression */
+ evaluate_driver_python(anim_rna, driver, driver_orig, evaltime);
+ break;
+ default:
+ /* special 'hack' - just use stored value
+ * This is currently used as the mechanism which allows animated settings to be able
+ * to be changed via the UI.
+ */
+ break;
+ }
+
+ /* return value for driver */
+ return driver->curval;
+}
diff --git a/source/blender/blenkernel/intern/fluid.c b/source/blender/blenkernel/intern/fluid.c
index ae51c997a08..b75592836e0 100644
--- a/source/blender/blenkernel/intern/fluid.c
+++ b/source/blender/blenkernel/intern/fluid.c
@@ -36,6 +36,7 @@
#include "DNA_fluid_types.h"
#include "DNA_modifier_types.h"
#include "DNA_object_types.h"
+#include "DNA_rigidbody_types.h"
#include "BKE_effect.h"
#include "BKE_fluid.h"
@@ -80,6 +81,8 @@
# include "RE_shader_ext.h"
+# include "CLG_log.h"
+
# include "manta_fluid_API.h"
#endif /* WITH_FLUID */
@@ -95,6 +98,8 @@ static void BKE_fluid_modifier_reset_ex(struct FluidModifierData *mmd, bool need
#ifdef WITH_FLUID
// #define DEBUG_PRINT
+static CLG_LogRef LOG = {"bke.fluid"};
+
/* -------------------------------------------------------------------- */
/** \name Fluid API
* \{ */
@@ -333,11 +338,19 @@ void BKE_fluid_reallocate_copy_fluid(FluidDomainSettings *mds,
manta_free(fluid_old);
}
+void BKE_fluid_cache_free_all(FluidDomainSettings *mds, Object *ob)
+{
+ int cache_map = (FLUID_DOMAIN_OUTDATED_DATA | FLUID_DOMAIN_OUTDATED_NOISE |
+ FLUID_DOMAIN_OUTDATED_MESH | FLUID_DOMAIN_OUTDATED_PARTICLES |
+ FLUID_DOMAIN_OUTDATED_GUIDE);
+ BKE_fluid_cache_free(mds, ob, cache_map);
+}
+
void BKE_fluid_cache_free(FluidDomainSettings *mds, Object *ob, int cache_map)
{
char temp_dir[FILE_MAX];
int flags = mds->cache_flag;
- const char *relbase = modifier_path_relbase_from_global(ob);
+ const char *relbase = BKE_modifier_path_relbase_from_global(ob);
if (cache_map & FLUID_DOMAIN_OUTDATED_DATA) {
flags &= ~(FLUID_DOMAIN_BAKING_DATA | FLUID_DOMAIN_BAKED_DATA | FLUID_DOMAIN_OUTDATED_DATA);
@@ -478,27 +491,6 @@ static void manta_set_domain_from_mesh(FluidDomainSettings *mds,
mds->cell_size[2] /= (float)mds->base_res[2];
}
-static void manta_set_domain_gravity(Scene *scene, FluidDomainSettings *mds)
-{
- float gravity[3] = {0.0f, 0.0f, -1.0f};
- float gravity_mag;
-
- /* Use global gravity if enabled. */
- if (scene->physics_settings.flag & PHYS_GLOBAL_GRAVITY) {
- copy_v3_v3(gravity, scene->physics_settings.gravity);
- /* Map default value to 1.0. */
- mul_v3_fl(gravity, 1.0f / 9.810f);
-
- /* Convert gravity to domain space. */
- gravity_mag = len_v3(gravity);
- mul_mat3_m4_v3(mds->imat, gravity);
- normalize_v3(gravity);
- mul_v3_fl(gravity, gravity_mag);
-
- copy_v3_v3(mds->gravity, gravity);
- }
-}
-
static bool BKE_fluid_modifier_init(
FluidModifierData *mmd, Depsgraph *depsgraph, Object *ob, Scene *scene, Mesh *me)
{
@@ -509,8 +501,11 @@ static bool BKE_fluid_modifier_init(
int res[3];
/* Set domain dimensions from mesh. */
manta_set_domain_from_mesh(mds, ob, me, true);
- /* Set domain gravity. */
- manta_set_domain_gravity(scene, mds);
+ /* Set domain gravity, use global gravity if enabled. */
+ if (scene->physics_settings.flag & PHYS_GLOBAL_GRAVITY) {
+ copy_v3_v3(mds->gravity, scene->physics_settings.gravity);
+ }
+ mul_v3_fl(mds->gravity, mds->effector_weights->global_gravity);
/* Reset domain values. */
zero_v3_int(mds->shift);
zero_v3(mds->shift_f);
@@ -538,7 +533,6 @@ static bool BKE_fluid_modifier_init(
/* Initially dt is equal to frame length (dt can change with adaptive-time stepping though). */
mds->dt = mds->frame_length;
mds->time_per_frame = 0;
- mds->time_total = abs(scene_framenr - mds->cache_frame_start) * mds->frame_length;
mmd->time = scene_framenr;
@@ -642,6 +636,11 @@ static bool is_static_object(Object *ob)
}
}
+ /* Active rigid body objects considered to be dynamic fluid objects. */
+ if (ob->rigidbody_object && ob->rigidbody_object->type == RBO_TYPE_ACTIVE) {
+ return false;
+ }
+
/* Finally, check if the object has animation data. If so, it is considered dynamic. */
return !BKE_object_moves_in_time(ob, true);
}
@@ -770,7 +769,9 @@ static void bb_combineMaps(FluidObjectBB *output,
/* Values. */
output->numobjs[index_out] = bb1.numobjs[index_in];
- output->influence[index_out] = bb1.influence[index_in];
+ if (output->influence && bb1.influence) {
+ output->influence[index_out] = bb1.influence[index_in];
+ }
output->distances[index_out] = bb1.distances[index_in];
if (output->velocity && bb1.velocity) {
copy_v3_v3(&output->velocity[index_out * 3], &bb1.velocity[index_in * 3]);
@@ -785,12 +786,14 @@ static void bb_combineMaps(FluidObjectBB *output,
/* Values. */
output->numobjs[index_out] = MAX2(bb2->numobjs[index_in], output->numobjs[index_out]);
- if (additive) {
- output->influence[index_out] += bb2->influence[index_in] * sample_size;
- }
- else {
- output->influence[index_out] = MAX2(bb2->influence[index_in],
- output->influence[index_out]);
+ if (output->influence && bb2->influence) {
+ if (additive) {
+ output->influence[index_out] += bb2->influence[index_in] * sample_size;
+ }
+ else {
+ output->influence[index_out] = MAX2(bb2->influence[index_in],
+ output->influence[index_out]);
+ }
}
output->distances[index_out] = MIN2(bb2->distances[index_in],
output->distances[index_out]);
@@ -925,11 +928,7 @@ static void sample_effector(FluidEffectorSettings *mes,
velocity_map[index * 3 + 2] += hit_vel[2];
# ifdef DEBUG_PRINT
/* Debugging: Print object velocities. */
- printf("adding effector object vel: [%f, %f, %f], dx is: %f\n",
- hit_vel[0],
- hit_vel[1],
- hit_vel[2],
- mds->dx);
+ printf("adding effector object vel: [%f, %f, %f]\n", hit_vel[0], hit_vel[1], hit_vel[2]);
# endif
}
}
@@ -1118,6 +1117,16 @@ static void obstacles_from_mesh(Object *coll_ob,
}
}
+static void ensure_obstaclefields(FluidDomainSettings *mds)
+{
+ if (mds->active_fields & FLUID_DOMAIN_ACTIVE_OBSTACLE) {
+ manta_ensure_obstacle(mds->fluid, mds->mmd);
+ }
+ if (mds->active_fields & FLUID_DOMAIN_ACTIVE_GUIDE) {
+ manta_ensure_guiding(mds->fluid, mds->mmd);
+ }
+}
+
static void update_obstacleflags(FluidDomainSettings *mds,
Object **coll_ob_array,
int coll_ob_array_len)
@@ -1132,8 +1141,8 @@ static void update_obstacleflags(FluidDomainSettings *mds,
/* Monitor active fields based on flow settings */
for (coll_index = 0; coll_index < coll_ob_array_len; coll_index++) {
Object *coll_ob = coll_ob_array[coll_index];
- FluidModifierData *mmd2 = (FluidModifierData *)modifiers_findByType(coll_ob,
- eModifierType_Fluid);
+ FluidModifierData *mmd2 = (FluidModifierData *)BKE_modifiers_findby_type(coll_ob,
+ eModifierType_Fluid);
/* Sanity check. */
if (!mmd2) {
@@ -1145,6 +1154,10 @@ static void update_obstacleflags(FluidDomainSettings *mds,
if (!mes) {
break;
}
+ if (mes->flags & FLUID_EFFECTOR_NEEDS_UPDATE) {
+ mes->flags &= ~FLUID_EFFECTOR_NEEDS_UPDATE;
+ mds->cache_flag |= FLUID_DOMAIN_OUTDATED_DATA;
+ }
if (mes->type == FLUID_EFFECTOR_TYPE_COLLISION) {
active_fields |= FLUID_DOMAIN_ACTIVE_OBSTACLE;
}
@@ -1153,44 +1166,56 @@ static void update_obstacleflags(FluidDomainSettings *mds,
}
}
}
- /* Finally, initialize new data fields if any */
- if (active_fields & FLUID_DOMAIN_ACTIVE_OBSTACLE) {
- manta_ensure_obstacle(mds->fluid, mds->mmd);
- }
- if (active_fields & FLUID_DOMAIN_ACTIVE_GUIDE) {
- manta_ensure_guiding(mds->fluid, mds->mmd);
- }
mds->active_fields = active_fields;
}
-static void update_obstacles(Depsgraph *depsgraph,
- Scene *scene,
- Object *ob,
- FluidDomainSettings *mds,
- float time_per_frame,
- float frame_length,
- int frame,
- float dt)
+static bool escape_effectorobject(Object *flowobj,
+ FluidDomainSettings *mds,
+ FluidEffectorSettings *mes,
+ int frame)
{
- FluidObjectBB *bb_maps = NULL;
- Object **effecobjs = NULL;
- uint numeffecobjs = 0, effec_index = 0;
- bool is_first_frame = (frame == mds->cache_frame_start);
+ bool is_static = is_static_object(flowobj);
- effecobjs = BKE_collision_objects_create(
- depsgraph, ob, mds->effector_group, &numeffecobjs, eModifierType_Fluid);
+ bool use_effector = (mes->flags & FLUID_EFFECTOR_USE_EFFEC);
- /* Update all effector related flags and ensure that corresponding grids get initialized. */
- update_obstacleflags(mds, effecobjs, numeffecobjs);
+ bool is_resume = (mds->cache_frame_pause_data == frame);
+ bool is_adaptive = (mds->flags & FLUID_DOMAIN_USE_ADAPTIVE_DOMAIN);
+ bool is_first_frame = (frame == mds->cache_frame_start);
- /* Initialize effector maps for each flow. */
- bb_maps = MEM_callocN(sizeof(struct FluidObjectBB) * numeffecobjs, "fluid_effector_bb_maps");
+ /* Cannot use static mode with adaptive domain.
+ * The adaptive domain might expand and only later discover the static object. */
+ if (is_adaptive) {
+ is_static = false;
+ }
+ /* Skip flow objects with disabled inflow flag. */
+ if (!use_effector) {
+ return true;
+ }
+ /* Skip static effector objects after initial frame. */
+ if (is_static && !is_first_frame && !is_resume) {
+ return true;
+ }
+ return false;
+}
+
+static void compute_obstaclesemission(Scene *scene,
+ FluidObjectBB *bb_maps,
+ struct Depsgraph *depsgraph,
+ float dt,
+ Object **effecobjs,
+ int frame,
+ float frame_length,
+ FluidDomainSettings *mds,
+ uint numeffecobjs,
+ float time_per_frame)
+{
+ bool is_first_frame = (frame == mds->cache_frame_start);
/* Prepare effector maps. */
- for (effec_index = 0; effec_index < numeffecobjs; effec_index++) {
+ for (int effec_index = 0; effec_index < numeffecobjs; effec_index++) {
Object *effecobj = effecobjs[effec_index];
- FluidModifierData *mmd2 = (FluidModifierData *)modifiers_findByType(effecobj,
- eModifierType_Fluid);
+ FluidModifierData *mmd2 = (FluidModifierData *)BKE_modifiers_findby_type(effecobj,
+ eModifierType_Fluid);
/* Sanity check. */
if (!mmd2) {
@@ -1203,69 +1228,37 @@ static void update_obstacles(Depsgraph *depsgraph,
int subframes = mes->subframes;
FluidObjectBB *bb = &bb_maps[effec_index];
- bool is_static = is_static_object(effecobj);
- /* Cannot use static mode with adaptive domain.
- * The adaptive domain might expand and only later in the simulations discover the static
- * object. */
- if (mds->flags & FLUID_DOMAIN_USE_ADAPTIVE_DOMAIN) {
- is_static = false;
- }
-
- /* Optimization: Static objects don't need emission computation after first frame. */
- if (is_static && !is_first_frame) {
- continue;
- }
- /* Optimization: Skip effector objects with disabled effec flag. */
- if ((mes->flags & FLUID_EFFECTOR_USE_EFFEC) == 0) {
+ /* Optimization: Skip this object under certain conditions. */
+ if (escape_effectorobject(effecobj, mds, mes, frame)) {
continue;
}
- /* Length of one adaptive frame. If using adaptive stepping, length is smaller than actual
- * frame length */
- float adaptframe_length = time_per_frame / frame_length;
- /* Adaptive frame length as percentage */
- CLAMP(adaptframe_length, 0.0f, 1.0f);
-
- /* More splitting because of emission subframe: If no subframes present, sample_size is 1. */
- float sample_size = 1.0f / (float)(subframes + 1);
-
/* First frame cannot have any subframes because there is (obviously) no previous frame from
* where subframes could come from. */
if (is_first_frame) {
subframes = 0;
}
- int subframe;
+ /* More splitting because of emission subframe: If no subframes present, sample_size is 1. */
+ float sample_size = 1.0f / (float)(subframes + 1);
float subframe_dt = dt * sample_size;
/* Emission loop. When not using subframes this will loop only once. */
- for (subframe = subframes; subframe >= 0; subframe--) {
+ for (int subframe = 0; subframe <= subframes; subframe++) {
/* Temporary emission map used when subframes are enabled, i.e. at least one subframe. */
FluidObjectBB bb_temp = {NULL};
/* Set scene time */
/* Handle emission subframe */
- if (subframe > 0 && !is_first_frame) {
- scene->r.subframe = adaptframe_length -
- sample_size * (float)(subframe) * (dt / frame_length);
+ if ((subframe < subframes || time_per_frame + dt + FLT_EPSILON < frame_length) &&
+ !is_first_frame) {
+ scene->r.subframe = (time_per_frame + (subframe + 1.0f) * subframe_dt) / frame_length;
scene->r.cfra = frame - 1;
}
- /* Last frame in this loop (subframe == suframes). Can be real end frame or in between
- * frames (adaptive frame). */
else {
- /* Handle adaptive subframe (ie has subframe fraction). Need to set according scene
- * subframe parameter. */
- if (time_per_frame < frame_length) {
- scene->r.subframe = adaptframe_length;
- scene->r.cfra = frame - 1;
- }
- /* Handle absolute endframe (ie no subframe fraction). Need to set the scene subframe
- * parameter to 0 and advance current scene frame. */
- else {
- scene->r.subframe = 0.0f;
- scene->r.cfra = frame;
- }
+ scene->r.subframe = 0.0f;
+ scene->r.cfra = frame;
}
/* Sanity check: subframe portion must be between 0 and 1. */
CLAMP(scene->r.subframe, 0.0f, 1.0f);
@@ -1304,6 +1297,44 @@ static void update_obstacles(Depsgraph *depsgraph,
}
}
}
+}
+
+static void update_obstacles(Depsgraph *depsgraph,
+ Scene *scene,
+ Object *ob,
+ FluidDomainSettings *mds,
+ float time_per_frame,
+ float frame_length,
+ int frame,
+ float dt)
+{
+ FluidObjectBB *bb_maps = NULL;
+ Object **effecobjs = NULL;
+ uint numeffecobjs = 0;
+ bool is_resume = (mds->cache_frame_pause_data == frame);
+ bool is_first_frame = (frame == mds->cache_frame_start);
+
+ effecobjs = BKE_collision_objects_create(
+ depsgraph, ob, mds->effector_group, &numeffecobjs, eModifierType_Fluid);
+
+ /* Update all effector related flags and ensure that corresponding grids get initialized. */
+ update_obstacleflags(mds, effecobjs, numeffecobjs);
+ ensure_obstaclefields(mds);
+
+ /* Allocate effector map for each effector object. */
+ bb_maps = MEM_callocN(sizeof(struct FluidObjectBB) * numeffecobjs, "fluid_effector_bb_maps");
+
+ /* Initialize effector map for each effector object. */
+ compute_obstaclesemission(scene,
+ bb_maps,
+ depsgraph,
+ dt,
+ effecobjs,
+ frame,
+ frame_length,
+ mds,
+ numeffecobjs,
+ time_per_frame);
float *vel_x = manta_get_ob_velocity_x(mds->fluid);
float *vel_y = manta_get_ob_velocity_y(mds->fluid);
@@ -1354,28 +1385,21 @@ static void update_obstacles(Depsgraph *depsgraph,
}
/* Prepare grids from effector objects. */
- for (effec_index = 0; effec_index < numeffecobjs; effec_index++) {
+ for (int effec_index = 0; effec_index < numeffecobjs; effec_index++) {
Object *effecobj = effecobjs[effec_index];
- FluidModifierData *mmd2 = (FluidModifierData *)modifiers_findByType(effecobj,
- eModifierType_Fluid);
+ FluidModifierData *mmd2 = (FluidModifierData *)BKE_modifiers_findby_type(effecobj,
+ eModifierType_Fluid);
/* Sanity check. */
if (!mmd2) {
continue;
}
- bool is_static = is_static_object(effecobj);
/* Cannot use static mode with adaptive domain.
* The adaptive domain might expand and only later in the simulations discover the static
* object. */
- if (mds->flags & FLUID_DOMAIN_USE_ADAPTIVE_DOMAIN) {
- is_static = false;
- }
-
- /* Optimization: Static objects don't need emission application after first frame. */
- if (is_static && !is_first_frame) {
- continue;
- }
+ bool is_static = is_static_object(effecobj) &&
+ ((mds->flags & FLUID_DOMAIN_USE_ADAPTIVE_DOMAIN) == 0);
/* Check for initialized effector object. */
if ((mmd2->type & MOD_FLUID_TYPE_EFFEC) && mmd2->effector) {
@@ -1415,53 +1439,35 @@ static void update_obstacles(Depsgraph *depsgraph,
continue;
}
- /* Apply static effectors to obstacle grid. */
- if (is_static && is_first_frame) {
- if (mes->type == FLUID_EFFECTOR_TYPE_COLLISION) {
- apply_effector_fields(mes,
- d_index,
- distance_map[e_index],
- phi_obsstatic_in,
- numobjs_map[e_index],
- num_obstacles,
- 0.0f,
- NULL,
- 0.0f,
- NULL,
- 0.0f,
- NULL);
- }
+ if (mes->type == FLUID_EFFECTOR_TYPE_COLLISION) {
+ float *levelset = ((is_first_frame || is_resume) && is_static) ? phi_obsstatic_in :
+ phi_obs_in;
+ apply_effector_fields(mes,
+ d_index,
+ distance_map[e_index],
+ levelset,
+ numobjs_map[e_index],
+ num_obstacles,
+ velocity_map[e_index * 3],
+ vel_x,
+ velocity_map[e_index * 3 + 1],
+ vel_y,
+ velocity_map[e_index * 3 + 2],
+ vel_z);
}
- /* Apply moving effectors to obstacle grid. */
- else if (!is_static) {
- if (mes->type == FLUID_EFFECTOR_TYPE_COLLISION) {
- apply_effector_fields(mes,
- d_index,
- distance_map[e_index],
- phi_obs_in,
- numobjs_map[e_index],
- num_obstacles,
- velocity_map[e_index * 3],
- vel_x,
- velocity_map[e_index * 3 + 1],
- vel_y,
- velocity_map[e_index * 3 + 2],
- vel_z);
- }
- if (mes->type == FLUID_EFFECTOR_TYPE_GUIDE) {
- apply_effector_fields(mes,
- d_index,
- distance_map[e_index],
- phi_guide_in,
- numobjs_map[e_index],
- num_guides,
- velocity_map[e_index * 3],
- vel_x_guide,
- velocity_map[e_index * 3 + 1],
- vel_y_guide,
- velocity_map[e_index * 3 + 2],
- vel_z_guide);
- }
+ if (mes->type == FLUID_EFFECTOR_TYPE_GUIDE) {
+ apply_effector_fields(mes,
+ d_index,
+ distance_map[e_index],
+ phi_guide_in,
+ numobjs_map[e_index],
+ num_guides,
+ velocity_map[e_index * 3],
+ vel_x_guide,
+ velocity_map[e_index * 3 + 1],
+ vel_y_guide,
+ velocity_map[e_index * 3 + 2],
+ vel_z_guide);
}
}
}
@@ -1966,9 +1972,9 @@ static void sample_mesh(FluidFlowSettings *mfs,
normalize_v3(hit_normal);
/* Apply normal directional velocity. */
- velocity_map[index * 3] += hit_normal[0] * mfs->vel_normal * 0.25f;
- velocity_map[index * 3 + 1] += hit_normal[1] * mfs->vel_normal * 0.25f;
- velocity_map[index * 3 + 2] += hit_normal[2] * mfs->vel_normal * 0.25f;
+ velocity_map[index * 3] += hit_normal[0] * mfs->vel_normal;
+ velocity_map[index * 3 + 1] += hit_normal[1] * mfs->vel_normal;
+ velocity_map[index * 3 + 2] += hit_normal[2] * mfs->vel_normal;
}
/* Apply object velocity. */
if (has_velocity && mfs->vel_multi) {
@@ -2458,12 +2464,13 @@ BLI_INLINE void apply_outflow_fields(int index,
float *color_b,
float *phiout)
{
- /* determine outflow cells - phiout used in smoke and liquids */
+ /* Set levelset value for liquid inflow.
+ * Ensure that distance value is "joined" into the levelset. */
if (phiout) {
- phiout[index] = distance_value;
+ phiout[index] = MIN2(distance_value, phiout[index]);
}
- /* set smoke outflow */
+ /* Set smoke outflow, i.e. reset cell to zero. */
if (density) {
density[index] = 0.0f;
}
@@ -2581,6 +2588,32 @@ BLI_INLINE void apply_inflow_fields(FluidFlowSettings *mfs,
}
}
+static void ensure_flowsfields(FluidDomainSettings *mds)
+{
+ if (mds->active_fields & FLUID_DOMAIN_ACTIVE_INVEL) {
+ manta_ensure_invelocity(mds->fluid, mds->mmd);
+ }
+ if (mds->active_fields & FLUID_DOMAIN_ACTIVE_OUTFLOW) {
+ manta_ensure_outflow(mds->fluid, mds->mmd);
+ }
+ if (mds->active_fields & FLUID_DOMAIN_ACTIVE_HEAT) {
+ manta_smoke_ensure_heat(mds->fluid, mds->mmd);
+ }
+ if (mds->active_fields & FLUID_DOMAIN_ACTIVE_FIRE) {
+ manta_smoke_ensure_fire(mds->fluid, mds->mmd);
+ }
+ if (mds->active_fields & FLUID_DOMAIN_ACTIVE_COLORS) {
+ /* initialize all smoke with "active_color" */
+ manta_smoke_ensure_colors(mds->fluid, mds->mmd);
+ }
+ if (mds->type == FLUID_DOMAIN_TYPE_LIQUID &&
+ (mds->particle_type & FLUID_DOMAIN_PARTICLE_SPRAY ||
+ mds->particle_type & FLUID_DOMAIN_PARTICLE_FOAM ||
+ mds->particle_type & FLUID_DOMAIN_PARTICLE_TRACER)) {
+ manta_liquid_ensure_sndparts(mds->fluid, mds->mmd);
+ }
+}
+
static void update_flowsflags(FluidDomainSettings *mds, Object **flowobjs, int numflowobj)
{
int active_fields = mds->active_fields;
@@ -2588,15 +2621,14 @@ static void update_flowsflags(FluidDomainSettings *mds, Object **flowobjs, int n
/* First, remove all flags that we want to update. */
int prev_flags = (FLUID_DOMAIN_ACTIVE_INVEL | FLUID_DOMAIN_ACTIVE_OUTFLOW |
- FLUID_DOMAIN_ACTIVE_HEAT | FLUID_DOMAIN_ACTIVE_FIRE |
- FLUID_DOMAIN_ACTIVE_COLOR_SET | FLUID_DOMAIN_ACTIVE_COLORS);
+ FLUID_DOMAIN_ACTIVE_HEAT | FLUID_DOMAIN_ACTIVE_FIRE);
active_fields &= ~prev_flags;
/* Monitor active fields based on flow settings */
for (flow_index = 0; flow_index < numflowobj; flow_index++) {
- Object *coll_ob = flowobjs[flow_index];
- FluidModifierData *mmd2 = (FluidModifierData *)modifiers_findByType(coll_ob,
- eModifierType_Fluid);
+ Object *flow_ob = flowobjs[flow_index];
+ FluidModifierData *mmd2 = (FluidModifierData *)BKE_modifiers_findby_type(flow_ob,
+ eModifierType_Fluid);
/* Sanity check. */
if (!mmd2) {
@@ -2608,6 +2640,10 @@ static void update_flowsflags(FluidDomainSettings *mds, Object **flowobjs, int n
if (!mfs) {
break;
}
+ if (mfs->flags & FLUID_FLOW_NEEDS_UPDATE) {
+ mfs->flags &= ~FLUID_FLOW_NEEDS_UPDATE;
+ mds->cache_flag |= FLUID_DOMAIN_OUTDATED_DATA;
+ }
if (mfs->flags & FLUID_FLOW_INITVELOCITY) {
active_fields |= FLUID_DOMAIN_ACTIVE_INVEL;
}
@@ -2656,60 +2692,74 @@ static void update_flowsflags(FluidDomainSettings *mds, Object **flowobjs, int n
active_fields |= FLUID_DOMAIN_ACTIVE_COLORS;
}
}
- /* Finally, initialize new data fields if any */
- if (active_fields & FLUID_DOMAIN_ACTIVE_INVEL) {
- manta_ensure_invelocity(mds->fluid, mds->mmd);
- }
- if (active_fields & FLUID_DOMAIN_ACTIVE_OUTFLOW) {
- manta_ensure_outflow(mds->fluid, mds->mmd);
- }
- if (active_fields & FLUID_DOMAIN_ACTIVE_HEAT) {
- manta_smoke_ensure_heat(mds->fluid, mds->mmd);
+ mds->active_fields = active_fields;
+}
+
+static bool escape_flowsobject(Object *flowobj,
+ FluidDomainSettings *mds,
+ FluidFlowSettings *mfs,
+ int frame)
+{
+ bool use_velocity = (mfs->flags & FLUID_FLOW_INITVELOCITY);
+ bool is_static = is_static_object(flowobj);
+
+ bool liquid_flow = mfs->type == FLUID_FLOW_TYPE_LIQUID;
+ bool gas_flow = (mfs->type == FLUID_FLOW_TYPE_SMOKE || mfs->type == FLUID_FLOW_TYPE_FIRE ||
+ mfs->type == FLUID_FLOW_TYPE_SMOKEFIRE);
+ bool is_geometry = (mfs->behavior == FLUID_FLOW_BEHAVIOR_GEOMETRY);
+ bool is_inflow = (mfs->behavior == FLUID_FLOW_BEHAVIOR_INFLOW);
+ bool is_outflow = (mfs->behavior == FLUID_FLOW_BEHAVIOR_OUTFLOW);
+ bool use_flow = (mfs->flags & FLUID_FLOW_USE_INFLOW);
+
+ bool liquid_domain = mds->type == FLUID_DOMAIN_TYPE_LIQUID;
+ bool gas_domain = mds->type == FLUID_DOMAIN_TYPE_GAS;
+ bool is_adaptive = (mds->flags & FLUID_DOMAIN_USE_ADAPTIVE_DOMAIN);
+ bool is_resume = (mds->cache_frame_pause_data == frame);
+ bool is_first_frame = (mds->cache_frame_start == frame);
+
+ /* Cannot use static mode with adaptive domain.
+ * The adaptive domain might expand and only later discover the static object. */
+ if (is_adaptive) {
+ is_static = false;
+ }
+ /* Skip flow objects with disabled inflow flag. */
+ if ((is_inflow || is_outflow) && !use_flow) {
+ return true;
}
- if (active_fields & FLUID_DOMAIN_ACTIVE_FIRE) {
- manta_smoke_ensure_fire(mds->fluid, mds->mmd);
+ /* No need to compute emission value if it won't be applied. */
+ if (liquid_flow && is_geometry && !is_first_frame) {
+ return true;
}
- if (active_fields & FLUID_DOMAIN_ACTIVE_COLORS) {
- /* initialize all smoke with "active_color" */
- manta_smoke_ensure_colors(mds->fluid, mds->mmd);
+ /* Skip flow object if it does not "belong" to this domain type. */
+ if ((liquid_flow && gas_domain) || (gas_flow && liquid_domain)) {
+ return true;
}
- if (mds->type == FLUID_DOMAIN_TYPE_LIQUID &&
- (mds->particle_type & FLUID_DOMAIN_PARTICLE_SPRAY ||
- mds->particle_type & FLUID_DOMAIN_PARTICLE_FOAM ||
- mds->particle_type & FLUID_DOMAIN_PARTICLE_TRACER)) {
- manta_liquid_ensure_sndparts(mds->fluid, mds->mmd);
+ /* Optimization: Static liquid flow objects don't need emission after first frame.
+ * TODO (sebbas): Also do not use static mode if initial velocities are enabled. */
+ if (liquid_flow && is_static && !is_first_frame && !is_resume && !use_velocity) {
+ return true;
}
- mds->active_fields = active_fields;
+ return false;
}
-static void update_flowsfluids(struct Depsgraph *depsgraph,
- Scene *scene,
- Object *ob,
- FluidDomainSettings *mds,
- float time_per_frame,
- float frame_length,
- int frame,
- float dt)
+static void compute_flowsemission(Scene *scene,
+ FluidObjectBB *bb_maps,
+ struct Depsgraph *depsgraph,
+ float dt,
+ Object **flowobjs,
+ int frame,
+ float frame_length,
+ FluidDomainSettings *mds,
+ uint numflowobjs,
+ float time_per_frame)
{
- FluidObjectBB *bb_maps = NULL;
- Object **flowobjs = NULL;
- uint numflowobj = 0, flow_index = 0;
bool is_first_frame = (frame == mds->cache_frame_start);
- flowobjs = BKE_collision_objects_create(
- depsgraph, ob, mds->fluid_group, &numflowobj, eModifierType_Fluid);
-
- /* Update all flow related flags and ensure that corresponding grids get initialized. */
- update_flowsflags(mds, flowobjs, numflowobj);
-
- /* Initialize emission maps for each flow. */
- bb_maps = MEM_callocN(sizeof(struct FluidObjectBB) * numflowobj, "fluid_flow_bb_maps");
-
/* Prepare flow emission maps. */
- for (flow_index = 0; flow_index < numflowobj; flow_index++) {
+ for (int flow_index = 0; flow_index < numflowobjs; flow_index++) {
Object *flowobj = flowobjs[flow_index];
- FluidModifierData *mmd2 = (FluidModifierData *)modifiers_findByType(flowobj,
- eModifierType_Fluid);
+ FluidModifierData *mmd2 = (FluidModifierData *)BKE_modifiers_findby_type(flowobj,
+ eModifierType_Fluid);
/* Sanity check. */
if (!mmd2) {
@@ -2722,48 +2772,10 @@ static void update_flowsfluids(struct Depsgraph *depsgraph,
int subframes = mfs->subframes;
FluidObjectBB *bb = &bb_maps[flow_index];
- bool use_velocity = mfs->flags & FLUID_FLOW_INITVELOCITY;
- bool is_static = is_static_object(flowobj);
- /* Cannot use static mode with adaptive domain.
- * The adaptive domain might expand and only later in the simulations discover the static
- * object. */
- if (mds->flags & FLUID_DOMAIN_USE_ADAPTIVE_DOMAIN) {
- is_static = false;
- }
-
- /* Optimization: Skip flow objects with disabled inflow flag. */
- if (mfs->behavior == FLUID_FLOW_BEHAVIOR_INFLOW &&
- (mfs->flags & FLUID_FLOW_USE_INFLOW) == 0) {
- continue;
- }
- /* Optimization: No need to compute emission value if it won't be applied. */
- if (mfs->behavior == FLUID_FLOW_BEHAVIOR_GEOMETRY && !is_first_frame) {
- continue;
- }
- /* Optimization: Skip flow object if it does not "belong" to this domain type. */
- if (mfs->type == FLUID_FLOW_TYPE_LIQUID && mds->type == FLUID_DOMAIN_TYPE_GAS) {
- continue;
- }
- if ((mfs->type == FLUID_FLOW_TYPE_SMOKE || mfs->type == FLUID_FLOW_TYPE_FIRE ||
- mfs->type == FLUID_FLOW_TYPE_SMOKEFIRE) &&
- mds->type == FLUID_DOMAIN_TYPE_LIQUID) {
+ /* Optimization: Skip this object under certain conditions. */
+ if (escape_flowsobject(flowobj, mds, mfs, frame)) {
continue;
}
- /* Optimization: Static liquid flow objects don't need emission computation after first
- * frame.
- * TODO (sebbas): Also do not use static mode if initial velocities are enabled. */
- if (mfs->type == FLUID_FLOW_TYPE_LIQUID && is_static && !is_first_frame && !use_velocity) {
- continue;
- }
-
- /* Length of one adaptive frame. If using adaptive stepping, length is smaller than actual
- * frame length */
- float adaptframe_length = time_per_frame / frame_length;
- /* Adaptive frame length as percentage */
- CLAMP(adaptframe_length, 0.0f, 1.0f);
-
- /* More splitting because of emission subframe: If no subframes present, sample_size is 1. */
- float sample_size = 1.0f / (float)(subframes + 1);
/* First frame cannot have any subframes because there is (obviously) no previous frame from
* where subframes could come from. */
@@ -2771,38 +2783,26 @@ static void update_flowsfluids(struct Depsgraph *depsgraph,
subframes = 0;
}
- int subframe;
+ /* More splitting because of emission subframe: If no subframes present, sample_size is 1. */
+ float sample_size = 1.0f / (float)(subframes + 1);
float subframe_dt = dt * sample_size;
/* Emission loop. When not using subframes this will loop only once. */
- for (subframe = subframes; subframe >= 0; subframe--) {
-
+ for (int subframe = 0; subframe <= subframes; subframe++) {
/* Temporary emission map used when subframes are enabled, i.e. at least one subframe. */
FluidObjectBB bb_temp = {NULL};
/* Set scene time */
- /* Handle emission subframe */
- if (subframe > 0 && !is_first_frame) {
- scene->r.subframe = adaptframe_length -
- sample_size * (float)(subframe) * (dt / frame_length);
+ if ((subframe < subframes || time_per_frame + dt + FLT_EPSILON < frame_length) &&
+ !is_first_frame) {
+ scene->r.subframe = (time_per_frame + (subframe + 1.0f) * subframe_dt) / frame_length;
scene->r.cfra = frame - 1;
}
- /* Last frame in this loop (subframe == suframes). Can be real end frame or in between
- * frames (adaptive frame). */
else {
- /* Handle adaptive subframe (ie has subframe fraction). Need to set according scene
- * subframe parameter. */
- if (time_per_frame < frame_length) {
- scene->r.subframe = adaptframe_length;
- scene->r.cfra = frame - 1;
- }
- /* Handle absolute endframe (ie no subframe fraction). Need to set the scene subframe
- * parameter to 0 and advance current scene frame. */
- else {
- scene->r.subframe = 0.0f;
- scene->r.cfra = frame;
- }
+ scene->r.subframe = 0.0f;
+ scene->r.cfra = frame;
}
+
/* Sanity check: subframe portion must be between 0 and 1. */
CLAMP(scene->r.subframe, 0.0f, 1.0f);
# ifdef DEBUG_PRINT
@@ -2862,15 +2862,55 @@ static void update_flowsfluids(struct Depsgraph *depsgraph,
frame_length,
dt);
# endif
+}
+
+static void update_flowsfluids(struct Depsgraph *depsgraph,
+ Scene *scene,
+ Object *ob,
+ FluidDomainSettings *mds,
+ float time_per_frame,
+ float frame_length,
+ int frame,
+ float dt)
+{
+ FluidObjectBB *bb_maps = NULL;
+ Object **flowobjs = NULL;
+ uint numflowobjs = 0;
+ bool is_resume = (mds->cache_frame_pause_data == frame);
+ bool is_first_frame = (mds->cache_frame_start == frame);
+
+ flowobjs = BKE_collision_objects_create(
+ depsgraph, ob, mds->fluid_group, &numflowobjs, eModifierType_Fluid);
+
+ /* Update all flow related flags and ensure that corresponding grids get initialized. */
+ update_flowsflags(mds, flowobjs, numflowobjs);
+ ensure_flowsfields(mds);
+
+ /* Allocate emission map for each flow object. */
+ bb_maps = MEM_callocN(sizeof(struct FluidObjectBB) * numflowobjs, "fluid_flow_bb_maps");
+
+ /* Initialize emission map for each flow object. */
+ compute_flowsemission(scene,
+ bb_maps,
+ depsgraph,
+ dt,
+ flowobjs,
+ frame,
+ frame_length,
+ mds,
+ numflowobjs,
+ time_per_frame);
/* Adjust domain size if needed. Only do this once for every frame. */
if (mds->type == FLUID_DOMAIN_TYPE_GAS && mds->flags & FLUID_DOMAIN_USE_ADAPTIVE_DOMAIN) {
- adaptive_domain_adjust(mds, ob, bb_maps, numflowobj, dt);
+ adaptive_domain_adjust(mds, ob, bb_maps, numflowobjs, dt);
}
float *phi_in = manta_get_phi_in(mds->fluid);
float *phistatic_in = manta_get_phistatic_in(mds->fluid);
float *phiout_in = manta_get_phiout_in(mds->fluid);
+ float *phioutstatic_in = manta_get_phioutstatic_in(mds->fluid);
+
float *density = manta_smoke_get_density(mds->fluid);
float *color_r = manta_smoke_get_color_r(mds->fluid);
float *color_g = manta_smoke_get_color_g(mds->fluid);
@@ -2893,16 +2933,18 @@ static void update_flowsfluids(struct Depsgraph *depsgraph,
float *velz_initial = manta_get_in_velocity_z(mds->fluid);
uint z;
- bool use_adaptivedomain = (mds->flags & FLUID_DOMAIN_USE_ADAPTIVE_DOMAIN);
-
/* Grid reset before writing again. */
for (z = 0; z < mds->res[0] * mds->res[1] * mds->res[2]; z++) {
+ /* Only reset static phi on first frame, dynamic phi gets reset every time. */
+ if (phistatic_in && is_first_frame) {
+ phistatic_in[z] = PHI_MAX;
+ }
if (phi_in) {
phi_in[z] = PHI_MAX;
}
- /* Only reset static inflow on first frame. Only use static inflow without adaptive domains. */
- if (phistatic_in && (is_first_frame || use_adaptivedomain)) {
- phistatic_in[z] = PHI_MAX;
+ /* Only reset static phi on first frame, dynamic phi gets reset every time. */
+ if (phioutstatic_in && is_first_frame) {
+ phioutstatic_in[z] = PHI_MAX;
}
if (phiout_in) {
phiout_in[z] = PHI_MAX;
@@ -2934,10 +2976,10 @@ static void update_flowsfluids(struct Depsgraph *depsgraph,
}
/* Apply emission data for every flow object. */
- for (flow_index = 0; flow_index < numflowobj; flow_index++) {
+ for (int flow_index = 0; flow_index < numflowobjs; flow_index++) {
Object *flowobj = flowobjs[flow_index];
- FluidModifierData *mmd2 = (FluidModifierData *)modifiers_findByType(flowobj,
- eModifierType_Fluid);
+ FluidModifierData *mmd2 = (FluidModifierData *)BKE_modifiers_findby_type(flowobj,
+ eModifierType_Fluid);
/* Sanity check. */
if (!mmd2) {
@@ -2948,38 +2990,11 @@ static void update_flowsfluids(struct Depsgraph *depsgraph,
if ((mmd2->type & MOD_FLUID_TYPE_FLOW) && mmd2->flow) {
FluidFlowSettings *mfs = mmd2->flow;
- bool use_velocity = mfs->flags & FLUID_FLOW_INITVELOCITY;
- bool use_inflow = (mfs->flags & FLUID_FLOW_USE_INFLOW);
- bool is_liquid = (mfs->type == FLUID_FLOW_TYPE_LIQUID);
bool is_inflow = (mfs->behavior == FLUID_FLOW_BEHAVIOR_INFLOW);
bool is_geometry = (mfs->behavior == FLUID_FLOW_BEHAVIOR_GEOMETRY);
bool is_outflow = (mfs->behavior == FLUID_FLOW_BEHAVIOR_OUTFLOW);
-
- bool is_static = is_static_object(flowobj);
- /* Cannot use static mode with adaptive domain.
- * The adaptive domain might expand and only later in the simulations discover the static
- * object. */
- if (mds->flags & FLUID_DOMAIN_USE_ADAPTIVE_DOMAIN) {
- is_static = false;
- }
-
- /* Optimization: Skip flow objects with disabled flow flag. */
- if (is_inflow && !use_inflow) {
- continue;
- }
- /* Optimization: Liquid objects don't always need emission application after first frame. */
- if (is_liquid && !is_first_frame) {
-
- /* Skip static liquid objects that are not on the first frame.
- * TODO (sebbas): Also do not use static mode if initial velocities are enabled. */
- if (is_static && !use_velocity) {
- continue;
- }
- /* Liquid geometry objects don't need emission application after first frame. */
- if (is_geometry) {
- continue;
- }
- }
+ bool is_static = is_static_object(flowobj) &&
+ ((mds->flags & FLUID_DOMAIN_USE_ADAPTIVE_DOMAIN) == 0);
FluidObjectBB *bb = &bb_maps[flow_index];
float *velocity_map = bb->velocity;
@@ -3012,6 +3027,8 @@ static void update_flowsfluids(struct Depsgraph *depsgraph,
/* Delete fluid in outflow regions. */
if (is_outflow) {
+ float *levelset = ((is_first_frame || is_resume) && is_static) ? phioutstatic_in :
+ phiout_in;
apply_outflow_fields(d_index,
distance_map[e_index],
density_in,
@@ -3021,7 +3038,7 @@ static void update_flowsfluids(struct Depsgraph *depsgraph,
color_r_in,
color_g_in,
color_b_in,
- phiout_in);
+ levelset);
}
/* Do not apply inflow after the first frame when in geometry mode. */
else if (is_geometry && !is_first_frame) {
@@ -3046,31 +3063,11 @@ static void update_flowsfluids(struct Depsgraph *depsgraph,
phi_in,
emission_in);
}
- /* Static liquid objects need inflow application onto static phi grid. */
- else if (is_inflow && is_liquid && is_static && is_first_frame) {
- apply_inflow_fields(mfs,
- 0.0f,
- distance_map[e_index],
- d_index,
- NULL,
- NULL,
- NULL,
- NULL,
- NULL,
- NULL,
- NULL,
- NULL,
- NULL,
- NULL,
- NULL,
- NULL,
- NULL,
- NULL,
- phistatic_in,
- NULL);
- }
/* Main inflow application. */
else if (is_geometry || is_inflow) {
+ float *levelset = ((is_first_frame || is_resume) && is_static && !is_geometry) ?
+ phistatic_in :
+ phi_in;
apply_inflow_fields(mfs,
emission_map[e_index],
distance_map[e_index],
@@ -3089,12 +3086,22 @@ static void update_flowsfluids(struct Depsgraph *depsgraph,
color_g,
color_b_in,
color_b,
- phi_in,
+ levelset,
emission_in);
if (mfs->flags & FLUID_FLOW_INITVELOCITY) {
- velx_initial[d_index] = velocity_map[e_index * 3];
- vely_initial[d_index] = velocity_map[e_index * 3 + 1];
- velz_initial[d_index] = velocity_map[e_index * 3 + 2];
+ /* Use the initial velocity from the inflow object with the highest velocity for
+ * now. */
+ float vel_initial[3];
+ vel_initial[0] = velx_initial[d_index];
+ vel_initial[1] = vely_initial[d_index];
+ vel_initial[2] = velz_initial[d_index];
+ float vel_initial_strength = len_squared_v3(vel_initial);
+ float vel_map_strength = len_squared_v3(velocity_map + 3 * e_index);
+ if (vel_map_strength > vel_initial_strength) {
+ velx_initial[d_index] = velocity_map[e_index * 3];
+ vely_initial[d_index] = velocity_map[e_index * 3 + 1];
+ velz_initial[d_index] = velocity_map[e_index * 3 + 2];
+ }
}
}
}
@@ -3189,7 +3196,7 @@ static void update_effectors(
{
ListBase *effectors;
/* make sure smoke flow influence is 0.0f */
- mds->effector_weights->weight[PFIELD_SMOKEFLOW] = 0.0f;
+ mds->effector_weights->weight[PFIELD_FLUIDFLOW] = 0.0f;
effectors = BKE_effectors_create(depsgraph, ob, NULL, mds->effector_weights);
if (effectors) {
@@ -3299,6 +3306,16 @@ static Mesh *create_liquid_geometry(FluidDomainSettings *mds, Mesh *orgmesh, Obj
/* Biggest dimension will be used for upscaling. */
float max_size = MAX3(size[0], size[1], size[2]);
+ float co_scale[3];
+ co_scale[0] = max_size / ob->scale[0];
+ co_scale[1] = max_size / ob->scale[1];
+ co_scale[2] = max_size / ob->scale[2];
+
+ float co_offset[3];
+ co_offset[0] = (mds->p0[0] + mds->p1[0]) / 2.0f;
+ co_offset[1] = (mds->p0[1] + mds->p1[1]) / 2.0f;
+ co_offset[2] = (mds->p0[2] + mds->p1[2]) / 2.0f;
+
/* Normals. */
normals = MEM_callocN(sizeof(short) * num_normals * 3, "Fluidmesh_tmp_normals");
@@ -3322,9 +3339,9 @@ static Mesh *create_liquid_geometry(FluidDomainSettings *mds, Mesh *orgmesh, Obj
mverts->co[2] *= mds->dx / mds->mesh_scale;
}
- mverts->co[0] *= max_size / fabsf(ob->scale[0]);
- mverts->co[1] *= max_size / fabsf(ob->scale[1]);
- mverts->co[2] *= max_size / fabsf(ob->scale[2]);
+ mul_v3_v3(mverts->co, co_scale);
+ add_v3_v3(mverts->co, co_offset);
+
# ifdef DEBUG_PRINT
/* Debugging: Print coordinates of vertices. */
printf("mverts->co[0]: %f, mverts->co[1]: %f, mverts->co[2]: %f\n",
@@ -3539,7 +3556,7 @@ static int manta_step(
Depsgraph *depsgraph, Scene *scene, Object *ob, Mesh *me, FluidModifierData *mmd, int frame)
{
FluidDomainSettings *mds = mmd->domain;
- float dt, frame_length, time_total;
+ float dt, frame_length, time_total, time_total_old;
float time_per_frame;
bool init_resolution = true;
@@ -3563,6 +3580,8 @@ static int manta_step(
dt = mds->dt;
time_per_frame = 0;
time_total = mds->time_total;
+ /* Keep track of original total time to correct small errors at end of step. */
+ time_total_old = mds->time_total;
BLI_mutex_lock(&object_update_lock);
@@ -3595,6 +3614,7 @@ static int manta_step(
break;
}
+ /* Only bake if the domain is bigger than one cell (important for adaptive domain). */
if (mds->total_cells > 1) {
update_effectors(depsgraph, scene, ob, mds, dt);
manta_bake_data(mds->fluid, mmd, frame);
@@ -3606,15 +3626,11 @@ static int manta_step(
mds->time_per_frame = time_per_frame;
mds->time_total = time_total;
-
- /* If user requested stop, quit baking */
- if (G.is_break && !mode_replay) {
- result = 0;
- break;
- }
}
+ /* Total time must not exceed framecount times framelength. Correct tiny errors here. */
+ CLAMP(mds->time_total, mds->time_total, time_total_old + mds->frame_length);
- if (mds->type == FLUID_DOMAIN_TYPE_GAS) {
+ if (mds->type == FLUID_DOMAIN_TYPE_GAS && result) {
manta_smoke_calc_transparency(mds, DEG_get_evaluated_view_layer(depsgraph));
}
BLI_mutex_unlock(&object_update_lock);
@@ -3704,24 +3720,60 @@ static void BKE_fluid_modifier_processDomain(FluidModifierData *mmd,
uint numobj = 0;
FluidModifierData *mmd_parent = NULL;
- bool is_startframe;
+ bool is_startframe, has_advanced;
is_startframe = (scene_framenr == mds->cache_frame_start);
+ has_advanced = (scene_framenr == mmd->time + 1);
- /* Reset fluid if no fluid present. */
+ /* Do not process modifier if current frame is out of cache range. */
+ if (scene_framenr < mds->cache_frame_start || scene_framenr > mds->cache_frame_end) {
+ return;
+ }
+
+ /* Reset fluid if no fluid present. Also resets active fields. */
if (!mds->fluid) {
BKE_fluid_modifier_reset_ex(mmd, false);
+ }
- /* Fluid domain init must not fail in order to continue modifier evaluation. */
- if (!BKE_fluid_modifier_init(mmd, depsgraph, ob, scene, me)) {
- return;
- }
+ /* Ensure cache directory is not relative. */
+ const char *relbase = BKE_modifier_path_relbase_from_global(ob);
+ BLI_path_abs(mds->cache_directory, relbase);
+
+ /* Ensure that all flags are up to date before doing any baking and/or cache reading. */
+ objs = BKE_collision_objects_create(
+ depsgraph, ob, mds->fluid_group, &numobj, eModifierType_Fluid);
+ update_flowsflags(mds, objs, numobj);
+ if (objs) {
+ MEM_freeN(objs);
+ }
+ objs = BKE_collision_objects_create(
+ depsgraph, ob, mds->effector_group, &numobj, eModifierType_Fluid);
+ update_obstacleflags(mds, objs, numobj);
+ if (objs) {
+ MEM_freeN(objs);
+ }
+
+ /* TODO (sebbas): Cache reset for when flow / effector object need update flag is set. */
+# if 0
+ /* If the just updated flags now carry the 'outdated' flag, reset the cache here!
+ * Plus sanity check: Do not clear cache on file load. */
+ if (mds->cache_flag & FLUID_DOMAIN_OUTDATED_DATA &&
+ ((mds->flags & FLUID_DOMAIN_FILE_LOAD) == 0)) {
+ BKE_fluid_cache_free_all(mds, ob);
+ BKE_fluid_modifier_reset_ex(mmd, false);
+ }
+# endif
+
+ /* Fluid domain init must not fail in order to continue modifier evaluation. */
+ if (!mds->fluid && !BKE_fluid_modifier_init(mmd, depsgraph, ob, scene, me)) {
+ CLOG_ERROR(&LOG, "Fluid initialization failed. Should not happen!");
+ return;
}
BLI_assert(mds->fluid);
/* Guiding parent res pointer needs initialization. */
guide_parent = mds->guide_parent;
if (guide_parent) {
- mmd_parent = (FluidModifierData *)modifiers_findByType(guide_parent, eModifierType_Fluid);
+ mmd_parent = (FluidModifierData *)BKE_modifiers_findby_type(guide_parent, eModifierType_Fluid);
if (mmd_parent && mmd_parent->domain) {
copy_v3_v3_int(mds->guide_res, mmd_parent->domain->res);
}
@@ -3732,26 +3784,17 @@ static void BKE_fluid_modifier_processDomain(FluidModifierData *mmd,
mds->frame_length = DT_DEFAULT * (25.0f / fps) * mds->time_scale;
mds->dt = mds->frame_length;
mds->time_per_frame = 0;
- /* Get distance between cache start and current frame for total time. */
- mds->time_total = abs(scene_framenr - mds->cache_frame_start) * mds->frame_length;
-
- objs = BKE_collision_objects_create(
- depsgraph, ob, mds->fluid_group, &numobj, eModifierType_Fluid);
- update_flowsflags(mds, objs, numobj);
- if (objs) {
- MEM_freeN(objs);
- }
- objs = BKE_collision_objects_create(
- depsgraph, ob, mds->effector_group, &numobj, eModifierType_Fluid);
- update_obstacleflags(mds, objs, numobj);
- if (objs) {
- MEM_freeN(objs);
+ /* Ensure that gravity is copied over every frame (could be keyframed). */
+ if (scene->physics_settings.flag & PHYS_GLOBAL_GRAVITY) {
+ copy_v3_v3(mds->gravity, scene->physics_settings.gravity);
+ mul_v3_fl(mds->gravity, mds->effector_weights->global_gravity);
}
- /* Ensure cache directory is not relative. */
- const char *relbase = modifier_path_relbase_from_global(ob);
- BLI_path_abs(mds->cache_directory, relbase);
+ int next_frame = scene_framenr + 1;
+ int prev_frame = scene_framenr - 1;
+ /* Ensure positivity of previous frame. */
+ CLAMP(prev_frame, mds->cache_frame_start, prev_frame);
int data_frame = scene_framenr, noise_frame = scene_framenr;
int mesh_frame = scene_framenr, particles_frame = scene_framenr, guide_frame = scene_framenr;
@@ -3773,18 +3816,20 @@ static void BKE_fluid_modifier_processDomain(FluidModifierData *mmd,
with_guide = mds->flags & FLUID_DOMAIN_USE_GUIDE;
with_particles = drops || bubble || floater;
- bool has_data, has_noise, has_mesh, has_particles, has_guide;
- has_data = has_noise = has_mesh = has_particles = has_guide = false;
+ bool has_data, has_noise, has_mesh, has_particles, has_guide, has_config;
+ has_data = manta_has_data(mds->fluid, mmd, scene_framenr);
+ has_noise = manta_has_noise(mds->fluid, mmd, scene_framenr);
+ has_mesh = manta_has_mesh(mds->fluid, mmd, scene_framenr);
+ has_particles = manta_has_particles(mds->fluid, mmd, scene_framenr);
+ has_guide = manta_has_guiding(mds->fluid, mmd, scene_framenr, guide_parent);
+ has_config = false;
- bool baking_data, baking_noise, baking_mesh, baking_particles, baking_guide, bake_outdated;
+ bool baking_data, baking_noise, baking_mesh, baking_particles, baking_guide;
baking_data = mds->cache_flag & FLUID_DOMAIN_BAKING_DATA;
baking_noise = mds->cache_flag & FLUID_DOMAIN_BAKING_NOISE;
baking_mesh = mds->cache_flag & FLUID_DOMAIN_BAKING_MESH;
baking_particles = mds->cache_flag & FLUID_DOMAIN_BAKING_PARTICLES;
baking_guide = mds->cache_flag & FLUID_DOMAIN_BAKING_GUIDE;
- bake_outdated = mds->cache_flag & (FLUID_DOMAIN_OUTDATED_DATA | FLUID_DOMAIN_OUTDATED_NOISE |
- FLUID_DOMAIN_OUTDATED_MESH | FLUID_DOMAIN_OUTDATED_PARTICLES |
- FLUID_DOMAIN_OUTDATED_GUIDE);
bool resume_data, resume_noise, resume_mesh, resume_particles, resume_guide;
resume_data = (!is_startframe) && (mds->cache_frame_pause_data == scene_framenr);
@@ -3797,15 +3842,28 @@ static void BKE_fluid_modifier_processDomain(FluidModifierData *mmd,
read_cache = false;
bake_cache = baking_data || baking_noise || baking_mesh || baking_particles || baking_guide;
+ bool next_data, next_noise, next_mesh, next_particles, next_guide;
+ next_data = manta_has_data(mds->fluid, mmd, next_frame);
+ next_noise = manta_has_noise(mds->fluid, mmd, next_frame);
+ next_mesh = manta_has_mesh(mds->fluid, mmd, next_frame);
+ next_particles = manta_has_particles(mds->fluid, mmd, next_frame);
+ next_guide = manta_has_guiding(mds->fluid, mmd, next_frame, guide_parent);
+
+ bool prev_data, prev_noise, prev_mesh, prev_particles, prev_guide;
+ prev_data = manta_has_data(mds->fluid, mmd, prev_frame);
+ prev_noise = manta_has_noise(mds->fluid, mmd, prev_frame);
+ prev_mesh = manta_has_mesh(mds->fluid, mmd, prev_frame);
+ prev_particles = manta_has_particles(mds->fluid, mmd, prev_frame);
+ prev_guide = manta_has_guiding(mds->fluid, mmd, prev_frame, guide_parent);
+
+ /* Unused for now. */
+ UNUSED_VARS(has_guide, prev_guide, next_mesh, next_guide);
+
bool with_gdomain;
with_gdomain = (mds->guide_source == FLUID_DOMAIN_GUIDE_SRC_DOMAIN);
int o_res[3], o_min[3], o_max[3], o_shift[3];
int mode = mds->cache_type;
- int prev_frame = scene_framenr - 1;
-
- /* Ensure positivity of previous frame. */
- CLAMP(prev_frame, 1, prev_frame);
/* Cache mode specific settings. */
switch (mode) {
@@ -3853,32 +3911,39 @@ static void BKE_fluid_modifier_processDomain(FluidModifierData *mmd,
break;
case FLUID_DOMAIN_CACHE_REPLAY:
default:
+ baking_data = !has_data && (is_startframe || prev_data);
+ if (with_smoke && with_noise) {
+ baking_noise = !has_noise && (is_startframe || prev_noise);
+ }
+ if (with_liquid && with_mesh) {
+ baking_mesh = !has_mesh && (is_startframe || prev_mesh);
+ }
+ if (with_liquid && with_particles) {
+ baking_particles = !has_particles && (is_startframe || prev_particles);
+ }
+
/* Always trying to read the cache in replay mode. */
read_cache = true;
+ bake_cache = false;
break;
}
- /* Cache outdated? If so reset, don't read, and then just rebake.
- * Note: Only do this in replay mode! */
- bool mode_replay = (mode == FLUID_DOMAIN_CACHE_REPLAY);
- if (bake_outdated && mode_replay) {
- read_cache = false;
- bake_cache = true;
- BKE_fluid_cache_free(mds, ob, mds->cache_flag);
- }
-
/* Try to read from cache and keep track of read success. */
if (read_cache) {
/* Read mesh cache. */
if (with_liquid && with_mesh) {
+ has_config = manta_read_config(mds->fluid, mmd, mesh_frame);
+
/* Update mesh data from file is faster than via Python (manta_read_mesh()). */
has_mesh = manta_update_mesh_structures(mds->fluid, mmd, mesh_frame);
}
/* Read particles cache. */
if (with_liquid && with_particles) {
- if (!baking_data && !baking_particles && !mode_replay) {
+ has_config = manta_read_config(mds->fluid, mmd, particles_frame);
+
+ if (!baking_data && !baking_particles && next_particles) {
/* Update particle data from file is faster than via Python (manta_read_particles()). */
has_particles = manta_update_particle_structures(mds->fluid, mmd, particles_frame);
}
@@ -3895,15 +3960,15 @@ static void BKE_fluid_modifier_processDomain(FluidModifierData *mmd,
/* Read noise and data cache */
if (with_smoke && with_noise) {
+ has_config = manta_read_config(mds->fluid, mmd, noise_frame);
/* Only reallocate when just reading cache or when resuming during bake. */
- if ((!baking_noise || (baking_noise && resume_noise)) &&
- manta_read_config(mds->fluid, mmd, noise_frame) &&
+ if ((!baking_noise || (baking_noise && resume_noise)) && has_config &&
manta_needs_realloc(mds->fluid, mmd)) {
BKE_fluid_reallocate_fluid(mds, mds->res, 1);
}
- if (!baking_data && !baking_noise && !mode_replay) {
- has_data = manta_update_noise_structures(mds->fluid, mmd, noise_frame);
+ if (!baking_data && !baking_noise && next_noise) {
+ has_noise = manta_update_noise_structures(mds->fluid, mmd, noise_frame);
}
else {
has_noise = manta_read_noise(mds->fluid, mmd, noise_frame);
@@ -3916,15 +3981,13 @@ static void BKE_fluid_modifier_processDomain(FluidModifierData *mmd,
copy_v3_v3_int(o_min, mds->res_min);
copy_v3_v3_int(o_max, mds->res_max);
copy_v3_v3_int(o_shift, mds->shift);
- if (manta_read_config(mds->fluid, mmd, data_frame) &&
- manta_needs_realloc(mds->fluid, mmd)) {
+ if (has_config && manta_needs_realloc(mds->fluid, mmd)) {
BKE_fluid_reallocate_copy_fluid(
mds, o_res, mds->res, o_min, mds->res_min, o_max, o_shift, mds->shift);
}
}
- if (!baking_data && !baking_noise && !mode_replay) {
- /* TODO (sebbas): Confirm if this read call is really needed or not. */
- has_data = manta_update_smoke_structures(mds->fluid, mmd, data_frame);
+ if (!baking_data && !baking_noise && next_data && next_noise) {
+ /* Nothing to do here since we already loaded noise grids. */
}
else {
has_data = manta_read_data(mds->fluid, mmd, data_frame);
@@ -3932,14 +3995,15 @@ static void BKE_fluid_modifier_processDomain(FluidModifierData *mmd,
}
/* Read data cache only */
else {
+ has_config = manta_read_config(mds->fluid, mmd, data_frame);
+
if (with_smoke) {
/* Read config and realloc fluid object if needed. */
- if (manta_read_config(mds->fluid, mmd, data_frame) &&
- manta_needs_realloc(mds->fluid, mmd)) {
+ if (has_config && manta_needs_realloc(mds->fluid, mmd)) {
BKE_fluid_reallocate_fluid(mds, mds->res, 1);
}
/* Read data cache */
- if (!baking_data && !baking_particles && !baking_mesh && !mode_replay) {
+ if (!baking_data && !baking_particles && !baking_mesh && next_data) {
has_data = manta_update_smoke_structures(mds->fluid, mmd, data_frame);
}
else {
@@ -3947,7 +4011,7 @@ static void BKE_fluid_modifier_processDomain(FluidModifierData *mmd,
}
}
if (with_liquid) {
- if (!baking_data && !baking_particles && !baking_mesh && !mode_replay) {
+ if (!baking_data && !baking_particles && !baking_mesh && next_data) {
has_data = manta_update_liquid_structures(mds->fluid, mmd, data_frame);
}
else {
@@ -3961,21 +4025,27 @@ static void BKE_fluid_modifier_processDomain(FluidModifierData *mmd,
switch (mode) {
case FLUID_DOMAIN_CACHE_FINAL:
case FLUID_DOMAIN_CACHE_MODULAR:
+ if (!baking_data && !baking_noise && !baking_mesh && !baking_particles && !baking_guide) {
+ bake_cache = false;
+ }
break;
case FLUID_DOMAIN_CACHE_REPLAY:
default:
- baking_data = !has_data;
+ baking_data = !has_data && (is_startframe || prev_data);
if (with_smoke && with_noise) {
- baking_noise = !has_noise;
+ baking_noise = !has_noise && (is_startframe || prev_noise);
}
if (with_liquid && with_mesh) {
- baking_mesh = !has_mesh;
+ baking_mesh = !has_mesh && (is_startframe || prev_mesh);
}
if (with_liquid && with_particles) {
- baking_particles = !has_particles;
+ baking_particles = !has_particles && (is_startframe || prev_particles);
}
- bake_cache = baking_data || baking_noise || baking_mesh || baking_particles;
+ /* Only bake if time advanced by one frame. */
+ if (is_startframe || has_advanced) {
+ bake_cache = baking_data || baking_noise || baking_mesh || baking_particles;
+ }
break;
}
@@ -4006,7 +4076,11 @@ static void BKE_fluid_modifier_processDomain(FluidModifierData *mmd,
}
if (has_data || baking_data) {
if (baking_noise && with_smoke && with_noise) {
- manta_bake_noise(mds->fluid, mmd, scene_framenr);
+ /* Ensure that no bake occurs if domain was minimized by adaptive domain. */
+ if (mds->total_cells > 1) {
+ manta_bake_noise(mds->fluid, mmd, scene_framenr);
+ }
+ manta_write_noise(mds->fluid, mmd, scene_framenr);
}
if (baking_mesh && with_liquid && with_mesh) {
manta_bake_mesh(mds->fluid, mmd, scene_framenr);
@@ -4016,6 +4090,8 @@ static void BKE_fluid_modifier_processDomain(FluidModifierData *mmd,
}
}
}
+
+ mds->flags &= ~FLUID_DOMAIN_FILE_LOAD;
mmd->time = scene_framenr;
}
@@ -4097,6 +4173,7 @@ struct Mesh *BKE_fluid_modifier_do(
mmd->domain->cache_flag &= ~FLUID_DOMAIN_OUTDATED_PARTICLES;
mmd->domain->cache_flag &= ~FLUID_DOMAIN_OUTDATED_GUIDE;
}
+
if (!result) {
result = BKE_mesh_copy_for_eval(me, false);
}
@@ -4311,26 +4388,25 @@ static void manta_smoke_calc_transparency(FluidDomainSettings *mds, ViewLayer *v
}
}
-/* get smoke velocity and density at given coordinates
- * returns fluid density or -1.0f if outside domain. */
+/* Get fluid velocity and density at given coordinates
+ * Returns fluid density or -1.0f if outside domain. */
float BKE_fluid_get_velocity_at(struct Object *ob, float position[3], float velocity[3])
{
- FluidModifierData *mmd = (FluidModifierData *)modifiers_findByType(ob, eModifierType_Fluid);
+ FluidModifierData *mmd = (FluidModifierData *)BKE_modifiers_findby_type(ob, eModifierType_Fluid);
zero_v3(velocity);
if (mmd && (mmd->type & MOD_FLUID_TYPE_DOMAIN) && mmd->domain && mmd->domain->fluid) {
FluidDomainSettings *mds = mmd->domain;
float time_mult = 25.f * DT_DEFAULT;
+ float size_mult = MAX3(mds->global_size[0], mds->global_size[1], mds->global_size[2]) /
+ mds->maxres;
float vel_mag;
- float *velX = manta_get_velocity_x(mds->fluid);
- float *velY = manta_get_velocity_y(mds->fluid);
- float *velZ = manta_get_velocity_z(mds->fluid);
float density = 0.0f, fuel = 0.0f;
float pos[3];
copy_v3_v3(pos, position);
manta_pos_to_cell(mds, pos);
- /* check if point is outside domain max bounds */
+ /* Check if position is outside domain max bounds. */
if (pos[0] < mds->res_min[0] || pos[1] < mds->res_min[1] || pos[2] < mds->res_min[2]) {
return -1.0f;
}
@@ -4343,9 +4419,8 @@ float BKE_fluid_get_velocity_at(struct Object *ob, float position[3], float velo
pos[1] = (pos[1] - mds->res_min[1]) / ((float)mds->res[1]);
pos[2] = (pos[2] - mds->res_min[2]) / ((float)mds->res[2]);
- /* check if point is outside active area */
- if (mmd->domain->type == FLUID_DOMAIN_TYPE_GAS &&
- mmd->domain->flags & FLUID_DOMAIN_USE_ADAPTIVE_DOMAIN) {
+ /* Check if position is outside active area. */
+ if (mds->type == FLUID_DOMAIN_TYPE_GAS && mds->flags & FLUID_DOMAIN_USE_ADAPTIVE_DOMAIN) {
if (pos[0] < 0.0f || pos[1] < 0.0f || pos[2] < 0.0f) {
return 0.0f;
}
@@ -4354,21 +4429,22 @@ float BKE_fluid_get_velocity_at(struct Object *ob, float position[3], float velo
}
}
- /* get interpolated velocity */
- velocity[0] = BLI_voxel_sample_trilinear(velX, mds->res, pos) * mds->global_size[0] *
- time_mult;
- velocity[1] = BLI_voxel_sample_trilinear(velY, mds->res, pos) * mds->global_size[1] *
- time_mult;
- velocity[2] = BLI_voxel_sample_trilinear(velZ, mds->res, pos) * mds->global_size[2] *
- time_mult;
+ /* Get interpolated velocity at given position. */
+ velocity[0] = BLI_voxel_sample_trilinear(manta_get_velocity_x(mds->fluid), mds->res, pos);
+ velocity[1] = BLI_voxel_sample_trilinear(manta_get_velocity_y(mds->fluid), mds->res, pos);
+ velocity[2] = BLI_voxel_sample_trilinear(manta_get_velocity_z(mds->fluid), mds->res, pos);
- /* convert velocity direction to global space */
+ /* Convert simulation units to Blender units. */
+ mul_v3_fl(velocity, size_mult);
+ mul_v3_fl(velocity, time_mult);
+
+ /* Convert velocity direction to global space. */
vel_mag = len_v3(velocity);
mul_mat3_m4_v3(mds->obmat, velocity);
normalize_v3(velocity);
mul_v3_fl(velocity, vel_mag);
- /* use max value of fuel or smoke density */
+ /* Use max value of fuel or smoke density. */
density = BLI_voxel_sample_trilinear(manta_smoke_get_density(mds->fluid), mds->res, pos);
if (manta_smoke_has_fuel(mds->fluid)) {
fuel = BLI_voxel_sample_trilinear(manta_smoke_get_fuel(mds->fluid), mds->res, pos);
@@ -4422,11 +4498,11 @@ void BKE_fluid_particle_system_create(struct Main *bmain,
BLI_addtail(&ob->particlesystem, psys);
/* add modifier */
- pmmd = (ParticleSystemModifierData *)modifier_new(eModifierType_ParticleSystem);
+ pmmd = (ParticleSystemModifierData *)BKE_modifier_new(eModifierType_ParticleSystem);
BLI_strncpy(pmmd->modifier.name, psys_name, sizeof(pmmd->modifier.name));
pmmd->psys = psys;
BLI_addtail(&ob->modifiers, pmmd);
- modifier_unique_name(&ob->modifiers, (ModifierData *)pmmd);
+ BKE_modifier_unique_name(&ob->modifiers, (ModifierData *)pmmd);
}
void BKE_fluid_particle_system_destroy(struct Object *ob, const int particle_type)
@@ -4440,7 +4516,7 @@ void BKE_fluid_particle_system_destroy(struct Object *ob, const int particle_typ
/* clear modifier */
pmmd = psys_get_modifier(ob, psys);
BLI_remlink(&ob->modifiers, pmmd);
- modifier_free((ModifierData *)pmmd);
+ BKE_modifier_free((ModifierData *)pmmd);
/* clear particle system */
BLI_remlink(&ob->particlesystem, psys);
@@ -4459,6 +4535,18 @@ void BKE_fluid_particle_system_destroy(struct Object *ob, const int particle_typ
* Use for versioning, even when fluids are disabled.
* \{ */
+void BKE_fluid_cache_startframe_set(FluidDomainSettings *settings, int value)
+{
+ settings->cache_frame_start = (value > settings->cache_frame_end) ? settings->cache_frame_end :
+ value;
+}
+
+void BKE_fluid_cache_endframe_set(FluidDomainSettings *settings, int value)
+{
+ settings->cache_frame_end = (value < settings->cache_frame_start) ? settings->cache_frame_start :
+ value;
+}
+
void BKE_fluid_cachetype_mesh_set(FluidDomainSettings *settings, int cache_mesh_format)
{
if (cache_mesh_format == settings->cache_mesh_format) {
@@ -4633,6 +4721,7 @@ static void BKE_fluid_modifier_freeFlow(FluidModifierData *mmd)
}
mmd->flow->verts_old = NULL;
mmd->flow->numverts = 0;
+ mmd->flow->flags &= ~FLUID_FLOW_NEEDS_UPDATE;
MEM_freeN(mmd->flow);
mmd->flow = NULL;
@@ -4652,6 +4741,7 @@ static void BKE_fluid_modifier_freeEffector(FluidModifierData *mmd)
}
mmd->effector->verts_old = NULL;
mmd->effector->numverts = 0;
+ mmd->effector->flags &= ~FLUID_EFFECTOR_NEEDS_UPDATE;
MEM_freeN(mmd->effector);
mmd->effector = NULL;
@@ -4690,6 +4780,7 @@ static void BKE_fluid_modifier_reset_ex(struct FluidModifierData *mmd, bool need
}
mmd->flow->verts_old = NULL;
mmd->flow->numverts = 0;
+ mmd->flow->flags &= ~FLUID_FLOW_NEEDS_UPDATE;
}
else if (mmd->effector) {
if (mmd->effector->verts_old) {
@@ -4697,6 +4788,7 @@ static void BKE_fluid_modifier_reset_ex(struct FluidModifierData *mmd, bool need
}
mmd->effector->verts_old = NULL;
mmd->effector->numverts = 0;
+ mmd->effector->flags &= ~FLUID_EFFECTOR_NEEDS_UPDATE;
}
}
@@ -4743,13 +4835,13 @@ void BKE_fluid_modifier_create_type_data(struct FluidModifierData *mmd)
mmd->domain->adapt_threshold = 0.02f;
/* fluid domain options */
- mmd->domain->maxres = 64;
+ mmd->domain->maxres = 32;
mmd->domain->solver_res = 3;
mmd->domain->border_collisions = 0; // open domain
mmd->domain->flags = FLUID_DOMAIN_USE_DISSOLVE_LOG | FLUID_DOMAIN_USE_ADAPTIVE_TIME;
mmd->domain->gravity[0] = 0.0f;
mmd->domain->gravity[1] = 0.0f;
- mmd->domain->gravity[2] = -1.0f;
+ mmd->domain->gravity[2] = -9.81f;
mmd->domain->active_fields = 0;
mmd->domain->type = FLUID_DOMAIN_TYPE_GAS;
mmd->domain->boundary_width = 1;
@@ -4796,7 +4888,6 @@ void BKE_fluid_modifier_create_type_data(struct FluidModifierData *mmd)
mmd->domain->surface_tension = 0.0f;
mmd->domain->viscosity_base = 1.0f;
mmd->domain->viscosity_exponent = 6.0f;
- mmd->domain->domain_size = 0.5f;
/* mesh options */
mmd->domain->mesh_velocities = NULL;
@@ -4838,14 +4929,14 @@ void BKE_fluid_modifier_create_type_data(struct FluidModifierData *mmd)
/* cache options */
mmd->domain->cache_frame_start = 1;
- mmd->domain->cache_frame_end = 50;
+ mmd->domain->cache_frame_end = 250;
mmd->domain->cache_frame_pause_data = 0;
mmd->domain->cache_frame_pause_noise = 0;
mmd->domain->cache_frame_pause_mesh = 0;
mmd->domain->cache_frame_pause_particles = 0;
mmd->domain->cache_frame_pause_guide = 0;
mmd->domain->cache_flag = 0;
- mmd->domain->cache_type = FLUID_DOMAIN_CACHE_MODULAR;
+ mmd->domain->cache_type = FLUID_DOMAIN_CACHE_REPLAY;
mmd->domain->cache_mesh_format = FLUID_DOMAIN_FILE_BIN_OBJECT;
#ifdef WITH_OPENVDB
mmd->domain->cache_data_format = FLUID_DOMAIN_FILE_OPENVDB;
@@ -4858,7 +4949,7 @@ void BKE_fluid_modifier_create_type_data(struct FluidModifierData *mmd)
#endif
char cache_name[64];
BKE_fluid_cache_new_name_for_current_session(sizeof(cache_name), cache_name);
- modifier_path_init(
+ BKE_modifier_path_init(
mmd->domain->cache_directory, sizeof(mmd->domain->cache_directory), cache_name);
/* time options */
@@ -5040,7 +5131,6 @@ void BKE_fluid_modifier_copy(const struct FluidModifierData *mmd,
tmds->surface_tension = mds->surface_tension;
tmds->viscosity_base = mds->viscosity_base;
tmds->viscosity_exponent = mds->viscosity_exponent;
- tmds->domain_size = mds->domain_size;
/* mesh options */
if (mds->mesh_velocities) {
diff --git a/source/blender/blenkernel/intern/fmodifier.c b/source/blender/blenkernel/intern/fmodifier.c
index 1d5a908e226..c85283e3653 100644
--- a/source/blender/blenkernel/intern/fmodifier.c
+++ b/source/blender/blenkernel/intern/fmodifier.c
@@ -1358,7 +1358,7 @@ uint evaluate_fmodifiers_storage_size_per_modifier(ListBase *modifiers)
uint max_size = 0;
- for (FModifier *fcm = modifiers->first; fcm; fcm = fcm->next) {
+ LISTBASE_FOREACH (FModifier *, fcm, modifiers) {
const FModifierTypeInfo *fmi = fmodifier_get_typeinfo(fcm);
if (fmi == NULL) {
diff --git a/source/blender/blenkernel/intern/font.c b/source/blender/blenkernel/intern/font.c
index e25603e0af5..54f2492af93 100644
--- a/source/blender/blenkernel/intern/font.c
+++ b/source/blender/blenkernel/intern/font.c
@@ -48,7 +48,7 @@
#include "DNA_packedFile_types.h"
#include "DNA_vfont_types.h"
-#include "BKE_anim.h"
+#include "BKE_anim_path.h"
#include "BKE_curve.h"
#include "BKE_font.h"
#include "BKE_global.h"
@@ -134,6 +134,7 @@ IDTypeInfo IDType_ID_VF = {
.copy_data = vfont_copy_data,
.free_data = vfont_free_data,
.make_local = NULL,
+ .foreach_id = NULL,
};
/***************************** VFont *******************************/
@@ -734,7 +735,7 @@ static bool vfont_to_curve(Object *ob,
float twidth = 0, maxlen = 0;
int i, slen, j;
int curbox;
- int selstart, selend;
+ int selstart = 0, selend = 0;
int cnr = 0, lnr = 0, wsnr = 0;
const char32_t *mem = NULL;
char32_t ascii;
@@ -1501,9 +1502,9 @@ static bool vfont_to_curve(Object *ob,
}
else if (tb_scale.h == 0.0f) {
/* This is a horizontal overflow. */
- if (lnr > 1) {
+ if (longest_line_length != 0.0f) {
/* We make sure longest line before it broke can fit here. */
- float scale_to_fit = tb_scale.w / (longest_line_length);
+ float scale_to_fit = tb_scale.w / longest_line_length;
scale_to_fit -= FLT_EPSILON;
iter_data->scale_to_fit = scale_to_fit;
diff --git a/source/blender/blenkernel/intern/gpencil.c b/source/blender/blenkernel/intern/gpencil.c
index 555b0af5a63..122cc656bc2 100644
--- a/source/blender/blenkernel/intern/gpencil.c
+++ b/source/blender/blenkernel/intern/gpencil.c
@@ -55,6 +55,7 @@
#include "BKE_idtype.h"
#include "BKE_image.h"
#include "BKE_lib_id.h"
+#include "BKE_lib_query.h"
#include "BKE_main.h"
#include "BKE_material.h"
#include "BKE_paint.h"
@@ -97,6 +98,19 @@ static void greasepencil_free_data(ID *id)
BKE_gpencil_free((bGPdata *)id, true);
}
+static void greasepencil_foreach_id(ID *id, LibraryForeachIDData *data)
+{
+ bGPdata *gpencil = (bGPdata *)id;
+ /* materials */
+ for (int i = 0; i < gpencil->totcol; i++) {
+ BKE_LIB_FOREACHID_PROCESS(data, gpencil->mat[i], IDWALK_CB_USER);
+ }
+
+ LISTBASE_FOREACH (bGPDlayer *, gplayer, &gpencil->layers) {
+ BKE_LIB_FOREACHID_PROCESS(data, gplayer->parent, IDWALK_CB_NOP);
+ }
+}
+
IDTypeInfo IDType_ID_GD = {
.id_code = ID_GD,
.id_filter = FILTER_ID_GD,
@@ -111,6 +125,7 @@ IDTypeInfo IDType_ID_GD = {
.copy_data = greasepencil_copy_data,
.free_data = greasepencil_free_data,
.make_local = NULL,
+ .foreach_id = greasepencil_foreach_id,
};
/* ************************************************** */
@@ -541,7 +556,12 @@ bGPDstroke *BKE_gpencil_stroke_new(int mat_idx, int totpoints, short thickness)
gps->flag = GP_STROKE_3DSPACE;
gps->totpoints = totpoints;
- gps->points = MEM_callocN(sizeof(bGPDspoint) * gps->totpoints, "gp_stroke_points");
+ if (gps->totpoints > 0) {
+ gps->points = MEM_callocN(sizeof(bGPDspoint) * gps->totpoints, "gp_stroke_points");
+ }
+ else {
+ gps->points = NULL;
+ }
/* initialize triangle memory to dummy data */
gps->triangles = NULL;
@@ -639,7 +659,7 @@ bGPDframe *BKE_gpencil_frame_duplicate(const bGPDframe *gpf_src)
/* copy strokes */
BLI_listbase_clear(&gpf_dst->strokes);
- for (bGPDstroke *gps_src = gpf_src->strokes.first; gps_src; gps_src = gps_src->next) {
+ LISTBASE_FOREACH (bGPDstroke *, gps_src, &gpf_src->strokes) {
/* make copy of source stroke */
gps_dst = BKE_gpencil_stroke_duplicate(gps_src, true);
BLI_addtail(&gpf_dst->strokes, gps_dst);
@@ -660,7 +680,7 @@ void BKE_gpencil_frame_copy_strokes(bGPDframe *gpf_src, struct bGPDframe *gpf_ds
/* copy strokes */
BLI_listbase_clear(&gpf_dst->strokes);
- for (bGPDstroke *gps_src = gpf_src->strokes.first; gps_src; gps_src = gps_src->next) {
+ LISTBASE_FOREACH (bGPDstroke *, gps_src, &gpf_src->strokes) {
/* make copy of source stroke */
gps_dst = BKE_gpencil_stroke_duplicate(gps_src, true);
BLI_addtail(&gpf_dst->strokes, gps_dst);
@@ -819,12 +839,7 @@ bool BKE_gpencil_layer_is_editable(const bGPDlayer *gpl)
/* Layer must be: Visible + Editable */
if ((gpl->flag & (GP_LAYER_HIDE | GP_LAYER_LOCKED)) == 0) {
- /* Opacity must be sufficiently high that it is still "visible"
- * Otherwise, it's not really "visible" to the user, so no point editing...
- */
- if (gpl->opacity > GPENCIL_ALPHA_OPACITY_THRESH) {
- return true;
- }
+ return true;
}
/* Something failed */
@@ -1743,7 +1758,18 @@ void BKE_gpencil_palette_ensure(Main *bmain, Scene *scene)
GpPaint *gp_paint = ts->gp_paint;
Paint *paint = &gp_paint->paint;
+ if (paint->palette != NULL) {
+ return;
+ }
+
paint->palette = BLI_findstring(&bmain->palettes, "Palette", offsetof(ID, name) + 2);
+ /* Try with first palette. */
+ if (bmain->palettes.first != NULL) {
+ paint->palette = bmain->palettes.first;
+ ts->gp_vertexpaint->paint.palette = paint->palette;
+ return;
+ }
+
if (paint->palette == NULL) {
paint->palette = BKE_palette_add(bmain, "Palette");
ts->gp_vertexpaint->paint.palette = paint->palette;
@@ -1824,8 +1850,13 @@ bool BKE_gpencil_from_image(SpaceImage *sima, bGPDframe *gpf, const float size,
*
* \{ */
-void BKE_gpencil_visible_stroke_iter(
- Object *ob, gpIterCb layer_cb, gpIterCb stroke_cb, void *thunk, bool do_onion, int cfra)
+void BKE_gpencil_visible_stroke_iter(ViewLayer *view_layer,
+ Object *ob,
+ gpIterCb layer_cb,
+ gpIterCb stroke_cb,
+ void *thunk,
+ bool do_onion,
+ int cfra)
{
bGPdata *gpd = (bGPdata *)ob->data;
const bool is_multiedit = GPENCIL_MULTIEDIT_SESSIONS_ON(gpd);
@@ -1847,6 +1878,14 @@ void BKE_gpencil_visible_stroke_iter(
continue;
}
+ /* Hide the layer if it's defined a view layer filter. This is used to
+ * generate renders, putting only selected GP layers for each View Layer.
+ * This is used only in final render and never in Viewport. */
+ if ((view_layer != NULL) && (gpl->viewlayername[0] != '\0') &&
+ (!STREQ(view_layer->name, gpl->viewlayername))) {
+ continue;
+ }
+
if (is_multiedit) {
sta_gpf = end_gpf = NULL;
/* Check the whole range and tag the editable frames. */
@@ -1926,6 +1965,9 @@ void BKE_gpencil_visible_stroke_iter(
}
LISTBASE_FOREACH (bGPDstroke *, gps, &gpf->strokes) {
+ if (gps->totpoints == 0) {
+ continue;
+ }
stroke_cb(gpl, gpf, gps, thunk);
}
}
@@ -1939,6 +1981,9 @@ void BKE_gpencil_visible_stroke_iter(
}
LISTBASE_FOREACH (bGPDstroke *, gps, &act_gpf->strokes) {
+ if (gps->totpoints == 0) {
+ continue;
+ }
stroke_cb(gpl, act_gpf, gps, thunk);
}
}
@@ -1960,8 +2005,11 @@ void BKE_gpencil_frame_original_pointers_update(const struct bGPDframe *gpf_orig
if (i > gps_eval->totpoints - 1) {
break;
}
+ bGPDspoint *pt_orig = &gps_orig->points[i];
bGPDspoint *pt_eval = &gps_eval->points[i];
- pt_eval->runtime.pt_orig = &gps_orig->points[i];
+ pt_orig->runtime.pt_orig = NULL;
+ pt_orig->runtime.idx_orig = i;
+ pt_eval->runtime.pt_orig = pt_orig;
pt_eval->runtime.idx_orig = i;
}
/* Increase pointer. */
diff --git a/source/blender/blenkernel/intern/gpencil_curve.c b/source/blender/blenkernel/intern/gpencil_curve.c
new file mode 100644
index 00000000000..8299943cc49
--- /dev/null
+++ b/source/blender/blenkernel/intern/gpencil_curve.c
@@ -0,0 +1,450 @@
+/*
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * The Original Code is Copyright (C) 2008, Blender Foundation
+ * This is a new part of Blender
+ */
+
+/** \file
+ * \ingroup bke
+ */
+
+#include <math.h>
+#include <stddef.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include "CLG_log.h"
+
+#include "MEM_guardedalloc.h"
+
+#include "BLI_blenlib.h"
+#include "BLI_math_vector.h"
+
+#include "BLT_translation.h"
+
+#include "DNA_gpencil_types.h"
+
+#include "BKE_collection.h"
+#include "BKE_curve.h"
+#include "BKE_gpencil.h"
+#include "BKE_gpencil_curve.h"
+#include "BKE_gpencil_geom.h"
+#include "BKE_main.h"
+#include "BKE_material.h"
+#include "BKE_object.h"
+
+#include "DEG_depsgraph_query.h"
+
+/* Helper: Check materials with same color. */
+static int gpencil_check_same_material_color(Object *ob_gp, float color[4], Material **r_mat)
+{
+ Material *ma = NULL;
+ float color_cu[4];
+ linearrgb_to_srgb_v3_v3(color_cu, color);
+ float hsv1[4];
+ rgb_to_hsv_v(color_cu, hsv1);
+ hsv1[3] = color[3];
+
+ for (int i = 1; i <= ob_gp->totcol; i++) {
+ ma = BKE_object_material_get(ob_gp, i);
+ MaterialGPencilStyle *gp_style = ma->gp_style;
+ /* Check color with small tolerance (better in HSV). */
+ float hsv2[4];
+ rgb_to_hsv_v(gp_style->fill_rgba, hsv2);
+ hsv2[3] = gp_style->fill_rgba[3];
+ if ((gp_style->fill_style == GP_MATERIAL_FILL_STYLE_SOLID) &&
+ (compare_v4v4(hsv1, hsv2, 0.01f))) {
+ *r_mat = ma;
+ return i - 1;
+ }
+ }
+
+ *r_mat = NULL;
+ return -1;
+}
+
+/* Helper: Add gpencil material using curve material as base. */
+static Material *gpencil_add_from_curve_material(Main *bmain,
+ Object *ob_gp,
+ const float cu_color[4],
+ const bool gpencil_lines,
+ const bool fill,
+ int *r_idx)
+{
+ Material *mat_gp = BKE_gpencil_object_material_new(
+ bmain, ob_gp, (fill) ? "Material" : "Unassigned", r_idx);
+ MaterialGPencilStyle *gp_style = mat_gp->gp_style;
+
+ /* Stroke color. */
+ if (gpencil_lines) {
+ ARRAY_SET_ITEMS(gp_style->stroke_rgba, 0.0f, 0.0f, 0.0f, 1.0f);
+ gp_style->flag |= GP_MATERIAL_STROKE_SHOW;
+ }
+ else {
+ linearrgb_to_srgb_v4(gp_style->stroke_rgba, cu_color);
+ gp_style->flag &= ~GP_MATERIAL_STROKE_SHOW;
+ }
+
+ /* Fill color. */
+ linearrgb_to_srgb_v4(gp_style->fill_rgba, cu_color);
+ /* Fill is false if the original curve hasn't material assigned, so enable it. */
+ if (fill) {
+ gp_style->flag |= GP_MATERIAL_FILL_SHOW;
+ }
+
+ /* Check at least one is enabled. */
+ if (((gp_style->flag & GP_MATERIAL_STROKE_SHOW) == 0) &&
+ ((gp_style->flag & GP_MATERIAL_FILL_SHOW) == 0)) {
+ gp_style->flag |= GP_MATERIAL_STROKE_SHOW;
+ }
+
+ return mat_gp;
+}
+
+/* Helper: Create new stroke section. */
+static void gpencil_add_new_points(bGPDstroke *gps,
+ float *coord_array,
+ float pressure,
+ int init,
+ int totpoints,
+ const float init_co[3],
+ bool last)
+{
+ for (int i = 0; i < totpoints; i++) {
+ bGPDspoint *pt = &gps->points[i + init];
+ copy_v3_v3(&pt->x, &coord_array[3 * i]);
+ /* Be sure the last point is not on top of the first point of the curve or
+ * the close of the stroke will produce glitches. */
+ if ((last) && (i > 0) && (i == totpoints - 1)) {
+ float dist = len_v3v3(init_co, &pt->x);
+ if (dist < 0.1f) {
+ /* Interpolate between previous point and current to back slightly. */
+ bGPDspoint *pt_prev = &gps->points[i + init - 1];
+ interp_v3_v3v3(&pt->x, &pt_prev->x, &pt->x, 0.95f);
+ }
+ }
+
+ pt->pressure = pressure;
+ pt->strength = 1.0f;
+ }
+}
+
+/* Helper: Get the first collection that includes the object. */
+static Collection *gpencil_get_parent_collection(Scene *scene, Object *ob)
+{
+ Collection *mycol = NULL;
+ FOREACH_SCENE_COLLECTION_BEGIN (scene, collection) {
+ LISTBASE_FOREACH (CollectionObject *, cob, &collection->gobject) {
+ if ((mycol == NULL) && (cob->ob == ob)) {
+ mycol = collection;
+ }
+ }
+ }
+ FOREACH_SCENE_COLLECTION_END;
+
+ return mycol;
+}
+
+/* Helper: Convert one spline to grease pencil stroke. */
+static void gpencil_convert_spline(Main *bmain,
+ Object *ob_gp,
+ Object *ob_cu,
+ const bool gpencil_lines,
+ const bool only_stroke,
+ bGPDframe *gpf,
+ Nurb *nu)
+{
+ Curve *cu = (Curve *)ob_cu->data;
+ bool cyclic = true;
+
+ /* Create Stroke. */
+ bGPDstroke *gps = MEM_callocN(sizeof(bGPDstroke), "bGPDstroke");
+ gps->thickness = 10.0f;
+ gps->fill_opacity_fac = 1.0f;
+ gps->hardeness = 1.0f;
+ gps->uv_scale = 1.0f;
+
+ ARRAY_SET_ITEMS(gps->aspect_ratio, 1.0f, 1.0f);
+ ARRAY_SET_ITEMS(gps->caps, GP_STROKE_CAP_ROUND, GP_STROKE_CAP_ROUND);
+ gps->inittime = 0.0f;
+
+ gps->flag &= ~GP_STROKE_SELECT;
+ gps->flag |= GP_STROKE_3DSPACE;
+
+ gps->mat_nr = 0;
+ /* Count total points
+ * The total of points must consider that last point of each segment is equal to the first
+ * point of next segment.
+ */
+ int totpoints = 0;
+ int segments = 0;
+ int resolu = nu->resolu + 1;
+ segments = nu->pntsu;
+ if ((nu->flagu & CU_NURB_CYCLIC) == 0) {
+ segments--;
+ cyclic = false;
+ }
+ totpoints = (resolu * segments) - (segments - 1);
+
+ /* Materials
+ * Notice: The color of the material is the color of viewport and not the final shader color.
+ */
+ Material *mat_gp = NULL;
+ bool fill = true;
+ /* Check if grease pencil has a material with same color.*/
+ float color[4];
+ if ((cu->mat) && (*cu->mat)) {
+ Material *mat_cu = *cu->mat;
+ copy_v4_v4(color, &mat_cu->r);
+ }
+ else {
+ /* Gray (unassigned from SVG add-on) */
+ zero_v4(color);
+ add_v3_fl(color, 0.6f);
+ color[3] = 1.0f;
+ fill = false;
+ }
+
+ /* Special case: If the color was created by the SVG add-on and the name contains '_stroke' and
+ * there is only one color, the stroke must not be closed, fill to false and use for
+ * stroke the fill color.
+ */
+ bool do_stroke = false;
+ if (ob_cu->totcol == 1) {
+ Material *ma_stroke = BKE_object_material_get(ob_cu, 1);
+ if ((ma_stroke) && (strstr(ma_stroke->id.name, "_stroke") != NULL)) {
+ do_stroke = true;
+ }
+ }
+
+ int r_idx = gpencil_check_same_material_color(ob_gp, color, &mat_gp);
+ if ((ob_cu->totcol > 0) && (r_idx < 0)) {
+ Material *mat_curve = BKE_object_material_get(ob_cu, 1);
+ mat_gp = gpencil_add_from_curve_material(bmain, ob_gp, color, gpencil_lines, fill, &r_idx);
+
+ if ((mat_curve) && (mat_curve->gp_style != NULL)) {
+ MaterialGPencilStyle *gp_style_cur = mat_curve->gp_style;
+ MaterialGPencilStyle *gp_style_gp = mat_gp->gp_style;
+
+ copy_v4_v4(gp_style_gp->mix_rgba, gp_style_cur->mix_rgba);
+ gp_style_gp->fill_style = gp_style_cur->fill_style;
+ gp_style_gp->mix_factor = gp_style_cur->mix_factor;
+ }
+
+ /* If object has more than 1 material, use second material for stroke color. */
+ if ((!only_stroke) && (ob_cu->totcol > 1) && (BKE_object_material_get(ob_cu, 2))) {
+ mat_curve = BKE_object_material_get(ob_cu, 2);
+ if (mat_curve) {
+ linearrgb_to_srgb_v3_v3(mat_gp->gp_style->stroke_rgba, &mat_curve->r);
+ mat_gp->gp_style->stroke_rgba[3] = mat_curve->a;
+ }
+ }
+ else if ((only_stroke) || (do_stroke)) {
+ /* Also use the first color if the fill is none for stroke color. */
+ if (ob_cu->totcol > 0) {
+ mat_curve = BKE_object_material_get(ob_cu, 1);
+ if (mat_curve) {
+ copy_v3_v3(mat_gp->gp_style->stroke_rgba, &mat_curve->r);
+ mat_gp->gp_style->stroke_rgba[3] = mat_curve->a;
+ /* Set fill and stroke depending of curve type (3D or 2D). */
+ if ((cu->flag & CU_3D) || ((cu->flag & (CU_FRONT | CU_BACK)) == 0)) {
+ mat_gp->gp_style->flag |= GP_MATERIAL_STROKE_SHOW;
+ mat_gp->gp_style->flag &= ~GP_MATERIAL_FILL_SHOW;
+ }
+ else {
+ mat_gp->gp_style->flag &= ~GP_MATERIAL_STROKE_SHOW;
+ mat_gp->gp_style->flag |= GP_MATERIAL_FILL_SHOW;
+ }
+ }
+ }
+ }
+ }
+ CLAMP_MIN(r_idx, 0);
+
+ /* Assign material index to stroke. */
+ gps->mat_nr = r_idx;
+
+ /* Add stroke to frame.*/
+ BLI_addtail(&gpf->strokes, gps);
+
+ float *coord_array = NULL;
+ float init_co[3];
+
+ switch (nu->type) {
+ case CU_POLY: {
+ /* Allocate memory for storage points. */
+ gps->totpoints = nu->pntsu;
+ gps->points = MEM_callocN(sizeof(bGPDspoint) * gps->totpoints, "gp_stroke_points");
+ /* Increase thickness for this type. */
+ gps->thickness = 10.0f;
+
+ /* Get all curve points */
+ for (int s = 0; s < gps->totpoints; s++) {
+ BPoint *bp = &nu->bp[s];
+ bGPDspoint *pt = &gps->points[s];
+ copy_v3_v3(&pt->x, bp->vec);
+ pt->pressure = bp->radius;
+ pt->strength = 1.0f;
+ }
+ break;
+ }
+ case CU_BEZIER: {
+ /* Allocate memory for storage points. */
+ gps->totpoints = totpoints;
+ gps->points = MEM_callocN(sizeof(bGPDspoint) * gps->totpoints, "gp_stroke_points");
+
+ int init = 0;
+ resolu = nu->resolu + 1;
+ segments = nu->pntsu;
+ if ((nu->flagu & CU_NURB_CYCLIC) == 0) {
+ segments--;
+ }
+ /* Get all interpolated curve points of Beziert */
+ for (int s = 0; s < segments; s++) {
+ int inext = (s + 1) % nu->pntsu;
+ BezTriple *prevbezt = &nu->bezt[s];
+ BezTriple *bezt = &nu->bezt[inext];
+ bool last = (bool)(s == segments - 1);
+
+ coord_array = MEM_callocN((size_t)3 * resolu * sizeof(float), __func__);
+
+ for (int j = 0; j < 3; j++) {
+ BKE_curve_forward_diff_bezier(prevbezt->vec[1][j],
+ prevbezt->vec[2][j],
+ bezt->vec[0][j],
+ bezt->vec[1][j],
+ coord_array + j,
+ resolu - 1,
+ 3 * sizeof(float));
+ }
+ /* Save first point coordinates. */
+ if (s == 0) {
+ copy_v3_v3(init_co, &coord_array[0]);
+ }
+ /* Add points to the stroke */
+ gpencil_add_new_points(gps, coord_array, bezt->radius, init, resolu, init_co, last);
+ /* Free memory. */
+ MEM_SAFE_FREE(coord_array);
+
+ /* As the last point of segment is the first point of next segment, back one array
+ * element to avoid duplicated points on the same location.
+ */
+ init += resolu - 1;
+ }
+ break;
+ }
+ case CU_NURBS: {
+ if (nu->pntsv == 1) {
+
+ int nurb_points;
+ if (nu->flagu & CU_NURB_CYCLIC) {
+ resolu++;
+ nurb_points = nu->pntsu * resolu;
+ }
+ else {
+ nurb_points = (nu->pntsu - 1) * resolu;
+ }
+ /* Get all curve points. */
+ coord_array = MEM_callocN(sizeof(float[3]) * nurb_points, __func__);
+ BKE_nurb_makeCurve(nu, coord_array, NULL, NULL, NULL, resolu, sizeof(float[3]));
+
+ /* Allocate memory for storage points. */
+ gps->totpoints = nurb_points - 1;
+ gps->points = MEM_callocN(sizeof(bGPDspoint) * gps->totpoints, "gp_stroke_points");
+
+ /* Add points. */
+ gpencil_add_new_points(gps, coord_array, 1.0f, 0, gps->totpoints, init_co, false);
+
+ MEM_SAFE_FREE(coord_array);
+ }
+ break;
+ }
+ default: {
+ break;
+ }
+ }
+ /* Cyclic curve, close stroke. */
+ if ((cyclic) && (!do_stroke)) {
+ BKE_gpencil_stroke_close(gps);
+ }
+
+ /* Recalc fill geometry. */
+ BKE_gpencil_stroke_geometry_update(gps);
+}
+
+/* Convert a curve object to grease pencil stroke.
+ *
+ * \param bmain: Main thread pointer
+ * \param scene: Original scene.
+ * \param ob_gp: Grease pencil object to add strokes.
+ * \param ob_cu: Curve to convert.
+ * \param gpencil_lines: Use lines for strokes.
+ * \param use_collections: Create layers using collection names.
+ * \param only_stroke: The material must be only stroke without fill.
+ */
+void BKE_gpencil_convert_curve(Main *bmain,
+ Scene *scene,
+ Object *ob_gp,
+ Object *ob_cu,
+ const bool gpencil_lines,
+ const bool use_collections,
+ const bool only_stroke)
+{
+ if (ELEM(NULL, ob_gp, ob_cu) || (ob_gp->type != OB_GPENCIL) || (ob_gp->data == NULL)) {
+ return;
+ }
+
+ Curve *cu = (Curve *)ob_cu->data;
+ bGPdata *gpd = (bGPdata *)ob_gp->data;
+ bGPDlayer *gpl = NULL;
+
+ /* If the curve is empty, cancel. */
+ if (cu->nurb.first == NULL) {
+ return;
+ }
+
+ /* Check if there is an active layer. */
+ if (use_collections) {
+ Collection *collection = gpencil_get_parent_collection(scene, ob_cu);
+ if (collection != NULL) {
+ gpl = BKE_gpencil_layer_named_get(gpd, collection->id.name + 2);
+ if (gpl == NULL) {
+ gpl = BKE_gpencil_layer_addnew(gpd, collection->id.name + 2, true);
+ }
+ }
+ }
+
+ if (gpl == NULL) {
+ gpl = BKE_gpencil_layer_active_get(gpd);
+ if (gpl == NULL) {
+ gpl = BKE_gpencil_layer_addnew(gpd, DATA_("GP_Layer"), true);
+ }
+ }
+
+ /* Check if there is an active frame and add if needed. */
+ bGPDframe *gpf = BKE_gpencil_layer_frame_get(gpl, CFRA, GP_GETFRAME_ADD_COPY);
+
+ /* Read all splines of the curve and create a stroke for each. */
+ LISTBASE_FOREACH (Nurb *, nu, &cu->nurb) {
+ gpencil_convert_spline(bmain, ob_gp, ob_cu, gpencil_lines, only_stroke, gpf, nu);
+ }
+
+ /* Tag for recalculation */
+ DEG_id_tag_update(&gpd->id, ID_RECALC_GEOMETRY | ID_RECALC_COPY_ON_WRITE);
+}
+
+/** \} */
diff --git a/source/blender/blenkernel/intern/gpencil_geom.c b/source/blender/blenkernel/intern/gpencil_geom.c
index c4acc871752..d200e4e3a15 100644
--- a/source/blender/blenkernel/intern/gpencil_geom.c
+++ b/source/blender/blenkernel/intern/gpencil_geom.c
@@ -35,18 +35,12 @@
#include "BLI_math_vector.h"
#include "BLI_polyfill_2d.h"
-#include "BLT_translation.h"
-
#include "DNA_gpencil_types.h"
#include "DNA_meshdata_types.h"
-#include "BKE_collection.h"
-#include "BKE_curve.h"
#include "BKE_deform.h"
#include "BKE_gpencil.h"
#include "BKE_gpencil_geom.h"
-#include "BKE_main.h"
-#include "BKE_material.h"
#include "BKE_object.h"
#include "DEG_depsgraph_query.h"
@@ -430,7 +424,7 @@ bool BKE_gpencil_stroke_sample(bGPDstroke *gps, const float dist, const bool sel
stroke_interpolate_deform_weights(gps, 0, 0, 0, &new_dv[0]);
}
- /* the rest */
+ /* The rest. */
while ((next_point_index = stroke_march_next_point(gps,
next_point_index,
last_coord,
@@ -1586,404 +1580,6 @@ void BKE_gpencil_stroke_merge_distance(bGPDframe *gpf,
BKE_gpencil_stroke_geometry_update(gps);
}
-/* Helper: Check materials with same color. */
-static int gpencil_check_same_material_color(Object *ob_gp, float color[4], Material **r_mat)
-{
- Material *ma = NULL;
- float color_cu[4];
- linearrgb_to_srgb_v3_v3(color_cu, color);
- float hsv1[4];
- rgb_to_hsv_v(color_cu, hsv1);
- hsv1[3] = color[3];
-
- for (int i = 1; i <= ob_gp->totcol; i++) {
- ma = BKE_object_material_get(ob_gp, i);
- MaterialGPencilStyle *gp_style = ma->gp_style;
- /* Check color with small tolerance (better in HSV). */
- float hsv2[4];
- rgb_to_hsv_v(gp_style->fill_rgba, hsv2);
- hsv2[3] = gp_style->fill_rgba[3];
- if ((gp_style->fill_style == GP_MATERIAL_FILL_STYLE_SOLID) &&
- (compare_v4v4(hsv1, hsv2, 0.01f))) {
- *r_mat = ma;
- return i - 1;
- }
- }
-
- *r_mat = NULL;
- return -1;
-}
-
-/* Helper: Add gpencil material using curve material as base. */
-static Material *gpencil_add_from_curve_material(Main *bmain,
- Object *ob_gp,
- const float cu_color[4],
- const bool gpencil_lines,
- const bool fill,
- int *r_idx)
-{
- Material *mat_gp = BKE_gpencil_object_material_new(
- bmain, ob_gp, (fill) ? "Material" : "Unassigned", r_idx);
- MaterialGPencilStyle *gp_style = mat_gp->gp_style;
-
- /* Stroke color. */
- if (gpencil_lines) {
- ARRAY_SET_ITEMS(gp_style->stroke_rgba, 0.0f, 0.0f, 0.0f, 1.0f);
- gp_style->flag |= GP_MATERIAL_STROKE_SHOW;
- }
- else {
- linearrgb_to_srgb_v4(gp_style->stroke_rgba, cu_color);
- gp_style->flag &= ~GP_MATERIAL_STROKE_SHOW;
- }
-
- /* Fill color. */
- linearrgb_to_srgb_v4(gp_style->fill_rgba, cu_color);
- /* Fill is false if the original curve hasn't material assigned, so enable it. */
- if (fill) {
- gp_style->flag |= GP_MATERIAL_FILL_SHOW;
- }
-
- /* Check at least one is enabled. */
- if (((gp_style->flag & GP_MATERIAL_STROKE_SHOW) == 0) &&
- ((gp_style->flag & GP_MATERIAL_FILL_SHOW) == 0)) {
- gp_style->flag |= GP_MATERIAL_STROKE_SHOW;
- }
-
- return mat_gp;
-}
-
-/* Helper: Create new stroke section. */
-static void gpencil_add_new_points(bGPDstroke *gps,
- float *coord_array,
- float pressure,
- int init,
- int totpoints,
- const float init_co[3],
- bool last)
-{
- for (int i = 0; i < totpoints; i++) {
- bGPDspoint *pt = &gps->points[i + init];
- copy_v3_v3(&pt->x, &coord_array[3 * i]);
- /* Be sure the last point is not on top of the first point of the curve or
- * the close of the stroke will produce glitches. */
- if ((last) && (i > 0) && (i == totpoints - 1)) {
- float dist = len_v3v3(init_co, &pt->x);
- if (dist < 0.1f) {
- /* Interpolate between previous point and current to back slightly. */
- bGPDspoint *pt_prev = &gps->points[i + init - 1];
- interp_v3_v3v3(&pt->x, &pt_prev->x, &pt->x, 0.95f);
- }
- }
-
- pt->pressure = pressure;
- pt->strength = 1.0f;
- }
-}
-
-/* Helper: Get the first collection that includes the object. */
-static Collection *gpencil_get_parent_collection(Scene *scene, Object *ob)
-{
- Collection *mycol = NULL;
- FOREACH_SCENE_COLLECTION_BEGIN (scene, collection) {
- for (CollectionObject *cob = collection->gobject.first; cob; cob = cob->next) {
- if ((mycol == NULL) && (cob->ob == ob)) {
- mycol = collection;
- }
- }
- }
- FOREACH_SCENE_COLLECTION_END;
-
- return mycol;
-}
-
-/* Helper: Convert one spline to grease pencil stroke. */
-static void gpencil_convert_spline(Main *bmain,
- Object *ob_gp,
- Object *ob_cu,
- const bool gpencil_lines,
- const bool only_stroke,
- bGPDframe *gpf,
- Nurb *nu)
-{
- Curve *cu = (Curve *)ob_cu->data;
- bool cyclic = true;
-
- /* Create Stroke. */
- bGPDstroke *gps = MEM_callocN(sizeof(bGPDstroke), "bGPDstroke");
- gps->thickness = 1.0f;
- gps->fill_opacity_fac = 1.0f;
- gps->hardeness = 1.0f;
- gps->uv_scale = 1.0f;
-
- ARRAY_SET_ITEMS(gps->aspect_ratio, 1.0f, 1.0f);
- ARRAY_SET_ITEMS(gps->caps, GP_STROKE_CAP_ROUND, GP_STROKE_CAP_ROUND);
- gps->inittime = 0.0f;
-
- gps->flag &= ~GP_STROKE_SELECT;
- gps->flag |= GP_STROKE_3DSPACE;
-
- gps->mat_nr = 0;
- /* Count total points
- * The total of points must consider that last point of each segment is equal to the first
- * point of next segment.
- */
- int totpoints = 0;
- int segments = 0;
- int resolu = nu->resolu + 1;
- segments = nu->pntsu;
- if (((nu->flagu & CU_NURB_CYCLIC) == 0) || (nu->pntsu == 2)) {
- segments--;
- cyclic = false;
- }
- totpoints = (resolu * segments) - (segments - 1);
-
- /* Materials
- * Notice: The color of the material is the color of viewport and not the final shader color.
- */
- Material *mat_gp = NULL;
- bool fill = true;
- /* Check if grease pencil has a material with same color.*/
- float color[4];
- if ((cu->mat) && (*cu->mat)) {
- Material *mat_cu = *cu->mat;
- copy_v4_v4(color, &mat_cu->r);
- }
- else {
- /* Gray (unassigned from SVG add-on) */
- zero_v4(color);
- add_v3_fl(color, 0.6f);
- color[3] = 1.0f;
- fill = false;
- }
-
- /* Special case: If the color was created by the SVG add-on and the name contains '_stroke' and
- * there is only one color, the stroke must not be closed, fill to false and use for
- * stroke the fill color.
- */
- bool do_stroke = false;
- if (ob_cu->totcol == 1) {
- Material *ma_stroke = BKE_object_material_get(ob_cu, 1);
- if ((ma_stroke) && (strstr(ma_stroke->id.name, "_stroke") != NULL)) {
- do_stroke = true;
- }
- }
-
- int r_idx = gpencil_check_same_material_color(ob_gp, color, &mat_gp);
- if ((ob_cu->totcol > 0) && (r_idx < 0)) {
- Material *mat_curve = BKE_object_material_get(ob_cu, 1);
- mat_gp = gpencil_add_from_curve_material(bmain, ob_gp, color, gpencil_lines, fill, &r_idx);
-
- if ((mat_curve) && (mat_curve->gp_style != NULL)) {
- MaterialGPencilStyle *gp_style_cur = mat_curve->gp_style;
- MaterialGPencilStyle *gp_style_gp = mat_gp->gp_style;
-
- copy_v4_v4(gp_style_gp->mix_rgba, gp_style_cur->mix_rgba);
- gp_style_gp->fill_style = gp_style_cur->fill_style;
- gp_style_gp->mix_factor = gp_style_cur->mix_factor;
- }
-
- /* If object has more than 1 material, use second material for stroke color. */
- if ((!only_stroke) && (ob_cu->totcol > 1) && (BKE_object_material_get(ob_cu, 2))) {
- mat_curve = BKE_object_material_get(ob_cu, 2);
- if (mat_curve) {
- linearrgb_to_srgb_v3_v3(mat_gp->gp_style->stroke_rgba, &mat_curve->r);
- mat_gp->gp_style->stroke_rgba[3] = mat_curve->a;
- }
- }
- else if ((only_stroke) || (do_stroke)) {
- /* Also use the first color if the fill is none for stroke color. */
- if (ob_cu->totcol > 0) {
- mat_curve = BKE_object_material_get(ob_cu, 1);
- if (mat_curve) {
- copy_v3_v3(mat_gp->gp_style->stroke_rgba, &mat_curve->r);
- mat_gp->gp_style->stroke_rgba[3] = mat_curve->a;
- /* Set fill and stroke depending of curve type (3D or 2D). */
- if ((cu->flag & CU_3D) || ((cu->flag & (CU_FRONT | CU_BACK)) == 0)) {
- mat_gp->gp_style->flag |= GP_MATERIAL_STROKE_SHOW;
- mat_gp->gp_style->flag &= ~GP_MATERIAL_FILL_SHOW;
- }
- else {
- mat_gp->gp_style->flag &= ~GP_MATERIAL_STROKE_SHOW;
- mat_gp->gp_style->flag |= GP_MATERIAL_FILL_SHOW;
- }
- }
- }
- }
- }
- CLAMP_MIN(r_idx, 0);
-
- /* Assign material index to stroke. */
- gps->mat_nr = r_idx;
-
- /* Add stroke to frame.*/
- BLI_addtail(&gpf->strokes, gps);
-
- float *coord_array = NULL;
- float init_co[3];
-
- switch (nu->type) {
- case CU_POLY: {
- /* Allocate memory for storage points. */
- gps->totpoints = nu->pntsu;
- gps->points = MEM_callocN(sizeof(bGPDspoint) * gps->totpoints, "gp_stroke_points");
- /* Increase thickness for this type. */
- gps->thickness = 10.0f;
-
- /* Get all curve points */
- for (int s = 0; s < gps->totpoints; s++) {
- BPoint *bp = &nu->bp[s];
- bGPDspoint *pt = &gps->points[s];
- copy_v3_v3(&pt->x, bp->vec);
- pt->pressure = bp->radius;
- pt->strength = 1.0f;
- }
- break;
- }
- case CU_BEZIER: {
- /* Allocate memory for storage points. */
- gps->totpoints = totpoints;
- gps->points = MEM_callocN(sizeof(bGPDspoint) * gps->totpoints, "gp_stroke_points");
-
- int init = 0;
- resolu = nu->resolu + 1;
- segments = nu->pntsu;
- if (((nu->flagu & CU_NURB_CYCLIC) == 0) || (nu->pntsu == 2)) {
- segments--;
- }
- /* Get all interpolated curve points of Beziert */
- for (int s = 0; s < segments; s++) {
- int inext = (s + 1) % nu->pntsu;
- BezTriple *prevbezt = &nu->bezt[s];
- BezTriple *bezt = &nu->bezt[inext];
- bool last = (bool)(s == segments - 1);
-
- coord_array = MEM_callocN((size_t)3 * resolu * sizeof(float), __func__);
-
- for (int j = 0; j < 3; j++) {
- BKE_curve_forward_diff_bezier(prevbezt->vec[1][j],
- prevbezt->vec[2][j],
- bezt->vec[0][j],
- bezt->vec[1][j],
- coord_array + j,
- resolu - 1,
- 3 * sizeof(float));
- }
- /* Save first point coordinates. */
- if (s == 0) {
- copy_v3_v3(init_co, &coord_array[0]);
- }
- /* Add points to the stroke */
- gpencil_add_new_points(gps, coord_array, bezt->radius, init, resolu, init_co, last);
- /* Free memory. */
- MEM_SAFE_FREE(coord_array);
-
- /* As the last point of segment is the first point of next segment, back one array
- * element to avoid duplicated points on the same location.
- */
- init += resolu - 1;
- }
- break;
- }
- case CU_NURBS: {
- if (nu->pntsv == 1) {
-
- int nurb_points;
- if (nu->flagu & CU_NURB_CYCLIC) {
- resolu++;
- nurb_points = nu->pntsu * resolu;
- }
- else {
- nurb_points = (nu->pntsu - 1) * resolu;
- }
- /* Get all curve points. */
- coord_array = MEM_callocN(sizeof(float[3]) * nurb_points, __func__);
- BKE_nurb_makeCurve(nu, coord_array, NULL, NULL, NULL, resolu, sizeof(float[3]));
-
- /* Allocate memory for storage points. */
- gps->totpoints = nurb_points - 1;
- gps->points = MEM_callocN(sizeof(bGPDspoint) * gps->totpoints, "gp_stroke_points");
-
- /* Add points. */
- gpencil_add_new_points(gps, coord_array, 1.0f, 0, gps->totpoints, init_co, false);
-
- MEM_SAFE_FREE(coord_array);
- }
- break;
- }
- default: {
- break;
- }
- }
- /* Cyclic curve, close stroke. */
- if ((cyclic) && (!do_stroke)) {
- BKE_gpencil_stroke_close(gps);
- }
-
- /* Recalc fill geometry. */
- BKE_gpencil_stroke_geometry_update(gps);
-}
-
-/* Convert a curve object to grease pencil stroke.
- *
- * \param bmain: Main thread pointer
- * \param scene: Original scene.
- * \param ob_gp: Grease pencil object to add strokes.
- * \param ob_cu: Curve to convert.
- * \param gpencil_lines: Use lines for strokes.
- * \param use_collections: Create layers using collection names.
- * \param only_stroke: The material must be only stroke without fill.
- */
-void BKE_gpencil_convert_curve(Main *bmain,
- Scene *scene,
- Object *ob_gp,
- Object *ob_cu,
- const bool gpencil_lines,
- const bool use_collections,
- const bool only_stroke)
-{
- if (ELEM(NULL, ob_gp, ob_cu) || (ob_gp->type != OB_GPENCIL) || (ob_gp->data == NULL)) {
- return;
- }
-
- Curve *cu = (Curve *)ob_cu->data;
- bGPdata *gpd = (bGPdata *)ob_gp->data;
- bGPDlayer *gpl = NULL;
-
- /* If the curve is empty, cancel. */
- if (cu->nurb.first == NULL) {
- return;
- }
-
- /* Check if there is an active layer. */
- if (use_collections) {
- Collection *collection = gpencil_get_parent_collection(scene, ob_cu);
- if (collection != NULL) {
- gpl = BKE_gpencil_layer_named_get(gpd, collection->id.name + 2);
- if (gpl == NULL) {
- gpl = BKE_gpencil_layer_addnew(gpd, collection->id.name + 2, true);
- }
- }
- }
-
- if (gpl == NULL) {
- gpl = BKE_gpencil_layer_active_get(gpd);
- if (gpl == NULL) {
- gpl = BKE_gpencil_layer_addnew(gpd, DATA_("GP_Layer"), true);
- }
- }
-
- /* Check if there is an active frame and add if needed. */
- bGPDframe *gpf = BKE_gpencil_layer_frame_get(gpl, CFRA, GP_GETFRAME_ADD_COPY);
-
- /* Read all splines of the curve and create a stroke for each. */
- for (Nurb *nu = cu->nurb.first; nu; nu = nu->next) {
- gpencil_convert_spline(bmain, ob_gp, ob_cu, gpencil_lines, only_stroke, gpf, nu);
- }
-
- /* Tag for recalculation */
- DEG_id_tag_update(&gpd->id, ID_RECALC_GEOMETRY | ID_RECALC_COPY_ON_WRITE);
-}
-
/* Apply Transforms */
void BKE_gpencil_transform(bGPdata *gpd, float mat[4][4])
{
diff --git a/source/blender/blenkernel/intern/gpencil_modifier.c b/source/blender/blenkernel/intern/gpencil_modifier.c
index 0bb6ce84b1b..b889b91e366 100644
--- a/source/blender/blenkernel/intern/gpencil_modifier.c
+++ b/source/blender/blenkernel/intern/gpencil_modifier.c
@@ -318,7 +318,7 @@ bool BKE_gpencil_has_geometry_modifiers(Object *ob)
{
GpencilModifierData *md;
for (md = ob->greasepencil_modifiers.first; md; md = md->next) {
- const GpencilModifierTypeInfo *mti = BKE_gpencil_modifierType_getInfo(md->type);
+ const GpencilModifierTypeInfo *mti = BKE_gpencil_modifier_get_info(md->type);
if (mti && mti->generateStrokes) {
return true;
@@ -332,7 +332,7 @@ bool BKE_gpencil_has_time_modifiers(Object *ob)
{
GpencilModifierData *md;
for (md = ob->greasepencil_modifiers.first; md; md = md->next) {
- const GpencilModifierTypeInfo *mti = BKE_gpencil_modifierType_getInfo(md->type);
+ const GpencilModifierTypeInfo *mti = BKE_gpencil_modifier_get_info(md->type);
if (mti && mti->remapTime) {
return true;
@@ -369,7 +369,7 @@ static int gpencil_time_modifier(
for (md = ob->greasepencil_modifiers.first; md; md = md->next) {
if (GPENCIL_MODIFIER_ACTIVE(md, is_render)) {
- const GpencilModifierTypeInfo *mti = BKE_gpencil_modifierType_getInfo(md->type);
+ const GpencilModifierTypeInfo *mti = BKE_gpencil_modifier_get_info(md->type);
if ((GPENCIL_MODIFIER_EDIT(md, is_edit)) && (!is_render)) {
continue;
@@ -421,7 +421,7 @@ void BKE_gpencil_modifier_init(void)
GpencilModifierData *BKE_gpencil_modifier_new(int type)
{
- const GpencilModifierTypeInfo *mti = BKE_gpencil_modifierType_getInfo(type);
+ const GpencilModifierTypeInfo *mti = BKE_gpencil_modifier_get_info(type);
GpencilModifierData *md = MEM_callocN(mti->struct_size, mti->struct_name);
/* note, this name must be made unique later */
@@ -456,7 +456,7 @@ static void modifier_free_data_id_us_cb(void *UNUSED(userData),
void BKE_gpencil_modifier_free_ex(GpencilModifierData *md, const int flag)
{
- const GpencilModifierTypeInfo *mti = BKE_gpencil_modifierType_getInfo(md->type);
+ const GpencilModifierTypeInfo *mti = BKE_gpencil_modifier_get_info(md->type);
if ((flag & LIB_ID_CREATE_NO_USER_REFCOUNT) == 0) {
if (mti->foreachIDLink) {
@@ -487,7 +487,7 @@ void BKE_gpencil_modifier_free(GpencilModifierData *md)
bool BKE_gpencil_modifier_unique_name(ListBase *modifiers, GpencilModifierData *gmd)
{
if (modifiers && gmd) {
- const GpencilModifierTypeInfo *gmti = BKE_gpencil_modifierType_getInfo(gmd->type);
+ const GpencilModifierTypeInfo *gmti = BKE_gpencil_modifier_get_info(gmd->type);
return BLI_uniquename(modifiers,
gmd,
DATA_(gmti->name),
@@ -498,14 +498,14 @@ bool BKE_gpencil_modifier_unique_name(ListBase *modifiers, GpencilModifierData *
return false;
}
-bool BKE_gpencil_modifier_dependsOnTime(GpencilModifierData *md)
+bool BKE_gpencil_modifier_depends_ontime(GpencilModifierData *md)
{
- const GpencilModifierTypeInfo *mti = BKE_gpencil_modifierType_getInfo(md->type);
+ const GpencilModifierTypeInfo *mti = BKE_gpencil_modifier_get_info(md->type);
return mti->dependsOnTime && mti->dependsOnTime(md);
}
-const GpencilModifierTypeInfo *BKE_gpencil_modifierType_getInfo(GpencilModifierType type)
+const GpencilModifierTypeInfo *BKE_gpencil_modifier_get_info(GpencilModifierType type)
{
/* type unsigned, no need to check < 0 */
if (type < NUM_GREASEPENCIL_MODIFIER_TYPES && modifier_gpencil_types[type]->name[0] != '\0') {
@@ -516,10 +516,10 @@ const GpencilModifierTypeInfo *BKE_gpencil_modifierType_getInfo(GpencilModifierT
}
}
-void BKE_gpencil_modifier_copyData_generic(const GpencilModifierData *md_src,
+void BKE_gpencil_modifier_copydata_generic(const GpencilModifierData *md_src,
GpencilModifierData *md_dst)
{
- const GpencilModifierTypeInfo *mti = BKE_gpencil_modifierType_getInfo(md_src->type);
+ const GpencilModifierTypeInfo *mti = BKE_gpencil_modifier_get_info(md_src->type);
/* md_dst may have already be fully initialized with some extra allocated data,
* we need to free it now to avoid memleak. */
@@ -545,11 +545,11 @@ static void gpencil_modifier_copy_data_id_us_cb(void *UNUSED(userData),
}
}
-void BKE_gpencil_modifier_copyData_ex(GpencilModifierData *md,
+void BKE_gpencil_modifier_copydata_ex(GpencilModifierData *md,
GpencilModifierData *target,
const int flag)
{
- const GpencilModifierTypeInfo *mti = BKE_gpencil_modifierType_getInfo(md->type);
+ const GpencilModifierTypeInfo *mti = BKE_gpencil_modifier_get_info(md->type);
target->mode = md->mode;
target->flag = md->flag;
@@ -569,12 +569,12 @@ void BKE_gpencil_modifier_copyData_ex(GpencilModifierData *md,
}
}
-void BKE_gpencil_modifier_copyData(GpencilModifierData *md, GpencilModifierData *target)
+void BKE_gpencil_modifier_copydata(GpencilModifierData *md, GpencilModifierData *target)
{
- BKE_gpencil_modifier_copyData_ex(md, target, 0);
+ BKE_gpencil_modifier_copydata_ex(md, target, 0);
}
-GpencilModifierData *BKE_gpencil_modifiers_findByType(Object *ob, GpencilModifierType type)
+GpencilModifierData *BKE_gpencil_modifiers_findby_type(Object *ob, GpencilModifierType type)
{
GpencilModifierData *md = ob->greasepencil_modifiers.first;
@@ -587,12 +587,12 @@ GpencilModifierData *BKE_gpencil_modifiers_findByType(Object *ob, GpencilModifie
return md;
}
-void BKE_gpencil_modifiers_foreachIDLink(Object *ob, GreasePencilIDWalkFunc walk, void *userData)
+void BKE_gpencil_modifiers_foreach_ID_link(Object *ob, GreasePencilIDWalkFunc walk, void *userData)
{
GpencilModifierData *md = ob->greasepencil_modifiers.first;
for (; md; md = md->next) {
- const GpencilModifierTypeInfo *mti = BKE_gpencil_modifierType_getInfo(md->type);
+ const GpencilModifierTypeInfo *mti = BKE_gpencil_modifier_get_info(md->type);
if (mti->foreachIDLink) {
mti->foreachIDLink(md, ob, walk, userData);
@@ -605,12 +605,14 @@ void BKE_gpencil_modifiers_foreachIDLink(Object *ob, GreasePencilIDWalkFunc walk
}
}
-void BKE_gpencil_modifiers_foreachTexLink(Object *ob, GreasePencilTexWalkFunc walk, void *userData)
+void BKE_gpencil_modifiers_foreach_tex_link(Object *ob,
+ GreasePencilTexWalkFunc walk,
+ void *userData)
{
GpencilModifierData *md = ob->greasepencil_modifiers.first;
for (; md; md = md->next) {
- const GpencilModifierTypeInfo *mti = BKE_gpencil_modifierType_getInfo(md->type);
+ const GpencilModifierTypeInfo *mti = BKE_gpencil_modifier_get_info(md->type);
if (mti->foreachTexLink) {
mti->foreachTexLink(md, ob, walk, userData);
@@ -618,7 +620,7 @@ void BKE_gpencil_modifiers_foreachTexLink(Object *ob, GreasePencilTexWalkFunc wa
}
}
-GpencilModifierData *BKE_gpencil_modifiers_findByName(Object *ob, const char *name)
+GpencilModifierData *BKE_gpencil_modifiers_findby_name(Object *ob, const char *name)
{
return BLI_findstring(&(ob->greasepencil_modifiers), name, offsetof(GpencilModifierData, name));
}
@@ -684,6 +686,7 @@ void BKE_gpencil_stroke_subdivide(bGPDstroke *gps, int level, int type)
CLAMP(pt_final->strength, GPENCIL_STRENGTH_MIN, 1.0f);
pt_final->time = interpf(pt->time, next->time, 0.5f);
pt_final->runtime.pt_orig = NULL;
+ pt_final->flag = 0;
interp_v4_v4v4(pt_final->vert_color, pt->vert_color, next->vert_color, 0.5f);
if (gps->dvert != NULL) {
@@ -880,7 +883,7 @@ void BKE_gpencil_modifiers_calc(Depsgraph *depsgraph, Scene *scene, Object *ob)
LISTBASE_FOREACH (GpencilModifierData *, md, &ob->greasepencil_modifiers) {
if (GPENCIL_MODIFIER_ACTIVE(md, is_render)) {
- const GpencilModifierTypeInfo *mti = BKE_gpencil_modifierType_getInfo(md->type);
+ const GpencilModifierTypeInfo *mti = BKE_gpencil_modifier_get_info(md->type);
if ((GPENCIL_MODIFIER_EDIT(md, is_edit)) && (!is_render)) {
continue;
diff --git a/source/blender/blenkernel/intern/hair.c b/source/blender/blenkernel/intern/hair.c
index e17c6a00144..90761d24b73 100644
--- a/source/blender/blenkernel/intern/hair.c
+++ b/source/blender/blenkernel/intern/hair.c
@@ -22,6 +22,7 @@
#include "DNA_defaults.h"
#include "DNA_hair_types.h"
+#include "DNA_material_types.h"
#include "DNA_object_types.h"
#include "BLI_listbase.h"
@@ -30,7 +31,7 @@
#include "BLI_string.h"
#include "BLI_utildefines.h"
-#include "BKE_animsys.h"
+#include "BKE_anim_data.h"
#include "BKE_customdata.h"
#include "BKE_global.h"
#include "BKE_hair.h"
@@ -48,50 +49,7 @@
/* Hair datablock */
-static void hair_random(Hair *hair)
-{
- const int numpoints = 8;
-
- hair->totcurve = 500;
- hair->totpoint = hair->totcurve * numpoints;
-
- CustomData_realloc(&hair->pdata, hair->totpoint);
- CustomData_realloc(&hair->cdata, hair->totcurve);
- BKE_hair_update_customdata_pointers(hair);
-
- RNG *rng = BLI_rng_new(0);
-
- for (int i = 0; i < hair->totcurve; i++) {
- HairCurve *curve = &hair->curves[i];
- curve->firstpoint = i * numpoints;
- curve->numpoints = numpoints;
-
- float theta = 2.0f * M_PI * BLI_rng_get_float(rng);
- float phi = saacosf(2.0f * BLI_rng_get_float(rng) - 1.0f);
-
- float no[3] = {sinf(theta) * sinf(phi), cosf(theta) * sinf(phi), cosf(phi)};
- normalize_v3(no);
-
- float co[3];
- copy_v3_v3(co, no);
-
- float(*curve_co)[3] = hair->co + curve->firstpoint;
- float *curve_radius = hair->radius + curve->firstpoint;
- for (int key = 0; key < numpoints; key++) {
- float t = key / (float)(numpoints - 1);
- copy_v3_v3(curve_co[key], co);
- curve_radius[key] = 0.02f * (1.0f - t);
-
- float offset[3] = {2.0f * BLI_rng_get_float(rng) - 1.0f,
- 2.0f * BLI_rng_get_float(rng) - 1.0f,
- 2.0f * BLI_rng_get_float(rng) - 1.0f};
- add_v3_v3(offset, no);
- madd_v3_v3fl(co, offset, 1.0f / numpoints);
- }
- }
-
- BLI_rng_free(rng);
-}
+static void hair_random(Hair *hair);
static void hair_init_data(ID *id)
{
@@ -111,15 +69,6 @@ static void hair_init_data(ID *id)
hair_random(hair);
}
-void *BKE_hair_add(Main *bmain, const char *name)
-{
- Hair *hair = BKE_libblock_alloc(bmain, ID_HA, name, 0);
-
- hair_init_data(&hair->id);
-
- return hair;
-}
-
static void hair_copy_data(Main *UNUSED(bmain), ID *id_dst, const ID *id_src, const int flag)
{
Hair *hair_dst = (Hair *)id_dst;
@@ -134,18 +83,6 @@ static void hair_copy_data(Main *UNUSED(bmain), ID *id_dst, const ID *id_src, co
hair_dst->batch_cache = NULL;
}
-Hair *BKE_hair_copy(Main *bmain, const Hair *hair)
-{
- Hair *hair_copy;
- BKE_id_copy(bmain, &hair->id, (ID **)&hair_copy);
- return hair_copy;
-}
-
-static void hair_make_local(Main *bmain, ID *id, const int flags)
-{
- BKE_lib_id_make_local_generic(bmain, id, flags);
-}
-
static void hair_free_data(ID *id)
{
Hair *hair = (Hair *)id;
@@ -159,6 +96,14 @@ static void hair_free_data(ID *id)
MEM_SAFE_FREE(hair->mat);
}
+static void hair_foreach_id(ID *id, LibraryForeachIDData *data)
+{
+ Hair *hair = (Hair *)id;
+ for (int i = 0; i < hair->totcol; i++) {
+ BKE_LIB_FOREACHID_PROCESS(data, hair->mat[i], IDWALK_CB_USER);
+ }
+}
+
IDTypeInfo IDType_ID_HA = {
.id_code = ID_HA,
.id_filter = FILTER_ID_HA,
@@ -172,9 +117,71 @@ IDTypeInfo IDType_ID_HA = {
.init_data = hair_init_data,
.copy_data = hair_copy_data,
.free_data = hair_free_data,
- .make_local = hair_make_local,
+ .make_local = NULL,
+ .foreach_id = hair_foreach_id,
};
+static void hair_random(Hair *hair)
+{
+ const int numpoints = 8;
+
+ hair->totcurve = 500;
+ hair->totpoint = hair->totcurve * numpoints;
+
+ CustomData_realloc(&hair->pdata, hair->totpoint);
+ CustomData_realloc(&hair->cdata, hair->totcurve);
+ BKE_hair_update_customdata_pointers(hair);
+
+ RNG *rng = BLI_rng_new(0);
+
+ for (int i = 0; i < hair->totcurve; i++) {
+ HairCurve *curve = &hair->curves[i];
+ curve->firstpoint = i * numpoints;
+ curve->numpoints = numpoints;
+
+ float theta = 2.0f * M_PI * BLI_rng_get_float(rng);
+ float phi = saacosf(2.0f * BLI_rng_get_float(rng) - 1.0f);
+
+ float no[3] = {sinf(theta) * sinf(phi), cosf(theta) * sinf(phi), cosf(phi)};
+ normalize_v3(no);
+
+ float co[3];
+ copy_v3_v3(co, no);
+
+ float(*curve_co)[3] = hair->co + curve->firstpoint;
+ float *curve_radius = hair->radius + curve->firstpoint;
+ for (int key = 0; key < numpoints; key++) {
+ float t = key / (float)(numpoints - 1);
+ copy_v3_v3(curve_co[key], co);
+ curve_radius[key] = 0.02f * (1.0f - t);
+
+ float offset[3] = {2.0f * BLI_rng_get_float(rng) - 1.0f,
+ 2.0f * BLI_rng_get_float(rng) - 1.0f,
+ 2.0f * BLI_rng_get_float(rng) - 1.0f};
+ add_v3_v3(offset, no);
+ madd_v3_v3fl(co, offset, 1.0f / numpoints);
+ }
+ }
+
+ BLI_rng_free(rng);
+}
+
+void *BKE_hair_add(Main *bmain, const char *name)
+{
+ Hair *hair = BKE_libblock_alloc(bmain, ID_HA, name, 0);
+
+ hair_init_data(&hair->id);
+
+ return hair;
+}
+
+Hair *BKE_hair_copy(Main *bmain, const Hair *hair)
+{
+ Hair *hair_copy;
+ BKE_id_copy(bmain, &hair->id, (ID **)&hair_copy);
+ return hair_copy;
+}
+
BoundBox *BKE_hair_boundbox_get(Object *ob)
{
BLI_assert(ob->type == OB_HAIR);
@@ -247,12 +254,65 @@ Hair *BKE_hair_copy_for_eval(Hair *hair_src, bool reference)
return result;
}
-static Hair *hair_evaluate_modifiers(struct Depsgraph *UNUSED(depsgraph),
- struct Scene *UNUSED(scene),
- Object *UNUSED(object),
+static Hair *hair_evaluate_modifiers(struct Depsgraph *depsgraph,
+ struct Scene *scene,
+ Object *object,
Hair *hair_input)
{
- return hair_input;
+ Hair *hair = hair_input;
+
+ /* Modifier evaluation modes. */
+ const bool use_render = (DEG_get_mode(depsgraph) == DAG_EVAL_RENDER);
+ const int required_mode = use_render ? eModifierMode_Render : eModifierMode_Realtime;
+ ModifierApplyFlag apply_flag = use_render ? MOD_APPLY_RENDER : MOD_APPLY_USECACHE;
+ const ModifierEvalContext mectx = {depsgraph, object, apply_flag};
+
+ /* Get effective list of modifiers to execute. Some effects like shape keys
+ * are added as virtual modifiers before the user created modifiers. */
+ VirtualModifierData virtualModifierData;
+ ModifierData *md = BKE_modifiers_get_virtual_modifierlist(object, &virtualModifierData);
+
+ /* Evaluate modifiers. */
+ for (; md; md = md->next) {
+ const ModifierTypeInfo *mti = BKE_modifier_get_info(md->type);
+
+ if (!BKE_modifier_is_enabled(scene, md, required_mode)) {
+ continue;
+ }
+
+ if ((mti->type == eModifierTypeType_OnlyDeform) &&
+ (mti->flags & eModifierTypeFlag_AcceptsVertexCosOnly)) {
+ /* Ensure we are not modifying the input. */
+ if (hair == hair_input) {
+ hair = BKE_hair_copy_for_eval(hair, true);
+ }
+
+ /* Ensure we are not overwriting referenced data. */
+ CustomData_duplicate_referenced_layer(&hair->pdata, CD_LOCATION, hair->totpoint);
+ BKE_hair_update_customdata_pointers(hair);
+
+ /* Created deformed coordinates array on demand. */
+ mti->deformVerts(md, &mectx, NULL, hair->co, hair->totpoint);
+ }
+ else if (mti->modifyHair) {
+ /* Ensure we are not modifying the input. */
+ if (hair == hair_input) {
+ hair = BKE_hair_copy_for_eval(hair, true);
+ }
+
+ Hair *hair_next = mti->modifyHair(md, &mectx, hair);
+
+ if (hair_next && hair_next != hair) {
+ /* If the modifier returned a new hair, release the old one. */
+ if (hair != hair_input) {
+ BKE_id_free(NULL, hair);
+ }
+ hair = hair_next;
+ }
+ }
+ }
+
+ return hair;
}
void BKE_hair_data_update(struct Depsgraph *depsgraph, struct Scene *scene, Object *object)
diff --git a/source/blender/blenkernel/intern/idprop.c b/source/blender/blenkernel/intern/idprop.c
index 554b8d93db3..669539ca574 100644
--- a/source/blender/blenkernel/intern/idprop.c
+++ b/source/blender/blenkernel/intern/idprop.c
@@ -800,7 +800,7 @@ void IDP_RelinkProperty(struct IDProperty *prop)
switch (prop->type) {
case IDP_GROUP: {
- for (IDProperty *loop = prop->data.group.first; loop; loop = loop->next) {
+ LISTBASE_FOREACH (IDProperty *, loop, &prop->data.group) {
IDP_RelinkProperty(loop);
}
break;
@@ -1130,4 +1130,45 @@ void IDP_Reset(IDProperty *prop, const IDProperty *reference)
}
}
+/**
+ * Loop through all ID properties in hierarchy of given \a id_property_root included.
+ *
+ * \note Container types (groups and arrays) are processed after applying the callback on them.
+ *
+ * \param type_filter: If not 0, only apply callback on properties of matching types, see
+ * IDP_TYPE_FILTER_ enum in DNA_ID.h.
+ */
+void IDP_foreach_property(IDProperty *id_property_root,
+ const int type_filter,
+ IDPForeachPropertyCallback callback,
+ void *user_data)
+{
+ if (!id_property_root) {
+ return;
+ }
+
+ if (type_filter == 0 || (1 << id_property_root->type) & type_filter) {
+ callback(id_property_root, user_data);
+ }
+
+ /* Recursive call into container types of ID properties. */
+ switch (id_property_root->type) {
+ case IDP_GROUP: {
+ LISTBASE_FOREACH (IDProperty *, loop, &id_property_root->data.group) {
+ IDP_foreach_property(loop, type_filter, callback, user_data);
+ }
+ break;
+ }
+ case IDP_IDPARRAY: {
+ IDProperty *loop = IDP_Array(id_property_root);
+ for (int i = 0; i < id_property_root->len; i++) {
+ IDP_foreach_property(&loop[i], type_filter, callback, user_data);
+ }
+ break;
+ }
+ default:
+ break; /* Nothing to do here with other types of IDProperties... */
+ }
+}
+
/** \} */
diff --git a/source/blender/blenkernel/intern/idprop_utils.c b/source/blender/blenkernel/intern/idprop_utils.c
index a7dd6afd10d..f8a1113f69b 100644
--- a/source/blender/blenkernel/intern/idprop_utils.c
+++ b/source/blender/blenkernel/intern/idprop_utils.c
@@ -22,6 +22,7 @@
#include <string.h>
#include "BLI_dynstr.h"
+#include "BLI_listbase.h"
#include "BLI_string.h"
#include "BLI_utildefines.h"
@@ -166,7 +167,7 @@ static void idp_repr_fn_recursive(struct ReprState *state, const IDProperty *pro
}
case IDP_GROUP: {
STR_APPEND_STR("{");
- for (const IDProperty *subprop = prop->data.group.first; subprop; subprop = subprop->next) {
+ LISTBASE_FOREACH (const IDProperty *, subprop, &prop->data.group) {
if (subprop != prop->data.group.first) {
STR_APPEND_STR(", ");
}
diff --git a/source/blender/blenkernel/intern/idtype.c b/source/blender/blenkernel/intern/idtype.c
index b7fc167cf33..fcd3bc9c5b4 100644
--- a/source/blender/blenkernel/intern/idtype.c
+++ b/source/blender/blenkernel/intern/idtype.c
@@ -10,7 +10,7 @@
* 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,
+ * 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) 2005 by the Blender Foundation.
@@ -92,6 +92,7 @@ static void id_type_init(void)
INIT_TYPE(ID_HA);
INIT_TYPE(ID_PT);
INIT_TYPE(ID_VO);
+ INIT_TYPE(ID_SIM);
/* Special naughty boy... */
BLI_assert(IDType_ID_LINK_PLACEHOLDER.main_listbase_index == INDEX_ID_NULL);
@@ -124,10 +125,10 @@ const IDTypeInfo *BKE_idtype_get_info_from_id(const ID *id)
return BKE_idtype_get_info_from_idcode(GS(id->name));
}
-static const IDTypeInfo *idtype_get_info_from_name(const char *str)
+static const IDTypeInfo *idtype_get_info_from_name(const char *idtype_name)
{
for (int i = ARRAY_SIZE(id_types); i--;) {
- if (id_types[i] != NULL && STREQ(str, id_types[i]->name)) {
+ if (id_types[i] != NULL && STREQ(idtype_name, id_types[i]->name)) {
return id_types[i];
}
}
@@ -179,14 +180,14 @@ const char *BKE_idtype_idcode_to_translation_context(const short idcode)
}
/**
- * Convert a name into an idcode (ie. ID_SCE)
+ * Convert an IDType name into an idcode (ie. ID_SCE)
*
- * \param name: The name to convert.
- * \return The code for the name, or 0 if invalid.
+ * \param idtype_name: The IDType's 'user visible name' to convert.
+ * \return The idcode for the name, or 0 if invalid.
*/
-short BKE_idtype_idcode_from_name(const char *name)
+short BKE_idtype_idcode_from_name(const char *idtype_name)
{
- const IDTypeInfo *id_type = idtype_get_info_from_name(name);
+ const IDTypeInfo *id_type = idtype_get_info_from_name(idtype_name);
BLI_assert(id_type);
return id_type != NULL ? id_type->id_code : 0;
}
@@ -251,6 +252,7 @@ uint64_t BKE_idtype_idcode_to_idfilter(const short idcode)
CASE_IDFILTER(PT);
CASE_IDFILTER(LP);
CASE_IDFILTER(SCE);
+ CASE_IDFILTER(SIM);
CASE_IDFILTER(SPK);
CASE_IDFILTER(SO);
CASE_IDFILTER(TE);
@@ -302,6 +304,7 @@ short BKE_idtype_idcode_from_idfilter(const uint64_t idfilter)
CASE_IDFILTER(PT);
CASE_IDFILTER(LP);
CASE_IDFILTER(SCE);
+ CASE_IDFILTER(SIM);
CASE_IDFILTER(SPK);
CASE_IDFILTER(SO);
CASE_IDFILTER(TE);
@@ -356,6 +359,7 @@ int BKE_idtype_idcode_to_index(const short idcode)
CASE_IDINDEX(LP);
CASE_IDINDEX(SCE);
CASE_IDINDEX(SCR);
+ CASE_IDINDEX(SIM);
CASE_IDINDEX(SPK);
CASE_IDINDEX(SO);
CASE_IDINDEX(TE);
@@ -417,6 +421,7 @@ short BKE_idtype_idcode_from_index(const int index)
CASE_IDCODE(LP);
CASE_IDCODE(SCE);
CASE_IDCODE(SCR);
+ CASE_IDCODE(SIM);
CASE_IDCODE(SPK);
CASE_IDCODE(SO);
CASE_IDCODE(TE);
diff --git a/source/blender/blenkernel/intern/image.c b/source/blender/blenkernel/intern/image.c
index 5dca9bf2ac5..b4a3f249c63 100644
--- a/source/blender/blenkernel/intern/image.c
+++ b/source/blender/blenkernel/intern/image.c
@@ -199,6 +199,7 @@ IDTypeInfo IDType_ID_IM = {
.copy_data = image_copy_data,
.free_data = image_free_data,
.make_local = NULL,
+ .foreach_id = NULL,
};
/* prototypes */
@@ -571,7 +572,7 @@ ImageTile *BKE_image_get_tile(Image *ima, int tile_number)
return NULL;
}
-ImageTile *BKE_image_get_tile_from_iuser(Image *ima, ImageUser *iuser)
+ImageTile *BKE_image_get_tile_from_iuser(Image *ima, const ImageUser *iuser)
{
return BKE_image_get_tile(ima, (iuser && iuser->tile) ? iuser->tile : 1001);
}
@@ -3101,7 +3102,7 @@ static void image_walk_ntree_all_users(
{
switch (ntree->type) {
case NTREE_SHADER:
- for (bNode *node = ntree->nodes.first; node; node = node->next) {
+ LISTBASE_FOREACH (bNode *, node, &ntree->nodes) {
if (node->id) {
if (node->type == SH_NODE_TEX_IMAGE) {
NodeTexImage *tex = node->storage;
@@ -3117,7 +3118,7 @@ static void image_walk_ntree_all_users(
}
break;
case NTREE_TEXTURE:
- for (bNode *node = ntree->nodes.first; node; node = node->next) {
+ LISTBASE_FOREACH (bNode *, node, &ntree->nodes) {
if (node->id && node->type == TEX_NODE_IMAGE) {
Image *ima = (Image *)node->id;
ImageUser *iuser = node->storage;
@@ -3126,7 +3127,7 @@ static void image_walk_ntree_all_users(
}
break;
case NTREE_COMPOSIT:
- for (bNode *node = ntree->nodes.first; node; node = node->next) {
+ LISTBASE_FOREACH (bNode *, node, &ntree->nodes) {
if (node->id && node->type == CMP_NODE_IMAGE) {
Image *ima = (Image *)node->id;
ImageUser *iuser = node->storage;
@@ -3189,19 +3190,19 @@ static void image_walk_id_all_users(
}
case ID_CA: {
Camera *cam = (Camera *)id;
- for (CameraBGImage *bgpic = cam->bg_images.first; bgpic; bgpic = bgpic->next) {
+ LISTBASE_FOREACH (CameraBGImage *, bgpic, &cam->bg_images) {
callback(bgpic->ima, NULL, &bgpic->iuser, customdata);
}
break;
}
case ID_WM: {
wmWindowManager *wm = (wmWindowManager *)id;
- for (wmWindow *win = wm->windows.first; win; win = win->next) {
+ LISTBASE_FOREACH (wmWindow *, win, &wm->windows) {
const bScreen *screen = BKE_workspace_active_screen_get(win->workspace_hook);
- for (ScrArea *sa = screen->areabase.first; sa; sa = sa->next) {
- if (sa->spacetype == SPACE_IMAGE) {
- SpaceImage *sima = sa->spacedata.first;
+ LISTBASE_FOREACH (ScrArea *, area, &screen->areabase) {
+ if (area->spacetype == SPACE_IMAGE) {
+ SpaceImage *sima = area->spacedata.first;
callback(sima->image, NULL, &sima->iuser, customdata);
}
}
@@ -3761,7 +3762,7 @@ static void image_init_multilayer_multiview(Image *ima, RenderResult *rr)
BKE_image_free_views(ima);
if (rr) {
- for (RenderView *rv = rr->views.first; rv; rv = rv->next) {
+ LISTBASE_FOREACH (RenderView *, rv, &rr->views) {
ImageView *iv = MEM_callocN(sizeof(ImageView), "Viewer Image View");
STRNCPY(iv->name, rv->name);
BLI_addtail(&ima->views, iv);
@@ -3977,7 +3978,9 @@ static ImBuf *load_sequence_single(
iuser_t = *iuser;
}
else {
- /* TODO(sergey): Do we need to initialize something here? */
+ /* BKE_image_user_file_path() uses this value for file name for sequences. */
+ iuser_t.framenr = frame;
+ /* TODO(sergey): Do we need to initialize something else here? */
}
iuser_t.view = view_id;
@@ -4794,7 +4797,7 @@ static ImBuf *image_get_cached_ibuf(Image *ima, ImageUser *iuser, int *r_entry,
return ibuf;
}
-BLI_INLINE bool image_quick_test(Image *ima, ImageUser *iuser)
+BLI_INLINE bool image_quick_test(Image *ima, const ImageUser *iuser)
{
if (ima == NULL) {
return false;
@@ -5316,8 +5319,8 @@ void BKE_image_user_file_path(ImageUser *iuser, Image *ima, char *filepath)
index = (iuser && iuser->tile) ? iuser->tile : 1001;
}
- BLI_stringdec(filepath, head, tail, &numlen);
- BLI_stringenc(filepath, head, tail, numlen, index);
+ BLI_path_sequence_decode(filepath, head, tail, &numlen);
+ BLI_path_sequence_encode(filepath, head, tail, numlen, index);
}
BLI_path_abs(filepath, ID_BLEND_PATH_FROM_GLOBAL(&ima->id));
@@ -5458,7 +5461,7 @@ float *BKE_image_get_float_pixels_for_frame(struct Image *image, int frame, int
int BKE_image_sequence_guess_offset(Image *image)
{
- return BLI_stringdec(image->name, NULL, NULL, NULL);
+ return BLI_path_sequence_decode(image->name, NULL, NULL, NULL);
}
bool BKE_image_has_anim(Image *ima)
@@ -5724,6 +5727,13 @@ RenderSlot *BKE_image_add_renderslot(Image *ima, const char *name)
bool BKE_image_remove_renderslot(Image *ima, ImageUser *iuser, int index)
{
+ if (index == ima->last_render_slot) {
+ /* Don't remove render slot while rendering to it. */
+ if (G.is_rendering) {
+ return false;
+ }
+ }
+
int num_slots = BLI_listbase_count(&ima->renderslots);
if (index >= num_slots || num_slots == 1) {
return false;
diff --git a/source/blender/blenkernel/intern/image_save.c b/source/blender/blenkernel/intern/image_save.c
index bd570c9688b..c034fe895a6 100644
--- a/source/blender/blenkernel/intern/image_save.c
+++ b/source/blender/blenkernel/intern/image_save.c
@@ -54,13 +54,13 @@ void BKE_image_save_options_init(ImageSaveOptions *opts, Main *bmain, Scene *sce
}
static void image_save_post(ReportList *reports,
- Main *bmain,
Image *ima,
ImBuf *ibuf,
int ok,
ImageSaveOptions *opts,
int save_copy,
- const char *filepath)
+ const char *filepath,
+ bool *r_colorspace_changed)
{
if (!ok) {
BKE_reportf(reports, RPT_ERROR, "Could not write image: %s", strerror(errno));
@@ -114,7 +114,7 @@ static void image_save_post(ReportList *reports,
IMB_colormanagement_colorspace_from_ibuf_ftype(&ima->colorspace_settings, ibuf);
if (!BKE_color_managed_colorspace_settings_equals(&old_colorspace_settings,
&ima->colorspace_settings)) {
- BKE_image_signal(bmain, ima, NULL, IMA_SIGNAL_COLORMANAGE);
+ *r_colorspace_changed = true;
}
}
@@ -138,8 +138,11 @@ static void imbuf_save_post(ImBuf *ibuf, ImBuf *colormanaged_ibuf)
* \note ``ima->name`` and ``ibuf->name`` should end up the same.
* \note for multiview the first ``ibuf`` is important to get the settings.
*/
-static bool image_save_single(
- ReportList *reports, Main *bmain, Image *ima, ImageUser *iuser, ImageSaveOptions *opts)
+static bool image_save_single(ReportList *reports,
+ Image *ima,
+ ImageUser *iuser,
+ ImageSaveOptions *opts,
+ bool *r_colorspace_changed)
{
void *lock;
ImBuf *ibuf = BKE_image_acquire_ibuf(ima, iuser, &lock);
@@ -223,7 +226,7 @@ static bool image_save_single(
if (imf->views_format == R_IMF_VIEWS_MULTIVIEW && is_exr_rr) {
/* save render result */
ok = RE_WriteRenderResult(reports, rr, opts->filepath, imf, NULL, layer);
- image_save_post(reports, bmain, ima, ibuf, ok, opts, true, opts->filepath);
+ image_save_post(reports, ima, ibuf, ok, opts, true, opts->filepath, r_colorspace_changed);
BKE_image_release_ibuf(ima, ibuf, lock);
}
/* regular mono pipeline */
@@ -237,8 +240,14 @@ static bool image_save_single(
ok = BKE_imbuf_write_as(colormanaged_ibuf, opts->filepath, imf, save_copy);
imbuf_save_post(ibuf, colormanaged_ibuf);
}
- image_save_post(
- reports, bmain, ima, ibuf, ok, opts, (is_exr_rr ? true : save_copy), opts->filepath);
+ image_save_post(reports,
+ ima,
+ ibuf,
+ ok,
+ opts,
+ (is_exr_rr ? true : save_copy),
+ opts->filepath,
+ r_colorspace_changed);
BKE_image_release_ibuf(ima, ibuf, lock);
}
/* individual multiview images */
@@ -260,7 +269,7 @@ static bool image_save_single(
if (is_exr_rr) {
BKE_scene_multiview_view_filepath_get(&opts->scene->r, opts->filepath, view, filepath);
ok_view = RE_WriteRenderResult(reports, rr, filepath, imf, view, layer);
- image_save_post(reports, bmain, ima, ibuf, ok_view, opts, true, filepath);
+ image_save_post(reports, ima, ibuf, ok_view, opts, true, filepath, r_colorspace_changed);
}
else {
/* copy iuser to get the correct ibuf for this view */
@@ -293,7 +302,7 @@ static bool image_save_single(
ibuf, save_as_render, true, &imf->view_settings, &imf->display_settings, imf);
ok_view = BKE_imbuf_write_as(colormanaged_ibuf, filepath, &opts->im_format, save_copy);
imbuf_save_post(ibuf, colormanaged_ibuf);
- image_save_post(reports, bmain, ima, ibuf, ok_view, opts, true, filepath);
+ image_save_post(reports, ima, ibuf, ok_view, opts, true, filepath, r_colorspace_changed);
BKE_image_release_ibuf(ima, ibuf, lock);
}
ok &= ok_view;
@@ -307,7 +316,7 @@ static bool image_save_single(
else if (opts->im_format.views_format == R_IMF_VIEWS_STEREO_3D) {
if (imf->imtype == R_IMF_IMTYPE_MULTILAYER) {
ok = RE_WriteRenderResult(reports, rr, opts->filepath, imf, NULL, layer);
- image_save_post(reports, bmain, ima, ibuf, ok, opts, true, opts->filepath);
+ image_save_post(reports, ima, ibuf, ok, opts, true, opts->filepath, r_colorspace_changed);
BKE_image_release_ibuf(ima, ibuf, lock);
}
else {
@@ -393,9 +402,11 @@ bool BKE_image_save(
ImageUser save_iuser;
BKE_imageuser_default(&save_iuser);
+ bool colorspace_changed = false;
+
if (ima->source == IMA_SRC_TILED) {
/* Verify filepath for tiles images. */
- if (BLI_stringdec(opts->filepath, NULL, NULL, NULL) != 1001) {
+ if (BLI_path_sequence_decode(opts->filepath, NULL, NULL, NULL) != 1001) {
BKE_reportf(reports,
RPT_ERROR,
"When saving a tiled image, the path '%s' must contain the UDIM tag 1001",
@@ -410,7 +421,7 @@ bool BKE_image_save(
}
/* Save image - or, for tiled images, the first tile. */
- bool ok = image_save_single(reports, bmain, ima, iuser, opts);
+ bool ok = image_save_single(reports, ima, iuser, opts, &colorspace_changed);
if (ok && ima->source == IMA_SRC_TILED) {
char filepath[FILE_MAX];
@@ -418,7 +429,7 @@ bool BKE_image_save(
char head[FILE_MAX], tail[FILE_MAX];
unsigned short numlen;
- BLI_stringdec(filepath, head, tail, &numlen);
+ BLI_path_sequence_decode(filepath, head, tail, &numlen);
/* Save all other tiles. */
LISTBASE_FOREACH (ImageTile *, tile, &ima->tiles) {
@@ -428,13 +439,17 @@ bool BKE_image_save(
}
/* Build filepath of the tile. */
- BLI_stringenc(opts->filepath, head, tail, numlen, tile->tile_number);
+ BLI_path_sequence_encode(opts->filepath, head, tail, numlen, tile->tile_number);
iuser->tile = tile->tile_number;
- ok = ok && image_save_single(reports, bmain, ima, iuser, opts);
+ ok = ok && image_save_single(reports, ima, iuser, opts, &colorspace_changed);
}
BLI_strncpy(opts->filepath, filepath, sizeof(opts->filepath));
}
+ if (colorspace_changed) {
+ BKE_image_signal(bmain, ima, NULL, IMA_SIGNAL_COLORMANAGE);
+ }
+
return ok;
}
diff --git a/source/blender/blenkernel/intern/ipo.c b/source/blender/blenkernel/intern/ipo.c
index 269235176cd..7bf9cb2d0a1 100644
--- a/source/blender/blenkernel/intern/ipo.c
+++ b/source/blender/blenkernel/intern/ipo.c
@@ -58,8 +58,9 @@
#include "BLT_translation.h"
#include "BKE_action.h"
-#include "BKE_animsys.h"
+#include "BKE_anim_data.h"
#include "BKE_fcurve.h"
+#include "BKE_fcurve_driver.h"
#include "BKE_global.h"
#include "BKE_idtype.h"
#include "BKE_ipo.h"
@@ -122,6 +123,7 @@ IDTypeInfo IDType_ID_IP = {
.copy_data = NULL,
.free_data = ipo_free_data,
.make_local = NULL,
+ .foreach_id = NULL,
};
/* *************************************************** */
@@ -1339,7 +1341,7 @@ static void icu_to_fcurves(ID *id,
int totbits;
/* allocate memory for a new F-Curve */
- fcu = MEM_callocN(sizeof(FCurve), "FCurve");
+ fcu = BKE_fcurve_create();
/* convert driver */
if (icu->driver) {
@@ -1418,7 +1420,7 @@ static void icu_to_fcurves(ID *id,
/* make a copy of existing base-data if not the last curve */
if (b < (totbits - 1)) {
- fcurve = copy_fcurve(fcu);
+ fcurve = BKE_fcurve_copy(fcu);
}
else {
fcurve = fcu;
@@ -2394,7 +2396,7 @@ void do_versions_ipos_to_animato(Main *bmain)
}
/* free unused drivers from actions + ipos */
- free_fcurves(&drivers);
+ BKE_fcurves_free(&drivers);
if (G.debug & G_DEBUG) {
printf("INFO: Animato convert done\n");
diff --git a/source/blender/blenkernel/intern/key.c b/source/blender/blenkernel/intern/key.c
index a6708413f70..af8ab22e14b 100644
--- a/source/blender/blenkernel/intern/key.c
+++ b/source/blender/blenkernel/intern/key.c
@@ -43,7 +43,6 @@
#include "DNA_object_types.h"
#include "DNA_scene_types.h"
-#include "BKE_animsys.h"
#include "BKE_curve.h"
#include "BKE_customdata.h"
#include "BKE_deform.h"
@@ -52,6 +51,7 @@
#include "BKE_key.h"
#include "BKE_lattice.h"
#include "BKE_lib_id.h"
+#include "BKE_lib_query.h"
#include "BKE_main.h"
#include "BKE_mesh.h"
#include "BKE_scene.h"
@@ -92,6 +92,12 @@ static void shapekey_free_data(ID *id)
}
}
+static void shapekey_foreach_id(ID *id, LibraryForeachIDData *data)
+{
+ Key *key = (Key *)id;
+ BKE_LIB_FOREACHID_PROCESS_ID(data, key->from, IDWALK_CB_LOOPBACK);
+}
+
IDTypeInfo IDType_ID_KE = {
.id_code = ID_KE,
.id_filter = 0,
@@ -106,6 +112,7 @@ IDTypeInfo IDType_ID_KE = {
.copy_data = shapekey_copy_data,
.free_data = shapekey_free_data,
.make_local = NULL,
+ .foreach_id = shapekey_foreach_id,
};
#define KEY_MODE_DUMMY 0 /* use where mode isn't checked for */
@@ -952,7 +959,7 @@ static void do_key(const int start,
k3 = key_block_get_data(key, actkb, k[2], &freek3);
k4 = key_block_get_data(key, actkb, k[3], &freek4);
- /* test for more or less points (per key!) */
+ /* Test for more or less points (per key!) */
if (tot != k[0]->totelem) {
k1tot = 0.0;
flagflo |= 1;
diff --git a/source/blender/blenkernel/intern/keyconfig.c b/source/blender/blenkernel/intern/keyconfig.c
index 84f48441cf9..ada5fc5b6aa 100644
--- a/source/blender/blenkernel/intern/keyconfig.c
+++ b/source/blender/blenkernel/intern/keyconfig.c
@@ -209,7 +209,7 @@ void BKE_keyconfig_pref_filter_items(struct UserDef *userdef,
bool (*filter_fn)(wmKeyMapItem *kmi, void *user_data),
void *user_data)
{
- for (wmKeyMap *keymap = userdef->user_keymaps.first; keymap; keymap = keymap->next) {
+ LISTBASE_FOREACH (wmKeyMap *, keymap, &userdef->user_keymaps) {
BKE_keyconfig_keymap_filter_item(keymap, params, filter_fn, user_data);
}
}
diff --git a/source/blender/blenkernel/intern/lattice.c b/source/blender/blenkernel/intern/lattice.c
index 3f353d6d576..e7a2421a625 100644
--- a/source/blender/blenkernel/intern/lattice.c
+++ b/source/blender/blenkernel/intern/lattice.c
@@ -45,14 +45,14 @@
#include "DNA_object_types.h"
#include "DNA_scene_types.h"
-#include "BKE_anim.h"
-#include "BKE_animsys.h"
+#include "BKE_anim_path.h"
#include "BKE_curve.h"
#include "BKE_displist.h"
#include "BKE_idtype.h"
#include "BKE_key.h"
#include "BKE_lattice.h"
#include "BKE_lib_id.h"
+#include "BKE_lib_query.h"
#include "BKE_main.h"
#include "BKE_modifier.h"
#include "BKE_object.h"
@@ -122,6 +122,12 @@ static void lattice_free_data(ID *id)
}
}
+static void lattice_foreach_id(ID *id, LibraryForeachIDData *data)
+{
+ Lattice *lattice = (Lattice *)id;
+ BKE_LIB_FOREACHID_PROCESS(data, lattice->key, IDWALK_CB_USER);
+}
+
IDTypeInfo IDType_ID_LT = {
.id_code = ID_LT,
.id_filter = FILTER_ID_LT,
@@ -136,6 +142,7 @@ IDTypeInfo IDType_ID_LT = {
.copy_data = lattice_copy_data,
.free_data = lattice_free_data,
.make_local = NULL,
+ .foreach_id = lattice_foreach_id,
};
int BKE_lattice_index_from_uvw(Lattice *lt, const int u, const int v, const int w)
@@ -1120,7 +1127,7 @@ void BKE_lattice_modifiers_calc(struct Depsgraph *depsgraph, Scene *scene, Objec
* otherwise we get already-modified coordinates. */
Object *ob_orig = DEG_get_original_object(ob);
VirtualModifierData virtualModifierData;
- ModifierData *md = modifiers_getVirtualModifierList(ob, &virtualModifierData);
+ ModifierData *md = BKE_modifiers_get_virtual_modifierlist(ob, &virtualModifierData);
float(*vert_coords)[3] = NULL;
int numVerts, editmode = (lt->editlatt != NULL);
const ModifierEvalContext mectx = {depsgraph, ob, 0};
@@ -1133,9 +1140,9 @@ void BKE_lattice_modifiers_calc(struct Depsgraph *depsgraph, Scene *scene, Objec
}
for (; md; md = md->next) {
- const ModifierTypeInfo *mti = modifierType_getInfo(md->type);
+ const ModifierTypeInfo *mti = BKE_modifier_get_info(md->type);
- if (!(mti->flags & eModifierTypeFlag_AcceptsLattice)) {
+ if (!(mti->flags & eModifierTypeFlag_AcceptsVertexCosOnly)) {
continue;
}
if (!(md->mode & eModifierMode_Realtime)) {
diff --git a/source/blender/blenkernel/intern/layer.c b/source/blender/blenkernel/intern/layer.c
index ffa1eecc87b..f03bf60817f 100644
--- a/source/blender/blenkernel/intern/layer.c
+++ b/source/blender/blenkernel/intern/layer.c
@@ -83,7 +83,7 @@ static void layer_collection_free(ViewLayer *view_layer, LayerCollection *lc)
view_layer->active_collection = NULL;
}
- for (LayerCollection *nlc = lc->layer_collections.first; nlc; nlc = nlc->next) {
+ LISTBASE_FOREACH (LayerCollection *, nlc, &lc->layer_collections) {
layer_collection_free(view_layer, nlc);
}
@@ -109,8 +109,7 @@ static Base *object_base_new(Object *ob)
* none linked to the workspace yet. */
ViewLayer *BKE_view_layer_default_view(const Scene *scene)
{
- for (ViewLayer *view_layer = scene->view_layers.first; view_layer;
- view_layer = view_layer->next) {
+ LISTBASE_FOREACH (ViewLayer *, view_layer, &scene->view_layers) {
if (!(view_layer->flag & VIEW_LAYER_RENDER)) {
return view_layer;
}
@@ -123,8 +122,7 @@ ViewLayer *BKE_view_layer_default_view(const Scene *scene)
/* Returns the default view layer to render if we need to render just one. */
ViewLayer *BKE_view_layer_default_render(const Scene *scene)
{
- for (ViewLayer *view_layer = scene->view_layers.first; view_layer;
- view_layer = view_layer->next) {
+ LISTBASE_FOREACH (ViewLayer *, view_layer, &scene->view_layers) {
if (view_layer->flag & VIEW_LAYER_RENDER) {
return view_layer;
}
@@ -137,8 +135,7 @@ ViewLayer *BKE_view_layer_default_render(const Scene *scene)
/* Returns view layer with matching name, or NULL if not found. */
ViewLayer *BKE_view_layer_find(const Scene *scene, const char *layer_name)
{
- for (ViewLayer *view_layer = scene->view_layers.first; view_layer;
- view_layer = view_layer->next) {
+ LISTBASE_FOREACH (ViewLayer *, view_layer, &scene->view_layers) {
if (STREQ(view_layer->name, layer_name)) {
return view_layer;
}
@@ -213,8 +210,9 @@ ViewLayer *BKE_view_layer_add(Scene *scene,
case VIEWLAYER_ADD_COPY: {
/* Allocate and copy view layer data */
view_layer_new = MEM_callocN(sizeof(ViewLayer), "View Layer");
- BLI_addtail(&scene->view_layers, view_layer_new);
+ *view_layer_new = *view_layer_source;
BKE_view_layer_copy_data(scene, scene, view_layer_new, view_layer_source, 0);
+ BLI_addtail(&scene->view_layers, view_layer_new);
BLI_strncpy_utf8(view_layer_new->name, name, sizeof(view_layer_new->name));
break;
@@ -262,12 +260,12 @@ void BKE_view_layer_free_ex(ViewLayer *view_layer, const bool do_id_user)
BLI_ghash_free(view_layer->object_bases_hash, NULL, NULL);
}
- for (LayerCollection *lc = view_layer->layer_collections.first; lc; lc = lc->next) {
+ LISTBASE_FOREACH (LayerCollection *, lc, &view_layer->layer_collections) {
layer_collection_free(view_layer, lc);
}
BLI_freelistN(&view_layer->layer_collections);
- for (ViewLayerEngineData *sled = view_layer->drawdata.first; sled; sled = sled->next) {
+ LISTBASE_FOREACH (ViewLayerEngineData *, sled, &view_layer->drawdata) {
if (sled->storage) {
if (sled->free) {
sled->free(sled->storage);
@@ -295,7 +293,7 @@ void BKE_view_layer_free_ex(ViewLayer *view_layer, const bool do_id_user)
*/
void BKE_view_layer_selected_objects_tag(ViewLayer *view_layer, const int tag)
{
- for (Base *base = view_layer->object_bases.first; base; base = base->next) {
+ LISTBASE_FOREACH (Base *, base, &view_layer->object_bases) {
if ((base->flag & BASE_SELECTED) != 0) {
base->object->flag |= tag;
}
@@ -307,7 +305,7 @@ void BKE_view_layer_selected_objects_tag(ViewLayer *view_layer, const int tag)
static bool find_scene_collection_in_scene_collections(ListBase *lb, const LayerCollection *lc)
{
- for (LayerCollection *lcn = lb->first; lcn; lcn = lcn->next) {
+ LISTBASE_FOREACH (LayerCollection *, lcn, lb) {
if (lcn == lc) {
return true;
}
@@ -327,7 +325,7 @@ static bool find_scene_collection_in_scene_collections(ListBase *lb, const Layer
*/
Object *BKE_view_layer_camera_find(ViewLayer *view_layer)
{
- for (Base *base = view_layer->object_bases.first; base; base = base->next) {
+ LISTBASE_FOREACH (Base *, base, &view_layer->object_bases) {
if (base->object->type == OB_CAMERA) {
return base->object;
}
@@ -341,8 +339,7 @@ Object *BKE_view_layer_camera_find(ViewLayer *view_layer)
*/
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) {
+ LISTBASE_FOREACH (ViewLayer *, view_layer, &scene->view_layers) {
if (find_scene_collection_in_scene_collections(&view_layer->layer_collections, lc)) {
return view_layer;
}
@@ -364,7 +361,7 @@ static void view_layer_bases_hash_create(ViewLayer *view_layer)
view_layer->object_bases_hash = BLI_ghash_new(
BLI_ghashutil_ptrhash, BLI_ghashutil_ptrcmp, __func__);
- for (Base *base = view_layer->object_bases.first; base; base = base->next) {
+ LISTBASE_FOREACH (Base *, base, &view_layer->object_bases) {
if (base->object) {
BLI_ghash_insert(view_layer->object_bases_hash, base->object, base);
}
@@ -455,7 +452,7 @@ void BKE_view_layer_copy_data(Scene *scene_dst,
/* Copy layer collections and object bases. */
/* Inline 'BLI_duplicatelist' and update the active base. */
BLI_listbase_clear(&view_layer_dst->object_bases);
- for (Base *base_src = view_layer_src->object_bases.first; base_src; base_src = base_src->next) {
+ LISTBASE_FOREACH (Base *, base_src, &view_layer_src->object_bases) {
Base *base_dst = MEM_dupallocN(base_src);
BLI_addtail(&view_layer_dst->object_bases, base_dst);
if (view_layer_src->basact == base_src) {
@@ -471,6 +468,10 @@ void BKE_view_layer_copy_data(Scene *scene_dst,
LayerCollection *lc_scene_dst = view_layer_dst->layer_collections.first;
lc_scene_dst->collection = scene_dst->master_collection;
+
+ if ((flag & LIB_ID_CREATE_NO_USER_REFCOUNT) == 0) {
+ id_us_plus((ID *)view_layer_dst->mat_override);
+ }
}
void BKE_view_layer_rename(Main *bmain, Scene *scene, ViewLayer *view_layer, const char *newname)
@@ -506,7 +507,7 @@ void BKE_view_layer_rename(Main *bmain, Scene *scene, ViewLayer *view_layer, con
/* WM can be missing on startup. */
wmWindowManager *wm = bmain->wm.first;
if (wm) {
- for (wmWindow *win = wm->windows.first; win; win = win->next) {
+ LISTBASE_FOREACH (wmWindow *, win, &wm->windows) {
if (win->scene == scene && STREQ(win->view_layer_name, oldname)) {
STRNCPY(win->view_layer_name, view_layer->name);
}
@@ -524,7 +525,7 @@ void BKE_view_layer_rename(Main *bmain, Scene *scene, ViewLayer *view_layer, con
*/
static LayerCollection *collection_from_index(ListBase *lb, const int number, int *i)
{
- for (LayerCollection *lc = lb->first; lc; lc = lc->next) {
+ LISTBASE_FOREACH (LayerCollection *, lc, lb) {
if (*i == number) {
return lc;
}
@@ -532,7 +533,7 @@ static LayerCollection *collection_from_index(ListBase *lb, const int number, in
(*i)++;
}
- for (LayerCollection *lc = lb->first; lc; lc = lc->next) {
+ LISTBASE_FOREACH (LayerCollection *, lc, lb) {
LayerCollection *lc_nested = collection_from_index(&lc->layer_collections, number, i);
if (lc_nested) {
return lc_nested;
@@ -635,7 +636,7 @@ LayerCollection *BKE_layer_collection_activate_parent(ViewLayer *view_layer, Lay
static int collection_count(ListBase *lb)
{
int i = 0;
- for (LayerCollection *lc = lb->first; lc; lc = lc->next) {
+ LISTBASE_FOREACH (LayerCollection *, lc, lb) {
i += collection_count(&lc->layer_collections) + 1;
}
return i;
@@ -655,7 +656,7 @@ int BKE_layer_collection_count(ViewLayer *view_layer)
*/
static int index_from_collection(ListBase *lb, const LayerCollection *lc, int *i)
{
- for (LayerCollection *lcol = lb->first; lcol; lcol = lcol->next) {
+ LISTBASE_FOREACH (LayerCollection *, lcol, lb) {
if (lcol == lc) {
return *i;
}
@@ -663,7 +664,7 @@ static int index_from_collection(ListBase *lb, const LayerCollection *lc, int *i
(*i)++;
}
- for (LayerCollection *lcol = lb->first; lcol; lcol = lcol->next) {
+ LISTBASE_FOREACH (LayerCollection *, lcol, lb) {
int i_nested = index_from_collection(&lcol->layer_collections, lc, i);
if (i_nested != -1) {
return i_nested;
@@ -693,14 +694,14 @@ int BKE_layer_collection_findindex(ViewLayer *view_layer, const LayerCollection
* in at least one layer collection. That list is also synchronized here, and
* stores state like selection. */
-static short layer_collection_sync(ViewLayer *view_layer,
- const ListBase *lb_scene,
- ListBase *lb_layer,
- ListBase *new_object_bases,
- short parent_exclude,
- short parent_restrict,
- short parent_layer_restrict,
- unsigned short parent_local_collections_bits)
+static void layer_collection_sync(ViewLayer *view_layer,
+ const ListBase *lb_scene,
+ ListBase *lb_layer,
+ ListBase *new_object_bases,
+ short parent_exclude,
+ short parent_restrict,
+ short parent_layer_restrict,
+ unsigned short parent_local_collections_bits)
{
/* TODO: support recovery after removal of intermediate collections, reordering, ..
* For local edits we can make editing operating do the appropriate thing, but for
@@ -731,9 +732,8 @@ static short layer_collection_sync(ViewLayer *view_layer,
/* Add layer collections for any new scene collections, and ensure order is the same. */
ListBase new_lb_layer = {NULL, NULL};
- short runtime_flag = 0;
- for (const CollectionChild *child = lb_scene->first; child; child = child->next) {
+ LISTBASE_FOREACH (const CollectionChild *, child, lb_scene) {
Collection *collection = child->collection;
LayerCollection *lc = BLI_findptr(lb_layer, collection, offsetof(LayerCollection, collection));
@@ -762,23 +762,20 @@ static short layer_collection_sync(ViewLayer *view_layer,
}
/* Sync child collections. */
- short child_runtime_flag = layer_collection_sync(view_layer,
- &collection->children,
- &lc->layer_collections,
- new_object_bases,
- lc->flag,
- child_restrict,
- child_layer_restrict,
- local_collections_bits);
+ layer_collection_sync(view_layer,
+ &collection->children,
+ &lc->layer_collections,
+ new_object_bases,
+ lc->flag,
+ child_restrict,
+ child_layer_restrict,
+ local_collections_bits);
/* Layer collection exclude is not inherited. */
+ lc->runtime_flag = 0;
if (lc->flag & LAYER_COLLECTION_EXCLUDE) {
- lc->runtime_flag = 0;
continue;
}
- else {
- lc->runtime_flag = child_runtime_flag;
- }
/* We separate restrict viewport and visible view layer because a layer collection can be
* hidden in the view layer yet (locally) visible in a viewport (if it is not restricted).*/
@@ -792,7 +789,7 @@ static short layer_collection_sync(ViewLayer *view_layer,
}
/* Sync objects, except if collection was excluded. */
- for (CollectionObject *cob = collection->gobject.first; cob; cob = cob->next) {
+ LISTBASE_FOREACH (CollectionObject *, cob, &collection->gobject) {
if (cob->ob == NULL) {
continue;
}
@@ -845,15 +842,11 @@ static short layer_collection_sync(ViewLayer *view_layer,
lc->runtime_flag |= LAYER_COLLECTION_HAS_OBJECTS;
}
-
- runtime_flag |= lc->runtime_flag;
}
/* Replace layer collection list with new one. */
*lb_layer = new_lb_layer;
BLI_assert(BLI_listbase_count(lb_scene) == BLI_listbase_count(lb_layer));
-
- return runtime_flag;
}
/**
@@ -877,7 +870,7 @@ void BKE_layer_collection_sync(const Scene *scene, ViewLayer *view_layer)
}
/* Clear visible and selectable flags to be reset. */
- for (Base *base = view_layer->object_bases.first; base; base = base->next) {
+ LISTBASE_FOREACH (Base *, base, &view_layer->object_bases) {
base->flag &= ~g_base_collection_flags;
base->flag_from_collection &= ~g_base_collection_flags;
}
@@ -898,7 +891,7 @@ void BKE_layer_collection_sync(const Scene *scene, ViewLayer *view_layer)
~(0));
/* Any remaining object bases are to be removed. */
- for (Base *base = view_layer->object_bases.first; base; base = base->next) {
+ LISTBASE_FOREACH (Base *, base, &view_layer->object_bases) {
if (view_layer->basact == base) {
view_layer->basact = NULL;
}
@@ -911,7 +904,7 @@ void BKE_layer_collection_sync(const Scene *scene, ViewLayer *view_layer)
BLI_freelistN(&view_layer->object_bases);
view_layer->object_bases = new_object_bases;
- for (Base *base = view_layer->object_bases.first; base; base = base->next) {
+ LISTBASE_FOREACH (Base *, base, &view_layer->object_bases) {
BKE_base_eval_flags(base);
}
@@ -927,8 +920,7 @@ void BKE_layer_collection_sync(const Scene *scene, ViewLayer *view_layer)
void BKE_scene_collection_sync(const Scene *scene)
{
- for (ViewLayer *view_layer = scene->view_layers.first; view_layer;
- view_layer = view_layer->next) {
+ LISTBASE_FOREACH (ViewLayer *, view_layer, &scene->view_layers) {
BKE_layer_collection_sync(scene, view_layer);
}
}
@@ -951,8 +943,7 @@ void BKE_main_collection_sync_remap(const Main *bmain)
/* TODO: try to make this faster */
for (const Scene *scene = bmain->scenes.first; scene; scene = scene->id.next) {
- for (ViewLayer *view_layer = scene->view_layers.first; view_layer;
- view_layer = view_layer->next) {
+ LISTBASE_FOREACH (ViewLayer *, view_layer, &scene->view_layers) {
MEM_SAFE_FREE(view_layer->object_bases_array);
if (view_layer->object_bases_hash) {
@@ -988,7 +979,7 @@ bool BKE_layer_collection_objects_select(ViewLayer *view_layer, LayerCollection
bool changed = false;
if (!(lc->flag & LAYER_COLLECTION_EXCLUDE)) {
- for (CollectionObject *cob = lc->collection->gobject.first; cob; cob = cob->next) {
+ LISTBASE_FOREACH (CollectionObject *, cob, &lc->collection->gobject) {
Base *base = BKE_view_layer_base_find(view_layer, cob->ob);
if (base) {
@@ -1008,7 +999,7 @@ bool BKE_layer_collection_objects_select(ViewLayer *view_layer, LayerCollection
}
}
- for (LayerCollection *iter = lc->layer_collections.first; iter; iter = iter->next) {
+ LISTBASE_FOREACH (LayerCollection *, iter, &lc->layer_collections) {
changed |= BKE_layer_collection_objects_select(view_layer, iter, deselect);
}
@@ -1022,7 +1013,7 @@ bool BKE_layer_collection_has_selected_objects(ViewLayer *view_layer, LayerColle
}
if (!(lc->flag & LAYER_COLLECTION_EXCLUDE)) {
- for (CollectionObject *cob = lc->collection->gobject.first; cob; cob = cob->next) {
+ LISTBASE_FOREACH (CollectionObject *, cob, &lc->collection->gobject) {
Base *base = BKE_view_layer_base_find(view_layer, cob->ob);
if (base && (base->flag & BASE_SELECTED) && (base->flag & BASE_VISIBLE_DEPSGRAPH)) {
@@ -1031,7 +1022,7 @@ bool BKE_layer_collection_has_selected_objects(ViewLayer *view_layer, LayerColle
}
}
- for (LayerCollection *iter = lc->layer_collections.first; iter; iter = iter->next) {
+ LISTBASE_FOREACH (LayerCollection *, iter, &lc->layer_collections) {
if (BKE_layer_collection_has_selected_objects(view_layer, iter)) {
return true;
}
@@ -1047,8 +1038,7 @@ bool BKE_layer_collection_has_layer_collection(LayerCollection *lc_parent,
return true;
}
- for (LayerCollection *lc_iter = lc_parent->layer_collections.first; lc_iter;
- lc_iter = lc_iter->next) {
+ LISTBASE_FOREACH (LayerCollection *, lc_iter, &lc_parent->layer_collections) {
if (BKE_layer_collection_has_layer_collection(lc_iter, lc_child)) {
return true;
}
@@ -1063,7 +1053,7 @@ void BKE_base_set_visible(Scene *scene, ViewLayer *view_layer, Base *base, bool
{
if (!extend) {
/* Make only one base visible. */
- for (Base *other = view_layer->object_bases.first; other; other = other->next) {
+ LISTBASE_FOREACH (Base *, other, &view_layer->object_bases) {
other->flag |= BASE_HIDDEN;
}
@@ -1134,7 +1124,7 @@ bool BKE_object_is_visible_in_viewport(const struct View3D *v3d, const struct Ob
static void layer_collection_flag_set_recursive(LayerCollection *lc, const int flag)
{
lc->flag |= flag;
- for (LayerCollection *lc_iter = lc->layer_collections.first; lc_iter; lc_iter = lc_iter->next) {
+ LISTBASE_FOREACH (LayerCollection *, lc_iter, &lc->layer_collections) {
layer_collection_flag_set_recursive(lc_iter, flag);
}
}
@@ -1142,7 +1132,7 @@ static void layer_collection_flag_set_recursive(LayerCollection *lc, const int f
static void layer_collection_flag_unset_recursive(LayerCollection *lc, const int flag)
{
lc->flag &= ~flag;
- for (LayerCollection *lc_iter = lc->layer_collections.first; lc_iter; lc_iter = lc_iter->next) {
+ LISTBASE_FOREACH (LayerCollection *, lc_iter, &lc->layer_collections) {
layer_collection_flag_unset_recursive(lc_iter, flag);
}
}
@@ -1165,8 +1155,7 @@ void BKE_layer_collection_isolate_global(Scene *scene,
if (!extend) {
/* Hide all collections . */
- for (LayerCollection *lc_iter = lc_master->layer_collections.first; lc_iter;
- lc_iter = lc_iter->next) {
+ LISTBASE_FOREACH (LayerCollection *, lc_iter, &lc_master->layer_collections) {
layer_collection_flag_set_recursive(lc_iter, LAYER_COLLECTION_HIDE);
}
}
@@ -1177,8 +1166,7 @@ void BKE_layer_collection_isolate_global(Scene *scene,
}
else {
LayerCollection *lc_parent = lc;
- for (LayerCollection *lc_iter = lc_master->layer_collections.first; lc_iter;
- lc_iter = lc_iter->next) {
+ LISTBASE_FOREACH (LayerCollection *, lc_iter, &lc_master->layer_collections) {
if (BKE_layer_collection_has_layer_collection(lc_iter, lc)) {
lc_parent = lc_iter;
break;
@@ -1188,8 +1176,7 @@ void BKE_layer_collection_isolate_global(Scene *scene,
while (lc_parent != lc) {
lc_parent->flag &= ~LAYER_COLLECTION_HIDE;
- for (LayerCollection *lc_iter = lc_parent->layer_collections.first; lc_iter;
- lc_iter = lc_iter->next) {
+ LISTBASE_FOREACH (LayerCollection *, lc_iter, &lc_parent->layer_collections) {
if (BKE_layer_collection_has_layer_collection(lc_iter, lc)) {
lc_parent = lc_iter;
break;
@@ -1210,8 +1197,7 @@ static void layer_collection_local_visibility_set_recursive(LayerCollection *lay
const int local_collections_uuid)
{
layer_collection->local_collections_bits |= local_collections_uuid;
- for (LayerCollection *child = layer_collection->layer_collections.first; child;
- child = child->next) {
+ LISTBASE_FOREACH (LayerCollection *, child, &layer_collection->layer_collections) {
layer_collection_local_visibility_set_recursive(child, local_collections_uuid);
}
}
@@ -1220,8 +1206,7 @@ static void layer_collection_local_visibility_unset_recursive(LayerCollection *l
const int local_collections_uuid)
{
layer_collection->local_collections_bits &= ~local_collections_uuid;
- for (LayerCollection *child = layer_collection->layer_collections.first; child;
- child = child->next) {
+ LISTBASE_FOREACH (LayerCollection *, child, &layer_collection->layer_collections) {
layer_collection_local_visibility_unset_recursive(child, local_collections_uuid);
}
}
@@ -1236,8 +1221,7 @@ static void layer_collection_local_sync(ViewLayer *view_layer,
}
if (visible) {
- for (CollectionObject *cob = layer_collection->collection->gobject.first; cob;
- cob = cob->next) {
+ LISTBASE_FOREACH (CollectionObject *, cob, &layer_collection->collection->gobject) {
BLI_assert(cob->ob);
Base *base = BKE_view_layer_base_find(view_layer, cob->ob);
base->local_collections_bits |= local_collections_uuid;
@@ -1256,7 +1240,7 @@ void BKE_layer_collection_local_sync(ViewLayer *view_layer, View3D *v3d)
const unsigned short local_collections_uuid = v3d->local_collections_uuid;
/* Reset flags and set the bases visible by default. */
- for (Base *base = view_layer->object_bases.first; base; base = base->next) {
+ LISTBASE_FOREACH (Base *, base, &view_layer->object_bases) {
base->local_collections_bits &= ~local_collections_uuid;
}
@@ -1280,8 +1264,7 @@ void BKE_layer_collection_isolate_local(ViewLayer *view_layer,
if (!extend) {
/* Hide all collections. */
- for (LayerCollection *lc_iter = lc_master->layer_collections.first; lc_iter;
- lc_iter = lc_iter->next) {
+ LISTBASE_FOREACH (LayerCollection *, lc_iter, &lc_master->layer_collections) {
layer_collection_local_visibility_unset_recursive(lc_iter, v3d->local_collections_uuid);
}
}
@@ -1292,8 +1275,7 @@ void BKE_layer_collection_isolate_local(ViewLayer *view_layer,
}
else {
LayerCollection *lc_parent = lc;
- for (LayerCollection *lc_iter = lc_master->layer_collections.first; lc_iter;
- lc_iter = lc_iter->next) {
+ LISTBASE_FOREACH (LayerCollection *, lc_iter, &lc_master->layer_collections) {
if (BKE_layer_collection_has_layer_collection(lc_iter, lc)) {
lc_parent = lc_iter;
break;
@@ -1303,8 +1285,7 @@ void BKE_layer_collection_isolate_local(ViewLayer *view_layer,
while (lc_parent != lc) {
lc_parent->local_collections_bits |= v3d->local_collections_uuid;
- for (LayerCollection *lc_iter = lc_parent->layer_collections.first; lc_iter;
- lc_iter = lc_iter->next) {
+ LISTBASE_FOREACH (LayerCollection *, lc_iter, &lc_parent->layer_collections) {
if (BKE_layer_collection_has_layer_collection(lc_iter, lc)) {
lc_parent = lc_iter;
break;
@@ -1322,12 +1303,12 @@ void BKE_layer_collection_isolate_local(ViewLayer *view_layer,
static void layer_collection_bases_show_recursive(ViewLayer *view_layer, LayerCollection *lc)
{
if ((lc->flag & LAYER_COLLECTION_EXCLUDE) == 0) {
- for (CollectionObject *cob = lc->collection->gobject.first; cob; cob = cob->next) {
+ LISTBASE_FOREACH (CollectionObject *, cob, &lc->collection->gobject) {
Base *base = BKE_view_layer_base_find(view_layer, cob->ob);
base->flag &= ~BASE_HIDDEN;
}
}
- for (LayerCollection *lc_iter = lc->layer_collections.first; lc_iter; lc_iter = lc_iter->next) {
+ LISTBASE_FOREACH (LayerCollection *, lc_iter, &lc->layer_collections) {
layer_collection_bases_show_recursive(view_layer, lc_iter);
}
}
@@ -1335,12 +1316,12 @@ static void layer_collection_bases_show_recursive(ViewLayer *view_layer, LayerCo
static void layer_collection_bases_hide_recursive(ViewLayer *view_layer, LayerCollection *lc)
{
if ((lc->flag & LAYER_COLLECTION_EXCLUDE) == 0) {
- for (CollectionObject *cob = lc->collection->gobject.first; cob; cob = cob->next) {
+ LISTBASE_FOREACH (CollectionObject *, cob, &lc->collection->gobject) {
Base *base = BKE_view_layer_base_find(view_layer, cob->ob);
base->flag |= BASE_HIDDEN;
}
}
- for (LayerCollection *lc_iter = lc->layer_collections.first; lc_iter; lc_iter = lc_iter->next) {
+ LISTBASE_FOREACH (LayerCollection *, lc_iter, &lc->layer_collections) {
layer_collection_bases_hide_recursive(view_layer, lc_iter);
}
}
@@ -1375,6 +1356,49 @@ void BKE_layer_collection_set_visible(ViewLayer *view_layer,
}
}
+/**
+ * Set layer collection hide/exclude/indirect flag on a layer collection.
+ * recursively.
+ */
+static void layer_collection_flag_recursive_set(LayerCollection *lc,
+ const int flag,
+ const bool value,
+ const bool restore_flag)
+{
+ if (flag == LAYER_COLLECTION_EXCLUDE) {
+ /* For exclude flag, we remember the state the children had before
+ * excluding and restoring it when enabling the parent collection again. */
+ if (value) {
+ if (restore_flag) {
+ SET_FLAG_FROM_TEST(
+ lc->flag, (lc->flag & LAYER_COLLECTION_EXCLUDE), LAYER_COLLECTION_PREVIOUSLY_EXCLUDED);
+ }
+ else {
+ lc->flag &= ~LAYER_COLLECTION_PREVIOUSLY_EXCLUDED;
+ }
+
+ lc->flag |= flag;
+ }
+ else {
+ if (!(lc->flag & LAYER_COLLECTION_PREVIOUSLY_EXCLUDED)) {
+ lc->flag &= ~flag;
+ }
+ }
+ }
+ else {
+ SET_FLAG_FROM_TEST(lc->flag, value, flag);
+ }
+
+ LISTBASE_FOREACH (LayerCollection *, nlc, &lc->layer_collections) {
+ layer_collection_flag_recursive_set(nlc, flag, value, true);
+ }
+}
+
+void BKE_layer_collection_set_flag(LayerCollection *lc, const int flag, const bool value)
+{
+ layer_collection_flag_recursive_set(lc, flag, value, false);
+}
+
/* ---------------------------------------------------------------------- */
static LayerCollection *find_layer_collection_by_scene_collection(LayerCollection *lc,
@@ -1384,7 +1408,7 @@ static LayerCollection *find_layer_collection_by_scene_collection(LayerCollectio
return lc;
}
- for (LayerCollection *nlc = lc->layer_collections.first; nlc; nlc = nlc->next) {
+ LISTBASE_FOREACH (LayerCollection *, nlc, &lc->layer_collections) {
LayerCollection *found = find_layer_collection_by_scene_collection(nlc, collection);
if (found) {
return found;
@@ -1425,8 +1449,7 @@ bool BKE_view_layer_has_collection(ViewLayer *view_layer, const Collection *coll
*/
bool BKE_scene_has_object(Scene *scene, Object *ob)
{
- for (ViewLayer *view_layer = scene->view_layers.first; view_layer;
- view_layer = view_layer->next) {
+ LISTBASE_FOREACH (ViewLayer *, view_layer, &scene->view_layers) {
Base *base = BKE_view_layer_base_find(view_layer, ob);
if (base) {
return true;
@@ -1768,7 +1791,7 @@ static void layer_eval_view_layer(struct Depsgraph *depsgraph,
view_layer->object_bases_array = MEM_malloc_arrayN(
num_object_bases, sizeof(Base *), "view_layer->object_bases_array");
int base_index = 0;
- for (Base *base = view_layer->object_bases.first; base; base = base->next) {
+ LISTBASE_FOREACH (Base *, base, &view_layer->object_bases) {
view_layer->object_bases_array[base_index++] = base;
}
}
diff --git a/source/blender/blenkernel/intern/lib_id.c b/source/blender/blenkernel/intern/lib_id.c
index a524db3c909..19462c62496 100644
--- a/source/blender/blenkernel/intern/lib_id.c
+++ b/source/blender/blenkernel/intern/lib_id.c
@@ -36,38 +36,12 @@
#include "MEM_guardedalloc.h"
/* all types are needed here, in order to do memory operations */
+#include "DNA_ID.h"
#include "DNA_anim_types.h"
-#include "DNA_armature_types.h"
-#include "DNA_brush_types.h"
-#include "DNA_cachefile_types.h"
-#include "DNA_camera_types.h"
-#include "DNA_collection_types.h"
#include "DNA_gpencil_types.h"
-#include "DNA_hair_types.h"
-#include "DNA_ipo_types.h"
#include "DNA_key_types.h"
-#include "DNA_lattice_types.h"
-#include "DNA_light_types.h"
-#include "DNA_lightprobe_types.h"
-#include "DNA_linestyle_types.h"
-#include "DNA_mask_types.h"
-#include "DNA_material_types.h"
-#include "DNA_mesh_types.h"
-#include "DNA_meta_types.h"
-#include "DNA_movieclip_types.h"
#include "DNA_node_types.h"
-#include "DNA_object_types.h"
-#include "DNA_pointcloud_types.h"
-#include "DNA_scene_types.h"
-#include "DNA_screen_types.h"
-#include "DNA_sound_types.h"
-#include "DNA_speaker_types.h"
-#include "DNA_text_types.h"
-#include "DNA_vfont_types.h"
-#include "DNA_volume_types.h"
-#include "DNA_windowmanager_types.h"
#include "DNA_workspace_types.h"
-#include "DNA_world_types.h"
#include "BLI_utildefines.h"
@@ -80,50 +54,21 @@
#include "BLT_translation.h"
-#include "BKE_action.h"
-#include "BKE_animsys.h"
+#include "BKE_anim_data.h"
#include "BKE_armature.h"
#include "BKE_bpath.h"
-#include "BKE_brush.h"
-#include "BKE_cachefile.h"
-#include "BKE_camera.h"
-#include "BKE_collection.h"
#include "BKE_context.h"
-#include "BKE_curve.h"
-#include "BKE_font.h"
#include "BKE_global.h"
#include "BKE_gpencil.h"
-#include "BKE_hair.h"
#include "BKE_idprop.h"
#include "BKE_idtype.h"
-#include "BKE_image.h"
#include "BKE_key.h"
-#include "BKE_lattice.h"
#include "BKE_lib_id.h"
#include "BKE_lib_query.h"
#include "BKE_lib_remap.h"
-#include "BKE_light.h"
-#include "BKE_lightprobe.h"
-#include "BKE_linestyle.h"
#include "BKE_main.h"
-#include "BKE_mask.h"
-#include "BKE_material.h"
-#include "BKE_mball.h"
-#include "BKE_mesh.h"
-#include "BKE_movieclip.h"
#include "BKE_node.h"
-#include "BKE_object.h"
-#include "BKE_paint.h"
-#include "BKE_particle.h"
-#include "BKE_pointcloud.h"
#include "BKE_rigidbody.h"
-#include "BKE_scene.h"
-#include "BKE_sound.h"
-#include "BKE_speaker.h"
-#include "BKE_text.h"
-#include "BKE_texture.h"
-#include "BKE_volume.h"
-#include "BKE_world.h"
#include "DEG_depsgraph.h"
@@ -183,8 +128,6 @@ static void lib_id_library_local_paths(Main *bmain, Library *lib, ID *id)
*/
static void lib_id_clear_library_data_ex(Main *bmain, ID *id)
{
- bNodeTree *ntree = NULL;
- Key *key = NULL;
const bool id_in_mainlist = (id->tag & LIB_TAG_NO_MAIN) == 0 &&
(id->flag & LIB_EMBEDDED_DATA) == 0;
@@ -201,14 +144,11 @@ static void lib_id_clear_library_data_ex(Main *bmain, ID *id)
}
}
- /* Internal bNodeTree blocks inside data-blocks also stores id->lib,
- * make sure this stays in sync. */
- if ((ntree = ntreeFromID(id))) {
- lib_id_clear_library_data_ex(bmain, &ntree->id);
- }
-
- /* Same goes for shapekeys. */
- if ((key = BKE_key_from_id(id))) {
+ /* Internal shape key blocks inside data-blocks also stores id->lib,
+ * make sure this stays in sync (note that we do not need any explicit handling for real EMBEDDED
+ * IDs here, this is down automatically in `lib_id_expand_local_cb()`. */
+ Key *key = BKE_key_from_id(id);
+ if (key != NULL) {
lib_id_clear_library_data_ex(bmain, &key->id);
}
}
@@ -320,7 +260,11 @@ void id_us_min(ID *id)
id->lib ? id->lib->filepath : "[Main]",
id->us,
limit);
- BLI_assert(0);
+ if (GS(id->name) != ID_IP) {
+ /* Do not assert on deprecated ID types, we cannot really ensure that their ID refcounting
+ * is valid... */
+ BLI_assert(0);
+ }
id->us = limit;
}
else {
@@ -361,10 +305,23 @@ void BKE_id_clear_newpoin(ID *id)
static int lib_id_expand_local_cb(LibraryIDLinkCallbackData *cb_data)
{
+ Main *bmain = cb_data->bmain;
ID *id_self = cb_data->id_self;
ID **id_pointer = cb_data->id_pointer;
int const cb_flag = cb_data->cb_flag;
+
+ if (cb_flag & IDWALK_CB_LOOPBACK) {
+ /* We should never have anything to do with loopback pointers here. */
+ return IDWALK_RET_NOP;
+ }
+
if (cb_flag & IDWALK_CB_EMBEDDED) {
+ /* Embedded data-blocks need to be made fully local as well. */
+ if (*id_pointer != NULL) {
+ BLI_assert(*id_pointer != id_self);
+
+ lib_id_clear_library_data_ex(bmain, *id_pointer);
+ }
return IDWALK_RET_NOP;
}
@@ -386,7 +343,7 @@ static int lib_id_expand_local_cb(LibraryIDLinkCallbackData *cb_data)
*/
void BKE_lib_id_expand_local(Main *bmain, ID *id)
{
- BKE_library_foreach_ID_link(bmain, id, lib_id_expand_local_cb, NULL, IDWALK_READONLY);
+ BKE_library_foreach_ID_link(bmain, id, lib_id_expand_local_cb, bmain, IDWALK_READONLY);
}
/**
@@ -444,6 +401,13 @@ void BKE_lib_id_make_local_generic(Main *bmain, ID *id, const int flags)
if (ntree && ntree_new) {
ID_NEW_SET(ntree, ntree_new);
}
+ if (GS(id->name) == ID_SCE) {
+ Collection *master_collection = ((Scene *)id)->master_collection,
+ *master_collection_new = ((Scene *)id_new)->master_collection;
+ if (master_collection && master_collection_new) {
+ ID_NEW_SET(master_collection, master_collection_new);
+ }
+ }
if (!lib_local) {
BKE_libblock_remap(bmain, id, id_new, ID_REMAP_SKIP_INDIRECT_USAGE);
@@ -659,7 +623,7 @@ static void id_swap(Main *bmain, ID *id_a, ID *id_b, const bool do_full_id)
* 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).
*
- * \param bmain May be NULL, in which case there will be no remapping of internal pointers to
+ * \param bmain: May be NULL, in which case there will be no remapping of internal pointers to
* itself.
*/
void BKE_lib_id_swap(Main *bmain, ID *id_a, ID *id_b)
@@ -671,7 +635,7 @@ void BKE_lib_id_swap(Main *bmain, ID *id_a, ID *id_b)
* Does a mere memory swap over the whole IDs data (including type-specific memory).
* \note All internal ID data itself is also swapped.
*
- * \param bmain May be NULL, in which case there will be no remapping of internal pointers to
+ * \param bmain: May be NULL, in which case there will be no remapping of internal pointers to
* itself.
*/
void BKE_lib_id_swap_full(Main *bmain, ID *id_a, ID *id_b)
@@ -901,7 +865,7 @@ void BKE_main_id_flag_all(Main *bmain, const int flag, const bool value)
void BKE_main_id_repair_duplicate_names_listbase(ListBase *lb)
{
int lb_len = 0;
- for (ID *id = lb->first; id; id = id->next) {
+ LISTBASE_FOREACH (ID *, id, lb) {
if (id->lib == NULL) {
lb_len += 1;
}
@@ -914,7 +878,7 @@ void BKE_main_id_repair_duplicate_names_listbase(ListBase *lb)
ID **id_array = MEM_mallocN(sizeof(*id_array) * lb_len, __func__);
GSet *gset = BLI_gset_str_new_ex(__func__, lb_len);
int i = 0;
- for (ID *id = lb->first; id; id = id->next) {
+ LISTBASE_FOREACH (ID *, id, lb) {
if (id->lib == NULL) {
id_array[i] = id;
i++;
@@ -1014,6 +978,8 @@ void *BKE_libblock_alloc(Main *bmain, short type, const char *name, const int fl
id->us = 1;
}
if ((flag & LIB_ID_CREATE_NO_MAIN) == 0) {
+ /* Note that 2.8x versioning has tested not to cause conflicts. */
+ BLI_assert(bmain->is_locked_for_linking == false || ELEM(type, ID_WS, ID_GR));
ListBase *lb = which_libbase(bmain, type);
BKE_main_lock(bmain);
@@ -1059,12 +1025,6 @@ void BKE_libblock_init_empty(ID *id)
/* ********** ID session-wise UUID management. ********** */
static uint global_session_uuid = 0;
-/** Reset the session-wise uuid counter (used when reading a new file e.g.). */
-void BKE_lib_libblock_session_uuid_reset()
-{
- global_session_uuid = 0;
-}
-
/**
* Generate a session-wise uuid for the given \a id.
*
@@ -1084,6 +1044,18 @@ void BKE_lib_libblock_session_uuid_ensure(ID *id)
}
/**
+ * Re-generate a new session-wise uuid for the given \a id.
+ *
+ * \warning This has a very specific use-case (to handle UI-related data-blocks that are kept
+ * across new file reading, when we do keep existing UI). No other usage is expected currently.
+ */
+void BKE_lib_libblock_session_uuid_renew(ID *id)
+{
+ id->session_uuid = MAIN_ID_SESSION_UUID_UNSET;
+ BKE_lib_libblock_session_uuid_ensure(id);
+}
+
+/**
* Generic helper to create a new empty data-block of given type in given \a bmain database.
*
* \param name: can be NULL, in which case we get default name for this ID type.
@@ -1244,7 +1216,7 @@ ID *BKE_libblock_find_name(struct Main *bmain, const short type, const char *nam
*
* \note All other IDs beside given one are assumed already properly sorted in the list.
*
- * \param id_sorting_hint Ignored if NULL. Otherwise, used to check if we can insert \a id
+ * \param id_sorting_hint: Ignored if NULL. Otherwise, used to check if we can insert \a id
* immediately before or after that pointer. It must always be into given \a lb list.
*/
void id_sort_by_name(ListBase *lb, ID *id, ID *id_sorting_hint)
@@ -1716,21 +1688,17 @@ static void library_make_local_copying_check(ID *id,
/* Used_to_user stores ID pointer, not pointer to ID pointer. */
ID *par_id = (ID *)entry->id_pointer;
- /* Our oh-so-beloved 'from' pointers... */
+ /* Our oh-so-beloved 'from' pointers... Those should always be ignored here, since the actual
+ * relation we want to check is in the other way around. */
if (entry->usage_flag & IDWALK_CB_LOOPBACK) {
- /* We totally disregard Object->proxy_from 'usage' here,
- * this one would only generate fake positives. */
- if (GS(par_id->name) == ID_OB) {
- BLI_assert(((Object *)par_id)->proxy_from == (Object *)id);
- continue;
- }
+ continue;
+ }
- /* Shapekeys are considered 'private' to their owner ID here, and never tagged
- * (since they cannot be linked), so we have to switch effective parent to their owner.
- */
- if (GS(par_id->name) == ID_KE) {
- par_id = ((Key *)par_id)->from;
- }
+ /* Shapekeys are considered 'private' to their owner ID here, and never tagged
+ * (since they cannot be linked), so we have to switch effective parent to their owner.
+ */
+ if (GS(par_id->name) == ID_KE) {
+ par_id = ((Key *)par_id)->from;
}
if (par_id->lib == NULL) {
@@ -2218,14 +2186,14 @@ void BKE_id_ordered_list(ListBase *ordered_lb, const ListBase *lb)
{
BLI_listbase_clear(ordered_lb);
- for (ID *id = lb->first; id; id = id->next) {
+ LISTBASE_FOREACH (ID *, id, lb) {
BLI_addtail(ordered_lb, BLI_genericNodeN(id));
}
BLI_listbase_sort(ordered_lb, id_order_compare);
int num = 0;
- for (LinkData *link = ordered_lb->first; link; link = link->next) {
+ LISTBASE_FOREACH (LinkData *, link, ordered_lb) {
int *order = id_order_get(link->data);
if (order) {
*order = num++;
@@ -2250,7 +2218,7 @@ void BKE_id_reorder(const ListBase *lb, ID *id, ID *relative, bool after)
if (after) {
/* Insert after. */
- for (ID *other = lb->first; other; other = other->next) {
+ LISTBASE_FOREACH (ID *, other, lb) {
int *order = id_order_get(other);
if (*order > relative_order) {
(*order)++;
@@ -2261,7 +2229,7 @@ void BKE_id_reorder(const ListBase *lb, ID *id, ID *relative, bool after)
}
else {
/* Insert before. */
- for (ID *other = lb->first; other; other = other->next) {
+ LISTBASE_FOREACH (ID *, other, lb) {
int *order = id_order_get(other);
if (*order < relative_order) {
(*order)--;
diff --git a/source/blender/blenkernel/intern/lib_id_delete.c b/source/blender/blenkernel/intern/lib_id_delete.c
index e1f4f36b822..7c96d0a6401 100644
--- a/source/blender/blenkernel/intern/lib_id_delete.c
+++ b/source/blender/blenkernel/intern/lib_id_delete.c
@@ -23,80 +23,20 @@
#include "MEM_guardedalloc.h"
/* all types are needed here, in order to do memory operations */
-#include "DNA_armature_types.h"
-#include "DNA_brush_types.h"
-#include "DNA_cachefile_types.h"
-#include "DNA_camera_types.h"
-#include "DNA_collection_types.h"
-#include "DNA_gpencil_types.h"
-#include "DNA_ipo_types.h"
-#include "DNA_key_types.h"
-#include "DNA_lattice_types.h"
-#include "DNA_light_types.h"
-#include "DNA_lightprobe_types.h"
-#include "DNA_linestyle_types.h"
-#include "DNA_mask_types.h"
-#include "DNA_material_types.h"
-#include "DNA_mesh_types.h"
-#include "DNA_meta_types.h"
-#include "DNA_movieclip_types.h"
-#include "DNA_node_types.h"
-#include "DNA_object_types.h"
-#include "DNA_scene_types.h"
-#include "DNA_screen_types.h"
-#include "DNA_sound_types.h"
-#include "DNA_speaker_types.h"
-#include "DNA_text_types.h"
-#include "DNA_vfont_types.h"
-#include "DNA_windowmanager_types.h"
-#include "DNA_workspace_types.h"
-#include "DNA_world_types.h"
+#include "DNA_ID.h"
#include "BLI_utildefines.h"
#include "BLI_listbase.h"
-#include "BKE_action.h"
-#include "BKE_animsys.h"
-#include "BKE_armature.h"
-#include "BKE_brush.h"
-#include "BKE_cachefile.h"
-#include "BKE_camera.h"
-#include "BKE_collection.h"
-#include "BKE_curve.h"
-#include "BKE_font.h"
-#include "BKE_gpencil.h"
+#include "BKE_anim_data.h"
#include "BKE_idprop.h"
#include "BKE_idtype.h"
-#include "BKE_image.h"
-#include "BKE_ipo.h"
-#include "BKE_key.h"
-#include "BKE_lattice.h"
#include "BKE_lib_id.h"
#include "BKE_lib_override.h"
#include "BKE_lib_remap.h"
#include "BKE_library.h"
-#include "BKE_light.h"
-#include "BKE_lightprobe.h"
-#include "BKE_linestyle.h"
#include "BKE_main.h"
-#include "BKE_mask.h"
-#include "BKE_material.h"
-#include "BKE_mball.h"
-#include "BKE_mesh.h"
-#include "BKE_movieclip.h"
-#include "BKE_node.h"
-#include "BKE_object.h"
-#include "BKE_paint.h"
-#include "BKE_particle.h"
-#include "BKE_scene.h"
-#include "BKE_screen.h"
-#include "BKE_sound.h"
-#include "BKE_speaker.h"
-#include "BKE_text.h"
-#include "BKE_texture.h"
-#include "BKE_workspace.h"
-#include "BKE_world.h"
#include "lib_intern.h"
@@ -188,6 +128,8 @@ void BKE_id_free_ex(Main *bmain, void *idv, int flag, const bool use_flag_from_i
const short type = GS(id->name);
if (bmain && (flag & LIB_ID_FREE_NO_DEG_TAG) == 0) {
+ BLI_assert(bmain->is_locked_for_linking == false);
+
DEG_id_type_tag(bmain, type);
}
diff --git a/source/blender/blenkernel/intern/lib_override.c b/source/blender/blenkernel/intern/lib_override.c
index 42d1806a41a..9426d229e01 100644
--- a/source/blender/blenkernel/intern/lib_override.c
+++ b/source/blender/blenkernel/intern/lib_override.c
@@ -46,6 +46,11 @@
#include "RNA_types.h"
#define OVERRIDE_AUTO_CHECK_DELAY 0.2 /* 200ms between auto-override checks. */
+//#define DEBUG_OVERRIDE_TIMEIT
+
+#ifdef DEBUG_OVERRIDE_TIMEIT
+# include "PIL_time_utildefines.h"
+#endif
static void lib_override_library_property_copy(IDOverrideLibraryProperty *op_dst,
IDOverrideLibraryProperty *op_src);
@@ -153,7 +158,7 @@ void BKE_lib_override_library_clear(IDOverrideLibrary *override, const bool do_i
BLI_ghash_clear(override->runtime, NULL, NULL);
}
- for (IDOverrideLibraryProperty *op = override->properties.first; op; op = op->next) {
+ LISTBASE_FOREACH (IDOverrideLibraryProperty *, op, &override->properties) {
lib_override_library_property_clear(op);
}
BLI_freelistN(&override->properties);
@@ -371,7 +376,7 @@ void lib_override_library_property_clear(IDOverrideLibraryProperty *op)
MEM_freeN(op->rna_path);
- for (IDOverrideLibraryPropertyOperation *opop = op->operations.first; opop; opop = opop->next) {
+ LISTBASE_FOREACH (IDOverrideLibraryPropertyOperation *, opop, &op->operations) {
lib_override_library_property_operation_clear(opop);
}
BLI_freelistN(&op->operations);
@@ -383,10 +388,10 @@ void lib_override_library_property_clear(IDOverrideLibraryProperty *op)
void BKE_lib_override_library_property_delete(IDOverrideLibrary *override,
IDOverrideLibraryProperty *override_property)
{
- lib_override_library_property_clear(override_property);
if (override->runtime != NULL) {
BLI_ghash_remove(override->runtime, override_property->rna_path, NULL, NULL);
}
+ lib_override_library_property_clear(override_property);
BLI_freelinkN(&override->properties, override_property);
}
@@ -559,6 +564,46 @@ void BKE_lib_override_library_property_operation_delete(
}
/**
+ * Validate that required data for a given operation are available.
+ */
+bool BKE_lib_override_library_property_operation_operands_validate(
+ struct IDOverrideLibraryPropertyOperation *override_property_operation,
+ struct PointerRNA *ptr_dst,
+ struct PointerRNA *ptr_src,
+ struct PointerRNA *ptr_storage,
+ struct PropertyRNA *prop_dst,
+ struct PropertyRNA *prop_src,
+ struct PropertyRNA *prop_storage)
+{
+ switch (override_property_operation->operation) {
+ case IDOVERRIDE_LIBRARY_OP_NOOP:
+ return true;
+ case IDOVERRIDE_LIBRARY_OP_ADD:
+ ATTR_FALLTHROUGH;
+ case IDOVERRIDE_LIBRARY_OP_SUBTRACT:
+ ATTR_FALLTHROUGH;
+ case IDOVERRIDE_LIBRARY_OP_MULTIPLY:
+ if (ptr_storage == NULL || ptr_storage->data == NULL || prop_storage == NULL) {
+ BLI_assert(!"Missing data to apply differential override operation.");
+ return false;
+ }
+ ATTR_FALLTHROUGH;
+ case IDOVERRIDE_LIBRARY_OP_INSERT_AFTER:
+ ATTR_FALLTHROUGH;
+ case IDOVERRIDE_LIBRARY_OP_INSERT_BEFORE:
+ ATTR_FALLTHROUGH;
+ case IDOVERRIDE_LIBRARY_OP_REPLACE:
+ if ((ptr_dst == NULL || ptr_dst->data == NULL || prop_dst == NULL) ||
+ (ptr_src == NULL || ptr_src->data == NULL || prop_src == NULL)) {
+ BLI_assert(!"Missing data to apply override operation.");
+ return false;
+ }
+ }
+
+ return true;
+}
+
+/**
* 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
@@ -704,8 +749,8 @@ bool BKE_lib_override_library_operations_create(Main *bmain, ID *local, const bo
if (GS(local->name) == ID_OB) {
/* Our beloved pose's bone cross-data pointers... Usually, depsgraph evaluation would ensure
- * this is valid, but in some cases (like hidden collections etc.) this won't be the case, so
- * we need to take care of this ourselves. */
+ * this is valid, but in some situations (like hidden collections etc.) this won't be the
+ * case, so we need to take care of this ourselves. */
Object *ob_local = (Object *)local;
if (ob_local->data != NULL && ob_local->type == OB_ARMATURE && ob_local->pose != NULL &&
ob_local->pose->flag & POSE_RECALC) {
@@ -748,6 +793,12 @@ void BKE_lib_override_library_main_operations_create(Main *bmain, const bool for
{
ID *id;
+ /* When force-auto is set, we also remove all unused existing override properties & operations.
+ */
+ if (force_auto) {
+ BKE_lib_override_library_main_tag(bmain, IDOVERRIDE_LIBRARY_TAG_UNUSED, true);
+ }
+
FOREACH_MAIN_ID_BEGIN (bmain, id) {
if ((ID_IS_OVERRIDE_LIBRARY(id) && force_auto) ||
(ID_IS_OVERRIDE_LIBRARY_AUTO(id) && (id->tag & LIB_TAG_OVERRIDE_LIBRARY_AUTOREFRESH))) {
@@ -756,6 +807,92 @@ void BKE_lib_override_library_main_operations_create(Main *bmain, const bool for
}
}
FOREACH_MAIN_ID_END;
+
+ if (force_auto) {
+ BKE_lib_override_library_main_unused_cleanup(bmain);
+ }
+}
+
+/** Set or clear given tag in all operations as unused in that override property data. */
+void BKE_lib_override_library_operations_tag(struct IDOverrideLibraryProperty *override_property,
+ const short tag,
+ const bool do_set)
+{
+ if (override_property != NULL) {
+ if (do_set) {
+ override_property->tag |= tag;
+ }
+ else {
+ override_property->tag &= ~tag;
+ }
+
+ LISTBASE_FOREACH (IDOverrideLibraryPropertyOperation *, opop, &override_property->operations) {
+ if (do_set) {
+ opop->tag |= tag;
+ }
+ else {
+ opop->tag &= ~tag;
+ }
+ }
+ }
+}
+
+/** Set or clear given tag in all properties and operations in that override data. */
+void BKE_lib_override_library_properties_tag(struct IDOverrideLibrary *override,
+ const short tag,
+ const bool do_set)
+{
+ if (override != NULL) {
+ LISTBASE_FOREACH (IDOverrideLibraryProperty *, op, &override->properties) {
+ BKE_lib_override_library_operations_tag(op, tag, do_set);
+ }
+ }
+}
+
+/** Set or clear given tag in all properties and operations in that Main's ID override data. */
+void BKE_lib_override_library_main_tag(struct Main *bmain, const short tag, const bool do_set)
+{
+ ID *id;
+
+ FOREACH_MAIN_ID_BEGIN (bmain, id) {
+ if (ID_IS_OVERRIDE_LIBRARY(id)) {
+ BKE_lib_override_library_properties_tag(id->override_library, tag, do_set);
+ }
+ }
+ FOREACH_MAIN_ID_END;
+}
+
+/** Remove all tagged-as-unused properties and operations from that ID override data. */
+void BKE_lib_override_library_id_unused_cleanup(struct ID *local)
+{
+ if (local->override_library != NULL) {
+ LISTBASE_FOREACH_MUTABLE (
+ IDOverrideLibraryProperty *, op, &local->override_library->properties) {
+ if (op->tag & IDOVERRIDE_LIBRARY_TAG_UNUSED) {
+ BKE_lib_override_library_property_delete(local->override_library, op);
+ }
+ else {
+ LISTBASE_FOREACH_MUTABLE (IDOverrideLibraryPropertyOperation *, opop, &op->operations) {
+ if (opop->tag & IDOVERRIDE_LIBRARY_TAG_UNUSED) {
+ BKE_lib_override_library_property_operation_delete(op, opop);
+ }
+ }
+ }
+ }
+ }
+}
+
+/** Remove all tagged-as-unused properties and operations from that Main's ID override data. */
+void BKE_lib_override_library_main_unused_cleanup(struct Main *bmain)
+{
+ ID *id;
+
+ FOREACH_MAIN_ID_BEGIN (bmain, id) {
+ if (ID_IS_OVERRIDE_LIBRARY(id)) {
+ BKE_lib_override_library_id_unused_cleanup(id);
+ }
+ }
+ FOREACH_MAIN_ID_END;
}
/** Update given override from its reference (re-applying overridden properties). */
@@ -895,7 +1032,7 @@ ID *BKE_lib_override_library_operations_store_start(Main *bmain,
ID *storage_id;
#ifdef DEBUG_OVERRIDE_TIMEIT
- TIMEIT_START_AVERAGED(BKE_override_operations_store_start);
+ TIMEIT_START_AVERAGED(BKE_lib_override_library_operations_store_start);
#endif
/* XXX TODO We may also want a specialized handling of things here too, to avoid copying heavy
@@ -923,12 +1060,13 @@ ID *BKE_lib_override_library_operations_store_start(Main *bmain,
local->override_library->storage = storage_id;
#ifdef DEBUG_OVERRIDE_TIMEIT
- TIMEIT_END_AVERAGED(BKE_override_operations_store_start);
+ TIMEIT_END_AVERAGED(BKE_lib_override_library_operations_store_start);
#endif
return storage_id;
}
-/** Restore given ID modified by \a BKE_override_operations_store_start, to its original state. */
+/** Restore given ID modified by \a BKE_lib_override_library_operations_store_start, to its
+ * original state. */
void BKE_lib_override_library_operations_store_end(
OverrideLibraryStorage *UNUSED(override_storage), ID *local)
{
diff --git a/source/blender/blenkernel/intern/lib_query.c b/source/blender/blenkernel/intern/lib_query.c
index 886fb4241a4..00a42b12e07 100644
--- a/source/blender/blenkernel/intern/lib_query.c
+++ b/source/blender/blenkernel/intern/lib_query.c
@@ -24,114 +24,19 @@
#include <stdlib.h>
#include "DNA_anim_types.h"
-#include "DNA_armature_types.h"
-#include "DNA_brush_types.h"
-#include "DNA_camera_types.h"
-#include "DNA_collection_types.h"
-#include "DNA_constraint_types.h"
-#include "DNA_gpencil_types.h"
-#include "DNA_hair_types.h"
-#include "DNA_key_types.h"
-#include "DNA_lattice_types.h"
-#include "DNA_light_types.h"
-#include "DNA_lightprobe_types.h"
-#include "DNA_linestyle_types.h"
-#include "DNA_mask_types.h"
-#include "DNA_material_types.h"
-#include "DNA_mesh_types.h"
-#include "DNA_meta_types.h"
-#include "DNA_movieclip_types.h"
-#include "DNA_node_types.h"
-#include "DNA_object_force_types.h"
-#include "DNA_outliner_types.h"
-#include "DNA_pointcloud_types.h"
-#include "DNA_rigidbody_types.h"
-#include "DNA_scene_types.h"
-#include "DNA_screen_types.h"
-#include "DNA_sequence_types.h"
-#include "DNA_sound_types.h"
-#include "DNA_space_types.h"
-#include "DNA_speaker_types.h"
-#include "DNA_text_types.h"
-#include "DNA_vfont_types.h"
-#include "DNA_volume_types.h"
-#include "DNA_windowmanager_types.h"
-#include "DNA_workspace_types.h"
-#include "DNA_world_types.h"
#include "BLI_ghash.h"
#include "BLI_linklist_stack.h"
+#include "BLI_listbase.h"
#include "BLI_utildefines.h"
-#include "BKE_animsys.h"
-#include "BKE_collection.h"
-#include "BKE_constraint.h"
-#include "BKE_fcurve.h"
-#include "BKE_gpencil_modifier.h"
+#include "BKE_anim_data.h"
#include "BKE_idprop.h"
+#include "BKE_idtype.h"
#include "BKE_lib_id.h"
#include "BKE_lib_query.h"
#include "BKE_main.h"
-#include "BKE_modifier.h"
#include "BKE_node.h"
-#include "BKE_particle.h"
-#include "BKE_rigidbody.h"
-#include "BKE_sequencer.h"
-#include "BKE_shader_fx.h"
-#include "BKE_workspace.h"
-
-#define FOREACH_FINALIZE _finalize
-#define FOREACH_FINALIZE_VOID \
- if (0) { \
- goto FOREACH_FINALIZE; \
- } \
- FOREACH_FINALIZE: \
- ((void)0)
-
-#define FOREACH_CALLBACK_INVOKE_ID_PP(_data, id_pp, _cb_flag) \
- CHECK_TYPE(id_pp, ID **); \
- if (!((_data)->status & IDWALK_STOP)) { \
- const int _flag = (_data)->flag; \
- ID *old_id = *(id_pp); \
- const int callback_return = (_data)->callback(&(struct LibraryIDLinkCallbackData){ \
- .user_data = (_data)->user_data, \
- .id_owner = (_data)->owner_id, \
- .id_self = (_data)->self_id, \
- .id_pointer = id_pp, \
- .cb_flag = ((_cb_flag | (_data)->cb_flag) & ~(_data)->cb_flag_clear)}); \
- if (_flag & IDWALK_READONLY) { \
- BLI_assert(*(id_pp) == old_id); \
- } \
- if (old_id && (_flag & IDWALK_RECURSE)) { \
- if (BLI_gset_add((_data)->ids_handled, old_id)) { \
- if (!(callback_return & IDWALK_RET_STOP_RECURSION)) { \
- BLI_LINKSTACK_PUSH((_data)->ids_todo, old_id); \
- } \
- } \
- } \
- if (callback_return & IDWALK_RET_STOP_ITER) { \
- (_data)->status |= IDWALK_STOP; \
- goto FOREACH_FINALIZE; \
- } \
- } \
- else { \
- goto FOREACH_FINALIZE; \
- } \
- ((void)0)
-
-#define FOREACH_CALLBACK_INVOKE_ID(_data, id, cb_flag) \
- { \
- CHECK_TYPE_ANY(id, ID *, void *); \
- FOREACH_CALLBACK_INVOKE_ID_PP(_data, (ID **)&(id), cb_flag); \
- } \
- ((void)0)
-
-#define FOREACH_CALLBACK_INVOKE(_data, id_super, cb_flag) \
- { \
- CHECK_TYPE(&((id_super)->id), ID *); \
- FOREACH_CALLBACK_INVOKE_ID_PP(_data, (ID **)&(id_super), cb_flag); \
- } \
- ((void)0)
/* status */
enum {
@@ -163,380 +68,89 @@ typedef struct LibraryForeachIDData {
BLI_LINKSTACK_DECLARE(ids_todo, ID *);
} LibraryForeachIDData;
-static void library_foreach_ID_link(Main *bmain,
- ID *id_owner,
- ID *id,
- LibraryIDLinkCallback callback,
- void *user_data,
- int flag,
- LibraryForeachIDData *inherit_data);
-
-static void library_foreach_idproperty_ID_link(LibraryForeachIDData *data,
- IDProperty *prop,
- int flag)
+bool BKE_lib_query_foreachid_process(LibraryForeachIDData *data, ID **id_pp, int cb_flag)
{
- if (!prop) {
- return;
- }
-
- switch (prop->type) {
- case IDP_GROUP: {
- for (IDProperty *loop = prop->data.group.first; loop; loop = loop->next) {
- library_foreach_idproperty_ID_link(data, loop, flag);
- }
- break;
+ if (!(data->status & IDWALK_STOP)) {
+ const int flag = data->flag;
+ ID *old_id = *id_pp;
+ const int callback_return = data->callback(&(struct LibraryIDLinkCallbackData){
+ .user_data = data->user_data,
+ .bmain = data->bmain,
+ .id_owner = data->owner_id,
+ .id_self = data->self_id,
+ .id_pointer = id_pp,
+ .cb_flag = ((cb_flag | data->cb_flag) & ~data->cb_flag_clear)});
+ if (flag & IDWALK_READONLY) {
+ BLI_assert(*(id_pp) == old_id);
}
- case IDP_IDPARRAY: {
- IDProperty *loop = IDP_Array(prop);
- for (int i = 0; i < prop->len; i++) {
- library_foreach_idproperty_ID_link(data, &loop[i], flag);
- }
- break;
- }
- case IDP_ID:
- FOREACH_CALLBACK_INVOKE_ID(data, prop->data.pointer, flag);
- break;
- default:
- break; /* Nothing to do here with other types of IDProperties... */
- }
-
- FOREACH_FINALIZE_VOID;
-}
-
-static void library_foreach_rigidbodyworldSceneLooper(struct RigidBodyWorld *UNUSED(rbw),
- ID **id_pointer,
- void *user_data,
- int cb_flag)
-{
- LibraryForeachIDData *data = (LibraryForeachIDData *)user_data;
- FOREACH_CALLBACK_INVOKE_ID_PP(data, id_pointer, cb_flag);
-
- FOREACH_FINALIZE_VOID;
-}
-
-static void library_foreach_modifiersForeachIDLink(void *user_data,
- Object *UNUSED(object),
- ID **id_pointer,
- int cb_flag)
-{
- LibraryForeachIDData *data = (LibraryForeachIDData *)user_data;
- FOREACH_CALLBACK_INVOKE_ID_PP(data, id_pointer, cb_flag);
-
- FOREACH_FINALIZE_VOID;
-}
-
-static void library_foreach_gpencil_modifiersForeachIDLink(void *user_data,
- Object *UNUSED(object),
- ID **id_pointer,
- int cb_flag)
-{
- LibraryForeachIDData *data = (LibraryForeachIDData *)user_data;
- FOREACH_CALLBACK_INVOKE_ID_PP(data, id_pointer, cb_flag);
-
- FOREACH_FINALIZE_VOID;
-}
-
-static void library_foreach_shaderfxForeachIDLink(void *user_data,
- Object *UNUSED(object),
- ID **id_pointer,
- int cb_flag)
-{
- LibraryForeachIDData *data = (LibraryForeachIDData *)user_data;
- FOREACH_CALLBACK_INVOKE_ID_PP(data, id_pointer, cb_flag);
-
- FOREACH_FINALIZE_VOID;
-}
-
-static void library_foreach_constraintObjectLooper(bConstraint *UNUSED(con),
- ID **id_pointer,
- bool is_reference,
- void *user_data)
-{
- LibraryForeachIDData *data = (LibraryForeachIDData *)user_data;
- const int cb_flag = is_reference ? IDWALK_CB_USER : IDWALK_CB_NOP;
- FOREACH_CALLBACK_INVOKE_ID_PP(data, id_pointer, cb_flag);
-
- FOREACH_FINALIZE_VOID;
-}
-
-static void library_foreach_particlesystemsObjectLooper(ParticleSystem *UNUSED(psys),
- ID **id_pointer,
- void *user_data,
- int cb_flag)
-{
- LibraryForeachIDData *data = (LibraryForeachIDData *)user_data;
- FOREACH_CALLBACK_INVOKE_ID_PP(data, id_pointer, cb_flag);
-
- FOREACH_FINALIZE_VOID;
-}
-
-static void library_foreach_nla_strip(LibraryForeachIDData *data, NlaStrip *strip)
-{
- NlaStrip *substrip;
-
- FOREACH_CALLBACK_INVOKE(data, strip->act, IDWALK_CB_USER);
-
- for (substrip = strip->strips.first; substrip; substrip = substrip->next) {
- library_foreach_nla_strip(data, substrip);
- }
-
- FOREACH_FINALIZE_VOID;
-}
-
-static void library_foreach_animationData(LibraryForeachIDData *data, AnimData *adt)
-{
- FCurve *fcu;
- NlaTrack *nla_track;
- NlaStrip *nla_strip;
-
- for (fcu = adt->drivers.first; fcu; fcu = fcu->next) {
- ChannelDriver *driver = fcu->driver;
- DriverVar *dvar;
-
- for (dvar = driver->variables.first; dvar; dvar = dvar->next) {
- /* only used targets */
- DRIVER_TARGETS_USED_LOOPER_BEGIN (dvar) {
- FOREACH_CALLBACK_INVOKE_ID(data, dtar->id, IDWALK_CB_NOP);
+ if (old_id && (flag & IDWALK_RECURSE)) {
+ if (BLI_gset_add((data)->ids_handled, old_id)) {
+ if (!(callback_return & IDWALK_RET_STOP_RECURSION)) {
+ BLI_LINKSTACK_PUSH(data->ids_todo, old_id);
+ }
}
- DRIVER_TARGETS_LOOPER_END;
}
- }
-
- FOREACH_CALLBACK_INVOKE(data, adt->action, IDWALK_CB_USER);
- FOREACH_CALLBACK_INVOKE(data, adt->tmpact, IDWALK_CB_USER);
-
- for (nla_track = adt->nla_tracks.first; nla_track; nla_track = nla_track->next) {
- for (nla_strip = nla_track->strips.first; nla_strip; nla_strip = nla_strip->next) {
- library_foreach_nla_strip(data, nla_strip);
+ if (callback_return & IDWALK_RET_STOP_ITER) {
+ data->status |= IDWALK_STOP;
+ return false;
}
+ return true;
}
-
- FOREACH_FINALIZE_VOID;
-}
-
-static void library_foreach_mtex(LibraryForeachIDData *data, MTex *mtex)
-{
- FOREACH_CALLBACK_INVOKE(data, mtex->object, IDWALK_CB_NOP);
- FOREACH_CALLBACK_INVOKE(data, mtex->tex, IDWALK_CB_USER);
-
- FOREACH_FINALIZE_VOID;
-}
-
-static void library_foreach_paint(LibraryForeachIDData *data, Paint *paint)
-{
- FOREACH_CALLBACK_INVOKE(data, paint->brush, IDWALK_CB_USER);
- for (int i = 0; i < paint->tool_slots_len; i++) {
- FOREACH_CALLBACK_INVOKE(data, paint->tool_slots[i].brush, IDWALK_CB_USER);
- }
- FOREACH_CALLBACK_INVOKE(data, paint->palette, IDWALK_CB_USER);
-
- FOREACH_FINALIZE_VOID;
-}
-
-static void library_foreach_bone(LibraryForeachIDData *data, Bone *bone)
-{
- library_foreach_idproperty_ID_link(data, bone->prop, IDWALK_CB_USER);
-
- for (Bone *curbone = bone->childbase.first; curbone; curbone = curbone->next) {
- library_foreach_bone(data, curbone);
+ else {
+ return false;
}
-
- FOREACH_FINALIZE_VOID;
}
-static void library_foreach_layer_collection(LibraryForeachIDData *data, ListBase *lb)
+int BKE_lib_query_foreachid_process_flags_get(LibraryForeachIDData *data)
{
- for (LayerCollection *lc = lb->first; lc; lc = lc->next) {
- /* XXX This is very weak. The whole idea of keeping pointers to private IDs is very bad
- * anyway... */
- const int cb_flag = (lc->collection != NULL &&
- (lc->collection->id.flag & LIB_EMBEDDED_DATA) != 0) ?
- IDWALK_CB_EMBEDDED :
- IDWALK_CB_NOP;
- FOREACH_CALLBACK_INVOKE(data, lc->collection, cb_flag);
- library_foreach_layer_collection(data, &lc->layer_collections);
- }
-
- FOREACH_FINALIZE_VOID;
+ return data->flag;
}
-/* Used by both real Collection data-blocks, and the fake horror of master collection from Scene.
- */
-static void library_foreach_collection(LibraryForeachIDData *data, Collection *collection)
+int BKE_lib_query_foreachid_process_callback_flag_override(LibraryForeachIDData *data,
+ const int cb_flag,
+ const bool do_replace)
{
- for (CollectionObject *cob = collection->gobject.first; cob; cob = cob->next) {
- FOREACH_CALLBACK_INVOKE(data, cob->ob, IDWALK_CB_USER);
- }
- for (CollectionChild *child = collection->children.first; child; child = child->next) {
- FOREACH_CALLBACK_INVOKE(data, child->collection, IDWALK_CB_NEVER_SELF | IDWALK_CB_USER);
+ const int cb_flag_backup = data->cb_flag;
+ if (do_replace) {
+ data->cb_flag = cb_flag;
}
- for (CollectionParent *parent = collection->parents.first; parent; parent = parent->next) {
- /* XXX This is very weak. The whole idea of keeping pointers to private IDs is very bad
- * anyway... */
- const int cb_flag = ((parent->collection != NULL &&
- (parent->collection->id.flag & LIB_EMBEDDED_DATA) != 0) ?
- IDWALK_CB_EMBEDDED :
- IDWALK_CB_NOP);
- FOREACH_CALLBACK_INVOKE(
- data, parent->collection, IDWALK_CB_NEVER_SELF | IDWALK_CB_LOOPBACK | cb_flag);
+ else {
+ data->cb_flag |= cb_flag;
}
-
- FOREACH_FINALIZE_VOID;
+ return cb_flag_backup;
}
-static void library_foreach_dopesheet(LibraryForeachIDData *data, bDopeSheet *ads)
-{
- if (ads != NULL) {
- FOREACH_CALLBACK_INVOKE_ID(data, ads->source, IDWALK_CB_NOP);
- FOREACH_CALLBACK_INVOKE(data, ads->filter_grp, IDWALK_CB_NOP);
- }
-
- FOREACH_FINALIZE_VOID;
-}
+static void library_foreach_ID_link(Main *bmain,
+ ID *id_owner,
+ ID *id,
+ LibraryIDLinkCallback callback,
+ void *user_data,
+ int flag,
+ LibraryForeachIDData *inherit_data);
-static void library_foreach_screen_area(LibraryForeachIDData *data, ScrArea *area)
+void BKE_lib_query_idpropertiesForeachIDLink_callback(IDProperty *id_prop, void *user_data)
{
- FOREACH_CALLBACK_INVOKE(data, area->full, IDWALK_CB_NOP);
-
- for (SpaceLink *sl = area->spacedata.first; sl; sl = sl->next) {
- switch (sl->spacetype) {
- case SPACE_VIEW3D: {
- View3D *v3d = (View3D *)sl;
-
- FOREACH_CALLBACK_INVOKE(data, v3d->camera, IDWALK_CB_NOP);
- FOREACH_CALLBACK_INVOKE(data, v3d->ob_center, IDWALK_CB_NOP);
-
- if (v3d->localvd) {
- FOREACH_CALLBACK_INVOKE(data, v3d->localvd->camera, IDWALK_CB_NOP);
- }
- break;
- }
- case SPACE_GRAPH: {
- SpaceGraph *sipo = (SpaceGraph *)sl;
-
- library_foreach_dopesheet(data, sipo->ads);
- break;
- }
- case SPACE_PROPERTIES: {
- SpaceProperties *sbuts = (SpaceProperties *)sl;
-
- FOREACH_CALLBACK_INVOKE_ID(data, sbuts->pinid, IDWALK_CB_NOP);
- break;
- }
- case SPACE_FILE:
- break;
- case SPACE_ACTION: {
- SpaceAction *saction = (SpaceAction *)sl;
-
- library_foreach_dopesheet(data, &saction->ads);
- FOREACH_CALLBACK_INVOKE(data, saction->action, IDWALK_CB_NOP);
- break;
- }
- case SPACE_IMAGE: {
- SpaceImage *sima = (SpaceImage *)sl;
-
- FOREACH_CALLBACK_INVOKE(data, sima->image, IDWALK_CB_USER_ONE);
- FOREACH_CALLBACK_INVOKE(data, sima->mask_info.mask, IDWALK_CB_USER_ONE);
- FOREACH_CALLBACK_INVOKE(data, sima->gpd, IDWALK_CB_USER);
- break;
- }
- case SPACE_SEQ: {
- SpaceSeq *sseq = (SpaceSeq *)sl;
-
- FOREACH_CALLBACK_INVOKE(data, sseq->gpd, IDWALK_CB_USER);
- break;
- }
- case SPACE_NLA: {
- SpaceNla *snla = (SpaceNla *)sl;
-
- library_foreach_dopesheet(data, snla->ads);
- break;
- }
- case SPACE_TEXT: {
- SpaceText *st = (SpaceText *)sl;
-
- FOREACH_CALLBACK_INVOKE(data, st->text, IDWALK_CB_NOP);
- break;
- }
- case SPACE_SCRIPT: {
- SpaceScript *scpt = (SpaceScript *)sl;
-
- FOREACH_CALLBACK_INVOKE(data, scpt->script, IDWALK_CB_NOP);
- break;
- }
- case SPACE_OUTLINER: {
- SpaceOutliner *so = (SpaceOutliner *)sl;
-
- FOREACH_CALLBACK_INVOKE_ID(data, so->search_tse.id, IDWALK_CB_NOP);
-
- if (so->treestore != NULL) {
- TreeStoreElem *tselem;
- BLI_mempool_iter iter;
-
- BLI_mempool_iternew(so->treestore, &iter);
- while ((tselem = BLI_mempool_iterstep(&iter))) {
- FOREACH_CALLBACK_INVOKE_ID(data, tselem->id, IDWALK_CB_NOP);
- }
- }
- break;
- }
- case SPACE_NODE: {
- SpaceNode *snode = (SpaceNode *)sl;
- bNodeTreePath *path;
-
- const bool is_private_nodetree = snode->id != NULL &&
- ntreeFromID(snode->id) == snode->nodetree;
-
- FOREACH_CALLBACK_INVOKE_ID(data, snode->id, IDWALK_CB_NOP);
- FOREACH_CALLBACK_INVOKE_ID(data, snode->from, IDWALK_CB_NOP);
-
- FOREACH_CALLBACK_INVOKE(
- data, snode->nodetree, is_private_nodetree ? IDWALK_CB_EMBEDDED : IDWALK_CB_USER);
-
- for (path = snode->treepath.first; path; path = path->next) {
- if (path == snode->treepath.first) {
- /* first nodetree in path is same as snode->nodetree */
- FOREACH_CALLBACK_INVOKE(
- data, path->nodetree, is_private_nodetree ? IDWALK_CB_EMBEDDED : IDWALK_CB_NOP);
- }
- else {
- FOREACH_CALLBACK_INVOKE(data, path->nodetree, IDWALK_CB_USER);
- }
-
- if (path->nodetree == NULL) {
- break;
- }
- }
-
- FOREACH_CALLBACK_INVOKE(data, snode->edittree, IDWALK_CB_NOP);
- break;
- }
- case SPACE_CLIP: {
- SpaceClip *sclip = (SpaceClip *)sl;
+ BLI_assert(id_prop->type == IDP_ID);
- FOREACH_CALLBACK_INVOKE(data, sclip->clip, IDWALK_CB_USER_ONE);
- FOREACH_CALLBACK_INVOKE(data, sclip->mask_info.mask, IDWALK_CB_USER_ONE);
- break;
- }
- default:
- break;
- }
- }
-
- FOREACH_FINALIZE_VOID;
+ LibraryForeachIDData *data = (LibraryForeachIDData *)user_data;
+ BKE_LIB_FOREACHID_PROCESS_ID(data, id_prop->data.pointer, IDWALK_CB_USER);
}
-static void library_foreach_ID_as_subdata_link(ID **id_pp,
- LibraryIDLinkCallback callback,
- void *user_data,
- int flag,
- LibraryForeachIDData *data)
+bool BKE_library_foreach_ID_embedded(LibraryForeachIDData *data, ID **id_pp)
{
/* Needed e.g. for callbacks handling relationships... This call shall be absolutely readonly. */
ID *id = *id_pp;
- FOREACH_CALLBACK_INVOKE_ID_PP(data, id_pp, IDWALK_CB_EMBEDDED);
+ const int flag = data->flag;
+
+ if (!BKE_lib_query_foreachid_process(data, id_pp, IDWALK_CB_EMBEDDED)) {
+ return false;
+ }
BLI_assert(id == *id_pp);
+ if (id == NULL) {
+ return true;
+ }
+
if (flag & IDWALK_IGNORE_EMBEDDED_ID) {
/* Do Nothing. */
}
@@ -550,10 +164,11 @@ static void library_foreach_ID_as_subdata_link(ID **id_pp,
}
}
else {
- library_foreach_ID_link(data->bmain, data->owner_id, id, callback, user_data, flag, data);
+ library_foreach_ID_link(
+ data->bmain, data->owner_id, id, data->callback, data->user_data, data->flag, data);
}
- FOREACH_FINALIZE_VOID;
+ return true;
}
static void library_foreach_ID_link(Main *bmain,
@@ -565,7 +180,6 @@ static void library_foreach_ID_link(Main *bmain,
LibraryForeachIDData *inherit_data)
{
LibraryForeachIDData data = {.bmain = bmain};
- int i;
BLI_assert(inherit_data == NULL || data.bmain == inherit_data->bmain);
@@ -586,10 +200,11 @@ static void library_foreach_ID_link(Main *bmain,
data.callback = callback;
data.user_data = user_data;
-#define CALLBACK_INVOKE_ID(check_id, cb_flag) FOREACH_CALLBACK_INVOKE_ID(&data, check_id, cb_flag)
+#define CALLBACK_INVOKE_ID(check_id, cb_flag) \
+ BKE_LIB_FOREACHID_PROCESS_ID(&data, check_id, cb_flag)
#define CALLBACK_INVOKE(check_id_super, cb_flag) \
- FOREACH_CALLBACK_INVOKE(&data, check_id_super, cb_flag)
+ BKE_LIB_FOREACHID_PROCESS(&data, check_id_super, cb_flag)
for (; id != NULL; id = (flag & IDWALK_RECURSE) ? BLI_LINKSTACK_POP(data.ids_todo) : NULL) {
data.self_id = id;
@@ -625,7 +240,7 @@ static void library_foreach_ID_link(Main *bmain,
* especially if/when it starts modifying Main database). */
MainIDRelationsEntry *entry = BLI_ghash_lookup(bmain->relations->id_user_to_used, id);
for (; entry != NULL; entry = entry->next) {
- FOREACH_CALLBACK_INVOKE_ID_PP(&data, entry->id_pointer, entry->usage_flag);
+ BKE_lib_query_foreachid_process(&data, entry->id_pointer, entry->usage_flag);
}
continue;
}
@@ -640,669 +255,26 @@ static void library_foreach_ID_link(Main *bmain,
IDWALK_CB_USER | IDWALK_CB_OVERRIDE_LIBRARY_REFERENCE);
}
- library_foreach_idproperty_ID_link(&data, id->properties, IDWALK_CB_USER);
+ IDP_foreach_property(id->properties,
+ IDP_TYPE_FILTER_ID,
+ BKE_lib_query_idpropertiesForeachIDLink_callback,
+ &data);
AnimData *adt = BKE_animdata_from_id(id);
if (adt) {
- library_foreach_animationData(&data, adt);
+ BKE_animdata_foreach_id(adt, &data);
}
- switch ((ID_Type)GS(id->name)) {
- case ID_LI: {
- Library *lib = (Library *)id;
- CALLBACK_INVOKE(lib->parent, IDWALK_CB_NEVER_SELF);
- break;
- }
- case ID_SCE: {
- Scene *scene = (Scene *)id;
- ToolSettings *toolsett = scene->toolsettings;
-
- CALLBACK_INVOKE(scene->camera, IDWALK_CB_NOP);
- CALLBACK_INVOKE(scene->world, IDWALK_CB_USER);
- CALLBACK_INVOKE(scene->set, IDWALK_CB_NEVER_SELF);
- CALLBACK_INVOKE(scene->clip, IDWALK_CB_USER);
- CALLBACK_INVOKE(scene->gpd, IDWALK_CB_USER);
- CALLBACK_INVOKE(scene->r.bake.cage_object, IDWALK_CB_NOP);
- if (scene->nodetree) {
- /* nodetree **are owned by IDs**, treat them as mere sub-data and not real ID! */
- library_foreach_ID_as_subdata_link(
- (ID **)&scene->nodetree, callback, user_data, flag, &data);
- }
- if (scene->ed) {
- Sequence *seq;
- SEQP_BEGIN (scene->ed, seq) {
- CALLBACK_INVOKE(seq->scene, IDWALK_CB_NEVER_SELF);
- CALLBACK_INVOKE(seq->scene_camera, IDWALK_CB_NOP);
- CALLBACK_INVOKE(seq->clip, IDWALK_CB_USER);
- CALLBACK_INVOKE(seq->mask, IDWALK_CB_USER);
- CALLBACK_INVOKE(seq->sound, IDWALK_CB_USER);
- library_foreach_idproperty_ID_link(&data, seq->prop, IDWALK_CB_USER);
- for (SequenceModifierData *smd = seq->modifiers.first; smd; smd = smd->next) {
- CALLBACK_INVOKE(smd->mask_id, IDWALK_CB_USER);
- }
-
- if (seq->type == SEQ_TYPE_TEXT && seq->effectdata) {
- TextVars *text_data = seq->effectdata;
- CALLBACK_INVOKE(text_data->text_font, IDWALK_CB_USER);
- }
- }
- SEQ_END;
- }
-
- /* This pointer can be NULL during old files reading, better be safe than sorry. */
- if (scene->master_collection != NULL) {
- library_foreach_collection(&data, scene->master_collection);
- }
-
- ViewLayer *view_layer;
- for (view_layer = scene->view_layers.first; view_layer; view_layer = view_layer->next) {
- CALLBACK_INVOKE(view_layer->mat_override, IDWALK_CB_USER);
-
- for (Base *base = view_layer->object_bases.first; base; base = base->next) {
- CALLBACK_INVOKE(base->object, IDWALK_CB_NOP);
- }
-
- library_foreach_layer_collection(&data, &view_layer->layer_collections);
-
- for (FreestyleModuleConfig *fmc = view_layer->freestyle_config.modules.first; fmc;
- fmc = fmc->next) {
- if (fmc->script) {
- CALLBACK_INVOKE(fmc->script, IDWALK_CB_NOP);
- }
- }
-
- for (FreestyleLineSet *fls = view_layer->freestyle_config.linesets.first; fls;
- fls = fls->next) {
- if (fls->group) {
- CALLBACK_INVOKE(fls->group, IDWALK_CB_USER);
- }
-
- if (fls->linestyle) {
- CALLBACK_INVOKE(fls->linestyle, IDWALK_CB_USER);
- }
- }
- }
-
- for (TimeMarker *marker = scene->markers.first; marker; marker = marker->next) {
- CALLBACK_INVOKE(marker->camera, IDWALK_CB_NOP);
- }
-
- if (toolsett) {
- CALLBACK_INVOKE(toolsett->particle.scene, IDWALK_CB_NOP);
- CALLBACK_INVOKE(toolsett->particle.object, IDWALK_CB_NOP);
- CALLBACK_INVOKE(toolsett->particle.shape_object, IDWALK_CB_NOP);
-
- library_foreach_paint(&data, &toolsett->imapaint.paint);
- CALLBACK_INVOKE(toolsett->imapaint.stencil, IDWALK_CB_USER);
- CALLBACK_INVOKE(toolsett->imapaint.clone, IDWALK_CB_USER);
- CALLBACK_INVOKE(toolsett->imapaint.canvas, IDWALK_CB_USER);
-
- if (toolsett->vpaint) {
- library_foreach_paint(&data, &toolsett->vpaint->paint);
- }
- if (toolsett->wpaint) {
- library_foreach_paint(&data, &toolsett->wpaint->paint);
- }
- if (toolsett->sculpt) {
- library_foreach_paint(&data, &toolsett->sculpt->paint);
- CALLBACK_INVOKE(toolsett->sculpt->gravity_object, IDWALK_CB_NOP);
- }
- if (toolsett->uvsculpt) {
- library_foreach_paint(&data, &toolsett->uvsculpt->paint);
- }
- if (toolsett->gp_paint) {
- library_foreach_paint(&data, &toolsett->gp_paint->paint);
- }
- if (toolsett->gp_vertexpaint) {
- library_foreach_paint(&data, &toolsett->gp_vertexpaint->paint);
- }
- if (toolsett->gp_sculptpaint) {
- library_foreach_paint(&data, &toolsett->gp_sculptpaint->paint);
- }
- if (toolsett->gp_weightpaint) {
- library_foreach_paint(&data, &toolsett->gp_weightpaint->paint);
- }
-
- CALLBACK_INVOKE(toolsett->gp_sculpt.guide.reference_object, IDWALK_CB_NOP);
- }
-
- if (scene->rigidbody_world) {
- BKE_rigidbody_world_id_loop(
- scene->rigidbody_world, library_foreach_rigidbodyworldSceneLooper, &data);
- }
+ const IDTypeInfo *id_type = BKE_idtype_get_info_from_id(id);
+ if (id_type->foreach_id != NULL) {
+ id_type->foreach_id(id, &data);
+ if (data.status & IDWALK_STOP) {
break;
}
-
- case ID_OB: {
- Object *object = (Object *)id;
- ParticleSystem *psys;
-
- /* Object is special, proxies make things hard... */
- const int data_cb_flag = data.cb_flag;
- const int proxy_cb_flag = ((data.flag & IDWALK_NO_INDIRECT_PROXY_DATA_USAGE) == 0 &&
- (object->proxy || object->proxy_group)) ?
- IDWALK_CB_INDIRECT_USAGE :
- 0;
-
- /* object data special case */
- data.cb_flag |= proxy_cb_flag;
- if (object->type == OB_EMPTY) {
- /* empty can have NULL or Image */
- CALLBACK_INVOKE_ID(object->data, IDWALK_CB_USER);
- }
- else {
- /* when set, this can't be NULL */
- if (object->data) {
- CALLBACK_INVOKE_ID(object->data, IDWALK_CB_USER | IDWALK_CB_NEVER_NULL);
- }
- }
- data.cb_flag = data_cb_flag;
-
- CALLBACK_INVOKE(object->parent, IDWALK_CB_NEVER_SELF);
- CALLBACK_INVOKE(object->track, IDWALK_CB_NEVER_SELF);
- /* object->proxy is refcounted, but not object->proxy_group... *sigh* */
- CALLBACK_INVOKE(object->proxy, IDWALK_CB_USER | IDWALK_CB_NEVER_SELF);
- CALLBACK_INVOKE(object->proxy_group, IDWALK_CB_NOP);
-
- /* Special case!
- * Since this field is set/owned by 'user' of this ID (and not ID itself),
- * it is only indirect usage if proxy object is linked... Twisted. */
- if (object->proxy_from) {
- data.cb_flag = ID_IS_LINKED(object->proxy_from) ? IDWALK_CB_INDIRECT_USAGE : 0;
- }
- CALLBACK_INVOKE(object->proxy_from, IDWALK_CB_LOOPBACK | IDWALK_CB_NEVER_SELF);
- data.cb_flag = data_cb_flag;
-
- CALLBACK_INVOKE(object->poselib, IDWALK_CB_USER);
-
- data.cb_flag |= proxy_cb_flag;
- for (i = 0; i < object->totcol; i++) {
- CALLBACK_INVOKE(object->mat[i], IDWALK_CB_USER);
- }
- data.cb_flag = data_cb_flag;
-
- /* Note that ob->gpd is deprecated, so no need to handle it here. */
- CALLBACK_INVOKE(object->instance_collection, IDWALK_CB_USER);
-
- if (object->pd) {
- CALLBACK_INVOKE(object->pd->tex, IDWALK_CB_USER);
- CALLBACK_INVOKE(object->pd->f_source, IDWALK_CB_NOP);
- }
- /* Note that ob->effect is deprecated, so no need to handle it here. */
-
- if (object->pose) {
- bPoseChannel *pchan;
-
- data.cb_flag |= proxy_cb_flag;
- for (pchan = object->pose->chanbase.first; pchan; pchan = pchan->next) {
- library_foreach_idproperty_ID_link(&data, pchan->prop, IDWALK_CB_USER);
- CALLBACK_INVOKE(pchan->custom, IDWALK_CB_USER);
- BKE_constraints_id_loop(
- &pchan->constraints, library_foreach_constraintObjectLooper, &data);
- }
- data.cb_flag = data_cb_flag;
- }
-
- if (object->rigidbody_constraint) {
- CALLBACK_INVOKE(object->rigidbody_constraint->ob1, IDWALK_CB_NEVER_SELF);
- CALLBACK_INVOKE(object->rigidbody_constraint->ob2, IDWALK_CB_NEVER_SELF);
- }
-
- if (object->lodlevels.first) {
- LodLevel *level;
- for (level = object->lodlevels.first; level; level = level->next) {
- CALLBACK_INVOKE(level->source, IDWALK_CB_NEVER_SELF);
- }
- }
-
- modifiers_foreachIDLink(object, library_foreach_modifiersForeachIDLink, &data);
- BKE_gpencil_modifiers_foreachIDLink(
- object, library_foreach_gpencil_modifiersForeachIDLink, &data);
- BKE_constraints_id_loop(
- &object->constraints, library_foreach_constraintObjectLooper, &data);
- BKE_shaderfx_foreachIDLink(object, library_foreach_shaderfxForeachIDLink, &data);
-
- for (psys = object->particlesystem.first; psys; psys = psys->next) {
- BKE_particlesystem_id_loop(psys, library_foreach_particlesystemsObjectLooper, &data);
- }
-
- if (object->soft) {
- CALLBACK_INVOKE(object->soft->collision_group, IDWALK_CB_NOP);
-
- if (object->soft->effector_weights) {
- CALLBACK_INVOKE(object->soft->effector_weights->group, IDWALK_CB_NOP);
- }
- }
- break;
- }
-
- case ID_AR: {
- bArmature *arm = (bArmature *)id;
-
- for (Bone *bone = arm->bonebase.first; bone; bone = bone->next) {
- library_foreach_bone(&data, bone);
- }
- break;
- }
-
- case ID_ME: {
- Mesh *mesh = (Mesh *)id;
- CALLBACK_INVOKE(mesh->texcomesh, IDWALK_CB_NEVER_SELF);
- CALLBACK_INVOKE(mesh->key, IDWALK_CB_USER);
- for (i = 0; i < mesh->totcol; i++) {
- CALLBACK_INVOKE(mesh->mat[i], IDWALK_CB_USER);
- }
- break;
- }
-
- case ID_CU: {
- Curve *curve = (Curve *)id;
- CALLBACK_INVOKE(curve->bevobj, IDWALK_CB_NOP);
- CALLBACK_INVOKE(curve->taperobj, IDWALK_CB_NOP);
- CALLBACK_INVOKE(curve->textoncurve, IDWALK_CB_NOP);
- CALLBACK_INVOKE(curve->key, IDWALK_CB_USER);
- for (i = 0; i < curve->totcol; i++) {
- CALLBACK_INVOKE(curve->mat[i], IDWALK_CB_USER);
- }
- CALLBACK_INVOKE(curve->vfont, IDWALK_CB_USER);
- CALLBACK_INVOKE(curve->vfontb, IDWALK_CB_USER);
- CALLBACK_INVOKE(curve->vfonti, IDWALK_CB_USER);
- CALLBACK_INVOKE(curve->vfontbi, IDWALK_CB_USER);
- break;
- }
-
- case ID_MB: {
- MetaBall *metaball = (MetaBall *)id;
- for (i = 0; i < metaball->totcol; i++) {
- CALLBACK_INVOKE(metaball->mat[i], IDWALK_CB_USER);
- }
- break;
- }
-
- case ID_MA: {
- Material *material = (Material *)id;
- if (material->nodetree) {
- /* nodetree **are owned by IDs**, treat them as mere sub-data and not real ID! */
- library_foreach_ID_as_subdata_link(
- (ID **)&material->nodetree, callback, user_data, flag, &data);
- }
- if (material->texpaintslot != NULL) {
- CALLBACK_INVOKE(material->texpaintslot->ima, IDWALK_CB_NOP);
- }
- if (material->gp_style != NULL) {
- CALLBACK_INVOKE(material->gp_style->sima, IDWALK_CB_USER);
- CALLBACK_INVOKE(material->gp_style->ima, IDWALK_CB_USER);
- }
- break;
- }
-
- case ID_TE: {
- Tex *texture = (Tex *)id;
- if (texture->nodetree) {
- /* nodetree **are owned by IDs**, treat them as mere sub-data and not real ID! */
- library_foreach_ID_as_subdata_link(
- (ID **)&texture->nodetree, callback, user_data, flag, &data);
- }
- CALLBACK_INVOKE(texture->ima, IDWALK_CB_USER);
- break;
- }
-
- case ID_LT: {
- Lattice *lattice = (Lattice *)id;
- CALLBACK_INVOKE(lattice->key, IDWALK_CB_USER);
- break;
- }
-
- case ID_LA: {
- Light *lamp = (Light *)id;
- if (lamp->nodetree) {
- /* nodetree **are owned by IDs**, treat them as mere sub-data and not real ID! */
- library_foreach_ID_as_subdata_link(
- (ID **)&lamp->nodetree, callback, user_data, flag, &data);
- }
- break;
- }
-
- case ID_CA: {
- Camera *camera = (Camera *)id;
- CALLBACK_INVOKE(camera->dof.focus_object, IDWALK_CB_NOP);
- for (CameraBGImage *bgpic = camera->bg_images.first; bgpic; bgpic = bgpic->next) {
- if (bgpic->source == CAM_BGIMG_SOURCE_IMAGE) {
- CALLBACK_INVOKE(bgpic->ima, IDWALK_CB_USER);
- }
- else if (bgpic->source == CAM_BGIMG_SOURCE_MOVIE) {
- CALLBACK_INVOKE(bgpic->clip, IDWALK_CB_USER);
- }
- }
-
- break;
- }
-
- case ID_KE: {
- Key *key = (Key *)id;
- CALLBACK_INVOKE_ID(key->from, IDWALK_CB_LOOPBACK);
- break;
- }
-
- case ID_WO: {
- World *world = (World *)id;
- if (world->nodetree) {
- /* nodetree **are owned by IDs**, treat them as mere sub-data and not real ID! */
- library_foreach_ID_as_subdata_link(
- (ID **)&world->nodetree, callback, user_data, flag, &data);
- }
- break;
- }
-
- case ID_SPK: {
- Speaker *speaker = (Speaker *)id;
- CALLBACK_INVOKE(speaker->sound, IDWALK_CB_USER);
- break;
- }
-
- case ID_LP: {
- LightProbe *probe = (LightProbe *)id;
- CALLBACK_INVOKE(probe->image, IDWALK_CB_USER);
- CALLBACK_INVOKE(probe->visibility_grp, IDWALK_CB_NOP);
- break;
- }
-
- case ID_GR: {
- Collection *collection = (Collection *)id;
- library_foreach_collection(&data, collection);
- break;
- }
-
- case ID_NT: {
- bNodeTree *ntree = (bNodeTree *)id;
- bNode *node;
- bNodeSocket *sock;
-
- CALLBACK_INVOKE(ntree->gpd, IDWALK_CB_USER);
-
- for (node = ntree->nodes.first; node; node = node->next) {
- CALLBACK_INVOKE_ID(node->id, IDWALK_CB_USER);
-
- library_foreach_idproperty_ID_link(&data, node->prop, IDWALK_CB_USER);
- for (sock = node->inputs.first; sock; sock = sock->next) {
- library_foreach_idproperty_ID_link(&data, sock->prop, IDWALK_CB_USER);
- }
- for (sock = node->outputs.first; sock; sock = sock->next) {
- library_foreach_idproperty_ID_link(&data, sock->prop, IDWALK_CB_USER);
- }
- }
-
- for (sock = ntree->inputs.first; sock; sock = sock->next) {
- library_foreach_idproperty_ID_link(&data, sock->prop, IDWALK_CB_USER);
- }
- for (sock = ntree->outputs.first; sock; sock = sock->next) {
- library_foreach_idproperty_ID_link(&data, sock->prop, IDWALK_CB_USER);
- }
- break;
- }
-
- case ID_BR: {
- Brush *brush = (Brush *)id;
- CALLBACK_INVOKE(brush->toggle_brush, IDWALK_CB_NOP);
- CALLBACK_INVOKE(brush->clone.image, IDWALK_CB_NOP);
- CALLBACK_INVOKE(brush->paint_curve, IDWALK_CB_USER);
- if (brush->gpencil_settings) {
- CALLBACK_INVOKE(brush->gpencil_settings->material, IDWALK_CB_USER);
- }
- library_foreach_mtex(&data, &brush->mtex);
- library_foreach_mtex(&data, &brush->mask_mtex);
- break;
- }
-
- case ID_PA: {
- ParticleSettings *psett = (ParticleSettings *)id;
- CALLBACK_INVOKE(psett->instance_collection, IDWALK_CB_USER);
- CALLBACK_INVOKE(psett->instance_object, IDWALK_CB_NOP);
- CALLBACK_INVOKE(psett->bb_ob, IDWALK_CB_NOP);
- CALLBACK_INVOKE(psett->collision_group, IDWALK_CB_NOP);
-
- for (i = 0; i < MAX_MTEX; i++) {
- if (psett->mtex[i]) {
- library_foreach_mtex(&data, psett->mtex[i]);
- }
- }
-
- if (psett->effector_weights) {
- CALLBACK_INVOKE(psett->effector_weights->group, IDWALK_CB_NOP);
- }
-
- if (psett->pd) {
- CALLBACK_INVOKE(psett->pd->tex, IDWALK_CB_USER);
- CALLBACK_INVOKE(psett->pd->f_source, IDWALK_CB_NOP);
- }
- if (psett->pd2) {
- CALLBACK_INVOKE(psett->pd2->tex, IDWALK_CB_USER);
- CALLBACK_INVOKE(psett->pd2->f_source, IDWALK_CB_NOP);
- }
-
- if (psett->boids) {
- BoidState *state;
- BoidRule *rule;
-
- for (state = psett->boids->states.first; state; state = state->next) {
- for (rule = state->rules.first; rule; rule = rule->next) {
- if (rule->type == eBoidRuleType_Avoid) {
- BoidRuleGoalAvoid *gabr = (BoidRuleGoalAvoid *)rule;
- CALLBACK_INVOKE(gabr->ob, IDWALK_CB_NOP);
- }
- else if (rule->type == eBoidRuleType_FollowLeader) {
- BoidRuleFollowLeader *flbr = (BoidRuleFollowLeader *)rule;
- CALLBACK_INVOKE(flbr->ob, IDWALK_CB_NOP);
- }
- }
- }
- }
-
- for (ParticleDupliWeight *dw = psett->instance_weights.first; dw; dw = dw->next) {
- CALLBACK_INVOKE(dw->ob, IDWALK_CB_NOP);
- }
- break;
- }
-
- case ID_MC: {
- MovieClip *clip = (MovieClip *)id;
- MovieTracking *tracking = &clip->tracking;
- MovieTrackingObject *object;
- MovieTrackingTrack *track;
- MovieTrackingPlaneTrack *plane_track;
-
- CALLBACK_INVOKE(clip->gpd, IDWALK_CB_USER);
-
- for (track = tracking->tracks.first; track; track = track->next) {
- CALLBACK_INVOKE(track->gpd, IDWALK_CB_USER);
- }
- for (object = tracking->objects.first; object; object = object->next) {
- for (track = object->tracks.first; track; track = track->next) {
- CALLBACK_INVOKE(track->gpd, IDWALK_CB_USER);
- }
- }
-
- for (plane_track = tracking->plane_tracks.first; plane_track;
- plane_track = plane_track->next) {
- CALLBACK_INVOKE(plane_track->image, IDWALK_CB_USER);
- }
- break;
- }
-
- case ID_MSK: {
- Mask *mask = (Mask *)id;
- MaskLayer *mask_layer;
- for (mask_layer = mask->masklayers.first; mask_layer; mask_layer = mask_layer->next) {
- MaskSpline *mask_spline;
-
- for (mask_spline = mask_layer->splines.first; mask_spline;
- mask_spline = mask_spline->next) {
- for (i = 0; i < mask_spline->tot_point; i++) {
- MaskSplinePoint *point = &mask_spline->points[i];
- CALLBACK_INVOKE_ID(point->parent.id, IDWALK_CB_USER);
- }
- }
- }
- break;
- }
-
- case ID_LS: {
- FreestyleLineStyle *linestyle = (FreestyleLineStyle *)id;
- LineStyleModifier *lsm;
- for (i = 0; i < MAX_MTEX; i++) {
- if (linestyle->mtex[i]) {
- library_foreach_mtex(&data, linestyle->mtex[i]);
- }
- }
- if (linestyle->nodetree) {
- /* nodetree **are owned by IDs**, treat them as mere sub-data and not real ID! */
- library_foreach_ID_as_subdata_link(
- (ID **)&linestyle->nodetree, callback, user_data, flag, &data);
- }
-
- for (lsm = linestyle->color_modifiers.first; lsm; lsm = lsm->next) {
- if (lsm->type == LS_MODIFIER_DISTANCE_FROM_OBJECT) {
- LineStyleColorModifier_DistanceFromObject *p =
- (LineStyleColorModifier_DistanceFromObject *)lsm;
- if (p->target) {
- CALLBACK_INVOKE(p->target, IDWALK_CB_NOP);
- }
- }
- }
- for (lsm = linestyle->alpha_modifiers.first; lsm; lsm = lsm->next) {
- if (lsm->type == LS_MODIFIER_DISTANCE_FROM_OBJECT) {
- LineStyleAlphaModifier_DistanceFromObject *p =
- (LineStyleAlphaModifier_DistanceFromObject *)lsm;
- if (p->target) {
- CALLBACK_INVOKE(p->target, IDWALK_CB_NOP);
- }
- }
- }
- for (lsm = linestyle->thickness_modifiers.first; lsm; lsm = lsm->next) {
- if (lsm->type == LS_MODIFIER_DISTANCE_FROM_OBJECT) {
- LineStyleThicknessModifier_DistanceFromObject *p =
- (LineStyleThicknessModifier_DistanceFromObject *)lsm;
- if (p->target) {
- CALLBACK_INVOKE(p->target, IDWALK_CB_NOP);
- }
- }
- }
- break;
- }
-
- case ID_AC: {
- bAction *act = (bAction *)id;
-
- for (TimeMarker *marker = act->markers.first; marker; marker = marker->next) {
- CALLBACK_INVOKE(marker->camera, IDWALK_CB_NOP);
- }
- break;
- }
-
- case ID_WM: {
- wmWindowManager *wm = (wmWindowManager *)id;
-
- for (wmWindow *win = wm->windows.first; win; win = win->next) {
- CALLBACK_INVOKE(win->scene, IDWALK_CB_USER_ONE);
-
- /* This pointer can be NULL during old files reading, better be safe than sorry. */
- if (win->workspace_hook != NULL) {
- ID *workspace = (ID *)BKE_workspace_active_get(win->workspace_hook);
- CALLBACK_INVOKE_ID(workspace, IDWALK_CB_NOP);
- /* allow callback to set a different workspace */
- BKE_workspace_active_set(win->workspace_hook, (WorkSpace *)workspace);
- }
- if (data.flag & IDWALK_INCLUDE_UI) {
- for (ScrArea *area = win->global_areas.areabase.first; area; area = area->next) {
- library_foreach_screen_area(&data, area);
- }
- }
- }
- break;
- }
-
- case ID_WS: {
- WorkSpace *workspace = (WorkSpace *)id;
- ListBase *layouts = BKE_workspace_layouts_get(workspace);
-
- for (WorkSpaceLayout *layout = layouts->first; layout; layout = layout->next) {
- bScreen *screen = BKE_workspace_layout_screen_get(layout);
-
- /* CALLBACK_INVOKE expects an actual pointer, not a variable holding the pointer.
- * However we can't access layout->screen here
- * since we are outside the workspace project. */
- CALLBACK_INVOKE(screen, IDWALK_CB_USER);
- /* allow callback to set a different screen */
- BKE_workspace_layout_screen_set(layout, screen);
- }
- break;
- }
-
- case ID_GD: {
- bGPdata *gpencil = (bGPdata *)id;
- /* materials */
- for (i = 0; i < gpencil->totcol; i++) {
- CALLBACK_INVOKE(gpencil->mat[i], IDWALK_CB_USER);
- }
-
- for (bGPDlayer *gplayer = gpencil->layers.first; gplayer != NULL;
- gplayer = gplayer->next) {
- CALLBACK_INVOKE(gplayer->parent, IDWALK_CB_NOP);
- }
-
- break;
- }
- case ID_HA: {
- Hair *hair = (Hair *)id;
- for (i = 0; i < hair->totcol; i++) {
- CALLBACK_INVOKE(hair->mat[i], IDWALK_CB_USER);
- }
- break;
- }
- case ID_PT: {
- PointCloud *pointcloud = (PointCloud *)id;
- for (i = 0; i < pointcloud->totcol; i++) {
- CALLBACK_INVOKE(pointcloud->mat[i], IDWALK_CB_USER);
- }
- break;
- }
- case ID_VO: {
- Volume *volume = (Volume *)id;
- for (i = 0; i < volume->totcol; i++) {
- CALLBACK_INVOKE(volume->mat[i], IDWALK_CB_USER);
- }
- break;
- }
-
- case ID_SCR: {
- if (data.flag & IDWALK_INCLUDE_UI) {
- bScreen *screen = (bScreen *)id;
-
- for (ScrArea *area = screen->areabase.first; area; area = area->next) {
- library_foreach_screen_area(&data, area);
- }
- }
- break;
- }
-
- /* Nothing needed for those... */
- case ID_IM:
- case ID_VF:
- case ID_TXT:
- case ID_SO:
- case ID_PAL:
- case ID_PC:
- case ID_CF:
- break;
-
- /* Deprecated. */
- case ID_IP:
- break;
}
}
-FOREACH_FINALIZE:
if (data.ids_handled) {
BLI_gset_free(data.ids_handled, NULL);
BLI_LINKSTACK_FREE(data.ids_todo);
@@ -1312,9 +284,6 @@ FOREACH_FINALIZE:
#undef CALLBACK_INVOKE
}
-#undef FOREACH_CALLBACK_INVOKE_ID
-#undef FOREACH_CALLBACK_INVOKE
-
/**
* Loop over all of the ID's this data-block links to.
*/
@@ -1339,14 +308,11 @@ void BKE_library_update_ID_link_user(ID *id_dst, ID *id_src, const int cb_flag)
}
/**
- * Say whether given \a id_type_owner can use (in any way) a data-block of \a id_type_used.
+ * Say whether given \a id_owner may use (in any way) a data-block of \a id_type_used.
*
* This is a 'simplified' abstract version of #BKE_library_foreach_ID_link() above,
- * quite useful to reduce* useless iterations in some cases.
+ * quite useful to reduce useless iterations in some cases.
*/
-/* XXX This has to be fully rethink, basing check on ID type is not really working anymore
- * (and even worth once IDProps will support ID pointers),
- * we'll have to do some quick checks on IDs themselves... */
bool BKE_library_id_can_use_idtype(ID *id_owner, const short id_type_used)
{
/* any type of ID can be used in custom props. */
@@ -1456,6 +422,7 @@ bool BKE_library_id_can_use_idtype(ID *id_owner, const short id_type_used)
case ID_PAL:
case ID_PC:
case ID_CF:
+ case ID_SIM:
/* Those types never use/reference other IDs... */
return false;
case ID_IP:
@@ -1709,7 +676,7 @@ void BKE_library_indirectly_used_data_tag_clear(Main *bmain)
do_loop = false;
while (i--) {
- for (ID *id = lb_array[i]->first; id; id = id->next) {
+ LISTBASE_FOREACH (ID *, id, lb_array[i]) {
if (id->lib == NULL || id->tag & LIB_TAG_DOIT) {
/* Local or non-indirectly-used ID (so far), no need to check it further. */
continue;
diff --git a/source/blender/blenkernel/intern/lib_remap.c b/source/blender/blenkernel/intern/lib_remap.c
index 72ae4629dba..ba986b1661b 100644
--- a/source/blender/blenkernel/intern/lib_remap.c
+++ b/source/blender/blenkernel/intern/lib_remap.c
@@ -334,7 +334,7 @@ static void libblock_remap_data_postprocess_obdata_relink(Main *bmain, Object *o
default:
break;
}
- test_object_modifiers(ob);
+ BKE_modifiers_test_object(ob);
BKE_object_materials_test(bmain, ob, new_id);
}
}
diff --git a/source/blender/blenkernel/intern/library.c b/source/blender/blenkernel/intern/library.c
index e3ed21aa536..64ffea22363 100644
--- a/source/blender/blenkernel/intern/library.c
+++ b/source/blender/blenkernel/intern/library.c
@@ -38,6 +38,7 @@
#include "BKE_idtype.h"
#include "BKE_lib_id.h"
+#include "BKE_lib_query.h"
#include "BKE_library.h"
#include "BKE_main.h"
#include "BKE_packedFile.h"
@@ -53,6 +54,12 @@ static void library_free_data(ID *id)
}
}
+static void library_foreach_id(ID *id, LibraryForeachIDData *data)
+{
+ Library *lib = (Library *)id;
+ BKE_LIB_FOREACHID_PROCESS(data, lib->parent, IDWALK_CB_NEVER_SELF);
+}
+
IDTypeInfo IDType_ID_LI = {
.id_code = ID_LI,
.id_filter = 0,
@@ -67,6 +74,7 @@ IDTypeInfo IDType_ID_LI = {
.copy_data = NULL,
.free_data = library_free_data,
.make_local = NULL,
+ .foreach_id = library_foreach_id,
};
void BKE_library_filepath_set(Main *bmain, Library *lib, const char *filepath)
diff --git a/source/blender/blenkernel/intern/light.c b/source/blender/blenkernel/intern/light.c
index aec0f808f64..aa1005c663f 100644
--- a/source/blender/blenkernel/intern/light.c
+++ b/source/blender/blenkernel/intern/light.c
@@ -37,17 +37,19 @@
#include "BLI_math.h"
#include "BLI_utildefines.h"
-#include "BKE_animsys.h"
#include "BKE_colortools.h"
#include "BKE_icons.h"
#include "BKE_idtype.h"
#include "BKE_lib_id.h"
+#include "BKE_lib_query.h"
#include "BKE_light.h"
#include "BKE_main.h"
#include "BKE_node.h"
#include "BLT_translation.h"
+#include "DEG_depsgraph.h"
+
static void light_init_data(ID *id)
{
Light *la = (Light *)id;
@@ -59,17 +61,6 @@ static void light_init_data(ID *id)
BKE_curvemapping_initialize(la->curfalloff);
}
-Light *BKE_light_add(Main *bmain, const char *name)
-{
- Light *la;
-
- la = BKE_libblock_alloc(bmain, ID_LA, name, 0);
-
- light_init_data(&la->id);
-
- return la;
-}
-
/**
* Only copy internal data of Light ID from source
* to already allocated/initialized destination.
@@ -101,6 +92,61 @@ static void light_copy_data(Main *bmain, ID *id_dst, const ID *id_src, const int
}
}
+static void light_free_data(ID *id)
+{
+ Light *la = (Light *)id;
+
+ BKE_curvemapping_free(la->curfalloff);
+
+ /* is no lib link block, but light extension */
+ if (la->nodetree) {
+ ntreeFreeEmbeddedTree(la->nodetree);
+ MEM_freeN(la->nodetree);
+ la->nodetree = NULL;
+ }
+
+ BKE_previewimg_free(&la->preview);
+ BKE_icon_id_delete(&la->id);
+ la->id.icon_id = 0;
+}
+
+static void light_foreach_id(ID *id, LibraryForeachIDData *data)
+{
+ Light *lamp = (Light *)id;
+ if (lamp->nodetree) {
+ /* nodetree **are owned by IDs**, treat them as mere sub-data and not real ID! */
+ BKE_library_foreach_ID_embedded(data, (ID **)&lamp->nodetree);
+ }
+}
+
+IDTypeInfo IDType_ID_LA = {
+ .id_code = ID_LA,
+ .id_filter = FILTER_ID_LA,
+ .main_listbase_index = INDEX_ID_LA,
+ .struct_size = sizeof(Light),
+ .name = "Light",
+ .name_plural = "lights",
+ .translation_context = BLT_I18NCONTEXT_ID_LIGHT,
+ .flags = 0,
+
+ .init_data = light_init_data,
+ .copy_data = light_copy_data,
+ .free_data = light_free_data,
+ .make_local = NULL,
+ .foreach_id = light_foreach_id,
+};
+
+Light *BKE_light_add(Main *bmain, const char *name)
+{
+ Light *la;
+
+ la = BKE_libblock_alloc(bmain, ID_LA, name, 0);
+
+ light_init_data(&la->id);
+
+ return la;
+}
+
Light *BKE_light_copy(Main *bmain, const Light *la)
{
Light *la_copy;
@@ -135,41 +181,7 @@ Light *BKE_light_localize(Light *la)
return lan;
}
-static void light_make_local(Main *bmain, ID *id, const int flags)
+void BKE_light_eval(struct Depsgraph *depsgraph, Light *la)
{
- BKE_lib_id_make_local_generic(bmain, id, flags);
+ DEG_debug_print_eval(depsgraph, __func__, la->id.name, la);
}
-
-static void light_free_data(ID *id)
-{
- Light *la = (Light *)id;
-
- BKE_curvemapping_free(la->curfalloff);
-
- /* is no lib link block, but light extension */
- if (la->nodetree) {
- ntreeFreeNestedTree(la->nodetree);
- MEM_freeN(la->nodetree);
- la->nodetree = NULL;
- }
-
- BKE_previewimg_free(&la->preview);
- BKE_icon_id_delete(&la->id);
- la->id.icon_id = 0;
-}
-
-IDTypeInfo IDType_ID_LA = {
- .id_code = ID_LA,
- .id_filter = FILTER_ID_LA,
- .main_listbase_index = INDEX_ID_LA,
- .struct_size = sizeof(Light),
- .name = "Light",
- .name_plural = "lights",
- .translation_context = BLT_I18NCONTEXT_ID_LIGHT,
- .flags = 0,
-
- .init_data = light_init_data,
- .copy_data = light_copy_data,
- .free_data = light_free_data,
- .make_local = light_make_local,
-};
diff --git a/source/blender/blenkernel/intern/lightprobe.c b/source/blender/blenkernel/intern/lightprobe.c
index 4675897cb0e..f73df66b43d 100644
--- a/source/blender/blenkernel/intern/lightprobe.c
+++ b/source/blender/blenkernel/intern/lightprobe.c
@@ -23,15 +23,16 @@
#include <string.h>
+#include "DNA_collection_types.h"
#include "DNA_defaults.h"
#include "DNA_lightprobe_types.h"
#include "DNA_object_types.h"
#include "BLI_utildefines.h"
-#include "BKE_animsys.h"
#include "BKE_idtype.h"
#include "BKE_lib_id.h"
+#include "BKE_lib_query.h"
#include "BKE_lightprobe.h"
#include "BKE_main.h"
@@ -45,6 +46,31 @@ static void lightprobe_init_data(ID *id)
MEMCPY_STRUCT_AFTER(probe, DNA_struct_default_get(LightProbe), id);
}
+static void lightprobe_foreach_id(ID *id, LibraryForeachIDData *data)
+{
+ LightProbe *probe = (LightProbe *)id;
+
+ BKE_LIB_FOREACHID_PROCESS(data, probe->image, IDWALK_CB_USER);
+ BKE_LIB_FOREACHID_PROCESS(data, probe->visibility_grp, IDWALK_CB_NOP);
+}
+
+IDTypeInfo IDType_ID_LP = {
+ .id_code = ID_LP,
+ .id_filter = FILTER_ID_LP,
+ .main_listbase_index = INDEX_ID_LP,
+ .struct_size = sizeof(LightProbe),
+ .name = "LightProbe",
+ .name_plural = "lightprobes",
+ .translation_context = BLT_I18NCONTEXT_ID_LIGHTPROBE,
+ .flags = 0,
+
+ .init_data = lightprobe_init_data,
+ .copy_data = NULL,
+ .free_data = NULL,
+ .make_local = NULL,
+ .foreach_id = lightprobe_foreach_id,
+};
+
void BKE_lightprobe_type_set(LightProbe *probe, const short lightprobe_type)
{
probe->type = lightprobe_type;
@@ -80,48 +106,9 @@ void *BKE_lightprobe_add(Main *bmain, const char *name)
return probe;
}
-/**
- * Only copy internal data of #LightProbe ID from source
- * to already allocated/initialized destination.
- * You probably never want to use that directly,
- * use #BKE_id_copy or #BKE_id_copy_ex for typical needs.
- *
- * WARNING! This function will not handle ID user count!
- *
- * \param flag: Copying options (see BKE_lib_id.h's LIB_ID_COPY_... flags for more).
- */
-static void lightprobe_copy_data(Main *UNUSED(bmain),
- ID *UNUSED(id_dst),
- const ID *UNUSED(id_src),
- const int UNUSED(flag))
-{
- /* Nothing to do here. */
-}
-
LightProbe *BKE_lightprobe_copy(Main *bmain, const LightProbe *probe)
{
LightProbe *probe_copy;
BKE_id_copy(bmain, &probe->id, (ID **)&probe_copy);
return probe_copy;
}
-
-static void lightprobe_make_local(Main *bmain, ID *id, const int flags)
-{
- BKE_lib_id_make_local_generic(bmain, id, flags);
-}
-
-IDTypeInfo IDType_ID_LP = {
- .id_code = ID_LP,
- .id_filter = FILTER_ID_LP,
- .main_listbase_index = INDEX_ID_LP,
- .struct_size = sizeof(LightProbe),
- .name = "LightProbe",
- .name_plural = "lightprobes",
- .translation_context = BLT_I18NCONTEXT_ID_LIGHTPROBE,
- .flags = 0,
-
- .init_data = lightprobe_init_data,
- .copy_data = lightprobe_copy_data,
- .free_data = NULL,
- .make_local = lightprobe_make_local,
-};
diff --git a/source/blender/blenkernel/intern/linestyle.c b/source/blender/blenkernel/intern/linestyle.c
index db39931a9d2..a389af5c47f 100644
--- a/source/blender/blenkernel/intern/linestyle.c
+++ b/source/blender/blenkernel/intern/linestyle.c
@@ -39,16 +39,17 @@
#include "BLT_translation.h"
-#include "BKE_animsys.h"
#include "BKE_colorband.h"
#include "BKE_colortools.h"
#include "BKE_context.h"
#include "BKE_freestyle.h"
#include "BKE_idtype.h"
#include "BKE_lib_id.h"
+#include "BKE_lib_query.h"
#include "BKE_linestyle.h"
#include "BKE_main.h"
#include "BKE_node.h"
+#include "BKE_texture.h"
static void linestyle_init_data(ID *id)
{
@@ -126,7 +127,7 @@ static void linestyle_free_data(ID *id)
/* is no lib link block, but linestyle extension */
if (linestyle->nodetree) {
- ntreeFreeNestedTree(linestyle->nodetree);
+ ntreeFreeEmbeddedTree(linestyle->nodetree);
MEM_freeN(linestyle->nodetree);
linestyle->nodetree = NULL;
}
@@ -145,6 +146,49 @@ static void linestyle_free_data(ID *id)
}
}
+static void linestyle_foreach_id(ID *id, LibraryForeachIDData *data)
+{
+ FreestyleLineStyle *linestyle = (FreestyleLineStyle *)id;
+
+ for (int i = 0; i < MAX_MTEX; i++) {
+ if (linestyle->mtex[i]) {
+ BKE_texture_mtex_foreach_id(data, linestyle->mtex[i]);
+ }
+ }
+ if (linestyle->nodetree) {
+ /* nodetree **are owned by IDs**, treat them as mere sub-data and not real ID! */
+ BKE_library_foreach_ID_embedded(data, (ID **)&linestyle->nodetree);
+ }
+
+ LISTBASE_FOREACH (LineStyleModifier *, lsm, &linestyle->color_modifiers) {
+ if (lsm->type == LS_MODIFIER_DISTANCE_FROM_OBJECT) {
+ LineStyleColorModifier_DistanceFromObject *p = (LineStyleColorModifier_DistanceFromObject *)
+ lsm;
+ if (p->target) {
+ BKE_LIB_FOREACHID_PROCESS(data, p->target, IDWALK_CB_NOP);
+ }
+ }
+ }
+ LISTBASE_FOREACH (LineStyleModifier *, lsm, &linestyle->alpha_modifiers) {
+ if (lsm->type == LS_MODIFIER_DISTANCE_FROM_OBJECT) {
+ LineStyleAlphaModifier_DistanceFromObject *p = (LineStyleAlphaModifier_DistanceFromObject *)
+ lsm;
+ if (p->target) {
+ BKE_LIB_FOREACHID_PROCESS(data, p->target, IDWALK_CB_NOP);
+ }
+ }
+ }
+ LISTBASE_FOREACH (LineStyleModifier *, lsm, &linestyle->thickness_modifiers) {
+ if (lsm->type == LS_MODIFIER_DISTANCE_FROM_OBJECT) {
+ LineStyleThicknessModifier_DistanceFromObject *p =
+ (LineStyleThicknessModifier_DistanceFromObject *)lsm;
+ if (p->target) {
+ BKE_LIB_FOREACHID_PROCESS(data, p->target, IDWALK_CB_NOP);
+ }
+ }
+ }
+}
+
IDTypeInfo IDType_ID_LS = {
.id_code = ID_LS,
.id_filter = FILTER_ID_LS,
@@ -159,6 +203,7 @@ IDTypeInfo IDType_ID_LS = {
.copy_data = linestyle_copy_data,
.free_data = linestyle_free_data,
.make_local = NULL,
+ .foreach_id = linestyle_foreach_id,
};
static const char *modifier_name[LS_MODIFIER_NUM] = {
diff --git a/source/blender/blenkernel/intern/main.c b/source/blender/blenkernel/intern/main.c
index caa29f7817a..ea3bee8b2f6 100644
--- a/source/blender/blenkernel/intern/main.c
+++ b/source/blender/blenkernel/intern/main.c
@@ -479,6 +479,8 @@ ListBase *which_libbase(Main *bmain, short type)
return &(bmain->pointclouds);
case ID_VO:
return &(bmain->volumes);
+ case ID_SIM:
+ return &(bmain->simulations);
}
return NULL;
}
@@ -554,6 +556,7 @@ int set_listbasepointers(Main *bmain, ListBase **lb)
lb[INDEX_ID_WS] = &(bmain->workspaces); /* before wm, so it's freed after it! */
lb[INDEX_ID_WM] = &(bmain->wm);
lb[INDEX_ID_MSK] = &(bmain->masks);
+ lb[INDEX_ID_SIM] = &(bmain->simulations);
lb[INDEX_ID_NULL] = NULL;
diff --git a/source/blender/blenkernel/intern/mask.c b/source/blender/blenkernel/intern/mask.c
index eb274fc1ef3..49c909850de 100644
--- a/source/blender/blenkernel/intern/mask.c
+++ b/source/blender/blenkernel/intern/mask.c
@@ -38,10 +38,6 @@
#include "BLT_translation.h"
#include "DNA_mask_types.h"
-#include "DNA_node_types.h"
-#include "DNA_screen_types.h"
-#include "DNA_sequence_types.h"
-#include "DNA_space_types.h"
#include "BKE_animsys.h"
#include "BKE_curve.h"
@@ -49,11 +45,10 @@
#include "BKE_image.h"
#include "BKE_lib_id.h"
+#include "BKE_lib_query.h"
#include "BKE_main.h"
#include "BKE_mask.h"
#include "BKE_movieclip.h"
-#include "BKE_node.h"
-#include "BKE_sequencer.h"
#include "BKE_tracking.h"
#include "DEG_depsgraph_build.h"
@@ -85,6 +80,20 @@ static void mask_free_data(ID *id)
BKE_mask_layer_free_list(&mask->masklayers);
}
+static void mask_foreach_id(ID *id, LibraryForeachIDData *data)
+{
+ Mask *mask = (Mask *)id;
+
+ LISTBASE_FOREACH (MaskLayer *, mask_layer, &mask->masklayers) {
+ LISTBASE_FOREACH (MaskSpline *, mask_spline, &mask_layer->splines) {
+ for (int i = 0; i < mask_spline->tot_point; i++) {
+ MaskSplinePoint *point = &mask_spline->points[i];
+ BKE_LIB_FOREACHID_PROCESS_ID(data, point->parent.id, IDWALK_CB_USER);
+ }
+ }
+ }
+}
+
IDTypeInfo IDType_ID_MSK = {
.id_code = ID_MSK,
.id_filter = FILTER_ID_MSK,
@@ -99,6 +108,7 @@ IDTypeInfo IDType_ID_MSK = {
.copy_data = mask_copy_data,
.free_data = mask_free_data,
.make_local = NULL,
+ .foreach_id = mask_foreach_id,
};
static struct {
diff --git a/source/blender/blenkernel/intern/material.c b/source/blender/blenkernel/intern/material.c
index 31fe93f64ed..d4de04a9e98 100644
--- a/source/blender/blenkernel/intern/material.c
+++ b/source/blender/blenkernel/intern/material.c
@@ -54,7 +54,6 @@
#include "BLT_translation.h"
-#include "BKE_animsys.h"
#include "BKE_brush.h"
#include "BKE_curve.h"
#include "BKE_displist.h"
@@ -65,6 +64,7 @@
#include "BKE_idtype.h"
#include "BKE_image.h"
#include "BKE_lib_id.h"
+#include "BKE_lib_query.h"
#include "BKE_main.h"
#include "BKE_material.h"
#include "BKE_mesh.h"
@@ -131,7 +131,7 @@ static void material_free_data(ID *id)
/* is no lib link block, but material extension */
if (material->nodetree) {
- ntreeFreeNestedTree(material->nodetree);
+ ntreeFreeEmbeddedTree(material->nodetree);
MEM_freeN(material->nodetree);
material->nodetree = NULL;
}
@@ -144,6 +144,22 @@ static void material_free_data(ID *id)
BKE_previewimg_free(&material->preview);
}
+static void material_foreach_id(ID *id, LibraryForeachIDData *data)
+{
+ Material *material = (Material *)id;
+ /* Nodetrees **are owned by IDs**, treat them as mere sub-data and not real ID! */
+ if (!BKE_library_foreach_ID_embedded(data, (ID **)&material->nodetree)) {
+ return;
+ }
+ if (material->texpaintslot != NULL) {
+ BKE_LIB_FOREACHID_PROCESS(data, material->texpaintslot->ima, IDWALK_CB_NOP);
+ }
+ if (material->gp_style != NULL) {
+ BKE_LIB_FOREACHID_PROCESS(data, material->gp_style->sima, IDWALK_CB_USER);
+ BKE_LIB_FOREACHID_PROCESS(data, material->gp_style->ima, IDWALK_CB_USER);
+ }
+}
+
IDTypeInfo IDType_ID_MA = {
.id_code = ID_MA,
.id_filter = FILTER_ID_MA,
@@ -158,6 +174,7 @@ IDTypeInfo IDType_ID_MA = {
.copy_data = material_copy_data,
.free_data = material_free_data,
.make_local = NULL,
+ .foreach_id = material_foreach_id,
};
void BKE_gpencil_material_attr_init(Material *ma)
@@ -169,10 +186,11 @@ void BKE_gpencil_material_attr_init(Material *ma)
/* set basic settings */
gp_style->stroke_rgba[3] = 1.0f;
gp_style->fill_rgba[3] = 1.0f;
- ARRAY_SET_ITEMS(gp_style->mix_rgba, 1.0f, 1.0f, 1.0f, 0.2f);
+ ARRAY_SET_ITEMS(gp_style->mix_rgba, 1.0f, 1.0f, 1.0f, 1.0f);
ARRAY_SET_ITEMS(gp_style->texture_scale, 1.0f, 1.0f);
- gp_style->texture_opacity = 1.0f;
+ gp_style->texture_offset[0] = -0.5f;
gp_style->texture_pixsize = 100.0f;
+ gp_style->mix_factor = 0.5f;
gp_style->flag |= GP_MATERIAL_STROKE_SHOW;
}
@@ -1123,7 +1141,7 @@ static bool ntree_foreach_texnode_recursive(bNodeTree *nodetree,
ForEachTexNodeCallback callback,
void *userdata)
{
- for (bNode *node = nodetree->nodes.first; node; node = node->next) {
+ LISTBASE_FOREACH (bNode *, node, &nodetree->nodes) {
if (node->typeinfo->nclass == NODE_CLASS_TEXTURE &&
node->typeinfo->type == SH_NODE_TEX_IMAGE && node->id) {
if (!callback(node, userdata)) {
@@ -1601,7 +1619,7 @@ void BKE_material_copybuf_paste(Main *bmain, Material *ma)
GPU_material_free(&ma->gpumaterial);
if (ma->nodetree) {
- ntreeFreeNestedTree(ma->nodetree);
+ ntreeFreeEmbeddedTree(ma->nodetree);
MEM_freeN(ma->nodetree);
}
@@ -1626,11 +1644,13 @@ void BKE_material_eval(struct Depsgraph *depsgraph, Material *material)
* default shader nodes. */
static Material default_material_empty;
+static Material default_material_holdout;
static Material default_material_surface;
static Material default_material_volume;
static Material default_material_gpencil;
static Material *default_materials[] = {&default_material_empty,
+ &default_material_holdout,
&default_material_surface,
&default_material_volume,
&default_material_gpencil,
@@ -1697,6 +1717,11 @@ Material *BKE_material_default_empty(void)
return &default_material_empty;
}
+Material *BKE_material_default_holdout(void)
+{
+ return &default_material_holdout;
+}
+
Material *BKE_material_default_surface(void)
{
return &default_material_surface;
diff --git a/source/blender/blenkernel/intern/mball.c b/source/blender/blenkernel/intern/mball.c
index b708c030152..94e5f435a43 100644
--- a/source/blender/blenkernel/intern/mball.c
+++ b/source/blender/blenkernel/intern/mball.c
@@ -50,11 +50,11 @@
#include "BKE_main.h"
-#include "BKE_animsys.h"
#include "BKE_curve.h"
#include "BKE_displist.h"
#include "BKE_idtype.h"
#include "BKE_lib_id.h"
+#include "BKE_lib_query.h"
#include "BKE_material.h"
#include "BKE_mball.h"
#include "BKE_object.h"
@@ -102,6 +102,14 @@ static void metaball_free_data(ID *id)
}
}
+static void metaball_foreach_id(ID *id, LibraryForeachIDData *data)
+{
+ MetaBall *metaball = (MetaBall *)id;
+ for (int i = 0; i < metaball->totcol; i++) {
+ BKE_LIB_FOREACHID_PROCESS(data, metaball->mat[i], IDWALK_CB_USER);
+ }
+}
+
IDTypeInfo IDType_ID_MB = {
.id_code = ID_MB,
.id_filter = FILTER_ID_MB,
@@ -116,6 +124,7 @@ IDTypeInfo IDType_ID_MB = {
.copy_data = metaball_copy_data,
.free_data = metaball_free_data,
.make_local = NULL,
+ .foreach_id = metaball_foreach_id,
};
/* Functions */
@@ -431,9 +440,8 @@ Object *BKE_mball_basis_find(Scene *scene, Object *basis)
BLI_split_name_num(basisname, &basisnr, basis->id.name + 2, '.');
- for (ViewLayer *view_layer = scene->view_layers.first; view_layer;
- view_layer = view_layer->next) {
- for (Base *base = view_layer->object_bases.first; base; base = base->next) {
+ LISTBASE_FOREACH (ViewLayer *, view_layer, &scene->view_layers) {
+ LISTBASE_FOREACH (Base *, base, &view_layer->object_bases) {
Object *ob = base->object;
if ((ob->type == OB_MBALL) && !(base->flag & BASE_FROM_DUPLI)) {
if (ob != bob) {
@@ -464,7 +472,7 @@ bool BKE_mball_minmax_ex(
INIT_MINMAX(min, max);
- for (const MetaElem *ml = mb->elems.first; ml; ml = ml->next) {
+ LISTBASE_FOREACH (const MetaElem *, ml, &mb->elems) {
if ((ml->flag & flag) == flag) {
const float scale_mb = (ml->rad * 0.5f) * scale;
int i;
@@ -494,7 +502,7 @@ bool BKE_mball_minmax(const MetaBall *mb, float min[3], float max[3])
{
INIT_MINMAX(min, max);
- for (const MetaElem *ml = mb->elems.first; ml; ml = ml->next) {
+ LISTBASE_FOREACH (const MetaElem *, ml, &mb->elems) {
minmax_v3v3_v3(min, max, &ml->x);
}
@@ -507,7 +515,7 @@ bool BKE_mball_center_median(const MetaBall *mb, float r_cent[3])
zero_v3(r_cent);
- for (const MetaElem *ml = mb->elems.first; ml; ml = ml->next) {
+ LISTBASE_FOREACH (const MetaElem *, ml, &mb->elems) {
add_v3_v3(r_cent, &ml->x);
total++;
}
@@ -539,7 +547,7 @@ void BKE_mball_transform(MetaBall *mb, const float mat[4][4], const bool do_prop
mat4_to_quat(quat, mat);
- for (MetaElem *ml = mb->elems.first; ml; ml = ml->next) {
+ LISTBASE_FOREACH (MetaElem *, ml, &mb->elems) {
mul_m4_v3(mat, &ml->x);
mul_qt_qtqt(ml->quat, quat, ml->quat);
@@ -559,7 +567,7 @@ void BKE_mball_transform(MetaBall *mb, const float mat[4][4], const bool do_prop
void BKE_mball_translate(MetaBall *mb, const float offset[3])
{
- for (MetaElem *ml = mb->elems.first; ml; ml = ml->next) {
+ LISTBASE_FOREACH (MetaElem *, ml, &mb->elems) {
add_v3_v3(&ml->x, offset);
}
}
@@ -568,7 +576,7 @@ void BKE_mball_translate(MetaBall *mb, const float offset[3])
int BKE_mball_select_count(const MetaBall *mb)
{
int sel = 0;
- for (const MetaElem *ml = mb->editelems->first; ml; ml = ml->next) {
+ LISTBASE_FOREACH (const MetaElem *, ml, mb->editelems) {
if (ml->flag & SELECT) {
sel++;
}
@@ -590,7 +598,7 @@ int BKE_mball_select_count_multi(Base **bases, int bases_len)
bool BKE_mball_select_all(MetaBall *mb)
{
bool changed = false;
- for (MetaElem *ml = mb->editelems->first; ml; ml = ml->next) {
+ LISTBASE_FOREACH (MetaElem *, ml, mb->editelems) {
if ((ml->flag & SELECT) == 0) {
ml->flag |= SELECT;
changed = true;
@@ -613,7 +621,7 @@ bool BKE_mball_select_all_multi_ex(Base **bases, int bases_len)
bool BKE_mball_deselect_all(MetaBall *mb)
{
bool changed = false;
- for (MetaElem *ml = mb->editelems->first; ml; ml = ml->next) {
+ LISTBASE_FOREACH (MetaElem *, ml, mb->editelems) {
if ((ml->flag & SELECT) != 0) {
ml->flag &= ~SELECT;
changed = true;
@@ -637,7 +645,7 @@ bool BKE_mball_deselect_all_multi_ex(Base **bases, int bases_len)
bool BKE_mball_select_swap(MetaBall *mb)
{
bool changed = false;
- for (MetaElem *ml = mb->editelems->first; ml; ml = ml->next) {
+ LISTBASE_FOREACH (MetaElem *, ml, mb->editelems) {
ml->flag ^= SELECT;
changed = true;
}
diff --git a/source/blender/blenkernel/intern/mball_tessellate.c b/source/blender/blenkernel/intern/mball_tessellate.c
index cd629c888a4..ad178e76ef6 100644
--- a/source/blender/blenkernel/intern/mball_tessellate.c
+++ b/source/blender/blenkernel/intern/mball_tessellate.c
@@ -44,6 +44,7 @@
#include "BKE_displist.h"
#include "BKE_mball_tessellate.h" /* own include */
+#include "BKE_object.h"
#include "BKE_scene.h"
#include "DEG_depsgraph.h"
@@ -1191,6 +1192,8 @@ static void init_meta(Depsgraph *depsgraph, PROCESS *process, Scene *scene, Obje
int obnr, zero_size = 0;
char obname[MAX_ID_NAME];
SceneBaseIter iter;
+ const eEvaluationMode deg_eval_mode = DEG_get_mode(depsgraph);
+ const short parenting_dupli_transflag = (OB_DUPLIFACES | OB_DUPLIVERTS);
copy_m4_m4(obmat, ob->obmat); /* to cope with duplicators from BKE_scene_base_iter_next */
invert_m4_m4(obinv, ob->obmat);
@@ -1204,6 +1207,14 @@ static void init_meta(Depsgraph *depsgraph, PROCESS *process, Scene *scene, Obje
zero_size = 0;
ml = NULL;
+ /* If this metaball is the original that's used for duplication, only have it it visible when
+ * the instancer is visible too. */
+ if ((base->flag_legacy & OB_FROMDUPLI) == 0 && ob->parent != NULL &&
+ (ob->parent->transflag & parenting_dupli_transflag) != 0 &&
+ (BKE_object_visibility(ob->parent, deg_eval_mode) & OB_VISIBLE_SELF) == 0) {
+ continue;
+ }
+
if (bob == ob && (base->flag_legacy & OB_FROMDUPLI) == 0) {
mb = ob->data;
diff --git a/source/blender/blenkernel/intern/mesh.c b/source/blender/blenkernel/intern/mesh.c
index a59337bc4a2..0d20d25f84c 100644
--- a/source/blender/blenkernel/intern/mesh.c
+++ b/source/blender/blenkernel/intern/mesh.c
@@ -25,6 +25,7 @@
#include "DNA_defaults.h"
#include "DNA_key_types.h"
+#include "DNA_material_types.h"
#include "DNA_mesh_types.h"
#include "DNA_meshdata_types.h"
#include "DNA_object_types.h"
@@ -41,12 +42,13 @@
#include "BLT_translation.h"
-#include "BKE_animsys.h"
+#include "BKE_anim_data.h"
#include "BKE_editmesh.h"
#include "BKE_global.h"
#include "BKE_idtype.h"
#include "BKE_key.h"
#include "BKE_lib_id.h"
+#include "BKE_lib_query.h"
#include "BKE_main.h"
#include "BKE_material.h"
#include "BKE_mesh.h"
@@ -142,6 +144,16 @@ static void mesh_free_data(ID *id)
MEM_SAFE_FREE(mesh->mat);
}
+static void mesh_foreach_id(ID *id, LibraryForeachIDData *data)
+{
+ Mesh *mesh = (Mesh *)id;
+ BKE_LIB_FOREACHID_PROCESS(data, mesh->texcomesh, IDWALK_CB_NEVER_SELF);
+ BKE_LIB_FOREACHID_PROCESS(data, mesh->key, IDWALK_CB_USER);
+ for (int i = 0; i < mesh->totcol; i++) {
+ BKE_LIB_FOREACHID_PROCESS(data, mesh->mat[i], IDWALK_CB_USER);
+ }
+}
+
IDTypeInfo IDType_ID_ME = {
.id_code = ID_ME,
.id_filter = FILTER_ID_ME,
@@ -156,6 +168,7 @@ IDTypeInfo IDType_ID_ME = {
.copy_data = mesh_copy_data,
.free_data = mesh_free_data,
.make_local = NULL,
+ .foreach_id = mesh_foreach_id,
};
enum {
@@ -853,26 +866,6 @@ Mesh *BKE_mesh_from_bmesh_for_eval_nomain(BMesh *bm,
return mesh;
}
-/**
- * TODO(campbell): support mesh with only an edit-mesh which is lazy initialized.
- */
-Mesh *BKE_mesh_from_editmesh_with_coords_thin_wrap(BMEditMesh *em,
- const CustomData_MeshMasks *cd_mask_extra,
- float (*vertexCos)[3],
- const Mesh *me_settings)
-{
- Mesh *me = BKE_mesh_from_bmesh_for_eval_nomain(em->bm, cd_mask_extra, me_settings);
- /* Use editmesh directly where possible. */
- me->runtime.is_original = true;
- if (vertexCos) {
- /* We will own this array in the future. */
- BKE_mesh_vert_coords_apply(me, vertexCos);
- MEM_freeN(vertexCos);
- me->runtime.is_original = false;
- }
- return me;
-}
-
BoundBox *BKE_mesh_boundbox_get(Object *ob)
{
/* This is Object-level data access,
@@ -882,7 +875,7 @@ BoundBox *BKE_mesh_boundbox_get(Object *ob)
float min[3], max[3];
INIT_MINMAX(min, max);
- if (!BKE_mesh_minmax(me, min, max)) {
+ if (!BKE_mesh_wrapper_minmax(me, min, max)) {
min[0] = min[1] = min[2] = -1.0f;
max[0] = max[1] = max[2] = 1.0f;
}
@@ -903,7 +896,7 @@ void BKE_mesh_texspace_calc(Mesh *me)
float min[3], max[3];
INIT_MINMAX(min, max);
- if (!BKE_mesh_minmax(me, min, max)) {
+ if (!BKE_mesh_wrapper_minmax(me, min, max)) {
min[0] = min[1] = min[2] = -1.0f;
max[0] = max[1] = max[2] = 1.0f;
}
@@ -1128,7 +1121,7 @@ void BKE_mesh_assign_object(Main *bmain, Object *ob, Mesh *me)
BKE_object_materials_test(bmain, ob, (ID *)me);
- test_object_modifiers(ob);
+ BKE_modifiers_test_object(ob);
}
void BKE_mesh_material_index_remove(Mesh *me, short index)
diff --git a/source/blender/blenkernel/intern/mesh_convert.c b/source/blender/blenkernel/intern/mesh_convert.c
index 74b79490d67..f2c84028570 100644
--- a/source/blender/blenkernel/intern/mesh_convert.c
+++ b/source/blender/blenkernel/intern/mesh_convert.c
@@ -1076,6 +1076,10 @@ static Mesh *mesh_new_from_mball_object(Object *object)
static Mesh *mesh_new_from_mesh(Object *object, Mesh *mesh)
{
+ /* While we could copy this into the new mesh,
+ * add the data to 'mesh' so future calls to this function don't need to re-convert the data. */
+ BKE_mesh_wrapper_ensure_mdata(mesh);
+
Mesh *mesh_result = NULL;
BKE_id_copy_ex(NULL,
&mesh->id,
@@ -1155,9 +1159,21 @@ Mesh *BKE_mesh_new_from_object(Depsgraph *depsgraph, Object *object, bool preser
/* Happens in special cases like request of mesh for non-mother meta ball. */
return NULL;
}
+
/* The result must have 0 users, since it's just a mesh which is free-dangling data-block.
* All the conversion functions are supposed to ensure mesh is not counted. */
BLI_assert(new_mesh->id.us == 0);
+
+ /* It is possible that mesh came from modifier stack evaluation, which preserves edit_mesh
+ * pointer (which allows draw manager to access edit mesh when drawing). Normally this does
+ * not cause ownership problems because evaluated object runtime is keeping track of the real
+ * ownership.
+ *
+ * Here we are constructing a mesh which is supposed to be independent, which means no shared
+ * ownership is allowed, so we make sure edit mesh is reset to NULL (which is similar to as if
+ * one duplicates the objects and applies all the modifiers). */
+ new_mesh->edit_mesh = NULL;
+
return new_mesh;
}
@@ -1301,7 +1317,7 @@ Mesh *BKE_mesh_create_derived_for_modifier(struct Depsgraph *depsgraph,
int build_shapekey_layers)
{
Mesh *me = ob_eval->runtime.data_orig ? ob_eval->runtime.data_orig : ob_eval->data;
- const ModifierTypeInfo *mti = modifierType_getInfo(md_eval->type);
+ const ModifierTypeInfo *mti = BKE_modifier_get_info(md_eval->type);
Mesh *result;
KeyBlock *kb;
ModifierEvalContext mectx = {depsgraph, ob_eval, MOD_APPLY_TO_BASE_MESH};
@@ -1341,7 +1357,7 @@ Mesh *BKE_mesh_create_derived_for_modifier(struct Depsgraph *depsgraph,
add_shapekey_layers(mesh_temp, me);
}
- result = mti->applyModifier(md_eval, &mectx, mesh_temp);
+ result = mti->modifyMesh(md_eval, &mectx, mesh_temp);
ASSERT_IS_VALID_MESH(result);
if (mesh_temp != result) {
diff --git a/source/blender/blenkernel/intern/mesh_evaluate.c b/source/blender/blenkernel/intern/mesh_evaluate.c
index 0b3650fd40a..433db26ded8 100644
--- a/source/blender/blenkernel/intern/mesh_evaluate.c
+++ b/source/blender/blenkernel/intern/mesh_evaluate.c
@@ -46,6 +46,7 @@
#include "BLI_utildefines.h"
#include "BKE_customdata.h"
+#include "BKE_editmesh_cache.h"
#include "BKE_global.h"
#include "BKE_mesh.h"
#include "BKE_multires.h"
@@ -396,6 +397,21 @@ void BKE_mesh_ensure_normals(Mesh *mesh)
*/
void BKE_mesh_ensure_normals_for_display(Mesh *mesh)
{
+ switch ((eMeshWrapperType)mesh->runtime.wrapper_type) {
+ case ME_WRAPPER_TYPE_MDATA:
+ /* Run code below. */
+ break;
+ case ME_WRAPPER_TYPE_BMESH: {
+ struct BMEditMesh *em = mesh->edit_mesh;
+ EditMeshData *emd = mesh->runtime.edit_data;
+ if (emd->vertexCos) {
+ BKE_editmesh_cache_ensure_vert_normals(em, emd);
+ BKE_editmesh_cache_ensure_poly_normals(em, emd);
+ }
+ return;
+ }
+ }
+
float(*poly_nors)[3] = CustomData_get_layer(&mesh->pdata, CD_NORMAL);
const bool do_vert_normals = (mesh->runtime.cd_dirty_vert & CD_MASK_NORMAL) != 0;
const bool do_poly_normals = (mesh->runtime.cd_dirty_poly & CD_MASK_NORMAL || poly_nors == NULL);
@@ -1012,7 +1028,7 @@ void BKE_mesh_loop_manifold_fan_around_vert_next(const MLoop *mloops,
static void split_loop_nor_single_do(LoopSplitTaskDataCommon *common_data, LoopSplitTaskData *data)
{
MLoopNorSpaceArray *lnors_spacearr = common_data->lnors_spacearr;
- short(*clnors_data)[2] = common_data->clnors_data;
+ const short(*clnors_data)[2] = common_data->clnors_data;
const MVert *mverts = common_data->mverts;
const MEdge *medges = common_data->medges;
@@ -1300,9 +1316,9 @@ static void loop_split_worker_do(LoopSplitTaskDataCommon *common_data,
}
}
-static void loop_split_worker(TaskPool *__restrict pool, void *taskdata, int UNUSED(threadid))
+static void loop_split_worker(TaskPool *__restrict pool, void *taskdata)
{
- LoopSplitTaskDataCommon *common_data = BLI_task_pool_userdata(pool);
+ LoopSplitTaskDataCommon *common_data = BLI_task_pool_user_data(pool);
LoopSplitTaskData *data = taskdata;
/* Temp edge vectors stack, only used when computing lnor spacearr. */
@@ -1555,7 +1571,7 @@ static void loop_split_generator(TaskPool *pool, LoopSplitTaskDataCommon *common
if (pool) {
data_idx++;
if (data_idx == LOOP_SPLIT_TASK_BLOCK_SIZE) {
- BLI_task_pool_push(pool, loop_split_worker, data_buff, true, TASK_PRIORITY_LOW);
+ BLI_task_pool_push(pool, loop_split_worker, data_buff, true, NULL);
data_idx = 0;
}
}
@@ -1572,7 +1588,7 @@ static void loop_split_generator(TaskPool *pool, LoopSplitTaskDataCommon *common
/* Last block of data... Since it is calloc'ed and we use first NULL item as stopper,
* everything is fine. */
if (pool && data_idx) {
- BLI_task_pool_push(pool, loop_split_worker, data_buff, true, TASK_PRIORITY_LOW);
+ BLI_task_pool_push(pool, loop_split_worker, data_buff, true, NULL);
}
if (edge_vectors) {
@@ -1704,11 +1720,7 @@ void BKE_mesh_normals_loop_split(const MVert *mverts,
loop_split_generator(NULL, &common_data);
}
else {
- TaskScheduler *task_scheduler;
- TaskPool *task_pool;
-
- task_scheduler = BLI_task_scheduler_get();
- task_pool = BLI_task_pool_create(task_scheduler, &common_data);
+ TaskPool *task_pool = BLI_task_pool_create(&common_data, TASK_PRIORITY_HIGH);
loop_split_generator(task_pool, &common_data);
diff --git a/source/blender/blenkernel/intern/mesh_iterators.c b/source/blender/blenkernel/intern/mesh_iterators.c
index f2ed9456b11..5ecf5ae316d 100644
--- a/source/blender/blenkernel/intern/mesh_iterators.c
+++ b/source/blender/blenkernel/intern/mesh_iterators.c
@@ -24,6 +24,8 @@
#include "DNA_meshdata_types.h"
#include "BKE_customdata.h"
+#include "BKE_editmesh.h"
+#include "BKE_editmesh_cache.h"
#include "BKE_mesh.h"
#include "BKE_mesh_iterators.h"
@@ -42,23 +44,53 @@ void BKE_mesh_foreach_mapped_vert(Mesh *mesh,
void *userData,
MeshForeachFlag flag)
{
- const MVert *mv = mesh->mvert;
- const int *index = CustomData_get_layer(&mesh->vdata, CD_ORIGINDEX);
-
- if (index) {
- for (int i = 0; i < mesh->totvert; i++, mv++) {
- const short *no = (flag & MESH_FOREACH_USE_NORMAL) ? mv->no : NULL;
- const int orig = *index++;
- if (orig == ORIGINDEX_NONE) {
- continue;
+ if (mesh->edit_mesh != NULL) {
+ BMEditMesh *em = mesh->edit_mesh;
+ BMesh *bm = em->bm;
+ BMIter iter;
+ BMVert *eve;
+ int i;
+ if (mesh->runtime.edit_data->vertexCos != NULL) {
+ const float(*vertexCos)[3] = mesh->runtime.edit_data->vertexCos;
+ const float(*vertexNos)[3];
+ if (flag & MESH_FOREACH_USE_NORMAL) {
+ BKE_editmesh_cache_ensure_vert_normals(em, mesh->runtime.edit_data);
+ vertexNos = mesh->runtime.edit_data->vertexNos;
+ }
+ else {
+ vertexNos = NULL;
+ }
+ BM_ITER_MESH_INDEX (eve, &iter, bm, BM_VERTS_OF_MESH, i) {
+ const float *no = (flag & MESH_FOREACH_USE_NORMAL) ? vertexNos[i] : NULL;
+ func(userData, i, vertexCos[i], no, NULL);
+ }
+ }
+ else {
+ BM_ITER_MESH_INDEX (eve, &iter, bm, BM_VERTS_OF_MESH, i) {
+ const float *no = (flag & MESH_FOREACH_USE_NORMAL) ? eve->no : NULL;
+ func(userData, i, eve->co, no, NULL);
}
- func(userData, orig, mv->co, NULL, no);
}
}
else {
- for (int i = 0; i < mesh->totvert; i++, mv++) {
- const short *no = (flag & MESH_FOREACH_USE_NORMAL) ? mv->no : NULL;
- func(userData, i, mv->co, NULL, no);
+ const MVert *mv = mesh->mvert;
+ const int *index = CustomData_get_layer(&mesh->vdata, CD_ORIGINDEX);
+
+ if (index) {
+ for (int i = 0; i < mesh->totvert; i++, mv++) {
+ const short *no = (flag & MESH_FOREACH_USE_NORMAL) ? mv->no : NULL;
+ const int orig = *index++;
+ if (orig == ORIGINDEX_NONE) {
+ continue;
+ }
+ func(userData, orig, mv->co, NULL, no);
+ }
+ }
+ else {
+ for (int i = 0; i < mesh->totvert; i++, mv++) {
+ const short *no = (flag & MESH_FOREACH_USE_NORMAL) ? mv->no : NULL;
+ func(userData, i, mv->co, NULL, no);
+ }
}
}
}
@@ -69,22 +101,47 @@ void BKE_mesh_foreach_mapped_edge(
void (*func)(void *userData, int index, const float v0co[3], const float v1co[3]),
void *userData)
{
- const MVert *mv = mesh->mvert;
- const MEdge *med = mesh->medge;
- const int *index = CustomData_get_layer(&mesh->edata, CD_ORIGINDEX);
+ if (mesh->edit_mesh != NULL) {
+ BMEditMesh *em = mesh->edit_mesh;
+ BMesh *bm = em->bm;
+ BMIter iter;
+ BMEdge *eed;
+ int i;
+ if (mesh->runtime.edit_data->vertexCos != NULL) {
+ const float(*vertexCos)[3] = mesh->runtime.edit_data->vertexCos;
+ BM_mesh_elem_index_ensure(bm, BM_VERT);
- if (index) {
- for (int i = 0; i < mesh->totedge; i++, med++) {
- const int orig = *index++;
- if (orig == ORIGINDEX_NONE) {
- continue;
+ BM_ITER_MESH_INDEX (eed, &iter, bm, BM_EDGES_OF_MESH, i) {
+ func(userData,
+ i,
+ vertexCos[BM_elem_index_get(eed->v1)],
+ vertexCos[BM_elem_index_get(eed->v2)]);
+ }
+ }
+ else {
+ BM_ITER_MESH_INDEX (eed, &iter, bm, BM_EDGES_OF_MESH, i) {
+ func(userData, i, eed->v1->co, eed->v2->co);
}
- func(userData, orig, mv[med->v1].co, mv[med->v2].co);
}
}
else {
- for (int i = 0; i < mesh->totedge; i++, med++) {
- func(userData, i, mv[med->v1].co, mv[med->v2].co);
+ const MVert *mv = mesh->mvert;
+ const MEdge *med = mesh->medge;
+ const int *index = CustomData_get_layer(&mesh->edata, CD_ORIGINDEX);
+
+ if (index) {
+ for (int i = 0; i < mesh->totedge; i++, med++) {
+ const int orig = *index++;
+ if (orig == ORIGINDEX_NONE) {
+ continue;
+ }
+ func(userData, orig, mv[med->v1].co, mv[med->v2].co);
+ }
+ }
+ else {
+ for (int i = 0; i < mesh->totedge; i++, med++) {
+ func(userData, i, mv[med->v1].co, mv[med->v2].co);
+ }
}
}
}
@@ -99,40 +156,72 @@ void BKE_mesh_foreach_mapped_loop(Mesh *mesh,
void *userData,
MeshForeachFlag flag)
{
+
/* We can't use dm->getLoopDataLayout(dm) here,
* we want to always access dm->loopData, EditDerivedBMesh would
* return loop data from bmesh itself. */
- const float(*lnors)[3] = (flag & MESH_FOREACH_USE_NORMAL) ?
- CustomData_get_layer(&mesh->ldata, CD_NORMAL) :
- NULL;
+ if (mesh->edit_mesh != NULL) {
+ BMEditMesh *em = mesh->edit_mesh;
+ BMesh *bm = em->bm;
+ BMIter iter;
+ BMFace *efa;
- const MVert *mv = mesh->mvert;
- const MLoop *ml = mesh->mloop;
- const MPoly *mp = mesh->mpoly;
- const int *v_index = CustomData_get_layer(&mesh->vdata, CD_ORIGINDEX);
- const int *f_index = CustomData_get_layer(&mesh->pdata, CD_ORIGINDEX);
- int p_idx, i;
-
- if (v_index || f_index) {
- for (p_idx = 0; p_idx < mesh->totpoly; p_idx++, mp++) {
- for (i = 0; i < mp->totloop; i++, ml++) {
- const int v_idx = v_index ? v_index[ml->v] : ml->v;
- const int f_idx = f_index ? f_index[p_idx] : p_idx;
+ const float(*vertexCos)[3] = mesh->runtime.edit_data->vertexCos;
+
+ /* XXX: investigate using EditMesh data. */
+ const float(*lnors)[3] = (flag & MESH_FOREACH_USE_NORMAL) ?
+ CustomData_get_layer(&mesh->ldata, CD_NORMAL) :
+ NULL;
+
+ int f_idx;
+
+ BM_mesh_elem_index_ensure(bm, BM_VERT);
+
+ BM_ITER_MESH_INDEX (efa, &iter, bm, BM_FACES_OF_MESH, f_idx) {
+ BMLoop *l_iter, *l_first;
+
+ l_iter = l_first = BM_FACE_FIRST_LOOP(efa);
+ do {
+ const BMVert *eve = l_iter->v;
+ const int v_idx = BM_elem_index_get(eve);
const float *no = lnors ? *lnors++ : NULL;
- if (ELEM(ORIGINDEX_NONE, v_idx, f_idx)) {
- continue;
- }
- func(userData, v_idx, f_idx, mv[ml->v].co, no);
- }
+ func(userData, v_idx, f_idx, vertexCos ? vertexCos[v_idx] : eve->co, no);
+ } while ((l_iter = l_iter->next) != l_first);
}
}
else {
- for (p_idx = 0; p_idx < mesh->totpoly; p_idx++, mp++) {
- for (i = 0; i < mp->totloop; i++, ml++) {
- const int v_idx = ml->v;
- const int f_idx = p_idx;
- const float *no = lnors ? *lnors++ : NULL;
- func(userData, v_idx, f_idx, mv[ml->v].co, no);
+ const float(*lnors)[3] = (flag & MESH_FOREACH_USE_NORMAL) ?
+ CustomData_get_layer(&mesh->ldata, CD_NORMAL) :
+ NULL;
+
+ const MVert *mv = mesh->mvert;
+ const MLoop *ml = mesh->mloop;
+ const MPoly *mp = mesh->mpoly;
+ const int *v_index = CustomData_get_layer(&mesh->vdata, CD_ORIGINDEX);
+ const int *f_index = CustomData_get_layer(&mesh->pdata, CD_ORIGINDEX);
+ int p_idx, i;
+
+ if (v_index || f_index) {
+ for (p_idx = 0; p_idx < mesh->totpoly; p_idx++, mp++) {
+ for (i = 0; i < mp->totloop; i++, ml++) {
+ const int v_idx = v_index ? v_index[ml->v] : ml->v;
+ const int f_idx = f_index ? f_index[p_idx] : p_idx;
+ const float *no = lnors ? *lnors++ : NULL;
+ if (ELEM(ORIGINDEX_NONE, v_idx, f_idx)) {
+ continue;
+ }
+ func(userData, v_idx, f_idx, mv[ml->v].co, no);
+ }
+ }
+ }
+ else {
+ for (p_idx = 0; p_idx < mesh->totpoly; p_idx++, mp++) {
+ for (i = 0; i < mp->totloop; i++, ml++) {
+ const int v_idx = ml->v;
+ const int f_idx = p_idx;
+ const float *no = lnors ? *lnors++ : NULL;
+ func(userData, v_idx, f_idx, mv[ml->v].co, no);
+ }
}
}
}
@@ -145,37 +234,72 @@ void BKE_mesh_foreach_mapped_face_center(
void *userData,
MeshForeachFlag flag)
{
- const MVert *mvert = mesh->mvert;
- const MPoly *mp = mesh->mpoly;
- const MLoop *ml;
- float _no_buf[3];
- float *no = (flag & MESH_FOREACH_USE_NORMAL) ? _no_buf : NULL;
- const int *index = CustomData_get_layer(&mesh->pdata, CD_ORIGINDEX);
+ if (mesh->edit_mesh != NULL) {
+ BMEditMesh *em = mesh->edit_mesh;
+ BMesh *bm = em->bm;
+ const float(*polyCos)[3];
+ const float(*polyNos)[3];
+ BMFace *efa;
+ BMIter iter;
+ int i;
- if (index) {
- for (int i = 0; i < mesh->totpoly; i++, mp++) {
- const int orig = *index++;
- if (orig == ORIGINDEX_NONE) {
- continue;
+ BKE_editmesh_cache_ensure_poly_centers(em, mesh->runtime.edit_data);
+ polyCos = mesh->runtime.edit_data->polyCos; /* always set */
+
+ if (flag & MESH_FOREACH_USE_NORMAL) {
+ BKE_editmesh_cache_ensure_poly_normals(em, mesh->runtime.edit_data);
+ polyNos = mesh->runtime.edit_data->polyNos; /* maybe NULL */
+ }
+ else {
+ polyNos = NULL;
+ }
+
+ if (polyNos) {
+ BM_ITER_MESH_INDEX (efa, &iter, bm, BM_FACES_OF_MESH, i) {
+ const float *no = polyNos[i];
+ func(userData, i, polyCos[i], no);
}
- float cent[3];
- ml = &mesh->mloop[mp->loopstart];
- BKE_mesh_calc_poly_center(mp, ml, mvert, cent);
- if (flag & MESH_FOREACH_USE_NORMAL) {
- BKE_mesh_calc_poly_normal(mp, ml, mvert, no);
+ }
+ else {
+ BM_ITER_MESH_INDEX (efa, &iter, bm, BM_FACES_OF_MESH, i) {
+ const float *no = (flag & MESH_FOREACH_USE_NORMAL) ? efa->no : NULL;
+ func(userData, i, polyCos[i], no);
}
- func(userData, orig, cent, no);
}
}
else {
- for (int i = 0; i < mesh->totpoly; i++, mp++) {
- float cent[3];
- ml = &mesh->mloop[mp->loopstart];
- BKE_mesh_calc_poly_center(mp, ml, mvert, cent);
- if (flag & MESH_FOREACH_USE_NORMAL) {
- BKE_mesh_calc_poly_normal(mp, ml, mvert, no);
+ const MVert *mvert = mesh->mvert;
+ const MPoly *mp = mesh->mpoly;
+ const MLoop *ml;
+ float _no_buf[3];
+ float *no = (flag & MESH_FOREACH_USE_NORMAL) ? _no_buf : NULL;
+ const int *index = CustomData_get_layer(&mesh->pdata, CD_ORIGINDEX);
+
+ if (index) {
+ for (int i = 0; i < mesh->totpoly; i++, mp++) {
+ const int orig = *index++;
+ if (orig == ORIGINDEX_NONE) {
+ continue;
+ }
+ float cent[3];
+ ml = &mesh->mloop[mp->loopstart];
+ BKE_mesh_calc_poly_center(mp, ml, mvert, cent);
+ if (flag & MESH_FOREACH_USE_NORMAL) {
+ BKE_mesh_calc_poly_normal(mp, ml, mvert, no);
+ }
+ func(userData, orig, cent, no);
+ }
+ }
+ else {
+ for (int i = 0; i < mesh->totpoly; i++, mp++) {
+ float cent[3];
+ ml = &mesh->mloop[mp->loopstart];
+ BKE_mesh_calc_poly_center(mp, ml, mvert, cent);
+ if (flag & MESH_FOREACH_USE_NORMAL) {
+ BKE_mesh_calc_poly_normal(mp, ml, mvert, no);
+ }
+ func(userData, i, cent, no);
}
- func(userData, i, cent, no);
}
}
}
diff --git a/source/blender/blenkernel/intern/mesh_mirror.c b/source/blender/blenkernel/intern/mesh_mirror.c
index 9799d97d1cc..d9be9a99b2b 100644
--- a/source/blender/blenkernel/intern/mesh_mirror.c
+++ b/source/blender/blenkernel/intern/mesh_mirror.c
@@ -77,7 +77,7 @@ Mesh *BKE_mesh_mirror_bisect_on_mirror_plane(MirrorModifierData *mmd,
}
plane_from_point_normal_v3(plane, plane_co, plane_no);
- BM_mesh_bisect_plane(bm, plane, false, false, 0, 0, bisect_distance);
+ BM_mesh_bisect_plane(bm, plane, true, false, 0, 0, bisect_distance);
/* Plane definitions for vert killing. */
float plane_offset[4];
@@ -290,6 +290,8 @@ Mesh *BKE_mesh_mirror_apply_mirror_on_axis(MirrorModifierData *mmd,
(is_zero_v2(mmd->uv_offset_copy) == false)) {
const bool do_mirr_u = (mmd->flag & MOD_MIR_MIRROR_U) != 0;
const bool do_mirr_v = (mmd->flag & MOD_MIR_MIRROR_V) != 0;
+ /* If set, flip around center of each tile. */
+ const bool do_mirr_udim = (mmd->flag & MOD_MIR_MIRROR_UDIM) != 0;
const int totuv = CustomData_number_of_layers(&result->ldata, CD_MLOOPUV);
@@ -299,10 +301,22 @@ Mesh *BKE_mesh_mirror_apply_mirror_on_axis(MirrorModifierData *mmd,
dmloopuv += j; /* second set of loops only */
for (; j-- > 0; dmloopuv++) {
if (do_mirr_u) {
- dmloopuv->uv[0] = 1.0f - dmloopuv->uv[0] + mmd->uv_offset[0];
+ float u = dmloopuv->uv[0];
+ if (do_mirr_udim) {
+ dmloopuv->uv[0] = ceilf(u) - fmodf(u, 1.0f) + mmd->uv_offset[0];
+ }
+ else {
+ dmloopuv->uv[0] = 1.0f - u + mmd->uv_offset[0];
+ }
}
if (do_mirr_v) {
- dmloopuv->uv[1] = 1.0f - dmloopuv->uv[1] + mmd->uv_offset[1];
+ float v = dmloopuv->uv[1];
+ if (do_mirr_udim) {
+ dmloopuv->uv[1] = ceilf(v) - fmodf(v, 1.0f) + mmd->uv_offset[1];
+ }
+ else {
+ dmloopuv->uv[1] = 1.0f - v + mmd->uv_offset[1];
+ }
}
dmloopuv->uv[0] += mmd->uv_offset_copy[0];
dmloopuv->uv[1] += mmd->uv_offset_copy[1];
diff --git a/source/blender/blenkernel/intern/mesh_remap.c b/source/blender/blenkernel/intern/mesh_remap.c
index d09205b5744..404d6a581ae 100644
--- a/source/blender/blenkernel/intern/mesh_remap.c
+++ b/source/blender/blenkernel/intern/mesh_remap.c
@@ -1555,6 +1555,7 @@ void BKE_mesh_remap_calc_loops_from_mesh(const int mode,
2,
6,
0,
+ NULL,
NULL);
}
@@ -1598,6 +1599,7 @@ void BKE_mesh_remap_calc_loops_from_mesh(const int mode,
2,
6,
0,
+ NULL,
NULL);
}
diff --git a/source/blender/blenkernel/intern/mesh_runtime.c b/source/blender/blenkernel/intern/mesh_runtime.c
index aa3586d1e3d..8bce577897b 100644
--- a/source/blender/blenkernel/intern/mesh_runtime.c
+++ b/source/blender/blenkernel/intern/mesh_runtime.c
@@ -53,6 +53,7 @@ void BKE_mesh_runtime_reset(Mesh *mesh)
memset(&mesh->runtime, 0, sizeof(mesh->runtime));
mesh->runtime.eval_mutex = MEM_mallocN(sizeof(ThreadMutex), "mesh runtime eval_mutex");
BLI_mutex_init(mesh->runtime.eval_mutex);
+ mesh->runtime.bvh_cache = NULL;
}
/* Clear all pointers which we don't want to be shared on copying the datablock.
@@ -227,7 +228,10 @@ bool BKE_mesh_runtime_clear_edit_data(Mesh *mesh)
void BKE_mesh_runtime_clear_geometry(Mesh *mesh)
{
- bvhcache_free(&mesh->runtime.bvh_cache);
+ if (mesh->runtime.bvh_cache) {
+ bvhcache_free(mesh->runtime.bvh_cache);
+ mesh->runtime.bvh_cache = NULL;
+ }
MEM_SAFE_FREE(mesh->runtime.looptris.array);
/* TODO(sergey): Does this really belong here? */
if (mesh->runtime.subdiv_ccg != NULL) {
diff --git a/source/blender/blenkernel/intern/mesh_tangent.c b/source/blender/blenkernel/intern/mesh_tangent.c
index ebc3e9c490a..d6f945cf34f 100644
--- a/source/blender/blenkernel/intern/mesh_tangent.c
+++ b/source/blender/blenkernel/intern/mesh_tangent.c
@@ -452,9 +452,7 @@ finally:
pRes[3] = fSign;
}
-static void DM_calc_loop_tangents_thread(TaskPool *__restrict UNUSED(pool),
- void *taskdata,
- int UNUSED(threadid))
+static void DM_calc_loop_tangents_thread(TaskPool *__restrict UNUSED(pool), void *taskdata)
{
struct SGLSLMeshToTangent *mesh2tangent = taskdata;
/* new computation method */
@@ -658,9 +656,7 @@ void BKE_mesh_calc_loop_tangent_ex(const MVert *mvert,
/* Calculation */
if (looptri_len != 0) {
- TaskScheduler *scheduler = BLI_task_scheduler_get();
- TaskPool *task_pool;
- task_pool = BLI_task_pool_create(scheduler, NULL);
+ TaskPool *task_pool = BLI_task_pool_create(NULL, TASK_PRIORITY_LOW);
tangent_mask_curr = 0;
/* Calculate tangent layers */
@@ -707,8 +703,7 @@ void BKE_mesh_calc_loop_tangent_ex(const MVert *mvert,
}
mesh2tangent->tangent = loopdata_out->layers[index].data;
- BLI_task_pool_push(
- task_pool, DM_calc_loop_tangents_thread, mesh2tangent, false, TASK_PRIORITY_LOW);
+ BLI_task_pool_push(task_pool, DM_calc_loop_tangents_thread, mesh2tangent, false, NULL);
}
BLI_assert(tangent_mask_curr == tangent_mask);
diff --git a/source/blender/blenkernel/intern/mesh_validate.c b/source/blender/blenkernel/intern/mesh_validate.c
index 3343d41b13c..f64ed609d18 100644
--- a/source/blender/blenkernel/intern/mesh_validate.c
+++ b/source/blender/blenkernel/intern/mesh_validate.c
@@ -1593,8 +1593,15 @@ void BKE_mesh_calc_edges(Mesh *mesh, bool update, const bool select)
MLoop *l_prev = (l + (mp->totloop - 1));
int j;
for (j = 0; j < mp->totloop; j++, l++) {
- /* lookup hashed edge index */
- med_index = POINTER_AS_INT(BLI_edgehash_lookup(eh, l_prev->v, l->v));
+ /* Lookup hashed edge index, if it's valid. */
+ if (l_prev->v != l->v) {
+ med_index = POINTER_AS_INT(BLI_edgehash_lookup(eh, l_prev->v, l->v));
+ }
+ else {
+ /* This is an invalid edge; normally this does not happen in Blender, but it can be part
+ * of an imported mesh with invalid geometry. See T76514. */
+ med_index = 0;
+ }
l_prev->e = med_index;
l_prev = l;
}
diff --git a/source/blender/blenkernel/intern/mesh_wrapper.c b/source/blender/blenkernel/intern/mesh_wrapper.c
new file mode 100644
index 00000000000..f073feffedc
--- /dev/null
+++ b/source/blender/blenkernel/intern/mesh_wrapper.c
@@ -0,0 +1,166 @@
+/*
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+
+/** \file
+ * \ingroup bke
+ *
+ * The primary purpose of this API is to avoid unnecessary mesh conversion for the final
+ * output of a modified mesh.
+ *
+ * This API handles the case when the modifier stack outputs a mesh which does not have
+ * #Mesh data (#MPoly, #MLoop, #MEdge, #MVert).
+ * Currently this is used so the resulting mesh can have #BMEditMesh data,
+ * postponing the converting until it's needed or avoiding conversion entirely
+ * which can be an expensive operation.
+ * Once converted, the meshes type changes to #ME_WRAPPER_TYPE_MDATA,
+ * although the edit mesh is not cleared.
+ *
+ * This API exposes functions that abstract over the different kinds of internal data,
+ * as well as supporting converting the mesh into regular mesh.
+ */
+
+#include "MEM_guardedalloc.h"
+
+#include "DNA_defaults.h"
+#include "DNA_key_types.h"
+#include "DNA_mesh_types.h"
+#include "DNA_meshdata_types.h"
+#include "DNA_object_types.h"
+
+#include "BLI_bitmap.h"
+#include "BLI_edgehash.h"
+#include "BLI_ghash.h"
+#include "BLI_hash.h"
+#include "BLI_linklist.h"
+#include "BLI_math.h"
+#include "BLI_memarena.h"
+#include "BLI_string.h"
+#include "BLI_utildefines.h"
+
+#include "BLT_translation.h"
+
+#include "BKE_animsys.h"
+#include "BKE_editmesh.h"
+#include "BKE_editmesh_cache.h"
+#include "BKE_global.h"
+#include "BKE_idtype.h"
+#include "BKE_key.h"
+#include "BKE_lib_id.h"
+#include "BKE_main.h"
+#include "BKE_material.h"
+#include "BKE_mesh.h"
+#include "BKE_mesh_runtime.h"
+#include "BKE_modifier.h"
+#include "BKE_multires.h"
+#include "BKE_object.h"
+
+#include "PIL_time.h"
+
+#include "DEG_depsgraph.h"
+#include "DEG_depsgraph_query.h"
+
+Mesh *BKE_mesh_wrapper_from_editmesh_with_coords(BMEditMesh *em,
+ const CustomData_MeshMasks *cd_mask_extra,
+ float (*vertexCos)[3],
+ const Mesh *me_settings)
+{
+ Mesh *me = BKE_id_new_nomain(ID_ME, NULL);
+ BKE_mesh_copy_settings(me, me_settings);
+ BKE_mesh_runtime_ensure_edit_data(me);
+
+ me->runtime.wrapper_type = ME_WRAPPER_TYPE_BMESH;
+ if (cd_mask_extra) {
+ me->runtime.cd_mask_extra = *cd_mask_extra;
+ }
+
+ /* Use edit-mesh directly where possible. */
+ me->runtime.is_original = true;
+ me->edit_mesh = MEM_dupallocN(em);
+
+/* Make sure, we crash if these are ever used. */
+#ifdef DEBUG
+ me->totvert = INT_MAX;
+ me->totedge = INT_MAX;
+ me->totpoly = INT_MAX;
+ me->totloop = INT_MAX;
+#else
+ me->totvert = 0;
+ me->totedge = 0;
+ me->totpoly = 0;
+ me->totloop = 0;
+#endif
+
+ EditMeshData *edit_data = me->runtime.edit_data;
+ edit_data->vertexCos = vertexCos;
+ return me;
+}
+
+Mesh *BKE_mesh_wrapper_from_editmesh(BMEditMesh *em,
+ const CustomData_MeshMasks *cd_mask_extra,
+ const Mesh *me_settings)
+{
+ return BKE_mesh_wrapper_from_editmesh_with_coords(em, cd_mask_extra, NULL, me_settings);
+}
+
+void BKE_mesh_wrapper_ensure_mdata(Mesh *me)
+{
+ if (me->runtime.wrapper_type == ME_WRAPPER_TYPE_MDATA) {
+ return;
+ }
+ const eMeshWrapperType geom_type_orig = me->runtime.wrapper_type;
+ me->runtime.wrapper_type = ME_WRAPPER_TYPE_MDATA;
+
+ switch (geom_type_orig) {
+ case ME_WRAPPER_TYPE_MDATA: {
+ break; /* Quiet warning. */
+ }
+ case ME_WRAPPER_TYPE_BMESH: {
+ me->totvert = 0;
+ me->totedge = 0;
+ me->totpoly = 0;
+ me->totloop = 0;
+
+ BLI_assert(me->edit_mesh != NULL);
+ BLI_assert(me->runtime.edit_data != NULL);
+
+ BMEditMesh *em = me->edit_mesh;
+ BM_mesh_bm_to_me_for_eval(em->bm, me, &me->runtime.cd_mask_extra);
+
+ EditMeshData *edit_data = me->runtime.edit_data;
+ if (edit_data->vertexCos) {
+ BKE_mesh_vert_coords_apply(me, edit_data->vertexCos);
+ me->runtime.is_original = false;
+ }
+ break;
+ }
+ }
+
+ if (me->runtime.wrapper_type_finalize) {
+ BKE_mesh_wrapper_deferred_finalize(me, &me->runtime.cd_mask_extra);
+ }
+}
+
+bool BKE_mesh_wrapper_minmax(const Mesh *me, float min[3], float max[3])
+{
+ switch ((eMeshWrapperType)me->runtime.wrapper_type) {
+ case ME_WRAPPER_TYPE_BMESH:
+ return BKE_editmesh_cache_calc_minmax(me->edit_mesh, me->runtime.edit_data, min, max);
+ case ME_WRAPPER_TYPE_MDATA:
+ return BKE_mesh_minmax(me, min, max);
+ }
+ BLI_assert(0);
+ return false;
+}
diff --git a/source/blender/blenkernel/intern/modifier.c b/source/blender/blenkernel/intern/modifier.c
index 0a76b61cdb1..6b54a530034 100644
--- a/source/blender/blenkernel/intern/modifier.c
+++ b/source/blender/blenkernel/intern/modifier.c
@@ -10,7 +10,7 @@
* 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,
+ * 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) 2005 by the Blender Foundation.
@@ -50,6 +50,7 @@
#include "BKE_DerivedMesh.h"
#include "BKE_appdir.h"
#include "BKE_editmesh.h"
+#include "BKE_editmesh_cache.h"
#include "BKE_global.h"
#include "BKE_idtype.h"
#include "BKE_key.h"
@@ -59,7 +60,7 @@
#include "BKE_multires.h"
#include "BKE_object.h"
-/* may move these, only for modifier_path_relbase */
+/* may move these, only for BKE_modifier_path_relbase */
#include "BKE_main.h"
/* end */
@@ -82,21 +83,21 @@ void BKE_modifier_init(void)
modifier_type_init(modifier_types); /* MOD_utils.c */
/* Initialize global cmmon storage used for virtual modifier list */
- md = modifier_new(eModifierType_Armature);
+ md = BKE_modifier_new(eModifierType_Armature);
virtualModifierCommonData.amd = *((ArmatureModifierData *)md);
- modifier_free(md);
+ BKE_modifier_free(md);
- md = modifier_new(eModifierType_Curve);
+ md = BKE_modifier_new(eModifierType_Curve);
virtualModifierCommonData.cmd = *((CurveModifierData *)md);
- modifier_free(md);
+ BKE_modifier_free(md);
- md = modifier_new(eModifierType_Lattice);
+ md = BKE_modifier_new(eModifierType_Lattice);
virtualModifierCommonData.lmd = *((LatticeModifierData *)md);
- modifier_free(md);
+ BKE_modifier_free(md);
- md = modifier_new(eModifierType_ShapeKey);
+ md = BKE_modifier_new(eModifierType_ShapeKey);
virtualModifierCommonData.smd = *((ShapeKeyModifierData *)md);
- modifier_free(md);
+ BKE_modifier_free(md);
virtualModifierCommonData.amd.modifier.mode |= eModifierMode_Virtual;
virtualModifierCommonData.cmd.modifier.mode |= eModifierMode_Virtual;
@@ -104,7 +105,7 @@ void BKE_modifier_init(void)
virtualModifierCommonData.smd.modifier.mode |= eModifierMode_Virtual;
}
-const ModifierTypeInfo *modifierType_getInfo(ModifierType type)
+const ModifierTypeInfo *BKE_modifier_get_info(ModifierType type)
{
/* type unsigned, no need to check < 0 */
if (type < NUM_MODIFIER_TYPES && modifier_types[type] && modifier_types[type]->name[0] != '\0') {
@@ -117,9 +118,9 @@ const ModifierTypeInfo *modifierType_getInfo(ModifierType type)
/***/
-ModifierData *modifier_new(int type)
+ModifierData *BKE_modifier_new(int type)
{
- const ModifierTypeInfo *mti = modifierType_getInfo(type);
+ const ModifierTypeInfo *mti = BKE_modifier_get_info(type);
ModifierData *md = MEM_callocN(mti->structSize, mti->structName);
/* note, this name must be made unique later */
@@ -151,9 +152,9 @@ static void modifier_free_data_id_us_cb(void *UNUSED(userData),
}
}
-void modifier_free_ex(ModifierData *md, const int flag)
+void BKE_modifier_free_ex(ModifierData *md, const int flag)
{
- const ModifierTypeInfo *mti = modifierType_getInfo(md->type);
+ const ModifierTypeInfo *mti = BKE_modifier_get_info(md->type);
if ((flag & LIB_ID_CREATE_NO_USER_REFCOUNT) == 0) {
if (mti->foreachIDLink) {
@@ -174,15 +175,15 @@ void modifier_free_ex(ModifierData *md, const int flag)
MEM_freeN(md);
}
-void modifier_free(ModifierData *md)
+void BKE_modifier_free(ModifierData *md)
{
- modifier_free_ex(md, 0);
+ BKE_modifier_free_ex(md, 0);
}
-bool modifier_unique_name(ListBase *modifiers, ModifierData *md)
+bool BKE_modifier_unique_name(ListBase *modifiers, ModifierData *md)
{
if (modifiers && md) {
- const ModifierTypeInfo *mti = modifierType_getInfo(md->type);
+ const ModifierTypeInfo *mti = BKE_modifier_get_info(md->type);
return BLI_uniquename(
modifiers, md, DATA_(mti->name), '.', offsetof(ModifierData, name), sizeof(md->name));
@@ -190,24 +191,24 @@ bool modifier_unique_name(ListBase *modifiers, ModifierData *md)
return false;
}
-bool modifier_dependsOnTime(ModifierData *md)
+bool BKE_modifier_depends_ontime(ModifierData *md)
{
- const ModifierTypeInfo *mti = modifierType_getInfo(md->type);
+ const ModifierTypeInfo *mti = BKE_modifier_get_info(md->type);
return mti->dependsOnTime && mti->dependsOnTime(md);
}
-bool modifier_supportsMapping(ModifierData *md)
+bool BKE_modifier_supports_mapping(ModifierData *md)
{
- const ModifierTypeInfo *mti = modifierType_getInfo(md->type);
+ const ModifierTypeInfo *mti = BKE_modifier_get_info(md->type);
return (mti->type == eModifierTypeType_OnlyDeform ||
(mti->flags & eModifierTypeFlag_SupportsMapping));
}
-bool modifier_isPreview(ModifierData *md)
+bool BKE_modifier_is_preview(ModifierData *md)
{
- const ModifierTypeInfo *mti = modifierType_getInfo(md->type);
+ const ModifierTypeInfo *mti = BKE_modifier_get_info(md->type);
/* Constructive modifiers are highly likely to also modify data like vgroups or vcol! */
if (!((mti->flags & eModifierTypeFlag_UsesPreview) ||
@@ -222,7 +223,7 @@ bool modifier_isPreview(ModifierData *md)
return false;
}
-ModifierData *modifiers_findByType(Object *ob, ModifierType type)
+ModifierData *BKE_modifiers_findby_type(Object *ob, ModifierType type)
{
ModifierData *md = ob->modifiers.first;
@@ -235,12 +236,12 @@ ModifierData *modifiers_findByType(Object *ob, ModifierType type)
return md;
}
-ModifierData *modifiers_findByName(Object *ob, const char *name)
+ModifierData *BKE_modifiers_findby_name(Object *ob, const char *name)
{
return BLI_findstring(&(ob->modifiers), name, offsetof(ModifierData, name));
}
-void modifiers_clearErrors(Object *ob)
+void BKE_modifiers_clear_errors(Object *ob)
{
ModifierData *md = ob->modifiers.first;
/* int qRedraw = 0; */
@@ -255,12 +256,12 @@ void modifiers_clearErrors(Object *ob)
}
}
-void modifiers_foreachObjectLink(Object *ob, ObjectWalkFunc walk, void *userData)
+void BKE_modifiers_foreach_object_link(Object *ob, ObjectWalkFunc walk, void *userData)
{
ModifierData *md = ob->modifiers.first;
for (; md; md = md->next) {
- const ModifierTypeInfo *mti = modifierType_getInfo(md->type);
+ const ModifierTypeInfo *mti = BKE_modifier_get_info(md->type);
if (mti->foreachObjectLink) {
mti->foreachObjectLink(md, ob, walk, userData);
@@ -268,12 +269,12 @@ void modifiers_foreachObjectLink(Object *ob, ObjectWalkFunc walk, void *userData
}
}
-void modifiers_foreachIDLink(Object *ob, IDWalkFunc walk, void *userData)
+void BKE_modifiers_foreach_ID_link(Object *ob, IDWalkFunc walk, void *userData)
{
ModifierData *md = ob->modifiers.first;
for (; md; md = md->next) {
- const ModifierTypeInfo *mti = modifierType_getInfo(md->type);
+ const ModifierTypeInfo *mti = BKE_modifier_get_info(md->type);
if (mti->foreachIDLink) {
mti->foreachIDLink(md, ob, walk, userData);
@@ -286,12 +287,12 @@ void modifiers_foreachIDLink(Object *ob, IDWalkFunc walk, void *userData)
}
}
-void modifiers_foreachTexLink(Object *ob, TexWalkFunc walk, void *userData)
+void BKE_modifiers_foreach_tex_link(Object *ob, TexWalkFunc walk, void *userData)
{
ModifierData *md = ob->modifiers.first;
for (; md; md = md->next) {
- const ModifierTypeInfo *mti = modifierType_getInfo(md->type);
+ const ModifierTypeInfo *mti = BKE_modifier_get_info(md->type);
if (mti->foreachTexLink) {
mti->foreachTexLink(md, ob, walk, userData);
@@ -302,11 +303,11 @@ void modifiers_foreachTexLink(Object *ob, TexWalkFunc walk, void *userData)
/* callback's can use this
* to avoid copying every member.
*/
-void modifier_copyData_generic(const ModifierData *md_src,
- ModifierData *md_dst,
- const int UNUSED(flag))
+void BKE_modifier_copydata_generic(const ModifierData *md_src,
+ ModifierData *md_dst,
+ const int UNUSED(flag))
{
- const ModifierTypeInfo *mti = modifierType_getInfo(md_src->type);
+ const ModifierTypeInfo *mti = BKE_modifier_get_info(md_src->type);
/* md_dst may have already be fully initialized with some extra allocated data,
* we need to free it now to avoid memleak. */
@@ -335,9 +336,9 @@ static void modifier_copy_data_id_us_cb(void *UNUSED(userData),
}
}
-void modifier_copyData_ex(ModifierData *md, ModifierData *target, const int flag)
+void BKE_modifier_copydata_ex(ModifierData *md, ModifierData *target, const int flag)
{
- const ModifierTypeInfo *mti = modifierType_getInfo(md->type);
+ const ModifierTypeInfo *mti = BKE_modifier_get_info(md->type);
target->mode = md->mode;
target->flag = md->flag;
@@ -356,40 +357,41 @@ void modifier_copyData_ex(ModifierData *md, ModifierData *target, const int flag
}
}
-void modifier_copyData(ModifierData *md, ModifierData *target)
+void BKE_modifier_copydata(ModifierData *md, ModifierData *target)
{
- modifier_copyData_ex(md, target, 0);
+ BKE_modifier_copydata_ex(md, target, 0);
}
-bool modifier_supportsCage(struct Scene *scene, ModifierData *md)
+bool BKE_modifier_supports_cage(struct Scene *scene, ModifierData *md)
{
- const ModifierTypeInfo *mti = modifierType_getInfo(md->type);
+ const ModifierTypeInfo *mti = BKE_modifier_get_info(md->type);
return ((!mti->isDisabled || !mti->isDisabled(scene, md, 0)) &&
- (mti->flags & eModifierTypeFlag_SupportsEditmode) && modifier_supportsMapping(md));
+ (mti->flags & eModifierTypeFlag_SupportsEditmode) && BKE_modifier_supports_mapping(md));
}
-bool modifier_couldBeCage(struct Scene *scene, ModifierData *md)
+bool BKE_modifier_couldbe_cage(struct Scene *scene, ModifierData *md)
{
- const ModifierTypeInfo *mti = modifierType_getInfo(md->type);
+ const ModifierTypeInfo *mti = BKE_modifier_get_info(md->type);
return ((md->mode & eModifierMode_Realtime) && (md->mode & eModifierMode_Editmode) &&
- (!mti->isDisabled || !mti->isDisabled(scene, md, 0)) && modifier_supportsMapping(md));
+ (!mti->isDisabled || !mti->isDisabled(scene, md, 0)) &&
+ BKE_modifier_supports_mapping(md));
}
-bool modifier_isSameTopology(ModifierData *md)
+bool BKE_modifier_is_same_topology(ModifierData *md)
{
- const ModifierTypeInfo *mti = modifierType_getInfo(md->type);
+ const ModifierTypeInfo *mti = BKE_modifier_get_info(md->type);
return ELEM(mti->type, eModifierTypeType_OnlyDeform, eModifierTypeType_NonGeometrical);
}
-bool modifier_isNonGeometrical(ModifierData *md)
+bool BKE_modifier_is_non_geometrical(ModifierData *md)
{
- const ModifierTypeInfo *mti = modifierType_getInfo(md->type);
+ const ModifierTypeInfo *mti = BKE_modifier_get_info(md->type);
return (mti->type == eModifierTypeType_NonGeometrical);
}
-void modifier_setError(ModifierData *md, const char *_format, ...)
+void BKE_modifier_set_error(ModifierData *md, const char *_format, ...)
{
char buffer[512];
va_list ap;
@@ -416,14 +418,15 @@ void modifier_setError(ModifierData *md, const char *_format, ...)
* then is NULL)
* also used for some mesh tools to give warnings
*/
-int modifiers_getCageIndex(struct Scene *scene,
- Object *ob,
- int *r_lastPossibleCageIndex,
- bool is_virtual)
+int BKE_modifiers_get_cage_index(struct Scene *scene,
+ Object *ob,
+ int *r_lastPossibleCageIndex,
+ bool is_virtual)
{
VirtualModifierData virtualModifierData;
- ModifierData *md = (is_virtual) ? modifiers_getVirtualModifierList(ob, &virtualModifierData) :
- ob->modifiers.first;
+ ModifierData *md = (is_virtual) ?
+ BKE_modifiers_get_virtual_modifierlist(ob, &virtualModifierData) :
+ ob->modifiers.first;
int i, cageIndex = -1;
if (r_lastPossibleCageIndex) {
@@ -433,7 +436,7 @@ int modifiers_getCageIndex(struct Scene *scene,
/* Find the last modifier acting on the cage. */
for (i = 0; md; i++, md = md->next) {
- const ModifierTypeInfo *mti = modifierType_getInfo(md->type);
+ const ModifierTypeInfo *mti = BKE_modifier_get_info(md->type);
bool supports_mapping;
if (mti->isDisabled && mti->isDisabled(scene, md, 0)) {
@@ -446,7 +449,7 @@ int modifiers_getCageIndex(struct Scene *scene,
continue;
}
- supports_mapping = modifier_supportsMapping(md);
+ supports_mapping = BKE_modifier_supports_mapping(md);
if (r_lastPossibleCageIndex && supports_mapping) {
*r_lastPossibleCageIndex = i;
}
@@ -470,30 +473,30 @@ int modifiers_getCageIndex(struct Scene *scene,
return cageIndex;
}
-bool modifiers_isSoftbodyEnabled(Object *ob)
+bool BKE_modifiers_is_softbody_enabled(Object *ob)
{
- ModifierData *md = modifiers_findByType(ob, eModifierType_Softbody);
+ ModifierData *md = BKE_modifiers_findby_type(ob, eModifierType_Softbody);
return (md && md->mode & (eModifierMode_Realtime | eModifierMode_Render));
}
-bool modifiers_isClothEnabled(Object *ob)
+bool BKE_modifiers_is_cloth_enabled(Object *ob)
{
- ModifierData *md = modifiers_findByType(ob, eModifierType_Cloth);
+ ModifierData *md = BKE_modifiers_findby_type(ob, eModifierType_Cloth);
return (md && md->mode & (eModifierMode_Realtime | eModifierMode_Render));
}
-bool modifiers_isModifierEnabled(Object *ob, int modifierType)
+bool BKE_modifiers_is_modifier_enabled(Object *ob, int modifierType)
{
- ModifierData *md = modifiers_findByType(ob, modifierType);
+ ModifierData *md = BKE_modifiers_findby_type(ob, modifierType);
return (md && md->mode & (eModifierMode_Realtime | eModifierMode_Render));
}
-bool modifiers_isParticleEnabled(Object *ob)
+bool BKE_modifiers_is_particle_enabled(Object *ob)
{
- ModifierData *md = modifiers_findByType(ob, eModifierType_ParticleSystem);
+ ModifierData *md = BKE_modifiers_findby_type(ob, eModifierType_ParticleSystem);
return (md && md->mode & (eModifierMode_Realtime | eModifierMode_Render));
}
@@ -504,9 +507,9 @@ bool modifiers_isParticleEnabled(Object *ob)
* \param scene: Current scene, may be NULL,
* in which case isDisabled callback of the modifier is never called.
*/
-bool modifier_isEnabled(const struct Scene *scene, ModifierData *md, int required_mode)
+bool BKE_modifier_is_enabled(const struct Scene *scene, ModifierData *md, int required_mode)
{
- const ModifierTypeInfo *mti = modifierType_getInfo(md->type);
+ const ModifierTypeInfo *mti = BKE_modifier_get_info(md->type);
if ((md->mode & required_mode) != required_mode) {
return false;
@@ -526,13 +529,13 @@ bool modifier_isEnabled(const struct Scene *scene, ModifierData *md, int require
return true;
}
-CDMaskLink *modifiers_calcDataMasks(struct Scene *scene,
- Object *ob,
- ModifierData *md,
- CustomData_MeshMasks *final_datamask,
- int required_mode,
- ModifierData *previewmd,
- const CustomData_MeshMasks *previewmask)
+CDMaskLink *BKE_modifier_calc_data_masks(struct Scene *scene,
+ Object *ob,
+ ModifierData *md,
+ CustomData_MeshMasks *final_datamask,
+ int required_mode,
+ ModifierData *previewmd,
+ const CustomData_MeshMasks *previewmask)
{
CDMaskLink *dataMasks = NULL;
CDMaskLink *curr, *prev;
@@ -540,11 +543,11 @@ CDMaskLink *modifiers_calcDataMasks(struct Scene *scene,
/* build a list of modifier data requirements in reverse order */
for (; md; md = md->next) {
- const ModifierTypeInfo *mti = modifierType_getInfo(md->type);
+ const ModifierTypeInfo *mti = BKE_modifier_get_info(md->type);
curr = MEM_callocN(sizeof(CDMaskLink), "CDMaskLink");
- if (modifier_isEnabled(scene, md, required_mode)) {
+ if (BKE_modifier_is_enabled(scene, md, required_mode)) {
if (mti->type == eModifierTypeType_OnlyDeform) {
have_deform_modifier = true;
}
@@ -594,7 +597,9 @@ CDMaskLink *modifiers_calcDataMasks(struct Scene *scene,
return dataMasks;
}
-ModifierData *modifiers_getLastPreview(struct Scene *scene, ModifierData *md, int required_mode)
+ModifierData *BKE_modifier_get_last_preview(struct Scene *scene,
+ ModifierData *md,
+ int required_mode)
{
ModifierData *tmp_md = NULL;
@@ -604,7 +609,7 @@ ModifierData *modifiers_getLastPreview(struct Scene *scene, ModifierData *md, in
/* Find the latest modifier in stack generating preview. */
for (; md; md = md->next) {
- if (modifier_isEnabled(scene, md, required_mode) && modifier_isPreview(md)) {
+ if (BKE_modifier_is_enabled(scene, md, required_mode) && BKE_modifier_is_preview(md)) {
tmp_md = md;
}
}
@@ -613,8 +618,8 @@ ModifierData *modifiers_getLastPreview(struct Scene *scene, ModifierData *md, in
/* This is to include things that are not modifiers in the evaluation of the modifier stack, for
* example parenting to an armature. */
-ModifierData *modifiers_getVirtualModifierList(const Object *ob,
- VirtualModifierData *virtualModifierData)
+ModifierData *BKE_modifiers_get_virtual_modifierlist(const Object *ob,
+ VirtualModifierData *virtualModifierData)
{
ModifierData *md;
@@ -661,10 +666,10 @@ ModifierData *modifiers_getVirtualModifierList(const Object *ob,
/* Takes an object and returns its first selected armature, else just its armature
* This should work for multiple armatures per object
*/
-Object *modifiers_isDeformedByArmature(Object *ob)
+Object *BKE_modifiers_is_deformed_by_armature(Object *ob)
{
VirtualModifierData virtualModifierData;
- ModifierData *md = modifiers_getVirtualModifierList(ob, &virtualModifierData);
+ ModifierData *md = BKE_modifiers_get_virtual_modifierlist(ob, &virtualModifierData);
ArmatureModifierData *amd = NULL;
/* return the first selected armature, this lets us use multiple armatures */
@@ -684,10 +689,10 @@ Object *modifiers_isDeformedByArmature(Object *ob)
return NULL;
}
-Object *modifiers_isDeformedByMeshDeform(Object *ob)
+Object *BKE_modifiers_is_deformed_by_meshdeform(Object *ob)
{
VirtualModifierData virtualModifierData;
- ModifierData *md = modifiers_getVirtualModifierList(ob, &virtualModifierData);
+ ModifierData *md = BKE_modifiers_get_virtual_modifierlist(ob, &virtualModifierData);
MeshDeformModifierData *mdmd = NULL;
/* return the first selected armature, this lets us use multiple armatures */
@@ -710,10 +715,10 @@ Object *modifiers_isDeformedByMeshDeform(Object *ob)
/* Takes an object and returns its first selected lattice, else just its lattice
* This should work for multiple lattices per object
*/
-Object *modifiers_isDeformedByLattice(Object *ob)
+Object *BKE_modifiers_is_deformed_by_lattice(Object *ob)
{
VirtualModifierData virtualModifierData;
- ModifierData *md = modifiers_getVirtualModifierList(ob, &virtualModifierData);
+ ModifierData *md = BKE_modifiers_get_virtual_modifierlist(ob, &virtualModifierData);
LatticeModifierData *lmd = NULL;
/* return the first selected lattice, this lets us use multiple lattices */
@@ -736,10 +741,10 @@ Object *modifiers_isDeformedByLattice(Object *ob)
/* Takes an object and returns its first selected curve, else just its curve
* This should work for multiple curves per object
*/
-Object *modifiers_isDeformedByCurve(Object *ob)
+Object *BKE_modifiers_is_deformed_by_curve(Object *ob)
{
VirtualModifierData virtualModifierData;
- ModifierData *md = modifiers_getVirtualModifierList(ob, &virtualModifierData);
+ ModifierData *md = BKE_modifiers_get_virtual_modifierlist(ob, &virtualModifierData);
CurveModifierData *cmd = NULL;
/* return the first selected curve, this lets us use multiple curves */
@@ -759,10 +764,10 @@ Object *modifiers_isDeformedByCurve(Object *ob)
return NULL;
}
-bool modifiers_usesMultires(Object *ob)
+bool BKE_modifiers_uses_multires(Object *ob)
{
VirtualModifierData virtualModifierData;
- ModifierData *md = modifiers_getVirtualModifierList(ob, &virtualModifierData);
+ ModifierData *md = BKE_modifiers_get_virtual_modifierlist(ob, &virtualModifierData);
MultiresModifierData *mmd = NULL;
for (; md; md = md->next) {
@@ -776,10 +781,10 @@ bool modifiers_usesMultires(Object *ob)
return false;
}
-bool modifiers_usesArmature(Object *ob, bArmature *arm)
+bool BKE_modifiers_uses_armature(Object *ob, bArmature *arm)
{
VirtualModifierData virtualModifierData;
- ModifierData *md = modifiers_getVirtualModifierList(ob, &virtualModifierData);
+ ModifierData *md = BKE_modifiers_get_virtual_modifierlist(ob, &virtualModifierData);
for (; md; md = md->next) {
if (md->type == eModifierType_Armature) {
@@ -793,13 +798,13 @@ bool modifiers_usesArmature(Object *ob, bArmature *arm)
return false;
}
-bool modifiers_usesSubsurfFacedots(struct Scene *scene, Object *ob)
+bool BKE_modifiers_uses_subsurf_facedots(struct Scene *scene, Object *ob)
{
/* Search (backward) in the modifier stack to find if we have a subsurf modifier (enabled) before
* the last modifier displayed on cage (or if the subsurf is the last). */
VirtualModifierData virtualModifierData;
- ModifierData *md = modifiers_getVirtualModifierList(ob, &virtualModifierData);
- int cage_index = modifiers_getCageIndex(scene, ob, NULL, 1);
+ ModifierData *md = BKE_modifiers_get_virtual_modifierlist(ob, &virtualModifierData);
+ int cage_index = BKE_modifiers_get_cage_index(scene, ob, NULL, 1);
if (cage_index == -1) {
return false;
}
@@ -809,10 +814,10 @@ bool modifiers_usesSubsurfFacedots(struct Scene *scene, Object *ob)
}
/* Now from this point, search for subsurf modifier. */
for (; md; md = md->prev) {
- const ModifierTypeInfo *mti = modifierType_getInfo(md->type);
+ const ModifierTypeInfo *mti = BKE_modifier_get_info(md->type);
if (md->type == eModifierType_Subsurf) {
ModifierMode mode = eModifierMode_Realtime | eModifierMode_Editmode;
- if (modifier_isEnabled(scene, md, mode)) {
+ if (BKE_modifier_is_enabled(scene, md, mode)) {
return true;
}
}
@@ -828,48 +833,33 @@ bool modifiers_usesSubsurfFacedots(struct Scene *scene, Object *ob)
return false;
}
-bool modifier_isCorrectableDeformed(ModifierData *md)
+bool BKE_modifier_is_correctable_deformed(ModifierData *md)
{
- const ModifierTypeInfo *mti = modifierType_getInfo(md->type);
+ const ModifierTypeInfo *mti = BKE_modifier_get_info(md->type);
return mti->deformMatricesEM != NULL;
}
-bool modifiers_isCorrectableDeformed(struct Scene *scene, Object *ob)
+bool BKE_modifiers_is_correctable_deformed(struct Scene *scene, Object *ob)
{
VirtualModifierData virtualModifierData;
- ModifierData *md = modifiers_getVirtualModifierList(ob, &virtualModifierData);
+ ModifierData *md = BKE_modifiers_get_virtual_modifierlist(ob, &virtualModifierData);
int required_mode = eModifierMode_Realtime;
if (ob->mode == OB_MODE_EDIT) {
required_mode |= eModifierMode_Editmode;
}
for (; md; md = md->next) {
- if (!modifier_isEnabled(scene, md, required_mode)) {
+ if (!BKE_modifier_is_enabled(scene, md, required_mode)) {
/* pass */
}
- else if (modifier_isCorrectableDeformed(md)) {
+ else if (BKE_modifier_is_correctable_deformed(md)) {
return true;
}
}
return false;
}
-/* Check whether the given object has a modifier in its stack that uses WEIGHT_MCOL CD layer
- * to preview something... Used by DynamicPaint and WeightVG currently. */
-bool modifiers_isPreview(Object *ob)
-{
- ModifierData *md = ob->modifiers.first;
-
- for (; md; md = md->next) {
- if (modifier_isPreview(md)) {
- return true;
- }
- }
-
- return false;
-}
-
-void modifier_freeTemporaryData(ModifierData *md)
+void BKE_modifier_free_temporary_data(ModifierData *md)
{
if (md->type == eModifierType_Armature) {
ArmatureModifierData *amd = (ArmatureModifierData *)md;
@@ -882,7 +872,7 @@ void modifier_freeTemporaryData(ModifierData *md)
}
/* ensure modifier correctness when changing ob->data */
-void test_object_modifiers(Object *ob)
+void BKE_modifiers_test_object(Object *ob)
{
ModifierData *md;
@@ -913,7 +903,7 @@ void test_object_modifiers(Object *ob)
* - else if the file has been saved return the blend file path.
* - else if the file isn't saved and the ID isn't from a library, return the temp dir.
*/
-const char *modifier_path_relbase(Main *bmain, Object *ob)
+const char *BKE_modifier_path_relbase(Main *bmain, Object *ob)
{
if (G.relbase_valid || ID_IS_LINKED(ob)) {
return ID_BLEND_PATH(bmain, &ob->id);
@@ -925,7 +915,7 @@ const char *modifier_path_relbase(Main *bmain, Object *ob)
}
}
-const char *modifier_path_relbase_from_global(Object *ob)
+const char *BKE_modifier_path_relbase_from_global(Object *ob)
{
if (G.relbase_valid || ID_IS_LINKED(ob)) {
return ID_BLEND_PATH_FROM_GLOBAL(&ob->id);
@@ -938,51 +928,81 @@ const char *modifier_path_relbase_from_global(Object *ob)
}
/* initializes the path with either */
-void modifier_path_init(char *path, int path_maxlen, const char *name)
+void BKE_modifier_path_init(char *path, int path_maxlen, const char *name)
{
/* elubie: changed this to default to the same dir as the render output
* to prevent saving to C:\ on Windows */
BLI_join_dirfile(path, path_maxlen, G.relbase_valid ? "//" : BKE_tempdir_session(), name);
}
-/* wrapper around ModifierTypeInfo.applyModifier that ensures valid normals */
+/**
+ * Call when #ModifierTypeInfo.dependsOnNormals callback requests normals.
+ */
+static void modwrap_dependsOnNormals(Mesh *me)
+{
+ switch ((eMeshWrapperType)me->runtime.wrapper_type) {
+ case ME_WRAPPER_TYPE_BMESH: {
+ EditMeshData *edit_data = me->runtime.edit_data;
+ if (edit_data->vertexCos) {
+ /* Note that 'ensure' is acceptable here since these values aren't modified in-place.
+ * If that changes we'll need to recalculate. */
+ BKE_editmesh_cache_ensure_vert_normals(me->edit_mesh, edit_data);
+ }
+ else {
+ BM_mesh_normals_update(me->edit_mesh->bm);
+ }
+ break;
+ }
+ case ME_WRAPPER_TYPE_MDATA:
+ BKE_mesh_calc_normals(me);
+ break;
+ }
+}
-struct Mesh *modwrap_applyModifier(ModifierData *md,
- const ModifierEvalContext *ctx,
- struct Mesh *me)
+/* wrapper around ModifierTypeInfo.modifyMesh that ensures valid normals */
+
+struct Mesh *BKE_modifier_modify_mesh(ModifierData *md,
+ const ModifierEvalContext *ctx,
+ struct Mesh *me)
{
- const ModifierTypeInfo *mti = modifierType_getInfo(md->type);
+ const ModifierTypeInfo *mti = BKE_modifier_get_info(md->type);
BLI_assert(CustomData_has_layer(&me->pdata, CD_NORMAL) == false);
+ if (me->runtime.wrapper_type == ME_WRAPPER_TYPE_BMESH) {
+ if ((mti->flags & eModifierTypeFlag_AcceptsBMesh) == 0) {
+ BKE_mesh_wrapper_ensure_mdata(me);
+ }
+ }
+
if (mti->dependsOnNormals && mti->dependsOnNormals(md)) {
- BKE_mesh_calc_normals(me);
+ modwrap_dependsOnNormals(me);
}
- return mti->applyModifier(md, ctx, me);
+ return mti->modifyMesh(md, ctx, me);
}
-void modwrap_deformVerts(ModifierData *md,
- const ModifierEvalContext *ctx,
- Mesh *me,
- float (*vertexCos)[3],
- int numVerts)
+void BKE_modifier_deform_verts(ModifierData *md,
+ const ModifierEvalContext *ctx,
+ Mesh *me,
+ float (*vertexCos)[3],
+ int numVerts)
{
- const ModifierTypeInfo *mti = modifierType_getInfo(md->type);
+ const ModifierTypeInfo *mti = BKE_modifier_get_info(md->type);
BLI_assert(!me || CustomData_has_layer(&me->pdata, CD_NORMAL) == false);
if (me && mti->dependsOnNormals && mti->dependsOnNormals(md)) {
- BKE_mesh_calc_normals(me);
+ modwrap_dependsOnNormals(me);
}
mti->deformVerts(md, ctx, me, vertexCos, numVerts);
}
-void modwrap_deformVertsEM(ModifierData *md,
- const ModifierEvalContext *ctx,
- struct BMEditMesh *em,
- Mesh *me,
- float (*vertexCos)[3],
- int numVerts)
+void BKE_modifier_deform_vertsEM(ModifierData *md,
+ const ModifierEvalContext *ctx,
+ struct BMEditMesh *em,
+ Mesh *me,
+ float (*vertexCos)[3],
+ int numVerts)
{
- const ModifierTypeInfo *mti = modifierType_getInfo(md->type);
+ const ModifierTypeInfo *mti = BKE_modifier_get_info(md->type);
BLI_assert(!me || CustomData_has_layer(&me->pdata, CD_NORMAL) == false);
if (me && mti->dependsOnNormals && mti->dependsOnNormals(md)) {
@@ -1025,7 +1045,7 @@ Mesh *BKE_modifier_get_evaluated_mesh_from_evaluated_object(Object *ob_eval,
return me;
}
-ModifierData *modifier_get_original(ModifierData *md)
+ModifierData *BKE_modifier_get_original(ModifierData *md)
{
if (md->orig_modifier_data == NULL) {
return md;
@@ -1033,11 +1053,13 @@ ModifierData *modifier_get_original(ModifierData *md)
return md->orig_modifier_data;
}
-struct ModifierData *modifier_get_evaluated(Depsgraph *depsgraph, Object *object, ModifierData *md)
+struct ModifierData *BKE_modifier_get_evaluated(Depsgraph *depsgraph,
+ Object *object,
+ ModifierData *md)
{
Object *object_eval = DEG_get_evaluated_object(depsgraph, object);
if (object_eval == object) {
return md;
}
- return modifiers_findByName(object_eval, md->name);
+ return BKE_modifiers_findby_name(object_eval, md->name);
}
diff --git a/source/blender/blenkernel/intern/movieclip.c b/source/blender/blenkernel/intern/movieclip.c
index 1935dc0cf6f..fe7c2055aef 100644
--- a/source/blender/blenkernel/intern/movieclip.c
+++ b/source/blender/blenkernel/intern/movieclip.c
@@ -36,6 +36,7 @@
#include "MEM_guardedalloc.h"
#include "DNA_constraint_types.h"
+#include "DNA_gpencil_types.h"
#include "DNA_movieclip_types.h"
#include "DNA_node_types.h"
#include "DNA_object_types.h"
@@ -53,12 +54,12 @@
#include "BLT_translation.h"
-#include "BKE_animsys.h"
#include "BKE_colortools.h"
#include "BKE_global.h"
#include "BKE_idtype.h"
#include "BKE_image.h" /* openanim */
#include "BKE_lib_id.h"
+#include "BKE_lib_query.h"
#include "BKE_main.h"
#include "BKE_movieclip.h"
#include "BKE_node.h"
@@ -107,6 +108,27 @@ static void movie_clip_free_data(ID *id)
BKE_tracking_free(&movie_clip->tracking);
}
+static void movie_clip_foreach_id(ID *id, LibraryForeachIDData *data)
+{
+ MovieClip *movie_clip = (MovieClip *)id;
+ MovieTracking *tracking = &movie_clip->tracking;
+
+ BKE_LIB_FOREACHID_PROCESS(data, movie_clip->gpd, IDWALK_CB_USER);
+
+ LISTBASE_FOREACH (MovieTrackingTrack *, track, &tracking->tracks) {
+ BKE_LIB_FOREACHID_PROCESS(data, track->gpd, IDWALK_CB_USER);
+ }
+ LISTBASE_FOREACH (MovieTrackingObject *, object, &tracking->objects) {
+ LISTBASE_FOREACH (MovieTrackingTrack *, track, &object->tracks) {
+ BKE_LIB_FOREACHID_PROCESS(data, track->gpd, IDWALK_CB_USER);
+ }
+ }
+
+ LISTBASE_FOREACH (MovieTrackingPlaneTrack *, plane_track, &tracking->plane_tracks) {
+ BKE_LIB_FOREACHID_PROCESS(data, plane_track->image, IDWALK_CB_USER);
+ }
+}
+
IDTypeInfo IDType_ID_MC = {
.id_code = ID_MC,
.id_filter = FILTER_ID_MC,
@@ -121,6 +143,7 @@ IDTypeInfo IDType_ID_MC = {
.copy_data = movie_clip_copy_data,
.free_data = movie_clip_free_data,
.make_local = NULL,
+ .foreach_id = movie_clip_foreach_id,
};
/*********************** movieclip buffer loaders *************************/
@@ -198,14 +221,14 @@ static void get_sequence_fname(const MovieClip *clip, const int framenr, char *n
int offset;
BLI_strncpy(name, clip->name, sizeof(clip->name));
- BLI_stringdec(name, head, tail, &numlen);
+ BLI_path_sequence_decode(name, head, tail, &numlen);
/* Movie-clips always points to first image from sequence, auto-guess offset for now.
* Could be something smarter in the future. */
offset = sequence_guess_offset(clip->name, strlen(head), numlen);
if (numlen) {
- BLI_stringenc(
+ BLI_path_sequence_encode(
name, head, tail, numlen, offset + framenr - clip->start_frame + clip->frame_offset);
}
else {
@@ -422,7 +445,7 @@ static void movieclip_calc_length(MovieClip *clip)
unsigned short numlen;
char name[FILE_MAX], head[FILE_MAX], tail[FILE_MAX];
- BLI_stringdec(clip->name, head, tail, &numlen);
+ BLI_path_sequence_decode(clip->name, head, tail, &numlen);
if (numlen == 0) {
/* there's no number group in file name, assume it's single framed sequence */
@@ -457,9 +480,11 @@ typedef struct MovieClipCache {
int flag;
/* cache for undistorted shot */
+ float focal_length;
float principal[2];
- float polynomial_k1;
- float division_k1;
+ float polynomial_k[3];
+ float division_k[2];
+ float nuke_k[2];
short distortion_model;
bool undistortion_used;
@@ -506,7 +531,7 @@ static int user_frame_to_cache_frame(MovieClip *clip, int framenr)
unsigned short numlen;
char head[FILE_MAX], tail[FILE_MAX];
- BLI_stringdec(clip->name, head, tail, &numlen);
+ BLI_path_sequence_decode(clip->name, head, tail, &numlen);
/* see comment in get_sequence_fname */
clip->cache->sequence_offset = sequence_guess_offset(clip->name, strlen(head), numlen);
@@ -649,7 +674,7 @@ static bool put_imbuf_cache(
clip->cache->sequence_offset = -1;
if (clip->source == MCLIP_SRC_SEQUENCE) {
unsigned short numlen;
- BLI_stringdec(clip->name, NULL, NULL, &numlen);
+ BLI_path_sequence_decode(clip->name, NULL, NULL, &numlen);
clip->cache->is_still_sequence = (numlen == 0);
}
}
@@ -888,6 +913,10 @@ static bool check_undistortion_cache_flags(const MovieClip *clip)
const MovieClipCache *cache = clip->cache;
const MovieTrackingCamera *camera = &clip->tracking.camera;
+ if (camera->focal != cache->postprocessed.focal_length) {
+ return false;
+ }
+
/* check for distortion model changes */
if (!equals_v2v2(camera->principal, cache->postprocessed.principal)) {
return false;
@@ -897,11 +926,14 @@ static bool check_undistortion_cache_flags(const MovieClip *clip)
return false;
}
- if (!equals_v3v3(&camera->k1, &cache->postprocessed.polynomial_k1)) {
+ if (!equals_v3v3(&camera->k1, cache->postprocessed.polynomial_k)) {
return false;
}
- if (!equals_v2v2(&camera->division_k1, &cache->postprocessed.division_k1)) {
+ if (!equals_v2v2(&camera->division_k1, cache->postprocessed.division_k)) {
+ return false;
+ }
+ if (!equals_v2v2(&camera->nuke_k1, cache->postprocessed.nuke_k)) {
return false;
}
@@ -1002,9 +1034,11 @@ static void put_postprocessed_frame_to_cache(
if (need_undistortion_postprocess(user, flag)) {
cache->postprocessed.distortion_model = camera->distortion_model;
+ cache->postprocessed.focal_length = camera->focal;
copy_v2_v2(cache->postprocessed.principal, camera->principal);
- copy_v3_v3(&cache->postprocessed.polynomial_k1, &camera->k1);
- copy_v2_v2(&cache->postprocessed.division_k1, &camera->division_k1);
+ copy_v3_v3(cache->postprocessed.polynomial_k, &camera->k1);
+ copy_v2_v2(cache->postprocessed.division_k, &camera->division_k1);
+ copy_v2_v2(cache->postprocessed.nuke_k, &camera->nuke_k1);
cache->postprocessed.undistortion_used = true;
}
else {
@@ -1507,7 +1541,8 @@ void BKE_movieclip_update_scopes(MovieClip *clip, MovieClipUser *user, MovieClip
undist_marker.pos[0] *= width;
undist_marker.pos[1] *= height * aspy;
- BKE_tracking_undistort_v2(&clip->tracking, undist_marker.pos, undist_marker.pos);
+ BKE_tracking_undistort_v2(
+ &clip->tracking, width, height, undist_marker.pos, undist_marker.pos);
undist_marker.pos[0] /= width;
undist_marker.pos[1] /= height * aspy;
@@ -1744,7 +1779,7 @@ bool BKE_movieclip_put_frame_if_possible(MovieClip *clip, MovieClipUser *user, I
return result;
}
-static void movieclip_selection_synchronize(MovieClip *clip_dst, const MovieClip *clip_src)
+static void movieclip_selection_sync(MovieClip *clip_dst, const MovieClip *clip_src)
{
BLI_assert(clip_dst != clip_src);
MovieTracking *tracking_dst = &clip_dst->tracking, tracking_src = clip_src->tracking;
@@ -1811,5 +1846,5 @@ void BKE_movieclip_eval_update(struct Depsgraph *depsgraph, Main *bmain, MovieCl
void BKE_movieclip_eval_selection_update(struct Depsgraph *depsgraph, MovieClip *clip)
{
DEG_debug_print_eval(depsgraph, __func__, clip->id.name, clip);
- movieclip_selection_synchronize(clip, (MovieClip *)clip->id.orig_id);
+ movieclip_selection_sync(clip, (MovieClip *)clip->id.orig_id);
}
diff --git a/source/blender/blenkernel/intern/multires.c b/source/blender/blenkernel/intern/multires.c
index b40dfcd3b7f..7e78be6d66e 100644
--- a/source/blender/blenkernel/intern/multires.c
+++ b/source/blender/blenkernel/intern/multires.c
@@ -10,7 +10,7 @@
* 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,
+ * 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) 2007 by Nicholas Bishop
@@ -289,8 +289,8 @@ Mesh *BKE_multires_create_mesh(struct Depsgraph *depsgraph,
.flag = MOD_APPLY_USECACHE | MOD_APPLY_IGNORE_SIMPLIFY,
};
- const ModifierTypeInfo *mti = modifierType_getInfo(mmd->modifier.type);
- Mesh *result = mti->applyModifier(&mmd->modifier, &modifier_ctx, deformed_mesh);
+ const ModifierTypeInfo *mti = BKE_modifier_get_info(mmd->modifier.type);
+ Mesh *result = mti->modifyMesh(&mmd->modifier, &modifier_ctx, deformed_mesh);
if (result == deformed_mesh) {
result = BKE_mesh_copy_for_eval(deformed_mesh, true);
@@ -308,6 +308,7 @@ float (*BKE_multires_create_deformed_base_mesh_vert_coords(struct Depsgraph *dep
Object object_for_eval = *object_eval;
object_for_eval.data = object->data;
+ object_for_eval.sculpt = NULL;
const bool use_render = (DEG_get_mode(depsgraph) == DAG_EVAL_RENDER);
ModifierEvalContext mesh_eval_context = {depsgraph, &object_for_eval, 0};
@@ -317,8 +318,8 @@ float (*BKE_multires_create_deformed_base_mesh_vert_coords(struct Depsgraph *dep
const int required_mode = use_render ? eModifierMode_Render : eModifierMode_Realtime;
VirtualModifierData virtual_modifier_data;
- ModifierData *first_md = modifiers_getVirtualModifierList(&object_for_eval,
- &virtual_modifier_data);
+ ModifierData *first_md = BKE_modifiers_get_virtual_modifierlist(&object_for_eval,
+ &virtual_modifier_data);
Mesh *base_mesh = object->data;
@@ -326,13 +327,13 @@ float (*BKE_multires_create_deformed_base_mesh_vert_coords(struct Depsgraph *dep
float(*deformed_verts)[3] = BKE_mesh_vert_coords_alloc(base_mesh, &num_deformed_verts);
for (ModifierData *md = first_md; md != NULL; md = md->next) {
- const ModifierTypeInfo *mti = modifierType_getInfo(md->type);
+ const ModifierTypeInfo *mti = BKE_modifier_get_info(md->type);
if (md == &mmd->modifier) {
break;
}
- if (!modifier_isEnabled(scene_eval, md, required_mode)) {
+ if (!BKE_modifier_is_enabled(scene_eval, md, required_mode)) {
continue;
}
@@ -340,7 +341,8 @@ float (*BKE_multires_create_deformed_base_mesh_vert_coords(struct Depsgraph *dep
break;
}
- modwrap_deformVerts(md, &mesh_eval_context, base_mesh, deformed_verts, num_deformed_verts);
+ BKE_modifier_deform_verts(
+ md, &mesh_eval_context, base_mesh, deformed_verts, num_deformed_verts);
}
if (r_num_deformed_verts != NULL) {
@@ -355,7 +357,7 @@ MultiresModifierData *find_multires_modifier_before(Scene *scene, ModifierData *
for (md = lastmd; md; md = md->prev) {
if (md->type == eModifierType_Multires) {
- if (modifier_isEnabled(scene, md, eModifierMode_Realtime)) {
+ if (BKE_modifier_is_enabled(scene, md, eModifierMode_Realtime)) {
return (MultiresModifierData *)md;
}
}
@@ -379,7 +381,7 @@ MultiresModifierData *get_multires_modifier(Scene *scene, Object *ob, bool use_f
firstmmd = (MultiresModifierData *)md;
}
- if (modifier_isEnabled(scene, md, eModifierMode_Realtime)) {
+ if (BKE_modifier_is_enabled(scene, md, eModifierMode_Realtime)) {
mmd = (MultiresModifierData *)md;
break;
}
@@ -406,7 +408,7 @@ int multires_get_level(const Scene *scene,
mmd->renderlvl;
}
else if (ob->mode == OB_MODE_SCULPT) {
- return BKE_multires_sculpt_level_get(mmd);
+ return mmd->sculptlvl;
}
else if (ignore_simplify) {
return mmd->lvl;
@@ -472,7 +474,8 @@ void multires_flush_sculpt_updates(Object *object)
}
SculptSession *sculpt_session = object->sculpt;
- if (BKE_pbvh_type(sculpt_session->pbvh) != PBVH_GRIDS || sculpt_session->multires == NULL) {
+ if (BKE_pbvh_type(sculpt_session->pbvh) != PBVH_GRIDS || !sculpt_session->multires.active ||
+ sculpt_session->multires.modifier == NULL) {
return;
}
@@ -487,7 +490,7 @@ void multires_flush_sculpt_updates(Object *object)
Mesh *mesh = object->data;
multiresModifier_reshapeFromCCG(
- sculpt_session->multires->totlvl, mesh, sculpt_session->subdiv_ccg);
+ sculpt_session->multires.modifier->totlvl, mesh, sculpt_session->subdiv_ccg);
subdiv_ccg->dirty.coords = false;
subdiv_ccg->dirty.hidden = false;
@@ -2191,10 +2194,10 @@ void multires_load_old(Object *ob, Mesh *me)
/* Add a multires modifier to the object */
md = ob->modifiers.first;
- while (md && modifierType_getInfo(md->type)->type == eModifierTypeType_OnlyDeform) {
+ while (md && BKE_modifier_get_info(md->type)->type == eModifierTypeType_OnlyDeform) {
md = md->next;
}
- mmd = (MultiresModifierData *)modifier_new(eModifierType_Multires);
+ mmd = (MultiresModifierData *)BKE_modifier_new(eModifierType_Multires);
BLI_insertlinkbefore(&ob->modifiers, md, mmd);
for (i = 0; i < me->mr->level_count - 1; i++) {
@@ -2232,7 +2235,14 @@ void multiresModifier_sync_levels_ex(Object *ob_dst,
}
if (mmd_src->totlvl > mmd_dst->totlvl) {
- multiresModifier_subdivide_to_level(ob_dst, mmd_dst, mmd_src->totlvl);
+ if (mmd_dst->simple) {
+ multiresModifier_subdivide_to_level(
+ ob_dst, mmd_dst, mmd_src->totlvl, MULTIRES_SUBDIVIDE_SIMPLE);
+ }
+ else {
+ multiresModifier_subdivide_to_level(
+ ob_dst, mmd_dst, mmd_src->totlvl, MULTIRES_SUBDIVIDE_CATMULL_CLARK);
+ }
}
else {
multires_del_higher(mmd_dst, ob_dst, mmd_src->totlvl);
@@ -2514,12 +2524,3 @@ int mdisp_rot_face_to_crn(struct MVert *UNUSED(mvert),
return S;
}
-
-/* This is a workaround for T58473.
- * Force sculpting on the highest level for until the root of the issue is solved.
- *
- * When that issue is solved simple replace call of this function with mmd->sculptlvl. */
-int BKE_multires_sculpt_level_get(const struct MultiresModifierData *mmd)
-{
- return mmd->totlvl;
-}
diff --git a/source/blender/blenkernel/intern/multires_reshape.c b/source/blender/blenkernel/intern/multires_reshape.c
index 8674f5d2dbf..64cc9130e25 100644
--- a/source/blender/blenkernel/intern/multires_reshape.c
+++ b/source/blender/blenkernel/intern/multires_reshape.c
@@ -10,7 +10,7 @@
* 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,
+ * along with this program; if not, write to the Free Software Foundation,
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*
* The Original Code is Copyright (C) 2020 Blender Foundation.
@@ -28,8 +28,6 @@
#include "DNA_modifier_types.h"
#include "DNA_scene_types.h"
-#include "BLI_math_vector.h"
-
#include "BKE_customdata.h"
#include "BKE_lib_id.h"
#include "BKE_mesh.h"
@@ -37,14 +35,16 @@
#include "BKE_modifier.h"
#include "BKE_multires.h"
#include "BKE_subdiv.h"
+#include "BKE_subsurf.h"
+#include "BLI_math_vector.h"
#include "DEG_depsgraph_query.h"
#include "multires_reshape.h"
-/* ================================================================================================
- * Reshape from object.
- */
+/* -------------------------------------------------------------------- */
+/** \name Reshape from object
+ * \{ */
bool multiresModifier_reshapeFromVertcos(struct Depsgraph *depsgraph,
struct Object *object,
@@ -93,9 +93,11 @@ bool multiresModifier_reshapeFromObject(struct Depsgraph *depsgraph,
return result;
}
-/* ================================================================================================
- * Reshape from modifier.
- */
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Reshape from modifier
+ * \{ */
bool multiresModifier_reshapeFromDeformModifier(struct Depsgraph *depsgraph,
struct Object *object,
@@ -119,7 +121,7 @@ bool multiresModifier_reshapeFromDeformModifier(struct Depsgraph *depsgraph,
.object = object,
.flag = MOD_APPLY_USECACHE | MOD_APPLY_IGNORE_SIMPLIFY,
};
- modwrap_deformVerts(
+ BKE_modifier_deform_verts(
deform_md, &modifier_ctx, multires_mesh, deformed_verts, multires_mesh->totvert);
BKE_id_free(NULL, multires_mesh);
@@ -133,9 +135,11 @@ bool multiresModifier_reshapeFromDeformModifier(struct Depsgraph *depsgraph,
return result;
}
-/* ================================================================================================
- * Reshape from grids.
- */
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Reshape from grids
+ * \{ */
bool multiresModifier_reshapeFromCCG(const int tot_level,
Mesh *coarse_mesh,
@@ -161,19 +165,24 @@ bool multiresModifier_reshapeFromCCG(const int tot_level,
return true;
}
-/* ================================================================================================
- * Subdivision.
- */
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Subdivision
+ * \{ */
-void multiresModifier_subdivide(Object *object, MultiresModifierData *mmd)
+void multiresModifier_subdivide(Object *object,
+ MultiresModifierData *mmd,
+ const eMultiresSubdivideModeType mode)
{
const int top_level = mmd->totlvl + 1;
- multiresModifier_subdivide_to_level(object, mmd, top_level);
+ multiresModifier_subdivide_to_level(object, mmd, top_level, mode);
}
void multiresModifier_subdivide_to_level(struct Object *object,
struct MultiresModifierData *mmd,
- const int top_level)
+ const int top_level,
+ const eMultiresSubdivideModeType mode)
{
if (top_level <= mmd->totlvl) {
return;
@@ -188,9 +197,23 @@ void multiresModifier_subdivide_to_level(struct Object *object,
if (!has_mdisps) {
CustomData_add_layer(&coarse_mesh->ldata, CD_MDISPS, CD_CALLOC, NULL, coarse_mesh->totloop);
}
- if (!has_mdisps || top_level == 1) {
+
+ /* NOTE: Subdivision happens from the top level of the existing multires modifier. If it is set
+ * to 0 and there is mdisps layer it would mean that the modifier went out of sync with the data.
+ * This happens when, for example, linking modifiers from one object to another.
+ *
+ * In such cases simply ensure grids to be the proper level.
+ *
+ * If something smarter is needed it is up to the operators which does data synchronization, so
+ * that the mdisps layer is also synchronized. */
+ if (!has_mdisps || top_level == 1 || mmd->totlvl == 0) {
multires_reshape_ensure_grids(coarse_mesh, top_level);
- multires_set_tot_level(object, mmd, top_level);
+ if (ELEM(mode, MULTIRES_SUBDIVIDE_LINEAR, MULTIRES_SUBDIVIDE_SIMPLE)) {
+ multires_subdivide_create_tangent_displacement_linear_grids(object, mmd);
+ }
+ else {
+ multires_set_tot_level(object, mmd, top_level);
+ }
return;
}
@@ -199,19 +222,34 @@ void multiresModifier_subdivide_to_level(struct Object *object,
if (!multires_reshape_context_create_from_subdivide(&reshape_context, object, mmd, top_level)) {
return;
}
+
multires_reshape_store_original_grids(&reshape_context);
multires_reshape_ensure_grids(coarse_mesh, reshape_context.top.level);
- multires_reshape_assign_final_coords_from_orig_mdisps(&reshape_context);
- multires_reshape_smooth_object_grids(&reshape_context);
+ multires_reshape_assign_final_elements_from_orig_mdisps(&reshape_context);
+
+ /* Free original grids which makes it so smoothing with details thinks all the details were
+ * added against base mesh's limit surface. This is similar behavior to as if we've done all
+ * displacement in sculpt mode at the old top level and then propagated to the new top level.*/
+ multires_reshape_free_original_grids(&reshape_context);
+
+ if (ELEM(mode, MULTIRES_SUBDIVIDE_LINEAR, MULTIRES_SUBDIVIDE_SIMPLE)) {
+ multires_reshape_smooth_object_grids(&reshape_context, mode);
+ }
+ else {
+ multires_reshape_smooth_object_grids_with_details(&reshape_context);
+ }
+
multires_reshape_object_grids_to_tangent_displacement(&reshape_context);
multires_reshape_context_free(&reshape_context);
multires_set_tot_level(object, mmd, top_level);
}
-/* ================================================================================================
- * Apply base.
- */
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Apply base
+ * \{ */
void multiresModifier_base_apply(struct Depsgraph *depsgraph,
Object *object,
@@ -257,3 +295,5 @@ void multiresModifier_base_apply(struct Depsgraph *depsgraph,
multires_reshape_context_free(&reshape_context);
}
+
+/** \} */
diff --git a/source/blender/blenkernel/intern/multires_reshape.h b/source/blender/blenkernel/intern/multires_reshape.h
index 79d3c48869f..12816a455ee 100644
--- a/source/blender/blenkernel/intern/multires_reshape.h
+++ b/source/blender/blenkernel/intern/multires_reshape.h
@@ -10,7 +10,7 @@
* 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,
+ * along with this program; if not, write to the Free Software Foundation,
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*
* The Original Code is Copyright (C) 2020 Blender Foundation.
@@ -26,6 +26,8 @@
#include "BLI_sys_types.h"
+#include "BKE_multires.h"
+
struct Depsgraph;
struct GridPaintMask;
struct MDisps;
@@ -138,7 +140,7 @@ typedef struct ReshapeConstGridElement {
float mask;
} ReshapeConstGridElement;
-/* ================================================================================================
+/* --------------------------------------------------------------------
* Construct/destruct reshape context.
*/
@@ -156,6 +158,11 @@ bool multires_reshape_context_create_from_object(MultiresReshapeContext *reshape
struct Object *object,
struct MultiresModifierData *mmd);
+bool multires_reshape_context_create_from_base_mesh(MultiresReshapeContext *reshape_context,
+ struct Depsgraph *depsgraph,
+ struct Object *object,
+ struct MultiresModifierData *mmd);
+
bool multires_reshape_context_create_from_ccg(MultiresReshapeContext *reshape_context,
struct SubdivCCG *subdiv_ccg,
struct Mesh *base_mesh,
@@ -166,9 +173,10 @@ bool multires_reshape_context_create_from_subdivide(MultiresReshapeContext *resh
struct MultiresModifierData *mmd,
int top_level);
+void multires_reshape_free_original_grids(MultiresReshapeContext *reshape_context);
void multires_reshape_context_free(MultiresReshapeContext *reshape_context);
-/* ================================================================================================
+/* --------------------------------------------------------------------
* Helper accessors.
*/
@@ -213,7 +221,7 @@ ReshapeGridElement multires_reshape_grid_element_for_ptex_coord(
ReshapeConstGridElement multires_reshape_orig_grid_element_for_grid_coord(
const MultiresReshapeContext *reshape_context, const GridCoord *grid_coord);
-/* ================================================================================================
+/* --------------------------------------------------------------------
* Sample limit surface of the base mesh.
*/
@@ -224,14 +232,14 @@ void multires_reshape_evaluate_limit_at_grid(const MultiresReshapeContext *resha
float r_P[3],
float r_tangent_matrix[3][3]);
-/* ================================================================================================
+/* --------------------------------------------------------------------
* Custom data preparation.
*/
/* Make sure custom data is allocated for the given level. */
void multires_reshape_ensure_grids(struct Mesh *mesh, const int level);
-/* ================================================================================================
+/* --------------------------------------------------------------------
* Functions specific to reshaping from a set of vertices in a object position.
*/
@@ -244,17 +252,21 @@ bool multires_reshape_assign_final_coords_from_vertcos(
const float (*vert_coords)[3],
const int num_vert_coords);
-/* ================================================================================================
+/* --------------------------------------------------------------------
* Functions specific to reshaping from CCG.
*/
-/* NOTE: Displacement grids to be at least at a reshape level.
+/* Store final object-space coordinates in the displacement grids.
+ * The reason why displacement grids are used for storage is based on memory
+ * footprint optimization.
+ *
+ * NOTE: Displacement grids to be at least at a reshape level.
*
* Return truth if all coordinates have been updated. */
bool multires_reshape_assign_final_coords_from_ccg(const MultiresReshapeContext *reshape_context,
struct SubdivCCG *subdiv_ccg);
-/* ================================================================================================
+/* --------------------------------------------------------------------
* Functions specific to reshaping from MDISPS.
*/
@@ -263,10 +275,10 @@ void multires_reshape_assign_final_coords_from_mdisps(
const MultiresReshapeContext *reshape_context);
/* Reads from original CD_MIDTSPS, writes to the current mesh CD_MDISPS. */
-void multires_reshape_assign_final_coords_from_orig_mdisps(
+void multires_reshape_assign_final_elements_from_orig_mdisps(
const MultiresReshapeContext *reshape_context);
-/* ================================================================================================
+/* --------------------------------------------------------------------
* Displacement smooth.
*/
@@ -283,9 +295,10 @@ void multires_reshape_smooth_object_grids_with_details(
*
* Makes it so surface on top level looks smooth. Details are not preserved
*/
-void multires_reshape_smooth_object_grids(const MultiresReshapeContext *reshape_context);
+void multires_reshape_smooth_object_grids(const MultiresReshapeContext *reshape_context,
+ const enum eMultiresSubdivideModeType mode);
-/* ================================================================================================
+/* --------------------------------------------------------------------
* Displacement, space conversion.
*/
@@ -296,7 +309,7 @@ void multires_reshape_store_original_grids(MultiresReshapeContext *reshape_conte
void multires_reshape_object_grids_to_tangent_displacement(
const MultiresReshapeContext *reshape_context);
-/* ================================================================================================
+/* --------------------------------------------------------------------
* Apply base.
*/
@@ -318,5 +331,4 @@ void multires_reshape_apply_base_refine_from_base(MultiresReshapeContext *reshap
*
* NOTE: Will re-evaluate all leading modifiers, so it's not cheap. */
void multires_reshape_apply_base_refine_from_deform(MultiresReshapeContext *reshape_context);
-
#endif /* __BKE_INTERN_MULTIRES_RESHAPE_H__ */
diff --git a/source/blender/blenkernel/intern/multires_reshape_apply_base.c b/source/blender/blenkernel/intern/multires_reshape_apply_base.c
index d480c46f2d0..105e56e4219 100644
--- a/source/blender/blenkernel/intern/multires_reshape_apply_base.c
+++ b/source/blender/blenkernel/intern/multires_reshape_apply_base.c
@@ -10,7 +10,7 @@
* 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,
+ * along with this program; if not, write to the Free Software Foundation,
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*
* The Original Code is Copyright (C) 2020 Blender Foundation.
@@ -81,6 +81,11 @@ static float v3_dist_from_plane(float v[3], float center[3], float no[3])
void multires_reshape_apply_base_refit_base_mesh(MultiresReshapeContext *reshape_context)
{
+ if (reshape_context->mmd->simple) {
+ /* Simple subdivisions does not move base mesh verticies, so no refitting is needed. */
+ return;
+ }
+
Mesh *base_mesh = reshape_context->base_mesh;
MeshElemMap *pmap;
@@ -177,7 +182,7 @@ void multires_reshape_apply_base_refit_base_mesh(MultiresReshapeContext *reshape
void multires_reshape_apply_base_refine_from_base(MultiresReshapeContext *reshape_context)
{
- BKE_subdiv_eval_update_from_mesh(reshape_context->subdiv, reshape_context->base_mesh, NULL);
+ BKE_subdiv_eval_refine_from_mesh(reshape_context->subdiv, reshape_context->base_mesh, NULL);
}
void multires_reshape_apply_base_refine_from_deform(MultiresReshapeContext *reshape_context)
@@ -192,7 +197,7 @@ void multires_reshape_apply_base_refine_from_deform(MultiresReshapeContext *resh
float(*deformed_verts)[3] = BKE_multires_create_deformed_base_mesh_vert_coords(
depsgraph, object, mmd, NULL);
- BKE_subdiv_eval_update_from_mesh(
+ BKE_subdiv_eval_refine_from_mesh(
reshape_context->subdiv, reshape_context->base_mesh, deformed_verts);
MEM_freeN(deformed_verts);
diff --git a/source/blender/blenkernel/intern/multires_reshape_ccg.c b/source/blender/blenkernel/intern/multires_reshape_ccg.c
index 1f8c782ed46..8273845e820 100644
--- a/source/blender/blenkernel/intern/multires_reshape_ccg.c
+++ b/source/blender/blenkernel/intern/multires_reshape_ccg.c
@@ -10,7 +10,7 @@
* 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,
+ * along with this program; if not, write to the Free Software Foundation,
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*
* The Original Code is Copyright (C) 2020 Blender Foundation.
diff --git a/source/blender/blenkernel/intern/multires_reshape_smooth.c b/source/blender/blenkernel/intern/multires_reshape_smooth.c
index 8b10d729901..3564ae80d24 100644
--- a/source/blender/blenkernel/intern/multires_reshape_smooth.c
+++ b/source/blender/blenkernel/intern/multires_reshape_smooth.c
@@ -10,7 +10,7 @@
* 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,
+ * along with this program; if not, write to the Free Software Foundation,
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*
* The Original Code is Copyright (C) 2020 Blender Foundation.
@@ -48,6 +48,15 @@
#include "atomic_ops.h"
#include "subdiv_converter.h"
+/* -------------------------------------------------------------------- */
+/** \name Local Structs
+ * \{ */
+
+/* Surface refers to a simplified and lower-memory footprint representation of the limit surface.
+ *
+ * Used to store pre-calculated information which is expensive or impossible to evaluate when
+ * traversing the final limit surface. */
+
typedef struct SurfacePoint {
float P[3];
float tangent_matrix[3][3];
@@ -57,6 +66,9 @@ typedef struct SurfaceGrid {
SurfacePoint *points;
} SurfaceGrid;
+/* Geometry elements which are used to simplify creation of topology refiner at the sculpt level.
+ * Contains a limited subset of information needed to construct topology refiner. */
+
typedef struct Vertex {
/* All grid coordinates which the vertex corresponding to.
* For a vertices which are created from inner points of grids there is always one coordinate. */
@@ -83,6 +95,32 @@ typedef struct Edge {
float sharpness;
} Edge;
+/* Storage of data which is linearly interpolated from the reshape level to the top level. */
+
+typedef struct LinearGridElement {
+ float mask;
+} LinearGridElement;
+
+typedef struct LinearGrid {
+ LinearGridElement *elements;
+} LinearGrid;
+
+typedef struct LinearGrids {
+ int num_grids;
+ int level;
+
+ /* Cached size for the grid, for faster lookup. */
+ int grid_size;
+
+ /* Indexed by grid index. */
+ LinearGrid *grids;
+
+ /* Elements for all grids are allocated in a single array, for the allocation performance. */
+ LinearGridElement *elements_storage;
+} LinearGrids;
+
+/* Context which holds all information eeded during propagation and smoothing. */
+
typedef struct MultiresReshapeSmoothContext {
const MultiresReshapeContext *reshape_context;
@@ -108,66 +146,118 @@ typedef struct MultiresReshapeSmoothContext {
Face *faces;
} geometry;
+ /* Grids of data which is linearly interpolated between grid elements at the reshape level.
+ * The data is actually stored as a delta, which is then to be added to the higher levels. */
+ LinearGrids linear_delta_grids;
+
/* Index i of this map indicates that base edge i is adjacent to at least one face. */
BLI_bitmap *non_loose_base_edge_map;
/* Subdivision surface created for geometry at a reshape level. */
Subdiv *reshape_subdiv;
+ /* Limit surface of the base mesh with original sculpt level details on it, subdivided up to the
+ * top level.
+ * Is used as a base point to calculate how much displacement has been made in the sculpt mode.
+ *
+ * NOTE: Referring to sculpt as it is the main user of this functionality and it is clear to
+ * understand what it actually means in a concrete example. This is a generic code which is also
+ * used by Subdivide operation, but the idea is exactly the same as propagation in the sculpt
+ * mode. */
SurfaceGrid *base_surface_grids;
+
+ /* Defines how displacement is interpolated on the higher levels (for example, whether
+ * displacement is smoothed in Catmull-Clark mode or interpolated linearly preserving sharp edges
+ * of the current sculpt level).
+ *
+ * NOTE: Uses same enumerator type as Subdivide operator, since the values are the same and
+ * decoupling type just adds extra headache to convert one enumerator to another. */
+ eMultiresSubdivideModeType smoothing_type;
} MultiresReshapeSmoothContext;
-/* ================================================================================================
- * Masks.
- */
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Linear grids manipulation
+ * \{ */
-/* Interpolate mask grid at a reshape level.
- * Will return 0 if there is no masks custom data layer. */
-static float interpolate_masks_grid(const MultiresReshapeSmoothContext *reshape_smooth_context,
- const GridCoord *grid_coord)
+static void linear_grids_init(LinearGrids *linear_grids)
{
- const MultiresReshapeContext *reshape_context = reshape_smooth_context->reshape_context;
- if (reshape_context->grid_paint_masks == NULL) {
- return 0.0f;
- }
+ linear_grids->num_grids = 0;
+ linear_grids->level = 0;
- const GridPaintMask *grid = &reshape_context->orig.grid_paint_masks[grid_coord->grid_index];
- const int grid_size = BKE_subdiv_grid_size_from_level(grid->level);
- const int grid_size_1 = grid_size - 1;
- const float grid_size_1_inv = 1.0f / (float)(grid_size_1);
+ linear_grids->grids = NULL;
+ linear_grids->elements_storage = NULL;
+}
- const float x_f = grid_coord->u * grid_size_1;
- const float y_f = grid_coord->v * grid_size_1;
+static void linear_grids_allocate(LinearGrids *linear_grids, int num_grids, int level)
+{
+ const size_t grid_size = BKE_subdiv_grid_size_from_level(level);
+ const size_t grid_area = grid_size * grid_size;
+ const size_t num_grid_elements = num_grids * grid_area;
- const int x_i = x_f;
- const int y_i = y_f;
- const int x_n_i = (x_i == grid_size - 1) ? (x_i) : (x_i + 1);
- const int y_n_i = (y_i == grid_size - 1) ? (y_i) : (y_i + 1);
+ linear_grids->num_grids = num_grids;
+ linear_grids->level = level;
+ linear_grids->grid_size = grid_size;
- const int corners[4][2] = {{x_i, y_i}, {x_n_i, y_i}, {x_n_i, y_n_i}, {x_i, y_n_i}};
- float mask_elements[4];
- for (int i = 0; i < 4; ++i) {
- GridCoord corner_grid_coord;
- corner_grid_coord.grid_index = grid_coord->grid_index;
- corner_grid_coord.u = corners[i][0] * grid_size_1_inv;
- corner_grid_coord.v = corners[i][1] * grid_size_1_inv;
+ linear_grids->grids = MEM_malloc_arrayN(num_grids, sizeof(LinearGrid), "linear grids");
+ linear_grids->elements_storage = MEM_calloc_arrayN(
+ num_grid_elements, sizeof(LinearGridElement), "linear elements storage");
- ReshapeConstGridElement element = multires_reshape_orig_grid_element_for_grid_coord(
- reshape_context, &corner_grid_coord);
- mask_elements[i] = element.mask;
+ for (int i = 0; i < num_grids; ++i) {
+ const size_t element_offset = grid_area * i;
+ linear_grids->grids[i].elements = &linear_grids->elements_storage[element_offset];
}
+}
- const float u = x_f - x_i;
- const float v = y_f - y_i;
- const float weights[4] = {(1.0f - u) * (1.0f - v), u * (1.0f - v), (1.0f - u) * v, u * v};
+static LinearGridElement *linear_grid_element_get(const LinearGrids *linear_grids,
+ const GridCoord *grid_coord)
+{
+ BLI_assert(grid_coord->grid_index >= 0);
+ BLI_assert(grid_coord->grid_index < linear_grids->num_grids);
+
+ const int grid_size = linear_grids->grid_size;
- return mask_elements[0] * weights[0] + mask_elements[1] * weights[1] +
- mask_elements[2] * weights[2] + mask_elements[3] * weights[3];
+ const int grid_x = lround(grid_coord->u * (grid_size - 1));
+ const int grid_y = lround(grid_coord->v * (grid_size - 1));
+ const int grid_element_index = grid_y * grid_size + grid_x;
+
+ LinearGrid *grid = &linear_grids->grids[grid_coord->grid_index];
+ return &grid->elements[grid_element_index];
}
-/* ================================================================================================
- * Surface.
- */
+static void linear_grids_free(LinearGrids *linear_grids)
+{
+ MEM_SAFE_FREE(linear_grids->grids);
+ MEM_SAFE_FREE(linear_grids->elements_storage);
+}
+
+static void linear_grid_element_init(LinearGridElement *linear_grid_element)
+{
+ linear_grid_element->mask = 0.0f;
+}
+
+/* result = a - b. */
+static void linear_grid_element_sub(LinearGridElement *result,
+ const LinearGridElement *a,
+ const LinearGridElement *b)
+{
+ result->mask = a->mask - b->mask;
+}
+
+static void linear_grid_element_interpolate(LinearGridElement *result,
+ const LinearGridElement elements[4],
+ const float weights[4])
+{
+ result->mask = elements[0].mask * weights[0] + elements[1].mask * weights[1] +
+ elements[2].mask * weights[2] + elements[3].mask * weights[3];
+}
+
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Surface
+ * \{ */
static void base_surface_grids_allocate(MultiresReshapeSmoothContext *reshape_smooth_context)
{
@@ -227,9 +317,11 @@ static void base_surface_grids_write(const MultiresReshapeSmoothContext *reshape
copy_m3_m3(point->tangent_matrix, tangent_matrix);
}
-/* ================================================================================================
- * Evaluation of subdivision surface at a reshape level.
- */
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Evaluation of subdivision surface at a reshape level
+ * \{ */
typedef void (*ForeachTopLevelGridCoordCallback)(
const MultiresReshapeSmoothContext *reshape_smooth_context,
@@ -383,11 +475,14 @@ static void foreach_toplevel_grid_coord(const MultiresReshapeSmoothContext *resh
0, num_faces, &data, foreach_toplevel_grid_coord_task, &parallel_range_settings);
}
-/* ================================================================================================
- * Generation of a topology information for OpenSubdiv converter.
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Generation of a topology information for OpenSubdiv converter
*
* Calculates vertices, their coordinates in the original grids, and connections of them so then
- * it's easy to create OpenSubdiv's topology refiner. */
+ * it's easy to create OpenSubdiv's topology refiner.
+ * \{ */
static int get_reshape_level_resolution(const MultiresReshapeContext *reshape_context)
{
@@ -399,15 +494,17 @@ static int get_reshape_level_resolution(const MultiresReshapeContext *reshape_co
static char get_effective_edge_crease_char(
const MultiresReshapeSmoothContext *reshape_smooth_context, const MEdge *base_edge)
{
- const MultiresReshapeContext *reshape_context = reshape_smooth_context->reshape_context;
- if (reshape_context->mmd->simple) {
+ if (ELEM(reshape_smooth_context->smoothing_type,
+ MULTIRES_SUBDIVIDE_LINEAR,
+ MULTIRES_SUBDIVIDE_SIMPLE)) {
return 255;
}
return base_edge->crease;
}
static void context_init(MultiresReshapeSmoothContext *reshape_smooth_context,
- const MultiresReshapeContext *reshape_context)
+ const MultiresReshapeContext *reshape_context,
+ const eMultiresSubdivideModeType mode)
{
reshape_smooth_context->reshape_context = reshape_context;
@@ -424,9 +521,13 @@ static void context_init(MultiresReshapeSmoothContext *reshape_smooth_context,
reshape_smooth_context->geometry.num_faces = 0;
reshape_smooth_context->geometry.faces = NULL;
+ linear_grids_init(&reshape_smooth_context->linear_delta_grids);
+
reshape_smooth_context->non_loose_base_edge_map = NULL;
reshape_smooth_context->reshape_subdiv = NULL;
reshape_smooth_context->base_surface_grids = NULL;
+
+ reshape_smooth_context->smoothing_type = mode;
}
static void context_free_geometry(MultiresReshapeSmoothContext *reshape_smooth_context)
@@ -440,6 +541,8 @@ static void context_free_geometry(MultiresReshapeSmoothContext *reshape_smooth_c
MEM_SAFE_FREE(reshape_smooth_context->geometry.corners);
MEM_SAFE_FREE(reshape_smooth_context->geometry.faces);
MEM_SAFE_FREE(reshape_smooth_context->geometry.edges);
+
+ linear_grids_free(&reshape_smooth_context->linear_delta_grids);
}
static void context_free_subdiv(MultiresReshapeSmoothContext *reshape_smooth_context)
@@ -461,12 +564,14 @@ static void context_free(MultiresReshapeSmoothContext *reshape_smooth_context)
static bool foreach_topology_info(const SubdivForeachContext *foreach_context,
const int num_vertices,
- const int UNUSED(num_edges),
+ const int num_edges,
const int num_loops,
const int num_polygons)
{
MultiresReshapeSmoothContext *reshape_smooth_context = foreach_context->user_data;
- const int max_edges = reshape_smooth_context->geometry.max_edges;
+ const int max_edges = reshape_smooth_context->smoothing_type == MULTIRES_SUBDIVIDE_LINEAR ?
+ num_edges :
+ reshape_smooth_context->geometry.max_edges;
/* NOTE: Calloc so the counters are re-set to 0 "for free". */
reshape_smooth_context->geometry.num_vertices = num_vertices;
@@ -659,6 +764,22 @@ static void foreach_vertex_of_loose_edge(const struct SubdivForeachContext *fore
}
}
+static void store_edge(MultiresReshapeSmoothContext *reshape_smooth_context,
+ const int subdiv_v1,
+ const int subdiv_v2,
+ const char crease)
+{
+ /* This is a bit overhead to use atomics in such a simple function called from many threads,
+ * but this allows to save quite measurable amount of memory. */
+ const int edge_index = atomic_fetch_and_add_z(&reshape_smooth_context->geometry.num_edges, 1);
+ BLI_assert(edge_index < reshape_smooth_context->geometry.max_edges);
+
+ Edge *edge = &reshape_smooth_context->geometry.edges[edge_index];
+ edge->v1 = subdiv_v1;
+ edge->v2 = subdiv_v2;
+ edge->sharpness = BKE_subdiv_edge_crease_to_sharpness_char(crease);
+}
+
static void foreach_edge(const struct SubdivForeachContext *foreach_context,
void *UNUSED(tls),
const int coarse_edge_index,
@@ -669,8 +790,15 @@ static void foreach_edge(const struct SubdivForeachContext *foreach_context,
MultiresReshapeSmoothContext *reshape_smooth_context = foreach_context->user_data;
const MultiresReshapeContext *reshape_context = reshape_smooth_context->reshape_context;
- /* Ignore all inner face edges as they have sharpness of zero. */
- if (coarse_edge_index == ORIGINDEX_NONE) {
+ if (reshape_smooth_context->smoothing_type == MULTIRES_SUBDIVIDE_LINEAR) {
+ store_edge(reshape_smooth_context, subdiv_v1, subdiv_v2, (char)255);
+ return;
+ }
+
+ /* Ignore all inner face edges as they have sharpness of zero when using Catmull-Clark mode. In
+ * simple mode, all edges have maximum sharpness, so they can't be skipped. */
+ if (coarse_edge_index == ORIGINDEX_NONE &&
+ reshape_smooth_context->smoothing_type != MULTIRES_SUBDIVIDE_SIMPLE) {
return;
}
/* Ignore all loose edges as well, as they are not communicated to the OpenSubdiv. */
@@ -684,16 +812,7 @@ static void foreach_edge(const struct SubdivForeachContext *foreach_context,
if (crease == 0) {
return;
}
-
- /* This is a bit overhead to use atomics in such a simple function called from many threads,
- * but this allows to save quite measurable amount of memory. */
- const int edge_index = atomic_fetch_and_add_z(&reshape_smooth_context->geometry.num_edges, 1);
- BLI_assert(edge_index < reshape_smooth_context->geometry.max_edges);
-
- Edge *edge = &reshape_smooth_context->geometry.edges[edge_index];
- edge->v1 = subdiv_v1;
- edge->v2 = subdiv_v2;
- edge->sharpness = BKE_subdiv_edge_crease_to_sharpness_char(crease);
+ store_edge(reshape_smooth_context, subdiv_v1, subdiv_v2, crease);
}
static void geometry_init_loose_information(MultiresReshapeSmoothContext *reshape_smooth_context)
@@ -757,9 +876,11 @@ static void geometry_create(MultiresReshapeSmoothContext *reshape_smooth_context
reshape_context->subdiv, &foreach_context, &mesh_settings, reshape_context->base_mesh);
}
-/* ================================================================================================
- * Generation of OpenSubdiv evaluator for topology created form reshape level.
- */
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Generation of OpenSubdiv evaluator for topology created form reshape level
+ * \{ */
static OpenSubdiv_SchemeType get_scheme_type(const OpenSubdiv_Converter *UNUSED(converter))
{
@@ -929,7 +1050,7 @@ typedef void(ReshapeSubdivCoarsePositionCb)(
const Vertex *vertex,
float r_P[3]);
-/* Refine subdivision surface topology at a reshape level for new coarse verticies positions. */
+/* Refine subdivision surface topology at a reshape level for new coarse vertices positions. */
static void reshape_subdiv_refine(const MultiresReshapeSmoothContext *reshape_smooth_context,
ReshapeSubdivCoarsePositionCb coarse_position_cb)
{
@@ -1037,9 +1158,138 @@ static void reshape_subdiv_evaluate_limit_at_grid(
BKE_multires_construct_tangent_matrix(r_tangent_matrix, dPdu, dPdv, corner);
}
-/* ================================================================================================
- * Evaluation of base surface.
- */
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Linearly interpolated data
+ * \{ */
+
+static LinearGridElement linear_grid_element_orig_get(
+ const MultiresReshapeSmoothContext *reshape_smooth_context, const GridCoord *grid_coord)
+{
+ const MultiresReshapeContext *reshape_context = reshape_smooth_context->reshape_context;
+ const ReshapeConstGridElement orig_grid_element =
+ multires_reshape_orig_grid_element_for_grid_coord(reshape_context, grid_coord);
+
+ LinearGridElement linear_grid_element;
+ linear_grid_element_init(&linear_grid_element);
+
+ linear_grid_element.mask = orig_grid_element.mask;
+
+ return linear_grid_element;
+}
+
+static LinearGridElement linear_grid_element_final_get(
+ const MultiresReshapeSmoothContext *reshape_smooth_context, const GridCoord *grid_coord)
+{
+ const MultiresReshapeContext *reshape_context = reshape_smooth_context->reshape_context;
+ const ReshapeGridElement final_grid_element = multires_reshape_grid_element_for_grid_coord(
+ reshape_context, grid_coord);
+
+ LinearGridElement linear_grid_element;
+ linear_grid_element_init(&linear_grid_element);
+
+ if (final_grid_element.mask != NULL) {
+ linear_grid_element.mask = *final_grid_element.mask;
+ }
+
+ return linear_grid_element;
+}
+
+/* Interpolate difference of the linear data.
+ *
+ * Will access final data and original data at the grid elements at the reshape level,
+ * calculate difference between final and original, and linearly interpolate to get value at the
+ * top level. */
+static void linear_grid_element_delta_interpolate(
+ const MultiresReshapeSmoothContext *reshape_smooth_context,
+ const GridCoord *grid_coord,
+ LinearGridElement *result)
+{
+ const MultiresReshapeContext *reshape_context = reshape_smooth_context->reshape_context;
+
+ const int reshape_level = reshape_context->reshape.level;
+ const int reshape_level_grid_size = BKE_subdiv_grid_size_from_level(reshape_level);
+ const int reshape_level_grid_size_1 = reshape_level_grid_size - 1;
+ const float reshape_level_grid_size_1_inv = 1.0f / (float)(reshape_level_grid_size_1);
+
+ const float x_f = grid_coord->u * reshape_level_grid_size_1;
+ const float y_f = grid_coord->v * reshape_level_grid_size_1;
+
+ const int x_i = x_f;
+ const int y_i = y_f;
+ const int x_n_i = (x_i == reshape_level_grid_size - 1) ? (x_i) : (x_i + 1);
+ const int y_n_i = (y_i == reshape_level_grid_size - 1) ? (y_i) : (y_i + 1);
+
+ const int corners_int_coords[4][2] = {{x_i, y_i}, {x_n_i, y_i}, {x_n_i, y_n_i}, {x_i, y_n_i}};
+
+ LinearGridElement corner_elements[4];
+ for (int i = 0; i < 4; ++i) {
+ GridCoord corner_grid_coord;
+ corner_grid_coord.grid_index = grid_coord->grid_index;
+ corner_grid_coord.u = corners_int_coords[i][0] * reshape_level_grid_size_1_inv;
+ corner_grid_coord.v = corners_int_coords[i][1] * reshape_level_grid_size_1_inv;
+
+ const LinearGridElement orig_element = linear_grid_element_orig_get(reshape_smooth_context,
+ &corner_grid_coord);
+ const LinearGridElement final_element = linear_grid_element_final_get(reshape_smooth_context,
+ &corner_grid_coord);
+ linear_grid_element_sub(&corner_elements[i], &final_element, &orig_element);
+ }
+
+ const float u = x_f - x_i;
+ const float v = y_f - y_i;
+ const float weights[4] = {(1.0f - u) * (1.0f - v), u * (1.0f - v), u * v, (1.0f - u) * v};
+
+ linear_grid_element_interpolate(result, corner_elements, weights);
+}
+
+static void evaluate_linear_delta_grids_callback(
+ const MultiresReshapeSmoothContext *reshape_smooth_context,
+ const PTexCoord *UNUSED(ptex_coord),
+ const GridCoord *grid_coord,
+ void *UNUSED(userdata_v))
+{
+ LinearGridElement *linear_delta_element = linear_grid_element_get(
+ &reshape_smooth_context->linear_delta_grids, grid_coord);
+
+ linear_grid_element_delta_interpolate(reshape_smooth_context, grid_coord, linear_delta_element);
+}
+
+static void evaluate_linear_delta_grids(MultiresReshapeSmoothContext *reshape_smooth_context)
+{
+ const MultiresReshapeContext *reshape_context = reshape_smooth_context->reshape_context;
+ const int num_grids = reshape_context->num_grids;
+ const int top_level = reshape_context->top.level;
+
+ linear_grids_allocate(&reshape_smooth_context->linear_delta_grids, num_grids, top_level);
+
+ foreach_toplevel_grid_coord(reshape_smooth_context, evaluate_linear_delta_grids_callback, NULL);
+}
+
+static void propagate_linear_data_delta(const MultiresReshapeSmoothContext *reshape_smooth_context,
+ ReshapeGridElement *final_grid_element,
+ const GridCoord *grid_coord)
+{
+ const MultiresReshapeContext *reshape_context = reshape_smooth_context->reshape_context;
+
+ LinearGridElement *linear_delta_element = linear_grid_element_get(
+ &reshape_smooth_context->linear_delta_grids, grid_coord);
+
+ const ReshapeConstGridElement orig_grid_element =
+ multires_reshape_orig_grid_element_for_grid_coord(reshape_context, grid_coord);
+
+ if (final_grid_element->mask != NULL) {
+ *final_grid_element->mask = clamp_f(
+ orig_grid_element.mask + linear_delta_element->mask, 0.0f, 1.0f);
+ }
+}
+
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Evaluation of base surface
+ * \{ */
static void evaluate_base_surface_grids_callback(
const MultiresReshapeSmoothContext *reshape_smooth_context,
@@ -1060,9 +1310,11 @@ static void evaluate_base_surface_grids(const MultiresReshapeSmoothContext *resh
foreach_toplevel_grid_coord(reshape_smooth_context, evaluate_base_surface_grids_callback, NULL);
}
-/* ================================================================================================
- * Evaluation of new surface.
- */
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Evaluation of new surface
+ * \{ */
/* Evaluate final position of the original (pre-sculpt-edit) point position at a given grid
* coordinate. */
@@ -1136,7 +1388,11 @@ static void evaluate_higher_grid_positions_with_details_callback(
grid_coord);
add_v3_v3v3(grid_element.displacement, smooth_limit_P, smooth_delta);
+
+ /* Propagate non-coordinate data. */
+ propagate_linear_data_delta(reshape_smooth_context, &grid_element, grid_coord);
}
+
static void evaluate_higher_grid_positions_with_details(
const MultiresReshapeSmoothContext *reshape_smooth_context)
{
@@ -1157,17 +1413,14 @@ static void evaluate_higher_grid_positions_callback(
grid_coord);
/* Surface. */
-
float P[3];
BKE_subdiv_eval_limit_point(
reshape_subdiv, ptex_coord->ptex_face_index, ptex_coord->u, ptex_coord->v, P);
copy_v3_v3(grid_element.displacement, P);
- /* Masks. */
- if (grid_element.mask != NULL) {
- *grid_element.mask = interpolate_masks_grid(reshape_smooth_context, grid_coord);
- }
+ /* Propagate non-coordinate data. */
+ propagate_linear_data_delta(reshape_smooth_context, &grid_element, grid_coord);
}
static void evaluate_higher_grid_positions(
@@ -1176,9 +1429,12 @@ static void evaluate_higher_grid_positions(
foreach_toplevel_grid_coord(
reshape_smooth_context, evaluate_higher_grid_positions_callback, NULL);
}
-/* ================================================================================================
- * Entry point.
- */
+
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Entry point
+ * \{ */
void multires_reshape_smooth_object_grids_with_details(
const MultiresReshapeContext *reshape_context)
@@ -1190,9 +1446,15 @@ void multires_reshape_smooth_object_grids_with_details(
}
MultiresReshapeSmoothContext reshape_smooth_context;
- context_init(&reshape_smooth_context, reshape_context);
+ if (reshape_context->subdiv->settings.is_simple) {
+ context_init(&reshape_smooth_context, reshape_context, MULTIRES_SUBDIVIDE_SIMPLE);
+ }
+ else {
+ context_init(&reshape_smooth_context, reshape_context, MULTIRES_SUBDIVIDE_CATMULL_CLARK);
+ }
geometry_create(&reshape_smooth_context);
+ evaluate_linear_delta_grids(&reshape_smooth_context);
reshape_subdiv_create(&reshape_smooth_context);
@@ -1206,7 +1468,8 @@ void multires_reshape_smooth_object_grids_with_details(
context_free(&reshape_smooth_context);
}
-void multires_reshape_smooth_object_grids(const MultiresReshapeContext *reshape_context)
+void multires_reshape_smooth_object_grids(const MultiresReshapeContext *reshape_context,
+ const eMultiresSubdivideModeType mode)
{
const int level_difference = (reshape_context->top.level - reshape_context->reshape.level);
if (level_difference == 0) {
@@ -1215,9 +1478,10 @@ void multires_reshape_smooth_object_grids(const MultiresReshapeContext *reshape_
}
MultiresReshapeSmoothContext reshape_smooth_context;
- context_init(&reshape_smooth_context, reshape_context);
+ context_init(&reshape_smooth_context, reshape_context, mode);
geometry_create(&reshape_smooth_context);
+ evaluate_linear_delta_grids(&reshape_smooth_context);
reshape_subdiv_create(&reshape_smooth_context);
@@ -1226,3 +1490,5 @@ void multires_reshape_smooth_object_grids(const MultiresReshapeContext *reshape_
context_free(&reshape_smooth_context);
}
+
+/** \} */
diff --git a/source/blender/blenkernel/intern/multires_reshape_subdivide.c b/source/blender/blenkernel/intern/multires_reshape_subdivide.c
new file mode 100644
index 00000000000..7b7c1efc533
--- /dev/null
+++ b/source/blender/blenkernel/intern/multires_reshape_subdivide.c
@@ -0,0 +1,106 @@
+/*
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * The Original Code is Copyright (C) 2020 Blender Foundation.
+ * All rights reserved.
+ */
+
+/** \file
+ * \ingroup bke
+ */
+
+#include "MEM_guardedalloc.h"
+
+#include "DNA_mesh_types.h"
+#include "DNA_meshdata_types.h"
+#include "DNA_modifier_types.h"
+#include "DNA_scene_types.h"
+
+#include "BKE_customdata.h"
+#include "BKE_lib_id.h"
+#include "BKE_mesh.h"
+#include "BKE_mesh_runtime.h"
+#include "BKE_modifier.h"
+#include "BKE_multires.h"
+#include "BKE_subdiv.h"
+#include "BKE_subsurf.h"
+#include "BLI_math_vector.h"
+
+#include "DEG_depsgraph_query.h"
+
+#include "multires_reshape.h"
+
+static void multires_subdivide_create_object_space_linear_grids(Mesh *mesh)
+{
+ MDisps *mdisps = CustomData_get_layer(&mesh->ldata, CD_MDISPS);
+ const int totpoly = mesh->totpoly;
+ for (int p = 0; p < totpoly; p++) {
+ MPoly *poly = &mesh->mpoly[p];
+ float poly_center[3];
+ BKE_mesh_calc_poly_center(poly, &mesh->mloop[poly->loopstart], mesh->mvert, poly_center);
+ for (int l = 0; l < poly->totloop; l++) {
+ const int loop_index = poly->loopstart + l;
+
+ float(*disps)[3] = mdisps[loop_index].disps;
+ mdisps[loop_index].totdisp = 4;
+ mdisps[loop_index].level = 1;
+
+ int prev_loop_index = l - 1 >= 0 ? loop_index - 1 : loop_index + poly->totloop - 1;
+ int next_loop_index = l + 1 < poly->totloop ? loop_index + 1 : poly->loopstart;
+
+ MLoop *loop = &mesh->mloop[loop_index];
+ MLoop *loop_next = &mesh->mloop[next_loop_index];
+ MLoop *loop_prev = &mesh->mloop[prev_loop_index];
+
+ copy_v3_v3(disps[0], poly_center);
+ mid_v3_v3v3(disps[1], mesh->mvert[loop->v].co, mesh->mvert[loop_next->v].co);
+ mid_v3_v3v3(disps[2], mesh->mvert[loop->v].co, mesh->mvert[loop_prev->v].co);
+ copy_v3_v3(disps[3], mesh->mvert[loop->v].co);
+ }
+ }
+}
+
+void multires_subdivide_create_tangent_displacement_linear_grids(Object *object,
+ MultiresModifierData *mmd)
+{
+ Mesh *coarse_mesh = object->data;
+ multires_force_sculpt_rebuild(object);
+
+ MultiresReshapeContext reshape_context;
+
+ const int new_top_level = mmd->totlvl + 1;
+
+ const bool has_mdisps = CustomData_has_layer(&coarse_mesh->ldata, CD_MDISPS);
+ if (!has_mdisps) {
+ CustomData_add_layer(&coarse_mesh->ldata, CD_MDISPS, CD_CALLOC, NULL, coarse_mesh->totloop);
+ }
+
+ if (new_top_level == 1) {
+ /* No MDISPS. Create new grids for level 1 using the edges mid point and poly centers. */
+ multires_reshape_ensure_grids(coarse_mesh, 1);
+ multires_subdivide_create_object_space_linear_grids(coarse_mesh);
+ }
+
+ /* Convert the new grids to tangent displacement. */
+ multires_set_tot_level(object, mmd, new_top_level);
+
+ if (!multires_reshape_context_create_from_subdivide(
+ &reshape_context, object, mmd, new_top_level)) {
+ return;
+ }
+
+ multires_reshape_object_grids_to_tangent_displacement(&reshape_context);
+ multires_reshape_context_free(&reshape_context);
+}
diff --git a/source/blender/blenkernel/intern/multires_reshape_util.c b/source/blender/blenkernel/intern/multires_reshape_util.c
index 759306f9422..e9a779dafeb 100644
--- a/source/blender/blenkernel/intern/multires_reshape_util.c
+++ b/source/blender/blenkernel/intern/multires_reshape_util.c
@@ -10,7 +10,7 @@
* 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,
+ * along with this program; if not, write to the Free Software Foundation,
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*
* The Original Code is Copyright (C) 2020 Blender Foundation.
@@ -43,9 +43,9 @@
#include "DEG_depsgraph_query.h"
-/* ================================================================================================
- * Construct/destruct reshape context.
- */
+/* -------------------------------------------------------------------- */
+/** \name Construct/destruct reshape context
+ * \{ */
/* Create subdivision surface descriptor which is configured for surface evaluation at a given
* multires modifier. */
@@ -67,7 +67,7 @@ Subdiv *multires_reshape_create_subdiv(Depsgraph *depsgraph,
SubdivSettings subdiv_settings;
BKE_multires_subdiv_settings_init(&subdiv_settings, mmd);
Subdiv *subdiv = BKE_subdiv_new_from_mesh(&subdiv_settings, base_mesh);
- if (!BKE_subdiv_eval_update_from_mesh(subdiv, base_mesh, NULL)) {
+ if (!BKE_subdiv_eval_begin_from_mesh(subdiv, base_mesh, NULL)) {
BKE_subdiv_free(subdiv);
return NULL;
}
@@ -152,6 +152,39 @@ static bool context_verify_or_free(MultiresReshapeContext *reshape_context)
return is_valid;
}
+bool multires_reshape_context_create_from_base_mesh(MultiresReshapeContext *reshape_context,
+ Depsgraph *depsgraph,
+ Object *object,
+ MultiresModifierData *mmd)
+{
+ context_zero(reshape_context);
+
+ const bool use_render_params = false;
+ Scene *scene_eval = DEG_get_evaluated_scene(depsgraph);
+ Mesh *base_mesh = (Mesh *)object->data;
+
+ reshape_context->depsgraph = depsgraph;
+ reshape_context->object = object;
+ reshape_context->mmd = mmd;
+
+ reshape_context->base_mesh = base_mesh;
+
+ reshape_context->subdiv = multires_reshape_create_subdiv(NULL, object, mmd);
+ reshape_context->need_free_subdiv = true;
+
+ reshape_context->reshape.level = multires_get_level(
+ scene_eval, object, mmd, use_render_params, true);
+ reshape_context->reshape.grid_size = BKE_subdiv_grid_size_from_level(
+ reshape_context->reshape.level);
+
+ reshape_context->top.level = mmd->totlvl;
+ reshape_context->top.grid_size = BKE_subdiv_grid_size_from_level(reshape_context->top.level);
+
+ context_init_commoon(reshape_context);
+
+ return context_verify_or_free(reshape_context);
+}
+
bool multires_reshape_context_create_from_object(MultiresReshapeContext *reshape_context,
Depsgraph *depsgraph,
Object *object,
@@ -236,7 +269,7 @@ bool multires_reshape_context_create_from_subdivide(MultiresReshapeContext *resh
return context_verify_or_free(reshape_context);
}
-static void free_original_grids(MultiresReshapeContext *reshape_context)
+void multires_reshape_free_original_grids(MultiresReshapeContext *reshape_context)
{
MDisps *orig_mdisps = reshape_context->orig.mdisps;
GridPaintMask *orig_grid_paint_masks = reshape_context->orig.grid_paint_masks;
@@ -259,6 +292,9 @@ static void free_original_grids(MultiresReshapeContext *reshape_context)
MEM_SAFE_FREE(orig_mdisps);
MEM_SAFE_FREE(orig_grid_paint_masks);
+
+ reshape_context->orig.mdisps = NULL;
+ reshape_context->orig.grid_paint_masks = NULL;
}
void multires_reshape_context_free(MultiresReshapeContext *reshape_context)
@@ -267,16 +303,18 @@ void multires_reshape_context_free(MultiresReshapeContext *reshape_context)
BKE_subdiv_free(reshape_context->subdiv);
}
- free_original_grids(reshape_context);
+ multires_reshape_free_original_grids(reshape_context);
- MEM_freeN(reshape_context->face_start_grid_index);
- MEM_freeN(reshape_context->ptex_start_grid_index);
- MEM_freeN(reshape_context->grid_to_face_index);
+ MEM_SAFE_FREE(reshape_context->face_start_grid_index);
+ MEM_SAFE_FREE(reshape_context->ptex_start_grid_index);
+ MEM_SAFE_FREE(reshape_context->grid_to_face_index);
}
-/* ================================================================================================
- * Helper accessors.
- */
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Helper accessors
+ * \{ */
/* For the given grid index get index of face it was created for. */
int multires_reshape_grid_to_face_index(const MultiresReshapeContext *reshape_context,
@@ -450,9 +488,11 @@ ReshapeConstGridElement multires_reshape_orig_grid_element_for_grid_coord(
return grid_element;
}
-/* ================================================================================================
- * Sample limit surface of the base mesh.
- */
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Sample limit surface of the base mesh
+ * \{ */
void multires_reshape_evaluate_limit_at_grid(const MultiresReshapeContext *reshape_context,
const GridCoord *grid_coord,
@@ -472,9 +512,11 @@ void multires_reshape_evaluate_limit_at_grid(const MultiresReshapeContext *resha
reshape_context, face_index, corner, dPdu, dPdv, r_tangent_matrix);
}
-/* ================================================================================================
- * Custom data preparation.
- */
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Custom data preparation
+ * \{ */
static void allocate_displacement_grid(MDisps *displacement_grid, const int level)
{
@@ -536,9 +578,11 @@ void multires_reshape_ensure_grids(Mesh *mesh, const int level)
ensure_mask_grids(mesh, level);
}
-/* ================================================================================================
- * Displacement, space conversion.
- */
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Displacement, space conversion
+ * \{ */
void multires_reshape_store_original_grids(MultiresReshapeContext *reshape_context)
{
@@ -675,10 +719,13 @@ void multires_reshape_object_grids_to_tangent_displacement(
NULL);
}
-/* ================================================================================================
- * MDISPS
- *
- * TODO(sergey): Make foreach_grid_coordinate more accessible and move this functionality to
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name MDISPS
+ * \{ */
+
+/* TODO(sergey): Make foreach_grid_coordinate more accessible and move this functionality to
* own file. */
static void assign_final_coords_from_mdisps(const MultiresReshapeContext *reshape_context,
@@ -704,9 +751,9 @@ void multires_reshape_assign_final_coords_from_mdisps(
reshape_context, reshape_context->top.level, assign_final_coords_from_mdisps, NULL);
}
-static void assign_final_coords_from_orig_mdisps(const MultiresReshapeContext *reshape_context,
- const GridCoord *grid_coord,
- void *UNUSED(userdata_v))
+static void assign_final_elements_from_orig_mdisps(const MultiresReshapeContext *reshape_context,
+ const GridCoord *grid_coord,
+ void *UNUSED(userdata_v))
{
float P[3];
float tangent_matrix[3][3];
@@ -721,11 +768,17 @@ static void assign_final_coords_from_orig_mdisps(const MultiresReshapeContext *r
ReshapeGridElement grid_element = multires_reshape_grid_element_for_grid_coord(reshape_context,
grid_coord);
add_v3_v3v3(grid_element.displacement, P, D);
+
+ if (grid_element.mask != NULL) {
+ *grid_element.mask = orig_grid_element.mask;
+ }
}
-void multires_reshape_assign_final_coords_from_orig_mdisps(
+void multires_reshape_assign_final_elements_from_orig_mdisps(
const MultiresReshapeContext *reshape_context)
{
foreach_grid_coordinate(
- reshape_context, reshape_context->top.level, assign_final_coords_from_orig_mdisps, NULL);
+ reshape_context, reshape_context->top.level, assign_final_elements_from_orig_mdisps, NULL);
}
+
+/** \} */
diff --git a/source/blender/blenkernel/intern/multires_reshape_vertcos.c b/source/blender/blenkernel/intern/multires_reshape_vertcos.c
index 5aff0b3caa2..04df5698cf9 100644
--- a/source/blender/blenkernel/intern/multires_reshape_vertcos.c
+++ b/source/blender/blenkernel/intern/multires_reshape_vertcos.c
@@ -10,7 +10,7 @@
* 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,
+ * along with this program; if not, write to the Free Software Foundation,
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*
* The Original Code is Copyright (C) 2020 Blender Foundation.
@@ -182,8 +182,7 @@ static void multires_reshape_vertcos_foreach_vertex_every_edge(
multires_reshape_vertcos_foreach_vertex(foreach_context, &ptex_coord, subdiv_vertex_index);
}
-/* Set displacement grids values at a reshape level to a object coordinates of the the given
- * source. */
+/* Set displacement grids values at a reshape level to a object coordinates of the given source. */
bool multires_reshape_assign_final_coords_from_vertcos(
const MultiresReshapeContext *reshape_context,
const float (*vert_coords)[3],
diff --git a/source/blender/blenkernel/intern/multires_subdiv.c b/source/blender/blenkernel/intern/multires_subdiv.c
index f7e42942f3e..fc092d3ccce 100644
--- a/source/blender/blenkernel/intern/multires_subdiv.c
+++ b/source/blender/blenkernel/intern/multires_subdiv.c
@@ -10,7 +10,7 @@
* 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,
+ * 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) 2018 Blender Foundation.
diff --git a/source/blender/blenkernel/intern/multires_unsubdivide.c b/source/blender/blenkernel/intern/multires_unsubdivide.c
new file mode 100644
index 00000000000..e5000e7774f
--- /dev/null
+++ b/source/blender/blenkernel/intern/multires_unsubdivide.c
@@ -0,0 +1,1297 @@
+/*
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * The Original Code is Copyright (C) 2020 Blender Foundation.
+ * All rights reserved.
+ */
+
+/** \file
+ * \ingroup bke
+ *
+ * This implements the un-subdivide algorithm, which generates a lower resolution base mesh and
+ * its corresponding grids to match a given original mesh.
+ */
+
+#include "MEM_guardedalloc.h"
+
+#include "DNA_mesh_types.h"
+#include "DNA_meshdata_types.h"
+#include "DNA_modifier_types.h"
+#include "DNA_scene_types.h"
+
+#include "BLI_gsqueue.h"
+#include "BLI_math_vector.h"
+
+#include "BKE_customdata.h"
+#include "BKE_lib_id.h"
+#include "BKE_mesh.h"
+#include "BKE_mesh_runtime.h"
+#include "BKE_modifier.h"
+#include "BKE_multires.h"
+#include "BKE_subdiv.h"
+#include "BKE_subsurf.h"
+
+#include "bmesh.h"
+
+#include "DEG_depsgraph_query.h"
+
+#include "multires_reshape.h"
+#include "multires_unsubdivide.h"
+
+/* This is done in the following steps:
+ *
+ * - If there are already grids in the original mesh,
+ * convert them from tangent displacement to object space coordinates.
+ * - Assign data-layers to the original mesh to map vertices to a new base mesh.
+ * These data-layers store the indices of the elements in the original mesh.
+ * This way the original indices are
+ * preserved when doing mesh modifications (removing and dissolving vertices)
+ * when building the new base mesh.
+ * - Try to find a lower resolution base mesh. This is done by flood fill operation that tags the
+ * center vertices of the lower level grid.
+ * If the algorithm can tag all vertices correctly,
+ * the lower level base mesh is generated by dissolving the tagged vertices.
+ * - Use the data-layers to map vertices from the base mesh to the original mesh and original to
+ * base mesh.
+ * - Find two adjacent vertices on the base mesh to a given vertex to map that loop from base mesh
+ * to original mesh
+ * - Extract the grid from the original mesh from that loop. If there are no grids in the original
+ * mesh, build the new grid directly from the vertex coordinates by iterating in a grid pattern
+ * over them. If there are grids in the original mesh, iterate in a grid pattern over the polys,
+ * reorder all the coordinates of the grid in that poly and copy those coordinates to the new
+ * base mesh grid.
+ * - Copy the new grid data over to a new allocated MDISP layer with the appropriate size to store
+ * the new levels.
+ * - Convert the grid data from object space to tangent displacement.
+ */
+
+/**
+ * Used to check if a vertex is in a disconnected element ID.
+ */
+static bool is_vertex_in_id(BMVert *v, int *elem_id, int elem)
+{
+ const int v_index = BM_elem_index_get(v);
+ return elem_id[v_index] == elem;
+}
+
+static bool is_vertex_pole_three(BMVert *v)
+{
+ return !BM_vert_is_boundary(v) && (BM_vert_edge_count(v) == 3);
+}
+
+static bool is_vertex_pole(BMVert *v)
+{
+ return !BM_vert_is_boundary(v) && (BM_vert_edge_count(v) == 3 || BM_vert_edge_count(v) >= 5);
+}
+
+/**
+ * Returns the first pole that is found in an element ID.
+ *
+ * Tries to give priority to 3 vert poles as they generally generate better results in cases were
+ * the un-subdivide solution is ambiguous.
+ */
+static BMVert *unsubdivide_find_any_pole(BMesh *bm, int *elem_id, int elem)
+{
+ BMIter iter;
+ BMVert *v;
+ BMVert *pole = NULL;
+ BM_ITER_MESH (v, &iter, bm, BM_VERTS_OF_MESH) {
+ if (is_vertex_in_id(v, elem_id, elem) && is_vertex_pole_three(v)) {
+ return v;
+ }
+ else if (is_vertex_in_id(v, elem_id, elem) && is_vertex_pole(v)) {
+ pole = v;
+ }
+ }
+ return pole;
+}
+
+/**
+ * Checks if the mesh is all quads.
+ *
+ * TODO(pablodp606): This can perform additional checks if they are faster than trying to search
+ * for an un-subdivide solution. This way it is possible to cancel the operation faster.
+ */
+static bool unsubdivide_is_all_quads(BMesh *bm)
+{
+ BMIter iter;
+ BMIter iter_a;
+ BMFace *f;
+ BMVert *v;
+ int count = 0;
+ if (bm->totface < 3) {
+ return false;
+ }
+
+ BM_ITER_MESH (f, &iter, bm, BM_FACES_OF_MESH) {
+ count = 0;
+ BM_ITER_ELEM (v, &iter_a, f, BM_VERTS_OF_FACE) {
+ count++;
+ }
+
+ if (count != 4) {
+ return false;
+ }
+ }
+
+ BM_ITER_MESH (v, &iter, bm, BM_VERTS_OF_MESH) {
+ if (BM_vert_is_wire(v)) {
+ return false;
+ }
+ if (BM_vert_edge_count(v) == 0) {
+ return false;
+ }
+ }
+
+ return true;
+}
+
+/**
+ * Returns true if from_v and to_v, which should be part of the same quad face, are diagonals.
+ */
+static bool is_vertex_diagonal(BMVert *from_v, BMVert *to_v)
+{
+ return !BM_edge_exists(from_v, to_v);
+}
+
+/**
+ * Generates a possible solution for un-subdivision by tagging the (0,0)
+ * vertices of the possible grids.
+ *
+ * This works using a flood fill operation using the quads diagonals to jump to the next vertex.
+ *
+ * If initial_vertex is part of the base mesh solution, the flood fill should tag only the (0.0)
+ * vertices of the grids that need to be dissolved, and nothing else.
+ */
+static void unsubdivide_face_center_vertex_tag(BMesh *bm, BMVert *initial_vertex)
+{
+ bool *visited_vertices = MEM_calloc_arrayN(sizeof(bool), bm->totvert, "visited vertices");
+ GSQueue *queue;
+ queue = BLI_gsqueue_new(sizeof(BMVert *));
+
+ /* Add and tag the vertices connected by a diagonal to initial_vertex to the flood fill queue. If
+ * initial_vertex is a pole and there is a valid solution, those vertices should be the (0,0) of
+ * the grids for the loops of initial_vertex. */
+ BMIter iter;
+ BMIter iter_a;
+ BMFace *f;
+ BMVert *neighbor_v;
+ BM_ITER_ELEM (f, &iter, initial_vertex, BM_FACES_OF_VERT) {
+ BM_ITER_ELEM (neighbor_v, &iter_a, f, BM_VERTS_OF_FACE) {
+ int neighbor_vertex_index = BM_elem_index_get(neighbor_v);
+ if (neighbor_v != initial_vertex && is_vertex_diagonal(neighbor_v, initial_vertex)) {
+ BLI_gsqueue_push(queue, &neighbor_v);
+ visited_vertices[neighbor_vertex_index] = true;
+ BM_elem_flag_set(neighbor_v, BM_ELEM_TAG, true);
+ }
+ }
+ }
+
+ /* Repeat a similar operation for all vertices in the queue. */
+ /* In this case, add to the queue the vertices connected by 2 steps using the diagonals in any
+ * direction. If a solution exists and intial_vertex was a pole, this is guaranteed that will tag
+ * all the (0,0) vertices of the grids, and nothing else. */
+ /* If it was not a pole, it may or may not find a solution, even if the solution exists. */
+ while (!BLI_gsqueue_is_empty(queue)) {
+ BMVert *from_v;
+ BLI_gsqueue_pop(queue, &from_v);
+
+ /* Get the diagonals (first connected step) */
+ GSQueue *diagonals;
+ diagonals = BLI_gsqueue_new(sizeof(BMVert *));
+ BM_ITER_ELEM (f, &iter, from_v, BM_FACES_OF_VERT) {
+ BM_ITER_ELEM (neighbor_v, &iter_a, f, BM_VERTS_OF_FACE) {
+ if (neighbor_v != from_v && is_vertex_diagonal(neighbor_v, from_v)) {
+ BLI_gsqueue_push(diagonals, &neighbor_v);
+ }
+ }
+ }
+
+ /* Do the second connected step. This vertices are the ones that are added to the flood fill
+ * queue. */
+ while (!BLI_gsqueue_is_empty(diagonals)) {
+ BMVert *diagonal_v;
+ BLI_gsqueue_pop(diagonals, &diagonal_v);
+ BM_ITER_ELEM (f, &iter, diagonal_v, BM_FACES_OF_VERT) {
+ BM_ITER_ELEM (neighbor_v, &iter_a, f, BM_VERTS_OF_FACE) {
+ int neighbor_vertex_index = BM_elem_index_get(neighbor_v);
+ if (!visited_vertices[neighbor_vertex_index] && neighbor_v != diagonal_v &&
+ is_vertex_diagonal(neighbor_v, diagonal_v)) {
+ BLI_gsqueue_push(queue, &neighbor_v);
+ visited_vertices[neighbor_vertex_index] = true;
+ BM_elem_flag_set(neighbor_v, BM_ELEM_TAG, true);
+ }
+ }
+ }
+ }
+ BLI_gsqueue_free(diagonals);
+ }
+
+ BLI_gsqueue_free(queue);
+ MEM_freeN(visited_vertices);
+}
+
+/**
+ * This function checks if the current status of the #BMVert tags
+ * corresponds to a valid un-subdivide solution.
+ *
+ * This means that all vertices corresponding to the (0,0) grid coordinate should be tagged.
+ *
+ * On a valid solution, the following things should happen:
+ * - No boundary vertices should be tagged
+ * - No vertices connected by an edge or a quad diagonal to a tagged vertex should be tagged
+ * - All boundary vertices should have one vertex connected by an edge or a diagonal tagged
+ */
+static bool unsubdivide_is_center_vertex_tag_valid(BMesh *bm, int *elem_id, int elem)
+{
+ BMVert *v, *neighbor_v;
+ BMIter iter, iter_a, iter_b;
+ BMFace *f;
+
+ BM_ITER_MESH (v, &iter, bm, BM_VERTS_OF_MESH) {
+ if (is_vertex_in_id(v, elem_id, elem)) {
+ if (BM_elem_flag_test(v, BM_ELEM_TAG)) {
+ /* Tagged vertex in boundary */
+ if (BM_vert_is_boundary(v)) {
+ return false;
+ }
+ /* Tagged vertex with connected tagged vertex. */
+ BM_ITER_ELEM (f, &iter_a, v, BM_FACES_OF_VERT) {
+ BM_ITER_ELEM (neighbor_v, &iter_b, f, BM_VERTS_OF_FACE) {
+ if (neighbor_v != v && BM_elem_flag_test(neighbor_v, BM_ELEM_TAG)) {
+ return false;
+ }
+ }
+ }
+ }
+ if (BM_vert_is_boundary(v)) {
+ /* Un-tagged vertex in boundary without connected tagged vertices. */
+ bool any_tagged = false;
+ BM_ITER_ELEM (f, &iter_a, v, BM_FACES_OF_VERT) {
+ BM_ITER_ELEM (neighbor_v, &iter_b, f, BM_VERTS_OF_FACE) {
+ if (neighbor_v != v && BM_elem_flag_test(neighbor_v, BM_ELEM_TAG)) {
+ any_tagged = true;
+ }
+ }
+ }
+ if (!any_tagged) {
+ return false;
+ }
+ }
+ }
+ }
+
+ return true;
+}
+
+/**
+ * Search and validates an un-subdivide solution for a given element ID.
+ */
+static bool unsubdivide_tag_disconnected_mesh_element(BMesh *bm, int *elem_id, int elem)
+{
+ /* First, get vertex candidates to try to generate possible un-subdivide solution. */
+ /* Find a vertex pole. If there is a solution on an all quad base mesh, this vertex should be
+ * part of the base mesh. If it isn't, then there is no solution. */
+ GSQueue *initial_vertex = BLI_gsqueue_new(sizeof(BMVert *));
+ BMVert *initial_vertex_pole = unsubdivide_find_any_pole(bm, elem_id, elem);
+ if (initial_vertex_pole != NULL) {
+ BLI_gsqueue_push(initial_vertex, &initial_vertex_pole);
+ }
+
+ /* Also try from the different 4 vertices of a quad in the current
+ * disconnected element ID. If a solution exists the search should return a valid solution from
+ * one of these vertices.*/
+ BMFace *f, *init_face = NULL;
+ BMVert *v;
+ BMIter iter_a, iter_b;
+ BM_ITER_MESH (f, &iter_a, bm, BM_FACES_OF_MESH) {
+ BM_ITER_ELEM (v, &iter_b, f, BM_VERTS_OF_FACE) {
+ if (is_vertex_in_id(v, elem_id, elem)) {
+ init_face = f;
+ break;
+ }
+ }
+ if (init_face != NULL) {
+ break;
+ }
+ }
+
+ BM_ITER_ELEM (v, &iter_a, init_face, BM_VERTS_OF_FACE) {
+ BLI_gsqueue_push(initial_vertex, &v);
+ }
+
+ bool valid_tag_found = false;
+
+ /* Check all vertex candidates to a solution. */
+ while (!BLI_gsqueue_is_empty(initial_vertex)) {
+
+ BMVert *iv;
+ BLI_gsqueue_pop(initial_vertex, &iv);
+
+ /* Generate a possible solution. */
+ unsubdivide_face_center_vertex_tag(bm, iv);
+
+ /* Check if the solution is valid. If it is, stop searching. */
+ if (unsubdivide_is_center_vertex_tag_valid(bm, elem_id, elem)) {
+ valid_tag_found = true;
+ break;
+ }
+
+ /* If the solution is not valid, reset the state of all tags in this disconnected element ID
+ * and try again. */
+ BMVert *v_reset;
+ BMIter iter;
+ BM_ITER_MESH (v_reset, &iter, bm, BM_VERTS_OF_MESH) {
+ if (is_vertex_in_id(v_reset, elem_id, elem)) {
+ BM_elem_flag_set(v_reset, BM_ELEM_TAG, false);
+ }
+ }
+ }
+ BLI_gsqueue_free(initial_vertex);
+ return valid_tag_found;
+}
+
+/**
+ * Uses a flood fill operation to generate a different ID for each disconnected mesh element.
+ */
+static int unsubdivide_init_elem_ids(BMesh *bm, int *elem_id)
+{
+ bool *visited_vertices = MEM_calloc_arrayN(sizeof(bool), bm->totvert, "visited vertices");
+ int current_id = 0;
+ for (int i = 0; i < bm->totvert; i++) {
+ if (!visited_vertices[i]) {
+ GSQueue *queue;
+ queue = BLI_gsqueue_new(sizeof(BMVert *));
+
+ visited_vertices[i] = true;
+ elem_id[i] = current_id;
+ BMVert *iv = BM_vert_at_index(bm, i);
+ BLI_gsqueue_push(queue, &iv);
+
+ while (!BLI_gsqueue_is_empty(queue)) {
+ BMIter iter;
+ BMVert *current_v, *neighbor_v;
+ BMEdge *ed;
+ BLI_gsqueue_pop(queue, &current_v);
+ BM_ITER_ELEM (ed, &iter, current_v, BM_EDGES_OF_VERT) {
+ neighbor_v = BM_edge_other_vert(ed, current_v);
+ const int neighbor_index = BM_elem_index_get(neighbor_v);
+ if (!visited_vertices[neighbor_index]) {
+ visited_vertices[neighbor_index] = true;
+ elem_id[neighbor_index] = current_id;
+ BLI_gsqueue_push(queue, &neighbor_v);
+ }
+ }
+ }
+ current_id++;
+ BLI_gsqueue_free(queue);
+ }
+ }
+ MEM_freeN(visited_vertices);
+ return current_id;
+}
+
+/**
+ * Builds a base mesh one subdivision level down from the current original mesh if the original
+ * mesh has a valid solution stored in the #BMVert tags.
+ */
+static void unsubdivide_build_base_mesh_from_tags(BMesh *bm)
+{
+ BMVert *v;
+ BMIter iter;
+
+ /* Stores the vertices which correspond to (1, 0) and (0, 1) of the grids in the select flag. */
+ BM_mesh_elem_hflag_enable_all(bm, BM_VERT | BM_EDGE | BM_FACE, BM_ELEM_SELECT, false);
+ BMVert *v_neighbor;
+ BMIter iter_a;
+ BMEdge *ed;
+ BM_ITER_MESH (v, &iter, bm, BM_VERTS_OF_MESH) {
+ BM_ITER_ELEM (ed, &iter_a, v, BM_EDGES_OF_VERT) {
+ v_neighbor = BM_edge_other_vert(ed, v);
+ if (BM_elem_flag_test(v_neighbor, BM_ELEM_TAG)) {
+ BM_elem_flag_set(v, BM_ELEM_SELECT, false);
+ }
+ }
+ }
+
+ /* Dissolves the (0,0) vertices of the grids. */
+ BMO_op_callf(bm,
+ (BMO_FLAG_DEFAULTS & ~BMO_FLAG_RESPECT_HIDE),
+ "dissolve_verts verts=%hv use_face_split=%b use_boundary_tear=%b",
+ BM_ELEM_TAG,
+ false,
+ true);
+
+ BM_mesh_elem_hflag_disable_all(bm, BM_VERT | BM_EDGE | BM_FACE, BM_ELEM_TAG, false);
+
+ /* Copy the select flag to the tag flag. */
+ BM_ITER_MESH (v, &iter, bm, BM_VERTS_OF_MESH) {
+ if (!BM_elem_flag_test(v, BM_ELEM_SELECT)) {
+ BM_elem_flag_set(v, BM_ELEM_TAG, true);
+ }
+ }
+
+ /* Dissolves the (1,0) and (0,1) vertices of the grids. */
+ BMO_op_callf(bm,
+ (BMO_FLAG_DEFAULTS & ~BMO_FLAG_RESPECT_HIDE),
+ "dissolve_verts verts=%hv use_face_split=%b use_boundary_tear=%b",
+ BM_ELEM_TAG,
+ false,
+ true);
+}
+
+/**
+ * Main function to get a base mesh one level down from the current original mesh if it exists.
+ *
+ * This searches for different un-subdivide solutions and stores them as a combination of #BMVert
+ * flags for each disconnected mesh element.
+ *
+ * If the solution for all elements are valid, it builds a new base mesh based on those tags by
+ * dissolving and merging vertices.
+ */
+static bool multires_unsubdivide_single_level(BMesh *bm)
+{
+
+ /* Do a first check to make sure that it makes sense to search for un-subdivision in this mesh.
+ */
+ if (!unsubdivide_is_all_quads(bm)) {
+ return false;
+ };
+
+ /* Initialize the vertex table. */
+ BM_mesh_elem_table_init(bm, BM_VERT);
+ BM_mesh_elem_table_ensure(bm, BM_VERT);
+
+ /* Build disconnected elements IDs. Each disconnected mesh element is evaluated separately. */
+ int *elem_id = MEM_calloc_arrayN(sizeof(int), bm->totvert, " ELEM ID");
+ const int tot_ids = unsubdivide_init_elem_ids(bm, elem_id);
+
+ bool valid_tag_found = true;
+
+ /* Reset the #BMesh flags as they are used to store data during the un-subdivide process. */
+ BM_mesh_elem_hflag_disable_all(bm, BM_VERT | BM_EDGE | BM_FACE, BM_ELEM_TAG, false);
+ BM_mesh_elem_hflag_disable_all(bm, BM_VERT | BM_EDGE | BM_FACE, BM_ELEM_SELECT, false);
+
+ /* For each disconnected mesh element ID, search if an un-subdivide solution is possible. The
+ * whole un-subdivide process fails if a single disconnected mesh element fails. */
+ for (int id = 0; id < tot_ids; id++) {
+ /* Try to the #BMesh vertex flag tags corresponding to an un-subdivide solution. */
+ if (!unsubdivide_tag_disconnected_mesh_element(bm, elem_id, id)) {
+ valid_tag_found = false;
+ break;
+ }
+ }
+
+ /* If a solution was found for all elements IDs, build the new base mesh using the solution
+ * stored in the BMVert tags. */
+ if (valid_tag_found) {
+ unsubdivide_build_base_mesh_from_tags(bm);
+ }
+
+ MEM_freeN(elem_id);
+ return valid_tag_found;
+}
+
+/**
+ * Returns the next edge and vertex in the direction of a given edge.
+ */
+static BMEdge *edge_step(BMVert *v, BMEdge *edge, BMVert **r_next_vertex)
+{
+ BMIter iter;
+ BMEdge *test_edge;
+ if (edge == NULL) {
+ (*r_next_vertex) = v;
+ return edge;
+ }
+ (*r_next_vertex) = BM_edge_other_vert(edge, v);
+ BM_ITER_ELEM (test_edge, &iter, (*r_next_vertex), BM_EDGES_OF_VERT) {
+ if (!BM_edge_share_quad_check(test_edge, edge)) {
+ return test_edge;
+ }
+ }
+ return NULL;
+}
+
+static BMFace *face_step(BMEdge *edge, BMFace *f)
+{
+ BMIter iter;
+ BMFace *face_iter;
+
+ BM_ITER_ELEM (face_iter, &iter, edge, BM_FACES_OF_EDGE) {
+ if (BM_face_share_edge_check(face_iter, f)) {
+ return face_iter;
+ }
+ }
+ return f;
+}
+
+/**
+ * Returns the other edge which belongs to the face f which is different from edge_x and shares
+ * initial_vertex.
+ */
+static BMEdge *get_initial_edge_y(BMFace *f, BMEdge *edge_x, BMVert *initial_vertex)
+{
+ BMIter iter;
+ BMEdge *test_edge;
+ BM_ITER_ELEM (test_edge, &iter, f, BM_EDGES_OF_FACE) {
+ if (edge_x != test_edge) {
+ if (test_edge->v1 != initial_vertex && test_edge->v2 == initial_vertex) {
+ return test_edge;
+ }
+ if (test_edge->v2 != initial_vertex && test_edge->v1 == initial_vertex) {
+ return test_edge;
+ }
+ }
+ }
+ return NULL;
+}
+
+/**
+ * Writes the current mdisp data into the corresponding area of quad poly giving its corner's loop.
+ */
+static void write_loop_in_face_grid(
+ float (*face_grid)[3], MDisps *mdisp, int face_grid_size, int orig_grid_size, int loop)
+{
+ int origin[2];
+ int step_x[2];
+ int step_y[2];
+
+ const int grid_offset = orig_grid_size - 1;
+ origin[0] = grid_offset;
+ origin[1] = grid_offset;
+
+ switch (loop) {
+ case 0:
+ step_x[0] = -1;
+ step_x[1] = 0;
+
+ step_y[0] = 0;
+ step_y[1] = -1;
+
+ break;
+ case 1:
+ step_x[0] = 0;
+ step_x[1] = 1;
+
+ step_y[0] = -1;
+ step_y[1] = -0;
+ break;
+ case 2:
+ step_x[0] = 1;
+ step_x[1] = 0;
+
+ step_y[0] = 0;
+ step_y[1] = 1;
+ break;
+ case 3:
+ step_x[0] = 0;
+ step_x[1] = -1;
+
+ step_y[0] = 1;
+ step_y[1] = 0;
+ break;
+ default:
+ BLI_assert(!"Should never happen");
+ break;
+ }
+
+ for (int y = 0; y < orig_grid_size; y++) {
+ for (int x = 0; x < orig_grid_size; x++) {
+ const int remap_x = origin[1] + (step_x[1] * x) + (step_y[1] * y);
+ const int remap_y = origin[0] + (step_x[0] * x) + (step_y[0] * y);
+
+ const int final_index = remap_x + remap_y * face_grid_size;
+ copy_v3_v3(face_grid[final_index], mdisp->disps[x + y * orig_grid_size]);
+ }
+ }
+}
+
+/**
+ * Writes a buffer containing the 4 grids in the correct orientation of the 4 loops of a face into
+ * the main #MultiresUnsubdivideGrid that is being extracted.
+ */
+static void write_face_grid_in_unsubdivide_grid(MultiresUnsubdivideGrid *grid,
+ float (*face_grid)[3],
+ int face_grid_size,
+ int gunsub_x,
+ int gunsub_y)
+{
+ const int grid_it = face_grid_size - 1;
+ for (int y = 0; y < face_grid_size; y++) {
+ for (int x = 0; x < face_grid_size; x++) {
+ const int remap_x = (grid_it * gunsub_x) + x;
+ const int remap_y = (grid_it * gunsub_y) + y;
+
+ const int remap_index_y = grid->grid_size - remap_x - 1;
+ const int remap_index_x = grid->grid_size - remap_y - 1;
+ const int grid_index = remap_index_x + (remap_index_y * grid->grid_size);
+ copy_v3_v3(grid->grid_co[grid_index], face_grid[x + y * face_grid_size]);
+ }
+ }
+}
+
+/**
+ * Stores the data from the mdisps grids of the loops of the face f
+ * into the new grid for the new base mesh.
+ *
+ * Used when there are already grids in the original mesh.
+ */
+static void store_grid_data(MultiresUnsubdivideContext *context,
+ MultiresUnsubdivideGrid *grid,
+ BMVert *v,
+ BMFace *f,
+ int grid_x,
+ int grid_y)
+{
+
+ Mesh *original_mesh = context->original_mesh;
+ MPoly *poly = &original_mesh->mpoly[BM_elem_index_get(f)];
+
+ const int corner_vertex_index = BM_elem_index_get(v);
+
+ /* Calculates an offset to write the grids correctly oriented in the main
+ * #MultiresUnsubdivideGrid. */
+ int loop_offset = 0;
+ for (int i = 0; i < poly->totloop; i++) {
+ const int loop_index = poly->loopstart + i;
+ MLoop *l = &original_mesh->mloop[loop_index];
+ if (l->v == corner_vertex_index) {
+ loop_offset = i;
+ break;
+ }
+ }
+
+ /* Write the 4 grids of the current quad with the right orientation into the face_grid buffer. */
+ const int grid_size = BKE_ccg_gridsize(context->num_original_levels);
+ const int face_grid_size = BKE_ccg_gridsize(context->num_original_levels + 1);
+ const int face_grid_area = face_grid_size * face_grid_size;
+ float(*face_grid)[3] = MEM_calloc_arrayN(face_grid_area, 3 * sizeof(float), "face_grid");
+
+ for (int i = 0; i < poly->totloop; i++) {
+ const int loop_index = poly->loopstart + i;
+ MDisps *mdisp = &context->original_mdisp[loop_index];
+ int quad_loop = i - loop_offset;
+ if (quad_loop < 0) {
+ quad_loop += 4;
+ }
+ if (quad_loop >= 4) {
+ quad_loop -= 4;
+ }
+ write_loop_in_face_grid(face_grid, mdisp, face_grid_size, grid_size, quad_loop);
+ }
+
+ /* Write the face_grid buffer in the correct position in the #MultiresUnsubdivideGrids that is
+ * being extracted. */
+ write_face_grid_in_unsubdivide_grid(grid, face_grid, face_grid_size, grid_x, grid_y);
+
+ MEM_freeN(face_grid);
+}
+
+/**
+ * Stores the data into the new grid from a #BMVert.
+ * Used when there are no grids in the original mesh.
+ */
+static void store_vertex_data(MultiresUnsubdivideGrid *grid, BMVert *v, int grid_x, int grid_y)
+{
+ const int remap_index_y = grid->grid_size - 1 - grid_x;
+ const int remap_index_x = grid->grid_size - 1 - grid_y;
+
+ const int grid_index = remap_index_x + (remap_index_y * grid->grid_size);
+
+ copy_v3_v3(grid->grid_co[grid_index], v->co);
+}
+
+/**
+ * Main function to extract data from the original bmesh and MDISPS as grids for the new base mesh.
+ */
+static void multires_unsubdivide_extract_single_grid_from_face_edge(
+ MultiresUnsubdivideContext *context,
+ BMFace *f1,
+ BMEdge *e1,
+ bool flip_grid,
+ MultiresUnsubdivideGrid *grid)
+{
+ BMVert *initial_vertex;
+ BMEdge *initial_edge_x;
+ BMEdge *initial_edge_y;
+
+ const int grid_size = BKE_ccg_gridsize(context->num_new_levels);
+ const int unsubdiv_grid_size = grid->grid_size = BKE_ccg_gridsize(context->num_total_levels);
+ grid->grid_size = unsubdiv_grid_size;
+ grid->grid_co = MEM_calloc_arrayN(
+ unsubdiv_grid_size * unsubdiv_grid_size, 3 * sizeof(float), "grids coordinates");
+
+ /* Get the vertex on the corner of the grid. This vertex was tagged previously as it also exist
+ * on the base mesh. */
+ initial_edge_x = e1;
+ if (BM_elem_flag_test(initial_edge_x->v1, BM_ELEM_TAG)) {
+ initial_vertex = initial_edge_x->v1;
+ }
+ else {
+ initial_vertex = initial_edge_x->v2;
+ }
+
+ /* From that vertex, get the edge that defines the grid Y axis for extraction. */
+ initial_edge_y = get_initial_edge_y(f1, initial_edge_x, initial_vertex);
+
+ if (flip_grid) {
+ BMEdge *edge_temp;
+ edge_temp = initial_edge_x;
+ initial_edge_x = initial_edge_y;
+ initial_edge_y = edge_temp;
+ }
+
+ int grid_x = 0;
+ int grid_y = 0;
+
+ BMVert *current_vertex_x = initial_vertex;
+ BMEdge *edge_x = initial_edge_x;
+
+ BMVert *current_vertex_y = initial_vertex;
+ BMEdge *edge_y = initial_edge_y;
+ BMEdge *prev_edge_y = initial_edge_y;
+
+ BMFace *current_face = f1;
+ BMFace *grid_face = f1;
+
+ /* If the data is going to be extracted from the already existing grids, there is no need to go
+ * to the last vertex of the iteration as that coordinate is also included in the grids
+ * corresponding to the loop of the face of the previous iteration. */
+ int grid_iteration_max_steps = grid_size;
+ if (context->num_original_levels > 0) {
+ grid_iteration_max_steps = grid_size - 1;
+ }
+
+ /* Iterate over the mesh vertices in a grid pattern using the axis defined by the two initial
+ * edges. */
+ while (grid_y < grid_iteration_max_steps) {
+
+ grid_face = current_face;
+
+ while (grid_x < grid_iteration_max_steps) {
+ if (context->num_original_levels == 0) {
+ /* If there were no grids on the original mesh, extract the data directly from the
+ * vertices. */
+ store_vertex_data(grid, current_vertex_x, grid_x, grid_y);
+ edge_x = edge_step(current_vertex_x, edge_x, &current_vertex_x);
+ }
+ else {
+ /* If there were grids in the original mesh, extract the data from the grids and iterate
+ * over the faces. */
+ store_grid_data(context, grid, current_vertex_x, grid_face, grid_x, grid_y);
+ edge_x = edge_step(current_vertex_x, edge_x, &current_vertex_x);
+ grid_face = face_step(edge_x, grid_face);
+ }
+
+ grid_x++;
+ }
+ grid_x = 0;
+
+ edge_y = edge_step(current_vertex_y, edge_y, &current_vertex_y);
+ current_vertex_x = current_vertex_y;
+
+ /* Get the next edge_x to extract the next row of the grid. This needs to be done because there
+ * may be two edges connected to current_vertex_x that belong to two different grids. */
+ BMIter iter;
+ BMEdge *ed;
+ BMFace *f;
+ BM_ITER_ELEM (ed, &iter, current_vertex_x, BM_EDGES_OF_VERT) {
+ if (ed != prev_edge_y && BM_edge_in_face(ed, current_face)) {
+ edge_x = ed;
+ break;
+ }
+ }
+ BM_ITER_ELEM (f, &iter, edge_x, BM_FACES_OF_EDGE) {
+ if (f != current_face) {
+ current_face = f;
+ break;
+ }
+ }
+
+ prev_edge_y = edge_y;
+ grid_y++;
+ }
+}
+
+/**
+ * Returns the l+1 and l-1 vertices of the base mesh poly were the grid from the face f1 and edge
+ * e1 is going to be extracted.
+ *
+ * These vertices should always have an corresponding existing vertex on the base mesh.
+ */
+static void multires_unsubdivide_get_grid_corners_on_base_mesh(BMFace *f1,
+ BMEdge *e1,
+ BMVert **r_corner_x,
+ BMVert **r_corner_y)
+{
+ BMVert *initial_vertex;
+ BMEdge *initial_edge_x;
+ BMEdge *initial_edge_y;
+
+ initial_edge_x = e1;
+ if (BM_elem_flag_test(initial_edge_x->v1, BM_ELEM_TAG)) {
+ initial_vertex = initial_edge_x->v1;
+ }
+ else {
+ initial_vertex = initial_edge_x->v2;
+ }
+
+ /* From that vertex, get the edge that defines the grid Y axis for extraction. */
+ initial_edge_y = get_initial_edge_y(f1, initial_edge_x, initial_vertex);
+
+ BMVert *current_vertex_x = initial_vertex;
+ BMEdge *edge_x = initial_edge_x;
+
+ BMVert *current_vertex_y = initial_vertex;
+ BMEdge *edge_y = initial_edge_y;
+
+ /* Do an edge step until it finds a tagged vertex, which is part of the base mesh. */
+ /* x axis */
+ edge_x = edge_step(current_vertex_x, edge_x, &current_vertex_x);
+ while (!BM_elem_flag_test(current_vertex_x, BM_ELEM_TAG)) {
+ edge_x = edge_step(current_vertex_x, edge_x, &current_vertex_x);
+ }
+ (*r_corner_x) = current_vertex_x;
+
+ /* Same for y axis */
+ edge_y = edge_step(current_vertex_y, edge_y, &current_vertex_y);
+ while (!BM_elem_flag_test(current_vertex_y, BM_ELEM_TAG)) {
+ edge_y = edge_step(current_vertex_y, edge_y, &current_vertex_y);
+ }
+ (*r_corner_y) = current_vertex_y;
+}
+
+static BMesh *get_bmesh_from_mesh(Mesh *mesh)
+{
+ const BMAllocTemplate allocsize = BMALLOC_TEMPLATE_FROM_ME(mesh);
+ BMesh *bm = BM_mesh_create(&allocsize,
+ &((struct BMeshCreateParams){
+ .use_toolflags = true,
+ }));
+
+ BM_mesh_bm_from_me(bm,
+ mesh,
+ (&(struct BMeshFromMeshParams){
+ .calc_face_normal = true,
+ }));
+
+ return bm;
+}
+
+/* Data-layer names to store the original indices of the elements before modifying the mesh. */
+static const char lname[] = "l_remap_index";
+static const char vname[] = "v_remap_index";
+
+static void multires_unsubdivide_free_original_datalayers(Mesh *mesh)
+{
+ const int l_layer_index = CustomData_get_named_layer_index(&mesh->ldata, CD_PROP_INT, lname);
+ if (l_layer_index != -1) {
+ CustomData_free_layer(&mesh->ldata, CD_PROP_INT, mesh->totloop, l_layer_index);
+ }
+
+ const int v_layer_index = CustomData_get_named_layer_index(&mesh->vdata, CD_PROP_INT, vname);
+ if (v_layer_index != -1) {
+ CustomData_free_layer(&mesh->vdata, CD_PROP_INT, mesh->totvert, v_layer_index);
+ }
+}
+
+/**
+ * Generates two data-layers to map loops and vertices from base mesh to original mesh after
+ * dissolving the vertices.
+ */
+static void multires_unsubdivide_add_original_index_datalayers(Mesh *mesh)
+{
+ multires_unsubdivide_free_original_datalayers(mesh);
+
+ int *l_index = CustomData_add_layer_named(
+ &mesh->ldata, CD_PROP_INT, CD_CALLOC, NULL, mesh->totloop, lname);
+
+ int *v_index = CustomData_add_layer_named(
+ &mesh->vdata, CD_PROP_INT, CD_CALLOC, NULL, mesh->totvert, vname);
+
+ /* Initialize these data-layer with the indices in the current mesh. */
+ for (int i = 0; i < mesh->totloop; i++) {
+ l_index[i] = i;
+ }
+ for (int i = 0; i < mesh->totvert; i++) {
+ v_index[i] = i;
+ }
+}
+
+static void multires_unsubdivide_prepare_original_bmesh_for_extract(
+ MultiresUnsubdivideContext *context)
+{
+
+ Mesh *original_mesh = context->original_mesh;
+ Mesh *base_mesh = context->base_mesh;
+
+ BMesh *bm_original_mesh = context->bm_original_mesh = get_bmesh_from_mesh(original_mesh);
+
+ /* Initialize the elem tables. */
+ BM_mesh_elem_table_ensure(bm_original_mesh, BM_EDGE);
+ BM_mesh_elem_table_ensure(bm_original_mesh, BM_FACE);
+ BM_mesh_elem_table_ensure(bm_original_mesh, BM_VERT);
+
+ /* Disable all flags. */
+ BM_mesh_elem_hflag_disable_all(
+ bm_original_mesh, BM_VERT | BM_EDGE | BM_FACE, BM_ELEM_TAG, false);
+ BM_mesh_elem_hflag_disable_all(
+ bm_original_mesh, BM_VERT | BM_EDGE | BM_FACE, BM_ELEM_SELECT, false);
+
+ /* Get the mapping data-layer. */
+ context->base_to_orig_vmap = CustomData_get_layer_named(&base_mesh->vdata, CD_PROP_INT, vname);
+
+ /* Tag the base mesh vertices in the original mesh. */
+ for (int i = 0; i < base_mesh->totvert; i++) {
+ int vert_basemesh_index = context->base_to_orig_vmap[i];
+ BMVert *v = BM_vert_at_index(bm_original_mesh, vert_basemesh_index);
+ BM_elem_flag_set(v, BM_ELEM_TAG, true);
+ }
+
+ /* Create a map from loop index to poly index for the original mesh. */
+ context->loop_to_face_map = MEM_calloc_arrayN(sizeof(int), original_mesh->totloop, "loop map");
+
+ for (int i = 0; i < original_mesh->totpoly; i++) {
+ MPoly *poly = &original_mesh->mpoly[i];
+ for (int l = 0; l < poly->totloop; l++) {
+ int original_loop_index = l + poly->loopstart;
+ context->loop_to_face_map[original_loop_index] = i;
+ }
+ }
+}
+
+/**
+ * Checks the orientation of the loops to flip the x and y axis when extracting the grid if
+ * necessary.
+ */
+static bool multires_unsubdivide_flip_grid_x_axis(Mesh *mesh, int poly, int loop, int v_x)
+{
+ MPoly *p = &mesh->mpoly[poly];
+
+ MLoop *l_first = &mesh->mloop[p->loopstart];
+ if ((loop == (p->loopstart + (p->totloop - 1))) && l_first->v == v_x) {
+ return true;
+ }
+
+ int next_l_index = loop + 1;
+ if (next_l_index < p->loopstart + p->totloop) {
+ MLoop *l_next = &mesh->mloop[next_l_index];
+ if (l_next->v == v_x) {
+ return true;
+ }
+ }
+
+ return false;
+}
+
+static void multires_unsubdivide_extract_grids(MultiresUnsubdivideContext *context)
+{
+ Mesh *original_mesh = context->original_mesh;
+ Mesh *base_mesh = context->base_mesh;
+
+ BMesh *bm_original_mesh = context->bm_original_mesh;
+
+ context->num_grids = base_mesh->totloop;
+ context->base_mesh_grids = MEM_calloc_arrayN(
+ sizeof(MultiresUnsubdivideGrid), base_mesh->totloop, "grids");
+
+ /* Based on the existing indices in the data-layers, generate two vertex indices maps. */
+ /* From vertex index in original to vertex index in base and from vertex index in base to vertex
+ * index in original. */
+ int *orig_to_base_vmap = MEM_calloc_arrayN(sizeof(int), bm_original_mesh->totvert, "orig vmap");
+ int *base_to_orig_vmap = MEM_calloc_arrayN(sizeof(int), base_mesh->totvert, "base vmap");
+
+ context->base_to_orig_vmap = CustomData_get_layer_named(&base_mesh->vdata, CD_PROP_INT, vname);
+ for (int i = 0; i < base_mesh->totvert; i++) {
+ base_to_orig_vmap[i] = context->base_to_orig_vmap[i];
+ }
+
+ /* If an index in original does not exist in base (it was dissolved when creating the new base
+ * mesh, return -1. */
+ for (int i = 0; i < original_mesh->totvert; i++) {
+ orig_to_base_vmap[i] = -1;
+ }
+
+ for (int i = 0; i < base_mesh->totvert; i++) {
+ const int orig_vertex_index = context->base_to_orig_vmap[i];
+ orig_to_base_vmap[orig_vertex_index] = i;
+ }
+
+ /* Add the original data-layers to the base mesh to have the loop indices stored in a data-layer,
+ * so they can be used from #BMesh. */
+ multires_unsubdivide_add_original_index_datalayers(base_mesh);
+
+ const int base_l_layer_index = CustomData_get_named_layer_index(
+ &base_mesh->ldata, CD_PROP_INT, lname);
+ BMesh *bm_base_mesh = get_bmesh_from_mesh(base_mesh);
+ BMIter iter, iter_a, iter_b;
+ BMVert *v;
+ BMLoop *l, *lb;
+
+ BM_mesh_elem_table_ensure(bm_base_mesh, BM_VERT);
+ BM_mesh_elem_table_ensure(bm_base_mesh, BM_FACE);
+
+ /* Get the data-layer that contains the loops indices. */
+ const int base_l_offset = CustomData_get_n_offset(
+ &bm_base_mesh->ldata, CD_PROP_INT, base_l_layer_index);
+
+ /* Main loop for extracting the grids. Iterates over the base mesh vertices. */
+ BM_ITER_MESH (v, &iter, bm_base_mesh, BM_VERTS_OF_MESH) {
+
+ /* For each base mesh vertex, get the corresponding #BMVert of the original mesh using the
+ * vertex map. */
+ const int orig_vertex_index = base_to_orig_vmap[BM_elem_index_get(v)];
+ BMVert *vert_original = BM_vert_at_index(bm_original_mesh, orig_vertex_index);
+
+ /* Iterate over the loops of that vertex in the original mesh. */
+ BM_ITER_ELEM (l, &iter_a, vert_original, BM_LOOPS_OF_VERT) {
+ /* For each loop, get the two vertices that should map to the l+1 and l-1 vertices in the
+ * base mesh of the poly of grid that is going to be extracted. */
+ BMVert *corner_x, *corner_y;
+ multires_unsubdivide_get_grid_corners_on_base_mesh(l->f, l->e, &corner_x, &corner_y);
+
+ /* Map the two obtained vertices to the base mesh. */
+ const int corner_x_index = orig_to_base_vmap[BM_elem_index_get(corner_x)];
+ const int corner_y_index = orig_to_base_vmap[BM_elem_index_get(corner_y)];
+
+ /* Iterate over the loops of the same vertex in the base mesh. With the previously obtained
+ * vertices and the current vertex it is possible to get the index of the loop in the base
+ * mesh the grid that is going to be extracted belongs to. */
+ BM_ITER_ELEM (lb, &iter_b, v, BM_LOOPS_OF_VERT) {
+ BMFace *base_face = lb->f;
+ BMVert *base_corner_x = BM_vert_at_index(bm_base_mesh, corner_x_index);
+ BMVert *base_corner_y = BM_vert_at_index(bm_base_mesh, corner_y_index);
+ /* If this is the correct loop in the base mesh, the original vertex and the two corners
+ * should be in the loop's face. */
+ if (BM_vert_in_face(base_corner_x, base_face) &&
+ BM_vert_in_face(base_corner_y, base_face)) {
+ /* Get the index of the loop. */
+ const int base_mesh_loop_index = BM_ELEM_CD_GET_INT(lb, base_l_offset);
+ const int base_mesh_face_index = BM_elem_index_get(base_face);
+
+ /* Check the orientation of the loops in case that is needed to flip the x and y axis
+ * when extracting the grid. */
+ const bool flip_grid = multires_unsubdivide_flip_grid_x_axis(
+ base_mesh, base_mesh_face_index, base_mesh_loop_index, corner_x_index);
+
+ /* Extract the grid for that loop. */
+ context->base_mesh_grids[base_mesh_loop_index].grid_index = base_mesh_loop_index;
+ multires_unsubdivide_extract_single_grid_from_face_edge(
+ context, l->f, l->e, !flip_grid, &context->base_mesh_grids[base_mesh_loop_index]);
+
+ break;
+ }
+ }
+ }
+ }
+
+ MEM_freeN(orig_to_base_vmap);
+ MEM_freeN(base_to_orig_vmap);
+
+ BM_mesh_free(bm_base_mesh);
+ multires_unsubdivide_free_original_datalayers(base_mesh);
+}
+
+static void multires_unsubdivide_private_extract_data_free(MultiresUnsubdivideContext *context)
+{
+ if (context->bm_original_mesh != NULL) {
+ BM_mesh_free(context->bm_original_mesh);
+ }
+ MEM_SAFE_FREE(context->loop_to_face_map);
+}
+
+void multires_unsubdivide_context_init(MultiresUnsubdivideContext *context,
+ Mesh *original_mesh,
+ struct MultiresModifierData *mmd)
+{
+ context->original_mesh = original_mesh;
+ context->num_new_levels = 0;
+ context->num_total_levels = 0;
+ context->num_original_levels = mmd->totlvl;
+}
+
+bool multires_unsubdivide_to_basemesh(MultiresUnsubdivideContext *context)
+{
+ Mesh *original_mesh = context->original_mesh;
+
+ /* Prepare the data-layers to map base to original. */
+ multires_unsubdivide_add_original_index_datalayers(original_mesh);
+ BMesh *bm_base_mesh = get_bmesh_from_mesh(original_mesh);
+
+ /* Un-subdivide as many iterations as possible. */
+ context->num_new_levels = 0;
+ int num_levels_left = context->max_new_levels;
+ while (num_levels_left > 0 && multires_unsubdivide_single_level(bm_base_mesh)) {
+ context->num_new_levels++;
+ num_levels_left--;
+ }
+
+ /* If no un-subdivide steps were possible, free the bmesh, the map data-layers and stop. */
+ if (context->num_new_levels == 0) {
+ multires_unsubdivide_free_original_datalayers(original_mesh);
+ BM_mesh_free(bm_base_mesh);
+ return false;
+ }
+
+ /* Calculate the final levels for the new grids over base mesh. */
+ context->num_total_levels = context->num_new_levels + context->num_original_levels;
+
+ /* Store the new base-mesh as a mesh in context, free bmesh. */
+ context->base_mesh = BKE_mesh_new_nomain(0, 0, 0, 0, 0);
+ BM_mesh_bm_to_me(NULL,
+ bm_base_mesh,
+ context->base_mesh,
+ (&(struct BMeshToMeshParams){
+ .calc_object_remap = true,
+ }));
+ BM_mesh_free(bm_base_mesh);
+
+ /* Initialize bmesh and maps for the original mesh and extract the grids. */
+
+ multires_unsubdivide_prepare_original_bmesh_for_extract(context);
+ multires_unsubdivide_extract_grids(context);
+
+ return true;
+}
+
+void multires_unsubdivide_context_free(MultiresUnsubdivideContext *context)
+{
+ multires_unsubdivide_private_extract_data_free(context);
+ for (int i = 0; i < context->num_grids; i++) {
+ if (context->base_mesh_grids[i].grid_size > 0) {
+ MEM_SAFE_FREE(context->base_mesh_grids[i].grid_co);
+ }
+ }
+ MEM_SAFE_FREE(context->base_mesh_grids);
+}
+
+/**
+ * This function allocates new mdisps with the right size to fit the new extracted grids from the
+ * base mesh and copies the data to them.
+ */
+static void multires_create_grids_in_unsubdivided_base_mesh(MultiresUnsubdivideContext *context,
+ Mesh *base_mesh)
+{
+ /* Free the current MDISPS and create a new ones. */
+ if (CustomData_has_layer(&base_mesh->ldata, CD_MDISPS)) {
+ CustomData_free_layers(&base_mesh->ldata, CD_MDISPS, base_mesh->totloop);
+ }
+ MDisps *mdisps = CustomData_add_layer(
+ &base_mesh->ldata, CD_MDISPS, CD_CALLOC, NULL, base_mesh->totloop);
+
+ const int totdisp = pow_i(BKE_ccg_gridsize(context->num_total_levels), 2);
+ const int totloop = base_mesh->totloop;
+
+ BLI_assert(base_mesh->totloop == context->num_grids);
+
+ /* Allocate the MDISPS grids and copy the extracted data from context. */
+ for (int i = 0; i < totloop; i++) {
+ float(*disps)[3] = MEM_calloc_arrayN(totdisp, 3 * sizeof(float), "multires disps");
+
+ if (mdisps[i].disps) {
+ MEM_freeN(mdisps[i].disps);
+ }
+
+ for (int j = 0; j < totdisp; j++) {
+ if (context->base_mesh_grids[i].grid_co) {
+ copy_v3_v3(disps[j], context->base_mesh_grids[i].grid_co[j]);
+ }
+ }
+
+ mdisps[i].disps = disps;
+ mdisps[i].totdisp = totdisp;
+ mdisps[i].level = context->num_total_levels;
+ }
+}
+
+int multiresModifier_rebuild_subdiv(struct Depsgraph *depsgraph,
+ struct Object *object,
+ struct MultiresModifierData *mmd,
+ int rebuild_limit,
+ bool switch_view_to_lower_level)
+{
+ Mesh *mesh = object->data;
+
+ multires_force_sculpt_rebuild(object);
+
+ MultiresUnsubdivideContext unsubdiv_context = {0};
+ MultiresReshapeContext reshape_context = {0};
+
+ multires_unsubdivide_context_init(&unsubdiv_context, mesh, mmd);
+
+ /* Convert and store the existing grids in object space if available. */
+ if (mmd->totlvl != 0) {
+ if (!multires_reshape_context_create_from_object(&reshape_context, depsgraph, object, mmd)) {
+ return 0;
+ }
+
+ multires_reshape_store_original_grids(&reshape_context);
+ multires_reshape_assign_final_coords_from_mdisps(&reshape_context);
+ unsubdiv_context.original_mdisp = reshape_context.mdisps;
+ }
+
+ /* Set the limit for the levels that should be rebuild. */
+ unsubdiv_context.max_new_levels = rebuild_limit;
+
+ /* Un-subdivide and create the data for the new grids. */
+ if (multires_unsubdivide_to_basemesh(&unsubdiv_context) == 0) {
+ /* If there was no possible to rebuild any level, free the data and return. */
+ if (mmd->totlvl != 0) {
+ multires_reshape_object_grids_to_tangent_displacement(&reshape_context);
+ multires_unsubdivide_context_free(&unsubdiv_context);
+ }
+ multires_reshape_context_free(&reshape_context);
+ return 0;
+ }
+
+ /* Free the reshape context used to convert the data from the original grids to object space. */
+ if (mmd->totlvl != 0) {
+ multires_reshape_context_free(&reshape_context);
+ }
+
+ /* Copy the new base mesh to the original mesh. */
+ BKE_mesh_nomain_to_mesh(unsubdiv_context.base_mesh, object->data, object, &CD_MASK_MESH, true);
+ Mesh *base_mesh = object->data;
+ multires_create_grids_in_unsubdivided_base_mesh(&unsubdiv_context, base_mesh);
+
+ /* Update the levels in the modifier. Force always to display at level 0 as it contains the new
+ * created level. */
+ mmd->totlvl = (char)unsubdiv_context.num_total_levels;
+
+ if (switch_view_to_lower_level) {
+ mmd->sculptlvl = 0;
+ mmd->lvl = 0;
+ }
+ else {
+ mmd->sculptlvl = (char)(mmd->sculptlvl + unsubdiv_context.num_new_levels);
+ mmd->lvl = (char)(mmd->lvl + unsubdiv_context.num_new_levels);
+ }
+
+ mmd->renderlvl = (char)(mmd->renderlvl + unsubdiv_context.num_new_levels);
+
+ /* Create a reshape context to convert the MDISPS data to tangent displacement. It can be the
+ * same as the previous one as a new Subdivision needs to be created for the new base mesh. */
+ if (!multires_reshape_context_create_from_base_mesh(&reshape_context, depsgraph, object, mmd)) {
+ return 0;
+ }
+ multires_reshape_object_grids_to_tangent_displacement(&reshape_context);
+ multires_reshape_context_free(&reshape_context);
+
+ /* Free the un-subdivide context and return the total number of levels that were rebuild. */
+ const int rebuild_subdvis = unsubdiv_context.num_new_levels;
+ multires_unsubdivide_context_free(&unsubdiv_context);
+
+ return rebuild_subdvis;
+}
diff --git a/source/blender/blenkernel/intern/multires_unsubdivide.h b/source/blender/blenkernel/intern/multires_unsubdivide.h
new file mode 100644
index 00000000000..e00a1ae6d8b
--- /dev/null
+++ b/source/blender/blenkernel/intern/multires_unsubdivide.h
@@ -0,0 +1,94 @@
+/*
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * The Original Code is Copyright (C) 2020 Blender Foundation.
+ * All rights reserved.
+ */
+
+/** \file
+ * \ingroup bke
+ */
+
+#ifndef __BKE_INTERN_MULTIRES_UNSUBDIVIDE_H__
+#define __BKE_INTERN_MULTIRES_UNSUBDIVIDE_H__
+
+#include "BLI_sys_types.h"
+
+struct BMesh;
+struct Depsgraph;
+struct Mesh;
+struct MultiresModifierData;
+struct Object;
+
+typedef struct MultiresUnsubdivideGrid {
+ /* For sanity checks. */
+ int grid_index;
+ int grid_size;
+
+ /** Grid coordinates in object space. */
+ float (*grid_co)[3];
+
+} MultiresUnsubdivideGrid;
+
+typedef struct MultiresUnsubdivideContext {
+ /* Input Mesh to un-subdivide. */
+ struct Mesh *original_mesh;
+ struct MDisps *original_mdisp;
+
+ /** Number of subdivision in the grids of the input mesh. */
+ int num_original_levels;
+
+ /** Level 0 base mesh after applying the maximum amount of unsubdivisions. */
+ struct Mesh *base_mesh;
+
+ /** Limit on how many levels down the unsubdivide operation should create, if possible. */
+ int max_new_levels;
+
+ /** New levels that were created after unsubdividing. */
+ int num_new_levels;
+
+ /**
+ * Number of subdivisions that should be applied to the base mesh.
+ * (num_new_levels + num_original_levels).
+ */
+ int num_total_levels;
+
+ /** Data for the new grids, indexed by base mesh loop index. */
+ int num_grids;
+ struct MultiresUnsubdivideGrid *base_mesh_grids;
+
+ /* Private data. */
+ struct BMesh *bm_original_mesh;
+ int *loop_to_face_map;
+ int *base_to_orig_vmap;
+} MultiresUnsubdivideContext;
+
+/* --------------------------------------------------------------------
+ * Construct/destruct reshape context.
+ */
+
+void multires_unsubdivide_context_init(MultiresUnsubdivideContext *context,
+ struct Mesh *original_mesh,
+ struct MultiresModifierData *mmd);
+void multires_unsubdivide_context_free(MultiresUnsubdivideContext *context);
+
+/* --------------------------------------------------------------------
+ * Rebuild Lower Subdivisions.
+ */
+
+/* Rebuilds all subdivision to the level 0 base mesh. */
+bool multires_unsubdivide_to_basemesh(MultiresUnsubdivideContext *context);
+
+#endif /* __BKE_INTERN_MULTIRES_UNSUBDIVIDE_H__ */
diff --git a/source/blender/blenkernel/intern/nla.c b/source/blender/blenkernel/intern/nla.c
index 6edccbccc76..7012688686b 100644
--- a/source/blender/blenkernel/intern/nla.c
+++ b/source/blender/blenkernel/intern/nla.c
@@ -49,6 +49,7 @@
#include "BKE_fcurve.h"
#include "BKE_global.h"
#include "BKE_lib_id.h"
+#include "BKE_lib_query.h"
#include "BKE_main.h"
#include "BKE_nla.h"
#include "BKE_sound.h"
@@ -91,7 +92,7 @@ void BKE_nlastrip_free(ListBase *strips, NlaStrip *strip, bool do_id_user)
// BKE_animremap_free();
/* free own F-Curves */
- free_fcurves(&strip->fcurves);
+ BKE_fcurves_free(&strip->fcurves);
/* free own F-Modifiers */
free_fmodifiers(&strip->modifiers);
@@ -197,7 +198,7 @@ NlaStrip *BKE_nlastrip_copy(Main *bmain,
}
/* copy F-Curves and modifiers */
- copy_fcurves(&strip_d->fcurves, &strip->fcurves);
+ BKE_fcurves_copy(&strip_d->fcurves, &strip->fcurves);
copy_fmodifiers(&strip_d->modifiers, &strip->modifiers);
/* make a copy of all the child-strips, one at a time */
@@ -425,6 +426,21 @@ NlaStrip *BKE_nla_add_soundstrip(Main *bmain, Scene *scene, Speaker *speaker)
return strip;
}
+/** Callback used by lib_query to walk over all ID usages (mimics `foreach_id` callback of
+ * `IDTypeInfo` structure). */
+void BKE_nla_strip_foreach_id(NlaStrip *strip, LibraryForeachIDData *data)
+{
+ BKE_LIB_FOREACHID_PROCESS(data, strip->act, IDWALK_CB_USER);
+
+ LISTBASE_FOREACH (FCurve *, fcu, &strip->fcurves) {
+ BKE_fcurve_foreach_id(fcu, data);
+ }
+
+ LISTBASE_FOREACH (NlaStrip *, substrip, &strip->strips) {
+ BKE_nla_strip_foreach_id(substrip, data);
+ }
+}
+
/* *************************************************** */
/* NLA Evaluation <-> Editing Stuff */
@@ -1478,12 +1494,12 @@ void BKE_nlastrip_validate_fcurves(NlaStrip *strip)
/* if controlling influence... */
if (strip->flag & NLASTRIP_FLAG_USR_INFLUENCE) {
/* try to get F-Curve */
- fcu = list_find_fcurve(&strip->fcurves, "influence", 0);
+ fcu = BKE_fcurve_find(&strip->fcurves, "influence", 0);
/* add one if not found */
if (fcu == NULL) {
/* make new F-Curve */
- fcu = MEM_callocN(sizeof(FCurve), "NlaStrip FCurve");
+ fcu = BKE_fcurve_create();
BLI_addtail(&strip->fcurves, fcu);
/* set default flags */
@@ -1509,12 +1525,12 @@ void BKE_nlastrip_validate_fcurves(NlaStrip *strip)
/* if controlling time... */
if (strip->flag & NLASTRIP_FLAG_USR_TIME) {
/* try to get F-Curve */
- fcu = list_find_fcurve(&strip->fcurves, "strip_time", 0);
+ fcu = BKE_fcurve_find(&strip->fcurves, "strip_time", 0);
/* add one if not found */
if (fcu == NULL) {
/* make new F-Curve */
- fcu = MEM_callocN(sizeof(FCurve), "NlaStrip FCurve");
+ fcu = BKE_fcurve_create();
BLI_addtail(&strip->fcurves, fcu);
/* set default flags */
diff --git a/source/blender/blenkernel/intern/node.c b/source/blender/blenkernel/intern/node.c
index 06ddf4a8582..48c6727add5 100644
--- a/source/blender/blenkernel/intern/node.c
+++ b/source/blender/blenkernel/intern/node.c
@@ -32,11 +32,13 @@
#include "DNA_action_types.h"
#include "DNA_anim_types.h"
+#include "DNA_gpencil_types.h"
#include "DNA_light_types.h"
#include "DNA_linestyle_types.h"
#include "DNA_material_types.h"
#include "DNA_node_types.h"
#include "DNA_scene_types.h"
+#include "DNA_simulation_types.h"
#include "DNA_texture_types.h"
#include "DNA_world_types.h"
@@ -50,11 +52,13 @@
#include "BLT_translation.h"
+#include "BKE_anim_data.h"
#include "BKE_animsys.h"
#include "BKE_global.h"
#include "BKE_idprop.h"
#include "BKE_idtype.h"
#include "BKE_lib_id.h"
+#include "BKE_lib_query.h"
#include "BKE_main.h"
#include "BKE_node.h"
@@ -65,7 +69,9 @@
#include "NOD_common.h"
#include "NOD_composite.h"
+#include "NOD_function.h"
#include "NOD_shader.h"
+#include "NOD_simulation.h"
#include "NOD_socket.h"
#include "NOD_texture.h"
@@ -85,7 +91,9 @@ static void ntree_set_typeinfo(bNodeTree *ntree, bNodeTreeType *typeinfo);
static void node_socket_copy(bNodeSocket *sock_dst, const bNodeSocket *sock_src, const int flag);
static void free_localized_node_groups(bNodeTree *ntree);
static void node_free_node(bNodeTree *ntree, bNode *node);
-static void node_socket_interface_free(bNodeTree *UNUSED(ntree), bNodeSocket *sock);
+static void node_socket_interface_free(bNodeTree *UNUSED(ntree),
+ bNodeSocket *sock,
+ const bool do_id_user);
static void ntree_init_data(ID *id)
{
@@ -112,7 +120,7 @@ static void ntree_copy_data(Main *UNUSED(bmain), ID *id_dst, const ID *id_src, c
/* Since source nodes and sockets are unique pointers we can put everything in a single map. */
GHash *new_pointers = BLI_ghash_ptr_new(__func__);
- for (const bNode *node_src = ntree_src->nodes.first; node_src; node_src = node_src->next) {
+ LISTBASE_FOREACH (const bNode *, node_src, &ntree_src->nodes) {
bNode *new_node = BKE_node_copy_ex(ntree_dst, node_src, flag_subdata, true);
BLI_ghash_insert(new_pointers, (void *)node_src, new_node);
/* Store mapping to inputs. */
@@ -228,12 +236,12 @@ static void ntree_free_data(ID *id)
/* free interface sockets */
for (sock = ntree->inputs.first; sock; sock = nextsock) {
nextsock = sock->next;
- node_socket_interface_free(ntree, sock);
+ node_socket_interface_free(ntree, sock, false);
MEM_freeN(sock);
}
for (sock = ntree->outputs.first; sock; sock = nextsock) {
nextsock = sock->next;
- node_socket_interface_free(ntree, sock);
+ node_socket_interface_free(ntree, sock, false);
MEM_freeN(sock);
}
@@ -247,6 +255,66 @@ static void ntree_free_data(ID *id)
}
}
+static void library_foreach_node_socket(LibraryForeachIDData *data, bNodeSocket *sock)
+{
+ IDP_foreach_property(
+ sock->prop, IDP_TYPE_FILTER_ID, BKE_lib_query_idpropertiesForeachIDLink_callback, data);
+
+ switch ((eNodeSocketDatatype)sock->type) {
+ case SOCK_OBJECT: {
+ bNodeSocketValueObject *default_value = sock->default_value;
+ BKE_LIB_FOREACHID_PROCESS(data, default_value->value, IDWALK_CB_USER);
+ break;
+ }
+ case SOCK_IMAGE: {
+ bNodeSocketValueImage *default_value = sock->default_value;
+ BKE_LIB_FOREACHID_PROCESS(data, default_value->value, IDWALK_CB_USER);
+ break;
+ }
+ case SOCK_FLOAT:
+ case SOCK_VECTOR:
+ case SOCK_RGBA:
+ case SOCK_BOOLEAN:
+ case SOCK_INT:
+ case SOCK_STRING:
+ case __SOCK_MESH:
+ case SOCK_CUSTOM:
+ case SOCK_SHADER:
+ case SOCK_EMITTERS:
+ case SOCK_EVENTS:
+ case SOCK_FORCES:
+ case SOCK_CONTROL_FLOW:
+ break;
+ }
+}
+
+static void node_foreach_id(ID *id, LibraryForeachIDData *data)
+{
+ bNodeTree *ntree = (bNodeTree *)id;
+
+ BKE_LIB_FOREACHID_PROCESS(data, ntree->gpd, IDWALK_CB_USER);
+
+ LISTBASE_FOREACH (bNode *, node, &ntree->nodes) {
+ BKE_LIB_FOREACHID_PROCESS_ID(data, node->id, IDWALK_CB_USER);
+
+ IDP_foreach_property(
+ node->prop, IDP_TYPE_FILTER_ID, BKE_lib_query_idpropertiesForeachIDLink_callback, data);
+ LISTBASE_FOREACH (bNodeSocket *, sock, &node->inputs) {
+ library_foreach_node_socket(data, sock);
+ }
+ LISTBASE_FOREACH (bNodeSocket *, sock, &node->outputs) {
+ library_foreach_node_socket(data, sock);
+ }
+ }
+
+ LISTBASE_FOREACH (bNodeSocket *, sock, &ntree->inputs) {
+ library_foreach_node_socket(data, sock);
+ }
+ LISTBASE_FOREACH (bNodeSocket *, sock, &ntree->outputs) {
+ library_foreach_node_socket(data, sock);
+ }
+}
+
IDTypeInfo IDType_ID_NT = {
.id_code = ID_NT,
.id_filter = FILTER_ID_NT,
@@ -261,6 +329,7 @@ IDTypeInfo IDType_ID_NT = {
.copy_data = ntree_copy_data,
.free_data = ntree_free_data,
.make_local = NULL,
+ .foreach_id = node_foreach_id,
};
static void node_add_sockets_from_type(bNodeTree *ntree, bNode *node, bNodeType *ntype)
@@ -743,6 +812,66 @@ static bNodeSocket *make_socket(bNodeTree *ntree,
return sock;
}
+static void socket_id_user_increment(bNodeSocket *sock)
+{
+ switch ((eNodeSocketDatatype)sock->type) {
+ case SOCK_OBJECT: {
+ bNodeSocketValueObject *default_value = sock->default_value;
+ id_us_plus(&default_value->value->id);
+ break;
+ }
+ case SOCK_IMAGE: {
+ bNodeSocketValueImage *default_value = sock->default_value;
+ id_us_plus(&default_value->value->id);
+ break;
+ }
+ case SOCK_FLOAT:
+ case SOCK_VECTOR:
+ case SOCK_RGBA:
+ case SOCK_BOOLEAN:
+ case SOCK_INT:
+ case SOCK_STRING:
+ case __SOCK_MESH:
+ case SOCK_CUSTOM:
+ case SOCK_SHADER:
+ case SOCK_EMITTERS:
+ case SOCK_EVENTS:
+ case SOCK_FORCES:
+ case SOCK_CONTROL_FLOW:
+ break;
+ }
+}
+
+static void socket_id_user_decrement(bNodeSocket *sock)
+{
+ switch ((eNodeSocketDatatype)sock->type) {
+ case SOCK_OBJECT: {
+ bNodeSocketValueObject *default_value = sock->default_value;
+ id_us_min(&default_value->value->id);
+ break;
+ }
+ case SOCK_IMAGE: {
+ bNodeSocketValueImage *default_value = sock->default_value;
+ id_us_min(&default_value->value->id);
+ break;
+ }
+ case SOCK_FLOAT:
+ case SOCK_VECTOR:
+ case SOCK_RGBA:
+ case SOCK_BOOLEAN:
+ case SOCK_INT:
+ case SOCK_STRING:
+ case __SOCK_MESH:
+ case SOCK_CUSTOM:
+ case SOCK_SHADER:
+ case SOCK_EMITTERS:
+ case SOCK_EVENTS:
+ case SOCK_FORCES:
+ case SOCK_CONTROL_FLOW:
+ break;
+ }
+}
+
void nodeModifySocketType(
bNodeTree *ntree, bNode *UNUSED(node), bNodeSocket *sock, int type, int subtype)
{
@@ -754,6 +883,7 @@ void nodeModifySocketType(
}
if (sock->default_value) {
+ socket_id_user_decrement(sock);
MEM_freeN(sock->default_value);
sock->default_value = NULL;
}
@@ -770,6 +900,10 @@ bNodeSocket *nodeAddSocket(bNodeTree *ntree,
const char *identifier,
const char *name)
{
+ BLI_assert(node->type != NODE_FRAME);
+ BLI_assert(!(in_out == SOCK_IN && node->type == NODE_GROUP_INPUT));
+ BLI_assert(!(in_out == SOCK_OUT && node->type == NODE_GROUP_OUTPUT));
+
ListBase *lb = (in_out == SOCK_IN ? &node->inputs : &node->outputs);
bNodeSocket *sock = make_socket(ntree, node, in_out, lb, idname, identifier, name);
@@ -857,6 +991,18 @@ const char *nodeStaticSocketType(int type, int subtype)
return "NodeSocketString";
case SOCK_SHADER:
return "NodeSocketShader";
+ case SOCK_OBJECT:
+ return "NodeSocketObject";
+ case SOCK_IMAGE:
+ return "NodeSocketImage";
+ case SOCK_EMITTERS:
+ return "NodeSocketEmitters";
+ case SOCK_EVENTS:
+ return "NodeSocketEvents";
+ case SOCK_FORCES:
+ return "NodeSocketForces";
+ case SOCK_CONTROL_FLOW:
+ return "NodeSocketControlFlow";
}
return NULL;
}
@@ -918,6 +1064,18 @@ const char *nodeStaticSocketInterfaceType(int type, int subtype)
return "NodeSocketInterfaceString";
case SOCK_SHADER:
return "NodeSocketInterfaceShader";
+ case SOCK_OBJECT:
+ return "NodeSocketInterfaceObject";
+ case SOCK_IMAGE:
+ return "NodeSocketInterfaceImage";
+ case SOCK_EMITTERS:
+ return "NodeSocketInterfaceEmitters";
+ case SOCK_EVENTS:
+ return "NodeSocketInterfaceEvents";
+ case SOCK_FORCES:
+ return "NodeSocketInterfaceForces";
+ case SOCK_CONTROL_FLOW:
+ return "NodeSocketInterfaceControlFlow";
}
return NULL;
}
@@ -976,6 +1134,9 @@ static void node_socket_free(bNodeTree *UNUSED(ntree),
}
if (sock->default_value) {
+ if (do_id_user) {
+ socket_id_user_decrement(sock);
+ }
MEM_freeN(sock->default_value);
}
}
@@ -1262,6 +1423,10 @@ static void node_socket_copy(bNodeSocket *sock_dst, const bNodeSocket *sock_src,
if (sock_src->default_value) {
sock_dst->default_value = MEM_dupallocN(sock_src->default_value);
+
+ if ((flag & LIB_ID_CREATE_NO_USER_REFCOUNT) == 0) {
+ socket_id_user_increment(sock_dst);
+ }
}
sock_dst->stack_index = 0;
@@ -1633,7 +1798,7 @@ void nodePositionRelative(bNode *from_node,
void nodePositionPropagate(bNode *node)
{
- for (bNodeSocket *nsock = node->inputs.first; nsock; nsock = nsock->next) {
+ LISTBASE_FOREACH (bNodeSocket *, nsock, &node->inputs) {
if (nsock->link != NULL) {
bNodeLink *link = nsock->link;
nodePositionRelative(link->fromnode, link->tonode, link->fromsock, link->tosock);
@@ -2082,6 +2247,13 @@ void nodeRemoveNode(Main *bmain, bNodeTree *ntree, bNode *node, bool do_id_user)
if (node->id) {
id_us_min(node->id);
}
+
+ LISTBASE_FOREACH (bNodeSocket *, sock, &node->inputs) {
+ socket_id_user_decrement(sock);
+ }
+ LISTBASE_FOREACH (bNodeSocket *, sock, &node->outputs) {
+ socket_id_user_decrement(sock);
+ }
}
/* Remove animation data. */
@@ -2101,13 +2273,18 @@ void nodeRemoveNode(Main *bmain, bNodeTree *ntree, bNode *node, bool do_id_user)
node_free_node(ntree, node);
}
-static void node_socket_interface_free(bNodeTree *UNUSED(ntree), bNodeSocket *sock)
+static void node_socket_interface_free(bNodeTree *UNUSED(ntree),
+ bNodeSocket *sock,
+ const bool do_id_user)
{
if (sock->prop) {
- IDP_FreeProperty(sock->prop);
+ IDP_FreeProperty_ex(sock->prop, do_id_user);
}
if (sock->default_value) {
+ if (do_id_user) {
+ socket_id_user_decrement(sock);
+ }
MEM_freeN(sock->default_value);
}
}
@@ -2142,7 +2319,7 @@ void ntreeFreeTree(bNodeTree *ntree)
BKE_animdata_free(&ntree->id, false);
}
-void ntreeFreeNestedTree(bNodeTree *ntree)
+void ntreeFreeEmbeddedTree(bNodeTree *ntree)
{
ntreeFreeTree(ntree);
BKE_libblock_free_data(&ntree->id, true);
@@ -2265,6 +2442,8 @@ bNodeTree **BKE_ntree_ptr_from_id(ID *id)
return &((Scene *)id)->nodetree;
case ID_LS:
return &((FreestyleLineStyle *)id)->nodetree;
+ case ID_SIM:
+ return &((Simulation *)id)->nodetree;
default:
return NULL;
}
@@ -2528,7 +2707,7 @@ void ntreeRemoveSocketInterface(bNodeTree *ntree, bNodeSocket *sock)
BLI_remlink(&ntree->inputs, sock);
BLI_remlink(&ntree->outputs, sock);
- node_socket_interface_free(ntree, sock);
+ node_socket_interface_free(ntree, sock, true);
MEM_freeN(sock);
ntree->update |= NTREE_UPDATE_GROUP;
@@ -2661,7 +2840,7 @@ void ntreeInterfaceTypeUpdate(bNodeTree *ntree)
bNode *ntreeFindType(const bNodeTree *ntree, int type)
{
if (ntree) {
- for (bNode *node = ntree->nodes.first; node; node = node->next) {
+ LISTBASE_FOREACH (bNode *, node, &ntree->nodes) {
if (node->type == type) {
return node;
}
@@ -3395,7 +3574,7 @@ void ntreeUpdateAllNew(Main *main)
* might have been set in file reading or versioning. */
FOREACH_NODETREE_BEGIN (main, ntree, owner_id) {
if (owner_id->tag & LIB_TAG_NEW) {
- for (bNode *node = ntree->nodes.first; node; node = node->next) {
+ LISTBASE_FOREACH (bNode *, node, &ntree->nodes) {
if (node->typeinfo->group_update_func) {
node->typeinfo->group_update_func(ntree, node);
}
@@ -3413,7 +3592,7 @@ void ntreeUpdateAllUsers(Main *main, ID *ngroup)
FOREACH_NODETREE_BEGIN (main, ntree, owner_id) {
bool need_update = false;
- for (bNode *node = ntree->nodes.first; node; node = node->next) {
+ LISTBASE_FOREACH (bNode *, node, &ntree->nodes) {
if (node->id == ngroup) {
if (node->typeinfo->group_update_func) {
node->typeinfo->group_update_func(ntree, node);
@@ -3624,9 +3803,9 @@ void node_type_base(bNodeType *ntype, int type, const char *name, short nclass,
#define DefNode(Category, ID, DefFunc, EnumName, StructName, UIName, UIDesc) \
case ID: \
BLI_strncpy(ntype->idname, #Category #StructName, sizeof(ntype->idname)); \
- ntype->ext.srna = RNA_struct_find(#Category #StructName); \
- BLI_assert(ntype->ext.srna != NULL); \
- RNA_struct_blender_type_set(ntype->ext.srna, ntype); \
+ ntype->rna_ext.srna = RNA_struct_find(#Category #StructName); \
+ BLI_assert(ntype->rna_ext.srna != NULL); \
+ RNA_struct_blender_type_set(ntype->rna_ext.srna, ntype); \
break;
switch (type) {
@@ -4113,6 +4292,33 @@ static void registerTextureNodes(void)
register_node_type_tex_proc_distnoise();
}
+static void registerSimulationNodes(void)
+{
+ register_node_type_sim_group();
+
+ register_node_type_sim_particle_simulation();
+ register_node_type_sim_force();
+ register_node_type_sim_set_particle_attribute();
+ register_node_type_sim_particle_birth_event();
+ register_node_type_sim_particle_time_step_event();
+ register_node_type_sim_execute_condition();
+ register_node_type_sim_multi_execute();
+ register_node_type_sim_particle_mesh_emitter();
+ register_node_type_sim_particle_mesh_collision_event();
+ register_node_type_sim_emit_particles();
+ register_node_type_sim_time();
+ register_node_type_sim_particle_attribute();
+}
+
+static void registerFunctionNodes(void)
+{
+ register_node_type_fn_boolean_math();
+ register_node_type_fn_float_compare();
+ register_node_type_fn_switch();
+ register_node_type_fn_group_instance_id();
+ register_node_type_fn_combine_strings();
+}
+
void init_nodesystem(void)
{
nodetreetypes_hash = BLI_ghash_str_new("nodetreetypes_hash gh");
@@ -4126,6 +4332,7 @@ void init_nodesystem(void)
register_node_tree_type_cmp();
register_node_tree_type_sh();
register_node_tree_type_tex();
+ register_node_tree_type_sim();
register_node_type_frame();
register_node_type_reroute();
@@ -4135,14 +4342,16 @@ void init_nodesystem(void)
registerCompositNodes();
registerShaderNodes();
registerTextureNodes();
+ registerSimulationNodes();
+ registerFunctionNodes();
}
void free_nodesystem(void)
{
if (nodetypes_hash) {
NODE_TYPES_BEGIN (nt) {
- if (nt->ext.free) {
- nt->ext.free(nt->ext.data);
+ if (nt->rna_ext.free) {
+ nt->rna_ext.free(nt->rna_ext.data);
}
}
NODE_TYPES_END;
@@ -4168,8 +4377,8 @@ void free_nodesystem(void)
if (nodetreetypes_hash) {
NODE_TREE_TYPES_BEGIN (nt) {
- if (nt->ext.free) {
- nt->ext.free(nt->ext.data);
+ if (nt->rna_ext.free) {
+ nt->rna_ext.free(nt->rna_ext.data);
}
}
NODE_TREE_TYPES_END;
@@ -4191,6 +4400,7 @@ void BKE_node_tree_iter_init(struct NodeTreeIterStore *ntreeiter, struct Main *b
ntreeiter->light = bmain->lights.first;
ntreeiter->world = bmain->worlds.first;
ntreeiter->linestyle = bmain->linestyles.first;
+ ntreeiter->simulation = bmain->simulations.first;
}
bool BKE_node_tree_iter_step(struct NodeTreeIterStore *ntreeiter,
bNodeTree **r_nodetree,
@@ -4231,6 +4441,11 @@ bool BKE_node_tree_iter_step(struct NodeTreeIterStore *ntreeiter,
*r_id = (ID *)ntreeiter->linestyle;
ntreeiter->linestyle = ntreeiter->linestyle->id.next;
}
+ else if (ntreeiter->simulation) {
+ *r_nodetree = ntreeiter->simulation->nodetree;
+ *r_id = (ID *)ntreeiter->simulation;
+ ntreeiter->simulation = ntreeiter->simulation->id.next;
+ }
else {
return false;
}
@@ -4244,7 +4459,7 @@ bool BKE_node_tree_iter_step(struct NodeTreeIterStore *ntreeiter,
void BKE_nodetree_remove_layer_n(bNodeTree *ntree, Scene *scene, const int layer_index)
{
BLI_assert(layer_index != -1);
- for (bNode *node = ntree->nodes.first; node; node = node->next) {
+ LISTBASE_FOREACH (bNode *, node, &ntree->nodes) {
if (node->type == CMP_NODE_R_LAYERS && (Scene *)node->id == scene) {
if (node->custom1 == layer_index) {
node->custom1 = 0;
diff --git a/source/blender/blenkernel/intern/object.c b/source/blender/blenkernel/intern/object.c
index 7a2e9583aa1..e7a8d04e0b8 100644
--- a/source/blender/blenkernel/intern/object.c
+++ b/source/blender/blenkernel/intern/object.c
@@ -68,7 +68,9 @@
#include "BKE_DerivedMesh.h"
#include "BKE_action.h"
-#include "BKE_anim.h"
+#include "BKE_anim_data.h"
+#include "BKE_anim_path.h"
+#include "BKE_anim_visualization.h"
#include "BKE_animsys.h"
#include "BKE_armature.h"
#include "BKE_camera.h"
@@ -77,9 +79,12 @@
#include "BKE_curve.h"
#include "BKE_deform.h"
#include "BKE_displist.h"
+#include "BKE_duplilist.h"
#include "BKE_editmesh.h"
+#include "BKE_editmesh_cache.h"
#include "BKE_effect.h"
#include "BKE_fcurve.h"
+#include "BKE_fcurve_driver.h"
#include "BKE_font.h"
#include "BKE_global.h"
#include "BKE_gpencil.h"
@@ -172,9 +177,6 @@ static void object_copy_data(Main *bmain, ID *id_dst, const ID *id_src, const in
{
Object *ob_dst = (Object *)id_dst;
const Object *ob_src = (const Object *)id_src;
- ModifierData *md;
- GpencilModifierData *gmd;
- ShaderFxData *fx;
/* Do not copy runtime data. */
BKE_object_runtime_reset_on_copy(ob_dst, flag);
@@ -204,28 +206,28 @@ static void object_copy_data(Main *bmain, ID *id_dst, const ID *id_src, const in
BLI_listbase_clear(&ob_dst->modifiers);
- for (md = ob_src->modifiers.first; md; md = md->next) {
- ModifierData *nmd = modifier_new(md->type);
+ LISTBASE_FOREACH (ModifierData *, md, &ob_src->modifiers) {
+ ModifierData *nmd = BKE_modifier_new(md->type);
BLI_strncpy(nmd->name, md->name, sizeof(nmd->name));
- modifier_copyData_ex(md, nmd, flag_subdata);
+ BKE_modifier_copydata_ex(md, nmd, flag_subdata);
BLI_addtail(&ob_dst->modifiers, nmd);
}
BLI_listbase_clear(&ob_dst->greasepencil_modifiers);
- for (gmd = ob_src->greasepencil_modifiers.first; gmd; gmd = gmd->next) {
+ LISTBASE_FOREACH (GpencilModifierData *, gmd, &ob_src->greasepencil_modifiers) {
GpencilModifierData *nmd = BKE_gpencil_modifier_new(gmd->type);
BLI_strncpy(nmd->name, gmd->name, sizeof(nmd->name));
- BKE_gpencil_modifier_copyData_ex(gmd, nmd, flag_subdata);
+ BKE_gpencil_modifier_copydata_ex(gmd, nmd, flag_subdata);
BLI_addtail(&ob_dst->greasepencil_modifiers, nmd);
}
BLI_listbase_clear(&ob_dst->shader_fx);
- for (fx = ob_src->shader_fx.first; fx; fx = fx->next) {
+ LISTBASE_FOREACH (ShaderFxData *, fx, &ob_src->shader_fx) {
ShaderFxData *nfx = BKE_shaderfx_new(fx->type);
BLI_strncpy(nfx->name, fx->name, sizeof(nfx->name));
- BKE_shaderfx_copyData_ex(fx, nfx, flag_subdata);
+ BKE_shaderfx_copydata_ex(fx, nfx, flag_subdata);
BLI_addtail(&ob_dst->shader_fx, nfx);
}
@@ -374,6 +376,153 @@ static void object_make_local(Main *bmain, ID *id, const int flags)
}
}
+static void library_foreach_modifiersForeachIDLink(void *user_data,
+ Object *UNUSED(object),
+ ID **id_pointer,
+ int cb_flag)
+{
+ LibraryForeachIDData *data = (LibraryForeachIDData *)user_data;
+ BKE_lib_query_foreachid_process(data, id_pointer, cb_flag);
+}
+
+static void library_foreach_gpencil_modifiersForeachIDLink(void *user_data,
+ Object *UNUSED(object),
+ ID **id_pointer,
+ int cb_flag)
+{
+ LibraryForeachIDData *data = (LibraryForeachIDData *)user_data;
+ BKE_lib_query_foreachid_process(data, id_pointer, cb_flag);
+}
+
+static void library_foreach_shaderfxForeachIDLink(void *user_data,
+ Object *UNUSED(object),
+ ID **id_pointer,
+ int cb_flag)
+{
+ LibraryForeachIDData *data = (LibraryForeachIDData *)user_data;
+ BKE_lib_query_foreachid_process(data, id_pointer, cb_flag);
+}
+
+static void library_foreach_constraintObjectLooper(bConstraint *UNUSED(con),
+ ID **id_pointer,
+ bool is_reference,
+ void *user_data)
+{
+ LibraryForeachIDData *data = (LibraryForeachIDData *)user_data;
+ const int cb_flag = is_reference ? IDWALK_CB_USER : IDWALK_CB_NOP;
+ BKE_lib_query_foreachid_process(data, id_pointer, cb_flag);
+}
+
+static void library_foreach_particlesystemsObjectLooper(ParticleSystem *UNUSED(psys),
+ ID **id_pointer,
+ void *user_data,
+ int cb_flag)
+{
+ LibraryForeachIDData *data = (LibraryForeachIDData *)user_data;
+ BKE_lib_query_foreachid_process(data, id_pointer, cb_flag);
+}
+
+static void object_foreach_id(ID *id, LibraryForeachIDData *data)
+{
+ Object *object = (Object *)id;
+
+ /* Object is special, proxies make things hard... */
+ const int proxy_cb_flag = ((BKE_lib_query_foreachid_process_flags_get(data) &
+ IDWALK_NO_INDIRECT_PROXY_DATA_USAGE) == 0 &&
+ (object->proxy || object->proxy_group)) ?
+ IDWALK_CB_INDIRECT_USAGE :
+ 0;
+
+ /* object data special case */
+ if (object->type == OB_EMPTY) {
+ /* empty can have NULL or Image */
+ BKE_LIB_FOREACHID_PROCESS_ID(data, object->data, proxy_cb_flag | IDWALK_CB_USER);
+ }
+ else {
+ /* when set, this can't be NULL */
+ if (object->data) {
+ BKE_LIB_FOREACHID_PROCESS_ID(
+ data, object->data, proxy_cb_flag | IDWALK_CB_USER | IDWALK_CB_NEVER_NULL);
+ }
+ }
+
+ BKE_LIB_FOREACHID_PROCESS(data, object->parent, IDWALK_CB_NEVER_SELF);
+ BKE_LIB_FOREACHID_PROCESS(data, object->track, IDWALK_CB_NEVER_SELF);
+ /* object->proxy is refcounted, but not object->proxy_group... *sigh* */
+ BKE_LIB_FOREACHID_PROCESS(data, object->proxy, IDWALK_CB_USER | IDWALK_CB_NEVER_SELF);
+ BKE_LIB_FOREACHID_PROCESS(data, object->proxy_group, IDWALK_CB_NOP);
+
+ /* Special case!
+ * Since this field is set/owned by 'user' of this ID (and not ID itself),
+ * it is only indirect usage if proxy object is linked... Twisted. */
+ {
+ const int cb_flag_orig = BKE_lib_query_foreachid_process_callback_flag_override(
+ data,
+ (object->proxy_from != NULL && ID_IS_LINKED(object->proxy_from)) ?
+ IDWALK_CB_INDIRECT_USAGE :
+ 0,
+ true);
+ BKE_LIB_FOREACHID_PROCESS(data, object->proxy_from, IDWALK_CB_LOOPBACK | IDWALK_CB_NEVER_SELF);
+ BKE_lib_query_foreachid_process_callback_flag_override(data, cb_flag_orig, true);
+ }
+
+ BKE_LIB_FOREACHID_PROCESS(data, object->poselib, IDWALK_CB_USER);
+
+ for (int i = 0; i < object->totcol; i++) {
+ BKE_LIB_FOREACHID_PROCESS(data, object->mat[i], proxy_cb_flag | IDWALK_CB_USER);
+ }
+
+ /* Note that ob->gpd is deprecated, so no need to handle it here. */
+ BKE_LIB_FOREACHID_PROCESS(data, object->instance_collection, IDWALK_CB_USER);
+
+ if (object->pd) {
+ BKE_LIB_FOREACHID_PROCESS(data, object->pd->tex, IDWALK_CB_USER);
+ BKE_LIB_FOREACHID_PROCESS(data, object->pd->f_source, IDWALK_CB_NOP);
+ }
+ /* Note that ob->effect is deprecated, so no need to handle it here. */
+
+ if (object->pose) {
+ const int cb_flag_orig = BKE_lib_query_foreachid_process_callback_flag_override(
+ data, proxy_cb_flag, false);
+ LISTBASE_FOREACH (bPoseChannel *, pchan, &object->pose->chanbase) {
+ IDP_foreach_property(
+ pchan->prop, IDP_TYPE_FILTER_ID, BKE_lib_query_idpropertiesForeachIDLink_callback, data);
+ BKE_LIB_FOREACHID_PROCESS(data, pchan->custom, IDWALK_CB_USER);
+ BKE_constraints_id_loop(&pchan->constraints, library_foreach_constraintObjectLooper, data);
+ }
+ BKE_lib_query_foreachid_process_callback_flag_override(data, cb_flag_orig, true);
+ }
+
+ if (object->rigidbody_constraint) {
+ BKE_LIB_FOREACHID_PROCESS(data, object->rigidbody_constraint->ob1, IDWALK_CB_NEVER_SELF);
+ BKE_LIB_FOREACHID_PROCESS(data, object->rigidbody_constraint->ob2, IDWALK_CB_NEVER_SELF);
+ }
+
+ if (object->lodlevels.first) {
+ LISTBASE_FOREACH (LodLevel *, level, &object->lodlevels) {
+ BKE_LIB_FOREACHID_PROCESS(data, level->source, IDWALK_CB_NEVER_SELF);
+ }
+ }
+
+ BKE_modifiers_foreach_ID_link(object, library_foreach_modifiersForeachIDLink, data);
+ BKE_gpencil_modifiers_foreach_ID_link(
+ object, library_foreach_gpencil_modifiersForeachIDLink, data);
+ BKE_constraints_id_loop(&object->constraints, library_foreach_constraintObjectLooper, data);
+ BKE_shaderfx_foreach_ID_link(object, library_foreach_shaderfxForeachIDLink, data);
+
+ LISTBASE_FOREACH (ParticleSystem *, psys, &object->particlesystem) {
+ BKE_particlesystem_id_loop(psys, library_foreach_particlesystemsObjectLooper, data);
+ }
+
+ if (object->soft) {
+ BKE_LIB_FOREACHID_PROCESS(data, object->soft->collision_group, IDWALK_CB_NOP);
+
+ if (object->soft->effector_weights) {
+ BKE_LIB_FOREACHID_PROCESS(data, object->soft->effector_weights->group, IDWALK_CB_NOP);
+ }
+ }
+}
+
IDTypeInfo IDType_ID_OB = {
.id_code = ID_OB,
.id_filter = FILTER_ID_OB,
@@ -388,6 +537,7 @@ IDTypeInfo IDType_ID_OB = {
.copy_data = object_copy_data,
.free_data = object_free_data,
.make_local = object_make_local,
+ .foreach_id = object_foreach_id,
};
void BKE_object_workob_clear(Object *workob)
@@ -433,7 +583,7 @@ void BKE_object_free_modifiers(Object *ob, const int flag)
GpencilModifierData *gp_md;
while ((md = BLI_pophead(&ob->modifiers))) {
- modifier_free_ex(md, flag);
+ BKE_modifier_free_ex(md, flag);
}
while ((gp_md = BLI_pophead(&ob->greasepencil_modifiers))) {
@@ -509,69 +659,97 @@ bool BKE_object_support_modifier_type_check(const Object *ob, int modifier_type)
{
const ModifierTypeInfo *mti;
- mti = modifierType_getInfo(modifier_type);
+ mti = BKE_modifier_get_info(modifier_type);
- /* only geometry objects should be able to get modifiers [#25291] */
- if (!ELEM(ob->type, OB_MESH, OB_CURVE, OB_SURF, OB_FONT, OB_LATTICE)) {
- return false;
+ /* Only geometry objects should be able to get modifiers [#25291] */
+ if (ob->type == OB_HAIR) {
+ return (mti->modifyHair != NULL) || (mti->flags & eModifierTypeFlag_AcceptsVertexCosOnly);
}
-
- if (ob->type == OB_LATTICE && (mti->flags & eModifierTypeFlag_AcceptsLattice) == 0) {
- return false;
+ else if (ob->type == OB_POINTCLOUD) {
+ return (mti->modifyPointCloud != NULL) ||
+ (mti->flags & eModifierTypeFlag_AcceptsVertexCosOnly);
}
+ else if (ob->type == OB_VOLUME) {
+ return (mti->modifyVolume != NULL);
+ }
+ else if (ELEM(ob->type, OB_MESH, OB_CURVE, OB_SURF, OB_FONT, OB_LATTICE)) {
+ if (ob->type == OB_LATTICE && (mti->flags & eModifierTypeFlag_AcceptsVertexCosOnly) == 0) {
+ return false;
+ }
- if (!((mti->flags & eModifierTypeFlag_AcceptsCVs) ||
- (ob->type == OB_MESH && (mti->flags & eModifierTypeFlag_AcceptsMesh)))) {
- return false;
+ if (!((mti->flags & eModifierTypeFlag_AcceptsCVs) ||
+ (ob->type == OB_MESH && (mti->flags & eModifierTypeFlag_AcceptsMesh)))) {
+ return false;
+ }
+
+ return true;
}
- return true;
+ return false;
}
void BKE_object_link_modifiers(struct Object *ob_dst, const struct Object *ob_src)
{
- ModifierData *md;
BKE_object_free_modifiers(ob_dst, 0);
- if (!ELEM(ob_dst->type, OB_MESH, OB_CURVE, OB_SURF, OB_FONT, OB_LATTICE)) {
+ if (!ELEM(ob_dst->type, OB_MESH, OB_CURVE, OB_SURF, OB_FONT, OB_LATTICE, OB_GPENCIL)) {
/* only objects listed above can have modifiers and linking them to objects
* which doesn't have modifiers stack is quite silly */
return;
}
- for (md = ob_src->modifiers.first; md; md = md->next) {
- ModifierData *nmd = NULL;
+ /* No grease pencil modifiers. */
+ if ((ob_src->type != OB_GPENCIL) && (ob_dst->type != OB_GPENCIL)) {
+ LISTBASE_FOREACH (ModifierData *, md, &ob_src->modifiers) {
+ ModifierData *nmd = NULL;
- if (ELEM(md->type, eModifierType_Hook, eModifierType_Collision)) {
- continue;
- }
+ if (ELEM(md->type, eModifierType_Hook, eModifierType_Collision)) {
+ continue;
+ }
- if (!BKE_object_support_modifier_type_check(ob_dst, md->type)) {
- continue;
- }
+ if (!BKE_object_support_modifier_type_check(ob_dst, md->type)) {
+ continue;
+ }
- switch (md->type) {
- case eModifierType_Softbody:
- BKE_object_copy_softbody(ob_dst, ob_src, 0);
- break;
- case eModifierType_Skin:
- /* ensure skin-node customdata exists */
- BKE_mesh_ensure_skin_customdata(ob_dst->data);
- break;
- }
+ switch (md->type) {
+ case eModifierType_Softbody:
+ BKE_object_copy_softbody(ob_dst, ob_src, 0);
+ break;
+ case eModifierType_Skin:
+ /* ensure skin-node customdata exists */
+ BKE_mesh_ensure_skin_customdata(ob_dst->data);
+ break;
+ }
- nmd = modifier_new(md->type);
- BLI_strncpy(nmd->name, md->name, sizeof(nmd->name));
+ nmd = BKE_modifier_new(md->type);
+ BLI_strncpy(nmd->name, md->name, sizeof(nmd->name));
+
+ if (md->type == eModifierType_Multires) {
+ /* Has to be done after mod creation, but *before* we actually copy its settings! */
+ multiresModifier_sync_levels_ex(
+ ob_dst, (MultiresModifierData *)md, (MultiresModifierData *)nmd);
+ }
- if (md->type == eModifierType_Multires) {
- /* Has to be done after mod creation, but *before* we actually copy its settings! */
- multiresModifier_sync_levels_ex(
- ob_dst, (MultiresModifierData *)md, (MultiresModifierData *)nmd);
+ BKE_modifier_copydata(md, nmd);
+ BLI_addtail(&ob_dst->modifiers, nmd);
+ BKE_modifier_unique_name(&ob_dst->modifiers, nmd);
}
+ }
- modifier_copyData(md, nmd);
- BLI_addtail(&ob_dst->modifiers, nmd);
- modifier_unique_name(&ob_dst->modifiers, nmd);
+ /* Copy grease pencil modifiers. */
+ if ((ob_src->type == OB_GPENCIL) && (ob_dst->type == OB_GPENCIL)) {
+ LISTBASE_FOREACH (GpencilModifierData *, md, &ob_src->greasepencil_modifiers) {
+ GpencilModifierData *nmd = NULL;
+
+ nmd = BKE_gpencil_modifier_new(md->type);
+ BLI_strncpy(nmd->name, md->name, sizeof(nmd->name));
+
+ const GpencilModifierTypeInfo *mti = BKE_gpencil_modifier_get_info(md->type);
+ mti->copyData(md, nmd);
+
+ BLI_addtail(&ob_dst->greasepencil_modifiers, nmd);
+ BKE_gpencil_modifier_unique_name(&ob_dst->greasepencil_modifiers, nmd);
+ }
}
BKE_object_copy_particlesystems(ob_dst, ob_src, 0);
@@ -1279,8 +1457,8 @@ ParticleSystem *BKE_object_copy_particlesystem(ParticleSystem *psys, const int f
psys_copy_particles(psysn, psys);
if (psys->clmd) {
- psysn->clmd = (ClothModifierData *)modifier_new(eModifierType_Cloth);
- modifier_copyData_ex((ModifierData *)psys->clmd, (ModifierData *)psysn->clmd, flag);
+ psysn->clmd = (ClothModifierData *)BKE_modifier_new(eModifierType_Cloth);
+ BKE_modifier_copydata_ex((ModifierData *)psys->clmd, (ModifierData *)psysn->clmd, flag);
psys->hair_in_mesh = psys->hair_out_mesh = NULL;
}
@@ -1433,7 +1611,7 @@ Object *BKE_object_pose_armature_get(Object *ob)
return ob;
}
- ob = modifiers_isDeformedByArmature(ob);
+ ob = BKE_modifiers_is_deformed_by_armature(ob);
/* Only use selected check when non-active. */
if (BKE_object_pose_context_check(ob)) {
@@ -1880,7 +2058,9 @@ bool BKE_object_obdata_is_libdata(const Object *ob)
return (ob && ob->data && ID_IS_LINKED(ob->data));
}
-/* *************** PROXY **************** */
+/* -------------------------------------------------------------------- */
+/** \name Object Proxy API
+ * \{ */
/* when you make proxy, ensure the exposed layers are extern */
static void armature_set_id_extern(Object *ob)
@@ -1907,8 +2087,8 @@ void BKE_object_copy_proxy_drivers(Object *ob, Object *target)
}
/* make a copy of all the drivers (for now), then correct any links that need fixing */
- free_fcurves(&ob->adt->drivers);
- copy_fcurves(&ob->adt->drivers, &target->adt->drivers);
+ BKE_fcurves_free(&ob->adt->drivers);
+ BKE_fcurves_copy(&ob->adt->drivers, &target->adt->drivers);
for (fcu = ob->adt->drivers.first; fcu; fcu = fcu->next) {
ChannelDriver *driver = fcu->driver;
@@ -2090,7 +2270,11 @@ void BKE_object_obdata_size_init(struct Object *ob, const float size)
}
}
-/* *************** CALC ****************** */
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Object Matrix Get/Set API
+ * \{ */
void BKE_object_scale_to_mat3(Object *ob, float mat[3][3])
{
@@ -2583,6 +2767,12 @@ void BKE_object_get_parent_matrix(Object *ob, Object *par, float parentmat[4][4]
}
}
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Object Matrix Evaluation API
+ * \{ */
+
/**
* \param r_originmat: Optional matrix that stores the space the object is in
* (without its own matrix applied)
@@ -2662,7 +2852,7 @@ void BKE_object_where_is_calc_time(Depsgraph *depsgraph, Scene *scene, Object *o
{
/* Execute drivers and animation. */
const bool flush_to_original = DEG_is_active(depsgraph);
- BKE_animsys_evaluate_animdata(scene, &ob->id, ob->adt, ctime, ADT_RECALC_ALL, flush_to_original);
+ BKE_animsys_evaluate_animdata(&ob->id, ob->adt, ctime, ADT_RECALC_ALL, flush_to_original);
object_where_is_calc_ex(depsgraph, scene, ob, ctime, NULL, NULL);
}
@@ -2787,6 +2977,12 @@ void BKE_object_apply_mat4(Object *ob,
BKE_object_apply_mat4_ex(ob, mat, use_parent ? ob->parent : NULL, ob->parentinv, use_compat);
}
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Object Bounding Box API
+ * \{ */
+
BoundBox *BKE_boundbox_alloc_unit(void)
{
BoundBox *bb;
@@ -2894,7 +3090,7 @@ void BKE_object_boundbox_calc_from_mesh(struct Object *ob, struct Mesh *me_eval)
INIT_MINMAX(min, max);
- if (!BKE_mesh_minmax(me_eval, min, max)) {
+ if (!BKE_mesh_wrapper_minmax(me_eval, min, max)) {
zero_v3(min);
zero_v3(max);
}
@@ -2908,6 +3104,8 @@ void BKE_object_boundbox_calc_from_mesh(struct Object *ob, struct Mesh *me_eval)
ob->runtime.bb->flag &= ~BOUNDBOX_DIRTY;
}
+/** \} */
+
/* -------------------------------------------------------------------- */
/** \name Object Dimension Get/Set
*
@@ -3591,9 +3789,11 @@ void BKE_object_delete_ptcache(Object *ob, int index)
BLI_freelinkN(&ob->pc_ids, link);
}
-/* shape key utility function */
+/* -------------------------------------------------------------------- */
+/** \name Object Data Shape Key Insert
+ * \{ */
-/************************* Mesh ************************/
+/* Mesh */
static KeyBlock *insert_meshkey(Main *bmain, Object *ob, const char *name, const bool from_mix)
{
Mesh *me = ob->data;
@@ -3625,7 +3825,7 @@ static KeyBlock *insert_meshkey(Main *bmain, Object *ob, const char *name, const
return kb;
}
-/************************* Lattice ************************/
+/* Lattice */
static KeyBlock *insert_lattkey(Main *bmain, Object *ob, const char *name, const bool from_mix)
{
Lattice *lt = ob->data;
@@ -3663,7 +3863,7 @@ static KeyBlock *insert_lattkey(Main *bmain, Object *ob, const char *name, const
return kb;
}
-/************************* Curve ************************/
+/* Curve */
static KeyBlock *insert_curvekey(Main *bmain, Object *ob, const char *name, const bool from_mix)
{
Curve *cu = ob->data;
@@ -3704,6 +3904,12 @@ static KeyBlock *insert_curvekey(Main *bmain, Object *ob, const char *name, cons
return kb;
}
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Object Shape Key API
+ * \{ */
+
KeyBlock *BKE_object_shapekey_insert(Main *bmain,
Object *ob,
const char *name,
@@ -3801,6 +4007,8 @@ bool BKE_object_shapekey_remove(Main *bmain, Object *ob, KeyBlock *kb)
return true;
}
+/** \} */
+
bool BKE_object_flag_test_recursive(const Object *ob, short flag)
{
if (ob->flag & flag) {
@@ -3828,6 +4036,10 @@ bool BKE_object_is_child_recursive(const Object *ob_parent, const Object *ob_chi
* cases false positives are hard to avoid (shape keys for example) */
int BKE_object_is_modified(Scene *scene, Object *ob)
{
+ /* Always test on original object since evaluated object may no longer
+ * have shape keys or modifiers that were used to evaluate it. */
+ ob = DEG_get_original_object(ob);
+
int flag = 0;
if (BKE_key_from_object(ob)) {
@@ -3837,16 +4049,16 @@ int BKE_object_is_modified(Scene *scene, Object *ob)
ModifierData *md;
VirtualModifierData virtualModifierData;
/* cloth */
- for (md = modifiers_getVirtualModifierList(ob, &virtualModifierData);
+ for (md = BKE_modifiers_get_virtual_modifierlist(ob, &virtualModifierData);
md && (flag != (eModifierMode_Render | eModifierMode_Realtime));
md = md->next) {
if ((flag & eModifierMode_Render) == 0 &&
- modifier_isEnabled(scene, md, eModifierMode_Render)) {
+ BKE_modifier_is_enabled(scene, md, eModifierMode_Render)) {
flag |= eModifierMode_Render;
}
if ((flag & eModifierMode_Realtime) == 0 &&
- modifier_isEnabled(scene, md, eModifierMode_Realtime)) {
+ BKE_modifier_is_enabled(scene, md, eModifierMode_Realtime)) {
flag |= eModifierMode_Realtime;
}
}
@@ -3958,6 +4170,10 @@ static bool modifiers_has_animation_check(const Object *ob)
* and we can still if there was actual deformation afterwards */
int BKE_object_is_deform_modified(Scene *scene, Object *ob)
{
+ /* Always test on original object since evaluated object may no longer
+ * have shape keys or modifiers that were used to evaluate it. */
+ ob = DEG_get_original_object(ob);
+
ModifierData *md;
VirtualModifierData virtualModifierData;
int flag = 0;
@@ -3975,10 +4191,10 @@ int BKE_object_is_deform_modified(Scene *scene, Object *ob)
}
/* cloth */
- for (md = modifiers_getVirtualModifierList(ob, &virtualModifierData);
+ for (md = BKE_modifiers_get_virtual_modifierlist(ob, &virtualModifierData);
md && (flag != (eModifierMode_Render | eModifierMode_Realtime));
md = md->next) {
- const ModifierTypeInfo *mti = modifierType_getInfo(md->type);
+ const ModifierTypeInfo *mti = BKE_modifier_get_info(md->type);
bool can_deform = mti->type == eModifierTypeType_OnlyDeform || is_modifier_animated;
if (!can_deform) {
@@ -3986,12 +4202,13 @@ int BKE_object_is_deform_modified(Scene *scene, Object *ob)
}
if (can_deform) {
- if (!(flag & eModifierMode_Render) && modifier_isEnabled(scene, md, eModifierMode_Render)) {
+ if (!(flag & eModifierMode_Render) &&
+ BKE_modifier_is_enabled(scene, md, eModifierMode_Render)) {
flag |= eModifierMode_Render;
}
if (!(flag & eModifierMode_Realtime) &&
- modifier_isEnabled(scene, md, eModifierMode_Realtime)) {
+ BKE_modifier_is_enabled(scene, md, eModifierMode_Realtime)) {
flag |= eModifierMode_Realtime;
}
}
@@ -4326,7 +4543,7 @@ KDTree_3d *BKE_object_as_kdtree(Object *ob, int *r_tot)
bool BKE_object_modifier_use_time(Object *ob, ModifierData *md)
{
- if (modifier_dependsOnTime(md)) {
+ if (BKE_modifier_depends_ontime(md)) {
return true;
}
@@ -4369,7 +4586,7 @@ bool BKE_object_modifier_use_time(Object *ob, ModifierData *md)
bool BKE_object_modifier_gpencil_use_time(Object *ob, GpencilModifierData *md)
{
- if (BKE_gpencil_modifier_dependsOnTime(md)) {
+ if (BKE_gpencil_modifier_depends_ontime(md)) {
return true;
}
@@ -4404,7 +4621,7 @@ bool BKE_object_modifier_gpencil_use_time(Object *ob, GpencilModifierData *md)
bool BKE_object_shaderfx_use_time(Object *ob, ShaderFxData *fx)
{
- if (BKE_shaderfx_dependsOnTime(fx)) {
+ if (BKE_shaderfx_depends_ontime(fx)) {
return true;
}
@@ -4470,7 +4687,7 @@ bool BKE_object_modifier_update_subframe(Depsgraph *depsgraph,
int type)
{
const bool flush_to_original = DEG_is_active(depsgraph);
- ModifierData *md = modifiers_findByType(ob, (ModifierType)type);
+ ModifierData *md = BKE_modifiers_findby_type(ob, (ModifierType)type);
bConstraint *con;
if (type == eModifierType_DynamicPaint) {
@@ -4534,8 +4751,7 @@ bool BKE_object_modifier_update_subframe(Depsgraph *depsgraph,
/* TODO(sergey): What about animation? */
ob->id.recalc |= ID_RECALC_ALL;
if (update_mesh) {
- BKE_animsys_evaluate_animdata(
- scene, &ob->id, ob->adt, frame, ADT_RECALC_ANIM, flush_to_original);
+ BKE_animsys_evaluate_animdata(&ob->id, ob->adt, frame, ADT_RECALC_ANIM, flush_to_original);
/* ignore cache clear during subframe updates
* to not mess up cache validity */
object_cacheIgnoreClear(ob, 1);
@@ -4549,14 +4765,12 @@ bool BKE_object_modifier_update_subframe(Depsgraph *depsgraph,
/* for curve following objects, parented curve has to be updated too */
if (ob->type == OB_CURVE) {
Curve *cu = ob->data;
- BKE_animsys_evaluate_animdata(
- scene, &cu->id, cu->adt, frame, ADT_RECALC_ANIM, flush_to_original);
+ BKE_animsys_evaluate_animdata(&cu->id, cu->adt, frame, ADT_RECALC_ANIM, flush_to_original);
}
/* and armatures... */
if (ob->type == OB_ARMATURE) {
bArmature *arm = ob->data;
- BKE_animsys_evaluate_animdata(
- scene, &arm->id, arm->adt, frame, ADT_RECALC_ANIM, flush_to_original);
+ BKE_animsys_evaluate_animdata(&arm->id, arm->adt, frame, ADT_RECALC_ANIM, flush_to_original);
BKE_pose_where_is(depsgraph, scene, ob);
}
diff --git a/source/blender/blenkernel/intern/object_deform.c b/source/blender/blenkernel/intern/object_deform.c
index a75180867cb..6ca1442497a 100644
--- a/source/blender/blenkernel/intern/object_deform.c
+++ b/source/blender/blenkernel/intern/object_deform.c
@@ -620,7 +620,7 @@ bool *BKE_object_defgroup_validmap_get(Object *ob, const int defbase_tot)
/* now loop through the armature modifiers and identify deform bones */
for (md = ob->modifiers.first; md; md = !md->next && step1 ? (step1 = 0),
- modifiers_getVirtualModifierList(ob, &virtualModifierData) :
+ BKE_modifiers_get_virtual_modifierlist(ob, &virtualModifierData) :
md->next) {
if (!(md->mode & (eModifierMode_Realtime | eModifierMode_Virtual))) {
continue;
diff --git a/source/blender/blenkernel/intern/object_dupli.c b/source/blender/blenkernel/intern/object_dupli.c
index 1217d230d0d..474142e8555 100644
--- a/source/blender/blenkernel/intern/object_dupli.c
+++ b/source/blender/blenkernel/intern/object_dupli.c
@@ -40,9 +40,8 @@
#include "DNA_scene_types.h"
#include "DNA_vfont_types.h"
-#include "BKE_anim.h"
-#include "BKE_animsys.h"
#include "BKE_collection.h"
+#include "BKE_duplilist.h"
#include "BKE_editmesh.h"
#include "BKE_font.h"
#include "BKE_global.h"
diff --git a/source/blender/blenkernel/intern/object_update.c b/source/blender/blenkernel/intern/object_update.c
index dd06e4f1753..c5ef5acb08b 100644
--- a/source/blender/blenkernel/intern/object_update.c
+++ b/source/blender/blenkernel/intern/object_update.c
@@ -37,7 +37,6 @@
#include "BKE_DerivedMesh.h"
#include "BKE_action.h"
-#include "BKE_animsys.h"
#include "BKE_armature.h"
#include "BKE_constraint.h"
#include "BKE_curve.h"
@@ -273,7 +272,7 @@ void BKE_object_handle_data_update(Depsgraph *depsgraph, Scene *scene, Object *o
/**
* TODO(sergey): Ensure that bounding box is already calculated, and move this
- * into #BKE_object_synchronize_to_original().
+ * into #BKE_object_sync_to_original().
*/
void BKE_object_eval_boundbox(Depsgraph *depsgraph, Object *object)
{
@@ -290,7 +289,7 @@ void BKE_object_eval_boundbox(Depsgraph *depsgraph, Object *object)
}
}
-void BKE_object_synchronize_to_original(Depsgraph *depsgraph, Object *object)
+void BKE_object_sync_to_original(Depsgraph *depsgraph, Object *object)
{
if (!DEG_is_active(depsgraph)) {
return;
diff --git a/source/blender/blenkernel/intern/ocean.c b/source/blender/blenkernel/intern/ocean.c
index 26485d10fbd..8957628c76a 100644
--- a/source/blender/blenkernel/intern/ocean.c
+++ b/source/blender/blenkernel/intern/ocean.c
@@ -453,21 +453,17 @@ static void ocean_compute_htilda(void *__restrict userdata,
}
}
-static void ocean_compute_displacement_y(TaskPool *__restrict pool,
- void *UNUSED(taskdata),
- int UNUSED(threadid))
+static void ocean_compute_displacement_y(TaskPool *__restrict pool, void *UNUSED(taskdata))
{
- OceanSimulateData *osd = BLI_task_pool_userdata(pool);
+ OceanSimulateData *osd = BLI_task_pool_user_data(pool);
const Ocean *o = osd->o;
fftw_execute(o->_disp_y_plan);
}
-static void ocean_compute_displacement_x(TaskPool *__restrict pool,
- void *UNUSED(taskdata),
- int UNUSED(threadid))
+static void ocean_compute_displacement_x(TaskPool *__restrict pool, void *UNUSED(taskdata))
{
- OceanSimulateData *osd = BLI_task_pool_userdata(pool);
+ OceanSimulateData *osd = BLI_task_pool_user_data(pool);
const Ocean *o = osd->o;
const float scale = osd->scale;
const float chop_amount = osd->chop_amount;
@@ -494,11 +490,9 @@ static void ocean_compute_displacement_x(TaskPool *__restrict pool,
fftw_execute(o->_disp_x_plan);
}
-static void ocean_compute_displacement_z(TaskPool *__restrict pool,
- void *UNUSED(taskdata),
- int UNUSED(threadid))
+static void ocean_compute_displacement_z(TaskPool *__restrict pool, void *UNUSED(taskdata))
{
- OceanSimulateData *osd = BLI_task_pool_userdata(pool);
+ OceanSimulateData *osd = BLI_task_pool_user_data(pool);
const Ocean *o = osd->o;
const float scale = osd->scale;
const float chop_amount = osd->chop_amount;
@@ -525,11 +519,9 @@ static void ocean_compute_displacement_z(TaskPool *__restrict pool,
fftw_execute(o->_disp_z_plan);
}
-static void ocean_compute_jacobian_jxx(TaskPool *__restrict pool,
- void *UNUSED(taskdata),
- int UNUSED(threadid))
+static void ocean_compute_jacobian_jxx(TaskPool *__restrict pool, void *UNUSED(taskdata))
{
- OceanSimulateData *osd = BLI_task_pool_userdata(pool);
+ OceanSimulateData *osd = BLI_task_pool_user_data(pool);
const Ocean *o = osd->o;
const float chop_amount = osd->chop_amount;
int i, j;
@@ -560,11 +552,9 @@ static void ocean_compute_jacobian_jxx(TaskPool *__restrict pool,
}
}
-static void ocean_compute_jacobian_jzz(TaskPool *__restrict pool,
- void *UNUSED(taskdata),
- int UNUSED(threadid))
+static void ocean_compute_jacobian_jzz(TaskPool *__restrict pool, void *UNUSED(taskdata))
{
- OceanSimulateData *osd = BLI_task_pool_userdata(pool);
+ OceanSimulateData *osd = BLI_task_pool_user_data(pool);
const Ocean *o = osd->o;
const float chop_amount = osd->chop_amount;
int i, j;
@@ -595,11 +585,9 @@ static void ocean_compute_jacobian_jzz(TaskPool *__restrict pool,
}
}
-static void ocean_compute_jacobian_jxz(TaskPool *__restrict pool,
- void *UNUSED(taskdata),
- int UNUSED(threadid))
+static void ocean_compute_jacobian_jxz(TaskPool *__restrict pool, void *UNUSED(taskdata))
{
- OceanSimulateData *osd = BLI_task_pool_userdata(pool);
+ OceanSimulateData *osd = BLI_task_pool_user_data(pool);
const Ocean *o = osd->o;
const float chop_amount = osd->chop_amount;
int i, j;
@@ -624,11 +612,9 @@ static void ocean_compute_jacobian_jxz(TaskPool *__restrict pool,
fftw_execute(o->_Jxz_plan);
}
-static void ocean_compute_normal_x(TaskPool *__restrict pool,
- void *UNUSED(taskdata),
- int UNUSED(threadid))
+static void ocean_compute_normal_x(TaskPool *__restrict pool, void *UNUSED(taskdata))
{
- OceanSimulateData *osd = BLI_task_pool_userdata(pool);
+ OceanSimulateData *osd = BLI_task_pool_user_data(pool);
const Ocean *o = osd->o;
int i, j;
@@ -645,11 +631,9 @@ static void ocean_compute_normal_x(TaskPool *__restrict pool,
fftw_execute(o->_N_x_plan);
}
-static void ocean_compute_normal_z(TaskPool *__restrict pool,
- void *UNUSED(taskdata),
- int UNUSED(threadid))
+static void ocean_compute_normal_z(TaskPool *__restrict pool, void *UNUSED(taskdata))
{
- OceanSimulateData *osd = BLI_task_pool_userdata(pool);
+ OceanSimulateData *osd = BLI_task_pool_user_data(pool);
const Ocean *o = osd->o;
int i, j;
@@ -668,7 +652,6 @@ static void ocean_compute_normal_z(TaskPool *__restrict pool,
void BKE_ocean_simulate(struct Ocean *o, float t, float scale, float chop_amount)
{
- TaskScheduler *scheduler = BLI_task_scheduler_get();
TaskPool *pool;
OceanSimulateData osd;
@@ -680,7 +663,7 @@ void BKE_ocean_simulate(struct Ocean *o, float t, float scale, float chop_amount
osd.scale = scale;
osd.chop_amount = chop_amount;
- pool = BLI_task_pool_create(scheduler, &osd);
+ pool = BLI_task_pool_create(&osd, TASK_PRIORITY_HIGH);
BLI_rw_mutex_lock(&o->oceanmutex, THREAD_LOCK_WRITE);
@@ -698,23 +681,23 @@ void BKE_ocean_simulate(struct Ocean *o, float t, float scale, float chop_amount
BLI_task_parallel_range(0, o->_M, &osd, ocean_compute_htilda, &settings);
if (o->_do_disp_y) {
- BLI_task_pool_push(pool, ocean_compute_displacement_y, NULL, false, TASK_PRIORITY_HIGH);
+ BLI_task_pool_push(pool, ocean_compute_displacement_y, NULL, false, NULL);
}
if (o->_do_chop) {
- BLI_task_pool_push(pool, ocean_compute_displacement_x, NULL, false, TASK_PRIORITY_HIGH);
- BLI_task_pool_push(pool, ocean_compute_displacement_z, NULL, false, TASK_PRIORITY_HIGH);
+ BLI_task_pool_push(pool, ocean_compute_displacement_x, NULL, false, NULL);
+ BLI_task_pool_push(pool, ocean_compute_displacement_z, NULL, false, NULL);
}
if (o->_do_jacobian) {
- BLI_task_pool_push(pool, ocean_compute_jacobian_jxx, NULL, false, TASK_PRIORITY_HIGH);
- BLI_task_pool_push(pool, ocean_compute_jacobian_jzz, NULL, false, TASK_PRIORITY_HIGH);
- BLI_task_pool_push(pool, ocean_compute_jacobian_jxz, NULL, false, TASK_PRIORITY_HIGH);
+ BLI_task_pool_push(pool, ocean_compute_jacobian_jxx, NULL, false, NULL);
+ BLI_task_pool_push(pool, ocean_compute_jacobian_jzz, NULL, false, NULL);
+ BLI_task_pool_push(pool, ocean_compute_jacobian_jxz, NULL, false, NULL);
}
if (o->_do_normals) {
- BLI_task_pool_push(pool, ocean_compute_normal_x, NULL, false, TASK_PRIORITY_HIGH);
- BLI_task_pool_push(pool, ocean_compute_normal_z, NULL, false, TASK_PRIORITY_HIGH);
+ BLI_task_pool_push(pool, ocean_compute_normal_x, NULL, false, NULL);
+ BLI_task_pool_push(pool, ocean_compute_normal_z, NULL, false, NULL);
o->_N_y = 1.0f / scale;
}
diff --git a/source/blender/blenkernel/intern/paint.c b/source/blender/blenkernel/intern/paint.c
index 719336f7351..f26b478c680 100644
--- a/source/blender/blenkernel/intern/paint.c
+++ b/source/blender/blenkernel/intern/paint.c
@@ -10,7 +10,7 @@
* 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,
+ * 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) 2009 by Nicholas Bishop
@@ -44,7 +44,6 @@
#include "BLT_translation.h"
-#include "BKE_animsys.h"
#include "BKE_brush.h"
#include "BKE_ccg.h"
#include "BKE_colortools.h"
@@ -117,6 +116,7 @@ IDTypeInfo IDType_ID_PAL = {
.copy_data = palette_copy_data,
.free_data = palette_free_data,
.make_local = NULL,
+ .foreach_id = NULL,
};
static void paint_curve_copy_data(Main *UNUSED(bmain),
@@ -154,6 +154,7 @@ IDTypeInfo IDType_ID_PC = {
.copy_data = paint_curve_copy_data,
.free_data = paint_curve_free_data,
.make_local = NULL,
+ .foreach_id = NULL,
};
const char PAINT_CURSOR_SCULPT[3] = {255, 100, 100};
@@ -548,35 +549,35 @@ void BKE_paint_runtime_init(const ToolSettings *ts, Paint *paint)
paint->runtime.tool_offset = offsetof(Brush, imagepaint_tool);
paint->runtime.ob_mode = OB_MODE_TEXTURE_PAINT;
}
- else if (paint == &ts->sculpt->paint) {
+ else if (ts->sculpt && paint == &ts->sculpt->paint) {
paint->runtime.tool_offset = offsetof(Brush, sculpt_tool);
paint->runtime.ob_mode = OB_MODE_SCULPT;
}
- else if (paint == &ts->vpaint->paint) {
+ else if (ts->vpaint && paint == &ts->vpaint->paint) {
paint->runtime.tool_offset = offsetof(Brush, vertexpaint_tool);
paint->runtime.ob_mode = OB_MODE_VERTEX_PAINT;
}
- else if (paint == &ts->wpaint->paint) {
+ else if (ts->wpaint && paint == &ts->wpaint->paint) {
paint->runtime.tool_offset = offsetof(Brush, weightpaint_tool);
paint->runtime.ob_mode = OB_MODE_WEIGHT_PAINT;
}
- else if (paint == &ts->uvsculpt->paint) {
+ else if (ts->uvsculpt && paint == &ts->uvsculpt->paint) {
paint->runtime.tool_offset = offsetof(Brush, uv_sculpt_tool);
paint->runtime.ob_mode = OB_MODE_EDIT;
}
- else if (paint == &ts->gp_paint->paint) {
+ else if (ts->gp_paint && paint == &ts->gp_paint->paint) {
paint->runtime.tool_offset = offsetof(Brush, gpencil_tool);
paint->runtime.ob_mode = OB_MODE_PAINT_GPENCIL;
}
- else if (paint == &ts->gp_vertexpaint->paint) {
+ else if (ts->gp_vertexpaint && paint == &ts->gp_vertexpaint->paint) {
paint->runtime.tool_offset = offsetof(Brush, gpencil_vertex_tool);
paint->runtime.ob_mode = OB_MODE_VERTEX_GPENCIL;
}
- else if (paint == &ts->gp_sculptpaint->paint) {
+ else if (ts->gp_sculptpaint && paint == &ts->gp_sculptpaint->paint) {
paint->runtime.tool_offset = offsetof(Brush, gpencil_sculpt_tool);
paint->runtime.ob_mode = OB_MODE_SCULPT_GPENCIL;
}
- else if (paint == &ts->gp_weightpaint->paint) {
+ else if (ts->gp_weightpaint && paint == &ts->gp_weightpaint->paint) {
paint->runtime.tool_offset = offsetof(Brush, gpencil_weight_tool);
paint->runtime.ob_mode = OB_MODE_WEIGHT_GPENCIL;
}
@@ -1307,9 +1308,10 @@ static void sculptsession_free_pbvh(Object *object)
}
MEM_SAFE_FREE(ss->pmap);
-
MEM_SAFE_FREE(ss->pmap_mem);
+ MEM_SAFE_FREE(ss->layer_base);
+
MEM_SAFE_FREE(ss->preview_vert_index_list);
ss->preview_vert_index_count = 0;
}
@@ -1354,31 +1356,17 @@ void BKE_sculptsession_free(Object *ob)
BM_log_free(ss->bm_log);
}
- if (ss->texcache) {
- MEM_freeN(ss->texcache);
- }
+ MEM_SAFE_FREE(ss->texcache);
if (ss->tex_pool) {
BKE_image_pool_free(ss->tex_pool);
}
- if (ss->layer_co) {
- MEM_freeN(ss->layer_co);
- }
-
- if (ss->orig_cos) {
- MEM_freeN(ss->orig_cos);
- }
- if (ss->deform_cos) {
- MEM_freeN(ss->deform_cos);
- }
- if (ss->deform_imats) {
- MEM_freeN(ss->deform_imats);
- }
+ MEM_SAFE_FREE(ss->orig_cos);
+ MEM_SAFE_FREE(ss->deform_cos);
+ MEM_SAFE_FREE(ss->deform_imats);
- if (ss->preview_vert_index_list) {
- MEM_freeN(ss->preview_vert_index_list);
- }
+ MEM_SAFE_FREE(ss->preview_vert_index_list);
if (ss->pose_ik_chain_preview) {
for (int i = 0; i < ss->pose_ik_chain_preview->tot_segments; i++) {
@@ -1420,15 +1408,15 @@ MultiresModifierData *BKE_sculpt_multires_active(Scene *scene, Object *ob)
return NULL;
}
- for (md = modifiers_getVirtualModifierList(ob, &virtualModifierData); md; md = md->next) {
+ for (md = BKE_modifiers_get_virtual_modifierlist(ob, &virtualModifierData); md; md = md->next) {
if (md->type == eModifierType_Multires) {
MultiresModifierData *mmd = (MultiresModifierData *)md;
- if (!modifier_isEnabled(scene, md, eModifierMode_Realtime)) {
+ if (!BKE_modifier_is_enabled(scene, md, eModifierMode_Realtime)) {
continue;
}
- if (BKE_multires_sculpt_level_get(mmd) > 0) {
+ if (mmd->sculptlvl > 0) {
return mmd;
}
else {
@@ -1457,12 +1445,12 @@ static bool sculpt_modifiers_active(Scene *scene, Sculpt *sd, Object *ob)
return true;
}
- md = modifiers_getVirtualModifierList(ob, &virtualModifierData);
+ md = BKE_modifiers_get_virtual_modifierlist(ob, &virtualModifierData);
/* exception for shape keys because we can edit those */
for (; md; md = md->next) {
- const ModifierTypeInfo *mti = modifierType_getInfo(md->type);
- if (!modifier_isEnabled(scene, md, eModifierMode_Realtime)) {
+ const ModifierTypeInfo *mti = BKE_modifier_get_info(md->type);
+ if (!BKE_modifier_is_enabled(scene, md, eModifierMode_Realtime)) {
continue;
}
if (md->type == eModifierType_Multires && (ob->mode & OB_MODE_SCULPT)) {
@@ -1494,6 +1482,7 @@ static void sculpt_update_object(
SculptSession *ss = ob->sculpt;
Mesh *me = BKE_object_get_original_mesh(ob);
MultiresModifierData *mmd = BKE_sculpt_multires_active(scene, ob);
+ const bool use_face_sets = (ob->mode & OB_MODE_SCULPT) != 0;
ss->deform_modifiers_active = sculpt_modifiers_active(scene, sd, ob);
ss->show_mask = (sd->flags & SCULPT_HIDE_MASK) == 0;
@@ -1522,23 +1511,34 @@ static void sculpt_update_object(
/* NOTE: Weight pPaint require mesh info for loop lookup, but it never uses multires code path,
* so no extra checks is needed here. */
if (mmd) {
- ss->multires = mmd;
+ ss->multires.active = true;
+ ss->multires.modifier = mmd;
+ ss->multires.level = mmd->sculptlvl;
ss->totvert = me_eval->totvert;
ss->totpoly = me_eval->totpoly;
- ss->mvert = NULL;
- ss->mpoly = NULL;
- ss->mloop = NULL;
+ ss->totfaces = me->totpoly;
+
+ /* These are assigned to the base mesh in Multires. This is needed because Face Sets operators
+ * and tools use the Face Sets data from the base mesh when Multires is active. */
+ ss->mvert = me->mvert;
+ ss->mpoly = me->mpoly;
+ ss->mloop = me->mloop;
}
else {
ss->totvert = me->totvert;
ss->totpoly = me->totpoly;
+ ss->totfaces = me->totpoly;
ss->mvert = me->mvert;
ss->mpoly = me->mpoly;
ss->mloop = me->mloop;
- ss->multires = NULL;
+ ss->multires.active = false;
+ ss->multires.modifier = NULL;
+ ss->multires.level = 0;
ss->vmask = CustomData_get_layer(&me->vdata, CD_PAINT_MASK);
+ }
- /* Sculpt Face Sets. */
+ /* Sculpt Face Sets. */
+ if (use_face_sets) {
if (!CustomData_has_layer(&me->pdata, CD_SCULPT_FACE_SETS)) {
ss->face_sets = CustomData_add_layer(
&me->pdata, CD_SCULPT_FACE_SETS, CD_CALLOC, NULL, me->totpoly);
@@ -1551,6 +1551,9 @@ static void sculpt_update_object(
}
ss->face_sets = CustomData_get_layer(&me->pdata, CD_SCULPT_FACE_SETS);
}
+ else {
+ ss->face_sets = NULL;
+ }
ss->subdiv_ccg = me_eval->runtime.subdiv_ccg;
@@ -1558,6 +1561,9 @@ static void sculpt_update_object(
BLI_assert(pbvh == ss->pbvh);
UNUSED_VARS_NDEBUG(pbvh);
+ BKE_pbvh_subdiv_cgg_set(ss->pbvh, ss->subdiv_ccg);
+ BKE_pbvh_face_sets_set(ss->pbvh, ss->face_sets);
+
BKE_pbvh_face_sets_color_set(ss->pbvh, me->face_sets_color_seed, me->face_sets_color_default);
if (need_pmap && ob->type == OB_MESH && !ss->pmap) {
@@ -1688,7 +1694,7 @@ int BKE_sculpt_mask_layers_ensure(Object *ob, MultiresModifierData *mmd)
* isn't one already */
if (mmd && !CustomData_has_layer(&me->ldata, CD_GRID_PAINT_MASK)) {
GridPaintMask *gmask;
- int level = max_ii(1, BKE_multires_sculpt_level_get(mmd));
+ int level = max_ii(1, mmd->sculptlvl);
int gridsize = BKE_ccg_gridsize(level);
int gridarea = gridsize * gridsize;
int i, j;
@@ -1807,11 +1813,12 @@ static PBVH *build_pbvh_for_dynamic_topology(Object *ob)
return pbvh;
}
-static PBVH *build_pbvh_from_regular_mesh(Object *ob, Mesh *me_eval_deform)
+static PBVH *build_pbvh_from_regular_mesh(Object *ob, Mesh *me_eval_deform, bool respect_hide)
{
Mesh *me = BKE_object_get_original_mesh(ob);
const int looptris_num = poly_to_tri_count(me->totpoly, me->totloop);
PBVH *pbvh = BKE_pbvh_new();
+ BKE_pbvh_respect_hide_set(pbvh, respect_hide);
MLoopTri *looptri = MEM_malloc_arrayN(looptris_num, sizeof(*looptri), __func__);
@@ -1843,11 +1850,12 @@ static PBVH *build_pbvh_from_regular_mesh(Object *ob, Mesh *me_eval_deform)
return pbvh;
}
-static PBVH *build_pbvh_from_ccg(Object *ob, SubdivCCG *subdiv_ccg)
+static PBVH *build_pbvh_from_ccg(Object *ob, SubdivCCG *subdiv_ccg, bool respect_hide)
{
CCGKey key;
BKE_subdiv_ccg_key_top_level(&key, subdiv_ccg);
PBVH *pbvh = BKE_pbvh_new();
+ BKE_pbvh_respect_hide_set(pbvh, respect_hide);
BKE_pbvh_build_grids(pbvh,
subdiv_ccg->grids,
subdiv_ccg->num_grids,
@@ -1856,7 +1864,7 @@ static PBVH *build_pbvh_from_ccg(Object *ob, SubdivCCG *subdiv_ccg)
subdiv_ccg->grid_flag_mats,
subdiv_ccg->grid_hidden);
pbvh_show_mask_set(pbvh, ob->sculpt->show_mask);
- pbvh_show_face_sets_set(pbvh, false);
+ pbvh_show_face_sets_set(pbvh, ob->sculpt->show_face_sets);
return pbvh;
}
@@ -1865,6 +1873,14 @@ PBVH *BKE_sculpt_object_pbvh_ensure(Depsgraph *depsgraph, Object *ob)
if (ob == NULL || ob->sculpt == NULL) {
return NULL;
}
+
+ bool respect_hide = true;
+ if (ob->mode & (OB_MODE_VERTEX_PAINT | OB_MODE_WEIGHT_PAINT)) {
+ if (!(BKE_paint_select_vert_test(ob) || BKE_paint_select_face_test(ob))) {
+ respect_hide = false;
+ }
+ }
+
PBVH *pbvh = ob->sculpt->pbvh;
if (pbvh != NULL) {
/* NOTE: It is possible that grids were re-allocated due to modifier
@@ -1888,11 +1904,11 @@ PBVH *BKE_sculpt_object_pbvh_ensure(Depsgraph *depsgraph, Object *ob)
Object *object_eval = DEG_get_evaluated_object(depsgraph, ob);
Mesh *mesh_eval = object_eval->data;
if (mesh_eval->runtime.subdiv_ccg != NULL) {
- pbvh = build_pbvh_from_ccg(ob, mesh_eval->runtime.subdiv_ccg);
+ pbvh = build_pbvh_from_ccg(ob, mesh_eval->runtime.subdiv_ccg, respect_hide);
}
else if (ob->type == OB_MESH) {
Mesh *me_eval_deform = object_eval->runtime.mesh_deform_eval;
- pbvh = build_pbvh_from_regular_mesh(ob, me_eval_deform);
+ pbvh = build_pbvh_from_regular_mesh(ob, me_eval_deform, respect_hide);
}
}
diff --git a/source/blender/blenkernel/intern/paint_toolslots.c b/source/blender/blenkernel/intern/paint_toolslots.c
index ea5cb168b12..0ea0173f8a3 100644
--- a/source/blender/blenkernel/intern/paint_toolslots.c
+++ b/source/blender/blenkernel/intern/paint_toolslots.c
@@ -10,7 +10,7 @@
* 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,
+ * along with this program; if not, write to the Free Software Foundation,
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
@@ -33,6 +33,13 @@
#include "BKE_main.h"
#include "BKE_paint.h"
+/* -------------------------------------------------------------------- */
+/** \name Tool Slot Initialization / Versioning
+ *
+ * These functions run to update old files (while versioning),
+ * take care only to perform low-level functions here.
+ * \{ */
+
void BKE_paint_toolslots_len_ensure(Paint *paint, int len)
{
/* Tool slots are 'uchar'. */
@@ -62,38 +69,54 @@ static void paint_toolslots_init(Main *bmain, Paint *paint)
}
}
+/**
+ * Initialize runtime since this is called from versioning code.
+ */
+static void paint_toolslots_init_with_runtime(Main *bmain, ToolSettings *ts, Paint *paint)
+{
+ if (paint == NULL) {
+ return;
+ }
+
+ /* Needed so #Paint_Runtime is updated when versioning. */
+ BKE_paint_runtime_init(ts, paint);
+ paint_toolslots_init(bmain, paint);
+}
+
void BKE_paint_toolslots_init_from_main(struct Main *bmain)
{
for (Scene *scene = bmain->scenes.first; scene; scene = scene->id.next) {
ToolSettings *ts = scene->toolsettings;
- paint_toolslots_init(bmain, &ts->imapaint.paint);
+ paint_toolslots_init_with_runtime(bmain, ts, &ts->imapaint.paint);
if (ts->sculpt) {
- paint_toolslots_init(bmain, &ts->sculpt->paint);
+ paint_toolslots_init_with_runtime(bmain, ts, &ts->sculpt->paint);
}
if (ts->vpaint) {
- paint_toolslots_init(bmain, &ts->vpaint->paint);
+ paint_toolslots_init_with_runtime(bmain, ts, &ts->vpaint->paint);
}
if (ts->wpaint) {
- paint_toolslots_init(bmain, &ts->wpaint->paint);
+ paint_toolslots_init_with_runtime(bmain, ts, &ts->wpaint->paint);
}
if (ts->uvsculpt) {
- paint_toolslots_init(bmain, &ts->uvsculpt->paint);
+ paint_toolslots_init_with_runtime(bmain, ts, &ts->uvsculpt->paint);
}
if (ts->gp_paint) {
- paint_toolslots_init(bmain, &ts->gp_paint->paint);
+ paint_toolslots_init_with_runtime(bmain, ts, &ts->gp_paint->paint);
}
if (ts->gp_vertexpaint) {
- paint_toolslots_init(bmain, &ts->gp_vertexpaint->paint);
+ paint_toolslots_init_with_runtime(bmain, ts, &ts->gp_vertexpaint->paint);
}
if (ts->gp_sculptpaint) {
- paint_toolslots_init(bmain, &ts->gp_sculptpaint->paint);
+ paint_toolslots_init_with_runtime(bmain, ts, &ts->gp_sculptpaint->paint);
}
if (ts->gp_weightpaint) {
- paint_toolslots_init(bmain, &ts->gp_weightpaint->paint);
+ paint_toolslots_init_with_runtime(bmain, ts, &ts->gp_weightpaint->paint);
}
}
}
+/** \} */
+
void BKE_paint_toolslots_brush_update_ex(Paint *paint, Brush *brush)
{
const uint tool_offset = paint->runtime.tool_offset;
diff --git a/source/blender/blenkernel/intern/particle.c b/source/blender/blenkernel/intern/particle.c
index f110a2bd3ae..eb485e1522f 100644
--- a/source/blender/blenkernel/intern/particle.c
+++ b/source/blender/blenkernel/intern/particle.c
@@ -50,28 +50,27 @@
#include "BLT_translation.h"
-#include "BKE_anim.h"
-#include "BKE_animsys.h"
-
+#include "BKE_anim_path.h"
#include "BKE_boids.h"
#include "BKE_cloth.h"
#include "BKE_collection.h"
#include "BKE_colortools.h"
-#include "BKE_effect.h"
-#include "BKE_idtype.h"
-#include "BKE_lattice.h"
-#include "BKE_main.h"
-
#include "BKE_deform.h"
#include "BKE_displist.h"
+#include "BKE_effect.h"
+#include "BKE_idtype.h"
#include "BKE_key.h"
+#include "BKE_lattice.h"
#include "BKE_lib_id.h"
+#include "BKE_lib_query.h"
+#include "BKE_main.h"
#include "BKE_material.h"
#include "BKE_mesh.h"
#include "BKE_modifier.h"
#include "BKE_particle.h"
#include "BKE_pointcache.h"
#include "BKE_scene.h"
+#include "BKE_texture.h"
#include "DEG_depsgraph.h"
#include "DEG_depsgraph_build.h"
@@ -148,6 +147,53 @@ static void particle_settings_free_data(ID *id)
fluid_free_settings(particle_settings->fluid);
}
+static void particle_settings_foreach_id(ID *id, LibraryForeachIDData *data)
+{
+ ParticleSettings *psett = (ParticleSettings *)id;
+ BKE_LIB_FOREACHID_PROCESS(data, psett->instance_collection, IDWALK_CB_USER);
+ BKE_LIB_FOREACHID_PROCESS(data, psett->instance_object, IDWALK_CB_NOP);
+ BKE_LIB_FOREACHID_PROCESS(data, psett->bb_ob, IDWALK_CB_NOP);
+ BKE_LIB_FOREACHID_PROCESS(data, psett->collision_group, IDWALK_CB_NOP);
+
+ for (int i = 0; i < MAX_MTEX; i++) {
+ if (psett->mtex[i]) {
+ BKE_texture_mtex_foreach_id(data, psett->mtex[i]);
+ }
+ }
+
+ if (psett->effector_weights) {
+ BKE_LIB_FOREACHID_PROCESS(data, psett->effector_weights->group, IDWALK_CB_NOP);
+ }
+
+ if (psett->pd) {
+ BKE_LIB_FOREACHID_PROCESS(data, psett->pd->tex, IDWALK_CB_USER);
+ BKE_LIB_FOREACHID_PROCESS(data, psett->pd->f_source, IDWALK_CB_NOP);
+ }
+ if (psett->pd2) {
+ BKE_LIB_FOREACHID_PROCESS(data, psett->pd2->tex, IDWALK_CB_USER);
+ BKE_LIB_FOREACHID_PROCESS(data, psett->pd2->f_source, IDWALK_CB_NOP);
+ }
+
+ if (psett->boids) {
+ LISTBASE_FOREACH (BoidState *, state, &psett->boids->states) {
+ LISTBASE_FOREACH (BoidRule *, rule, &state->rules) {
+ if (rule->type == eBoidRuleType_Avoid) {
+ BoidRuleGoalAvoid *gabr = (BoidRuleGoalAvoid *)rule;
+ BKE_LIB_FOREACHID_PROCESS(data, gabr->ob, IDWALK_CB_NOP);
+ }
+ else if (rule->type == eBoidRuleType_FollowLeader) {
+ BoidRuleFollowLeader *flbr = (BoidRuleFollowLeader *)rule;
+ BKE_LIB_FOREACHID_PROCESS(data, flbr->ob, IDWALK_CB_NOP);
+ }
+ }
+ }
+ }
+
+ LISTBASE_FOREACH (ParticleDupliWeight *, dw, &psett->instance_weights) {
+ BKE_LIB_FOREACHID_PROCESS(data, dw->ob, IDWALK_CB_NOP);
+ }
+}
+
IDTypeInfo IDType_ID_PA = {
.id_code = ID_PA,
.id_filter = FILTER_ID_PA,
@@ -162,6 +208,7 @@ IDTypeInfo IDType_ID_PA = {
.copy_data = particle_settings_copy_data,
.free_data = particle_settings_free_data,
.make_local = NULL,
+ .foreach_id = particle_settings_foreach_id,
};
unsigned int PSYS_FRAND_SEED_OFFSET[PSYS_FRAND_COUNT];
@@ -481,7 +528,7 @@ void psys_find_group_weights(ParticleSettings *part)
instance_collection_objects = BKE_collection_object_cache_get(part->instance_collection);
}
- for (ParticleDupliWeight *dw = part->instance_weights.first; dw; dw = dw->next) {
+ LISTBASE_FOREACH (ParticleDupliWeight *, dw, &part->instance_weights) {
if (dw->ob == NULL) {
Base *base = BLI_findlink(&instance_collection_objects, dw->index);
if (base != NULL) {
@@ -585,7 +632,7 @@ void free_hair(Object *object, ParticleSystem *psys, int dynamics)
if (psys->clmd) {
if (dynamics) {
- modifier_free((ModifierData *)psys->clmd);
+ BKE_modifier_free((ModifierData *)psys->clmd);
psys->clmd = NULL;
PTCacheID pid;
BKE_ptcache_id_from_particles(&pid, object, psys);
@@ -737,7 +784,7 @@ void psys_free(Object *ob, ParticleSystem *psys)
*/
free_hair(ob, psys, 0);
if (psys->clmd != NULL) {
- modifier_free((ModifierData *)psys->clmd);
+ BKE_modifier_free((ModifierData *)psys->clmd);
}
psys_free_particles(psys);
@@ -2385,9 +2432,10 @@ static bool psys_thread_context_init_path(ParticleThreadContext *ctx,
}
else {
totchild = (int)((float)totchild * (float)part->disp / 100.0f);
- totparent = MIN2(totparent, totchild);
}
+ totparent = MIN2(totparent, totchild);
+
if (totchild == 0) {
return false;
}
@@ -2789,9 +2837,7 @@ static void psys_thread_create_path(ParticleTask *task,
}
}
-static void exec_child_path_cache(TaskPool *__restrict UNUSED(pool),
- void *taskdata,
- int UNUSED(threadid))
+static void exec_child_path_cache(TaskPool *__restrict UNUSED(pool), void *taskdata)
{
ParticleTask *task = taskdata;
ParticleThreadContext *ctx = task->ctx;
@@ -2812,7 +2858,6 @@ void psys_cache_child_paths(ParticleSimulationData *sim,
const bool editupdate,
const bool use_render_params)
{
- TaskScheduler *task_scheduler;
TaskPool *task_pool;
ParticleThreadContext ctx;
ParticleTask *tasks_parent, *tasks_child;
@@ -2828,8 +2873,7 @@ void psys_cache_child_paths(ParticleSimulationData *sim,
return;
}
- task_scheduler = BLI_task_scheduler_get();
- task_pool = BLI_task_pool_create(task_scheduler, &ctx);
+ task_pool = BLI_task_pool_create(&ctx, TASK_PRIORITY_LOW);
totchild = ctx.totchild;
totparent = ctx.totparent;
@@ -2852,7 +2896,7 @@ void psys_cache_child_paths(ParticleSimulationData *sim,
ParticleTask *task = &tasks_parent[i];
psys_task_init_path(task, sim);
- BLI_task_pool_push(task_pool, exec_child_path_cache, task, false, TASK_PRIORITY_LOW);
+ BLI_task_pool_push(task_pool, exec_child_path_cache, task, false, NULL);
}
BLI_task_pool_work_and_wait(task_pool);
@@ -2863,7 +2907,7 @@ void psys_cache_child_paths(ParticleSimulationData *sim,
ParticleTask *task = &tasks_child[i];
psys_task_init_path(task, sim);
- BLI_task_pool_push(task_pool, exec_child_path_cache, task, false, TASK_PRIORITY_LOW);
+ BLI_task_pool_push(task_pool, exec_child_path_cache, task, false, NULL);
}
BLI_task_pool_work_and_wait(task_pool);
@@ -3379,7 +3423,6 @@ void psys_cache_edit_paths(Depsgraph *depsgraph,
TaskParallelSettings settings;
BLI_parallel_range_settings_defaults(&settings);
- settings.scheduling_mode = TASK_SCHEDULING_DYNAMIC;
BLI_task_parallel_range(0, edit->totpoint, &iter_data, psys_cache_edit_paths_iter, &settings);
edit->totcached = totpart;
@@ -3592,9 +3635,9 @@ ModifierData *object_add_particle_system(Main *bmain, Scene *scene, Object *ob,
psys->part = BKE_particlesettings_add(bmain, psys->name);
- md = modifier_new(eModifierType_ParticleSystem);
+ md = BKE_modifier_new(eModifierType_ParticleSystem);
BLI_strncpy(md->name, psys->name, sizeof(md->name));
- modifier_unique_name(&ob->modifiers, md);
+ BKE_modifier_unique_name(&ob->modifiers, md);
psmd = (ParticleSystemModifierData *)md;
psmd->psys = psys;
@@ -3622,7 +3665,7 @@ void object_remove_particle_system(Main *bmain, Scene *UNUSED(scene), Object *ob
}
/* Clear particle system in fluid modifier. */
- if ((md = modifiers_findByType(ob, eModifierType_Fluid))) {
+ if ((md = BKE_modifiers_findby_type(ob, eModifierType_Fluid))) {
FluidModifierData *mmd = (FluidModifierData *)md;
/* Clear particle system pointer in flow settings. */
@@ -3664,7 +3707,7 @@ void object_remove_particle_system(Main *bmain, Scene *UNUSED(scene), Object *ob
}
}
- if ((md = modifiers_findByType(ob, eModifierType_DynamicPaint))) {
+ if ((md = BKE_modifiers_findby_type(ob, eModifierType_DynamicPaint))) {
DynamicPaintModifierData *pmd = (DynamicPaintModifierData *)md;
if (pmd->brush && pmd->brush->psys) {
if (pmd->brush->psys == psys) {
@@ -3677,7 +3720,7 @@ void object_remove_particle_system(Main *bmain, Scene *UNUSED(scene), Object *ob
psmd = psys_get_modifier(ob, psys);
if (psmd) {
BLI_remlink(&ob->modifiers, psmd);
- modifier_free((ModifierData *)psmd);
+ BKE_modifier_free((ModifierData *)psmd);
}
/* Clear particle system. */
@@ -4011,7 +4054,7 @@ static void get_cpa_texture(Mesh *mesh,
break;
}
- externtex(mtex, texvec, &value, rgba, rgba + 1, rgba + 2, rgba + 3, 0, NULL, false, false);
+ RE_texture_evaluate(mtex, texvec, 0, NULL, false, false, &value, rgba);
if ((event & mtex->mapto) & PAMAP_ROUGH) {
ptex->rough1 = ptex->rough2 = ptex->roughe = texture_value_blend(
@@ -4126,7 +4169,7 @@ void psys_get_texture(
break;
}
- externtex(mtex, texvec, &value, rgba, rgba + 1, rgba + 2, rgba + 3, 0, NULL, false, false);
+ RE_texture_evaluate(mtex, texvec, 0, NULL, false, false, &value, rgba);
if ((event & mtex->mapto) & PAMAP_TIME) {
/* the first time has to set the base value for time regardless of blend mode */
@@ -4740,11 +4783,11 @@ void psys_get_dupli_texture(ParticleSystem *psys,
/* XXX: on checking '(psmd->dm != NULL)'
* This is incorrect but needed for metaball evaluation.
- * Ideally this would be calculated via the depsgraph, however with metaballs,
+ * Ideally this would be calculated via the depsgraph, however with meta-balls,
* the entire scenes dupli's are scanned, which also looks into uncalculated data.
*
* For now just include this workaround as an alternative to crashing,
- * but longer term metaballs should behave in a more manageable way, see: T46622. */
+ * but longer term meta-balls should behave in a more manageable way, see: T46622. */
uv[0] = uv[1] = 0.f;
diff --git a/source/blender/blenkernel/intern/particle_distribute.c b/source/blender/blenkernel/intern/particle_distribute.c
index 9069f549e61..7b9b2484dbe 100644
--- a/source/blender/blenkernel/intern/particle_distribute.c
+++ b/source/blender/blenkernel/intern/particle_distribute.c
@@ -773,9 +773,7 @@ static void distribute_children_exec(ParticleTask *thread, ChildParticle *cpa, i
}
}
-static void exec_distribute_parent(TaskPool *__restrict UNUSED(pool),
- void *taskdata,
- int UNUSED(threadid))
+static void exec_distribute_parent(TaskPool *__restrict UNUSED(pool), void *taskdata)
{
ParticleTask *task = taskdata;
ParticleSystem *psys = task->ctx->sim.psys;
@@ -804,9 +802,7 @@ static void exec_distribute_parent(TaskPool *__restrict UNUSED(pool),
}
}
-static void exec_distribute_child(TaskPool *__restrict UNUSED(pool),
- void *taskdata,
- int UNUSED(threadid))
+static void exec_distribute_child(TaskPool *__restrict UNUSED(pool), void *taskdata)
{
ParticleTask *task = taskdata;
ParticleSystem *psys = task->ctx->sim.psys;
@@ -1324,7 +1320,6 @@ static void psys_task_init_distribute(ParticleTask *task, ParticleSimulationData
static void distribute_particles_on_dm(ParticleSimulationData *sim, int from)
{
- TaskScheduler *task_scheduler;
TaskPool *task_pool;
ParticleThreadContext ctx;
ParticleTask *tasks;
@@ -1336,8 +1331,7 @@ static void distribute_particles_on_dm(ParticleSimulationData *sim, int from)
return;
}
- task_scheduler = BLI_task_scheduler_get();
- task_pool = BLI_task_pool_create(task_scheduler, &ctx);
+ task_pool = BLI_task_pool_create(&ctx, TASK_PRIORITY_LOW);
totpart = (from == PART_FROM_CHILD ? sim->psys->totchild : sim->psys->totpart);
psys_tasks_create(&ctx, 0, totpart, &tasks, &numtasks);
@@ -1346,10 +1340,10 @@ static void distribute_particles_on_dm(ParticleSimulationData *sim, int from)
psys_task_init_distribute(task, sim);
if (from == PART_FROM_CHILD) {
- BLI_task_pool_push(task_pool, exec_distribute_child, task, false, TASK_PRIORITY_LOW);
+ BLI_task_pool_push(task_pool, exec_distribute_child, task, false, NULL);
}
else {
- BLI_task_pool_push(task_pool, exec_distribute_parent, task, false, TASK_PRIORITY_LOW);
+ BLI_task_pool_push(task_pool, exec_distribute_parent, task, false, NULL);
}
}
BLI_task_pool_work_and_wait(task_pool);
diff --git a/source/blender/blenkernel/intern/particle_system.c b/source/blender/blenkernel/intern/particle_system.c
index cc49f500a5f..31d51a74e7f 100644
--- a/source/blender/blenkernel/intern/particle_system.c
+++ b/source/blender/blenkernel/intern/particle_system.c
@@ -1258,7 +1258,8 @@ static void set_keyed_keys(ParticleSimulationData *sim)
key = pa->keys + k;
key->time = -1.0; /* use current time */
- psys_get_particle_state(&ksim, p % ksim.psys->totpart, key, 1);
+ const int p_ksim = (ksim.psys->totpart) ? p % ksim.psys->totpart : 0;
+ psys_get_particle_state(&ksim, p_ksim, key, 1);
if (psys->flag & PSYS_KEYED_TIMING) {
key->time = pa->time + pt->time;
@@ -2162,7 +2163,7 @@ static void psys_sph_flush_springs(SPHData *sphdata)
BLI_buffer_field_free(&sphdata->new_springs);
}
-void psys_sph_finalise(SPHData *sphdata)
+void psys_sph_finalize(SPHData *sphdata)
{
psys_sph_flush_springs(sphdata);
@@ -3449,7 +3450,7 @@ static void do_hair_dynamics(ParticleSimulationData *sim)
bool realloc_roots;
if (!psys->clmd) {
- psys->clmd = (ClothModifierData *)modifier_new(eModifierType_Cloth);
+ psys->clmd = (ClothModifierData *)BKE_modifier_new(eModifierType_Cloth);
psys->clmd->sim_parms->goalspring = 0.0f;
psys->clmd->sim_parms->flags |= CLOTH_SIMSETTINGS_FLAG_RESIST_SPRING_COMPRESS;
psys->clmd->coll_parms->flags &= ~CLOTH_COLLSETTINGS_FLAG_SELF;
@@ -3692,10 +3693,11 @@ typedef struct DynamicStepSolverTaskData {
SpinLock spin;
} DynamicStepSolverTaskData;
-static void dynamics_step_finalize_sphdata(void *__restrict UNUSED(userdata),
- void *__restrict tls_userdata_chunk)
+static void dynamics_step_sphdata_reduce(const void *__restrict UNUSED(userdata),
+ void *__restrict UNUSED(join_v),
+ void *__restrict chunk_v)
{
- SPHData *sphdata = tls_userdata_chunk;
+ SPHData *sphdata = chunk_v;
psys_sph_flush_springs(sphdata);
}
@@ -3986,7 +3988,7 @@ static void dynamics_step(ParticleSimulationData *sim, float cfra)
settings.use_threading = (psys->totpart > 100);
settings.userdata_chunk = &sphdata;
settings.userdata_chunk_size = sizeof(sphdata);
- settings.func_finalize = dynamics_step_finalize_sphdata;
+ settings.func_reduce = dynamics_step_sphdata_reduce;
BLI_task_parallel_range(
0, psys->totpart, &task_data, dynamics_step_sph_ddr_task_cb_ex, &settings);
@@ -4018,7 +4020,7 @@ static void dynamics_step(ParticleSimulationData *sim, float cfra)
settings.use_threading = (psys->totpart > 100);
settings.userdata_chunk = &sphdata;
settings.userdata_chunk_size = sizeof(sphdata);
- settings.func_finalize = dynamics_step_finalize_sphdata;
+ settings.func_reduce = dynamics_step_sphdata_reduce;
BLI_task_parallel_range(0,
psys->totpart,
&task_data,
@@ -4033,7 +4035,7 @@ static void dynamics_step(ParticleSimulationData *sim, float cfra)
settings.use_threading = (psys->totpart > 100);
settings.userdata_chunk = &sphdata;
settings.userdata_chunk_size = sizeof(sphdata);
- settings.func_finalize = dynamics_step_finalize_sphdata;
+ settings.func_reduce = dynamics_step_sphdata_reduce;
BLI_task_parallel_range(0,
psys->totpart,
&task_data,
@@ -4044,7 +4046,7 @@ static void dynamics_step(ParticleSimulationData *sim, float cfra)
BLI_spin_end(&task_data.spin);
- psys_sph_finalise(&sphdata);
+ psys_sph_finalize(&sphdata);
break;
}
}
@@ -4181,7 +4183,8 @@ static void particles_fluid_step(ParticleSimulationData *sim,
#else
{
Object *ob = sim->ob;
- FluidModifierData *mmd = (FluidModifierData *)modifiers_findByType(ob, eModifierType_Fluid);
+ FluidModifierData *mmd = (FluidModifierData *)BKE_modifiers_findby_type(ob,
+ eModifierType_Fluid);
if (mmd && mmd->domain && mmd->domain->fluid) {
FluidDomainSettings *mds = mmd->domain;
@@ -4189,7 +4192,7 @@ static void particles_fluid_step(ParticleSimulationData *sim,
ParticleSettings *part = psys->part;
ParticleData *pa = NULL;
- int p, totpart, tottypepart = 0;
+ int p, totpart = 0, tottypepart = 0;
int flagActivePart, activeParts = 0;
float posX, posY, posZ, velX, velY, velZ;
float resX, resY, resZ;
@@ -4847,7 +4850,7 @@ void particle_system_update(struct Depsgraph *depsgraph,
hcfra = 100.0f * (float)i / (float)psys->part->hair_step;
if ((part->flag & PART_HAIR_REGROW) == 0) {
BKE_animsys_evaluate_animdata(
- scene, &part_local->id, part_local->adt, hcfra, ADT_RECALC_ANIM, false);
+ &part_local->id, part_local->adt, hcfra, ADT_RECALC_ANIM, false);
}
system_step(&sim, hcfra, use_render_params);
psys->cfra = hcfra;
diff --git a/source/blender/blenkernel/intern/pbvh.c b/source/blender/blenkernel/intern/pbvh.c
index 9a4ce8acb11..19f28047b80 100644
--- a/source/blender/blenkernel/intern/pbvh.c
+++ b/source/blender/blenkernel/intern/pbvh.c
@@ -61,7 +61,7 @@ typedef struct PBVHStack {
} PBVHStack;
typedef struct PBVHIter {
- PBVH *bvh;
+ PBVH *pbvh;
BKE_pbvh_SearchCallback scb;
void *search_data;
@@ -131,7 +131,7 @@ void BBC_update_centroid(BBC *bbc)
}
/* Not recursive */
-static void update_node_vb(PBVH *bvh, PBVHNode *node)
+static void update_node_vb(PBVH *pbvh, PBVHNode *node)
{
BB vb;
@@ -140,15 +140,15 @@ static void update_node_vb(PBVH *bvh, PBVHNode *node)
if (node->flag & PBVH_Leaf) {
PBVHVertexIter vd;
- BKE_pbvh_vertex_iter_begin(bvh, node, vd, PBVH_ITER_ALL)
+ BKE_pbvh_vertex_iter_begin(pbvh, node, vd, PBVH_ITER_ALL)
{
BB_expand(&vb, vd.co);
}
BKE_pbvh_vertex_iter_end;
}
else {
- BB_expand_with_bb(&vb, &bvh->nodes[node->children_offset].vb);
- BB_expand_with_bb(&vb, &bvh->nodes[node->children_offset + 1].vb);
+ BB_expand_with_bb(&vb, &pbvh->nodes[node->children_offset].vb);
+ BB_expand_with_bb(&vb, &pbvh->nodes[node->children_offset + 1].vb);
}
node->vb = vb;
@@ -197,24 +197,24 @@ static int partition_indices(int *prim_indices, int lo, int hi, int axis, float
}
/* Returns the index of the first element on the right of the partition */
-static int partition_indices_material(PBVH *bvh, int lo, int hi)
+static int partition_indices_material(PBVH *pbvh, int lo, int hi)
{
- const MPoly *mpoly = bvh->mpoly;
- const MLoopTri *looptri = bvh->looptri;
- const DMFlagMat *flagmats = bvh->grid_flag_mats;
- const int *indices = bvh->prim_indices;
+ const MPoly *mpoly = pbvh->mpoly;
+ const MLoopTri *looptri = pbvh->looptri;
+ const DMFlagMat *flagmats = pbvh->grid_flag_mats;
+ const int *indices = pbvh->prim_indices;
const void *first;
int i = lo, j = hi;
- if (bvh->looptri) {
- first = &mpoly[looptri[bvh->prim_indices[lo]].poly];
+ if (pbvh->looptri) {
+ first = &mpoly[looptri[pbvh->prim_indices[lo]].poly];
}
else {
- first = &flagmats[bvh->prim_indices[lo]];
+ first = &flagmats[pbvh->prim_indices[lo]];
}
for (;;) {
- if (bvh->looptri) {
+ if (pbvh->looptri) {
for (; face_materials_match(first, &mpoly[looptri[indices[i]].poly]); i++) {
/* pass */
}
@@ -235,36 +235,36 @@ static int partition_indices_material(PBVH *bvh, int lo, int hi)
return i;
}
- SWAP(int, bvh->prim_indices[i], bvh->prim_indices[j]);
+ SWAP(int, pbvh->prim_indices[i], pbvh->prim_indices[j]);
i++;
}
}
-void pbvh_grow_nodes(PBVH *bvh, int totnode)
+void pbvh_grow_nodes(PBVH *pbvh, int totnode)
{
- if (UNLIKELY(totnode > bvh->node_mem_count)) {
- bvh->node_mem_count = bvh->node_mem_count + (bvh->node_mem_count / 3);
- if (bvh->node_mem_count < totnode) {
- bvh->node_mem_count = totnode;
+ if (UNLIKELY(totnode > pbvh->node_mem_count)) {
+ pbvh->node_mem_count = pbvh->node_mem_count + (pbvh->node_mem_count / 3);
+ if (pbvh->node_mem_count < totnode) {
+ pbvh->node_mem_count = totnode;
}
- bvh->nodes = MEM_recallocN(bvh->nodes, sizeof(PBVHNode) * bvh->node_mem_count);
+ pbvh->nodes = MEM_recallocN(pbvh->nodes, sizeof(PBVHNode) * pbvh->node_mem_count);
}
- bvh->totnode = totnode;
+ pbvh->totnode = totnode;
}
/* Add a vertex to the map, with a positive value for unique vertices and
* a negative value for additional vertices */
static int map_insert_vert(
- PBVH *bvh, GHash *map, unsigned int *face_verts, unsigned int *uniq_verts, int vertex)
+ PBVH *pbvh, GHash *map, unsigned int *face_verts, unsigned int *uniq_verts, int vertex)
{
void *key, **value_p;
key = POINTER_FROM_INT(vertex);
if (!BLI_ghash_ensure_p(map, key, &value_p)) {
int value_i;
- if (BLI_BITMAP_TEST(bvh->vert_bitmap, vertex) == 0) {
- BLI_BITMAP_ENABLE(bvh->vert_bitmap, vertex);
+ if (BLI_BITMAP_TEST(pbvh->vert_bitmap, vertex) == 0) {
+ BLI_BITMAP_ENABLE(pbvh->vert_bitmap, vertex);
value_i = *uniq_verts;
(*uniq_verts)++;
}
@@ -281,7 +281,7 @@ static int map_insert_vert(
}
/* Find vertices used by the faces in this node and update the draw buffers */
-static void build_mesh_leaf_node(PBVH *bvh, PBVHNode *node)
+static void build_mesh_leaf_node(PBVH *pbvh, PBVHNode *node)
{
bool has_visible = false;
@@ -295,15 +295,21 @@ static void build_mesh_leaf_node(PBVH *bvh, PBVHNode *node)
node->face_vert_indices = (const int(*)[3])face_vert_indices;
+ if (pbvh->respect_hide == false) {
+ has_visible = true;
+ }
+
for (int i = 0; i < totface; i++) {
- const MLoopTri *lt = &bvh->looptri[node->prim_indices[i]];
+ const MLoopTri *lt = &pbvh->looptri[node->prim_indices[i]];
for (int j = 0; j < 3; j++) {
face_vert_indices[i][j] = map_insert_vert(
- bvh, map, &node->face_verts, &node->uniq_verts, bvh->mloop[lt->tri[j]].v);
+ pbvh, map, &node->face_verts, &node->uniq_verts, pbvh->mloop[lt->tri[j]].v);
}
- if (!paint_is_face_hidden(lt, bvh->verts, bvh->mloop)) {
- has_visible = true;
+ if (has_visible == false) {
+ if (!paint_is_face_hidden(lt, pbvh->verts, pbvh->mloop)) {
+ has_visible = true;
+ }
}
}
@@ -341,11 +347,11 @@ static void build_mesh_leaf_node(PBVH *bvh, PBVHNode *node)
BLI_ghash_free(map, NULL, NULL);
}
-static void update_vb(PBVH *bvh, PBVHNode *node, BBC *prim_bbc, int offset, int count)
+static void update_vb(PBVH *pbvh, PBVHNode *node, BBC *prim_bbc, int offset, int count)
{
BB_reset(&node->vb);
for (int i = offset + count - 1; i >= offset; i--) {
- BB_expand_with_bb(&node->vb, (BB *)(&prim_bbc[bvh->prim_indices[i]]));
+ BB_expand_with_bb(&node->vb, (BB *)(&prim_bbc[pbvh->prim_indices[i]]));
}
node->orig_vb = node->vb;
}
@@ -383,58 +389,78 @@ int BKE_pbvh_count_grid_quads(BLI_bitmap **grid_hidden,
return totquad;
}
-static void build_grid_leaf_node(PBVH *bvh, PBVHNode *node)
+void BKE_pbvh_sync_face_sets_to_grids(PBVH *pbvh)
+{
+ const int gridsize = pbvh->gridkey.grid_size;
+ for (int i = 0; i < pbvh->totgrid; i++) {
+ BLI_bitmap *gh = pbvh->grid_hidden[i];
+ const int face_index = BKE_subdiv_ccg_grid_to_face_index(pbvh->subdiv_ccg, i);
+ if (!gh && pbvh->face_sets[face_index] < 0) {
+ gh = pbvh->grid_hidden[i] = BLI_BITMAP_NEW(pbvh->gridkey.grid_area,
+ "partialvis_update_grids");
+ }
+ if (gh) {
+ for (int y = 0; y < gridsize; y++) {
+ for (int x = 0; x < gridsize; x++) {
+ BLI_BITMAP_SET(gh, y * gridsize + x, pbvh->face_sets[face_index] < 0);
+ }
+ }
+ }
+ }
+}
+
+static void build_grid_leaf_node(PBVH *pbvh, PBVHNode *node)
{
int totquads = BKE_pbvh_count_grid_quads(
- bvh->grid_hidden, node->prim_indices, node->totprim, bvh->gridkey.grid_size);
+ pbvh->grid_hidden, node->prim_indices, node->totprim, pbvh->gridkey.grid_size);
BKE_pbvh_node_fully_hidden_set(node, (totquads == 0));
BKE_pbvh_node_mark_rebuild_draw(node);
}
-static void build_leaf(PBVH *bvh, int node_index, BBC *prim_bbc, int offset, int count)
+static void build_leaf(PBVH *pbvh, int node_index, BBC *prim_bbc, int offset, int count)
{
- bvh->nodes[node_index].flag |= PBVH_Leaf;
+ pbvh->nodes[node_index].flag |= PBVH_Leaf;
- bvh->nodes[node_index].prim_indices = bvh->prim_indices + offset;
- bvh->nodes[node_index].totprim = count;
+ pbvh->nodes[node_index].prim_indices = pbvh->prim_indices + offset;
+ pbvh->nodes[node_index].totprim = count;
/* Still need vb for searches */
- update_vb(bvh, &bvh->nodes[node_index], prim_bbc, offset, count);
+ update_vb(pbvh, &pbvh->nodes[node_index], prim_bbc, offset, count);
- if (bvh->looptri) {
- build_mesh_leaf_node(bvh, bvh->nodes + node_index);
+ if (pbvh->looptri) {
+ build_mesh_leaf_node(pbvh, pbvh->nodes + node_index);
}
else {
- build_grid_leaf_node(bvh, bvh->nodes + node_index);
+ build_grid_leaf_node(pbvh, pbvh->nodes + node_index);
}
}
/* Return zero if all primitives in the node can be drawn with the
* same material (including flat/smooth shading), non-zero otherwise */
-static bool leaf_needs_material_split(PBVH *bvh, int offset, int count)
+static bool leaf_needs_material_split(PBVH *pbvh, int offset, int count)
{
if (count <= 1) {
return false;
}
- if (bvh->looptri) {
- const MLoopTri *first = &bvh->looptri[bvh->prim_indices[offset]];
- const MPoly *mp = &bvh->mpoly[first->poly];
+ if (pbvh->looptri) {
+ const MLoopTri *first = &pbvh->looptri[pbvh->prim_indices[offset]];
+ const MPoly *mp = &pbvh->mpoly[first->poly];
for (int i = offset + count - 1; i > offset; i--) {
- int prim = bvh->prim_indices[i];
- const MPoly *mp_other = &bvh->mpoly[bvh->looptri[prim].poly];
+ int prim = pbvh->prim_indices[i];
+ const MPoly *mp_other = &pbvh->mpoly[pbvh->looptri[prim].poly];
if (!face_materials_match(mp, mp_other)) {
return true;
}
}
}
else {
- const DMFlagMat *first = &bvh->grid_flag_mats[bvh->prim_indices[offset]];
+ const DMFlagMat *first = &pbvh->grid_flag_mats[pbvh->prim_indices[offset]];
for (int i = offset + count - 1; i > offset; i--) {
- int prim = bvh->prim_indices[i];
- if (!grid_materials_match(first, &bvh->grid_flag_mats[prim])) {
+ int prim = pbvh->prim_indices[i];
+ if (!grid_materials_match(first, &pbvh->grid_flag_mats[prim])) {
return true;
}
}
@@ -454,26 +480,26 @@ static bool leaf_needs_material_split(PBVH *bvh, int offset, int count)
* offset and start indicate a range in the array of primitive indices
*/
-static void build_sub(PBVH *bvh, int node_index, BB *cb, BBC *prim_bbc, int offset, int count)
+static void build_sub(PBVH *pbvh, int node_index, BB *cb, BBC *prim_bbc, int offset, int count)
{
int end;
BB cb_backing;
/* Decide whether this is a leaf or not */
- const bool below_leaf_limit = count <= bvh->leaf_limit;
+ const bool below_leaf_limit = count <= pbvh->leaf_limit;
if (below_leaf_limit) {
- if (!leaf_needs_material_split(bvh, offset, count)) {
- build_leaf(bvh, node_index, prim_bbc, offset, count);
+ if (!leaf_needs_material_split(pbvh, offset, count)) {
+ build_leaf(pbvh, node_index, prim_bbc, offset, count);
return;
}
}
/* Add two child nodes */
- bvh->nodes[node_index].children_offset = bvh->totnode;
- pbvh_grow_nodes(bvh, bvh->totnode + 2);
+ pbvh->nodes[node_index].children_offset = pbvh->totnode;
+ pbvh_grow_nodes(pbvh, pbvh->totnode + 2);
/* Update parent node bounding box */
- update_vb(bvh, &bvh->nodes[node_index], prim_bbc, offset, count);
+ update_vb(pbvh, &pbvh->nodes[node_index], prim_bbc, offset, count);
if (!below_leaf_limit) {
/* Find axis with widest range of primitive centroids */
@@ -481,13 +507,13 @@ static void build_sub(PBVH *bvh, int node_index, BB *cb, BBC *prim_bbc, int offs
cb = &cb_backing;
BB_reset(cb);
for (int i = offset + count - 1; i >= offset; i--) {
- BB_expand(cb, prim_bbc[bvh->prim_indices[i]].bcentroid);
+ BB_expand(cb, prim_bbc[pbvh->prim_indices[i]].bcentroid);
}
}
const int axis = BB_widest_axis(cb);
/* Partition primitives along that axis */
- end = partition_indices(bvh->prim_indices,
+ end = partition_indices(pbvh->prim_indices,
offset,
offset + count - 1,
axis,
@@ -496,38 +522,42 @@ static void build_sub(PBVH *bvh, int node_index, BB *cb, BBC *prim_bbc, int offs
}
else {
/* Partition primitives by material */
- end = partition_indices_material(bvh, offset, offset + count - 1);
+ end = partition_indices_material(pbvh, offset, offset + count - 1);
}
/* Build children */
- build_sub(bvh, bvh->nodes[node_index].children_offset, NULL, prim_bbc, offset, end - offset);
- build_sub(
- bvh, bvh->nodes[node_index].children_offset + 1, NULL, prim_bbc, end, offset + count - end);
+ build_sub(pbvh, pbvh->nodes[node_index].children_offset, NULL, prim_bbc, offset, end - offset);
+ build_sub(pbvh,
+ pbvh->nodes[node_index].children_offset + 1,
+ NULL,
+ prim_bbc,
+ end,
+ offset + count - end);
}
-static void pbvh_build(PBVH *bvh, BB *cb, BBC *prim_bbc, int totprim)
+static void pbvh_build(PBVH *pbvh, BB *cb, BBC *prim_bbc, int totprim)
{
- if (totprim != bvh->totprim) {
- bvh->totprim = totprim;
- if (bvh->nodes) {
- MEM_freeN(bvh->nodes);
+ if (totprim != pbvh->totprim) {
+ pbvh->totprim = totprim;
+ if (pbvh->nodes) {
+ MEM_freeN(pbvh->nodes);
}
- if (bvh->prim_indices) {
- MEM_freeN(bvh->prim_indices);
+ if (pbvh->prim_indices) {
+ MEM_freeN(pbvh->prim_indices);
}
- bvh->prim_indices = MEM_mallocN(sizeof(int) * totprim, "bvh prim indices");
+ pbvh->prim_indices = MEM_mallocN(sizeof(int) * totprim, "bvh prim indices");
for (int i = 0; i < totprim; i++) {
- bvh->prim_indices[i] = i;
+ pbvh->prim_indices[i] = i;
}
- bvh->totnode = 0;
- if (bvh->node_mem_count < 100) {
- bvh->node_mem_count = 100;
- bvh->nodes = MEM_callocN(sizeof(PBVHNode) * bvh->node_mem_count, "bvh initial nodes");
+ pbvh->totnode = 0;
+ if (pbvh->node_mem_count < 100) {
+ pbvh->node_mem_count = 100;
+ pbvh->nodes = MEM_callocN(sizeof(PBVHNode) * pbvh->node_mem_count, "bvh initial nodes");
}
}
- bvh->totnode = 1;
- build_sub(bvh, 0, cb, prim_bbc, 0, totprim);
+ pbvh->totnode = 1;
+ build_sub(pbvh, 0, cb, prim_bbc, 0, totprim);
}
/**
@@ -536,7 +566,7 @@ static void pbvh_build(PBVH *bvh, BB *cb, BBC *prim_bbc, int totprim)
* \note Unlike mpoly/mloop/verts, looptri is **totally owned** by PBVH
* (which means it may rewrite it if needed, see #BKE_pbvh_vert_coords_apply().
*/
-void BKE_pbvh_build_mesh(PBVH *bvh,
+void BKE_pbvh_build_mesh(PBVH *pbvh,
const Mesh *mesh,
const MPoly *mpoly,
const MLoop *mloop,
@@ -551,21 +581,21 @@ void BKE_pbvh_build_mesh(PBVH *bvh,
BBC *prim_bbc = NULL;
BB cb;
- bvh->mesh = mesh;
- bvh->type = PBVH_FACES;
- bvh->mpoly = mpoly;
- bvh->mloop = mloop;
- bvh->looptri = looptri;
- bvh->verts = verts;
- bvh->vert_bitmap = BLI_BITMAP_NEW(totvert, "bvh->vert_bitmap");
- bvh->totvert = totvert;
- bvh->leaf_limit = LEAF_LIMIT;
- bvh->vdata = vdata;
- bvh->ldata = ldata;
- bvh->pdata = pdata;
-
- bvh->face_sets_color_seed = mesh->face_sets_color_seed;
- bvh->face_sets_color_default = mesh->face_sets_color_default;
+ pbvh->mesh = mesh;
+ pbvh->type = PBVH_FACES;
+ pbvh->mpoly = mpoly;
+ pbvh->mloop = mloop;
+ pbvh->looptri = looptri;
+ pbvh->verts = verts;
+ pbvh->vert_bitmap = BLI_BITMAP_NEW(totvert, "bvh->vert_bitmap");
+ pbvh->totvert = totvert;
+ pbvh->leaf_limit = LEAF_LIMIT;
+ pbvh->vdata = vdata;
+ pbvh->ldata = ldata;
+ pbvh->pdata = pdata;
+
+ pbvh->face_sets_color_seed = mesh->face_sets_color_seed;
+ pbvh->face_sets_color_default = mesh->face_sets_color_default;
BB_reset(&cb);
@@ -580,7 +610,7 @@ void BKE_pbvh_build_mesh(PBVH *bvh,
BB_reset((BB *)bbc);
for (int j = 0; j < sides; j++) {
- BB_expand((BB *)bbc, verts[bvh->mloop[lt->tri[j]].v].co);
+ BB_expand((BB *)bbc, verts[pbvh->mloop[lt->tri[j]].v].co);
}
BBC_update_centroid(bbc);
@@ -589,15 +619,15 @@ void BKE_pbvh_build_mesh(PBVH *bvh,
}
if (looptri_num) {
- pbvh_build(bvh, &cb, prim_bbc, looptri_num);
+ pbvh_build(pbvh, &cb, prim_bbc, looptri_num);
}
MEM_freeN(prim_bbc);
- MEM_freeN(bvh->vert_bitmap);
+ MEM_freeN(pbvh->vert_bitmap);
}
/* Do a full rebuild with on Grids data structure */
-void BKE_pbvh_build_grids(PBVH *bvh,
+void BKE_pbvh_build_grids(PBVH *pbvh,
CCGElem **grids,
int totgrid,
CCGKey *key,
@@ -607,14 +637,14 @@ void BKE_pbvh_build_grids(PBVH *bvh,
{
const int gridsize = key->grid_size;
- bvh->type = PBVH_GRIDS;
- bvh->grids = grids;
- bvh->gridfaces = gridfaces;
- bvh->grid_flag_mats = flagmats;
- bvh->totgrid = totgrid;
- bvh->gridkey = *key;
- bvh->grid_hidden = grid_hidden;
- bvh->leaf_limit = max_ii(LEAF_LIMIT / ((gridsize - 1) * (gridsize - 1)), 1);
+ pbvh->type = PBVH_GRIDS;
+ pbvh->grids = grids;
+ pbvh->gridfaces = gridfaces;
+ pbvh->grid_flag_mats = flagmats;
+ pbvh->totgrid = totgrid;
+ pbvh->gridkey = *key;
+ pbvh->grid_hidden = grid_hidden;
+ pbvh->leaf_limit = max_ii(LEAF_LIMIT / ((gridsize - 1) * (gridsize - 1)), 1);
BB cb;
BB_reset(&cb);
@@ -638,7 +668,7 @@ void BKE_pbvh_build_grids(PBVH *bvh,
}
if (totgrid) {
- pbvh_build(bvh, &cb, prim_bbc, totgrid);
+ pbvh_build(pbvh, &cb, prim_bbc, totgrid);
}
MEM_freeN(prim_bbc);
@@ -646,15 +676,15 @@ void BKE_pbvh_build_grids(PBVH *bvh,
PBVH *BKE_pbvh_new(void)
{
- PBVH *bvh = MEM_callocN(sizeof(PBVH), "pbvh");
-
- return bvh;
+ PBVH *pbvh = MEM_callocN(sizeof(PBVH), "pbvh");
+ pbvh->respect_hide = true;
+ return pbvh;
}
-void BKE_pbvh_free(PBVH *bvh)
+void BKE_pbvh_free(PBVH *pbvh)
{
- for (int i = 0; i < bvh->totnode; i++) {
- PBVHNode *node = &bvh->nodes[i];
+ for (int i = 0; i < pbvh->totnode; i++) {
+ PBVHNode *node = &pbvh->nodes[i];
if (node->flag & PBVH_Leaf) {
if (node->draw_buffers) {
@@ -666,8 +696,6 @@ void BKE_pbvh_free(PBVH *bvh)
if (node->face_vert_indices) {
MEM_freeN((void *)node->face_vert_indices);
}
- BKE_pbvh_node_layer_disp_free(node);
-
if (node->bm_faces) {
BLI_gset_free(node->bm_faces, NULL);
}
@@ -680,49 +708,42 @@ void BKE_pbvh_free(PBVH *bvh)
}
}
- if (bvh->deformed) {
- if (bvh->verts) {
+ if (pbvh->deformed) {
+ if (pbvh->verts) {
/* if pbvh was deformed, new memory was allocated for verts/faces -- free it */
- MEM_freeN((void *)bvh->verts);
+ MEM_freeN((void *)pbvh->verts);
}
}
- if (bvh->looptri) {
- MEM_freeN((void *)bvh->looptri);
+ if (pbvh->looptri) {
+ MEM_freeN((void *)pbvh->looptri);
}
- if (bvh->nodes) {
- MEM_freeN(bvh->nodes);
+ if (pbvh->nodes) {
+ MEM_freeN(pbvh->nodes);
}
- if (bvh->prim_indices) {
- MEM_freeN(bvh->prim_indices);
+ if (pbvh->prim_indices) {
+ MEM_freeN(pbvh->prim_indices);
}
- MEM_freeN(bvh);
-}
-
-void BKE_pbvh_free_layer_disp(PBVH *bvh)
-{
- for (int i = 0; i < bvh->totnode; i++) {
- BKE_pbvh_node_layer_disp_free(&bvh->nodes[i]);
- }
+ MEM_freeN(pbvh);
}
static void pbvh_iter_begin(PBVHIter *iter,
- PBVH *bvh,
+ PBVH *pbvh,
BKE_pbvh_SearchCallback scb,
void *search_data)
{
- iter->bvh = bvh;
+ iter->pbvh = pbvh;
iter->scb = scb;
iter->search_data = search_data;
iter->stack = iter->stackfixed;
iter->stackspace = STACK_FIXED_DEPTH;
- iter->stack[0].node = bvh->nodes;
+ iter->stack[0].node = pbvh->nodes;
iter->stack[0].revisiting = false;
iter->stacksize = 1;
}
@@ -788,8 +809,8 @@ static PBVHNode *pbvh_iter_next(PBVHIter *iter)
pbvh_stack_push(iter, node, true);
/* push two child nodes on the stack */
- pbvh_stack_push(iter, iter->bvh->nodes + node->children_offset + 1, false);
- pbvh_stack_push(iter, iter->bvh->nodes + node->children_offset, false);
+ pbvh_stack_push(iter, iter->pbvh->nodes + node->children_offset + 1, false);
+ pbvh_stack_push(iter, iter->pbvh->nodes + node->children_offset, false);
}
}
@@ -818,8 +839,8 @@ static PBVHNode *pbvh_iter_next_occluded(PBVHIter *iter)
return node;
}
else {
- pbvh_stack_push(iter, iter->bvh->nodes + node->children_offset + 1, false);
- pbvh_stack_push(iter, iter->bvh->nodes + node->children_offset, false);
+ pbvh_stack_push(iter, iter->pbvh->nodes + node->children_offset + 1, false);
+ pbvh_stack_push(iter, iter->pbvh->nodes + node->children_offset, false);
}
}
@@ -827,13 +848,13 @@ static PBVHNode *pbvh_iter_next_occluded(PBVHIter *iter)
}
void BKE_pbvh_search_gather(
- PBVH *bvh, BKE_pbvh_SearchCallback scb, void *search_data, PBVHNode ***r_array, int *r_tot)
+ PBVH *pbvh, BKE_pbvh_SearchCallback scb, void *search_data, PBVHNode ***r_array, int *r_tot)
{
PBVHIter iter;
PBVHNode **array = NULL, *node;
int tot = 0, space = 0;
- pbvh_iter_begin(&iter, bvh, scb, search_data);
+ pbvh_iter_begin(&iter, pbvh, scb, search_data);
while ((node = pbvh_iter_next(&iter))) {
if (node->flag & PBVH_Leaf) {
@@ -859,7 +880,7 @@ void BKE_pbvh_search_gather(
*r_tot = tot;
}
-void BKE_pbvh_search_callback(PBVH *bvh,
+void BKE_pbvh_search_callback(PBVH *pbvh,
BKE_pbvh_SearchCallback scb,
void *search_data,
BKE_pbvh_HitCallback hcb,
@@ -868,7 +889,7 @@ void BKE_pbvh_search_callback(PBVH *bvh,
PBVHIter iter;
PBVHNode *node;
- pbvh_iter_begin(&iter, bvh, scb, search_data);
+ pbvh_iter_begin(&iter, pbvh, scb, search_data);
while ((node = pbvh_iter_next(&iter))) {
if (node->flag & PBVH_Leaf) {
@@ -942,7 +963,7 @@ float BKE_pbvh_node_get_tmin(PBVHNode *node)
return node->tmin;
}
-static void BKE_pbvh_search_callback_occluded(PBVH *bvh,
+static void BKE_pbvh_search_callback_occluded(PBVH *pbvh,
BKE_pbvh_SearchCallback scb,
void *search_data,
BKE_pbvh_HitOccludedCallback hcb,
@@ -952,7 +973,7 @@ static void BKE_pbvh_search_callback_occluded(PBVH *bvh,
PBVHNode *node;
node_tree *tree = NULL;
- pbvh_iter_begin(&iter, bvh, scb, search_data);
+ pbvh_iter_begin(&iter, pbvh, scb, search_data);
while ((node = pbvh_iter_next_occluded(&iter))) {
if (node->flag & PBVH_Leaf) {
@@ -993,13 +1014,12 @@ static bool update_search_cb(PBVHNode *node, void *data_v)
}
typedef struct PBVHUpdateData {
- PBVH *bvh;
+ PBVH *pbvh;
PBVHNode **nodes;
int totnode;
float (*vnors)[3];
int flag;
- bool show_vcol;
bool show_sculpt_face_sets;
} PBVHUpdateData;
@@ -1009,7 +1029,7 @@ static void pbvh_update_normals_accum_task_cb(void *__restrict userdata,
{
PBVHUpdateData *data = userdata;
- PBVH *bvh = data->bvh;
+ PBVH *pbvh = data->pbvh;
PBVHNode *node = data->nodes[n];
float(*vnors)[3] = data->vnors;
@@ -1021,25 +1041,25 @@ static void pbvh_update_normals_accum_task_cb(void *__restrict userdata,
const int totface = node->totprim;
for (int i = 0; i < totface; i++) {
- const MLoopTri *lt = &bvh->looptri[faces[i]];
+ const MLoopTri *lt = &pbvh->looptri[faces[i]];
const unsigned int vtri[3] = {
- bvh->mloop[lt->tri[0]].v,
- bvh->mloop[lt->tri[1]].v,
- bvh->mloop[lt->tri[2]].v,
+ pbvh->mloop[lt->tri[0]].v,
+ pbvh->mloop[lt->tri[1]].v,
+ pbvh->mloop[lt->tri[2]].v,
};
const int sides = 3;
/* Face normal and mask */
if (lt->poly != mpoly_prev) {
- const MPoly *mp = &bvh->mpoly[lt->poly];
- BKE_mesh_calc_poly_normal(mp, &bvh->mloop[mp->loopstart], bvh->verts, fn);
+ const MPoly *mp = &pbvh->mpoly[lt->poly];
+ BKE_mesh_calc_poly_normal(mp, &pbvh->mloop[mp->loopstart], pbvh->verts, fn);
mpoly_prev = lt->poly;
}
for (int j = sides; j--;) {
const int v = vtri[j];
- if (bvh->verts[v].flag & ME_VERT_PBVH_UPDATE) {
+ if (pbvh->verts[v].flag & ME_VERT_PBVH_UPDATE) {
/* Note: This avoids `lock, add_v3_v3, unlock`
* and is five to ten times quicker than a spin-lock.
* Not exact equivalent though, since atomicity is only ensured for one component
@@ -1058,7 +1078,7 @@ static void pbvh_update_normals_store_task_cb(void *__restrict userdata,
const TaskParallelTLS *__restrict UNUSED(tls))
{
PBVHUpdateData *data = userdata;
- PBVH *bvh = data->bvh;
+ PBVH *pbvh = data->pbvh;
PBVHNode *node = data->nodes[n];
float(*vnors)[3] = data->vnors;
@@ -1068,7 +1088,7 @@ static void pbvh_update_normals_store_task_cb(void *__restrict userdata,
for (int i = 0; i < totvert; i++) {
const int v = verts[i];
- MVert *mvert = &bvh->verts[v];
+ MVert *mvert = &pbvh->verts[v];
/* No atomics necessary because we are iterating over uniq_verts only,
* so we know only this thread will handle this vertex. */
@@ -1083,11 +1103,11 @@ static void pbvh_update_normals_store_task_cb(void *__restrict userdata,
}
}
-static void pbvh_faces_update_normals(PBVH *bvh, PBVHNode **nodes, int totnode)
+static void pbvh_faces_update_normals(PBVH *pbvh, PBVHNode **nodes, int totnode)
{
/* could be per node to save some memory, but also means
* we have to store for each vertex which node it is in */
- float(*vnors)[3] = MEM_callocN(sizeof(*vnors) * bvh->totvert, __func__);
+ float(*vnors)[3] = MEM_callocN(sizeof(*vnors) * pbvh->totvert, __func__);
/* subtle assumptions:
* - We know that for all edited vertices, the nodes with faces
@@ -1100,16 +1120,16 @@ static void pbvh_faces_update_normals(PBVH *bvh, PBVHNode **nodes, int totnode)
*/
PBVHUpdateData data = {
- .bvh = bvh,
+ .pbvh = pbvh,
.nodes = nodes,
.vnors = vnors,
};
- PBVHParallelSettings settings;
+ TaskParallelSettings settings;
BKE_pbvh_parallel_range_settings(&settings, true, totnode);
- BKE_pbvh_parallel_range(0, totnode, &data, pbvh_update_normals_accum_task_cb, &settings);
- BKE_pbvh_parallel_range(0, totnode, &data, pbvh_update_normals_store_task_cb, &settings);
+ BLI_task_parallel_range(0, totnode, &data, pbvh_update_normals_accum_task_cb, &settings);
+ BLI_task_parallel_range(0, totnode, &data, pbvh_update_normals_store_task_cb, &settings);
MEM_freeN(vnors);
}
@@ -1120,7 +1140,7 @@ static void pbvh_update_mask_redraw_task_cb(void *__restrict userdata,
{
PBVHUpdateData *data = userdata;
- PBVH *bvh = data->bvh;
+ PBVH *pbvh = data->pbvh;
PBVHNode *node = data->nodes[n];
if (node->flag & PBVH_UpdateMask) {
@@ -1129,7 +1149,7 @@ static void pbvh_update_mask_redraw_task_cb(void *__restrict userdata,
if (node->flag & PBVH_Leaf) {
PBVHVertexIter vd;
- BKE_pbvh_vertex_iter_begin(bvh, node, vd, PBVH_ITER_ALL)
+ BKE_pbvh_vertex_iter_begin(pbvh, node, vd, PBVH_ITER_ALL)
{
if (vd.mask && *vd.mask < 1.0f) {
has_unmasked = true;
@@ -1151,17 +1171,17 @@ static void pbvh_update_mask_redraw_task_cb(void *__restrict userdata,
}
}
-static void pbvh_update_mask_redraw(PBVH *bvh, PBVHNode **nodes, int totnode, int flag)
+static void pbvh_update_mask_redraw(PBVH *pbvh, PBVHNode **nodes, int totnode, int flag)
{
PBVHUpdateData data = {
- .bvh = bvh,
+ .pbvh = pbvh,
.nodes = nodes,
.flag = flag,
};
- PBVHParallelSettings settings;
+ TaskParallelSettings settings;
BKE_pbvh_parallel_range_settings(&settings, true, totnode);
- BKE_pbvh_parallel_range(0, totnode, &data, pbvh_update_mask_redraw_task_cb, &settings);
+ BLI_task_parallel_range(0, totnode, &data, pbvh_update_mask_redraw_task_cb, &settings);
}
static void pbvh_update_visibility_redraw_task_cb(void *__restrict userdata,
@@ -1170,14 +1190,14 @@ static void pbvh_update_visibility_redraw_task_cb(void *__restrict userdata,
{
PBVHUpdateData *data = userdata;
- PBVH *bvh = data->bvh;
+ PBVH *pbvh = data->pbvh;
PBVHNode *node = data->nodes[n];
if (node->flag & PBVH_UpdateVisibility) {
node->flag &= ~PBVH_UpdateVisibility;
BKE_pbvh_node_fully_hidden_set(node, true);
if (node->flag & PBVH_Leaf) {
PBVHVertexIter vd;
- BKE_pbvh_vertex_iter_begin(bvh, node, vd, PBVH_ITER_ALL)
+ BKE_pbvh_vertex_iter_begin(pbvh, node, vd, PBVH_ITER_ALL)
{
if (vd.visible) {
BKE_pbvh_node_fully_hidden_set(node, false);
@@ -1189,17 +1209,17 @@ static void pbvh_update_visibility_redraw_task_cb(void *__restrict userdata,
}
}
-static void pbvh_update_visibility_redraw(PBVH *bvh, PBVHNode **nodes, int totnode, int flag)
+static void pbvh_update_visibility_redraw(PBVH *pbvh, PBVHNode **nodes, int totnode, int flag)
{
PBVHUpdateData data = {
- .bvh = bvh,
+ .pbvh = pbvh,
.nodes = nodes,
.flag = flag,
};
- PBVHParallelSettings settings;
+ TaskParallelSettings settings;
BKE_pbvh_parallel_range_settings(&settings, true, totnode);
- BKE_pbvh_parallel_range(0, totnode, &data, pbvh_update_visibility_redraw_task_cb, &settings);
+ BLI_task_parallel_range(0, totnode, &data, pbvh_update_visibility_redraw_task_cb, &settings);
}
static void pbvh_update_BB_redraw_task_cb(void *__restrict userdata,
@@ -1207,14 +1227,14 @@ static void pbvh_update_BB_redraw_task_cb(void *__restrict userdata,
const TaskParallelTLS *__restrict UNUSED(tls))
{
PBVHUpdateData *data = userdata;
- PBVH *bvh = data->bvh;
+ PBVH *pbvh = data->pbvh;
PBVHNode *node = data->nodes[n];
const int flag = data->flag;
if ((flag & PBVH_UpdateBB) && (node->flag & PBVH_UpdateBB)) {
/* don't clear flag yet, leave it for flushing later */
/* Note that bvh usage is read-only here, so no need to thread-protect it. */
- update_node_vb(bvh, node);
+ update_node_vb(pbvh, node);
}
if ((flag & PBVH_UpdateOriginalBB) && (node->flag & PBVH_UpdateOriginalBB)) {
@@ -1226,26 +1246,24 @@ static void pbvh_update_BB_redraw_task_cb(void *__restrict userdata,
}
}
-void pbvh_update_BB_redraw(PBVH *bvh, PBVHNode **nodes, int totnode, int flag)
+void pbvh_update_BB_redraw(PBVH *pbvh, PBVHNode **nodes, int totnode, int flag)
{
/* update BB, redraw flag */
PBVHUpdateData data = {
- .bvh = bvh,
+ .pbvh = pbvh,
.nodes = nodes,
.flag = flag,
};
- PBVHParallelSettings settings;
+ TaskParallelSettings settings;
BKE_pbvh_parallel_range_settings(&settings, true, totnode);
- BKE_pbvh_parallel_range(0, totnode, &data, pbvh_update_BB_redraw_task_cb, &settings);
+ BLI_task_parallel_range(0, totnode, &data, pbvh_update_BB_redraw_task_cb, &settings);
}
-static int pbvh_get_buffers_update_flags(PBVH *bvh, bool show_vcol)
+static int pbvh_get_buffers_update_flags(PBVH *UNUSED(pbvh))
{
- int update_flags = 0;
- update_flags |= bvh->show_mask ? GPU_PBVH_BUFFERS_SHOW_MASK : 0;
- update_flags |= show_vcol ? GPU_PBVH_BUFFERS_SHOW_VCOL : 0;
- update_flags |= bvh->show_face_sets ? GPU_PBVH_BUFFERS_SHOW_SCULPT_FACE_SETS : 0;
+ int update_flags = GPU_PBVH_BUFFERS_SHOW_VCOL | GPU_PBVH_BUFFERS_SHOW_MASK |
+ GPU_PBVH_BUFFERS_SHOW_SCULPT_FACE_SETS;
return update_flags;
}
@@ -1257,61 +1275,61 @@ static void pbvh_update_draw_buffer_cb(void *__restrict userdata,
* do any OpenGL calls. Flags are not cleared immediately, that happens
* after GPU_pbvh_buffer_flush() which does the final OpenGL calls. */
PBVHUpdateData *data = userdata;
- PBVH *bvh = data->bvh;
+ PBVH *pbvh = data->pbvh;
PBVHNode *node = data->nodes[n];
if (node->flag & PBVH_RebuildDrawBuffers) {
- switch (bvh->type) {
+ switch (pbvh->type) {
case PBVH_GRIDS:
- node->draw_buffers = GPU_pbvh_grid_buffers_build(node->totprim, bvh->grid_hidden);
+ node->draw_buffers = GPU_pbvh_grid_buffers_build(node->totprim, pbvh->grid_hidden);
break;
case PBVH_FACES:
node->draw_buffers = GPU_pbvh_mesh_buffers_build(
- node->face_vert_indices,
- bvh->mpoly,
- bvh->mloop,
- bvh->looptri,
- bvh->verts,
+ pbvh->mpoly,
+ pbvh->mloop,
+ pbvh->looptri,
+ pbvh->verts,
node->prim_indices,
- CustomData_get_layer(bvh->pdata, CD_SCULPT_FACE_SETS),
+ CustomData_get_layer(pbvh->pdata, CD_SCULPT_FACE_SETS),
node->totprim,
- bvh->mesh);
+ pbvh->mesh);
break;
case PBVH_BMESH:
- node->draw_buffers = GPU_pbvh_bmesh_buffers_build(bvh->flags &
+ node->draw_buffers = GPU_pbvh_bmesh_buffers_build(pbvh->flags &
PBVH_DYNTOPO_SMOOTH_SHADING);
break;
}
}
if (node->flag & PBVH_UpdateDrawBuffers) {
- const int update_flags = pbvh_get_buffers_update_flags(bvh, data->show_vcol);
- switch (bvh->type) {
+ const int update_flags = pbvh_get_buffers_update_flags(pbvh);
+ switch (pbvh->type) {
case PBVH_GRIDS:
GPU_pbvh_grid_buffers_update(node->draw_buffers,
- bvh->grids,
- bvh->grid_flag_mats,
+ pbvh->subdiv_ccg,
+ pbvh->grids,
+ pbvh->grid_flag_mats,
node->prim_indices,
node->totprim,
- &bvh->gridkey,
+ pbvh->face_sets,
+ pbvh->face_sets_color_seed,
+ pbvh->face_sets_color_default,
+ &pbvh->gridkey,
update_flags);
break;
case PBVH_FACES:
GPU_pbvh_mesh_buffers_update(node->draw_buffers,
- bvh->verts,
- node->vert_indices,
- node->uniq_verts + node->face_verts,
- CustomData_get_layer(bvh->vdata, CD_PAINT_MASK),
- CustomData_get_layer(bvh->ldata, CD_MLOOPCOL),
- CustomData_get_layer(bvh->pdata, CD_SCULPT_FACE_SETS),
- bvh->face_sets_color_seed,
- bvh->face_sets_color_default,
- node->face_vert_indices,
+ pbvh->verts,
+ CustomData_get_layer(pbvh->vdata, CD_PAINT_MASK),
+ CustomData_get_layer(pbvh->ldata, CD_MLOOPCOL),
+ CustomData_get_layer(pbvh->pdata, CD_SCULPT_FACE_SETS),
+ pbvh->face_sets_color_seed,
+ pbvh->face_sets_color_default,
update_flags);
break;
case PBVH_BMESH:
GPU_pbvh_bmesh_buffers_update(node->draw_buffers,
- bvh->bm,
+ pbvh->bm,
node->bm_faces,
node->bm_unique_verts,
node->bm_other_verts,
@@ -1321,10 +1339,9 @@ static void pbvh_update_draw_buffer_cb(void *__restrict userdata,
}
}
-static void pbvh_update_draw_buffers(
- PBVH *bvh, PBVHNode **nodes, int totnode, bool show_vcol, int update_flag)
+static void pbvh_update_draw_buffers(PBVH *pbvh, PBVHNode **nodes, int totnode, int update_flag)
{
- if ((update_flag & PBVH_RebuildDrawBuffers) || ELEM(bvh->type, PBVH_GRIDS, PBVH_BMESH)) {
+ if ((update_flag & PBVH_RebuildDrawBuffers) || ELEM(pbvh->type, PBVH_GRIDS, PBVH_BMESH)) {
/* Free buffers uses OpenGL, so not in parallel. */
for (int n = 0; n < totnode; n++) {
PBVHNode *node = nodes[n];
@@ -1333,11 +1350,11 @@ static void pbvh_update_draw_buffers(
node->draw_buffers = NULL;
}
else if ((node->flag & PBVH_UpdateDrawBuffers) && node->draw_buffers) {
- if (bvh->type == PBVH_GRIDS) {
+ if (pbvh->type == PBVH_GRIDS) {
GPU_pbvh_grid_buffers_update_free(
- node->draw_buffers, bvh->grid_flag_mats, node->prim_indices);
+ node->draw_buffers, pbvh->grid_flag_mats, node->prim_indices);
}
- else if (bvh->type == PBVH_BMESH) {
+ else if (pbvh->type == PBVH_BMESH) {
GPU_pbvh_bmesh_buffers_update_free(node->draw_buffers);
}
}
@@ -1346,17 +1363,16 @@ static void pbvh_update_draw_buffers(
/* Parallel creation and update of draw buffers. */
PBVHUpdateData data = {
- .bvh = bvh,
+ .pbvh = pbvh,
.nodes = nodes,
- .show_vcol = show_vcol,
};
- PBVHParallelSettings settings;
+ TaskParallelSettings settings;
BKE_pbvh_parallel_range_settings(&settings, true, totnode);
- BKE_pbvh_parallel_range(0, totnode, &data, pbvh_update_draw_buffer_cb, &settings);
+ BLI_task_parallel_range(0, totnode, &data, pbvh_update_draw_buffer_cb, &settings);
}
-static int pbvh_flush_bb(PBVH *bvh, PBVHNode *node, int flag)
+static int pbvh_flush_bb(PBVH *pbvh, PBVHNode *node, int flag)
{
int update = 0;
@@ -1375,11 +1391,11 @@ static int pbvh_flush_bb(PBVH *bvh, PBVHNode *node, int flag)
return update;
}
else {
- update |= pbvh_flush_bb(bvh, bvh->nodes + node->children_offset, flag);
- update |= pbvh_flush_bb(bvh, bvh->nodes + node->children_offset + 1, flag);
+ update |= pbvh_flush_bb(pbvh, pbvh->nodes + node->children_offset, flag);
+ update |= pbvh_flush_bb(pbvh, pbvh->nodes + node->children_offset + 1, flag);
if (update & PBVH_UpdateBB) {
- update_node_vb(bvh, node);
+ update_node_vb(pbvh, node);
}
if (update & PBVH_UpdateOriginalBB) {
node->orig_vb = node->vb;
@@ -1389,45 +1405,45 @@ static int pbvh_flush_bb(PBVH *bvh, PBVHNode *node, int flag)
return update;
}
-void BKE_pbvh_update_bounds(PBVH *bvh, int flag)
+void BKE_pbvh_update_bounds(PBVH *pbvh, int flag)
{
- if (!bvh->nodes) {
+ if (!pbvh->nodes) {
return;
}
PBVHNode **nodes;
int totnode;
- BKE_pbvh_search_gather(bvh, update_search_cb, POINTER_FROM_INT(flag), &nodes, &totnode);
+ BKE_pbvh_search_gather(pbvh, update_search_cb, POINTER_FROM_INT(flag), &nodes, &totnode);
if (flag & (PBVH_UpdateBB | PBVH_UpdateOriginalBB | PBVH_UpdateRedraw)) {
- pbvh_update_BB_redraw(bvh, nodes, totnode, flag);
+ pbvh_update_BB_redraw(pbvh, nodes, totnode, flag);
}
if (flag & (PBVH_UpdateBB | PBVH_UpdateOriginalBB)) {
- pbvh_flush_bb(bvh, bvh->nodes, flag);
+ pbvh_flush_bb(pbvh, pbvh->nodes, flag);
}
MEM_SAFE_FREE(nodes);
}
-void BKE_pbvh_update_vertex_data(PBVH *bvh, int flag)
+void BKE_pbvh_update_vertex_data(PBVH *pbvh, int flag)
{
- if (!bvh->nodes) {
+ if (!pbvh->nodes) {
return;
}
PBVHNode **nodes;
int totnode;
- BKE_pbvh_search_gather(bvh, update_search_cb, POINTER_FROM_INT(flag), &nodes, &totnode);
+ BKE_pbvh_search_gather(pbvh, update_search_cb, POINTER_FROM_INT(flag), &nodes, &totnode);
if (flag & (PBVH_UpdateMask)) {
- pbvh_update_mask_redraw(bvh, nodes, totnode, flag);
+ pbvh_update_mask_redraw(pbvh, nodes, totnode, flag);
}
if (flag & (PBVH_UpdateVisibility)) {
- pbvh_update_visibility_redraw(bvh, nodes, totnode, flag);
+ pbvh_update_visibility_redraw(pbvh, nodes, totnode, flag);
}
if (nodes) {
@@ -1435,13 +1451,13 @@ void BKE_pbvh_update_vertex_data(PBVH *bvh, int flag)
}
}
-static void pbvh_faces_node_visibility_update(PBVH *bvh, PBVHNode *node)
+static void pbvh_faces_node_visibility_update(PBVH *pbvh, PBVHNode *node)
{
MVert *mvert;
const int *vert_indices;
int totvert, i;
- BKE_pbvh_node_num_verts(bvh, node, NULL, &totvert);
- BKE_pbvh_node_get_verts(bvh, node, &vert_indices, &mvert);
+ BKE_pbvh_node_num_verts(pbvh, node, NULL, &totvert);
+ BKE_pbvh_node_get_verts(pbvh, node, &vert_indices, &mvert);
for (i = 0; i < totvert; i++) {
MVert *v = &mvert[vert_indices[i]];
@@ -1454,15 +1470,15 @@ static void pbvh_faces_node_visibility_update(PBVH *bvh, PBVHNode *node)
BKE_pbvh_node_fully_hidden_set(node, true);
}
-static void pbvh_grids_node_visibility_update(PBVH *bvh, PBVHNode *node)
+static void pbvh_grids_node_visibility_update(PBVH *pbvh, PBVHNode *node)
{
CCGElem **grids;
BLI_bitmap **grid_hidden;
int *grid_indices, totgrid, i;
- BKE_pbvh_node_get_grids(bvh, node, &grid_indices, &totgrid, NULL, NULL, &grids);
- grid_hidden = BKE_pbvh_grid_hidden(bvh);
- CCGKey key = *BKE_pbvh_get_grid_key(bvh);
+ BKE_pbvh_node_get_grids(pbvh, node, &grid_indices, &totgrid, NULL, NULL, &grids);
+ grid_hidden = BKE_pbvh_grid_hidden(pbvh);
+ CCGKey key = *BKE_pbvh_get_grid_key(pbvh);
for (i = 0; i < totgrid; i++) {
int g = grid_indices[i], x, y;
@@ -1519,15 +1535,15 @@ static void pbvh_update_visibility_task_cb(void *__restrict userdata,
{
PBVHUpdateData *data = userdata;
- PBVH *bvh = data->bvh;
+ PBVH *pbvh = data->pbvh;
PBVHNode *node = data->nodes[n];
if (node->flag & PBVH_UpdateMask) {
- switch (BKE_pbvh_type(bvh)) {
+ switch (BKE_pbvh_type(pbvh)) {
case PBVH_FACES:
- pbvh_faces_node_visibility_update(bvh, node);
+ pbvh_faces_node_visibility_update(pbvh, node);
break;
case PBVH_GRIDS:
- pbvh_grids_node_visibility_update(bvh, node);
+ pbvh_grids_node_visibility_update(pbvh, node);
break;
case PBVH_BMESH:
pbvh_bmesh_node_visibility_update(node);
@@ -1537,21 +1553,21 @@ static void pbvh_update_visibility_task_cb(void *__restrict userdata,
}
}
-static void pbvh_update_visibility(PBVH *bvh, PBVHNode **nodes, int totnode)
+static void pbvh_update_visibility(PBVH *pbvh, PBVHNode **nodes, int totnode)
{
PBVHUpdateData data = {
- .bvh = bvh,
+ .pbvh = pbvh,
.nodes = nodes,
};
- PBVHParallelSettings settings;
+ TaskParallelSettings settings;
BKE_pbvh_parallel_range_settings(&settings, true, totnode);
- BKE_pbvh_parallel_range(0, totnode, &data, pbvh_update_visibility_task_cb, &settings);
+ BLI_task_parallel_range(0, totnode, &data, pbvh_update_visibility_task_cb, &settings);
}
-void BKE_pbvh_update_visibility(PBVH *bvh)
+void BKE_pbvh_update_visibility(PBVH *pbvh)
{
- if (!bvh->nodes) {
+ if (!pbvh->nodes) {
return;
}
@@ -1559,15 +1575,15 @@ void BKE_pbvh_update_visibility(PBVH *bvh)
int totnode;
BKE_pbvh_search_gather(
- bvh, update_search_cb, POINTER_FROM_INT(PBVH_UpdateVisibility), &nodes, &totnode);
- pbvh_update_visibility(bvh, nodes, totnode);
+ pbvh, update_search_cb, POINTER_FROM_INT(PBVH_UpdateVisibility), &nodes, &totnode);
+ pbvh_update_visibility(pbvh, nodes, totnode);
if (nodes) {
MEM_freeN(nodes);
}
}
-void BKE_pbvh_redraw_BB(PBVH *bvh, float bb_min[3], float bb_max[3])
+void BKE_pbvh_redraw_BB(PBVH *pbvh, float bb_min[3], float bb_max[3])
{
PBVHIter iter;
PBVHNode *node;
@@ -1575,7 +1591,7 @@ void BKE_pbvh_redraw_BB(PBVH *bvh, float bb_min[3], float bb_max[3])
BB_reset(&bb);
- pbvh_iter_begin(&iter, bvh, NULL, NULL);
+ pbvh_iter_begin(&iter, pbvh, NULL, NULL);
while ((node = pbvh_iter_next(&iter))) {
if (node->flag & PBVH_UpdateRedraw) {
@@ -1589,18 +1605,18 @@ void BKE_pbvh_redraw_BB(PBVH *bvh, float bb_min[3], float bb_max[3])
copy_v3_v3(bb_max, bb.bmax);
}
-void BKE_pbvh_get_grid_updates(PBVH *bvh, bool clear, void ***r_gridfaces, int *r_totface)
+void BKE_pbvh_get_grid_updates(PBVH *pbvh, bool clear, void ***r_gridfaces, int *r_totface)
{
GSet *face_set = BLI_gset_ptr_new(__func__);
PBVHNode *node;
PBVHIter iter;
- pbvh_iter_begin(&iter, bvh, NULL, NULL);
+ pbvh_iter_begin(&iter, pbvh, NULL, NULL);
while ((node = pbvh_iter_next(&iter))) {
if (node->flag & PBVH_UpdateNormals) {
for (uint i = 0; i < node->totprim; i++) {
- void *face = bvh->gridfaces[node->prim_indices[i]];
+ void *face = pbvh->gridfaces[node->prim_indices[i]];
BLI_gset_add(face_set, face);
}
@@ -1636,25 +1652,25 @@ void BKE_pbvh_get_grid_updates(PBVH *bvh, bool clear, void ***r_gridfaces, int *
/***************************** PBVH Access ***********************************/
-PBVHType BKE_pbvh_type(const PBVH *bvh)
+PBVHType BKE_pbvh_type(const PBVH *pbvh)
{
- return bvh->type;
+ return pbvh->type;
}
-bool BKE_pbvh_has_faces(const PBVH *bvh)
+bool BKE_pbvh_has_faces(const PBVH *pbvh)
{
- if (bvh->type == PBVH_BMESH) {
- return (bvh->bm->totface != 0);
+ if (pbvh->type == PBVH_BMESH) {
+ return (pbvh->bm->totface != 0);
}
else {
- return (bvh->totprim != 0);
+ return (pbvh->totprim != 0);
}
}
-void BKE_pbvh_bounding_box(const PBVH *bvh, float min[3], float max[3])
+void BKE_pbvh_bounding_box(const PBVH *pbvh, float min[3], float max[3])
{
- if (bvh->totnode) {
- const BB *bb = &bvh->nodes[0].vb;
+ if (pbvh->totnode) {
+ const BB *bb = &pbvh->nodes[0].vb;
copy_v3_v3(min, bb->bmin);
copy_v3_v3(max, bb->bmax);
}
@@ -1664,34 +1680,40 @@ void BKE_pbvh_bounding_box(const PBVH *bvh, float min[3], float max[3])
}
}
-BLI_bitmap **BKE_pbvh_grid_hidden(const PBVH *bvh)
+BLI_bitmap **BKE_pbvh_grid_hidden(const PBVH *pbvh)
+{
+ BLI_assert(pbvh->type == PBVH_GRIDS);
+ return pbvh->grid_hidden;
+}
+
+const CCGKey *BKE_pbvh_get_grid_key(const PBVH *pbvh)
{
- BLI_assert(bvh->type == PBVH_GRIDS);
- return bvh->grid_hidden;
+ BLI_assert(pbvh->type == PBVH_GRIDS);
+ return &pbvh->gridkey;
}
-const CCGKey *BKE_pbvh_get_grid_key(const PBVH *bvh)
+struct CCGElem **BKE_pbvh_get_grids(const PBVH *pbvh)
{
- BLI_assert(bvh->type == PBVH_GRIDS);
- return &bvh->gridkey;
+ BLI_assert(pbvh->type == PBVH_GRIDS);
+ return pbvh->grids;
}
-struct CCGElem **BKE_pbvh_get_grids(const PBVH *bvh)
+BLI_bitmap **BKE_pbvh_get_grid_visibility(const PBVH *pbvh)
{
- BLI_assert(bvh->type == PBVH_GRIDS);
- return bvh->grids;
+ BLI_assert(pbvh->type == PBVH_GRIDS);
+ return pbvh->grid_hidden;
}
-int BKE_pbvh_get_grid_num_vertices(const PBVH *bvh)
+int BKE_pbvh_get_grid_num_vertices(const PBVH *pbvh)
{
- BLI_assert(bvh->type == PBVH_GRIDS);
- return bvh->totgrid * bvh->gridkey.grid_area;
+ BLI_assert(pbvh->type == PBVH_GRIDS);
+ return pbvh->totgrid * pbvh->gridkey.grid_area;
}
-BMesh *BKE_pbvh_get_bmesh(PBVH *bvh)
+BMesh *BKE_pbvh_get_bmesh(PBVH *pbvh)
{
- BLI_assert(bvh->type == PBVH_BMESH);
- return bvh->bm;
+ BLI_assert(pbvh->type == PBVH_BMESH);
+ return pbvh->bm;
}
/***************************** Node Access ***********************************/
@@ -1774,7 +1796,7 @@ bool BKE_pbvh_node_fully_unmasked_get(PBVHNode *node)
return (node->flag & PBVH_Leaf) && (node->flag & PBVH_FullyUnmasked);
}
-void BKE_pbvh_node_get_verts(PBVH *bvh,
+void BKE_pbvh_node_get_verts(PBVH *pbvh,
PBVHNode *node,
const int **r_vert_indices,
MVert **r_verts)
@@ -1784,17 +1806,17 @@ void BKE_pbvh_node_get_verts(PBVH *bvh,
}
if (r_verts) {
- *r_verts = bvh->verts;
+ *r_verts = pbvh->verts;
}
}
-void BKE_pbvh_node_num_verts(PBVH *bvh, PBVHNode *node, int *r_uniquevert, int *r_totvert)
+void BKE_pbvh_node_num_verts(PBVH *pbvh, PBVHNode *node, int *r_uniquevert, int *r_totvert)
{
int tot;
- switch (bvh->type) {
+ switch (pbvh->type) {
case PBVH_GRIDS:
- tot = node->totprim * bvh->gridkey.grid_area;
+ tot = node->totprim * pbvh->gridkey.grid_area;
if (r_totvert) {
*r_totvert = tot;
}
@@ -1822,7 +1844,7 @@ void BKE_pbvh_node_num_verts(PBVH *bvh, PBVHNode *node, int *r_uniquevert, int *
}
}
-void BKE_pbvh_node_get_grids(PBVH *bvh,
+void BKE_pbvh_node_get_grids(PBVH *pbvh,
PBVHNode *node,
int **r_grid_indices,
int *r_totgrid,
@@ -1830,7 +1852,7 @@ void BKE_pbvh_node_get_grids(PBVH *bvh,
int *r_gridsize,
CCGElem ***r_griddata)
{
- switch (bvh->type) {
+ switch (pbvh->type) {
case PBVH_GRIDS:
if (r_grid_indices) {
*r_grid_indices = node->prim_indices;
@@ -1839,13 +1861,13 @@ void BKE_pbvh_node_get_grids(PBVH *bvh,
*r_totgrid = node->totprim;
}
if (r_maxgrid) {
- *r_maxgrid = bvh->totgrid;
+ *r_maxgrid = pbvh->totgrid;
}
if (r_gridsize) {
- *r_gridsize = bvh->gridkey.grid_size;
+ *r_gridsize = pbvh->gridkey.grid_size;
}
if (r_griddata) {
- *r_griddata = bvh->grids;
+ *r_griddata = pbvh->grids;
}
break;
case PBVH_FACES:
@@ -1913,18 +1935,18 @@ void BKE_pbvh_node_get_bm_orco_data(PBVHNode *node,
/**
* \note doing a full search on all vertices here seems expensive,
- * however this is important to avoid having to recalculate boundbox & sync the buffers to the
+ * however this is important to avoid having to recalculate bound-box & sync the buffers to the
* GPU (which is far more expensive!) See: T47232.
*/
-bool BKE_pbvh_node_vert_update_check_any(PBVH *bvh, PBVHNode *node)
+bool BKE_pbvh_node_vert_update_check_any(PBVH *pbvh, PBVHNode *node)
{
- BLI_assert(bvh->type == PBVH_FACES);
+ BLI_assert(pbvh->type == PBVH_FACES);
const int *verts = node->vert_indices;
const int totvert = node->uniq_verts + node->face_verts;
for (int i = 0; i < totvert; i++) {
const int v = verts[i];
- const MVert *mvert = &bvh->verts[v];
+ const MVert *mvert = &pbvh->verts[v];
if (mvert->flag & ME_VERT_PBVH_UPDATE) {
return true;
@@ -1960,7 +1982,7 @@ static bool ray_aabb_intersect(PBVHNode *node, void *data_v)
return isect_ray_aabb_v3(&rcd->ray, bb_min, bb_max, &node->tmin);
}
-void BKE_pbvh_raycast(PBVH *bvh,
+void BKE_pbvh_raycast(PBVH *pbvh,
BKE_pbvh_HitOccludedCallback cb,
void *data,
const float ray_start[3],
@@ -1972,7 +1994,7 @@ void BKE_pbvh_raycast(PBVH *bvh,
isect_ray_aabb_v3_precalc(&rcd.ray, ray_start, ray_normal);
rcd.original = original;
- BKE_pbvh_search_callback_occluded(bvh, ray_aabb_intersect, &rcd, cb, data);
+ BKE_pbvh_search_callback_occluded(pbvh, ray_aabb_intersect, &rcd, cb, data);
}
bool ray_face_intersection_quad(const float ray_start[3],
@@ -2090,7 +2112,7 @@ bool ray_face_nearest_tri(const float ray_start[3],
}
}
-static bool pbvh_faces_node_raycast(PBVH *bvh,
+static bool pbvh_faces_node_raycast(PBVH *pbvh,
const PBVHNode *node,
float (*origco)[3],
const float ray_start[3],
@@ -2098,20 +2120,21 @@ static bool pbvh_faces_node_raycast(PBVH *bvh,
struct IsectRayPrecalc *isect_precalc,
float *depth,
int *r_active_vertex_index,
+ int *r_active_face_index,
float *r_face_normal)
{
- const MVert *vert = bvh->verts;
- const MLoop *mloop = bvh->mloop;
+ const MVert *vert = pbvh->verts;
+ const MLoop *mloop = pbvh->mloop;
const int *faces = node->prim_indices;
int totface = node->totprim;
bool hit = false;
float nearest_vertex_co[3] = {0.0f};
for (int i = 0; i < totface; i++) {
- const MLoopTri *lt = &bvh->looptri[faces[i]];
+ const MLoopTri *lt = &pbvh->looptri[faces[i]];
const int *face_verts = node->face_vert_indices[i];
- if (paint_is_face_hidden(lt, vert, mloop)) {
+ if (pbvh->respect_hide && paint_is_face_hidden(lt, vert, mloop)) {
continue;
}
@@ -2140,9 +2163,14 @@ static bool pbvh_faces_node_raycast(PBVH *bvh,
float location[3] = {0.0f};
madd_v3_v3v3fl(location, ray_start, ray_normal, *depth);
for (int j = 0; j < 3; j++) {
- if (len_squared_v3v3(location, co[j]) < len_squared_v3v3(location, nearest_vertex_co)) {
+ /* Always assign nearest_vertex_co in the first iteration to avoid comparison against
+ * uninitialized values. This stores the closest vertex in the current intersecting
+ * triangle. */
+ if (j == 0 ||
+ len_squared_v3v3(location, co[j]) < len_squared_v3v3(location, nearest_vertex_co)) {
copy_v3_v3(nearest_vertex_co, co[j]);
*r_active_vertex_index = mloop[lt->tri[j]].v;
+ *r_active_face_index = lt->poly;
}
}
}
@@ -2152,7 +2180,7 @@ static bool pbvh_faces_node_raycast(PBVH *bvh,
return hit;
}
-static bool pbvh_grids_node_raycast(PBVH *bvh,
+static bool pbvh_grids_node_raycast(PBVH *pbvh,
PBVHNode *node,
float (*origco)[3],
const float ray_start[3],
@@ -2160,24 +2188,25 @@ static bool pbvh_grids_node_raycast(PBVH *bvh,
struct IsectRayPrecalc *isect_precalc,
float *depth,
int *r_active_vertex_index,
+ int *r_active_grid_index,
float *r_face_normal)
{
const int totgrid = node->totprim;
- const int gridsize = bvh->gridkey.grid_size;
+ const int gridsize = pbvh->gridkey.grid_size;
bool hit = false;
float nearest_vertex_co[3] = {0.0};
- const CCGKey *gridkey = &bvh->gridkey;
+ const CCGKey *gridkey = &pbvh->gridkey;
for (int i = 0; i < totgrid; i++) {
const int grid_index = node->prim_indices[i];
- CCGElem *grid = bvh->grids[grid_index];
+ CCGElem *grid = pbvh->grids[grid_index];
BLI_bitmap *gh;
if (!grid) {
continue;
}
- gh = bvh->grid_hidden[grid_index];
+ gh = pbvh->grid_hidden[grid_index];
for (int y = 0; y < gridsize - 1; y++) {
for (int x = 0; x < gridsize - 1; x++) {
@@ -2213,15 +2242,26 @@ static bool pbvh_grids_node_raycast(PBVH *bvh,
if (r_active_vertex_index) {
float location[3] = {0.0};
madd_v3_v3v3fl(location, ray_start, ray_normal, *depth);
+
+ const int x_it[4] = {0, 1, 1, 0};
+ const int y_it[4] = {0, 0, 1, 1};
+
for (int j = 0; j < 4; j++) {
- if (len_squared_v3v3(location, co[j]) <
- len_squared_v3v3(location, nearest_vertex_co)) {
+ /* Always assign nearest_vertex_co in the first iteration to avoid comparison against
+ * uninitialized values. This stores the closest vertex in the current intersecting
+ * quad. */
+ if (j == 0 || len_squared_v3v3(location, co[j]) <
+ len_squared_v3v3(location, nearest_vertex_co)) {
copy_v3_v3(nearest_vertex_co, co[j]);
- *r_active_vertex_index = gridkey->grid_area * grid_index + y * gridkey->grid_size +
- x;
+
+ *r_active_vertex_index = gridkey->grid_area * grid_index +
+ (y + y_it[j]) * gridkey->grid_size + (x + x_it[j]);
}
}
}
+ if (r_active_grid_index) {
+ *r_active_grid_index = grid_index;
+ }
}
}
}
@@ -2234,7 +2274,7 @@ static bool pbvh_grids_node_raycast(PBVH *bvh,
return hit;
}
-bool BKE_pbvh_node_raycast(PBVH *bvh,
+bool BKE_pbvh_node_raycast(PBVH *pbvh,
PBVHNode *node,
float (*origco)[3],
bool use_origco,
@@ -2243,6 +2283,7 @@ bool BKE_pbvh_node_raycast(PBVH *bvh,
struct IsectRayPrecalc *isect_precalc,
float *depth,
int *active_vertex_index,
+ int *active_face_grid_index,
float *face_normal)
{
bool hit = false;
@@ -2251,9 +2292,9 @@ bool BKE_pbvh_node_raycast(PBVH *bvh,
return false;
}
- switch (bvh->type) {
+ switch (pbvh->type) {
case PBVH_FACES:
- hit |= pbvh_faces_node_raycast(bvh,
+ hit |= pbvh_faces_node_raycast(pbvh,
node,
origco,
ray_start,
@@ -2261,10 +2302,11 @@ bool BKE_pbvh_node_raycast(PBVH *bvh,
isect_precalc,
depth,
active_vertex_index,
+ active_face_grid_index,
face_normal);
break;
case PBVH_GRIDS:
- hit |= pbvh_grids_node_raycast(bvh,
+ hit |= pbvh_grids_node_raycast(pbvh,
node,
origco,
ray_start,
@@ -2272,10 +2314,11 @@ bool BKE_pbvh_node_raycast(PBVH *bvh,
isect_precalc,
depth,
active_vertex_index,
+ active_face_grid_index,
face_normal);
break;
case PBVH_BMESH:
- BM_mesh_elem_index_ensure(bvh->bm, BM_VERT);
+ BM_mesh_elem_index_ensure(pbvh->bm, BM_VERT);
hit = pbvh_bmesh_node_raycast(node,
ray_start,
ray_normal,
@@ -2291,9 +2334,9 @@ bool BKE_pbvh_node_raycast(PBVH *bvh,
}
void BKE_pbvh_raycast_project_ray_root(
- PBVH *bvh, bool original, float ray_start[3], float ray_end[3], float ray_normal[3])
+ PBVH *pbvh, bool original, float ray_start[3], float ray_end[3], float ray_normal[3])
{
- if (bvh->nodes) {
+ if (pbvh->nodes) {
float rootmin_start, rootmin_end;
float bb_min_root[3], bb_max_root[3], bb_center[3], bb_diff[3];
struct IsectRayAABB_Precalc ray;
@@ -2302,10 +2345,10 @@ void BKE_pbvh_raycast_project_ray_root(
float offset_vec[3] = {1e-3f, 1e-3f, 1e-3f};
if (original) {
- BKE_pbvh_node_get_original_BB(bvh->nodes, bb_min_root, bb_max_root);
+ BKE_pbvh_node_get_original_BB(pbvh->nodes, bb_min_root, bb_max_root);
}
else {
- BKE_pbvh_node_get_BB(bvh->nodes, bb_min_root, bb_max_root);
+ BKE_pbvh_node_get_BB(pbvh->nodes, bb_min_root, bb_max_root);
}
/* Slightly offset min and max in case we have a zero width node
@@ -2367,7 +2410,7 @@ static bool nearest_to_ray_aabb_dist_sq(PBVHNode *node, void *data_v)
return depth > 0.0f;
}
-void BKE_pbvh_find_nearest_to_ray(PBVH *bvh,
+void BKE_pbvh_find_nearest_to_ray(PBVH *pbvh,
BKE_pbvh_SearchNearestCallback cb,
void *data,
const float ray_start[3],
@@ -2379,10 +2422,10 @@ void BKE_pbvh_find_nearest_to_ray(PBVH *bvh,
dist_squared_ray_to_aabb_v3_precalc(&ncd.dist_ray_to_aabb_precalc, ray_start, ray_normal);
ncd.original = original;
- BKE_pbvh_search_callback_occluded(bvh, nearest_to_ray_aabb_dist_sq, &ncd, cb, data);
+ BKE_pbvh_search_callback_occluded(pbvh, nearest_to_ray_aabb_dist_sq, &ncd, cb, data);
}
-static bool pbvh_faces_node_nearest_to_ray(PBVH *bvh,
+static bool pbvh_faces_node_nearest_to_ray(PBVH *pbvh,
const PBVHNode *node,
float (*origco)[3],
const float ray_start[3],
@@ -2390,17 +2433,17 @@ static bool pbvh_faces_node_nearest_to_ray(PBVH *bvh,
float *depth,
float *dist_sq)
{
- const MVert *vert = bvh->verts;
- const MLoop *mloop = bvh->mloop;
+ const MVert *vert = pbvh->verts;
+ const MLoop *mloop = pbvh->mloop;
const int *faces = node->prim_indices;
int i, totface = node->totprim;
bool hit = false;
for (i = 0; i < totface; i++) {
- const MLoopTri *lt = &bvh->looptri[faces[i]];
+ const MLoopTri *lt = &pbvh->looptri[faces[i]];
const int *face_verts = node->face_vert_indices[i];
- if (paint_is_face_hidden(lt, vert, mloop)) {
+ if (pbvh->respect_hide && paint_is_face_hidden(lt, vert, mloop)) {
continue;
}
@@ -2429,7 +2472,7 @@ static bool pbvh_faces_node_nearest_to_ray(PBVH *bvh,
return hit;
}
-static bool pbvh_grids_node_nearest_to_ray(PBVH *bvh,
+static bool pbvh_grids_node_nearest_to_ray(PBVH *pbvh,
PBVHNode *node,
float (*origco)[3],
const float ray_start[3],
@@ -2438,18 +2481,18 @@ static bool pbvh_grids_node_nearest_to_ray(PBVH *bvh,
float *dist_sq)
{
const int totgrid = node->totprim;
- const int gridsize = bvh->gridkey.grid_size;
+ const int gridsize = pbvh->gridkey.grid_size;
bool hit = false;
for (int i = 0; i < totgrid; i++) {
- CCGElem *grid = bvh->grids[node->prim_indices[i]];
+ CCGElem *grid = pbvh->grids[node->prim_indices[i]];
BLI_bitmap *gh;
if (!grid) {
continue;
}
- gh = bvh->grid_hidden[node->prim_indices[i]];
+ gh = pbvh->grid_hidden[node->prim_indices[i]];
for (int y = 0; y < gridsize - 1; y++) {
for (int x = 0; x < gridsize - 1; x++) {
@@ -2473,10 +2516,10 @@ static bool pbvh_grids_node_nearest_to_ray(PBVH *bvh,
else {
hit |= ray_face_nearest_quad(ray_start,
ray_normal,
- CCG_grid_elem_co(&bvh->gridkey, grid, x, y),
- CCG_grid_elem_co(&bvh->gridkey, grid, x + 1, y),
- CCG_grid_elem_co(&bvh->gridkey, grid, x + 1, y + 1),
- CCG_grid_elem_co(&bvh->gridkey, grid, x, y + 1),
+ CCG_grid_elem_co(&pbvh->gridkey, grid, x, y),
+ CCG_grid_elem_co(&pbvh->gridkey, grid, x + 1, y),
+ CCG_grid_elem_co(&pbvh->gridkey, grid, x + 1, y + 1),
+ CCG_grid_elem_co(&pbvh->gridkey, grid, x, y + 1),
depth,
dist_sq);
}
@@ -2491,7 +2534,7 @@ static bool pbvh_grids_node_nearest_to_ray(PBVH *bvh,
return hit;
}
-bool BKE_pbvh_node_find_nearest_to_ray(PBVH *bvh,
+bool BKE_pbvh_node_find_nearest_to_ray(PBVH *pbvh,
PBVHNode *node,
float (*origco)[3],
bool use_origco,
@@ -2506,14 +2549,14 @@ bool BKE_pbvh_node_find_nearest_to_ray(PBVH *bvh,
return false;
}
- switch (bvh->type) {
+ switch (pbvh->type) {
case PBVH_FACES:
hit |= pbvh_faces_node_nearest_to_ray(
- bvh, node, origco, ray_start, ray_normal, depth, dist_sq);
+ pbvh, node, origco, ray_start, ray_normal, depth, dist_sq);
break;
case PBVH_GRIDS:
hit |= pbvh_grids_node_nearest_to_ray(
- bvh, node, origco, ray_start, ray_normal, depth, dist_sq);
+ pbvh, node, origco, ray_start, ray_normal, depth, dist_sq);
break;
case PBVH_BMESH:
hit = pbvh_bmesh_node_nearest_to_ray(
@@ -2587,26 +2630,26 @@ bool BKE_pbvh_node_frustum_exclude_AABB(PBVHNode *node, void *data)
return test_frustum_aabb(bb_min, bb_max, data) != ISECT_INSIDE;
}
-void BKE_pbvh_update_normals(PBVH *bvh, struct SubdivCCG *subdiv_ccg)
+void BKE_pbvh_update_normals(PBVH *pbvh, struct SubdivCCG *subdiv_ccg)
{
/* Update normals */
PBVHNode **nodes;
int totnode;
BKE_pbvh_search_gather(
- bvh, update_search_cb, POINTER_FROM_INT(PBVH_UpdateNormals), &nodes, &totnode);
+ pbvh, update_search_cb, POINTER_FROM_INT(PBVH_UpdateNormals), &nodes, &totnode);
if (totnode > 0) {
- if (bvh->type == PBVH_BMESH) {
+ if (pbvh->type == PBVH_BMESH) {
pbvh_bmesh_normals_update(nodes, totnode);
}
- else if (bvh->type == PBVH_FACES) {
- pbvh_faces_update_normals(bvh, nodes, totnode);
+ else if (pbvh->type == PBVH_FACES) {
+ pbvh_faces_update_normals(pbvh, nodes, totnode);
}
- else if (bvh->type == PBVH_GRIDS) {
+ else if (pbvh->type == PBVH_GRIDS) {
struct CCGFace **faces;
int num_faces;
- BKE_pbvh_get_grid_updates(bvh, true, (void ***)&faces, &num_faces);
+ BKE_pbvh_get_grid_updates(pbvh, true, (void ***)&faces, &num_faces);
if (num_faces > 0) {
BKE_subdiv_ccg_update_normals(subdiv_ccg, faces, num_faces);
MEM_freeN(faces);
@@ -2617,10 +2660,10 @@ void BKE_pbvh_update_normals(PBVH *bvh, struct SubdivCCG *subdiv_ccg)
MEM_SAFE_FREE(nodes);
}
-void BKE_pbvh_face_sets_color_set(PBVH *bvh, int seed, int color_default)
+void BKE_pbvh_face_sets_color_set(PBVH *pbvh, int seed, int color_default)
{
- bvh->face_sets_color_seed = seed;
- bvh->face_sets_color_default = color_default;
+ pbvh->face_sets_color_seed = seed;
+ pbvh->face_sets_color_default = color_default;
}
/**
@@ -2643,10 +2686,10 @@ static bool pbvh_draw_search_cb(PBVHNode *node, void *data_v)
return true;
}
-void BKE_pbvh_draw_cb(PBVH *bvh,
- bool show_vcol,
+void BKE_pbvh_draw_cb(PBVH *pbvh,
bool update_only_visible,
- PBVHFrustumPlanes *frustum,
+ PBVHFrustumPlanes *update_frustum,
+ PBVHFrustumPlanes *draw_frustum,
void (*draw_fn)(void *user_data, GPU_PBVH_Buffers *buffers),
void *user_data)
{
@@ -2657,22 +2700,23 @@ void BKE_pbvh_draw_cb(PBVH *bvh,
if (!update_only_visible) {
/* Update all draw buffers, also those outside the view. */
- BKE_pbvh_search_gather(bvh, update_search_cb, POINTER_FROM_INT(update_flag), &nodes, &totnode);
+ BKE_pbvh_search_gather(
+ pbvh, update_search_cb, POINTER_FROM_INT(update_flag), &nodes, &totnode);
if (totnode) {
- pbvh_update_draw_buffers(bvh, nodes, totnode, show_vcol, update_flag);
+ pbvh_update_draw_buffers(pbvh, nodes, totnode, update_flag);
}
MEM_SAFE_FREE(nodes);
}
/* Gather visible nodes. */
- PBVHDrawSearchData data = {.frustum = frustum, .accum_update_flag = 0};
- BKE_pbvh_search_gather(bvh, pbvh_draw_search_cb, &data, &nodes, &totnode);
+ PBVHDrawSearchData data = {.frustum = update_frustum, .accum_update_flag = 0};
+ BKE_pbvh_search_gather(pbvh, pbvh_draw_search_cb, &data, &nodes, &totnode);
if (update_only_visible && (data.accum_update_flag & update_flag)) {
/* Update draw buffers in visible nodes. */
- pbvh_update_draw_buffers(bvh, nodes, totnode, show_vcol, data.accum_update_flag);
+ pbvh_update_draw_buffers(pbvh, nodes, totnode, data.accum_update_flag);
}
/* Draw. */
@@ -2685,7 +2729,15 @@ void BKE_pbvh_draw_cb(PBVH *bvh,
}
node->flag &= ~(PBVH_RebuildDrawBuffers | PBVH_UpdateDrawBuffers);
+ }
+ MEM_SAFE_FREE(nodes);
+
+ PBVHDrawSearchData draw_data = {.frustum = draw_frustum, .accum_update_flag = 0};
+ BKE_pbvh_search_gather(pbvh, pbvh_draw_search_cb, &draw_data, &nodes, &totnode);
+
+ for (int a = 0; a < totnode; a++) {
+ PBVHNode *node = nodes[a];
if (!(node->flag & PBVH_FullyHidden)) {
draw_fn(user_data, node->draw_buffers);
}
@@ -2695,53 +2747,33 @@ void BKE_pbvh_draw_cb(PBVH *bvh,
}
void BKE_pbvh_draw_debug_cb(
- PBVH *bvh,
+ PBVH *pbvh,
void (*draw_fn)(void *user_data, const float bmin[3], const float bmax[3], PBVHNodeFlags flag),
void *user_data)
{
- for (int a = 0; a < bvh->totnode; a++) {
- PBVHNode *node = &bvh->nodes[a];
+ for (int a = 0; a < pbvh->totnode; a++) {
+ PBVHNode *node = &pbvh->nodes[a];
draw_fn(user_data, node->vb.bmin, node->vb.bmax, node->flag);
}
}
void BKE_pbvh_grids_update(
- PBVH *bvh, CCGElem **grids, void **gridfaces, DMFlagMat *flagmats, BLI_bitmap **grid_hidden)
+ PBVH *pbvh, CCGElem **grids, void **gridfaces, DMFlagMat *flagmats, BLI_bitmap **grid_hidden)
{
- bvh->grids = grids;
- bvh->gridfaces = gridfaces;
+ pbvh->grids = grids;
+ pbvh->gridfaces = gridfaces;
- if (flagmats != bvh->grid_flag_mats || bvh->grid_hidden != grid_hidden) {
- bvh->grid_flag_mats = flagmats;
- bvh->grid_hidden = grid_hidden;
+ if (flagmats != pbvh->grid_flag_mats || pbvh->grid_hidden != grid_hidden) {
+ pbvh->grid_flag_mats = flagmats;
+ pbvh->grid_hidden = grid_hidden;
- for (int a = 0; a < bvh->totnode; a++) {
- BKE_pbvh_node_mark_rebuild_draw(&bvh->nodes[a]);
+ for (int a = 0; a < pbvh->totnode; a++) {
+ BKE_pbvh_node_mark_rebuild_draw(&pbvh->nodes[a]);
}
}
}
-/* Get the node's displacement layer, creating it if necessary */
-float *BKE_pbvh_node_layer_disp_get(PBVH *bvh, PBVHNode *node)
-{
- if (!node->layer_disp) {
- int totvert = 0;
- BKE_pbvh_node_num_verts(bvh, node, &totvert, NULL);
- node->layer_disp = MEM_callocN(sizeof(float) * totvert, "layer disp");
- }
- return node->layer_disp;
-}
-
-/* If the node has a displacement layer, free it and set to null */
-void BKE_pbvh_node_layer_disp_free(PBVHNode *node)
-{
- if (node->layer_disp) {
- MEM_freeN(node->layer_disp);
- node->layer_disp = NULL;
- }
-}
-
float (*BKE_pbvh_vert_coords_alloc(PBVH *pbvh))[3]
{
float(*vertCos)[3] = NULL;
@@ -2810,7 +2842,7 @@ bool BKE_pbvh_is_deformed(PBVH *pbvh)
}
/* Proxies */
-PBVHProxyNode *BKE_pbvh_node_add_proxy(PBVH *bvh, PBVHNode *node)
+PBVHProxyNode *BKE_pbvh_node_add_proxy(PBVH *pbvh, PBVHNode *node)
{
int index, totverts;
@@ -2825,7 +2857,7 @@ PBVHProxyNode *BKE_pbvh_node_add_proxy(PBVH *bvh, PBVHNode *node)
node->proxies = MEM_mallocN(sizeof(PBVHProxyNode), "PBVHNodeProxy");
}
- BKE_pbvh_node_num_verts(bvh, node, &totverts, NULL);
+ BKE_pbvh_node_num_verts(pbvh, node, &totverts, NULL);
node->proxies[index].co = MEM_callocN(sizeof(float[3]) * totverts, "PBVHNodeProxy.co");
return node->proxies + index;
@@ -2873,7 +2905,7 @@ void BKE_pbvh_gather_proxies(PBVH *pbvh, PBVHNode ***r_array, int *r_tot)
*r_tot = tot;
}
-void pbvh_vertex_iter_init(PBVH *bvh, PBVHNode *node, PBVHVertexIter *vi, int mode)
+void pbvh_vertex_iter_init(PBVH *pbvh, PBVHNode *node, PBVHVertexIter *vi, int mode)
{
struct CCGElem **grids;
struct MVert *verts;
@@ -2886,10 +2918,16 @@ void pbvh_vertex_iter_init(PBVH *bvh, PBVHNode *node, PBVHVertexIter *vi, int mo
vi->fno = NULL;
vi->mvert = NULL;
- BKE_pbvh_node_get_grids(bvh, node, &grid_indices, &totgrid, NULL, &gridsize, &grids);
- BKE_pbvh_node_num_verts(bvh, node, &uniq_verts, &totvert);
- BKE_pbvh_node_get_verts(bvh, node, &vert_indices, &verts);
- vi->key = bvh->gridkey;
+ vi->respect_hide = pbvh->respect_hide;
+ if (pbvh->respect_hide == false) {
+ /* The same value for all vertices. */
+ vi->visible = true;
+ }
+
+ BKE_pbvh_node_get_grids(pbvh, node, &grid_indices, &totgrid, NULL, &gridsize, &grids);
+ BKE_pbvh_node_num_verts(pbvh, node, &uniq_verts, &totvert);
+ BKE_pbvh_node_get_verts(pbvh, node, &vert_indices, &verts);
+ vi->key = pbvh->gridkey;
vi->grids = grids;
vi->grid_indices = grid_indices;
@@ -2905,45 +2943,45 @@ void pbvh_vertex_iter_init(PBVH *bvh, PBVHNode *node, PBVHVertexIter *vi, int mo
vi->vert_indices = vert_indices;
vi->mverts = verts;
- if (bvh->type == PBVH_BMESH) {
+ if (pbvh->type == PBVH_BMESH) {
BLI_gsetIterator_init(&vi->bm_unique_verts, node->bm_unique_verts);
BLI_gsetIterator_init(&vi->bm_other_verts, node->bm_other_verts);
- vi->bm_vdata = &bvh->bm->vdata;
+ vi->bm_vdata = &pbvh->bm->vdata;
vi->cd_vert_mask_offset = CustomData_get_offset(vi->bm_vdata, CD_PAINT_MASK);
}
vi->gh = NULL;
if (vi->grids && mode == PBVH_ITER_UNIQUE) {
- vi->grid_hidden = bvh->grid_hidden;
+ vi->grid_hidden = pbvh->grid_hidden;
}
vi->mask = NULL;
- if (bvh->type == PBVH_FACES) {
- vi->vmask = CustomData_get_layer(bvh->vdata, CD_PAINT_MASK);
+ if (pbvh->type == PBVH_FACES) {
+ vi->vmask = CustomData_get_layer(pbvh->vdata, CD_PAINT_MASK);
}
}
-bool pbvh_has_mask(PBVH *bvh)
+bool pbvh_has_mask(PBVH *pbvh)
{
- switch (bvh->type) {
+ switch (pbvh->type) {
case PBVH_GRIDS:
- return (bvh->gridkey.has_mask != 0);
+ return (pbvh->gridkey.has_mask != 0);
case PBVH_FACES:
- return (bvh->vdata && CustomData_get_layer(bvh->vdata, CD_PAINT_MASK));
+ return (pbvh->vdata && CustomData_get_layer(pbvh->vdata, CD_PAINT_MASK));
case PBVH_BMESH:
- return (bvh->bm && (CustomData_get_offset(&bvh->bm->vdata, CD_PAINT_MASK) != -1));
+ return (pbvh->bm && (CustomData_get_offset(&pbvh->bm->vdata, CD_PAINT_MASK) != -1));
}
return false;
}
-bool pbvh_has_face_sets(PBVH *bvh)
+bool pbvh_has_face_sets(PBVH *pbvh)
{
- switch (bvh->type) {
+ switch (pbvh->type) {
case PBVH_GRIDS:
- return false;
+ return (pbvh->pdata && CustomData_get_layer(pbvh->pdata, CD_SCULPT_FACE_SETS));
case PBVH_FACES:
- return (bvh->pdata && CustomData_get_layer(bvh->pdata, CD_SCULPT_FACE_SETS));
+ return (pbvh->pdata && CustomData_get_layer(pbvh->pdata, CD_SCULPT_FACE_SETS));
case PBVH_BMESH:
return false;
}
@@ -2951,17 +2989,33 @@ bool pbvh_has_face_sets(PBVH *bvh)
return false;
}
-void pbvh_show_mask_set(PBVH *bvh, bool show_mask)
+void pbvh_show_mask_set(PBVH *pbvh, bool show_mask)
+{
+ pbvh->show_mask = show_mask;
+}
+
+void pbvh_show_face_sets_set(PBVH *pbvh, bool show_face_sets)
+{
+ pbvh->show_face_sets = show_face_sets;
+}
+
+void BKE_pbvh_set_frustum_planes(PBVH *pbvh, PBVHFrustumPlanes *planes)
{
- bvh->show_mask = show_mask;
+ pbvh->num_planes = planes->num_planes;
+ for (int i = 0; i < pbvh->num_planes; i++) {
+ copy_v4_v4(pbvh->planes[i], planes->planes[i]);
+ }
}
-void pbvh_show_face_sets_set(PBVH *bvh, bool show_face_sets)
+void BKE_pbvh_get_frustum_planes(PBVH *pbvh, PBVHFrustumPlanes *planes)
{
- bvh->show_face_sets = show_face_sets;
+ planes->num_planes = pbvh->num_planes;
+ for (int i = 0; i < planes->num_planes; i++) {
+ copy_v4_v4(planes->planes[i], pbvh->planes[i]);
+ }
}
-void BKE_pbvh_parallel_range_settings(PBVHParallelSettings *settings,
+void BKE_pbvh_parallel_range_settings(TaskParallelSettings *settings,
bool use_threading,
int totnode)
{
@@ -2969,8 +3023,23 @@ void BKE_pbvh_parallel_range_settings(PBVHParallelSettings *settings,
settings->use_threading = use_threading && totnode > 1;
}
-MVert *BKE_pbvh_get_verts(const PBVH *bvh)
+MVert *BKE_pbvh_get_verts(const PBVH *pbvh)
+{
+ BLI_assert(pbvh->type == PBVH_FACES);
+ return pbvh->verts;
+}
+
+void BKE_pbvh_subdiv_cgg_set(PBVH *pbvh, SubdivCCG *subdiv_ccg)
+{
+ pbvh->subdiv_ccg = subdiv_ccg;
+}
+
+void BKE_pbvh_face_sets_set(PBVH *pbvh, int *face_sets)
+{
+ pbvh->face_sets = face_sets;
+}
+
+void BKE_pbvh_respect_hide_set(PBVH *pbvh, bool respect_hide)
{
- BLI_assert(bvh->type == PBVH_FACES);
- return bvh->verts;
+ pbvh->respect_hide = respect_hide;
}
diff --git a/source/blender/blenkernel/intern/pbvh_bmesh.c b/source/blender/blenkernel/intern/pbvh_bmesh.c
index 73042222436..e87c7c8d46d 100644
--- a/source/blender/blenkernel/intern/pbvh_bmesh.c
+++ b/source/blender/blenkernel/intern/pbvh_bmesh.c
@@ -62,7 +62,7 @@
// #define USE_VERIFY
#ifdef USE_VERIFY
-static void pbvh_bmesh_verify(PBVH *bvh);
+static void pbvh_bmesh_verify(PBVH *pbvh);
#endif
/** \name BMesh Utility API
@@ -200,13 +200,13 @@ static BMVert *bm_vert_hash_lookup_chain(GHash *deleted_verts, BMVert *v)
/****************************** Building ******************************/
/* Update node data after splitting */
-static void pbvh_bmesh_node_finalize(PBVH *bvh,
+static void pbvh_bmesh_node_finalize(PBVH *pbvh,
const int node_index,
const int cd_vert_node_offset,
const int cd_face_node_offset)
{
GSetIterator gs_iter;
- PBVHNode *n = &bvh->nodes[node_index];
+ PBVHNode *n = &pbvh->nodes[node_index];
bool has_visible = false;
/* Create vert hash sets */
@@ -258,15 +258,15 @@ static void pbvh_bmesh_node_finalize(PBVH *bvh,
}
/* Recursively split the node if it exceeds the leaf_limit */
-static void pbvh_bmesh_node_split(PBVH *bvh, const BBC *bbc_array, int node_index)
+static void pbvh_bmesh_node_split(PBVH *pbvh, const BBC *bbc_array, int node_index)
{
- const int cd_vert_node_offset = bvh->cd_vert_node_offset;
- const int cd_face_node_offset = bvh->cd_face_node_offset;
- PBVHNode *n = &bvh->nodes[node_index];
+ const int cd_vert_node_offset = pbvh->cd_vert_node_offset;
+ const int cd_face_node_offset = pbvh->cd_face_node_offset;
+ PBVHNode *n = &pbvh->nodes[node_index];
- if (BLI_gset_len(n->bm_faces) <= bvh->leaf_limit) {
+ if (BLI_gset_len(n->bm_faces) <= pbvh->leaf_limit) {
/* Node limit not exceeded */
- pbvh_bmesh_node_finalize(bvh, node_index, cd_vert_node_offset, cd_face_node_offset);
+ pbvh_bmesh_node_finalize(pbvh, node_index, cd_vert_node_offset, cd_face_node_offset);
return;
}
@@ -286,15 +286,15 @@ static void pbvh_bmesh_node_split(PBVH *bvh, const BBC *bbc_array, int node_inde
const float mid = (cb.bmax[axis] + cb.bmin[axis]) * 0.5f;
/* Add two new child nodes */
- const int children = bvh->totnode;
+ const int children = pbvh->totnode;
n->children_offset = children;
- pbvh_grow_nodes(bvh, bvh->totnode + 2);
+ pbvh_grow_nodes(pbvh, pbvh->totnode + 2);
/* Array reallocated, update current node pointer */
- n = &bvh->nodes[node_index];
+ n = &pbvh->nodes[node_index];
/* Initialize children */
- PBVHNode *c1 = &bvh->nodes[children], *c2 = &bvh->nodes[children + 1];
+ PBVHNode *c1 = &pbvh->nodes[children], *c2 = &pbvh->nodes[children + 1];
c1->flag |= PBVH_Leaf;
c2->flag |= PBVH_Leaf;
c1->bm_faces = BLI_gset_ptr_new_ex("bm_faces", BLI_gset_len(n->bm_faces) / 2);
@@ -370,25 +370,25 @@ static void pbvh_bmesh_node_split(PBVH *bvh, const BBC *bbc_array, int node_inde
n->flag &= ~PBVH_Leaf;
/* Recurse */
- pbvh_bmesh_node_split(bvh, bbc_array, children);
- pbvh_bmesh_node_split(bvh, bbc_array, children + 1);
+ pbvh_bmesh_node_split(pbvh, bbc_array, children);
+ pbvh_bmesh_node_split(pbvh, bbc_array, children + 1);
/* Array maybe reallocated, update current node pointer */
- n = &bvh->nodes[node_index];
+ n = &pbvh->nodes[node_index];
/* Update bounding box */
BB_reset(&n->vb);
- BB_expand_with_bb(&n->vb, &bvh->nodes[n->children_offset].vb);
- BB_expand_with_bb(&n->vb, &bvh->nodes[n->children_offset + 1].vb);
+ BB_expand_with_bb(&n->vb, &pbvh->nodes[n->children_offset].vb);
+ BB_expand_with_bb(&n->vb, &pbvh->nodes[n->children_offset + 1].vb);
n->orig_vb = n->vb;
}
/* Recursively split the node if it exceeds the leaf_limit */
-static bool pbvh_bmesh_node_limit_ensure(PBVH *bvh, int node_index)
+static bool pbvh_bmesh_node_limit_ensure(PBVH *pbvh, int node_index)
{
- GSet *bm_faces = bvh->nodes[node_index].bm_faces;
+ GSet *bm_faces = pbvh->nodes[node_index].bm_faces;
const int bm_faces_size = BLI_gset_len(bm_faces);
- if (bm_faces_size <= bvh->leaf_limit) {
+ if (bm_faces_size <= pbvh->leaf_limit) {
/* Node limit not exceeded */
return false;
}
@@ -414,9 +414,9 @@ static bool pbvh_bmesh_node_limit_ensure(PBVH *bvh, int node_index)
BM_elem_index_set(f, i); /* set_dirty! */
}
/* Likely this is already dirty. */
- bvh->bm->elem_index_dirty |= BM_FACE;
+ pbvh->bm->elem_index_dirty |= BM_FACE;
- pbvh_bmesh_node_split(bvh, bbc_array, node_index);
+ pbvh_bmesh_node_split(pbvh, bbc_array, node_index);
MEM_freeN(bbc_array);
@@ -426,88 +426,91 @@ static bool pbvh_bmesh_node_limit_ensure(PBVH *bvh, int node_index)
/**********************************************************************/
#if 0
-static int pbvh_bmesh_node_offset_from_elem(PBVH *bvh, BMElem *ele)
+static int pbvh_bmesh_node_offset_from_elem(PBVH *pbvh, BMElem *ele)
{
switch (ele->head.htype) {
case BM_VERT:
- return bvh->cd_vert_node_offset;
+ return pbvh->cd_vert_node_offset;
default:
BLI_assert(ele->head.htype == BM_FACE);
- return bvh->cd_face_node_offset;
+ return pbvh->cd_face_node_offset;
}
}
-static int pbvh_bmesh_node_index_from_elem(PBVH *bvh, void *key)
+static int pbvh_bmesh_node_index_from_elem(PBVH *pbvh, void *key)
{
- const int cd_node_offset = pbvh_bmesh_node_offset_from_elem(bvh, key);
+ const int cd_node_offset = pbvh_bmesh_node_offset_from_elem(pbvh, key);
const int node_index = BM_ELEM_CD_GET_INT((BMElem *)key, cd_node_offset);
BLI_assert(node_index != DYNTOPO_NODE_NONE);
- BLI_assert(node_index < bvh->totnode);
- (void)bvh;
+ BLI_assert(node_index < pbvh->totnode);
+ (void)pbvh;
return node_index;
}
-static PBVHNode *pbvh_bmesh_node_from_elem(PBVH *bvh, void *key)
+static PBVHNode *pbvh_bmesh_node_from_elem(PBVH *pbvh, void *key)
{
- return &bvh->nodes[pbvh_bmesh_node_index_from_elem(bvh, key)];
+ return &pbvh->nodes[pbvh_bmesh_node_index_from_elem(pbvh, key)];
}
/* typecheck */
-# define pbvh_bmesh_node_index_from_elem(bvh, key) \
- (CHECK_TYPE_ANY(key, BMFace *, BMVert *), pbvh_bmesh_node_index_from_elem(bvh, key))
-# define pbvh_bmesh_node_from_elem(bvh, key) \
- (CHECK_TYPE_ANY(key, BMFace *, BMVert *), pbvh_bmesh_node_from_elem(bvh, key))
+# define pbvh_bmesh_node_index_from_elem(pbvh, key) \
+ (CHECK_TYPE_ANY(key, BMFace *, BMVert *), pbvh_bmesh_node_index_from_elem(pbvh, key))
+# define pbvh_bmesh_node_from_elem(pbvh, key) \
+ (CHECK_TYPE_ANY(key, BMFace *, BMVert *), pbvh_bmesh_node_from_elem(pbvh, key))
#endif
-BLI_INLINE int pbvh_bmesh_node_index_from_vert(PBVH *bvh, const BMVert *key)
+BLI_INLINE int pbvh_bmesh_node_index_from_vert(PBVH *pbvh, const BMVert *key)
{
- const int node_index = BM_ELEM_CD_GET_INT((const BMElem *)key, bvh->cd_vert_node_offset);
+ const int node_index = BM_ELEM_CD_GET_INT((const BMElem *)key, pbvh->cd_vert_node_offset);
BLI_assert(node_index != DYNTOPO_NODE_NONE);
- BLI_assert(node_index < bvh->totnode);
+ BLI_assert(node_index < pbvh->totnode);
return node_index;
}
-BLI_INLINE int pbvh_bmesh_node_index_from_face(PBVH *bvh, const BMFace *key)
+BLI_INLINE int pbvh_bmesh_node_index_from_face(PBVH *pbvh, const BMFace *key)
{
- const int node_index = BM_ELEM_CD_GET_INT((const BMElem *)key, bvh->cd_face_node_offset);
+ const int node_index = BM_ELEM_CD_GET_INT((const BMElem *)key, pbvh->cd_face_node_offset);
BLI_assert(node_index != DYNTOPO_NODE_NONE);
- BLI_assert(node_index < bvh->totnode);
+ BLI_assert(node_index < pbvh->totnode);
return node_index;
}
-BLI_INLINE PBVHNode *pbvh_bmesh_node_from_vert(PBVH *bvh, const BMVert *key)
+BLI_INLINE PBVHNode *pbvh_bmesh_node_from_vert(PBVH *pbvh, const BMVert *key)
{
- return &bvh->nodes[pbvh_bmesh_node_index_from_vert(bvh, key)];
+ return &pbvh->nodes[pbvh_bmesh_node_index_from_vert(pbvh, key)];
}
-BLI_INLINE PBVHNode *pbvh_bmesh_node_from_face(PBVH *bvh, const BMFace *key)
+BLI_INLINE PBVHNode *pbvh_bmesh_node_from_face(PBVH *pbvh, const BMFace *key)
{
- return &bvh->nodes[pbvh_bmesh_node_index_from_face(bvh, key)];
+ return &pbvh->nodes[pbvh_bmesh_node_index_from_face(pbvh, key)];
}
-static BMVert *pbvh_bmesh_vert_create(
- PBVH *bvh, int node_index, const float co[3], const float no[3], const int cd_vert_mask_offset)
+static BMVert *pbvh_bmesh_vert_create(PBVH *pbvh,
+ int node_index,
+ const float co[3],
+ const float no[3],
+ const int cd_vert_mask_offset)
{
- PBVHNode *node = &bvh->nodes[node_index];
+ PBVHNode *node = &pbvh->nodes[node_index];
- BLI_assert((bvh->totnode == 1 || node_index) && node_index <= bvh->totnode);
+ BLI_assert((pbvh->totnode == 1 || node_index) && node_index <= pbvh->totnode);
/* avoid initializing customdata because its quite involved */
- BMVert *v = BM_vert_create(bvh->bm, co, NULL, BM_CREATE_SKIP_CD);
- CustomData_bmesh_set_default(&bvh->bm->vdata, &v->head.data);
+ BMVert *v = BM_vert_create(pbvh->bm, co, NULL, BM_CREATE_SKIP_CD);
+ CustomData_bmesh_set_default(&pbvh->bm->vdata, &v->head.data);
/* This value is logged below */
copy_v3_v3(v->no, no);
BLI_gset_insert(node->bm_unique_verts, v);
- BM_ELEM_CD_SET_INT(v, bvh->cd_vert_node_offset, node_index);
+ BM_ELEM_CD_SET_INT(v, pbvh->cd_vert_node_offset, node_index);
node->flag |= PBVH_UpdateDrawBuffers | PBVH_UpdateBB;
/* Log the new vertex */
- BM_log_vert_added(bvh->bm_log, v, cd_vert_mask_offset);
+ BM_log_vert_added(pbvh->bm_log, v, cd_vert_mask_offset);
return v;
}
@@ -516,38 +519,38 @@ static BMVert *pbvh_bmesh_vert_create(
* \note Callers are responsible for checking if the face exists before adding.
*/
static BMFace *pbvh_bmesh_face_create(
- PBVH *bvh, int node_index, BMVert *v_tri[3], BMEdge *e_tri[3], const BMFace *f_example)
+ PBVH *pbvh, int node_index, BMVert *v_tri[3], BMEdge *e_tri[3], const BMFace *f_example)
{
- PBVHNode *node = &bvh->nodes[node_index];
+ PBVHNode *node = &pbvh->nodes[node_index];
/* ensure we never add existing face */
BLI_assert(!BM_face_exists(v_tri, 3));
- BMFace *f = BM_face_create(bvh->bm, v_tri, e_tri, 3, f_example, BM_CREATE_NOP);
+ BMFace *f = BM_face_create(pbvh->bm, v_tri, e_tri, 3, f_example, BM_CREATE_NOP);
f->head.hflag = f_example->head.hflag;
BLI_gset_insert(node->bm_faces, f);
- BM_ELEM_CD_SET_INT(f, bvh->cd_face_node_offset, node_index);
+ BM_ELEM_CD_SET_INT(f, pbvh->cd_face_node_offset, node_index);
/* mark node for update */
node->flag |= PBVH_UpdateDrawBuffers | PBVH_UpdateNormals;
node->flag &= ~PBVH_FullyHidden;
/* Log the new face */
- BM_log_face_added(bvh->bm_log, f);
+ BM_log_face_added(pbvh->bm_log, f);
return f;
}
/* Return the number of faces in 'node' that use vertex 'v' */
#if 0
-static int pbvh_bmesh_node_vert_use_count(PBVH *bvh, PBVHNode *node, BMVert *v)
+static int pbvh_bmesh_node_vert_use_count(PBVH *pbvh, PBVHNode *node, BMVert *v)
{
BMFace *f;
int count = 0;
BM_FACES_OF_VERT_ITER_BEGIN (f, v) {
- PBVHNode *f_node = pbvh_bmesh_node_from_face(bvh, f);
+ PBVHNode *f_node = pbvh_bmesh_node_from_face(pbvh, f);
if (f_node == node) {
count++;
}
@@ -558,10 +561,10 @@ static int pbvh_bmesh_node_vert_use_count(PBVH *bvh, PBVHNode *node, BMVert *v)
}
#endif
-#define pbvh_bmesh_node_vert_use_count_is_equal(bvh, node, v, n) \
- (pbvh_bmesh_node_vert_use_count_at_most(bvh, node, v, (n) + 1) == n)
+#define pbvh_bmesh_node_vert_use_count_is_equal(pbvh, node, v, n) \
+ (pbvh_bmesh_node_vert_use_count_at_most(pbvh, node, v, (n) + 1) == n)
-static int pbvh_bmesh_node_vert_use_count_at_most(PBVH *bvh,
+static int pbvh_bmesh_node_vert_use_count_at_most(PBVH *pbvh,
PBVHNode *node,
BMVert *v,
const int count_max)
@@ -570,7 +573,7 @@ static int pbvh_bmesh_node_vert_use_count_at_most(PBVH *bvh,
BMFace *f;
BM_FACES_OF_VERT_ITER_BEGIN (f, v) {
- PBVHNode *f_node = pbvh_bmesh_node_from_face(bvh, f);
+ PBVHNode *f_node = pbvh_bmesh_node_from_face(pbvh, f);
if (f_node == node) {
count++;
if (count == count_max) {
@@ -584,13 +587,13 @@ static int pbvh_bmesh_node_vert_use_count_at_most(PBVH *bvh,
}
/* Return a node that uses vertex 'v' other than its current owner */
-static PBVHNode *pbvh_bmesh_vert_other_node_find(PBVH *bvh, BMVert *v)
+static PBVHNode *pbvh_bmesh_vert_other_node_find(PBVH *pbvh, BMVert *v)
{
- PBVHNode *current_node = pbvh_bmesh_node_from_vert(bvh, v);
+ PBVHNode *current_node = pbvh_bmesh_node_from_vert(pbvh, v);
BMFace *f;
BM_FACES_OF_VERT_ITER_BEGIN (f, v) {
- PBVHNode *f_node = pbvh_bmesh_node_from_face(bvh, f);
+ PBVHNode *f_node = pbvh_bmesh_node_from_face(pbvh, f);
if (f_node != current_node) {
return f_node;
@@ -601,9 +604,9 @@ static PBVHNode *pbvh_bmesh_vert_other_node_find(PBVH *bvh, BMVert *v)
return NULL;
}
-static void pbvh_bmesh_vert_ownership_transfer(PBVH *bvh, PBVHNode *new_owner, BMVert *v)
+static void pbvh_bmesh_vert_ownership_transfer(PBVH *pbvh, PBVHNode *new_owner, BMVert *v)
{
- PBVHNode *current_owner = pbvh_bmesh_node_from_vert(bvh, v);
+ PBVHNode *current_owner = pbvh_bmesh_node_from_vert(pbvh, v);
/* mark node for update */
current_owner->flag |= PBVH_UpdateDrawBuffers | PBVH_UpdateBB;
@@ -613,7 +616,7 @@ static void pbvh_bmesh_vert_ownership_transfer(PBVH *bvh, PBVHNode *new_owner, B
BLI_gset_remove(current_owner->bm_unique_verts, v, NULL);
/* Set new ownership */
- BM_ELEM_CD_SET_INT(v, bvh->cd_vert_node_offset, new_owner - bvh->nodes);
+ BM_ELEM_CD_SET_INT(v, pbvh->cd_vert_node_offset, new_owner - pbvh->nodes);
BLI_gset_insert(new_owner->bm_unique_verts, v);
BLI_gset_remove(new_owner->bm_other_verts, v, NULL);
BLI_assert(!BLI_gset_haskey(new_owner->bm_other_verts, v));
@@ -622,26 +625,26 @@ static void pbvh_bmesh_vert_ownership_transfer(PBVH *bvh, PBVHNode *new_owner, B
new_owner->flag |= PBVH_UpdateDrawBuffers | PBVH_UpdateBB;
}
-static void pbvh_bmesh_vert_remove(PBVH *bvh, BMVert *v)
+static void pbvh_bmesh_vert_remove(PBVH *pbvh, BMVert *v)
{
/* never match for first time */
int f_node_index_prev = DYNTOPO_NODE_NONE;
- PBVHNode *v_node = pbvh_bmesh_node_from_vert(bvh, v);
+ PBVHNode *v_node = pbvh_bmesh_node_from_vert(pbvh, v);
BLI_gset_remove(v_node->bm_unique_verts, v, NULL);
- BM_ELEM_CD_SET_INT(v, bvh->cd_vert_node_offset, DYNTOPO_NODE_NONE);
+ BM_ELEM_CD_SET_INT(v, pbvh->cd_vert_node_offset, DYNTOPO_NODE_NONE);
/* Have to check each neighboring face's node */
BMFace *f;
BM_FACES_OF_VERT_ITER_BEGIN (f, v) {
- const int f_node_index = pbvh_bmesh_node_index_from_face(bvh, f);
+ const int f_node_index = pbvh_bmesh_node_index_from_face(pbvh, f);
/* faces often share the same node,
* quick check to avoid redundant #BLI_gset_remove calls */
if (f_node_index_prev != f_node_index) {
f_node_index_prev = f_node_index;
- PBVHNode *f_node = &bvh->nodes[f_node_index];
+ PBVHNode *f_node = &pbvh->nodes[f_node_index];
f_node->flag |= PBVH_UpdateDrawBuffers | PBVH_UpdateBB;
/* Remove current ownership */
@@ -654,9 +657,9 @@ static void pbvh_bmesh_vert_remove(PBVH *bvh, BMVert *v)
BM_FACES_OF_VERT_ITER_END;
}
-static void pbvh_bmesh_face_remove(PBVH *bvh, BMFace *f)
+static void pbvh_bmesh_face_remove(PBVH *pbvh, BMFace *f)
{
- PBVHNode *f_node = pbvh_bmesh_node_from_face(bvh, f);
+ PBVHNode *f_node = pbvh_bmesh_node_from_face(pbvh, f);
/* Check if any of this face's vertices need to be removed
* from the node */
@@ -664,16 +667,16 @@ static void pbvh_bmesh_face_remove(PBVH *bvh, BMFace *f)
BMLoop *l_iter = l_first;
do {
BMVert *v = l_iter->v;
- if (pbvh_bmesh_node_vert_use_count_is_equal(bvh, f_node, v, 1)) {
+ if (pbvh_bmesh_node_vert_use_count_is_equal(pbvh, f_node, v, 1)) {
if (BLI_gset_haskey(f_node->bm_unique_verts, v)) {
/* Find a different node that uses 'v' */
PBVHNode *new_node;
- new_node = pbvh_bmesh_vert_other_node_find(bvh, v);
+ new_node = pbvh_bmesh_vert_other_node_find(pbvh, v);
BLI_assert(new_node || BM_vert_face_count_is_equal(v, 1));
if (new_node) {
- pbvh_bmesh_vert_ownership_transfer(bvh, new_node, v);
+ pbvh_bmesh_vert_ownership_transfer(pbvh, new_node, v);
}
}
else {
@@ -685,10 +688,10 @@ static void pbvh_bmesh_face_remove(PBVH *bvh, BMFace *f)
/* Remove face from node and top level */
BLI_gset_remove(f_node->bm_faces, f, NULL);
- BM_ELEM_CD_SET_INT(f, bvh->cd_face_node_offset, DYNTOPO_NODE_NONE);
+ BM_ELEM_CD_SET_INT(f, pbvh->cd_face_node_offset, DYNTOPO_NODE_NONE);
/* Log removed face */
- BM_log_face_removed(bvh->bm_log, f);
+ BM_log_face_removed(pbvh->bm_log, f);
/* mark node for update */
f_node->flag |= PBVH_UpdateDrawBuffers | PBVH_UpdateNormals;
@@ -766,10 +769,10 @@ typedef struct {
#ifdef USE_EDGEQUEUE_TAG_VERIFY
/* simply check no edges are tagged
* (it's a requirement that edges enter and leave a clean tag state) */
-static void pbvh_bmesh_edge_tag_verify(PBVH *bvh)
+static void pbvh_bmesh_edge_tag_verify(PBVH *pbvh)
{
- for (int n = 0; n < bvh->totnode; n++) {
- PBVHNode *node = &bvh->nodes[n];
+ for (int n = 0; n < pbvh->totnode; n++) {
+ PBVHNode *node = &pbvh->nodes[n];
if (node->bm_faces) {
GSetIterator gs_iter;
GSET_ITER (gs_iter, node->bm_faces) {
@@ -999,7 +1002,7 @@ static void short_edge_queue_face_add(EdgeQueueContext *eq_ctx, BMFace *f)
* The highest priority (lowest number) is given to the longest edge.
*/
static void long_edge_queue_create(EdgeQueueContext *eq_ctx,
- PBVH *bvh,
+ PBVH *pbvh,
const float center[3],
const float view_normal[3],
float radius,
@@ -1009,9 +1012,9 @@ static void long_edge_queue_create(EdgeQueueContext *eq_ctx,
eq_ctx->q->heap = BLI_heapsimple_new();
eq_ctx->q->center = center;
eq_ctx->q->radius_squared = radius * radius;
- eq_ctx->q->limit_len_squared = bvh->bm_max_edge_len * bvh->bm_max_edge_len;
+ eq_ctx->q->limit_len_squared = pbvh->bm_max_edge_len * pbvh->bm_max_edge_len;
#ifdef USE_EDGEQUEUE_EVEN_SUBDIV
- eq_ctx->q->limit_len = bvh->bm_max_edge_len;
+ eq_ctx->q->limit_len = pbvh->bm_max_edge_len;
#endif
eq_ctx->q->view_normal = view_normal;
@@ -1031,11 +1034,11 @@ static void long_edge_queue_create(EdgeQueueContext *eq_ctx,
}
#ifdef USE_EDGEQUEUE_TAG_VERIFY
- pbvh_bmesh_edge_tag_verify(bvh);
+ pbvh_bmesh_edge_tag_verify(pbvh);
#endif
- for (int n = 0; n < bvh->totnode; n++) {
- PBVHNode *node = &bvh->nodes[n];
+ for (int n = 0; n < pbvh->totnode; n++) {
+ PBVHNode *node = &pbvh->nodes[n];
/* Check leaf nodes marked for topology update */
if ((node->flag & PBVH_Leaf) && (node->flag & PBVH_UpdateTopology) &&
@@ -1062,7 +1065,7 @@ static void long_edge_queue_create(EdgeQueueContext *eq_ctx,
* The highest priority (lowest number) is given to the shortest edge.
*/
static void short_edge_queue_create(EdgeQueueContext *eq_ctx,
- PBVH *bvh,
+ PBVH *pbvh,
const float center[3],
const float view_normal[3],
float radius,
@@ -1072,9 +1075,9 @@ static void short_edge_queue_create(EdgeQueueContext *eq_ctx,
eq_ctx->q->heap = BLI_heapsimple_new();
eq_ctx->q->center = center;
eq_ctx->q->radius_squared = radius * radius;
- eq_ctx->q->limit_len_squared = bvh->bm_min_edge_len * bvh->bm_min_edge_len;
+ eq_ctx->q->limit_len_squared = pbvh->bm_min_edge_len * pbvh->bm_min_edge_len;
#ifdef USE_EDGEQUEUE_EVEN_SUBDIV
- eq_ctx->q->limit_len = bvh->bm_min_edge_len;
+ eq_ctx->q->limit_len = pbvh->bm_min_edge_len;
#endif
eq_ctx->q->view_normal = view_normal;
@@ -1093,8 +1096,8 @@ static void short_edge_queue_create(EdgeQueueContext *eq_ctx,
eq_ctx->q->edge_queue_tri_in_range = edge_queue_tri_in_sphere;
}
- for (int n = 0; n < bvh->totnode; n++) {
- PBVHNode *node = &bvh->nodes[n];
+ for (int n = 0; n < pbvh->totnode; n++) {
+ PBVHNode *node = &pbvh->nodes[n];
/* Check leaf nodes marked for topology update */
if ((node->flag & PBVH_Leaf) && (node->flag & PBVH_UpdateTopology) &&
@@ -1114,7 +1117,7 @@ static void short_edge_queue_create(EdgeQueueContext *eq_ctx,
/*************************** Topology update **************************/
static void pbvh_bmesh_split_edge(EdgeQueueContext *eq_ctx,
- PBVH *bvh,
+ PBVH *pbvh,
BMEdge *e,
BLI_Buffer *edge_loops)
{
@@ -1130,7 +1133,7 @@ static void pbvh_bmesh_split_edge(EdgeQueueContext *eq_ctx,
int node_index = BM_ELEM_CD_GET_INT(e->v1, eq_ctx->cd_vert_node_offset);
BMVert *v_new = pbvh_bmesh_vert_create(
- bvh, node_index, co_mid, no_mid, eq_ctx->cd_vert_mask_offset);
+ pbvh, node_index, co_mid, no_mid, eq_ctx->cd_vert_mask_offset);
/* update paint mask */
if (eq_ctx->cd_vert_mask_offset != -1) {
@@ -1163,7 +1166,7 @@ static void pbvh_bmesh_split_edge(EdgeQueueContext *eq_ctx,
v2 = l_adj->next->v;
if (ni != node_index && i == 0) {
- pbvh_bmesh_vert_ownership_transfer(bvh, &bvh->nodes[ni], v_new);
+ pbvh_bmesh_vert_ownership_transfer(pbvh, &pbvh->nodes[ni], v_new);
}
/**
@@ -1196,26 +1199,26 @@ static void pbvh_bmesh_split_edge(EdgeQueueContext *eq_ctx,
v_tri[0] = v1;
v_tri[1] = v_new;
v_tri[2] = v_opp;
- bm_edges_from_tri(bvh->bm, v_tri, e_tri);
- f_new = pbvh_bmesh_face_create(bvh, ni, v_tri, e_tri, f_adj);
+ bm_edges_from_tri(pbvh->bm, v_tri, e_tri);
+ f_new = pbvh_bmesh_face_create(pbvh, ni, v_tri, e_tri, f_adj);
long_edge_queue_face_add(eq_ctx, f_new);
v_tri[0] = v_new;
v_tri[1] = v2;
/* v_tri[2] = v_opp; */ /* unchanged */
- e_tri[0] = BM_edge_create(bvh->bm, v_tri[0], v_tri[1], NULL, BM_CREATE_NO_DOUBLE);
+ e_tri[0] = BM_edge_create(pbvh->bm, v_tri[0], v_tri[1], NULL, BM_CREATE_NO_DOUBLE);
e_tri[2] = e_tri[1]; /* switched */
- e_tri[1] = BM_edge_create(bvh->bm, v_tri[1], v_tri[2], NULL, BM_CREATE_NO_DOUBLE);
- f_new = pbvh_bmesh_face_create(bvh, ni, v_tri, e_tri, f_adj);
+ e_tri[1] = BM_edge_create(pbvh->bm, v_tri[1], v_tri[2], NULL, BM_CREATE_NO_DOUBLE);
+ f_new = pbvh_bmesh_face_create(pbvh, ni, v_tri, e_tri, f_adj);
long_edge_queue_face_add(eq_ctx, f_new);
/* Delete original */
- pbvh_bmesh_face_remove(bvh, f_adj);
- BM_face_kill(bvh->bm, f_adj);
+ pbvh_bmesh_face_remove(pbvh, f_adj);
+ BM_face_kill(pbvh->bm, f_adj);
/* Ensure new vertex is in the node */
- if (!BLI_gset_haskey(bvh->nodes[ni].bm_unique_verts, v_new)) {
- BLI_gset_add(bvh->nodes[ni].bm_other_verts, v_new);
+ if (!BLI_gset_haskey(pbvh->nodes[ni].bm_unique_verts, v_new)) {
+ BLI_gset_add(pbvh->nodes[ni].bm_other_verts, v_new);
}
if (BM_vert_edge_count_is_over(v_opp, 8)) {
@@ -1228,11 +1231,11 @@ static void pbvh_bmesh_split_edge(EdgeQueueContext *eq_ctx,
}
}
- BM_edge_kill(bvh->bm, e);
+ BM_edge_kill(pbvh->bm, e);
}
static bool pbvh_bmesh_subdivide_long_edges(EdgeQueueContext *eq_ctx,
- PBVH *bvh,
+ PBVH *pbvh,
BLI_Buffer *edge_loops)
{
bool any_subdivided = false;
@@ -1274,17 +1277,17 @@ static bool pbvh_bmesh_subdivide_long_edges(EdgeQueueContext *eq_ctx,
any_subdivided = true;
- pbvh_bmesh_split_edge(eq_ctx, bvh, e, edge_loops);
+ pbvh_bmesh_split_edge(eq_ctx, pbvh, e, edge_loops);
}
#ifdef USE_EDGEQUEUE_TAG_VERIFY
- pbvh_bmesh_edge_tag_verify(bvh);
+ pbvh_bmesh_edge_tag_verify(pbvh);
#endif
return any_subdivided;
}
-static void pbvh_bmesh_collapse_edge(PBVH *bvh,
+static void pbvh_bmesh_collapse_edge(PBVH *pbvh,
BMEdge *e,
BMVert *v1,
BMVert *v2,
@@ -1306,20 +1309,20 @@ static void pbvh_bmesh_collapse_edge(PBVH *bvh,
}
/* Remove the merge vertex from the PBVH */
- pbvh_bmesh_vert_remove(bvh, v_del);
+ pbvh_bmesh_vert_remove(pbvh, v_del);
/* Remove all faces adjacent to the edge */
BMLoop *l_adj;
while ((l_adj = e->l)) {
BMFace *f_adj = l_adj->f;
- pbvh_bmesh_face_remove(bvh, f_adj);
- BM_face_kill(bvh->bm, f_adj);
+ pbvh_bmesh_face_remove(pbvh, f_adj);
+ BM_face_kill(pbvh->bm, f_adj);
}
/* Kill the edge */
BLI_assert(BM_edge_is_wire(e));
- BM_edge_kill(bvh->bm, e);
+ BM_edge_kill(pbvh->bm, e);
/* For all remaining faces of v_del, create a new face that is the
* same except it uses v_conn instead of v_del */
@@ -1364,10 +1367,10 @@ static void pbvh_bmesh_collapse_edge(PBVH *bvh,
BLI_assert(!BM_face_exists(v_tri, 3));
BMEdge *e_tri[3];
- PBVHNode *n = pbvh_bmesh_node_from_face(bvh, f);
- int ni = n - bvh->nodes;
- bm_edges_from_tri(bvh->bm, v_tri, e_tri);
- pbvh_bmesh_face_create(bvh, ni, v_tri, e_tri, f);
+ PBVHNode *n = pbvh_bmesh_node_from_face(pbvh, f);
+ int ni = n - pbvh->nodes;
+ bm_edges_from_tri(pbvh->bm, v_tri, e_tri);
+ pbvh_bmesh_face_create(pbvh, ni, v_tri, e_tri, f);
/* Ensure that v_conn is in the new face's node */
if (!BLI_gset_haskey(n->bm_unique_verts, v_conn)) {
@@ -1398,14 +1401,14 @@ static void pbvh_bmesh_collapse_edge(PBVH *bvh,
e_tri[2] = l_iter->e;
/* Remove the face */
- pbvh_bmesh_face_remove(bvh, f_del);
- BM_face_kill(bvh->bm, f_del);
+ pbvh_bmesh_face_remove(pbvh, f_del);
+ BM_face_kill(pbvh->bm, f_del);
/* Check if any of the face's edges are now unused by any
* face, if so delete them */
for (int j = 0; j < 3; j++) {
if (BM_edge_is_wire(e_tri[j])) {
- BM_edge_kill(bvh->bm, e_tri[j]);
+ BM_edge_kill(pbvh->bm, e_tri[j]);
}
}
@@ -1413,15 +1416,15 @@ static void pbvh_bmesh_collapse_edge(PBVH *bvh,
* remove them from the PBVH */
for (int j = 0; j < 3; j++) {
if ((v_tri[j] != v_del) && (v_tri[j]->e == NULL)) {
- pbvh_bmesh_vert_remove(bvh, v_tri[j]);
+ pbvh_bmesh_vert_remove(pbvh, v_tri[j]);
- BM_log_vert_removed(bvh->bm_log, v_tri[j], eq_ctx->cd_vert_mask_offset);
+ BM_log_vert_removed(pbvh->bm_log, v_tri[j], eq_ctx->cd_vert_mask_offset);
if (v_tri[j] == v_conn) {
v_conn = NULL;
}
BLI_ghash_insert(deleted_verts, v_tri[j], NULL);
- BM_vert_kill(bvh->bm, v_tri[j]);
+ BM_vert_kill(pbvh->bm, v_tri[j]);
}
}
}
@@ -1429,7 +1432,7 @@ static void pbvh_bmesh_collapse_edge(PBVH *bvh,
/* Move v_conn to the midpoint of v_conn and v_del (if v_conn still exists, it
* may have been deleted above) */
if (v_conn != NULL) {
- BM_log_vert_before_modified(bvh->bm_log, v_conn, eq_ctx->cd_vert_mask_offset);
+ BM_log_vert_before_modified(pbvh->bm_log, v_conn, eq_ctx->cd_vert_mask_offset);
mid_v3_v3v3(v_conn->co, v_conn->co, v_del->co);
add_v3_v3(v_conn->no, v_del->no);
normalize_v3(v_conn->no);
@@ -1437,7 +1440,7 @@ static void pbvh_bmesh_collapse_edge(PBVH *bvh,
/* update boundboxes attached to the connected vertex
* note that we can often get-away without this but causes T48779 */
BM_LOOPS_OF_VERT_ITER_BEGIN (l, v_conn) {
- PBVHNode *f_node = pbvh_bmesh_node_from_face(bvh, l->f);
+ PBVHNode *f_node = pbvh_bmesh_node_from_face(pbvh, l->f);
f_node->flag |= PBVH_UpdateDrawBuffers | PBVH_UpdateNormals | PBVH_UpdateBB;
}
BM_LOOPS_OF_VERT_ITER_END;
@@ -1445,17 +1448,17 @@ static void pbvh_bmesh_collapse_edge(PBVH *bvh,
/* Delete v_del */
BLI_assert(!BM_vert_face_check(v_del));
- BM_log_vert_removed(bvh->bm_log, v_del, eq_ctx->cd_vert_mask_offset);
+ BM_log_vert_removed(pbvh->bm_log, v_del, eq_ctx->cd_vert_mask_offset);
/* v_conn == NULL is OK */
BLI_ghash_insert(deleted_verts, v_del, v_conn);
- BM_vert_kill(bvh->bm, v_del);
+ BM_vert_kill(pbvh->bm, v_del);
}
static bool pbvh_bmesh_collapse_short_edges(EdgeQueueContext *eq_ctx,
- PBVH *bvh,
+ PBVH *pbvh,
BLI_Buffer *deleted_faces)
{
- const float min_len_squared = bvh->bm_min_edge_len * bvh->bm_min_edge_len;
+ const float min_len_squared = pbvh->bm_min_edge_len * pbvh->bm_min_edge_len;
bool any_collapsed = false;
/* deleted verts point to vertices they were merged into, or NULL when removed. */
GHash *deleted_verts = BLI_ghash_ptr_new("deleted_verts");
@@ -1496,7 +1499,7 @@ static bool pbvh_bmesh_collapse_short_edges(EdgeQueueContext *eq_ctx,
any_collapsed = true;
- pbvh_bmesh_collapse_edge(bvh, e, v1, v2, deleted_verts, deleted_faces, eq_ctx);
+ pbvh_bmesh_collapse_edge(pbvh, e, v1, v2, deleted_verts, deleted_faces, eq_ctx);
}
BLI_ghash_free(deleted_verts, NULL, NULL);
@@ -1691,11 +1694,11 @@ struct FastNodeBuildInfo {
* to a sub part of the arrays.
*/
static void pbvh_bmesh_node_limit_ensure_fast(
- PBVH *bvh, BMFace **nodeinfo, BBC *bbc_array, struct FastNodeBuildInfo *node, MemArena *arena)
+ PBVH *pbvh, BMFace **nodeinfo, BBC *bbc_array, struct FastNodeBuildInfo *node, MemArena *arena)
{
struct FastNodeBuildInfo *child1, *child2;
- if (node->totface <= bvh->leaf_limit) {
+ if (node->totface <= pbvh->leaf_limit) {
return;
}
@@ -1782,38 +1785,38 @@ static void pbvh_bmesh_node_limit_ensure_fast(
child2->start = node->start + num_child1;
child1->child1 = child1->child2 = child2->child1 = child2->child2 = NULL;
- pbvh_bmesh_node_limit_ensure_fast(bvh, nodeinfo, bbc_array, child1, arena);
- pbvh_bmesh_node_limit_ensure_fast(bvh, nodeinfo, bbc_array, child2, arena);
+ pbvh_bmesh_node_limit_ensure_fast(pbvh, nodeinfo, bbc_array, child1, arena);
+ pbvh_bmesh_node_limit_ensure_fast(pbvh, nodeinfo, bbc_array, child2, arena);
}
static void pbvh_bmesh_create_nodes_fast_recursive(
- PBVH *bvh, BMFace **nodeinfo, BBC *bbc_array, struct FastNodeBuildInfo *node, int node_index)
+ PBVH *pbvh, BMFace **nodeinfo, BBC *bbc_array, struct FastNodeBuildInfo *node, int node_index)
{
- PBVHNode *n = bvh->nodes + node_index;
+ PBVHNode *n = pbvh->nodes + node_index;
/* two cases, node does not have children or does have children */
if (node->child1) {
- int children_offset = bvh->totnode;
+ int children_offset = pbvh->totnode;
n->children_offset = children_offset;
- pbvh_grow_nodes(bvh, bvh->totnode + 2);
+ pbvh_grow_nodes(pbvh, pbvh->totnode + 2);
pbvh_bmesh_create_nodes_fast_recursive(
- bvh, nodeinfo, bbc_array, node->child1, children_offset);
+ pbvh, nodeinfo, bbc_array, node->child1, children_offset);
pbvh_bmesh_create_nodes_fast_recursive(
- bvh, nodeinfo, bbc_array, node->child2, children_offset + 1);
+ pbvh, nodeinfo, bbc_array, node->child2, children_offset + 1);
- n = &bvh->nodes[node_index];
+ n = &pbvh->nodes[node_index];
/* Update bounding box */
BB_reset(&n->vb);
- BB_expand_with_bb(&n->vb, &bvh->nodes[n->children_offset].vb);
- BB_expand_with_bb(&n->vb, &bvh->nodes[n->children_offset + 1].vb);
+ BB_expand_with_bb(&n->vb, &pbvh->nodes[n->children_offset].vb);
+ BB_expand_with_bb(&n->vb, &pbvh->nodes[n->children_offset + 1].vb);
n->orig_vb = n->vb;
}
else {
/* node does not have children so it's a leaf node, populate with faces and tag accordingly
* this is an expensive part but it's not so easily thread-able due to vertex node indices */
- const int cd_vert_node_offset = bvh->cd_vert_node_offset;
- const int cd_face_node_offset = bvh->cd_face_node_offset;
+ const int cd_vert_node_offset = pbvh->cd_vert_node_offset;
+ const int cd_face_node_offset = pbvh->cd_face_node_offset;
bool has_visible = false;
@@ -1876,27 +1879,27 @@ static void pbvh_bmesh_create_nodes_fast_recursive(
/***************************** Public API *****************************/
/* Build a PBVH from a BMesh */
-void BKE_pbvh_build_bmesh(PBVH *bvh,
+void BKE_pbvh_build_bmesh(PBVH *pbvh,
BMesh *bm,
bool smooth_shading,
BMLog *log,
const int cd_vert_node_offset,
const int cd_face_node_offset)
{
- bvh->cd_vert_node_offset = cd_vert_node_offset;
- bvh->cd_face_node_offset = cd_face_node_offset;
- bvh->bm = bm;
+ pbvh->cd_vert_node_offset = cd_vert_node_offset;
+ pbvh->cd_face_node_offset = cd_face_node_offset;
+ pbvh->bm = bm;
- BKE_pbvh_bmesh_detail_size_set(bvh, 0.75);
+ BKE_pbvh_bmesh_detail_size_set(pbvh, 0.75);
- bvh->type = PBVH_BMESH;
- bvh->bm_log = log;
+ pbvh->type = PBVH_BMESH;
+ pbvh->bm_log = log;
/* TODO: choose leaf limit better */
- bvh->leaf_limit = 100;
+ pbvh->leaf_limit = 100;
if (smooth_shading) {
- bvh->flags |= PBVH_DYNTOPO_SMOOTH_SHADING;
+ pbvh->flags |= PBVH_DYNTOPO_SMOOTH_SHADING;
}
/* bounding box array of all faces, no need to recalculate every time */
@@ -1936,17 +1939,17 @@ void BKE_pbvh_build_bmesh(PBVH *bvh,
rootnode.totface = bm->totface;
/* start recursion, assign faces to nodes accordingly */
- pbvh_bmesh_node_limit_ensure_fast(bvh, nodeinfo, bbc_array, &rootnode, arena);
+ pbvh_bmesh_node_limit_ensure_fast(pbvh, nodeinfo, bbc_array, &rootnode, arena);
/* We now have all faces assigned to a node,
* next we need to assign those to the gsets of the nodes. */
/* Start with all faces in the root node */
- bvh->nodes = MEM_callocN(sizeof(PBVHNode), "PBVHNode");
- bvh->totnode = 1;
+ pbvh->nodes = MEM_callocN(sizeof(PBVHNode), "PBVHNode");
+ pbvh->totnode = 1;
/* take root node and visit and populate children recursively */
- pbvh_bmesh_create_nodes_fast_recursive(bvh, nodeinfo, bbc_array, &rootnode, 0);
+ pbvh_bmesh_create_nodes_fast_recursive(pbvh, nodeinfo, bbc_array, &rootnode, 0);
BLI_memarena_free(arena);
MEM_freeN(bbc_array);
@@ -1954,7 +1957,7 @@ void BKE_pbvh_build_bmesh(PBVH *bvh,
}
/* Collapse short edges, subdivide long edges */
-bool BKE_pbvh_bmesh_update_topology(PBVH *bvh,
+bool BKE_pbvh_bmesh_update_topology(PBVH *pbvh,
PBVHTopologyUpdateMode mode,
const float center[3],
const float view_normal[3],
@@ -1965,9 +1968,9 @@ bool BKE_pbvh_bmesh_update_topology(PBVH *bvh,
/* 2 is enough for edge faces - manifold edge */
BLI_buffer_declare_static(BMLoop *, edge_loops, BLI_BUFFER_NOP, 2);
BLI_buffer_declare_static(BMFace *, deleted_faces, BLI_BUFFER_NOP, 32);
- const int cd_vert_mask_offset = CustomData_get_offset(&bvh->bm->vdata, CD_PAINT_MASK);
- const int cd_vert_node_offset = bvh->cd_vert_node_offset;
- const int cd_face_node_offset = bvh->cd_face_node_offset;
+ const int cd_vert_mask_offset = CustomData_get_offset(&pbvh->bm->vdata, CD_PAINT_MASK);
+ const int cd_vert_node_offset = pbvh->cd_vert_node_offset;
+ const int cd_face_node_offset = pbvh->cd_face_node_offset;
bool modified = false;
@@ -1981,15 +1984,15 @@ bool BKE_pbvh_bmesh_update_topology(PBVH *bvh,
EdgeQueueContext eq_ctx = {
&q,
queue_pool,
- bvh->bm,
+ pbvh->bm,
cd_vert_mask_offset,
cd_vert_node_offset,
cd_face_node_offset,
};
short_edge_queue_create(
- &eq_ctx, bvh, center, view_normal, radius, use_frontface, use_projected);
- modified |= pbvh_bmesh_collapse_short_edges(&eq_ctx, bvh, &deleted_faces);
+ &eq_ctx, pbvh, center, view_normal, radius, use_frontface, use_projected);
+ modified |= pbvh_bmesh_collapse_short_edges(&eq_ctx, pbvh, &deleted_faces);
BLI_heapsimple_free(q.heap, NULL);
BLI_mempool_destroy(queue_pool);
}
@@ -2000,22 +2003,22 @@ bool BKE_pbvh_bmesh_update_topology(PBVH *bvh,
EdgeQueueContext eq_ctx = {
&q,
queue_pool,
- bvh->bm,
+ pbvh->bm,
cd_vert_mask_offset,
cd_vert_node_offset,
cd_face_node_offset,
};
long_edge_queue_create(
- &eq_ctx, bvh, center, view_normal, radius, use_frontface, use_projected);
- modified |= pbvh_bmesh_subdivide_long_edges(&eq_ctx, bvh, &edge_loops);
+ &eq_ctx, pbvh, center, view_normal, radius, use_frontface, use_projected);
+ modified |= pbvh_bmesh_subdivide_long_edges(&eq_ctx, pbvh, &edge_loops);
BLI_heapsimple_free(q.heap, NULL);
BLI_mempool_destroy(queue_pool);
}
/* Unmark nodes */
- for (int n = 0; n < bvh->totnode; n++) {
- PBVHNode *node = &bvh->nodes[n];
+ for (int n = 0; n < pbvh->totnode; n++) {
+ PBVHNode *node = &pbvh->nodes[n];
if (node->flag & PBVH_Leaf && node->flag & PBVH_UpdateTopology) {
node->flag &= ~PBVH_UpdateTopology;
@@ -2025,7 +2028,7 @@ bool BKE_pbvh_bmesh_update_topology(PBVH *bvh,
BLI_buffer_free(&deleted_faces);
#ifdef USE_VERIFY
- pbvh_bmesh_verify(bvh);
+ pbvh_bmesh_verify(pbvh);
#endif
return modified;
@@ -2092,25 +2095,25 @@ void BKE_pbvh_bmesh_node_save_orig(BMesh *bm, PBVHNode *node)
node->bm_tot_ortri = i;
}
-void BKE_pbvh_bmesh_after_stroke(PBVH *bvh)
+void BKE_pbvh_bmesh_after_stroke(PBVH *pbvh)
{
- for (int i = 0; i < bvh->totnode; i++) {
- PBVHNode *n = &bvh->nodes[i];
+ for (int i = 0; i < pbvh->totnode; i++) {
+ PBVHNode *n = &pbvh->nodes[i];
if (n->flag & PBVH_Leaf) {
/* Free orco/ortri data */
pbvh_bmesh_node_drop_orig(n);
/* Recursively split nodes that have gotten too many
* elements */
- pbvh_bmesh_node_limit_ensure(bvh, i);
+ pbvh_bmesh_node_limit_ensure(pbvh, i);
}
}
}
-void BKE_pbvh_bmesh_detail_size_set(PBVH *bvh, float detail_size)
+void BKE_pbvh_bmesh_detail_size_set(PBVH *pbvh, float detail_size)
{
- bvh->bm_max_edge_len = detail_size;
- bvh->bm_min_edge_len = bvh->bm_max_edge_len * 0.4f;
+ pbvh->bm_max_edge_len = detail_size;
+ pbvh->bm_min_edge_len = pbvh->bm_max_edge_len * 0.4f;
}
void BKE_pbvh_node_mark_topology_update(PBVHNode *node)
@@ -2137,25 +2140,25 @@ struct GSet *BKE_pbvh_bmesh_node_faces(PBVHNode *node)
#if 0
-static void pbvh_bmesh_print(PBVH *bvh)
+static void pbvh_bmesh_print(PBVH *pbvh)
{
- fprintf(stderr, "\npbvh=%p\n", bvh);
+ fprintf(stderr, "\npbvh=%p\n", pbvh);
fprintf(stderr, "bm_face_to_node:\n");
BMIter iter;
BMFace *f;
- BM_ITER_MESH (f, &iter, bvh->bm, BM_FACES_OF_MESH) {
- fprintf(stderr, " %d -> %d\n", BM_elem_index_get(f), pbvh_bmesh_node_index_from_face(bvh, f));
+ BM_ITER_MESH (f, &iter, pbvh->bm, BM_FACES_OF_MESH) {
+ fprintf(stderr, " %d -> %d\n", BM_elem_index_get(f), pbvh_bmesh_node_index_from_face(pbvh, f));
}
fprintf(stderr, "bm_vert_to_node:\n");
BMVert *v;
- BM_ITER_MESH (v, &iter, bvh->bm, BM_FACES_OF_MESH) {
- fprintf(stderr, " %d -> %d\n", BM_elem_index_get(v), pbvh_bmesh_node_index_from_vert(bvh, v));
+ BM_ITER_MESH (v, &iter, pbvh->bm, BM_FACES_OF_MESH) {
+ fprintf(stderr, " %d -> %d\n", BM_elem_index_get(v), pbvh_bmesh_node_index_from_vert(pbvh, v));
}
- for (int n = 0; n < bvh->totnode; n++) {
- PBVHNode *node = &bvh->nodes[n];
+ for (int n = 0; n < pbvh->totnode; n++) {
+ PBVHNode *node = &pbvh->nodes[n];
if (!(node->flag & PBVH_Leaf)) {
continue;
}
@@ -2186,25 +2189,25 @@ static void print_flag_factors(int flag)
#ifdef USE_VERIFY
-static void pbvh_bmesh_verify(PBVH *bvh)
+static void pbvh_bmesh_verify(PBVH *pbvh)
{
/* build list of faces & verts to lookup */
- GSet *faces_all = BLI_gset_ptr_new_ex(__func__, bvh->bm->totface);
+ GSet *faces_all = BLI_gset_ptr_new_ex(__func__, pbvh->bm->totface);
BMIter iter;
{
BMFace *f;
- BM_ITER_MESH (f, &iter, bvh->bm, BM_FACES_OF_MESH) {
- BLI_assert(BM_ELEM_CD_GET_INT(f, bvh->cd_face_node_offset) != DYNTOPO_NODE_NONE);
+ BM_ITER_MESH (f, &iter, pbvh->bm, BM_FACES_OF_MESH) {
+ BLI_assert(BM_ELEM_CD_GET_INT(f, pbvh->cd_face_node_offset) != DYNTOPO_NODE_NONE);
BLI_gset_insert(faces_all, f);
}
}
- GSet *verts_all = BLI_gset_ptr_new_ex(__func__, bvh->bm->totvert);
+ GSet *verts_all = BLI_gset_ptr_new_ex(__func__, pbvh->bm->totvert);
{
BMVert *v;
- BM_ITER_MESH (v, &iter, bvh->bm, BM_VERTS_OF_MESH) {
- if (BM_ELEM_CD_GET_INT(v, bvh->cd_vert_node_offset) != DYNTOPO_NODE_NONE) {
+ BM_ITER_MESH (v, &iter, pbvh->bm, BM_VERTS_OF_MESH) {
+ if (BM_ELEM_CD_GET_INT(v, pbvh->cd_vert_node_offset) != DYNTOPO_NODE_NONE) {
BLI_gset_insert(verts_all, v);
}
}
@@ -2213,8 +2216,8 @@ static void pbvh_bmesh_verify(PBVH *bvh)
/* Check vert/face counts */
{
int totface = 0, totvert = 0;
- for (int i = 0; i < bvh->totnode; i++) {
- PBVHNode *n = &bvh->nodes[i];
+ for (int i = 0; i < pbvh->totnode; i++) {
+ PBVHNode *n = &pbvh->nodes[i];
totface += n->bm_faces ? BLI_gset_len(n->bm_faces) : 0;
totvert += n->bm_unique_verts ? BLI_gset_len(n->bm_unique_verts) : 0;
}
@@ -2225,10 +2228,10 @@ static void pbvh_bmesh_verify(PBVH *bvh)
{
BMFace *f;
- BM_ITER_MESH (f, &iter, bvh->bm, BM_FACES_OF_MESH) {
+ BM_ITER_MESH (f, &iter, pbvh->bm, BM_FACES_OF_MESH) {
BMIter bm_iter;
BMVert *v;
- PBVHNode *n = pbvh_bmesh_node_lookup(bvh, f);
+ PBVHNode *n = pbvh_bmesh_node_lookup(pbvh, f);
/* Check that the face's node is a leaf */
BLI_assert(n->flag & PBVH_Leaf);
@@ -2244,7 +2247,7 @@ static void pbvh_bmesh_verify(PBVH *bvh)
BLI_assert(BLI_gset_haskey(n->bm_unique_verts, v) ^ BLI_gset_haskey(n->bm_other_verts, v));
/* Check that the vertex has a node owner */
- nv = pbvh_bmesh_node_lookup(bvh, v);
+ nv = pbvh_bmesh_node_lookup(pbvh, v);
/* Check that the vertex's node knows it owns the vert */
BLI_assert(BLI_gset_haskey(nv->bm_unique_verts, v));
@@ -2258,13 +2261,13 @@ static void pbvh_bmesh_verify(PBVH *bvh)
/* Check verts */
{
BMVert *v;
- BM_ITER_MESH (v, &iter, bvh->bm, BM_VERTS_OF_MESH) {
+ BM_ITER_MESH (v, &iter, pbvh->bm, BM_VERTS_OF_MESH) {
/* vertex isn't tracked */
- if (BM_ELEM_CD_GET_INT(v, bvh->cd_vert_node_offset) == DYNTOPO_NODE_NONE) {
+ if (BM_ELEM_CD_GET_INT(v, pbvh->cd_vert_node_offset) == DYNTOPO_NODE_NONE) {
continue;
}
- PBVHNode *n = pbvh_bmesh_node_lookup(bvh, v);
+ PBVHNode *n = pbvh_bmesh_node_lookup(pbvh, v);
/* Check that the vert's node is a leaf */
BLI_assert(n->flag & PBVH_Leaf);
@@ -2281,7 +2284,7 @@ static void pbvh_bmesh_verify(PBVH *bvh)
BMIter bm_iter;
BMFace *f = NULL;
BM_ITER_ELEM (f, &bm_iter, v, BM_FACES_OF_VERT) {
- if (pbvh_bmesh_node_lookup(bvh, f) == n) {
+ if (pbvh_bmesh_node_lookup(pbvh, f) == n) {
found = true;
break;
}
@@ -2291,8 +2294,8 @@ static void pbvh_bmesh_verify(PBVH *bvh)
# if 1
/* total freak stuff, check if node exists somewhere else */
/* Slow */
- for (int i = 0; i < bvh->totnode; i++) {
- PBVHNode *n_other = &bvh->nodes[i];
+ for (int i = 0; i < pbvh->totnode; i++) {
+ PBVHNode *n_other = &pbvh->nodes[i];
if ((n != n_other) && (n_other->bm_unique_verts)) {
BLI_assert(!BLI_gset_haskey(n_other->bm_unique_verts, v));
}
@@ -2304,10 +2307,10 @@ static void pbvh_bmesh_verify(PBVH *bvh)
# if 0
/* check that every vert belongs somewhere */
/* Slow */
- BM_ITER_MESH (vi, &iter, bvh->bm, BM_VERTS_OF_MESH) {
+ BM_ITER_MESH (vi, &iter, pbvh->bm, BM_VERTS_OF_MESH) {
bool has_unique = false;
- for (int i = 0; i < bvh->totnode; i++) {
- PBVHNode *n = &bvh->nodes[i];
+ for (int i = 0; i < pbvh->totnode; i++) {
+ PBVHNode *n = &pbvh->nodes[i];
if ((n->bm_unique_verts != NULL) && BLI_gset_haskey(n->bm_unique_verts, vi)) {
has_unique = true;
}
@@ -2317,25 +2320,25 @@ static void pbvh_bmesh_verify(PBVH *bvh)
}
/* if totvert differs from number of verts inside the hash. hash-totvert is checked above */
- BLI_assert(vert_count == bvh->bm->totvert);
+ BLI_assert(vert_count == pbvh->bm->totvert);
# endif
/* Check that node elements are recorded in the top level */
- for (int i = 0; i < bvh->totnode; i++) {
- PBVHNode *n = &bvh->nodes[i];
+ for (int i = 0; i < pbvh->totnode; i++) {
+ PBVHNode *n = &pbvh->nodes[i];
if (n->flag & PBVH_Leaf) {
GSetIterator gs_iter;
GSET_ITER (gs_iter, n->bm_faces) {
BMFace *f = BLI_gsetIterator_getKey(&gs_iter);
- PBVHNode *n_other = pbvh_bmesh_node_lookup(bvh, f);
+ PBVHNode *n_other = pbvh_bmesh_node_lookup(pbvh, f);
BLI_assert(n == n_other);
BLI_assert(BLI_gset_haskey(faces_all, f));
}
GSET_ITER (gs_iter, n->bm_unique_verts) {
BMVert *v = BLI_gsetIterator_getKey(&gs_iter);
- PBVHNode *n_other = pbvh_bmesh_node_lookup(bvh, v);
+ PBVHNode *n_other = pbvh_bmesh_node_lookup(pbvh, v);
BLI_assert(!BLI_gset_haskey(n->bm_other_verts, v));
BLI_assert(n == n_other);
BLI_assert(BLI_gset_haskey(verts_all, v));
diff --git a/source/blender/blenkernel/intern/pbvh_intern.h b/source/blender/blenkernel/intern/pbvh_intern.h
index af92f11e219..7397f939894 100644
--- a/source/blender/blenkernel/intern/pbvh_intern.h
+++ b/source/blender/blenkernel/intern/pbvh_intern.h
@@ -138,6 +138,7 @@ struct PBVH {
int face_sets_color_seed;
int face_sets_color_default;
+ int *face_sets;
/* Grid Data */
CCGKey gridkey;
@@ -159,6 +160,7 @@ struct PBVH {
bool deformed;
bool show_mask;
bool show_face_sets;
+ bool respect_hide;
/* Dynamic topology */
BMesh *bm;
@@ -167,7 +169,11 @@ struct PBVH {
int cd_vert_node_offset;
int cd_face_node_offset;
+ float planes[6][4];
+ int num_planes;
+
struct BMLog *bm_log;
+ struct SubdivCCG *subdiv_ccg;
};
/* pbvh.c */
diff --git a/source/blender/blenkernel/intern/pointcache.c b/source/blender/blenkernel/intern/pointcache.c
index 76088867997..5ee61667eca 100644
--- a/source/blender/blenkernel/intern/pointcache.c
+++ b/source/blender/blenkernel/intern/pointcache.c
@@ -51,7 +51,6 @@
#include "PIL_time.h"
-#include "BKE_anim.h"
#include "BKE_appdir.h"
#include "BKE_cloth.h"
#include "BKE_collection.h"
@@ -584,7 +583,7 @@ static int ptcache_cloth_totpoint(void *cloth_v, int UNUSED(cfra))
static void ptcache_cloth_error(void *cloth_v, const char *message)
{
ClothModifierData *clmd = cloth_v;
- modifier_setError(&clmd->modifier, "%s", message);
+ BKE_modifier_set_error(&clmd->modifier, "%s", message);
}
#ifdef WITH_SMOKE
@@ -605,7 +604,7 @@ static int ptcache_smoke_totpoint(void *smoke_v, int UNUSED(cfra))
static void ptcache_smoke_error(void *smoke_v, const char *message)
{
FluidModifierData *mmd = (FluidModifierData *)smoke_v;
- modifier_setError(&mmd->modifier, "%s", message);
+ BKE_modifier_set_error(&mmd->modifier, "%s", message);
}
# define SMOKE_CACHE_VERSION "1.04"
@@ -1840,7 +1839,7 @@ PTCacheID BKE_ptcache_id_find(Object *ob, Scene *scene, PointCache *cache)
ListBase pidlist;
BKE_ptcache_ids_from_object(&pidlist, ob, scene, MAX_DUPLI_RECUR);
- for (PTCacheID *pid = pidlist.first; pid; pid = pid->next) {
+ LISTBASE_FOREACH (PTCacheID *, pid, &pidlist) {
if (pid->cache == cache) {
result = *pid;
break;
@@ -2067,7 +2066,7 @@ static int ptcache_path(PTCacheID *pid, char *filename)
BLI_path_abs(filename, blendfilename);
}
- return BLI_add_slash(filename); /* new strlen() */
+ return BLI_path_slash_ensure(filename); /* new strlen() */
}
else if (G.relbase_valid || lib) {
char file[MAX_PTCACHE_PATH]; /* we don't want the dir, only the file */
@@ -2084,14 +2083,14 @@ static int ptcache_path(PTCacheID *pid, char *filename)
BLI_snprintf(filename, MAX_PTCACHE_PATH, "//" PTCACHE_PATH "%s", file);
BLI_path_abs(filename, blendfilename);
- return BLI_add_slash(filename); /* new strlen() */
+ return BLI_path_slash_ensure(filename); /* new strlen() */
}
/* use the temp path. this is weak but better then not using point cache at all */
/* temporary directory is assumed to exist and ALWAYS has a trailing slash */
BLI_snprintf(filename, MAX_PTCACHE_PATH, "%s" PTCACHE_PATH, BKE_tempdir_session());
- return BLI_add_slash(filename); /* new strlen() */
+ return BLI_path_slash_ensure(filename); /* new strlen() */
}
static int ptcache_filename(PTCacheID *pid, char *filename, int cfra, short do_path, short do_ext)
diff --git a/source/blender/blenkernel/intern/pointcloud.c b/source/blender/blenkernel/intern/pointcloud.c
index 3e4cc5c6185..e03888dcad7 100644
--- a/source/blender/blenkernel/intern/pointcloud.c
+++ b/source/blender/blenkernel/intern/pointcloud.c
@@ -21,6 +21,7 @@
#include "MEM_guardedalloc.h"
#include "DNA_defaults.h"
+#include "DNA_material_types.h"
#include "DNA_object_types.h"
#include "DNA_pointcloud_types.h"
@@ -30,7 +31,7 @@
#include "BLI_string.h"
#include "BLI_utildefines.h"
-#include "BKE_animsys.h"
+#include "BKE_anim_data.h"
#include "BKE_customdata.h"
#include "BKE_global.h"
#include "BKE_idtype.h"
@@ -48,23 +49,7 @@
/* PointCloud datablock */
-static void pointcloud_random(PointCloud *pointcloud)
-{
- pointcloud->totpoint = 400;
- CustomData_realloc(&pointcloud->pdata, pointcloud->totpoint);
- BKE_pointcloud_update_customdata_pointers(pointcloud);
-
- RNG *rng = BLI_rng_new(0);
-
- for (int i = 0; i < pointcloud->totpoint; i++) {
- pointcloud->co[i][0] = 2.0f * BLI_rng_get_float(rng) - 1.0f;
- pointcloud->co[i][1] = 2.0f * BLI_rng_get_float(rng) - 1.0f;
- pointcloud->co[i][2] = 2.0f * BLI_rng_get_float(rng) - 1.0f;
- pointcloud->radius[i] = 0.05f * BLI_rng_get_float(rng);
- }
-
- BLI_rng_free(rng);
-}
+static void pointcloud_random(PointCloud *pointcloud);
static void pointcloud_init_data(ID *id)
{
@@ -81,15 +66,6 @@ static void pointcloud_init_data(ID *id)
pointcloud_random(pointcloud);
}
-void *BKE_pointcloud_add(Main *bmain, const char *name)
-{
- PointCloud *pointcloud = BKE_libblock_alloc(bmain, ID_PT, name, 0);
-
- pointcloud_init_data(&pointcloud->id);
-
- return pointcloud;
-}
-
static void pointcloud_copy_data(Main *UNUSED(bmain), ID *id_dst, const ID *id_src, const int flag)
{
PointCloud *pointcloud_dst = (PointCloud *)id_dst;
@@ -105,18 +81,6 @@ static void pointcloud_copy_data(Main *UNUSED(bmain), ID *id_dst, const ID *id_s
BKE_pointcloud_update_customdata_pointers(pointcloud_dst);
}
-PointCloud *BKE_pointcloud_copy(Main *bmain, const PointCloud *pointcloud)
-{
- PointCloud *pointcloud_copy;
- BKE_id_copy(bmain, &pointcloud->id, (ID **)&pointcloud_copy);
- return pointcloud_copy;
-}
-
-static void pointcloud_make_local(Main *bmain, ID *id, const int flags)
-{
- BKE_lib_id_make_local_generic(bmain, id, flags);
-}
-
static void pointcloud_free_data(ID *id)
{
PointCloud *pointcloud = (PointCloud *)id;
@@ -126,6 +90,14 @@ static void pointcloud_free_data(ID *id)
MEM_SAFE_FREE(pointcloud->mat);
}
+static void pointcloud_foreach_id(ID *id, LibraryForeachIDData *data)
+{
+ PointCloud *pointcloud = (PointCloud *)id;
+ for (int i = 0; i < pointcloud->totcol; i++) {
+ BKE_LIB_FOREACHID_PROCESS(data, pointcloud->mat[i], IDWALK_CB_USER);
+ }
+}
+
IDTypeInfo IDType_ID_PT = {
.id_code = ID_PT,
.id_filter = FILTER_ID_PT,
@@ -139,9 +111,44 @@ IDTypeInfo IDType_ID_PT = {
.init_data = pointcloud_init_data,
.copy_data = pointcloud_copy_data,
.free_data = pointcloud_free_data,
- .make_local = pointcloud_make_local,
+ .make_local = NULL,
+ .foreach_id = pointcloud_foreach_id,
};
+static void pointcloud_random(PointCloud *pointcloud)
+{
+ pointcloud->totpoint = 400;
+ CustomData_realloc(&pointcloud->pdata, pointcloud->totpoint);
+ BKE_pointcloud_update_customdata_pointers(pointcloud);
+
+ RNG *rng = BLI_rng_new(0);
+
+ for (int i = 0; i < pointcloud->totpoint; i++) {
+ pointcloud->co[i][0] = 2.0f * BLI_rng_get_float(rng) - 1.0f;
+ pointcloud->co[i][1] = 2.0f * BLI_rng_get_float(rng) - 1.0f;
+ pointcloud->co[i][2] = 2.0f * BLI_rng_get_float(rng) - 1.0f;
+ pointcloud->radius[i] = 0.05f * BLI_rng_get_float(rng);
+ }
+
+ BLI_rng_free(rng);
+}
+
+void *BKE_pointcloud_add(Main *bmain, const char *name)
+{
+ PointCloud *pointcloud = BKE_libblock_alloc(bmain, ID_PT, name, 0);
+
+ pointcloud_init_data(&pointcloud->id);
+
+ return pointcloud;
+}
+
+PointCloud *BKE_pointcloud_copy(Main *bmain, const PointCloud *pointcloud)
+{
+ PointCloud *pointcloud_copy;
+ BKE_id_copy(bmain, &pointcloud->id, (ID **)&pointcloud_copy);
+ return pointcloud_copy;
+}
+
BoundBox *BKE_pointcloud_boundbox_get(Object *ob)
{
BLI_assert(ob->type == OB_POINTCLOUD);
@@ -184,7 +191,7 @@ void BKE_pointcloud_update_customdata_pointers(PointCloud *pointcloud)
PointCloud *BKE_pointcloud_new_for_eval(const PointCloud *pointcloud_src, int totpoint)
{
- PointCloud *pointcloud_dst = BKE_id_new_nomain(ID_HA, NULL);
+ PointCloud *pointcloud_dst = BKE_id_new_nomain(ID_PT, NULL);
STRNCPY(pointcloud_dst->id.name, pointcloud_src->id.name);
pointcloud_dst->mat = MEM_dupallocN(pointcloud_src->mat);
@@ -211,12 +218,65 @@ PointCloud *BKE_pointcloud_copy_for_eval(struct PointCloud *pointcloud_src, bool
return result;
}
-static PointCloud *pointcloud_evaluate_modifiers(struct Depsgraph *UNUSED(depsgraph),
- struct Scene *UNUSED(scene),
- Object *UNUSED(object),
+static PointCloud *pointcloud_evaluate_modifiers(struct Depsgraph *depsgraph,
+ struct Scene *scene,
+ Object *object,
PointCloud *pointcloud_input)
{
- return pointcloud_input;
+ PointCloud *pointcloud = pointcloud_input;
+
+ /* Modifier evaluation modes. */
+ const bool use_render = (DEG_get_mode(depsgraph) == DAG_EVAL_RENDER);
+ const int required_mode = use_render ? eModifierMode_Render : eModifierMode_Realtime;
+ ModifierApplyFlag apply_flag = use_render ? MOD_APPLY_RENDER : MOD_APPLY_USECACHE;
+ const ModifierEvalContext mectx = {depsgraph, object, apply_flag};
+
+ /* Get effective list of modifiers to execute. Some effects like shape keys
+ * are added as virtual modifiers before the user created modifiers. */
+ VirtualModifierData virtualModifierData;
+ ModifierData *md = BKE_modifiers_get_virtual_modifierlist(object, &virtualModifierData);
+
+ /* Evaluate modifiers. */
+ for (; md; md = md->next) {
+ const ModifierTypeInfo *mti = BKE_modifier_get_info(md->type);
+
+ if (!BKE_modifier_is_enabled(scene, md, required_mode)) {
+ continue;
+ }
+
+ if ((mti->type == eModifierTypeType_OnlyDeform) &&
+ (mti->flags & eModifierTypeFlag_AcceptsVertexCosOnly)) {
+ /* Ensure we are not modifying the input. */
+ if (pointcloud == pointcloud_input) {
+ pointcloud = BKE_pointcloud_copy_for_eval(pointcloud, true);
+ }
+
+ /* Ensure we are not overwriting referenced data. */
+ CustomData_duplicate_referenced_layer(&pointcloud->pdata, CD_LOCATION, pointcloud->totpoint);
+ BKE_pointcloud_update_customdata_pointers(pointcloud);
+
+ /* Created deformed coordinates array on demand. */
+ mti->deformVerts(md, &mectx, NULL, pointcloud->co, pointcloud->totpoint);
+ }
+ else if (mti->modifyPointCloud) {
+ /* Ensure we are not modifying the input. */
+ if (pointcloud == pointcloud_input) {
+ pointcloud = BKE_pointcloud_copy_for_eval(pointcloud, true);
+ }
+
+ PointCloud *pointcloud_next = mti->modifyPointCloud(md, &mectx, pointcloud);
+
+ if (pointcloud_next && pointcloud_next != pointcloud) {
+ /* If the modifier returned a new pointcloud, release the old one. */
+ if (pointcloud != pointcloud_input) {
+ BKE_id_free(NULL, pointcloud);
+ }
+ pointcloud = pointcloud_next;
+ }
+ }
+ }
+
+ return pointcloud;
}
void BKE_pointcloud_data_update(struct Depsgraph *depsgraph, struct Scene *scene, Object *object)
diff --git a/source/blender/blenkernel/intern/rigidbody.c b/source/blender/blenkernel/intern/rigidbody.c
index f08de835a9d..c9911d2cf85 100644
--- a/source/blender/blenkernel/intern/rigidbody.c
+++ b/source/blender/blenkernel/intern/rigidbody.c
@@ -1027,6 +1027,11 @@ static void rigidbody_validate_sim_constraint(RigidBodyWorld *rbw, Object *ob, b
return;
}
+ /* When 'rbc->type' is unknown. */
+ if (rbc->physics_constraint == NULL) {
+ return;
+ }
+
RB_constraint_set_enabled(rbc->physics_constraint, rbc->flag & RBC_FLAG_ENABLED);
if (rbc->flag & RBC_FLAG_USE_BREAKING) {
@@ -2111,6 +2116,7 @@ void BKE_rigidbody_ensure_local_object(Main *bmain, Object *ob)
bool BKE_rigidbody_add_object(Main *bmain, Scene *scene, Object *ob, int type, ReportList *reports)
{
+ BKE_report(reports, RPT_ERROR, "Compiled without Bullet physics engine");
return false;
}
diff --git a/source/blender/blenkernel/intern/scene.c b/source/blender/blenkernel/intern/scene.c
index b12402d74fc..aa2a1b14841 100644
--- a/source/blender/blenkernel/intern/scene.c
+++ b/source/blender/blenkernel/intern/scene.c
@@ -33,6 +33,7 @@
#include "DNA_defaults.h"
#include "DNA_gpencil_types.h"
#include "DNA_linestyle_types.h"
+#include "DNA_mask_types.h"
#include "DNA_mesh_types.h"
#include "DNA_node_types.h"
#include "DNA_object_types.h"
@@ -42,6 +43,7 @@
#include "DNA_sequence_types.h"
#include "DNA_sound_types.h"
#include "DNA_space_types.h"
+#include "DNA_text_types.h"
#include "DNA_view3d_types.h"
#include "DNA_windowmanager_types.h"
#include "DNA_workspace_types.h"
@@ -59,13 +61,14 @@
#include "BLT_translation.h"
#include "BKE_action.h"
-#include "BKE_anim.h"
+#include "BKE_anim_data.h"
#include "BKE_animsys.h"
#include "BKE_armature.h"
#include "BKE_cachefile.h"
#include "BKE_collection.h"
#include "BKE_colortools.h"
#include "BKE_curveprofile.h"
+#include "BKE_duplilist.h"
#include "BKE_editmesh.h"
#include "BKE_fcurve.h"
#include "BKE_freestyle.h"
@@ -76,6 +79,7 @@
#include "BKE_image.h"
#include "BKE_layer.h"
#include "BKE_lib_id.h"
+#include "BKE_lib_query.h"
#include "BKE_lib_remap.h"
#include "BKE_linestyle.h"
#include "BKE_main.h"
@@ -154,6 +158,9 @@ static void scene_init_data(ID *id)
scene->unit.mass_unit = (uchar)bUnit_GetBaseUnitOfType(USER_UNIT_METRIC, B_UNIT_MASS);
scene->unit.time_unit = (uchar)bUnit_GetBaseUnitOfType(USER_UNIT_METRIC, B_UNIT_TIME);
+ /* Anti-Aliasing threshold. */
+ scene->grease_pencil_settings.smaa_threshold = 1.0f;
+
{
ParticleEditSettings *pset;
pset = &scene->toolsettings->particle;
@@ -339,12 +346,17 @@ static void scene_free_data(ID *id)
/* is no lib link block, but scene extension */
if (scene->nodetree) {
- ntreeFreeNestedTree(scene->nodetree);
+ ntreeFreeEmbeddedTree(scene->nodetree);
MEM_freeN(scene->nodetree);
scene->nodetree = NULL;
}
if (scene->rigidbody_world) {
+ /* Prevent rigidbody freeing code to follow other IDs pointers, this should never be allowed
+ * nor necessary from here, and with new undo code, those pointers may be fully invalid or
+ * worse, pointing to data actually belonging to new BMain! */
+ scene->rigidbody_world->constraints = NULL;
+ scene->rigidbody_world->group = NULL;
BKE_rigidbody_free_world(scene);
}
@@ -409,6 +421,155 @@ static void scene_free_data(ID *id)
BLI_assert(scene->layer_properties == NULL);
}
+static void library_foreach_rigidbodyworldSceneLooper(struct RigidBodyWorld *UNUSED(rbw),
+ ID **id_pointer,
+ void *user_data,
+ int cb_flag)
+{
+ LibraryForeachIDData *data = (LibraryForeachIDData *)user_data;
+ BKE_lib_query_foreachid_process(data, id_pointer, cb_flag);
+}
+
+static void library_foreach_paint(LibraryForeachIDData *data, Paint *paint)
+{
+ BKE_LIB_FOREACHID_PROCESS(data, paint->brush, IDWALK_CB_USER);
+ for (int i = 0; i < paint->tool_slots_len; i++) {
+ BKE_LIB_FOREACHID_PROCESS(data, paint->tool_slots[i].brush, IDWALK_CB_USER);
+ }
+ BKE_LIB_FOREACHID_PROCESS(data, paint->palette, IDWALK_CB_USER);
+}
+
+static void library_foreach_layer_collection(LibraryForeachIDData *data, ListBase *lb)
+{
+ LISTBASE_FOREACH (LayerCollection *, lc, lb) {
+ /* XXX This is very weak. The whole idea of keeping pointers to private IDs is very bad
+ * anyway... */
+ const int cb_flag = (lc->collection != NULL &&
+ (lc->collection->id.flag & LIB_EMBEDDED_DATA) != 0) ?
+ IDWALK_CB_EMBEDDED :
+ IDWALK_CB_NOP;
+ BKE_LIB_FOREACHID_PROCESS(data, lc->collection, cb_flag);
+ library_foreach_layer_collection(data, &lc->layer_collections);
+ }
+}
+
+static void scene_foreach_id(ID *id, LibraryForeachIDData *data)
+{
+ Scene *scene = (Scene *)id;
+
+ BKE_LIB_FOREACHID_PROCESS(data, scene->camera, IDWALK_CB_NOP);
+ BKE_LIB_FOREACHID_PROCESS(data, scene->world, IDWALK_CB_USER);
+ BKE_LIB_FOREACHID_PROCESS(data, scene->set, IDWALK_CB_NEVER_SELF);
+ BKE_LIB_FOREACHID_PROCESS(data, scene->clip, IDWALK_CB_USER);
+ BKE_LIB_FOREACHID_PROCESS(data, scene->gpd, IDWALK_CB_USER);
+ BKE_LIB_FOREACHID_PROCESS(data, scene->r.bake.cage_object, IDWALK_CB_NOP);
+ if (scene->nodetree) {
+ /* nodetree **are owned by IDs**, treat them as mere sub-data and not real ID! */
+ BKE_library_foreach_ID_embedded(data, (ID **)&scene->nodetree);
+ }
+ if (scene->ed) {
+ Sequence *seq;
+ SEQP_BEGIN (scene->ed, seq) {
+ BKE_LIB_FOREACHID_PROCESS(data, seq->scene, IDWALK_CB_NEVER_SELF);
+ BKE_LIB_FOREACHID_PROCESS(data, seq->scene_camera, IDWALK_CB_NOP);
+ BKE_LIB_FOREACHID_PROCESS(data, seq->clip, IDWALK_CB_USER);
+ BKE_LIB_FOREACHID_PROCESS(data, seq->mask, IDWALK_CB_USER);
+ BKE_LIB_FOREACHID_PROCESS(data, seq->sound, IDWALK_CB_USER);
+ IDP_foreach_property(
+ seq->prop, IDP_TYPE_FILTER_ID, BKE_lib_query_idpropertiesForeachIDLink_callback, data);
+ LISTBASE_FOREACH (SequenceModifierData *, smd, &seq->modifiers) {
+ BKE_LIB_FOREACHID_PROCESS(data, smd->mask_id, IDWALK_CB_USER);
+ }
+
+ if (seq->type == SEQ_TYPE_TEXT && seq->effectdata) {
+ TextVars *text_data = seq->effectdata;
+ BKE_LIB_FOREACHID_PROCESS(data, text_data->text_font, IDWALK_CB_USER);
+ }
+ }
+ SEQ_END;
+ }
+
+ /* This pointer can be NULL during old files reading, better be safe than sorry. */
+ if (scene->master_collection != NULL) {
+ BKE_library_foreach_ID_embedded(data, (ID **)&scene->master_collection);
+ }
+
+ LISTBASE_FOREACH (ViewLayer *, view_layer, &scene->view_layers) {
+ BKE_LIB_FOREACHID_PROCESS(data, view_layer->mat_override, IDWALK_CB_USER);
+
+ LISTBASE_FOREACH (Base *, base, &view_layer->object_bases) {
+ BKE_LIB_FOREACHID_PROCESS(data, base->object, IDWALK_CB_NOP);
+ }
+
+ library_foreach_layer_collection(data, &view_layer->layer_collections);
+
+ LISTBASE_FOREACH (FreestyleModuleConfig *, fmc, &view_layer->freestyle_config.modules) {
+ if (fmc->script) {
+ BKE_LIB_FOREACHID_PROCESS(data, fmc->script, IDWALK_CB_NOP);
+ }
+ }
+
+ LISTBASE_FOREACH (FreestyleLineSet *, fls, &view_layer->freestyle_config.linesets) {
+ if (fls->group) {
+ BKE_LIB_FOREACHID_PROCESS(data, fls->group, IDWALK_CB_USER);
+ }
+
+ if (fls->linestyle) {
+ BKE_LIB_FOREACHID_PROCESS(data, fls->linestyle, IDWALK_CB_USER);
+ }
+ }
+ }
+
+ LISTBASE_FOREACH (TimeMarker *, marker, &scene->markers) {
+ BKE_LIB_FOREACHID_PROCESS(data, marker->camera, IDWALK_CB_NOP);
+ }
+
+ ToolSettings *toolsett = scene->toolsettings;
+ if (toolsett) {
+ BKE_LIB_FOREACHID_PROCESS(data, toolsett->particle.scene, IDWALK_CB_NOP);
+ BKE_LIB_FOREACHID_PROCESS(data, toolsett->particle.object, IDWALK_CB_NOP);
+ BKE_LIB_FOREACHID_PROCESS(data, toolsett->particle.shape_object, IDWALK_CB_NOP);
+
+ library_foreach_paint(data, &toolsett->imapaint.paint);
+ BKE_LIB_FOREACHID_PROCESS(data, toolsett->imapaint.stencil, IDWALK_CB_USER);
+ BKE_LIB_FOREACHID_PROCESS(data, toolsett->imapaint.clone, IDWALK_CB_USER);
+ BKE_LIB_FOREACHID_PROCESS(data, toolsett->imapaint.canvas, IDWALK_CB_USER);
+
+ if (toolsett->vpaint) {
+ library_foreach_paint(data, &toolsett->vpaint->paint);
+ }
+ if (toolsett->wpaint) {
+ library_foreach_paint(data, &toolsett->wpaint->paint);
+ }
+ if (toolsett->sculpt) {
+ library_foreach_paint(data, &toolsett->sculpt->paint);
+ BKE_LIB_FOREACHID_PROCESS(data, toolsett->sculpt->gravity_object, IDWALK_CB_NOP);
+ }
+ if (toolsett->uvsculpt) {
+ library_foreach_paint(data, &toolsett->uvsculpt->paint);
+ }
+ if (toolsett->gp_paint) {
+ library_foreach_paint(data, &toolsett->gp_paint->paint);
+ }
+ if (toolsett->gp_vertexpaint) {
+ library_foreach_paint(data, &toolsett->gp_vertexpaint->paint);
+ }
+ if (toolsett->gp_sculptpaint) {
+ library_foreach_paint(data, &toolsett->gp_sculptpaint->paint);
+ }
+ if (toolsett->gp_weightpaint) {
+ library_foreach_paint(data, &toolsett->gp_weightpaint->paint);
+ }
+
+ BKE_LIB_FOREACHID_PROCESS(data, toolsett->gp_sculpt.guide.reference_object, IDWALK_CB_NOP);
+ }
+
+ if (scene->rigidbody_world) {
+ BKE_rigidbody_world_id_loop(
+ scene->rigidbody_world, library_foreach_rigidbodyworldSceneLooper, data);
+ }
+}
+
IDTypeInfo IDType_ID_SCE = {
.id_code = ID_SCE,
.id_filter = FILTER_ID_SCE,
@@ -425,6 +586,7 @@ IDTypeInfo IDType_ID_SCE = {
/* For now default `BKE_lib_id_make_local_generic()` should work, may need more work though to
* support all possible corner cases. */
.make_local = NULL,
+ .foreach_id = scene_foreach_id,
};
const char *RE_engine_id_BLENDER_EEVEE = "BLENDER_EEVEE";
@@ -459,7 +621,7 @@ static void remove_sequencer_fcurves(Scene *sce)
if ((fcu->rna_path) && strstr(fcu->rna_path, "sequences_all")) {
action_groups_remove_channel(adt->action, fcu);
- free_fcurve(fcu);
+ BKE_fcurve_free(fcu);
}
}
}
@@ -506,7 +668,6 @@ ToolSettings *BKE_toolsettings_copy(ToolSettings *toolsettings, const int flag)
}
BKE_paint_copy(&ts->imapaint.paint, &ts->imapaint.paint, flag);
- ts->imapaint.paintcursor = NULL;
ts->particle.paintcursor = NULL;
ts->particle.scene = NULL;
ts->particle.object = NULL;
@@ -668,10 +829,9 @@ Scene *BKE_scene_copy(Main *bmain, Scene *sce, int type)
if (type == SCE_COPY_FULL) {
/* Copy Freestyle LineStyle datablocks. */
- for (ViewLayer *view_layer_dst = sce_copy->view_layers.first; view_layer_dst;
- view_layer_dst = view_layer_dst->next) {
- for (FreestyleLineSet *lineset = view_layer_dst->freestyle_config.linesets.first; lineset;
- lineset = lineset->next) {
+ LISTBASE_FOREACH (ViewLayer *, view_layer_dst, &sce_copy->view_layers) {
+ LISTBASE_FOREACH (
+ FreestyleLineSet *, lineset, &view_layer_dst->freestyle_config.linesets) {
if (lineset->linestyle) {
id_us_min(&lineset->linestyle->id);
BKE_id_copy_ex(
@@ -731,8 +891,7 @@ Scene *BKE_scene_add(Main *bmain, const char *name)
*/
bool BKE_scene_object_find(Scene *scene, Object *ob)
{
- for (ViewLayer *view_layer = scene->view_layers.first; view_layer;
- view_layer = view_layer->next) {
+ LISTBASE_FOREACH (ViewLayer *, view_layer, &scene->view_layers) {
if (BLI_findptr(&view_layer->object_bases, ob, offsetof(Base, object))) {
return true;
}
@@ -742,9 +901,8 @@ bool BKE_scene_object_find(Scene *scene, Object *ob)
Object *BKE_scene_object_find_by_name(const Scene *scene, const char *name)
{
- for (ViewLayer *view_layer = scene->view_layers.first; view_layer;
- view_layer = view_layer->next) {
- for (Base *base = view_layer->object_bases.first; base; base = base->next) {
+ LISTBASE_FOREACH (ViewLayer *, view_layer, &scene->view_layers) {
+ LISTBASE_FOREACH (Base *, base, &view_layer->object_bases) {
if (STREQ(base->object->id.name + 2, name)) {
return base->object;
}
@@ -772,9 +930,8 @@ void BKE_scene_set_background(Main *bmain, Scene *scene)
}
/* copy layers and flags from bases to objects */
- for (ViewLayer *view_layer = scene->view_layers.first; view_layer;
- view_layer = view_layer->next) {
- for (Base *base = view_layer->object_bases.first; base; base = base->next) {
+ LISTBASE_FOREACH (ViewLayer *, view_layer, &scene->view_layers) {
+ LISTBASE_FOREACH (Base *, base, &view_layer->object_bases) {
ob = base->object;
/* collection patch... */
BKE_scene_object_base_flag_sync_from_base(base);
@@ -928,7 +1085,7 @@ int BKE_scene_base_iter_next(
Scene *BKE_scene_find_from_collection(const Main *bmain, const Collection *collection)
{
for (Scene *scene = bmain->scenes.first; scene; scene = scene->id.next) {
- for (ViewLayer *layer = scene->view_layers.first; layer; layer = layer->next) {
+ LISTBASE_FOREACH (ViewLayer *, layer, &scene->view_layers) {
if (BKE_view_layer_has_collection(layer, collection)) {
return scene;
}
@@ -954,7 +1111,7 @@ Object *BKE_scene_camera_switch_find(Scene *scene)
Object *camera = NULL;
Object *first_camera = NULL;
- for (TimeMarker *m = scene->markers.first; m; m = m->next) {
+ LISTBASE_FOREACH (TimeMarker *, m, &scene->markers) {
if (m->camera && (m->camera->restrictflag & OB_RESTRICT_RENDER) == 0) {
if ((m->frame <= cfra) && (m->frame > frame)) {
camera = m->camera;
@@ -1091,9 +1248,7 @@ bool BKE_scene_validate_setscene(Main *bmain, Scene *sce)
}
/**
- * This function is needed to cope with fractional frames - including two Blender rendering
- * features mblur (motion blur that renders 'subframes' and blurs them together),
- * and fields rendering.
+ * This function is needed to cope with fractional frames, needed for motion blur & physics.
*/
float BKE_scene_frame_get(const Scene *scene)
{
@@ -1170,34 +1325,6 @@ int BKE_scene_orientation_slot_get_index(const TransformOrientationSlot *orient_
/** \} */
-/* That's like really a bummer, because currently animation data for armatures
- * might want to use pose, and pose might be missing on the object.
- * This happens when changing visible layers, which leads to situations when
- * pose is missing or marked for recalc, animation will change it and then
- * object update will restore the pose.
- *
- * This could be solved by the new dependency graph, but for until then we'll
- * do an extra pass on the objects to ensure it's all fine.
- */
-#define POSE_ANIMATION_WORKAROUND
-
-#ifdef POSE_ANIMATION_WORKAROUND
-static void scene_armature_depsgraph_workaround(Main *bmain, Depsgraph *depsgraph)
-{
- Object *ob;
- if (BLI_listbase_is_empty(&bmain->armatures) || !DEG_id_type_updated(depsgraph, ID_OB)) {
- return;
- }
- for (ob = bmain->objects.first; ob; ob = ob->id.next) {
- if (ob->type == OB_ARMATURE && ob->adt) {
- if (ob->pose == NULL || (ob->pose->flag & POSE_RECALC)) {
- BKE_pose_rebuild(bmain, ob, ob->data, true);
- }
- }
- }
-}
-#endif
-
static bool check_rendered_viewport_visible(Main *bmain)
{
wmWindowManager *wm = bmain->wm.first;
@@ -1281,6 +1408,14 @@ void BKE_scene_update_sound(Depsgraph *depsgraph, Main *bmain)
BKE_sound_update_scene(depsgraph, scene);
}
+void BKE_scene_update_tag_audio_volume(Depsgraph *UNUSED(depsgraph), Scene *scene)
+{
+ BLI_assert(DEG_is_evaluated_id(&scene->id));
+ /* The volume is actually updated in BKE_scene_update_sound(), from either
+ * scene_graph_update_tagged() or from BKE_scene_graph_update_for_newframe(). */
+ scene->id.recalc |= ID_RECALC_AUDIO_VOLUME;
+}
+
/* TODO(sergey): This actually should become view_layer_graph or so.
* Same applies to update_for_newframe.
*
@@ -1374,9 +1509,6 @@ void BKE_scene_graph_update_for_newframe(Depsgraph *depsgraph, Main *bmain)
BKE_image_editors_update_frame(bmain, scene->r.cfra);
BKE_sound_set_cfra(scene->r.cfra);
DEG_graph_relations_update(depsgraph, bmain, scene, view_layer);
-#ifdef POSE_ANIMATION_WORKAROUND
- scene_armature_depsgraph_workaround(bmain, depsgraph);
-#endif
/* Update all objects: drivers, matrices, displists, etc. flags set
* by depgraph or manual, no layer check here, gets correct flushed.
*
@@ -2097,7 +2229,7 @@ static Depsgraph **scene_get_depsgraph_p(Main *bmain,
if (allocate_depsgraph) {
*depsgraph_ptr = DEG_graph_new(bmain, scene, view_layer, DAG_EVAL_VIEWPORT);
/* TODO(sergey): Would be cool to avoid string format print,
- * but is a bit tricky because we can't know in advance whether
+ * but is a bit tricky because we can't know in advance whether
* we will ever enable debug messages for this depsgraph.
*/
char name[1024];
@@ -2170,8 +2302,6 @@ GHash *BKE_scene_undo_depsgraphs_extract(Main *bmain)
void BKE_scene_undo_depsgraphs_restore(Main *bmain, GHash *depsgraph_extract)
{
for (Scene *scene = bmain->scenes.first; scene != NULL; scene = scene->id.next) {
- BLI_assert(scene->depsgraph_hash == NULL);
-
for (ViewLayer *view_layer = scene->view_layers.first; view_layer != NULL;
view_layer = view_layer->next) {
char key_full[MAX_ID_NAME + FILE_MAX + MAX_NAME] = {0};
diff --git a/source/blender/blenkernel/intern/screen.c b/source/blender/blenkernel/intern/screen.c
index dbf460fdea2..bfc0d437994 100644
--- a/source/blender/blenkernel/intern/screen.c
+++ b/source/blender/blenkernel/intern/screen.c
@@ -32,14 +32,18 @@
#include "MEM_guardedalloc.h"
#include "DNA_defaults.h"
+#include "DNA_gpencil_types.h"
+#include "DNA_mask_types.h"
#include "DNA_scene_types.h"
#include "DNA_screen_types.h"
#include "DNA_space_types.h"
+#include "DNA_text_types.h"
#include "DNA_view3d_types.h"
#include "DNA_workspace_types.h"
#include "BLI_listbase.h"
#include "BLI_math_vector.h"
+#include "BLI_mempool.h"
#include "BLI_rect.h"
#include "BLI_utildefines.h"
@@ -48,6 +52,8 @@
#include "BKE_icons.h"
#include "BKE_idprop.h"
#include "BKE_idtype.h"
+#include "BKE_lib_query.h"
+#include "BKE_node.h"
#include "BKE_screen.h"
#include "BKE_workspace.h"
@@ -72,6 +78,158 @@ static void screen_free_data(ID *id)
MEM_SAFE_FREE(screen->tool_tip);
}
+static void screen_foreach_id_dopesheet(LibraryForeachIDData *data, bDopeSheet *ads)
+{
+ if (ads != NULL) {
+ BKE_LIB_FOREACHID_PROCESS_ID(data, ads->source, IDWALK_CB_NOP);
+ BKE_LIB_FOREACHID_PROCESS(data, ads->filter_grp, IDWALK_CB_NOP);
+ }
+}
+
+void BKE_screen_foreach_id_screen_area(LibraryForeachIDData *data, ScrArea *area)
+{
+ BKE_LIB_FOREACHID_PROCESS(data, area->full, IDWALK_CB_NOP);
+
+ /* TODO this should be moved to a callback in `SpaceType`, defined in each editor's own code.
+ * Will be for a later round of cleanup though... */
+ LISTBASE_FOREACH (SpaceLink *, sl, &area->spacedata) {
+ switch (sl->spacetype) {
+ case SPACE_VIEW3D: {
+ View3D *v3d = (View3D *)sl;
+
+ BKE_LIB_FOREACHID_PROCESS(data, v3d->camera, IDWALK_CB_NOP);
+ BKE_LIB_FOREACHID_PROCESS(data, v3d->ob_center, IDWALK_CB_NOP);
+
+ if (v3d->localvd) {
+ BKE_LIB_FOREACHID_PROCESS(data, v3d->localvd->camera, IDWALK_CB_NOP);
+ }
+ break;
+ }
+ case SPACE_GRAPH: {
+ SpaceGraph *sipo = (SpaceGraph *)sl;
+
+ screen_foreach_id_dopesheet(data, sipo->ads);
+ break;
+ }
+ case SPACE_PROPERTIES: {
+ SpaceProperties *sbuts = (SpaceProperties *)sl;
+
+ BKE_LIB_FOREACHID_PROCESS_ID(data, sbuts->pinid, IDWALK_CB_NOP);
+ break;
+ }
+ case SPACE_FILE:
+ break;
+ case SPACE_ACTION: {
+ SpaceAction *saction = (SpaceAction *)sl;
+
+ screen_foreach_id_dopesheet(data, &saction->ads);
+ BKE_LIB_FOREACHID_PROCESS(data, saction->action, IDWALK_CB_NOP);
+ break;
+ }
+ case SPACE_IMAGE: {
+ SpaceImage *sima = (SpaceImage *)sl;
+
+ BKE_LIB_FOREACHID_PROCESS(data, sima->image, IDWALK_CB_USER_ONE);
+ BKE_LIB_FOREACHID_PROCESS(data, sima->mask_info.mask, IDWALK_CB_USER_ONE);
+ BKE_LIB_FOREACHID_PROCESS(data, sima->gpd, IDWALK_CB_USER);
+ break;
+ }
+ case SPACE_SEQ: {
+ SpaceSeq *sseq = (SpaceSeq *)sl;
+
+ BKE_LIB_FOREACHID_PROCESS(data, sseq->gpd, IDWALK_CB_USER);
+ break;
+ }
+ case SPACE_NLA: {
+ SpaceNla *snla = (SpaceNla *)sl;
+
+ screen_foreach_id_dopesheet(data, snla->ads);
+ break;
+ }
+ case SPACE_TEXT: {
+ SpaceText *st = (SpaceText *)sl;
+
+ BKE_LIB_FOREACHID_PROCESS(data, st->text, IDWALK_CB_NOP);
+ break;
+ }
+ case SPACE_SCRIPT: {
+ SpaceScript *scpt = (SpaceScript *)sl;
+
+ BKE_LIB_FOREACHID_PROCESS(data, scpt->script, IDWALK_CB_NOP);
+ break;
+ }
+ case SPACE_OUTLINER: {
+ SpaceOutliner *so = (SpaceOutliner *)sl;
+
+ BKE_LIB_FOREACHID_PROCESS_ID(data, so->search_tse.id, IDWALK_CB_NOP);
+
+ if (so->treestore != NULL) {
+ TreeStoreElem *tselem;
+ BLI_mempool_iter iter;
+
+ BLI_mempool_iternew(so->treestore, &iter);
+ while ((tselem = BLI_mempool_iterstep(&iter))) {
+ BKE_LIB_FOREACHID_PROCESS_ID(data, tselem->id, IDWALK_CB_NOP);
+ }
+ }
+ break;
+ }
+ case SPACE_NODE: {
+ SpaceNode *snode = (SpaceNode *)sl;
+
+ const bool is_private_nodetree = snode->id != NULL &&
+ ntreeFromID(snode->id) == snode->nodetree;
+
+ BKE_LIB_FOREACHID_PROCESS_ID(data, snode->id, IDWALK_CB_NOP);
+ BKE_LIB_FOREACHID_PROCESS_ID(data, snode->from, IDWALK_CB_NOP);
+
+ BKE_LIB_FOREACHID_PROCESS(
+ data, snode->nodetree, is_private_nodetree ? IDWALK_CB_EMBEDDED : IDWALK_CB_USER_ONE);
+
+ LISTBASE_FOREACH (bNodeTreePath *, path, &snode->treepath) {
+ if (path == snode->treepath.first) {
+ /* first nodetree in path is same as snode->nodetree */
+ BKE_LIB_FOREACHID_PROCESS(data,
+ path->nodetree,
+ is_private_nodetree ? IDWALK_CB_EMBEDDED :
+ IDWALK_CB_USER_ONE);
+ }
+ else {
+ BKE_LIB_FOREACHID_PROCESS(data, path->nodetree, IDWALK_CB_USER_ONE);
+ }
+
+ if (path->nodetree == NULL) {
+ break;
+ }
+ }
+
+ BKE_LIB_FOREACHID_PROCESS(data, snode->edittree, IDWALK_CB_NOP);
+ break;
+ }
+ case SPACE_CLIP: {
+ SpaceClip *sclip = (SpaceClip *)sl;
+
+ BKE_LIB_FOREACHID_PROCESS(data, sclip->clip, IDWALK_CB_USER_ONE);
+ BKE_LIB_FOREACHID_PROCESS(data, sclip->mask_info.mask, IDWALK_CB_USER_ONE);
+ break;
+ }
+ default:
+ break;
+ }
+ }
+}
+
+static void screen_foreach_id(ID *id, LibraryForeachIDData *data)
+{
+ if (BKE_lib_query_foreachid_process_flags_get(data) & IDWALK_INCLUDE_UI) {
+ bScreen *screen = (bScreen *)id;
+
+ LISTBASE_FOREACH (ScrArea *, area, &screen->areabase) {
+ BKE_screen_foreach_id_screen_area(data, area);
+ }
+ }
+}
+
IDTypeInfo IDType_ID_SCR = {
.id_code = ID_SCR,
.id_filter = 0,
@@ -86,6 +244,7 @@ IDTypeInfo IDType_ID_SCR = {
.copy_data = NULL,
.free_data = screen_free_data,
.make_local = NULL,
+ .foreach_id = screen_foreach_id,
};
/* ************ Spacetype/regiontype handling ************** */
@@ -104,16 +263,16 @@ static void spacetype_free(SpaceType *st)
BLI_freelistN(&art->drawcalls);
for (pt = art->paneltypes.first; pt; pt = pt->next) {
- if (pt->ext.free) {
- pt->ext.free(pt->ext.data);
+ if (pt->rna_ext.free) {
+ pt->rna_ext.free(pt->rna_ext.data);
}
BLI_freelistN(&pt->children);
}
for (ht = art->headertypes.first; ht; ht = ht->next) {
- if (ht->ext.free) {
- ht->ext.free(ht->ext.data);
+ if (ht->rna_ext.free) {
+ ht->rna_ext.free(ht->rna_ext.data);
}
}
@@ -230,11 +389,11 @@ static void panel_list_copy(ListBase *newlb, const ListBase *lb)
BLI_duplicatelist(newlb, lb);
/* copy panel pointers */
- Panel *newpa = newlb->first;
- Panel *pa = lb->first;
- for (; newpa; newpa = newpa->next, pa = pa->next) {
- newpa->activedata = NULL;
- panel_list_copy(&newpa->children, &pa->children);
+ Panel *new_panel = newlb->first;
+ Panel *panel = lb->first;
+ for (; new_panel; new_panel = new_panel->next, panel = panel->next) {
+ new_panel->activedata = NULL;
+ panel_list_copy(&new_panel->children, &panel->children);
}
}
@@ -338,15 +497,17 @@ void BKE_spacedata_draw_locks(int set)
/**
* Version of #BKE_area_find_region_type that also works if \a slink
- * is not the active space of \a sa.
+ * is not the active space of \a area.
*/
-ARegion *BKE_spacedata_find_region_type(const SpaceLink *slink, const ScrArea *sa, int region_type)
+ARegion *BKE_spacedata_find_region_type(const SpaceLink *slink,
+ const ScrArea *area,
+ int region_type)
{
- const bool is_slink_active = slink == sa->spacedata.first;
- const ListBase *regionbase = (is_slink_active) ? &sa->regionbase : &slink->regionbase;
+ const bool is_slink_active = slink == area->spacedata.first;
+ const ListBase *regionbase = (is_slink_active) ? &area->regionbase : &slink->regionbase;
ARegion *region = NULL;
- BLI_assert(BLI_findindex(&sa->spacedata, slink) != -1);
+ BLI_assert(BLI_findindex(&area->spacedata, slink) != -1);
for (region = regionbase->first; region; region = region->next) {
if (region->regiontype == region_type) {
break;
@@ -354,26 +515,26 @@ ARegion *BKE_spacedata_find_region_type(const SpaceLink *slink, const ScrArea *s
}
/* Should really unit test this instead. */
- BLI_assert(!is_slink_active || region == BKE_area_find_region_type(sa, region_type));
+ BLI_assert(!is_slink_active || region == BKE_area_find_region_type(area, region_type));
return region;
}
-static void (*spacedata_id_remap_cb)(struct ScrArea *sa,
+static void (*spacedata_id_remap_cb)(struct ScrArea *area,
struct SpaceLink *sl,
ID *old_id,
ID *new_id) = NULL;
-void BKE_spacedata_callback_id_remap_set(void (*func)(ScrArea *sa, SpaceLink *sl, ID *, ID *))
+void BKE_spacedata_callback_id_remap_set(void (*func)(ScrArea *area, SpaceLink *sl, ID *, ID *))
{
spacedata_id_remap_cb = func;
}
/* UNUSED!!! */
-void BKE_spacedata_id_unref(struct ScrArea *sa, struct SpaceLink *sl, struct ID *id)
+void BKE_spacedata_id_unref(struct ScrArea *area, struct SpaceLink *sl, struct ID *id)
{
if (spacedata_id_remap_cb) {
- spacedata_id_remap_cb(sa, sl, id, NULL);
+ spacedata_id_remap_cb(area, sl, id, NULL);
}
}
@@ -387,16 +548,16 @@ void BKE_region_callback_refresh_tag_gizmomap_set(void (*callback)(struct wmGizm
region_refresh_tag_gizmomap_callback = callback;
}
-void BKE_screen_gizmo_tag_refresh(struct bScreen *sc)
+void BKE_screen_gizmo_tag_refresh(struct bScreen *screen)
{
if (region_refresh_tag_gizmomap_callback == NULL) {
return;
}
- ScrArea *sa;
+ ScrArea *area;
ARegion *region;
- for (sa = sc->areabase.first; sa; sa = sa->next) {
- for (region = sa->regionbase.first; region; region = region->next) {
+ for (area = screen->areabase.first; area; area = area->next) {
+ for (region = area->regionbase.first; region; region = region->next) {
if (region->gizmo_map != NULL) {
region_refresh_tag_gizmomap_callback(region->gizmo_map);
}
@@ -416,13 +577,13 @@ void BKE_region_callback_free_gizmomap_set(void (*callback)(struct wmGizmoMap *)
void BKE_area_region_panels_free(ListBase *lb)
{
- Panel *pa, *pa_next;
- for (pa = lb->first; pa; pa = pa_next) {
- pa_next = pa->next;
- if (pa->activedata) {
- MEM_freeN(pa->activedata);
+ Panel *panel, *panel_next;
+ for (panel = lb->first; panel; panel = panel_next) {
+ panel_next = panel->next;
+ if (panel->activedata) {
+ MEM_freeN(panel->activedata);
}
- BKE_area_region_panels_free(&pa->children);
+ BKE_area_region_panels_free(&panel->children);
}
BLI_freelistN(lb);
@@ -482,21 +643,21 @@ void BKE_area_region_free(SpaceType *st, ARegion *region)
}
/* not area itself */
-void BKE_screen_area_free(ScrArea *sa)
+void BKE_screen_area_free(ScrArea *area)
{
- SpaceType *st = BKE_spacetype_from_id(sa->spacetype);
+ SpaceType *st = BKE_spacetype_from_id(area->spacetype);
ARegion *region;
- for (region = sa->regionbase.first; region; region = region->next) {
+ for (region = area->regionbase.first; region; region = region->next) {
BKE_area_region_free(st, region);
}
- MEM_SAFE_FREE(sa->global);
- BLI_freelistN(&sa->regionbase);
+ MEM_SAFE_FREE(area->global);
+ BLI_freelistN(&area->regionbase);
- BKE_spacedata_freelist(&sa->spacedata);
+ BKE_spacedata_freelist(&area->spacedata);
- BLI_freelistN(&sa->actionzones);
+ BLI_freelistN(&area->actionzones);
}
void BKE_screen_area_map_free(ScrAreaMap *area_map)
@@ -512,19 +673,19 @@ void BKE_screen_area_map_free(ScrAreaMap *area_map)
}
/** Free (or release) any data used by this screen (does not free the screen itself). */
-void BKE_screen_free(bScreen *sc)
+void BKE_screen_free(bScreen *screen)
{
- screen_free_data(&sc->id);
+ screen_free_data(&screen->id);
}
/* ***************** Screen edges & verts ***************** */
-ScrEdge *BKE_screen_find_edge(bScreen *sc, ScrVert *v1, ScrVert *v2)
+ScrEdge *BKE_screen_find_edge(bScreen *screen, ScrVert *v1, ScrVert *v2)
{
ScrEdge *se;
BKE_screen_sort_scrvert(&v1, &v2);
- for (se = sc->edgebase.first; se; se = se->next) {
+ for (se = screen->edgebase.first; se; se = se->next) {
if (se->v1 == v1 && se->v2 == v2) {
return se;
}
@@ -544,13 +705,13 @@ void BKE_screen_sort_scrvert(ScrVert **v1, ScrVert **v2)
}
}
-void BKE_screen_remove_double_scrverts(bScreen *sc)
+void BKE_screen_remove_double_scrverts(bScreen *screen)
{
ScrVert *v1, *verg;
ScrEdge *se;
- ScrArea *sa;
+ ScrArea *area;
- verg = sc->vertbase.first;
+ verg = screen->vertbase.first;
while (verg) {
if (verg->newv == NULL) { /* !!! */
v1 = verg->next;
@@ -568,7 +729,7 @@ void BKE_screen_remove_double_scrverts(bScreen *sc)
}
/* replace pointers in edges and faces */
- se = sc->edgebase.first;
+ se = screen->edgebase.first;
while (se) {
if (se->v1->newv) {
se->v1 = se->v1->newv;
@@ -580,47 +741,47 @@ void BKE_screen_remove_double_scrverts(bScreen *sc)
BKE_screen_sort_scrvert(&(se->v1), &(se->v2));
se = se->next;
}
- sa = sc->areabase.first;
- while (sa) {
- if (sa->v1->newv) {
- sa->v1 = sa->v1->newv;
+ area = screen->areabase.first;
+ while (area) {
+ if (area->v1->newv) {
+ area->v1 = area->v1->newv;
}
- if (sa->v2->newv) {
- sa->v2 = sa->v2->newv;
+ if (area->v2->newv) {
+ area->v2 = area->v2->newv;
}
- if (sa->v3->newv) {
- sa->v3 = sa->v3->newv;
+ if (area->v3->newv) {
+ area->v3 = area->v3->newv;
}
- if (sa->v4->newv) {
- sa->v4 = sa->v4->newv;
+ if (area->v4->newv) {
+ area->v4 = area->v4->newv;
}
- sa = sa->next;
+ area = area->next;
}
/* remove */
- verg = sc->vertbase.first;
+ verg = screen->vertbase.first;
while (verg) {
v1 = verg->next;
if (verg->newv) {
- BLI_remlink(&sc->vertbase, verg);
+ BLI_remlink(&screen->vertbase, verg);
MEM_freeN(verg);
}
verg = v1;
}
}
-void BKE_screen_remove_double_scredges(bScreen *sc)
+void BKE_screen_remove_double_scredges(bScreen *screen)
{
ScrEdge *verg, *se, *sn;
/* compare */
- verg = sc->edgebase.first;
+ verg = screen->edgebase.first;
while (verg) {
se = verg->next;
while (se) {
sn = se->next;
if (verg->v1 == se->v1 && verg->v2 == se->v2) {
- BLI_remlink(&sc->edgebase, se);
+ BLI_remlink(&screen->edgebase, se);
MEM_freeN(se);
}
se = sn;
@@ -629,51 +790,51 @@ void BKE_screen_remove_double_scredges(bScreen *sc)
}
}
-void BKE_screen_remove_unused_scredges(bScreen *sc)
+void BKE_screen_remove_unused_scredges(bScreen *screen)
{
ScrEdge *se, *sen;
- ScrArea *sa;
+ ScrArea *area;
int a = 0;
/* sets flags when edge is used in area */
- sa = sc->areabase.first;
- while (sa) {
- se = BKE_screen_find_edge(sc, sa->v1, sa->v2);
+ area = screen->areabase.first;
+ while (area) {
+ se = BKE_screen_find_edge(screen, area->v1, area->v2);
if (se == NULL) {
printf("error: area %d edge 1 doesn't exist\n", a);
}
else {
se->flag = 1;
}
- se = BKE_screen_find_edge(sc, sa->v2, sa->v3);
+ se = BKE_screen_find_edge(screen, area->v2, area->v3);
if (se == NULL) {
printf("error: area %d edge 2 doesn't exist\n", a);
}
else {
se->flag = 1;
}
- se = BKE_screen_find_edge(sc, sa->v3, sa->v4);
+ se = BKE_screen_find_edge(screen, area->v3, area->v4);
if (se == NULL) {
printf("error: area %d edge 3 doesn't exist\n", a);
}
else {
se->flag = 1;
}
- se = BKE_screen_find_edge(sc, sa->v4, sa->v1);
+ se = BKE_screen_find_edge(screen, area->v4, area->v1);
if (se == NULL) {
printf("error: area %d edge 4 doesn't exist\n", a);
}
else {
se->flag = 1;
}
- sa = sa->next;
+ area = area->next;
a++;
}
- se = sc->edgebase.first;
+ se = screen->edgebase.first;
while (se) {
sen = se->next;
if (se->flag == 0) {
- BLI_remlink(&sc->edgebase, se);
+ BLI_remlink(&screen->edgebase, se);
MEM_freeN(se);
}
else {
@@ -683,25 +844,25 @@ void BKE_screen_remove_unused_scredges(bScreen *sc)
}
}
-void BKE_screen_remove_unused_scrverts(bScreen *sc)
+void BKE_screen_remove_unused_scrverts(bScreen *screen)
{
ScrVert *sv, *svn;
ScrEdge *se;
/* we assume edges are ok */
- se = sc->edgebase.first;
+ se = screen->edgebase.first;
while (se) {
se->v1->flag = 1;
se->v2->flag = 1;
se = se->next;
}
- sv = sc->vertbase.first;
+ sv = screen->vertbase.first;
while (sv) {
svn = sv->next;
if (sv->flag == 0) {
- BLI_remlink(&sc->vertbase, sv);
+ BLI_remlink(&screen->vertbase, sv);
MEM_freeN(sv);
}
else {
@@ -714,15 +875,15 @@ void BKE_screen_remove_unused_scrverts(bScreen *sc)
/* ***************** Utilities ********************** */
/**
- * Find a region of type \a region_type in the currently active space of \a sa.
+ * Find a region of type \a region_type in the currently active space of \a area.
*
* \note This does _not_ work if the region to look up is not in the active
* space. Use #BKE_spacedata_find_region_type if that may be the case.
*/
-ARegion *BKE_area_find_region_type(const ScrArea *sa, int region_type)
+ARegion *BKE_area_find_region_type(const ScrArea *area, int region_type)
{
- if (sa) {
- for (ARegion *region = sa->regionbase.first; region; region = region->next) {
+ if (area) {
+ LISTBASE_FOREACH (ARegion *, region, &area->regionbase) {
if (region->regiontype == region_type) {
return region;
}
@@ -732,87 +893,87 @@ ARegion *BKE_area_find_region_type(const ScrArea *sa, int region_type)
return NULL;
}
-ARegion *BKE_area_find_region_active_win(ScrArea *sa)
+ARegion *BKE_area_find_region_active_win(ScrArea *area)
{
- if (sa) {
- ARegion *region = BLI_findlink(&sa->regionbase, sa->region_active_win);
+ if (area) {
+ ARegion *region = BLI_findlink(&area->regionbase, area->region_active_win);
if (region && (region->regiontype == RGN_TYPE_WINDOW)) {
return region;
}
/* fallback to any */
- return BKE_area_find_region_type(sa, RGN_TYPE_WINDOW);
+ return BKE_area_find_region_type(area, RGN_TYPE_WINDOW);
}
return NULL;
}
-ARegion *BKE_area_find_region_xy(ScrArea *sa, const int regiontype, int x, int y)
+ARegion *BKE_area_find_region_xy(ScrArea *area, const int regiontype, int x, int y)
{
- ARegion *ar_found = NULL;
- if (sa) {
+ ARegion *region_found = NULL;
+ if (area) {
ARegion *region;
- for (region = sa->regionbase.first; region; region = region->next) {
+ for (region = area->regionbase.first; region; region = region->next) {
if ((regiontype == RGN_TYPE_ANY) || (region->regiontype == regiontype)) {
if (BLI_rcti_isect_pt(&region->winrct, x, y)) {
- ar_found = region;
+ region_found = region;
break;
}
}
}
}
- return ar_found;
+ return region_found;
}
/**
* \note This is only for screen level regions (typically menus/popups).
*/
-ARegion *BKE_screen_find_region_xy(bScreen *sc, const int regiontype, int x, int y)
+ARegion *BKE_screen_find_region_xy(bScreen *screen, const int regiontype, int x, int y)
{
- ARegion *ar_found = NULL;
- for (ARegion *region = sc->regionbase.first; region; region = region->next) {
+ ARegion *region_found = NULL;
+ LISTBASE_FOREACH (ARegion *, region, &screen->regionbase) {
if ((regiontype == RGN_TYPE_ANY) || (region->regiontype == regiontype)) {
if (BLI_rcti_isect_pt(&region->winrct, x, y)) {
- ar_found = region;
+ region_found = region;
break;
}
}
}
- return ar_found;
+ return region_found;
}
/**
* \note Ideally we can get the area from the context,
* there are a few places however where this isn't practical.
*/
-ScrArea *BKE_screen_find_area_from_space(struct bScreen *sc, SpaceLink *sl)
+ScrArea *BKE_screen_find_area_from_space(struct bScreen *screen, SpaceLink *sl)
{
- ScrArea *sa;
+ ScrArea *area;
- for (sa = sc->areabase.first; sa; sa = sa->next) {
- if (BLI_findindex(&sa->spacedata, sl) != -1) {
+ for (area = screen->areabase.first; area; area = area->next) {
+ if (BLI_findindex(&area->spacedata, sl) != -1) {
break;
}
}
- return sa;
+ return area;
}
/**
* \note Using this function is generally a last resort, you really want to be
* using the context when you can - campbell
*/
-ScrArea *BKE_screen_find_big_area(bScreen *sc, const int spacetype, const short min)
+ScrArea *BKE_screen_find_big_area(bScreen *screen, const int spacetype, const short min)
{
- ScrArea *sa, *big = NULL;
+ ScrArea *area, *big = NULL;
int size, maxsize = 0;
- for (sa = sc->areabase.first; sa; sa = sa->next) {
- if ((spacetype == SPACE_TYPE_ANY) || (sa->spacetype == spacetype)) {
- if (min <= sa->winx && min <= sa->winy) {
- size = sa->winx * sa->winy;
+ for (area = screen->areabase.first; area; area = area->next) {
+ if ((spacetype == SPACE_TYPE_ANY) || (area->spacetype == spacetype)) {
+ if (min <= area->winx && min <= area->winy) {
+ size = area->winx * area->winy;
if (size > maxsize) {
maxsize = size;
- big = sa;
+ big = area;
}
}
}
@@ -826,19 +987,19 @@ ScrArea *BKE_screen_area_map_find_area_xy(const ScrAreaMap *areamap,
int x,
int y)
{
- for (ScrArea *sa = areamap->areabase.first; sa; sa = sa->next) {
- if (BLI_rcti_isect_pt(&sa->totrct, x, y)) {
- if ((spacetype == SPACE_TYPE_ANY) || (sa->spacetype == spacetype)) {
- return sa;
+ LISTBASE_FOREACH (ScrArea *, area, &areamap->areabase) {
+ if (BLI_rcti_isect_pt(&area->totrct, x, y)) {
+ if ((spacetype == SPACE_TYPE_ANY) || (area->spacetype == spacetype)) {
+ return area;
}
break;
}
}
return NULL;
}
-ScrArea *BKE_screen_find_area_xy(bScreen *sc, const int spacetype, int x, int y)
+ScrArea *BKE_screen_find_area_xy(bScreen *screen, const int spacetype, int x, int y)
{
- return BKE_screen_area_map_find_area_xy(AREAMAP_FROM_SCREEN(sc), spacetype, x, y);
+ return BKE_screen_area_map_find_area_xy(AREAMAP_FROM_SCREEN(screen), spacetype, x, y);
}
void BKE_screen_view3d_sync(View3D *v3d, struct Scene *scene)
@@ -861,13 +1022,13 @@ void BKE_screen_view3d_sync(View3D *v3d, struct Scene *scene)
}
}
-void BKE_screen_view3d_scene_sync(bScreen *sc, Scene *scene)
+void BKE_screen_view3d_scene_sync(bScreen *screen, Scene *scene)
{
/* are there cameras in the views that are not in the scene? */
- ScrArea *sa;
- for (sa = sc->areabase.first; sa; sa = sa->next) {
+ ScrArea *area;
+ for (area = screen->areabase.first; area; area = area->next) {
SpaceLink *sl;
- for (sl = sa->spacedata.first; sl; sl = sl->next) {
+ for (sl = area->spacedata.first; sl; sl = sl->next) {
if (sl->spacetype == SPACE_VIEW3D) {
View3D *v3d = (View3D *)sl;
BKE_screen_view3d_sync(v3d, scene);
@@ -913,17 +1074,17 @@ bool BKE_screen_is_used(const bScreen *screen)
void BKE_screen_header_alignment_reset(bScreen *screen)
{
int alignment = (U.uiflag & USER_HEADER_BOTTOM) ? RGN_ALIGN_BOTTOM : RGN_ALIGN_TOP;
- for (ScrArea *sa = screen->areabase.first; sa; sa = sa->next) {
- for (ARegion *region = sa->regionbase.first; region; region = region->next) {
+ LISTBASE_FOREACH (ScrArea *, area, &screen->areabase) {
+ LISTBASE_FOREACH (ARegion *, region, &area->regionbase) {
if (ELEM(region->regiontype, RGN_TYPE_HEADER, RGN_TYPE_TOOL_HEADER)) {
- if (ELEM(sa->spacetype, SPACE_FILE, SPACE_USERPREF, SPACE_OUTLINER, SPACE_PROPERTIES)) {
+ if (ELEM(area->spacetype, SPACE_FILE, SPACE_USERPREF, SPACE_OUTLINER, SPACE_PROPERTIES)) {
region->alignment = RGN_ALIGN_TOP;
continue;
}
region->alignment = alignment;
}
if (region->regiontype == RGN_TYPE_FOOTER) {
- if (ELEM(sa->spacetype, SPACE_FILE, SPACE_USERPREF, SPACE_OUTLINER, SPACE_PROPERTIES)) {
+ if (ELEM(area->spacetype, SPACE_FILE, SPACE_USERPREF, SPACE_OUTLINER, SPACE_PROPERTIES)) {
region->alignment = RGN_ALIGN_BOTTOM;
continue;
}
diff --git a/source/blender/blenkernel/intern/seqcache.c b/source/blender/blenkernel/intern/seqcache.c
index a2c0434a474..5c2d5b0087f 100644
--- a/source/blender/blenkernel/intern/seqcache.c
+++ b/source/blender/blenkernel/intern/seqcache.c
@@ -243,7 +243,7 @@ static void seq_disk_cache_get_files(SeqDiskCache *disk_cache, char *path)
if (is_dir && !FILENAME_IS_CURRPAR(file)) {
char subpath[FILE_MAX];
BLI_strncpy(subpath, fl->path, sizeof(subpath));
- BLI_add_slash(subpath);
+ BLI_path_slash_ensure(subpath);
seq_disk_cache_get_files(disk_cache, subpath);
}
@@ -439,7 +439,7 @@ static void seq_disk_cache_delete_invalid_files(SeqDiskCache *disk_cache,
DiskCacheFile *next_file, *cache_file = disk_cache->files.first;
char cache_dir[FILE_MAX];
seq_disk_cache_get_dir(disk_cache, scene, seq, cache_dir, sizeof(cache_dir));
- BLI_add_slash(cache_dir);
+ BLI_path_slash_ensure(cache_dir);
while (cache_file) {
next_file = cache_file->next;
@@ -1153,7 +1153,8 @@ void BKE_sequencer_cache_cleanup(Scene *scene)
void BKE_sequencer_cache_cleanup_sequence(Scene *scene,
Sequence *seq,
Sequence *seq_changed,
- int invalidate_types)
+ int invalidate_types,
+ bool force_seq_changed_range)
{
SeqCache *cache = seq_cache_get_from_scene(scene);
if (!cache) {
@@ -1169,12 +1170,14 @@ void BKE_sequencer_cache_cleanup_sequence(Scene *scene,
int range_start = seq_changed->startdisp;
int range_end = seq_changed->enddisp;
- if (seq->startdisp > range_start) {
- range_start = seq->startdisp;
- }
+ if (!force_seq_changed_range) {
+ if (seq->startdisp > range_start) {
+ range_start = seq->startdisp;
+ }
- if (seq->enddisp < range_end) {
- range_end = seq->enddisp;
+ if (seq->enddisp < range_end) {
+ range_end = seq->enddisp;
+ }
}
int invalidate_composite = invalidate_types & SEQ_CACHE_STORE_FINAL_OUT;
@@ -1214,6 +1217,11 @@ void BKE_sequencer_cache_cleanup_sequence(Scene *scene,
struct ImBuf *BKE_sequencer_cache_get(
const SeqRenderData *context, Sequence *seq, float cfra, int type, bool skip_disk_cache)
{
+
+ if (context->skip_cache || context->is_proxy_render || !seq) {
+ return NULL;
+ }
+
Scene *scene = context->scene;
if (context->is_prefetch_render) {
@@ -1222,6 +1230,10 @@ struct ImBuf *BKE_sequencer_cache_get(
seq = BKE_sequencer_prefetch_get_original_sequence(seq, scene);
}
+ if (!seq) {
+ return NULL;
+ }
+
if (!scene->ed->cache) {
seq_cache_create(context->bmain, scene);
}
@@ -1284,6 +1296,10 @@ bool BKE_sequencer_cache_put_if_possible(const SeqRenderData *context,
seq = BKE_sequencer_prefetch_get_original_sequence(seq, scene);
}
+ if (!seq) {
+ return false;
+ }
+
if (BKE_sequencer_cache_recycle_item(scene)) {
BKE_sequencer_cache_put(context, seq, cfra, type, ibuf, cost, skip_disk_cache);
return true;
@@ -1303,6 +1319,10 @@ void BKE_sequencer_cache_put(const SeqRenderData *context,
float cost,
bool skip_disk_cache)
{
+ if (i == NULL || context->skip_cache || context->is_proxy_render || !seq) {
+ return;
+ }
+
Scene *scene = context->scene;
if (context->is_prefetch_render) {
@@ -1311,10 +1331,6 @@ void BKE_sequencer_cache_put(const SeqRenderData *context,
seq = BKE_sequencer_prefetch_get_original_sequence(seq, scene);
}
- if (i == NULL || context->skip_cache || context->is_proxy_render || !seq) {
- return;
- }
-
/* Prevent reinserting, it breaks cache key linking. */
ImBuf *test = BKE_sequencer_cache_get(context, seq, cfra, type, true);
if (test) {
diff --git a/source/blender/blenkernel/intern/seqeffects.c b/source/blender/blenkernel/intern/seqeffects.c
index 70f92c6d6bd..9fa43ed0a5f 100644
--- a/source/blender/blenkernel/intern/seqeffects.c
+++ b/source/blender/blenkernel/intern/seqeffects.c
@@ -30,6 +30,7 @@
#include "MEM_guardedalloc.h"
+#include "BLI_listbase.h"
#include "BLI_math.h" /* windows needs for M_PI */
#include "BLI_path_util.h"
#include "BLI_rect.h"
@@ -60,6 +61,8 @@
#include "BLF_api.h"
+static struct SeqEffectHandle get_sequence_effect_impl(int seq_type);
+
static void slice_get_byte_buffers(const SeqRenderData *context,
const ImBuf *ibuf1,
const ImBuf *ibuf2,
@@ -2499,15 +2502,14 @@ static ImBuf *do_transform_effect(const SeqRenderData *context,
/*********************** Glow *************************/
static void RVBlurBitmap2_float(float *map, int width, int height, float blur, int quality)
-/* MUUUCCH better than the previous blur. */
-/* We do the blurring in two passes which is a whole lot faster. */
-/* I changed the math around to implement an actual Gaussian */
-/* distribution. */
-/* */
-/* Watch out though, it tends to misbehaven with large blur values on */
-/* a small bitmap. Avoid avoid avoid. */
-/*=============================== */
{
+ /* Much better than the previous blur!
+ * We do the blurring in two passes which is a whole lot faster.
+ * I changed the math around to implement an actual Gaussian distribution.
+ *
+ * Watch out though, it tends to misbehave with large blur values on
+ * a small bitmap. Avoid avoid! */
+
float *temp = NULL, *swap;
float *filter = NULL;
int x, y, i, fx, fy;
@@ -3118,7 +3120,7 @@ static void copy_speed_effect(Sequence *dst, Sequence *src, const int UNUSED(fla
static int early_out_speed(Sequence *UNUSED(seq), float UNUSED(facf0), float UNUSED(facf1))
{
- return EARLY_USE_INPUT_1;
+ return EARLY_DO_EFFECT;
}
static void store_icu_yrange_speed(Sequence *seq, short UNUSED(adrcode), float *ymin, float *ymax)
@@ -3166,7 +3168,6 @@ void BKE_sequence_effect_speed_rebuild_map(Scene *scene, Sequence *seq, bool for
/* XXX - new in 2.5x. should we use the animation system this way?
* The fcurve is needed because many frames need evaluating at once - campbell */
fcu = id_data_find_fcurve(&scene->id, seq, &RNA_Sequence, "speed_factor", 0, NULL);
-
if (!v->frameMap || v->length != seq->len) {
if (v->frameMap) {
MEM_freeN(v->frameMap);
@@ -3249,36 +3250,60 @@ void BKE_sequence_effect_speed_rebuild_map(Scene *scene, Sequence *seq, bool for
}
}
+/* Override cfra when rendering speed effect input. */
+float BKE_sequencer_speed_effect_target_frame_get(const SeqRenderData *context,
+ Sequence *seq,
+ float cfra,
+ int input)
+{
+ int nr = BKE_sequencer_give_stripelem_index(seq, cfra);
+ SpeedControlVars *s = (SpeedControlVars *)seq->effectdata;
+ BKE_sequence_effect_speed_rebuild_map(context->scene, seq, false);
+
+ /* No interpolation. */
+ if ((s->flags & SEQ_SPEED_USE_INTERPOLATION) == 0) {
+ return seq->start + s->frameMap[nr];
+ }
+
+ /* We need to provide current and next image for interpolation. */
+ if (input == 0) { /* Current frame. */
+ return floor(seq->start + s->frameMap[nr]);
+ }
+ else { /* Next frame. */
+ return ceil(seq->start + s->frameMap[nr]);
+ }
+}
+
+static float speed_effect_interpolation_ratio_get(SpeedControlVars *s, Sequence *seq, float cfra)
+{
+ int nr = BKE_sequencer_give_stripelem_index(seq, cfra);
+ return s->frameMap[nr] - floor(s->frameMap[nr]);
+}
+
static ImBuf *do_speed_effect(const SeqRenderData *context,
- Sequence *UNUSED(seq),
- float UNUSED(cfra),
+ Sequence *seq,
+ float cfra,
float facf0,
float facf1,
ImBuf *ibuf1,
ImBuf *ibuf2,
ImBuf *ibuf3)
{
- ImBuf *out = prepare_effect_imbufs(context, ibuf1, ibuf2, ibuf3);
+ SpeedControlVars *s = (SpeedControlVars *)seq->effectdata;
+ struct SeqEffectHandle cross_effect = get_sequence_effect_impl(SEQ_TYPE_CROSS);
+ ImBuf *out;
- if (out->rect_float) {
- do_cross_effect_float(facf0,
- facf1,
- context->rectx,
- context->recty,
- ibuf1->rect_float,
- ibuf2->rect_float,
- out->rect_float);
+ if (s->flags & SEQ_SPEED_USE_INTERPOLATION) {
+ out = prepare_effect_imbufs(context, ibuf1, ibuf2, ibuf3);
+ facf0 = facf1 = speed_effect_interpolation_ratio_get(s, seq, cfra);
+ /* Current frame is ibuf1, next frame is ibuf2. */
+ out = BKE_sequencer_effect_execute_threaded(
+ &cross_effect, context, NULL, cfra, facf0, facf1, ibuf1, ibuf2, ibuf3);
+ return out;
}
- else {
- do_cross_effect_byte(facf0,
- facf1,
- context->rectx,
- context->recty,
- (unsigned char *)ibuf1->rect,
- (unsigned char *)ibuf2->rect,
- (unsigned char *)out->rect);
- }
- return out;
+
+ /* No interpolation. */
+ return IMB_dupImBuf(ibuf1);
}
/*********************** overdrop *************************/
@@ -3882,11 +3907,9 @@ static ImBuf *do_text_effect(const SeqRenderData *context,
display = IMB_colormanagement_display_get_named(display_device);
/* Compensate text size for preview render size. */
- if (context->preview_render_size == SEQ_PROXY_RENDER_SIZE_SCENE) {
- proxy_size_comp = context->scene->r.size / 100.0;
- }
- else {
- proxy_size_comp = BKE_sequencer_rendersize_to_scale_factor(context->preview_render_size);
+ proxy_size_comp = context->scene->r.size / 100.0;
+ if (context->preview_render_size != SEQ_PROXY_RENDER_SIZE_SCENE) {
+ proxy_size_comp *= BKE_sequencer_rendersize_to_scale_factor(context->preview_render_size);
}
/* set before return */
diff --git a/source/blender/blenkernel/intern/seqprefetch.c b/source/blender/blenkernel/intern/seqprefetch.c
index 8c7d119857a..30a371b5b28 100644
--- a/source/blender/blenkernel/intern/seqprefetch.c
+++ b/source/blender/blenkernel/intern/seqprefetch.c
@@ -39,8 +39,10 @@
#include "IMB_imbuf.h"
#include "IMB_imbuf_types.h"
+#include "BKE_anim_data.h"
#include "BKE_animsys.h"
#include "BKE_context.h"
+#include "BKE_global.h"
#include "BKE_layer.h"
#include "BKE_lib_id.h"
#include "BKE_main.h"
@@ -133,19 +135,29 @@ static bool seq_prefetch_job_is_waiting(Scene *scene)
return pfjob->waiting;
}
-/* for cache context swapping */
-Sequence *BKE_sequencer_prefetch_get_original_sequence(Sequence *seq, Scene *scene)
+static Sequence *sequencer_prefetch_get_original_sequence(Sequence *seq, ListBase *seqbase)
{
- Editing *ed = scene->ed;
- ListBase *seqbase = &ed->seqbase;
- Sequence *seq_orig = NULL;
-
- for (seq_orig = (Sequence *)seqbase->first; seq_orig; seq_orig = seq_orig->next) {
+ LISTBASE_FOREACH (Sequence *, seq_orig, seqbase) {
if (strcmp(seq->name, seq_orig->name) == 0) {
- break;
+ return seq_orig;
+ }
+
+ if (seq_orig->type == SEQ_TYPE_META) {
+ Sequence *match = sequencer_prefetch_get_original_sequence(seq, &seq_orig->seqbase);
+ if (match != NULL) {
+ return match;
+ }
}
}
- return seq_orig;
+
+ return NULL;
+}
+
+/* for cache context swapping */
+Sequence *BKE_sequencer_prefetch_get_original_sequence(Sequence *seq, Scene *scene)
+{
+ Editing *ed = scene->ed;
+ return sequencer_prefetch_get_original_sequence(seq, &ed->seqbase);
}
/* for cache context swapping */
@@ -167,12 +179,17 @@ static bool seq_prefetch_is_cache_full(Scene *scene)
return BKE_sequencer_cache_recycle_item(pfjob->scene) == false;
}
+static float seq_prefetch_cfra(PrefetchJob *pfjob)
+{
+ return pfjob->cfra + pfjob->num_frames_prefetched;
+}
+
void BKE_sequencer_prefetch_get_time_range(Scene *scene, int *start, int *end)
{
PrefetchJob *pfjob = seq_prefetch_job_get(scene);
*start = pfjob->cfra;
- *end = pfjob->cfra + pfjob->num_frames_prefetched;
+ *end = seq_prefetch_cfra(pfjob);
}
static void seq_prefetch_free_depsgraph(PrefetchJob *pfjob)
@@ -186,8 +203,7 @@ static void seq_prefetch_free_depsgraph(PrefetchJob *pfjob)
static void seq_prefetch_update_depsgraph(PrefetchJob *pfjob)
{
- DEG_evaluate_on_framechange(
- pfjob->bmain_eval, pfjob->depsgraph, pfjob->cfra + pfjob->num_frames_prefetched);
+ DEG_evaluate_on_framechange(pfjob->bmain_eval, pfjob->depsgraph, seq_prefetch_cfra(pfjob));
}
static void seq_prefetch_init_depsgraph(PrefetchJob *pfjob)
@@ -231,6 +247,14 @@ static void seq_prefetch_update_area(PrefetchJob *pfjob)
}
}
+void BKE_sequencer_prefetch_stop_all(void)
+{
+ /*TODO(Richard): Use wm_jobs for prefetch, or pass main. */
+ for (Scene *scene = G.main->scenes.first; scene; scene = scene->id.next) {
+ BKE_sequencer_prefetch_stop(scene);
+ }
+}
+
/* Use also to update scene and context changes
* This function should almost always be called by cache invalidation, not directly.
*/
@@ -323,21 +347,96 @@ void BKE_sequencer_prefetch_free(Scene *scene)
scene->ed->prefetch_job = NULL;
}
+static bool seq_prefetch_do_skip_frame(Scene *scene)
+{
+ Editing *ed = scene->ed;
+ PrefetchJob *pfjob = seq_prefetch_job_get(scene);
+ float cfra = seq_prefetch_cfra(pfjob);
+ Sequence *seq_arr[MAXSEQ + 1];
+ int count = BKE_sequencer_get_shown_sequences(ed->seqbasep, cfra, 0, seq_arr);
+ SeqRenderData *ctx = &pfjob->context_cpy;
+ ImBuf *ibuf = NULL;
+
+ /* Disable prefetching 3D scene strips, but check for disk cache. */
+ for (int i = 0; i < count; i++) {
+ if (seq_arr[i]->type == SEQ_TYPE_SCENE && (seq_arr[i]->flag & SEQ_SCENE_STRIPS) == 0) {
+ int cached_types = 0;
+
+ ibuf = BKE_sequencer_cache_get(ctx, seq_arr[i], cfra, SEQ_CACHE_STORE_FINAL_OUT, false);
+ if (ibuf != NULL) {
+ cached_types |= SEQ_CACHE_STORE_FINAL_OUT;
+ IMB_freeImBuf(ibuf);
+ ibuf = NULL;
+ }
+
+ ibuf = BKE_sequencer_cache_get(ctx, seq_arr[i], cfra, SEQ_CACHE_STORE_FINAL_OUT, false);
+ if (ibuf != NULL) {
+ cached_types |= SEQ_CACHE_STORE_COMPOSITE;
+ IMB_freeImBuf(ibuf);
+ ibuf = NULL;
+ }
+
+ ibuf = BKE_sequencer_cache_get(ctx, seq_arr[i], cfra, SEQ_CACHE_STORE_PREPROCESSED, false);
+ if (ibuf != NULL) {
+ cached_types |= SEQ_CACHE_STORE_PREPROCESSED;
+ IMB_freeImBuf(ibuf);
+ ibuf = NULL;
+ }
+
+ ibuf = BKE_sequencer_cache_get(ctx, seq_arr[i], cfra, SEQ_CACHE_STORE_RAW, false);
+ if (ibuf != NULL) {
+ cached_types |= SEQ_CACHE_STORE_RAW;
+ IMB_freeImBuf(ibuf);
+ ibuf = NULL;
+ }
+
+ if ((cached_types & (SEQ_CACHE_STORE_RAW | SEQ_CACHE_STORE_PREPROCESSED)) != 0) {
+ continue;
+ }
+
+ /* It is only safe to use these cache types if strip is last in stack. */
+ if (i == count - 1 &&
+ (cached_types & (SEQ_CACHE_STORE_PREPROCESSED | SEQ_CACHE_STORE_RAW)) != 0) {
+ continue;
+ }
+
+ return true;
+ }
+ }
+
+ return false;
+}
+
+static bool seq_prefetch_need_suspend(PrefetchJob *pfjob)
+{
+ return seq_prefetch_is_cache_full(pfjob->scene) || seq_prefetch_is_scrubbing(pfjob->bmain) ||
+ (seq_prefetch_cfra(pfjob) >= pfjob->scene->r.efra);
+}
+
+static void seq_prefetch_do_suspend(PrefetchJob *pfjob)
+{
+ BLI_mutex_lock(&pfjob->prefetch_suspend_mutex);
+ while (seq_prefetch_need_suspend(pfjob) &&
+ (pfjob->scene->ed->cache_flag & SEQ_CACHE_PREFETCH_ENABLE) && !pfjob->stop) {
+ pfjob->waiting = true;
+ BLI_condition_wait(&pfjob->prefetch_suspend_cond, &pfjob->prefetch_suspend_mutex);
+ seq_prefetch_update_area(pfjob);
+ }
+ pfjob->waiting = false;
+ BLI_mutex_unlock(&pfjob->prefetch_suspend_mutex);
+}
+
static void *seq_prefetch_frames(void *job)
{
PrefetchJob *pfjob = (PrefetchJob *)job;
- while (pfjob->cfra + pfjob->num_frames_prefetched <= pfjob->scene->r.efra) {
+ while (seq_prefetch_cfra(pfjob) <= pfjob->scene->r.efra) {
pfjob->scene_eval->ed->prefetch_job = NULL;
- AnimData *adt = BKE_animdata_from_id(&pfjob->context_cpy.scene->id);
- BKE_animsys_evaluate_animdata(pfjob->context_cpy.scene,
- &pfjob->context_cpy.scene->id,
- adt,
- pfjob->cfra + pfjob->num_frames_prefetched,
- ADT_RECALC_ALL,
- false);
seq_prefetch_update_depsgraph(pfjob);
+ AnimData *adt = BKE_animdata_from_id(&pfjob->context_cpy.scene->id);
+ BKE_animsys_evaluate_animdata(
+ &pfjob->context_cpy.scene->id, adt, seq_prefetch_cfra(pfjob), ADT_RECALC_ALL, false);
/* This is quite hacky solution:
* We need cross-reference original scene with copy for cache.
@@ -347,26 +446,22 @@ static void *seq_prefetch_frames(void *job)
*/
pfjob->scene_eval->ed->prefetch_job = pfjob;
- ImBuf *ibuf = BKE_sequencer_give_ibuf(
- &pfjob->context_cpy, pfjob->cfra + pfjob->num_frames_prefetched, 0);
+ if (seq_prefetch_do_skip_frame(pfjob->scene)) {
+ pfjob->num_frames_prefetched++;
+ continue;
+ }
+
+ ImBuf *ibuf = BKE_sequencer_give_ibuf(&pfjob->context_cpy, seq_prefetch_cfra(pfjob), 0);
BKE_sequencer_cache_free_temp_cache(
- pfjob->scene, pfjob->context.task_id, pfjob->cfra + pfjob->num_frames_prefetched);
+ pfjob->scene, pfjob->context.task_id, seq_prefetch_cfra(pfjob));
IMB_freeImBuf(ibuf);
- /* suspend thread */
- BLI_mutex_lock(&pfjob->prefetch_suspend_mutex);
- while ((seq_prefetch_is_cache_full(pfjob->scene) || seq_prefetch_is_scrubbing(pfjob->bmain)) &&
- pfjob->scene->ed->cache_flag & SEQ_CACHE_PREFETCH_ENABLE && !pfjob->stop) {
- pfjob->waiting = true;
- BLI_condition_wait(&pfjob->prefetch_suspend_cond, &pfjob->prefetch_suspend_mutex);
- seq_prefetch_update_area(pfjob);
- }
- pfjob->waiting = false;
- BLI_mutex_unlock(&pfjob->prefetch_suspend_mutex);
+ /* Suspend thread if there is nothing to be prefetched. */
+ seq_prefetch_do_suspend(pfjob);
/* Avoid "collision" with main thread, but make sure to fetch at least few frames */
if (pfjob->num_frames_prefetched > 5 &&
- (pfjob->cfra + pfjob->num_frames_prefetched - pfjob->scene->r.cfra) < 2) {
+ (seq_prefetch_cfra(pfjob) - pfjob->scene->r.cfra) < 2) {
break;
}
@@ -379,7 +474,7 @@ static void *seq_prefetch_frames(void *job)
}
BKE_sequencer_cache_free_temp_cache(
- pfjob->scene, pfjob->context.task_id, pfjob->cfra + pfjob->num_frames_prefetched);
+ pfjob->scene, pfjob->context.task_id, seq_prefetch_cfra(pfjob));
pfjob->running = false;
pfjob->scene_eval->ed->prefetch_job = NULL;
@@ -436,10 +531,12 @@ void BKE_sequencer_prefetch_start(const SeqRenderData *context, float cfra, floa
seq_prefetch_resume(scene);
/* conditions to start:
* prefetch enabled, prefetch not running, not scrubbing,
- * not playing and rendering-expensive footage, cache storage enabled, has strips to render
+ * not playing and rendering-expensive footage, cache storage enabled, has strips to render,
+ * not rendering, not doing modal transform - important, see D7820.
*/
if ((ed->cache_flag & SEQ_CACHE_PREFETCH_ENABLE) && !running && !scrubbing &&
- !(playing && cost > 0.9) && ed->cache_flag & SEQ_CACHE_ALL_TYPES && has_strips) {
+ !(playing && cost > 0.9) && ed->cache_flag & SEQ_CACHE_ALL_TYPES && has_strips &&
+ !G.is_rendering && !G.moving) {
seq_prefetch_start(context, cfra);
}
diff --git a/source/blender/blenkernel/intern/sequencer.c b/source/blender/blenkernel/intern/sequencer.c
index 9fb28fe250a..90edebfaa97 100644
--- a/source/blender/blenkernel/intern/sequencer.c
+++ b/source/blender/blenkernel/intern/sequencer.c
@@ -39,6 +39,7 @@
#include "DNA_sequence_types.h"
#include "DNA_sound_types.h"
#include "DNA_space_types.h"
+#include "DNA_windowmanager_types.h"
#include "BLI_fileops.h"
#include "BLI_linklist.h"
@@ -58,6 +59,7 @@
#include "BLT_translation.h"
+#include "BKE_anim_data.h"
#include "BKE_animsys.h"
#include "BKE_fcurve.h"
#include "BKE_global.h"
@@ -68,6 +70,7 @@
#include "BKE_main.h"
#include "BKE_mask.h"
#include "BKE_movieclip.h"
+#include "BKE_report.h"
#include "BKE_scene.h"
#include "BKE_sequencer.h"
#include "BKE_sequencer_offscreen.h"
@@ -105,6 +108,14 @@ static ImBuf *seq_render_strip_stack(const SeqRenderData *context,
ListBase *seqbasep,
float cfra,
int chanshown);
+static ImBuf *seq_render_preprocess_ibuf(const SeqRenderData *context,
+ Sequence *seq,
+ ImBuf *ibuf,
+ float cfra,
+ clock_t begin,
+ bool use_preprocess,
+ const bool is_proxy_image,
+ const bool is_preprocessed);
static ImBuf *seq_render_strip(const SeqRenderData *context,
SeqRenderState *state,
Sequence *seq,
@@ -120,7 +131,8 @@ static ThreadMutex seq_render_mutex = BLI_MUTEX_INITIALIZER;
#define SELECT 1
ListBase seqbase_clipboard;
int seqbase_clipboard_frame;
-SequencerDrawView sequencer_view3d_cb = NULL; /* NULL in background mode */
+
+SequencerDrawView sequencer_view3d_fn = NULL; /* NULL in background mode */
#if 0 /* unused function */
static void printf_strip(Sequence *seq)
@@ -152,28 +164,28 @@ static void sequencer_state_init(SeqRenderState *state)
}
int BKE_sequencer_base_recursive_apply(ListBase *seqbase,
- int (*apply_func)(Sequence *seq, void *),
+ int (*apply_fn)(Sequence *seq, void *),
void *arg)
{
Sequence *iseq;
for (iseq = seqbase->first; iseq; iseq = iseq->next) {
- if (BKE_sequencer_recursive_apply(iseq, apply_func, arg) == -1) {
+ if (BKE_sequencer_recursive_apply(iseq, apply_fn, arg) == -1) {
return -1; /* bail out */
}
}
return 1;
}
-int BKE_sequencer_recursive_apply(Sequence *seq, int (*apply_func)(Sequence *, void *), void *arg)
+int BKE_sequencer_recursive_apply(Sequence *seq, int (*apply_fn)(Sequence *, void *), void *arg)
{
- int ret = apply_func(seq, arg);
+ int ret = apply_fn(seq, arg);
if (ret == -1) {
return -1; /* bail out */
}
if (ret && seq->seqbase.first) {
- ret = BKE_sequencer_base_recursive_apply(&seq->seqbase, apply_func, arg);
+ ret = BKE_sequencer_base_recursive_apply(&seq->seqbase, apply_fn, arg);
}
return ret;
@@ -227,7 +239,8 @@ static void seq_free_strip(Strip *strip)
static void BKE_sequence_free_ex(Scene *scene,
Sequence *seq,
const bool do_cache,
- const bool do_id_user)
+ const bool do_id_user,
+ const bool do_clean_animdata)
{
if (seq->strip) {
seq_free_strip(seq->strip);
@@ -262,7 +275,10 @@ static void BKE_sequence_free_ex(Scene *scene,
BKE_sound_remove_scene_sound(scene, seq->scene_sound);
}
- seq_free_animdata(scene, seq);
+ /* XXX This must not be done in BKE code. */
+ if (do_clean_animdata) {
+ seq_free_animdata(scene, seq);
+ }
}
if (seq->prop) {
@@ -290,9 +306,9 @@ static void BKE_sequence_free_ex(Scene *scene,
MEM_freeN(seq);
}
-void BKE_sequence_free(Scene *scene, Sequence *seq)
+void BKE_sequence_free(Scene *scene, Sequence *seq, const bool do_clean_animdata)
{
- BKE_sequence_free_ex(scene, seq, true, true);
+ BKE_sequence_free_ex(scene, seq, true, true, do_clean_animdata);
}
/* Function to free imbuf and anim data on changes */
@@ -322,7 +338,7 @@ static void seq_free_sequence_recurse(Scene *scene, Sequence *seq, const bool do
seq_free_sequence_recurse(scene, iseq, do_id_user);
}
- BKE_sequence_free_ex(scene, seq, false, do_id_user);
+ BKE_sequence_free_ex(scene, seq, false, do_id_user, true);
}
Editing *BKE_sequencer_editing_get(Scene *scene, bool alloc)
@@ -492,7 +508,7 @@ void BKE_sequencer_editing_free(Scene *scene, const bool do_id_user)
SEQ_BEGIN (ed, seq) {
/* handle cache freeing above */
- BKE_sequence_free_ex(scene, seq, false, do_id_user);
+ BKE_sequence_free_ex(scene, seq, false, do_id_user, false);
}
SEQ_END;
@@ -752,10 +768,10 @@ static int metaseq_end(Sequence *metaseq)
return metaseq->start + metaseq->len - metaseq->endofs;
}
-static void seq_update_sound_bounds_recursive_rec(Scene *scene,
- Sequence *metaseq,
- int start,
- int end)
+static void seq_update_sound_bounds_recursive_impl(Scene *scene,
+ Sequence *metaseq,
+ int start,
+ int end)
{
Sequence *seq;
@@ -763,7 +779,7 @@ static void seq_update_sound_bounds_recursive_rec(Scene *scene,
* since sound is played outside of evaluating the imbufs, */
for (seq = metaseq->seqbase.first; seq; seq = seq->next) {
if (seq->type == SEQ_TYPE_META) {
- seq_update_sound_bounds_recursive_rec(
+ seq_update_sound_bounds_recursive_impl(
scene, seq, max_ii(start, metaseq_start(seq)), min_ii(end, metaseq_end(seq)));
}
else if (ELEM(seq->type, SEQ_TYPE_SOUND_RAM, SEQ_TYPE_SCENE)) {
@@ -790,7 +806,7 @@ static void seq_update_sound_bounds_recursive_rec(Scene *scene,
static void seq_update_sound_bounds_recursive(Scene *scene, Sequence *metaseq)
{
- seq_update_sound_bounds_recursive_rec(
+ seq_update_sound_bounds_recursive_impl(
scene, metaseq, metaseq_start(metaseq), metaseq_end(metaseq));
}
@@ -1138,7 +1154,7 @@ int BKE_sequencer_cmp_time_startdisp(const void *a, const void *b)
return (seq_a->startdisp > seq_b->startdisp);
}
-static int clear_scene_in_allseqs_cb(Sequence *seq, void *arg_pt)
+static int clear_scene_in_allseqs_fn(Sequence *seq, void *arg_pt)
{
if (seq->scene == (Scene *)arg_pt) {
seq->scene = NULL;
@@ -1154,7 +1170,7 @@ void BKE_sequencer_clear_scene_in_allseqs(Main *bmain, Scene *scene)
for (scene_iter = bmain->scenes.first; scene_iter; scene_iter = scene_iter->id.next) {
if (scene_iter != scene && scene_iter->ed) {
BKE_sequencer_base_recursive_apply(
- &scene_iter->ed->seqbase, clear_scene_in_allseqs_cb, scene);
+ &scene_iter->ed->seqbase, clear_scene_in_allseqs_fn, scene);
}
}
}
@@ -1184,7 +1200,7 @@ static void seqbase_unique_name(ListBase *seqbasep, SeqUniqueInfo *sui)
}
}
-static int seqbase_unique_name_recursive_cb(Sequence *seq, void *arg_pt)
+static int seqbase_unique_name_recursive_fn(Sequence *seq, void *arg_pt)
{
if (seq->seqbase.first) {
seqbase_unique_name(&seq->seqbase, (SeqUniqueInfo *)arg_pt);
@@ -1216,7 +1232,7 @@ void BKE_sequence_base_unique_name_recursive(ListBase *seqbasep, Sequence *seq)
while (sui.match) {
sui.match = 0;
seqbase_unique_name(seqbasep, &sui);
- BKE_sequencer_base_recursive_apply(seqbasep, seqbase_unique_name_recursive_cb, &sui);
+ BKE_sequencer_base_recursive_apply(seqbasep, seqbase_unique_name_recursive_fn, &sui);
}
BLI_strncpy(seq->name + 2, sui.name_dest, sizeof(seq->name) - 2);
@@ -1381,7 +1397,7 @@ static void multibuf(ImBuf *ibuf, const float fmul)
}
}
-static float give_stripelem_index(Sequence *seq, float cfra)
+float BKE_sequencer_give_stripelem_index(Sequence *seq, float cfra)
{
float nr;
int sta = seq->start;
@@ -1439,7 +1455,7 @@ StripElem *BKE_sequencer_give_stripelem(Sequence *seq, int cfra)
* all other strips don't use this...
*/
- int nr = (int)give_stripelem_index(seq, cfra);
+ int nr = (int)BKE_sequencer_give_stripelem_index(seq, cfra);
if (nr == -1 || se == NULL) {
return NULL;
@@ -1458,7 +1474,7 @@ static int evaluate_seq_frame_gen(Sequence **seq_arr, ListBase *seqbase, int cfr
memset(seq_arr, 0, sizeof(Sequence *) * (MAXSEQ + 1));
- for (Sequence *seq = seqbase->first; seq; seq = seq->next) {
+ LISTBASE_FOREACH (Sequence *, seq, seqbase) {
if ((seq->startdisp <= cfra) && (seq->enddisp > cfra)) {
if ((seq->type & SEQ_TYPE_EFFECT) && !(seq->flag & SEQ_MUTE)) {
@@ -1522,7 +1538,10 @@ static bool video_seq_is_rendered(Sequence *seq)
return (seq && !(seq->flag & SEQ_MUTE) && seq->type != SEQ_TYPE_SOUND_RAM);
}
-static int get_shown_sequences(ListBase *seqbasep, int cfra, int chanshown, Sequence **seq_arr_out)
+int BKE_sequencer_get_shown_sequences(ListBase *seqbasep,
+ int cfra,
+ int chanshown,
+ Sequence **seq_arr_out)
{
Sequence *seq_arr[MAXSEQ + 1];
int b = chanshown;
@@ -1876,7 +1895,7 @@ static bool seq_proxy_get_fname(Editing *ed,
frameno = 1;
}
else {
- frameno = (int)give_stripelem_index(seq, cfra) + seq->anim_startofs;
+ frameno = (int)BKE_sequencer_give_stripelem_index(seq, cfra) + seq->anim_startofs;
BLI_snprintf(name, PROXY_MAXFILE, "%s/proxy_misc/%d/####%s", dir, proxy_size_number, suffix);
}
@@ -1891,9 +1910,10 @@ static bool seq_proxy_get_fname(Editing *ed,
static ImBuf *seq_proxy_fetch(const SeqRenderData *context, Sequence *seq, int cfra)
{
char name[PROXY_MAXFILE];
- IMB_Proxy_Size psize = seq_rendersize_to_proxysize(context->preview_render_size);
- int size_flags;
StripProxy *proxy = seq->strip->proxy;
+ const eSpaceSeq_Proxy_RenderSize psize = context->preview_render_size;
+ const IMB_Proxy_Size psize_flag = seq_rendersize_to_proxysize(psize);
+ int size_flags;
Editing *ed = context->scene->ed;
StripAnim *sanim;
@@ -1904,12 +1924,12 @@ static ImBuf *seq_proxy_fetch(const SeqRenderData *context, Sequence *seq, int c
size_flags = proxy->build_size_flags;
/* only use proxies, if they are enabled (even if present!) */
- if (psize == IMB_PROXY_NONE || (size_flags & psize) == 0) {
+ if (psize_flag == IMB_PROXY_NONE || (size_flags & psize_flag) == 0) {
return NULL;
}
if (proxy->storage & SEQ_STORAGE_PROXY_CUSTOM_FILE) {
- int frameno = (int)give_stripelem_index(seq, cfra) + seq->anim_startofs;
+ int frameno = (int)BKE_sequencer_give_stripelem_index(seq, cfra) + seq->anim_startofs;
if (proxy->anim == NULL) {
if (seq_proxy_get_fname(ed, seq, cfra, psize, name, context->view_id) == 0) {
return NULL;
@@ -2874,15 +2894,15 @@ static void *render_effect_execute_do_thread(void *thread_data_v)
return NULL;
}
-static ImBuf *seq_render_effect_execute_threaded(struct SeqEffectHandle *sh,
- const SeqRenderData *context,
- Sequence *seq,
- float cfra,
- float facf0,
- float facf1,
- ImBuf *ibuf1,
- ImBuf *ibuf2,
- ImBuf *ibuf3)
+ImBuf *BKE_sequencer_effect_execute_threaded(struct SeqEffectHandle *sh,
+ const SeqRenderData *context,
+ Sequence *seq,
+ float cfra,
+ float facf0,
+ float facf1,
+ ImBuf *ibuf1,
+ ImBuf *ibuf2,
+ ImBuf *ibuf3)
{
RenderEffectInitData init_data;
ImBuf *out = sh->init_execution(context, ibuf1, ibuf2, ibuf3);
@@ -2956,14 +2976,21 @@ static ImBuf *seq_render_effect_strip_impl(const SeqRenderData *context,
break;
case EARLY_DO_EFFECT:
for (i = 0; i < 3; i++) {
- if (input[i]) {
- ibuf[i] = seq_render_strip(context, state, input[i], cfra);
+ /* Speed effect requires time remapping of cfra for input(s). */
+ if (input[1] && seq->type == SEQ_TYPE_SPEED) {
+ float target_frame = BKE_sequencer_speed_effect_target_frame_get(context, seq, cfra, i);
+ ibuf[i] = seq_render_strip(context, state, input[i], target_frame);
+ }
+ else { /* Other effects. */
+ if (input[i]) {
+ ibuf[i] = seq_render_strip(context, state, input[i], cfra);
+ }
}
}
if (ibuf[0] && ibuf[1]) {
if (sh.multithreaded) {
- out = seq_render_effect_execute_threaded(
+ out = BKE_sequencer_effect_execute_threaded(
&sh, context, seq, cfra, fac, facf, ibuf[0], ibuf[1], ibuf[2]);
}
else {
@@ -3025,7 +3052,6 @@ static ImBuf *seq_render_image_strip(const SeqRenderData *context,
struct ImBuf **ibufs_arr;
char prefix[FILE_MAX];
const char *ext = NULL;
- int i;
if (totfiles > 1) {
BKE_scene_multiview_view_prefix_get(context->scene, name, prefix, &ext);
@@ -3040,21 +3066,21 @@ static ImBuf *seq_render_image_strip(const SeqRenderData *context,
totviews = BKE_scene_multiview_num_views_get(&context->scene->r);
ibufs_arr = MEM_callocN(sizeof(ImBuf *) * totviews, "Sequence Image Views Imbufs");
- for (i = 0; i < totfiles; i++) {
+ for (int view_id = 0; view_id < totfiles; view_id++) {
if (prefix[0] == '\0') {
- ibufs_arr[i] = IMB_loadiffname(name, flag, seq->strip->colorspace_settings.name);
+ ibufs_arr[view_id] = IMB_loadiffname(name, flag, seq->strip->colorspace_settings.name);
}
else {
char str[FILE_MAX];
- seq_multiview_name(context->scene, i, prefix, ext, str, FILE_MAX);
- ibufs_arr[i] = IMB_loadiffname(str, flag, seq->strip->colorspace_settings.name);
+ seq_multiview_name(context->scene, view_id, prefix, ext, str, FILE_MAX);
+ ibufs_arr[view_id] = IMB_loadiffname(str, flag, seq->strip->colorspace_settings.name);
}
- if (ibufs_arr[i]) {
+ if (ibufs_arr[view_id]) {
/* we don't need both (speed reasons)! */
- if (ibufs_arr[i]->rect_float && ibufs_arr[i]->rect) {
- imb_freerectImBuf(ibufs_arr[i]);
+ if (ibufs_arr[view_id]->rect_float && ibufs_arr[view_id]->rect) {
+ imb_freerectImBuf(ibufs_arr[view_id]);
}
}
}
@@ -3063,17 +3089,17 @@ static ImBuf *seq_render_image_strip(const SeqRenderData *context,
IMB_ImBufFromStereo3d(seq->stereo3d_format, ibufs_arr[0], &ibufs_arr[0], &ibufs_arr[1]);
}
- for (i = 0; i < totviews; i++) {
- if (ibufs_arr[i]) {
+ for (int view_id = 0; view_id < totviews; view_id++) {
+ if (ibufs_arr[view_id]) {
SeqRenderData localcontext = *context;
- localcontext.view_id = i;
+ localcontext.view_id = view_id;
/* all sequencer color is done in SRGB space, linear gives odd crossfades */
- BKE_sequencer_imbuf_to_sequencer_space(context->scene, ibufs_arr[i], false);
+ BKE_sequencer_imbuf_to_sequencer_space(context->scene, ibufs_arr[view_id], false);
- if (i != context->view_id) {
- BKE_sequencer_cache_put(
- &localcontext, seq, cfra, SEQ_CACHE_STORE_PREPROCESSED, ibufs_arr[i], 0, false);
+ if (view_id != context->view_id) {
+ ibufs_arr[view_id] = seq_render_preprocess_ibuf(
+ &localcontext, seq, ibufs_arr[view_id], cfra, clock(), true, false, false);
}
}
}
@@ -3086,9 +3112,9 @@ static ImBuf *seq_render_image_strip(const SeqRenderData *context,
}
/* "remove" the others (decrease their refcount) */
- for (i = 0; i < totviews; i++) {
- if (ibufs_arr[i] != ibuf) {
- IMB_freeImBuf(ibufs_arr[i]);
+ for (int view_id = 0; view_id < totviews; view_id++) {
+ if (ibufs_arr[view_id] != ibuf) {
+ IMB_freeImBuf(ibufs_arr[view_id]);
}
}
@@ -3136,7 +3162,7 @@ static ImBuf *seq_render_movie_strip(const SeqRenderData *context,
ImBuf **ibuf_arr;
const int totfiles = seq_num_files(context->scene, seq->views_format, true);
int totviews;
- int i;
+ int ibuf_view_id;
if (totfiles != BLI_listbase_count_at_most(&seq->anims, totfiles + 1)) {
goto monoview_movie;
@@ -3145,28 +3171,28 @@ static ImBuf *seq_render_movie_strip(const SeqRenderData *context,
totviews = BKE_scene_multiview_num_views_get(&context->scene->r);
ibuf_arr = MEM_callocN(sizeof(ImBuf *) * totviews, "Sequence Image Views Imbufs");
- for (i = 0, sanim = seq->anims.first; sanim; sanim = sanim->next, i++) {
+ for (ibuf_view_id = 0, sanim = seq->anims.first; sanim; sanim = sanim->next, ibuf_view_id++) {
if (sanim->anim) {
IMB_anim_set_preseek(sanim->anim, seq->anim_preseek);
- ibuf_arr[i] = IMB_anim_absolute(sanim->anim,
- nr + seq->anim_startofs,
- seq->strip->proxy ? seq->strip->proxy->tc :
- IMB_TC_RECORD_RUN,
- psize);
+ ibuf_arr[ibuf_view_id] = IMB_anim_absolute(sanim->anim,
+ nr + seq->anim_startofs,
+ seq->strip->proxy ? seq->strip->proxy->tc :
+ IMB_TC_RECORD_RUN,
+ psize);
/* fetching for requested proxy size failed, try fetching the original instead */
- if (!ibuf_arr[i] && psize != IMB_PROXY_NONE) {
- ibuf_arr[i] = IMB_anim_absolute(sanim->anim,
- nr + seq->anim_startofs,
- seq->strip->proxy ? seq->strip->proxy->tc :
- IMB_TC_RECORD_RUN,
- IMB_PROXY_NONE);
+ if (!ibuf_arr[ibuf_view_id] && psize != IMB_PROXY_NONE) {
+ ibuf_arr[ibuf_view_id] = IMB_anim_absolute(sanim->anim,
+ nr + seq->anim_startofs,
+ seq->strip->proxy ? seq->strip->proxy->tc :
+ IMB_TC_RECORD_RUN,
+ IMB_PROXY_NONE);
}
- if (ibuf_arr[i]) {
+ if (ibuf_arr[ibuf_view_id]) {
/* we don't need both (speed reasons)! */
- if (ibuf_arr[i]->rect_float && ibuf_arr[i]->rect) {
- imb_freerectImBuf(ibuf_arr[i]);
+ if (ibuf_arr[ibuf_view_id]->rect_float && ibuf_arr[ibuf_view_id]->rect) {
+ imb_freerectImBuf(ibuf_arr[ibuf_view_id]);
}
}
}
@@ -3183,17 +3209,17 @@ static ImBuf *seq_render_movie_strip(const SeqRenderData *context,
}
}
- for (i = 0; i < totviews; i++) {
+ for (int view_id = 0; view_id < totviews; view_id++) {
SeqRenderData localcontext = *context;
- localcontext.view_id = i;
+ localcontext.view_id = view_id;
- if (ibuf_arr[i]) {
+ if (ibuf_arr[view_id]) {
/* all sequencer color is done in SRGB space, linear gives odd crossfades */
- BKE_sequencer_imbuf_to_sequencer_space(context->scene, ibuf_arr[i], false);
+ BKE_sequencer_imbuf_to_sequencer_space(context->scene, ibuf_arr[view_id], false);
}
- if (i != context->view_id) {
- BKE_sequencer_cache_put(
- &localcontext, seq, cfra, SEQ_CACHE_STORE_PREPROCESSED, ibuf_arr[i], 0, false);
+ if (view_id != context->view_id) {
+ ibuf_arr[view_id] = seq_render_preprocess_ibuf(
+ &localcontext, seq, ibuf_arr[view_id], cfra, clock(), true, false, false);
}
}
@@ -3205,9 +3231,9 @@ static ImBuf *seq_render_movie_strip(const SeqRenderData *context,
}
/* "remove" the others (decrease their refcount) */
- for (i = 0; i < totviews; i++) {
- if (ibuf_arr[i] != ibuf) {
- IMB_freeImBuf(ibuf_arr[i]);
+ for (int view_id = 0; view_id < totviews; view_id++) {
+ if (ibuf_arr[view_id] != ibuf) {
+ IMB_freeImBuf(ibuf_arr[view_id]);
}
}
@@ -3318,8 +3344,7 @@ static ImBuf *seq_render_mask(const SeqRenderData *context, Mask *mask, float nr
/* anim-data */
adt = BKE_animdata_from_id(&mask->id);
- BKE_animsys_evaluate_animdata(
- context->scene, &mask_temp->id, adt, mask->sfra + nr, ADT_RECALC_ANIM, false);
+ BKE_animsys_evaluate_animdata(&mask_temp->id, adt, mask->sfra + nr, ADT_RECALC_ANIM, false);
maskbuf = MEM_mallocN(sizeof(float) * context->rectx * context->recty, __func__);
@@ -3450,6 +3475,11 @@ static ImBuf *seq_render_scene_strip(const SeqRenderData *context,
return NULL;
}
+ /* Prevent rendering scene recursively. */
+ if (seq->scene == context->scene) {
+ return NULL;
+ }
+
scene = seq->scene;
frame = (double)scene->r.sfra + (double)nr + (double)seq->anim_startofs;
@@ -3498,7 +3528,7 @@ static ImBuf *seq_render_scene_strip(const SeqRenderData *context,
is_frame_update = (orig_data.cfra != scene->r.cfra) || (orig_data.subframe != scene->r.subframe);
- if ((sequencer_view3d_cb && do_seq_gl && camera) && is_thread_main) {
+ if ((sequencer_view3d_fn && do_seq_gl && camera) && is_thread_main) {
char err_out[256] = "unknown";
const int width = (scene->r.xsch * scene->r.size) / 100;
const int height = (scene->r.ysch * scene->r.size) / 100;
@@ -3519,7 +3549,7 @@ static ImBuf *seq_render_scene_strip(const SeqRenderData *context,
/* opengl offscreen render */
depsgraph = BKE_scene_get_depsgraph(context->bmain, scene, view_layer, true);
BKE_scene_graph_update_for_newframe(depsgraph, context->bmain);
- ibuf = sequencer_view3d_cb(
+ ibuf = sequencer_view3d_fn(
/* set for OpenGL render (NULL when scrubbing) */
depsgraph,
scene,
@@ -3541,7 +3571,6 @@ static ImBuf *seq_render_scene_strip(const SeqRenderData *context,
else {
Render *re = RE_GetSceneRender(scene);
const int totviews = BKE_scene_multiview_num_views_get(&scene->r);
- int i;
ImBuf **ibufs_arr;
ibufs_arr = MEM_callocN(sizeof(ImBuf *) * totviews, "Sequence Image Views Imbufs");
@@ -3566,34 +3595,37 @@ static ImBuf *seq_render_scene_strip(const SeqRenderData *context,
G.is_rendering = is_rendering;
}
- for (i = 0; i < totviews; i++) {
+ for (int view_id = 0; view_id < totviews; view_id++) {
SeqRenderData localcontext = *context;
RenderResult rres;
- localcontext.view_id = i;
+ localcontext.view_id = view_id;
- RE_AcquireResultImage(re, &rres, i);
+ RE_AcquireResultImage(re, &rres, view_id);
if (rres.rectf) {
- ibufs_arr[i] = IMB_allocImBuf(rres.rectx, rres.recty, 32, IB_rectfloat);
- memcpy(ibufs_arr[i]->rect_float, rres.rectf, 4 * sizeof(float) * rres.rectx * rres.recty);
+ ibufs_arr[view_id] = IMB_allocImBuf(rres.rectx, rres.recty, 32, IB_rectfloat);
+ memcpy(ibufs_arr[view_id]->rect_float,
+ rres.rectf,
+ 4 * sizeof(float) * rres.rectx * rres.recty);
if (rres.rectz) {
- addzbuffloatImBuf(ibufs_arr[i]);
- memcpy(ibufs_arr[i]->zbuf_float, rres.rectz, sizeof(float) * rres.rectx * rres.recty);
+ addzbuffloatImBuf(ibufs_arr[view_id]);
+ memcpy(
+ ibufs_arr[view_id]->zbuf_float, rres.rectz, sizeof(float) * rres.rectx * rres.recty);
}
/* float buffers in the sequencer are not linear */
- BKE_sequencer_imbuf_to_sequencer_space(context->scene, ibufs_arr[i], false);
+ BKE_sequencer_imbuf_to_sequencer_space(context->scene, ibufs_arr[view_id], false);
}
else if (rres.rect32) {
- ibufs_arr[i] = IMB_allocImBuf(rres.rectx, rres.recty, 32, IB_rect);
- memcpy(ibufs_arr[i]->rect, rres.rect32, 4 * rres.rectx * rres.recty);
+ ibufs_arr[view_id] = IMB_allocImBuf(rres.rectx, rres.recty, 32, IB_rect);
+ memcpy(ibufs_arr[view_id]->rect, rres.rect32, 4 * rres.rectx * rres.recty);
}
- if (i != context->view_id) {
+ if (view_id != context->view_id) {
BKE_sequencer_cache_put(
- &localcontext, seq, cfra, SEQ_CACHE_STORE_RAW, ibufs_arr[i], 0, false);
+ &localcontext, seq, cfra, SEQ_CACHE_STORE_RAW, ibufs_arr[view_id], 0, false);
}
RE_ReleaseResultImage(re);
@@ -3603,9 +3635,9 @@ static ImBuf *seq_render_scene_strip(const SeqRenderData *context,
ibuf = ibufs_arr[context->view_id];
/* "remove" the others (decrease their refcount) */
- for (i = 0; i < totviews; i++) {
- if (ibufs_arr[i] != ibuf) {
- IMB_freeImBuf(ibufs_arr[i]);
+ for (int view_id = 0; view_id < totviews; view_id++) {
+ if (ibufs_arr[view_id] != ibuf) {
+ IMB_freeImBuf(ibufs_arr[view_id]);
}
}
MEM_freeN(ibufs_arr);
@@ -3646,8 +3678,7 @@ static ImBuf *do_render_strip_seqbase(const SeqRenderData *context,
if (seqbase && !BLI_listbase_is_empty(seqbase)) {
if (seq->flag & SEQ_SCENE_STRIPS && seq->scene) {
- BKE_animsys_evaluate_all_animation(
- context->bmain, context->depsgraph, seq->scene, nr + offset);
+ BKE_animsys_evaluate_all_animation(context->bmain, context->depsgraph, nr + offset);
}
ibuf = seq_render_strip_stack(context,
@@ -3667,9 +3698,8 @@ static ImBuf *do_render_strip_uncached(const SeqRenderData *context,
float cfra)
{
ImBuf *ibuf = NULL;
- float nr = give_stripelem_index(seq, cfra);
- int type = (seq->type & SEQ_TYPE_EFFECT && seq->type != SEQ_TYPE_SPEED) ? SEQ_TYPE_EFFECT :
- seq->type;
+ float nr = BKE_sequencer_give_stripelem_index(seq, cfra);
+ int type = (seq->type & SEQ_TYPE_EFFECT) ? SEQ_TYPE_EFFECT : seq->type;
switch (type) {
case SEQ_TYPE_META: {
ibuf = do_render_strip_seqbase(context, state, seq, nr);
@@ -3711,21 +3741,8 @@ static ImBuf *do_render_strip_uncached(const SeqRenderData *context,
break;
}
- case SEQ_TYPE_SPEED: {
- float f_cfra;
- SpeedControlVars *s = (SpeedControlVars *)seq->effectdata;
-
- BKE_sequence_effect_speed_rebuild_map(context->scene, seq, false);
-
- /* weeek! */
- f_cfra = seq->start + s->frameMap[(int)nr];
- ibuf = seq_render_strip(context, state, seq->seq1, f_cfra);
-
- break;
- }
-
case SEQ_TYPE_EFFECT: {
- ibuf = seq_render_effect_strip_impl(context, state, seq, seq->start + nr);
+ ibuf = seq_render_effect_strip_impl(context, state, seq, cfra);
break;
}
@@ -3790,6 +3807,34 @@ static float seq_estimate_render_cost_end(Scene *scene, clock_t begin)
}
}
+static ImBuf *seq_render_preprocess_ibuf(const SeqRenderData *context,
+ Sequence *seq,
+ ImBuf *ibuf,
+ float cfra,
+ clock_t begin,
+ bool use_preprocess,
+ const bool is_proxy_image,
+ const bool is_preprocessed)
+{
+ if (context->is_proxy_render == false &&
+ (ibuf->x != context->rectx || ibuf->y != context->recty)) {
+ use_preprocess = true;
+ }
+
+ if (use_preprocess) {
+ float cost = seq_estimate_render_cost_end(context->scene, begin);
+ BKE_sequencer_cache_put(context, seq, cfra, SEQ_CACHE_STORE_RAW, ibuf, cost, false);
+
+ /* Reset timer so we can get partial render time. */
+ begin = seq_estimate_render_cost_begin();
+ ibuf = input_preprocess(context, seq, cfra, ibuf, is_proxy_image, is_preprocessed);
+ }
+
+ float cost = seq_estimate_render_cost_end(context->scene, begin);
+ BKE_sequencer_cache_put(context, seq, cfra, SEQ_CACHE_STORE_PREPROCESSED, ibuf, cost, false);
+ return ibuf;
+}
+
static ImBuf *seq_render_strip(const SeqRenderData *context,
SeqRenderState *state,
Sequence *seq,
@@ -3838,22 +3883,8 @@ static ImBuf *seq_render_strip(const SeqRenderData *context,
sequencer_imbuf_assign_spaces(context->scene, ibuf);
}
- if (context->is_proxy_render == false &&
- (ibuf->x != context->rectx || ibuf->y != context->recty)) {
- use_preprocess = true;
- }
-
- if (use_preprocess) {
- float cost = seq_estimate_render_cost_end(context->scene, begin);
- BKE_sequencer_cache_put(context, seq, cfra, SEQ_CACHE_STORE_RAW, ibuf, cost, false);
-
- /* reset timer so we can get partial render time */
- begin = seq_estimate_render_cost_begin();
- ibuf = input_preprocess(context, seq, cfra, ibuf, is_proxy_image, is_preprocessed);
- }
-
- float cost = seq_estimate_render_cost_end(context->scene, begin);
- BKE_sequencer_cache_put(context, seq, cfra, SEQ_CACHE_STORE_PREPROCESSED, ibuf, cost, false);
+ ibuf = seq_render_preprocess_ibuf(
+ context, seq, ibuf, cfra, begin, use_preprocess, is_proxy_image, is_preprocessed);
}
return ibuf;
}
@@ -3905,7 +3936,7 @@ static ImBuf *seq_render_strip_stack_apply_effect(
if (swap_input) {
if (sh.multithreaded) {
- out = seq_render_effect_execute_threaded(
+ out = BKE_sequencer_effect_execute_threaded(
&sh, context, seq, cfra, facf, facf, ibuf2, ibuf1, NULL);
}
else {
@@ -3914,7 +3945,7 @@ static ImBuf *seq_render_strip_stack_apply_effect(
}
else {
if (sh.multithreaded) {
- out = seq_render_effect_execute_threaded(
+ out = BKE_sequencer_effect_execute_threaded(
&sh, context, seq, cfra, facf, facf, ibuf1, ibuf2, NULL);
}
else {
@@ -3937,7 +3968,7 @@ static ImBuf *seq_render_strip_stack(const SeqRenderData *context,
ImBuf *out = NULL;
clock_t begin;
- count = get_shown_sequences(seqbasep, cfra, chanshown, (Sequence **)&seq_arr);
+ count = BKE_sequencer_get_shown_sequences(seqbasep, cfra, chanshown, (Sequence **)&seq_arr);
if (count == 0) {
return NULL;
@@ -4045,7 +4076,7 @@ ImBuf *BKE_sequencer_give_ibuf(const SeqRenderData *context, float cfra, int cha
Sequence *seq_arr[MAXSEQ + 1];
int count;
- count = get_shown_sequences(seqbasep, cfra, chanshown, seq_arr);
+ count = BKE_sequencer_get_shown_sequences(seqbasep, cfra, chanshown, seq_arr);
if (count) {
out = BKE_sequencer_cache_get(
@@ -4138,8 +4169,15 @@ static void sequence_do_invalidate_dependent(Scene *scene, Sequence *seq, ListBa
}
if (BKE_sequence_check_depend(seq, cur)) {
- BKE_sequencer_cache_cleanup_sequence(
- scene, cur, seq, SEQ_CACHE_STORE_COMPOSITE | SEQ_CACHE_STORE_FINAL_OUT);
+ /* Effect must be invalidated completely if they depend on invalidated seq. */
+ if ((cur->type & SEQ_TYPE_EFFECT) != 0) {
+ BKE_sequencer_cache_cleanup_sequence(scene, cur, seq, SEQ_CACHE_ALL_TYPES, false);
+ }
+ else {
+ /* In case of alpha over for example only invalidate composite image */
+ BKE_sequencer_cache_cleanup_sequence(
+ scene, cur, seq, SEQ_CACHE_STORE_COMPOSITE | SEQ_CACHE_STORE_FINAL_OUT, false);
+ }
}
if (cur->seqbase.first) {
@@ -4157,7 +4195,7 @@ static void sequence_invalidate_cache(Scene *scene,
if (invalidate_self) {
BKE_sequence_free_anim(seq);
- BKE_sequencer_cache_cleanup_sequence(scene, seq, seq, invalidate_types);
+ BKE_sequencer_cache_cleanup_sequence(scene, seq, seq, invalidate_types, false);
}
if (seq->effectdata && seq->type == SEQ_TYPE_SPEED) {
@@ -4169,6 +4207,14 @@ static void sequence_invalidate_cache(Scene *scene,
BKE_sequencer_prefetch_stop(scene);
}
+void BKE_sequence_invalidate_cache_in_range(Scene *scene,
+ Sequence *seq,
+ Sequence *range_mask,
+ int invalidate_types)
+{
+ BKE_sequencer_cache_cleanup_sequence(scene, seq, range_mask, invalidate_types, true);
+}
+
void BKE_sequence_invalidate_cache_raw(Scene *scene, Sequence *seq)
{
sequence_invalidate_cache(scene, seq, true, SEQ_CACHE_ALL_TYPES);
@@ -4568,6 +4614,10 @@ bool BKE_sequence_test_overlap(ListBase *seqbasep, Sequence *test)
void BKE_sequence_translate(Scene *evil_scene, Sequence *seq, int delta)
{
+ if (delta == 0) {
+ return;
+ }
+
BKE_sequencer_offset_animdata(evil_scene, seq, delta);
seq->start += delta;
@@ -5069,7 +5119,7 @@ void BKE_sequencer_dupe_animdata(Scene *scene, const char *name_src, const char
for (fcu = scene->adt->action->curves.first; fcu && fcu->prev != fcu_last; fcu = fcu->next) {
if (STREQLEN(fcu->rna_path, str_from, str_from_len)) {
- fcu_cpy = copy_fcurve(fcu);
+ fcu_cpy = BKE_fcurve_copy(fcu);
BLI_addtail(&lb, fcu_cpy);
}
}
@@ -5102,7 +5152,7 @@ static void seq_free_animdata(Scene *scene, Sequence *seq)
FCurve *next_fcu = fcu->next;
BLI_remlink(&scene->adt->action->curves, fcu);
- free_fcurve(fcu);
+ BKE_fcurve_free(fcu);
fcu = next_fcu;
}
@@ -5775,7 +5825,7 @@ void BKE_sequence_base_dupli_recursive(const Scene *scene_src,
Sequence *seqn = NULL;
Sequence *last_seq = BKE_sequencer_active_get((Scene *)scene_src);
/* always include meta's strips */
- int dupe_flag_recursive = dupe_flag | SEQ_DUPE_ALL;
+ int dupe_flag_recursive = dupe_flag | SEQ_DUPE_ALL | SEQ_DUPE_IS_RECURSIVE_CALL;
for (seq = seqbase->first; seq; seq = seq->next) {
seq->tmp = NULL;
@@ -5801,6 +5851,12 @@ void BKE_sequence_base_dupli_recursive(const Scene *scene_src,
}
}
+ /* Fix modifier links recursively from the top level only, when all sequences have been
+ * copied. */
+ if (dupe_flag & SEQ_DUPE_IS_RECURSIVE_CALL) {
+ return;
+ }
+
/* fix modifier linking */
for (seq = nseqbase->first; seq; seq = seq->next) {
seq_new_fix_links_recursive(seq);
@@ -5921,3 +5977,62 @@ void BKE_sequencer_all_free_anim_ibufs(Scene *scene, int cfra)
sequencer_all_free_anim_ibufs(&ed->seqbase, cfra);
BKE_sequencer_cache_cleanup(scene);
}
+
+static bool sequencer_seq_generates_image(Sequence *seq)
+{
+ switch (seq->type) {
+ case SEQ_TYPE_IMAGE:
+ case SEQ_TYPE_SCENE:
+ case SEQ_TYPE_MOVIE:
+ case SEQ_TYPE_MOVIECLIP:
+ case SEQ_TYPE_MASK:
+ case SEQ_TYPE_COLOR:
+ case SEQ_TYPE_TEXT:
+ return true;
+ }
+ return false;
+}
+
+static Sequence *sequencer_check_scene_recursion(Scene *scene, ListBase *seqbase)
+{
+ LISTBASE_FOREACH (Sequence *, seq, seqbase) {
+ if (seq->type == SEQ_TYPE_SCENE && seq->scene == scene) {
+ return seq;
+ }
+
+ if (seq->type == SEQ_TYPE_META && sequencer_check_scene_recursion(scene, &seq->seqbase)) {
+ return seq;
+ }
+ }
+
+ return NULL;
+}
+
+bool BKE_sequencer_check_scene_recursion(Scene *scene, ReportList *reports)
+{
+ Editing *ed = BKE_sequencer_editing_get(scene, false);
+ if (ed == NULL) {
+ return false;
+ }
+
+ Sequence *recursive_seq = sequencer_check_scene_recursion(scene, &ed->seqbase);
+
+ if (recursive_seq != NULL) {
+ BKE_reportf(reports,
+ RPT_WARNING,
+ "Recursion detected in video sequencer. Strip %s at frame %d will not be rendered",
+ recursive_seq->name + 2,
+ recursive_seq->startdisp);
+
+ LISTBASE_FOREACH (Sequence *, seq, &ed->seqbase) {
+ if (seq->type != SEQ_TYPE_SCENE && sequencer_seq_generates_image(seq)) {
+ /* There are other strips to render, so render them. */
+ return false;
+ }
+ }
+ /* No other strips to render - cancel operator. */
+ return true;
+ }
+
+ return false;
+}
diff --git a/source/blender/blenkernel/intern/shader_fx.c b/source/blender/blenkernel/intern/shader_fx.c
index 8d692782413..0ad61de1ff2 100644
--- a/source/blender/blenkernel/intern/shader_fx.c
+++ b/source/blender/blenkernel/intern/shader_fx.c
@@ -59,7 +59,7 @@ bool BKE_shaderfx_has_gpencil(Object *ob)
{
ShaderFxData *fx;
for (fx = ob->shader_fx.first; fx; fx = fx->next) {
- const ShaderFxTypeInfo *fxi = BKE_shaderfxType_getInfo(fx->type);
+ const ShaderFxTypeInfo *fxi = BKE_shaderfx_get_info(fx->type);
if (fxi->type == eShaderFxType_GpencilType) {
return true;
}
@@ -75,7 +75,7 @@ void BKE_shaderfx_init(void)
ShaderFxData *BKE_shaderfx_new(int type)
{
- const ShaderFxTypeInfo *fxi = BKE_shaderfxType_getInfo(type);
+ const ShaderFxTypeInfo *fxi = BKE_shaderfx_get_info(type);
ShaderFxData *fx = MEM_callocN(fxi->struct_size, fxi->struct_name);
/* note, this name must be made unique later */
@@ -109,7 +109,7 @@ static void shaderfx_free_data_id_us_cb(void *UNUSED(userData),
void BKE_shaderfx_free_ex(ShaderFxData *fx, const int flag)
{
- const ShaderFxTypeInfo *fxi = BKE_shaderfxType_getInfo(fx->type);
+ const ShaderFxTypeInfo *fxi = BKE_shaderfx_get_info(fx->type);
if ((flag & LIB_ID_CREATE_NO_USER_REFCOUNT) == 0) {
if (fxi->foreachIDLink) {
@@ -139,21 +139,21 @@ void BKE_shaderfx_free(ShaderFxData *fx)
bool BKE_shaderfx_unique_name(ListBase *shaders, ShaderFxData *fx)
{
if (shaders && fx) {
- const ShaderFxTypeInfo *fxi = BKE_shaderfxType_getInfo(fx->type);
+ const ShaderFxTypeInfo *fxi = BKE_shaderfx_get_info(fx->type);
return BLI_uniquename(
shaders, fx, DATA_(fxi->name), '.', offsetof(ShaderFxData, name), sizeof(fx->name));
}
return false;
}
-bool BKE_shaderfx_dependsOnTime(ShaderFxData *fx)
+bool BKE_shaderfx_depends_ontime(ShaderFxData *fx)
{
- const ShaderFxTypeInfo *fxi = BKE_shaderfxType_getInfo(fx->type);
+ const ShaderFxTypeInfo *fxi = BKE_shaderfx_get_info(fx->type);
return fxi->dependsOnTime && fxi->dependsOnTime(fx);
}
-const ShaderFxTypeInfo *BKE_shaderfxType_getInfo(ShaderFxType type)
+const ShaderFxTypeInfo *BKE_shaderfx_get_info(ShaderFxType type)
{
/* type unsigned, no need to check < 0 */
if (type < NUM_SHADER_FX_TYPES && shader_fx_types[type]->name[0] != '\0') {
@@ -164,9 +164,9 @@ const ShaderFxTypeInfo *BKE_shaderfxType_getInfo(ShaderFxType type)
}
}
-void BKE_shaderfx_copyData_generic(const ShaderFxData *fx_src, ShaderFxData *fx_dst)
+void BKE_shaderfx_copydata_generic(const ShaderFxData *fx_src, ShaderFxData *fx_dst)
{
- const ShaderFxTypeInfo *fxi = BKE_shaderfxType_getInfo(fx_src->type);
+ const ShaderFxTypeInfo *fxi = BKE_shaderfx_get_info(fx_src->type);
/* fx_dst may have already be fully initialized with some extra allocated data,
* we need to free it now to avoid memleak. */
@@ -192,9 +192,9 @@ static void shaderfx_copy_data_id_us_cb(void *UNUSED(userData),
}
}
-void BKE_shaderfx_copyData_ex(ShaderFxData *fx, ShaderFxData *target, const int flag)
+void BKE_shaderfx_copydata_ex(ShaderFxData *fx, ShaderFxData *target, const int flag)
{
- const ShaderFxTypeInfo *fxi = BKE_shaderfxType_getInfo(fx->type);
+ const ShaderFxTypeInfo *fxi = BKE_shaderfx_get_info(fx->type);
target->mode = fx->mode;
target->flag = fx->flag;
@@ -214,12 +214,12 @@ void BKE_shaderfx_copyData_ex(ShaderFxData *fx, ShaderFxData *target, const int
}
}
-void BKE_shaderfx_copyData(ShaderFxData *fx, ShaderFxData *target)
+void BKE_shaderfx_copydata(ShaderFxData *fx, ShaderFxData *target)
{
- BKE_shaderfx_copyData_ex(fx, target, 0);
+ BKE_shaderfx_copydata_ex(fx, target, 0);
}
-ShaderFxData *BKE_shaderfx_findByType(Object *ob, ShaderFxType type)
+ShaderFxData *BKE_shaderfx_findby_type(Object *ob, ShaderFxType type)
{
ShaderFxData *fx = ob->shader_fx.first;
@@ -232,12 +232,12 @@ ShaderFxData *BKE_shaderfx_findByType(Object *ob, ShaderFxType type)
return fx;
}
-void BKE_shaderfx_foreachIDLink(Object *ob, ShaderFxIDWalkFunc walk, void *userData)
+void BKE_shaderfx_foreach_ID_link(Object *ob, ShaderFxIDWalkFunc walk, void *userData)
{
ShaderFxData *fx = ob->shader_fx.first;
for (; fx; fx = fx->next) {
- const ShaderFxTypeInfo *fxi = BKE_shaderfxType_getInfo(fx->type);
+ const ShaderFxTypeInfo *fxi = BKE_shaderfx_get_info(fx->type);
if (fxi->foreachIDLink) {
fxi->foreachIDLink(fx, ob, walk, userData);
@@ -250,7 +250,7 @@ void BKE_shaderfx_foreachIDLink(Object *ob, ShaderFxIDWalkFunc walk, void *userD
}
}
-ShaderFxData *BKE_shaderfx_findByName(Object *ob, const char *name)
+ShaderFxData *BKE_shaderfx_findby_name(Object *ob, const char *name)
{
return BLI_findstring(&(ob->shader_fx), name, offsetof(ShaderFxData, name));
}
diff --git a/source/blender/blenkernel/intern/shrinkwrap.c b/source/blender/blenkernel/intern/shrinkwrap.c
index 06086cdf56a..c59042bc045 100644
--- a/source/blender/blenkernel/intern/shrinkwrap.c
+++ b/source/blender/blenkernel/intern/shrinkwrap.c
@@ -443,7 +443,7 @@ bool BKE_shrinkwrap_project_normal(char options,
BVHTreeRayHit *hit)
{
/* don't use this because this dist value could be incompatible
- * this value used by the callback for comparing prev/new dist values.
+ * this value used by the callback for comparing previous/new dist values.
* also, at the moment there is no need to have a corrected 'dist' value */
// #define USE_DIST_CORRECT
diff --git a/source/blender/blenkernel/intern/simulation.cc b/source/blender/blenkernel/intern/simulation.cc
new file mode 100644
index 00000000000..d5ba345928b
--- /dev/null
+++ b/source/blender/blenkernel/intern/simulation.cc
@@ -0,0 +1,132 @@
+/*
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+
+/** \file
+ * \ingroup bke
+ */
+
+#include <iostream>
+
+#include "MEM_guardedalloc.h"
+
+#include "DNA_ID.h"
+#include "DNA_defaults.h"
+#include "DNA_scene_types.h"
+#include "DNA_simulation_types.h"
+
+#include "BLI_compiler_compat.h"
+#include "BLI_listbase.h"
+#include "BLI_math.h"
+#include "BLI_string.h"
+#include "BLI_utildefines.h"
+
+#include "BKE_anim_data.h"
+#include "BKE_animsys.h"
+#include "BKE_idtype.h"
+#include "BKE_lib_id.h"
+#include "BKE_lib_query.h"
+#include "BKE_lib_remap.h"
+#include "BKE_main.h"
+#include "BKE_node.h"
+#include "BKE_simulation.h"
+
+#include "NOD_simulation.h"
+
+#include "BLT_translation.h"
+
+#include "DEG_depsgraph.h"
+#include "DEG_depsgraph_query.h"
+
+static void simulation_init_data(ID *id)
+{
+ Simulation *simulation = (Simulation *)id;
+ BLI_assert(MEMCMP_STRUCT_AFTER_IS_ZERO(simulation, id));
+
+ MEMCPY_STRUCT_AFTER(simulation, DNA_struct_default_get(Simulation), id);
+
+ bNodeTree *ntree = ntreeAddTree(nullptr, "Simulation Nodetree", ntreeType_Simulation->idname);
+ simulation->nodetree = ntree;
+}
+
+static void simulation_copy_data(Main *bmain, ID *id_dst, const ID *id_src, const int flag)
+{
+ Simulation *simulation_dst = (Simulation *)id_dst;
+ Simulation *simulation_src = (Simulation *)id_src;
+
+ /* We always need allocation of our private ID data. */
+ const int flag_private_id_data = flag & ~LIB_ID_CREATE_NO_ALLOCATE;
+
+ if (simulation_src->nodetree) {
+ BKE_id_copy_ex(bmain,
+ (ID *)simulation_src->nodetree,
+ (ID **)&simulation_dst->nodetree,
+ flag_private_id_data);
+ }
+}
+
+static void simulation_free_data(ID *id)
+{
+ Simulation *simulation = (Simulation *)id;
+
+ BKE_animdata_free(&simulation->id, false);
+
+ if (simulation->nodetree) {
+ ntreeFreeEmbeddedTree(simulation->nodetree);
+ MEM_freeN(simulation->nodetree);
+ simulation->nodetree = nullptr;
+ }
+}
+
+static void simulation_foreach_id(ID *id, LibraryForeachIDData *data)
+{
+ Simulation *simulation = (Simulation *)id;
+ if (simulation->nodetree) {
+ /* nodetree **are owned by IDs**, treat them as mere sub-data and not real ID! */
+ BKE_library_foreach_ID_embedded(data, (ID **)&simulation->nodetree);
+ }
+}
+
+IDTypeInfo IDType_ID_SIM = {
+ /* id_code */ ID_SIM,
+ /* id_filter */ FILTER_ID_SIM,
+ /* main_listbase_index */ INDEX_ID_SIM,
+ /* struct_size */ sizeof(Simulation),
+ /* name */ "Simulation",
+ /* name_plural */ "simulations",
+ /* translation_context */ BLT_I18NCONTEXT_ID_SIMULATION,
+ /* flags */ 0,
+
+ /* init_data */ simulation_init_data,
+ /* copy_data */ simulation_copy_data,
+ /* free_data */ simulation_free_data,
+ /* make_local */ nullptr,
+ /* foreach_id */ simulation_foreach_id,
+};
+
+void *BKE_simulation_add(Main *bmain, const char *name)
+{
+ Simulation *simulation = (Simulation *)BKE_libblock_alloc(bmain, ID_SIM, name, 0);
+
+ simulation_init_data(&simulation->id);
+
+ return simulation;
+}
+
+void BKE_simulation_data_update(Depsgraph *UNUSED(depsgraph),
+ Scene *UNUSED(scene),
+ Simulation *UNUSED(simulation))
+{
+}
diff --git a/source/blender/blenkernel/intern/softbody.c b/source/blender/blenkernel/intern/softbody.c
index c358dde449f..68d0822a223 100644
--- a/source/blender/blenkernel/intern/softbody.c
+++ b/source/blender/blenkernel/intern/softbody.c
@@ -285,7 +285,7 @@ static ccd_Mesh *ccd_mesh_make(Object *ob)
float hull;
int i;
- cmd = (CollisionModifierData *)modifiers_findByType(ob, eModifierType_Collision);
+ cmd = (CollisionModifierData *)BKE_modifiers_findby_type(ob, eModifierType_Collision);
/* first some paranoia checks */
if (!cmd) {
@@ -371,7 +371,7 @@ static void ccd_mesh_update(Object *ob, ccd_Mesh *pccd_M)
float hull;
int i;
- cmd = (CollisionModifierData *)modifiers_findByType(ob, eModifierType_Collision);
+ cmd = (CollisionModifierData *)BKE_modifiers_findby_type(ob, eModifierType_Collision);
/* first some paranoia checks */
if (!cmd) {
@@ -3010,7 +3010,7 @@ static void curve_surf_to_softbody(Scene *scene, Object *ob)
* (C2= continuous in second derivate -> no jump in bending ) condition.
*
* Not too hard to do, but needs some more code to care for;
- * some one may want look at it JOW 2010/06/12. */
+ * some one may want look at it (JOW 2010/06/12). */
for (bezt = nu->bezt, a = 0; a < nu->pntsu; a++, bezt++, bp += 3, curindex += 3) {
if (setgoal) {
bp->goal *= bezt->weight;
diff --git a/source/blender/blenkernel/intern/sound.c b/source/blender/blenkernel/intern/sound.c
index 3bb95eaeff0..e8f31594cc0 100644
--- a/source/blender/blenkernel/intern/sound.c
+++ b/source/blender/blenkernel/intern/sound.c
@@ -127,6 +127,7 @@ IDTypeInfo IDType_ID_SO = {
.copy_data = sound_copy_data,
.free_data = sound_free_data,
.make_local = NULL,
+ .foreach_id = NULL,
};
#ifdef WITH_AUDASPACE
@@ -550,12 +551,12 @@ void BKE_sound_destroy_scene(Scene *scene)
}
}
-void BKE_sound_lock_scene(struct Scene *scene)
+void BKE_sound_lock()
{
AUD_Device_lock(sound_device);
}
-void BKE_sound_unlock_scene(struct Scene *scene)
+void BKE_sound_unlock()
{
AUD_Device_unlock(sound_device);
}
@@ -751,12 +752,20 @@ static void sound_start_play_scene(Scene *scene)
}
}
+static double get_cur_time(Scene *scene)
+{
+ /* We divide by the current framelen to take into account time remapping.
+ * Otherwise we will get the wrong starting time which will break A/V sync.
+ * See T74111 for further details. */
+ return FRA2TIME((CFRA + SUBFRA) / (double)scene->r.framelen);
+}
+
void BKE_sound_play_scene(Scene *scene)
{
sound_verify_evaluated_id(&scene->id);
AUD_Status status;
- const float cur_time = (float)((double)CFRA / FPS);
+ const double cur_time = get_cur_time(scene);
AUD_Device_lock(sound_device);
@@ -803,8 +812,8 @@ void BKE_sound_seek_scene(Main *bmain, Scene *scene)
bScreen *screen;
int animation_playing;
- const float one_frame = (float)(1.0 / FPS);
- const float cur_time = (float)((double)CFRA / FPS);
+ const double one_frame = 1.0 / FPS;
+ const double cur_time = FRA2TIME(CFRA);
AUD_Device_lock(sound_device);
@@ -861,7 +870,7 @@ void BKE_sound_seek_scene(Main *bmain, Scene *scene)
AUD_Device_unlock(sound_device);
}
-float BKE_sound_sync_scene(Scene *scene)
+double BKE_sound_sync_scene(Scene *scene)
{
sound_verify_evaluated_id(&scene->id);
@@ -1161,10 +1170,10 @@ void BKE_sound_create_scene(Scene *UNUSED(scene))
void BKE_sound_destroy_scene(Scene *UNUSED(scene))
{
}
-void BKE_sound_lock_scene(Scene *UNUSED(scene))
+void BKE_sound_lock(void)
{
}
-void BKE_sound_unlock_scene(Scene *UNUSED(scene))
+void BKE_sound_unlock(void)
{
}
void BKE_sound_reset_scene_specs(Scene *UNUSED(scene))
@@ -1222,7 +1231,7 @@ void BKE_sound_stop_scene(Scene *UNUSED(scene))
void BKE_sound_seek_scene(Main *UNUSED(bmain), Scene *UNUSED(scene))
{
}
-float BKE_sound_sync_scene(Scene *UNUSED(scene))
+double BKE_sound_sync_scene(Scene *UNUSED(scene))
{
return NAN_FLT;
}
@@ -1333,7 +1342,7 @@ void BKE_sound_jack_sync_callback_set(SoundJackSyncCallback callback)
#endif
}
-void BKE_sound_jack_scene_update(Scene *scene, int mode, float time)
+void BKE_sound_jack_scene_update(Scene *scene, int mode, double time)
{
sound_verify_evaluated_id(&scene->id);
diff --git a/source/blender/blenkernel/intern/speaker.c b/source/blender/blenkernel/intern/speaker.c
index d81ebe0fb64..1f778f5fcd6 100644
--- a/source/blender/blenkernel/intern/speaker.c
+++ b/source/blender/blenkernel/intern/speaker.c
@@ -28,9 +28,9 @@
#include "BLT_translation.h"
-#include "BKE_animsys.h"
#include "BKE_idtype.h"
#include "BKE_lib_id.h"
+#include "BKE_lib_query.h"
#include "BKE_main.h"
#include "BKE_speaker.h"
@@ -43,6 +43,13 @@ static void speaker_init_data(ID *id)
MEMCPY_STRUCT_AFTER(speaker, DNA_struct_default_get(Speaker), id);
}
+static void speaker_foreach_id(ID *id, LibraryForeachIDData *data)
+{
+ Speaker *speaker = (Speaker *)id;
+
+ BKE_LIB_FOREACHID_PROCESS(data, speaker->sound, IDWALK_CB_USER);
+}
+
IDTypeInfo IDType_ID_SPK = {
.id_code = ID_SPK,
.id_filter = FILTER_ID_SPK,
@@ -57,6 +64,7 @@ IDTypeInfo IDType_ID_SPK = {
.copy_data = NULL,
.free_data = NULL,
.make_local = NULL,
+ .foreach_id = speaker_foreach_id,
};
void *BKE_speaker_add(Main *bmain, const char *name)
diff --git a/source/blender/blenkernel/intern/studiolight.c b/source/blender/blenkernel/intern/studiolight.c
index 5cb4703bc46..4892e8d6ede 100644
--- a/source/blender/blenkernel/intern/studiolight.c
+++ b/source/blender/blenkernel/intern/studiolight.c
@@ -503,10 +503,8 @@ static void studiolight_create_equirect_radiance_gputexture(StudioLight *sl)
sl->equirect_radiance_gputexture = GPU_texture_create_2d(
ibuf->x, ibuf->y, GPU_RGBA16F, ibuf->rect_float, NULL);
GPUTexture *tex = sl->equirect_radiance_gputexture;
- GPU_texture_bind(tex, 0);
GPU_texture_filter_mode(tex, true);
- GPU_texture_wrap_mode(tex, true);
- GPU_texture_unbind(tex);
+ GPU_texture_wrap_mode(tex, true, true);
}
sl->flag |= STUDIOLIGHT_EQUIRECT_RADIANCE_GPUTEXTURE;
}
@@ -567,10 +565,8 @@ static void studiolight_create_equirect_irradiance_gputexture(StudioLight *sl)
sl->equirect_irradiance_gputexture = GPU_texture_create_2d(
ibuf->x, ibuf->y, GPU_RGBA16F, ibuf->rect_float, NULL);
GPUTexture *tex = sl->equirect_irradiance_gputexture;
- GPU_texture_bind(tex, 0);
GPU_texture_filter_mode(tex, true);
- GPU_texture_wrap_mode(tex, true);
- GPU_texture_unbind(tex);
+ GPU_texture_wrap_mode(tex, true, true);
}
sl->flag |= STUDIOLIGHT_EQUIRECT_IRRADIANCE_GPUTEXTURE;
}
diff --git a/source/blender/blenkernel/intern/subdiv.c b/source/blender/blenkernel/intern/subdiv.c
index 1f7cb225fc7..fe1dd3835fd 100644
--- a/source/blender/blenkernel/intern/subdiv.c
+++ b/source/blender/blenkernel/intern/subdiv.c
@@ -38,6 +38,18 @@
#include "opensubdiv_evaluator_capi.h"
#include "opensubdiv_topology_refiner_capi.h"
+/* =================----====--===== MODULE ==========================------== */
+
+void BKE_subdiv_init()
+{
+ openSubdiv_init();
+}
+
+void BKE_subdiv_exit()
+{
+ openSubdiv_cleanup();
+}
+
/* ========================== CONVERSION HELPERS ============================ */
eSubdivFVarLinearInterpolation BKE_subdiv_fvar_interpolation_from_uv_smooth(int uv_smooth)
diff --git a/source/blender/blenkernel/intern/subdiv_ccg.c b/source/blender/blenkernel/intern/subdiv_ccg.c
index 3c1a9c4d3d6..d5d5530c1ce 100644
--- a/source/blender/blenkernel/intern/subdiv_ccg.c
+++ b/source/blender/blenkernel/intern/subdiv_ccg.c
@@ -40,9 +40,9 @@
#include "opensubdiv_topology_refiner_capi.h"
-/* =============================================================================
- * Various forward declarations.
- */
+/* -------------------------------------------------------------------- */
+/** \name Various forward declarations
+ * \{ */
static void subdiv_ccg_average_all_boundaries_and_corners(SubdivCCG *subdiv_ccg, CCGKey *key);
@@ -50,9 +50,11 @@ static void subdiv_ccg_average_inner_face_grids(SubdivCCG *subdiv_ccg,
CCGKey *key,
SubdivCCGFace *face);
-/* =============================================================================
- * Generally useful internal helpers.
- */
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Generally useful internal helpers
+ * \{ */
/* Number of floats in per-vertex elements. */
static int num_element_float_get(const SubdivCCG *subdiv_ccg)
@@ -74,9 +76,11 @@ static int element_size_bytes_get(const SubdivCCG *subdiv_ccg)
return sizeof(float) * num_element_float_get(subdiv_ccg);
}
-/* =============================================================================
- * Internal helpers for CCG creation.
- */
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Internal helpers for CCG creation
+ * \{ */
static void subdiv_ccg_init_layers(SubdivCCG *subdiv_ccg, const SubdivToCCGSettings *settings)
{
@@ -158,9 +162,11 @@ static void subdiv_ccg_alloc_elements(SubdivCCG *subdiv_ccg, Subdiv *subdiv)
}
}
-/* =============================================================================
- * Grids evaluation.
- */
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Grids evaluation
+ * \{ */
typedef struct CCGEvalGridsData {
SubdivCCG *subdiv_ccg;
@@ -556,9 +562,11 @@ static void subdiv_ccg_init_faces_neighborhood(SubdivCCG *subdiv_ccg)
subdiv_ccg_init_faces_vertex_neighborhood(subdiv_ccg);
}
-/* =============================================================================
- * Creation / evaluation.
- */
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Creation / evaluation
+ * \{ */
SubdivCCG *BKE_subdiv_to_ccg(Subdiv *subdiv,
const SubdivToCCGSettings *settings,
@@ -589,7 +597,7 @@ Mesh *BKE_subdiv_to_ccg_mesh(Subdiv *subdiv,
{
/* Make sure evaluator is ready. */
BKE_subdiv_stats_begin(&subdiv->stats, SUBDIV_STATS_SUBDIV_TO_CCG);
- if (!BKE_subdiv_eval_update_from_mesh(subdiv, coarse_mesh, NULL)) {
+ if (!BKE_subdiv_eval_begin_from_mesh(subdiv, coarse_mesh, NULL)) {
if (coarse_mesh->totpoly) {
return NULL;
}
@@ -670,9 +678,11 @@ void BKE_subdiv_ccg_key_top_level(CCGKey *key, const SubdivCCG *subdiv_ccg)
BKE_subdiv_ccg_key(key, subdiv_ccg, subdiv_ccg->level);
}
-/* =============================================================================
- * Normals.
- */
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Normals
+ * \{ */
typedef struct RecalcInnerNormalsData {
SubdivCCG *subdiv_ccg;
@@ -770,8 +780,8 @@ static void subdiv_ccg_recalc_inner_normal_task(void *__restrict userdata_v,
subdiv_ccg_average_inner_face_normals(data->subdiv_ccg, data->key, tls, grid_index);
}
-static void subdiv_ccg_recalc_inner_normal_finalize(void *__restrict UNUSED(userdata),
- void *__restrict tls_v)
+static void subdiv_ccg_recalc_inner_normal_free(const void *__restrict UNUSED(userdata),
+ void *__restrict tls_v)
{
RecalcInnerNormalsTLSData *tls = tls_v;
MEM_SAFE_FREE(tls->face_normals);
@@ -791,7 +801,7 @@ static void subdiv_ccg_recalc_inner_grid_normals(SubdivCCG *subdiv_ccg)
BLI_parallel_range_settings_defaults(&parallel_range_settings);
parallel_range_settings.userdata_chunk = &tls_data;
parallel_range_settings.userdata_chunk_size = sizeof(tls_data);
- parallel_range_settings.func_finalize = subdiv_ccg_recalc_inner_normal_finalize;
+ parallel_range_settings.func_free = subdiv_ccg_recalc_inner_normal_free;
BLI_task_parallel_range(0,
subdiv_ccg->num_grids,
&data,
@@ -834,8 +844,8 @@ static void subdiv_ccg_recalc_modified_inner_normal_task(void *__restrict userda
subdiv_ccg_average_inner_face_grids(subdiv_ccg, key, face);
}
-static void subdiv_ccg_recalc_modified_inner_normal_finalize(void *__restrict UNUSED(userdata),
- void *__restrict tls_v)
+static void subdiv_ccg_recalc_modified_inner_normal_free(const void *__restrict UNUSED(userdata),
+ void *__restrict tls_v)
{
RecalcInnerNormalsTLSData *tls = tls_v;
MEM_SAFE_FREE(tls->face_normals);
@@ -857,7 +867,7 @@ static void subdiv_ccg_recalc_modified_inner_grid_normals(SubdivCCG *subdiv_ccg,
BLI_parallel_range_settings_defaults(&parallel_range_settings);
parallel_range_settings.userdata_chunk = &tls_data;
parallel_range_settings.userdata_chunk_size = sizeof(tls_data);
- parallel_range_settings.func_finalize = subdiv_ccg_recalc_modified_inner_normal_finalize;
+ parallel_range_settings.func_free = subdiv_ccg_recalc_modified_inner_normal_free;
BLI_task_parallel_range(0,
num_effected_faces,
&data,
@@ -885,9 +895,11 @@ void BKE_subdiv_ccg_update_normals(SubdivCCG *subdiv_ccg,
subdiv_ccg_average_all_boundaries_and_corners(subdiv_ccg, &key);
}
-/* =============================================================================
- * Boundary averaging/stitching.
- */
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Boundary averaging/stitching
+ * \{ */
typedef struct AverageInnerGridsData {
SubdivCCG *subdiv_ccg;
@@ -1077,8 +1089,8 @@ static void subdiv_ccg_average_grids_boundaries_task(void *__restrict userdata_v
subdiv_ccg_average_grids_boundary(subdiv_ccg, key, adjacent_edge, tls);
}
-static void subdiv_ccg_average_grids_boundaries_finalize(void *__restrict UNUSED(userdata),
- void *__restrict tls_v)
+static void subdiv_ccg_average_grids_boundaries_free(const void *__restrict UNUSED(userdata),
+ void *__restrict tls_v)
{
AverageGridsBoundariesTLSData *tls = tls_v;
MEM_SAFE_FREE(tls->accumulators);
@@ -1136,7 +1148,7 @@ static void subdiv_ccg_average_all_boundaries(SubdivCCG *subdiv_ccg, CCGKey *key
AverageGridsBoundariesTLSData tls_data = {NULL};
parallel_range_settings.userdata_chunk = &tls_data;
parallel_range_settings.userdata_chunk_size = sizeof(tls_data);
- parallel_range_settings.func_finalize = subdiv_ccg_average_grids_boundaries_finalize;
+ parallel_range_settings.func_free = subdiv_ccg_average_grids_boundaries_free;
BLI_task_parallel_range(0,
subdiv_ccg->num_adjacent_edges,
&boundaries_data,
@@ -1244,9 +1256,11 @@ void BKE_subdiv_ccg_topology_counters(const SubdivCCG *subdiv_ccg,
*r_num_loops = *r_num_faces * 4;
}
-/* =============================================================================
- * Neighbors.
- */
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Neighbors
+ * \{ */
void BKE_subdiv_ccg_print_coord(const char *message, const SubdivCCGCoord *coord)
{
@@ -1780,3 +1794,16 @@ void BKE_subdiv_ccg_neighbor_coords_get(const SubdivCCG *subdiv_ccg,
}
#endif
}
+
+int BKE_subdiv_ccg_grid_to_face_index(const SubdivCCG *subdiv_ccg, const int grid_index)
+{
+ // Subdiv *subdiv = subdiv_ccg->subdiv; /* UNUSED */
+ // OpenSubdiv_TopologyRefiner *topology_refiner = subdiv->topology_refiner; /* UNUSED */
+ SubdivCCGFace *face = subdiv_ccg->grid_faces[grid_index];
+
+ // const int face_grid_index = grid_index - face->start_grid_index; /* UNUSED */
+ const int face_index = face - subdiv_ccg->faces;
+ return face_index;
+}
+
+/** \} */
diff --git a/source/blender/blenkernel/intern/subdiv_deform.c b/source/blender/blenkernel/intern/subdiv_deform.c
index b5fd3ae63eb..f03cf4c4d21 100644
--- a/source/blender/blenkernel/intern/subdiv_deform.c
+++ b/source/blender/blenkernel/intern/subdiv_deform.c
@@ -39,9 +39,9 @@
#include "MEM_guardedalloc.h"
-/* ================================================================================================
- * Subdivision context.
- */
+/* -------------------------------------------------------------------- */
+/** \name Subdivision context
+ * \{ */
typedef struct SubdivDeformContext {
const Mesh *coarse_mesh;
@@ -77,9 +77,11 @@ static void subdiv_mesh_context_free(SubdivDeformContext *ctx)
MEM_SAFE_FREE(ctx->accumulated_counters);
}
-/* ================================================================================================
- * Accumulation helpers.
- */
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Accumulation helpers
+ * \{ */
static void subdiv_accumulate_vertex_displacement(SubdivDeformContext *ctx,
const int ptex_face_index,
@@ -105,9 +107,11 @@ static void subdiv_accumulate_vertex_displacement(SubdivDeformContext *ctx,
++ctx->accumulated_counters[vertex_index];
}
-/* ================================================================================================
- * Subdivision callbacks.
- */
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Subdivision callbacks
+ * \{ */
static bool subdiv_mesh_topology_info(const SubdivForeachContext *foreach_context,
const int UNUSED(num_vertices),
@@ -165,9 +169,11 @@ static void subdiv_mesh_vertex_corner(const SubdivForeachContext *foreach_contex
add_v3_v3(vertex_co, D);
}
-/* ================================================================================================
- * Initialization.
- */
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Initialization
+ * \{ */
static void setup_foreach_callbacks(const SubdivDeformContext *subdiv_context,
SubdivForeachContext *foreach_context)
@@ -182,9 +188,11 @@ static void setup_foreach_callbacks(const SubdivDeformContext *subdiv_context,
foreach_context->vertex_corner = subdiv_mesh_vertex_corner;
}
-/* ================================================================================================
- * Public entry point.
- */
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Public entry point
+ * \{ */
void BKE_subdiv_deform_coarse_vertices(struct Subdiv *subdiv,
const struct Mesh *coarse_mesh,
@@ -194,7 +202,7 @@ void BKE_subdiv_deform_coarse_vertices(struct Subdiv *subdiv,
BKE_subdiv_stats_begin(&subdiv->stats, SUBDIV_STATS_SUBDIV_TO_MESH);
/* Make sure evaluator is up to date with possible new topology, and that
* is refined for the new positions of coarse vertices. */
- if (!BKE_subdiv_eval_update_from_mesh(subdiv, coarse_mesh, vertex_cos)) {
+ if (!BKE_subdiv_eval_begin_from_mesh(subdiv, coarse_mesh, vertex_cos)) {
/* This could happen in two situations:
* - OpenSubdiv is disabled.
* - Something totally bad happened, and OpenSubdiv rejected our
@@ -234,3 +242,5 @@ void BKE_subdiv_deform_coarse_vertices(struct Subdiv *subdiv,
/* Free used memory. */
subdiv_mesh_context_free(&subdiv_context);
}
+
+/** \} */
diff --git a/source/blender/blenkernel/intern/subdiv_eval.c b/source/blender/blenkernel/intern/subdiv_eval.c
index 78e0e42753a..1c10a9a1935 100644
--- a/source/blender/blenkernel/intern/subdiv_eval.c
+++ b/source/blender/blenkernel/intern/subdiv_eval.c
@@ -121,13 +121,20 @@ static void set_face_varying_data_from_uv(Subdiv *subdiv,
}
}
-bool BKE_subdiv_eval_update_from_mesh(Subdiv *subdiv,
- const Mesh *mesh,
- const float (*coarse_vertex_cos)[3])
+bool BKE_subdiv_eval_begin_from_mesh(Subdiv *subdiv,
+ const Mesh *mesh,
+ const float (*coarse_vertex_cos)[3])
{
if (!BKE_subdiv_eval_begin(subdiv)) {
return false;
}
+ return BKE_subdiv_eval_refine_from_mesh(subdiv, mesh, coarse_vertex_cos);
+}
+
+bool BKE_subdiv_eval_refine_from_mesh(Subdiv *subdiv,
+ const Mesh *mesh,
+ const float (*coarse_vertex_cos)[3])
+{
if (subdiv->evaluator == NULL) {
/* NOTE: This situation is supposed to be handled by begin(). */
BLI_assert(!"Is not supposed to happen");
diff --git a/source/blender/blenkernel/intern/subdiv_foreach.c b/source/blender/blenkernel/intern/subdiv_foreach.c
index 533279f4425..ff7f6fad5f0 100644
--- a/source/blender/blenkernel/intern/subdiv_foreach.c
+++ b/source/blender/blenkernel/intern/subdiv_foreach.c
@@ -40,9 +40,9 @@
#include "MEM_guardedalloc.h"
-/* =============================================================================
- * General helpers.
- */
+/* -------------------------------------------------------------------- */
+/** \name General helpers
+ * \{ */
/* Number of ptex faces for a given polygon. */
BLI_INLINE int num_ptex_faces_per_poly_get(const MPoly *poly)
@@ -75,9 +75,11 @@ BLI_INLINE int ptex_face_resolution_get(const MPoly *poly, int resolution)
return (poly->totloop == 4) ? (resolution) : ((resolution >> 1) + 1);
}
-/* =============================================================================
- * Context which is passed to all threaded tasks.
- */
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Context which is passed to all threaded tasks
+ * \{ */
typedef struct SubdivForeachTaskContext {
const Mesh *coarse_mesh;
@@ -122,9 +124,11 @@ typedef struct SubdivForeachTaskContext {
BLI_bitmap *coarse_edges_used_map;
} SubdivForeachTaskContext;
-/* =============================================================================
- * Threading helpers.
- */
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Threading helpers
+ * \{ */
static void *subdiv_foreach_tls_alloc(SubdivForeachTaskContext *ctx)
{
@@ -148,9 +152,11 @@ static void subdiv_foreach_tls_free(SubdivForeachTaskContext *ctx, void *tls)
MEM_freeN(tls);
}
-/* =============================================================================
- * Initialization.
- */
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Initialization
+ * \{ */
/* NOTE: Expects edge map to be zeroed. */
static void subdiv_foreach_ctx_count(SubdivForeachTaskContext *ctx)
@@ -294,9 +300,11 @@ static void subdiv_foreach_ctx_free(SubdivForeachTaskContext *ctx)
MEM_freeN(ctx->subdiv_polygon_offset);
}
-/* =============================================================================
- * Vertex traversal process.
- */
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Vertex traversal process
+ * \{ */
/* Traversal of corner vertices. They are coming from coarse vertices. */
@@ -706,9 +714,11 @@ static void subdiv_foreach_vertices(SubdivForeachTaskContext *ctx, void *tls, co
}
}
-/* =============================================================================
- * Edge traversal process.
- */
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Edge traversal process
+ * \{ */
/* TODO(sergey): Coarse edge are always NONE, consider getting rid of it. */
static int subdiv_foreach_edges_row(SubdivForeachTaskContext *ctx,
@@ -1022,9 +1032,11 @@ static void subdiv_foreach_boundary_edges(SubdivForeachTaskContext *ctx,
ctx->foreach_context, tls, coarse_edge_index, subdiv_edge_index, v1, v2);
}
-/* =============================================================================
- * Loops traversal.
- */
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Loops traversal
+ * \{ */
static void rotate_indices(const int rot, int *a, int *b, int *c, int *d)
{
@@ -1666,9 +1678,11 @@ static void subdiv_foreach_loops(SubdivForeachTaskContext *ctx, void *tls, int p
}
}
-/* =============================================================================
- * Polygons traverse process.
- */
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Polygons traverse process
+ * \{ */
static void subdiv_foreach_polys(SubdivForeachTaskContext *ctx, void *tls, int poly_index)
{
@@ -1697,9 +1711,11 @@ static void subdiv_foreach_polys(SubdivForeachTaskContext *ctx, void *tls, int p
}
}
-/* =============================================================================
- * Loose elements traverse process.
- */
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Loose elements traverse process
+ * \{ */
static void subdiv_foreach_loose_vertices_task(void *__restrict userdata,
const int coarse_vertex_index,
@@ -1754,9 +1770,11 @@ static void subdiv_foreach_vertices_of_loose_edges_task(void *__restrict userdat
}
}
-/* =============================================================================
- * Subdivision process entry points.
- */
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Subdivision process entry points
+ * \{ */
static void subdiv_foreach_single_geometry_vertices(SubdivForeachTaskContext *ctx, void *tls)
{
@@ -1838,9 +1856,9 @@ static void subdiv_foreach_boundary_edges_task(void *__restrict userdata,
subdiv_foreach_boundary_edges(ctx, tls->userdata_chunk, edge_index);
}
-static void subdiv_foreach_finalize(void *__restrict userdata, void *__restrict userdata_chunk)
+static void subdiv_foreach_free(const void *__restrict userdata, void *__restrict userdata_chunk)
{
- SubdivForeachTaskContext *ctx = userdata;
+ const SubdivForeachTaskContext *ctx = userdata;
ctx->foreach_context->user_data_tls_free(userdata_chunk);
}
@@ -1873,8 +1891,15 @@ bool BKE_subdiv_foreach_subdiv_geometry(Subdiv *subdiv,
parallel_range_settings.userdata_chunk_size = context->user_data_tls_size;
parallel_range_settings.min_iter_per_thread = 1;
if (context->user_data_tls_free != NULL) {
- parallel_range_settings.func_finalize = subdiv_foreach_finalize;
+ parallel_range_settings.func_free = subdiv_foreach_free;
}
+
+ /* TODO(sergey): Possible optimization is to have a single pool and push all
+ * the tasks into it.
+ * NOTE: Watch out for callbacks which needs to run for loose geometry as they
+ * currently are relying on the fact that face/grid callbacks will tag non-
+ * loose geometry. */
+
BLI_task_parallel_range(
0, coarse_mesh->totpoly, &ctx, subdiv_foreach_task, &parallel_range_settings);
if (context->vertex_loose != NULL) {
@@ -1901,3 +1926,5 @@ bool BKE_subdiv_foreach_subdiv_geometry(Subdiv *subdiv,
subdiv_foreach_ctx_free(&ctx);
return true;
}
+
+/** \} */
diff --git a/source/blender/blenkernel/intern/subdiv_mesh.c b/source/blender/blenkernel/intern/subdiv_mesh.c
index cdb766f2507..987cc0311c7 100644
--- a/source/blender/blenkernel/intern/subdiv_mesh.c
+++ b/source/blender/blenkernel/intern/subdiv_mesh.c
@@ -41,9 +41,9 @@
#include "MEM_guardedalloc.h"
-/* =============================================================================
- * Subdivision context.
- */
+/* -------------------------------------------------------------------- */
+/** \name Subdivision Context
+ * \{ */
typedef struct SubdivMeshContext {
const SubdivToMeshSettings *settings;
@@ -119,9 +119,11 @@ static void subdiv_mesh_context_free(SubdivMeshContext *ctx)
MEM_SAFE_FREE(ctx->accumulated_counters);
}
-/* =============================================================================
- * Loop custom data copy helpers.
- */
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Loop custom data copy helpers
+ * \{ */
typedef struct LoopsOfPtex {
/* First loop of the ptex, starts at ptex (0, 0) and goes in u direction. */
@@ -159,9 +161,11 @@ static void loops_of_ptex_get(const SubdivMeshContext *ctx,
}
}
-/* =============================================================================
- * Vertex custom data interpolation helpers.
- */
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Vertex custom data interpolation helpers
+ * \{ */
/* TODO(sergey): Somehow de-duplicate with loops storage, without too much
* exception cases all over the code. */
@@ -295,9 +299,11 @@ static void vertex_interpolation_end(VerticesForInterpolation *vertex_interpolat
}
}
-/* =============================================================================
- * Loop custom data interpolation helpers.
- */
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Loop custom data interpolation helpers
+ * \{ */
typedef struct LoopsForInterpolation {
/* This field points to a loop data which is to be used for interpolation.
@@ -413,9 +419,11 @@ static void loop_interpolation_end(LoopsForInterpolation *loop_interpolation)
}
}
-/* =============================================================================
- * TLS.
- */
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name TLS
+ * \{ */
typedef struct SubdivMeshTLS {
bool vertex_interpolation_initialized;
@@ -440,9 +448,11 @@ static void subdiv_mesh_tls_free(void *tls_v)
}
}
-/* =============================================================================
- * Evaluation helper functions.
- */
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Evaluation helper functions
+ * \{ */
static void eval_final_point_and_vertex_normal(Subdiv *subdiv,
const int ptex_face_index,
@@ -459,9 +469,11 @@ static void eval_final_point_and_vertex_normal(Subdiv *subdiv,
}
}
-/* =============================================================================
- * Accumulation helpers.
- */
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Accumulation helpers
+ * \{ */
static void subdiv_accumulate_vertex_normal_and_displacement(SubdivMeshContext *ctx,
const int ptex_face_index,
@@ -490,9 +502,11 @@ static void subdiv_accumulate_vertex_normal_and_displacement(SubdivMeshContext *
++ctx->accumulated_counters[subdiv_vertex_index];
}
-/* =============================================================================
- * Callbacks.
- */
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Callbacks
+ * \{ */
static bool subdiv_mesh_topology_info(const SubdivForeachContext *foreach_context,
const int num_vertices,
@@ -513,9 +527,11 @@ static bool subdiv_mesh_topology_info(const SubdivForeachContext *foreach_contex
return true;
}
-/* =============================================================================
- * Vertex subdivision process.
- */
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Vertex subdivision process
+ * \{ */
static void subdiv_vertex_data_copy(const SubdivMeshContext *ctx,
const MVert *coarse_vertex,
@@ -778,9 +794,11 @@ static void subdiv_mesh_vertex_inner(const SubdivForeachContext *foreach_context
subdiv_mesh_tag_center_vertex(coarse_poly, subdiv_vert, u, v);
}
-/* =============================================================================
- * Edge subdivision process.
- */
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Edge subdivision process
+ * \{ */
static void subdiv_copy_edge_data(SubdivMeshContext *ctx,
MEdge *subdiv_edge,
@@ -827,9 +845,11 @@ static void subdiv_mesh_edge(const SubdivForeachContext *foreach_context,
subdiv_edge->v2 = subdiv_v2;
}
-/* =============================================================================
- * Loops creation/interpolation.
- */
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Loops creation/interpolation
+ * \{ */
static void subdiv_interpolate_loop_data(const SubdivMeshContext *ctx,
MLoop *subdiv_loop,
@@ -921,9 +941,11 @@ static void subdiv_mesh_loop(const SubdivForeachContext *foreach_context,
subdiv_loop->e = subdiv_edge_index;
}
-/* =============================================================================
- * Polygons subdivision process.
- */
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Polygons subdivision process
+ * \{ */
static void subdiv_copy_poly_data(const SubdivMeshContext *ctx,
MPoly *subdiv_poly,
@@ -955,9 +977,11 @@ static void subdiv_mesh_poly(const SubdivForeachContext *foreach_context,
subdiv_poly->totloop = num_loops;
}
-/* =============================================================================
- * Loose elements subdivision process.
- */
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Loose elements subdivision process
+ * \{ */
static void subdiv_mesh_vertex_loose(const SubdivForeachContext *foreach_context,
void *UNUSED(tls),
@@ -1127,9 +1151,11 @@ static void subdiv_mesh_vertex_of_loose_edge(const struct SubdivForeachContext *
normal_float_to_short_v3(subdiv_vertex->no, no);
}
-/* =============================================================================
- * Initialization.
- */
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Initialization
+ * \{ */
static void setup_foreach_callbacks(const SubdivMeshContext *subdiv_context,
SubdivForeachContext *foreach_context)
@@ -1157,9 +1183,11 @@ static void setup_foreach_callbacks(const SubdivMeshContext *subdiv_context,
foreach_context->user_data_tls_free = subdiv_mesh_tls_free;
}
-/* =============================================================================
- * Public entry point.
- */
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Public entry point
+ * \{ */
Mesh *BKE_subdiv_to_mesh(Subdiv *subdiv,
const SubdivToMeshSettings *settings,
@@ -1168,7 +1196,7 @@ Mesh *BKE_subdiv_to_mesh(Subdiv *subdiv,
BKE_subdiv_stats_begin(&subdiv->stats, SUBDIV_STATS_SUBDIV_TO_MESH);
/* Make sure evaluator is up to date with possible new topology, and that
* it is refined for the new positions of coarse vertices. */
- if (!BKE_subdiv_eval_update_from_mesh(subdiv, coarse_mesh, NULL)) {
+ if (!BKE_subdiv_eval_begin_from_mesh(subdiv, coarse_mesh, NULL)) {
/* This could happen in two situations:
* - OpenSubdiv is disabled.
* - Something totally bad happened, and OpenSubdiv rejected our
@@ -1206,3 +1234,5 @@ Mesh *BKE_subdiv_to_mesh(Subdiv *subdiv,
subdiv_mesh_context_free(&subdiv_context);
return result;
}
+
+/** \} */
diff --git a/source/blender/blenkernel/intern/subsurf_ccg.c b/source/blender/blenkernel/intern/subsurf_ccg.c
index c21d640a4c1..7a0a5645b80 100644
--- a/source/blender/blenkernel/intern/subsurf_ccg.c
+++ b/source/blender/blenkernel/intern/subsurf_ccg.c
@@ -71,18 +71,13 @@
#include "CCGSubSurf.h"
-#ifdef WITH_OPENSUBDIV
-# include "opensubdiv_capi.h"
-#endif
-
/* assumes MLoop's are laid out 4 for each poly, in order */
#define USE_LOOP_LAYOUT_FAST
static CCGDerivedMesh *getCCGDerivedMesh(CCGSubSurf *ss,
int drawInteriorEdges,
int useSubsurfUv,
- DerivedMesh *dm,
- bool use_gpu_backend);
+ DerivedMesh *dm);
///
static void *arena_alloc(CCGAllocatorHDL a, int numBytes)
@@ -404,82 +399,6 @@ static int ss_sync_from_uv(CCGSubSurf *ss, CCGSubSurf *origss, DerivedMesh *dm,
return 1;
}
-#ifdef WITH_OPENSUBDIV
-static void UNUSED_FUNCTION(set_subsurf_osd_ccg_uv)(CCGSubSurf *ss,
- DerivedMesh *dm,
- DerivedMesh *result,
- int layer_index)
-{
- CCGFace **faceMap;
- MTFace *tf;
- MLoopUV *mluv;
- CCGFaceIterator fi;
- int index, gridSize, gridFaces, totface, x, y, S;
- MLoopUV *dmloopuv = CustomData_get_layer_n(&dm->loopData, CD_MLOOPUV, layer_index);
- /* need to update both CD_MTFACE & CD_MLOOPUV, hrmf, we could get away with
- * just tface except applying the modifier then looses subsurf UV */
- MTFace *tface = CustomData_get_layer_n(&result->faceData, CD_MTFACE, layer_index);
- MLoopUV *mloopuv = CustomData_get_layer_n(&result->loopData, CD_MLOOPUV, layer_index);
-
- if (dmloopuv == NULL || (tface == NULL && mloopuv == NULL)) {
- return;
- }
-
- ccgSubSurf_evaluatorSetFVarUV(ss, dm, layer_index);
-
- /* get some info from CCGSubSurf */
- totface = ccgSubSurf_getNumFaces(ss);
- gridSize = ccgSubSurf_getGridSize(ss);
- gridFaces = gridSize - 1;
-
- /* make a map from original faces to CCGFaces */
- faceMap = MEM_mallocN(totface * sizeof(*faceMap), "facemapuv");
- for (ccgSubSurf_initFaceIterator(ss, &fi); !ccgFaceIterator_isStopped(&fi);
- ccgFaceIterator_next(&fi)) {
- CCGFace *f = ccgFaceIterator_getCurrent(&fi);
- faceMap[POINTER_AS_INT(ccgSubSurf_getFaceFaceHandle(f))] = f;
- }
-
- /* load coordinates from uvss into tface */
- tf = tface;
- mluv = mloopuv;
- for (index = 0; index < totface; index++) {
- CCGFace *f = faceMap[index];
- int numVerts = ccgSubSurf_getFaceNumVerts(f);
- for (S = 0; S < numVerts; S++) {
- for (y = 0; y < gridFaces; y++) {
- for (x = 0; x < gridFaces; x++) {
- const int delta[4][2] = {{0, 0}, {0, 1}, {1, 1}, {1, 0}};
- float uv[4][2];
- int i;
- for (i = 0; i < 4; i++) {
- const int dx = delta[i][0], dy = delta[i][1];
- const float grid_u = ((float)(x + dx)) / (gridSize - 1),
- grid_v = ((float)(y + dy)) / (gridSize - 1);
- ccgSubSurf_evaluatorFVarUV(ss, index, S, grid_u, grid_v, uv[i]);
- }
- if (tf) {
- copy_v2_v2(tf->uv[0], uv[0]);
- copy_v2_v2(tf->uv[1], uv[1]);
- copy_v2_v2(tf->uv[2], uv[2]);
- copy_v2_v2(tf->uv[3], uv[3]);
- tf++;
- }
- if (mluv) {
- copy_v2_v2(mluv[0].uv, uv[0]);
- copy_v2_v2(mluv[1].uv, uv[1]);
- copy_v2_v2(mluv[2].uv, uv[2]);
- copy_v2_v2(mluv[3].uv, uv[3]);
- mluv += 4;
- }
- }
- }
- }
- }
- MEM_freeN(faceMap);
-}
-#endif /* WITH_OPENSUBDIV */
-
static void set_subsurf_legacy_uv(CCGSubSurf *ss, DerivedMesh *dm, DerivedMesh *result, int n)
{
CCGSubSurf *uvss;
@@ -564,16 +483,7 @@ static void set_subsurf_legacy_uv(CCGSubSurf *ss, DerivedMesh *dm, DerivedMesh *
static void set_subsurf_uv(CCGSubSurf *ss, DerivedMesh *dm, DerivedMesh *result, int layer_index)
{
-#ifdef WITH_OPENSUBDIV
- if (!ccgSubSurf_needGrids(ss)) {
- /* GPU backend is used, no need to evaluate UVs on CPU. */
- /* TODO(sergey): Think of how to support edit mode of UVs. */
- }
- else
-#endif
- {
- set_subsurf_legacy_uv(ss, dm, result, layer_index);
- }
+ set_subsurf_legacy_uv(ss, dm, result, layer_index);
}
/* face weighting */
@@ -763,40 +673,13 @@ static void ss_sync_ccg_from_derivedmesh(CCGSubSurf *ss,
#endif
}
-#ifdef WITH_OPENSUBDIV
-static void ss_sync_osd_from_derivedmesh(CCGSubSurf *ss, DerivedMesh *dm)
-{
- ccgSubSurf_initFullSync(ss);
- ccgSubSurf_prepareTopologyRefiner(ss, dm);
- ccgSubSurf_processSync(ss);
-}
-#endif /* WITH_OPENSUBDIV */
-
static void ss_sync_from_derivedmesh(CCGSubSurf *ss,
DerivedMesh *dm,
float (*vertexCos)[3],
int use_flat_subdiv,
- bool use_subdiv_uvs)
+ bool UNUSED(use_subdiv_uvs))
{
-#ifndef WITH_OPENSUBDIV
- UNUSED_VARS(use_subdiv_uvs);
-#endif
-
-#ifdef WITH_OPENSUBDIV
- /* Reset all related descriptors if actual mesh topology changed or if
- * other evaluation-related settings changed.
- */
- if (!ccgSubSurf_needGrids(ss)) {
- /* TODO(sergey): Use vertex coordinates and flat subdiv flag. */
- ccgSubSurf__sync_subdivUvs(ss, use_subdiv_uvs);
- ccgSubSurf_checkTopologyChanged(ss, dm);
- ss_sync_osd_from_derivedmesh(ss, dm);
- }
- else
-#endif
- {
- ss_sync_ccg_from_derivedmesh(ss, dm, vertexCos, use_flat_subdiv);
- }
+ ss_sync_ccg_from_derivedmesh(ss, dm, vertexCos, use_flat_subdiv);
}
/***/
@@ -850,13 +733,6 @@ static void UNUSED_FUNCTION(ccgDM_getMinMax)(DerivedMesh *dm, float r_min[3], fl
int i, edgeSize = ccgSubSurf_getEdgeSize(ss);
int gridSize = ccgSubSurf_getGridSize(ss);
-#ifdef WITH_OPENSUBDIV
- if (ccgdm->useGpuBackend) {
- ccgSubSurf_getMinMax(ccgdm->ss, r_min, r_max);
- return;
- }
-#endif
-
CCG_key_top_level(&key, ss);
if (!ccgSubSurf_getNumVerts(ss)) {
@@ -1642,11 +1518,9 @@ static void ccgDM_release(DerivedMesh *dm)
}
MEM_freeN(ccgdm->edgeFlags);
MEM_freeN(ccgdm->faceFlags);
- if (ccgdm->useGpuBackend == false) {
- MEM_freeN(ccgdm->vertMap);
- MEM_freeN(ccgdm->edgeMap);
- MEM_freeN(ccgdm->faceMap);
- }
+ MEM_freeN(ccgdm->vertMap);
+ MEM_freeN(ccgdm->edgeMap);
+ MEM_freeN(ccgdm->faceMap);
BLI_mutex_end(&ccgdm->loops_cache_lock);
BLI_rw_mutex_end(&ccgdm->origindex_cache_rwlock);
@@ -2417,76 +2291,44 @@ static void set_ccgdm_all_geometry(CCGDerivedMesh *ccgdm,
BLI_assert(faceNum == ccgSubSurf_getNumFinalFaces(ss));
}
-/* Fill in only geometry arrays needed for the GPU tessellation. */
-static void set_ccgdm_gpu_geometry(CCGDerivedMesh *ccgdm, DerivedMesh *dm)
-{
- const int totface = dm->getNumPolys(dm);
- MPoly *mpoly = CustomData_get_layer(&dm->polyData, CD_MPOLY);
- int index;
- DMFlagMat *faceFlags = ccgdm->faceFlags;
-
- for (index = 0; index < totface; index++) {
- faceFlags->flag = mpoly ? mpoly[index].flag : 0;
- faceFlags->mat_nr = mpoly ? mpoly[index].mat_nr : 0;
- faceFlags++;
- }
-
- /* TODO(sergey): Fill in edge flags. */
-}
-
-static CCGDerivedMesh *getCCGDerivedMesh(
- CCGSubSurf *ss, int drawInteriorEdges, int useSubsurfUv, DerivedMesh *dm, bool use_gpu_backend)
+static CCGDerivedMesh *getCCGDerivedMesh(CCGSubSurf *ss,
+ int drawInteriorEdges,
+ int useSubsurfUv,
+ DerivedMesh *dm)
{
-#ifdef WITH_OPENSUBDIV
- const int totedge = dm->getNumEdges(dm);
- const int totface = dm->getNumPolys(dm);
-#else
const int totedge = ccgSubSurf_getNumEdges(ss);
const int totface = ccgSubSurf_getNumFaces(ss);
-#endif
CCGDerivedMesh *ccgdm = MEM_callocN(sizeof(*ccgdm), "ccgdm");
- if (use_gpu_backend == false) {
- BLI_assert(totedge == ccgSubSurf_getNumEdges(ss));
- BLI_assert(totface == ccgSubSurf_getNumFaces(ss));
- DM_from_template(&ccgdm->dm,
- dm,
- DM_TYPE_CCGDM,
- ccgSubSurf_getNumFinalVerts(ss),
- ccgSubSurf_getNumFinalEdges(ss),
- 0,
- ccgSubSurf_getNumFinalFaces(ss) * 4,
- ccgSubSurf_getNumFinalFaces(ss));
+ BLI_assert(totedge == ccgSubSurf_getNumEdges(ss));
+ BLI_assert(totface == ccgSubSurf_getNumFaces(ss));
+ DM_from_template(&ccgdm->dm,
+ dm,
+ DM_TYPE_CCGDM,
+ ccgSubSurf_getNumFinalVerts(ss),
+ ccgSubSurf_getNumFinalEdges(ss),
+ 0,
+ ccgSubSurf_getNumFinalFaces(ss) * 4,
+ ccgSubSurf_getNumFinalFaces(ss));
- CustomData_free_layer_active(&ccgdm->dm.polyData, CD_NORMAL, ccgdm->dm.numPolyData);
+ CustomData_free_layer_active(&ccgdm->dm.polyData, CD_NORMAL, ccgdm->dm.numPolyData);
- ccgdm->reverseFaceMap = MEM_callocN(sizeof(int) * ccgSubSurf_getNumFinalFaces(ss),
- "reverseFaceMap");
+ ccgdm->reverseFaceMap = MEM_callocN(sizeof(int) * ccgSubSurf_getNumFinalFaces(ss),
+ "reverseFaceMap");
- create_ccgdm_maps(ccgdm, ss);
- }
- else {
- DM_from_template(&ccgdm->dm, dm, DM_TYPE_CCGDM, 0, 0, 0, 0, dm->getNumPolys(dm));
- CustomData_copy_data(&dm->polyData, &ccgdm->dm.polyData, 0, 0, dm->getNumPolys(dm));
- }
+ create_ccgdm_maps(ccgdm, ss);
set_default_ccgdm_callbacks(ccgdm);
ccgdm->ss = ss;
ccgdm->drawInteriorEdges = drawInteriorEdges;
ccgdm->useSubsurfUv = useSubsurfUv;
- ccgdm->useGpuBackend = use_gpu_backend;
/* CDDM hack. */
ccgdm->edgeFlags = MEM_callocN(sizeof(short) * totedge, "edgeFlags");
ccgdm->faceFlags = MEM_callocN(sizeof(DMFlagMat) * totface, "faceFlags");
- if (use_gpu_backend == false) {
- set_ccgdm_all_geometry(ccgdm, ss, dm, useSubsurfUv != 0);
- }
- else {
- set_ccgdm_gpu_geometry(ccgdm, dm);
- }
+ set_ccgdm_all_geometry(ccgdm, ss, dm, useSubsurfUv != 0);
ccgdm->dm.numVertData = ccgSubSurf_getNumFinalVerts(ss);
ccgdm->dm.numEdgeData = ccgSubSurf_getNumFinalEdges(ss);
@@ -2502,21 +2344,6 @@ static CCGDerivedMesh *getCCGDerivedMesh(
/***/
-static bool subsurf_use_gpu_backend(SubsurfFlags flags)
-{
-#ifdef WITH_OPENSUBDIV
- /* Use GPU backend if it's a last modifier in the stack
- * and user chose to use any of the OSD compute devices,
- * but also check if GPU has all needed features.
- */
- return (flags & SUBSURF_USE_GPU_BACKEND) != 0 &&
- (U.opensubdiv_compute_type != USER_OPENSUBDIV_COMPUTE_NONE);
-#else
- (void)flags;
- return false;
-#endif
-}
-
struct DerivedMesh *subsurf_make_derived_from_derived(struct DerivedMesh *dm,
struct SubsurfModifierData *smd,
const struct Scene *scene,
@@ -2527,7 +2354,6 @@ struct DerivedMesh *subsurf_make_derived_from_derived(struct DerivedMesh *dm,
const CCGFlags useAging = (smd->flags & eSubsurfModifierFlag_DebugIncr) ? CCG_USE_AGING : 0;
const int useSubsurfUv = (smd->uv_smooth != SUBSURF_UV_SMOOTH_NONE);
const int drawInteriorEdges = !(smd->flags & eSubsurfModifierFlag_ControlEdges);
- const bool use_gpu_backend = subsurf_use_gpu_backend(flags);
const bool ignore_simplify = (flags & SUBSURF_IGNORE_SIMPLIFY);
CCGDerivedMesh *result;
@@ -2546,11 +2372,8 @@ struct DerivedMesh *subsurf_make_derived_from_derived(struct DerivedMesh *dm,
smd->emCache = _getSubSurf(smd->emCache, levels, 3, useSimple | useAging | CCG_CALC_NORMALS);
-#ifdef WITH_OPENSUBDIV
- ccgSubSurf_setSkipGrids(smd->emCache, use_gpu_backend);
-#endif
ss_sync_from_derivedmesh(smd->emCache, dm, vertCos, useSimple, useSubsurfUv);
- result = getCCGDerivedMesh(smd->emCache, drawInteriorEdges, useSubsurfUv, dm, use_gpu_backend);
+ result = getCCGDerivedMesh(smd->emCache, drawInteriorEdges, useSubsurfUv, dm);
}
else if (flags & SUBSURF_USE_RENDER_PARAMS) {
/* Do not use cache in render mode. */
@@ -2567,7 +2390,7 @@ struct DerivedMesh *subsurf_make_derived_from_derived(struct DerivedMesh *dm,
ss_sync_from_derivedmesh(ss, dm, vertCos, useSimple, useSubsurfUv);
- result = getCCGDerivedMesh(ss, drawInteriorEdges, useSubsurfUv, dm, false);
+ result = getCCGDerivedMesh(ss, drawInteriorEdges, useSubsurfUv, dm);
result->freeSS = 1;
}
@@ -2600,32 +2423,15 @@ struct DerivedMesh *subsurf_make_derived_from_derived(struct DerivedMesh *dm,
ss_sync_from_derivedmesh(ss, dm, vertCos, useSimple, useSubsurfUv);
- result = getCCGDerivedMesh(smd->mCache, drawInteriorEdges, useSubsurfUv, dm, false);
+ result = getCCGDerivedMesh(smd->mCache, drawInteriorEdges, useSubsurfUv, dm);
}
else {
CCGFlags ccg_flags = useSimple | CCG_USE_ARENA | CCG_CALC_NORMALS;
CCGSubSurf *prevSS = NULL;
if (smd->mCache && (flags & SUBSURF_IS_FINAL_CALC)) {
-#ifdef WITH_OPENSUBDIV
- /* With OpenSubdiv enabled we always tries to re-use previous
- * subsurf structure in order to save computation time since
- * re-creation is rather a complicated business.
- *
- * TODO(sergey): There was a good reason why final calculation
- * used to free entirely cached subsurf structure. reason of
- * this is to be investigated still to be sure we don't have
- * regressions here.
- */
- if (use_gpu_backend) {
- prevSS = smd->mCache;
- }
- else
-#endif
- {
- ccgSubSurf_free(smd->mCache);
- smd->mCache = NULL;
- }
+ ccgSubSurf_free(smd->mCache);
+ smd->mCache = NULL;
}
if (flags & SUBSURF_ALLOC_PAINT_MASK) {
@@ -2633,12 +2439,9 @@ struct DerivedMesh *subsurf_make_derived_from_derived(struct DerivedMesh *dm,
}
ss = _getSubSurf(prevSS, levels, 3, ccg_flags);
-#ifdef WITH_OPENSUBDIV
- ccgSubSurf_setSkipGrids(ss, use_gpu_backend);
-#endif
ss_sync_from_derivedmesh(ss, dm, vertCos, useSimple, useSubsurfUv);
- result = getCCGDerivedMesh(ss, drawInteriorEdges, useSubsurfUv, dm, use_gpu_backend);
+ result = getCCGDerivedMesh(ss, drawInteriorEdges, useSubsurfUv, dm);
if (flags & SUBSURF_IS_FINAL_CALC) {
smd->mCache = ss;
@@ -2710,26 +2513,10 @@ void subsurf_calculate_limit_positions(Mesh *me, float (*r_positions)[3])
bool subsurf_has_edges(DerivedMesh *dm)
{
- CCGDerivedMesh *ccgdm = (CCGDerivedMesh *)dm;
-#ifdef WITH_OPENSUBDIV
- if (ccgdm->useGpuBackend) {
- return true;
- }
-#else
- (void)ccgdm;
-#endif
return dm->getNumEdges(dm) != 0;
}
bool subsurf_has_faces(DerivedMesh *dm)
{
- CCGDerivedMesh *ccgdm = (CCGDerivedMesh *)dm;
-#ifdef WITH_OPENSUBDIV
- if (ccgdm->useGpuBackend) {
- return true;
- }
-#else
- (void)ccgdm;
-#endif
return dm->getNumPolys(dm) != 0;
}
diff --git a/source/blender/blenkernel/intern/text.c b/source/blender/blenkernel/intern/text.c
index 94c41777cea..527b54a1aa2 100644
--- a/source/blender/blenkernel/intern/text.c
+++ b/source/blender/blenkernel/intern/text.c
@@ -164,7 +164,7 @@ static void text_copy_data(Main *UNUSED(bmain),
text_dst->compiled = NULL;
/* Walk down, reconstructing. */
- for (TextLine *line_src = text_src->lines.first; line_src; line_src = line_src->next) {
+ LISTBASE_FOREACH (TextLine *, line_src, &text_src->lines) {
TextLine *line_dst = MEM_mallocN(sizeof(*line_dst), __func__);
line_dst->line = BLI_strdup(line_src->line);
@@ -206,6 +206,7 @@ IDTypeInfo IDType_ID_TXT = {
.copy_data = text_copy_data,
.free_data = text_free_data,
.make_local = NULL,
+ .foreach_id = NULL,
};
/***/
@@ -1311,12 +1312,12 @@ void txt_sel_set(Text *text, int startl, int startc, int endl, int endc)
char *txt_to_buf_for_undo(Text *text, int *r_buf_len)
{
int buf_len = 0;
- for (const TextLine *l = text->lines.first; l; l = l->next) {
+ LISTBASE_FOREACH (const TextLine *, l, &text->lines) {
buf_len += l->len + 1;
}
char *buf = MEM_mallocN(buf_len, __func__);
char *buf_step = buf;
- for (const TextLine *l = text->lines.first; l; l = l->next) {
+ LISTBASE_FOREACH (const TextLine *, l, &text->lines) {
memcpy(buf_step, l->line, l->len);
buf_step += l->len;
*buf_step++ = '\n';
diff --git a/source/blender/blenkernel/intern/texture.c b/source/blender/blenkernel/intern/texture.c
index b0f000d6e04..e2c3c20e36e 100644
--- a/source/blender/blenkernel/intern/texture.c
+++ b/source/blender/blenkernel/intern/texture.c
@@ -29,6 +29,7 @@
#include "MEM_guardedalloc.h"
#include "BLI_kdopbvh.h"
+#include "BLI_listbase.h"
#include "BLI_math.h"
#include "BLI_math_color.h"
#include "BLI_utildefines.h"
@@ -49,7 +50,6 @@
#include "BKE_main.h"
-#include "BKE_animsys.h"
#include "BKE_colorband.h"
#include "BKE_colortools.h"
#include "BKE_icons.h"
@@ -57,6 +57,7 @@
#include "BKE_image.h"
#include "BKE_key.h"
#include "BKE_lib_id.h"
+#include "BKE_lib_query.h"
#include "BKE_material.h"
#include "BKE_node.h"
#include "BKE_scene.h"
@@ -112,7 +113,7 @@ static void texture_free_data(ID *id)
/* is no lib link block, but texture extension */
if (texture->nodetree) {
- ntreeFreeNestedTree(texture->nodetree);
+ ntreeFreeEmbeddedTree(texture->nodetree);
MEM_freeN(texture->nodetree);
texture->nodetree = NULL;
}
@@ -123,6 +124,16 @@ static void texture_free_data(ID *id)
BKE_previewimg_free(&texture->preview);
}
+static void texture_foreach_id(ID *id, LibraryForeachIDData *data)
+{
+ Tex *texture = (Tex *)id;
+ if (texture->nodetree) {
+ /* nodetree **are owned by IDs**, treat them as mere sub-data and not real ID! */
+ BKE_library_foreach_ID_embedded(data, (ID **)&texture->nodetree);
+ }
+ BKE_LIB_FOREACHID_PROCESS(data, texture->ima, IDWALK_CB_USER);
+}
+
IDTypeInfo IDType_ID_TE = {
.id_code = ID_TE,
.id_filter = FILTER_ID_TE,
@@ -137,8 +148,16 @@ IDTypeInfo IDType_ID_TE = {
.copy_data = texture_copy_data,
.free_data = texture_free_data,
.make_local = NULL,
+ .foreach_id = texture_foreach_id,
};
+/* Utils for all IDs using those texture slots. */
+void BKE_texture_mtex_foreach_id(LibraryForeachIDData *data, MTex *mtex)
+{
+ BKE_LIB_FOREACHID_PROCESS(data, mtex->object, IDWALK_CB_NOP);
+ BKE_LIB_FOREACHID_PROCESS(data, mtex->tex, IDWALK_CB_USER);
+}
+
/* ****************** Mapping ******************* */
TexMapping *BKE_texture_mapping_add(int type)
@@ -697,7 +716,7 @@ static void texture_nodes_fetch_images_for_pool(Tex *texture,
bNodeTree *ntree,
struct ImagePool *pool)
{
- for (bNode *node = ntree->nodes.first; node; node = node->next) {
+ LISTBASE_FOREACH (bNode *, node, &ntree->nodes) {
if (node->type == SH_NODE_TEX_IMAGE && node->id != NULL) {
Image *image = (Image *)node->id;
BKE_image_pool_acquire_ibuf(image, &texture->iuser, pool);
diff --git a/source/blender/blenkernel/intern/tracking.c b/source/blender/blenkernel/intern/tracking.c
index 0204667b3bd..97d95cb7e46 100644
--- a/source/blender/blenkernel/intern/tracking.c
+++ b/source/blender/blenkernel/intern/tracking.c
@@ -2288,13 +2288,15 @@ void BKE_tracking_distortion_free(MovieDistortion *distortion)
MEM_freeN(distortion);
}
-void BKE_tracking_distort_v2(MovieTracking *tracking, const float co[2], float r_co[2])
+void BKE_tracking_distort_v2(
+ MovieTracking *tracking, int image_width, int image_height, const float co[2], float r_co[2])
{
const MovieTrackingCamera *camera = &tracking->camera;
const float aspy = 1.0f / tracking->camera.pixel_aspect;
libmv_CameraIntrinsicsOptions camera_intrinsics_options;
- tracking_cameraIntrinscisOptionsFromTracking(tracking, 0, 0, &camera_intrinsics_options);
+ tracking_cameraIntrinscisOptionsFromTracking(
+ tracking, image_width, image_height, &camera_intrinsics_options);
libmv_CameraIntrinsics *intrinsics = libmv_cameraIntrinsicsNew(&camera_intrinsics_options);
/* Normalize coordinates. */
@@ -2309,13 +2311,15 @@ void BKE_tracking_distort_v2(MovieTracking *tracking, const float co[2], float r
r_co[1] = y;
}
-void BKE_tracking_undistort_v2(MovieTracking *tracking, const float co[2], float r_co[2])
+void BKE_tracking_undistort_v2(
+ MovieTracking *tracking, int image_width, int image_height, const float co[2], float r_co[2])
{
const MovieTrackingCamera *camera = &tracking->camera;
const float aspy = 1.0f / tracking->camera.pixel_aspect;
libmv_CameraIntrinsicsOptions camera_intrinsics_options;
- tracking_cameraIntrinscisOptionsFromTracking(tracking, 0, 0, &camera_intrinsics_options);
+ tracking_cameraIntrinscisOptionsFromTracking(
+ tracking, image_width, image_height, &camera_intrinsics_options);
libmv_CameraIntrinsics *intrinsics = libmv_cameraIntrinsicsNew(&camera_intrinsics_options);
double x = co[0], y = co[1];
@@ -2361,13 +2365,19 @@ ImBuf *BKE_tracking_distort_frame(MovieTracking *tracking,
}
void BKE_tracking_max_distortion_delta_across_bound(MovieTracking *tracking,
+ int image_width,
+ int image_height,
rcti *rect,
bool undistort,
float delta[2])
{
float pos[2], warped_pos[2];
const int coord_delta = 5;
- void (*apply_distortion)(MovieTracking * tracking, const float pos[2], float out[2]);
+ void (*apply_distortion)(MovieTracking * tracking,
+ int image_width,
+ int image_height,
+ const float pos[2],
+ float out[2]);
if (undistort) {
apply_distortion = BKE_tracking_undistort_v2;
@@ -2387,7 +2397,7 @@ void BKE_tracking_max_distortion_delta_across_bound(MovieTracking *tracking,
pos[0] = a;
pos[1] = rect->ymin;
- apply_distortion(tracking, pos, warped_pos);
+ apply_distortion(tracking, image_width, image_height, pos, warped_pos);
delta[0] = max_ff(delta[0], fabsf(pos[0] - warped_pos[0]));
delta[1] = max_ff(delta[1], fabsf(pos[1] - warped_pos[1]));
@@ -2396,7 +2406,7 @@ void BKE_tracking_max_distortion_delta_across_bound(MovieTracking *tracking,
pos[0] = a;
pos[1] = rect->ymax;
- apply_distortion(tracking, pos, warped_pos);
+ apply_distortion(tracking, image_width, image_height, pos, warped_pos);
delta[0] = max_ff(delta[0], fabsf(pos[0] - warped_pos[0]));
delta[1] = max_ff(delta[1], fabsf(pos[1] - warped_pos[1]));
@@ -2415,7 +2425,7 @@ void BKE_tracking_max_distortion_delta_across_bound(MovieTracking *tracking,
pos[0] = rect->xmin;
pos[1] = a;
- apply_distortion(tracking, pos, warped_pos);
+ apply_distortion(tracking, image_width, image_height, pos, warped_pos);
delta[0] = max_ff(delta[0], fabsf(pos[0] - warped_pos[0]));
delta[1] = max_ff(delta[1], fabsf(pos[1] - warped_pos[1]));
@@ -2424,7 +2434,7 @@ void BKE_tracking_max_distortion_delta_across_bound(MovieTracking *tracking,
pos[0] = rect->xmax;
pos[1] = a;
- apply_distortion(tracking, pos, warped_pos);
+ apply_distortion(tracking, image_width, image_height, pos, warped_pos);
delta[0] = max_ff(delta[0], fabsf(pos[0] - warped_pos[0]));
delta[1] = max_ff(delta[1], fabsf(pos[1] - warped_pos[1]));
diff --git a/source/blender/blenkernel/intern/tracking_solver.c b/source/blender/blenkernel/intern/tracking_solver.c
index 5c1f6caad9d..46870a03e62 100644
--- a/source/blender/blenkernel/intern/tracking_solver.c
+++ b/source/blender/blenkernel/intern/tracking_solver.c
@@ -600,7 +600,7 @@ static void tracking_scale_reconstruction(ListBase *tracksbase,
sub_v3_v3(camera->mat[3], first_camera_delta);
}
- for (MovieTrackingTrack *track = tracksbase->first; track; track = track->next) {
+ LISTBASE_FOREACH (MovieTrackingTrack *, track, tracksbase) {
if (track->flag & TRACK_HAS_BUNDLE) {
mul_v3_v3(track->bundle_pos, scale);
sub_v3_v3(track->bundle_pos, first_camera_delta);
diff --git a/source/blender/blenkernel/intern/tracking_stabilize.c b/source/blender/blenkernel/intern/tracking_stabilize.c
index dffc703c943..e09e92588c6 100644
--- a/source/blender/blenkernel/intern/tracking_stabilize.c
+++ b/source/blender/blenkernel/intern/tracking_stabilize.c
@@ -42,6 +42,7 @@
#include "BKE_movieclip.h"
#include "BKE_tracking.h"
+#include "IMB_colormanagement.h"
#include "IMB_imbuf.h"
#include "IMB_imbuf_types.h"
#include "MEM_guardedalloc.h"
@@ -1399,7 +1400,7 @@ ImBuf *BKE_tracking_stabilize_frame(
return ibuf;
}
- /* Allocate frame for stabilization result. */
+ /* Allocate frame for stabilization result, copy alpha mode and colorspace. */
ibuf_flags = 0;
if (ibuf->rect) {
ibuf_flags |= IB_rect;
@@ -1409,6 +1410,7 @@ ImBuf *BKE_tracking_stabilize_frame(
}
tmpibuf = IMB_allocImBuf(ibuf->x, ibuf->y, ibuf->planes, ibuf_flags);
+ IMB_colormanagegent_copy_settings(ibuf, tmpibuf);
/* Calculate stabilization matrix. */
BKE_tracking_stabilization_data_get(clip, framenr, width, height, tloc, &tscale, &tangle);
diff --git a/source/blender/blenkernel/intern/tracking_util.c b/source/blender/blenkernel/intern/tracking_util.c
index 51758abdf3f..dcaa9082026 100644
--- a/source/blender/blenkernel/intern/tracking_util.c
+++ b/source/blender/blenkernel/intern/tracking_util.c
@@ -35,6 +35,7 @@
#include "BLI_math.h"
#include "BLI_string.h"
#include "BLI_string_utils.h"
+#include "BLI_threads.h"
#include "BLI_utildefines.h"
#include "BLT_translation.h"
@@ -432,6 +433,71 @@ void tracking_marker_insert_disabled(MovieTrackingTrack *track,
}
}
+static void distortion_model_parameters_from_tracking(
+ const MovieTrackingCamera *camera, libmv_CameraIntrinsicsOptions *camera_intrinsics_options)
+{
+ switch (camera->distortion_model) {
+ case TRACKING_DISTORTION_MODEL_POLYNOMIAL:
+ camera_intrinsics_options->distortion_model = LIBMV_DISTORTION_MODEL_POLYNOMIAL;
+ camera_intrinsics_options->polynomial_k1 = camera->k1;
+ camera_intrinsics_options->polynomial_k2 = camera->k2;
+ camera_intrinsics_options->polynomial_k3 = camera->k3;
+ camera_intrinsics_options->polynomial_p1 = 0.0;
+ camera_intrinsics_options->polynomial_p2 = 0.0;
+ return;
+
+ case TRACKING_DISTORTION_MODEL_DIVISION:
+ camera_intrinsics_options->distortion_model = LIBMV_DISTORTION_MODEL_DIVISION;
+ camera_intrinsics_options->division_k1 = camera->division_k1;
+ camera_intrinsics_options->division_k2 = camera->division_k2;
+ return;
+
+ case TRACKING_DISTORTION_MODEL_NUKE:
+ camera_intrinsics_options->distortion_model = LIBMV_DISTORTION_MODEL_NUKE;
+ camera_intrinsics_options->nuke_k1 = camera->nuke_k1;
+ camera_intrinsics_options->nuke_k2 = camera->nuke_k2;
+ return;
+ }
+
+ /* Unknown distortion model, which might be due to opening newer file in older Blender.
+ * Fallback to a known and supported model with 0 distortion. */
+ camera_intrinsics_options->distortion_model = LIBMV_DISTORTION_MODEL_POLYNOMIAL;
+ camera_intrinsics_options->polynomial_k1 = 0.0;
+ camera_intrinsics_options->polynomial_k2 = 0.0;
+ camera_intrinsics_options->polynomial_k3 = 0.0;
+ camera_intrinsics_options->polynomial_p1 = 0.0;
+ camera_intrinsics_options->polynomial_p2 = 0.0;
+}
+
+static void distortion_model_parameters_from_options(
+ const libmv_CameraIntrinsicsOptions *camera_intrinsics_options, MovieTrackingCamera *camera)
+{
+ switch (camera_intrinsics_options->distortion_model) {
+ case LIBMV_DISTORTION_MODEL_POLYNOMIAL:
+ camera->distortion_model = TRACKING_DISTORTION_MODEL_POLYNOMIAL;
+ camera->k1 = camera_intrinsics_options->polynomial_k1;
+ camera->k2 = camera_intrinsics_options->polynomial_k2;
+ camera->k3 = camera_intrinsics_options->polynomial_k3;
+ return;
+
+ case LIBMV_DISTORTION_MODEL_DIVISION:
+ camera->distortion_model = TRACKING_DISTORTION_MODEL_DIVISION;
+ camera->division_k1 = camera_intrinsics_options->division_k1;
+ camera->division_k2 = camera_intrinsics_options->division_k2;
+ return;
+
+ case LIBMV_DISTORTION_MODEL_NUKE:
+ camera->distortion_model = TRACKING_DISTORTION_MODEL_NUKE;
+ camera->nuke_k1 = camera_intrinsics_options->nuke_k1;
+ camera->nuke_k2 = camera_intrinsics_options->nuke_k2;
+ return;
+ }
+
+ /* Libmv returned distortion model which is not known to Blender. This is a logical error in code
+ * and Blender side is to be updated to match Libmv. */
+ BLI_assert(!"Unknown distortion model");
+}
+
/* Fill in Libmv C-API camera intrinsics options from tracking structure. */
void tracking_cameraIntrinscisOptionsFromTracking(
MovieTracking *tracking,
@@ -442,29 +508,14 @@ void tracking_cameraIntrinscisOptionsFromTracking(
MovieTrackingCamera *camera = &tracking->camera;
float aspy = 1.0f / tracking->camera.pixel_aspect;
+ camera_intrinsics_options->num_threads = BLI_system_thread_count();
+
camera_intrinsics_options->focal_length = camera->focal;
camera_intrinsics_options->principal_point_x = camera->principal[0];
camera_intrinsics_options->principal_point_y = camera->principal[1] * aspy;
- switch (camera->distortion_model) {
- case TRACKING_DISTORTION_MODEL_POLYNOMIAL:
- camera_intrinsics_options->distortion_model = LIBMV_DISTORTION_MODEL_POLYNOMIAL;
- camera_intrinsics_options->polynomial_k1 = camera->k1;
- camera_intrinsics_options->polynomial_k2 = camera->k2;
- camera_intrinsics_options->polynomial_k3 = camera->k3;
- camera_intrinsics_options->polynomial_p1 = 0.0;
- camera_intrinsics_options->polynomial_p2 = 0.0;
- break;
- case TRACKING_DISTORTION_MODEL_DIVISION:
- camera_intrinsics_options->distortion_model = LIBMV_DISTORTION_MODEL_DIVISION;
- camera_intrinsics_options->division_k1 = camera->division_k1;
- camera_intrinsics_options->division_k2 = camera->division_k2;
- break;
- default:
- BLI_assert(!"Unknown distortion model");
- break;
- }
+ distortion_model_parameters_from_tracking(camera, camera_intrinsics_options);
camera_intrinsics_options->image_width = calibration_width;
camera_intrinsics_options->image_height = (int)(calibration_height * aspy);
@@ -481,22 +532,7 @@ void tracking_trackingCameraFromIntrinscisOptions(
camera->principal[0] = camera_intrinsics_options->principal_point_x;
camera->principal[1] = camera_intrinsics_options->principal_point_y / (double)aspy;
- switch (camera_intrinsics_options->distortion_model) {
- case LIBMV_DISTORTION_MODEL_POLYNOMIAL:
- camera->distortion_model = TRACKING_DISTORTION_MODEL_POLYNOMIAL;
- camera->k1 = camera_intrinsics_options->polynomial_k1;
- camera->k2 = camera_intrinsics_options->polynomial_k2;
- camera->k3 = camera_intrinsics_options->polynomial_k3;
- break;
- case LIBMV_DISTORTION_MODEL_DIVISION:
- camera->distortion_model = TRACKING_DISTORTION_MODEL_DIVISION;
- camera->division_k1 = camera_intrinsics_options->division_k1;
- camera->division_k2 = camera_intrinsics_options->division_k2;
- break;
- default:
- BLI_assert(!"Unknown distortion model");
- break;
- }
+ distortion_model_parameters_from_options(camera_intrinsics_options, camera);
}
/* Get previous keyframed marker. */
@@ -677,7 +713,7 @@ static ImBuf *make_grayscale_ibuf_copy(ImBuf *ibuf)
*/
const size_t size = (size_t)grayscale->x * (size_t)grayscale->y * sizeof(float);
grayscale->channels = 1;
- if ((grayscale->rect_float = MEM_mapallocN(size, "tracking grayscale image")) != NULL) {
+ if ((grayscale->rect_float = MEM_callocN(size, "tracking grayscale image")) != NULL) {
grayscale->mall |= IB_rectfloat;
grayscale->flags |= IB_rectfloat;
@@ -705,7 +741,7 @@ static ImBuf *float_image_to_ibuf(libmv_FloatImage *float_image)
ImBuf *ibuf = IMB_allocImBuf(float_image->width, float_image->height, 32, 0);
size_t size = (size_t)ibuf->x * (size_t)ibuf->y * float_image->channels * sizeof(float);
ibuf->channels = float_image->channels;
- if ((ibuf->rect_float = MEM_mapallocN(size, "tracking grayscale image")) != NULL) {
+ if ((ibuf->rect_float = MEM_callocN(size, "tracking grayscale image")) != NULL) {
ibuf->mall |= IB_rectfloat;
ibuf->flags |= IB_rectfloat;
diff --git a/source/blender/blenkernel/intern/undo_system.c b/source/blender/blenkernel/intern/undo_system.c
index 6d484a7b702..e155dedeef0 100644
--- a/source/blender/blenkernel/intern/undo_system.c
+++ b/source/blender/blenkernel/intern/undo_system.c
@@ -110,7 +110,7 @@ static ListBase g_undo_types = {NULL, NULL};
static const UndoType *BKE_undosys_type_from_context(bContext *C)
{
- for (const UndoType *ut = g_undo_types.first; ut; ut = ut->next) {
+ LISTBASE_FOREACH (const UndoType *, ut, &g_undo_types) {
/* No poll means we don't check context. */
if (ut->poll && ut->poll(C)) {
return ut;
@@ -143,7 +143,7 @@ static void undosys_id_ref_resolve(void *user_data, UndoRefID *id_ref)
* for now it's not too bad since it only runs when we access undo! */
Main *bmain = user_data;
ListBase *lb = which_libbase(bmain, GS(id_ref->name));
- for (ID *id = lb->first; id; id = id->next) {
+ LISTBASE_FOREACH (ID *, id, lb) {
if (STREQ(id_ref->name, id->name) && (id->lib == NULL)) {
id_ref->ptr = id;
break;
@@ -399,7 +399,7 @@ UndoStep *BKE_undosys_stack_init_or_active_with_type(UndoStack *ustack, const Un
void BKE_undosys_stack_limit_steps_and_memory(UndoStack *ustack, int steps, size_t memory_limit)
{
UNDO_NESTED_ASSERT(false);
- if (!(steps || memory_limit)) {
+ if ((steps == -1) && (memory_limit != 0)) {
return;
}
@@ -416,7 +416,7 @@ void BKE_undosys_stack_limit_steps_and_memory(UndoStack *ustack, int steps, size
break;
}
}
- if (steps) {
+ if (steps != -1) {
if (us_count == steps) {
break;
}
@@ -427,10 +427,6 @@ void BKE_undosys_stack_limit_steps_and_memory(UndoStack *ustack, int steps, size
}
if (us) {
- if (us->prev && us->prev->prev) {
- us = us->prev;
- }
-
#ifdef WITH_GLOBAL_UNDO_KEEP_ONE
/* Hack, we need to keep at least one BKE_UNDOSYS_TYPE_MEMFILE. */
if (us->type != BKE_UNDOSYS_TYPE_MEMFILE) {
@@ -438,6 +434,12 @@ void BKE_undosys_stack_limit_steps_and_memory(UndoStack *ustack, int steps, size
while (us_exclude && us_exclude->type != BKE_UNDOSYS_TYPE_MEMFILE) {
us_exclude = us_exclude->prev;
}
+ /* Once this is outside the given number of 'steps', undoing onto this state
+ * may skip past many undo steps which is confusing, instead,
+ * disallow stepping onto this state entirely. */
+ if (us_exclude) {
+ us_exclude->skip = true;
+ }
}
#endif
/* Free from first to last, free functions may update de-duplication info
@@ -464,12 +466,12 @@ UndoStep *BKE_undosys_step_push_init_with_type(UndoStack *ustack,
}
UndoStep *us = MEM_callocN(ut->step_size, __func__);
- CLOG_INFO(&LOG, 1, "addr=%p, name='%s', type='%s'", us, name, ut->name);
if (name != NULL) {
BLI_strncpy(us->name, name, sizeof(us->name));
}
us->type = ut;
ustack->step_init = us;
+ CLOG_INFO(&LOG, 1, "addr=%p, name='%s', type='%s'", us, us->name, us->type->name);
ut->step_encode_init(C, us);
undosys_stack_validate(ustack, false);
return us;
@@ -552,6 +554,8 @@ bool BKE_undosys_step_push_with_type(UndoStack *ustack,
us->type = ut;
/* Initialized, not added yet. */
+ CLOG_INFO(&LOG, 1, "addr=%p, name='%s', type='%s'", us, us->name, us->type->name);
+
if (!undosys_step_encode(C, G_MAIN, ustack, us)) {
MEM_freeN(us);
undosys_stack_validate(ustack, true);
@@ -670,7 +674,15 @@ bool BKE_undosys_step_undo_with_data_ex(UndoStack *ustack,
us = us_prev;
}
- if (us != NULL) {
+ /* This will be active once complete. */
+ UndoStep *us_active = us_prev;
+ if (use_skip) {
+ while (us_active && us_active->skip) {
+ us_active = us_active->prev;
+ }
+ }
+
+ if ((us != NULL) && (us_active != NULL)) {
CLOG_INFO(&LOG, 1, "addr=%p, name='%s', type='%s'", us, us->name, us->type->name);
/* Handle accumulate steps. */
@@ -687,13 +699,6 @@ bool BKE_undosys_step_undo_with_data_ex(UndoStack *ustack,
}
}
- UndoStep *us_active = us_prev;
- if (use_skip) {
- while (us_active->skip && us_active->prev) {
- us_active = us_active->prev;
- }
- }
-
{
UndoStep *us_iter = us_prev;
do {
@@ -742,7 +747,15 @@ bool BKE_undosys_step_redo_with_data_ex(UndoStack *ustack,
/* Unlike undo accumulate, we always use the next. */
us = us_next;
- if (us != NULL) {
+ /* This will be active once complete. */
+ UndoStep *us_active = us_next;
+ if (use_skip) {
+ while (us_active && us_active->skip) {
+ us_active = us_active->next;
+ }
+ }
+
+ if ((us != NULL) && (us_active != NULL)) {
CLOG_INFO(&LOG, 1, "addr=%p, name='%s', type='%s'", us, us->name, us->type->name);
/* Handle accumulate steps. */
@@ -754,13 +767,6 @@ bool BKE_undosys_step_redo_with_data_ex(UndoStack *ustack,
}
}
- UndoStep *us_active = us_next;
- if (use_skip) {
- while (us_active->skip && us_active->prev) {
- us_active = us_active->next;
- }
- }
-
{
UndoStep *us_iter = us_next;
do {
@@ -855,7 +861,7 @@ static void UNUSED_FUNCTION(BKE_undosys_foreach_ID_ref(UndoStack *ustack,
UndoTypeForEachIDRefFn foreach_ID_ref_fn,
void *user_data))
{
- for (UndoStep *us = ustack->steps.first; us; us = us->next) {
+ LISTBASE_FOREACH (UndoStep *, us, &ustack->steps) {
const UndoType *ut = us->type;
if (ut->step_foreach_ID_ref != NULL) {
ut->step_foreach_ID_ref(us, foreach_ID_ref_fn, user_data);
@@ -874,13 +880,14 @@ void BKE_undosys_print(UndoStack *ustack)
printf("Undo %d Steps (*: active, #=applied, M=memfile-active, S=skip)\n",
BLI_listbase_count(&ustack->steps));
int index = 0;
- for (UndoStep *us = ustack->steps.first; us; us = us->next) {
- printf("[%c%c%c%c] %3d type='%s', name='%s'\n",
+ LISTBASE_FOREACH (UndoStep *, us, &ustack->steps) {
+ printf("[%c%c%c%c] %3d {%p} type='%s', name='%s'\n",
(us == ustack->step_active) ? '*' : ' ',
us->is_applied ? '#' : ' ',
(us == ustack->step_active_memfile) ? 'M' : ' ',
us->skip ? 'S' : ' ',
index,
+ (void *)us,
us->type->name,
us->name);
index++;
diff --git a/source/blender/blenkernel/intern/unit.c b/source/blender/blenkernel/intern/unit.c
index 3f44c13ba19..f37feab4b85 100644
--- a/source/blender/blenkernel/intern/unit.c
+++ b/source/blender/blenkernel/intern/unit.c
@@ -713,6 +713,113 @@ static bool ch_is_op(char op)
}
}
+/**
+ * Helper function for #unit_distribute_negatives to find the next negative to distribute.
+ *
+ * \note This unnecessarily skips the next space if it comes right after the "-"
+ * just to make a more predictable output.
+ */
+static char *find_next_negative(const char *str, const char *remaining_str)
+{
+ char *str_found = strstr(remaining_str, "-");
+
+ if (str_found == NULL) {
+ return NULL;
+ }
+
+ /* Don't use the "-" from scientific notation, but make sure we can look backwards first. */
+ if ((str_found != str) && ELEM(*(str_found - 1), 'e', 'E')) {
+ return find_next_negative(str, str_found + 1);
+ }
+
+ if (*(str_found + 1) == ' ') {
+ str_found++;
+ }
+
+ return str_found + 1;
+}
+
+/**
+ * Helper function for #unit_distribute_negatives to find the next operation, including "-".
+ *
+ * \note This unnecessarily skips the space before the operation character
+ * just to make a more predictable output.
+ */
+static char *find_next_op(const char *str, char *remaining_str, int len_max)
+{
+ int i;
+ bool scientific_notation = false;
+ for (i = 0; i < len_max; i++) {
+ if (remaining_str[i] == '\0') {
+ return remaining_str + i;
+ }
+
+ if (ch_is_op(remaining_str[i])) {
+ if (scientific_notation) {
+ scientific_notation = false;
+ continue;
+ }
+
+ /* Make sure we don't look backwards before the start of the string. */
+ if (remaining_str != str && i != 0) {
+ /* Check for scientific notation. */
+ if (remaining_str[i - 1] == 'e' || remaining_str[i - 1] == 'E') {
+ scientific_notation = true;
+ continue;
+ }
+
+ /* Return position before a space character. */
+ if (remaining_str[i - 1] == ' ') {
+ i--;
+ }
+ }
+
+ return remaining_str + i;
+ }
+ }
+ BLI_assert(!"String should be NULL terminated");
+ return remaining_str + i;
+}
+
+/**
+ * Put parentheses around blocks of values after negative signs to get rid of an implied "+"
+ * between numbers without an operation between them. For example:
+ *
+ * "-1m50cm + 1 - 2m50cm" -> "-(1m50cm) + 1 - (2m50cm)"
+ */
+static bool unit_distribute_negatives(char *str, const int len_max)
+{
+ bool changed = false;
+
+ char *remaining_str = str;
+ int remaining_str_len = len_max;
+ while ((remaining_str = find_next_negative(str, remaining_str)) != NULL) {
+ /* Exit early in the unlikely situation that we've run out of length to add the parentheses. */
+ remaining_str_len = len_max - (int)(remaining_str - str);
+ if (remaining_str_len <= 2) {
+ return changed;
+ }
+
+ changed = true;
+
+ /* Add '(', shift the following characters to the right to make space. */
+ memmove(remaining_str + 1, remaining_str, remaining_str_len - 2);
+ *remaining_str = '(';
+
+ /* Add the ')' before the next operation or at the end. */
+ remaining_str = find_next_op(str, remaining_str + 1, remaining_str_len);
+ remaining_str_len = len_max - (int)(remaining_str - str);
+ memmove(remaining_str + 1, remaining_str, remaining_str_len - 2);
+ *remaining_str = ')';
+
+ /* Only move forward by 1 even though we added two characters. Minus signs need to be able to
+ * apply to the next block of values too. */
+ remaining_str += 1;
+ }
+
+ return changed;
+}
+
static int unit_scale_str(char *str,
int len_max,
char *str_tmp,
@@ -896,6 +1003,10 @@ bool bUnit_ReplaceString(
char str_tmp[TEMP_STR_SIZE];
bool changed = false;
+ /* Fix cases like "-1m50cm" which would evaluate to -0.5m without this. */
+ changed |= unit_distribute_negatives(str, len_max);
+ printf("%s\n", str);
+
/* Try to find a default unit from current or previous string. */
default_unit = unit_detect_from_str(usys, str, str_prev);
diff --git a/source/blender/blenkernel/intern/volume.cc b/source/blender/blenkernel/intern/volume.cc
index 6e00a942283..26c5810aefa 100644
--- a/source/blender/blenkernel/intern/volume.cc
+++ b/source/blender/blenkernel/intern/volume.cc
@@ -21,6 +21,7 @@
#include "MEM_guardedalloc.h"
#include "DNA_defaults.h"
+#include "DNA_material_types.h"
#include "DNA_object_types.h"
#include "DNA_scene_types.h"
#include "DNA_volume_types.h"
@@ -33,7 +34,7 @@
#include "BLI_string.h"
#include "BLI_utildefines.h"
-#include "BKE_animsys.h"
+#include "BKE_anim_data.h"
#include "BKE_global.h"
#include "BKE_idtype.h"
#include "BKE_lib_id.h"
@@ -442,26 +443,6 @@ static void volume_init_data(ID *id)
BKE_volume_init_grids(volume);
}
-void BKE_volume_init_grids(Volume *volume)
-{
-#ifdef WITH_OPENVDB
- if (volume->runtime.grids == NULL) {
- volume->runtime.grids = OBJECT_GUARDED_NEW(VolumeGridVector);
- }
-#else
- UNUSED_VARS(volume);
-#endif
-}
-
-void *BKE_volume_add(Main *bmain, const char *name)
-{
- Volume *volume = (Volume *)BKE_libblock_alloc(bmain, ID_VO, name, 0);
-
- volume_init_data(&volume->id);
-
- return volume;
-}
-
static void volume_copy_data(Main *UNUSED(bmain),
ID *id_dst,
const ID *id_src,
@@ -483,18 +464,6 @@ static void volume_copy_data(Main *UNUSED(bmain),
#endif
}
-Volume *BKE_volume_copy(Main *bmain, const Volume *volume)
-{
- Volume *volume_copy;
- BKE_id_copy(bmain, &volume->id, (ID **)&volume_copy);
- return volume_copy;
-}
-
-static void volume_make_local(Main *bmain, ID *id, const int flags)
-{
- BKE_lib_id_make_local_generic(bmain, id, flags);
-}
-
static void volume_free_data(ID *id)
{
Volume *volume = (Volume *)id;
@@ -506,6 +475,14 @@ static void volume_free_data(ID *id)
#endif
}
+static void volume_foreach_id(ID *id, LibraryForeachIDData *data)
+{
+ Volume *volume = (Volume *)id;
+ for (int i = 0; i < volume->totcol; i++) {
+ BKE_LIB_FOREACHID_PROCESS(data, volume->mat[i], IDWALK_CB_USER);
+ }
+}
+
IDTypeInfo IDType_ID_VO = {
/* id_code */ ID_VO,
/* id_filter */ FILTER_ID_VO,
@@ -519,9 +496,37 @@ IDTypeInfo IDType_ID_VO = {
/* init_data */ volume_init_data,
/* copy_data */ volume_copy_data,
/* free_data */ volume_free_data,
- /* make_local */ volume_make_local,
+ /* make_local */ nullptr,
+ /* foreach_id */ volume_foreach_id,
};
+void BKE_volume_init_grids(Volume *volume)
+{
+#ifdef WITH_OPENVDB
+ if (volume->runtime.grids == NULL) {
+ volume->runtime.grids = OBJECT_GUARDED_NEW(VolumeGridVector);
+ }
+#else
+ UNUSED_VARS(volume);
+#endif
+}
+
+void *BKE_volume_add(Main *bmain, const char *name)
+{
+ Volume *volume = (Volume *)BKE_libblock_alloc(bmain, ID_VO, name, 0);
+
+ volume_init_data(&volume->id);
+
+ return volume;
+}
+
+Volume *BKE_volume_copy(Main *bmain, const Volume *volume)
+{
+ Volume *volume_copy;
+ BKE_id_copy(bmain, &volume->id, (ID **)&volume_copy);
+ return volume_copy;
+}
+
/* Sequence */
static int volume_sequence_frame(const Depsgraph *depsgraph, const Volume *volume)
@@ -795,12 +800,52 @@ bool BKE_volume_is_points_only(const Volume *volume)
/* Dependency Graph */
-static Volume *volume_evaluate_modifiers(struct Depsgraph *UNUSED(depsgraph),
- struct Scene *UNUSED(scene),
- Object *UNUSED(object),
+static Volume *volume_evaluate_modifiers(struct Depsgraph *depsgraph,
+ struct Scene *scene,
+ Object *object,
Volume *volume_input)
{
- return volume_input;
+ Volume *volume = volume_input;
+
+ /* Modifier evaluation modes. */
+ const bool use_render = (DEG_get_mode(depsgraph) == DAG_EVAL_RENDER);
+ const int required_mode = use_render ? eModifierMode_Render : eModifierMode_Realtime;
+ ModifierApplyFlag apply_flag = use_render ? MOD_APPLY_RENDER : MOD_APPLY_USECACHE;
+ const ModifierEvalContext mectx = {depsgraph, object, apply_flag};
+
+ /* Get effective list of modifiers to execute. Some effects like shape keys
+ * are added as virtual modifiers before the user created modifiers. */
+ VirtualModifierData virtualModifierData;
+ ModifierData *md = BKE_modifiers_get_virtual_modifierlist(object, &virtualModifierData);
+
+ /* Evaluate modifiers. */
+ for (; md; md = md->next) {
+ const ModifierTypeInfo *mti = (const ModifierTypeInfo *)BKE_modifier_get_info(
+ (ModifierType)md->type);
+
+ if (!BKE_modifier_is_enabled(scene, md, required_mode)) {
+ continue;
+ }
+
+ if (mti->modifyVolume) {
+ /* Ensure we are not modifying the input. */
+ if (volume == volume_input) {
+ volume = BKE_volume_copy_for_eval(volume, true);
+ }
+
+ Volume *volume_next = mti->modifyVolume(md, &mectx, volume);
+
+ if (volume_next && volume_next != volume) {
+ /* If the modifier returned a new volume, release the old one. */
+ if (volume != volume_input) {
+ BKE_id_free(NULL, volume);
+ }
+ volume = volume_next;
+ }
+ }
+ }
+
+ return volume;
}
void BKE_volume_eval_geometry(struct Depsgraph *depsgraph, Volume *volume)
@@ -815,7 +860,10 @@ void BKE_volume_eval_geometry(struct Depsgraph *depsgraph, Volume *volume)
/* Flush back to original. */
if (DEG_is_active(depsgraph)) {
Volume *volume_orig = (Volume *)DEG_get_original_id(&volume->id);
- volume_orig->runtime.frame = volume->runtime.frame;
+ if (volume_orig->runtime.frame != volume->runtime.frame) {
+ BKE_volume_unload(volume_orig);
+ volume_orig->runtime.frame = volume->runtime.frame;
+ }
}
}
@@ -901,6 +949,16 @@ const char *BKE_volume_grids_error_msg(const Volume *volume)
#endif
}
+const char *BKE_volume_grids_frame_filepath(const Volume *volume)
+{
+#ifdef WITH_OPENVDB
+ return volume->runtime.grids->filepath;
+#else
+ UNUSED_VARS(volume);
+ return "";
+#endif
+}
+
VolumeGrid *BKE_volume_grid_get(const Volume *volume, int grid_index)
{
#ifdef WITH_OPENVDB
diff --git a/source/blender/blenkernel/intern/workspace.c b/source/blender/blenkernel/intern/workspace.c
index 66a3c2cdced..4625fd76293 100644
--- a/source/blender/blenkernel/intern/workspace.c
+++ b/source/blender/blenkernel/intern/workspace.c
@@ -32,6 +32,7 @@
#include "BKE_idprop.h"
#include "BKE_idtype.h"
#include "BKE_lib_id.h"
+#include "BKE_lib_query.h"
#include "BKE_main.h"
#include "BKE_object.h"
#include "BKE_scene.h"
@@ -65,6 +66,15 @@ static void workspace_free_data(ID *id)
MEM_SAFE_FREE(workspace->status_text);
}
+static void workspace_foreach_id(ID *id, LibraryForeachIDData *data)
+{
+ WorkSpace *workspace = (WorkSpace *)id;
+
+ LISTBASE_FOREACH (WorkSpaceLayout *, layout, &workspace->layouts) {
+ BKE_LIB_FOREACHID_PROCESS(data, layout->screen, IDWALK_CB_USER);
+ }
+}
+
IDTypeInfo IDType_ID_WS = {
.id_code = ID_WS,
.id_filter = FILTER_ID_WS,
@@ -79,6 +89,7 @@ IDTypeInfo IDType_ID_WS = {
.copy_data = NULL,
.free_data = workspace_free_data,
.make_local = NULL,
+ .foreach_id = workspace_foreach_id,
};
/** \name Internal Utils
@@ -209,7 +220,7 @@ WorkSpaceInstanceHook *BKE_workspace_instance_hook_create(const Main *bmain)
/* set an active screen-layout for each possible window/workspace combination */
for (WorkSpace *workspace = bmain->workspaces.first; workspace; workspace = workspace->id.next) {
- BKE_workspace_hook_layout_for_workspace_set(hook, workspace, workspace->layouts.first);
+ BKE_workspace_active_layout_set(hook, workspace, workspace->layouts.first);
}
return hook;
@@ -396,7 +407,7 @@ void BKE_workspace_id_tag_all_visible(Main *bmain, int tag)
{
BKE_main_id_tag_listbase(&bmain->workspaces, tag, false);
wmWindowManager *wm = bmain->wm.first;
- for (wmWindow *win = wm->windows.first; win; win = win->next) {
+ LISTBASE_FOREACH (wmWindow *, win, &wm->windows) {
WorkSpace *workspace = BKE_workspace_active_get(win->workspace_hook);
workspace->id.tag |= tag;
}
@@ -414,6 +425,10 @@ WorkSpace *BKE_workspace_active_get(WorkSpaceInstanceHook *hook)
}
void BKE_workspace_active_set(WorkSpaceInstanceHook *hook, WorkSpace *workspace)
{
+ if (hook->active == workspace) {
+ return;
+ }
+
hook->active = workspace;
if (workspace) {
WorkSpaceLayout *layout = workspace_relation_get_data_matching_parent(
@@ -424,13 +439,47 @@ void BKE_workspace_active_set(WorkSpaceInstanceHook *hook, WorkSpace *workspace)
}
}
+/**
+ * Get the layout that is active for \a hook (which is the visible layout for the active workspace
+ * in \a hook).
+ */
WorkSpaceLayout *BKE_workspace_active_layout_get(const WorkSpaceInstanceHook *hook)
{
return hook->act_layout;
}
-void BKE_workspace_active_layout_set(WorkSpaceInstanceHook *hook, WorkSpaceLayout *layout)
+
+/**
+ * Get the layout to be activated should \a workspace become or be the active workspace in \a hook.
+ */
+WorkSpaceLayout *BKE_workspace_active_layout_for_workspace_get(const WorkSpaceInstanceHook *hook,
+ const WorkSpace *workspace)
+{
+ /* If the workspace is active, the active layout can be returned, no need for a lookup. */
+ if (hook->active == workspace) {
+ return hook->act_layout;
+ }
+
+ /* Inactive workspace */
+ return workspace_relation_get_data_matching_parent(&workspace->hook_layout_relations, hook);
+}
+
+/**
+ * \brief Activate a layout
+ *
+ * Sets \a layout as active for \a workspace when activated through or already active in \a hook.
+ * So when the active workspace of \a hook is \a workspace, \a layout becomes the active layout of
+ * \a hook too. See #BKE_workspace_active_set().
+ *
+ * \a workspace does not need to be active for this.
+ *
+ * WorkSpaceInstanceHook.act_layout should only be modified directly to update the layout pointer.
+ */
+void BKE_workspace_active_layout_set(WorkSpaceInstanceHook *hook,
+ WorkSpace *workspace,
+ WorkSpaceLayout *layout)
{
hook->act_layout = layout;
+ workspace_relation_ensure_updated(&workspace->hook_layout_relations, hook, layout);
}
bScreen *BKE_workspace_active_screen_get(const WorkSpaceInstanceHook *hook)
@@ -443,12 +492,7 @@ void BKE_workspace_active_screen_set(WorkSpaceInstanceHook *hook,
{
/* we need to find the WorkspaceLayout that wraps this screen */
WorkSpaceLayout *layout = BKE_workspace_layout_find(hook->active, screen);
- BKE_workspace_hook_layout_for_workspace_set(hook, workspace, layout);
-}
-
-ListBase *BKE_workspace_layouts_get(WorkSpace *workspace)
-{
- return &workspace->layouts;
+ BKE_workspace_active_layout_set(hook, workspace, layout);
}
const char *BKE_workspace_layout_name_get(const WorkSpaceLayout *layout)
@@ -466,22 +510,5 @@ bScreen *BKE_workspace_layout_screen_get(const WorkSpaceLayout *layout)
{
return layout->screen;
}
-void BKE_workspace_layout_screen_set(WorkSpaceLayout *layout, bScreen *screen)
-{
- layout->screen = screen;
-}
-
-WorkSpaceLayout *BKE_workspace_hook_layout_for_workspace_get(const WorkSpaceInstanceHook *hook,
- const WorkSpace *workspace)
-{
- return workspace_relation_get_data_matching_parent(&workspace->hook_layout_relations, hook);
-}
-void BKE_workspace_hook_layout_for_workspace_set(WorkSpaceInstanceHook *hook,
- WorkSpace *workspace,
- WorkSpaceLayout *layout)
-{
- hook->act_layout = layout;
- workspace_relation_ensure_updated(&workspace->hook_layout_relations, hook, layout);
-}
/** \} */
diff --git a/source/blender/blenkernel/intern/world.c b/source/blender/blenkernel/intern/world.c
index 3492a35b242..e3b58e03d93 100644
--- a/source/blender/blenkernel/intern/world.c
+++ b/source/blender/blenkernel/intern/world.c
@@ -35,10 +35,10 @@
#include "BLI_listbase.h"
#include "BLI_utildefines.h"
-#include "BKE_animsys.h"
#include "BKE_icons.h"
#include "BKE_idtype.h"
#include "BKE_lib_id.h"
+#include "BKE_lib_query.h"
#include "BKE_main.h"
#include "BKE_node.h"
#include "BKE_world.h"
@@ -60,7 +60,7 @@ static void world_free_data(ID *id)
/* is no lib link block, but world extension */
if (wrld->nodetree) {
- ntreeFreeNestedTree(wrld->nodetree);
+ ntreeFreeEmbeddedTree(wrld->nodetree);
MEM_freeN(wrld->nodetree);
wrld->nodetree = NULL;
}
@@ -79,17 +79,6 @@ static void world_init_data(ID *id)
MEMCPY_STRUCT_AFTER(wrld, DNA_struct_default_get(World), id);
}
-World *BKE_world_add(Main *bmain, const char *name)
-{
- World *wrld;
-
- wrld = BKE_libblock_alloc(bmain, ID_WO, name, 0);
-
- world_init_data(&wrld->id);
-
- return wrld;
-}
-
/**
* Only copy internal data of World ID from source
* to already allocated/initialized destination.
@@ -123,6 +112,44 @@ static void world_copy_data(Main *bmain, ID *id_dst, const ID *id_src, const int
}
}
+static void world_foreach_id(ID *id, LibraryForeachIDData *data)
+{
+ World *world = (World *)id;
+
+ if (world->nodetree) {
+ /* nodetree **are owned by IDs**, treat them as mere sub-data and not real ID! */
+ BKE_library_foreach_ID_embedded(data, (ID **)&world->nodetree);
+ }
+}
+
+IDTypeInfo IDType_ID_WO = {
+ .id_code = ID_WO,
+ .id_filter = FILTER_ID_WO,
+ .main_listbase_index = INDEX_ID_WO,
+ .struct_size = sizeof(World),
+ .name = "World",
+ .name_plural = "worlds",
+ .translation_context = BLT_I18NCONTEXT_ID_WORLD,
+ .flags = 0,
+
+ .init_data = world_init_data,
+ .copy_data = world_copy_data,
+ .free_data = world_free_data,
+ .make_local = NULL,
+ .foreach_id = world_foreach_id,
+};
+
+World *BKE_world_add(Main *bmain, const char *name)
+{
+ World *wrld;
+
+ wrld = BKE_libblock_alloc(bmain, ID_WO, name, 0);
+
+ world_init_data(&wrld->id);
+
+ return wrld;
+}
+
World *BKE_world_copy(Main *bmain, const World *wrld)
{
World *wrld_copy;
@@ -160,27 +187,6 @@ World *BKE_world_localize(World *wrld)
return wrldn;
}
-static void world_make_local(Main *bmain, ID *id, const int flags)
-{
- BKE_lib_id_make_local_generic(bmain, id, flags);
-}
-
-IDTypeInfo IDType_ID_WO = {
- .id_code = ID_WO,
- .id_filter = FILTER_ID_WO,
- .main_listbase_index = INDEX_ID_WO,
- .struct_size = sizeof(World),
- .name = "World",
- .name_plural = "worlds",
- .translation_context = BLT_I18NCONTEXT_ID_WORLD,
- .flags = 0,
-
- .init_data = world_init_data,
- .copy_data = world_copy_data,
- .free_data = world_free_data,
- .make_local = world_make_local,
-};
-
void BKE_world_eval(struct Depsgraph *depsgraph, World *world)
{
DEG_debug_print_eval(depsgraph, __func__, world->id.name, world);
diff --git a/source/blender/blenkernel/intern/writeffmpeg.c b/source/blender/blenkernel/intern/writeffmpeg.c
index 16e56200131..724c4ab93b2 100644
--- a/source/blender/blenkernel/intern/writeffmpeg.c
+++ b/source/blender/blenkernel/intern/writeffmpeg.c
@@ -606,7 +606,10 @@ static AVStream *alloc_video_stream(FFMpegContext *context,
c->gop_size = context->ffmpeg_gop_size;
c->max_b_frames = context->ffmpeg_max_b_frames;
- if (context->ffmpeg_crf >= 0) {
+ if (context->ffmpeg_type == FFMPEG_WEBM && context->ffmpeg_crf == 0) {
+ ffmpeg_dict_set_int(&opts, "lossless", 1);
+ }
+ else if (context->ffmpeg_crf >= 0) {
ffmpeg_dict_set_int(&opts, "crf", context->ffmpeg_crf);
}
else {
diff --git a/source/blender/blenlib/BLI_allocator.h b/source/blender/blenlib/BLI_allocator.hh
index e2d39c4e897..c52db4aab53 100644
--- a/source/blender/blenlib/BLI_allocator.h
+++ b/source/blender/blenlib/BLI_allocator.hh
@@ -13,8 +13,8 @@
* along with this program; if not, write to the Free Software Foundation,
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
-#ifndef __BLI_ALLOCATOR_H__
-#define __BLI_ALLOCATOR_H__
+#ifndef __BLI_ALLOCATOR_HH__
+#define __BLI_ALLOCATOR_HH__
/** \file
* \ingroup bli
@@ -102,4 +102,4 @@ class RawAllocator {
} // namespace BLI
-#endif /* __BLI_ALLOCATOR_H__ */
+#endif /* __BLI_ALLOCATOR_HH__ */
diff --git a/source/blender/blenlib/BLI_array_cxx.h b/source/blender/blenlib/BLI_array.hh
index 8fc2aec6698..9dd8341aa76 100644
--- a/source/blender/blenlib/BLI_array_cxx.h
+++ b/source/blender/blenlib/BLI_array.hh
@@ -13,8 +13,8 @@
* along with this program; if not, write to the Free Software Foundation,
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
-#ifndef __BLI_ARRAY_CXX_H__
-#define __BLI_ARRAY_CXX_H__
+#ifndef __BLI_ARRAY_HH__
+#define __BLI_ARRAY_HH__
/** \file
* \ingroup bli
@@ -23,20 +23,21 @@
* a template argument. Instead it can be specified at the construction time.
*/
-#include "BLI_allocator.h"
-#include "BLI_array_ref.h"
-#include "BLI_index_range.h"
-#include "BLI_memory_utils_cxx.h"
+#include "BLI_allocator.hh"
+#include "BLI_array_ref.hh"
+#include "BLI_index_range.hh"
+#include "BLI_memory_utils.hh"
#include "BLI_utildefines.h"
namespace BLI {
-template<typename T, uint N = 4, typename Allocator = GuardedAllocator> class Array {
+template<typename T, uint InlineBufferCapacity = 4, typename Allocator = GuardedAllocator>
+class Array {
private:
T *m_data;
uint m_size;
Allocator m_allocator;
- AlignedBuffer<sizeof(T) * N, alignof(T)> m_inline_storage;
+ AlignedBuffer<sizeof(T) * InlineBufferCapacity, alignof(T)> m_inline_storage;
public:
Array()
@@ -79,7 +80,7 @@ template<typename T, uint N = 4, typename Allocator = GuardedAllocator> class Ar
m_allocator = other.m_allocator;
m_data = this->get_buffer_for_size(other.size());
- copy_n(other.begin(), m_size, m_data);
+ uninitialized_copy_n(other.begin(), m_size, m_data);
}
Array(Array &&other) noexcept
@@ -201,10 +202,15 @@ template<typename T, uint N = 4, typename Allocator = GuardedAllocator> class Ar
return IndexRange(m_size);
}
+ Allocator &allocator()
+ {
+ return m_allocator;
+ }
+
private:
T *get_buffer_for_size(uint size)
{
- if (size <= N) {
+ if (size <= InlineBufferCapacity) {
return this->inline_storage();
}
else {
@@ -231,4 +237,4 @@ template<typename T, uint N = 4, typename Allocator = GuardedAllocator> class Ar
} // namespace BLI
-#endif /* __BLI_ARRAY_CXX_H__ */
+#endif /* __BLI_ARRAY_HH__ */
diff --git a/source/blender/blenlib/BLI_array_ref.h b/source/blender/blenlib/BLI_array_ref.hh
index 2c2e441a47d..c0484493bda 100644
--- a/source/blender/blenlib/BLI_array_ref.h
+++ b/source/blender/blenlib/BLI_array_ref.hh
@@ -14,8 +14,8 @@
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
-#ifndef __BLI_ARRAY_REF_H__
-#define __BLI_ARRAY_REF_H__
+#ifndef __BLI_ARRAY_REF_HH__
+#define __BLI_ARRAY_REF_HH__
/** \file
* \ingroup bli
@@ -41,8 +41,8 @@
#include <string>
#include <vector>
-#include "BLI_index_range.h"
-#include "BLI_memory_utils_cxx.h"
+#include "BLI_index_range.hh"
+#include "BLI_memory_utils.hh"
#include "BLI_utildefines.h"
namespace BLI {
@@ -508,6 +508,16 @@ template<typename T> class MutableArrayRef {
BLI_assert(m_size > 0);
return m_start[m_size - 1];
}
+
+ /**
+ * Get a new array ref to the same underlying memory buffer. No conversions are done.
+ */
+ template<typename NewT> MutableArrayRef<NewT> cast() const
+ {
+ BLI_assert((m_size * sizeof(T)) % sizeof(NewT) == 0);
+ uint new_size = m_size * sizeof(T) / sizeof(NewT);
+ return MutableArrayRef<NewT>(reinterpret_cast<NewT *>(m_start), new_size);
+ }
};
/**
@@ -542,4 +552,4 @@ void assert_same_size(const T1 &v1, const T2 &v2, const T3 &v3)
} /* namespace BLI */
-#endif /* __BLI_ARRAY_REF_H__ */
+#endif /* __BLI_ARRAY_REF_HH__ */
diff --git a/source/blender/blenlib/BLI_asan.h b/source/blender/blenlib/BLI_asan.h
new file mode 100644
index 00000000000..fdade805c2a
--- /dev/null
+++ b/source/blender/blenlib/BLI_asan.h
@@ -0,0 +1,45 @@
+/*
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+
+#ifndef __BLI_ADDRESS_SANITIZER_H__
+#define __BLI_ADDRESS_SANITIZER_H__
+
+/* Clang defines this. */
+#ifndef __has_feature
+# define __has_feature(x) 0
+#endif
+
+#if defined(__SANITIZE_ADDRESS__) || __has_feature(address_sanitizer)
+# include "sanitizer/asan_interface.h"
+#else
+/* Ensure return value is used. Just using UNUSED_VARS results in a warning. */
+# define ASAN_POISON_MEMORY_REGION(addr, size) (void)(0 && ((size) != 0 && (addr) != NULL))
+# define ASAN_UNPOISON_MEMORY_REGION(addr, size) (void)(0 && ((size) != 0 && (addr) != NULL))
+#endif
+
+/**
+ * Mark a region of memory as "freed". When using address sanitizer, accessing the given memory
+ * region will cause an use-after-poison error. This can be used to find errors when dealing with
+ * uninitialized memory in custom containers.
+ */
+#define BLI_asan_poison(addr, size) ASAN_POISON_MEMORY_REGION(addr, size)
+
+/**
+ * Mark a region of memory as usable again.
+ */
+#define BLI_asan_unpoison(addr, size) ASAN_UNPOISON_MEMORY_REGION(addr, size)
+
+#endif /* __BLI_ADDRESS_SANITIZER_H__ */
diff --git a/source/blender/blenlib/BLI_assert.h b/source/blender/blenlib/BLI_assert.h
index b9cb32a310e..603be115b35 100644
--- a/source/blender/blenlib/BLI_assert.h
+++ b/source/blender/blenlib/BLI_assert.h
@@ -69,7 +69,13 @@ extern "C" {
# endif
/* _BLI_ASSERT_ABORT */
# ifdef WITH_ASSERT_ABORT
-# define _BLI_ASSERT_ABORT abort
+# ifdef __GNUC__
+/* Cast to remove 'noreturn' attribute since this suppresses missing return statements,
+ * allowing changes to debug builds to accidentally to break release builds. */
+# define _BLI_ASSERT_ABORT ((void (*)(void))(*(((void **)abort))))
+# else
+# define _BLI_ASSERT_ABORT abort
+# endif
# else
# define _BLI_ASSERT_ABORT() (void)0
# endif
diff --git a/source/blender/blenlib/BLI_bitmap.h b/source/blender/blenlib/BLI_bitmap.h
index d67fbabd11c..2b811e50efb 100644
--- a/source/blender/blenlib/BLI_bitmap.h
+++ b/source/blender/blenlib/BLI_bitmap.h
@@ -24,12 +24,12 @@
* \ingroup bli
*/
+#include "BLI_utildefines.h"
+
#ifdef __cplusplus
extern "C" {
#endif
-#include "BLI_utildefines.h"
-
typedef unsigned int BLI_bitmap;
/* warning: the bitmap does not keep track of its own size or check
diff --git a/source/blender/blenlib/BLI_blenlib.h b/source/blender/blenlib/BLI_blenlib.h
index 41603bb4f06..6dd1abacf78 100644
--- a/source/blender/blenlib/BLI_blenlib.h
+++ b/source/blender/blenlib/BLI_blenlib.h
@@ -52,10 +52,6 @@
#include <stdlib.h>
-#ifdef __cplusplus
-extern "C" {
-#endif
-
#include "BLI_listbase.h"
#include "BLI_string.h"
@@ -68,8 +64,4 @@ extern "C" {
#include "BLI_rect.h"
-#ifdef __cplusplus
-}
-#endif
-
#endif
diff --git a/source/blender/blenlib/BLI_color.hh b/source/blender/blenlib/BLI_color.hh
new file mode 100644
index 00000000000..ff28ae2c076
--- /dev/null
+++ b/source/blender/blenlib/BLI_color.hh
@@ -0,0 +1,92 @@
+/*
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+
+#ifndef __BLI_COLOR_HH__
+#define __BLI_COLOR_HH__
+
+#include <iostream>
+
+#include "BLI_math_color.h"
+
+namespace BLI {
+
+struct Color4f {
+ float r, g, b, a;
+
+ Color4f() = default;
+
+ Color4f(float r, float g, float b, float a) : r(r), g(g), b(b), a(a)
+ {
+ }
+
+ operator float *()
+ {
+ return &r;
+ }
+
+ operator const float *() const
+ {
+ return &r;
+ }
+
+ friend std::ostream &operator<<(std::ostream &stream, Color4f c)
+ {
+ stream << "(" << c.r << ", " << c.g << ", " << c.b << ", " << c.a << ")";
+ return stream;
+ }
+};
+
+struct Color4b {
+ uint8_t r, g, b, a;
+
+ Color4b() = default;
+
+ Color4b(uint8_t r, uint8_t g, uint8_t b, uint8_t a) : r(r), g(g), b(b), a(a)
+ {
+ }
+
+ Color4b(Color4f other)
+ {
+ rgba_float_to_uchar(*this, other);
+ }
+
+ operator Color4f() const
+ {
+ Color4f result;
+ rgba_uchar_to_float(result, *this);
+ return result;
+ }
+
+ operator uint8_t *()
+ {
+ return &r;
+ }
+
+ operator const uint8_t *() const
+ {
+ return &r;
+ }
+
+ friend std::ostream &operator<<(std::ostream &stream, Color4b c)
+ {
+ stream << "(" << c.r << ", " << c.g << ", " << c.b << ", " << c.a << ")";
+ return stream;
+ }
+};
+
+} // namespace BLI
+
+#endif /* __BLI_COLOR_HH__ */
diff --git a/source/blender/blenlib/BLI_compiler_typecheck.h b/source/blender/blenlib/BLI_compiler_typecheck.h
index 958ffeb0748..0a2eddc4ecc 100644
--- a/source/blender/blenlib/BLI_compiler_typecheck.h
+++ b/source/blender/blenlib/BLI_compiler_typecheck.h
@@ -24,6 +24,8 @@
* These depend on compiler extensions and c11 in some cases.
*/
+#include "BLI_utildefines_variadic.h"
+
/* Causes warning:
* incompatible types when assigning to type 'Foo' from type 'Bar'
* ... the compiler optimizes away the temp var */
diff --git a/source/blender/blenlib/BLI_dot_export.hh b/source/blender/blenlib/BLI_dot_export.hh
new file mode 100644
index 00000000000..08c37fec01e
--- /dev/null
+++ b/source/blender/blenlib/BLI_dot_export.hh
@@ -0,0 +1,290 @@
+/*
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+
+#ifndef __BLI_DOT_EXPORT_HH__
+#define __BLI_DOT_EXPORT_HH__
+
+/**
+ * Language grammar: https://www.graphviz.org/doc/info/lang.html
+ * Attributes: https://www.graphviz.org/doc/info/attrs.html
+ * Node Shapes: https://www.graphviz.org/doc/info/shapes.html
+ * Preview: https://dreampuf.github.io/GraphvizOnline
+ */
+
+#include "BLI_map.hh"
+#include "BLI_optional.hh"
+#include "BLI_set.hh"
+#include "BLI_string_map.hh"
+#include "BLI_utility_mixins.hh"
+#include "BLI_vector.hh"
+
+#include "BLI_dot_export_attribute_enums.hh"
+
+#include <sstream>
+
+namespace BLI {
+namespace DotExport {
+
+class Graph;
+class DirectedGraph;
+class UndirectedGraph;
+class Node;
+class NodePort;
+class DirectedEdge;
+class UndirectedEdge;
+class Cluster;
+class AttributeList;
+
+class AttributeList {
+ private:
+ Map<std::string, std::string> m_attributes;
+
+ public:
+ void export__as_bracket_list(std::stringstream &ss) const;
+
+ void set(StringRef key, StringRef value)
+ {
+ m_attributes.add_override(key, value);
+ }
+};
+
+class Graph {
+ private:
+ AttributeList m_attributes;
+ Vector<std::unique_ptr<Node>> m_nodes;
+ Vector<std::unique_ptr<Cluster>> m_clusters;
+
+ Set<Node *> m_top_level_nodes;
+ Set<Cluster *> m_top_level_clusters;
+
+ friend Cluster;
+ friend Node;
+
+ public:
+ Node &new_node(StringRef label);
+ Cluster &new_cluster(StringRef label = "");
+
+ void export__declare_nodes_and_clusters(std::stringstream &ss) const;
+
+ void set_attribute(StringRef key, StringRef value)
+ {
+ m_attributes.set(key, value);
+ }
+
+ void set_rankdir(Attr_rankdir rankdir)
+ {
+ this->set_attribute("rankdir", rankdir_to_string(rankdir));
+ }
+
+ void set_random_cluster_bgcolors();
+};
+
+class Cluster {
+ private:
+ AttributeList m_attributes;
+ Graph &m_graph;
+ Cluster *m_parent = nullptr;
+ Set<Cluster *> m_children;
+ Set<Node *> m_nodes;
+
+ friend Graph;
+ friend Node;
+
+ Cluster(Graph &graph) : m_graph(graph)
+ {
+ }
+
+ public:
+ void export__declare_nodes_and_clusters(std::stringstream &ss) const;
+
+ void set_attribute(StringRef key, StringRef value)
+ {
+ m_attributes.set(key, value);
+ }
+
+ void set_parent_cluster(Cluster *cluster);
+ void set_parent_cluster(Cluster &cluster)
+ {
+ this->set_parent_cluster(&cluster);
+ }
+
+ void set_random_cluster_bgcolors();
+};
+
+class Node {
+ private:
+ AttributeList m_attributes;
+ Graph &m_graph;
+ Cluster *m_cluster = nullptr;
+
+ friend Graph;
+
+ Node(Graph &graph) : m_graph(graph)
+ {
+ }
+
+ public:
+ const AttributeList &attributes() const
+ {
+ return m_attributes;
+ }
+
+ AttributeList &attributes()
+ {
+ return m_attributes;
+ }
+
+ void set_parent_cluster(Cluster *cluster);
+ void set_parent_cluster(Cluster &cluster)
+ {
+ this->set_parent_cluster(&cluster);
+ }
+
+ void set_attribute(StringRef key, StringRef value)
+ {
+ m_attributes.set(key, value);
+ }
+
+ void set_shape(Attr_shape shape)
+ {
+ this->set_attribute("shape", shape_to_string(shape));
+ }
+
+ /* See https://www.graphviz.org/doc/info/attrs.html#k:color. */
+ void set_background_color(StringRef name)
+ {
+ this->set_attribute("fillcolor", name);
+ this->set_attribute("style", "filled");
+ }
+
+ void export__as_id(std::stringstream &ss) const;
+
+ void export__as_declaration(std::stringstream &ss) const;
+};
+
+class UndirectedGraph final : public Graph {
+ private:
+ Vector<std::unique_ptr<UndirectedEdge>> m_edges;
+
+ public:
+ std::string to_dot_string() const;
+
+ UndirectedEdge &new_edge(NodePort a, NodePort b);
+};
+
+class DirectedGraph final : public Graph {
+ private:
+ Vector<std::unique_ptr<DirectedEdge>> m_edges;
+
+ public:
+ std::string to_dot_string() const;
+
+ DirectedEdge &new_edge(NodePort from, NodePort to);
+};
+
+class NodePort {
+ private:
+ Node *m_node;
+ Optional<std::string> m_port_name;
+
+ public:
+ NodePort(Node &node, Optional<std::string> port_name = {})
+ : m_node(&node), m_port_name(std::move(port_name))
+ {
+ }
+
+ void to_dot_string(std::stringstream &ss) const;
+};
+
+class Edge : BLI::NonCopyable, BLI::NonMovable {
+ protected:
+ AttributeList m_attributes;
+ NodePort m_a;
+ NodePort m_b;
+
+ public:
+ Edge(NodePort a, NodePort b) : m_a(std::move(a)), m_b(std::move(b))
+ {
+ }
+
+ void set_attribute(StringRef key, StringRef value)
+ {
+ m_attributes.set(key, value);
+ }
+
+ void set_arrowhead(Attr_arrowType type)
+ {
+ this->set_attribute("arrowhead", arrowType_to_string(type));
+ }
+
+ void set_arrowtail(Attr_arrowType type)
+ {
+ this->set_attribute("arrowtail", arrowType_to_string(type));
+ }
+
+ void set_dir(Attr_dirType type)
+ {
+ this->set_attribute("dir", dirType_to_string(type));
+ }
+};
+
+class DirectedEdge : public Edge {
+ public:
+ DirectedEdge(NodePort from, NodePort to) : Edge(std::move(from), std::move(to))
+ {
+ }
+
+ void export__as_edge_statement(std::stringstream &ss) const;
+};
+
+class UndirectedEdge : public Edge {
+ public:
+ UndirectedEdge(NodePort a, NodePort b) : Edge(std::move(a), std::move(b))
+ {
+ }
+
+ void export__as_edge_statement(std::stringstream &ss) const;
+};
+
+std::string color_attr_from_hsv(float h, float s, float v);
+
+class NodeWithSocketsRef {
+ private:
+ Node *m_node;
+
+ public:
+ NodeWithSocketsRef(Node &node,
+ StringRef name,
+ ArrayRef<std::string> input_names,
+ ArrayRef<std::string> output_names);
+
+ NodePort input(uint index) const
+ {
+ std::string port = "\"in" + std::to_string(index) + "\"";
+ return NodePort(*m_node, port);
+ }
+
+ NodePort output(uint index) const
+ {
+ std::string port = "\"out" + std::to_string(index) + "\"";
+ return NodePort(*m_node, port);
+ }
+};
+
+} // namespace DotExport
+} // namespace BLI
+
+#endif /* __BLI_DOT_EXPORT_HH__ */
diff --git a/source/blender/blenlib/BLI_dot_export_attribute_enums.hh b/source/blender/blenlib/BLI_dot_export_attribute_enums.hh
new file mode 100644
index 00000000000..8e61f46dc12
--- /dev/null
+++ b/source/blender/blenlib/BLI_dot_export_attribute_enums.hh
@@ -0,0 +1,125 @@
+/*
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+
+#ifndef __BLI_DOT_EXPORT_ATTRIBUTE_ENUMS_HH__
+#define __BLI_DOT_EXPORT_ATTRIBUTE_ENUMS_HH__
+
+#include "BLI_string_ref.hh"
+
+namespace BLI {
+namespace DotExport {
+
+enum class Attr_rankdir {
+ LeftToRight,
+ TopToBottom,
+};
+
+inline StringRef rankdir_to_string(Attr_rankdir value)
+{
+ switch (value) {
+ case Attr_rankdir::LeftToRight:
+ return "LR";
+ case Attr_rankdir::TopToBottom:
+ return "TB";
+ }
+ return "";
+}
+
+enum class Attr_shape {
+ Rectangle,
+ Ellipse,
+ Circle,
+ Point,
+ Diamond,
+ Square,
+};
+
+inline StringRef shape_to_string(Attr_shape value)
+{
+ switch (value) {
+ case Attr_shape::Rectangle:
+ return "rectangle";
+ case Attr_shape::Ellipse:
+ return "ellipse";
+ case Attr_shape::Circle:
+ return "circle";
+ case Attr_shape::Point:
+ return "point";
+ case Attr_shape::Diamond:
+ return "diamond";
+ case Attr_shape::Square:
+ return "square";
+ }
+ return "";
+}
+
+enum class Attr_arrowType {
+ Normal,
+ Inv,
+ Dot,
+ None,
+ Empty,
+ Box,
+ Vee,
+};
+
+inline StringRef arrowType_to_string(Attr_arrowType value)
+{
+ switch (value) {
+ case Attr_arrowType::Normal:
+ return "normal";
+ case Attr_arrowType::Inv:
+ return "inv";
+ case Attr_arrowType::Dot:
+ return "dot";
+ case Attr_arrowType::None:
+ return "none";
+ case Attr_arrowType::Empty:
+ return "empty";
+ case Attr_arrowType::Box:
+ return "box";
+ case Attr_arrowType::Vee:
+ return "vee";
+ }
+ return "";
+}
+
+enum class Attr_dirType {
+ Forward,
+ Back,
+ Both,
+ None,
+};
+
+inline StringRef dirType_to_string(Attr_dirType value)
+{
+ switch (value) {
+ case Attr_dirType::Forward:
+ return "forward";
+ case Attr_dirType::Back:
+ return "back";
+ case Attr_dirType::Both:
+ return "both";
+ case Attr_dirType::None:
+ return "none";
+ }
+ return "";
+}
+
+} // namespace DotExport
+} // namespace BLI
+
+#endif /* __BLI_DOT_EXPORT_ATTRIBUTE_ENUMS_HH__ */
diff --git a/source/blender/blenlib/BLI_fileops.h b/source/blender/blenlib/BLI_fileops.h
index 4eb6f184a76..fe4600b9121 100644
--- a/source/blender/blenlib/BLI_fileops.h
+++ b/source/blender/blenlib/BLI_fileops.h
@@ -29,10 +29,6 @@
#include <stdio.h>
#include <sys/stat.h>
-#ifdef __cplusplus
-extern "C" {
-#endif
-
/* for size_t (needed on windows) */
#include <stddef.h>
@@ -41,6 +37,10 @@ extern "C" {
#include "BLI_compiler_attrs.h"
#include "BLI_utildefines.h"
+#ifdef __cplusplus
+extern "C" {
+#endif
+
#ifndef PATH_MAX
# define PATH_MAX 4096
#endif
diff --git a/source/blender/blenlib/BLI_float2.hh b/source/blender/blenlib/BLI_float2.hh
new file mode 100644
index 00000000000..da12dd7d206
--- /dev/null
+++ b/source/blender/blenlib/BLI_float2.hh
@@ -0,0 +1,86 @@
+/*
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+
+#ifndef __BLI_FLOAT2_HH__
+#define __BLI_FLOAT2_HH__
+
+#include "BLI_float3.hh"
+
+namespace BLI {
+
+struct float2 {
+ float x, y;
+
+ float2() = default;
+
+ float2(const float *ptr) : x{ptr[0]}, y{ptr[1]}
+ {
+ }
+
+ float2(float x, float y) : x(x), y(y)
+ {
+ }
+
+ float2(const float3 &other) : x(other.x), y(other.y)
+ {
+ }
+
+ operator float *()
+ {
+ return &x;
+ }
+
+ operator const float *() const
+ {
+ return &x;
+ }
+
+ friend float2 operator+(const float2 &a, const float2 &b)
+ {
+ return {a.x + b.x, a.y + b.y};
+ }
+
+ friend float2 operator-(const float2 &a, const float2 &b)
+ {
+ return {a.x - b.x, a.y - b.y};
+ }
+
+ friend float2 operator*(const float2 &a, float b)
+ {
+ return {a.x * b, a.y * b};
+ }
+
+ friend float2 operator/(const float2 &a, float b)
+ {
+ BLI_assert(b != 0.0f);
+ return {a.x / b, a.y / b};
+ }
+
+ friend float2 operator*(float a, const float2 &b)
+ {
+ return b * a;
+ }
+
+ friend std::ostream &operator<<(std::ostream &stream, const float2 &v)
+ {
+ stream << "(" << v.x << ", " << v.y << ")";
+ return stream;
+ }
+};
+
+} // namespace BLI
+
+#endif /* __BLI_FLOAT2_HH__ */
diff --git a/source/blender/blenlib/BLI_float3.hh b/source/blender/blenlib/BLI_float3.hh
new file mode 100644
index 00000000000..9678fa4b2d3
--- /dev/null
+++ b/source/blender/blenlib/BLI_float3.hh
@@ -0,0 +1,218 @@
+/*
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+
+#ifndef __BLI_FLOAT3_HH__
+#define __BLI_FLOAT3_HH__
+
+#include <iostream>
+
+#include "BLI_math_vector.h"
+
+namespace BLI {
+
+struct float3 {
+ float x, y, z;
+
+ float3() = default;
+
+ float3(const float *ptr) : x{ptr[0]}, y{ptr[1]}, z{ptr[2]}
+ {
+ }
+
+ float3(const float (*ptr)[3]) : float3((const float *)ptr)
+ {
+ }
+
+ explicit float3(float value) : x(value), y(value), z(value)
+ {
+ }
+
+ explicit float3(int value) : x(value), y(value), z(value)
+ {
+ }
+
+ float3(float x, float y, float z) : x{x}, y{y}, z{z}
+ {
+ }
+
+ operator const float *() const
+ {
+ return &x;
+ }
+
+ operator float *()
+ {
+ return &x;
+ }
+
+ float normalize_and_get_length()
+ {
+ return normalize_v3(*this);
+ }
+
+ float3 normalized() const
+ {
+ float3 result;
+ normalize_v3_v3(result, *this);
+ return result;
+ }
+
+ float length() const
+ {
+ return len_v3(*this);
+ }
+
+ float length_squared() const
+ {
+ return len_squared_v3(*this);
+ }
+
+ void reflect(const float3 &normal)
+ {
+ *this = this->reflected(normal);
+ }
+
+ float3 reflected(const float3 &normal) const
+ {
+ float3 result;
+ reflect_v3_v3v3(result, *this, normal);
+ return result;
+ }
+
+ static float3 safe_divide(const float3 &a, const float3 &b)
+ {
+ float3 result;
+ result.x = (b.x == 0.0f) ? 0.0f : a.x / b.x;
+ result.y = (b.y == 0.0f) ? 0.0f : a.y / b.y;
+ result.z = (b.z == 0.0f) ? 0.0f : a.z / b.z;
+ return result;
+ }
+
+ void invert()
+ {
+ x = -x;
+ y = -y;
+ z = -z;
+ }
+
+ friend float3 operator+(const float3 &a, const float3 &b)
+ {
+ return {a.x + b.x, a.y + b.y, a.z + b.z};
+ }
+
+ void operator+=(const float3 &b)
+ {
+ this->x += b.x;
+ this->y += b.y;
+ this->z += b.z;
+ }
+
+ friend float3 operator-(const float3 &a, const float3 &b)
+ {
+ return {a.x - b.x, a.y - b.y, a.z - b.z};
+ }
+
+ friend float3 operator-(const float3 &a)
+ {
+ return {-a.x, -a.y, -a.z};
+ }
+
+ void operator-=(const float3 &b)
+ {
+ this->x -= b.x;
+ this->y -= b.y;
+ this->z -= b.z;
+ }
+
+ void operator*=(float scalar)
+ {
+ this->x *= scalar;
+ this->y *= scalar;
+ this->z *= scalar;
+ }
+
+ void operator*=(const float3 &other)
+ {
+ this->x *= other.x;
+ this->y *= other.y;
+ this->z *= other.z;
+ }
+
+ friend float3 operator*(const float3 &a, const float3 &b)
+ {
+ return {a.x * b.x, a.y * b.y, a.z * b.z};
+ }
+
+ friend float3 operator*(const float3 &a, float b)
+ {
+ return {a.x * b, a.y * b, a.z * b};
+ }
+
+ friend float3 operator*(float a, const float3 &b)
+ {
+ return b * a;
+ }
+
+ friend float3 operator/(const float3 &a, float b)
+ {
+ BLI_assert(b != 0.0f);
+ return {a.x / b, a.y / b, a.z / b};
+ }
+
+ friend std::ostream &operator<<(std::ostream &stream, const float3 &v)
+ {
+ stream << "(" << v.x << ", " << v.y << ", " << v.z << ")";
+ return stream;
+ }
+
+ static float dot(const float3 &a, const float3 &b)
+ {
+ return a.x * b.x + a.y * b.y + a.z * b.z;
+ }
+
+ static float3 cross_high_precision(const float3 &a, const float3 &b)
+ {
+ float3 result;
+ cross_v3_v3v3_hi_prec(result, a, b);
+ return result;
+ }
+
+ static float3 project(const float3 &a, const float3 &b)
+ {
+ float3 result;
+ project_v3_v3v3(result, a, b);
+ return result;
+ }
+
+ static float distance(const float3 &a, const float3 &b)
+ {
+ return (a - b).length();
+ }
+
+ static float distance_squared(const float3 &a, const float3 &b)
+ {
+ return float3::dot(a, b);
+ }
+
+ static float3 interpolate(const float3 &a, const float3 &b, float t)
+ {
+ return a * (1 - t) + b * t;
+ }
+};
+
+} // namespace BLI
+
+#endif /* __BLI_FLOAT3_HH__ */
diff --git a/source/blender/blenlib/BLI_float4x4.hh b/source/blender/blenlib/BLI_float4x4.hh
new file mode 100644
index 00000000000..36186d319c9
--- /dev/null
+++ b/source/blender/blenlib/BLI_float4x4.hh
@@ -0,0 +1,115 @@
+/*
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+
+#ifndef __BLI_FLOAT4X4_HH__
+#define __BLI_FLOAT4X4_HH__
+
+#include "BLI_float3.hh"
+#include "BLI_math_matrix.h"
+
+namespace BLI {
+
+struct float4x4 {
+ float values[4][4];
+
+ float4x4() = default;
+
+ float4x4(const float *matrix)
+ {
+ memcpy(values, matrix, sizeof(float) * 16);
+ }
+
+ float4x4(const float matrix[4][4]) : float4x4((float *)matrix)
+ {
+ }
+
+ operator float *()
+ {
+ return (float *)this;
+ }
+
+ operator const float *() const
+ {
+ return (const float *)this;
+ }
+
+ float4x4 inverted() const
+ {
+ float result[4][4];
+ invert_m4_m4(result, values);
+ return result;
+ }
+
+ /**
+ * Matrix inversion can be implemented more efficiently for affine matrices.
+ */
+ float4x4 inverted_affine() const
+ {
+ BLI_assert(values[0][3] == 0.0f && values[1][3] == 0.0f && values[2][3] == 0.0f &&
+ values[3][3] == 1.0f);
+ return this->inverted();
+ }
+
+ friend float4x4 operator*(const float4x4 &a, const float4x4 &b)
+ {
+ float4x4 result;
+ mul_m4_m4m4(result.values, a.values, b.values);
+ return result;
+ }
+
+ /**
+ * This also applies the translation on the vector. Use `m.ref_3x3() * v` if that is not
+ * intended.
+ */
+ friend float3 operator*(const float4x4 &m, const float3 &v)
+ {
+ float3 result;
+ mul_v3_m4v3(result, m.values, v);
+ return result;
+ }
+
+ friend float3 operator*(const float4x4 &m, const float (*v)[3])
+ {
+ return m * float3(v);
+ }
+
+ struct float3x3_ref {
+ const float4x4 &data;
+
+ friend float3 operator*(const float3x3_ref &m, const float3 &v)
+ {
+ float3 result;
+ mul_v3_mat3_m4v3(result, m.data.values, v);
+ return result;
+ }
+ };
+
+ float3x3_ref ref_3x3() const
+ {
+ return {*this};
+ }
+
+ static float4x4 interpolate(const float4x4 &a, const float4x4 &b, float t)
+ {
+ float result[4][4];
+ interp_m4_m4m4(result, a.values, b.values, t);
+ return result;
+ }
+};
+
+} // namespace BLI
+
+#endif /* __BLI_FLOAT4X4_HH__ */
diff --git a/source/blender/blenlib/BLI_gsqueue.h b/source/blender/blenlib/BLI_gsqueue.h
index dffb2a165ee..b69bdb7057c 100644
--- a/source/blender/blenlib/BLI_gsqueue.h
+++ b/source/blender/blenlib/BLI_gsqueue.h
@@ -24,6 +24,8 @@
* \ingroup bli
*/
+#include "BLI_utildefines.h"
+
#ifdef __cplusplus
extern "C" {
#endif
diff --git a/source/blender/blenlib/BLI_hash.h b/source/blender/blenlib/BLI_hash.h
index d09291b64be..96111ffaf5a 100644
--- a/source/blender/blenlib/BLI_hash.h
+++ b/source/blender/blenlib/BLI_hash.h
@@ -21,12 +21,12 @@
* \ingroup bli
*/
+#include "BLI_utildefines.h"
+
#ifdef __cplusplus
extern "C" {
#endif
-#include "BLI_utildefines.h"
-
BLI_INLINE unsigned int BLI_hash_int_2d(unsigned int kx, unsigned int ky)
{
#define rot(x, k) (((x) << (k)) | ((x) >> (32 - (k))))
@@ -81,7 +81,7 @@ BLI_INLINE void BLI_hash_pointer_to_color(const void *ptr, int *r, int *g, int *
{
size_t val = (size_t)ptr;
const size_t hash_a = BLI_hash_int(val & 0x0000ffff);
- const size_t hash_b = BLI_hash_int((uint)((val & 0xffff0000) >> 32));
+ const size_t hash_b = BLI_hash_int((uint)((val & 0xffff0000) >> 16));
const size_t hash = hash_a ^ (hash_b + 0x9e3779b9 + (hash_a << 6) + (hash_a >> 2));
*r = (hash & 0xff0000) >> 16;
*g = (hash & 0x00ff00) >> 8;
diff --git a/source/blender/blenlib/BLI_hash_cxx.h b/source/blender/blenlib/BLI_hash.hh
index 22941a792ba..3b3448f66b1 100644
--- a/source/blender/blenlib/BLI_hash_cxx.h
+++ b/source/blender/blenlib/BLI_hash.hh
@@ -14,8 +14,8 @@
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
-#ifndef __BLI_HASH_CXX_H__
-#define __BLI_HASH_CXX_H__
+#ifndef __BLI_HASH_HH__
+#define __BLI_HASH_HH__
/** \file
* \ingroup bli
@@ -30,6 +30,7 @@
#include <utility>
#include "BLI_math_base.h"
+#include "BLI_string_ref.hh"
#include "BLI_utildefines.h"
namespace BLI {
@@ -67,14 +68,33 @@ template<> struct DefaultHash<float> {
}
};
+inline uint32_t hash_string(StringRef str)
+{
+ uint32_t hash = 5381;
+ for (char c : str) {
+ hash = hash * 33 + c;
+ }
+ return hash;
+}
+
template<> struct DefaultHash<std::string> {
uint32_t operator()(const std::string &value) const
{
- uint32_t hash = 5381;
- for (char c : value) {
- hash = hash * 33 + c;
- }
- return hash;
+ return hash_string(value);
+ }
+};
+
+template<> struct DefaultHash<StringRef> {
+ uint32_t operator()(const StringRef &value) const
+ {
+ return hash_string(value);
+ }
+};
+
+template<> struct DefaultHash<StringRefNull> {
+ uint32_t operator()(const StringRefNull &value) const
+ {
+ return hash_string(value);
}
};
@@ -109,4 +129,4 @@ template<typename T1, typename T2> struct DefaultHash<std::pair<T1, T2>> {
} // namespace BLI
-#endif /* __BLI_HASH_CXX_H__ */
+#endif /* __BLI_HASH_HH__ */
diff --git a/source/blender/blenlib/BLI_heap.h b/source/blender/blenlib/BLI_heap.h
index fa8e49ef376..ca5edcbead5 100644
--- a/source/blender/blenlib/BLI_heap.h
+++ b/source/blender/blenlib/BLI_heap.h
@@ -22,12 +22,12 @@
* \brief A min-heap / priority queue ADT
*/
+#include "BLI_math.h"
+
#ifdef __cplusplus
extern "C" {
#endif
-#include "BLI_math.h"
-
struct Heap;
struct HeapNode;
typedef struct Heap Heap;
diff --git a/source/blender/blenlib/BLI_index_range.h b/source/blender/blenlib/BLI_index_range.hh
index 4553c996454..e24fd567810 100644
--- a/source/blender/blenlib/BLI_index_range.h
+++ b/source/blender/blenlib/BLI_index_range.hh
@@ -14,8 +14,8 @@
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
-#ifndef __BLI_INDEX_RANGE_H__
-#define __BLI_INDEX_RANGE_H__
+#ifndef __BLI_INDEX_RANGE_HH__
+#define __BLI_INDEX_RANGE_HH__
/** \file
* \ingroup bli
@@ -208,4 +208,4 @@ class IndexRange {
} // namespace BLI
-#endif /* __BLI_INDEX_RANGE_H__ */
+#endif /* __BLI_INDEX_RANGE_HH__ */
diff --git a/source/blender/blenlib/BLI_lasso_2d.h b/source/blender/blenlib/BLI_lasso_2d.h
index 56db360dab0..fb661c41784 100644
--- a/source/blender/blenlib/BLI_lasso_2d.h
+++ b/source/blender/blenlib/BLI_lasso_2d.h
@@ -30,14 +30,14 @@ extern "C" {
struct rcti;
-void BLI_lasso_boundbox(struct rcti *rect, const int mcords[][2], const unsigned int moves);
-bool BLI_lasso_is_point_inside(const int mcords[][2],
- const unsigned int moves,
+void BLI_lasso_boundbox(struct rcti *rect, const int mcoords[][2], const unsigned int mcoords_len);
+bool BLI_lasso_is_point_inside(const int mcoords[][2],
+ const unsigned int mcoords_len,
const int sx,
const int sy,
const int error_value);
-bool BLI_lasso_is_edge_inside(const int mcords[][2],
- const unsigned int moves,
+bool BLI_lasso_is_edge_inside(const int mcoords[][2],
+ const unsigned int mcoords_len,
int x0,
int y0,
int x1,
diff --git a/source/blender/blenlib/BLI_linear_allocator.hh b/source/blender/blenlib/BLI_linear_allocator.hh
new file mode 100644
index 00000000000..285af49f500
--- /dev/null
+++ b/source/blender/blenlib/BLI_linear_allocator.hh
@@ -0,0 +1,220 @@
+/*
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+
+/** \file
+ * \ingroup bli
+ *
+ * A linear allocator is the simplest form of an allocator. It never reuses any memory, and
+ * therefore does not need a deallocation method. It simply hands out consecutive buffers of
+ * memory. When the current buffer is full, it reallocates a new larger buffer and continues.
+ */
+
+#ifndef __BLI_LINEAR_ALLOCATOR_HH__
+#define __BLI_LINEAR_ALLOCATOR_HH__
+
+#include "BLI_string_ref.hh"
+#include "BLI_utility_mixins.hh"
+#include "BLI_vector.hh"
+
+namespace BLI {
+
+template<typename Allocator = GuardedAllocator> class LinearAllocator : NonCopyable, NonMovable {
+ private:
+ Allocator m_allocator;
+ Vector<void *> m_owned_buffers;
+ Vector<ArrayRef<char>> m_unused_borrowed_buffers;
+
+ uintptr_t m_current_begin;
+ uintptr_t m_current_end;
+ uint m_next_min_alloc_size;
+
+#ifdef DEBUG
+ uint m_debug_allocated_amount = 0;
+#endif
+
+ public:
+ LinearAllocator()
+ {
+ m_current_begin = 0;
+ m_current_end = 0;
+ m_next_min_alloc_size = 64;
+ }
+
+ ~LinearAllocator()
+ {
+ for (void *ptr : m_owned_buffers) {
+ m_allocator.deallocate(ptr);
+ }
+ }
+
+ /**
+ * Get a pointer to a memory buffer with the given size an alignment. The memory buffer will be
+ * freed when this LinearAllocator is destructed.
+ *
+ * The alignment has to be a power of 2.
+ */
+ void *allocate(uint size, uint alignment)
+ {
+ BLI_assert(alignment >= 1);
+ BLI_assert(is_power_of_2_i(alignment));
+
+#ifdef DEBUG
+ m_debug_allocated_amount += size;
+#endif
+
+ uintptr_t alignment_mask = alignment - 1;
+ uintptr_t potential_allocation_begin = (m_current_begin + alignment_mask) & ~alignment_mask;
+ uintptr_t potential_allocation_end = potential_allocation_begin + size;
+
+ if (potential_allocation_end <= m_current_end) {
+ m_current_begin = potential_allocation_end;
+ return (void *)potential_allocation_begin;
+ }
+ else {
+ this->allocate_new_buffer(size + alignment);
+ return this->allocate(size, alignment);
+ }
+ };
+
+ /**
+ * Allocate a memory buffer that can hold an instance of T.
+ *
+ * This method only allocates memory and does not construct the instance.
+ */
+ template<typename T> T *allocate()
+ {
+ return (T *)this->allocate(sizeof(T), alignof(T));
+ }
+
+ /**
+ * Allocate a memory buffer that can hold T array with the given size.
+ *
+ * This method only allocates memory and does not construct the instance.
+ */
+ template<typename T> MutableArrayRef<T> allocate_array(uint size)
+ {
+ return MutableArrayRef<T>((T *)this->allocate(sizeof(T) * size, alignof(T)), size);
+ }
+
+ /**
+ * Construct an instance of T in memory provided by this allocator.
+ *
+ * Arguments passed to this method will be forwarded to the constructor of T.
+ *
+ * You must not call `delete` on the returned pointer.
+ * Instead, the destruct has to be called explicitly.
+ */
+ template<typename T, typename... Args> T *construct(Args &&... args)
+ {
+ void *buffer = this->allocate(sizeof(T), alignof(T));
+ T *value = new (buffer) T(std::forward<Args>(args)...);
+ return value;
+ }
+
+ /**
+ * Copy the given array into a memory buffer provided by this allocator.
+ */
+ template<typename T> MutableArrayRef<T> construct_array_copy(ArrayRef<T> src)
+ {
+ MutableArrayRef<T> dst = this->allocate_array<T>(src.size());
+ uninitialized_copy_n(src.begin(), src.size(), dst.begin());
+ return dst;
+ }
+
+ /**
+ * Copy the given string into a memory buffer provided by this allocator. The returned string is
+ * always null terminated.
+ */
+ StringRefNull copy_string(StringRef str)
+ {
+ uint alloc_size = str.size() + 1;
+ char *buffer = (char *)this->allocate(alloc_size, 1);
+ str.copy(buffer, alloc_size);
+ return StringRefNull((const char *)buffer);
+ }
+
+ MutableArrayRef<void *> allocate_elements_and_pointer_array(uint element_amount,
+ uint element_size,
+ uint element_alignment)
+ {
+ void *pointer_buffer = this->allocate(element_amount * sizeof(void *), alignof(void *));
+ void *elements_buffer = this->allocate(element_amount * element_size, element_alignment);
+
+ MutableArrayRef<void *> pointers((void **)pointer_buffer, element_amount);
+ void *next_element_buffer = elements_buffer;
+ for (uint i : IndexRange(element_amount)) {
+ pointers[i] = next_element_buffer;
+ next_element_buffer = POINTER_OFFSET(next_element_buffer, element_size);
+ }
+
+ return pointers;
+ }
+
+ template<typename T, typename... Args>
+ ArrayRef<T *> construct_elements_and_pointer_array(uint n, Args &&... args)
+ {
+ MutableArrayRef<void *> void_pointers = this->allocate_elements_and_pointer_array(
+ n, sizeof(T), alignof(T));
+ MutableArrayRef<T *> pointers = void_pointers.cast<T *>();
+
+ for (uint i : IndexRange(n)) {
+ new (pointers[i]) T(std::forward<Args>(args)...);
+ }
+
+ return pointers;
+ }
+
+ /**
+ * Tell the allocator to use up the given memory buffer, before allocating new memory from the
+ * system.
+ */
+ void provide_buffer(void *buffer, uint size)
+ {
+ m_unused_borrowed_buffers.append(ArrayRef<char>((char *)buffer, size));
+ }
+
+ template<uint Size, uint Alignment>
+ void provide_buffer(AlignedBuffer<Size, Alignment> &aligned_buffer)
+ {
+ this->provide_buffer(aligned_buffer.ptr(), Size);
+ }
+
+ private:
+ void allocate_new_buffer(uint min_allocation_size)
+ {
+ for (uint i : m_unused_borrowed_buffers.index_range()) {
+ ArrayRef<char> buffer = m_unused_borrowed_buffers[i];
+ if (buffer.size() >= min_allocation_size) {
+ m_unused_borrowed_buffers.remove_and_reorder(i);
+ m_current_begin = (uintptr_t)buffer.begin();
+ m_current_end = (uintptr_t)buffer.end();
+ return;
+ }
+ }
+
+ uint size_in_bytes = power_of_2_min_u(std::max(min_allocation_size, m_next_min_alloc_size));
+ m_next_min_alloc_size = size_in_bytes * 2;
+
+ void *buffer = m_allocator.allocate(size_in_bytes, __func__);
+ m_owned_buffers.append(buffer);
+ m_current_begin = (uintptr_t)buffer;
+ m_current_end = m_current_begin + size_in_bytes;
+ }
+};
+
+} // namespace BLI
+
+#endif /* __BLI_LINEAR_ALLOCATOR_HH__ */
diff --git a/source/blender/blenlib/BLI_link_utils.h b/source/blender/blenlib/BLI_link_utils.h
index f37841e3192..c0db53ca9a3 100644
--- a/source/blender/blenlib/BLI_link_utils.h
+++ b/source/blender/blenlib/BLI_link_utils.h
@@ -61,7 +61,7 @@
#define BLI_LINKS_FREE(list) \
{ \
while (list) { \
- void *next = list->next; \
+ void *next = (list)->next; \
MEM_freeN(list); \
list = next; \
} \
diff --git a/source/blender/blenlib/BLI_listbase_wrapper.h b/source/blender/blenlib/BLI_listbase_wrapper.hh
index d6832166e35..02313d9d22d 100644
--- a/source/blender/blenlib/BLI_listbase_wrapper.h
+++ b/source/blender/blenlib/BLI_listbase_wrapper.hh
@@ -14,8 +14,8 @@
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
-#ifndef __BLI_LISTBASE_WRAPPER_H__
-#define __BLI_LISTBASE_WRAPPER_H__
+#ifndef __BLI_LISTBASE_WRAPPER_HH__
+#define __BLI_LISTBASE_WRAPPER_HH__
/** \file
* \ingroup bli
@@ -29,17 +29,17 @@
namespace BLI {
-template<typename T> class IntrusiveListBaseWrapper {
+template<typename T> class ListBaseWrapper {
private:
ListBase *m_listbase;
public:
- IntrusiveListBaseWrapper(ListBase *listbase) : m_listbase(listbase)
+ ListBaseWrapper(ListBase *listbase) : m_listbase(listbase)
{
BLI_assert(listbase);
}
- IntrusiveListBaseWrapper(ListBase &listbase) : IntrusiveListBaseWrapper(&listbase)
+ ListBaseWrapper(ListBase &listbase) : ListBaseWrapper(&listbase)
{
}
@@ -110,4 +110,4 @@ template<typename T> class IntrusiveListBaseWrapper {
} /* namespace BLI */
-#endif /* __BLI_LISTBASE_WRAPPER_H__ */
+#endif /* __BLI_LISTBASE_WRAPPER_HH__ */
diff --git a/source/blender/blenlib/BLI_map.h b/source/blender/blenlib/BLI_map.hh
index 4b7ac0791d9..ea5e5da4099 100644
--- a/source/blender/blenlib/BLI_map.h
+++ b/source/blender/blenlib/BLI_map.hh
@@ -14,8 +14,8 @@
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
-#ifndef __BLI_MAP_H__
-#define __BLI_MAP_H__
+#ifndef __BLI_MAP_HH__
+#define __BLI_MAP_HH__
/** \file
* \ingroup bli
@@ -26,9 +26,9 @@
* lookups. Keys and values are stored in groups of four to avoid wasting memory due to padding.
*/
-#include "BLI_array_ref.h"
-#include "BLI_hash_cxx.h"
-#include "BLI_open_addressing.h"
+#include "BLI_array_ref.hh"
+#include "BLI_hash.hh"
+#include "BLI_open_addressing.hh"
namespace BLI {
@@ -53,7 +53,11 @@ namespace BLI {
// clang-format on
-template<typename KeyT, typename ValueT, typename Allocator = GuardedAllocator> class Map {
+template<typename KeyT,
+ typename ValueT,
+ uint32_t InlineBufferCapacity = 4,
+ typename Allocator = GuardedAllocator>
+class Map {
private:
static constexpr uint OFFSET_MASK = 3;
static constexpr uint OFFSET_SHIFT = 2;
@@ -65,8 +69,8 @@ template<typename KeyT, typename ValueT, typename Allocator = GuardedAllocator>
static constexpr uint8_t IS_DUMMY = 2;
uint8_t m_status[4];
- char m_keys[4 * sizeof(KeyT)];
- char m_values[4 * sizeof(ValueT)];
+ AlignedBuffer<4 * sizeof(KeyT), alignof(KeyT)> m_keys_buffer;
+ AlignedBuffer<4 * sizeof(ValueT), alignof(ValueT)> m_values_buffer;
public:
static constexpr uint slots_per_item = 4;
@@ -134,20 +138,18 @@ template<typename KeyT, typename ValueT, typename Allocator = GuardedAllocator>
KeyT *key(uint offset) const
{
- return (KeyT *)(m_keys + offset * sizeof(KeyT));
+ return (KeyT *)m_keys_buffer.ptr() + offset;
}
ValueT *value(uint offset) const
{
- return (ValueT *)(m_values + offset * sizeof(ValueT));
+ return (ValueT *)m_values_buffer.ptr() + offset;
}
template<typename ForwardKeyT, typename ForwardValueT>
void store(uint offset, ForwardKeyT &&key, ForwardValueT &&value)
{
- BLI_assert(m_status[offset] != IS_SET);
- m_status[offset] = IS_SET;
- new (this->key(offset)) KeyT(std::forward<ForwardKeyT>(key));
+ this->store_without_value(offset, std::forward<ForwardKeyT>(key));
new (this->value(offset)) ValueT(std::forward<ForwardValueT>(value));
}
@@ -167,7 +169,7 @@ template<typename KeyT, typename ValueT, typename Allocator = GuardedAllocator>
}
};
- using ArrayType = OpenAddressingArray<Item, 1, Allocator>;
+ using ArrayType = OpenAddressingArray<Item, InlineBufferCapacity, Allocator>;
ArrayType m_array;
public:
@@ -351,6 +353,12 @@ template<typename KeyT, typename ValueT, typename Allocator = GuardedAllocator>
ITER_SLOTS_END(offset);
}
+ ValueT *lookup_ptr(const KeyT &key)
+ {
+ const Map *const_this = this;
+ return const_cast<ValueT *>(const_this->lookup_ptr(key));
+ }
+
/**
* Lookup the value that corresponds to the key.
* Asserts when the key does not exist.
@@ -362,12 +370,6 @@ template<typename KeyT, typename ValueT, typename Allocator = GuardedAllocator>
return *ptr;
}
- ValueT *lookup_ptr(const KeyT &key)
- {
- const Map *const_this = this;
- return const_cast<ValueT *>(const_this->lookup_ptr(key));
- }
-
ValueT &lookup(const KeyT &key)
{
const Map *const_this = this;
@@ -406,6 +408,19 @@ template<typename KeyT, typename ValueT, typename Allocator = GuardedAllocator>
}
/**
+ * Return the value that corresponds to the given key.
+ * If it does not exist yet, insert a new default constructed value and return that.
+ */
+ ValueT &lookup_or_add_default(const KeyT &key)
+ {
+ return this->lookup_or_add(key, []() { return ValueT(); });
+ }
+ ValueT &lookup_or_add_default(const KeyT &&key)
+ {
+ return this->lookup_or_add(std::move(key), []() { return ValueT(); });
+ }
+
+ /**
* Get the number of elements in the map.
*/
uint32_t size() const
@@ -413,6 +428,17 @@ template<typename KeyT, typename ValueT, typename Allocator = GuardedAllocator>
return m_array.slots_set();
}
+ /**
+ * Returns true if there are no elements in the map.
+ */
+ bool is_empty() const
+ {
+ return this->size() == 0;
+ }
+
+ /**
+ * Calls the given function for each key-value-pair.
+ */
template<typename FuncT> void foreach_item(const FuncT &func) const
{
for (const Item &item : m_array) {
@@ -733,4 +759,4 @@ template<typename KeyT, typename ValueT, typename Allocator = GuardedAllocator>
} // namespace BLI
-#endif /* __BLI_MAP_H__ */
+#endif /* __BLI_MAP_HH__ */
diff --git a/source/blender/blenlib/BLI_math_base.h b/source/blender/blenlib/BLI_math_base.h
index 7a9d17d2b05..c456ab0ecef 100644
--- a/source/blender/blenlib/BLI_math_base.h
+++ b/source/blender/blenlib/BLI_math_base.h
@@ -33,6 +33,7 @@
#include "BLI_assert.h"
#include "BLI_math_inline.h"
+#include "BLI_sys_types.h"
#include <math.h>
#ifndef M_PI
@@ -92,6 +93,10 @@ static const int NAN_INT = 0x7FC00000;
# pragma GCC diagnostic ignored "-Wredundant-decls"
#endif
+#ifdef __cplusplus
+extern "C" {
+#endif
+
/******************************* Float ******************************/
MINLINE float pow2f(float x);
@@ -151,6 +156,9 @@ MINLINE int max_iiii(int a, int b, int c, int d);
MINLINE size_t min_zz(size_t a, size_t b);
MINLINE size_t max_zz(size_t a, size_t b);
+MINLINE char min_cc(char a, char b);
+MINLINE char max_cc(char a, char b);
+
MINLINE int clamp_i(int value, int min, int max);
MINLINE float clamp_f(float value, float min, float max);
MINLINE size_t clamp_z(size_t value, size_t min, size_t max);
@@ -278,4 +286,8 @@ double double_round(double x, int ndigits);
# define BLI_ASSERT_UNIT_M3(m) (void)(m)
#endif
+#ifdef __cplusplus
+}
+#endif
+
#endif /* __BLI_MATH_BASE_H__ */
diff --git a/source/blender/blenlib/BLI_math_bits.h b/source/blender/blenlib/BLI_math_bits.h
index 71e2d2d9e2c..842fce22f91 100644
--- a/source/blender/blenlib/BLI_math_bits.h
+++ b/source/blender/blenlib/BLI_math_bits.h
@@ -22,12 +22,12 @@
* \ingroup bli
*/
+#include "BLI_math_inline.h"
+
#ifdef __cplusplus
extern "C" {
#endif
-#include "BLI_math_inline.h"
-
/* Search the value from LSB to MSB for a set bit. Returns index of this bit. */
MINLINE int bitscan_forward_i(int a);
MINLINE unsigned int bitscan_forward_uint(unsigned int a);
diff --git a/source/blender/blenlib/BLI_math_color.h b/source/blender/blenlib/BLI_math_color.h
index 97d0eb1ddda..f247e09a83b 100644
--- a/source/blender/blenlib/BLI_math_color.h
+++ b/source/blender/blenlib/BLI_math_color.h
@@ -27,12 +27,12 @@
* \ingroup bli
*/
+#include "BLI_math_inline.h"
+
#ifdef __cplusplus
extern "C" {
#endif
-#include "BLI_math_inline.h"
-
/* YCbCr */
#define BLI_YCC_ITU_BT601 0
#define BLI_YCC_ITU_BT709 1
diff --git a/source/blender/blenlib/BLI_math_color_blend.h b/source/blender/blenlib/BLI_math_color_blend.h
index 47bafff3a49..60ada1e4509 100644
--- a/source/blender/blenlib/BLI_math_color_blend.h
+++ b/source/blender/blenlib/BLI_math_color_blend.h
@@ -27,12 +27,12 @@
* \ingroup bli
*/
+#include "BLI_math_inline.h"
+
#ifdef __cplusplus
extern "C" {
#endif
-#include "BLI_math_inline.h"
-
/******************** Blending Modes **********************
* - byte function assume straight alpha
* - float functions assume premultiplied alpha
diff --git a/source/blender/blenlib/BLI_math_geom.h b/source/blender/blenlib/BLI_math_geom.h
index 2049f368578..563bcad5d14 100644
--- a/source/blender/blenlib/BLI_math_geom.h
+++ b/source/blender/blenlib/BLI_math_geom.h
@@ -27,10 +27,6 @@
* \ingroup bli
*/
-#ifdef __cplusplus
-extern "C" {
-#endif
-
#include "BLI_compiler_attrs.h"
#include "BLI_math_inline.h"
@@ -39,6 +35,10 @@ extern "C" {
# pragma GCC diagnostic ignored "-Wredundant-decls"
#endif
+#ifdef __cplusplus
+extern "C" {
+#endif
+
/********************************** Polygons *********************************/
float normal_tri_v3(float r[3], const float a[3], const float b[3], const float c[3]);
diff --git a/source/blender/blenlib/BLI_math_matrix.h b/source/blender/blenlib/BLI_math_matrix.h
index 1221ecfb7b1..2d11797bc34 100644
--- a/source/blender/blenlib/BLI_math_matrix.h
+++ b/source/blender/blenlib/BLI_math_matrix.h
@@ -26,13 +26,13 @@
* \ingroup bli
*/
+#include "BLI_compiler_attrs.h"
+#include "BLI_sys_types.h"
+
#ifdef __cplusplus
extern "C" {
#endif
-#include "BLI_compiler_attrs.h"
-#include "BLI_sys_types.h"
-
/********************************* Init **************************************/
void zero_m2(float R[2][2]);
diff --git a/source/blender/blenlib/BLI_math_solvers.h b/source/blender/blenlib/BLI_math_solvers.h
index 4bd1a46bb78..193bbdd4e8c 100644
--- a/source/blender/blenlib/BLI_math_solvers.h
+++ b/source/blender/blenlib/BLI_math_solvers.h
@@ -24,13 +24,13 @@
* \ingroup bli
*/
+#include "BLI_compiler_attrs.h"
+#include "BLI_math_inline.h"
+
#ifdef __cplusplus
extern "C" {
#endif
-#include "BLI_compiler_attrs.h"
-#include "BLI_math_inline.h"
-
#ifdef BLI_MATH_GCC_WARN_PRAGMA
# pragma GCC diagnostic push
# pragma GCC diagnostic ignored "-Wredundant-decls"
diff --git a/source/blender/blenlib/BLI_math_statistics.h b/source/blender/blenlib/BLI_math_statistics.h
index b2cc6568abb..a9f9ae39506 100644
--- a/source/blender/blenlib/BLI_math_statistics.h
+++ b/source/blender/blenlib/BLI_math_statistics.h
@@ -24,13 +24,13 @@
* \ingroup bli
*/
+#include "BLI_compiler_attrs.h"
+#include "BLI_math_inline.h"
+
#ifdef __cplusplus
extern "C" {
#endif
-#include "BLI_compiler_attrs.h"
-#include "BLI_math_inline.h"
-
#ifdef BLI_MATH_GCC_WARN_PRAGMA
# pragma GCC diagnostic push
# pragma GCC diagnostic ignored "-Wredundant-decls"
diff --git a/source/blender/blenlib/BLI_math_vector.h b/source/blender/blenlib/BLI_math_vector.h
index 6cfa2d2ced6..d46c02a961c 100644
--- a/source/blender/blenlib/BLI_math_vector.h
+++ b/source/blender/blenlib/BLI_math_vector.h
@@ -27,14 +27,14 @@
* \ingroup bli
*/
-#ifdef __cplusplus
-extern "C" {
-#endif
-
#include "BLI_compiler_attrs.h"
#include "BLI_math_inline.h"
#include "BLI_utildefines.h"
+#ifdef __cplusplus
+extern "C" {
+#endif
+
/************************************* Init ***********************************/
#ifdef BLI_MATH_GCC_WARN_PRAGMA
@@ -62,6 +62,11 @@ MINLINE void swap_v4_v4(float a[4], float b[4]);
MINLINE void copy_v2_v2_uchar(unsigned char r[2], const unsigned char a[2]);
MINLINE void copy_v3_v3_uchar(unsigned char r[3], const unsigned char a[3]);
MINLINE void copy_v4_v4_uchar(unsigned char r[4], const unsigned char a[4]);
+
+MINLINE void copy_v2_uchar(unsigned char r[2], const unsigned char a);
+MINLINE void copy_v3_uchar(unsigned char r[3], const unsigned char a);
+MINLINE void copy_v4_uchar(unsigned char r[4], const unsigned char a);
+
/* char */
MINLINE void copy_v2_v2_char(char r[2], const char a[2]);
MINLINE void copy_v3_v3_char(char r[3], const char a[3]);
@@ -431,6 +436,7 @@ MINLINE void normal_short_to_float_v3(float r[3], const short n[3]);
MINLINE void normal_float_to_short_v3(short r[3], const float n[3]);
MINLINE void normal_float_to_short_v4(short r[4], const float n[4]);
+void minmax_v4v4_v4(float min[4], float max[4], const float vec[4]);
void minmax_v3v3_v3(float min[3], float max[3], const float vec[3]);
void minmax_v2v2_v2(float min[2], float max[2], const float vec[2]);
diff --git a/source/blender/blenlib/BLI_memarena.h b/source/blender/blenlib/BLI_memarena.h
index 5440bdfef60..e0aff82e874 100644
--- a/source/blender/blenlib/BLI_memarena.h
+++ b/source/blender/blenlib/BLI_memarena.h
@@ -24,12 +24,12 @@
#ifndef __BLI_MEMARENA_H__
#define __BLI_MEMARENA_H__
+#include "BLI_compiler_attrs.h"
+
#ifdef __cplusplus
extern "C" {
#endif
-#include "BLI_compiler_attrs.h"
-
/* A reasonable standard buffer size, big
* enough to not cause much internal fragmentation,
* small enough not to waste resources
diff --git a/source/blender/blenlib/BLI_memblock.h b/source/blender/blenlib/BLI_memblock.h
index 8bd8642a4e8..8f66ee3b9cb 100644
--- a/source/blender/blenlib/BLI_memblock.h
+++ b/source/blender/blenlib/BLI_memblock.h
@@ -24,12 +24,12 @@
* \ingroup bli
*/
+#include "BLI_compiler_attrs.h"
+
#ifdef __cplusplus
extern "C" {
#endif
-#include "BLI_compiler_attrs.h"
-
#define BLI_MEM_BLOCK_CHUNK_SIZE (1 << 15) /* 32KiB */
struct BLI_memblock;
diff --git a/source/blender/blenlib/BLI_memiter.h b/source/blender/blenlib/BLI_memiter.h
index fb4a79a491b..4aa9cdb6b6c 100644
--- a/source/blender/blenlib/BLI_memiter.h
+++ b/source/blender/blenlib/BLI_memiter.h
@@ -21,14 +21,14 @@
* \ingroup bli
*/
-#ifdef __cplusplus
-extern "C" {
-#endif
-
#include "BLI_compiler_attrs.h"
#include "BLI_compiler_compat.h"
#include "BLI_sys_types.h"
+#ifdef __cplusplus
+extern "C" {
+#endif
+
/* 512kb, good default for small elems. */
#define BLI_MEMITER_DEFAULT_SIZE (1 << 19)
diff --git a/source/blender/blenlib/BLI_memory_utils_cxx.h b/source/blender/blenlib/BLI_memory_utils.hh
index 6534138315d..d9acf08a43f 100644
--- a/source/blender/blenlib/BLI_memory_utils_cxx.h
+++ b/source/blender/blenlib/BLI_memory_utils.hh
@@ -14,8 +14,8 @@
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
-#ifndef __BLI_MEMORY_UTILS_CXX_H__
-#define __BLI_MEMORY_UTILS_CXX_H__
+#ifndef __BLI_MEMORY_UTILS_HH__
+#define __BLI_MEMORY_UTILS_HH__
/** \file
* \ingroup bli
@@ -120,4 +120,4 @@ template<uint Size, uint Alignment> class alignas(Alignment) AlignedBuffer {
} // namespace BLI
-#endif /* __BLI_MEMORY_UTILS_CXX_H__ */
+#endif /* __BLI_MEMORY_UTILS_HH__ */
diff --git a/source/blender/blenlib/BLI_mempool.h b/source/blender/blenlib/BLI_mempool.h
index 6491180c2fd..3749f9e1b76 100644
--- a/source/blender/blenlib/BLI_mempool.h
+++ b/source/blender/blenlib/BLI_mempool.h
@@ -24,13 +24,13 @@
* \ingroup bli
*/
+#include "BLI_compiler_attrs.h"
+#include "BLI_utildefines.h"
+
#ifdef __cplusplus
extern "C" {
#endif
-#include "BLI_compiler_attrs.h"
-#include "BLI_utildefines.h"
-
struct BLI_mempool;
struct BLI_mempool_chunk;
diff --git a/source/blender/blenlib/BLI_open_addressing.h b/source/blender/blenlib/BLI_open_addressing.hh
index 6a0acd418eb..3bd932350d0 100644
--- a/source/blender/blenlib/BLI_open_addressing.h
+++ b/source/blender/blenlib/BLI_open_addressing.hh
@@ -14,8 +14,8 @@
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
-#ifndef __BLI_OPEN_ADDRESSING_H__
-#define __BLI_OPEN_ADDRESSING_H__
+#ifndef __BLI_OPEN_ADDRESSING_HH__
+#define __BLI_OPEN_ADDRESSING_HH__
/** \file
* \ingroup bli
@@ -33,28 +33,88 @@
#include <cmath>
-#include "BLI_allocator.h"
+#include "BLI_allocator.hh"
+#include "BLI_array.hh"
#include "BLI_math_base.h"
-#include "BLI_memory_utils_cxx.h"
+#include "BLI_memory_utils.hh"
#include "BLI_utildefines.h"
namespace BLI {
-template<typename Item, uint32_t ItemsInSmallStorage = 1, typename Allocator = GuardedAllocator>
+/** \name Constexpr utility functions.
+ * \{ */
+
+inline constexpr int is_power_of_2_i_constexpr(int n)
+{
+ return (n & (n - 1)) == 0;
+}
+
+inline constexpr uint32_t log2_floor_u_constexpr(uint32_t x)
+{
+ return x <= 1 ? 0 : 1 + log2_floor_u_constexpr(x >> 1);
+}
+
+inline constexpr uint32_t log2_ceil_u_constexpr(uint32_t x)
+{
+ return (is_power_of_2_i_constexpr((int)x)) ? log2_floor_u_constexpr(x) :
+ log2_floor_u_constexpr(x) + 1;
+}
+
+template<typename IntT> inline constexpr IntT ceil_division(IntT x, IntT y)
+{
+ BLI_STATIC_ASSERT(!std::is_signed<IntT>::value, "");
+ return x / y + ((x % y) != 0);
+}
+
+template<typename IntT> inline constexpr IntT floor_division(IntT x, IntT y)
+{
+ BLI_STATIC_ASSERT(!std::is_signed<IntT>::value, "");
+ return x / y;
+}
+
+inline constexpr uint8_t compute_item_exponent(uint32_t min_usable_slots,
+ uint32_t slots_per_item,
+ uint32_t max_load_factor_numerator,
+ uint32_t max_load_factor_denominator)
+{
+ // uint64_t min_total_slots = ceil_division((uint64_t)min_usable_slots *
+ // (uint64_t)max_load_factor_denominator,
+ // (uint64_t)max_load_factor_numerator);
+ // uint32_t min_total_items = (uint32_t)ceil_division(min_total_slots, (uint64_t)slots_per_item);
+ // uint8_t item_exponent = (uint8_t)log2_ceil_u_constexpr(min_total_items);
+ // return item_exponent;
+
+ return (uint8_t)log2_ceil_u_constexpr((uint32_t)ceil_division(
+ ceil_division((uint64_t)min_usable_slots * (uint64_t)max_load_factor_denominator,
+ (uint64_t)max_load_factor_numerator),
+ (uint64_t)slots_per_item));
+}
+
+/** \} */
+
+template<typename Item,
+ uint32_t MinUsableSlotsInSmallStorage = 1,
+ typename Allocator = GuardedAllocator>
class OpenAddressingArray {
private:
- static constexpr uint32_t slots_per_item = Item::slots_per_item;
- static constexpr float max_load_factor = 0.5f;
+ static constexpr uint32_t s_max_load_factor_numerator = 1;
+ static constexpr uint32_t s_max_load_factor_denominator = 2;
+ static constexpr uint32_t s_slots_per_item = Item::slots_per_item;
+
+ static constexpr uint8_t s_small_storage_item_exponent = compute_item_exponent(
+ MinUsableSlotsInSmallStorage,
+ s_slots_per_item,
+ s_max_load_factor_numerator,
+ s_max_load_factor_denominator);
+ static constexpr uint32_t s_items_in_small_storage = 1u << s_small_storage_item_exponent;
/* Invariants:
* 2^m_item_exponent = m_item_amount
- * m_item_amount * slots_per_item = m_slots_total
+ * m_item_amount * s_slots_per_item = m_slots_total
* m_slot_mask = m_slots_total - 1
* m_slots_set_or_dummy < m_slots_total
*/
- /* Array containing the actual hash table. Might be a pointer to the inlined storage. */
- Item *m_items;
/* Number of items in the hash table. Must be a power of two. */
uint32_t m_item_amount;
/* Exponent of the current item amount. */
@@ -69,65 +129,28 @@ class OpenAddressingArray {
uint32_t m_slots_usable;
/* Can be used to map a hash value into the range of valid slot indices. */
uint32_t m_slot_mask;
- Allocator m_allocator;
- AlignedBuffer<sizeof(Item) * ItemsInSmallStorage, alignof(Item)> m_local_storage;
+
+ Array<Item, s_items_in_small_storage, Allocator> m_items;
public:
- explicit OpenAddressingArray(uint8_t item_exponent = 0)
+ explicit OpenAddressingArray(uint8_t item_exponent = s_small_storage_item_exponent)
{
- m_slots_total = ((uint32_t)1 << item_exponent) * slots_per_item;
+ m_item_exponent = item_exponent;
+ m_item_amount = 1u << item_exponent;
+ m_slots_total = m_item_amount * s_slots_per_item;
+ m_slot_mask = m_slots_total - 1;
m_slots_set_or_dummy = 0;
m_slots_dummy = 0;
- m_slots_usable = (uint32_t)((float)m_slots_total * max_load_factor);
- m_slot_mask = m_slots_total - 1;
- m_item_amount = m_slots_total / slots_per_item;
- m_item_exponent = item_exponent;
+ m_slots_usable = (uint32_t)floor_division((uint64_t)m_slots_total *
+ (uint64_t)s_max_load_factor_numerator,
+ (uint64_t)s_max_load_factor_denominator);
- if (m_item_amount <= ItemsInSmallStorage) {
- m_items = this->small_storage();
- }
- else {
- m_items = (Item *)m_allocator.allocate_aligned(
- (uint32_t)sizeof(Item) * m_item_amount, std::alignment_of<Item>::value, __func__);
- }
-
- for (uint32_t i = 0; i < m_item_amount; i++) {
- new (m_items + i) Item();
- }
+ m_items = Array<Item, s_items_in_small_storage, Allocator>(m_item_amount);
}
- ~OpenAddressingArray()
- {
- if (m_items != nullptr) {
- for (uint32_t i = 0; i < m_item_amount; i++) {
- m_items[i].~Item();
- }
- if (!this->is_in_small_storage()) {
- m_allocator.deallocate((void *)m_items);
- }
- }
- }
-
- OpenAddressingArray(const OpenAddressingArray &other)
- {
- m_slots_total = other.m_slots_total;
- m_slots_set_or_dummy = other.m_slots_set_or_dummy;
- m_slots_dummy = other.m_slots_dummy;
- m_slots_usable = other.m_slots_usable;
- m_slot_mask = other.m_slot_mask;
- m_item_amount = other.m_item_amount;
- m_item_exponent = other.m_item_exponent;
-
- if (m_item_amount <= ItemsInSmallStorage) {
- m_items = this->small_storage();
- }
- else {
- m_items = (Item *)m_allocator.allocate_aligned(
- sizeof(Item) * m_item_amount, std::alignment_of<Item>::value, __func__);
- }
+ ~OpenAddressingArray() = default;
- uninitialized_copy_n(other.m_items, m_item_amount, m_items);
- }
+ OpenAddressingArray(const OpenAddressingArray &other) = default;
OpenAddressingArray(OpenAddressingArray &&other) noexcept
{
@@ -138,15 +161,8 @@ class OpenAddressingArray {
m_slot_mask = other.m_slot_mask;
m_item_amount = other.m_item_amount;
m_item_exponent = other.m_item_exponent;
- if (other.is_in_small_storage()) {
- m_items = this->small_storage();
- uninitialized_relocate_n(other.m_items, m_item_amount, m_items);
- }
- else {
- m_items = other.m_items;
- }
+ m_items = std::move(other.m_items);
- other.m_items = nullptr;
other.~OpenAddressingArray();
new (&other) OpenAddressingArray();
}
@@ -171,13 +187,19 @@ class OpenAddressingArray {
return *this;
}
+ Allocator &allocator()
+ {
+ return m_items.allocator();
+ }
+
/* Prepare a new array that can hold a minimum of min_usable_slots elements. All entries are
* empty. */
OpenAddressingArray init_reserved(uint32_t min_usable_slots) const
{
- float min_total_slots = (float)min_usable_slots / max_load_factor;
- uint32_t min_total_items = (uint32_t)std::ceil(min_total_slots / (float)slots_per_item);
- uint8_t item_exponent = (uint8_t)log2_ceil_u(min_total_items);
+ uint8_t item_exponent = compute_item_exponent(min_usable_slots,
+ s_slots_per_item,
+ s_max_load_factor_numerator,
+ s_max_load_factor_denominator);
OpenAddressingArray grown(item_exponent);
grown.m_slots_set_or_dummy = this->slots_set();
return grown;
@@ -270,36 +292,25 @@ class OpenAddressingArray {
Item *begin()
{
- return m_items;
+ return m_items.begin();
}
Item *end()
{
- return m_items + m_item_amount;
+ return m_items.end();
}
const Item *begin() const
{
- return m_items;
+ return m_items.begin();
}
const Item *end() const
{
- return m_items + m_item_amount;
- }
-
- private:
- Item *small_storage() const
- {
- return reinterpret_cast<Item *>((char *)m_local_storage.ptr());
- }
-
- bool is_in_small_storage() const
- {
- return m_items == this->small_storage();
+ return m_items.end();
}
};
} // namespace BLI
-#endif /* __BLI_OPEN_ADDRESSING_H__ */
+#endif /* __BLI_OPEN_ADDRESSING_HH__ */
diff --git a/source/blender/blenlib/BLI_optional.h b/source/blender/blenlib/BLI_optional.hh
index 267c858e0f2..eac11293781 100644
--- a/source/blender/blenlib/BLI_optional.h
+++ b/source/blender/blenlib/BLI_optional.hh
@@ -20,10 +20,10 @@
* Simple version of std::optional, which is only available since C++17.
*/
-#ifndef __BLI_OPTIONAL_H__
-#define __BLI_OPTIONAL_H__
+#ifndef __BLI_OPTIONAL_HH__
+#define __BLI_OPTIONAL_HH__
-#include "BLI_memory_utils_cxx.h"
+#include "BLI_memory_utils.hh"
#include "BLI_utildefines.h"
#include <algorithm>
@@ -196,4 +196,4 @@ template<typename T> class Optional {
} /* namespace BLI */
-#endif /* __BLI_OPTIONAL_H__ */
+#endif /* __BLI_OPTIONAL_HH__ */
diff --git a/source/blender/blenlib/BLI_path_util.h b/source/blender/blenlib/BLI_path_util.h
index 4376aefdc25..30823773d6c 100644
--- a/source/blender/blenlib/BLI_path_util.h
+++ b/source/blender/blenlib/BLI_path_util.h
@@ -23,13 +23,13 @@
* \ingroup bli
*/
+#include "BLI_compiler_attrs.h"
+#include "BLI_utildefines.h"
+
#ifdef __cplusplus
extern "C" {
#endif
-#include "BLI_compiler_attrs.h"
-#include "BLI_utildefines.h"
-
void BLI_setenv(const char *env, const char *val) ATTR_NONNULL(1);
void BLI_setenv_if_new(const char *env, const char *val) ATTR_NONNULL(1);
const char *BLI_getenv(const char *env) ATTR_NONNULL(1);
@@ -56,11 +56,11 @@ bool BLI_path_name_at_index(const char *__restrict path,
int *__restrict r_offset,
int *__restrict r_len) ATTR_NONNULL() ATTR_WARN_UNUSED_RESULT;
-const char *BLI_last_slash(const char *string) ATTR_NONNULL() ATTR_WARN_UNUSED_RESULT;
-int BLI_add_slash(char *string) ATTR_NONNULL();
-void BLI_del_slash(char *string) ATTR_NONNULL();
-const char *BLI_first_slash(const char *string) ATTR_NONNULL() ATTR_WARN_UNUSED_RESULT;
-void BLI_path_native_slash(char *path) ATTR_NONNULL();
+const char *BLI_path_slash_rfind(const char *string) ATTR_NONNULL() ATTR_WARN_UNUSED_RESULT;
+int BLI_path_slash_ensure(char *string) ATTR_NONNULL();
+void BLI_path_slash_rstrip(char *string) ATTR_NONNULL();
+const char *BLI_path_slash_find(const char *string) ATTR_NONNULL() ATTR_WARN_UNUSED_RESULT;
+void BLI_path_slash_native(char *path) ATTR_NONNULL();
#ifdef _WIN32
bool BLI_path_program_extensions_add_win32(char *name, const size_t maxlen);
@@ -77,22 +77,22 @@ bool BLI_path_extension_check_glob(const char *str, const char *ext_fnmatch)
bool BLI_path_extension_glob_validate(char *ext_fnmatch) ATTR_NONNULL();
bool BLI_path_extension_replace(char *path, size_t maxlen, const char *ext) ATTR_NONNULL();
bool BLI_path_extension_ensure(char *path, size_t maxlen, const char *ext) ATTR_NONNULL();
-bool BLI_ensure_filename(char *filepath, size_t maxlen, const char *filename) ATTR_NONNULL();
-int BLI_stringdec(const char *string, char *head, char *start, unsigned short *numlen);
-void BLI_stringenc(
+bool BLI_path_filename_ensure(char *filepath, size_t maxlen, const char *filename) ATTR_NONNULL();
+int BLI_path_sequence_decode(const char *string, char *head, char *start, unsigned short *numlen);
+void BLI_path_sequence_encode(
char *string, const char *head, const char *tail, unsigned short numlen, int pic);
-void BLI_cleanup_path(const char *relabase, char *path) ATTR_NONNULL(2);
+void BLI_path_normalize(const char *relabase, char *path) ATTR_NONNULL(2);
/* Same as above but adds a trailing slash. */
-void BLI_cleanup_dir(const char *relabase, char *dir) ATTR_NONNULL(2);
+void BLI_path_normalize_dir(const char *relabase, char *dir) ATTR_NONNULL(2);
bool BLI_filename_make_safe(char *fname) ATTR_NONNULL(1);
bool BLI_path_make_safe(char *path) ATTR_NONNULL(1);
/* Go back one directory. */
-bool BLI_parent_dir(char *path) ATTR_NONNULL();
+bool BLI_path_parent_dir(char *path) ATTR_NONNULL();
/* Go back until the directory is found. */
-bool BLI_parent_dir_until_exists(char *path) ATTR_NONNULL();
+bool BLI_path_parent_dir_until_exists(char *path) ATTR_NONNULL();
bool BLI_path_abs(char *path, const char *basepath) ATTR_NONNULL();
bool BLI_path_frame(char *path, int frame, int digits) ATTR_NONNULL();
@@ -100,7 +100,7 @@ bool BLI_path_frame_range(char *path, int sta, int end, int digits) ATTR_NONNULL
bool BLI_path_frame_get(char *path, int *r_frame, int *numdigits) ATTR_NONNULL();
void BLI_path_frame_strip(char *path, char *ext) ATTR_NONNULL();
bool BLI_path_frame_check_chars(const char *path) ATTR_NONNULL();
-bool BLI_path_cwd(char *path, const size_t maxlen) ATTR_NONNULL();
+bool BLI_path_abs_from_cwd(char *path, const size_t maxlen) ATTR_NONNULL();
void BLI_path_rel(char *file, const char *relfile) ATTR_NONNULL();
bool BLI_path_is_rel(const char *path) ATTR_NONNULL() ATTR_WARN_UNUSED_RESULT;
@@ -109,8 +109,8 @@ bool BLI_path_is_unc(const char *path);
void BLI_path_to_display_name(char *display_name, int maxlen, const char *name) ATTR_NONNULL();
#if defined(WIN32)
-void BLI_cleanup_unc_16(wchar_t *path_16);
-void BLI_cleanup_unc(char *path_16, int maxlen);
+void BLI_path_normalize_unc_16(wchar_t *path_16);
+void BLI_path_normalize_unc(char *path_16, int maxlen);
#endif
bool BLI_path_suffix(char *string, size_t maxlen, const char *suffix, const char *sep)
diff --git a/source/blender/blenlib/BLI_rand.h b/source/blender/blenlib/BLI_rand.h
index ad8a90b3977..ae78ea3af16 100644
--- a/source/blender/blenlib/BLI_rand.h
+++ b/source/blender/blenlib/BLI_rand.h
@@ -21,6 +21,7 @@
#define __BLI_RAND_H__
#include "BLI_compiler_attrs.h"
+#include "BLI_sys_types.h"
/** \file
* \ingroup bli
diff --git a/source/blender/blenlib/BLI_scanfill.h b/source/blender/blenlib/BLI_scanfill.h
index 39d3a679eb3..376ea9d88de 100644
--- a/source/blender/blenlib/BLI_scanfill.h
+++ b/source/blender/blenlib/BLI_scanfill.h
@@ -36,7 +36,7 @@ typedef struct ScanFillContext {
ListBase fillfacebase;
/* increment this value before adding each curve to skip having to calculate
- * 'poly_nr' for edges and verts (which can take approx half scanfill time) */
+ * 'poly_nr' for edges and verts (which can take approx half scan-fill time) */
unsigned short poly_nr;
/* private */
@@ -46,9 +46,9 @@ typedef struct ScanFillContext {
#define BLI_SCANFILL_ARENA_SIZE MEM_SIZE_OPTIMAL(1 << 14)
/**
- * \note this is USHRT_MAX so incrementing will set to zero
+ * \note this is USHRT_MAX so incrementing will set to zero
* which happens if callers choose to increment #ScanFillContext.poly_nr before adding each curve.
- * Nowhere else in scanfill do we make use of intentional overflow like this.
+ * Nowhere else in scan-fill do we make use of intentional overflow like this.
*/
#define SF_POLY_UNSET ((unsigned short)-1)
@@ -64,7 +64,7 @@ typedef struct ScanFillVert {
float co[3];
/** 2D projection of vertex location */
float xy[2];
- /** index, caller can use how it likes to match the scanfill result with own data */
+ /** index, caller can use how it likes to match the scan-fill result with own data */
unsigned int keyindex;
unsigned short poly_nr;
/** number of edges using this vertex */
diff --git a/source/blender/blenlib/BLI_set.h b/source/blender/blenlib/BLI_set.hh
index dc101add1a7..dc9df5d116a 100644
--- a/source/blender/blenlib/BLI_set.h
+++ b/source/blender/blenlib/BLI_set.hh
@@ -14,8 +14,8 @@
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
-#ifndef __BLI_SET_H__
-#define __BLI_SET_H__
+#ifndef __BLI_SET_HH__
+#define __BLI_SET_HH__
/** \file
* \ingroup bli
@@ -23,9 +23,9 @@
* This file provides a set implementation that uses open addressing with probing.
*/
-#include "BLI_hash_cxx.h"
-#include "BLI_open_addressing.h"
-#include "BLI_vector.h"
+#include "BLI_hash.hh"
+#include "BLI_open_addressing.hh"
+#include "BLI_vector.hh"
namespace BLI {
@@ -50,7 +50,8 @@ namespace BLI {
// clang-format on
-template<typename T, typename Allocator = GuardedAllocator> class Set {
+template<typename T, uint InlineBufferCapacity = 4, typename Allocator = GuardedAllocator>
+class Set {
private:
static constexpr uint OFFSET_MASK = 3;
static constexpr uint OFFSET_SHIFT = 2;
@@ -62,7 +63,7 @@ template<typename T, typename Allocator = GuardedAllocator> class Set {
static constexpr uint8_t IS_DUMMY = 2;
uint8_t m_status[4];
- char m_values[4 * sizeof(T)];
+ AlignedBuffer<4 * sizeof(T), alignof(T)> m_buffer;
public:
static constexpr uint slots_per_item = 4;
@@ -114,7 +115,7 @@ template<typename T, typename Allocator = GuardedAllocator> class Set {
T *value(uint offset) const
{
- return (T *)(m_values + offset * sizeof(T));
+ return (T *)m_buffer.ptr() + offset;
}
template<typename ForwardT> void store(uint offset, ForwardT &&value)
@@ -153,8 +154,8 @@ template<typename T, typename Allocator = GuardedAllocator> class Set {
}
};
- using ArrayType = OpenAddressingArray<Item, 1, Allocator>;
- ArrayType m_array = OpenAddressingArray<Item>();
+ using ArrayType = OpenAddressingArray<Item, InlineBufferCapacity, Allocator>;
+ ArrayType m_array;
public:
Set() = default;
@@ -202,6 +203,7 @@ template<typename T, typename Allocator = GuardedAllocator> class Set {
/**
* Add a new value to the set if it does not exist yet.
+ * Returns true of the value has been newly added.
*/
bool add(const T &value)
{
@@ -266,19 +268,26 @@ template<typename T, typename Allocator = GuardedAllocator> class Set {
ITER_SLOTS_END(offset);
}
- Vector<T> to_small_vector() const
+ /**
+ * Get the amount of values stored in the set.
+ */
+ uint32_t size() const
{
- Vector<T> vector;
- vector.reserve(this->size());
- for (const T &value : *this) {
- vector.append(value);
- }
- return vector;
+ return m_array.slots_set();
}
- uint32_t size() const
+ /**
+ * Return true if this set contains no elements.
+ */
+ bool is_empty() const
{
- return m_array.slots_set();
+ return this->size() == 0;
+ }
+
+ void clear()
+ {
+ this->~Set();
+ new (this) Set();
}
/**
@@ -480,4 +489,4 @@ template<typename T, typename Allocator = GuardedAllocator> class Set {
} // namespace BLI
-#endif /* __BLI_SET_H__ */
+#endif /* __BLI_SET_HH__ */
diff --git a/source/blender/blenlib/BLI_stack.h b/source/blender/blenlib/BLI_stack.h
index 9d122fdf798..9fc25e378a3 100644
--- a/source/blender/blenlib/BLI_stack.h
+++ b/source/blender/blenlib/BLI_stack.h
@@ -10,7 +10,7 @@
* 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,
+ * along with this program; if not, write to the Free Software Foundation,
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
diff --git a/source/blender/blenlib/BLI_stack_cxx.h b/source/blender/blenlib/BLI_stack.hh
index a26318a3dcb..7f1f9f9cc10 100644
--- a/source/blender/blenlib/BLI_stack_cxx.h
+++ b/source/blender/blenlib/BLI_stack.hh
@@ -14,8 +14,8 @@
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
-#ifndef __BLI_STACK_CXX_H__
-#define __BLI_STACK_CXX_H__
+#ifndef __BLI_STACK_HH__
+#define __BLI_STACK_HH__
/** \file
* \ingroup bli
@@ -23,13 +23,14 @@
* Basic stack implementation with support for small object optimization.
*/
-#include "BLI_vector.h"
+#include "BLI_vector.hh"
namespace BLI {
-template<typename T, uint N = 4, typename Allocator = GuardedAllocator> class Stack {
+template<typename T, uint InlineBufferCapacity = 4, typename Allocator = GuardedAllocator>
+class Stack {
private:
- Vector<T, N, Allocator> m_elements;
+ Vector<T, InlineBufferCapacity, Allocator> m_elements;
public:
Stack() = default;
@@ -147,4 +148,4 @@ template<typename T, uint N = 4, typename Allocator = GuardedAllocator> class St
} /* namespace BLI */
-#endif /* __BLI_STACK_CXX_H__ */
+#endif /* __BLI_STACK_HH__ */
diff --git a/source/blender/blenlib/BLI_string.h b/source/blender/blenlib/BLI_string.h
index 6d3f38c7a52..00e4e3485d1 100644
--- a/source/blender/blenlib/BLI_string.h
+++ b/source/blender/blenlib/BLI_string.h
@@ -27,13 +27,13 @@
#include <inttypes.h>
#include <stdarg.h>
+#include "BLI_compiler_attrs.h"
+#include "BLI_utildefines.h"
+
#ifdef __cplusplus
extern "C" {
#endif
-#include "BLI_compiler_attrs.h"
-#include "BLI_utildefines.h"
-
char *BLI_strdupn(const char *str, const size_t len) ATTR_MALLOC ATTR_WARN_UNUSED_RESULT
ATTR_NONNULL();
diff --git a/source/blender/blenlib/BLI_string_map.h b/source/blender/blenlib/BLI_string_map.hh
index ed97a6ae349..caa7e16d1f3 100644
--- a/source/blender/blenlib/BLI_string_map.h
+++ b/source/blender/blenlib/BLI_string_map.hh
@@ -14,8 +14,8 @@
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
-#ifndef __BLI_STRING_MAP_H__
-#define __BLI_STRING_MAP_H__
+#ifndef __BLI_STRING_MAP_HH__
+#define __BLI_STRING_MAP_HH__
/** \file
* \ingroup bli
@@ -27,10 +27,10 @@
* make it more efficient later on. Also, even if we will never implement this optimization, having
* a special map with string keys can be quite handy. */
-#include "BLI_map.h"
-#include "BLI_optional.h"
-#include "BLI_string_ref.h"
-#include "BLI_vector.h"
+#include "BLI_map.hh"
+#include "BLI_optional.hh"
+#include "BLI_string_ref.hh"
+#include "BLI_vector.hh"
namespace BLI {
@@ -156,10 +156,15 @@ template<typename T, typename Allocator = GuardedAllocator> class StringMap {
template<typename ForwardT>
void store(uint offset, uint32_t hash, uint32_t index, ForwardT &&value)
{
+ this->store_without_value(offset, hash, index);
+ new (this->value(offset)) T(std::forward<ForwardT>(value));
+ }
+
+ void store_without_value(uint offset, uint32_t hash, uint32_t index)
+ {
BLI_assert(!this->is_set(offset));
m_hashes[offset] = hash;
m_indices[offset] = index;
- new (this->value(offset)) T(std::forward<ForwardT>(value));
}
};
@@ -195,15 +200,51 @@ template<typename T, typename Allocator = GuardedAllocator> class StringMap {
*/
void add(StringRef key, const T &value)
{
- if (!this->contains(key)) {
- this->add_new(key, value);
- }
+ this->add__impl(key, value);
}
void add(StringRef key, T &&value)
{
- if (!this->contains(key)) {
- this->add_new(key, std::move(value));
+ this->add__impl(key, std::move(value));
+ }
+
+ /**
+ * First, checks if the key exists in the map.
+ * If it does exist, call the modify function with a pointer to the corresponding value.
+ * If it does not exist, call the create function with a pointer to where the value should be
+ * created.
+ *
+ * Returns whatever is returned from one of the callback functions. Both callbacks have to return
+ * the same type.
+ *
+ * CreateValueF: Takes a pointer to where the value should be created.
+ * ModifyValueF: Takes a pointer to the value that should be modified.
+ */
+ template<typename CreateValueF, typename ModifyValueF>
+ auto add_or_modify(StringRef key,
+ const CreateValueF &create_value,
+ const ModifyValueF &modify_value) -> decltype(create_value(nullptr))
+ {
+ using CreateReturnT = decltype(create_value(nullptr));
+ using ModifyReturnT = decltype(modify_value(nullptr));
+ BLI_STATIC_ASSERT((std::is_same<CreateReturnT, ModifyReturnT>::value),
+ "Both callbacks should return the same type.");
+
+ this->ensure_can_add();
+ uint32_t hash = this->compute_string_hash(key);
+ ITER_SLOTS_BEGIN (hash, m_array, , item, offset) {
+ if (item.is_empty(offset)) {
+ m_array.update__empty_to_set();
+ uint32_t index = this->save_key_in_array(key);
+ item.store_without_value(offset, hash, index);
+ T *value_ptr = item.value(offset);
+ return create_value(value_ptr);
+ }
+ else if (item.has_hash(offset, hash) && item.has_exact_key(offset, key, m_chars)) {
+ T *value_ptr = item.value(offset);
+ return modify_value(value_ptr);
+ }
}
+ ITER_SLOTS_END(offset);
}
/**
@@ -301,6 +342,27 @@ template<typename T, typename Allocator = GuardedAllocator> class StringMap {
}
/**
+ * Return the value that corresponds to the given key.
+ * If it does not exist yet, create and insert it first.
+ */
+ template<typename CreateValueF> T &lookup_or_add(StringRef key, const CreateValueF &create_value)
+ {
+ return *this->add_or_modify(
+ key,
+ [&](T *value) { return new (value) T(create_value()); },
+ [](T *value) { return value; });
+ }
+
+ /**
+ * Return the value that corresponds to the given key.
+ * If it does not exist yet, insert a new default constructed value and return that.
+ */
+ T &lookup_or_add_default(StringRef key)
+ {
+ return this->lookup_or_add(key, []() { return T(); });
+ }
+
+ /**
* Do a linear search over all items to find a key for a value.
*/
StringRefNull find_key_for_value(const T &value) const
@@ -435,9 +497,8 @@ template<typename T, typename Allocator = GuardedAllocator> class StringMap {
ITER_SLOTS_END(offset);
}
- template<typename ForwardT> void add_new__impl(StringRef key, ForwardT &&value)
+ template<typename ForwardT> bool add__impl(StringRef key, ForwardT &&value)
{
- BLI_assert(!this->contains(key));
this->ensure_can_add();
uint32_t hash = this->compute_string_hash(key);
ITER_SLOTS_BEGIN (hash, m_array, , item, offset) {
@@ -445,17 +506,27 @@ template<typename T, typename Allocator = GuardedAllocator> class StringMap {
uint32_t index = this->save_key_in_array(key);
item.store(offset, hash, index, std::forward<ForwardT>(value));
m_array.update__empty_to_set();
- return;
+ return true;
+ }
+ else if (item.has_hash(offset, hash) && item.has_exact_key(offset, key, m_chars)) {
+ return false;
}
}
ITER_SLOTS_END(offset);
}
- template<typename ForwardT> void add__impl(StringRef key, ForwardT &&value)
+ template<typename ForwardT> void add_new__impl(StringRef key, ForwardT &&value)
{
+ BLI_assert(!this->contains(key));
this->ensure_can_add();
uint32_t hash = this->compute_string_hash(key);
ITER_SLOTS_BEGIN (hash, m_array, , item, offset) {
+ if (item.is_empty(offset)) {
+ uint32_t index = this->save_key_in_array(key);
+ item.store(offset, hash, index, std::forward<ForwardT>(value));
+ m_array.update__empty_to_set();
+ return;
+ }
}
ITER_SLOTS_END(offset);
}
@@ -466,4 +537,4 @@ template<typename T, typename Allocator = GuardedAllocator> class StringMap {
} // namespace BLI
-#endif /* __BLI_STRING_MAP_H__ */
+#endif /* __BLI_STRING_MAP_HH__ */
diff --git a/source/blender/blenlib/BLI_string_ref.h b/source/blender/blenlib/BLI_string_ref.hh
index 2389542bcea..eacc501375a 100644
--- a/source/blender/blenlib/BLI_string_ref.h
+++ b/source/blender/blenlib/BLI_string_ref.hh
@@ -14,8 +14,8 @@
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
-#ifndef __BLI_STRING_REF_H__
-#define __BLI_STRING_REF_H__
+#ifndef __BLI_STRING_REF_HH__
+#define __BLI_STRING_REF_HH__
/** \file
* \ingroup bli
@@ -32,7 +32,7 @@
#include <sstream>
#include <string>
-#include "BLI_array_ref.h"
+#include "BLI_array_ref.hh"
#include "BLI_utildefines.h"
namespace BLI {
@@ -94,12 +94,28 @@ class StringRefBase {
return m_data + m_size;
}
- void copy_to__with_null(char *dst) const
+ void unsafe_copy(char *dst) const
{
memcpy(dst, m_data, m_size);
dst[m_size] = '\0';
}
+ void copy(char *dst, uint dst_size) const
+ {
+ if (m_size < dst_size) {
+ this->unsafe_copy(dst);
+ }
+ else {
+ BLI_assert(false);
+ dst[0] = '\0';
+ }
+ }
+
+ template<uint N> void copy(char (&dst)[N])
+ {
+ this->copy(dst, N);
+ }
+
/**
* Returns true when the string begins with the given prefix. Otherwise false.
*/
@@ -252,4 +268,4 @@ inline StringRef StringRefBase::substr(uint start, uint size) const
} // namespace BLI
-#endif /* __BLI_STRING_REF_H__ */
+#endif /* __BLI_STRING_REF_HH__ */
diff --git a/source/blender/blenlib/BLI_string_utf8.h b/source/blender/blenlib/BLI_string_utf8.h
index 8d986d45a17..78e7113b6ef 100644
--- a/source/blender/blenlib/BLI_string_utf8.h
+++ b/source/blender/blenlib/BLI_string_utf8.h
@@ -21,13 +21,13 @@
* \ingroup bli
*/
+#include "BLI_compiler_attrs.h"
+#include "BLI_sys_types.h"
+
#ifdef __cplusplus
extern "C" {
#endif
-#include "BLI_compiler_attrs.h"
-#include "BLI_sys_types.h"
-
char *BLI_strncpy_utf8(char *__restrict dst, const char *__restrict src, size_t maxncpy)
ATTR_NONNULL();
size_t BLI_strncpy_utf8_rlen(char *__restrict dst, const char *__restrict src, size_t maxncpy)
diff --git a/source/blender/blenlib/BLI_string_utils.h b/source/blender/blenlib/BLI_string_utils.h
index 7b0dd13e0c7..857b22540e9 100644
--- a/source/blender/blenlib/BLI_string_utils.h
+++ b/source/blender/blenlib/BLI_string_utils.h
@@ -26,13 +26,13 @@
#include <stdarg.h>
+#include "BLI_compiler_attrs.h"
+#include "BLI_utildefines.h"
+
#ifdef __cplusplus
extern "C" {
#endif
-#include "BLI_compiler_attrs.h"
-#include "BLI_utildefines.h"
-
struct ListBase;
typedef bool (*UniquenameCheckCallback)(void *arg, const char *name);
diff --git a/source/blender/blenlib/BLI_sys_types.h b/source/blender/blenlib/BLI_sys_types.h
index b9e799aa2a9..ef15ce111b6 100644
--- a/source/blender/blenlib/BLI_sys_types.h
+++ b/source/blender/blenlib/BLI_sys_types.h
@@ -73,7 +73,7 @@ typedef uint64_t u_int64_t;
#include <stddef.h> /* size_t define */
#ifndef __cplusplus
-# if defined(__APPLE__)
+# if defined(__APPLE__) || defined(__NetBSD__)
/* The <uchar.h> standard header is missing on macOS. */
typedef unsigned int char32_t;
# else
diff --git a/source/blender/blenlib/BLI_system.h b/source/blender/blenlib/BLI_system.h
index 8c0c9ad99bf..50f8adc20f6 100644
--- a/source/blender/blenlib/BLI_system.h
+++ b/source/blender/blenlib/BLI_system.h
@@ -53,6 +53,10 @@ int BLI_system_memory_max_in_megabytes_int(void);
/* getpid */
#ifdef WIN32
# define BLI_SYSTEM_PID_H <process.h>
+
+/* void* since we really do not want to drag Windows.h in to get the proper typedef. */
+void BLI_windows_handle_exception(void *exception);
+
#else
# define BLI_SYSTEM_PID_H <unistd.h>
#endif
diff --git a/source/blender/blenlib/BLI_task.h b/source/blender/blenlib/BLI_task.h
index 83bcdff214d..eee304a9b72 100644
--- a/source/blender/blenlib/BLI_task.h
+++ b/source/blender/blenlib/BLI_task.h
@@ -25,13 +25,13 @@ struct ListBase;
* \ingroup bli
*/
+#include "BLI_threads.h"
+#include "BLI_utildefines.h"
+
#ifdef __cplusplus
extern "C" {
#endif
-#include "BLI_threads.h"
-#include "BLI_utildefines.h"
-
struct BLI_mempool;
/* Task Scheduler
@@ -43,16 +43,13 @@ struct BLI_mempool;
* must be called from the main threads. All other scheduler and pool functions
* are thread-safe. */
-typedef struct TaskScheduler TaskScheduler;
-
-TaskScheduler *BLI_task_scheduler_create(int num_threads);
-void BLI_task_scheduler_free(TaskScheduler *scheduler);
-
-int BLI_task_scheduler_num_threads(TaskScheduler *scheduler);
+void BLI_task_scheduler_init(void);
+void BLI_task_scheduler_exit(void);
+int BLI_task_scheduler_num_threads(void);
/* Task Pool
*
- * Pool of tasks that will be executed by the central TaskScheduler. For each
+ * Pool of tasks that will be executed by the central task scheduler. For each
* pool, we can wait for all tasks to be done, or cancel them before they are
* done.
*
@@ -70,36 +67,40 @@ typedef enum TaskPriority {
} TaskPriority;
typedef struct TaskPool TaskPool;
-typedef void (*TaskRunFunction)(TaskPool *__restrict pool, void *taskdata, int threadid);
-typedef void (*TaskFreeFunction)(TaskPool *__restrict pool, void *taskdata, int threadid);
+typedef void (*TaskRunFunction)(TaskPool *__restrict pool, void *taskdata);
+typedef void (*TaskFreeFunction)(TaskPool *__restrict pool, void *taskdata);
+
+/* Regular task pool that immediately starts executing tasks as soon as they
+ * are pushed, either on the current or another thread. */
+TaskPool *BLI_task_pool_create(void *userdata, TaskPriority priority);
+
+/* Background: always run tasks in a background thread, never immediately
+ * execute them. For running background jobs. */
+TaskPool *BLI_task_pool_create_background(void *userdata, TaskPriority priority);
+
+/* Background Serial: run tasks one after the other in the background,
+ * without parallelization between the tasks. */
+TaskPool *BLI_task_pool_create_background_serial(void *userdata, TaskPriority priority);
+
+/* Suspended: don't execute tasks until work_and_wait is called. This is slower
+ * as threads can't immediately start working. But it can be used if the data
+ * structures the threads operate on are not fully initialized until all tasks
+ * are created. */
+TaskPool *BLI_task_pool_create_suspended(void *userdata, TaskPriority priority);
+
+/* No threads: immediately executes tasks on the same thread. For debugging. */
+TaskPool *BLI_task_pool_create_no_threads(void *userdata);
-TaskPool *BLI_task_pool_create(TaskScheduler *scheduler, void *userdata);
-TaskPool *BLI_task_pool_create_background(TaskScheduler *scheduler, void *userdata);
-TaskPool *BLI_task_pool_create_suspended(TaskScheduler *scheduler, void *userdata);
void BLI_task_pool_free(TaskPool *pool);
-void BLI_task_pool_push_ex(TaskPool *pool,
- TaskRunFunction run,
- void *taskdata,
- bool free_taskdata,
- TaskFreeFunction freedata,
- TaskPriority priority);
void BLI_task_pool_push(TaskPool *pool,
TaskRunFunction run,
void *taskdata,
bool free_taskdata,
- TaskPriority priority);
-void BLI_task_pool_push_from_thread(TaskPool *pool,
- TaskRunFunction run,
- void *taskdata,
- bool free_taskdata,
- TaskPriority priority,
- int thread_id);
+ TaskFreeFunction freedata);
/* work and wait until all tasks are done */
void BLI_task_pool_work_and_wait(TaskPool *pool);
-/* work and wait until all tasks are done, then reset to the initial suspended state */
-void BLI_task_pool_work_wait_and_reset(TaskPool *pool);
/* cancel all tasks, keep worker threads running */
void BLI_task_pool_cancel(TaskPool *pool);
@@ -107,50 +108,29 @@ void BLI_task_pool_cancel(TaskPool *pool);
bool BLI_task_pool_canceled(TaskPool *pool);
/* optional userdata pointer to pass along to run function */
-void *BLI_task_pool_userdata(TaskPool *pool);
+void *BLI_task_pool_user_data(TaskPool *pool);
/* optional mutex to use from run function */
ThreadMutex *BLI_task_pool_user_mutex(TaskPool *pool);
-/* Delayed push, use that to reduce thread overhead by accumulating
- * all new tasks into local queue first and pushing it to scheduler
- * from within a single mutex lock.
- */
-void BLI_task_pool_delayed_push_begin(TaskPool *pool, int thread_id);
-void BLI_task_pool_delayed_push_end(TaskPool *pool, int thread_id);
-
/* Parallel for routines */
-typedef enum eTaskSchedulingMode {
- /* Task scheduler will divide overall work into equal chunks, scheduling
- * even chunks to all worker threads.
- * Least run time benefit, ideal for cases when each task requires equal
- * amount of compute power.
- */
- TASK_SCHEDULING_STATIC,
- /* Task scheduler will schedule small amount of work to each worker thread.
- * Has more run time overhead, but deals much better with cases when each
- * part of the work requires totally different amount of compute power.
- */
- TASK_SCHEDULING_DYNAMIC,
-} eTaskSchedulingMode;
-
/* Per-thread specific data passed to the callback. */
typedef struct TaskParallelTLS {
- /* Identifier of the thread who this data belongs to. */
- int thread_id;
/* Copy of user-specifier chunk, which is copied from original chunk to all
* worker threads. This is similar to OpenMP's firstprivate.
*/
void *userdata_chunk;
} TaskParallelTLS;
-typedef void (*TaskParallelFinalizeFunc)(void *__restrict userdata,
- void *__restrict userdata_chunk);
-
typedef void (*TaskParallelRangeFunc)(void *__restrict userdata,
const int iter,
const TaskParallelTLS *__restrict tls);
+typedef void (*TaskParallelReduceFunc)(const void *__restrict userdata,
+ void *__restrict chunk_join,
+ void *__restrict chunk);
+
+typedef void (*TaskParallelFreeFunc)(const void *__restrict userdata, void *__restrict chunk);
typedef struct TaskParallelSettings {
/* Whether caller allows to do threading of the particular range.
@@ -160,8 +140,6 @@ typedef struct TaskParallelSettings {
* is higher than a chunk size. As in, threading will always be performed.
*/
bool use_threading;
- /* Scheduling mode to use for this parallel range invocation. */
- eTaskSchedulingMode scheduling_mode;
/* Each instance of looping chunks will get a copy of this data
* (similar to OpenMP's firstprivate).
*/
@@ -170,7 +148,13 @@ typedef struct TaskParallelSettings {
/* Function called from calling thread once whole range have been
* processed.
*/
- TaskParallelFinalizeFunc func_finalize;
+ /* Function called to join user data chunk into another, to reduce
+ * the result to the original userdata_chunk memory.
+ * The reduce functions should have no side effects, so that they
+ * can be run on any thread. */
+ TaskParallelReduceFunc func_reduce;
+ /* Function called to free data created by TaskParallelRangeFunc. */
+ TaskParallelFreeFunc func_free;
/* Minimum allowed number of range iterators to be handled by a single
* thread. This allows to achieve following:
* - Reduce amount of threading overhead.
@@ -190,19 +174,7 @@ void BLI_task_parallel_range(const int start,
const int stop,
void *userdata,
TaskParallelRangeFunc func,
- TaskParallelSettings *settings);
-
-typedef struct TaskParallelRangePool TaskParallelRangePool;
-struct TaskParallelRangePool *BLI_task_parallel_range_pool_init(
- const struct TaskParallelSettings *settings);
-void BLI_task_parallel_range_pool_push(struct TaskParallelRangePool *range_pool,
- const int start,
- const int stop,
- void *userdata,
- TaskParallelRangeFunc func,
- const struct TaskParallelSettings *settings);
-void BLI_task_parallel_range_pool_work_and_wait(struct TaskParallelRangePool *range_pool);
-void BLI_task_parallel_range_pool_free(struct TaskParallelRangePool *range_pool);
+ const TaskParallelSettings *settings);
/* This data is shared between all tasks, its access needs thread lock or similar protection.
*/
@@ -257,11 +229,90 @@ BLI_INLINE void BLI_parallel_range_settings_defaults(TaskParallelSettings *setti
{
memset(settings, 0, sizeof(*settings));
settings->use_threading = true;
- settings->scheduling_mode = TASK_SCHEDULING_STATIC;
/* Use default heuristic to define actual chunk size. */
settings->min_iter_per_thread = 0;
}
+/* Don't use this, store any thread specific data in tls->userdata_chunk instead.
+ * Only here for code to be removed. */
+int BLI_task_parallel_thread_id(const TaskParallelTLS *tls);
+
+/* Task Graph Scheduling */
+/* Task Graphs can be used to create a forest of directional trees and schedule work to any tree.
+ * The nodes in the graph can be run in separate threads.
+ *
+ * +---- [root] ----+
+ * | |
+ * v v
+ * [node_1] +---- [node_2] ----+
+ * | |
+ * v v
+ * [node_3] [node_4]
+ *
+ * TaskGraph *task_graph = BLI_task_graph_create();
+ * TaskNode *root = BLI_task_graph_node_create(task_graph, root_exec, NULL, NULL);
+ * TaskNode *node_1 = BLI_task_graph_node_create(task_graph, node_exec, NULL, NULL);
+ * TaskNode *node_2 = BLI_task_graph_node_create(task_graph, node_exec, NULL, NULL);
+ * TaskNode *node_3 = BLI_task_graph_node_create(task_graph, node_exec, NULL, NULL);
+ * TaskNode *node_4 = BLI_task_graph_node_create(task_graph, node_exec, NULL, NULL);
+ *
+ * BLI_task_graph_edge_create(root, node_1);
+ * BLI_task_graph_edge_create(root, node_2);
+ * BLI_task_graph_edge_create(node_2, node_3);
+ * BLI_task_graph_edge_create(node_2, node_4);
+ *
+ * Any node can be triggered to start a chain of tasks. Normally you would trigger a root node but
+ * it is supported to start the chain of tasks anywhere in the forest or tree. When a node
+ * completes, the execution flow is forwarded via the created edges.
+ * When a child node has multiple parents the child node will be triggered once for each parent.
+ *
+ * BLI_task_graph_node_push_work(root);
+ *
+ * In this example After `root` is finished, `node_1` and `node_2` will be started.
+ * Only after `node_2` is finished `node_3` and `node_4` will be started.
+ *
+ * After scheduling work we need to wait until all the tasks have been finished.
+ *
+ * BLI_task_graph_work_and_wait();
+ *
+ * When finished you can clean up all the resources by freeing the task_graph. Nodes are owned by
+ * the graph and are freed task_data will only be freed if a free_func was given.
+ *
+ * BLI_task_graph_free(task_graph);
+ *
+ * Work can enter a tree on any node. Normally this would be the root_node.
+ * A `task_graph` can be reused, but the caller needs to make sure the task_data is reset.
+ *
+ * ** Task-Data **
+ *
+ * Typically you want give a task data to work on.
+ * Task data can be shared with other nodes, but be careful not to free the data multiple times.
+ * Task data is freed when calling `BLI_task_graph_free`.
+ *
+ * MyData *task_data = MEM_callocN(sizeof(MyData), __func__);
+ * TaskNode *root = BLI_task_graph_node_create(task_graph, root_exec, task_data, MEM_freeN);
+ * TaskNode *node_1 = BLI_task_graph_node_create(task_graph, node_exec, task_data, NULL);
+ * TaskNode *node_2 = BLI_task_graph_node_create(task_graph, node_exec, task_data, NULL);
+ * TaskNode *node_3 = BLI_task_graph_node_create(task_graph, node_exec, task_data, NULL);
+ * TaskNode *node_4 = BLI_task_graph_node_create(task_graph, node_exec, task_data, NULL);
+ *
+ */
+struct TaskGraph;
+struct TaskNode;
+
+typedef void (*TaskGraphNodeRunFunction)(void *__restrict task_data);
+typedef void (*TaskGraphNodeFreeFunction)(void *task_data);
+
+struct TaskGraph *BLI_task_graph_create(void);
+void BLI_task_graph_work_and_wait(struct TaskGraph *task_graph);
+void BLI_task_graph_free(struct TaskGraph *task_graph);
+struct TaskNode *BLI_task_graph_node_create(struct TaskGraph *task_graph,
+ TaskGraphNodeRunFunction run,
+ void *task_data,
+ TaskGraphNodeFreeFunction free_func);
+bool BLI_task_graph_node_push_work(struct TaskNode *task_node);
+void BLI_task_graph_edge_create(struct TaskNode *from_node, struct TaskNode *to_node);
+
#ifdef __cplusplus
}
#endif
diff --git a/source/blender/blenlib/BLI_threads.h b/source/blender/blenlib/BLI_threads.h
index c2127c1ec3a..03fe27c10ed 100644
--- a/source/blender/blenlib/BLI_threads.h
+++ b/source/blender/blenlib/BLI_threads.h
@@ -23,9 +23,6 @@
/** \file
* \ingroup bli
*/
-#ifdef __cplusplus
-extern "C" {
-#endif
#include <pthread.h>
@@ -35,6 +32,10 @@ extern "C" {
# include <libkern/OSAtomic.h>
#endif
+#ifdef __cplusplus
+extern "C" {
+#endif
+
/* for tables, button in UI, etc */
#define BLENDER_MAX_THREADS 1024
@@ -47,8 +48,6 @@ struct TaskScheduler;
void BLI_threadapi_init(void);
void BLI_threadapi_exit(void);
-struct TaskScheduler *BLI_task_scheduler_get(void);
-
void BLI_threadpool_init(struct ListBase *threadbase, void *(*do_thread)(void *), int tot);
int BLI_available_threads(struct ListBase *threadbase);
int BLI_threadpool_available_thread_index(struct ListBase *threadbase);
@@ -59,9 +58,6 @@ void BLI_threadpool_clear(struct ListBase *threadbase);
void BLI_threadpool_end(struct ListBase *threadbase);
int BLI_thread_is_main(void);
-void BLI_threaded_malloc_begin(void);
-void BLI_threaded_malloc_end(void);
-
/* System Information */
int BLI_system_thread_count(void); /* gets the number of threads the system can make use of */
diff --git a/source/blender/blenlib/BLI_timeit.hh b/source/blender/blenlib/BLI_timeit.hh
new file mode 100644
index 00000000000..e9f121ec654
--- /dev/null
+++ b/source/blender/blenlib/BLI_timeit.hh
@@ -0,0 +1,62 @@
+/*
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+
+#ifndef __BLI_TIMEIT_HH__
+#define __BLI_TIMEIT_HH__
+
+#include <chrono>
+#include <iostream>
+#include <string>
+
+#include "BLI_sys_types.h"
+
+namespace BLI {
+namespace Timeit {
+
+using Clock = std::chrono::steady_clock;
+using TimePoint = Clock::time_point;
+using Nanoseconds = std::chrono::nanoseconds;
+
+void print_duration(Nanoseconds duration);
+
+class ScopedTimer {
+ private:
+ std::string m_name;
+ TimePoint m_start;
+
+ public:
+ ScopedTimer(std::string name) : m_name(std::move(name))
+ {
+ m_start = Clock::now();
+ }
+
+ ~ScopedTimer()
+ {
+ TimePoint end = Clock::now();
+ Nanoseconds duration = end - m_start;
+
+ std::cout << "Timer '" << m_name << "' took ";
+ print_duration(duration);
+ std::cout << '\n';
+ }
+};
+
+} // namespace Timeit
+} // namespace BLI
+
+#define SCOPED_TIMER(name) BLI::Timeit::ScopedTimer scoped_timer(name)
+
+#endif /* __BLI_TIMEIT_HH__ */
diff --git a/source/blender/blenlib/BLI_utildefines.h b/source/blender/blenlib/BLI_utildefines.h
index fb5dbf66819..1f28f7e80c5 100644
--- a/source/blender/blenlib/BLI_utildefines.h
+++ b/source/blender/blenlib/BLI_utildefines.h
@@ -24,10 +24,6 @@
* \ingroup bli
*/
-#ifdef __cplusplus
-extern "C" {
-#endif
-
/* avoid many includes for now */
#include "BLI_compiler_compat.h"
#include "BLI_sys_types.h"
@@ -39,6 +35,10 @@ extern "C" {
/* include after _VA_NARGS macro */
#include "BLI_compiler_typecheck.h"
+#ifdef __cplusplus
+extern "C" {
+#endif
+
/* -------------------------------------------------------------------- */
/** \name Min/Max Macros
* \{ */
diff --git a/source/blender/blenlib/BLI_utility_mixins.h b/source/blender/blenlib/BLI_utility_mixins.hh
index ce7a4ce094a..441575f9111 100644
--- a/source/blender/blenlib/BLI_utility_mixins.h
+++ b/source/blender/blenlib/BLI_utility_mixins.hh
@@ -18,8 +18,8 @@
* \ingroup bli
*/
-#ifndef __BLI_UTILITY_MIXINS_H__
-#define __BLI_UTILITY_MIXINS_H__
+#ifndef __BLI_UTILITY_MIXINS_HH__
+#define __BLI_UTILITY_MIXINS_HH__
namespace BLI {
@@ -49,4 +49,4 @@ class NonMovable {
} // namespace BLI
-#endif /* __BLI_UTILITY_MIXINS_H__ */
+#endif /* __BLI_UTILITY_MIXINS_HH__ */
diff --git a/source/blender/blenlib/BLI_vector.h b/source/blender/blenlib/BLI_vector.hh
index 6a708759d0e..49cf41c2005 100644
--- a/source/blender/blenlib/BLI_vector.h
+++ b/source/blender/blenlib/BLI_vector.hh
@@ -14,8 +14,8 @@
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
-#ifndef __BLI_VECTOR_H__
-#define __BLI_VECTOR_H__
+#ifndef __BLI_VECTOR_HH__
+#define __BLI_VECTOR_HH__
/** \file
* \ingroup bli
@@ -31,25 +31,26 @@
#include <iostream>
#include <memory>
-#include "BLI_allocator.h"
-#include "BLI_array_ref.h"
-#include "BLI_index_range.h"
-#include "BLI_listbase_wrapper.h"
+#include "BLI_allocator.hh"
+#include "BLI_array_ref.hh"
+#include "BLI_index_range.hh"
+#include "BLI_listbase_wrapper.hh"
#include "BLI_math_base.h"
-#include "BLI_memory_utils_cxx.h"
+#include "BLI_memory_utils.hh"
#include "BLI_utildefines.h"
#include "MEM_guardedalloc.h"
namespace BLI {
-template<typename T, uint N = 4, typename Allocator = GuardedAllocator> class Vector {
+template<typename T, uint InlineBufferCapacity = 4, typename Allocator = GuardedAllocator>
+class Vector {
private:
T *m_begin;
T *m_end;
T *m_capacity_end;
Allocator m_allocator;
- AlignedBuffer<sizeof(T) * N, alignof(T)> m_small_buffer;
+ AlignedBuffer<(uint)sizeof(T) * InlineBufferCapacity, (uint)alignof(T)> m_small_buffer;
#ifndef NDEBUG
/* Storing size in debug builds, because it makes debugging much easier sometimes. */
@@ -70,7 +71,7 @@ template<typename T, uint N = 4, typename Allocator = GuardedAllocator> class Ve
{
m_begin = this->small_buffer();
m_end = m_begin;
- m_capacity_end = m_begin + N;
+ m_capacity_end = m_begin + InlineBufferCapacity;
UPDATE_VECTOR_SIZE(this);
}
@@ -130,20 +131,17 @@ template<typename T, uint N = 4, typename Allocator = GuardedAllocator> class Ve
/**
* Create a vector from a ListBase.
*/
- Vector(ListBase &values, bool intrusive_next_and_prev_pointers) : Vector()
+ Vector(ListBase &values) : Vector()
{
- BLI_assert(intrusive_next_and_prev_pointers);
- if (intrusive_next_and_prev_pointers) {
- for (T value : IntrusiveListBaseWrapper<typename std::remove_pointer<T>::type>(values)) {
- this->append(value);
- }
+ for (T value : ListBaseWrapper<typename std::remove_pointer<T>::type>(values)) {
+ this->append(value);
}
}
/**
* Create a copy of another vector.
* The other vector will not be changed.
- * If the other vector has less than N elements, no allocation will be made.
+ * If the other vector has less than InlineBufferCapacity elements, no allocation will be made.
*/
Vector(const Vector &other) : m_allocator(other.m_allocator)
{
@@ -167,11 +165,11 @@ template<typename T, uint N = 4, typename Allocator = GuardedAllocator> class Ve
uint size = other.size();
if (other.is_small()) {
- if (size <= N) {
+ if (size <= InlineBufferCapacity) {
/* Copy between inline buffers. */
m_begin = this->small_buffer();
m_end = m_begin + size;
- m_capacity_end = m_begin + N;
+ m_capacity_end = m_begin + InlineBufferCapacity;
uninitialized_relocate_n(other.m_begin, size, m_begin);
}
else {
@@ -286,7 +284,7 @@ template<typename T, uint N = 4, typename Allocator = GuardedAllocator> class Ve
m_begin = this->small_buffer();
m_end = m_begin;
- m_capacity_end = m_begin + N;
+ m_capacity_end = m_begin + InlineBufferCapacity;
UPDATE_VECTOR_SIZE(this);
}
@@ -429,7 +427,7 @@ template<typename T, uint N = 4, typename Allocator = GuardedAllocator> class Ve
/**
* Returns true when the vector contains no elements, otherwise false.
*/
- bool empty() const
+ bool is_empty() const
{
return m_begin == m_end;
}
@@ -440,7 +438,7 @@ template<typename T, uint N = 4, typename Allocator = GuardedAllocator> class Ve
*/
void remove_last()
{
- BLI_assert(!this->empty());
+ BLI_assert(!this->is_empty());
m_end--;
destruct(m_end);
UPDATE_VECTOR_SIZE(this);
@@ -451,7 +449,7 @@ template<typename T, uint N = 4, typename Allocator = GuardedAllocator> class Ve
*/
T pop_last()
{
- BLI_assert(!this->empty());
+ BLI_assert(!this->is_empty());
m_end--;
T value = std::move(*m_end);
destruct(m_end);
@@ -581,7 +579,8 @@ template<typename T, uint N = 4, typename Allocator = GuardedAllocator> class Ve
std::cout << "Small Vector at " << (void *)this << ":" << std::endl;
std::cout << " Elements: " << this->size() << std::endl;
std::cout << " Capacity: " << (m_capacity_end - m_begin) << std::endl;
- std::cout << " Small Elements: " << N << " Size on Stack: " << sizeof(*this) << std::endl;
+ std::cout << " Small Elements: " << InlineBufferCapacity
+ << " Size on Stack: " << sizeof(*this) << std::endl;
}
private:
@@ -637,9 +636,9 @@ template<typename T, uint N = 4, typename Allocator = GuardedAllocator> class Ve
uint size = other.size();
uint capacity = size;
- if (size <= N) {
+ if (size <= InlineBufferCapacity) {
m_begin = this->small_buffer();
- capacity = N;
+ capacity = InlineBufferCapacity;
}
else {
m_begin = (T *)m_allocator.allocate_aligned(
@@ -661,8 +660,9 @@ template<typename T, uint N = 4, typename Allocator = GuardedAllocator> class Ve
* Use when the vector is used in the local scope of a function. It has a larger inline storage by
* default to make allocations less likely.
*/
-template<typename T, uint N = 20> using ScopedVector = Vector<T, N, GuardedAllocator>;
+template<typename T, uint InlineBufferCapacity = 20>
+using ScopedVector = Vector<T, InlineBufferCapacity, GuardedAllocator>;
} /* namespace BLI */
-#endif /* __BLI_VECTOR_H__ */
+#endif /* __BLI_VECTOR_HH__ */
diff --git a/source/blender/blenlib/BLI_vector_set.h b/source/blender/blenlib/BLI_vector_set.hh
index 99d955c60d8..f402f47c357 100644
--- a/source/blender/blenlib/BLI_vector_set.h
+++ b/source/blender/blenlib/BLI_vector_set.hh
@@ -14,8 +14,8 @@
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
-#ifndef __BLI_VECTOR_SET_H__
-#define __BLI_VECTOR_SET_H__
+#ifndef __BLI_VECTOR_SET_HH__
+#define __BLI_VECTOR_SET_HH__
/** \file
* \ingroup bli
@@ -25,9 +25,9 @@
* no deletes. The expected time to check if a value is in the VectorSet is O(1).
*/
-#include "BLI_hash_cxx.h"
-#include "BLI_open_addressing.h"
-#include "BLI_vector.h"
+#include "BLI_hash.hh"
+#include "BLI_open_addressing.hh"
+#include "BLI_vector.hh"
namespace BLI {
@@ -76,7 +76,7 @@ template<typename T, typename Allocator = GuardedAllocator> class VectorSet {
return m_value == IS_DUMMY;
}
- bool has_value(const T &value, const Vector<T> &elements) const
+ bool has_value(const T &value, const T *elements) const
{
return this->is_set() && elements[this->index()] == value;
}
@@ -112,12 +112,14 @@ template<typename T, typename Allocator = GuardedAllocator> class VectorSet {
using ArrayType = OpenAddressingArray<Slot, 4, Allocator>;
ArrayType m_array;
- Vector<T, 4, Allocator> m_elements;
+
+ /* The capacity of the array should always be at least m_array.slots_usable(). */
+ T *m_elements = nullptr;
public:
VectorSet()
{
- BLI_assert(m_array.slots_usable() <= m_elements.capacity());
+ m_elements = this->allocate_elements_array(m_array.slots_usable());
}
VectorSet(ArrayRef<T> values) : VectorSet()
@@ -135,6 +137,43 @@ template<typename T, typename Allocator = GuardedAllocator> class VectorSet {
this->add_multiple(values);
}
+ VectorSet(const VectorSet &other) : m_array(other.m_array)
+ {
+ m_elements = this->allocate_elements_array(m_array.slots_usable());
+ uninitialized_copy_n(other.m_elements, m_array.slots_set(), m_elements);
+ }
+
+ VectorSet(VectorSet &&other) : m_array(std::move(other.m_array)), m_elements(other.m_elements)
+ {
+ other.m_elements = other.allocate_elements_array(other.m_array.slots_usable());
+ }
+
+ ~VectorSet()
+ {
+ destruct_n(m_elements, this->size());
+ this->deallocate_elements_array(m_elements);
+ }
+
+ VectorSet &operator=(const VectorSet &other)
+ {
+ if (this == &other) {
+ return *this;
+ }
+ this->~VectorSet();
+ new (this) VectorSet(other);
+ return *this;
+ }
+
+ VectorSet &operator=(VectorSet &&other)
+ {
+ if (this == &other) {
+ return *this;
+ }
+ this->~VectorSet();
+ new (this) VectorSet(std::move(other));
+ return *this;
+ }
+
/**
* Allocate memory such that at least min_usable_slots can be added without having to grow again.
*/
@@ -203,17 +242,17 @@ template<typename T, typename Allocator = GuardedAllocator> class VectorSet {
BLI_assert(this->contains(value));
ITER_SLOTS_BEGIN (value, m_array, , slot) {
if (slot.has_value(value, m_elements)) {
- uint old_index = m_elements.size() - 1;
+ uint old_index = this->size() - 1;
uint new_index = slot.index();
- m_elements.remove_and_reorder(new_index);
+ if (new_index < old_index) {
+ m_elements[new_index] = std::move(m_elements[old_index]);
+ this->update_slot_index(m_elements[new_index], old_index, new_index);
+ }
+
+ destruct(m_elements + old_index);
slot.set_dummy();
m_array.update__set_to_dummy();
-
- if (old_index != new_index) {
- T &moved_value = m_elements[new_index];
- this->update_slot_index(moved_value, old_index, new_index);
- }
return;
}
}
@@ -226,11 +265,12 @@ template<typename T, typename Allocator = GuardedAllocator> class VectorSet {
T pop()
{
BLI_assert(this->size() > 0);
- T value = m_elements.pop_last();
- uint old_index = m_elements.size();
+ uint index_to_pop = this->size() - 1;
+ T value = std::move(m_elements[index_to_pop]);
+ destruct(m_elements + index_to_pop);
ITER_SLOTS_BEGIN (value, m_array, , slot) {
- if (slot.has_index(old_index)) {
+ if (slot.has_index(index_to_pop)) {
slot.set_dummy();
m_array.update__set_to_dummy();
return value;
@@ -277,18 +317,24 @@ template<typename T, typename Allocator = GuardedAllocator> class VectorSet {
return m_array.slots_set();
}
+ bool is_empty() const
+ {
+ return this->size() == 0;
+ }
+
const T *begin() const
{
- return m_elements.begin();
+ return m_elements;
}
const T *end() const
{
- return m_elements.end();
+ return m_elements + this->size();
}
const T &operator[](uint index) const
{
+ BLI_assert(index <= this->size());
return m_elements[index];
}
@@ -299,7 +345,7 @@ template<typename T, typename Allocator = GuardedAllocator> class VectorSet {
operator ArrayRef<T>() const
{
- return m_elements;
+ return ArrayRef<T>(m_elements, this->size());
}
void print_stats() const
@@ -326,9 +372,9 @@ template<typename T, typename Allocator = GuardedAllocator> class VectorSet {
template<typename ForwardT> void add_new_in_slot(Slot &slot, ForwardT &&value)
{
- uint index = m_elements.size();
+ uint index = this->size();
slot.set_index(index);
- m_elements.append_unchecked(std::forward<ForwardT>(value));
+ new (m_elements + index) T(std::forward<ForwardT>(value));
m_array.update__empty_to_set();
}
@@ -341,14 +387,20 @@ template<typename T, typename Allocator = GuardedAllocator> class VectorSet {
BLI_NOINLINE void grow(uint min_usable_slots)
{
+ uint size = this->size();
+
ArrayType new_array = m_array.init_reserved(min_usable_slots);
+ T *new_elements = this->allocate_elements_array(new_array.slots_usable());
- for (uint i = 0; i < m_elements.size(); i++) {
+ for (uint i : IndexRange(size)) {
this->add_after_grow(i, new_array);
}
+ uninitialized_relocate_n(m_elements, size, new_elements);
+ this->deallocate_elements_array(m_elements);
+
m_array = std::move(new_array);
- m_elements.reserve(m_array.slots_usable());
+ m_elements = new_elements;
}
void add_after_grow(uint index, ArrayType &new_array)
@@ -365,15 +417,15 @@ template<typename T, typename Allocator = GuardedAllocator> class VectorSet {
float compute_average_collisions() const
{
- if (m_elements.size() == 0) {
+ if (this->size() == 0) {
return 0.0f;
}
uint collisions_sum = 0;
- for (const T &value : m_elements) {
+ for (const T &value : this->as_ref()) {
collisions_sum += this->count_collisions(value);
}
- return (float)collisions_sum / (float)m_elements.size();
+ return (float)collisions_sum / (float)this->size();
}
uint count_collisions(const T &value) const
@@ -415,6 +467,16 @@ template<typename T, typename Allocator = GuardedAllocator> class VectorSet {
}
ITER_SLOTS_END;
}
+
+ T *allocate_elements_array(uint size)
+ {
+ return (T *)m_array.allocator().allocate_aligned((uint)sizeof(T) * size, alignof(T), __func__);
+ }
+
+ void deallocate_elements_array(T *elements)
+ {
+ m_array.allocator().deallocate(elements);
+ }
};
#undef ITER_SLOTS_BEGIN
@@ -422,4 +484,4 @@ template<typename T, typename Allocator = GuardedAllocator> class VectorSet {
} // namespace BLI
-#endif /* __BLI_VECTOR_SET_H__ */
+#endif /* __BLI_VECTOR_SET_HH__ */
diff --git a/source/blender/blenlib/CMakeLists.txt b/source/blender/blenlib/CMakeLists.txt
index 5f5145cab70..7757b838afe 100644
--- a/source/blender/blenlib/CMakeLists.txt
+++ b/source/blender/blenlib/CMakeLists.txt
@@ -64,6 +64,7 @@ set(SRC
intern/buffer.c
intern/convexhull_2d.c
intern/delaunay_2d.c
+ intern/dot_export.cc
intern/dynlib.c
intern/easing.c
intern/edgehash.c
@@ -118,10 +119,15 @@ set(SRC
intern/string_utf8.c
intern/string_utils.c
intern/system.c
- intern/task.c
+ intern/task_graph.cc
+ intern/task_iterator.c
+ intern/task_pool.cc
+ intern/task_range.cc
+ intern/task_scheduler.cc
intern/threads.c
intern/time.c
intern/timecode.c
+ intern/timeit.cc
intern/uvproject.c
intern/voronoi_2d.c
intern/voxel.c
@@ -133,16 +139,16 @@ set(SRC
intern/list_sort_impl.h
-
BLI_alloca.h
- BLI_allocator.h
+ BLI_allocator.hh
BLI_args.h
BLI_array.h
- BLI_array_cxx.h
- BLI_array_ref.h
+ BLI_array.hh
+ BLI_array_ref.hh
BLI_array_store.h
BLI_array_store_utils.h
BLI_array_utils.h
+ BLI_asan.h
BLI_assert.h
BLI_astar.h
BLI_bitmap.h
@@ -150,6 +156,7 @@ set(SRC
BLI_blenlib.h
BLI_boxpack_2d.h
BLI_buffer.h
+ BLI_color.hh
BLI_compiler_attrs.h
BLI_compiler_compat.h
BLI_compiler_typecheck.h
@@ -158,6 +165,8 @@ set(SRC
BLI_delaunay_2d.h
BLI_dial_2d.h
BLI_dlrbTree.h
+ BLI_dot_export.hh
+ BLI_dot_export_attribute_enums.hh
BLI_dynlib.h
BLI_dynstr.h
BLI_easing.h
@@ -167,17 +176,20 @@ set(SRC
BLI_expr_pylike_eval.h
BLI_fileops.h
BLI_fileops_types.h
+ BLI_float2.hh
+ BLI_float3.hh
+ BLI_float4x4.hh
BLI_fnmatch.h
BLI_ghash.h
BLI_gsqueue.h
BLI_hash.h
- BLI_hash_cxx.h
+ BLI_hash.hh
BLI_hash_md5.h
BLI_hash_mm2a.h
BLI_hash_mm3.h
BLI_heap.h
BLI_heap_simple.h
- BLI_index_range.h
+ BLI_index_range.hh
BLI_iterator.h
BLI_jitter_2d.h
BLI_kdopbvh.h
@@ -189,8 +201,8 @@ set(SRC
BLI_linklist_lockfree.h
BLI_linklist_stack.h
BLI_listbase.h
- BLI_listbase_wrapper.h
- BLI_map.h
+ BLI_listbase_wrapper.hh
+ BLI_map.hh
BLI_math.h
BLI_math_base.h
BLI_math_bits.h
@@ -208,11 +220,11 @@ set(SRC
BLI_memblock.h
BLI_memiter.h
BLI_memory_utils.h
- BLI_memory_utils_cxx.h
+ BLI_memory_utils.hh
BLI_mempool.h
BLI_noise.h
- BLI_open_addressing.h
- BLI_optional.h
+ BLI_open_addressing.hh
+ BLI_optional.hh
BLI_path_util.h
BLI_polyfill_2d.h
BLI_polyfill_2d_beautify.h
@@ -220,17 +232,17 @@ set(SRC
BLI_rand.h
BLI_rect.h
BLI_scanfill.h
- BLI_set.h
+ BLI_set.hh
BLI_smallhash.h
BLI_sort.h
BLI_sort_utils.h
BLI_stack.h
- BLI_stack_cxx.h
+ BLI_stack.hh
BLI_strict_flags.h
BLI_string.h
BLI_string_cursor_utf8.h
- BLI_string_map.h
- BLI_string_ref.h
+ BLI_string_map.hh
+ BLI_string_ref.hh
BLI_string_utf8.h
BLI_string_utils.h
BLI_sys_types.h
@@ -238,15 +250,16 @@ set(SRC
BLI_task.h
BLI_threads.h
BLI_timecode.h
+ BLI_timeit.hh
BLI_timer.h
BLI_utildefines.h
BLI_utildefines_iter.h
BLI_utildefines_stack.h
BLI_utildefines_variadic.h
- BLI_utility_mixins.h
+ BLI_utility_mixins.hh
BLI_uvproject.h
- BLI_vector.h
- BLI_vector_set.h
+ BLI_vector.hh
+ BLI_vector_set.hh
BLI_vfontdata.h
BLI_voronoi_2d.h
BLI_voxel.h
@@ -268,6 +281,18 @@ if(WITH_MEM_VALGRIND)
add_definitions(-DWITH_MEM_VALGRIND)
endif()
+if(WITH_TBB)
+ add_definitions(-DWITH_TBB)
+
+ list(APPEND INC_SYS
+ ${TBB_INCLUDE_DIRS}
+ )
+
+ list(APPEND LIB
+ ${TBB_LIBRARIES}
+ )
+endif()
+
if(WIN32)
list(APPEND INC
../../../intern/utfconv
@@ -275,6 +300,9 @@ if(WIN32)
list(APPEND LIB
bf_intern_utfconv
)
+ list(APPEND SRC
+ intern/system_win32.c
+ )
endif()
diff --git a/source/blender/blenlib/intern/BLI_filelist.c b/source/blender/blenlib/intern/BLI_filelist.c
index 2e402f0c063..26f1de33aa9 100644
--- a/source/blender/blenlib/intern/BLI_filelist.c
+++ b/source/blender/blenlib/intern/BLI_filelist.c
@@ -147,7 +147,7 @@ static void bli_builddir(struct BuildDirCtx *dir_ctx, const char *dirname)
char pardir[FILE_MAXDIR];
BLI_strncpy(pardir, dirname, sizeof(pardir));
- if (BLI_parent_dir(pardir) && (BLI_access(pardir, R_OK) == 0)) {
+ if (BLI_path_parent_dir(pardir) && (BLI_access(pardir, R_OK) == 0)) {
struct dirlink *const dlink = (struct dirlink *)malloc(sizeof(struct dirlink));
if (dlink != NULL) {
dlink->name = BLI_strdup(FILENAME_PARENT);
diff --git a/source/blender/blenlib/intern/BLI_ghash.c b/source/blender/blenlib/intern/BLI_ghash.c
index 0800027e520..09dbf18acd0 100644
--- a/source/blender/blenlib/intern/BLI_ghash.c
+++ b/source/blender/blenlib/intern/BLI_ghash.c
@@ -1056,7 +1056,7 @@ void BLI_ghash_flag_clear(GHash *gh, uint flag)
* #BLI_ghash_len(gh) times before becoming done.
*
* \param gh: The GHash to iterate over.
- * \return Pointer to a new DynStr.
+ * \return Pointer to a new iterator.
*/
GHashIterator *BLI_ghashIterator_new(GHash *gh)
{
diff --git a/source/blender/blenlib/intern/BLI_index_range.cc b/source/blender/blenlib/intern/BLI_index_range.cc
index 90eb4e4a89c..fefb6e6598e 100644
--- a/source/blender/blenlib/intern/BLI_index_range.cc
+++ b/source/blender/blenlib/intern/BLI_index_range.cc
@@ -17,10 +17,10 @@
#include <atomic>
#include <mutex>
-#include "BLI_array_cxx.h"
-#include "BLI_array_ref.h"
-#include "BLI_index_range.h"
-#include "BLI_vector.h"
+#include "BLI_array.hh"
+#include "BLI_array_ref.hh"
+#include "BLI_index_range.hh"
+#include "BLI_vector.hh"
namespace BLI {
diff --git a/source/blender/blenlib/intern/BLI_kdopbvh.c b/source/blender/blenlib/intern/BLI_kdopbvh.c
index 3a07cef7cac..da67baf0ead 100644
--- a/source/blender/blenlib/intern/BLI_kdopbvh.c
+++ b/source/blender/blenlib/intern/BLI_kdopbvh.c
@@ -719,10 +719,10 @@ static void non_recursive_bvh_div_nodes_task_cb(void *__restrict userdata,
refit_kdop_hull(data->tree, parent, parent_leafs_begin, parent_leafs_end);
split_axis = get_largest_axis(parent->bv);
- /* Save split axis (this can be used on raytracing to speedup the query time) */
+ /* Save split axis (this can be used on ray-tracing to speedup the query time) */
parent->main_axis = split_axis / 2;
- /* Split the childs along the split_axis, note: its not needed to sort the whole leafs array
+ /* Split the children along the split_axis, note: its not needed to sort the whole leafs array
* Only to assure that the elements are partitioned on a way that each child takes the elements
* it would take in case the whole array was sorted.
* Split_leafs takes care of that "sort" problem. */
diff --git a/source/blender/blenlib/intern/BLI_memarena.c b/source/blender/blenlib/intern/BLI_memarena.c
index fd2367aa992..fc381c22315 100644
--- a/source/blender/blenlib/intern/BLI_memarena.c
+++ b/source/blender/blenlib/intern/BLI_memarena.c
@@ -34,6 +34,7 @@
#include "MEM_guardedalloc.h"
+#include "BLI_asan.h"
#include "BLI_memarena.h"
#include "BLI_strict_flags.h"
#include "BLI_utildefines.h"
@@ -46,18 +47,6 @@
# define VALGRIND_MEMPOOL_ALLOC(pool, addr, size) UNUSED_VARS(pool, addr, size)
#endif
-/* Clang defines this. */
-#ifndef __has_feature
-# define __has_feature(x) 0
-#endif
-#if defined(__SANITIZE_ADDRESS__) || __has_feature(address_sanitizer)
-# include "sanitizer/asan_interface.h"
-#else
-/* Ensure return value is used. */
-# define ASAN_POISON_MEMORY_REGION(addr, size) (void)(0 && ((size) != 0 && (addr) != NULL))
-# define ASAN_UNPOISON_MEMORY_REGION(addr, size) (void)(0 && ((size) != 0 && (addr) != NULL))
-#endif
-
struct MemBuf {
struct MemBuf *next;
uchar data[0];
@@ -80,7 +69,7 @@ static void memarena_buf_free_all(struct MemBuf *mb)
struct MemBuf *mb_next = mb->next;
/* Unpoison memory because MEM_freeN might overwrite it. */
- ASAN_UNPOISON_MEMORY_REGION(mb, (uint)MEM_allocN_len(mb));
+ BLI_asan_unpoison(mb, (uint)MEM_allocN_len(mb));
MEM_freeN(mb);
mb = mb_next;
@@ -160,7 +149,7 @@ void *BLI_memarena_alloc(MemArena *ma, size_t size)
mb->next = ma->bufs;
ma->bufs = mb;
- ASAN_POISON_MEMORY_REGION(ma->curbuf, ma->cursize);
+ BLI_asan_poison(ma->curbuf, ma->cursize);
memarena_curbuf_align(ma);
}
@@ -171,7 +160,7 @@ void *BLI_memarena_alloc(MemArena *ma, size_t size)
VALGRIND_MEMPOOL_ALLOC(ma, ptr, size);
- ASAN_UNPOISON_MEMORY_REGION(ptr, size);
+ BLI_asan_unpoison(ptr, size);
return ptr;
}
@@ -215,7 +204,7 @@ void BLI_memarena_clear(MemArena *ma)
if (ma->use_calloc) {
memset(ma->curbuf, 0, curbuf_used);
}
- ASAN_POISON_MEMORY_REGION(ma->curbuf, ma->cursize);
+ BLI_asan_poison(ma->curbuf, ma->cursize);
}
VALGRIND_DESTROY_MEMPOOL(ma);
diff --git a/source/blender/blenlib/intern/BLI_memiter.c b/source/blender/blenlib/intern/BLI_memiter.c
index 017f08f8d35..1b9509e36d8 100644
--- a/source/blender/blenlib/intern/BLI_memiter.c
+++ b/source/blender/blenlib/intern/BLI_memiter.c
@@ -40,6 +40,7 @@
#include <stdlib.h>
#include <string.h>
+#include "BLI_asan.h"
#include "BLI_utildefines.h"
#include "BLI_memiter.h" /* own include */
@@ -50,18 +51,6 @@
/* TODO: Valgrind. */
-/* Clang defines this. */
-#ifndef __has_feature
-# define __has_feature(x) 0
-#endif
-#if defined(__SANITIZE_ADDRESS__) || __has_feature(address_sanitizer)
-# include "sanitizer/asan_interface.h"
-#else
-/* Ensure return value is used. */
-# define ASAN_POISON_MEMORY_REGION(addr, size) (void)(0 && ((size) != 0 && (addr) != NULL))
-# define ASAN_UNPOISON_MEMORY_REGION(addr, size) (void)(0 && ((size) != 0 && (addr) != NULL))
-#endif
-
typedef uintptr_t data_t;
typedef intptr_t offset_t;
@@ -114,7 +103,7 @@ static void memiter_set_rewind_offset(BLI_memiter *mi)
{
BLI_memiter_elem *elem = (BLI_memiter_elem *)mi->data_curr;
- ASAN_UNPOISON_MEMORY_REGION(elem, sizeof(BLI_memiter_elem));
+ BLI_asan_unpoison(elem, sizeof(BLI_memiter_elem));
elem->size = (offset_t)(((data_t *)mi->tail) - mi->data_curr);
BLI_assert(elem->size < 0);
@@ -197,14 +186,14 @@ void *BLI_memiter_alloc(BLI_memiter *mi, uint elem_size)
mi->data_last = chunk->data + (chunk_size - 1);
data_curr_next = mi->data_curr + (1 + data_offset);
- ASAN_POISON_MEMORY_REGION(chunk->data, chunk_size * sizeof(data_t));
+ BLI_asan_poison(chunk->data, chunk_size * sizeof(data_t));
}
BLI_assert(data_curr_next <= mi->data_last);
BLI_memiter_elem *elem = (BLI_memiter_elem *)mi->data_curr;
- ASAN_UNPOISON_MEMORY_REGION(elem, sizeof(BLI_memiter_elem) + elem_size);
+ BLI_asan_unpoison(elem, sizeof(BLI_memiter_elem) + elem_size);
elem->size = (offset_t)elem_size;
mi->data_curr = data_curr_next;
@@ -242,7 +231,7 @@ static void memiter_free_data(BLI_memiter *mi)
BLI_memiter_chunk *chunk_next = chunk->next;
/* Unpoison memory because MEM_freeN might overwrite it. */
- ASAN_UNPOISON_MEMORY_REGION(chunk, MEM_allocN_len(chunk));
+ BLI_asan_unpoison(chunk, MEM_allocN_len(chunk));
MEM_freeN(chunk);
chunk = chunk_next;
diff --git a/source/blender/blenlib/intern/array_store.c b/source/blender/blenlib/intern/array_store.c
index c87dbee0f0e..85fbe7ece0f 100644
--- a/source/blender/blenlib/intern/array_store.c
+++ b/source/blender/blenlib/intern/array_store.c
@@ -406,7 +406,7 @@ static void bchunk_list_decref(BArrayMemory *bs_mem, BChunkList *chunk_list)
static size_t bchunk_list_data_check(const BChunkList *chunk_list, const uchar *data)
{
size_t offset = 0;
- for (BChunkRef *cref = chunk_list->chunk_refs.first; cref; cref = cref->next) {
+ LISTBASE_FOREACH (BChunkRef *, cref, &chunk_list->chunk_refs) {
if (memcmp(&data[offset], cref->link->data, cref->link->data_len) != 0) {
return false;
}
@@ -1511,7 +1511,7 @@ void BLI_array_store_clear(BArrayStore *bs)
size_t BLI_array_store_calc_size_expanded_get(const BArrayStore *bs)
{
size_t size_accum = 0;
- for (const BArrayState *state = bs->states.first; state; state = state->next) {
+ LISTBASE_FOREACH (const BArrayState *, state, &bs->states) {
size_accum += state->chunk_list->total_size;
}
return size_accum;
@@ -1632,14 +1632,14 @@ void BLI_array_store_state_data_get(BArrayState *state, void *data)
{
#ifdef USE_PARANOID_CHECKS
size_t data_test_len = 0;
- for (BChunkRef *cref = state->chunk_list->chunk_refs.first; cref; cref = cref->next) {
+ LISTBASE_FOREACH (BChunkRef *, cref, &state->chunk_list->chunk_refs) {
data_test_len += cref->link->data_len;
}
BLI_assert(data_test_len == state->chunk_list->total_size);
#endif
uchar *data_step = (uchar *)data;
- for (BChunkRef *cref = state->chunk_list->chunk_refs.first; cref; cref = cref->next) {
+ LISTBASE_FOREACH (BChunkRef *, cref, &state->chunk_list->chunk_refs) {
BLI_assert(cref->link->users > 0);
memcpy(data_step, cref->link->data, cref->link->data_len);
data_step += cref->link->data_len;
@@ -1666,7 +1666,7 @@ void *BLI_array_store_state_data_get_alloc(BArrayState *state, size_t *r_data_le
static size_t bchunk_list_size(const BChunkList *chunk_list)
{
size_t total_size = 0;
- for (BChunkRef *cref = chunk_list->chunk_refs.first; cref; cref = cref->next) {
+ LISTBASE_FOREACH (BChunkRef *, cref, &chunk_list->chunk_refs) {
total_size += cref->link->data_len;
}
return total_size;
@@ -1679,7 +1679,7 @@ bool BLI_array_store_is_valid(BArrayStore *bs)
/* Check Length
* ------------ */
- for (BArrayState *state = bs->states.first; state; state = state->next) {
+ LISTBASE_FOREACH (BArrayState *, state, &bs->states) {
BChunkList *chunk_list = state->chunk_list;
if (!(bchunk_list_size(chunk_list) == chunk_list->total_size)) {
return false;
@@ -1692,7 +1692,7 @@ bool BLI_array_store_is_valid(BArrayStore *bs)
#ifdef USE_MERGE_CHUNKS
/* ensure we merge all chunks that could be merged */
if (chunk_list->total_size > bs->info.chunk_byte_size_min) {
- for (BChunkRef *cref = chunk_list->chunk_refs.first; cref; cref = cref->next) {
+ LISTBASE_FOREACH (BChunkRef *, cref, &chunk_list->chunk_refs) {
if (cref->link->data_len < bs->info.chunk_byte_size_min) {
return false;
}
@@ -1734,7 +1734,7 @@ bool BLI_array_store_is_valid(BArrayStore *bs)
GHash *chunk_map = BLI_ghash_ptr_new(__func__);
int totrefs = 0;
- for (BArrayState *state = bs->states.first; state; state = state->next) {
+ LISTBASE_FOREACH (BArrayState *, state, &bs->states) {
GHASH_PTR_ADD_USER(chunk_list_map, state->chunk_list);
}
GHASH_ITER (gh_iter, chunk_list_map) {
@@ -1753,7 +1753,7 @@ bool BLI_array_store_is_valid(BArrayStore *bs)
/* count chunk's */
GHASH_ITER (gh_iter, chunk_list_map) {
const struct BChunkList *chunk_list = BLI_ghashIterator_getKey(&gh_iter);
- for (const BChunkRef *cref = chunk_list->chunk_refs.first; cref; cref = cref->next) {
+ LISTBASE_FOREACH (const BChunkRef *, cref, &chunk_list->chunk_refs) {
GHASH_PTR_ADD_USER(chunk_map, cref->link);
totrefs += 1;
}
diff --git a/source/blender/blenlib/intern/boxpack_2d.c b/source/blender/blenlib/intern/boxpack_2d.c
index 6ecadeecec5..83866f766df 100644
--- a/source/blender/blenlib/intern/boxpack_2d.c
+++ b/source/blender/blenlib/intern/boxpack_2d.c
@@ -705,7 +705,7 @@ void BLI_box_pack_2d_fixedarea(ListBase *boxes, int width, int height, ListBase
LISTBASE_FOREACH_MUTABLE (FixedSizeBoxPack *, box, boxes) {
LISTBASE_FOREACH (FixedSizeBoxPack *, space, &spaces) {
/* Skip this space if it's too small. */
- if (box->w > space->w || box->h > space->w) {
+ if (box->w > space->w || box->h > space->h) {
continue;
}
diff --git a/source/blender/blenlib/intern/delaunay_2d.c b/source/blender/blenlib/intern/delaunay_2d.c
index 201c8a66d1a..4e0cd3a78dc 100644
--- a/source/blender/blenlib/intern/delaunay_2d.c
+++ b/source/blender/blenlib/intern/delaunay_2d.c
@@ -1264,6 +1264,7 @@ static void fill_crossdata_for_intersect(CDT_state *cdt,
se_vcva = t->next->next;
BLI_assert(se_vcva->vert == vc && se_vcva->next->vert == va);
BLI_assert(se_vcvb->vert == vc && se_vcvb->next->vert == vb);
+ UNUSED_VARS_NDEBUG(vc);
isect = isect_seg_seg_v2_lambda_mu_db(va->co, vb->co, curco, v2->co, &lambda, &mu);
#ifdef DEBUG_CDT
if (dbg_level > 0) {
@@ -1992,25 +1993,25 @@ typedef struct EdgeVertLambda {
/* For sorting first by edge id, then by lambda, then by vert id. */
static int evl_cmp(const void *a, const void *b)
{
- const EdgeVertLambda *sa = a;
+ const EdgeVertLambda *area = a;
const EdgeVertLambda *sb = b;
- if (sa->e_id < sb->e_id) {
+ if (area->e_id < sb->e_id) {
return -1;
}
- else if (sa->e_id > sb->e_id) {
+ else if (area->e_id > sb->e_id) {
return 1;
}
- else if (sa->lambda < sb->lambda) {
+ else if (area->lambda < sb->lambda) {
return -1;
}
- else if (sa->lambda > sb->lambda) {
+ else if (area->lambda > sb->lambda) {
return 1;
}
- else if (sa->v_id < sb->v_id) {
+ else if (area->v_id < sb->v_id) {
return -1;
}
- else if (sa->v_id > sb->v_id) {
+ else if (area->v_id > sb->v_id) {
return 1;
}
return 0;
diff --git a/source/blender/blenlib/intern/dot_export.cc b/source/blender/blenlib/intern/dot_export.cc
new file mode 100644
index 00000000000..96de4056fc5
--- /dev/null
+++ b/source/blender/blenlib/intern/dot_export.cc
@@ -0,0 +1,305 @@
+/*
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+
+#include <iomanip>
+
+#include "BLI_dot_export.hh"
+
+namespace BLI {
+namespace DotExport {
+
+/* Graph Building
+ ************************************************/
+
+Node &Graph::new_node(StringRef label)
+{
+ Node *node = new Node(*this);
+ m_nodes.append(std::unique_ptr<Node>(node));
+ m_top_level_nodes.add_new(node);
+ node->set_attribute("label", label);
+ return *node;
+}
+
+Cluster &Graph::new_cluster(StringRef label)
+{
+ Cluster *cluster = new Cluster(*this);
+ m_clusters.append(std::unique_ptr<Cluster>(cluster));
+ m_top_level_clusters.add_new(cluster);
+ cluster->set_attribute("label", label);
+ return *cluster;
+}
+
+UndirectedEdge &UndirectedGraph::new_edge(NodePort a, NodePort b)
+{
+ UndirectedEdge *edge = new UndirectedEdge(a, b);
+ m_edges.append(std::unique_ptr<UndirectedEdge>(edge));
+ return *edge;
+}
+
+DirectedEdge &DirectedGraph::new_edge(NodePort from, NodePort to)
+{
+ DirectedEdge *edge = new DirectedEdge(from, to);
+ m_edges.append(std::unique_ptr<DirectedEdge>(edge));
+ return *edge;
+}
+
+void Cluster::set_parent_cluster(Cluster *new_parent)
+{
+ if (m_parent == new_parent) {
+ return;
+ }
+ else if (m_parent == nullptr) {
+ m_graph.m_top_level_clusters.remove(this);
+ new_parent->m_children.add_new(this);
+ }
+ else if (new_parent == nullptr) {
+ m_parent->m_children.remove(this);
+ m_graph.m_top_level_clusters.add_new(this);
+ }
+ else {
+ m_parent->m_children.remove(this);
+ new_parent->m_children.add_new(this);
+ }
+ m_parent = new_parent;
+}
+
+void Node::set_parent_cluster(Cluster *cluster)
+{
+ if (m_cluster == cluster) {
+ return;
+ }
+ else if (m_cluster == nullptr) {
+ m_graph.m_top_level_nodes.remove(this);
+ cluster->m_nodes.add_new(this);
+ }
+ else if (cluster == nullptr) {
+ m_cluster->m_nodes.remove(this);
+ m_graph.m_top_level_nodes.add_new(this);
+ }
+ else {
+ m_cluster->m_nodes.remove(this);
+ cluster->m_nodes.add_new(this);
+ }
+ m_cluster = cluster;
+}
+
+/* Utility methods
+ **********************************************/
+
+void Graph::set_random_cluster_bgcolors()
+{
+ for (Cluster *cluster : m_top_level_clusters) {
+ cluster->set_random_cluster_bgcolors();
+ }
+}
+
+void Cluster::set_random_cluster_bgcolors()
+{
+ float hue = rand() / (float)RAND_MAX;
+ float staturation = 0.3f;
+ float value = 0.8f;
+ this->set_attribute("bgcolor", color_attr_from_hsv(hue, staturation, value));
+
+ for (Cluster *cluster : m_children) {
+ cluster->set_random_cluster_bgcolors();
+ }
+}
+
+/* Dot Generation
+ **********************************************/
+
+std::string DirectedGraph::to_dot_string() const
+{
+ std::stringstream ss;
+ ss << "digraph {\n";
+ this->export__declare_nodes_and_clusters(ss);
+ ss << "\n";
+
+ for (const std::unique_ptr<DirectedEdge> &edge : m_edges) {
+ edge->export__as_edge_statement(ss);
+ ss << "\n";
+ }
+
+ ss << "}\n";
+ return ss.str();
+}
+
+std::string UndirectedGraph::to_dot_string() const
+{
+ std::stringstream ss;
+ ss << "graph {\n";
+ this->export__declare_nodes_and_clusters(ss);
+ ss << "\n";
+
+ for (const std::unique_ptr<UndirectedEdge> &edge : m_edges) {
+ edge->export__as_edge_statement(ss);
+ ss << "\n";
+ }
+
+ ss << "}\n";
+ return ss.str();
+}
+
+void Graph::export__declare_nodes_and_clusters(std::stringstream &ss) const
+{
+ ss << "graph ";
+ m_attributes.export__as_bracket_list(ss);
+ ss << "\n\n";
+
+ for (Node *node : m_top_level_nodes) {
+ node->export__as_declaration(ss);
+ }
+
+ for (Cluster *cluster : m_top_level_clusters) {
+ cluster->export__declare_nodes_and_clusters(ss);
+ }
+}
+
+void Cluster::export__declare_nodes_and_clusters(std::stringstream &ss) const
+{
+ ss << "subgraph cluster_" << (uintptr_t)this << " {\n";
+
+ ss << "graph ";
+ m_attributes.export__as_bracket_list(ss);
+ ss << "\n\n";
+
+ for (Node *node : m_nodes) {
+ node->export__as_declaration(ss);
+ }
+
+ for (Cluster *cluster : m_children) {
+ cluster->export__declare_nodes_and_clusters(ss);
+ }
+
+ ss << "}\n";
+}
+
+void DirectedEdge::export__as_edge_statement(std::stringstream &ss) const
+{
+ m_a.to_dot_string(ss);
+ ss << " -> ";
+ m_b.to_dot_string(ss);
+ ss << " ";
+ m_attributes.export__as_bracket_list(ss);
+}
+
+void UndirectedEdge::export__as_edge_statement(std::stringstream &ss) const
+{
+ m_a.to_dot_string(ss);
+ ss << " -- ";
+ m_b.to_dot_string(ss);
+ ss << " ";
+ m_attributes.export__as_bracket_list(ss);
+}
+
+void AttributeList::export__as_bracket_list(std::stringstream &ss) const
+{
+ ss << "[";
+ m_attributes.foreach_item([&](StringRef key, StringRef value) {
+ if (StringRef(value).startswith("<")) {
+ /* Don't draw the quotes, this is an html-like value. */
+ ss << key << "=" << value << ", ";
+ }
+ else {
+ ss << key << "=\"" << value << "\", ";
+ }
+ });
+ ss << "]";
+}
+
+void Node::export__as_id(std::stringstream &ss) const
+{
+ ss << '"' << (uintptr_t)this << '"';
+}
+
+void Node::export__as_declaration(std::stringstream &ss) const
+{
+ this->export__as_id(ss);
+ ss << " ";
+ m_attributes.export__as_bracket_list(ss);
+ ss << "\n";
+}
+
+void NodePort::to_dot_string(std::stringstream &ss) const
+{
+ m_node->export__as_id(ss);
+ if (m_port_name.has_value()) {
+ ss << ":" << m_port_name.value();
+ }
+}
+
+std::string color_attr_from_hsv(float h, float s, float v)
+{
+ std::stringstream ss;
+ ss << std::setprecision(4) << h << ' ' << s << ' ' << v;
+ return ss.str();
+}
+
+NodeWithSocketsRef::NodeWithSocketsRef(Node &node,
+ StringRef name,
+ ArrayRef<std::string> input_names,
+ ArrayRef<std::string> output_names)
+ : m_node(&node)
+{
+ std::stringstream ss;
+
+ ss << "<<table border=\"0\" cellspacing=\"3\">";
+
+ /* Header */
+ ss << "<tr><td colspan=\"3\" align=\"center\"><b>";
+ ss << ((name.size() == 0) ? "No Name" : name);
+ ss << "</b></td></tr>";
+
+ /* Sockets */
+ uint socket_max_amount = std::max(input_names.size(), output_names.size());
+ for (uint i = 0; i < socket_max_amount; i++) {
+ ss << "<tr>";
+ if (i < input_names.size()) {
+ StringRef name = input_names[i];
+ if (name.size() == 0) {
+ name = "No Name";
+ }
+ ss << "<td align=\"left\" port=\"in" << i << "\">";
+ ss << name;
+ ss << "</td>";
+ }
+ else {
+ ss << "<td></td>";
+ }
+ ss << "<td></td>";
+ if (i < output_names.size()) {
+ StringRef name = output_names[i];
+ if (name.size() == 0) {
+ name = "No Name";
+ }
+ ss << "<td align=\"right\" port=\"out" << i << "\">";
+ ss << name;
+ ss << "</td>";
+ }
+ else {
+ ss << "<td></td>";
+ }
+ ss << "</tr>";
+ }
+
+ ss << "</table>>";
+
+ m_node->set_attribute("label", ss.str());
+ m_node->set_shape(Attr_shape::Rectangle);
+}
+
+} // namespace DotExport
+} // namespace BLI
diff --git a/source/blender/blenlib/intern/fileops.c b/source/blender/blenlib/intern/fileops.c
index da77046547c..b9133edcae3 100644
--- a/source/blender/blenlib/intern/fileops.c
+++ b/source/blender/blenlib/intern/fileops.c
@@ -492,7 +492,7 @@ static bool delete_recursive(const char *dir)
/* dir listing produces dir path without trailing slash... */
BLI_strncpy(path, fl->path, sizeof(path));
- BLI_add_slash(path);
+ BLI_path_slash_ensure(path);
if (delete_recursive(path)) {
err = true;
@@ -562,9 +562,9 @@ int BLI_move(const char *file, const char *to)
BLI_strncpy(str, to, sizeof(str));
/* points 'to' to a directory ? */
- if (BLI_last_slash(str) == (str + strlen(str) - 1)) {
- if (BLI_last_slash(file) != NULL) {
- strcat(str, BLI_last_slash(file) + 1);
+ if (BLI_path_slash_rfind(str) == (str + strlen(str) - 1)) {
+ if (BLI_path_slash_rfind(file) != NULL) {
+ strcat(str, BLI_path_slash_rfind(file) + 1);
}
}
@@ -594,9 +594,9 @@ int BLI_copy(const char *file, const char *to)
BLI_strncpy(str, to, sizeof(str));
/* points 'to' to a directory ? */
- if (BLI_last_slash(str) == (str + strlen(str) - 1)) {
- if (BLI_last_slash(file) != NULL) {
- strcat(str, BLI_last_slash(file) + 1);
+ if (BLI_path_slash_rfind(str) == (str + strlen(str) - 1)) {
+ if (BLI_path_slash_rfind(file) != NULL) {
+ strcat(str, BLI_path_slash_rfind(file) + 1);
}
}
@@ -638,7 +638,7 @@ bool BLI_dir_create_recursive(const char *dirname)
* blah1/blah2 (without slash) */
BLI_strncpy(tmp, dirname, sizeof(tmp));
- BLI_del_slash(tmp);
+ BLI_path_slash_rstrip(tmp);
/* check special case "c:\foo", don't try create "c:", harmless but prints an error below */
if (isalpha(tmp[0]) && (tmp[1] == ':') && tmp[2] == '\0') {
@@ -652,7 +652,7 @@ bool BLI_dir_create_recursive(const char *dirname)
return false;
}
- lslash = (char *)BLI_last_slash(tmp);
+ lslash = (char *)BLI_path_slash_rfind(tmp);
if (lslash) {
/* Split about the last slash and recurse */
@@ -723,7 +723,7 @@ static void join_dirfile_alloc(char **dst, size_t *alloc_len, const char *dir, c
static char *strip_last_slash(const char *dir)
{
char *result = BLI_strdup(dir);
- BLI_del_slash(result);
+ BLI_path_slash_rstrip(result);
return result;
}
@@ -1277,7 +1277,7 @@ static const char *check_destination(const char *file, const char *to)
size_t len = 0;
str = strip_last_slash(file);
- filename = BLI_last_slash(str);
+ filename = BLI_path_slash_rfind(str);
if (!filename) {
MEM_freeN(str);
@@ -1350,9 +1350,9 @@ bool BLI_dir_create_recursive(const char *dirname)
BLI_strncpy(tmp, dirname, size);
/* Avoids one useless recursion in case of '/foo/bar/' path... */
- BLI_del_slash(tmp);
+ BLI_path_slash_rstrip(tmp);
- lslash = (char *)BLI_last_slash(tmp);
+ lslash = (char *)BLI_path_slash_rfind(tmp);
if (lslash) {
/* Split about the last slash and recurse */
*lslash = 0;
diff --git a/source/blender/blenlib/intern/fnmatch.c b/source/blender/blenlib/intern/fnmatch.c
index 3df09976972..33fe34e7c24 100644
--- a/source/blender/blenlib/intern/fnmatch.c
+++ b/source/blender/blenlib/intern/fnmatch.c
@@ -27,8 +27,9 @@
# define _GNU_SOURCE 1
#endif
-#include <errno.h>
#include <ctype.h>
+#include <errno.h>
+
#include "BLI_fnmatch.h"
diff --git a/source/blender/blenlib/intern/lasso_2d.c b/source/blender/blenlib/intern/lasso_2d.c
index f1e9b1e655f..a01adf4fa6a 100644
--- a/source/blender/blenlib/intern/lasso_2d.c
+++ b/source/blender/blenlib/intern/lasso_2d.c
@@ -28,47 +28,47 @@
#include "BLI_lasso_2d.h" /* own include */
-void BLI_lasso_boundbox(rcti *rect, const int mcords[][2], const unsigned int moves)
+void BLI_lasso_boundbox(rcti *rect, const int mcoords[][2], const unsigned int mcoords_len)
{
unsigned int a;
- rect->xmin = rect->xmax = mcords[0][0];
- rect->ymin = rect->ymax = mcords[0][1];
+ rect->xmin = rect->xmax = mcoords[0][0];
+ rect->ymin = rect->ymax = mcoords[0][1];
- for (a = 1; a < moves; a++) {
- if (mcords[a][0] < rect->xmin) {
- rect->xmin = mcords[a][0];
+ for (a = 1; a < mcoords_len; a++) {
+ if (mcoords[a][0] < rect->xmin) {
+ rect->xmin = mcoords[a][0];
}
- else if (mcords[a][0] > rect->xmax) {
- rect->xmax = mcords[a][0];
+ else if (mcoords[a][0] > rect->xmax) {
+ rect->xmax = mcoords[a][0];
}
- if (mcords[a][1] < rect->ymin) {
- rect->ymin = mcords[a][1];
+ if (mcoords[a][1] < rect->ymin) {
+ rect->ymin = mcoords[a][1];
}
- else if (mcords[a][1] > rect->ymax) {
- rect->ymax = mcords[a][1];
+ else if (mcoords[a][1] > rect->ymax) {
+ rect->ymax = mcoords[a][1];
}
}
}
-bool BLI_lasso_is_point_inside(const int mcords[][2],
- const unsigned int moves,
+bool BLI_lasso_is_point_inside(const int mcoords[][2],
+ const unsigned int mcoords_len,
const int sx,
const int sy,
const int error_value)
{
- if (sx == error_value || moves == 0) {
+ if (sx == error_value || mcoords_len == 0) {
return false;
}
else {
int pt[2] = {sx, sy};
- return isect_point_poly_v2_int(pt, mcords, moves, true);
+ return isect_point_poly_v2_int(pt, mcoords, mcoords_len, true);
}
}
/* edge version for lasso select. we assume boundbox check was done */
-bool BLI_lasso_is_edge_inside(const int mcords[][2],
- const unsigned int moves,
+bool BLI_lasso_is_edge_inside(const int mcoords[][2],
+ const unsigned int mcoords_len,
int x0,
int y0,
int x1,
@@ -76,27 +76,27 @@ bool BLI_lasso_is_edge_inside(const int mcords[][2],
const int error_value)
{
- if (x0 == error_value || x1 == error_value || moves == 0) {
+ if (x0 == error_value || x1 == error_value || mcoords_len == 0) {
return false;
}
const int v1[2] = {x0, y0}, v2[2] = {x1, y1};
/* check points in lasso */
- if (BLI_lasso_is_point_inside(mcords, moves, v1[0], v1[1], error_value)) {
+ if (BLI_lasso_is_point_inside(mcoords, mcoords_len, v1[0], v1[1], error_value)) {
return true;
}
- if (BLI_lasso_is_point_inside(mcords, moves, v2[0], v2[1], error_value)) {
+ if (BLI_lasso_is_point_inside(mcoords, mcoords_len, v2[0], v2[1], error_value)) {
return true;
}
/* no points in lasso, so we have to intersect with lasso edge */
- if (isect_seg_seg_v2_int(mcords[0], mcords[moves - 1], v1, v2) > 0) {
+ if (isect_seg_seg_v2_int(mcoords[0], mcoords[mcoords_len - 1], v1, v2) > 0) {
return true;
}
- for (unsigned int a = 0; a < moves - 1; a++) {
- if (isect_seg_seg_v2_int(mcords[a], mcords[a + 1], v1, v2) > 0) {
+ for (unsigned int a = 0; a < mcoords_len - 1; a++) {
+ if (isect_seg_seg_v2_int(mcoords[a], mcoords[a + 1], v1, v2) > 0) {
return true;
}
}
diff --git a/source/blender/blenlib/intern/math_base_inline.c b/source/blender/blenlib/intern/math_base_inline.c
index c4b68e9164c..1b388dcf11f 100644
--- a/source/blender/blenlib/intern/math_base_inline.c
+++ b/source/blender/blenlib/intern/math_base_inline.c
@@ -38,6 +38,10 @@
#include "BLI_math_base.h"
+#ifdef __cplusplus
+extern "C" {
+#endif
+
/* copied from BLI_utildefines.h */
#ifdef __GNUC__
# define UNLIKELY(x) __builtin_expect(!!(x), 0)
@@ -356,6 +360,14 @@ MINLINE int divide_floor_i(int a, int b)
}
/**
+ * Integer division that returns the ceiling, instead of flooring like normal C division.
+ */
+MINLINE uint divide_ceil_u(uint a, uint b)
+{
+ return (a + b - 1) / b;
+}
+
+/**
* modulo that handles negative numbers, works the same as Python's.
*/
MINLINE int mod_i(int i, int n)
@@ -524,6 +536,15 @@ MINLINE size_t max_zz(size_t a, size_t b)
return (b < a) ? a : b;
}
+MINLINE char min_cc(char a, char b)
+{
+ return (a < b) ? a : b;
+}
+MINLINE char max_cc(char a, char b)
+{
+ return (b < a) ? a : b;
+}
+
MINLINE int clamp_i(int value, int min, int max)
{
return min_ii(max_ii(value, min), max);
@@ -784,4 +805,8 @@ MINLINE unsigned char unit_ushort_to_uchar(unsigned short val)
} \
((void)0)
+#ifdef __cplusplus
+}
+#endif
+
#endif /* __MATH_BASE_INLINE_C__ */
diff --git a/source/blender/blenlib/intern/math_color.c b/source/blender/blenlib/intern/math_color.c
index cc29ebe4f20..c1f7b0c2907 100644
--- a/source/blender/blenlib/intern/math_color.c
+++ b/source/blender/blenlib/intern/math_color.c
@@ -91,6 +91,7 @@ void rgb_to_yuv(float r, float g, float b, float *ly, float *lu, float *lv, int
break;
case BLI_YUV_ITU_BT709:
default:
+ BLI_assert(colorspace == BLI_YUV_ITU_BT709);
y = 0.2126f * r + 0.7152f * g + 0.0722f * b;
u = -0.09991f * r - 0.33609f * g + 0.436f * b;
v = 0.615f * r - 0.55861f * g - 0.05639f * b;
@@ -113,6 +114,8 @@ void yuv_to_rgb(float y, float u, float v, float *lr, float *lg, float *lb, int
b = y + 2.032f * u;
break;
case BLI_YUV_ITU_BT709:
+ default:
+ BLI_assert(colorspace == BLI_YUV_ITU_BT709);
r = y + 1.28033f * v;
g = y - 0.21482f * u - 0.38059f * v;
b = y + 2.12798f * u;
diff --git a/source/blender/blenlib/intern/math_geom.c b/source/blender/blenlib/intern/math_geom.c
index 4c0d7e08a3c..e7c1fc8c2d9 100644
--- a/source/blender/blenlib/intern/math_geom.c
+++ b/source/blender/blenlib/intern/math_geom.c
@@ -2379,7 +2379,10 @@ bool isect_tri_tri_epsilon_v3(const float t_a0[3],
if (UNLIKELY(edge_fac == -1.0f)) {
/* pass */
}
- else if (edge_fac > 0.0f && edge_fac < 1.0f) {
+ /* Important to include 0.0f and 1.0f as one of the triangles vertices may be placed
+ * exactly on the plane. In this case both it's edges will have a factor of 0 or 1,
+ * but not be going through the plane. See T73566. */
+ else if (edge_fac >= 0.0f && edge_fac <= 1.0f) {
float ix_tri[3];
float span_fac;
@@ -4217,7 +4220,19 @@ static float mean_value_half_tan_v2(const struct Float2_Len *d_curr,
void interp_weights_poly_v3(float *w, float v[][3], const int n, const float co[3])
{
- const float eps = 1e-5f; /* take care, low values cause [#36105] */
+ /* Before starting to calculate the weight, we need to figure out the floating point precision we
+ * can expect from the supplied data. */
+ float max_value = 0;
+
+ for (int i = 0; i < n; i++) {
+ max_value = max_ff(max_value, fabsf(v[i][0] - co[0]));
+ max_value = max_ff(max_value, fabsf(v[i][1] - co[1]));
+ max_value = max_ff(max_value, fabsf(v[i][2] - co[2]));
+ }
+
+ /* These to values we derived by empirically testing different values that works for the test
+ * files in D7772. */
+ const float eps = 16.0f * FLT_EPSILON * max_value;
const float eps_sq = eps * eps;
const float *v_curr, *v_next;
float ht_prev, ht; /* half tangents */
@@ -4290,8 +4305,20 @@ void interp_weights_poly_v3(float *w, float v[][3], const int n, const float co[
void interp_weights_poly_v2(float *w, float v[][2], const int n, const float co[2])
{
- const float eps = 1e-5f; /* take care, low values cause [#36105] */
+ /* Before starting to calculate the weight, we need to figure out the floating point precision we
+ * can expect from the supplied data. */
+ float max_value = 0;
+
+ for (int i = 0; i < n; i++) {
+ max_value = max_ff(max_value, fabsf(v[i][0] - co[0]));
+ max_value = max_ff(max_value, fabsf(v[i][1] - co[1]));
+ }
+
+ /* These to values we derived by empirically testing different values that works for the test
+ * files in D7772. */
+ const float eps = 16.0f * FLT_EPSILON * max_value;
const float eps_sq = eps * eps;
+
const float *v_curr, *v_next;
float ht_prev, ht; /* half tangents */
float totweight = 0.0f;
diff --git a/source/blender/blenlib/intern/math_solvers.c b/source/blender/blenlib/intern/math_solvers.c
index 235589abdab..cda3d9b66a2 100644
--- a/source/blender/blenlib/intern/math_solvers.c
+++ b/source/blender/blenlib/intern/math_solvers.c
@@ -55,7 +55,7 @@ bool BLI_eigen_solve_selfadjoint_m3(const float m3[3][3],
}
/**
- * \brief Compute the SVD (Singular Values Decomposition) of given 3D matrix (m3 = USV*).
+ * \brief Compute the SVD (Singular Values Decomposition) of given 3D matrix (m3 = USV*).
*
* \param m3: the matrix to decompose.
* \return r_U the computed left singular vector of \a m3 (NULL if not needed).
diff --git a/source/blender/blenlib/intern/math_vector.c b/source/blender/blenlib/intern/math_vector.c
index 5919b7e1dd6..6ec7c960d6b 100644
--- a/source/blender/blenlib/intern/math_vector.c
+++ b/source/blender/blenlib/intern/math_vector.c
@@ -778,7 +778,7 @@ void bisect_v3_v3v3v3(float out[3], const float v1[3], const float v2[3], const
* <pre>
* v
* + ^
- * \ |
+ * \ |
* \|
* + normal: axis of reflection
* /
@@ -949,6 +949,35 @@ void print_vn(const char *str, const float v[], const int n)
printf("\n");
}
+void minmax_v4v4_v4(float min[4], float max[4], const float vec[4])
+{
+ if (min[0] > vec[0]) {
+ min[0] = vec[0];
+ }
+ if (min[1] > vec[1]) {
+ min[1] = vec[1];
+ }
+ if (min[2] > vec[2]) {
+ min[2] = vec[2];
+ }
+ if (min[3] > vec[3]) {
+ min[3] = vec[3];
+ }
+
+ if (max[0] < vec[0]) {
+ max[0] = vec[0];
+ }
+ if (max[1] < vec[1]) {
+ max[1] = vec[1];
+ }
+ if (max[2] < vec[2]) {
+ max[2] = vec[2];
+ }
+ if (max[3] < vec[3]) {
+ max[3] = vec[3];
+ }
+}
+
void minmax_v3v3_v3(float min[3], float max[3], const float vec[3])
{
if (min[0] > vec[0]) {
diff --git a/source/blender/blenlib/intern/math_vector_inline.c b/source/blender/blenlib/intern/math_vector_inline.c
index d2c55233653..ca405907bdd 100644
--- a/source/blender/blenlib/intern/math_vector_inline.c
+++ b/source/blender/blenlib/intern/math_vector_inline.c
@@ -123,6 +123,27 @@ MINLINE void copy_v4_v4_uchar(unsigned char r[4], const unsigned char a[4])
r[3] = a[3];
}
+MINLINE void copy_v2_uchar(unsigned char r[2], const unsigned char a)
+{
+ r[0] = a;
+ r[1] = a;
+}
+
+MINLINE void copy_v3_uchar(unsigned char r[3], const unsigned char a)
+{
+ r[0] = a;
+ r[1] = a;
+ r[2] = a;
+}
+
+MINLINE void copy_v4_uchar(unsigned char r[4], const unsigned char a)
+{
+ r[0] = a;
+ r[1] = a;
+ r[2] = a;
+ r[3] = a;
+}
+
/* char */
MINLINE void copy_v2_v2_char(char r[2], const char a[2])
{
diff --git a/source/blender/blenlib/intern/noise.c b/source/blender/blenlib/intern/noise.c
index 229a06948c2..42b5ba28f5a 100644
--- a/source/blender/blenlib/intern/noise.c
+++ b/source/blender/blenlib/intern/noise.c
@@ -23,6 +23,7 @@
#include <math.h>
+#include "BLI_compiler_compat.h"
#include "BLI_noise.h"
/* local */
@@ -264,17 +265,17 @@ static const float hashvectf[768] = {
/* IMPROVED PERLIN NOISE */
/**************************/
-static float lerp(float t, float a, float b)
+BLI_INLINE float lerp(float t, float a, float b)
{
return (a + t * (b - a));
}
-static float npfade(float t)
+BLI_INLINE float npfade(float t)
{
return (t * t * t * (t * (t * 6.0f - 15.0f) + 10.0f));
}
-static float grad(int hash_val, float x, float y, float z)
+BLI_INLINE float grad(int hash_val, float x, float y, float z)
{
int h = hash_val & 15; /* CONVERT LO 4 BITS OF HASH CODE */
float u = h < 8 ? x : y; /* INTO 12 GRADIENT DIRECTIONS. */
diff --git a/source/blender/blenlib/intern/path_util.c b/source/blender/blenlib/intern/path_util.c
index 0bb2ba5859b..2f51b66725b 100644
--- a/source/blender/blenlib/intern/path_util.c
+++ b/source/blender/blenlib/intern/path_util.c
@@ -80,12 +80,12 @@ static bool BLI_path_is_abs(const char *name);
* or from dot if no digits.
* \param r_num_len: Optional to return number of digits found.
*/
-int BLI_stringdec(const char *string, char *head, char *tail, ushort *r_num_len)
+int BLI_path_sequence_decode(const char *string, char *head, char *tail, ushort *r_num_len)
{
uint nums = 0, nume = 0;
int i;
bool found_digit = false;
- const char *const lslash = BLI_last_slash(string);
+ const char *const lslash = BLI_path_slash_rfind(string);
const uint string_len = strlen(string);
const uint lslash_len = lslash != NULL ? (int)(lslash - string) : 0;
uint name_end = string_len;
@@ -151,7 +151,7 @@ int BLI_stringdec(const char *string, char *head, char *tail, ushort *r_num_len)
* Returns in area pointed to by string a string of the form "<head><pic><tail>", where pic
* is formatted as numlen digits with leading zeroes.
*/
-void BLI_stringenc(
+void BLI_path_sequence_encode(
char *string, const char *head, const char *tail, unsigned short numlen, int pic)
{
sprintf(string, "%s%.*d%s", head, numlen, MAX2(0, pic), tail);
@@ -170,7 +170,7 @@ static int BLI_path_unc_prefix_len(const char *path); /* defined below in same f
*
* \note \a path isn't protected for max string names...
*/
-void BLI_cleanup_path(const char *relabase, char *path)
+void BLI_path_normalize(const char *relabase, char *path)
{
ptrdiff_t a;
char *start, *eind;
@@ -263,10 +263,10 @@ void BLI_cleanup_path(const char *relabase, char *path)
/**
* Cleanup filepath ensuring a trailing slash.
*/
-void BLI_cleanup_dir(const char *relabase, char *dir)
+void BLI_path_normalize_dir(const char *relabase, char *dir)
{
- BLI_cleanup_path(relabase, dir);
- BLI_add_slash(dir);
+ BLI_path_normalize(relabase, dir);
+ BLI_path_slash_ensure(dir);
}
/**
@@ -381,8 +381,8 @@ bool BLI_path_make_safe(char *path)
}
#endif
- for (curr_slash = (char *)BLI_first_slash(curr_path); curr_slash;
- curr_slash = (char *)BLI_first_slash(curr_path)) {
+ for (curr_slash = (char *)BLI_path_slash_find(curr_path); curr_slash;
+ curr_slash = (char *)BLI_path_slash_find(curr_path)) {
const char backup = *curr_slash;
*curr_slash = '\0';
if (!skip_first && (*curr_path != '\0') && BLI_filename_make_safe(curr_path)) {
@@ -494,14 +494,14 @@ static void BLI_path_unc_to_short(wchar_t *unc)
}
}
-void BLI_cleanup_unc(char *path, int maxlen)
+void BLI_path_normalize_unc(char *path, int maxlen)
{
wchar_t *tmp_16 = alloc_utf16_from_8(path, 1);
- BLI_cleanup_unc_16(tmp_16);
+ BLI_path_normalize_unc_16(tmp_16);
conv_utf_16_to_8(tmp_16, path, maxlen);
}
-void BLI_cleanup_unc_16(wchar_t *path_16)
+void BLI_path_normalize_unc_16(wchar_t *path_16)
{
BLI_path_unc_to_short(path_16);
BLI_path_add_slash_to_share(path_16);
@@ -578,11 +578,11 @@ void BLI_path_rel(char *file, const char *relfile)
BLI_str_replace_char(file + BLI_path_unc_prefix_len(file), '\\', '/');
/* remove /./ which confuse the following slash counting... */
- BLI_cleanup_path(NULL, file);
- BLI_cleanup_path(NULL, temp);
+ BLI_path_normalize(NULL, file);
+ BLI_path_normalize(NULL, temp);
/* the last slash in the file indicates where the path part ends */
- lslash = BLI_last_slash(temp);
+ lslash = BLI_path_slash_rfind(temp);
if (lslash) {
/* find the prefix of the filename that is equal for both filenames.
@@ -701,13 +701,13 @@ bool BLI_path_suffix(char *string, size_t maxlen, const char *suffix, const char
* Replaces path with the path of its parent directory, returning true if
* it was able to find a parent directory within the pathname.
*/
-bool BLI_parent_dir(char *path)
+bool BLI_path_parent_dir(char *path)
{
const char parent_dir[] = {'.', '.', SEP, '\0'}; /* "../" or "..\\" */
char tmp[FILE_MAX + 4];
BLI_join_dirfile(tmp, sizeof(tmp), path, parent_dir);
- BLI_cleanup_path(NULL, tmp); /* does all the work of normalizing the path for us */
+ BLI_path_normalize(NULL, tmp); /* does all the work of normalizing the path for us */
if (!BLI_path_extension_check(tmp, parent_dir)) {
strcpy(path, tmp); /* We assume pardir is always shorter... */
@@ -722,12 +722,12 @@ bool BLI_parent_dir(char *path)
* Strips off nonexistent (or non-accessible) subdirectories from the end of *dir,
* leaving the path of the lowest-level directory that does exist and we can read.
*/
-bool BLI_parent_dir_until_exists(char *dir)
+bool BLI_path_parent_dir_until_exists(char *dir)
{
bool valid_path = true;
/* Loop as long as cur path is not a dir, and we can get a parent path. */
- while ((BLI_access(dir, R_OK) != 0) && (valid_path = BLI_parent_dir(dir))) {
+ while ((BLI_access(dir, R_OK) != 0) && (valid_path = BLI_path_parent_dir(dir))) {
/* pass */
}
return (valid_path && dir[0]);
@@ -777,7 +777,7 @@ static bool stringframe_chars(const char *path, int *char_start, int *char_end)
*/
static void ensure_digits(char *path, int digits)
{
- char *file = (char *)BLI_last_slash(path);
+ char *file = (char *)BLI_path_slash_rfind(path);
if (file == NULL) {
file = path;
@@ -852,7 +852,7 @@ bool BLI_path_frame_range(char *path, int sta, int end, int digits)
bool BLI_path_frame_get(char *path, int *r_frame, int *r_numdigits)
{
if (*path) {
- char *file = (char *)BLI_last_slash(path);
+ char *file = (char *)BLI_path_slash_rfind(path);
char *c;
int len, numdigits;
@@ -908,7 +908,7 @@ void BLI_path_frame_strip(char *path, char *r_ext)
return;
}
- char *file = (char *)BLI_last_slash(path);
+ char *file = (char *)BLI_path_slash_rfind(path);
char *c, *suffix;
int len;
int numdigits = 0;
@@ -1075,8 +1075,8 @@ bool BLI_path_abs(char *path, const char *basepath)
BLI_strncpy(base, basepath, sizeof(base));
/* file component is ignored, so don't bother with the trailing slash */
- BLI_cleanup_path(NULL, base);
- lslash = BLI_last_slash(base);
+ BLI_path_normalize(NULL, base);
+ lslash = BLI_path_slash_rfind(base);
BLI_str_replace_char(base + BLI_path_unc_prefix_len(base), '\\', '/');
if (lslash) {
@@ -1110,19 +1110,20 @@ bool BLI_path_abs(char *path, const char *basepath)
#endif
/* ensure this is after correcting for path switch */
- BLI_cleanup_path(NULL, path);
+ BLI_path_normalize(NULL, path);
return wasrelative;
}
/**
- * Expands path relative to the current working directory, if it was relative.
- * Returns true if such expansion was done.
+ * Checks for relative path, expanding them relative to the current working directory.
+ * Returns true if the expansion was performed.
*
- * \note Should only be done with command line paths.
- * this is _not_ something blenders internal paths support like the "//" prefix
+ * \note Should only be called with command line paths.
+ * This is _not_ something Blender's internal paths support, instead they use the "//" prefix.
+ * In most cases #BLI_path_abs should be used instead.
*/
-bool BLI_path_cwd(char *path, const size_t maxlen)
+bool BLI_path_abs_from_cwd(char *path, const size_t maxlen)
{
#ifdef DEBUG_STRSIZE
memset(path, 0xff, sizeof(*path) * maxlen);
@@ -1363,7 +1364,7 @@ void BLI_make_file_string(const char *relabase, char *string, const char *dir, c
/* Get the file name, chop everything past the last slash (ie. the filename) */
strcpy(string, relabase);
- lslash = (char *)BLI_last_slash(string);
+ lslash = (char *)BLI_path_slash_rfind(string);
if (lslash) {
*(lslash + 1) = 0;
}
@@ -1418,7 +1419,7 @@ void BLI_make_file_string(const char *relabase, char *string, const char *dir, c
strcat(string, file);
/* Push all slashes to the system preferred direction */
- BLI_path_native_slash(string);
+ BLI_path_slash_native(string);
}
static bool path_extension_check_ex(const char *str,
@@ -1608,12 +1609,12 @@ bool BLI_path_extension_ensure(char *path, size_t maxlen, const char *ext)
return true;
}
-bool BLI_ensure_filename(char *filepath, size_t maxlen, const char *filename)
+bool BLI_path_filename_ensure(char *filepath, size_t maxlen, const char *filename)
{
#ifdef DEBUG_STRSIZE
memset(filepath, 0xff, sizeof(*filepath) * maxlen);
#endif
- char *c = (char *)BLI_last_slash(filepath);
+ char *c = (char *)BLI_path_slash_rfind(filepath);
if (!c || ((c - filepath) < maxlen - (strlen(filename) + 1))) {
strcpy(c ? &c[1] : filepath, filename);
return true;
@@ -1636,7 +1637,7 @@ void BLI_split_dirfile(
memset(dir, 0xff, sizeof(*dir) * dirlen);
memset(file, 0xff, sizeof(*file) * filelen);
#endif
- const char *lslash_str = BLI_last_slash(string);
+ const char *lslash_str = BLI_path_slash_rfind(string);
const size_t lslash = lslash_str ? (size_t)(lslash_str - string) + 1 : 0;
if (dir) {
@@ -1680,7 +1681,7 @@ const char *BLI_path_extension(const char *filepath)
if (extension == NULL) {
return NULL;
}
- if (BLI_first_slash(extension) != NULL) {
+ if (BLI_path_slash_find(extension) != NULL) {
/* There is a path separator in the extension, so the '.' was found in a
* directory component and not in the filename. */
return NULL;
@@ -1695,7 +1696,7 @@ void BLI_path_append(char *__restrict dst, const size_t maxlen, const char *__re
{
size_t dirlen = BLI_strnlen(dst, maxlen);
- /* inline BLI_add_slash */
+ /* inline BLI_path_slash_ensure */
if ((dirlen > 0) && (dst[dirlen - 1] != SEP)) {
dst[dirlen++] = SEP;
dst[dirlen] = '\0';
@@ -1738,7 +1739,7 @@ void BLI_join_dirfile(char *__restrict dst,
return; /* fills the path */
}
- /* inline BLI_add_slash */
+ /* inline BLI_path_slash_ensure */
if ((dirlen > 0) && !ELEM(dst[dirlen - 1], SEP, ALTSEP)) {
dst[dirlen++] = SEP;
dst[dirlen] = '\0';
@@ -1846,7 +1847,7 @@ size_t BLI_path_join(char *__restrict dst, const size_t dst_len, const char *pat
*/
const char *BLI_path_basename(const char *path)
{
- const char *const filename = BLI_last_slash(path);
+ const char *const filename = BLI_path_slash_rfind(path);
return filename ? filename + 1 : path;
}
@@ -1921,7 +1922,7 @@ bool BLI_path_name_at_index(const char *__restrict path,
/**
* Returns pointer to the leftmost path separator in string. Not actually used anywhere.
*/
-const char *BLI_first_slash(const char *string)
+const char *BLI_path_slash_find(const char *string)
{
const char *const ffslash = strchr(string, '/');
const char *const fbslash = strchr(string, '\\');
@@ -1939,7 +1940,7 @@ const char *BLI_first_slash(const char *string)
/**
* Returns pointer to the rightmost path separator in string.
*/
-const char *BLI_last_slash(const char *string)
+const char *BLI_path_slash_rfind(const char *string)
{
const char *const lfslash = strrchr(string, '/');
const char *const lbslash = strrchr(string, '\\');
@@ -1958,7 +1959,7 @@ const char *BLI_last_slash(const char *string)
* Appends a slash to string if there isn't one there already.
* Returns the new length of the string.
*/
-int BLI_add_slash(char *string)
+int BLI_path_slash_ensure(char *string)
{
int len = strlen(string);
if (len == 0 || string[len - 1] != SEP) {
@@ -1972,7 +1973,7 @@ int BLI_add_slash(char *string)
/**
* Removes the last slash and everything after it to the end of string, if there is one.
*/
-void BLI_del_slash(char *string)
+void BLI_path_slash_rstrip(char *string)
{
int len = strlen(string);
while (len) {
@@ -1989,7 +1990,7 @@ void BLI_del_slash(char *string)
/**
* Changes to the path separators to the native ones for this OS.
*/
-void BLI_path_native_slash(char *path)
+void BLI_path_slash_native(char *path)
{
#ifdef WIN32
if (path && BLI_strnlen(path, 3) > 2) {
diff --git a/source/blender/blenlib/intern/quadric.c b/source/blender/blenlib/intern/quadric.c
index 0a1ff9f8116..3ad1844cfe1 100644
--- a/source/blender/blenlib/intern/quadric.c
+++ b/source/blender/blenlib/intern/quadric.c
@@ -141,9 +141,14 @@ void BLI_quadric_mul(Quadric *a, const double scalar)
double BLI_quadric_evaluate(const Quadric *q, const double v[3])
{
- return ((q->a2 * v[0] * v[0]) + (q->ab * 2 * v[0] * v[1]) + (q->ac * 2 * v[0] * v[2]) +
- (q->ad * 2 * v[0]) + (q->b2 * v[1] * v[1]) + (q->bc * 2 * v[1] * v[2]) +
- (q->bd * 2 * v[1]) + (q->c2 * v[2] * v[2]) + (q->cd * 2 * v[2]) + (q->d2));
+ const double v00 = v[0] * v[0], v01 = v[0] * v[1], v02 = v[0] * v[2];
+ const double v11 = v[1] * v[1], v12 = v[1] * v[2];
+ const double v22 = v[2] * v[2];
+ return ((q->a2 * v00) + (q->ab * 2 * v01) + (q->ac * 2 * v02) + (q->ad * 2 * v[0]) + /* a */
+ (q->b2 * v11) + (q->bc * 2 * v12) + (q->bd * 2 * v[1]) + /* b */
+ (q->c2 * v22) + (q->cd * 2 * v[2]) + /* c */
+ (q->d2) /* d */
+ );
}
bool BLI_quadric_optimize(const Quadric *q, double v[3], const double epsilon)
diff --git a/source/blender/blenlib/intern/stack.c b/source/blender/blenlib/intern/stack.c
index e75d944c764..f2e8b352aab 100644
--- a/source/blender/blenlib/intern/stack.c
+++ b/source/blender/blenlib/intern/stack.c
@@ -10,7 +10,7 @@
* 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,
+ * along with this program; if not, write to the Free Software Foundation,
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
diff --git a/source/blender/blenlib/intern/storage.c b/source/blender/blenlib/intern/storage.c
index 7274a15661a..fbfb258693b 100644
--- a/source/blender/blenlib/intern/storage.c
+++ b/source/blender/blenlib/intern/storage.c
@@ -55,6 +55,7 @@
# include "utfconv.h"
# include <direct.h>
# include <io.h>
+# include <shobjidl_core.h>
# include <stdbool.h>
#else
# include <pwd.h>
@@ -226,14 +227,22 @@ size_t BLI_file_size(const char *path)
return stats.st_size;
}
+/* Return file attributes. Apple version of this function is defined in storage_apple.mm */
#ifndef __APPLE__
eFileAttributes BLI_file_attributes(const char *path)
{
int ret = 0;
# ifdef WIN32
- wchar_t wline[FILE_MAXDIR];
- BLI_strncpy_wchar_from_utf8(wline, path, ARRAY_SIZE(wline));
+
+ if (BLI_path_extension_check(path, ".lnk")) {
+ return FILE_ATTR_ALIAS;
+ }
+
+ WCHAR wline[FILE_MAXDIR];
+ if (conv_utf_8_to_16(path, wline, ARRAY_SIZE(wline)) != 0) {
+ return ret;
+ }
DWORD attr = GetFileAttributesW(wline);
if (attr & FILE_ATTRIBUTE_READONLY) {
ret |= FILE_ATTR_READONLY;
@@ -282,15 +291,52 @@ eFileAttributes BLI_file_attributes(const char *path)
}
#endif
-/**
- * Returns the target path of a file-based redirection, like Mac Alias or Win32 Shortcut file.
- */
+/* Return alias/shortcut file target. Apple version is defined in storage_apple.mm */
#ifndef __APPLE__
-bool BLI_file_alias_target(char UNUSED(target[FILE_MAXDIR]), const char *UNUSED(filepath))
+bool BLI_file_alias_target(char target[FILE_MAXDIR], const char *filepath)
{
- /* TODO: Find target in Win32 Shortcut - Shell Link (.lnk) file.
- * Format: https://docs.microsoft.com/en-us/openspecs/windows_protocols/ms-shllink/ */
+# ifdef WIN32
+ if (!BLI_path_extension_check(filepath, ".lnk")) {
+ return false;
+ }
+
+ IShellLinkW *Shortcut = NULL;
+ bool success = false;
+ CoInitializeEx(NULL, COINIT_MULTITHREADED);
+
+ HRESULT hr = CoCreateInstance(
+ &CLSID_ShellLink, NULL, CLSCTX_INPROC_SERVER, &IID_IShellLinkW, (LPVOID *)&Shortcut);
+ if (SUCCEEDED(hr)) {
+ IPersistFile *PersistFile;
+ hr = Shortcut->lpVtbl->QueryInterface(Shortcut, &IID_IPersistFile, (LPVOID *)&PersistFile);
+ if (SUCCEEDED(hr)) {
+ WCHAR path_utf16[FILE_MAXDIR] = {0};
+ if (conv_utf_8_to_16(filepath, path_utf16, ARRAY_SIZE(path_utf16)) == 0) {
+ hr = PersistFile->lpVtbl->Load(PersistFile, path_utf16, STGM_READ);
+ if (SUCCEEDED(hr)) {
+ hr = Shortcut->lpVtbl->Resolve(Shortcut, 0, SLR_NO_UI | SLR_UPDATE);
+ if (SUCCEEDED(hr)) {
+ wchar_t target_utf16[FILE_MAXDIR] = {0};
+ hr = Shortcut->lpVtbl->GetPath(Shortcut, target_utf16, FILE_MAXDIR, NULL, 0);
+ if (SUCCEEDED(hr)) {
+ success = (conv_utf_16_to_8(target_utf16, target, FILE_MAXDIR) == 0);
+ }
+ }
+ PersistFile->lpVtbl->Release(PersistFile);
+ }
+ }
+ }
+ Shortcut->lpVtbl->Release(Shortcut);
+ }
+
+ return (success && target[0]);
+# endif
+
+# ifdef __linux__
+ UNUSED_VARS(target, filepath);
+ /* File-based redirection not supported. */
return false;
+# endif
}
#endif
@@ -316,7 +362,7 @@ int BLI_exists(const char *name)
* 2. after the C:\ when the path is the volume only
*/
if ((len >= 3) && (tmp_16[0] == L'\\') && (tmp_16[1] == L'\\')) {
- BLI_cleanup_unc_16(tmp_16);
+ BLI_path_normalize_unc_16(tmp_16);
}
if ((tmp_16[1] == L':') && (tmp_16[2] == L'\0')) {
diff --git a/source/blender/blenlib/intern/storage_apple.mm b/source/blender/blenlib/intern/storage_apple.mm
index 7cb8ca28e24..08d2cfdf4a4 100644
--- a/source/blender/blenlib/intern/storage_apple.mm
+++ b/source/blender/blenlib/intern/storage_apple.mm
@@ -30,7 +30,9 @@
bool BLI_file_alias_target(char targetpath[FILE_MAXDIR], const char *filepath)
{
+ /* clang-format off */
@autoreleasepool {
+ /* clang-format on */
NSError *error = nil;
NSURL *shortcutURL = [[NSURL alloc] initFileURLWithFileSystemRepresentation:filepath
isDirectory:NO
@@ -64,7 +66,9 @@ eFileAttributes BLI_file_attributes(const char *path)
{
int ret = 0;
+ /* clang-format off */
@autoreleasepool {
+ /* clang-format on */
NSURL *fileURL = [[NSURL alloc] initFileURLWithFileSystemRepresentation:path
isDirectory:NO
relativeToURL:nil];
@@ -87,7 +91,7 @@ eFileAttributes BLI_file_attributes(const char *path)
if (is_readable && !is_writable) {
ret |= FILE_ATTR_READONLY;
}
- if (is_readable) {
+ if (!is_readable) {
ret |= FILE_ATTR_SYSTEM;
}
}
diff --git a/source/blender/blenlib/intern/system.c b/source/blender/blenlib/intern/system.c
index 7d9ed2598a6..53db49aa59c 100644
--- a/source/blender/blenlib/intern/system.c
+++ b/source/blender/blenlib/intern/system.c
@@ -32,11 +32,8 @@
/* for backtrace and gethostname/GetComputerName */
#if defined(WIN32)
# include <intrin.h>
-# include <windows.h>
-# pragma warning(push)
-# pragma warning(disable : 4091)
-# include <dbghelp.h>
-# pragma warning(pop)
+
+# include "BLI_winstuff.h"
#else
# include <execinfo.h>
# include <unistd.h>
@@ -74,6 +71,8 @@ int BLI_cpu_support_sse2(void)
#endif
}
+/* Windows stackwalk lives in system_win32.c */
+#if !defined(_MSC_VER)
/**
* Write a backtrace into a file for systems which support it.
*/
@@ -81,9 +80,9 @@ void BLI_system_backtrace(FILE *fp)
{
/* ------------- */
/* Linux / Apple */
-#if defined(__linux__) || defined(__APPLE__)
+# if defined(__linux__) || defined(__APPLE__)
-# define SIZE 100
+# define SIZE 100
void *buffer[SIZE];
int nptrs;
char **strings;
@@ -98,48 +97,15 @@ void BLI_system_backtrace(FILE *fp)
}
free(strings);
-# undef SIZE
-
- /* -------- */
- /* Windows */
-#elif defined(_MSC_VER)
-
-# ifndef NDEBUG
-# define MAXSYMBOL 256
-# define SIZE 100
- unsigned short i;
- void *stack[SIZE];
- unsigned short nframes;
- SYMBOL_INFO *symbolinfo;
- HANDLE process;
-
- process = GetCurrentProcess();
-
- SymInitialize(process, NULL, TRUE);
-
- nframes = CaptureStackBackTrace(0, SIZE, stack, NULL);
- symbolinfo = MEM_callocN(sizeof(SYMBOL_INFO) + MAXSYMBOL * sizeof(char), "crash Symbol table");
- symbolinfo->MaxNameLen = MAXSYMBOL - 1;
- symbolinfo->SizeOfStruct = sizeof(SYMBOL_INFO);
-
- for (i = 0; i < nframes; i++) {
- SymFromAddr(process, (DWORD64)(stack[i]), 0, symbolinfo);
-
- fprintf(fp, "%u: %s - 0x%0llX\n", nframes - i - 1, symbolinfo->Name, symbolinfo->Address);
- }
-
- MEM_freeN(symbolinfo);
-# undef MAXSYMBOL
# undef SIZE
+
# else
- fprintf(fp, "Crash backtrace not supported on release builds\n");
-# endif /* NDEBUG */
-#else /* _MSC_VER */
/* ------------------ */
/* non msvc/osx/linux */
(void)fp;
-#endif
+# endif
}
+#endif
/* end BLI_system_backtrace */
/* NOTE: The code for CPU brand string is adopted from Cycles. */
diff --git a/source/blender/blenlib/intern/system_win32.c b/source/blender/blenlib/intern/system_win32.c
new file mode 100644
index 00000000000..d60f54ebe67
--- /dev/null
+++ b/source/blender/blenlib/intern/system_win32.c
@@ -0,0 +1,410 @@
+/*
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+
+/** \file
+ * \ingroup bli
+ */
+#include <Windows.h>
+#include <stdio.h>
+
+#include <dbghelp.h>
+#include <shlwapi.h>
+#include <tlhelp32.h>
+
+#include "BLI_string.h"
+
+#include "MEM_guardedalloc.h"
+
+static EXCEPTION_POINTERS *current_exception = NULL;
+
+static const char *bli_windows_get_exception_description(const DWORD exceptioncode)
+{
+ switch (exceptioncode) {
+ case EXCEPTION_ACCESS_VIOLATION:
+ return "EXCEPTION_ACCESS_VIOLATION";
+ case EXCEPTION_ARRAY_BOUNDS_EXCEEDED:
+ return "EXCEPTION_ARRAY_BOUNDS_EXCEEDED";
+ case EXCEPTION_BREAKPOINT:
+ return "EXCEPTION_BREAKPOINT";
+ case EXCEPTION_DATATYPE_MISALIGNMENT:
+ return "EXCEPTION_DATATYPE_MISALIGNMENT";
+ case EXCEPTION_FLT_DENORMAL_OPERAND:
+ return "EXCEPTION_FLT_DENORMAL_OPERAND";
+ case EXCEPTION_FLT_DIVIDE_BY_ZERO:
+ return "EXCEPTION_FLT_DIVIDE_BY_ZERO";
+ case EXCEPTION_FLT_INEXACT_RESULT:
+ return "EXCEPTION_FLT_INEXACT_RESULT";
+ case EXCEPTION_FLT_INVALID_OPERATION:
+ return "EXCEPTION_FLT_INVALID_OPERATION";
+ case EXCEPTION_FLT_OVERFLOW:
+ return "EXCEPTION_FLT_OVERFLOW";
+ case EXCEPTION_FLT_STACK_CHECK:
+ return "EXCEPTION_FLT_STACK_CHECK";
+ case EXCEPTION_FLT_UNDERFLOW:
+ return "EXCEPTION_FLT_UNDERFLOW";
+ case EXCEPTION_ILLEGAL_INSTRUCTION:
+ return "EXCEPTION_ILLEGAL_INSTRUCTION";
+ case EXCEPTION_IN_PAGE_ERROR:
+ return "EXCEPTION_IN_PAGE_ERROR";
+ case EXCEPTION_INT_DIVIDE_BY_ZERO:
+ return "EXCEPTION_INT_DIVIDE_BY_ZERO";
+ case EXCEPTION_INT_OVERFLOW:
+ return "EXCEPTION_INT_OVERFLOW";
+ case EXCEPTION_INVALID_DISPOSITION:
+ return "EXCEPTION_INVALID_DISPOSITION";
+ case EXCEPTION_NONCONTINUABLE_EXCEPTION:
+ return "EXCEPTION_NONCONTINUABLE_EXCEPTION";
+ case EXCEPTION_PRIV_INSTRUCTION:
+ return "EXCEPTION_PRIV_INSTRUCTION";
+ case EXCEPTION_SINGLE_STEP:
+ return "EXCEPTION_SINGLE_STEP";
+ case EXCEPTION_STACK_OVERFLOW:
+ return "EXCEPTION_STACK_OVERFLOW";
+ default:
+ return "UNKNOWN EXCEPTION";
+ }
+}
+
+static void bli_windows_get_module_name(LPVOID address, PCHAR buffer, size_t size)
+{
+ HMODULE mod;
+ buffer[0] = 0;
+ if (GetModuleHandleEx(GET_MODULE_HANDLE_EX_FLAG_FROM_ADDRESS, address, &mod)) {
+ if (GetModuleFileName(mod, buffer, size)) {
+ PathStripPath(buffer);
+ }
+ }
+}
+
+static void bli_windows_get_module_version(const char *file, char *buffer, size_t buffersize)
+{
+ buffer[0] = 0;
+ DWORD verHandle = 0;
+ UINT size = 0;
+ LPBYTE lpBuffer = NULL;
+ DWORD verSize = GetFileVersionInfoSize(file, &verHandle);
+ if (verSize != 0) {
+ LPSTR verData = (LPSTR)MEM_callocN(verSize, "crash module version");
+
+ if (GetFileVersionInfo(file, verHandle, verSize, verData)) {
+ if (VerQueryValue(verData, "\\", (VOID FAR * FAR *)&lpBuffer, &size)) {
+ if (size) {
+ VS_FIXEDFILEINFO *verInfo = (VS_FIXEDFILEINFO *)lpBuffer;
+ /* Magic value from
+ * https://docs.microsoft.com/en-us/windows/win32/api/verrsrc/ns-verrsrc-vs_fixedfileinfo
+ */
+ if (verInfo->dwSignature == 0xfeef04bd) {
+ BLI_snprintf(buffer,
+ buffersize,
+ "%d.%d.%d.%d",
+ (verInfo->dwFileVersionMS >> 16) & 0xffff,
+ (verInfo->dwFileVersionMS >> 0) & 0xffff,
+ (verInfo->dwFileVersionLS >> 16) & 0xffff,
+ (verInfo->dwFileVersionLS >> 0) & 0xffff);
+ }
+ }
+ }
+ }
+ MEM_freeN(verData);
+ }
+}
+
+static void bli_windows_system_backtrace_exception_record(FILE *fp, PEXCEPTION_RECORD record)
+{
+ char module[MAX_PATH];
+ fprintf(fp, "Exception Record:\n\n");
+ fprintf(fp,
+ "ExceptionCode : %s\n",
+ bli_windows_get_exception_description(record->ExceptionCode));
+ fprintf(fp, "Exception Address : 0x%p\n", record->ExceptionAddress);
+ bli_windows_get_module_name(record->ExceptionAddress, module, sizeof(module));
+ fprintf(fp, "Exception Module : %s\n", module);
+ fprintf(fp, "Exception Flags : 0x%.8x\n", record->ExceptionFlags);
+ fprintf(fp, "Exception Parameters : 0x%x\n", record->NumberParameters);
+ for (DWORD idx = 0; idx < record->NumberParameters; idx++) {
+ fprintf(fp, "\tParameters[%d] : 0x%p\n", idx, (LPVOID *)record->ExceptionInformation[idx]);
+ }
+ if (record->ExceptionRecord) {
+ fprintf(fp, "Nested ");
+ bli_windows_system_backtrace_exception_record(fp, record->ExceptionRecord);
+ }
+ fprintf(fp, "\n\n");
+}
+
+static bool BLI_windows_system_backtrace_run_trace(FILE *fp, HANDLE hThread, PCONTEXT context)
+{
+ const int max_symbol_length = 100;
+
+ bool result = true;
+
+ PSYMBOL_INFO symbolinfo = MEM_callocN(sizeof(SYMBOL_INFO) + max_symbol_length * sizeof(char),
+ "crash Symbol table");
+ symbolinfo->MaxNameLen = max_symbol_length - 1;
+ symbolinfo->SizeOfStruct = sizeof(SYMBOL_INFO);
+
+ STACKFRAME frame = {0};
+ frame.AddrPC.Offset = context->Rip;
+ frame.AddrPC.Mode = AddrModeFlat;
+ frame.AddrFrame.Offset = context->Rsp;
+ frame.AddrFrame.Mode = AddrModeFlat;
+ frame.AddrStack.Offset = context->Rsp;
+ frame.AddrStack.Mode = AddrModeFlat;
+
+ while (true) {
+ if (StackWalk64(IMAGE_FILE_MACHINE_AMD64,
+ GetCurrentProcess(),
+ hThread,
+ &frame,
+ context,
+ NULL,
+ SymFunctionTableAccess64,
+ SymGetModuleBase64,
+ 0)) {
+ if (frame.AddrPC.Offset) {
+ char module[MAX_PATH];
+
+ bli_windows_get_module_name((LPVOID)frame.AddrPC.Offset, module, sizeof(module));
+
+ if (SymFromAddr(GetCurrentProcess(), (DWORD64)(frame.AddrPC.Offset), 0, symbolinfo)) {
+ fprintf(fp, "%-20s:0x%p %s", module, (LPVOID)symbolinfo->Address, symbolinfo->Name);
+ IMAGEHLP_LINE lineinfo;
+ lineinfo.SizeOfStruct = sizeof(lineinfo);
+ DWORD displacement = 0;
+ if (SymGetLineFromAddr(
+ GetCurrentProcess(), (DWORD64)(frame.AddrPC.Offset), &displacement, &lineinfo)) {
+ fprintf(fp, " %s:%d", lineinfo.FileName, lineinfo.LineNumber);
+ }
+ fprintf(fp, "\n");
+ }
+ else {
+ fprintf(fp,
+ "%-20s:0x%p %s\n",
+ module,
+ (LPVOID)frame.AddrPC.Offset,
+ "Symbols not available");
+ result = false;
+ break;
+ }
+ }
+ else {
+ break;
+ }
+ }
+ else {
+ break;
+ }
+ }
+ MEM_freeN(symbolinfo);
+ fprintf(fp, "\n\n");
+ return result;
+}
+
+static bool bli_windows_system_backtrace_stack_thread(FILE *fp, HANDLE hThread)
+{
+ CONTEXT context = {0};
+ context.ContextFlags = CONTEXT_ALL;
+ /* GetThreadContext requires the thread to be in a suspended state, which is problematic for the
+ * currently running thread, RtlCaptureContext is used as an alternative to sidestep this */
+ if (hThread != GetCurrentThread()) {
+ SuspendThread(hThread);
+ bool success = GetThreadContext(hThread, &context);
+ ResumeThread(hThread);
+ if (!success) {
+ fprintf(fp, "Cannot get thread context : 0x0%.8x\n", GetLastError());
+ return false;
+ }
+ }
+ else {
+ RtlCaptureContext(&context);
+ }
+ return BLI_windows_system_backtrace_run_trace(fp, hThread, &context);
+}
+
+static void bli_windows_system_backtrace_modules(FILE *fp)
+{
+ fprintf(fp, "Loaded Modules :\n");
+ HANDLE hModuleSnap = CreateToolhelp32Snapshot(TH32CS_SNAPMODULE, 0);
+ if (hModuleSnap == INVALID_HANDLE_VALUE)
+ return;
+
+ MODULEENTRY32 me32;
+ me32.dwSize = sizeof(MODULEENTRY32);
+
+ if (!Module32First(hModuleSnap, &me32)) {
+ CloseHandle(hModuleSnap); // Must clean up the snapshot object!
+ fprintf(fp, " Error getting module list.\n");
+ return;
+ }
+
+ do {
+ if (me32.th32ProcessID == GetCurrentProcessId()) {
+ char version[MAX_PATH];
+ bli_windows_get_module_version(me32.szExePath, version, sizeof(version));
+
+ IMAGEHLP_MODULE64 m64;
+ m64.SizeOfStruct = sizeof(m64);
+ if (SymGetModuleInfo64(GetCurrentProcess(), (DWORD64)me32.modBaseAddr, &m64)) {
+ fprintf(fp,
+ "0x%p %-20s %s %s %s\n",
+ me32.modBaseAddr,
+ version,
+ me32.szModule,
+ m64.LoadedPdbName,
+ m64.PdbUnmatched ? "[unmatched]" : "");
+ }
+ else {
+ fprintf(fp, "0x%p %-20s %s\n", me32.modBaseAddr, version, me32.szModule);
+ }
+ }
+ } while (Module32Next(hModuleSnap, &me32));
+}
+
+static void bli_windows_system_backtrace_threads(FILE *fp)
+{
+ fprintf(fp, "Threads:\n");
+ HANDLE hThreadSnap = INVALID_HANDLE_VALUE;
+ THREADENTRY32 te32;
+
+ hThreadSnap = CreateToolhelp32Snapshot(TH32CS_SNAPTHREAD, 0);
+ if (hThreadSnap == INVALID_HANDLE_VALUE) {
+ fprintf(fp, "Unable to retrieve threads list.\n");
+ return;
+ }
+
+ te32.dwSize = sizeof(THREADENTRY32);
+
+ if (!Thread32First(hThreadSnap, &te32)) {
+ CloseHandle(hThreadSnap);
+ return;
+ }
+ do {
+ if (te32.th32OwnerProcessID == GetCurrentProcessId()) {
+ if (GetCurrentThreadId() != te32.th32ThreadID) {
+ fprintf(fp, "Thread : %.8x\n", te32.th32ThreadID);
+ HANDLE ht = OpenThread(THREAD_ALL_ACCESS, FALSE, te32.th32ThreadID);
+ bli_windows_system_backtrace_stack_thread(fp, ht);
+ CloseHandle(ht);
+ }
+ }
+ } while (Thread32Next(hThreadSnap, &te32));
+ CloseHandle(hThreadSnap);
+}
+
+static bool BLI_windows_system_backtrace_stack(FILE *fp)
+{
+ fprintf(fp, "Stack trace:\n");
+ /* If we are handling an exception use the context record from that. */
+ if (current_exception && current_exception->ExceptionRecord->ExceptionAddress) {
+ /* The back trace code will write to the context record, to protect the original record from
+ * modifications give the backtrace a copy to work on. */
+ CONTEXT TempContext = *current_exception->ContextRecord;
+ return BLI_windows_system_backtrace_run_trace(fp, GetCurrentThread(), &TempContext);
+ }
+ else {
+ /* If there is no current exception or the address is not set, walk the current stack. */
+ return bli_windows_system_backtrace_stack_thread(fp, GetCurrentThread());
+ }
+}
+
+static bool bli_private_symbols_loaded()
+{
+ IMAGEHLP_MODULE64 m64;
+ m64.SizeOfStruct = sizeof(m64);
+ if (SymGetModuleInfo64(GetCurrentProcess(), (DWORD64)GetModuleHandle(NULL), &m64)) {
+ return m64.GlobalSymbols;
+ }
+ return false;
+}
+
+static void bli_load_symbols()
+{
+ /* If this is a developer station and the private pdb is already loaded leave it be. */
+ if (bli_private_symbols_loaded()) {
+ return;
+ }
+
+ char pdb_file[MAX_PATH] = {0};
+
+ /* get the currently executing image */
+ if (GetModuleFileNameA(NULL, pdb_file, sizeof(pdb_file))) {
+ /* remove the filename */
+ PathRemoveFileSpecA(pdb_file);
+ /* append blender.pdb */
+ PathAppendA(pdb_file, "blender.pdb");
+ if (PathFileExistsA(pdb_file)) {
+ HMODULE mod = GetModuleHandle(NULL);
+ if (mod) {
+ WIN32_FILE_ATTRIBUTE_DATA file_data;
+ if (GetFileAttributesExA(pdb_file, GetFileExInfoStandard, &file_data)) {
+ /* SymInitialize will try to load symbols on its own, so we first must unload whatever it
+ * did trying to help */
+ SymUnloadModule64(GetCurrentProcess(), (DWORD64)mod);
+
+ DWORD64 module_base = SymLoadModule(GetCurrentProcess(),
+ NULL,
+ pdb_file,
+ NULL,
+ (DWORD64)mod,
+ (DWORD)file_data.nFileSizeLow);
+ if (module_base == 0) {
+ fprintf(stderr,
+ "Error loading symbols %s\n\terror:0x%.8x\n\tsize = %d\n\tbase=0x%p\n",
+ pdb_file,
+ GetLastError(),
+ file_data.nFileSizeLow,
+ (LPVOID)mod);
+ }
+ }
+ }
+ }
+ }
+}
+
+void BLI_system_backtrace(FILE *fp)
+{
+ SymInitialize(GetCurrentProcess(), NULL, TRUE);
+ bli_load_symbols();
+ if (current_exception) {
+ bli_windows_system_backtrace_exception_record(fp, current_exception->ExceptionRecord);
+ }
+ if (BLI_windows_system_backtrace_stack(fp)) {
+ /* When the blender symbols are missing the stack traces will be unreliable
+ * so only run if the previous step completed successfully. */
+ bli_windows_system_backtrace_threads(fp);
+ }
+ bli_windows_system_backtrace_modules(fp);
+ fputc(0, fp); /* Give our selves a nice zero terminator for later on */
+}
+
+void BLI_windows_handle_exception(EXCEPTION_POINTERS *exception)
+{
+ current_exception = exception;
+ if (current_exception) {
+ fprintf(stderr,
+ "Error : %s\n",
+ bli_windows_get_exception_description(exception->ExceptionRecord->ExceptionCode));
+ fflush(stderr);
+
+ LPVOID address = exception->ExceptionRecord->ExceptionAddress;
+ fprintf(stderr, "Address : 0x%p\n", address);
+
+ CHAR modulename[MAX_PATH];
+ bli_windows_get_module_name(address, modulename, sizeof(modulename));
+ fprintf(stderr, "Module : %s\n", modulename);
+ fprintf(stderr, "Thread : %.8x\n", GetCurrentThreadId());
+ }
+ fflush(stderr);
+}
diff --git a/source/blender/blenlib/intern/task.c b/source/blender/blenlib/intern/task.c
deleted file mode 100644
index 293275c402d..00000000000
--- a/source/blender/blenlib/intern/task.c
+++ /dev/null
@@ -1,1930 +0,0 @@
-/*
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License
- * as published by the Free Software Foundation; either version 2
- * of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-
-/** \file
- * \ingroup bli
- *
- * A generic task system which can be used for any task based subsystem.
- */
-
-#include <stdlib.h>
-
-#include "MEM_guardedalloc.h"
-
-#include "DNA_listBase.h"
-
-#include "BLI_listbase.h"
-#include "BLI_math.h"
-#include "BLI_mempool.h"
-#include "BLI_task.h"
-#include "BLI_threads.h"
-
-#include "atomic_ops.h"
-
-/* Define this to enable some detailed statistic print. */
-#undef DEBUG_STATS
-
-/* Types */
-
-/* Number of per-thread pre-allocated tasks.
- *
- * For more details see description of TaskMemPool.
- */
-#define MEMPOOL_SIZE 256
-
-/* Number of tasks which are pushed directly to local thread queue.
- *
- * This allows thread to fetch next task without locking the whole queue.
- */
-#define LOCAL_QUEUE_SIZE 1
-
-/* Number of tasks which are allowed to be scheduled in a delayed manner.
- *
- * This allows to use less locks per graph node children schedule. More details
- * could be found at TaskThreadLocalStorage::do_delayed_push.
- */
-#define DELAYED_QUEUE_SIZE 4096
-
-#ifndef NDEBUG
-# define ASSERT_THREAD_ID(scheduler, thread_id) \
- do { \
- if (!BLI_thread_is_main()) { \
- TaskThread *thread = pthread_getspecific(scheduler->tls_id_key); \
- if (thread == NULL) { \
- BLI_assert(thread_id == 0); \
- } \
- else { \
- BLI_assert(thread_id == thread->id); \
- } \
- } \
- else { \
- BLI_assert(thread_id == 0); \
- } \
- } while (false)
-#else
-# define ASSERT_THREAD_ID(scheduler, thread_id)
-#endif
-
-typedef struct Task {
- struct Task *next, *prev;
-
- TaskRunFunction run;
- void *taskdata;
- bool free_taskdata;
- TaskFreeFunction freedata;
- TaskPool *pool;
-} Task;
-
-/* This is a per-thread storage of pre-allocated tasks.
- *
- * The idea behind this is simple: reduce amount of malloc() calls when pushing
- * new task to the pool. This is done by keeping memory from the tasks which
- * were finished already, so instead of freeing that memory we put it to the
- * pool for the later re-use.
- *
- * The tricky part here is to avoid any inter-thread synchronization, hence no
- * lock must exist around this pool. The pool will become an owner of the pointer
- * from freed task, and only corresponding thread will be able to use this pool
- * (no memory stealing and such).
- *
- * This leads to the following use of the pool:
- *
- * - task_push() should provide proper thread ID from which the task is being
- * pushed from.
- *
- * - Task allocation function which check corresponding memory pool and if there
- * is any memory in there it'll mark memory as re-used, remove it from the pool
- * and use that memory for the new task.
- *
- * At this moment task queue owns the memory.
- *
- * - When task is done and task_free() is called the memory will be put to the
- * pool which corresponds to a thread which handled the task.
- */
-typedef struct TaskMemPool {
- /* Number of pre-allocated tasks in the pool. */
- int num_tasks;
- /* Pre-allocated task memory pointers. */
- Task *tasks[MEMPOOL_SIZE];
-} TaskMemPool;
-
-#ifdef DEBUG_STATS
-typedef struct TaskMemPoolStats {
- /* Number of allocations. */
- int num_alloc;
- /* Number of avoided allocations (pointer was re-used from the pool). */
- int num_reuse;
- /* Number of discarded memory due to pool saturation, */
- int num_discard;
-} TaskMemPoolStats;
-#endif
-
-typedef struct TaskThreadLocalStorage {
- /* Memory pool for faster task allocation.
- * The idea is to re-use memory of finished/discarded tasks by this thread.
- */
- TaskMemPool task_mempool;
-
- /* Local queue keeps thread alive by keeping small amount of tasks ready
- * to be picked up without causing global thread locks for synchronization.
- */
- int num_local_queue;
- Task *local_queue[LOCAL_QUEUE_SIZE];
-
- /* Thread can be marked for delayed tasks push. This is helpful when it's
- * know that lots of subsequent task pushed will happen from the same thread
- * without "interrupting" for task execution.
- *
- * We try to accumulate as much tasks as possible in a local queue without
- * any locks first, and then we push all of them into a scheduler's queue
- * from within a single mutex lock.
- */
- bool do_delayed_push;
- int num_delayed_queue;
- Task *delayed_queue[DELAYED_QUEUE_SIZE];
-} TaskThreadLocalStorage;
-
-struct TaskPool {
- TaskScheduler *scheduler;
-
- volatile size_t num;
- ThreadMutex num_mutex;
- ThreadCondition num_cond;
-
- void *userdata;
- ThreadMutex user_mutex;
-
- volatile bool do_cancel;
- volatile bool do_work;
-
- volatile bool is_suspended;
- bool start_suspended;
- ListBase suspended_queue;
- size_t num_suspended;
-
- /* If set, this pool may never be work_and_wait'ed, which means TaskScheduler
- * has to use its special background fallback thread in case we are in
- * single-threaded situation.
- */
- bool run_in_background;
-
- /* This is a task scheduler's ID of a thread at which pool was constructed.
- * It will be used to access task TLS.
- */
- int thread_id;
-
- /* For the pools which are created from non-main thread which is not a
- * scheduler worker thread we can't re-use any of scheduler's threads TLS
- * and have to use our own one.
- */
- bool use_local_tls;
- TaskThreadLocalStorage local_tls;
-#ifndef NDEBUG
- pthread_t creator_thread_id;
-#endif
-
-#ifdef DEBUG_STATS
- TaskMemPoolStats *mempool_stats;
-#endif
-};
-
-struct TaskScheduler {
- pthread_t *threads;
- struct TaskThread *task_threads;
- int num_threads;
- bool background_thread_only;
-
- ListBase queue;
- ThreadMutex queue_mutex;
- ThreadCondition queue_cond;
-
- ThreadMutex startup_mutex;
- ThreadCondition startup_cond;
- volatile int num_thread_started;
-
- volatile bool do_exit;
-
- /* NOTE: In pthread's TLS we store the whole TaskThread structure. */
- pthread_key_t tls_id_key;
-};
-
-typedef struct TaskThread {
- TaskScheduler *scheduler;
- int id;
- TaskThreadLocalStorage tls;
-} TaskThread;
-
-/* Helper */
-BLI_INLINE void task_data_free(Task *task, const int thread_id)
-{
- if (task->free_taskdata) {
- if (task->freedata) {
- task->freedata(task->pool, task->taskdata, thread_id);
- }
- else {
- MEM_freeN(task->taskdata);
- }
- }
-}
-
-BLI_INLINE void initialize_task_tls(TaskThreadLocalStorage *tls)
-{
- memset(tls, 0, sizeof(TaskThreadLocalStorage));
-}
-
-BLI_INLINE TaskThreadLocalStorage *get_task_tls(TaskPool *pool, const int thread_id)
-{
- TaskScheduler *scheduler = pool->scheduler;
- BLI_assert(thread_id >= 0);
- BLI_assert(thread_id <= scheduler->num_threads);
- if (pool->use_local_tls && thread_id == 0) {
- BLI_assert(pool->thread_id == 0);
- BLI_assert(!BLI_thread_is_main());
- BLI_assert(pthread_equal(pthread_self(), pool->creator_thread_id));
- return &pool->local_tls;
- }
- if (thread_id == 0) {
- BLI_assert(BLI_thread_is_main());
- return &scheduler->task_threads[pool->thread_id].tls;
- }
- return &scheduler->task_threads[thread_id].tls;
-}
-
-BLI_INLINE void free_task_tls(TaskThreadLocalStorage *tls)
-{
- TaskMemPool *task_mempool = &tls->task_mempool;
- for (int i = 0; i < task_mempool->num_tasks; i++) {
- MEM_freeN(task_mempool->tasks[i]);
- }
-}
-
-static Task *task_alloc(TaskPool *pool, const int thread_id)
-{
- BLI_assert(thread_id <= pool->scheduler->num_threads);
- if (thread_id != -1) {
- BLI_assert(thread_id >= 0);
- BLI_assert(thread_id <= pool->scheduler->num_threads);
- TaskThreadLocalStorage *tls = get_task_tls(pool, thread_id);
- TaskMemPool *task_mempool = &tls->task_mempool;
- /* Try to re-use task memory from a thread local storage. */
- if (task_mempool->num_tasks > 0) {
- --task_mempool->num_tasks;
- /* Success! We've just avoided task allocation. */
-#ifdef DEBUG_STATS
- pool->mempool_stats[thread_id].num_reuse++;
-#endif
- return task_mempool->tasks[task_mempool->num_tasks];
- }
- /* We are doomed to allocate new task data. */
-#ifdef DEBUG_STATS
- pool->mempool_stats[thread_id].num_alloc++;
-#endif
- }
- return MEM_mallocN(sizeof(Task), "New task");
-}
-
-static void task_free(TaskPool *pool, Task *task, const int thread_id)
-{
- task_data_free(task, thread_id);
- BLI_assert(thread_id >= 0);
- BLI_assert(thread_id <= pool->scheduler->num_threads);
- if (thread_id == 0) {
- BLI_assert(pool->use_local_tls || BLI_thread_is_main());
- }
- TaskThreadLocalStorage *tls = get_task_tls(pool, thread_id);
- TaskMemPool *task_mempool = &tls->task_mempool;
- if (task_mempool->num_tasks < MEMPOOL_SIZE - 1) {
- /* Successfully allowed the task to be re-used later. */
- task_mempool->tasks[task_mempool->num_tasks] = task;
- ++task_mempool->num_tasks;
- }
- else {
- /* Local storage saturated, no other way than just discard
- * the memory.
- *
- * TODO(sergey): We can perhaps store such pointer in a global
- * scheduler pool, maybe it'll be faster than discarding and
- * allocating again.
- */
- MEM_freeN(task);
-#ifdef DEBUG_STATS
- pool->mempool_stats[thread_id].num_discard++;
-#endif
- }
-}
-
-/* Task Scheduler */
-
-static void task_pool_num_decrease(TaskPool *pool, size_t done)
-{
- BLI_mutex_lock(&pool->num_mutex);
-
- BLI_assert(pool->num >= done);
-
- pool->num -= done;
-
- if (pool->num == 0) {
- BLI_condition_notify_all(&pool->num_cond);
- }
-
- BLI_mutex_unlock(&pool->num_mutex);
-}
-
-static void task_pool_num_increase(TaskPool *pool, size_t new)
-{
- BLI_mutex_lock(&pool->num_mutex);
-
- pool->num += new;
- BLI_condition_notify_all(&pool->num_cond);
-
- BLI_mutex_unlock(&pool->num_mutex);
-}
-
-static bool task_scheduler_thread_wait_pop(TaskScheduler *scheduler, Task **task)
-{
- bool found_task = false;
- BLI_mutex_lock(&scheduler->queue_mutex);
-
- while (!scheduler->queue.first && !scheduler->do_exit) {
- BLI_condition_wait(&scheduler->queue_cond, &scheduler->queue_mutex);
- }
-
- do {
- Task *current_task;
-
- /* Assuming we can only have a void queue in 'exit' case here seems logical
- * (we should only be here after our worker thread has been woken up from a
- * condition_wait(), which only happens after a new task was added to the queue),
- * but it is wrong.
- * Waiting on condition may wake up the thread even if condition is not signaled
- * (spurious wake-ups), and some race condition may also empty the queue **after**
- * condition has been signaled, but **before** awoken thread reaches this point...
- * See http://stackoverflow.com/questions/8594591
- *
- * So we only abort here if do_exit is set.
- */
- if (scheduler->do_exit) {
- BLI_mutex_unlock(&scheduler->queue_mutex);
- return false;
- }
-
- for (current_task = scheduler->queue.first; current_task != NULL;
- current_task = current_task->next) {
- TaskPool *pool = current_task->pool;
-
- if (scheduler->background_thread_only && !pool->run_in_background) {
- continue;
- }
-
- *task = current_task;
- found_task = true;
- BLI_remlink(&scheduler->queue, *task);
- break;
- }
- if (!found_task) {
- BLI_condition_wait(&scheduler->queue_cond, &scheduler->queue_mutex);
- }
- } while (!found_task);
-
- BLI_mutex_unlock(&scheduler->queue_mutex);
-
- return true;
-}
-
-BLI_INLINE void handle_local_queue(TaskThreadLocalStorage *tls, const int thread_id)
-{
- BLI_assert(!tls->do_delayed_push);
- while (tls->num_local_queue > 0) {
- /* We pop task from queue before handling it so handler of the task can
- * push next job to the local queue.
- */
- tls->num_local_queue--;
- Task *local_task = tls->local_queue[tls->num_local_queue];
- /* TODO(sergey): Double-check work_and_wait() doesn't handle other's
- * pool tasks.
- */
- TaskPool *local_pool = local_task->pool;
- local_task->run(local_pool, local_task->taskdata, thread_id);
- task_free(local_pool, local_task, thread_id);
- }
- BLI_assert(!tls->do_delayed_push);
-}
-
-static void *task_scheduler_thread_run(void *thread_p)
-{
- TaskThread *thread = (TaskThread *)thread_p;
- TaskThreadLocalStorage *tls = &thread->tls;
- TaskScheduler *scheduler = thread->scheduler;
- int thread_id = thread->id;
- Task *task;
-
- pthread_setspecific(scheduler->tls_id_key, thread);
-
- /* signal the main thread when all threads have started */
- BLI_mutex_lock(&scheduler->startup_mutex);
- scheduler->num_thread_started++;
- if (scheduler->num_thread_started == scheduler->num_threads) {
- BLI_condition_notify_one(&scheduler->startup_cond);
- }
- BLI_mutex_unlock(&scheduler->startup_mutex);
-
- /* keep popping off tasks */
- while (task_scheduler_thread_wait_pop(scheduler, &task)) {
- TaskPool *pool = task->pool;
-
- /* run task */
- BLI_assert(!tls->do_delayed_push);
- task->run(pool, task->taskdata, thread_id);
- BLI_assert(!tls->do_delayed_push);
-
- /* delete task */
- task_free(pool, task, thread_id);
-
- /* Handle all tasks from local queue. */
- handle_local_queue(tls, thread_id);
-
- /* notify pool task was done */
- task_pool_num_decrease(pool, 1);
- }
-
- return NULL;
-}
-
-TaskScheduler *BLI_task_scheduler_create(int num_threads)
-{
- TaskScheduler *scheduler = MEM_callocN(sizeof(TaskScheduler), "TaskScheduler");
-
- /* multiple places can use this task scheduler, sharing the same
- * threads, so we keep track of the number of users. */
- scheduler->do_exit = false;
-
- BLI_listbase_clear(&scheduler->queue);
- BLI_mutex_init(&scheduler->queue_mutex);
- BLI_condition_init(&scheduler->queue_cond);
-
- BLI_mutex_init(&scheduler->startup_mutex);
- BLI_condition_init(&scheduler->startup_cond);
- scheduler->num_thread_started = 0;
-
- if (num_threads == 0) {
- /* automatic number of threads will be main thread + num cores */
- num_threads = BLI_system_thread_count();
- }
-
- /* main thread will also work, so we count it too */
- num_threads -= 1;
-
- /* Add background-only thread if needed. */
- if (num_threads == 0) {
- scheduler->background_thread_only = true;
- num_threads = 1;
- }
-
- scheduler->task_threads = MEM_mallocN(sizeof(TaskThread) * (num_threads + 1),
- "TaskScheduler task threads");
-
- /* Initialize TLS for main thread. */
- initialize_task_tls(&scheduler->task_threads[0].tls);
-
- pthread_key_create(&scheduler->tls_id_key, NULL);
-
- /* launch threads that will be waiting for work */
- if (num_threads > 0) {
- int i;
-
- scheduler->num_threads = num_threads;
- scheduler->threads = MEM_callocN(sizeof(pthread_t) * num_threads, "TaskScheduler threads");
-
- for (i = 0; i < num_threads; i++) {
- TaskThread *thread = &scheduler->task_threads[i + 1];
- thread->scheduler = scheduler;
- thread->id = i + 1;
- initialize_task_tls(&thread->tls);
-
- if (pthread_create(&scheduler->threads[i], NULL, task_scheduler_thread_run, thread) != 0) {
- fprintf(stderr, "TaskScheduler failed to launch thread %d/%d\n", i, num_threads);
- }
- }
- }
-
- /* Wait for all worker threads to start before returning to caller to prevent the case where
- * threads are still starting and pthread_join is called, which causes a deadlock on pthreads4w.
- */
- BLI_mutex_lock(&scheduler->startup_mutex);
- /* NOTE: Use loop here to avoid false-positive everything-is-ready caused by spontaneous thread
- * wake up. */
- while (scheduler->num_thread_started != num_threads) {
- BLI_condition_wait(&scheduler->startup_cond, &scheduler->startup_mutex);
- }
- BLI_mutex_unlock(&scheduler->startup_mutex);
-
- return scheduler;
-}
-
-void BLI_task_scheduler_free(TaskScheduler *scheduler)
-{
- Task *task;
-
- /* stop all waiting threads */
- BLI_mutex_lock(&scheduler->queue_mutex);
- scheduler->do_exit = true;
- BLI_condition_notify_all(&scheduler->queue_cond);
- BLI_mutex_unlock(&scheduler->queue_mutex);
-
- pthread_key_delete(scheduler->tls_id_key);
-
- /* delete threads */
- if (scheduler->threads) {
- int i;
-
- for (i = 0; i < scheduler->num_threads; i++) {
- if (pthread_join(scheduler->threads[i], NULL) != 0) {
- fprintf(stderr, "TaskScheduler failed to join thread %d/%d\n", i, scheduler->num_threads);
- }
- }
-
- MEM_freeN(scheduler->threads);
- }
-
- /* Delete task thread data */
- if (scheduler->task_threads) {
- for (int i = 0; i < scheduler->num_threads + 1; i++) {
- TaskThreadLocalStorage *tls = &scheduler->task_threads[i].tls;
- free_task_tls(tls);
- }
-
- MEM_freeN(scheduler->task_threads);
- }
-
- /* delete leftover tasks */
- for (task = scheduler->queue.first; task; task = task->next) {
- task_data_free(task, 0);
- }
- BLI_freelistN(&scheduler->queue);
-
- /* delete mutex/condition */
- BLI_mutex_end(&scheduler->queue_mutex);
- BLI_condition_end(&scheduler->queue_cond);
- BLI_mutex_end(&scheduler->startup_mutex);
- BLI_condition_end(&scheduler->startup_cond);
-
- MEM_freeN(scheduler);
-}
-
-int BLI_task_scheduler_num_threads(TaskScheduler *scheduler)
-{
- return scheduler->num_threads + 1;
-}
-
-static void task_scheduler_push(TaskScheduler *scheduler, Task *task, TaskPriority priority)
-{
- task_pool_num_increase(task->pool, 1);
-
- /* add task to queue */
- BLI_mutex_lock(&scheduler->queue_mutex);
-
- if (priority == TASK_PRIORITY_HIGH) {
- BLI_addhead(&scheduler->queue, task);
- }
- else {
- BLI_addtail(&scheduler->queue, task);
- }
-
- BLI_condition_notify_one(&scheduler->queue_cond);
- BLI_mutex_unlock(&scheduler->queue_mutex);
-}
-
-static void task_scheduler_push_all(TaskScheduler *scheduler,
- TaskPool *pool,
- Task **tasks,
- int num_tasks)
-{
- if (num_tasks == 0) {
- return;
- }
-
- task_pool_num_increase(pool, num_tasks);
-
- BLI_mutex_lock(&scheduler->queue_mutex);
-
- for (int i = 0; i < num_tasks; i++) {
- BLI_addhead(&scheduler->queue, tasks[i]);
- }
-
- BLI_condition_notify_all(&scheduler->queue_cond);
- BLI_mutex_unlock(&scheduler->queue_mutex);
-}
-
-static void task_scheduler_clear(TaskScheduler *scheduler, TaskPool *pool)
-{
- Task *task, *nexttask;
- size_t done = 0;
-
- BLI_mutex_lock(&scheduler->queue_mutex);
-
- /* free all tasks from this pool from the queue */
- for (task = scheduler->queue.first; task; task = nexttask) {
- nexttask = task->next;
-
- if (task->pool == pool) {
- task_data_free(task, pool->thread_id);
- BLI_freelinkN(&scheduler->queue, task);
-
- done++;
- }
- }
-
- BLI_mutex_unlock(&scheduler->queue_mutex);
-
- /* notify done */
- task_pool_num_decrease(pool, done);
-}
-
-/* Task Pool */
-
-static TaskPool *task_pool_create_ex(TaskScheduler *scheduler,
- void *userdata,
- const bool is_background,
- const bool is_suspended)
-{
- TaskPool *pool = MEM_mallocN(sizeof(TaskPool), "TaskPool");
-
-#ifndef NDEBUG
- /* Assert we do not try to create a background pool from some parent task -
- * those only work OK from main thread. */
- if (is_background) {
- const pthread_t thread_id = pthread_self();
- int i = scheduler->num_threads;
-
- while (i--) {
- BLI_assert(!pthread_equal(scheduler->threads[i], thread_id));
- }
- }
-#endif
-
- pool->scheduler = scheduler;
- pool->num = 0;
- pool->do_cancel = false;
- pool->do_work = false;
- pool->is_suspended = is_suspended;
- pool->start_suspended = is_suspended;
- pool->num_suspended = 0;
- pool->suspended_queue.first = pool->suspended_queue.last = NULL;
- pool->run_in_background = is_background;
- pool->use_local_tls = false;
-
- BLI_mutex_init(&pool->num_mutex);
- BLI_condition_init(&pool->num_cond);
-
- pool->userdata = userdata;
- BLI_mutex_init(&pool->user_mutex);
-
- if (BLI_thread_is_main()) {
- pool->thread_id = 0;
- }
- else {
- TaskThread *thread = pthread_getspecific(scheduler->tls_id_key);
- if (thread == NULL) {
- /* NOTE: Task pool is created from non-main thread which is not
- * managed by the task scheduler. We identify ourselves as thread ID
- * 0 but we do not use scheduler's TLS storage and use our own
- * instead to avoid any possible threading conflicts.
- */
- pool->thread_id = 0;
- pool->use_local_tls = true;
-#ifndef NDEBUG
- pool->creator_thread_id = pthread_self();
-#endif
- initialize_task_tls(&pool->local_tls);
- }
- else {
- pool->thread_id = thread->id;
- }
- }
-
-#ifdef DEBUG_STATS
- pool->mempool_stats = MEM_callocN(sizeof(*pool->mempool_stats) * (scheduler->num_threads + 1),
- "per-taskpool mempool stats");
-#endif
-
- /* Ensure malloc will go fine from threads,
- *
- * This is needed because we could be in main thread here
- * and malloc could be non-thread safe at this point because
- * no other jobs are running.
- */
- BLI_threaded_malloc_begin();
-
- return pool;
-}
-
-/**
- * Create a normal task pool. Tasks will be executed as soon as they are added.
- */
-TaskPool *BLI_task_pool_create(TaskScheduler *scheduler, void *userdata)
-{
- return task_pool_create_ex(scheduler, userdata, false, false);
-}
-
-/**
- * Create a background task pool.
- * In multi-threaded context, there is no differences with #BLI_task_pool_create(),
- * but in single-threaded case it is ensured to have at least one worker thread to run on
- * (i.e. you don't have to call #BLI_task_pool_work_and_wait
- * on it to be sure it will be processed).
- *
- * \note Background pools are non-recursive
- * (that is, you should not create other background pools in tasks assigned to a background pool,
- * they could end never being executed, since the 'fallback' background thread is already
- * busy with parent task in single-threaded context).
- */
-TaskPool *BLI_task_pool_create_background(TaskScheduler *scheduler, void *userdata)
-{
- return task_pool_create_ex(scheduler, userdata, true, false);
-}
-
-/**
- * Similar to BLI_task_pool_create() but does not schedule any tasks for execution
- * for until BLI_task_pool_work_and_wait() is called. This helps reducing threading
- * overhead when pushing huge amount of small initial tasks from the main thread.
- */
-TaskPool *BLI_task_pool_create_suspended(TaskScheduler *scheduler, void *userdata)
-{
- return task_pool_create_ex(scheduler, userdata, false, true);
-}
-
-void BLI_task_pool_free(TaskPool *pool)
-{
- BLI_task_pool_cancel(pool);
-
- BLI_mutex_end(&pool->num_mutex);
- BLI_condition_end(&pool->num_cond);
-
- BLI_mutex_end(&pool->user_mutex);
-
-#ifdef DEBUG_STATS
- printf("Thread ID Allocated Reused Discarded\n");
- for (int i = 0; i < pool->scheduler->num_threads + 1; i++) {
- printf("%02d %05d %05d %05d\n",
- i,
- pool->mempool_stats[i].num_alloc,
- pool->mempool_stats[i].num_reuse,
- pool->mempool_stats[i].num_discard);
- }
- MEM_freeN(pool->mempool_stats);
-#endif
-
- if (pool->use_local_tls) {
- free_task_tls(&pool->local_tls);
- }
-
- MEM_freeN(pool);
-
- BLI_threaded_malloc_end();
-}
-
-BLI_INLINE bool task_can_use_local_queues(TaskPool *pool, int thread_id)
-{
- return (thread_id != -1 && (thread_id != pool->thread_id || pool->do_work));
-}
-
-static void task_pool_push(TaskPool *pool,
- TaskRunFunction run,
- void *taskdata,
- bool free_taskdata,
- TaskFreeFunction freedata,
- TaskPriority priority,
- int thread_id)
-{
- /* Allocate task and fill it's properties. */
- Task *task = task_alloc(pool, thread_id);
- task->run = run;
- task->taskdata = taskdata;
- task->free_taskdata = free_taskdata;
- task->freedata = freedata;
- task->pool = pool;
- /* For suspended pools we put everything yo a global queue first
- * and exit as soon as possible.
- *
- * This tasks will be moved to actual execution when pool is
- * activated by work_and_wait().
- */
- if (pool->is_suspended) {
- BLI_addhead(&pool->suspended_queue, task);
- atomic_fetch_and_add_z(&pool->num_suspended, 1);
- return;
- }
- /* Populate to any local queue first, this is cheapest push ever. */
- if (task_can_use_local_queues(pool, thread_id)) {
- ASSERT_THREAD_ID(pool->scheduler, thread_id);
- TaskThreadLocalStorage *tls = get_task_tls(pool, thread_id);
- /* Try to push to a local execution queue.
- * These tasks will be picked up next.
- */
- if (tls->num_local_queue < LOCAL_QUEUE_SIZE) {
- tls->local_queue[tls->num_local_queue] = task;
- tls->num_local_queue++;
- return;
- }
- /* If we are in the delayed tasks push mode, we push tasks to a
- * temporary local queue first without any locks, and then move them
- * to global execution queue with a single lock.
- */
- if (tls->do_delayed_push && tls->num_delayed_queue < DELAYED_QUEUE_SIZE) {
- tls->delayed_queue[tls->num_delayed_queue] = task;
- tls->num_delayed_queue++;
- return;
- }
- }
- /* Do push to a global execution pool, slowest possible method,
- * causes quite reasonable amount of threading overhead.
- */
- task_scheduler_push(pool->scheduler, task, priority);
-}
-
-void BLI_task_pool_push_ex(TaskPool *pool,
- TaskRunFunction run,
- void *taskdata,
- bool free_taskdata,
- TaskFreeFunction freedata,
- TaskPriority priority)
-{
- task_pool_push(pool, run, taskdata, free_taskdata, freedata, priority, -1);
-}
-
-void BLI_task_pool_push(
- TaskPool *pool, TaskRunFunction run, void *taskdata, bool free_taskdata, TaskPriority priority)
-{
- BLI_task_pool_push_ex(pool, run, taskdata, free_taskdata, NULL, priority);
-}
-
-void BLI_task_pool_push_from_thread(TaskPool *pool,
- TaskRunFunction run,
- void *taskdata,
- bool free_taskdata,
- TaskPriority priority,
- int thread_id)
-{
- task_pool_push(pool, run, taskdata, free_taskdata, NULL, priority, thread_id);
-}
-
-void BLI_task_pool_work_and_wait(TaskPool *pool)
-{
- TaskThreadLocalStorage *tls = get_task_tls(pool, pool->thread_id);
- TaskScheduler *scheduler = pool->scheduler;
-
- if (atomic_fetch_and_and_uint8((uint8_t *)&pool->is_suspended, 0)) {
- if (pool->num_suspended) {
- task_pool_num_increase(pool, pool->num_suspended);
- BLI_mutex_lock(&scheduler->queue_mutex);
-
- BLI_movelisttolist(&scheduler->queue, &pool->suspended_queue);
-
- BLI_condition_notify_all(&scheduler->queue_cond);
- BLI_mutex_unlock(&scheduler->queue_mutex);
-
- pool->num_suspended = 0;
- }
- }
-
- pool->do_work = true;
-
- ASSERT_THREAD_ID(pool->scheduler, pool->thread_id);
-
- handle_local_queue(tls, pool->thread_id);
-
- BLI_mutex_lock(&pool->num_mutex);
-
- while (pool->num != 0) {
- Task *task, *work_task = NULL;
- bool found_task = false;
-
- BLI_mutex_unlock(&pool->num_mutex);
-
- BLI_mutex_lock(&scheduler->queue_mutex);
-
- /* find task from this pool. if we get a task from another pool,
- * we can get into deadlock */
-
- for (task = scheduler->queue.first; task; task = task->next) {
- if (task->pool == pool) {
- work_task = task;
- found_task = true;
- BLI_remlink(&scheduler->queue, task);
- break;
- }
- }
-
- BLI_mutex_unlock(&scheduler->queue_mutex);
-
- /* if found task, do it, otherwise wait until other tasks are done */
- if (found_task) {
- /* run task */
- BLI_assert(!tls->do_delayed_push);
- work_task->run(pool, work_task->taskdata, pool->thread_id);
- BLI_assert(!tls->do_delayed_push);
-
- /* delete task */
- task_free(pool, task, pool->thread_id);
-
- /* Handle all tasks from local queue. */
- handle_local_queue(tls, pool->thread_id);
-
- /* notify pool task was done */
- task_pool_num_decrease(pool, 1);
- }
-
- BLI_mutex_lock(&pool->num_mutex);
- if (pool->num == 0) {
- break;
- }
-
- if (!found_task) {
- BLI_condition_wait(&pool->num_cond, &pool->num_mutex);
- }
- }
-
- BLI_mutex_unlock(&pool->num_mutex);
-
- BLI_assert(tls->num_local_queue == 0);
-}
-
-void BLI_task_pool_work_wait_and_reset(TaskPool *pool)
-{
- BLI_task_pool_work_and_wait(pool);
-
- pool->do_work = false;
- pool->is_suspended = pool->start_suspended;
-}
-
-void BLI_task_pool_cancel(TaskPool *pool)
-{
- pool->do_cancel = true;
-
- task_scheduler_clear(pool->scheduler, pool);
-
- /* wait until all entries are cleared */
- BLI_mutex_lock(&pool->num_mutex);
- while (pool->num) {
- BLI_condition_wait(&pool->num_cond, &pool->num_mutex);
- }
- BLI_mutex_unlock(&pool->num_mutex);
-
- pool->do_cancel = false;
-}
-
-bool BLI_task_pool_canceled(TaskPool *pool)
-{
- return pool->do_cancel;
-}
-
-void *BLI_task_pool_userdata(TaskPool *pool)
-{
- return pool->userdata;
-}
-
-ThreadMutex *BLI_task_pool_user_mutex(TaskPool *pool)
-{
- return &pool->user_mutex;
-}
-
-void BLI_task_pool_delayed_push_begin(TaskPool *pool, int thread_id)
-{
- if (task_can_use_local_queues(pool, thread_id)) {
- ASSERT_THREAD_ID(pool->scheduler, thread_id);
- TaskThreadLocalStorage *tls = get_task_tls(pool, thread_id);
- tls->do_delayed_push = true;
- }
-}
-
-void BLI_task_pool_delayed_push_end(TaskPool *pool, int thread_id)
-{
- if (task_can_use_local_queues(pool, thread_id)) {
- ASSERT_THREAD_ID(pool->scheduler, thread_id);
- TaskThreadLocalStorage *tls = get_task_tls(pool, thread_id);
- BLI_assert(tls->do_delayed_push);
- task_scheduler_push_all(pool->scheduler, pool, tls->delayed_queue, tls->num_delayed_queue);
- tls->do_delayed_push = false;
- tls->num_delayed_queue = 0;
- }
-}
-
-/* Parallel range routines */
-
-/**
- *
- * Main functions:
- * - #BLI_task_parallel_range
- * - #BLI_task_parallel_listbase (#ListBase - double linked list)
- *
- * TODO:
- * - #BLI_task_parallel_foreach_link (#Link - single linked list)
- * - #BLI_task_parallel_foreach_ghash/gset (#GHash/#GSet - hash & set)
- * - #BLI_task_parallel_foreach_mempool (#BLI_mempool - iterate over mempools)
- */
-
-/* Allows to avoid using malloc for userdata_chunk in tasks, when small enough. */
-#define MALLOCA(_size) ((_size) <= 8192) ? alloca((_size)) : MEM_mallocN((_size), __func__)
-#define MALLOCA_FREE(_mem, _size) \
- if (((_mem) != NULL) && ((_size) > 8192)) \
- MEM_freeN((_mem))
-
-/* Stores all needed data to perform a parallelized iteration,
- * with a same operation (callback function).
- * It can be chained with other tasks in a single-linked list way. */
-typedef struct TaskParallelRangeState {
- struct TaskParallelRangeState *next;
-
- /* Start and end point of integer value iteration. */
- int start, stop;
-
- /* User-defined data, shared between all worker threads. */
- void *userdata_shared;
- /* User-defined callback function called for each value in [start, stop[ specified range. */
- TaskParallelRangeFunc func;
-
- /* Each instance of looping chunks will get a copy of this data
- * (similar to OpenMP's firstprivate).
- */
- void *initial_tls_memory; /* Pointer to actual user-defined 'tls' data. */
- size_t tls_data_size; /* Size of that data. */
-
- void *flatten_tls_storage; /* 'tls' copies of initial_tls_memory for each running task. */
- /* Number of 'tls' copies in the array, i.e. number of worker threads. */
- size_t num_elements_in_tls_storage;
-
- /* Function called from calling thread once whole range have been processed. */
- TaskParallelFinalizeFunc func_finalize;
-
- /* Current value of the iterator, shared between all threads (atomically updated). */
- int iter_value;
- int iter_chunk_num; /* Amount of iterations to process in a single step. */
-} TaskParallelRangeState;
-
-/* Stores all the parallel tasks for a single pool. */
-typedef struct TaskParallelRangePool {
- /* The workers' task pool. */
- TaskPool *pool;
- /* The number of worker tasks we need to create. */
- int num_tasks;
- /* The total number of iterations in all the added ranges. */
- int num_total_iters;
- /* The size (number of items) processed at once by a worker task. */
- int chunk_size;
-
- /* Linked list of range tasks to process. */
- TaskParallelRangeState *parallel_range_states;
- /* Current range task beeing processed, swapped atomically. */
- TaskParallelRangeState *current_state;
- /* Scheduling settings common to all tasks. */
- TaskParallelSettings *settings;
-} TaskParallelRangePool;
-
-BLI_INLINE void task_parallel_calc_chunk_size(const TaskParallelSettings *settings,
- const int tot_items,
- int num_tasks,
- int *r_chunk_size)
-{
- int chunk_size = 0;
-
- if (!settings->use_threading) {
- /* Some users of this helper will still need a valid chunk size in case processing is not
- * threaded. We can use a bigger one than in default threaded case then. */
- chunk_size = 1024;
- num_tasks = 1;
- }
- else if (settings->min_iter_per_thread > 0) {
- /* Already set by user, no need to do anything here. */
- chunk_size = settings->min_iter_per_thread;
- }
- else {
- /* Multiplier used in heuristics below to define "optimal" chunk size.
- * The idea here is to increase the chunk size to compensate for a rather measurable threading
- * overhead caused by fetching tasks. With too many CPU threads we are starting
- * to spend too much time in those overheads.
- * First values are: 1 if num_tasks < 16;
- * else 2 if num_tasks < 32;
- * else 3 if num_tasks < 48;
- * else 4 if num_tasks < 64;
- * etc.
- * Note: If we wanted to keep the 'power of two' multiplier, we'd need something like:
- * 1 << max_ii(0, (int)(sizeof(int) * 8) - 1 - bitscan_reverse_i(num_tasks) - 3)
- */
- const int num_tasks_factor = max_ii(1, num_tasks >> 3);
-
- /* We could make that 'base' 32 number configurable in TaskParallelSettings too, or maybe just
- * always use that heuristic using TaskParallelSettings.min_iter_per_thread as basis? */
- chunk_size = 32 * num_tasks_factor;
-
- /* Basic heuristic to avoid threading on low amount of items.
- * We could make that limit configurable in settings too. */
- if (tot_items > 0 && tot_items < max_ii(256, chunk_size * 2)) {
- chunk_size = tot_items;
- }
- }
-
- BLI_assert(chunk_size > 0);
-
- if (tot_items > 0) {
- switch (settings->scheduling_mode) {
- case TASK_SCHEDULING_STATIC:
- *r_chunk_size = max_ii(chunk_size, tot_items / num_tasks);
- break;
- case TASK_SCHEDULING_DYNAMIC:
- *r_chunk_size = chunk_size;
- break;
- }
- }
- else {
- /* If total amount of items is unknown, we can only use dynamic scheduling. */
- *r_chunk_size = chunk_size;
- }
-}
-
-BLI_INLINE void task_parallel_range_calc_chunk_size(TaskParallelRangePool *range_pool)
-{
- int num_iters = 0;
- int min_num_iters = INT_MAX;
- for (TaskParallelRangeState *state = range_pool->parallel_range_states; state != NULL;
- state = state->next) {
- const int ni = state->stop - state->start;
- num_iters += ni;
- if (min_num_iters > ni) {
- min_num_iters = ni;
- }
- }
- range_pool->num_total_iters = num_iters;
- /* Note: Passing min_num_iters here instead of num_iters kind of partially breaks the 'static'
- * scheduling, but pooled range iterator is inherently non-static anyway, so adding a small level
- * of dynamic scheduling here should be fine. */
- task_parallel_calc_chunk_size(
- range_pool->settings, min_num_iters, range_pool->num_tasks, &range_pool->chunk_size);
-}
-
-BLI_INLINE bool parallel_range_next_iter_get(TaskParallelRangePool *__restrict range_pool,
- int *__restrict r_iter,
- int *__restrict r_count,
- TaskParallelRangeState **__restrict r_state)
-{
- /* We need an atomic op here as well to fetch the initial state, since some other thread might
- * have already updated it. */
- TaskParallelRangeState *current_state = atomic_cas_ptr(
- (void **)&range_pool->current_state, NULL, NULL);
-
- int previter = INT32_MAX;
-
- while (current_state != NULL && previter >= current_state->stop) {
- previter = atomic_fetch_and_add_int32(&current_state->iter_value, range_pool->chunk_size);
- *r_iter = previter;
- *r_count = max_ii(0, min_ii(range_pool->chunk_size, current_state->stop - previter));
-
- if (previter >= current_state->stop) {
- /* At this point the state we got is done, we need to go to the next one. In case some other
- * thread already did it, then this does nothing, and we'll just get current valid state
- * at start of the next loop. */
- TaskParallelRangeState *current_state_from_atomic_cas = atomic_cas_ptr(
- (void **)&range_pool->current_state, current_state, current_state->next);
-
- if (current_state == current_state_from_atomic_cas) {
- /* The atomic CAS operation was successful, we did update range_pool->current_state, so we
- * can safely switch to next state. */
- current_state = current_state->next;
- }
- else {
- /* The atomic CAS operation failed, but we still got range_pool->current_state value out of
- * it, just use it as our new current state. */
- current_state = current_state_from_atomic_cas;
- }
- }
- }
-
- *r_state = current_state;
- return (current_state != NULL && previter < current_state->stop);
-}
-
-static void parallel_range_func(TaskPool *__restrict pool, void *tls_data_idx, int thread_id)
-{
- TaskParallelRangePool *__restrict range_pool = BLI_task_pool_userdata(pool);
- TaskParallelTLS tls = {
- .thread_id = thread_id,
- .userdata_chunk = NULL,
- };
- TaskParallelRangeState *state;
- int iter, count;
- while (parallel_range_next_iter_get(range_pool, &iter, &count, &state)) {
- tls.userdata_chunk = (char *)state->flatten_tls_storage +
- (((size_t)POINTER_AS_INT(tls_data_idx)) * state->tls_data_size);
- for (int i = 0; i < count; i++) {
- state->func(state->userdata_shared, iter + i, &tls);
- }
- }
-}
-
-static void parallel_range_single_thread(TaskParallelRangePool *range_pool)
-{
- for (TaskParallelRangeState *state = range_pool->parallel_range_states; state != NULL;
- state = state->next) {
- const int start = state->start;
- const int stop = state->stop;
- void *userdata = state->userdata_shared;
- TaskParallelRangeFunc func = state->func;
-
- void *initial_tls_memory = state->initial_tls_memory;
- const size_t tls_data_size = state->tls_data_size;
- void *flatten_tls_storage = NULL;
- const bool use_tls_data = (tls_data_size != 0) && (initial_tls_memory != NULL);
- if (use_tls_data) {
- flatten_tls_storage = MALLOCA(tls_data_size);
- memcpy(flatten_tls_storage, initial_tls_memory, tls_data_size);
- }
- TaskParallelTLS tls = {
- .thread_id = 0,
- .userdata_chunk = flatten_tls_storage,
- };
- for (int i = start; i < stop; i++) {
- func(userdata, i, &tls);
- }
- if (state->func_finalize != NULL) {
- state->func_finalize(userdata, flatten_tls_storage);
- }
- MALLOCA_FREE(flatten_tls_storage, tls_data_size);
- }
-}
-
-/**
- * This function allows to parallelized for loops in a similar way to OpenMP's
- * 'parallel for' statement.
- *
- * See public API doc of ParallelRangeSettings for description of all settings.
- */
-void BLI_task_parallel_range(const int start,
- const int stop,
- void *userdata,
- TaskParallelRangeFunc func,
- TaskParallelSettings *settings)
-{
- if (start == stop) {
- return;
- }
-
- BLI_assert(start < stop);
-
- TaskParallelRangeState state = {
- .next = NULL,
- .start = start,
- .stop = stop,
- .userdata_shared = userdata,
- .func = func,
- .iter_value = start,
- .initial_tls_memory = settings->userdata_chunk,
- .tls_data_size = settings->userdata_chunk_size,
- .func_finalize = settings->func_finalize,
- };
- TaskParallelRangePool range_pool = {
- .pool = NULL, .parallel_range_states = &state, .current_state = NULL, .settings = settings};
- int i, num_threads, num_tasks;
-
- void *tls_data = settings->userdata_chunk;
- const size_t tls_data_size = settings->userdata_chunk_size;
- if (tls_data_size != 0) {
- BLI_assert(tls_data != NULL);
- }
- const bool use_tls_data = (tls_data_size != 0) && (tls_data != NULL);
- void *flatten_tls_storage = NULL;
-
- /* If it's not enough data to be crunched, don't bother with tasks at all,
- * do everything from the current thread.
- */
- if (!settings->use_threading) {
- parallel_range_single_thread(&range_pool);
- return;
- }
-
- TaskScheduler *task_scheduler = BLI_task_scheduler_get();
- num_threads = BLI_task_scheduler_num_threads(task_scheduler);
-
- /* The idea here is to prevent creating task for each of the loop iterations
- * and instead have tasks which are evenly distributed across CPU cores and
- * pull next iter to be crunched using the queue.
- */
- range_pool.num_tasks = num_tasks = num_threads + 2;
-
- task_parallel_range_calc_chunk_size(&range_pool);
- range_pool.num_tasks = num_tasks = min_ii(num_tasks,
- max_ii(1, (stop - start) / range_pool.chunk_size));
-
- if (num_tasks == 1) {
- parallel_range_single_thread(&range_pool);
- return;
- }
-
- TaskPool *task_pool = range_pool.pool = BLI_task_pool_create_suspended(task_scheduler,
- &range_pool);
-
- range_pool.current_state = &state;
-
- if (use_tls_data) {
- state.flatten_tls_storage = flatten_tls_storage = MALLOCA(tls_data_size * (size_t)num_tasks);
- state.tls_data_size = tls_data_size;
- }
-
- for (i = 0; i < num_tasks; i++) {
- if (use_tls_data) {
- void *userdata_chunk_local = (char *)flatten_tls_storage + (tls_data_size * (size_t)i);
- memcpy(userdata_chunk_local, tls_data, tls_data_size);
- }
- /* Use this pool's pre-allocated tasks. */
- BLI_task_pool_push_from_thread(task_pool,
- parallel_range_func,
- POINTER_FROM_INT(i),
- false,
- TASK_PRIORITY_HIGH,
- task_pool->thread_id);
- }
-
- BLI_task_pool_work_and_wait(task_pool);
- BLI_task_pool_free(task_pool);
-
- if (use_tls_data) {
- if (settings->func_finalize != NULL) {
- for (i = 0; i < num_tasks; i++) {
- void *userdata_chunk_local = (char *)flatten_tls_storage + (tls_data_size * (size_t)i);
- settings->func_finalize(userdata, userdata_chunk_local);
- }
- }
- MALLOCA_FREE(flatten_tls_storage, tls_data_size * (size_t)num_tasks);
- }
-}
-
-/**
- * Initialize a task pool to parallelize several for loops at the same time.
- *
- * See public API doc of ParallelRangeSettings for description of all settings.
- * Note that loop-specific settings (like 'tls' data or finalize function) must be left NULL here.
- * Only settings controlling how iteration is parallelized must be defined, as those will affect
- * all loops added to that pool.
- */
-TaskParallelRangePool *BLI_task_parallel_range_pool_init(const TaskParallelSettings *settings)
-{
- TaskParallelRangePool *range_pool = MEM_callocN(sizeof(*range_pool), __func__);
-
- BLI_assert(settings->userdata_chunk == NULL);
- BLI_assert(settings->func_finalize == NULL);
- range_pool->settings = MEM_mallocN(sizeof(*range_pool->settings), __func__);
- *range_pool->settings = *settings;
-
- return range_pool;
-}
-
-/**
- * Add a loop task to the pool. It does not execute it at all.
- *
- * See public API doc of ParallelRangeSettings for description of all settings.
- * Note that only 'tls'-related data are used here.
- */
-void BLI_task_parallel_range_pool_push(TaskParallelRangePool *range_pool,
- const int start,
- const int stop,
- void *userdata,
- TaskParallelRangeFunc func,
- const TaskParallelSettings *settings)
-{
- BLI_assert(range_pool->pool == NULL);
-
- if (start == stop) {
- return;
- }
-
- BLI_assert(start < stop);
- if (settings->userdata_chunk_size != 0) {
- BLI_assert(settings->userdata_chunk != NULL);
- }
-
- TaskParallelRangeState *state = MEM_callocN(sizeof(*state), __func__);
- state->start = start;
- state->stop = stop;
- state->userdata_shared = userdata;
- state->func = func;
- state->iter_value = start;
- state->initial_tls_memory = settings->userdata_chunk;
- state->tls_data_size = settings->userdata_chunk_size;
- state->func_finalize = settings->func_finalize;
-
- state->next = range_pool->parallel_range_states;
- range_pool->parallel_range_states = state;
-}
-
-static void parallel_range_func_finalize(TaskPool *__restrict pool,
- void *v_state,
- int UNUSED(thread_id))
-{
- TaskParallelRangePool *__restrict range_pool = BLI_task_pool_userdata(pool);
- TaskParallelRangeState *state = v_state;
-
- for (int i = 0; i < range_pool->num_tasks; i++) {
- void *tls_data = (char *)state->flatten_tls_storage + (state->tls_data_size * (size_t)i);
- state->func_finalize(state->userdata_shared, tls_data);
- }
-}
-
-/**
- * Run all tasks pushed to the range_pool.
- *
- * Note that the range pool is re-usable (you may push new tasks into it and call this function
- * again).
- */
-void BLI_task_parallel_range_pool_work_and_wait(TaskParallelRangePool *range_pool)
-{
- BLI_assert(range_pool->pool == NULL);
-
- /* If it's not enough data to be crunched, don't bother with tasks at all,
- * do everything from the current thread.
- */
- if (!range_pool->settings->use_threading) {
- parallel_range_single_thread(range_pool);
- return;
- }
-
- TaskScheduler *task_scheduler = BLI_task_scheduler_get();
- const int num_threads = BLI_task_scheduler_num_threads(task_scheduler);
-
- /* The idea here is to prevent creating task for each of the loop iterations
- * and instead have tasks which are evenly distributed across CPU cores and
- * pull next iter to be crunched using the queue.
- */
- int num_tasks = num_threads + 2;
- range_pool->num_tasks = num_tasks;
-
- task_parallel_range_calc_chunk_size(range_pool);
- range_pool->num_tasks = num_tasks = min_ii(
- num_tasks, max_ii(1, range_pool->num_total_iters / range_pool->chunk_size));
-
- if (num_tasks == 1) {
- parallel_range_single_thread(range_pool);
- return;
- }
-
- /* We create all 'tls' data here in a single loop. */
- for (TaskParallelRangeState *state = range_pool->parallel_range_states; state != NULL;
- state = state->next) {
- void *userdata_chunk = state->initial_tls_memory;
- const size_t userdata_chunk_size = state->tls_data_size;
- if (userdata_chunk_size == 0) {
- BLI_assert(userdata_chunk == NULL);
- continue;
- }
-
- void *userdata_chunk_array = NULL;
- state->flatten_tls_storage = userdata_chunk_array = MALLOCA(userdata_chunk_size *
- (size_t)num_tasks);
- for (int i = 0; i < num_tasks; i++) {
- void *userdata_chunk_local = (char *)userdata_chunk_array +
- (userdata_chunk_size * (size_t)i);
- memcpy(userdata_chunk_local, userdata_chunk, userdata_chunk_size);
- }
- }
-
- TaskPool *task_pool = range_pool->pool = BLI_task_pool_create_suspended(task_scheduler,
- range_pool);
-
- range_pool->current_state = range_pool->parallel_range_states;
-
- for (int i = 0; i < num_tasks; i++) {
- BLI_task_pool_push_from_thread(task_pool,
- parallel_range_func,
- POINTER_FROM_INT(i),
- false,
- TASK_PRIORITY_HIGH,
- task_pool->thread_id);
- }
-
- BLI_task_pool_work_and_wait(task_pool);
-
- BLI_assert(atomic_cas_ptr((void **)&range_pool->current_state, NULL, NULL) == NULL);
-
- /* Finalize all tasks. */
- for (TaskParallelRangeState *state = range_pool->parallel_range_states; state != NULL;
- state = state->next) {
- const size_t userdata_chunk_size = state->tls_data_size;
- void *userdata_chunk_array = state->flatten_tls_storage;
- UNUSED_VARS_NDEBUG(userdata_chunk_array);
- if (userdata_chunk_size == 0) {
- BLI_assert(userdata_chunk_array == NULL);
- continue;
- }
-
- if (state->func_finalize != NULL) {
- BLI_task_pool_push_from_thread(task_pool,
- parallel_range_func_finalize,
- state,
- false,
- TASK_PRIORITY_HIGH,
- task_pool->thread_id);
- }
- }
-
- BLI_task_pool_work_and_wait(task_pool);
- BLI_task_pool_free(task_pool);
- range_pool->pool = NULL;
-
- /* Cleanup all tasks. */
- TaskParallelRangeState *state_next;
- for (TaskParallelRangeState *state = range_pool->parallel_range_states; state != NULL;
- state = state_next) {
- state_next = state->next;
-
- const size_t userdata_chunk_size = state->tls_data_size;
- void *userdata_chunk_array = state->flatten_tls_storage;
- if (userdata_chunk_size != 0) {
- BLI_assert(userdata_chunk_array != NULL);
- MALLOCA_FREE(userdata_chunk_array, userdata_chunk_size * (size_t)num_tasks);
- }
-
- MEM_freeN(state);
- }
- range_pool->parallel_range_states = NULL;
-}
-
-/**
- * Clear/free given \a range_pool.
- */
-void BLI_task_parallel_range_pool_free(TaskParallelRangePool *range_pool)
-{
- TaskParallelRangeState *state_next = NULL;
- for (TaskParallelRangeState *state = range_pool->parallel_range_states; state != NULL;
- state = state_next) {
- state_next = state->next;
- MEM_freeN(state);
- }
- MEM_freeN(range_pool->settings);
- MEM_freeN(range_pool);
-}
-
-typedef struct TaskParallelIteratorState {
- void *userdata;
- TaskParallelIteratorIterFunc iter_func;
- TaskParallelIteratorFunc func;
-
- /* *** Data used to 'acquire' chunks of items from the iterator. *** */
- /* Common data also passed to the generator callback. */
- TaskParallelIteratorStateShared iter_shared;
- /* Total number of items. If unknown, set it to a negative number. */
- int tot_items;
-} TaskParallelIteratorState;
-
-BLI_INLINE void task_parallel_iterator_calc_chunk_size(const TaskParallelSettings *settings,
- const int num_tasks,
- TaskParallelIteratorState *state)
-{
- task_parallel_calc_chunk_size(
- settings, state->tot_items, num_tasks, &state->iter_shared.chunk_size);
-}
-
-static void parallel_iterator_func_do(TaskParallelIteratorState *__restrict state,
- void *userdata_chunk,
- int threadid)
-{
- TaskParallelTLS tls = {
- .thread_id = threadid,
- .userdata_chunk = userdata_chunk,
- };
-
- void **current_chunk_items;
- int *current_chunk_indices;
- int current_chunk_size;
-
- const size_t items_size = sizeof(*current_chunk_items) * (size_t)state->iter_shared.chunk_size;
- const size_t indices_size = sizeof(*current_chunk_indices) *
- (size_t)state->iter_shared.chunk_size;
-
- current_chunk_items = MALLOCA(items_size);
- current_chunk_indices = MALLOCA(indices_size);
- current_chunk_size = 0;
-
- for (bool do_abort = false; !do_abort;) {
- if (state->iter_shared.spin_lock != NULL) {
- BLI_spin_lock(state->iter_shared.spin_lock);
- }
-
- /* Get current status. */
- int index = state->iter_shared.next_index;
- void *item = state->iter_shared.next_item;
- int i;
-
- /* 'Acquire' a chunk of items from the iterator function. */
- for (i = 0; i < state->iter_shared.chunk_size && !state->iter_shared.is_finished; i++) {
- current_chunk_indices[i] = index;
- current_chunk_items[i] = item;
- state->iter_func(state->userdata, &tls, &item, &index, &state->iter_shared.is_finished);
- }
-
- /* Update current status. */
- state->iter_shared.next_index = index;
- state->iter_shared.next_item = item;
- current_chunk_size = i;
-
- do_abort = state->iter_shared.is_finished;
-
- if (state->iter_shared.spin_lock != NULL) {
- BLI_spin_unlock(state->iter_shared.spin_lock);
- }
-
- for (i = 0; i < current_chunk_size; ++i) {
- state->func(state->userdata, current_chunk_items[i], current_chunk_indices[i], &tls);
- }
- }
-
- MALLOCA_FREE(current_chunk_items, items_size);
- MALLOCA_FREE(current_chunk_indices, indices_size);
-}
-
-static void parallel_iterator_func(TaskPool *__restrict pool, void *userdata_chunk, int threadid)
-{
- TaskParallelIteratorState *__restrict state = BLI_task_pool_userdata(pool);
-
- parallel_iterator_func_do(state, userdata_chunk, threadid);
-}
-
-static void task_parallel_iterator_no_threads(const TaskParallelSettings *settings,
- TaskParallelIteratorState *state)
-{
- /* Prepare user's TLS data. */
- void *userdata_chunk = settings->userdata_chunk;
- const size_t userdata_chunk_size = settings->userdata_chunk_size;
- void *userdata_chunk_local = NULL;
- const bool use_userdata_chunk = (userdata_chunk_size != 0) && (userdata_chunk != NULL);
- if (use_userdata_chunk) {
- userdata_chunk_local = MALLOCA(userdata_chunk_size);
- memcpy(userdata_chunk_local, userdata_chunk, userdata_chunk_size);
- }
-
- /* Also marking it as non-threaded for the iterator callback. */
- state->iter_shared.spin_lock = NULL;
-
- parallel_iterator_func_do(state, userdata_chunk, 0);
-
- if (use_userdata_chunk) {
- if (settings->func_finalize != NULL) {
- settings->func_finalize(state->userdata, userdata_chunk_local);
- }
- MALLOCA_FREE(userdata_chunk_local, userdata_chunk_size);
- }
-}
-
-static void task_parallel_iterator_do(const TaskParallelSettings *settings,
- TaskParallelIteratorState *state)
-{
- TaskScheduler *task_scheduler = BLI_task_scheduler_get();
- const int num_threads = BLI_task_scheduler_num_threads(task_scheduler);
-
- task_parallel_iterator_calc_chunk_size(settings, num_threads, state);
-
- if (!settings->use_threading) {
- task_parallel_iterator_no_threads(settings, state);
- return;
- }
-
- const int chunk_size = state->iter_shared.chunk_size;
- const int tot_items = state->tot_items;
- const size_t num_tasks = tot_items >= 0 ?
- (size_t)min_ii(num_threads, state->tot_items / chunk_size) :
- (size_t)num_threads;
-
- BLI_assert(num_tasks > 0);
- if (num_tasks == 1) {
- task_parallel_iterator_no_threads(settings, state);
- return;
- }
-
- SpinLock spin_lock;
- BLI_spin_init(&spin_lock);
- state->iter_shared.spin_lock = &spin_lock;
-
- void *userdata_chunk = settings->userdata_chunk;
- const size_t userdata_chunk_size = settings->userdata_chunk_size;
- void *userdata_chunk_local = NULL;
- void *userdata_chunk_array = NULL;
- const bool use_userdata_chunk = (userdata_chunk_size != 0) && (userdata_chunk != NULL);
-
- TaskPool *task_pool = BLI_task_pool_create_suspended(task_scheduler, state);
-
- if (use_userdata_chunk) {
- userdata_chunk_array = MALLOCA(userdata_chunk_size * num_tasks);
- }
-
- for (size_t i = 0; i < num_tasks; i++) {
- if (use_userdata_chunk) {
- userdata_chunk_local = (char *)userdata_chunk_array + (userdata_chunk_size * i);
- memcpy(userdata_chunk_local, userdata_chunk, userdata_chunk_size);
- }
- /* Use this pool's pre-allocated tasks. */
- BLI_task_pool_push_from_thread(task_pool,
- parallel_iterator_func,
- userdata_chunk_local,
- false,
- TASK_PRIORITY_HIGH,
- task_pool->thread_id);
- }
-
- BLI_task_pool_work_and_wait(task_pool);
- BLI_task_pool_free(task_pool);
-
- if (use_userdata_chunk) {
- if (settings->func_finalize != NULL) {
- for (size_t i = 0; i < num_tasks; i++) {
- userdata_chunk_local = (char *)userdata_chunk_array + (userdata_chunk_size * i);
- settings->func_finalize(state->userdata, userdata_chunk_local);
- }
- }
- MALLOCA_FREE(userdata_chunk_array, userdata_chunk_size * num_tasks);
- }
-
- BLI_spin_end(&spin_lock);
- state->iter_shared.spin_lock = NULL;
-}
-
-/**
- * This function allows to parallelize for loops using a generic iterator.
- *
- * \param userdata: Common userdata passed to all instances of \a func.
- * \param iter_func: Callback function used to generate chunks of items.
- * \param init_item: The initial item, if necessary (may be NULL if unused).
- * \param init_index: The initial index.
- * \param tot_items: The total amount of items to iterate over
- * (if unknown, set it to a negative number).
- * \param func: Callback function.
- * \param settings: See public API doc of TaskParallelSettings for description of all settings.
- *
- * \note Static scheduling is only available when \a tot_items is >= 0.
- */
-
-void BLI_task_parallel_iterator(void *userdata,
- TaskParallelIteratorIterFunc iter_func,
- void *init_item,
- const int init_index,
- const int tot_items,
- TaskParallelIteratorFunc func,
- const TaskParallelSettings *settings)
-{
- TaskParallelIteratorState state = {0};
-
- state.tot_items = tot_items;
- state.iter_shared.next_index = init_index;
- state.iter_shared.next_item = init_item;
- state.iter_shared.is_finished = false;
- state.userdata = userdata;
- state.iter_func = iter_func;
- state.func = func;
-
- task_parallel_iterator_do(settings, &state);
-}
-
-static void task_parallel_listbase_get(void *__restrict UNUSED(userdata),
- const TaskParallelTLS *__restrict UNUSED(tls),
- void **r_next_item,
- int *r_next_index,
- bool *r_do_abort)
-{
- /* Get current status. */
- Link *link = *r_next_item;
-
- if (link->next == NULL) {
- *r_do_abort = true;
- }
- *r_next_item = link->next;
- (*r_next_index)++;
-}
-
-/**
- * This function allows to parallelize for loops over ListBase items.
- *
- * \param listbase: The double linked list to loop over.
- * \param userdata: Common userdata passed to all instances of \a func.
- * \param func: Callback function.
- * \param settings: See public API doc of ParallelRangeSettings for description of all settings.
- *
- * \note There is no static scheduling here,
- * since it would need another full loop over items to count them.
- */
-void BLI_task_parallel_listbase(ListBase *listbase,
- void *userdata,
- TaskParallelIteratorFunc func,
- const TaskParallelSettings *settings)
-{
- if (BLI_listbase_is_empty(listbase)) {
- return;
- }
-
- TaskParallelIteratorState state = {0};
-
- state.tot_items = BLI_listbase_count(listbase);
- state.iter_shared.next_index = 0;
- state.iter_shared.next_item = listbase->first;
- state.iter_shared.is_finished = false;
- state.userdata = userdata;
- state.iter_func = task_parallel_listbase_get;
- state.func = func;
-
- task_parallel_iterator_do(settings, &state);
-}
-
-#undef MALLOCA
-#undef MALLOCA_FREE
-
-typedef struct ParallelMempoolState {
- void *userdata;
- TaskParallelMempoolFunc func;
-} ParallelMempoolState;
-
-static void parallel_mempool_func(TaskPool *__restrict pool, void *taskdata, int UNUSED(threadid))
-{
- ParallelMempoolState *__restrict state = BLI_task_pool_userdata(pool);
- BLI_mempool_iter *iter = taskdata;
- MempoolIterData *item;
-
- while ((item = BLI_mempool_iterstep(iter)) != NULL) {
- state->func(state->userdata, item);
- }
-}
-
-/**
- * This function allows to parallelize for loops over Mempool items.
- *
- * \param mempool: The iterable BLI_mempool to loop over.
- * \param userdata: Common userdata passed to all instances of \a func.
- * \param func: Callback function.
- * \param use_threading: If \a true, actually split-execute loop in threads,
- * else just do a sequential for loop
- * (allows caller to use any kind of test to switch on parallelization or not).
- *
- * \note There is no static scheduling here.
- */
-void BLI_task_parallel_mempool(BLI_mempool *mempool,
- void *userdata,
- TaskParallelMempoolFunc func,
- const bool use_threading)
-{
- TaskScheduler *task_scheduler;
- TaskPool *task_pool;
- ParallelMempoolState state;
- int i, num_threads, num_tasks;
-
- if (BLI_mempool_len(mempool) == 0) {
- return;
- }
-
- if (!use_threading) {
- BLI_mempool_iter iter;
- BLI_mempool_iternew(mempool, &iter);
-
- for (void *item = BLI_mempool_iterstep(&iter); item != NULL;
- item = BLI_mempool_iterstep(&iter)) {
- func(userdata, item);
- }
- return;
- }
-
- task_scheduler = BLI_task_scheduler_get();
- task_pool = BLI_task_pool_create_suspended(task_scheduler, &state);
- num_threads = BLI_task_scheduler_num_threads(task_scheduler);
-
- /* The idea here is to prevent creating task for each of the loop iterations
- * and instead have tasks which are evenly distributed across CPU cores and
- * pull next item to be crunched using the threaded-aware BLI_mempool_iter.
- */
- num_tasks = num_threads + 2;
-
- state.userdata = userdata;
- state.func = func;
-
- BLI_mempool_iter *mempool_iterators = BLI_mempool_iter_threadsafe_create(mempool,
- (size_t)num_tasks);
-
- for (i = 0; i < num_tasks; i++) {
- /* Use this pool's pre-allocated tasks. */
- BLI_task_pool_push_from_thread(task_pool,
- parallel_mempool_func,
- &mempool_iterators[i],
- false,
- TASK_PRIORITY_HIGH,
- task_pool->thread_id);
- }
-
- BLI_task_pool_work_and_wait(task_pool);
- BLI_task_pool_free(task_pool);
-
- BLI_mempool_iter_threadsafe_free(mempool_iterators);
-}
diff --git a/source/blender/blenlib/intern/task_graph.cc b/source/blender/blenlib/intern/task_graph.cc
new file mode 100644
index 00000000000..4f112c5b2c8
--- /dev/null
+++ b/source/blender/blenlib/intern/task_graph.cc
@@ -0,0 +1,166 @@
+/*
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+
+/** \file
+ * \ingroup bli
+ *
+ * Task graph.
+ */
+
+#include "MEM_guardedalloc.h"
+
+#include "BLI_task.h"
+
+#include <memory>
+#include <vector>
+
+#ifdef WITH_TBB
+/* Quiet top level deprecation message, unrelated to API usage here. */
+# define TBB_SUPPRESS_DEPRECATED_MESSAGES 1
+# include <tbb/flow_graph.h>
+# include <tbb/tbb.h>
+#endif
+
+/* Task Graph */
+struct TaskGraph {
+#ifdef WITH_TBB
+ tbb::flow::graph tbb_graph;
+#endif
+ std::vector<std::unique_ptr<TaskNode>> nodes;
+
+#ifdef WITH_CXX_GUARDEDALLOC
+ MEM_CXX_CLASS_ALLOC_FUNCS("task_graph:TaskGraph")
+#endif
+};
+
+/* TaskNode - a node in the task graph. */
+struct TaskNode {
+ /* TBB Node. */
+#ifdef WITH_TBB
+ tbb::flow::continue_node<tbb::flow::continue_msg> tbb_node;
+#endif
+ /* Successors to execute after this task, for serial execution fallback. */
+ std::vector<TaskNode *> successors;
+
+ /* User function to be executed with given task data. */
+ TaskGraphNodeRunFunction run_func;
+ void *task_data;
+ /* Optional callback to free task data along with the graph. If task data
+ * is shared between nodes, only a single task node should free the data. */
+ TaskGraphNodeFreeFunction free_func;
+
+ TaskNode(TaskGraph *task_graph,
+ TaskGraphNodeRunFunction run_func,
+ void *task_data,
+ TaskGraphNodeFreeFunction free_func)
+ :
+#ifdef WITH_TBB
+ tbb_node(task_graph->tbb_graph,
+ tbb::flow::unlimited,
+ std::bind(&TaskNode::run, this, std::placeholders::_1)),
+#endif
+ run_func(run_func),
+ task_data(task_data),
+ free_func(free_func)
+ {
+#ifndef WITH_TBB
+ UNUSED_VARS(task_graph);
+#endif
+ }
+
+ TaskNode(const TaskNode &other) = delete;
+ TaskNode &operator=(const TaskNode &other) = delete;
+
+ ~TaskNode()
+ {
+ if (task_data && free_func) {
+ free_func(task_data);
+ }
+ }
+
+#ifdef WITH_TBB
+ tbb::flow::continue_msg run(const tbb::flow::continue_msg UNUSED(input))
+ {
+ tbb::this_task_arena::isolate([this] { run_func(task_data); });
+ return tbb::flow::continue_msg();
+ }
+#endif
+
+ void run_serial()
+ {
+ run_func(task_data);
+ for (TaskNode *successor : successors) {
+ successor->run_serial();
+ }
+ }
+
+#ifdef WITH_CXX_GUARDEDALLOC
+ MEM_CXX_CLASS_ALLOC_FUNCS("task_graph:TaskNode")
+#endif
+};
+
+TaskGraph *BLI_task_graph_create(void)
+{
+ return new TaskGraph();
+}
+
+void BLI_task_graph_free(TaskGraph *task_graph)
+{
+ delete task_graph;
+}
+
+void BLI_task_graph_work_and_wait(TaskGraph *task_graph)
+{
+#ifdef WITH_TBB
+ task_graph->tbb_graph.wait_for_all();
+#else
+ UNUSED_VARS(task_graph);
+#endif
+}
+
+struct TaskNode *BLI_task_graph_node_create(struct TaskGraph *task_graph,
+ TaskGraphNodeRunFunction run,
+ void *user_data,
+ TaskGraphNodeFreeFunction free_func)
+{
+ TaskNode *task_node = new TaskNode(task_graph, run, user_data, free_func);
+ task_graph->nodes.push_back(std::unique_ptr<TaskNode>(task_node));
+ return task_node;
+}
+
+bool BLI_task_graph_node_push_work(struct TaskNode *task_node)
+{
+#ifdef WITH_TBB
+ if (BLI_task_scheduler_num_threads() > 1) {
+ return task_node->tbb_node.try_put(tbb::flow::continue_msg());
+ }
+#endif
+
+ task_node->run_serial();
+ return true;
+}
+
+void BLI_task_graph_edge_create(struct TaskNode *from_node, struct TaskNode *to_node)
+{
+#ifdef WITH_TBB
+ if (BLI_task_scheduler_num_threads() > 1) {
+ tbb::flow::make_edge(from_node->tbb_node, to_node->tbb_node);
+ return;
+ }
+#endif
+
+ from_node->successors.push_back(to_node);
+}
diff --git a/source/blender/blenlib/intern/task_iterator.c b/source/blender/blenlib/intern/task_iterator.c
new file mode 100644
index 00000000000..ee459ac2548
--- /dev/null
+++ b/source/blender/blenlib/intern/task_iterator.c
@@ -0,0 +1,423 @@
+/*
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+
+/** \file
+ * \ingroup bli
+ *
+ * Parallel tasks over all elements in a container.
+ */
+
+#include <stdlib.h>
+
+#include "MEM_guardedalloc.h"
+
+#include "DNA_listBase.h"
+
+#include "BLI_listbase.h"
+#include "BLI_math.h"
+#include "BLI_mempool.h"
+#include "BLI_task.h"
+#include "BLI_threads.h"
+
+#include "atomic_ops.h"
+
+/* Allows to avoid using malloc for userdata_chunk in tasks, when small enough. */
+#define MALLOCA(_size) ((_size) <= 8192) ? alloca((_size)) : MEM_mallocN((_size), __func__)
+#define MALLOCA_FREE(_mem, _size) \
+ if (((_mem) != NULL) && ((_size) > 8192)) \
+ MEM_freeN((_mem))
+
+BLI_INLINE void task_parallel_calc_chunk_size(const TaskParallelSettings *settings,
+ const int tot_items,
+ int num_tasks,
+ int *r_chunk_size)
+{
+ int chunk_size = 0;
+
+ if (!settings->use_threading) {
+ /* Some users of this helper will still need a valid chunk size in case processing is not
+ * threaded. We can use a bigger one than in default threaded case then. */
+ chunk_size = 1024;
+ num_tasks = 1;
+ }
+ else if (settings->min_iter_per_thread > 0) {
+ /* Already set by user, no need to do anything here. */
+ chunk_size = settings->min_iter_per_thread;
+ }
+ else {
+ /* Multiplier used in heuristics below to define "optimal" chunk size.
+ * The idea here is to increase the chunk size to compensate for a rather measurable threading
+ * overhead caused by fetching tasks. With too many CPU threads we are starting
+ * to spend too much time in those overheads.
+ * First values are: 1 if num_tasks < 16;
+ * else 2 if num_tasks < 32;
+ * else 3 if num_tasks < 48;
+ * else 4 if num_tasks < 64;
+ * etc.
+ * Note: If we wanted to keep the 'power of two' multiplier, we'd need something like:
+ * 1 << max_ii(0, (int)(sizeof(int) * 8) - 1 - bitscan_reverse_i(num_tasks) - 3)
+ */
+ const int num_tasks_factor = max_ii(1, num_tasks >> 3);
+
+ /* We could make that 'base' 32 number configurable in TaskParallelSettings too, or maybe just
+ * always use that heuristic using TaskParallelSettings.min_iter_per_thread as basis? */
+ chunk_size = 32 * num_tasks_factor;
+
+ /* Basic heuristic to avoid threading on low amount of items.
+ * We could make that limit configurable in settings too. */
+ if (tot_items > 0 && tot_items < max_ii(256, chunk_size * 2)) {
+ chunk_size = tot_items;
+ }
+ }
+
+ BLI_assert(chunk_size > 0);
+ *r_chunk_size = chunk_size;
+}
+
+typedef struct TaskParallelIteratorState {
+ void *userdata;
+ TaskParallelIteratorIterFunc iter_func;
+ TaskParallelIteratorFunc func;
+
+ /* *** Data used to 'acquire' chunks of items from the iterator. *** */
+ /* Common data also passed to the generator callback. */
+ TaskParallelIteratorStateShared iter_shared;
+ /* Total number of items. If unknown, set it to a negative number. */
+ int tot_items;
+} TaskParallelIteratorState;
+
+static void parallel_iterator_func_do(TaskParallelIteratorState *__restrict state,
+ void *userdata_chunk)
+{
+ TaskParallelTLS tls = {
+ .userdata_chunk = userdata_chunk,
+ };
+
+ void **current_chunk_items;
+ int *current_chunk_indices;
+ int current_chunk_size;
+
+ const size_t items_size = sizeof(*current_chunk_items) * (size_t)state->iter_shared.chunk_size;
+ const size_t indices_size = sizeof(*current_chunk_indices) *
+ (size_t)state->iter_shared.chunk_size;
+
+ current_chunk_items = MALLOCA(items_size);
+ current_chunk_indices = MALLOCA(indices_size);
+ current_chunk_size = 0;
+
+ for (bool do_abort = false; !do_abort;) {
+ if (state->iter_shared.spin_lock != NULL) {
+ BLI_spin_lock(state->iter_shared.spin_lock);
+ }
+
+ /* Get current status. */
+ int index = state->iter_shared.next_index;
+ void *item = state->iter_shared.next_item;
+ int i;
+
+ /* 'Acquire' a chunk of items from the iterator function. */
+ for (i = 0; i < state->iter_shared.chunk_size && !state->iter_shared.is_finished; i++) {
+ current_chunk_indices[i] = index;
+ current_chunk_items[i] = item;
+ state->iter_func(state->userdata, &tls, &item, &index, &state->iter_shared.is_finished);
+ }
+
+ /* Update current status. */
+ state->iter_shared.next_index = index;
+ state->iter_shared.next_item = item;
+ current_chunk_size = i;
+
+ do_abort = state->iter_shared.is_finished;
+
+ if (state->iter_shared.spin_lock != NULL) {
+ BLI_spin_unlock(state->iter_shared.spin_lock);
+ }
+
+ for (i = 0; i < current_chunk_size; ++i) {
+ state->func(state->userdata, current_chunk_items[i], current_chunk_indices[i], &tls);
+ }
+ }
+
+ MALLOCA_FREE(current_chunk_items, items_size);
+ MALLOCA_FREE(current_chunk_indices, indices_size);
+}
+
+static void parallel_iterator_func(TaskPool *__restrict pool, void *userdata_chunk)
+{
+ TaskParallelIteratorState *__restrict state = BLI_task_pool_user_data(pool);
+
+ parallel_iterator_func_do(state, userdata_chunk);
+}
+
+static void task_parallel_iterator_no_threads(const TaskParallelSettings *settings,
+ TaskParallelIteratorState *state)
+{
+ /* Prepare user's TLS data. */
+ void *userdata_chunk = settings->userdata_chunk;
+ const size_t userdata_chunk_size = settings->userdata_chunk_size;
+ void *userdata_chunk_local = NULL;
+ const bool use_userdata_chunk = (userdata_chunk_size != 0) && (userdata_chunk != NULL);
+ if (use_userdata_chunk) {
+ userdata_chunk_local = MALLOCA(userdata_chunk_size);
+ memcpy(userdata_chunk_local, userdata_chunk, userdata_chunk_size);
+ }
+
+ /* Also marking it as non-threaded for the iterator callback. */
+ state->iter_shared.spin_lock = NULL;
+
+ parallel_iterator_func_do(state, userdata_chunk);
+
+ if (use_userdata_chunk && settings->func_free != NULL) {
+ /* `func_free` should only free data that was created during execution of `func`. */
+ settings->func_free(state->userdata, userdata_chunk_local);
+ }
+}
+
+static void task_parallel_iterator_do(const TaskParallelSettings *settings,
+ TaskParallelIteratorState *state)
+{
+ const int num_threads = BLI_task_scheduler_num_threads();
+
+ task_parallel_calc_chunk_size(
+ settings, state->tot_items, num_threads, &state->iter_shared.chunk_size);
+
+ if (!settings->use_threading) {
+ task_parallel_iterator_no_threads(settings, state);
+ return;
+ }
+
+ const int chunk_size = state->iter_shared.chunk_size;
+ const int tot_items = state->tot_items;
+ const size_t num_tasks = tot_items >= 0 ?
+ (size_t)min_ii(num_threads, state->tot_items / chunk_size) :
+ (size_t)num_threads;
+
+ BLI_assert(num_tasks > 0);
+ if (num_tasks == 1) {
+ task_parallel_iterator_no_threads(settings, state);
+ return;
+ }
+
+ SpinLock spin_lock;
+ BLI_spin_init(&spin_lock);
+ state->iter_shared.spin_lock = &spin_lock;
+
+ void *userdata_chunk = settings->userdata_chunk;
+ const size_t userdata_chunk_size = settings->userdata_chunk_size;
+ void *userdata_chunk_local = NULL;
+ void *userdata_chunk_array = NULL;
+ const bool use_userdata_chunk = (userdata_chunk_size != 0) && (userdata_chunk != NULL);
+
+ TaskPool *task_pool = BLI_task_pool_create(state, TASK_PRIORITY_HIGH);
+
+ if (use_userdata_chunk) {
+ userdata_chunk_array = MALLOCA(userdata_chunk_size * num_tasks);
+ }
+
+ for (size_t i = 0; i < num_tasks; i++) {
+ if (use_userdata_chunk) {
+ userdata_chunk_local = (char *)userdata_chunk_array + (userdata_chunk_size * i);
+ memcpy(userdata_chunk_local, userdata_chunk, userdata_chunk_size);
+ }
+ /* Use this pool's pre-allocated tasks. */
+ BLI_task_pool_push(task_pool, parallel_iterator_func, userdata_chunk_local, false, NULL);
+ }
+
+ BLI_task_pool_work_and_wait(task_pool);
+ BLI_task_pool_free(task_pool);
+
+ if (use_userdata_chunk && (settings->func_reduce != NULL || settings->func_free != NULL)) {
+ for (size_t i = 0; i < num_tasks; i++) {
+ userdata_chunk_local = (char *)userdata_chunk_array + (userdata_chunk_size * i);
+ if (settings->func_reduce != NULL) {
+ settings->func_reduce(state->userdata, userdata_chunk, userdata_chunk_local);
+ }
+ if (settings->func_free != NULL) {
+ settings->func_free(state->userdata, userdata_chunk_local);
+ }
+ }
+ MALLOCA_FREE(userdata_chunk_array, userdata_chunk_size * num_tasks);
+ }
+
+ BLI_spin_end(&spin_lock);
+ state->iter_shared.spin_lock = NULL;
+}
+
+/**
+ * This function allows to parallelize for loops using a generic iterator.
+ *
+ * \param userdata: Common userdata passed to all instances of \a func.
+ * \param iter_func: Callback function used to generate chunks of items.
+ * \param init_item: The initial item, if necessary (may be NULL if unused).
+ * \param init_index: The initial index.
+ * \param tot_items: The total amount of items to iterate over
+ * (if unknown, set it to a negative number).
+ * \param func: Callback function.
+ * \param settings: See public API doc of TaskParallelSettings for description of all settings.
+ *
+ * \note Static scheduling is only available when \a tot_items is >= 0.
+ */
+
+void BLI_task_parallel_iterator(void *userdata,
+ TaskParallelIteratorIterFunc iter_func,
+ void *init_item,
+ const int init_index,
+ const int tot_items,
+ TaskParallelIteratorFunc func,
+ const TaskParallelSettings *settings)
+{
+ TaskParallelIteratorState state = {0};
+
+ state.tot_items = tot_items;
+ state.iter_shared.next_index = init_index;
+ state.iter_shared.next_item = init_item;
+ state.iter_shared.is_finished = false;
+ state.userdata = userdata;
+ state.iter_func = iter_func;
+ state.func = func;
+
+ task_parallel_iterator_do(settings, &state);
+}
+
+static void task_parallel_listbase_get(void *__restrict UNUSED(userdata),
+ const TaskParallelTLS *__restrict UNUSED(tls),
+ void **r_next_item,
+ int *r_next_index,
+ bool *r_do_abort)
+{
+ /* Get current status. */
+ Link *link = *r_next_item;
+
+ if (link->next == NULL) {
+ *r_do_abort = true;
+ }
+ *r_next_item = link->next;
+ (*r_next_index)++;
+}
+
+/**
+ * This function allows to parallelize for loops over ListBase items.
+ *
+ * \param listbase: The double linked list to loop over.
+ * \param userdata: Common userdata passed to all instances of \a func.
+ * \param func: Callback function.
+ * \param settings: See public API doc of ParallelRangeSettings for description of all settings.
+ *
+ * \note There is no static scheduling here,
+ * since it would need another full loop over items to count them.
+ */
+void BLI_task_parallel_listbase(ListBase *listbase,
+ void *userdata,
+ TaskParallelIteratorFunc func,
+ const TaskParallelSettings *settings)
+{
+ if (BLI_listbase_is_empty(listbase)) {
+ return;
+ }
+
+ TaskParallelIteratorState state = {0};
+
+ state.tot_items = BLI_listbase_count(listbase);
+ state.iter_shared.next_index = 0;
+ state.iter_shared.next_item = listbase->first;
+ state.iter_shared.is_finished = false;
+ state.userdata = userdata;
+ state.iter_func = task_parallel_listbase_get;
+ state.func = func;
+
+ task_parallel_iterator_do(settings, &state);
+}
+
+#undef MALLOCA
+#undef MALLOCA_FREE
+
+typedef struct ParallelMempoolState {
+ void *userdata;
+ TaskParallelMempoolFunc func;
+} ParallelMempoolState;
+
+static void parallel_mempool_func(TaskPool *__restrict pool, void *taskdata)
+{
+ ParallelMempoolState *__restrict state = BLI_task_pool_user_data(pool);
+ BLI_mempool_iter *iter = taskdata;
+ MempoolIterData *item;
+
+ while ((item = BLI_mempool_iterstep(iter)) != NULL) {
+ state->func(state->userdata, item);
+ }
+}
+
+/**
+ * This function allows to parallelize for loops over Mempool items.
+ *
+ * \param mempool: The iterable BLI_mempool to loop over.
+ * \param userdata: Common userdata passed to all instances of \a func.
+ * \param func: Callback function.
+ * \param use_threading: If \a true, actually split-execute loop in threads,
+ * else just do a sequential for loop
+ * (allows caller to use any kind of test to switch on parallelization or not).
+ *
+ * \note There is no static scheduling here.
+ */
+void BLI_task_parallel_mempool(BLI_mempool *mempool,
+ void *userdata,
+ TaskParallelMempoolFunc func,
+ const bool use_threading)
+{
+ TaskPool *task_pool;
+ ParallelMempoolState state;
+ int i, num_threads, num_tasks;
+
+ if (BLI_mempool_len(mempool) == 0) {
+ return;
+ }
+
+ if (!use_threading) {
+ BLI_mempool_iter iter;
+ BLI_mempool_iternew(mempool, &iter);
+
+ for (void *item = BLI_mempool_iterstep(&iter); item != NULL;
+ item = BLI_mempool_iterstep(&iter)) {
+ func(userdata, item);
+ }
+ return;
+ }
+
+ task_pool = BLI_task_pool_create(&state, TASK_PRIORITY_HIGH);
+ num_threads = BLI_task_scheduler_num_threads();
+
+ /* The idea here is to prevent creating task for each of the loop iterations
+ * and instead have tasks which are evenly distributed across CPU cores and
+ * pull next item to be crunched using the threaded-aware BLI_mempool_iter.
+ */
+ num_tasks = num_threads + 2;
+
+ state.userdata = userdata;
+ state.func = func;
+
+ BLI_mempool_iter *mempool_iterators = BLI_mempool_iter_threadsafe_create(mempool,
+ (size_t)num_tasks);
+
+ for (i = 0; i < num_tasks; i++) {
+ /* Use this pool's pre-allocated tasks. */
+ BLI_task_pool_push(task_pool, parallel_mempool_func, &mempool_iterators[i], false, NULL);
+ }
+
+ BLI_task_pool_work_and_wait(task_pool);
+ BLI_task_pool_free(task_pool);
+
+ BLI_mempool_iter_threadsafe_free(mempool_iterators);
+}
diff --git a/source/blender/blenlib/intern/task_pool.cc b/source/blender/blenlib/intern/task_pool.cc
new file mode 100644
index 00000000000..cf328ec407c
--- /dev/null
+++ b/source/blender/blenlib/intern/task_pool.cc
@@ -0,0 +1,546 @@
+/*
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+
+/** \file
+ * \ingroup bli
+ *
+ * Task pool to run tasks in parallel.
+ */
+
+#include <memory>
+#include <stdlib.h>
+#include <utility>
+
+#include "MEM_guardedalloc.h"
+
+#include "DNA_listBase.h"
+
+#include "BLI_math.h"
+#include "BLI_mempool.h"
+#include "BLI_task.h"
+#include "BLI_threads.h"
+
+#ifdef WITH_TBB
+/* Quiet top level deprecation message, unrelated to API usage here. */
+# define TBB_SUPPRESS_DEPRECATED_MESSAGES 1
+# include <tbb/tbb.h>
+#endif
+
+/* Task
+ *
+ * Unit of work to execute. This is a C++ class to work with TBB. */
+
+class Task {
+ public:
+ TaskPool *pool;
+ TaskRunFunction run;
+ void *taskdata;
+ bool free_taskdata;
+ TaskFreeFunction freedata;
+
+ Task(TaskPool *pool,
+ TaskRunFunction run,
+ void *taskdata,
+ bool free_taskdata,
+ TaskFreeFunction freedata)
+ : pool(pool), run(run), taskdata(taskdata), free_taskdata(free_taskdata), freedata(freedata)
+ {
+ }
+
+ ~Task()
+ {
+ if (free_taskdata) {
+ if (freedata) {
+ freedata(pool, taskdata);
+ }
+ else {
+ MEM_freeN(taskdata);
+ }
+ }
+ }
+
+ /* Move constructor.
+ * For performance, ensure we never copy the task and only move it.
+ * For TBB version 2017 and earlier we apply a workaround to make up for
+ * the lack of move constructor support. */
+ Task(Task &&other)
+ : pool(other.pool),
+ run(other.run),
+ taskdata(other.taskdata),
+ free_taskdata(other.free_taskdata),
+ freedata(other.freedata)
+ {
+ other.pool = NULL;
+ other.run = NULL;
+ other.taskdata = NULL;
+ other.free_taskdata = false;
+ other.freedata = NULL;
+ }
+
+#if defined(WITH_TBB) && TBB_INTERFACE_VERSION_MAJOR < 10
+ Task(const Task &other)
+ : pool(other.pool),
+ run(other.run),
+ taskdata(other.taskdata),
+ free_taskdata(other.free_taskdata),
+ freedata(other.freedata)
+ {
+ ((Task &)other).pool = NULL;
+ ((Task &)other).run = NULL;
+ ((Task &)other).taskdata = NULL;
+ ((Task &)other).free_taskdata = false;
+ ((Task &)other).freedata = NULL;
+ }
+#else
+ Task(const Task &other) = delete;
+#endif
+
+ Task &operator=(const Task &other) = delete;
+ Task &operator=(Task &&other) = delete;
+
+ /* Execute task. */
+ void operator()() const
+ {
+#ifdef WITH_TBB
+ tbb::this_task_arena::isolate([this] { run(pool, taskdata); });
+#else
+ run(pool, taskdata);
+#endif
+ }
+};
+
+/* TBB Task Group.
+ *
+ * Subclass since there seems to be no other way to set priority. */
+
+#ifdef WITH_TBB
+class TBBTaskGroup : public tbb::task_group {
+ public:
+ TBBTaskGroup(TaskPriority priority)
+ {
+ switch (priority) {
+ case TASK_PRIORITY_LOW:
+ my_context.set_priority(tbb::priority_low);
+ break;
+ case TASK_PRIORITY_HIGH:
+ my_context.set_priority(tbb::priority_normal);
+ break;
+ }
+ }
+
+ ~TBBTaskGroup()
+ {
+ }
+};
+#endif
+
+/* Task Pool */
+
+typedef enum TaskPoolType {
+ TASK_POOL_TBB,
+ TASK_POOL_TBB_SUSPENDED,
+ TASK_POOL_NO_THREADS,
+ TASK_POOL_BACKGROUND,
+ TASK_POOL_BACKGROUND_SERIAL,
+} TaskPoolType;
+
+struct TaskPool {
+ TaskPoolType type;
+ bool use_threads;
+
+ ThreadMutex user_mutex;
+ void *userdata;
+
+ /* TBB task pool. */
+#ifdef WITH_TBB
+ TBBTaskGroup tbb_group;
+#endif
+ volatile bool is_suspended;
+ BLI_mempool *suspended_mempool;
+
+ /* Background task pool. */
+ ListBase background_threads;
+ ThreadQueue *background_queue;
+ volatile bool background_is_canceling;
+};
+
+/* TBB Task Pool.
+ *
+ * Task pool using the TBB scheduler for tasks. When building without TBB
+ * support or running Blender with -t 1, this reverts to single threaded.
+ *
+ * Tasks may be suspended until in all are created, to make it possible to
+ * initialize data structures and create tasks in a single pass. */
+
+static void tbb_task_pool_create(TaskPool *pool, TaskPriority priority)
+{
+ if (pool->type == TASK_POOL_TBB_SUSPENDED) {
+ pool->is_suspended = true;
+ pool->suspended_mempool = BLI_mempool_create(sizeof(Task), 512, 512, BLI_MEMPOOL_ALLOW_ITER);
+ }
+
+#ifdef WITH_TBB
+ if (pool->use_threads) {
+ new (&pool->tbb_group) TBBTaskGroup(priority);
+ }
+#else
+ UNUSED_VARS(priority);
+#endif
+}
+
+static void tbb_task_pool_run(TaskPool *pool, Task &&task)
+{
+ if (pool->is_suspended) {
+ /* Suspended task that will be executed in work_and_wait(). */
+ Task *task_mem = (Task *)BLI_mempool_alloc(pool->suspended_mempool);
+ new (task_mem) Task(std::move(task));
+#ifdef __GNUC__
+ /* Work around apparent compiler bug where task is not properly copied
+ * to task_mem. This appears unrelated to the use of placement new or
+ * move semantics, happens even writing to a plain C struct. Rather the
+ * call into TBB seems to have some indirect effect. */
+ std::atomic_thread_fence(std::memory_order_release);
+#endif
+ }
+#ifdef WITH_TBB
+ else if (pool->use_threads) {
+ /* Execute in TBB task group. */
+ pool->tbb_group.run(std::move(task));
+ }
+#endif
+ else {
+ /* Execute immediately. */
+ task();
+ }
+}
+
+static void tbb_task_pool_work_and_wait(TaskPool *pool)
+{
+ /* Start any suspended task now. */
+ if (pool->suspended_mempool) {
+ pool->is_suspended = false;
+
+ BLI_mempool_iter iter;
+ BLI_mempool_iternew(pool->suspended_mempool, &iter);
+ while (Task *task = (Task *)BLI_mempool_iterstep(&iter)) {
+ tbb_task_pool_run(pool, std::move(*task));
+ }
+
+ BLI_mempool_clear(pool->suspended_mempool);
+ }
+
+#ifdef WITH_TBB
+ if (pool->use_threads) {
+ /* This is called wait(), but internally it can actually do work. This
+ * matters because we don't want recursive usage of task pools to run
+ * out of threads and get stuck. */
+ pool->tbb_group.wait();
+ }
+#endif
+}
+
+static void tbb_task_pool_cancel(TaskPool *pool)
+{
+#ifdef WITH_TBB
+ if (pool->use_threads) {
+ pool->tbb_group.cancel();
+ pool->tbb_group.wait();
+ }
+#else
+ UNUSED_VARS(pool);
+#endif
+}
+
+static bool tbb_task_pool_canceled(TaskPool *pool)
+{
+#ifdef WITH_TBB
+ if (pool->use_threads) {
+ return pool->tbb_group.is_canceling();
+ }
+#else
+ UNUSED_VARS(pool);
+#endif
+
+ return false;
+}
+
+static void tbb_task_pool_free(TaskPool *pool)
+{
+#ifdef WITH_TBB
+ if (pool->use_threads) {
+ pool->tbb_group.~TBBTaskGroup();
+ }
+#endif
+
+ if (pool->suspended_mempool) {
+ BLI_mempool_destroy(pool->suspended_mempool);
+ }
+}
+
+/* Background Task Pool.
+ *
+ * Fallback for running background tasks when building without TBB. */
+
+static void *background_task_run(void *userdata)
+{
+ TaskPool *pool = (TaskPool *)userdata;
+ while (Task *task = (Task *)BLI_thread_queue_pop(pool->background_queue)) {
+ (*task)();
+ task->~Task();
+ MEM_freeN(task);
+ }
+ return NULL;
+}
+
+static void background_task_pool_create(TaskPool *pool)
+{
+ pool->background_queue = BLI_thread_queue_init();
+ BLI_threadpool_init(&pool->background_threads, background_task_run, 1);
+}
+
+static void background_task_pool_run(TaskPool *pool, Task &&task)
+{
+ Task *task_mem = (Task *)MEM_mallocN(sizeof(Task), __func__);
+ new (task_mem) Task(std::move(task));
+ BLI_thread_queue_push(pool->background_queue, task_mem);
+
+ if (BLI_available_threads(&pool->background_threads)) {
+ BLI_threadpool_insert(&pool->background_threads, pool);
+ }
+}
+
+static void background_task_pool_work_and_wait(TaskPool *pool)
+{
+ /* Signal background thread to stop waiting for new tasks if none are
+ * left, and wait for tasks and thread to finish. */
+ BLI_thread_queue_nowait(pool->background_queue);
+ BLI_thread_queue_wait_finish(pool->background_queue);
+ BLI_threadpool_clear(&pool->background_threads);
+}
+
+static void background_task_pool_cancel(TaskPool *pool)
+{
+ pool->background_is_canceling = true;
+
+ /* Remove tasks not yet started by background thread. */
+ BLI_thread_queue_nowait(pool->background_queue);
+ while (Task *task = (Task *)BLI_thread_queue_pop(pool->background_queue)) {
+ task->~Task();
+ MEM_freeN(task);
+ }
+
+ /* Let background thread finish or cancel task it is working on. */
+ BLI_threadpool_remove(&pool->background_threads, pool);
+ pool->background_is_canceling = false;
+}
+
+static bool background_task_pool_canceled(TaskPool *pool)
+{
+ return pool->background_is_canceling;
+}
+
+static void background_task_pool_free(TaskPool *pool)
+{
+ background_task_pool_work_and_wait(pool);
+
+ BLI_threadpool_end(&pool->background_threads);
+ BLI_thread_queue_free(pool->background_queue);
+}
+
+/* Task Pool */
+
+static TaskPool *task_pool_create_ex(void *userdata, TaskPoolType type, TaskPriority priority)
+{
+ const bool use_threads = BLI_task_scheduler_num_threads() > 1 && type != TASK_POOL_NO_THREADS;
+
+ /* Background task pool uses regular TBB scheduling if available. Only when
+ * building without TBB or running with -t 1 do we need to ensure these tasks
+ * do not block the main thread. */
+ if (type == TASK_POOL_BACKGROUND && use_threads) {
+ type = TASK_POOL_TBB;
+ }
+
+ /* Allocate task pool. */
+ TaskPool *pool = (TaskPool *)MEM_callocN(sizeof(TaskPool), "TaskPool");
+
+ pool->type = type;
+ pool->use_threads = use_threads;
+
+ pool->userdata = userdata;
+ BLI_mutex_init(&pool->user_mutex);
+
+ switch (type) {
+ case TASK_POOL_TBB:
+ case TASK_POOL_TBB_SUSPENDED:
+ case TASK_POOL_NO_THREADS:
+ tbb_task_pool_create(pool, priority);
+ break;
+ case TASK_POOL_BACKGROUND:
+ case TASK_POOL_BACKGROUND_SERIAL:
+ background_task_pool_create(pool);
+ break;
+ }
+
+ return pool;
+}
+
+/**
+ * Create a normal task pool. Tasks will be executed as soon as they are added.
+ */
+TaskPool *BLI_task_pool_create(void *userdata, TaskPriority priority)
+{
+ return task_pool_create_ex(userdata, TASK_POOL_TBB, priority);
+}
+
+/**
+ * Create a background task pool.
+ * In multi-threaded context, there is no differences with #BLI_task_pool_create(),
+ * but in single-threaded case it is ensured to have at least one worker thread to run on
+ * (i.e. you don't have to call #BLI_task_pool_work_and_wait
+ * on it to be sure it will be processed).
+ *
+ * \note Background pools are non-recursive
+ * (that is, you should not create other background pools in tasks assigned to a background pool,
+ * they could end never being executed, since the 'fallback' background thread is already
+ * busy with parent task in single-threaded context).
+ */
+TaskPool *BLI_task_pool_create_background(void *userdata, TaskPriority priority)
+{
+ return task_pool_create_ex(userdata, TASK_POOL_BACKGROUND, priority);
+}
+
+/**
+ * Similar to BLI_task_pool_create() but does not schedule any tasks for execution
+ * for until BLI_task_pool_work_and_wait() is called. This helps reducing threading
+ * overhead when pushing huge amount of small initial tasks from the main thread.
+ */
+TaskPool *BLI_task_pool_create_suspended(void *userdata, TaskPriority priority)
+{
+ return task_pool_create_ex(userdata, TASK_POOL_TBB_SUSPENDED, priority);
+}
+
+/**
+ * Single threaded task pool that executes pushed task immediately, for
+ * debugging purposes.
+ */
+TaskPool *BLI_task_pool_create_no_threads(void *userdata)
+{
+ return task_pool_create_ex(userdata, TASK_POOL_NO_THREADS, TASK_PRIORITY_HIGH);
+}
+
+/**
+ * Task pool that executes one task after the other, possibly on different threads
+ * but never in parallel.
+ */
+TaskPool *BLI_task_pool_create_background_serial(void *userdata, TaskPriority priority)
+{
+ return task_pool_create_ex(userdata, TASK_POOL_BACKGROUND_SERIAL, priority);
+}
+
+void BLI_task_pool_free(TaskPool *pool)
+{
+ switch (pool->type) {
+ case TASK_POOL_TBB:
+ case TASK_POOL_TBB_SUSPENDED:
+ case TASK_POOL_NO_THREADS:
+ tbb_task_pool_free(pool);
+ break;
+ case TASK_POOL_BACKGROUND:
+ case TASK_POOL_BACKGROUND_SERIAL:
+ background_task_pool_free(pool);
+ break;
+ }
+
+ BLI_mutex_end(&pool->user_mutex);
+
+ MEM_freeN(pool);
+}
+
+void BLI_task_pool_push(TaskPool *pool,
+ TaskRunFunction run,
+ void *taskdata,
+ bool free_taskdata,
+ TaskFreeFunction freedata)
+{
+ Task task(pool, run, taskdata, free_taskdata, freedata);
+
+ switch (pool->type) {
+ case TASK_POOL_TBB:
+ case TASK_POOL_TBB_SUSPENDED:
+ case TASK_POOL_NO_THREADS:
+ tbb_task_pool_run(pool, std::move(task));
+ break;
+ case TASK_POOL_BACKGROUND:
+ case TASK_POOL_BACKGROUND_SERIAL:
+ background_task_pool_run(pool, std::move(task));
+ break;
+ }
+}
+
+void BLI_task_pool_work_and_wait(TaskPool *pool)
+{
+ switch (pool->type) {
+ case TASK_POOL_TBB:
+ case TASK_POOL_TBB_SUSPENDED:
+ case TASK_POOL_NO_THREADS:
+ tbb_task_pool_work_and_wait(pool);
+ break;
+ case TASK_POOL_BACKGROUND:
+ case TASK_POOL_BACKGROUND_SERIAL:
+ background_task_pool_work_and_wait(pool);
+ break;
+ }
+}
+
+void BLI_task_pool_cancel(TaskPool *pool)
+{
+ switch (pool->type) {
+ case TASK_POOL_TBB:
+ case TASK_POOL_TBB_SUSPENDED:
+ case TASK_POOL_NO_THREADS:
+ tbb_task_pool_cancel(pool);
+ break;
+ case TASK_POOL_BACKGROUND:
+ case TASK_POOL_BACKGROUND_SERIAL:
+ background_task_pool_cancel(pool);
+ break;
+ }
+}
+
+bool BLI_task_pool_canceled(TaskPool *pool)
+{
+ switch (pool->type) {
+ case TASK_POOL_TBB:
+ case TASK_POOL_TBB_SUSPENDED:
+ case TASK_POOL_NO_THREADS:
+ return tbb_task_pool_canceled(pool);
+ case TASK_POOL_BACKGROUND:
+ case TASK_POOL_BACKGROUND_SERIAL:
+ return background_task_pool_canceled(pool);
+ }
+ BLI_assert("BLI_task_pool_canceled: Control flow should not come here!");
+ return false;
+}
+
+void *BLI_task_pool_user_data(TaskPool *pool)
+{
+ return pool->userdata;
+}
+
+ThreadMutex *BLI_task_pool_user_mutex(TaskPool *pool)
+{
+ return &pool->user_mutex;
+}
diff --git a/source/blender/blenkernel/intern/pbvh_parallel.cc b/source/blender/blenlib/intern/task_range.cc
index 2534fdea3ee..67d8960434e 100644
--- a/source/blender/blenkernel/intern/pbvh_parallel.cc
+++ b/source/blender/blenlib/intern/task_range.cc
@@ -14,60 +14,72 @@
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
+/** \file
+ * \ingroup bli
+ *
+ * Task parallel range functions.
+ */
+
+#include <stdlib.h>
+
#include "MEM_guardedalloc.h"
+#include "DNA_listBase.h"
+
#include "BLI_task.h"
#include "BLI_threads.h"
-#include "BKE_pbvh.h"
-
#include "atomic_ops.h"
#ifdef WITH_TBB
-
/* Quiet top level deprecation message, unrelated to API usage here. */
# define TBB_SUPPRESS_DEPRECATED_MESSAGES 1
-
# include <tbb/tbb.h>
+#endif
+
+#ifdef WITH_TBB
/* Functor for running TBB parallel_for and parallel_reduce. */
-struct PBVHTask {
- PBVHParallelRangeFunc func;
+struct RangeTask {
+ TaskParallelRangeFunc func;
void *userdata;
- const PBVHParallelSettings *settings;
+ const TaskParallelSettings *settings;
void *userdata_chunk;
/* Root constructor. */
- PBVHTask(PBVHParallelRangeFunc func, void *userdata, const PBVHParallelSettings *settings)
+ RangeTask(TaskParallelRangeFunc func, void *userdata, const TaskParallelSettings *settings)
: func(func), userdata(userdata), settings(settings)
{
init_chunk(settings->userdata_chunk);
}
/* Copy constructor. */
- PBVHTask(const PBVHTask &other)
+ RangeTask(const RangeTask &other)
: func(other.func), userdata(other.userdata), settings(other.settings)
{
- init_chunk(other.userdata_chunk);
+ init_chunk(settings->userdata_chunk);
}
/* Splitting constructor for parallel reduce. */
- PBVHTask(PBVHTask &other, tbb::split)
+ RangeTask(RangeTask &other, tbb::split)
: func(other.func), userdata(other.userdata), settings(other.settings)
{
init_chunk(settings->userdata_chunk);
}
- ~PBVHTask()
+ ~RangeTask()
{
+ if (settings->func_free != NULL) {
+ settings->func_free(userdata, userdata_chunk);
+ }
MEM_SAFE_FREE(userdata_chunk);
}
void init_chunk(void *from_chunk)
{
if (from_chunk) {
- userdata_chunk = MEM_mallocN(settings->userdata_chunk_size, "PBVHTask");
+ userdata_chunk = MEM_mallocN(settings->userdata_chunk_size, "RangeTask");
memcpy(userdata_chunk, from_chunk, settings->userdata_chunk_size);
}
else {
@@ -77,62 +89,45 @@ struct PBVHTask {
void operator()(const tbb::blocked_range<int> &r) const
{
- TaskParallelTLS tls;
- tls.thread_id = get_thread_id();
- tls.userdata_chunk = userdata_chunk;
- for (int i = r.begin(); i != r.end(); ++i) {
- func(userdata, i, &tls);
- }
+ tbb::this_task_arena::isolate([this, r] {
+ TaskParallelTLS tls;
+ tls.userdata_chunk = userdata_chunk;
+ for (int i = r.begin(); i != r.end(); ++i) {
+ func(userdata, i, &tls);
+ }
+ });
}
- void join(const PBVHTask &other)
+ void join(const RangeTask &other)
{
settings->func_reduce(userdata, userdata_chunk, other.userdata_chunk);
}
-
- int get_thread_id() const
- {
- /* Get a unique thread ID for texture nodes. In the future we should get rid
- * of the thread ID and change texture evaluation to not require per-thread
- * storage that can't be efficiently allocated on the stack. */
- static tbb::enumerable_thread_specific<int> pbvh_thread_id(-1);
- static int pbvh_thread_id_counter = 0;
-
- int &thread_id = pbvh_thread_id.local();
- if (thread_id == -1) {
- thread_id = atomic_fetch_and_add_int32(&pbvh_thread_id_counter, 1);
- if (thread_id >= BLENDER_MAX_THREADS) {
- BLI_assert(!"Maximum number of threads exceeded for sculpting");
- thread_id = thread_id % BLENDER_MAX_THREADS;
- }
- }
- return thread_id;
- }
};
#endif
-void BKE_pbvh_parallel_range(const int start,
+void BLI_task_parallel_range(const int start,
const int stop,
void *userdata,
- PBVHParallelRangeFunc func,
- const struct PBVHParallelSettings *settings)
+ TaskParallelRangeFunc func,
+ const TaskParallelSettings *settings)
{
#ifdef WITH_TBB
/* Multithreading. */
- if (settings->use_threading) {
- PBVHTask task(func, userdata, settings);
+ if (settings->use_threading && BLI_task_scheduler_num_threads() > 1) {
+ RangeTask task(func, userdata, settings);
+ const size_t grainsize = MAX2(settings->min_iter_per_thread, 1);
+ const tbb::blocked_range<int> range(start, stop, grainsize);
if (settings->func_reduce) {
- parallel_reduce(tbb::blocked_range<int>(start, stop), task);
+ parallel_reduce(range, task);
if (settings->userdata_chunk) {
memcpy(settings->userdata_chunk, task.userdata_chunk, settings->userdata_chunk_size);
}
}
else {
- parallel_for(tbb::blocked_range<int>(start, stop), task);
+ parallel_for(range, task);
}
-
return;
}
#endif
@@ -140,9 +135,34 @@ void BKE_pbvh_parallel_range(const int start,
/* Single threaded. Nothing to reduce as everything is accumulated into the
* main userdata chunk directly. */
TaskParallelTLS tls;
- tls.thread_id = 0;
tls.userdata_chunk = settings->userdata_chunk;
for (int i = start; i < stop; i++) {
func(userdata, i, &tls);
}
+ if (settings->func_free != NULL) {
+ settings->func_free(userdata, settings->userdata_chunk);
+ }
+}
+
+int BLI_task_parallel_thread_id(const TaskParallelTLS *UNUSED(tls))
+{
+#ifdef WITH_TBB
+ /* Get a unique thread ID for texture nodes. In the future we should get rid
+ * of the thread ID and change texture evaluation to not require per-thread
+ * storage that can't be efficiently allocated on the stack. */
+ static tbb::enumerable_thread_specific<int> tbb_thread_id(-1);
+ static int tbb_thread_id_counter = 0;
+
+ int &thread_id = tbb_thread_id.local();
+ if (thread_id == -1) {
+ thread_id = atomic_fetch_and_add_int32(&tbb_thread_id_counter, 1);
+ if (thread_id >= BLENDER_MAX_THREADS) {
+ BLI_assert(!"Maximum number of threads exceeded for sculpting");
+ thread_id = thread_id % BLENDER_MAX_THREADS;
+ }
+ }
+ return thread_id;
+#else
+ return 0;
+#endif
}
diff --git a/source/blender/blenlib/intern/task_scheduler.cc b/source/blender/blenlib/intern/task_scheduler.cc
new file mode 100644
index 00000000000..b0245da0385
--- /dev/null
+++ b/source/blender/blenlib/intern/task_scheduler.cc
@@ -0,0 +1,78 @@
+/*
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+
+/** \file
+ * \ingroup bli
+ *
+ * Task scheduler initialization.
+ */
+
+#include "MEM_guardedalloc.h"
+
+#include "BLI_task.h"
+#include "BLI_threads.h"
+
+#ifdef WITH_TBB
+/* Quiet top level deprecation message, unrelated to API usage here. */
+# define TBB_SUPPRESS_DEPRECATED_MESSAGES 1
+# include <tbb/tbb.h>
+# if TBB_INTERFACE_VERSION_MAJOR >= 10
+# define WITH_TBB_GLOBAL_CONTROL
+# endif
+#endif
+
+/* Task Scheduler */
+
+static int task_scheduler_num_threads = 1;
+#ifdef WITH_TBB_GLOBAL_CONTROL
+static tbb::global_control *task_scheduler_global_control = nullptr;
+#endif
+
+void BLI_task_scheduler_init()
+{
+#ifdef WITH_TBB_GLOBAL_CONTROL
+ const int num_threads_override = BLI_system_num_threads_override_get();
+
+ if (num_threads_override > 0) {
+ /* Override number of threads. This settings is used within the lifetime
+ * of tbb::global_control, so we allocate it on the heap. */
+ task_scheduler_global_control = OBJECT_GUARDED_NEW(
+ tbb::global_control, tbb::global_control::max_allowed_parallelism, num_threads_override);
+ task_scheduler_num_threads = num_threads_override;
+ }
+ else {
+ /* Let TBB choose the number of threads. For (legacy) code that calls
+ * BLI_task_scheduler_num_threads() we provide the system thread count.
+ * Ideally such code should be rewritten not to use the number of threads
+ * at all. */
+ task_scheduler_num_threads = BLI_system_thread_count();
+ }
+#else
+ task_scheduler_num_threads = BLI_system_thread_count();
+#endif
+}
+
+void BLI_task_scheduler_exit()
+{
+#ifdef WITH_TBB_GLOBAL_CONTROL
+ OBJECT_GUARDED_DELETE(task_scheduler_global_control, tbb::global_control);
+#endif
+}
+
+int BLI_task_scheduler_num_threads()
+{
+ return task_scheduler_num_threads;
+}
diff --git a/source/blender/blenlib/intern/threads.c b/source/blender/blenlib/intern/threads.c
index 0a574ea34ca..be43c27e945 100644
--- a/source/blender/blenlib/intern/threads.c
+++ b/source/blender/blenlib/intern/threads.c
@@ -61,9 +61,6 @@ extern pthread_key_t gomp_tls_key;
static void *thread_tls_data;
#endif
-/* We're using one global task scheduler for all kind of tasks. */
-static TaskScheduler *task_scheduler = NULL;
-
/* ********** basic thread control API ************
*
* Many thread cases have an X amount of jobs, and only an Y amount of
@@ -93,11 +90,9 @@ static TaskScheduler *task_scheduler = NULL;
* for (go over all jobs)
* if (job is ready) {
* if (job was not removed) {
- * BLI_threadpool_remove(&lb, job);
- * }
+ * BLI_threadpool_remove(&lb, job); * }
* }
- * else cont = 1;
- * }
+ * else cont = 1; * }
* // conditions to exit loop
* if (if escape loop event) {
* if (BLI_available_threadslots(&lb) == maxthreads) {
@@ -109,7 +104,6 @@ static TaskScheduler *task_scheduler = NULL;
* BLI_threadpool_end(&lb);
*
************************************************ */
-static SpinLock _malloc_lock;
static pthread_mutex_t _image_lock = PTHREAD_MUTEX_INITIALIZER;
static pthread_mutex_t _image_draw_lock = PTHREAD_MUTEX_INITIALIZER;
static pthread_mutex_t _viewer_lock = PTHREAD_MUTEX_INITIALIZER;
@@ -137,21 +131,9 @@ typedef struct ThreadSlot {
int avail;
} ThreadSlot;
-static void BLI_lock_malloc_thread(void)
-{
- BLI_spin_lock(&_malloc_lock);
-}
-
-static void BLI_unlock_malloc_thread(void)
-{
- BLI_spin_unlock(&_malloc_lock);
-}
-
void BLI_threadapi_init(void)
{
mainid = pthread_self();
-
- BLI_spin_init(&_malloc_lock);
if (numaAPI_Initialize() == NUMAAPI_SUCCESS) {
is_numa_available = true;
}
@@ -159,25 +141,6 @@ void BLI_threadapi_init(void)
void BLI_threadapi_exit(void)
{
- if (task_scheduler) {
- BLI_task_scheduler_free(task_scheduler);
- task_scheduler = NULL;
- }
- BLI_spin_end(&_malloc_lock);
-}
-
-TaskScheduler *BLI_task_scheduler_get(void)
-{
- if (task_scheduler == NULL) {
- int tot_thread = BLI_system_thread_count();
-
- /* Do a lazy initialization, so it happens after
- * command line arguments parsing
- */
- task_scheduler = BLI_task_scheduler_create(tot_thread);
- }
-
- return task_scheduler;
}
/* tot = 0 only initializes malloc mutex in a safe way (see sequence.c)
@@ -208,8 +171,6 @@ void BLI_threadpool_init(ListBase *threadbase, void *(*do_thread)(void *), int t
unsigned int level = atomic_fetch_and_add_u(&thread_levels, 1);
if (level == 0) {
- MEM_set_lock_callback(BLI_lock_malloc_thread, BLI_unlock_malloc_thread);
-
#ifdef USE_APPLE_OMP_FIX
/* workaround for Apple gcc 4.2.1 omp vs background thread bug,
* we copy gomp thread local storage pointer to setting it again
@@ -336,11 +297,6 @@ void BLI_threadpool_end(ListBase *threadbase)
}
BLI_freelistN(threadbase);
}
-
- unsigned int level = atomic_sub_and_fetch_u(&thread_levels, 1);
- if (level == 0) {
- MEM_set_lock_callback(NULL, NULL);
- }
}
/* System Information */
@@ -834,29 +790,6 @@ void BLI_thread_queue_wait_finish(ThreadQueue *queue)
pthread_mutex_unlock(&queue->mutex);
}
-/* ************************************************ */
-
-void BLI_threaded_malloc_begin(void)
-{
- unsigned int level = atomic_fetch_and_add_u(&thread_levels, 1);
- if (level == 0) {
- MEM_set_lock_callback(BLI_lock_malloc_thread, BLI_unlock_malloc_thread);
- /* There is a little chance that two threads will need to access to a
- * scheduler which was not yet created from main thread. which could
- * cause scheduler created multiple times.
- */
- BLI_task_scheduler_get();
- }
-}
-
-void BLI_threaded_malloc_end(void)
-{
- unsigned int level = atomic_sub_and_fetch_u(&thread_levels, 1);
- if (level == 0) {
- MEM_set_lock_callback(NULL, NULL);
- }
-}
-
/* **** Special functions to help performance on crazy NUMA setups. **** */
#if 0 /* UNUSED */
diff --git a/source/blender/blenlib/intern/timeit.cc b/source/blender/blenlib/intern/timeit.cc
new file mode 100644
index 00000000000..bab8fd81746
--- /dev/null
+++ b/source/blender/blenlib/intern/timeit.cc
@@ -0,0 +1,36 @@
+/*
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+
+#include "BLI_timeit.hh"
+
+namespace BLI {
+namespace Timeit {
+
+void print_duration(Nanoseconds duration)
+{
+ if (duration < std::chrono::microseconds(100)) {
+ std::cout << duration.count() << " ns";
+ }
+ else if (duration < std::chrono::seconds(5)) {
+ std::cout << duration.count() / 1.0e6 << " ms";
+ }
+ else {
+ std::cout << duration.count() / 1.0e9 << " s";
+ }
+}
+
+} // namespace Timeit
+} // namespace BLI
diff --git a/source/blender/blenloader/BLO_read_write.h b/source/blender/blenloader/BLO_read_write.h
new file mode 100644
index 00000000000..7abfa621736
--- /dev/null
+++ b/source/blender/blenloader/BLO_read_write.h
@@ -0,0 +1,207 @@
+/*
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+
+/** \file
+ * \ingroup blenloader
+ *
+ * This file contains an API that allows different parts of Blender to define what data is stored
+ * in .blend files.
+ *
+ * Four callbacks have to be provided to fully implement .blend I/O for a piece of data. One of
+ * those is related to file writing and three for file reading. Reading requires multiple
+ * callbacks, due to the way linking between files works.
+ *
+ * Brief description of the individual callbacks:
+ * - Blend Write: Define which structs and memory buffers are saved.
+ * - Blend Read Data: Loads structs and memory buffers from file and updates pointers them.
+ * - Blend Read Lib: Updates pointers to ID data blocks.
+ * - Blend Expand: Defines which other data blocks should be loaded (possibly from other files).
+ *
+ * Each of these callbacks uses a different API functions.
+ *
+ * Some parts of Blender, e.g. modifiers, don't require you to implement all four callbacks.
+ * Instead only the first two are necessary. The other two are handled by general ID management. In
+ * the future, we might want to get rid of those two callbacks entirely, but for now they are
+ * necessary.
+ */
+
+#ifndef __BLO_READ_WRITE_H__
+#define __BLO_READ_WRITE_H__
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+typedef struct BlendWriter BlendWriter;
+typedef struct BlendDataReader BlendDataReader;
+typedef struct BlendLibReader BlendLibReader;
+typedef struct BlendExpander BlendExpander;
+
+/* Blend Write API
+ * ===============
+ *
+ * Most functions fall into one of two categories. Either they write a DNA struct or a raw memory
+ * buffer to the .blend file.
+ *
+ * It is safe to pass NULL as data_ptr. In this case nothing will be stored.
+ *
+ * DNA Struct Writing
+ * ------------------
+ *
+ * Functions dealing with DNA structs begin with BLO_write_struct_*.
+ *
+ * DNA struct types can be identified in different ways:
+ * - Run-time Name: The name is provided as const char *.
+ * - Compile-time Name: The name is provided at compile time. This can be more efficient. Note
+ * that this optimization is not implemented currently.
+ * - Struct ID: Every DNA struct type has an integer ID that can be queried with
+ * BLO_get_struct_id_by_name. Providing this ID can be a useful optimization when many structs
+ * of the same type are stored AND if those structs are not in a continuous array.
+ *
+ * Often only a single instance of a struct is written at once. However, sometimes it is necessary
+ * to write arrays or linked lists. Separate functions for that are provided as well.
+ *
+ * There is a special macro for writing id structs: BLO_write_id_struct. Those are handled
+ * differently from other structs.
+ *
+ * Raw Data Writing
+ * ----------------
+ *
+ * At the core there is BLO_write_raw, which can write arbitrary memory buffers to the file. The
+ * code that reads this data might have to correct its byte-order. For the common cases there are
+ * convenience functions that write and read arrays of simple types such as int32. Those will
+ * correct endianness automatically.
+ */
+
+/* Mapping between names and ids. */
+int BLO_get_struct_id_by_name(BlendWriter *writer, const char *struct_name);
+#define BLO_get_struct_id(writer, struct_name) BLO_get_struct_id_by_name(writer, #struct_name)
+
+/* Write single struct. */
+void BLO_write_struct_by_name(BlendWriter *writer, const char *struct_name, const void *data_ptr);
+void BLO_write_struct_by_id(BlendWriter *writer, int struct_id, const void *data_ptr);
+#define BLO_write_struct(writer, struct_name, data_ptr) \
+ BLO_write_struct_by_id(writer, BLO_get_struct_id(writer, struct_name), data_ptr)
+
+/* Write struct array. */
+void BLO_write_struct_array_by_name(BlendWriter *writer,
+ const char *struct_name,
+ int array_size,
+ const void *data_ptr);
+void BLO_write_struct_array_by_id(BlendWriter *writer,
+ int struct_id,
+ int array_size,
+ const void *data_ptr);
+#define BLO_write_struct_array(writer, struct_name, array_size, data_ptr) \
+ BLO_write_struct_array_by_id( \
+ writer, BLO_get_struct_id(writer, struct_name), array_size, data_ptr)
+
+/* Write struct list. */
+void BLO_write_struct_list_by_name(BlendWriter *writer,
+ const char *struct_name,
+ struct ListBase *list);
+void BLO_write_struct_list_by_id(BlendWriter *writer, int struct_id, struct ListBase *list);
+#define BLO_write_struct_list(writer, struct_name, list_ptr) \
+ BLO_write_struct_list_by_id(writer, BLO_get_struct_id(writer, struct_name), list_ptr)
+
+/* Write id struct. */
+void blo_write_id_struct(BlendWriter *writer,
+ int struct_id,
+ const void *id_address,
+ const struct ID *id);
+#define BLO_write_id_struct(writer, struct_name, id_address, id) \
+ blo_write_id_struct(writer, BLO_get_struct_id(writer, struct_name), id_address, id)
+
+/* Write raw data. */
+void BLO_write_raw(BlendWriter *writer, int size_in_bytes, const void *data_ptr);
+void BLO_write_int32_array(BlendWriter *writer, int size, const int32_t *data_ptr);
+void BLO_write_uint32_array(BlendWriter *writer, int size, const uint32_t *data_ptr);
+void BLO_write_float_array(BlendWriter *writer, int size, const float *data_ptr);
+void BLO_write_float3_array(BlendWriter *writer, int size, const float *data_ptr);
+void BLO_write_string(BlendWriter *writer, const char *data_ptr);
+
+/* Misc. */
+bool BLO_write_is_undo(BlendWriter *writer);
+
+/* Blend Read Data API
+ * ===================
+ *
+ * Generally, for every BLO_write_* call there should be a corresponding BLO_read_* call.
+ *
+ * Most BLO_read_* functions get a pointer to a pointer as argument. That allows the function to
+ * update the pointer to its new value.
+ *
+ * When the given pointer points to a memory buffer that was not stored in the file, the pointer is
+ * updated to be NULL. When it was pointing to NULL before, it will stay that way.
+ *
+ * Examples of matching calls:
+ * BLO_write_struct(writer, ClothSimSettings, clmd->sim_parms);
+ * BLO_read_data_address(reader, &clmd->sim_parms);
+ *
+ * BLO_write_struct_list(writer, TimeMarker, &action->markers);
+ * BLO_read_list(reader, &action->markers, NULL);
+ *
+ * BLO_write_int32_array(writer, hmd->totindex, hmd->indexar);
+ * BLO_read_int32_array(reader, hmd->totindex, &hmd->indexar);
+ */
+
+void *BLO_read_get_new_data_address(BlendDataReader *reader, const void *old_address);
+
+#define BLO_read_data_address(reader, ptr_p) \
+ *(ptr_p) = BLO_read_get_new_data_address((reader), *(ptr_p))
+
+typedef void (*BlendReadListFn)(BlendDataReader *reader, void *data);
+void BLO_read_list(BlendDataReader *reader, struct ListBase *list, BlendReadListFn callback);
+
+/* Update data pointers and correct byte-order if necessary. */
+void BLO_read_int32_array(BlendDataReader *reader, int array_size, int32_t **ptr_p);
+void BLO_read_uint32_array(BlendDataReader *reader, int array_size, uint32_t **ptr_p);
+void BLO_read_float_array(BlendDataReader *reader, int array_size, float **ptr_p);
+void BLO_read_float3_array(BlendDataReader *reader, int array_size, float **ptr_p);
+void BLO_read_double_array(BlendDataReader *reader, int array_size, double **ptr_p);
+void BLO_read_pointer_array(BlendDataReader *reader, void **ptr_p);
+
+/* Misc. */
+bool BLO_read_requires_endian_switch(BlendDataReader *reader);
+
+/* Blend Read Lib API
+ * ===================
+ *
+ * This API does almost the same as the Blend Read Data API. However, now only pointers to ID data
+ * blocks are updated.
+ */
+
+ID *BLO_read_get_new_id_address(BlendLibReader *reader, struct Library *lib, struct ID *id);
+
+#define BLO_read_id_address(reader, lib, id_ptr_p) \
+ *(id_ptr_p) = (void *)BLO_read_get_new_id_address((reader), (lib), (ID *)*(id_ptr_p))
+
+/* Blend Expand API
+ * ===================
+ *
+ * BLO_expand has to be called for every data block that should be loaded. If the data block is in
+ * a separate .blend file, it will be pulled from there.
+ */
+
+void BLO_expand_id(BlendExpander *expander, struct ID *id);
+
+#define BLO_expand(expander, id) BLO_expand_id(expander, (struct ID *)id)
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* __BLO_READ_WRITE_H__ */
diff --git a/source/blender/blenloader/BLO_undofile.h b/source/blender/blenloader/BLO_undofile.h
index 5f1142cc20e..f9300f8a521 100644
--- a/source/blender/blenloader/BLO_undofile.h
+++ b/source/blender/blenloader/BLO_undofile.h
@@ -26,6 +26,7 @@
*/
struct Scene;
+struct GHash;
typedef struct {
void *next, *prev;
@@ -38,6 +39,9 @@ typedef struct {
* detect unchanged IDs).
* Defined when writing the next step (i.e. last undo step has those always false). */
bool is_identical_future;
+ /** Session UUID of the ID being currently written (MAIN_ID_SESSION_UUID_UNSET when not writing
+ * ID-related data). Used to find matching chunks in previous memundo step. */
+ uint id_session_uuid;
} MemFileChunk;
typedef struct MemFile {
@@ -45,6 +49,17 @@ typedef struct MemFile {
size_t size;
} MemFile;
+typedef struct MemFileWriteData {
+ MemFile *written_memfile;
+ MemFile *reference_memfile;
+
+ uint current_id_session_uuid;
+ MemFileChunk *reference_current_chunk;
+
+ /** Maps an ID session uuid to its first reference MemFileChunk, if existing. */
+ struct GHash *id_session_uuid_mapping;
+} MemFileWriteData;
+
typedef struct MemFileUndoData {
char filename[1024]; /* FILE_MAX */
MemFile memfile;
@@ -52,14 +67,18 @@ typedef struct MemFileUndoData {
} MemFileUndoData;
/* actually only used writefile.c */
-extern void memfile_chunk_add(MemFile *memfile,
- const char *buf,
- unsigned int size,
- MemFileChunk **compchunk_step);
+
+void BLO_memfile_write_init(MemFileWriteData *mem_data,
+ MemFile *written_memfile,
+ MemFile *reference_memfile);
+void BLO_memfile_write_finalize(MemFileWriteData *mem_data);
+
+void BLO_memfile_chunk_add(MemFileWriteData *mem_data, const char *buf, unsigned int size);
/* exports */
extern void BLO_memfile_free(MemFile *memfile);
extern void BLO_memfile_merge(MemFile *first, MemFile *second);
+extern void BLO_memfile_clear_future(MemFile *memfile);
/* utilities */
extern struct Main *BLO_memfile_main_get(struct MemFile *memfile,
diff --git a/source/blender/blenloader/CMakeLists.txt b/source/blender/blenloader/CMakeLists.txt
index 450d3fc2371..09e2f4bf417 100644
--- a/source/blender/blenloader/CMakeLists.txt
+++ b/source/blender/blenloader/CMakeLists.txt
@@ -53,6 +53,7 @@ set(SRC
intern/versioning_260.c
intern/versioning_270.c
intern/versioning_280.c
+ intern/versioning_290.c
intern/versioning_cycles.c
intern/versioning_defaults.c
intern/versioning_dna.c
@@ -63,6 +64,7 @@ set(SRC
BLO_blend_defs.h
BLO_blend_validate.h
BLO_readfile.h
+ BLO_read_write.h
BLO_undofile.h
BLO_writefile.h
intern/readfile.h
diff --git a/source/blender/blenloader/intern/readblenentry.c b/source/blender/blenloader/intern/readblenentry.c
index adf7db0267e..1309b3e3c33 100644
--- a/source/blender/blenloader/intern/readblenentry.c
+++ b/source/blender/blenloader/intern/readblenentry.c
@@ -428,41 +428,6 @@ BlendFileData *BLO_read_from_memfile(Main *oldmain,
* but oldmain itself shall *never* be 'transferred' to new mainlist! */
BLI_assert(old_mainlist.first == oldmain);
- if (bfd && old_mainlist.first != old_mainlist.last) {
- /* Even though directly used libs have been already moved to new main,
- * indirect ones have not.
- * This is a bit annoying, but we have no choice but to keep them all for now -
- * means some now unused data may remain in memory, but think we'll have to live with it. */
- Main *libmain, *libmain_next;
- Main *newmain = bfd->main;
- ListBase new_mainlist = {newmain, newmain};
-
- for (libmain = oldmain->next; libmain; libmain = libmain_next) {
- libmain_next = libmain->next;
- /* Note that LIB_INDIRECT does not work with libraries themselves, so we use non-NULL
- * parent to detect indirect-linked ones. */
- if (libmain->curlib && (libmain->curlib->parent != NULL)) {
- BLI_remlink(&old_mainlist, libmain);
- BLI_addtail(&new_mainlist, libmain);
- }
- else {
-#ifdef PRINT_DEBUG
- printf("Dropped Main for lib: %s\n", libmain->curlib->id.name);
-#endif
- }
- }
- /* In any case, we need to move all lib data-blocks themselves - those are
- * 'first level data', getting rid of them would imply updating spaces & co
- * to prevent invalid pointers access. */
- BLI_movelisttolist(&newmain->libraries, &oldmain->libraries);
-
- blo_join_main(&new_mainlist);
- }
-
-#if 0
- printf("Remaining mains/libs in oldmain: %d\n", BLI_listbase_count(&fd->old_mainlist) - 1);
-#endif
-
/* That way, libs (aka mains) we did not reuse in new undone/redone state
* will be cleared together with oldmain... */
blo_join_main(&old_mainlist);
diff --git a/source/blender/blenloader/intern/readfile.c b/source/blender/blenloader/intern/readfile.c
index 61179f65ad2..6a51102a969 100644
--- a/source/blender/blenloader/intern/readfile.c
+++ b/source/blender/blenloader/intern/readfile.c
@@ -86,6 +86,7 @@
#include "DNA_sdna_types.h"
#include "DNA_sequence_types.h"
#include "DNA_shader_fx_types.h"
+#include "DNA_simulation_types.h"
#include "DNA_sound_types.h"
#include "DNA_space_types.h"
#include "DNA_speaker_types.h"
@@ -109,7 +110,7 @@
#include "BLT_translation.h"
#include "BKE_action.h"
-#include "BKE_animsys.h"
+#include "BKE_anim_data.h"
#include "BKE_armature.h"
#include "BKE_brush.h"
#include "BKE_collection.h"
@@ -117,7 +118,7 @@
#include "BKE_constraint.h"
#include "BKE_curve.h"
#include "BKE_effect.h"
-#include "BKE_fcurve.h"
+#include "BKE_fcurve_driver.h"
#include "BKE_fluid.h"
#include "BKE_global.h" // for G
#include "BKE_gpencil_modifier.h"
@@ -146,6 +147,7 @@
#include "BKE_screen.h"
#include "BKE_sequencer.h"
#include "BKE_shader_fx.h"
+#include "BKE_simulation.h"
#include "BKE_sound.h"
#include "BKE_volume.h"
#include "BKE_workspace.h"
@@ -158,6 +160,7 @@
#include "BLO_blend_defs.h"
#include "BLO_blend_validate.h"
+#include "BLO_read_write.h"
#include "BLO_readfile.h"
#include "BLO_undofile.h"
@@ -470,8 +473,9 @@ static void *oldnewmap_liblookup(OldNewMap *onm, const void *addr, const void *l
return NULL;
}
-static void oldnewmap_free_unused(OldNewMap *onm)
+static void oldnewmap_clear(OldNewMap *onm)
{
+ /* Free unused data. */
for (int i = 0; i < onm->nentries; i++) {
OldNew *entry = &onm->entries[i];
if (entry->nr == 0) {
@@ -479,10 +483,7 @@ static void oldnewmap_free_unused(OldNewMap *onm)
entry->newp = NULL;
}
}
-}
-static void oldnewmap_clear(OldNewMap *onm)
-{
onm->capacity_exp = DEFAULT_SIZE_EXP;
oldnewmap_clear_map(onm);
onm->nentries = 0;
@@ -664,7 +665,7 @@ static Main *blo_find_main(FileData *fd, const char *filepath, const char *relab
char name1[FILE_MAX];
BLI_strncpy(name1, filepath, sizeof(name1));
- BLI_cleanup_path(relabase, name1);
+ BLI_path_normalize(relabase, name1);
// printf("blo_find_main: relabase %s\n", relabase);
// printf("blo_find_main: original in %s\n", filepath);
@@ -691,7 +692,7 @@ static Main *blo_find_main(FileData *fd, const char *filepath, const char *relab
/* Important, consistency with main ID reading code from read_libblock(). */
lib->id.us = ID_FAKE_USERS(lib);
- /* Matches lib_link_library(). */
+ /* Matches direct_link_library(). */
id_us_ensure_real(&lib->id);
BLI_strncpy(lib->name, filepath, sizeof(lib->name));
@@ -713,6 +714,20 @@ static Main *blo_find_main(FileData *fd, const char *filepath, const char *relab
/** \name File Parsing
* \{ */
+typedef struct BlendDataReader {
+ FileData *fd;
+} BlendDataReader;
+
+typedef struct BlendLibReader {
+ FileData *fd;
+ Main *main;
+} BlendLibReader;
+
+typedef struct BlendExpander {
+ FileData *fd;
+ Main *main;
+} BlendExpander;
+
static void switch_endian_bh4(BHead4 *bhead)
{
/* the ID_.. codes */
@@ -1680,7 +1695,7 @@ bool BLO_library_path_explode(const char *path, char *r_dir, char **r_group, cha
strcpy(r_dir, path);
- while ((slash = (char *)BLI_last_slash(r_dir))) {
+ while ((slash = (char *)BLI_path_slash_rfind(r_dir))) {
char tc = *slash;
*slash = '\0';
if (BLO_has_bfile_extension(r_dir) && BLI_is_file(r_dir)) {
@@ -2376,9 +2391,6 @@ static void *read_struct(FileData *fd, BHead *bh, const char *blockname)
}
}
- if (!BHEADN_FROM_BHEAD(bh)->is_memchunk_identical) {
- fd->are_memchunks_identical = false;
- }
#ifdef USE_BHEAD_READ_ON_DEMAND
if (bh_orig != bh) {
MEM_freeN(BHEADN_FROM_BHEAD(bh));
@@ -2389,6 +2401,15 @@ static void *read_struct(FileData *fd, BHead *bh, const char *blockname)
return temp;
}
+/* Like read_struct, but gets a pointer without allocating. Only works for
+ * undo since DNA must match. */
+static const void *peek_struct_undo(FileData *fd, BHead *bhead)
+{
+ BLI_assert(fd->memfile != NULL);
+ UNUSED_VARS_NDEBUG(fd);
+ return (bhead->len) ? (const void *)(bhead + 1) : NULL;
+}
+
typedef void (*link_list_cb)(FileData *fd, void *data);
static void link_list_ex(FileData *fd, ListBase *lb, link_list_cb callback) /* only direct data */
@@ -2670,7 +2691,7 @@ static void IDP_LibLinkProperty(IDProperty *prop, FileData *fd)
}
case IDP_GROUP: /* PointerProperty */
{
- for (IDProperty *loop = prop->data.group.first; loop; loop = loop->next) {
+ LISTBASE_FOREACH (IDProperty *, loop, &prop->data.group) {
IDP_LibLinkProperty(loop, fd);
}
break;
@@ -2715,7 +2736,7 @@ static void lib_link_id(FileData *fd, Main *bmain, ID *id);
static void lib_link_nodetree(FileData *fd, Main *bmain, bNodeTree *ntree);
static void lib_link_collection(FileData *fd, Main *bmain, Collection *collection);
-static void lib_link_id_private_id(FileData *fd, Main *bmain, ID *id)
+static void lib_link_id_embedded_id(FileData *fd, Main *bmain, ID *id)
{
/* Handle 'private IDs'. */
bNodeTree *nodetree = ntreeFromID(id);
@@ -2749,7 +2770,7 @@ static void lib_link_id(FileData *fd, Main *bmain, ID *id)
id->override_library->storage = newlibadr(fd, id->lib, id->override_library->storage);
}
- lib_link_id_private_id(fd, bmain, id);
+ lib_link_id_embedded_id(fd, bmain, id);
}
static void direct_link_id_override_property_operation_cb(FileData *fd, void *data)
@@ -2758,6 +2779,8 @@ static void direct_link_id_override_property_operation_cb(FileData *fd, void *da
opop->subitem_reference_name = newdataadr(fd, opop->subitem_reference_name);
opop->subitem_local_name = newdataadr(fd, opop->subitem_local_name);
+
+ opop->tag = 0; /* Runtime only. */
}
static void direct_link_id_override_property_cb(FileData *fd, void *data)
@@ -2765,20 +2788,28 @@ static void direct_link_id_override_property_cb(FileData *fd, void *data)
IDOverrideLibraryProperty *op = data;
op->rna_path = newdataadr(fd, op->rna_path);
+
+ op->tag = 0; /* Runtime only. */
+
link_list_ex(fd, &op->operations, direct_link_id_override_property_operation_cb);
}
-static void direct_link_id(FileData *fd, ID *id, ID *id_old);
+static void direct_link_id_common(
+ FileData *fd, Library *current_library, ID *id, ID *id_old, const int tag);
static void direct_link_nodetree(FileData *fd, bNodeTree *ntree);
static void direct_link_collection(FileData *fd, Collection *collection);
-static void direct_link_id_private_id(FileData *fd, ID *id, ID *id_old)
+static void direct_link_id_embedded_id(FileData *fd, Library *current_library, ID *id, ID *id_old)
{
/* Handle 'private IDs'. */
bNodeTree **nodetree = BKE_ntree_ptr_from_id(id);
if (nodetree != NULL && *nodetree != NULL) {
*nodetree = newdataadr(fd, *nodetree);
- direct_link_id(fd, (ID *)*nodetree, id_old != NULL ? (ID *)ntreeFromID(id_old) : NULL);
+ direct_link_id_common(fd,
+ current_library,
+ (ID *)*nodetree,
+ id_old != NULL ? (ID *)ntreeFromID(id_old) : NULL,
+ 0);
direct_link_nodetree(fd, *nodetree);
}
@@ -2786,28 +2817,106 @@ static void direct_link_id_private_id(FileData *fd, ID *id, ID *id_old)
Scene *scene = (Scene *)id;
if (scene->master_collection != NULL) {
scene->master_collection = newdataadr(fd, scene->master_collection);
- direct_link_id(fd,
- &scene->master_collection->id,
- id_old != NULL ? &((Scene *)id_old)->master_collection->id : NULL);
+ direct_link_id_common(fd,
+ current_library,
+ &scene->master_collection->id,
+ id_old != NULL ? &((Scene *)id_old)->master_collection->id : NULL,
+ 0);
direct_link_collection(fd, scene->master_collection);
}
}
}
-static void direct_link_id(FileData *fd, ID *id, ID *id_old)
+static int direct_link_id_restore_recalc_exceptions(const ID *id_current)
+{
+ /* Exception for armature objects, where the pose has direct points to the
+ * armature databolock. */
+ if (GS(id_current->name) == ID_OB && ((Object *)id_current)->pose) {
+ return ID_RECALC_GEOMETRY;
+ }
+
+ return 0;
+}
+
+static int direct_link_id_restore_recalc(const FileData *fd,
+ const ID *id_target,
+ const ID *id_current,
+ const bool is_identical)
+{
+ /* These are the evaluations that had not been performed yet at the time the
+ * target undo state was written. These need to be done again, since they may
+ * flush back changes to the original datablock. */
+ int recalc = id_target->recalc;
+
+ if (id_current == NULL) {
+ /* ID does not currently exist in the database, so also will not exist in
+ * the dependency graphs. That means it will be newly created and as a
+ * result also fully re-evaluated regardless of the recalc flag set here. */
+ recalc |= ID_RECALC_ALL;
+ }
+ else {
+ /* If the contents datablock changed, the depsgraph needs to copy the
+ * datablock again to ensure it matches the original datablock. */
+ if (!is_identical) {
+ recalc |= ID_RECALC_COPY_ON_WRITE;
+ }
+
+ /* Special exceptions. */
+ recalc |= direct_link_id_restore_recalc_exceptions(id_current);
+
+ /* Evaluations for the current state that have not been performed yet
+ * by the time we are performing this undo step. */
+ recalc |= id_current->recalc;
+
+ /* Tags that were set between the target state and the current state,
+ * that we need to perform again. */
+ if (fd->undo_direction < 0) {
+ /* Undo: tags from target to the current state. */
+ recalc |= id_current->recalc_up_to_undo_push;
+ }
+ else {
+ /* Redo: tags from current to the target state. */
+ recalc |= id_target->recalc_up_to_undo_push;
+ }
+ }
+
+ return recalc;
+}
+
+static void direct_link_id_common(
+ FileData *fd, Library *current_library, ID *id, ID *id_old, const int tag)
{
+ if (fd->memfile == NULL) {
+ /* When actually reading a file , we do want to reset/re-generate session uuids.
+ * In undo case, we want to re-use existing ones. */
+ id->session_uuid = MAIN_ID_SESSION_UUID_UNSET;
+ }
+
+ BKE_lib_libblock_session_uuid_ensure(id);
+
+ id->lib = current_library;
+ id->us = ID_FAKE_USERS(id);
+ id->icon_id = 0;
+ id->newid = NULL; /* Needed because .blend may have been saved with crap value here... */
+ id->orig_id = NULL;
+ id->py_instance = NULL;
+
+ /* Initialize with provided tag. */
+ id->tag = tag;
+
+ if (tag & LIB_TAG_ID_LINK_PLACEHOLDER) {
+ /* For placeholder we only need to set the tag and properly initialize generic ID fields above,
+ * no further data to read. */
+ return;
+ }
+
/*link direct data of ID properties*/
if (id->properties) {
id->properties = newdataadr(fd, id->properties);
/* this case means the data was written incorrectly, it should not happen */
IDP_DirectLinkGroup_OrFree(&id->properties, (fd->flags & FD_FLAGS_SWITCH_ENDIAN), fd);
}
- id->py_instance = NULL;
- /* That way data-lock reading not going through main read_libblock()
- * function are still in a clear tag state.
- * (glowering at certain nodetree fake data-lock here...). */
- id->tag = 0;
id->flag &= ~LIB_INDIRECT_WEAK_LINK;
/* NOTE: It is important to not clear the recalc flags for undo/redo.
@@ -2820,32 +2929,11 @@ static void direct_link_id(FileData *fd, ID *id, ID *id_old)
* the version the file has been saved with. */
if (fd->memfile == NULL) {
id->recalc = 0;
- id->recalc_undo_accumulated = 0;
+ id->recalc_after_undo_push = 0;
}
else if ((fd->skip_flags & BLO_READ_SKIP_UNDO_OLD_MAIN) == 0) {
- if (fd->undo_direction < 0) {
- /* We are coming from the future (i.e. do an actual undo, and not a redo), and we found an
- * old (aka existing) ID: we use its 'accumulated recalc flags since last memfile undo step
- * saving' as recalc flags of our newly read ID. */
- if (id_old != NULL) {
- id->recalc = id_old->recalc_undo_accumulated;
- }
- }
- else {
- /* We are coming from the past (i.e. do a redo), we use saved 'accumulated
- * recalc flags since last memfile undo step saving' as recalc flags of our newly read ID. */
- id->recalc = id->recalc_undo_accumulated;
- }
- /* In any case, we need to flush the depsgraph's CoWs, as even if the ID address itself did not
- * change, internal data most likely have. */
- id->recalc |= ID_RECALC_COPY_ON_WRITE;
-
- /* We need to 'accumulate' the accumulated recalc flags of all undo steps until we actually
- * perform a depsgraph update, otherwise we'd only ever use the flags from one of the steps,
- * and never get proper flags matching all others. */
- if (id_old != NULL) {
- id->recalc_undo_accumulated |= id_old->recalc_undo_accumulated;
- }
+ id->recalc = direct_link_id_restore_recalc(fd, id, id_old, false);
+ id->recalc_after_undo_push = 0;
}
/* Link direct data of overrides. */
@@ -2861,7 +2949,7 @@ static void direct_link_id(FileData *fd, ID *id, ID *id_old)
}
/* Handle 'private IDs'. */
- direct_link_id_private_id(fd, id, id_old);
+ direct_link_id_embedded_id(fd, current_library, id, id_old);
}
/** \} */
@@ -2955,6 +3043,19 @@ static void direct_link_brush(FileData *fd, Brush *brush)
brush->gpencil_settings->curve_strength);
brush->gpencil_settings->curve_jitter = newdataadr(fd, brush->gpencil_settings->curve_jitter);
+ brush->gpencil_settings->curve_rand_pressure = newdataadr(
+ fd, brush->gpencil_settings->curve_rand_pressure);
+ brush->gpencil_settings->curve_rand_strength = newdataadr(
+ fd, brush->gpencil_settings->curve_rand_strength);
+ brush->gpencil_settings->curve_rand_uv = newdataadr(fd,
+ brush->gpencil_settings->curve_rand_uv);
+ brush->gpencil_settings->curve_rand_hue = newdataadr(fd,
+ brush->gpencil_settings->curve_rand_hue);
+ brush->gpencil_settings->curve_rand_saturation = newdataadr(
+ fd, brush->gpencil_settings->curve_rand_saturation);
+ brush->gpencil_settings->curve_rand_value = newdataadr(
+ fd, brush->gpencil_settings->curve_rand_value);
+
if (brush->gpencil_settings->curve_sensitivity) {
direct_link_curvemapping(fd, brush->gpencil_settings->curve_sensitivity);
}
@@ -2966,6 +3067,30 @@ static void direct_link_brush(FileData *fd, Brush *brush)
if (brush->gpencil_settings->curve_jitter) {
direct_link_curvemapping(fd, brush->gpencil_settings->curve_jitter);
}
+
+ if (brush->gpencil_settings->curve_rand_pressure) {
+ direct_link_curvemapping(fd, brush->gpencil_settings->curve_rand_pressure);
+ }
+
+ if (brush->gpencil_settings->curve_rand_strength) {
+ direct_link_curvemapping(fd, brush->gpencil_settings->curve_rand_strength);
+ }
+
+ if (brush->gpencil_settings->curve_rand_uv) {
+ direct_link_curvemapping(fd, brush->gpencil_settings->curve_rand_uv);
+ }
+
+ if (brush->gpencil_settings->curve_rand_hue) {
+ direct_link_curvemapping(fd, brush->gpencil_settings->curve_rand_hue);
+ }
+
+ if (brush->gpencil_settings->curve_rand_saturation) {
+ direct_link_curvemapping(fd, brush->gpencil_settings->curve_rand_saturation);
+ }
+
+ if (brush->gpencil_settings->curve_rand_value) {
+ direct_link_curvemapping(fd, brush->gpencil_settings->curve_rand_value);
+ }
}
brush->preview = NULL;
@@ -3030,7 +3155,7 @@ static PackedFile *direct_link_packedfile(FileData *fd, PackedFile *oldpf)
// XXX deprecated - old animation system
static void lib_link_ipo(FileData *fd, Main *UNUSED(bmain), Ipo *ipo)
{
- for (IpoCurve *icu = ipo->curve.first; icu; icu = icu->next) {
+ LISTBASE_FOREACH (IpoCurve *, icu, &ipo->curve) {
if (icu->driver) {
icu->driver->ob = newlibadr(fd, ipo->id.lib, icu->driver->ob);
}
@@ -3251,7 +3376,7 @@ static void direct_link_fcurves(FileData *fd, ListBase *list)
static void lib_link_action(FileData *fd, Main *UNUSED(bmain), bAction *act)
{
// XXX deprecated - old animation system <<<
- for (bActionChannel *chan = act->chanbase.first; chan; chan = chan->next) {
+ LISTBASE_FOREACH (bActionChannel *, chan, &act->chanbase) {
chan->ipo = newlibadr(fd, act->id.lib, chan->ipo);
lib_link_constraint_channels(fd, &act->id, &chan->constraintChannels);
}
@@ -3259,7 +3384,7 @@ static void lib_link_action(FileData *fd, Main *UNUSED(bmain), bAction *act)
lib_link_fcurves(fd, &act->id, &act->curves);
- for (TimeMarker *marker = act->markers.first; marker; marker = marker->next) {
+ LISTBASE_FOREACH (TimeMarker *, marker, &act->markers) {
if (marker->camera) {
marker->camera = newlibadr(fd, act->id.lib, marker->camera);
}
@@ -3305,11 +3430,6 @@ static void lib_link_nladata_strips(FileData *fd, ID *id, ListBase *list)
/* reassign the counted-reference to action */
strip->act = newlibadr(fd, id->lib, strip->act);
-
- /* fix action id-root (i.e. if it comes from a pre 2.57 .blend file) */
- if ((strip->act) && (strip->act->idroot == 0)) {
- strip->act->idroot = GS(id->name);
- }
}
}
@@ -3404,14 +3524,6 @@ static void lib_link_animdata(FileData *fd, ID *id, AnimData *adt)
adt->action = newlibadr(fd, id->lib, adt->action);
adt->tmpact = newlibadr(fd, id->lib, adt->tmpact);
- /* fix action id-roots (i.e. if they come from a pre 2.57 .blend file) */
- if ((adt->action) && (adt->action->idroot == 0)) {
- adt->action->idroot = GS(id->name);
- }
- if ((adt->tmpact) && (adt->tmpact->idroot == 0)) {
- adt->tmpact->idroot = GS(id->name);
- }
-
/* link drivers */
lib_link_fcurves(fd, id, &adt->drivers);
@@ -3482,15 +3594,11 @@ static void direct_link_cachefile(FileData *fd, CacheFile *cache_file)
static void lib_link_workspaces(FileData *fd, Main *bmain, WorkSpace *workspace)
{
- ListBase *layouts = BKE_workspace_layouts_get(workspace);
ID *id = (ID *)workspace;
- id_us_ensure_real(id);
-
- for (WorkSpaceLayout *layout = layouts->first, *layout_next; layout; layout = layout_next) {
+ LISTBASE_FOREACH_MUTABLE (WorkSpaceLayout *, layout, &workspace->layouts) {
layout->screen = newlibadr(fd, id->lib, layout->screen);
- layout_next = layout->next;
if (layout->screen) {
if (ID_IS_LINKED(id)) {
layout->screen->winid = 0;
@@ -3510,39 +3618,34 @@ static void lib_link_workspaces(FileData *fd, Main *bmain, WorkSpace *workspace)
static void direct_link_workspace(FileData *fd, WorkSpace *workspace, const Main *main)
{
- link_list(fd, BKE_workspace_layouts_get(workspace));
+ link_list(fd, &workspace->layouts);
link_list(fd, &workspace->hook_layout_relations);
link_list(fd, &workspace->owner_ids);
link_list(fd, &workspace->tools);
- for (WorkSpaceDataRelation *relation = workspace->hook_layout_relations.first; relation;
- relation = relation->next) {
-
+ LISTBASE_FOREACH (WorkSpaceDataRelation *, relation, &workspace->hook_layout_relations) {
/* data from window - need to access through global oldnew-map */
relation->parent = newglobadr(fd, relation->parent);
-
relation->value = newdataadr(fd, relation->value);
}
/* Same issue/fix as in direct_link_workspace_link_scene_data: Can't read workspace data
* when reading windows, so have to update windows after/when reading workspaces. */
for (wmWindowManager *wm = main->wm.first; wm; wm = wm->id.next) {
- for (wmWindow *win = wm->windows.first; win; win = win->next) {
- WorkSpaceLayout *act_layout = newdataadr(
- fd, BKE_workspace_active_layout_get(win->workspace_hook));
- if (act_layout) {
- BKE_workspace_active_layout_set(win->workspace_hook, act_layout);
- }
+ LISTBASE_FOREACH (wmWindow *, win, &wm->windows) {
+ win->workspace_hook->act_layout = newdataadr(fd, win->workspace_hook->act_layout);
}
}
- for (bToolRef *tref = workspace->tools.first; tref; tref = tref->next) {
+ LISTBASE_FOREACH (bToolRef *, tref, &workspace->tools) {
tref->runtime = NULL;
tref->properties = newdataadr(fd, tref->properties);
IDP_DirectLinkGroup_OrFree(&tref->properties, (fd->flags & FD_FLAGS_SWITCH_ENDIAN), fd);
}
workspace->status_text = NULL;
+
+ id_us_ensure_real(&workspace->id);
}
static void lib_link_workspace_instance_hook(FileData *fd, WorkSpaceInstanceHook *hook, ID *id)
@@ -3557,6 +3660,45 @@ static void lib_link_workspace_instance_hook(FileData *fd, WorkSpaceInstanceHook
/** \name Read ID: Node Tree
* \{ */
+static void lib_link_node_socket(FileData *fd, Library *lib, bNodeSocket *sock)
+{
+ IDP_LibLinkProperty(sock->prop, fd);
+
+ switch ((eNodeSocketDatatype)sock->type) {
+ case SOCK_OBJECT: {
+ bNodeSocketValueObject *default_value = sock->default_value;
+ default_value->value = newlibadr(fd, lib, default_value->value);
+ break;
+ }
+ case SOCK_IMAGE: {
+ bNodeSocketValueImage *default_value = sock->default_value;
+ default_value->value = newlibadr(fd, lib, default_value->value);
+ break;
+ }
+ case SOCK_FLOAT:
+ case SOCK_VECTOR:
+ case SOCK_RGBA:
+ case SOCK_BOOLEAN:
+ case SOCK_INT:
+ case SOCK_STRING:
+ case __SOCK_MESH:
+ case SOCK_CUSTOM:
+ case SOCK_SHADER:
+ case SOCK_EMITTERS:
+ case SOCK_EVENTS:
+ case SOCK_FORCES:
+ case SOCK_CONTROL_FLOW:
+ break;
+ }
+}
+
+static void lib_link_node_sockets(FileData *fd, Library *lib, ListBase *sockets)
+{
+ LISTBASE_FOREACH (bNodeSocket *, sock, sockets) {
+ lib_link_node_socket(fd, lib, sock);
+ }
+}
+
/* Single node tree (also used for material/scene trees), ntree is not NULL */
static void lib_link_ntree(FileData *fd, Library *lib, bNodeTree *ntree)
{
@@ -3564,27 +3706,19 @@ static void lib_link_ntree(FileData *fd, Library *lib, bNodeTree *ntree)
ntree->gpd = newlibadr(fd, lib, ntree->gpd);
- for (bNode *node = ntree->nodes.first; node; node = node->next) {
+ LISTBASE_FOREACH (bNode *, node, &ntree->nodes) {
/* Link ID Properties -- and copy this comment EXACTLY for easy finding
* of library blocks that implement this.*/
IDP_LibLinkProperty(node->prop, fd);
node->id = newlibadr(fd, lib, node->id);
- for (bNodeSocket *sock = node->inputs.first; sock; sock = sock->next) {
- IDP_LibLinkProperty(sock->prop, fd);
- }
- for (bNodeSocket *sock = node->outputs.first; sock; sock = sock->next) {
- IDP_LibLinkProperty(sock->prop, fd);
- }
+ lib_link_node_sockets(fd, lib, &node->inputs);
+ lib_link_node_sockets(fd, lib, &node->outputs);
}
- for (bNodeSocket *sock = ntree->inputs.first; sock; sock = sock->next) {
- IDP_LibLinkProperty(sock->prop, fd);
- }
- for (bNodeSocket *sock = ntree->outputs.first; sock; sock = sock->next) {
- IDP_LibLinkProperty(sock->prop, fd);
- }
+ lib_link_node_sockets(fd, lib, &ntree->inputs);
+ lib_link_node_sockets(fd, lib, &ntree->outputs);
/* Set node->typeinfo pointers. This is done in lib linking, after the
* first versioning that can change types still without functions that
@@ -3595,7 +3729,7 @@ static void lib_link_ntree(FileData *fd, Library *lib, bNodeTree *ntree)
/* For nodes with static socket layout, add/remove sockets as needed
* to match the static layout. */
if (fd->memfile == NULL) {
- for (bNode *node = ntree->nodes.first; node; node = node->next) {
+ LISTBASE_FOREACH (bNode *, node, &ntree->nodes) {
node_verify_socket_templates(ntree, node);
}
}
@@ -3757,23 +3891,23 @@ static void direct_link_nodetree(FileData *fd, bNodeTree *ntree)
}
#if 0
- if (ntree->previews) {
- bNodeInstanceHash* new_previews = BKE_node_instance_hash_new("node previews");
- bNodeInstanceHashIterator iter;
-
- NODE_INSTANCE_HASH_ITER(iter, ntree->previews) {
- bNodePreview* preview = BKE_node_instance_hash_iterator_get_value(&iter);
- if (preview) {
- bNodePreview* new_preview = newimaadr(fd, preview);
- if (new_preview) {
- bNodeInstanceKey key = BKE_node_instance_hash_iterator_get_key(&iter);
- BKE_node_instance_hash_insert(new_previews, key, new_preview);
- }
- }
- }
- BKE_node_instance_hash_free(ntree->previews, NULL);
- ntree->previews = new_previews;
- }
+ if (ntree->previews) {
+ bNodeInstanceHash* new_previews = BKE_node_instance_hash_new("node previews");
+ bNodeInstanceHashIterator iter;
+
+ NODE_INSTANCE_HASH_ITER(iter, ntree->previews) {
+ bNodePreview* preview = BKE_node_instance_hash_iterator_get_value(&iter);
+ if (preview) {
+ bNodePreview* new_preview = newimaadr(fd, preview);
+ if (new_preview) {
+ bNodeInstanceKey key = BKE_node_instance_hash_iterator_get_key(&iter);
+ BKE_node_instance_hash_insert(new_previews, key, new_preview);
+ }
+ }
+ }
+ BKE_node_instance_hash_free(ntree->previews, NULL);
+ ntree->previews = new_previews;
+ }
#else
/* XXX TODO */
ntree->previews = NULL;
@@ -3796,20 +3930,11 @@ typedef struct tConstraintLinkData {
/* callback function used to relink constraint ID-links */
static void lib_link_constraint_cb(bConstraint *UNUSED(con),
ID **idpoin,
- bool is_reference,
+ bool UNUSED(is_reference),
void *userdata)
{
tConstraintLinkData *cld = (tConstraintLinkData *)userdata;
-
- /* for reference types, we need to increment the user-counts on load... */
- if (is_reference) {
- /* reference type - with usercount */
- *idpoin = newlibadr(cld->fd, cld->id->lib, *idpoin);
- }
- else {
- /* target type - no usercount needed */
- *idpoin = newlibadr(cld->fd, cld->id->lib, *idpoin);
- }
+ *idpoin = newlibadr(cld->fd, cld->id->lib, *idpoin);
}
static void lib_link_constraints(FileData *fd, ID *id, ListBase *conlist)
@@ -3929,7 +4054,7 @@ static void lib_link_pose(FileData *fd, Main *bmain, Object *ob, bPose *pose)
}
}
- for (bPoseChannel *pchan = pose->chanbase.first; pchan; pchan = pchan->next) {
+ LISTBASE_FOREACH (bPoseChannel *, pchan, &pose->chanbase) {
lib_link_constraints(fd, (ID *)ob, &pchan->constraints);
pchan->bone = BKE_armature_find_bone_name(arm, pchan->name);
@@ -3958,14 +4083,14 @@ static void lib_link_bones(FileData *fd, Bone *bone)
{
IDP_LibLinkProperty(bone->prop, fd);
- for (Bone *curbone = bone->childbase.first; curbone; curbone = curbone->next) {
+ LISTBASE_FOREACH (Bone *, curbone, &bone->childbase) {
lib_link_bones(fd, curbone);
}
}
static void lib_link_armature(FileData *fd, Main *UNUSED(bmain), bArmature *arm)
{
- for (Bone *curbone = arm->bonebase.first; curbone; curbone = curbone->next) {
+ LISTBASE_FOREACH (Bone *, curbone, &arm->bonebase) {
lib_link_bones(fd, curbone);
}
}
@@ -4026,7 +4151,7 @@ static void lib_link_camera(FileData *fd, Main *UNUSED(bmain), Camera *ca)
ca->dof_ob = newlibadr(fd, ca->id.lib, ca->dof_ob); /* deprecated, for versioning */
ca->dof.focus_object = newlibadr(fd, ca->id.lib, ca->dof.focus_object);
- for (CameraBGImage *bgpic = ca->bg_images.first; bgpic; bgpic = bgpic->next) {
+ LISTBASE_FOREACH (CameraBGImage *, bgpic, &ca->bg_images) {
bgpic->ima = newlibadr(fd, ca->id.lib, bgpic->ima);
bgpic->clip = newlibadr(fd, ca->id.lib, bgpic->clip);
}
@@ -4039,7 +4164,7 @@ static void direct_link_camera(FileData *fd, Camera *ca)
link_list(fd, &ca->bg_images);
- for (CameraBGImage *bgpic = ca->bg_images.first; bgpic; bgpic = bgpic->next) {
+ LISTBASE_FOREACH (CameraBGImage *, bgpic, &ca->bg_images) {
bgpic->iuser.ok = 1;
bgpic->iuser.scene = NULL;
}
@@ -4232,10 +4357,10 @@ static void direct_link_text(FileData *fd, Text *text)
text->compiled = NULL;
#if 0
- if (text->flags & TXT_ISEXT) {
- BKE_text_reload(text);
- }
- /* else { */
+ if (text->flags & TXT_ISEXT) {
+ BKE_text_reload(text);
+ }
+ /* else { */
#endif
link_list(fd, &text->lines);
@@ -4614,7 +4739,7 @@ static void lib_link_particlesettings(FileData *fd, Main *UNUSED(bmain), Particl
}
if (part->instance_weights.first && part->instance_collection) {
- for (ParticleDupliWeight *dw = part->instance_weights.first; dw; dw = dw->next) {
+ LISTBASE_FOREACH (ParticleDupliWeight *, dw, &part->instance_weights) {
dw->ob = newlibadr(fd, part->id.lib, dw->ob);
}
}
@@ -4745,7 +4870,7 @@ static void lib_link_particlesystems(FileData *fd, Object *ob, ID *id, ListBase
/* particle modifier must be removed before particle system */
ParticleSystemModifierData *psmd = psys_get_modifier(ob, psys);
BLI_remlink(&ob->modifiers, psmd);
- modifier_free((ModifierData *)psmd);
+ BKE_modifier_free((ModifierData *)psmd);
BLI_remlink(particles, psys);
MEM_freeN(psys);
@@ -5114,7 +5239,7 @@ static void lib_link_modifiers_common(void *userData, Object *ob, ID **idpoin, i
static void lib_link_modifiers(FileData *fd, Object *ob)
{
- modifiers_foreachIDLink(ob, lib_link_modifiers_common, fd);
+ BKE_modifiers_foreach_ID_link(ob, lib_link_modifiers_common, fd);
/* If linking from a library, clear 'local' library override flag. */
if (ob->id.lib != NULL) {
@@ -5126,7 +5251,7 @@ static void lib_link_modifiers(FileData *fd, Object *ob)
static void lib_link_gpencil_modifiers(FileData *fd, Object *ob)
{
- BKE_gpencil_modifiers_foreachIDLink(ob, lib_link_modifiers_common, fd);
+ BKE_gpencil_modifiers_foreach_ID_link(ob, lib_link_modifiers_common, fd);
/* If linking from a library, clear 'local' library override flag. */
if (ob->id.lib != NULL) {
@@ -5139,7 +5264,7 @@ static void lib_link_gpencil_modifiers(FileData *fd, Object *ob)
static void lib_link_shaderfxs(FileData *fd, Object *ob)
{
- BKE_shaderfx_foreachIDLink(ob, lib_link_modifiers_common, fd);
+ BKE_shaderfx_foreach_ID_link(ob, lib_link_modifiers_common, fd);
/* If linking from a library, clear 'local' library override flag. */
if (ob->id.lib != NULL) {
@@ -5223,7 +5348,7 @@ static void lib_link_object(FileData *fd, Main *bmain, Object *ob)
* some leaked memory rather then crashing immediately
* while bad this _is_ an exceptional case - campbell */
#if 0
- BKE_pose_free(ob->pose);
+ BKE_pose_free(ob->pose);
#else
MEM_freeN(ob->pose);
#endif
@@ -5259,14 +5384,14 @@ static void lib_link_object(FileData *fd, Main *bmain, Object *ob)
lib_link_nlastrips(fd, &ob->id, &ob->nlastrips);
// >>> XXX deprecated - old animation system
- for (PartEff *paf = ob->effect.first; paf; paf = paf->next) {
+ LISTBASE_FOREACH (PartEff *, paf, &ob->effect) {
if (paf->type == EFF_PARTICLE) {
paf->group = newlibadr(fd, ob->id.lib, paf->group);
}
}
{
- FluidsimModifierData *fluidmd = (FluidsimModifierData *)modifiers_findByType(
+ FluidsimModifierData *fluidmd = (FluidsimModifierData *)BKE_modifiers_findby_type(
ob, eModifierType_Fluidsim);
if (fluidmd && fluidmd->fss) {
@@ -5276,12 +5401,19 @@ static void lib_link_object(FileData *fd, Main *bmain, Object *ob)
}
{
- FluidModifierData *mmd = (FluidModifierData *)modifiers_findByType(ob, eModifierType_Fluid);
+ FluidModifierData *mmd = (FluidModifierData *)BKE_modifiers_findby_type(ob,
+ eModifierType_Fluid);
if (mmd && (mmd->type == MOD_FLUID_TYPE_DOMAIN) && mmd->domain) {
/* Flag for refreshing the simulation after loading */
mmd->domain->flags |= FLUID_DOMAIN_FILE_LOAD;
}
+ else if (mmd && (mmd->type == MOD_FLUID_TYPE_FLOW) && mmd->flow) {
+ mmd->flow->flags &= ~FLUID_FLOW_NEEDS_UPDATE;
+ }
+ else if (mmd && (mmd->type == MOD_FLUID_TYPE_EFFEC) && mmd->effector) {
+ mmd->effector->flags &= ~FLUID_EFFECTOR_NEEDS_UPDATE;
+ }
}
/* texture field */
@@ -5412,7 +5544,7 @@ static ModifierData *modifier_replace_with_fluid(FileData *fd,
ListBase *modifiers,
ModifierData *old_modifier_data)
{
- ModifierData *new_modifier_data = modifier_new(eModifierType_Fluid);
+ ModifierData *new_modifier_data = BKE_modifier_new(eModifierType_Fluid);
FluidModifierData *fluid_modifier_data = (FluidModifierData *)new_modifier_data;
if (old_modifier_data->type == eModifierType_Fluidsim) {
@@ -5535,7 +5667,7 @@ static void direct_link_modifiers(FileData *fd, ListBase *lb, Object *ob)
is_allocated = true;
}
/* if modifiers disappear, or for upward compatibility */
- if (NULL == modifierType_getInfo(md->type)) {
+ if (NULL == BKE_modifier_get_info(md->type)) {
md->type = eModifierType_None;
}
@@ -5693,15 +5825,15 @@ static void direct_link_modifiers(FileData *fd, ListBase *lb, Object *ob)
else if (md->type == eModifierType_Collision) {
CollisionModifierData *collmd = (CollisionModifierData *)md;
#if 0
- // TODO: CollisionModifier should use pointcache
- // + have proper reset events before enabling this
- collmd->x = newdataadr(fd, collmd->x);
- collmd->xnew = newdataadr(fd, collmd->xnew);
- collmd->mfaces = newdataadr(fd, collmd->mfaces);
-
- collmd->current_x = MEM_calloc_arrayN(collmd->numverts, sizeof(MVert), "current_x");
- collmd->current_xnew = MEM_calloc_arrayN(collmd->numverts, sizeof(MVert), "current_xnew");
- collmd->current_v = MEM_calloc_arrayN(collmd->numverts, sizeof(MVert), "current_v");
+ // TODO: CollisionModifier should use pointcache
+ // + have proper reset events before enabling this
+ collmd->x = newdataadr(fd, collmd->x);
+ collmd->xnew = newdataadr(fd, collmd->xnew);
+ collmd->mfaces = newdataadr(fd, collmd->mfaces);
+
+ collmd->current_x = MEM_calloc_arrayN(collmd->numverts, sizeof(MVert), "current_x");
+ collmd->current_xnew = MEM_calloc_arrayN(collmd->numverts, sizeof(MVert), "current_xnew");
+ collmd->current_v = MEM_calloc_arrayN(collmd->numverts, sizeof(MVert), "current_v");
#endif
collmd->x = NULL;
@@ -5889,7 +6021,7 @@ static void direct_link_gpencil_modifiers(FileData *fd, ListBase *lb)
md->error = NULL;
/* if modifiers disappear, or for upward compatibility */
- if (NULL == BKE_gpencil_modifierType_getInfo(md->type)) {
+ if (NULL == BKE_gpencil_modifier_get_info(md->type)) {
md->type = eModifierType_None;
}
@@ -5970,7 +6102,7 @@ static void direct_link_shaderfxs(FileData *fd, ListBase *lb)
fx->error = NULL;
/* if shader disappear, or for upward compatibility */
- if (NULL == BKE_shaderfxType_getInfo(fx->type)) {
+ if (NULL == BKE_shaderfx_get_info(fx->type)) {
fx->type = eShaderFxType_None;
}
}
@@ -6033,7 +6165,7 @@ static void direct_link_object(FileData *fd, Object *ob)
if (paf->type == EFF_WAVE) {
WaveEff *wav = (WaveEff *)paf;
PartEff *next = paf->next;
- WaveModifierData *wmd = (WaveModifierData *)modifier_new(eModifierType_Wave);
+ WaveModifierData *wmd = (WaveModifierData *)BKE_modifier_new(eModifierType_Wave);
wmd->damp = wav->damp;
wmd->flag = wav->flag;
@@ -6057,7 +6189,7 @@ static void direct_link_object(FileData *fd, Object *ob)
if (paf->type == EFF_BUILD) {
BuildEff *baf = (BuildEff *)paf;
PartEff *next = paf->next;
- BuildModifierData *bmd = (BuildModifierData *)modifier_new(eModifierType_Build);
+ BuildModifierData *bmd = (BuildModifierData *)BKE_modifier_new(eModifierType_Build);
bmd->start = baf->sfra;
bmd->length = baf->len;
@@ -6134,7 +6266,7 @@ static void direct_link_object(FileData *fd, Object *ob)
link_list(fd, &ob->hooks);
while (ob->hooks.first) {
ObHook *hook = ob->hooks.first;
- HookModifierData *hmd = (HookModifierData *)modifier_new(eModifierType_Hook);
+ HookModifierData *hmd = (HookModifierData *)BKE_modifier_new(eModifierType_Hook);
hook->indexar = newdataadr(fd, hook->indexar);
if (fd->flags & FD_FLAGS_SWITCH_ENDIAN) {
@@ -6156,7 +6288,7 @@ static void direct_link_object(FileData *fd, Object *ob)
BLI_addhead(&ob->modifiers, hmd);
BLI_remlink(&ob->hooks, hook);
- modifier_unique_name(&ob->modifiers, (ModifierData *)hmd);
+ BKE_modifier_unique_name(&ob->modifiers, (ModifierData *)hmd);
MEM_freeN(hook);
}
@@ -6204,7 +6336,7 @@ static void direct_link_view_settings(FileData *fd, ColorManagedViewSettings *vi
static void direct_link_layer_collections(FileData *fd, ListBase *lb, bool master)
{
link_list(fd, lb);
- for (LayerCollection *lc = lb->first; lc; lc = lc->next) {
+ LISTBASE_FOREACH (LayerCollection *, lc, lb) {
#ifdef USE_COLLECTION_COMPAT_28
lc->scene_collection = newdataadr(fd, lc->scene_collection);
#endif
@@ -6257,12 +6389,11 @@ static void lib_link_layer_collection(FileData *fd,
static void lib_link_view_layer(FileData *fd, Library *lib, ViewLayer *view_layer)
{
- for (FreestyleModuleConfig *fmc = view_layer->freestyle_config.modules.first; fmc;
- fmc = fmc->next) {
+ LISTBASE_FOREACH (FreestyleModuleConfig *, fmc, &view_layer->freestyle_config.modules) {
fmc->script = newlibadr(fd, lib, fmc->script);
}
- for (FreestyleLineSet *fls = view_layer->freestyle_config.linesets.first; fls; fls = fls->next) {
+ LISTBASE_FOREACH (FreestyleLineSet *, fls, &view_layer->freestyle_config.linesets) {
fls->linestyle = newlibadr(fd, lib, fls->linestyle);
fls->group = newlibadr(fd, lib, fls->group);
}
@@ -6305,19 +6436,19 @@ static void direct_link_scene_collection(FileData *fd, SceneCollection *sc)
link_list(fd, &sc->objects);
link_list(fd, &sc->scene_collections);
- for (SceneCollection *nsc = sc->scene_collections.first; nsc; nsc = nsc->next) {
+ LISTBASE_FOREACH (SceneCollection *, nsc, &sc->scene_collections) {
direct_link_scene_collection(fd, nsc);
}
}
static void lib_link_scene_collection(FileData *fd, Library *lib, SceneCollection *sc)
{
- for (LinkData *link = sc->objects.first; link; link = link->next) {
+ LISTBASE_FOREACH (LinkData *, link, &sc->objects) {
link->data = newlibadr(fd, lib, link->data);
BLI_assert(link->data);
}
- for (SceneCollection *nsc = sc->scene_collections.first; nsc; nsc = nsc->next) {
+ LISTBASE_FOREACH (SceneCollection *, nsc, &sc->scene_collections) {
lib_link_scene_collection(fd, lib, nsc);
}
}
@@ -6625,7 +6756,7 @@ static void lib_link_scene(FileData *fd, Main *UNUSED(bmain), Scene *sce)
}
SEQ_END;
- for (TimeMarker *marker = sce->markers.first; marker; marker = marker->next) {
+ LISTBASE_FOREACH (TimeMarker *, marker, &sce->markers) {
if (marker->camera) {
marker->camera = newlibadr(fd, sce->id.lib, marker->camera);
}
@@ -6649,12 +6780,12 @@ static void lib_link_scene(FileData *fd, Main *UNUSED(bmain), Scene *sce)
composite_patch(sce->nodetree, sce);
}
- for (SceneRenderLayer *srl = sce->r.layers.first; srl; srl = srl->next) {
+ LISTBASE_FOREACH (SceneRenderLayer *, srl, &sce->r.layers) {
srl->mat_override = newlibadr(fd, sce->id.lib, srl->mat_override);
- for (FreestyleModuleConfig *fmc = srl->freestyleConfig.modules.first; fmc; fmc = fmc->next) {
+ LISTBASE_FOREACH (FreestyleModuleConfig *, fmc, &srl->freestyleConfig.modules) {
fmc->script = newlibadr(fd, sce->id.lib, fmc->script);
}
- for (FreestyleLineSet *fls = srl->freestyleConfig.linesets.first; fls; fls = fls->next) {
+ LISTBASE_FOREACH (FreestyleLineSet *, fls, &srl->freestyleConfig.linesets) {
fls->linestyle = newlibadr(fd, sce->id.lib, fls->linestyle);
fls->group = newlibadr(fd, sce->id.lib, fls->group);
}
@@ -6668,7 +6799,7 @@ static void lib_link_scene(FileData *fd, Main *UNUSED(bmain), Scene *sce)
}
#endif
- for (ViewLayer *view_layer = sce->view_layers.first; view_layer; view_layer = view_layer->next) {
+ LISTBASE_FOREACH (ViewLayer *, view_layer, &sce->view_layers) {
lib_link_view_layer(fd, sce->id.lib, view_layer);
}
@@ -6825,7 +6956,6 @@ static void direct_link_scene(FileData *fd, Scene *sce)
direct_link_paint(fd, sce, &sce->toolsettings->imapaint.paint);
- sce->toolsettings->imapaint.paintcursor = NULL;
sce->toolsettings->particle.paintcursor = NULL;
sce->toolsettings->particle.scene = NULL;
sce->toolsettings->particle.object = NULL;
@@ -7199,11 +7329,11 @@ static void direct_link_panel_list(FileData *fd, ListBase *lb)
{
link_list(fd, lb);
- for (Panel *pa = lb->first; pa; pa = pa->next) {
- pa->runtime_flag = 0;
- pa->activedata = NULL;
- pa->type = NULL;
- direct_link_panel_list(fd, &pa->children);
+ LISTBASE_FOREACH (Panel *, panel, lb) {
+ panel->runtime_flag = 0;
+ panel->activedata = NULL;
+ panel->type = NULL;
+ direct_link_panel_list(fd, &panel->children);
}
}
@@ -7408,10 +7538,10 @@ static void direct_link_area(FileData *fd, ScrArea *area)
* so sacrifice a few old files for now to avoid crashes with new files!
* committed: r28002 */
#if 0
- sima->gpd = newdataadr(fd, sima->gpd);
- if (sima->gpd) {
- direct_link_gpencil(fd, sima->gpd);
- }
+ sima->gpd = newdataadr(fd, sima->gpd);
+ if (sima->gpd) {
+ direct_link_gpencil(fd, sima->gpd);
+ }
#endif
}
else if (sl->spacetype == SPACE_NODE) {
@@ -7442,10 +7572,10 @@ static void direct_link_area(FileData *fd, ScrArea *area)
* simple return NULL here (sergey)
*/
#if 0
- if (sseq->gpd) {
- sseq->gpd = newdataadr(fd, sseq->gpd);
- direct_link_gpencil(fd, sseq->gpd);
- }
+ if (sseq->gpd) {
+ sseq->gpd = newdataadr(fd, sseq->gpd);
+ direct_link_gpencil(fd, sseq->gpd);
+ }
#endif
sseq->scopes.reference_ibuf = NULL;
sseq->scopes.zebra_ibuf = NULL;
@@ -7524,7 +7654,7 @@ static void lib_link_area(FileData *fd, ID *parent_id, ScrArea *area)
memset(&area->runtime, 0x0, sizeof(area->runtime));
- for (SpaceLink *sl = area->spacedata.first; sl; sl = sl->next) {
+ LISTBASE_FOREACH (SpaceLink *, sl, &area->spacedata) {
switch (sl->spacetype) {
case SPACE_VIEW3D: {
View3D *v3d = (View3D *)sl;
@@ -7701,12 +7831,12 @@ static bool direct_link_area_map(FileData *fd, ScrAreaMap *area_map)
link_list(fd, &area_map->vertbase);
link_list(fd, &area_map->edgebase);
link_list(fd, &area_map->areabase);
- for (ScrArea *area = area_map->areabase.first; area; area = area->next) {
+ LISTBASE_FOREACH (ScrArea *, area, &area_map->areabase) {
direct_link_area(fd, area);
}
/* edges */
- for (ScrEdge *se = area_map->edgebase.first; se; se = se->next) {
+ LISTBASE_FOREACH (ScrEdge *, se, &area_map->edgebase) {
se->v1 = newdataadr(fd, se->v1);
se->v2 = newdataadr(fd, se->v2);
BKE_screen_sort_scrvert(&se->v1, &se->v2);
@@ -7823,7 +7953,7 @@ static void direct_link_windowmanager(FileData *fd, wmWindowManager *wm)
static void lib_link_windowmanager(FileData *fd, Main *UNUSED(bmain), wmWindowManager *wm)
{
- for (wmWindow *win = wm->windows.first; win; win = win->next) {
+ LISTBASE_FOREACH (wmWindow *, win, &wm->windows) {
if (win->workspace_hook) { /* NULL for old files */
lib_link_workspace_instance_hook(fd, win->workspace_hook, &wm->id);
}
@@ -7831,7 +7961,7 @@ static void lib_link_windowmanager(FileData *fd, Main *UNUSED(bmain), wmWindowMa
/* deprecated, but needed for versioning (will be NULL'ed then) */
win->screen = newlibadr(fd, NULL, win->screen);
- for (ScrArea *area = win->global_areas.areabase.first; area; area = area->next) {
+ LISTBASE_FOREACH (ScrArea *, area, &win->global_areas.areabase) {
lib_link_area(fd, &wm->id, area);
}
@@ -7847,17 +7977,17 @@ static void lib_link_windowmanager(FileData *fd, Main *UNUSED(bmain), wmWindowMa
/* note: file read without screens option G_FILE_NO_UI;
* check lib pointers in call below */
-static void lib_link_screen(FileData *fd, Main *UNUSED(bmain), bScreen *sc)
+static void lib_link_screen(FileData *fd, Main *UNUSED(bmain), bScreen *screen)
{
/* deprecated, but needed for versioning (will be NULL'ed then) */
- sc->scene = newlibadr(fd, sc->id.lib, sc->scene);
+ screen->scene = newlibadr(fd, screen->id.lib, screen->scene);
- sc->animtimer = NULL; /* saved in rare cases */
- sc->tool_tip = NULL;
- sc->scrubbing = false;
+ screen->animtimer = NULL; /* saved in rare cases */
+ screen->tool_tip = NULL;
+ screen->scrubbing = false;
- for (ScrArea *area = sc->areabase.first; area; area = area->next) {
- lib_link_area(fd, &sc->id, area);
+ LISTBASE_FOREACH (ScrArea *, area, &screen->areabase) {
+ lib_link_area(fd, &screen->id, area);
}
}
@@ -8010,8 +8140,8 @@ static void lib_link_window_scene_data_restore(wmWindow *win, Scene *scene, View
{
bScreen *screen = BKE_workspace_active_screen_get(win->workspace_hook);
- for (ScrArea *area = screen->areabase.first; area; area = area->next) {
- for (SpaceLink *sl = area->spacedata.first; sl; sl = sl->next) {
+ LISTBASE_FOREACH (ScrArea *, area, &screen->areabase) {
+ LISTBASE_FOREACH (SpaceLink *, sl, &area->spacedata) {
if (sl->spacetype == SPACE_VIEW3D) {
View3D *v3d = (View3D *)sl;
@@ -8039,7 +8169,7 @@ static void lib_link_window_scene_data_restore(wmWindow *win, Scene *scene, View
/* Regionbase storage is different depending if the space is active. */
ListBase *regionbase = (sl == area->spacedata.first) ? &area->regionbase :
&sl->regionbase;
- for (ARegion *region = regionbase->first; region; region = region->next) {
+ LISTBASE_FOREACH (ARegion *, region, regionbase) {
if (region->regiontype == RGN_TYPE_WINDOW) {
RegionView3D *rv3d = region->regiondata;
if (rv3d->localvd) {
@@ -8063,26 +8193,13 @@ static void lib_link_workspace_layout_restore(struct IDNameLib_Map *id_map,
/* avoid conflicts with 2.8x branch */
{
- for (ScrArea *sa = screen->areabase.first; sa; sa = sa->next) {
- for (SpaceLink *sl = sa->spacedata.first; sl; sl = sl->next) {
+ LISTBASE_FOREACH (ScrArea *, area, &screen->areabase) {
+ LISTBASE_FOREACH (SpaceLink *, sl, &area->spacedata) {
if (sl->spacetype == SPACE_VIEW3D) {
View3D *v3d = (View3D *)sl;
- ARegion *region;
v3d->camera = restore_pointer_by_name(id_map, (ID *)v3d->camera, USER_REAL);
v3d->ob_center = restore_pointer_by_name(id_map, (ID *)v3d->ob_center, USER_REAL);
-
- /* Free render engines for now. */
- ListBase *regionbase = (sl == sa->spacedata.first) ? &sa->regionbase : &sl->regionbase;
- for (region = regionbase->first; region; region = region->next) {
- if (region->regiontype == RGN_TYPE_WINDOW) {
- RegionView3D *rv3d = region->regiondata;
- if (rv3d && rv3d->render_engine) {
- RE_engine_free(rv3d->render_engine);
- rv3d->render_engine = NULL;
- }
- }
- }
}
else if (sl->spacetype == SPACE_GRAPH) {
SpaceGraph *sipo = (SpaceGraph *)sl;
@@ -8145,11 +8262,11 @@ static void lib_link_workspace_layout_restore(struct IDNameLib_Map *id_map,
sima->iuser.scene = NULL;
#if 0
- /* Those are allocated and freed by space code, no need to handle them here. */
- MEM_SAFE_FREE(sima->scopes.waveform_1);
- MEM_SAFE_FREE(sima->scopes.waveform_2);
- MEM_SAFE_FREE(sima->scopes.waveform_3);
- MEM_SAFE_FREE(sima->scopes.vecscope);
+ /* Those are allocated and freed by space code, no need to handle them here. */
+ MEM_SAFE_FREE(sima->scopes.waveform_1);
+ MEM_SAFE_FREE(sima->scopes.waveform_2);
+ MEM_SAFE_FREE(sima->scopes.waveform_3);
+ MEM_SAFE_FREE(sima->scopes.vecscope);
#endif
sima->scopes.ok = 0;
@@ -8194,7 +8311,7 @@ static void lib_link_workspace_layout_restore(struct IDNameLib_Map *id_map,
scpt->script = restore_pointer_by_name(id_map, (ID *)scpt->script, USER_REAL);
- /*sc->script = NULL; - 2.45 set to null, better re-run the script */
+ /*screen->script = NULL; - 2.45 set to null, better re-run the script */
if (scpt->script) {
SCRIPT_SET_NULL(scpt->script);
}
@@ -8300,14 +8417,12 @@ void blo_lib_link_restore(Main *oldmain,
for (WorkSpace *workspace = newmain->workspaces.first; workspace;
workspace = workspace->id.next) {
- ListBase *layouts = BKE_workspace_layouts_get(workspace);
-
- for (WorkSpaceLayout *layout = layouts->first; layout; layout = layout->next) {
+ LISTBASE_FOREACH (WorkSpaceLayout *, layout, &workspace->layouts) {
lib_link_workspace_layout_restore(id_map, newmain, layout);
}
}
- for (wmWindow *win = curwm->windows.first; win; win = win->next) {
+ LISTBASE_FOREACH (wmWindow *, win, &curwm->windows) {
WorkSpace *workspace = BKE_workspace_active_get(win->workspace_hook);
ID *workspace_id = (ID *)workspace;
Scene *oldscene = win->scene;
@@ -8377,22 +8492,22 @@ void blo_do_versions_view3d_split_250(View3D *v3d, ListBase *regions)
}
}
-static bool direct_link_screen(FileData *fd, bScreen *sc)
+static bool direct_link_screen(FileData *fd, bScreen *screen)
{
- bool wrong_id = false;
+ bool success = true;
- sc->regionbase.first = sc->regionbase.last = NULL;
- sc->context = NULL;
- sc->active_region = NULL;
+ screen->regionbase.first = screen->regionbase.last = NULL;
+ screen->context = NULL;
+ screen->active_region = NULL;
- sc->preview = direct_link_preview_image(fd, sc->preview);
+ screen->preview = direct_link_preview_image(fd, screen->preview);
- if (!direct_link_area_map(fd, AREAMAP_FROM_SCREEN(sc))) {
- printf("Error reading Screen %s... removing it.\n", sc->id.name + 2);
- wrong_id = true;
+ if (!direct_link_area_map(fd, AREAMAP_FROM_SCREEN(screen))) {
+ printf("Error reading Screen %s... removing it.\n", screen->id.name + 2);
+ success = false;
}
- return wrong_id;
+ return success;
}
/** \} */
@@ -8437,7 +8552,7 @@ static void direct_link_library(FileData *fd, Library *lib, Main *main)
/* make sure we have full path in lib->filepath */
BLI_strncpy(lib->filepath, lib->name, sizeof(lib->name));
- BLI_cleanup_path(fd->relabase, lib->filepath);
+ BLI_path_normalize(fd->relabase, lib->filepath);
// printf("direct_link_library: name %s\n", lib->name);
// printf("direct_link_library: filepath %s\n", lib->filepath);
@@ -8450,11 +8565,12 @@ static void direct_link_library(FileData *fd, Library *lib, Main *main)
newmain->curlib = lib;
lib->parent = NULL;
+
+ id_us_ensure_real(&lib->id);
}
-static void lib_link_library(FileData *UNUSED(fd), Main *UNUSED(bmain), Library *lib)
+static void lib_link_library(FileData *UNUSED(fd), Main *UNUSED(bmain), Library *UNUSED(lib))
{
- id_us_ensure_real(&lib->id);
}
/* Always call this once you have loaded new library data to set the relative paths correctly
@@ -8522,8 +8638,8 @@ static void direct_link_speaker(FileData *fd, Speaker *spk)
direct_link_animdata(fd, spk->adt);
#if 0
- spk->sound = newdataadr(fd, spk->sound);
- direct_link_sound(fd, spk->sound);
+ spk->sound = newdataadr(fd, spk->sound);
+ direct_link_sound(fd, spk->sound);
#endif
}
@@ -8685,7 +8801,7 @@ static void lib_link_movieclip(FileData *fd, Main *UNUSED(bmain), MovieClip *cli
lib_link_movieTracks(fd, clip, &tracking->tracks);
lib_link_moviePlaneTracks(fd, clip, &tracking->plane_tracks);
- for (MovieTrackingObject *object = tracking->objects.first; object; object = object->next) {
+ LISTBASE_FOREACH (MovieTrackingObject *, object, &tracking->objects) {
lib_link_movieTracks(fd, clip, &object->tracks);
lib_link_moviePlaneTracks(fd, clip, &object->plane_tracks);
}
@@ -8762,7 +8878,7 @@ static void lib_link_mask_parent(FileData *fd, Mask *mask, MaskParent *parent)
static void lib_link_mask(FileData *fd, Main *UNUSED(bmain), Mask *mask)
{
- for (MaskLayer *masklay = mask->masklayers.first; masklay; masklay = masklay->next) {
+ LISTBASE_FOREACH (MaskLayer *, masklay, &mask->masklayers) {
MaskSpline *spline;
spline = masklay->splines.first;
@@ -9107,6 +9223,24 @@ static void direct_link_volume(FileData *fd, Volume *volume)
/** \} */
/* -------------------------------------------------------------------- */
+/** \name Read ID: Simulation
+ * \{ */
+
+static void lib_link_simulation(FileData *UNUSED(fd),
+ Main *UNUSED(main),
+ Simulation *UNUSED(simulation))
+{
+}
+
+static void direct_link_simulation(FileData *fd, Simulation *simulation)
+{
+ simulation->adt = newdataadr(fd, simulation->adt);
+ direct_link_animdata(fd, simulation->adt);
+}
+
+/** \} */
+
+/* -------------------------------------------------------------------- */
/** \name Read Library Data Block
* \{ */
@@ -9224,328 +9358,33 @@ static const char *dataname(short id_code)
return "Data from PT";
case ID_VO:
return "Data from VO";
+ case ID_SIM:
+ return "Data from SIM";
}
return "Data from Lib Block";
}
-static BHead *read_data_into_oldnewmap(FileData *fd, BHead *bhead, const char *allocname)
+static bool direct_link_id(FileData *fd, Main *main, const int tag, ID *id, ID *id_old)
{
- bhead = blo_bhead_next(fd, bhead);
-
- while (bhead && bhead->code == DATA) {
- void *data;
-#if 0
- /* XXX DUMB DEBUGGING OPTION TO GIVE NAMES for guarded malloc errors */
- short* sp = fd->filesdna->structs[bhead->SDNAnr];
- char* tmp = malloc(100);
- allocname = fd->filesdna->types[sp[0]];
- strcpy(tmp, allocname);
- data = read_struct(fd, bhead, tmp);
-#else
- data = read_struct(fd, bhead, allocname);
-#endif
-
- if (data) {
- oldnewmap_insert(fd->datamap, bhead->old, data, 0);
- }
+ /* Read part of datablock that is common between real and embedded datablocks. */
+ direct_link_id_common(fd, main->curlib, id, id_old, tag);
- bhead = blo_bhead_next(fd, bhead);
+ if (tag & LIB_TAG_ID_LINK_PLACEHOLDER) {
+ /* For placeholder we only need to set the tag, no further data to read. */
+ id->tag = tag;
+ return true;
}
- return bhead;
-}
-
-static BHead *read_libblock(FileData *fd,
- Main *main,
- BHead *bhead,
- const int tag,
- const bool placeholder_set_indirect_extern,
- ID **r_id)
-{
- /* this routine reads a libblock and its direct data. Use link functions to connect it all
- */
- ID *id;
- ListBase *lb;
- const char *allocname;
-
- /* XXX Very weakly handled currently, see comment at the end of this function before trying to
+ /* XXX Very weakly handled currently, see comment in read_libblock() before trying to
* use it for anything new. */
- bool wrong_id = false;
-
- /* In undo case, most libs and linked data should be kept as is from previous state
- * (see BLO_read_from_memfile).
- * However, some needed by the snapshot being read may have been removed in previous one,
- * and would go missing.
- * This leads e.g. to disappearing objects in some undo/redo case, see T34446.
- * That means we have to carefully check whether current lib or
- * libdata already exits in old main, if it does we merely copy it over into new main area,
- * otherwise we have to do a full read of that bhead... */
- if (fd->memfile && ELEM(bhead->code, ID_LI, ID_LINK_PLACEHOLDER)) {
- const char *idname = blo_bhead_id_name(fd, bhead);
-
- DEBUG_PRINTF("Checking %s...\n", idname);
-
- if (bhead->code == ID_LI) {
- Main *libmain = fd->old_mainlist->first;
- /* Skip oldmain itself... */
- for (libmain = libmain->next; libmain; libmain = libmain->next) {
- DEBUG_PRINTF("... against %s: ", libmain->curlib ? libmain->curlib->id.name : "<NULL>");
- if (libmain->curlib && STREQ(idname, libmain->curlib->id.name)) {
- Main *oldmain = fd->old_mainlist->first;
- DEBUG_PRINTF("FOUND!\n");
- /* In case of a library, we need to re-add its main to fd->mainlist,
- * because if we have later a missing ID_LINK_PLACEHOLDER,
- * we need to get the correct lib it is linked to!
- * Order is crucial, we cannot bulk-add it in BLO_read_from_memfile()
- * like it used to be. */
- BLI_remlink(fd->old_mainlist, libmain);
- BLI_remlink_safe(&oldmain->libraries, libmain->curlib);
- BLI_addtail(fd->mainlist, libmain);
- BLI_addtail(&main->libraries, libmain->curlib);
-
- if (r_id) {
- *r_id = NULL; /* Just in case... */
- }
- return blo_bhead_next(fd, bhead);
- }
- DEBUG_PRINTF("nothing...\n");
- }
- }
- else {
- DEBUG_PRINTF("... in %s (%s): ",
- main->curlib ? main->curlib->id.name : "<NULL>",
- main->curlib ? main->curlib->name : "<NULL>");
- if ((id = BKE_libblock_find_name(main, GS(idname), idname + 2))) {
- DEBUG_PRINTF("FOUND!\n");
- /* Even though we found our linked ID,
- * there is no guarantee its address is still the same. */
- if (id != bhead->old) {
- oldnewmap_insert(fd->libmap, bhead->old, id, GS(id->name));
- }
-
- /* No need to do anything else for ID_LINK_PLACEHOLDER,
- * it's assumed already present in its lib's main. */
- if (r_id) {
- *r_id = NULL; /* Just in case... */
- }
- return blo_bhead_next(fd, bhead);
- }
- DEBUG_PRINTF("nothing...\n");
- }
- }
-
- /* read libblock */
- fd->are_memchunks_identical = true;
- id = read_struct(fd, bhead, "lib block");
- const short idcode = id != NULL ? GS(id->name) : 0;
-
- BHead *id_bhead = bhead;
- /* Used when undoing from memfile, we swap changed IDs into their old addresses when found. */
- ID *id_old = NULL;
- bool do_id_swap = false;
-
- if (id != NULL) {
- const bool do_partial_undo = (fd->skip_flags & BLO_READ_SKIP_UNDO_OLD_MAIN) == 0;
-
- if (id_bhead->code != ID_LINK_PLACEHOLDER) {
- /* need a name for the mallocN, just for debugging and sane prints on leaks */
- allocname = dataname(idcode);
-
- /* read all data into fd->datamap */
- /* TODO: instead of building oldnewmap here we could just quickly check the bheads... could
- * save some more ticks. Probably not worth it though, bottleneck is full depsgraph rebuild
- * and evaluate, not actual file reading. */
- bhead = read_data_into_oldnewmap(fd, id_bhead, allocname);
-
- DEBUG_PRINTF(
- "%s: ID %s is unchanged: %d\n", __func__, id->name, fd->are_memchunks_identical);
-
- if (fd->memfile != NULL) {
- BLI_assert(fd->old_idmap != NULL || !do_partial_undo);
- /* This code should only ever be reached for local data-blocks. */
- BLI_assert(main->curlib == NULL);
-
- /* Find the 'current' existing ID we want to reuse instead of the one we would read from
- * the undo memfile. */
- DEBUG_PRINTF("\t Looking for ID %s with uuid %u instead of newly read one\n",
- id->name,
- id->session_uuid);
- id_old = do_partial_undo ? BKE_main_idmap_lookup_uuid(fd->old_idmap, id->session_uuid) :
- NULL;
- bool can_finalize_and_return = false;
-
- if (ELEM(idcode, ID_WM, ID_SCR, ID_WS)) {
- /* Read WindowManager, Screen and WorkSpace IDs are never actually used during undo (see
- * `setup_app_data()` in `blendfile.c`).
- * So we can just abort here, just ensuring libmapping is set accordingly. */
- can_finalize_and_return = true;
- }
- else if (id_old != NULL && fd->are_memchunks_identical) {
- /* Do not add LIB_TAG_NEW here, this should not be needed/used in undo case anyway (as
- * this is only for do_version-like code), but for sake of consistency, and also because
- * it will tell us which ID is re-used from old Main, and which one is actually new. */
- id_old->tag = tag | LIB_TAG_NEED_LINK | LIB_TAG_UNDO_OLD_ID_REUSED;
- id_old->lib = main->curlib;
- id_old->us = ID_FAKE_USERS(id_old);
- /* Do not reset id->icon_id here, memory allocated for it remains valid. */
- /* Needed because .blend may have been saved with crap value here... */
- id_old->newid = NULL;
- id_old->orig_id = NULL;
-
- /* About recalc: since that ID did not change at all, we know that its recalc fields also
- * remained unchanged, so no need to handle neither recalc nor recalc_undo_future here.
- */
-
- Main *old_bmain = fd->old_mainlist->first;
- ListBase *old_lb = which_libbase(old_bmain, idcode);
- ListBase *new_lb = which_libbase(main, idcode);
- BLI_remlink(old_lb, id_old);
- BLI_addtail(new_lb, id_old);
-
- can_finalize_and_return = true;
- }
-
- if (can_finalize_and_return) {
- DEBUG_PRINTF("Re-using existing ID %s instead of newly read one\n", id_old->name);
- oldnewmap_insert(fd->libmap, id_bhead->old, id_old, id_bhead->code);
- oldnewmap_insert(fd->libmap, id_old, id_old, id_bhead->code);
-
- if (r_id) {
- *r_id = id_old;
- }
-
- if (do_partial_undo) {
- /* Even though we re-use the old ID as-is, it does not mean that we are 100% safe from
- * needing some depsgraph updates for it (it could depend on another ID which address
- * did
- * not change, but which actual content might have been re-read from the memfile). */
- if (fd->undo_direction < 0) {
- /* We are coming from the future (i.e. do an actual undo, and not a redo), we use our
- * old reused ID's 'accumulated recalc flags since last memfile undo step saving' as
- * recalc flags. */
- id_old->recalc = id_old->recalc_undo_accumulated;
- }
- else {
- /* We are coming from the past (i.e. do a redo), we use the saved 'accumulated recalc
- * flags since last memfile undo step saving' from the newly read ID as recalc flags.
- */
- id_old->recalc = id->recalc_undo_accumulated;
- }
- /* There is no need to flush the depsgraph's CoWs here, since that ID's data itself did
- * not change. */
-
- /* We need to 'accumulate' the accumulated recalc flags of all undo steps until we
- * actually perform a depsgraph update, otherwise we'd only ever use the flags from one
- * of the steps, and never get proper flags matching all others. */
- id_old->recalc_undo_accumulated |= id->recalc_undo_accumulated;
- }
-
- MEM_freeN(id);
- oldnewmap_free_unused(fd->datamap);
- oldnewmap_clear(fd->datamap);
-
- return bhead;
- }
- }
- }
-
- /* do after read_struct, for dna reconstruct */
- lb = which_libbase(main, idcode);
- if (lb) {
- /* Some re-used old IDs might also use newly read ones, so we have to check for old memory
- * addresses for those as well. */
- if (fd->memfile != NULL && do_partial_undo && id->lib == NULL) {
- BLI_assert(fd->old_idmap != NULL);
- DEBUG_PRINTF("\t Looking for ID %s with uuid %u instead of newly read one\n",
- id->name,
- id->session_uuid);
- id_old = BKE_main_idmap_lookup_uuid(fd->old_idmap, id->session_uuid);
- if (id_old != NULL) {
- BLI_assert(MEM_allocN_len(id) == MEM_allocN_len(id_old));
- /* UI IDs are always re-used from old bmain at higher-level calling code, so never swap
- * those. Besides maybe custom properties, no other ID should have pointers to those
- * anyway...
- * And linked IDs are handled separately as well. */
- do_id_swap = !ELEM(idcode, ID_WM, ID_SCR, ID_WS) &&
- !(id_bhead->code == ID_LINK_PLACEHOLDER);
- }
- }
-
- /* At this point, we know we are going to keep that newly read & allocated ID, so we need to
- * reallocate it to ensure we actually get a unique memory address for it. */
- if (!do_id_swap) {
- DEBUG_PRINTF("using newly-read ID %s to a new mem address\n", id->name);
- }
- else {
- DEBUG_PRINTF("using newly-read ID %s to its old, already existing address\n", id->name);
- }
-
- /* for ID_LINK_PLACEHOLDER check */
- ID *id_target = do_id_swap ? id_old : id;
- oldnewmap_insert(fd->libmap, id_bhead->old, id_target, id_bhead->code);
- oldnewmap_insert(fd->libmap, id_old, id_target, id_bhead->code);
-
- BLI_addtail(lb, id);
-
- if (fd->memfile == NULL) {
- /* When actually reading a file , we do want to reset/re-generate session uuids.
- * In unod case, we want to re-use existing ones. */
- id->session_uuid = MAIN_ID_SESSION_UUID_UNSET;
- }
-
- BKE_lib_libblock_session_uuid_ensure(id);
- }
- else {
- /* unknown ID type */
- printf("%s: unknown id code '%c%c'\n", __func__, (idcode & 0xff), (idcode >> 8));
- MEM_freeN(id);
- id = NULL;
- }
- }
-
- if (r_id) {
- *r_id = do_id_swap ? id_old : id;
- }
- if (!id) {
- return blo_bhead_next(fd, id_bhead);
- }
-
- id->lib = main->curlib;
- id->us = ID_FAKE_USERS(id);
- id->icon_id = 0;
- id->newid = NULL; /* Needed because .blend may have been saved with crap value here... */
- id->orig_id = NULL;
-
- /* this case cannot be direct_linked: it's just the ID part */
- if (id_bhead->code == ID_LINK_PLACEHOLDER) {
- /* That way, we know which data-lock needs do_versions (required currently for linking). */
- id->tag = tag | LIB_TAG_ID_LINK_PLACEHOLDER | LIB_TAG_NEED_LINK | LIB_TAG_NEW;
-
- if (placeholder_set_indirect_extern) {
- if (id->flag & LIB_INDIRECT_WEAK_LINK) {
- id->tag |= LIB_TAG_INDIRECT;
- }
- else {
- id->tag |= LIB_TAG_EXTERN;
- }
- }
-
- return blo_bhead_next(fd, id_bhead);
- }
-
- /* init pointers direct data */
- direct_link_id(fd, id, id_old);
-
- /* That way, we know which data-lock needs do_versions (required currently for linking). */
- /* Note: doing this after direct_link_id(), which resets that field. */
- id->tag = tag | LIB_TAG_NEED_LINK | LIB_TAG_NEW;
+ bool success = true;
- switch (idcode) {
+ switch (GS(id->name)) {
case ID_WM:
direct_link_windowmanager(fd, (wmWindowManager *)id);
break;
case ID_SCR:
- wrong_id = direct_link_screen(fd, (bScreen *)id);
+ success = direct_link_screen(fd, (bScreen *)id);
break;
case ID_SCE:
direct_link_scene(fd, (Scene *)id);
@@ -9658,12 +9497,372 @@ static BHead *read_libblock(FileData *fd,
case ID_VO:
direct_link_volume(fd, (Volume *)id);
break;
+ case ID_SIM:
+ direct_link_simulation(fd, (Simulation *)id);
+ break;
}
- oldnewmap_free_unused(fd->datamap);
+ return success;
+}
+
+/* Read all data associated with a datablock into datamap. */
+static BHead *read_data_into_datamap(FileData *fd, BHead *bhead, const char *allocname)
+{
+ bhead = blo_bhead_next(fd, bhead);
+
+ while (bhead && bhead->code == DATA) {
+ void *data;
+#if 0
+ /* XXX DUMB DEBUGGING OPTION TO GIVE NAMES for guarded malloc errors */
+ short* sp = fd->filesdna->structs[bhead->SDNAnr];
+ char* tmp = malloc(100);
+ allocname = fd->filesdna->types[sp[0]];
+ strcpy(tmp, allocname);
+ data = read_struct(fd, bhead, tmp);
+#else
+ data = read_struct(fd, bhead, allocname);
+#endif
+
+ if (data) {
+ oldnewmap_insert(fd->datamap, bhead->old, data, 0);
+ }
+
+ bhead = blo_bhead_next(fd, bhead);
+ }
+
+ return bhead;
+}
+
+/* Verify if the datablock and all associated data is identical. */
+static bool read_libblock_is_identical(FileData *fd, BHead *bhead)
+{
+ /* Test ID itself. */
+ if (bhead->len && !BHEADN_FROM_BHEAD(bhead)->is_memchunk_identical) {
+ return false;
+ }
+
+ /* Test any other data that is part of ID (logic must match read_data_into_datamap). */
+ bhead = blo_bhead_next(fd, bhead);
+
+ while (bhead && bhead->code == DATA) {
+ if (bhead->len && !BHEADN_FROM_BHEAD(bhead)->is_memchunk_identical) {
+ return false;
+ }
+
+ bhead = blo_bhead_next(fd, bhead);
+ }
+
+ return true;
+}
+
+/* For undo, restore matching library datablock from the old main. */
+static bool read_libblock_undo_restore_library(FileData *fd, Main *main, const ID *id)
+{
+ /* In undo case, most libs and linked data should be kept as is from previous state
+ * (see BLO_read_from_memfile).
+ * However, some needed by the snapshot being read may have been removed in previous one,
+ * and would go missing.
+ * This leads e.g. to disappearing objects in some undo/redo case, see T34446.
+ * That means we have to carefully check whether current lib or
+ * libdata already exits in old main, if it does we merely copy it over into new main area,
+ * otherwise we have to do a full read of that bhead... */
+ DEBUG_PRINTF("UNDO: restore library %s\n", id->name);
+
+ Main *libmain = fd->old_mainlist->first;
+ /* Skip oldmain itself... */
+ for (libmain = libmain->next; libmain; libmain = libmain->next) {
+ DEBUG_PRINTF(" compare with %s -> ", libmain->curlib ? libmain->curlib->id.name : "<NULL>");
+ if (libmain->curlib && STREQ(id->name, libmain->curlib->id.name)) {
+ Main *oldmain = fd->old_mainlist->first;
+ DEBUG_PRINTF("match!\n");
+ /* In case of a library, we need to re-add its main to fd->mainlist,
+ * because if we have later a missing ID_LINK_PLACEHOLDER,
+ * we need to get the correct lib it is linked to!
+ * Order is crucial, we cannot bulk-add it in BLO_read_from_memfile()
+ * like it used to be. */
+ BLI_remlink(fd->old_mainlist, libmain);
+ BLI_remlink_safe(&oldmain->libraries, libmain->curlib);
+ BLI_addtail(fd->mainlist, libmain);
+ BLI_addtail(&main->libraries, libmain->curlib);
+ return true;
+ }
+ DEBUG_PRINTF("no match\n");
+ }
+
+ return false;
+}
+
+/* For undo, restore existing linked datablock from the old main. */
+static bool read_libblock_undo_restore_linked(FileData *fd, Main *main, const ID *id, BHead *bhead)
+{
+ DEBUG_PRINTF("UNDO: restore linked datablock %s\n", id->name);
+ DEBUG_PRINTF(" from %s (%s): ",
+ main->curlib ? main->curlib->id.name : "<NULL>",
+ main->curlib ? main->curlib->name : "<NULL>");
+
+ ID *id_old = BKE_libblock_find_name(main, GS(id->name), id->name + 2);
+ if (id_old != NULL) {
+ DEBUG_PRINTF(" found!\n");
+ /* Even though we found our linked ID, there is no guarantee its address
+ * is still the same. */
+ if (id_old != bhead->old) {
+ oldnewmap_insert(fd->libmap, bhead->old, id_old, GS(id_old->name));
+ }
+
+ /* No need to do anything else for ID_LINK_PLACEHOLDER, it's assumed
+ * already present in its lib's main. */
+ return true;
+ }
+
+ DEBUG_PRINTF(" not found\n");
+ return false;
+}
+
+/* For undo, restore unchanged datablock from old main. */
+static void read_libblock_undo_restore_identical(
+ FileData *fd, Main *main, const ID *UNUSED(id), ID *id_old, const int tag)
+{
+ BLI_assert((fd->skip_flags & BLO_READ_SKIP_UNDO_OLD_MAIN) == 0);
+ BLI_assert(id_old != NULL);
+
+ /* Some tags need to be preserved here. */
+ id_old->tag = tag | (id_old->tag & LIB_TAG_EXTRAUSER);
+ id_old->lib = main->curlib;
+ id_old->us = ID_FAKE_USERS(id_old);
+ /* Do not reset id->icon_id here, memory allocated for it remains valid. */
+ /* Needed because .blend may have been saved with crap value here... */
+ id_old->newid = NULL;
+ id_old->orig_id = NULL;
+
+ const short idcode = GS(id_old->name);
+ Main *old_bmain = fd->old_mainlist->first;
+ ListBase *old_lb = which_libbase(old_bmain, idcode);
+ ListBase *new_lb = which_libbase(main, idcode);
+ BLI_remlink(old_lb, id_old);
+ BLI_addtail(new_lb, id_old);
+
+ /* Recalc flags, mostly these just remain as they are. */
+ id_old->recalc |= direct_link_id_restore_recalc_exceptions(id_old);
+ id_old->recalc_after_undo_push = 0;
+
+ /* As usual, proxies require some special love...
+ * In `blo_clear_proxy_pointers_from_lib()` we clear all `proxy_from` pointers to local IDs, for
+ * undo. This is required since we do not re-read linked data in that case, so we also do not
+ * re-'lib_link' their pointers.
+ * Those `proxy_from` pointers are then re-defined properly when lib_linking the newly read local
+ * object. However, in case of re-used data 'as-is', we never lib_link it again, so we have to
+ * fix those backward pointers here. */
+ if (GS(id_old->name) == ID_OB) {
+ Object *ob = (Object *)id_old;
+ if (ob->proxy != NULL) {
+ ob->proxy->proxy_from = ob;
+ }
+ }
+}
+
+/* For undo, store changed datablock at old address. */
+static void read_libblock_undo_restore_at_old_address(FileData *fd, Main *main, ID *id, ID *id_old)
+{
+ /* During memfile undo, if an ID changed and we cannot directly re-use existing one from old
+ * bmain, we do a full read of the new id from the memfile, and then fully swap its content
+ * with the old id. This allows us to keep the same pointer even for modified data, which
+ * helps reducing further detected changes by the depsgraph (since unchanged IDs remain fully
+ * unchanged, even if they are using/pointing to a changed one). */
+ BLI_assert((fd->skip_flags & BLO_READ_SKIP_UNDO_OLD_MAIN) == 0);
+ BLI_assert(id_old != NULL);
+
+ const short idcode = GS(id->name);
+
+ /* XXX 3DCursor (witch is UI data and as such should not be affected by undo) is stored in
+ * Scene... So this requires some special handling, previously done in `blo_lib_link_restore()`,
+ * but this cannot work anymore when we overwrite existing memory... */
+ if (idcode == ID_SCE) {
+ Scene *scene_old = (Scene *)id_old;
+ Scene *scene = (Scene *)id;
+ SWAP(View3DCursor, scene_old->cursor, scene->cursor);
+ }
+
+ Main *old_bmain = fd->old_mainlist->first;
+ ListBase *old_lb = which_libbase(old_bmain, idcode);
+ ListBase *new_lb = which_libbase(main, idcode);
+ BLI_remlink(old_lb, id_old);
+ BLI_remlink(new_lb, id);
+
+ /* We do not need any remapping from this call here, since no ID pointer is valid in the data
+ * currently (they are all pointing to old addresses, and need to go through `lib_link`
+ * process). So we can pass NULL for the Main pointer parameter. */
+ BKE_lib_id_swap_full(NULL, id, id_old);
+
+ BLI_addtail(new_lb, id_old);
+ BLI_addtail(old_lb, id);
+}
+
+static bool read_libblock_undo_restore(
+ FileData *fd, Main *main, BHead *bhead, const int tag, ID **r_id_old)
+{
+ /* Get pointer to memory of new ID that we will be reading. */
+ const ID *id = peek_struct_undo(fd, bhead);
+ const short idcode = GS(id->name);
+
+ if (bhead->code == ID_LI) {
+ /* Restore library datablock. */
+ if (read_libblock_undo_restore_library(fd, main, id)) {
+ return true;
+ }
+ }
+ else if (bhead->code == ID_LINK_PLACEHOLDER) {
+ /* Restore linked datablock. */
+ if (read_libblock_undo_restore_linked(fd, main, id, bhead)) {
+ return true;
+ }
+ }
+ else if (ELEM(idcode, ID_WM, ID_SCR, ID_WS)) {
+ /* Skip reading any UI datablocks, existing ones are kept. We don't
+ * support pointers from other datablocks to UI datablocks so those
+ * we also don't put UI datablocks in fd->libmap. */
+ return true;
+ }
+
+ /* Restore local datablocks. */
+ DEBUG_PRINTF("UNDO: read %s (uuid %u) -> ", id->name, id->session_uuid);
+
+ ID *id_old = NULL;
+ const bool do_partial_undo = (fd->skip_flags & BLO_READ_SKIP_UNDO_OLD_MAIN) == 0;
+ if (do_partial_undo && (bhead->code != ID_LINK_PLACEHOLDER)) {
+ /* This code should only ever be reached for local data-blocks. */
+ BLI_assert(main->curlib == NULL);
+
+ /* Find the 'current' existing ID we want to reuse instead of the one we
+ * would read from the undo memfile. */
+ BLI_assert(fd->old_idmap != NULL);
+ id_old = BKE_main_idmap_lookup_uuid(fd->old_idmap, id->session_uuid);
+ }
+
+ if (id_old != NULL && read_libblock_is_identical(fd, bhead)) {
+ /* Local datablock was unchanged, restore from the old main. */
+ DEBUG_PRINTF("keep identical datablock\n");
+
+ /* Do not add LIB_TAG_NEW here, this should not be needed/used in undo case anyway (as
+ * this is only for do_version-like code), but for sake of consistency, and also because
+ * it will tell us which ID is re-used from old Main, and which one is actually new. */
+ /* Also do not add LIB_TAG_NEED_LINK, those IDs will never be re-liblinked, hence that tag will
+ * never be cleared, leading to critical issue in link/append code. */
+ const int id_tag = tag | LIB_TAG_UNDO_OLD_ID_REUSED;
+ read_libblock_undo_restore_identical(fd, main, id, id_old, id_tag);
+
+ /* Insert into library map for lookup by newly read datablocks (with pointer value bhead->old).
+ * Note that existing datablocks in memory (which pointer value would be id_old) are not
+ * remapped anymore, so no need to store this info here. */
+ oldnewmap_insert(fd->libmap, bhead->old, id_old, bhead->code);
+
+ *r_id_old = id_old;
+ return true;
+ }
+ else if (id_old != NULL) {
+ /* Local datablock was changed. Restore at the address of the old datablock. */
+ DEBUG_PRINTF("read to old existing address\n");
+ *r_id_old = id_old;
+ return false;
+ }
+ else {
+ /* Local datablock does not exist in the undo step, so read from scratch. */
+ DEBUG_PRINTF("read at new address\n");
+ return false;
+ }
+}
+
+/* This routine reads a datablock and its direct data, and advances bhead to
+ * the next datablock. For library linked datablocks, only a placeholder will
+ * be generated, to be replaced in read_library_linked_ids.
+ *
+ * When reading for undo, libraries, linked datablocks and unchanged datablocks
+ * will be restored from the old database. Only new or changed datablocks will
+ * actually be read. */
+static BHead *read_libblock(FileData *fd,
+ Main *main,
+ BHead *bhead,
+ const int tag,
+ const bool placeholder_set_indirect_extern,
+ ID **r_id)
+{
+ /* First attempt to restore existing datablocks for undo.
+ * When datablocks are changed but still exist, we restore them at the old
+ * address and inherit recalc flags for the dependency graph. */
+ ID *id_old = NULL;
+ if (fd->memfile != NULL) {
+ if (read_libblock_undo_restore(fd, main, bhead, tag, &id_old)) {
+ if (r_id) {
+ *r_id = id_old;
+ }
+ return blo_bhead_next(fd, bhead);
+ }
+ }
+
+ /* Read libblock struct. */
+ ID *id = read_struct(fd, bhead, "lib block");
+ if (id == NULL) {
+ if (r_id) {
+ *r_id = NULL;
+ }
+ return blo_bhead_next(fd, bhead);
+ }
+
+ /* Determine ID type and add to main database list. */
+ const short idcode = GS(id->name);
+ ListBase *lb = which_libbase(main, idcode);
+ if (lb == NULL) {
+ /* Unknown ID type. */
+ printf("%s: unknown id code '%c%c'\n", __func__, (idcode & 0xff), (idcode >> 8));
+ MEM_freeN(id);
+ if (r_id) {
+ *r_id = NULL;
+ }
+ return blo_bhead_next(fd, bhead);
+ }
+
+ /* NOTE: id must be added to the list before direct_link_id(), since
+ * direct_link_library() may remove it from there in case of duplicates. */
+ BLI_addtail(lb, id);
+
+ /* Insert into library map for lookup by newly read datablocks (with pointer value bhead->old).
+ * Note that existing datablocks in memory (which pointer value would be id_old) are not remapped
+ * remapped anymore, so no need to store this info here. */
+ ID *id_target = id_old ? id_old : id;
+ oldnewmap_insert(fd->libmap, bhead->old, id_target, bhead->code);
+
+ if (r_id) {
+ *r_id = id_target;
+ }
+
+ /* Set tag for new datablock to indicate lib linking and versioning needs
+ * to be done still. */
+ int id_tag = tag | LIB_TAG_NEED_LINK | LIB_TAG_NEW;
+
+ if (bhead->code == ID_LINK_PLACEHOLDER) {
+ /* Read placeholder for linked datablock. */
+ id_tag |= LIB_TAG_ID_LINK_PLACEHOLDER;
+
+ if (placeholder_set_indirect_extern) {
+ if (id->flag & LIB_INDIRECT_WEAK_LINK) {
+ id_tag |= LIB_TAG_INDIRECT;
+ }
+ else {
+ id_tag |= LIB_TAG_EXTERN;
+ }
+ }
+
+ direct_link_id(fd, main, id_tag, id, id_old);
+ return blo_bhead_next(fd, bhead);
+ }
+
+ /* Read datablock contents.
+ * Use convenient malloc name for debugging and better memory link prints. */
+ const char *allocname = dataname(idcode);
+ bhead = read_data_into_datamap(fd, bhead, allocname);
+ const bool success = direct_link_id(fd, main, id_tag, id, id_old);
oldnewmap_clear(fd->datamap);
- if (wrong_id) {
+ if (!success) {
/* XXX This is probably working OK currently given the very limited scope of that flag.
* However, it is absolutely **not** handled correctly: it is freeing an ID pointer that has
* been added to the fd->libmap mapping, which in theory could lead to nice crashes...
@@ -9673,39 +9872,12 @@ static BHead *read_libblock(FileData *fd,
*r_id = NULL;
}
}
- else if (do_id_swap) {
- /* During memfile undo, if an ID changed and we cannot directly re-use existing one from old
- * bmain, we do a full read of the new id from the memfile, and then fully swap its content
- * with the old id. This allows us to keep the same pointer even for modified data, which helps
- * reducing further detected changes by the depsgraph (since unchanged IDs remain fully
- * unchanged, even if they are using/pointing to a changed one). */
-
- BLI_assert((fd->skip_flags & BLO_READ_SKIP_UNDO_OLD_MAIN) == 0);
-
- Main *old_bmain = fd->old_mainlist->first;
- BLI_assert(id_old != NULL);
-
- ListBase *old_lb = which_libbase(old_bmain, idcode);
- ListBase *new_lb = which_libbase(main, idcode);
- BLI_remlink(old_lb, id_old);
- BLI_remlink(new_lb, id);
-
- /* We do not need any remapping from this call here, since no ID pointer is valid in the data
- * currently (they are all pointing to old addresses, and need to go through `lib_link`
- * process). So we can pass NULL for the Main pointer parameter. */
- BKE_lib_id_swap_full(NULL, id, id_old);
-
- BLI_addtail(new_lb, id_old);
- BLI_addtail(old_lb, id);
- }
- else if (fd->memfile != NULL) {
- DEBUG_PRINTF("We had to fully re-recreate ID %s (old addr: %p, new addr: %p)...\n",
- id->name,
- id_old,
- id);
+ else if (id_old) {
+ /* For undo, store contents read into id at id_old. */
+ read_libblock_undo_restore_at_old_address(fd, main, id, id_old);
}
- return (bhead);
+ return bhead;
}
/** \} */
@@ -9823,6 +9995,9 @@ static void do_versions(FileData *fd, Library *lib, Main *main)
{
/* WATCH IT!!!: pointers from libdata have not been converted */
+ /* Don't allow versioning to create new data-blocks. */
+ main->is_locked_for_linking = true;
+
if (G.debug & G_DEBUG) {
char build_commit_datetime[32];
time_t temp_time = main->build_commit_timestamp;
@@ -9847,12 +10022,15 @@ static void do_versions(FileData *fd, Library *lib, Main *main)
blo_do_versions_260(fd, lib, main);
blo_do_versions_270(fd, lib, main);
blo_do_versions_280(fd, lib, main);
+ blo_do_versions_290(fd, lib, main);
blo_do_versions_cycles(fd, lib, main);
/* WATCH IT!!!: pointers from libdata have not been converted yet here! */
/* WATCH IT 2!: Userdef struct init see do_versions_userdef() above! */
/* don't forget to set version number in BKE_blender_version.h! */
+
+ main->is_locked_for_linking = false;
}
static void do_versions_after_linking(Main *main, ReportList *reports)
@@ -9860,11 +10038,17 @@ static void do_versions_after_linking(Main *main, ReportList *reports)
// printf("%s for %s (%s), %d.%d\n", __func__, main->curlib ? main->curlib->name : main->name,
// main->curlib ? "LIB" : "MAIN", main->versionfile, main->subversionfile);
+ /* Don't allow versioning to create new data-blocks. */
+ main->is_locked_for_linking = true;
+
do_versions_after_linking_250(main);
do_versions_after_linking_260(main);
do_versions_after_linking_270(main);
do_versions_after_linking_280(main, reports);
+ do_versions_after_linking_290(main, reports);
do_versions_after_linking_cycles(main);
+
+ main->is_locked_for_linking = false;
}
/** \} */
@@ -10019,6 +10203,9 @@ static void lib_link_all(FileData *fd, Main *bmain)
case ID_AC:
lib_link_action(fd, bmain, (bAction *)id);
break;
+ case ID_SIM:
+ lib_link_simulation(fd, bmain, (Simulation *)id);
+ break;
case ID_IP:
/* XXX deprecated... still needs to be maintained for version patches still. */
lib_link_ipo(fd, bmain, (Ipo *)id);
@@ -10051,6 +10238,15 @@ static void lib_link_all(FileData *fd, Main *bmain)
* 'permanently' in our data structures... */
BKE_main_collections_parent_relations_rebuild(bmain);
}
+
+#ifndef NDEBUG
+ /* Double check we do not have any 'need link' tag remaining, this should never be the case once
+ * this function has run. */
+ FOREACH_MAIN_ID_BEGIN (bmain, id) {
+ BLI_assert((id->tag & LIB_TAG_NEED_LINK) == 0);
+ }
+ FOREACH_MAIN_ID_END;
+#endif
}
/** \} */
@@ -10082,7 +10278,7 @@ static BHead *read_userdef(BlendFileData *bfd, FileData *fd, BHead *bhead)
user->subversionfile = bfd->main->subversionfile;
/* read all data into fd->datamap */
- bhead = read_data_into_oldnewmap(fd, bhead, "user def");
+ bhead = read_data_into_datamap(fd, bhead, "user def");
link_list(fd, &user->themes);
link_list(fd, &user->user_keymaps);
@@ -10116,14 +10312,14 @@ static BHead *read_userdef(BlendFileData *bfd, FileData *fd, BHead *bhead)
}
}
- for (wmKeyConfigPref *kpt = user->user_keyconfig_prefs.first; kpt; kpt = kpt->next) {
+ LISTBASE_FOREACH (wmKeyConfigPref *, kpt, &user->user_keyconfig_prefs) {
kpt->prop = newdataadr(fd, kpt->prop);
IDP_DirectLinkGroup_OrFree(&kpt->prop, (fd->flags & FD_FLAGS_SWITCH_ENDIAN), fd);
}
- for (bUserMenu *um = user->user_menus.first; um; um = um->next) {
+ LISTBASE_FOREACH (bUserMenu *, um, &user->user_menus) {
link_list(fd, &um->items);
- for (bUserMenuItem *umi = um->items.first; umi; umi = umi->next) {
+ LISTBASE_FOREACH (bUserMenuItem *, umi, &um->items) {
if (umi->type == USER_MENU_TYPE_OPERATOR) {
bUserMenuItem_Op *umi_op = (bUserMenuItem_Op *)umi;
umi_op->prop = newdataadr(fd, umi_op->prop);
@@ -10150,7 +10346,6 @@ static BHead *read_userdef(BlendFileData *bfd, FileData *fd, BHead *bhead)
user->edit_studio_light = 0;
/* free fd->datamap again */
- oldnewmap_free_unused(fd->datamap);
oldnewmap_clear(fd->datamap);
return bhead;
@@ -10168,6 +10363,10 @@ BlendFileData *blo_read_file_internal(FileData *fd, const char *filepath)
BlendFileData *bfd;
ListBase mainlist = {NULL, NULL};
+ if (fd->memfile != NULL) {
+ DEBUG_PRINTF("\nUNDO: read step\n");
+ }
+
bfd = MEM_callocN(sizeof(BlendFileData), "blendfiledata");
bfd->main = BKE_main_new();
@@ -10285,7 +10484,7 @@ BlendFileData *blo_read_file_internal(FileData *fd, const char *filepath)
/* Yep, second splitting... but this is a very cheap operation, so no big deal. */
blo_split_main(&mainlist, bfd->main);
- for (Main *mainvar = mainlist.first; mainvar; mainvar = mainvar->next) {
+ LISTBASE_FOREACH (Main *, mainvar, &mainlist) {
BLI_assert(mainvar->versionfile != 0);
do_versions_after_linking(mainvar, fd->reports);
}
@@ -10394,7 +10593,7 @@ static BHead *find_previous_lib(FileData *fd, BHead *bhead)
static BHead *find_bhead(FileData *fd, void *old)
{
#if 0
- BHead* bhead;
+ BHead* bhead;
#endif
struct BHeadSort *bhs, bhs_s;
@@ -10414,11 +10613,11 @@ static BHead *find_bhead(FileData *fd, void *old)
}
#if 0
- for (bhead = blo_bhead_first(fd); bhead; bhead = blo_bhead_next(fd, bhead)) {
- if (bhead->old == old) {
- return bhead;
- }
- }
+ for (bhead = blo_bhead_first(fd); bhead; bhead = blo_bhead_next(fd, bhead)) {
+ if (bhead->old == old) {
+ return bhead;
+ }
+ }
#endif
return NULL;
@@ -10549,9 +10748,9 @@ static void expand_doit_library(void *fdhandle, Main *mainvar, void *old)
/* Commented because this can print way too much. */
#if 0
- if (G.debug & G_DEBUG) {
- printf("expand_doit: already linked: %s lib: %s\n", id->name, lib->name);
- }
+ if (G.debug & G_DEBUG) {
+ printf("expand_doit: already linked: %s lib: %s\n", id->name, lib->name);
+ }
#endif
}
@@ -10703,7 +10902,7 @@ static void expand_idprops(FileData *fd, Main *mainvar, IDProperty *prop)
break;
}
case IDP_GROUP:
- for (IDProperty *loop = prop->data.group.first; loop; loop = loop->next) {
+ LISTBASE_FOREACH (IDProperty *, loop, &prop->data.group) {
expand_idprops(fd, mainvar, loop);
}
break;
@@ -10714,7 +10913,7 @@ static void expand_id(FileData *fd, Main *mainvar, ID *id);
static void expand_nodetree(FileData *fd, Main *mainvar, bNodeTree *ntree);
static void expand_collection(FileData *fd, Main *mainvar, Collection *collection);
-static void expand_id_private_id(FileData *fd, Main *mainvar, ID *id)
+static void expand_id_embedded_id(FileData *fd, Main *mainvar, ID *id)
{
/* Handle 'private IDs'. */
bNodeTree *nodetree = ntreeFromID(id);
@@ -10746,7 +10945,7 @@ static void expand_id(FileData *fd, Main *mainvar, ID *id)
expand_animdata(fd, mainvar, adt);
}
- expand_id_private_id(fd, mainvar, id);
+ expand_id_embedded_id(fd, mainvar, id);
}
static void expand_action(FileData *fd, Main *mainvar, bAction *act)
@@ -10763,7 +10962,7 @@ static void expand_action(FileData *fd, Main *mainvar, bAction *act)
/* F-Curves in Action */
expand_fcurves(fd, mainvar, &act->curves);
- for (TimeMarker *marker = act->markers.first; marker; marker = marker->next) {
+ LISTBASE_FOREACH (TimeMarker *, marker, &act->markers) {
if (marker->camera) {
expand_doit(fd, mainvar, marker->camera);
}
@@ -10831,18 +11030,18 @@ static void expand_particlesettings(FileData *fd, Main *mainvar, ParticleSetting
}
}
- for (ParticleDupliWeight *dw = part->instance_weights.first; dw; dw = dw->next) {
+ LISTBASE_FOREACH (ParticleDupliWeight *, dw, &part->instance_weights) {
expand_doit(fd, mainvar, dw->ob);
}
}
static void expand_collection(FileData *fd, Main *mainvar, Collection *collection)
{
- for (CollectionObject *cob = collection->gobject.first; cob; cob = cob->next) {
+ LISTBASE_FOREACH (CollectionObject *, cob, &collection->gobject) {
expand_doit(fd, mainvar, cob->ob);
}
- for (CollectionChild *child = collection->children.first; child; child = child->next) {
+ LISTBASE_FOREACH (CollectionChild *, child, &collection->children) {
expand_doit(fd, mainvar, child->collection);
}
@@ -10858,10 +11057,51 @@ static void expand_key(FileData *fd, Main *mainvar, Key *key)
expand_doit(fd, mainvar, key->ipo); // XXX deprecated - old animation system
}
+static void expand_node_socket(FileData *fd, Main *mainvar, bNodeSocket *sock)
+{
+ expand_idprops(fd, mainvar, sock->prop);
+
+ if (sock->default_value != NULL) {
+
+ switch ((eNodeSocketDatatype)sock->type) {
+ case SOCK_OBJECT: {
+ bNodeSocketValueObject *default_value = sock->default_value;
+ expand_doit(fd, mainvar, default_value->value);
+ break;
+ }
+ case SOCK_IMAGE: {
+ bNodeSocketValueImage *default_value = sock->default_value;
+ expand_doit(fd, mainvar, default_value->value);
+ break;
+ }
+ case SOCK_FLOAT:
+ case SOCK_VECTOR:
+ case SOCK_RGBA:
+ case SOCK_BOOLEAN:
+ case SOCK_INT:
+ case SOCK_STRING:
+ case __SOCK_MESH:
+ case SOCK_CUSTOM:
+ case SOCK_SHADER:
+ case SOCK_EMITTERS:
+ case SOCK_EVENTS:
+ case SOCK_FORCES:
+ case SOCK_CONTROL_FLOW:
+ break;
+ }
+ }
+}
+
+static void expand_node_sockets(FileData *fd, Main *mainvar, ListBase *sockets)
+{
+ LISTBASE_FOREACH (bNodeSocket *, sock, sockets) {
+ expand_node_socket(fd, mainvar, sock);
+ }
+}
+
static void expand_nodetree(FileData *fd, Main *mainvar, bNodeTree *ntree)
{
bNode *node;
- bNodeSocket *sock;
if (ntree->gpd) {
expand_doit(fd, mainvar, ntree->gpd);
@@ -10874,20 +11114,12 @@ static void expand_nodetree(FileData *fd, Main *mainvar, bNodeTree *ntree)
expand_idprops(fd, mainvar, node->prop);
- for (sock = node->inputs.first; sock; sock = sock->next) {
- expand_idprops(fd, mainvar, sock->prop);
- }
- for (sock = node->outputs.first; sock; sock = sock->next) {
- expand_idprops(fd, mainvar, sock->prop);
- }
+ expand_node_sockets(fd, mainvar, &node->inputs);
+ expand_node_sockets(fd, mainvar, &node->outputs);
}
- for (sock = ntree->inputs.first; sock; sock = sock->next) {
- expand_idprops(fd, mainvar, sock->prop);
- }
- for (sock = ntree->outputs.first; sock; sock = sock->next) {
- expand_idprops(fd, mainvar, sock->prop);
- }
+ expand_node_sockets(fd, mainvar, &ntree->inputs);
+ expand_node_sockets(fd, mainvar, &ntree->outputs);
}
static void expand_texture(FileData *fd, Main *mainvar, Tex *tex)
@@ -11027,14 +11259,14 @@ static void expand_bones(FileData *fd, Main *mainvar, Bone *bone)
{
expand_idprops(fd, mainvar, bone->prop);
- for (Bone *curBone = bone->childbase.first; curBone; curBone = curBone->next) {
+ LISTBASE_FOREACH (Bone *, curBone, &bone->childbase) {
expand_bones(fd, mainvar, curBone);
}
}
static void expand_armature(FileData *fd, Main *mainvar, bArmature *arm)
{
- for (Bone *curBone = arm->bonebase.first; curBone; curBone = curBone->next) {
+ LISTBASE_FOREACH (Bone *, curBone, &arm->bonebase) {
expand_bones(fd, mainvar, curBone);
}
}
@@ -11073,7 +11305,7 @@ static void expand_object(FileData *fd, Main *mainvar, Object *ob)
data.fd = fd;
data.mainvar = mainvar;
- modifiers_foreachIDLink(ob, expand_object_expandModifiers, (void *)&data);
+ BKE_modifiers_foreach_ID_link(ob, expand_object_expandModifiers, (void *)&data);
}
/* expand_object_expandModifier() */
@@ -11085,7 +11317,7 @@ static void expand_object(FileData *fd, Main *mainvar, Object *ob)
data.fd = fd;
data.mainvar = mainvar;
- BKE_gpencil_modifiers_foreachIDLink(ob, expand_object_expandModifiers, (void *)&data);
+ BKE_gpencil_modifiers_foreach_ID_link(ob, expand_object_expandModifiers, (void *)&data);
}
/* expand_object_expandShaderFx() */
@@ -11097,7 +11329,7 @@ static void expand_object(FileData *fd, Main *mainvar, Object *ob)
data.fd = fd;
data.mainvar = mainvar;
- BKE_shaderfx_foreachIDLink(ob, expand_object_expandModifiers, (void *)&data);
+ BKE_shaderfx_foreach_ID_link(ob, expand_object_expandModifiers, (void *)&data);
}
expand_pose(fd, mainvar, ob->pose);
@@ -11172,11 +11404,11 @@ static void expand_object(FileData *fd, Main *mainvar, Object *ob)
#ifdef USE_COLLECTION_COMPAT_28
static void expand_scene_collection(FileData *fd, Main *mainvar, SceneCollection *sc)
{
- for (LinkData *link = sc->objects.first; link; link = link->next) {
+ LISTBASE_FOREACH (LinkData *, link, &sc->objects) {
expand_doit(fd, mainvar, link->data);
}
- for (SceneCollection *nsc = sc->scene_collections.first; nsc; nsc = nsc->next) {
+ LISTBASE_FOREACH (SceneCollection *, nsc, &sc->scene_collections) {
expand_scene_collection(fd, mainvar, nsc);
}
}
@@ -11188,7 +11420,7 @@ static void expand_scene(FileData *fd, Main *mainvar, Scene *sce)
FreestyleModuleConfig *module;
FreestyleLineSet *lineset;
- for (Base *base_legacy = sce->base.first; base_legacy; base_legacy = base_legacy->next) {
+ LISTBASE_FOREACH (Base *, base_legacy, &sce->base) {
expand_doit(fd, mainvar, base_legacy->object);
}
expand_doit(fd, mainvar, sce->camera);
@@ -11215,7 +11447,7 @@ static void expand_scene(FileData *fd, Main *mainvar, Scene *sce)
}
}
- for (ViewLayer *view_layer = sce->view_layers.first; view_layer; view_layer = view_layer->next) {
+ LISTBASE_FOREACH (ViewLayer *, view_layer, &sce->view_layers) {
expand_idprops(fd, mainvar, view_layer->id_properties);
for (module = view_layer->freestyle_config.modules.first; module; module = module->next) {
@@ -11271,7 +11503,7 @@ static void expand_scene(FileData *fd, Main *mainvar, Scene *sce)
expand_doit(fd, mainvar, sce->rigidbody_world->constraints);
}
- for (TimeMarker *marker = sce->markers.first; marker; marker = marker->next) {
+ LISTBASE_FOREACH (TimeMarker *, marker, &sce->markers) {
if (marker->camera) {
expand_doit(fd, mainvar, marker->camera);
}
@@ -11294,7 +11526,7 @@ static void expand_camera(FileData *fd, Main *mainvar, Camera *ca)
{
expand_doit(fd, mainvar, ca->ipo); // XXX deprecated - old animation system
- for (CameraBGImage *bgpic = ca->bg_images.first; bgpic; bgpic = bgpic->next) {
+ LISTBASE_FOREACH (CameraBGImage *, bgpic, &ca->bg_images) {
if (bgpic->source == CAM_BGIMG_SOURCE_IMAGE) {
expand_doit(fd, mainvar, bgpic->ima);
}
@@ -11398,9 +11630,7 @@ static void expand_gpencil(FileData *fd, Main *mainvar, bGPdata *gpd)
static void expand_workspace(FileData *fd, Main *mainvar, WorkSpace *workspace)
{
- ListBase *layouts = BKE_workspace_layouts_get(workspace);
-
- for (WorkSpaceLayout *layout = layouts->first; layout; layout = layout->next) {
+ LISTBASE_FOREACH (WorkSpaceLayout *, layout, &workspace->layouts) {
expand_doit(fd, mainvar, BKE_workspace_layout_screen_get(layout));
}
}
@@ -11438,6 +11668,13 @@ static void expand_volume(FileData *fd, Main *mainvar, Volume *volume)
}
}
+static void expand_simulation(FileData *fd, Main *mainvar, Simulation *simulation)
+{
+ if (simulation->adt) {
+ expand_animdata(fd, mainvar, simulation->adt);
+ }
+}
+
/**
* Set the callback func used over all ID data found by \a BLO_expand_main func.
*
@@ -11567,6 +11804,9 @@ void BLO_expand_main(void *fdhandle, Main *mainvar)
case ID_VO:
expand_volume(fd, mainvar, (Volume *)id);
break;
+ case ID_SIM:
+ expand_simulation(fd, mainvar, (Simulation *)id);
+ break;
default:
break;
}
@@ -11703,6 +11943,7 @@ static void add_collections_to_scene(Main *mainvar,
/* BKE_object_add(...) messes with the selection. */
Object *ob = BKE_object_add_only_object(bmain, OB_EMPTY, collection->id.name + 2);
ob->type = OB_EMPTY;
+ ob->empty_drawsize = U.collection_instance_empty_size;
BKE_collection_object_add(bmain, active_collection, ob);
Base *base = BKE_view_layer_base_find(view_layer, ob);
@@ -12142,7 +12383,7 @@ static int has_linked_ids_to_read(Main *mainvar)
int a = set_listbasepointers(mainvar, lbarray);
while (a--) {
- for (ID *id = lbarray[a]->first; id; id = id->next) {
+ LISTBASE_FOREACH (ID *, id, lbarray[a]) {
if ((id->tag & LIB_TAG_ID_LINK_PLACEHOLDER) && !(id->flag & LIB_INDIRECT_WEAK_LINK)) {
return true;
}
@@ -12373,9 +12614,9 @@ static void read_libraries(FileData *basefd, ListBase *mainlist)
/* Does this library have any more linked data-blocks we need to read? */
if (has_linked_ids_to_read(mainptr)) {
#if 0
- printf("Reading linked data-blocks from %s (%s)\n",
- mainptr->curlib->id.name,
- mainptr->curlib->name);
+ printf("Reading linked data-blocks from %s (%s)\n",
+ mainptr->curlib->id.name,
+ mainptr->curlib->name);
#endif
/* Open file if it has not been done yet. */
@@ -12439,4 +12680,164 @@ static void read_libraries(FileData *basefd, ListBase *mainlist)
BKE_main_free(main_newid);
}
+void *BLO_read_get_new_data_address(BlendDataReader *reader, const void *old_address)
+{
+ return newdataadr(reader->fd, old_address);
+}
+
+ID *BLO_read_get_new_id_address(BlendLibReader *reader, Library *lib, ID *id)
+{
+ return newlibadr(reader->fd, lib, id);
+}
+
+bool BLO_read_requires_endian_switch(BlendDataReader *reader)
+{
+ return (reader->fd->flags & FD_FLAGS_SWITCH_ENDIAN) != 0;
+}
+
+/**
+ * Updates all ->prev and ->next pointers of the list elements.
+ * Updates the list->first and list->last pointers.
+ * When not NULL, calls the callback on every element.
+ */
+void BLO_read_list(BlendDataReader *reader, ListBase *list, BlendReadListFn callback)
+{
+ if (BLI_listbase_is_empty(list)) {
+ return;
+ }
+
+ BLO_read_data_address(reader, &list->first);
+ if (callback != NULL) {
+ callback(reader, list->first);
+ }
+ Link *ln = list->first;
+ Link *prev = NULL;
+ while (ln) {
+ BLO_read_data_address(reader, &ln->next);
+ if (ln->next != NULL && callback != NULL) {
+ callback(reader, ln->next);
+ }
+ ln->prev = prev;
+ prev = ln;
+ ln = ln->next;
+ }
+ list->last = prev;
+}
+
+void BLO_read_int32_array(BlendDataReader *reader, int array_size, int32_t **ptr_p)
+{
+ BLO_read_data_address(reader, ptr_p);
+ if (BLO_read_requires_endian_switch(reader)) {
+ BLI_endian_switch_int32_array(*ptr_p, array_size);
+ }
+}
+
+void BLO_read_uint32_array(BlendDataReader *reader, int array_size, uint32_t **ptr_p)
+{
+ BLO_read_data_address(reader, ptr_p);
+ if (BLO_read_requires_endian_switch(reader)) {
+ BLI_endian_switch_uint32_array(*ptr_p, array_size);
+ }
+}
+
+void BLO_read_float_array(BlendDataReader *reader, int array_size, float **ptr_p)
+{
+ BLO_read_data_address(reader, ptr_p);
+ if (BLO_read_requires_endian_switch(reader)) {
+ BLI_endian_switch_float_array(*ptr_p, array_size);
+ }
+}
+
+void BLO_read_float3_array(BlendDataReader *reader, int array_size, float **ptr_p)
+{
+ BLO_read_float_array(reader, array_size * 3, ptr_p);
+}
+
+void BLO_read_double_array(BlendDataReader *reader, int array_size, double **ptr_p)
+{
+ BLO_read_data_address(reader, ptr_p);
+ if (BLO_read_requires_endian_switch(reader)) {
+ BLI_endian_switch_double_array(*ptr_p, array_size);
+ }
+}
+
+static void convert_pointer_array_64_to_32(BlendDataReader *reader,
+ uint array_size,
+ const uint64_t *src,
+ uint32_t *dst)
+{
+ /* Match pointer conversion rules from bh4_from_bh8 and cast_pointer. */
+ if (BLO_read_requires_endian_switch(reader)) {
+ for (int i = 0; i < array_size; i++) {
+ uint64_t ptr = src[i];
+ BLI_endian_switch_uint64(&ptr);
+ dst[i] = (uint32_t)(ptr >> 3);
+ }
+ }
+ else {
+ for (int i = 0; i < array_size; i++) {
+ dst[i] = (uint32_t)(src[i] >> 3);
+ }
+ }
+}
+
+static void convert_pointer_array_32_to_64(BlendDataReader *UNUSED(reader),
+ uint array_size,
+ const uint32_t *src,
+ uint64_t *dst)
+{
+ /* Match pointer conversion rules from bh8_from_bh4 and cast_pointer. */
+ for (int i = 0; i < array_size; i++) {
+ dst[i] = src[i];
+ }
+}
+
+void BLO_read_pointer_array(BlendDataReader *reader, void **ptr_p)
+{
+ FileData *fd = reader->fd;
+
+ void *orig_array = newdataadr(fd, *ptr_p);
+ if (orig_array == NULL) {
+ *ptr_p = NULL;
+ return;
+ }
+
+ int file_pointer_size = fd->filesdna->pointer_size;
+ int current_pointer_size = fd->memsdna->pointer_size;
+
+ /* Overallocation is fine, but might be better to pass the length as parameter. */
+ int array_size = MEM_allocN_len(orig_array) / file_pointer_size;
+
+ void *final_array = NULL;
+
+ if (file_pointer_size == current_pointer_size) {
+ /* No pointer conversion necessary. */
+ final_array = orig_array;
+ }
+ else if (file_pointer_size == 8 && current_pointer_size == 4) {
+ /* Convert pointers from 64 to 32 bit. */
+ final_array = MEM_malloc_arrayN(array_size, 4, "new pointer array");
+ convert_pointer_array_64_to_32(
+ reader, array_size, (uint64_t *)orig_array, (uint32_t *)final_array);
+ MEM_freeN(orig_array);
+ }
+ else if (file_pointer_size == 4 && current_pointer_size == 8) {
+ /* Convert pointers from 32 to 64 bit. */
+ final_array = MEM_malloc_arrayN(array_size, 8, "new pointer array");
+ convert_pointer_array_32_to_64(
+ reader, array_size, (uint32_t *)orig_array, (uint64_t *)final_array);
+ MEM_freeN(orig_array);
+ }
+ else {
+ BLI_assert(false);
+ }
+
+ *ptr_p = final_array;
+}
+
+void BLO_expand_id(BlendExpander *expander, ID *id)
+{
+ expand_doit(expander->fd, expander->main, id);
+}
+
/** \} */
diff --git a/source/blender/blenloader/intern/readfile.h b/source/blender/blenloader/intern/readfile.h
index 5be7e703d6b..f698d642e33 100644
--- a/source/blender/blenloader/intern/readfile.h
+++ b/source/blender/blenloader/intern/readfile.h
@@ -85,11 +85,6 @@ typedef struct FileData {
const char *buffer;
/** Variables needed for reading from memfile (undo). */
struct MemFile *memfile;
- /** Whether all data read from memfile so far was identical
- * (i.e. shared with some previous undo step).
- * Updated by `fd_read_from_memfile()`, user is responsible to reset it to true when needed.
- * Used to detect unchanged IDs. */
- bool are_memchunks_identical;
/** Whether we are undoing (< 0) or redoing (> 0), used to choose which 'unchanged' flag to use
* to detect unchanged data from memfile. */
short undo_direction;
@@ -204,12 +199,14 @@ void blo_do_versions_250(struct FileData *fd, struct Library *lib, struct Main *
void blo_do_versions_260(struct FileData *fd, struct Library *lib, struct Main *bmain);
void blo_do_versions_270(struct FileData *fd, struct Library *lib, struct Main *bmain);
void blo_do_versions_280(struct FileData *fd, struct Library *lib, struct Main *bmain);
+void blo_do_versions_290(struct FileData *fd, struct Library *lib, struct Main *bmain);
void blo_do_versions_cycles(struct FileData *fd, struct Library *lib, struct Main *bmain);
void do_versions_after_linking_250(struct Main *bmain);
void do_versions_after_linking_260(struct Main *bmain);
void do_versions_after_linking_270(struct Main *bmain);
-void do_versions_after_linking_280(struct Main *bmain, ReportList *reports);
+void do_versions_after_linking_280(struct Main *bmain, struct ReportList *reports);
+void do_versions_after_linking_290(struct Main *bmain, struct ReportList *reports);
void do_versions_after_linking_cycles(struct Main *bmain);
#endif
diff --git a/source/blender/blenloader/intern/undofile.c b/source/blender/blenloader/intern/undofile.c
index 06469a0c087..28b37c4a737 100644
--- a/source/blender/blenloader/intern/undofile.c
+++ b/source/blender/blenloader/intern/undofile.c
@@ -41,10 +41,12 @@
#include "DNA_listBase.h"
#include "BLI_blenlib.h"
+#include "BLI_ghash.h"
#include "BLO_readfile.h"
#include "BLO_undofile.h"
+#include "BKE_lib_id.h"
#include "BKE_main.h"
/* keep last */
@@ -92,13 +94,69 @@ void BLO_memfile_merge(MemFile *first, MemFile *second)
BLO_memfile_free(first);
}
-void memfile_chunk_add(MemFile *memfile, const char *buf, uint size, MemFileChunk **compchunk_step)
+/* Clear is_identical_future before adding next memfile. */
+void BLO_memfile_clear_future(MemFile *memfile)
{
+ LISTBASE_FOREACH (MemFileChunk *, chunk, &memfile->chunks) {
+ chunk->is_identical_future = false;
+ }
+}
+
+void BLO_memfile_write_init(MemFileWriteData *mem_data,
+ MemFile *written_memfile,
+ MemFile *reference_memfile)
+{
+ mem_data->written_memfile = written_memfile;
+ mem_data->reference_memfile = reference_memfile;
+ mem_data->reference_current_chunk = reference_memfile ? reference_memfile->chunks.first : NULL;
+
+ /* If we have a reference memfile, we generate a mapping between the session_uuid's of the IDs
+ * stored in that previous undo step, and its first matching memchunk.
+ * This will allow us to easily find the existing undo memory storage of IDs even when some
+ * re-ordering in current Main data-base broke the order matching with the memchunks from
+ * previous step. */
+ if (reference_memfile != NULL) {
+ mem_data->id_session_uuid_mapping = BLI_ghash_new(
+ BLI_ghashutil_inthash_p_simple, BLI_ghashutil_intcmp, __func__);
+ uint current_session_uuid = MAIN_ID_SESSION_UUID_UNSET;
+ LISTBASE_FOREACH (MemFileChunk *, mem_chunk, &reference_memfile->chunks) {
+ if (!ELEM(mem_chunk->id_session_uuid, MAIN_ID_SESSION_UUID_UNSET, current_session_uuid)) {
+ current_session_uuid = mem_chunk->id_session_uuid;
+ void **entry;
+ if (!BLI_ghash_ensure_p(mem_data->id_session_uuid_mapping,
+ POINTER_FROM_UINT(current_session_uuid),
+ &entry)) {
+ *entry = mem_chunk;
+ }
+ else {
+ BLI_assert(0);
+ }
+ }
+ }
+ }
+}
+
+void BLO_memfile_write_finalize(MemFileWriteData *mem_data)
+{
+ if (mem_data->id_session_uuid_mapping != NULL) {
+ BLI_ghash_free(mem_data->id_session_uuid_mapping, NULL, NULL);
+ }
+}
+
+void BLO_memfile_chunk_add(MemFileWriteData *mem_data, const char *buf, uint size)
+{
+ MemFile *memfile = mem_data->written_memfile;
+ MemFileChunk **compchunk_step = &mem_data->reference_current_chunk;
+
MemFileChunk *curchunk = MEM_mallocN(sizeof(MemFileChunk), "MemFileChunk");
curchunk->size = size;
curchunk->buf = NULL;
curchunk->is_identical = false;
- curchunk->is_identical_future = false;
+ /* This is unsafe in the sense that an app handler or other code that does not
+ * perform an undo push may make changes after the last undo push that
+ * will then not be undo. Though it's not entirely clear that is wrong behavior. */
+ curchunk->is_identical_future = true;
+ curchunk->id_session_uuid = mem_data->current_id_session_uuid;
BLI_addtail(&memfile->chunks, curchunk);
/* we compare compchunk with buf */
diff --git a/source/blender/blenloader/intern/versioning_250.c b/source/blender/blenloader/intern/versioning_250.c
index fed0cbda466..eaeef0d52c1 100644
--- a/source/blender/blenloader/intern/versioning_250.c
+++ b/source/blender/blenloader/intern/versioning_250.c
@@ -61,7 +61,8 @@
#include "BLI_math.h"
#include "BLI_utildefines.h"
-#include "BKE_anim.h"
+#include "BKE_anim_data.h"
+#include "BKE_anim_visualization.h"
#include "BKE_armature.h"
#include "BKE_colortools.h"
#include "BKE_global.h" // for G
@@ -88,13 +89,13 @@
#define U (*((const UserDef *)&U))
/* 2.50 patch */
-static void area_add_header_region(ScrArea *sa, ListBase *lb)
+static void area_add_header_region(ScrArea *area, ListBase *lb)
{
ARegion *region = MEM_callocN(sizeof(ARegion), "area region from do_versions");
BLI_addtail(lb, region);
region->regiontype = RGN_TYPE_HEADER;
- if (sa->headertype == 1) {
+ if (area->headertype == 1) {
region->alignment = RGN_ALIGN_BOTTOM;
}
else {
@@ -133,10 +134,10 @@ static void sequencer_init_preview_region(ARegion *region)
region->v2d.keeptot = V2D_KEEPTOT_FREE;
}
-static void area_add_window_regions(ScrArea *sa, SpaceLink *sl, ListBase *lb)
+static void area_add_window_regions(ScrArea *area, SpaceLink *sl, ListBase *lb)
{
ARegion *region;
- ARegion *ar_main;
+ ARegion *region_main;
if (sl) {
/* first channels for ipo action nla... */
@@ -205,14 +206,14 @@ static void area_add_window_regions(ScrArea *sa, SpaceLink *sl, ListBase *lb)
region->alignment = RGN_ALIGN_TOP;
break;
case SPACE_SEQ:
- ar_main = (ARegion *)lb->first;
- for (; ar_main; ar_main = ar_main->next) {
- if (ar_main->regiontype == RGN_TYPE_WINDOW) {
+ region_main = (ARegion *)lb->first;
+ for (; region_main; region_main = region_main->next) {
+ if (region_main->regiontype == RGN_TYPE_WINDOW) {
break;
}
}
region = MEM_callocN(sizeof(ARegion), "preview area for sequencer");
- BLI_insertlinkbefore(lb, ar_main, region);
+ BLI_insertlinkbefore(lb, region_main, region);
sequencer_init_preview_region(region);
break;
case SPACE_VIEW3D:
@@ -256,7 +257,7 @@ static void area_add_window_regions(ScrArea *sa, SpaceLink *sl, ListBase *lb)
region = MEM_callocN(sizeof(ARegion), "area region from do_versions");
BLI_addtail(lb, region);
- region->winrct = sa->totrct;
+ region->winrct = area->totrct;
region->regiontype = RGN_TYPE_WINDOW;
@@ -303,7 +304,7 @@ static void area_add_window_regions(ScrArea *sa, SpaceLink *sl, ListBase *lb)
SpaceNla *snla = (SpaceNla *)sl;
memcpy(&region->v2d, &snla->v2d, sizeof(View2D));
- region->v2d.tot.ymin = (float)(-sa->winy) / 3.0f;
+ region->v2d.tot.ymin = (float)(-area->winy) / 3.0f;
region->v2d.tot.ymax = 0.0f;
region->v2d.scroll |= (V2D_SCROLL_BOTTOM | V2D_SCROLL_HORIZONTAL_HANDLES);
@@ -318,8 +319,8 @@ static void area_add_window_regions(ScrArea *sa, SpaceLink *sl, ListBase *lb)
/* We totally reinit the view for the Action Editor,
* as some old instances had some weird cruft set. */
region->v2d.tot.xmin = -20.0f;
- region->v2d.tot.ymin = (float)(-sa->winy) / 3.0f;
- region->v2d.tot.xmax = (float)((sa->winx > 120) ? (sa->winx) : 120);
+ region->v2d.tot.ymin = (float)(-area->winy) / 3.0f;
+ region->v2d.tot.xmax = (float)((area->winx > 120) ? (area->winx) : 120);
region->v2d.tot.ymax = 0.0f;
region->v2d.cur = region->v2d.tot;
@@ -397,40 +398,40 @@ static void area_add_window_regions(ScrArea *sa, SpaceLink *sl, ListBase *lb)
static void do_versions_windowmanager_2_50(bScreen *screen)
{
- ScrArea *sa;
+ ScrArea *area;
SpaceLink *sl;
/* add regions */
- for (sa = screen->areabase.first; sa; sa = sa->next) {
+ for (area = screen->areabase.first; area; area = area->next) {
/* we keep headertype variable to convert old files only */
- if (sa->headertype) {
- area_add_header_region(sa, &sa->regionbase);
+ if (area->headertype) {
+ area_add_header_region(area, &area->regionbase);
}
- area_add_window_regions(sa, sa->spacedata.first, &sa->regionbase);
+ area_add_window_regions(area, area->spacedata.first, &area->regionbase);
/* space imageselect is deprecated */
- for (sl = sa->spacedata.first; sl; sl = sl->next) {
+ for (sl = area->spacedata.first; sl; sl = sl->next) {
if (sl->spacetype == SPACE_IMASEL) {
sl->spacetype = SPACE_EMPTY; /* spacedata then matches */
}
}
/* space sound is deprecated */
- for (sl = sa->spacedata.first; sl; sl = sl->next) {
+ for (sl = area->spacedata.first; sl; sl = sl->next) {
if (sl->spacetype == SPACE_SOUND) {
sl->spacetype = SPACE_EMPTY; /* spacedata then matches */
}
}
/* pushed back spaces also need regions! */
- if (sa->spacedata.first) {
- sl = sa->spacedata.first;
+ if (area->spacedata.first) {
+ sl = area->spacedata.first;
for (sl = sl->next; sl; sl = sl->next) {
- if (sa->headertype) {
- area_add_header_region(sa, &sl->regionbase);
+ if (area->headertype) {
+ area_add_header_region(area, &sl->regionbase);
}
- area_add_window_regions(sa, sl, &sl->regionbase);
+ area_add_window_regions(area, sl, &sl->regionbase);
}
}
}
@@ -455,12 +456,12 @@ static void versions_gpencil_add_main(ListBase *lb, ID *id, const char *name)
static void do_versions_gpencil_2_50(Main *main, bScreen *screen)
{
- ScrArea *sa;
+ ScrArea *area;
SpaceLink *sl;
/* add regions */
- for (sa = screen->areabase.first; sa; sa = sa->next) {
- for (sl = sa->spacedata.first; sl; sl = sl->next) {
+ for (area = screen->areabase.first; area; area = area->next) {
+ for (sl = area->spacedata.first; sl; sl = sl->next) {
if (sl->spacetype == SPACE_VIEW3D) {
View3D *v3d = (View3D *)sl;
if (v3d->gpd) {
@@ -514,7 +515,7 @@ static void do_version_mdef_250(Main *main)
mmd->bindcagecos = mmd->bindcos;
mmd->bindcos = NULL;
- modifier_mdef_compact_influences(md);
+ BKE_modifier_mdef_compact_influences(md);
}
}
}
@@ -871,7 +872,7 @@ void blo_do_versions_250(FileData *fd, Library *lib, Main *bmain)
for (ob = bmain->objects.first; ob; ob = ob->id.next) {
/* fluid-sim stuff */
- FluidsimModifierData *fluidmd = (FluidsimModifierData *)modifiers_findByType(
+ FluidsimModifierData *fluidmd = (FluidsimModifierData *)BKE_modifiers_findby_type(
ob, eModifierType_Fluidsim);
if (fluidmd) {
fluidmd->fss->fmd = fluidmd;
@@ -918,8 +919,8 @@ void blo_do_versions_250(FileData *fd, Library *lib, Main *bmain)
if (do_gravity) {
for (md = ob->modifiers.first; md; md = md->next) {
- ClothModifierData *clmd = (ClothModifierData *)modifiers_findByType(ob,
- eModifierType_Cloth);
+ ClothModifierData *clmd = (ClothModifierData *)BKE_modifiers_findby_type(
+ ob, eModifierType_Cloth);
if (clmd) {
clmd->sim_parms->effector_weights->global_gravity = clmd->sim_parms->gravity[2] /
-9.81f;
@@ -1079,12 +1080,12 @@ void blo_do_versions_250(FileData *fd, Library *lib, Main *bmain)
{
bScreen *screen;
- ScrArea *sa;
+ ScrArea *area;
SpaceLink *sl;
for (screen = bmain->screens.first; screen; screen = screen->id.next) {
- for (sa = screen->areabase.first; sa; sa = sa->next) {
- for (sl = sa->spacedata.first; sl; sl = sl->next) {
+ for (area = screen->areabase.first; area; area = area->next) {
+ for (sl = area->spacedata.first; sl; sl = sl->next) {
if (sl->spacetype == SPACE_VIEW3D) {
View3D *v3d = (View3D *)sl;
if (v3d->drawtype == OB_MATERIAL) {
@@ -1154,7 +1155,7 @@ void blo_do_versions_250(FileData *fd, Library *lib, Main *bmain)
}
for (ob = bmain->objects.first; ob; ob = ob->id.next) {
- MultiresModifierData *mmd = (MultiresModifierData *)modifiers_findByType(
+ MultiresModifierData *mmd = (MultiresModifierData *)BKE_modifiers_findby_type(
ob, eModifierType_Multires);
if (mmd) {
@@ -1188,19 +1189,19 @@ void blo_do_versions_250(FileData *fd, Library *lib, Main *bmain)
if (bmain->versionfile == 250 && bmain->subversionfile == 10) {
/* fix for new view type in sequencer */
bScreen *screen;
- ScrArea *sa;
+ ScrArea *area;
SpaceLink *sl;
/* remove all preview window in wrong spaces */
for (screen = bmain->screens.first; screen; screen = screen->id.next) {
- for (sa = screen->areabase.first; sa; sa = sa->next) {
- for (sl = sa->spacedata.first; sl; sl = sl->next) {
+ for (area = screen->areabase.first; area; area = area->next) {
+ for (sl = area->spacedata.first; sl; sl = sl->next) {
if (sl->spacetype != SPACE_SEQ) {
ARegion *region;
ListBase *regionbase;
- if (sl == sa->spacedata.first) {
- regionbase = &sa->regionbase;
+ if (sl == area->spacedata.first) {
+ regionbase = &area->regionbase;
}
else {
regionbase = &sl->regionbase;
@@ -1227,20 +1228,20 @@ void blo_do_versions_250(FileData *fd, Library *lib, Main *bmain)
{
/* fix for new view type in sequencer */
bScreen *screen;
- ScrArea *sa;
+ ScrArea *area;
SpaceLink *sl;
for (screen = bmain->screens.first; screen; screen = screen->id.next) {
- for (sa = screen->areabase.first; sa; sa = sa->next) {
- for (sl = sa->spacedata.first; sl; sl = sl->next) {
+ for (area = screen->areabase.first; area; area = area->next) {
+ for (sl = area->spacedata.first; sl; sl = sl->next) {
if (sl->spacetype == SPACE_SEQ) {
ARegion *region;
- ARegion *ar_main;
+ ARegion *region_main;
ListBase *regionbase;
SpaceSeq *sseq = (SpaceSeq *)sl;
- if (sl == sa->spacedata.first) {
- regionbase = &sa->regionbase;
+ if (sl == area->spacedata.first) {
+ regionbase = &area->regionbase;
}
else {
regionbase = &sl->regionbase;
@@ -1253,14 +1254,14 @@ void blo_do_versions_250(FileData *fd, Library *lib, Main *bmain)
sseq->mainb = SEQ_DRAW_IMG_IMBUF;
}
- ar_main = (ARegion *)regionbase->first;
- for (; ar_main; ar_main = ar_main->next) {
- if (ar_main->regiontype == RGN_TYPE_WINDOW) {
+ region_main = (ARegion *)regionbase->first;
+ for (; region_main; region_main = region_main->next) {
+ if (region_main->regiontype == RGN_TYPE_WINDOW) {
break;
}
}
region = MEM_callocN(sizeof(ARegion), "preview area for sequencer");
- BLI_insertlinkbefore(regionbase, ar_main, region);
+ BLI_insertlinkbefore(regionbase, region_main, region);
sequencer_init_preview_region(region);
}
}
@@ -1360,17 +1361,17 @@ void blo_do_versions_250(FileData *fd, Library *lib, Main *bmain)
if (bmain->versionfile < 250 || (bmain->versionfile == 250 && bmain->subversionfile < 14)) {
/* fix for bad View2D extents for Animation Editors */
bScreen *screen;
- ScrArea *sa;
+ ScrArea *area;
SpaceLink *sl;
for (screen = bmain->screens.first; screen; screen = screen->id.next) {
- for (sa = screen->areabase.first; sa; sa = sa->next) {
- for (sl = sa->spacedata.first; sl; sl = sl->next) {
+ for (area = screen->areabase.first; area; area = area->next) {
+ for (sl = area->spacedata.first; sl; sl = sl->next) {
ListBase *regionbase;
ARegion *region;
- if (sl == sa->spacedata.first) {
- regionbase = &sa->regionbase;
+ if (sl == area->spacedata.first) {
+ regionbase = &area->regionbase;
}
else {
regionbase = &sl->regionbase;
@@ -1380,7 +1381,7 @@ void blo_do_versions_250(FileData *fd, Library *lib, Main *bmain)
for (region = (ARegion *)regionbase->first; region; region = region->next) {
if (region->regiontype == RGN_TYPE_WINDOW) {
region->v2d.cur.ymax = region->v2d.tot.ymax = 0.0f;
- region->v2d.cur.ymin = region->v2d.tot.ymin = (float)(-sa->winy) / 3.0f;
+ region->v2d.cur.ymin = region->v2d.tot.ymin = (float)(-area->winy) / 3.0f;
}
}
}
@@ -1426,31 +1427,31 @@ void blo_do_versions_250(FileData *fd, Library *lib, Main *bmain)
/* sequencer changes */
{
bScreen *screen;
- ScrArea *sa;
+ ScrArea *area;
SpaceLink *sl;
for (screen = bmain->screens.first; screen; screen = screen->id.next) {
- for (sa = screen->areabase.first; sa; sa = sa->next) {
- for (sl = sa->spacedata.first; sl; sl = sl->next) {
+ for (area = screen->areabase.first; area; area = area->next) {
+ for (sl = area->spacedata.first; sl; sl = sl->next) {
if (sl->spacetype == SPACE_SEQ) {
- ARegion *ar_preview;
+ ARegion *region_preview;
ListBase *regionbase;
- if (sl == sa->spacedata.first) {
- regionbase = &sa->regionbase;
+ if (sl == area->spacedata.first) {
+ regionbase = &area->regionbase;
}
else {
regionbase = &sl->regionbase;
}
- ar_preview = (ARegion *)regionbase->first;
- for (; ar_preview; ar_preview = ar_preview->next) {
- if (ar_preview->regiontype == RGN_TYPE_PREVIEW) {
+ region_preview = (ARegion *)regionbase->first;
+ for (; region_preview; region_preview = region_preview->next) {
+ if (region_preview->regiontype == RGN_TYPE_PREVIEW) {
break;
}
}
- if (ar_preview && (ar_preview->regiontype == RGN_TYPE_PREVIEW)) {
- sequencer_init_preview_region(ar_preview);
+ if (region_preview && (region_preview->regiontype == RGN_TYPE_PREVIEW)) {
+ sequencer_init_preview_region(region_preview);
}
}
}
@@ -1460,17 +1461,17 @@ void blo_do_versions_250(FileData *fd, Library *lib, Main *bmain)
}
if (bmain->versionfile <= 251) { /* 2.5.1 had no subversions */
- bScreen *sc;
+ bScreen *screen;
/* Blender 2.5.2 - subversion 0 introduced a new setting: V3D_HIDE_OVERLAYS.
* This bit was used in the past for V3D_TRANSFORM_SNAP, which is now deprecated.
* Here we clear it for old files so they don't come in with V3D_HIDE_OVERLAYS set,
* which would cause cameras, lights, etc to become invisible */
- for (sc = bmain->screens.first; sc; sc = sc->id.next) {
- ScrArea *sa;
- for (sa = sc->areabase.first; sa; sa = sa->next) {
+ for (screen = bmain->screens.first; screen; screen = screen->id.next) {
+ ScrArea *area;
+ for (area = screen->areabase.first; area; area = area->next) {
SpaceLink *sl;
- for (sl = sa->spacedata.first; sl; sl = sl->next) {
+ for (sl = area->spacedata.first; sl; sl = sl->next) {
if (sl->spacetype == SPACE_VIEW3D) {
View3D *v3d = (View3D *)sl;
v3d->flag2 &= ~V3D_HIDE_OVERLAYS;
@@ -1547,16 +1548,16 @@ void blo_do_versions_250(FileData *fd, Library *lib, Main *bmain)
}
if (bmain->versionfile < 252 || (bmain->versionfile == 252 && bmain->subversionfile < 5)) {
- bScreen *sc;
+ bScreen *screen;
/* Image editor scopes */
- for (sc = bmain->screens.first; sc; sc = sc->id.next) {
- ScrArea *sa;
+ for (screen = bmain->screens.first; screen; screen = screen->id.next) {
+ ScrArea *area;
- for (sa = sc->areabase.first; sa; sa = sa->next) {
+ for (area = screen->areabase.first; area; area = area->next) {
SpaceLink *sl;
- for (sl = sa->spacedata.first; sl; sl = sl->next) {
+ for (sl = area->spacedata.first; sl; sl = sl->next) {
if (sl->spacetype == SPACE_IMAGE) {
SpaceImage *sima = (SpaceImage *)sl;
BKE_scopes_new(&sima->scopes);
@@ -1569,23 +1570,23 @@ void blo_do_versions_250(FileData *fd, Library *lib, Main *bmain)
if (bmain->versionfile < 253) {
Object *ob;
Scene *scene;
- bScreen *sc;
+ bScreen *screen;
Tex *tex;
Brush *brush;
- for (sc = bmain->screens.first; sc; sc = sc->id.next) {
- ScrArea *sa;
- for (sa = sc->areabase.first; sa; sa = sa->next) {
+ for (screen = bmain->screens.first; screen; screen = screen->id.next) {
+ ScrArea *area;
+ for (area = screen->areabase.first; area; area = area->next) {
SpaceLink *sl;
- for (sl = sa->spacedata.first; sl; sl = sl->next) {
+ for (sl = area->spacedata.first; sl; sl = sl->next) {
if (sl->spacetype == SPACE_NODE) {
SpaceNode *snode = (SpaceNode *)sl;
ListBase *regionbase;
ARegion *region;
- if (sl == sa->spacedata.first) {
- regionbase = &sa->regionbase;
+ if (sl == area->spacedata.first) {
+ regionbase = &area->regionbase;
}
else {
regionbase = &sl->regionbase;
@@ -1625,7 +1626,7 @@ void blo_do_versions_250(FileData *fd, Library *lib, Main *bmain)
ArmatureModifierData *amd;
bArmature *arm = (bArmature *)blo_do_versions_newlibadr(fd, lib, parent->data);
- amd = (ArmatureModifierData *)modifier_new(eModifierType_Armature);
+ amd = (ArmatureModifierData *)BKE_modifier_new(eModifierType_Armature);
amd->object = ob->parent;
BLI_addtail((ListBase *)&ob->modifiers, amd);
amd->deformflag = arm->deformflag;
@@ -1634,7 +1635,7 @@ void blo_do_versions_250(FileData *fd, Library *lib, Main *bmain)
else if (parent->type == OB_LATTICE && ob->partype == PARSKEL) {
LatticeModifierData *lmd;
- lmd = (LatticeModifierData *)modifier_new(eModifierType_Lattice);
+ lmd = (LatticeModifierData *)BKE_modifier_new(eModifierType_Lattice);
lmd->object = ob->parent;
BLI_addtail((ListBase *)&ob->modifiers, lmd);
ob->partype = PAROBJECT;
@@ -1642,7 +1643,7 @@ void blo_do_versions_250(FileData *fd, Library *lib, Main *bmain)
else if (parent->type == OB_CURVE && ob->partype == PARCURVE) {
CurveModifierData *cmd;
- cmd = (CurveModifierData *)modifier_new(eModifierType_Curve);
+ cmd = (CurveModifierData *)BKE_modifier_new(eModifierType_Curve);
cmd->object = ob->parent;
BLI_addtail((ListBase *)&ob->modifiers, cmd);
ob->partype = PAROBJECT;
@@ -1833,7 +1834,7 @@ void blo_do_versions_250(FileData *fd, Library *lib, Main *bmain)
if (bmain->versionfile < 255 || (bmain->versionfile == 255 && bmain->subversionfile < 1)) {
Brush *br;
ParticleSettings *part;
- bScreen *sc;
+ bScreen *screen;
for (br = bmain->brushes.first; br; br = br->id.next) {
if (br->ob_mode == 0) {
@@ -1850,18 +1851,18 @@ void blo_do_versions_250(FileData *fd, Library *lib, Main *bmain)
part->kink_amp_clump = 1.f; /* keep old files looking similar */
}
- for (sc = bmain->screens.first; sc; sc = sc->id.next) {
- ScrArea *sa;
- for (sa = sc->areabase.first; sa; sa = sa->next) {
+ for (screen = bmain->screens.first; screen; screen = screen->id.next) {
+ ScrArea *area;
+ for (area = screen->areabase.first; area; area = area->next) {
SpaceLink *sl;
- for (sl = sa->spacedata.first; sl; sl = sl->next) {
+ for (sl = area->spacedata.first; sl; sl = sl->next) {
if (sl->spacetype == SPACE_INFO) {
SpaceInfo *sinfo = (SpaceInfo *)sl;
ARegion *region;
sinfo->rpt_mask = INFO_RPT_OP;
- for (region = sa->regionbase.first; region; region = region->next) {
+ for (region = area->regionbase.first; region; region = region->next) {
if (region->regiontype == RGN_TYPE_WINDOW) {
region->v2d.scroll = (V2D_SCROLL_RIGHT);
region->v2d.align = V2D_ALIGN_NO_NEG_X |
@@ -1896,16 +1897,16 @@ void blo_do_versions_250(FileData *fd, Library *lib, Main *bmain)
}
if (bmain->versionfile < 256) {
- bScreen *sc;
- ScrArea *sa;
+ bScreen *screen;
+ ScrArea *area;
Key *key;
/* Fix for sample line scope initializing with no height */
- for (sc = bmain->screens.first; sc; sc = sc->id.next) {
- sa = sc->areabase.first;
- while (sa) {
+ for (screen = bmain->screens.first; screen; screen = screen->id.next) {
+ area = screen->areabase.first;
+ while (area) {
SpaceLink *sl;
- for (sl = sa->spacedata.first; sl; sl = sl->next) {
+ for (sl = area->spacedata.first; sl; sl = sl->next) {
if (sl->spacetype == SPACE_IMAGE) {
SpaceImage *sima = (SpaceImage *)sl;
if (sima->sample_line_hist.height == 0) {
@@ -1913,7 +1914,7 @@ void blo_do_versions_250(FileData *fd, Library *lib, Main *bmain)
}
}
}
- sa = sa->next;
+ area = area->next;
}
}
@@ -2040,18 +2041,18 @@ void blo_do_versions_250(FileData *fd, Library *lib, Main *bmain)
}
if (bmain->versionfile < 256 || (bmain->versionfile == 256 && bmain->subversionfile < 3)) {
- bScreen *sc;
+ bScreen *screen;
Brush *brush;
Object *ob;
ParticleSettings *part;
/* redraws flag in SpaceTime has been moved to Screen level */
- for (sc = bmain->screens.first; sc; sc = sc->id.next) {
- if (sc->redraws_flag == 0) {
+ for (screen = bmain->screens.first; screen; screen = screen->id.next) {
+ if (screen->redraws_flag == 0) {
/* just initialize to default? */
/* XXX: we could also have iterated through areas,
* and taken them from the first timeline available... */
- sc->redraws_flag = TIME_ALL_3D_WIN | TIME_ALL_ANIM_WIN;
+ screen->redraws_flag = TIME_ALL_3D_WIN | TIME_ALL_ANIM_WIN;
}
}
@@ -2117,13 +2118,13 @@ void blo_do_versions_250(FileData *fd, Library *lib, Main *bmain)
bScreen *screen;
for (screen = bmain->screens.first; screen; screen = screen->id.next) {
- ScrArea *sa;
+ ScrArea *area;
/* add regions */
- for (sa = screen->areabase.first; sa; sa = sa->next) {
- SpaceLink *sl = sa->spacedata.first;
+ for (area = screen->areabase.first; area; area = area->next) {
+ SpaceLink *sl = area->spacedata.first;
if (sl->spacetype == SPACE_IMAGE) {
ARegion *region;
- for (region = sa->regionbase.first; region; region = region->next) {
+ for (region = area->regionbase.first; region; region = region->next) {
if (region->regiontype == RGN_TYPE_WINDOW) {
View2D *v2d = &region->v2d;
v2d->minzoom = v2d->maxzoom = v2d->scroll = v2d->keeptot = v2d->keepzoom =
@@ -2132,7 +2133,7 @@ void blo_do_versions_250(FileData *fd, Library *lib, Main *bmain)
}
}
- for (sl = sa->spacedata.first; sl; sl = sl->next) {
+ for (sl = area->spacedata.first; sl; sl = sl->next) {
if (sl->spacetype == SPACE_IMAGE) {
ARegion *region;
for (region = sl->regionbase.first; region; region = region->next) {
@@ -2174,14 +2175,14 @@ void blo_do_versions_250(FileData *fd, Library *lib, Main *bmain)
{
bScreen *screen;
for (screen = bmain->screens.first; screen; screen = screen->id.next) {
- ScrArea *sa;
+ ScrArea *area;
/* add regions */
- for (sa = screen->areabase.first; sa; sa = sa->next) {
- SpaceLink *sl = sa->spacedata.first;
+ for (area = screen->areabase.first; area; area = area->next) {
+ SpaceLink *sl = area->spacedata.first;
if (sl->spacetype == SPACE_SEQ) {
ARegion *region;
- for (region = sa->regionbase.first; region; region = region->next) {
+ for (region = area->regionbase.first; region; region = region->next) {
if (region->regiontype == RGN_TYPE_WINDOW) {
if (region->v2d.min[1] == 4.0f) {
region->v2d.min[1] = 0.5f;
@@ -2189,7 +2190,7 @@ void blo_do_versions_250(FileData *fd, Library *lib, Main *bmain)
}
}
}
- for (sl = sa->spacedata.first; sl; sl = sl->next) {
+ for (sl = area->spacedata.first; sl; sl = sl->next) {
if (sl->spacetype == SPACE_SEQ) {
ARegion *region;
for (region = sl->regionbase.first; region; region = region->next) {
@@ -2352,4 +2353,32 @@ void do_versions_after_linking_250(Main *bmain)
}
FOREACH_NODETREE_END;
}
+
+ if (!MAIN_VERSION_ATLEAST(bmain, 258, 0)) {
+ /* Some very old (original comments claim pre-2.57) versioning that was wrongly done in
+ * lib-linking code... Putting it here just to be sure (this is also checked at runtime anyway
+ * by `action_idcode_patch_check`). */
+ ID *id;
+ FOREACH_MAIN_ID_BEGIN (bmain, id) {
+ AnimData *adt = BKE_animdata_from_id(id);
+ if (adt != NULL) {
+ /* Fix actions' id-roots (i.e. if they come from a pre 2.57 .blend file). */
+ if ((adt->action) && (adt->action->idroot == 0)) {
+ adt->action->idroot = GS(id->name);
+ }
+ if ((adt->tmpact) && (adt->tmpact->idroot == 0)) {
+ adt->tmpact->idroot = GS(id->name);
+ }
+
+ LISTBASE_FOREACH (NlaTrack *, nla_track, &adt->nla_tracks) {
+ LISTBASE_FOREACH (NlaStrip *, nla_strip, &nla_track->strips) {
+ if ((nla_strip->act) && (nla_strip->act->idroot == 0)) {
+ nla_strip->act->idroot = GS(id->name);
+ }
+ }
+ }
+ }
+ }
+ FOREACH_MAIN_ID_END;
+ }
}
diff --git a/source/blender/blenloader/intern/versioning_260.c b/source/blender/blenloader/intern/versioning_260.c
index 26de003dc17..98e10bef470 100644
--- a/source/blender/blenloader/intern/versioning_260.c
+++ b/source/blender/blenloader/intern/versioning_260.c
@@ -52,7 +52,7 @@
#include "BLT_translation.h"
-#include "BKE_anim.h"
+#include "BKE_anim_visualization.h"
#include "BKE_image.h"
#include "BKE_main.h" // for Main
#include "BKE_mesh.h" // for ME_ defines (patching)
@@ -765,14 +765,14 @@ void blo_do_versions_260(FileData *fd, Library *UNUSED(lib), Main *bmain)
{
/* Tomato compatibility code. */
- bScreen *sc;
+ bScreen *screen;
MovieClip *clip;
- for (sc = bmain->screens.first; sc; sc = sc->id.next) {
- ScrArea *sa;
- for (sa = sc->areabase.first; sa; sa = sa->next) {
+ for (screen = bmain->screens.first; screen; screen = screen->id.next) {
+ ScrArea *area;
+ for (area = screen->areabase.first; area; area = area->next) {
SpaceLink *sl;
- for (sl = sa->spacedata.first; sl; sl = sl->next) {
+ for (sl = area->spacedata.first; sl; sl = sl->next) {
if (sl->spacetype == SPACE_VIEW3D) {
View3D *v3d = (View3D *)sl;
if (v3d->bundle_size == 0.0f) {
@@ -1188,20 +1188,20 @@ void blo_do_versions_260(FileData *fd, Library *UNUSED(lib), Main *bmain)
}
if (bmain->versionfile < 263 || (bmain->versionfile == 263 && bmain->subversionfile < 2)) {
- bScreen *sc;
+ bScreen *screen;
- for (sc = bmain->screens.first; sc; sc = sc->id.next) {
- ScrArea *sa;
- for (sa = sc->areabase.first; sa; sa = sa->next) {
+ for (screen = bmain->screens.first; screen; screen = screen->id.next) {
+ ScrArea *area;
+ for (area = screen->areabase.first; area; area = area->next) {
SpaceLink *sl;
- for (sl = sa->spacedata.first; sl; sl = sl->next) {
+ for (sl = area->spacedata.first; sl; sl = sl->next) {
if (sl->spacetype == SPACE_CLIP) {
SpaceClip *sclip = (SpaceClip *)sl;
ARegion *region;
bool hide = false;
- for (region = sa->regionbase.first; region; region = region->next) {
+ for (region = area->regionbase.first; region; region = region->next) {
if (region->regiontype == RGN_TYPE_PREVIEW) {
if (region->alignment != RGN_ALIGN_NONE) {
region->flag |= RGN_FLAG_HIDDEN;
@@ -1368,15 +1368,15 @@ void blo_do_versions_260(FileData *fd, Library *UNUSED(lib), Main *bmain)
}
{
- bScreen *sc;
+ bScreen *screen;
- for (sc = bmain->screens.first; sc; sc = sc->id.next) {
- ScrArea *sa;
+ for (screen = bmain->screens.first; screen; screen = screen->id.next) {
+ ScrArea *area;
- for (sa = sc->areabase.first; sa; sa = sa->next) {
+ for (area = screen->areabase.first; area; area = area->next) {
SpaceLink *sl;
- for (sl = sa->spacedata.first; sl; sl = sl->next) {
+ for (sl = area->spacedata.first; sl; sl = sl->next) {
if (sl->spacetype == SPACE_CLIP) {
SpaceClip *sclip = (SpaceClip *)sl;
@@ -1661,13 +1661,13 @@ void blo_do_versions_260(FileData *fd, Library *UNUSED(lib), Main *bmain)
/* render border for viewport */
{
- bScreen *sc;
+ bScreen *screen;
- for (sc = bmain->screens.first; sc; sc = sc->id.next) {
- ScrArea *sa;
- for (sa = sc->areabase.first; sa; sa = sa->next) {
+ for (screen = bmain->screens.first; screen; screen = screen->id.next) {
+ ScrArea *area;
+ for (area = screen->areabase.first; area; area = area->next) {
SpaceLink *sl;
- for (sl = sa->spacedata.first; sl; sl = sl->next) {
+ for (sl = area->spacedata.first; sl; sl = sl->next) {
if (sl->spacetype == SPACE_VIEW3D) {
View3D *v3d = (View3D *)sl;
if (v3d->render_border.xmin == 0.0f && v3d->render_border.ymin == 0.0f &&
@@ -1758,12 +1758,12 @@ void blo_do_versions_260(FileData *fd, Library *UNUSED(lib), Main *bmain)
}
if (bmain->versionfile < 265 || (bmain->versionfile == 265 && bmain->subversionfile < 3)) {
- bScreen *sc;
- for (sc = bmain->screens.first; sc; sc = sc->id.next) {
- ScrArea *sa;
- for (sa = sc->areabase.first; sa; sa = sa->next) {
+ bScreen *screen;
+ for (screen = bmain->screens.first; screen; screen = screen->id.next) {
+ ScrArea *area;
+ for (area = screen->areabase.first; area; area = area->next) {
SpaceLink *sl;
- for (sl = sa->spacedata.first; sl; sl = sl->next) {
+ for (sl = area->spacedata.first; sl; sl = sl->next) {
switch (sl->spacetype) {
case SPACE_VIEW3D: {
View3D *v3d = (View3D *)sl;
@@ -1943,12 +1943,12 @@ void blo_do_versions_260(FileData *fd, Library *UNUSED(lib), Main *bmain)
}
if (MAIN_VERSION_OLDER(bmain, 266, 2)) {
- bScreen *sc;
- for (sc = bmain->screens.first; sc; sc = sc->id.next) {
- ScrArea *sa;
- for (sa = sc->areabase.first; sa; sa = sa->next) {
+ bScreen *screen;
+ for (screen = bmain->screens.first; screen; screen = screen->id.next) {
+ ScrArea *area;
+ for (area = screen->areabase.first; area; area = area->next) {
SpaceLink *sl;
- for (sl = sa->spacedata.first; sl; sl = sl->next) {
+ for (sl = area->spacedata.first; sl; sl = sl->next) {
if (sl->spacetype == SPACE_NODE) {
SpaceNode *snode = (SpaceNode *)sl;
@@ -2119,10 +2119,10 @@ void blo_do_versions_260(FileData *fd, Library *UNUSED(lib), Main *bmain)
bNodeInstanceKey active_viewer_key = {0};
/* simply pick the first node space and use that for the active viewer key */
for (screen = bmain->screens.first; screen; screen = screen->id.next) {
- ScrArea *sa;
- for (sa = screen->areabase.first; sa; sa = sa->next) {
+ ScrArea *area;
+ for (area = screen->areabase.first; area; area = area->next) {
SpaceLink *sl;
- for (sl = sa->spacedata.first; sl; sl = sl->next) {
+ for (sl = area->spacedata.first; sl; sl = sl->next) {
if (sl->spacetype == SPACE_NODE) {
SpaceNode *snode = (SpaceNode *)sl;
bNodeTreePath *path = snode->treepath.last;
@@ -2199,7 +2199,7 @@ void blo_do_versions_260(FileData *fd, Library *UNUSED(lib), Main *bmain)
}
if (!MAIN_VERSION_ATLEAST(bmain, 268, 4)) {
- bScreen *sc;
+ bScreen *screen;
Object *ob;
for (ob = bmain->objects.first; ob; ob = ob->id.next) {
@@ -2240,11 +2240,11 @@ void blo_do_versions_260(FileData *fd, Library *UNUSED(lib), Main *bmain)
*
* We moved this check to the do versions to be sure the value makes any sense.
*/
- for (sc = bmain->screens.first; sc; sc = sc->id.next) {
- ScrArea *sa;
- for (sa = sc->areabase.first; sa; sa = sa->next) {
+ for (screen = bmain->screens.first; screen; screen = screen->id.next) {
+ ScrArea *area;
+ for (area = screen->areabase.first; area; area = area->next) {
SpaceLink *sl;
- for (sl = sa->spacedata.first; sl; sl = sl->next) {
+ for (sl = area->spacedata.first; sl; sl = sl->next) {
if (sl->spacetype == SPACE_NODE) {
SpaceNode *snode = (SpaceNode *)sl;
if (snode->zoom < 0.02f) {
@@ -2257,23 +2257,23 @@ void blo_do_versions_260(FileData *fd, Library *UNUSED(lib), Main *bmain)
}
if (!MAIN_VERSION_ATLEAST(bmain, 268, 5)) {
- bScreen *sc;
- ScrArea *sa;
+ bScreen *screen;
+ ScrArea *area;
/* add missing (+) expander in node editor */
- for (sc = bmain->screens.first; sc; sc = sc->id.next) {
- for (sa = sc->areabase.first; sa; sa = sa->next) {
+ for (screen = bmain->screens.first; screen; screen = screen->id.next) {
+ for (area = screen->areabase.first; area; area = area->next) {
ARegion *region, *arnew;
- if (sa->spacetype == SPACE_NODE) {
- region = BKE_area_find_region_type(sa, RGN_TYPE_TOOLS);
+ if (area->spacetype == SPACE_NODE) {
+ region = BKE_area_find_region_type(area, RGN_TYPE_TOOLS);
if (region) {
continue;
}
/* add subdiv level; after header */
- region = BKE_area_find_region_type(sa, RGN_TYPE_HEADER);
+ region = BKE_area_find_region_type(area, RGN_TYPE_HEADER);
/* is error! */
if (region == NULL) {
@@ -2282,7 +2282,7 @@ void blo_do_versions_260(FileData *fd, Library *UNUSED(lib), Main *bmain)
arnew = MEM_callocN(sizeof(ARegion), "node tools");
- BLI_insertlinkafter(&sa->regionbase, region, arnew);
+ BLI_insertlinkafter(&area->regionbase, region, arnew);
arnew->regiontype = RGN_TYPE_TOOLS;
arnew->alignment = RGN_ALIGN_LEFT;
@@ -2338,15 +2338,15 @@ void blo_do_versions_260(FileData *fd, Library *UNUSED(lib), Main *bmain)
}
if (!MAIN_VERSION_ATLEAST(bmain, 269, 3)) {
- bScreen *sc;
- ScrArea *sa;
+ bScreen *screen;
+ ScrArea *area;
SpaceLink *sl;
Scene *scene;
/* Update files using invalid (outdated) outlinevis Outliner values. */
- for (sc = bmain->screens.first; sc; sc = sc->id.next) {
- for (sa = sc->areabase.first; sa; sa = sa->next) {
- for (sl = sa->spacedata.first; sl; sl = sl->next) {
+ for (screen = bmain->screens.first; screen; screen = screen->id.next) {
+ for (area = screen->areabase.first; area; area = area->next) {
+ for (sl = area->spacedata.first; sl; sl = sl->next) {
if (sl->spacetype == SPACE_OUTLINER) {
SpaceOutliner *so = (SpaceOutliner *)sl;
@@ -2542,20 +2542,20 @@ void blo_do_versions_260(FileData *fd, Library *UNUSED(lib), Main *bmain)
}
if (!MAIN_VERSION_ATLEAST(bmain, 269, 11)) {
- bScreen *sc;
+ bScreen *screen;
- for (sc = bmain->screens.first; sc; sc = sc->id.next) {
- ScrArea *sa;
- for (sa = sc->areabase.first; sa; sa = sa->next) {
+ for (screen = bmain->screens.first; screen; screen = screen->id.next) {
+ ScrArea *area;
+ for (area = screen->areabase.first; area; area = area->next) {
SpaceLink *space_link;
- for (space_link = sa->spacedata.first; space_link; space_link = space_link->next) {
+ for (space_link = area->spacedata.first; space_link; space_link = space_link->next) {
if (space_link->spacetype == SPACE_IMAGE) {
ARegion *region;
ListBase *lb;
- if (space_link == sa->spacedata.first) {
- lb = &sa->regionbase;
+ if (space_link == area->spacedata.first) {
+ lb = &area->regionbase;
}
else {
lb = &space_link->regionbase;
diff --git a/source/blender/blenloader/intern/versioning_270.c b/source/blender/blenloader/intern/versioning_270.c
index 80f75a7ac4a..0ca6fd34535 100644
--- a/source/blender/blenloader/intern/versioning_270.c
+++ b/source/blender/blenloader/intern/versioning_270.c
@@ -52,9 +52,10 @@
#include "DNA_genfile.h"
+#include "BKE_anim_data.h"
#include "BKE_animsys.h"
#include "BKE_colortools.h"
-#include "BKE_fcurve.h"
+#include "BKE_fcurve_driver.h"
#include "BKE_main.h"
#include "BKE_mask.h"
#include "BKE_modifier.h"
@@ -257,7 +258,7 @@ static void do_version_action_editor_properties_region(ListBase *regionbase)
static void do_version_bones_super_bbone(ListBase *lb)
{
- for (Bone *bone = lb->first; bone; bone = bone->next) {
+ LISTBASE_FOREACH (Bone *, bone, lb) {
bone->scale_in_x = bone->scale_in_y = 1.0f;
bone->scale_out_x = bone->scale_out_y = 1.0f;
@@ -342,7 +343,7 @@ static void do_versions_compositor_render_passes_storage(bNode *node)
static void do_versions_compositor_render_passes(bNodeTree *ntree)
{
- for (bNode *node = ntree->nodes.first; node; node = node->next) {
+ LISTBASE_FOREACH (bNode *, node, &ntree->nodes) {
if (node->type == CMP_NODE_R_LAYERS) {
/* First we make sure existing sockets have proper names.
* This is important because otherwise verification will
@@ -391,7 +392,7 @@ static void do_version_bbone_easing_fcurve_fix(ID *UNUSED(id),
/* Driver -> Driver Vars (for bbone_in/out) */
if (fcu->driver) {
- for (DriverVar *dvar = fcu->driver->variables.first; dvar; dvar = dvar->next) {
+ LISTBASE_FOREACH (DriverVar *, dvar, &fcu->driver->variables) {
DRIVER_TARGETS_LOOPER_BEGIN (dvar) {
if (dtar->rna_path) {
dtar->rna_path = replace_bbone_easing_rnapath(dtar->rna_path);
@@ -403,7 +404,7 @@ static void do_version_bbone_easing_fcurve_fix(ID *UNUSED(id),
/* FModifiers -> Stepped (for frame_start/end) */
if (fcu->modifiers.first) {
- for (FModifier *fcm = fcu->modifiers.first; fcm; fcm = fcm->next) {
+ LISTBASE_FOREACH (FModifier *, fcm, &fcu->modifiers) {
if (fcm->type == FMODIFIER_TYPE_STEPPED) {
FMod_Stepped *data = fcm->data;
@@ -519,16 +520,16 @@ void blo_do_versions_270(FileData *fd, Library *UNUSED(lib), Main *bmain)
* leading to corrupted files (see T39847).
* This will always reset situation to a valid state.
*/
- bScreen *sc;
+ bScreen *screen;
- for (sc = bmain->screens.first; sc; sc = sc->id.next) {
- ScrArea *sa;
- for (sa = sc->areabase.first; sa; sa = sa->next) {
+ for (screen = bmain->screens.first; screen; screen = screen->id.next) {
+ ScrArea *area;
+ for (area = screen->areabase.first; area; area = area->next) {
SpaceLink *sl;
- for (sl = sa->spacedata.first; sl; sl = sl->next) {
+ for (sl = area->spacedata.first; sl; sl = sl->next) {
ARegion *region;
- ListBase *lb = (sl == sa->spacedata.first) ? &sa->regionbase : &sl->regionbase;
+ ListBase *lb = (sl == area->spacedata.first) ? &area->regionbase : &sl->regionbase;
for (region = lb->first; region; region = region->next) {
BLI_listbase_clear(&region->ui_previews);
@@ -840,7 +841,7 @@ void blo_do_versions_270(FileData *fd, Library *UNUSED(lib), Main *bmain)
for (ob = bmain->objects.first; ob != NULL; ob = ob->id.next) {
ModifierData *md;
for (md = ob->modifiers.last; md != NULL; md = md->prev) {
- if (modifier_unique_name(&ob->modifiers, md)) {
+ if (BKE_modifier_unique_name(&ob->modifiers, md)) {
printf(
"Warning: Object '%s' had several modifiers with the "
"same name, renamed one of them to '%s'.\n",
@@ -852,15 +853,15 @@ void blo_do_versions_270(FileData *fd, Library *UNUSED(lib), Main *bmain)
}
if (!MAIN_VERSION_ATLEAST(bmain, 273, 9)) {
- bScreen *scr;
- ScrArea *sa;
+ bScreen *screen;
+ ScrArea *area;
SpaceLink *sl;
ARegion *region;
/* Make sure sequencer preview area limits zoom */
- for (scr = bmain->screens.first; scr; scr = scr->id.next) {
- for (sa = scr->areabase.first; sa; sa = sa->next) {
- for (sl = sa->spacedata.first; sl; sl = sl->next) {
+ for (screen = bmain->screens.first; screen; screen = screen->id.next) {
+ for (area = screen->areabase.first; area; area = area->next) {
+ for (sl = area->spacedata.first; sl; sl = sl->next) {
if (sl->spacetype == SPACE_SEQ) {
for (region = sl->regionbase.first; region; region = region->next) {
if (region->regiontype == RGN_TYPE_PREVIEW) {
@@ -942,11 +943,11 @@ void blo_do_versions_270(FileData *fd, Library *UNUSED(lib), Main *bmain)
}
for (screen = bmain->screens.first; screen; screen = screen->id.next) {
- ScrArea *sa;
- for (sa = screen->areabase.first; sa; sa = sa->next) {
+ ScrArea *area;
+ for (area = screen->areabase.first; area; area = area->next) {
SpaceLink *sl;
- for (sl = sa->spacedata.first; sl; sl = sl->next) {
+ for (sl = area->spacedata.first; sl; sl = sl->next) {
switch (sl->spacetype) {
case SPACE_VIEW3D: {
View3D *v3d = (View3D *)sl;
@@ -996,12 +997,12 @@ void blo_do_versions_270(FileData *fd, Library *UNUSED(lib), Main *bmain)
if (!DNA_struct_elem_find(fd->filesdna, "FileSelectParams", "int", "thumbnail_size")) {
for (screen = bmain->screens.first; screen; screen = screen->id.next) {
- ScrArea *sa;
+ ScrArea *area;
- for (sa = screen->areabase.first; sa; sa = sa->next) {
+ for (area = screen->areabase.first; area; area = area->next) {
SpaceLink *sl;
- for (sl = sa->spacedata.first; sl; sl = sl->next) {
+ for (sl = area->spacedata.first; sl; sl = sl->next) {
if (sl->spacetype == SPACE_FILE) {
SpaceFile *sfile = (SpaceFile *)sl;
@@ -1064,13 +1065,13 @@ void blo_do_versions_270(FileData *fd, Library *UNUSED(lib), Main *bmain)
bScreen *screen;
#define RV3D_VIEW_PERSPORTHO 7
for (screen = bmain->screens.first; screen; screen = screen->id.next) {
- ScrArea *sa;
- for (sa = screen->areabase.first; sa; sa = sa->next) {
+ ScrArea *area;
+ for (area = screen->areabase.first; area; area = area->next) {
SpaceLink *sl;
- for (sl = sa->spacedata.first; sl; sl = sl->next) {
+ for (sl = area->spacedata.first; sl; sl = sl->next) {
if (sl->spacetype == SPACE_VIEW3D) {
ARegion *region;
- ListBase *lb = (sl == sa->spacedata.first) ? &sa->regionbase : &sl->regionbase;
+ ListBase *lb = (sl == area->spacedata.first) ? &area->regionbase : &sl->regionbase;
for (region = lb->first; region; region = region->next) {
if (region->regiontype == RGN_TYPE_WINDOW) {
if (region->regiondata) {
@@ -1152,7 +1153,7 @@ void blo_do_versions_270(FileData *fd, Library *UNUSED(lib), Main *bmain)
* otherwise they could collide with any new persistent flag we may add in the future. */
a = set_listbasepointers(bmain, lbarray);
while (a--) {
- for (ID *id = lbarray[a]->first; id; id = id->next) {
+ LISTBASE_FOREACH (ID *, id, lbarray[a]) {
id->flag &= LIB_FAKEUSER;
}
}
@@ -1176,14 +1177,15 @@ void blo_do_versions_270(FileData *fd, Library *UNUSED(lib), Main *bmain)
}
for (bScreen *screen = bmain->screens.first; screen; screen = screen->id.next) {
- for (ScrArea *sa = screen->areabase.first; sa; sa = sa->next) {
- for (SpaceLink *sl = sa->spacedata.first; sl; sl = sl->next) {
- ListBase *regionbase = (sl == sa->spacedata.first) ? &sa->regionbase : &sl->regionbase;
+ LISTBASE_FOREACH (ScrArea *, area, &screen->areabase) {
+ LISTBASE_FOREACH (SpaceLink *, sl, &area->spacedata) {
+ ListBase *regionbase = (sl == area->spacedata.first) ? &area->regionbase :
+ &sl->regionbase;
/* Bug: Was possible to add preview region to sequencer view by using AZones. */
if (sl->spacetype == SPACE_SEQ) {
SpaceSeq *sseq = (SpaceSeq *)sl;
if (sseq->view == SEQ_VIEW_SEQUENCE) {
- for (ARegion *region = regionbase->first; region; region = region->next) {
+ LISTBASE_FOREACH (ARegion *, region, regionbase) {
/* remove preview region for sequencer-only view! */
if (region->regiontype == RGN_TYPE_PREVIEW) {
region->flag |= RGN_FLAG_HIDDEN;
@@ -1195,7 +1197,7 @@ void blo_do_versions_270(FileData *fd, Library *UNUSED(lib), Main *bmain)
}
/* Remove old deprecated region from filebrowsers */
else if (sl->spacetype == SPACE_FILE) {
- for (ARegion *region = regionbase->first; region; region = region->next) {
+ LISTBASE_FOREACH (ARegion *, region, regionbase) {
if (region->regiontype == RGN_TYPE_CHANNELS) {
/* Free old deprecated 'channel' region... */
BKE_area_region_free(NULL, region);
@@ -1243,9 +1245,9 @@ void blo_do_versions_270(FileData *fd, Library *UNUSED(lib), Main *bmain)
/* Adding "Properties" region to DopeSheet */
for (bScreen *screen = bmain->screens.first; screen; screen = screen->id.next) {
- for (ScrArea *sa = screen->areabase.first; sa; sa = sa->next) {
+ LISTBASE_FOREACH (ScrArea *, area, &screen->areabase) {
/* handle pushed-back space data first */
- for (SpaceLink *sl = sa->spacedata.first; sl; sl = sl->next) {
+ LISTBASE_FOREACH (SpaceLink *, sl, &area->spacedata) {
if (sl->spacetype == SPACE_ACTION) {
SpaceAction *saction = (SpaceAction *)sl;
do_version_action_editor_properties_region(&saction->regionbase);
@@ -1253,8 +1255,8 @@ void blo_do_versions_270(FileData *fd, Library *UNUSED(lib), Main *bmain)
}
/* active spacedata info must be handled too... */
- if (sa->spacetype == SPACE_ACTION) {
- do_version_action_editor_properties_region(&sa->regionbase);
+ if (area->spacetype == SPACE_ACTION) {
+ do_version_action_editor_properties_region(&area->regionbase);
}
}
}
@@ -1269,7 +1271,7 @@ void blo_do_versions_270(FileData *fd, Library *UNUSED(lib), Main *bmain)
if (!DNA_struct_elem_find(fd->filesdna, "bPoseChannel", "float", "scaleIn")) {
for (Object *ob = bmain->objects.first; ob; ob = ob->id.next) {
if (ob->pose) {
- for (bPoseChannel *pchan = ob->pose->chanbase.first; pchan; pchan = pchan->next) {
+ LISTBASE_FOREACH (bPoseChannel *, pchan, &ob->pose->chanbase) {
/* see do_version_bones_super_bbone()... */
pchan->scale_in_x = pchan->scale_in_y = 1.0f;
pchan->scale_out_x = pchan->scale_out_y = 1.0f;
@@ -1559,8 +1561,8 @@ void blo_do_versions_270(FileData *fd, Library *UNUSED(lib), Main *bmain)
if (!MAIN_VERSION_ATLEAST(bmain, 278, 5)) {
/* Mask primitive adding code was not initializing correctly id_type of its points' parent. */
for (Mask *mask = bmain->masks.first; mask; mask = mask->id.next) {
- for (MaskLayer *mlayer = mask->masklayers.first; mlayer; mlayer = mlayer->next) {
- for (MaskSpline *mspline = mlayer->splines.first; mspline; mspline = mspline->next) {
+ LISTBASE_FOREACH (MaskLayer *, mlayer, &mask->masklayers) {
+ LISTBASE_FOREACH (MaskSpline *, mspline, &mlayer->splines) {
int i = 0;
for (MaskSplinePoint *mspoint = mspline->points; i < mspline->tot_point;
mspoint++, i++) {
@@ -1577,7 +1579,7 @@ void blo_do_versions_270(FileData *fd, Library *UNUSED(lib), Main *bmain)
FOREACH_NODETREE_BEGIN (bmain, ntree, id) {
if (ntree->type == NTREE_COMPOSIT) {
ntreeSetTypes(NULL, ntree);
- for (bNode *node = ntree->nodes.first; node; node = node->next) {
+ LISTBASE_FOREACH (bNode *, node, &ntree->nodes) {
if (node->type == CMP_NODE_GLARE) {
NodeGlare *ndg = node->storage;
switch (ndg->type) {
@@ -1599,7 +1601,7 @@ void blo_do_versions_270(FileData *fd, Library *UNUSED(lib), Main *bmain)
if (!DNA_struct_elem_find(fd->filesdna, "SurfaceDeformModifierData", "float", "mat[4][4]")) {
for (Object *ob = bmain->objects.first; ob; ob = ob->id.next) {
- for (ModifierData *md = ob->modifiers.first; md; md = md->next) {
+ LISTBASE_FOREACH (ModifierData *, md, &ob->modifiers) {
if (md->type == eModifierType_SurfaceDeform) {
SurfaceDeformModifierData *smd = (SurfaceDeformModifierData *)md;
unit_m4(smd->mat);
@@ -1649,10 +1651,10 @@ void blo_do_versions_270(FileData *fd, Library *UNUSED(lib), Main *bmain)
if (!MAIN_VERSION_ATLEAST(bmain, 279, 4)) {
/* Fix for invalid state of screen due to bug in older versions. */
- for (bScreen *sc = bmain->screens.first; sc; sc = sc->id.next) {
- for (ScrArea *sa = sc->areabase.first; sa; sa = sa->next) {
- if (sa->full && sc->state == SCREENNORMAL) {
- sa->full = NULL;
+ for (bScreen *screen = bmain->screens.first; screen; screen = screen->id.next) {
+ LISTBASE_FOREACH (ScrArea *, area, &screen->areabase) {
+ if (area->full && screen->state == SCREENNORMAL) {
+ area->full = NULL;
}
}
}
@@ -1681,7 +1683,7 @@ void blo_do_versions_270(FileData *fd, Library *UNUSED(lib), Main *bmain)
* Must set previous defaults. */
if (!DNA_struct_elem_find(fd->filesdna, "SimpleDeformModifierData", "char", "deform_axis")) {
for (Object *ob = bmain->objects.first; ob; ob = ob->id.next) {
- for (ModifierData *md = ob->modifiers.first; md; md = md->next) {
+ LISTBASE_FOREACH (ModifierData *, md, &ob->modifiers) {
if (md->type == eModifierType_SimpleDeform) {
SimpleDeformModifierData *smd = (SimpleDeformModifierData *)md;
smd->deform_axis = 2;
@@ -1710,7 +1712,7 @@ void blo_do_versions_270(FileData *fd, Library *UNUSED(lib), Main *bmain)
if (!DNA_struct_elem_find(
fd->filesdna, "ParticleInstanceModifierData", "float", "particle_amount")) {
for (Object *ob = bmain->objects.first; ob; ob = ob->id.next) {
- for (ModifierData *md = ob->modifiers.first; md; md = md->next) {
+ LISTBASE_FOREACH (ModifierData *, md, &ob->modifiers) {
if (md->type == eModifierType_ParticleInstance) {
ParticleInstanceModifierData *pimd = (ParticleInstanceModifierData *)md;
pimd->space = eParticleInstanceSpace_World;
@@ -1729,7 +1731,7 @@ void do_versions_after_linking_270(Main *bmain)
FOREACH_NODETREE_BEGIN (bmain, ntree, id) {
if (ntree->type == NTREE_COMPOSIT) {
ntreeSetTypes(NULL, ntree);
- for (bNode *node = ntree->nodes.first; node; node = node->next) {
+ LISTBASE_FOREACH (bNode *, node, &ntree->nodes) {
if (node->type == CMP_NODE_HUE_SAT) {
do_version_hue_sat_node(ntree, node);
}
diff --git a/source/blender/blenloader/intern/versioning_280.c b/source/blender/blenloader/intern/versioning_280.c
index eda13dce084..6211c58d7d4 100644
--- a/source/blender/blenloader/intern/versioning_280.c
+++ b/source/blender/blenloader/intern/versioning_280.c
@@ -40,6 +40,7 @@
#include "DNA_constraint_types.h"
#include "DNA_curve_types.h"
#include "DNA_curveprofile_types.h"
+#include "DNA_fluid_types.h"
#include "DNA_freestyle_types.h"
#include "DNA_genfile.h"
#include "DNA_gpencil_modifier_types.h"
@@ -74,6 +75,7 @@
#include "BKE_curveprofile.h"
#include "BKE_customdata.h"
#include "BKE_fcurve.h"
+#include "BKE_fcurve_driver.h"
#include "BKE_freestyle.h"
#include "BKE_global.h"
#include "BKE_gpencil.h"
@@ -111,15 +113,44 @@
/* Make preferences read-only, use versioning_userdef.c. */
#define U (*((const UserDef *)&U))
+/**
+ * Rename if the ID doesn't exist.
+ */
+static ID *rename_id_for_versioning(Main *bmain,
+ const short id_type,
+ const char *name_src,
+ const char *name_dst)
+{
+ /* We can ignore libraries */
+ ListBase *lb = which_libbase(bmain, id_type);
+ ID *id = NULL;
+ LISTBASE_FOREACH (ID *, idtest, lb) {
+ if (idtest->lib == NULL) {
+ if (STREQ(idtest->name + 2, name_src)) {
+ id = idtest;
+ }
+ if (STREQ(idtest->name + 2, name_dst)) {
+ return NULL;
+ }
+ }
+ }
+ if (id != NULL) {
+ BLI_strncpy(id->name + 2, name_dst, sizeof(id->name) - 2);
+ /* We know it's unique, this just sorts. */
+ BLI_libblock_ensure_unique_name(bmain, id->name);
+ }
+ return id;
+}
+
static bScreen *screen_parent_find(const bScreen *screen)
{
/* Can avoid lookup if screen state isn't maximized/full
* (parent and child store the same state). */
if (ELEM(screen->state, SCREENMAXIMIZED, SCREENFULL)) {
- for (const ScrArea *sa = screen->areabase.first; sa; sa = sa->next) {
- if (sa->full && sa->full != screen) {
- BLI_assert(sa->full->state == screen->state);
- return sa->full;
+ LISTBASE_FOREACH (const ScrArea *, area, &screen->areabase) {
+ if (area->full && area->full != screen) {
+ BLI_assert(area->full->state == screen->state);
+ return area->full;
}
}
}
@@ -129,6 +160,8 @@ static bScreen *screen_parent_find(const bScreen *screen)
static void do_version_workspaces_create_from_screens(Main *bmain)
{
+ bmain->is_locked_for_linking = false;
+
for (bScreen *screen = bmain->screens.first; screen; screen = screen->id.next) {
const bScreen *screen_parent = screen_parent_find(screen);
WorkSpace *workspace;
@@ -150,6 +183,8 @@ static void do_version_workspaces_create_from_screens(Main *bmain)
}
BKE_workspace_layout_add(bmain, workspace, screen, screen->id.name + 2);
}
+
+ bmain->is_locked_for_linking = true;
}
static void do_version_area_change_space_to_space_action(ScrArea *area, const Scene *scene)
@@ -159,7 +194,7 @@ static void do_version_area_change_space_to_space_action(ScrArea *area, const Sc
ARegion *region_channels;
/* Properly free current regions */
- for (ARegion *region = area->regionbase.first; region; region = region->next) {
+ LISTBASE_FOREACH (ARegion *, region, &area->regionbase) {
BKE_area_region_free(area->type, region);
}
BLI_freelistN(&area->regionbase);
@@ -199,7 +234,7 @@ static void do_version_workspaces_after_lib_link(Main *bmain)
do_version_workspaces_create_from_screens(bmain);
for (wmWindowManager *wm = bmain->wm.first; wm; wm = wm->id.next) {
- for (wmWindow *win = wm->windows.first; win; win = win->next) {
+ LISTBASE_FOREACH (wmWindow *, win, &wm->windows) {
bScreen *screen_parent = screen_parent_find(win->screen);
bScreen *screen = screen_parent ? screen_parent : win->screen;
@@ -222,7 +257,7 @@ static void do_version_workspaces_after_lib_link(Main *bmain)
win->workspace_hook = BKE_workspace_instance_hook_create(bmain);
BKE_workspace_active_set(win->workspace_hook, workspace);
- BKE_workspace_active_layout_set(win->workspace_hook, layout);
+ BKE_workspace_active_layout_set(win->workspace_hook, workspace, layout);
/* Move scene and view layer to window. */
Scene *scene = screen->scene;
@@ -278,7 +313,7 @@ static void do_version_layer_collection_pre(ViewLayer *view_layer,
GSet *selectable_set)
{
/* Convert from deprecated DISABLED to new layer collection and collection flags */
- for (LayerCollection *lc = lb->first; lc; lc = lc->next) {
+ LISTBASE_FOREACH (LayerCollection *, lc, lb) {
if (lc->scene_collection) {
if (!(lc->flag & COLLECTION_DEPRECATED_DISABLED)) {
BLI_gset_insert(enabled_set, lc->scene_collection);
@@ -300,7 +335,7 @@ static void do_version_layer_collection_post(ViewLayer *view_layer,
GHash *collection_map)
{
/* Apply layer collection exclude flags. */
- for (LayerCollection *lc = lb->first; lc; lc = lc->next) {
+ LISTBASE_FOREACH (LayerCollection *, lc, lb) {
if (!(lc->collection->flag & COLLECTION_IS_MASTER)) {
SceneCollection *sc = BLI_ghash_lookup(collection_map, lc->collection);
const bool enabled = (sc && BLI_gset_haskey(enabled_set, sc));
@@ -334,7 +369,7 @@ static void do_version_scene_collection_convert(
nsc = nsc_next;
}
- for (LinkData *link = sc->objects.first; link; link = link->next) {
+ LISTBASE_FOREACH (LinkData *, link, &sc->objects) {
Object *ob = link->data;
if (ob) {
BKE_collection_object_add(bmain, collection, ob);
@@ -422,7 +457,7 @@ static void do_version_layers_to_collections(Main *bmain, Scene *scene)
Collection *collections[20] = {NULL};
for (int layer = 0; layer < 20; layer++) {
- for (Base *base = scene->base.first; base; base = base->next) {
+ LISTBASE_FOREACH (Base *, base, &scene->base) {
if (base->lay & (1 << layer)) {
/* Create collections when needed only. */
if (collections[layer] == NULL) {
@@ -461,7 +496,7 @@ static void do_version_layers_to_collections(Main *bmain, Scene *scene)
bool have_override = false;
const bool need_default_renderlayer = scene->r.layers.first == NULL;
- for (SceneRenderLayer *srl = scene->r.layers.first; srl; srl = srl->next) {
+ LISTBASE_FOREACH (SceneRenderLayer *, srl, &scene->r.layers) {
ViewLayer *view_layer = BKE_view_layer_add(scene, srl->name, NULL, VIEWLAYER_ADD_NEW);
if (srl->layflag & SCE_LAY_DISABLE) {
@@ -493,7 +528,7 @@ static void do_version_layers_to_collections(Main *bmain, Scene *scene)
/* Disable excluded layer. */
have_override = true;
lc->flag |= LAYER_COLLECTION_EXCLUDE;
- for (LayerCollection *nlc = lc->layer_collections.first; nlc; nlc = nlc->next) {
+ LISTBASE_FOREACH (LayerCollection *, nlc, &lc->layer_collections) {
nlc->flag |= LAYER_COLLECTION_EXCLUDE;
}
}
@@ -516,7 +551,7 @@ static void do_version_layers_to_collections(Main *bmain, Scene *scene)
view_layer->basact = BKE_view_layer_base_find(view_layer, scene->basact->object);
}
- for (Base *base = view_layer->object_bases.first; base; base = base->next) {
+ LISTBASE_FOREACH (Base *, base, &view_layer->object_bases) {
if ((base->flag & BASE_SELECTABLE) && (base->object->flag & SELECT)) {
base->flag |= BASE_SELECTED;
}
@@ -542,7 +577,7 @@ static void do_version_layers_to_collections(Main *bmain, Scene *scene)
}
/* convert selected bases */
- for (Base *base = view_layer->object_bases.first; base; base = base->next) {
+ LISTBASE_FOREACH (Base *, base, &view_layer->object_bases) {
if ((base->flag & BASE_SELECTABLE) && (base->object->flag & SELECT)) {
base->flag |= BASE_SELECTED;
}
@@ -553,7 +588,7 @@ static void do_version_layers_to_collections(Main *bmain, Scene *scene)
}
/* remove bases once and for all */
- for (Base *base = scene->base.first; base; base = base->next) {
+ LISTBASE_FOREACH (Base *, base, &scene->base) {
id_us_min(&base->object->id);
}
@@ -577,8 +612,8 @@ static void do_version_collection_propagate_lib_to_children(Collection *collecti
/** convert old annotations colors */
static void do_versions_fix_annotations(bGPdata *gpd)
{
- for (const bGPDpalette *palette = gpd->palettes.first; palette; palette = palette->next) {
- for (bGPDpalettecolor *palcolor = palette->colors.first; palcolor; palcolor = palcolor->next) {
+ LISTBASE_FOREACH (const bGPDpalette *, palette, &gpd->palettes) {
+ LISTBASE_FOREACH (bGPDpalettecolor *, palcolor, &palette->colors) {
/* fix layers */
LISTBASE_FOREACH (bGPDlayer *, gpl, &gpd->layers) {
/* unlock/unhide layer */
@@ -609,9 +644,9 @@ static void do_versions_remove_region(ListBase *regionbase, ARegion *region)
static void do_versions_remove_regions_by_type(ListBase *regionbase, int regiontype)
{
- ARegion *region, *ar_next;
- for (region = regionbase->first; region; region = ar_next) {
- ar_next = region->next;
+ ARegion *region, *region_next;
+ for (region = regionbase->first; region; region = region_next) {
+ region_next = region->next;
if (region->regiontype == regiontype) {
do_versions_remove_region(regionbase, region);
}
@@ -620,7 +655,7 @@ static void do_versions_remove_regions_by_type(ListBase *regionbase, int regiont
static ARegion *do_versions_find_region_or_null(ListBase *regionbase, int regiontype)
{
- for (ARegion *region = regionbase->first; region; region = region->next) {
+ LISTBASE_FOREACH (ARegion *, region, regionbase) {
if (region->regiontype == regiontype) {
return region;
}
@@ -649,13 +684,14 @@ static void do_versions_area_ensure_tool_region(Main *bmain,
const short region_flag)
{
for (bScreen *screen = bmain->screens.first; screen; screen = screen->id.next) {
- for (ScrArea *sa = screen->areabase.first; sa; sa = sa->next) {
- for (SpaceLink *sl = sa->spacedata.first; sl; sl = sl->next) {
+ LISTBASE_FOREACH (ScrArea *, area, &screen->areabase) {
+ LISTBASE_FOREACH (SpaceLink *, sl, &area->spacedata) {
if (sl->spacetype == space_type) {
- ListBase *regionbase = (sl == sa->spacedata.first) ? &sa->regionbase : &sl->regionbase;
- ARegion *region = BKE_area_find_region_type(sa, RGN_TYPE_TOOLS);
+ ListBase *regionbase = (sl == area->spacedata.first) ? &area->regionbase :
+ &sl->regionbase;
+ ARegion *region = BKE_area_find_region_type(area, RGN_TYPE_TOOLS);
if (!region) {
- ARegion *header = BKE_area_find_region_type(sa, RGN_TYPE_HEADER);
+ ARegion *header = BKE_area_find_region_type(area, RGN_TYPE_HEADER);
region = do_versions_add_region(RGN_TYPE_TOOLS, "tools region");
BLI_insertlinkafter(regionbase, header, region);
region->alignment = RGN_ALIGN_LEFT;
@@ -669,7 +705,7 @@ static void do_versions_area_ensure_tool_region(Main *bmain,
static void do_version_bones_split_bbone_scale(ListBase *lb)
{
- for (Bone *bone = lb->first; bone; bone = bone->next) {
+ LISTBASE_FOREACH (Bone *, bone, lb) {
bone->scale_in_y = bone->scale_in_x;
bone->scale_out_y = bone->scale_out_x;
@@ -679,7 +715,7 @@ static void do_version_bones_split_bbone_scale(ListBase *lb)
static void do_version_bones_inherit_scale(ListBase *lb)
{
- for (Bone *bone = lb->first; bone; bone = bone->next) {
+ LISTBASE_FOREACH (Bone *, bone, lb) {
if (bone->flag & BONE_NO_SCALE) {
bone->inherit_scale_mode = BONE_INHERIT_SCALE_NONE_LEGACY;
bone->flag &= ~BONE_NO_SCALE;
@@ -723,7 +759,7 @@ static void do_version_bbone_scale_fcurve_fix(ListBase *curves, FCurve *fcu)
/* Update F-Curve's path. */
if (replace_bbone_scale_rnapath(&fcu->rna_path)) {
/* If matched, duplicate the curve and tweak name. */
- FCurve *second = copy_fcurve(fcu);
+ FCurve *second = BKE_fcurve_copy(fcu);
second->rna_path[strlen(second->rna_path) - 1] = 'y';
@@ -749,7 +785,7 @@ static void do_version_bbone_scale_animdata_cb(ID *UNUSED(id),
static void do_version_constraints_maintain_volume_mode_uniform(ListBase *lb)
{
- for (bConstraint *con = lb->first; con; con = con->next) {
+ LISTBASE_FOREACH (bConstraint *, con, lb) {
if (con->type == CONSTRAINT_TYPE_SAMEVOL) {
bSameVolumeConstraint *data = (bSameVolumeConstraint *)con->data;
data->mode = SAMEVOL_UNIFORM;
@@ -759,7 +795,7 @@ static void do_version_constraints_maintain_volume_mode_uniform(ListBase *lb)
static void do_version_constraints_copy_scale_power(ListBase *lb)
{
- for (bConstraint *con = lb->first; con; con = con->next) {
+ LISTBASE_FOREACH (bConstraint *, con, lb) {
if (con->type == CONSTRAINT_TYPE_SIZELIKE) {
bSizeLikeConstraint *data = (bSizeLikeConstraint *)con->data;
data->power = 1.0f;
@@ -769,7 +805,7 @@ static void do_version_constraints_copy_scale_power(ListBase *lb)
static void do_version_constraints_copy_rotation_mix_mode(ListBase *lb)
{
- for (bConstraint *con = lb->first; con; con = con->next) {
+ LISTBASE_FOREACH (bConstraint *, con, lb) {
if (con->type == CONSTRAINT_TYPE_ROTLIKE) {
bRotateLikeConstraint *data = (bRotateLikeConstraint *)con->data;
data->mix_mode = (data->flag & ROTLIKE_OFFSET) ? ROTLIKE_MIX_OFFSET : ROTLIKE_MIX_REPLACE;
@@ -1243,8 +1279,8 @@ void do_versions_after_linking_280(Main *bmain, ReportList *UNUSED(reports))
* so same layer as BKE_view_layer_default_view would return */
ViewLayer *layer = screen->scene->view_layers.first;
- for (ScrArea *sa = screen->areabase.first; sa; sa = sa->next) {
- for (SpaceLink *space = sa->spacedata.first; space; space = space->next) {
+ LISTBASE_FOREACH (ScrArea *, area, &screen->areabase) {
+ LISTBASE_FOREACH (SpaceLink *, space, &area->spacedata) {
if (space->spacetype == SPACE_OUTLINER) {
SpaceOutliner *soutliner = (SpaceOutliner *)space;
@@ -1273,8 +1309,8 @@ void do_versions_after_linking_280(Main *bmain, ReportList *UNUSED(reports))
if (!MAIN_VERSION_ATLEAST(bmain, 280, 0)) {
for (bScreen *screen = bmain->screens.first; screen; screen = screen->id.next) {
- for (ScrArea *sa = screen->areabase.first; sa; sa = sa->next) {
- for (SpaceLink *space = sa->spacedata.first; space; space = space->next) {
+ LISTBASE_FOREACH (ScrArea *, area, &screen->areabase) {
+ LISTBASE_FOREACH (SpaceLink *, space, &area->spacedata) {
if (space->spacetype == SPACE_IMAGE) {
SpaceImage *sima = (SpaceImage *)space;
if ((sima) && (sima->gpd)) {
@@ -1304,7 +1340,7 @@ void do_versions_after_linking_280(Main *bmain, ReportList *UNUSED(reports))
/* Cleanup any remaining SceneRenderLayer data for files that were created
* with Blender 2.8 before the SceneRenderLayer > RenderLayer refactor. */
for (Scene *scene = bmain->scenes.first; scene; scene = scene->id.next) {
- for (SceneRenderLayer *srl = scene->r.layers.first; srl; srl = srl->next) {
+ LISTBASE_FOREACH (SceneRenderLayer *, srl, &scene->r.layers) {
if (srl->prop) {
IDP_FreeProperty(srl->prop);
}
@@ -1319,7 +1355,7 @@ void do_versions_after_linking_280(Main *bmain, ReportList *UNUSED(reports))
* no longer be visible.
* Here we correct this by setting a default draw size for those files. */
for (Object *object = bmain->objects.first; object; object = object->id.next) {
- for (ParticleSystem *psys = object->particlesystem.first; psys; psys = psys->next) {
+ LISTBASE_FOREACH (ParticleSystem *, psys, &object->particlesystem) {
if (psys->part->draw_size == 0.0f) {
psys->part->draw_size = 0.1f;
}
@@ -1331,7 +1367,7 @@ void do_versions_after_linking_280(Main *bmain, ReportList *UNUSED(reports))
for (Object *object = bmain->objects.first; object; object = object->id.next) {
if (object->particlesystem.first) {
object->duplicator_visibility_flag = OB_DUPLI_FLAG_VIEWPORT;
- for (ParticleSystem *psys = object->particlesystem.first; psys; psys = psys->next) {
+ LISTBASE_FOREACH (ParticleSystem *, psys, &object->particlesystem) {
if (psys->part->draw & PART_DRAW_EMITTER) {
object->duplicator_visibility_flag |= OB_DUPLI_FLAG_RENDER;
break;
@@ -1362,9 +1398,9 @@ void do_versions_after_linking_280(Main *bmain, ReportList *UNUSED(reports))
* screens using the active scene of the window they're displayed in.
* Next, update remaining screens using first scene in main listbase. */
- for (wmWindow *win = wm->windows.first; win; win = win->next) {
+ LISTBASE_FOREACH (wmWindow *, win, &wm->windows) {
const bScreen *screen = BKE_workspace_active_screen_get(win->workspace_hook);
- for (ScrArea *area = screen->areabase.first; area; area = area->next) {
+ LISTBASE_FOREACH (ScrArea *, area, &screen->areabase) {
if (ELEM(area->butspacetype, SPACE_TIME, SPACE_LOGIC)) {
do_version_area_change_space_to_space_action(area, win->scene);
@@ -1376,7 +1412,7 @@ void do_versions_after_linking_280(Main *bmain, ReportList *UNUSED(reports))
}
if (scene != NULL) {
for (bScreen *screen = bmain->screens.first; screen; screen = screen->id.next) {
- for (ScrArea *area = screen->areabase.first; area; area = area->next) {
+ LISTBASE_FOREACH (ScrArea *, area, &screen->areabase) {
if (ELEM(area->butspacetype, SPACE_TIME, SPACE_LOGIC)) {
/* Areas that were already handled won't be handled again */
do_version_area_change_space_to_space_action(area, scene);
@@ -1413,7 +1449,7 @@ void do_versions_after_linking_280(Main *bmain, ReportList *UNUSED(reports))
int new_count = BKE_keyblock_curve_element_count(&cu->nurb);
- for (KeyBlock *block = cu->key->block.first; block; block = block->next) {
+ LISTBASE_FOREACH (KeyBlock *, block, &cu->key->block) {
int old_count = block->totelem;
void *old_data = block->data;
@@ -1427,7 +1463,7 @@ void do_versions_after_linking_280(Main *bmain, ReportList *UNUSED(reports))
float *oldptr = old_data;
float(*newptr)[3] = block->data;
- for (Nurb *nu = cu->nurb.first; nu; nu = nu->next) {
+ LISTBASE_FOREACH (Nurb *, nu, &cu->nurb) {
if (nu->bezt) {
BezTriple *bezt = nu->bezt;
@@ -1480,7 +1516,7 @@ void do_versions_after_linking_280(Main *bmain, ReportList *UNUSED(reports))
if (ob->pose && arm && arm->id.lib == ob->id.lib) {
bool rebuild = false;
- for (bPoseChannel *pchan = ob->pose->chanbase.first; pchan; pchan = pchan->next) {
+ LISTBASE_FOREACH (bPoseChannel *, pchan, &ob->pose->chanbase) {
/* If the 2.7 flag is enabled, processing is needed. */
if (pchan->bone && (pchan->bboneflag & PCHAN_BBONE_CUSTOM_HANDLES)) {
/* If the settings in the Bone are not set, copy. */
@@ -1632,14 +1668,42 @@ void do_versions_after_linking_280(Main *bmain, ReportList *UNUSED(reports))
if (!MAIN_VERSION_ATLEAST(bmain, 282, 2)) {
/* Init all Vertex/Sculpt and Weight Paint brushes. */
- Brush *brush = BLI_findstring(&bmain->brushes, "Pencil", offsetof(ID, name) + 2);
+ Brush *brush;
+ Material *ma;
+ /* Pen Soft brush. */
+ brush = (Brush *)rename_id_for_versioning(bmain, ID_BR, "Draw Soft", "Pencil Soft");
+ if (brush) {
+ brush->gpencil_settings->icon_id = GP_BRUSH_ICON_PEN;
+ }
+ rename_id_for_versioning(bmain, ID_BR, "Draw Pencil", "Pencil");
+ rename_id_for_versioning(bmain, ID_BR, "Draw Pen", "Pen");
+ rename_id_for_versioning(bmain, ID_BR, "Draw Ink", "Ink Pen");
+ rename_id_for_versioning(bmain, ID_BR, "Draw Noise", "Ink Pen Rough");
+ rename_id_for_versioning(bmain, ID_BR, "Draw Marker", "Marker Bold");
+ rename_id_for_versioning(bmain, ID_BR, "Draw Block", "Marker Chisel");
+
+ ma = BLI_findstring(&bmain->materials, "Black", offsetof(ID, name) + 2);
+ if (ma && ma->gp_style) {
+ rename_id_for_versioning(bmain, ID_MA, "Black", "Solid Stroke");
+ }
+ ma = BLI_findstring(&bmain->materials, "Red", offsetof(ID, name) + 2);
+ if (ma && ma->gp_style) {
+ rename_id_for_versioning(bmain, ID_MA, "Red", "Squares Stroke");
+ }
+ ma = BLI_findstring(&bmain->materials, "Grey", offsetof(ID, name) + 2);
+ if (ma && ma->gp_style) {
+ rename_id_for_versioning(bmain, ID_MA, "Grey", "Solid Fill");
+ }
+ ma = BLI_findstring(&bmain->materials, "Black Dots", offsetof(ID, name) + 2);
+ if (ma && ma->gp_style) {
+ rename_id_for_versioning(bmain, ID_MA, "Black Dots", "Dots Stroke");
+ }
+
+ brush = BLI_findstring(&bmain->brushes, "Pencil", offsetof(ID, name) + 2);
+
for (Scene *scene = bmain->scenes.first; scene; scene = scene->id.next) {
ToolSettings *ts = scene->toolsettings;
- BKE_brush_gpencil_vertex_presets(bmain, ts);
- BKE_brush_gpencil_sculpt_presets(bmain, ts);
- BKE_brush_gpencil_weight_presets(bmain, ts);
-
/* Ensure new Paint modes. */
BKE_paint_ensure_from_paintmode(scene, PAINT_MODE_GPENCIL);
BKE_paint_ensure_from_paintmode(scene, PAINT_MODE_VERTEX_GPENCIL);
@@ -1653,8 +1717,6 @@ void do_versions_after_linking_280(Main *bmain, ReportList *UNUSED(reports))
/* Enable cursor by default. */
paint->flags |= PAINT_SHOW_BRUSH;
}
- /* Ensure Palette by default. */
- BKE_gpencil_palette_ensure(bmain, scene);
}
}
@@ -1665,6 +1727,14 @@ void do_versions_after_linking_280(Main *bmain, ReportList *UNUSED(reports))
LISTBASE_FOREACH (Object *, ob, &bmain->objects) {
BKE_fcurves_id_cb(&ob->id, do_version_fcurve_hide_viewport_fix, NULL);
}
+
+ /* Reset all grease pencil brushes. */
+ LISTBASE_FOREACH (Scene *, scene, &bmain->scenes) {
+ /* Ensure new Paint modes. */
+ BKE_paint_ensure_from_paintmode(scene, PAINT_MODE_VERTEX_GPENCIL);
+ BKE_paint_ensure_from_paintmode(scene, PAINT_MODE_SCULPT_GPENCIL);
+ BKE_paint_ensure_from_paintmode(scene, PAINT_MODE_WEIGHT_GPENCIL);
+ }
}
/**
@@ -1783,7 +1853,7 @@ void blo_do_versions_280(FileData *fd, Library *UNUSED(lib), Main *bmain)
FOREACH_NODETREE_BEGIN (bmain, ntree, id) {
if (ntree->type == NTREE_SHADER) {
- for (bNode *node = ntree->nodes.first; node; node = node->next) {
+ LISTBASE_FOREACH (bNode *, node, &ntree->nodes) {
if (node->type == 194 /* SH_NODE_EEVEE_METALLIC */ &&
STREQ(node->idname, "ShaderNodeOutputMetallic")) {
BLI_strncpy(node->idname, "ShaderNodeEeveeMetallic", sizeof(node->idname));
@@ -1912,8 +1982,8 @@ void blo_do_versions_280(FileData *fd, Library *UNUSED(lib), Main *bmain)
/* init grease pencil grids and paper */
if (!DNA_struct_elem_find(fd->filesdna, "View3DOverlay", "float", "gpencil_paper_color[3]")) {
for (bScreen *screen = bmain->screens.first; screen; screen = screen->id.next) {
- for (ScrArea *area = screen->areabase.first; area; area = area->next) {
- for (SpaceLink *sl = area->spacedata.first; sl; sl = sl->next) {
+ LISTBASE_FOREACH (ScrArea *, area, &screen->areabase) {
+ LISTBASE_FOREACH (SpaceLink *, sl, &area->spacedata) {
if (sl->spacetype == SPACE_VIEW3D) {
View3D *v3d = (View3D *)sl;
v3d->overlay.gpencil_paper_opacity = 0.5f;
@@ -1927,14 +1997,14 @@ void blo_do_versions_280(FileData *fd, Library *UNUSED(lib), Main *bmain)
if (!MAIN_VERSION_ATLEAST(bmain, 280, 6)) {
if (DNA_struct_elem_find(fd->filesdna, "SpaceOutliner", "int", "filter") == false) {
- bScreen *sc;
- ScrArea *sa;
+ bScreen *screen;
+ ScrArea *area;
SpaceLink *sl;
/* Update files using invalid (outdated) outlinevis Outliner values. */
- for (sc = bmain->screens.first; sc; sc = sc->id.next) {
- for (sa = sc->areabase.first; sa; sa = sa->next) {
- for (sl = sa->spacedata.first; sl; sl = sl->next) {
+ for (screen = bmain->screens.first; screen; screen = screen->id.next) {
+ for (area = screen->areabase.first; area; area = area->next) {
+ for (sl = area->spacedata.first; sl; sl = sl->next) {
if (sl->spacetype == SPACE_OUTLINER) {
SpaceOutliner *so = (SpaceOutliner *)sl;
@@ -1972,9 +2042,9 @@ void blo_do_versions_280(FileData *fd, Library *UNUSED(lib), Main *bmain)
}
}
- for (bScreen *sc = bmain->screens.first; sc; sc = sc->id.next) {
- for (ScrArea *sa = sc->areabase.first; sa; sa = sa->next) {
- for (SpaceLink *sl = sa->spacedata.first; sl; sl = sl->next) {
+ for (bScreen *screen = bmain->screens.first; screen; screen = screen->id.next) {
+ LISTBASE_FOREACH (ScrArea *, area, &screen->areabase) {
+ LISTBASE_FOREACH (SpaceLink *, sl, &area->spacedata) {
if (sl->spacetype == SPACE_VIEW3D) {
View3D *v3d = (View3D *)sl;
v3d->shading.light = V3D_LIGHTING_STUDIO;
@@ -2026,7 +2096,7 @@ void blo_do_versions_280(FileData *fd, Library *UNUSED(lib), Main *bmain)
for (bScreen *screen = bmain->screens.first; screen; screen = screen->id.next) {
/* Calculate window width/height from screen vertices */
int win_width = 0, win_height = 0;
- for (ScrVert *vert = screen->vertbase.first; vert; vert = vert->next) {
+ LISTBASE_FOREACH (ScrVert *, vert, &screen->vertbase) {
win_width = MAX2(win_width, vert->vec.x);
win_height = MAX2(win_height, vert->vec.y);
}
@@ -2066,10 +2136,11 @@ void blo_do_versions_280(FileData *fd, Library *UNUSED(lib), Main *bmain)
if (!MAIN_VERSION_ATLEAST(bmain, 280, 12)) {
/* Remove tool property regions. */
for (bScreen *screen = bmain->screens.first; screen; screen = screen->id.next) {
- for (ScrArea *sa = screen->areabase.first; sa; sa = sa->next) {
- for (SpaceLink *sl = sa->spacedata.first; sl; sl = sl->next) {
+ LISTBASE_FOREACH (ScrArea *, area, &screen->areabase) {
+ LISTBASE_FOREACH (SpaceLink *, sl, &area->spacedata) {
if (ELEM(sl->spacetype, SPACE_VIEW3D, SPACE_CLIP)) {
- ListBase *regionbase = (sl == sa->spacedata.first) ? &sa->regionbase : &sl->regionbase;
+ ListBase *regionbase = (sl == area->spacedata.first) ? &area->regionbase :
+ &sl->regionbase;
for (ARegion *region = regionbase->first, *region_next; region; region = region_next) {
region_next = region->next;
@@ -2095,8 +2166,8 @@ void blo_do_versions_280(FileData *fd, Library *UNUSED(lib), Main *bmain)
/* Initialize new view3D options. */
for (bScreen *screen = bmain->screens.first; screen; screen = screen->id.next) {
- for (ScrArea *sa = screen->areabase.first; sa; sa = sa->next) {
- for (SpaceLink *sl = sa->spacedata.first; sl; sl = sl->next) {
+ LISTBASE_FOREACH (ScrArea *, area, &screen->areabase) {
+ LISTBASE_FOREACH (SpaceLink *, sl, &area->spacedata) {
if (sl->spacetype == SPACE_VIEW3D) {
View3D *v3d = (View3D *)sl;
v3d->shading.light = V3D_LIGHTING_STUDIO;
@@ -2320,8 +2391,8 @@ void blo_do_versions_280(FileData *fd, Library *UNUSED(lib), Main *bmain)
}
for (bScreen *screen = bmain->screens.first; screen; screen = screen->id.next) {
- for (ScrArea *sa = screen->areabase.first; sa; sa = sa->next) {
- for (SpaceLink *sl = sa->spacedata.first; sl; sl = sl->next) {
+ LISTBASE_FOREACH (ScrArea *, area, &screen->areabase) {
+ LISTBASE_FOREACH (SpaceLink *, sl, &area->spacedata) {
if (sl->spacetype == SPACE_OUTLINER) {
SpaceOutliner *soops = (SpaceOutliner *)sl;
soops->filter_id_type = ID_GR;
@@ -2402,8 +2473,8 @@ void blo_do_versions_280(FileData *fd, Library *UNUSED(lib), Main *bmain)
}
for (bScreen *screen = bmain->screens.first; screen; screen = screen->id.next) {
- for (ScrArea *sa = screen->areabase.first; sa; sa = sa->next) {
- for (SpaceLink *sl = sa->spacedata.first; sl; sl = sl->next) {
+ LISTBASE_FOREACH (ScrArea *, area, &screen->areabase) {
+ LISTBASE_FOREACH (SpaceLink *, sl, &area->spacedata) {
if (sl->spacetype == SPACE_VIEW3D) {
View3D *v3d = (View3D *)sl;
v3d->shading.flag |= V3D_SHADING_SPECULAR_HIGHLIGHT;
@@ -2415,8 +2486,8 @@ void blo_do_versions_280(FileData *fd, Library *UNUSED(lib), Main *bmain)
if (!DNA_struct_elem_find(fd->filesdna, "View3DShading", "float", "xray_alpha")) {
for (bScreen *screen = bmain->screens.first; screen; screen = screen->id.next) {
- for (ScrArea *sa = screen->areabase.first; sa; sa = sa->next) {
- for (SpaceLink *sl = sa->spacedata.first; sl; sl = sl->next) {
+ LISTBASE_FOREACH (ScrArea *, area, &screen->areabase) {
+ LISTBASE_FOREACH (SpaceLink *, sl, &area->spacedata) {
if (sl->spacetype == SPACE_VIEW3D) {
View3D *v3d = (View3D *)sl;
v3d->shading.xray_alpha = 0.5f;
@@ -2430,8 +2501,8 @@ void blo_do_versions_280(FileData *fd, Library *UNUSED(lib), Main *bmain)
/* when loading the internal file is loaded before the matcaps */
if (default_matcap) {
for (bScreen *screen = bmain->screens.first; screen; screen = screen->id.next) {
- for (ScrArea *sa = screen->areabase.first; sa; sa = sa->next) {
- for (SpaceLink *sl = sa->spacedata.first; sl; sl = sl->next) {
+ LISTBASE_FOREACH (ScrArea *, area, &screen->areabase) {
+ LISTBASE_FOREACH (SpaceLink *, sl, &area->spacedata) {
if (sl->spacetype == SPACE_VIEW3D) {
View3D *v3d = (View3D *)sl;
BLI_strncpy(v3d->shading.matcap, default_matcap->name, FILE_MAXFILE);
@@ -2443,8 +2514,8 @@ void blo_do_versions_280(FileData *fd, Library *UNUSED(lib), Main *bmain)
}
if (!DNA_struct_elem_find(fd->filesdna, "View3DOverlay", "float", "wireframe_threshold")) {
for (bScreen *screen = bmain->screens.first; screen; screen = screen->id.next) {
- for (ScrArea *sa = screen->areabase.first; sa; sa = sa->next) {
- for (SpaceLink *sl = sa->spacedata.first; sl; sl = sl->next) {
+ LISTBASE_FOREACH (ScrArea *, area, &screen->areabase) {
+ LISTBASE_FOREACH (SpaceLink *, sl, &area->spacedata) {
if (sl->spacetype == SPACE_VIEW3D) {
View3D *v3d = (View3D *)sl;
v3d->overlay.wireframe_threshold = 0.5f;
@@ -2455,8 +2526,8 @@ void blo_do_versions_280(FileData *fd, Library *UNUSED(lib), Main *bmain)
}
if (!DNA_struct_elem_find(fd->filesdna, "View3DShading", "float", "cavity_valley_factor")) {
for (bScreen *screen = bmain->screens.first; screen; screen = screen->id.next) {
- for (ScrArea *sa = screen->areabase.first; sa; sa = sa->next) {
- for (SpaceLink *sl = sa->spacedata.first; sl; sl = sl->next) {
+ LISTBASE_FOREACH (ScrArea *, area, &screen->areabase) {
+ LISTBASE_FOREACH (SpaceLink *, sl, &area->spacedata) {
if (sl->spacetype == SPACE_VIEW3D) {
View3D *v3d = (View3D *)sl;
v3d->shading.cavity_valley_factor = 1.0f;
@@ -2468,8 +2539,8 @@ void blo_do_versions_280(FileData *fd, Library *UNUSED(lib), Main *bmain)
}
if (!DNA_struct_elem_find(fd->filesdna, "View3DOverlay", "float", "xray_alpha_bone")) {
for (bScreen *screen = bmain->screens.first; screen; screen = screen->id.next) {
- for (ScrArea *sa = screen->areabase.first; sa; sa = sa->next) {
- for (SpaceLink *sl = sa->spacedata.first; sl; sl = sl->next) {
+ LISTBASE_FOREACH (ScrArea *, area, &screen->areabase) {
+ LISTBASE_FOREACH (SpaceLink *, sl, &area->spacedata) {
if (sl->spacetype == SPACE_VIEW3D) {
View3D *v3d = (View3D *)sl;
v3d->overlay.xray_alpha_bone = 0.5f;
@@ -2494,8 +2565,8 @@ void blo_do_versions_280(FileData *fd, Library *UNUSED(lib), Main *bmain)
}
if (!DNA_struct_elem_find(fd->filesdna, "SpaceAction", "char", "mode_prev")) {
for (bScreen *screen = bmain->screens.first; screen; screen = screen->id.next) {
- for (ScrArea *sa = screen->areabase.first; sa; sa = sa->next) {
- for (SpaceLink *sl = sa->spacedata.first; sl; sl = sl->next) {
+ LISTBASE_FOREACH (ScrArea *, area, &screen->areabase) {
+ LISTBASE_FOREACH (SpaceLink *, sl, &area->spacedata) {
if (sl->spacetype == SPACE_ACTION) {
SpaceAction *saction = (SpaceAction *)sl;
/* "Dopesheet" should be default here,
@@ -2510,8 +2581,8 @@ void blo_do_versions_280(FileData *fd, Library *UNUSED(lib), Main *bmain)
}
for (bScreen *screen = bmain->screens.first; screen; screen = screen->id.next) {
- for (ScrArea *sa = screen->areabase.first; sa; sa = sa->next) {
- for (SpaceLink *sl = sa->spacedata.first; sl; sl = sl->next) {
+ LISTBASE_FOREACH (ScrArea *, area, &screen->areabase) {
+ LISTBASE_FOREACH (SpaceLink *, sl, &area->spacedata) {
if (sl->spacetype == SPACE_VIEW3D) {
View3D *v3d = (View3D *)sl;
if (v3d->drawtype == OB_TEXTURE) {
@@ -2535,8 +2606,8 @@ void blo_do_versions_280(FileData *fd, Library *UNUSED(lib), Main *bmain)
if (!DNA_struct_elem_find(
fd->filesdna, "View3DOverlay", "float", "texture_paint_mode_opacity")) {
for (bScreen *screen = bmain->screens.first; screen; screen = screen->id.next) {
- for (ScrArea *sa = screen->areabase.first; sa; sa = sa->next) {
- for (SpaceLink *sl = sa->spacedata.first; sl; sl = sl->next) {
+ LISTBASE_FOREACH (ScrArea *, area, &screen->areabase) {
+ LISTBASE_FOREACH (SpaceLink *, sl, &area->spacedata) {
if (sl->spacetype == SPACE_VIEW3D) {
enum {
V3D_SHOW_MODE_SHADE_OVERRIDE = (1 << 15),
@@ -2554,8 +2625,8 @@ void blo_do_versions_280(FileData *fd, Library *UNUSED(lib), Main *bmain)
if (!DNA_struct_elem_find(fd->filesdna, "View3DShading", "char", "background_type")) {
for (bScreen *screen = bmain->screens.first; screen; screen = screen->id.next) {
- for (ScrArea *sa = screen->areabase.first; sa; sa = sa->next) {
- for (SpaceLink *sl = sa->spacedata.first; sl; sl = sl->next) {
+ LISTBASE_FOREACH (ScrArea *, area, &screen->areabase) {
+ LISTBASE_FOREACH (SpaceLink *, sl, &area->spacedata) {
if (sl->spacetype == SPACE_VIEW3D) {
View3D *v3d = (View3D *)sl;
copy_v3_fl(v3d->shading.background_color, 0.05f);
@@ -2619,8 +2690,8 @@ void blo_do_versions_280(FileData *fd, Library *UNUSED(lib), Main *bmain)
if (!DNA_struct_elem_find(fd->filesdna, "View3DShading", "short", "type")) {
for (bScreen *screen = bmain->screens.first; screen; screen = screen->id.next) {
- for (ScrArea *sa = screen->areabase.first; sa; sa = sa->next) {
- for (SpaceLink *sl = sa->spacedata.first; sl; sl = sl->next) {
+ LISTBASE_FOREACH (ScrArea *, area, &screen->areabase) {
+ LISTBASE_FOREACH (SpaceLink *, sl, &area->spacedata) {
if (sl->spacetype == SPACE_VIEW3D) {
View3D *v3d = (View3D *)sl;
if (v3d->drawtype == OB_RENDER) {
@@ -2641,9 +2712,9 @@ void blo_do_versions_280(FileData *fd, Library *UNUSED(lib), Main *bmain)
}
/* initialize grease pencil view data */
if (!DNA_struct_elem_find(fd->filesdna, "SpaceView3D", "float", "vertex_opacity")) {
- for (bScreen *sc = bmain->screens.first; sc; sc = sc->id.next) {
- for (ScrArea *sa = sc->areabase.first; sa; sa = sa->next) {
- for (SpaceLink *sl = sa->spacedata.first; sl; sl = sl->next) {
+ for (bScreen *screen = bmain->screens.first; screen; screen = screen->id.next) {
+ LISTBASE_FOREACH (ScrArea *, area, &screen->areabase) {
+ LISTBASE_FOREACH (SpaceLink *, sl, &area->spacedata) {
if (sl->spacetype == SPACE_VIEW3D) {
View3D *v3d = (View3D *)sl;
v3d->vertex_opacity = 1.0f;
@@ -2674,8 +2745,8 @@ void blo_do_versions_280(FileData *fd, Library *UNUSED(lib), Main *bmain)
}
if (!DNA_struct_elem_find(fd->filesdna, "View3DOverlay", "float", "gpencil_paper_opacity")) {
for (bScreen *screen = bmain->screens.first; screen; screen = screen->id.next) {
- for (ScrArea *sa = screen->areabase.first; sa; sa = sa->next) {
- for (SpaceLink *sl = sa->spacedata.first; sl; sl = sl->next) {
+ LISTBASE_FOREACH (ScrArea *, area, &screen->areabase) {
+ LISTBASE_FOREACH (SpaceLink *, sl, &area->spacedata) {
if (sl->spacetype == SPACE_VIEW3D) {
View3D *v3d = (View3D *)sl;
v3d->overlay.gpencil_paper_opacity = 0.5f;
@@ -2686,8 +2757,8 @@ void blo_do_versions_280(FileData *fd, Library *UNUSED(lib), Main *bmain)
}
if (!DNA_struct_elem_find(fd->filesdna, "View3DOverlay", "float", "gpencil_grid_opacity")) {
for (bScreen *screen = bmain->screens.first; screen; screen = screen->id.next) {
- for (ScrArea *sa = screen->areabase.first; sa; sa = sa->next) {
- for (SpaceLink *sl = sa->spacedata.first; sl; sl = sl->next) {
+ LISTBASE_FOREACH (ScrArea *, area, &screen->areabase) {
+ LISTBASE_FOREACH (SpaceLink *, sl, &area->spacedata) {
if (sl->spacetype == SPACE_VIEW3D) {
View3D *v3d = (View3D *)sl;
v3d->overlay.gpencil_grid_opacity = 0.5f;
@@ -2711,7 +2782,7 @@ void blo_do_versions_280(FileData *fd, Library *UNUSED(lib), Main *bmain)
/* Versioning code for Subsurf modifier. */
if (!DNA_struct_elem_find(fd->filesdna, "SubsurfModifier", "short", "uv_smooth")) {
for (Object *object = bmain->objects.first; object != NULL; object = object->id.next) {
- for (ModifierData *md = object->modifiers.first; md; md = md->next) {
+ LISTBASE_FOREACH (ModifierData *, md, &object->modifiers) {
if (md->type == eModifierType_Subsurf) {
SubsurfModifierData *smd = (SubsurfModifierData *)md;
if (smd->flags & eSubsurfModifierFlag_SubsurfUv_DEPRECATED) {
@@ -2727,7 +2798,7 @@ void blo_do_versions_280(FileData *fd, Library *UNUSED(lib), Main *bmain)
if (!DNA_struct_elem_find(fd->filesdna, "SubsurfModifier", "short", "quality")) {
for (Object *object = bmain->objects.first; object != NULL; object = object->id.next) {
- for (ModifierData *md = object->modifiers.first; md; md = md->next) {
+ LISTBASE_FOREACH (ModifierData *, md, &object->modifiers) {
if (md->type == eModifierType_Subsurf) {
SubsurfModifierData *smd = (SubsurfModifierData *)md;
smd->quality = min_ii(smd->renderLevels, 3);
@@ -2738,7 +2809,7 @@ void blo_do_versions_280(FileData *fd, Library *UNUSED(lib), Main *bmain)
/* Versioning code for Multires modifier. */
if (!DNA_struct_elem_find(fd->filesdna, "MultiresModifier", "short", "quality")) {
for (Object *object = bmain->objects.first; object != NULL; object = object->id.next) {
- for (ModifierData *md = object->modifiers.first; md; md = md->next) {
+ LISTBASE_FOREACH (ModifierData *, md, &object->modifiers) {
if (md->type == eModifierType_Multires) {
MultiresModifierData *mmd = (MultiresModifierData *)md;
mmd->quality = 3;
@@ -2755,7 +2826,7 @@ void blo_do_versions_280(FileData *fd, Library *UNUSED(lib), Main *bmain)
if (!DNA_struct_elem_find(fd->filesdna, "ClothSimSettings", "short", "bending_model")) {
for (Object *ob = bmain->objects.first; ob; ob = ob->id.next) {
- for (ModifierData *md = ob->modifiers.first; md; md = md->next) {
+ LISTBASE_FOREACH (ModifierData *, md, &ob->modifiers) {
ClothModifierData *clmd = NULL;
if (md->type == eModifierType_Cloth) {
clmd = (ClothModifierData *)md;
@@ -2795,7 +2866,7 @@ void blo_do_versions_280(FileData *fd, Library *UNUSED(lib), Main *bmain)
}
for (Object *ob = bmain->objects.first; ob; ob = ob->id.next) {
- for (ModifierData *md = ob->modifiers.first; md; md = md->next) {
+ LISTBASE_FOREACH (ModifierData *, md, &ob->modifiers) {
if (md->type == eModifierType_Cloth) {
ClothModifierData *clmd = (ClothModifierData *)md;
@@ -2824,15 +2895,14 @@ void blo_do_versions_280(FileData *fd, Library *UNUSED(lib), Main *bmain)
if (!MAIN_VERSION_ATLEAST(bmain, 280, 24)) {
for (bScreen *screen = bmain->screens.first; screen; screen = screen->id.next) {
- for (ScrArea *sa = screen->areabase.first; sa; sa = sa->next) {
- for (SpaceLink *sl = sa->spacedata.first; sl; sl = sl->next) {
+ LISTBASE_FOREACH (ScrArea *, area, &screen->areabase) {
+ LISTBASE_FOREACH (SpaceLink *, sl, &area->spacedata) {
if (sl->spacetype == SPACE_VIEW3D) {
View3D *v3d = (View3D *)sl;
v3d->overlay.edit_flag |= V3D_OVERLAY_EDIT_FACES | V3D_OVERLAY_EDIT_SEAMS |
V3D_OVERLAY_EDIT_SHARP | V3D_OVERLAY_EDIT_FREESTYLE_EDGE |
V3D_OVERLAY_EDIT_FREESTYLE_FACE | V3D_OVERLAY_EDIT_EDGES |
- V3D_OVERLAY_EDIT_CREASES | V3D_OVERLAY_EDIT_BWEIGHTS |
- V3D_OVERLAY_EDIT_CU_HANDLES | V3D_OVERLAY_EDIT_CU_NORMALS;
+ V3D_OVERLAY_EDIT_CREASES | V3D_OVERLAY_EDIT_BWEIGHTS;
}
}
}
@@ -2840,7 +2910,7 @@ void blo_do_versions_280(FileData *fd, Library *UNUSED(lib), Main *bmain)
if (!DNA_struct_elem_find(fd->filesdna, "ShrinkwrapModifierData", "char", "shrinkMode")) {
for (Object *ob = bmain->objects.first; ob; ob = ob->id.next) {
- for (ModifierData *md = ob->modifiers.first; md; md = md->next) {
+ LISTBASE_FOREACH (ModifierData *, md, &ob->modifiers) {
if (md->type == eModifierType_Shrinkwrap) {
ShrinkwrapModifierData *smd = (ShrinkwrapModifierData *)md;
if (smd->shrinkOpts & MOD_SHRINKWRAP_KEEP_ABOVE_SURFACE) {
@@ -2858,7 +2928,7 @@ void blo_do_versions_280(FileData *fd, Library *UNUSED(lib), Main *bmain)
ob->pd->pdef_cfrict = 5.0f;
}
- for (ModifierData *md = ob->modifiers.first; md; md = md->next) {
+ LISTBASE_FOREACH (ModifierData *, md, &ob->modifiers) {
if (md->type == eModifierType_Cloth) {
ClothModifierData *clmd = (ClothModifierData *)md;
@@ -2870,8 +2940,8 @@ void blo_do_versions_280(FileData *fd, Library *UNUSED(lib), Main *bmain)
if (!DNA_struct_elem_find(fd->filesdna, "View3DShading", "float", "xray_alpha_wire")) {
for (bScreen *screen = bmain->screens.first; screen; screen = screen->id.next) {
- for (ScrArea *sa = screen->areabase.first; sa; sa = sa->next) {
- for (SpaceLink *sl = sa->spacedata.first; sl; sl = sl->next) {
+ LISTBASE_FOREACH (ScrArea *, area, &screen->areabase) {
+ LISTBASE_FOREACH (SpaceLink *, sl, &area->spacedata) {
if (sl->spacetype == SPACE_VIEW3D) {
View3D *v3d = (View3D *)sl;
v3d->shading.flag |= V3D_SHADING_XRAY_WIREFRAME;
@@ -2908,8 +2978,8 @@ void blo_do_versions_280(FileData *fd, Library *UNUSED(lib), Main *bmain)
if (!MAIN_VERSION_ATLEAST(bmain, 280, 29)) {
for (bScreen *screen = bmain->screens.first; screen; screen = screen->id.next) {
- for (ScrArea *sa = screen->areabase.first; sa; sa = sa->next) {
- for (SpaceLink *sl = sa->spacedata.first; sl; sl = sl->next) {
+ LISTBASE_FOREACH (ScrArea *, area, &screen->areabase) {
+ LISTBASE_FOREACH (SpaceLink *, sl, &area->spacedata) {
if (sl->spacetype == SPACE_VIEW3D) {
enum { V3D_OCCLUDE_WIRE = (1 << 14) };
View3D *v3d = (View3D *)sl;
@@ -2931,12 +3001,13 @@ void blo_do_versions_280(FileData *fd, Library *UNUSED(lib), Main *bmain)
*/
if (!MAIN_VERSION_ATLEAST(bmain, 283, 1)) {
for (bScreen *screen = bmain->screens.first; screen; screen = screen->id.next) {
- for (ScrArea *sa = screen->areabase.first; sa; sa = sa->next) {
- for (SpaceLink *sl = sa->spacedata.first; sl; sl = sl->next) {
- ListBase *regionbase = (sl == sa->spacedata.first) ? &sa->regionbase : &sl->regionbase;
- ARegion *ar_header = do_versions_find_region_or_null(regionbase, RGN_TYPE_HEADER);
+ LISTBASE_FOREACH (ScrArea *, area, &screen->areabase) {
+ LISTBASE_FOREACH (SpaceLink *, sl, &area->spacedata) {
+ ListBase *regionbase = (sl == area->spacedata.first) ? &area->regionbase :
+ &sl->regionbase;
+ ARegion *region_header = do_versions_find_region_or_null(regionbase, RGN_TYPE_HEADER);
- if (!ar_header) {
+ if (!region_header) {
/* Headers should always be first in the region list, except if there's also a
* tool-header. These were only introduced in later versions though, so should be
* fine to always insert headers first. */
@@ -2954,21 +3025,23 @@ void blo_do_versions_280(FileData *fd, Library *UNUSED(lib), Main *bmain)
}
for (bScreen *screen = bmain->screens.first; screen; screen = screen->id.next) {
- for (ScrArea *sa = screen->areabase.first; sa; sa = sa->next) {
- for (SpaceLink *sl = sa->spacedata.first; sl; sl = sl->next) {
+ LISTBASE_FOREACH (ScrArea *, area, &screen->areabase) {
+ LISTBASE_FOREACH (SpaceLink *, sl, &area->spacedata) {
if (sl->spacetype == SPACE_PROPERTIES) {
- ListBase *regionbase = (sl == sa->spacedata.first) ? &sa->regionbase : &sl->regionbase;
+ ListBase *regionbase = (sl == area->spacedata.first) ? &area->regionbase :
+ &sl->regionbase;
ARegion *region = MEM_callocN(sizeof(ARegion), "navigation bar for properties");
- ARegion *ar_header = NULL;
+ ARegion *region_header = NULL;
- for (ar_header = regionbase->first; ar_header; ar_header = ar_header->next) {
- if (ar_header->regiontype == RGN_TYPE_HEADER) {
+ for (region_header = regionbase->first; region_header;
+ region_header = region_header->next) {
+ if (region_header->regiontype == RGN_TYPE_HEADER) {
break;
}
}
- BLI_assert(ar_header);
+ BLI_assert(region_header);
- BLI_insertlinkafter(regionbase, ar_header, region);
+ BLI_insertlinkafter(regionbase, region_header, region);
region->regiontype = RGN_TYPE_NAV_BAR;
region->alignment = RGN_ALIGN_LEFT;
@@ -2980,8 +3053,8 @@ void blo_do_versions_280(FileData *fd, Library *UNUSED(lib), Main *bmain)
/* grease pencil fade layer opacity */
if (!DNA_struct_elem_find(fd->filesdna, "View3DOverlay", "float", "gpencil_fade_layer")) {
for (bScreen *screen = bmain->screens.first; screen; screen = screen->id.next) {
- for (ScrArea *sa = screen->areabase.first; sa; sa = sa->next) {
- for (SpaceLink *sl = sa->spacedata.first; sl; sl = sl->next) {
+ LISTBASE_FOREACH (ScrArea *, area, &screen->areabase) {
+ LISTBASE_FOREACH (SpaceLink *, sl, &area->spacedata) {
if (sl->spacetype == SPACE_VIEW3D) {
View3D *v3d = (View3D *)sl;
v3d->overlay.gpencil_fade_layer = 0.5f;
@@ -3185,8 +3258,8 @@ void blo_do_versions_280(FileData *fd, Library *UNUSED(lib), Main *bmain)
if (!MAIN_VERSION_ATLEAST(bmain, 280, 34)) {
for (bScreen *screen = bmain->screens.first; screen; screen = screen->id.next) {
- for (ScrArea *area = screen->areabase.first; area; area = area->next) {
- for (SpaceLink *slink = area->spacedata.first; slink; slink = slink->next) {
+ LISTBASE_FOREACH (ScrArea *, area, &screen->areabase) {
+ LISTBASE_FOREACH (SpaceLink *, slink, &area->spacedata) {
if (slink->spacetype == SPACE_USERPREF) {
ARegion *navigation_region = BKE_spacedata_find_region_type(
slink, area, RGN_TYPE_NAV_BAR);
@@ -3214,8 +3287,8 @@ void blo_do_versions_280(FileData *fd, Library *UNUSED(lib), Main *bmain)
if (!MAIN_VERSION_ATLEAST(bmain, 280, 36)) {
if (!DNA_struct_elem_find(fd->filesdna, "View3DShading", "float", "curvature_ridge_factor")) {
for (bScreen *screen = bmain->screens.first; screen; screen = screen->id.next) {
- for (ScrArea *sa = screen->areabase.first; sa; sa = sa->next) {
- for (SpaceLink *sl = sa->spacedata.first; sl; sl = sl->next) {
+ LISTBASE_FOREACH (ScrArea *, area, &screen->areabase) {
+ LISTBASE_FOREACH (SpaceLink *, sl, &area->spacedata) {
if (sl->spacetype == SPACE_VIEW3D) {
View3D *v3d = (View3D *)sl;
v3d->shading.curvature_ridge_factor = 1.0f;
@@ -3246,8 +3319,8 @@ void blo_do_versions_280(FileData *fd, Library *UNUSED(lib), Main *bmain)
/* Move studio_light selection to lookdev_light. */
if (!DNA_struct_elem_find(fd->filesdna, "View3DShading", "char", "lookdev_light[256]")) {
for (bScreen *screen = bmain->screens.first; screen; screen = screen->id.next) {
- for (ScrArea *sa = screen->areabase.first; sa; sa = sa->next) {
- for (SpaceLink *sl = sa->spacedata.first; sl; sl = sl->next) {
+ LISTBASE_FOREACH (ScrArea *, area, &screen->areabase) {
+ LISTBASE_FOREACH (SpaceLink *, sl, &area->spacedata) {
if (sl->spacetype == SPACE_VIEW3D) {
View3D *v3d = (View3D *)sl;
memcpy(v3d->shading.lookdev_light, v3d->shading.studio_light, sizeof(char) * 256);
@@ -3300,8 +3373,8 @@ void blo_do_versions_280(FileData *fd, Library *UNUSED(lib), Main *bmain)
}
for (bScreen *screen = bmain->screens.first; screen; screen = screen->id.next) {
- for (ScrArea *area = screen->areabase.first; area; area = area->next) {
- for (SpaceLink *sl = area->spacedata.first; sl; sl = sl->next) {
+ LISTBASE_FOREACH (ScrArea *, area, &screen->areabase) {
+ LISTBASE_FOREACH (SpaceLink *, sl, &area->spacedata) {
switch (sl->spacetype) {
case SPACE_IMAGE: {
SpaceImage *sima = (SpaceImage *)sl;
@@ -3417,8 +3490,8 @@ void blo_do_versions_280(FileData *fd, Library *UNUSED(lib), Main *bmain)
}
for (bScreen *screen = bmain->screens.first; screen; screen = screen->id.next) {
- for (ScrArea *area = screen->areabase.first; area; area = area->next) {
- for (SpaceLink *sl = area->spacedata.first; sl; sl = sl->next) {
+ LISTBASE_FOREACH (ScrArea *, area, &screen->areabase) {
+ LISTBASE_FOREACH (SpaceLink *, sl, &area->spacedata) {
switch (sl->spacetype) {
case SPACE_VIEW3D: {
enum { V3D_BACKFACE_CULLING = (1 << 10) };
@@ -3460,21 +3533,21 @@ void blo_do_versions_280(FileData *fd, Library *UNUSED(lib), Main *bmain)
}
for (bScreen *screen = bmain->screens.first; screen; screen = screen->id.next) {
- for (ScrArea *area = screen->areabase.first; area; area = area->next) {
- for (SpaceLink *sl = area->spacedata.first; sl; sl = sl->next) {
+ LISTBASE_FOREACH (ScrArea *, area, &screen->areabase) {
+ LISTBASE_FOREACH (SpaceLink *, sl, &area->spacedata) {
if (sl->spacetype == SPACE_USERPREF) {
ARegion *execute_region = BKE_spacedata_find_region_type(sl, area, RGN_TYPE_EXECUTE);
if (!execute_region) {
ListBase *regionbase = (sl == area->spacedata.first) ? &area->regionbase :
&sl->regionbase;
- ARegion *ar_navbar = BKE_spacedata_find_region_type(sl, area, RGN_TYPE_NAV_BAR);
+ ARegion *region_navbar = BKE_spacedata_find_region_type(sl, area, RGN_TYPE_NAV_BAR);
execute_region = MEM_callocN(sizeof(ARegion), "execute region for properties");
- BLI_assert(ar_navbar);
+ BLI_assert(region_navbar);
- BLI_insertlinkafter(regionbase, ar_navbar, execute_region);
+ BLI_insertlinkafter(regionbase, region_navbar, execute_region);
execute_region->regiontype = RGN_TYPE_EXECUTE;
execute_region->alignment = RGN_ALIGN_BOTTOM | RGN_SPLIT_PREV;
@@ -3519,8 +3592,8 @@ void blo_do_versions_280(FileData *fd, Library *UNUSED(lib), Main *bmain)
/* Add wireframe color. */
if (!DNA_struct_elem_find(fd->filesdna, "View3DShading", "char", "wire_color_type")) {
for (bScreen *screen = bmain->screens.first; screen; screen = screen->id.next) {
- for (ScrArea *sa = screen->areabase.first; sa; sa = sa->next) {
- for (SpaceLink *sl = sa->spacedata.first; sl; sl = sl->next) {
+ LISTBASE_FOREACH (ScrArea *, area, &screen->areabase) {
+ LISTBASE_FOREACH (SpaceLink *, sl, &area->spacedata) {
if (sl->spacetype == SPACE_VIEW3D) {
View3D *v3d = (View3D *)sl;
v3d->shading.wire_color_type = V3D_SHADING_SINGLE_COLOR;
@@ -3622,7 +3695,7 @@ void blo_do_versions_280(FileData *fd, Library *UNUSED(lib), Main *bmain)
if (!DNA_struct_elem_find(fd->filesdna, "TriangulateModifierData", "int", "min_vertices")) {
for (Object *ob = bmain->objects.first; ob; ob = ob->id.next) {
- for (ModifierData *md = ob->modifiers.first; md; md = md->next) {
+ LISTBASE_FOREACH (ModifierData *, md, &ob->modifiers) {
if (md->type == eModifierType_Triangulate) {
TriangulateModifierData *smd = (TriangulateModifierData *)md;
smd->min_vertices = 4;
@@ -3633,7 +3706,7 @@ void blo_do_versions_280(FileData *fd, Library *UNUSED(lib), Main *bmain)
FOREACH_NODETREE_BEGIN (bmain, ntree, id) {
if (ntree->type == NTREE_SHADER) {
- for (bNode *node = ntree->nodes.first; node; node = node->next) {
+ LISTBASE_FOREACH (bNode *, node, &ntree->nodes) {
/* Fix missing version patching from earlier changes. */
if (STREQ(node->idname, "ShaderNodeOutputLamp")) {
STRNCPY(node->idname, "ShaderNodeOutputLight");
@@ -3672,7 +3745,7 @@ void blo_do_versions_280(FileData *fd, Library *UNUSED(lib), Main *bmain)
if (!MAIN_VERSION_ATLEAST(bmain, 280, 54)) {
for (Object *ob = bmain->objects.first; ob; ob = ob->id.next) {
bool is_first_subdiv = true;
- for (ModifierData *md = ob->modifiers.first; md; md = md->next) {
+ LISTBASE_FOREACH (ModifierData *, md, &ob->modifiers) {
if (md->type == eModifierType_Subsurf) {
SubsurfModifierData *smd = (SubsurfModifierData *)md;
if (is_first_subdiv) {
@@ -3699,10 +3772,11 @@ void blo_do_versions_280(FileData *fd, Library *UNUSED(lib), Main *bmain)
if (!MAIN_VERSION_ATLEAST(bmain, 280, 55)) {
for (bScreen *screen = bmain->screens.first; screen; screen = screen->id.next) {
- for (ScrArea *sa = screen->areabase.first; sa; sa = sa->next) {
- for (SpaceLink *sl = sa->spacedata.first; sl; sl = sl->next) {
+ LISTBASE_FOREACH (ScrArea *, area, &screen->areabase) {
+ LISTBASE_FOREACH (SpaceLink *, sl, &area->spacedata) {
if (sl->spacetype == SPACE_TEXT) {
- ListBase *regionbase = (sl == sa->spacedata.first) ? &sa->regionbase : &sl->regionbase;
+ ListBase *regionbase = (sl == area->spacedata.first) ? &area->regionbase :
+ &sl->regionbase;
/* Remove multiple footers that were added by mistake. */
do_versions_remove_regions_by_type(regionbase, RGN_TYPE_FOOTER);
@@ -3711,8 +3785,8 @@ void blo_do_versions_280(FileData *fd, Library *UNUSED(lib), Main *bmain)
ARegion *region = do_versions_add_region(RGN_TYPE_FOOTER, "footer for text");
region->alignment = (U.uiflag & USER_HEADER_BOTTOM) ? RGN_ALIGN_TOP : RGN_ALIGN_BOTTOM;
- ARegion *ar_header = do_versions_find_region(regionbase, RGN_TYPE_HEADER);
- BLI_insertlinkafter(regionbase, ar_header, region);
+ ARegion *region_header = do_versions_find_region(regionbase, RGN_TYPE_HEADER);
+ BLI_insertlinkafter(regionbase, region_header, region);
}
}
}
@@ -3721,8 +3795,8 @@ void blo_do_versions_280(FileData *fd, Library *UNUSED(lib), Main *bmain)
if (!MAIN_VERSION_ATLEAST(bmain, 280, 56)) {
for (bScreen *screen = bmain->screens.first; screen; screen = screen->id.next) {
- for (ScrArea *area = screen->areabase.first; area; area = area->next) {
- for (SpaceLink *sl = area->spacedata.first; sl; sl = sl->next) {
+ LISTBASE_FOREACH (ScrArea *, area, &screen->areabase) {
+ LISTBASE_FOREACH (SpaceLink *, sl, &area->spacedata) {
if (sl->spacetype == SPACE_VIEW3D) {
View3D *v3d = (View3D *)sl;
v3d->gizmo_show_armature = V3D_GIZMO_SHOW_ARMATURE_BBONE |
@@ -3739,8 +3813,8 @@ void blo_do_versions_280(FileData *fd, Library *UNUSED(lib), Main *bmain)
if (!MAIN_VERSION_ATLEAST(bmain, 280, 57)) {
/* Enable Show Interpolation in dopesheet by default. */
for (bScreen *screen = bmain->screens.first; screen; screen = screen->id.next) {
- for (ScrArea *sa = screen->areabase.first; sa; sa = sa->next) {
- for (SpaceLink *sl = sa->spacedata.first; sl; sl = sl->next) {
+ LISTBASE_FOREACH (ScrArea *, area, &screen->areabase) {
+ LISTBASE_FOREACH (SpaceLink *, sl, &area->spacedata) {
if (sl->spacetype == SPACE_ACTION) {
SpaceAction *saction = (SpaceAction *)sl;
if ((saction->flag & SACTION_SHOW_EXTREMES) == 0) {
@@ -3778,8 +3852,8 @@ void blo_do_versions_280(FileData *fd, Library *UNUSED(lib), Main *bmain)
/* enable the axis aligned ortho grid by default */
for (bScreen *screen = bmain->screens.first; screen; screen = screen->id.next) {
- for (ScrArea *area = screen->areabase.first; area; area = area->next) {
- for (SpaceLink *sl = area->spacedata.first; sl; sl = sl->next) {
+ LISTBASE_FOREACH (ScrArea *, area, &screen->areabase) {
+ LISTBASE_FOREACH (SpaceLink *, sl, &area->spacedata) {
if (sl->spacetype == SPACE_VIEW3D) {
View3D *v3d = (View3D *)sl;
v3d->gridflag |= V3D_SHOW_ORTHO_GRID;
@@ -3792,9 +3866,10 @@ void blo_do_versions_280(FileData *fd, Library *UNUSED(lib), Main *bmain)
/* Keep un-versioned until we're finished adding space types. */
{
for (bScreen *screen = bmain->screens.first; screen; screen = screen->id.next) {
- for (ScrArea *sa = screen->areabase.first; sa; sa = sa->next) {
- for (SpaceLink *sl = sa->spacedata.first; sl; sl = sl->next) {
- ListBase *regionbase = (sl == sa->spacedata.first) ? &sa->regionbase : &sl->regionbase;
+ LISTBASE_FOREACH (ScrArea *, area, &screen->areabase) {
+ LISTBASE_FOREACH (SpaceLink *, sl, &area->spacedata) {
+ ListBase *regionbase = (sl == area->spacedata.first) ? &area->regionbase :
+ &sl->regionbase;
/* All spaces that use tools must be eventually added. */
ARegion *region = NULL;
if (ELEM(sl->spacetype, SPACE_VIEW3D, SPACE_IMAGE, SPACE_SEQ) &&
@@ -3804,8 +3879,8 @@ void blo_do_versions_280(FileData *fd, Library *UNUSED(lib), Main *bmain)
region = do_versions_add_region(RGN_TYPE_TOOL_HEADER, "tool header");
region->alignment = (U.uiflag & USER_HEADER_BOTTOM) ? RGN_ALIGN_BOTTOM : RGN_ALIGN_TOP;
- ARegion *ar_header = do_versions_find_region(regionbase, RGN_TYPE_HEADER);
- BLI_insertlinkbefore(regionbase, ar_header, region);
+ ARegion *region_header = do_versions_find_region(regionbase, RGN_TYPE_HEADER);
+ BLI_insertlinkbefore(regionbase, region_header, region);
/* Hide by default, enable for painting workspaces (startup only). */
region->flag |= RGN_FLAG_HIDDEN | RGN_FLAG_HIDDEN_BY_USER;
}
@@ -3822,8 +3897,8 @@ void blo_do_versions_280(FileData *fd, Library *UNUSED(lib), Main *bmain)
if (!DNA_struct_elem_find(fd->filesdna, "bSplineIKConstraint", "short", "yScaleMode")) {
for (Object *ob = bmain->objects.first; ob; ob = ob->id.next) {
if (ob->pose) {
- for (bPoseChannel *pchan = ob->pose->chanbase.first; pchan; pchan = pchan->next) {
- for (bConstraint *con = pchan->constraints.first; con; con = con->next) {
+ LISTBASE_FOREACH (bPoseChannel *, pchan, &ob->pose->chanbase) {
+ LISTBASE_FOREACH (bConstraint *, con, &pchan->constraints) {
if (con->type == CONSTRAINT_TYPE_SPLINEIK) {
bSplineIKConstraint *data = (bSplineIKConstraint *)con->data;
if ((data->flag & CONSTRAINT_SPLINEIK_SCALE_LIMITED) == 0) {
@@ -3839,8 +3914,8 @@ void blo_do_versions_280(FileData *fd, Library *UNUSED(lib), Main *bmain)
if (!DNA_struct_elem_find(
fd->filesdna, "View3DOverlay", "float", "sculpt_mode_mask_opacity")) {
for (bScreen *screen = bmain->screens.first; screen; screen = screen->id.next) {
- for (ScrArea *sa = screen->areabase.first; sa; sa = sa->next) {
- for (SpaceLink *sl = sa->spacedata.first; sl; sl = sl->next) {
+ LISTBASE_FOREACH (ScrArea *, area, &screen->areabase) {
+ LISTBASE_FOREACH (SpaceLink *, sl, &area->spacedata) {
if (sl->spacetype == SPACE_VIEW3D) {
View3D *v3d = (View3D *)sl;
v3d->overlay.sculpt_mode_mask_opacity = 0.75f;
@@ -3903,10 +3978,11 @@ void blo_do_versions_280(FileData *fd, Library *UNUSED(lib), Main *bmain)
}
for (bScreen *screen = bmain->screens.first; screen; screen = screen->id.next) {
- for (ScrArea *sa = screen->areabase.first; sa; sa = sa->next) {
- for (SpaceLink *sl = sa->spacedata.first; sl; sl = sl->next) {
+ LISTBASE_FOREACH (ScrArea *, area, &screen->areabase) {
+ LISTBASE_FOREACH (SpaceLink *, sl, &area->spacedata) {
if (ELEM(sl->spacetype, SPACE_CLIP, SPACE_GRAPH, SPACE_SEQ)) {
- ListBase *regionbase = (sl == sa->spacedata.first) ? &sa->regionbase : &sl->regionbase;
+ ListBase *regionbase = (sl == area->spacedata.first) ? &area->regionbase :
+ &sl->regionbase;
ARegion *region = NULL;
if (sl->spacetype == SPACE_CLIP) {
@@ -3928,8 +4004,8 @@ void blo_do_versions_280(FileData *fd, Library *UNUSED(lib), Main *bmain)
}
for (bScreen *screen = bmain->screens.first; screen; screen = screen->id.next) {
- for (ScrArea *area = screen->areabase.first; area; area = area->next) {
- for (SpaceLink *sl = area->spacedata.first; sl; sl = sl->next) {
+ LISTBASE_FOREACH (ScrArea *, area, &screen->areabase) {
+ LISTBASE_FOREACH (SpaceLink *, sl, &area->spacedata) {
if (sl->spacetype != SPACE_OUTLINER) {
continue;
}
@@ -4039,7 +4115,7 @@ void blo_do_versions_280(FileData *fd, Library *UNUSED(lib), Main *bmain)
if (!MAIN_VERSION_ATLEAST(bmain, 281, 1)) {
LISTBASE_FOREACH (Object *, ob, &bmain->objects) {
- for (ModifierData *md = ob->modifiers.first; md; md = md->next) {
+ LISTBASE_FOREACH (ModifierData *, md, &ob->modifiers) {
if (md->type == eModifierType_DataTransfer) {
/* Now datatransfer's mix factor is multiplied with weights when any,
* instead of being ignored,
@@ -4055,10 +4131,11 @@ void blo_do_versions_280(FileData *fd, Library *UNUSED(lib), Main *bmain)
if (!MAIN_VERSION_ATLEAST(bmain, 281, 3)) {
for (bScreen *screen = bmain->screens.first; screen; screen = screen->id.next) {
- for (ScrArea *sa = screen->areabase.first; sa; sa = sa->next) {
- for (SpaceLink *sl = sa->spacedata.first; sl; sl = sl->next) {
+ LISTBASE_FOREACH (ScrArea *, area, &screen->areabase) {
+ LISTBASE_FOREACH (SpaceLink *, sl, &area->spacedata) {
if (sl->spacetype == SPACE_TEXT) {
- ListBase *regionbase = (sl == sa->spacedata.first) ? &sa->regionbase : &sl->regionbase;
+ ListBase *regionbase = (sl == area->spacedata.first) ? &area->regionbase :
+ &sl->regionbase;
ARegion *region = do_versions_find_region_or_null(regionbase, RGN_TYPE_UI);
if (region) {
region->alignment = RGN_ALIGN_RIGHT;
@@ -4109,14 +4186,14 @@ void blo_do_versions_280(FileData *fd, Library *UNUSED(lib), Main *bmain)
if (!MAIN_VERSION_ATLEAST(bmain, 281, 6)) {
for (bScreen *screen = bmain->screens.first; screen; screen = screen->id.next) {
- for (ScrArea *sa = screen->areabase.first; sa; sa = sa->next) {
- for (SpaceLink *sl = sa->spacedata.first; sl; sl = sl->next) {
+ LISTBASE_FOREACH (ScrArea *, area, &screen->areabase) {
+ LISTBASE_FOREACH (SpaceLink *, sl, &area->spacedata) {
if (sl->spacetype == SPACE_VIEW3D) {
View3D *v3d = (View3D *)sl;
v3d->shading.flag |= V3D_SHADING_SCENE_LIGHTS_RENDER | V3D_SHADING_SCENE_WORLD_RENDER;
/* files by default don't have studio lights selected unless interacted
- * with the shading popover. When no studiolight could be read, we will
+ * with the shading popover. When no studio-light could be read, we will
* select the default world one. */
StudioLight *studio_light = BKE_studiolight_find(v3d->shading.lookdev_light,
STUDIOLIGHT_TYPE_WORLD);
@@ -4131,29 +4208,31 @@ void blo_do_versions_280(FileData *fd, Library *UNUSED(lib), Main *bmain)
if (!MAIN_VERSION_ATLEAST(bmain, 281, 9)) {
for (bScreen *screen = bmain->screens.first; screen; screen = screen->id.next) {
- for (ScrArea *sa = screen->areabase.first; sa; sa = sa->next) {
- for (SpaceLink *sl = sa->spacedata.first; sl; sl = sl->next) {
+ LISTBASE_FOREACH (ScrArea *, area, &screen->areabase) {
+ LISTBASE_FOREACH (SpaceLink *, sl, &area->spacedata) {
if (sl->spacetype == SPACE_FILE) {
SpaceFile *sfile = (SpaceFile *)sl;
- ListBase *regionbase = (sl == sa->spacedata.first) ? &sa->regionbase : &sl->regionbase;
- ARegion *ar_ui = do_versions_find_region(regionbase, RGN_TYPE_UI);
- ARegion *ar_header = do_versions_find_region(regionbase, RGN_TYPE_HEADER);
- ARegion *ar_toolprops = do_versions_find_region_or_null(regionbase,
- RGN_TYPE_TOOL_PROPS);
+ ListBase *regionbase = (sl == area->spacedata.first) ? &area->regionbase :
+ &sl->regionbase;
+ ARegion *region_ui = do_versions_find_region(regionbase, RGN_TYPE_UI);
+ ARegion *region_header = do_versions_find_region(regionbase, RGN_TYPE_HEADER);
+ ARegion *region_toolprops = do_versions_find_region_or_null(regionbase,
+ RGN_TYPE_TOOL_PROPS);
/* Reinsert UI region so that it spawns entire area width */
- BLI_remlink(regionbase, ar_ui);
- BLI_insertlinkafter(regionbase, ar_header, ar_ui);
+ BLI_remlink(regionbase, region_ui);
+ BLI_insertlinkafter(regionbase, region_header, region_ui);
- ar_ui->flag |= RGN_FLAG_DYNAMIC_SIZE;
+ region_ui->flag |= RGN_FLAG_DYNAMIC_SIZE;
- if (ar_toolprops && (ar_toolprops->alignment == (RGN_ALIGN_BOTTOM | RGN_SPLIT_PREV))) {
+ if (region_toolprops &&
+ (region_toolprops->alignment == (RGN_ALIGN_BOTTOM | RGN_SPLIT_PREV))) {
SpaceType *stype = BKE_spacetype_from_id(sl->spacetype);
/* Remove empty region at old location. */
BLI_assert(sfile->op == NULL);
- BKE_area_region_free(stype, ar_toolprops);
- BLI_freelinkN(regionbase, ar_toolprops);
+ BKE_area_region_free(stype, region_toolprops);
+ BLI_freelinkN(regionbase, region_toolprops);
}
if (sfile->params) {
@@ -4183,11 +4262,11 @@ void blo_do_versions_280(FileData *fd, Library *UNUSED(lib), Main *bmain)
}
}
- /* Added studiolight intensity */
+ /* Added studio-light intensity. */
if (!DNA_struct_elem_find(fd->filesdna, "View3DShading", "float", "studiolight_intensity")) {
for (bScreen *screen = bmain->screens.first; screen; screen = screen->id.next) {
- for (ScrArea *sa = screen->areabase.first; sa; sa = sa->next) {
- for (SpaceLink *sl = sa->spacedata.first; sl; sl = sl->next) {
+ LISTBASE_FOREACH (ScrArea *, area, &screen->areabase) {
+ LISTBASE_FOREACH (SpaceLink *, sl, &area->spacedata) {
if (sl->spacetype == SPACE_VIEW3D) {
View3D *v3d = (View3D *)sl;
v3d->shading.studiolight_intensity = 1.0f;
@@ -4224,14 +4303,13 @@ void blo_do_versions_280(FileData *fd, Library *UNUSED(lib), Main *bmain)
}
for (bScreen *screen = bmain->screens.first; screen; screen = screen->id.next) {
- for (ScrArea *sa = screen->areabase.first; sa; sa = sa->next) {
- for (SpaceLink *sl = sa->spacedata.first; sl; sl = sl->next) {
+ LISTBASE_FOREACH (ScrArea *, area, &screen->areabase) {
+ LISTBASE_FOREACH (SpaceLink *, sl, &area->spacedata) {
if (sl->spacetype == SPACE_VIEW3D) {
View3D *v3d = (View3D *)sl;
- for (ScrArea *sa_other = screen->areabase.first; sa_other; sa_other = sa_other->next) {
- for (SpaceLink *sl_other = sa_other->spacedata.first; sl_other;
- sl_other = sl_other->next) {
+ LISTBASE_FOREACH (ScrArea *, area_other, &screen->areabase) {
+ LISTBASE_FOREACH (SpaceLink *, sl_other, &area_other->spacedata) {
if (sl != sl_other && sl_other->spacetype == SPACE_VIEW3D) {
View3D *v3d_other = (View3D *)sl_other;
@@ -4243,25 +4321,27 @@ void blo_do_versions_280(FileData *fd, Library *UNUSED(lib), Main *bmain)
}
}
else if (sl->spacetype == SPACE_FILE) {
- ListBase *regionbase = (sl == sa->spacedata.first) ? &sa->regionbase : &sl->regionbase;
- ARegion *ar_tools = do_versions_find_region_or_null(regionbase, RGN_TYPE_TOOLS);
- ARegion *ar_header = do_versions_find_region(regionbase, RGN_TYPE_HEADER);
+ ListBase *regionbase = (sl == area->spacedata.first) ? &area->regionbase :
+ &sl->regionbase;
+ ARegion *region_tools = do_versions_find_region_or_null(regionbase, RGN_TYPE_TOOLS);
+ ARegion *region_header = do_versions_find_region(regionbase, RGN_TYPE_HEADER);
- if (ar_tools) {
- ARegion *ar_next = ar_tools->next;
+ if (region_tools) {
+ ARegion *region_next = region_tools->next;
/* We temporarily had two tools regions, get rid of the second one. */
- if (ar_next && ar_next->regiontype == RGN_TYPE_TOOLS) {
- do_versions_remove_region(regionbase, ar_next);
+ if (region_next && region_next->regiontype == RGN_TYPE_TOOLS) {
+ do_versions_remove_region(regionbase, region_next);
}
- BLI_remlink(regionbase, ar_tools);
- BLI_insertlinkafter(regionbase, ar_header, ar_tools);
+ BLI_remlink(regionbase, region_tools);
+ BLI_insertlinkafter(regionbase, region_header, region_tools);
}
else {
- ar_tools = do_versions_add_region(RGN_TYPE_TOOLS, "versioning file tools region");
- BLI_insertlinkafter(regionbase, ar_header, ar_tools);
- ar_tools->alignment = RGN_ALIGN_LEFT;
+ region_tools = do_versions_add_region(RGN_TYPE_TOOLS,
+ "versioning file tools region");
+ BLI_insertlinkafter(regionbase, region_header, region_tools);
+ region_tools->alignment = RGN_ALIGN_LEFT;
}
}
}
@@ -4279,8 +4359,8 @@ void blo_do_versions_280(FileData *fd, Library *UNUSED(lib), Main *bmain)
do_version_curvemapping_walker(bmain, do_version_curvemapping_flag_extend_extrapolate);
for (bScreen *screen = bmain->screens.first; screen; screen = screen->id.next) {
- for (ScrArea *sa = screen->areabase.first; sa; sa = sa->next) {
- sa->flag &= ~AREA_FLAG_UNUSED_6;
+ LISTBASE_FOREACH (ScrArea *, area, &screen->areabase) {
+ area->flag &= ~AREA_FLAG_UNUSED_6;
}
}
@@ -4297,7 +4377,7 @@ void blo_do_versions_280(FileData *fd, Library *UNUSED(lib), Main *bmain)
/* Add custom curve profile to bevel modifier */
if (!DNA_struct_elem_find(fd->filesdna, "BevelModifier", "CurveProfile", "custom_profile")) {
for (Object *object = bmain->objects.first; object != NULL; object = object->id.next) {
- for (ModifierData *md = object->modifiers.first; md; md = md->next) {
+ LISTBASE_FOREACH (ModifierData *, md, &object->modifiers) {
if (md->type == eModifierType_Bevel) {
BevelModifierData *bmd = (BevelModifierData *)md;
if (!bmd->custom_profile) {
@@ -4325,7 +4405,7 @@ void blo_do_versions_280(FileData *fd, Library *UNUSED(lib), Main *bmain)
/* Cloth pressure */
for (Object *ob = bmain->objects.first; ob; ob = ob->id.next) {
- for (ModifierData *md = ob->modifiers.first; md; md = md->next) {
+ LISTBASE_FOREACH (ModifierData *, md, &ob->modifiers) {
if (md->type == eModifierType_Cloth) {
ClothModifierData *clmd = (ClothModifierData *)md;
@@ -4350,8 +4430,8 @@ void blo_do_versions_280(FileData *fd, Library *UNUSED(lib), Main *bmain)
}
for (bScreen *screen = bmain->screens.first; screen; screen = screen->id.next) {
- for (ScrArea *sa = screen->areabase.first; sa; sa = sa->next) {
- for (SpaceLink *sl = sa->spacedata.first; sl; sl = sl->next) {
+ LISTBASE_FOREACH (ScrArea *, area, &screen->areabase) {
+ LISTBASE_FOREACH (SpaceLink *, sl, &area->spacedata) {
if (sl->spacetype == SPACE_VIEW3D) {
View3D *v3d = (View3D *)sl;
v3d->shading.render_pass = SCE_PASS_COMBINED;
@@ -4363,8 +4443,8 @@ void blo_do_versions_280(FileData *fd, Library *UNUSED(lib), Main *bmain)
/* Make markers region visible by default. */
for (bScreen *screen = bmain->screens.first; screen; screen = screen->id.next) {
- for (ScrArea *area = screen->areabase.first; area; area = area->next) {
- for (SpaceLink *sl = area->spacedata.first; sl; sl = sl->next) {
+ LISTBASE_FOREACH (ScrArea *, area, &screen->areabase) {
+ LISTBASE_FOREACH (SpaceLink *, sl, &area->spacedata) {
switch (sl->spacetype) {
case SPACE_SEQ: {
SpaceSeq *sseq = (SpaceSeq *)sl;
@@ -4393,13 +4473,26 @@ void blo_do_versions_280(FileData *fd, Library *UNUSED(lib), Main *bmain)
}
if (!MAIN_VERSION_ATLEAST(bmain, 283, 3)) {
+ /* Color Management Look. */
+ for (Scene *scene = bmain->scenes.first; scene; scene = scene->id.next) {
+ ColorManagedViewSettings *view_settings;
+ view_settings = &scene->view_settings;
+ if (BLI_str_startswith(view_settings->look, "Filmic - ")) {
+ char *src = view_settings->look + strlen("Filmic - ");
+ memmove(view_settings->look, src, strlen(src) + 1);
+ }
+ else if (BLI_str_startswith(view_settings->look, "Standard - ")) {
+ char *src = view_settings->look + strlen("Standard - ");
+ memmove(view_settings->look, src, strlen(src) + 1);
+ }
+ }
/* Sequencer Tool region */
do_versions_area_ensure_tool_region(bmain, SPACE_SEQ, RGN_FLAG_HIDDEN);
/* Cloth internal springs */
for (Object *ob = bmain->objects.first; ob; ob = ob->id.next) {
- for (ModifierData *md = ob->modifiers.first; md; md = md->next) {
+ LISTBASE_FOREACH (ModifierData *, md, &ob->modifiers) {
if (md->type == eModifierType_Cloth) {
ClothModifierData *clmd = (ClothModifierData *)md;
@@ -4425,8 +4518,8 @@ void blo_do_versions_280(FileData *fd, Library *UNUSED(lib), Main *bmain)
/* UDIM Image Editor change. */
if (!DNA_struct_elem_find(fd->filesdna, "SpaceImage", "int", "tile_grid_shape[2]")) {
for (bScreen *screen = bmain->screens.first; screen; screen = screen->id.next) {
- for (ScrArea *sa = screen->areabase.first; sa; sa = sa->next) {
- for (SpaceLink *sl = sa->spacedata.first; sl; sl = sl->next) {
+ LISTBASE_FOREACH (ScrArea *, area, &screen->areabase) {
+ LISTBASE_FOREACH (SpaceLink *, sl, &area->spacedata) {
if (sl->spacetype == SPACE_IMAGE) {
SpaceImage *sima = (SpaceImage *)sl;
sima->tile_grid_shape[0] = 1;
@@ -4488,7 +4581,7 @@ void blo_do_versions_280(FileData *fd, Library *UNUSED(lib), Main *bmain)
/* Add 2D transform to UV Warp modifier. */
if (!DNA_struct_elem_find(fd->filesdna, "UVWarpModifierData", "float", "scale[2]")) {
for (Object *ob = bmain->objects.first; ob; ob = ob->id.next) {
- for (ModifierData *md = ob->modifiers.first; md; md = md->next) {
+ LISTBASE_FOREACH (ModifierData *, md, &ob->modifiers) {
if (md->type == eModifierType_UVWarp) {
UVWarpModifierData *umd = (UVWarpModifierData *)md;
copy_v2_fl(umd->scale, 1.0f);
@@ -4500,8 +4593,8 @@ void blo_do_versions_280(FileData *fd, Library *UNUSED(lib), Main *bmain)
/* Add Lookdev blur property. */
if (!DNA_struct_elem_find(fd->filesdna, "View3DShading", "float", "studiolight_blur")) {
for (bScreen *screen = bmain->screens.first; screen; screen = screen->id.next) {
- for (ScrArea *sa = screen->areabase.first; sa; sa = sa->next) {
- for (SpaceLink *sl = sa->spacedata.first; sl; sl = sl->next) {
+ LISTBASE_FOREACH (ScrArea *, area, &screen->areabase) {
+ LISTBASE_FOREACH (SpaceLink *, sl, &area->spacedata) {
if (sl->spacetype == SPACE_VIEW3D) {
View3D *v3d = (View3D *)sl;
v3d->shading.studiolight_blur = 0.5f;
@@ -4541,8 +4634,6 @@ void blo_do_versions_280(FileData *fd, Library *UNUSED(lib), Main *bmain)
brush->gpencil_weight_tool = brush->gpencil_settings->brush_type;
}
}
-
- BKE_paint_toolslots_init_from_main(bmain);
}
LISTBASE_FOREACH (Material *, mat, &bmain->materials) {
@@ -4774,8 +4865,8 @@ void blo_do_versions_280(FileData *fd, Library *UNUSED(lib), Main *bmain)
if (!DNA_struct_elem_find(
fd->filesdna, "View3DOverlay", "float", "sculpt_mode_face_sets_opacity")) {
for (bScreen *screen = bmain->screens.first; screen; screen = screen->id.next) {
- for (ScrArea *sa = screen->areabase.first; sa; sa = sa->next) {
- for (SpaceLink *sl = sa->spacedata.first; sl; sl = sl->next) {
+ LISTBASE_FOREACH (ScrArea *, area, &screen->areabase) {
+ LISTBASE_FOREACH (SpaceLink *, sl, &area->spacedata) {
if (sl->spacetype == SPACE_VIEW3D) {
View3D *v3d = (View3D *)sl;
v3d->overlay.sculpt_mode_face_sets_opacity = 1.0f;
@@ -4805,7 +4896,7 @@ void blo_do_versions_280(FileData *fd, Library *UNUSED(lib), Main *bmain)
/* Corrective smooth modifier scale*/
if (!DNA_struct_elem_find(fd->filesdna, "CorrectiveSmoothModifierData", "float", "scale")) {
for (Object *ob = bmain->objects.first; ob; ob = ob->id.next) {
- for (ModifierData *md = ob->modifiers.first; md; md = md->next) {
+ LISTBASE_FOREACH (ModifierData *, md, &ob->modifiers) {
if (md->type == eModifierType_CorrectiveSmooth) {
CorrectiveSmoothModifierData *csmd = (CorrectiveSmoothModifierData *)md;
csmd->scale = 1.0f;
@@ -4828,7 +4919,7 @@ void blo_do_versions_280(FileData *fd, Library *UNUSED(lib), Main *bmain)
if (!MAIN_VERSION_ATLEAST(bmain, 283, 11)) {
if (!DNA_struct_elem_find(fd->filesdna, "OceanModifierData", "float", "fetch_jonswap")) {
for (Object *object = bmain->objects.first; object != NULL; object = object->id.next) {
- for (ModifierData *md = object->modifiers.first; md; md = md->next) {
+ LISTBASE_FOREACH (ModifierData *, md, &object->modifiers) {
if (md->type == eModifierType_Ocean) {
OceanModifierData *omd = (OceanModifierData *)md;
omd->fetch_jonswap = 120.0f;
@@ -4852,6 +4943,125 @@ void blo_do_versions_280(FileData *fd, Library *UNUSED(lib), Main *bmain)
wm->xr.session_settings.flag = XR_SESSION_USE_POSITION_TRACKING;
}
}
+
+ /* Surface deform modifier strength*/
+ if (!DNA_struct_elem_find(fd->filesdna, "SurfaceDeformModifierData", "float", "strength")) {
+ for (Object *ob = bmain->objects.first; ob; ob = ob->id.next) {
+ LISTBASE_FOREACH (ModifierData *, md, &ob->modifiers) {
+ if (md->type == eModifierType_SurfaceDeform) {
+ SurfaceDeformModifierData *sdmd = (SurfaceDeformModifierData *)md;
+ sdmd->strength = 1.0f;
+ }
+ }
+ }
+ }
+ }
+
+ if (!MAIN_VERSION_ATLEAST(bmain, 283, 12)) {
+ /* Activate f-curve drawing in the sequencer. */
+ for (bScreen *screen = bmain->screens.first; screen; screen = screen->id.next) {
+ for (ScrArea *area = screen->areabase.first; area; area = area->next) {
+ for (SpaceLink *sl = area->spacedata.first; sl; sl = sl->next) {
+ if (sl->spacetype == SPACE_SEQ) {
+ SpaceSeq *sseq = (SpaceSeq *)sl;
+ sseq->flag |= SEQ_SHOW_FCURVES;
+ }
+ }
+ }
+ }
+
+ /* Remesh Modifier Voxel Mode. */
+ if (!DNA_struct_elem_find(fd->filesdna, "RemeshModifierData", "float", "voxel_size")) {
+ for (Object *ob = bmain->objects.first; ob; ob = ob->id.next) {
+ LISTBASE_FOREACH (ModifierData *, md, &ob->modifiers) {
+ if (md->type == eModifierType_Remesh) {
+ RemeshModifierData *rmd = (RemeshModifierData *)md;
+ rmd->voxel_size = 0.1f;
+ rmd->adaptivity = 0.0f;
+ }
+ }
+ }
+ }
+ }
+
+ if (!MAIN_VERSION_ATLEAST(bmain, 283, 14)) {
+ /* Solidify modifier merge tolerance. */
+ if (!DNA_struct_elem_find(fd->filesdna, "SolidifyModifierData", "float", "merge_tolerance")) {
+ for (Object *ob = bmain->objects.first; ob; ob = ob->id.next) {
+ for (ModifierData *md = ob->modifiers.first; md; md = md->next) {
+ if (md->type == eModifierType_Solidify) {
+ SolidifyModifierData *smd = (SolidifyModifierData *)md;
+ /* set to 0.0003 since that is what was used before, default now is 0.0001 */
+ smd->merge_tolerance = 0.0003f;
+ }
+ }
+ }
+ }
+
+ /* Enumerator was incorrect for a time in 2.83 development.
+ * Note that this only corrects values known to be invalid. */
+ for (Object *ob = bmain->objects.first; ob; ob = ob->id.next) {
+ RigidBodyCon *rbc = ob->rigidbody_constraint;
+ if (rbc != NULL) {
+ enum {
+ INVALID_RBC_TYPE_SLIDER = 2,
+ INVALID_RBC_TYPE_6DOF_SPRING = 4,
+ INVALID_RBC_TYPE_MOTOR = 7,
+ };
+ switch (rbc->type) {
+ case INVALID_RBC_TYPE_SLIDER:
+ rbc->type = RBC_TYPE_SLIDER;
+ break;
+ case INVALID_RBC_TYPE_6DOF_SPRING:
+ rbc->type = RBC_TYPE_6DOF_SPRING;
+ break;
+ case INVALID_RBC_TYPE_MOTOR:
+ rbc->type = RBC_TYPE_MOTOR;
+ break;
+ }
+ }
+ }
+ }
+
+ /* Match scale of fluid modifier gravity with scene gravity. */
+ if (!MAIN_VERSION_ATLEAST(bmain, 283, 15)) {
+ for (Object *ob = bmain->objects.first; ob; ob = ob->id.next) {
+ for (ModifierData *md = ob->modifiers.first; md; md = md->next) {
+ if (md->type == eModifierType_Fluid) {
+ FluidModifierData *fmd = (FluidModifierData *)md;
+ if (fmd->domain != NULL) {
+ mul_v3_fl(fmd->domain->gravity, 9.81f);
+ }
+ }
+ }
+ }
+ }
+
+ if (!MAIN_VERSION_ATLEAST(bmain, 283, 16)) {
+ /* Init SMAA threshold for grease pencil render. */
+ LISTBASE_FOREACH (Scene *, scene, &bmain->scenes) {
+ scene->grease_pencil_settings.smaa_threshold = 1.0f;
+ }
+ }
+
+ if (!MAIN_VERSION_ATLEAST(bmain, 283, 17)) {
+ /* Reset the cloth mass to 1.0 in brushes with an invalid value. */
+ for (Brush *br = bmain->brushes.first; br; br = br->id.next) {
+ if (br->sculpt_tool == SCULPT_TOOL_CLOTH) {
+ if (br->cloth_mass == 0.0f) {
+ br->cloth_mass = 1.0f;
+ }
+ }
+ }
+
+ /* Set Brush default color for grease pencil. */
+ LISTBASE_FOREACH (Brush *, brush, &bmain->brushes) {
+ if (brush->gpencil_settings) {
+ brush->rgb[0] = 0.498f;
+ brush->rgb[1] = 1.0f;
+ brush->rgb[2] = 0.498f;
+ }
+ }
}
/**
diff --git a/source/blender/blenloader/intern/versioning_290.c b/source/blender/blenloader/intern/versioning_290.c
new file mode 100644
index 00000000000..ed23b69c623
--- /dev/null
+++ b/source/blender/blenloader/intern/versioning_290.c
@@ -0,0 +1,270 @@
+/*
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+
+/** \file
+ * \ingroup blenloader
+ */
+/* allow readfile to use deprecated functionality */
+#define DNA_DEPRECATED_ALLOW
+
+#include "BLI_listbase.h"
+#include "BLI_utildefines.h"
+
+#include "DNA_brush_types.h"
+#include "DNA_genfile.h"
+#include "DNA_gpencil_modifier_types.h"
+#include "DNA_modifier_types.h"
+#include "DNA_object_types.h"
+#include "DNA_screen_types.h"
+
+#include "BKE_collection.h"
+#include "BKE_colortools.h"
+#include "BKE_lib_id.h"
+#include "BKE_main.h"
+
+#include "BLO_readfile.h"
+#include "readfile.h"
+
+/* Make preferences read-only, use versioning_userdef.c. */
+#define U (*((const UserDef *)&U))
+
+void do_versions_after_linking_290(Main *bmain, ReportList *UNUSED(reports))
+{
+ if (!MAIN_VERSION_ATLEAST(bmain, 290, 1)) {
+ /* Patch old grease pencil modifiers material filter. */
+ LISTBASE_FOREACH (Object *, ob, &bmain->objects) {
+ LISTBASE_FOREACH (GpencilModifierData *, md, &ob->greasepencil_modifiers) {
+ switch (md->type) {
+ case eGpencilModifierType_Array: {
+ ArrayGpencilModifierData *gpmd = (ArrayGpencilModifierData *)md;
+ if (gpmd->materialname[0] != '\0') {
+ gpmd->material = BLI_findstring(
+ &bmain->materials, gpmd->materialname, offsetof(ID, name) + 2);
+ gpmd->materialname[0] = '\0';
+ }
+ break;
+ }
+ case eGpencilModifierType_Color: {
+ ColorGpencilModifierData *gpmd = (ColorGpencilModifierData *)md;
+ if (gpmd->materialname[0] != '\0') {
+ gpmd->material = BLI_findstring(
+ &bmain->materials, gpmd->materialname, offsetof(ID, name) + 2);
+ gpmd->materialname[0] = '\0';
+ }
+ break;
+ }
+ case eGpencilModifierType_Hook: {
+ HookGpencilModifierData *gpmd = (HookGpencilModifierData *)md;
+ if (gpmd->materialname[0] != '\0') {
+ gpmd->material = BLI_findstring(
+ &bmain->materials, gpmd->materialname, offsetof(ID, name) + 2);
+ gpmd->materialname[0] = '\0';
+ }
+ break;
+ }
+ case eGpencilModifierType_Lattice: {
+ LatticeGpencilModifierData *gpmd = (LatticeGpencilModifierData *)md;
+ if (gpmd->materialname[0] != '\0') {
+ gpmd->material = BLI_findstring(
+ &bmain->materials, gpmd->materialname, offsetof(ID, name) + 2);
+ gpmd->materialname[0] = '\0';
+ }
+ break;
+ }
+ case eGpencilModifierType_Mirror: {
+ MirrorGpencilModifierData *gpmd = (MirrorGpencilModifierData *)md;
+ if (gpmd->materialname[0] != '\0') {
+ gpmd->material = BLI_findstring(
+ &bmain->materials, gpmd->materialname, offsetof(ID, name) + 2);
+ gpmd->materialname[0] = '\0';
+ }
+ break;
+ }
+ case eGpencilModifierType_Multiply: {
+ MultiplyGpencilModifierData *gpmd = (MultiplyGpencilModifierData *)md;
+ if (gpmd->materialname[0] != '\0') {
+ gpmd->material = BLI_findstring(
+ &bmain->materials, gpmd->materialname, offsetof(ID, name) + 2);
+ gpmd->materialname[0] = '\0';
+ }
+ break;
+ }
+ case eGpencilModifierType_Noise: {
+ NoiseGpencilModifierData *gpmd = (NoiseGpencilModifierData *)md;
+ if (gpmd->materialname[0] != '\0') {
+ gpmd->material = BLI_findstring(
+ &bmain->materials, gpmd->materialname, offsetof(ID, name) + 2);
+ gpmd->materialname[0] = '\0';
+ }
+ break;
+ }
+ case eGpencilModifierType_Offset: {
+ OffsetGpencilModifierData *gpmd = (OffsetGpencilModifierData *)md;
+ if (gpmd->materialname[0] != '\0') {
+ gpmd->material = BLI_findstring(
+ &bmain->materials, gpmd->materialname, offsetof(ID, name) + 2);
+ gpmd->materialname[0] = '\0';
+ }
+ break;
+ }
+ case eGpencilModifierType_Opacity: {
+ OpacityGpencilModifierData *gpmd = (OpacityGpencilModifierData *)md;
+ if (gpmd->materialname[0] != '\0') {
+ gpmd->material = BLI_findstring(
+ &bmain->materials, gpmd->materialname, offsetof(ID, name) + 2);
+ gpmd->materialname[0] = '\0';
+ }
+ break;
+ }
+ case eGpencilModifierType_Simplify: {
+ SimplifyGpencilModifierData *gpmd = (SimplifyGpencilModifierData *)md;
+ if (gpmd->materialname[0] != '\0') {
+ gpmd->material = BLI_findstring(
+ &bmain->materials, gpmd->materialname, offsetof(ID, name) + 2);
+ gpmd->materialname[0] = '\0';
+ }
+ break;
+ }
+ case eGpencilModifierType_Smooth: {
+ SmoothGpencilModifierData *gpmd = (SmoothGpencilModifierData *)md;
+ if (gpmd->materialname[0] != '\0') {
+ gpmd->material = BLI_findstring(
+ &bmain->materials, gpmd->materialname, offsetof(ID, name) + 2);
+ gpmd->materialname[0] = '\0';
+ }
+ break;
+ }
+ case eGpencilModifierType_Subdiv: {
+ SubdivGpencilModifierData *gpmd = (SubdivGpencilModifierData *)md;
+ if (gpmd->materialname[0] != '\0') {
+ gpmd->material = BLI_findstring(
+ &bmain->materials, gpmd->materialname, offsetof(ID, name) + 2);
+ gpmd->materialname[0] = '\0';
+ }
+ break;
+ }
+ case eGpencilModifierType_Texture: {
+ TextureGpencilModifierData *gpmd = (TextureGpencilModifierData *)md;
+ if (gpmd->materialname[0] != '\0') {
+ gpmd->material = BLI_findstring(
+ &bmain->materials, gpmd->materialname, offsetof(ID, name) + 2);
+ gpmd->materialname[0] = '\0';
+ }
+ break;
+ }
+ case eGpencilModifierType_Thick: {
+ ThickGpencilModifierData *gpmd = (ThickGpencilModifierData *)md;
+ if (gpmd->materialname[0] != '\0') {
+ gpmd->material = BLI_findstring(
+ &bmain->materials, gpmd->materialname, offsetof(ID, name) + 2);
+ gpmd->materialname[0] = '\0';
+ }
+ break;
+ }
+ default:
+ break;
+ }
+ }
+ }
+ }
+
+ /**
+ * Versioning code until next subversion bump goes here.
+ *
+ * \note Be sure to check when bumping the version:
+ * - #blo_do_versions_290 in this file.
+ * - "versioning_userdef.c", #BLO_version_defaults_userpref_blend
+ * - "versioning_userdef.c", #do_versions_theme
+ *
+ * \note Keep this message at the bottom of the function.
+ */
+ {
+ /* Keep this block, even when empty. */
+ }
+}
+
+void blo_do_versions_290(FileData *fd, Library *UNUSED(lib), Main *bmain)
+{
+ UNUSED_VARS(fd);
+
+ /** Repair files from duplicate brushes added to blend files, see: T76738. */
+ if (!MAIN_VERSION_ATLEAST(bmain, 290, 2)) {
+ {
+ short id_codes[] = {ID_BR, ID_PAL};
+ for (int i = 0; i < ARRAY_SIZE(id_codes); i++) {
+ ListBase *lb = which_libbase(bmain, id_codes[i]);
+ BKE_main_id_repair_duplicate_names_listbase(lb);
+ }
+ }
+
+ if (!DNA_struct_elem_find(fd->filesdna, "SpaceImage", "float", "uv_opacity")) {
+ for (bScreen *screen = bmain->screens.first; screen; screen = screen->id.next) {
+ LISTBASE_FOREACH (ScrArea *, area, &screen->areabase) {
+ LISTBASE_FOREACH (SpaceLink *, sl, &area->spacedata) {
+ if (sl->spacetype == SPACE_IMAGE) {
+ SpaceImage *sima = (SpaceImage *)sl;
+ sima->uv_opacity = 1.0f;
+ }
+ }
+ }
+ }
+ }
+
+ /* Init Grease Pencil new random curves. */
+ if (!DNA_struct_elem_find(fd->filesdna, "BrushGpencilSettings", "float", "random_hue")) {
+ LISTBASE_FOREACH (Brush *, brush, &bmain->brushes) {
+ if ((brush->gpencil_settings) && (brush->gpencil_settings->curve_rand_pressure == NULL)) {
+ brush->gpencil_settings->curve_rand_pressure = BKE_curvemapping_add(
+ 1, 0.0f, 0.0f, 1.0f, 1.0f);
+ brush->gpencil_settings->curve_rand_strength = BKE_curvemapping_add(
+ 1, 0.0f, 0.0f, 1.0f, 1.0f);
+ brush->gpencil_settings->curve_rand_uv = BKE_curvemapping_add(1, 0.0f, 0.0f, 1.0f, 1.0f);
+ brush->gpencil_settings->curve_rand_hue = BKE_curvemapping_add(
+ 1, 0.0f, 0.0f, 1.0f, 1.0f);
+ brush->gpencil_settings->curve_rand_saturation = BKE_curvemapping_add(
+ 1, 0.0f, 0.0f, 1.0f, 1.0f);
+ brush->gpencil_settings->curve_rand_value = BKE_curvemapping_add(
+ 1, 0.0f, 0.0f, 1.0f, 1.0f);
+ }
+ }
+ }
+ }
+
+ if (!MAIN_VERSION_ATLEAST(bmain, 290, 4)) {
+ /* Clear old deprecated bit-flag from edit weights modifiers, we now use it for something else.
+ */
+ LISTBASE_FOREACH (Object *, ob, &bmain->objects) {
+ LISTBASE_FOREACH (ModifierData *, md, &ob->modifiers) {
+ if (md->type == eModifierType_WeightVGEdit) {
+ ((WeightVGEditModifierData *)md)->edit_flags &= ~MOD_WVG_EDIT_WEIGHTS_NORMALIZE;
+ }
+ }
+ }
+ }
+
+ /**
+ * Versioning code until next subversion bump goes here.
+ *
+ * \note Be sure to check when bumping the version:
+ * - "versioning_userdef.c", #BLO_version_defaults_userpref_blend
+ * - "versioning_userdef.c", #do_versions_theme
+ *
+ * \note Keep this message at the bottom of the function.
+ */
+ {
+ /* Keep this block, even when empty. */
+ }
+}
diff --git a/source/blender/blenloader/intern/versioning_cycles.c b/source/blender/blenloader/intern/versioning_cycles.c
index 14a940b9297..ff3d4574561 100644
--- a/source/blender/blenloader/intern/versioning_cycles.c
+++ b/source/blender/blenloader/intern/versioning_cycles.c
@@ -173,7 +173,7 @@ static void square_roughness_node_insert(bNodeTree *ntree)
bool need_update = false;
/* Update default values */
- for (bNode *node = ntree->nodes.first; node; node = node->next) {
+ LISTBASE_FOREACH (bNode *, node, &ntree->nodes) {
if (node_has_roughness(node)) {
bNodeSocket *roughness_input = nodeFindSocket(node, SOCK_IN, "Roughness");
float *roughness_value = cycles_node_socket_float_value(roughness_input);
@@ -256,7 +256,7 @@ static void ambient_occlusion_node_relink(bNodeTree *ntree)
bool need_update = false;
/* Set default values. */
- for (bNode *node = ntree->nodes.first; node; node = node->next) {
+ LISTBASE_FOREACH (bNode *, node, &ntree->nodes) {
if (node->type == SH_NODE_AMBIENT_OCCLUSION) {
node->custom1 = 1; /* samples */
node->custom2 &= ~SHD_AO_LOCAL;
@@ -338,7 +338,7 @@ static void light_emission_node_to_energy(Light *light, float *energy, float col
}
bNode *emission_node = NULL;
- for (bNodeLink *link = ntree->links.first; link; link = link->next) {
+ LISTBASE_FOREACH (bNodeLink *, link, &ntree->links) {
if (link->tonode == output_node && link->fromnode->type == SH_NODE_EMISSION) {
emission_node = link->fromnode;
break;
@@ -410,7 +410,7 @@ static void update_math_node_single_operand_operators(bNodeTree *ntree)
{
bool need_update = false;
- for (bNode *node = ntree->nodes.first; node; node = node->next) {
+ LISTBASE_FOREACH (bNode *, node, &ntree->nodes) {
if (node->type == SH_NODE_MATH) {
if (ELEM(node->custom1,
NODE_MATH_SQRT,
@@ -459,7 +459,7 @@ static void update_vector_math_node_add_and_subtract_operators(bNodeTree *ntree)
{
bool need_update = false;
- for (bNode *node = ntree->nodes.first; node; node = node->next) {
+ LISTBASE_FOREACH (bNode *, node, &ntree->nodes) {
if (node->type == SH_NODE_VECTOR_MATH) {
bNodeSocket *sockOutValue = nodeFindSocket(node, SOCK_OUT, "Value");
if (socket_is_used(sockOutValue) &&
@@ -511,7 +511,7 @@ static void update_vector_math_node_dot_product_operator(bNodeTree *ntree)
{
bool need_update = false;
- for (bNode *node = ntree->nodes.first; node; node = node->next) {
+ LISTBASE_FOREACH (bNode *, node, &ntree->nodes) {
if (node->type == SH_NODE_VECTOR_MATH) {
bNodeSocket *sockOutVector = nodeFindSocket(node, SOCK_OUT, "Vector");
if (socket_is_used(sockOutVector) && node->custom1 == NODE_VECTOR_MATH_DOT_PRODUCT) {
@@ -550,7 +550,7 @@ static void update_vector_math_node_cross_product_operator(bNodeTree *ntree)
{
bool need_update = false;
- for (bNode *node = ntree->nodes.first; node; node = node->next) {
+ LISTBASE_FOREACH (bNode *, node, &ntree->nodes) {
if (node->type == SH_NODE_VECTOR_MATH) {
if (node->custom1 == NODE_VECTOR_MATH_CROSS_PRODUCT) {
bNodeSocket *sockOutVector = nodeFindSocket(node, SOCK_OUT, "Vector");
@@ -616,7 +616,7 @@ static void update_vector_math_node_normalize_operator(bNodeTree *ntree)
{
bool need_update = false;
- for (bNode *node = ntree->nodes.first; node; node = node->next) {
+ LISTBASE_FOREACH (bNode *, node, &ntree->nodes) {
if (node->type == SH_NODE_VECTOR_MATH) {
bNodeSocket *sockOutValue = nodeFindSocket(node, SOCK_OUT, "Value");
if (node->custom1 == NODE_VECTOR_MATH_NORMALIZE && socket_is_used(sockOutValue)) {
@@ -675,7 +675,7 @@ static void update_vector_math_node_normalize_operator(bNodeTree *ntree)
*/
static void update_vector_math_node_operators_enum_mapping(bNodeTree *ntree)
{
- for (bNode *node = ntree->nodes.first; node; node = node->next) {
+ LISTBASE_FOREACH (bNode *, node, &ntree->nodes) {
if (node->type == SH_NODE_VECTOR_MATH) {
switch (node->custom1) {
case 2:
@@ -702,7 +702,7 @@ static void update_vector_math_node_average_operator(bNodeTree *ntree)
{
bool need_update = false;
- for (bNode *node = ntree->nodes.first; node; node = node->next) {
+ LISTBASE_FOREACH (bNode *, node, &ntree->nodes) {
if (node->type == SH_NODE_VECTOR_MATH) {
/* See update_vector_math_node_operators_enum_mapping. */
if (node->custom1 == -1) {
@@ -765,7 +765,7 @@ static void update_vector_math_node_average_operator(bNodeTree *ntree)
*/
static void update_noise_node_dimensions(bNodeTree *ntree)
{
- for (bNode *node = ntree->nodes.first; node; node = node->next) {
+ LISTBASE_FOREACH (bNode *, node, &ntree->nodes) {
if (node->type == SH_NODE_TEX_NOISE && node->storage) {
NodeTexNoise *tex = (NodeTexNoise *)node->storage;
tex->dimensions = 3;
@@ -853,7 +853,7 @@ static void update_mapping_node_inputs_and_properties(bNodeTree *ntree)
{
bool need_update = false;
- for (bNode *node = ntree->nodes.first; node; node = node->next) {
+ LISTBASE_FOREACH (bNode *, node, &ntree->nodes) {
/* If node->storage is NULL, then conversion has already taken place.
* This can happen if a file with the new mapping node [saved from (2, 81, 8) or newer]
* is opened in a blender version prior to (2, 81, 8) and saved from there again. */
@@ -949,7 +949,7 @@ static void update_mapping_node_inputs_and_properties(bNodeTree *ntree)
*/
static void update_musgrave_node_dimensions(bNodeTree *ntree)
{
- for (bNode *node = ntree->nodes.first; node; node = node->next) {
+ LISTBASE_FOREACH (bNode *, node, &ntree->nodes) {
if (node->type == SH_NODE_TEX_MUSGRAVE && node->storage) {
NodeTexMusgrave *tex = (NodeTexMusgrave *)node->storage;
tex->dimensions = 3;
@@ -977,7 +977,7 @@ static void update_musgrave_node_color_output(bNodeTree *ntree)
*/
static void update_voronoi_node_dimensions(bNodeTree *ntree)
{
- for (bNode *node = ntree->nodes.first; node; node = node->next) {
+ LISTBASE_FOREACH (bNode *, node, &ntree->nodes) {
if (node->type == SH_NODE_TEX_VORONOI && node->storage) {
NodeTexVoronoi *tex = (NodeTexVoronoi *)node->storage;
tex->dimensions = 3;
@@ -992,7 +992,7 @@ static void update_voronoi_node_dimensions(bNodeTree *ntree)
*/
static void update_voronoi_node_f3_and_f4(bNodeTree *ntree)
{
- for (bNode *node = ntree->nodes.first; node; node = node->next) {
+ LISTBASE_FOREACH (bNode *, node, &ntree->nodes) {
if (node->type == SH_NODE_TEX_VORONOI && node->storage) {
NodeTexVoronoi *tex = (NodeTexVoronoi *)node->storage;
if (ELEM(tex->feature, 2, 3)) {
@@ -1010,7 +1010,7 @@ static void update_voronoi_node_f3_and_f4(bNodeTree *ntree)
*/
static void update_voronoi_node_fac_output(bNodeTree *ntree)
{
- for (bNode *node = ntree->nodes.first; node; node = node->next) {
+ LISTBASE_FOREACH (bNode *, node, &ntree->nodes) {
if (node->type == SH_NODE_TEX_VORONOI) {
bNodeSocket *facOutput = BLI_findlink(&node->outputs, 1);
strcpy(facOutput->identifier, "Distance");
@@ -1040,7 +1040,7 @@ static void update_voronoi_node_crackle(bNodeTree *ntree)
{
bool need_update = false;
- for (bNode *node = ntree->nodes.first; node; node = node->next) {
+ LISTBASE_FOREACH (bNode *, node, &ntree->nodes) {
if (node->type == SH_NODE_TEX_VORONOI && node->storage) {
NodeTexVoronoi *tex = (NodeTexVoronoi *)node->storage;
bNodeSocket *sockDistance = nodeFindSocket(node, SOCK_OUT, "Distance");
@@ -1169,7 +1169,7 @@ static void update_voronoi_node_square_distance(bNodeTree *ntree)
{
bool need_update = false;
- for (bNode *node = ntree->nodes.first; node; node = node->next) {
+ LISTBASE_FOREACH (bNode *, node, &ntree->nodes) {
if (node->type == SH_NODE_TEX_VORONOI && node->storage) {
NodeTexVoronoi *tex = (NodeTexVoronoi *)node->storage;
bNodeSocket *sockDistance = nodeFindSocket(node, SOCK_OUT, "Distance");
@@ -1213,7 +1213,7 @@ static void update_noise_and_wave_distortion(bNodeTree *ntree)
{
bool need_update = false;
- for (bNode *node = ntree->nodes.first; node; node = node->next) {
+ LISTBASE_FOREACH (bNode *, node, &ntree->nodes) {
if (node->type == SH_NODE_TEX_NOISE || node->type == SH_NODE_TEX_WAVE) {
bNodeSocket *sockDistortion = nodeFindSocket(node, SOCK_IN, "Distortion");
@@ -1262,7 +1262,7 @@ static void update_noise_and_wave_distortion(bNodeTree *ntree)
*/
static void update_wave_node_directions_and_offset(bNodeTree *ntree)
{
- for (bNode *node = ntree->nodes.first; node; node = node->next) {
+ LISTBASE_FOREACH (bNode *, node, &ntree->nodes) {
if (node->type == SH_NODE_TEX_WAVE) {
NodeTexWave *tex = (NodeTexWave *)node->storage;
tex->bands_direction = SHD_WAVE_BANDS_DIRECTION_DIAGONAL;
@@ -1351,13 +1351,13 @@ void do_versions_after_linking_cycles(Main *bmain)
if (!MAIN_VERSION_ATLEAST(bmain, 273, 5)) {
/* Euler order was ZYX in previous versions. */
- for (bNode *node = ntree->nodes.first; node; node = node->next) {
+ LISTBASE_FOREACH (bNode *, node, &ntree->nodes) {
mapping_node_order_flip(node);
}
}
if (!MAIN_VERSION_ATLEAST(bmain, 276, 6)) {
- for (bNode *node = ntree->nodes.first; node; node = node->next) {
+ LISTBASE_FOREACH (bNode *, node, &ntree->nodes) {
vector_curve_node_remap(node);
}
}
@@ -1368,7 +1368,7 @@ void do_versions_after_linking_cycles(Main *bmain)
}
if (!MAIN_VERSION_ATLEAST(bmain, 279, 3)) {
- for (bNode *node = ntree->nodes.first; node; node = node->next) {
+ LISTBASE_FOREACH (bNode *, node, &ntree->nodes) {
displacement_principled_nodes(node);
}
}
@@ -1384,7 +1384,7 @@ void do_versions_after_linking_cycles(Main *bmain)
}
if (!MAIN_VERSION_ATLEAST(bmain, 280, 66)) {
- for (bNode *node = ntree->nodes.first; node; node = node->next) {
+ LISTBASE_FOREACH (bNode *, node, &ntree->nodes) {
image_node_colorspace(node);
}
}
diff --git a/source/blender/blenloader/intern/versioning_defaults.c b/source/blender/blenloader/intern/versioning_defaults.c
index 80395177100..91d89254c90 100644
--- a/source/blender/blenloader/intern/versioning_defaults.c
+++ b/source/blender/blenloader/intern/versioning_defaults.c
@@ -71,7 +71,7 @@ static ID *rename_id_for_versioning(Main *bmain,
/* We can ignore libraries */
ListBase *lb = which_libbase(bmain, id_type);
ID *id = NULL;
- for (ID *idtest = lb->first; idtest; idtest = idtest->next) {
+ LISTBASE_FOREACH (ID *, idtest, lb) {
if (idtest->lib == NULL) {
if (STREQ(idtest->name + 2, name_src)) {
id = idtest;
@@ -101,8 +101,8 @@ static void blo_update_defaults_screen(bScreen *screen,
const char *workspace_name)
{
/* For all app templates. */
- for (ScrArea *sa = screen->areabase.first; sa; sa = sa->next) {
- for (ARegion *region = sa->regionbase.first; region; region = region->next) {
+ LISTBASE_FOREACH (ScrArea *, area, &screen->areabase) {
+ LISTBASE_FOREACH (ARegion *, region, &area->regionbase) {
/* Some toolbars have been saved as initialized,
* we don't want them to have odd zoom-level or scrolling set, see: T47047 */
if (ELEM(region->regiontype, RGN_TYPE_UI, RGN_TYPE_TOOLS, RGN_TYPE_TOOL_PROPS)) {
@@ -111,7 +111,7 @@ static void blo_update_defaults_screen(bScreen *screen,
}
/* Set default folder. */
- for (SpaceLink *sl = sa->spacedata.first; sl; sl = sl->next) {
+ LISTBASE_FOREACH (SpaceLink *, sl, &area->spacedata) {
if (sl->spacetype == SPACE_FILE) {
SpaceFile *sfile = (SpaceFile *)sl;
if (sfile->params) {
@@ -130,8 +130,8 @@ static void blo_update_defaults_screen(bScreen *screen,
return;
}
- for (ScrArea *sa = screen->areabase.first; sa; sa = sa->next) {
- for (ARegion *region = sa->regionbase.first; region; region = region->next) {
+ LISTBASE_FOREACH (ScrArea *, area, &screen->areabase) {
+ LISTBASE_FOREACH (ARegion *, region, &area->regionbase) {
/* Remove all stored panels, we want to use defaults
* (order, open/closed) as defined by UI code here! */
BKE_area_region_panels_free(&region->panels);
@@ -142,48 +142,48 @@ static void blo_update_defaults_screen(bScreen *screen,
region->sizey = 0;
}
- if (sa->spacetype == SPACE_IMAGE) {
+ if (area->spacetype == SPACE_IMAGE) {
if (STREQ(workspace_name, "UV Editing")) {
- SpaceImage *sima = sa->spacedata.first;
+ SpaceImage *sima = area->spacedata.first;
if (sima->mode == SI_MODE_VIEW) {
sima->mode = SI_MODE_UV;
}
}
}
- else if (sa->spacetype == SPACE_ACTION) {
+ else if (area->spacetype == SPACE_ACTION) {
/* Show markers region, hide channels and collapse summary in timelines. */
- SpaceAction *saction = sa->spacedata.first;
+ SpaceAction *saction = area->spacedata.first;
saction->flag |= SACTION_SHOW_MARKERS;
if (saction->mode == SACTCONT_TIMELINE) {
saction->ads.flag |= ADS_FLAG_SUMMARY_COLLAPSED;
- for (ARegion *region = sa->regionbase.first; region; region = region->next) {
+ LISTBASE_FOREACH (ARegion *, region, &area->regionbase) {
if (region->regiontype == RGN_TYPE_CHANNELS) {
region->flag |= RGN_FLAG_HIDDEN;
}
}
}
}
- else if (sa->spacetype == SPACE_GRAPH) {
- SpaceGraph *sipo = sa->spacedata.first;
+ else if (area->spacetype == SPACE_GRAPH) {
+ SpaceGraph *sipo = area->spacedata.first;
sipo->flag |= SIPO_SHOW_MARKERS;
}
- else if (sa->spacetype == SPACE_NLA) {
- SpaceNla *snla = sa->spacedata.first;
+ else if (area->spacetype == SPACE_NLA) {
+ SpaceNla *snla = area->spacedata.first;
snla->flag |= SNLA_SHOW_MARKERS;
}
- else if (sa->spacetype == SPACE_SEQ) {
- SpaceSeq *seq = sa->spacedata.first;
- seq->flag |= SEQ_SHOW_MARKERS;
+ else if (area->spacetype == SPACE_SEQ) {
+ SpaceSeq *seq = area->spacedata.first;
+ seq->flag |= SEQ_SHOW_MARKERS | SEQ_SHOW_FCURVES;
}
- else if (sa->spacetype == SPACE_TEXT) {
+ else if (area->spacetype == SPACE_TEXT) {
/* Show syntax and line numbers in Script workspace text editor. */
- SpaceText *stext = sa->spacedata.first;
+ SpaceText *stext = area->spacedata.first;
stext->showsyntax = true;
stext->showlinenrs = true;
}
- else if (sa->spacetype == SPACE_VIEW3D) {
- View3D *v3d = sa->spacedata.first;
+ else if (area->spacetype == SPACE_VIEW3D) {
+ View3D *v3d = area->spacedata.first;
/* Screen space cavity by default for faster performance. */
v3d->shading.cavity_type = V3D_SHADING_CAVITY_CURVATURE;
v3d->shading.flag |= V3D_SHADING_SPECULAR_HIGHLIGHT;
@@ -197,24 +197,27 @@ static void blo_update_defaults_screen(bScreen *screen,
v3d->gp_flag |= V3D_GP_SHOW_EDIT_LINES;
/* Remove dither pattern in wireframe mode. */
v3d->shading.xray_alpha_wire = 0.0f;
+ v3d->clip_start = 0.01f;
/* Skip startups that use the viewport color by default. */
if (v3d->shading.background_type != V3D_SHADING_BACKGROUND_VIEWPORT) {
copy_v3_fl(v3d->shading.background_color, 0.05f);
}
+ /* Disable Curve Normals. */
+ v3d->overlay.edit_flag &= ~V3D_OVERLAY_EDIT_CU_NORMALS;
}
- else if (sa->spacetype == SPACE_CLIP) {
- SpaceClip *sclip = sa->spacedata.first;
+ else if (area->spacetype == SPACE_CLIP) {
+ SpaceClip *sclip = area->spacedata.first;
sclip->around = V3D_AROUND_CENTER_MEDIAN;
}
}
/* Show tool-header by default (for most cases at least, hide for others). */
const bool hide_image_tool_header = STREQ(workspace_name, "Rendering");
- for (ScrArea *sa = screen->areabase.first; sa; sa = sa->next) {
- for (SpaceLink *sl = sa->spacedata.first; sl; sl = sl->next) {
- ListBase *regionbase = (sl == sa->spacedata.first) ? &sa->regionbase : &sl->regionbase;
+ LISTBASE_FOREACH (ScrArea *, area, &screen->areabase) {
+ LISTBASE_FOREACH (SpaceLink *, sl, &area->spacedata) {
+ ListBase *regionbase = (sl == area->spacedata.first) ? &area->regionbase : &sl->regionbase;
- for (ARegion *region = regionbase->first; region; region = region->next) {
+ LISTBASE_FOREACH (ARegion *, region, regionbase) {
if (region->regiontype == RGN_TYPE_TOOL_HEADER) {
if ((sl->spacetype == SPACE_IMAGE) && hide_image_tool_header) {
region->flag |= RGN_FLAG_HIDDEN;
@@ -229,20 +232,18 @@ static void blo_update_defaults_screen(bScreen *screen,
/* 2D animation template. */
if (app_template && STREQ(app_template, "2D_Animation")) {
- for (ScrArea *sa = screen->areabase.first; sa; sa = sa->next) {
- for (ARegion *region = sa->regionbase.first; region; region = region->next) {
- if (sa->spacetype == SPACE_ACTION) {
- SpaceAction *saction = sa->spacedata.first;
- /* Enable Sliders. */
- saction->flag |= SACTION_SLIDERS;
- }
- else if (sa->spacetype == SPACE_VIEW3D) {
- View3D *v3d = sa->spacedata.first;
- /* Set Material Color by default. */
- v3d->shading.color_type = V3D_SHADING_MATERIAL_COLOR;
- /* Enable Annotations. */
- v3d->flag2 |= V3D_SHOW_ANNOTATION;
- }
+ LISTBASE_FOREACH (ScrArea *, area, &screen->areabase) {
+ if (area->spacetype == SPACE_ACTION) {
+ SpaceAction *saction = area->spacedata.first;
+ /* Enable Sliders. */
+ saction->flag |= SACTION_SLIDERS;
+ }
+ else if (area->spacetype == SPACE_VIEW3D) {
+ View3D *v3d = area->spacedata.first;
+ /* Set Material Color by default. */
+ v3d->shading.color_type = V3D_SHADING_MATERIAL_COLOR;
+ /* Enable Annotations. */
+ v3d->flag2 |= V3D_SHOW_ANNOTATION;
}
}
}
@@ -250,8 +251,7 @@ static void blo_update_defaults_screen(bScreen *screen,
void BLO_update_defaults_workspace(WorkSpace *workspace, const char *app_template)
{
- ListBase *layouts = BKE_workspace_layouts_get(workspace);
- for (WorkSpaceLayout *layout = layouts->first; layout; layout = layout->next) {
+ LISTBASE_FOREACH (WorkSpaceLayout *, layout, &workspace->layouts) {
if (layout->screen) {
blo_update_defaults_screen(layout->screen, app_template, workspace->id.name + 2);
}
@@ -270,13 +270,13 @@ void BLO_update_defaults_workspace(WorkSpace *workspace, const char *app_templat
/* For Sculpting template. */
if (STREQ(workspace->id.name + 2, "Sculpting")) {
- for (WorkSpaceLayout *layout = layouts->first; layout; layout = layout->next) {
+ LISTBASE_FOREACH (WorkSpaceLayout *, layout, &workspace->layouts) {
bScreen *screen = layout->screen;
if (screen) {
- for (ScrArea *sa = screen->areabase.first; sa; sa = sa->next) {
- for (ARegion *region = sa->regionbase.first; region; region = region->next) {
- if (sa->spacetype == SPACE_VIEW3D) {
- View3D *v3d = sa->spacedata.first;
+ LISTBASE_FOREACH (ScrArea *, area, &screen->areabase) {
+ LISTBASE_FOREACH (ARegion *, region, &area->regionbase) {
+ if (area->spacetype == SPACE_VIEW3D) {
+ View3D *v3d = area->spacedata.first;
v3d->shading.flag &= ~V3D_SHADING_CAVITY;
copy_v3_fl(v3d->shading.single_color, 1.0f);
STRNCPY(v3d->shading.matcap, "basic_1");
@@ -297,7 +297,7 @@ static void blo_update_defaults_scene(Main *bmain, Scene *scene)
/* Don't enable compositing nodes. */
if (scene->nodetree) {
- ntreeFreeNestedTree(scene->nodetree);
+ ntreeFreeEmbeddedTree(scene->nodetree);
MEM_freeN(scene->nodetree);
scene->nodetree = NULL;
scene->use_nodes = false;
@@ -368,7 +368,13 @@ static void blo_update_defaults_scene(Main *bmain, Scene *scene)
/**
* Update defaults in startup.blend, without having to save and embed the file.
- * This function can be emptied each time the startup.blend is updated. */
+ * This function can be emptied each time the startup.blend is updated.
+ *
+ * \note Screen data may be cleared at this point, this will happen in the case
+ * an app-template's data needs to be versioned when read-file is called with "Load UI" disabled.
+ * Versioning the screen data can be safely skipped without "Load UI" since the screen data
+ * will have been versioned when it was first loaded.
+ */
void BLO_update_defaults_startup_blend(Main *bmain, const char *app_template)
{
/* For all app templates. */
@@ -376,30 +382,132 @@ void BLO_update_defaults_startup_blend(Main *bmain, const char *app_template)
BLO_update_defaults_workspace(workspace, app_template);
}
+ /* New grease pencil brushes and vertex paint setup. */
+ {
+ /* Update Grease Pencil brushes. */
+ Brush *brush;
+
+ /* Pencil brush. */
+ rename_id_for_versioning(bmain, ID_BR, "Draw Pencil", "Pencil");
+
+ /* Pen brush. */
+ rename_id_for_versioning(bmain, ID_BR, "Draw Pen", "Pen");
+
+ /* Pen Soft brush. */
+ brush = (Brush *)rename_id_for_versioning(bmain, ID_BR, "Draw Soft", "Pencil Soft");
+ if (brush) {
+ brush->gpencil_settings->icon_id = GP_BRUSH_ICON_PEN;
+ }
+
+ /* Ink Pen brush. */
+ rename_id_for_versioning(bmain, ID_BR, "Draw Ink", "Ink Pen");
+
+ /* Ink Pen Rough brush. */
+ rename_id_for_versioning(bmain, ID_BR, "Draw Noise", "Ink Pen Rough");
+
+ /* Marker Bold brush. */
+ rename_id_for_versioning(bmain, ID_BR, "Draw Marker", "Marker Bold");
+
+ /* Marker Chisel brush. */
+ rename_id_for_versioning(bmain, ID_BR, "Draw Block", "Marker Chisel");
+
+ /* Remove useless Fill Area.001 brush. */
+ brush = BLI_findstring(&bmain->brushes, "Fill Area.001", offsetof(ID, name) + 2);
+ if (brush) {
+ BKE_id_delete(bmain, brush);
+ }
+
+ /* Rename and fix materials and enable default object lights on. */
+ if (app_template && STREQ(app_template, "2D_Animation")) {
+ Material *ma = NULL;
+ rename_id_for_versioning(bmain, ID_MA, "Black", "Solid Stroke");
+ rename_id_for_versioning(bmain, ID_MA, "Red", "Squares Stroke");
+ rename_id_for_versioning(bmain, ID_MA, "Grey", "Solid Fill");
+ rename_id_for_versioning(bmain, ID_MA, "Black Dots", "Dots Stroke");
+
+ /* Dots Stroke. */
+ ma = BLI_findstring(&bmain->materials, "Dots Stroke", offsetof(ID, name) + 2);
+ if (ma == NULL) {
+ ma = BKE_gpencil_material_add(bmain, "Dots Stroke");
+ }
+ ma->gp_style->mode = GP_MATERIAL_MODE_DOT;
+
+ /* Squares Stroke. */
+ ma = BLI_findstring(&bmain->materials, "Squares Stroke", offsetof(ID, name) + 2);
+ if (ma == NULL) {
+ ma = BKE_gpencil_material_add(bmain, "Squares Stroke");
+ }
+ ma->gp_style->mode = GP_MATERIAL_MODE_SQUARE;
+
+ /* Change Solid Stroke settings. */
+ ma = BLI_findstring(&bmain->materials, "Solid Stroke", offsetof(ID, name) + 2);
+ if (ma != NULL) {
+ ma->gp_style->mix_rgba[3] = 1.0f;
+ ma->gp_style->texture_offset[0] = -0.5f;
+ ma->gp_style->mix_factor = 0.5f;
+ }
+
+ /* Change Solid Fill settings. */
+ ma = BLI_findstring(&bmain->materials, "Solid Fill", offsetof(ID, name) + 2);
+ if (ma != NULL) {
+ ma->gp_style->flag &= ~GP_MATERIAL_STROKE_SHOW;
+ ma->gp_style->mix_rgba[3] = 1.0f;
+ ma->gp_style->texture_offset[0] = -0.5f;
+ ma->gp_style->mix_factor = 0.5f;
+ }
+
+ Object *ob = BLI_findstring(&bmain->objects, "Stroke", offsetof(ID, name) + 2);
+ if (ob && ob->type == OB_GPENCIL) {
+ ob->dtx |= OB_USE_GPENCIL_LIGHTS;
+ }
+ }
+
+ /* Reset all grease pencil brushes. */
+ Scene *scene = bmain->scenes.first;
+ BKE_brush_gpencil_paint_presets(bmain, scene->toolsettings, true);
+ BKE_brush_gpencil_sculpt_presets(bmain, scene->toolsettings, true);
+ BKE_brush_gpencil_vertex_presets(bmain, scene->toolsettings, true);
+ BKE_brush_gpencil_weight_presets(bmain, scene->toolsettings, true);
+
+ /* Ensure new Paint modes. */
+ BKE_paint_ensure_from_paintmode(scene, PAINT_MODE_VERTEX_GPENCIL);
+ BKE_paint_ensure_from_paintmode(scene, PAINT_MODE_SCULPT_GPENCIL);
+ BKE_paint_ensure_from_paintmode(scene, PAINT_MODE_WEIGHT_GPENCIL);
+
+ /* Enable cursor. */
+ GpPaint *gp_paint = scene->toolsettings->gp_paint;
+ gp_paint->paint.flags |= PAINT_SHOW_BRUSH;
+
+ /* Ensure Palette by default. */
+ BKE_gpencil_palette_ensure(bmain, scene);
+ }
+
/* For builtin templates only. */
if (!blo_is_builtin_template(app_template)) {
return;
}
/* Workspaces. */
- wmWindow *win = ((wmWindowManager *)bmain->wm.first)->windows.first;
- for (WorkSpace *workspace = bmain->workspaces.first; workspace; workspace = workspace->id.next) {
- WorkSpaceLayout *layout = BKE_workspace_hook_layout_for_workspace_get(win->workspace_hook,
- workspace);
-
- /* Name all screens by their workspaces (avoids 'Default.###' names). */
- /* Default only has one window. */
- if (layout->screen) {
- bScreen *screen = layout->screen;
- BLI_strncpy(screen->id.name + 2, workspace->id.name + 2, sizeof(screen->id.name) - 2);
- BLI_libblock_ensure_unique_name(bmain, screen->id.name);
- }
+ LISTBASE_FOREACH (wmWindowManager *, wm, &bmain->wm) {
+ LISTBASE_FOREACH (wmWindow *, win, &wm->windows) {
+ LISTBASE_FOREACH (WorkSpace *, workspace, &bmain->workspaces) {
+ WorkSpaceLayout *layout = BKE_workspace_active_layout_for_workspace_get(
+ win->workspace_hook, workspace);
+ /* Name all screens by their workspaces (avoids 'Default.###' names). */
+ /* Default only has one window. */
+ if (layout->screen) {
+ bScreen *screen = layout->screen;
+ BLI_strncpy(screen->id.name + 2, workspace->id.name + 2, sizeof(screen->id.name) - 2);
+ BLI_libblock_ensure_unique_name(bmain, screen->id.name);
+ }
- /* For some reason we have unused screens, needed until re-saving.
- * Clear unused layouts because they're visible in the outliner & Python API. */
- LISTBASE_FOREACH_MUTABLE (WorkSpaceLayout *, layout_iter, &workspace->layouts) {
- if (layout != layout_iter) {
- BKE_workspace_layout_remove(bmain, workspace, layout_iter);
+ /* For some reason we have unused screens, needed until re-saving.
+ * Clear unused layouts because they're visible in the outliner & Python API. */
+ LISTBASE_FOREACH_MUTABLE (WorkSpaceLayout *, layout_iter, &workspace->layouts) {
+ if (layout != layout_iter) {
+ BKE_workspace_layout_remove(bmain, workspace, layout_iter);
+ }
+ }
}
}
}
@@ -472,7 +580,7 @@ void BLO_update_defaults_startup_blend(Main *bmain, const char *app_template)
ma->roughness = 0.4f;
if (ma->nodetree) {
- for (bNode *node = ma->nodetree->nodes.first; node; node = node->next) {
+ LISTBASE_FOREACH (bNode *, node, &ma->nodetree->nodes) {
if (node->type == SH_NODE_BSDF_PRINCIPLED) {
bNodeSocket *roughness_socket = nodeFindSocket(node, SOCK_IN, "Roughness");
bNodeSocketValueFloat *roughness_data = roughness_socket->default_value;
@@ -598,90 +706,4 @@ void BLO_update_defaults_startup_blend(Main *bmain, const char *app_template)
}
}
}
-
- /* New grease pencil brushes and vertex paint setup. */
- {
- /* Update Grease Pencil brushes. */
- Brush *brush;
-
- /* Pencil brush. */
- rename_id_for_versioning(bmain, ID_BR, "Draw Pencil", "Pencil");
-
- /* Pen brush. */
- rename_id_for_versioning(bmain, ID_BR, "Draw Pen", "Pen");
-
- /* Pen Soft brush. */
- brush = (Brush *)rename_id_for_versioning(bmain, ID_BR, "Draw Soft", "Pencil Soft");
- if (brush) {
- brush->gpencil_settings->icon_id = GP_BRUSH_ICON_PEN;
- }
-
- /* Ink Pen brush. */
- rename_id_for_versioning(bmain, ID_BR, "Draw Ink", "Ink Pen");
-
- /* Ink Pen Rough brush. */
- rename_id_for_versioning(bmain, ID_BR, "Draw Noise", "Ink Pen Rough");
-
- /* Marker Bold brush. */
- rename_id_for_versioning(bmain, ID_BR, "Draw Marker", "Marker Bold");
-
- /* Marker Chisel brush. */
- rename_id_for_versioning(bmain, ID_BR, "Draw Block", "Marker Chisel");
-
- /* Remove useless Fill Area.001 brush. */
- brush = BLI_findstring(&bmain->brushes, "Fill Area.001", offsetof(ID, name) + 2);
- if (brush) {
- BKE_id_delete(bmain, brush);
- }
-
- /* Rename and fix materials and enable default object lights on. */
- if (app_template && STREQ(app_template, "2D_Animation")) {
- Material *ma = NULL;
- rename_id_for_versioning(bmain, ID_MA, "Black", "Solid Stroke");
- rename_id_for_versioning(bmain, ID_MA, "Red", "Squares Stroke");
- rename_id_for_versioning(bmain, ID_MA, "Grey", "Solid Fill");
- rename_id_for_versioning(bmain, ID_MA, "Black Dots", "Dots Stroke");
-
- /* Dots Stroke. */
- ma = BLI_findstring(&bmain->materials, "Dots Stroke", offsetof(ID, name) + 2);
- if (ma == NULL) {
- ma = BKE_gpencil_material_add(bmain, "Dots Stroke");
- }
- ma->gp_style->mode = GP_MATERIAL_MODE_DOT;
-
- /* Squares Stroke. */
- ma = BLI_findstring(&bmain->materials, "Squares Stroke", offsetof(ID, name) + 2);
- if (ma == NULL) {
- ma = BKE_gpencil_material_add(bmain, "Squares Stroke");
- }
- ma->gp_style->mode = GP_MATERIAL_MODE_SQUARE;
-
- /* Change Solid Fill settings. */
- ma = BLI_findstring(&bmain->materials, "Solid Fill", offsetof(ID, name) + 2);
- if (ma != NULL) {
- ma->gp_style->flag &= ~GP_MATERIAL_STROKE_SHOW;
- }
-
- Object *ob = BLI_findstring(&bmain->objects, "Stroke", offsetof(ID, name) + 2);
- if (ob && ob->type == OB_GPENCIL) {
- ob->dtx |= OB_USE_GPENCIL_LIGHTS;
- }
- }
-
- /* Reset all grease pencil brushes. */
- Scene *scene = bmain->scenes.first;
- BKE_brush_gpencil_paint_presets(bmain, scene->toolsettings);
-
- /* Ensure new Paint modes. */
- BKE_paint_ensure_from_paintmode(scene, PAINT_MODE_VERTEX_GPENCIL);
- BKE_paint_ensure_from_paintmode(scene, PAINT_MODE_SCULPT_GPENCIL);
- BKE_paint_ensure_from_paintmode(scene, PAINT_MODE_WEIGHT_GPENCIL);
-
- /* Enable cursor. */
- GpPaint *gp_paint = scene->toolsettings->gp_paint;
- gp_paint->paint.flags |= PAINT_SHOW_BRUSH;
-
- /* Ensure Palette by default. */
- BKE_gpencil_palette_ensure(bmain, scene);
- }
}
diff --git a/source/blender/blenloader/intern/versioning_legacy.c b/source/blender/blenloader/intern/versioning_legacy.c
index 29c4a0f3c9d..2cc811e213f 100644
--- a/source/blender/blenloader/intern/versioning_legacy.c
+++ b/source/blender/blenloader/intern/versioning_legacy.c
@@ -580,11 +580,11 @@ void blo_do_versions_pre250(FileData *fd, Library *lib, Main *bmain)
if (bmain->versionfile <= 109) {
/* new variable: gridlines */
- bScreen *sc = bmain->screens.first;
- while (sc) {
- ScrArea *sa = sc->areabase.first;
- while (sa) {
- SpaceLink *sl = sa->spacedata.first;
+ bScreen *screen = bmain->screens.first;
+ while (screen) {
+ ScrArea *area = screen->areabase.first;
+ while (area) {
+ SpaceLink *sl = area->spacedata.first;
while (sl) {
if (sl->spacetype == SPACE_VIEW3D) {
View3D *v3d = (View3D *)sl;
@@ -595,9 +595,9 @@ void blo_do_versions_pre250(FileData *fd, Library *lib, Main *bmain)
}
sl = sl->next;
}
- sa = sa->next;
+ area = area->next;
}
- sc = sc->id.next;
+ screen = screen->id.next;
}
}
@@ -694,11 +694,11 @@ void blo_do_versions_pre250(FileData *fd, Library *lib, Main *bmain)
}
if (bmain->versionfile <= 169) {
- bScreen *sc = bmain->screens.first;
- while (sc) {
- ScrArea *sa = sc->areabase.first;
- while (sa) {
- SpaceLink *sl = sa->spacedata.first;
+ bScreen *screen = bmain->screens.first;
+ while (screen) {
+ ScrArea *area = screen->areabase.first;
+ while (area) {
+ SpaceLink *sl = area->spacedata.first;
while (sl) {
if (sl->spacetype == SPACE_GRAPH) {
SpaceGraph *sipo = (SpaceGraph *)sl;
@@ -706,9 +706,9 @@ void blo_do_versions_pre250(FileData *fd, Library *lib, Main *bmain)
}
sl = sl->next;
}
- sa = sa->next;
+ area = area->next;
}
- sc = sc->id.next;
+ screen = screen->id.next;
}
}
@@ -727,11 +727,11 @@ void blo_do_versions_pre250(FileData *fd, Library *lib, Main *bmain)
}
if (bmain->versionfile <= 171) {
- bScreen *sc = bmain->screens.first;
- while (sc) {
- ScrArea *sa = sc->areabase.first;
- while (sa) {
- SpaceLink *sl = sa->spacedata.first;
+ bScreen *screen = bmain->screens.first;
+ while (screen) {
+ ScrArea *area = screen->areabase.first;
+ while (area) {
+ SpaceLink *sl = area->spacedata.first;
while (sl) {
if (sl->spacetype == SPACE_TEXT) {
SpaceText *st = (SpaceText *)sl;
@@ -739,9 +739,9 @@ void blo_do_versions_pre250(FileData *fd, Library *lib, Main *bmain)
}
sl = sl->next;
}
- sa = sa->next;
+ area = area->next;
}
- sc = sc->id.next;
+ screen = screen->id.next;
}
}
@@ -866,7 +866,7 @@ void blo_do_versions_pre250(FileData *fd, Library *lib, Main *bmain)
bSound *sound;
Scene *sce;
Mesh *me;
- bScreen *sc;
+ bScreen *screen;
for (sound = bmain->sounds.first; sound; sound = sound->id.next) {
if (sound->packedfile) {
@@ -889,13 +889,13 @@ void blo_do_versions_pre250(FileData *fd, Library *lib, Main *bmain)
}
/* some oldfile patch, moved from set_func_space */
- for (sc = bmain->screens.first; sc; sc = sc->id.next) {
- ScrArea *sa;
+ for (screen = bmain->screens.first; screen; screen = screen->id.next) {
+ ScrArea *area;
- for (sa = sc->areabase.first; sa; sa = sa->next) {
+ for (area = screen->areabase.first; area; area = area->next) {
SpaceLink *sl;
- for (sl = sa->spacedata.first; sl; sl = sl->next) {
+ for (sl = area->spacedata.first; sl; sl = sl->next) {
if (sl->spacetype == SPACE_GRAPH) {
SpaceSeq *sseq = (SpaceSeq *)sl;
sseq->v2d.keeptot = 0;
@@ -907,7 +907,7 @@ void blo_do_versions_pre250(FileData *fd, Library *lib, Main *bmain)
if (bmain->versionfile <= 227) {
Scene *sce;
- bScreen *sc;
+ bScreen *screen;
Object *ob;
/* As of now, this insures that the transition from the old Track system
@@ -962,13 +962,13 @@ void blo_do_versions_pre250(FileData *fd, Library *lib, Main *bmain)
}
/* patch for old wrong max view2d settings, allows zooming out more */
- for (sc = bmain->screens.first; sc; sc = sc->id.next) {
- ScrArea *sa;
+ for (screen = bmain->screens.first; screen; screen = screen->id.next) {
+ ScrArea *area;
- for (sa = sc->areabase.first; sa; sa = sa->next) {
+ for (area = screen->areabase.first; area; area = area->next) {
SpaceLink *sl;
- for (sl = sa->spacedata.first; sl; sl = sl->next) {
+ for (sl = area->spacedata.first; sl; sl = sl->next) {
if (sl->spacetype == SPACE_ACTION) {
SpaceAction *sac = (SpaceAction *)sl;
sac->v2d.max[0] = 32000;
@@ -983,7 +983,7 @@ void blo_do_versions_pre250(FileData *fd, Library *lib, Main *bmain)
}
if (bmain->versionfile <= 228) {
- bScreen *sc;
+ bScreen *screen;
Object *ob;
/* As of now, this insures that the transition from the old Track system
@@ -1029,13 +1029,13 @@ void blo_do_versions_pre250(FileData *fd, Library *lib, Main *bmain)
}
/* convert old mainb values for new button panels */
- for (sc = bmain->screens.first; sc; sc = sc->id.next) {
- ScrArea *sa;
+ for (screen = bmain->screens.first; screen; screen = screen->id.next) {
+ ScrArea *area;
- for (sa = sc->areabase.first; sa; sa = sa->next) {
+ for (area = screen->areabase.first; area; area = area->next) {
SpaceLink *sl;
- for (sl = sa->spacedata.first; sl; sl = sl->next) {
+ for (sl = area->spacedata.first; sl; sl = sl->next) {
if (sl->spacetype == SPACE_PROPERTIES) {
SpaceProperties *sbuts = (SpaceProperties *)sl;
@@ -1096,16 +1096,16 @@ void blo_do_versions_pre250(FileData *fd, Library *lib, Main *bmain)
*/
if (bmain->versionfile <= 230) {
- bScreen *sc;
+ bScreen *screen;
/* new variable blockscale, for panels in any area */
- for (sc = bmain->screens.first; sc; sc = sc->id.next) {
- ScrArea *sa;
+ for (screen = bmain->screens.first; screen; screen = screen->id.next) {
+ ScrArea *area;
- for (sa = sc->areabase.first; sa; sa = sa->next) {
+ for (area = screen->areabase.first; area; area = area->next) {
SpaceLink *sl;
- for (sl = sa->spacedata.first; sl; sl = sl->next) {
+ for (sl = area->spacedata.first; sl; sl = sl->next) {
/* added: 5x better zoom in for action */
if (sl->spacetype == SPACE_ACTION) {
SpaceAction *sac = (SpaceAction *)sl;
@@ -1117,14 +1117,14 @@ void blo_do_versions_pre250(FileData *fd, Library *lib, Main *bmain)
}
if (bmain->versionfile <= 231) {
- bScreen *sc = bmain->screens.first;
+ bScreen *screen = bmain->screens.first;
/* new bit flags for showing/hiding grid floor and axes */
- while (sc) {
- ScrArea *sa = sc->areabase.first;
- while (sa) {
- SpaceLink *sl = sa->spacedata.first;
+ while (screen) {
+ ScrArea *area = screen->areabase.first;
+ while (area) {
+ SpaceLink *sl = area->spacedata.first;
while (sl) {
if (sl->spacetype == SPACE_VIEW3D) {
View3D *v3d = (View3D *)sl;
@@ -1138,16 +1138,16 @@ void blo_do_versions_pre250(FileData *fd, Library *lib, Main *bmain)
}
sl = sl->next;
}
- sa = sa->next;
+ area = area->next;
}
- sc = sc->id.next;
+ screen = screen->id.next;
}
}
if (bmain->versionfile <= 232) {
Tex *tex = bmain->textures.first;
World *wrld = bmain->worlds.first;
- bScreen *sc;
+ bScreen *screen;
while (tex) {
if ((tex->flag & (TEX_CHECKER_ODD + TEX_CHECKER_EVEN)) == 0) {
@@ -1184,11 +1184,11 @@ void blo_do_versions_pre250(FileData *fd, Library *lib, Main *bmain)
/* new variable blockscale, for panels in any area, do again because new
* areas didn't initialize it to 0.7 yet
*/
- for (sc = bmain->screens.first; sc; sc = sc->id.next) {
- ScrArea *sa;
- for (sa = sc->areabase.first; sa; sa = sa->next) {
+ for (screen = bmain->screens.first; screen; screen = screen->id.next) {
+ ScrArea *area;
+ for (area = screen->areabase.first; area; area = area->next) {
SpaceLink *sl;
- for (sl = sa->spacedata.first; sl; sl = sl->next) {
+ for (sl = area->spacedata.first; sl; sl = sl->next) {
/* added: 5x better zoom in for nla */
if (sl->spacetype == SPACE_NLA) {
SpaceNla *snla = (SpaceNla *)sl;
@@ -1200,13 +1200,13 @@ void blo_do_versions_pre250(FileData *fd, Library *lib, Main *bmain)
}
if (bmain->versionfile <= 233) {
- bScreen *sc;
+ bScreen *screen;
- for (sc = bmain->screens.first; sc; sc = sc->id.next) {
- ScrArea *sa;
- for (sa = sc->areabase.first; sa; sa = sa->next) {
+ for (screen = bmain->screens.first; screen; screen = screen->id.next) {
+ ScrArea *area;
+ for (area = screen->areabase.first; area; area = area->next) {
SpaceLink *sl;
- for (sl = sa->spacedata.first; sl; sl = sl->next) {
+ for (sl = area->spacedata.first; sl; sl = sl->next) {
if (sl->spacetype == SPACE_VIEW3D) {
View3D *v3d = (View3D *)sl;
v3d->flag |= V3D_SELECT_OUTLINE;
@@ -1217,13 +1217,13 @@ void blo_do_versions_pre250(FileData *fd, Library *lib, Main *bmain)
}
if (bmain->versionfile <= 234) {
- bScreen *sc;
+ bScreen *screen;
- for (sc = bmain->screens.first; sc; sc = sc->id.next) {
- ScrArea *sa;
- for (sa = sc->areabase.first; sa; sa = sa->next) {
+ for (screen = bmain->screens.first; screen; screen = screen->id.next) {
+ ScrArea *area;
+ for (area = screen->areabase.first; area; area = area->next) {
SpaceLink *sl;
- for (sl = sa->spacedata.first; sl; sl = sl->next) {
+ for (sl = area->spacedata.first; sl; sl = sl->next) {
if (sl->spacetype == SPACE_TEXT) {
SpaceText *st = (SpaceText *)sl;
if (st->tabnumber == 0) {
@@ -1351,7 +1351,8 @@ void blo_do_versions_pre250(FileData *fd, Library *lib, Main *bmain)
};
if ((me->flag & ME_SUBSURF)) {
- SubsurfModifierData *smd = (SubsurfModifierData *)modifier_new(eModifierType_Subsurf);
+ SubsurfModifierData *smd = (SubsurfModifierData *)BKE_modifier_new(
+ eModifierType_Subsurf);
smd->levels = MAX2(1, me->subdiv);
smd->renderLevels = MAX2(1, me->subdivr);
@@ -1371,7 +1372,7 @@ void blo_do_versions_pre250(FileData *fd, Library *lib, Main *bmain)
BLI_addtail(&ob->modifiers, smd);
- modifier_unique_name(&ob->modifiers, (ModifierData *)smd);
+ BKE_modifier_unique_name(&ob->modifiers, (ModifierData *)smd);
}
}
@@ -1428,18 +1429,19 @@ void blo_do_versions_pre250(FileData *fd, Library *lib, Main *bmain)
}
}
- if ((ob->softflag & OB_SB_ENABLE) && !modifiers_findByType(ob, eModifierType_Softbody)) {
+ if ((ob->softflag & OB_SB_ENABLE) &&
+ !BKE_modifiers_findby_type(ob, eModifierType_Softbody)) {
if (ob->softflag & OB_SB_POSTDEF) {
md = ob->modifiers.first;
- while (md && modifierType_getInfo(md->type)->type == eModifierTypeType_OnlyDeform) {
+ while (md && BKE_modifier_get_info(md->type)->type == eModifierTypeType_OnlyDeform) {
md = md->next;
}
- BLI_insertlinkbefore(&ob->modifiers, md, modifier_new(eModifierType_Softbody));
+ BLI_insertlinkbefore(&ob->modifiers, md, BKE_modifier_new(eModifierType_Softbody));
}
else {
- BLI_addhead(&ob->modifiers, modifier_new(eModifierType_Softbody));
+ BLI_addhead(&ob->modifiers, BKE_modifier_new(eModifierType_Softbody));
}
ob->softflag &= ~OB_SB_ENABLE;
@@ -1651,7 +1653,7 @@ void blo_do_versions_pre250(FileData *fd, Library *lib, Main *bmain)
if (bmain->versionfile <= 242) {
Scene *sce;
- bScreen *sc;
+ bScreen *screen;
Object *ob;
Curve *cu;
Material *ma;
@@ -1663,13 +1665,13 @@ void blo_do_versions_pre250(FileData *fd, Library *lib, Main *bmain)
bNodeTree *ntree;
int a;
- for (sc = bmain->screens.first; sc; sc = sc->id.next) {
- ScrArea *sa;
- sa = sc->areabase.first;
- while (sa) {
+ for (screen = bmain->screens.first; screen; screen = screen->id.next) {
+ ScrArea *area;
+ area = screen->areabase.first;
+ while (area) {
SpaceLink *sl;
- for (sl = sa->spacedata.first; sl; sl = sl->next) {
+ for (sl = area->spacedata.first; sl; sl = sl->next) {
if (sl->spacetype == SPACE_VIEW3D) {
View3D *v3d = (View3D *)sl;
if (v3d->gridsubdiv == 0) {
@@ -1677,7 +1679,7 @@ void blo_do_versions_pre250(FileData *fd, Library *lib, Main *bmain)
}
}
}
- sa = sa->next;
+ area = area->next;
}
}
@@ -1922,17 +1924,17 @@ void blo_do_versions_pre250(FileData *fd, Library *lib, Main *bmain)
}
if (bmain->versionfile <= 244) {
- bScreen *sc;
+ bScreen *screen;
if (bmain->versionfile != 244 || bmain->subversionfile < 2) {
/* correct older action editors - incorrect scrolling */
- for (sc = bmain->screens.first; sc; sc = sc->id.next) {
- ScrArea *sa;
- sa = sc->areabase.first;
- while (sa) {
+ for (screen = bmain->screens.first; screen; screen = screen->id.next) {
+ ScrArea *area;
+ area = screen->areabase.first;
+ while (area) {
SpaceLink *sl;
- for (sl = sa->spacedata.first; sl; sl = sl->next) {
+ for (sl = area->spacedata.first; sl; sl = sl->next) {
if (sl->spacetype == SPACE_ACTION) {
SpaceAction *saction = (SpaceAction *)sl;
@@ -1943,7 +1945,7 @@ void blo_do_versions_pre250(FileData *fd, Library *lib, Main *bmain)
saction->v2d.cur.ymax = 5.0;
}
}
- sa = sa->next;
+ area = area->next;
}
}
}
@@ -2271,7 +2273,7 @@ void blo_do_versions_pre250(FileData *fd, Library *lib, Main *bmain)
BLI_addtail(&ob->particlesystem, psys);
- md = modifier_new(eModifierType_ParticleSystem);
+ md = BKE_modifier_new(eModifierType_ParticleSystem);
BLI_snprintf(md->name,
sizeof(md->name),
"ParticleSystem %i",
@@ -2357,7 +2359,7 @@ void blo_do_versions_pre250(FileData *fd, Library *lib, Main *bmain)
}
{
- FluidsimModifierData *fluidmd = (FluidsimModifierData *)modifiers_findByType(
+ FluidsimModifierData *fluidmd = (FluidsimModifierData *)BKE_modifiers_findby_type(
ob, eModifierType_Fluidsim);
if (fluidmd && fluidmd->fss && fluidmd->fss->type == OB_FLUIDSIM_PARTICLE) {
part->type = PART_FLUID;
@@ -2483,7 +2485,7 @@ void blo_do_versions_pre250(FileData *fd, Library *lib, Main *bmain)
for (ob = bmain->objects.first; ob; ob = ob->id.next) {
if (ob->fluidsimSettings) {
- FluidsimModifierData *fluidmd = (FluidsimModifierData *)modifier_new(
+ FluidsimModifierData *fluidmd = (FluidsimModifierData *)BKE_modifier_new(
eModifierType_Fluidsim);
BLI_addhead(&ob->modifiers, (ModifierData *)fluidmd);
@@ -2540,16 +2542,16 @@ void blo_do_versions_pre250(FileData *fd, Library *lib, Main *bmain)
}
if (bmain->versionfile < 248 || (bmain->versionfile == 248 && bmain->subversionfile < 3)) {
- bScreen *sc;
+ bScreen *screen;
/* adjust default settings for Animation Editors */
- for (sc = bmain->screens.first; sc; sc = sc->id.next) {
- ScrArea *sa;
+ for (screen = bmain->screens.first; screen; screen = screen->id.next) {
+ ScrArea *area;
- for (sa = sc->areabase.first; sa; sa = sa->next) {
+ for (area = screen->areabase.first; area; area = area->next) {
SpaceLink *sl;
- for (sl = sa->spacedata.first; sl; sl = sl->next) {
+ for (sl = area->spacedata.first; sl; sl = sl->next) {
switch (sl->spacetype) {
case SPACE_ACTION: {
SpaceAction *sact = (SpaceAction *)sl;
diff --git a/source/blender/blenloader/intern/versioning_userdef.c b/source/blender/blenloader/intern/versioning_userdef.c
index a88e4e20d68..1b0e41ec54a 100644
--- a/source/blender/blenloader/intern/versioning_userdef.c
+++ b/source/blender/blenloader/intern/versioning_userdef.c
@@ -22,9 +22,14 @@
#define DNA_DEPRECATED_ALLOW
#include <string.h>
+#include "BLI_listbase.h"
#include "BLI_math.h"
#include "BLI_utildefines.h"
+#ifdef WITH_INTERNATIONAL
+# include "BLT_translation.h"
+#endif
+
#include "DNA_anim_types.h"
#include "DNA_curve_types.h"
#include "DNA_scene_types.h"
@@ -533,7 +538,7 @@ void BLO_version_defaults_userpref_blend(Main *bmain, UserDef *userdef)
userdef->gpu_viewport_quality = 0.6f;
/* Reset theme, old themes will not be compatible with minor version updates from now on. */
- for (bTheme *btheme = userdef->themes.first; btheme; btheme = btheme->next) {
+ LISTBASE_FOREACH (bTheme *, btheme, &userdef->themes) {
memcpy(btheme, &U_theme_default, sizeof(*btheme));
}
@@ -551,8 +556,8 @@ void BLO_version_defaults_userpref_blend(Main *bmain, UserDef *userdef)
if (!USER_VERSION_ATLEAST(280, 31)) {
/* Remove select/action mouse from user defined keymaps. */
- for (wmKeyMap *keymap = userdef->user_keymaps.first; keymap; keymap = keymap->next) {
- for (wmKeyMapDiffItem *kmdi = keymap->diff_items.first; kmdi; kmdi = kmdi->next) {
+ LISTBASE_FOREACH (wmKeyMap *, keymap, &userdef->user_keymaps) {
+ LISTBASE_FOREACH (wmKeyMapDiffItem *, kmdi, &keymap->diff_items) {
if (kmdi->remove_item) {
do_version_select_mouse(userdef, kmdi->remove_item);
}
@@ -561,7 +566,7 @@ void BLO_version_defaults_userpref_blend(Main *bmain, UserDef *userdef)
}
}
- for (wmKeyMapItem *kmi = keymap->items.first; kmi; kmi = kmi->next) {
+ LISTBASE_FOREACH (wmKeyMapItem *, kmi, &keymap->items) {
do_version_select_mouse(userdef, kmi);
}
}
@@ -739,6 +744,15 @@ void BLO_version_defaults_userpref_blend(Main *bmain, UserDef *userdef)
userdef->gpu_flag |= USER_GPU_FLAG_OVERLAY_SMOOTH_WIRE;
}
+ if (!USER_VERSION_ATLEAST(283, 13)) {
+ /* If Translations is off then language should default to English. */
+ if ((userdef->transopts & USER_DOTRANSLATE_DEPRECATED) == 0) {
+ userdef->language = ULANGUAGE_ENGLISH;
+ }
+ /* Clear this deprecated flag. */
+ userdef->transopts &= ~USER_DOTRANSLATE_DEPRECATED;
+ }
+
/**
* Versioning code until next subversion bump goes here.
*
@@ -750,13 +764,17 @@ void BLO_version_defaults_userpref_blend(Main *bmain, UserDef *userdef)
*/
{
/* Keep this block, even when empty. */
+
+ if (userdef->collection_instance_empty_size == 0) {
+ userdef->collection_instance_empty_size = 1.0f;
+ }
}
if (userdef->pixelsize == 0.0f) {
userdef->pixelsize = 1.0f;
}
- for (bTheme *btheme = userdef->themes.first; btheme; btheme = btheme->next) {
+ LISTBASE_FOREACH (bTheme *, btheme, &userdef->themes) {
do_versions_theme(userdef, btheme);
}
#undef USER_VERSION_ATLEAST
diff --git a/source/blender/blenloader/intern/writefile.c b/source/blender/blenloader/intern/writefile.c
index 599e592c77d..73bab07a008 100644
--- a/source/blender/blenloader/intern/writefile.c
+++ b/source/blender/blenloader/intern/writefile.c
@@ -133,6 +133,7 @@
#include "DNA_sdna_types.h"
#include "DNA_sequence_types.h"
#include "DNA_shader_fx_types.h"
+#include "DNA_simulation_types.h"
#include "DNA_sound_types.h"
#include "DNA_space_types.h"
#include "DNA_speaker_types.h"
@@ -156,14 +157,17 @@
#include "BKE_constraint.h"
#include "BKE_curve.h"
#include "BKE_fcurve.h"
+#include "BKE_fcurve_driver.h"
#include "BKE_global.h" // for G
#include "BKE_gpencil_modifier.h"
#include "BKE_idtype.h"
#include "BKE_layer.h"
+#include "BKE_lib_id.h"
#include "BKE_lib_override.h"
#include "BKE_main.h"
#include "BKE_modifier.h"
#include "BKE_node.h"
+#include "BKE_object.h"
#include "BKE_pointcache.h"
#include "BKE_report.h"
#include "BKE_sequencer.h"
@@ -173,6 +177,7 @@
#include "BLO_blend_defs.h"
#include "BLO_blend_validate.h"
+#include "BLO_read_write.h"
#include "BLO_readfile.h"
#include "BLO_undofile.h"
#include "BLO_writefile.h"
@@ -323,12 +328,7 @@ typedef struct {
bool error;
/** #MemFile writing (used for undo). */
- struct {
- MemFile *current;
- MemFile *compare;
- /** Use to de-duplicate chunks when writing. */
- MemFileChunk *compare_chunk;
- } mem;
+ MemFileWriteData mem;
/** When true, write to #WriteData.current, could also call 'is_undo'. */
bool use_memfile;
@@ -340,6 +340,10 @@ typedef struct {
WriteWrap *ww;
} WriteData;
+typedef struct BlendWriter {
+ WriteData *wd;
+} BlendWriter;
+
static WriteData *writedata_new(WriteWrap *ww)
{
WriteData *wd = MEM_callocN(sizeof(*wd), "writedata");
@@ -367,7 +371,7 @@ static void writedata_do_write(WriteData *wd, const void *mem, int memlen)
/* memory based save */
if (wd->use_memfile) {
- memfile_chunk_add(wd->mem.current, mem, memlen, &wd->mem.compare_chunk);
+ BLO_memfile_chunk_add(&wd->mem, mem, memlen);
}
else {
if (wd->ww->write(wd->ww, mem, memlen) != memlen) {
@@ -468,9 +472,7 @@ static WriteData *mywrite_begin(WriteWrap *ww, MemFile *compare, MemFile *curren
WriteData *wd = writedata_new(ww);
if (current != NULL) {
- wd->mem.current = current;
- wd->mem.compare = compare;
- wd->mem.compare_chunk = compare ? compare->chunks.first : NULL;
+ BLO_memfile_write_init(&wd->mem, current, compare);
wd->use_memfile = true;
}
@@ -490,12 +492,58 @@ static bool mywrite_end(WriteData *wd)
wd->buf_used_len = 0;
}
+ if (wd->use_memfile) {
+ BLO_memfile_write_finalize(&wd->mem);
+ }
+
const bool err = wd->error;
writedata_free(wd);
return err;
}
+/**
+ * Start writing of data related to a single ID.
+ *
+ * Only does something when storing an undo step.
+ */
+static void mywrite_id_begin(WriteData *wd, ID *id)
+{
+ if (wd->use_memfile) {
+ wd->mem.current_id_session_uuid = id->session_uuid;
+
+ /* If current next memchunk does not match the ID we are about to write, try to find the
+ * correct memchunk in the mapping using ID's session_uuid. */
+ if (wd->mem.id_session_uuid_mapping != NULL &&
+ (wd->mem.reference_current_chunk == NULL ||
+ wd->mem.reference_current_chunk->id_session_uuid != id->session_uuid)) {
+ void *ref = BLI_ghash_lookup(wd->mem.id_session_uuid_mapping,
+ POINTER_FROM_UINT(id->session_uuid));
+ if (ref != NULL) {
+ wd->mem.reference_current_chunk = ref;
+ }
+ /* Else, no existing memchunk found, i.e. this is supposed to be a new ID. */
+ }
+ /* Otherwise, we try with the current memchunk in any case, whether it is matching current
+ * ID's session_uuid or not. */
+ }
+}
+
+/**
+ * Start writing of data related to a single ID.
+ *
+ * Only does something when storing an undo step.
+ */
+static void mywrite_id_end(WriteData *wd, ID *UNUSED(id))
+{
+ if (wd->use_memfile) {
+ /* Very important to do it after every ID write now, otherwise we cannot know whether a
+ * specific ID changed or not. */
+ mywrite_flush(wd);
+ wd->mem.current_id_session_uuid = MAIN_ID_SESSION_UUID_UNSET;
+ }
+}
+
/** \} */
/* -------------------------------------------------------------------- */
@@ -631,79 +679,86 @@ static void writelist_id(WriteData *wd, int filecode, const char *structname, co
* These functions are used by blender's .blend system for file saving/loading.
* \{ */
-void IDP_WriteProperty_OnlyData(const IDProperty *prop, void *wd);
-void IDP_WriteProperty(const IDProperty *prop, void *wd);
+void IDP_WriteProperty_OnlyData(const IDProperty *prop, BlendWriter *writer);
+void IDP_WriteProperty(const IDProperty *prop, WriteData *wd);
+void IDP_WriteProperty_new_api(const IDProperty *prop, BlendWriter *writer);
-static void IDP_WriteArray(const IDProperty *prop, void *wd)
+static void IDP_WriteArray(const IDProperty *prop, BlendWriter *writer)
{
/*REMEMBER to set totalen to len in the linking code!!*/
if (prop->data.pointer) {
- writedata(wd, DATA, MEM_allocN_len(prop->data.pointer), prop->data.pointer);
+ BLO_write_raw(writer, MEM_allocN_len(prop->data.pointer), prop->data.pointer);
if (prop->subtype == IDP_GROUP) {
IDProperty **array = prop->data.pointer;
int a;
for (a = 0; a < prop->len; a++) {
- IDP_WriteProperty(array[a], wd);
+ IDP_WriteProperty_new_api(array[a], writer);
}
}
}
}
-static void IDP_WriteIDPArray(const IDProperty *prop, void *wd)
+static void IDP_WriteIDPArray(const IDProperty *prop, BlendWriter *writer)
{
/*REMEMBER to set totalen to len in the linking code!!*/
if (prop->data.pointer) {
const IDProperty *array = prop->data.pointer;
int a;
- writestruct(wd, DATA, IDProperty, prop->len, array);
+ BLO_write_struct_array(writer, IDProperty, prop->len, array);
for (a = 0; a < prop->len; a++) {
- IDP_WriteProperty_OnlyData(&array[a], wd);
+ IDP_WriteProperty_OnlyData(&array[a], writer);
}
}
}
-static void IDP_WriteString(const IDProperty *prop, void *wd)
+static void IDP_WriteString(const IDProperty *prop, BlendWriter *writer)
{
/*REMEMBER to set totalen to len in the linking code!!*/
- writedata(wd, DATA, prop->len, prop->data.pointer);
+ BLO_write_raw(writer, prop->len, prop->data.pointer);
}
-static void IDP_WriteGroup(const IDProperty *prop, void *wd)
+static void IDP_WriteGroup(const IDProperty *prop, BlendWriter *writer)
{
IDProperty *loop;
for (loop = prop->data.group.first; loop; loop = loop->next) {
- IDP_WriteProperty(loop, wd);
+ IDP_WriteProperty_new_api(loop, writer);
}
}
/* Functions to read/write ID Properties */
-void IDP_WriteProperty_OnlyData(const IDProperty *prop, void *wd)
+void IDP_WriteProperty_OnlyData(const IDProperty *prop, BlendWriter *writer)
{
switch (prop->type) {
case IDP_GROUP:
- IDP_WriteGroup(prop, wd);
+ IDP_WriteGroup(prop, writer);
break;
case IDP_STRING:
- IDP_WriteString(prop, wd);
+ IDP_WriteString(prop, writer);
break;
case IDP_ARRAY:
- IDP_WriteArray(prop, wd);
+ IDP_WriteArray(prop, writer);
break;
case IDP_IDPARRAY:
- IDP_WriteIDPArray(prop, wd);
+ IDP_WriteIDPArray(prop, writer);
break;
}
}
-void IDP_WriteProperty(const IDProperty *prop, void *wd)
+void IDP_WriteProperty_new_api(const IDProperty *prop, BlendWriter *writer)
{
- writestruct(wd, DATA, IDProperty, 1, prop);
- IDP_WriteProperty_OnlyData(prop, wd);
+ BLO_write_struct(writer, IDProperty, prop);
+ IDP_WriteProperty_OnlyData(prop, writer);
+}
+
+void IDP_WriteProperty(const IDProperty *prop, WriteData *wd)
+{
+ BlendWriter writer = {wd};
+ IDP_WriteProperty_new_api(prop, &writer);
}
static void write_iddata(WriteData *wd, ID *id)
@@ -717,13 +772,11 @@ static void write_iddata(WriteData *wd, ID *id)
writestruct(wd, DATA, IDOverrideLibrary, 1, id->override_library);
writelist(wd, DATA, IDOverrideLibraryProperty, &id->override_library->properties);
- for (IDOverrideLibraryProperty *op = id->override_library->properties.first; op;
- op = op->next) {
+ LISTBASE_FOREACH (IDOverrideLibraryProperty *, op, &id->override_library->properties) {
writedata(wd, DATA, strlen(op->rna_path) + 1, op->rna_path);
writelist(wd, DATA, IDOverrideLibraryPropertyOperation, &op->operations);
- for (IDOverrideLibraryPropertyOperation *opop = op->operations.first; opop;
- opop = opop->next) {
+ LISTBASE_FOREACH (IDOverrideLibraryPropertyOperation *, opop, &op->operations) {
if (opop->subitem_reference_name) {
writedata(
wd, DATA, strlen(opop->subitem_reference_name) + 1, opop->subitem_reference_name);
@@ -734,11 +787,6 @@ static void write_iddata(WriteData *wd, ID *id)
}
}
}
-
- /* Clear the accumulated recalc flags in case of undo step saving. */
- if (wd->use_memfile) {
- id->recalc_undo_accumulated = 0;
- }
}
static void write_previews(WriteData *wd, const PreviewImage *prv_orig)
@@ -859,19 +907,19 @@ static void write_fcurves(WriteData *wd, ListBase *fcurves)
}
}
-static void write_action(WriteData *wd, bAction *act)
+static void write_action(WriteData *wd, bAction *act, const void *id_address)
{
if (act->id.us > 0 || wd->use_memfile) {
- writestruct(wd, ID_AC, bAction, 1, act);
+ writestruct_at_address(wd, ID_AC, bAction, 1, id_address, act);
write_iddata(wd, &act->id);
write_fcurves(wd, &act->curves);
- for (bActionGroup *grp = act->groups.first; grp; grp = grp->next) {
+ LISTBASE_FOREACH (bActionGroup *, grp, &act->groups) {
writestruct(wd, DATA, bActionGroup, 1, grp);
}
- for (TimeMarker *marker = act->markers.first; marker; marker = marker->next) {
+ LISTBASE_FOREACH (TimeMarker *, marker, &act->markers) {
writestruct(wd, DATA, TimeMarker, 1, marker);
}
}
@@ -996,9 +1044,19 @@ static void write_node_socket_default_value(WriteData *wd, bNodeSocket *sock)
case SOCK_STRING:
writestruct(wd, DATA, bNodeSocketValueString, 1, sock->default_value);
break;
+ case SOCK_OBJECT:
+ writestruct(wd, DATA, bNodeSocketValueObject, 1, sock->default_value);
+ break;
+ case SOCK_IMAGE:
+ writestruct(wd, DATA, bNodeSocketValueImage, 1, sock->default_value);
+ break;
case __SOCK_MESH:
case SOCK_CUSTOM:
case SOCK_SHADER:
+ case SOCK_EMITTERS:
+ case SOCK_EVENTS:
+ case SOCK_FORCES:
+ case SOCK_CONTROL_FLOW:
BLI_assert(false);
break;
}
@@ -1139,11 +1197,6 @@ static void write_nodetree_nolib(WriteData *wd, bNodeTree *ntree)
for (sock = ntree->outputs.first; sock; sock = sock->next) {
write_node_socket_interface(wd, sock);
}
-
- /* Clear the accumulated recalc flags in case of undo step saving. */
- if (wd->use_memfile) {
- ntree->id.recalc_undo_accumulated = 0;
- }
}
/**
@@ -1235,14 +1288,14 @@ static void write_userdef(WriteData *wd, const UserDef *userdef)
{
writestruct(wd, USER, UserDef, 1, userdef);
- for (const bTheme *btheme = userdef->themes.first; btheme; btheme = btheme->next) {
+ LISTBASE_FOREACH (const bTheme *, btheme, &userdef->themes) {
writestruct(wd, DATA, bTheme, 1, btheme);
}
- for (const wmKeyMap *keymap = userdef->user_keymaps.first; keymap; keymap = keymap->next) {
+ LISTBASE_FOREACH (const wmKeyMap *, keymap, &userdef->user_keymaps) {
writestruct(wd, DATA, wmKeyMap, 1, keymap);
- for (const wmKeyMapDiffItem *kmdi = keymap->diff_items.first; kmdi; kmdi = kmdi->next) {
+ LISTBASE_FOREACH (const wmKeyMapDiffItem *, kmdi, &keymap->diff_items) {
writestruct(wd, DATA, wmKeyMapDiffItem, 1, kmdi);
if (kmdi->remove_item) {
write_keymapitem(wd, kmdi->remove_item);
@@ -1252,21 +1305,21 @@ static void write_userdef(WriteData *wd, const UserDef *userdef)
}
}
- for (const wmKeyMapItem *kmi = keymap->items.first; kmi; kmi = kmi->next) {
+ LISTBASE_FOREACH (const wmKeyMapItem *, kmi, &keymap->items) {
write_keymapitem(wd, kmi);
}
}
- for (const wmKeyConfigPref *kpt = userdef->user_keyconfig_prefs.first; kpt; kpt = kpt->next) {
+ LISTBASE_FOREACH (const wmKeyConfigPref *, kpt, &userdef->user_keyconfig_prefs) {
writestruct(wd, DATA, wmKeyConfigPref, 1, kpt);
if (kpt->prop) {
IDP_WriteProperty(kpt->prop, wd);
}
}
- for (const bUserMenu *um = userdef->user_menus.first; um; um = um->next) {
+ LISTBASE_FOREACH (const bUserMenu *, um, &userdef->user_menus) {
writestruct(wd, DATA, bUserMenu, 1, um);
- for (const bUserMenuItem *umi = um->items.first; umi; umi = umi->next) {
+ LISTBASE_FOREACH (const bUserMenuItem *, umi, &um->items) {
if (umi->type == USER_MENU_TYPE_OPERATOR) {
const bUserMenuItem_Op *umi_op = (const bUserMenuItem_Op *)umi;
writestruct(wd, DATA, bUserMenuItem_Op, 1, umi_op);
@@ -1288,19 +1341,18 @@ static void write_userdef(WriteData *wd, const UserDef *userdef)
}
}
- for (const bAddon *bext = userdef->addons.first; bext; bext = bext->next) {
+ LISTBASE_FOREACH (const bAddon *, bext, &userdef->addons) {
writestruct(wd, DATA, bAddon, 1, bext);
if (bext->prop) {
IDP_WriteProperty(bext->prop, wd);
}
}
- for (const bPathCompare *path_cmp = userdef->autoexec_paths.first; path_cmp;
- path_cmp = path_cmp->next) {
+ LISTBASE_FOREACH (const bPathCompare *, path_cmp, &userdef->autoexec_paths) {
writestruct(wd, DATA, bPathCompare, 1, path_cmp);
}
- for (const uiStyle *style = userdef->uistyles.first; style; style = style->next) {
+ LISTBASE_FOREACH (const uiStyle *, style, &userdef->uistyles) {
writestruct(wd, DATA, uiStyle, 1, style);
}
}
@@ -1396,11 +1448,11 @@ static void write_pointcaches(WriteData *wd, ListBase *ptcaches)
}
}
-static void write_particlesettings(WriteData *wd, ParticleSettings *part)
+static void write_particlesettings(WriteData *wd, ParticleSettings *part, const void *id_address)
{
if (part->id.us > 0 || wd->use_memfile) {
/* write LibData */
- writestruct(wd, ID_PA, ParticleSettings, 1, part);
+ writestruct_at_address(wd, ID_PA, ParticleSettings, 1, id_address, part);
write_iddata(wd, &part->id);
if (part->adt) {
@@ -1420,7 +1472,7 @@ static void write_particlesettings(WriteData *wd, ParticleSettings *part)
write_curvemapping(wd, part->twistcurve);
}
- for (ParticleDupliWeight *dw = part->instance_weights.first; dw; dw = dw->next) {
+ LISTBASE_FOREACH (ParticleDupliWeight *, dw, &part->instance_weights) {
/* update indices, but only if dw->ob is set (can be NULL after loading e.g.) */
if (dw->ob != NULL) {
dw->index = 0;
@@ -1440,7 +1492,7 @@ static void write_particlesettings(WriteData *wd, ParticleSettings *part)
if (part->boids && part->phystype == PART_PHYS_BOIDS) {
writestruct(wd, DATA, BoidSettings, 1, part->boids);
- for (BoidState *state = part->boids->states.first; state; state = state->next) {
+ LISTBASE_FOREACH (BoidState *, state, &part->boids->states) {
write_boid_state(wd, state);
}
}
@@ -1625,14 +1677,14 @@ static void write_pose(WriteData *wd, bPose *pose)
static void write_defgroups(WriteData *wd, ListBase *defbase)
{
- for (bDeformGroup *defgroup = defbase->first; defgroup; defgroup = defgroup->next) {
+ LISTBASE_FOREACH (bDeformGroup *, defgroup, defbase) {
writestruct(wd, DATA, bDeformGroup, 1, defgroup);
}
}
static void write_fmaps(WriteData *wd, ListBase *fbase)
{
- for (bFaceMap *fmap = fbase->first; fmap; fmap = fmap->next) {
+ LISTBASE_FOREACH (bFaceMap *, fmap, fbase) {
writestruct(wd, DATA, bFaceMap, 1, fmap);
}
}
@@ -1646,7 +1698,7 @@ static void write_modifiers(WriteData *wd, ListBase *modbase)
}
for (md = modbase->first; md; md = md->next) {
- const ModifierTypeInfo *mti = modifierType_getInfo(md->type);
+ const ModifierTypeInfo *mti = BKE_modifier_get_info(md->type);
if (mti == NULL) {
return;
}
@@ -1829,7 +1881,7 @@ static void write_gpencil_modifiers(WriteData *wd, ListBase *modbase)
}
for (md = modbase->first; md; md = md->next) {
- const GpencilModifierTypeInfo *mti = BKE_gpencil_modifierType_getInfo(md->type);
+ const GpencilModifierTypeInfo *mti = BKE_gpencil_modifier_get_info(md->type);
if (mti == NULL) {
return;
}
@@ -1896,7 +1948,7 @@ static void write_shaderfxs(WriteData *wd, ListBase *fxbase)
}
for (fx = fxbase->first; fx; fx = fx->next) {
- const ShaderFxTypeInfo *fxi = BKE_shaderfxType_getInfo(fx->type);
+ const ShaderFxTypeInfo *fxi = BKE_shaderfx_get_info(fx->type);
if (fxi == NULL) {
return;
}
@@ -1905,11 +1957,14 @@ static void write_shaderfxs(WriteData *wd, ListBase *fxbase)
}
}
-static void write_object(WriteData *wd, Object *ob)
+static void write_object(WriteData *wd, Object *ob, const void *id_address)
{
if (ob->id.us > 0 || wd->use_memfile) {
+ /* Clean up, important in undo case to reduce false detection of changed datablocks. */
+ BKE_object_runtime_reset(ob);
+
/* write LibData */
- writestruct(wd, ID_OB, Object, 1, ob);
+ writestruct_at_address(wd, ID_OB, Object, 1, id_address, ob);
write_iddata(wd, &ob->id);
if (ob->adt) {
@@ -1970,11 +2025,15 @@ static void write_object(WriteData *wd, Object *ob)
}
}
-static void write_vfont(WriteData *wd, VFont *vf)
+static void write_vfont(WriteData *wd, VFont *vf, const void *id_address)
{
if (vf->id.us > 0 || wd->use_memfile) {
+ /* Clean up, important in undo case to reduce false detection of changed datablocks. */
+ vf->data = NULL;
+ vf->temp_pf = NULL;
+
/* write LibData */
- writestruct(wd, ID_VF, VFont, 1, vf);
+ writestruct_at_address(wd, ID_VF, VFont, 1, id_address, vf);
write_iddata(wd, &vf->id);
/* direct data */
@@ -1986,11 +2045,11 @@ static void write_vfont(WriteData *wd, VFont *vf)
}
}
-static void write_key(WriteData *wd, Key *key)
+static void write_key(WriteData *wd, Key *key, const void *id_address)
{
if (key->id.us > 0 || wd->use_memfile) {
/* write LibData */
- writestruct(wd, ID_KE, Key, 1, key);
+ writestruct_at_address(wd, ID_KE, Key, 1, id_address, key);
write_iddata(wd, &key->id);
if (key->adt) {
@@ -1998,7 +2057,7 @@ static void write_key(WriteData *wd, Key *key)
}
/* direct data */
- for (KeyBlock *kb = key->block.first; kb; kb = kb->next) {
+ LISTBASE_FOREACH (KeyBlock *, kb, &key->block) {
writestruct(wd, DATA, KeyBlock, 1, kb);
if (kb->data) {
writedata(wd, DATA, kb->totelem * key->elemsize, kb->data);
@@ -2007,28 +2066,36 @@ static void write_key(WriteData *wd, Key *key)
}
}
-static void write_camera(WriteData *wd, Camera *cam)
+static void write_camera(WriteData *wd, Camera *cam, const void *id_address)
{
if (cam->id.us > 0 || wd->use_memfile) {
/* write LibData */
- writestruct(wd, ID_CA, Camera, 1, cam);
+ writestruct_at_address(wd, ID_CA, Camera, 1, id_address, cam);
write_iddata(wd, &cam->id);
if (cam->adt) {
write_animdata(wd, cam->adt);
}
- for (CameraBGImage *bgpic = cam->bg_images.first; bgpic; bgpic = bgpic->next) {
+ LISTBASE_FOREACH (CameraBGImage *, bgpic, &cam->bg_images) {
writestruct(wd, DATA, CameraBGImage, 1, bgpic);
}
}
}
-static void write_mball(WriteData *wd, MetaBall *mb)
+static void write_mball(WriteData *wd, MetaBall *mb, const void *id_address)
{
if (mb->id.us > 0 || wd->use_memfile) {
+ /* Clean up, important in undo case to reduce false detection of changed datablocks. */
+ BLI_listbase_clear(&mb->disp);
+ mb->editelems = NULL;
+ /* Must always be cleared (meta's don't have their own edit-data). */
+ mb->needs_flush_to_id = 0;
+ mb->lastelem = NULL;
+ mb->batch_cache = NULL;
+
/* write LibData */
- writestruct(wd, ID_MB, MetaBall, 1, mb);
+ writestruct_at_address(wd, ID_MB, MetaBall, 1, id_address, mb);
write_iddata(wd, &mb->id);
/* direct data */
@@ -2037,17 +2104,22 @@ static void write_mball(WriteData *wd, MetaBall *mb)
write_animdata(wd, mb->adt);
}
- for (MetaElem *ml = mb->elems.first; ml; ml = ml->next) {
+ LISTBASE_FOREACH (MetaElem *, ml, &mb->elems) {
writestruct(wd, DATA, MetaElem, 1, ml);
}
}
}
-static void write_curve(WriteData *wd, Curve *cu)
+static void write_curve(WriteData *wd, Curve *cu, const void *id_address)
{
if (cu->id.us > 0 || wd->use_memfile) {
+ /* Clean up, important in undo case to reduce false detection of changed datablocks. */
+ cu->editnurb = NULL;
+ cu->editfont = NULL;
+ cu->batch_cache = NULL;
+
/* write LibData */
- writestruct(wd, ID_CU, Curve, 1, cu);
+ writestruct_at_address(wd, ID_CU, Curve, 1, id_address, cu);
write_iddata(wd, &cu->id);
/* direct data */
@@ -2063,10 +2135,10 @@ static void write_curve(WriteData *wd, Curve *cu)
}
else {
/* is also the order of reading */
- for (Nurb *nu = cu->nurb.first; nu; nu = nu->next) {
+ LISTBASE_FOREACH (Nurb *, nu, &cu->nurb) {
writestruct(wd, DATA, Nurb, 1, nu);
}
- for (Nurb *nu = cu->nurb.first; nu; nu = nu->next) {
+ LISTBASE_FOREACH (Nurb *, nu, &cu->nurb) {
if (nu->type == CU_BEZIER) {
writestruct(wd, DATA, BezTriple, nu->pntsu, nu->bezt);
}
@@ -2186,7 +2258,7 @@ static void write_customdata(WriteData *wd,
datasize = structnum * count;
writestruct_id(wd, DATA, structname, datasize, layer->data);
}
- else {
+ else if (!wd->use_memfile) { /* Do not warn on undo. */
printf("%s error: layer '%s':%d - can't be written to file\n",
__func__,
structname,
@@ -2200,19 +2272,14 @@ static void write_customdata(WriteData *wd,
}
}
-static void write_mesh(WriteData *wd, Mesh *mesh)
+static void write_mesh(WriteData *wd, Mesh *mesh, const void *id_address)
{
if (mesh->id.us > 0 || wd->use_memfile) {
- /* Write a copy of the mesh with possibly reduced number of data layers.
- * Don't edit the original since other threads might be reading it. */
- Mesh *old_mesh = mesh;
- Mesh copy_mesh = *mesh;
- mesh = &copy_mesh;
-
/* cache only - don't write */
mesh->mface = NULL;
mesh->totface = 0;
memset(&mesh->fdata, 0, sizeof(mesh->fdata));
+ memset(&mesh->runtime, 0, sizeof(mesh->runtime));
/* Reduce xdata layers, fill xlayers with layers to be written.
* This makes xdata invalid for Blender, which is why we made a
@@ -2229,7 +2296,7 @@ static void write_mesh(WriteData *wd, Mesh *mesh)
CustomData_file_write_prepare(&mesh->ldata, &llayers, llayers_buff, ARRAY_SIZE(llayers_buff));
CustomData_file_write_prepare(&mesh->pdata, &players, players_buff, ARRAY_SIZE(players_buff));
- writestruct_at_address(wd, ID_ME, Mesh, 1, old_mesh, mesh);
+ writestruct_at_address(wd, ID_ME, Mesh, 1, id_address, mesh);
write_iddata(wd, &mesh->id);
/* direct data */
@@ -2247,9 +2314,6 @@ static void write_mesh(WriteData *wd, Mesh *mesh)
write_customdata(wd, &mesh->id, mesh->totloop, &mesh->ldata, llayers, CD_MASK_MESH.lmask);
write_customdata(wd, &mesh->id, mesh->totpoly, &mesh->pdata, players, CD_MASK_MESH.pmask);
- /* restore pointer */
- mesh = old_mesh;
-
/* free temporary data */
if (vlayers && vlayers != vlayers_buff) {
MEM_freeN(vlayers);
@@ -2269,11 +2333,15 @@ static void write_mesh(WriteData *wd, Mesh *mesh)
}
}
-static void write_lattice(WriteData *wd, Lattice *lt)
+static void write_lattice(WriteData *wd, Lattice *lt, const void *id_address)
{
if (lt->id.us > 0 || wd->use_memfile) {
+ /* Clean up, important in undo case to reduce false detection of changed datablocks. */
+ lt->editlatt = NULL;
+ lt->batch_cache = NULL;
+
/* write LibData */
- writestruct(wd, ID_LT, Lattice, 1, lt);
+ writestruct_at_address(wd, ID_LT, Lattice, 1, id_address, lt);
write_iddata(wd, &lt->id);
/* write animdata */
@@ -2288,7 +2356,7 @@ static void write_lattice(WriteData *wd, Lattice *lt)
}
}
-static void write_image(WriteData *wd, Image *ima)
+static void write_image(WriteData *wd, Image *ima, const void *id_address)
{
if (ima->id.us > 0 || wd->use_memfile) {
ImagePackedFile *imapf;
@@ -2301,7 +2369,7 @@ static void write_image(WriteData *wd, Image *ima)
}
/* write LibData */
- writestruct(wd, ID_IM, Image, 1, ima);
+ writestruct_at_address(wd, ID_IM, Image, 1, id_address, ima);
write_iddata(wd, &ima->id);
for (imapf = ima->packedfiles.first; imapf; imapf = imapf->next) {
@@ -2315,7 +2383,7 @@ static void write_image(WriteData *wd, Image *ima)
write_previews(wd, ima->preview);
- for (ImageView *iv = ima->views.first; iv; iv = iv->next) {
+ LISTBASE_FOREACH (ImageView *, iv, &ima->views) {
writestruct(wd, DATA, ImageView, 1, iv);
}
writestruct(wd, DATA, Stereo3dFormat, 1, ima->stereo3d_format);
@@ -2328,11 +2396,11 @@ static void write_image(WriteData *wd, Image *ima)
}
}
-static void write_texture(WriteData *wd, Tex *tex)
+static void write_texture(WriteData *wd, Tex *tex, const void *id_address)
{
if (tex->id.us > 0 || wd->use_memfile) {
/* write LibData */
- writestruct(wd, ID_TE, Tex, 1, tex);
+ writestruct_at_address(wd, ID_TE, Tex, 1, id_address, tex);
write_iddata(wd, &tex->id);
if (tex->adt) {
@@ -2354,11 +2422,15 @@ static void write_texture(WriteData *wd, Tex *tex)
}
}
-static void write_material(WriteData *wd, Material *ma)
+static void write_material(WriteData *wd, Material *ma, const void *id_address)
{
if (ma->id.us > 0 || wd->use_memfile) {
+ /* Clean up, important in undo case to reduce false detection of changed datablocks. */
+ ma->texpaintslot = NULL;
+ BLI_listbase_clear(&ma->gpumaterial);
+
/* write LibData */
- writestruct(wd, ID_MA, Material, 1, ma);
+ writestruct_at_address(wd, ID_MA, Material, 1, id_address, ma);
write_iddata(wd, &ma->id);
if (ma->adt) {
@@ -2380,11 +2452,14 @@ static void write_material(WriteData *wd, Material *ma)
}
}
-static void write_world(WriteData *wd, World *wrld)
+static void write_world(WriteData *wd, World *wrld, const void *id_address)
{
if (wrld->id.us > 0 || wd->use_memfile) {
+ /* Clean up, important in undo case to reduce false detection of changed datablocks. */
+ BLI_listbase_clear(&wrld->gpumaterial);
+
/* write LibData */
- writestruct(wd, ID_WO, World, 1, wrld);
+ writestruct_at_address(wd, ID_WO, World, 1, id_address, wrld);
write_iddata(wd, &wrld->id);
if (wrld->adt) {
@@ -2401,11 +2476,11 @@ static void write_world(WriteData *wd, World *wrld)
}
}
-static void write_light(WriteData *wd, Light *la)
+static void write_light(WriteData *wd, Light *la, const void *id_address)
{
if (la->id.us > 0 || wd->use_memfile) {
/* write LibData */
- writestruct(wd, ID_LA, Light, 1, la);
+ writestruct_at_address(wd, ID_LA, Light, 1, id_address, la);
write_iddata(wd, &la->id);
if (la->adt) {
@@ -2431,25 +2506,26 @@ static void write_collection_nolib(WriteData *wd, Collection *collection)
/* Shared function for collection data-blocks and scene master collection. */
write_previews(wd, collection->preview);
- for (CollectionObject *cob = collection->gobject.first; cob; cob = cob->next) {
+ LISTBASE_FOREACH (CollectionObject *, cob, &collection->gobject) {
writestruct(wd, DATA, CollectionObject, 1, cob);
}
- for (CollectionChild *child = collection->children.first; child; child = child->next) {
+ LISTBASE_FOREACH (CollectionChild *, child, &collection->children) {
writestruct(wd, DATA, CollectionChild, 1, child);
}
-
- /* Clear the accumulated recalc flags in case of undo step saving. */
- if (wd->use_memfile) {
- collection->id.recalc_undo_accumulated = 0;
- }
}
-static void write_collection(WriteData *wd, Collection *collection)
+static void write_collection(WriteData *wd, Collection *collection, const void *id_address)
{
if (collection->id.us > 0 || wd->use_memfile) {
+ /* Clean up, important in undo case to reduce false detection of changed datablocks. */
+ collection->flag &= ~COLLECTION_HAS_OBJECT_CACHE;
+ collection->tag = 0;
+ BLI_listbase_clear(&collection->object_cache);
+ BLI_listbase_clear(&collection->parents);
+
/* write LibData */
- writestruct(wd, ID_GR, Collection, 1, collection);
+ writestruct_at_address(wd, ID_GR, Collection, 1, id_address, collection);
write_iddata(wd, &collection->id);
write_collection_nolib(wd, collection);
@@ -2507,7 +2583,7 @@ static void write_paint(WriteData *wd, Paint *p)
static void write_layer_collections(WriteData *wd, ListBase *lb)
{
- for (LayerCollection *lc = lb->first; lc; lc = lc->next) {
+ LISTBASE_FOREACH (LayerCollection *, lc, lb) {
writestruct(wd, DATA, LayerCollection, 1, lc);
write_layer_collections(wd, &lc->layer_collections);
@@ -2523,12 +2599,11 @@ static void write_view_layer(WriteData *wd, ViewLayer *view_layer)
IDP_WriteProperty(view_layer->id_properties, wd);
}
- for (FreestyleModuleConfig *fmc = view_layer->freestyle_config.modules.first; fmc;
- fmc = fmc->next) {
+ LISTBASE_FOREACH (FreestyleModuleConfig *, fmc, &view_layer->freestyle_config.modules) {
writestruct(wd, DATA, FreestyleModuleConfig, 1, fmc);
}
- for (FreestyleLineSet *fls = view_layer->freestyle_config.linesets.first; fls; fls = fls->next) {
+ LISTBASE_FOREACH (FreestyleLineSet *, fls, &view_layer->freestyle_config.linesets) {
writestruct(wd, DATA, FreestyleLineSet, 1, fls);
}
write_layer_collections(wd, &view_layer->layer_collections);
@@ -2564,10 +2639,16 @@ static void write_lightcache(WriteData *wd, LightCache *cache)
writestruct(wd, DATA, LightProbeCache, cache->cube_len, cache->cube_data);
}
-static void write_scene(WriteData *wd, Scene *sce)
+static void write_scene(WriteData *wd, Scene *sce, const void *id_address)
{
+ if (wd->use_memfile) {
+ /* Clean up, important in undo case to reduce false detection of changed datablocks. */
+ /* XXX This UI data should not be stored in Scene at all... */
+ memset(&sce->cursor, 0, sizeof(sce->cursor));
+ }
+
/* write LibData */
- writestruct(wd, ID_SCE, Scene, 1, sce);
+ writestruct_at_address(wd, ID_SCE, Scene, 1, id_address, sce);
write_iddata(wd, &sce->id);
if (sce->adt) {
@@ -2714,7 +2795,7 @@ static void write_scene(WriteData *wd, Scene *sce)
SEQ_END;
/* new; meta stack too, even when its nasty restore code */
- for (MetaStack *ms = ed->metastack.first; ms; ms = ms->next) {
+ LISTBASE_FOREACH (MetaStack *, ms, &ed->metastack) {
writestruct(wd, DATA, MetaStack, 1, ms);
}
}
@@ -2733,17 +2814,17 @@ static void write_scene(WriteData *wd, Scene *sce)
}
/* writing dynamic list of TimeMarkers to the blend file */
- for (TimeMarker *marker = sce->markers.first; marker; marker = marker->next) {
+ LISTBASE_FOREACH (TimeMarker *, marker, &sce->markers) {
writestruct(wd, DATA, TimeMarker, 1, marker);
}
/* writing dynamic list of TransformOrientations to the blend file */
- for (TransformOrientation *ts = sce->transform_spaces.first; ts; ts = ts->next) {
+ LISTBASE_FOREACH (TransformOrientation *, ts, &sce->transform_spaces) {
writestruct(wd, DATA, TransformOrientation, 1, ts);
}
/* writing MultiView to the blend file */
- for (SceneRenderView *srv = sce->r.views.first; srv; srv = srv->next) {
+ LISTBASE_FOREACH (SceneRenderView *, srv, &sce->r.views) {
writestruct(wd, DATA, SceneRenderView, 1, srv);
}
@@ -2769,7 +2850,7 @@ static void write_scene(WriteData *wd, Scene *sce)
write_previews(wd, sce->preview);
write_curvemapping_curves(wd, &sce->r.mblur_shutter_curve);
- for (ViewLayer *view_layer = sce->view_layers.first; view_layer; view_layer = view_layer->next) {
+ LISTBASE_FOREACH (ViewLayer *, view_layer, &sce->view_layers) {
write_view_layer(wd, view_layer);
}
@@ -2790,11 +2871,19 @@ static void write_scene(WriteData *wd, Scene *sce)
BLI_assert(sce->layer_properties == NULL);
}
-static void write_gpencil(WriteData *wd, bGPdata *gpd)
+static void write_gpencil(WriteData *wd, bGPdata *gpd, const void *id_address)
{
if (gpd->id.us > 0 || wd->use_memfile) {
+ /* Clean up, important in undo case to reduce false detection of changed data-blocks. */
+ /* XXX not sure why the whole run-time data is not cleared in reading code,
+ * for now mimicking it here. */
+ gpd->runtime.sbuffer = NULL;
+ gpd->runtime.sbuffer_used = 0;
+ gpd->runtime.sbuffer_size = 0;
+ gpd->runtime.tot_cp_points = 0;
+
/* write gpd data block to file */
- writestruct(wd, ID_GD, bGPdata, 1, gpd);
+ writestruct_at_address(wd, ID_GD, bGPdata, 1, id_address, gpd);
write_iddata(wd, &gpd->id);
if (gpd->adt) {
@@ -2914,35 +3003,33 @@ static void write_soops(WriteData *wd, SpaceOutliner *so)
static void write_panel_list(WriteData *wd, ListBase *lb)
{
- for (Panel *pa = lb->first; pa; pa = pa->next) {
- writestruct(wd, DATA, Panel, 1, pa);
- write_panel_list(wd, &pa->children);
+ LISTBASE_FOREACH (Panel *, panel, lb) {
+ writestruct(wd, DATA, Panel, 1, panel);
+ write_panel_list(wd, &panel->children);
}
}
static void write_area_regions(WriteData *wd, ScrArea *area)
{
- for (ARegion *region = area->regionbase.first; region; region = region->next) {
+ LISTBASE_FOREACH (ARegion *, region, &area->regionbase) {
write_region(wd, region, area->spacetype);
write_panel_list(wd, &region->panels);
- for (PanelCategoryStack *pc_act = region->panels_category_active.first; pc_act;
- pc_act = pc_act->next) {
+ LISTBASE_FOREACH (PanelCategoryStack *, pc_act, &region->panels_category_active) {
writestruct(wd, DATA, PanelCategoryStack, 1, pc_act);
}
- for (uiList *ui_list = region->ui_lists.first; ui_list; ui_list = ui_list->next) {
+ LISTBASE_FOREACH (uiList *, ui_list, &region->ui_lists) {
write_uilist(wd, ui_list);
}
- for (uiPreview *ui_preview = region->ui_previews.first; ui_preview;
- ui_preview = ui_preview->next) {
+ LISTBASE_FOREACH (uiPreview *, ui_preview, &region->ui_previews) {
writestruct(wd, DATA, uiPreview, 1, ui_preview);
}
}
- for (SpaceLink *sl = area->spacedata.first; sl; sl = sl->next) {
- for (ARegion *region = sl->regionbase.first; region; region = region->next) {
+ LISTBASE_FOREACH (SpaceLink *, sl, &area->spacedata) {
+ LISTBASE_FOREACH (ARegion *, region, &sl->regionbase) {
write_region(wd, region, sl->spacetype);
}
@@ -3055,7 +3142,7 @@ static void write_area_map(WriteData *wd, ScrAreaMap *area_map)
{
writelist(wd, DATA, ScrVert, &area_map->vertbase);
writelist(wd, DATA, ScrEdge, &area_map->edgebase);
- for (ScrArea *area = area_map->areabase.first; area; area = area->next) {
+ LISTBASE_FOREACH (ScrArea *, area, &area_map->areabase) {
area->butspacetype = area->spacetype; /* Just for compatibility, will be reset below. */
writestruct(wd, DATA, ScrArea, 1, area);
@@ -3070,13 +3157,13 @@ static void write_area_map(WriteData *wd, ScrAreaMap *area_map)
}
}
-static void write_windowmanager(WriteData *wd, wmWindowManager *wm)
+static void write_windowmanager(BlendWriter *writer, wmWindowManager *wm, const void *id_address)
{
- writestruct(wd, ID_WM, wmWindowManager, 1, wm);
- write_iddata(wd, &wm->id);
- write_wm_xr_data(wd, &wm->xr);
+ BLO_write_id_struct(writer, wmWindowManager, id_address, &wm->id);
+ write_iddata(writer->wd, &wm->id);
+ write_wm_xr_data(writer->wd, &wm->xr);
- for (wmWindow *win = wm->windows.first; win; win = win->next) {
+ LISTBASE_FOREACH (wmWindow *, win, &wm->windows) {
#ifndef WITH_GLOBAL_AREA_WRITING
/* Don't write global areas yet, while we make changes to them. */
ScrAreaMap global_areas = win->global_areas;
@@ -3086,12 +3173,12 @@ static void write_windowmanager(WriteData *wd, wmWindowManager *wm)
/* update deprecated screen member (for so loading in 2.7x uses the correct screen) */
win->screen = BKE_workspace_active_screen_get(win->workspace_hook);
- writestruct(wd, DATA, wmWindow, 1, win);
- writestruct(wd, DATA, WorkSpaceInstanceHook, 1, win->workspace_hook);
- writestruct(wd, DATA, Stereo3dFormat, 1, win->stereo3d_format);
+ BLO_write_struct(writer, wmWindow, win);
+ BLO_write_struct(writer, WorkSpaceInstanceHook, win->workspace_hook);
+ BLO_write_struct(writer, Stereo3dFormat, win->stereo3d_format);
#ifdef WITH_GLOBAL_AREA_WRITING
- write_area_map(wd, &win->global_areas);
+ write_area_map(writer->wd, &win->global_areas);
#else
win->global_areas = global_areas;
#endif
@@ -3101,19 +3188,19 @@ static void write_windowmanager(WriteData *wd, wmWindowManager *wm)
}
}
-static void write_screen(WriteData *wd, bScreen *sc)
+static void write_screen(WriteData *wd, bScreen *screen, const void *id_address)
{
/* Screens are reference counted, only saved if used by a workspace. */
- if (sc->id.us > 0 || wd->use_memfile) {
+ if (screen->id.us > 0 || wd->use_memfile) {
/* write LibData */
/* in 2.50+ files, the file identifier for screens is patched, forward compatibility */
- writestruct(wd, ID_SCRN, bScreen, 1, sc);
- write_iddata(wd, &sc->id);
+ writestruct_at_address(wd, ID_SCRN, bScreen, 1, id_address, screen);
+ write_iddata(wd, &screen->id);
- write_previews(wd, sc->preview);
+ write_previews(wd, screen->preview);
/* direct data */
- write_area_map(wd, AREAMAP_FROM_SCREEN(sc));
+ write_area_map(wd, AREAMAP_FROM_SCREEN(screen));
}
}
@@ -3132,15 +3219,22 @@ static void write_bone(WriteData *wd, Bone *bone)
}
/* Write Children */
- for (Bone *cbone = bone->childbase.first; cbone; cbone = cbone->next) {
+ LISTBASE_FOREACH (Bone *, cbone, &bone->childbase) {
write_bone(wd, cbone);
}
}
-static void write_armature(WriteData *wd, bArmature *arm)
+static void write_armature(WriteData *wd, bArmature *arm, const void *id_address)
{
if (arm->id.us > 0 || wd->use_memfile) {
- writestruct(wd, ID_AR, bArmature, 1, arm);
+ /* Clean up, important in undo case to reduce false detection of changed datablocks. */
+ arm->bonehash = NULL;
+ arm->edbo = NULL;
+ /* Must always be cleared (armatures don't have their own edit-data). */
+ arm->needs_flush_to_id = 0;
+ arm->act_edbone = NULL;
+
+ writestruct_at_address(wd, ID_AR, bArmature, 1, id_address, arm);
write_iddata(wd, &arm->id);
if (arm->adt) {
@@ -3148,20 +3242,24 @@ static void write_armature(WriteData *wd, bArmature *arm)
}
/* Direct data */
- for (Bone *bone = arm->bonebase.first; bone; bone = bone->next) {
+ LISTBASE_FOREACH (Bone *, bone, &arm->bonebase) {
write_bone(wd, bone);
}
}
}
-static void write_text(WriteData *wd, Text *text)
+static void write_text(WriteData *wd, Text *text, const void *id_address)
{
+ /* Note: we are clearing local temp data here, *not* the flag in the actual 'real' ID. */
if ((text->flags & TXT_ISMEM) && (text->flags & TXT_ISEXT)) {
text->flags &= ~TXT_ISEXT;
}
+ /* Clean up, important in undo case to reduce false detection of changed datablocks. */
+ text->compiled = NULL;
+
/* write LibData */
- writestruct(wd, ID_TXT, Text, 1, text);
+ writestruct_at_address(wd, ID_TXT, Text, 1, id_address, text);
write_iddata(wd, &text->id);
if (text->name) {
@@ -3170,21 +3268,21 @@ static void write_text(WriteData *wd, Text *text)
if (!(text->flags & TXT_ISEXT)) {
/* now write the text data, in two steps for optimization in the readfunction */
- for (TextLine *tmp = text->lines.first; tmp; tmp = tmp->next) {
+ LISTBASE_FOREACH (TextLine *, tmp, &text->lines) {
writestruct(wd, DATA, TextLine, 1, tmp);
}
- for (TextLine *tmp = text->lines.first; tmp; tmp = tmp->next) {
+ LISTBASE_FOREACH (TextLine *, tmp, &text->lines) {
writedata(wd, DATA, tmp->len + 1, tmp->line);
}
}
}
-static void write_speaker(WriteData *wd, Speaker *spk)
+static void write_speaker(WriteData *wd, Speaker *spk, const void *id_address)
{
if (spk->id.us > 0 || wd->use_memfile) {
/* write LibData */
- writestruct(wd, ID_SPK, Speaker, 1, spk);
+ writestruct_at_address(wd, ID_SPK, Speaker, 1, id_address, spk);
write_iddata(wd, &spk->id);
if (spk->adt) {
@@ -3193,11 +3291,17 @@ static void write_speaker(WriteData *wd, Speaker *spk)
}
}
-static void write_sound(WriteData *wd, bSound *sound)
+static void write_sound(WriteData *wd, bSound *sound, const void *id_address)
{
if (sound->id.us > 0 || wd->use_memfile) {
+ /* Clean up, important in undo case to reduce false detection of changed datablocks. */
+ sound->tags = 0;
+ sound->handle = NULL;
+ sound->playback_handle = NULL;
+ sound->spinlock = NULL;
+
/* write LibData */
- writestruct(wd, ID_SO, bSound, 1, sound);
+ writestruct_at_address(wd, ID_SO, bSound, 1, id_address, sound);
write_iddata(wd, &sound->id);
if (sound->packedfile) {
@@ -3208,11 +3312,11 @@ static void write_sound(WriteData *wd, bSound *sound)
}
}
-static void write_probe(WriteData *wd, LightProbe *prb)
+static void write_probe(WriteData *wd, LightProbe *prb, const void *id_address)
{
if (prb->id.us > 0 || wd->use_memfile) {
/* write LibData */
- writestruct(wd, ID_LP, LightProbe, 1, prb);
+ writestruct_at_address(wd, ID_LP, LightProbe, 1, id_address, prb);
write_iddata(wd, &prb->id);
if (prb->adt) {
@@ -3221,10 +3325,18 @@ static void write_probe(WriteData *wd, LightProbe *prb)
}
}
-static void write_nodetree(WriteData *wd, bNodeTree *ntree)
+static void write_nodetree(WriteData *wd, bNodeTree *ntree, const void *id_address)
{
if (ntree->id.us > 0 || wd->use_memfile) {
- writestruct(wd, ID_NT, bNodeTree, 1, ntree);
+ /* Clean up, important in undo case to reduce false detection of changed datablocks. */
+ ntree->init = 0; /* to set callbacks and force setting types */
+ ntree->is_updating = false;
+ ntree->typeinfo = NULL;
+ ntree->interface_type = NULL;
+ ntree->progress = NULL;
+ ntree->execdata = NULL;
+
+ writestruct_at_address(wd, ID_NT, bNodeTree, 1, id_address, ntree);
/* Note that trees directly used by other IDs (materials etc.) are not 'real' ID, they cannot
* be linked, etc., so we write actual id data here only, for 'real' ID trees. */
write_iddata(wd, &ntree->id);
@@ -3233,10 +3345,10 @@ static void write_nodetree(WriteData *wd, bNodeTree *ntree)
}
}
-static void write_brush(WriteData *wd, Brush *brush)
+static void write_brush(WriteData *wd, Brush *brush, const void *id_address)
{
if (brush->id.us > 0 || wd->use_memfile) {
- writestruct(wd, ID_BR, Brush, 1, brush);
+ writestruct_at_address(wd, ID_BR, Brush, 1, id_address, brush);
write_iddata(wd, &brush->id);
if (brush->curve) {
@@ -3255,6 +3367,24 @@ static void write_brush(WriteData *wd, Brush *brush)
if (brush->gpencil_settings->curve_jitter) {
write_curvemapping(wd, brush->gpencil_settings->curve_jitter);
}
+ if (brush->gpencil_settings->curve_rand_pressure) {
+ write_curvemapping(wd, brush->gpencil_settings->curve_rand_pressure);
+ }
+ if (brush->gpencil_settings->curve_rand_strength) {
+ write_curvemapping(wd, brush->gpencil_settings->curve_rand_strength);
+ }
+ if (brush->gpencil_settings->curve_rand_uv) {
+ write_curvemapping(wd, brush->gpencil_settings->curve_rand_uv);
+ }
+ if (brush->gpencil_settings->curve_rand_hue) {
+ write_curvemapping(wd, brush->gpencil_settings->curve_rand_hue);
+ }
+ if (brush->gpencil_settings->curve_rand_saturation) {
+ write_curvemapping(wd, brush->gpencil_settings->curve_rand_saturation);
+ }
+ if (brush->gpencil_settings->curve_rand_value) {
+ write_curvemapping(wd, brush->gpencil_settings->curve_rand_value);
+ }
}
if (brush->gradient) {
writestruct(wd, DATA, ColorBand, 1, brush->gradient);
@@ -3262,11 +3392,11 @@ static void write_brush(WriteData *wd, Brush *brush)
}
}
-static void write_palette(WriteData *wd, Palette *palette)
+static void write_palette(WriteData *wd, Palette *palette, const void *id_address)
{
if (palette->id.us > 0 || wd->use_memfile) {
PaletteColor *color;
- writestruct(wd, ID_PAL, Palette, 1, palette);
+ writestruct_at_address(wd, ID_PAL, Palette, 1, id_address, palette);
write_iddata(wd, &palette->id);
for (color = palette->colors.first; color; color = color->next) {
@@ -3275,10 +3405,10 @@ static void write_palette(WriteData *wd, Palette *palette)
}
}
-static void write_paintcurve(WriteData *wd, PaintCurve *pc)
+static void write_paintcurve(WriteData *wd, PaintCurve *pc, const void *id_address)
{
if (pc->id.us > 0 || wd->use_memfile) {
- writestruct(wd, ID_PC, PaintCurve, 1, pc);
+ writestruct_at_address(wd, ID_PC, PaintCurve, 1, id_address, pc);
write_iddata(wd, &pc->id);
writestruct(wd, DATA, PaintCurvePoint, pc->tot_points, pc->points);
@@ -3324,13 +3454,18 @@ static void write_movieReconstruction(WriteData *wd, MovieTrackingReconstruction
}
}
-static void write_movieclip(WriteData *wd, MovieClip *clip)
+static void write_movieclip(WriteData *wd, MovieClip *clip, const void *id_address)
{
if (clip->id.us > 0 || wd->use_memfile) {
+ /* Clean up, important in undo case to reduce false detection of changed datablocks. */
+ clip->anim = NULL;
+ clip->tracking_context = NULL;
+ clip->tracking.stats = NULL;
+
MovieTracking *tracking = &clip->tracking;
MovieTrackingObject *object;
- writestruct(wd, ID_MC, MovieClip, 1, clip);
+ writestruct_at_address(wd, ID_MC, MovieClip, 1, id_address, clip);
write_iddata(wd, &clip->id);
if (clip->adt) {
@@ -3354,12 +3489,12 @@ static void write_movieclip(WriteData *wd, MovieClip *clip)
}
}
-static void write_mask(WriteData *wd, Mask *mask)
+static void write_mask(WriteData *wd, Mask *mask, const void *id_address)
{
if (mask->id.us > 0 || wd->use_memfile) {
MaskLayer *masklay;
- writestruct(wd, ID_MSK, Mask, 1, mask);
+ writestruct_at_address(wd, ID_MSK, Mask, 1, id_address, mask);
write_iddata(wd, &mask->id);
if (mask->adt) {
@@ -3661,10 +3796,10 @@ static void write_linestyle_geometry_modifiers(WriteData *wd, ListBase *modifier
}
}
-static void write_linestyle(WriteData *wd, FreestyleLineStyle *linestyle)
+static void write_linestyle(WriteData *wd, FreestyleLineStyle *linestyle, const void *id_address)
{
if (linestyle->id.us > 0 || wd->use_memfile) {
- writestruct(wd, ID_LS, FreestyleLineStyle, 1, linestyle);
+ writestruct_at_address(wd, ID_LS, FreestyleLineStyle, 1, id_address, linestyle);
write_iddata(wd, &linestyle->id);
if (linestyle->adt) {
@@ -3687,10 +3822,16 @@ static void write_linestyle(WriteData *wd, FreestyleLineStyle *linestyle)
}
}
-static void write_cachefile(WriteData *wd, CacheFile *cache_file)
+static void write_cachefile(WriteData *wd, CacheFile *cache_file, const void *id_address)
{
if (cache_file->id.us > 0 || wd->use_memfile) {
- writestruct(wd, ID_CF, CacheFile, 1, cache_file);
+ /* Clean up, important in undo case to reduce false detection of changed datablocks. */
+ BLI_listbase_clear(&cache_file->object_paths);
+ cache_file->handle = NULL;
+ memset(cache_file->handle_filepath, 0, sizeof(cache_file->handle_filepath));
+ cache_file->handle_readers = NULL;
+
+ writestruct_at_address(wd, ID_CF, CacheFile, 1, id_address, cache_file);
if (cache_file->adt) {
write_animdata(wd, cache_file->adt);
@@ -3698,39 +3839,31 @@ static void write_cachefile(WriteData *wd, CacheFile *cache_file)
}
}
-static void write_workspace(WriteData *wd, WorkSpace *workspace)
+static void write_workspace(BlendWriter *writer, WorkSpace *workspace, const void *id_address)
{
- ListBase *layouts = BKE_workspace_layouts_get(workspace);
-
- writestruct(wd, ID_WS, WorkSpace, 1, workspace);
- write_iddata(wd, &workspace->id);
- writelist(wd, DATA, WorkSpaceLayout, layouts);
- writelist(wd, DATA, WorkSpaceDataRelation, &workspace->hook_layout_relations);
- writelist(wd, DATA, wmOwnerID, &workspace->owner_ids);
- writelist(wd, DATA, bToolRef, &workspace->tools);
- for (bToolRef *tref = workspace->tools.first; tref; tref = tref->next) {
+ BLO_write_id_struct(writer, WorkSpace, id_address, &workspace->id);
+ write_iddata(writer->wd, &workspace->id);
+ BLO_write_struct_list(writer, WorkSpaceLayout, &workspace->layouts);
+ BLO_write_struct_list(writer, WorkSpaceDataRelation, &workspace->hook_layout_relations);
+ BLO_write_struct_list(writer, wmOwnerID, &workspace->owner_ids);
+ BLO_write_struct_list(writer, bToolRef, &workspace->tools);
+ LISTBASE_FOREACH (bToolRef *, tref, &workspace->tools) {
if (tref->properties) {
- IDP_WriteProperty(tref->properties, wd);
+ IDP_WriteProperty_new_api(tref->properties, writer);
}
}
}
-static void write_hair(WriteData *wd, Hair *hair)
+static void write_hair(WriteData *wd, Hair *hair, const void *id_address)
{
if (hair->id.us > 0 || wd->use_memfile) {
- /* Write a copy of the hair with possibly reduced number of data layers.
- * Don't edit the original since other threads might be reading it. */
- Hair *old_hair = hair;
- Hair copy_hair = *hair;
- hair = &copy_hair;
-
CustomDataLayer *players = NULL, players_buff[CD_TEMP_CHUNK_SIZE];
CustomDataLayer *clayers = NULL, clayers_buff[CD_TEMP_CHUNK_SIZE];
CustomData_file_write_prepare(&hair->pdata, &players, players_buff, ARRAY_SIZE(players_buff));
CustomData_file_write_prepare(&hair->cdata, &clayers, clayers_buff, ARRAY_SIZE(clayers_buff));
/* Write LibData */
- writestruct_at_address(wd, ID_HA, Hair, 1, old_hair, hair);
+ writestruct_at_address(wd, ID_HA, Hair, 1, id_address, hair);
write_iddata(wd, &hair->id);
/* Direct data */
@@ -3748,27 +3881,18 @@ static void write_hair(WriteData *wd, Hair *hair)
if (clayers && clayers != clayers_buff) {
MEM_freeN(clayers);
}
-
- /* restore pointer */
- hair = old_hair;
}
}
-static void write_pointcloud(WriteData *wd, PointCloud *pointcloud)
+static void write_pointcloud(WriteData *wd, PointCloud *pointcloud, const void *id_address)
{
if (pointcloud->id.us > 0 || wd->use_memfile) {
- /* Write a copy of the pointcloud with possibly reduced number of data layers.
- * Don't edit the original since other threads might be reading it. */
- PointCloud *old_pointcloud = pointcloud;
- PointCloud copy_pointcloud = *pointcloud;
- pointcloud = &copy_pointcloud;
-
CustomDataLayer *players = NULL, players_buff[CD_TEMP_CHUNK_SIZE];
CustomData_file_write_prepare(
&pointcloud->pdata, &players, players_buff, ARRAY_SIZE(players_buff));
/* Write LibData */
- writestruct_at_address(wd, ID_PT, PointCloud, 1, old_pointcloud, pointcloud);
+ writestruct_at_address(wd, ID_PT, PointCloud, 1, id_address, pointcloud);
write_iddata(wd, &pointcloud->id);
/* Direct data */
@@ -3786,11 +3910,14 @@ static void write_pointcloud(WriteData *wd, PointCloud *pointcloud)
}
}
-static void write_volume(WriteData *wd, Volume *volume)
+static void write_volume(WriteData *wd, Volume *volume, const void *id_address)
{
if (volume->id.us > 0 || wd->use_memfile) {
+ /* Clean up, important in undo case to reduce false detection of changed datablocks. */
+ volume->runtime.grids = 0;
+
/* write LibData */
- writestruct(wd, ID_VO, Volume, 1, volume);
+ writestruct_at_address(wd, ID_VO, Volume, 1, id_address, volume);
write_iddata(wd, &volume->id);
/* direct data */
@@ -3807,6 +3934,24 @@ static void write_volume(WriteData *wd, Volume *volume)
}
}
+static void write_simulation(WriteData *wd, Simulation *simulation)
+{
+ if (simulation->id.us > 0 || wd->use_memfile) {
+ writestruct(wd, ID_SIM, Simulation, 1, simulation);
+ write_iddata(wd, &simulation->id);
+
+ if (simulation->adt) {
+ write_animdata(wd, simulation->adt);
+ }
+
+ /* nodetree is integral part of simulation, no libdata */
+ if (simulation->nodetree) {
+ writestruct(wd, DATA, bNodeTree, 1, simulation->nodetree);
+ write_nodetree_nolib(wd, simulation->nodetree);
+ }
+ }
+}
+
/* Keep it last of write_foodata functions. */
static void write_libraries(WriteData *wd, Main *main)
{
@@ -3822,6 +3967,11 @@ static void write_libraries(WriteData *wd, Main *main)
if (main->curlib && main->curlib->packedfile) {
found_one = true;
}
+ else if (wd->use_memfile) {
+ /* When writing undo step we always write all existing libraries, makes reading undo step
+ * much easier when dealing with purely indirectly used libraries. */
+ found_one = true;
+ }
else {
found_one = false;
while (!found_one && tot--) {
@@ -3909,12 +4059,12 @@ static void write_global(WriteData *wd, int fileflags, Main *mainvar)
fg.globalf = G.f;
BLI_strncpy(fg.filename, mainvar->name, sizeof(fg.filename));
- sprintf(subvstr, "%4d", BLENDER_SUBVERSION);
+ sprintf(subvstr, "%4d", BLENDER_FILE_SUBVERSION);
memcpy(fg.subvstr, subvstr, 4);
- fg.subversion = BLENDER_SUBVERSION;
- fg.minversion = BLENDER_MINVERSION;
- fg.minsubversion = BLENDER_MINSUBVERSION;
+ fg.subversion = BLENDER_FILE_SUBVERSION;
+ fg.minversion = BLENDER_FILE_MIN_VERSION;
+ fg.minsubversion = BLENDER_FILE_MIN_SUBVERSION;
#ifdef WITH_BUILDINFO
{
extern unsigned long build_commit_timestamp;
@@ -3968,7 +4118,7 @@ static bool write_file_handle(Main *mainvar,
"BLENDER%c%c%.3d",
(sizeof(void *) == 8) ? '-' : '_',
(ENDIAN_ORDER == B_ENDIAN) ? 'V' : 'v',
- BLENDER_VERSION);
+ BLENDER_FILE_VERSION);
mywrite(wd, buf, 12);
@@ -3983,6 +4133,7 @@ static bool write_file_handle(Main *mainvar,
OverrideLibraryStorage *override_storage =
wd->use_memfile ? NULL : BKE_lib_override_library_operations_store_initialize();
+#define ID_BUFFER_STATIC_SIZE 8192
/* This outer loop allows to save first data-blocks from real mainvar,
* then the temp ones from override process,
* if needed, without duplicating whole code. */
@@ -3993,10 +4144,18 @@ static bool write_file_handle(Main *mainvar,
while (a--) {
ID *id = lbarray[a]->first;
- if (id && GS(id->name) == ID_LI) {
+ if (id == NULL || GS(id->name) == ID_LI) {
continue; /* Libraries are handled separately below. */
}
+ char id_buffer_static[ID_BUFFER_STATIC_SIZE];
+ void *id_buffer = id_buffer_static;
+ const size_t idtype_struct_size = BKE_idtype_get_info_from_id(id)->struct_size;
+ if (idtype_struct_size > ID_BUFFER_STATIC_SIZE) {
+ BLI_assert(0);
+ id_buffer = MEM_mallocN(idtype_struct_size, __func__);
+ }
+
for (; id; id = id->next) {
/* We should never attempt to write non-regular IDs
* (i.e. all kind of temp/runtime ones). */
@@ -4009,117 +4168,155 @@ static bool write_file_handle(Main *mainvar,
BKE_lib_override_library_operations_store_start(bmain, override_storage, id);
}
+ if (wd->use_memfile) {
+ /* Record the changes that happened up to this undo push in
+ * recalc_up_to_undo_push, and clear recalc_after_undo_push again
+ * to start accumulating for the next undo push. */
+ id->recalc_up_to_undo_push = id->recalc_after_undo_push;
+ id->recalc_after_undo_push = 0;
+
+ bNodeTree *nodetree = ntreeFromID(id);
+ if (nodetree != NULL) {
+ nodetree->id.recalc_up_to_undo_push = nodetree->id.recalc_after_undo_push;
+ nodetree->id.recalc_after_undo_push = 0;
+ }
+ if (GS(id->name) == ID_SCE) {
+ Scene *scene = (Scene *)id;
+ if (scene->master_collection != NULL) {
+ scene->master_collection->id.recalc_up_to_undo_push =
+ scene->master_collection->id.recalc_after_undo_push;
+ scene->master_collection->id.recalc_after_undo_push = 0;
+ }
+ }
+ }
+
+ mywrite_id_begin(wd, id);
+
+ memcpy(id_buffer, id, idtype_struct_size);
+
+ ((ID *)id_buffer)->tag = 0;
+ /* Those listbase data change every time we add/remove an ID, and also often when renaming
+ * one (due to re-sorting). This avoids generating a lot of false 'is changed' detections
+ * between undo steps. */
+ ((ID *)id_buffer)->prev = NULL;
+ ((ID *)id_buffer)->next = NULL;
+
+ BlendWriter writer = {wd};
+
switch ((ID_Type)GS(id->name)) {
case ID_WM:
- write_windowmanager(wd, (wmWindowManager *)id);
+ write_windowmanager(&writer, (wmWindowManager *)id_buffer, id);
break;
case ID_WS:
- write_workspace(wd, (WorkSpace *)id);
+ write_workspace(&writer, (WorkSpace *)id_buffer, id);
break;
case ID_SCR:
- write_screen(wd, (bScreen *)id);
+ write_screen(wd, (bScreen *)id_buffer, id);
break;
case ID_MC:
- write_movieclip(wd, (MovieClip *)id);
+ write_movieclip(wd, (MovieClip *)id_buffer, id);
break;
case ID_MSK:
- write_mask(wd, (Mask *)id);
+ write_mask(wd, (Mask *)id_buffer, id);
break;
case ID_SCE:
- write_scene(wd, (Scene *)id);
+ write_scene(wd, (Scene *)id_buffer, id);
break;
case ID_CU:
- write_curve(wd, (Curve *)id);
+ write_curve(wd, (Curve *)id_buffer, id);
break;
case ID_MB:
- write_mball(wd, (MetaBall *)id);
+ write_mball(wd, (MetaBall *)id_buffer, id);
break;
case ID_IM:
- write_image(wd, (Image *)id);
+ write_image(wd, (Image *)id_buffer, id);
break;
case ID_CA:
- write_camera(wd, (Camera *)id);
+ write_camera(wd, (Camera *)id_buffer, id);
break;
case ID_LA:
- write_light(wd, (Light *)id);
+ write_light(wd, (Light *)id_buffer, id);
break;
case ID_LT:
- write_lattice(wd, (Lattice *)id);
+ write_lattice(wd, (Lattice *)id_buffer, id);
break;
case ID_VF:
- write_vfont(wd, (VFont *)id);
+ write_vfont(wd, (VFont *)id_buffer, id);
break;
case ID_KE:
- write_key(wd, (Key *)id);
+ write_key(wd, (Key *)id_buffer, id);
break;
case ID_WO:
- write_world(wd, (World *)id);
+ write_world(wd, (World *)id_buffer, id);
break;
case ID_TXT:
- write_text(wd, (Text *)id);
+ write_text(wd, (Text *)id_buffer, id);
break;
case ID_SPK:
- write_speaker(wd, (Speaker *)id);
+ write_speaker(wd, (Speaker *)id_buffer, id);
break;
case ID_LP:
- write_probe(wd, (LightProbe *)id);
+ write_probe(wd, (LightProbe *)id_buffer, id);
break;
case ID_SO:
- write_sound(wd, (bSound *)id);
+ write_sound(wd, (bSound *)id_buffer, id);
break;
case ID_GR:
- write_collection(wd, (Collection *)id);
+ write_collection(wd, (Collection *)id_buffer, id);
break;
case ID_AR:
- write_armature(wd, (bArmature *)id);
+ write_armature(wd, (bArmature *)id_buffer, id);
break;
case ID_AC:
- write_action(wd, (bAction *)id);
+ write_action(wd, (bAction *)id_buffer, id);
break;
case ID_OB:
- write_object(wd, (Object *)id);
+ write_object(wd, (Object *)id_buffer, id);
break;
case ID_MA:
- write_material(wd, (Material *)id);
+ write_material(wd, (Material *)id_buffer, id);
break;
case ID_TE:
- write_texture(wd, (Tex *)id);
+ write_texture(wd, (Tex *)id_buffer, id);
break;
case ID_ME:
- write_mesh(wd, (Mesh *)id);
+ write_mesh(wd, (Mesh *)id_buffer, id);
break;
case ID_PA:
- write_particlesettings(wd, (ParticleSettings *)id);
+ write_particlesettings(wd, (ParticleSettings *)id_buffer, id);
break;
case ID_NT:
- write_nodetree(wd, (bNodeTree *)id);
+ write_nodetree(wd, (bNodeTree *)id_buffer, id);
break;
case ID_BR:
- write_brush(wd, (Brush *)id);
+ write_brush(wd, (Brush *)id_buffer, id);
break;
case ID_PAL:
- write_palette(wd, (Palette *)id);
+ write_palette(wd, (Palette *)id_buffer, id);
break;
case ID_PC:
- write_paintcurve(wd, (PaintCurve *)id);
+ write_paintcurve(wd, (PaintCurve *)id_buffer, id);
break;
case ID_GD:
- write_gpencil(wd, (bGPdata *)id);
+ write_gpencil(wd, (bGPdata *)id_buffer, id);
break;
case ID_LS:
- write_linestyle(wd, (FreestyleLineStyle *)id);
+ write_linestyle(wd, (FreestyleLineStyle *)id_buffer, id);
break;
case ID_CF:
- write_cachefile(wd, (CacheFile *)id);
+ write_cachefile(wd, (CacheFile *)id_buffer, id);
break;
case ID_HA:
- write_hair(wd, (Hair *)id);
+ write_hair(wd, (Hair *)id_buffer, id);
break;
case ID_PT:
- write_pointcloud(wd, (PointCloud *)id);
+ write_pointcloud(wd, (PointCloud *)id_buffer, id);
break;
case ID_VO:
- write_volume(wd, (Volume *)id);
+ write_volume(wd, (Volume *)id_buffer, id);
+ break;
+ case ID_SIM:
+ write_simulation(wd, (Simulation *)id);
break;
case ID_LI:
/* Do nothing, handled below - and should never be reached. */
@@ -4138,11 +4335,11 @@ static bool write_file_handle(Main *mainvar,
BKE_lib_override_library_operations_store_end(override_storage, id);
}
- if (wd->use_memfile) {
- /* Very important to do it after every ID write now, otherwise we cannot know whether a
- * specific ID changed or not. */
- mywrite_flush(wd);
- }
+ mywrite_id_end(wd, id);
+ }
+
+ if (id_buffer != id_buffer_static) {
+ MEM_SAFE_FREE(id_buffer);
}
mywrite_flush(wd);
@@ -4277,8 +4474,8 @@ bool BLO_write_file(Main *mainvar,
BLI_split_dir_part(filepath, dir_dst, sizeof(dir_dst));
/* Just in case there is some subtle difference. */
- BLI_cleanup_path(mainvar->name, dir_dst);
- BLI_cleanup_path(mainvar->name, dir_src);
+ BLI_path_normalize(mainvar->name, dir_dst);
+ BLI_path_normalize(mainvar->name, dir_src);
if (G.relbase_valid && (BLI_path_cmp(dir_dst, dir_src) == 0)) {
/* Saved to same path. Nothing to do. */
@@ -4353,4 +4550,98 @@ bool BLO_write_file_mem(Main *mainvar, MemFile *compare, MemFile *current, int w
return (err == 0);
}
+void BLO_write_raw(BlendWriter *writer, int size_in_bytes, const void *data_ptr)
+{
+ writedata(writer->wd, DATA, size_in_bytes, data_ptr);
+}
+
+void BLO_write_struct_by_name(BlendWriter *writer, const char *struct_name, const void *data_ptr)
+{
+ int struct_id = BLO_get_struct_id_by_name(writer, struct_name);
+ BLO_write_struct_by_id(writer, struct_id, data_ptr);
+}
+
+void BLO_write_struct_array_by_name(BlendWriter *writer,
+ const char *struct_name,
+ int array_size,
+ const void *data_ptr)
+{
+ int struct_id = BLO_get_struct_id_by_name(writer, struct_name);
+ BLO_write_struct_array_by_id(writer, struct_id, array_size, data_ptr);
+}
+
+void BLO_write_struct_by_id(BlendWriter *writer, int struct_id, const void *data_ptr)
+{
+ writestruct_nr(writer->wd, DATA, struct_id, 1, data_ptr);
+}
+
+void BLO_write_struct_array_by_id(BlendWriter *writer,
+ int struct_id,
+ int array_size,
+ const void *data_ptr)
+{
+ writestruct_nr(writer->wd, DATA, struct_id, array_size, data_ptr);
+}
+
+void BLO_write_struct_list_by_id(BlendWriter *writer, int struct_id, ListBase *list)
+{
+ writelist_nr(writer->wd, DATA, struct_id, list);
+}
+
+void BLO_write_struct_list_by_name(BlendWriter *writer, const char *struct_name, ListBase *list)
+{
+ BLO_write_struct_list_by_id(writer, BLO_get_struct_id_by_name(writer, struct_name), list);
+}
+
+void blo_write_id_struct(BlendWriter *writer, int struct_id, const void *id_address, const ID *id)
+{
+ writestruct_at_address_nr(writer->wd, GS(id->name), struct_id, 1, id_address, id);
+}
+
+int BLO_get_struct_id_by_name(BlendWriter *writer, const char *struct_name)
+{
+ int struct_id = DNA_struct_find_nr(writer->wd->sdna, struct_name);
+ BLI_assert(struct_id >= 0);
+ return struct_id;
+}
+
+void BLO_write_int32_array(BlendWriter *writer, int size, const int32_t *data_ptr)
+{
+ BLO_write_raw(writer, sizeof(int32_t) * size, data_ptr);
+}
+
+void BLO_write_uint32_array(BlendWriter *writer, int size, const uint32_t *data_ptr)
+{
+ BLO_write_raw(writer, sizeof(uint32_t) * size, data_ptr);
+}
+
+void BLO_write_float_array(BlendWriter *writer, int size, const float *data_ptr)
+{
+ BLO_write_raw(writer, sizeof(float) * size, data_ptr);
+}
+
+void BLO_write_float3_array(BlendWriter *writer, int size, const float *data_ptr)
+{
+ BLO_write_raw(writer, sizeof(float) * 3 * size, data_ptr);
+}
+
+/**
+ * Write a null terminated string.
+ */
+void BLO_write_string(BlendWriter *writer, const char *str)
+{
+ if (str != NULL) {
+ BLO_write_raw(writer, strlen(str) + 1, str);
+ }
+}
+
+/**
+ * Sometimes different data is written depending on whether the file is saved to disk or used for
+ * undo. This function returns true when the current file-writing is done for undo.
+ */
+bool BLO_write_is_undo(BlendWriter *writer)
+{
+ return writer->wd->use_memfile;
+}
+
/** \} */
diff --git a/source/blender/blentranslation/BLT_translation.h b/source/blender/blentranslation/BLT_translation.h
index 74c46b1cf3e..817b99e8b91 100644
--- a/source/blender/blentranslation/BLT_translation.h
+++ b/source/blender/blentranslation/BLT_translation.h
@@ -65,9 +65,9 @@ bool BLT_lang_is_ime_supported(void);
# define IFACE_(msgid) msgid
# define TIP_(msgid) msgid
# define DATA_(msgid) msgid
-# define CTX_IFACE_(context, msgid) msgid
-# define CTX_TIP_(context, msgid) msgid
-# define CTX_DATA_(context, msgid) msgid
+# define CTX_IFACE_(context, msgid) ((void)(0 ? (context) : 0), msgid)
+# define CTX_TIP_(context, msgid) ((void)(0 ? (context) : 0), msgid)
+# define CTX_DATA_(context, msgid) ((void)(0 ? (context) : 0), msgid)
#endif
/* Helper macro, when we want to define a same msgid for multiple msgctxt...
@@ -122,6 +122,7 @@ bool BLT_lang_is_ime_supported(void);
#define BLT_I18NCONTEXT_ID_IMAGE "Image"
/*#define BLT_I18NCONTEXT_ID_IPO "Ipo"*/ /* Deprecated */
#define BLT_I18NCONTEXT_ID_SHAPEKEY "Key"
+#define BLT_I18NCONTEXT_ID_SIMULATION "Simulation"
#define BLT_I18NCONTEXT_ID_LIGHT "Light"
#define BLT_I18NCONTEXT_ID_LIBRARY "Library"
#define BLT_I18NCONTEXT_ID_LATTICE "Lattice"
@@ -202,6 +203,7 @@ typedef struct {
BLT_I18NCONTEXTS_ITEM(BLT_I18NCONTEXT_ID_SCENE, "id_scene"), \
BLT_I18NCONTEXTS_ITEM(BLT_I18NCONTEXT_ID_SCREEN, "id_screen"), \
BLT_I18NCONTEXTS_ITEM(BLT_I18NCONTEXT_ID_SEQUENCE, "id_sequence"), \
+ BLT_I18NCONTEXTS_ITEM(BLT_I18NCONTEXT_ID_SIMULATION, "id_simulation"), \
BLT_I18NCONTEXTS_ITEM(BLT_I18NCONTEXT_ID_SPEAKER, "id_speaker"), \
BLT_I18NCONTEXTS_ITEM(BLT_I18NCONTEXT_ID_SOUND, "id_sound"), \
BLT_I18NCONTEXTS_ITEM(BLT_I18NCONTEXT_ID_TEXTURE, "id_texture"), \
diff --git a/source/blender/blentranslation/intern/blt_lang.c b/source/blender/blentranslation/intern/blt_lang.c
index 112c615fac2..bcbffe56636 100644
--- a/source/blender/blentranslation/intern/blt_lang.c
+++ b/source/blender/blentranslation/intern/blt_lang.c
@@ -253,7 +253,8 @@ void BLT_lang_free(void)
}
#ifdef WITH_INTERNATIONAL
-# define ULANGUAGE ((U.language >= 0 && U.language < num_locales) ? U.language : 0)
+# define ULANGUAGE \
+ ((U.language >= ULANGUAGE_AUTO && U.language < num_locales) ? U.language : ULANGUAGE_ENGLISH)
# define LOCALE(_id) (locales ? locales[(_id)] : "")
#endif
@@ -264,10 +265,6 @@ void BLT_lang_set(const char *str)
const char *short_locale = str ? str : LOCALE(ulang);
const char *short_locale_utf8 = NULL;
- if ((U.transopts & USER_DOTRANSLATE) == 0) {
- return;
- }
-
/* We want to avoid locales like '.UTF-8'! */
if (short_locale[0]) {
/* Hurrey! encoding needs to be placed *before* variant! */
@@ -388,13 +385,7 @@ static void blt_lang_check_ime_supported(void)
{
#ifdef WITH_INPUT_IME
const char *uilng = BLT_lang_get();
- if (U.transopts & USER_DOTRANSLATE) {
- ime_is_lang_supported = STREQ(uilng, "zh_CN") || STREQ(uilng, "zh_TW") ||
- STREQ(uilng, "ja_JP");
- }
- else {
- ime_is_lang_supported = false;
- }
+ ime_is_lang_supported = STREQ(uilng, "zh_CN") || STREQ(uilng, "zh_TW") || STREQ(uilng, "ja_JP");
#else
ime_is_lang_supported = false;
#endif
diff --git a/source/blender/blentranslation/intern/blt_translation.c b/source/blender/blentranslation/intern/blt_translation.c
index 64e14522aca..0ca068d4263 100644
--- a/source/blender/blentranslation/intern/blt_translation.c
+++ b/source/blender/blentranslation/intern/blt_translation.c
@@ -81,7 +81,7 @@ const char *BLT_pgettext(const char *msgctxt, const char *msgid)
bool BLT_translate(void)
{
#ifdef WITH_INTERNATIONAL
- return BLI_thread_is_main() && (U.transopts & USER_DOTRANSLATE);
+ return BLI_thread_is_main() && (U.language != ULANGUAGE_ENGLISH);
#else
return false;
#endif
diff --git a/source/blender/bmesh/CMakeLists.txt b/source/blender/bmesh/CMakeLists.txt
index 35c33837d64..7a389c63abd 100644
--- a/source/blender/bmesh/CMakeLists.txt
+++ b/source/blender/bmesh/CMakeLists.txt
@@ -56,7 +56,7 @@ set(SRC
operators/bmo_hull.c
operators/bmo_inset.c
operators/bmo_join_triangles.c
- operators/bmo_mesh_conv.c
+ operators/bmo_mesh_convert.c
operators/bmo_mirror.c
operators/bmo_normals.c
operators/bmo_offset_edgeloops.c
@@ -97,8 +97,8 @@ set(SRC
intern/bmesh_marking.h
intern/bmesh_mesh.c
intern/bmesh_mesh.h
- intern/bmesh_mesh_conv.c
- intern/bmesh_mesh_conv.h
+ intern/bmesh_mesh_convert.c
+ intern/bmesh_mesh_convert.h
intern/bmesh_mesh_duplicate.c
intern/bmesh_mesh_duplicate.h
intern/bmesh_mesh_validate.c
diff --git a/source/blender/bmesh/bmesh.h b/source/blender/bmesh/bmesh.h
index 7d2100c0f65..c0791e6fdbc 100644
--- a/source/blender/bmesh/bmesh.h
+++ b/source/blender/bmesh/bmesh.h
@@ -188,10 +188,6 @@
* - Use two different iterator types for BMO map/buffer types.
*/
-#ifdef __cplusplus
-extern "C" {
-#endif
-
#include "DNA_customdata_types.h" /* BMesh struct in bmesh_class.h uses */
#include "DNA_listBase.h" /* selection history uses */
@@ -199,6 +195,10 @@ extern "C" {
#include <stdio.h>
#include <stdlib.h>
+#ifdef __cplusplus
+extern "C" {
+#endif
+
#include "bmesh_class.h"
/* include the rest of the API */
@@ -215,7 +215,7 @@ extern "C" {
#include "intern/bmesh_log.h"
#include "intern/bmesh_marking.h"
#include "intern/bmesh_mesh.h"
-#include "intern/bmesh_mesh_conv.h"
+#include "intern/bmesh_mesh_convert.h"
#include "intern/bmesh_mesh_duplicate.h"
#include "intern/bmesh_mesh_validate.h"
#include "intern/bmesh_mods.h"
diff --git a/source/blender/bmesh/intern/bmesh_construct.c b/source/blender/bmesh/intern/bmesh_construct.c
index 592d8124b23..0d79d60e5c1 100644
--- a/source/blender/bmesh/intern/bmesh_construct.c
+++ b/source/blender/bmesh/intern/bmesh_construct.c
@@ -717,6 +717,10 @@ BMesh *BM_mesh_copy(BMesh *bm_old)
MEM_freeN(vtable);
MEM_freeN(ftable);
+ /* Copy various settings. */
+ bm_new->shapenr = bm_old->shapenr;
+ bm_new->selectmode = bm_old->selectmode;
+
return bm_new;
}
diff --git a/source/blender/bmesh/intern/bmesh_edgeloop.h b/source/blender/bmesh/intern/bmesh_edgeloop.h
index 7701c680ae9..4c76ea4f9cf 100644
--- a/source/blender/bmesh/intern/bmesh_edgeloop.h
+++ b/source/blender/bmesh/intern/bmesh_edgeloop.h
@@ -78,7 +78,7 @@ bool BM_edgeloop_overlap_check(struct BMEdgeLoopStore *el_store_a,
#define BM_EDGELINK_NEXT(el_store, elink) \
(elink)->next ? \
- elink->next : \
+ (elink)->next : \
(BM_edgeloop_is_closed(el_store) ? BM_edgeloop_verts_get(el_store)->first : NULL)
#define BM_EDGELOOP_NEXT(el_store) \
diff --git a/source/blender/bmesh/intern/bmesh_marking.c b/source/blender/bmesh/intern/bmesh_marking.c
index d33f4e0a1d6..177599656b6 100644
--- a/source/blender/bmesh/intern/bmesh_marking.c
+++ b/source/blender/bmesh/intern/bmesh_marking.c
@@ -1021,7 +1021,7 @@ void BM_select_history_validate(BMesh *bm)
bool BM_select_history_active_get(BMesh *bm, BMEditSelection *ese)
{
BMEditSelection *ese_last = bm->selected.last;
- BMFace *efa = BM_mesh_active_face_get(bm, false, false);
+ BMFace *efa = BM_mesh_active_face_get(bm, false, true);
ese->next = ese->prev = NULL;
@@ -1083,12 +1083,12 @@ void BM_select_history_merge_from_targetmap(
{
#ifdef DEBUG
- for (BMEditSelection *ese = bm->selected.first; ese; ese = ese->next) {
+ LISTBASE_FOREACH (BMEditSelection *, ese, &bm->selected) {
BLI_assert(BM_ELEM_API_FLAG_TEST(ese->ele, _FLAG_OVERLAP) == 0);
}
#endif
- for (BMEditSelection *ese = bm->selected.first; ese; ese = ese->next) {
+ LISTBASE_FOREACH (BMEditSelection *, ese, &bm->selected) {
BM_ELEM_API_FLAG_ENABLE(ese->ele, _FLAG_OVERLAP);
/* Only loop when (use_chain == true). */
diff --git a/source/blender/bmesh/intern/bmesh_mesh.c b/source/blender/bmesh/intern/bmesh_mesh.c
index ff618142bfa..854421d32d4 100644
--- a/source/blender/bmesh/intern/bmesh_mesh.c
+++ b/source/blender/bmesh/intern/bmesh_mesh.c
@@ -676,7 +676,7 @@ static void bm_mesh_loops_calc_normals(BMesh *bm,
const float (*fnos)[3],
float (*r_lnos)[3],
MLoopNorSpaceArray *r_lnors_spacearr,
- short (*clnors_data)[2],
+ const short (*clnors_data)[2],
const int cd_loop_clnors_offset,
const bool do_rebuild)
{
@@ -786,8 +786,9 @@ static void bm_mesh_loops_calc_normals(BMesh *bm,
BKE_lnor_space_add_loop(r_lnors_spacearr, lnor_space, l_curr_index, l_curr, true);
if (has_clnors) {
- short(*clnor)[2] = clnors_data ? &clnors_data[l_curr_index] :
- BM_ELEM_CD_GET_VOID_P(l_curr, cd_loop_clnors_offset);
+ const short(*clnor)[2] = clnors_data ? &clnors_data[l_curr_index] :
+ (const void *)BM_ELEM_CD_GET_VOID_P(
+ l_curr, cd_loop_clnors_offset);
BKE_lnor_space_custom_data_to_normal(lnor_space, *clnor, r_lnos[l_curr_index]);
}
}
@@ -820,7 +821,7 @@ static void bm_mesh_loops_calc_normals(BMesh *bm,
/* We validate clnors data on the fly - cheapest way to do! */
int clnors_avg[2] = {0, 0};
- short(*clnor_ref)[2] = NULL;
+ const short(*clnor_ref)[2] = NULL;
int clnors_nbr = 0;
bool clnors_invalid = false;
@@ -886,9 +887,9 @@ static void bm_mesh_loops_calc_normals(BMesh *bm,
if (has_clnors) {
/* Accumulate all clnors, if they are not all equal we have to fix that! */
- short(*clnor)[2] = clnors_data ?
- &clnors_data[lfan_pivot_index] :
- BM_ELEM_CD_GET_VOID_P(lfan_pivot, cd_loop_clnors_offset);
+ const short(*clnor)[2] = clnors_data ? &clnors_data[lfan_pivot_index] :
+ (const void *)BM_ELEM_CD_GET_VOID_P(
+ lfan_pivot, cd_loop_clnors_offset);
if (clnors_nbr) {
clnors_invalid |= ((*clnor_ref)[0] != (*clnor)[0] ||
(*clnor_ref)[1] != (*clnor)[1]);
@@ -1049,7 +1050,7 @@ void BM_mesh_loop_normals_update(BMesh *bm,
const float split_angle,
float (*r_lnos)[3],
MLoopNorSpaceArray *r_lnors_spacearr,
- short (*clnors_data)[2],
+ const short (*clnors_data)[2],
const int cd_loop_clnors_offset)
{
const bool has_clnors = clnors_data || (cd_loop_clnors_offset != -1);
@@ -1627,20 +1628,6 @@ void BM_loop_normal_editdata_array_free(BMLoopNorEditDataArray *lnors_ed_arr)
MEM_freeN(lnors_ed_arr);
}
-int BM_total_loop_select(BMesh *bm)
-{
- int r_sel = 0;
- BMVert *v;
- BMIter viter;
-
- BM_ITER_MESH (v, &viter, bm, BM_VERTS_OF_MESH) {
- if (BM_elem_flag_test(v, BM_ELEM_SELECT)) {
- r_sel += BM_vert_face_count(v);
- }
- }
- return r_sel;
-}
-
/**
* \brief BMesh Begin Edit
*
@@ -2593,7 +2580,7 @@ void BM_mesh_rebuild(BMesh *bm,
}
}
- for (BMEditSelection *ese = bm->selected.first; ese; ese = ese->next) {
+ LISTBASE_FOREACH (BMEditSelection *, ese, &bm->selected) {
switch (ese->htype) {
case BM_VERT:
if (remap & BM_VERT) {
diff --git a/source/blender/bmesh/intern/bmesh_mesh.h b/source/blender/bmesh/intern/bmesh_mesh.h
index ea0fea1f603..fa542ba5f12 100644
--- a/source/blender/bmesh/intern/bmesh_mesh.h
+++ b/source/blender/bmesh/intern/bmesh_mesh.h
@@ -72,7 +72,6 @@ void BM_lnorspace_err(BMesh *bm);
struct BMLoopNorEditDataArray *BM_loop_normal_editdata_array_init(BMesh *bm,
const bool do_all_loops_of_vert);
void BM_loop_normal_editdata_array_free(struct BMLoopNorEditDataArray *lnors_ed_arr);
-int BM_total_loop_select(BMesh *bm);
void BM_edges_sharp_from_angle_set(BMesh *bm, const float split_angle);
diff --git a/source/blender/bmesh/intern/bmesh_mesh_conv.c b/source/blender/bmesh/intern/bmesh_mesh_convert.c
index de32d7881b0..b8508f7e12c 100644
--- a/source/blender/bmesh/intern/bmesh_mesh_conv.c
+++ b/source/blender/bmesh/intern/bmesh_mesh_convert.c
@@ -893,6 +893,10 @@ void BM_mesh_bm_to_me(Main *bmain, BMesh *bm, Mesh *me, const struct BMeshToMesh
j = bm_to_mesh_shape_layer_index_from_kb(bm, currkey);
cd_shape_offset = CustomData_get_n_offset(&bm->vdata, CD_SHAPEKEY, j);
+ if (cd_shape_offset < 0) {
+ /* The target Mesh has more shapekeys than the BMesh. */
+ continue;
+ }
fp = newkey = MEM_callocN(me->key->elemsize * bm->totvert, "currkey->data");
oldkey = currkey->data;
diff --git a/source/blender/bmesh/intern/bmesh_mesh_conv.h b/source/blender/bmesh/intern/bmesh_mesh_convert.h
index 1ad43558c60..1ad43558c60 100644
--- a/source/blender/bmesh/intern/bmesh_mesh_conv.h
+++ b/source/blender/bmesh/intern/bmesh_mesh_convert.h
diff --git a/source/blender/bmesh/intern/bmesh_opdefines.c b/source/blender/bmesh/intern/bmesh_opdefines.c
index 4fa7bf64834..04cdc0020d9 100644
--- a/source/blender/bmesh/intern/bmesh_opdefines.c
+++ b/source/blender/bmesh/intern/bmesh_opdefines.c
@@ -122,6 +122,11 @@ static BMO_FlagSet bmo_enum_falloff_type[] = {
{0, NULL},
};
+/* Quiet 'enum-conversion' warning. */
+#define BM_FACE ((int)BM_FACE)
+#define BM_EDGE ((int)BM_EDGE)
+#define BM_VERT ((int)BM_VERT)
+
/*
* Vertex Smooth.
*
@@ -320,6 +325,7 @@ static BMOpDefine bmo_mirror_def = {
{"axis", BMO_OP_SLOT_INT, {(int)BMO_OP_SLOT_SUBTYPE_INT_ENUM}, bmo_enum_axis_xyz}, /* the axis to use. */
{"mirror_u", BMO_OP_SLOT_BOOL}, /* mirror UVs across the u axis */
{"mirror_v", BMO_OP_SLOT_BOOL}, /* mirror UVs across the v axis */
+ {"mirror_udim", BMO_OP_SLOT_BOOL}, /* mirror UVs in each tile */
{{'\0'}},
},
/* slots_out */
@@ -1046,6 +1052,7 @@ static BMOpDefine bmo_extrude_face_region_def = {
{"use_keep_orig", BMO_OP_SLOT_BOOL}, /* keep original geometry (requires ``geom`` to include edges). */
{"use_normal_flip", BMO_OP_SLOT_BOOL}, /* Create faces with reversed direction. */
{"use_normal_from_adjacent", BMO_OP_SLOT_BOOL}, /* Use winding from surrounding faces instead of this region. */
+ {"use_dissolve_ortho_edges", BMO_OP_SLOT_BOOL}, /* Dissolve edges whose faces form a flat surface. */
{"use_select_history", BMO_OP_SLOT_BOOL}, /* pass to duplicate */
{{'\0'}},
},
@@ -2072,6 +2079,10 @@ static BMOpDefine bmo_symmetrize_def = {
/* clang-format on */
+#undef BM_FACE
+#undef BM_EDGE
+#undef BM_VERT
+
const BMOpDefine *bmo_opdefines[] = {
&bmo_average_vert_facedata_def,
&bmo_beautify_fill_def,
diff --git a/source/blender/bmesh/intern/bmesh_operator_api.h b/source/blender/bmesh/intern/bmesh_operator_api.h
index dbd2bf076c6..5af812d1b1d 100644
--- a/source/blender/bmesh/intern/bmesh_operator_api.h
+++ b/source/blender/bmesh/intern/bmesh_operator_api.h
@@ -21,14 +21,14 @@
* \ingroup bmesh
*/
-#ifdef __cplusplus
-extern "C" {
-#endif
-
#include "BLI_ghash.h"
#include <stdarg.h>
+#ifdef __cplusplus
+extern "C" {
+#endif
+
/**
* operators represent logical, executable mesh modules. all topological
* operations involving a bmesh has to go through them.
diff --git a/source/blender/bmesh/intern/bmesh_operators.c b/source/blender/bmesh/intern/bmesh_operators.c
index d3c8499477b..6454079a5dc 100644
--- a/source/blender/bmesh/intern/bmesh_operators.c
+++ b/source/blender/bmesh/intern/bmesh_operators.c
@@ -138,6 +138,8 @@ static void bmo_op_slots_init(const BMOSlotType *slot_types, BMOpSlot *slot_args
BMO_OP_SLOT_SUBTYPE_INT_ENUM,
BMO_OP_SLOT_SUBTYPE_INT_FLAG)) {
slot->data.enum_data.flags = slot_types[i].enum_flags;
+ /* Set the first value of the enum as the default value. */
+ slot->data.i = slot->data.enum_data.flags[0].value;
}
default:
break;
diff --git a/source/blender/bmesh/intern/bmesh_polygon.c b/source/blender/bmesh/intern/bmesh_polygon.c
index 9ab5106cec2..a40c293f1aa 100644
--- a/source/blender/bmesh/intern/bmesh_polygon.c
+++ b/source/blender/bmesh/intern/bmesh_polygon.c
@@ -596,6 +596,31 @@ void BM_face_calc_center_bounds(const BMFace *f, float r_cent[3])
}
/**
+ * computes center of face in 3d. uses center of bounding box.
+ */
+void BM_face_calc_center_bounds_vcos(const BMesh *bm,
+ const BMFace *f,
+ float r_cent[3],
+ float const (*vertexCos)[3])
+{
+ /* must have valid index data */
+ BLI_assert((bm->elem_index_dirty & BM_VERT) == 0);
+ (void)bm;
+
+ const BMLoop *l_iter, *l_first;
+ float min[3], max[3];
+
+ INIT_MINMAX(min, max);
+
+ l_iter = l_first = BM_FACE_FIRST_LOOP(f);
+ do {
+ minmax_v3v3_v3(min, max, vertexCos[BM_elem_index_get(l_iter->v)]);
+ } while ((l_iter = l_iter->next) != l_first);
+
+ mid_v3_v3v3(r_cent, min, max);
+}
+
+/**
* computes the center of a face, using the mean average
*/
void BM_face_calc_center_median(const BMFace *f, float r_cent[3])
diff --git a/source/blender/bmesh/intern/bmesh_polygon.h b/source/blender/bmesh/intern/bmesh_polygon.h
index 2ae32777a7d..1611bc0b893 100644
--- a/source/blender/bmesh/intern/bmesh_polygon.h
+++ b/source/blender/bmesh/intern/bmesh_polygon.h
@@ -60,10 +60,14 @@ void BM_face_calc_tangent_edge_diagonal(const BMFace *f, float r_plane[3]) ATTR_
void BM_face_calc_tangent_vert_diagonal(const BMFace *f, float r_plane[3]) ATTR_NONNULL();
void BM_face_calc_tangent_auto(const BMFace *f, float r_plane[3]) ATTR_NONNULL();
void BM_face_calc_center_bounds(const BMFace *f, float center[3]) ATTR_NONNULL();
-void BM_face_calc_center_median(const BMFace *f, float center[3]) ATTR_NONNULL();
+void BM_face_calc_center_bounds_vcos(const BMesh *bm,
+ const BMFace *f,
+ float r_center[3],
+ float const (*vertexCos)[3]) ATTR_NONNULL();
+void BM_face_calc_center_median(const BMFace *f, float r_center[3]) ATTR_NONNULL();
void BM_face_calc_center_median_vcos(const BMesh *bm,
const BMFace *f,
- float r_cent[3],
+ float r_center[3],
float const (*vertexCos)[3]) ATTR_NONNULL();
void BM_face_calc_center_median_weighted(const BMFace *f, float center[3]) ATTR_NONNULL();
diff --git a/source/blender/bmesh/intern/bmesh_query.c b/source/blender/bmesh/intern/bmesh_query.c
index e3b6e243906..e000b253000 100644
--- a/source/blender/bmesh/intern/bmesh_query.c
+++ b/source/blender/bmesh/intern/bmesh_query.c
@@ -1568,6 +1568,41 @@ float BM_loop_calc_face_normal_safe_ex(const BMLoop *l, const float epsilon_sq,
}
/**
+ * A version of BM_loop_calc_face_normal_safe_ex which takes vertex coordinates.
+ */
+float BM_loop_calc_face_normal_safe_vcos_ex(const BMLoop *l,
+ const float normal_fallback[3],
+ float const (*vertexCos)[3],
+ const float epsilon_sq,
+ float r_normal[3])
+{
+ const int i_prev = BM_elem_index_get(l->prev->v);
+ const int i_next = BM_elem_index_get(l->next->v);
+ const int i = BM_elem_index_get(l->v);
+
+ float v1[3], v2[3], v_tmp[3];
+ sub_v3_v3v3(v1, vertexCos[i_prev], vertexCos[i]);
+ sub_v3_v3v3(v2, vertexCos[i_next], vertexCos[i]);
+
+ const float fac = ((v2[0] == 0.0f) ?
+ ((v2[1] == 0.0f) ? ((v2[2] == 0.0f) ? 0.0f : v1[2] / v2[2]) :
+ v1[1] / v2[1]) :
+ v1[0] / v2[0]);
+
+ mul_v3_v3fl(v_tmp, v2, fac);
+ sub_v3_v3(v_tmp, v1);
+ if (fac != 0.0f && !is_zero_v3(v1) && len_squared_v3(v_tmp) > epsilon_sq) {
+ /* Not co-linear, we can compute cross-product and normalize it into normal. */
+ cross_v3_v3v3(r_normal, v1, v2);
+ return normalize_v3(r_normal);
+ }
+ else {
+ copy_v3_v3(r_normal, normal_fallback);
+ return 0.0f;
+ }
+}
+
+/**
* #BM_loop_calc_face_normal_safe_ex with pre-defined sane epsilon.
*
* Since this doesn't scale based on triangle size, fixed value works well.
@@ -1577,6 +1612,15 @@ float BM_loop_calc_face_normal_safe(const BMLoop *l, float r_normal[3])
return BM_loop_calc_face_normal_safe_ex(l, 1e-5f, r_normal);
}
+float BM_loop_calc_face_normal_safe_vcos(const BMLoop *l,
+ const float normal_fallback[3],
+ float const (*vertexCos)[3],
+ float r_normal[3])
+
+{
+ return BM_loop_calc_face_normal_safe_vcos_ex(l, normal_fallback, vertexCos, 1e-5f, r_normal);
+}
+
/**
* \brief BM_loop_calc_face_normal
*
@@ -2431,6 +2475,22 @@ bool BM_edge_is_all_face_flag_test(const BMEdge *e, const char hflag, const bool
return true;
}
+bool BM_edge_is_any_face_flag_test(const BMEdge *e, const char hflag)
+{
+ if (e->l) {
+ BMLoop *l_iter, *l_first;
+
+ l_iter = l_first = e->l;
+ do {
+ if (BM_elem_flag_test(l_iter->f, hflag)) {
+ return true;
+ }
+ } while ((l_iter = l_iter->radial_next) != l_first);
+ }
+
+ return false;
+}
+
/* convenience functions for checking flags */
bool BM_edge_is_any_vert_flag_test(const BMEdge *e, const char hflag)
{
diff --git a/source/blender/bmesh/intern/bmesh_query.h b/source/blender/bmesh/intern/bmesh_query.h
index fb646b11076..7e07059d4d8 100644
--- a/source/blender/bmesh/intern/bmesh_query.h
+++ b/source/blender/bmesh/intern/bmesh_query.h
@@ -142,6 +142,16 @@ float BM_loop_calc_face_normal(const BMLoop *l, float r_normal[3]) ATTR_NONNULL(
float BM_loop_calc_face_normal_safe(const BMLoop *l, float r_normal[3]) ATTR_NONNULL();
float BM_loop_calc_face_normal_safe_ex(const BMLoop *l, const float epsilon, float r_normal[3])
ATTR_NONNULL();
+float BM_loop_calc_face_normal_safe_vcos_ex(const BMLoop *l,
+ const float normal_fallback[3],
+ float const (*vertexCos)[3],
+ const float epsilon_sq,
+ float r_normal[3]) ATTR_NONNULL();
+float BM_loop_calc_face_normal_safe_vcos(const BMLoop *l,
+ const float normal_fallback[3],
+ float const (*vertexCos)[3],
+ float r_normal[3]) ATTR_NONNULL();
+
void BM_loop_calc_face_direction(const BMLoop *l, float r_normal[3]);
void BM_loop_calc_face_tangent(const BMLoop *l, float r_tangent[3]);
@@ -226,6 +236,8 @@ bool BM_edge_is_all_face_flag_test(const BMEdge *e,
bool BM_edge_is_any_vert_flag_test(const BMEdge *e, const char hflag) ATTR_WARN_UNUSED_RESULT
ATTR_NONNULL();
+bool BM_edge_is_any_face_flag_test(const BMEdge *e, const char hflag) ATTR_WARN_UNUSED_RESULT
+ ATTR_NONNULL();
bool BM_face_is_any_vert_flag_test(const BMFace *f, const char hflag) ATTR_WARN_UNUSED_RESULT
ATTR_NONNULL();
bool BM_face_is_any_edge_flag_test(const BMFace *f, const char hflag) ATTR_WARN_UNUSED_RESULT
diff --git a/source/blender/bmesh/operators/bmo_extrude.c b/source/blender/bmesh/operators/bmo_extrude.c
index 7a7f4a14db3..3c63f4a60d6 100644
--- a/source/blender/bmesh/operators/bmo_extrude.c
+++ b/source/blender/bmesh/operators/bmo_extrude.c
@@ -39,6 +39,7 @@ enum {
EXT_INPUT = 1,
EXT_KEEP = 2,
EXT_DEL = 4,
+ EXT_TAG = 8,
};
#define VERT_MARK 1
@@ -335,6 +336,8 @@ void bmo_extrude_face_region_exec(BMesh *bm, BMOperator *op)
const bool use_normal_flip = BMO_slot_bool_get(op->slots_in, "use_normal_flip");
const bool use_normal_from_adjacent = BMO_slot_bool_get(op->slots_in,
"use_normal_from_adjacent");
+ const bool use_dissolve_ortho_edges = BMO_slot_bool_get(op->slots_in,
+ "use_dissolve_ortho_edges");
/* initialize our sub-operators */
BMO_op_initf(bm,
@@ -442,6 +445,24 @@ void bmo_extrude_face_region_exec(BMesh *bm, BMOperator *op)
}
}
+ BMVert **dissolve_verts = NULL;
+ int dissolve_verts_len = 0;
+ float average_normal[3];
+ if (use_dissolve_ortho_edges) {
+ /* Calc average normal. */
+ zero_v3(average_normal);
+ BMO_ITER (f, &siter, dupeop.slots_out, "geom.out", BM_FACE) {
+ add_v3_v3(average_normal, f->no);
+ }
+ if (normalize_v3(average_normal) == 0.0f) {
+ average_normal[2] = 1.0f;
+ }
+
+ /* Allocate array to store possible vertices that will be dissolved. */
+ int boundary_verts_len = BMO_slot_map_count(dupeop.slots_out, "boundary_map.out");
+ dissolve_verts = MEM_mallocN((size_t)boundary_verts_len * sizeof(*dissolve_verts), __func__);
+ }
+
BMO_slot_copy(&dupeop, slots_out, "geom.out", op, slots_out, "geom.out");
slot_edges_exclude = BMO_slot_get(op->slots_in, "edges_exclude");
@@ -483,6 +504,16 @@ void bmo_extrude_face_region_exec(BMesh *bm, BMOperator *op)
continue;
}
+ BMFace *join_face = NULL;
+ if (use_dissolve_ortho_edges) {
+ if (BM_edge_is_boundary(e)) {
+ join_face = e->l->f;
+ if (fabs(dot_v3v3(average_normal, join_face->no)) > 0.0001f) {
+ join_face = NULL;
+ }
+ }
+ }
+
bool edge_normal_flip;
if (use_normal_from_adjacent == false) {
/* Orient loop to give same normal as a loop of 'e_new'
@@ -541,7 +572,22 @@ void bmo_extrude_face_region_exec(BMesh *bm, BMOperator *op)
f = BM_face_create_verts(bm, f_verts, 4, NULL, BM_CREATE_NOP, true);
#endif
- bm_extrude_copy_face_loop_attributes(bm, f);
+ if (join_face) {
+ BMVert *v1 = e->v1;
+ BMVert *v2 = e->v2;
+ if (!BMO_elem_flag_test(bm, v1, EXT_TAG)) {
+ BMO_elem_flag_enable(bm, v1, EXT_TAG);
+ dissolve_verts[dissolve_verts_len++] = v1;
+ }
+ if (!BMO_elem_flag_test(bm, v2, EXT_TAG)) {
+ BMO_elem_flag_enable(bm, v2, EXT_TAG);
+ dissolve_verts[dissolve_verts_len++] = v2;
+ }
+ bmesh_kernel_join_face_kill_edge(bm, join_face, f, e);
+ }
+ else {
+ bm_extrude_copy_face_loop_attributes(bm, f);
+ }
}
/* link isolated vert */
@@ -559,6 +605,23 @@ void bmo_extrude_face_region_exec(BMesh *bm, BMOperator *op)
BM_edge_create(bm, v, v2, NULL, BM_CREATE_NO_DOUBLE);
}
+ if (dissolve_verts) {
+ BMVert **v_iter = &dissolve_verts[0];
+ for (int i = dissolve_verts_len; i--; v_iter++) {
+ v = *v_iter;
+ e = v->e;
+ BMEdge *e_other = BM_DISK_EDGE_NEXT(e, v);
+ if ((e_other == e) || (BM_DISK_EDGE_NEXT(e_other, v) == e)) {
+ /* Lose edge or BMVert is edge pair. */
+ BM_edge_collapse(bm, e, v, true, false);
+ }
+ else {
+ BLI_assert(!BM_vert_is_edge_pair(v));
+ }
+ }
+ MEM_freeN(dissolve_verts);
+ }
+
/* cleanup */
if (delorig) {
BMO_op_finish(bm, &delop);
diff --git a/source/blender/bmesh/operators/bmo_fill_grid.c b/source/blender/bmesh/operators/bmo_fill_grid.c
index adc612cfb54..6986655c6de 100644
--- a/source/blender/bmesh/operators/bmo_fill_grid.c
+++ b/source/blender/bmesh/operators/bmo_fill_grid.c
@@ -616,7 +616,14 @@ void bmo_grid_fill_exec(BMesh *bm, BMOperator *op)
count = BM_mesh_edgeloops_find(bm, &eloops, bm_edge_test_cb, (void *)bm);
if (count != 2) {
- BMO_error_raise(bm, op, BMERR_INVALID_SELECTION, "Select two edge loops");
+ /* Note that this error message has been adjusted to make sense when called
+ * from the operator 'MESH_OT_fill_grid' which has a 'prepare' pass which can
+ * extract two 'rail' loops from a single edge loop, see T72075. */
+ BMO_error_raise(bm,
+ op,
+ BMERR_INVALID_SELECTION,
+ "Select two edge loops "
+ "or a single closed edge loop from which two edge loops can be calculated");
goto cleanup;
}
diff --git a/source/blender/bmesh/operators/bmo_mesh_conv.c b/source/blender/bmesh/operators/bmo_mesh_convert.c
index e480db64f9d..e480db64f9d 100644
--- a/source/blender/bmesh/operators/bmo_mesh_conv.c
+++ b/source/blender/bmesh/operators/bmo_mesh_convert.c
diff --git a/source/blender/bmesh/operators/bmo_mirror.c b/source/blender/bmesh/operators/bmo_mirror.c
index 36297b3f816..b5b56f4432d 100644
--- a/source/blender/bmesh/operators/bmo_mirror.c
+++ b/source/blender/bmesh/operators/bmo_mirror.c
@@ -48,6 +48,7 @@ void bmo_mirror_exec(BMesh *bm, BMOperator *op)
int axis = BMO_slot_int_get(op->slots_in, "axis");
bool mirror_u = BMO_slot_bool_get(op->slots_in, "mirror_u");
bool mirror_v = BMO_slot_bool_get(op->slots_in, "mirror_v");
+ bool mirror_udim = BMO_slot_bool_get(op->slots_in, "mirror_udim");
BMOpSlot *slot_targetmap;
ototvert = bm->totvert;
@@ -94,10 +95,22 @@ void bmo_mirror_exec(BMesh *bm, BMOperator *op)
for (i = 0; i < totlayer; i++) {
luv = CustomData_bmesh_get_n(&bm->ldata, l->head.data, CD_MLOOPUV, i);
if (mirror_u) {
- luv->uv[0] = 1.0f - luv->uv[0];
+ float uv_u = luv->uv[0];
+ if (mirror_udim) {
+ luv->uv[0] = ceilf(uv_u) - fmodf(uv_u, 1.0f);
+ }
+ else {
+ luv->uv[0] = 1.0f - uv_u;
+ }
}
if (mirror_v) {
- luv->uv[1] = 1.0f - luv->uv[1];
+ float uv_v = luv->uv[1];
+ if (mirror_udim) {
+ luv->uv[1] = ceilf(uv_v) - fmodf(uv_v, 1.0f);
+ }
+ else {
+ luv->uv[1] = 1.0f - uv_v;
+ }
}
}
}
diff --git a/source/blender/bmesh/operators/bmo_primitive.c b/source/blender/bmesh/operators/bmo_primitive.c
index 64687ac154c..d661859c8e3 100644
--- a/source/blender/bmesh/operators/bmo_primitive.c
+++ b/source/blender/bmesh/operators/bmo_primitive.c
@@ -1393,16 +1393,15 @@ void bmo_create_cone_exec(BMesh *bm, BMOperator *op)
BMVert *v1, *v2, *lastv1 = NULL, *lastv2 = NULL, *cent1, *cent2, *firstv1, *firstv2;
BMFace *f;
float vec[3], mat[4][4], phi, phid;
- float dia1 = BMO_slot_float_get(op->slots_in, "diameter1");
- float dia2 = BMO_slot_float_get(op->slots_in, "diameter2");
- float depth = BMO_slot_float_get(op->slots_in, "depth");
+ const float dia1 = BMO_slot_float_get(op->slots_in, "diameter1");
+ const float dia2 = BMO_slot_float_get(op->slots_in, "diameter2");
+ const float depth_half = 0.5f * BMO_slot_float_get(op->slots_in, "depth");
int segs = BMO_slot_int_get(op->slots_in, "segments");
const bool cap_ends = BMO_slot_bool_get(op->slots_in, "cap_ends");
const bool cap_tris = BMO_slot_bool_get(op->slots_in, "cap_tris");
const int cd_loop_uv_offset = CustomData_get_offset(&bm->ldata, CD_MLOOPUV);
const bool calc_uvs = (cd_loop_uv_offset != -1) && BMO_slot_bool_get(op->slots_in, "calc_uvs");
- int a;
if (!segs) {
return;
@@ -1413,16 +1412,15 @@ void bmo_create_cone_exec(BMesh *bm, BMOperator *op)
phid = 2.0f * (float)M_PI / segs;
phi = 0;
- depth *= 0.5f;
if (cap_ends) {
vec[0] = vec[1] = 0.0f;
- vec[2] = -depth;
+ vec[2] = -depth_half;
mul_m4_v3(mat, vec);
cent1 = BM_vert_create(bm, vec, NULL, BM_CREATE_NOP);
vec[0] = vec[1] = 0.0f;
- vec[2] = depth;
+ vec[2] = depth_half;
mul_m4_v3(mat, vec);
cent2 = BM_vert_create(bm, vec, NULL, BM_CREATE_NOP);
@@ -1431,23 +1429,26 @@ void bmo_create_cone_exec(BMesh *bm, BMOperator *op)
BMO_vert_flag_enable(bm, cent2, VERT_MARK);
}
- for (a = 0; a < segs; a++, phi += phid) {
+ const int side_faces_len = segs - 1;
+ BMFace **side_faces = MEM_mallocN(sizeof(*side_faces) * side_faces_len, __func__);
+
+ for (int i = 0; i < segs; i++, phi += phid) {
vec[0] = dia1 * sinf(phi);
vec[1] = dia1 * cosf(phi);
- vec[2] = -depth;
+ vec[2] = -depth_half;
mul_m4_v3(mat, vec);
v1 = BM_vert_create(bm, vec, NULL, BM_CREATE_NOP);
vec[0] = dia2 * sinf(phi);
vec[1] = dia2 * cosf(phi);
- vec[2] = depth;
+ vec[2] = depth_half;
mul_m4_v3(mat, vec);
v2 = BM_vert_create(bm, vec, NULL, BM_CREATE_NOP);
BMO_vert_flag_enable(bm, v1, VERT_MARK);
BMO_vert_flag_enable(bm, v2, VERT_MARK);
- if (a) {
+ if (i) {
if (cap_ends) {
f = BM_face_create_quad_tri(bm, cent1, lastv1, v1, NULL, NULL, BM_CREATE_NOP);
if (calc_uvs) {
@@ -1466,6 +1467,7 @@ void bmo_create_cone_exec(BMesh *bm, BMOperator *op)
if (calc_uvs) {
BMO_face_flag_enable(bm, f, FACE_MARK);
}
+ side_faces[i - 1] = f;
}
else {
firstv1 = v1;
@@ -1476,10 +1478,6 @@ void bmo_create_cone_exec(BMesh *bm, BMOperator *op)
lastv2 = v2;
}
- if (!a) {
- return;
- }
-
if (cap_ends) {
f = BM_face_create_quad_tri(bm, cent1, v1, firstv1, NULL, NULL, BM_CREATE_NOP);
if (calc_uvs) {
@@ -1503,11 +1501,38 @@ void bmo_create_cone_exec(BMesh *bm, BMOperator *op)
BM_mesh_calc_uvs_cone(bm, mat, dia2, dia1, segs, cap_ends, FACE_MARK, cd_loop_uv_offset);
}
+ /* Collapse vertices at the first end. */
+ if (dia1 == 0.0f) {
+ if (cap_ends) {
+ BM_vert_kill(bm, cent1);
+ }
+ for (int i = 0; i < side_faces_len; i++) {
+ f = side_faces[i];
+ BMLoop *l = BM_FACE_FIRST_LOOP(f);
+ BM_edge_collapse(bm, l->prev->e, l->prev->v, true, true);
+ }
+ }
+
+ /* Collapse vertices at the second end. */
+ if (dia2 == 0.0f) {
+ if (cap_ends) {
+ BM_vert_kill(bm, cent2);
+ }
+ for (int i = 0; i < side_faces_len; i++) {
+ f = side_faces[i];
+ BMLoop *l = BM_FACE_FIRST_LOOP(f);
+ BM_edge_collapse(bm, l->next->e, l->next->v, true, true);
+ }
+ }
+
if (!cap_tris) {
BMO_op_callf(bm, op->flag, "dissolve_faces faces=%ff", FACE_NEW);
}
- BMO_op_callf(bm, op->flag, "remove_doubles verts=%fv dist=%f", VERT_MARK, 0.0000005 * depth);
+ if (side_faces != NULL) {
+ MEM_freeN(side_faces);
+ }
+
BMO_slot_buffer_from_enabled_flag(bm, op, op->slots_out, "verts.out", BM_VERT, VERT_MARK);
}
diff --git a/source/blender/bmesh/tools/bmesh_bevel.c b/source/blender/bmesh/tools/bmesh_bevel.c
index bc127243836..720eb34bda7 100644
--- a/source/blender/bmesh/tools/bmesh_bevel.c
+++ b/source/blender/bmesh/tools/bmesh_bevel.c
@@ -997,10 +997,10 @@ static bool point_between_edges(float co[3], BMVert *v, BMFace *f, EdgeHalf *e1,
* record the change in offset_l (or offset_r); later we can tell that a change has happened
* because the offset will differ from its original value in offset_l_spec (or offset_r_spec).
*
- * \param edges_between If this is true, there are edges between e1 and e2 in CCW order so they
+ * \param edges_between: If this is true, there are edges between e1 and e2 in CCW order so they
* don't share a common face. We want the meeting point to be on an existing face so it
* should be dropped onto one of the intermediate faces, if possible.
- * \param e_in_plane If we need to drop from the calculated offset lines to one of the faces,
+ * \param e_in_plane: If we need to drop from the calculated offset lines to one of the faces,
* we don't want to drop onto the 'in plane' face, so if this is not null skip this edge's faces.
*/
static void offset_meet(EdgeHalf *e1,
@@ -2601,13 +2601,13 @@ static void adjust_miter_inner_coords(BevelParams *bp, BevVert *bv, EdgeHalf *em
* to be a subsequent pass to make the widths as consistent as possible.
* Doesn't make the actual BMVerts.
*
- * For a width consistency pass, we just recalculate the coordinates of the BoundVerts. If the
+ * For a width consistency pass, we just recalculate the coordinates of the #BoundVerts. If the
* other ends have been (re)built already, then we copy the offsets from there to match, else we
* use the ideal (user-specified) widths.
*
- * \param construct The first time through, construct will be true and we are making the BoundVerts
- * and setting up the BoundVert and EdgeHalf pointers appropriately. Also, if construct, decide on
- * the mesh pattern that will be used inside the boundary.
+ * \param construct: The first time through, construct will be true and we are making the
+ * #BoundVerts and setting up the #BoundVert and #EdgeHalf pointers appropriately.
+ * Also, if construct, decide on the mesh pattern that will be used inside the boundary.
*/
static void build_boundary(BevelParams *bp, BevVert *bv, bool construct)
{
@@ -4167,6 +4167,10 @@ static int tri_corner_test(BevelParams *bp, BevVert *bv)
if (bv->vmesh->count != 3) {
return 0;
}
+
+ /* Only use the tri-corner special case if the offset is the same for every edge. */
+ float offset = bv->edges[0].offset_l;
+
totang = 0.0f;
for (i = 0; i < bv->edgecount; i++) {
e = &bv->edges[i];
@@ -4178,6 +4182,11 @@ static int tri_corner_test(BevelParams *bp, BevVert *bv)
else if (absang >= 3.0f * (float)M_PI_4) {
return -1;
}
+
+ if (e->is_bev && !compare_ff(e->offset_l, offset, BEVEL_EPSILON)) {
+ return -1;
+ }
+
totang += ang;
}
if (in_plane_e != bv->edgecount - 3) {
diff --git a/source/blender/bmesh/tools/bmesh_bevel.h b/source/blender/bmesh/tools/bmesh_bevel.h
index 479a8a3f6d6..8562e584ec9 100644
--- a/source/blender/bmesh/tools/bmesh_bevel.h
+++ b/source/blender/bmesh/tools/bmesh_bevel.h
@@ -47,4 +47,5 @@ void BM_mesh_bevel(BMesh *bm,
const bool use_custom_profile,
const struct CurveProfile *custom_profile,
const int vmesh_method);
+
#endif /* __BMESH_BEVEL_H__ */
diff --git a/source/blender/bmesh/tools/bmesh_intersect.c b/source/blender/bmesh/tools/bmesh_intersect.c
index 4ca8364c312..c73b80d57f7 100644
--- a/source/blender/bmesh/tools/bmesh_intersect.c
+++ b/source/blender/bmesh/tools/bmesh_intersect.c
@@ -509,7 +509,7 @@ static bool bm_loop_filter_fn(const BMLoop *l, void *user_data)
* Return true if we have any intersections.
*/
static void bm_isect_tri_tri(
- struct ISectState *s, int a_index, int b_index, BMLoop **a, BMLoop **b)
+ struct ISectState *s, int a_index, int b_index, BMLoop **a, BMLoop **b, bool no_shared)
{
BMFace *f_a = (*a)->f;
BMFace *f_b = (*b)->f;
@@ -527,9 +527,16 @@ static void bm_isect_tri_tri(
STACK_DECLARE(iv_ls_a);
STACK_DECLARE(iv_ls_b);
- if (UNLIKELY(ELEM(fv_a[0], UNPACK3(fv_b)) || ELEM(fv_a[1], UNPACK3(fv_b)) ||
- ELEM(fv_a[2], UNPACK3(fv_b)))) {
- return;
+ if (no_shared) {
+ if (UNLIKELY(ELEM(fv_a[0], UNPACK3(fv_b)) || ELEM(fv_a[1], UNPACK3(fv_b)) ||
+ ELEM(fv_a[2], UNPACK3(fv_b)))) {
+ return;
+ }
+ }
+ else {
+ if (UNLIKELY(BM_face_share_edge_check(f_a, f_b))) {
+ return;
+ }
}
STACK_INIT(iv_ls_a, ARRAY_SIZE(iv_ls_a));
@@ -564,11 +571,11 @@ static void bm_isect_tri_tri(
for (i_b = 0; i_b < 3; i_b++) {
if (len_squared_v3v3(fv_a[i_a]->co, fv_b[i_b]->co) <= s->epsilon.eps2x_sq) {
#ifdef USE_DUMP
- if (BM_ELEM_API_FLAG_TEST(fv_a[i_a], VERT_VISIT) == 0) {
- printf(" ('VERT-VERT-A') %d, %d),\n", i_a, BM_elem_index_get(fv_a[i_a]));
+ if (BM_ELEM_API_FLAG_TEST(fv_a[i_a], VERT_VISIT_A) == 0) {
+ printf(" ('VERT-VERT-A') %u, %d),\n", i_a, BM_elem_index_get(fv_a[i_a]));
}
- if (BM_ELEM_API_FLAG_TEST(fv_b[i_b], VERT_VISIT) == 0) {
- printf(" ('VERT-VERT-B') %d, %d),\n", i_b, BM_elem_index_get(fv_b[i_b]));
+ if (BM_ELEM_API_FLAG_TEST(fv_b[i_b], VERT_VISIT_B) == 0) {
+ printf(" ('VERT-VERT-B') %u, %d),\n", i_b, BM_elem_index_get(fv_b[i_b]));
}
#endif
STACK_PUSH_TEST_A(fv_a[i_a]);
@@ -905,7 +912,7 @@ static int isect_bvhtree_point_v3(BVHTree *tree, const float **looptris, const f
BLI_bvhtree_ray_cast(tree, co, dir, 0.0f, &hit, raycast_callback, &raycast_data);
# ifdef USE_DUMP
- printf("%s: Total intersections: %d\n", __func__, z_buffer.count);
+ printf("%s: Total intersections: %zu\n", __func__, z_buffer.count);
# endif
int num_isect;
@@ -1082,6 +1089,12 @@ bool BM_mesh_intersect(BMesh *bm,
tree_b = tree_a;
}
+ /* For self intersection this can be useful, sometimes users generate geometry
+ * where surfaces that seem disconnected happen to share an edge.
+ * So when performing intersection calculation allow shared vertices,
+ * just not shared edges. See T75946. */
+ const bool isect_tri_tri_no_shared = (boolean_mode != BMESH_ISECT_BOOLEAN_NONE);
+
int flag = BVH_OVERLAP_USE_THREADING | BVH_OVERLAP_RETURN_PAIRS;
# ifdef DEBUG
/* The overlap result must match that obtained in Release to succeed
@@ -1103,7 +1116,8 @@ bool BM_mesh_intersect(BMesh *bm,
overlap[i].indexA,
overlap[i].indexB,
looptris[overlap[i].indexA],
- looptris[overlap[i].indexB]);
+ looptris[overlap[i].indexB],
+ isect_tri_tri_no_shared);
# ifdef USE_DUMP
printf(")),\n");
# endif
@@ -1140,7 +1154,7 @@ bool BM_mesh_intersect(BMesh *bm,
# ifdef USE_DUMP
printf(" ((%d, %d), (", i_a, i_b);
# endif
- bm_isect_tri_tri(&s, i_a, i_b, looptris[i_a], looptris[i_b]);
+ bm_isect_tri_tri(&s, i_a, i_b, looptris[i_a], looptris[i_b], isect_tri_tri_no_shared);
# ifdef USE_DUMP
printf(")),\n");
# endif
@@ -1179,7 +1193,7 @@ bool BM_mesh_intersect(BMesh *bm,
}
# ifdef USE_DUMP
- printf("# SPLITTING EDGE: %d, %d\n", BM_elem_index_get(e), v_ls_base->list_len);
+ printf("# SPLITTING EDGE: %d, %u\n", BM_elem_index_get(e), v_ls_base->list_len);
# endif
/* intersect */
is_wire = BLI_gset_haskey(s.wire_edges, e);
@@ -1258,6 +1272,13 @@ bool BM_mesh_intersect(BMesh *bm,
continue;
}
+ /* It's possible the vertex to dissolve is an edge on an existing face
+ * that doesn't divide the face, therefor the edges are not wire
+ * and shouldn't be handled here, see: T63787. */
+ if (!BLI_gset_haskey(s.wire_edges, e_pair[0]) || !BLI_gset_haskey(s.wire_edges, e_pair[1])) {
+ continue;
+ }
+
v_a = BM_edge_other_vert(e_pair[0], v);
v_b = BM_edge_other_vert(e_pair[1], v);
diff --git a/source/blender/bmesh/tools/bmesh_intersect_edges.c b/source/blender/bmesh/tools/bmesh_intersect_edges.c
index 2df7c85871d..3f0492aebb6 100644
--- a/source/blender/bmesh/tools/bmesh_intersect_edges.c
+++ b/source/blender/bmesh/tools/bmesh_intersect_edges.c
@@ -152,6 +152,7 @@ static BMFace *bm_vert_pair_best_face_get(
sub_v3_v3v3(data[1], v_a->co, data[0]);
r_best_face = BM_vert_pair_shared_face_cb(
v_a, v_b, false, bm_vert_pair_share_splittable_face_cb, &data, &dummy, &dummy);
+ BLI_assert(!r_best_face || BM_edge_in_face(edgenet[0], r_best_face) == false);
}
else {
struct EDBMSplitBestFaceData data = {
@@ -846,6 +847,7 @@ bool BM_mesh_intersect_edges(
v_val = (*pair_iter)[1].vert;
BLI_ghash_insert(r_targetmap, v_key, v_val);
if (split_faces) {
+ /* The vertex index indicates its position in the pair_array flat. */
BM_elem_index_set(v_key, i * 2);
BM_elem_index_set(v_val, i * 2 + 1);
}
@@ -858,6 +860,7 @@ bool BM_mesh_intersect_edges(
struct EDBMSplitElem *pair_flat = (struct EDBMSplitElem *)&pair_array[0];
BM_ITER_MESH (e, &iter, bm, BM_EDGES_OF_MESH) {
if (BM_elem_flag_test(e, BM_ELEM_TAG)) {
+ /* Edge out of context or already tested. */
continue;
}
@@ -869,7 +872,7 @@ bool BM_mesh_intersect_edges(
int v_cut_other = BM_elem_index_get(vb);
if (v_cut == -1 && v_cut_other == -1) {
if (!BM_elem_flag_test(va, BM_ELEM_TAG) && !BM_elem_flag_test(vb, BM_ELEM_TAG)) {
- /* Ignore edges out of context. */
+ /* Edge out of context. */
BM_elem_flag_enable(e, BM_ELEM_TAG);
}
continue;
@@ -884,38 +887,65 @@ bool BM_mesh_intersect_edges(
v_cut_other = -1;
}
+ /* `v_cut` indicates the other vertex within the `pair_array`. */
v_cut += v_cut % 2 ? -1 : 1;
va_dest = pair_flat[v_cut].vert;
+ if (BM_vert_pair_share_face_check(va, va_dest)) {
+ /* Vert par acts on the same face.
+ * Although there are cases like this where the face can be split,
+ * for efficiency it is better to ignore then. */
+ continue;
+ }
+
BMFace *best_face = NULL;
- int edgenet_len = 0;
BMVert *v_other_dest, *v_other = vb;
BMEdge *e_net = e;
+ int edgenet_len = 0;
while (true) {
- if (edgenet_alloc_len == edgenet_len) {
- edgenet_alloc_len = (edgenet_alloc_len + 1) * 2;
- edgenet = MEM_reallocN(edgenet, (edgenet_alloc_len) * sizeof(*edgenet));
- }
- edgenet[edgenet_len++] = e_net;
-
if (v_cut_other != -1) {
v_cut_other += v_cut_other % 2 ? -1 : 1;
v_other_dest = pair_flat[v_cut_other].vert;
+
+ if (BM_vert_pair_share_face_check(v_other, v_other_dest)) {
+ /* Vert par acts on the same face.
+ * Although there are cases like this where the face can be split,
+ * for efficiency and to avoid complications, it is better to ignore these cases.
+ */
+ break;
+ }
}
else {
v_other_dest = v_other;
}
- if (BM_edge_exists(va_dest, v_other_dest)) {
- /* No need to detect face. (Optimization). */
+ if (va_dest == v_other_dest) {
+ /* Edge/Edgenet to vertex - we can't split the face. */
break;
}
+ if (edgenet_len == 0 && BM_edge_exists(va_dest, v_other_dest)) {
+ /* Edge to edge - no need to detect face. */
+ break;
+ }
+
+ if (edgenet_alloc_len == edgenet_len) {
+ edgenet_alloc_len = (edgenet_alloc_len + 1) * 2;
+ edgenet = MEM_reallocN(edgenet, (edgenet_alloc_len) * sizeof(*edgenet));
+ }
+ edgenet[edgenet_len++] = e_net;
best_face = bm_vert_pair_best_face_get(
va_dest, v_other_dest, edgenet, edgenet_len, dist);
if (best_face) {
- if (va_dest != va) {
+ if ((va_dest != va) && !BM_edge_exists(va_dest, va)) {
+ /**
+ * <pre>
+ * va---vb---
+ * /
+ * va_dest
+ * </pre>
+ */
e_net = edgenet[0];
if (edgenet_len > 1) {
vb = BM_edge_other_vert(e_net, va);
@@ -925,7 +955,15 @@ bool BM_mesh_intersect_edges(
}
edgenet[0] = BM_edge_create(bm, va_dest, vb, e_net, BM_CREATE_NOP);
}
- if ((edgenet_len > 1) && (v_other_dest != v_other)) {
+ if ((edgenet_len > 1) && (v_other_dest != v_other) &&
+ !BM_edge_exists(v_other_dest, v_other)) {
+ /**
+ * <pre>
+ * ---v---v_other
+ * \
+ * v_other_dest
+ * </pre>
+ */
e_net = edgenet[edgenet_len - 1];
edgenet[edgenet_len - 1] = BM_edge_create(
bm, v_other_dest, BM_edge_other_vert(e_net, v_other), e_net, BM_CREATE_NOP);
diff --git a/source/blender/bmesh/tools/bmesh_path.c b/source/blender/bmesh/tools/bmesh_path.c
index 0331ca476dd..713a68969e5 100644
--- a/source/blender/bmesh/tools/bmesh_path.c
+++ b/source/blender/bmesh/tools/bmesh_path.c
@@ -225,7 +225,7 @@ static void edgetag_add_adjacent(HeapSimple *heap,
/* unlike vert/face, stepping faces disables scanning connected edges
* and only steps over faces (selecting a ring of edges instead of a loop) */
- if (params->use_step_face == false) {
+ if (params->use_step_face == false || e_a->l == NULL) {
BMIter viter;
BMVert *v;
diff --git a/source/blender/compositor/COM_compositor.h b/source/blender/compositor/COM_compositor.h
index 55f68f2b5c1..a24904551c6 100644
--- a/source/blender/compositor/COM_compositor.h
+++ b/source/blender/compositor/COM_compositor.h
@@ -19,13 +19,13 @@
#ifndef __COM_COMPOSITOR_H__
#define __COM_COMPOSITOR_H__
+#include "DNA_color_types.h"
+#include "DNA_node_types.h"
+
#ifdef __cplusplus
extern "C" {
#endif
-#include "DNA_color_types.h"
-#include "DNA_node_types.h"
-
/* Keep ascii art. */
/* clang-format off */
/**
@@ -295,8 +295,6 @@ extern "C" {
*
* \section executePixel executing a pixel
* Finally the last step, the node functionality :)
- *
- * \page newnode Creating new nodes
*/
/**
diff --git a/source/blender/compositor/intern/COM_Converter.cpp b/source/blender/compositor/intern/COM_Converter.cpp
index e8474ba8318..edfeb3a3a04 100644
--- a/source/blender/compositor/intern/COM_Converter.cpp
+++ b/source/blender/compositor/intern/COM_Converter.cpp
@@ -18,11 +18,9 @@
#include <string.h>
-extern "C" {
#include "DNA_node_types.h"
#include "BKE_node.h"
-}
#include "COM_NodeOperation.h"
#include "COM_NodeOperationBuilder.h"
diff --git a/source/blender/compositor/intern/COM_ExecutionSystem.cpp b/source/blender/compositor/intern/COM_ExecutionSystem.cpp
index fa40f150335..34682aae2fd 100644
--- a/source/blender/compositor/intern/COM_ExecutionSystem.cpp
+++ b/source/blender/compositor/intern/COM_ExecutionSystem.cpp
@@ -20,9 +20,8 @@
#include "BLI_utildefines.h"
#include "PIL_time.h"
-extern "C" {
+
#include "BKE_node.h"
-}
#include "BLT_translation.h"
diff --git a/source/blender/compositor/intern/COM_MemoryBuffer.h b/source/blender/compositor/intern/COM_MemoryBuffer.h
index 7e5b0264aa3..6ba8f144482 100644
--- a/source/blender/compositor/intern/COM_MemoryBuffer.h
+++ b/source/blender/compositor/intern/COM_MemoryBuffer.h
@@ -25,10 +25,8 @@ class MemoryBuffer;
#include "COM_MemoryProxy.h"
#include "COM_SocketReader.h"
-extern "C" {
#include "BLI_math.h"
#include "BLI_rect.h"
-}
/**
* \brief state of a memory buffer
diff --git a/source/blender/compositor/intern/COM_Node.cpp b/source/blender/compositor/intern/COM_Node.cpp
index df5a8e690d3..31535c5851f 100644
--- a/source/blender/compositor/intern/COM_Node.cpp
+++ b/source/blender/compositor/intern/COM_Node.cpp
@@ -18,11 +18,9 @@
#include <string.h>
-extern "C" {
#include "BKE_node.h"
#include "RNA_access.h"
-}
#include "COM_ExecutionSystem.h"
#include "COM_NodeOperation.h"
diff --git a/source/blender/compositor/intern/COM_NodeConverter.cpp b/source/blender/compositor/intern/COM_NodeConverter.cpp
index eff825b075d..2db31bd4133 100644
--- a/source/blender/compositor/intern/COM_NodeConverter.cpp
+++ b/source/blender/compositor/intern/COM_NodeConverter.cpp
@@ -16,9 +16,7 @@
* Copyright 2013, Blender Foundation.
*/
-extern "C" {
#include "BLI_utildefines.h"
-}
#include "COM_Debug.h"
diff --git a/source/blender/compositor/intern/COM_NodeGraph.cpp b/source/blender/compositor/intern/COM_NodeGraph.cpp
index 6640f144518..cb27fa21b4d 100644
--- a/source/blender/compositor/intern/COM_NodeGraph.cpp
+++ b/source/blender/compositor/intern/COM_NodeGraph.cpp
@@ -18,14 +18,12 @@
#include <cstring>
-extern "C" {
#include "BLI_listbase.h"
#include "BLI_utildefines.h"
#include "DNA_node_types.h"
#include "BKE_node.h"
-}
#include "COM_CompositorContext.h"
#include "COM_Converter.h"
diff --git a/source/blender/compositor/intern/COM_NodeGraph.h b/source/blender/compositor/intern/COM_NodeGraph.h
index b005149c839..531832c2c65 100644
--- a/source/blender/compositor/intern/COM_NodeGraph.h
+++ b/source/blender/compositor/intern/COM_NodeGraph.h
@@ -23,9 +23,7 @@
#include <set>
#include <vector>
-extern "C" {
#include "DNA_node_types.h"
-}
#ifdef WITH_CXX_GUARDEDALLOC
# include "MEM_guardedalloc.h"
diff --git a/source/blender/compositor/intern/COM_NodeOperation.h b/source/blender/compositor/intern/COM_NodeOperation.h
index b2c4961ca35..07f482f9e5f 100644
--- a/source/blender/compositor/intern/COM_NodeOperation.h
+++ b/source/blender/compositor/intern/COM_NodeOperation.h
@@ -23,11 +23,9 @@
#include <sstream>
#include <string>
-extern "C" {
#include "BLI_math_color.h"
#include "BLI_math_vector.h"
#include "BLI_threads.h"
-}
#include "COM_MemoryBuffer.h"
#include "COM_MemoryProxy.h"
diff --git a/source/blender/compositor/intern/COM_NodeOperationBuilder.cpp b/source/blender/compositor/intern/COM_NodeOperationBuilder.cpp
index 9f6b91915e0..5ce6ca34b34 100644
--- a/source/blender/compositor/intern/COM_NodeOperationBuilder.cpp
+++ b/source/blender/compositor/intern/COM_NodeOperationBuilder.cpp
@@ -16,9 +16,7 @@
* Copyright 2013, Blender Foundation.
*/
-extern "C" {
#include "BLI_utildefines.h"
-}
#include "COM_Converter.h"
#include "COM_Debug.h"
diff --git a/source/blender/compositor/intern/COM_WorkScheduler.h b/source/blender/compositor/intern/COM_WorkScheduler.h
index 5e0675f1833..3a1b4c533bd 100644
--- a/source/blender/compositor/intern/COM_WorkScheduler.h
+++ b/source/blender/compositor/intern/COM_WorkScheduler.h
@@ -20,9 +20,9 @@
#define __COM_WORKSCHEDULER_H__
#include "COM_ExecutionGroup.h"
-extern "C" {
+
#include "BLI_threads.h"
-}
+
#include "COM_Device.h"
#include "COM_WorkPackage.h"
#include "COM_defines.h"
diff --git a/source/blender/compositor/intern/COM_compositor.cpp b/source/blender/compositor/intern/COM_compositor.cpp
index 1793abae134..bccdd026ead 100644
--- a/source/blender/compositor/intern/COM_compositor.cpp
+++ b/source/blender/compositor/intern/COM_compositor.cpp
@@ -16,13 +16,11 @@
* Copyright 2011, Blender Foundation.
*/
-extern "C" {
-#include "BKE_node.h"
#include "BLI_threads.h"
-}
#include "BLT_translation.h"
+#include "BKE_node.h"
#include "BKE_scene.h"
#include "COM_ExecutionSystem.h"
diff --git a/source/blender/compositor/nodes/COM_CornerPinNode.h b/source/blender/compositor/nodes/COM_CornerPinNode.h
index ea62dea12de..a8e88a0ef4f 100644
--- a/source/blender/compositor/nodes/COM_CornerPinNode.h
+++ b/source/blender/compositor/nodes/COM_CornerPinNode.h
@@ -20,9 +20,7 @@
#include "COM_Node.h"
-extern "C" {
#include "DNA_node_types.h"
-}
/**
* \brief CornerPinNode
diff --git a/source/blender/compositor/nodes/COM_ImageNode.h b/source/blender/compositor/nodes/COM_ImageNode.h
index 6ed9acd58b8..7883f4d7ab3 100644
--- a/source/blender/compositor/nodes/COM_ImageNode.h
+++ b/source/blender/compositor/nodes/COM_ImageNode.h
@@ -23,9 +23,8 @@
#include "COM_defines.h"
#include "DNA_image_types.h"
#include "DNA_node_types.h"
-extern "C" {
+
#include "RE_engine.h"
-}
/**
* \brief ImageNode
diff --git a/source/blender/compositor/nodes/COM_KeyingScreenNode.cpp b/source/blender/compositor/nodes/COM_KeyingScreenNode.cpp
index 6a005b2b712..93a9a071226 100644
--- a/source/blender/compositor/nodes/COM_KeyingScreenNode.cpp
+++ b/source/blender/compositor/nodes/COM_KeyingScreenNode.cpp
@@ -20,9 +20,7 @@
#include "COM_ExecutionSystem.h"
#include "COM_KeyingScreenOperation.h"
-extern "C" {
#include "DNA_movieclip_types.h"
-}
KeyingScreenNode::KeyingScreenNode(bNode *editorNode) : Node(editorNode)
{
diff --git a/source/blender/compositor/nodes/COM_MaskNode.cpp b/source/blender/compositor/nodes/COM_MaskNode.cpp
index cceeef6b437..b28b849521c 100644
--- a/source/blender/compositor/nodes/COM_MaskNode.cpp
+++ b/source/blender/compositor/nodes/COM_MaskNode.cpp
@@ -20,9 +20,7 @@
#include "COM_ExecutionSystem.h"
#include "COM_MaskOperation.h"
-extern "C" {
#include "DNA_mask_types.h"
-}
MaskNode::MaskNode(bNode *editorNode) : Node(editorNode)
{
diff --git a/source/blender/compositor/nodes/COM_MovieClipNode.cpp b/source/blender/compositor/nodes/COM_MovieClipNode.cpp
index 29fd47f33b3..3366a8c20d6 100644
--- a/source/blender/compositor/nodes/COM_MovieClipNode.cpp
+++ b/source/blender/compositor/nodes/COM_MovieClipNode.cpp
@@ -22,12 +22,12 @@
#include "COM_MovieClipOperation.h"
#include "COM_SetValueOperation.h"
-extern "C" {
#include "BKE_movieclip.h"
#include "BKE_tracking.h"
+
#include "DNA_movieclip_types.h"
+
#include "IMB_imbuf.h"
-}
MovieClipNode::MovieClipNode(bNode *editorNode) : Node(editorNode)
{
diff --git a/source/blender/compositor/nodes/COM_PlaneTrackDeformNode.cpp b/source/blender/compositor/nodes/COM_PlaneTrackDeformNode.cpp
index 39616bba4f9..6b9b51631ec 100644
--- a/source/blender/compositor/nodes/COM_PlaneTrackDeformNode.cpp
+++ b/source/blender/compositor/nodes/COM_PlaneTrackDeformNode.cpp
@@ -21,11 +21,9 @@
#include "COM_PlaneTrackOperation.h"
-extern "C" {
#include "BKE_movieclip.h"
#include "BKE_node.h"
#include "BKE_tracking.h"
-}
PlaneTrackDeformNode::PlaneTrackDeformNode(bNode *editorNode) : Node(editorNode)
{
diff --git a/source/blender/compositor/nodes/COM_PlaneTrackDeformNode.h b/source/blender/compositor/nodes/COM_PlaneTrackDeformNode.h
index 6ee73e22af0..2c17739a220 100644
--- a/source/blender/compositor/nodes/COM_PlaneTrackDeformNode.h
+++ b/source/blender/compositor/nodes/COM_PlaneTrackDeformNode.h
@@ -21,10 +21,8 @@
#include "COM_Node.h"
-extern "C" {
#include "DNA_movieclip_types.h"
#include "DNA_node_types.h"
-}
/**
* \brief PlaneTrackDeformNode
diff --git a/source/blender/compositor/nodes/COM_Stabilize2dNode.cpp b/source/blender/compositor/nodes/COM_Stabilize2dNode.cpp
index 0b6cb97b049..7a308ac47b9 100644
--- a/source/blender/compositor/nodes/COM_Stabilize2dNode.cpp
+++ b/source/blender/compositor/nodes/COM_Stabilize2dNode.cpp
@@ -24,10 +24,9 @@
#include "COM_SetSamplerOperation.h"
#include "COM_TranslateOperation.h"
-extern "C" {
#include "BKE_tracking.h"
+
#include "DNA_movieclip_types.h"
-}
Stabilize2dNode::Stabilize2dNode(bNode *editorNode) : Node(editorNode)
{
diff --git a/source/blender/compositor/nodes/COM_TimeNode.cpp b/source/blender/compositor/nodes/COM_TimeNode.cpp
index b6927fb8373..9722ead0716 100644
--- a/source/blender/compositor/nodes/COM_TimeNode.cpp
+++ b/source/blender/compositor/nodes/COM_TimeNode.cpp
@@ -19,9 +19,9 @@
#include "COM_TimeNode.h"
#include "COM_ExecutionSystem.h"
#include "COM_SetValueOperation.h"
-extern "C" {
+
#include "BKE_colortools.h"
-}
+
#include "BLI_utildefines.h"
TimeNode::TimeNode(bNode *editorNode) : Node(editorNode)
diff --git a/source/blender/compositor/nodes/COM_TrackPositionNode.cpp b/source/blender/compositor/nodes/COM_TrackPositionNode.cpp
index da9f50a590b..52e7f7d832b 100644
--- a/source/blender/compositor/nodes/COM_TrackPositionNode.cpp
+++ b/source/blender/compositor/nodes/COM_TrackPositionNode.cpp
@@ -22,11 +22,9 @@
#include "COM_ExecutionSystem.h"
#include "COM_TrackPositionOperation.h"
-extern "C" {
#include "DNA_movieclip_types.h"
#include "BKE_node.h"
-}
TrackPositionNode::TrackPositionNode(bNode *editorNode) : Node(editorNode)
{
diff --git a/source/blender/compositor/operations/COM_AntiAliasOperation.cpp b/source/blender/compositor/operations/COM_AntiAliasOperation.cpp
index de7c43a8751..85725cc1d37 100644
--- a/source/blender/compositor/operations/COM_AntiAliasOperation.cpp
+++ b/source/blender/compositor/operations/COM_AntiAliasOperation.cpp
@@ -22,9 +22,7 @@
#include "MEM_guardedalloc.h"
-extern "C" {
#include "RE_render_ext.h"
-}
/* An implementation of the Scale3X edge-extrapolation algorithm.
*
diff --git a/source/blender/compositor/operations/COM_BilateralBlurOperation.cpp b/source/blender/compositor/operations/COM_BilateralBlurOperation.cpp
index 44cb4056c99..8168867a522 100644
--- a/source/blender/compositor/operations/COM_BilateralBlurOperation.cpp
+++ b/source/blender/compositor/operations/COM_BilateralBlurOperation.cpp
@@ -19,9 +19,7 @@
#include "COM_BilateralBlurOperation.h"
#include "BLI_math.h"
-extern "C" {
#include "RE_pipeline.h"
-}
BilateralBlurOperation::BilateralBlurOperation() : NodeOperation()
{
diff --git a/source/blender/compositor/operations/COM_BlurBaseOperation.cpp b/source/blender/compositor/operations/COM_BlurBaseOperation.cpp
index 24c68ddbec7..ef0f259c592 100644
--- a/source/blender/compositor/operations/COM_BlurBaseOperation.cpp
+++ b/source/blender/compositor/operations/COM_BlurBaseOperation.cpp
@@ -20,9 +20,7 @@
#include "BLI_math.h"
#include "MEM_guardedalloc.h"
-extern "C" {
#include "RE_pipeline.h"
-}
BlurBaseOperation::BlurBaseOperation(DataType data_type) : NodeOperation()
{
diff --git a/source/blender/compositor/operations/COM_BokehBlurOperation.cpp b/source/blender/compositor/operations/COM_BokehBlurOperation.cpp
index 4d858934796..c00ef2468c0 100644
--- a/source/blender/compositor/operations/COM_BokehBlurOperation.cpp
+++ b/source/blender/compositor/operations/COM_BokehBlurOperation.cpp
@@ -20,9 +20,7 @@
#include "BLI_math.h"
#include "COM_OpenCLDevice.h"
-extern "C" {
#include "RE_pipeline.h"
-}
BokehBlurOperation::BokehBlurOperation() : NodeOperation()
{
diff --git a/source/blender/compositor/operations/COM_CalculateMeanOperation.cpp b/source/blender/compositor/operations/COM_CalculateMeanOperation.cpp
index 5d01154bbda..ecd61e95f43 100644
--- a/source/blender/compositor/operations/COM_CalculateMeanOperation.cpp
+++ b/source/blender/compositor/operations/COM_CalculateMeanOperation.cpp
@@ -20,9 +20,7 @@
#include "BLI_math.h"
#include "BLI_utildefines.h"
-extern "C" {
#include "IMB_colormanagement.h"
-}
CalculateMeanOperation::CalculateMeanOperation() : NodeOperation()
{
diff --git a/source/blender/compositor/operations/COM_CalculateStandardDeviationOperation.cpp b/source/blender/compositor/operations/COM_CalculateStandardDeviationOperation.cpp
index dfe1a936c9c..059040d6f05 100644
--- a/source/blender/compositor/operations/COM_CalculateStandardDeviationOperation.cpp
+++ b/source/blender/compositor/operations/COM_CalculateStandardDeviationOperation.cpp
@@ -20,9 +20,7 @@
#include "BLI_math.h"
#include "BLI_utildefines.h"
-extern "C" {
#include "IMB_colormanagement.h"
-}
CalculateStandardDeviationOperation::CalculateStandardDeviationOperation()
: CalculateMeanOperation()
diff --git a/source/blender/compositor/operations/COM_ColorCorrectionOperation.cpp b/source/blender/compositor/operations/COM_ColorCorrectionOperation.cpp
index 31567398d98..39ffb690328 100644
--- a/source/blender/compositor/operations/COM_ColorCorrectionOperation.cpp
+++ b/source/blender/compositor/operations/COM_ColorCorrectionOperation.cpp
@@ -19,9 +19,7 @@
#include "COM_ColorCorrectionOperation.h"
#include "BLI_math.h"
-extern "C" {
#include "IMB_colormanagement.h"
-}
ColorCorrectionOperation::ColorCorrectionOperation() : NodeOperation()
{
diff --git a/source/blender/compositor/operations/COM_ColorCurveOperation.cpp b/source/blender/compositor/operations/COM_ColorCurveOperation.cpp
index 90d3a60abd0..9d514c872f7 100644
--- a/source/blender/compositor/operations/COM_ColorCurveOperation.cpp
+++ b/source/blender/compositor/operations/COM_ColorCurveOperation.cpp
@@ -18,14 +18,9 @@
#include "COM_ColorCurveOperation.h"
-#ifdef __cplusplus
-extern "C" {
-#endif
#include "BKE_colortools.h"
-#ifdef __cplusplus
-}
-# include "MEM_guardedalloc.h"
-#endif
+
+#include "MEM_guardedalloc.h"
ColorCurveOperation::ColorCurveOperation() : CurveBaseOperation()
{
diff --git a/source/blender/compositor/operations/COM_ColorRampOperation.cpp b/source/blender/compositor/operations/COM_ColorRampOperation.cpp
index f2c153c5d30..95e0bd2d82b 100644
--- a/source/blender/compositor/operations/COM_ColorRampOperation.cpp
+++ b/source/blender/compositor/operations/COM_ColorRampOperation.cpp
@@ -18,13 +18,7 @@
#include "COM_ColorRampOperation.h"
-#ifdef __cplusplus
-extern "C" {
-#endif
#include "BKE_colorband.h"
-#ifdef __cplusplus
-}
-#endif
ColorRampOperation::ColorRampOperation() : NodeOperation()
{
diff --git a/source/blender/compositor/operations/COM_CompositorOperation.cpp b/source/blender/compositor/operations/COM_CompositorOperation.cpp
index cb41071e6f0..71cef9dc4da 100644
--- a/source/blender/compositor/operations/COM_CompositorOperation.cpp
+++ b/source/blender/compositor/operations/COM_CompositorOperation.cpp
@@ -22,13 +22,14 @@
#include "BLI_listbase.h"
#include "MEM_guardedalloc.h"
-extern "C" {
#include "BLI_threads.h"
+
#include "RE_pipeline.h"
#include "RE_render_ext.h"
#include "RE_shader_ext.h"
+
#include "render_types.h"
-}
+
#include "PIL_time.h"
CompositorOperation::CompositorOperation() : NodeOperation()
diff --git a/source/blender/compositor/operations/COM_ConvertColorProfileOperation.cpp b/source/blender/compositor/operations/COM_ConvertColorProfileOperation.cpp
index 59a605a77c9..6a4c5db856c 100644
--- a/source/blender/compositor/operations/COM_ConvertColorProfileOperation.cpp
+++ b/source/blender/compositor/operations/COM_ConvertColorProfileOperation.cpp
@@ -18,9 +18,8 @@
#include "COM_ConvertColorProfileOperation.h"
-extern "C" {
#include "IMB_imbuf.h"
-}
+
ConvertColorProfileOperation::ConvertColorProfileOperation() : NodeOperation()
{
this->addInputSocket(COM_DT_COLOR);
diff --git a/source/blender/compositor/operations/COM_ConvertOperation.cpp b/source/blender/compositor/operations/COM_ConvertOperation.cpp
index 6caccb89046..0bd3f5b8796 100644
--- a/source/blender/compositor/operations/COM_ConvertOperation.cpp
+++ b/source/blender/compositor/operations/COM_ConvertOperation.cpp
@@ -18,9 +18,7 @@
#include "COM_ConvertOperation.h"
-extern "C" {
#include "IMB_colormanagement.h"
-}
ConvertBaseOperation::ConvertBaseOperation()
{
diff --git a/source/blender/compositor/operations/COM_CurveBaseOperation.cpp b/source/blender/compositor/operations/COM_CurveBaseOperation.cpp
index 858931ad46d..b18e77cf0e3 100644
--- a/source/blender/compositor/operations/COM_CurveBaseOperation.cpp
+++ b/source/blender/compositor/operations/COM_CurveBaseOperation.cpp
@@ -18,13 +18,7 @@
#include "COM_CurveBaseOperation.h"
-#ifdef __cplusplus
-extern "C" {
-#endif
#include "BKE_colortools.h"
-#ifdef __cplusplus
-}
-#endif
CurveBaseOperation::CurveBaseOperation() : NodeOperation()
{
diff --git a/source/blender/compositor/operations/COM_DirectionalBlurOperation.cpp b/source/blender/compositor/operations/COM_DirectionalBlurOperation.cpp
index 1b590c0c392..31eb74fbc42 100644
--- a/source/blender/compositor/operations/COM_DirectionalBlurOperation.cpp
+++ b/source/blender/compositor/operations/COM_DirectionalBlurOperation.cpp
@@ -17,11 +17,11 @@
*/
#include "COM_DirectionalBlurOperation.h"
-#include "BLI_math.h"
#include "COM_OpenCLDevice.h"
-extern "C" {
+
+#include "BLI_math.h"
+
#include "RE_pipeline.h"
-}
DirectionalBlurOperation::DirectionalBlurOperation() : NodeOperation()
{
diff --git a/source/blender/compositor/operations/COM_DoubleEdgeMaskOperation.cpp b/source/blender/compositor/operations/COM_DoubleEdgeMaskOperation.cpp
index 22949a8e6f1..ae6f49bffcd 100644
--- a/source/blender/compositor/operations/COM_DoubleEdgeMaskOperation.cpp
+++ b/source/blender/compositor/operations/COM_DoubleEdgeMaskOperation.cpp
@@ -1136,7 +1136,7 @@ static void do_fillGradientBuffer(unsigned int rw,
* purpose of GO for the proportion calculation.
*
* For the purposes of the minimum distance comparisons, we only check
- * the sums-of-squares against eachother, since they are in the same
+ * the sums-of-squares against each other, since they are in the same
* mathematical sort-order as if we did go ahead and take square roots
*
* Loop through all gradient pixels.
diff --git a/source/blender/compositor/operations/COM_GaussianAlphaXBlurOperation.cpp b/source/blender/compositor/operations/COM_GaussianAlphaXBlurOperation.cpp
index c6239dba604..c028a2c0e4c 100644
--- a/source/blender/compositor/operations/COM_GaussianAlphaXBlurOperation.cpp
+++ b/source/blender/compositor/operations/COM_GaussianAlphaXBlurOperation.cpp
@@ -20,9 +20,7 @@
#include "BLI_math.h"
#include "MEM_guardedalloc.h"
-extern "C" {
#include "RE_pipeline.h"
-}
GaussianAlphaXBlurOperation::GaussianAlphaXBlurOperation() : BlurBaseOperation(COM_DT_VALUE)
{
diff --git a/source/blender/compositor/operations/COM_GaussianAlphaYBlurOperation.cpp b/source/blender/compositor/operations/COM_GaussianAlphaYBlurOperation.cpp
index 37109b4a03e..35abe4cd47b 100644
--- a/source/blender/compositor/operations/COM_GaussianAlphaYBlurOperation.cpp
+++ b/source/blender/compositor/operations/COM_GaussianAlphaYBlurOperation.cpp
@@ -20,9 +20,7 @@
#include "BLI_math.h"
#include "MEM_guardedalloc.h"
-extern "C" {
#include "RE_pipeline.h"
-}
GaussianAlphaYBlurOperation::GaussianAlphaYBlurOperation() : BlurBaseOperation(COM_DT_VALUE)
{
diff --git a/source/blender/compositor/operations/COM_GaussianBokehBlurOperation.cpp b/source/blender/compositor/operations/COM_GaussianBokehBlurOperation.cpp
index 318c182fdff..43e571c4bb7 100644
--- a/source/blender/compositor/operations/COM_GaussianBokehBlurOperation.cpp
+++ b/source/blender/compositor/operations/COM_GaussianBokehBlurOperation.cpp
@@ -19,9 +19,8 @@
#include "COM_GaussianBokehBlurOperation.h"
#include "BLI_math.h"
#include "MEM_guardedalloc.h"
-extern "C" {
+
#include "RE_pipeline.h"
-}
GaussianBokehBlurOperation::GaussianBokehBlurOperation() : BlurBaseOperation(COM_DT_COLOR)
{
diff --git a/source/blender/compositor/operations/COM_GaussianXBlurOperation.cpp b/source/blender/compositor/operations/COM_GaussianXBlurOperation.cpp
index 68cde0d365f..32ad0482791 100644
--- a/source/blender/compositor/operations/COM_GaussianXBlurOperation.cpp
+++ b/source/blender/compositor/operations/COM_GaussianXBlurOperation.cpp
@@ -21,9 +21,7 @@
#include "COM_OpenCLDevice.h"
#include "MEM_guardedalloc.h"
-extern "C" {
#include "RE_pipeline.h"
-}
GaussianXBlurOperation::GaussianXBlurOperation() : BlurBaseOperation(COM_DT_COLOR)
{
diff --git a/source/blender/compositor/operations/COM_GaussianYBlurOperation.cpp b/source/blender/compositor/operations/COM_GaussianYBlurOperation.cpp
index eeddd98d4a4..3ffa797c0c1 100644
--- a/source/blender/compositor/operations/COM_GaussianYBlurOperation.cpp
+++ b/source/blender/compositor/operations/COM_GaussianYBlurOperation.cpp
@@ -21,9 +21,7 @@
#include "COM_OpenCLDevice.h"
#include "MEM_guardedalloc.h"
-extern "C" {
#include "RE_pipeline.h"
-}
GaussianYBlurOperation::GaussianYBlurOperation() : BlurBaseOperation(COM_DT_COLOR)
{
diff --git a/source/blender/compositor/operations/COM_GlareThresholdOperation.cpp b/source/blender/compositor/operations/COM_GlareThresholdOperation.cpp
index 142c51122a1..d050d9b58a9 100644
--- a/source/blender/compositor/operations/COM_GlareThresholdOperation.cpp
+++ b/source/blender/compositor/operations/COM_GlareThresholdOperation.cpp
@@ -19,9 +19,7 @@
#include "COM_GlareThresholdOperation.h"
#include "BLI_math.h"
-extern "C" {
#include "IMB_colormanagement.h"
-}
GlareThresholdOperation::GlareThresholdOperation() : NodeOperation()
{
diff --git a/source/blender/compositor/operations/COM_HueSaturationValueCorrectOperation.cpp b/source/blender/compositor/operations/COM_HueSaturationValueCorrectOperation.cpp
index fae280249de..8292413f6f1 100644
--- a/source/blender/compositor/operations/COM_HueSaturationValueCorrectOperation.cpp
+++ b/source/blender/compositor/operations/COM_HueSaturationValueCorrectOperation.cpp
@@ -20,13 +20,7 @@
#include "BLI_math.h"
-#ifdef __cplusplus
-extern "C" {
-#endif
#include "BKE_colortools.h"
-#ifdef __cplusplus
-}
-#endif
HueSaturationValueCorrectOperation::HueSaturationValueCorrectOperation() : CurveBaseOperation()
{
diff --git a/source/blender/compositor/operations/COM_ImageOperation.cpp b/source/blender/compositor/operations/COM_ImageOperation.cpp
index d70cab4ad2a..38d2fbf9ed4 100644
--- a/source/blender/compositor/operations/COM_ImageOperation.cpp
+++ b/source/blender/compositor/operations/COM_ImageOperation.cpp
@@ -24,14 +24,12 @@
#include "BLI_math.h"
#include "DNA_image_types.h"
-extern "C" {
#include "IMB_colormanagement.h"
#include "IMB_imbuf.h"
#include "IMB_imbuf_types.h"
#include "RE_pipeline.h"
#include "RE_render_ext.h"
#include "RE_shader_ext.h"
-}
BaseImageOperation::BaseImageOperation() : NodeOperation()
{
diff --git a/source/blender/compositor/operations/COM_ImageOperation.h b/source/blender/compositor/operations/COM_ImageOperation.h
index 57656d03092..3e081ee0000 100644
--- a/source/blender/compositor/operations/COM_ImageOperation.h
+++ b/source/blender/compositor/operations/COM_ImageOperation.h
@@ -24,11 +24,10 @@
#include "BLI_utildefines.h"
#include "COM_NodeOperation.h"
#include "MEM_guardedalloc.h"
-extern "C" {
+
#include "RE_pipeline.h"
#include "RE_render_ext.h"
#include "RE_shader_ext.h"
-}
/**
* \brief Base class for all image operations
diff --git a/source/blender/compositor/operations/COM_KeyingScreenOperation.cpp b/source/blender/compositor/operations/COM_KeyingScreenOperation.cpp
index ab9ef0335e0..082091411fb 100644
--- a/source/blender/compositor/operations/COM_KeyingScreenOperation.cpp
+++ b/source/blender/compositor/operations/COM_KeyingScreenOperation.cpp
@@ -24,13 +24,11 @@
#include "BLI_math.h"
#include "BLI_math_color.h"
-extern "C" {
#include "BKE_movieclip.h"
#include "BKE_tracking.h"
#include "IMB_imbuf.h"
#include "IMB_imbuf_types.h"
-}
KeyingScreenOperation::KeyingScreenOperation() : NodeOperation()
{
diff --git a/source/blender/compositor/operations/COM_KeyingScreenOperation.h b/source/blender/compositor/operations/COM_KeyingScreenOperation.h
index 860a358e79d..593e902117b 100644
--- a/source/blender/compositor/operations/COM_KeyingScreenOperation.h
+++ b/source/blender/compositor/operations/COM_KeyingScreenOperation.h
@@ -28,9 +28,7 @@
#include "BLI_listbase.h"
#include "BLI_string.h"
-extern "C" {
#include "BLI_voronoi_2d.h"
-}
/**
* Class with implementation of green screen gradient rasterization
diff --git a/source/blender/compositor/operations/COM_LuminanceMatteOperation.cpp b/source/blender/compositor/operations/COM_LuminanceMatteOperation.cpp
index 30ad954e0bc..936ac00a0e8 100644
--- a/source/blender/compositor/operations/COM_LuminanceMatteOperation.cpp
+++ b/source/blender/compositor/operations/COM_LuminanceMatteOperation.cpp
@@ -19,9 +19,7 @@
#include "COM_LuminanceMatteOperation.h"
#include "BLI_math.h"
-extern "C" {
#include "IMB_colormanagement.h"
-}
LuminanceMatteOperation::LuminanceMatteOperation() : NodeOperation()
{
diff --git a/source/blender/compositor/operations/COM_MaskOperation.cpp b/source/blender/compositor/operations/COM_MaskOperation.cpp
index 88a3a5c535c..bdc954ac081 100644
--- a/source/blender/compositor/operations/COM_MaskOperation.cpp
+++ b/source/blender/compositor/operations/COM_MaskOperation.cpp
@@ -23,9 +23,7 @@
#include "BLI_listbase.h"
#include "BLI_math.h"
-extern "C" {
#include "BKE_mask.h"
-}
MaskOperation::MaskOperation() : NodeOperation()
{
diff --git a/source/blender/compositor/operations/COM_MathBaseOperation.cpp b/source/blender/compositor/operations/COM_MathBaseOperation.cpp
index 524812ac992..1363b75433a 100644
--- a/source/blender/compositor/operations/COM_MathBaseOperation.cpp
+++ b/source/blender/compositor/operations/COM_MathBaseOperation.cpp
@@ -17,9 +17,8 @@
*/
#include "COM_MathBaseOperation.h"
-extern "C" {
+
#include "BLI_math.h"
-}
MathBaseOperation::MathBaseOperation() : NodeOperation()
{
diff --git a/source/blender/compositor/operations/COM_MixOperation.cpp b/source/blender/compositor/operations/COM_MixOperation.cpp
index 6b8a0caa13b..371da20044f 100644
--- a/source/blender/compositor/operations/COM_MixOperation.cpp
+++ b/source/blender/compositor/operations/COM_MixOperation.cpp
@@ -18,9 +18,7 @@
#include "COM_MixOperation.h"
-extern "C" {
#include "BLI_math.h"
-}
/* ******** Mix Base Operation ******** */
diff --git a/source/blender/compositor/operations/COM_MovieClipAttributeOperation.cpp b/source/blender/compositor/operations/COM_MovieClipAttributeOperation.cpp
index 4f5d7f6f00b..34773a1e4f8 100644
--- a/source/blender/compositor/operations/COM_MovieClipAttributeOperation.cpp
+++ b/source/blender/compositor/operations/COM_MovieClipAttributeOperation.cpp
@@ -17,10 +17,10 @@
*/
#include "COM_MovieClipAttributeOperation.h"
-extern "C" {
+
#include "BKE_movieclip.h"
#include "BKE_tracking.h"
-}
+
MovieClipAttributeOperation::MovieClipAttributeOperation() : NodeOperation()
{
this->addOutputSocket(COM_DT_VALUE);
diff --git a/source/blender/compositor/operations/COM_MovieClipOperation.cpp b/source/blender/compositor/operations/COM_MovieClipOperation.cpp
index c5757274143..17794ae879e 100644
--- a/source/blender/compositor/operations/COM_MovieClipOperation.cpp
+++ b/source/blender/compositor/operations/COM_MovieClipOperation.cpp
@@ -20,11 +20,11 @@
#include "BLI_listbase.h"
#include "BLI_math.h"
-extern "C" {
+
+#include "BKE_image.h"
#include "BKE_movieclip.h"
+
#include "IMB_imbuf.h"
-}
-#include "BKE_image.h"
MovieClipBaseOperation::MovieClipBaseOperation() : NodeOperation()
{
diff --git a/source/blender/compositor/operations/COM_MovieDistortionOperation.cpp b/source/blender/compositor/operations/COM_MovieDistortionOperation.cpp
index ec858ee2c19..67491d51547 100644
--- a/source/blender/compositor/operations/COM_MovieDistortionOperation.cpp
+++ b/source/blender/compositor/operations/COM_MovieDistortionOperation.cpp
@@ -18,11 +18,10 @@
#include "COM_MovieDistortionOperation.h"
-extern "C" {
#include "BKE_movieclip.h"
#include "BKE_tracking.h"
+
#include "BLI_linklist.h"
-}
MovieDistortionOperation::MovieDistortionOperation(bool distortion) : NodeOperation()
{
@@ -50,7 +49,8 @@ void MovieDistortionOperation::initExecution()
full_frame.xmin = full_frame.ymin = 0;
full_frame.xmax = this->m_width;
full_frame.ymax = this->m_height;
- BKE_tracking_max_distortion_delta_across_bound(tracking, &full_frame, !this->m_apply, delta);
+ BKE_tracking_max_distortion_delta_across_bound(
+ tracking, this->m_width, this->m_height, &full_frame, !this->m_apply, delta);
/* 5 is just in case we didn't hit real max of distortion in
* BKE_tracking_max_undistortion_delta_across_bound
diff --git a/source/blender/compositor/operations/COM_MovieDistortionOperation.h b/source/blender/compositor/operations/COM_MovieDistortionOperation.h
index 3ca9fe16b1e..799c6385a10 100644
--- a/source/blender/compositor/operations/COM_MovieDistortionOperation.h
+++ b/source/blender/compositor/operations/COM_MovieDistortionOperation.h
@@ -23,9 +23,7 @@
#include "DNA_movieclip_types.h"
#include "MEM_guardedalloc.h"
-extern "C" {
#include "BKE_tracking.h"
-}
class MovieDistortionOperation : public NodeOperation {
private:
diff --git a/source/blender/compositor/operations/COM_MultilayerImageOperation.cpp b/source/blender/compositor/operations/COM_MultilayerImageOperation.cpp
index 9876c319944..8878b05ade7 100644
--- a/source/blender/compositor/operations/COM_MultilayerImageOperation.cpp
+++ b/source/blender/compositor/operations/COM_MultilayerImageOperation.cpp
@@ -17,10 +17,9 @@
*/
#include "COM_MultilayerImageOperation.h"
-extern "C" {
+
#include "IMB_imbuf.h"
#include "IMB_imbuf_types.h"
-}
MultilayerBaseOperation::MultilayerBaseOperation(int passindex, int view) : BaseImageOperation()
{
diff --git a/source/blender/compositor/operations/COM_OutputFileMultiViewOperation.cpp b/source/blender/compositor/operations/COM_OutputFileMultiViewOperation.cpp
index 65f4eeeb8bb..c0fe7237687 100644
--- a/source/blender/compositor/operations/COM_OutputFileMultiViewOperation.cpp
+++ b/source/blender/compositor/operations/COM_OutputFileMultiViewOperation.cpp
@@ -33,11 +33,9 @@
#include "DNA_color_types.h"
#include "MEM_guardedalloc.h"
-extern "C" {
#include "IMB_colormanagement.h"
#include "IMB_imbuf.h"
#include "IMB_imbuf_types.h"
-}
/************************************ OpenEXR Singlelayer Multiview ******************************/
diff --git a/source/blender/compositor/operations/COM_OutputFileOperation.cpp b/source/blender/compositor/operations/COM_OutputFileOperation.cpp
index efe01d0b5cc..ee3779edcb4 100644
--- a/source/blender/compositor/operations/COM_OutputFileOperation.cpp
+++ b/source/blender/compositor/operations/COM_OutputFileOperation.cpp
@@ -32,11 +32,9 @@
#include "DNA_color_types.h"
#include "MEM_guardedalloc.h"
-extern "C" {
#include "IMB_colormanagement.h"
#include "IMB_imbuf.h"
#include "IMB_imbuf_types.h"
-}
void add_exr_channels(void *exrhandle,
const char *layerName,
diff --git a/source/blender/compositor/operations/COM_PlaneCornerPinOperation.cpp b/source/blender/compositor/operations/COM_PlaneCornerPinOperation.cpp
index 676601d82da..eae576ceb56 100644
--- a/source/blender/compositor/operations/COM_PlaneCornerPinOperation.cpp
+++ b/source/blender/compositor/operations/COM_PlaneCornerPinOperation.cpp
@@ -24,9 +24,7 @@
#include "BLI_math.h"
#include "BLI_math_color.h"
-extern "C" {
#include "BKE_node.h"
-}
static bool check_corners(float corners[4][2])
{
diff --git a/source/blender/compositor/operations/COM_PlaneDistortCommonOperation.cpp b/source/blender/compositor/operations/COM_PlaneDistortCommonOperation.cpp
index 07053d01d43..e7574e80c2f 100644
--- a/source/blender/compositor/operations/COM_PlaneDistortCommonOperation.cpp
+++ b/source/blender/compositor/operations/COM_PlaneDistortCommonOperation.cpp
@@ -20,7 +20,6 @@
#include "MEM_guardedalloc.h"
-extern "C" {
#include "BLI_jitter_2d.h"
#include "BLI_listbase.h"
#include "BLI_math.h"
@@ -29,7 +28,6 @@ extern "C" {
#include "BKE_movieclip.h"
#include "BKE_node.h"
#include "BKE_tracking.h"
-}
/* ******** PlaneDistort WarpImage ******** */
diff --git a/source/blender/compositor/operations/COM_PlaneTrackOperation.cpp b/source/blender/compositor/operations/COM_PlaneTrackOperation.cpp
index cbf5a25fa31..ed9a776d0a3 100644
--- a/source/blender/compositor/operations/COM_PlaneTrackOperation.cpp
+++ b/source/blender/compositor/operations/COM_PlaneTrackOperation.cpp
@@ -25,11 +25,9 @@
#include "BLI_math.h"
#include "BLI_math_color.h"
-extern "C" {
#include "BKE_movieclip.h"
#include "BKE_node.h"
#include "BKE_tracking.h"
-}
/* ******** PlaneTrackCommon ******** */
diff --git a/source/blender/compositor/operations/COM_PreviewOperation.cpp b/source/blender/compositor/operations/COM_PreviewOperation.cpp
index e9e1b4a8cd9..30fe2ca824d 100644
--- a/source/blender/compositor/operations/COM_PreviewOperation.cpp
+++ b/source/blender/compositor/operations/COM_PreviewOperation.cpp
@@ -27,12 +27,11 @@
#include "PIL_time.h"
#include "WM_api.h"
#include "WM_types.h"
-extern "C" {
+
#include "BKE_node.h"
#include "IMB_colormanagement.h"
#include "IMB_imbuf.h"
#include "IMB_imbuf_types.h"
-}
PreviewOperation::PreviewOperation(const ColorManagedViewSettings *viewSettings,
const ColorManagedDisplaySettings *displaySettings)
diff --git a/source/blender/compositor/operations/COM_RenderLayersProg.cpp b/source/blender/compositor/operations/COM_RenderLayersProg.cpp
index 722aab329d7..c8a68c70c4d 100644
--- a/source/blender/compositor/operations/COM_RenderLayersProg.cpp
+++ b/source/blender/compositor/operations/COM_RenderLayersProg.cpp
@@ -22,11 +22,9 @@
#include "BLI_listbase.h"
#include "DNA_scene_types.h"
-extern "C" {
#include "RE_pipeline.h"
#include "RE_render_ext.h"
#include "RE_shader_ext.h"
-}
/* ******** Render Layers Base Prog ******** */
diff --git a/source/blender/compositor/operations/COM_RenderLayersProg.h b/source/blender/compositor/operations/COM_RenderLayersProg.h
index cb47725b749..6f84eae3252 100644
--- a/source/blender/compositor/operations/COM_RenderLayersProg.h
+++ b/source/blender/compositor/operations/COM_RenderLayersProg.h
@@ -24,9 +24,8 @@
#include "COM_NodeOperation.h"
#include "DNA_scene_types.h"
#include "MEM_guardedalloc.h"
-extern "C" {
+
#include "RE_pipeline.h"
-}
/**
* Base class for all renderlayeroperations
@@ -56,7 +55,7 @@ class RenderLayersProg : public NodeOperation {
float *m_inputBuffer;
/**
- * renderpass where this operation needs to get its data from
+ * Render-pass where this operation needs to get its data from.
*/
std::string m_passName;
diff --git a/source/blender/compositor/operations/COM_ScreenLensDistortionOperation.cpp b/source/blender/compositor/operations/COM_ScreenLensDistortionOperation.cpp
index 1afc6d9477f..738c51fc719 100644
--- a/source/blender/compositor/operations/COM_ScreenLensDistortionOperation.cpp
+++ b/source/blender/compositor/operations/COM_ScreenLensDistortionOperation.cpp
@@ -18,12 +18,11 @@
#include "COM_ScreenLensDistortionOperation.h"
-extern "C" {
#include "BLI_math.h"
#include "BLI_rand.h"
#include "BLI_utildefines.h"
+
#include "PIL_time.h"
-}
ScreenLensDistortionOperation::ScreenLensDistortionOperation() : NodeOperation()
{
diff --git a/source/blender/compositor/operations/COM_SplitOperation.cpp b/source/blender/compositor/operations/COM_SplitOperation.cpp
index 1862fde2d40..3eddf033cf4 100644
--- a/source/blender/compositor/operations/COM_SplitOperation.cpp
+++ b/source/blender/compositor/operations/COM_SplitOperation.cpp
@@ -24,10 +24,8 @@
#include "BLI_utildefines.h"
#include "MEM_guardedalloc.h"
-extern "C" {
#include "IMB_imbuf.h"
#include "IMB_imbuf_types.h"
-}
SplitOperation::SplitOperation() : NodeOperation()
{
diff --git a/source/blender/compositor/operations/COM_TextureOperation.cpp b/source/blender/compositor/operations/COM_TextureOperation.cpp
index 0a27a6916b7..07316280bbc 100644
--- a/source/blender/compositor/operations/COM_TextureOperation.cpp
+++ b/source/blender/compositor/operations/COM_TextureOperation.cpp
@@ -20,13 +20,11 @@
#include "COM_WorkScheduler.h"
#include "BKE_image.h"
+#include "BKE_node.h"
+
#include "BLI_listbase.h"
#include "BLI_threads.h"
-extern "C" {
-#include "BKE_node.h"
-}
-
TextureBaseOperation::TextureBaseOperation() : NodeOperation()
{
this->addInputSocket(COM_DT_VECTOR); // offset
diff --git a/source/blender/compositor/operations/COM_TextureOperation.h b/source/blender/compositor/operations/COM_TextureOperation.h
index 0d06ac0bc27..ebfdbb6513a 100644
--- a/source/blender/compositor/operations/COM_TextureOperation.h
+++ b/source/blender/compositor/operations/COM_TextureOperation.h
@@ -23,11 +23,10 @@
#include "COM_NodeOperation.h"
#include "DNA_texture_types.h"
#include "MEM_guardedalloc.h"
-extern "C" {
+
#include "RE_pipeline.h"
#include "RE_render_ext.h"
#include "RE_shader_ext.h"
-}
/**
* Base class for all renderlayeroperations
diff --git a/source/blender/compositor/operations/COM_TonemapOperation.cpp b/source/blender/compositor/operations/COM_TonemapOperation.cpp
index 6b408a0a791..417fe8713ed 100644
--- a/source/blender/compositor/operations/COM_TonemapOperation.cpp
+++ b/source/blender/compositor/operations/COM_TonemapOperation.cpp
@@ -20,9 +20,7 @@
#include "BLI_math.h"
#include "BLI_utildefines.h"
-extern "C" {
#include "IMB_colormanagement.h"
-}
TonemapOperation::TonemapOperation() : NodeOperation()
{
diff --git a/source/blender/compositor/operations/COM_TrackPositionOperation.cpp b/source/blender/compositor/operations/COM_TrackPositionOperation.cpp
index e497d58732b..5c4f3b99f58 100644
--- a/source/blender/compositor/operations/COM_TrackPositionOperation.cpp
+++ b/source/blender/compositor/operations/COM_TrackPositionOperation.cpp
@@ -24,11 +24,9 @@
#include "BLI_math.h"
#include "BLI_math_color.h"
-extern "C" {
#include "BKE_movieclip.h"
#include "BKE_node.h"
#include "BKE_tracking.h"
-}
TrackPositionOperation::TrackPositionOperation() : NodeOperation()
{
diff --git a/source/blender/compositor/operations/COM_VariableSizeBokehBlurOperation.cpp b/source/blender/compositor/operations/COM_VariableSizeBokehBlurOperation.cpp
index 02f13effc8f..057dc553f7f 100644
--- a/source/blender/compositor/operations/COM_VariableSizeBokehBlurOperation.cpp
+++ b/source/blender/compositor/operations/COM_VariableSizeBokehBlurOperation.cpp
@@ -20,9 +20,7 @@
#include "BLI_math.h"
#include "COM_OpenCLDevice.h"
-extern "C" {
#include "RE_pipeline.h"
-}
VariableSizeBokehBlurOperation::VariableSizeBokehBlurOperation() : NodeOperation()
{
diff --git a/source/blender/compositor/operations/COM_VectorBlurOperation.cpp b/source/blender/compositor/operations/COM_VectorBlurOperation.cpp
index 83ae1a0526d..ee1bb0739b9 100644
--- a/source/blender/compositor/operations/COM_VectorBlurOperation.cpp
+++ b/source/blender/compositor/operations/COM_VectorBlurOperation.cpp
@@ -16,12 +16,13 @@
* Copyright 2011, Blender Foundation.
*/
-#include "BLI_math.h"
-#include "MEM_guardedalloc.h"
#include <string.h>
-extern "C" {
+
+#include "MEM_guardedalloc.h"
+
#include "BLI_jitter_2d.h"
-}
+#include "BLI_math.h"
+
#include "COM_VectorBlurOperation.h"
/* Defined */
@@ -569,15 +570,15 @@ void zbuf_accumulate_vecblur(NodeBlurData *nbd,
zspan.zofsy = 0.0f;
/* the buffers */
- rectz = (float *)MEM_mapallocN(sizeof(float) * xsize * ysize, "zbuf accum");
+ rectz = (float *)MEM_callocN(sizeof(float) * xsize * ysize, "zbuf accum");
zspan.rectz = (int *)rectz;
- rectmove = (char *)MEM_mapallocN(xsize * ysize, "rectmove");
- rectdraw = (DrawBufPixel *)MEM_mapallocN(sizeof(DrawBufPixel) * xsize * ysize, "rect draw");
+ rectmove = (char *)MEM_callocN(xsize * ysize, "rectmove");
+ rectdraw = (DrawBufPixel *)MEM_callocN(sizeof(DrawBufPixel) * xsize * ysize, "rect draw");
zspan.rectdraw = rectdraw;
- rectweight = (float *)MEM_mapallocN(sizeof(float) * xsize * ysize, "rect weight");
- rectmax = (float *)MEM_mapallocN(sizeof(float) * xsize * ysize, "rect max");
+ rectweight = (float *)MEM_callocN(sizeof(float) * xsize * ysize, "rect weight");
+ rectmax = (float *)MEM_callocN(sizeof(float) * xsize * ysize, "rect max");
/* debug... check if PASS_VECTOR_MAX still is in buffers */
dvec1 = vecbufrect;
@@ -596,7 +597,7 @@ void zbuf_accumulate_vecblur(NodeBlurData *nbd,
float minspeed = (float)nbd->minspeed;
float minspeedsq = minspeed * minspeed;
- minvecbufrect = (float *)MEM_mapallocN(4 * sizeof(float) * xsize * ysize, "minspeed buf");
+ minvecbufrect = (float *)MEM_callocN(4 * sizeof(float) * xsize * ysize, "minspeed buf");
dvec1 = vecbufrect;
dvec2 = minvecbufrect;
@@ -622,7 +623,7 @@ void zbuf_accumulate_vecblur(NodeBlurData *nbd,
}
/* make vertex buffer with averaged speed and zvalues */
- rectvz = (float *)MEM_mapallocN(4 * sizeof(float) * (xsize + 1) * (ysize + 1), "vertices");
+ rectvz = (float *)MEM_callocN(4 * sizeof(float) * (xsize + 1) * (ysize + 1), "vertices");
dvz = rectvz;
for (y = 0; y <= ysize; y++) {
diff --git a/source/blender/compositor/operations/COM_VectorCurveOperation.cpp b/source/blender/compositor/operations/COM_VectorCurveOperation.cpp
index 6996c7ecb71..61312355a39 100644
--- a/source/blender/compositor/operations/COM_VectorCurveOperation.cpp
+++ b/source/blender/compositor/operations/COM_VectorCurveOperation.cpp
@@ -18,13 +18,7 @@
#include "COM_VectorCurveOperation.h"
-#ifdef __cplusplus
-extern "C" {
-#endif
#include "BKE_colortools.h"
-#ifdef __cplusplus
-}
-#endif
VectorCurveOperation::VectorCurveOperation() : CurveBaseOperation()
{
diff --git a/source/blender/compositor/operations/COM_ViewerOperation.cpp b/source/blender/compositor/operations/COM_ViewerOperation.cpp
index 5c32b9962f4..fc26d6219e1 100644
--- a/source/blender/compositor/operations/COM_ViewerOperation.cpp
+++ b/source/blender/compositor/operations/COM_ViewerOperation.cpp
@@ -28,11 +28,9 @@
#include "WM_api.h"
#include "WM_types.h"
-extern "C" {
#include "IMB_colormanagement.h"
#include "IMB_imbuf.h"
#include "IMB_imbuf_types.h"
-}
ViewerOperation::ViewerOperation() : NodeOperation()
{
diff --git a/source/blender/depsgraph/DEG_depsgraph.h b/source/blender/depsgraph/DEG_depsgraph.h
index c94a8876ab0..d735d3b89bc 100644
--- a/source/blender/depsgraph/DEG_depsgraph.h
+++ b/source/blender/depsgraph/DEG_depsgraph.h
@@ -184,7 +184,7 @@ void DEG_editors_set_update_cb(DEG_EditorUpdateIDCb id_func, DEG_EditorUpdateSce
/* Evaluation ----------------------------------- */
-bool DEG_is_evaluating(struct Depsgraph *depsgraph);
+bool DEG_is_evaluating(const struct Depsgraph *depsgraph);
bool DEG_is_active(const struct Depsgraph *depsgraph);
void DEG_make_active(struct Depsgraph *depsgraph);
diff --git a/source/blender/depsgraph/DEG_depsgraph_build.h b/source/blender/depsgraph/DEG_depsgraph_build.h
index e24fa9e8996..81157102bb1 100644
--- a/source/blender/depsgraph/DEG_depsgraph_build.h
+++ b/source/blender/depsgraph/DEG_depsgraph_build.h
@@ -39,15 +39,16 @@ struct ID;
struct Main;
struct Object;
struct Scene;
+struct Simulation;
struct ViewLayer;
struct bNodeTree;
+#include "BLI_sys_types.h"
+
#ifdef __cplusplus
extern "C" {
#endif
-#include "BLI_sys_types.h"
-
/* Graph Building -------------------------------- */
/* Build depsgraph for the given scene, and dump results in given graph container. */
@@ -153,6 +154,9 @@ void DEG_add_object_relation(struct DepsNodeHandle *node_handle,
struct Object *object,
eDepsObjectComponentType component,
const char *description);
+void DEG_add_simulation_relation(struct DepsNodeHandle *node_handle,
+ struct Simulation *simulation,
+ const char *description);
void DEG_add_bone_relation(struct DepsNodeHandle *handle,
struct Object *object,
const char *bone_name,
diff --git a/source/blender/depsgraph/DEG_depsgraph_query.h b/source/blender/depsgraph/DEG_depsgraph_query.h
index 26b46376a0a..3d570536223 100644
--- a/source/blender/depsgraph/DEG_depsgraph_query.h
+++ b/source/blender/depsgraph/DEG_depsgraph_query.h
@@ -111,14 +111,14 @@ struct ID *DEG_get_original_id(struct ID *id);
*
* Original IDs are considered all the IDs which are not covered by copy-on-write system and are
* not out-of-main localized data-blocks. */
-bool DEG_is_original_id(struct ID *id);
-bool DEG_is_original_object(struct Object *object);
+bool DEG_is_original_id(const struct ID *id);
+bool DEG_is_original_object(const struct Object *object);
/* Opposite of the above.
*
* If the data-block is not original it must be evaluated, and vice versa. */
-bool DEG_is_evaluated_id(struct ID *id);
-bool DEG_is_evaluated_object(struct Object *object);
+bool DEG_is_evaluated_id(const struct ID *id);
+bool DEG_is_evaluated_object(const struct Object *object);
/* Check whether depsgraph os fully evaluated. This includes the following checks:
* - Relations are up-to-date.
diff --git a/source/blender/depsgraph/intern/builder/deg_builder.cc b/source/blender/depsgraph/intern/builder/deg_builder.cc
index 18ab9bf7e43..82f3ea7d182 100644
--- a/source/blender/depsgraph/intern/builder/deg_builder.cc
+++ b/source/blender/depsgraph/intern/builder/deg_builder.cc
@@ -31,16 +31,11 @@
#include "DNA_layer_types.h"
#include "DNA_object_types.h"
-#include "BLI_ghash.h"
#include "BLI_stack.h"
#include "BLI_utildefines.h"
#include "BKE_action.h"
-extern "C" {
-#include "BKE_animsys.h"
-}
-
#include "intern/builder/deg_builder_cache.h"
#include "intern/builder/deg_builder_remove_noop.h"
#include "intern/depsgraph.h"
@@ -161,10 +156,9 @@ void deg_graph_build_flush_visibility(Depsgraph *graph)
BLI_Stack *stack = BLI_stack_new(sizeof(OperationNode *), "DEG flush layers stack");
for (IDNode *id_node : graph->id_nodes) {
- GHASH_FOREACH_BEGIN (ComponentNode *, comp_node, id_node->components) {
+ for (ComponentNode *comp_node : id_node->components.values()) {
comp_node->affects_directly_visible |= id_node->is_directly_visible;
}
- GHASH_FOREACH_END();
}
for (OperationNode *op_node : graph->operations) {
op_node->custom_flags = 0;
diff --git a/source/blender/depsgraph/intern/builder/deg_builder_cache.cc b/source/blender/depsgraph/intern/builder/deg_builder_cache.cc
index fe1886c67e8..ba0238b43c7 100644
--- a/source/blender/depsgraph/intern/builder/deg_builder_cache.cc
+++ b/source/blender/depsgraph/intern/builder/deg_builder_cache.cc
@@ -29,9 +29,7 @@
#include "BLI_utildefines.h"
-extern "C" {
#include "BKE_animsys.h"
-}
namespace DEG {
diff --git a/source/blender/depsgraph/intern/builder/deg_builder_nodes.cc b/source/blender/depsgraph/intern/builder/deg_builder_nodes.cc
index f2108b3ad6c..9230fa19c32 100644
--- a/source/blender/depsgraph/intern/builder/deg_builder_nodes.cc
+++ b/source/blender/depsgraph/intern/builder/deg_builder_nodes.cc
@@ -34,7 +34,6 @@
#include "BLI_string.h"
#include "BLI_utildefines.h"
-extern "C" {
#include "DNA_action_types.h"
#include "DNA_anim_types.h"
#include "DNA_armature_types.h"
@@ -60,12 +59,14 @@ extern "C" {
#include "DNA_rigidbody_types.h"
#include "DNA_scene_types.h"
#include "DNA_sequence_types.h"
+#include "DNA_simulation_types.h"
#include "DNA_sound_types.h"
#include "DNA_speaker_types.h"
#include "DNA_texture_types.h"
#include "DNA_world_types.h"
#include "BKE_action.h"
+#include "BKE_anim_data.h"
#include "BKE_animsys.h"
#include "BKE_armature.h"
#include "BKE_cachefile.h"
@@ -73,14 +74,16 @@ extern "C" {
#include "BKE_constraint.h"
#include "BKE_curve.h"
#include "BKE_effect.h"
-#include "BKE_fcurve.h"
+#include "BKE_fcurve_driver.h"
#include "BKE_gpencil.h"
#include "BKE_gpencil_modifier.h"
+#include "BKE_idprop.h"
#include "BKE_idtype.h"
#include "BKE_image.h"
#include "BKE_key.h"
#include "BKE_lattice.h"
#include "BKE_layer.h"
+#include "BKE_light.h"
#include "BKE_mask.h"
#include "BKE_material.h"
#include "BKE_mball.h"
@@ -95,6 +98,7 @@ extern "C" {
#include "BKE_scene.h"
#include "BKE_sequencer.h"
#include "BKE_shader_fx.h"
+#include "BKE_simulation.h"
#include "BKE_sound.h"
#include "BKE_tracking.h"
#include "BKE_volume.h"
@@ -102,7 +106,6 @@ extern "C" {
#include "RNA_access.h"
#include "RNA_types.h"
-} /* extern "C" */
#include "DEG_depsgraph.h"
#include "DEG_depsgraph_build.h"
@@ -118,20 +121,6 @@ extern "C" {
namespace DEG {
-namespace {
-
-void free_copy_on_write_datablock(void *id_info_v)
-{
- DepsgraphNodeBuilder::IDInfo *id_info = (DepsgraphNodeBuilder::IDInfo *)id_info_v;
- if (id_info->id_cow != nullptr) {
- deg_free_copy_on_write_datablock(id_info->id_cow);
- MEM_freeN(id_info->id_cow);
- }
- MEM_freeN(id_info);
-}
-
-} /* namespace */
-
/* ************ */
/* Node Builder */
@@ -145,15 +134,18 @@ DepsgraphNodeBuilder::DepsgraphNodeBuilder(Main *bmain,
view_layer_(nullptr),
view_layer_index_(-1),
collection_(nullptr),
- is_parent_collection_visible_(true),
- id_info_hash_(nullptr)
+ is_parent_collection_visible_(true)
{
}
DepsgraphNodeBuilder::~DepsgraphNodeBuilder()
{
- if (id_info_hash_ != nullptr) {
- BLI_ghash_free(id_info_hash_, nullptr, free_copy_on_write_datablock);
+ for (IDInfo *id_info : id_info_hash_.values()) {
+ if (id_info->id_cow != nullptr) {
+ deg_free_copy_on_write_datablock(id_info->id_cow);
+ MEM_freeN(id_info->id_cow);
+ }
+ MEM_freeN(id_info);
}
}
@@ -164,7 +156,7 @@ IDNode *DepsgraphNodeBuilder::add_id_node(ID *id)
IDComponentsMask previously_visible_components_mask = 0;
uint32_t previous_eval_flags = 0;
DEGCustomDataMeshMasks previous_customdata_masks;
- IDInfo *id_info = (IDInfo *)BLI_ghash_lookup(id_info_hash_, id);
+ IDInfo *id_info = id_info_hash_.lookup_default(id, nullptr);
if (id_info != nullptr) {
id_cow = id_info->id_cow;
previously_visible_components_mask = id_info->previously_visible_components_mask;
@@ -180,7 +172,7 @@ IDNode *DepsgraphNodeBuilder::add_id_node(ID *id)
/* Currently all ID nodes are supposed to have copy-on-write logic.
*
* NOTE: Zero number of components indicates that ID node was just created. */
- if (BLI_ghash_len(id_node->components) == 0) {
+ if (id_node->components.is_empty()) {
ComponentNode *comp_cow = id_node->add_component(NodeType::COPY_ON_WRITE);
OperationNode *op_cow = comp_cow->add_operation(
function_bind(deg_evaluate_copy_on_write, _1, id_node),
@@ -318,7 +310,6 @@ void DepsgraphNodeBuilder::begin_build()
{
/* Store existing copy-on-write versions of datablock, so we can re-use
* them for new ID nodes. */
- id_info_hash_ = BLI_ghash_ptr_new("Depsgraph id hash");
for (IDNode *id_node : graph_->id_nodes) {
/* It is possible that the ID does not need to have CoW version in which case id_cow is the
* same as id_orig. Additionally, such ID might have been removed, which makes the check
@@ -342,11 +333,11 @@ void DepsgraphNodeBuilder::begin_build()
id_info->previously_visible_components_mask = id_node->visible_components_mask;
id_info->previous_eval_flags = id_node->eval_flags;
id_info->previous_customdata_masks = id_node->customdata_masks;
- BLI_ghash_insert(id_info_hash_, id_node->id_orig, id_info);
+ id_info_hash_.add_new(id_node->id_orig, id_info);
id_node->id_cow = nullptr;
}
- GSET_FOREACH_BEGIN (OperationNode *, op_node, graph_->entry_tags) {
+ for (OperationNode *op_node : graph_->entry_tags) {
ComponentNode *comp_node = op_node->owner;
IDNode *id_node = comp_node->owner;
@@ -358,12 +349,11 @@ void DepsgraphNodeBuilder::begin_build()
entry_tag.name_tag = op_node->name_tag;
saved_entry_tags_.push_back(entry_tag);
}
- GSET_FOREACH_END();
/* Make sure graph has no nodes left from previous state. */
graph_->clear_all_nodes();
graph_->operations.clear();
- BLI_gset_clear(graph_->entry_tags, nullptr);
+ graph_->entry_tags.clear();
}
void DepsgraphNodeBuilder::end_build()
@@ -480,6 +470,9 @@ void DepsgraphNodeBuilder::build_id(ID *id)
case ID_SCE:
build_scene_parameters((Scene *)id);
break;
+ case ID_SIM:
+ build_simulation((Simulation *)id);
+ break;
default:
fprintf(stderr, "Unhandled ID %s\n", id->name);
BLI_assert(!"Should never happen");
@@ -487,6 +480,18 @@ void DepsgraphNodeBuilder::build_id(ID *id)
}
}
+static void build_idproperties_callback(IDProperty *id_property, void *user_data)
+{
+ DepsgraphNodeBuilder *builder = reinterpret_cast<DepsgraphNodeBuilder *>(user_data);
+ BLI_assert(id_property->type == IDP_ID);
+ builder->build_id(reinterpret_cast<ID *>(id_property->data.pointer));
+}
+
+void DepsgraphNodeBuilder::build_idproperties(IDProperty *id_property)
+{
+ IDP_foreach_property(id_property, IDP_TYPE_FILTER_ID, build_idproperties_callback, this);
+}
+
void DepsgraphNodeBuilder::build_collection(LayerCollection *from_layer_collection,
Collection *collection)
{
@@ -505,8 +510,7 @@ void DepsgraphNodeBuilder::build_collection(LayerCollection *from_layer_collecti
}
else if (from_layer_collection == nullptr && !id_node->is_collection_fully_expanded) {
/* Initially collection was built from layer now, and was requested
- * to not recurs into object. But nw it's asked to recurs into all
- * objects. */
+ * to not recurs into object. But now it's asked to recurs into all objects. */
}
else {
return;
@@ -516,6 +520,8 @@ void DepsgraphNodeBuilder::build_collection(LayerCollection *from_layer_collecti
/* Collection itself. */
id_node = add_id_node(&collection->id);
id_node->is_directly_visible = is_collection_visible;
+
+ build_idproperties(collection->id.properties);
}
if (from_layer_collection != nullptr) {
/* If we came from layer collection we don't go deeper, view layer
@@ -600,21 +606,21 @@ void DepsgraphNodeBuilder::build_object(int base_index,
BuilderWalkUserData data;
data.builder = this;
data.is_parent_visible = is_visible;
- modifiers_foreachIDLink(object, modifier_walk, &data);
+ BKE_modifiers_foreach_ID_link(object, modifier_walk, &data);
}
/* Grease Pencil Modifiers. */
if (object->greasepencil_modifiers.first != nullptr) {
BuilderWalkUserData data;
data.builder = this;
data.is_parent_visible = is_visible;
- BKE_gpencil_modifiers_foreachIDLink(object, modifier_walk, &data);
+ BKE_gpencil_modifiers_foreach_ID_link(object, modifier_walk, &data);
}
/* Shader FX. */
if (object->shader_fx.first != nullptr) {
BuilderWalkUserData data;
data.builder = this;
data.is_parent_visible = is_visible;
- BKE_shaderfx_foreachIDLink(object, modifier_walk, &data);
+ BKE_shaderfx_foreach_ID_link(object, modifier_walk, &data);
}
/* Constraints. */
if (object->constraints.first != nullptr) {
@@ -628,6 +634,7 @@ void DepsgraphNodeBuilder::build_object(int base_index,
/* Parameters, used by both drivers/animation and also to inform dependency
* from object's data. */
build_parameters(&object->id);
+ build_idproperties(object->id.properties);
/* Build animation data,
*
* Do it now because it's possible object data will affect
@@ -652,7 +659,7 @@ void DepsgraphNodeBuilder::build_object(int base_index,
add_operation_node(&object->id,
NodeType::SYNCHRONIZATION,
OperationCode::SYNCHRONIZE_TO_ORIGINAL,
- function_bind(BKE_object_synchronize_to_original, _1, object_cow));
+ function_bind(BKE_object_sync_to_original, _1, object_cow));
}
void DepsgraphNodeBuilder::build_object_flags(int base_index,
@@ -942,6 +949,7 @@ void DepsgraphNodeBuilder::build_action(bAction *action)
if (built_map_.checkIsBuiltAndTag(action)) {
return;
}
+ build_idproperties(action->id.properties);
add_operation_node(&action->id, NodeType::ANIMATION, OperationCode::ANIMATION_EVAL);
}
@@ -1047,6 +1055,7 @@ void DepsgraphNodeBuilder::build_world(World *world)
NodeType::SHADING,
OperationCode::WORLD_UPDATE,
function_bind(BKE_world_eval, _1, world_cow));
+ build_idproperties(world->id.properties);
/* Animation. */
build_animdata(&world->id);
build_parameters(&world->id);
@@ -1142,8 +1151,8 @@ void DepsgraphNodeBuilder::build_particle_systems(Object *object, bool is_object
* evaluation context for an object. It acts as the container
* for all the nodes associated with a particular set of particle
* systems.
- * 2) Particle System Eval Operation - This operation node acts as a
- * blackbox evaluation step for one particle system referenced by
+ * 2) Particle System Evaluation Operation - This operation node acts as a
+ * black-box evaluation step for one particle system referenced by
* the particle systems stack. All dependencies link to this operation. */
/* Component for all particle systems. */
ComponentNode *psys_comp = add_component_node(&object->id, NodeType::PARTICLE_SYSTEM);
@@ -1164,7 +1173,7 @@ void DepsgraphNodeBuilder::build_particle_systems(Object *object, bool is_object
/* Particle system evaluation. */
add_operation_node(psys_comp, OperationCode::PARTICLE_SYSTEM_EVAL, nullptr, psys->name);
/* Keyed particle targets. */
- if (part->phystype == PART_PHYS_KEYED) {
+ if (ELEM(part->phystype, PART_PHYS_KEYED, PART_PHYS_BOIDS)) {
LISTBASE_FOREACH (ParticleTarget *, particle_target, &psys->targets) {
if (particle_target->ob == nullptr || particle_target->ob == object) {
continue;
@@ -1229,6 +1238,7 @@ void DepsgraphNodeBuilder::build_shapekeys(Key *key)
if (built_map_.checkIsBuiltAndTag(key)) {
return;
}
+ build_idproperties(key->id.properties);
build_animdata(&key->id);
build_parameters(&key->id);
/* This is an exit operation for the entire key datablock, is what is used
@@ -1283,6 +1293,7 @@ void DepsgraphNodeBuilder::build_object_data_geometry_datablock(ID *obdata, bool
/* Make sure we've got an ID node before requesting CoW pointer. */
(void)add_id_node((ID *)obdata);
ID *obdata_cow = get_cow_id(obdata);
+ build_idproperties(obdata->properties);
/* Animation. */
build_animdata(obdata);
/* ShapeKeys */
@@ -1388,10 +1399,24 @@ void DepsgraphNodeBuilder::build_armature(bArmature *armature)
if (built_map_.checkIsBuiltAndTag(armature)) {
return;
}
+ build_idproperties(armature->id.properties);
build_animdata(&armature->id);
build_parameters(&armature->id);
/* Make sure pose is up-to-date with armature updates. */
- add_operation_node(&armature->id, NodeType::ARMATURE, OperationCode::ARMATURE_EVAL);
+ bArmature *armature_cow = (bArmature *)get_cow_id(&armature->id);
+ add_operation_node(&armature->id,
+ NodeType::ARMATURE,
+ OperationCode::ARMATURE_EVAL,
+ function_bind(BKE_armature_refresh_layer_used, _1, armature_cow));
+ build_armature_bones(&armature->bonebase);
+}
+
+void DepsgraphNodeBuilder::build_armature_bones(ListBase *bones)
+{
+ LISTBASE_FOREACH (Bone *, bone, bones) {
+ build_idproperties(bone->prop);
+ build_armature_bones(&bone->childbase);
+ }
}
void DepsgraphNodeBuilder::build_camera(Camera *camera)
@@ -1399,6 +1424,7 @@ void DepsgraphNodeBuilder::build_camera(Camera *camera)
if (built_map_.checkIsBuiltAndTag(camera)) {
return;
}
+ build_idproperties(camera->id.properties);
build_animdata(&camera->id);
build_parameters(&camera->id);
if (camera->dof.focus_object != nullptr) {
@@ -1411,10 +1437,17 @@ void DepsgraphNodeBuilder::build_light(Light *lamp)
if (built_map_.checkIsBuiltAndTag(lamp)) {
return;
}
+ build_idproperties(lamp->id.properties);
build_animdata(&lamp->id);
build_parameters(&lamp->id);
/* light's nodetree */
build_nodetree(lamp->nodetree);
+
+ Light *lamp_cow = get_cow_datablock(lamp);
+ add_operation_node(&lamp->id,
+ NodeType::SHADING,
+ OperationCode::LIGHT_UPDATE,
+ function_bind(BKE_light_eval, _1, lamp_cow));
}
void DepsgraphNodeBuilder::build_nodetree(bNodeTree *ntree)
@@ -1430,6 +1463,7 @@ void DepsgraphNodeBuilder::build_nodetree(bNodeTree *ntree)
bNodeTree *ntree_cow = get_cow_datablock(ntree);
/* General parameters. */
build_parameters(&ntree->id);
+ build_idproperties(ntree->id.properties);
/* Animation, */
build_animdata(&ntree->id);
/* Shading update. */
@@ -1442,6 +1476,14 @@ void DepsgraphNodeBuilder::build_nodetree(bNodeTree *ntree)
function_bind(BKE_nodetree_shading_params_eval, _1, ntree_cow, ntree));
/* nodetree's nodes... */
LISTBASE_FOREACH (bNode *, bnode, &ntree->nodes) {
+ build_idproperties(bnode->prop);
+ LISTBASE_FOREACH (bNodeSocket *, socket, &bnode->inputs) {
+ build_idproperties(socket->prop);
+ }
+ LISTBASE_FOREACH (bNodeSocket *, socket, &bnode->outputs) {
+ build_idproperties(socket->prop);
+ }
+
ID *id = bnode->id;
if (id == nullptr) {
continue;
@@ -1490,6 +1532,13 @@ void DepsgraphNodeBuilder::build_nodetree(bNodeTree *ntree)
}
}
+ LISTBASE_FOREACH (bNodeSocket *, socket, &ntree->inputs) {
+ build_idproperties(socket->prop);
+ }
+ LISTBASE_FOREACH (bNodeSocket *, socket, &ntree->outputs) {
+ build_idproperties(socket->prop);
+ }
+
// TODO: link from nodetree to owner_component?
}
@@ -1507,6 +1556,7 @@ void DepsgraphNodeBuilder::build_material(Material *material)
NodeType::SHADING,
OperationCode::MATERIAL_UPDATE,
function_bind(BKE_material_eval, _1, material_cow));
+ build_idproperties(material->id.properties);
/* Material animation. */
build_animdata(&material->id);
build_parameters(&material->id);
@@ -1531,6 +1581,8 @@ void DepsgraphNodeBuilder::build_texture(Tex *texture)
return;
}
/* Texture itself. */
+ add_id_node(&texture->id);
+ build_idproperties(texture->id.properties);
build_animdata(&texture->id);
build_parameters(&texture->id);
/* Texture's nodetree. */
@@ -1551,6 +1603,7 @@ void DepsgraphNodeBuilder::build_image(Image *image)
return;
}
build_parameters(&image->id);
+ build_idproperties(image->id.properties);
add_operation_node(
&image->id, NodeType::GENERIC_DATABLOCK, OperationCode::GENERIC_DATABLOCK_UPDATE);
}
@@ -1579,6 +1632,7 @@ void DepsgraphNodeBuilder::build_cachefile(CacheFile *cache_file)
ID *cache_file_id = &cache_file->id;
add_id_node(cache_file_id);
CacheFile *cache_file_cow = get_cow_datablock(cache_file);
+ build_idproperties(cache_file_id->properties);
/* Animation, */
build_animdata(cache_file_id);
build_parameters(cache_file_id);
@@ -1596,6 +1650,7 @@ void DepsgraphNodeBuilder::build_mask(Mask *mask)
}
ID *mask_id = &mask->id;
Mask *mask_cow = (Mask *)ensure_cow_id(mask_id);
+ build_idproperties(mask->id.properties);
/* F-Curve based animation. */
build_animdata(mask_id);
build_parameters(mask_id);
@@ -1632,6 +1687,7 @@ void DepsgraphNodeBuilder::build_freestyle_linestyle(FreestyleLineStyle *linesty
ID *linestyle_id = &linestyle->id;
build_parameters(linestyle_id);
+ build_idproperties(linestyle->id.properties);
build_animdata(linestyle_id);
build_nodetree(linestyle->nodetree);
}
@@ -1643,6 +1699,7 @@ void DepsgraphNodeBuilder::build_movieclip(MovieClip *clip)
}
ID *clip_id = &clip->id;
MovieClip *clip_cow = (MovieClip *)ensure_cow_id(clip_id);
+ build_idproperties(clip_id->properties);
/* Animation. */
build_animdata(clip_id);
build_parameters(clip_id);
@@ -1665,6 +1722,7 @@ void DepsgraphNodeBuilder::build_lightprobe(LightProbe *probe)
}
/* Placeholder so we can add relations and tag ID node for update. */
add_operation_node(&probe->id, NodeType::PARAMETERS, OperationCode::LIGHT_PROBE_EVAL);
+ build_idproperties(probe->id.properties);
build_animdata(&probe->id);
build_parameters(&probe->id);
}
@@ -1676,6 +1734,7 @@ void DepsgraphNodeBuilder::build_speaker(Speaker *speaker)
}
/* Placeholder so we can add relations and tag ID node for update. */
add_operation_node(&speaker->id, NodeType::AUDIO, OperationCode::SPEAKER_EVAL);
+ build_idproperties(speaker->id.properties);
build_animdata(&speaker->id);
build_parameters(&speaker->id);
if (speaker->sound != nullptr) {
@@ -1694,10 +1753,29 @@ void DepsgraphNodeBuilder::build_sound(bSound *sound)
NodeType::AUDIO,
OperationCode::SOUND_EVAL,
function_bind(BKE_sound_evaluate, _1, bmain_, sound_cow));
+ build_idproperties(sound->id.properties);
build_animdata(&sound->id);
build_parameters(&sound->id);
}
+void DepsgraphNodeBuilder::build_simulation(Simulation *simulation)
+{
+ if (built_map_.checkIsBuiltAndTag(simulation)) {
+ return;
+ }
+ add_id_node(&simulation->id);
+ build_animdata(&simulation->id);
+ build_parameters(&simulation->id);
+
+ Simulation *simulation_cow = get_cow_datablock(simulation);
+ Scene *scene_cow = get_cow_datablock(scene_);
+
+ add_operation_node(&simulation->id,
+ NodeType::SIMULATION,
+ OperationCode::SIMULATION_EVAL,
+ function_bind(BKE_simulation_data_update, _1, scene_cow, simulation_cow));
+}
+
void DepsgraphNodeBuilder::build_scene_sequencer(Scene *scene)
{
if (scene->ed == nullptr) {
@@ -1712,6 +1790,7 @@ void DepsgraphNodeBuilder::build_scene_sequencer(Scene *scene)
/* Make sure data for sequences is in the graph. */
Sequence *seq;
SEQ_BEGIN (scene->ed, seq) {
+ build_idproperties(seq->prop);
if (seq->sound != nullptr) {
build_sound(seq->sound);
}
@@ -1735,7 +1814,14 @@ void DepsgraphNodeBuilder::build_scene_audio(Scene *scene)
if (built_map_.checkIsBuiltAndTag(scene, BuilderMap::TAG_SCENE_AUDIO)) {
return;
}
+
add_operation_node(&scene->id, NodeType::AUDIO, OperationCode::SOUND_EVAL);
+
+ Scene *scene_cow = get_cow_datablock(scene);
+ add_operation_node(&scene->id,
+ NodeType::AUDIO,
+ OperationCode::AUDIO_VOLUME,
+ function_bind(BKE_scene_update_tag_audio_volume, _1, scene_cow));
}
void DepsgraphNodeBuilder::build_scene_speakers(Scene * /*scene*/, ViewLayer *view_layer)
diff --git a/source/blender/depsgraph/intern/builder/deg_builder_nodes.h b/source/blender/depsgraph/intern/builder/deg_builder_nodes.h
index 7fcc8b431e7..5cd7f7449a2 100644
--- a/source/blender/depsgraph/intern/builder/deg_builder_nodes.h
+++ b/source/blender/depsgraph/intern/builder/deg_builder_nodes.h
@@ -37,8 +37,8 @@ struct Collection;
struct FCurve;
struct FreestyleLineSet;
struct FreestyleLineStyle;
-struct GHash;
struct ID;
+struct IDProperty;
struct Image;
struct Key;
struct LayerCollection;
@@ -52,6 +52,7 @@ struct MovieClip;
struct Object;
struct ParticleSettings;
struct Scene;
+struct Simulation;
struct Speaker;
struct Tex;
struct World;
@@ -149,6 +150,8 @@ class DepsgraphNodeBuilder : public DepsgraphBuilder {
virtual void build_id(ID *id);
+ virtual void build_idproperties(IDProperty *id_property);
+
virtual void build_scene_render(Scene *scene, ViewLayer *view_layer);
virtual void build_scene_parameters(Scene *scene);
virtual void build_scene_compositor(Scene *scene);
@@ -199,6 +202,7 @@ class DepsgraphNodeBuilder : public DepsgraphBuilder {
virtual void build_rig(Object *object, bool is_object_visible);
virtual void build_proxy_rig(Object *object);
virtual void build_armature(bArmature *armature);
+ virtual void build_armature_bones(ListBase *bones);
virtual void build_shapekeys(Key *key);
virtual void build_camera(Camera *camera);
virtual void build_light(Light *lamp);
@@ -217,6 +221,7 @@ class DepsgraphNodeBuilder : public DepsgraphBuilder {
virtual void build_lightprobe(LightProbe *probe);
virtual void build_speaker(Speaker *speaker);
virtual void build_sound(bSound *sound);
+ virtual void build_simulation(Simulation *simulation);
virtual void build_scene_sequencer(Scene *scene);
virtual void build_scene_audio(Scene *scene);
virtual void build_scene_speakers(Scene *scene, ViewLayer *view_layer);
@@ -275,7 +280,7 @@ class DepsgraphNodeBuilder : public DepsgraphBuilder {
bool is_parent_collection_visible_;
/* Indexed by original ID, values are IDInfo. */
- GHash *id_info_hash_;
+ Map<const ID *, IDInfo *> id_info_hash_;
/* Set of IDs which were already build. Makes it easier to keep track of
* what was already built and what was not. */
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 5383e26bbd4..ab0a5c13321 100644
--- a/source/blender/depsgraph/intern/builder/deg_builder_nodes_rig.cc
+++ b/source/blender/depsgraph/intern/builder/deg_builder_nodes_rig.cc
@@ -34,7 +34,6 @@
#include "BLI_string.h"
#include "BLI_utildefines.h"
-extern "C" {
#include "DNA_anim_types.h"
#include "DNA_armature_types.h"
#include "DNA_constraint_types.h"
@@ -44,7 +43,6 @@ extern "C" {
#include "BKE_action.h"
#include "BKE_armature.h"
#include "BKE_constraint.h"
-} /* extern "C" */
#include "DEG_depsgraph.h"
#include "DEG_depsgraph_build.h"
@@ -143,8 +141,7 @@ void DepsgraphNodeBuilder::build_rig(Object *object, bool is_object_visible)
Scene *scene_cow = get_cow_datablock(scene_);
Object *object_cow = get_cow_datablock(object);
OperationNode *op_node;
- /* Animation and/or drivers linking posebones to base-armature used to
- * define them.
+ /* Animation and/or drivers linking pose-bones to base-armature used to define them.
*
* NOTE: AnimData here is really used to control animated deform properties,
* which ideally should be able to be unique across different
@@ -244,6 +241,7 @@ void DepsgraphNodeBuilder::build_rig(Object *object, bool is_object_visible)
/* Custom properties. */
if (pchan->prop != nullptr) {
+ build_idproperties(pchan->prop);
add_operation_node(
&object->id, NodeType::PARAMETERS, OperationCode::PARAMETERS_EVAL, nullptr, pchan->name);
}
@@ -323,6 +321,7 @@ void DepsgraphNodeBuilder::build_proxy_rig(Object *object)
/* Custom properties. */
if (pchan->prop != nullptr) {
+ build_idproperties(pchan->prop);
add_operation_node(
&object->id, NodeType::PARAMETERS, OperationCode::PARAMETERS_EVAL, nullptr, pchan->name);
}
diff --git a/source/blender/depsgraph/intern/builder/deg_builder_nodes_scene.cc b/source/blender/depsgraph/intern/builder/deg_builder_nodes_scene.cc
index 1edf9826208..60e843f9124 100644
--- a/source/blender/depsgraph/intern/builder/deg_builder_nodes_scene.cc
+++ b/source/blender/depsgraph/intern/builder/deg_builder_nodes_scene.cc
@@ -57,6 +57,7 @@ void DepsgraphNodeBuilder::build_scene_parameters(Scene *scene)
return;
}
build_parameters(&scene->id);
+ build_idproperties(scene->id.properties);
add_operation_node(&scene->id, NodeType::PARAMETERS, OperationCode::SCENE_EVAL);
/* NOTE: This is a bit overkill and can potentially pull a bit too much into the graph, but:
*
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 1aa3c5bf613..58cfb36b4ab 100644
--- a/source/blender/depsgraph/intern/builder/deg_builder_nodes_view_layer.cc
+++ b/source/blender/depsgraph/intern/builder/deg_builder_nodes_view_layer.cc
@@ -34,7 +34,6 @@
#include "BLI_string.h"
#include "BLI_utildefines.h"
-extern "C" {
#include "DNA_freestyle_types.h"
#include "DNA_layer_types.h"
#include "DNA_linestyle_types.h"
@@ -45,7 +44,6 @@ extern "C" {
#include "BKE_layer.h"
#include "BKE_main.h"
#include "BKE_node.h"
-} /* extern "C" */
#include "DEG_depsgraph.h"
#include "DEG_depsgraph_build.h"
diff --git a/source/blender/depsgraph/intern/builder/deg_builder_pchanmap.cc b/source/blender/depsgraph/intern/builder/deg_builder_pchanmap.cc
index ecacfcf7ee9..a0179181866 100644
--- a/source/blender/depsgraph/intern/builder/deg_builder_pchanmap.cc
+++ b/source/blender/depsgraph/intern/builder/deg_builder_pchanmap.cc
@@ -26,104 +26,55 @@
#include <stdio.h>
#include <string.h>
-#include "BLI_ghash.h"
#include "BLI_utildefines.h"
namespace DEG {
-static void free_rootpchanmap_valueset(void *val)
-{
- /* Just need to free the set itself - the names stored are all references. */
- GSet *values = (GSet *)val;
- BLI_gset_free(values, nullptr);
-}
-
RootPChanMap::RootPChanMap()
{
- /* Just create empty map. */
- map_ = BLI_ghash_str_new("RootPChanMap");
}
RootPChanMap::~RootPChanMap()
{
- /* Free the map, and all the value sets. */
- BLI_ghash_free(map_, nullptr, free_rootpchanmap_valueset);
}
/* Debug contents of map */
void RootPChanMap::print_debug()
{
- GHashIterator it1;
- GSetIterator it2;
-
- printf("Root PChan Map:\n");
- GHASH_ITER (it1, map_) {
- const char *item = (const char *)BLI_ghashIterator_getKey(&it1);
- GSet *values = (GSet *)BLI_ghashIterator_getValue(&it1);
-
- printf(" %s : { ", item);
- GSET_ITER (it2, values) {
- const char *val = (const char *)BLI_gsetIterator_getKey(&it2);
- printf("%s, ", val);
+ map_.foreach_item([](StringRefNull key, const Set<StringRefNull> &values) {
+ printf(" %s : { ", key.data());
+ for (StringRefNull val : values) {
+ printf("%s, ", val.data());
}
printf("}\n");
- }
+ });
}
/* Add a mapping. */
void RootPChanMap::add_bone(const char *bone, const char *root)
{
- if (BLI_ghash_haskey(map_, bone)) {
- /* Add new entry, but only add the root if it doesn't already
- * exist in there. */
- GSet *values = (GSet *)BLI_ghash_lookup(map_, bone);
- BLI_gset_add(values, (void *)root);
- }
- else {
- /* Create new set and mapping. */
- GSet *values = BLI_gset_new(
- BLI_ghashutil_strhash_p, BLI_ghashutil_strcmp, "RootPChanMap Value Set");
- BLI_ghash_insert(map_, (void *)bone, (void *)values);
-
- /* Add new entry now. */
- BLI_gset_insert(values, (void *)root);
- }
+ map_.lookup_or_add_default(bone).add(root);
}
/* Check if there's a common root bone between two bones. */
bool RootPChanMap::has_common_root(const char *bone1, const char *bone2) const
{
- /* Ensure that both are in the map... */
- if (BLI_ghash_haskey(map_, bone1) == false) {
+ const Set<StringRefNull> *bone1_roots = map_.lookup_ptr(bone1);
+ const Set<StringRefNull> *bone2_roots = map_.lookup_ptr(bone2);
+
+ if (bone1_roots == nullptr) {
// fprintf("RootPChanMap: bone1 '%s' not found (%s => %s)\n", bone1, bone1, bone2);
// print_debug();
return false;
}
- if (BLI_ghash_haskey(map_, bone2) == false) {
+ if (bone2_roots == nullptr) {
// fprintf("RootPChanMap: bone2 '%s' not found (%s => %s)\n", bone2, bone1, bone2);
// print_debug();
return false;
}
- GSet *bone1_roots = (GSet *)BLI_ghash_lookup(map_, (void *)bone1);
- GSet *bone2_roots = (GSet *)BLI_ghash_lookup(map_, (void *)bone2);
-
- GSetIterator it1, it2;
- GSET_ITER (it1, bone1_roots) {
- GSET_ITER (it2, bone2_roots) {
- const char *v1 = (const char *)BLI_gsetIterator_getKey(&it1);
- const char *v2 = (const char *)BLI_gsetIterator_getKey(&it2);
-
- if (strcmp(v1, v2) == 0) {
- // fprintf("RootPchanMap: %s in common for %s => %s\n", v1, bone1, bone2);
- return true;
- }
- }
- }
-
- // fprintf("RootPChanMap: No common root found (%s => %s)\n", bone1, bone2);
- return false;
+ return Set<StringRefNull>::Intersects(*bone1_roots, *bone2_roots);
}
} // namespace DEG
diff --git a/source/blender/depsgraph/intern/builder/deg_builder_pchanmap.h b/source/blender/depsgraph/intern/builder/deg_builder_pchanmap.h
index 1442f547b08..df8b295f5bb 100644
--- a/source/blender/depsgraph/intern/builder/deg_builder_pchanmap.h
+++ b/source/blender/depsgraph/intern/builder/deg_builder_pchanmap.h
@@ -23,12 +23,12 @@
#pragma once
-struct GHash;
+#include "intern/depsgraph_type.h"
namespace DEG {
struct RootPChanMap {
- /* ctor and dtor - Create and free the internal map respectively. */
+ /* Constructor and destructor - Create and free the internal map respectively. */
RootPChanMap();
~RootPChanMap();
@@ -42,13 +42,11 @@ struct RootPChanMap {
bool has_common_root(const char *bone1, const char *bone2) const;
protected:
- /* The actual map:
- * - Keys are "strings" (const char *) - not dynamically allocated.
- * - Values are "sets" (const char *) - not dynamically allocated.
- *
- * We don't use the C++ maps here, as it's more convenient to use
- * Blender's GHash and be able to compare by-value instead of by-ref. */
- struct GHash *map_;
+ /**
+ * The strings are only referenced by this map. Users of RootPChanMap have to make sure that the
+ * life-time of the strings is long enough.
+ */
+ Map<StringRefNull, Set<StringRefNull>> map_;
};
} // namespace DEG
diff --git a/source/blender/depsgraph/intern/builder/deg_builder_relations.cc b/source/blender/depsgraph/intern/builder/deg_builder_relations.cc
index 40fbfbc2b99..f5a131a1731 100644
--- a/source/blender/depsgraph/intern/builder/deg_builder_relations.cc
+++ b/source/blender/depsgraph/intern/builder/deg_builder_relations.cc
@@ -28,14 +28,12 @@
#include <cstring> /* required for STREQ later on. */
#include <stdio.h>
#include <stdlib.h>
-#include <unordered_set>
#include "MEM_guardedalloc.h"
#include "BLI_blenlib.h"
#include "BLI_utildefines.h"
-extern "C" {
#include "DNA_action_types.h"
#include "DNA_anim_types.h"
#include "DNA_armature_types.h"
@@ -62,6 +60,7 @@ extern "C" {
#include "DNA_rigidbody_types.h"
#include "DNA_scene_types.h"
#include "DNA_sequence_types.h"
+#include "DNA_simulation_types.h"
#include "DNA_sound_types.h"
#include "DNA_speaker_types.h"
#include "DNA_texture_types.h"
@@ -69,15 +68,16 @@ extern "C" {
#include "DNA_world_types.h"
#include "BKE_action.h"
-#include "BKE_animsys.h"
+#include "BKE_anim_data.h"
#include "BKE_armature.h"
#include "BKE_collection.h"
#include "BKE_collision.h"
#include "BKE_constraint.h"
#include "BKE_curve.h"
#include "BKE_effect.h"
-#include "BKE_fcurve.h"
+#include "BKE_fcurve_driver.h"
#include "BKE_gpencil_modifier.h"
+#include "BKE_idprop.h"
#include "BKE_image.h"
#include "BKE_key.h"
#include "BKE_layer.h"
@@ -98,7 +98,6 @@ extern "C" {
#include "RNA_access.h"
#include "RNA_types.h"
-} /* extern "C" */
#include "DEG_depsgraph.h"
#include "DEG_depsgraph_build.h"
@@ -121,8 +120,6 @@ extern "C" {
namespace DEG {
-using std::unordered_set;
-
/* ***************** */
/* Relations Builder */
@@ -436,7 +433,7 @@ void DepsgraphRelationBuilder::add_particle_forcefield_relations(const Operation
}
/* Smoke flow relations. */
- if (relation->pd->forcefield == PFIELD_SMOKEFLOW && relation->pd->f_source) {
+ if (relation->pd->forcefield == PFIELD_FLUIDFLOW && relation->pd->f_source) {
ComponentKey trf_key(&relation->pd->f_source->id, NodeType::TRANSFORM);
add_relation(trf_key, key, "Smoke Force Domain");
ComponentKey eff_key(&relation->pd->f_source->id, NodeType::GEOMETRY);
@@ -558,6 +555,9 @@ void DepsgraphRelationBuilder::build_id(ID *id)
case ID_SCE:
build_scene_parameters((Scene *)id);
break;
+ case ID_SIM:
+ build_simulation((Simulation *)id);
+ break;
default:
fprintf(stderr, "Unhandled ID %s\n", id->name);
BLI_assert(!"Should never happen");
@@ -565,6 +565,18 @@ void DepsgraphRelationBuilder::build_id(ID *id)
}
}
+static void build_idproperties_callback(IDProperty *id_property, void *user_data)
+{
+ DepsgraphRelationBuilder *builder = reinterpret_cast<DepsgraphRelationBuilder *>(user_data);
+ BLI_assert(id_property->type == IDP_ID);
+ builder->build_id(reinterpret_cast<ID *>(id_property->data.pointer));
+}
+
+void DepsgraphRelationBuilder::build_idproperties(IDProperty *id_property)
+{
+ IDP_foreach_property(id_property, IDP_TYPE_FILTER_ID, build_idproperties_callback, this);
+}
+
void DepsgraphRelationBuilder::build_collection(LayerCollection *from_layer_collection,
Object *object,
Collection *collection)
@@ -578,6 +590,7 @@ void DepsgraphRelationBuilder::build_collection(LayerCollection *from_layer_coll
* recurses into all the nested objects and collections. */
return;
}
+ build_idproperties(collection->id.properties);
const bool group_done = built_map_.checkIsBuiltAndTag(collection);
OperationKey object_transform_final_key(object != nullptr ? &object->id : nullptr,
NodeType::TRANSFORM,
@@ -645,19 +658,19 @@ void DepsgraphRelationBuilder::build_object(Base *base, Object *object)
if (object->modifiers.first != nullptr) {
BuilderWalkUserData data;
data.builder = this;
- modifiers_foreachIDLink(object, modifier_walk, &data);
+ BKE_modifiers_foreach_ID_link(object, modifier_walk, &data);
}
/* Grease Pencil Modifiers. */
if (object->greasepencil_modifiers.first != nullptr) {
BuilderWalkUserData data;
data.builder = this;
- BKE_gpencil_modifiers_foreachIDLink(object, modifier_walk, &data);
+ BKE_gpencil_modifiers_foreach_ID_link(object, modifier_walk, &data);
}
/* Shader FX. */
if (object->shader_fx.first != nullptr) {
BuilderWalkUserData data;
data.builder = this;
- BKE_shaderfx_foreachIDLink(object, modifier_walk, &data);
+ BKE_shaderfx_foreach_ID_link(object, modifier_walk, &data);
}
/* Constraints. */
if (object->constraints.first != nullptr) {
@@ -691,6 +704,7 @@ void DepsgraphRelationBuilder::build_object(Base *base, Object *object)
final_transform_key,
"Simulation -> Final Transform");
}
+ build_idproperties(object->id.properties);
/* Animation data */
build_animdata(&object->id);
/* Object data. */
@@ -1219,6 +1233,12 @@ void DepsgraphRelationBuilder::build_animdata(ID *id)
build_animdata_curves(id);
/* Drivers. */
build_animdata_drivers(id);
+
+ if (check_id_has_anim_component(id)) {
+ ComponentKey animation_key(id, NodeType::ANIMATION);
+ ComponentKey parameters_key(id, NodeType::PARAMETERS);
+ add_relation(animation_key, parameters_key, "Animation -> Parameters");
+ }
}
void DepsgraphRelationBuilder::build_animdata_curves(ID *id)
@@ -1367,6 +1387,7 @@ void DepsgraphRelationBuilder::build_action(bAction *action)
if (built_map_.checkIsBuiltAndTag(action)) {
return;
}
+ build_idproperties(action->id.properties);
if (!BLI_listbase_is_empty(&action->curves)) {
TimeSourceKey time_src_key;
ComponentKey animation_key(&action->id, NodeType::ANIMATION);
@@ -1479,7 +1500,10 @@ void DepsgraphRelationBuilder::build_driver_data(ID *id, FCurve *fcu)
}
}
if (property_entry_key.prop != nullptr && RNA_property_is_idprop(property_entry_key.prop)) {
- RNAPathKey property_exit_key(id, rna_path, RNAPointerSource::EXIT);
+ RNAPathKey property_exit_key(property_entry_key.id,
+ property_entry_key.ptr,
+ property_entry_key.prop,
+ RNAPointerSource::EXIT);
OperationKey parameters_key(id, NodeType::PARAMETERS, OperationCode::PARAMETERS_EVAL);
add_relation(property_exit_key, parameters_key, "Driven Property -> Properties");
}
@@ -1612,6 +1636,7 @@ void DepsgraphRelationBuilder::build_world(World *world)
if (built_map_.checkIsBuiltAndTag(world)) {
return;
}
+ build_idproperties(world->id.properties);
/* animation */
build_animdata(&world->id);
build_parameters(&world->id);
@@ -1789,7 +1814,7 @@ void DepsgraphRelationBuilder::build_particle_systems(Object *object)
}
}
/* Keyed particle targets. */
- if (part->phystype == PART_PHYS_KEYED) {
+ if (ELEM(part->phystype, PART_PHYS_KEYED, PART_PHYS_BOIDS)) {
LISTBASE_FOREACH (ParticleTarget *, particle_target, &psys->targets) {
if (particle_target->ob == nullptr || particle_target->ob == object) {
continue;
@@ -1854,8 +1879,9 @@ void DepsgraphRelationBuilder::build_particle_settings(ParticleSettings *part)
ComponentKey texture_key(&mtex->tex->id, NodeType::GENERIC_DATABLOCK);
add_relation(texture_key,
particle_settings_reset_key,
- "Particle Texture",
+ "Particle Texture -> Particle Reset",
RELATION_FLAG_FLUSH_USER_EDIT_ONLY);
+ add_relation(texture_key, particle_settings_eval_key, "Particle Texture -> Particle Eval");
/* TODO(sergey): Consider moving texture space handling to an own
* function. */
if (mtex->texco == TEXCO_OBJECT && mtex->object != nullptr) {
@@ -1890,6 +1916,7 @@ void DepsgraphRelationBuilder::build_shapekeys(Key *key)
if (built_map_.checkIsBuiltAndTag(key)) {
return;
}
+ build_idproperties(key->id.properties);
/* Attach animdata to geometry. */
build_animdata(&key->id);
build_parameters(&key->id);
@@ -1947,7 +1974,7 @@ void DepsgraphRelationBuilder::build_object_data_geometry(Object *object)
ctx.scene = scene_;
ctx.object = object;
LISTBASE_FOREACH (ModifierData *, md, &object->modifiers) {
- const ModifierTypeInfo *mti = modifierType_getInfo((ModifierType)md->type);
+ const ModifierTypeInfo *mti = BKE_modifier_get_info((ModifierType)md->type);
if (mti->updateDepsgraph) {
DepsNodeHandle handle = create_node_handle(obdata_ubereval_key);
ctx.node = reinterpret_cast<::DepsNodeHandle *>(&handle);
@@ -1965,7 +1992,7 @@ void DepsgraphRelationBuilder::build_object_data_geometry(Object *object)
ctx.scene = scene_;
ctx.object = object;
LISTBASE_FOREACH (GpencilModifierData *, md, &object->greasepencil_modifiers) {
- const GpencilModifierTypeInfo *mti = BKE_gpencil_modifierType_getInfo(
+ const GpencilModifierTypeInfo *mti = BKE_gpencil_modifier_get_info(
(GpencilModifierType)md->type);
if (mti->updateDepsgraph) {
DepsNodeHandle handle = create_node_handle(obdata_ubereval_key);
@@ -1984,7 +2011,7 @@ void DepsgraphRelationBuilder::build_object_data_geometry(Object *object)
ctx.scene = scene_;
ctx.object = object;
LISTBASE_FOREACH (ShaderFxData *, fx, &object->shader_fx) {
- const ShaderFxTypeInfo *fxi = BKE_shaderfxType_getInfo((ShaderFxType)fx->type);
+ const ShaderFxTypeInfo *fxi = BKE_shaderfx_get_info((ShaderFxType)fx->type);
if (fxi->updateDepsgraph) {
DepsNodeHandle handle = create_node_handle(obdata_ubereval_key);
ctx.node = reinterpret_cast<::DepsNodeHandle *>(&handle);
@@ -2069,6 +2096,7 @@ void DepsgraphRelationBuilder::build_object_data_geometry_datablock(ID *obdata)
if (built_map_.checkIsBuiltAndTag(obdata)) {
return;
}
+ build_idproperties(obdata->properties);
/* Animation. */
build_animdata(obdata);
build_parameters(obdata);
@@ -2181,8 +2209,18 @@ void DepsgraphRelationBuilder::build_armature(bArmature *armature)
if (built_map_.checkIsBuiltAndTag(armature)) {
return;
}
+ build_idproperties(armature->id.properties);
build_animdata(&armature->id);
build_parameters(&armature->id);
+ build_armature_bones(&armature->bonebase);
+}
+
+void DepsgraphRelationBuilder::build_armature_bones(ListBase *bones)
+{
+ LISTBASE_FOREACH (Bone *, bone, bones) {
+ build_idproperties(bone->prop);
+ build_armature_bones(&bone->childbase);
+ }
}
void DepsgraphRelationBuilder::build_camera(Camera *camera)
@@ -2190,6 +2228,7 @@ void DepsgraphRelationBuilder::build_camera(Camera *camera)
if (built_map_.checkIsBuiltAndTag(camera)) {
return;
}
+ build_idproperties(camera->id.properties);
build_animdata(&camera->id);
build_parameters(&camera->id);
if (camera->dof.focus_object != nullptr) {
@@ -2206,16 +2245,23 @@ void DepsgraphRelationBuilder::build_light(Light *lamp)
if (built_map_.checkIsBuiltAndTag(lamp)) {
return;
}
+ build_idproperties(lamp->id.properties);
build_animdata(&lamp->id);
build_parameters(&lamp->id);
+
+ ComponentKey lamp_parameters_key(&lamp->id, NodeType::PARAMETERS);
+
/* light's nodetree */
if (lamp->nodetree != nullptr) {
build_nodetree(lamp->nodetree);
- ComponentKey lamp_parameters_key(&lamp->id, NodeType::PARAMETERS);
ComponentKey nodetree_key(&lamp->nodetree->id, NodeType::SHADING);
add_relation(nodetree_key, lamp_parameters_key, "NTree->Light Parameters");
build_nested_nodetree(&lamp->id, lamp->nodetree);
}
+
+ /* For allowing drivers on lamp properties. */
+ ComponentKey shading_key(&lamp->id, NodeType::SHADING);
+ add_relation(lamp_parameters_key, shading_key, "Light Shading Parameters");
}
void DepsgraphRelationBuilder::build_nodetree(bNodeTree *ntree)
@@ -2226,11 +2272,20 @@ void DepsgraphRelationBuilder::build_nodetree(bNodeTree *ntree)
if (built_map_.checkIsBuiltAndTag(ntree)) {
return;
}
+ build_idproperties(ntree->id.properties);
build_animdata(&ntree->id);
build_parameters(&ntree->id);
ComponentKey shading_key(&ntree->id, NodeType::SHADING);
/* nodetree's nodes... */
LISTBASE_FOREACH (bNode *, bnode, &ntree->nodes) {
+ build_idproperties(bnode->prop);
+ LISTBASE_FOREACH (bNodeSocket *, socket, &bnode->inputs) {
+ build_idproperties(socket->prop);
+ }
+ LISTBASE_FOREACH (bNodeSocket *, socket, &bnode->outputs) {
+ build_idproperties(socket->prop);
+ }
+
ID *id = bnode->id;
if (id == nullptr) {
continue;
@@ -2295,6 +2350,13 @@ void DepsgraphRelationBuilder::build_nodetree(bNodeTree *ntree)
}
}
+ LISTBASE_FOREACH (bNodeSocket *, socket, &ntree->inputs) {
+ build_idproperties(socket->prop);
+ }
+ LISTBASE_FOREACH (bNodeSocket *, socket, &ntree->outputs) {
+ build_idproperties(socket->prop);
+ }
+
OperationKey shading_update_key(&ntree->id, NodeType::SHADING, OperationCode::MATERIAL_UPDATE);
OperationKey shading_parameters_key(
&ntree->id, NodeType::SHADING_PARAMETERS, OperationCode::MATERIAL_UPDATE);
@@ -2314,6 +2376,7 @@ void DepsgraphRelationBuilder::build_material(Material *material)
if (built_map_.checkIsBuiltAndTag(material)) {
return;
}
+ build_idproperties(material->id.properties);
/* animation */
build_animdata(&material->id);
build_parameters(&material->id);
@@ -2345,21 +2408,33 @@ void DepsgraphRelationBuilder::build_texture(Tex *texture)
return;
}
/* texture itself */
+ ComponentKey texture_key(&texture->id, NodeType::GENERIC_DATABLOCK);
+ build_idproperties(texture->id.properties);
build_animdata(&texture->id);
build_parameters(&texture->id);
+
/* texture's nodetree */
build_nodetree(texture->nodetree);
+ build_nested_nodetree(&texture->id, texture->nodetree);
+
/* Special cases for different IDs which texture uses. */
if (texture->type == TEX_IMAGE) {
if (texture->ima != nullptr) {
build_image(texture->ima);
+
+ ComponentKey image_key(&texture->ima->id, NodeType::GENERIC_DATABLOCK);
+ add_relation(image_key, texture_key, "Texture Image");
}
}
- build_nested_nodetree(&texture->id, texture->nodetree);
+
if (check_id_has_anim_component(&texture->id)) {
ComponentKey animation_key(&texture->id, NodeType::ANIMATION);
- ComponentKey datablock_key(&texture->id, NodeType::GENERIC_DATABLOCK);
- add_relation(animation_key, datablock_key, "Datablock Animation");
+ add_relation(animation_key, texture_key, "Datablock Animation");
+ }
+
+ if (BKE_image_user_id_has_animation(&texture->id)) {
+ ComponentKey image_animation_key(&texture->id, NodeType::IMAGE_ANIMATION);
+ add_relation(image_animation_key, texture_key, "Datablock Image Animation");
}
}
@@ -2368,6 +2443,7 @@ void DepsgraphRelationBuilder::build_image(Image *image)
if (built_map_.checkIsBuiltAndTag(image)) {
return;
}
+ build_idproperties(image->id.properties);
build_parameters(&image->id);
}
@@ -2388,6 +2464,7 @@ void DepsgraphRelationBuilder::build_cachefile(CacheFile *cache_file)
if (built_map_.checkIsBuiltAndTag(cache_file)) {
return;
}
+ build_idproperties(cache_file->id.properties);
/* Animation. */
build_animdata(&cache_file->id);
build_parameters(&cache_file->id);
@@ -2417,6 +2494,7 @@ void DepsgraphRelationBuilder::build_mask(Mask *mask)
return;
}
ID *mask_id = &mask->id;
+ build_idproperties(mask_id->properties);
/* F-Curve animation. */
build_animdata(mask_id);
build_parameters(mask_id);
@@ -2455,6 +2533,7 @@ void DepsgraphRelationBuilder::build_freestyle_linestyle(FreestyleLineStyle *lin
ID *linestyle_id = &linestyle->id;
build_parameters(linestyle_id);
+ build_idproperties(linestyle_id->properties);
build_animdata(linestyle_id);
build_nodetree(linestyle->nodetree);
}
@@ -2465,6 +2544,7 @@ void DepsgraphRelationBuilder::build_movieclip(MovieClip *clip)
return;
}
/* Animation. */
+ build_idproperties(clip->id.properties);
build_animdata(&clip->id);
build_parameters(&clip->id);
}
@@ -2474,6 +2554,7 @@ void DepsgraphRelationBuilder::build_lightprobe(LightProbe *probe)
if (built_map_.checkIsBuiltAndTag(probe)) {
return;
}
+ build_idproperties(probe->id.properties);
build_animdata(&probe->id);
build_parameters(&probe->id);
}
@@ -2483,6 +2564,7 @@ void DepsgraphRelationBuilder::build_speaker(Speaker *speaker)
if (built_map_.checkIsBuiltAndTag(speaker)) {
return;
}
+ build_idproperties(speaker->id.properties);
build_animdata(&speaker->id);
build_parameters(&speaker->id);
if (speaker->sound != nullptr) {
@@ -2498,10 +2580,25 @@ void DepsgraphRelationBuilder::build_sound(bSound *sound)
if (built_map_.checkIsBuiltAndTag(sound)) {
return;
}
+ build_idproperties(sound->id.properties);
build_animdata(&sound->id);
build_parameters(&sound->id);
}
+void DepsgraphRelationBuilder::build_simulation(Simulation *simulation)
+{
+ if (built_map_.checkIsBuiltAndTag(simulation)) {
+ return;
+ }
+ build_animdata(&simulation->id);
+ build_parameters(&simulation->id);
+
+ OperationKey simulation_update_key(
+ &simulation->id, NodeType::SIMULATION, OperationCode::SIMULATION_EVAL);
+ TimeSourceKey time_src_key;
+ add_relation(time_src_key, simulation_update_key, "TimeSrc -> Simulation");
+}
+
void DepsgraphRelationBuilder::build_scene_sequencer(Scene *scene)
{
if (scene->ed == nullptr) {
@@ -2514,6 +2611,7 @@ void DepsgraphRelationBuilder::build_scene_sequencer(Scene *scene)
Sequence *seq;
bool has_audio_strips = false;
SEQ_BEGIN (scene->ed, seq) {
+ build_idproperties(seq->prop);
if (seq->sound != nullptr) {
build_sound(seq->sound);
ComponentKey sound_key(&seq->sound->id, NodeType::AUDIO);
@@ -2544,8 +2642,16 @@ void DepsgraphRelationBuilder::build_scene_sequencer(Scene *scene)
}
}
-void DepsgraphRelationBuilder::build_scene_audio(Scene * /*scene*/)
+void DepsgraphRelationBuilder::build_scene_audio(Scene *scene)
{
+ OperationKey scene_audio_volume_key(&scene->id, NodeType::AUDIO, OperationCode::AUDIO_VOLUME);
+ OperationKey scene_sound_eval_key(&scene->id, NodeType::AUDIO, OperationCode::SOUND_EVAL);
+ add_relation(scene_audio_volume_key, scene_sound_eval_key, "Audio Volume -> Sound");
+
+ if (scene->audio.flag & AUDIO_VOLUME_ANIMATED) {
+ ComponentKey scene_anim_key(&scene->id, NodeType::ANIMATION);
+ add_relation(scene_anim_key, scene_audio_volume_key, "Animation -> Audio Volume");
+ }
}
void DepsgraphRelationBuilder::build_scene_speakers(Scene * /*scene*/, ViewLayer *view_layer)
@@ -2608,7 +2714,7 @@ void DepsgraphRelationBuilder::build_copy_on_write_relations(IDNode *id_node)
Node *node_cow = find_node(copy_on_write_key);
OperationNode *op_cow = node_cow->get_exit_operation();
/* Plug any other components to this one. */
- GHASH_FOREACH_BEGIN (ComponentNode *, comp_node, id_node->components) {
+ for (ComponentNode *comp_node : id_node->components.values()) {
if (comp_node->type == NodeType::COPY_ON_WRITE) {
/* Copy-on-write component never depends on itself. */
continue;
@@ -2651,11 +2757,11 @@ void DepsgraphRelationBuilder::build_copy_on_write_relations(IDNode *id_node)
rel->flag |= rel_flag;
}
/* All dangling operations should also be executed after copy-on-write. */
- GHASH_FOREACH_BEGIN (OperationNode *, op_node, comp_node->operations_map) {
+ for (OperationNode *op_node : comp_node->operations_map->values()) {
if (op_node == op_entry) {
continue;
}
- if (op_node->inlinks.size() == 0) {
+ if (op_node->inlinks.is_empty()) {
Relation *rel = graph_->add_new_relation(op_cow, op_node, "CoW Dependency");
rel->flag |= rel_flag;
}
@@ -2677,7 +2783,6 @@ void DepsgraphRelationBuilder::build_copy_on_write_relations(IDNode *id_node)
}
}
}
- GHASH_FOREACH_END();
/* NOTE: We currently ignore implicit relations to an external
* data-blocks for copy-on-write operations. This means, for example,
* copy-on-write component of Object will not wait for copy-on-write
@@ -2686,7 +2791,6 @@ void DepsgraphRelationBuilder::build_copy_on_write_relations(IDNode *id_node)
* evaluation step needs geometry, it will have transitive dependency
* to Mesh copy-on-write already. */
}
- GHASH_FOREACH_END();
/* TODO(sergey): This solves crash for now, but causes too many
* updates potentially. */
if (GS(id_orig->name) == ID_OB) {
@@ -2735,7 +2839,7 @@ static bool is_reachable(const Node *const from, const Node *const to)
// Perform a graph walk from 'to' towards its incoming connections.
// Walking from 'from' towards its outgoing connections is 10x slower on the Spring rig.
deque<const Node *> queue;
- unordered_set<const Node *> seen;
+ Set<const Node *> seen;
queue.push_back(to);
while (!queue.empty()) {
// Visit the next node to inspect.
@@ -2749,7 +2853,7 @@ static bool is_reachable(const Node *const from, const Node *const to)
// Queue all incoming relations that we haven't seen before.
for (Relation *relation : visit->inlinks) {
const Node *prev_node = relation->from;
- if (seen.insert(prev_node).second) {
+ if (seen.add(prev_node)) {
queue.push_back(prev_node);
}
}
@@ -2788,6 +2892,9 @@ void DepsgraphRelationBuilder::build_driver_relations(IDNode *id_node)
DriverGroupMap driver_groups;
LISTBASE_FOREACH (FCurve *, fcu, &adt->drivers) {
+ if (fcu->rna_path == nullptr) {
+ continue;
+ }
// Get the RNA path except the part after the last dot.
char *last_dot = strrchr(fcu->rna_path, '.');
string rna_prefix;
@@ -2838,7 +2945,7 @@ void DepsgraphRelationBuilder::build_driver_relations(IDNode *id_node)
}
}
}
-}
+} // namespace DEG
/* **** ID traversal callbacks functions **** */
diff --git a/source/blender/depsgraph/intern/builder/deg_builder_relations.h b/source/blender/depsgraph/intern/builder/deg_builder_relations.h
index 099a00d66a6..aa6d8ababd3 100644
--- a/source/blender/depsgraph/intern/builder/deg_builder_relations.h
+++ b/source/blender/depsgraph/intern/builder/deg_builder_relations.h
@@ -54,6 +54,7 @@ struct FCurve;
struct FreestyleLineSet;
struct FreestyleLineStyle;
struct ID;
+struct IDProperty;
struct Image;
struct Key;
struct LayerCollection;
@@ -68,6 +69,7 @@ struct Object;
struct ParticleSettings;
struct ParticleSystem;
struct Scene;
+struct Simulation;
struct Speaker;
struct Tex;
struct ViewLayer;
@@ -195,6 +197,8 @@ class DepsgraphRelationBuilder : public DepsgraphBuilder {
virtual void build_id(ID *id);
+ virtual void build_idproperties(IDProperty *id_property);
+
virtual void build_scene_render(Scene *scene, ViewLayer *view_layer);
virtual void build_scene_parameters(Scene *scene);
virtual void build_scene_compositor(Scene *scene);
@@ -266,6 +270,7 @@ class DepsgraphRelationBuilder : public DepsgraphBuilder {
virtual void build_proxy_rig(Object *object);
virtual void build_shapekeys(Key *key);
virtual void build_armature(bArmature *armature);
+ virtual void build_armature_bones(ListBase *bones);
virtual void build_camera(Camera *camera);
virtual void build_light(Light *lamp);
virtual void build_nodetree(bNodeTree *ntree);
@@ -282,6 +287,7 @@ class DepsgraphRelationBuilder : public DepsgraphBuilder {
virtual void build_lightprobe(LightProbe *probe);
virtual void build_speaker(Speaker *speaker);
virtual void build_sound(bSound *sound);
+ virtual void build_simulation(Simulation *simulation);
virtual void build_scene_sequencer(Scene *scene);
virtual void build_scene_audio(Scene *scene);
virtual void build_scene_speakers(Scene *scene, ViewLayer *view_layer);
diff --git a/source/blender/depsgraph/intern/builder/deg_builder_relations_impl.h b/source/blender/depsgraph/intern/builder/deg_builder_relations_impl.h
index eeeb58100b0..5983627fafc 100644
--- a/source/blender/depsgraph/intern/builder/deg_builder_relations_impl.h
+++ b/source/blender/depsgraph/intern/builder/deg_builder_relations_impl.h
@@ -25,10 +25,8 @@
#include "intern/node/deg_node_id.h"
-extern "C" {
#include "DNA_ID.h"
#include "DNA_object_types.h"
-}
namespace DEG {
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 6fe9a3c2a00..fe9adecbf0a 100644
--- a/source/blender/depsgraph/intern/builder/deg_builder_relations_rig.cc
+++ b/source/blender/depsgraph/intern/builder/deg_builder_relations_rig.cc
@@ -34,7 +34,6 @@
#include "BLI_blenlib.h"
#include "BLI_utildefines.h"
-extern "C" {
#include "DNA_action_types.h"
#include "DNA_anim_types.h"
#include "DNA_armature_types.h"
@@ -45,7 +44,6 @@ extern "C" {
#include "BKE_action.h"
#include "BKE_armature.h"
#include "BKE_constraint.h"
-} /* extern "C" */
#include "DEG_depsgraph.h"
#include "DEG_depsgraph_build.h"
@@ -68,6 +66,12 @@ void DepsgraphRelationBuilder::build_ik_pose(Object *object,
bConstraint *con,
RootPChanMap *root_map)
{
+ if ((con->flag & CONSTRAINT_DISABLE) != 0) {
+ /* Do not add disabled IK constraints to the relations. If these needs to be temporarily
+ * enabled, they will be added as temporary constraints during transform. */
+ return;
+ }
+
bKinematicConstraint *data = (bKinematicConstraint *)con->data;
/* Attach owner to IK Solver to. */
bPoseChannel *rootchan = BKE_armature_ik_solver_find_root(pchan, data);
@@ -350,6 +354,7 @@ void DepsgraphRelationBuilder::build_rig(Object *object)
}
/* Links between operations for each bone. */
LISTBASE_FOREACH (bPoseChannel *, pchan, &object->pose->chanbase) {
+ build_idproperties(pchan->prop);
OperationKey bone_local_key(
&object->id, NodeType::BONE, pchan->name, OperationCode::BONE_LOCAL);
OperationKey bone_pose_key(
@@ -458,6 +463,7 @@ void DepsgraphRelationBuilder::build_proxy_rig(Object *object)
OperationKey pose_done_key(&object->id, NodeType::EVAL_POSE, OperationCode::POSE_DONE);
OperationKey pose_cleanup_key(&object->id, NodeType::EVAL_POSE, OperationCode::POSE_CLEANUP);
LISTBASE_FOREACH (bPoseChannel *, pchan, &object->pose->chanbase) {
+ build_idproperties(pchan->prop);
OperationKey bone_local_key(
&object->id, NodeType::BONE, pchan->name, OperationCode::BONE_LOCAL);
OperationKey bone_ready_key(
diff --git a/source/blender/depsgraph/intern/builder/deg_builder_relations_scene.cc b/source/blender/depsgraph/intern/builder/deg_builder_relations_scene.cc
index 08191bcecc8..410df839875 100644
--- a/source/blender/depsgraph/intern/builder/deg_builder_relations_scene.cc
+++ b/source/blender/depsgraph/intern/builder/deg_builder_relations_scene.cc
@@ -52,6 +52,7 @@ void DepsgraphRelationBuilder::build_scene_parameters(Scene *scene)
if (built_map_.checkIsBuiltAndTag(scene, BuilderMap::TAG_PARAMETERS)) {
return;
}
+ build_idproperties(scene->id.properties);
build_parameters(&scene->id);
OperationKey parameters_eval_key(
&scene->id, NodeType::PARAMETERS, OperationCode::PARAMETERS_EXIT);
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 d3bdaccd404..e132ba30e67 100644
--- a/source/blender/depsgraph/intern/builder/deg_builder_relations_view_layer.cc
+++ b/source/blender/depsgraph/intern/builder/deg_builder_relations_view_layer.cc
@@ -34,7 +34,6 @@
#include "BLI_blenlib.h"
#include "BLI_utildefines.h"
-extern "C" {
#include "DNA_linestyle_types.h"
#include "DNA_node_types.h"
#include "DNA_object_types.h"
@@ -43,7 +42,6 @@ extern "C" {
#include "BKE_layer.h"
#include "BKE_main.h"
#include "BKE_node.h"
-} /* extern "C" */
#include "DEG_depsgraph.h"
#include "DEG_depsgraph_build.h"
diff --git a/source/blender/depsgraph/intern/builder/deg_builder_remove_noop.cc b/source/blender/depsgraph/intern/builder/deg_builder_remove_noop.cc
index 2ce1f1f1c1d..c6545362bb1 100644
--- a/source/blender/depsgraph/intern/builder/deg_builder_remove_noop.cc
+++ b/source/blender/depsgraph/intern/builder/deg_builder_remove_noop.cc
@@ -43,7 +43,7 @@ static inline bool is_unused_noop(OperationNode *op_node)
if (op_node->flag & OperationFlag::DEPSOP_FLAG_PINNED) {
return false;
}
- return op_node->is_noop() && op_node->outlinks.empty();
+ return op_node->is_noop() && op_node->outlinks.is_empty();
}
void deg_graph_remove_unused_noops(Depsgraph *graph)
@@ -61,7 +61,7 @@ void deg_graph_remove_unused_noops(Depsgraph *graph)
OperationNode *to_remove = queue.front();
queue.pop_front();
- while (!to_remove->inlinks.empty()) {
+ while (!to_remove->inlinks.is_empty()) {
Relation *rel_in = to_remove->inlinks[0];
Node *dependency = rel_in->from;
diff --git a/source/blender/depsgraph/intern/builder/deg_builder_rna.cc b/source/blender/depsgraph/intern/builder/deg_builder_rna.cc
index 73f6730be03..9fa663b9b6d 100644
--- a/source/blender/depsgraph/intern/builder/deg_builder_rna.cc
+++ b/source/blender/depsgraph/intern/builder/deg_builder_rna.cc
@@ -27,18 +27,15 @@
#include "MEM_guardedalloc.h"
-#include "BLI_ghash.h"
#include "BLI_listbase.h"
#include "BLI_utildefines.h"
-extern "C" {
#include "DNA_action_types.h"
#include "DNA_armature_types.h"
#include "DNA_constraint_types.h"
#include "DNA_key_types.h"
#include "DNA_object_types.h"
#include "DNA_sequence_types.h"
-}
#include "BKE_constraint.h"
@@ -57,37 +54,33 @@ namespace DEG {
class RNANodeQueryIDData {
public:
- explicit RNANodeQueryIDData(const ID *id) : id_(id), contraint_to_pchan_map_(nullptr)
+ explicit RNANodeQueryIDData(const ID *id) : id_(id), constraint_to_pchan_map_(nullptr)
{
}
~RNANodeQueryIDData()
{
- if (contraint_to_pchan_map_ != nullptr) {
- BLI_ghash_free(contraint_to_pchan_map_, nullptr, nullptr);
- }
+ delete constraint_to_pchan_map_;
}
const bPoseChannel *get_pchan_for_constraint(const bConstraint *constraint)
{
ensure_constraint_to_pchan_map();
- return static_cast<bPoseChannel *>(BLI_ghash_lookup(contraint_to_pchan_map_, constraint));
+ return constraint_to_pchan_map_->lookup_default(constraint, nullptr);
}
void ensure_constraint_to_pchan_map()
{
- if (contraint_to_pchan_map_ != nullptr) {
+ if (constraint_to_pchan_map_ != nullptr) {
return;
}
BLI_assert(GS(id_->name) == ID_OB);
const Object *object = reinterpret_cast<const Object *>(id_);
- contraint_to_pchan_map_ = BLI_ghash_ptr_new("id data pchan constraint map");
+ constraint_to_pchan_map_ = new Map<const bConstraint *, const bPoseChannel *>();
if (object->pose != nullptr) {
LISTBASE_FOREACH (const bPoseChannel *, pchan, &object->pose->chanbase) {
LISTBASE_FOREACH (const bConstraint *, constraint, &pchan->constraints) {
- BLI_ghash_insert(contraint_to_pchan_map_,
- const_cast<bConstraint *>(constraint),
- const_cast<bPoseChannel *>(pchan));
+ constraint_to_pchan_map_->add_new(constraint, pchan);
}
}
}
@@ -99,7 +92,7 @@ class RNANodeQueryIDData {
/* indexed by bConstraint*, returns pose channel which contains that
* constraint. */
- GHash *contraint_to_pchan_map_;
+ Map<const bConstraint *, const bPoseChannel *> *constraint_to_pchan_map_;
};
/* ***************************** Node Identifier **************************** */
@@ -121,26 +114,13 @@ bool RNANodeIdentifier::is_valid() const
/* ********************************** Query ********************************* */
-namespace {
-
-void ghash_id_data_free_func(void *value)
-{
- RNANodeQueryIDData *id_data = static_cast<RNANodeQueryIDData *>(value);
- OBJECT_GUARDED_DELETE(id_data, RNANodeQueryIDData);
-}
-
-} // namespace
-
RNANodeQuery::RNANodeQuery(Depsgraph *depsgraph, DepsgraphBuilder *builder)
- : depsgraph_(depsgraph),
- builder_(builder),
- id_data_map_(BLI_ghash_ptr_new("rna node query id data hash"))
+ : depsgraph_(depsgraph), builder_(builder)
{
}
RNANodeQuery::~RNANodeQuery()
{
- BLI_ghash_free(id_data_map_, nullptr, ghash_id_data_free_func);
}
Node *RNANodeQuery::find_node(const PointerRNA *ptr,
@@ -384,12 +364,9 @@ RNANodeIdentifier RNANodeQuery::construct_node_identifier(const PointerRNA *ptr,
RNANodeQueryIDData *RNANodeQuery::ensure_id_data(const ID *id)
{
- RNANodeQueryIDData **id_data_ptr;
- if (!BLI_ghash_ensure_p(
- id_data_map_, const_cast<ID *>(id), reinterpret_cast<void ***>(&id_data_ptr))) {
- *id_data_ptr = OBJECT_GUARDED_NEW(RNANodeQueryIDData, id);
- }
- return *id_data_ptr;
+ unique_ptr<RNANodeQueryIDData> &id_data = id_data_map_.lookup_or_add(
+ id, [&]() { return BLI::make_unique<RNANodeQueryIDData>(id); });
+ return id_data.get();
}
} // namespace DEG
diff --git a/source/blender/depsgraph/intern/builder/deg_builder_rna.h b/source/blender/depsgraph/intern/builder/deg_builder_rna.h
index 8a79d9abef9..bd806ce058a 100644
--- a/source/blender/depsgraph/intern/builder/deg_builder_rna.h
+++ b/source/blender/depsgraph/intern/builder/deg_builder_rna.h
@@ -26,7 +26,6 @@
#include "intern/node/deg_node.h"
#include "intern/node/deg_node_operation.h"
-struct GHash;
struct ID;
struct PointerRNA;
struct PropertyRNA;
@@ -83,7 +82,7 @@ class RNANodeQuery {
DepsgraphBuilder *builder_;
/* Indexed by an ID, returns RNANodeQueryIDData associated with that ID. */
- GHash *id_data_map_;
+ Map<const ID *, unique_ptr<RNANodeQueryIDData>> id_data_map_;
/* Construct identifier of the node which corresponds given configuration
* of RNA property. */
diff --git a/source/blender/depsgraph/intern/builder/deg_builder_transitive.cc b/source/blender/depsgraph/intern/builder/deg_builder_transitive.cc
index 3f828ef5bb0..22ceac899b8 100644
--- a/source/blender/depsgraph/intern/builder/deg_builder_transitive.cc
+++ b/source/blender/depsgraph/intern/builder/deg_builder_transitive.cc
@@ -72,6 +72,8 @@ static void deg_graph_tag_paths_recursive(Node *node)
void deg_graph_transitive_reduction(Depsgraph *graph)
{
int num_removed_relations = 0;
+ Vector<Relation *> relations_to_remove;
+
for (OperationNode *target : graph->operations) {
/* Clear tags. */
for (OperationNode *node : graph->operations) {
@@ -85,25 +87,24 @@ void deg_graph_transitive_reduction(Depsgraph *graph)
deg_graph_tag_paths_recursive(rel->from);
}
/* Remove redundant paths to the target. */
- for (Node::Relations::const_iterator it_rel = target->inlinks.begin();
- it_rel != target->inlinks.end();) {
- Relation *rel = *it_rel;
+ for (Relation *rel : target->inlinks) {
if (rel->from->type == NodeType::TIMESOURCE) {
/* HACK: time source nodes don't get "custom_flags" flag
* set/cleared. */
/* TODO: there will be other types in future, so iterators above
* need modifying. */
- ++it_rel;
+ continue;
}
else if (rel->from->custom_flags & OP_REACHABLE) {
- rel->unlink();
- OBJECT_GUARDED_DELETE(rel, Relation);
- num_removed_relations++;
- }
- else {
- ++it_rel;
+ relations_to_remove.append(rel);
}
}
+ for (Relation *rel : relations_to_remove) {
+ rel->unlink();
+ OBJECT_GUARDED_DELETE(rel, Relation);
+ }
+ num_removed_relations += relations_to_remove.size();
+ relations_to_remove.clear();
}
DEG_DEBUG_PRINTF((::Depsgraph *)graph, BUILD, "Removed %d relations\n", num_removed_relations);
}
diff --git a/source/blender/depsgraph/intern/debug/deg_debug_relations_graphviz.cc b/source/blender/depsgraph/intern/debug/deg_debug_relations_graphviz.cc
index 7080f8a1a9b..dbe88ee92a8 100644
--- a/source/blender/depsgraph/intern/debug/deg_debug_relations_graphviz.cc
+++ b/source/blender/depsgraph/intern/debug/deg_debug_relations_graphviz.cc
@@ -25,12 +25,9 @@
#include <cstdarg>
-#include "BLI_ghash.h"
#include "BLI_utildefines.h"
-extern "C" {
#include "DNA_listBase.h"
-} /* extern "C" */
#include "DEG_depsgraph.h"
#include "DEG_depsgraph_debug.h"
@@ -407,15 +404,14 @@ static void deg_debug_graphviz_node(const DebugContext &ctx, const Node *node)
switch (node->type) {
case NodeType::ID_REF: {
const IDNode *id_node = (const IDNode *)node;
- if (BLI_ghash_len(id_node->components) == 0) {
+ if (id_node->components.is_empty()) {
deg_debug_graphviz_node_single(ctx, node);
}
else {
deg_debug_graphviz_node_cluster_begin(ctx, node);
- GHASH_FOREACH_BEGIN (const ComponentNode *, comp, id_node->components) {
+ for (const ComponentNode *comp : id_node->components.values()) {
deg_debug_graphviz_node(ctx, comp);
}
- GHASH_FOREACH_END();
deg_debug_graphviz_node_cluster_end(ctx);
}
break;
@@ -443,7 +439,8 @@ static void deg_debug_graphviz_node(const DebugContext &ctx, const Node *node)
case NodeType::SYNCHRONIZATION:
case NodeType::AUDIO:
case NodeType::ARMATURE:
- case NodeType::GENERIC_DATABLOCK: {
+ case NodeType::GENERIC_DATABLOCK:
+ case NodeType::SIMULATION: {
ComponentNode *comp_node = (ComponentNode *)node;
if (!comp_node->operations.empty()) {
deg_debug_graphviz_node_cluster_begin(ctx, node);
@@ -472,7 +469,7 @@ static bool deg_debug_graphviz_is_cluster(const Node *node)
switch (node->type) {
case NodeType::ID_REF: {
const IDNode *id_node = (const IDNode *)node;
- return BLI_ghash_len(id_node->components) > 0;
+ return !id_node->components.is_empty();
}
case NodeType::PARAMETERS:
case NodeType::ANIMATION:
@@ -568,12 +565,11 @@ static void deg_debug_graphviz_graph_nodes(const DebugContext &ctx, const Depsgr
static void deg_debug_graphviz_graph_relations(const DebugContext &ctx, const Depsgraph *graph)
{
for (IDNode *id_node : graph->id_nodes) {
- GHASH_FOREACH_BEGIN (ComponentNode *, comp_node, id_node->components) {
+ for (ComponentNode *comp_node : id_node->components.values()) {
for (OperationNode *op_node : comp_node->operations) {
deg_debug_graphviz_node_relations(ctx, op_node);
}
}
- GHASH_FOREACH_END();
}
TimeSourceNode *time_source = graph->find_time_source();
diff --git a/source/blender/depsgraph/intern/debug/deg_debug_stats_gnuplot.cc b/source/blender/depsgraph/intern/debug/deg_debug_stats_gnuplot.cc
index c37188bc3ca..7bef5fda636 100644
--- a/source/blender/depsgraph/intern/debug/deg_debug_stats_gnuplot.cc
+++ b/source/blender/depsgraph/intern/debug/deg_debug_stats_gnuplot.cc
@@ -32,9 +32,7 @@
#include "intern/depsgraph.h"
#include "intern/node/deg_node_id.h"
-extern "C" {
#include "DNA_ID.h"
-} /* extern "C" */
#define NL "\r\n"
diff --git a/source/blender/depsgraph/intern/depsgraph.cc b/source/blender/depsgraph/intern/depsgraph.cc
index 6d88782d68c..d4a6b0a8b76 100644
--- a/source/blender/depsgraph/intern/depsgraph.cc
+++ b/source/blender/depsgraph/intern/depsgraph.cc
@@ -31,15 +31,12 @@
#include "MEM_guardedalloc.h"
#include "BLI_console.h"
-#include "BLI_ghash.h"
#include "BLI_hash.h"
#include "BLI_utildefines.h"
-extern "C" {
#include "BKE_global.h"
#include "BKE_idtype.h"
#include "BKE_scene.h"
-}
#include "DEG_depsgraph.h"
#include "DEG_depsgraph_debug.h"
@@ -60,12 +57,6 @@ extern "C" {
namespace DEG {
-/* TODO(sergey): Find a better place for this. */
-template<typename T> static void remove_from_vector(vector<T> *vector, const T &value)
-{
- vector->erase(std::remove(vector->begin(), vector->end(), value), vector->end());
-}
-
Depsgraph::Depsgraph(Main *bmain, Scene *scene, ViewLayer *view_layer, eEvaluationMode mode)
: time_source(nullptr),
need_update(true),
@@ -81,8 +72,6 @@ Depsgraph::Depsgraph(Main *bmain, Scene *scene, ViewLayer *view_layer, eEvaluati
is_render_pipeline_depsgraph(false)
{
BLI_spin_init(&lock);
- id_hash = BLI_ghash_ptr_new("Depsgraph id hash");
- entry_tags = BLI_gset_ptr_new("Depsgraph entry_tags");
memset(id_type_updated, 0, sizeof(id_type_updated));
memset(id_type_exist, 0, sizeof(id_type_exist));
memset(physics_relations, 0, sizeof(physics_relations));
@@ -91,8 +80,6 @@ Depsgraph::Depsgraph(Main *bmain, Scene *scene, ViewLayer *view_layer, eEvaluati
Depsgraph::~Depsgraph()
{
clear_id_nodes();
- BLI_ghash_free(id_hash, nullptr, nullptr);
- BLI_gset_free(entry_tags, nullptr);
if (time_source != nullptr) {
OBJECT_GUARDED_DELETE(time_source, TimeSourceNode);
}
@@ -117,7 +104,7 @@ TimeSourceNode *Depsgraph::find_time_source() const
IDNode *Depsgraph::find_id_node(const ID *id) const
{
- return reinterpret_cast<IDNode *>(BLI_ghash_lookup(id_hash, id));
+ return id_hash.lookup_default(id, nullptr);
}
IDNode *Depsgraph::add_id_node(ID *id, ID *id_cow_hint)
@@ -132,7 +119,7 @@ IDNode *Depsgraph::add_id_node(ID *id, ID *id_cow_hint)
*
* NOTE: We address ID nodes by the original ID pointer they are
* referencing to. */
- BLI_ghash_insert(id_hash, id, id_node);
+ id_hash.add_new(id, id_node);
id_nodes.push_back(id_node);
id_type_exist[BKE_idtype_idcode_to_index(GS(id->name))] = 1;
@@ -170,7 +157,7 @@ void Depsgraph::clear_id_nodes()
OBJECT_GUARDED_DELETE(id_node, IDNode);
}
/* Clear containers. */
- BLI_ghash_clear(id_hash, nullptr, nullptr);
+ id_hash.clear();
id_nodes.clear();
/* Clear physics relation caches. */
clear_physics_relations(this);
@@ -233,7 +220,7 @@ void Depsgraph::add_entry_tag(OperationNode *node)
* from.
* NOTE: this is necessary since we have several thousand nodes to play
* with. */
- BLI_gset_insert(entry_tags, node);
+ entry_tags.add(node);
}
void Depsgraph::clear_all_nodes()
@@ -320,9 +307,9 @@ void DEG_graph_free(Depsgraph *graph)
OBJECT_GUARDED_DELETE(deg_depsgraph, Depsgraph);
}
-bool DEG_is_evaluating(struct Depsgraph *depsgraph)
+bool DEG_is_evaluating(const struct Depsgraph *depsgraph)
{
- DEG::Depsgraph *deg_graph = reinterpret_cast<DEG::Depsgraph *>(depsgraph);
+ const DEG::Depsgraph *deg_graph = reinterpret_cast<const DEG::Depsgraph *>(depsgraph);
return deg_graph->is_evaluating;
}
diff --git a/source/blender/depsgraph/intern/depsgraph.h b/source/blender/depsgraph/intern/depsgraph.h
index 7801f95e008..672f202338e 100644
--- a/source/blender/depsgraph/intern/depsgraph.h
+++ b/source/blender/depsgraph/intern/depsgraph.h
@@ -43,8 +43,6 @@
#include "intern/debug/deg_debug.h"
#include "intern/depsgraph_type.h"
-struct GHash;
-struct GSet;
struct ID;
struct Scene;
struct ViewLayer;
@@ -97,7 +95,7 @@ struct Depsgraph {
/* <ID : IDNode> mapping from ID blocks to nodes representing these
* blocks, used for quick lookups. */
- GHash *id_hash;
+ Map<const ID *, IDNode *> id_hash;
/* Ordered list of ID nodes, order matches ID allocation order.
* Used for faster iteration, especially for areas which are critical to
@@ -119,7 +117,7 @@ struct Depsgraph {
/* Quick-Access Temp Data ............. */
/* Nodes which have been tagged as "directly modified". */
- GSet *entry_tags;
+ Set<OperationNode *> entry_tags;
/* Special entry tag for time source. Allows to tag invisible dependency graphs for update when
* scene frame changes, so then when dependency graph becomes visible it is on a proper state. */
@@ -169,7 +167,7 @@ struct Depsgraph {
/* Cached list of colliders/effectors for collections and the scene
* created along with relations, for fast lookup during evaluation. */
- GHash *physics_relations[DEG_PHYSICS_RELATIONS_NUM];
+ Map<const ID *, ListBase *> *physics_relations[DEG_PHYSICS_RELATIONS_NUM];
};
} // namespace DEG
diff --git a/source/blender/depsgraph/intern/depsgraph_build.cc b/source/blender/depsgraph/intern/depsgraph_build.cc
index d78bc07ac5e..9e50bd87d6c 100644
--- a/source/blender/depsgraph/intern/depsgraph_build.cc
+++ b/source/blender/depsgraph/intern/depsgraph_build.cc
@@ -25,21 +25,19 @@
#include "MEM_guardedalloc.h"
-#include "BLI_ghash.h"
#include "BLI_listbase.h"
#include "BLI_utildefines.h"
#include "PIL_time.h"
#include "PIL_time_utildefines.h"
-extern "C" {
#include "DNA_cachefile_types.h"
#include "DNA_object_types.h"
#include "DNA_scene_types.h"
+#include "DNA_simulation_types.h"
#include "BKE_main.h"
#include "BKE_scene.h"
-} /* extern "C" */
#include "DEG_depsgraph.h"
#include "DEG_depsgraph_build.h"
@@ -106,6 +104,16 @@ void DEG_add_object_relation(DepsNodeHandle *node_handle,
deg_node_handle->builder->add_node_handle_relation(comp_key, deg_node_handle, description);
}
+void DEG_add_simulation_relation(DepsNodeHandle *node_handle,
+ Simulation *simulation,
+ const char *description)
+{
+ DEG::OperationKey operation_key(
+ &simulation->id, DEG::NodeType::SIMULATION, DEG::OperationCode::SIMULATION_EVAL);
+ DEG::DepsNodeHandle *deg_node_handle = get_node_handle(node_handle);
+ deg_node_handle->builder->add_node_handle_relation(operation_key, deg_node_handle, description);
+}
+
void DEG_add_object_cache_relation(DepsNodeHandle *node_handle,
CacheFile *cache_file,
eDepsObjectComponentType component,
diff --git a/source/blender/depsgraph/intern/depsgraph_debug.cc b/source/blender/depsgraph/intern/depsgraph_debug.cc
index c713a4a3fb1..8f5117ec0f6 100644
--- a/source/blender/depsgraph/intern/depsgraph_debug.cc
+++ b/source/blender/depsgraph/intern/depsgraph_debug.cc
@@ -23,12 +23,9 @@
* Implementation of tools for debugging the depsgraph
*/
-#include "BLI_ghash.h"
#include "BLI_utildefines.h"
-extern "C" {
#include "DNA_scene_types.h"
-} /* extern "C" */
#include "DNA_object_types.h"
@@ -198,10 +195,10 @@ bool DEG_debug_consistency_check(Depsgraph *graph)
/* ------------------------------------------------ */
/**
- * Obtain simple statistics about the complexity of the depsgraph
- * \param[out] r_outer The number of outer nodes in the graph
- * \param[out] r_operations The number of operation nodes in the graph
- * \param[out] r_relations The number of relations between (executable) nodes in the graph
+ * Obtain simple statistics about the complexity of the depsgraph.
+ * \param[out] r_outer: The number of outer nodes in the graph
+ * \param[out] r_operations: The number of operation nodes in the graph
+ * \param[out] r_relations: The number of relations between (executable) nodes in the graph
*/
void DEG_stats_simple(const Depsgraph *graph,
size_t *r_outer,
@@ -224,13 +221,12 @@ void DEG_stats_simple(const Depsgraph *graph,
for (DEG::IDNode *id_node : deg_graph->id_nodes) {
tot_outer++;
- GHASH_FOREACH_BEGIN (DEG::ComponentNode *, comp_node, id_node->components) {
+ for (DEG::ComponentNode *comp_node : id_node->components.values()) {
tot_outer++;
for (DEG::OperationNode *op_node : comp_node->operations) {
tot_rels += op_node->inlinks.size();
}
}
- GHASH_FOREACH_END();
}
DEG::TimeSourceNode *time_source = deg_graph->find_time_source();
diff --git a/source/blender/depsgraph/intern/depsgraph_eval.cc b/source/blender/depsgraph/intern/depsgraph_eval.cc
index 7e7ab07825f..b6c6129e9ba 100644
--- a/source/blender/depsgraph/intern/depsgraph_eval.cc
+++ b/source/blender/depsgraph/intern/depsgraph_eval.cc
@@ -20,21 +20,18 @@
/** \file
* \ingroup depsgraph
*
- * Evaluation engine entrypoints for Depsgraph Engine.
+ * Evaluation engine entry-points for Depsgraph Engine.
*/
#include "MEM_guardedalloc.h"
-#include "BLI_ghash.h"
#include "BLI_listbase.h"
#include "BLI_utildefines.h"
-extern "C" {
#include "BKE_scene.h"
#include "DNA_object_types.h"
#include "DNA_scene_types.h"
-} /* extern "C" */
#include "DEG_depsgraph.h"
#include "DEG_depsgraph_query.h"
@@ -87,5 +84,5 @@ void DEG_evaluate_on_framechange(Main *bmain, Depsgraph *graph, float ctime)
bool DEG_needs_eval(Depsgraph *graph)
{
DEG::Depsgraph *deg_graph = reinterpret_cast<DEG::Depsgraph *>(graph);
- return BLI_gset_len(deg_graph->entry_tags) != 0 || deg_graph->need_update_time;
+ return !deg_graph->entry_tags.is_empty() || deg_graph->need_update_time;
}
diff --git a/source/blender/depsgraph/intern/depsgraph_physics.cc b/source/blender/depsgraph/intern/depsgraph_physics.cc
index d7c09780845..44c3d23ace4 100644
--- a/source/blender/depsgraph/intern/depsgraph_physics.cc
+++ b/source/blender/depsgraph/intern/depsgraph_physics.cc
@@ -28,14 +28,11 @@
#include "MEM_guardedalloc.h"
#include "BLI_compiler_compat.h"
-#include "BLI_ghash.h"
#include "BLI_listbase.h"
-extern "C" {
#include "BKE_collision.h"
#include "BKE_effect.h"
#include "BKE_modifier.h"
-} /* extern "C" */
#include "DNA_collection_types.h"
#include "DNA_object_force_types.h"
@@ -72,8 +69,8 @@ ListBase *DEG_get_effector_relations(const Depsgraph *graph, Collection *collect
}
ID *collection_orig = DEG_get_original_id(&collection->id);
- return (ListBase *)BLI_ghash_lookup(deg_graph->physics_relations[DEG_PHYSICS_EFFECTOR],
- collection_orig);
+ return deg_graph->physics_relations[DEG_PHYSICS_EFFECTOR]->lookup_default(collection_orig,
+ nullptr);
}
ListBase *DEG_get_collision_relations(const Depsgraph *graph,
@@ -86,7 +83,7 @@ ListBase *DEG_get_collision_relations(const Depsgraph *graph,
return nullptr;
}
ID *collection_orig = DEG_get_original_id(&collection->id);
- return (ListBase *)BLI_ghash_lookup(deg_graph->physics_relations[type], collection_orig);
+ return deg_graph->physics_relations[type]->lookup_default(collection_orig, nullptr);
}
/********************** Depsgraph Building API ************************/
@@ -107,7 +104,7 @@ void DEG_add_collision_relations(DepsNodeHandle *handle,
continue;
}
if (filter_function == nullptr ||
- filter_function(ob1, modifiers_findByType(ob1, (ModifierType)modifier_type))) {
+ filter_function(ob1, BKE_modifiers_findby_type(ob1, (ModifierType)modifier_type))) {
DEG_add_object_pointcache_relation(handle, ob1, DEG_OB_COMP_TRANSFORM, name);
DEG_add_object_pointcache_relation(handle, ob1, DEG_OB_COMP_GEOMETRY, name);
}
@@ -144,11 +141,11 @@ void DEG_add_forcefield_relations(DepsNodeHandle *handle,
}
/* Smoke flow relations. */
- if (relation->pd->forcefield == PFIELD_SMOKEFLOW && relation->pd->f_source != nullptr) {
+ if (relation->pd->forcefield == PFIELD_FLUIDFLOW && relation->pd->f_source != nullptr) {
DEG_add_object_pointcache_relation(
- handle, relation->pd->f_source, DEG_OB_COMP_TRANSFORM, "Smoke Force Domain");
+ handle, relation->pd->f_source, DEG_OB_COMP_TRANSFORM, "Fluid Force Domain");
DEG_add_object_pointcache_relation(
- handle, relation->pd->f_source, DEG_OB_COMP_GEOMETRY, "Smoke Force Domain");
+ handle, relation->pd->f_source, DEG_OB_COMP_GEOMETRY, "Fluid Force Domain");
}
/* Absorption forces need collision relation. */
@@ -165,19 +162,15 @@ namespace DEG {
ListBase *build_effector_relations(Depsgraph *graph, Collection *collection)
{
- GHash *hash = graph->physics_relations[DEG_PHYSICS_EFFECTOR];
+ Map<const ID *, ListBase *> *hash = graph->physics_relations[DEG_PHYSICS_EFFECTOR];
if (hash == nullptr) {
- graph->physics_relations[DEG_PHYSICS_EFFECTOR] = BLI_ghash_ptr_new(
- "Depsgraph physics relations hash");
+ graph->physics_relations[DEG_PHYSICS_EFFECTOR] = new Map<const ID *, ListBase *>();
hash = graph->physics_relations[DEG_PHYSICS_EFFECTOR];
}
- ListBase *relations = reinterpret_cast<ListBase *>(BLI_ghash_lookup(hash, collection));
- if (relations == nullptr) {
+ return hash->lookup_or_add(&collection->id, [&]() {
::Depsgraph *depsgraph = reinterpret_cast<::Depsgraph *>(graph);
- relations = BKE_effector_relations_create(depsgraph, graph->view_layer, collection);
- BLI_ghash_insert(hash, &collection->id, relations);
- }
- return relations;
+ return BKE_effector_relations_create(depsgraph, graph->view_layer, collection);
+ });
}
ListBase *build_collision_relations(Depsgraph *graph,
@@ -185,52 +178,41 @@ ListBase *build_collision_relations(Depsgraph *graph,
unsigned int modifier_type)
{
const ePhysicsRelationType type = modifier_to_relation_type(modifier_type);
- GHash *hash = graph->physics_relations[type];
+ Map<const ID *, ListBase *> *hash = graph->physics_relations[type];
if (hash == nullptr) {
- graph->physics_relations[type] = BLI_ghash_ptr_new("Depsgraph physics relations hash");
+ graph->physics_relations[type] = new Map<const ID *, ListBase *>();
hash = graph->physics_relations[type];
}
- ListBase *relations = reinterpret_cast<ListBase *>(BLI_ghash_lookup(hash, collection));
- if (relations == nullptr) {
+ return hash->lookup_or_add(&collection->id, [&]() {
::Depsgraph *depsgraph = reinterpret_cast<::Depsgraph *>(graph);
- relations = BKE_collision_relations_create(depsgraph, collection, modifier_type);
- BLI_ghash_insert(hash, &collection->id, relations);
- }
- return relations;
-}
-
-namespace {
-
-void free_effector_relations(void *value)
-{
- BKE_effector_relations_free(reinterpret_cast<ListBase *>(value));
+ return BKE_collision_relations_create(depsgraph, collection, modifier_type);
+ });
}
-void free_collision_relations(void *value)
-{
- BKE_collision_relations_free(reinterpret_cast<ListBase *>(value));
-}
-
-} // namespace
-
void clear_physics_relations(Depsgraph *graph)
{
for (int i = 0; i < DEG_PHYSICS_RELATIONS_NUM; i++) {
- if (graph->physics_relations[i]) {
+ Map<const ID *, ListBase *> *hash = graph->physics_relations[i];
+ if (hash) {
const ePhysicsRelationType type = (ePhysicsRelationType)i;
switch (type) {
case DEG_PHYSICS_EFFECTOR:
- BLI_ghash_free(graph->physics_relations[i], nullptr, free_effector_relations);
+ for (ListBase *list : hash->values()) {
+ BKE_effector_relations_free(list);
+ }
break;
case DEG_PHYSICS_COLLISION:
case DEG_PHYSICS_SMOKE_COLLISION:
case DEG_PHYSICS_DYNAMIC_BRUSH:
- BLI_ghash_free(graph->physics_relations[i], nullptr, free_collision_relations);
+ for (ListBase *list : hash->values()) {
+ BKE_collision_relations_free(list);
+ }
break;
case DEG_PHYSICS_RELATIONS_NUM:
break;
}
+ delete hash;
graph->physics_relations[i] = nullptr;
}
}
diff --git a/source/blender/depsgraph/intern/depsgraph_query.cc b/source/blender/depsgraph/intern/depsgraph_query.cc
index 6e85b2e8bd9..3c760e71197 100644
--- a/source/blender/depsgraph/intern/depsgraph_query.cc
+++ b/source/blender/depsgraph/intern/depsgraph_query.cc
@@ -25,10 +25,8 @@
#include "MEM_guardedalloc.h"
-extern "C" {
#include <string.h> // XXX: memcpy
-#include "BLI_ghash.h"
#include "BLI_listbase.h"
#include "BLI_utildefines.h"
@@ -37,8 +35,6 @@ extern "C" {
#include "BKE_idtype.h"
#include "BKE_main.h"
-} /* extern "C" */
-
#include "DNA_object_types.h"
#include "DNA_scene_types.h"
@@ -271,7 +267,7 @@ ID *DEG_get_original_id(ID *id)
return (ID *)id->orig_id;
}
-bool DEG_is_original_id(ID *id)
+bool DEG_is_original_id(const ID *id)
{
/* Some explanation of the logic.
*
@@ -296,17 +292,17 @@ bool DEG_is_original_id(ID *id)
return true;
}
-bool DEG_is_original_object(Object *object)
+bool DEG_is_original_object(const Object *object)
{
return DEG_is_original_id(&object->id);
}
-bool DEG_is_evaluated_id(ID *id)
+bool DEG_is_evaluated_id(const ID *id)
{
return !DEG_is_original_id(id);
}
-bool DEG_is_evaluated_object(Object *object)
+bool DEG_is_evaluated_object(const Object *object)
{
return !DEG_is_original_object(object);
}
@@ -319,7 +315,7 @@ bool DEG_is_fully_evaluated(const struct Depsgraph *depsgraph)
return false;
}
/* Check whether IDs are up to date. */
- if (BLI_gset_len(deg_graph->entry_tags) > 0) {
+ if (!deg_graph->entry_tags.is_empty()) {
return false;
}
return true;
diff --git a/source/blender/depsgraph/intern/depsgraph_query_foreach.cc b/source/blender/depsgraph/intern/depsgraph_query_foreach.cc
index 6409f5b3cea..b68c4b91fcc 100644
--- a/source/blender/depsgraph/intern/depsgraph_query_foreach.cc
+++ b/source/blender/depsgraph/intern/depsgraph_query_foreach.cc
@@ -25,10 +25,7 @@
#include "MEM_guardedalloc.h"
-extern "C" {
-#include "BLI_ghash.h"
#include "BLI_utildefines.h"
-} /* extern "C" */
#include "DNA_object_types.h"
#include "DNA_scene_types.h"
@@ -49,23 +46,9 @@ namespace DEG {
namespace {
typedef deque<OperationNode *> TraversalQueue;
-enum {
- DEG_NODE_VISITED = (1 << 0),
-};
typedef void (*DEGForeachOperation)(OperationNode *op_node, void *user_data);
-void deg_foreach_clear_flags(const Depsgraph *graph)
-{
- for (OperationNode *op_node : graph->operations) {
- op_node->scheduled = false;
- op_node->owner->custom_flags = 0;
- }
- for (IDNode *id_node : graph->id_nodes) {
- id_node->custom_flags = 0;
- }
-}
-
bool deg_foreach_needs_visit(const OperationNode *op_node, const int flags)
{
if (flags & DEG_FOREACH_COMPONENT_IGNORE_TRANSFORM_SOLVERS) {
@@ -76,25 +59,22 @@ bool deg_foreach_needs_visit(const OperationNode *op_node, const int flags)
return true;
}
-void deg_foreach_dependent_operation(const Depsgraph *graph,
- const ID *id,
+void deg_foreach_dependent_operation(const Depsgraph *UNUSED(graph),
+ const IDNode *target_id_node,
eDepsObjectComponentType source_component_type,
int flags,
DEGForeachOperation callback,
void *user_data)
{
- /* Start with getting ID node from the graph. */
- IDNode *target_id_node = graph->find_id_node(id);
if (target_id_node == nullptr) {
/* 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 (ComponentNode *, comp_node, target_id_node->components) {
+ Set<OperationNode *> scheduled;
+ for (ComponentNode *comp_node : target_id_node->components.values()) {
if (source_component_type != DEG_OB_COMP_ANY &&
nodeTypeToObjectComponent(comp_node->type) != source_component_type) {
continue;
@@ -104,12 +84,9 @@ void deg_foreach_dependent_operation(const Depsgraph *graph,
continue;
}
queue.push_back(op_node);
- op_node->scheduled = true;
- op_node->owner->custom_flags |= DEG_NODE_VISITED;
+ scheduled.add(op_node);
}
}
- GHASH_FOREACH_END();
- target_id_node->custom_flags |= DEG_NODE_VISITED;
/* Process the queue. */
while (!queue.empty()) {
/* get next operation node to process. */
@@ -120,8 +97,8 @@ void deg_foreach_dependent_operation(const Depsgraph *graph,
/* Schedule outgoing operation nodes. */
if (op_node->outlinks.size() == 1) {
OperationNode *to_node = (OperationNode *)op_node->outlinks[0]->to;
- if (to_node->scheduled == false && deg_foreach_needs_visit(to_node, flags)) {
- to_node->scheduled = true;
+ if (!scheduled.contains(to_node) && deg_foreach_needs_visit(to_node, flags)) {
+ scheduled.add_new(to_node);
op_node = to_node;
}
else {
@@ -131,9 +108,9 @@ void deg_foreach_dependent_operation(const Depsgraph *graph,
else {
for (Relation *rel : op_node->outlinks) {
OperationNode *to_node = (OperationNode *)rel->to;
- if (to_node->scheduled == false && deg_foreach_needs_visit(to_node, flags)) {
+ if (!scheduled.contains(to_node) && deg_foreach_needs_visit(to_node, flags)) {
queue.push_front(to_node);
- to_node->scheduled = true;
+ scheduled.add_new(to_node);
}
}
break;
@@ -145,17 +122,19 @@ void deg_foreach_dependent_operation(const Depsgraph *graph,
struct ForeachIDComponentData {
DEGForeachIDComponentCallback callback;
void *user_data;
+ IDNode *target_id_node;
+ Set<ComponentNode *> visited;
};
void deg_foreach_dependent_component_callback(OperationNode *op_node, void *user_data_v)
{
ForeachIDComponentData *user_data = reinterpret_cast<ForeachIDComponentData *>(user_data_v);
ComponentNode *comp_node = op_node->owner;
- if ((comp_node->custom_flags & DEG_NODE_VISITED) == 0) {
- IDNode *id_node = comp_node->owner;
+ IDNode *id_node = comp_node->owner;
+ if (id_node != user_data->target_id_node && !user_data->visited.contains(comp_node)) {
user_data->callback(
id_node->id_orig, nodeTypeToObjectComponent(comp_node->type), user_data->user_data);
- comp_node->custom_flags |= DEG_NODE_VISITED;
+ user_data->visited.add_new(comp_node);
}
}
@@ -169,13 +148,20 @@ void deg_foreach_dependent_ID_component(const Depsgraph *graph,
ForeachIDComponentData data;
data.callback = callback;
data.user_data = user_data;
- deg_foreach_dependent_operation(
- graph, id, source_component_type, flags, deg_foreach_dependent_component_callback, &data);
+ data.target_id_node = graph->find_id_node(id);
+ deg_foreach_dependent_operation(graph,
+ data.target_id_node,
+ source_component_type,
+ flags,
+ deg_foreach_dependent_component_callback,
+ &data);
}
struct ForeachIDData {
DEGForeachIDCallback callback;
void *user_data;
+ IDNode *target_id_node;
+ Set<IDNode *> visited;
};
void deg_foreach_dependent_ID_callback(OperationNode *op_node, void *user_data_v)
@@ -183,9 +169,9 @@ void deg_foreach_dependent_ID_callback(OperationNode *op_node, void *user_data_v
ForeachIDData *user_data = reinterpret_cast<ForeachIDData *>(user_data_v);
ComponentNode *comp_node = op_node->owner;
IDNode *id_node = comp_node->owner;
- if ((id_node->custom_flags & DEG_NODE_VISITED) == 0) {
+ if (id_node != user_data->target_id_node && !user_data->visited.contains(id_node)) {
user_data->callback(id_node->id_orig, user_data->user_data);
- id_node->custom_flags |= DEG_NODE_VISITED;
+ user_data->visited.add_new(id_node);
}
}
@@ -197,8 +183,9 @@ void deg_foreach_dependent_ID(const Depsgraph *graph,
ForeachIDData data;
data.callback = callback;
data.user_data = user_data;
+ data.target_id_node = graph->find_id_node(id);
deg_foreach_dependent_operation(
- graph, id, DEG_OB_COMP_ANY, 0, deg_foreach_dependent_ID_callback, &data);
+ graph, data.target_id_node, DEG_OB_COMP_ANY, 0, deg_foreach_dependent_ID_callback, &data);
}
void deg_foreach_ancestor_ID(const Depsgraph *graph,
@@ -213,18 +200,17 @@ void deg_foreach_ancestor_ID(const Depsgraph *graph,
* 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 (ComponentNode *, comp_node, target_id_node->components) {
+ Set<OperationNode *> scheduled;
+ for (ComponentNode *comp_node : target_id_node->components.values()) {
for (OperationNode *op_node : comp_node->operations) {
queue.push_back(op_node);
- op_node->scheduled = true;
+ scheduled.add(op_node);
}
}
- GHASH_FOREACH_END();
- target_id_node->custom_flags |= DEG_NODE_VISITED;
+ Set<IDNode *> visited;
+ visited.add_new(target_id_node);
/* Process the queue. */
while (!queue.empty()) {
/* get next operation node to process. */
@@ -234,18 +220,17 @@ void deg_foreach_ancestor_ID(const Depsgraph *graph,
/* Check whether we need to inform callee about corresponding ID node. */
ComponentNode *comp_node = op_node->owner;
IDNode *id_node = comp_node->owner;
- if ((id_node->custom_flags & DEG_NODE_VISITED) == 0) {
+ if (!visited.contains(id_node)) {
/* TODO(sergey): Is it orig or CoW? */
callback(id_node->id_orig, user_data);
- id_node->custom_flags |= DEG_NODE_VISITED;
+ visited.add_new(id_node);
}
/* Schedule incoming operation nodes. */
if (op_node->inlinks.size() == 1) {
Node *from = op_node->inlinks[0]->from;
if (from->get_class() == NodeClass::OPERATION) {
OperationNode *from_node = (OperationNode *)from;
- if (from_node->scheduled == false) {
- from_node->scheduled = true;
+ if (scheduled.add(from_node)) {
op_node = from_node;
}
else {
@@ -258,9 +243,8 @@ void deg_foreach_ancestor_ID(const Depsgraph *graph,
Node *from = rel->from;
if (from->get_class() == NodeClass::OPERATION) {
OperationNode *from_node = (OperationNode *)from;
- if (from_node->scheduled == false) {
+ if (scheduled.add(from_node)) {
queue.push_front(from_node);
- from_node->scheduled = true;
}
}
}
diff --git a/source/blender/depsgraph/intern/depsgraph_query_iter.cc b/source/blender/depsgraph/intern/depsgraph_query_iter.cc
index 427a16adfc4..1eb07206465 100644
--- a/source/blender/depsgraph/intern/depsgraph_query_iter.cc
+++ b/source/blender/depsgraph/intern/depsgraph_query_iter.cc
@@ -28,15 +28,14 @@
#include "MEM_guardedalloc.h"
-extern "C" {
-#include "BKE_anim.h"
+#include "BKE_duplilist.h"
#include "BKE_idprop.h"
#include "BKE_layer.h"
#include "BKE_node.h"
#include "BKE_object.h"
+
#include "BLI_math.h"
#include "BLI_utildefines.h"
-} /* extern "C" */
#include "DNA_object_types.h"
#include "DNA_scene_types.h"
@@ -103,7 +102,10 @@ static bool deg_object_hide_original(eEvaluationMode eval_mode, Object *ob, Dupl
* by its parent. Ideally this should not be needed, but due to the wrong
* dependency direction in the data design there is no way to keep the object
* visible otherwise. The better solution eventually would be for objects
- * to specify which object they instance, instead of through parenting. */
+ * to specify which object they instance, instead of through parenting.
+ *
+ * This function should not be used for metaballs. They have custom visibility rules, as hiding
+ * the base metaball will also hide all the other balls in the group. */
if (eval_mode == DAG_EVAL_RENDER || dob) {
const int hide_original_types = OB_DUPLIVERTS | OB_DUPLIFACES;
@@ -215,7 +217,7 @@ void deg_iterator_objects_step(BLI_Iterator *iter, DEG::IDNode *id_node)
if (data->flag & DEG_ITER_OBJECT_FLAG_VISIBLE) {
ob_visibility = BKE_object_visibility(object, data->eval_mode);
- if (deg_object_hide_original(data->eval_mode, object, nullptr)) {
+ if (object->type != OB_MBALL && deg_object_hide_original(data->eval_mode, object, nullptr)) {
return;
}
}
diff --git a/source/blender/depsgraph/intern/depsgraph_registry.cc b/source/blender/depsgraph/intern/depsgraph_registry.cc
index ad60b1bc4cf..3b0a0b3ea19 100644
--- a/source/blender/depsgraph/intern/depsgraph_registry.cc
+++ b/source/blender/depsgraph/intern/depsgraph_registry.cc
@@ -29,46 +29,33 @@
namespace DEG {
-typedef set<Depsgraph *> DepsgraphStorage;
-typedef map<Main *, DepsgraphStorage> MainDepsgraphMap;
-
-static MainDepsgraphMap g_graph_registry;
+static Map<Main *, VectorSet<Depsgraph *>> g_graph_registry;
void register_graph(Depsgraph *depsgraph)
{
Main *bmain = depsgraph->bmain;
- MainDepsgraphMap::iterator it = g_graph_registry.find(bmain);
- if (it == g_graph_registry.end()) {
- it = g_graph_registry.insert(make_pair(bmain, DepsgraphStorage())).first;
- }
- DepsgraphStorage &storage = it->second;
- storage.insert(depsgraph);
+ g_graph_registry.lookup_or_add_default(bmain).add_new(depsgraph);
}
void unregister_graph(Depsgraph *depsgraph)
{
Main *bmain = depsgraph->bmain;
- MainDepsgraphMap::iterator it = g_graph_registry.find(bmain);
- BLI_assert(it != g_graph_registry.end());
-
- // Remove dependency graph from storage.
- DepsgraphStorage &storage = it->second;
- storage.erase(depsgraph);
+ VectorSet<Depsgraph *> &graphs = g_graph_registry.lookup(bmain);
+ graphs.remove(depsgraph);
// If this was the last depsgraph associated with the main, remove the main entry as well.
- if (storage.empty()) {
- g_graph_registry.erase(bmain);
+ if (graphs.is_empty()) {
+ g_graph_registry.remove(bmain);
}
}
-const set<Depsgraph *> &get_all_registered_graphs(Main *bmain)
+ArrayRef<Depsgraph *> get_all_registered_graphs(Main *bmain)
{
- MainDepsgraphMap::iterator it = g_graph_registry.find(bmain);
- if (it == g_graph_registry.end()) {
- static DepsgraphStorage empty_storage;
- return empty_storage;
+ VectorSet<Depsgraph *> *graphs = g_graph_registry.lookup_ptr(bmain);
+ if (graphs != nullptr) {
+ return *graphs;
}
- return it->second;
+ return {};
}
} // namespace DEG
diff --git a/source/blender/depsgraph/intern/depsgraph_registry.h b/source/blender/depsgraph/intern/depsgraph_registry.h
index 7517b6a0b2a..f8e5b9543f2 100644
--- a/source/blender/depsgraph/intern/depsgraph_registry.h
+++ b/source/blender/depsgraph/intern/depsgraph_registry.h
@@ -33,6 +33,6 @@ struct Depsgraph;
void register_graph(Depsgraph *depsgraph);
void unregister_graph(Depsgraph *depsgraph);
-const set<Depsgraph *> &get_all_registered_graphs(Main *bmain);
+ArrayRef<Depsgraph *> get_all_registered_graphs(Main *bmain);
} // namespace DEG
diff --git a/source/blender/depsgraph/intern/depsgraph_relation.cc b/source/blender/depsgraph/intern/depsgraph_relation.cc
index cff62540ca8..a4ec48658f5 100644
--- a/source/blender/depsgraph/intern/depsgraph_relation.cc
+++ b/source/blender/depsgraph/intern/depsgraph_relation.cc
@@ -30,12 +30,6 @@
namespace DEG {
-/* TODO(sergey): Find a better place for this. */
-template<typename T> static void remove_from_vector(vector<T> *vector, const T &value)
-{
- vector->erase(std::remove(vector->begin(), vector->end(), value), vector->end());
-}
-
Relation::Relation(Node *from, Node *to, const char *description)
: from(from), to(to), name(description), flag(0)
{
@@ -52,8 +46,8 @@ Relation::Relation(Node *from, Node *to, const char *description)
*
* - Un-registering relation is not a cheap operation, so better to have it
* as an explicit call if we need this. */
- from->outlinks.push_back(this);
- to->inlinks.push_back(this);
+ from->outlinks.append(this);
+ to->inlinks.append(this);
}
Relation::~Relation()
@@ -66,8 +60,8 @@ void Relation::unlink()
{
/* Sanity check. */
BLI_assert(from != nullptr && to != nullptr);
- remove_from_vector(&from->outlinks, this);
- remove_from_vector(&to->inlinks, this);
+ from->outlinks.remove_first_occurrence_and_reorder(this);
+ to->inlinks.remove_first_occurrence_and_reorder(this);
}
} // namespace DEG
diff --git a/source/blender/depsgraph/intern/depsgraph_tag.cc b/source/blender/depsgraph/intern/depsgraph_tag.cc
index 3b0782cd5d6..0ee86088e43 100644
--- a/source/blender/depsgraph/intern/depsgraph_tag.cc
+++ b/source/blender/depsgraph/intern/depsgraph_tag.cc
@@ -33,7 +33,6 @@
#include "BLI_task.h"
#include "BLI_utildefines.h"
-extern "C" {
#include "DNA_anim_types.h"
#include "DNA_curve_types.h"
#include "DNA_key_types.h"
@@ -44,7 +43,7 @@ extern "C" {
#include "DNA_screen_types.h"
#include "DNA_windowmanager_types.h"
-#include "BKE_animsys.h"
+#include "BKE_anim_data.h"
#include "BKE_global.h"
#include "BKE_idtype.h"
#include "BKE_node.h"
@@ -54,7 +53,6 @@ extern "C" {
#define new new_
#include "BKE_screen.h"
#undef new
-} /* extern "C" */
#include "DEG_depsgraph.h"
#include "DEG_depsgraph_debug.h"
@@ -495,13 +493,13 @@ void deg_graph_node_tag_zero(Main *bmain,
ID *id = id_node->id_orig;
/* TODO(sergey): Which recalc flags to set here? */
id_node->id_cow->recalc |= deg_recalc_flags_for_legacy_zero();
- GHASH_FOREACH_BEGIN (ComponentNode *, comp_node, id_node->components) {
+
+ for (ComponentNode *comp_node : id_node->components.values()) {
if (comp_node->type == NodeType::ANIMATION) {
continue;
}
comp_node->tag_update(graph, update_source);
}
- GHASH_FOREACH_END();
deg_graph_id_tag_legacy_compat(bmain, graph, id, (IDRecalcFlag)0, update_source);
}
@@ -622,6 +620,10 @@ void id_tag_update(Main *bmain, ID *id, int flag, eUpdateSource update_source)
for (DEG::Depsgraph *depsgraph : DEG::get_all_registered_graphs(bmain)) {
graph_id_tag_update(bmain, depsgraph, id, flag, update_source);
}
+
+ /* Accumulate all tags for an ID between two undo steps, so they can be
+ * replayed for undo. */
+ id->recalc_after_undo_push |= deg_recalc_flags_effective(NULL, flag);
}
void graph_id_tag_update(
@@ -820,13 +822,10 @@ void DEG_ids_check_recalc(
static void deg_graph_clear_id_recalc_flags(ID *id)
{
- /* Keep incremental track of used recalc flags, to get proper update when undoing. */
- id->recalc_undo_accumulated |= id->recalc;
id->recalc &= ~ID_RECALC_ALL;
bNodeTree *ntree = ntreeFromID(id);
/* Clear embedded node trees too. */
if (ntree) {
- ntree->id.recalc_undo_accumulated |= ntree->id.recalc;
ntree->id.recalc &= ~ID_RECALC_ALL;
}
/* XXX And what about scene's master collection here? */
diff --git a/source/blender/depsgraph/intern/depsgraph_type.cc b/source/blender/depsgraph/intern/depsgraph_type.cc
index 559bf8dfdab..92d775b0ae4 100644
--- a/source/blender/depsgraph/intern/depsgraph_type.cc
+++ b/source/blender/depsgraph/intern/depsgraph_type.cc
@@ -25,7 +25,6 @@
#include <cstdlib> // for BLI_assert()
-#include "BLI_ghash.h"
#include "BLI_utildefines.h"
#include "DNA_customdata_types.h"
diff --git a/source/blender/depsgraph/intern/depsgraph_type.h b/source/blender/depsgraph/intern/depsgraph_type.h
index fbf5c2fd381..7016d07ae72 100644
--- a/source/blender/depsgraph/intern/depsgraph_type.h
+++ b/source/blender/depsgraph/intern/depsgraph_type.h
@@ -38,9 +38,14 @@
#include <map>
#include <set>
#include <string>
-#include <unordered_map>
#include <vector>
+#include "BLI_map.hh"
+#include "BLI_set.hh"
+#include "BLI_string_ref.hh"
+#include "BLI_vector.hh"
+#include "BLI_vector_set.hh"
+
struct Depsgraph;
struct CustomData_MeshMasks;
@@ -48,12 +53,19 @@ struct CustomData_MeshMasks;
namespace DEG {
/* Commonly used types. */
+using BLI::ArrayRef;
+using BLI::Map;
+using BLI::Set;
+using BLI::StringRef;
+using BLI::StringRefNull;
+using BLI::Vector;
+using BLI::VectorSet;
using std::deque;
using std::map;
using std::pair;
using std::set;
using std::string;
-using std::unordered_map;
+using std::unique_ptr;
using std::vector;
/* Commonly used functions. */
diff --git a/source/blender/depsgraph/intern/eval/deg_eval.cc b/source/blender/depsgraph/intern/eval/deg_eval.cc
index 4540cda7e99..189beb506b3 100644
--- a/source/blender/depsgraph/intern/eval/deg_eval.cc
+++ b/source/blender/depsgraph/intern/eval/deg_eval.cc
@@ -28,7 +28,6 @@
#include "PIL_time.h"
#include "BLI_compiler_attrs.h"
-#include "BLI_ghash.h"
#include "BLI_gsqueue.h"
#include "BLI_task.h"
#include "BLI_utildefines.h"
@@ -61,19 +60,17 @@ namespace {
struct DepsgraphEvalState;
-void deg_task_run_func(TaskPool *pool, void *taskdata, int thread_id);
+void deg_task_run_func(TaskPool *pool, void *taskdata);
template<typename ScheduleFunction, typename... ScheduleFunctionArgs>
void schedule_children(DepsgraphEvalState *state,
OperationNode *node,
- const int thread_id,
ScheduleFunction *schedule_function,
ScheduleFunctionArgs... schedule_function_args);
-void schedule_node_to_pool(OperationNode *node, const int thread_id, TaskPool *pool)
+void schedule_node_to_pool(OperationNode *node, const int UNUSED(thread_id), TaskPool *pool)
{
- BLI_task_pool_push_from_thread(
- pool, deg_task_run_func, node, false, TASK_PRIORITY_HIGH, thread_id);
+ BLI_task_pool_push(pool, deg_task_run_func, node, false, NULL);
}
/* Denotes which part of dependency graph is being evaluated. */
@@ -117,9 +114,9 @@ void evaluate_node(const DepsgraphEvalState *state, OperationNode *operation_nod
}
}
-void deg_task_run_func(TaskPool *pool, void *taskdata, int thread_id)
+void deg_task_run_func(TaskPool *pool, void *taskdata)
{
- void *userdata_v = BLI_task_pool_userdata(pool);
+ void *userdata_v = BLI_task_pool_user_data(pool);
DepsgraphEvalState *state = (DepsgraphEvalState *)userdata_v;
/* Evaluate node. */
@@ -127,9 +124,7 @@ void deg_task_run_func(TaskPool *pool, void *taskdata, int thread_id)
evaluate_node(state, operation_node);
/* Schedule children. */
- BLI_task_pool_delayed_push_begin(pool, thread_id);
- schedule_children(state, operation_node, thread_id, schedule_node_to_pool, pool);
- BLI_task_pool_delayed_push_end(pool, thread_id);
+ schedule_children(state, operation_node, schedule_node_to_pool, pool);
}
bool check_operation_node_visible(OperationNode *op_node)
@@ -239,7 +234,6 @@ template<typename ScheduleFunction, typename... ScheduleFunctionArgs>
void schedule_node(DepsgraphEvalState *state,
OperationNode *node,
bool dec_parents,
- const int thread_id,
ScheduleFunction *schedule_function,
ScheduleFunctionArgs... schedule_function_args)
{
@@ -272,11 +266,11 @@ void schedule_node(DepsgraphEvalState *state,
if (!is_scheduled) {
if (node->is_noop()) {
/* skip NOOP node, schedule children right away */
- schedule_children(state, node, thread_id, schedule_function, schedule_function_args...);
+ schedule_children(state, node, schedule_function, schedule_function_args...);
}
else {
/* children are scheduled once this task is completed */
- schedule_function(node, thread_id, schedule_function_args...);
+ schedule_function(node, 0, schedule_function_args...);
}
}
}
@@ -287,14 +281,13 @@ void schedule_graph(DepsgraphEvalState *state,
ScheduleFunctionArgs... schedule_function_args)
{
for (OperationNode *node : state->graph->operations) {
- schedule_node(state, node, false, -1, schedule_function, schedule_function_args...);
+ schedule_node(state, node, false, schedule_function, schedule_function_args...);
}
}
template<typename ScheduleFunction, typename... ScheduleFunctionArgs>
void schedule_children(DepsgraphEvalState *state,
OperationNode *node,
- const int thread_id,
ScheduleFunction *schedule_function,
ScheduleFunctionArgs... schedule_function_args)
{
@@ -308,7 +301,6 @@ void schedule_children(DepsgraphEvalState *state,
schedule_node(state,
child,
(rel->flag & RELATION_FLAG_CYCLIC) == 0,
- thread_id,
schedule_function,
schedule_function_args...);
}
@@ -331,7 +323,7 @@ void evaluate_graph_single_threaded(DepsgraphEvalState *state)
BLI_gsqueue_pop(evaluation_queue, &operation_node);
evaluate_node(state, operation_node);
- schedule_children(state, operation_node, 0, schedule_node_to_queue, evaluation_queue);
+ schedule_children(state, operation_node, schedule_node_to_queue, evaluation_queue);
}
BLI_gsqueue_free(evaluation_queue);
@@ -355,6 +347,16 @@ void depsgraph_ensure_view_layer(Depsgraph *graph)
} // namespace
+static TaskPool *deg_evaluate_task_pool_create(DepsgraphEvalState *state)
+{
+ if (G.debug & G_DEBUG_DEPSGRAPH_NO_THREADS) {
+ return BLI_task_pool_create_no_threads(state);
+ }
+ else {
+ return BLI_task_pool_create_suspended(state, TASK_PRIORITY_HIGH);
+ }
+}
+
/**
* Evaluate all nodes tagged for updating,
* \warning This is usually done as part of main loop, but may also be
@@ -365,7 +367,7 @@ void depsgraph_ensure_view_layer(Depsgraph *graph)
void deg_evaluate_on_refresh(Depsgraph *graph)
{
/* Nothing to update, early out. */
- if (BLI_gset_len(graph->entry_tags) == 0) {
+ if (graph->entry_tags.is_empty()) {
return;
}
@@ -378,30 +380,20 @@ void deg_evaluate_on_refresh(Depsgraph *graph)
state.graph = graph;
state.do_stats = graph->debug.do_time_debug();
state.need_single_thread_pass = false;
- /* Set up task scheduler and pull for threaded evaluation. */
- TaskScheduler *task_scheduler;
- bool need_free_scheduler;
- if (G.debug & G_DEBUG_DEPSGRAPH_NO_THREADS) {
- task_scheduler = BLI_task_scheduler_create(1);
- need_free_scheduler = true;
- }
- else {
- task_scheduler = BLI_task_scheduler_get();
- need_free_scheduler = false;
- }
- TaskPool *task_pool = BLI_task_pool_create_suspended(task_scheduler, &state);
/* Prepare all nodes for evaluation. */
initialize_execution(&state, graph);
/* Do actual evaluation now. */
-
/* First, process all Copy-On-Write nodes. */
state.stage = EvaluationStage::COPY_ON_WRITE;
+ TaskPool *task_pool = deg_evaluate_task_pool_create(&state);
schedule_graph(&state, schedule_node_to_pool, task_pool);
- BLI_task_pool_work_wait_and_reset(task_pool);
+ BLI_task_pool_work_and_wait(task_pool);
+ BLI_task_pool_free(task_pool);
/* After that, process all other nodes. */
state.stage = EvaluationStage::THREADED_EVALUATION;
+ task_pool = deg_evaluate_task_pool_create(&state);
schedule_graph(&state, schedule_node_to_pool, task_pool);
BLI_task_pool_work_and_wait(task_pool);
BLI_task_pool_free(task_pool);
@@ -419,9 +411,6 @@ void deg_evaluate_on_refresh(Depsgraph *graph)
}
/* Clear any uncleared tags - just in case. */
deg_graph_clear_tags(graph);
- if (need_free_scheduler) {
- BLI_task_scheduler_free(task_scheduler);
- }
graph->is_evaluating = false;
graph->debug.end_graph_evaluation();
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 f51def4caa9..2f2e05d410e 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
@@ -53,7 +53,6 @@
#include "MEM_guardedalloc.h"
-extern "C" {
#include "DNA_ID.h"
#include "DNA_anim_types.h"
#include "DNA_armature_types.h"
@@ -82,6 +81,7 @@ extern "C" {
#endif
#include "BKE_action.h"
+#include "BKE_anim_data.h"
#include "BKE_animsys.h"
#include "BKE_armature.h"
#include "BKE_editmesh.h"
@@ -91,7 +91,6 @@ extern "C" {
#include "BKE_pointcache.h"
#include "BKE_sequencer.h"
#include "BKE_sound.h"
-}
#include "intern/builder/deg_builder.h"
#include "intern/builder/deg_builder_nodes.h"
diff --git a/source/blender/depsgraph/intern/eval/deg_eval_flush.cc b/source/blender/depsgraph/intern/eval/deg_eval_flush.cc
index dd72bc22a70..ee543dcf25d 100644
--- a/source/blender/depsgraph/intern/eval/deg_eval_flush.cc
+++ b/source/blender/depsgraph/intern/eval/deg_eval_flush.cc
@@ -27,7 +27,6 @@
#include <cmath>
-#include "BLI_ghash.h"
#include "BLI_listbase.h"
#include "BLI_math_vector.h"
#include "BLI_task.h"
@@ -36,12 +35,10 @@
#include "BKE_object.h"
#include "BKE_scene.h"
-extern "C" {
#include "DNA_object_types.h"
#include "DNA_scene_types.h"
#include "DRW_engine.h"
-} /* extern "C" */
#include "DEG_depsgraph.h"
@@ -94,9 +91,9 @@ void flush_init_id_node_func(void *__restrict data_v,
Depsgraph *graph = (Depsgraph *)data_v;
IDNode *id_node = graph->id_nodes[i];
id_node->custom_flags = ID_STATE_NONE;
- GHASH_FOREACH_BEGIN (ComponentNode *, comp_node, id_node->components)
+ for (ComponentNode *comp_node : id_node->components.values()) {
comp_node->custom_flags = COMPONENT_STATE_NONE;
- GHASH_FOREACH_END();
+ }
}
BLI_INLINE void flush_prepare(Depsgraph *graph)
@@ -116,7 +113,7 @@ BLI_INLINE void flush_prepare(Depsgraph *graph)
BLI_INLINE void flush_schedule_entrypoints(Depsgraph *graph, FlushQueue *queue)
{
- GSET_FOREACH_BEGIN (OperationNode *, op_node, graph->entry_tags) {
+ for (OperationNode *op_node : graph->entry_tags) {
queue->push_back(op_node);
op_node->scheduled = true;
DEG_DEBUG_PRINTF((::Depsgraph *)graph,
@@ -124,7 +121,6 @@ BLI_INLINE void flush_schedule_entrypoints(Depsgraph *graph, FlushQueue *queue)
"Operation is entry point for update: %s\n",
op_node->identifier().c_str());
}
- GSET_FOREACH_END();
}
BLI_INLINE void flush_handle_id_node(IDNode *id_node)
@@ -172,16 +168,17 @@ BLI_INLINE void flush_handle_component_node(IDNode *id_node,
*/
BLI_INLINE OperationNode *flush_schedule_children(OperationNode *op_node, FlushQueue *queue)
{
+ if (op_node->flag & DEPSOP_FLAG_USER_MODIFIED) {
+ IDNode *id_node = op_node->owner->owner;
+ id_node->is_user_modified = true;
+ }
+
OperationNode *result = nullptr;
for (Relation *rel : op_node->outlinks) {
/* Flush is forbidden, completely. */
if (rel->flag & RELATION_FLAG_NO_FLUSH) {
continue;
}
- if (op_node->flag & DEPSOP_FLAG_USER_MODIFIED) {
- IDNode *id_node = op_node->owner->owner;
- id_node->is_user_modified = true;
- }
/* Relation only allows flushes on user changes, but the node was not
* affected by user. */
if ((rel->flag & RELATION_FLAG_FLUSH_USER_EDIT_ONLY) &&
@@ -230,7 +227,7 @@ void flush_editors_id_update(Depsgraph *graph, const DEGEditorUpdateContext *upd
ID *id_orig = id_node->id_orig;
ID *id_cow = id_node->id_cow;
/* Gather recalc flags from all changed components. */
- GHASH_FOREACH_BEGIN (ComponentNode *, comp_node, id_node->components) {
+ for (DEG::ComponentNode *comp_node : id_node->components.values()) {
if (comp_node->custom_flags != COMPONENT_STATE_DONE) {
continue;
}
@@ -238,7 +235,6 @@ void flush_editors_id_update(Depsgraph *graph, const DEGEditorUpdateContext *upd
BLI_assert(factory != nullptr);
id_cow->recalc |= factory->id_recalc_tag();
}
- GHASH_FOREACH_END();
DEG_DEBUG_PRINTF((::Depsgraph *)graph,
EVAL,
"Accumulated recalc bits for %s: %u\n",
@@ -306,7 +302,7 @@ void invalidate_tagged_evaluated_data(Depsgraph *graph)
if (!deg_copy_on_write_is_expanded(id_cow)) {
continue;
}
- GHASH_FOREACH_BEGIN (ComponentNode *, comp_node, id_node->components) {
+ for (ComponentNode *comp_node : id_node->components.values()) {
if (comp_node->custom_flags != COMPONENT_STATE_DONE) {
continue;
}
@@ -321,7 +317,6 @@ void invalidate_tagged_evaluated_data(Depsgraph *graph)
break;
}
}
- GHASH_FOREACH_END();
}
#else
(void)graph;
@@ -346,7 +341,7 @@ void deg_graph_flush_updates(Main *bmain, Depsgraph *graph)
graph->ctime = ctime;
time_source->tag_update(graph, DEG::DEG_UPDATE_SOURCE_TIME);
}
- if (BLI_gset_len(graph->entry_tags) == 0) {
+ if (graph->entry_tags.is_empty()) {
return;
}
/* Reset all flags, get ready for the flush. */
@@ -392,7 +387,7 @@ void deg_graph_clear_tags(Depsgraph *graph)
DEPSOP_FLAG_USER_MODIFIED);
}
/* Clear any entry tags which haven't been flushed. */
- BLI_gset_clear(graph->entry_tags, nullptr);
+ graph->entry_tags.clear();
}
} // namespace DEG
diff --git a/source/blender/depsgraph/intern/eval/deg_eval_runtime_backup.cc b/source/blender/depsgraph/intern/eval/deg_eval_runtime_backup.cc
index e141925725b..c3733cb235c 100644
--- a/source/blender/depsgraph/intern/eval/deg_eval_runtime_backup.cc
+++ b/source/blender/depsgraph/intern/eval/deg_eval_runtime_backup.cc
@@ -32,7 +32,7 @@
namespace DEG {
RuntimeBackup::RuntimeBackup(const Depsgraph *depsgraph)
- : have_backup(nullptr),
+ : have_backup(false),
animation_backup(depsgraph),
scene_backup(depsgraph),
sound_backup(depsgraph),
diff --git a/source/blender/depsgraph/intern/eval/deg_eval_runtime_backup_object.cc b/source/blender/depsgraph/intern/eval/deg_eval_runtime_backup_object.cc
index 2f45ea45197..2b172f824b6 100644
--- a/source/blender/depsgraph/intern/eval/deg_eval_runtime_backup_object.cc
+++ b/source/blender/depsgraph/intern/eval/deg_eval_runtime_backup_object.cc
@@ -166,7 +166,7 @@ void ObjectRuntimeBackup::restore_modifier_runtime_data(Object *object)
if (value.second == nullptr) {
continue;
}
- const ModifierTypeInfo *modifier_type_info = modifierType_getInfo(modifier_data_id.type);
+ const ModifierTypeInfo *modifier_type_info = BKE_modifier_get_info(modifier_data_id.type);
BLI_assert(modifier_type_info != nullptr);
modifier_type_info->freeRuntimeData(runtime);
}
diff --git a/source/blender/depsgraph/intern/eval/deg_eval_runtime_backup_scene.cc b/source/blender/depsgraph/intern/eval/deg_eval_runtime_backup_scene.cc
index 36d0138f697..32b2d0b93c1 100644
--- a/source/blender/depsgraph/intern/eval/deg_eval_runtime_backup_scene.cc
+++ b/source/blender/depsgraph/intern/eval/deg_eval_runtime_backup_scene.cc
@@ -46,7 +46,7 @@ void SceneBackup::reset()
void SceneBackup::init_from_scene(Scene *scene)
{
- BKE_sound_lock_scene(scene);
+ BKE_sound_lock();
sound_scene = scene->sound_scene;
playback_handle = scene->playback_handle;
@@ -80,7 +80,7 @@ void SceneBackup::restore_to_scene(Scene *scene)
sequencer_backup.restore_to_scene(scene);
- BKE_sound_unlock_scene(scene);
+ BKE_sound_unlock();
reset();
}
diff --git a/source/blender/depsgraph/intern/eval/deg_eval_stats.cc b/source/blender/depsgraph/intern/eval/deg_eval_stats.cc
index f164560ac24..9d3b1356570 100644
--- a/source/blender/depsgraph/intern/eval/deg_eval_stats.cc
+++ b/source/blender/depsgraph/intern/eval/deg_eval_stats.cc
@@ -23,7 +23,6 @@
#include "intern/eval/deg_eval_stats.h"
-#include "BLI_ghash.h"
#include "BLI_utildefines.h"
#include "intern/depsgraph.h"
@@ -41,10 +40,9 @@ void deg_eval_stats_aggregate(Depsgraph *graph)
* Those are not filled in by the evaluation engine. */
for (Node *node : graph->id_nodes) {
IDNode *id_node = (IDNode *)node;
- GHASH_FOREACH_BEGIN (ComponentNode *, comp_node, id_node->components) {
+ for (ComponentNode *comp_node : id_node->components.values()) {
comp_node->stats.reset_current();
}
- GHASH_FOREACH_END();
id_node->stats.reset_current();
}
/* Now accumulate operation timings to components and IDs. */
diff --git a/source/blender/depsgraph/intern/node/deg_node.cc b/source/blender/depsgraph/intern/node/deg_node.cc
index d95e05a6f4f..10760d3170b 100644
--- a/source/blender/depsgraph/intern/node/deg_node.cc
+++ b/source/blender/depsgraph/intern/node/deg_node.cc
@@ -114,6 +114,8 @@ const char *nodeTypeAsString(NodeType type)
return "ARMATURE";
case NodeType::GENERIC_DATABLOCK:
return "GENERIC_DATABLOCK";
+ case NodeType::SIMULATION:
+ return "SIMULATION";
/* Total number of meaningful node types. */
case NodeType::NUM_TYPES:
@@ -172,6 +174,7 @@ eDepsSceneComponentType nodeTypeToSceneComponent(NodeType type)
case NodeType::SHADING:
case NodeType::CACHE:
case NodeType::PROXY:
+ case NodeType::SIMULATION:
return DEG_SCENE_COMP_PARAMETERS;
}
BLI_assert(!"Unhandled node type, not suppsed to happen.");
@@ -245,6 +248,7 @@ eDepsObjectComponentType nodeTypeToObjectComponent(NodeType type)
case NodeType::BATCH_CACHE:
case NodeType::DUPLI:
case NodeType::SYNCHRONIZATION:
+ case NodeType::SIMULATION:
case NodeType::UNDEFINED:
case NodeType::NUM_TYPES:
return DEG_OB_COMP_PARAMETERS;
diff --git a/source/blender/depsgraph/intern/node/deg_node.h b/source/blender/depsgraph/intern/node/deg_node.h
index ffa37341ea6..f0ce38ddeae 100644
--- a/source/blender/depsgraph/intern/node/deg_node.h
+++ b/source/blender/depsgraph/intern/node/deg_node.h
@@ -127,6 +127,8 @@ enum class NodeType {
DUPLI,
/* Synchronization back to original datablock. */
SYNCHRONIZATION,
+ /* Simulation component. */
+ SIMULATION,
/* Total number of meaningful node types. */
NUM_TYPES,
@@ -163,7 +165,7 @@ struct Node {
* The reason why all depsgraph nodes are descended from this type (apart
* from basic serialization benefits - from the typeinfo) is that we can
* have relationships between these nodes. */
- typedef vector<Relation *> Relations;
+ typedef Vector<Relation *> Relations;
string name; /* Identifier - mainly for debugging purposes. */
NodeType type; /* Structural type of node. */
diff --git a/source/blender/depsgraph/intern/node/deg_node_component.cc b/source/blender/depsgraph/intern/node/deg_node_component.cc
index 54796b8965b..f4d042fecf9 100644
--- a/source/blender/depsgraph/intern/node/deg_node_component.cc
+++ b/source/blender/depsgraph/intern/node/deg_node_component.cc
@@ -26,14 +26,11 @@
#include <cstring> /* required for STREQ later on. */
#include <stdio.h>
-#include "BLI_ghash.h"
#include "BLI_utildefines.h"
-extern "C" {
#include "DNA_object_types.h"
#include "BKE_action.h"
-} /* extern "C" */
#include "intern/node/deg_node_factory.h"
#include "intern/node/deg_node_id.h"
@@ -72,41 +69,10 @@ bool ComponentNode::OperationIDKey::operator==(const OperationIDKey &other) cons
return (opcode == other.opcode) && (STREQ(name, other.name)) && (name_tag == other.name_tag);
}
-static unsigned int comp_node_hash_key(const void *key_v)
-{
- const ComponentNode::OperationIDKey *key =
- reinterpret_cast<const ComponentNode::OperationIDKey *>(key_v);
- int opcode_as_int = static_cast<int>(key->opcode);
- return BLI_ghashutil_combine_hash(BLI_ghashutil_uinthash(opcode_as_int),
- BLI_ghashutil_strhash_p(key->name));
-}
-
-static bool comp_node_hash_key_cmp(const void *a, const void *b)
-{
- const ComponentNode::OperationIDKey *key_a =
- reinterpret_cast<const ComponentNode::OperationIDKey *>(a);
- const ComponentNode::OperationIDKey *key_b =
- reinterpret_cast<const ComponentNode::OperationIDKey *>(b);
- return !(*key_a == *key_b);
-}
-
-static void comp_node_hash_key_free(void *key_v)
-{
- typedef ComponentNode::OperationIDKey OperationIDKey;
- OperationIDKey *key = reinterpret_cast<OperationIDKey *>(key_v);
- OBJECT_GUARDED_DELETE(key, OperationIDKey);
-}
-
-static void comp_node_hash_value_free(void *value_v)
-{
- OperationNode *op_node = reinterpret_cast<OperationNode *>(value_v);
- OBJECT_GUARDED_DELETE(op_node, OperationNode);
-}
-
ComponentNode::ComponentNode()
: entry_operation(nullptr), exit_operation(nullptr), affects_directly_visible(false)
{
- operations_map = BLI_ghash_new(comp_node_hash_key, comp_node_hash_key_cmp, "Depsgraph id hash");
+ operations_map = new Map<ComponentNode::OperationIDKey, OperationNode *>();
}
/* Initialize 'component' node - from pointer data given */
@@ -121,7 +87,7 @@ ComponentNode::~ComponentNode()
{
clear_operations();
if (operations_map != nullptr) {
- BLI_ghash_free(operations_map, comp_node_hash_key_free, comp_node_hash_value_free);
+ delete operations_map;
}
}
@@ -137,7 +103,7 @@ OperationNode *ComponentNode::find_operation(OperationIDKey key) const
{
OperationNode *node = nullptr;
if (operations_map != nullptr) {
- node = (OperationNode *)BLI_ghash_lookup(operations_map, &key);
+ node = operations_map->lookup_default(key, nullptr);
}
else {
for (OperationNode *op_node : operations) {
@@ -203,8 +169,8 @@ OperationNode *ComponentNode::add_operation(const DepsEvalOperationCb &op,
op_node = (OperationNode *)factory->create_node(this->owner->id_orig, "", name);
/* register opnode in this component's operation set */
- OperationIDKey *key = OBJECT_GUARDED_NEW(OperationIDKey, opcode, name, name_tag);
- BLI_ghash_insert(operations_map, key, op_node);
+ OperationIDKey key(opcode, name, name_tag);
+ operations_map->add(key, op_node);
/* set backlink */
op_node->owner = this;
@@ -242,7 +208,10 @@ void ComponentNode::set_exit_operation(OperationNode *op_node)
void ComponentNode::clear_operations()
{
if (operations_map != nullptr) {
- BLI_ghash_clear(operations_map, comp_node_hash_key_free, comp_node_hash_value_free);
+ for (OperationNode *op_node : operations_map->values()) {
+ OBJECT_GUARDED_DELETE(op_node, OperationNode);
+ }
+ operations_map->clear();
}
for (OperationNode *op_node : operations) {
OBJECT_GUARDED_DELETE(op_node, OperationNode);
@@ -261,10 +230,9 @@ void ComponentNode::tag_update(Depsgraph *graph, eUpdateSource source)
}
// It is possible that tag happens before finalization.
if (operations_map != nullptr) {
- GHASH_FOREACH_BEGIN (OperationNode *, op_node, operations_map) {
+ for (OperationNode *op_node : operations_map->values()) {
op_node->tag_update(graph, source);
}
- GHASH_FOREACH_END();
}
}
@@ -273,13 +241,12 @@ OperationNode *ComponentNode::get_entry_operation()
if (entry_operation) {
return entry_operation;
}
- else if (operations_map != nullptr && BLI_ghash_len(operations_map) == 1) {
+ else if (operations_map != nullptr && operations_map->size() == 1) {
OperationNode *op_node = nullptr;
/* TODO(sergey): This is somewhat slow. */
- GHASH_FOREACH_BEGIN (OperationNode *, tmp, operations_map) {
+ for (OperationNode *tmp : operations_map->values()) {
op_node = tmp;
}
- GHASH_FOREACH_END();
/* Cache for the subsequent usage. */
entry_operation = op_node;
return op_node;
@@ -295,13 +262,12 @@ OperationNode *ComponentNode::get_exit_operation()
if (exit_operation) {
return exit_operation;
}
- else if (operations_map != nullptr && BLI_ghash_len(operations_map) == 1) {
+ else if (operations_map != nullptr && operations_map->size() == 1) {
OperationNode *op_node = nullptr;
/* TODO(sergey): This is somewhat slow. */
- GHASH_FOREACH_BEGIN (OperationNode *, tmp, operations_map) {
+ for (OperationNode *tmp : operations_map->values()) {
op_node = tmp;
}
- GHASH_FOREACH_END();
/* Cache for the subsequent usage. */
exit_operation = op_node;
return op_node;
@@ -314,12 +280,11 @@ OperationNode *ComponentNode::get_exit_operation()
void ComponentNode::finalize_build(Depsgraph * /*graph*/)
{
- operations.reserve(BLI_ghash_len(operations_map));
- GHASH_FOREACH_BEGIN (OperationNode *, op_node, operations_map) {
+ operations.reserve(operations_map->size());
+ for (OperationNode *op_node : operations_map->values()) {
operations.push_back(op_node);
}
- GHASH_FOREACH_END();
- BLI_ghash_free(operations_map, comp_node_hash_key_free, nullptr);
+ delete operations_map;
operations_map = nullptr;
}
@@ -368,6 +333,7 @@ DEG_COMPONENT_NODE_DEFINE(Synchronization, SYNCHRONIZATION, 0);
DEG_COMPONENT_NODE_DEFINE(Audio, AUDIO, 0);
DEG_COMPONENT_NODE_DEFINE(Armature, ARMATURE, 0);
DEG_COMPONENT_NODE_DEFINE(GenericDatablock, GENERIC_DATABLOCK, 0);
+DEG_COMPONENT_NODE_DEFINE(Simulation, SIMULATION, 0);
/* Node Types Register =================================== */
@@ -397,6 +363,7 @@ void deg_register_component_depsnodes()
register_node_typeinfo(&DNTI_AUDIO);
register_node_typeinfo(&DNTI_ARMATURE);
register_node_typeinfo(&DNTI_GENERIC_DATABLOCK);
+ register_node_typeinfo(&DNTI_SIMULATION);
}
} // namespace DEG
diff --git a/source/blender/depsgraph/intern/node/deg_node_component.h b/source/blender/depsgraph/intern/node/deg_node_component.h
index 38ea4005a72..ca37401d200 100644
--- a/source/blender/depsgraph/intern/node/deg_node_component.h
+++ b/source/blender/depsgraph/intern/node/deg_node_component.h
@@ -26,10 +26,11 @@
#include "intern/node/deg_node.h"
#include "intern/node/deg_node_operation.h"
+#include "BLI_ghash.h"
+#include "BLI_hash.hh"
#include "BLI_string.h"
#include "BLI_utildefines.h"
-struct GHash;
struct ID;
struct bPoseChannel;
@@ -115,7 +116,7 @@ struct ComponentNode : public Node {
/* Operations stored as a hash map, for faster build.
* This hash map will be freed when graph is fully built. */
- GHash *operations_map;
+ Map<ComponentNode::OperationIDKey, OperationNode *> *operations_map;
/* This is a "normal" list of operations, used by evaluation
* and other routines after construction. */
@@ -190,6 +191,7 @@ DEG_COMPONENT_NODE_DECLARE_GENERIC(Synchronization);
DEG_COMPONENT_NODE_DECLARE_GENERIC(Audio);
DEG_COMPONENT_NODE_DECLARE_GENERIC(Armature);
DEG_COMPONENT_NODE_DECLARE_GENERIC(GenericDatablock);
+DEG_COMPONENT_NODE_DECLARE_GENERIC(Simulation);
/* Bone Component */
struct BoneComponentNode : public ComponentNode {
@@ -203,3 +205,18 @@ struct BoneComponentNode : public ComponentNode {
void deg_register_component_depsnodes();
} // namespace DEG
+
+namespace BLI {
+
+template<> struct DefaultHash<DEG::ComponentNode::OperationIDKey> {
+ uint32_t operator()(const DEG::ComponentNode::OperationIDKey &key) const
+ {
+ const int opcode_as_int = static_cast<int>(key.opcode);
+ return BLI_ghashutil_combine_hash(
+ key.name_tag,
+ BLI_ghashutil_combine_hash(BLI_ghashutil_uinthash(opcode_as_int),
+ BLI_ghashutil_strhash_p(key.name)));
+ }
+};
+
+} // namespace BLI
diff --git a/source/blender/depsgraph/intern/node/deg_node_id.cc b/source/blender/depsgraph/intern/node/deg_node_id.cc
index 0bb09390b4f..4a7e5c4568b 100644
--- a/source/blender/depsgraph/intern/node/deg_node_id.cc
+++ b/source/blender/depsgraph/intern/node/deg_node_id.cc
@@ -26,17 +26,13 @@
#include <cstring> /* required for STREQ later on. */
#include <stdio.h>
-#include "BLI_ghash.h"
#include "BLI_string.h"
#include "BLI_utildefines.h"
-extern "C" {
#include "DNA_ID.h"
#include "DNA_anim_types.h"
-#include "BKE_animsys.h"
#include "BKE_lib_id.h"
-}
#include "DEG_depsgraph.h"
@@ -70,34 +66,6 @@ bool IDNode::ComponentIDKey::operator==(const ComponentIDKey &other) const
return type == other.type && STREQ(name, other.name);
}
-static unsigned int id_deps_node_hash_key(const void *key_v)
-{
- const IDNode::ComponentIDKey *key = reinterpret_cast<const IDNode::ComponentIDKey *>(key_v);
- const int type_as_int = static_cast<int>(key->type);
- return BLI_ghashutil_combine_hash(BLI_ghashutil_uinthash(type_as_int),
- BLI_ghashutil_strhash_p(key->name));
-}
-
-static bool id_deps_node_hash_key_cmp(const void *a, const void *b)
-{
- const IDNode::ComponentIDKey *key_a = reinterpret_cast<const IDNode::ComponentIDKey *>(a);
- const IDNode::ComponentIDKey *key_b = reinterpret_cast<const IDNode::ComponentIDKey *>(b);
- return !(*key_a == *key_b);
-}
-
-static void id_deps_node_hash_key_free(void *key_v)
-{
- typedef IDNode::ComponentIDKey ComponentIDKey;
- ComponentIDKey *key = reinterpret_cast<ComponentIDKey *>(key_v);
- OBJECT_GUARDED_DELETE(key, ComponentIDKey);
-}
-
-static void id_deps_node_hash_value_free(void *value_v)
-{
- ComponentNode *comp_node = reinterpret_cast<ComponentNode *>(value_v);
- OBJECT_GUARDED_DELETE(comp_node, ComponentNode);
-}
-
/* Initialize 'id' node - from pointer data given. */
void IDNode::init(const ID *id, const char *UNUSED(subdata))
{
@@ -117,9 +85,6 @@ void IDNode::init(const ID *id, const char *UNUSED(subdata))
visible_components_mask = 0;
previously_visible_components_mask = 0;
-
- components = BLI_ghash_new(
- id_deps_node_hash_key, id_deps_node_hash_key_cmp, "Depsgraph id components hash");
}
void IDNode::init_copy_on_write(ID *id_cow_hint)
@@ -159,7 +124,9 @@ void IDNode::destroy()
return;
}
- BLI_ghash_free(components, id_deps_node_hash_key_free, id_deps_node_hash_value_free);
+ for (ComponentNode *comp_node : components.values()) {
+ OBJECT_GUARDED_DELETE(comp_node, ComponentNode);
+ }
/* Free memory used by this CoW ID. */
if (id_cow != id_orig && id_cow != nullptr) {
@@ -186,7 +153,7 @@ string IDNode::identifier() const
ComponentNode *IDNode::find_component(NodeType type, const char *name) const
{
ComponentIDKey key(type, name);
- return reinterpret_cast<ComponentNode *>(BLI_ghash_lookup(components, &key));
+ return components.lookup_default(key, nullptr);
}
ComponentNode *IDNode::add_component(NodeType type, const char *name)
@@ -197,8 +164,8 @@ ComponentNode *IDNode::add_component(NodeType type, const char *name)
comp_node = (ComponentNode *)factory->create_node(this->id_orig, "", name);
/* Register. */
- ComponentIDKey *key = OBJECT_GUARDED_NEW(ComponentIDKey, type, name);
- BLI_ghash_insert(components, key, comp_node);
+ ComponentIDKey key(type, name);
+ components.add_new(key, comp_node);
comp_node->owner = this;
}
return comp_node;
@@ -206,7 +173,7 @@ ComponentNode *IDNode::add_component(NodeType type, const char *name)
void IDNode::tag_update(Depsgraph *graph, eUpdateSource source)
{
- GHASH_FOREACH_BEGIN (ComponentNode *, comp_node, components) {
+ for (ComponentNode *comp_node : components.values()) {
/* Relations update does explicit animation update when needed. Here we ignore animation
* component to avoid loss of possible unkeyed changes. */
if (comp_node->type == NodeType::ANIMATION && source == DEG_UPDATE_SOURCE_RELATIONS) {
@@ -214,30 +181,27 @@ void IDNode::tag_update(Depsgraph *graph, eUpdateSource source)
}
comp_node->tag_update(graph, source);
}
- GHASH_FOREACH_END();
}
void IDNode::finalize_build(Depsgraph *graph)
{
/* Finalize build of all components. */
- GHASH_FOREACH_BEGIN (ComponentNode *, comp_node, components) {
+ for (ComponentNode *comp_node : components.values()) {
comp_node->finalize_build(graph);
}
- GHASH_FOREACH_END();
visible_components_mask = get_visible_components_mask();
}
IDComponentsMask IDNode::get_visible_components_mask() const
{
IDComponentsMask result = 0;
- GHASH_FOREACH_BEGIN (ComponentNode *, comp_node, components) {
+ for (ComponentNode *comp_node : components.values()) {
if (comp_node->affects_directly_visible) {
const int component_type_as_int = static_cast<int>(comp_node->type);
BLI_assert(component_type_as_int < 64);
result |= (1ULL << component_type_as_int);
}
}
- GHASH_FOREACH_END();
return result;
}
diff --git a/source/blender/depsgraph/intern/node/deg_node_id.h b/source/blender/depsgraph/intern/node/deg_node_id.h
index 80bb67f182f..c7663b50c6f 100644
--- a/source/blender/depsgraph/intern/node/deg_node_id.h
+++ b/source/blender/depsgraph/intern/node/deg_node_id.h
@@ -23,12 +23,11 @@
#pragma once
+#include "BLI_ghash.h"
#include "BLI_sys_types.h"
#include "DNA_ID.h"
#include "intern/node/deg_node.h"
-struct GHash;
-
namespace DEG {
struct ComponentNode;
@@ -82,7 +81,7 @@ struct IDNode : public Node {
ID *id_cow;
/* Hash to make it faster to look up components. */
- GHash *components;
+ Map<ComponentIDKey, ComponentNode *> components;
/* Additional flags needed for scene evaluation.
* TODO(sergey): Only needed for until really granular updates
@@ -116,3 +115,16 @@ struct IDNode : public Node {
};
} // namespace DEG
+
+namespace BLI {
+
+template<> struct DefaultHash<DEG::IDNode::ComponentIDKey> {
+ uint32_t operator()(const DEG::IDNode::ComponentIDKey &key) const
+ {
+ const int type_as_int = static_cast<int>(key.type);
+ return BLI_ghashutil_combine_hash(BLI_ghashutil_uinthash(type_as_int),
+ BLI_ghashutil_strhash_p(key.name));
+ }
+};
+
+} // namespace BLI
diff --git a/source/blender/depsgraph/intern/node/deg_node_operation.cc b/source/blender/depsgraph/intern/node/deg_node_operation.cc
index 78399d5c953..91bd0117f6c 100644
--- a/source/blender/depsgraph/intern/node/deg_node_operation.cc
+++ b/source/blender/depsgraph/intern/node/deg_node_operation.cc
@@ -25,7 +25,6 @@
#include "MEM_guardedalloc.h"
-#include "BLI_ghash.h"
#include "BLI_utildefines.h"
#include "intern/depsgraph.h"
@@ -61,6 +60,8 @@ const char *operationCodeAsString(OperationCode opcode)
/* Scene related. */
case OperationCode::SCENE_EVAL:
return "SCENE_EVAL";
+ case OperationCode::AUDIO_VOLUME:
+ return "AUDIO_VOLUME";
/* Object related. */
case OperationCode::OBJECT_BASE_FLAGS:
return "OBJECT_BASE_FLAGS";
@@ -171,6 +172,8 @@ const char *operationCodeAsString(OperationCode opcode)
return "SHADING";
case OperationCode::MATERIAL_UPDATE:
return "MATERIAL_UPDATE";
+ case OperationCode::LIGHT_UPDATE:
+ return "LIGHT_UPDATE";
case OperationCode::WORLD_UPDATE:
return "WORLD_UPDATE";
/* Movie clip. */
@@ -193,6 +196,8 @@ const char *operationCodeAsString(OperationCode opcode)
/* instancing/duplication. */
case OperationCode::DUPLI:
return "DUPLI";
+ case OperationCode::SIMULATION_EVAL:
+ return "SIMULATION_EVAL";
}
BLI_assert(!"Unhandled operation code, should never happen.");
return "UNKNOWN";
diff --git a/source/blender/depsgraph/intern/node/deg_node_operation.h b/source/blender/depsgraph/intern/node/deg_node_operation.h
index bdc0df7f399..6b14e6af02f 100644
--- a/source/blender/depsgraph/intern/node/deg_node_operation.h
+++ b/source/blender/depsgraph/intern/node/deg_node_operation.h
@@ -60,6 +60,7 @@ enum class OperationCode {
/* Scene related. ------------------------------------------------------- */
SCENE_EVAL,
+ AUDIO_VOLUME,
/* Object related. ------------------------------------------------------ */
OBJECT_BASE_FLAGS,
@@ -169,6 +170,7 @@ enum class OperationCode {
/* Shading. ------------------------------------------------------------- */
SHADING,
MATERIAL_UPDATE,
+ LIGHT_UPDATE,
WORLD_UPDATE,
/* Batch caches. -------------------------------------------------------- */
@@ -197,6 +199,9 @@ enum class OperationCode {
/* Duplication/instancing system. --------------------------------------- */
DUPLI,
+
+ /* Simulation. ---------------------------------------------------------- */
+ SIMULATION_EVAL,
};
const char *operationCodeAsString(OperationCode opcode);
diff --git a/source/blender/draw/CMakeLists.txt b/source/blender/draw/CMakeLists.txt
index 46263f694cb..a26c150cb51 100644
--- a/source/blender/draw/CMakeLists.txt
+++ b/source/blender/draw/CMakeLists.txt
@@ -34,6 +34,7 @@ set(INC
../imbuf
../makesdna
../makesrna
+ ../nodes
../render/extern/include
../render/intern/include
../windowmanager
@@ -303,8 +304,8 @@ data_to_c_simple(engines/select/shaders/selection_id_3D_vert.glsl SRC)
data_to_c_simple(engines/select/shaders/selection_id_frag.glsl SRC)
data_to_c_simple(engines/basic/shaders/conservative_depth_geom.glsl SRC)
-data_to_c_simple(engines/basic/shaders/conservative_depth_vert.glsl SRC)
-data_to_c_simple(engines/basic/shaders/conservative_depth_frag.glsl SRC)
+data_to_c_simple(engines/basic/shaders/depth_vert.glsl SRC)
+data_to_c_simple(engines/basic/shaders/depth_frag.glsl SRC)
data_to_c_simple(engines/overlay/shaders/antialiasing_frag.glsl SRC)
data_to_c_simple(engines/overlay/shaders/antialiasing_vert.glsl SRC)
@@ -384,6 +385,7 @@ data_to_c_simple(engines/overlay/shaders/particle_frag.glsl SRC)
data_to_c_simple(engines/overlay/shaders/pointcloud_vert.glsl SRC)
data_to_c_simple(engines/overlay/shaders/pointcloud_frag.glsl SRC)
data_to_c_simple(engines/overlay/shaders/sculpt_mask_vert.glsl SRC)
+data_to_c_simple(engines/overlay/shaders/sculpt_mask_frag.glsl SRC)
data_to_c_simple(engines/overlay/shaders/volume_velocity_vert.glsl SRC)
data_to_c_simple(engines/overlay/shaders/wireframe_vert.glsl SRC)
data_to_c_simple(engines/overlay/shaders/wireframe_frag.glsl SRC)
@@ -400,4 +402,6 @@ if(WITH_XR_OPENXR)
add_definitions(-DWITH_XR_OPENXR)
endif()
+add_definitions(${GL_DEFINITIONS})
+
blender_add_lib(bf_draw "${SRC}" "${INC}" "${INC_SYS}" "${LIB}")
diff --git a/source/blender/draw/DRW_engine.h b/source/blender/draw/DRW_engine.h
index 7ecf9df275d..6c835c6d7ae 100644
--- a/source/blender/draw/DRW_engine.h
+++ b/source/blender/draw/DRW_engine.h
@@ -23,12 +23,16 @@
#ifndef __DRW_ENGINE_H__
#define __DRW_ENGINE_H__
+#include "BLI_sys_types.h" /* for bool */
+
+#include "DNA_object_enums.h"
+
+#include "DRW_engine_types.h"
+
#ifdef __cplusplus
extern "C" {
#endif
-#include "BLI_sys_types.h" /* for bool */
-
struct ARegion;
struct DRWInstanceDataList;
struct Depsgraph;
@@ -47,9 +51,6 @@ struct ViewLayer;
struct bContext;
struct rcti;
-#include "DNA_object_enums.h"
-#include "DRW_engine_types.h"
-
void DRW_engines_register(void);
void DRW_engines_free(void);
@@ -77,7 +78,7 @@ typedef bool (*DRW_SelectPassFn)(eDRWSelectStage stage, void *user_data);
typedef bool (*DRW_ObjectFilterFn)(struct Object *ob, void *user_data);
void DRW_draw_view(const struct bContext *C);
-void DRW_draw_region_engine_info(int xoffset, int yoffset);
+void DRW_draw_region_engine_info(int xoffset, int *yoffset, int line_height);
void DRW_draw_render_loop_ex(struct Depsgraph *depsgraph,
struct RenderEngineType *engine_type,
@@ -118,7 +119,8 @@ void DRW_draw_depth_loop_gpencil(struct Depsgraph *depsgraph,
struct ARegion *region,
struct View3D *v3d,
struct GPUViewport *viewport);
-void DRW_draw_depth_object(struct ARegion *region,
+void DRW_draw_depth_object(struct Scene *scene,
+ struct ARegion *region,
struct View3D *v3d,
struct GPUViewport *viewport,
struct Object *object);
diff --git a/source/blender/draw/engines/basic/basic_engine.c b/source/blender/draw/engines/basic/basic_engine.c
index 799359098fe..bbc3c407f14 100644
--- a/source/blender/draw/engines/basic/basic_engine.c
+++ b/source/blender/draw/engines/basic/basic_engine.c
@@ -37,8 +37,8 @@
#define BASIC_ENGINE "BLENDER_BASIC"
-extern char datatoc_conservative_depth_frag_glsl[];
-extern char datatoc_conservative_depth_vert_glsl[];
+extern char datatoc_depth_frag_glsl[];
+extern char datatoc_depth_vert_glsl[];
extern char datatoc_conservative_depth_geom_glsl[];
extern char datatoc_common_view_lib_glsl[];
@@ -79,6 +79,7 @@ static struct {
typedef struct BASIC_PrivateData {
DRWShadingGroup *depth_shgrp[2];
DRWShadingGroup *depth_shgrp_cull[2];
+ DRWShadingGroup *depth_hair_shgrp[2];
} BASIC_PrivateData; /* Transient data */
/* Functions */
@@ -90,22 +91,28 @@ static void basic_engine_init(void *UNUSED(vedata))
/* Depth prepass */
if (!sh_data->depth) {
- sh_data->depth = DRW_shader_create_3d_depth_only(draw_ctx->sh_cfg);
-
const GPUShaderConfigData *sh_cfg = &GPU_shader_cfg_data[draw_ctx->sh_cfg];
+
+ sh_data->depth = GPU_shader_create_from_arrays({
+ .vert = (const char *[]){sh_cfg->lib,
+ datatoc_common_view_lib_glsl,
+ datatoc_depth_vert_glsl,
+ NULL},
+ .frag = (const char *[]){datatoc_depth_frag_glsl, NULL},
+ .defs = (const char *[]){sh_cfg->def, NULL},
+ });
+
sh_data->depth_conservative = GPU_shader_create_from_arrays({
.vert = (const char *[]){sh_cfg->lib,
datatoc_common_view_lib_glsl,
- datatoc_conservative_depth_vert_glsl,
+ datatoc_depth_vert_glsl,
NULL},
.geom = (const char *[]){sh_cfg->lib,
datatoc_common_view_lib_glsl,
datatoc_conservative_depth_geom_glsl,
NULL},
- .frag = (const char *[]){datatoc_common_view_lib_glsl,
- datatoc_conservative_depth_frag_glsl,
- NULL},
- .defs = (const char *[]){sh_cfg->def, NULL},
+ .frag = (const char *[]){datatoc_depth_frag_glsl, NULL},
+ .defs = (const char *[]){sh_cfg->def, "#define CONSERVATIVE_RASTER\n", NULL},
});
}
}
@@ -137,6 +144,9 @@ static void basic_cache_init(void *vedata)
DRW_shgroup_uniform_vec2(grp, "sizeViewport", DRW_viewport_size_get(), 1);
DRW_shgroup_uniform_vec2(grp, "sizeViewportInv", DRW_viewport_invert_size_get(), 1);
+ stl->g_data->depth_hair_shgrp[i] = grp = DRW_shgroup_create(sh_data->depth,
+ psl->depth_pass[i]);
+
state |= DRW_STATE_CULL_BACK;
DRW_PASS_CREATE(psl->depth_pass_cull[i], state | clip_state | infront_state);
stl->g_data->depth_shgrp_cull[i] = grp = DRW_shgroup_create(sh, psl->depth_pass_cull[i]);
@@ -167,7 +177,7 @@ static void basic_cache_populate(void *vedata, Object *ob)
const int draw_as = (part->draw_as == PART_DRAW_REND) ? part->ren_as : part->draw_as;
if (draw_as == PART_DRAW_PATH) {
struct GPUBatch *hairs = DRW_cache_particles_get_hair(ob, psys, NULL);
- DRW_shgroup_call(stl->g_data->depth_shgrp[do_in_front], hairs, NULL);
+ DRW_shgroup_call(stl->g_data->depth_hair_shgrp[do_in_front], hairs, NULL);
}
}
}
@@ -198,7 +208,7 @@ static void basic_cache_populate(void *vedata, Object *ob)
stl->g_data->depth_shgrp[do_in_front];
if (use_sculpt_pbvh) {
- DRW_shgroup_call_sculpt(shgrp, ob, false, false, false);
+ DRW_shgroup_call_sculpt(shgrp, ob, false, false);
}
else {
struct GPUBatch *geom = DRW_cache_object_surface_get(ob);
@@ -229,6 +239,7 @@ static void basic_engine_free(void)
{
for (int i = 0; i < GPU_SHADER_CFG_LEN; i++) {
BASIC_Shaders *sh_data = &e_data.sh_data[i];
+ DRW_SHADER_FREE_SAFE(sh_data->depth);
DRW_SHADER_FREE_SAFE(sh_data->depth_conservative);
}
}
diff --git a/source/blender/draw/engines/basic/shaders/conservative_depth_frag.glsl b/source/blender/draw/engines/basic/shaders/depth_frag.glsl
index ff4a015c335..ff4a015c335 100644
--- a/source/blender/draw/engines/basic/shaders/conservative_depth_frag.glsl
+++ b/source/blender/draw/engines/basic/shaders/depth_frag.glsl
diff --git a/source/blender/draw/engines/basic/shaders/conservative_depth_vert.glsl b/source/blender/draw/engines/basic/shaders/depth_vert.glsl
index c55a3211ff2..318d0acef6f 100644
--- a/source/blender/draw/engines/basic/shaders/conservative_depth_vert.glsl
+++ b/source/blender/draw/engines/basic/shaders/depth_vert.glsl
@@ -1,12 +1,16 @@
+#ifdef CONSERVATIVE_RASTER
RESOURCE_ID_VARYING
+#endif
in vec3 pos;
void main()
{
GPU_INTEL_VERTEX_SHADER_WORKAROUND
+#ifdef CONSERVATIVE_RASTER
PASS_RESOURCE_ID
+#endif
vec3 world_pos = point_object_to_world(pos);
gl_Position = point_world_to_ndc(world_pos);
diff --git a/source/blender/draw/engines/eevee/eevee_bloom.c b/source/blender/draw/engines/eevee/eevee_bloom.c
index 6545a1bca84..8fd953478d5 100644
--- a/source/blender/draw/engines/eevee/eevee_bloom.c
+++ b/source/blender/draw/engines/eevee/eevee_bloom.c
@@ -323,8 +323,8 @@ void EEVEE_bloom_draw(EEVEE_Data *vedata)
/* Upsample and accumulate */
for (int i = effects->bloom_iteration_len - 2; i >= 0; i--) {
copy_v2_v2(effects->unf_source_texel_size, effects->downsamp_texel_size[i]);
- effects->unf_source_buffer = effects->bloom_downsample[i];
- effects->unf_base_buffer = last;
+ effects->unf_source_buffer = last;
+ effects->unf_base_buffer = effects->bloom_downsample[i];
GPU_framebuffer_bind(fbl->bloom_accum_fb[i]);
DRW_draw_pass(psl->bloom_upsample);
diff --git a/source/blender/draw/engines/eevee/eevee_data.c b/source/blender/draw/engines/eevee/eevee_data.c
index 6874947de55..a19af77124f 100644
--- a/source/blender/draw/engines/eevee/eevee_data.c
+++ b/source/blender/draw/engines/eevee/eevee_data.c
@@ -24,6 +24,8 @@
#include "DRW_render.h"
+#include "BLI_memblock.h"
+
#include "eevee_lightcache.h"
#include "eevee_private.h"
@@ -54,8 +56,17 @@ void EEVEE_view_layer_data_free(void *storage)
DRW_UBO_FREE_SAFE(sldata->grid_ubo);
DRW_UBO_FREE_SAFE(sldata->planar_ubo);
DRW_UBO_FREE_SAFE(sldata->common_ubo);
- for (int i = 0; i < MAX_MATERIAL_RENDER_PASSES_UBO; i++) {
- DRW_UBO_FREE_SAFE(sldata->renderpass_ubo[i]);
+
+ DRW_UBO_FREE_SAFE(sldata->renderpass_ubo.combined);
+ DRW_UBO_FREE_SAFE(sldata->renderpass_ubo.diff_color);
+ DRW_UBO_FREE_SAFE(sldata->renderpass_ubo.diff_light);
+ DRW_UBO_FREE_SAFE(sldata->renderpass_ubo.spec_color);
+ DRW_UBO_FREE_SAFE(sldata->renderpass_ubo.spec_light);
+ DRW_UBO_FREE_SAFE(sldata->renderpass_ubo.emit);
+
+ if (sldata->material_cache) {
+ BLI_memblock_destroy(sldata->material_cache, NULL);
+ sldata->material_cache = NULL;
}
}
diff --git a/source/blender/draw/engines/eevee/eevee_depth_of_field.c b/source/blender/draw/engines/eevee/eevee_depth_of_field.c
index ec6770e4549..4a3cc36ddef 100644
--- a/source/blender/draw/engines/eevee/eevee_depth_of_field.c
+++ b/source/blender/draw/engines/eevee/eevee_depth_of_field.c
@@ -31,6 +31,8 @@
#include "BKE_camera.h"
+#include "BLI_string_utils.h"
+
#include "DEG_depsgraph.h"
#include "DEG_depsgraph_query.h"
@@ -48,24 +50,28 @@ static struct {
extern char datatoc_effect_dof_vert_glsl[];
extern char datatoc_effect_dof_frag_glsl[];
+extern char datatoc_common_view_lib_glsl[];
+
static void eevee_create_shader_depth_of_field(const bool use_alpha)
{
+ char *frag = BLI_string_joinN(datatoc_common_view_lib_glsl, datatoc_effect_dof_frag_glsl);
e_data.dof_downsample_sh[use_alpha] = DRW_shader_create_fullscreen(
- datatoc_effect_dof_frag_glsl,
+ frag,
use_alpha ? "#define USE_ALPHA_DOF\n"
"#define STEP_DOWNSAMPLE\n" :
"#define STEP_DOWNSAMPLE\n");
e_data.dof_scatter_sh[use_alpha] = DRW_shader_create(datatoc_effect_dof_vert_glsl,
NULL,
- datatoc_effect_dof_frag_glsl,
+ frag,
use_alpha ? "#define USE_ALPHA_DOF\n"
"#define STEP_SCATTER\n" :
"#define STEP_SCATTER\n");
- e_data.dof_resolve_sh[use_alpha] = DRW_shader_create_fullscreen(datatoc_effect_dof_frag_glsl,
+ e_data.dof_resolve_sh[use_alpha] = DRW_shader_create_fullscreen(frag,
use_alpha ?
"#define USE_ALPHA_DOF\n"
"#define STEP_RESOLVE\n" :
"#define STEP_RESOLVE\n");
+ MEM_freeN(frag);
}
int EEVEE_depth_of_field_init(EEVEE_ViewLayerData *UNUSED(sldata),
diff --git a/source/blender/draw/engines/eevee/eevee_effects.c b/source/blender/draw/engines/eevee/eevee_effects.c
index 05b18da4374..ab846fe0f11 100644
--- a/source/blender/draw/engines/eevee/eevee_effects.c
+++ b/source/blender/draw/engines/eevee/eevee_effects.c
@@ -333,8 +333,7 @@ void EEVEE_effects_cache_init(EEVEE_ViewLayerData *sldata, EEVEE_Data *vedata)
grp = DRW_shgroup_create(EEVEE_shaders_velocity_resolve_sh_get(), psl->velocity_resolve);
DRW_shgroup_uniform_texture_ref(grp, "depthBuffer", &e_data.depth_src);
DRW_shgroup_uniform_block(grp, "common_block", sldata->common_ubo);
- DRW_shgroup_uniform_block(
- grp, "renderpass_block", EEVEE_material_default_render_pass_ubo_get(sldata));
+ DRW_shgroup_uniform_block(grp, "renderpass_block", sldata->renderpass_ubo.combined);
DRW_shgroup_uniform_mat4(grp, "currPersinv", effects->velocity_curr_persinv);
DRW_shgroup_uniform_mat4(grp, "pastPersmat", effects->velocity_past_persmat);
DRW_shgroup_call(grp, quad, NULL);
diff --git a/source/blender/draw/engines/eevee/eevee_engine.c b/source/blender/draw/engines/eevee/eevee_engine.c
index a1112eb92df..b698574f9d7 100644
--- a/source/blender/draw/engines/eevee/eevee_engine.c
+++ b/source/blender/draw/engines/eevee/eevee_engine.c
@@ -88,7 +88,7 @@ static void eevee_engine_init(void *ved)
* `EEVEE_effects_init` needs to go second for TAA. */
EEVEE_renderpasses_init(vedata);
EEVEE_effects_init(sldata, vedata, camera, false);
- EEVEE_materials_init(sldata, stl, fbl);
+ EEVEE_materials_init(sldata, vedata, stl, fbl);
EEVEE_shadows_init(sldata);
EEVEE_lightprobes_init(sldata, vedata);
}
@@ -230,7 +230,7 @@ static void eevee_draw_scene(void *vedata)
BLI_halton_3d(primes, offset, samp, r);
EEVEE_update_noise(psl, fbl, r);
EEVEE_volumes_set_jitter(sldata, samp - 1);
- EEVEE_materials_init(sldata, stl, fbl);
+ EEVEE_materials_init(sldata, vedata, stl, fbl);
}
/* Copy previous persmat to UBO data */
copy_m4_m4(sldata->common_data.prev_persmat, stl->effects->prev_persmat);
@@ -274,8 +274,7 @@ static void eevee_draw_scene(void *vedata)
/* Depth prepass */
DRW_stats_group_start("Prepass");
- DRW_draw_pass(psl->depth_pass);
- DRW_draw_pass(psl->depth_pass_cull);
+ DRW_draw_pass(psl->depth_ps);
DRW_stats_group_end();
/* Create minmax texture */
@@ -289,9 +288,9 @@ static void eevee_draw_scene(void *vedata)
/* Shading pass */
DRW_stats_group_start("Shading");
if (DRW_state_draw_background()) {
- DRW_draw_pass(psl->background_pass);
+ DRW_draw_pass(psl->background_ps);
}
- EEVEE_materials_draw_opaque(sldata, psl);
+ DRW_draw_pass(psl->material_ps);
EEVEE_subsurface_data_render(sldata, vedata);
DRW_stats_group_end();
@@ -306,9 +305,8 @@ static void eevee_draw_scene(void *vedata)
/* Opaque refraction */
DRW_stats_group_start("Opaque Refraction");
- DRW_draw_pass(psl->refract_depth_pass);
- DRW_draw_pass(psl->refract_depth_pass_cull);
- DRW_draw_pass(psl->refract_pass);
+ DRW_draw_pass(psl->depth_refract_ps);
+ DRW_draw_pass(psl->material_refract_ps);
DRW_stats_group_end();
/* Volumetrics Resolve Opaque */
diff --git a/source/blender/draw/engines/eevee/eevee_lightcache.c b/source/blender/draw/engines/eevee/eevee_lightcache.c
index 9447c365c48..4cdd166f09c 100644
--- a/source/blender/draw/engines/eevee/eevee_lightcache.c
+++ b/source/blender/draw/engines/eevee/eevee_lightcache.c
@@ -379,9 +379,7 @@ static bool eevee_lightcache_static_load(LightCache *lcache)
0,
false,
NULL);
- GPU_texture_bind(lcache->grid_tx.tex, 0);
GPU_texture_filter_mode(lcache->grid_tx.tex, true);
- GPU_texture_unbind(lcache->grid_tx.tex);
}
if (lcache->cube_tx.tex == NULL) {
@@ -406,13 +404,11 @@ static bool eevee_lightcache_static_load(LightCache *lcache)
NULL);
}
- GPU_texture_bind(lcache->cube_tx.tex, 0);
- GPU_texture_mipmap_mode(lcache->cube_tx.tex, true, true);
for (int mip = 0; mip < lcache->mips_len; mip++) {
GPU_texture_add_mipmap(
lcache->cube_tx.tex, GPU_DATA_10_11_11_REV, mip + 1, lcache->cube_mips[mip].data);
}
- GPU_texture_unbind(lcache->cube_tx.tex);
+ GPU_texture_mipmap_mode(lcache->cube_tx.tex, true, true);
}
return true;
}
@@ -777,8 +773,6 @@ static void eevee_lightbake_delete_resources(EEVEE_LightBake *lbake)
if (!lbake->resource_only) {
BLI_mutex_unlock(lbake->mutex);
}
-
- EEVEE_volumes_free_smoke_textures();
}
/* Cache as in draw cache not light cache. */
@@ -824,7 +818,7 @@ static void eevee_lightbake_cache_create(EEVEE_Data *vedata, EEVEE_LightBake *lb
DRW_render_viewport_size_set(viewport_size);
EEVEE_effects_init(sldata, vedata, NULL, true);
- EEVEE_materials_init(sldata, stl, fbl);
+ EEVEE_materials_init(sldata, vedata, stl, fbl);
EEVEE_shadows_init(sldata);
EEVEE_lightprobes_init(sldata, vedata);
@@ -1347,6 +1341,9 @@ void EEVEE_lightbake_job(void *custom_data, short *stop, short *do_update, float
}
eevee_lightbake_delete_resources(lbake);
+
+ /* Free GPU smoke textures and the smoke domain list correctly: See also T73921.*/
+ EEVEE_volumes_free_smoke_textures();
}
/* This is to update the world irradiance and reflection contribution from
diff --git a/source/blender/draw/engines/eevee/eevee_lightprobes.c b/source/blender/draw/engines/eevee/eevee_lightprobes.c
index 9816632c0c3..83b2a9bb6d4 100644
--- a/source/blender/draw/engines/eevee/eevee_lightprobes.c
+++ b/source/blender/draw/engines/eevee/eevee_lightprobes.c
@@ -248,8 +248,7 @@ void EEVEE_lightbake_cache_init(EEVEE_ViewLayerData *sldata,
// DRW_shgroup_uniform_texture(grp, "texJitter", e_data.jitter);
DRW_shgroup_uniform_texture(grp, "probeHdr", rt_color);
DRW_shgroup_uniform_block(grp, "common_block", sldata->common_ubo);
- DRW_shgroup_uniform_block(
- grp, "renderpass_block", EEVEE_material_default_render_pass_ubo_get(sldata));
+ DRW_shgroup_uniform_block(grp, "renderpass_block", sldata->renderpass_ubo.combined);
struct GPUBatch *geom = DRW_cache_fullscreen_quad_get();
DRW_shgroup_call_instances(grp, NULL, geom, 6);
@@ -271,8 +270,7 @@ void EEVEE_lightbake_cache_init(EEVEE_ViewLayerData *sldata,
DRW_shgroup_uniform_float(grp, "intensityFac", &pinfo->intensity_fac, 1);
DRW_shgroup_uniform_texture(grp, "probeHdr", rt_color);
DRW_shgroup_uniform_block(grp, "common_block", sldata->common_ubo);
- DRW_shgroup_uniform_block(
- grp, "renderpass_block", EEVEE_material_default_render_pass_ubo_get(sldata));
+ DRW_shgroup_uniform_block(grp, "renderpass_block", sldata->renderpass_ubo.combined);
struct GPUBatch *geom = DRW_cache_fullscreen_quad_get();
DRW_shgroup_call(grp, geom, NULL);
@@ -293,8 +291,7 @@ void EEVEE_lightbake_cache_init(EEVEE_ViewLayerData *sldata,
DRW_shgroup_uniform_texture(grp, "texHammersley", e_data.hammersley);
DRW_shgroup_uniform_texture(grp, "probeDepth", rt_depth);
DRW_shgroup_uniform_block(grp, "common_block", sldata->common_ubo);
- DRW_shgroup_uniform_block(
- grp, "renderpass_block", EEVEE_material_default_render_pass_ubo_get(sldata));
+ DRW_shgroup_uniform_block(grp, "renderpass_block", sldata->renderpass_ubo.combined);
struct GPUBatch *geom = DRW_cache_fullscreen_quad_get();
DRW_shgroup_call(grp, geom, NULL);
@@ -337,51 +334,29 @@ void EEVEE_lightprobes_cache_init(EEVEE_ViewLayerData *sldata, EEVEE_Data *vedat
Scene *scene = draw_ctx->scene;
World *wo = scene->world;
- const float *col = G_draw.block.colorBackground;
-
/* LookDev */
EEVEE_lookdev_cache_init(vedata, sldata, &grp, psl->probe_background, wo, pinfo);
- /* END */
+
if (!grp && wo) {
- col = &wo->horr;
-
- if (wo->use_nodes && wo->nodetree) {
- static float error_col[3] = {1.0f, 0.0f, 1.0f};
- static float queue_col[3] = {0.5f, 0.5f, 0.5f};
- struct GPUMaterial *gpumat = EEVEE_material_world_lightprobe_get(scene, wo);
-
- eGPUMaterialStatus status = GPU_material_status(gpumat);
-
- switch (status) {
- case GPU_MAT_SUCCESS:
- grp = DRW_shgroup_material_create(gpumat, psl->probe_background);
- DRW_shgroup_uniform_float_copy(grp, "backgroundAlpha", 1.0f);
- /* TODO (fclem): remove those (need to clean the GLSL files). */
- DRW_shgroup_uniform_block(grp, "common_block", sldata->common_ubo);
- DRW_shgroup_uniform_block(grp, "grid_block", sldata->grid_ubo);
- DRW_shgroup_uniform_block(grp, "probe_block", sldata->probe_ubo);
- DRW_shgroup_uniform_block(grp, "planar_block", sldata->planar_ubo);
- DRW_shgroup_uniform_block(grp, "light_block", sldata->light_ubo);
- DRW_shgroup_uniform_block(grp, "shadow_block", sldata->shadow_ubo);
- DRW_shgroup_uniform_block(
- grp, "renderpass_block", EEVEE_material_default_render_pass_ubo_get(sldata));
- DRW_shgroup_call(grp, geom, NULL);
- break;
- case GPU_MAT_QUEUED:
- stl->g_data->queued_shaders_count++;
- col = queue_col;
- break;
- default:
- col = error_col;
- break;
- }
- }
+ struct GPUMaterial *gpumat = EEVEE_material_get(vedata, scene, NULL, wo, VAR_WORLD_PROBE);
+
+ grp = DRW_shgroup_material_create(gpumat, psl->probe_background);
+ DRW_shgroup_uniform_float_copy(grp, "backgroundAlpha", 1.0f);
+ /* TODO (fclem): remove those (need to clean the GLSL files). */
+ DRW_shgroup_uniform_block(grp, "common_block", sldata->common_ubo);
+ DRW_shgroup_uniform_block(grp, "grid_block", sldata->grid_ubo);
+ DRW_shgroup_uniform_block(grp, "probe_block", sldata->probe_ubo);
+ DRW_shgroup_uniform_block(grp, "planar_block", sldata->planar_ubo);
+ DRW_shgroup_uniform_block(grp, "light_block", sldata->light_ubo);
+ DRW_shgroup_uniform_block(grp, "shadow_block", sldata->shadow_ubo);
+ DRW_shgroup_uniform_block(grp, "renderpass_block", sldata->renderpass_ubo.combined);
+ DRW_shgroup_call(grp, geom, NULL);
}
/* Fallback if shader fails or if not using nodetree. */
if (grp == NULL) {
grp = DRW_shgroup_create(EEVEE_shaders_probe_default_sh_get(), psl->probe_background);
- DRW_shgroup_uniform_vec3(grp, "color", col, 1);
+ DRW_shgroup_uniform_vec3(grp, "color", G_draw.block.colorBackground, 1);
DRW_shgroup_uniform_float_copy(grp, "backgroundAlpha", 1.0f);
DRW_shgroup_call(grp, geom, NULL);
}
@@ -402,14 +377,13 @@ void EEVEE_lightprobes_cache_init(EEVEE_ViewLayerData *sldata, EEVEE_Data *vedat
DRW_shgroup_uniform_texture_ref(grp, "probeCubes", &lcache->cube_tx.tex);
DRW_shgroup_uniform_block(grp, "probe_block", sldata->probe_ubo);
DRW_shgroup_uniform_block(grp, "common_block", sldata->common_ubo);
- DRW_shgroup_uniform_vec3(grp, "screen_vecs[0]", DRW_viewport_screenvecs_get(), 2);
+ DRW_shgroup_uniform_vec3(grp, "screen_vecs", DRW_viewport_screenvecs_get(), 2);
DRW_shgroup_uniform_float_copy(
grp, "sphere_size", scene_eval->eevee.gi_cubemap_draw_size * 0.5f);
/* TODO (fclem) get rid of those UBO. */
DRW_shgroup_uniform_block(grp, "planar_block", sldata->planar_ubo);
DRW_shgroup_uniform_block(grp, "grid_block", sldata->grid_ubo);
- DRW_shgroup_uniform_block(
- grp, "renderpass_block", EEVEE_material_default_render_pass_ubo_get(sldata));
+ DRW_shgroup_uniform_block(grp, "renderpass_block", sldata->renderpass_ubo.combined);
DRW_shgroup_call_procedural_triangles(grp, NULL, cube_len * 2);
}
@@ -427,7 +401,7 @@ void EEVEE_lightprobes_cache_init(EEVEE_ViewLayerData *sldata, EEVEE_Data *vedat
DRW_shgroup_uniform_vec3(shgrp, "increment_x", egrid->increment_x, 1);
DRW_shgroup_uniform_vec3(shgrp, "increment_y", egrid->increment_y, 1);
DRW_shgroup_uniform_vec3(shgrp, "increment_z", egrid->increment_z, 1);
- DRW_shgroup_uniform_vec3(shgrp, "screen_vecs[0]", DRW_viewport_screenvecs_get(), 2);
+ DRW_shgroup_uniform_vec3(shgrp, "screen_vecs", DRW_viewport_screenvecs_get(), 2);
DRW_shgroup_uniform_texture_ref(shgrp, "irradianceGrid", &lcache->grid_tx.tex);
DRW_shgroup_uniform_float_copy(
shgrp, "sphere_size", scene_eval->eevee.gi_irradiance_draw_size * 0.5f);
@@ -436,8 +410,7 @@ void EEVEE_lightprobes_cache_init(EEVEE_ViewLayerData *sldata, EEVEE_Data *vedat
DRW_shgroup_uniform_block(shgrp, "planar_block", sldata->planar_ubo);
DRW_shgroup_uniform_block(shgrp, "grid_block", sldata->grid_ubo);
DRW_shgroup_uniform_block(shgrp, "common_block", sldata->common_ubo);
- DRW_shgroup_uniform_block(
- shgrp, "renderpass_block", EEVEE_material_default_render_pass_ubo_get(sldata));
+ DRW_shgroup_uniform_block(shgrp, "renderpass_block", sldata->renderpass_ubo.combined);
int tri_count = egrid->resolution[0] * egrid->resolution[1] * egrid->resolution[2] * 2;
DRW_shgroup_call_procedural_triangles(shgrp, NULL, tri_count);
}
@@ -455,8 +428,7 @@ void EEVEE_lightprobes_cache_init(EEVEE_ViewLayerData *sldata, EEVEE_Data *vedat
DRWShadingGroup *grp = DRW_shgroup_create(EEVEE_shaders_probe_planar_display_sh_get(),
psl->probe_display);
DRW_shgroup_uniform_texture_ref(grp, "probePlanars", &txl->planar_pool);
- DRW_shgroup_uniform_block(
- grp, "renderpass_block", EEVEE_material_default_render_pass_ubo_get(sldata));
+ DRW_shgroup_uniform_block(grp, "renderpass_block", sldata->renderpass_ubo.combined);
stl->g_data->planar_display_shgrp = DRW_shgroup_call_buffer_instance(
grp, e_data.format_probe_display_planar, DRW_cache_quad_get());
@@ -923,12 +895,10 @@ static void lightbake_render_scene_face(int face, EEVEE_BakeRenderData *user_dat
GPU_framebuffer_bind(face_fb[face]);
GPU_framebuffer_clear_depth(face_fb[face], 1.0f);
- DRW_draw_pass(psl->depth_pass);
- DRW_draw_pass(psl->depth_pass_cull);
+ DRW_draw_pass(psl->depth_ps);
DRW_draw_pass(psl->probe_background);
- EEVEE_materials_draw_opaque(sldata, psl);
- DRW_draw_pass(psl->sss_pass); /* Only output standard pass */
- DRW_draw_pass(psl->sss_pass_cull);
+ DRW_draw_pass(psl->material_ps);
+ DRW_draw_pass(psl->material_sss_ps); /* Only output standard pass */
DRW_draw_pass(psl->transparent_pass);
}
@@ -987,10 +957,8 @@ static void lightbake_render_scene_reflected(int layer, EEVEE_BakeRenderData *us
/* Slight modification: we handle refraction as normal
* shading and don't do SSRefraction. */
- DRW_draw_pass(psl->depth_pass_clip);
- DRW_draw_pass(psl->depth_pass_clip_cull);
- DRW_draw_pass(psl->refract_depth_pass_clip);
- DRW_draw_pass(psl->refract_depth_pass_clip_cull);
+ DRW_draw_pass(psl->depth_ps);
+ DRW_draw_pass(psl->depth_refract_ps);
DRW_draw_pass(psl->probe_background);
EEVEE_create_minmax_buffer(vedata, tmp_planar_depth, layer);
@@ -999,10 +967,9 @@ static void lightbake_render_scene_reflected(int layer, EEVEE_BakeRenderData *us
GPU_framebuffer_bind(fbl->planarref_fb);
/* Shading pass */
- EEVEE_materials_draw_opaque(sldata, psl);
- DRW_draw_pass(psl->sss_pass); /* Only output standard pass */
- DRW_draw_pass(psl->sss_pass_cull);
- DRW_draw_pass(psl->refract_pass);
+ DRW_draw_pass(psl->material_ps);
+ DRW_draw_pass(psl->material_sss_ps); /* Only output standard pass */
+ DRW_draw_pass(psl->material_refract_ps);
/* Transparent */
if (DRW_state_is_image_render()) {
diff --git a/source/blender/draw/engines/eevee/eevee_lookdev.c b/source/blender/draw/engines/eevee/eevee_lookdev.c
index b33be750d80..18365d69514 100644
--- a/source/blender/draw/engines/eevee/eevee_lookdev.c
+++ b/source/blender/draw/engines/eevee/eevee_lookdev.c
@@ -34,6 +34,8 @@
#include "ED_screen.h"
+#include "GPU_material.h"
+
#include "UI_resources.h"
#include "eevee_lightcache.h"
@@ -56,6 +58,43 @@ static void eevee_lookdev_lightcache_delete(EEVEE_Data *vedata)
g_data->studiolight_rot_z = 0.0f;
}
+static void eevee_lookdev_hdri_preview_init(EEVEE_Data *vedata, EEVEE_ViewLayerData *sldata)
+{
+ EEVEE_PassList *psl = vedata->psl;
+ const DRWContextState *draw_ctx = DRW_context_state_get();
+ Scene *scene = draw_ctx->scene;
+ DRWShadingGroup *grp;
+
+ struct GPUBatch *sphere = DRW_cache_sphere_get();
+ int mat_options = VAR_MAT_MESH | VAR_MAT_LOOKDEV;
+
+ DRWState state = DRW_STATE_WRITE_COLOR | DRW_STATE_WRITE_DEPTH | DRW_STATE_DEPTH_ALWAYS |
+ DRW_STATE_CULL_BACK;
+
+ {
+ Material *ma = EEVEE_material_default_diffuse_get();
+ GPUMaterial *gpumat = EEVEE_material_get(vedata, scene, ma, NULL, mat_options);
+ struct GPUShader *sh = GPU_material_get_shader(gpumat);
+
+ DRW_PASS_CREATE(psl->lookdev_diffuse_pass, state);
+ grp = DRW_shgroup_create(sh, psl->lookdev_diffuse_pass);
+ EEVEE_material_bind_resources(grp, gpumat, sldata, vedata, NULL, NULL, false, false);
+ DRW_shgroup_add_material_resources(grp, gpumat);
+ DRW_shgroup_call(grp, sphere, NULL);
+ }
+ {
+ Material *ma = EEVEE_material_default_glossy_get();
+ GPUMaterial *gpumat = EEVEE_material_get(vedata, scene, ma, NULL, mat_options);
+ struct GPUShader *sh = GPU_material_get_shader(gpumat);
+
+ DRW_PASS_CREATE(psl->lookdev_glossy_pass, state);
+ grp = DRW_shgroup_create(sh, psl->lookdev_glossy_pass);
+ EEVEE_material_bind_resources(grp, gpumat, sldata, vedata, NULL, NULL, false, false);
+ DRW_shgroup_add_material_resources(grp, gpumat);
+ DRW_shgroup_call(grp, sphere, NULL);
+ }
+}
+
void EEVEE_lookdev_cache_init(EEVEE_Data *vedata,
EEVEE_ViewLayerData *sldata,
DRWShadingGroup **r_grp,
@@ -106,6 +145,8 @@ void EEVEE_lookdev_cache_init(EEVEE_Data *vedata,
effects->anchor[1] = rect->ymin;
EEVEE_temporal_sampling_reset(vedata);
}
+
+ eevee_lookdev_hdri_preview_init(vedata, sldata);
}
if (LOOK_DEV_STUDIO_LIGHT_ENABLED(v3d)) {
@@ -176,8 +217,7 @@ void EEVEE_lookdev_cache_init(EEVEE_Data *vedata,
DRW_shgroup_uniform_block(grp, "grid_block", sldata->grid_ubo);
DRW_shgroup_uniform_block(grp, "planar_block", sldata->planar_ubo);
DRW_shgroup_uniform_block(grp, "common_block", sldata->common_ubo);
- DRW_shgroup_uniform_block(
- grp, "renderpass_block", EEVEE_material_default_render_pass_ubo_get(sldata));
+ DRW_shgroup_uniform_block(grp, "renderpass_block", sldata->renderpass_ubo.combined);
}
DRW_shgroup_call(grp, DRW_cache_fullscreen_quad_get(), NULL);
diff --git a/source/blender/draw/engines/eevee/eevee_lut_gen.c b/source/blender/draw/engines/eevee/eevee_lut_gen.c
new file mode 100644
index 00000000000..5f20d6fbfb8
--- /dev/null
+++ b/source/blender/draw/engines/eevee/eevee_lut_gen.c
@@ -0,0 +1,198 @@
+/*
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * Copyright 2020, Blender Foundation.
+ */
+
+/** \file
+ * \ingroup draw_engine
+ *
+ * EEVEE LUT generation:
+ *
+ * Routine to generate the LUT used by eevee stored in eevee_lut.h
+ * Theses functions are not to be used in the final executable.
+ */
+
+#include "DRW_render.h"
+
+#include "BLI_alloca.h"
+#include "BLI_rand.h"
+#include "BLI_string_utils.h"
+
+extern char datatoc_bsdf_lut_frag_glsl[];
+extern char datatoc_btdf_lut_frag_glsl[];
+extern char datatoc_bsdf_common_lib_glsl[];
+extern char datatoc_bsdf_sampling_lib_glsl[];
+extern char datatoc_lightprobe_geom_glsl[];
+extern char datatoc_lightprobe_vert_glsl[];
+
+static struct GPUTexture *create_ggx_lut_texture(int UNUSED(w), int UNUSED(h))
+{
+ struct GPUTexture *tex;
+ struct GPUFrameBuffer *fb = NULL;
+ static float samples_len = 8192.0f;
+ static float inv_samples_len = 1.0f / 8192.0f;
+
+ char *lib_str = BLI_string_joinN(datatoc_bsdf_common_lib_glsl, datatoc_bsdf_sampling_lib_glsl);
+
+ struct GPUShader *sh = DRW_shader_create_with_lib(datatoc_lightprobe_vert_glsl,
+ datatoc_lightprobe_geom_glsl,
+ datatoc_bsdf_lut_frag_glsl,
+ lib_str,
+ "#define HAMMERSLEY_SIZE 8192\n"
+ "#define BRDF_LUT_SIZE 64\n"
+ "#define NOISE_SIZE 64\n");
+
+ DRWPass *pass = DRW_pass_create("LightProbe Filtering", DRW_STATE_WRITE_COLOR);
+ DRWShadingGroup *grp = DRW_shgroup_create(sh, pass);
+ DRW_shgroup_uniform_float(grp, "sampleCount", &samples_len, 1);
+ DRW_shgroup_uniform_float(grp, "invSampleCount", &inv_samples_len, 1);
+ DRW_shgroup_uniform_texture(grp, "texHammersley", e_data.hammersley);
+ DRW_shgroup_uniform_texture(grp, "texJitter", e_data.jitter);
+
+ struct GPUBatch *geom = DRW_cache_fullscreen_quad_get();
+ DRW_shgroup_call(grp, geom, NULL);
+
+ float *texels = MEM_mallocN(sizeof(float[2]) * w * h, "lut");
+
+ tex = DRW_texture_create_2d(w, h, GPU_RG16F, DRW_TEX_FILTER, (float *)texels);
+
+ DRWFboTexture tex_filter = {&tex, GPU_RG16F, DRW_TEX_FILTER};
+ GPU_framebuffer_init(&fb, &draw_engine_eevee_type, w, h, &tex_filter, 1);
+
+ GPU_framebuffer_bind(fb);
+ DRW_draw_pass(pass);
+
+ float *data = MEM_mallocN(sizeof(float[3]) * w * h, "lut");
+ glReadBuffer(GL_COLOR_ATTACHMENT0);
+ glReadPixels(0, 0, w, h, GL_RGB, GL_FLOAT, data);
+
+ printf("{");
+ for (int i = 0; i < w * h * 3; i += 3) {
+ printf("%ff, %ff, ", data[i], data[i + 1]);
+ i += 3;
+ printf("%ff, %ff, ", data[i], data[i + 1]);
+ i += 3;
+ printf("%ff, %ff, ", data[i], data[i + 1]);
+ i += 3;
+ printf("%ff, %ff, \n", data[i], data[i + 1]);
+ }
+ printf("}");
+
+ MEM_freeN(texels);
+ MEM_freeN(data);
+
+ return tex;
+}
+
+static struct GPUTexture *create_ggx_refraction_lut_texture(int w, int h)
+{
+ struct GPUTexture *tex;
+ struct GPUTexture *hammersley = create_hammersley_sample_texture(8192);
+ struct GPUFrameBuffer *fb = NULL;
+ static float samples_len = 8192.0f;
+ static float a2 = 0.0f;
+ static float inv_samples_len = 1.0f / 8192.0f;
+
+ char *frag_str = BLI_string_joinN(
+ datatoc_bsdf_common_lib_glsl, datatoc_bsdf_sampling_lib_glsl, datatoc_btdf_lut_frag_glsl);
+
+ struct GPUShader *sh = DRW_shader_create_fullscreen(frag_str,
+ "#define HAMMERSLEY_SIZE 8192\n"
+ "#define BRDF_LUT_SIZE 64\n"
+ "#define NOISE_SIZE 64\n"
+ "#define LUT_SIZE 64\n");
+
+ MEM_freeN(frag_str);
+
+ DRWPass *pass = DRW_pass_create("LightProbe Filtering", DRW_STATE_WRITE_COLOR);
+ DRWShadingGroup *grp = DRW_shgroup_create(sh, pass);
+ DRW_shgroup_uniform_float(grp, "a2", &a2, 1);
+ DRW_shgroup_uniform_float(grp, "sampleCount", &samples_len, 1);
+ DRW_shgroup_uniform_float(grp, "invSampleCount", &inv_samples_len, 1);
+ DRW_shgroup_uniform_texture(grp, "texHammersley", hammersley);
+ DRW_shgroup_uniform_texture(grp, "utilTex", e_data.util_tex);
+
+ struct GPUBatch *geom = DRW_cache_fullscreen_quad_get();
+ DRW_shgroup_call(grp, geom, NULL);
+
+ float *texels = MEM_mallocN(sizeof(float[2]) * w * h, "lut");
+
+ tex = DRW_texture_create_2d(w, h, GPU_R16F, DRW_TEX_FILTER, (float *)texels);
+
+ DRWFboTexture tex_filter = {&tex, GPU_R16F, DRW_TEX_FILTER};
+ GPU_framebuffer_init(&fb, &draw_engine_eevee_type, w, h, &tex_filter, 1);
+
+ GPU_framebuffer_bind(fb);
+
+ float *data = MEM_mallocN(sizeof(float[3]) * w * h, "lut");
+
+ float inc = 1.0f / 31.0f;
+ float roughness = 1e-8f - inc;
+ FILE *f = BLI_fopen("btdf_split_sum_ggx.h", "w");
+ fprintf(f, "static float btdf_split_sum_ggx[32][64 * 64] = {\n");
+ do {
+ roughness += inc;
+ CLAMP(roughness, 1e-4f, 1.0f);
+ a2 = powf(roughness, 4.0f);
+ DRW_draw_pass(pass);
+
+ GPU_framebuffer_read_data(0, 0, w, h, 3, 0, data);
+
+#if 1
+ fprintf(f, "\t{\n\t\t");
+ for (int i = 0; i < w * h * 3; i += 3) {
+ fprintf(f, "%ff,", data[i]);
+ if (((i / 3) + 1) % 12 == 0) {
+ fprintf(f, "\n\t\t");
+ }
+ else {
+ fprintf(f, " ");
+ }
+ }
+ fprintf(f, "\n\t},\n");
+#else
+ for (int i = 0; i < w * h * 3; i += 3) {
+ if (data[i] < 0.01) {
+ printf(" ");
+ }
+ else if (data[i] < 0.3) {
+ printf(".");
+ }
+ else if (data[i] < 0.6) {
+ printf("+");
+ }
+ else if (data[i] < 0.9) {
+ printf("%%");
+ }
+ else {
+ printf("#");
+ }
+ if ((i / 3 + 1) % 64 == 0) {
+ printf("\n");
+ }
+ }
+#endif
+
+ } while (roughness < 1.0f);
+ fprintf(f, "\n};\n");
+
+ fclose(f);
+
+ MEM_freeN(texels);
+ MEM_freeN(data);
+
+ return tex;
+} \ No newline at end of file
diff --git a/source/blender/draw/engines/eevee/eevee_materials.c b/source/blender/draw/engines/eevee/eevee_materials.c
index 79087ddfa9e..cfc70baaf01 100644
--- a/source/blender/draw/engines/eevee/eevee_materials.c
+++ b/source/blender/draw/engines/eevee/eevee_materials.c
@@ -23,9 +23,10 @@
#include "DRW_render.h"
#include "BLI_alloca.h"
-#include "BLI_dynstr.h"
#include "BLI_ghash.h"
+#include "BLI_listbase.h"
#include "BLI_math_bits.h"
+#include "BLI_memblock.h"
#include "BLI_rand.h"
#include "BLI_string_utils.h"
@@ -47,29 +48,11 @@
/* *********** STATIC *********** */
static struct {
- char *frag_shader_lib;
- char *vert_shader_str;
- char *vert_shadow_shader_str;
- char *vert_background_shader_str;
- char *vert_volume_shader_str;
- char *geom_volume_shader_str;
- char *volume_shader_lib;
-
- struct GPUShader *default_prepass_sh;
- struct GPUShader *default_prepass_clip_sh;
- struct GPUShader *default_hair_prepass_sh;
- struct GPUShader *default_hair_prepass_clip_sh;
- struct GPUShader *default_lit[VAR_MAT_MAX];
- struct GPUShader *default_background;
- struct GPUShader *update_noise_sh;
-
/* 64*64 array texture containing all LUTs and other utilitarian arrays.
* Packing enables us to same precious textures slots. */
struct GPUTexture *util_tex;
struct GPUTexture *noise_tex;
- uint sss_count;
-
float noise_offsets[3];
} e_data = {NULL}; /* Engine data */
@@ -81,8 +64,6 @@ extern char datatoc_prepass_vert_glsl[];
extern char datatoc_default_frag_glsl[];
extern char datatoc_default_world_frag_glsl[];
extern char datatoc_ltc_lib_glsl[];
-extern char datatoc_bsdf_lut_frag_glsl[];
-extern char datatoc_btdf_lut_frag_glsl[];
extern char datatoc_bsdf_common_lib_glsl[];
extern char datatoc_bsdf_sampling_lib_glsl[];
extern char datatoc_common_uniforms_lib_glsl[];
@@ -106,319 +87,45 @@ extern char datatoc_volumetric_frag_glsl[];
extern char datatoc_volumetric_lib_glsl[];
extern char datatoc_gpu_shader_uniform_color_frag_glsl[];
-#define DEFAULT_RENDER_PASS_FLAG 0xefffffff
-
-/* Iterator for render passes. This iteration will only do the material based render passes. it
- * will ignore `EEVEE_RENDER_PASS_ENVIRONMENT`.
- *
- * parameters:
- * - `render_passes_` is a bitflag for render_passes that needs to be iterated over.
- * - `render_pass_index_` is a parameter name where the index of the render_pass will be available
- * during iteration. This index can be used to select the right pass in the `psl`.
- * - `render_pass_` is the bitflag of the render_pass of the current iteration.
- *
- * The `render_pass_index_` parameter needs to be the same for the `RENDER_PASS_ITER_BEGIN` and
- * `RENDER_PASS_ITER_END`.
- */
-#define RENDER_PASS_ITER_BEGIN(render_passes_, render_pass_index_, render_pass_) \
- const eViewLayerEEVEEPassType __filtered_##render_pass_index_ = render_passes_ & \
- EEVEE_RENDERPASSES_MATERIAL & \
- ~EEVEE_RENDER_PASS_ENVIRONMENT; \
- if (__filtered_##render_pass_index_ != 0) { \
- int render_pass_index_ = 1; \
- for (int bit_##render_pass_ = 0; bit_##render_pass_ < EEVEE_RENDER_PASS_MAX_BIT; \
- bit_##render_pass_++) { \
- eViewLayerEEVEEPassType render_pass_ = (1 << bit_##render_pass_); \
- if ((__filtered_##render_pass_index_ & render_pass_) != 0) {
-#define RENDER_PASS_ITER_END(render_pass_index_) \
- render_pass_index_ += 1; \
- } \
- } \
- }
+typedef struct EeveeMaterialCache {
+ struct DRWShadingGroup *depth_grp;
+ struct DRWShadingGroup *shading_grp;
+ struct DRWShadingGroup *shadow_grp;
+ struct GPUMaterial *shading_gpumat;
+ /* Meh, Used by hair to ensure draw order when calling DRW_shgroup_create_sub.
+ * Pointers to ghash values. */
+ struct DRWShadingGroup **depth_grp_p;
+ struct DRWShadingGroup **shading_grp_p;
+ struct DRWShadingGroup **shadow_grp_p;
+} EeveeMaterialCache;
/* *********** FUNCTIONS *********** */
-#if 0 /* Used only to generate the LUT values */
-static struct GPUTexture *create_ggx_lut_texture(int UNUSED(w), int UNUSED(h))
-{
- struct GPUTexture *tex;
- struct GPUFrameBuffer *fb = NULL;
- static float samples_len = 8192.0f;
- static float inv_samples_len = 1.0f / 8192.0f;
-
- char *lib_str = BLI_string_joinN(datatoc_bsdf_common_lib_glsl, datatoc_bsdf_sampling_lib_glsl);
-
- struct GPUShader *sh = DRW_shader_create_with_lib(datatoc_lightprobe_vert_glsl,
- datatoc_lightprobe_geom_glsl,
- datatoc_bsdf_lut_frag_glsl,
- lib_str,
- "#define HAMMERSLEY_SIZE 8192\n"
- "#define BRDF_LUT_SIZE 64\n"
- "#define NOISE_SIZE 64\n");
-
- DRWPass *pass = DRW_pass_create("LightProbe Filtering", DRW_STATE_WRITE_COLOR);
- DRWShadingGroup *grp = DRW_shgroup_create(sh, pass);
- DRW_shgroup_uniform_float(grp, "sampleCount", &samples_len, 1);
- DRW_shgroup_uniform_float(grp, "invSampleCount", &inv_samples_len, 1);
- DRW_shgroup_uniform_texture(grp, "texHammersley", e_data.hammersley);
- DRW_shgroup_uniform_texture(grp, "texJitter", e_data.jitter);
-
- struct GPUBatch *geom = DRW_cache_fullscreen_quad_get();
- DRW_shgroup_call(grp, geom, NULL);
-
- float *texels = MEM_mallocN(sizeof(float[2]) * w * h, "lut");
-
- tex = DRW_texture_create_2d(w, h, GPU_RG16F, DRW_TEX_FILTER, (float *)texels);
-
- DRWFboTexture tex_filter = {&tex, GPU_RG16F, DRW_TEX_FILTER};
- GPU_framebuffer_init(&fb, &draw_engine_eevee_type, w, h, &tex_filter, 1);
-
- GPU_framebuffer_bind(fb);
- DRW_draw_pass(pass);
-
- float *data = MEM_mallocN(sizeof(float[3]) * w * h, "lut");
- glReadBuffer(GL_COLOR_ATTACHMENT0);
- glReadPixels(0, 0, w, h, GL_RGB, GL_FLOAT, data);
-
- printf("{");
- for (int i = 0; i < w * h * 3; i += 3) {
- printf("%ff, %ff, ", data[i], data[i + 1]);
- i += 3;
- printf("%ff, %ff, ", data[i], data[i + 1]);
- i += 3;
- printf("%ff, %ff, ", data[i], data[i + 1]);
- i += 3;
- printf("%ff, %ff, \n", data[i], data[i + 1]);
- }
- printf("}");
-
- MEM_freeN(texels);
- MEM_freeN(data);
-
- return tex;
-}
-
-static struct GPUTexture *create_ggx_refraction_lut_texture(int w, int h)
-{
- struct GPUTexture *tex;
- struct GPUTexture *hammersley = create_hammersley_sample_texture(8192);
- struct GPUFrameBuffer *fb = NULL;
- static float samples_len = 8192.0f;
- static float a2 = 0.0f;
- static float inv_samples_len = 1.0f / 8192.0f;
-
- char *frag_str = BLI_string_joinN(
- datatoc_bsdf_common_lib_glsl, datatoc_bsdf_sampling_lib_glsl, datatoc_btdf_lut_frag_glsl);
-
- struct GPUShader *sh = DRW_shader_create_fullscreen(frag_str,
- "#define HAMMERSLEY_SIZE 8192\n"
- "#define BRDF_LUT_SIZE 64\n"
- "#define NOISE_SIZE 64\n"
- "#define LUT_SIZE 64\n");
-
- MEM_freeN(frag_str);
-
- DRWPass *pass = DRW_pass_create("LightProbe Filtering", DRW_STATE_WRITE_COLOR);
- DRWShadingGroup *grp = DRW_shgroup_create(sh, pass);
- DRW_shgroup_uniform_float(grp, "a2", &a2, 1);
- DRW_shgroup_uniform_float(grp, "sampleCount", &samples_len, 1);
- DRW_shgroup_uniform_float(grp, "invSampleCount", &inv_samples_len, 1);
- DRW_shgroup_uniform_texture(grp, "texHammersley", hammersley);
- DRW_shgroup_uniform_texture(grp, "utilTex", e_data.util_tex);
-
- struct GPUBatch *geom = DRW_cache_fullscreen_quad_get();
- DRW_shgroup_call(grp, geom, NULL);
-
- float *texels = MEM_mallocN(sizeof(float[2]) * w * h, "lut");
-
- tex = DRW_texture_create_2d(w, h, GPU_R16F, DRW_TEX_FILTER, (float *)texels);
-
- DRWFboTexture tex_filter = {&tex, GPU_R16F, DRW_TEX_FILTER};
- GPU_framebuffer_init(&fb, &draw_engine_eevee_type, w, h, &tex_filter, 1);
-
- GPU_framebuffer_bind(fb);
-
- float *data = MEM_mallocN(sizeof(float[3]) * w * h, "lut");
-
- float inc = 1.0f / 31.0f;
- float roughness = 1e-8f - inc;
- FILE *f = BLI_fopen("btdf_split_sum_ggx.h", "w");
- fprintf(f, "static float btdf_split_sum_ggx[32][64 * 64] = {\n");
- do {
- roughness += inc;
- CLAMP(roughness, 1e-4f, 1.0f);
- a2 = powf(roughness, 4.0f);
- DRW_draw_pass(pass);
-
- GPU_framebuffer_read_data(0, 0, w, h, 3, 0, data);
-
-# if 1
- fprintf(f, "\t{\n\t\t");
- for (int i = 0; i < w * h * 3; i += 3) {
- fprintf(f, "%ff,", data[i]);
- if (((i / 3) + 1) % 12 == 0) {
- fprintf(f, "\n\t\t");
- }
- else {
- fprintf(f, " ");
- }
- }
- fprintf(f, "\n\t},\n");
-# else
- for (int i = 0; i < w * h * 3; i += 3) {
- if (data[i] < 0.01) {
- printf(" ");
- }
- else if (data[i] < 0.3) {
- printf(".");
- }
- else if (data[i] < 0.6) {
- printf("+");
- }
- else if (data[i] < 0.9) {
- printf("%%");
- }
- else {
- printf("#");
- }
- if ((i / 3 + 1) % 64 == 0) {
- printf("\n");
- }
- }
-# endif
-
- } while (roughness < 1.0f);
- fprintf(f, "\n};\n");
-
- fclose(f);
-
- MEM_freeN(texels);
- MEM_freeN(data);
-
- return tex;
-}
-#endif
/* XXX TODO define all shared resources in a shared place without duplication */
struct GPUTexture *EEVEE_materials_get_util_tex(void)
{
return e_data.util_tex;
}
-static char *eevee_get_defines(int options)
-{
- char *str = NULL;
-
- DynStr *ds = BLI_dynstr_new();
- BLI_dynstr_append(ds, SHADER_DEFINES);
-
- if ((options & VAR_MAT_MESH) != 0) {
- BLI_dynstr_append(ds, "#define MESH_SHADER\n");
- }
- if ((options & VAR_MAT_HAIR) != 0) {
- BLI_dynstr_append(ds, "#define HAIR_SHADER\n");
- }
- if ((options & VAR_MAT_PROBE) != 0) {
- BLI_dynstr_append(ds, "#define PROBE_CAPTURE\n");
- }
- if ((options & VAR_MAT_CLIP) != 0) {
- BLI_dynstr_append(ds, "#define USE_ALPHA_CLIP\n");
- }
- if ((options & VAR_MAT_SHADOW) != 0) {
- BLI_dynstr_append(ds, "#define SHADOW_SHADER\n");
- }
- if ((options & VAR_MAT_HASH) != 0) {
- BLI_dynstr_append(ds, "#define USE_ALPHA_HASH\n");
- }
- if ((options & VAR_MAT_BLEND) != 0) {
- BLI_dynstr_append(ds, "#define USE_ALPHA_BLEND\n");
- }
- if ((options & VAR_MAT_MULT) != 0) {
- BLI_dynstr_append(ds, "#define USE_MULTIPLY\n");
- }
- if ((options & VAR_MAT_REFRACT) != 0) {
- BLI_dynstr_append(ds, "#define USE_REFRACTION\n");
- }
- if ((options & VAR_MAT_LOOKDEV) != 0) {
- BLI_dynstr_append(ds, "#define LOOKDEV\n");
- }
- if ((options & VAR_MAT_HOLDOUT) != 0) {
- BLI_dynstr_append(ds, "#define HOLDOUT\n");
- }
-
- str = BLI_dynstr_get_cstring(ds);
- BLI_dynstr_free(ds);
-
- return str;
-}
-
-static char *eevee_get_volume_defines(int options)
-{
- char *str = NULL;
-
- DynStr *ds = BLI_dynstr_new();
- BLI_dynstr_append(ds, SHADER_DEFINES);
- BLI_dynstr_append(ds, "#define VOLUMETRICS\n");
-
- if ((options & VAR_MAT_VOLUME) != 0) {
- BLI_dynstr_append(ds, "#define MESH_SHADER\n");
- }
-
- str = BLI_dynstr_get_cstring(ds);
- BLI_dynstr_free(ds);
-
- return str;
-}
-
-/* Get the default render pass ubo. This is a ubo that enables all bsdf render passes. */
-struct GPUUniformBuffer *EEVEE_material_default_render_pass_ubo_get(EEVEE_ViewLayerData *sldata)
-{
- return sldata->renderpass_ubo[0];
-}
-
-/* Get the render pass ubo for rendering the given render_pass. */
-static struct GPUUniformBuffer *get_render_pass_ubo(EEVEE_ViewLayerData *sldata,
- eViewLayerEEVEEPassType render_pass)
-{
- int index;
- switch (render_pass) {
- case EEVEE_RENDER_PASS_DIFFUSE_COLOR:
- index = 1;
- break;
- case EEVEE_RENDER_PASS_DIFFUSE_LIGHT:
- index = 2;
- break;
- case EEVEE_RENDER_PASS_SPECULAR_COLOR:
- index = 3;
- break;
- case EEVEE_RENDER_PASS_SPECULAR_LIGHT:
- index = 4;
- break;
- case EEVEE_RENDER_PASS_EMIT:
- index = 5;
- break;
- default:
- index = 0;
- break;
- }
- return sldata->renderpass_ubo[index];
-}
/**
* ssr_id can be null to disable ssr contribution.
*/
-static void add_standard_uniforms(DRWShadingGroup *shgrp,
- EEVEE_ViewLayerData *sldata,
- EEVEE_Data *vedata,
- int *ssr_id,
- float *refract_depth,
- bool use_diffuse,
- bool use_glossy,
- bool use_refract,
- bool use_ssrefraction,
- bool use_alpha_blend,
- eViewLayerEEVEEPassType render_pass)
+void EEVEE_material_bind_resources(DRWShadingGroup *shgrp,
+ GPUMaterial *gpumat,
+ EEVEE_ViewLayerData *sldata,
+ EEVEE_Data *vedata,
+ int *ssr_id,
+ float *refract_depth,
+ bool use_ssrefraction,
+ bool use_alpha_blend)
{
+ bool use_diffuse = GPU_material_flag_get(gpumat, GPU_MATFLAG_DIFFUSE);
+ bool use_glossy = GPU_material_flag_get(gpumat, GPU_MATFLAG_GLOSSY);
+ bool use_refract = GPU_material_flag_get(gpumat, GPU_MATFLAG_REFRACT);
+
LightCache *lcache = vedata->stl->g_data->light_cache;
EEVEE_EffectsInfo *effects = vedata->stl->effects;
+ EEVEE_PrivateData *pd = vedata->stl->g_data;
DRW_shgroup_uniform_block(shgrp, "probe_block", sldata->probe_ubo);
DRW_shgroup_uniform_block(shgrp, "grid_block", sldata->grid_ubo);
@@ -426,11 +133,11 @@ static void add_standard_uniforms(DRWShadingGroup *shgrp,
DRW_shgroup_uniform_block(shgrp, "light_block", sldata->light_ubo);
DRW_shgroup_uniform_block(shgrp, "shadow_block", sldata->shadow_ubo);
DRW_shgroup_uniform_block(shgrp, "common_block", sldata->common_ubo);
- DRW_shgroup_uniform_block(shgrp, "renderpass_block", get_render_pass_ubo(sldata, render_pass));
+ DRW_shgroup_uniform_block_ref(shgrp, "renderpass_block", &pd->renderpass_ubo);
DRW_shgroup_uniform_int_copy(shgrp, "outputSssId", 1);
+ DRW_shgroup_uniform_texture(shgrp, "utilTex", e_data.util_tex);
if (use_diffuse || use_glossy || use_refract) {
- DRW_shgroup_uniform_texture(shgrp, "utilTex", e_data.util_tex);
DRW_shgroup_uniform_texture_ref(shgrp, "shadowCubeTexture", &sldata->shadow_cube_pool);
DRW_shgroup_uniform_texture_ref(shgrp, "shadowCascadeTexture", &sldata->shadow_cascade_pool);
DRW_shgroup_uniform_texture_ref(shgrp, "maxzBuffer", &vedata->txl->maxzbuffer);
@@ -461,36 +168,6 @@ static void add_standard_uniforms(DRWShadingGroup *shgrp,
}
}
-/* Add the uniforms for the background shader to `shgrp`. */
-static void add_background_uniforms(DRWShadingGroup *shgrp,
- EEVEE_ViewLayerData *sldata,
- EEVEE_Data *vedata)
-{
- EEVEE_StorageList *stl = ((EEVEE_Data *)vedata)->stl;
- DRW_shgroup_uniform_float(shgrp, "backgroundAlpha", &stl->g_data->background_alpha, 1);
- /* TODO (fclem): remove those (need to clean the GLSL files). */
- DRW_shgroup_uniform_block(shgrp, "common_block", sldata->common_ubo);
- DRW_shgroup_uniform_block(shgrp, "grid_block", sldata->grid_ubo);
- DRW_shgroup_uniform_block(shgrp, "probe_block", sldata->probe_ubo);
- DRW_shgroup_uniform_block(shgrp, "planar_block", sldata->planar_ubo);
- DRW_shgroup_uniform_block(shgrp, "light_block", sldata->light_ubo);
- DRW_shgroup_uniform_block(shgrp, "shadow_block", sldata->shadow_ubo);
- DRW_shgroup_uniform_block(
- shgrp, "renderpass_block", EEVEE_material_default_render_pass_ubo_get(sldata));
-}
-
-static void create_default_shader(int options)
-{
- char *frag_str = BLI_string_joinN(e_data.frag_shader_lib, datatoc_default_frag_glsl);
-
- char *defines = eevee_get_defines(options);
-
- e_data.default_lit[options] = DRW_shader_create(e_data.vert_shader_str, NULL, frag_str, defines);
-
- MEM_freeN(defines);
- MEM_freeN(frag_str);
-}
-
static void eevee_init_noise_texture(void)
{
e_data.noise_tex = DRW_texture_create_2d(64, 64, GPU_RGBA16F, 0, (float *)blue_noise);
@@ -557,8 +234,6 @@ void EEVEE_update_noise(EEVEE_PassList *psl, EEVEE_FramebufferList *fbl, const d
e_data.noise_offsets[1] = offsets[1];
e_data.noise_offsets[2] = offsets[2];
- /* Attach & detach because we don't currently support multiple FB per texture,
- * and this would be the case for multiple viewport. */
GPU_framebuffer_bind(fbl->update_noise_fb);
DRW_draw_pass(psl->update_noise_pass);
}
@@ -604,94 +279,15 @@ void EEVEE_update_viewvecs(float invproj[4][4], float winmat[4][4], float (*r_vi
}
void EEVEE_materials_init(EEVEE_ViewLayerData *sldata,
+ EEVEE_Data *vedata,
EEVEE_StorageList *stl,
EEVEE_FramebufferList *fbl)
{
const DRWContextState *draw_ctx = DRW_context_state_get();
EEVEE_PrivateData *g_data = stl->g_data;
- if (!e_data.frag_shader_lib) {
- /* Shaders */
- e_data.frag_shader_lib = BLI_string_joinN(datatoc_common_view_lib_glsl,
- datatoc_common_uniforms_lib_glsl,
- datatoc_bsdf_common_lib_glsl,
- datatoc_bsdf_sampling_lib_glsl,
- datatoc_ambient_occlusion_lib_glsl,
- datatoc_raytrace_lib_glsl,
- datatoc_ssr_lib_glsl,
- datatoc_octahedron_lib_glsl,
- datatoc_cubemap_lib_glsl,
- datatoc_irradiance_lib_glsl,
- datatoc_lightprobe_lib_glsl,
- datatoc_ltc_lib_glsl,
- datatoc_lights_lib_glsl,
- /* Add one for each Closure */
- datatoc_lit_surface_frag_glsl,
- datatoc_lit_surface_frag_glsl,
- datatoc_lit_surface_frag_glsl,
- datatoc_lit_surface_frag_glsl,
- datatoc_lit_surface_frag_glsl,
- datatoc_lit_surface_frag_glsl,
- datatoc_lit_surface_frag_glsl,
- datatoc_lit_surface_frag_glsl,
- datatoc_lit_surface_frag_glsl,
- datatoc_lit_surface_frag_glsl,
- datatoc_lit_surface_frag_glsl,
- datatoc_volumetric_lib_glsl);
-
- e_data.volume_shader_lib = BLI_string_joinN(datatoc_common_view_lib_glsl,
- datatoc_common_uniforms_lib_glsl,
- datatoc_bsdf_common_lib_glsl,
- datatoc_ambient_occlusion_lib_glsl,
- datatoc_octahedron_lib_glsl,
- datatoc_cubemap_lib_glsl,
- datatoc_irradiance_lib_glsl,
- datatoc_lightprobe_lib_glsl,
- datatoc_ltc_lib_glsl,
- datatoc_lights_lib_glsl,
- datatoc_volumetric_lib_glsl,
- datatoc_volumetric_frag_glsl);
-
- e_data.vert_shader_str = BLI_string_joinN(
- datatoc_common_view_lib_glsl, datatoc_common_hair_lib_glsl, datatoc_lit_surface_vert_glsl);
-
- e_data.vert_shadow_shader_str = BLI_string_joinN(
- datatoc_common_view_lib_glsl, datatoc_common_hair_lib_glsl, datatoc_shadow_vert_glsl);
-
- e_data.vert_background_shader_str = BLI_string_joinN(datatoc_common_view_lib_glsl,
- datatoc_background_vert_glsl);
-
- e_data.vert_volume_shader_str = BLI_string_joinN(datatoc_common_view_lib_glsl,
- datatoc_volumetric_vert_glsl);
-
- e_data.geom_volume_shader_str = BLI_string_joinN(datatoc_common_view_lib_glsl,
- datatoc_volumetric_geom_glsl);
-
- e_data.default_background = DRW_shader_create_with_lib(datatoc_background_vert_glsl,
- NULL,
- datatoc_default_world_frag_glsl,
- datatoc_common_view_lib_glsl,
- NULL);
-
- char *vert_str = BLI_string_joinN(
- datatoc_common_view_lib_glsl, datatoc_common_hair_lib_glsl, datatoc_prepass_vert_glsl);
-
- e_data.default_prepass_sh = DRW_shader_create(vert_str, NULL, datatoc_prepass_frag_glsl, NULL);
-
- e_data.default_prepass_clip_sh = DRW_shader_create(
- vert_str, NULL, datatoc_prepass_frag_glsl, "#define CLIP_PLANES\n");
-
- e_data.default_hair_prepass_sh = DRW_shader_create(
- vert_str, NULL, datatoc_prepass_frag_glsl, "#define HAIR_SHADER\n");
-
- e_data.default_hair_prepass_clip_sh = DRW_shader_create(vert_str,
- NULL,
- datatoc_prepass_frag_glsl,
- "#define HAIR_SHADER\n"
- "#define CLIP_PLANES\n");
- MEM_freeN(vert_str);
-
- e_data.update_noise_sh = DRW_shader_create_fullscreen(datatoc_update_noise_frag_glsl, NULL);
+ if (!e_data.util_tex) {
+ EEVEE_shaders_material_shaders_init();
eevee_init_util_texture();
eevee_init_noise_texture();
@@ -726,33 +322,36 @@ void EEVEE_materials_init(EEVEE_ViewLayerData *sldata,
{
/* Create RenderPass UBO */
- if (sldata->renderpass_ubo[0] == NULL) {
- /* EEVEE_RENDER_PASS_COMBINED */
- sldata->renderpass_data[0] = (const EEVEE_RenderPassData){
- true, true, true, true, true, false};
- /* EEVEE_RENDER_PASS_DIFFUSE_COLOR */
- sldata->renderpass_data[1] = (const EEVEE_RenderPassData){
- true, false, false, false, false, true};
- /* EEVEE_RENDER_PASS_DIFFUSE_LIGHT */
- sldata->renderpass_data[2] = (const EEVEE_RenderPassData){
- true, true, false, false, false, false};
- /* EEVEE_RENDER_PASS_SPECULAR_COLOR */
- sldata->renderpass_data[3] = (const EEVEE_RenderPassData){
- false, false, true, false, false, false};
- /* EEVEE_RENDER_PASS_SPECULAR_LIGHT */
- sldata->renderpass_data[4] = (const EEVEE_RenderPassData){
- false, false, true, true, false, false};
- /* EEVEE_RENDER_PASS_EMIT */
- sldata->renderpass_data[5] = (const EEVEE_RenderPassData){
- false, false, false, false, true, false};
-
- for (int i = 0; i < MAX_MATERIAL_RENDER_PASSES_UBO; i++) {
- sldata->renderpass_ubo[i] = DRW_uniformbuffer_create(sizeof(EEVEE_RenderPassData),
- &sldata->renderpass_data[i]);
- }
+ if (sldata->renderpass_ubo.combined == NULL) {
+ sldata->renderpass_ubo.combined = DRW_uniformbuffer_create(
+ sizeof(EEVEE_RenderPassData),
+ &(const EEVEE_RenderPassData){true, true, true, true, true, false});
+
+ sldata->renderpass_ubo.diff_color = DRW_uniformbuffer_create(
+ sizeof(EEVEE_RenderPassData),
+ &(const EEVEE_RenderPassData){true, false, false, false, false, true});
+
+ sldata->renderpass_ubo.diff_light = DRW_uniformbuffer_create(
+ sizeof(EEVEE_RenderPassData),
+ &(const EEVEE_RenderPassData){true, true, false, false, false, false});
+
+ sldata->renderpass_ubo.spec_color = DRW_uniformbuffer_create(
+ sizeof(EEVEE_RenderPassData),
+ &(const EEVEE_RenderPassData){false, false, true, false, false, false});
+
+ sldata->renderpass_ubo.spec_light = DRW_uniformbuffer_create(
+ sizeof(EEVEE_RenderPassData),
+ &(const EEVEE_RenderPassData){false, false, true, true, false, false});
+
+ sldata->renderpass_ubo.emit = DRW_uniformbuffer_create(
+ sizeof(EEVEE_RenderPassData),
+ &(const EEVEE_RenderPassData){false, false, false, false, true, false});
}
- /* HACK: EEVEE_material_world_background_get can create a new context. This can only be
+ /* Used combined pass by default. */
+ g_data->renderpass_ubo = sldata->renderpass_ubo.combined;
+
+ /* HACK: EEVEE_material_get can create a new context. This can only be
* done when there is no active framebuffer. We do this here otherwise
* `EEVEE_renderpasses_output_init` will fail. It cannot be done in
* `EEVEE_renderpasses_init` as the `e_data.vertcode` can be uninitialized.
@@ -761,414 +360,12 @@ void EEVEE_materials_init(EEVEE_ViewLayerData *sldata,
struct Scene *scene = draw_ctx->scene;
struct World *wo = scene->world;
if (wo && wo->use_nodes) {
- EEVEE_material_world_background_get(scene, wo);
+ EEVEE_material_get(vedata, scene, NULL, wo, VAR_WORLD_BACKGROUND);
}
}
}
}
-struct GPUMaterial *EEVEE_material_world_lightprobe_get(struct Scene *scene, World *wo)
-{
- const void *engine = &DRW_engine_viewport_eevee_type;
- const int options = VAR_WORLD_PROBE;
-
- GPUMaterial *mat = DRW_shader_find_from_world(wo, engine, options, false);
- if (mat != NULL) {
- return mat;
- }
- return DRW_shader_create_from_world(scene,
- wo,
- engine,
- options,
- false,
- e_data.vert_background_shader_str,
- NULL,
- e_data.frag_shader_lib,
- SHADER_DEFINES "#define PROBE_CAPTURE\n",
- false);
-}
-
-struct GPUMaterial *EEVEE_material_world_background_get(struct Scene *scene, World *wo)
-{
- const void *engine = &DRW_engine_viewport_eevee_type;
- int options = VAR_WORLD_BACKGROUND;
-
- GPUMaterial *mat = DRW_shader_find_from_world(wo, engine, options, true);
- if (mat != NULL) {
- return mat;
- }
- return DRW_shader_create_from_world(scene,
- wo,
- engine,
- options,
- false,
- e_data.vert_background_shader_str,
- NULL,
- e_data.frag_shader_lib,
- SHADER_DEFINES "#define WORLD_BACKGROUND\n",
- true);
-}
-
-struct GPUMaterial *EEVEE_material_world_volume_get(struct Scene *scene, World *wo)
-{
- const void *engine = &DRW_engine_viewport_eevee_type;
- int options = VAR_WORLD_VOLUME;
-
- GPUMaterial *mat = DRW_shader_find_from_world(wo, engine, options, true);
- if (mat != NULL) {
- return mat;
- }
-
- char *defines = eevee_get_volume_defines(options);
-
- mat = DRW_shader_create_from_world(scene,
- wo,
- engine,
- options,
- true,
- e_data.vert_volume_shader_str,
- e_data.geom_volume_shader_str,
- e_data.volume_shader_lib,
- defines,
- true);
-
- MEM_freeN(defines);
-
- return mat;
-}
-
-struct GPUMaterial *EEVEE_material_mesh_get(struct Scene *scene,
- Material *ma,
- EEVEE_Data *UNUSED(vedata),
- bool use_blend,
- bool use_refract)
-{
- const void *engine = &DRW_engine_viewport_eevee_type;
- int options = VAR_MAT_MESH;
-
- SET_FLAG_FROM_TEST(options, use_blend, VAR_MAT_BLEND);
- SET_FLAG_FROM_TEST(options, use_refract, VAR_MAT_REFRACT);
-
- GPUMaterial *mat = DRW_shader_find_from_material(ma, engine, options, true);
- if (mat) {
- return mat;
- }
-
- char *defines = eevee_get_defines(options);
-
- mat = DRW_shader_create_from_material(scene,
- ma,
- engine,
- options,
- false,
- e_data.vert_shader_str,
- NULL,
- e_data.frag_shader_lib,
- defines,
- true);
-
- MEM_freeN(defines);
-
- return mat;
-}
-
-struct GPUMaterial *EEVEE_material_mesh_volume_get(struct Scene *scene, Material *ma)
-{
- const void *engine = &DRW_engine_viewport_eevee_type;
- int options = VAR_MAT_VOLUME;
-
- GPUMaterial *mat = DRW_shader_find_from_material(ma, engine, options, true);
- if (mat != NULL) {
- return mat;
- }
-
- char *defines = eevee_get_volume_defines(options);
-
- mat = DRW_shader_create_from_material(scene,
- ma,
- engine,
- options,
- true,
- e_data.vert_volume_shader_str,
- e_data.geom_volume_shader_str,
- e_data.volume_shader_lib,
- defines,
- true);
-
- MEM_freeN(defines);
-
- return mat;
-}
-
-struct GPUMaterial *EEVEE_material_mesh_depth_get(struct Scene *scene,
- Material *ma,
- bool use_hashed_alpha,
- bool is_shadow)
-{
- const void *engine = &DRW_engine_viewport_eevee_type;
- int options = VAR_MAT_MESH;
-
- SET_FLAG_FROM_TEST(options, use_hashed_alpha, VAR_MAT_HASH);
- SET_FLAG_FROM_TEST(options, !use_hashed_alpha, VAR_MAT_CLIP);
- SET_FLAG_FROM_TEST(options, is_shadow, VAR_MAT_SHADOW);
-
- GPUMaterial *mat = DRW_shader_find_from_material(ma, engine, options, true);
- if (mat) {
- return mat;
- }
-
- char *defines = eevee_get_defines(options);
-
- char *frag_str = BLI_string_joinN(e_data.frag_shader_lib, datatoc_prepass_frag_glsl);
-
- mat = DRW_shader_create_from_material(scene,
- ma,
- engine,
- options,
- false,
- (is_shadow) ? e_data.vert_shadow_shader_str :
- e_data.vert_shader_str,
- NULL,
- frag_str,
- defines,
- true);
-
- MEM_freeN(frag_str);
- MEM_freeN(defines);
-
- return mat;
-}
-
-static struct GPUMaterial *EEVEE_material_hair_depth_get(struct Scene *scene,
- Material *ma,
- bool use_hashed_alpha,
- bool is_shadow)
-{
- const void *engine = &DRW_engine_viewport_eevee_type;
- int options = VAR_MAT_MESH | VAR_MAT_HAIR;
-
- SET_FLAG_FROM_TEST(options, use_hashed_alpha, VAR_MAT_HASH);
- SET_FLAG_FROM_TEST(options, !use_hashed_alpha, VAR_MAT_CLIP);
- SET_FLAG_FROM_TEST(options, is_shadow, VAR_MAT_SHADOW);
-
- GPUMaterial *mat = DRW_shader_find_from_material(ma, engine, options, true);
- if (mat) {
- return mat;
- }
-
- char *defines = eevee_get_defines(options);
-
- char *frag_str = BLI_string_joinN(e_data.frag_shader_lib, datatoc_prepass_frag_glsl);
-
- mat = DRW_shader_create_from_material(scene,
- ma,
- engine,
- options,
- false,
- (is_shadow) ? e_data.vert_shadow_shader_str :
- e_data.vert_shader_str,
- NULL,
- frag_str,
- defines,
- false);
-
- MEM_freeN(frag_str);
- MEM_freeN(defines);
-
- return mat;
-}
-
-struct GPUMaterial *EEVEE_material_hair_get(struct Scene *scene, Material *ma)
-{
- const void *engine = &DRW_engine_viewport_eevee_type;
- int options = VAR_MAT_MESH | VAR_MAT_HAIR;
-
- GPUMaterial *mat = DRW_shader_find_from_material(ma, engine, options, true);
- if (mat) {
- return mat;
- }
-
- char *defines = eevee_get_defines(options);
-
- mat = DRW_shader_create_from_material(scene,
- ma,
- engine,
- options,
- false,
- e_data.vert_shader_str,
- NULL,
- e_data.frag_shader_lib,
- defines,
- true);
-
- MEM_freeN(defines);
-
- return mat;
-}
-
-/**
- * Create a default shading group inside the given pass.
- */
-static struct DRWShadingGroup *EEVEE_default_shading_group_create(EEVEE_ViewLayerData *sldata,
- EEVEE_Data *vedata,
- DRWPass *pass,
- bool is_hair,
- bool use_blend,
- bool use_ssr)
-{
- static int ssr_id;
- ssr_id = (use_ssr) ? 1 : -1;
- int options = VAR_MAT_MESH;
-
- SET_FLAG_FROM_TEST(options, is_hair, VAR_MAT_HAIR);
- SET_FLAG_FROM_TEST(options, use_blend, VAR_MAT_BLEND);
-
- if (e_data.default_lit[options] == NULL) {
- create_default_shader(options);
- }
-
- DRWShadingGroup *shgrp = DRW_shgroup_create(e_data.default_lit[options], pass);
- add_standard_uniforms(shgrp,
- sldata,
- vedata,
- &ssr_id,
- NULL,
- true,
- true,
- false,
- false,
- use_blend,
- DEFAULT_RENDER_PASS_FLAG);
-
- return shgrp;
-}
-
-/**
- * Create a default shading group inside the default pass without standard uniforms.
- */
-static struct DRWShadingGroup *EEVEE_default_shading_group_get(EEVEE_ViewLayerData *sldata,
- EEVEE_Data *vedata,
- Object *ob,
- ParticleSystem *psys,
- ModifierData *md,
- bool is_hair,
- bool holdout,
- bool use_ssr)
-{
- static int ssr_id;
- ssr_id = (use_ssr) ? 1 : -1;
- int options = VAR_MAT_MESH;
-
- EEVEE_PassList *psl = vedata->psl;
-
- BLI_assert(!is_hair || (ob && ((psys && md) || ob->type == OB_HAIR)));
-
- SET_FLAG_FROM_TEST(options, is_hair, VAR_MAT_HAIR);
- SET_FLAG_FROM_TEST(options, holdout, VAR_MAT_HOLDOUT);
-
- if (e_data.default_lit[options] == NULL) {
- create_default_shader(options);
- }
-
- if (psl->default_pass[options] == NULL) {
- DRWState state = DRW_STATE_WRITE_COLOR | DRW_STATE_DEPTH_EQUAL | DRW_STATE_CLIP_PLANES;
- DRW_PASS_CREATE(psl->default_pass[options], state);
-
- /* XXX / WATCH: This creates non persistent binds for the ubos and textures.
- * But it's currently OK because the following shgroups does not add any bind.
- * EDIT: THIS IS NOT THE CASE FOR HAIRS !!! DUMMY!!! */
- if (!is_hair) {
- DRWShadingGroup *shgrp = DRW_shgroup_create(e_data.default_lit[options],
- psl->default_pass[options]);
- add_standard_uniforms(shgrp,
- sldata,
- vedata,
- &ssr_id,
- NULL,
- true,
- true,
- false,
- false,
- false,
- DEFAULT_RENDER_PASS_FLAG);
- }
- }
-
- if (is_hair) {
- DRWShadingGroup *shgrp = DRW_shgroup_hair_create(
- ob, psys, md, vedata->psl->default_pass[options], e_data.default_lit[options]);
- add_standard_uniforms(shgrp,
- sldata,
- vedata,
- &ssr_id,
- NULL,
- true,
- true,
- false,
- false,
- false,
- DEFAULT_RENDER_PASS_FLAG);
- return shgrp;
- }
- else {
- return DRW_shgroup_create(e_data.default_lit[options], vedata->psl->default_pass[options]);
- }
-}
-
-static struct DRWShadingGroup *EEVEE_default_render_pass_shading_group_get(
- EEVEE_ViewLayerData *sldata,
- EEVEE_Data *vedata,
- bool holdout,
- bool use_ssr,
- DRWPass *pass,
- eViewLayerEEVEEPassType render_pass_flag)
-{
- static int ssr_id;
- ssr_id = (use_ssr) ? 1 : -1;
- int options = VAR_MAT_MESH;
-
- SET_FLAG_FROM_TEST(options, holdout, VAR_MAT_HOLDOUT);
-
- if (e_data.default_lit[options] == NULL) {
- create_default_shader(options);
- }
-
- DRWShadingGroup *shgrp = DRW_shgroup_create(e_data.default_lit[options], pass);
- add_standard_uniforms(
- shgrp, sldata, vedata, &ssr_id, NULL, true, true, false, false, false, render_pass_flag);
- return shgrp;
-}
-
-static struct DRWShadingGroup *EEVEE_default_hair_render_pass_shading_group_get(
- EEVEE_ViewLayerData *sldata,
- EEVEE_Data *vedata,
- Object *ob,
- ParticleSystem *psys,
- ModifierData *md,
- bool holdout,
- bool use_ssr,
- DRWPass *pass,
- eViewLayerEEVEEPassType render_pass_flag)
-{
- static int ssr_id;
- ssr_id = (use_ssr) ? 1 : -1;
- int options = VAR_MAT_MESH | VAR_MAT_HAIR;
-
- BLI_assert((ob && psys && md));
-
- SET_FLAG_FROM_TEST(options, holdout, VAR_MAT_HOLDOUT);
-
- if (e_data.default_lit[options] == NULL) {
- create_default_shader(options);
- }
-
- DRWShadingGroup *shgrp = DRW_shgroup_hair_create(
- ob, psys, md, pass, e_data.default_lit[options]);
- add_standard_uniforms(
- shgrp, sldata, vedata, &ssr_id, NULL, true, true, false, false, false, render_pass_flag);
- return shgrp;
-}
-
void EEVEE_materials_cache_init(EEVEE_ViewLayerData *sldata, EEVEE_Data *vedata)
{
EEVEE_PassList *psl = ((EEVEE_Data *)vedata)->psl;
@@ -1178,10 +375,17 @@ void EEVEE_materials_cache_init(EEVEE_ViewLayerData *sldata, EEVEE_Data *vedata)
/* Create Material Ghash */
{
stl->g_data->material_hash = BLI_ghash_ptr_new("Eevee_material ghash");
+
+ if (sldata->material_cache == NULL) {
+ sldata->material_cache = BLI_memblock_create(sizeof(EeveeMaterialCache));
+ }
+ else {
+ BLI_memblock_clear(sldata->material_cache, NULL);
+ }
}
{
- DRW_PASS_CREATE(psl->background_pass, DRW_STATE_WRITE_COLOR | DRW_STATE_DEPTH_EQUAL);
+ DRW_PASS_CREATE(psl->background_ps, DRW_STATE_WRITE_COLOR | DRW_STATE_DEPTH_EQUAL);
struct GPUBatch *geom = DRW_cache_fullscreen_quad_get();
DRWShadingGroup *grp = NULL;
@@ -1189,483 +393,297 @@ void EEVEE_materials_cache_init(EEVEE_ViewLayerData *sldata, EEVEE_Data *vedata)
Scene *scene = draw_ctx->scene;
World *wo = scene->world;
- const float *col = G_draw.block.colorBackground;
-
- EEVEE_lookdev_cache_init(vedata, sldata, &grp, psl->background_pass, wo, NULL);
+ EEVEE_lookdev_cache_init(vedata, sldata, &grp, psl->background_ps, wo, NULL);
if (!grp && wo) {
- col = &wo->horr;
-
- if (wo->use_nodes && wo->nodetree) {
- static float error_col[3] = {1.0f, 0.0f, 1.0f};
- static float compile_col[3] = {0.5f, 0.5f, 0.5f};
- struct GPUMaterial *gpumat = EEVEE_material_world_background_get(scene, wo);
-
- switch (GPU_material_status(gpumat)) {
- case GPU_MAT_SUCCESS:
- grp = DRW_shgroup_material_create(gpumat, psl->background_pass);
- add_background_uniforms(grp, sldata, vedata);
- DRW_shgroup_call(grp, geom, NULL);
- break;
- case GPU_MAT_QUEUED:
- /* TODO Bypass probe compilation. */
- stl->g_data->queued_shaders_count++;
- col = compile_col;
- break;
- case GPU_MAT_FAILED:
- default:
- col = error_col;
- break;
- }
- }
+ struct GPUMaterial *gpumat = EEVEE_material_get(
+ vedata, scene, NULL, wo, VAR_WORLD_BACKGROUND);
+
+ grp = DRW_shgroup_material_create(gpumat, psl->background_ps);
+ DRW_shgroup_uniform_float(grp, "backgroundAlpha", &stl->g_data->background_alpha, 1);
+ /* TODO (fclem): remove those (need to clean the GLSL files). */
+ DRW_shgroup_uniform_block(grp, "common_block", sldata->common_ubo);
+ DRW_shgroup_uniform_block(grp, "grid_block", sldata->grid_ubo);
+ DRW_shgroup_uniform_block(grp, "probe_block", sldata->probe_ubo);
+ DRW_shgroup_uniform_block(grp, "planar_block", sldata->planar_ubo);
+ DRW_shgroup_uniform_block(grp, "light_block", sldata->light_ubo);
+ DRW_shgroup_uniform_block(grp, "shadow_block", sldata->shadow_ubo);
+ DRW_shgroup_uniform_block(grp, "renderpass_block", sldata->renderpass_ubo.combined);
+ DRW_shgroup_call(grp, geom, NULL);
}
/* Fallback if shader fails or if not using nodetree. */
if (grp == NULL) {
- grp = DRW_shgroup_create(e_data.default_background, psl->background_pass);
- DRW_shgroup_uniform_vec3(grp, "color", col, 1);
+ GPUShader *sh = EEVEE_shaders_default_background_sh_get();
+ grp = DRW_shgroup_create(sh, psl->background_ps);
+ DRW_shgroup_uniform_vec3(grp, "color", G_draw.block.colorBackground, 1);
DRW_shgroup_uniform_float(grp, "backgroundAlpha", &stl->g_data->background_alpha, 1);
DRW_shgroup_call(grp, geom, NULL);
}
}
- {
- DRWState state = DRW_STATE_WRITE_DEPTH | DRW_STATE_DEPTH_LESS_EQUAL;
- DRW_PASS_CREATE(psl->depth_pass, state);
- stl->g_data->depth_shgrp = DRW_shgroup_create(e_data.default_prepass_sh, psl->depth_pass);
-
- state = DRW_STATE_WRITE_DEPTH | DRW_STATE_DEPTH_LESS_EQUAL | DRW_STATE_CULL_BACK;
- DRW_PASS_CREATE(psl->depth_pass_cull, state);
- stl->g_data->depth_shgrp_cull = DRW_shgroup_create(e_data.default_prepass_sh,
- psl->depth_pass_cull);
-
- state = DRW_STATE_WRITE_DEPTH | DRW_STATE_DEPTH_LESS_EQUAL | DRW_STATE_CLIP_PLANES;
- DRW_PASS_CREATE(psl->depth_pass_clip, state);
- stl->g_data->depth_shgrp_clip = DRW_shgroup_create(e_data.default_prepass_clip_sh,
- psl->depth_pass_clip);
-
- state = DRW_STATE_WRITE_DEPTH | DRW_STATE_DEPTH_LESS_EQUAL | DRW_STATE_CLIP_PLANES |
- DRW_STATE_CULL_BACK;
- DRW_PASS_CREATE(psl->depth_pass_clip_cull, state);
- stl->g_data->depth_shgrp_clip_cull = DRW_shgroup_create(e_data.default_prepass_clip_sh,
- psl->depth_pass_clip_cull);
- }
+#define EEVEE_PASS_CREATE(pass, state) \
+ do { \
+ DRW_PASS_CREATE(psl->pass##_ps, state); \
+ DRW_PASS_CREATE(psl->pass##_cull_ps, state | DRW_STATE_CULL_BACK); \
+ DRW_pass_link(psl->pass##_ps, psl->pass##_cull_ps); \
+ } while (0)
- {
- DRWState state = DRW_STATE_WRITE_COLOR | DRW_STATE_DEPTH_EQUAL | DRW_STATE_CLIP_PLANES;
- DRW_PASS_CREATE(psl->material_pass, state);
- DRW_PASS_CREATE(psl->material_pass_cull, state | DRW_STATE_CULL_BACK);
- }
+#define EEVEE_CLIP_PASS_CREATE(pass, state) \
+ do { \
+ DRWState st = state | DRW_STATE_CLIP_PLANES; \
+ DRW_PASS_INSTANCE_CREATE(psl->pass##_clip_ps, psl->pass##_ps, st); \
+ DRW_PASS_INSTANCE_CREATE( \
+ psl->pass##_clip_cull_ps, psl->pass##_cull_ps, st | DRW_STATE_CULL_BACK); \
+ DRW_pass_link(psl->pass##_clip_ps, psl->pass##_clip_cull_ps); \
+ } while (0)
{
- DRWState state = DRW_STATE_WRITE_DEPTH | DRW_STATE_DEPTH_LESS_EQUAL;
- DRW_PASS_CREATE(psl->refract_depth_pass, state);
- stl->g_data->refract_depth_shgrp = DRW_shgroup_create(e_data.default_prepass_sh,
- psl->refract_depth_pass);
-
- state = DRW_STATE_WRITE_DEPTH | DRW_STATE_DEPTH_LESS_EQUAL | DRW_STATE_CULL_BACK;
- DRW_PASS_CREATE(psl->refract_depth_pass_cull, state);
- stl->g_data->refract_depth_shgrp_cull = DRW_shgroup_create(e_data.default_prepass_sh,
- psl->refract_depth_pass_cull);
-
- state = DRW_STATE_WRITE_DEPTH | DRW_STATE_DEPTH_LESS_EQUAL | DRW_STATE_CLIP_PLANES;
- DRW_PASS_CREATE(psl->refract_depth_pass_clip, state);
- stl->g_data->refract_depth_shgrp_clip = DRW_shgroup_create(e_data.default_prepass_clip_sh,
- psl->refract_depth_pass_clip);
-
- state = DRW_STATE_WRITE_DEPTH | DRW_STATE_DEPTH_LESS_EQUAL | DRW_STATE_CLIP_PLANES |
- DRW_STATE_CULL_BACK;
- DRW_PASS_CREATE(psl->refract_depth_pass_clip_cull, state);
- stl->g_data->refract_depth_shgrp_clip_cull = DRW_shgroup_create(
- e_data.default_prepass_clip_sh, psl->refract_depth_pass_clip_cull);
- }
+ DRWState state_depth = DRW_STATE_WRITE_DEPTH | DRW_STATE_DEPTH_LESS_EQUAL;
+ DRWState state_shading = DRW_STATE_WRITE_COLOR | DRW_STATE_DEPTH_EQUAL | DRW_STATE_CLIP_PLANES;
+ DRWState state_sss = DRW_STATE_WRITE_STENCIL | DRW_STATE_STENCIL_ALWAYS;
- {
- DRWState state = (DRW_STATE_WRITE_COLOR | DRW_STATE_DEPTH_EQUAL | DRW_STATE_CLIP_PLANES);
- DRW_PASS_CREATE(psl->refract_pass, state);
- }
+ EEVEE_PASS_CREATE(depth, state_depth);
+ EEVEE_CLIP_PASS_CREATE(depth, state_depth);
- {
- DRWState state = (DRW_STATE_WRITE_COLOR | DRW_STATE_DEPTH_EQUAL | DRW_STATE_CLIP_PLANES |
- DRW_STATE_WRITE_STENCIL | DRW_STATE_STENCIL_ALWAYS);
- DRW_PASS_CREATE(psl->sss_pass, state);
- DRW_PASS_CREATE(psl->sss_pass_cull, state | DRW_STATE_CULL_BACK);
- e_data.sss_count = 0;
+ EEVEE_PASS_CREATE(depth_refract, state_depth);
+ EEVEE_CLIP_PASS_CREATE(depth_refract, state_depth);
+
+ EEVEE_PASS_CREATE(material, state_shading);
+ EEVEE_PASS_CREATE(material_refract, state_shading);
+ EEVEE_PASS_CREATE(material_sss, state_shading | state_sss);
}
+ {
+ /* Renderpass accumulation. */
+ DRWState state = DRW_STATE_WRITE_COLOR | DRW_STATE_DEPTH_EQUAL | DRW_STATE_BLEND_ADD_FULL;
+ /* Create an instance of each of theses passes and link them together. */
+ DRWPass *passes[] = {
+ psl->material_ps,
+ psl->material_cull_ps,
+ psl->material_sss_ps,
+ psl->material_sss_cull_ps,
+ };
+ DRWPass *first = NULL, *last = NULL;
+ for (int i = 0; i < ARRAY_SIZE(passes); i++) {
+ DRWPass *pass = DRW_pass_create_instance("Renderpass Accumulation", passes[i], state);
+ if (first == NULL) {
+ first = last = pass;
+ }
+ else {
+ DRW_pass_link(last, pass);
+ last = pass;
+ }
+ }
+ psl->material_accum_ps = first;
+ /* Same for background */
+ DRW_PASS_INSTANCE_CREATE(psl->background_accum_ps, psl->background_ps, state);
+ }
{
DRWState state = DRW_STATE_WRITE_COLOR | DRW_STATE_DEPTH_LESS_EQUAL | DRW_STATE_CLIP_PLANES;
DRW_PASS_CREATE(psl->transparent_pass, state);
}
-
{
DRW_PASS_CREATE(psl->update_noise_pass, DRW_STATE_WRITE_COLOR);
- DRWShadingGroup *grp = DRW_shgroup_create(e_data.update_noise_sh, psl->update_noise_pass);
+ GPUShader *sh = EEVEE_shaders_update_noise_sh_get();
+ DRWShadingGroup *grp = DRW_shgroup_create(sh, psl->update_noise_pass);
DRW_shgroup_uniform_texture(grp, "blueNoise", e_data.noise_tex);
DRW_shgroup_uniform_vec3(grp, "offsets", e_data.noise_offsets, 1);
DRW_shgroup_call(grp, DRW_cache_fullscreen_quad_get(), NULL);
}
+}
- if (eevee_hdri_preview_overlay_enabled(draw_ctx->v3d)) {
- DRWShadingGroup *shgrp;
-
- struct GPUBatch *sphere = DRW_cache_sphere_get();
- static float color_chrome[3] = {1.0f, 1.0f, 1.0f};
- static float color_diffuse[3] = {0.8f, 0.8f, 0.8f};
- int options = VAR_MAT_MESH | VAR_MAT_LOOKDEV;
+BLI_INLINE void material_shadow(EEVEE_Data *vedata,
+ EEVEE_ViewLayerData *sldata,
+ Material *ma,
+ bool is_hair,
+ EeveeMaterialCache *emc)
+{
+ EEVEE_PrivateData *pd = vedata->stl->g_data;
+ EEVEE_PassList *psl = vedata->psl;
+ const DRWContextState *draw_ctx = DRW_context_state_get();
+ Scene *scene = draw_ctx->scene;
- if (e_data.default_lit[options] == NULL) {
- create_default_shader(options);
+ if (ma->blend_shadow != MA_BS_NONE) {
+ /* Shadow Pass */
+ const bool use_shadow_shader = ma->use_nodes && ma->nodetree &&
+ ELEM(ma->blend_shadow, MA_BS_CLIP, MA_BS_HASHED);
+ int mat_options = VAR_MAT_MESH | VAR_MAT_DEPTH;
+ SET_FLAG_FROM_TEST(mat_options, use_shadow_shader, VAR_MAT_HASH);
+ SET_FLAG_FROM_TEST(mat_options, is_hair, VAR_MAT_HAIR);
+ GPUMaterial *gpumat = (use_shadow_shader) ?
+ EEVEE_material_get(vedata, scene, ma, NULL, mat_options) :
+ EEVEE_material_default_get(scene, ma, mat_options);
+
+ /* Avoid possible confusion with depth pre-pass options. */
+ int option = KEY_SHADOW;
+ SET_FLAG_FROM_TEST(option, is_hair, KEY_HAIR);
+
+ /* Search for the same shaders usage in the pass. */
+ struct GPUShader *sh = GPU_material_get_shader(gpumat);
+ void *cache_key = (char *)sh + option;
+ DRWShadingGroup *grp, **grp_p;
+
+ if (BLI_ghash_ensure_p(pd->material_hash, cache_key, (void ***)&grp_p)) {
+ /* This GPUShader has already been used by another material.
+ * Add new shading group just after to avoid shader switching cost. */
+ grp = DRW_shgroup_create_sub(*grp_p);
+ }
+ else {
+ *grp_p = grp = DRW_shgroup_create(sh, psl->shadow_pass);
+ EEVEE_material_bind_resources(grp, gpumat, sldata, vedata, NULL, NULL, false, false);
}
- DRWState state = DRW_STATE_WRITE_COLOR | DRW_STATE_WRITE_DEPTH | DRW_STATE_DEPTH_ALWAYS |
- DRW_STATE_CULL_BACK;
-
- DRW_PASS_CREATE(psl->lookdev_diffuse_pass, state);
- shgrp = DRW_shgroup_create(e_data.default_lit[options], psl->lookdev_diffuse_pass);
- add_standard_uniforms(shgrp,
- sldata,
- vedata,
- NULL,
- NULL,
- true,
- true,
- false,
- false,
- false,
- DEFAULT_RENDER_PASS_FLAG);
- DRW_shgroup_uniform_vec3(shgrp, "basecol", color_diffuse, 1);
- DRW_shgroup_uniform_float_copy(shgrp, "metallic", 0.0f);
- DRW_shgroup_uniform_float_copy(shgrp, "specular", 0.5f);
- DRW_shgroup_uniform_float_copy(shgrp, "roughness", 1.0f);
- DRW_shgroup_call(shgrp, sphere, NULL);
-
- DRW_PASS_CREATE(psl->lookdev_glossy_pass, state);
- shgrp = DRW_shgroup_create(e_data.default_lit[options], psl->lookdev_glossy_pass);
- add_standard_uniforms(shgrp,
- sldata,
- vedata,
- NULL,
- NULL,
- true,
- true,
- false,
- false,
- false,
- DEFAULT_RENDER_PASS_FLAG);
- DRW_shgroup_uniform_vec3(shgrp, "basecol", color_chrome, 1);
- DRW_shgroup_uniform_float_copy(shgrp, "metallic", 1.0f);
- DRW_shgroup_uniform_float_copy(shgrp, "roughness", 0.0f);
- DRW_shgroup_call(shgrp, sphere, NULL);
- }
+ DRW_shgroup_add_material_resources(grp, gpumat);
- {
- memset(psl->material_accum_pass, 0, sizeof(psl->material_accum_pass));
- for (int pass_index = 0; pass_index < stl->g_data->render_passes_material_count;
- pass_index++) {
- DRWState state = DRW_STATE_WRITE_COLOR | DRW_STATE_DEPTH_EQUAL | DRW_STATE_BLEND_ADD_FULL;
- DRW_PASS_CREATE(psl->material_accum_pass[pass_index], state);
- }
+ emc->shadow_grp = grp;
+ emc->shadow_grp_p = grp_p;
+ }
+ else {
+ emc->shadow_grp = NULL;
+ emc->shadow_grp_p = NULL;
}
}
-#define ADD_SHGROUP_CALL(shgrp, ob, geom, oedata) \
- do { \
- if (oedata) { \
- DRW_shgroup_call_with_callback(shgrp, geom, ob, oedata); \
- } \
- else { \
- DRW_shgroup_call(shgrp, geom, ob); \
- } \
- } while (0)
-
-#define ADD_SHGROUP_CALL_SAFE(shgrp, ob, geom, oedata) \
- do { \
- if (shgrp) { \
- ADD_SHGROUP_CALL(shgrp, ob, geom, oedata); \
- } \
- } while (0)
-
-typedef struct EeveeMaterialShadingGroups {
- struct DRWShadingGroup *shading_grp;
- struct DRWShadingGroup *depth_grp;
- struct DRWShadingGroup *depth_clip_grp;
- struct DRWShadingGroup *material_accum_grp[MAX_MATERIAL_RENDER_PASSES];
-} EeveeMaterialShadingGroups;
-
-static void material_opaque(Material *ma,
- GHash *material_hash,
- EEVEE_ViewLayerData *sldata,
- EEVEE_Data *vedata,
- struct GPUMaterial **gpumat,
- struct GPUMaterial **gpumat_depth,
- struct EeveeMaterialShadingGroups *shgrps,
- bool holdout)
+static EeveeMaterialCache material_opaque(EEVEE_Data *vedata,
+ EEVEE_ViewLayerData *sldata,
+ Material *ma,
+ const bool is_hair)
{
EEVEE_EffectsInfo *effects = vedata->stl->effects;
+ EEVEE_PrivateData *pd = vedata->stl->g_data;
+ EEVEE_PassList *psl = vedata->psl;
const DRWContextState *draw_ctx = DRW_context_state_get();
Scene *scene = draw_ctx->scene;
- EEVEE_StorageList *stl = ((EEVEE_Data *)vedata)->stl;
- EEVEE_PassList *psl = ((EEVEE_Data *)vedata)->psl;
- bool use_diffuse, use_glossy, use_refract;
- bool store_material = true;
- float *color_p = &ma->r;
- float *metal_p = &ma->metallic;
- float *spec_p = &ma->spec;
- float *rough_p = &ma->roughness;
- const bool do_cull = (ma->blend_flag & MA_BL_CULL_BACKFACE) != 0;
- const bool use_gpumat = (ma->use_nodes && ma->nodetree && !holdout);
+ const bool do_cull = !is_hair && (ma->blend_flag & MA_BL_CULL_BACKFACE) != 0;
+ const bool use_gpumat = (ma->use_nodes && ma->nodetree);
const bool use_ssrefract = use_gpumat && ((ma->blend_flag & MA_BL_SS_REFRACTION) != 0) &&
((effects->enabled_effects & EFFECT_REFRACT) != 0);
- const bool use_translucency = ((ma->blend_flag & MA_BL_TRANSLUCENCY) != 0);
-
- EeveeMaterialShadingGroups *emsg = BLI_ghash_lookup(material_hash, (const void *)ma);
-
- if (emsg) {
- memcpy(shgrps, emsg, sizeof(EeveeMaterialShadingGroups));
+ const bool use_depth_shader = use_gpumat && ELEM(ma->blend_method, MA_BM_CLIP, MA_BM_HASHED);
- /* This will have been created already, just perform a lookup. */
- *gpumat = (use_gpumat) ? EEVEE_material_mesh_get(scene, ma, vedata, false, use_ssrefract) :
- NULL;
- *gpumat_depth = (use_gpumat) ? EEVEE_material_mesh_depth_get(
- scene, ma, (ma->blend_method == MA_BM_HASHED), false) :
- NULL;
- return;
+ /* HACK: Assume the struct will never be smaller than our variations.
+ * This allow us to only keep one ghash and avoid bigger keys comparisons/hashing. */
+ void *key = (char *)ma + is_hair;
+ /* Search for other material instances (sharing the same Material data-block). */
+ EeveeMaterialCache **emc_p, *emc;
+ if (BLI_ghash_ensure_p(pd->material_hash, key, (void ***)&emc_p)) {
+ return **emc_p;
+ }
+ else {
+ *emc_p = emc = BLI_memblock_alloc(sldata->material_cache);
}
- emsg = MEM_callocN(sizeof(EeveeMaterialShadingGroups), "EeveeMaterialShadingGroups");
- if (use_gpumat) {
- static float error_col[3] = {1.0f, 0.0f, 1.0f};
- static float compile_col[3] = {0.5f, 0.5f, 0.5f};
- static float half = 0.5f;
-
- /* Shading */
- *gpumat = EEVEE_material_mesh_get(scene, ma, vedata, false, use_ssrefract);
-
- eGPUMaterialStatus status_mat_surface = GPU_material_status(*gpumat);
-
- /* Alpha CLipped : Discard pixel from depth pass, then
- * fail the depth test for shading. */
- if (ELEM(ma->blend_method, MA_BM_CLIP, MA_BM_HASHED)) {
- *gpumat_depth = EEVEE_material_mesh_depth_get(
- scene, ma, (ma->blend_method == MA_BM_HASHED), false);
+ material_shadow(vedata, sldata, ma, is_hair, emc);
- eGPUMaterialStatus status_mat_depth = GPU_material_status(*gpumat_depth);
- if (status_mat_depth != GPU_MAT_SUCCESS) {
- /* Mixing both flags. If depth shader fails, show it to the user by not using
- * the surface shader. */
- status_mat_surface = status_mat_depth;
- }
- else if (use_ssrefract) {
- emsg->depth_grp = DRW_shgroup_material_create(
- *gpumat_depth, (do_cull) ? psl->refract_depth_pass_cull : psl->refract_depth_pass);
- emsg->depth_clip_grp = DRW_shgroup_material_create(
- *gpumat_depth,
- (do_cull) ? psl->refract_depth_pass_clip_cull : psl->refract_depth_pass_clip);
- }
- else {
- emsg->depth_grp = DRW_shgroup_material_create(
- *gpumat_depth, (do_cull) ? psl->depth_pass_cull : psl->depth_pass);
- emsg->depth_clip_grp = DRW_shgroup_material_create(
- *gpumat_depth, (do_cull) ? psl->depth_pass_clip_cull : psl->depth_pass_clip);
- }
-
- if (emsg->depth_grp != NULL) {
- use_diffuse = GPU_material_flag_get(*gpumat_depth, GPU_MATFLAG_DIFFUSE);
- use_glossy = GPU_material_flag_get(*gpumat_depth, GPU_MATFLAG_GLOSSY);
- use_refract = GPU_material_flag_get(*gpumat_depth, GPU_MATFLAG_REFRACT);
-
- add_standard_uniforms(emsg->depth_grp,
- sldata,
- vedata,
- NULL,
- NULL,
- use_diffuse,
- use_glossy,
- use_refract,
- false,
- false,
- DEFAULT_RENDER_PASS_FLAG);
- add_standard_uniforms(emsg->depth_clip_grp,
- sldata,
- vedata,
- NULL,
- NULL,
- use_diffuse,
- use_glossy,
- use_refract,
- false,
- false,
- DEFAULT_RENDER_PASS_FLAG);
-
- if (ma->blend_method == MA_BM_CLIP) {
- DRW_shgroup_uniform_float(emsg->depth_grp, "alphaThreshold", &ma->alpha_threshold, 1);
- DRW_shgroup_uniform_float(
- emsg->depth_clip_grp, "alphaThreshold", &ma->alpha_threshold, 1);
- }
- }
+ {
+ /* Depth Pass */
+ int mat_options = VAR_MAT_MESH | VAR_MAT_DEPTH;
+ SET_FLAG_FROM_TEST(mat_options, use_ssrefract, VAR_MAT_REFRACT);
+ SET_FLAG_FROM_TEST(mat_options, use_depth_shader, VAR_MAT_HASH);
+ SET_FLAG_FROM_TEST(mat_options, is_hair, VAR_MAT_HAIR);
+ GPUMaterial *gpumat = (use_depth_shader) ?
+ EEVEE_material_get(vedata, scene, ma, NULL, mat_options) :
+ EEVEE_material_default_get(scene, ma, mat_options);
+
+ int option = 0;
+ SET_FLAG_FROM_TEST(option, do_cull, KEY_CULL);
+ SET_FLAG_FROM_TEST(option, use_ssrefract, KEY_REFRACT);
+ DRWPass *depth_ps = (DRWPass *[]){
+ psl->depth_ps,
+ psl->depth_cull_ps,
+ psl->depth_refract_ps,
+ psl->depth_refract_cull_ps,
+ }[option];
+ /* Hair are rendered inside the non-cull pass but needs to have a separate cache key. */
+ SET_FLAG_FROM_TEST(option, is_hair, KEY_HAIR);
+
+ /* Search for the same shaders usage in the pass. */
+ struct GPUShader *sh = GPU_material_get_shader(gpumat);
+ void *cache_key = (char *)sh + option;
+ DRWShadingGroup *grp, **grp_p;
+
+ if (BLI_ghash_ensure_p(pd->material_hash, cache_key, (void ***)&grp_p)) {
+ /* This GPUShader has already been used by another material.
+ * Add new shading group just after to avoid shader switching cost. */
+ grp = DRW_shgroup_create_sub(*grp_p);
}
-
- switch (status_mat_surface) {
- case GPU_MAT_SUCCESS: {
- static int no_ssr = 0;
- static int first_ssr = 1;
- int *ssr_id = (((effects->enabled_effects & EFFECT_SSR) != 0) && !use_ssrefract) ?
- &first_ssr :
- &no_ssr;
- const bool use_sss = GPU_material_flag_get(*gpumat, GPU_MATFLAG_SSS);
- use_diffuse = GPU_material_flag_get(*gpumat, GPU_MATFLAG_DIFFUSE);
- use_glossy = GPU_material_flag_get(*gpumat, GPU_MATFLAG_GLOSSY);
- use_refract = GPU_material_flag_get(*gpumat, GPU_MATFLAG_REFRACT);
-
- emsg->shading_grp = DRW_shgroup_material_create(
- *gpumat,
- (use_ssrefract) ?
- psl->refract_pass :
- (use_sss) ? ((do_cull) ? psl->sss_pass_cull : psl->sss_pass) :
- ((do_cull) ? psl->material_pass_cull : psl->material_pass));
-
- add_standard_uniforms(emsg->shading_grp,
- sldata,
- vedata,
- ssr_id,
- &ma->refract_depth,
- use_diffuse,
- use_glossy,
- use_refract,
- use_ssrefract,
- false,
- DEFAULT_RENDER_PASS_FLAG);
-
- if (use_sss) {
- struct GPUTexture *sss_tex_profile = NULL;
- struct GPUUniformBuffer *sss_profile = GPU_material_sss_profile_get(
- *gpumat, stl->effects->sss_sample_count, &sss_tex_profile);
-
- if (sss_profile) {
- /* Limit of 8 bit stencil buffer. ID 255 is refraction. */
- if (e_data.sss_count < 254) {
- int sss_id = e_data.sss_count + 1;
- DRW_shgroup_stencil_mask(emsg->shading_grp, sss_id);
- EEVEE_subsurface_add_pass(sldata, vedata, sss_id, sss_profile);
- if (use_translucency) {
- EEVEE_subsurface_translucency_add_pass(
- sldata, vedata, sss_id, sss_profile, sss_tex_profile);
- }
- e_data.sss_count++;
- }
- else {
- /* TODO : display message. */
- printf("Error: Too many different Subsurface shader in the scene.\n");
- }
- }
- }
-
- RENDER_PASS_ITER_BEGIN(stl->g_data->render_passes, render_pass_index, render_pass_flag)
- emsg->material_accum_grp[render_pass_index] = DRW_shgroup_material_create(
- *gpumat, psl->material_accum_pass[render_pass_index]);
- add_standard_uniforms(emsg->material_accum_grp[render_pass_index],
- sldata,
- vedata,
- ssr_id,
- &ma->refract_depth,
- use_diffuse,
- use_glossy,
- use_refract,
- use_ssrefract,
- false,
- render_pass_flag);
- RENDER_PASS_ITER_END(render_pass_index)
-
- break;
- }
- case GPU_MAT_QUEUED: {
- stl->g_data->queued_shaders_count++;
- color_p = compile_col;
- metal_p = spec_p = rough_p = &half;
- store_material = false;
- break;
- }
- case GPU_MAT_FAILED:
- default:
- color_p = error_col;
- metal_p = spec_p = rough_p = &half;
- break;
+ else {
+ *grp_p = grp = DRW_shgroup_create(sh, depth_ps);
+ EEVEE_material_bind_resources(grp, gpumat, sldata, vedata, NULL, NULL, false, false);
}
- }
- /* Fallback to default shader */
- if (emsg->shading_grp == NULL) {
- bool use_ssr = ((effects->enabled_effects & EFFECT_SSR) != 0);
- emsg->shading_grp = EEVEE_default_shading_group_get(
- sldata, vedata, NULL, NULL, NULL, false, holdout, use_ssr);
- DRW_shgroup_uniform_vec3(emsg->shading_grp, "basecol", color_p, 1);
- DRW_shgroup_uniform_float(emsg->shading_grp, "metallic", metal_p, 1);
- DRW_shgroup_uniform_float(emsg->shading_grp, "specular", spec_p, 1);
- DRW_shgroup_uniform_float(emsg->shading_grp, "roughness", rough_p, 1);
-
- RENDER_PASS_ITER_BEGIN(stl->g_data->render_passes, render_pass_index, render_pass_flag)
- DRWShadingGroup *shgrp = EEVEE_default_render_pass_shading_group_get(
- sldata,
- vedata,
- holdout,
- use_ssr,
- psl->material_accum_pass[render_pass_index],
- render_pass_flag);
-
- DRW_shgroup_uniform_vec3(shgrp, "basecol", color_p, 1);
- DRW_shgroup_uniform_float(shgrp, "metallic", metal_p, 1);
- DRW_shgroup_uniform_float(shgrp, "specular", spec_p, 1);
- DRW_shgroup_uniform_float(shgrp, "roughness", rough_p, 1);
- emsg->material_accum_grp[render_pass_index] = shgrp;
- RENDER_PASS_ITER_END(render_pass_index)
- }
+ DRW_shgroup_add_material_resources(grp, gpumat);
- /* Fallback default depth prepass */
- if (emsg->depth_grp == NULL) {
- if (use_ssrefract) {
- emsg->depth_grp = (do_cull) ? stl->g_data->refract_depth_shgrp_cull :
- stl->g_data->refract_depth_shgrp;
- emsg->depth_clip_grp = (do_cull) ? stl->g_data->refract_depth_shgrp_clip_cull :
- stl->g_data->refract_depth_shgrp_clip;
+ emc->depth_grp = grp;
+ emc->depth_grp_p = grp_p;
+ }
+ {
+ /* Shading Pass */
+ int mat_options = VAR_MAT_MESH;
+ SET_FLAG_FROM_TEST(mat_options, use_ssrefract, VAR_MAT_REFRACT);
+ SET_FLAG_FROM_TEST(mat_options, is_hair, VAR_MAT_HAIR);
+ GPUMaterial *gpumat = EEVEE_material_get(vedata, scene, ma, NULL, mat_options);
+ const bool use_sss = GPU_material_flag_get(gpumat, GPU_MATFLAG_SSS);
+
+ int ssr_id = (((effects->enabled_effects & EFFECT_SSR) != 0) && !use_ssrefract) ? 1 : 0;
+ int option = (use_ssrefract ? 0 : (use_sss ? 1 : 2)) * 2 + do_cull;
+ DRWPass *shading_pass = (DRWPass *[]){
+ psl->material_refract_ps,
+ psl->material_refract_cull_ps,
+ psl->material_sss_ps,
+ psl->material_sss_cull_ps,
+ psl->material_ps,
+ psl->material_cull_ps,
+ }[option];
+ /* Hair are rendered inside the non-cull pass but needs to have a separate cache key */
+ option = option * 2 + is_hair;
+
+ /* Search for the same shaders usage in the pass. */
+ /* HACK: Assume the struct will never be smaller than our variations.
+ * This allow us to only keep one ghash and avoid bigger keys comparisons/hashing. */
+ BLI_assert(option <= 16);
+ struct GPUShader *sh = GPU_material_get_shader(gpumat);
+ void *cache_key = (char *)sh + option;
+ DRWShadingGroup *grp, **grp_p;
+
+ if (BLI_ghash_ensure_p(pd->material_hash, cache_key, (void ***)&grp_p)) {
+ /* This GPUShader has already been used by another material.
+ * Add new shading group just after to avoid shader switching cost. */
+ grp = DRW_shgroup_create_sub(*grp_p);
}
else {
- emsg->depth_grp = (do_cull) ? stl->g_data->depth_shgrp_cull : stl->g_data->depth_shgrp;
- emsg->depth_clip_grp = (do_cull) ? stl->g_data->depth_shgrp_clip_cull :
- stl->g_data->depth_shgrp_clip;
+ *grp_p = grp = DRW_shgroup_create(sh, shading_pass);
+ EEVEE_material_bind_resources(
+ grp, gpumat, sldata, vedata, &ssr_id, &ma->refract_depth, use_ssrefract, false);
}
- }
+ DRW_shgroup_add_material_resources(grp, gpumat);
- memcpy(shgrps, emsg, sizeof(EeveeMaterialShadingGroups));
- if (store_material) {
- BLI_ghash_insert(material_hash, ma, emsg);
- }
- else {
- MEM_freeN(emsg);
+ if (use_sss) {
+ EEVEE_subsurface_add_pass(sldata, vedata, ma, grp, gpumat);
+ }
+
+ emc->shading_grp = grp;
+ emc->shading_grp_p = grp_p;
+ emc->shading_gpumat = gpumat;
}
+ return *emc;
}
-static void material_transparent(Material *ma,
- EEVEE_ViewLayerData *sldata,
- EEVEE_Data *vedata,
- struct GPUMaterial **gpumat,
- struct EeveeMaterialShadingGroups *shgrps)
+static EeveeMaterialCache material_transparent(EEVEE_Data *vedata,
+ EEVEE_ViewLayerData *sldata,
+ Material *ma)
{
const DRWContextState *draw_ctx = DRW_context_state_get();
Scene *scene = draw_ctx->scene;
- EEVEE_StorageList *stl = ((EEVEE_Data *)vedata)->stl;
- EEVEE_PassList *psl = ((EEVEE_Data *)vedata)->psl;
+ EEVEE_PassList *psl = vedata->psl;
+ EEVEE_EffectsInfo *effects = vedata->stl->effects;
+ EeveeMaterialCache emc = {0};
const bool do_cull = (ma->blend_flag & MA_BL_CULL_BACKFACE) != 0;
const bool use_gpumat = ma->use_nodes && ma->nodetree;
const bool use_ssrefract = use_gpumat && ((ma->blend_flag & MA_BL_SS_REFRACTION) != 0) &&
- ((stl->effects->enabled_effects & EFFECT_REFRACT) != 0);
- const float *color_p = &ma->r;
- const float *metal_p = &ma->metallic;
- const float *spec_p = &ma->spec;
- const float *rough_p = &ma->roughness;
-
+ ((effects->enabled_effects & EFFECT_REFRACT) != 0);
const bool use_prepass = ((ma->blend_flag & MA_BL_HIDE_BACKFACE) != 0);
DRWState cur_state;
@@ -1673,98 +691,96 @@ static void material_transparent(Material *ma,
DRW_STATE_DEPTH_LESS_EQUAL | DRW_STATE_DEPTH_EQUAL |
DRW_STATE_BLEND_CUSTOM);
- /* Depth prepass */
+ material_shadow(vedata, sldata, ma, false, &emc);
+
if (use_prepass) {
- shgrps->depth_grp = DRW_shgroup_create(e_data.default_prepass_clip_sh, psl->transparent_pass);
+ /* Depth prepass */
+ int mat_options = VAR_MAT_MESH | VAR_MAT_DEPTH;
+ GPUMaterial *gpumat = EEVEE_material_get(vedata, scene, ma, NULL, mat_options);
+ struct GPUShader *sh = GPU_material_get_shader(gpumat);
+
+ DRWShadingGroup *grp = DRW_shgroup_create(sh, psl->transparent_pass);
+
+ EEVEE_material_bind_resources(grp, gpumat, sldata, vedata, NULL, NULL, false, true);
+ DRW_shgroup_add_material_resources(grp, gpumat);
cur_state = DRW_STATE_WRITE_DEPTH | DRW_STATE_DEPTH_LESS_EQUAL;
cur_state |= (do_cull) ? DRW_STATE_CULL_BACK : 0;
- DRW_shgroup_state_disable(shgrps->depth_grp, all_state);
- DRW_shgroup_state_enable(shgrps->depth_grp, cur_state);
+ DRW_shgroup_state_disable(grp, all_state);
+ DRW_shgroup_state_enable(grp, cur_state);
+
+ emc.depth_grp = grp;
}
+ {
+ /* Shading */
+ int ssr_id = -1; /* TODO transparent SSR */
+ int mat_options = VAR_MAT_MESH | VAR_MAT_BLEND;
+ SET_FLAG_FROM_TEST(mat_options, use_ssrefract, VAR_MAT_REFRACT);
+ GPUMaterial *gpumat = EEVEE_material_get(vedata, scene, ma, NULL, mat_options);
- if (use_gpumat) {
- static float error_col[3] = {1.0f, 0.0f, 1.0f};
- static float compile_col[3] = {0.5f, 0.5f, 0.5f};
- static float half = 0.5f;
+ DRWShadingGroup *grp = DRW_shgroup_create(GPU_material_get_shader(gpumat),
+ psl->transparent_pass);
- /* Shading */
- *gpumat = EEVEE_material_mesh_get(scene, ma, vedata, true, use_ssrefract);
-
- switch (GPU_material_status(*gpumat)) {
- case GPU_MAT_SUCCESS: {
- static int ssr_id = -1; /* TODO transparent SSR */
-
- shgrps->shading_grp = DRW_shgroup_material_create(*gpumat, psl->transparent_pass);
-
- bool use_blend = true;
- bool use_diffuse = GPU_material_flag_get(*gpumat, GPU_MATFLAG_DIFFUSE);
- bool use_glossy = GPU_material_flag_get(*gpumat, GPU_MATFLAG_GLOSSY);
- bool use_refract = GPU_material_flag_get(*gpumat, GPU_MATFLAG_REFRACT);
-
- add_standard_uniforms(shgrps->shading_grp,
- sldata,
- vedata,
- &ssr_id,
- &ma->refract_depth,
- use_diffuse,
- use_glossy,
- use_refract,
- use_ssrefract,
- use_blend,
- DEFAULT_RENDER_PASS_FLAG);
- break;
- }
- case GPU_MAT_QUEUED: {
- /* TODO Bypass probe compilation. */
- stl->g_data->queued_shaders_count++;
- color_p = compile_col;
- metal_p = spec_p = rough_p = &half;
- break;
- }
- case GPU_MAT_FAILED:
- default:
- color_p = error_col;
- metal_p = spec_p = rough_p = &half;
- break;
- }
- }
+ EEVEE_material_bind_resources(
+ grp, gpumat, sldata, vedata, &ssr_id, &ma->refract_depth, use_ssrefract, true);
+ DRW_shgroup_add_material_resources(grp, gpumat);
- /* Fallback to default shader */
- if (shgrps->shading_grp == NULL) {
- shgrps->shading_grp = EEVEE_default_shading_group_create(
- sldata, vedata, psl->transparent_pass, false, true, false);
- DRW_shgroup_uniform_vec3(shgrps->shading_grp, "basecol", color_p, 1);
- DRW_shgroup_uniform_float(shgrps->shading_grp, "metallic", metal_p, 1);
- DRW_shgroup_uniform_float(shgrps->shading_grp, "specular", spec_p, 1);
- DRW_shgroup_uniform_float(shgrps->shading_grp, "roughness", rough_p, 1);
- }
+ cur_state = DRW_STATE_WRITE_COLOR | DRW_STATE_BLEND_CUSTOM;
+ cur_state |= (use_prepass) ? DRW_STATE_DEPTH_EQUAL : DRW_STATE_DEPTH_LESS_EQUAL;
+ cur_state |= (do_cull) ? DRW_STATE_CULL_BACK : 0;
- cur_state = DRW_STATE_WRITE_COLOR | DRW_STATE_BLEND_CUSTOM;
- cur_state |= (use_prepass) ? DRW_STATE_DEPTH_EQUAL : DRW_STATE_DEPTH_LESS_EQUAL;
- cur_state |= (do_cull) ? DRW_STATE_CULL_BACK : 0;
+ /* Disable other blend modes and use the one we want. */
+ DRW_shgroup_state_disable(grp, all_state);
+ DRW_shgroup_state_enable(grp, cur_state);
- /* Disable other blend modes and use the one we want. */
- DRW_shgroup_state_disable(shgrps->shading_grp, all_state);
- DRW_shgroup_state_enable(shgrps->shading_grp, cur_state);
+ emc.shading_grp = grp;
+ emc.shading_gpumat = gpumat;
+ }
+ return emc;
}
/* Return correct material or empty default material if slot is empty. */
-BLI_INLINE Material *eevee_object_material_get(Object *ob, int slot)
+BLI_INLINE Material *eevee_object_material_get(Object *ob, int slot, bool holdout)
{
+ if (holdout) {
+ return BKE_material_default_holdout();
+ }
Material *ma = BKE_object_material_get(ob, slot + 1);
if (ma == NULL) {
if (ob->type == OB_VOLUME) {
ma = BKE_material_default_volume();
}
else {
- ma = BKE_material_default_empty();
+ ma = BKE_material_default_surface();
}
}
return ma;
}
+BLI_INLINE EeveeMaterialCache eevee_material_cache_get(
+ EEVEE_Data *vedata, EEVEE_ViewLayerData *sldata, Object *ob, int slot, bool is_hair)
+{
+ const bool holdout = (ob->base_flag & BASE_HOLDOUT) != 0;
+ EeveeMaterialCache matcache;
+ Material *ma = eevee_object_material_get(ob, slot, holdout);
+ switch (ma->blend_method) {
+ case MA_BM_BLEND:
+ if (!is_hair) {
+ matcache = material_transparent(vedata, sldata, ma);
+ break;
+ }
+ ATTR_FALLTHROUGH;
+ case MA_BM_SOLID:
+ case MA_BM_CLIP:
+ case MA_BM_HASHED:
+ default:
+ matcache = material_opaque(vedata, sldata, ma, is_hair);
+ break;
+ }
+ return matcache;
+}
+
static void eevee_hair_cache_populate(EEVEE_Data *vedata,
EEVEE_ViewLayerData *sldata,
Object *ob,
@@ -1773,238 +789,49 @@ static void eevee_hair_cache_populate(EEVEE_Data *vedata,
int matnr,
bool *cast_shadow)
{
- EEVEE_PassList *psl = vedata->psl;
- EEVEE_StorageList *stl = vedata->stl;
- const DRWContextState *draw_ctx = DRW_context_state_get();
- Scene *scene = draw_ctx->scene;
-
- DRWShadingGroup *shgrp = NULL;
- Material *ma = eevee_object_material_get(ob, matnr - 1);
- const bool holdout = (ob->base_flag & BASE_HOLDOUT) != 0;
- const bool use_gpumat = ma->use_nodes && ma->nodetree && !holdout;
- const bool use_alpha_hash = (ma->blend_method == MA_BM_HASHED);
- const bool use_alpha_clip = (ma->blend_method == MA_BM_CLIP);
- const bool use_ssr = ((stl->effects->enabled_effects & EFFECT_SSR) != 0);
+ EeveeMaterialCache matcache = eevee_material_cache_get(vedata, sldata, ob, matnr - 1, true);
- GPUMaterial *gpumat = use_gpumat ? EEVEE_material_hair_get(scene, ma) : NULL;
- eGPUMaterialStatus status_mat_surface = gpumat ? GPU_material_status(gpumat) : GPU_MAT_SUCCESS;
-
- float *color_p = &ma->r;
- float *metal_p = &ma->metallic;
- float *spec_p = &ma->spec;
- float *rough_p = &ma->roughness;
-
- /* Depth prepass. */
- if (use_gpumat && (use_alpha_clip || use_alpha_hash)) {
- GPUMaterial *gpumat_depth = EEVEE_material_hair_depth_get(scene, ma, use_alpha_hash, false);
-
- eGPUMaterialStatus status_mat_depth = GPU_material_status(gpumat_depth);
-
- if (status_mat_depth != GPU_MAT_SUCCESS) {
- /* Mixing both flags. If depth shader fails, show it to the user by not using
- * the surface shader. */
- status_mat_surface = status_mat_depth;
- }
- else {
- const bool use_diffuse = GPU_material_flag_get(gpumat_depth, GPU_MATFLAG_DIFFUSE);
- const bool use_glossy = GPU_material_flag_get(gpumat_depth, GPU_MATFLAG_GLOSSY);
- const bool use_refract = GPU_material_flag_get(gpumat_depth, GPU_MATFLAG_REFRACT);
-
- for (int i = 0; i < 2; i++) {
- DRWPass *pass = (i == 0) ? psl->depth_pass : psl->depth_pass_clip;
-
- shgrp = DRW_shgroup_material_hair_create(ob, psys, md, pass, gpumat_depth);
-
- add_standard_uniforms(shgrp,
- sldata,
- vedata,
- NULL,
- NULL,
- use_diffuse,
- use_glossy,
- use_refract,
- false,
- false,
- DEFAULT_RENDER_PASS_FLAG);
-
- /* Unfortunately needed for correctness but not 99% of the time not needed.
- * TODO detect when needed? */
- DRW_shgroup_uniform_block(shgrp, "probe_block", sldata->probe_ubo);
- DRW_shgroup_uniform_block(shgrp, "grid_block", sldata->grid_ubo);
- DRW_shgroup_uniform_block(shgrp, "planar_block", sldata->planar_ubo);
- DRW_shgroup_uniform_block(shgrp, "light_block", sldata->light_ubo);
- DRW_shgroup_uniform_block(shgrp, "shadow_block", sldata->shadow_ubo);
- DRW_shgroup_uniform_block(
- shgrp, "renderpass_block", EEVEE_material_default_render_pass_ubo_get(sldata));
- DRW_shgroup_uniform_block(shgrp, "common_block", sldata->common_ubo);
- DRW_shgroup_uniform_texture(shgrp, "utilTex", e_data.util_tex);
-
- if (use_alpha_clip) {
- DRW_shgroup_uniform_float(shgrp, "alphaThreshold", &ma->alpha_threshold, 1);
- }
- }
- }
+ if (matcache.depth_grp) {
+ *matcache.depth_grp_p = DRW_shgroup_hair_create_sub(ob, psys, md, matcache.depth_grp);
}
-
- /* Fallback to default shader */
- if (shgrp == NULL) {
- for (int i = 0; i < 2; i++) {
- DRWPass *depth_pass = (i == 0) ? psl->depth_pass : psl->depth_pass_clip;
- struct GPUShader *depth_sh = (i == 0) ? e_data.default_hair_prepass_sh :
- e_data.default_hair_prepass_clip_sh;
- DRW_shgroup_hair_create(ob, psys, md, depth_pass, depth_sh);
- }
+ if (matcache.shading_grp) {
+ *matcache.shading_grp_p = DRW_shgroup_hair_create_sub(ob, psys, md, matcache.shading_grp);
}
-
- shgrp = NULL;
-
- if (gpumat) {
- static int ssr_id;
- ssr_id = (use_ssr) ? 1 : -1;
- static float half = 0.5f;
- static float error_col[3] = {1.0f, 0.0f, 1.0f};
- static float compile_col[3] = {0.5f, 0.5f, 0.5f};
-
- switch (status_mat_surface) {
- case GPU_MAT_SUCCESS: {
- bool use_diffuse = GPU_material_flag_get(gpumat, GPU_MATFLAG_DIFFUSE);
- bool use_glossy = GPU_material_flag_get(gpumat, GPU_MATFLAG_GLOSSY);
- bool use_refract = GPU_material_flag_get(gpumat, GPU_MATFLAG_REFRACT);
-
- shgrp = DRW_shgroup_material_hair_create(ob, psys, md, psl->material_pass, gpumat);
-
- if (!use_diffuse && !use_glossy && !use_refract) {
- /* HACK: Small hack to avoid issue when utilTex is needed for
- * world_normals_get and none of the bsdfs are present.
- * This binds utilTex even if not needed. */
- DRW_shgroup_uniform_texture(shgrp, "utilTex", e_data.util_tex);
- }
-
- add_standard_uniforms(shgrp,
- sldata,
- vedata,
- &ssr_id,
- NULL,
- use_diffuse,
- use_glossy,
- use_refract,
- false,
- false,
- DEFAULT_RENDER_PASS_FLAG);
-
- /* Add the hair to all the render_passes that are enabled */
- RENDER_PASS_ITER_BEGIN(stl->g_data->render_passes, render_pass_index, render_pass_flag)
- shgrp = DRW_shgroup_material_hair_create(
- ob, psys, md, psl->material_accum_pass[render_pass_index], gpumat);
- if (!use_diffuse && !use_glossy && !use_refract) {
- /* Small hack to avoid issue when utilTex is needed for
- * world_normals_get and none of the bsdfs that need it are present.
- * This binds `utilTex` even if not needed. */
- DRW_shgroup_uniform_texture(shgrp, "utilTex", e_data.util_tex);
- }
-
- add_standard_uniforms(shgrp,
- sldata,
- vedata,
- &ssr_id,
- NULL,
- use_diffuse,
- use_glossy,
- use_refract,
- false,
- false,
- render_pass_flag);
- RENDER_PASS_ITER_END(render_pass_index)
-
- break;
- }
- case GPU_MAT_QUEUED: {
- stl->g_data->queued_shaders_count++;
- color_p = compile_col;
- metal_p = spec_p = rough_p = &half;
- break;
- }
- case GPU_MAT_FAILED:
- default:
- color_p = error_col;
- metal_p = spec_p = rough_p = &half;
- break;
- }
+ if (matcache.shadow_grp) {
+ *matcache.shadow_grp_p = DRW_shgroup_hair_create_sub(ob, psys, md, matcache.shadow_grp);
+ *cast_shadow = true;
}
+}
- /* Fallback to default shader */
- if (shgrp == NULL) {
- shgrp = EEVEE_default_shading_group_get(sldata, vedata, ob, psys, md, true, holdout, use_ssr);
- DRW_shgroup_uniform_vec3(shgrp, "basecol", color_p, 1);
- DRW_shgroup_uniform_float(shgrp, "metallic", metal_p, 1);
- DRW_shgroup_uniform_float(shgrp, "specular", spec_p, 1);
- DRW_shgroup_uniform_float(shgrp, "roughness", rough_p, 1);
-
- RENDER_PASS_ITER_BEGIN(stl->g_data->render_passes, render_pass_index, render_pass_flag)
- shgrp = EEVEE_default_hair_render_pass_shading_group_get(
- sldata,
- vedata,
- ob,
- psys,
- md,
- holdout,
- use_ssr,
- psl->material_accum_pass[render_pass_index],
- render_pass_flag);
-
- DRW_shgroup_uniform_vec3(shgrp, "basecol", color_p, 1);
- DRW_shgroup_uniform_float(shgrp, "metallic", metal_p, 1);
- DRW_shgroup_uniform_float(shgrp, "specular", spec_p, 1);
- DRW_shgroup_uniform_float(shgrp, "roughness", rough_p, 1);
- RENDER_PASS_ITER_END(render_pass_index)
- }
+#define ADD_SHGROUP_CALL(shgrp, ob, geom, oedata) \
+ do { \
+ if (oedata) { \
+ DRW_shgroup_call_with_callback(shgrp, geom, ob, oedata); \
+ } \
+ else { \
+ DRW_shgroup_call(shgrp, geom, ob); \
+ } \
+ } while (0)
- /* Shadows */
- char blend_shadow = use_gpumat ? ma->blend_shadow : MA_BS_SOLID;
- const bool shadow_alpha_hash = (blend_shadow == MA_BS_HASHED);
- switch (blend_shadow) {
- case MA_BS_SOLID:
- DRW_shgroup_hair_create(ob, psys, md, psl->shadow_pass, e_data.default_hair_prepass_sh);
- *cast_shadow = true;
- break;
- case MA_BS_CLIP:
- case MA_BS_HASHED:
- gpumat = EEVEE_material_hair_depth_get(scene, ma, shadow_alpha_hash, true);
- shgrp = DRW_shgroup_material_hair_create(ob, psys, md, psl->shadow_pass, gpumat);
- /* Unfortunately needed for correctness but not 99% of the time not needed.
- * TODO detect when needed? */
- DRW_shgroup_uniform_block(shgrp, "probe_block", sldata->probe_ubo);
- DRW_shgroup_uniform_block(shgrp, "grid_block", sldata->grid_ubo);
- DRW_shgroup_uniform_block(shgrp, "planar_block", sldata->planar_ubo);
- DRW_shgroup_uniform_block(shgrp, "light_block", sldata->light_ubo);
- DRW_shgroup_uniform_block(shgrp, "shadow_block", sldata->shadow_ubo);
- DRW_shgroup_uniform_block(
- shgrp, "renderpass_block", EEVEE_material_default_render_pass_ubo_get(sldata));
- DRW_shgroup_uniform_block(shgrp, "common_block", sldata->common_ubo);
- DRW_shgroup_uniform_texture(shgrp, "utilTex", e_data.util_tex);
-
- if (!shadow_alpha_hash) {
- DRW_shgroup_uniform_float(shgrp, "alphaThreshold", &ma->alpha_threshold, 1);
- }
- *cast_shadow = true;
- break;
- case MA_BS_NONE:
- default:
- break;
+#define ADD_SHGROUP_CALL_SAFE(shgrp, ob, geom, oedata) \
+ do { \
+ if (shgrp) { \
+ ADD_SHGROUP_CALL(shgrp, ob, geom, oedata); \
+ } \
+ } while (0)
+
+#define MATCACHE_AS_ARRAY(matcache, member, materials_len, output_array) \
+ for (int i = 0; i < materials_len; i++) { \
+ output_array[i] = matcache[i].member; \
}
-}
void EEVEE_materials_cache_populate(EEVEE_Data *vedata,
EEVEE_ViewLayerData *sldata,
Object *ob,
bool *cast_shadow)
{
- EEVEE_PassList *psl = vedata->psl;
- EEVEE_StorageList *stl = vedata->stl;
const DRWContextState *draw_ctx = DRW_context_state_get();
Scene *scene = draw_ctx->scene;
- GHash *material_hash = stl->g_data->material_hash;
- const bool holdout = (ob->base_flag & BASE_HOLDOUT) != 0;
bool use_sculpt_pbvh = BKE_sculptsession_use_pbvh_draw(ob, draw_ctx->v3d) &&
!DRW_state_is_image_render();
@@ -2013,153 +840,64 @@ void EEVEE_materials_cache_populate(EEVEE_Data *vedata,
if (ELEM(ob->type, OB_MESH, OB_CURVE, OB_SURF, OB_FONT, OB_MBALL)) {
const int materials_len = DRW_cache_object_material_count_get(ob);
- struct EeveeMaterialShadingGroups *shgrps_array = BLI_array_alloca(shgrps_array,
- materials_len);
-
- struct GPUMaterial **gpumat_array = BLI_array_alloca(gpumat_array, materials_len);
- struct GPUMaterial **gpumat_depth_array = BLI_array_alloca(gpumat_array, materials_len);
- struct Material **ma_array = BLI_array_alloca(ma_array, materials_len);
-
+ EeveeMaterialCache *matcache = BLI_array_alloca(matcache, materials_len);
for (int i = 0; i < materials_len; i++) {
- ma_array[i] = eevee_object_material_get(ob, i);
- memset(&shgrps_array[i], 0, sizeof(EeveeMaterialShadingGroups));
- gpumat_array[i] = NULL;
- gpumat_depth_array[i] = NULL;
-
- if (holdout) {
- material_opaque(ma_array[i],
- material_hash,
- sldata,
- vedata,
- &gpumat_array[i],
- &gpumat_depth_array[i],
- &shgrps_array[i],
- true);
- continue;
- }
-
- switch (ma_array[i]->blend_method) {
- case MA_BM_SOLID:
- case MA_BM_CLIP:
- case MA_BM_HASHED:
- material_opaque(ma_array[i],
- material_hash,
- sldata,
- vedata,
- &gpumat_array[i],
- &gpumat_depth_array[i],
- &shgrps_array[i],
- false);
- break;
- case MA_BM_BLEND:
- material_transparent(ma_array[i], sldata, vedata, &gpumat_array[i], &shgrps_array[i]);
- break;
- default:
- BLI_assert(0);
- break;
- }
+ matcache[i] = eevee_material_cache_get(vedata, sldata, ob, i, false);
}
/* Only support single volume material for now. */
/* XXX We rely on the previously compiled surface shader
* to know if the material has a "volume nodetree".
*/
- bool use_volume_material = (gpumat_array[0] &&
- GPU_material_has_volume_output(gpumat_array[0]));
+ bool use_volume_material = (matcache[0].shading_gpumat &&
+ GPU_material_has_volume_output(matcache[0].shading_gpumat));
if ((ob->dt >= OB_SOLID) || DRW_state_is_image_render()) {
- /* Get per-material split surface */
- struct GPUBatch **mat_geom = NULL;
-
- if (!use_sculpt_pbvh) {
- mat_geom = DRW_cache_object_surface_material_get(ob, gpumat_array, materials_len);
- }
-
if (use_sculpt_pbvh) {
- /* Vcol is not supported in the modes that require PBVH drawing. */
- const bool use_vcol = false;
- struct DRWShadingGroup **sculpt_shgrps_array = BLI_array_alloca(sculpt_shgrps_array,
- materials_len);
- for (int i = 0; i < materials_len; i++) {
- sculpt_shgrps_array[i] = shgrps_array[i].shading_grp;
- }
- DRW_shgroup_call_sculpt_with_materials(sculpt_shgrps_array, ob, use_vcol);
+ struct DRWShadingGroup **shgrps_array = BLI_array_alloca(shgrps_array, materials_len);
- for (int i = 0; i < materials_len; i++) {
- sculpt_shgrps_array[i] = shgrps_array[i].depth_grp;
- }
- DRW_shgroup_call_sculpt_with_materials(sculpt_shgrps_array, ob, use_vcol);
- for (int i = 0; i < materials_len; i++) {
- sculpt_shgrps_array[i] = shgrps_array[i].depth_clip_grp;
- }
- DRW_shgroup_call_sculpt_with_materials(sculpt_shgrps_array, ob, use_vcol);
+ MATCACHE_AS_ARRAY(matcache, shading_grp, materials_len, shgrps_array);
+ DRW_shgroup_call_sculpt_with_materials(shgrps_array, materials_len, ob);
- for (int renderpass_index = 0;
- renderpass_index < stl->g_data->render_passes_material_count;
- renderpass_index++) {
- for (int i = 0; i < materials_len; i++) {
- sculpt_shgrps_array[i] = shgrps_array[i].material_accum_grp[renderpass_index];
- }
- DRW_shgroup_call_sculpt_with_materials(sculpt_shgrps_array, ob, use_vcol);
- }
+ MATCACHE_AS_ARRAY(matcache, depth_grp, materials_len, shgrps_array);
+ DRW_shgroup_call_sculpt_with_materials(shgrps_array, materials_len, ob);
- /* TODO(fclem): Support shadows in sculpt mode. */
+ MATCACHE_AS_ARRAY(matcache, shadow_grp, materials_len, shgrps_array);
+ DRW_shgroup_call_sculpt_with_materials(shgrps_array, materials_len, ob);
}
- else if (mat_geom) {
- for (int i = 0; i < materials_len; i++) {
- if (mat_geom[i] == NULL) {
- continue;
- }
+ else {
+ struct GPUMaterial **gpumat_array = BLI_array_alloca(gpumat_array, materials_len);
+ MATCACHE_AS_ARRAY(matcache, shading_gpumat, materials_len, gpumat_array);
+ /* Get per-material split surface */
+ struct GPUBatch **mat_geom = DRW_cache_object_surface_material_get(
+ ob, gpumat_array, materials_len);
- /* 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_has_surface_output(gpumat_array[i]))) {
- continue;
- }
+ if (mat_geom) {
+ for (int i = 0; i < materials_len; i++) {
+ if (mat_geom[i] == NULL) {
+ continue;
+ }
- /* XXX TODO rewrite this to include the dupli objects.
- * This means we cannot exclude dupli objects from reflections!!! */
- EEVEE_ObjectEngineData *oedata = NULL;
- if ((ob->base_flag & BASE_FROM_DUPLI) == 0) {
- oedata = EEVEE_object_data_ensure(ob);
- oedata->ob = ob;
- oedata->test_data = &sldata->probes->vis_data;
- }
- EeveeMaterialShadingGroups *shgrps = &shgrps_array[i];
- ADD_SHGROUP_CALL(shgrps->shading_grp, ob, mat_geom[i], oedata);
- ADD_SHGROUP_CALL_SAFE(shgrps->depth_grp, ob, mat_geom[i], oedata);
- ADD_SHGROUP_CALL_SAFE(shgrps->depth_clip_grp, ob, mat_geom[i], oedata);
- for (int renderpass_index = 0;
- renderpass_index < stl->g_data->render_passes_material_count;
- renderpass_index++) {
- ADD_SHGROUP_CALL_SAFE(
- shgrps->material_accum_grp[renderpass_index], ob, mat_geom[i], oedata);
- }
+ /* 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_has_surface_output(gpumat_array[i]))) {
+ continue;
+ }
+
+ /* XXX TODO rewrite this to include the dupli objects.
+ * This means we cannot exclude dupli objects from reflections!!! */
+ EEVEE_ObjectEngineData *oedata = NULL;
+ if ((ob->base_flag & BASE_FROM_DUPLI) == 0) {
+ oedata = EEVEE_object_data_ensure(ob);
+ oedata->ob = ob;
+ oedata->test_data = &sldata->probes->vis_data;
+ }
- /* Shadow Pass */
- struct GPUMaterial *gpumat;
- const bool use_gpumat = (ma_array[i]->use_nodes && ma_array[i]->nodetree);
- char blend_shadow = use_gpumat ? ma_array[i]->blend_shadow : MA_BS_SOLID;
- switch (blend_shadow) {
- case MA_BS_SOLID:
- EEVEE_shadows_caster_add(sldata, stl, mat_geom[i], ob);
- *cast_shadow = true;
- break;
- case MA_BS_CLIP:
- gpumat = EEVEE_material_mesh_depth_get(scene, ma_array[i], false, true);
- EEVEE_shadows_caster_material_add(
- sldata, psl, gpumat, mat_geom[i], ob, &ma_array[i]->alpha_threshold);
- *cast_shadow = true;
- break;
- case MA_BS_HASHED:
- gpumat = EEVEE_material_mesh_depth_get(scene, ma_array[i], true, true);
- EEVEE_shadows_caster_material_add(sldata, psl, gpumat, mat_geom[i], ob, NULL);
- *cast_shadow = true;
- break;
- case MA_BS_NONE:
- default:
- break;
+ ADD_SHGROUP_CALL(matcache[i].shading_grp, ob, mat_geom[i], oedata);
+ ADD_SHGROUP_CALL_SAFE(matcache[i].depth_grp, ob, mat_geom[i], oedata);
+ ADD_SHGROUP_CALL_SAFE(matcache[i].shadow_grp, ob, mat_geom[i], oedata);
+ *cast_shadow = (matcache[i].shadow_grp != NULL);
}
}
}
@@ -2181,7 +919,7 @@ void EEVEE_particle_hair_cache_populate(EEVEE_Data *vedata,
if (ob->type == OB_MESH) {
if (ob != draw_ctx->object_edit) {
- for (ModifierData *md = ob->modifiers.first; md; md = md->next) {
+ LISTBASE_FOREACH (ModifierData *, md, &ob->modifiers) {
if (md->type != eModifierType_ParticleSystem) {
continue;
}
@@ -2210,11 +948,12 @@ void EEVEE_object_hair_cache_populate(EEVEE_Data *vedata,
void EEVEE_materials_cache_finish(EEVEE_ViewLayerData *sldata, EEVEE_Data *vedata)
{
- EEVEE_StorageList *stl = ((EEVEE_Data *)vedata)->stl;
+ EEVEE_PrivateData *pd = vedata->stl->g_data;
+ EEVEE_EffectsInfo *effects = vedata->stl->effects;
- BLI_ghash_free(stl->g_data->material_hash, NULL, MEM_freeN);
+ BLI_ghash_free(pd->material_hash, NULL, NULL);
- SET_FLAG_FROM_TEST(stl->effects->enabled_effects, e_data.sss_count > 0, EFFECT_SSS);
+ SET_FLAG_FROM_TEST(effects->enabled_effects, effects->sss_surface_count > 0, EFFECT_SSS);
/* TODO(fclem) this is not really clean. Init should not be done in cache finish. */
EEVEE_subsurface_draw_init(sldata, vedata);
@@ -2222,38 +961,10 @@ void EEVEE_materials_cache_finish(EEVEE_ViewLayerData *sldata, EEVEE_Data *vedat
void EEVEE_materials_free(void)
{
- for (int i = 0; i < VAR_MAT_MAX; i++) {
- DRW_SHADER_FREE_SAFE(e_data.default_lit[i]);
- }
- MEM_SAFE_FREE(e_data.frag_shader_lib);
- MEM_SAFE_FREE(e_data.vert_shader_str);
- MEM_SAFE_FREE(e_data.vert_shadow_shader_str);
- MEM_SAFE_FREE(e_data.vert_background_shader_str);
- MEM_SAFE_FREE(e_data.vert_volume_shader_str);
- MEM_SAFE_FREE(e_data.geom_volume_shader_str);
- MEM_SAFE_FREE(e_data.volume_shader_lib);
- DRW_SHADER_FREE_SAFE(e_data.default_hair_prepass_sh);
- DRW_SHADER_FREE_SAFE(e_data.default_hair_prepass_clip_sh);
- DRW_SHADER_FREE_SAFE(e_data.default_prepass_sh);
- DRW_SHADER_FREE_SAFE(e_data.default_prepass_clip_sh);
- DRW_SHADER_FREE_SAFE(e_data.default_background);
- DRW_SHADER_FREE_SAFE(e_data.update_noise_sh);
DRW_TEXTURE_FREE_SAFE(e_data.util_tex);
DRW_TEXTURE_FREE_SAFE(e_data.noise_tex);
}
-void EEVEE_materials_draw_opaque(EEVEE_ViewLayerData *UNUSED(sldata), EEVEE_PassList *psl)
-{
- for (int i = 0; i < VAR_MAT_MAX; i++) {
- if (psl->default_pass[i]) {
- DRW_draw_pass(psl->default_pass[i]);
- }
- }
-
- DRW_draw_pass(psl->material_pass);
- DRW_draw_pass(psl->material_pass_cull);
-}
-
/* -------------------------------------------------------------------- */
/** \name Render Passes
@@ -2261,172 +972,140 @@ void EEVEE_materials_draw_opaque(EEVEE_ViewLayerData *UNUSED(sldata), EEVEE_Pass
void EEVEE_material_renderpasses_init(EEVEE_Data *vedata)
{
- EEVEE_StorageList *stl = vedata->stl;
- EEVEE_PrivateData *g_data = stl->g_data;
+ EEVEE_PrivateData *pd = vedata->stl->g_data;
/* For diffuse and glossy we calculate the final light + color buffer where we extract the
* light from by dividing by the color buffer. When one the light is requested we also tag
* the color buffer to do the extraction. */
- if (g_data->render_passes & EEVEE_RENDER_PASS_DIFFUSE_LIGHT) {
- g_data->render_passes |= EEVEE_RENDER_PASS_DIFFUSE_COLOR;
+ if (pd->render_passes & EEVEE_RENDER_PASS_DIFFUSE_LIGHT) {
+ pd->render_passes |= EEVEE_RENDER_PASS_DIFFUSE_COLOR;
}
- if (g_data->render_passes & EEVEE_RENDER_PASS_SPECULAR_LIGHT) {
- g_data->render_passes |= EEVEE_RENDER_PASS_SPECULAR_COLOR;
+ if (pd->render_passes & EEVEE_RENDER_PASS_SPECULAR_LIGHT) {
+ pd->render_passes |= EEVEE_RENDER_PASS_SPECULAR_COLOR;
}
+}
- /* Calculate the number of material based render passes */
- uint num_render_passes = count_bits_i(stl->g_data->render_passes & EEVEE_RENDERPASSES_MATERIAL);
- if ((num_render_passes != 0 && stl->g_data->render_passes & EEVEE_RENDER_PASS_ENVIRONMENT) ==
- 0) {
- num_render_passes += 1;
+static void material_renderpass_init(EEVEE_FramebufferList *fbl,
+ GPUTexture **output_tx,
+ const eGPUTextureFormat format,
+ const bool do_clear)
+{
+ DRW_texture_ensure_fullscreen_2d(output_tx, format, 0);
+ /* Clear texture. */
+ if (do_clear) {
+ float clear[4] = {0.0f, 0.0f, 0.0f, 0.0f};
+ /* TODO(fclem) replace by GPU_texture_clear once it is fast. */
+ GPU_framebuffer_texture_attach(fbl->material_accum_fb, *output_tx, 0, 0);
+ GPU_framebuffer_bind(fbl->material_accum_fb);
+ GPU_framebuffer_clear_color(fbl->material_accum_fb, clear);
+ GPU_framebuffer_bind(fbl->main_fb);
+ GPU_framebuffer_texture_detach(fbl->material_accum_fb, *output_tx);
}
- stl->g_data->render_passes_material_count = num_render_passes;
}
void EEVEE_material_output_init(EEVEE_ViewLayerData *sldata, EEVEE_Data *vedata, uint tot_samples)
{
- const DRWContextState *draw_ctx = DRW_context_state_get();
EEVEE_FramebufferList *fbl = vedata->fbl;
DefaultTextureList *dtxl = DRW_viewport_texture_list_get();
EEVEE_TextureList *txl = vedata->txl;
EEVEE_StorageList *stl = vedata->stl;
- EEVEE_PassList *psl = vedata->psl;
EEVEE_EffectsInfo *effects = stl->effects;
+ EEVEE_PrivateData *pd = stl->g_data;
- float clear[4] = {0.0f, 0.0f, 0.0f, 0.0f};
+ /* Should be enough precision for many samples. */
+ const eGPUTextureFormat texture_format = (tot_samples > 128) ? GPU_RGBA32F : GPU_RGBA16F;
+ const bool do_clear = DRW_state_is_image_render() || (effects->taa_current_sample == 1);
/* Create FrameBuffer. */
+ GPU_framebuffer_ensure_config(&fbl->material_accum_fb,
+ {GPU_ATTACHMENT_TEXTURE(dtxl->depth), GPU_ATTACHMENT_LEAVE});
- /* Should be enough precision for many samples. */
- const eGPUTextureFormat texture_format_material_accum = (tot_samples > 128) ? GPU_RGBA32F :
- GPU_RGBA16F;
- const eViewLayerEEVEEPassType render_passes = stl->g_data->render_passes &
- EEVEE_RENDERPASSES_MATERIAL;
- if (render_passes != 0) {
- GPU_framebuffer_ensure_config(&fbl->material_accum_fb,
- {GPU_ATTACHMENT_TEXTURE(dtxl->depth), GPU_ATTACHMENT_LEAVE});
- int render_pass_index = ((render_passes & EEVEE_RENDER_PASS_ENVIRONMENT) != 0) ? 0 : 1;
- for (int bit = 0; bit < 32; bit++) {
- eViewLayerEEVEEPassType bitflag = (1 << bit);
- if ((render_passes & bitflag) != 0) {
-
- DRW_texture_ensure_fullscreen_2d(
- &txl->material_accum[render_pass_index], texture_format_material_accum, 0);
-
- /* Clear texture. */
- if (DRW_state_is_image_render() || effects->taa_current_sample == 1) {
- GPU_framebuffer_texture_attach(
- fbl->material_accum_fb, txl->material_accum[render_pass_index], 0, 0);
- GPU_framebuffer_bind(fbl->material_accum_fb);
- GPU_framebuffer_clear_color(fbl->material_accum_fb, clear);
- GPU_framebuffer_bind(fbl->main_fb);
- GPU_framebuffer_texture_detach(fbl->material_accum_fb,
- txl->material_accum[render_pass_index]);
- }
- render_pass_index++;
- }
- }
+ if (pd->render_passes & EEVEE_RENDER_PASS_ENVIRONMENT) {
+ material_renderpass_init(fbl, &txl->env_accum, texture_format, do_clear);
+ }
+ if (pd->render_passes & EEVEE_RENDER_PASS_EMIT) {
+ material_renderpass_init(fbl, &txl->emit_accum, texture_format, do_clear);
+ }
+ if (pd->render_passes & EEVEE_RENDER_PASS_DIFFUSE_COLOR) {
+ material_renderpass_init(fbl, &txl->diff_color_accum, texture_format, do_clear);
+ }
+ if (pd->render_passes & EEVEE_RENDER_PASS_DIFFUSE_LIGHT) {
+ material_renderpass_init(fbl, &txl->diff_light_accum, texture_format, do_clear);
+ }
+ if (pd->render_passes & EEVEE_RENDER_PASS_SPECULAR_COLOR) {
+ material_renderpass_init(fbl, &txl->spec_color_accum, texture_format, do_clear);
+ }
+ if (pd->render_passes & EEVEE_RENDER_PASS_SPECULAR_LIGHT) {
+ material_renderpass_init(fbl, &txl->spec_light_accum, texture_format, do_clear);
- if ((render_passes & EEVEE_RENDER_PASS_SPECULAR_LIGHT) &&
- (effects->enabled_effects & EFFECT_SSR)) {
+ if (effects->enabled_effects & EFFECT_SSR) {
EEVEE_reflection_output_init(sldata, vedata, tot_samples);
}
+ }
+}
- if (render_passes & EEVEE_RENDER_PASS_ENVIRONMENT) {
- Scene *scene = draw_ctx->scene;
- World *wo = scene->world;
+static void material_renderpass_accumulate(EEVEE_FramebufferList *fbl,
+ DRWPass *renderpass,
+ EEVEE_PrivateData *pd,
+ GPUTexture *output_tx,
+ struct GPUUniformBuffer *renderpass_option_ubo)
+{
+ GPU_framebuffer_texture_attach(fbl->material_accum_fb, output_tx, 0, 0);
+ GPU_framebuffer_bind(fbl->material_accum_fb);
- if (wo && wo->use_nodes && wo->nodetree) {
- struct GPUMaterial *gpumat = EEVEE_material_world_background_get(scene, wo);
- if (GPU_material_status(gpumat) == GPU_MAT_SUCCESS) {
- DRWShadingGroup *grp = DRW_shgroup_material_create(gpumat, psl->material_accum_pass[0]);
- add_background_uniforms(grp, sldata, vedata);
- DRW_shgroup_call(grp, DRW_cache_fullscreen_quad_get(), NULL);
- }
- }
- }
- }
+ pd->renderpass_ubo = renderpass_option_ubo;
+ DRW_draw_pass(renderpass);
+
+ GPU_framebuffer_texture_detach(fbl->material_accum_fb, output_tx);
}
void EEVEE_material_output_accumulate(EEVEE_ViewLayerData *sldata, EEVEE_Data *vedata)
{
EEVEE_FramebufferList *fbl = vedata->fbl;
EEVEE_PassList *psl = vedata->psl;
- EEVEE_StorageList *stl = vedata->stl;
+ EEVEE_PrivateData *pd = vedata->stl->g_data;
+ EEVEE_EffectsInfo *effects = vedata->stl->effects;
EEVEE_TextureList *txl = vedata->txl;
if (fbl->material_accum_fb != NULL) {
- for (int renderpass_index = 0; renderpass_index < stl->g_data->render_passes_material_count;
- renderpass_index++) {
- if (txl->material_accum[renderpass_index] != NULL) {
- GPU_framebuffer_texture_attach(
- fbl->material_accum_fb, txl->material_accum[renderpass_index], 0, 0);
- GPU_framebuffer_bind(fbl->material_accum_fb);
- DRW_draw_pass(psl->material_accum_pass[renderpass_index]);
- GPU_framebuffer_bind(fbl->main_fb);
- GPU_framebuffer_texture_detach(fbl->material_accum_fb,
- txl->material_accum[renderpass_index]);
- }
+ DRWPass *material_accum_ps = psl->material_accum_ps;
+ if (pd->render_passes & EEVEE_RENDER_PASS_ENVIRONMENT) {
+ material_renderpass_accumulate(
+ fbl, psl->background_accum_ps, pd, txl->env_accum, sldata->renderpass_ubo.combined);
}
- if ((stl->g_data->render_passes & EEVEE_RENDER_PASS_SPECULAR_LIGHT) &&
- (stl->effects->enabled_effects & EFFECT_SSR)) {
- EEVEE_reflection_output_accumulate(sldata, vedata);
+ if (pd->render_passes & EEVEE_RENDER_PASS_EMIT) {
+ material_renderpass_accumulate(
+ fbl, material_accum_ps, pd, txl->emit_accum, sldata->renderpass_ubo.emit);
}
- }
-}
-
-int EEVEE_material_output_pass_index_get(EEVEE_ViewLayerData *UNUSED(sldata),
- EEVEE_Data *vedata,
- eViewLayerEEVEEPassType renderpass_type)
-{
- EEVEE_StorageList *stl = vedata->stl;
-
- BLI_assert((stl->g_data->render_passes & EEVEE_RENDERPASSES_MATERIAL) != 0);
- BLI_assert((stl->g_data->render_passes & EEVEE_RENDERPASSES_MATERIAL & renderpass_type) != 0);
-
- /* pass_index 0 is reserved for the environment pass. */
- if ((stl->g_data->render_passes & EEVEE_RENDER_PASS_ENVIRONMENT & renderpass_type) != 0) {
- return 0;
- }
-
- /* pass_index 0 is reserved for the environment pass. Other passes start from index 1 */
- int index = 1;
- eViewLayerEEVEEPassType active_material_passes = stl->g_data->render_passes &
- EEVEE_RENDERPASSES_MATERIAL &
- ~EEVEE_RENDER_PASS_ENVIRONMENT;
+ if (pd->render_passes & EEVEE_RENDER_PASS_DIFFUSE_COLOR) {
+ material_renderpass_accumulate(
+ fbl, material_accum_ps, pd, txl->diff_color_accum, sldata->renderpass_ubo.diff_color);
+ }
+ if (pd->render_passes & EEVEE_RENDER_PASS_DIFFUSE_LIGHT) {
+ material_renderpass_accumulate(
+ fbl, material_accum_ps, pd, txl->diff_light_accum, sldata->renderpass_ubo.diff_light);
- for (int bitshift = 0; bitshift < 32; bitshift++) {
- eViewLayerEEVEEPassType pass_flag = (1 << bitshift);
- if (pass_flag == renderpass_type) {
- break;
+ if (effects->enabled_effects & EFFECT_SSS) {
+ EEVEE_subsurface_output_accumulate(sldata, vedata);
+ }
}
- if (active_material_passes & pass_flag) {
- index++;
+ if (pd->render_passes & EEVEE_RENDER_PASS_SPECULAR_COLOR) {
+ material_renderpass_accumulate(
+ fbl, material_accum_ps, pd, txl->spec_color_accum, sldata->renderpass_ubo.spec_color);
}
- }
+ if (pd->render_passes & EEVEE_RENDER_PASS_SPECULAR_LIGHT) {
+ material_renderpass_accumulate(
+ fbl, material_accum_ps, pd, txl->spec_light_accum, sldata->renderpass_ubo.spec_light);
- return index;
-}
+ if (effects->enabled_effects & EFFECT_SSR) {
+ EEVEE_reflection_output_accumulate(sldata, vedata);
+ }
+ }
-/* Get the pass index that contains the color pass for the given renderpass_type. */
-int EEVEE_material_output_color_pass_index_get(EEVEE_ViewLayerData *sldata,
- EEVEE_Data *vedata,
- eViewLayerEEVEEPassType renderpass_type)
-{
- BLI_assert(
- ELEM(renderpass_type, EEVEE_RENDER_PASS_DIFFUSE_LIGHT, EEVEE_RENDER_PASS_SPECULAR_LIGHT));
- eViewLayerEEVEEPassType color_pass_type;
- switch (renderpass_type) {
- case EEVEE_RENDER_PASS_DIFFUSE_LIGHT:
- color_pass_type = EEVEE_RENDER_PASS_DIFFUSE_COLOR;
- break;
- case EEVEE_RENDER_PASS_SPECULAR_LIGHT:
- color_pass_type = EEVEE_RENDER_PASS_SPECULAR_COLOR;
- break;
- default:
- color_pass_type = 0;
- BLI_assert(false);
+ /* Restore default. */
+ pd->renderpass_ubo = sldata->renderpass_ubo.combined;
+ GPU_framebuffer_bind(fbl->main_fb);
}
- return EEVEE_material_output_pass_index_get(sldata, vedata, color_pass_type);
}
+
/* \} */
diff --git a/source/blender/draw/engines/eevee/eevee_mist.c b/source/blender/draw/engines/eevee/eevee_mist.c
index cdcfd64d995..7b942784ee9 100644
--- a/source/blender/draw/engines/eevee/eevee_mist.c
+++ b/source/blender/draw/engines/eevee/eevee_mist.c
@@ -114,8 +114,7 @@ void EEVEE_mist_output_init(EEVEE_ViewLayerData *sldata, EEVEE_Data *vedata)
DRWShadingGroup *grp = DRW_shgroup_create(e_data.mist_sh, psl->mist_accum_ps);
DRW_shgroup_uniform_texture_ref(grp, "depthBuffer", &dtxl->depth);
DRW_shgroup_uniform_block(grp, "common_block", sldata->common_ubo);
- DRW_shgroup_uniform_block(
- grp, "renderpass_block", EEVEE_material_default_render_pass_ubo_get(sldata));
+ DRW_shgroup_uniform_block(grp, "renderpass_block", sldata->renderpass_ubo.combined);
DRW_shgroup_uniform_vec3(grp, "mistSettings", &g_data->mist_start, 1);
DRW_shgroup_call(grp, DRW_cache_fullscreen_quad_get(), NULL);
}
diff --git a/source/blender/draw/engines/eevee/eevee_motion_blur.c b/source/blender/draw/engines/eevee/eevee_motion_blur.c
index 13927cd5124..a6e6b30a6b1 100644
--- a/source/blender/draw/engines/eevee/eevee_motion_blur.c
+++ b/source/blender/draw/engines/eevee/eevee_motion_blur.c
@@ -73,8 +73,7 @@ static void eevee_motion_blur_camera_get_matrix_at_time(Scene *scene,
/* Past matrix */
/* FIXME : This is a temporal solution that does not take care of parent animations */
/* Recalc Anim manually */
- BKE_animsys_evaluate_animdata(
- scene, &camdata_cpy.id, camdata_cpy.adt, time, ADT_RECALC_ALL, false);
+ BKE_animsys_evaluate_animdata(&camdata_cpy.id, camdata_cpy.adt, time, ADT_RECALC_ALL, false);
BKE_object_where_is_calc_time(draw_ctx->depsgraph, scene, &cam_cpy, time);
/* Compute winmat */
diff --git a/source/blender/draw/engines/eevee/eevee_occlusion.c b/source/blender/draw/engines/eevee/eevee_occlusion.c
index be4dfd07ce1..f5ebbe08dd1 100644
--- a/source/blender/draw/engines/eevee/eevee_occlusion.c
+++ b/source/blender/draw/engines/eevee/eevee_occlusion.c
@@ -170,8 +170,7 @@ void EEVEE_occlusion_output_init(EEVEE_ViewLayerData *sldata, EEVEE_Data *vedata
DRW_shgroup_uniform_texture_ref(grp, "normalBuffer", &effects->ssr_normal_input);
DRW_shgroup_uniform_texture_ref(grp, "horizonBuffer", &effects->gtao_horizons);
DRW_shgroup_uniform_block(grp, "common_block", sldata->common_ubo);
- DRW_shgroup_uniform_block(
- grp, "renderpass_block", EEVEE_material_default_render_pass_ubo_get(sldata));
+ DRW_shgroup_uniform_block(grp, "renderpass_block", sldata->renderpass_ubo.combined);
DRW_shgroup_call(grp, DRW_cache_fullscreen_quad_get(), NULL);
}
else {
@@ -209,8 +208,7 @@ void EEVEE_occlusion_cache_init(EEVEE_ViewLayerData *sldata, EEVEE_Data *vedata)
DRW_shgroup_uniform_texture_ref(grp, "maxzBuffer", &txl->maxzbuffer);
DRW_shgroup_uniform_texture_ref(grp, "depthBuffer", &effects->ao_src_depth);
DRW_shgroup_uniform_block(grp, "common_block", sldata->common_ubo);
- DRW_shgroup_uniform_block(
- grp, "renderpass_block", EEVEE_material_default_render_pass_ubo_get(sldata));
+ DRW_shgroup_uniform_block(grp, "renderpass_block", sldata->renderpass_ubo.combined);
DRW_shgroup_call(grp, quad, NULL);
DRW_PASS_CREATE(psl->ao_horizon_search_layer, DRW_STATE_WRITE_COLOR);
@@ -219,8 +217,7 @@ void EEVEE_occlusion_cache_init(EEVEE_ViewLayerData *sldata, EEVEE_Data *vedata)
DRW_shgroup_uniform_texture_ref(grp, "maxzBuffer", &txl->maxzbuffer);
DRW_shgroup_uniform_texture_ref(grp, "depthBufferLayered", &effects->ao_src_depth);
DRW_shgroup_uniform_block(grp, "common_block", sldata->common_ubo);
- DRW_shgroup_uniform_block(
- grp, "renderpass_block", EEVEE_material_default_render_pass_ubo_get(sldata));
+ DRW_shgroup_uniform_block(grp, "renderpass_block", sldata->renderpass_ubo.combined);
DRW_shgroup_uniform_int(grp, "layer", &stl->effects->ao_depth_layer, 1);
DRW_shgroup_call(grp, quad, NULL);
@@ -233,8 +230,7 @@ void EEVEE_occlusion_cache_init(EEVEE_ViewLayerData *sldata, EEVEE_Data *vedata)
DRW_shgroup_uniform_texture_ref(grp, "normalBuffer", &effects->ssr_normal_input);
DRW_shgroup_uniform_texture_ref(grp, "horizonBuffer", &effects->gtao_horizons);
DRW_shgroup_uniform_block(grp, "common_block", sldata->common_ubo);
- DRW_shgroup_uniform_block(
- grp, "renderpass_block", EEVEE_material_default_render_pass_ubo_get(sldata));
+ DRW_shgroup_uniform_block(grp, "renderpass_block", sldata->renderpass_ubo.combined);
DRW_shgroup_call(grp, quad, NULL);
}
}
diff --git a/source/blender/draw/engines/eevee/eevee_private.h b/source/blender/draw/engines/eevee/eevee_private.h
index e2470b4fa76..40008c5c364 100644
--- a/source/blender/draw/engines/eevee/eevee_private.h
+++ b/source/blender/draw/engines/eevee/eevee_private.h
@@ -158,35 +158,34 @@ BLI_INLINE bool eevee_hdri_preview_overlay_enabled(const View3D *v3d)
(EEVEE_RENDER_PASS_EMIT | EEVEE_RENDER_PASS_DIFFUSE_COLOR | EEVEE_RENDER_PASS_DIFFUSE_LIGHT | \
EEVEE_RENDER_PASS_SPECULAR_COLOR | EEVEE_RENDER_PASS_SPECULAR_LIGHT | \
EEVEE_RENDER_PASS_ENVIRONMENT)
-#define MAX_MATERIAL_RENDER_PASSES 6
-#define MAX_MATERIAL_RENDER_PASSES_UBO 6
-/* World shader variations */
-enum {
- VAR_WORLD_BACKGROUND = 0,
- VAR_WORLD_PROBE = 1,
- VAR_WORLD_VOLUME = 2,
-};
/* Material shader variations */
enum {
VAR_MAT_MESH = (1 << 0),
- VAR_MAT_PROBE = (1 << 1),
+ VAR_MAT_VOLUME = (1 << 1),
VAR_MAT_HAIR = (1 << 2),
- VAR_MAT_BLEND = (1 << 3),
- VAR_MAT_VOLUME = (1 << 4),
+ VAR_MAT_PROBE = (1 << 3),
+ VAR_MAT_BLEND = (1 << 4),
VAR_MAT_LOOKDEV = (1 << 5),
VAR_MAT_HOLDOUT = (1 << 6),
- /* Max number of variation */
- /* IMPORTANT : Leave it last and set
- * it's value accordingly. */
- VAR_MAT_MAX = (1 << 7),
- /* These are options that are not counted in VAR_MAT_MAX
- * because they are not cumulative with the others above. */
- VAR_MAT_CLIP = (1 << 9),
- VAR_MAT_HASH = (1 << 10),
- VAR_MAT_MULT = (1 << 11),
- VAR_MAT_SHADOW = (1 << 12),
- VAR_MAT_REFRACT = (1 << 13),
+ VAR_MAT_HASH = (1 << 7),
+ VAR_MAT_DEPTH = (1 << 8),
+ VAR_MAT_REFRACT = (1 << 9),
+ VAR_WORLD_BACKGROUND = (1 << 10),
+ VAR_WORLD_PROBE = (1 << 11),
+ VAR_WORLD_VOLUME = (1 << 12),
+ VAR_DEFAULT = (1 << 13),
+};
+
+/* Material shader cache keys */
+enum {
+ /* HACK: This assumes the struct GPUShader will never be smaller than our variations.
+ * This allow us to only keep one ghash and avoid bigger keys comparisons/hashing.
+ * We combine the GPUShader pointer with the key. */
+ KEY_CULL = (1 << 0),
+ KEY_REFRACT = (1 << 1),
+ KEY_HAIR = (1 << 2),
+ KEY_SHADOW = (1 << 3),
};
/* ************ PROBE UBO ************* */
@@ -272,23 +271,26 @@ typedef struct EEVEE_PassList {
struct DRWPass *maxz_copydepth_ps;
struct DRWPass *maxz_copydepth_layer_ps;
- struct DRWPass *depth_pass;
- struct DRWPass *depth_pass_cull;
- struct DRWPass *depth_pass_clip;
- struct DRWPass *depth_pass_clip_cull;
- struct DRWPass *refract_depth_pass;
- struct DRWPass *refract_depth_pass_cull;
- struct DRWPass *refract_depth_pass_clip;
- struct DRWPass *refract_depth_pass_clip_cull;
- struct DRWPass *default_pass[VAR_MAT_MAX];
- struct DRWPass *sss_pass;
- struct DRWPass *sss_pass_cull;
- struct DRWPass *material_pass;
- struct DRWPass *material_pass_cull;
- struct DRWPass *material_accum_pass[MAX_MATERIAL_RENDER_PASSES];
- struct DRWPass *refract_pass;
+ /* Renderpass Accumulation. */
+ struct DRWPass *material_accum_ps;
+ struct DRWPass *background_accum_ps;
+
+ struct DRWPass *depth_ps;
+ struct DRWPass *depth_cull_ps;
+ struct DRWPass *depth_clip_ps;
+ struct DRWPass *depth_clip_cull_ps;
+ struct DRWPass *depth_refract_ps;
+ struct DRWPass *depth_refract_cull_ps;
+ struct DRWPass *depth_refract_clip_ps;
+ struct DRWPass *depth_refract_clip_cull_ps;
+ struct DRWPass *material_ps;
+ struct DRWPass *material_cull_ps;
+ struct DRWPass *material_refract_ps;
+ struct DRWPass *material_refract_cull_ps;
+ struct DRWPass *material_sss_ps;
+ struct DRWPass *material_sss_cull_ps;
struct DRWPass *transparent_pass;
- struct DRWPass *background_pass;
+ struct DRWPass *background_ps;
struct DRWPass *update_noise_pass;
struct DRWPass *lookdev_glossy_pass;
struct DRWPass *lookdev_diffuse_pass;
@@ -348,7 +350,12 @@ typedef struct EEVEE_TextureList {
struct GPUTexture *mist_accum;
struct GPUTexture *ao_accum;
struct GPUTexture *sss_accum;
- struct GPUTexture *material_accum[MAX_MATERIAL_RENDER_PASSES];
+ struct GPUTexture *env_accum;
+ struct GPUTexture *diff_color_accum;
+ struct GPUTexture *diff_light_accum;
+ struct GPUTexture *spec_color_accum;
+ struct GPUTexture *spec_light_accum;
+ struct GPUTexture *emit_accum;
struct GPUTexture *bloom_accum;
struct GPUTexture *ssr_accum;
struct GPUTexture *shadow_accum;
@@ -574,6 +581,7 @@ typedef struct EEVEE_EffectsInfo {
bool swap_double_buffer;
/* SSSS */
int sss_sample_count;
+ int sss_surface_count;
struct GPUTexture *sss_irradiance; /* Textures from pool */
struct GPUTexture *sss_radius;
struct GPUTexture *sss_albedo;
@@ -600,6 +608,7 @@ typedef struct EEVEE_EffectsInfo {
int taa_total_sample;
float taa_alpha;
bool prev_drw_support;
+ bool prev_is_navigating;
float prev_drw_persmat[4][4];
struct DRWView *taa_view;
/* Ambient Occlusion */
@@ -753,14 +762,22 @@ typedef struct EEVEE_ViewLayerData {
struct GPUUniformBuffer *planar_ubo;
/* Material Render passes */
- struct EEVEE_RenderPassData renderpass_data[MAX_MATERIAL_RENDER_PASSES_UBO];
- struct GPUUniformBuffer *renderpass_ubo[MAX_MATERIAL_RENDER_PASSES_UBO];
+ struct {
+ struct GPUUniformBuffer *combined;
+ struct GPUUniformBuffer *diff_color;
+ struct GPUUniformBuffer *diff_light;
+ struct GPUUniformBuffer *spec_color;
+ struct GPUUniformBuffer *spec_light;
+ struct GPUUniformBuffer *emit;
+ } renderpass_ubo;
/* Common Uniform Buffer */
struct EEVEE_CommonUniformBuffer common_data;
struct GPUUniformBuffer *common_ubo;
struct LightCache *fallback_lightcache;
+
+ struct BLI_memblock *material_cache;
} EEVEE_ViewLayerData;
/* ************ OBJECT DATA ************ */
@@ -808,14 +825,6 @@ typedef struct EEVEE_Data {
typedef struct EEVEE_PrivateData {
struct DRWShadingGroup *shadow_shgrp;
struct DRWShadingGroup *shadow_accum_shgrp;
- struct DRWShadingGroup *depth_shgrp;
- struct DRWShadingGroup *depth_shgrp_cull;
- struct DRWShadingGroup *depth_shgrp_clip;
- struct DRWShadingGroup *depth_shgrp_clip_cull;
- struct DRWShadingGroup *refract_depth_shgrp;
- struct DRWShadingGroup *refract_depth_shgrp_cull;
- struct DRWShadingGroup *refract_depth_shgrp_clip;
- struct DRWShadingGroup *refract_depth_shgrp_clip_cull;
struct DRWCallBuffer *planar_display_shgrp;
struct GHash *material_hash;
float background_alpha; /* TODO find a better place for this. */
@@ -861,9 +870,8 @@ typedef struct EEVEE_PrivateData {
GPUTexture *renderpass_input;
GPUTexture *renderpass_col_input;
GPUTexture *renderpass_light_input;
- /* The number of active material based render passes */
- uint render_passes_material_count;
-
+ /* Renderpass ubo reference used by material pass. */
+ struct GPUUniformBuffer *renderpass_ubo;
/** For rendering shadows. */
struct DRWView *cube_views[6];
/** For rendering probes. */
@@ -891,6 +899,7 @@ EEVEE_WorldEngineData *EEVEE_world_data_ensure(World *wo);
/* eevee_materials.c */
struct GPUTexture *EEVEE_materials_get_util_tex(void); /* XXX */
void EEVEE_materials_init(EEVEE_ViewLayerData *sldata,
+ EEVEE_Data *vedata,
EEVEE_StorageList *stl,
EEVEE_FramebufferList *fbl);
void EEVEE_materials_cache_init(EEVEE_ViewLayerData *sldata, EEVEE_Data *vedata);
@@ -907,31 +916,20 @@ void EEVEE_object_hair_cache_populate(EEVEE_Data *vedata,
Object *ob,
bool *cast_shadow);
void EEVEE_materials_cache_finish(EEVEE_ViewLayerData *sldata, EEVEE_Data *vedata);
-struct GPUMaterial *EEVEE_material_world_lightprobe_get(struct Scene *scene, struct World *wo);
-struct GPUMaterial *EEVEE_material_world_background_get(struct Scene *scene, struct World *wo);
-struct GPUMaterial *EEVEE_material_world_volume_get(struct Scene *scene, struct World *wo);
-struct GPUMaterial *EEVEE_material_mesh_get(
- struct Scene *scene, Material *ma, EEVEE_Data *vedata, bool use_blend, bool use_refract);
-struct GPUMaterial *EEVEE_material_mesh_volume_get(struct Scene *scene, Material *ma);
-struct GPUMaterial *EEVEE_material_mesh_depth_get(struct Scene *scene,
- Material *ma,
- bool use_hashed_alpha,
- bool is_shadow);
-struct GPUMaterial *EEVEE_material_hair_get(struct Scene *scene, Material *ma);
-struct GPUUniformBuffer *EEVEE_material_default_render_pass_ubo_get(EEVEE_ViewLayerData *sldata);
void EEVEE_materials_free(void);
-void EEVEE_materials_draw_opaque(EEVEE_ViewLayerData *sldata, EEVEE_PassList *psl);
void EEVEE_update_noise(EEVEE_PassList *psl, EEVEE_FramebufferList *fbl, const double offsets[3]);
void EEVEE_update_viewvecs(float invproj[4][4], float winmat[4][4], float (*r_viewvecs)[4]);
void EEVEE_material_renderpasses_init(EEVEE_Data *vedata);
void EEVEE_material_output_init(EEVEE_ViewLayerData *sldata, EEVEE_Data *vedata, uint tot_samples);
void EEVEE_material_output_accumulate(EEVEE_ViewLayerData *sldata, EEVEE_Data *vedata);
-int EEVEE_material_output_pass_index_get(EEVEE_ViewLayerData *UNUSED(sldata),
- EEVEE_Data *vedata,
- eViewLayerEEVEEPassType renderpass_type);
-int EEVEE_material_output_color_pass_index_get(EEVEE_ViewLayerData *sldata,
- EEVEE_Data *vedata,
- eViewLayerEEVEEPassType renderpass_type);
+void EEVEE_material_bind_resources(DRWShadingGroup *shgrp,
+ struct GPUMaterial *gpumat,
+ EEVEE_ViewLayerData *sldata,
+ EEVEE_Data *vedata,
+ int *ssr_id,
+ float *refract_depth,
+ bool use_ssrefraction,
+ bool use_alpha_blend);
/* eevee_lights.c */
void eevee_light_matrix_get(const EEVEE_Light *evli, float r_mat[4][4]);
void EEVEE_lights_cache_init(EEVEE_ViewLayerData *sldata, EEVEE_Data *vedata);
@@ -942,16 +940,6 @@ void EEVEE_lights_cache_finish(EEVEE_ViewLayerData *sldata, EEVEE_Data *vedata);
void eevee_contact_shadow_setup(const Light *la, EEVEE_Shadow *evsh);
void EEVEE_shadows_init(EEVEE_ViewLayerData *sldata);
void EEVEE_shadows_cache_init(EEVEE_ViewLayerData *sldata, EEVEE_Data *vedata);
-void EEVEE_shadows_caster_add(EEVEE_ViewLayerData *sldata,
- EEVEE_StorageList *stl,
- struct GPUBatch *geom,
- Object *ob);
-void EEVEE_shadows_caster_material_add(EEVEE_ViewLayerData *sldata,
- EEVEE_PassList *psl,
- struct GPUMaterial *gpumat,
- struct GPUBatch *geom,
- struct Object *ob,
- const float *alpha_threshold);
void EEVEE_shadows_caster_register(EEVEE_ViewLayerData *sldata, struct Object *ob);
void EEVEE_shadows_update(EEVEE_ViewLayerData *sldata, EEVEE_Data *vedata);
void EEVEE_shadows_cube_add(EEVEE_LightsInfo *linfo, EEVEE_Light *evli, struct Object *ob);
@@ -985,6 +973,7 @@ void EEVEE_random_rotation_m4(int sample_ofs, float scale, float r_mat[4][4]);
/* eevee_shaders.c */
void EEVEE_shaders_lightprobe_shaders_init(void);
+void EEVEE_shaders_material_shaders_init(void);
struct GPUShader *EEVEE_shaders_probe_filter_glossy_sh_get(void);
struct GPUShader *EEVEE_shaders_probe_default_sh_get(void);
struct GPUShader *EEVEE_shaders_probe_filter_diffuse_sh_get(void);
@@ -992,12 +981,22 @@ struct GPUShader *EEVEE_shaders_probe_filter_visibility_sh_get(void);
struct GPUShader *EEVEE_shaders_probe_grid_fill_sh_get(void);
struct GPUShader *EEVEE_shaders_probe_planar_downsample_sh_get(void);
struct GPUShader *EEVEE_shaders_default_studiolight_sh_get(void);
+struct GPUShader *EEVEE_shaders_default_background_sh_get(void);
struct GPUShader *EEVEE_shaders_background_studiolight_sh_get(void);
struct GPUShader *EEVEE_shaders_probe_cube_display_sh_get(void);
struct GPUShader *EEVEE_shaders_probe_grid_display_sh_get(void);
struct GPUShader *EEVEE_shaders_probe_planar_display_sh_get(void);
+struct GPUShader *EEVEE_shaders_update_noise_sh_get(void);
struct GPUShader *EEVEE_shaders_velocity_resolve_sh_get(void);
struct GPUShader *EEVEE_shaders_taa_resolve_sh_get(EEVEE_EffectsFlag enabled_effects);
+struct bNodeTree *EEVEE_shader_default_surface_nodetree(Material *ma);
+struct bNodeTree *EEVEE_shader_default_world_nodetree(World *wo);
+Material *EEVEE_material_default_diffuse_get(void);
+Material *EEVEE_material_default_glossy_get(void);
+Material *EEVEE_material_default_error_get(void);
+struct GPUMaterial *EEVEE_material_default_get(struct Scene *scene, Material *ma, int options);
+struct GPUMaterial *EEVEE_material_get(
+ EEVEE_Data *vedata, struct Scene *scene, Material *ma, World *wo, int options);
void EEVEE_shaders_free(void);
/* eevee_lightprobes.c */
@@ -1104,13 +1103,9 @@ void EEVEE_subsurface_output_init(EEVEE_ViewLayerData *sldata,
uint tot_samples);
void EEVEE_subsurface_add_pass(EEVEE_ViewLayerData *sldata,
EEVEE_Data *vedata,
- uint sss_id,
- struct GPUUniformBuffer *sss_profile);
-void EEVEE_subsurface_translucency_add_pass(EEVEE_ViewLayerData *sldata,
- EEVEE_Data *vedata,
- uint sss_id,
- struct GPUUniformBuffer *sss_profile,
- struct GPUTexture *sss_tex_profile);
+ Material *ma,
+ DRWShadingGroup *shgrp,
+ struct GPUMaterial *gpumat);
void EEVEE_subsurface_data_render(EEVEE_ViewLayerData *sldata, EEVEE_Data *vedata);
void EEVEE_subsurface_compute(EEVEE_ViewLayerData *sldata, EEVEE_Data *vedata);
void EEVEE_subsurface_output_accumulate(EEVEE_ViewLayerData *sldata, EEVEE_Data *vedata);
diff --git a/source/blender/draw/engines/eevee/eevee_render.c b/source/blender/draw/engines/eevee/eevee_render.c
index 255c6c50c2d..89a5ad2198a 100644
--- a/source/blender/draw/engines/eevee/eevee_render.c
+++ b/source/blender/draw/engines/eevee/eevee_render.c
@@ -135,9 +135,8 @@ bool EEVEE_render_init(EEVEE_Data *ved, RenderEngine *engine, struct Depsgraph *
float winmat[4][4], viewmat[4][4], viewinv[4][4];
/* TODO(sergey): Shall render hold pointer to an evaluated camera instead? */
struct Object *ob_camera_eval = DEG_get_evaluated_object(depsgraph, RE_GetCamera(engine->re));
- float frame = BKE_scene_frame_get(scene);
- RE_GetCameraWindow(engine->re, ob_camera_eval, frame, winmat);
+ RE_GetCameraWindow(engine->re, ob_camera_eval, winmat);
RE_GetCameraWindowWithOverscan(engine->re, winmat, g_data->overscan);
RE_GetCameraModelMatrix(engine->re, ob_camera_eval, viewinv);
@@ -152,7 +151,7 @@ bool EEVEE_render_init(EEVEE_Data *ved, RenderEngine *engine, struct Depsgraph *
* `EEVEE_effects_init` needs to go second for TAA. */
EEVEE_renderpasses_init(vedata);
EEVEE_effects_init(sldata, vedata, ob_camera_eval, false);
- EEVEE_materials_init(sldata, stl, fbl);
+ EEVEE_materials_init(sldata, vedata, stl, fbl);
EEVEE_shadows_init(sldata);
EEVEE_lightprobes_init(sldata, vedata);
@@ -464,7 +463,7 @@ static void eevee_render_draw_background(EEVEE_Data *vedata)
GPU_ATTACHMENT_NONE});
GPU_framebuffer_bind(fbl->main_fb);
- DRW_draw_pass(psl->background_pass);
+ DRW_draw_pass(psl->background_ps);
GPU_framebuffer_ensure_config(&fbl->main_fb,
{GPU_ATTACHMENT_LEAVE,
@@ -557,7 +556,7 @@ void EEVEE_render_draw(EEVEE_Data *vedata, RenderEngine *engine, RenderLayer *rl
EEVEE_update_noise(psl, fbl, r);
EEVEE_temporal_sampling_matrices_calc(stl->effects, r);
EEVEE_volumes_set_jitter(sldata, stl->effects->taa_current_sample - 1);
- EEVEE_materials_init(sldata, stl, fbl);
+ EEVEE_materials_init(sldata, vedata, stl, fbl);
/* Refresh Probes
* Shadows needs to be updated for correct probes */
@@ -579,8 +578,7 @@ void EEVEE_render_draw(EEVEE_Data *vedata, RenderEngine *engine, RenderLayer *rl
GPU_framebuffer_bind(fbl->main_fb);
GPU_framebuffer_clear_color_depth_stencil(fbl->main_fb, clear_col, clear_depth, clear_stencil);
/* Depth prepass */
- DRW_draw_pass(psl->depth_pass);
- DRW_draw_pass(psl->depth_pass_cull);
+ DRW_draw_pass(psl->depth_ps);
/* Create minmax texture */
EEVEE_create_minmax_buffer(vedata, dtxl->depth, -1);
EEVEE_occlusion_compute(sldata, vedata, dtxl->depth, -1);
@@ -588,16 +586,15 @@ void EEVEE_render_draw(EEVEE_Data *vedata, RenderEngine *engine, RenderLayer *rl
/* Shading pass */
eevee_render_draw_background(vedata);
GPU_framebuffer_bind(fbl->main_fb);
- EEVEE_materials_draw_opaque(sldata, psl);
+ DRW_draw_pass(psl->material_ps);
EEVEE_subsurface_data_render(sldata, vedata);
/* Effects pre-transparency */
EEVEE_subsurface_compute(sldata, vedata);
EEVEE_reflection_compute(sldata, vedata);
EEVEE_refraction_compute(sldata, vedata);
/* Opaque refraction */
- DRW_draw_pass(psl->refract_depth_pass);
- DRW_draw_pass(psl->refract_depth_pass_cull);
- DRW_draw_pass(psl->refract_pass);
+ DRW_draw_pass(psl->depth_refract_ps);
+ DRW_draw_pass(psl->material_refract_ps);
/* Result NORMAL */
eevee_render_result_normal(rl, viewname, rect, vedata, sldata);
/* Volumetrics Resolve Opaque */
diff --git a/source/blender/draw/engines/eevee/eevee_renderpasses.c b/source/blender/draw/engines/eevee/eevee_renderpasses.c
index 9112e14dcf5..9a47ca19e7b 100644
--- a/source/blender/draw/engines/eevee/eevee_renderpasses.c
+++ b/source/blender/draw/engines/eevee/eevee_renderpasses.c
@@ -201,8 +201,7 @@ void EEVEE_renderpasses_output_init(EEVEE_ViewLayerData *sldata,
grp, "inputSecondLightBuffer", &g_data->renderpass_light_input);
DRW_shgroup_uniform_texture_ref(grp, "depthBuffer", &dtxl->depth);
DRW_shgroup_uniform_block(grp, "common_block", sldata->common_ubo);
- DRW_shgroup_uniform_block(
- grp, "renderpass_block", EEVEE_material_default_render_pass_ubo_get(sldata));
+ DRW_shgroup_uniform_block(grp, "renderpass_block", sldata->renderpass_ubo.combined);
DRW_shgroup_uniform_int(grp, "currentSample", &g_data->renderpass_current_sample, 1);
DRW_shgroup_uniform_int(grp, "renderpassType", &g_data->renderpass_type, 1);
DRW_shgroup_uniform_int(grp, "postProcessType", &g_data->renderpass_postprocess, 1);
@@ -216,7 +215,7 @@ void EEVEE_renderpasses_output_init(EEVEE_ViewLayerData *sldata,
}
}
-/* Postprocess data to construct a specific renderpass
+/* Post-process data to construct a specific render-pass
*
* This method will create a shading group to perform the post-processing for the given
* `renderpass_type`. The post-processing will be done and the result will be stored in the
@@ -224,8 +223,8 @@ void EEVEE_renderpasses_output_init(EEVEE_ViewLayerData *sldata,
*
* Only invoke this function for passes that need post-processing.
*
- * After invoking this function the active framebuffer is set to `vedata->fbl->renderpass_fb`. */
-void EEVEE_renderpasses_postprocess(EEVEE_ViewLayerData *sldata,
+ * After invoking this function the active frame-buffer is set to `vedata->fbl->renderpass_fb`. */
+void EEVEE_renderpasses_postprocess(EEVEE_ViewLayerData *UNUSED(sldata),
EEVEE_Data *vedata,
eViewLayerEEVEEPassType renderpass_type)
{
@@ -276,22 +275,30 @@ void EEVEE_renderpasses_postprocess(EEVEE_ViewLayerData *sldata,
g_data->renderpass_input = txl->shadow_accum;
break;
}
- case EEVEE_RENDER_PASS_DIFFUSE_COLOR:
- case EEVEE_RENDER_PASS_SPECULAR_COLOR:
- case EEVEE_RENDER_PASS_ENVIRONMENT:
+ case EEVEE_RENDER_PASS_DIFFUSE_COLOR: {
+ g_data->renderpass_postprocess = PASS_POST_ACCUMULATED_COLOR;
+ g_data->renderpass_input = txl->diff_color_accum;
+ break;
+ }
+ case EEVEE_RENDER_PASS_SPECULAR_COLOR: {
+ g_data->renderpass_postprocess = PASS_POST_ACCUMULATED_COLOR;
+ g_data->renderpass_input = txl->spec_color_accum;
+ break;
+ }
+ case EEVEE_RENDER_PASS_ENVIRONMENT: {
+ g_data->renderpass_postprocess = PASS_POST_ACCUMULATED_COLOR;
+ g_data->renderpass_input = txl->env_accum;
+ break;
+ }
case EEVEE_RENDER_PASS_EMIT: {
g_data->renderpass_postprocess = PASS_POST_ACCUMULATED_COLOR;
- int renderpass_index = EEVEE_material_output_pass_index_get(sldata, vedata, renderpass_type);
- g_data->renderpass_input = txl->material_accum[renderpass_index];
+ g_data->renderpass_input = txl->emit_accum;
break;
}
case EEVEE_RENDER_PASS_SPECULAR_LIGHT: {
g_data->renderpass_postprocess = PASS_POST_ACCUMULATED_LIGHT;
- int renderpass_index = EEVEE_material_output_pass_index_get(sldata, vedata, renderpass_type);
- int renderpass_index_color = EEVEE_material_output_color_pass_index_get(
- sldata, vedata, renderpass_type);
- g_data->renderpass_input = txl->material_accum[renderpass_index];
- g_data->renderpass_col_input = txl->material_accum[renderpass_index_color];
+ g_data->renderpass_input = txl->spec_light_accum;
+ g_data->renderpass_col_input = txl->spec_color_accum;
if ((stl->effects->enabled_effects & EFFECT_SSR) != 0) {
g_data->renderpass_postprocess = PASS_POST_TWO_LIGHT_BUFFERS;
g_data->renderpass_light_input = txl->ssr_accum;
@@ -303,11 +310,8 @@ void EEVEE_renderpasses_postprocess(EEVEE_ViewLayerData *sldata,
}
case EEVEE_RENDER_PASS_DIFFUSE_LIGHT: {
g_data->renderpass_postprocess = PASS_POST_ACCUMULATED_LIGHT;
- int renderpass_index = EEVEE_material_output_pass_index_get(sldata, vedata, renderpass_type);
- int renderpass_index_color = EEVEE_material_output_color_pass_index_get(
- sldata, vedata, renderpass_type);
- g_data->renderpass_input = txl->material_accum[renderpass_index];
- g_data->renderpass_col_input = txl->material_accum[renderpass_index_color];
+ g_data->renderpass_input = txl->diff_light_accum;
+ g_data->renderpass_col_input = txl->diff_color_accum;
if ((stl->effects->enabled_effects & EFFECT_SSS) != 0) {
g_data->renderpass_postprocess = PASS_POST_TWO_LIGHT_BUFFERS;
g_data->renderpass_light_input = txl->sss_accum;
@@ -343,10 +347,6 @@ void EEVEE_renderpasses_output_accumulate(EEVEE_ViewLayerData *sldata,
if ((render_pass & EEVEE_RENDER_PASS_MIST) != 0) {
EEVEE_mist_output_accumulate(sldata, vedata);
}
- if ((render_pass & EEVEE_RENDER_PASS_DIFFUSE_LIGHT) != 0 &&
- (effects->enabled_effects & EFFECT_SSS) != 0) {
- EEVEE_subsurface_output_accumulate(sldata, vedata);
- }
if ((render_pass & EEVEE_RENDER_PASS_AO) != 0) {
EEVEE_occlusion_output_accumulate(sldata, vedata);
}
diff --git a/source/blender/draw/engines/eevee/eevee_screen_raytrace.c b/source/blender/draw/engines/eevee/eevee_screen_raytrace.c
index 2e467fe8535..cece67334c5 100644
--- a/source/blender/draw/engines/eevee/eevee_screen_raytrace.c
+++ b/source/blender/draw/engines/eevee/eevee_screen_raytrace.c
@@ -237,8 +237,7 @@ void EEVEE_screen_raytrace_cache_init(EEVEE_ViewLayerData *sldata, EEVEE_Data *v
DRW_shgroup_uniform_block(grp, "probe_block", sldata->probe_ubo);
DRW_shgroup_uniform_block(grp, "planar_block", sldata->planar_ubo);
DRW_shgroup_uniform_block(grp, "common_block", sldata->common_ubo);
- DRW_shgroup_uniform_block(
- grp, "renderpass_block", EEVEE_material_default_render_pass_ubo_get(sldata));
+ DRW_shgroup_uniform_block(grp, "renderpass_block", sldata->renderpass_ubo.combined);
if (!effects->reflection_trace_full) {
DRW_shgroup_uniform_ivec2(grp, "halfresOffset", effects->ssr_halfres_ofs, 1);
}
@@ -259,8 +258,7 @@ void EEVEE_screen_raytrace_cache_init(EEVEE_ViewLayerData *sldata, EEVEE_Data *v
DRW_shgroup_uniform_block(grp, "probe_block", sldata->probe_ubo);
DRW_shgroup_uniform_block(grp, "planar_block", sldata->planar_ubo);
DRW_shgroup_uniform_block(grp, "common_block", sldata->common_ubo);
- DRW_shgroup_uniform_block(
- grp, "renderpass_block", EEVEE_material_default_render_pass_ubo_get(sldata));
+ DRW_shgroup_uniform_block(grp, "renderpass_block", sldata->renderpass_ubo.combined);
DRW_shgroup_uniform_int(grp, "neighborOffset", &effects->ssr_neighbor_ofs, 1);
if ((effects->enabled_effects & EFFECT_GTAO) != 0) {
DRW_shgroup_uniform_texture(grp, "utilTex", EEVEE_materials_get_util_tex());
diff --git a/source/blender/draw/engines/eevee/eevee_shaders.c b/source/blender/draw/engines/eevee/eevee_shaders.c
index 50b7c5c5f97..09e74c84948 100644
--- a/source/blender/draw/engines/eevee/eevee_shaders.c
+++ b/source/blender/draw/engines/eevee/eevee_shaders.c
@@ -22,12 +22,20 @@
#include "DRW_render.h"
+#include "BKE_lib_id.h"
+#include "BKE_node.h"
+
+#include "BLI_dynstr.h"
#include "BLI_string_utils.h"
#include "MEM_guardedalloc.h"
+#include "GPU_material.h"
#include "GPU_shader.h"
+#include "NOD_shader.h"
+
+#include "eevee_engine.h"
#include "eevee_private.h"
static const char *filter_defines = "#define HAMMERSLEY_SIZE " STRINGIFY(HAMMERSLEY_SIZE) "\n"
@@ -61,6 +69,38 @@ static struct {
struct GPUShader *taa_resolve_sh;
struct GPUShader *taa_resolve_reproject_sh;
+ /* General purpose Shaders. */
+ struct GPUShader *default_background;
+ struct GPUShader *update_noise_sh;
+
+ /* Shader strings */
+ char *frag_shader_lib;
+ char *vert_shader_str;
+ char *vert_shadow_shader_str;
+ char *vert_background_shader_str;
+ char *vert_volume_shader_str;
+ char *geom_volume_shader_str;
+ char *volume_shader_lib;
+
+ /* LookDev Materials */
+ Material *glossy_mat;
+ Material *diffuse_mat;
+
+ Material *error_mat;
+
+ /* Default Material */
+ struct {
+ bNodeTree *ntree;
+ bNodeSocketValueRGBA *color_socket;
+ bNodeSocketValueFloat *metallic_socket;
+ bNodeSocketValueFloat *roughness_socket;
+ bNodeSocketValueFloat *specular_socket;
+ } surface;
+
+ struct {
+ bNodeTree *ntree;
+ bNodeSocketValueRGBA *color_socket;
+ } world;
} e_data = {NULL}; /* Engine data */
extern char datatoc_bsdf_common_lib_glsl[];
@@ -68,27 +108,42 @@ extern char datatoc_bsdf_sampling_lib_glsl[];
extern char datatoc_common_uniforms_lib_glsl[];
extern char datatoc_common_view_lib_glsl[];
+extern char datatoc_ambient_occlusion_lib_glsl[];
extern char datatoc_background_vert_glsl[];
+extern char datatoc_common_hair_lib_glsl[];
+extern char datatoc_cubemap_lib_glsl[];
extern char datatoc_default_world_frag_glsl[];
-extern char datatoc_lightprobe_geom_glsl[];
-extern char datatoc_lightprobe_vert_glsl[];
+extern char datatoc_irradiance_lib_glsl[];
extern char datatoc_lightprobe_cube_display_frag_glsl[];
extern char datatoc_lightprobe_cube_display_vert_glsl[];
extern char datatoc_lightprobe_filter_diffuse_frag_glsl[];
extern char datatoc_lightprobe_filter_glossy_frag_glsl[];
extern char datatoc_lightprobe_filter_visibility_frag_glsl[];
+extern char datatoc_lightprobe_geom_glsl[];
extern char datatoc_lightprobe_grid_display_frag_glsl[];
extern char datatoc_lightprobe_grid_display_vert_glsl[];
extern char datatoc_lightprobe_grid_fill_frag_glsl[];
+extern char datatoc_lightprobe_lib_glsl[];
extern char datatoc_lightprobe_planar_display_frag_glsl[];
extern char datatoc_lightprobe_planar_display_vert_glsl[];
extern char datatoc_lightprobe_planar_downsample_frag_glsl[];
extern char datatoc_lightprobe_planar_downsample_geom_glsl[];
extern char datatoc_lightprobe_planar_downsample_vert_glsl[];
-extern char datatoc_irradiance_lib_glsl[];
-extern char datatoc_lightprobe_lib_glsl[];
+extern char datatoc_lightprobe_vert_glsl[];
+extern char datatoc_lights_lib_glsl[];
+extern char datatoc_lit_surface_frag_glsl[];
+extern char datatoc_lit_surface_vert_glsl[];
+extern char datatoc_ltc_lib_glsl[];
extern char datatoc_octahedron_lib_glsl[];
-extern char datatoc_cubemap_lib_glsl[];
+extern char datatoc_prepass_frag_glsl[];
+extern char datatoc_raytrace_lib_glsl[];
+extern char datatoc_shadow_vert_glsl[];
+extern char datatoc_ssr_lib_glsl[];
+extern char datatoc_update_noise_frag_glsl[];
+extern char datatoc_volumetric_frag_glsl[];
+extern char datatoc_volumetric_geom_glsl[];
+extern char datatoc_volumetric_lib_glsl[];
+extern char datatoc_volumetric_vert_glsl[];
/* Velocity Resolve */
extern char datatoc_effect_velocity_resolve_frag_glsl[];
@@ -150,6 +205,64 @@ void EEVEE_shaders_lightprobe_shaders_init(void)
NULL);
}
+void EEVEE_shaders_material_shaders_init(void)
+{
+ e_data.frag_shader_lib = BLI_string_joinN(datatoc_common_view_lib_glsl,
+ datatoc_common_uniforms_lib_glsl,
+ datatoc_bsdf_common_lib_glsl,
+ datatoc_bsdf_sampling_lib_glsl,
+ datatoc_ambient_occlusion_lib_glsl,
+ datatoc_raytrace_lib_glsl,
+ datatoc_ssr_lib_glsl,
+ datatoc_octahedron_lib_glsl,
+ datatoc_cubemap_lib_glsl,
+ datatoc_irradiance_lib_glsl,
+ datatoc_lightprobe_lib_glsl,
+ datatoc_ltc_lib_glsl,
+ datatoc_lights_lib_glsl,
+ /* Add one for each Closure */
+ datatoc_lit_surface_frag_glsl,
+ datatoc_lit_surface_frag_glsl,
+ datatoc_lit_surface_frag_glsl,
+ datatoc_lit_surface_frag_glsl,
+ datatoc_lit_surface_frag_glsl,
+ datatoc_lit_surface_frag_glsl,
+ datatoc_lit_surface_frag_glsl,
+ datatoc_lit_surface_frag_glsl,
+ datatoc_lit_surface_frag_glsl,
+ datatoc_lit_surface_frag_glsl,
+ datatoc_lit_surface_frag_glsl,
+ datatoc_volumetric_lib_glsl);
+
+ e_data.volume_shader_lib = BLI_string_joinN(datatoc_common_view_lib_glsl,
+ datatoc_common_uniforms_lib_glsl,
+ datatoc_bsdf_common_lib_glsl,
+ datatoc_ambient_occlusion_lib_glsl,
+ datatoc_octahedron_lib_glsl,
+ datatoc_cubemap_lib_glsl,
+ datatoc_irradiance_lib_glsl,
+ datatoc_lightprobe_lib_glsl,
+ datatoc_ltc_lib_glsl,
+ datatoc_lights_lib_glsl,
+ datatoc_volumetric_lib_glsl,
+ datatoc_volumetric_frag_glsl);
+
+ e_data.vert_shader_str = BLI_string_joinN(
+ datatoc_common_view_lib_glsl, datatoc_common_hair_lib_glsl, datatoc_lit_surface_vert_glsl);
+
+ e_data.vert_shadow_shader_str = BLI_string_joinN(
+ datatoc_common_view_lib_glsl, datatoc_common_hair_lib_glsl, datatoc_shadow_vert_glsl);
+
+ e_data.vert_background_shader_str = BLI_string_joinN(datatoc_common_view_lib_glsl,
+ datatoc_background_vert_glsl);
+
+ e_data.vert_volume_shader_str = BLI_string_joinN(datatoc_common_view_lib_glsl,
+ datatoc_volumetric_vert_glsl);
+
+ e_data.geom_volume_shader_str = BLI_string_joinN(datatoc_common_view_lib_glsl,
+ datatoc_volumetric_geom_glsl);
+}
+
GPUShader *EEVEE_shaders_probe_filter_glossy_sh_get(void)
{
return e_data.probe_filter_glossy_sh;
@@ -292,6 +405,26 @@ GPUShader *EEVEE_shaders_velocity_resolve_sh_get(void)
return e_data.velocity_resolve_sh;
}
+GPUShader *EEVEE_shaders_default_background_sh_get(void)
+{
+ if (e_data.default_background == NULL) {
+ e_data.default_background = DRW_shader_create_with_lib(datatoc_background_vert_glsl,
+ NULL,
+ datatoc_default_world_frag_glsl,
+ datatoc_common_view_lib_glsl,
+ NULL);
+ }
+ return e_data.default_background;
+}
+
+GPUShader *EEVEE_shaders_update_noise_sh_get(void)
+{
+ if (e_data.update_noise_sh == NULL) {
+ e_data.update_noise_sh = DRW_shader_create_fullscreen(datatoc_update_noise_frag_glsl, NULL);
+ }
+ return e_data.update_noise_sh;
+}
+
GPUShader *EEVEE_shaders_taa_resolve_sh_get(EEVEE_EffectsFlag enabled_effects)
{
GPUShader **sh;
@@ -316,8 +449,330 @@ GPUShader *EEVEE_shaders_taa_resolve_sh_get(EEVEE_EffectsFlag enabled_effects)
return *sh;
}
+Material *EEVEE_material_default_diffuse_get(void)
+{
+ if (!e_data.diffuse_mat) {
+ Material *ma = BKE_id_new_nomain(ID_MA, "EEVEEE default diffuse");
+
+ bNodeTree *ntree = ntreeAddTree(NULL, "Shader Nodetree", ntreeType_Shader->idname);
+ ma->nodetree = ntree;
+ ma->use_nodes = true;
+
+ bNode *bsdf = nodeAddStaticNode(NULL, ntree, SH_NODE_BSDF_DIFFUSE);
+ bNodeSocket *base_color = nodeFindSocket(bsdf, SOCK_IN, "Color");
+ copy_v3_fl(((bNodeSocketValueRGBA *)base_color->default_value)->value, 0.8f);
+
+ bNode *output = nodeAddStaticNode(NULL, ntree, SH_NODE_OUTPUT_MATERIAL);
+
+ nodeAddLink(ntree,
+ bsdf,
+ nodeFindSocket(bsdf, SOCK_OUT, "BSDF"),
+ output,
+ nodeFindSocket(output, SOCK_IN, "Surface"));
+
+ nodeSetActive(ntree, output);
+ e_data.diffuse_mat = ma;
+ }
+ return e_data.diffuse_mat;
+}
+
+Material *EEVEE_material_default_glossy_get(void)
+{
+ if (!e_data.glossy_mat) {
+ Material *ma = BKE_id_new_nomain(ID_MA, "EEVEEE default metal");
+
+ bNodeTree *ntree = ntreeAddTree(NULL, "Shader Nodetree", ntreeType_Shader->idname);
+ ma->nodetree = ntree;
+ ma->use_nodes = true;
+
+ bNode *bsdf = nodeAddStaticNode(NULL, ntree, SH_NODE_BSDF_GLOSSY);
+ bNodeSocket *base_color = nodeFindSocket(bsdf, SOCK_IN, "Color");
+ copy_v3_fl(((bNodeSocketValueRGBA *)base_color->default_value)->value, 1.0f);
+ bNodeSocket *roughness = nodeFindSocket(bsdf, SOCK_IN, "Roughness");
+ ((bNodeSocketValueFloat *)roughness->default_value)->value = 0.0f;
+
+ bNode *output = nodeAddStaticNode(NULL, ntree, SH_NODE_OUTPUT_MATERIAL);
+
+ nodeAddLink(ntree,
+ bsdf,
+ nodeFindSocket(bsdf, SOCK_OUT, "BSDF"),
+ output,
+ nodeFindSocket(output, SOCK_IN, "Surface"));
+
+ nodeSetActive(ntree, output);
+ e_data.glossy_mat = ma;
+ }
+ return e_data.glossy_mat;
+}
+
+Material *EEVEE_material_default_error_get(void)
+{
+ if (!e_data.error_mat) {
+ Material *ma = BKE_id_new_nomain(ID_MA, "EEVEEE default metal");
+
+ bNodeTree *ntree = ntreeAddTree(NULL, "Shader Nodetree", ntreeType_Shader->idname);
+ ma->nodetree = ntree;
+ ma->use_nodes = true;
+
+ /* Use emission and output material to be compatible with both World and Material. */
+ bNode *bsdf = nodeAddStaticNode(NULL, ntree, SH_NODE_EMISSION);
+ bNodeSocket *color = nodeFindSocket(bsdf, SOCK_IN, "Color");
+ copy_v3_fl3(((bNodeSocketValueRGBA *)color->default_value)->value, 1.0f, 0.0f, 1.0f);
+
+ bNode *output = nodeAddStaticNode(NULL, ntree, SH_NODE_OUTPUT_MATERIAL);
+
+ nodeAddLink(ntree,
+ bsdf,
+ nodeFindSocket(bsdf, SOCK_OUT, "Emission"),
+ output,
+ nodeFindSocket(output, SOCK_IN, "Surface"));
+
+ nodeSetActive(ntree, output);
+ e_data.error_mat = ma;
+ }
+ return e_data.error_mat;
+}
+
+/* Configure a default nodetree with the given material. */
+struct bNodeTree *EEVEE_shader_default_surface_nodetree(Material *ma)
+{
+ /* WARNING: This function is not threadsafe. Which is not a problem for the moment. */
+ if (!e_data.surface.ntree) {
+ bNodeTree *ntree = ntreeAddTree(NULL, "Shader Nodetree", ntreeType_Shader->idname);
+ bNode *bsdf = nodeAddStaticNode(NULL, ntree, SH_NODE_BSDF_PRINCIPLED);
+ bNode *output = nodeAddStaticNode(NULL, ntree, SH_NODE_OUTPUT_MATERIAL);
+ bNodeSocket *bsdf_out = nodeFindSocket(bsdf, SOCK_OUT, "BSDF");
+ bNodeSocket *output_in = nodeFindSocket(output, SOCK_IN, "Surface");
+ nodeAddLink(ntree, bsdf, bsdf_out, output, output_in);
+ nodeSetActive(ntree, output);
+
+ e_data.surface.color_socket = nodeFindSocket(bsdf, SOCK_IN, "Base Color")->default_value;
+ e_data.surface.metallic_socket = nodeFindSocket(bsdf, SOCK_IN, "Metallic")->default_value;
+ e_data.surface.roughness_socket = nodeFindSocket(bsdf, SOCK_IN, "Roughness")->default_value;
+ e_data.surface.specular_socket = nodeFindSocket(bsdf, SOCK_IN, "Specular")->default_value;
+ e_data.surface.ntree = ntree;
+ }
+ /* Update */
+ copy_v3_fl3(e_data.surface.color_socket->value, ma->r, ma->g, ma->b);
+ e_data.surface.metallic_socket->value = ma->metallic;
+ e_data.surface.roughness_socket->value = ma->roughness;
+ e_data.surface.specular_socket->value = ma->spec;
+
+ return e_data.surface.ntree;
+}
+
+/* Configure a default nodetree with the given world. */
+struct bNodeTree *EEVEE_shader_default_world_nodetree(World *wo)
+{
+ /* WARNING: This function is not threadsafe. Which is not a problem for the moment. */
+ if (!e_data.world.ntree) {
+ bNodeTree *ntree = ntreeAddTree(NULL, "Shader Nodetree", ntreeType_Shader->idname);
+ bNode *bg = nodeAddStaticNode(NULL, ntree, SH_NODE_BACKGROUND);
+ bNode *output = nodeAddStaticNode(NULL, ntree, SH_NODE_OUTPUT_WORLD);
+ bNodeSocket *bg_out = nodeFindSocket(bg, SOCK_OUT, "Background");
+ bNodeSocket *output_in = nodeFindSocket(output, SOCK_IN, "Surface");
+ nodeAddLink(ntree, bg, bg_out, output, output_in);
+ nodeSetActive(ntree, output);
+
+ e_data.world.color_socket = nodeFindSocket(bg, SOCK_IN, "Color")->default_value;
+ e_data.world.ntree = ntree;
+ }
+
+ copy_v3_fl3(e_data.world.color_socket->value, wo->horr, wo->horg, wo->horb);
+
+ return e_data.world.ntree;
+}
+
+static char *eevee_get_defines(int options)
+{
+ char *str = NULL;
+
+ DynStr *ds = BLI_dynstr_new();
+ BLI_dynstr_append(ds, SHADER_DEFINES);
+
+ if ((options & VAR_WORLD_BACKGROUND) != 0) {
+ BLI_dynstr_append(ds, "#define WORLD_BACKGROUND\n");
+ }
+ if ((options & VAR_MAT_VOLUME) != 0) {
+ BLI_dynstr_append(ds, "#define VOLUMETRICS\n");
+ }
+ if ((options & VAR_MAT_MESH) != 0) {
+ BLI_dynstr_append(ds, "#define MESH_SHADER\n");
+ }
+ if ((options & VAR_MAT_DEPTH) != 0) {
+ BLI_dynstr_append(ds, "#define DEPTH_SHADER\n");
+ }
+ if ((options & VAR_MAT_HAIR) != 0) {
+ BLI_dynstr_append(ds, "#define HAIR_SHADER\n");
+ }
+ if ((options & (VAR_MAT_PROBE | VAR_WORLD_PROBE)) != 0) {
+ BLI_dynstr_append(ds, "#define PROBE_CAPTURE\n");
+ }
+ if ((options & VAR_MAT_HASH) != 0) {
+ BLI_dynstr_append(ds, "#define USE_ALPHA_HASH\n");
+ }
+ if ((options & VAR_MAT_BLEND) != 0) {
+ BLI_dynstr_append(ds, "#define USE_ALPHA_BLEND\n");
+ }
+ if ((options & VAR_MAT_REFRACT) != 0) {
+ BLI_dynstr_append(ds, "#define USE_REFRACTION\n");
+ }
+ if ((options & VAR_MAT_LOOKDEV) != 0) {
+ BLI_dynstr_append(ds, "#define LOOKDEV\n");
+ }
+ if ((options & VAR_MAT_HOLDOUT) != 0) {
+ BLI_dynstr_append(ds, "#define HOLDOUT\n");
+ }
+
+ str = BLI_dynstr_get_cstring(ds);
+ BLI_dynstr_free(ds);
+
+ return str;
+}
+
+static char *eevee_get_vert(int options)
+{
+ char *str = NULL;
+
+ if ((options & VAR_MAT_VOLUME) != 0) {
+ str = BLI_strdup(e_data.vert_volume_shader_str);
+ }
+ else if ((options & (VAR_WORLD_PROBE | VAR_WORLD_BACKGROUND)) != 0) {
+ str = BLI_strdup(e_data.vert_background_shader_str);
+ }
+ else {
+ str = BLI_strdup(e_data.vert_shader_str);
+ }
+
+ return str;
+}
+
+static char *eevee_get_geom(int options)
+{
+ char *str = NULL;
+
+ if ((options & VAR_MAT_VOLUME) != 0) {
+ str = BLI_strdup(e_data.geom_volume_shader_str);
+ }
+
+ return str;
+}
+
+static char *eevee_get_frag(int options)
+{
+ char *str = NULL;
+
+ if ((options & VAR_MAT_VOLUME) != 0) {
+ str = BLI_strdup(e_data.volume_shader_lib);
+ }
+ else if ((options & VAR_MAT_DEPTH) != 0) {
+ str = BLI_string_joinN(e_data.frag_shader_lib, datatoc_prepass_frag_glsl);
+ }
+ else {
+ str = BLI_strdup(e_data.frag_shader_lib);
+ }
+
+ return str;
+}
+
+static struct GPUMaterial *eevee_material_get_ex(
+ struct Scene *scene, Material *ma, World *wo, int options, bool deferred)
+{
+ BLI_assert(ma || wo);
+ const bool is_volume = (options & VAR_MAT_VOLUME) != 0;
+ const bool is_default = (options & VAR_DEFAULT) != 0;
+ const void *engine = &DRW_engine_viewport_eevee_type;
+
+ GPUMaterial *mat = NULL;
+
+ if (ma) {
+ mat = DRW_shader_find_from_material(ma, engine, options, deferred);
+ }
+ else {
+ mat = DRW_shader_find_from_world(wo, engine, options, deferred);
+ }
+
+ if (mat) {
+ return mat;
+ }
+
+ char *defines = eevee_get_defines(options);
+ char *vert = eevee_get_vert(options);
+ char *geom = eevee_get_geom(options);
+ char *frag = eevee_get_frag(options);
+
+ if (ma) {
+ bNodeTree *ntree = !is_default ? ma->nodetree : EEVEE_shader_default_surface_nodetree(ma);
+ mat = DRW_shader_create_from_material(
+ scene, ma, ntree, engine, options, is_volume, vert, geom, frag, defines, deferred);
+ }
+ else {
+ bNodeTree *ntree = !is_default ? wo->nodetree : EEVEE_shader_default_world_nodetree(wo);
+ mat = DRW_shader_create_from_world(
+ scene, wo, ntree, engine, options, is_volume, vert, geom, frag, defines, deferred);
+ }
+
+ MEM_SAFE_FREE(defines);
+ MEM_SAFE_FREE(vert);
+ MEM_SAFE_FREE(geom);
+ MEM_SAFE_FREE(frag);
+
+ return mat;
+}
+
+/* Note: Compilation is not deferred. */
+struct GPUMaterial *EEVEE_material_default_get(struct Scene *scene, Material *ma, int options)
+{
+ Material *def_ma = (ma && (options & VAR_MAT_VOLUME)) ? BKE_material_default_volume() :
+ BKE_material_default_surface();
+ BLI_assert(def_ma->use_nodes && def_ma->nodetree);
+
+ return eevee_material_get_ex(scene, def_ma, NULL, options, false);
+}
+
+struct GPUMaterial *EEVEE_material_get(
+ EEVEE_Data *vedata, struct Scene *scene, Material *ma, World *wo, int options)
+{
+ if ((ma && (!ma->use_nodes || !ma->nodetree)) || (wo && (!wo->use_nodes || !wo->nodetree))) {
+ options |= VAR_DEFAULT;
+ }
+
+ /* Meh, implicit option. World probe cannot be deferred because they need
+ * to be rendered immediately. */
+ const bool deferred = (options & VAR_WORLD_PROBE) == 0;
+
+ GPUMaterial *mat = eevee_material_get_ex(scene, ma, wo, options, deferred);
+
+ int status = GPU_material_status(mat);
+ switch (status) {
+ case GPU_MAT_SUCCESS:
+ break;
+ case GPU_MAT_QUEUED:
+ vedata->stl->g_data->queued_shaders_count++;
+ mat = EEVEE_material_default_get(scene, ma, options);
+ break;
+ case GPU_MAT_FAILED:
+ default:
+ ma = EEVEE_material_default_error_get();
+ mat = eevee_material_get_ex(scene, ma, NULL, options, false);
+ break;
+ }
+ /* Returned material should be ready to be drawn. */
+ BLI_assert(GPU_material_status(mat) == GPU_MAT_SUCCESS);
+ return mat;
+}
+
void EEVEE_shaders_free(void)
{
+ MEM_SAFE_FREE(e_data.frag_shader_lib);
+ MEM_SAFE_FREE(e_data.vert_shader_str);
+ MEM_SAFE_FREE(e_data.vert_shadow_shader_str);
+ MEM_SAFE_FREE(e_data.vert_background_shader_str);
+ MEM_SAFE_FREE(e_data.vert_volume_shader_str);
+ MEM_SAFE_FREE(e_data.geom_volume_shader_str);
+ MEM_SAFE_FREE(e_data.volume_shader_lib);
+ DRW_SHADER_FREE_SAFE(e_data.default_background);
+ DRW_SHADER_FREE_SAFE(e_data.update_noise_sh);
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);
@@ -332,4 +787,27 @@ void EEVEE_shaders_free(void)
DRW_SHADER_FREE_SAFE(e_data.velocity_resolve_sh);
DRW_SHADER_FREE_SAFE(e_data.taa_resolve_sh);
DRW_SHADER_FREE_SAFE(e_data.taa_resolve_reproject_sh);
+
+ if (e_data.glossy_mat) {
+ BKE_id_free(NULL, e_data.glossy_mat);
+ e_data.glossy_mat = NULL;
+ }
+ if (e_data.diffuse_mat) {
+ BKE_id_free(NULL, e_data.diffuse_mat);
+ e_data.diffuse_mat = NULL;
+ }
+ if (e_data.error_mat) {
+ BKE_id_free(NULL, e_data.error_mat);
+ e_data.error_mat = NULL;
+ }
+ if (e_data.surface.ntree) {
+ ntreeFreeEmbeddedTree(e_data.surface.ntree);
+ MEM_freeN(e_data.surface.ntree);
+ e_data.surface.ntree = NULL;
+ }
+ if (e_data.world.ntree) {
+ ntreeFreeEmbeddedTree(e_data.world.ntree);
+ MEM_freeN(e_data.world.ntree);
+ e_data.world.ntree = NULL;
+ }
}
diff --git a/source/blender/draw/engines/eevee/eevee_shadows.c b/source/blender/draw/engines/eevee/eevee_shadows.c
index fb338d85fde..84c50a22ae6 100644
--- a/source/blender/draw/engines/eevee/eevee_shadows.c
+++ b/source/blender/draw/engines/eevee/eevee_shadows.c
@@ -159,47 +159,6 @@ void EEVEE_shadows_cache_init(EEVEE_ViewLayerData *sldata, EEVEE_Data *vedata)
}
}
-/* Add a shadow caster to the shadowpasses */
-void EEVEE_shadows_caster_add(EEVEE_ViewLayerData *UNUSED(sldata),
- EEVEE_StorageList *stl,
- struct GPUBatch *geom,
- Object *ob)
-{
- DRW_shgroup_call(stl->g_data->shadow_shgrp, geom, ob);
-}
-
-void EEVEE_shadows_caster_material_add(EEVEE_ViewLayerData *sldata,
- EEVEE_PassList *psl,
- struct GPUMaterial *gpumat,
- struct GPUBatch *geom,
- struct Object *ob,
- const float *alpha_threshold)
-{
- /* TODO / PERF : reuse the same shading group for objects with the same material */
- DRWShadingGroup *grp = DRW_shgroup_material_create(gpumat, psl->shadow_pass);
-
- if (grp == NULL) {
- return;
- }
-
- /* Unfortunately needed for correctness but not 99% of the time not needed.
- * TODO detect when needed? */
- DRW_shgroup_uniform_block(grp, "probe_block", sldata->probe_ubo);
- DRW_shgroup_uniform_block(grp, "grid_block", sldata->grid_ubo);
- DRW_shgroup_uniform_block(grp, "planar_block", sldata->planar_ubo);
- DRW_shgroup_uniform_block(grp, "light_block", sldata->light_ubo);
- DRW_shgroup_uniform_block(grp, "shadow_block", sldata->shadow_ubo);
- DRW_shgroup_uniform_block(
- grp, "renderpass_block", EEVEE_material_default_render_pass_ubo_get(sldata));
- DRW_shgroup_uniform_block(grp, "common_block", sldata->common_ubo);
-
- if (alpha_threshold != NULL) {
- DRW_shgroup_uniform_float(grp, "alphaThreshold", alpha_threshold, 1);
- }
-
- DRW_shgroup_call(grp, geom, ob);
-}
-
/* Make that object update shadow casting lights inside its influence bounding box. */
void EEVEE_shadows_caster_register(EEVEE_ViewLayerData *sldata, Object *ob)
{
@@ -470,8 +429,7 @@ void EEVEE_shadow_output_init(EEVEE_ViewLayerData *sldata,
DRW_shgroup_uniform_block(grp, "light_block", sldata->light_ubo);
DRW_shgroup_uniform_block(grp, "shadow_block", sldata->shadow_ubo);
DRW_shgroup_uniform_block(grp, "common_block", sldata->common_ubo);
- DRW_shgroup_uniform_block(
- grp, "renderpass_block", EEVEE_material_default_render_pass_ubo_get(sldata));
+ DRW_shgroup_uniform_block(grp, "renderpass_block", sldata->renderpass_ubo.combined);
DRW_shgroup_uniform_texture_ref(grp, "shadowCubeTexture", &sldata->shadow_cube_pool);
DRW_shgroup_uniform_texture_ref(grp, "shadowCascadeTexture", &sldata->shadow_cascade_pool);
diff --git a/source/blender/draw/engines/eevee/eevee_subsurface.c b/source/blender/draw/engines/eevee/eevee_subsurface.c
index 3f4008eb8b9..7674148f76a 100644
--- a/source/blender/draw/engines/eevee/eevee_subsurface.c
+++ b/source/blender/draw/engines/eevee/eevee_subsurface.c
@@ -29,7 +29,9 @@
#include "DEG_depsgraph_query.h"
#include "GPU_extensions.h"
+#include "GPU_material.h"
#include "GPU_texture.h"
+
#include "eevee_private.h"
static struct {
@@ -83,6 +85,7 @@ void EEVEE_subsurface_init(EEVEE_ViewLayerData *sldata, EEVEE_Data *vedata)
const Scene *scene_eval = DEG_get_evaluated_scene(draw_ctx->depsgraph);
effects->sss_sample_count = 1 + scene_eval->eevee.sss_samples * 2;
+ effects->sss_surface_count = 0;
common_data->sss_jitter_threshold = scene_eval->eevee.sss_jitter_threshold;
}
@@ -145,7 +148,7 @@ void EEVEE_subsurface_draw_init(EEVEE_ViewLayerData *sldata, EEVEE_Data *vedata)
}
else {
GPU_FRAMEBUFFER_FREE_SAFE(fbl->sss_accum_fb);
- txl->sss_accum = NULL;
+ DRW_TEXTURE_FREE_SAFE(txl->sss_accum);
}
}
else {
@@ -154,11 +157,11 @@ void EEVEE_subsurface_draw_init(EEVEE_ViewLayerData *sldata, EEVEE_Data *vedata)
GPU_FRAMEBUFFER_FREE_SAFE(fbl->sss_resolve_fb);
GPU_FRAMEBUFFER_FREE_SAFE(fbl->sss_clear_fb);
GPU_FRAMEBUFFER_FREE_SAFE(fbl->sss_accum_fb);
+ DRW_TEXTURE_FREE_SAFE(txl->sss_accum);
effects->sss_stencil = NULL;
effects->sss_blur = NULL;
effects->sss_irradiance = NULL;
effects->sss_radius = NULL;
- txl->sss_accum = NULL;
}
}
@@ -221,70 +224,77 @@ void EEVEE_subsurface_cache_init(EEVEE_ViewLayerData *UNUSED(sldata), EEVEE_Data
void EEVEE_subsurface_add_pass(EEVEE_ViewLayerData *sldata,
EEVEE_Data *vedata,
- uint sss_id,
- struct GPUUniformBuffer *sss_profile)
+ Material *ma,
+ DRWShadingGroup *shgrp,
+ struct GPUMaterial *gpumat)
{
- DefaultTextureList *dtxl = DRW_viewport_texture_list_get();
EEVEE_PassList *psl = vedata->psl;
EEVEE_StorageList *stl = vedata->stl;
EEVEE_EffectsInfo *effects = stl->effects;
- struct GPUBatch *quad = DRW_cache_fullscreen_quad_get();
+ DefaultTextureList *dtxl = DRW_viewport_texture_list_get();
GPUTexture **depth_src = GPU_depth_blitting_workaround() ? &effects->sss_stencil : &dtxl->depth;
- DRWShadingGroup *grp = DRW_shgroup_create(e_data.sss_sh[0], psl->sss_blur_ps);
- DRW_shgroup_uniform_texture(grp, "utilTex", EEVEE_materials_get_util_tex());
- DRW_shgroup_uniform_texture_ref(grp, "depthBuffer", depth_src);
- DRW_shgroup_uniform_texture_ref(grp, "sssIrradiance", &effects->sss_irradiance);
- DRW_shgroup_uniform_texture_ref(grp, "sssRadius", &effects->sss_radius);
- DRW_shgroup_uniform_block(grp, "sssProfile", sss_profile);
- DRW_shgroup_uniform_block(grp, "common_block", sldata->common_ubo);
- DRW_shgroup_uniform_block(
- grp, "renderpass_block", EEVEE_material_default_render_pass_ubo_get(sldata));
- DRW_shgroup_stencil_mask(grp, sss_id);
- DRW_shgroup_call(grp, quad, NULL);
-
- grp = DRW_shgroup_create(e_data.sss_sh[1], psl->sss_resolve_ps);
- DRW_shgroup_uniform_texture(grp, "utilTex", EEVEE_materials_get_util_tex());
- DRW_shgroup_uniform_texture_ref(grp, "depthBuffer", depth_src);
- DRW_shgroup_uniform_texture_ref(grp, "sssIrradiance", &effects->sss_blur);
- DRW_shgroup_uniform_texture_ref(grp, "sssAlbedo", &effects->sss_albedo);
- DRW_shgroup_uniform_texture_ref(grp, "sssRadius", &effects->sss_radius);
- DRW_shgroup_uniform_block(grp, "sssProfile", sss_profile);
- DRW_shgroup_uniform_block(grp, "common_block", sldata->common_ubo);
- DRW_shgroup_uniform_block(
- grp, "renderpass_block", EEVEE_material_default_render_pass_ubo_get(sldata));
- DRW_shgroup_stencil_mask(grp, sss_id);
- DRW_shgroup_call(grp, quad, NULL);
-}
+ struct GPUTexture *sss_tex_profile = NULL;
+ struct GPUUniformBuffer *sss_profile = GPU_material_sss_profile_get(
+ gpumat, stl->effects->sss_sample_count, &sss_tex_profile);
-void EEVEE_subsurface_translucency_add_pass(EEVEE_ViewLayerData *sldata,
- EEVEE_Data *vedata,
- uint sss_id,
- struct GPUUniformBuffer *sss_profile,
- GPUTexture *sss_tex_profile)
-{
- DefaultTextureList *dtxl = DRW_viewport_texture_list_get();
- EEVEE_PassList *psl = vedata->psl;
- EEVEE_StorageList *stl = vedata->stl;
- EEVEE_EffectsInfo *effects = stl->effects;
- struct GPUBatch *quad = DRW_cache_fullscreen_quad_get();
- GPUTexture **depth_src = GPU_depth_blitting_workaround() ? &effects->sss_stencil : &dtxl->depth;
+ if (!sss_profile) {
+ BLI_assert(0 && "SSS pass requested but no SSS data was found");
+ return;
+ }
+
+ /* Limit of 8 bit stencil buffer. ID 255 is refraction. */
+ if (effects->sss_surface_count >= 254) {
+ /* TODO : display message. */
+ printf("Error: Too many different Subsurface shader in the scene.\n");
+ return;
+ }
+
+ int sss_id = ++(effects->sss_surface_count);
+ /* Make main pass output stencil mask. */
+ DRW_shgroup_stencil_mask(shgrp, sss_id);
+
+ {
+ DRWShadingGroup *grp = DRW_shgroup_create(e_data.sss_sh[0], psl->sss_blur_ps);
+ DRW_shgroup_uniform_texture(grp, "utilTex", EEVEE_materials_get_util_tex());
+ DRW_shgroup_uniform_texture_ref(grp, "depthBuffer", depth_src);
+ DRW_shgroup_uniform_texture_ref(grp, "sssIrradiance", &effects->sss_irradiance);
+ DRW_shgroup_uniform_texture_ref(grp, "sssRadius", &effects->sss_radius);
+ DRW_shgroup_uniform_block(grp, "sssProfile", sss_profile);
+ DRW_shgroup_uniform_block(grp, "common_block", sldata->common_ubo);
+ DRW_shgroup_uniform_block(grp, "renderpass_block", sldata->renderpass_ubo.combined);
+ DRW_shgroup_stencil_mask(grp, sss_id);
+ DRW_shgroup_call_procedural_triangles(grp, NULL, 1);
+
+ grp = DRW_shgroup_create(e_data.sss_sh[1], psl->sss_resolve_ps);
+ DRW_shgroup_uniform_texture(grp, "utilTex", EEVEE_materials_get_util_tex());
+ DRW_shgroup_uniform_texture_ref(grp, "depthBuffer", depth_src);
+ DRW_shgroup_uniform_texture_ref(grp, "sssIrradiance", &effects->sss_blur);
+ DRW_shgroup_uniform_texture_ref(grp, "sssAlbedo", &effects->sss_albedo);
+ DRW_shgroup_uniform_texture_ref(grp, "sssRadius", &effects->sss_radius);
+ DRW_shgroup_uniform_block(grp, "sssProfile", sss_profile);
+ DRW_shgroup_uniform_block(grp, "common_block", sldata->common_ubo);
+ DRW_shgroup_uniform_block(grp, "renderpass_block", sldata->renderpass_ubo.combined);
+ DRW_shgroup_stencil_mask(grp, sss_id);
+ DRW_shgroup_call_procedural_triangles(grp, NULL, 1);
+ }
- DRWShadingGroup *grp = DRW_shgroup_create(e_data.sss_sh[2], psl->sss_translucency_ps);
- DRW_shgroup_uniform_texture(grp, "utilTex", EEVEE_materials_get_util_tex());
- DRW_shgroup_uniform_texture(grp, "sssTexProfile", sss_tex_profile);
- DRW_shgroup_uniform_texture_ref(grp, "depthBuffer", depth_src);
- DRW_shgroup_uniform_texture_ref(grp, "sssRadius", &effects->sss_radius);
- DRW_shgroup_uniform_texture_ref(grp, "sssShadowCubes", &sldata->shadow_cube_pool);
- DRW_shgroup_uniform_texture_ref(grp, "sssShadowCascades", &sldata->shadow_cascade_pool);
- DRW_shgroup_uniform_block(grp, "sssProfile", sss_profile);
- DRW_shgroup_uniform_block(grp, "light_block", sldata->light_ubo);
- DRW_shgroup_uniform_block(grp, "shadow_block", sldata->shadow_ubo);
- DRW_shgroup_uniform_block(grp, "common_block", sldata->common_ubo);
- DRW_shgroup_uniform_block(
- grp, "renderpass_block", EEVEE_material_default_render_pass_ubo_get(sldata));
- DRW_shgroup_stencil_mask(grp, sss_id);
- DRW_shgroup_call(grp, quad, NULL);
+ if (ma->blend_flag & MA_BL_TRANSLUCENCY) {
+ DRWShadingGroup *grp = DRW_shgroup_create(e_data.sss_sh[2], psl->sss_translucency_ps);
+ DRW_shgroup_uniform_texture(grp, "utilTex", EEVEE_materials_get_util_tex());
+ DRW_shgroup_uniform_texture(grp, "sssTexProfile", sss_tex_profile);
+ DRW_shgroup_uniform_texture_ref(grp, "depthBuffer", depth_src);
+ DRW_shgroup_uniform_texture_ref(grp, "sssRadius", &effects->sss_radius);
+ DRW_shgroup_uniform_texture_ref(grp, "sssShadowCubes", &sldata->shadow_cube_pool);
+ DRW_shgroup_uniform_texture_ref(grp, "sssShadowCascades", &sldata->shadow_cascade_pool);
+ DRW_shgroup_uniform_block(grp, "sssProfile", sss_profile);
+ DRW_shgroup_uniform_block(grp, "light_block", sldata->light_ubo);
+ DRW_shgroup_uniform_block(grp, "shadow_block", sldata->shadow_ubo);
+ DRW_shgroup_uniform_block(grp, "common_block", sldata->common_ubo);
+ DRW_shgroup_uniform_block(grp, "renderpass_block", sldata->renderpass_ubo.combined);
+ DRW_shgroup_stencil_mask(grp, sss_id);
+ DRW_shgroup_call_procedural_triangles(grp, NULL, 1);
+ }
}
void EEVEE_subsurface_data_render(EEVEE_ViewLayerData *UNUSED(sldata), EEVEE_Data *vedata)
@@ -310,8 +320,7 @@ void EEVEE_subsurface_data_render(EEVEE_ViewLayerData *UNUSED(sldata), EEVEE_Dat
GPU_ATTACHMENT_TEXTURE(effects->sss_albedo)});
GPU_framebuffer_bind(fbl->main_fb);
- DRW_draw_pass(psl->sss_pass);
- DRW_draw_pass(psl->sss_pass_cull);
+ DRW_draw_pass(psl->material_sss_ps);
/* Restore */
GPU_framebuffer_ensure_config(&fbl->main_fb,
@@ -350,23 +359,15 @@ void EEVEE_subsurface_compute(EEVEE_ViewLayerData *sldata, EEVEE_Data *vedata)
if (!DRW_pass_is_empty(psl->sss_translucency_ps)) {
/* We sample the shadow-maps using normal sampler. We need to disable Comparison mode.
* TODO(fclem) avoid this by using sampler objects.*/
- GPU_texture_bind(sldata->shadow_cube_pool, 0);
GPU_texture_compare_mode(sldata->shadow_cube_pool, false);
- GPU_texture_unbind(sldata->shadow_cube_pool);
- GPU_texture_bind(sldata->shadow_cascade_pool, 0);
GPU_texture_compare_mode(sldata->shadow_cascade_pool, false);
- GPU_texture_unbind(sldata->shadow_cascade_pool);
GPU_framebuffer_bind(fbl->sss_translucency_fb);
DRW_draw_pass(psl->sss_translucency_ps);
/* Reset original state. */
- GPU_texture_bind(sldata->shadow_cube_pool, 0);
GPU_texture_compare_mode(sldata->shadow_cube_pool, true);
- GPU_texture_unbind(sldata->shadow_cube_pool);
- GPU_texture_bind(sldata->shadow_cascade_pool, 0);
GPU_texture_compare_mode(sldata->shadow_cascade_pool, true);
- GPU_texture_unbind(sldata->shadow_cascade_pool);
}
/* 1. horizontal pass */
diff --git a/source/blender/draw/engines/eevee/eevee_temporal_sampling.c b/source/blender/draw/engines/eevee/eevee_temporal_sampling.c
index 1f44b815a42..d57048f2c4e 100644
--- a/source/blender/draw/engines/eevee/eevee_temporal_sampling.c
+++ b/source/blender/draw/engines/eevee/eevee_temporal_sampling.c
@@ -244,8 +244,10 @@ int EEVEE_temporal_sampling_init(EEVEE_ViewLayerData *UNUSED(sldata), EEVEE_Data
copy_m4_m4(effects->prev_drw_persmat, persmat);
/* Prevent ghosting from probe data. */
- view_is_valid = view_is_valid && (effects->prev_drw_support == DRW_state_draw_support());
+ view_is_valid = view_is_valid && (effects->prev_drw_support == DRW_state_draw_support()) &&
+ (effects->prev_is_navigating == DRW_state_is_navigating());
effects->prev_drw_support = DRW_state_draw_support();
+ effects->prev_is_navigating = DRW_state_is_navigating();
if (((effects->taa_total_sample == 0) ||
(effects->taa_current_sample < effects->taa_total_sample)) ||
@@ -290,8 +292,7 @@ void EEVEE_temporal_sampling_cache_init(EEVEE_ViewLayerData *sldata, EEVEE_Data
DRW_shgroup_uniform_texture_ref(grp, "colorHistoryBuffer", &txl->taa_history);
DRW_shgroup_uniform_texture_ref(grp, "colorBuffer", &effects->source_buffer);
DRW_shgroup_uniform_block(grp, "common_block", sldata->common_ubo);
- DRW_shgroup_uniform_block(
- grp, "renderpass_block", EEVEE_material_default_render_pass_ubo_get(sldata));
+ DRW_shgroup_uniform_block(grp, "renderpass_block", sldata->renderpass_ubo.combined);
if (effects->enabled_effects & EFFECT_TAA_REPROJECT) {
// DefaultTextureList *dtxl = DRW_viewport_texture_list_get();
diff --git a/source/blender/draw/engines/eevee/eevee_volumes.c b/source/blender/draw/engines/eevee/eevee_volumes.c
index 5ea7aaa7207..90860e94270 100644
--- a/source/blender/draw/engines/eevee/eevee_volumes.c
+++ b/source/blender/draw/engines/eevee/eevee_volumes.c
@@ -24,6 +24,7 @@
#include "DRW_render.h"
+#include "BLI_listbase.h"
#include "BLI_rand.h"
#include "BLI_string_utils.h"
@@ -354,7 +355,7 @@ void EEVEE_volumes_cache_init(EEVEE_ViewLayerData *sldata, EEVEE_Data *vedata)
struct World *wo = scene->world;
if (wo != NULL && wo->use_nodes && wo->nodetree &&
!LOOK_DEV_STUDIO_LIGHT_ENABLED(draw_ctx->v3d)) {
- struct GPUMaterial *mat = EEVEE_material_world_volume_get(scene, wo);
+ struct GPUMaterial *mat = EEVEE_material_get(vedata, scene, NULL, wo, VAR_MAT_VOLUME);
if (GPU_material_has_volume_output(mat)) {
grp = DRW_shgroup_material_create(mat, psl->volumetric_world_ps);
@@ -368,8 +369,7 @@ void EEVEE_volumes_cache_init(EEVEE_ViewLayerData *sldata, EEVEE_Data *vedata)
DRW_shgroup_uniform_block(grp, "planar_block", sldata->planar_ubo);
DRW_shgroup_uniform_block(grp, "light_block", sldata->light_ubo);
DRW_shgroup_uniform_block(grp, "shadow_block", sldata->shadow_ubo);
- DRW_shgroup_uniform_block(
- grp, "renderpass_block", EEVEE_material_default_render_pass_ubo_get(sldata));
+ DRW_shgroup_uniform_block(grp, "renderpass_block", sldata->renderpass_ubo.combined);
/* Fix principle volumetric not working with world materials. */
ListBase gpu_grids = GPU_material_volume_grids(mat);
@@ -387,8 +387,7 @@ void EEVEE_volumes_cache_init(EEVEE_ViewLayerData *sldata, EEVEE_Data *vedata)
/* If no world or volume material is present just clear the buffer with this drawcall */
grp = DRW_shgroup_create(e_data.volumetric_clear_sh, psl->volumetric_world_ps);
DRW_shgroup_uniform_block(grp, "common_block", sldata->common_ubo);
- DRW_shgroup_uniform_block(
- grp, "renderpass_block", EEVEE_material_default_render_pass_ubo_get(sldata));
+ DRW_shgroup_uniform_block(grp, "renderpass_block", sldata->renderpass_ubo.combined);
DRW_shgroup_call_procedural_triangles(grp, NULL, common_data->vol_tex_size[2]);
}
@@ -485,9 +484,8 @@ static bool eevee_volume_object_mesh_init(Scene *scene,
ModifierData *md = NULL;
/* Smoke Simulation */
- if (((ob->base_flag & BASE_FROM_DUPLI) == 0) &&
- (md = modifiers_findByType(ob, eModifierType_Fluid)) &&
- (modifier_isEnabled(scene, md, eModifierMode_Realtime)) &&
+ if ((md = BKE_modifiers_findby_type(ob, eModifierType_Fluid)) &&
+ (BKE_modifier_is_enabled(scene, md, eModifierMode_Realtime)) &&
((FluidModifierData *)md)->domain != NULL) {
FluidModifierData *mmd = (FluidModifierData *)md;
FluidDomainSettings *mds = mmd->domain;
@@ -590,12 +588,10 @@ void EEVEE_volumes_cache_object_add(EEVEE_ViewLayerData *sldata,
return;
}
- struct GPUMaterial *mat = EEVEE_material_mesh_volume_get(scene, ma);
+ int mat_options = VAR_MAT_VOLUME | VAR_MAT_MESH;
+ struct GPUMaterial *mat = EEVEE_material_get(vedata, scene, ma, NULL, mat_options);
eGPUMaterialStatus status = GPU_material_status(mat);
- if (status == GPU_MAT_QUEUED) {
- vedata->stl->g_data->queued_shaders_count++;
- }
/* If shader failed to compile or is currently compiling. */
if (status != GPU_MAT_SUCCESS) {
return;
@@ -609,8 +605,7 @@ void EEVEE_volumes_cache_object_add(EEVEE_ViewLayerData *sldata,
DRW_shgroup_uniform_block(grp, "shadow_block", sldata->shadow_ubo);
DRW_shgroup_uniform_block(grp, "light_block", sldata->light_ubo);
DRW_shgroup_uniform_block(grp, "grid_block", sldata->grid_ubo);
- DRW_shgroup_uniform_block(
- grp, "renderpass_block", EEVEE_material_default_render_pass_ubo_get(sldata));
+ DRW_shgroup_uniform_block(grp, "renderpass_block", sldata->renderpass_ubo.combined);
DRW_shgroup_uniform_block(grp, "common_block", sldata->common_ubo);
@@ -661,8 +656,7 @@ void EEVEE_volumes_cache_finish(EEVEE_ViewLayerData *sldata, EEVEE_Data *vedata)
DRW_shgroup_uniform_block(grp, "light_block", sldata->light_ubo);
DRW_shgroup_uniform_block(grp, "shadow_block", sldata->shadow_ubo);
DRW_shgroup_uniform_block(grp, "common_block", sldata->common_ubo);
- DRW_shgroup_uniform_block(
- grp, "renderpass_block", EEVEE_material_default_render_pass_ubo_get(sldata));
+ DRW_shgroup_uniform_block(grp, "renderpass_block", sldata->renderpass_ubo.combined);
DRW_shgroup_call_procedural_triangles(grp, NULL, common_data->vol_tex_size[2]);
@@ -671,8 +665,7 @@ void EEVEE_volumes_cache_finish(EEVEE_ViewLayerData *sldata, EEVEE_Data *vedata)
DRW_shgroup_uniform_texture_ref(grp, "volumeScattering", &txl->volume_scatter);
DRW_shgroup_uniform_texture_ref(grp, "volumeExtinction", &txl->volume_transmit);
DRW_shgroup_uniform_block(grp, "common_block", sldata->common_ubo);
- DRW_shgroup_uniform_block(
- grp, "renderpass_block", EEVEE_material_default_render_pass_ubo_get(sldata));
+ DRW_shgroup_uniform_block(grp, "renderpass_block", sldata->renderpass_ubo.combined);
DRW_shgroup_call_procedural_triangles(
grp, NULL, USE_VOLUME_OPTI ? 1 : common_data->vol_tex_size[2]);
@@ -683,8 +676,7 @@ void EEVEE_volumes_cache_finish(EEVEE_ViewLayerData *sldata, EEVEE_Data *vedata)
DRW_shgroup_uniform_texture_ref(grp, "inTransmittance", &txl->volume_transmit);
DRW_shgroup_uniform_texture_ref(grp, "inSceneDepth", &e_data.depth_src);
DRW_shgroup_uniform_block(grp, "common_block", sldata->common_ubo);
- DRW_shgroup_uniform_block(
- grp, "renderpass_block", EEVEE_material_default_render_pass_ubo_get(sldata));
+ DRW_shgroup_uniform_block(grp, "renderpass_block", sldata->renderpass_ubo.combined);
DRW_shgroup_call_procedural_triangles(grp, NULL, 1);
}
@@ -775,12 +767,8 @@ void EEVEE_volumes_compute(EEVEE_ViewLayerData *sldata, EEVEE_Data *vedata)
/* We sample the shadow-maps using shadow sampler. We need to enable Comparison mode.
* TODO(fclem) avoid this by using sampler objects.*/
- GPU_texture_bind(sldata->shadow_cube_pool, 0);
GPU_texture_compare_mode(sldata->shadow_cube_pool, true);
- GPU_texture_unbind(sldata->shadow_cube_pool);
- GPU_texture_bind(sldata->shadow_cascade_pool, 0);
GPU_texture_compare_mode(sldata->shadow_cascade_pool, true);
- GPU_texture_unbind(sldata->shadow_cascade_pool);
GPU_framebuffer_bind(fbl->volumetric_fb);
DRW_draw_pass(psl->volumetric_world_ps);
@@ -851,7 +839,7 @@ void EEVEE_volumes_resolve(EEVEE_ViewLayerData *UNUSED(sldata), EEVEE_Data *veda
void EEVEE_volumes_free_smoke_textures(void)
{
/* Free Smoke Textures after rendering */
- for (LinkData *link = e_data.smoke_domains.first; link; link = link->next) {
+ LISTBASE_FOREACH (LinkData *, link, &e_data.smoke_domains) {
FluidModifierData *mmd = (FluidModifierData *)link->data;
GPU_free_smoke(mmd);
}
@@ -920,8 +908,7 @@ void EEVEE_volumes_output_init(EEVEE_ViewLayerData *sldata, EEVEE_Data *vedata,
DRW_shgroup_uniform_texture_ref(grp, "inTransmittance", &txl->volume_transmit);
DRW_shgroup_uniform_texture_ref(grp, "inSceneDepth", &e_data.depth_src);
DRW_shgroup_uniform_block(grp, "common_block", sldata->common_ubo);
- DRW_shgroup_uniform_block(
- grp, "renderpass_block", EEVEE_material_default_render_pass_ubo_get(sldata));
+ DRW_shgroup_uniform_block(grp, "renderpass_block", sldata->renderpass_ubo.combined);
}
else {
/* There is no volumetrics in the scene. Use a shader to fill the accum textures with a default
diff --git a/source/blender/draw/engines/eevee/shaders/ambient_occlusion_lib.glsl b/source/blender/draw/engines/eevee/shaders/ambient_occlusion_lib.glsl
index 8662c0ecb6a..57b16418696 100644
--- a/source/blender/draw/engines/eevee/shaders/ambient_occlusion_lib.glsl
+++ b/source/blender/draw/engines/eevee/shaders/ambient_occlusion_lib.glsl
@@ -6,13 +6,9 @@
#if defined(MESH_SHADER)
# if !defined(USE_ALPHA_HASH)
-# if !defined(USE_ALPHA_CLIP)
-# if !defined(SHADOW_SHADER)
-# if !defined(USE_MULTIPLY)
-# if !defined(USE_ALPHA_BLEND)
-# define ENABLE_DEFERED_AO
-# endif
-# endif
+# if !defined(DEPTH_SHADER)
+# if !defined(USE_ALPHA_BLEND)
+# define ENABLE_DEFERED_AO
# endif
# endif
# endif
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 c3518198805..402d306df45 100644
--- a/source/blender/draw/engines/eevee/shaders/bsdf_common_lib.glsl
+++ b/source/blender/draw/engines/eevee/shaders/bsdf_common_lib.glsl
@@ -928,7 +928,7 @@ Closure closure_emission(vec3 rgb)
/* Breaking this across multiple lines causes issues for some older GLSL compilers. */
/* clang-format off */
-# if defined(MESH_SHADER) && !defined(USE_ALPHA_HASH) && !defined(USE_ALPHA_CLIP) && !defined(SHADOW_SHADER)
+# if defined(MESH_SHADER) && !defined(DEPTH_SHADER)
/* clang-format on */
# ifndef USE_ALPHA_BLEND
layout(location = 0) out vec4 outRadiance;
@@ -1001,6 +1001,10 @@ void main()
outRadiance.rgb += cl.sss_irradiance.rgb * cl.sss_albedo.rgb * fac;
# endif
+# ifdef LOOKDEV
+ gl_FragDepth = 0.0;
+# endif
+
# ifndef USE_ALPHA_BLEND
float alpha_div = 1.0 / max(1e-8, alpha);
outRadiance.rgb *= alpha_div;
@@ -1011,6 +1015,6 @@ void main()
# endif
}
-# endif /* MESH_SHADER && !SHADOW_SHADER */
+# endif /* MESH_SHADER */
#endif /* VOLUMETRICS */
diff --git a/source/blender/draw/engines/eevee/shaders/effect_dof_frag.glsl b/source/blender/draw/engines/eevee/shaders/effect_dof_frag.glsl
index 5277bfa32bb..d56890769a7 100644
--- a/source/blender/draw/engines/eevee/shaders/effect_dof_frag.glsl
+++ b/source/blender/draw/engines/eevee/shaders/effect_dof_frag.glsl
@@ -1,6 +1,4 @@
-uniform mat4 ProjectionMatrix;
-
uniform sampler2D colorBuffer;
uniform sampler2D depthBuffer;
diff --git a/source/blender/draw/engines/eevee/shaders/lit_surface_frag.glsl b/source/blender/draw/engines/eevee/shaders/lit_surface_frag.glsl
index 8c2619650b9..bc7879763c3 100644
--- a/source/blender/draw/engines/eevee/shaders/lit_surface_frag.glsl
+++ b/source/blender/draw/engines/eevee/shaders/lit_surface_frag.glsl
@@ -177,7 +177,7 @@ void CLOSURE_NAME(vec3 N
out_refr = vec3(0.0);
#endif
-#if defined(SHADOW_SHADER) || defined(WORLD_BACKGROUND)
+#if defined(DEPTH_SHADER) || defined(WORLD_BACKGROUND)
/* This makes shader resources become unused and avoid issues with samplers. (see T59747) */
return;
#else
diff --git a/source/blender/draw/engines/eevee/shaders/lit_surface_vert.glsl b/source/blender/draw/engines/eevee/shaders/lit_surface_vert.glsl
index cf20b3ff5b9..1b94fc2bee1 100644
--- a/source/blender/draw/engines/eevee/shaders/lit_surface_vert.glsl
+++ b/source/blender/draw/engines/eevee/shaders/lit_surface_vert.glsl
@@ -4,11 +4,12 @@ in vec3 pos;
in vec3 nor;
#endif
+#ifdef MESH_SHADER
out vec3 worldPosition;
out vec3 viewPosition;
-
out vec3 worldNormal;
out vec3 viewNormal;
+#endif
#ifdef HAIR_SHADER
out vec3 hairTangent;
@@ -41,22 +42,28 @@ void main()
hairThickness,
hairThickTime);
worldNormal = cross(hairTangent, binor);
- worldPosition = pos;
+ vec3 world_pos = pos;
#else
- worldPosition = point_object_to_world(pos);
- worldNormal = normalize(normal_object_to_world(nor));
+ vec3 world_pos = point_object_to_world(pos);
#endif
- /* No need to normalize since this is just a rotation. */
- viewNormal = normal_world_to_view(worldNormal);
+ gl_Position = point_world_to_ndc(world_pos);
+ /* Used for planar reflections */
+ gl_ClipDistance[0] = dot(vec4(world_pos, 1.0), clipPlanes[0]);
+
+#ifdef MESH_SHADER
+ worldPosition = world_pos;
viewPosition = point_world_to_view(worldPosition);
- gl_Position = point_world_to_ndc(worldPosition);
- /* Used for planar reflections */
- gl_ClipDistance[0] = dot(vec4(worldPosition, 1.0), clipPlanes[0]);
+# ifndef HAIR_SHADER
+ worldNormal = normalize(normal_object_to_world(nor));
+# endif
-#ifdef USE_ATTR
+ /* No need to normalize since this is just a rotation. */
+ viewNormal = normal_world_to_view(worldNormal);
+# ifdef USE_ATTR
pass_attr(pos);
+# endif
#endif
}
diff --git a/source/blender/draw/engines/eevee/shaders/prepass_frag.glsl b/source/blender/draw/engines/eevee/shaders/prepass_frag.glsl
index b49dbfceba2..9acd8f998f6 100644
--- a/source/blender/draw/engines/eevee/shaders/prepass_frag.glsl
+++ b/source/blender/draw/engines/eevee/shaders/prepass_frag.glsl
@@ -45,26 +45,22 @@ float hashed_alpha_threshold(vec3 co)
/* Find our final, uniformly distributed alpha threshold. */
float threshold = (x < one_a) ? ((x < a) ? cases.x : cases.y) : cases.z;
+ /* Jitter the threshold for TAA accumulation. */
+ threshold = fract(threshold + alphaHashOffset);
+
/* Avoids threshold == 0. */
threshold = clamp(threshold, 1.0e-6, 1.0);
- /* Jitter the threshold for TAA accumulation. */
- return fract(threshold + alphaHashOffset);
+ return threshold;
}
#endif
-#ifdef USE_ALPHA_CLIP
-uniform float alphaThreshold;
-#endif
+#define NODETREE_EXEC
void main()
{
- /* For now do nothing.
- * In the future, output object motion blur. */
-
-#if defined(USE_ALPHA_HASH) || defined(USE_ALPHA_CLIP)
-# define NODETREE_EXEC
+#if defined(USE_ALPHA_HASH)
Closure cl = nodetree_exec();
@@ -75,11 +71,6 @@ void main()
if (opacity < hashed_alpha_threshold(worldPosition)) {
discard;
}
-# elif defined(USE_ALPHA_CLIP)
- /* Alpha clip */
- if (opacity <= alphaThreshold) {
- discard;
- }
# endif
#endif
}
diff --git a/source/blender/draw/engines/external/external_engine.c b/source/blender/draw/engines/external/external_engine.c
index ee4bd58ab80..2f448b784ed 100644
--- a/source/blender/draw/engines/external/external_engine.c
+++ b/source/blender/draw/engines/external/external_engine.c
@@ -25,10 +25,12 @@
#include "DRW_render.h"
+#include "DNA_modifier_types.h"
#include "DNA_screen_types.h"
#include "DNA_view3d_types.h"
#include "BKE_object.h"
+#include "BKE_particle.h"
#include "ED_screen.h"
@@ -42,6 +44,11 @@
#define EXTERNAL_ENGINE "BLENDER_EXTERNAL"
+extern char datatoc_depth_frag_glsl[];
+extern char datatoc_depth_vert_glsl[];
+
+extern char datatoc_common_view_lib_glsl[];
+
/* *********** LISTS *********** */
/* GPUViewport.storage
@@ -104,7 +111,16 @@ static void external_engine_init(void *vedata)
/* Depth prepass */
if (!e_data.depth_sh) {
- e_data.depth_sh = DRW_shader_create_3d_depth_only(GPU_SHADER_CFG_DEFAULT);
+ const GPUShaderConfigData *sh_cfg = &GPU_shader_cfg_data[GPU_SHADER_CFG_DEFAULT];
+
+ e_data.depth_sh = GPU_shader_create_from_arrays({
+ .vert = (const char *[]){sh_cfg->lib,
+ datatoc_common_view_lib_glsl,
+ datatoc_depth_vert_glsl,
+ NULL},
+ .frag = (const char *[]){datatoc_depth_frag_glsl, NULL},
+ .defs = (const char *[]){sh_cfg->def, NULL},
+ });
}
if (!stl->g_data) {
@@ -166,6 +182,24 @@ static void external_cache_populate(void *vedata, Object *ob)
return;
}
+ if (ob->type == OB_MESH && ob->modifiers.first != NULL) {
+ LISTBASE_FOREACH (ModifierData *, md, &ob->modifiers) {
+ if (md->type != eModifierType_ParticleSystem) {
+ continue;
+ }
+ ParticleSystem *psys = ((ParticleSystemModifierData *)md)->psys;
+ if (!DRW_object_is_visible_psys_in_active_context(ob, psys)) {
+ continue;
+ }
+ ParticleSettings *part = psys->part;
+ const int draw_as = (part->draw_as == PART_DRAW_REND) ? part->ren_as : part->draw_as;
+
+ if (draw_as == PART_DRAW_PATH) {
+ struct GPUBatch *hairs = DRW_cache_particles_get_hair(ob, psys, NULL);
+ DRW_shgroup_call(stl->g_data->depth_shgrp, hairs, NULL);
+ }
+ }
+ }
struct GPUBatch *geom = DRW_cache_object_surface_get(ob);
if (geom) {
/* Depth Prepass */
@@ -195,7 +229,7 @@ static void external_draw_scene_do(void *vedata)
return;
}
- RenderEngine *engine = RE_engine_create_ex(engine_type, true);
+ RenderEngine *engine = RE_engine_create(engine_type);
engine->tile_x = scene->r.tilex;
engine->tile_y = scene->r.tiley;
engine_type->view_update(engine, draw_ctx->evil_C, draw_ctx->depsgraph);
@@ -257,7 +291,7 @@ static void external_draw_scene(void *vedata)
static void external_engine_free(void)
{
- /* All shaders are builtin. */
+ DRW_SHADER_FREE_SAFE(e_data.depth_sh);
}
static const DrawEngineDataSize external_data_size = DRW_VIEWPORT_DATA_SIZE(EXTERNAL_Data);
diff --git a/source/blender/draw/engines/gpencil/gpencil_antialiasing.c b/source/blender/draw/engines/gpencil/gpencil_antialiasing.c
index e81073db4a5..8955240c549 100644
--- a/source/blender/draw/engines/gpencil/gpencil_antialiasing.c
+++ b/source/blender/draw/engines/gpencil/gpencil_antialiasing.c
@@ -78,13 +78,8 @@ void GPENCIL_antialiasing_init(struct GPENCIL_Data *vedata)
false,
NULL);
- GPU_texture_bind(txl->smaa_search_tx, 0);
GPU_texture_filter_mode(txl->smaa_search_tx, true);
- GPU_texture_unbind(txl->smaa_search_tx);
-
- GPU_texture_bind(txl->smaa_area_tx, 0);
GPU_texture_filter_mode(txl->smaa_area_tx, true);
- GPU_texture_unbind(txl->smaa_area_tx);
}
{
@@ -115,6 +110,8 @@ void GPENCIL_antialiasing_init(struct GPENCIL_Data *vedata)
DRW_shgroup_uniform_texture(grp, "colorTex", pd->color_tx);
DRW_shgroup_uniform_texture(grp, "revealTex", pd->reveal_tx);
DRW_shgroup_uniform_vec4_copy(grp, "viewportMetrics", metrics);
+ DRW_shgroup_uniform_float_copy(
+ grp, "lumaWeight", pd->scene->grease_pencil_settings.smaa_threshold);
DRW_shgroup_clear_framebuffer(grp, GPU_COLOR_BIT, 0, 0, 0, 0, 0.0f, 0x0);
DRW_shgroup_call_procedural_triangles(grp, NULL, 1);
diff --git a/source/blender/draw/engines/gpencil/gpencil_cache_utils.c b/source/blender/draw/engines/gpencil/gpencil_cache_utils.c
index a5f67b7831e..2b811f1d52e 100644
--- a/source/blender/draw/engines/gpencil/gpencil_cache_utils.c
+++ b/source/blender/draw/engines/gpencil/gpencil_cache_utils.c
@@ -33,6 +33,7 @@
#include "BKE_lib_id.h"
#include "BKE_object.h"
+#include "BLI_hash.h"
#include "BLI_link_utils.h"
#include "BLI_memblock.h"
@@ -234,6 +235,21 @@ static void gpencil_layer_final_tint_and_alpha_get(const GPENCIL_PrivateData *pd
*r_alpha *= pd->xray_alpha;
}
+/* Random color by layer. */
+static void gpencil_layer_random_color_get(const Object *ob,
+ const bGPDlayer *gpl,
+ float r_color[3])
+{
+ const float hsv_saturation = 0.7f;
+ const float hsv_value = 0.6f;
+
+ uint ob_hash = BLI_ghashutil_strhash_p_murmur(ob->id.name);
+ uint gpl_hash = BLI_ghashutil_strhash_p_murmur(gpl->info);
+ float hue = BLI_hash_int_01(ob_hash * gpl_hash);
+ float hsv[3] = {hue, hsv_saturation, hsv_value};
+ hsv_to_rgb_v(hsv, r_color);
+}
+
GPENCIL_tLayer *gpencil_layer_cache_add(GPENCIL_PrivateData *pd,
const Object *ob,
const bGPDlayer *gpl,
@@ -314,12 +330,12 @@ GPENCIL_tLayer *gpencil_layer_cache_add(GPENCIL_PrivateData *pd,
break;
case eGplBlendMode_Multiply:
case eGplBlendMode_Divide:
- case eGplBlendMode_Overlay:
+ case eGplBlendMode_HardLight:
state |= DRW_STATE_BLEND_MUL;
break;
}
- if (ELEM(gpl->blend_mode, eGplBlendMode_Subtract, eGplBlendMode_Overlay)) {
+ if (ELEM(gpl->blend_mode, eGplBlendMode_Subtract, eGplBlendMode_HardLight)) {
/* For these effect to propagate, we need a signed floating point buffer. */
pd->use_signed_fb = true;
}
@@ -336,7 +352,7 @@ GPENCIL_tLayer *gpencil_layer_cache_add(GPENCIL_PrivateData *pd,
DRW_shgroup_stencil_mask(grp, 0xFF);
DRW_shgroup_call_procedural_triangles(grp, NULL, 1);
- if (gpl->blend_mode == eGplBlendMode_Overlay) {
+ if (gpl->blend_mode == eGplBlendMode_HardLight) {
/* We cannot do custom blending on MultiTarget framebuffers.
* Workaround by doing 2 passes. */
grp = DRW_shgroup_create(sh, tgp_layer->blend_ps);
@@ -365,7 +381,7 @@ GPENCIL_tLayer *gpencil_layer_cache_add(GPENCIL_PrivateData *pd,
struct GPUShader *sh = GPENCIL_shader_geometry_get();
DRWShadingGroup *grp = tgp_layer->base_shgrp = DRW_shgroup_create(sh, tgp_layer->geom_ps);
- DRW_shgroup_uniform_texture_persistent(grp, "gpSceneDepthTexture", depth_tex);
+ DRW_shgroup_uniform_texture(grp, "gpSceneDepthTexture", depth_tex);
DRW_shgroup_uniform_texture_ref(grp, "gpMaskTexture", mask_tex);
DRW_shgroup_uniform_vec3_copy(grp, "gpNormal", tgp_ob->plane_normal);
DRW_shgroup_uniform_bool_copy(grp, "strokeOrder3d", tgp_ob->is_drawmode3d);
@@ -375,7 +391,16 @@ GPENCIL_tLayer *gpencil_layer_cache_add(GPENCIL_PrivateData *pd,
DRW_shgroup_uniform_float_copy(grp, "thicknessOffset", (float)gpl->line_change);
DRW_shgroup_uniform_float_copy(grp, "thicknessWorldScale", thickness_scale);
DRW_shgroup_uniform_float_copy(grp, "vertexColorOpacity", vert_col_opacity);
- DRW_shgroup_uniform_vec4_copy(grp, "layerTint", layer_tint);
+
+ /* If random color type, need color by layer. */
+ float gpl_color[4];
+ copy_v4_v4(gpl_color, layer_tint);
+ if (pd->v3d_color_type == V3D_SHADING_RANDOM_COLOR) {
+ gpencil_layer_random_color_get(ob, gpl, gpl_color);
+ gpl_color[3] = 1.0f;
+ }
+ DRW_shgroup_uniform_vec4_copy(grp, "layerTint", gpl_color);
+
DRW_shgroup_uniform_float_copy(grp, "layerOpacity", layer_alpha);
DRW_shgroup_stencil_mask(grp, 0xFF);
}
diff --git a/source/blender/draw/engines/gpencil/gpencil_draw_data.c b/source/blender/draw/engines/gpencil/gpencil_draw_data.c
index 625af8cec6f..6e6b35e19ca 100644
--- a/source/blender/draw/engines/gpencil/gpencil_draw_data.c
+++ b/source/blender/draw/engines/gpencil/gpencil_draw_data.c
@@ -91,21 +91,6 @@ static void gpencil_uv_transform_get(const float ofs[2],
copy_v2_v2(r_uvmat[2], mat[3]);
}
-#define HSV_SATURATION 0.5
-#define HSV_VALUE 0.8
-
-static void gpencil_object_random_color_get(const Object *ob, float r_color[3])
-{
- /* Duplicated from workbench_material.c */
- uint hash = BLI_ghashutil_strhash_p_murmur(ob->id.name);
- if (ob->id.lib) {
- hash = (hash * 13) ^ BLI_ghashutil_strhash_p_murmur(ob->id.lib->name);
- }
- float hue = BLI_hash_int_01(hash);
- float hsv[3] = {hue, HSV_SATURATION, HSV_VALUE};
- hsv_to_rgb_v(hsv, r_color);
-}
-
static void gpencil_shade_color(float color[3])
{
/* This is scene refereed color, not gamma corrected and not per perceptual.
@@ -129,6 +114,10 @@ static MaterialGPencilStyle *gpencil_viewport_material_overrides(GPENCIL_Private
switch (color_type) {
case V3D_SHADING_MATERIAL_COLOR:
+ case V3D_SHADING_RANDOM_COLOR:
+ /* Random uses a random color by layer and this is done using the tint
+ * layer. A simple color by object, like meshes, is not practical in
+ * grease pencil. */
copy_v4_v4(gp_style_tmp.stroke_rgba, gp_style->stroke_rgba);
copy_v4_v4(gp_style_tmp.fill_rgba, gp_style->fill_rgba);
gp_style = &gp_style_tmp;
@@ -152,15 +141,6 @@ static MaterialGPencilStyle *gpencil_viewport_material_overrides(GPENCIL_Private
gp_style->mix_factor = 0.0f;
}
break;
- case V3D_SHADING_RANDOM_COLOR:
- gp_style = &gp_style_tmp;
- gp_style->stroke_style = GP_MATERIAL_STROKE_STYLE_SOLID;
- gp_style->fill_style = GP_MATERIAL_FILL_STYLE_SOLID;
- gpencil_object_random_color_get(ob, gp_style->fill_rgba);
- gp_style->fill_rgba[3] = 1.0f;
- copy_v4_v4(gp_style->stroke_rgba, gp_style->fill_rgba);
- gpencil_shade_color(gp_style->stroke_rgba);
- break;
case V3D_SHADING_SINGLE_COLOR:
gp_style = &gp_style_tmp;
gp_style->stroke_style = GP_MATERIAL_STROKE_STYLE_SOLID;
diff --git a/source/blender/draw/engines/gpencil/gpencil_engine.c b/source/blender/draw/engines/gpencil/gpencil_engine.c
index 9ebd20eb539..495de7ef10b 100644
--- a/source/blender/draw/engines/gpencil/gpencil_engine.c
+++ b/source/blender/draw/engines/gpencil/gpencil_engine.c
@@ -33,6 +33,7 @@
#include "BKE_global.h" /* for G.debug */
#include "BLI_link_utils.h"
+#include "BLI_listbase.h"
#include "BLI_memblock.h"
#include "DNA_camera_types.h"
@@ -90,6 +91,7 @@ void GPENCIL_engine_init(void *ved)
stl->pd->gp_object_pool = vldata->gp_object_pool;
stl->pd->gp_layer_pool = vldata->gp_layer_pool;
stl->pd->gp_vfx_pool = vldata->gp_vfx_pool;
+ stl->pd->view_layer = ctx->view_layer;
stl->pd->scene = ctx->scene;
stl->pd->v3d = ctx->v3d;
stl->pd->last_light_pool = NULL;
@@ -291,7 +293,7 @@ void GPENCIL_cache_init(void *ved)
grp = DRW_shgroup_create(sh, psl->merge_depth_ps);
DRW_shgroup_uniform_texture_ref(grp, "depthBuf", &pd->depth_tx);
DRW_shgroup_uniform_bool(grp, "strokeOrder3d", &pd->is_stroke_order_3d, 1);
- DRW_shgroup_uniform_vec4(grp, "gpModelMatrix[0]", pd->object_bound_mat[0], 4);
+ DRW_shgroup_uniform_vec4(grp, "gpModelMatrix", pd->object_bound_mat[0], 4);
DRW_shgroup_call_procedural_triangles(grp, NULL, 1);
}
{
@@ -467,7 +469,7 @@ static void gpencil_layer_cache_populate(bGPDlayer *gpl,
/* Iterator dependent uniforms. */
DRWShadingGroup *grp = iter->grp = tgp_layer->base_shgrp;
- DRW_shgroup_uniform_block_persistent(grp, "gpLightBlock", iter->ubo_lights);
+ DRW_shgroup_uniform_block(grp, "gpLightBlock", iter->ubo_lights);
DRW_shgroup_uniform_block(grp, "gpMaterialBlock", iter->ubo_mat);
DRW_shgroup_uniform_texture(grp, "gpFillTexture", iter->tex_fill);
DRW_shgroup_uniform_texture(grp, "gpStrokeTexture", iter->tex_stroke);
@@ -597,6 +599,7 @@ void GPENCIL_cache_populate(void *ved, Object *ob)
GPENCIL_Data *vedata = (GPENCIL_Data *)ved;
GPENCIL_PrivateData *pd = vedata->stl->pd;
GPENCIL_TextureList *txl = vedata->txl;
+ const bool is_final_render = DRW_state_is_image_render();
/* object must be visible */
if (!(DRW_object_visibility_in_active_context(ob) & OB_VISIBLE_SELF)) {
@@ -616,7 +619,8 @@ void GPENCIL_cache_populate(void *ved, Object *ob)
bGPdata *gpd = (bGPdata *)ob->data;
bool do_onion = (!pd->is_render) ? pd->do_onion : (gpd->onion_flag & GP_ONION_GHOST_ALWAYS);
- BKE_gpencil_visible_stroke_iter(ob,
+ BKE_gpencil_visible_stroke_iter(is_final_render ? pd->view_layer : NULL,
+ ob,
gpencil_layer_cache_populate,
gpencil_stroke_cache_populate,
&iter,
@@ -743,8 +747,8 @@ static void GPENCIL_draw_scene_depth_only(void *ved)
GPU_framebuffer_bind(dfbl->depth_only_fb);
}
- for (GPENCIL_tObject *ob = pd->tobjects.first; ob; ob = ob->next) {
- for (GPENCIL_tLayer *layer = ob->layers.first; layer; layer = layer->next) {
+ LISTBASE_FOREACH (GPENCIL_tObject *, ob, &pd->tobjects) {
+ LISTBASE_FOREACH (GPENCIL_tLayer *, layer, &ob->layers) {
DRW_draw_pass(layer->geom_ps);
}
}
@@ -825,7 +829,7 @@ static void GPENCIL_draw_object(GPENCIL_Data *vedata, GPENCIL_tObject *ob)
GPU_framebuffer_multi_clear(fb_object, clear_cols);
}
- for (GPENCIL_tLayer *layer = ob->layers.first; layer; layer = layer->next) {
+ LISTBASE_FOREACH (GPENCIL_tLayer *, layer, &ob->layers) {
if (layer->mask_bits) {
gpencil_draw_mask(vedata, ob, layer);
}
@@ -846,7 +850,7 @@ static void GPENCIL_draw_object(GPENCIL_Data *vedata, GPENCIL_tObject *ob)
}
}
- for (GPENCIL_tVfx *vfx = ob->vfx.first; vfx; vfx = vfx->next) {
+ LISTBASE_FOREACH (GPENCIL_tVfx *, vfx, &ob->vfx) {
GPU_framebuffer_bind(*(vfx->target_fb));
DRW_draw_pass(vfx->vfx_ps);
}
@@ -892,7 +896,7 @@ static void GPENCIL_fast_draw_end(GPENCIL_Data *vedata)
pd->snapshot_buffer_dirty = false;
}
/* Draw the sbuffer stroke(s). */
- for (GPENCIL_tObject *ob = pd->sbuffer_tobjects.first; ob; ob = ob->next) {
+ LISTBASE_FOREACH (GPENCIL_tObject *, ob, &pd->sbuffer_tobjects) {
GPENCIL_draw_object(vedata, ob);
}
}
@@ -933,7 +937,7 @@ void GPENCIL_draw_scene(void *ved)
GPU_framebuffer_multi_clear(fbl->gpencil_fb, clear_cols);
}
- for (GPENCIL_tObject *ob = pd->tobjects.first; ob; ob = ob->next) {
+ LISTBASE_FOREACH (GPENCIL_tObject *, ob, &pd->tobjects) {
GPENCIL_draw_object(vedata, ob);
}
diff --git a/source/blender/draw/engines/gpencil/gpencil_engine.h b/source/blender/draw/engines/gpencil/gpencil_engine.h
index f765dcf73de..cedd75af813 100644
--- a/source/blender/draw/engines/gpencil/gpencil_engine.h
+++ b/source/blender/draw/engines/gpencil/gpencil_engine.h
@@ -307,6 +307,8 @@ typedef struct GPENCIL_PrivateData {
float dof_params[2];
/* Used for DoF Setup. */
Object *camera;
+ /* Copy of draw_ctx->view_layer for convenience. */
+ struct ViewLayer *view_layer;
/* Copy of draw_ctx->scene for convenience. */
struct Scene *scene;
/* Copy of draw_ctx->vie3d for convenience. */
diff --git a/source/blender/draw/engines/gpencil/gpencil_render.c b/source/blender/draw/engines/gpencil/gpencil_render.c
index 496122c0483..bb91bdbe396 100644
--- a/source/blender/draw/engines/gpencil/gpencil_render.c
+++ b/source/blender/draw/engines/gpencil/gpencil_render.c
@@ -51,8 +51,7 @@ void GPENCIL_render_init(GPENCIL_Data *vedata,
float winmat[4][4], viewmat[4][4], viewinv[4][4];
struct Object *camera = DEG_get_evaluated_object(depsgraph, RE_GetCamera(engine->re));
- float frame = BKE_scene_frame_get(scene);
- RE_GetCameraWindow(engine->re, camera, frame, winmat);
+ RE_GetCameraWindow(engine->re, camera, winmat);
RE_GetCameraModelMatrix(engine->re, camera, viewinv);
invert_m4_m4(viewmat, viewinv);
diff --git a/source/blender/draw/engines/gpencil/gpencil_shader.c b/source/blender/draw/engines/gpencil/gpencil_shader.c
index 8c7ba42a70e..6284e0a648c 100644
--- a/source/blender/draw/engines/gpencil/gpencil_shader.c
+++ b/source/blender/draw/engines/gpencil/gpencil_shader.c
@@ -77,10 +77,33 @@ static struct {
void GPENCIL_shader_free(void)
{
- GPUShader **sh_data_as_array = (GPUShader **)&g_shaders;
- for (int i = 0; i < (sizeof(g_shaders) / sizeof(GPUShader *)); i++) {
- DRW_SHADER_FREE_SAFE(sh_data_as_array[i]);
- }
+ DRW_SHADER_FREE_SAFE(g_shaders.antialiasing_sh[0]);
+ DRW_SHADER_FREE_SAFE(g_shaders.antialiasing_sh[1]);
+ DRW_SHADER_FREE_SAFE(g_shaders.antialiasing_sh[2]);
+ DRW_SHADER_FREE_SAFE(g_shaders.gpencil_sh);
+ DRW_SHADER_FREE_SAFE(g_shaders.composite_sh);
+ DRW_SHADER_FREE_SAFE(g_shaders.layer_blend_sh);
+ DRW_SHADER_FREE_SAFE(g_shaders.depth_merge_sh);
+ DRW_SHADER_FREE_SAFE(g_shaders.mask_invert_sh);
+ DRW_SHADER_FREE_SAFE(g_shaders.fx_composite_sh);
+ DRW_SHADER_FREE_SAFE(g_shaders.fx_colorize_sh);
+ DRW_SHADER_FREE_SAFE(g_shaders.fx_blur_sh);
+ DRW_SHADER_FREE_SAFE(g_shaders.fx_glow_sh);
+ DRW_SHADER_FREE_SAFE(g_shaders.fx_pixel_sh);
+ DRW_SHADER_FREE_SAFE(g_shaders.fx_rim_sh);
+ DRW_SHADER_FREE_SAFE(g_shaders.fx_shadow_sh);
+ DRW_SHADER_FREE_SAFE(g_shaders.fx_transform_sh);
+ DRW_SHADER_FREE_SAFE(g_shaders.gpencil_fill_sh);
+ DRW_SHADER_FREE_SAFE(g_shaders.gpencil_stroke_sh);
+ DRW_SHADER_FREE_SAFE(g_shaders.gpencil_point_sh);
+ DRW_SHADER_FREE_SAFE(g_shaders.gpencil_edit_point_sh);
+ DRW_SHADER_FREE_SAFE(g_shaders.gpencil_line_sh);
+ DRW_SHADER_FREE_SAFE(g_shaders.gpencil_drawing_fill_sh);
+ DRW_SHADER_FREE_SAFE(g_shaders.gpencil_fullscreen_sh);
+ DRW_SHADER_FREE_SAFE(g_shaders.gpencil_simple_fullscreen_sh);
+ DRW_SHADER_FREE_SAFE(g_shaders.gpencil_blend_fullscreen_sh);
+ DRW_SHADER_FREE_SAFE(g_shaders.gpencil_background_sh);
+ DRW_SHADER_FREE_SAFE(g_shaders.gpencil_paper_sh);
}
GPUShader *GPENCIL_shader_antialiasing(int stage)
@@ -112,10 +135,11 @@ GPUShader *GPENCIL_shader_antialiasing(int stage)
},
.defs =
(const char *[]){
+ "uniform float lumaWeight;\n",
"#define SMAA_GLSL_3\n",
"#define SMAA_RT_METRICS viewportMetrics\n",
"#define SMAA_PRESET_HIGH\n",
- "#define SMAA_LUMA_WEIGHT float4(1.0, 1.0, 1.0, 0.0)\n",
+ "#define SMAA_LUMA_WEIGHT float4(lumaWeight, lumaWeight, lumaWeight, 0.0)\n",
"#define SMAA_NO_DISCARD\n",
stage_define,
NULL,
diff --git a/source/blender/draw/engines/gpencil/shaders/gpencil_common_lib.glsl b/source/blender/draw/engines/gpencil/shaders/gpencil_common_lib.glsl
index cb34515a960..1e75f6dd5bb 100644
--- a/source/blender/draw/engines/gpencil/shaders/gpencil_common_lib.glsl
+++ b/source/blender/draw/engines/gpencil/shaders/gpencil_common_lib.glsl
@@ -77,12 +77,12 @@ layout(std140) uniform gpLightBlock
/* Must match eGPLayerBlendModes */
#define MODE_REGULAR 0
-#define MODE_OVERLAY 1
+#define MODE_HARDLIGHT 1
#define MODE_ADD 2
#define MODE_SUB 3
#define MODE_MULTIPLY 4
#define MODE_DIVIDE 5
-#define MODE_OVERLAY_SECOND_PASS 999
+#define MODE_HARDLIGHT_SECOND_PASS 999
void blend_mode_output(
int blend_mode, vec4 color, float opacity, out vec4 frag_color, out vec4 frag_revealage)
@@ -104,7 +104,7 @@ void blend_mode_output(
color.a *= opacity;
frag_revealage = frag_color = clamp(1.0 / max(vec4(1e-6), 1.0 - color * color.a), 0.0, 1e18);
break;
- case MODE_OVERLAY:
+ case MODE_HARDLIGHT:
/* Reminder: Blending func is multiply blend (dst.rgba * src.rgba).*/
/**
* We need to separate the overlay equation into 2 term (one mul and one add).
@@ -120,11 +120,13 @@ void blend_mode_output(
color = mix(vec4(0.5), color, color.a * opacity);
vec4 s = step(-0.5, -color);
frag_revealage = frag_color = 2.0 * s + 2.0 * color * (1.0 - s * 2.0);
+ frag_revealage = max(vec4(0.0), frag_revealage);
break;
- case MODE_OVERLAY_SECOND_PASS:
+ case MODE_HARDLIGHT_SECOND_PASS:
/* Reminder: Blending func is additive blend (dst.rgba + src.rgba).*/
color = mix(vec4(0.5), color, color.a * opacity);
frag_revealage = frag_color = (-1.0 + 2.0 * color) * step(-0.5, -color);
+ frag_revealage = max(vec4(0.0), frag_revealage);
break;
case MODE_SUB:
case MODE_ADD:
@@ -210,7 +212,7 @@ uniform vec4 layerTint;
uniform float layerOpacity; /* Used for onion skin. */
uniform float strokeIndexOffset = 0.0;
-/* All of these attribs are quad loaded the same way
+/* All of these attributes are quad loaded the same way
* as GL_LINES_ADJACENCY would feed a geometry shader:
* - ma reference the previous adjacency point.
* - ma1 reference the current line first point.
@@ -234,7 +236,7 @@ in vec4 uv2;
in vec4 col1;
in vec4 col2;
in vec4 fcol1;
-/* WARNING: Max attrib count is actually 14 because OSX OpenGL implementation
+/* WARNING: Max attribute count is actually 14 because OSX OpenGL implementation
* considers gl_VertexID and gl_InstanceID as vertex attribute. (see T74536) */
# define stroke_id1 ma1.y
# define point_id1 ma1.z
@@ -315,7 +317,7 @@ vec2 safe_normalize_len(vec2 v, out float len)
}
}
-float stroke_thickness_modulate(float thickness)
+float stroke_thickness_modulate(float thickness, out float opacity)
{
/* Modify stroke thickness by object and layer factors.-*/
thickness *= thicknessScale;
@@ -331,6 +333,11 @@ float stroke_thickness_modulate(float thickness)
/* World space point size. */
thickness *= thicknessWorldScale * ProjectionMatrix[1][1] * sizeViewport.y;
}
+ /* To avoid aliasing artifact, we clamp the line thickness and reduce its opacity. */
+ float min_thickness = gl_Position.w * 1.3;
+ opacity = smoothstep(0.0, gl_Position.w * 1.0, thickness);
+ thickness = max(min_thickness, thickness);
+
return thickness;
}
@@ -387,7 +394,7 @@ void stroke_vertex()
mat4 model_mat = model_matrix_get();
- /* Avoid using a vertex attrib for quad positioning. */
+ /* Avoid using a vertex attribute for quad positioning. */
float x = float(gl_VertexID & 1) * 2.0 - 1.0; /* [-1..1] */
float y = float(gl_VertexID & 2) - 1.0; /* [-1..1] */
@@ -412,8 +419,9 @@ void stroke_vertex()
vec2 line = safe_normalize_len(ss2 - ss1, line_len);
vec2 line_adj = safe_normalize((use_curr) ? (ss1 - ss_adj) : (ss_adj - ss2));
+ float small_line_opacity;
float thickness = abs((use_curr) ? thickness1 : thickness2);
- thickness = stroke_thickness_modulate(thickness);
+ thickness = stroke_thickness_modulate(thickness, small_line_opacity);
finalUvs = vec2(x, y) * 0.5 + 0.5;
strokeHardeness = decode_hardness(use_curr ? hardness1 : hardness2);
@@ -471,8 +479,8 @@ void stroke_vertex()
float miter_dot = dot(miter_tan, line_adj);
/* Break corners after a certain angle to avoid really thick corners. */
const float miter_limit = 0.5; /* cos(60°) */
- bool miter_break = (miter_dot < miter_limit) || is_stroke_start || is_stroke_end;
- miter_tan = (miter_break) ? line : (miter_tan / miter_dot);
+ bool miter_break = (miter_dot < miter_limit);
+ miter_tan = (miter_break || is_stroke_start || is_stroke_end) ? line : (miter_tan / miter_dot);
vec2 miter = rotate_90deg(miter_tan);
@@ -485,7 +493,7 @@ void stroke_vertex()
/* Reminder: we packed the cap flag into the sign of stength and thickness sign. */
if ((is_stroke_start && strength1 > 0.0) || (is_stroke_end && thickness1 > 0.0) ||
- miter_break) {
+ (miter_break && !is_stroke_start && !is_stroke_end)) {
screen_ofs += line * x;
}
@@ -503,7 +511,7 @@ void stroke_vertex()
vec4 stroke_col = MATERIAL(m).stroke_color;
float mix_tex = MATERIAL(m).stroke_texture_mix;
- color_output(stroke_col, vert_col, vert_strength, mix_tex);
+ color_output(stroke_col, vert_col, vert_strength * small_line_opacity, mix_tex);
matFlag = MATERIAL(m).flag & ~GP_FILL_FLAGS;
# endif
@@ -572,6 +580,7 @@ void fill_vertex()
finalUvs = rot_scale * uv1.xy + loc;
# endif
+ strokeHardeness = 1.0;
strokeThickness = 1e18;
strokeAspect = vec2(1.0);
strokePt1 = strokePt2 = vec2(0.0);
diff --git a/source/blender/draw/engines/gpencil/shaders/gpencil_frag.glsl b/source/blender/draw/engines/gpencil/shaders/gpencil_frag.glsl
index 8c2032f834a..d81c6f4fe0b 100644
--- a/source/blender/draw/engines/gpencil/shaders/gpencil_frag.glsl
+++ b/source/blender/draw/engines/gpencil/shaders/gpencil_frag.glsl
@@ -99,8 +99,10 @@ void main()
discard;
}
+ vec2 fb_size = max(vec2(textureSize(gpSceneDepthTexture, 0).xy),
+ vec2(textureSize(gpMaskTexture, 0).xy));
+ vec2 uvs = gl_FragCoord.xy / fb_size;
/* Manual depth test */
- vec2 uvs = gl_FragCoord.xy / vec2(textureSize(gpSceneDepthTexture, 0).xy);
float scene_depth = texture(gpSceneDepthTexture, uvs).r;
if (gl_FragCoord.z > scene_depth) {
discard;
diff --git a/source/blender/draw/engines/gpencil/shaders/gpencil_vert.glsl b/source/blender/draw/engines/gpencil/shaders/gpencil_vert.glsl
index c6cfee5ef2d..225601eb9ba 100644
--- a/source/blender/draw/engines/gpencil/shaders/gpencil_vert.glsl
+++ b/source/blender/draw/engines/gpencil/shaders/gpencil_vert.glsl
@@ -2,4 +2,4 @@
void main()
{
gpencil_vertex();
-} \ No newline at end of file
+}
diff --git a/source/blender/draw/engines/overlay/overlay_antialiasing.c b/source/blender/draw/engines/overlay/overlay_antialiasing.c
index efd2f6588ba..a32242d6292 100644
--- a/source/blender/draw/engines/overlay/overlay_antialiasing.c
+++ b/source/blender/draw/engines/overlay/overlay_antialiasing.c
@@ -193,12 +193,6 @@ void OVERLAY_antialiasing_cache_finish(OVERLAY_Data *vedata)
pd->antialiasing.do_depth_infront_copy;
if (pd->xray_enabled || do_wireframe) {
DRW_texture_ensure_fullscreen_2d(&txl->temp_depth_tx, GPU_DEPTH24_STENCIL8, 0);
-
- GPU_framebuffer_ensure_config(&fbl->overlay_xray_depth_copy_fb,
- {
- GPU_ATTACHMENT_TEXTURE(txl->temp_depth_tx),
- GPU_ATTACHMENT_NONE,
- });
}
}
@@ -224,12 +218,13 @@ void OVERLAY_antialiasing_start(OVERLAY_Data *vedata)
void OVERLAY_xray_depth_copy(OVERLAY_Data *vedata)
{
OVERLAY_FramebufferList *fbl = vedata->fbl;
+ OVERLAY_TextureList *txl = vedata->txl;
OVERLAY_PrivateData *pd = vedata->stl->pd;
if (DRW_state_is_fbo() && pd->antialiasing.do_depth_copy) {
+ DefaultTextureList *dtxl = DRW_viewport_texture_list_get();
/* We copy the depth of the rendered geometry to be able to compare to the overlays depth. */
- GPU_framebuffer_blit(
- fbl->overlay_default_fb, 0, fbl->overlay_xray_depth_copy_fb, 0, GPU_DEPTH_BIT);
+ GPU_texture_copy(txl->temp_depth_tx, dtxl->depth);
}
if (DRW_state_is_fbo() && pd->xray_enabled) {
@@ -241,13 +236,13 @@ void OVERLAY_xray_depth_copy(OVERLAY_Data *vedata)
void OVERLAY_xray_depth_infront_copy(OVERLAY_Data *vedata)
{
- OVERLAY_FramebufferList *fbl = vedata->fbl;
+ OVERLAY_TextureList *txl = vedata->txl;
OVERLAY_PrivateData *pd = vedata->stl->pd;
if (DRW_state_is_fbo() && pd->antialiasing.do_depth_infront_copy) {
+ DefaultTextureList *dtxl = DRW_viewport_texture_list_get();
/* We copy the depth of the rendered geometry to be able to compare to the overlays depth. */
- GPU_framebuffer_blit(
- fbl->overlay_in_front_fb, 0, fbl->overlay_xray_depth_copy_fb, 0, GPU_DEPTH_BIT);
+ GPU_texture_copy(txl->temp_depth_tx, dtxl->depth_in_front);
}
}
diff --git a/source/blender/draw/engines/overlay/overlay_armature.c b/source/blender/draw/engines/overlay/overlay_armature.c
index 49dece13869..95fd918f8c1 100644
--- a/source/blender/draw/engines/overlay/overlay_armature.c
+++ b/source/blender/draw/engines/overlay/overlay_armature.c
@@ -137,9 +137,7 @@ void OVERLAY_armature_cache_init(OVERLAY_Data *vedata)
pd->armature.do_pose_fade_geom = pd->armature.do_pose_xray &&
((draw_ctx->object_mode & OB_MODE_WEIGHT_PAINT) == 0) &&
draw_ctx->object_pose != NULL;
-
- DRWState state = DRW_STATE_WRITE_COLOR | DRW_STATE_DEPTH_LESS_EQUAL | DRW_STATE_BLEND_ADD;
- DRW_PASS_CREATE(psl->armature_transp_ps, state | pd->clipping_state);
+ DRWState state;
if (pd->armature.do_pose_fade_geom) {
state = DRW_STATE_WRITE_COLOR | DRW_STATE_DEPTH_EQUAL | DRW_STATE_BLEND_ALPHA;
@@ -163,17 +161,21 @@ void OVERLAY_armature_cache_init(OVERLAY_Data *vedata)
OVERLAY_InstanceFormats *formats = OVERLAY_shader_instance_formats_get();
OVERLAY_ArmatureCallBuffers *cb = &pd->armature_call_buffers[i];
- DRWPass **p_armature_ps = &psl->armature_ps[i];
cb->custom_shapes_ghash = BLI_ghash_ptr_new(__func__);
cb->custom_shapes_transp_ghash = BLI_ghash_ptr_new(__func__);
+ DRWPass **p_armature_ps = &psl->armature_ps[i];
DRWState infront_state = (DRW_state_is_select() && (i == 1)) ? DRW_STATE_IN_FRONT_SELECT : 0;
state = DRW_STATE_WRITE_COLOR | DRW_STATE_DEPTH_LESS_EQUAL | DRW_STATE_WRITE_DEPTH;
DRW_PASS_CREATE(*p_armature_ps, state | pd->clipping_state | infront_state);
-
DRWPass *armature_ps = *p_armature_ps;
+ DRWPass **p_armature_trans_ps = &psl->armature_transp_ps[i];
+ state = DRW_STATE_WRITE_COLOR | DRW_STATE_DEPTH_LESS_EQUAL | DRW_STATE_BLEND_ADD;
+ DRW_PASS_CREATE(*p_armature_trans_ps, state | pd->clipping_state);
+ DRWPass *armature_transp_ps = *p_armature_trans_ps;
+
#define BUF_INSTANCE DRW_shgroup_call_buffer_instance
#define BUF_LINE(grp, format) DRW_shgroup_call_buffer(grp, format, GPU_PRIM_LINES)
@@ -182,7 +184,7 @@ void OVERLAY_armature_cache_init(OVERLAY_Data *vedata)
sh = OVERLAY_shader_armature_sphere(false);
grp = DRW_shgroup_create(sh, armature_ps);
- DRW_shgroup_uniform_block_persistent(grp, "globalsBlock", G_draw.block_ubo);
+ DRW_shgroup_uniform_block(grp, "globalsBlock", G_draw.block_ubo);
DRW_shgroup_uniform_float_copy(grp, "alpha", 1.0f);
cb->point_solid = BUF_INSTANCE(grp, format, DRW_cache_bone_point_get());
@@ -194,7 +196,7 @@ void OVERLAY_armature_cache_init(OVERLAY_Data *vedata)
sh = OVERLAY_shader_armature_shape(false);
grp = DRW_shgroup_create(sh, armature_ps);
- DRW_shgroup_uniform_block_persistent(grp, "globalsBlock", G_draw.block_ubo);
+ DRW_shgroup_uniform_block(grp, "globalsBlock", G_draw.block_ubo);
DRW_shgroup_uniform_float_copy(grp, "alpha", 1.0f);
cb->custom_solid = grp;
cb->box_solid = BUF_INSTANCE(grp, format, DRW_cache_bone_box_get());
@@ -210,29 +212,29 @@ void OVERLAY_armature_cache_init(OVERLAY_Data *vedata)
sh = OVERLAY_shader_armature_sphere(true);
grp = DRW_shgroup_create(sh, armature_ps);
- DRW_shgroup_uniform_block_persistent(grp, "globalsBlock", G_draw.block_ubo);
+ DRW_shgroup_uniform_block(grp, "globalsBlock", G_draw.block_ubo);
cb->point_outline = BUF_INSTANCE(grp, format, DRW_cache_bone_point_wire_outline_get());
sh = OVERLAY_shader_armature_shape(true);
cb->custom_outline = grp = DRW_shgroup_create(sh, armature_ps);
- DRW_shgroup_uniform_block_persistent(grp, "globalsBlock", G_draw.block_ubo);
+ DRW_shgroup_uniform_block(grp, "globalsBlock", G_draw.block_ubo);
cb->box_outline = BUF_INSTANCE(grp, format, DRW_cache_bone_box_wire_get());
cb->octa_outline = BUF_INSTANCE(grp, format, DRW_cache_bone_octahedral_wire_get());
sh = OVERLAY_shader_armature_shape_wire();
cb->custom_wire = grp = DRW_shgroup_create(sh, armature_ps);
- DRW_shgroup_uniform_block_persistent(grp, "globalsBlock", G_draw.block_ubo);
+ DRW_shgroup_uniform_block(grp, "globalsBlock", G_draw.block_ubo);
}
{
format = formats->instance_extra;
sh = OVERLAY_shader_armature_degrees_of_freedom();
grp = DRW_shgroup_create(sh, armature_ps);
- DRW_shgroup_uniform_block_persistent(grp, "globalsBlock", G_draw.block_ubo);
+ DRW_shgroup_uniform_block(grp, "globalsBlock", G_draw.block_ubo);
cb->dof_lines = BUF_INSTANCE(grp, format, DRW_cache_bone_dof_lines_get());
- grp = DRW_shgroup_create(sh, psl->armature_transp_ps);
- DRW_shgroup_uniform_block_persistent(grp, "globalsBlock", G_draw.block_ubo);
+ grp = DRW_shgroup_create(sh, armature_transp_ps);
+ DRW_shgroup_uniform_block(grp, "globalsBlock", G_draw.block_ubo);
cb->dof_sphere = BUF_INSTANCE(grp, format, DRW_cache_bone_dof_sphere_get());
}
{
@@ -240,7 +242,7 @@ void OVERLAY_armature_cache_init(OVERLAY_Data *vedata)
sh = OVERLAY_shader_armature_stick();
grp = DRW_shgroup_create(sh, armature_ps);
- DRW_shgroup_uniform_block_persistent(grp, "globalsBlock", G_draw.block_ubo);
+ DRW_shgroup_uniform_block(grp, "globalsBlock", G_draw.block_ubo);
cb->stick = BUF_INSTANCE(grp, format, DRW_cache_bone_stick_get());
}
{
@@ -249,7 +251,7 @@ void OVERLAY_armature_cache_init(OVERLAY_Data *vedata)
sh = OVERLAY_shader_armature_envelope(false);
grp = DRW_shgroup_create(sh, armature_ps);
DRW_shgroup_state_enable(grp, DRW_STATE_CULL_BACK);
- DRW_shgroup_uniform_block_persistent(grp, "globalsBlock", G_draw.block_ubo);
+ DRW_shgroup_uniform_block(grp, "globalsBlock", G_draw.block_ubo);
DRW_shgroup_uniform_bool_copy(grp, "isDistance", false);
DRW_shgroup_uniform_float_copy(grp, "alpha", 1.0f);
cb->envelope_solid = BUF_INSTANCE(grp, format, DRW_cache_bone_envelope_solid_get());
@@ -264,14 +266,14 @@ void OVERLAY_armature_cache_init(OVERLAY_Data *vedata)
sh = OVERLAY_shader_armature_envelope(true);
grp = DRW_shgroup_create(sh, armature_ps);
- DRW_shgroup_uniform_block_persistent(grp, "globalsBlock", G_draw.block_ubo);
+ DRW_shgroup_uniform_block(grp, "globalsBlock", G_draw.block_ubo);
cb->envelope_outline = BUF_INSTANCE(grp, format, DRW_cache_bone_envelope_outline_get());
format = formats->instance_bone_envelope_distance;
sh = OVERLAY_shader_armature_envelope(false);
- grp = DRW_shgroup_create(sh, psl->armature_transp_ps);
- DRW_shgroup_uniform_block_persistent(grp, "globalsBlock", G_draw.block_ubo);
+ grp = DRW_shgroup_create(sh, armature_transp_ps);
+ DRW_shgroup_uniform_block(grp, "globalsBlock", G_draw.block_ubo);
DRW_shgroup_uniform_bool_copy(grp, "isDistance", true);
DRW_shgroup_state_enable(grp, DRW_STATE_CULL_FRONT);
cb->envelope_distance = BUF_INSTANCE(grp, format, DRW_cache_bone_envelope_solid_get());
@@ -281,7 +283,7 @@ void OVERLAY_armature_cache_init(OVERLAY_Data *vedata)
sh = OVERLAY_shader_armature_wire();
grp = DRW_shgroup_create(sh, armature_ps);
- DRW_shgroup_uniform_block_persistent(grp, "globalsBlock", G_draw.block_ubo);
+ DRW_shgroup_uniform_block(grp, "globalsBlock", G_draw.block_ubo);
cb->wire = BUF_LINE(grp, format);
}
}
@@ -1341,8 +1343,8 @@ static void draw_points(ArmatureDrawContext *ctx,
bone_hint_color_shade(col_hint_tail, (ctx->const_color) ? col_solid_tail : col_wire_tail);
/* Draw root point if we are not connected to our parent */
- if (!(eBone ? (eBone->parent && (eBone->flag & BONE_CONNECTED)) :
- (pchan->bone->parent && (pchan->bone->flag & BONE_CONNECTED)))) {
+ if (!(eBone ? (eBone->parent && (boneflag & BONE_CONNECTED)) :
+ (pchan->bone->parent && (boneflag & BONE_CONNECTED)))) {
if (select_id != -1) {
DRW_select_load_id(select_id | BONESEL_ROOT);
}
@@ -1522,8 +1524,8 @@ static void draw_bone_line(ArmatureDrawContext *ctx,
}
/* Draw root point if we are not connected to our parent. */
- if (!(eBone ? (eBone->parent && (eBone->flag & BONE_CONNECTED)) :
- (pchan->bone->parent && (pchan->bone->flag & BONE_CONNECTED)))) {
+ if (!(eBone ? (eBone->parent && (boneflag & BONE_CONNECTED)) :
+ (pchan->bone->parent && (boneflag & BONE_CONNECTED)))) {
if (eBone) {
col_head = (eBone->flag & BONE_ROOTSEL) ? G_draw.block.colorVertexSelect : col_bone;
@@ -2204,7 +2206,7 @@ void OVERLAY_armature_cache_populate(OVERLAY_Data *vedata, Object *ob)
static bool POSE_is_driven_by_active_armature(Object *ob)
{
- Object *ob_arm = modifiers_isDeformedByArmature(ob);
+ Object *ob_arm = BKE_modifiers_is_deformed_by_armature(ob);
if (ob_arm) {
const DRWContextState *draw_ctx = DRW_context_state_get();
bool is_active = OVERLAY_armature_is_pose_mode(ob_arm, draw_ctx);
@@ -2214,7 +2216,7 @@ static bool POSE_is_driven_by_active_armature(Object *ob)
return is_active;
}
else {
- Object *ob_mesh_deform = modifiers_isDeformedByMeshDeform(ob);
+ Object *ob_mesh_deform = BKE_modifiers_is_deformed_by_meshdeform(ob);
if (ob_mesh_deform) {
/* Recursive. */
return POSE_is_driven_by_active_armature(ob_mesh_deform);
@@ -2255,7 +2257,7 @@ void OVERLAY_armature_draw(OVERLAY_Data *vedata)
{
OVERLAY_PassList *psl = vedata->psl;
- DRW_draw_pass(psl->armature_transp_ps);
+ DRW_draw_pass(psl->armature_transp_ps[0]);
DRW_draw_pass(psl->armature_ps[0]);
}
@@ -2264,6 +2266,7 @@ void OVERLAY_armature_in_front_draw(OVERLAY_Data *vedata)
OVERLAY_PassList *psl = vedata->psl;
if (psl->armature_bone_select_ps == NULL || DRW_state_is_select()) {
+ DRW_draw_pass(psl->armature_transp_ps[1]);
DRW_draw_pass(psl->armature_ps[1]);
}
}
@@ -2285,6 +2288,7 @@ void OVERLAY_pose_draw(OVERLAY_Data *vedata)
GPU_framebuffer_clear_depth(fbl->overlay_line_in_front_fb, 1.0f);
}
+ DRW_draw_pass(psl->armature_transp_ps[1]);
DRW_draw_pass(psl->armature_ps[1]);
}
}
diff --git a/source/blender/draw/engines/overlay/overlay_background.c b/source/blender/draw/engines/overlay/overlay_background.c
index f1ffa9035e0..f52ae691a35 100644
--- a/source/blender/draw/engines/overlay/overlay_background.c
+++ b/source/blender/draw/engines/overlay/overlay_background.c
@@ -71,15 +71,16 @@ void OVERLAY_background_cache_init(OVERLAY_Data *vedata)
}
else {
switch (UI_GetThemeValue(TH_BACKGROUND_TYPE)) {
- case TH_BACKGROUND_SINGLE_COLOR:
- background_type = BG_SOLID;
- break;
case TH_BACKGROUND_GRADIENT_LINEAR:
background_type = BG_GRADIENT;
break;
case TH_BACKGROUND_GRADIENT_RADIAL:
background_type = BG_RADIAL;
break;
+ default:
+ case TH_BACKGROUND_SINGLE_COLOR:
+ background_type = BG_SOLID;
+ break;
}
}
diff --git a/source/blender/draw/engines/overlay/overlay_edit_curve.c b/source/blender/draw/engines/overlay/overlay_edit_curve.c
index d9b9fac6b4b..9a79c78c996 100644
--- a/source/blender/draw/engines/overlay/overlay_edit_curve.c
+++ b/source/blender/draw/engines/overlay/overlay_edit_curve.c
@@ -36,7 +36,8 @@ void OVERLAY_edit_curve_cache_init(OVERLAY_Data *vedata)
GPUShader *sh;
DRWState state;
- pd->edit_curve.show_handles = (v3d->overlay.edit_flag & V3D_OVERLAY_EDIT_CU_HANDLES) != 0;
+ pd->edit_curve.show_handles = v3d->overlay.handle_display != CURVE_HANDLE_NONE;
+ pd->edit_curve.handle_display = v3d->overlay.handle_display;
pd->shdata.edit_curve_normal_length = v3d->overlay.normals_length;
/* Run Twice for in-front passes. */
@@ -62,10 +63,13 @@ void OVERLAY_edit_curve_cache_init(OVERLAY_Data *vedata)
pd->edit_curve_handle_grp = grp = DRW_shgroup_create(sh, psl->edit_curve_handle_ps);
DRW_shgroup_uniform_block(grp, "globalsBlock", G_draw.block_ubo);
DRW_shgroup_uniform_bool_copy(grp, "showCurveHandles", pd->edit_curve.show_handles);
+ DRW_shgroup_uniform_int_copy(grp, "curveHandleDisplay", pd->edit_curve.handle_display);
DRW_shgroup_state_enable(grp, DRW_STATE_BLEND_ALPHA);
sh = OVERLAY_shader_edit_curve_point();
pd->edit_curve_points_grp = grp = DRW_shgroup_create(sh, psl->edit_curve_handle_ps);
+ DRW_shgroup_uniform_bool_copy(grp, "showCurveHandles", pd->edit_curve.show_handles);
+ DRW_shgroup_uniform_int_copy(grp, "curveHandleDisplay", pd->edit_curve.handle_display);
DRW_shgroup_uniform_block(grp, "globalsBlock", G_draw.block_ubo);
}
}
@@ -94,7 +98,7 @@ void OVERLAY_edit_curve_cache_populate(OVERLAY_Data *vedata, Object *ob)
DRW_shgroup_call_no_cull(pd->edit_curve_handle_grp, geom, ob);
}
- geom = DRW_cache_curve_vert_overlay_get(ob, pd->edit_curve.show_handles);
+ geom = DRW_cache_curve_vert_overlay_get(ob);
if (geom) {
DRW_shgroup_call_no_cull(pd->edit_curve_points_grp, geom, ob);
}
@@ -110,7 +114,7 @@ void OVERLAY_edit_surf_cache_populate(OVERLAY_Data *vedata, Object *ob)
DRW_shgroup_call_no_cull(pd->edit_curve_handle_grp, geom, ob);
}
- geom = DRW_cache_curve_vert_overlay_get(ob, false);
+ geom = DRW_cache_curve_vert_overlay_get(ob);
if (geom) {
DRW_shgroup_call_no_cull(pd->edit_curve_points_grp, geom, ob);
}
diff --git a/source/blender/draw/engines/overlay/overlay_edit_mesh.c b/source/blender/draw/engines/overlay/overlay_edit_mesh.c
index 400947ea819..7fc1a7fdce6 100644
--- a/source/blender/draw/engines/overlay/overlay_edit_mesh.c
+++ b/source/blender/draw/engines/overlay/overlay_edit_mesh.c
@@ -118,18 +118,6 @@ void OVERLAY_edit_mesh_cache_init(OVERLAY_Data *vedata)
show_face_dots = true;
}
- {
- /* TODO(fclem) Shouldn't this be going into the paint overlay? */
- state = DRW_STATE_WRITE_COLOR | DRW_STATE_WRITE_DEPTH | DRW_STATE_DEPTH_LESS_EQUAL;
- DRW_PASS_CREATE(psl->edit_mesh_weight_ps, state | pd->clipping_state);
-
- sh = OVERLAY_shader_paint_weight();
- pd->edit_mesh_weight_grp = grp = DRW_shgroup_create(sh, psl->edit_mesh_weight_ps);
- DRW_shgroup_uniform_float_copy(grp, "opacity", 1.0);
- DRW_shgroup_uniform_bool_copy(grp, "drawContours", false);
- DRW_shgroup_uniform_texture(grp, "colorramp", G_draw.weight_ramp);
- DRW_shgroup_uniform_block(grp, "globalsBlock", G_draw.block_ubo);
- }
/* Run Twice for in-front passes. */
for (int i = 0; i < 2; i++) {
/* Complementary Depth Pass */
@@ -266,7 +254,7 @@ static void overlay_edit_mesh_add_ob_to_pass(OVERLAY_PrivateData *pd, Object *ob
if (has_skin_roots) {
circle = DRW_cache_circle_get();
skin_roots = DRW_mesh_batch_cache_get_edit_skin_roots(ob->data);
- DRW_shgroup_call_instances_with_attribs(skin_roots_shgrp, ob, circle, skin_roots);
+ DRW_shgroup_call_instances_with_attrs(skin_roots_shgrp, ob, circle, skin_roots);
}
}
@@ -283,17 +271,12 @@ void OVERLAY_edit_mesh_cache_populate(OVERLAY_Data *vedata, Object *ob)
bool do_in_front = (ob->dtx & OB_DRAWXRAY) != 0;
bool do_occlude_wire = (pd->edit_mesh.flag & V3D_OVERLAY_EDIT_OCCLUDE_WIRE) != 0;
- bool do_show_weight = (pd->edit_mesh.flag & V3D_OVERLAY_EDIT_WEIGHT) != 0;
bool do_show_mesh_analysis = (pd->edit_mesh.flag & V3D_OVERLAY_EDIT_STATVIS) != 0;
bool fnormals_do = (pd->edit_mesh.flag & V3D_OVERLAY_EDIT_FACE_NORMALS) != 0;
bool vnormals_do = (pd->edit_mesh.flag & V3D_OVERLAY_EDIT_VERT_NORMALS) != 0;
bool lnormals_do = (pd->edit_mesh.flag & V3D_OVERLAY_EDIT_LOOP_NORMALS) != 0;
- if (do_show_weight) {
- geom = DRW_cache_mesh_surface_weights_get(ob);
- DRW_shgroup_call_no_cull(pd->edit_mesh_weight_grp, geom, ob);
- }
- else if (do_show_mesh_analysis && !pd->xray_enabled) {
+ if (do_show_mesh_analysis && !pd->xray_enabled) {
geom = DRW_cache_mesh_surface_mesh_analysis_get(ob);
if (geom) {
DRW_shgroup_call_no_cull(pd->edit_mesh_analysis_grp, geom, ob);
@@ -309,15 +292,15 @@ void OVERLAY_edit_mesh_cache_populate(OVERLAY_Data *vedata, Object *ob)
struct GPUBatch *normal_geom = DRW_cache_normal_arrow_get();
if (vnormals_do) {
geom = DRW_mesh_batch_cache_get_edit_vnors(ob->data);
- DRW_shgroup_call_instances_with_attribs(pd->edit_mesh_normals_grp, ob, normal_geom, geom);
+ DRW_shgroup_call_instances_with_attrs(pd->edit_mesh_normals_grp, ob, normal_geom, geom);
}
if (lnormals_do) {
geom = DRW_mesh_batch_cache_get_edit_lnors(ob->data);
- DRW_shgroup_call_instances_with_attribs(pd->edit_mesh_normals_grp, ob, normal_geom, geom);
+ DRW_shgroup_call_instances_with_attrs(pd->edit_mesh_normals_grp, ob, normal_geom, geom);
}
if (fnormals_do) {
geom = DRW_mesh_batch_cache_get_edit_facedots(ob->data);
- DRW_shgroup_call_instances_with_attribs(pd->edit_mesh_normals_grp, ob, normal_geom, geom);
+ DRW_shgroup_call_instances_with_attrs(pd->edit_mesh_normals_grp, ob, normal_geom, geom);
}
}
@@ -364,7 +347,6 @@ void OVERLAY_edit_mesh_draw(OVERLAY_Data *vedata)
GPU_framebuffer_bind(fbl->overlay_default_fb);
}
- DRW_draw_pass(psl->edit_mesh_weight_ps);
DRW_draw_pass(psl->edit_mesh_analysis_ps);
DRW_draw_pass(psl->edit_mesh_depth_ps[NOT_IN_FRONT]);
diff --git a/source/blender/draw/engines/overlay/overlay_edit_text.c b/source/blender/draw/engines/overlay/overlay_edit_text.c
index 3de0155d6e0..c4d020adc11 100644
--- a/source/blender/draw/engines/overlay/overlay_edit_text.c
+++ b/source/blender/draw/engines/overlay/overlay_edit_text.c
@@ -38,7 +38,8 @@ void OVERLAY_edit_text_cache_init(OVERLAY_Data *vedata)
GPUShader *sh;
DRWState state;
- pd->edit_curve.show_handles = (v3d->overlay.edit_flag & V3D_OVERLAY_EDIT_CU_HANDLES) != 0;
+ pd->edit_curve.show_handles = v3d->overlay.handle_display != CURVE_HANDLE_NONE;
+ pd->edit_curve.handle_display = v3d->overlay.handle_display;
pd->shdata.edit_curve_normal_length = v3d->overlay.normals_length;
/* Run Twice for in-front passes. */
diff --git a/source/blender/draw/engines/overlay/overlay_engine.c b/source/blender/draw/engines/overlay/overlay_engine.c
index 97f6b91b7a9..61337ac8d1d 100644
--- a/source/blender/draw/engines/overlay/overlay_engine.c
+++ b/source/blender/draw/engines/overlay/overlay_engine.c
@@ -30,6 +30,7 @@
#include "ED_view3d.h"
#include "BKE_object.h"
+#include "BKE_paint.h"
#include "overlay_engine.h"
#include "overlay_private.h"
@@ -45,6 +46,8 @@ static void OVERLAY_engine_init(void *vedata)
const DRWContextState *draw_ctx = DRW_context_state_get();
const RegionView3D *rv3d = draw_ctx->rv3d;
const View3D *v3d = draw_ctx->v3d;
+ const Scene *scene = draw_ctx->scene;
+ const ToolSettings *ts = scene->toolsettings;
if (!stl->pd) {
/* Alloc transient pointers */
@@ -69,12 +72,24 @@ static void OVERLAY_engine_init(void *vedata)
pd->overlay.flag = V3D_OVERLAY_HIDE_TEXT | V3D_OVERLAY_HIDE_MOTION_PATHS |
V3D_OVERLAY_HIDE_BONES | V3D_OVERLAY_HIDE_OBJECT_XTRAS |
V3D_OVERLAY_HIDE_OBJECT_ORIGINS;
+ pd->overlay.wireframe_threshold = v3d->overlay.wireframe_threshold;
}
if (v3d->shading.type == OB_WIRE) {
pd->overlay.flag |= V3D_OVERLAY_WIREFRAMES;
}
+ if (ts->sculpt) {
+ if (ts->sculpt->flags & SCULPT_HIDE_FACE_SETS) {
+ pd->overlay.sculpt_mode_face_sets_opacity = 0.0f;
+ }
+ if (ts->sculpt->flags & SCULPT_HIDE_MASK) {
+ pd->overlay.sculpt_mode_mask_opacity = 0.0f;
+ }
+ }
+
+ pd->use_in_front = (v3d->shading.type <= OB_SOLID) ||
+ BKE_scene_uses_blender_workbench(draw_ctx->scene);
pd->wireframe_mode = (v3d->shading.type == OB_WIRE);
pd->clipping_state = RV3D_CLIPPING_ENABLED(v3d, rv3d) ? DRW_STATE_CLIP_PLANES : 0;
pd->xray_opacity = XRAY_ALPHA(v3d);
@@ -110,6 +125,11 @@ static void OVERLAY_cache_init(void *vedata)
switch (pd->ctx_mode) {
case CTX_MODE_EDIT_MESH:
OVERLAY_edit_mesh_cache_init(vedata);
+ /* `pd->edit_mesh.flag` is valid after calling `OVERLAY_edit_mesh_cache_init`. */
+ const bool draw_edit_weights = (pd->edit_mesh.flag & V3D_OVERLAY_EDIT_WEIGHT);
+ if (draw_edit_weights) {
+ OVERLAY_paint_cache_init(vedata);
+ }
break;
case CTX_MODE_EDIT_SURFACE:
case CTX_MODE_EDIT_CURVE:
@@ -226,10 +246,12 @@ static void OVERLAY_cache_populate(void *vedata, Object *ob)
const bool renderable = DRW_object_is_renderable(ob);
const bool in_pose_mode = ob->type == OB_ARMATURE && OVERLAY_armature_is_pose_mode(ob, draw_ctx);
const bool in_edit_mode = overlay_object_is_edit_mode(pd, ob);
- const bool in_particle_edit_mode = ob->mode == OB_MODE_PARTICLE_EDIT;
+ const bool in_particle_edit_mode = (ob->mode == OB_MODE_PARTICLE_EDIT) &&
+ (pd->ctx_mode == CTX_MODE_PARTICLE);
const bool in_paint_mode = (ob == draw_ctx->obact) &&
(draw_ctx->object_mode & OB_MODE_ALL_PAINT);
- const bool in_sculpt_mode = (ob == draw_ctx->obact) && (ob->sculpt != NULL);
+ const bool in_sculpt_mode = (ob == draw_ctx->obact) && (ob->sculpt != NULL) &&
+ (ob->sculpt->mode_type == OB_MODE_SCULPT);
const bool has_surface = ELEM(ob->type,
OB_MESH,
OB_CURVE,
@@ -241,7 +263,8 @@ static void OVERLAY_cache_populate(void *vedata, Object *ob)
OB_POINTCLOUD,
OB_VOLUME);
const bool draw_surface = (ob->dt >= OB_WIRE) && (renderable || (ob->dt == OB_WIRE));
- const bool draw_facing = draw_surface && (pd->overlay.flag & V3D_OVERLAY_FACE_ORIENTATION);
+ const bool draw_facing = draw_surface && (pd->overlay.flag & V3D_OVERLAY_FACE_ORIENTATION) &&
+ !is_select;
const bool draw_bones = (pd->overlay.flag & V3D_OVERLAY_HIDE_BONES) == 0;
const bool draw_wires = draw_surface && has_surface &&
(pd->wireframe_mode || !pd->hide_overlays);
@@ -250,6 +273,7 @@ static void OVERLAY_cache_populate(void *vedata, Object *ob)
(ob->base_flag & BASE_SELECTED);
const bool draw_bone_selection = (ob->type == OB_MESH) && pd->armature.do_pose_fade_geom &&
!is_select;
+ const bool draw_edit_weights = in_edit_mode && (pd->edit_mesh.flag & V3D_OVERLAY_EDIT_WEIGHT);
const bool draw_extras =
(!pd->hide_overlays) &&
(((pd->overlay.flag & V3D_OVERLAY_HIDE_OBJECT_XTRAS) == 0) ||
@@ -278,6 +302,9 @@ static void OVERLAY_cache_populate(void *vedata, Object *ob)
switch (ob->type) {
case OB_MESH:
OVERLAY_edit_mesh_cache_populate(vedata, ob);
+ if (draw_edit_weights) {
+ OVERLAY_paint_weight_cache_populate(vedata, ob);
+ }
break;
case OB_ARMATURE:
if (draw_bones) {
@@ -469,6 +496,12 @@ static void OVERLAY_draw_scene(void *vedata)
OVERLAY_xray_depth_infront_copy(vedata);
if (DRW_state_is_fbo()) {
+ GPU_framebuffer_bind(fbl->overlay_in_front_fb);
+ }
+
+ OVERLAY_facing_infront_draw(vedata);
+
+ if (DRW_state_is_fbo()) {
GPU_framebuffer_bind(fbl->overlay_line_in_front_fb);
}
@@ -485,7 +518,7 @@ static void OVERLAY_draw_scene(void *vedata)
OVERLAY_motion_path_draw(vedata);
OVERLAY_extra_centers_draw(vedata);
- if (DRW_state_is_select()) {
+ if (DRW_state_is_select() || DRW_state_is_depth()) {
/* Edit modes have their own selection code. */
return;
}
@@ -494,6 +527,7 @@ static void OVERLAY_draw_scene(void *vedata)
switch (pd->ctx_mode) {
case CTX_MODE_EDIT_MESH:
+ OVERLAY_paint_draw(vedata);
OVERLAY_edit_mesh_draw(vedata);
break;
case CTX_MODE_EDIT_SURFACE:
diff --git a/source/blender/draw/engines/overlay/overlay_extra.c b/source/blender/draw/engines/overlay/overlay_extra.c
index bc0797eff0d..859f3f93b1d 100644
--- a/source/blender/draw/engines/overlay/overlay_extra.c
+++ b/source/blender/draw/engines/overlay/overlay_extra.c
@@ -24,7 +24,7 @@
#include "UI_resources.h"
-#include "BKE_anim.h"
+#include "BKE_anim_path.h"
#include "BKE_camera.h"
#include "BKE_constraint.h"
#include "BKE_curve.h"
@@ -36,6 +36,8 @@
#include "BKE_object.h"
#include "BKE_tracking.h"
+#include "BLI_listbase.h"
+
#include "DNA_camera_types.h"
#include "DNA_constraint_types.h"
#include "DNA_curve_types.h"
@@ -63,6 +65,7 @@ void OVERLAY_extra_cache_init(OVERLAY_Data *vedata)
OVERLAY_PassList *psl = vedata->psl;
OVERLAY_TextureList *txl = vedata->txl;
OVERLAY_PrivateData *pd = vedata->stl->pd;
+ const bool is_select = DRW_state_is_select();
DRWState state_blend = DRW_STATE_WRITE_COLOR | DRW_STATE_BLEND_ALPHA;
DRW_PASS_CREATE(psl->extra_blend_ps, state_blend | pd->clipping_state);
@@ -78,8 +81,8 @@ void OVERLAY_extra_cache_init(OVERLAY_Data *vedata)
struct GPUTexture *tex = DRW_state_is_fbo() ? dtxl->depth : txl->dummy_depth_tx;
pd->extra_grid_grp = grp = DRW_shgroup_create(sh, psl->extra_grid_ps);
- DRW_shgroup_uniform_texture_persistent(grp, "depthBuffer", tex);
- DRW_shgroup_uniform_block_persistent(grp, "globalsBlock", G_draw.block_ubo);
+ DRW_shgroup_uniform_texture(grp, "depthBuffer", tex);
+ DRW_shgroup_uniform_block(grp, "globalsBlock", G_draw.block_ubo);
DRW_shgroup_uniform_bool_copy(grp, "isTransform", (G.moving & G_TRANSFORM_OBJ) != 0);
}
@@ -106,10 +109,10 @@ void OVERLAY_extra_cache_init(OVERLAY_Data *vedata)
/* Sorted by shader to avoid state changes during render. */
{
format = formats->instance_extra;
- sh = OVERLAY_shader_extra();
+ sh = OVERLAY_shader_extra(is_select);
grp = DRW_shgroup_create(sh, extra_ps);
- DRW_shgroup_uniform_block_persistent(grp, "globalsBlock", G_draw.block_ubo);
+ DRW_shgroup_uniform_block(grp, "globalsBlock", G_draw.block_ubo);
grp_sub = DRW_shgroup_create_sub(grp);
cb->camera_distances = BUF_INSTANCE(grp_sub, format, DRW_cache_camera_distances_get());
@@ -154,7 +157,7 @@ void OVERLAY_extra_cache_init(OVERLAY_Data *vedata)
{
format = formats->instance_extra;
grp = DRW_shgroup_create(sh, psl->extra_blend_ps); /* NOTE: not the same pass! */
- DRW_shgroup_uniform_block_persistent(grp, "globalsBlock", G_draw.block_ubo);
+ DRW_shgroup_uniform_block(grp, "globalsBlock", G_draw.block_ubo);
grp_sub = DRW_shgroup_create_sub(grp);
DRW_shgroup_state_enable(grp_sub, DRW_STATE_DEPTH_LESS_EQUAL | DRW_STATE_CULL_BACK);
@@ -171,38 +174,38 @@ void OVERLAY_extra_cache_init(OVERLAY_Data *vedata)
sh = OVERLAY_shader_extra_groundline();
grp = DRW_shgroup_create(sh, extra_ps);
- DRW_shgroup_uniform_block_persistent(grp, "globalsBlock", G_draw.block_ubo);
+ DRW_shgroup_uniform_block(grp, "globalsBlock", G_draw.block_ubo);
DRW_shgroup_state_enable(grp, DRW_STATE_BLEND_ALPHA);
cb->groundline = BUF_INSTANCE(grp, format, DRW_cache_groundline_get());
}
{
- sh = OVERLAY_shader_extra_wire(false);
+ sh = OVERLAY_shader_extra_wire(false, is_select);
grp = DRW_shgroup_create(sh, extra_ps);
- DRW_shgroup_uniform_block_persistent(grp, "globalsBlock", G_draw.block_ubo);
+ DRW_shgroup_uniform_block(grp, "globalsBlock", G_draw.block_ubo);
cb->extra_dashed_lines = BUF_LINE(grp, formats->pos_color);
cb->extra_lines = BUF_LINE(grp, formats->wire_extra);
}
{
- sh = OVERLAY_shader_extra_wire(true);
+ sh = OVERLAY_shader_extra_wire(true, is_select);
cb->extra_wire = grp = DRW_shgroup_create(sh, extra_ps);
- DRW_shgroup_uniform_block_persistent(grp, "globalsBlock", G_draw.block_ubo);
+ DRW_shgroup_uniform_block(grp, "globalsBlock", G_draw.block_ubo);
}
{
sh = OVERLAY_shader_extra_loose_point();
cb->extra_loose_points = grp = DRW_shgroup_create(sh, extra_ps);
- DRW_shgroup_uniform_block_persistent(grp, "globalsBlock", G_draw.block_ubo);
+ DRW_shgroup_uniform_block(grp, "globalsBlock", G_draw.block_ubo);
}
{
format = formats->pos;
sh = OVERLAY_shader_extra_point();
grp = DRW_shgroup_create(sh, psl->extra_centers_ps); /* NOTE: not the same pass! */
- DRW_shgroup_uniform_block_persistent(grp, "globalsBlock", G_draw.block_ubo);
+ DRW_shgroup_uniform_block(grp, "globalsBlock", G_draw.block_ubo);
grp_sub = DRW_shgroup_create_sub(grp);
DRW_shgroup_uniform_vec4_copy(grp_sub, "color", G_draw.block.colorActive);
@@ -766,10 +769,7 @@ void OVERLAY_lightprobe_cache_populate(OVERLAY_Data *vedata, Object *ob)
uint cell_count = prb->grid_resolution_x * prb->grid_resolution_y * prb->grid_resolution_z;
DRWShadingGroup *grp = DRW_shgroup_create_sub(vedata->stl->pd->extra_grid_grp);
- DRW_shgroup_uniform_vec4_copy(grp, "gridModelMatrix[0]", instdata.mat[0]);
- DRW_shgroup_uniform_vec4_copy(grp, "gridModelMatrix[1]", instdata.mat[1]);
- DRW_shgroup_uniform_vec4_copy(grp, "gridModelMatrix[2]", instdata.mat[2]);
- DRW_shgroup_uniform_vec4_copy(grp, "gridModelMatrix[3]", instdata.mat[3]);
+ DRW_shgroup_uniform_vec4_array_copy(grp, "gridModelMatrix", instdata.mat, 4);
DRW_shgroup_call_procedural_points(grp, NULL, cell_count);
}
break;
@@ -911,7 +911,7 @@ static void camera_view3d_reconstruction(OVERLAY_ExtraCallBuffers *cb,
}
ListBase *tracksbase = BKE_tracking_object_get_tracks(tracking, tracking_object);
- for (MovieTrackingTrack *track = tracksbase->first; track; track = track->next) {
+ LISTBASE_FOREACH (MovieTrackingTrack *, track, tracksbase) {
if ((track->flag & TRACK_HAS_BUNDLE) == 0) {
continue;
}
@@ -1158,6 +1158,10 @@ void OVERLAY_camera_cache_populate(OVERLAY_Data *vedata, Object *ob)
}
else {
copy_v3_fl3(scale, len_v3(ob->obmat[0]), len_v3(ob->obmat[1]), len_v3(ob->obmat[2]));
+ /* Avoid division by 0. */
+ if (ELEM(0.0f, scale[0], scale[1], scale[2])) {
+ return;
+ }
invert_v3(scale);
}
@@ -1367,9 +1371,9 @@ static void OVERLAY_volume_extra(OVERLAY_ExtraCallBuffers *cb,
madd_v3fl_v3fl_v3fl_v3i(min, mds->p0, mds->cell_size, mds->res_min);
float voxel_cubemat[4][4] = {{0.0f}};
/* scale small cube to voxel size */
- voxel_cubemat[0][0] = 1.0f / (float)mds->base_res[0];
- voxel_cubemat[1][1] = 1.0f / (float)mds->base_res[1];
- voxel_cubemat[2][2] = 1.0f / (float)mds->base_res[2];
+ voxel_cubemat[0][0] = mds->cell_size[0] / 2.0f;
+ voxel_cubemat[1][1] = mds->cell_size[1] / 2.0f;
+ voxel_cubemat[2][2] = mds->cell_size[2] / 2.0f;
voxel_cubemat[3][3] = 1.0f;
/* translate small cube to corner */
copy_v3_v3(voxel_cubemat[3], min);
@@ -1500,8 +1504,9 @@ void OVERLAY_extra_cache_populate(OVERLAY_Data *vedata, Object *ob)
const bool draw_xform = draw_ctx->object_mode == OB_MODE_OBJECT &&
(scene->toolsettings->transform_flag & SCE_XFORM_DATA_ORIGIN) &&
(ob->base_flag & BASE_SELECTED) && !is_select_mode;
- const bool draw_volume = !from_dupli && (md = modifiers_findByType(ob, eModifierType_Fluid)) &&
- (modifier_isEnabled(scene, md, eModifierMode_Realtime)) &&
+ const bool draw_volume = !from_dupli &&
+ (md = BKE_modifiers_findby_type(ob, eModifierType_Fluid)) &&
+ (BKE_modifier_is_enabled(scene, md, eModifierMode_Realtime)) &&
(((FluidModifierData *)md)->domain != NULL);
float *color;
diff --git a/source/blender/draw/engines/overlay/overlay_facing.c b/source/blender/draw/engines/overlay/overlay_facing.c
index 872fa0e8796..4eb4b8ae85b 100644
--- a/source/blender/draw/engines/overlay/overlay_facing.c
+++ b/source/blender/draw/engines/overlay/overlay_facing.c
@@ -34,28 +34,41 @@ void OVERLAY_facing_cache_init(OVERLAY_Data *vedata)
OVERLAY_PassList *psl = vedata->psl;
OVERLAY_PrivateData *pd = vedata->stl->pd;
- DRWState state = DRW_STATE_WRITE_COLOR | DRW_STATE_DEPTH_EQUAL | DRW_STATE_BLEND_ALPHA;
- DRW_PASS_CREATE(psl->facing_ps, state | pd->clipping_state);
+ for (int i = 0; i < 2; i++) {
+ /* Non Meshes Pass (Camera, empties, lights ...) */
+ DRWState state = DRW_STATE_WRITE_COLOR | DRW_STATE_DEPTH_EQUAL | DRW_STATE_BLEND_ALPHA;
+ DRW_PASS_CREATE(psl->facing_ps[i], state | pd->clipping_state);
- GPUShader *sh = OVERLAY_shader_facing();
- pd->facing_grp = DRW_shgroup_create(sh, psl->facing_ps);
- DRW_shgroup_uniform_block_persistent(pd->facing_grp, "globalsBlock", G_draw.block_ubo);
+ GPUShader *sh = OVERLAY_shader_facing();
+ pd->facing_grp[i] = DRW_shgroup_create(sh, psl->facing_ps[i]);
+ DRW_shgroup_uniform_block(pd->facing_grp[i], "globalsBlock", G_draw.block_ubo);
+ }
+
+ if (!pd->use_in_front) {
+ pd->facing_grp[IN_FRONT] = pd->facing_grp[NOT_IN_FRONT];
+ }
}
void OVERLAY_facing_cache_populate(OVERLAY_Data *vedata, Object *ob)
{
OVERLAY_PrivateData *pd = vedata->stl->pd;
+ if (pd->xray_enabled) {
+ return;
+ }
+
const DRWContextState *draw_ctx = DRW_context_state_get();
const bool use_sculpt_pbvh = BKE_sculptsession_use_pbvh_draw(ob, draw_ctx->v3d) &&
!DRW_state_is_image_render();
+ const bool is_xray = (ob->dtx & OB_DRAWXRAY) != 0;
+
if (use_sculpt_pbvh) {
- DRW_shgroup_call_sculpt(pd->facing_grp, ob, false, false, false);
+ DRW_shgroup_call_sculpt(pd->facing_grp[is_xray], ob, false, false);
}
else {
struct GPUBatch *geom = DRW_cache_object_surface_get(ob);
if (geom) {
- DRW_shgroup_call(pd->facing_grp, geom, ob);
+ DRW_shgroup_call(pd->facing_grp[is_xray], geom, ob);
}
}
}
@@ -64,5 +77,12 @@ void OVERLAY_facing_draw(OVERLAY_Data *vedata)
{
OVERLAY_PassList *psl = vedata->psl;
- DRW_draw_pass(psl->facing_ps);
+ DRW_draw_pass(psl->facing_ps[NOT_IN_FRONT]);
+}
+
+void OVERLAY_facing_infront_draw(OVERLAY_Data *vedata)
+{
+ OVERLAY_PassList *psl = vedata->psl;
+
+ DRW_draw_pass(psl->facing_ps[IN_FRONT]);
}
diff --git a/source/blender/draw/engines/overlay/overlay_gpencil.c b/source/blender/draw/engines/overlay/overlay_gpencil.c
index c96c448c63b..ccc914e0422 100644
--- a/source/blender/draw/engines/overlay/overlay_gpencil.c
+++ b/source/blender/draw/engines/overlay/overlay_gpencil.c
@@ -201,7 +201,10 @@ void OVERLAY_gpencil_cache_init(OVERLAY_Data *vedata)
}
const bool show_overlays = (v3d->flag2 & V3D_HIDE_OVERLAYS) == 0;
- const bool show_grid = (v3d->gp_flag & V3D_GP_SHOW_GRID) != 0;
+ const bool show_grid = (v3d->gp_flag & V3D_GP_SHOW_GRID) != 0 &&
+ ((ts->gpencil_v3d_align &
+ (GP_PROJECT_DEPTH_VIEW | GP_PROJECT_DEPTH_STROKE)) == 0);
+ const bool grid_xray = (v3d->gp_flag & V3D_GP_SHOW_GRID_XRAY);
if (show_grid && show_overlays) {
const char *grid_unit = NULL;
@@ -238,6 +241,15 @@ void OVERLAY_gpencil_cache_init(OVERLAY_Data *vedata)
break;
}
+ /* Move the grid to the right location depending of the align type.
+ * This is required only for 3D Cursor or Origin. */
+ if (ts->gpencil_v3d_align & GP_PROJECT_CURSOR) {
+ copy_v3_v3(mat[3], cursor->location);
+ }
+ else if (ts->gpencil_v3d_align & GP_PROJECT_VIEWSPACE) {
+ copy_v3_v3(mat[3], ob->obmat[3]);
+ }
+
translate_m4(mat, gpd->grid.offset[0], gpd->grid.offset[1], 0.0f);
mul_v2_v2fl(size, gpd->grid.scale, 2.0f * ED_scene_grid_scale(scene, &grid_unit));
rescale_m4(mat, (float[3]){size[0], size[1], 0.0f});
@@ -245,7 +257,9 @@ void OVERLAY_gpencil_cache_init(OVERLAY_Data *vedata)
const int gridlines = (gpd->grid.lines <= 0) ? 1 : gpd->grid.lines;
int line_ct = gridlines * 4 + 2;
- DRWState state = DRW_STATE_WRITE_COLOR | DRW_STATE_DEPTH_LESS_EQUAL | DRW_STATE_BLEND_ALPHA;
+ DRWState state = DRW_STATE_WRITE_COLOR | DRW_STATE_BLEND_ALPHA;
+ state |= (grid_xray) ? DRW_STATE_DEPTH_ALWAYS : DRW_STATE_DEPTH_LESS_EQUAL;
+
DRW_PASS_CREATE(psl->gpencil_canvas_ps, state);
sh = OVERLAY_shader_gpencil_canvas();
@@ -267,6 +281,11 @@ static void OVERLAY_edit_gpencil_cache_populate(OVERLAY_Data *vedata, Object *ob
const DRWContextState *draw_ctx = DRW_context_state_get();
View3D *v3d = draw_ctx->v3d;
+ /* Overlay is only for active object. */
+ if (ob != draw_ctx->obact) {
+ return;
+ }
+
if (pd->edit_gpencil_wires_grp) {
DRWShadingGroup *grp = DRW_shgroup_create_sub(pd->edit_gpencil_wires_grp);
DRW_shgroup_uniform_vec4_copy(grp, "gpEditColor", gpd->line_color);
@@ -342,7 +361,7 @@ static void OVERLAY_gpencil_color_names(Object *ob)
int cfra = DEG_get_ctime(draw_ctx->depsgraph);
BKE_gpencil_visible_stroke_iter(
- ob, NULL, overlay_gpencil_draw_stroke_color_name, ob, false, cfra);
+ NULL, ob, NULL, overlay_gpencil_draw_stroke_color_name, ob, false, cfra);
}
void OVERLAY_gpencil_cache_populate(OVERLAY_Data *vedata, Object *ob)
diff --git a/source/blender/draw/engines/overlay/overlay_grid.c b/source/blender/draw/engines/overlay/overlay_grid.c
index 6f6ad36b4f8..5ed32de6d93 100644
--- a/source/blender/draw/engines/overlay/overlay_grid.c
+++ b/source/blender/draw/engines/overlay/overlay_grid.c
@@ -60,8 +60,11 @@ void OVERLAY_grid_init(OVERLAY_Data *vedata)
const bool show_ortho_grid = (pd->v3d_gridflag & V3D_SHOW_ORTHO_GRID) != 0;
shd->grid_flag = 0;
+ shd->zneg_flag = 0;
+ shd->zpos_flag = 0;
- if (pd->hide_overlays || !(show_axis_y || show_axis_z || show_floor || show_ortho_grid)) {
+ if (pd->hide_overlays || !(pd->v3d_gridflag & (V3D_SHOW_X | V3D_SHOW_Y | V3D_SHOW_Z |
+ V3D_SHOW_FLOOR | V3D_SHOW_ORTHO_GRID))) {
return;
}
@@ -169,7 +172,7 @@ void OVERLAY_grid_cache_init(OVERLAY_Data *vedata)
psl->grid_ps = NULL;
- if (shd->grid_flag == 0 || !DRW_state_is_fbo()) {
+ if ((shd->grid_flag == 0 && shd->zpos_flag == 0) || !DRW_state_is_fbo()) {
return;
}
@@ -188,7 +191,9 @@ void OVERLAY_grid_cache_init(OVERLAY_Data *vedata)
DRW_shgroup_uniform_float_copy(grp, "meshSize", shd->grid_mesh_size);
DRW_shgroup_uniform_block(grp, "globalsBlock", G_draw.block_ubo);
DRW_shgroup_uniform_texture_ref(grp, "depthBuffer", &dtxl->depth);
- DRW_shgroup_call(grp, geom, NULL);
+ if (shd->zneg_flag) {
+ DRW_shgroup_call(grp, geom, NULL);
+ }
grp = DRW_shgroup_create(sh, psl->grid_ps);
DRW_shgroup_uniform_int(grp, "gridFlag", &shd->grid_flag, 1);
@@ -196,14 +201,18 @@ void OVERLAY_grid_cache_init(OVERLAY_Data *vedata)
DRW_shgroup_uniform_block(grp, "globalsBlock", G_draw.block_ubo);
DRW_shgroup_uniform_texture_ref(grp, "depthBuffer", &dtxl->depth);
DRW_shgroup_uniform_float(grp, "gridSteps", shd->grid_steps, ARRAY_SIZE(shd->grid_steps));
- DRW_shgroup_call(grp, geom, NULL);
+ if (shd->grid_flag) {
+ DRW_shgroup_call(grp, geom, NULL);
+ }
grp = DRW_shgroup_create(sh, psl->grid_ps);
DRW_shgroup_uniform_int(grp, "gridFlag", &shd->zpos_flag, 1);
DRW_shgroup_uniform_vec3(grp, "planeAxes", shd->zplane_axes, 1);
DRW_shgroup_uniform_block(grp, "globalsBlock", G_draw.block_ubo);
DRW_shgroup_uniform_texture_ref(grp, "depthBuffer", &dtxl->depth);
- DRW_shgroup_call(grp, geom, NULL);
+ if (shd->zpos_flag) {
+ DRW_shgroup_call(grp, geom, NULL);
+ }
}
void OVERLAY_grid_draw(OVERLAY_Data *vedata)
diff --git a/source/blender/draw/engines/overlay/overlay_image.c b/source/blender/draw/engines/overlay/overlay_image.c
index f81c51f0883..be3510967b6 100644
--- a/source/blender/draw/engines/overlay/overlay_image.c
+++ b/source/blender/draw/engines/overlay/overlay_image.c
@@ -27,6 +27,8 @@
#include "BKE_movieclip.h"
#include "BKE_object.h"
+#include "BLI_listbase.h"
+
#include "DNA_camera_types.h"
#include "DNA_screen_types.h"
@@ -102,25 +104,28 @@ static void overlay_image_calc_aspect(Image *ima, const int size[2], float r_ima
}
}
-static void camera_background_images_stereo_setup(Scene *scene,
- View3D *v3d,
+static eStereoViews camera_background_images_stereo_eye(const Scene *scene, const View3D *v3d)
+{
+ if ((scene->r.scemode & R_MULTIVIEW) == 0) {
+ return STEREO_LEFT_ID;
+ }
+ else if (v3d->stereo3d_camera != STEREO_3D_ID) {
+ /* show only left or right camera */
+ return v3d->stereo3d_camera;
+ }
+ else {
+ return v3d->multiview_eye;
+ }
+}
+
+static void camera_background_images_stereo_setup(const Scene *scene,
+ const View3D *v3d,
Image *ima,
ImageUser *iuser)
{
if (BKE_image_is_stereo(ima)) {
iuser->flag |= IMA_SHOW_STEREO;
-
- if ((scene->r.scemode & R_MULTIVIEW) == 0) {
- iuser->multiview_eye = STEREO_LEFT_ID;
- }
- else if (v3d->stereo3d_camera != STEREO_3D_ID) {
- /* show only left or right camera */
- iuser->multiview_eye = v3d->stereo3d_camera;
- }
- else {
- iuser->multiview_eye = v3d->multiview_eye;
- }
-
+ iuser->multiview_eye = camera_background_images_stereo_eye(scene, v3d);
BKE_image_multiview_index(ima, iuser);
}
else {
@@ -244,7 +249,7 @@ static void image_camera_background_matrix_get(const Camera *cam,
unit_m4(scale);
unit_m4(translate);
- /* Normalized Object space camera frame corners. */
+ /* Normalized Object space camera frame corners. */
float cam_corners[4][3];
BKE_camera_view_frame(draw_ctx->scene, cam, cam_corners);
float cam_width = fabsf(cam_corners[0][0] - cam_corners[3][0]);
@@ -282,6 +287,9 @@ static void image_camera_background_matrix_get(const Camera *cam,
translate[3][0] = bgpic->offset[0];
translate[3][1] = bgpic->offset[1];
translate[3][2] = cam_corners[0][2];
+ if (cam->type == CAM_ORTHO) {
+ mul_v2_fl(translate[3], cam->ortho_scale);
+ }
/* These lines are for keeping 2.80 behavior and could be removed to keep 2.79 behavior. */
translate[3][0] *= min_ff(1.0f, cam_aspect);
translate[3][1] /= max_ff(1.0f, cam_aspect) * (image_aspect / cam_aspect);
@@ -300,6 +308,8 @@ void OVERLAY_image_camera_cache_populate(OVERLAY_Data *vedata, Object *ob)
OVERLAY_PrivateData *pd = vedata->stl->pd;
OVERLAY_PassList *psl = vedata->psl;
const DRWContextState *draw_ctx = DRW_context_state_get();
+ const View3D *v3d = draw_ctx->v3d;
+ const Scene *scene = draw_ctx->scene;
Camera *cam = ob->data;
const bool show_frame = BKE_object_empty_image_frame_is_visible_in_view3d(ob, draw_ctx->rv3d);
@@ -308,10 +318,12 @@ void OVERLAY_image_camera_cache_populate(OVERLAY_Data *vedata, Object *ob)
return;
}
- float norm_obmat[4][4];
- normalize_m4_m4(norm_obmat, ob->obmat);
+ const bool stereo_eye = camera_background_images_stereo_eye(scene, v3d) == STEREO_LEFT_ID;
+ const char *viewname = (stereo_eye == STEREO_LEFT_ID) ? STEREO_RIGHT_NAME : STEREO_LEFT_NAME;
+ float modelmat[4][4];
+ BKE_camera_multiview_model_matrix(&scene->r, ob, viewname, modelmat);
- for (CameraBGImage *bgpic = cam->bg_images.first; bgpic; bgpic = bgpic->next) {
+ LISTBASE_FOREACH (CameraBGImage *, bgpic, &cam->bg_images) {
if (bgpic->flag & CAM_BGIMG_FLAG_DISABLED) {
continue;
}
@@ -327,7 +339,7 @@ void OVERLAY_image_camera_cache_populate(OVERLAY_Data *vedata, Object *ob)
if (tex) {
image_camera_background_matrix_get(cam, bgpic, draw_ctx, aspect, mat);
- mul_m4_m4m4(mat, norm_obmat, mat);
+ mul_m4_m4m4(mat, modelmat, mat);
const bool is_foreground = (bgpic->flag & CAM_BGIMG_FLAG_FOREGROUND) != 0;
float color_premult_alpha[4] = {bgpic->alpha, bgpic->alpha, bgpic->alpha, bgpic->alpha};
@@ -393,16 +405,22 @@ void OVERLAY_image_empty_cache_populate(OVERLAY_Data *vedata, Object *ob)
/* Use the actual depth if we are doing depth tests to determine the distance to the object */
char depth_mode = DRW_state_is_depth() ? OB_EMPTY_IMAGE_DEPTH_DEFAULT : ob->empty_image_depth;
DRWPass *pass = NULL;
- switch (depth_mode) {
- case OB_EMPTY_IMAGE_DEPTH_DEFAULT:
- pass = (use_alpha_blend) ? psl->image_empties_blend_ps : psl->image_empties_ps;
- break;
- case OB_EMPTY_IMAGE_DEPTH_BACK:
- pass = psl->image_empties_back_ps;
- break;
- case OB_EMPTY_IMAGE_DEPTH_FRONT:
- pass = psl->image_empties_front_ps;
- break;
+ if ((ob->dtx & OB_DRAWXRAY) != 0) {
+ /* Object In Front overrides image empty depth mode. */
+ pass = psl->image_empties_front_ps;
+ }
+ else {
+ switch (depth_mode) {
+ case OB_EMPTY_IMAGE_DEPTH_DEFAULT:
+ pass = (use_alpha_blend) ? psl->image_empties_blend_ps : psl->image_empties_ps;
+ break;
+ case OB_EMPTY_IMAGE_DEPTH_BACK:
+ pass = psl->image_empties_back_ps;
+ break;
+ case OB_EMPTY_IMAGE_DEPTH_FRONT:
+ pass = psl->image_empties_front_ps;
+ break;
+ }
}
if (show_frame) {
diff --git a/source/blender/draw/engines/overlay/overlay_motion_path.c b/source/blender/draw/engines/overlay/overlay_motion_path.c
index 29eb4fd12a4..168f6f8a17f 100644
--- a/source/blender/draw/engines/overlay/overlay_motion_path.c
+++ b/source/blender/draw/engines/overlay/overlay_motion_path.c
@@ -22,6 +22,7 @@
#include "DRW_render.h"
+#include "BLI_listbase.h"
#include "BLI_string.h"
#include "DNA_armature_types.h"
@@ -48,11 +49,11 @@ void OVERLAY_motion_path_cache_init(OVERLAY_Data *vedata)
sh = OVERLAY_shader_motion_path_line();
pd->motion_path_lines_grp = grp = DRW_shgroup_create(sh, psl->motion_paths_ps);
- DRW_shgroup_uniform_block_persistent(grp, "globalsBlock", G_draw.block_ubo);
+ DRW_shgroup_uniform_block(grp, "globalsBlock", G_draw.block_ubo);
sh = OVERLAY_shader_motion_path_vert();
pd->motion_path_points_grp = grp = DRW_shgroup_create(sh, psl->motion_paths_ps);
- DRW_shgroup_uniform_block_persistent(grp, "globalsBlock", G_draw.block_ubo);
+ DRW_shgroup_uniform_block(grp, "globalsBlock", G_draw.block_ubo);
}
/* Just convert the CPU cache to GPU cache. */
@@ -211,7 +212,7 @@ void OVERLAY_motion_path_cache_populate(OVERLAY_Data *vedata, Object *ob)
if (ob->type == OB_ARMATURE) {
if (OVERLAY_armature_is_pose_mode(ob, draw_ctx)) {
- for (bPoseChannel *pchan = ob->pose->chanbase.first; pchan; pchan = pchan->next) {
+ LISTBASE_FOREACH (bPoseChannel *, pchan, &ob->pose->chanbase) {
if (pchan->mpath) {
motion_path_cache(vedata, ob, pchan, &ob->pose->avs, pchan->mpath);
}
diff --git a/source/blender/draw/engines/overlay/overlay_outline.c b/source/blender/draw/engines/overlay/overlay_outline.c
index 0395f6890bd..99d22fc380f 100644
--- a/source/blender/draw/engines/overlay/overlay_outline.c
+++ b/source/blender/draw/engines/overlay/overlay_outline.c
@@ -102,14 +102,18 @@ void OVERLAY_outline_init(OVERLAY_Data *vedata)
if (pd->antialiasing.enabled) {
GPU_framebuffer_ensure_config(&fbl->outlines_resolve_fb,
- {GPU_ATTACHMENT_NONE,
- GPU_ATTACHMENT_TEXTURE(txl->overlay_color_tx),
- GPU_ATTACHMENT_TEXTURE(txl->overlay_line_tx)});
+ {
+ GPU_ATTACHMENT_NONE,
+ GPU_ATTACHMENT_TEXTURE(txl->overlay_color_tx),
+ GPU_ATTACHMENT_TEXTURE(txl->overlay_line_tx),
+ });
}
else {
- GPU_framebuffer_ensure_config(
- &fbl->outlines_resolve_fb,
- {GPU_ATTACHMENT_TEXTURE(txl->temp_depth_tx), GPU_ATTACHMENT_TEXTURE(dtxl->color)});
+ GPU_framebuffer_ensure_config(&fbl->outlines_resolve_fb,
+ {
+ GPU_ATTACHMENT_NONE,
+ GPU_ATTACHMENT_TEXTURE(dtxl->color_overlay),
+ });
}
}
}
@@ -255,7 +259,7 @@ static void OVERLAY_outline_gpencil(OVERLAY_PrivateData *pd, Object *ob)
}
BKE_gpencil_visible_stroke_iter(
- ob, gp_layer_cache_populate, gp_stroke_cache_populate, &iter, false, pd->cfra);
+ NULL, ob, gp_layer_cache_populate, gp_stroke_cache_populate, &iter, false, pd->cfra);
}
void OVERLAY_outline_cache_populate(OVERLAY_Data *vedata,
diff --git a/source/blender/draw/engines/overlay/overlay_paint.c b/source/blender/draw/engines/overlay/overlay_paint.c
index 4a1aa270de0..456c56f9c03 100644
--- a/source/blender/draw/engines/overlay/overlay_paint.c
+++ b/source/blender/draw/engines/overlay/overlay_paint.c
@@ -62,7 +62,8 @@ void OVERLAY_paint_init(OVERLAY_Data *vedata)
OVERLAY_PrivateData *pd = stl->pd;
const DRWContextState *draw_ctx = DRW_context_state_get();
- pd->painting.in_front = draw_ctx->obact && (draw_ctx->obact->dtx & OB_DRAWXRAY);
+ pd->painting.in_front = pd->use_in_front && draw_ctx->obact &&
+ (draw_ctx->obact->dtx & OB_DRAWXRAY);
pd->painting.alpha_blending = paint_object_is_rendered_transparent(draw_ctx->v3d,
draw_ctx->obact);
}
@@ -76,15 +77,18 @@ void OVERLAY_paint_cache_init(OVERLAY_Data *vedata)
DRWShadingGroup *grp;
DRWState state;
- const bool draw_contours = (pd->overlay.wpaint_flag & V3D_OVERLAY_WPAINT_CONTOURS) != 0;
+ const bool is_edit_mode = (pd->ctx_mode == CTX_MODE_EDIT_MESH);
+ const bool draw_contours = !is_edit_mode &&
+ (pd->overlay.wpaint_flag & V3D_OVERLAY_WPAINT_CONTOURS) != 0;
float opacity = 0.0f;
pd->paint_depth_grp = NULL;
psl->paint_depth_ps = NULL;
switch (pd->ctx_mode) {
case CTX_MODE_POSE:
+ case CTX_MODE_EDIT_MESH:
case CTX_MODE_PAINT_WEIGHT: {
- opacity = pd->overlay.weight_paint_mode_opacity;
+ opacity = is_edit_mode ? 1.0 : pd->overlay.weight_paint_mode_opacity;
if (opacity > 0.0f) {
state = DRW_STATE_WRITE_COLOR | DRW_STATE_DEPTH_EQUAL;
state |= pd->painting.alpha_blending ? DRW_STATE_BLEND_ALPHA : DRW_STATE_BLEND_MUL;
@@ -207,11 +211,12 @@ void OVERLAY_paint_vertex_cache_populate(OVERLAY_Data *vedata, Object *ob)
struct GPUBatch *geom = NULL;
const Mesh *me_orig = DEG_get_original_object(ob)->data;
- const bool use_wire = (pd->overlay.paint_flag & V3D_OVERLAY_PAINT_WIRE) != 0;
- const bool use_face_sel = (me_orig->editflag & ME_EDIT_PAINT_FACE_SEL) != 0;
- const bool use_vert_sel = (me_orig->editflag & ME_EDIT_PAINT_VERT_SEL) != 0;
+ const bool is_edit_mode = (pd->ctx_mode == CTX_MODE_EDIT_MESH);
+ const bool use_wire = !is_edit_mode && (pd->overlay.paint_flag & V3D_OVERLAY_PAINT_WIRE);
+ const bool use_face_sel = !is_edit_mode && (me_orig->editflag & ME_EDIT_PAINT_FACE_SEL);
+ const bool use_vert_sel = !is_edit_mode && (me_orig->editflag & ME_EDIT_PAINT_VERT_SEL);
- if (ob->mode == OB_MODE_WEIGHT_PAINT) {
+ if (ELEM(ob->mode, OB_MODE_WEIGHT_PAINT, OB_MODE_EDIT)) {
if (pd->paint_surf_grp) {
geom = DRW_cache_mesh_surface_weights_get(ob);
DRW_shgroup_call(pd->paint_surf_grp, geom, ob);
@@ -262,5 +267,7 @@ void OVERLAY_paint_draw(OVERLAY_Data *vedata)
if (psl->paint_color_ps) {
DRW_draw_pass(psl->paint_color_ps);
}
- DRW_draw_pass(psl->paint_overlay_ps);
+ if (psl->paint_overlay_ps) {
+ DRW_draw_pass(psl->paint_overlay_ps);
+ }
}
diff --git a/source/blender/draw/engines/overlay/overlay_particle.c b/source/blender/draw/engines/overlay/overlay_particle.c
index dc98c1b55c1..b891bb4ce4c 100644
--- a/source/blender/draw/engines/overlay/overlay_particle.c
+++ b/source/blender/draw/engines/overlay/overlay_particle.c
@@ -152,13 +152,13 @@ void OVERLAY_particle_cache_init(OVERLAY_Data *vedata)
sh = OVERLAY_shader_particle_dot();
pd->particle_dots_grp = grp = DRW_shgroup_create(sh, psl->particle_ps);
- DRW_shgroup_uniform_block_persistent(grp, "globalsBlock", G_draw.block_ubo);
- DRW_shgroup_uniform_texture_persistent(grp, "weightTex", G_draw.ramp);
+ DRW_shgroup_uniform_block(grp, "globalsBlock", G_draw.block_ubo);
+ DRW_shgroup_uniform_texture(grp, "weightTex", G_draw.ramp);
sh = OVERLAY_shader_particle_shape();
pd->particle_shapes_grp = grp = DRW_shgroup_create(sh, psl->particle_ps);
- DRW_shgroup_uniform_block_persistent(grp, "globalsBlock", G_draw.block_ubo);
- DRW_shgroup_uniform_texture_persistent(grp, "weightTex", G_draw.ramp);
+ DRW_shgroup_uniform_block(grp, "globalsBlock", G_draw.block_ubo);
+ DRW_shgroup_uniform_texture(grp, "weightTex", G_draw.ramp);
}
void OVERLAY_particle_cache_populate(OVERLAY_Data *vedata, Object *ob)
@@ -205,7 +205,7 @@ void OVERLAY_particle_cache_populate(OVERLAY_Data *vedata, Object *ob)
grp = DRW_shgroup_create_sub(pd->particle_shapes_grp);
DRW_shgroup_uniform_vec4_copy(grp, "color", color);
shape = DRW_cache_particles_get_prim(draw_as);
- DRW_shgroup_call_instances_with_attribs(grp, NULL, shape, geom);
+ DRW_shgroup_call_instances_with_attrs(grp, NULL, shape, geom);
break;
}
}
diff --git a/source/blender/draw/engines/overlay/overlay_pointcloud.c b/source/blender/draw/engines/overlay/overlay_pointcloud.c
index a0de7aac1f1..b2a2d44bf73 100644
--- a/source/blender/draw/engines/overlay/overlay_pointcloud.c
+++ b/source/blender/draw/engines/overlay/overlay_pointcloud.c
@@ -46,7 +46,7 @@ void OVERLAY_pointcloud_cache_init(OVERLAY_Data *vedata)
sh = OVERLAY_shader_pointcloud_dot();
pd->pointcloud_dots_grp = grp = DRW_shgroup_create(sh, psl->pointcloud_ps);
- DRW_shgroup_uniform_block_persistent(grp, "globalsBlock", G_draw.block_ubo);
+ DRW_shgroup_uniform_block(grp, "globalsBlock", G_draw.block_ubo);
}
void OVERLAY_pointcloud_cache_populate(OVERLAY_Data *vedata, Object *ob)
diff --git a/source/blender/draw/engines/overlay/overlay_private.h b/source/blender/draw/engines/overlay/overlay_private.h
index bd9583c6a5f..ed0a9cf6981 100644
--- a/source/blender/draw/engines/overlay/overlay_private.h
+++ b/source/blender/draw/engines/overlay/overlay_private.h
@@ -35,7 +35,6 @@ typedef struct OVERLAY_FramebufferList {
struct GPUFrameBuffer *overlay_color_only_fb;
struct GPUFrameBuffer *overlay_in_front_fb;
struct GPUFrameBuffer *overlay_line_in_front_fb;
- struct GPUFrameBuffer *overlay_xray_depth_copy_fb;
struct GPUFrameBuffer *outlines_prepass_fb;
struct GPUFrameBuffer *outlines_resolve_fb;
} OVERLAY_FramebufferList;
@@ -55,7 +54,7 @@ typedef struct OVERLAY_PassList {
DRWPass *antialiasing_ps;
DRWPass *armature_ps[2];
DRWPass *armature_bone_select_ps;
- DRWPass *armature_transp_ps;
+ DRWPass *armature_transp_ps[2];
DRWPass *background_ps;
DRWPass *clipping_frustum_ps;
DRWPass *edit_curve_wire_ps[2];
@@ -70,7 +69,6 @@ typedef struct OVERLAY_PassList {
DRWPass *edit_mesh_faces_cage_ps[2];
DRWPass *edit_mesh_analysis_ps;
DRWPass *edit_mesh_normals_ps;
- DRWPass *edit_mesh_weight_ps;
DRWPass *edit_particle_ps;
DRWPass *edit_text_overlay_ps;
DRWPass *edit_text_wire_ps[2];
@@ -79,7 +77,7 @@ typedef struct OVERLAY_PassList {
DRWPass *extra_centers_ps;
DRWPass *extra_grid_ps;
DRWPass *gpencil_canvas_ps;
- DRWPass *facing_ps;
+ DRWPass *facing_ps[2];
DRWPass *grid_ps;
DRWPass *image_background_ps;
DRWPass *image_empties_ps;
@@ -235,13 +233,12 @@ typedef struct OVERLAY_PrivateData {
DRWShadingGroup *edit_mesh_skin_roots_grp[2];
DRWShadingGroup *edit_mesh_normals_grp;
DRWShadingGroup *edit_mesh_analysis_grp;
- DRWShadingGroup *edit_mesh_weight_grp;
DRWShadingGroup *edit_particle_strand_grp;
DRWShadingGroup *edit_particle_point_grp;
DRWShadingGroup *edit_text_overlay_grp;
DRWShadingGroup *edit_text_wire_grp[2];
DRWShadingGroup *extra_grid_grp;
- DRWShadingGroup *facing_grp;
+ DRWShadingGroup *facing_grp[2];
DRWShadingGroup *motion_path_lines_grp;
DRWShadingGroup *motion_path_points_grp;
DRWShadingGroup *outlines_grp;
@@ -256,8 +253,9 @@ typedef struct OVERLAY_PrivateData {
DRWShadingGroup *particle_shapes_grp;
DRWShadingGroup *pointcloud_dots_grp;
DRWShadingGroup *sculpt_mask_grp;
- DRWShadingGroup *wires_grp[2][2]; /* With and without coloring. */
- DRWShadingGroup *wires_all_grp[2][2]; /* With and without coloring. */
+ DRWShadingGroup *wires_grp[2][2]; /* With and without coloring. */
+ DRWShadingGroup *wires_all_grp[2][2]; /* With and without coloring. */
+ DRWShadingGroup *wires_hair_grp[2][2]; /* With and without coloring. */
DRWShadingGroup *wires_sculpt_grp[2];
DRWView *view_default;
@@ -280,6 +278,7 @@ typedef struct OVERLAY_PrivateData {
View3DOverlay overlay;
enum eContextObjectMode ctx_mode;
bool clear_in_front;
+ bool use_in_front;
bool wireframe_mode;
bool hide_overlays;
bool xray_enabled;
@@ -298,6 +297,7 @@ typedef struct OVERLAY_PrivateData {
} antialiasing;
struct {
bool show_handles;
+ int handle_display;
} edit_curve;
struct {
int ghost_ob;
@@ -501,6 +501,7 @@ void OVERLAY_facing_init(OVERLAY_Data *vedata);
void OVERLAY_facing_cache_init(OVERLAY_Data *vedata);
void OVERLAY_facing_cache_populate(OVERLAY_Data *vedata, Object *ob);
void OVERLAY_facing_draw(OVERLAY_Data *vedata);
+void OVERLAY_facing_infront_draw(OVERLAY_Data *vedata);
void OVERLAY_grid_init(OVERLAY_Data *vedata);
void OVERLAY_grid_cache_init(OVERLAY_Data *vedata);
@@ -589,9 +590,9 @@ GPUShader *OVERLAY_shader_edit_mesh_skin_root(void);
GPUShader *OVERLAY_shader_edit_mesh_vert(void);
GPUShader *OVERLAY_shader_edit_particle_strand(void);
GPUShader *OVERLAY_shader_edit_particle_point(void);
-GPUShader *OVERLAY_shader_extra(void);
+GPUShader *OVERLAY_shader_extra(bool is_select);
GPUShader *OVERLAY_shader_extra_groundline(void);
-GPUShader *OVERLAY_shader_extra_wire(bool use_object);
+GPUShader *OVERLAY_shader_extra_wire(bool use_object, bool is_select);
GPUShader *OVERLAY_shader_extra_loose_point(void);
GPUShader *OVERLAY_shader_extra_point(void);
GPUShader *OVERLAY_shader_facing(void);
diff --git a/source/blender/draw/engines/overlay/overlay_sculpt.c b/source/blender/draw/engines/overlay/overlay_sculpt.c
index 391c49e0695..111fa6316ed 100644
--- a/source/blender/draw/engines/overlay/overlay_sculpt.c
+++ b/source/blender/draw/engines/overlay/overlay_sculpt.c
@@ -54,7 +54,7 @@ void OVERLAY_sculpt_cache_populate(OVERLAY_Data *vedata, Object *ob)
if (use_pbvh || !ob->sculpt->deform_modifiers_active || ob->sculpt->shapekey_active) {
if (!use_pbvh || pbvh_has_mask(pbvh) || pbvh_has_face_sets(pbvh)) {
- DRW_shgroup_call_sculpt(pd->sculpt_mask_grp, ob, false, true, false);
+ DRW_shgroup_call_sculpt(pd->sculpt_mask_grp, ob, false, true);
}
}
}
diff --git a/source/blender/draw/engines/overlay/overlay_shader.c b/source/blender/draw/engines/overlay/overlay_shader.c
index 8b70a0982af..0610b8397a1 100644
--- a/source/blender/draw/engines/overlay/overlay_shader.c
+++ b/source/blender/draw/engines/overlay/overlay_shader.c
@@ -105,6 +105,7 @@ extern char datatoc_particle_frag_glsl[];
extern char datatoc_pointcloud_vert_glsl[];
extern char datatoc_pointcloud_frag_glsl[];
extern char datatoc_sculpt_mask_vert_glsl[];
+extern char datatoc_sculpt_mask_frag_glsl[];
extern char datatoc_volume_velocity_vert_glsl[];
extern char datatoc_wireframe_vert_glsl[];
extern char datatoc_wireframe_frag_glsl[];
@@ -163,8 +164,10 @@ typedef struct OVERLAY_Shaders {
GPUShader *edit_particle_strand;
GPUShader *edit_particle_point;
GPUShader *extra;
+ GPUShader *extra_select;
GPUShader *extra_groundline;
GPUShader *extra_wire[2];
+ GPUShader *extra_wire_select;
GPUShader *extra_point;
GPUShader *extra_lightprobe_grid;
GPUShader *extra_loose_point;
@@ -233,10 +236,12 @@ GPUShader *OVERLAY_shader_background(void)
GPUShader *OVERLAY_shader_clipbound(void)
{
OVERLAY_Shaders *sh_data = &e_data.sh_data[0];
+ const GPUShaderConfigData *sh_cfg = &GPU_shader_cfg_data[0];
if (!sh_data->clipbound) {
sh_data->clipbound = GPU_shader_create_from_arrays({
.vert = (const char *[]){datatoc_common_view_lib_glsl, datatoc_clipbound_vert_glsl, NULL},
.frag = (const char *[]){datatoc_gpu_shader_uniform_color_frag_glsl, NULL},
+ .defs = (const char *[]){sh_cfg->def, NULL},
});
}
return sh_data->clipbound;
@@ -713,7 +718,7 @@ GPUShader *OVERLAY_shader_edit_mesh_normal(void)
datatoc_edit_mesh_normal_vert_glsl,
NULL},
.frag = (const char *[]){datatoc_gpu_shader_flat_color_frag_glsl, NULL},
- .defs = (const char *[]){sh_cfg->def, "#define INSTANCED_ATTRIB\n", NULL},
+ .defs = (const char *[]){sh_cfg->def, "#define INSTANCED_ATTR\n", NULL},
});
}
return sh_data->edit_mesh_normals;
@@ -750,7 +755,7 @@ GPUShader *OVERLAY_shader_edit_mesh_skin_root(void)
datatoc_edit_mesh_skin_root_vert_glsl,
NULL},
.frag = (const char *[]){datatoc_gpu_shader_flat_color_frag_glsl, NULL},
- .defs = (const char *[]){sh_cfg->def, "#define INSTANCED_ATTRIB\n", NULL},
+ .defs = (const char *[]){sh_cfg->def, "#define INSTANCED_ATTR\n", NULL},
});
}
return sh_data->edit_mesh_skin_root;
@@ -794,23 +799,24 @@ GPUShader *OVERLAY_shader_edit_particle_point(void)
return sh_data->edit_particle_point;
}
-GPUShader *OVERLAY_shader_extra(void)
+GPUShader *OVERLAY_shader_extra(bool is_select)
{
const DRWContextState *draw_ctx = DRW_context_state_get();
const GPUShaderConfigData *sh_cfg = &GPU_shader_cfg_data[draw_ctx->sh_cfg];
OVERLAY_Shaders *sh_data = &e_data.sh_data[draw_ctx->sh_cfg];
- if (!sh_data->extra) {
- sh_data->extra = GPU_shader_create_from_arrays({
+ GPUShader **sh = (is_select) ? &sh_data->extra_select : &sh_data->extra;
+ if (!*sh) {
+ *sh = GPU_shader_create_from_arrays({
.vert = (const char *[]){sh_cfg->lib,
datatoc_common_globals_lib_glsl,
datatoc_common_view_lib_glsl,
datatoc_extra_vert_glsl,
NULL},
.frag = (const char *[]){datatoc_common_view_lib_glsl, datatoc_extra_frag_glsl, NULL},
- .defs = (const char *[]){sh_cfg->def, NULL},
+ .defs = (const char *[]){sh_cfg->def, (is_select) ? "#define SELECT_EDGES\n" : NULL, NULL},
});
}
- return sh_data->extra;
+ return *sh;
}
GPUShader *OVERLAY_shader_extra_grid(void)
@@ -852,12 +858,13 @@ GPUShader *OVERLAY_shader_extra_groundline(void)
return sh_data->extra_groundline;
}
-GPUShader *OVERLAY_shader_extra_wire(bool use_object)
+GPUShader *OVERLAY_shader_extra_wire(bool use_object, bool is_select)
{
const DRWContextState *draw_ctx = DRW_context_state_get();
const GPUShaderConfigData *sh_cfg = &GPU_shader_cfg_data[draw_ctx->sh_cfg];
OVERLAY_Shaders *sh_data = &e_data.sh_data[draw_ctx->sh_cfg];
- if (!sh_data->extra_wire[use_object]) {
+ GPUShader **sh = (is_select) ? &sh_data->extra_wire_select : &sh_data->extra_wire[use_object];
+ if (!*sh) {
char colorids[1024];
/* NOTE: define all ids we need here. */
BLI_snprintf(colorids,
@@ -872,7 +879,7 @@ GPUShader *OVERLAY_shader_extra_wire(bool use_object)
TH_TRANSFORM,
TH_WIRE,
TH_CAMERA_PATH);
- sh_data->extra_wire[use_object] = GPU_shader_create_from_arrays({
+ *sh = GPU_shader_create_from_arrays({
.vert = (const char *[]){sh_cfg->lib,
datatoc_common_globals_lib_glsl,
datatoc_common_view_lib_glsl,
@@ -881,11 +888,12 @@ GPUShader *OVERLAY_shader_extra_wire(bool use_object)
.frag = (const char *[]){datatoc_common_view_lib_glsl, datatoc_extra_wire_frag_glsl, NULL},
.defs = (const char *[]){sh_cfg->def,
colorids,
+ (is_select) ? "#define SELECT_EDGES\n" : "",
(use_object) ? "#define OBJECT_WIRE \n" : NULL,
NULL},
});
}
- return sh_data->extra_wire[use_object];
+ return *sh;
}
GPUShader *OVERLAY_shader_extra_loose_point(void)
@@ -1269,7 +1277,7 @@ GPUShader *OVERLAY_shader_particle_shape(void)
datatoc_particle_vert_glsl,
NULL},
.frag = (const char *[]){datatoc_gpu_shader_flat_color_frag_glsl, NULL},
- .defs = (const char *[]){sh_cfg->def, "#define INSTANCED_ATTRIB\n", NULL},
+ .defs = (const char *[]){sh_cfg->def, "#define INSTANCED_ATTR\n", NULL},
});
}
return sh_data->particle_shape;
@@ -1305,7 +1313,7 @@ GPUShader *OVERLAY_shader_sculpt_mask(void)
datatoc_common_view_lib_glsl,
datatoc_sculpt_mask_vert_glsl,
NULL},
- .frag = (const char *[]){datatoc_gpu_shader_3D_smooth_color_frag_glsl, NULL},
+ .frag = (const char *[]){datatoc_sculpt_mask_frag_glsl, NULL},
.defs = (const char *[]){sh_cfg->def, NULL},
});
}
@@ -1339,6 +1347,7 @@ struct GPUShader *OVERLAY_shader_volume_velocity(bool use_needle)
NULL,
datatoc_gpu_shader_flat_color_frag_glsl,
datatoc_common_view_lib_glsl,
+ "#define blender_srgb_to_framebuffer_space(a) a\n"
"#define USE_NEEDLE\n");
}
else if (!sh_data->volume_velocity_sh) {
@@ -1347,7 +1356,7 @@ struct GPUShader *OVERLAY_shader_volume_velocity(bool use_needle)
NULL,
datatoc_gpu_shader_flat_color_frag_glsl,
datatoc_common_view_lib_glsl,
- NULL);
+ "#define blender_srgb_to_framebuffer_space(a) a\n");
}
return (use_needle) ? sh_data->volume_velocity_needle_sh : sh_data->volume_velocity_sh;
}
diff --git a/source/blender/draw/engines/overlay/overlay_wireframe.c b/source/blender/draw/engines/overlay/overlay_wireframe.c
index 27f3f4ae9af..eebfc88fdce 100644
--- a/source/blender/draw/engines/overlay/overlay_wireframe.c
+++ b/source/blender/draw/engines/overlay/overlay_wireframe.c
@@ -21,15 +21,18 @@
*/
#include "DNA_mesh_types.h"
+#include "DNA_particle_types.h"
#include "DNA_view3d_types.h"
#include "DNA_volume_types.h"
#include "BKE_curve.h"
#include "BKE_displist.h"
+#include "BKE_duplilist.h"
#include "BKE_editmesh.h"
#include "BKE_global.h"
#include "BKE_object.h"
#include "BKE_paint.h"
+#include "BKE_particle.h"
#include "BLI_hash.h"
@@ -73,8 +76,9 @@ void OVERLAY_wireframe_cache_init(OVERLAY_Data *vedata)
DRWState state = DRW_STATE_FIRST_VERTEX_CONVENTION | DRW_STATE_WRITE_COLOR |
DRW_STATE_WRITE_DEPTH | DRW_STATE_DEPTH_LESS_EQUAL;
DRWPass *pass;
- GPUTexture **depth_tx = (pd->xray_enabled || pd->xray_opacity > 0.0f) ? &txl->temp_depth_tx :
- &txl->dummy_depth_tx;
+ GPUTexture **depth_tx = ((pd->xray_enabled || pd->xray_opacity > 0.0f) && DRW_state_is_fbo()) ?
+ &txl->temp_depth_tx :
+ &txl->dummy_depth_tx;
if (xray == 0) {
DRW_PASS_CREATE(psl->wireframe_ps, state | pd->clipping_state);
@@ -87,23 +91,31 @@ void OVERLAY_wireframe_cache_init(OVERLAY_Data *vedata)
for (int use_coloring = 0; use_coloring < 2; use_coloring++) {
pd->wires_grp[xray][use_coloring] = grp = DRW_shgroup_create(wires_sh, pass);
- DRW_shgroup_uniform_block_persistent(grp, "globalsBlock", G_draw.block_ubo);
+ DRW_shgroup_uniform_block(grp, "globalsBlock", G_draw.block_ubo);
DRW_shgroup_uniform_texture_ref(grp, "depthTex", depth_tx);
DRW_shgroup_uniform_float_copy(grp, "wireStepParam", pd->shdata.wire_step_param);
DRW_shgroup_uniform_bool_copy(grp, "useColoring", use_coloring);
DRW_shgroup_uniform_bool_copy(grp, "isTransform", (G.moving & G_TRANSFORM_OBJ) != 0);
DRW_shgroup_uniform_bool_copy(grp, "isObjectColor", is_object_color);
DRW_shgroup_uniform_bool_copy(grp, "isRandomColor", is_random_color);
+ DRW_shgroup_uniform_bool_copy(grp, "isHair", false);
pd->wires_all_grp[xray][use_coloring] = grp = DRW_shgroup_create(wires_sh, pass);
DRW_shgroup_uniform_texture_ref(grp, "depthTex", depth_tx);
DRW_shgroup_uniform_float_copy(grp, "wireStepParam", 1.0f);
+
+ pd->wires_hair_grp[xray][use_coloring] = grp = DRW_shgroup_create(wires_sh, pass);
+ /* TODO(fclem) texture ref persist */
+ DRW_shgroup_uniform_texture_ref(grp, "depthTex", depth_tx);
+ DRW_shgroup_uniform_bool_copy(grp, "isHair", true);
+ DRW_shgroup_uniform_float_copy(grp, "wireStepParam", 10.0f);
}
pd->wires_sculpt_grp[xray] = grp = DRW_shgroup_create(wires_sh, pass);
DRW_shgroup_uniform_texture_ref(grp, "depthTex", depth_tx);
DRW_shgroup_uniform_float_copy(grp, "wireStepParam", 10.0f);
DRW_shgroup_uniform_bool_copy(grp, "useColoring", false);
+ DRW_shgroup_uniform_bool_copy(grp, "isHair", false);
}
if (is_material_shmode) {
@@ -111,19 +123,50 @@ void OVERLAY_wireframe_cache_init(OVERLAY_Data *vedata)
for (int use_coloring = 0; use_coloring < 2; use_coloring++) {
pd->wires_grp[1][use_coloring] = pd->wires_grp[0][use_coloring];
pd->wires_all_grp[1][use_coloring] = pd->wires_all_grp[0][use_coloring];
+ pd->wires_hair_grp[1][use_coloring] = pd->wires_hair_grp[0][use_coloring];
}
pd->wires_sculpt_grp[1] = pd->wires_sculpt_grp[0];
psl->wireframe_xray_ps = NULL;
}
}
+static void wireframe_hair_cache_populate(OVERLAY_Data *vedata, Object *ob, ParticleSystem *psys)
+{
+ OVERLAY_PrivateData *pd = vedata->stl->pd;
+ const bool is_xray = (ob->dtx & OB_DRAWXRAY) != 0;
+
+ Object *dupli_parent = DRW_object_get_dupli_parent(ob);
+ DupliObject *dupli_object = DRW_object_get_dupli(ob);
+
+ float dupli_mat[4][4];
+ if ((dupli_parent != NULL) && (dupli_object != NULL)) {
+ if (dupli_object->type & OB_DUPLICOLLECTION) {
+ copy_m4_m4(dupli_mat, dupli_parent->obmat);
+ }
+ else {
+ copy_m4_m4(dupli_mat, dupli_object->ob->obmat);
+ invert_m4(dupli_mat);
+ mul_m4_m4m4(dupli_mat, ob->obmat, dupli_mat);
+ }
+ }
+ else {
+ unit_m4(dupli_mat);
+ }
+
+ struct GPUBatch *hairs = DRW_cache_particles_get_hair(ob, psys, NULL);
+
+ const bool use_coloring = true;
+ DRWShadingGroup *shgrp = DRW_shgroup_create_sub(pd->wires_hair_grp[is_xray][use_coloring]);
+ DRW_shgroup_uniform_vec4_array_copy(shgrp, "hairDupliMatrix", dupli_mat, 4);
+ DRW_shgroup_call_no_cull(shgrp, hairs, ob);
+}
+
void OVERLAY_wireframe_cache_populate(OVERLAY_Data *vedata,
Object *ob,
OVERLAY_DupliData *dupli,
bool init_dupli)
{
- OVERLAY_Data *data = vedata;
- OVERLAY_PrivateData *pd = data->stl->pd;
+ OVERLAY_PrivateData *pd = vedata->stl->pd;
const DRWContextState *draw_ctx = DRW_context_state_get();
const bool all_wires = (ob->dtx & OB_DRAW_ALL_EDGES) != 0;
const bool is_xray = (ob->dtx & OB_DRAWXRAY) != 0;
@@ -133,7 +176,20 @@ void OVERLAY_wireframe_cache_populate(OVERLAY_Data *vedata,
const bool use_wire = !is_mesh_verts_only && ((pd->overlay.flag & V3D_OVERLAY_WIREFRAMES) ||
(ob->dtx & OB_DRAWWIRE) || (ob->dt == OB_WIRE));
- if (ELEM(ob->type, OB_CURVE, OB_SURF)) {
+ if (use_wire && pd->wireframe_mode && ob->particlesystem.first) {
+ for (ParticleSystem *psys = ob->particlesystem.first; psys != NULL; psys = psys->next) {
+ if (!DRW_object_is_visible_psys_in_active_context(ob, psys)) {
+ continue;
+ }
+ ParticleSettings *part = psys->part;
+ const int draw_as = (part->draw_as == PART_DRAW_REND) ? part->ren_as : part->draw_as;
+ if (draw_as == PART_DRAW_PATH) {
+ wireframe_hair_cache_populate(vedata, ob, psys);
+ }
+ }
+ }
+
+ if (ELEM(ob->type, OB_CURVE, OB_FONT, OB_SURF)) {
OVERLAY_ExtraCallBuffers *cb = OVERLAY_extra_call_buffer_get(vedata, ob);
float *color;
DRW_object_wire_theme_get(ob, draw_ctx->view_layer, &color);
@@ -141,11 +197,19 @@ void OVERLAY_wireframe_cache_populate(OVERLAY_Data *vedata,
struct GPUBatch *geom = NULL;
switch (ob->type) {
case OB_CURVE:
- if (ob->runtime.curve_cache && BKE_displist_has_faces(&ob->runtime.curve_cache->disp)) {
+ if (!pd->wireframe_mode && !use_wire && ob->runtime.curve_cache &&
+ BKE_displist_has_faces(&ob->runtime.curve_cache->disp)) {
break;
}
geom = DRW_cache_curve_edge_wire_get(ob);
break;
+ case OB_FONT:
+ if (!pd->wireframe_mode && !use_wire && ob->runtime.curve_cache &&
+ BKE_displist_has_faces(&ob->runtime.curve_cache->disp)) {
+ break;
+ }
+ geom = DRW_cache_text_loose_edges_get(ob);
+ break;
case OB_SURF:
geom = DRW_cache_surf_edge_wire_get(ob);
break;
@@ -223,7 +287,7 @@ void OVERLAY_wireframe_cache_populate(OVERLAY_Data *vedata,
DRW_shgroup_call_no_cull(shgrp, geom, ob);
}
else if (use_sculpt_pbvh) {
- DRW_shgroup_call_sculpt(shgrp, ob, true, false, false);
+ DRW_shgroup_call_sculpt(shgrp, ob, true, false);
}
else {
DRW_shgroup_call(shgrp, geom, ob);
diff --git a/source/blender/draw/engines/overlay/shaders/edit_curve_handle_geom.glsl b/source/blender/draw/engines/overlay/shaders/edit_curve_handle_geom.glsl
index b6576ba7a21..306fbb473ee 100644
--- a/source/blender/draw/engines/overlay/shaders/edit_curve_handle_geom.glsl
+++ b/source/blender/draw/engines/overlay/shaders/edit_curve_handle_geom.glsl
@@ -1,12 +1,18 @@
/* Keep the same value of `ACTIVE_NURB` in `draw_cache_imp_curve.c` */
#define ACTIVE_NURB 1 << 2
-#define EVEN_U_BIT 1 << 3
+#define EVEN_U_BIT 1 << 4
+#define COLOR_SHIFT 5
+
+/* Keep the same value in `handle_display` in `DNA_view3d_types.h` */
+#define CURVE_HANDLE_SELECTED 0
+#define CURVE_HANDLE_ALL 1
layout(lines) in;
layout(triangle_strip, max_vertices = 10) out;
uniform bool showCurveHandles;
+uniform int curveHandleDisplay;
flat in int vertFlag[];
@@ -37,7 +43,7 @@ void main()
vec4 v2 = gl_in[1].gl_Position;
int is_active_nurb = (vertFlag[1] & ACTIVE_NURB);
- int color_id = (vertFlag[1] >> 4);
+ int color_id = (vertFlag[1] >> COLOR_SHIFT);
/* Don't output any edges if we don't show handles */
if (!showCurveHandles && (color_id < 5)) {
@@ -45,6 +51,17 @@ void main()
}
bool edge_selected = (((vertFlag[1] | vertFlag[0]) & VERT_SELECTED) != 0);
+ bool handle_selected = (showCurveHandles &&
+ (((vertFlag[1] | vertFlag[0]) & HANDLE_SELECTED) != 0));
+
+ /* If handle type is only selected and the edge is not selected, don't show. */
+ if ((curveHandleDisplay != CURVE_HANDLE_ALL) && (!handle_selected)) {
+ /* Nurbs must show the handles always. */
+ bool is_u_segment = (((vertFlag[1] ^ vertFlag[0]) & EVEN_U_BIT) != 0);
+ if (!is_u_segment) {
+ return;
+ }
+ }
vec4 inner_color;
if (color_id == 0) {
diff --git a/source/blender/draw/engines/overlay/shaders/edit_curve_point_vert.glsl b/source/blender/draw/engines/overlay/shaders/edit_curve_point_vert.glsl
index aca40bba171..b1e1c0879a5 100644
--- a/source/blender/draw/engines/overlay/shaders/edit_curve_point_vert.glsl
+++ b/source/blender/draw/engines/overlay/shaders/edit_curve_point_vert.glsl
@@ -1,4 +1,13 @@
+/* Keep the same value of `BEZIER_HANDLE` in `draw_cache_imp_curve.c` */
+#define BEZIER_HANDLE 1 << 3
+
+/* Keep the same value in `handle_display` in `DNA_view3d_types.h` */
+#define CURVE_HANDLE_SELECTED 0
+
+uniform bool showCurveHandles;
+uniform int curveHandleDisplay;
+
in vec3 pos;
in int data;
@@ -26,4 +35,14 @@ void main()
#ifdef USE_WORLD_CLIP_PLANES
world_clip_planes_calc_clip_distance(world_pos);
#endif
+
+ bool show_handle = showCurveHandles;
+ if ((curveHandleDisplay == CURVE_HANDLE_SELECTED) && ((data & HANDLE_SELECTED) == 0)) {
+ show_handle = false;
+ }
+
+ if (!show_handle && ((data & BEZIER_HANDLE) != 0)) {
+ /* We set the vertex at the camera origin to generate 0 fragments. */
+ gl_Position = vec4(0.0, 0.0, -3e36, 0.0);
+ }
}
diff --git a/source/blender/draw/engines/overlay/shaders/edit_gpencil_vert.glsl b/source/blender/draw/engines/overlay/shaders/edit_gpencil_vert.glsl
index 3a52e0c73b7..732e392ffe0 100644
--- a/source/blender/draw/engines/overlay/shaders/edit_gpencil_vert.glsl
+++ b/source/blender/draw/engines/overlay/shaders/edit_gpencil_vert.glsl
@@ -21,11 +21,11 @@ void discard_vert()
gl_Position = vec4(0.0, 0.0, -3e36, 0.0);
}
-#define GP_EDIT_POINT_SELECTED (1u << 0u)
-#define GP_EDIT_STROKE_SELECTED (1u << 1u)
-#define GP_EDIT_MULTIFRAME (1u << 2u)
-#define GP_EDIT_STROKE_START (1u << 3u)
-#define GP_EDIT_STROKE_END (1u << 4u)
+#define GP_EDIT_POINT_SELECTED 1u /* 1 << 0 */
+#define GP_EDIT_STROKE_SELECTED 2u /* 1 << 1 */
+#define GP_EDIT_MULTIFRAME 4u /* 1 << 2 */
+#define GP_EDIT_STROKE_START 8u /* 1 << 3 */
+#define GP_EDIT_STROKE_END 16u /* 1 << 4 */
#ifdef USE_POINTS
# define colorUnselect colorGpencilVertex
diff --git a/source/blender/draw/engines/overlay/shaders/edit_mesh_common_lib.glsl b/source/blender/draw/engines/overlay/shaders/edit_mesh_common_lib.glsl
index b79bae45f23..195d2a5a7b7 100644
--- a/source/blender/draw/engines/overlay/shaders/edit_mesh_common_lib.glsl
+++ b/source/blender/draw/engines/overlay/shaders/edit_mesh_common_lib.glsl
@@ -20,7 +20,7 @@ vec4 EDIT_MESH_edge_color_inner(int edge_flag)
color = ((edge_flag & EDGE_SELECTED) != 0) ? color_select : color;
color = ((edge_flag & EDGE_ACTIVE) != 0) ? colorEditMeshActive : color;
- color.a = (selectEdges || (edge_flag & (EDGE_SELECTED | EDGE_ACTIVE)) != 0) ? 1.0 : 0.4;
+ color.a = (selectEdges || (edge_flag & (EDGE_SELECTED | EDGE_ACTIVE)) != 0) ? 1.0 : 0.7;
return color;
}
@@ -32,7 +32,7 @@ vec4 EDIT_MESH_edge_vertex_color(int vertex_flag)
bool edge_selected = (vertex_flag & (VERT_ACTIVE | VERT_SELECTED)) != 0;
color = (edge_selected) ? color_select : color;
- color.a = (selectEdges || edge_selected) ? 1.0 : 0.4;
+ color.a = (selectEdges || edge_selected) ? 1.0 : 0.7;
return color;
}
diff --git a/source/blender/draw/engines/overlay/shaders/edit_mesh_normal_vert.glsl b/source/blender/draw/engines/overlay/shaders/edit_mesh_normal_vert.glsl
index 8833490e818..c2aeae4df91 100644
--- a/source/blender/draw/engines/overlay/shaders/edit_mesh_normal_vert.glsl
+++ b/source/blender/draw/engines/overlay/shaders/edit_mesh_normal_vert.glsl
@@ -21,7 +21,7 @@ void main()
GPU_INTEL_VERTEX_SHADER_WORKAROUND
vec3 nor;
- /* Select the right normal by cheking if the generic attrib is used. */
+ /* Select the right normal by checking if the generic attribute is used. */
if (!all(equal(lnor.xyz, vec3(0)))) {
if (lnor.w < 0.0) {
finalColor = vec4(0.0);
@@ -40,7 +40,7 @@ void main()
}
else {
nor = norAndFlag.xyz;
- if (all(equal(nor, vec3(0.0)))) {
+ if (all(equal(nor, vec3(0)))) {
finalColor = vec4(0.0);
return;
}
diff --git a/source/blender/draw/engines/overlay/shaders/edit_mesh_vert.glsl b/source/blender/draw/engines/overlay/shaders/edit_mesh_vert.glsl
index 768b0596d17..203f6cb1901 100644
--- a/source/blender/draw/engines/overlay/shaders/edit_mesh_vert.glsl
+++ b/source/blender/draw/engines/overlay/shaders/edit_mesh_vert.glsl
@@ -48,10 +48,10 @@ void main()
gl_PointSize = sizeVertex * 2.0;
/* Make selected and active vertex always on top. */
if ((data.x & VERT_SELECTED) != 0) {
- gl_Position.z -= 1e-7;
+ gl_Position.z -= 5e-7 * abs(gl_Position.w);
}
if ((data.x & VERT_ACTIVE) != 0) {
- gl_Position.z -= 1e-7;
+ gl_Position.z -= 5e-7 * abs(gl_Position.w);
}
bool occluded = test_occlusion();
@@ -69,6 +69,10 @@ void main()
float bweight = float(m_data.w) / 255.0;
finalColorOuter = EDIT_MESH_edge_color_outer(m_data.y, m_data.x, crease, bweight);
+ if (finalColorOuter.a > 0.0) {
+ gl_Position.z -= 5e-7 * abs(gl_Position.w);
+ }
+
bool occluded = false; /* Done in fragment shader */
#elif defined(FACE)
diff --git a/source/blender/draw/engines/overlay/shaders/extra_vert.glsl b/source/blender/draw/engines/overlay/shaders/extra_vert.glsl
index 035fab1040e..2168d8065fc 100644
--- a/source/blender/draw/engines/overlay/shaders/extra_vert.glsl
+++ b/source/blender/draw/engines/overlay/shaders/extra_vert.glsl
@@ -221,6 +221,13 @@ void main()
/* Convert to screen position [0..sizeVp]. */
edgePos = edgeStart = ((gl_Position.xy / gl_Position.w) * 0.5 + 0.5) * sizeViewport.xy;
+#ifdef SELECT_EDGES
+ /* HACK: to avoid loosing sub pixel object in selections, we add a bit of randomness to the
+ * wire to at least create one fragment that will pass the occlusion query. */
+ /* TODO(fclem) Limit this workaround to selection. It's not very noticeable but still... */
+ gl_Position.xy += sizeViewportInv.xy * gl_Position.w * ((gl_VertexID % 2 == 0) ? -1.0 : 1.0);
+#endif
+
#ifdef USE_WORLD_CLIP_PLANES
world_clip_planes_calc_clip_distance(world_pos);
#endif
diff --git a/source/blender/draw/engines/overlay/shaders/extra_wire_vert.glsl b/source/blender/draw/engines/overlay/shaders/extra_wire_vert.glsl
index 97183638a71..0fbf9ba8137 100644
--- a/source/blender/draw/engines/overlay/shaders/extra_wire_vert.glsl
+++ b/source/blender/draw/engines/overlay/shaders/extra_wire_vert.glsl
@@ -1,7 +1,7 @@
in vec3 pos;
in vec4 color;
-in int colorid; /* if equal 0 (i.e: Not specified) use color attrib and stippling. */
+in int colorid; /* if equal 0 (i.e: Not specified) use color attribute and stippling. */
noperspective out vec2 stipple_coord;
flat out vec2 stipple_start;
@@ -17,6 +17,13 @@ void main()
vec3 world_pos = point_object_to_world(pos);
gl_Position = point_world_to_ndc(world_pos);
+#ifdef SELECT_EDGES
+ /* HACK: to avoid loosing sub pixel object in selections, we add a bit of randomness to the
+ * wire to at least create one fragment that will pass the occlusion query. */
+ /* TODO(fclem) Limit this workaround to selection. It's not very noticeable but still... */
+ gl_Position.xy += sizeViewportInv.xy * gl_Position.w * ((gl_VertexID % 2 == 0) ? -1.0 : 1.0);
+#endif
+
stipple_coord = stipple_start = screen_position(gl_Position);
#ifdef OBJECT_WIRE
@@ -34,6 +41,10 @@ void main()
}
#endif
+#ifdef SELECT_EDGES
+ finalColor.a = 0.0; /* No Stipple */
+#endif
+
#ifdef USE_WORLD_CLIP_PLANES
world_clip_planes_calc_clip_distance(world_pos);
#endif
diff --git a/source/blender/draw/engines/overlay/shaders/grid_frag.glsl b/source/blender/draw/engines/overlay/shaders/grid_frag.glsl
index db845c7f1dd..9743f918ce3 100644
--- a/source/blender/draw/engines/overlay/shaders/grid_frag.glsl
+++ b/source/blender/draw/engines/overlay/shaders/grid_frag.glsl
@@ -227,21 +227,20 @@ void main()
}
}
- /* Add a small bias so the grid will always
- * be on top of a mesh with the same depth. */
- float grid_depth = gl_FragCoord.z - 6e-8 - fwidth(gl_FragCoord.z);
float scene_depth = texelFetch(depthBuffer, ivec2(gl_FragCoord.xy), 0).r;
if ((gridFlag & GRID_BACK) != 0) {
fade *= (scene_depth == 1.0) ? 1.0 : 0.0;
}
else {
+ /* Add a small bias so the grid will always be below of a mesh with the same depth. */
+ float grid_depth = gl_FragCoord.z + 4.8e-7;
/* Manual, non hard, depth test:
* Progressively fade the grid below occluders
* (avoids popping visuals due to depth buffer precision) */
/* Harder settings tend to flicker more,
* but have less "see through" appearance. */
- const float test_hardness = 1e7;
- fade *= 1.0 - clamp((grid_depth - scene_depth) * test_hardness, 0.0, 1.0);
+ float bias = max(fwidth(gl_FragCoord.z), 2.4e-7);
+ fade *= linearstep(grid_depth, grid_depth + bias, scene_depth);
}
FragColor.a *= fade;
diff --git a/source/blender/draw/engines/overlay/shaders/sculpt_mask_frag.glsl b/source/blender/draw/engines/overlay/shaders/sculpt_mask_frag.glsl
new file mode 100644
index 00000000000..a778e518392
--- /dev/null
+++ b/source/blender/draw/engines/overlay/shaders/sculpt_mask_frag.glsl
@@ -0,0 +1,10 @@
+
+flat in vec3 faceset_color;
+in float mask_color;
+
+out vec4 fragColor;
+
+void main()
+{
+ fragColor = vec4(faceset_color * vec3(mask_color), 1.0);
+}
diff --git a/source/blender/draw/engines/overlay/shaders/sculpt_mask_vert.glsl b/source/blender/draw/engines/overlay/shaders/sculpt_mask_vert.glsl
index 5d79195a40b..f2b827738ac 100644
--- a/source/blender/draw/engines/overlay/shaders/sculpt_mask_vert.glsl
+++ b/source/blender/draw/engines/overlay/shaders/sculpt_mask_vert.glsl
@@ -8,13 +8,16 @@ in float msk;
out vec4 finalColor;
+flat out vec3 faceset_color;
+out float mask_color;
+
void main()
{
vec3 world_pos = point_object_to_world(pos);
gl_Position = point_world_to_ndc(world_pos);
- finalColor = vec4(mix(vec3(1.0), fset, faceSetsOpacity), 1.0);
- finalColor.rgb *= (1.0 - (msk * maskOpacity));
+ faceset_color = mix(vec3(1.0), fset, faceSetsOpacity);
+ mask_color = 1.0 - (msk * maskOpacity);
#ifdef USE_WORLD_CLIP_PLANES
world_clip_planes_calc_clip_distance(world_pos);
diff --git a/source/blender/draw/engines/overlay/shaders/wireframe_vert.glsl b/source/blender/draw/engines/overlay/shaders/wireframe_vert.glsl
index 3fefe2cc0bf..f7467aa3bf4 100644
--- a/source/blender/draw/engines/overlay/shaders/wireframe_vert.glsl
+++ b/source/blender/draw/engines/overlay/shaders/wireframe_vert.glsl
@@ -4,6 +4,8 @@ uniform bool useColoring;
uniform bool isTransform;
uniform bool isObjectColor;
uniform bool isRandomColor;
+uniform bool isHair;
+uniform vec4 hairDupliMatrix[4];
in vec3 pos;
in vec3 nor;
@@ -101,11 +103,18 @@ void wire_object_color_get(out vec3 rim_col, out vec3 wire_col)
void main()
{
- bool no_attrib = all(equal(nor, vec3(0)));
- vec3 wnor = no_attrib ? ViewMatrixInverse[2].xyz : normalize(normal_object_to_world(nor));
-
+ bool no_attr = all(equal(nor, vec3(0)));
+ vec3 wnor = no_attr ? ViewMatrixInverse[2].xyz : normalize(normal_object_to_world(nor));
vec3 wpos = point_object_to_world(pos);
+ if (isHair) {
+ mat4 obmat = mat4(
+ hairDupliMatrix[0], hairDupliMatrix[1], hairDupliMatrix[2], hairDupliMatrix[3]);
+
+ wpos = (obmat * vec4(pos, 1.0)).xyz;
+ wnor = -normalize(mat3(obmat) * nor);
+ }
+
bool is_persp = (ProjectionMatrix[3][3] == 0.0);
vec3 V = (is_persp) ? normalize(ViewMatrixInverse[3].xyz - wpos) : ViewMatrixInverse[2].xyz;
@@ -152,7 +161,7 @@ void main()
#endif
/* Cull flat edges below threshold. */
- if (!no_attrib && (get_edge_sharpness(wd) < 0.0)) {
+ if (!no_attr && (get_edge_sharpness(wd) < 0.0)) {
edgeStart = vec2(-1.0);
}
diff --git a/source/blender/draw/engines/select/select_engine.c b/source/blender/draw/engines/select/select_engine.c
index 08ec0038755..bb7c947a0b9 100644
--- a/source/blender/draw/engines/select/select_engine.c
+++ b/source/blender/draw/engines/select/select_engine.c
@@ -307,9 +307,6 @@ static void select_draw_scene(void *vedata)
return;
}
- /* dithering and AA break color coding, so disable */
- glDisable(GL_DITHER);
-
DRW_view_set_active(stl->g_data->view_faces);
if (!DRW_pass_is_empty(psl->depth_only_pass)) {
diff --git a/source/blender/draw/engines/workbench/shaders/workbench_curvature_lib.glsl b/source/blender/draw/engines/workbench/shaders/workbench_curvature_lib.glsl
index e6bc4c7bbc6..a4d81393dbc 100644
--- a/source/blender/draw/engines/workbench/shaders/workbench_curvature_lib.glsl
+++ b/source/blender/draw/engines/workbench/shaders/workbench_curvature_lib.glsl
@@ -26,6 +26,10 @@ void curvature_compute(vec2 uv,
if ((object_up != object_down) || (object_right != object_left)) {
return;
}
+ /* Avoid shading background pixels. */
+ if ((object_up == object_right) && (object_right == 0u)) {
+ return;
+ }
float normal_up = workbench_normal_decode(texture(normalBuffer, uv + offset.zy)).g;
float normal_down = workbench_normal_decode(texture(normalBuffer, uv - offset.zy)).g;
diff --git a/source/blender/draw/engines/workbench/shaders/workbench_effect_dof_frag.glsl b/source/blender/draw/engines/workbench/shaders/workbench_effect_dof_frag.glsl
index 0efcfb35929..51007a9f246 100644
--- a/source/blender/draw/engines/workbench/shaders/workbench_effect_dof_frag.glsl
+++ b/source/blender/draw/engines/workbench/shaders/workbench_effect_dof_frag.glsl
@@ -4,7 +4,6 @@
* Converted and adapted from HLSL to GLSL by Clément Foucault
*/
-uniform mat4 ProjectionMatrix;
uniform vec2 invertedViewportSize;
uniform vec2 nearFar;
uniform vec3 dofParams;
diff --git a/source/blender/draw/engines/workbench/shaders/workbench_image_lib.glsl b/source/blender/draw/engines/workbench/shaders/workbench_image_lib.glsl
index 6f99739f259..e45f7a7b9e3 100644
--- a/source/blender/draw/engines/workbench/shaders/workbench_image_lib.glsl
+++ b/source/blender/draw/engines/workbench/shaders/workbench_image_lib.glsl
@@ -24,11 +24,17 @@ bool node_tex_tile_lookup(inout vec3 co, sampler2DArray ima, sampler1DArray map)
vec4 workbench_sample_texture(sampler2D image, vec2 coord, bool nearest_sampling)
{
- vec2 tex_size = vec2(textureSize(image, 0).xy);
/* TODO(fclem) We could do the same with sampler objects.
* But this is a quick workaround instead of messing with the GPUTexture itself. */
- vec2 uv = nearest_sampling ? (floor(coord * tex_size) + 0.5) / tex_size : coord;
- return texture(image, uv);
+ if (nearest_sampling) {
+ /* Use texelFetch for nearest_sampling to reduce glitches. See: T73726 */
+ vec2 tex_size = vec2(textureSize(image, 0).xy);
+ ivec2 uv = ivec2(floor(coord * tex_size) + 0.5);
+ return texelFetch(image, uv, 0);
+ }
+ else {
+ return texture(image, coord);
+ }
}
vec4 workbench_sample_texture_array(sampler2DArray tile_array,
@@ -36,7 +42,6 @@ vec4 workbench_sample_texture_array(sampler2DArray tile_array,
vec2 coord,
bool nearest_sampling)
{
- vec2 tex_size = vec2(textureSize(tile_array, 0).xy);
vec3 uv = vec3(coord, 0);
if (!node_tex_tile_lookup(uv, tile_array, tile_data))
@@ -44,8 +49,15 @@ vec4 workbench_sample_texture_array(sampler2DArray tile_array,
/* TODO(fclem) We could do the same with sampler objects.
* But this is a quick workaround instead of messing with the GPUTexture itself. */
- uv.xy = nearest_sampling ? (floor(uv.xy * tex_size) + 0.5) / tex_size : uv.xy;
- return texture(tile_array, uv);
+ if (nearest_sampling) {
+ /* Use texelFetch for nearest_sampling to reduce glitches. See: T73726 */
+ vec3 tex_size = vec3(textureSize(tile_array, 0));
+ uv.xy = floor(uv.xy * tex_size.xy) + 0.5;
+ return texelFetch(tile_array, ivec3(uv), 0);
+ }
+ else {
+ return texture(tile_array, uv);
+ }
}
uniform sampler2DArray imageTileArray;
diff --git a/source/blender/draw/engines/workbench/shaders/workbench_merge_infront_frag.glsl b/source/blender/draw/engines/workbench/shaders/workbench_merge_infront_frag.glsl
index 58becb03290..b77e168889f 100644
--- a/source/blender/draw/engines/workbench/shaders/workbench_merge_infront_frag.glsl
+++ b/source/blender/draw/engines/workbench/shaders/workbench_merge_infront_frag.glsl
@@ -15,4 +15,4 @@ void main()
/* Make this fragment occlude any fragment that will try to
* render over it in the normal passes. */
gl_FragDepth = 0.0;
-} \ No newline at end of file
+}
diff --git a/source/blender/draw/engines/workbench/shaders/workbench_world_light_lib.glsl b/source/blender/draw/engines/workbench/shaders/workbench_world_light_lib.glsl
index 81f6e651be0..41ef516ee4d 100644
--- a/source/blender/draw/engines/workbench/shaders/workbench_world_light_lib.glsl
+++ b/source/blender/draw/engines/workbench/shaders/workbench_world_light_lib.glsl
@@ -128,4 +128,4 @@ float get_shadow(vec3 N)
float shadow_mix = smoothstep(world_data.shadow_shift, world_data.shadow_focus, light_factor);
shadow_mix *= forceShadowing ? 0.0 : world_data.shadow_mul;
return shadow_mix + world_data.shadow_add;
-} \ No newline at end of file
+}
diff --git a/source/blender/draw/engines/workbench/workbench_data.c b/source/blender/draw/engines/workbench/workbench_data.c
index fc047eadf55..7b08e97ac31 100644
--- a/source/blender/draw/engines/workbench/workbench_data.c
+++ b/source/blender/draw/engines/workbench/workbench_data.c
@@ -182,7 +182,7 @@ void workbench_private_data_init(WORKBENCH_PrivateData *wpd)
WORKBENCH_ViewLayerData *vldata = workbench_view_layer_data_ensure_ex(draw_ctx->view_layer);
wpd->is_playback = DRW_state_is_playback();
- wpd->is_navigating = rv3d && (rv3d->rflag & (RV3D_NAVIGATING | RV3D_PAINTING));
+ wpd->is_navigating = DRW_state_is_navigating();
wpd->ctx_mode = CTX_data_mode_enum_ex(
draw_ctx->object_edit, draw_ctx->obact, draw_ctx->object_mode);
@@ -199,7 +199,6 @@ void workbench_private_data_init(WORKBENCH_PrivateData *wpd)
}
wpd->clip_state = clip_state;
- wpd->cull_state = CULL_BACKFACE_ENABLED(wpd) ? DRW_STATE_CULL_BACK : 0;
wpd->vldata = vldata;
wpd->world_ubo = vldata->world_ubo;
@@ -218,8 +217,7 @@ void workbench_private_data_init(WORKBENCH_PrivateData *wpd)
if (!v3d || (v3d->shading.type == OB_RENDER && BKE_scene_uses_blender_workbench(scene))) {
/* FIXME: This reproduce old behavior when workbench was separated in 2 engines.
* But this is a workaround for a missing update tagging from operators. */
- if (scene->display.shading.type != wpd->shading.type ||
- (v3d && (XRAY_ENABLED(v3d) != XRAY_ENABLED(&scene->display))) ||
+ if ((v3d && (XRAY_ENABLED(v3d) != XRAY_ENABLED(&scene->display))) ||
(scene->display.shading.flag != wpd->shading.flag)) {
wpd->view_updated = true;
}
@@ -246,13 +244,14 @@ void workbench_private_data_init(WORKBENCH_PrivateData *wpd)
else {
/* FIXME: This reproduce old behavior when workbench was separated in 2 engines.
* But this is a workaround for a missing update tagging from operators. */
- if (v3d->shading.type != wpd->shading.type || XRAY_ENABLED(v3d) != XRAY_ENABLED(wpd) ||
- v3d->shading.flag != wpd->shading.flag) {
+ if (XRAY_ENABLED(v3d) != XRAY_ENABLED(wpd) || v3d->shading.flag != wpd->shading.flag) {
wpd->view_updated = true;
}
wpd->shading = v3d->shading;
if (wpd->shading.type < OB_SOLID) {
+ wpd->shading.light = V3D_LIGHTING_FLAT;
+ wpd->shading.color_type = V3D_SHADING_OBJECT_COLOR;
wpd->shading.xray_alpha = 0.0f;
}
else if (XRAY_ENABLED(v3d)) {
@@ -266,6 +265,8 @@ void workbench_private_data_init(WORKBENCH_PrivateData *wpd)
copy_v4_fl(wpd->background_color, 0.0f);
}
+ wpd->cull_state = CULL_BACKFACE_ENABLED(wpd) ? DRW_STATE_CULL_BACK : 0;
+
if (wpd->shading.light == V3D_LIGHTING_MATCAP) {
wpd->studio_light = BKE_studiolight_find(wpd->shading.matcap, STUDIOLIGHT_TYPE_MATCAP);
}
diff --git a/source/blender/draw/engines/workbench/workbench_effect_antialiasing.c b/source/blender/draw/engines/workbench/workbench_effect_antialiasing.c
index a0db09e9273..0e896c4b7bb 100644
--- a/source/blender/draw/engines/workbench/workbench_effect_antialiasing.c
+++ b/source/blender/draw/engines/workbench/workbench_effect_antialiasing.c
@@ -19,7 +19,7 @@
/** \file
* \ingroup draw_engine
*
- * Anti-aliasing:
+ * Anti-Aliasing:
*
* We use SMAA (Smart Morphological Anti-Aliasing) as a fast antialiasing solution.
*
@@ -141,7 +141,6 @@ static bool workbench_in_front_history_needed(WORKBENCH_Data *vedata)
WORKBENCH_StorageList *stl = vedata->stl;
const DRWContextState *draw_ctx = DRW_context_state_get();
const View3D *v3d = draw_ctx->v3d;
- const Object *obact = draw_ctx->obact;
if (!v3d || (v3d->flag2 & V3D_HIDE_OVERLAYS)) {
return false;
@@ -151,11 +150,6 @@ static bool workbench_in_front_history_needed(WORKBENCH_Data *vedata)
return false;
}
- if (!obact || draw_ctx->object_mode != OB_MODE_WEIGHT_PAINT ||
- v3d->overlay.weight_paint_mode_opacity == 0.0) {
- return false;
- }
-
return true;
}
@@ -168,18 +162,37 @@ void workbench_antialiasing_engine_init(WORKBENCH_Data *vedata)
wpd->view = NULL;
- /* reset complete drawing when navigating or during viewport playback. */
+ /* Reset complete drawing when navigating or during viewport playback or when
+ * leaving one of those states. In case of multires modifier the navigation
+ * mesh differs from the viewport mesh, so we need to be sure to restart. */
if (wpd->taa_sample != 0) {
if (wpd->is_navigating || wpd->is_playback) {
wpd->taa_sample = 0;
+ wpd->reset_next_sample = true;
+ }
+ else if (wpd->reset_next_sample) {
+ wpd->taa_sample = 0;
+ wpd->reset_next_sample = false;
}
}
+ /* Reset the TAA when we have already draw a sample, but the sample count differs from previous
+ * time. This removes render artifacts when the viewport anti-aliasing in the user preferences is
+ * set to a lower value. */
+ if (wpd->taa_sample_len != wpd->taa_sample_len_previous) {
+ wpd->taa_sample = 0;
+ wpd->taa_sample_len_previous = wpd->taa_sample_len;
+ }
+
if (wpd->view_updated) {
wpd->taa_sample = 0;
wpd->view_updated = false;
}
+ if (wpd->taa_sample_len > 0 && wpd->valid_history == false) {
+ wpd->taa_sample = 0;
+ }
+
{
float persmat[4][4];
DRW_view_persmat_get(NULL, persmat, false);
@@ -253,13 +266,8 @@ void workbench_antialiasing_engine_init(WORKBENCH_Data *vedata)
false,
NULL);
- GPU_texture_bind(txl->smaa_search_tx, 0);
GPU_texture_filter_mode(txl->smaa_search_tx, true);
- GPU_texture_unbind(txl->smaa_search_tx);
-
- GPU_texture_bind(txl->smaa_area_tx, 0);
GPU_texture_filter_mode(txl->smaa_area_tx, true);
- GPU_texture_unbind(txl->smaa_area_tx);
}
}
else {
@@ -406,13 +414,16 @@ void workbench_antialiasing_draw_pass(WORKBENCH_Data *vedata)
{
WORKBENCH_PrivateData *wpd = vedata->stl->wpd;
WORKBENCH_FramebufferList *fbl = vedata->fbl;
+ WORKBENCH_TextureList *txl = vedata->txl;
WORKBENCH_PassList *psl = vedata->psl;
DefaultFramebufferList *dfbl = DRW_viewport_framebuffer_list_get();
+ DefaultTextureList *dtxl = DRW_viewport_texture_list_get();
if (wpd->taa_sample_len == 0) {
/* AA disabled. */
/* Just set sample to 1 to avoid rendering indefinitely. */
wpd->taa_sample = 1;
+ wpd->valid_history = false;
return;
}
@@ -425,12 +436,15 @@ void workbench_antialiasing_draw_pass(WORKBENCH_Data *vedata)
const bool last_sample = wpd->taa_sample + 1 == wpd->taa_sample_len;
const bool taa_finished = wpd->taa_sample >= wpd->taa_sample_len;
if (wpd->taa_sample == 0) {
+ wpd->valid_history = true;
+ GPU_texture_copy(txl->history_buffer_tx, dtxl->color);
/* In playback mode, we are sure the next redraw will not use the same viewmatrix.
* In this case no need to save the depth buffer. */
- eGPUFrameBufferBits bits = GPU_COLOR_BIT | (!wpd->is_playback ? GPU_DEPTH_BIT : 0);
- GPU_framebuffer_blit(dfbl->default_fb, 0, fbl->antialiasing_fb, 0, bits);
+ if (!wpd->is_playback) {
+ GPU_texture_copy(txl->depth_buffer_tx, dtxl->depth);
+ }
if (workbench_in_front_history_needed(vedata)) {
- GPU_framebuffer_blit(dfbl->in_front_fb, 0, fbl->antialiasing_in_front_fb, 0, GPU_DEPTH_BIT);
+ GPU_texture_copy(txl->depth_buffer_in_front_tx, dtxl->depth_in_front);
}
}
else {
@@ -440,9 +454,9 @@ void workbench_antialiasing_draw_pass(WORKBENCH_Data *vedata)
DRW_draw_pass(psl->aa_accum_ps);
}
/* Copy back the saved depth buffer for correct overlays. */
- GPU_framebuffer_blit(fbl->antialiasing_fb, 0, dfbl->default_fb, 0, GPU_DEPTH_BIT);
+ GPU_texture_copy(dtxl->depth, txl->depth_buffer_tx);
if (workbench_in_front_history_needed(vedata)) {
- GPU_framebuffer_blit(fbl->antialiasing_in_front_fb, 0, dfbl->in_front_fb, 0, GPU_DEPTH_BIT);
+ GPU_texture_copy(dtxl->depth_in_front, txl->depth_buffer_in_front_tx);
}
}
diff --git a/source/blender/draw/engines/workbench/workbench_effect_cavity.c b/source/blender/draw/engines/workbench/workbench_effect_cavity.c
index cdf8a93fc57..4a8db65c02e 100644
--- a/source/blender/draw/engines/workbench/workbench_effect_cavity.c
+++ b/source/blender/draw/engines/workbench/workbench_effect_cavity.c
@@ -42,11 +42,11 @@
/* Using Hammersley distribution */
static float *create_disk_samples(int num_samples, int num_iterations)
{
+ BLI_assert(num_samples * num_iterations <= CAVITY_MAX_SAMPLES);
const int total_samples = num_samples * num_iterations;
const float num_samples_inv = 1.0f / num_samples;
/* vec4 to ensure memory alignment. */
float(*texels)[4] = MEM_callocN(sizeof(float[4]) * CAVITY_MAX_SAMPLES, __func__);
-
for (int i = 0; i < total_samples; i++) {
float it_add = (i / num_samples) * 0.499f;
float r = fmodf((i + 0.5f + it_add) * num_samples_inv, 1.0f);
@@ -102,7 +102,7 @@ void workbench_cavity_data_update(WORKBENCH_PrivateData *wpd, WORKBENCH_UBO_Worl
if (CAVITY_ENABLED(wpd)) {
int cavity_sample_count_single_iteration = scene->display.matcap_ssao_samples;
int cavity_sample_count_total = workbench_cavity_total_sample_count(wpd, scene);
- int max_iter_count = cavity_sample_count_total / cavity_sample_count_single_iteration;
+ const int max_iter_count = cavity_sample_count_total / cavity_sample_count_single_iteration;
int sample = wpd->taa_sample % max_iter_count;
wd->cavity_sample_start = cavity_sample_count_single_iteration * sample;
@@ -128,6 +128,7 @@ void workbench_cavity_samples_ubo_ensure(WORKBENCH_PrivateData *wpd)
int cavity_sample_count_single_iteration = scene->display.matcap_ssao_samples;
int cavity_sample_count = workbench_cavity_total_sample_count(wpd, scene);
+ const int max_iter_count = max_ii(1, cavity_sample_count / cavity_sample_count_single_iteration);
if (wpd->vldata->cavity_sample_count != cavity_sample_count) {
DRW_UBO_FREE_SAFE(wpd->vldata->cavity_sample_ubo);
@@ -135,8 +136,7 @@ void workbench_cavity_samples_ubo_ensure(WORKBENCH_PrivateData *wpd)
}
if (wpd->vldata->cavity_sample_ubo == NULL) {
- float *samples = create_disk_samples(cavity_sample_count_single_iteration,
- max_ii(1, wpd->taa_sample_len));
+ float *samples = create_disk_samples(cavity_sample_count_single_iteration, max_iter_count);
wpd->vldata->cavity_jitter_tx = create_jitter_texture(cavity_sample_count);
/* NOTE: Uniform buffer needs to always be filled to be valid. */
wpd->vldata->cavity_sample_ubo = DRW_uniformbuffer_create(
diff --git a/source/blender/draw/engines/workbench/workbench_engine.c b/source/blender/draw/engines/workbench/workbench_engine.c
index c6c594dc04d..511dd563b46 100644
--- a/source/blender/draw/engines/workbench/workbench_engine.c
+++ b/source/blender/draw/engines/workbench/workbench_engine.c
@@ -55,6 +55,7 @@ void workbench_engine_init(void *ved)
if (!stl->wpd) {
stl->wpd = MEM_callocN(sizeof(*stl->wpd), __func__);
+ stl->wpd->taa_sample_len_previous = -1;
stl->wpd->view_updated = true;
}
@@ -112,13 +113,12 @@ static void workbench_cache_sculpt_populate(WORKBENCH_PrivateData *wpd,
Object *ob,
eV3DShadingColorType color_type)
{
- const bool use_vcol = ELEM(color_type, V3D_SHADING_VERTEX_COLOR);
const bool use_single_drawcall = !ELEM(color_type, V3D_SHADING_MATERIAL_COLOR);
BLI_assert(wpd->shading.color_type != V3D_SHADING_TEXTURE_COLOR);
if (use_single_drawcall) {
DRWShadingGroup *grp = workbench_material_setup(wpd, ob, 0, color_type, NULL);
- DRW_shgroup_call_sculpt(grp, ob, false, false, use_vcol);
+ DRW_shgroup_call_sculpt(grp, ob, false, false);
}
else {
const int materials_len = DRW_cache_object_material_count_get(ob);
@@ -126,7 +126,7 @@ static void workbench_cache_sculpt_populate(WORKBENCH_PrivateData *wpd,
for (int i = 0; i < materials_len; i++) {
shgrps[i] = workbench_material_setup(wpd, ob, i + 1, color_type, NULL);
}
- DRW_shgroup_call_sculpt_with_materials(shgrps, ob, false);
+ DRW_shgroup_call_sculpt_with_materials(shgrps, materials_len, ob);
}
}
@@ -153,6 +153,9 @@ static void workbench_cache_texpaint_populate(WORKBENCH_PrivateData *wpd, Object
if (geoms) {
const int materials_len = DRW_cache_object_material_count_get(ob);
for (int i = 0; i < materials_len; i++) {
+ if (geoms[i] == NULL) {
+ continue;
+ }
DRWShadingGroup *grp = workbench_image_setup(wpd, ob, i + 1, NULL, NULL, 0);
DRW_shgroup_call(grp, geoms[i], ob);
}
@@ -184,6 +187,9 @@ static void workbench_cache_common_populate(WORKBENCH_PrivateData *wpd,
if (geoms) {
const int materials_len = DRW_cache_object_material_count_get(ob);
for (int i = 0; i < materials_len; i++) {
+ if (geoms[i] == NULL) {
+ continue;
+ }
DRWShadingGroup *grp = workbench_material_setup(wpd, ob, i + 1, color_type, r_transp);
DRW_shgroup_call(grp, geoms[i], ob);
}
@@ -315,8 +321,8 @@ void workbench_cache_populate(void *ved, Object *ob)
}
if (!(ob->base_flag & BASE_FROM_DUPLI)) {
- ModifierData *md = modifiers_findByType(ob, eModifierType_Fluid);
- if (md && modifier_isEnabled(wpd->scene, md, eModifierMode_Realtime)) {
+ ModifierData *md = BKE_modifiers_findby_type(ob, eModifierType_Fluid);
+ if (md && BKE_modifier_is_enabled(wpd->scene, md, eModifierMode_Realtime)) {
FluidModifierData *fmd = (FluidModifierData *)md;
if (fmd->domain && fmd->domain->type == FLUID_DOMAIN_TYPE_GAS) {
workbench_volume_cache_populate(vedata, wpd->scene, ob, md, V3D_SHADING_SINGLE_COLOR);
diff --git a/source/blender/draw/engines/workbench/workbench_materials.c b/source/blender/draw/engines/workbench/workbench_materials.c
index a2abecb679f..b36a4a3a494 100644
--- a/source/blender/draw/engines/workbench/workbench_materials.c
+++ b/source/blender/draw/engines/workbench/workbench_materials.c
@@ -267,7 +267,6 @@ DRWShadingGroup *workbench_image_setup_ex(WORKBENCH_PrivateData *wpd,
}
if (tex == NULL) {
- printf("Image not found\n");
tex = wpd->dummy_image_tx;
}
@@ -285,11 +284,11 @@ DRWShadingGroup *workbench_image_setup_ex(WORKBENCH_PrivateData *wpd,
*grp_tex = grp = DRW_shgroup_create_sub(grp);
if (tex_tile_data) {
- DRW_shgroup_uniform_texture_persistent(grp, "imageTileArray", tex);
- DRW_shgroup_uniform_texture_persistent(grp, "imageTileData", tex_tile_data);
+ DRW_shgroup_uniform_texture(grp, "imageTileArray", tex);
+ DRW_shgroup_uniform_texture(grp, "imageTileData", tex_tile_data);
}
else {
- DRW_shgroup_uniform_texture_persistent(grp, "imageTexture", tex);
+ DRW_shgroup_uniform_texture(grp, "imageTexture", tex);
}
DRW_shgroup_uniform_bool_copy(grp, "imagePremult", (ima && ima->alpha_mode == IMA_ALPHA_PREMUL));
DRW_shgroup_uniform_bool_copy(grp, "imageNearest", (interp == SHD_INTERP_CLOSEST));
diff --git a/source/blender/draw/engines/workbench/workbench_opaque.c b/source/blender/draw/engines/workbench/workbench_opaque.c
index 08511ca092c..27d5b71f35c 100644
--- a/source/blender/draw/engines/workbench/workbench_opaque.c
+++ b/source/blender/draw/engines/workbench/workbench_opaque.c
@@ -92,22 +92,24 @@ void workbench_opaque_cache_init(WORKBENCH_Data *data)
wpd->prepass[opaque][infront][hair].common_shgrp = grp = DRW_shgroup_create(sh, pass);
DRW_shgroup_uniform_block(grp, "material_block", wpd->material_ubo_curr);
DRW_shgroup_uniform_int_copy(grp, "materialIndex", -1);
+ DRW_shgroup_uniform_bool_copy(grp, "useMatcap", use_matcap);
wpd->prepass[opaque][infront][hair].vcol_shgrp = grp = DRW_shgroup_create(sh, pass);
- DRW_shgroup_uniform_block_persistent(grp, "material_block", wpd->material_ubo_curr);
+ DRW_shgroup_uniform_block(grp, "material_block", wpd->material_ubo_curr);
DRW_shgroup_uniform_int_copy(grp, "materialIndex", 0); /* Default material. (uses vcol) */
+ DRW_shgroup_uniform_bool_copy(grp, "useMatcap", use_matcap);
sh = workbench_shader_opaque_image_get(wpd, hair, false);
wpd->prepass[opaque][infront][hair].image_shgrp = grp = DRW_shgroup_create(sh, pass);
- DRW_shgroup_uniform_block_persistent(grp, "material_block", wpd->material_ubo_curr);
+ DRW_shgroup_uniform_block(grp, "material_block", wpd->material_ubo_curr);
DRW_shgroup_uniform_int_copy(grp, "materialIndex", 0); /* Default material. */
DRW_shgroup_uniform_bool_copy(grp, "useMatcap", use_matcap);
sh = workbench_shader_opaque_image_get(wpd, hair, true);
wpd->prepass[opaque][infront][hair].image_tiled_shgrp = grp = DRW_shgroup_create(sh, pass);
- DRW_shgroup_uniform_block_persistent(grp, "material_block", wpd->material_ubo_curr);
+ DRW_shgroup_uniform_block(grp, "material_block", wpd->material_ubo_curr);
DRW_shgroup_uniform_int_copy(grp, "materialIndex", 0); /* Default material. */
DRW_shgroup_uniform_bool_copy(grp, "useMatcap", use_matcap);
}
@@ -121,9 +123,9 @@ void workbench_opaque_cache_init(WORKBENCH_Data *data)
sh = workbench_shader_composite_get(wpd);
grp = DRW_shgroup_create(sh, psl->composite_ps);
- DRW_shgroup_uniform_block_persistent(grp, "world_block", wpd->world_ubo);
- DRW_shgroup_uniform_texture_persistent(grp, "materialBuffer", wpd->material_buffer_tx);
- DRW_shgroup_uniform_texture_persistent(grp, "normalBuffer", wpd->normal_buffer_tx);
+ DRW_shgroup_uniform_block(grp, "world_block", wpd->world_ubo);
+ DRW_shgroup_uniform_texture(grp, "materialBuffer", wpd->material_buffer_tx);
+ DRW_shgroup_uniform_texture(grp, "normalBuffer", wpd->normal_buffer_tx);
DRW_shgroup_uniform_bool_copy(grp, "forceShadowing", false);
DRW_shgroup_stencil_mask(grp, 0x00);
@@ -135,8 +137,8 @@ void workbench_opaque_cache_init(WORKBENCH_Data *data)
struct GPUTexture *spec_tx = wpd->studio_light->matcap_specular.gputexture;
const bool use_spec = workbench_is_specular_highlight_enabled(wpd);
spec_tx = (use_spec && spec_tx) ? spec_tx : diff_tx;
- DRW_shgroup_uniform_texture_persistent(grp, "matcapDiffuseImage", diff_tx);
- DRW_shgroup_uniform_texture_persistent(grp, "matcapSpecularImage", spec_tx);
+ DRW_shgroup_uniform_texture(grp, "matcapDiffuseImage", diff_tx);
+ DRW_shgroup_uniform_texture(grp, "matcapSpecularImage", spec_tx);
}
DRW_shgroup_call_procedural_triangles(grp, NULL, 1);
diff --git a/source/blender/draw/engines/workbench/workbench_private.h b/source/blender/draw/engines/workbench/workbench_private.h
index 87b1c82ce94..967bdf9bae0 100644
--- a/source/blender/draw/engines/workbench/workbench_private.h
+++ b/source/blender/draw/engines/workbench/workbench_private.h
@@ -261,12 +261,16 @@ typedef struct WORKBENCH_PrivateData {
/* Temporal Antialiasing */
/** Total number of samples to after which TAA stops accumulating samples. */
int taa_sample_len;
+ /** Total number of samples of the previous TAA. When changed TAA will be reset. */
+ int taa_sample_len_previous;
/** Current TAA sample index in [0..taa_sample_len[ range. */
int taa_sample;
/** Inverse of taa_sample to divide the accumulation buffer. */
float taa_sample_inv;
/** If the view has been updated and TAA needs to be reset. */
bool view_updated;
+ /** True if the history buffer contains relevant data and false if it could contain garbage. */
+ bool valid_history;
/** View */
struct DRWView *view;
/** Last projection matrix to see if view is still valid. */
@@ -333,6 +337,7 @@ typedef struct WORKBENCH_PrivateData {
bool dof_enabled;
bool is_playback;
bool is_navigating;
+ bool reset_next_sample;
} WORKBENCH_PrivateData; /* Transient data */
typedef struct WORKBENCH_ObjectData {
diff --git a/source/blender/draw/engines/workbench/workbench_render.c b/source/blender/draw/engines/workbench/workbench_render.c
index 5a315e80a47..9e66bcb07f4 100644
--- a/source/blender/draw/engines/workbench/workbench_render.c
+++ b/source/blender/draw/engines/workbench/workbench_render.c
@@ -52,14 +52,12 @@ static void workbench_render_cache(void *vedata,
static void workbench_render_matrices_init(RenderEngine *engine, Depsgraph *depsgraph)
{
/* TODO(sergey): Shall render hold pointer to an evaluated camera instead? */
- Scene *scene = DEG_get_evaluated_scene(depsgraph);
struct Object *ob_camera_eval = DEG_get_evaluated_object(depsgraph, RE_GetCamera(engine->re));
- float frame = BKE_scene_frame_get(scene);
/* Set the persective, view and window matrix. */
float winmat[4][4], viewmat[4][4], viewinv[4][4];
- RE_GetCameraWindow(engine->re, ob_camera_eval, frame, winmat);
+ RE_GetCameraWindow(engine->re, ob_camera_eval, winmat);
RE_GetCameraModelMatrix(engine->re, ob_camera_eval, viewinv);
invert_m4_m4(viewmat, viewinv);
diff --git a/source/blender/draw/engines/workbench/workbench_shader.c b/source/blender/draw/engines/workbench/workbench_shader.c
index 2e796056029..99366779b22 100644
--- a/source/blender/draw/engines/workbench/workbench_shader.c
+++ b/source/blender/draw/engines/workbench/workbench_shader.c
@@ -23,6 +23,7 @@
#include "DRW_render.h"
#include "BLI_dynstr.h"
+#include "BLI_string_utils.h"
#include "workbench_engine.h"
#include "workbench_private.h"
@@ -359,32 +360,24 @@ void workbench_shader_depth_of_field_get(GPUShader **prepare_sh,
GPUShader **resolve_sh)
{
if (e_data.dof_prepare_sh == NULL) {
- e_data.dof_prepare_sh = DRW_shader_create_fullscreen(datatoc_workbench_effect_dof_frag_glsl,
- "#define PREPARE\n");
-
- e_data.dof_downsample_sh = DRW_shader_create_fullscreen(datatoc_workbench_effect_dof_frag_glsl,
- "#define DOWNSAMPLE\n");
+ char *frag = BLI_string_joinN(datatoc_common_view_lib_glsl,
+ datatoc_workbench_effect_dof_frag_glsl);
+ e_data.dof_prepare_sh = DRW_shader_create_fullscreen(frag, "#define PREPARE\n");
+ e_data.dof_downsample_sh = DRW_shader_create_fullscreen(frag, "#define DOWNSAMPLE\n");
#if 0 /* TODO(fclem) finish COC min_max optimization */
- e_data.dof_flatten_v_sh = DRW_shader_create_fullscreen(datatoc_workbench_effect_dof_frag_glsl,
+ e_data.dof_flatten_v_sh = DRW_shader_create_fullscreen(frag,
"#define FLATTEN_VERTICAL\n");
-
- e_data.dof_flatten_h_sh = DRW_shader_create_fullscreen(datatoc_workbench_effect_dof_frag_glsl,
+ e_data.dof_flatten_h_sh = DRW_shader_create_fullscreen(frag,
"#define FLATTEN_HORIZONTAL\n");
-
- e_data.dof_dilate_v_sh = DRW_shader_create_fullscreen(datatoc_workbench_effect_dof_frag_glsl,
+ e_data.dof_dilate_v_sh = DRW_shader_create_fullscreen(frag,
"#define DILATE_VERTICAL\n");
-
- e_data.dof_dilate_h_sh = DRW_shader_create_fullscreen(datatoc_workbench_effect_dof_frag_glsl,
+ e_data.dof_dilate_h_sh = DRW_shader_create_fullscreen(frag,
"#define DILATE_HORIZONTAL\n");
#endif
- e_data.dof_blur1_sh = DRW_shader_create_fullscreen(datatoc_workbench_effect_dof_frag_glsl,
- "#define BLUR1\n");
-
- e_data.dof_blur2_sh = DRW_shader_create_fullscreen(datatoc_workbench_effect_dof_frag_glsl,
- "#define BLUR2\n");
-
- e_data.dof_resolve_sh = DRW_shader_create_fullscreen(datatoc_workbench_effect_dof_frag_glsl,
- "#define RESOLVE\n");
+ e_data.dof_blur1_sh = DRW_shader_create_fullscreen(frag, "#define BLUR1\n");
+ e_data.dof_blur2_sh = DRW_shader_create_fullscreen(frag, "#define BLUR2\n");
+ e_data.dof_resolve_sh = DRW_shader_create_fullscreen(frag, "#define RESOLVE\n");
+ MEM_freeN(frag);
}
*prepare_sh = e_data.dof_prepare_sh;
diff --git a/source/blender/draw/engines/workbench/workbench_shadow.c b/source/blender/draw/engines/workbench/workbench_shadow.c
index efd0ad9134e..2cf5f3c4c13 100644
--- a/source/blender/draw/engines/workbench/workbench_shadow.c
+++ b/source/blender/draw/engines/workbench/workbench_shadow.c
@@ -333,6 +333,11 @@ void workbench_shadow_cache_populate(WORKBENCH_Data *data, Object *ob, const boo
use_shadow_pass_technique = false;
}
+ /* We cannot use Shadow Pass technique on non-manifold object (see T76168). */
+ if (use_shadow_pass_technique && !is_manifold && (wpd->cull_state != 0)) {
+ use_shadow_pass_technique = false;
+ }
+
if (use_shadow_pass_technique) {
grp = DRW_shgroup_create_sub(wpd->shadow_pass_grp[is_manifold]);
DRW_shgroup_uniform_vec3(grp, "lightDirection", engine_object_data->shadow_dir, 1);
diff --git a/source/blender/draw/engines/workbench/workbench_transparent.c b/source/blender/draw/engines/workbench/workbench_transparent.c
index 39aa721a41c..5fd8229304a 100644
--- a/source/blender/draw/engines/workbench/workbench_transparent.c
+++ b/source/blender/draw/engines/workbench/workbench_transparent.c
@@ -67,7 +67,7 @@ void workbench_transparent_engine_init(WORKBENCH_Data *data)
static void workbench_transparent_lighting_uniforms(WORKBENCH_PrivateData *wpd,
DRWShadingGroup *grp)
{
- DRW_shgroup_uniform_block_persistent(grp, "world_block", wpd->world_ubo);
+ DRW_shgroup_uniform_block(grp, "world_block", wpd->world_ubo);
DRW_shgroup_uniform_bool_copy(grp, "forceShadowing", false);
if (STUDIOLIGHT_TYPE_MATCAP_ENABLED(wpd)) {
@@ -78,8 +78,8 @@ static void workbench_transparent_lighting_uniforms(WORKBENCH_PrivateData *wpd,
struct GPUTexture *spec_tx = wpd->studio_light->matcap_specular.gputexture;
const bool use_spec = workbench_is_specular_highlight_enabled(wpd);
spec_tx = (use_spec && spec_tx) ? spec_tx : diff_tx;
- DRW_shgroup_uniform_texture_persistent(grp, "matcapDiffuseImage", diff_tx);
- DRW_shgroup_uniform_texture_persistent(grp, "matcapSpecularImage", spec_tx);
+ DRW_shgroup_uniform_texture(grp, "matcapDiffuseImage", diff_tx);
+ DRW_shgroup_uniform_texture(grp, "matcapSpecularImage", spec_tx);
}
}
@@ -116,20 +116,20 @@ void workbench_transparent_cache_init(WORKBENCH_Data *data)
workbench_transparent_lighting_uniforms(wpd, grp);
wpd->prepass[transp][infront][hair].vcol_shgrp = grp = DRW_shgroup_create(sh, pass);
- DRW_shgroup_uniform_block_persistent(grp, "material_block", wpd->material_ubo_curr);
+ DRW_shgroup_uniform_block(grp, "material_block", wpd->material_ubo_curr);
DRW_shgroup_uniform_int_copy(grp, "materialIndex", 0); /* Default material. (uses vcol) */
sh = workbench_shader_transparent_image_get(wpd, hair, false);
wpd->prepass[transp][infront][hair].image_shgrp = grp = DRW_shgroup_create(sh, pass);
- DRW_shgroup_uniform_block_persistent(grp, "material_block", wpd->material_ubo_curr);
+ DRW_shgroup_uniform_block(grp, "material_block", wpd->material_ubo_curr);
DRW_shgroup_uniform_int_copy(grp, "materialIndex", 0); /* Default material. */
workbench_transparent_lighting_uniforms(wpd, grp);
sh = workbench_shader_transparent_image_get(wpd, hair, true);
wpd->prepass[transp][infront][hair].image_tiled_shgrp = grp = DRW_shgroup_create(sh, pass);
- DRW_shgroup_uniform_block_persistent(grp, "material_block", wpd->material_ubo_curr);
+ DRW_shgroup_uniform_block(grp, "material_block", wpd->material_ubo_curr);
DRW_shgroup_uniform_int_copy(grp, "materialIndex", 0); /* Default material. */
workbench_transparent_lighting_uniforms(wpd, grp);
}
diff --git a/source/blender/draw/engines/workbench/workbench_volume.c b/source/blender/draw/engines/workbench/workbench_volume.c
index 951712d6ba3..21cb567aaae 100644
--- a/source/blender/draw/engines/workbench/workbench_volume.c
+++ b/source/blender/draw/engines/workbench/workbench_volume.c
@@ -28,6 +28,7 @@
#include "DNA_volume_types.h"
#include "BLI_dynstr.h"
+#include "BLI_listbase.h"
#include "BLI_rand.h"
#include "BLI_string_utils.h"
@@ -290,7 +291,7 @@ void workbench_volume_draw_finish(WORKBENCH_Data *vedata)
* modifier we don't want them to take precious VRAM if the
* modifier is not used for display. We should share them for
* all viewport in a redraw at least. */
- for (LinkData *link = wpd->smoke_domains.first; link; link = link->next) {
+ LISTBASE_FOREACH (LinkData *, link, &wpd->smoke_domains) {
FluidModifierData *mmd = (FluidModifierData *)link->data;
GPU_free_smoke(mmd);
}
diff --git a/source/blender/draw/intern/DRW_render.h b/source/blender/draw/intern/DRW_render.h
index 382e7313f21..e7dd9e449b7 100644
--- a/source/blender/draw/intern/DRW_render.h
+++ b/source/blender/draw/intern/DRW_render.h
@@ -210,10 +210,7 @@ struct GPUShader *DRW_shader_create_with_transform_feedback(const char *vert,
const eGPUShaderTFBType prim_type,
const char **varying_names,
const int varying_count);
-struct GPUShader *DRW_shader_create_2d(const char *frag, const char *defines);
-struct GPUShader *DRW_shader_create_3d(const char *frag, const char *defines);
struct GPUShader *DRW_shader_create_fullscreen(const char *frag, const char *defines);
-struct GPUShader *DRW_shader_create_3d_depth_only(eGPUShaderConfig slot);
struct GPUMaterial *DRW_shader_find_from_world(struct World *wo,
const void *engine_type,
const int options,
@@ -224,6 +221,7 @@ struct GPUMaterial *DRW_shader_find_from_material(struct Material *ma,
bool deferred);
struct GPUMaterial *DRW_shader_create_from_world(struct Scene *scene,
struct World *wo,
+ struct bNodeTree *ntree,
const void *engine_type,
const int options,
const bool is_volume_shader,
@@ -234,6 +232,7 @@ struct GPUMaterial *DRW_shader_create_from_world(struct Scene *scene,
bool deferred);
struct GPUMaterial *DRW_shader_create_from_material(struct Scene *scene,
struct Material *ma,
+ struct bNodeTree *ntree,
const void *engine_type,
const int options,
const bool is_volume_shader,
@@ -365,6 +364,8 @@ DRWShadingGroup *DRW_shgroup_transform_feedback_create(struct GPUShader *shader,
DRWPass *pass,
struct GPUVertBuf *tf_target);
+void DRW_shgroup_add_material_resources(DRWShadingGroup *grp, struct GPUMaterial *material);
+
/* return final visibility */
typedef bool(DRWCallVisibilityFn)(bool vis_in, void *user_data);
@@ -404,14 +405,14 @@ void DRW_shgroup_call_instances(DRWShadingGroup *shgroup,
Object *ob,
struct GPUBatch *geom,
uint count);
-/* Warning: Only use with Shaders that have INSTANCED_ATTRIB defined. */
-void DRW_shgroup_call_instances_with_attribs(DRWShadingGroup *shgroup,
- Object *ob,
- struct GPUBatch *geom,
- struct GPUBatch *inst_attributes);
+/* Warning: Only use with Shaders that have INSTANCED_ATTR defined. */
+void DRW_shgroup_call_instances_with_attrs(DRWShadingGroup *shgroup,
+ Object *ob,
+ struct GPUBatch *geom,
+ struct GPUBatch *inst_attributes);
-void DRW_shgroup_call_sculpt(DRWShadingGroup *sh, Object *ob, bool wire, bool mask, bool vcol);
-void DRW_shgroup_call_sculpt_with_materials(DRWShadingGroup **sh, Object *ob, bool vcol);
+void DRW_shgroup_call_sculpt(DRWShadingGroup *sh, Object *ob, bool wire, bool mask);
+void DRW_shgroup_call_sculpt_with_materials(DRWShadingGroup **sh, int num_sh, Object *ob);
DRWCallBuffer *DRW_shgroup_call_buffer(DRWShadingGroup *shading_group,
struct GPUVertFormat *format,
@@ -460,18 +461,15 @@ void DRW_shgroup_clear_framebuffer(DRWShadingGroup *shgroup,
void DRW_shgroup_uniform_texture(DRWShadingGroup *shgroup,
const char *name,
const struct GPUTexture *tex);
-void DRW_shgroup_uniform_texture_persistent(DRWShadingGroup *shgroup,
- const char *name,
- const struct GPUTexture *tex);
-void DRW_shgroup_uniform_block(DRWShadingGroup *shgroup,
- const char *name,
- const struct GPUUniformBuffer *ubo);
-void DRW_shgroup_uniform_block_persistent(DRWShadingGroup *shgroup,
- const char *name,
- const struct GPUUniformBuffer *ubo);
void DRW_shgroup_uniform_texture_ref(DRWShadingGroup *shgroup,
const char *name,
struct GPUTexture **tex);
+void DRW_shgroup_uniform_block(DRWShadingGroup *shgroup,
+ const char *name,
+ const struct GPUUniformBuffer *ubo);
+void DRW_shgroup_uniform_block_ref(DRWShadingGroup *shgroup,
+ const char *name,
+ struct GPUUniformBuffer **ubo);
void DRW_shgroup_uniform_float(DRWShadingGroup *shgroup,
const char *name,
const float *value,
@@ -521,11 +519,17 @@ void DRW_shgroup_uniform_float_copy(DRWShadingGroup *shgroup, const char *name,
void DRW_shgroup_uniform_vec2_copy(DRWShadingGroup *shgroup, const char *name, const float *value);
void DRW_shgroup_uniform_vec3_copy(DRWShadingGroup *shgroup, const char *name, const float *value);
void DRW_shgroup_uniform_vec4_copy(DRWShadingGroup *shgroup, const char *name, const float *value);
+void DRW_shgroup_uniform_vec4_array_copy(DRWShadingGroup *shgroup,
+ const char *name,
+ const float (*value)[4],
+ int arraysize);
bool DRW_shgroup_is_empty(DRWShadingGroup *shgroup);
/* Passes */
DRWPass *DRW_pass_create(const char *name, DRWState state);
+DRWPass *DRW_pass_create_instance(const char *name, DRWPass *original, DRWState state);
+void DRW_pass_link(DRWPass *first, DRWPass *second);
/* TODO Replace with passes inheritance. */
void DRW_pass_state_set(DRWPass *pass, DRWState state);
void DRW_pass_state_add(DRWPass *pass, DRWState state);
@@ -539,6 +543,8 @@ void DRW_pass_sort_shgroup_reverse(DRWPass *pass);
bool DRW_pass_is_empty(DRWPass *pass);
#define DRW_PASS_CREATE(pass, state) (pass = DRW_pass_create(#pass, state))
+#define DRW_PASS_INSTANCE_CREATE(pass, original, state) \
+ (pass = DRW_pass_create_instance(#pass, (original), state))
/* Views */
DRWView *DRW_view_create(const float viewmat[4][4],
@@ -670,6 +676,7 @@ bool DRW_state_do_color_management(void);
bool DRW_state_is_scene_render(void);
bool DRW_state_is_opengl_render(void);
bool DRW_state_is_playback(void);
+bool DRW_state_is_navigating(void);
bool DRW_state_show_text(void);
bool DRW_state_draw_support(void);
bool DRW_state_draw_background(void);
@@ -691,6 +698,8 @@ typedef struct DRWContextState {
struct Depsgraph *depsgraph;
+ struct TaskGraph *task_graph;
+
eObjectMode object_mode;
eGPUShaderConfig sh_cfg;
diff --git a/source/blender/draw/intern/draw_cache.c b/source/blender/draw/intern/draw_cache.c
index ffd3be9280f..c23ea3d7c82 100644
--- a/source/blender/draw/intern/draw_cache.c
+++ b/source/blender/draw/intern/draw_cache.c
@@ -2898,12 +2898,12 @@ GPUBatch *DRW_cache_curve_edge_overlay_get(Object *ob)
return DRW_curve_batch_cache_get_edit_edges(cu);
}
-GPUBatch *DRW_cache_curve_vert_overlay_get(Object *ob, bool handles)
+GPUBatch *DRW_cache_curve_vert_overlay_get(Object *ob)
{
BLI_assert(ELEM(ob->type, OB_CURVE, OB_SURF));
struct Curve *cu = ob->data;
- return DRW_curve_batch_cache_get_edit_verts(cu, handles);
+ return DRW_curve_batch_cache_get_edit_verts(cu);
}
GPUBatch *DRW_cache_curve_surface_get(Object *ob)
@@ -3081,8 +3081,7 @@ GPUBatch *DRW_cache_text_loose_edges_get(Object *ob)
return DRW_mesh_batch_cache_get_loose_edges(mesh_eval);
}
else {
- /* TODO */
- return NULL;
+ return DRW_curve_batch_cache_get_wire_edge(cu);
}
}
@@ -3535,13 +3534,15 @@ void drw_batch_cache_generate_requested(Object *ob)
struct Mesh *mesh_eval = BKE_object_get_evaluated_mesh(ob);
switch (ob->type) {
case OB_MESH:
- DRW_mesh_batch_cache_create_requested(ob, (Mesh *)ob->data, scene, is_paint_mode, use_hide);
+ DRW_mesh_batch_cache_create_requested(
+ DST.task_graph, ob, (Mesh *)ob->data, scene, is_paint_mode, use_hide);
break;
case OB_CURVE:
case OB_FONT:
case OB_SURF:
if (mesh_eval) {
- DRW_mesh_batch_cache_create_requested(ob, mesh_eval, scene, is_paint_mode, use_hide);
+ DRW_mesh_batch_cache_create_requested(
+ DST.task_graph, ob, mesh_eval, scene, is_paint_mode, use_hide);
}
DRW_curve_batch_cache_create_requested(ob);
break;
diff --git a/source/blender/draw/intern/draw_cache.h b/source/blender/draw/intern/draw_cache.h
index 77c7b6b9307..221fb89612f 100644
--- a/source/blender/draw/intern/draw_cache.h
+++ b/source/blender/draw/intern/draw_cache.h
@@ -150,7 +150,7 @@ struct GPUBatch *DRW_cache_curve_edge_detection_get(struct Object *ob, bool *r_i
/* edit-mode */
struct GPUBatch *DRW_cache_curve_edge_normal_get(struct Object *ob);
struct GPUBatch *DRW_cache_curve_edge_overlay_get(struct Object *ob);
-struct GPUBatch *DRW_cache_curve_vert_overlay_get(struct Object *ob, bool handles);
+struct GPUBatch *DRW_cache_curve_vert_overlay_get(struct Object *ob);
/* Font */
struct GPUBatch *DRW_cache_text_surface_get(struct Object *ob);
diff --git a/source/blender/draw/intern/draw_cache_extract.h b/source/blender/draw/intern/draw_cache_extract.h
index 0e02b07e95b..f203c2ff1ea 100644
--- a/source/blender/draw/intern/draw_cache_extract.h
+++ b/source/blender/draw/intern/draw_cache_extract.h
@@ -23,6 +23,8 @@
#ifndef __DRAW_CACHE_EXTRACT_H__
#define __DRAW_CACHE_EXTRACT_H__
+struct TaskGraph;
+
/* Vertex Group Selection and display options */
typedef struct DRW_MeshWeightState {
int defgroup_active;
@@ -249,10 +251,12 @@ typedef struct MeshBatchCache {
bool no_loose_wire;
} MeshBatchCache;
-void mesh_buffer_cache_create_requested(MeshBatchCache *cache,
+void mesh_buffer_cache_create_requested(struct TaskGraph *task_graph,
+ MeshBatchCache *cache,
MeshBufferCache mbc,
Mesh *me,
const bool is_editmode,
+ const bool is_paint_mode,
const float obmat[4][4],
const bool do_final,
const bool do_uvedit,
diff --git a/source/blender/draw/intern/draw_cache_extract_mesh.c b/source/blender/draw/intern/draw_cache_extract_mesh.c
index 54e745102f0..06462d5b9c5 100644
--- a/source/blender/draw/intern/draw_cache_extract_mesh.c
+++ b/source/blender/draw/intern/draw_cache_extract_mesh.c
@@ -105,6 +105,14 @@ typedef struct MeshRenderData {
BMEditMesh *edit_bmesh;
BMesh *bm;
EditMeshData *edit_data;
+
+ /* For deformed edit-mesh data. */
+ /* Use for #ME_WRAPPER_TYPE_BMESH. */
+ const float (*bm_vert_coords)[3];
+ const float (*bm_vert_normals)[3];
+ const float (*bm_poly_normals)[3];
+ const float (*bm_poly_centers)[3];
+
int *v_origindex, *e_origindex, *p_origindex;
int crease_ofs;
int bweight_ofs;
@@ -126,14 +134,12 @@ typedef struct MeshRenderData {
float (*poly_normals)[3];
int *lverts, *ledges;
} MeshRenderData;
-
static MeshRenderData *mesh_render_data_create(Mesh *me,
const bool is_editmode,
+ const bool is_paint_mode,
const float obmat[4][4],
const bool do_final,
const bool do_uvedit,
- const eMRIterType iter_type,
- const eMRDataType data_flag,
const DRW_MeshCDMask *UNUSED(cd_used),
const ToolSettings *ts)
{
@@ -143,16 +149,28 @@ static MeshRenderData *mesh_render_data_create(Mesh *me,
copy_m4_m4(mr->obmat, obmat);
- const bool is_auto_smooth = (me->flag & ME_AUTOSMOOTH) != 0;
- const float split_angle = is_auto_smooth ? me->smoothresh : (float)M_PI;
-
if (is_editmode) {
BLI_assert(me->edit_mesh->mesh_eval_cage && me->edit_mesh->mesh_eval_final);
mr->bm = me->edit_mesh->bm;
mr->edit_bmesh = me->edit_mesh;
- mr->edit_data = me->runtime.edit_data;
mr->me = (do_final) ? me->edit_mesh->mesh_eval_final : me->edit_mesh->mesh_eval_cage;
- bool use_mapped = !do_uvedit && mr->me && !mr->me->runtime.is_original;
+ mr->edit_data = mr->me->runtime.edit_data;
+
+ if (mr->edit_data) {
+ EditMeshData *emd = mr->edit_data;
+ if (emd->vertexCos) {
+ BKE_editmesh_cache_ensure_vert_normals(mr->edit_bmesh, emd);
+ BKE_editmesh_cache_ensure_poly_normals(mr->edit_bmesh, emd);
+ }
+
+ mr->bm_vert_coords = mr->edit_data->vertexCos;
+ mr->bm_vert_normals = mr->edit_data->vertexNos;
+ mr->bm_poly_normals = mr->edit_data->polyNos;
+ mr->bm_poly_centers = mr->edit_data->polyCos;
+ }
+
+ bool has_mdata = (mr->me->runtime.wrapper_type == ME_WRAPPER_TYPE_MDATA);
+ bool use_mapped = has_mdata && !do_uvedit && mr->me && !mr->me->runtime.is_original;
int bm_ensure_types = BM_VERT | BM_EDGE | BM_LOOP | BM_FACE;
@@ -183,7 +201,7 @@ static MeshRenderData *mesh_render_data_create(Mesh *me,
/* Seems like the mesh_eval_final do not have the right origin indices.
* Force not mapped in this case. */
- if (do_final && me->edit_mesh->mesh_eval_final != me->edit_mesh->mesh_eval_cage) {
+ if (has_mdata && do_final && me->edit_mesh->mesh_eval_final != me->edit_mesh->mesh_eval_cage) {
// mr->edit_bmesh = NULL;
mr->extract_type = MR_EXTRACT_MESH;
}
@@ -191,7 +209,17 @@ static MeshRenderData *mesh_render_data_create(Mesh *me,
else {
mr->me = me;
mr->edit_bmesh = NULL;
- mr->extract_type = MR_EXTRACT_MESH;
+
+ bool use_mapped = is_paint_mode && mr->me && !mr->me->runtime.is_original;
+ if (use_mapped) {
+ mr->v_origindex = CustomData_get_layer(&mr->me->vdata, CD_ORIGINDEX);
+ mr->e_origindex = CustomData_get_layer(&mr->me->edata, CD_ORIGINDEX);
+ mr->p_origindex = CustomData_get_layer(&mr->me->pdata, CD_ORIGINDEX);
+
+ use_mapped = (mr->v_origindex || mr->e_origindex || mr->p_origindex);
+ }
+
+ mr->extract_type = use_mapped ? MR_EXTRACT_MAPPED : MR_EXTRACT_MESH;
}
if (mr->extract_type != MR_EXTRACT_BMESH) {
@@ -210,7 +238,32 @@ static MeshRenderData *mesh_render_data_create(Mesh *me,
mr->v_origindex = CustomData_get_layer(&mr->me->vdata, CD_ORIGINDEX);
mr->e_origindex = CustomData_get_layer(&mr->me->edata, CD_ORIGINDEX);
mr->p_origindex = CustomData_get_layer(&mr->me->pdata, CD_ORIGINDEX);
+ }
+ else {
+ /* BMesh */
+ BMesh *bm = mr->bm;
+
+ mr->vert_len = bm->totvert;
+ mr->edge_len = bm->totedge;
+ mr->loop_len = bm->totloop;
+ mr->poly_len = bm->totface;
+ mr->tri_len = poly_to_tri_count(mr->poly_len, mr->loop_len);
+ }
+
+ return mr;
+}
+
+/* Part of the creation of the MeshRenderData that happens in a thread. */
+static void mesh_render_data_update(MeshRenderData *mr,
+ const eMRIterType iter_type,
+ const eMRDataType data_flag)
+{
+ Mesh *me = mr->me;
+ const bool is_auto_smooth = (me->flag & ME_AUTOSMOOTH) != 0;
+ const float split_angle = is_auto_smooth ? me->smoothresh : (float)M_PI;
+ if (mr->extract_type != MR_EXTRACT_BMESH) {
+ /* Mesh */
if (data_flag & (MR_DATA_POLY_NOR | MR_DATA_LOOP_NOR | MR_DATA_TAN_LOOP_NOR)) {
mr->poly_normals = MEM_mallocN(sizeof(*mr->poly_normals) * mr->poly_len, __func__);
BKE_mesh_calc_normals_poly((MVert *)mr->mvert,
@@ -289,23 +342,27 @@ static MeshRenderData *mesh_render_data_create(Mesh *me,
else {
/* BMesh */
BMesh *bm = mr->bm;
-
- mr->vert_len = bm->totvert;
- mr->edge_len = bm->totedge;
- mr->loop_len = bm->totloop;
- mr->poly_len = bm->totface;
- mr->tri_len = poly_to_tri_count(mr->poly_len, mr->loop_len);
-
if (data_flag & MR_DATA_POLY_NOR) {
/* Use bmface->no instead. */
}
if (((data_flag & MR_DATA_LOOP_NOR) && is_auto_smooth) || (data_flag & MR_DATA_TAN_LOOP_NOR)) {
+
+ const float(*vert_coords)[3] = NULL;
+ const float(*vert_normals)[3] = NULL;
+ const float(*poly_normals)[3] = NULL;
+
+ if (mr->edit_data && mr->edit_data->vertexCos) {
+ vert_coords = mr->bm_vert_coords;
+ vert_normals = mr->bm_vert_normals;
+ poly_normals = mr->bm_poly_normals;
+ }
+
mr->loop_normals = MEM_mallocN(sizeof(*mr->loop_normals) * mr->loop_len, __func__);
int clnors_offset = CustomData_get_offset(&mr->bm->ldata, CD_CUSTOMLOOPNORMAL);
BM_loops_calc_normal_vcos(mr->bm,
- NULL,
- NULL,
- NULL,
+ vert_coords,
+ vert_normals,
+ poly_normals,
is_auto_smooth,
split_angle,
mr->loop_normals,
@@ -349,7 +406,6 @@ static MeshRenderData *mesh_render_data_create(Mesh *me,
mr->loop_loose_len = mr->vert_loose_len + mr->edge_loose_len * 2;
}
}
- return mr;
}
static void mesh_render_data_free(MeshRenderData *mr)
@@ -385,6 +441,42 @@ BLI_INLINE BMVert *bm_original_vert_get(const MeshRenderData *mr, int idx)
NULL;
}
+BLI_INLINE const float *bm_vert_co_get(const MeshRenderData *mr, const BMVert *eve)
+{
+ const float(*vert_coords)[3] = mr->bm_vert_coords;
+ if (vert_coords != NULL) {
+ return vert_coords[BM_elem_index_get(eve)];
+ }
+ else {
+ UNUSED_VARS(mr);
+ return eve->co;
+ }
+}
+
+BLI_INLINE const float *bm_vert_no_get(const MeshRenderData *mr, const BMVert *eve)
+{
+ const float(*vert_normals)[3] = mr->bm_vert_normals;
+ if (vert_normals != NULL) {
+ return vert_normals[BM_elem_index_get(eve)];
+ }
+ else {
+ UNUSED_VARS(mr);
+ return eve->co;
+ }
+}
+
+BLI_INLINE const float *bm_face_no_get(const MeshRenderData *mr, const BMFace *efa)
+{
+ const float(*poly_normals)[3] = mr->bm_poly_normals;
+ if (poly_normals != NULL) {
+ return poly_normals[BM_elem_index_get(efa)];
+ }
+ else {
+ UNUSED_VARS(mr);
+ return efa->no;
+ }
+}
+
/** \} */
/* ---------------------------------------------------------------------- */
@@ -596,7 +688,7 @@ static void extract_lines_loop_mesh(const MeshRenderData *mr,
{
const MEdge *medge = &mr->medge[mloop->e];
if (!((mr->use_hide && (medge->flag & ME_HIDE)) ||
- ((mr->extract_type == MR_EXTRACT_MAPPED) &&
+ ((mr->extract_type == MR_EXTRACT_MAPPED) && (mr->e_origindex) &&
(mr->e_origindex[mloop->e] == ORIGINDEX_NONE)))) {
int loopend = mpoly->totloop + mpoly->loopstart - 1;
int other_loop = (l == loopend) ? mpoly->loopstart : (l + 1);
@@ -629,7 +721,7 @@ static void extract_lines_ledge_mesh(const MeshRenderData *mr,
int ledge_idx = mr->edge_len + e;
int edge_idx = mr->ledges[e];
if (!((mr->use_hide && (medge->flag & ME_HIDE)) ||
- ((mr->extract_type == MR_EXTRACT_MAPPED) &&
+ ((mr->extract_type == MR_EXTRACT_MAPPED) && (mr->e_origindex) &&
(mr->e_origindex[edge_idx] == ORIGINDEX_NONE)))) {
int l = mr->loop_len + e * 2;
GPU_indexbuf_set_line_verts(elb, ledge_idx, l, l + 1);
@@ -661,46 +753,15 @@ static const MeshExtract extract_lines = {
0,
false,
};
-
/** \} */
/* ---------------------------------------------------------------------- */
-/** \name Extract Loose Edges Indices
+/** \name Extract Loose Edges Sub Buffer
* \{ */
-static void *extract_lines_loose_init(const MeshRenderData *UNUSED(mr), void *UNUSED(buf))
-{
- return NULL;
-}
-
-static void extract_lines_loose_ledge_mesh(const MeshRenderData *UNUSED(mr),
- int UNUSED(e),
- const MEdge *UNUSED(medge),
- void *UNUSED(elb))
-{
- /* This function is intentionally empty. The existence of this functions ensures that
- * `iter_type` `MR_ITER_LVERT` is set when initializing the `MeshRenderData` (See
- * `mesh_extract_iter_type`). This flag ensures that `mr->edge_loose_len` field is filled. This
- * field we use in the `extract_lines_loose_finish` function to create a subrange from the
- * `ibo.lines`. */
-}
-
-static void extract_lines_loose_ledge_bmesh(const MeshRenderData *UNUSED(mr),
- int UNUSED(e),
- BMEdge *UNUSED(eed),
- void *UNUSED(elb))
-{
- /* This function is intentionally empty. The existence of this functions ensures that
- * `iter_type` `MR_ITER_LVERT` is set when initializing the `MeshRenderData` (See
- * `mesh_extract_iter_type`). This flag ensures that `mr->edge_loose_len` field is filled. This
- * field we use in the `extract_lines_loose_finish` function to create a subrange from the
- * `ibo.lines`. */
-}
-
-static void extract_lines_loose_finish(const MeshRenderData *mr,
- void *UNUSED(ibo),
- void *UNUSED(elb))
+static void extract_lines_loose_subbuffer(const MeshRenderData *mr)
{
+ BLI_assert(mr->cache->final.ibo.lines);
/* Multiply by 2 because these are edges indices. */
const int start = mr->edge_len * 2;
const int len = mr->edge_loose_len * 2;
@@ -709,17 +770,24 @@ static void extract_lines_loose_finish(const MeshRenderData *mr,
mr->cache->no_loose_wire = (len == 0);
}
-static const MeshExtract extract_lines_loose = {
- extract_lines_loose_init,
- NULL,
- NULL,
+static void extract_lines_with_lines_loose_finish(const MeshRenderData *mr, void *ibo, void *elb)
+{
+ GPU_indexbuf_build_in_place(elb, ibo);
+ extract_lines_loose_subbuffer(mr);
+ MEM_freeN(elb);
+}
+
+static const MeshExtract extract_lines_with_lines_loose = {
+ extract_lines_init,
NULL,
NULL,
- extract_lines_loose_ledge_bmesh,
- extract_lines_loose_ledge_mesh,
+ extract_lines_loop_bmesh,
+ extract_lines_loop_mesh,
+ extract_lines_ledge_bmesh,
+ extract_lines_ledge_mesh,
NULL,
NULL,
- extract_lines_loose_finish,
+ extract_lines_with_lines_loose_finish,
0,
false,
};
@@ -755,7 +823,7 @@ BLI_INLINE void vert_set_mesh(GPUIndexBufBuilder *elb,
{
const MVert *mvert = &mr->mvert[vert_idx];
if (!((mr->use_hide && (mvert->flag & ME_HIDE)) ||
- ((mr->extract_type == MR_EXTRACT_MAPPED) &&
+ ((mr->extract_type == MR_EXTRACT_MAPPED) && (mr->v_origindex) &&
(mr->v_origindex[vert_idx] == ORIGINDEX_NONE)))) {
GPU_indexbuf_set_point_vert(elb, vert_idx, loop);
}
@@ -924,10 +992,14 @@ static void extract_lines_paint_mask_loop_mesh(const MeshRenderData *mr,
void *_data)
{
MeshExtract_LinePaintMask_Data *data = (MeshExtract_LinePaintMask_Data *)_data;
- if (!(mr->use_hide && (mpoly->flag & ME_HIDE))) {
+ const int edge_idx = mloop->e;
+ const MEdge *medge = &mr->medge[edge_idx];
+ if (!((mr->use_hide && (medge->flag & ME_HIDE)) ||
+ ((mr->extract_type == MR_EXTRACT_MAPPED) && (mr->e_origindex) &&
+ (mr->e_origindex[edge_idx] == ORIGINDEX_NONE)))) {
+
int loopend = mpoly->totloop + mpoly->loopstart - 1;
int other_loop = (l == loopend) ? mpoly->loopstart : (l + 1);
- int edge_idx = mloop->e;
if (mpoly->flag & ME_FACE_SEL) {
if (BLI_BITMAP_TEST_AND_SET_ATOMIC(data->select_map, edge_idx)) {
/* Hide edge as it has more than 2 selected loop. */
@@ -945,6 +1017,9 @@ static void extract_lines_paint_mask_loop_mesh(const MeshRenderData *mr,
}
}
}
+ else {
+ GPU_indexbuf_set_line_restart(&data->elb, edge_idx);
+ }
}
static void extract_lines_paint_mask_finish(const MeshRenderData *UNUSED(mr),
void *ibo,
@@ -1316,7 +1391,7 @@ static void extract_edituv_points_loop_mesh(const MeshRenderData *mr,
const MPoly *mpoly,
void *data)
{
- const bool real_vert = (mr->extract_type == MR_EXTRACT_MAPPED &&
+ const bool real_vert = (mr->extract_type == MR_EXTRACT_MAPPED && (mr->v_origindex) &&
mr->v_origindex[mloop->v] != ORIGINDEX_NONE);
edituv_point_add(
data, ((mpoly->flag & ME_HIDE) != 0) || !real_vert, (mpoly->flag & ME_FACE_SEL) != 0, l);
@@ -1390,7 +1465,7 @@ static void extract_edituv_fdots_loop_mesh(const MeshRenderData *mr,
const MPoly *mpoly,
void *data)
{
- const bool real_fdot = (mr->extract_type == MR_EXTRACT_MAPPED &&
+ const bool real_fdot = (mr->extract_type == MR_EXTRACT_MAPPED && mr->p_origindex &&
mr->p_origindex[p] != ORIGINDEX_NONE);
const bool subd_fdot = (!mr->use_subsurf_fdots ||
(mr->mvert[mloop->v].flag & ME_VERT_FACEDOT) != 0);
@@ -1462,7 +1537,7 @@ static void *extract_pos_nor_init(const MeshRenderData *mr, void *buf)
BMVert *eve;
int v;
BM_ITER_MESH_INDEX (eve, &iter, mr->bm, BM_VERTS_OF_MESH, v) {
- data->packed_nor[v] = GPU_normal_convert_i10_v3(eve->no);
+ data->packed_nor[v] = GPU_normal_convert_i10_v3(bm_vert_no_get(mr, eve));
}
}
else {
@@ -1474,14 +1549,11 @@ static void *extract_pos_nor_init(const MeshRenderData *mr, void *buf)
return data;
}
-static void extract_pos_nor_loop_bmesh(const MeshRenderData *UNUSED(mr),
- int l,
- BMLoop *loop,
- void *_data)
+static void extract_pos_nor_loop_bmesh(const MeshRenderData *mr, int l, BMLoop *loop, void *_data)
{
MeshExtract_PosNor_Data *data = _data;
PosNorLoop *vert = data->vbo_data + l;
- copy_v3_v3(vert->pos, loop->v->co);
+ copy_v3_v3(vert->pos, bm_vert_co_get(mr, loop->v));
vert->nor = data->packed_nor[BM_elem_index_get(loop->v)];
BMFace *efa = loop->f;
vert->nor.w = BM_elem_flag_test(efa, BM_ELEM_HIDDEN) ? -1 : 0;
@@ -1500,7 +1572,9 @@ static void extract_pos_nor_loop_mesh(const MeshRenderData *mr,
copy_v3_v3(vert->pos, mvert->co);
vert->nor = data->packed_nor[mloop->v];
/* Flag for paint mode overlay. */
- if (mpoly->flag & ME_HIDE || mvert->flag & ME_HIDE) {
+ if (mpoly->flag & ME_HIDE || mvert->flag & ME_HIDE ||
+ ((mr->extract_type == MR_EXTRACT_MAPPED) && (mr->v_origindex) &&
+ (mr->v_origindex[mloop->v] == ORIGINDEX_NONE))) {
vert->nor.w = -1;
}
else if (mvert->flag & SELECT) {
@@ -1516,8 +1590,8 @@ static void extract_pos_nor_ledge_bmesh(const MeshRenderData *mr, int e, BMEdge
int l = mr->loop_len + e * 2;
MeshExtract_PosNor_Data *data = _data;
PosNorLoop *vert = data->vbo_data + l;
- copy_v3_v3(vert[0].pos, eed->v1->co);
- copy_v3_v3(vert[1].pos, eed->v2->co);
+ copy_v3_v3(vert[0].pos, bm_vert_co_get(mr, eed->v1));
+ copy_v3_v3(vert[1].pos, bm_vert_co_get(mr, eed->v2));
vert[0].nor = data->packed_nor[BM_elem_index_get(eed->v1)];
vert[1].nor = data->packed_nor[BM_elem_index_get(eed->v2)];
}
@@ -1541,7 +1615,7 @@ static void extract_pos_nor_lvert_bmesh(const MeshRenderData *mr, int v, BMVert
int l = mr->loop_len + mr->edge_loose_len * 2 + v;
MeshExtract_PosNor_Data *data = _data;
PosNorLoop *vert = data->vbo_data + l;
- copy_v3_v3(vert->pos, eve->co);
+ copy_v3_v3(vert->pos, bm_vert_co_get(mr, eve));
vert->nor = data->packed_nor[BM_elem_index_get(eve)];
}
@@ -1607,34 +1681,40 @@ static void extract_lnor_hq_loop_bmesh(const MeshRenderData *mr, int l, BMLoop *
normal_float_to_short_v3(&((gpuHQNor *)data)[l].x, mr->loop_normals[l]);
}
else if (BM_elem_flag_test(loop->f, BM_ELEM_SMOOTH)) {
- normal_float_to_short_v3(&((gpuHQNor *)data)[l].x, loop->v->no);
+ normal_float_to_short_v3(&((gpuHQNor *)data)[l].x, bm_vert_no_get(mr, loop->v));
}
else {
- normal_float_to_short_v3(&((gpuHQNor *)data)[l].x, loop->f->no);
+ normal_float_to_short_v3(&((gpuHQNor *)data)[l].x, bm_face_no_get(mr, loop->f));
}
}
static void extract_lnor_hq_loop_mesh(
const MeshRenderData *mr, int l, const MLoop *mloop, int p, const MPoly *mpoly, void *data)
{
+ gpuHQNor *lnor_data = &((gpuHQNor *)data)[l];
if (mr->loop_normals) {
- normal_float_to_short_v3(&((gpuHQNor *)data)[l].x, mr->loop_normals[l]);
+ normal_float_to_short_v3(&lnor_data->x, mr->loop_normals[l]);
}
else if (mpoly->flag & ME_SMOOTH) {
- copy_v3_v3_short(&((gpuHQNor *)data)[l].x, mr->mvert[mloop->v].no);
+ copy_v3_v3_short(&lnor_data->x, mr->mvert[mloop->v].no);
}
else {
- normal_float_to_short_v3(&((gpuHQNor *)data)[l].x, mr->poly_normals[p]);
+ normal_float_to_short_v3(&lnor_data->x, mr->poly_normals[p]);
}
- /* Flag for paint mode overlay. */
- if (mpoly->flag & ME_HIDE) {
- ((gpuHQNor *)data)[l].w = -1;
+
+ /* Flag for paint mode overlay.
+ * Only use MR_EXTRACT_MAPPED in edit mode where it is used to display the edge-normals. In
+ * paint mode it will use the unmapped data to draw the wireframe. */
+ if (mpoly->flag & ME_HIDE ||
+ (mr->edit_bmesh && mr->extract_type == MR_EXTRACT_MAPPED && (mr->v_origindex) &&
+ mr->v_origindex[mloop->v] == ORIGINDEX_NONE)) {
+ lnor_data->w = -1;
}
else if (mpoly->flag & ME_FACE_SEL) {
- ((gpuHQNor *)data)[l].w = 1;
+ lnor_data->w = 1;
}
else {
- ((gpuHQNor *)data)[l].w = 0;
+ lnor_data->w = 0;
}
}
@@ -1678,10 +1758,10 @@ static void extract_lnor_loop_bmesh(const MeshRenderData *mr, int l, BMLoop *loo
((GPUPackedNormal *)data)[l] = GPU_normal_convert_i10_v3(mr->loop_normals[l]);
}
else if (BM_elem_flag_test(loop->f, BM_ELEM_SMOOTH)) {
- ((GPUPackedNormal *)data)[l] = GPU_normal_convert_i10_v3(loop->v->no);
+ ((GPUPackedNormal *)data)[l] = GPU_normal_convert_i10_v3(bm_vert_no_get(mr, loop->v));
}
else {
- ((GPUPackedNormal *)data)[l] = GPU_normal_convert_i10_v3(loop->f->no);
+ ((GPUPackedNormal *)data)[l] = GPU_normal_convert_i10_v3(bm_face_no_get(mr, loop->f));
}
BMFace *efa = loop->f;
((GPUPackedNormal *)data)[l].w = BM_elem_flag_test(efa, BM_ELEM_HIDDEN) ? -1 : 0;
@@ -1690,24 +1770,30 @@ static void extract_lnor_loop_bmesh(const MeshRenderData *mr, int l, BMLoop *loo
static void extract_lnor_loop_mesh(
const MeshRenderData *mr, int l, const MLoop *mloop, int p, const MPoly *mpoly, void *data)
{
+ GPUPackedNormal *lnor_data = &((GPUPackedNormal *)data)[l];
if (mr->loop_normals) {
- ((GPUPackedNormal *)data)[l] = GPU_normal_convert_i10_v3(mr->loop_normals[l]);
+ *lnor_data = GPU_normal_convert_i10_v3(mr->loop_normals[l]);
}
else if (mpoly->flag & ME_SMOOTH) {
- ((GPUPackedNormal *)data)[l] = GPU_normal_convert_i10_s3(mr->mvert[mloop->v].no);
+ *lnor_data = GPU_normal_convert_i10_s3(mr->mvert[mloop->v].no);
}
else {
- ((GPUPackedNormal *)data)[l] = GPU_normal_convert_i10_v3(mr->poly_normals[p]);
+ *lnor_data = GPU_normal_convert_i10_v3(mr->poly_normals[p]);
}
- /* Flag for paint mode overlay. */
- if (mpoly->flag & ME_HIDE) {
- ((GPUPackedNormal *)data)[l].w = -1;
+
+ /* Flag for paint mode overlay.
+ * Only use MR_EXTRACT_MAPPED in edit mode where it is used to display the edge-normals. In
+ * paint mode it will use the unmapped data to draw the wireframe. */
+ if (mpoly->flag & ME_HIDE ||
+ (mr->edit_bmesh && mr->extract_type == MR_EXTRACT_MAPPED && (mr->v_origindex) &&
+ mr->v_origindex[mloop->v] == ORIGINDEX_NONE)) {
+ lnor_data->w = -1;
}
else if (mpoly->flag & ME_FACE_SEL) {
- ((GPUPackedNormal *)data)[l].w = 1;
+ lnor_data->w = 1;
}
else {
- ((GPUPackedNormal *)data)[l].w = 0;
+ lnor_data->w = 0;
}
}
@@ -1750,10 +1836,10 @@ static void *extract_uv_init(const MeshRenderData *mr, void *buf)
for (int i = 0; i < MAX_MTFACE; i++) {
if (uv_layers & (1 << i)) {
- char attr_name[32], attr_safe_name[GPU_MAX_SAFE_ATTRIB_NAME];
+ char attr_name[32], attr_safe_name[GPU_MAX_SAFE_ATTR_NAME];
const char *layer_name = CustomData_get_layer_name(cd_ldata, CD_MLOOPUV, i);
- GPU_vertformat_safe_attrib_name(layer_name, attr_safe_name, GPU_MAX_SAFE_ATTRIB_NAME);
+ GPU_vertformat_safe_attr_name(layer_name, attr_safe_name, GPU_MAX_SAFE_ATTR_NAME);
/* UV layer name. */
BLI_snprintf(attr_name, sizeof(attr_name), "u%s", attr_safe_name);
GPU_vertformat_attr_add(&format, attr_name, GPU_COMP_F32, 2, GPU_FETCH_FLOAT);
@@ -1857,9 +1943,9 @@ static void extract_tan_ex(const MeshRenderData *mr, GPUVertBuf *vbo, const bool
for (int i = 0; i < MAX_MTFACE; i++) {
if (tan_layers & (1 << i)) {
- char attr_name[32], attr_safe_name[GPU_MAX_SAFE_ATTRIB_NAME];
+ char attr_name[32], attr_safe_name[GPU_MAX_SAFE_ATTR_NAME];
const char *layer_name = CustomData_get_layer_name(cd_ldata, CD_MLOOPUV, i);
- GPU_vertformat_safe_attrib_name(layer_name, attr_safe_name, GPU_MAX_SAFE_ATTRIB_NAME);
+ GPU_vertformat_safe_attr_name(layer_name, attr_safe_name, GPU_MAX_SAFE_ATTR_NAME);
/* Tangent layer name. */
BLI_snprintf(attr_name, sizeof(attr_name), "t%s", attr_safe_name);
GPU_vertformat_attr_add(&format, attr_name, comp_type, 4, fetch_mode);
@@ -1883,7 +1969,10 @@ static void extract_tan_ex(const MeshRenderData *mr, GPUVertBuf *vbo, const bool
if (mr->extract_type == MR_EXTRACT_BMESH) {
BMesh *bm = mr->bm;
for (int v = 0; v < mr->vert_len; v++) {
- copy_v3_v3(orco[v], BM_vert_at_index(bm, v)->co);
+ const BMVert *eve = BM_vert_at_index(bm, v);
+ /* Exceptional case where #bm_vert_co_get can be avoided, as we want the original coords.
+ * not the distorted ones. */
+ copy_v3_v3(orco[v], eve->co);
}
}
else {
@@ -1934,9 +2023,9 @@ static void extract_tan_ex(const MeshRenderData *mr, GPUVertBuf *vbo, const bool
}
if (use_orco_tan) {
- char attr_name[32], attr_safe_name[GPU_MAX_SAFE_ATTRIB_NAME];
+ char attr_name[32], attr_safe_name[GPU_MAX_SAFE_ATTR_NAME];
const char *layer_name = CustomData_get_layer_name(cd_ldata, CD_TANGENT, 0);
- GPU_vertformat_safe_attrib_name(layer_name, attr_safe_name, GPU_MAX_SAFE_ATTRIB_NAME);
+ GPU_vertformat_safe_attr_name(layer_name, attr_safe_name, GPU_MAX_SAFE_ATTR_NAME);
BLI_snprintf(attr_name, sizeof(*attr_name), "t%s", attr_safe_name);
GPU_vertformat_attr_add(&format, attr_name, comp_type, 4, fetch_mode);
GPU_vertformat_alias_add(&format, "t");
@@ -2060,14 +2149,14 @@ static void *extract_vcol_init(const MeshRenderData *mr, void *buf)
GPUVertFormat format = {0};
GPU_vertformat_deinterleave(&format);
- CustomData *cd_ldata = &mr->me->ldata;
+ CustomData *cd_ldata = (mr->extract_type == MR_EXTRACT_BMESH) ? &mr->bm->ldata : &mr->me->ldata;
uint32_t vcol_layers = mr->cache->cd_used.vcol;
- for (int i = 0; i < 8; i++) {
+ for (int i = 0; i < MAX_MCOL; i++) {
if (vcol_layers & (1 << i)) {
- char attr_name[32], attr_safe_name[GPU_MAX_SAFE_ATTRIB_NAME];
+ char attr_name[32], attr_safe_name[GPU_MAX_SAFE_ATTR_NAME];
const char *layer_name = CustomData_get_layer_name(cd_ldata, CD_MLOOPCOL, i);
- GPU_vertformat_safe_attrib_name(layer_name, attr_safe_name, GPU_MAX_SAFE_ATTRIB_NAME);
+ GPU_vertformat_safe_attr_name(layer_name, attr_safe_name, GPU_MAX_SAFE_ATTR_NAME);
BLI_snprintf(attr_name, sizeof(attr_name), "c%s", attr_safe_name);
GPU_vertformat_attr_add(&format, attr_name, GPU_COMP_U16, 4, GPU_FETCH_INT_TO_FLOAT_UNIT);
@@ -2095,14 +2184,32 @@ static void *extract_vcol_init(const MeshRenderData *mr, void *buf)
} gpuMeshVcol;
gpuMeshVcol *vcol_data = (gpuMeshVcol *)vbo->data;
- for (int i = 0; i < 8; i++) {
+ for (int i = 0; i < MAX_MCOL; i++) {
if (vcol_layers & (1 << i)) {
- MLoopCol *mcol = (MLoopCol *)CustomData_get_layer_n(cd_ldata, CD_MLOOPCOL, i);
- for (int l = 0; l < mr->loop_len; l++, mcol++, vcol_data++) {
- vcol_data->r = unit_float_to_ushort_clamp(BLI_color_from_srgb_table[mcol->r]);
- vcol_data->g = unit_float_to_ushort_clamp(BLI_color_from_srgb_table[mcol->g]);
- vcol_data->b = unit_float_to_ushort_clamp(BLI_color_from_srgb_table[mcol->b]);
- vcol_data->a = unit_float_to_ushort_clamp(mcol->a * (1.0f / 255.0f));
+ if (mr->extract_type == MR_EXTRACT_BMESH) {
+ int cd_ofs = CustomData_get_n_offset(cd_ldata, CD_MLOOPCOL, i);
+ BMIter f_iter, l_iter;
+ BMFace *efa;
+ BMLoop *loop;
+ BM_ITER_MESH (efa, &f_iter, mr->bm, BM_FACES_OF_MESH) {
+ BM_ITER_ELEM (loop, &l_iter, efa, BM_LOOPS_OF_FACE) {
+ const MLoopCol *mloopcol = BM_ELEM_CD_GET_VOID_P(loop, cd_ofs);
+ vcol_data->r = unit_float_to_ushort_clamp(BLI_color_from_srgb_table[mloopcol->r]);
+ vcol_data->g = unit_float_to_ushort_clamp(BLI_color_from_srgb_table[mloopcol->g]);
+ vcol_data->b = unit_float_to_ushort_clamp(BLI_color_from_srgb_table[mloopcol->b]);
+ vcol_data->a = unit_float_to_ushort_clamp(mloopcol->a * (1.0f / 255.0f));
+ vcol_data++;
+ }
+ }
+ }
+ else {
+ const MLoopCol *mloopcol = (MLoopCol *)CustomData_get_layer_n(cd_ldata, CD_MLOOPCOL, i);
+ for (int l = 0; l < mr->loop_len; l++, mloopcol++, vcol_data++) {
+ vcol_data->r = unit_float_to_ushort_clamp(BLI_color_from_srgb_table[mloopcol->r]);
+ vcol_data->g = unit_float_to_ushort_clamp(BLI_color_from_srgb_table[mloopcol->g]);
+ vcol_data->b = unit_float_to_ushort_clamp(BLI_color_from_srgb_table[mloopcol->b]);
+ vcol_data->a = unit_float_to_ushort_clamp(mloopcol->a * (1.0f / 255.0f));
+ }
}
}
}
@@ -2139,7 +2246,7 @@ static void *extract_orco_init(const MeshRenderData *mr, void *buf)
static GPUVertFormat format = {0};
if (format.attr_len == 0) {
/* FIXME(fclem): We use the last component as a way to differentiate from generic vertex
- * attribs. This is a substantial waste of Vram and should be done another way.
+ * attributes. This is a substantial waste of Vram and should be done another way.
* Unfortunately, at the time of writing, I did not found any other "non disruptive"
* alternative. */
GPU_vertformat_attr_add(&format, "orco", GPU_COMP_F32, 4, GPU_FETCH_FLOAT);
@@ -2167,7 +2274,7 @@ static void extract_orco_loop_bmesh(const MeshRenderData *UNUSED(mr),
MeshExtract_Orco_Data *orco_data = (MeshExtract_Orco_Data *)data;
float *loop_orco = orco_data->vbo_data[l];
copy_v3_v3(loop_orco, orco_data->orco[BM_elem_index_get(loop->v)]);
- loop_orco[3] = 0.0; /* Tag as not a generic attrib */
+ loop_orco[3] = 0.0; /* Tag as not a generic attribute. */
}
static void extract_orco_loop_mesh(const MeshRenderData *UNUSED(mr),
@@ -2180,7 +2287,7 @@ static void extract_orco_loop_mesh(const MeshRenderData *UNUSED(mr),
MeshExtract_Orco_Data *orco_data = (MeshExtract_Orco_Data *)data;
float *loop_orco = orco_data->vbo_data[l];
copy_v3_v3(loop_orco, orco_data->orco[mloop->v]);
- loop_orco[3] = 0.0; /* Tag as not a generic attrib */
+ loop_orco[3] = 0.0; /* Tag as not a generic attribute. */
}
static void extract_orco_finish(const MeshRenderData *UNUSED(mr), void *UNUSED(buf), void *data)
@@ -2269,14 +2376,14 @@ static void *extract_edge_fac_init(const MeshRenderData *mr, void *buf)
return data;
}
-static void extract_edge_fac_loop_bmesh(const MeshRenderData *UNUSED(mr),
- int l,
- BMLoop *loop,
- void *_data)
+static void extract_edge_fac_loop_bmesh(const MeshRenderData *mr, int l, BMLoop *loop, void *_data)
{
MeshExtract_EdgeFac_Data *data = (MeshExtract_EdgeFac_Data *)_data;
if (BM_edge_is_manifold(loop->e)) {
- float ratio = loop_edge_factor_get(loop->f->no, loop->v->co, loop->v->no, loop->next->v->co);
+ float ratio = loop_edge_factor_get(bm_face_no_get(mr, loop->f),
+ bm_vert_co_get(mr, loop->v),
+ bm_vert_no_get(mr, loop->v),
+ bm_vert_co_get(mr, loop->next->v));
data->vbo_data[l] = ratio * 253 + 1;
}
else {
@@ -3101,7 +3208,7 @@ static void *extract_stretch_angle_init(const MeshRenderData *mr, void *buf)
return data;
}
-static void extract_stretch_angle_loop_bmesh(const MeshRenderData *UNUSED(mr),
+static void extract_stretch_angle_loop_bmesh(const MeshRenderData *mr,
int l,
BMLoop *loop,
void *_data)
@@ -3118,8 +3225,12 @@ static void extract_stretch_angle_loop_bmesh(const MeshRenderData *UNUSED(mr),
BMLoop *l_next_tmp = loop;
luv = BM_ELEM_CD_GET_VOID_P(l_tmp, data->cd_ofs);
luv_next = BM_ELEM_CD_GET_VOID_P(l_next_tmp, data->cd_ofs);
- compute_normalize_edge_vectors(
- auv, av, luv->uv, luv_next->uv, l_tmp->v->co, l_next_tmp->v->co);
+ compute_normalize_edge_vectors(auv,
+ av,
+ luv->uv,
+ luv_next->uv,
+ bm_vert_co_get(mr, l_tmp->v),
+ bm_vert_co_get(mr, l_next_tmp->v));
/* Save last edge. */
copy_v2_v2(last_auv, auv[1]);
copy_v3_v3(last_av, av[1]);
@@ -3135,7 +3246,12 @@ static void extract_stretch_angle_loop_bmesh(const MeshRenderData *UNUSED(mr),
else {
luv = BM_ELEM_CD_GET_VOID_P(loop, data->cd_ofs);
luv_next = BM_ELEM_CD_GET_VOID_P(l_next, data->cd_ofs);
- compute_normalize_edge_vectors(auv, av, luv->uv, luv_next->uv, loop->v->co, l_next->v->co);
+ compute_normalize_edge_vectors(auv,
+ av,
+ luv->uv,
+ luv_next->uv,
+ bm_vert_co_get(mr, loop->v),
+ bm_vert_co_get(mr, l_next->v));
}
edituv_get_stretch_angle(auv, av, data->vbo_data + l);
}
@@ -3275,7 +3391,7 @@ static void statvis_calc_overhang(const MeshRenderData *mr, float *r_overhang)
if (mr->extract_type == MR_EXTRACT_BMESH) {
int l = 0;
BM_ITER_MESH (f, &iter, bm, BM_FACES_OF_MESH) {
- float fac = angle_normalized_v3v3(f->no, dir) / (float)M_PI;
+ float fac = angle_normalized_v3v3(bm_face_no_get(mr, f), dir) / (float)M_PI;
fac = overhang_remap(fac, min, max, minmax_irange);
for (int i = 0; i < f->len; i++, l++) {
r_overhang[l] = fac;
@@ -3353,7 +3469,11 @@ static void statvis_calc_thickness(const MeshRenderData *mr, float *r_thickness)
for (int i = 0; i < mr->tri_len; i++) {
BMLoop **ltri = looptris[i];
const int index = BM_elem_index_get(ltri[0]->f);
- const float *cos[3] = {ltri[0]->v->co, ltri[1]->v->co, ltri[2]->v->co};
+ const float *cos[3] = {
+ bm_vert_co_get(mr, ltri[0]->v),
+ bm_vert_co_get(mr, ltri[1]->v),
+ bm_vert_co_get(mr, ltri[2]->v),
+ };
float ray_co[3];
float ray_no[3];
@@ -3366,7 +3486,8 @@ static void statvis_calc_thickness(const MeshRenderData *mr, float *r_thickness)
BMFace *f_hit = BKE_bmbvh_ray_cast(bmtree, ray_co, ray_no, 0.0f, &dist, NULL, NULL);
if (f_hit && dist < face_dists[index]) {
- float angle_fac = fabsf(dot_v3v3(ltri[0]->f->no, f_hit->no));
+ float angle_fac = fabsf(
+ dot_v3v3(bm_face_no_get(mr, ltri[0]->f), bm_face_no_get(mr, f_hit)));
angle_fac = 1.0f - angle_fac;
angle_fac = angle_fac * angle_fac * angle_fac;
angle_fac = 1.0f - angle_fac;
@@ -3571,8 +3692,17 @@ static void statvis_calc_distort(const MeshRenderData *mr, float *r_distort)
BMesh *bm = em->bm;
BMFace *f;
+ if (mr->bm_vert_coords != NULL) {
+ BKE_editmesh_cache_ensure_poly_normals(em, mr->edit_data);
+
+ /* Most likely this is already valid, ensure just in case.
+ * Needed for #BM_loop_calc_face_normal_safe_vcos. */
+ BM_mesh_elem_index_ensure(em->bm, BM_VERT);
+ }
+
int l = 0;
- BM_ITER_MESH (f, &iter, bm, BM_FACES_OF_MESH) {
+ int p = 0;
+ BM_ITER_MESH_INDEX (f, &iter, bm, BM_FACES_OF_MESH, p) {
float fac = -1.0f;
if (f->len > 3) {
@@ -3581,13 +3711,23 @@ static void statvis_calc_distort(const MeshRenderData *mr, float *r_distort)
fac = 0.0f;
l_iter = l_first = BM_FACE_FIRST_LOOP(f);
do {
+ const float *no_face;
float no_corner[3];
- BM_loop_calc_face_normal_safe(l_iter, no_corner);
+ if (mr->bm_vert_coords != NULL) {
+ no_face = mr->bm_poly_normals[p];
+ BM_loop_calc_face_normal_safe_vcos(l_iter, no_face, mr->bm_vert_coords, no_corner);
+ }
+ else {
+ no_face = f->no;
+ BM_loop_calc_face_normal_safe(l_iter, no_corner);
+ }
+
/* simple way to detect (what is most likely) concave */
- if (dot_v3v3(f->no, no_corner) < 0.0f) {
+ if (dot_v3v3(no_face, no_corner) < 0.0f) {
negate_v3(no_corner);
}
- fac = max_ff(fac, angle_normalized_v3v3(f->no, no_corner));
+ fac = max_ff(fac, angle_normalized_v3v3(no_face, no_corner));
+
} while ((l_iter = l_iter->next) != l_first);
fac *= 2.0f;
}
@@ -3810,14 +3950,14 @@ static void *extract_fdots_pos_init(const MeshRenderData *mr, void *buf)
return vbo->data;
}
-static void extract_fdots_pos_loop_bmesh(const MeshRenderData *UNUSED(mr),
+static void extract_fdots_pos_loop_bmesh(const MeshRenderData *mr,
int UNUSED(l),
BMLoop *loop,
void *data)
{
float(*center)[3] = (float(*)[3])data;
float w = 1.0f / (float)loop->f->len;
- madd_v3_v3fl(center[BM_elem_index_get(loop->f)], loop->v->co, w);
+ madd_v3_v3fl(center[BM_elem_index_get(loop->f)], bm_vert_co_get(mr, loop->v), w);
}
static void extract_fdots_pos_loop_mesh(const MeshRenderData *mr,
@@ -3890,12 +4030,13 @@ static void extract_fdots_nor_finish(const MeshRenderData *mr, void *buf, void *
for (int f = 0; f < mr->poly_len; f++) {
efa = BM_face_at_index(mr->bm, f);
const bool is_face_hidden = BM_elem_flag_test(efa, BM_ELEM_HIDDEN);
- if (is_face_hidden) {
+ if (is_face_hidden || (mr->extract_type == MR_EXTRACT_MAPPED && mr->p_origindex &&
+ mr->p_origindex[f] == ORIGINDEX_NONE)) {
nor[f] = GPU_normal_convert_i10_v3(invalid_normal);
nor[f].w = NOR_AND_FLAG_HIDDEN;
}
else {
- nor[f] = GPU_normal_convert_i10_v3(efa->no);
+ nor[f] = GPU_normal_convert_i10_v3(bm_face_no_get(mr, efa));
/* Select / Active Flag. */
nor[f].w = (BM_elem_flag_test(efa, BM_ELEM_SELECT) ?
((efa == mr->efa_act) ? NOR_AND_FLAG_ACTIVE : NOR_AND_FLAG_SELECT) :
@@ -3906,12 +4047,14 @@ static void extract_fdots_nor_finish(const MeshRenderData *mr, void *buf, void *
else {
for (int f = 0; f < mr->poly_len; f++) {
efa = bm_original_face_get(mr, f);
- if (!efa || BM_elem_flag_test(efa, BM_ELEM_HIDDEN)) {
+ const bool is_face_hidden = efa && BM_elem_flag_test(efa, BM_ELEM_HIDDEN);
+ if (is_face_hidden || (mr->extract_type == MR_EXTRACT_MAPPED && mr->p_origindex &&
+ mr->p_origindex[f] == ORIGINDEX_NONE)) {
nor[f] = GPU_normal_convert_i10_v3(invalid_normal);
nor[f].w = NOR_AND_FLAG_HIDDEN;
}
else {
- nor[f] = GPU_normal_convert_i10_v3(efa->no);
+ nor[f] = GPU_normal_convert_i10_v3(bm_face_no_get(mr, efa));
/* Select / Active Flag. */
nor[f].w = (BM_elem_flag_test(efa, BM_ELEM_SELECT) ?
((efa == mr->efa_act) ? NOR_AND_FLAG_ACTIVE : NOR_AND_FLAG_SELECT) :
@@ -4136,7 +4279,7 @@ static void *extract_skin_roots_init(const MeshRenderData *mr, void *buf)
const MVertSkin *vs = BM_ELEM_CD_GET_VOID_P(eve, cd_ofs);
if (vs->flag & MVERT_SKIN_ROOT) {
vbo_data->size = (vs->radius[0] + vs->radius[1]) * 0.5f;
- copy_v3_v3(vbo_data->local_pos, eve->co);
+ copy_v3_v3(vbo_data->local_pos, bm_vert_co_get(mr, eve));
vbo_data++;
root_len++;
}
@@ -4384,10 +4527,14 @@ static const MeshExtract extract_fdot_idx = {
/** \} */
/* ---------------------------------------------------------------------- */
-/** \name Extract Loop
+/** \name ExtractTaskData
* \{ */
+typedef struct ExtractUserData {
+ void *user_data;
+} ExtractUserData;
typedef struct ExtractTaskData {
+ void *next, *prev;
const MeshRenderData *mr;
const MeshExtract *extract;
eMRIterType iter_type;
@@ -4395,9 +4542,16 @@ typedef struct ExtractTaskData {
/** Decremented each time a task is finished. */
int32_t *task_counter;
void *buf;
- void *user_data;
+ ExtractUserData *user_data;
} ExtractTaskData;
+static void extract_task_data_free(void *data)
+{
+ ExtractTaskData *task_data = data;
+ MEM_SAFE_FREE(task_data->user_data);
+ MEM_freeN(task_data);
+}
+
BLI_INLINE void mesh_extract_iter(const MeshRenderData *mr,
const eMRIterType iter_type,
int start,
@@ -4474,37 +4628,191 @@ BLI_INLINE void mesh_extract_iter(const MeshRenderData *mr,
}
}
-static void extract_run(TaskPool *__restrict UNUSED(pool), void *taskdata, int UNUSED(threadid))
+static void extract_init(ExtractTaskData *data)
+{
+ data->user_data->user_data = data->extract->init(data->mr, data->buf);
+}
+
+static void extract_run(void *__restrict taskdata)
{
- ExtractTaskData *data = taskdata;
- mesh_extract_iter(
- data->mr, data->iter_type, data->start, data->end, data->extract, data->user_data);
+ ExtractTaskData *data = (ExtractTaskData *)taskdata;
+ mesh_extract_iter(data->mr,
+ data->iter_type,
+ data->start,
+ data->end,
+ data->extract,
+ data->user_data->user_data);
/* If this is the last task, we do the finish function. */
int remainin_tasks = atomic_sub_and_fetch_int32(data->task_counter, 1);
if (remainin_tasks == 0 && data->extract->finish != NULL) {
- data->extract->finish(data->mr, data->buf, data->user_data);
+ data->extract->finish(data->mr, data->buf, data->user_data->user_data);
+ }
+}
+
+static void extract_init_and_run(void *__restrict taskdata)
+{
+ extract_init((ExtractTaskData *)taskdata);
+ extract_run(taskdata);
+}
+
+/** \} */
+
+/* ---------------------------------------------------------------------- */
+/** \name Task Node - Update Mesh Render Data
+ * \{ */
+typedef struct MeshRenderDataUpdateTaskData {
+ MeshRenderData *mr;
+ eMRIterType iter_type;
+ eMRDataType data_flag;
+} MeshRenderDataUpdateTaskData;
+
+static void mesh_render_data_update_task_data_free(MeshRenderDataUpdateTaskData *taskdata)
+{
+ BLI_assert(taskdata);
+ mesh_render_data_free(taskdata->mr);
+ MEM_freeN(taskdata);
+}
+
+static void mesh_extract_render_data_node_exec(void *__restrict task_data)
+{
+ MeshRenderDataUpdateTaskData *update_task_data = task_data;
+ mesh_render_data_update(
+ update_task_data->mr, update_task_data->iter_type, update_task_data->data_flag);
+}
+
+static struct TaskNode *mesh_extract_render_data_node_create(struct TaskGraph *task_graph,
+ MeshRenderData *mr,
+ const eMRIterType iter_type,
+ const eMRDataType data_flag)
+{
+ MeshRenderDataUpdateTaskData *task_data = MEM_mallocN(sizeof(MeshRenderDataUpdateTaskData),
+ __func__);
+ task_data->mr = mr;
+ task_data->iter_type = iter_type;
+ task_data->data_flag = data_flag;
+
+ struct TaskNode *task_node = BLI_task_graph_node_create(
+ task_graph,
+ mesh_extract_render_data_node_exec,
+ task_data,
+ (TaskGraphNodeFreeFunction)mesh_render_data_update_task_data_free);
+ return task_node;
+}
+
+/** \} */
+
+/* ---------------------------------------------------------------------- */
+/** \name Task Node - Extract Single Threaded
+ * \{ */
+typedef struct ExtractSingleThreadedTaskData {
+ ListBase task_datas;
+} ExtractSingleThreadedTaskData;
+
+static void extract_single_threaded_task_data_free(ExtractSingleThreadedTaskData *taskdata)
+{
+ BLI_assert(taskdata);
+ LISTBASE_FOREACH_MUTABLE (ExtractTaskData *, td, &taskdata->task_datas) {
+ extract_task_data_free(td);
+ }
+ BLI_listbase_clear(&taskdata->task_datas);
+ MEM_freeN(taskdata);
+}
+
+static void extract_single_threaded_task_node_exec(void *__restrict task_data)
+{
+ ExtractSingleThreadedTaskData *extract_task_data = task_data;
+ LISTBASE_FOREACH (ExtractTaskData *, td, &extract_task_data->task_datas) {
+ extract_init_and_run(td);
+ }
+}
+
+static struct TaskNode *extract_single_threaded_task_node_create(
+ struct TaskGraph *task_graph, ExtractSingleThreadedTaskData *task_data)
+{
+ struct TaskNode *task_node = BLI_task_graph_node_create(
+ task_graph,
+ extract_single_threaded_task_node_exec,
+ task_data,
+ (TaskGraphNodeFreeFunction)extract_single_threaded_task_data_free);
+ return task_node;
+}
+
+/** \} */
+
+/* ---------------------------------------------------------------------- */
+/** \name Task Node - UserData Initializer
+ * \{ */
+typedef struct UserDataInitTaskData {
+ ListBase task_datas;
+ int32_t *task_counters;
+
+} UserDataInitTaskData;
+
+static void user_data_init_task_data_free(UserDataInitTaskData *taskdata)
+{
+ BLI_assert(taskdata);
+ LISTBASE_FOREACH_MUTABLE (ExtractTaskData *, td, &taskdata->task_datas) {
+ extract_task_data_free(td);
}
+ BLI_listbase_clear(&taskdata->task_datas);
+ MEM_SAFE_FREE(taskdata->task_counters);
+ MEM_freeN(taskdata);
+}
+
+static void user_data_init_task_data_exec(void *__restrict task_data)
+{
+ UserDataInitTaskData *extract_task_data = task_data;
+ LISTBASE_FOREACH (ExtractTaskData *, td, &extract_task_data->task_datas) {
+ extract_init(td);
+ }
+}
+
+static struct TaskNode *user_data_init_task_node_create(struct TaskGraph *task_graph,
+ UserDataInitTaskData *task_data)
+{
+ struct TaskNode *task_node = BLI_task_graph_node_create(
+ task_graph,
+ user_data_init_task_data_exec,
+ task_data,
+ (TaskGraphNodeFreeFunction)user_data_init_task_data_free);
+ return task_node;
}
-static void extract_range_task_create(
- TaskPool *task_pool, ExtractTaskData *taskdata, const eMRIterType type, int start, int length)
+/** \} */
+/* ---------------------------------------------------------------------- */
+/** \name Extract Loop
+ * \{ */
+
+static void extract_range_task_create(struct TaskGraph *task_graph,
+ struct TaskNode *task_node_user_data_init,
+ ExtractTaskData *taskdata,
+ const eMRIterType type,
+ int start,
+ int length)
{
taskdata = MEM_dupallocN(taskdata);
atomic_add_and_fetch_int32(taskdata->task_counter, 1);
taskdata->iter_type = type;
taskdata->start = start;
taskdata->end = start + length;
- BLI_task_pool_push(task_pool, extract_run, taskdata, true, TASK_PRIORITY_HIGH);
+ struct TaskNode *task_node = BLI_task_graph_node_create(
+ task_graph, extract_run, taskdata, MEM_freeN);
+ BLI_task_graph_edge_create(task_node_user_data_init, task_node);
}
-static void extract_task_create(TaskPool *task_pool,
+static void extract_task_create(struct TaskGraph *task_graph,
+ struct TaskNode *task_node_mesh_render_data,
+ struct TaskNode *task_node_user_data_init,
+ ListBase *single_threaded_task_datas,
+ ListBase *user_data_init_task_datas,
const Scene *scene,
const MeshRenderData *mr,
const MeshExtract *extract,
void *buf,
int32_t *task_counter)
{
+ BLI_assert(scene != NULL);
const bool do_hq_normals = (scene->r.perf_flag & SCE_PERF_HQ_NORMALS) != 0;
if (do_hq_normals && (extract == &extract_lnor)) {
extract = &extract_lnor_hq;
@@ -4515,59 +4823,77 @@ static void extract_task_create(TaskPool *task_pool,
/* Divide extraction of the VBO/IBO into sensible chunks of works. */
ExtractTaskData *taskdata = MEM_mallocN(sizeof(*taskdata), "ExtractTaskData");
+ taskdata->next = NULL;
+ taskdata->prev = NULL;
taskdata->mr = mr;
taskdata->extract = extract;
taskdata->buf = buf;
- taskdata->user_data = extract->init(mr, buf);
+
+ /* ExtractUserData is shared between the iterations as it holds counters to detect if the
+ * extraction is finished. To make sure the duplication of the userdata does not create a new
+ * instance of the counters we allocate the userdata in its own container.
+ *
+ * This structure makes sure that when extract_init is called, that the user data of all
+ * iterations are updated. */
+ taskdata->user_data = MEM_callocN(sizeof(ExtractUserData), __func__);
taskdata->iter_type = mesh_extract_iter_type(extract);
taskdata->task_counter = task_counter;
taskdata->start = 0;
taskdata->end = INT_MAX;
/* Simple heuristic. */
- const bool use_thread = (mr->loop_len + mr->loop_loose_len) > 8192;
+ const int chunk_size = 8192;
+ const bool use_thread = (mr->loop_len + mr->loop_loose_len) > chunk_size;
if (use_thread && extract->use_threading) {
+
/* Divide task into sensible chunks. */
- const int chunk_size = 8192;
if (taskdata->iter_type & MR_ITER_LOOPTRI) {
for (int i = 0; i < mr->tri_len; i += chunk_size) {
- extract_range_task_create(task_pool, taskdata, MR_ITER_LOOPTRI, i, chunk_size);
+ extract_range_task_create(
+ task_graph, task_node_user_data_init, taskdata, MR_ITER_LOOPTRI, i, chunk_size);
}
}
if (taskdata->iter_type & MR_ITER_LOOP) {
for (int i = 0; i < mr->poly_len; i += chunk_size) {
- extract_range_task_create(task_pool, taskdata, MR_ITER_LOOP, i, chunk_size);
+ extract_range_task_create(
+ task_graph, task_node_user_data_init, taskdata, MR_ITER_LOOP, i, chunk_size);
}
}
if (taskdata->iter_type & MR_ITER_LEDGE) {
for (int i = 0; i < mr->edge_loose_len; i += chunk_size) {
- extract_range_task_create(task_pool, taskdata, MR_ITER_LEDGE, i, chunk_size);
+ extract_range_task_create(
+ task_graph, task_node_user_data_init, taskdata, MR_ITER_LEDGE, i, chunk_size);
}
}
if (taskdata->iter_type & MR_ITER_LVERT) {
for (int i = 0; i < mr->vert_loose_len; i += chunk_size) {
- extract_range_task_create(task_pool, taskdata, MR_ITER_LVERT, i, chunk_size);
+ extract_range_task_create(
+ task_graph, task_node_user_data_init, taskdata, MR_ITER_LVERT, i, chunk_size);
}
}
- MEM_freeN(taskdata);
+ BLI_addtail(user_data_init_task_datas, taskdata);
}
else if (use_thread) {
/* One task for the whole VBO. */
(*task_counter)++;
- BLI_task_pool_push(task_pool, extract_run, taskdata, true, TASK_PRIORITY_HIGH);
+ struct TaskNode *one_task = BLI_task_graph_node_create(
+ task_graph, extract_init_and_run, taskdata, extract_task_data_free);
+ BLI_task_graph_edge_create(task_node_mesh_render_data, one_task);
}
else {
/* Single threaded extraction. */
(*task_counter)++;
- extract_run(NULL, taskdata, -1);
- MEM_freeN(taskdata);
+ BLI_addtail(single_threaded_task_datas, taskdata);
}
}
-void mesh_buffer_cache_create_requested(MeshBatchCache *cache,
+void mesh_buffer_cache_create_requested(struct TaskGraph *task_graph,
+ MeshBatchCache *cache,
MeshBufferCache mbc,
Mesh *me,
+
const bool is_editmode,
+ const bool is_paint_mode,
const float obmat[4][4],
const bool do_final,
const bool do_uvedit,
@@ -4577,9 +4903,41 @@ void mesh_buffer_cache_create_requested(MeshBatchCache *cache,
const ToolSettings *ts,
const bool use_hide)
{
+ /* For each mesh where batches needs to be updated a sub-graph will be added to the task_graph.
+ * This sub-graph starts with an extract_render_data_node. This fills/converts the required data
+ * from Mesh.
+ *
+ * Small extractions and extractions that can't be multi-threaded are grouped in a single
+ * `extract_single_threaded_task_node`.
+ *
+ * Other extractions will create a node for each loop exceeding 8192 items. these nodes are
+ * linked to the `user_data_init_task_node`. the `user_data_init_task_node` prepares the userdata
+ * needed for the extraction based on the data extracted from the mesh. counters are used to
+ * check if the finalize of a task has to be called.
+ *
+ * Mesh extraction sub graph
+ *
+ * +----------------------+
+ * +-----> | extract_task1_loop_1 |
+ * | +----------------------+
+ * +------------------+ +----------------------+ +----------------------+
+ * | mesh_render_data | --> | | --> | extract_task1_loop_2 |
+ * +------------------+ | | +----------------------+
+ * | | | +----------------------+
+ * | | user_data_init | --> | extract_task2_loop_1 |
+ * v | | +----------------------+
+ * +------------------+ | | +----------------------+
+ * | single_threaded | | | --> | extract_task2_loop_2 |
+ * +------------------+ +----------------------+ +----------------------+
+ * | +----------------------+
+ * +-----> | extract_task2_loop_3 |
+ * +----------------------+
+ */
eMRIterType iter_flag = 0;
eMRDataType data_flag = 0;
+ const bool do_lines_loose_subbuffer = mbc.ibo.lines_loose != NULL;
+
#define TEST_ASSIGN(type, type_lowercase, name) \
do { \
if (DRW_TEST_ASSIGN_##type(mbc.type_lowercase.name)) { \
@@ -4617,7 +4975,6 @@ void mesh_buffer_cache_create_requested(MeshBatchCache *cache,
TEST_ASSIGN(IBO, ibo, fdots);
TEST_ASSIGN(IBO, ibo, lines_paint_mask);
TEST_ASSIGN(IBO, ibo, lines_adjacency);
- TEST_ASSIGN(IBO, ibo, lines_loose);
TEST_ASSIGN(IBO, ibo, edituv_tris);
TEST_ASSIGN(IBO, ibo, edituv_lines);
TEST_ASSIGN(IBO, ibo, edituv_points);
@@ -4630,7 +4987,7 @@ void mesh_buffer_cache_create_requested(MeshBatchCache *cache,
#endif
MeshRenderData *mr = mesh_render_data_create(
- me, is_editmode, obmat, do_final, do_uvedit, iter_flag, data_flag, cd_layer_used, ts);
+ me, is_editmode, is_paint_mode, obmat, do_final, do_uvedit, cd_layer_used, ts);
mr->cache = cache; /* HACK */
mr->use_hide = use_hide;
mr->use_subsurf_fdots = use_subsurf_fdots;
@@ -4640,20 +4997,32 @@ void mesh_buffer_cache_create_requested(MeshBatchCache *cache,
double rdata_end = PIL_check_seconds_timer();
#endif
- TaskScheduler *task_scheduler;
- TaskPool *task_pool;
-
- task_scheduler = BLI_task_scheduler_get();
- task_pool = BLI_task_pool_create_suspended(task_scheduler, NULL);
-
size_t counters_size = (sizeof(mbc) / sizeof(void *)) * sizeof(int32_t);
int32_t *task_counters = MEM_callocN(counters_size, __func__);
int counter_used = 0;
+ struct TaskNode *task_node_mesh_render_data = mesh_extract_render_data_node_create(
+ task_graph, mr, iter_flag, data_flag);
+ ExtractSingleThreadedTaskData *single_threaded_task_data = MEM_callocN(
+ sizeof(ExtractSingleThreadedTaskData), __func__);
+ UserDataInitTaskData *user_data_init_task_data = MEM_callocN(sizeof(UserDataInitTaskData),
+ __func__);
+ user_data_init_task_data->task_counters = task_counters;
+ struct TaskNode *task_node_user_data_init = user_data_init_task_node_create(
+ task_graph, user_data_init_task_data);
+
#define EXTRACT(buf, name) \
if (mbc.buf.name) { \
- extract_task_create( \
- task_pool, scene, mr, &extract_##name, mbc.buf.name, &task_counters[counter_used++]); \
+ extract_task_create(task_graph, \
+ task_node_mesh_render_data, \
+ task_node_user_data_init, \
+ &single_threaded_task_data->task_datas, \
+ &user_data_init_task_data->task_datas, \
+ scene, \
+ mr, \
+ &extract_##name, \
+ mbc.buf.name, \
+ &task_counters[counter_used++]); \
} \
((void)0)
@@ -4681,7 +5050,33 @@ void mesh_buffer_cache_create_requested(MeshBatchCache *cache,
EXTRACT(vbo, skin_roots);
EXTRACT(ibo, tris);
- EXTRACT(ibo, lines);
+ if (mbc.ibo.lines) {
+ /* When `lines` and `lines_loose` are requested, schedule lines extraction that also creates
+ * the `lines_loose` sub-buffer. */
+ const MeshExtract *lines_extractor = do_lines_loose_subbuffer ?
+ &extract_lines_with_lines_loose :
+ &extract_lines;
+ extract_task_create(task_graph,
+ task_node_mesh_render_data,
+ task_node_user_data_init,
+ &single_threaded_task_data->task_datas,
+ &user_data_init_task_data->task_datas,
+ scene,
+ mr,
+ lines_extractor,
+ mbc.ibo.lines,
+ &task_counters[counter_used++]);
+ }
+ else {
+ if (do_lines_loose_subbuffer) {
+ /* When `lines_loose` is requested without `lines` we can create the sub-buffer on the fly as
+ * the `lines` buffer should then already be up-to-date.
+ * (see `DRW_batch_requested(cache->batch.loose_edges, GPU_PRIM_LINES)` in
+ * `DRW_mesh_batch_cache_create_requested`).
+ */
+ extract_lines_loose_subbuffer(mr);
+ }
+ }
EXTRACT(ibo, points);
EXTRACT(ibo, fdots);
EXTRACT(ibo, lines_paint_mask);
@@ -4691,27 +5086,29 @@ void mesh_buffer_cache_create_requested(MeshBatchCache *cache,
EXTRACT(ibo, edituv_points);
EXTRACT(ibo, edituv_fdots);
- /* TODO(fclem) Ideally, we should have one global pool for all
- * objects and wait for finish only before drawing when buffers
- * need to be ready. */
- BLI_task_pool_work_and_wait(task_pool);
-
- /* The next task(s) rely on the result of the tasks above. */
+ /* Only create the edge when there is user data that needs to be initialized.
+ * The task is still part of the graph so the task_data will be freed when the graph is freed.
+ */
+ if (!BLI_listbase_is_empty(&user_data_init_task_data->task_datas)) {
+ BLI_task_graph_edge_create(task_node_mesh_render_data, task_node_user_data_init);
+ }
- /* The `lines_loose` is a sub buffer from `ibo.lines`.
- * We schedule it here due to potential synchronization issues.*/
- EXTRACT(ibo, lines_loose);
+ if (!BLI_listbase_is_empty(&single_threaded_task_data->task_datas)) {
+ struct TaskNode *task_node = extract_single_threaded_task_node_create(
+ task_graph, single_threaded_task_data);
+ BLI_task_graph_edge_create(task_node_mesh_render_data, task_node);
+ }
+ else {
+ extract_single_threaded_task_data_free(single_threaded_task_data);
+ }
- BLI_task_pool_work_and_wait(task_pool);
+ /* Trigger the sub-graph for this mesh. */
+ BLI_task_graph_node_push_work(task_node_mesh_render_data);
#undef EXTRACT
- BLI_task_pool_free(task_pool);
- MEM_freeN(task_counters);
-
- mesh_render_data_free(mr);
-
#ifdef DEBUG_TIME
+ BLI_task_graph_work_and_wait(task_graph);
double end = PIL_check_seconds_timer();
static double avg = 0;
diff --git a/source/blender/draw/intern/draw_cache_impl.h b/source/blender/draw/intern/draw_cache_impl.h
index 3ce8a7d4e43..80649143537 100644
--- a/source/blender/draw/intern/draw_cache_impl.h
+++ b/source/blender/draw/intern/draw_cache_impl.h
@@ -31,6 +31,7 @@ struct ListBase;
struct ModifierData;
struct PTCacheEdit;
struct ParticleSystem;
+struct TaskGraph;
struct Curve;
struct Hair;
@@ -93,7 +94,7 @@ struct GPUBatch *DRW_curve_batch_cache_get_wire_edge(struct Curve *cu);
struct GPUBatch *DRW_curve_batch_cache_get_normal_edge(struct Curve *cu);
struct GPUBatch *DRW_curve_batch_cache_get_edge_detection(struct Curve *cu, bool *r_is_manifold);
struct GPUBatch *DRW_curve_batch_cache_get_edit_edges(struct Curve *cu);
-struct GPUBatch *DRW_curve_batch_cache_get_edit_verts(struct Curve *cu, bool handles);
+struct GPUBatch *DRW_curve_batch_cache_get_edit_verts(struct Curve *cu);
struct GPUBatch *DRW_curve_batch_cache_get_triangles_with_normals(struct Curve *cu);
struct GPUBatch **DRW_curve_batch_cache_get_surface_shaded(struct Curve *cu,
@@ -150,7 +151,8 @@ int DRW_volume_material_count_get(struct Volume *volume);
struct GPUBatch *DRW_volume_batch_cache_get_wireframes_face(struct Volume *volume);
/* Mesh */
-void DRW_mesh_batch_cache_create_requested(struct Object *ob,
+void DRW_mesh_batch_cache_create_requested(struct TaskGraph *task_graph,
+ struct Object *ob,
struct Mesh *me,
const struct Scene *scene,
const bool is_paint_mode,
@@ -208,6 +210,7 @@ enum {
VFLAG_EDGE_SEAM = 1 << 4,
VFLAG_EDGE_SHARP = 1 << 5,
VFLAG_EDGE_FREESTYLE = 1 << 6,
+ VFLAG_HANDLE_SELECTED = 1 << 7,
/* Beware to not go over 1 << 7 (it's a byte flag)
* (see gpu_shader_edit_mesh_overlay_geom.glsl) */
};
diff --git a/source/blender/draw/intern/draw_cache_impl_curve.c b/source/blender/draw/intern/draw_cache_impl_curve.c
index 331f8073ed5..c6112994b65 100644
--- a/source/blender/draw/intern/draw_cache_impl_curve.c
+++ b/source/blender/draw/intern/draw_cache_impl_curve.c
@@ -25,6 +25,7 @@
#include "MEM_guardedalloc.h"
+#include "BLI_listbase.h"
#include "BLI_math_vector.h"
#include "BLI_utildefines.h"
@@ -48,7 +49,9 @@
#define SELECT 1
#define ACTIVE_NURB 1 << 2
-#define EVEN_U_BIT 1 << 3 /* Alternate this bit for every U vert. */
+#define BEZIER_HANDLE 1 << 3
+#define EVEN_U_BIT 1 << 4 /* Alternate this bit for every U vert. */
+#define COLOR_SHIFT 5
/* Used as values of `color_id` in `edit_curve_overlay_handle_geom.glsl` */
enum {
@@ -76,7 +79,7 @@ static void curve_render_overlay_verts_edges_len_get(ListBase *lb,
BLI_assert(r_vert_len || r_edge_len);
int vert_len = 0;
int edge_len = 0;
- for (Nurb *nu = lb->first; nu; nu = nu->next) {
+ LISTBASE_FOREACH (Nurb *, nu, lb) {
if (nu->bezt) {
vert_len += nu->pntsu * 3;
/* 2x handles per point*/
@@ -106,7 +109,7 @@ static void curve_render_wire_verts_edges_len_get(const CurveCache *ob_curve_cac
int vert_len = 0;
int edge_len = 0;
int curve_len = 0;
- for (const BevList *bl = ob_curve_cache->bev.first; bl; bl = bl->next) {
+ LISTBASE_FOREACH (const BevList *, bl, &ob_curve_cache->bev) {
if (bl->nr > 0) {
const bool is_cyclic = bl->poly != -1;
edge_len += (is_cyclic) ? bl->nr : bl->nr - 1;
@@ -114,7 +117,7 @@ static void curve_render_wire_verts_edges_len_get(const CurveCache *ob_curve_cac
curve_len += 1;
}
}
- for (const DispList *dl = ob_curve_cache->disp.first; dl; dl = dl->next) {
+ LISTBASE_FOREACH (const DispList *, dl, &ob_curve_cache->disp) {
if (ELEM(dl->type, DL_SEGM, DL_POLY)) {
BLI_assert(dl->parts == 1);
const bool is_cyclic = dl->type == DL_POLY;
@@ -314,7 +317,7 @@ static void curve_cd_calc_used_gpu_layers(int *cd_layers,
}
ListBase gpu_attrs = GPU_material_attributes(gpumat);
- for (GPUMaterialAttribute *gpu_attr = gpu_attrs.first; gpu_attr; gpu_attr = gpu_attr->next) {
+ LISTBASE_FOREACH (GPUMaterialAttribute *, gpu_attr, &gpu_attrs) {
const char *name = gpu_attr->name;
int type = gpu_attr->type;
@@ -375,7 +378,7 @@ typedef struct CurveBatchCache {
GPUIndexBuf *curves_lines;
GPUIndexBuf *edges_adj_lines;
/* Edit mode */
- GPUIndexBuf *edit_verts_points; /* Only control points. Not handles. */
+ GPUIndexBuf *edit_verts;
GPUIndexBuf *edit_lines;
} ibo;
@@ -386,7 +389,6 @@ typedef struct CurveBatchCache {
/* control handles and vertices */
GPUBatch *edit_edges;
GPUBatch *edit_verts;
- GPUBatch *edit_handles_verts;
GPUBatch *edit_normals;
GPUBatch *edge_detection;
} batch;
@@ -496,7 +498,6 @@ void DRW_curve_batch_cache_dirty_tag(Curve *cu, int mode)
GPU_BATCH_DISCARD_SAFE(cache->batch.edit_edges);
GPU_BATCH_DISCARD_SAFE(cache->batch.edit_verts);
- GPU_BATCH_DISCARD_SAFE(cache->batch.edit_handles_verts);
break;
default:
BLI_assert(0);
@@ -565,7 +566,7 @@ static void curve_create_curves_pos(CurveRenderData *rdata, GPUVertBuf *vbo_curv
GPU_vertbuf_data_alloc(vbo_curves_pos, vert_len);
int v_idx = 0;
- for (const BevList *bl = rdata->ob_curve_cache->bev.first; bl; bl = bl->next) {
+ LISTBASE_FOREACH (const BevList *, bl, &rdata->ob_curve_cache->bev) {
if (bl->nr <= 0) {
continue;
}
@@ -574,7 +575,7 @@ static void curve_create_curves_pos(CurveRenderData *rdata, GPUVertBuf *vbo_curv
GPU_vertbuf_attr_set(vbo_curves_pos, attr_id.pos, v_idx, bevp->vec);
}
}
- for (const DispList *dl = rdata->ob_curve_cache->disp.first; dl; dl = dl->next) {
+ LISTBASE_FOREACH (const DispList *, dl, &rdata->ob_curve_cache->disp) {
if (ELEM(dl->type, DL_SEGM, DL_POLY)) {
for (int i = 0; i < dl->nr; v_idx++, i++) {
GPU_vertbuf_attr_set(vbo_curves_pos, attr_id.pos, v_idx, &((float(*)[3])dl->verts)[i]);
@@ -598,7 +599,7 @@ static void curve_create_curves_lines(CurveRenderData *rdata, GPUIndexBuf *ibo_c
GPU_indexbuf_init_ex(&elb, GPU_PRIM_LINE_STRIP, index_len, vert_len);
int v_idx = 0;
- for (const BevList *bl = rdata->ob_curve_cache->bev.first; bl; bl = bl->next) {
+ LISTBASE_FOREACH (const BevList *, bl, &rdata->ob_curve_cache->bev) {
if (bl->nr <= 0) {
continue;
}
@@ -612,7 +613,7 @@ static void curve_create_curves_lines(CurveRenderData *rdata, GPUIndexBuf *ibo_c
GPU_indexbuf_add_primitive_restart(&elb);
v_idx += bl->nr;
}
- for (const DispList *dl = rdata->ob_curve_cache->disp.first; dl; dl = dl->next) {
+ LISTBASE_FOREACH (const DispList *, dl, &rdata->ob_curve_cache->disp) {
if (ELEM(dl->type, DL_SEGM, DL_POLY)) {
const bool is_cyclic = dl->type == DL_POLY;
if (is_cyclic) {
@@ -684,15 +685,22 @@ static void curve_create_edit_curves_nor(CurveRenderData *rdata, GPUVertBuf *vbo
BLI_assert(vbo_len_used == verts_len_capacity);
}
-static char beztriple_vflag_get(
- CurveRenderData *rdata, char flag, char col_id, int v_idx, int nu_id)
+static char beztriple_vflag_get(CurveRenderData *rdata,
+ char flag,
+ char col_id,
+ int v_idx,
+ int nu_id,
+ bool handle_point,
+ const bool handle_selected)
{
char vflag = 0;
SET_FLAG_FROM_TEST(vflag, (flag & SELECT), VFLAG_VERT_SELECTED);
SET_FLAG_FROM_TEST(vflag, (v_idx == rdata->actvert && nu_id == rdata->actnu), VFLAG_VERT_ACTIVE);
SET_FLAG_FROM_TEST(vflag, (nu_id == rdata->actnu), ACTIVE_NURB);
+ SET_FLAG_FROM_TEST(vflag, handle_point, BEZIER_HANDLE);
+ SET_FLAG_FROM_TEST(vflag, handle_selected, VFLAG_HANDLE_SELECTED);
/* handle color id */
- vflag |= col_id << 4; /* << 4 because of EVEN_U_BIT */
+ vflag |= col_id << COLOR_SHIFT;
return vflag;
}
@@ -703,7 +711,7 @@ static char bpoint_vflag_get(CurveRenderData *rdata, char flag, int v_idx, int n
SET_FLAG_FROM_TEST(vflag, (v_idx == rdata->actvert && nu_id == rdata->actnu), VFLAG_VERT_ACTIVE);
SET_FLAG_FROM_TEST(vflag, (nu_id == rdata->actnu), ACTIVE_NURB);
SET_FLAG_FROM_TEST(vflag, ((u % 2) == 0), EVEN_U_BIT);
- vflag |= COLOR_NURB_ULINE_ID << 4; /* << 4 because of EVEN_U_BIT */
+ vflag |= COLOR_NURB_ULINE_ID << COLOR_SHIFT;
return vflag;
}
@@ -752,14 +760,18 @@ static void curve_create_edit_data_and_handles(CurveRenderData *rdata,
for (Nurb *nu = rdata->nurbs->first; nu; nu = nu->next, nu_id++) {
const BezTriple *bezt = nu->bezt;
const BPoint *bp = nu->bp;
+
if (bezt) {
for (int a = 0; a < nu->pntsu; a++, bezt++) {
if (bezt->hide == true) {
continue;
}
+ const bool handle_selected = BEZT_ISSEL_ANY(bezt);
if (elbp_verts) {
+ GPU_indexbuf_add_point_vert(elbp_verts, vbo_len_used + 0);
GPU_indexbuf_add_point_vert(elbp_verts, vbo_len_used + 1);
+ GPU_indexbuf_add_point_vert(elbp_verts, vbo_len_used + 2);
}
if (elbp_lines) {
GPU_indexbuf_add_line_verts(elbp_lines, vbo_len_used + 1, vbo_len_used + 0);
@@ -767,9 +779,9 @@ static void curve_create_edit_data_and_handles(CurveRenderData *rdata,
}
if (vbo_data) {
const char vflag[3] = {
- beztriple_vflag_get(rdata, bezt->f1, bezt->h1, a, nu_id),
- beztriple_vflag_get(rdata, bezt->f2, bezt->h1, a, nu_id),
- beztriple_vflag_get(rdata, bezt->f3, bezt->h2, a, nu_id),
+ beztriple_vflag_get(rdata, bezt->f1, bezt->h1, a, nu_id, true, handle_selected),
+ beztriple_vflag_get(rdata, bezt->f2, bezt->h1, a, nu_id, false, handle_selected),
+ beztriple_vflag_get(rdata, bezt->f3, bezt->h2, a, nu_id, true, handle_selected),
};
for (int j = 0; j < 3; j++) {
GPU_vertbuf_attr_set(vbo_data, attr_id.data, vbo_len_used + j, &vflag[j]);
@@ -858,15 +870,10 @@ GPUBatch *DRW_curve_batch_cache_get_edit_edges(Curve *cu)
return DRW_batch_request(&cache->batch.edit_edges);
}
-GPUBatch *DRW_curve_batch_cache_get_edit_verts(Curve *cu, bool handles)
+GPUBatch *DRW_curve_batch_cache_get_edit_verts(Curve *cu)
{
CurveBatchCache *cache = curve_batch_cache_get(cu);
- if (handles) {
- return DRW_batch_request(&cache->batch.edit_handles_verts);
- }
- else {
- return DRW_batch_request(&cache->batch.edit_verts);
- }
+ return DRW_batch_request(&cache->batch.edit_verts);
}
GPUBatch *DRW_curve_batch_cache_get_triangles_with_normals(struct Curve *cu)
@@ -964,14 +971,10 @@ void DRW_curve_batch_cache_create_requested(Object *ob)
DRW_vbo_request(cache->batch.edit_edges, &cache->edit.data);
}
if (DRW_batch_requested(cache->batch.edit_verts, GPU_PRIM_POINTS)) {
- DRW_ibo_request(cache->batch.edit_verts, &cache->ibo.edit_verts_points);
+ DRW_ibo_request(cache->batch.edit_verts, &cache->ibo.edit_verts);
DRW_vbo_request(cache->batch.edit_verts, &cache->edit.pos);
DRW_vbo_request(cache->batch.edit_verts, &cache->edit.data);
}
- if (DRW_batch_requested(cache->batch.edit_handles_verts, GPU_PRIM_POINTS)) {
- DRW_vbo_request(cache->batch.edit_handles_verts, &cache->edit.pos);
- DRW_vbo_request(cache->batch.edit_handles_verts, &cache->edit.data);
- }
if (DRW_batch_requested(cache->batch.edit_normals, GPU_PRIM_LINES)) {
DRW_vbo_request(cache->batch.edit_normals, &cache->edit.curves_nor);
}
@@ -1011,7 +1014,7 @@ void DRW_curve_batch_cache_create_requested(Object *ob)
DRW_ADD_FLAG_FROM_VBO_REQUEST(mr_flag, cache->edit.data, CU_DATATYPE_OVERLAY);
DRW_ADD_FLAG_FROM_VBO_REQUEST(mr_flag, cache->edit.curves_nor, CU_DATATYPE_NORMAL);
DRW_ADD_FLAG_FROM_VBO_REQUEST(mr_flag, cache->edit.curves_weight, CU_DATATYPE_OVERLAY);
- DRW_ADD_FLAG_FROM_IBO_REQUEST(mr_flag, cache->ibo.edit_verts_points, CU_DATATYPE_OVERLAY);
+ DRW_ADD_FLAG_FROM_IBO_REQUEST(mr_flag, cache->ibo.edit_verts, CU_DATATYPE_OVERLAY);
DRW_ADD_FLAG_FROM_IBO_REQUEST(mr_flag, cache->ibo.edit_lines, CU_DATATYPE_OVERLAY);
for (int i = 0; i < cache->mat_len; i++) {
@@ -1039,7 +1042,7 @@ void DRW_curve_batch_cache_create_requested(Object *ob)
}
if (DRW_vbo_requested(cache->ordered.loop_pos_nor) ||
- DRW_vbo_requested(cache->ordered.loop_uv)) {
+ DRW_vbo_requested(cache->ordered.loop_uv) || DRW_vbo_requested(cache->ordered.loop_tan)) {
DRW_displist_vertbuf_create_loop_pos_and_nor_and_uv_and_tan(
lb, cache->ordered.loop_pos_nor, cache->ordered.loop_uv, cache->ordered.loop_tan);
}
@@ -1064,13 +1067,9 @@ void DRW_curve_batch_cache_create_requested(Object *ob)
}
if (DRW_vbo_requested(cache->edit.pos) || DRW_vbo_requested(cache->edit.data) ||
- DRW_ibo_requested(cache->ibo.edit_verts_points) ||
- DRW_ibo_requested(cache->ibo.edit_lines)) {
- curve_create_edit_data_and_handles(rdata,
- cache->edit.pos,
- cache->edit.data,
- cache->ibo.edit_verts_points,
- cache->ibo.edit_lines);
+ DRW_ibo_requested(cache->ibo.edit_verts) || DRW_ibo_requested(cache->ibo.edit_lines)) {
+ curve_create_edit_data_and_handles(
+ rdata, cache->edit.pos, cache->edit.data, cache->ibo.edit_verts, cache->ibo.edit_lines);
}
if (DRW_vbo_requested(cache->edit.curves_nor)) {
curve_create_edit_curves_nor(rdata, cache->edit.curves_nor);
diff --git a/source/blender/draw/intern/draw_cache_impl_displist.c b/source/blender/draw/intern/draw_cache_impl_displist.c
index 04889463447..e09f78aa51f 100644
--- a/source/blender/draw/intern/draw_cache_impl_displist.c
+++ b/source/blender/draw/intern/draw_cache_impl_displist.c
@@ -27,6 +27,7 @@
#include "BLI_alloca.h"
#include "BLI_edgehash.h"
+#include "BLI_listbase.h"
#include "BLI_math_vector.h"
#include "BLI_utildefines.h"
@@ -71,7 +72,7 @@ static int dl_tri_len(const DispList *dl)
static int curve_render_surface_vert_len_get(const ListBase *lb)
{
int vert_len = 0;
- for (const DispList *dl = lb->first; dl; dl = dl->next) {
+ LISTBASE_FOREACH (const DispList *, dl, lb) {
vert_len += dl_vert_len(dl);
}
return vert_len;
@@ -80,7 +81,7 @@ static int curve_render_surface_vert_len_get(const ListBase *lb)
static int curve_render_surface_tri_len_get(const ListBase *lb)
{
int tri_len = 0;
- for (const DispList *dl = lb->first; dl; dl = dl->next) {
+ LISTBASE_FOREACH (const DispList *, dl, lb) {
tri_len += dl_tri_len(dl);
}
return tri_len;
@@ -192,7 +193,7 @@ void DRW_displist_vertbuf_create_pos_and_nor(ListBase *lb, GPUVertBuf *vbo)
BKE_displist_normals_add(lb);
int vbo_len_used = 0;
- for (const DispList *dl = lb->first; dl; dl = dl->next) {
+ LISTBASE_FOREACH (const DispList *, dl, lb) {
const bool ndata_is_single = dl->type == DL_INDEX3;
if (ELEM(dl->type, DL_INDEX3, DL_INDEX4, DL_SURF)) {
const float *fp_co = dl->verts;
@@ -262,7 +263,7 @@ void DRW_displist_indexbuf_create_triangles_in_order(ListBase *lb, GPUIndexBuf *
GPU_indexbuf_init(&elb, GPU_PRIM_TRIS, tri_len, vert_len);
int ofs = 0;
- for (const DispList *dl = lb->first; dl; dl = dl->next) {
+ LISTBASE_FOREACH (const DispList *, dl, lb) {
displist_indexbufbuilder_set((SetTriIndicesFn *)GPU_indexbuf_add_tri_verts,
(SetTriIndicesFn *)GPU_indexbuf_add_tri_verts,
&elb,
@@ -289,7 +290,7 @@ void DRW_displist_indexbuf_create_triangles_loop_split_by_material(ListBase *lb,
/* calc each index buffer builder */
uint v_idx = 0;
- for (const DispList *dl = lb->first; dl; dl = dl->next) {
+ LISTBASE_FOREACH (const DispList *, dl, lb) {
v_idx = displist_indexbufbuilder_tess_set((SetTriIndicesFn *)GPU_indexbuf_add_tri_verts,
(SetTriIndicesFn *)GPU_indexbuf_add_tri_verts,
&elb[dl->col],
@@ -327,7 +328,7 @@ void DRW_displist_indexbuf_create_lines_in_order(ListBase *lb, GPUIndexBuf *ibo)
GPU_indexbuf_init(&elb, GPU_PRIM_LINES, tri_len * 3, vert_len);
int ofs = 0;
- for (const DispList *dl = lb->first; dl; dl = dl->next) {
+ LISTBASE_FOREACH (const DispList *, dl, lb) {
displist_indexbufbuilder_set(
set_overlay_wires_tri_indices, set_overlay_wires_quad_tri_indices, &elb, dl, ofs);
ofs += dl_vert_len(dl);
@@ -406,7 +407,7 @@ static void displist_vertbuf_attr_set_tri_pos_nor_uv(GPUVertBufRaw *pos_step,
}
}
-#define SURFACE_QUAD_ITER_START(dl) \
+#define SURFACE_QUAD_ITER_BEGIN(dl) \
{ \
uint quad[4]; \
int quad_index = 0; \
@@ -446,8 +447,7 @@ static void displist_surf_fnors_ensure(const DispList *dl, float (**fnors)[3])
float(*nor_flat)[3] = MEM_mallocN(sizeof(float) * 3 * u_len * v_len, __func__);
*fnors = nor_flat;
- SURFACE_QUAD_ITER_START(dl)
- {
+ SURFACE_QUAD_ITER_BEGIN (dl) {
normal_quad_v3(*nor_flat, verts[quad[0]], verts[quad[1]], verts[quad[2]], verts[quad[3]]);
nor_flat++;
}
@@ -508,7 +508,7 @@ void DRW_displist_vertbuf_create_loop_pos_and_nor_and_uv_and_tan(ListBase *lb,
BKE_displist_normals_add(lb);
- for (const DispList *dl = lb->first; dl; dl = dl->next) {
+ LISTBASE_FOREACH (const DispList *, dl, lb) {
const bool is_smooth = (dl->rt & CU_SMOOTH) != 0;
if (ELEM(dl->type, DL_INDEX3, DL_INDEX4, DL_SURF)) {
const float(*verts)[3] = (float(*)[3])dl->verts;
@@ -570,8 +570,7 @@ void DRW_displist_vertbuf_create_loop_pos_and_nor_and_uv_and_tan(ListBase *lb,
BKE_displist_tangent_calc(dl, fnors, &tangents);
}
- SURFACE_QUAD_ITER_START(dl)
- {
+ SURFACE_QUAD_ITER_BEGIN (dl) {
if (vbo_uv) {
surf_uv_quad(dl, quad, uv);
}
@@ -781,7 +780,7 @@ void DRW_displist_indexbuf_create_edges_adjacency_lines(struct ListBase *lb,
/* pack values to pass to `set_edges_adjacency_lines_indices` function. */
void *thunk[3] = {&elb, eh, r_is_manifold};
int v_idx = 0;
- for (const DispList *dl = lb->first; dl; dl = dl->next) {
+ LISTBASE_FOREACH (const DispList *, dl, lb) {
displist_indexbufbuilder_set((SetTriIndicesFn *)set_edges_adjacency_lines_indices,
(SetTriIndicesFn *)set_edges_adjacency_lines_indices,
thunk,
diff --git a/source/blender/draw/intern/draw_cache_impl_gpencil.c b/source/blender/draw/intern/draw_cache_impl_gpencil.c
index 349eb6b00ae..b4974330043 100644
--- a/source/blender/draw/intern/draw_cache_impl_gpencil.c
+++ b/source/blender/draw/intern/draw_cache_impl_gpencil.c
@@ -62,8 +62,6 @@ typedef struct GpencilBatchCache {
/** Cache is dirty */
bool is_dirty;
- /** Edit mode flag */
- bool is_editmode;
/** Last cache frame */
int cache_frame;
} GpencilBatchCache;
@@ -71,21 +69,17 @@ typedef struct GpencilBatchCache {
static bool gpencil_batch_cache_valid(GpencilBatchCache *cache, bGPdata *gpd, int cfra)
{
bool valid = true;
+
if (cache == NULL) {
return false;
}
- cache->is_editmode = GPENCIL_ANY_EDIT_MODE(gpd);
if (cfra != cache->cache_frame) {
valid = false;
}
else if (gpd->flag & GP_DATA_CACHE_IS_DIRTY) {
valid = false;
}
- else if (gpd->flag & GP_DATA_PYTHON_UPDATED) {
- gpd->flag &= ~GP_DATA_PYTHON_UPDATED;
- valid = false;
- }
else if (cache->is_dirty) {
valid = false;
}
@@ -106,9 +100,9 @@ static GpencilBatchCache *gpencil_batch_cache_init(Object *ob, int cfra)
memset(cache, 0, sizeof(*cache));
}
- cache->is_editmode = GPENCIL_ANY_EDIT_MODE(gpd);
cache->is_dirty = true;
cache->cache_frame = cfra;
+
return cache;
}
@@ -181,7 +175,8 @@ static GPUVertFormat *gpencil_stroke_format(void)
GPU_vertformat_attr_add(&format, "ma", GPU_COMP_I32, 4, GPU_FETCH_INT);
GPU_vertformat_attr_add(&format, "pos", GPU_COMP_F32, 4, GPU_FETCH_FLOAT);
GPU_vertformat_attr_add(&format, "uv", GPU_COMP_F32, 4, GPU_FETCH_FLOAT);
- /* IMPORTANT: This means having only 4 attributes to fit into GPU module limit of 16 attrib. */
+ /* IMPORTANT: This means having only 4 attributes
+ * to fit into GPU module limit of 16 attributes. */
GPU_vertformat_multiload_enable(&format, 4);
}
return &format;
@@ -215,7 +210,8 @@ static GPUVertFormat *gpencil_color_format(void)
if (format.attr_len == 0) {
GPU_vertformat_attr_add(&format, "col", GPU_COMP_F32, 4, GPU_FETCH_FLOAT);
GPU_vertformat_attr_add(&format, "fcol", GPU_COMP_F32, 4, GPU_FETCH_FLOAT);
- /* IMPORTANT: This means having only 4 attributes to fit into GPU module limit of 16 attrib. */
+ /* IMPORTANT: This means having only 4 attributes
+ * to fit into GPU module limit of 16 attributes. */
GPU_vertformat_multiload_enable(&format, 4);
}
return &format;
@@ -296,7 +292,7 @@ static void gpencil_buffer_add_point(gpStrokeVert *verts,
vert->u_stroke = pt->uv_fac;
vert->stroke_id = gps->runtime.stroke_start;
vert->point_id = v;
- vert->thickness = max_ff(0.0f, gps->thickness * pt->pressure) * (round_cap1 ? 1.0 : -1.0);
+ vert->thickness = max_ff(0.0f, gps->thickness * pt->pressure) * (round_cap1 ? 1.0f : -1.0f);
/* Tag endpoint material to -1 so they get discarded by vertex shader. */
vert->mat = (is_endpoint) ? -1 : (gps->mat_nr % GP_MATERIAL_BUFFER_LEN);
@@ -390,7 +386,8 @@ static void gpencil_batches_ensure(Object *ob, GpencilBatchCache *cache, int cfr
.vert_len = 1, /* Start at 1 for the gl_InstanceID trick to work (see vert shader). */
.tri_len = 0,
};
- BKE_gpencil_visible_stroke_iter(ob, NULL, gp_object_verts_count_cb, &iter, do_onion, cfra);
+ BKE_gpencil_visible_stroke_iter(
+ NULL, ob, NULL, gp_object_verts_count_cb, &iter, do_onion, cfra);
/* Create VBOs. */
GPUVertFormat *format = gpencil_stroke_format();
@@ -406,7 +403,7 @@ static void gpencil_batches_ensure(Object *ob, GpencilBatchCache *cache, int cfr
GPU_indexbuf_init(&iter.ibo, GPU_PRIM_TRIS, iter.tri_len, iter.vert_len);
/* Fill buffers with data. */
- BKE_gpencil_visible_stroke_iter(ob, NULL, gpencil_stroke_iter_cb, &iter, do_onion, cfra);
+ BKE_gpencil_visible_stroke_iter(NULL, ob, NULL, gpencil_stroke_iter_cb, &iter, do_onion, cfra);
/* Mark last 2 verts as invalid. */
for (int i = 0; i < 2; i++) {
@@ -480,7 +477,7 @@ GPUBatch *DRW_cache_gpencil_face_wireframe_get(Object *ob)
/* IMPORTANT: Keep in sync with gpencil_edit_batches_ensure() */
bool do_onion = true;
- BKE_gpencil_visible_stroke_iter(ob, NULL, gp_lines_indices_cb, &iter, do_onion, cfra);
+ BKE_gpencil_visible_stroke_iter(NULL, ob, NULL, gp_lines_indices_cb, &iter, do_onion, cfra);
GPUIndexBuf *ibo = GPU_indexbuf_build(&iter.ibo);
@@ -542,15 +539,14 @@ static void gpencil_sbuffer_stroke_ensure(bGPdata *gpd, bool do_stroke, bool do_
/* Get origin to reproject points. */
float origin[3];
- bGPDlayer *gpl = BKE_gpencil_layer_active_get(gpd);
ToolSettings *ts = scene->toolsettings;
- ED_gpencil_drawing_reference_get(scene, ob, gpl, ts->gpencil_v3d_align, origin);
+ ED_gpencil_drawing_reference_get(scene, ob, ts->gpencil_v3d_align, origin);
for (int i = 0; i < vert_len; i++) {
ED_gpencil_tpoint_to_point(region, origin, &tpoints[i], &gps->points[i]);
mul_m4_v3(ob->imat, &gps->points[i].x);
bGPDspoint *pt = &gps->points[i];
- copy_v4_v4(pt->vert_color, gpd->runtime.vert_color);
+ copy_v4_v4(pt->vert_color, tpoints[i].vert_color);
}
/* Calc uv data along the stroke. */
BKE_gpencil_stroke_uv_update(gps);
@@ -730,7 +726,8 @@ static void gpencil_edit_batches_ensure(Object *ob, GpencilBatchCache *cache, in
iter.verts = (gpEditVert *)cache->edit_vbo->data;
/* Fill buffers with data. */
- BKE_gpencil_visible_stroke_iter(ob, NULL, gpencil_edit_stroke_iter_cb, &iter, do_onion, cfra);
+ BKE_gpencil_visible_stroke_iter(
+ NULL, ob, NULL, gpencil_edit_stroke_iter_cb, &iter, do_onion, cfra);
/* Create the batches */
cache->edit_points_batch = GPU_batch_create(GPU_PRIM_POINTS, cache->vbo, NULL);
diff --git a/source/blender/draw/intern/draw_cache_impl_mesh.c b/source/blender/draw/intern/draw_cache_impl_mesh.c
index aedc86c2eae..99e285a18f1 100644
--- a/source/blender/draw/intern/draw_cache_impl_mesh.c
+++ b/source/blender/draw/intern/draw_cache_impl_mesh.c
@@ -29,9 +29,11 @@
#include "BLI_bitmap.h"
#include "BLI_buffer.h"
#include "BLI_edgehash.h"
+#include "BLI_listbase.h"
#include "BLI_math_bits.h"
#include "BLI_math_vector.h"
#include "BLI_string.h"
+#include "BLI_task.h"
#include "BLI_utildefines.h"
#include "DNA_mesh_types.h"
@@ -95,11 +97,25 @@ static void mesh_cd_calc_edit_uv_layer(const Mesh *UNUSED(me), DRW_MeshCDMask *c
cd_used->edit_uv = 1;
}
+BLI_INLINE const CustomData *mesh_cd_ldata_get_from_mesh(const Mesh *me)
+{
+ switch ((eMeshWrapperType)me->runtime.wrapper_type) {
+ case ME_WRAPPER_TYPE_MDATA:
+ return &me->ldata;
+ break;
+ case ME_WRAPPER_TYPE_BMESH:
+ return &me->edit_mesh->bm->ldata;
+ break;
+ }
+
+ BLI_assert(0);
+ return &me->ldata;
+}
+
static void mesh_cd_calc_active_uv_layer(const Mesh *me, DRW_MeshCDMask *cd_used)
{
const Mesh *me_final = (me->edit_mesh) ? me->edit_mesh->mesh_eval_final : me;
- const CustomData *cd_ldata = &me_final->ldata;
-
+ const CustomData *cd_ldata = mesh_cd_ldata_get_from_mesh(me_final);
int layer = CustomData_get_active_layer(cd_ldata, CD_MLOOPUV);
if (layer != -1) {
cd_used->uv |= (1 << layer);
@@ -109,8 +125,7 @@ static void mesh_cd_calc_active_uv_layer(const Mesh *me, DRW_MeshCDMask *cd_used
static void mesh_cd_calc_active_mask_uv_layer(const Mesh *me, DRW_MeshCDMask *cd_used)
{
const Mesh *me_final = (me->edit_mesh) ? me->edit_mesh->mesh_eval_final : me;
- const CustomData *cd_ldata = &me_final->ldata;
-
+ const CustomData *cd_ldata = mesh_cd_ldata_get_from_mesh(me_final);
int layer = CustomData_get_stencil_layer(cd_ldata, CD_MLOOPUV);
if (layer != -1) {
cd_used->uv |= (1 << layer);
@@ -120,8 +135,7 @@ static void mesh_cd_calc_active_mask_uv_layer(const Mesh *me, DRW_MeshCDMask *cd
static void mesh_cd_calc_active_vcol_layer(const Mesh *me, DRW_MeshCDMask *cd_used)
{
const Mesh *me_final = (me->edit_mesh) ? me->edit_mesh->mesh_eval_final : me;
- const CustomData *cd_ldata = &me_final->ldata;
-
+ const CustomData *cd_ldata = mesh_cd_ldata_get_from_mesh(me_final);
int layer = CustomData_get_active_layer(cd_ldata, CD_MLOOPCOL);
if (layer != -1) {
cd_used->vcol |= (1 << layer);
@@ -133,7 +147,7 @@ static DRW_MeshCDMask mesh_cd_calc_used_gpu_layers(const Mesh *me,
int gpumat_array_len)
{
const Mesh *me_final = (me->edit_mesh) ? me->edit_mesh->mesh_eval_final : me;
- const CustomData *cd_ldata = &me_final->ldata;
+ const CustomData *cd_ldata = mesh_cd_ldata_get_from_mesh(me_final);
/* See: DM_vertex_attributes_from_gpu for similar logic */
DRW_MeshCDMask cd_used;
@@ -143,7 +157,7 @@ static DRW_MeshCDMask mesh_cd_calc_used_gpu_layers(const Mesh *me,
GPUMaterial *gpumat = gpumat_array[i];
if (gpumat) {
ListBase gpu_attrs = GPU_material_attributes(gpumat);
- for (GPUMaterialAttribute *gpu_attr = gpu_attrs.first; gpu_attr; gpu_attr = gpu_attr->next) {
+ LISTBASE_FOREACH (GPUMaterialAttribute *, gpu_attr, &gpu_attrs) {
const char *name = gpu_attr->name;
int type = gpu_attr->type;
int layer = -1;
@@ -301,7 +315,7 @@ static void drw_mesh_weight_state_extract(Object *ob,
wstate->alert_mode = ts->weightuser;
if (paint_mode && ts->multipaint) {
- /* Multipaint needs to know all selected bones, not just the active group.
+ /* Multi-paint needs to know all selected bones, not just the active group.
* This is actually a relatively expensive operation, but caching would be difficult. */
wstate->defgroup_sel = BKE_object_defgroup_selected_get(
ob, wstate->defgroup_len, &wstate->defgroup_sel_count);
@@ -436,8 +450,7 @@ static void mesh_batch_cache_check_vertex_group(MeshBatchCache *cache,
const struct DRW_MeshWeightState *wstate)
{
if (!drw_mesh_weight_state_compare(&cache->weight_state, wstate)) {
- FOREACH_MESH_BUFFER_CACHE(cache, mbufcache)
- {
+ FOREACH_MESH_BUFFER_CACHE (cache, mbufcache) {
GPU_VERTBUF_DISCARD_SAFE(mbufcache->vbo.weights);
}
GPU_BATCH_CLEAR_SAFE(cache->batch.surface_weights);
@@ -460,8 +473,7 @@ static void mesh_batch_cache_discard_shaded_batches(MeshBatchCache *cache)
static void mesh_batch_cache_discard_shaded_tri(MeshBatchCache *cache)
{
- FOREACH_MESH_BUFFER_CACHE(cache, mbufcache)
- {
+ FOREACH_MESH_BUFFER_CACHE (cache, mbufcache) {
GPU_VERTBUF_DISCARD_SAFE(mbufcache->vbo.pos_nor);
GPU_VERTBUF_DISCARD_SAFE(mbufcache->vbo.uv);
GPU_VERTBUF_DISCARD_SAFE(mbufcache->vbo.tan);
@@ -478,8 +490,7 @@ static void mesh_batch_cache_discard_shaded_tri(MeshBatchCache *cache)
static void mesh_batch_cache_discard_uvedit(MeshBatchCache *cache)
{
- FOREACH_MESH_BUFFER_CACHE(cache, mbufcache)
- {
+ FOREACH_MESH_BUFFER_CACHE (cache, mbufcache) {
GPU_VERTBUF_DISCARD_SAFE(mbufcache->vbo.stretch_angle);
GPU_VERTBUF_DISCARD_SAFE(mbufcache->vbo.stretch_area);
GPU_VERTBUF_DISCARD_SAFE(mbufcache->vbo.uv);
@@ -517,8 +528,7 @@ static void mesh_batch_cache_discard_uvedit(MeshBatchCache *cache)
static void mesh_batch_cache_discard_uvedit_select(MeshBatchCache *cache)
{
- FOREACH_MESH_BUFFER_CACHE(cache, mbufcache)
- {
+ FOREACH_MESH_BUFFER_CACHE (cache, mbufcache) {
GPU_VERTBUF_DISCARD_SAFE(mbufcache->vbo.edituv_data);
GPU_VERTBUF_DISCARD_SAFE(mbufcache->vbo.fdots_edituv_data);
GPU_INDEXBUF_DISCARD_SAFE(mbufcache->ibo.edituv_tris);
@@ -544,8 +554,7 @@ void DRW_mesh_batch_cache_dirty_tag(Mesh *me, int mode)
}
switch (mode) {
case BKE_MESH_BATCH_DIRTY_SELECT:
- FOREACH_MESH_BUFFER_CACHE(cache, mbufcache)
- {
+ FOREACH_MESH_BUFFER_CACHE (cache, mbufcache) {
GPU_VERTBUF_DISCARD_SAFE(mbufcache->vbo.edit_data);
GPU_VERTBUF_DISCARD_SAFE(mbufcache->vbo.fdots_nor);
}
@@ -566,10 +575,9 @@ void DRW_mesh_batch_cache_dirty_tag(Mesh *me, int mode)
mesh_batch_cache_discard_uvedit_select(cache);
break;
case BKE_MESH_BATCH_DIRTY_SELECT_PAINT:
- /* Paint mode selection flag is packed inside the nor attrib.
+ /* Paint mode selection flag is packed inside the nor attribute.
* Note that it can be slow if auto smooth is enabled. (see T63946) */
- FOREACH_MESH_BUFFER_CACHE(cache, mbufcache)
- {
+ FOREACH_MESH_BUFFER_CACHE (cache, mbufcache) {
GPU_INDEXBUF_DISCARD_SAFE(mbufcache->ibo.lines_paint_mask);
GPU_VERTBUF_DISCARD_SAFE(mbufcache->vbo.pos_nor);
GPU_VERTBUF_DISCARD_SAFE(mbufcache->vbo.lnor);
@@ -595,8 +603,7 @@ void DRW_mesh_batch_cache_dirty_tag(Mesh *me, int mode)
mesh_batch_cache_discard_uvedit(cache);
break;
case BKE_MESH_BATCH_DIRTY_UVEDIT_SELECT:
- FOREACH_MESH_BUFFER_CACHE(cache, mbufcache)
- {
+ FOREACH_MESH_BUFFER_CACHE (cache, mbufcache) {
GPU_VERTBUF_DISCARD_SAFE(mbufcache->vbo.edituv_data);
GPU_VERTBUF_DISCARD_SAFE(mbufcache->vbo.fdots_edituv_data);
}
@@ -619,8 +626,7 @@ static void mesh_batch_cache_clear(Mesh *me)
if (!cache) {
return;
}
- FOREACH_MESH_BUFFER_CACHE(cache, mbufcache)
- {
+ FOREACH_MESH_BUFFER_CACHE (cache, mbufcache) {
GPUVertBuf **vbos = (GPUVertBuf **)&mbufcache->vbo;
GPUIndexBuf **ibos = (GPUIndexBuf **)&mbufcache->ibo;
for (int i = 0; i < sizeof(mbufcache->vbo) / sizeof(void *); i++) {
@@ -1014,9 +1020,14 @@ void DRW_mesh_batch_cache_free_old(Mesh *me, int ctime)
}
/* Can be called for any surface type. Mesh *me is the final mesh. */
-void DRW_mesh_batch_cache_create_requested(
- Object *ob, Mesh *me, const Scene *scene, const bool is_paint_mode, const bool use_hide)
-{
+void DRW_mesh_batch_cache_create_requested(struct TaskGraph *task_graph,
+ Object *ob,
+ Mesh *me,
+ const Scene *scene,
+ const bool is_paint_mode,
+ const bool use_hide)
+{
+ BLI_assert(task_graph);
GPUIndexBuf **saved_elem_ranges = NULL;
const ToolSettings *ts = NULL;
if (scene) {
@@ -1060,8 +1071,7 @@ void DRW_mesh_batch_cache_create_requested(
* index ranges initialized. So discard ibo.tris in order to recreate it.
* This needs to happen before saved_elem_ranges is populated. */
if ((batch_requested & MBC_SURF_PER_MAT) != 0 && (cache->batch_ready & MBC_SURF_PER_MAT) == 0) {
- FOREACH_MESH_BUFFER_CACHE(cache, mbuffercache)
- {
+ FOREACH_MESH_BUFFER_CACHE (cache, mbuffercache) {
GPU_INDEXBUF_DISCARD_SAFE(mbuffercache->ibo.tris);
}
/* Clear all batches that reference ibo.tris. */
@@ -1098,8 +1108,7 @@ void DRW_mesh_batch_cache_create_requested(
* material. */
bool cd_overlap = mesh_cd_layers_type_overlap(cache->cd_used, cache->cd_needed);
if (cd_overlap == false) {
- FOREACH_MESH_BUFFER_CACHE(cache, mbuffercache)
- {
+ FOREACH_MESH_BUFFER_CACHE (cache, mbuffercache) {
if ((cache->cd_used.uv & cache->cd_needed.uv) != cache->cd_needed.uv) {
GPU_VERTBUF_DISCARD_SAFE(mbuffercache->vbo.uv);
cd_uv_update = true;
@@ -1145,8 +1154,7 @@ void DRW_mesh_batch_cache_create_requested(
const bool is_uvsyncsel = ts && (ts->uv_flag & UV_SYNC_SELECTION);
if (cd_uv_update || (cache->is_uvsyncsel != is_uvsyncsel)) {
cache->is_uvsyncsel = is_uvsyncsel;
- FOREACH_MESH_BUFFER_CACHE(cache, mbuffercache)
- {
+ FOREACH_MESH_BUFFER_CACHE (cache, mbuffercache) {
GPU_VERTBUF_DISCARD_SAFE(mbuffercache->vbo.edituv_data);
GPU_VERTBUF_DISCARD_SAFE(mbuffercache->vbo.fdots_uv);
GPU_INDEXBUF_DISCARD_SAFE(mbuffercache->ibo.edituv_tris);
@@ -1184,10 +1192,10 @@ void DRW_mesh_batch_cache_create_requested(
MeshBufferCache *mbufcache = &cache->final;
- /* Init batches and request VBOs & IBOs */
+ /* Initialize batches and request VBO's & IBO's. */
if (DRW_batch_requested(cache->batch.surface, GPU_PRIM_TRIS)) {
DRW_ibo_request(cache->batch.surface, &mbufcache->ibo.tris);
- /* Order matters. First ones override latest vbos' attribs. */
+ /* Order matters. First ones override latest VBO's attributes. */
DRW_vbo_request(cache->batch.surface, &mbufcache->vbo.lnor);
DRW_vbo_request(cache->batch.surface, &mbufcache->vbo.pos_nor);
if (cache->cd_used.uv != 0) {
@@ -1220,7 +1228,7 @@ void DRW_mesh_batch_cache_create_requested(
}
if (DRW_batch_requested(cache->batch.wire_loops, GPU_PRIM_LINES)) {
DRW_ibo_request(cache->batch.wire_loops, &mbufcache->ibo.lines_paint_mask);
- /* Order matters. First ones override latest vbos' attribs. */
+ /* Order matters. First ones override latest VBO's attributes. */
DRW_vbo_request(cache->batch.wire_loops, &mbufcache->vbo.lnor);
DRW_vbo_request(cache->batch.wire_loops, &mbufcache->vbo.pos_nor);
}
@@ -1252,7 +1260,7 @@ void DRW_mesh_batch_cache_create_requested(
else {
DRW_ibo_request(cache->surface_per_mat[i], &mbufcache->ibo.tris);
}
- /* Order matters. First ones override latest vbos' attribs. */
+ /* Order matters. First ones override latest VBO's attributes. */
DRW_vbo_request(cache->surface_per_mat[i], &mbufcache->vbo.lnor);
DRW_vbo_request(cache->surface_per_mat[i], &mbufcache->vbo.pos_nor);
if (cache->cd_used.uv != 0) {
@@ -1372,13 +1380,16 @@ void DRW_mesh_batch_cache_create_requested(
}
/* Meh loose Scene const correctness here. */
- const bool use_subsurf_fdots = scene ? modifiers_usesSubsurfFacedots((Scene *)scene, ob) : false;
+ const bool use_subsurf_fdots = scene ? BKE_modifiers_uses_subsurf_facedots((Scene *)scene, ob) :
+ false;
if (do_uvcage) {
- mesh_buffer_cache_create_requested(cache,
+ mesh_buffer_cache_create_requested(task_graph,
+ cache,
cache->uv_cage,
me,
is_editmode,
+ is_paint_mode,
ob->obmat,
false,
true,
@@ -1390,10 +1401,12 @@ void DRW_mesh_batch_cache_create_requested(
}
if (do_cage) {
- mesh_buffer_cache_create_requested(cache,
+ mesh_buffer_cache_create_requested(task_graph,
+ cache,
cache->cage,
me,
is_editmode,
+ is_paint_mode,
ob->obmat,
false,
false,
@@ -1404,10 +1417,12 @@ void DRW_mesh_batch_cache_create_requested(
true);
}
- mesh_buffer_cache_create_requested(cache,
+ mesh_buffer_cache_create_requested(task_graph,
+ cache,
cache->final,
me,
is_editmode,
+ is_paint_mode,
ob->obmat,
true,
false,
@@ -1416,10 +1431,12 @@ void DRW_mesh_batch_cache_create_requested(
scene,
ts,
use_hide);
-
#ifdef DEBUG
check:
/* Make sure all requested batches have been setup. */
+ /* TODO(jbakker): we should move this to the draw_manager but that needs refactoring and
+ * additional looping.*/
+ BLI_task_graph_work_and_wait(task_graph);
for (int i = 0; i < sizeof(cache->batch) / sizeof(void *); i++) {
BLI_assert(!DRW_batch_requested(((GPUBatch **)&cache->batch)[i], 0));
}
diff --git a/source/blender/draw/intern/draw_cache_impl_particles.c b/source/blender/draw/intern/draw_cache_impl_particles.c
index 42a1dce891d..331a1f80bec 100644
--- a/source/blender/draw/intern/draw_cache_impl_particles.c
+++ b/source/blender/draw/intern/draw_cache_impl_particles.c
@@ -339,7 +339,8 @@ static void particle_calculate_parent_mcol(ParticleSystem *psys,
if (num != DMCACHE_NOTFOUND && num != DMCACHE_ISCHILD) {
MFace *mface = &psmd->mesh_final->mface[num];
for (int j = 0; j < num_col_layers; j++) {
- psys_interpolate_mcol(mcols[j] + num, mface->v4, particle->fuv, &r_mcol[j]);
+ /* CustomDataLayer CD_MCOL has 4 structs per face. */
+ psys_interpolate_mcol(mcols[j] + num * 4, mface->v4, particle->fuv, &r_mcol[j]);
}
}
}
@@ -388,6 +389,7 @@ static void particle_interpolate_children_mcol(ParticleSystem *psys,
if (num != DMCACHE_NOTFOUND) {
MFace *mface = &psmd->mesh_final->mface[num];
for (int j = 0; j < num_col_layers; j++) {
+ /* CustomDataLayer CD_MCOL has 4 structs per face. */
psys_interpolate_mcol(mcols[j] + num * 4, mface->v4, particle->fuv, &r_mcol[j]);
}
}
@@ -877,9 +879,9 @@ static void particle_batch_cache_ensure_procedural_strand_data(PTCacheEdit *edit
GPU_vertbuf_data_alloc(cache->proc_uv_buf[i], cache->strands_len);
GPU_vertbuf_attr_get_raw_data(cache->proc_uv_buf[i], uv_id, &uv_step[i]);
- char attr_safe_name[GPU_MAX_SAFE_ATTRIB_NAME];
+ char attr_safe_name[GPU_MAX_SAFE_ATTR_NAME];
const char *name = CustomData_get_layer_name(&psmd->mesh_final->ldata, CD_MLOOPUV, i);
- GPU_vertformat_safe_attrib_name(name, attr_safe_name, GPU_MAX_SAFE_ATTRIB_NAME);
+ GPU_vertformat_safe_attr_name(name, attr_safe_name, GPU_MAX_SAFE_ATTR_NAME);
int n = 0;
BLI_snprintf(cache->uv_layer_names[i][n++], MAX_LAYER_NAME_LEN, "u%s", attr_safe_name);
@@ -898,9 +900,9 @@ static void particle_batch_cache_ensure_procedural_strand_data(PTCacheEdit *edit
GPU_vertbuf_data_alloc(cache->proc_col_buf[i], cache->strands_len);
GPU_vertbuf_attr_get_raw_data(cache->proc_col_buf[i], col_id, &col_step[i]);
- char attr_safe_name[GPU_MAX_SAFE_ATTRIB_NAME];
+ char attr_safe_name[GPU_MAX_SAFE_ATTR_NAME];
const char *name = CustomData_get_layer_name(&psmd->mesh_final->ldata, CD_MLOOPCOL, i);
- GPU_vertformat_safe_attrib_name(name, attr_safe_name, GPU_MAX_SAFE_ATTRIB_NAME);
+ GPU_vertformat_safe_attr_name(name, attr_safe_name, GPU_MAX_SAFE_ATTR_NAME);
int n = 0;
BLI_snprintf(cache->col_layer_names[i][n++], MAX_LAYER_NAME_LEN, "c%s", attr_safe_name);
@@ -1164,9 +1166,9 @@ static void particle_batch_cache_ensure_pos_and_seg(PTCacheEdit *edit,
for (int i = 0; i < num_uv_layers; i++) {
- char uuid[32], attr_safe_name[GPU_MAX_SAFE_ATTRIB_NAME];
+ char uuid[32], attr_safe_name[GPU_MAX_SAFE_ATTR_NAME];
const char *name = CustomData_get_layer_name(&psmd->mesh_final->ldata, CD_MLOOPUV, i);
- GPU_vertformat_safe_attrib_name(name, attr_safe_name, GPU_MAX_SAFE_ATTRIB_NAME);
+ GPU_vertformat_safe_attr_name(name, attr_safe_name, GPU_MAX_SAFE_ATTR_NAME);
BLI_snprintf(uuid, sizeof(uuid), "u%s", attr_safe_name);
uv_id[i] = GPU_vertformat_attr_add(&format, uuid, GPU_COMP_F32, 2, GPU_FETCH_FLOAT);
@@ -1177,9 +1179,9 @@ static void particle_batch_cache_ensure_pos_and_seg(PTCacheEdit *edit,
}
for (int i = 0; i < num_col_layers; i++) {
- char uuid[32], attr_safe_name[GPU_MAX_SAFE_ATTRIB_NAME];
+ char uuid[32], attr_safe_name[GPU_MAX_SAFE_ATTR_NAME];
const char *name = CustomData_get_layer_name(&psmd->mesh_final->ldata, CD_MLOOPCOL, i);
- GPU_vertformat_safe_attrib_name(name, attr_safe_name, GPU_MAX_SAFE_ATTRIB_NAME);
+ GPU_vertformat_safe_attr_name(name, attr_safe_name, GPU_MAX_SAFE_ATTR_NAME);
BLI_snprintf(uuid, sizeof(uuid), "c%s", attr_safe_name);
col_id[i] = GPU_vertformat_attr_add(&format, uuid, GPU_COMP_U16, 4, GPU_FETCH_FLOAT);
diff --git a/source/blender/draw/intern/draw_cache_impl_pointcloud.c b/source/blender/draw/intern/draw_cache_impl_pointcloud.c
index 83757cb714a..53939b35285 100644
--- a/source/blender/draw/intern/draw_cache_impl_pointcloud.c
+++ b/source/blender/draw/intern/draw_cache_impl_pointcloud.c
@@ -134,7 +134,7 @@ static void pointcloud_batch_cache_ensure_pos(Object *ob, PointCloudBatchCache *
/* initialize vertex format */
pos_id = GPU_vertformat_attr_add(&format, "pointcloud_pos", GPU_COMP_F32, 3, GPU_FETCH_FLOAT);
radius_id = GPU_vertformat_attr_add(
- &format, "pointcloud_radius", GPU_COMP_F32, 3, GPU_FETCH_FLOAT);
+ &format, "pointcloud_radius", GPU_COMP_F32, 1, GPU_FETCH_FLOAT);
}
GPU_VERTBUF_DISCARD_SAFE(cache->pos);
diff --git a/source/blender/draw/intern/draw_cache_impl_volume.c b/source/blender/draw/intern/draw_cache_impl_volume.c
index cdac8b33fba..9c2c075ab4f 100644
--- a/source/blender/draw/intern/draw_cache_impl_volume.c
+++ b/source/blender/draw/intern/draw_cache_impl_volume.c
@@ -27,6 +27,7 @@
#include "MEM_guardedalloc.h"
+#include "BLI_listbase.h"
#include "BLI_math_base.h"
#include "BLI_math_vector.h"
#include "BLI_utildefines.h"
@@ -123,7 +124,7 @@ static void volume_batch_cache_clear(Volume *volume)
return;
}
- for (DRWVolumeGrid *grid = cache->grids.first; grid; grid = grid->next) {
+ LISTBASE_FOREACH (DRWVolumeGrid *, grid, &cache->grids) {
MEM_SAFE_FREE(grid->name);
DRW_TEXTURE_FREE_SAFE(grid->texture);
}
@@ -266,6 +267,7 @@ static DRWVolumeGrid *volume_grid_cache_get(Volume *volume,
GPU_texture_bind(cache_grid->texture, 0);
GPU_texture_swizzle_channel_auto(cache_grid->texture, channels);
+ GPU_texture_wrap_mode(cache_grid->texture, false, false);
GPU_texture_unbind(cache_grid->texture);
MEM_freeN(voxels);
diff --git a/source/blender/draw/intern/draw_common.h b/source/blender/draw/intern/draw_common.h
index f14cdc0dbde..656d72b2808 100644
--- a/source/blender/draw/intern/draw_common.h
+++ b/source/blender/draw/intern/draw_common.h
@@ -172,23 +172,11 @@ bool DRW_object_axis_orthogonal_to_view(Object *ob, int axis);
/* This creates a shading group with display hairs.
* The draw call is already added by this function, just add additional uniforms. */
-struct DRWShadingGroup *DRW_shgroup_hair_create(struct Object *object,
- struct ParticleSystem *psys,
- struct ModifierData *md,
- struct DRWPass *hair_pass,
- struct GPUShader *shader);
-
struct DRWShadingGroup *DRW_shgroup_hair_create_sub(struct Object *object,
struct ParticleSystem *psys,
struct ModifierData *md,
struct DRWShadingGroup *shgrp);
-struct DRWShadingGroup *DRW_shgroup_material_hair_create(struct Object *object,
- struct ParticleSystem *psys,
- struct ModifierData *md,
- struct DRWPass *hair_pass,
- struct GPUMaterial *material);
-
void DRW_hair_init(void);
void DRW_hair_update(void);
void DRW_hair_free(void);
diff --git a/source/blender/draw/intern/draw_hair.c b/source/blender/draw/intern/draw_hair.c
index 048adccc4e6..2fdaf0d5345 100644
--- a/source/blender/draw/intern/draw_hair.c
+++ b/source/blender/draw/intern/draw_hair.c
@@ -32,7 +32,7 @@
#include "DNA_modifier_types.h"
#include "DNA_particle_types.h"
-#include "BKE_anim.h"
+#include "BKE_duplilist.h"
#include "GPU_batch.h"
#include "GPU_shader.h"
@@ -89,6 +89,7 @@ static GPUShader *hair_refine_shader_get(ParticleRefineShader sh)
g_refine_shaders[sh] = DRW_shader_create(vert_with_lib,
NULL,
datatoc_gpu_shader_3D_smooth_color_frag_glsl,
+ "#define blender_srgb_to_framebuffer_space(a) a\n"
"#define HAIR_PHASE_SUBDIV\n"
"#define TF_WORKAROUND\n");
#endif
@@ -123,13 +124,10 @@ void DRW_hair_init(void)
}
}
-static DRWShadingGroup *drw_shgroup_create_hair_procedural_ex(Object *object,
- ParticleSystem *psys,
- ModifierData *md,
- DRWPass *hair_pass,
- DRWShadingGroup *shgrp_parent,
- struct GPUMaterial *gpu_mat,
- GPUShader *gpu_shader)
+DRWShadingGroup *DRW_shgroup_hair_create_sub(Object *object,
+ ParticleSystem *psys,
+ ModifierData *md,
+ DRWShadingGroup *shgrp_parent)
{
/* TODO(fclem): Pass the scene as parameter */
const DRWContextState *draw_ctx = DRW_context_state_get();
@@ -153,24 +151,7 @@ static DRWShadingGroup *drw_shgroup_create_hair_procedural_ex(Object *object,
need_ft_update = hair_ensure_procedural_data(object, &hair_cache, subdiv, thickness_res);
}
- DRWShadingGroup *shgrp;
- if (shgrp_parent) {
- shgrp = DRW_shgroup_create_sub(shgrp_parent);
- }
- else if (gpu_mat) {
- shgrp = DRW_shgroup_material_create(gpu_mat, hair_pass);
- }
- else if (gpu_shader) {
- shgrp = DRW_shgroup_create(gpu_shader, hair_pass);
- }
- else {
- shgrp = NULL;
- BLI_assert(0);
- }
-
- if (shgrp == NULL) {
- return NULL;
- }
+ DRWShadingGroup *shgrp = DRW_shgroup_create_sub(shgrp_parent);
/* TODO optimize this. Only bind the ones GPUMaterial needs. */
for (int i = 0; i < hair_cache->num_uv_layers; i++) {
@@ -239,10 +220,7 @@ static DRWShadingGroup *drw_shgroup_create_hair_procedural_ex(Object *object,
DRW_shgroup_uniform_int(shgrp, "hairStrandsRes", &hair_cache->final[subdiv].strands_res, 1);
DRW_shgroup_uniform_int_copy(shgrp, "hairThicknessRes", thickness_res);
DRW_shgroup_uniform_float_copy(shgrp, "hairRadShape", hair_rad_shape);
- DRW_shgroup_uniform_vec4_copy(shgrp, "hairDupliMatrix[0]", dupli_mat[0]);
- DRW_shgroup_uniform_vec4_copy(shgrp, "hairDupliMatrix[1]", dupli_mat[1]);
- DRW_shgroup_uniform_vec4_copy(shgrp, "hairDupliMatrix[2]", dupli_mat[2]);
- DRW_shgroup_uniform_vec4_copy(shgrp, "hairDupliMatrix[3]", dupli_mat[3]);
+ DRW_shgroup_uniform_vec4_array_copy(shgrp, "hairDupliMatrix", dupli_mat, 4);
DRW_shgroup_uniform_float_copy(shgrp, "hairRadRoot", hair_rad_root);
DRW_shgroup_uniform_float_copy(shgrp, "hairRadTip", hair_rad_tip);
DRW_shgroup_uniform_bool_copy(shgrp, "hairCloseTip", hair_close_tip);
@@ -286,29 +264,6 @@ static DRWShadingGroup *drw_shgroup_create_hair_procedural_ex(Object *object,
return shgrp;
}
-DRWShadingGroup *DRW_shgroup_hair_create(
- Object *object, ParticleSystem *psys, ModifierData *md, DRWPass *hair_pass, GPUShader *shader)
-{
- return drw_shgroup_create_hair_procedural_ex(object, psys, md, hair_pass, NULL, NULL, shader);
-}
-
-DRWShadingGroup *DRW_shgroup_hair_create_sub(Object *object,
- ParticleSystem *psys,
- ModifierData *md,
- DRWShadingGroup *shgrp)
-{
- return drw_shgroup_create_hair_procedural_ex(object, psys, md, NULL, shgrp, NULL, NULL);
-}
-
-DRWShadingGroup *DRW_shgroup_material_hair_create(Object *object,
- ParticleSystem *psys,
- ModifierData *md,
- DRWPass *hair_pass,
- struct GPUMaterial *material)
-{
- return drw_shgroup_create_hair_procedural_ex(object, psys, md, hair_pass, NULL, material, NULL);
-}
-
void DRW_hair_update(void)
{
#ifndef USE_TRANSFORM_FEEDBACK
diff --git a/source/blender/draw/intern/draw_hair_private.h b/source/blender/draw/intern/draw_hair_private.h
index 4d9eaf88a7d..b599ad389c1 100644
--- a/source/blender/draw/intern/draw_hair_private.h
+++ b/source/blender/draw/intern/draw_hair_private.h
@@ -25,7 +25,7 @@
#define __DRAW_HAIR_PRIVATE_H__
#define MAX_LAYER_NAME_CT 4 /* u0123456789, u, au, a0123456789 */
-#define MAX_LAYER_NAME_LEN GPU_MAX_SAFE_ATTRIB_NAME + 2
+#define MAX_LAYER_NAME_LEN GPU_MAX_SAFE_ATTR_NAME + 2
#define MAX_THICKRES 2 /* see eHairType */
#define MAX_HAIR_SUBDIV 4 /* see hair_subdiv rna */
diff --git a/source/blender/draw/intern/draw_manager.c b/source/blender/draw/intern/draw_manager.c
index cc618c76ccd..e7dff422105 100644
--- a/source/blender/draw/intern/draw_manager.c
+++ b/source/blender/draw/intern/draw_manager.c
@@ -27,14 +27,15 @@
#include "BLI_memblock.h"
#include "BLI_rect.h"
#include "BLI_string.h"
+#include "BLI_task.h"
#include "BLI_threads.h"
#include "BLF_api.h"
-#include "BKE_anim.h"
#include "BKE_colortools.h"
#include "BKE_context.h"
#include "BKE_curve.h"
+#include "BKE_duplilist.h"
#include "BKE_editmesh.h"
#include "BKE_global.h"
#include "BKE_gpencil.h"
@@ -63,11 +64,11 @@
#include "ED_space_api.h"
#include "ED_view3d.h"
-#include "GPU_draw.h"
#include "GPU_extensions.h"
#include "GPU_framebuffer.h"
#include "GPU_immediate.h"
#include "GPU_matrix.h"
+#include "GPU_state.h"
#include "GPU_uniformbuffer.h"
#include "GPU_viewport.h"
@@ -111,17 +112,6 @@ static ListBase DRW_engines = {NULL, NULL};
static void drw_state_prepare_clean_for_draw(DRWManager *dst)
{
memset(dst, 0x0, offsetof(DRWManager, gl_context));
-
- /* Maybe not the best place for this. */
- if (!DST.uniform_names.buffer) {
- DST.uniform_names.buffer = MEM_callocN(DRW_UNIFORM_BUFFER_NAME, "Name Buffer");
- DST.uniform_names.buffer_len = DRW_UNIFORM_BUFFER_NAME;
- }
- else if (DST.uniform_names.buffer_len > DRW_UNIFORM_BUFFER_NAME) {
- DST.uniform_names.buffer = MEM_reallocN(DST.uniform_names.buffer, DRW_UNIFORM_BUFFER_NAME);
- DST.uniform_names.buffer_len = DRW_UNIFORM_BUFFER_NAME;
- }
- DST.uniform_names.buffer_ofs = 0;
}
/* This function is used to reset draw manager to a state
@@ -136,6 +126,23 @@ static void drw_state_ensure_not_reused(DRWManager *dst)
#endif
/* -------------------------------------------------------------------- */
+/** \name Threading
+ * \{ */
+static void drw_task_graph_init(void)
+{
+ BLI_assert(DST.task_graph == NULL);
+ DST.task_graph = BLI_task_graph_create();
+}
+
+static void drw_task_graph_deinit(void)
+{
+ BLI_task_graph_work_and_wait(DST.task_graph);
+ BLI_task_graph_free(DST.task_graph);
+ DST.task_graph = NULL;
+}
+/* \} */
+
+/* -------------------------------------------------------------------- */
/** \name Settings
* \{ */
@@ -145,11 +152,8 @@ bool DRW_object_is_renderable(const Object *ob)
if (ob->type == OB_MESH) {
if ((ob == DST.draw_ctx.object_edit) || DRW_object_is_in_edit_mode(ob)) {
-
View3D *v3d = DST.draw_ctx.v3d;
- const int mask = (V3D_OVERLAY_EDIT_OCCLUDE_WIRE | V3D_OVERLAY_EDIT_WEIGHT);
-
- if (v3d && v3d->overlay.edit_flag & mask) {
+ if (v3d && v3d->overlay.edit_flag & V3D_OVERLAY_EDIT_OCCLUDE_WIRE) {
return false;
}
}
@@ -587,9 +591,6 @@ static void drw_viewport_var_init(void)
ED_view3d_init_mats_rv3d(DST.draw_ctx.object_edit, rv3d);
}
- /* Alloc array of texture reference. */
- memset(&DST.RST, 0x0, sizeof(DST.RST));
-
if (G_draw.view_ubo == NULL) {
G_draw.view_ubo = DRW_uniformbuffer_create(sizeof(DRWViewUboStorage), NULL);
}
@@ -693,8 +694,7 @@ void **DRW_duplidata_get(void *vedata)
void *DRW_view_layer_engine_data_get(DrawEngineType *engine_type)
{
- for (ViewLayerEngineData *sled = DST.draw_ctx.view_layer->drawdata.first; sled;
- sled = sled->next) {
+ LISTBASE_FOREACH (ViewLayerEngineData *, sled, &DST.draw_ctx.view_layer->drawdata) {
if (sled->engine_type == engine_type) {
return sled->storage;
}
@@ -925,7 +925,7 @@ void DRW_cache_free_old_batches(Main *bmain)
static void drw_engines_init(void)
{
- for (LinkData *link = DST.enabled_engines.first; link; link = link->next) {
+ LISTBASE_FOREACH (LinkData *, link, &DST.enabled_engines) {
DrawEngineType *engine = link->data;
ViewportEngineData *data = drw_viewport_engine_data_ensure(engine);
PROFILE_START(stime);
@@ -969,7 +969,7 @@ static void drw_engines_world_update(Scene *scene)
return;
}
- for (LinkData *link = DST.enabled_engines.first; link; link = link->next) {
+ LISTBASE_FOREACH (LinkData *, link, &DST.enabled_engines) {
DrawEngineType *engine = link->data;
ViewportEngineData *data = drw_viewport_engine_data_ensure(engine);
@@ -1035,7 +1035,7 @@ static void drw_engines_cache_finish(void)
static void drw_engines_draw_scene(void)
{
- for (LinkData *link = DST.enabled_engines.first; link; link = link->next) {
+ LISTBASE_FOREACH (LinkData *, link, &DST.enabled_engines) {
DrawEngineType *engine = link->data;
ViewportEngineData *data = drw_viewport_engine_data_ensure(engine);
PROFILE_START(stime);
@@ -1058,7 +1058,7 @@ static void drw_engines_draw_scene(void)
static void drw_engines_draw_text(void)
{
- for (LinkData *link = DST.enabled_engines.first; link; link = link->next) {
+ LISTBASE_FOREACH (LinkData *, link, &DST.enabled_engines) {
DrawEngineType *engine = link->data;
ViewportEngineData *data = drw_viewport_engine_data_ensure(engine);
PROFILE_START(stime);
@@ -1072,9 +1072,9 @@ static void drw_engines_draw_text(void)
}
/* Draw render engine info. */
-void DRW_draw_region_engine_info(int xoffset, int yoffset)
+void DRW_draw_region_engine_info(int xoffset, int *yoffset, int line_height)
{
- for (LinkData *link = DST.enabled_engines.first; link; link = link->next) {
+ LISTBASE_FOREACH (LinkData *, link, &DST.enabled_engines) {
DrawEngineType *engine = link->data;
ViewportEngineData *data = drw_viewport_engine_data_ensure(engine);
@@ -1095,8 +1095,8 @@ void DRW_draw_region_engine_info(int xoffset, int yoffset)
if (*chr_current == '\n') {
char info[GPU_INFO_SIZE];
BLI_strncpy(info, chr_start, line_len + 1);
- yoffset -= U.widget_unit;
- BLF_draw_default(xoffset, yoffset, 0.0f, info, sizeof(info));
+ *yoffset -= line_height;
+ BLF_draw_default(xoffset, *yoffset, 0.0f, info, sizeof(info));
/* Re-start counting. */
chr_start = chr_current + 1;
@@ -1106,8 +1106,8 @@ void DRW_draw_region_engine_info(int xoffset, int yoffset)
char info[GPU_INFO_SIZE];
BLI_strncpy(info, chr_start, line_len + 1);
- yoffset -= U.widget_unit;
- BLF_draw_default(xoffset, yoffset, 0.0f, info, sizeof(info));
+ *yoffset -= line_height;
+ BLF_draw_default(xoffset, *yoffset, 0.0f, info, sizeof(info));
BLF_disable(font_id, BLF_SHADOW);
}
@@ -1181,7 +1181,7 @@ static void drw_engines_data_validate(void)
void **engine_handle_array = BLI_array_alloca(engine_handle_array, enabled_engines + 1);
int i = 0;
- for (LinkData *link = DST.enabled_engines.first; link; link = link->next) {
+ LISTBASE_FOREACH (LinkData *, link, &DST.enabled_engines) {
DrawEngineType *engine = link->data;
engine_handle_array[i++] = engine;
}
@@ -1248,7 +1248,7 @@ void DRW_notify_view_update(const DRWUpdateContext *update_ctx)
drw_engines_enable(view_layer, engine_type, gpencil_engine_needed);
drw_engines_data_validate();
- for (LinkData *link = DST.enabled_engines.first; link; link = link->next) {
+ LISTBASE_FOREACH (LinkData *, link, &DST.enabled_engines) {
DrawEngineType *draw_engine = link->data;
ViewportEngineData *data = drw_viewport_engine_data_ensure(draw_engine);
@@ -1300,9 +1300,6 @@ void DRW_draw_callbacks_post_scene(void)
DRW_state_reset();
GPU_framebuffer_bind(dfbl->overlay_fb);
- /* Disable sRGB encoding from the fixed function pipeline since all the drawing in this
- * function is done with sRGB color. Avoid double transform. */
- glDisable(GL_FRAMEBUFFER_SRGB);
GPU_matrix_projection_set(rv3d->winmat);
GPU_matrix_set(rv3d->viewmat);
@@ -1431,6 +1428,7 @@ void DRW_draw_render_loop_ex(struct Depsgraph *depsgraph,
/* reuse if caller sets */
.evil_C = DST.draw_ctx.evil_C,
};
+ drw_task_graph_init();
drw_context_state_init();
drw_viewport_var_init();
@@ -1495,6 +1493,7 @@ void DRW_draw_render_loop_ex(struct Depsgraph *depsgraph,
#endif
}
+ drw_task_graph_deinit();
DRW_stats_begin();
GPU_framebuffer_bind(DST.default_framebuffer);
@@ -1514,6 +1513,8 @@ void DRW_draw_render_loop_ex(struct Depsgraph *depsgraph,
/* Fix 3D view being "laggy" on macos and win+nvidia. (See T56996, T61474) */
GPU_flush();
+ DRW_stats_reset();
+
DRW_draw_callbacks_post_scene();
if (WM_draw_region_get_bound_viewport(region)) {
@@ -1773,7 +1774,6 @@ void DRW_render_to_image(RenderEngine *engine, struct Depsgraph *depsgraph)
DST.options.is_image_render = true;
DST.options.is_scene_render = true;
DST.options.draw_background = scene->r.alphamode == R_ADDSKY;
-
DST.draw_ctx = (DRWContextState){
.scene = scene,
.view_layer = view_layer,
@@ -1858,9 +1858,9 @@ void DRW_render_object_iter(
void (*callback)(void *vedata, Object *ob, RenderEngine *engine, struct Depsgraph *depsgraph))
{
const DRWContextState *draw_ctx = DRW_context_state_get();
-
DRW_hair_init();
+ drw_task_graph_init();
const int object_type_exclude_viewport = draw_ctx->v3d ?
draw_ctx->v3d->object_type_exclude_viewport :
0;
@@ -1883,6 +1883,7 @@ void DRW_render_object_iter(
DEG_OBJECT_ITER_FOR_RENDER_ENGINE_END;
drw_duplidata_free();
+ drw_task_graph_deinit();
}
/* Assume a valid gl context is bound (and that the gl_context_mutex has been acquired).
@@ -2032,7 +2033,7 @@ void DRW_draw_select_loop(struct Depsgraph *depsgraph,
Object *obweight = OBWEIGHTPAINT_FROM_OBACT(obact);
if (obweight) {
/* Only use Armature pose selection, when connected armature is in pose mode. */
- Object *ob_armature = modifiers_isDeformedByArmature(obweight);
+ Object *ob_armature = BKE_modifiers_is_deformed_by_armature(obweight);
if (ob_armature && ob_armature->mode == OB_MODE_POSE) {
obpose = ob_armature;
}
@@ -2054,14 +2055,16 @@ void DRW_draw_select_loop(struct Depsgraph *depsgraph,
DST.viewport = viewport;
DST.options.is_select = true;
-
+ drw_task_graph_init();
/* Get list of enabled engines */
if (use_obedit) {
drw_engines_enable_overlays();
}
else if (!draw_surface) {
/* grease pencil selection */
- use_drw_engine(&draw_engine_gpencil_type);
+ if (drw_gpencil_engine_needed(depsgraph, v3d)) {
+ use_drw_engine(&draw_engine_gpencil_type);
+ }
drw_engines_enable_overlays();
}
@@ -2069,7 +2072,9 @@ void DRW_draw_select_loop(struct Depsgraph *depsgraph,
/* Draw surface for occlusion. */
drw_engines_enable_basic();
/* grease pencil selection */
- use_drw_engine(&draw_engine_gpencil_type);
+ if (drw_gpencil_engine_needed(depsgraph, v3d)) {
+ use_drw_engine(&draw_engine_gpencil_type);
+ }
drw_engines_enable_overlays();
}
@@ -2160,6 +2165,7 @@ void DRW_draw_select_loop(struct Depsgraph *depsgraph,
}
drw_duplidata_free();
+ drw_task_graph_deinit();
drw_engines_cache_finish();
DRW_render_instance_buffer_finish();
@@ -2240,7 +2246,7 @@ static void drw_draw_depth_loop_imp(struct Depsgraph *depsgraph,
.engine_type = engine_type,
.depsgraph = depsgraph,
};
-
+ drw_task_graph_init();
drw_engines_data_validate();
/* Setup framebuffer */
@@ -2284,6 +2290,7 @@ static void drw_draw_depth_loop_imp(struct Depsgraph *depsgraph,
DRW_render_instance_buffer_finish();
}
+ drw_task_graph_deinit();
/* Start Drawing */
DRW_state_reset();
@@ -2373,7 +2380,7 @@ void DRW_draw_select_id(Depsgraph *depsgraph, ARegion *region, View3D *v3d, cons
.obact = OBACT(view_layer),
.depsgraph = depsgraph,
};
-
+ drw_task_graph_init();
drw_context_state_init();
/* Setup viewport */
@@ -2408,6 +2415,7 @@ void DRW_draw_select_id(Depsgraph *depsgraph, ARegion *region, View3D *v3d, cons
drw_resource_buffer_finish(DST.vmempool);
#endif
}
+ drw_task_graph_deinit();
/* Start Drawing */
DRW_state_reset();
@@ -2433,7 +2441,8 @@ static void draw_world_clip_planes_from_rv3d(GPUBatch *batch, const float world_
/**
* Clears the Depth Buffer and draws only the specified object.
*/
-void DRW_draw_depth_object(ARegion *region, View3D *v3d, GPUViewport *viewport, Object *object)
+void DRW_draw_depth_object(
+ Scene *scene, ARegion *region, View3D *v3d, GPUViewport *viewport, Object *object)
{
RegionView3D *rv3d = region->regiondata;
@@ -2470,8 +2479,10 @@ void DRW_draw_depth_object(ARegion *region, View3D *v3d, GPUViewport *viewport,
else {
batch = DRW_mesh_batch_cache_get_surface(me);
}
-
- DRW_mesh_batch_cache_create_requested(object, me, NULL, false, true);
+ struct TaskGraph *task_graph = BLI_task_graph_create();
+ DRW_mesh_batch_cache_create_requested(task_graph, object, me, scene, false, true);
+ BLI_task_graph_work_and_wait(task_graph);
+ BLI_task_graph_free(task_graph);
const eGPUShaderConfig sh_cfg = world_clip_planes ? GPU_SHADER_CFG_CLIPPED :
GPU_SHADER_CFG_DEFAULT;
@@ -2575,6 +2586,15 @@ bool DRW_state_is_playback(void)
}
/**
+ * Is the user navigating the region.
+ */
+bool DRW_state_is_navigating(void)
+{
+ const RegionView3D *rv3d = DST.draw_ctx.rv3d;
+ return (rv3d) && (rv3d->rflag & (RV3D_NAVIGATING | RV3D_PAINTING));
+}
+
+/**
* Should text draw in this mode?
*/
bool DRW_state_show_text(void)
@@ -2705,8 +2725,6 @@ void DRW_engines_free(void)
DRW_TEXTURE_FREE_SAFE(G_draw.ramp);
DRW_TEXTURE_FREE_SAFE(G_draw.weight_ramp);
- MEM_SAFE_FREE(DST.uniform_names.buffer);
-
if (DST.draw_list) {
GPU_draw_list_discard(DST.draw_list);
}
diff --git a/source/blender/draw/intern/draw_manager.h b/source/blender/draw/intern/draw_manager.h
index df7f0597017..6cae2a4f9f6 100644
--- a/source/blender/draw/intern/draw_manager.h
+++ b/source/blender/draw/intern/draw_manager.h
@@ -31,6 +31,7 @@
#include "BLI_assert.h"
#include "BLI_linklist.h"
#include "BLI_memblock.h"
+#include "BLI_task.h"
#include "BLI_threads.h"
#include "GPU_batch.h"
@@ -210,7 +211,7 @@ typedef struct DRWCommandDrawInstance {
GPUBatch *batch;
DRWResourceHandle handle;
uint inst_count;
- uint use_attribs; /* bool */
+ uint use_attrs; /* bool */
} DRWCommandDrawInstance;
typedef struct DRWCommandDrawInstanceRange {
@@ -276,10 +277,9 @@ typedef enum {
DRW_UNIFORM_FLOAT,
DRW_UNIFORM_FLOAT_COPY,
DRW_UNIFORM_TEXTURE,
- DRW_UNIFORM_TEXTURE_PERSIST,
DRW_UNIFORM_TEXTURE_REF,
DRW_UNIFORM_BLOCK,
- DRW_UNIFORM_BLOCK_PERSIST,
+ DRW_UNIFORM_BLOCK_REF,
DRW_UNIFORM_TFEEDBACK_TARGET,
/** Per drawcall uniforms/UBO */
DRW_UNIFORM_BLOCK_OBMATS,
@@ -290,7 +290,6 @@ typedef enum {
DRW_UNIFORM_BASE_INSTANCE,
DRW_UNIFORM_MODEL_MATRIX,
DRW_UNIFORM_MODEL_MATRIX_INVERSE,
- DRW_UNIFORM_MODELVIEWPROJECTION_MATRIX,
/* WARNING: set DRWUniform->type
* bit length accordingly. */
} DRWUniformType;
@@ -299,15 +298,28 @@ struct DRWUniform {
union {
/* For reference or array/vector types. */
const void *pvalue;
- /* Single values. */
+ /* DRW_UNIFORM_TEXTURE */
+ struct {
+ union {
+ GPUTexture *texture;
+ GPUTexture **texture_ref;
+ };
+ eGPUSamplerState sampler_state;
+ };
+ /* DRW_UNIFORM_BLOCK */
+ union {
+ GPUUniformBuffer *block;
+ GPUUniformBuffer **block_ref;
+ };
+ /* DRW_UNIFORM_FLOAT_COPY */
float fvalue[4];
+ /* DRW_UNIFORM_INT_COPY */
int ivalue[4];
};
- int location;
- uint32_t type : 5; /* DRWUniformType */
- uint32_t length : 5; /* cannot be more than 16 */
- uint32_t arraysize : 5; /* cannot be more than 16 too */
- uint32_t name_ofs : 17; /* name offset in name buffer. */
+ int location; /* Uniform location or binding point for textures and ubos. */
+ uint8_t type; /* DRWUniformType */
+ uint8_t length; /* Length of vector types. */
+ uint8_t arraysize; /* Array size of scalar/vector types. */
};
struct DRWShadingGroup {
@@ -322,10 +334,13 @@ struct DRWShadingGroup {
} cmd;
union {
+ /* This struct is used during cache populate. */
struct {
int objectinfo; /* Equal to 1 if the shader needs obinfos. */
DRWResourceHandle pass_handle; /* Memblock key to parent pass. */
};
+ /* This struct is used after cache populate if using the Z sorting.
+ * It will not conflict with the above struct. */
struct {
float distance; /* Distance from camera. */
uint original_index; /* Original position inside the shgroup list. */
@@ -342,6 +357,13 @@ struct DRWPass {
DRWShadingGroup *last;
} shgroups;
+ /* Draw the shgroups of this pass instead.
+ * This avoid duplicating drawcalls/shgroups
+ * for similar passes. */
+ DRWPass *original;
+ /* Link list of additional passes to render. */
+ DRWPass *next;
+
DRWResourceHandle handle;
DRWState state;
char name[MAX_PASS_NAME];
@@ -525,6 +547,8 @@ typedef struct DRWManager {
uint select_id;
#endif
+ struct TaskGraph *task_graph;
+
/* ---------- Nothing after this point is cleared after use ----------- */
/* gl_context serves as the offset for clearing only
@@ -537,31 +561,11 @@ typedef struct DRWManager {
GPUDrawList *draw_list;
- /** GPU Resource State: Memory storage between drawing. */
- struct {
- /* High end GPUs supports up to 32 binds per shader stage.
- * We only use textures during the vertex and fragment stage,
- * so 2 * 32 slots is a nice limit. */
- GPUTexture *bound_texs[DST_MAX_SLOTS];
- uint64_t bound_tex_slots;
- uint64_t bound_tex_slots_persist;
-
- GPUUniformBuffer *bound_ubos[DST_MAX_SLOTS];
- uint64_t bound_ubo_slots;
- uint64_t bound_ubo_slots_persist;
- } RST;
-
struct {
/* TODO(fclem) optimize: use chunks. */
DRWDebugLine *lines;
DRWDebugSphere *spheres;
} debug;
-
- struct {
- char *buffer;
- uint buffer_len;
- uint buffer_ofs;
- } uniform_names;
} DRWManager;
extern DRWManager DST; /* TODO: get rid of this and allow multi-threaded rendering. */
diff --git a/source/blender/draw/intern/draw_manager_data.c b/source/blender/draw/intern/draw_manager_data.c
index 94a3e9e8343..ea67dd87772 100644
--- a/source/blender/draw/intern/draw_manager_data.c
+++ b/source/blender/draw/intern/draw_manager_data.c
@@ -22,8 +22,8 @@
#include "draw_manager.h"
-#include "BKE_anim.h"
#include "BKE_curve.h"
+#include "BKE_duplilist.h"
#include "BKE_global.h"
#include "BKE_image.h"
#include "BKE_mesh.h"
@@ -38,6 +38,7 @@
#include "BLI_alloca.h"
#include "BLI_hash.h"
#include "BLI_link_utils.h"
+#include "BLI_listbase.h"
#include "BLI_memblock.h"
#include "BLI_mempool.h"
@@ -169,13 +170,20 @@ void drw_resource_buffer_finish(ViewportMemoryPool *vmempool)
/** \name Uniforms (DRW_shgroup_uniform)
* \{ */
-static DRWUniform *drw_shgroup_uniform_create_ex(DRWShadingGroup *shgroup,
- int loc,
- DRWUniformType type,
- const void *value,
- int length,
- int arraysize)
+static void drw_shgroup_uniform_create_ex(DRWShadingGroup *shgroup,
+ int loc,
+ DRWUniformType type,
+ const void *value,
+ eGPUSamplerState sampler_state,
+ int length,
+ int arraysize)
{
+ if (loc == -1) {
+ /* Nice to enable eventually, for now eevee uses uniforms that might not exist. */
+ // BLI_assert(0);
+ return;
+ }
+
DRWUniformChunk *unichunk = shgroup->uniforms;
/* Happens on first uniform or if chunk is full. */
if (!unichunk || unichunk->uniform_used == unichunk->uniform_len) {
@@ -201,22 +209,24 @@ static DRWUniform *drw_shgroup_uniform_create_ex(DRWShadingGroup *shgroup,
BLI_assert(length <= 4);
memcpy(uni->fvalue, value, sizeof(float) * length);
break;
+ case DRW_UNIFORM_BLOCK:
+ uni->block = (GPUUniformBuffer *)value;
+ break;
+ case DRW_UNIFORM_BLOCK_REF:
+ uni->block_ref = (GPUUniformBuffer **)value;
+ break;
+ case DRW_UNIFORM_TEXTURE:
+ uni->texture = (GPUTexture *)value;
+ uni->sampler_state = sampler_state;
+ break;
+ case DRW_UNIFORM_TEXTURE_REF:
+ uni->texture_ref = (GPUTexture **)value;
+ uni->sampler_state = sampler_state;
+ break;
default:
uni->pvalue = (const float *)value;
break;
}
-
- return uni;
-}
-
-static void drw_shgroup_builtin_uniform(
- DRWShadingGroup *shgroup, int builtin, const void *value, int length, int arraysize)
-{
- int loc = GPU_shader_get_builtin_uniform(shgroup->shader, builtin);
-
- if (loc != -1) {
- drw_shgroup_uniform_create_ex(shgroup, loc, DRW_UNIFORM_FLOAT, value, length, arraysize);
- }
}
static void drw_shgroup_uniform(DRWShadingGroup *shgroup,
@@ -226,61 +236,29 @@ static void drw_shgroup_uniform(DRWShadingGroup *shgroup,
int length,
int arraysize)
{
- int location;
- if (ELEM(type, DRW_UNIFORM_BLOCK, DRW_UNIFORM_BLOCK_PERSIST)) {
- location = GPU_shader_get_uniform_block(shgroup->shader, name);
- }
- else {
- location = GPU_shader_get_uniform(shgroup->shader, name);
- }
-
- if (location == -1) {
- /* Nice to enable eventually, for now eevee uses uniforms that might not exist. */
- // BLI_assert(0);
- return;
- }
-
BLI_assert(arraysize > 0 && arraysize <= 16);
BLI_assert(length >= 0 && length <= 16);
-
- DRWUniform *uni = drw_shgroup_uniform_create_ex(
- shgroup, location, type, value, length, arraysize);
-
- /* If location is -2, the uniform has not yet been queried.
- * We save the name for query just before drawing. */
- if (location == -2 || DRW_DEBUG_USE_UNIFORM_NAME) {
- int ofs = DST.uniform_names.buffer_ofs;
- int max_len = DST.uniform_names.buffer_len - ofs;
- size_t len = strlen(name) + 1;
-
- if (len >= max_len) {
- DST.uniform_names.buffer_len += MAX2(DST.uniform_names.buffer_len, len);
- DST.uniform_names.buffer = MEM_reallocN(DST.uniform_names.buffer,
- DST.uniform_names.buffer_len);
- }
-
- char *dst = DST.uniform_names.buffer + ofs;
- memcpy(dst, name, len); /* Copies NULL terminator. */
-
- DST.uniform_names.buffer_ofs += len;
- uni->name_ofs = ofs;
- }
+ BLI_assert(!ELEM(type,
+ DRW_UNIFORM_BLOCK,
+ DRW_UNIFORM_BLOCK_REF,
+ DRW_UNIFORM_TEXTURE,
+ DRW_UNIFORM_TEXTURE_REF));
+ int location = GPU_shader_get_uniform(shgroup->shader, name);
+ drw_shgroup_uniform_create_ex(shgroup, location, type, value, 0, length, arraysize);
}
void DRW_shgroup_uniform_texture(DRWShadingGroup *shgroup, const char *name, const GPUTexture *tex)
{
BLI_assert(tex != NULL);
- drw_shgroup_uniform(shgroup, name, DRW_UNIFORM_TEXTURE, tex, 0, 1);
+ int loc = GPU_shader_get_texture_binding(shgroup->shader, name);
+ drw_shgroup_uniform_create_ex(shgroup, loc, DRW_UNIFORM_TEXTURE, tex, GPU_SAMPLER_MAX, 0, 1);
}
-/* Same as DRW_shgroup_uniform_texture but is guaranteed to be bound if shader does not change
- * between shgrp. */
-void DRW_shgroup_uniform_texture_persistent(DRWShadingGroup *shgroup,
- const char *name,
- const GPUTexture *tex)
+void DRW_shgroup_uniform_texture_ref(DRWShadingGroup *shgroup, const char *name, GPUTexture **tex)
{
BLI_assert(tex != NULL);
- drw_shgroup_uniform(shgroup, name, DRW_UNIFORM_TEXTURE_PERSIST, tex, 0, 1);
+ int loc = GPU_shader_get_texture_binding(shgroup->shader, name);
+ drw_shgroup_uniform_create_ex(shgroup, loc, DRW_UNIFORM_TEXTURE_REF, tex, GPU_SAMPLER_MAX, 0, 1);
}
void DRW_shgroup_uniform_block(DRWShadingGroup *shgroup,
@@ -288,22 +266,17 @@ void DRW_shgroup_uniform_block(DRWShadingGroup *shgroup,
const GPUUniformBuffer *ubo)
{
BLI_assert(ubo != NULL);
- drw_shgroup_uniform(shgroup, name, DRW_UNIFORM_BLOCK, ubo, 0, 1);
+ int loc = GPU_shader_get_uniform_block_binding(shgroup->shader, name);
+ drw_shgroup_uniform_create_ex(shgroup, loc, DRW_UNIFORM_BLOCK, ubo, 0, 0, 1);
}
-/* Same as DRW_shgroup_uniform_block but is guaranteed to be bound if shader does not change
- * between shgrp. */
-void DRW_shgroup_uniform_block_persistent(DRWShadingGroup *shgroup,
- const char *name,
- const GPUUniformBuffer *ubo)
+void DRW_shgroup_uniform_block_ref(DRWShadingGroup *shgroup,
+ const char *name,
+ GPUUniformBuffer **ubo)
{
BLI_assert(ubo != NULL);
- drw_shgroup_uniform(shgroup, name, DRW_UNIFORM_BLOCK_PERSIST, ubo, 0, 1);
-}
-
-void DRW_shgroup_uniform_texture_ref(DRWShadingGroup *shgroup, const char *name, GPUTexture **tex)
-{
- drw_shgroup_uniform(shgroup, name, DRW_UNIFORM_TEXTURE_REF, tex, 0, 1);
+ int loc = GPU_shader_get_uniform_block_binding(shgroup->shader, name);
+ drw_shgroup_uniform_create_ex(shgroup, loc, DRW_UNIFORM_BLOCK_REF, ubo, 0, 0, 1);
}
void DRW_shgroup_uniform_bool(DRWShadingGroup *shgroup,
@@ -435,6 +408,25 @@ void DRW_shgroup_uniform_vec4_copy(DRWShadingGroup *shgroup, const char *name, c
drw_shgroup_uniform(shgroup, name, DRW_UNIFORM_FLOAT_COPY, value, 4, 1);
}
+void DRW_shgroup_uniform_vec4_array_copy(DRWShadingGroup *shgroup,
+ const char *name,
+ const float (*value)[4],
+ int arraysize)
+{
+ int location = GPU_shader_get_uniform(shgroup->shader, name);
+
+ if (location == -1) {
+ /* Nice to enable eventually, for now eevee uses uniforms that might not exist. */
+ // BLI_assert(0);
+ return;
+ }
+
+ for (int i = 0; i < arraysize; i++) {
+ drw_shgroup_uniform_create_ex(
+ shgroup, location + i, DRW_UNIFORM_FLOAT_COPY, &value[i], 0, 4, 1);
+ }
+}
+
/** \} */
/* -------------------------------------------------------------------- */
@@ -657,17 +649,14 @@ static void drw_command_draw_range(
cmd->vert_count = count;
}
-static void drw_command_draw_instance(DRWShadingGroup *shgroup,
- GPUBatch *batch,
- DRWResourceHandle handle,
- uint count,
- bool use_attrib)
+static void drw_command_draw_instance(
+ DRWShadingGroup *shgroup, GPUBatch *batch, DRWResourceHandle handle, uint count, bool use_attr)
{
DRWCommandDrawInstance *cmd = drw_command_create(shgroup, DRW_CMD_DRAW_INSTANCE);
cmd->batch = batch;
cmd->handle = handle;
cmd->inst_count = count;
- cmd->use_attribs = use_attrib;
+ cmd->use_attrs = use_attr;
}
static void drw_command_draw_intance_range(
@@ -841,10 +830,10 @@ void DRW_shgroup_call_instances(DRWShadingGroup *shgroup,
drw_command_draw_instance(shgroup, geom, handle, count, false);
}
-void DRW_shgroup_call_instances_with_attribs(DRWShadingGroup *shgroup,
- Object *ob,
- struct GPUBatch *geom,
- struct GPUBatch *inst_attributes)
+void DRW_shgroup_call_instances_with_attrs(DRWShadingGroup *shgroup,
+ Object *ob,
+ struct GPUBatch *geom,
+ struct GPUBatch *inst_attributes)
{
BLI_assert(geom != NULL);
BLI_assert(inst_attributes != NULL);
@@ -860,6 +849,7 @@ void DRW_shgroup_call_instances_with_attribs(DRWShadingGroup *shgroup,
typedef struct DRWSculptCallbackData {
Object *ob;
DRWShadingGroup **shading_groups;
+ int num_shading_groups;
bool use_wire;
bool use_mats;
bool use_mask;
@@ -884,7 +874,11 @@ static float sculpt_debug_colors[9][4] = {
static void sculpt_draw_cb(DRWSculptCallbackData *scd, GPU_PBVH_Buffers *buffers)
{
+ if (!buffers) {
+ return;
+ }
+ /* Meh... use_mask is a bit misleading here. */
if (scd->use_mask && !GPU_pbvh_buffers_has_overlays(buffers)) {
return;
}
@@ -894,6 +888,9 @@ static void sculpt_draw_cb(DRWSculptCallbackData *scd, GPU_PBVH_Buffers *buffers
if (scd->use_mats) {
index = GPU_pbvh_buffers_material_index_get(buffers);
+ if (index >= scd->num_shading_groups) {
+ index = 0;
+ }
}
DRWShadingGroup *shgrp = scd->shading_groups[index];
@@ -948,7 +945,7 @@ static void drw_sculpt_get_frustum_planes(Object *ob, float planes[6][4])
}
}
-static void drw_sculpt_generate_calls(DRWSculptCallbackData *scd, bool use_vcol)
+static void drw_sculpt_generate_calls(DRWSculptCallbackData *scd)
{
/* PBVH should always exist for non-empty meshes, created by depsgrah eval. */
PBVH *pbvh = (scd->ob->sculpt) ? scd->ob->sculpt->pbvh : NULL;
@@ -958,32 +955,60 @@ static void drw_sculpt_generate_calls(DRWSculptCallbackData *scd, bool use_vcol)
const DRWContextState *drwctx = DRW_context_state_get();
RegionView3D *rv3d = drwctx->rv3d;
+ const bool navigating = rv3d && (rv3d->rflag & RV3D_NAVIGATING);
+
+ Paint *p = NULL;
+ if (drwctx->evil_C != NULL) {
+ p = BKE_paint_get_active_from_context(drwctx->evil_C);
+ }
/* Frustum planes to show only visible PBVH nodes. */
- float planes[6][4];
- drw_sculpt_get_frustum_planes(scd->ob, planes);
- PBVHFrustumPlanes frustum = {.planes = planes, .num_planes = 6};
+ float update_planes[6][4];
+ float draw_planes[6][4];
+ PBVHFrustumPlanes update_frustum;
+ PBVHFrustumPlanes draw_frustum;
+
+ if (p && (p->flags & PAINT_SCULPT_DELAY_UPDATES)) {
+ update_frustum.planes = update_planes;
+ update_frustum.num_planes = 6;
+ BKE_pbvh_get_frustum_planes(pbvh, &update_frustum);
+ if (!navigating) {
+ drw_sculpt_get_frustum_planes(scd->ob, update_planes);
+ update_frustum.planes = update_planes;
+ update_frustum.num_planes = 6;
+ BKE_pbvh_set_frustum_planes(pbvh, &update_frustum);
+ }
+ }
+ else {
+ drw_sculpt_get_frustum_planes(scd->ob, update_planes);
+ update_frustum.planes = update_planes;
+ update_frustum.num_planes = 6;
+ }
+
+ drw_sculpt_get_frustum_planes(scd->ob, draw_planes);
+ draw_frustum.planes = draw_planes;
+ draw_frustum.num_planes = 6;
/* Fast mode to show low poly multires while navigating. */
scd->fast_mode = false;
- if (drwctx->evil_C != NULL) {
- Paint *p = BKE_paint_get_active_from_context(drwctx->evil_C);
- if (p && (p->flags & PAINT_FAST_NAVIGATE)) {
- scd->fast_mode = rv3d && (rv3d->rflag & RV3D_NAVIGATING);
- }
+ if (p && (p->flags & PAINT_FAST_NAVIGATE)) {
+ scd->fast_mode = rv3d && (rv3d->rflag & RV3D_NAVIGATING);
}
/* Update draw buffers only for visible nodes while painting.
* But do update them otherwise so navigating stays smooth. */
- const bool update_only_visible = rv3d && (rv3d->rflag & RV3D_PAINTING);
+ bool update_only_visible = rv3d && !(rv3d->rflag & RV3D_PAINTING);
+ if (p && (p->flags & PAINT_SCULPT_DELAY_UPDATES)) {
+ update_only_visible = true;
+ }
Mesh *mesh = scd->ob->data;
BKE_pbvh_update_normals(pbvh, mesh->runtime.subdiv_ccg);
BKE_pbvh_draw_cb(pbvh,
- use_vcol,
update_only_visible,
- &frustum,
+ &update_frustum,
+ &draw_frustum,
(void (*)(void *, GPU_PBVH_Buffers *))sculpt_draw_cb,
scd);
@@ -998,29 +1023,32 @@ static void drw_sculpt_generate_calls(DRWSculptCallbackData *scd, bool use_vcol)
}
}
-void DRW_shgroup_call_sculpt(
- DRWShadingGroup *shgroup, Object *ob, bool use_wire, bool use_mask, bool use_vcol)
+void DRW_shgroup_call_sculpt(DRWShadingGroup *shgroup, Object *ob, bool use_wire, bool use_mask)
{
DRWSculptCallbackData scd = {
.ob = ob,
.shading_groups = &shgroup,
+ .num_shading_groups = 1,
.use_wire = use_wire,
.use_mats = false,
.use_mask = use_mask,
};
- drw_sculpt_generate_calls(&scd, use_vcol);
+ drw_sculpt_generate_calls(&scd);
}
-void DRW_shgroup_call_sculpt_with_materials(DRWShadingGroup **shgroups, Object *ob, bool use_vcol)
+void DRW_shgroup_call_sculpt_with_materials(DRWShadingGroup **shgroups,
+ int num_shgroups,
+ Object *ob)
{
DRWSculptCallbackData scd = {
.ob = ob,
.shading_groups = shgroups,
+ .num_shading_groups = num_shgroups,
.use_wire = false,
.use_mats = true,
.use_mask = false,
};
- drw_sculpt_generate_calls(&scd, use_vcol);
+ drw_sculpt_generate_calls(&scd);
}
static GPUVertFormat inst_select_format = {0};
@@ -1140,53 +1168,49 @@ static void drw_shgroup_init(DRWShadingGroup *shgroup, GPUShader *shader)
{
shgroup->uniforms = NULL;
- /* TODO(fclem) make them builtin. */
- int view_ubo_location = GPU_shader_get_uniform_block(shader, "viewBlock");
- int model_ubo_location = GPU_shader_get_uniform_block(shader, "modelBlock");
- int info_ubo_location = GPU_shader_get_uniform_block(shader, "infoBlock");
+ int view_ubo_location = GPU_shader_get_builtin_block(shader, GPU_UNIFORM_BLOCK_VIEW);
+ int model_ubo_location = GPU_shader_get_builtin_block(shader, GPU_UNIFORM_BLOCK_MODEL);
+ int info_ubo_location = GPU_shader_get_builtin_block(shader, GPU_UNIFORM_BLOCK_INFO);
int baseinst_location = GPU_shader_get_builtin_uniform(shader, GPU_UNIFORM_BASE_INSTANCE);
int chunkid_location = GPU_shader_get_builtin_uniform(shader, GPU_UNIFORM_RESOURCE_CHUNK);
int resourceid_location = GPU_shader_get_builtin_uniform(shader, GPU_UNIFORM_RESOURCE_ID);
if (chunkid_location != -1) {
drw_shgroup_uniform_create_ex(
- shgroup, chunkid_location, DRW_UNIFORM_RESOURCE_CHUNK, NULL, 0, 1);
+ shgroup, chunkid_location, DRW_UNIFORM_RESOURCE_CHUNK, NULL, 0, 0, 1);
}
if (resourceid_location != -1) {
drw_shgroup_uniform_create_ex(
- shgroup, resourceid_location, DRW_UNIFORM_RESOURCE_ID, NULL, 0, 1);
+ shgroup, resourceid_location, DRW_UNIFORM_RESOURCE_ID, NULL, 0, 0, 1);
}
if (baseinst_location != -1) {
drw_shgroup_uniform_create_ex(
- shgroup, baseinst_location, DRW_UNIFORM_BASE_INSTANCE, NULL, 0, 1);
+ shgroup, baseinst_location, DRW_UNIFORM_BASE_INSTANCE, NULL, 0, 0, 1);
}
if (model_ubo_location != -1) {
drw_shgroup_uniform_create_ex(
- shgroup, model_ubo_location, DRW_UNIFORM_BLOCK_OBMATS, NULL, 0, 1);
+ shgroup, model_ubo_location, DRW_UNIFORM_BLOCK_OBMATS, NULL, 0, 0, 1);
}
else {
+ /* Note: This is only here to support old hardware fallback where uniform buffer is still
+ * too slow or buggy. */
int model = GPU_shader_get_builtin_uniform(shader, GPU_UNIFORM_MODEL);
int modelinverse = GPU_shader_get_builtin_uniform(shader, GPU_UNIFORM_MODEL_INV);
- int modelviewprojection = GPU_shader_get_builtin_uniform(shader, GPU_UNIFORM_MVP);
if (model != -1) {
- drw_shgroup_uniform_create_ex(shgroup, model, DRW_UNIFORM_MODEL_MATRIX, NULL, 0, 1);
+ drw_shgroup_uniform_create_ex(shgroup, model, DRW_UNIFORM_MODEL_MATRIX, NULL, 0, 0, 1);
}
if (modelinverse != -1) {
drw_shgroup_uniform_create_ex(
- shgroup, modelinverse, DRW_UNIFORM_MODEL_MATRIX_INVERSE, NULL, 0, 1);
- }
- if (modelviewprojection != -1) {
- drw_shgroup_uniform_create_ex(
- shgroup, modelviewprojection, DRW_UNIFORM_MODELVIEWPROJECTION_MATRIX, NULL, 0, 1);
+ shgroup, modelinverse, DRW_UNIFORM_MODEL_MATRIX_INVERSE, NULL, 0, 0, 1);
}
}
if (info_ubo_location != -1) {
drw_shgroup_uniform_create_ex(
- shgroup, info_ubo_location, DRW_UNIFORM_BLOCK_OBINFOS, NULL, 0, 1);
+ shgroup, info_ubo_location, DRW_UNIFORM_BLOCK_OBINFOS, NULL, 0, 0, 1);
/* Abusing this loc to tell shgroup we need the obinfos. */
shgroup->objectinfo = 1;
@@ -1197,25 +1221,21 @@ static void drw_shgroup_init(DRWShadingGroup *shgroup, GPUShader *shader)
if (view_ubo_location != -1) {
drw_shgroup_uniform_create_ex(
- shgroup, view_ubo_location, DRW_UNIFORM_BLOCK_PERSIST, G_draw.view_ubo, 0, 1);
- }
- else {
- /* Only here to support builtin shaders. This should not be used by engines. */
- /* TODO remove. */
- DRWViewUboStorage *storage = &DST.view_storage_cpy;
- drw_shgroup_builtin_uniform(shgroup, GPU_UNIFORM_VIEW, storage->viewmat, 16, 1);
- drw_shgroup_builtin_uniform(shgroup, GPU_UNIFORM_VIEW_INV, storage->viewinv, 16, 1);
- drw_shgroup_builtin_uniform(shgroup, GPU_UNIFORM_VIEWPROJECTION, storage->persmat, 16, 1);
- drw_shgroup_builtin_uniform(shgroup, GPU_UNIFORM_VIEWPROJECTION_INV, storage->persinv, 16, 1);
- drw_shgroup_builtin_uniform(shgroup, GPU_UNIFORM_PROJECTION, storage->winmat, 16, 1);
- drw_shgroup_builtin_uniform(shgroup, GPU_UNIFORM_PROJECTION_INV, storage->wininv, 16, 1);
- drw_shgroup_builtin_uniform(shgroup, GPU_UNIFORM_CLIPPLANES, storage->clipplanes, 4, 6);
+ shgroup, view_ubo_location, DRW_UNIFORM_BLOCK, G_draw.view_ubo, 0, 0, 1);
}
/* Not supported. */
BLI_assert(GPU_shader_get_builtin_uniform(shader, GPU_UNIFORM_MODELVIEW_INV) == -1);
BLI_assert(GPU_shader_get_builtin_uniform(shader, GPU_UNIFORM_MODELVIEW) == -1);
BLI_assert(GPU_shader_get_builtin_uniform(shader, GPU_UNIFORM_NORMAL) == -1);
+ BLI_assert(GPU_shader_get_builtin_uniform(shader, GPU_UNIFORM_VIEW) == -1);
+ BLI_assert(GPU_shader_get_builtin_uniform(shader, GPU_UNIFORM_VIEW_INV) == -1);
+ BLI_assert(GPU_shader_get_builtin_uniform(shader, GPU_UNIFORM_VIEWPROJECTION) == -1);
+ BLI_assert(GPU_shader_get_builtin_uniform(shader, GPU_UNIFORM_VIEWPROJECTION_INV) == -1);
+ BLI_assert(GPU_shader_get_builtin_uniform(shader, GPU_UNIFORM_PROJECTION) == -1);
+ BLI_assert(GPU_shader_get_builtin_uniform(shader, GPU_UNIFORM_PROJECTION_INV) == -1);
+ BLI_assert(GPU_shader_get_builtin_uniform(shader, GPU_UNIFORM_CLIPPLANES) == -1);
+ BLI_assert(GPU_shader_get_builtin_uniform(shader, GPU_UNIFORM_MVP) == -1);
}
static DRWShadingGroup *drw_shgroup_create_ex(struct GPUShader *shader, DRWPass *pass)
@@ -1253,31 +1273,36 @@ static DRWShadingGroup *drw_shgroup_material_create_ex(GPUPass *gpupass, DRWPass
static void drw_shgroup_material_texture(DRWShadingGroup *grp,
GPUMaterialTexture *tex,
const char *name,
+ eGPUSamplerState state,
int textarget)
{
GPUTexture *gputex = GPU_texture_from_blender(tex->ima, tex->iuser, NULL, textarget);
- DRW_shgroup_uniform_texture(grp, name, gputex);
+
+ int loc = GPU_shader_get_texture_binding(grp->shader, name);
+ drw_shgroup_uniform_create_ex(grp, loc, DRW_UNIFORM_TEXTURE, gputex, state, 0, 1);
GPUTexture **gputex_ref = BLI_memblock_alloc(DST.vmempool->images);
*gputex_ref = gputex;
GPU_texture_ref(gputex);
}
-static DRWShadingGroup *drw_shgroup_material_inputs(DRWShadingGroup *grp,
- struct GPUMaterial *material)
+void DRW_shgroup_add_material_resources(DRWShadingGroup *grp, struct GPUMaterial *material)
{
ListBase textures = GPU_material_textures(material);
/* Bind all textures needed by the material. */
- for (GPUMaterialTexture *tex = textures.first; tex; tex = tex->next) {
+ LISTBASE_FOREACH (GPUMaterialTexture *, tex, &textures) {
if (tex->ima) {
/* Image */
if (tex->tiled_mapping_name[0]) {
- drw_shgroup_material_texture(grp, tex, tex->sampler_name, GL_TEXTURE_2D_ARRAY);
- drw_shgroup_material_texture(grp, tex, tex->tiled_mapping_name, GL_TEXTURE_1D_ARRAY);
+ drw_shgroup_material_texture(
+ grp, tex, tex->sampler_name, tex->sampler_state, GL_TEXTURE_2D_ARRAY);
+ drw_shgroup_material_texture(
+ grp, tex, tex->tiled_mapping_name, tex->sampler_state, GL_TEXTURE_1D_ARRAY);
}
else {
- drw_shgroup_material_texture(grp, tex, tex->sampler_name, GL_TEXTURE_2D);
+ drw_shgroup_material_texture(
+ grp, tex, tex->sampler_name, tex->sampler_state, GL_TEXTURE_2D);
}
}
else if (tex->colorband) {
@@ -1290,8 +1315,6 @@ static DRWShadingGroup *drw_shgroup_material_inputs(DRWShadingGroup *grp,
if (ubo != NULL) {
DRW_shgroup_uniform_block(grp, GPU_UBO_BLOCK_NAME, ubo);
}
-
- return grp;
}
GPUVertFormat *DRW_shgroup_instance_format_array(const DRWInstanceAttrFormat attrs[],
@@ -1316,7 +1339,7 @@ DRWShadingGroup *DRW_shgroup_material_create(struct GPUMaterial *material, DRWPa
if (shgroup) {
drw_shgroup_init(shgroup, GPU_pass_shader_get(gpupass));
- drw_shgroup_material_inputs(shgroup, material);
+ DRW_shgroup_add_material_resources(shgroup, material);
}
return shgroup;
}
@@ -1335,7 +1358,7 @@ DRWShadingGroup *DRW_shgroup_transform_feedback_create(struct GPUShader *shader,
BLI_assert(tf_target != NULL);
DRWShadingGroup *shgroup = drw_shgroup_create_ex(shader, pass);
drw_shgroup_init(shgroup, shader);
- drw_shgroup_uniform_create_ex(shgroup, 0, DRW_UNIFORM_TFEEDBACK_TARGET, tf_target, 0, 1);
+ drw_shgroup_uniform_create_ex(shgroup, 0, DRW_UNIFORM_TFEEDBACK_TARGET, tf_target, 0, 0, 1);
return shgroup;
}
@@ -1867,12 +1890,31 @@ DRWPass *DRW_pass_create(const char *name, DRWState state)
pass->handle = DST.pass_handle;
DRW_handle_increment(&DST.pass_handle);
+ pass->original = NULL;
+ pass->next = NULL;
+
+ return pass;
+}
+
+DRWPass *DRW_pass_create_instance(const char *name, DRWPass *original, DRWState state)
+{
+ DRWPass *pass = DRW_pass_create(name, state);
+ pass->original = original;
+
return pass;
}
+/* Link two passes so that they are both rendered if the first one is being drawn. */
+void DRW_pass_link(DRWPass *first, DRWPass *second)
+{
+ BLI_assert(first != second);
+ BLI_assert(first->next == NULL);
+ first->next = second;
+}
+
bool DRW_pass_is_empty(DRWPass *pass)
{
- for (DRWShadingGroup *shgroup = pass->shgroups.first; shgroup; shgroup = shgroup->next) {
+ LISTBASE_FOREACH (DRWShadingGroup *, shgroup, &pass->shgroups) {
if (!DRW_shgroup_is_empty(shgroup)) {
return false;
}
@@ -1899,7 +1941,7 @@ void DRW_pass_foreach_shgroup(DRWPass *pass,
void (*callback)(void *userData, DRWShadingGroup *shgrp),
void *userData)
{
- for (DRWShadingGroup *shgroup = pass->shgroups.first; shgroup; shgroup = shgroup->next) {
+ LISTBASE_FOREACH (DRWShadingGroup *, shgroup, &pass->shgroups) {
callback(userData, shgroup);
}
}
@@ -1963,7 +2005,10 @@ void DRW_pass_sort_shgroup_z(DRWPass *pass)
}
}
/* To be sorted a shgroup needs to have at least one draw command. */
- BLI_assert(handle != 0);
+ /* FIXME(fclem) In some case, we can still have empty shading group to sort. However their
+ * final order is not well defined.
+ * (see T76730 & D7729). */
+ // BLI_assert(handle != 0);
DRWObjectMatrix *obmats = DRW_memblock_elem_from_handle(DST.vmempool->obmats, &handle);
diff --git a/source/blender/draw/intern/draw_manager_exec.c b/source/blender/draw/intern/draw_manager_exec.c
index 8e712295b61..59b4e9af14e 100644
--- a/source/blender/draw/intern/draw_manager_exec.c
+++ b/source/blender/draw/intern/draw_manager_exec.c
@@ -22,6 +22,7 @@
#include "draw_manager.h"
+#include "BLI_alloca.h"
#include "BLI_math.h"
#include "BLI_math_bits.h"
#include "BLI_memblock.h"
@@ -65,7 +66,6 @@ typedef struct DRWCommandsState {
/* Legacy matrix support. */
int obmat_loc;
int obinv_loc;
- int mvp_loc;
/* Selection ID state. */
GPUVertBuf *select_buf;
uint select_id;
@@ -454,6 +454,8 @@ void DRW_state_reset(void)
{
DRW_state_reset_ex(DRW_STATE_DEFAULT);
+ GPU_texture_unbind_all();
+
/* Should stay constant during the whole rendering. */
GPU_point_size(5);
GPU_line_smooth(false);
@@ -655,8 +657,7 @@ static void draw_compute_culling(DRWView *view)
BLI_INLINE void draw_legacy_matrix_update(DRWShadingGroup *shgroup,
DRWResourceHandle *handle,
float obmat_loc,
- float obinv_loc,
- float mvp_loc)
+ float obinv_loc)
{
/* Still supported for compatibility with gpu_shader_* but should be forbidden. */
DRWObjectMatrix *ob_mats = DRW_memblock_elem_from_handle(DST.vmempool->obmats, handle);
@@ -666,13 +667,6 @@ BLI_INLINE void draw_legacy_matrix_update(DRWShadingGroup *shgroup,
if (obinv_loc != -1) {
GPU_shader_uniform_vector(shgroup->shader, obinv_loc, 16, 1, (float *)ob_mats->modelinverse);
}
- /* Still supported for compatibility with gpu_shader_* but should be forbidden
- * and is slow (since it does not cache the result). */
- if (mvp_loc != -1) {
- float mvp[4][4];
- mul_m4_m4m4(mvp, DST.view_active->storage.persmat, ob_mats->model);
- GPU_shader_uniform_vector(shgroup->shader, mvp_loc, 16, 1, (float *)mvp);
- }
}
BLI_INLINE void draw_geometry_bind(DRWShadingGroup *shgroup, GPUBatch *geom)
@@ -744,107 +738,6 @@ BLI_INLINE void draw_indirect_call(DRWShadingGroup *shgroup, DRWCommandsState *s
}
}
-enum {
- BIND_NONE = 0,
- BIND_TEMP = 1, /* Release slot after this shading group. */
- BIND_PERSIST = 2, /* Release slot only after the next shader change. */
-};
-
-static void set_bound_flags(uint64_t *slots, uint64_t *persist_slots, int slot_idx, char bind_type)
-{
- uint64_t slot = 1llu << (unsigned long)slot_idx;
- *slots |= slot;
- if (bind_type == BIND_PERSIST) {
- *persist_slots |= slot;
- }
-}
-
-static int get_empty_slot_index(uint64_t slots)
-{
- uint64_t empty_slots = ~slots;
- /* Find first empty slot using bitscan. */
- if (empty_slots != 0) {
- if ((empty_slots & 0xFFFFFFFFlu) != 0) {
- return (int)bitscan_forward_uint(empty_slots);
- }
- else {
- return (int)bitscan_forward_uint(empty_slots >> 32) + 32;
- }
- }
- else {
- /* Greater than GPU_max_textures() */
- return 99999;
- }
-}
-
-static void bind_texture(GPUTexture *tex, char bind_type)
-{
- int idx = GPU_texture_bound_number(tex);
- if (idx == -1) {
- /* Texture isn't bound yet. Find an empty slot and bind it. */
- idx = get_empty_slot_index(DST.RST.bound_tex_slots);
-
- if (idx < GPU_max_textures()) {
- GPUTexture **gpu_tex_slot = &DST.RST.bound_texs[idx];
- /* Unbind any previous texture. */
- if (*gpu_tex_slot != NULL) {
- GPU_texture_unbind(*gpu_tex_slot);
- }
- GPU_texture_bind(tex, idx);
- *gpu_tex_slot = tex;
- }
- else {
- printf("Not enough texture slots! Reduce number of textures used by your shader.\n");
- return;
- }
- }
- else {
- /* This texture slot was released but the tex
- * is still bound. Just flag the slot again. */
- BLI_assert(DST.RST.bound_texs[idx] == tex);
- }
- set_bound_flags(&DST.RST.bound_tex_slots, &DST.RST.bound_tex_slots_persist, idx, bind_type);
-}
-
-static void bind_ubo(GPUUniformBuffer *ubo, char bind_type)
-{
- int idx = GPU_uniformbuffer_bindpoint(ubo);
- if (idx == -1) {
- /* UBO isn't bound yet. Find an empty slot and bind it. */
- idx = get_empty_slot_index(DST.RST.bound_ubo_slots);
-
- /* [0..1] are reserved ubo slots. */
- idx += 2;
-
- if (idx < GPU_max_ubo_binds()) {
- GPUUniformBuffer **gpu_ubo_slot = &DST.RST.bound_ubos[idx];
- /* Unbind any previous UBO. */
- if (*gpu_ubo_slot != NULL) {
- GPU_uniformbuffer_unbind(*gpu_ubo_slot);
- }
- GPU_uniformbuffer_bind(ubo, idx);
- *gpu_ubo_slot = ubo;
- }
- else {
- /* printf so user can report bad behavior */
- printf("Not enough ubo slots! This should not happen!\n");
- /* This is not depending on user input.
- * It is our responsibility to make sure there is enough slots. */
- BLI_assert(0);
- return;
- }
- }
- else {
- BLI_assert(idx < 64);
- /* This UBO slot was released but the UBO is
- * still bound here. Just flag the slot again. */
- BLI_assert(DST.RST.bound_ubos[idx] == ubo);
- }
- /* Remove offset for flag bitfield. */
- idx -= 2;
- set_bound_flags(&DST.RST.bound_ubo_slots, &DST.RST.bound_ubo_slots_persist, idx, bind_type);
-}
-
#ifndef NDEBUG
/**
* Opengl specification is strict on buffer binding.
@@ -900,28 +793,6 @@ static bool ubo_bindings_validate(DRWShadingGroup *shgroup)
}
#endif
-static void release_texture_slots(bool with_persist)
-{
- if (with_persist) {
- DST.RST.bound_tex_slots = 0;
- DST.RST.bound_tex_slots_persist = 0;
- }
- else {
- DST.RST.bound_tex_slots &= DST.RST.bound_tex_slots_persist;
- }
-}
-
-static void release_ubo_slots(bool with_persist)
-{
- if (with_persist) {
- DST.RST.bound_ubo_slots = 0;
- DST.RST.bound_ubo_slots_persist = 0;
- }
- else {
- DST.RST.bound_ubo_slots &= DST.RST.bound_ubo_slots_persist;
- }
-}
-
static void draw_update_uniforms(DRWShadingGroup *shgroup,
DRWCommandsState *state,
bool *use_tfeedback)
@@ -929,69 +800,42 @@ static void draw_update_uniforms(DRWShadingGroup *shgroup,
for (DRWUniformChunk *unichunk = shgroup->uniforms; unichunk; unichunk = unichunk->next) {
DRWUniform *uni = unichunk->uniforms;
for (int i = 0; i < unichunk->uniform_used; i++, uni++) {
- GPUTexture *tex;
- GPUUniformBuffer *ubo;
- if (uni->location == -2) {
- uni->location = GPU_shader_get_uniform_ensure(shgroup->shader,
- DST.uniform_names.buffer + uni->name_ofs);
- if (uni->location == -1) {
- continue;
- }
- }
- const void *data = uni->pvalue;
- if (ELEM(uni->type, DRW_UNIFORM_INT_COPY, DRW_UNIFORM_FLOAT_COPY)) {
- data = uni->fvalue;
- }
switch (uni->type) {
case DRW_UNIFORM_INT_COPY:
+ GPU_shader_uniform_vector_int(
+ shgroup->shader, uni->location, uni->length, uni->arraysize, uni->ivalue);
+ break;
case DRW_UNIFORM_INT:
GPU_shader_uniform_vector_int(
- shgroup->shader, uni->location, uni->length, uni->arraysize, data);
+ shgroup->shader, uni->location, uni->length, uni->arraysize, uni->pvalue);
break;
case DRW_UNIFORM_FLOAT_COPY:
+ GPU_shader_uniform_vector(
+ shgroup->shader, uni->location, uni->length, uni->arraysize, uni->fvalue);
+ break;
case DRW_UNIFORM_FLOAT:
GPU_shader_uniform_vector(
- shgroup->shader, uni->location, uni->length, uni->arraysize, data);
+ shgroup->shader, uni->location, uni->length, uni->arraysize, uni->pvalue);
break;
case DRW_UNIFORM_TEXTURE:
- tex = (GPUTexture *)uni->pvalue;
- BLI_assert(tex);
- bind_texture(tex, BIND_TEMP);
- GPU_shader_uniform_texture(shgroup->shader, uni->location, tex);
- break;
- case DRW_UNIFORM_TEXTURE_PERSIST:
- tex = (GPUTexture *)uni->pvalue;
- BLI_assert(tex);
- bind_texture(tex, BIND_PERSIST);
- GPU_shader_uniform_texture(shgroup->shader, uni->location, tex);
+ GPU_texture_bind_ex(uni->texture, uni->sampler_state, uni->location, false);
break;
case DRW_UNIFORM_TEXTURE_REF:
- tex = *((GPUTexture **)uni->pvalue);
- BLI_assert(tex);
- bind_texture(tex, BIND_TEMP);
- GPU_shader_uniform_texture(shgroup->shader, uni->location, tex);
+ GPU_texture_bind_ex(*uni->texture_ref, uni->sampler_state, uni->location, false);
break;
case DRW_UNIFORM_BLOCK:
- ubo = (GPUUniformBuffer *)uni->pvalue;
- bind_ubo(ubo, BIND_TEMP);
- GPU_shader_uniform_buffer(shgroup->shader, uni->location, ubo);
+ GPU_uniformbuffer_bind(uni->block, uni->location);
break;
- case DRW_UNIFORM_BLOCK_PERSIST:
- ubo = (GPUUniformBuffer *)uni->pvalue;
- bind_ubo(ubo, BIND_PERSIST);
- GPU_shader_uniform_buffer(shgroup->shader, uni->location, ubo);
+ case DRW_UNIFORM_BLOCK_REF:
+ GPU_uniformbuffer_bind(*uni->block_ref, uni->location);
break;
case DRW_UNIFORM_BLOCK_OBMATS:
state->obmats_loc = uni->location;
- ubo = DST.vmempool->matrices_ubo[0];
- GPU_uniformbuffer_bind(ubo, 0);
- GPU_shader_uniform_buffer(shgroup->shader, uni->location, ubo);
+ GPU_uniformbuffer_bind(DST.vmempool->matrices_ubo[0], uni->location);
break;
case DRW_UNIFORM_BLOCK_OBINFOS:
state->obinfos_loc = uni->location;
- ubo = DST.vmempool->obinfos_ubo[0];
- GPU_uniformbuffer_bind(ubo, 1);
- GPU_shader_uniform_buffer(shgroup->shader, uni->location, ubo);
+ GPU_uniformbuffer_bind(DST.vmempool->obinfos_ubo[0], uni->location);
break;
case DRW_UNIFORM_RESOURCE_CHUNK:
state->chunkid_loc = uni->location;
@@ -1001,9 +845,9 @@ static void draw_update_uniforms(DRWShadingGroup *shgroup,
state->resourceid_loc = uni->location;
break;
case DRW_UNIFORM_TFEEDBACK_TARGET:
- BLI_assert(data && (*use_tfeedback == false));
- *use_tfeedback = GPU_shader_transform_feedback_enable(shgroup->shader,
- ((GPUVertBuf *)data)->vbo_id);
+ BLI_assert(uni->pvalue && (*use_tfeedback == false));
+ *use_tfeedback = GPU_shader_transform_feedback_enable(
+ shgroup->shader, ((GPUVertBuf *)uni->pvalue)->vbo_id);
break;
/* Legacy/Fallback support. */
case DRW_UNIFORM_BASE_INSTANCE:
@@ -1015,9 +859,6 @@ static void draw_update_uniforms(DRWShadingGroup *shgroup,
case DRW_UNIFORM_MODEL_MATRIX_INVERSE:
state->obinv_loc = uni->location;
break;
- case DRW_UNIFORM_MODELVIEWPROJECTION_MATRIX:
- state->mvp_loc = uni->location;
- break;
}
}
}
@@ -1110,11 +951,11 @@ static void draw_call_resource_bind(DRWCommandsState *state, const DRWResourceHa
}
if (state->obmats_loc != -1) {
GPU_uniformbuffer_unbind(DST.vmempool->matrices_ubo[state->resource_chunk]);
- GPU_uniformbuffer_bind(DST.vmempool->matrices_ubo[chunk], 0);
+ GPU_uniformbuffer_bind(DST.vmempool->matrices_ubo[chunk], state->obmats_loc);
}
if (state->obinfos_loc != -1) {
GPU_uniformbuffer_unbind(DST.vmempool->obinfos_ubo[state->resource_chunk]);
- GPU_uniformbuffer_bind(DST.vmempool->obinfos_ubo[chunk], 1);
+ GPU_uniformbuffer_bind(DST.vmempool->obinfos_ubo[chunk], state->obinfos_loc);
}
state->resource_chunk = chunk;
}
@@ -1153,10 +994,8 @@ static void draw_call_single_do(DRWShadingGroup *shgroup,
draw_call_resource_bind(state, &handle);
/* TODO This is Legacy. Need to be removed. */
- if (state->obmats_loc == -1 &&
- (state->obmat_loc != -1 || state->obinv_loc != -1 || state->mvp_loc != -1)) {
- draw_legacy_matrix_update(
- shgroup, &handle, state->obmat_loc, state->obinv_loc, state->mvp_loc);
+ if (state->obmats_loc == -1 && (state->obmat_loc != -1 || state->obinv_loc != -1)) {
+ draw_legacy_matrix_update(shgroup, &handle, state->obmat_loc, state->obinv_loc);
}
if (G.f & G_FLAG_PICKSEL) {
@@ -1262,7 +1101,6 @@ static void draw_shgroup(DRWShadingGroup *shgroup, DRWState pass_state)
.resourceid_loc = -1,
.obmat_loc = -1,
.obinv_loc = -1,
- .mvp_loc = -1,
.drw_state_enabled = 0,
.drw_state_disabled = 0,
};
@@ -1273,6 +1111,11 @@ static void draw_shgroup(DRWShadingGroup *shgroup, DRWState pass_state)
if (shader_changed) {
if (DST.shader) {
GPU_shader_unbind();
+
+ /* Unbinding can be costly. Skip in normal condition. */
+ if (G.debug & G_DEBUG_GPU) {
+ GPU_texture_unbind_all();
+ }
}
GPU_shader_bind(shgroup->shader);
DST.shader = shgroup->shader;
@@ -1283,9 +1126,6 @@ static void draw_shgroup(DRWShadingGroup *shgroup, DRWState pass_state)
DST.batch = NULL;
}
- release_ubo_slots(shader_changed);
- release_texture_slots(shader_changed);
-
draw_update_uniforms(shgroup, &state, &use_tfeedback);
drw_state_set(pass_state);
@@ -1376,7 +1216,7 @@ static void draw_shgroup(DRWShadingGroup *shgroup, DRWState pass_state)
0,
0,
cmd->instance.inst_count,
- cmd->instance.use_attribs == 0);
+ cmd->instance.use_attrs == 0);
break;
case DRW_CMD_DRAW_RANGE:
draw_call_single_do(shgroup,
@@ -1426,6 +1266,11 @@ static void drw_draw_pass_ex(DRWPass *pass,
DRWShadingGroup *start_group,
DRWShadingGroup *end_group)
{
+ if (pass->original) {
+ start_group = pass->original->shgroups.first;
+ end_group = pass->original->shgroups.last;
+ }
+
if (start_group == NULL) {
return;
}
@@ -1462,22 +1307,6 @@ static void drw_draw_pass_ex(DRWPass *pass,
}
}
- /* Clear Bound textures */
- for (int i = 0; i < DST_MAX_SLOTS; i++) {
- if (DST.RST.bound_texs[i] != NULL) {
- GPU_texture_unbind(DST.RST.bound_texs[i]);
- DST.RST.bound_texs[i] = NULL;
- }
- }
-
- /* Clear Bound Ubos */
- for (int i = 0; i < DST_MAX_SLOTS; i++) {
- if (DST.RST.bound_ubos[i] != NULL) {
- GPU_uniformbuffer_unbind(DST.RST.bound_ubos[i]);
- DST.RST.bound_ubos[i] = NULL;
- }
- }
-
if (DST.shader) {
GPU_shader_unbind();
DST.shader = NULL;
@@ -1511,7 +1340,9 @@ static void drw_draw_pass_ex(DRWPass *pass,
void DRW_draw_pass(DRWPass *pass)
{
- drw_draw_pass_ex(pass, pass->shgroups.first, pass->shgroups.last);
+ for (; pass; pass = pass->next) {
+ drw_draw_pass_ex(pass, pass->shgroups.first, pass->shgroups.last);
+ }
}
/* Draw only a subset of shgroups. Used in special situations as grease pencil strokes */
diff --git a/source/blender/draw/intern/draw_manager_profiling.c b/source/blender/draw/intern/draw_manager_profiling.c
index 76382132230..57887c11c02 100644
--- a/source/blender/draw/intern/draw_manager_profiling.c
+++ b/source/blender/draw/intern/draw_manager_profiling.c
@@ -20,6 +20,7 @@
* \ingroup draw
*/
+#include "BLI_listbase.h"
#include "BLI_rect.h"
#include "BLI_string.h"
@@ -250,7 +251,7 @@ void DRW_stats_draw(const rcti *rect)
/* Engines rows */
char time_to_txt[16];
- for (LinkData *link = DST.enabled_engines.first; link; link = link->next) {
+ LISTBASE_FOREACH (LinkData *, link, &DST.enabled_engines) {
u = 0;
DrawEngineType *engine = link->data;
ViewportEngineData *data = drw_viewport_engine_data_ensure(engine);
diff --git a/source/blender/draw/intern/draw_manager_shader.c b/source/blender/draw/intern/draw_manager_shader.c
index 89884d58099..6304b707cb9 100644
--- a/source/blender/draw/intern/draw_manager_shader.c
+++ b/source/blender/draw/intern/draw_manager_shader.c
@@ -99,6 +99,10 @@ static void drw_deferred_shader_compilation_exec(void *custom_data,
DRWShaderCompiler *comp = (DRWShaderCompiler *)custom_data;
void *gl_context = comp->gl_context;
+#if TRUST_NO_ONE
+ BLI_assert(gl_context != NULL);
+#endif
+
WM_opengl_context_activate(gl_context);
while (true) {
@@ -237,6 +241,9 @@ static void drw_deferred_shader_add(GPUMaterial *mat, bool deferred)
WM_jobs_timer(wm_job, 0.1, NC_MATERIAL | ND_SHADING_DRAW, 0);
WM_jobs_delay_start(wm_job, 0.1);
WM_jobs_callbacks(wm_job, drw_deferred_shader_compilation_exec, NULL, NULL, NULL);
+
+ G.is_break = false;
+
WM_jobs_start(wm, wm_job);
}
@@ -249,7 +256,7 @@ void DRW_deferred_shader_remove(GPUMaterial *mat)
/* No job running, do not create a new one by calling WM_jobs_get. */
continue;
}
- for (wmWindow *win = wm->windows.first; win; win = win->next) {
+ LISTBASE_FOREACH (wmWindow *, win, &wm->windows) {
wmJob *wm_job = WM_jobs_get(
wm, win, scene, "Shaders Compilation", WM_JOB_PROGRESS, WM_JOB_TYPE_SHADER_COMPILATION);
@@ -336,27 +343,12 @@ GPUShader *DRW_shader_create_with_transform_feedback(const char *vert,
__func__);
}
-GPUShader *DRW_shader_create_2d(const char *frag, const char *defines)
-{
- return GPU_shader_create(datatoc_gpu_shader_2D_vert_glsl, frag, NULL, NULL, defines, __func__);
-}
-
-GPUShader *DRW_shader_create_3d(const char *frag, const char *defines)
-{
- return GPU_shader_create(datatoc_gpu_shader_3D_vert_glsl, frag, NULL, NULL, defines, __func__);
-}
-
GPUShader *DRW_shader_create_fullscreen(const char *frag, const char *defines)
{
return GPU_shader_create(
datatoc_common_fullscreen_vert_glsl, frag, NULL, NULL, defines, __func__);
}
-GPUShader *DRW_shader_create_3d_depth_only(eGPUShaderConfig sh_cfg)
-{
- return GPU_shader_get_builtin_shader_with_config(GPU_SHADER_3D_DEPTH_ONLY, sh_cfg);
-}
-
GPUMaterial *DRW_shader_find_from_world(World *wo,
const void *engine_type,
const int options,
@@ -391,6 +383,7 @@ GPUMaterial *DRW_shader_find_from_material(Material *ma,
GPUMaterial *DRW_shader_create_from_world(struct Scene *scene,
World *wo,
+ struct bNodeTree *ntree,
const void *engine_type,
const int options,
const bool is_volume_shader,
@@ -401,7 +394,7 @@ GPUMaterial *DRW_shader_create_from_world(struct Scene *scene,
bool deferred)
{
GPUMaterial *mat = NULL;
- if (DRW_state_is_image_render()) {
+ if (DRW_state_is_image_render() || !deferred) {
mat = GPU_material_from_nodetree_find(&wo->gpumaterial, engine_type, options);
}
@@ -409,7 +402,7 @@ GPUMaterial *DRW_shader_create_from_world(struct Scene *scene,
scene = (Scene *)DEG_get_original_id(&DST.draw_ctx.scene->id);
mat = GPU_material_from_nodetree(scene,
NULL,
- wo->nodetree,
+ ntree,
&wo->gpumaterial,
engine_type,
options,
@@ -430,6 +423,7 @@ GPUMaterial *DRW_shader_create_from_world(struct Scene *scene,
GPUMaterial *DRW_shader_create_from_material(struct Scene *scene,
Material *ma,
+ struct bNodeTree *ntree,
const void *engine_type,
const int options,
const bool is_volume_shader,
@@ -440,7 +434,7 @@ GPUMaterial *DRW_shader_create_from_material(struct Scene *scene,
bool deferred)
{
GPUMaterial *mat = NULL;
- if (DRW_state_is_image_render()) {
+ if (DRW_state_is_image_render() || !deferred) {
mat = GPU_material_from_nodetree_find(&ma->gpumaterial, engine_type, options);
}
@@ -448,7 +442,7 @@ GPUMaterial *DRW_shader_create_from_material(struct Scene *scene,
scene = (Scene *)DEG_get_original_id(&DST.draw_ctx.scene->id);
mat = GPU_material_from_nodetree(scene,
ma,
- ma->nodetree,
+ ntree,
&ma->gpumaterial,
engine_type,
options,
diff --git a/source/blender/draw/intern/draw_manager_text.c b/source/blender/draw/intern/draw_manager_text.c
index 2692f7b4795..23956df71e8 100644
--- a/source/blender/draw/intern/draw_manager_text.c
+++ b/source/blender/draw/intern/draw_manager_text.c
@@ -27,6 +27,7 @@
#include "BLI_string.h"
#include "BKE_editmesh.h"
+#include "BKE_editmesh_cache.h"
#include "BKE_global.h"
#include "BKE_unit.h"
@@ -48,6 +49,7 @@
#include "WM_api.h"
#include "draw_manager_text.h"
+#include "intern/bmesh_polygon.h"
typedef struct ViewCachedString {
float vec[3];
@@ -216,6 +218,8 @@ void DRW_text_edit_mesh_measure_stats(ARegion *region,
float clip_planes[4][4];
/* allow for displaying shape keys and deform mods */
BMIter iter;
+ const float(*vert_coords)[3] = (me->runtime.edit_data ? me->runtime.edit_data->vertexCos : NULL);
+ const bool use_coords = (vert_coords != NULL);
/* when 2 or more edge-info options are enabled, space apart */
short edge_tex_count = 0;
@@ -261,6 +265,10 @@ void DRW_text_edit_mesh_measure_stats(ARegion *region,
UI_GetThemeColor3ubv(TH_DRAWEXTRA_EDGELEN, col);
+ if (use_coords) {
+ BM_mesh_elem_index_ensure(em->bm, BM_VERT);
+ }
+
BM_ITER_MESH (eed, &iter, em->bm, BM_EDGES_OF_MESH) {
/* draw selected edges, or edges next to selected verts while dragging */
if (BM_elem_flag_test(eed, BM_ELEM_SELECT) ||
@@ -268,8 +276,14 @@ void DRW_text_edit_mesh_measure_stats(ARegion *region,
BM_elem_flag_test(eed->v2, BM_ELEM_SELECT)))) {
float v1_clip[3], v2_clip[3];
- copy_v3_v3(v1, eed->v1->co);
- copy_v3_v3(v2, eed->v2->co);
+ if (vert_coords) {
+ copy_v3_v3(v1, vert_coords[BM_elem_index_get(eed->v1)]);
+ copy_v3_v3(v2, vert_coords[BM_elem_index_get(eed->v2)]);
+ }
+ else {
+ copy_v3_v3(v1, eed->v1->co);
+ copy_v3_v3(v2, eed->v2->co);
+ }
if (clip_segment_v3_plane_n(v1, v2, clip_planes, 4, v1_clip, v2_clip)) {
@@ -306,6 +320,13 @@ void DRW_text_edit_mesh_measure_stats(ARegion *region,
UI_GetThemeColor3ubv(TH_DRAWEXTRA_EDGEANG, col);
+ const float(*poly_normals)[3] = NULL;
+ if (use_coords) {
+ BM_mesh_elem_index_ensure(em->bm, BM_VERT | BM_FACE);
+ BKE_editmesh_cache_ensure_poly_normals(em, me->runtime.edit_data);
+ poly_normals = me->runtime.edit_data->polyNos;
+ }
+
BM_ITER_MESH (eed, &iter, em->bm, BM_EDGES_OF_MESH) {
BMLoop *l_a, *l_b;
if (BM_edge_loop_pair(eed, &l_a, &l_b)) {
@@ -321,8 +342,14 @@ void DRW_text_edit_mesh_measure_stats(ARegion *region,
BM_elem_flag_test(l_b->prev->v, BM_ELEM_SELECT)))) {
float v1_clip[3], v2_clip[3];
- copy_v3_v3(v1, eed->v1->co);
- copy_v3_v3(v2, eed->v2->co);
+ if (vert_coords) {
+ copy_v3_v3(v1, vert_coords[BM_elem_index_get(eed->v1)]);
+ copy_v3_v3(v2, vert_coords[BM_elem_index_get(eed->v2)]);
+ }
+ else {
+ copy_v3_v3(v1, eed->v1->co);
+ copy_v3_v3(v2, eed->v2->co);
+ }
if (clip_segment_v3_plane_n(v1, v2, clip_planes, 4, v1_clip, v2_clip)) {
float no_a[3], no_b[3];
@@ -331,8 +358,14 @@ void DRW_text_edit_mesh_measure_stats(ARegion *region,
mid_v3_v3v3(vmid, v1_clip, v2_clip);
mul_m4_v3(ob->obmat, vmid);
- copy_v3_v3(no_a, l_a->f->no);
- copy_v3_v3(no_b, l_b->f->no);
+ if (use_coords) {
+ copy_v3_v3(no_a, poly_normals[BM_elem_index_get(l_a->f)]);
+ copy_v3_v3(no_b, poly_normals[BM_elem_index_get(l_b->f)]);
+ }
+ else {
+ copy_v3_v3(no_a, l_a->f->no);
+ copy_v3_v3(no_b, l_b->f->no);
+ }
if (do_global) {
mul_mat3_m4_v3(ob->imat, no_a);
@@ -372,9 +405,17 @@ void DRW_text_edit_mesh_measure_stats(ARegion *region,
zero_v3(vmid);
BMLoop *(*l)[3] = &em->looptris[poly_to_tri_count(i, BM_elem_index_get(f->l_first))];
for (int j = 0; j < numtri; j++) {
- copy_v3_v3(v1, l[j][0]->v->co);
- copy_v3_v3(v2, l[j][1]->v->co);
- copy_v3_v3(v3, l[j][2]->v->co);
+
+ if (use_coords) {
+ copy_v3_v3(v1, vert_coords[BM_elem_index_get(l[j][0]->v)]);
+ copy_v3_v3(v2, vert_coords[BM_elem_index_get(l[j][1]->v)]);
+ copy_v3_v3(v3, vert_coords[BM_elem_index_get(l[j][2]->v)]);
+ }
+ else {
+ copy_v3_v3(v1, l[j][0]->v->co);
+ copy_v3_v3(v2, l[j][1]->v->co);
+ copy_v3_v3(v3, l[j][2]->v->co);
+ }
add_v3_v3(vmid, v1);
add_v3_v3(vmid, v2);
@@ -417,6 +458,10 @@ void DRW_text_edit_mesh_measure_stats(ARegion *region,
UI_GetThemeColor3ubv(TH_DRAWEXTRA_FACEANG, col);
+ if (use_coords) {
+ BM_mesh_elem_index_ensure(em->bm, BM_VERT);
+ }
+
BM_ITER_MESH (efa, &iter, em->bm, BM_FACES_OF_MESH) {
const bool is_face_sel = BM_elem_flag_test_bool(efa, BM_ELEM_SELECT);
@@ -433,12 +478,24 @@ void DRW_text_edit_mesh_measure_stats(ARegion *region,
/* lazy init center calc */
if (is_first) {
- BM_face_calc_center_bounds(efa, vmid);
+ if (use_coords) {
+ BM_face_calc_center_bounds_vcos(em->bm, efa, vmid, vert_coords);
+ }
+ else {
+ BM_face_calc_center_bounds(efa, vmid);
+ }
is_first = false;
}
- copy_v3_v3(v1, loop->prev->v->co);
- copy_v3_v3(v2, loop->v->co);
- copy_v3_v3(v3, loop->next->v->co);
+ if (use_coords) {
+ copy_v3_v3(v1, vert_coords[BM_elem_index_get(loop->prev->v)]);
+ copy_v3_v3(v2, vert_coords[BM_elem_index_get(loop->v)]);
+ copy_v3_v3(v3, vert_coords[BM_elem_index_get(loop->next->v)]);
+ }
+ else {
+ copy_v3_v3(v1, loop->prev->v->co);
+ copy_v3_v3(v2, loop->v->co);
+ copy_v3_v3(v3, loop->next->v->co);
+ }
copy_v3_v3(v2_local, v2);
@@ -475,29 +532,44 @@ void DRW_text_edit_mesh_measure_stats(ARegion *region,
if (em->selectmode & SCE_SELECT_VERTEX) {
BMVert *v;
+ if (use_coords) {
+ BM_mesh_elem_index_ensure(em->bm, BM_VERT);
+ }
BM_ITER_MESH_INDEX (v, &iter, em->bm, BM_VERTS_OF_MESH, i) {
if (BM_elem_flag_test(v, BM_ELEM_SELECT)) {
- float vec[3];
- mul_v3_m4v3(vec, ob->obmat, v->co);
+ if (use_coords) {
+ copy_v3_v3(v1, vert_coords[BM_elem_index_get(v)]);
+ }
+ else {
+ copy_v3_v3(v1, v->co);
+ }
+
+ mul_m4_v3(ob->obmat, v1);
numstr_len = BLI_snprintf_rlen(numstr, sizeof(numstr), "%d", i);
- DRW_text_cache_add(dt, vec, numstr, numstr_len, 0, 0, txt_flag, col);
+ DRW_text_cache_add(dt, v1, numstr, numstr_len, 0, 0, txt_flag, col);
}
}
}
if (em->selectmode & SCE_SELECT_EDGE) {
- BMEdge *e;
+ BMEdge *eed;
const bool use_edge_tex_sep = (edge_tex_count == 2);
const bool use_edge_tex_len = (v3d->overlay.edit_flag & V3D_OVERLAY_EDIT_EDGE_LEN);
- BM_ITER_MESH_INDEX (e, &iter, em->bm, BM_EDGES_OF_MESH, i) {
- if (BM_elem_flag_test(e, BM_ELEM_SELECT)) {
+ BM_ITER_MESH_INDEX (eed, &iter, em->bm, BM_EDGES_OF_MESH, i) {
+ if (BM_elem_flag_test(eed, BM_ELEM_SELECT)) {
float v1_clip[3], v2_clip[3];
- copy_v3_v3(v1, e->v1->co);
- copy_v3_v3(v2, e->v2->co);
+ if (use_coords) {
+ copy_v3_v3(v1, vert_coords[BM_elem_index_get(eed->v1)]);
+ copy_v3_v3(v2, vert_coords[BM_elem_index_get(eed->v2)]);
+ }
+ else {
+ copy_v3_v3(v1, eed->v1->co);
+ copy_v3_v3(v2, eed->v2->co);
+ }
if (clip_segment_v3_plane_n(v1, v2, clip_planes, 4, v1_clip, v2_clip)) {
mid_v3_v3v3(vmid, v1_clip, v2_clip);
@@ -521,9 +593,20 @@ void DRW_text_edit_mesh_measure_stats(ARegion *region,
if (em->selectmode & SCE_SELECT_FACE) {
BMFace *f;
+ if (use_coords) {
+ BM_mesh_elem_index_ensure(em->bm, BM_VERT);
+ }
+
BM_ITER_MESH_INDEX (f, &iter, em->bm, BM_FACES_OF_MESH, i) {
if (BM_elem_flag_test(f, BM_ELEM_SELECT)) {
- BM_face_calc_center_median(f, v1);
+
+ if (use_coords) {
+ BM_face_calc_center_median_vcos(em->bm, f, v1, vert_coords);
+ }
+ else {
+ BM_face_calc_center_median(f, v1);
+ }
+
mul_m4_v3(ob->obmat, v1);
numstr_len = BLI_snprintf_rlen(numstr, sizeof(numstr), "%d", i);
diff --git a/source/blender/draw/intern/draw_manager_texture.c b/source/blender/draw/intern/draw_manager_texture.c
index 3f11fe9d11e..77b0462303d 100644
--- a/source/blender/draw/intern/draw_manager_texture.c
+++ b/source/blender/draw/intern/draw_manager_texture.c
@@ -61,17 +61,17 @@ static bool drw_texture_format_supports_framebuffer(eGPUTextureFormat format)
void drw_texture_set_parameters(GPUTexture *tex, DRWTextureFlag flags)
{
- GPU_texture_bind(tex, 0);
if (flags & DRW_TEX_MIPMAP) {
GPU_texture_mipmap_mode(tex, true, flags & DRW_TEX_FILTER);
+ GPU_texture_bind(tex, 0);
GPU_texture_generate_mipmap(tex);
+ GPU_texture_unbind(tex);
}
else {
GPU_texture_filter_mode(tex, flags & DRW_TEX_FILTER);
}
- GPU_texture_wrap_mode(tex, flags & DRW_TEX_WRAP);
+ GPU_texture_wrap_mode(tex, flags & DRW_TEX_WRAP, true);
GPU_texture_compare_mode(tex, flags & DRW_TEX_COMPARE);
- GPU_texture_unbind(tex);
}
GPUTexture *DRW_texture_create_1d(int w,
diff --git a/source/blender/draw/intern/shaders/common_globals_lib.glsl b/source/blender/draw/intern/shaders/common_globals_lib.glsl
index 9dfd48cc21a..a479a87e14b 100644
--- a/source/blender/draw/intern/shaders/common_globals_lib.glsl
+++ b/source/blender/draw/intern/shaders/common_globals_lib.glsl
@@ -140,3 +140,4 @@ layout(std140) uniform globalsBlock
#define EDGE_SEAM (1 << 4)
#define EDGE_SHARP (1 << 5)
#define EDGE_FREESTYLE (1 << 6)
+#define HANDLE_SELECTED (1 << 7)
diff --git a/source/blender/draw/intern/shaders/common_view_lib.glsl b/source/blender/draw/intern/shaders/common_view_lib.glsl
index 3faefd485bf..1054f4d11c9 100644
--- a/source/blender/draw/intern/shaders/common_view_lib.glsl
+++ b/source/blender/draw/intern/shaders/common_view_lib.glsl
@@ -77,12 +77,12 @@ uniform int resourceChunk;
uniform int baseInstance;
# endif
-# if defined(IN_PLACE_INSTANCES) || defined(INSTANCED_ATTRIB)
+# if defined(IN_PLACE_INSTANCES) || defined(INSTANCED_ATTR)
/* When drawing instances of an object at the same position. */
# define instanceId 0
# elif defined(GPU_DEPRECATED_AMD_DRIVER)
/* A driver bug make it so that when using an attribute with GL_INT_2_10_10_10_REV as format,
- * the gl_InstanceID is incremented by the 2 bit component of the attrib.
+ * the gl_InstanceID is incremented by the 2 bit component of the attribute.
* Ignore gl_InstanceID then. */
# define instanceId 0
# else
@@ -124,7 +124,7 @@ flat in int resourceIDFrag;
/* Breaking this across multiple lines causes issues for some older GLSL compilers. */
/* clang-format off */
-#if !defined(GPU_INTEL) && !defined(GPU_DEPRECATED_AMD_DRIVER) && !defined(OS_MAC) && !defined(INSTANCED_ATTRIB)
+#if !defined(GPU_INTEL) && !defined(GPU_DEPRECATED_AMD_DRIVER) && !defined(OS_MAC) && !defined(INSTANCED_ATTR)
/* clang-format on */
struct ObjectMatrices {
mat4 drw_modelMatrix;
diff --git a/source/blender/editors/animation/anim_channels_defines.c b/source/blender/editors/animation/anim_channels_defines.c
index 67e899382bb..0947023e071 100644
--- a/source/blender/editors/animation/anim_channels_defines.c
+++ b/source/blender/editors/animation/anim_channels_defines.c
@@ -51,6 +51,7 @@
#include "DNA_pointcloud_types.h"
#include "DNA_scene_types.h"
#include "DNA_screen_types.h"
+#include "DNA_simulation_types.h"
#include "DNA_space_types.h"
#include "DNA_speaker_types.h"
#include "DNA_volume_types.h"
@@ -58,6 +59,7 @@
#include "RNA_access.h"
+#include "BKE_anim_data.h"
#include "BKE_animsys.h"
#include "BKE_context.h"
#include "BKE_curve.h"
@@ -856,7 +858,7 @@ static void acf_group_color(bAnimContext *ac, bAnimListElem *ale, float r_color[
bool showGroupColors = acf_show_channel_colors(ac);
if (showGroupColors && agrp->customCol) {
- unsigned char cp[3];
+ uchar cp[3];
/* highlight only for active */
if (ale->flag & AGRP_ACTIVE) {
@@ -3032,6 +3034,83 @@ static bAnimChannelType ACF_DSVOLUME = {
acf_dsvolume_setting_ptr /* pointer for setting */
};
+/* Simulation Expander ----------------------------------------- */
+
+static int acf_dssimulation_icon(bAnimListElem *UNUSED(ale))
+{
+ /* TODO: Use correct icon. */
+ return ICON_PHYSICS;
+}
+
+static int acf_dssimulation_setting_flag(bAnimContext *UNUSED(ac),
+ eAnimChannel_Settings setting,
+ bool *neg)
+{
+ /* clear extra return data first */
+ *neg = false;
+
+ switch (setting) {
+ case ACHANNEL_SETTING_EXPAND: /* expanded */
+ return SIM_DS_EXPAND;
+
+ case ACHANNEL_SETTING_MUTE: /* mute (only in NLA) */
+ return ADT_NLA_EVAL_OFF;
+
+ case ACHANNEL_SETTING_VISIBLE: /* visible (only in Graph Editor) */
+ *neg = true;
+ return ADT_CURVES_NOT_VISIBLE;
+
+ case ACHANNEL_SETTING_SELECT: /* selected */
+ return ADT_UI_SELECTED;
+
+ default: /* unsupported */
+ return 0;
+ }
+}
+
+static void *acf_dssimulation_setting_ptr(bAnimListElem *ale,
+ eAnimChannel_Settings setting,
+ short *type)
+{
+ Simulation *simulation = (Simulation *)ale->data;
+
+ /* clear extra return data first */
+ *type = 0;
+
+ switch (setting) {
+ case ACHANNEL_SETTING_EXPAND: /* expanded */
+ return GET_ACF_FLAG_PTR(simulation->flag, type);
+
+ case ACHANNEL_SETTING_SELECT: /* selected */
+ case ACHANNEL_SETTING_MUTE: /* muted (for NLA only) */
+ case ACHANNEL_SETTING_VISIBLE: /* visible (for Graph Editor only) */
+ if (simulation->adt)
+ return GET_ACF_FLAG_PTR(simulation->adt->flag, type);
+ return NULL;
+
+ default: /* unsupported */
+ return NULL;
+ }
+}
+
+static bAnimChannelType ACF_DSSIMULATION = {
+ "Simulation Expander", /* type name */
+ ACHANNEL_ROLE_EXPANDER, /* role */
+
+ acf_generic_dataexpand_color, /* backdrop color */
+ acf_generic_dataexpand_backdrop, /* backdrop */
+ acf_generic_indention_1, /* indent level */
+ acf_generic_basic_offset, /* offset */
+
+ acf_generic_idblock_name, /* name */
+ acf_generic_idblock_name_prop, /* name prop */
+ acf_dssimulation_icon, /* icon */
+
+ acf_generic_dataexpand_setting_valid, /* has setting */
+ acf_dssimulation_setting_flag, /* flag for setting */
+ acf_dssimulation_setting_ptr /* pointer for setting */
+};
+
/* GPencil Expander ------------------------------------------- */
// TODO: just get this from RNA?
@@ -4048,6 +4127,7 @@ static void ANIM_init_channel_typeinfo_data(void)
animchannelTypeInfo[type++] = &ACF_DSHAIR; /* Hair Channel */
animchannelTypeInfo[type++] = &ACF_DSPOINTCLOUD; /* PointCloud Channel */
animchannelTypeInfo[type++] = &ACF_DSVOLUME; /* Volume Channel */
+ animchannelTypeInfo[type++] = &ACF_DSSIMULATION; /* Simulation Channel */
animchannelTypeInfo[type++] = &ACF_SHAPEKEY; /* ShapeKey */
@@ -4395,7 +4475,7 @@ void ANIM_channel_draw(
if (acf->name && !achannel_is_being_renamed(ac, acf, channel_index)) {
const uiFontStyle *fstyle = UI_FSTYLE_WIDGET;
char name[ANIM_CHAN_NAME_SIZE]; /* hopefully this will be enough! */
- unsigned char col[4];
+ uchar col[4];
/* set text color */
/* XXX: if active, highlight differently? */
@@ -4818,7 +4898,7 @@ static void draw_setting_widget(bAnimContext *ac,
icon = ICON_HIDE_ON;
if (ELEM(ale->type, ANIMTYPE_FCURVE, ANIMTYPE_NLACURVE)) {
- tooltip = TIP_("F-Curve is visible in Graph Editor for editing");
+ tooltip = TIP_("F-Curve visibility in Graph Editor");
}
else if (ale->type == ANIMTYPE_GPLAYER) {
tooltip = TIP_("Grease Pencil layer is visible in the viewport");
@@ -4835,7 +4915,7 @@ static void draw_setting_widget(bAnimContext *ac,
case ACHANNEL_SETTING_MOD_OFF: /* modifiers disabled */
icon = ICON_MODIFIER_OFF;
- tooltip = TIP_("F-Curve modifiers are disabled");
+ tooltip = TIP_("Enable F-Curve modifiers");
break;
case ACHANNEL_SETTING_EXPAND: /* expanded triangle */
@@ -4879,7 +4959,9 @@ static void draw_setting_widget(bAnimContext *ac,
"Temporarily disable NLA stack evaluation (i.e. only the active action is evaluated)");
}
else if (ale->type == ANIMTYPE_GPLAYER) {
- tooltip = TIP_("Lock current frame displayed by layer (i.e. disable animation playback)");
+ tooltip = TIP_(
+ "Shows all keyframes during animation playback and enabled all frames for editing "
+ "(uncheck to use only the current keyframe during animation playback and editing)");
}
else {
tooltip = TIP_("Do channels contribute to result (toggle channel muting)");
diff --git a/source/blender/editors/animation/anim_channels_edit.c b/source/blender/editors/animation/anim_channels_edit.c
index f47ed85f5bf..1ca3452e8d8 100644
--- a/source/blender/editors/animation/anim_channels_edit.c
+++ b/source/blender/editors/animation/anim_channels_edit.c
@@ -42,7 +42,7 @@
#include "RNA_define.h"
#include "BKE_action.h"
-#include "BKE_animsys.h"
+#include "BKE_anim_data.h"
#include "BKE_context.h"
#include "BKE_fcurve.h"
#include "BKE_global.h"
@@ -138,7 +138,8 @@ void ANIM_set_active_channel(bAnimContext *ac,
case ANIMTYPE_DSMCLIP:
case ANIMTYPE_DSHAIR:
case ANIMTYPE_DSPOINTCLOUD:
- case ANIMTYPE_DSVOLUME: {
+ case ANIMTYPE_DSVOLUME:
+ case ANIMTYPE_DSSIMULATION: {
/* need to verify that this data is valid for now */
if (ale->adt) {
ACHANNEL_SET_FLAG(ale->adt, ACHANNEL_SETFLAG_CLEAR, ADT_UI_ACTIVE);
@@ -194,7 +195,8 @@ void ANIM_set_active_channel(bAnimContext *ac,
case ANIMTYPE_DSMCLIP:
case ANIMTYPE_DSHAIR:
case ANIMTYPE_DSPOINTCLOUD:
- case ANIMTYPE_DSVOLUME: {
+ case ANIMTYPE_DSVOLUME:
+ case ANIMTYPE_DSSIMULATION: {
/* need to verify that this data is valid for now */
if (ale && ale->adt) {
ale->adt->flag |= ADT_UI_ACTIVE;
@@ -332,7 +334,8 @@ void ANIM_deselect_anim_channels(
case ANIMTYPE_DSMCLIP:
case ANIMTYPE_DSHAIR:
case ANIMTYPE_DSPOINTCLOUD:
- case ANIMTYPE_DSVOLUME: {
+ case ANIMTYPE_DSVOLUME:
+ case ANIMTYPE_DSSIMULATION: {
if ((ale->adt) && (ale->adt->flag & ADT_UI_SELECTED)) {
sel = ACHANNEL_SETFLAG_CLEAR;
}
@@ -428,7 +431,8 @@ void ANIM_deselect_anim_channels(
case ANIMTYPE_DSMCLIP:
case ANIMTYPE_DSHAIR:
case ANIMTYPE_DSPOINTCLOUD:
- case ANIMTYPE_DSVOLUME: {
+ case ANIMTYPE_DSVOLUME:
+ case ANIMTYPE_DSSIMULATION: {
/* need to verify that this data is valid for now */
if (ale->adt) {
ACHANNEL_SET_FLAG(ale->adt, sel, ADT_UI_SELECTED);
@@ -667,7 +671,7 @@ void ANIM_fcurve_delete_from_animdata(bAnimContext *ac, AnimData *adt, FCurve *f
}
/* free the F-Curve itself */
- free_fcurve(fcu);
+ BKE_fcurve_free(fcu);
}
/* If the action has no F-Curves, unlink it from AnimData if it did not
@@ -695,15 +699,15 @@ bool ANIM_remove_empty_action_from_animdata(struct AnimData *adt)
/* poll callback for being in an Animation Editor channels list region */
static bool animedit_poll_channels_active(bContext *C)
{
- ScrArea *sa = CTX_wm_area(C);
+ ScrArea *area = CTX_wm_area(C);
/* channels region test */
/* TODO: could enhance with actually testing if channels region? */
- if (ELEM(NULL, sa, CTX_wm_region(C))) {
+ if (ELEM(NULL, area, CTX_wm_region(C))) {
return 0;
}
/* animation editor test */
- if (ELEM(sa->spacetype, SPACE_ACTION, SPACE_GRAPH, SPACE_NLA) == 0) {
+ if (ELEM(area->spacetype, SPACE_ACTION, SPACE_GRAPH, SPACE_NLA) == 0) {
return 0;
}
@@ -713,21 +717,21 @@ static bool animedit_poll_channels_active(bContext *C)
/* poll callback for Animation Editor channels list region + not in NLA-tweakmode for NLA */
static bool animedit_poll_channels_nla_tweakmode_off(bContext *C)
{
- ScrArea *sa = CTX_wm_area(C);
+ ScrArea *area = CTX_wm_area(C);
Scene *scene = CTX_data_scene(C);
/* channels region test */
/* TODO: could enhance with actually testing if channels region? */
- if (ELEM(NULL, sa, CTX_wm_region(C))) {
+ if (ELEM(NULL, area, CTX_wm_region(C))) {
return 0;
}
/* animation editor test */
- if (ELEM(sa->spacetype, SPACE_ACTION, SPACE_GRAPH, SPACE_NLA) == 0) {
+ if (ELEM(area->spacetype, SPACE_ACTION, SPACE_GRAPH, SPACE_NLA) == 0) {
return 0;
}
/* NLA TweakMode test */
- if (sa->spacetype == SPACE_NLA) {
+ if (area->spacetype == SPACE_NLA) {
if ((scene == NULL) || (scene->flag & SCE_NLA_EDIT_ON)) {
return 0;
}
@@ -1518,19 +1522,19 @@ static void ANIM_OT_channels_move(wmOperatorType *ot)
static bool animchannels_grouping_poll(bContext *C)
{
- ScrArea *sa = CTX_wm_area(C);
+ ScrArea *area = CTX_wm_area(C);
SpaceLink *sl;
/* channels region test */
/* TODO: could enhance with actually testing if channels region? */
- if (ELEM(NULL, sa, CTX_wm_region(C))) {
+ if (ELEM(NULL, area, CTX_wm_region(C))) {
return 0;
}
/* animation editor test - must be suitable modes only */
sl = CTX_wm_space_data(C);
- switch (sa->spacetype) {
+ switch (area->spacetype) {
/* supported... */
case SPACE_ACTION: {
SpaceAction *saction = (SpaceAction *)sl;
@@ -1802,7 +1806,7 @@ static int animchannels_delete_exec(bContext *C, wmOperator *UNUSED(op))
/* remove from group and action, then free */
action_groups_remove_channel(adt->action, fcu);
- free_fcurve(fcu);
+ BKE_fcurve_free(fcu);
}
/* free the group itself */
@@ -1856,7 +1860,7 @@ static int animchannels_delete_exec(bContext *C, wmOperator *UNUSED(op))
/* unlink and free the F-Curve */
BLI_remlink(&strip->fcurves, fcu);
- free_fcurve(fcu);
+ BKE_fcurve_free(fcu);
tag_update_animation_element(ale);
break;
}
@@ -2268,7 +2272,8 @@ static int animchannels_clean_empty_exec(bContext *C, wmOperator *UNUSED(op))
}
/* get animdata blocks */
- filter = (ANIMFILTER_DATA_VISIBLE | ANIMFILTER_LIST_VISIBLE | ANIMFILTER_ANIMDATA);
+ filter = (ANIMFILTER_DATA_VISIBLE | ANIMFILTER_LIST_VISIBLE | ANIMFILTER_ANIMDATA |
+ ANIMFILTER_NODUPLIS);
ANIM_animdata_filter(&ac, &anim_data, filter, ac.data, ac.datatype);
for (ale = anim_data.first; ale; ale = ale->next) {
@@ -2353,16 +2358,16 @@ static void ANIM_OT_channels_clean_empty(wmOperatorType *ot)
static bool animchannels_enable_poll(bContext *C)
{
- ScrArea *sa = CTX_wm_area(C);
+ ScrArea *area = CTX_wm_area(C);
/* channels region test */
/* TODO: could enhance with actually testing if channels region? */
- if (ELEM(NULL, sa, CTX_wm_region(C))) {
+ if (ELEM(NULL, area, CTX_wm_region(C))) {
return 0;
}
/* animation editor test - Action/Dopesheet/etc. and Graph only */
- if (ELEM(sa->spacetype, SPACE_ACTION, SPACE_GRAPH) == 0) {
+ if (ELEM(area->spacetype, SPACE_ACTION, SPACE_GRAPH) == 0) {
return 0;
}
@@ -2431,14 +2436,14 @@ static void ANIM_OT_channels_fcurves_enable(wmOperatorType *ot)
/* XXX: make this generic? */
static bool animchannels_find_poll(bContext *C)
{
- ScrArea *sa = CTX_wm_area(C);
+ ScrArea *area = CTX_wm_area(C);
- if (sa == NULL) {
+ if (area == NULL) {
return 0;
}
/* animation editor with dopesheet */
- return ELEM(sa->spacetype, SPACE_ACTION, SPACE_GRAPH, SPACE_NLA);
+ return ELEM(area->spacetype, SPACE_ACTION, SPACE_GRAPH, SPACE_NLA);
}
/* find_invoke() - Get initial channels */
@@ -2964,7 +2969,8 @@ static int mouse_anim_channels(bContext *C, bAnimContext *ac, int channel_index,
case ANIMTYPE_DSMCLIP:
case ANIMTYPE_DSHAIR:
case ANIMTYPE_DSPOINTCLOUD:
- case ANIMTYPE_DSVOLUME: {
+ case ANIMTYPE_DSVOLUME:
+ case ANIMTYPE_DSSIMULATION: {
/* sanity checking... */
if (ale->adt) {
/* select/deselect */
diff --git a/source/blender/editors/animation/anim_deps.c b/source/blender/editors/animation/anim_deps.c
index 6f7770d97f1..4fb68b614ff 100644
--- a/source/blender/editors/animation/anim_deps.c
+++ b/source/blender/editors/animation/anim_deps.c
@@ -38,7 +38,7 @@
#include "BLI_utildefines.h"
#include "BKE_action.h"
-#include "BKE_animsys.h"
+#include "BKE_anim_data.h"
#include "BKE_context.h"
#include "BKE_fcurve.h"
#include "BKE_gpencil.h"
diff --git a/source/blender/editors/animation/anim_draw.c b/source/blender/editors/animation/anim_draw.c
index bcb9ddc5889..a2a1f7eb1d2 100644
--- a/source/blender/editors/animation/anim_draw.c
+++ b/source/blender/editors/animation/anim_draw.c
@@ -62,67 +62,6 @@
/* *************************************************** */
/* CURRENT FRAME DRAWING */
-/* Draw current frame number in a little green box beside the current frame indicator */
-void ANIM_draw_cfra_number(const bContext *C, View2D *v2d, short flag)
-{
- Scene *scene = CTX_data_scene(C);
- const float time = scene->r.cfra + scene->r.subframe;
- const float cfra = (float)(time * scene->r.framelen);
- const bool show_time = (flag & DRAWCFRA_UNIT_SECONDS) != 0;
-
- const uiFontStyle *fstyle = UI_FSTYLE_WIDGET;
- unsigned char col[4];
- float color[4];
- float xscale, x, y;
- char numstr[32] = " t "; /* t is the character to start replacing from */
- float hlen;
- int slen;
-
- /* because the frame number text is subject to the same scaling as the contents of the view */
- UI_view2d_scale_get(v2d, &xscale, NULL);
- GPU_matrix_push();
- GPU_matrix_scale_2f(1.0f / xscale, 1.0f);
-
- /* get timecode string
- * - padding on str-buf passed so that it doesn't sit on the frame indicator
- */
- if (show_time) {
- BLI_timecode_string_from_time(
- &numstr[2], sizeof(numstr) - 2, 0, FRA2TIME(cfra), FPS, U.timecode_style);
- }
- else {
- BLI_timecode_string_from_time_seconds(&numstr[2], sizeof(numstr) - 2, 1, cfra);
- }
-
- slen = UI_fontstyle_string_width(fstyle, numstr) - 1;
- hlen = slen * 0.5f;
-
- /* get starting coordinates for drawing */
- x = cfra * xscale;
- y = -0.1f * U.widget_unit;
-
- /* draw green box around/behind text */
- UI_GetThemeColor4fv(TH_CFRAME, color);
- color[3] = 3.0f;
-
- UI_draw_roundbox_corner_set(UI_CNR_ALL);
- UI_draw_roundbox_aa(true,
- x - hlen - 0.1f * U.widget_unit,
- y + 3.0f,
- x + hlen + 0.1f * U.widget_unit,
- y - 3.0f + U.widget_unit,
- 0.1f * U.widget_unit,
- color);
-
- /* draw current frame number */
- UI_GetThemeColor4ubv(TH_TEXT_HI, col);
- UI_fontstyle_draw_simple(
- fstyle, x - hlen - 0.15f * U.widget_unit, y + 0.28f * U.widget_unit, numstr, col);
-
- /* restore view transform */
- GPU_matrix_pop();
-}
-
/* General call for drawing current frame indicator in animation editor */
void ANIM_draw_cfra(const bContext *C, View2D *v2d, short flag)
{
@@ -441,12 +380,45 @@ static float normalization_factor_get(Scene *scene, FCurve *fcu, short flag, flo
min_coord = min_ff(min_coord, prev_bezt->vec[1][1]);
}
else {
- float step_size = (bezt->vec[1][0] - prev_bezt->vec[1][0]) / resol;
- for (int j = 0; j <= resol; j++) {
- float eval_time = prev_bezt->vec[1][0] + step_size * j;
- float eval_value = evaluate_fcurve_only_curve(fcu, eval_time);
- max_coord = max_ff(max_coord, eval_value);
- min_coord = min_ff(min_coord, eval_value);
+ if (!ELEM(prev_bezt->ipo, BEZT_IPO_BACK, BEZT_IPO_ELASTIC)) {
+ /* Calculate min/max using bezier forward differencing. */
+ float data[120];
+ float v1[2], v2[2], v3[2], v4[2];
+
+ v1[0] = prev_bezt->vec[1][0];
+ v1[1] = prev_bezt->vec[1][1];
+ v2[0] = prev_bezt->vec[2][0];
+ v2[1] = prev_bezt->vec[2][1];
+
+ v3[0] = bezt->vec[0][0];
+ v3[1] = bezt->vec[0][1];
+ v4[0] = bezt->vec[1][0];
+ v4[1] = bezt->vec[1][1];
+
+ correct_bezpart(v1, v2, v3, v4);
+
+ BKE_curve_forward_diff_bezier(
+ v1[0], v2[0], v3[0], v4[0], data, resol, sizeof(float) * 3);
+ BKE_curve_forward_diff_bezier(
+ v1[1], v2[1], v3[1], v4[1], data + 1, resol, sizeof(float) * 3);
+
+ for (int j = 0; j <= resol; ++j) {
+ const float *fp = &data[j * 3];
+ max_coord = max_ff(max_coord, fp[1]);
+ min_coord = min_ff(min_coord, fp[1]);
+ }
+ }
+ else {
+ /* Calculate min/max using full fcurve evaluation.
+ * [slower than bezier forward differencing but evaluates Back/Elastic interpolation
+ * as well].*/
+ float step_size = (bezt->vec[1][0] - prev_bezt->vec[1][0]) / resol;
+ for (int j = 0; j <= resol; j++) {
+ float eval_time = prev_bezt->vec[1][0] + step_size * j;
+ float eval_value = evaluate_fcurve_only_curve(fcu, eval_time);
+ max_coord = max_ff(max_coord, eval_value);
+ min_coord = min_ff(min_coord, eval_value);
+ }
}
}
}
diff --git a/source/blender/editors/animation/anim_filter.c b/source/blender/editors/animation/anim_filter.c
index a09db0380e6..bd83bdae31b 100644
--- a/source/blender/editors/animation/anim_filter.c
+++ b/source/blender/editors/animation/anim_filter.c
@@ -67,6 +67,7 @@
#include "DNA_scene_types.h"
#include "DNA_screen_types.h"
#include "DNA_sequence_types.h"
+#include "DNA_simulation_types.h"
#include "DNA_space_types.h"
#include "DNA_speaker_types.h"
#include "DNA_userdef_types.h"
@@ -82,10 +83,11 @@
#include "BLI_utildefines.h"
#include "BKE_action.h"
-#include "BKE_animsys.h"
+#include "BKE_anim_data.h"
#include "BKE_collection.h"
#include "BKE_context.h"
#include "BKE_fcurve.h"
+#include "BKE_fcurve_driver.h"
#include "BKE_global.h"
#include "BKE_key.h"
#include "BKE_layer.h"
@@ -399,7 +401,7 @@ bool ANIM_animdata_context_getdata(bAnimContext *ac)
bool ANIM_animdata_get_context(const bContext *C, bAnimContext *ac)
{
Main *bmain = CTX_data_main(C);
- ScrArea *sa = CTX_wm_area(C);
+ ScrArea *area = CTX_wm_area(C);
ARegion *region = CTX_wm_region(C);
SpaceLink *sl = CTX_wm_space_data(C);
Scene *scene = CTX_data_scene(C);
@@ -418,10 +420,10 @@ bool ANIM_animdata_get_context(const bContext *C, bAnimContext *ac)
}
ac->view_layer = CTX_data_view_layer(C);
ac->obact = (ac->view_layer->basact) ? ac->view_layer->basact->object : NULL;
- ac->sa = sa;
+ ac->area = area;
ac->region = region;
ac->sl = sl;
- ac->spacetype = (sa) ? sa->spacetype : 0;
+ ac->spacetype = (area) ? area->spacetype : 0;
ac->regiontype = (region) ? region->regiontype : 0;
/* initialise default y-scale factor */
@@ -826,6 +828,18 @@ static bAnimListElem *make_new_animlistelem(void *data,
ale->adt = BKE_animdata_from_id(data);
break;
}
+ case ANIMTYPE_DSSIMULATION: {
+ Simulation *simulation = (Simulation *)data;
+ AnimData *adt = simulation->adt;
+
+ ale->flag = FILTER_SIMULATION_OBJD(simulation);
+
+ ale->key_data = (adt) ? adt->action : NULL;
+ ale->datatype = ALE_ACT;
+
+ ale->adt = BKE_animdata_from_id(data);
+ break;
+ }
case ANIMTYPE_DSSKEY: {
Key *key = (Key *)data;
AnimData *adt = key->adt;
@@ -974,7 +988,7 @@ static bAnimListElem *make_new_animlistelem(void *data,
* then free the MEM_alloc'd string
*/
if (rna_path) {
- ale->key_data = (void *)list_find_fcurve(&act->curves, rna_path, 0);
+ ale->key_data = (void *)BKE_fcurve_find(&act->curves, rna_path, 0);
MEM_freeN(rna_path);
}
}
@@ -1840,15 +1854,18 @@ static size_t animdata_filter_gpencil(bAnimContext *ac,
bDopeSheet *ads = ac->ads;
size_t items = 0;
- Scene *scene = (Scene *)ads->source;
ViewLayer *view_layer = (ViewLayer *)ac->view_layer;
Base *base;
- /* Active scene's GPencil block first - No parent item needed... */
- if (scene->gpd) {
- items += animdata_filter_gpencil_data(anim_data, ads, scene->gpd, filter_mode);
+ /* Include all annotation datablocks. */
+ if (((ads->filterflag & ADS_FILTER_ONLYSEL) == 0) ||
+ (ads->filterflag & ADS_FILTER_INCL_HIDDEN)) {
+ LISTBASE_FOREACH (bGPdata *, gpd, &ac->bmain->gpencils) {
+ if (gpd->flag & GP_DATA_ANNOTATIONS) {
+ items += animdata_filter_gpencil_data(anim_data, ads, gpd, filter_mode);
+ }
+ }
}
-
/* Objects in the scene */
for (base = view_layer->object_bases.first; base; base = base->next) {
/* Only consider this object if it has got some GP data (saving on all the other tests) */
@@ -1877,13 +1894,12 @@ static size_t animdata_filter_gpencil(bAnimContext *ac,
}
}
- /* check selection and object type filters only for Object mode */
- if (ob->mode == OB_MODE_OBJECT) {
- if ((ads->filterflag & ADS_FILTER_ONLYSEL) && !((base->flag & BASE_SELECTED))) {
- /* only selected should be shown */
- continue;
- }
+ /* check selection and object type filters */
+ if ((ads->filterflag & ADS_FILTER_ONLYSEL) && !((base->flag & BASE_SELECTED))) {
+ /* only selected should be shown */
+ continue;
}
+
/* check if object belongs to the filtering group if option to filter
* objects by the grouped status is on
* - used to ease the process of doing multiple-character choreographies
@@ -2412,7 +2428,7 @@ static size_t animdata_filter_ds_modifiers(
afm.filter_mode = filter_mode;
/* 2) walk over dependencies */
- modifiers_foreachIDLink(ob, animfilter_modifier_idpoin_cb, &afm);
+ BKE_modifiers_foreach_ID_link(ob, animfilter_modifier_idpoin_cb, &afm);
/* 3) extract data from the context, merging it back into the standard list */
if (afm.items) {
@@ -3139,7 +3155,7 @@ static Base **animdata_filter_ds_sorted_bases(bDopeSheet *ads,
size_t num_bases = 0;
Base **sorted_bases = MEM_mallocN(sizeof(Base *) * tot_bases, "Dopesheet Usable Sorted Bases");
- for (Base *base = view_layer->object_bases.first; base; base = base->next) {
+ LISTBASE_FOREACH (Base *, base, &view_layer->object_bases) {
if (animdata_filter_base_is_ok(ads, base, filter_mode)) {
sorted_bases[num_bases++] = base;
}
@@ -3233,7 +3249,7 @@ static size_t animdata_filter_dopesheet(bAnimContext *ac,
/* Filter and add contents of each base (i.e. object) without them sorting first
* NOTE: This saves performance in cases where order doesn't matter
*/
- for (Base *base = view_layer->object_bases.first; base; base = base->next) {
+ LISTBASE_FOREACH (Base *, base, &view_layer->object_bases) {
if (animdata_filter_base_is_ok(ads, base, filter_mode)) {
/* since we're still here, this object should be usable */
items += animdata_filter_dopesheet_ob(ac, anim_data, ads, base, filter_mode);
diff --git a/source/blender/editors/animation/anim_ipo_utils.c b/source/blender/editors/animation/anim_ipo_utils.c
index f631d08f3e4..3613ca9eeda 100644
--- a/source/blender/editors/animation/anim_ipo_utils.c
+++ b/source/blender/editors/animation/anim_ipo_utils.c
@@ -203,7 +203,7 @@ int getname_anim_fcurve(char *name, ID *id, FCurve *fcu)
#define HSV_BANDWIDTH 0.3f
/* used to determine the color of F-Curves with FCURVE_COLOR_AUTO_RAINBOW set */
-// void fcurve_rainbow(unsigned int cur, unsigned int tot, float *out)
+// void fcurve_rainbow(uint cur, uint tot, float *out)
void getcolor_fcurve_rainbow(int cur, int tot, float out[3])
{
float hsv[3], fac;
diff --git a/source/blender/editors/animation/anim_markers.c b/source/blender/editors/animation/anim_markers.c
index 8b0e9b22ce8..46566feea91 100644
--- a/source/blender/editors/animation/anim_markers.c
+++ b/source/blender/editors/animation/anim_markers.c
@@ -74,12 +74,12 @@
/* ************* Marker API **************** */
/* helper function for getting the list of markers to work on */
-static ListBase *context_get_markers(Scene *scene, ScrArea *sa)
+static ListBase *context_get_markers(Scene *scene, ScrArea *area)
{
/* local marker sets... */
- if (sa) {
- if (sa->spacetype == SPACE_ACTION) {
- SpaceAction *saction = (SpaceAction *)sa->spacedata.first;
+ if (area) {
+ if (area->spacetype == SPACE_ACTION) {
+ SpaceAction *saction = (SpaceAction *)area->spacedata.first;
/* local markers can only be shown when there's only a single active action to grab them from
* - flag only takes effect when there's an action, otherwise it can get too confusing?
@@ -108,7 +108,7 @@ ListBase *ED_context_get_markers(const bContext *C)
ListBase *ED_animcontext_get_markers(const bAnimContext *ac)
{
if (ac) {
- return context_get_markers(ac->scene, ac->sa);
+ return context_get_markers(ac->scene, ac->area);
}
else {
return NULL;
@@ -234,35 +234,35 @@ void ED_markers_get_minmax(ListBase *markers, short sel, float *r_first, float *
*/
static bool ED_operator_markers_region_active(bContext *C)
{
- ScrArea *sa = CTX_wm_area(C);
- if (sa == NULL) {
+ ScrArea *area = CTX_wm_area(C);
+ if (area == NULL) {
return false;
}
- switch (sa->spacetype) {
+ switch (area->spacetype) {
case SPACE_ACTION: {
- SpaceAction *saction = sa->spacedata.first;
+ SpaceAction *saction = area->spacedata.first;
if (saction->flag & SACTION_SHOW_MARKERS) {
return true;
}
break;
}
case SPACE_GRAPH: {
- SpaceGraph *sipo = sa->spacedata.first;
+ SpaceGraph *sipo = area->spacedata.first;
if (sipo->mode != SIPO_MODE_DRIVERS && sipo->flag & SIPO_SHOW_MARKERS) {
return true;
}
break;
}
case SPACE_NLA: {
- SpaceNla *snla = sa->spacedata.first;
+ SpaceNla *snla = area->spacedata.first;
if (snla->flag & SNLA_SHOW_MARKERS) {
return true;
}
break;
}
case SPACE_SEQ: {
- SpaceSeq *seq = sa->spacedata.first;
+ SpaceSeq *seq = area->spacedata.first;
if (seq->flag & SEQ_SHOW_MARKERS) {
return true;
}
@@ -358,7 +358,7 @@ void ED_markers_deselect_all(ListBase *markers, int action)
action = ED_markers_get_first_selected(markers) ? SEL_DESELECT : SEL_SELECT;
}
- for (TimeMarker *marker = markers->first; marker; marker = marker->next) {
+ LISTBASE_FOREACH (TimeMarker *, marker, markers) {
if (action == SEL_SELECT) {
marker->flag |= SELECT;
}
@@ -528,7 +528,7 @@ static void draw_markers_background(rctf *rect)
uint pos = GPU_vertformat_attr_add(immVertexFormat(), "pos", GPU_COMP_F32, 2, GPU_FETCH_FLOAT);
immBindBuiltinProgram(GPU_SHADER_2D_UNIFORM_COLOR);
- unsigned char shade[4];
+ uchar shade[4];
UI_GetThemeColor4ubv(TH_TIME_SCRUB_BACKGROUND, shade);
immUniformColor4ubv(shade);
@@ -599,14 +599,14 @@ void ED_markers_draw(const bContext *C, int flag)
const uiFontStyle *fstyle = UI_FSTYLE_WIDGET;
/* Separate loops in order to draw selected markers on top */
- for (TimeMarker *marker = markers->first; marker; marker = marker->next) {
+ LISTBASE_FOREACH (TimeMarker *, marker, markers) {
if ((marker->flag & SELECT) == 0) {
if (marker_is_in_frame_range(marker, clip_frame_range)) {
draw_marker(fstyle, marker, cfra, marker->frame * xscale, flag, region->winy);
}
}
}
- for (TimeMarker *marker = markers->first; marker; marker = marker->next) {
+ LISTBASE_FOREACH (TimeMarker *, marker, markers) {
if (marker->flag & SELECT) {
if (marker_is_in_frame_range(marker, clip_frame_range)) {
draw_marker(fstyle, marker, cfra, marker->frame * xscale, flag, region->winy);
@@ -906,7 +906,7 @@ static int ed_marker_move_invoke(bContext *C, wmOperator *op, const wmEvent *eve
static void ed_marker_move_apply(bContext *C, wmOperator *op)
{
#ifdef DURIAN_CAMERA_SWITCH
- bScreen *sc = CTX_wm_screen(C);
+ bScreen *screen = CTX_wm_screen(C);
Scene *scene = CTX_data_scene(C);
Object *camera = scene->camera;
#endif
@@ -930,7 +930,7 @@ static void ed_marker_move_apply(bContext *C, wmOperator *op)
BKE_scene_camera_switch_update(scene);
if (camera != scene->camera) {
- BKE_screen_view3d_scene_sync(sc, scene);
+ BKE_screen_view3d_scene_sync(screen, scene);
WM_event_add_notifier(C, NC_SCENE | NA_EDITED, scene);
}
#endif
@@ -1156,7 +1156,7 @@ static void MARKER_OT_duplicate(wmOperatorType *ot)
static void deselect_markers(ListBase *markers)
{
- for (TimeMarker *marker = markers->first; marker; marker = marker->next) {
+ LISTBASE_FOREACH (TimeMarker *, marker, markers) {
marker->flag &= ~SELECT;
}
}
@@ -1373,7 +1373,7 @@ static int ed_marker_box_select_exec(bContext *C, wmOperator *op)
ED_markers_deselect_all(markers, SEL_DESELECT);
}
- for (TimeMarker *marker = markers->first; marker; marker = marker->next) {
+ LISTBASE_FOREACH (TimeMarker *, marker, markers) {
if (BLI_rctf_isect_x(&rect, marker->frame)) {
SET_FLAG_FROM_TEST(marker->flag, select, SELECT);
}
@@ -1621,7 +1621,7 @@ static void MARKER_OT_make_links_scene(wmOperatorType *ot)
static int ed_marker_camera_bind_exec(bContext *C, wmOperator *op)
{
- bScreen *sc = CTX_wm_screen(C);
+ bScreen *screen = CTX_wm_screen(C);
Scene *scene = CTX_data_scene(C);
Object *ob = CTX_data_active_object(C);
ListBase *markers = ED_context_get_markers(C);
@@ -1646,7 +1646,7 @@ static int ed_marker_camera_bind_exec(bContext *C, wmOperator *op)
BLI_addtail(markers, marker);
/* deselect all others, so that the user can then move it without problems */
- for (TimeMarker *m = markers->first; m; m = m->next) {
+ LISTBASE_FOREACH (TimeMarker *, m, markers) {
if (m != marker) {
m->flag &= ~SELECT;
}
@@ -1658,7 +1658,7 @@ static int ed_marker_camera_bind_exec(bContext *C, wmOperator *op)
/* camera may have changes */
BKE_scene_camera_switch_update(scene);
- BKE_screen_view3d_scene_sync(sc, scene);
+ BKE_screen_view3d_scene_sync(screen, scene);
WM_event_add_notifier(C, NC_SCENE | ND_MARKERS, NULL);
WM_event_add_notifier(C, NC_ANIMATION | ND_MARKERS, NULL);
diff --git a/source/blender/editors/animation/anim_motion_paths.c b/source/blender/editors/animation/anim_motion_paths.c
index 7e36799ff1b..4c10c66dfa6 100644
--- a/source/blender/editors/animation/anim_motion_paths.c
+++ b/source/blender/editors/animation/anim_motion_paths.c
@@ -31,7 +31,7 @@
#include "DNA_scene_types.h"
#include "BKE_action.h"
-#include "BKE_animsys.h"
+#include "BKE_anim_data.h"
#include "BKE_main.h"
#include "BKE_scene.h"
@@ -228,7 +228,7 @@ static void motionpath_get_global_framerange(ListBase *targets, int *r_sfra, int
{
*r_sfra = INT_MAX;
*r_efra = INT_MIN;
- for (MPathTarget *mpt = targets->first; mpt; mpt = mpt->next) {
+ LISTBASE_FOREACH (MPathTarget *, mpt, targets) {
*r_sfra = min_ii(*r_sfra, mpt->mpath->start_frame);
*r_efra = max_ii(*r_efra, mpt->mpath->end_frame);
}
@@ -348,7 +348,7 @@ static void motionpath_calculate_update_range(MPathTarget *mpt,
static void motionpath_free_free_tree_data(ListBase *targets)
{
- for (MPathTarget *mpt = targets->first; mpt; mpt = mpt->next) {
+ LISTBASE_FOREACH (MPathTarget *, mpt, targets) {
BLI_dlrbTree_free(&mpt->keys);
}
}
@@ -412,7 +412,7 @@ void animviz_calc_motionpaths(Depsgraph *depsgraph,
DEG_make_inactive(depsgraph);
}
- for (MPathTarget *mpt = targets->first; mpt; mpt = mpt->next) {
+ LISTBASE_FOREACH (MPathTarget *, mpt, targets) {
mpt->ob_eval = DEG_get_evaluated_object(depsgraph, mpt->ob);
AnimData *adt = BKE_animdata_from_id(&mpt->ob_eval->id);
@@ -492,7 +492,7 @@ void animviz_calc_motionpaths(Depsgraph *depsgraph,
}
/* clear recalc flags from targets */
- for (MPathTarget *mpt = targets->first; mpt; mpt = mpt->next) {
+ LISTBASE_FOREACH (MPathTarget *, mpt, targets) {
bMotionPath *mpath = mpt->mpath;
/* get pointer to animviz settings for each target */
diff --git a/source/blender/editors/animation/anim_ops.c b/source/blender/editors/animation/anim_ops.c
index 6b0d11802f4..40cd368e02b 100644
--- a/source/blender/editors/animation/anim_ops.c
+++ b/source/blender/editors/animation/anim_ops.c
@@ -49,6 +49,7 @@
#include "ED_anim_api.h"
#include "ED_screen.h"
#include "ED_sequencer.h"
+#include "ED_time_scrub_ui.h"
#include "ED_util.h"
#include "DEG_depsgraph.h"
@@ -61,7 +62,7 @@
/* Check if the operator can be run from the current context */
static bool change_frame_poll(bContext *C)
{
- ScrArea *sa = CTX_wm_area(C);
+ ScrArea *area = CTX_wm_area(C);
/* XXX temp? prevent changes during render */
if (G.is_rendering) {
@@ -71,16 +72,10 @@ static bool change_frame_poll(bContext *C)
/* although it's only included in keymaps for regions using ED_KEYMAP_ANIMATION,
* this shouldn't show up in 3D editor (or others without 2D timeline view) via search
*/
- if (sa) {
- if (ELEM(sa->spacetype, SPACE_ACTION, SPACE_NLA, SPACE_SEQ, SPACE_CLIP)) {
+ if (area) {
+ if (ELEM(area->spacetype, SPACE_ACTION, SPACE_NLA, SPACE_SEQ, SPACE_CLIP, SPACE_GRAPH)) {
return true;
}
- else if (sa->spacetype == SPACE_GRAPH) {
- /* NOTE: Graph Editor has special version which does some extra stuff.
- * No need to show the generic error message for that case though!
- */
- return false;
- }
}
CTX_wm_operator_poll_msg_set(C, "Expected an animation area to be active");
@@ -151,11 +146,13 @@ static float frame_from_event(bContext *C, const wmEvent *event)
static void change_frame_seq_preview_begin(bContext *C, const wmEvent *event)
{
- ScrArea *sa = CTX_wm_area(C);
+ ScrArea *area = CTX_wm_area(C);
bScreen *screen = CTX_wm_screen(C);
- if (sa && sa->spacetype == SPACE_SEQ) {
- SpaceSeq *sseq = sa->spacedata.first;
- if (ED_space_sequencer_check_show_strip(sseq)) {
+ if (area && area->spacetype == SPACE_SEQ) {
+ SpaceSeq *sseq = area->spacedata.first;
+ ARegion *region = CTX_wm_region(C);
+ if (ED_space_sequencer_check_show_strip(sseq) &&
+ !ED_time_scrub_event_in_region(region, event)) {
ED_sequencer_special_preview_set(C, event->mval);
}
}
@@ -282,7 +279,7 @@ static void ANIM_OT_change_frame(wmOperatorType *ot)
static bool anim_set_end_frames_poll(bContext *C)
{
- ScrArea *sa = CTX_wm_area(C);
+ ScrArea *area = CTX_wm_area(C);
/* XXX temp? prevent changes during render */
if (G.is_rendering) {
@@ -292,8 +289,8 @@ static bool anim_set_end_frames_poll(bContext *C)
/* although it's only included in keymaps for regions using ED_KEYMAP_ANIMATION,
* this shouldn't show up in 3D editor (or others without 2D timeline view) via search
*/
- if (sa) {
- if (ELEM(sa->spacetype, SPACE_ACTION, SPACE_GRAPH, SPACE_NLA, SPACE_SEQ, SPACE_CLIP)) {
+ if (area) {
+ if (ELEM(area->spacetype, SPACE_ACTION, SPACE_GRAPH, SPACE_NLA, SPACE_SEQ, SPACE_CLIP)) {
return true;
}
}
diff --git a/source/blender/editors/animation/drivers.c b/source/blender/editors/animation/drivers.c
index ee0f403a155..328e435877c 100644
--- a/source/blender/editors/animation/drivers.c
+++ b/source/blender/editors/animation/drivers.c
@@ -36,9 +36,11 @@
#include "DNA_space_types.h"
#include "DNA_texture_types.h"
+#include "BKE_anim_data.h"
#include "BKE_animsys.h"
#include "BKE_context.h"
#include "BKE_fcurve.h"
+#include "BKE_fcurve_driver.h"
#include "BKE_report.h"
#include "DEG_depsgraph.h"
@@ -90,7 +92,7 @@ FCurve *verify_driver_fcurve(ID *id,
* - add if not found and allowed to add one
* TODO: add auto-grouping support? how this works will need to be resolved
*/
- fcu = list_find_fcurve(&adt->drivers, rna_path, array_index);
+ fcu = BKE_fcurve_find(&adt->drivers, rna_path, array_index);
if (fcu == NULL && creation_mode != DRIVER_FCURVE_LOOKUP_ONLY) {
/* use default settings to make a F-Curve */
@@ -108,7 +110,7 @@ struct FCurve *alloc_driver_fcurve(const char rna_path[],
const int array_index,
eDriverFCurveCreationMode creation_mode)
{
- FCurve *fcu = MEM_callocN(sizeof(FCurve), "FCurve");
+ FCurve *fcu = BKE_fcurve_create();
fcu->flag = (FCURVE_VISIBLE | FCURVE_SELECTED);
fcu->auto_smoothing = U.auto_smoothing_new;
@@ -568,13 +570,13 @@ bool ANIM_remove_driver(ReportList *UNUSED(reports),
/* step through all drivers, removing all of those with the same base path */
FCurve *fcu_iter = adt->drivers.first;
- while ((fcu = iter_step_fcurve(fcu_iter, rna_path)) != NULL) {
+ while ((fcu = BKE_fcurve_iter_step(fcu_iter, rna_path)) != NULL) {
/* store the next fcurve for looping */
fcu_iter = fcu->next;
/* remove F-Curve from driver stack, then free it */
BLI_remlink(&adt->drivers, fcu);
- free_fcurve(fcu);
+ BKE_fcurve_free(fcu);
/* done successfully */
success = true;
@@ -588,7 +590,7 @@ bool ANIM_remove_driver(ReportList *UNUSED(reports),
fcu = verify_driver_fcurve(id, rna_path, array_index, DRIVER_FCURVE_LOOKUP_ONLY);
if (fcu) {
BLI_remlink(&adt->drivers, fcu);
- free_fcurve(fcu);
+ BKE_fcurve_free(fcu);
success = true;
}
@@ -609,7 +611,7 @@ void ANIM_drivers_copybuf_free(void)
{
/* free the buffer F-Curve if it exists, as if it were just another F-Curve */
if (channeldriver_copypaste_buf) {
- free_fcurve(channeldriver_copypaste_buf);
+ BKE_fcurve_free(channeldriver_copypaste_buf);
}
channeldriver_copypaste_buf = NULL;
}
@@ -660,7 +662,7 @@ bool ANIM_copy_driver(
fcu->rna_path = NULL;
/* make a copy of the F-Curve with */
- channeldriver_copypaste_buf = copy_fcurve(fcu);
+ channeldriver_copypaste_buf = BKE_fcurve_copy(fcu);
/* restore the path */
fcu->rna_path = tmp_path;
@@ -979,7 +981,8 @@ static bool add_driver_button_poll(bContext *C)
}
/* Don't do anything if there is an fcurve for animation without a driver. */
- FCurve *fcu = rna_get_fcurve_context_ui(C, &ptr, prop, index, NULL, NULL, &driven, &special);
+ FCurve *fcu = BKE_fcurve_find_by_rna_context_ui(
+ C, &ptr, prop, index, NULL, NULL, &driven, &special);
return (fcu == NULL || fcu->driver);
}
diff --git a/source/blender/editors/animation/fmodifier_ui.c b/source/blender/editors/animation/fmodifier_ui.c
index 9bdfd9cfe33..eadaa449b92 100644
--- a/source/blender/editors/animation/fmodifier_ui.c
+++ b/source/blender/editors/animation/fmodifier_ui.c
@@ -42,7 +42,6 @@
#include "BLI_blenlib.h"
#include "BLI_utildefines.h"
-#include "BKE_animsys.h"
#include "BKE_context.h"
#include "BKE_fcurve.h"
@@ -178,7 +177,7 @@ static void draw_modifier__generator(uiLayout *layout,
const uiFontStyle *fstyle = UI_FSTYLE_WIDGET;
float *cp = NULL;
char xval[32];
- unsigned int i;
+ uint i;
int maxXWidth;
/* draw polynomial order selector */
@@ -317,7 +316,7 @@ static void draw_modifier__generator(uiLayout *layout,
case FCM_GENERATOR_POLYNOMIAL_FACTORISED: /* Factorized polynomial expression */
{
float *cp = NULL;
- unsigned int i;
+ uint i;
/* draw polynomial order selector */
row = uiLayoutRow(layout, false);
@@ -718,28 +717,31 @@ static void draw_modifier__envelope(uiLayout *layout,
/* control points list */
for (i = 0, fed = env->data; i < env->totvert; i++, fed++) {
+ PointerRNA ctrl_ptr;
+ RNA_pointer_create(fcurve_owner_id, &RNA_FModifierEnvelopeControlPoint, fed, &ctrl_ptr);
+
/* get a new row to operate on */
row = uiLayoutRow(layout, true);
block = uiLayoutGetBlock(row);
UI_block_align_begin(block);
- but = uiDefButF(block,
- UI_BTYPE_NUM,
- B_FMODIFIER_REDRAW,
- IFACE_("Fra:"),
- 0,
- 0,
- 4.5 * UI_UNIT_X,
- UI_UNIT_Y,
- &fed->time,
- -MAXFRAMEF,
- MAXFRAMEF,
- 10,
- 1,
- TIP_("Frame that envelope point occurs"));
- UI_but_func_set(but, validate_fmodifier_cb, fcm, NULL);
-
- uiDefButF(block,
+ uiDefButR(block,
+ UI_BTYPE_NUM,
+ B_FMODIFIER_REDRAW,
+ IFACE_("Fra:"),
+ 0,
+ 0,
+ 4.5 * UI_UNIT_X,
+ UI_UNIT_Y,
+ &ctrl_ptr,
+ "frame",
+ -1,
+ -MAXFRAMEF,
+ MAXFRAMEF,
+ 10,
+ 1,
+ NULL);
+ uiDefButR(block,
UI_BTYPE_NUM,
B_FMODIFIER_REDRAW,
IFACE_("Min:"),
@@ -747,13 +749,15 @@ static void draw_modifier__envelope(uiLayout *layout,
0,
5 * UI_UNIT_X,
UI_UNIT_Y,
- &fed->min,
+ &ctrl_ptr,
+ "min",
+ -1,
-UI_FLT_MAX,
UI_FLT_MAX,
10,
2,
- TIP_("Minimum bound of envelope at this point"));
- uiDefButF(block,
+ NULL);
+ uiDefButR(block,
UI_BTYPE_NUM,
B_FMODIFIER_REDRAW,
IFACE_("Max:"),
@@ -761,12 +765,14 @@ static void draw_modifier__envelope(uiLayout *layout,
0,
5 * UI_UNIT_X,
UI_UNIT_Y,
- &fed->max,
+ &ctrl_ptr,
+ "max",
+ -1,
-UI_FLT_MAX,
UI_FLT_MAX,
10,
2,
- TIP_("Maximum bound of envelope at this point"));
+ NULL);
but = uiDefIconBut(block,
UI_BTYPE_BUT,
diff --git a/source/blender/editors/animation/keyframes_draw.c b/source/blender/editors/animation/keyframes_draw.c
index 4b3b730d0fe..b921ba039be 100644
--- a/source/blender/editors/animation/keyframes_draw.c
+++ b/source/blender/editors/animation/keyframes_draw.c
@@ -31,6 +31,7 @@
#include "MEM_guardedalloc.h"
#include "BLI_dlrbTree.h"
+#include "BLI_listbase.h"
#include "BLI_math.h"
#include "BLI_rect.h"
#include "BLI_utildefines.h"
@@ -505,14 +506,14 @@ static void update_keyblocks(DLRBT_Tree *keys, BezTriple *bezt, int bezt_len)
/* Find the curve count */
int max_curve = 0;
- for (ActKeyColumn *col = keys->first; col; col = col->next) {
+ LISTBASE_FOREACH (ActKeyColumn *, col, keys) {
max_curve = MAX2(max_curve, col->totcurve);
}
/* Propagate blocks to inserted keys */
ActKeyColumn *prev_ready = NULL;
- for (ActKeyColumn *col = keys->first; col; col = col->next) {
+ LISTBASE_FOREACH (ActKeyColumn *, col, keys) {
/* Pre-existing column. */
if (col->totcurve > 0) {
prev_ready = col;
@@ -558,11 +559,11 @@ void draw_keyframe_shape(float x,
short key_type,
short mode,
float alpha,
- unsigned int pos_id,
- unsigned int size_id,
- unsigned int color_id,
- unsigned int outline_color_id,
- unsigned int flags_id,
+ uint pos_id,
+ uint size_id,
+ uint color_id,
+ uint outline_color_id,
+ uint flags_id,
short handle_type,
short extreme_type)
{
@@ -595,9 +596,9 @@ void draw_keyframe_shape(float x,
size -= 0.8f * key_type;
}
- unsigned char fill_col[4];
- unsigned char outline_col[4];
- unsigned int flags = 0;
+ uchar fill_col[4];
+ uchar outline_col[4];
+ uint flags = 0;
/* draw! */
if (draw_fill) {
@@ -730,7 +731,7 @@ static void draw_keylist(View2D *v2d,
ipo_color_mix[3] *= 0.5f;
uint block_len = 0;
- for (ActKeyColumn *ab = keys->first; ab; ab = ab->next) {
+ LISTBASE_FOREACH (ActKeyColumn *, ab, keys) {
if (actkeyblock_get_valid_hold(ab)) {
block_len++;
}
@@ -746,7 +747,7 @@ static void draw_keylist(View2D *v2d,
immBindBuiltinProgram(GPU_SHADER_2D_FLAT_COLOR);
immBegin(GPU_PRIM_TRIS, 6 * block_len);
- for (ActKeyColumn *ab = keys->first; ab; ab = ab->next) {
+ LISTBASE_FOREACH (ActKeyColumn *, ab, keys) {
int valid_hold = actkeyblock_get_valid_hold(ab);
if (valid_hold != 0) {
if ((valid_hold & ACTKEYBLOCK_FLAG_STATIC_HOLD) == 0) {
@@ -791,7 +792,7 @@ static void draw_keylist(View2D *v2d,
if (keys) {
/* count keys */
uint key_len = 0;
- for (ActKeyColumn *ak = keys->first; ak; ak = ak->next) {
+ LISTBASE_FOREACH (ActKeyColumn *, ak, keys) {
/* Optimization: if keyframe doesn't appear within 5 units (screenspace)
* in visible area, don't draw.
* This might give some improvements,
@@ -822,7 +823,7 @@ static void draw_keylist(View2D *v2d,
short handle_type = KEYFRAME_HANDLE_NONE, extreme_type = KEYFRAME_EXTREME_NONE;
- for (ActKeyColumn *ak = keys->first; ak; ak = ak->next) {
+ LISTBASE_FOREACH (ActKeyColumn *, ak, keys) {
if (IN_RANGE_INCL(ak->cfra, v2d->cur.xmin, v2d->cur.xmax)) {
if (show_ipo) {
handle_type = ak->handle_type;
@@ -1153,7 +1154,7 @@ void cachefile_to_keylist(bDopeSheet *ads,
ANIM_animdata_filter(&ac, &anim_data, filter, ac.data, ac.datatype);
/* loop through each F-Curve, grabbing the keyframes */
- for (bAnimListElem *ale = anim_data.first; ale; ale = ale->next) {
+ LISTBASE_FOREACH (bAnimListElem *, ale, &anim_data) {
fcurve_to_keylist(ale->adt, ale->data, keys, saction_flag);
}
diff --git a/source/blender/editors/animation/keyframes_edit.c b/source/blender/editors/animation/keyframes_edit.c
index 61488e7f63a..2dae4e8b4c5 100644
--- a/source/blender/editors/animation/keyframes_edit.c
+++ b/source/blender/editors/animation/keyframes_edit.c
@@ -79,7 +79,7 @@ short ANIM_fcurve_keyframes_loop(KeyframeEditData *ked,
{
BezTriple *bezt;
short ok = 0;
- unsigned int i;
+ uint i;
/* sanity check */
if (ELEM(NULL, fcu, fcu->bezt)) {
@@ -633,7 +633,7 @@ bool keyframe_region_lasso_test(const KeyframeEdit_LassoData *data_lasso, const
BLI_rctf_transform_pt_v(data_lasso->rectf_view, data_lasso->rectf_scaled, xy_view, xy);
if (BLI_lasso_is_point_inside(
- data_lasso->mcords, data_lasso->mcords_tot, xy_view[0], xy_view[1], INT_MAX)) {
+ data_lasso->mcoords, data_lasso->mcoords_len, xy_view[0], xy_view[1], INT_MAX)) {
return true;
}
}
diff --git a/source/blender/editors/animation/keyframes_general.c b/source/blender/editors/animation/keyframes_general.c
index c526c185383..fc9ec870496 100644
--- a/source/blender/editors/animation/keyframes_general.c
+++ b/source/blender/editors/animation/keyframes_general.c
@@ -1189,7 +1189,7 @@ short paste_animedit_keys(bAnimContext *ac,
* one F-Curve has been pasted into.
*/
for (pass = 0; pass < 3; pass++) {
- unsigned int totmatch = 0;
+ uint totmatch = 0;
for (ale = anim_data->first; ale; ale = ale->next) {
/* Find buffer item to paste from:
diff --git a/source/blender/editors/animation/keyframing.c b/source/blender/editors/animation/keyframing.c
index e66ebb1928c..2aa8d468e2d 100644
--- a/source/blender/editors/animation/keyframing.c
+++ b/source/blender/editors/animation/keyframing.c
@@ -45,10 +45,12 @@
#include "DNA_scene_types.h"
#include "BKE_action.h"
+#include "BKE_anim_data.h"
#include "BKE_animsys.h"
#include "BKE_armature.h"
#include "BKE_context.h"
#include "BKE_fcurve.h"
+#include "BKE_fcurve_driver.h"
#include "BKE_global.h"
#include "BKE_idtype.h"
#include "BKE_key.h"
@@ -182,7 +184,7 @@ FCurve *ED_action_fcurve_find(struct bAction *act, const char rna_path[], const
if (ELEM(NULL, act, rna_path)) {
return NULL;
}
- return list_find_fcurve(&act->curves, rna_path, array_index);
+ return BKE_fcurve_find(&act->curves, rna_path, array_index);
}
/**
@@ -208,11 +210,11 @@ FCurve *ED_action_fcurve_ensure(struct Main *bmain,
* - add if not found and allowed to add one
* TODO: add auto-grouping support? how this works will need to be resolved
*/
- fcu = list_find_fcurve(&act->curves, rna_path, array_index);
+ fcu = BKE_fcurve_find(&act->curves, rna_path, array_index);
if (fcu == NULL) {
/* use default settings to make a F-Curve */
- fcu = MEM_callocN(sizeof(FCurve), "FCurve");
+ fcu = BKE_fcurve_create();
fcu->flag = (FCURVE_VISIBLE | FCURVE_SELECTED);
fcu->auto_smoothing = U.auto_smoothing_new;
@@ -494,7 +496,7 @@ int insert_vert_fcurve(
FCurve *fcu, float x, float y, eBezTriple_KeyframeType keyframe_type, eInsertKeyFlags flag)
{
BezTriple beztr = {{{0}}};
- unsigned int oldTot = fcu->totvert;
+ uint oldTot = fcu->totvert;
int a;
/* set all three points, for nicer start position
@@ -1118,7 +1120,7 @@ static bool insert_keyframe_value(ReportList *reports,
eInsertKeyFlags flag)
{
/* F-Curve not editable? */
- if (fcurve_is_keyframable(fcu) == 0) {
+ if (BKE_fcurve_is_keyframable(fcu) == 0) {
BKE_reportf(
reports,
RPT_ERROR,
@@ -1793,11 +1795,11 @@ enum {
*/
static bool modify_key_op_poll(bContext *C)
{
- ScrArea *sa = CTX_wm_area(C);
+ ScrArea *area = CTX_wm_area(C);
Scene *scene = CTX_data_scene(C);
/* if no area or active scene */
- if (ELEM(NULL, sa, scene)) {
+ if (ELEM(NULL, area, scene)) {
return false;
}
@@ -1825,7 +1827,7 @@ static int insert_key_exec(bContext *C, wmOperator *op)
* updated since the last switching to the edit mode will be keyframed correctly
*/
if (obedit && ANIM_keyingset_find_id(ks, (ID *)obedit->data)) {
- ED_object_mode_toggle(C, OB_MODE_EDIT);
+ ED_object_mode_set(C, OB_MODE_OBJECT);
ob_edit_mode = true;
}
@@ -1841,7 +1843,7 @@ static int insert_key_exec(bContext *C, wmOperator *op)
/* restore the edit mode if necessary */
if (ob_edit_mode) {
- ED_object_mode_toggle(C, OB_MODE_EDIT);
+ ED_object_mode_set(C, OB_MODE_EDIT);
}
/* report failure or do updates? */
@@ -2398,7 +2400,7 @@ static int insert_key_button_exec(bContext *C, wmOperator *op)
* not have any effect.
*/
NlaStrip *strip = ptr.data;
- FCurve *fcu = list_find_fcurve(&strip->fcurves, RNA_property_identifier(prop), index);
+ FCurve *fcu = BKE_fcurve_find(&strip->fcurves, RNA_property_identifier(prop), index);
if (fcu) {
changed = insert_keyframe_direct(
@@ -2415,7 +2417,7 @@ static int insert_key_button_exec(bContext *C, wmOperator *op)
FCurve *fcu;
bool driven, special;
- fcu = rna_get_fcurve_context_ui(C, &ptr, prop, index, NULL, NULL, &driven, &special);
+ fcu = BKE_fcurve_find_by_rna_context_ui(C, &ptr, prop, index, NULL, NULL, &driven, &special);
if (fcu && driven) {
changed = insert_keyframe_direct(
@@ -2558,7 +2560,7 @@ static int delete_key_button_exec(bContext *C, wmOperator *op)
*/
ID *id = ptr.owner_id;
NlaStrip *strip = ptr.data;
- FCurve *fcu = list_find_fcurve(&strip->fcurves, RNA_property_identifier(prop), 0);
+ FCurve *fcu = BKE_fcurve_find(&strip->fcurves, RNA_property_identifier(prop), 0);
if (fcu) {
if (BKE_fcurve_is_protected(fcu)) {
@@ -2999,7 +3001,8 @@ bool ED_autokeyframe_property(
bool special;
bool changed = false;
- fcu = rna_get_fcurve_context_ui(C, ptr, prop, rnaindex, NULL, &action, &driven, &special);
+ fcu = BKE_fcurve_find_by_rna_context_ui(
+ C, ptr, prop, rnaindex, NULL, &action, &driven, &special);
if (fcu == NULL) {
return changed;
diff --git a/source/blender/editors/animation/keyingsets.c b/source/blender/editors/animation/keyingsets.c
index d30d03a1c73..89c7860982b 100644
--- a/source/blender/editors/animation/keyingsets.c
+++ b/source/blender/editors/animation/keyingsets.c
@@ -646,8 +646,8 @@ void ANIM_keyingset_infos_exit(void)
next = ksi->next;
/* free extra RNA data, and remove from list */
- if (ksi->ext.free) {
- ksi->ext.free(ksi->ext.data);
+ if (ksi->rna_ext.free) {
+ ksi->rna_ext.free(ksi->rna_ext.data);
}
BLI_freelinkN(&keyingset_type_infos, ksi);
}
diff --git a/source/blender/editors/animation/time_scrub_ui.c b/source/blender/editors/animation/time_scrub_ui.c
index 25b8e78de92..7679995d9a4 100644
--- a/source/blender/editors/animation/time_scrub_ui.c
+++ b/source/blender/editors/animation/time_scrub_ui.c
@@ -95,7 +95,7 @@ static void draw_current_frame(const Scene *scene,
int current_frame)
{
const uiFontStyle *fstyle = UI_FSTYLE_WIDGET;
- const unsigned char color[] = {255, 255, 255, 255};
+ const uchar color[] = {255, 255, 255, 255};
int frame_x = UI_view2d_view_to_region_x(v2d, current_frame);
char frame_str[64];
diff --git a/source/blender/editors/armature/armature_add.c b/source/blender/editors/armature/armature_add.c
index e87040279af..895b4953992 100644
--- a/source/blender/editors/armature/armature_add.c
+++ b/source/blender/editors/armature/armature_add.c
@@ -22,6 +22,7 @@
* \ingroup edarmature
*/
+#include "DNA_anim_types.h"
#include "DNA_armature_types.h"
#include "DNA_constraint_types.h"
#include "DNA_object_types.h"
@@ -38,8 +39,12 @@
#include "BKE_constraint.h"
#include "BKE_context.h"
#include "BKE_deform.h"
+#include "BKE_fcurve.h"
#include "BKE_idprop.h"
#include "BKE_layer.h"
+#include "BKE_lib_id.h"
+#include "BKE_library.h"
+#include "BKE_main.h"
#include "RNA_access.h"
#include "RNA_define.h"
@@ -48,6 +53,7 @@
#include "WM_types.h"
#include "ED_armature.h"
+#include "ED_outliner.h"
#include "ED_screen.h"
#include "ED_view3d.h"
@@ -217,6 +223,7 @@ static int armature_click_extrude_exec(bContext *C, wmOperator *UNUSED(op))
WM_event_add_notifier(C, NC_OBJECT | ND_BONE_SELECT, obedit);
DEG_id_tag_update(&obedit->id, ID_RECALC_SELECT);
+ ED_outliner_select_sync_from_edit_bone_tag(C);
return OPERATOR_FINISHED;
}
@@ -341,7 +348,7 @@ void postEditBoneDuplicate(struct ListBase *editbones, Object *ob)
GHash *name_map = BLI_ghash_str_new(__func__);
- for (EditBone *ebone_src = editbones->first; ebone_src; ebone_src = ebone_src->next) {
+ LISTBASE_FOREACH (EditBone *, ebone_src, editbones) {
EditBone *ebone_dst = ebone_src->temp.ebone;
if (!ebone_dst) {
ebone_dst = ED_armature_ebone_get_mirrored(editbones, ebone_src);
@@ -351,7 +358,7 @@ void postEditBoneDuplicate(struct ListBase *editbones, Object *ob)
}
}
- for (EditBone *ebone_src = editbones->first; ebone_src; ebone_src = ebone_src->next) {
+ LISTBASE_FOREACH (EditBone *, ebone_src, editbones) {
EditBone *ebone_dst = ebone_src->temp.ebone;
if (ebone_dst) {
bPoseChannel *pchan_src = BKE_pose_channel_find_name(ob->pose, ebone_src->name);
@@ -375,25 +382,20 @@ void postEditBoneDuplicate(struct ListBase *editbones, Object *ob)
BLI_ghash_free(name_map, NULL, NULL);
}
-/*
- * Note: When duplicating cross objects, editbones here is the list of bones
- * from the SOURCE object but ob is the DESTINATION object
- * */
-void updateDuplicateSubtargetObjects(EditBone *dupBone,
+static void updateDuplicateSubtarget(EditBone *dup_bone,
ListBase *editbones,
- Object *src_ob,
- Object *dst_ob)
+ Object *ob,
+ bool lookup_mirror_subtarget)
{
- /* If an edit bone has been duplicated, lets
- * update it's constraints if the subtarget
- * they point to has also been duplicated
+ /* If an edit bone has been duplicated, lets update it's constraints if the
+ * subtarget they point to has also been duplicated.
*/
EditBone *oldtarget, *newtarget;
bPoseChannel *pchan;
bConstraint *curcon;
ListBase *conlist;
- if ((pchan = BKE_pose_channel_verify(dst_ob->pose, dupBone->name))) {
+ if ((pchan = BKE_pose_channel_verify(ob->pose, dup_bone->name))) {
if ((conlist = &pchan->constraints)) {
for (curcon = conlist->first; curcon; curcon = curcon->next) {
/* does this constraint have a subtarget in
@@ -407,8 +409,7 @@ void updateDuplicateSubtargetObjects(EditBone *dupBone,
cti->get_constraint_targets(curcon, &targets);
for (ct = targets.first; ct; ct = ct->next) {
- if ((ct->tar == src_ob) && (ct->subtarget[0])) {
- ct->tar = dst_ob; /* update target */
+ if ((ct->tar == ob) && (ct->subtarget[0])) {
oldtarget = get_named_editbone(editbones, ct->subtarget);
if (oldtarget) {
/* was the subtarget bone duplicated too? If
@@ -419,6 +420,17 @@ void updateDuplicateSubtargetObjects(EditBone *dupBone,
newtarget = oldtarget->temp.ebone;
BLI_strncpy(ct->subtarget, newtarget->name, sizeof(ct->subtarget));
}
+ else if (lookup_mirror_subtarget) {
+ /* The subtarget was not selected for duplication, try to see if a mirror bone of
+ * the current target exists */
+ char name_flip[MAXBONENAME];
+
+ BLI_string_flip_side_name(name_flip, oldtarget->name, false, sizeof(name_flip));
+ newtarget = get_named_editbone(editbones, name_flip);
+ if (newtarget) {
+ BLI_strncpy(ct->subtarget, newtarget->name, sizeof(ct->subtarget));
+ }
+ }
}
}
}
@@ -432,32 +444,434 @@ void updateDuplicateSubtargetObjects(EditBone *dupBone,
}
}
-void updateDuplicateSubtarget(EditBone *dupBone, ListBase *editbones, Object *ob)
+static void updateDuplicateActionConstraintSettings(EditBone *dup_bone,
+ EditBone *orig_bone,
+ Object *ob,
+ bConstraint *curcon)
{
- updateDuplicateSubtargetObjects(dupBone, editbones, ob, ob);
+ bActionConstraint *act_con = (bActionConstraint *)curcon->data;
+ bAction *act = (bAction *)act_con->act;
+
+ float mat[4][4];
+
+ unit_m4(mat);
+ bPoseChannel *target_pchan = BKE_pose_channel_find_name(ob->pose, act_con->subtarget);
+ BKE_constraint_mat_convertspace(
+ ob, target_pchan, mat, curcon->tarspace, CONSTRAINT_SPACE_LOCAL, false);
+
+ float max_axis_val = 0;
+ int max_axis = 0;
+ /* Which axis represents X now. IE, which axis defines the mirror plane. */
+ for (int i = 0; i < 3; i++) {
+ float cur_val = fabsf(mat[0][i]);
+ if (cur_val > max_axis_val) {
+ max_axis = i;
+ max_axis_val = cur_val;
+ }
+ }
+
+ /* data->type is mapped as follows for backwards compatibility:
+ * 00,01,02 - rotation (it used to be like this)
+ * 10,11,12 - scaling
+ * 20,21,22 - location
+ */
+ /* Mirror the target range */
+ if (act_con->type < 10 && act_con->type != max_axis) {
+ /* Y or Z rotation */
+ act_con->min = -act_con->min;
+ act_con->max = -act_con->max;
+ }
+ else if (act_con->type == max_axis + 10) {
+ /* X scaling */
+ }
+ else if (act_con->type == max_axis + 20) {
+ /* X location */
+ float imat[4][4];
+
+ invert_m4_m4(imat, mat);
+
+ float min_vec[3], max_vec[3];
+
+ zero_v3(min_vec);
+ zero_v3(max_vec);
+
+ min_vec[0] = act_con->min;
+ max_vec[0] = act_con->max;
+
+ /* convert values into local object space */
+ mul_m4_v3(mat, min_vec);
+ mul_m4_v3(mat, max_vec);
+
+ min_vec[0] *= -1;
+ max_vec[0] *= -1;
+
+ /* convert back to the settings space */
+ mul_m4_v3(imat, min_vec);
+ mul_m4_v3(imat, max_vec);
+
+ act_con->min = min_vec[0];
+ act_con->max = max_vec[0];
+ }
+
+ /* See if there is any channels that uses this bone */
+ ListBase ani_curves;
+ BLI_listbase_clear(&ani_curves);
+ if (BKE_fcurves_filter(&ani_curves, &act->curves, "pose.bones[", orig_bone->name)) {
+ /* Create a copy and mirror the animation */
+ for (LinkData *ld = ani_curves.first; ld; ld = ld->next) {
+ FCurve *old_curve = ld->data;
+ FCurve *new_curve = BKE_fcurve_copy(old_curve);
+ bActionGroup *agrp;
+
+ char *old_path = new_curve->rna_path;
+
+ new_curve->rna_path = BLI_str_replaceN(old_path, orig_bone->name, dup_bone->name);
+ MEM_freeN(old_path);
+
+ /* Flip the animation */
+ int i;
+ BezTriple *bezt;
+ for (i = 0, bezt = new_curve->bezt; i < new_curve->totvert; i++, bezt++) {
+ const size_t slength = strlen(new_curve->rna_path);
+ bool flip = false;
+ if (BLI_strn_endswith(new_curve->rna_path, "location", slength) &&
+ new_curve->array_index == 0) {
+ flip = true;
+ }
+ else if (BLI_strn_endswith(new_curve->rna_path, "rotation_quaternion", slength) &&
+ ELEM(new_curve->array_index, 2, 3)) {
+ flip = true;
+ }
+ else if (BLI_strn_endswith(new_curve->rna_path, "rotation_euler", slength) &&
+ ELEM(new_curve->array_index, 1, 2)) {
+ flip = true;
+ }
+ else if (BLI_strn_endswith(new_curve->rna_path, "rotation_axis_angle", slength) &&
+ ELEM(new_curve->array_index, 2, 3)) {
+ flip = true;
+ }
+
+ if (flip) {
+ bezt->vec[0][1] *= -1;
+ bezt->vec[1][1] *= -1;
+ bezt->vec[2][1] *= -1;
+ }
+ }
+
+ /* Make sure that a action group name for the new bone exists */
+ agrp = BKE_action_group_find_name(act, dup_bone->name);
+
+ if (agrp == NULL) {
+ agrp = action_groups_add_new(act, dup_bone->name);
+ }
+ BLI_assert(agrp != NULL);
+ action_groups_add_channel(act, agrp, new_curve);
+ }
+ }
+ BLI_freelistN(&ani_curves);
+
+ /* Make deps graph aware of our changes */
+ DEG_id_tag_update(&act->id, ID_RECALC_ANIMATION_NO_FLUSH);
}
-EditBone *duplicateEditBoneObjects(
- EditBone *curBone, const char *name, ListBase *editbones, Object *src_ob, Object *dst_ob)
+static void updateDuplicateKinematicConstraintSettings(bConstraint *curcon)
{
- EditBone *eBone = MEM_mallocN(sizeof(EditBone), "addup_editbone");
+ /* IK constraint */
+ bKinematicConstraint *ik = (bKinematicConstraint *)curcon->data;
+ ik->poleangle = -M_PI - ik->poleangle;
+ /* Wrap the angle to the +/-180.0f range (default soft limit of the input boxes). */
+ ik->poleangle = angle_wrap_rad(ik->poleangle);
+}
- /* Copy data from old bone to new bone */
- memcpy(eBone, curBone, sizeof(EditBone));
+static void updateDuplicateLocRotConstraintSettings(Object *ob,
+ bPoseChannel *pchan,
+ bConstraint *curcon)
+{
+ /* This code assumes that bRotLimitConstraint and bLocLimitConstraint have the same fields in
+ * the same memory locations. */
+ BLI_assert(sizeof(bLocLimitConstraint) == sizeof(bRotLimitConstraint));
- curBone->temp.ebone = eBone;
- eBone->temp.ebone = curBone;
+ bRotLimitConstraint *limit = (bRotLimitConstraint *)curcon->data;
+ float local_mat[4][4], imat[4][4];
- if (name != NULL) {
- BLI_strncpy(eBone->name, name, sizeof(eBone->name));
+ float min_vec[3], max_vec[3];
+
+ min_vec[0] = limit->xmin;
+ min_vec[1] = limit->ymin;
+ min_vec[2] = limit->zmin;
+
+ max_vec[0] = limit->xmax;
+ max_vec[1] = limit->ymax;
+ max_vec[2] = limit->zmax;
+
+ unit_m4(local_mat);
+
+ BKE_constraint_mat_convertspace(
+ ob, pchan, local_mat, curcon->ownspace, CONSTRAINT_SPACE_LOCAL, false);
+
+ if (curcon->type == CONSTRAINT_TYPE_ROTLIMIT) {
+ /* Zero out any location translation */
+ local_mat[3][0] = local_mat[3][1] = local_mat[3][2] = 0;
+ }
+
+ invert_m4_m4(imat, local_mat);
+ /* convert values into local object space */
+ mul_m4_v3(local_mat, min_vec);
+ mul_m4_v3(local_mat, max_vec);
+
+ if (curcon->type == CONSTRAINT_TYPE_ROTLIMIT) {
+ float min_copy[3];
+
+ copy_v3_v3(min_copy, min_vec);
+
+ min_vec[1] = max_vec[1] * -1;
+ min_vec[2] = max_vec[2] * -1;
+
+ max_vec[1] = min_copy[1] * -1;
+ max_vec[2] = min_copy[2] * -1;
+ }
+ else {
+ float min_x_copy = min_vec[0];
+
+ min_vec[0] = max_vec[0] * -1;
+ max_vec[0] = min_x_copy * -1;
+ }
+
+ /* convert back to the settings space */
+ mul_m4_v3(imat, min_vec);
+ mul_m4_v3(imat, max_vec);
+
+ limit->xmin = min_vec[0];
+ limit->ymin = min_vec[1];
+ limit->zmin = min_vec[2];
+
+ limit->xmax = max_vec[0];
+ limit->ymax = max_vec[1];
+ limit->zmax = max_vec[2];
+}
+
+static void updateDuplicateTransformConstraintSettings(Object *ob,
+ bPoseChannel *pchan,
+ bConstraint *curcon)
+{
+ bTransformConstraint *trans = (bTransformConstraint *)curcon->data;
+
+ float target_mat[4][4], own_mat[4][4], imat[4][4];
+
+ unit_m4(own_mat);
+ BKE_constraint_mat_convertspace(
+ ob, pchan, own_mat, curcon->ownspace, CONSTRAINT_SPACE_LOCAL, false);
+
+ /* ###Source map mirroring### */
+ float old_min, old_max;
+
+ /* Source location */
+ invert_m4_m4(imat, own_mat);
+
+ /* convert values into local object space */
+ mul_m4_v3(own_mat, trans->from_min);
+ mul_m4_v3(own_mat, trans->from_max);
+
+ old_min = trans->from_min[0];
+ old_max = trans->from_max[0];
+
+ trans->from_min[0] = -old_max;
+ trans->from_max[0] = -old_min;
+
+ /* convert back to the settings space */
+ mul_m4_v3(imat, trans->from_min);
+ mul_m4_v3(imat, trans->from_max);
+
+ /* Source rotation */
+
+ /* Zero out any location translation */
+ own_mat[3][0] = own_mat[3][1] = own_mat[3][2] = 0;
+
+ invert_m4_m4(imat, own_mat);
+
+ /* convert values into local object space */
+ mul_m4_v3(own_mat, trans->from_min_rot);
+ mul_m4_v3(own_mat, trans->from_max_rot);
+
+ old_min = trans->from_min_rot[1];
+ old_max = trans->from_max_rot[1];
+
+ trans->from_min_rot[1] = old_max * -1;
+ trans->from_max_rot[1] = old_min * -1;
+
+ old_min = trans->from_min_rot[2];
+ old_max = trans->from_max_rot[2];
+
+ trans->from_min_rot[2] = old_max * -1;
+ trans->from_max_rot[2] = old_min * -1;
+
+ /* convert back to the settings space */
+ mul_m4_v3(imat, trans->from_min_rot);
+ mul_m4_v3(imat, trans->from_max_rot);
+
+ /* Source scale does not require any mirroring */
+
+ /* ###Destination map mirroring### */
+ float temp_vec[3];
+ float imat_rot[4][4];
+
+ bPoseChannel *target_pchan = BKE_pose_channel_find_name(ob->pose, trans->subtarget);
+ unit_m4(target_mat);
+ BKE_constraint_mat_convertspace(
+ ob, target_pchan, target_mat, curcon->tarspace, CONSTRAINT_SPACE_LOCAL, false);
+
+ invert_m4_m4(imat, target_mat);
+ /* convert values into local object space */
+ mul_m4_v3(target_mat, trans->to_min);
+ mul_m4_v3(target_mat, trans->to_max);
+ mul_m4_v3(target_mat, trans->to_min_scale);
+ mul_m4_v3(target_mat, trans->to_max_scale);
+
+ /* Zero out any location translation */
+ target_mat[3][0] = target_mat[3][1] = target_mat[3][2] = 0;
+ invert_m4_m4(imat_rot, target_mat);
+
+ mul_m4_v3(target_mat, trans->to_min_rot);
+ mul_m4_v3(target_mat, trans->to_max_rot);
+
+ /* TODO(sebpa): This does not support euler order, but doing so will make this way more complex.
+ * For now we have decided to not support all corner cases and advanced setups. */
+
+ /* Helper variables to denote the axis in trans->map */
+ const char X = 0;
+ const char Y = 1;
+ const char Z = 2;
+
+ switch (trans->to) {
+ case TRANS_SCALE:
+ copy_v3_v3(temp_vec, trans->to_max_scale);
+
+ for (int i = 0; i < 3; i++) {
+ if ((trans->from == TRANS_LOCATION && trans->map[i] == X) ||
+ (trans->from == TRANS_ROTATION && trans->map[i] != X)) {
+ /* X Loc to X/Y/Z Scale: Min/Max Flipped */
+ /* Y Rot to X/Y/Z Scale: Min/Max Flipped */
+ /* Z Rot to X/Y/Z Scale: Min/Max Flipped */
+ trans->to_max_scale[i] = trans->to_min_scale[i];
+ trans->to_min_scale[i] = temp_vec[i];
+ }
+ }
+ break;
+ case TRANS_LOCATION:
+ /* Invert the X location */
+ trans->to_min[0] *= -1;
+ trans->to_max[0] *= -1;
+
+ copy_v3_v3(temp_vec, trans->to_max);
+
+ for (int i = 0; i < 3; i++) {
+ if ((trans->from == TRANS_LOCATION && trans->map[i] == X) ||
+ (trans->from == TRANS_ROTATION && trans->map[i] != X)) {
+ /* X Loc to X/Y/Z Loc: Min/Max Flipped (and Inverted)
+ * Y Rot to X/Y/Z Loc: Min/Max Flipped
+ * Z Rot to X/Y/Z Loc: Min/Max Flipped */
+ trans->to_max[i] = trans->to_min[i];
+ trans->to_min[i] = temp_vec[i];
+ }
+ }
+ break;
+ case TRANS_ROTATION:
+ /* Invert the Z rotation */
+ trans->to_min_rot[2] *= -1;
+ trans->to_max_rot[2] *= -1;
+
+ if ((trans->from == TRANS_LOCATION && trans->map[1] != X) ||
+ (trans->from == TRANS_ROTATION && trans->map[1] != Y) || trans->from == TRANS_SCALE) {
+ /* Invert the Y rotation */
+ trans->to_min_rot[1] *= -1;
+ trans->to_max_rot[1] *= -1;
+ }
+
+ copy_v3_v3(temp_vec, trans->to_max_rot);
+
+ for (int i = 0; i < 3; i++) {
+ if ((trans->from == TRANS_LOCATION && trans->map[i] == X && i != 1) ||
+ (trans->from == TRANS_ROTATION && trans->map[i] == Y && i != 1) ||
+ (trans->from == TRANS_ROTATION && trans->map[i] == Z)) {
+ /* X Loc to X/Z Rot: Flipped
+ * Y Rot to X/Z Rot: Flipped
+ * Z Rot to X/Y/Z rot: Flipped */
+ trans->to_max_rot[i] = trans->to_min_rot[i];
+ trans->to_min_rot[i] = temp_vec[i];
+ }
+ }
+ break;
+ }
+ /* convert back to the settings space */
+ mul_m4_v3(imat, trans->to_min);
+ mul_m4_v3(imat, trans->to_max);
+ mul_m4_v3(imat_rot, trans->to_min_rot);
+ mul_m4_v3(imat_rot, trans->to_max_rot);
+ mul_m4_v3(imat, trans->to_min_scale);
+ mul_m4_v3(imat, trans->to_max_scale);
+}
+
+static void updateDuplicateConstraintSettings(EditBone *dup_bone, EditBone *orig_bone, Object *ob)
+{
+ /* If an edit bone has been duplicated, lets update it's constraints if the
+ * subtarget they point to has also been duplicated.
+ */
+ bPoseChannel *pchan;
+ bConstraint *curcon;
+ ListBase *conlist;
+
+ if ((pchan = BKE_pose_channel_verify(ob->pose, dup_bone->name)) == NULL ||
+ (conlist = &pchan->constraints) == NULL) {
+ return;
}
- ED_armature_ebone_unique_name(editbones, eBone->name, NULL);
- BLI_addtail(editbones, eBone);
+ for (curcon = conlist->first; curcon; curcon = curcon->next) {
+ switch (curcon->type) {
+ case CONSTRAINT_TYPE_ACTION:
+ updateDuplicateActionConstraintSettings(dup_bone, orig_bone, ob, curcon);
+ break;
+ case CONSTRAINT_TYPE_KINEMATIC:
+ updateDuplicateKinematicConstraintSettings(curcon);
+ break;
+ case CONSTRAINT_TYPE_LOCLIMIT:
+ case CONSTRAINT_TYPE_ROTLIMIT:
+ updateDuplicateLocRotConstraintSettings(ob, pchan, curcon);
+ break;
+ case CONSTRAINT_TYPE_TRANSFORM:
+ updateDuplicateTransformConstraintSettings(ob, pchan, curcon);
+ break;
+ }
+ }
+}
+static void updateDuplicateCustomBoneShapes(bContext *C, EditBone *dup_bone, Object *ob)
+{
+ if (ob->pose == NULL) {
+ return;
+ }
+ bPoseChannel *pchan;
+ pchan = BKE_pose_channel_verify(ob->pose, dup_bone->name);
+
+ if (pchan->custom != NULL) {
+ Main *bmain = CTX_data_main(C);
+ char name_flip[MAX_ID_NAME - 2];
+
+ /* Skip the first two chars in the object name as those are used to store object type */
+ BLI_string_flip_side_name(name_flip, pchan->custom->id.name + 2, false, sizeof(name_flip));
+ Object *shape_ob = (Object *)BKE_libblock_find_name(bmain, ID_OB, name_flip);
+
+ if (shape_ob != NULL) {
+ /* A flipped shape object exists, use it! */
+ pchan->custom = shape_ob;
+ }
+ }
+}
+
+static void copy_pchan(EditBone *src_bone, EditBone *dst_bone, Object *src_ob, Object *dst_ob)
+{
/* copy the ID property */
- if (curBone->prop) {
- eBone->prop = IDP_CopyProperty(curBone->prop);
+ if (src_bone->prop) {
+ dst_bone->prop = IDP_CopyProperty(src_bone->prop);
}
/* Lets duplicate the list of constraints that the
@@ -466,25 +880,46 @@ EditBone *duplicateEditBoneObjects(
if (src_ob->pose) {
bPoseChannel *chanold, *channew;
- chanold = BKE_pose_channel_verify(src_ob->pose, curBone->name);
+ chanold = BKE_pose_channel_verify(src_ob->pose, src_bone->name);
if (chanold) {
/* WARNING: this creates a new posechannel, but there will not be an attached bone
* yet as the new bones created here are still 'EditBones' not 'Bones'.
*/
- channew = BKE_pose_channel_verify(dst_ob->pose, eBone->name);
+ channew = BKE_pose_channel_verify(dst_ob->pose, dst_bone->name);
if (channew) {
BKE_pose_channel_copy_data(channew, chanold);
}
}
}
+}
+
+EditBone *duplicateEditBoneObjects(
+ EditBone *cur_bone, const char *name, ListBase *editbones, Object *src_ob, Object *dst_ob)
+{
+ EditBone *e_bone = MEM_mallocN(sizeof(EditBone), "addup_editbone");
+
+ /* Copy data from old bone to new bone */
+ memcpy(e_bone, cur_bone, sizeof(EditBone));
+
+ cur_bone->temp.ebone = e_bone;
+ e_bone->temp.ebone = cur_bone;
+
+ if (name != NULL) {
+ BLI_strncpy(e_bone->name, name, sizeof(e_bone->name));
+ }
- return eBone;
+ ED_armature_ebone_unique_name(editbones, e_bone->name, NULL);
+ BLI_addtail(editbones, e_bone);
+
+ copy_pchan(cur_bone, e_bone, src_ob, dst_ob);
+
+ return e_bone;
}
-EditBone *duplicateEditBone(EditBone *curBone, const char *name, ListBase *editbones, Object *ob)
+EditBone *duplicateEditBone(EditBone *cur_bone, const char *name, ListBase *editbones, Object *ob)
{
- return duplicateEditBoneObjects(curBone, name, editbones, ob, ob);
+ return duplicateEditBoneObjects(cur_bone, name, editbones, ob, ob);
}
static int armature_duplicate_selected_exec(bContext *C, wmOperator *op)
@@ -538,8 +973,8 @@ static int armature_duplicate_selected_exec(bContext *C, wmOperator *op)
BLI_string_flip_side_name(
new_bone_name_buff, ebone_iter->name, false, sizeof(new_bone_name_buff));
- /* Only use flipped name if not yet in use. Otherwise we'd get again inconsistent namings
- * (different numbers), better keep default behavior in this case. */
+ /* Only use flipped name if not yet in use. Otherwise we'd get again inconsistent
+ * namings (different numbers), better keep default behavior in this case. */
if (ED_armature_ebone_find_name(arm->edbo, new_bone_name_buff) == NULL) {
new_bone_name = new_bone_name_buff;
}
@@ -567,13 +1002,13 @@ static int armature_duplicate_selected_exec(bContext *C, wmOperator *op)
}
else if (ebone_iter->parent->temp.ebone) {
/* If this bone has a parent that was duplicated,
- * Set the duplicate->parent to the curBone->parent->temp
+ * Set the duplicate->parent to the cur_bone->parent->temp
*/
ebone->parent = ebone_iter->parent->temp.ebone;
}
else {
/* If this bone has a parent that IS not selected,
- * Set the duplicate->parent to the curBone->parent
+ * Set the duplicate->parent to the cur_bone->parent
*/
ebone->parent = (EditBone *)ebone_iter->parent;
ebone->flag &= ~BONE_CONNECTED;
@@ -590,7 +1025,7 @@ static int armature_duplicate_selected_exec(bContext *C, wmOperator *op)
/* Lets try to fix any constraint subtargets that might
* have been duplicated
*/
- updateDuplicateSubtarget(ebone, arm->edbo, ob);
+ updateDuplicateSubtarget(ebone, arm->edbo, ob, false);
}
}
@@ -616,6 +1051,8 @@ static int armature_duplicate_selected_exec(bContext *C, wmOperator *op)
}
MEM_freeN(objects);
+ ED_outliner_select_sync_from_edit_bone_tag(C);
+
return OPERATOR_FINISHED;
}
@@ -742,12 +1179,24 @@ static int armature_symmetrize_exec(bContext *C, wmOperator *op)
}
}
- /* Find the selected bones and duplicate them as needed, with mirrored name */
+ /* Find the selected bones and duplicate them as needed, with mirrored name. */
for (ebone_iter = arm->edbo->first; ebone_iter && ebone_iter != ebone_first_dupe;
ebone_iter = ebone_iter->next) {
- if (EBONE_VISIBLE(arm, ebone_iter) && (ebone_iter->flag & BONE_SELECTED) &&
- /* will be set if the mirror bone already exists (no need to make a new one) */
- (ebone_iter->temp.ebone == NULL)) {
+ if (EBONE_VISIBLE(arm, ebone_iter) && (ebone_iter->flag & BONE_SELECTED)) {
+ if (ebone_iter->temp.ebone != NULL) {
+ /* This will be set if the mirror bone already exists (no need to make a new one)
+ * but we do need to make sure that the 'pchan' settings (constraints etc)
+ * is synchronized. */
+ bPoseChannel *pchan;
+ /* Make sure we clean up the old data before overwriting it */
+ pchan = BKE_pose_channel_verify(obedit->pose, ebone_iter->temp.ebone->name);
+ BKE_pose_channel_free(pchan);
+ /* Sync pchan data */
+ copy_pchan(ebone_iter, ebone_iter->temp.ebone, obedit, obedit);
+ /* Sync scale mode */
+ ebone_iter->temp.ebone->inherit_scale_mode = ebone_iter->inherit_scale_mode;
+ continue;
+ }
char name_flip[MAXBONENAME];
BLI_string_flip_side_name(name_flip, ebone_iter->name, false, sizeof(name_flip));
@@ -765,7 +1214,7 @@ static int armature_symmetrize_exec(bContext *C, wmOperator *op)
}
}
- /* Run through the list and fix the pointers */
+ /* Run through the list and fix the pointers. */
for (ebone_iter = arm->edbo->first; ebone_iter && ebone_iter != ebone_first_dupe;
ebone_iter = ebone_iter->next) {
if (ebone_iter->temp.ebone) {
@@ -793,7 +1242,12 @@ static int armature_symmetrize_exec(bContext *C, wmOperator *op)
* then we can assume the parent has no L/R but is a center bone.
* So just use the same parent for both.
*/
- ebone->flag &= ~BONE_CONNECTED;
+
+ if (ebone->head[axis] != 0.0f) {
+ /* The mirrored bone doesn't start on the mirror axis, so assume that this one should
+ * not be connected to the old parent */
+ ebone->flag &= ~BONE_CONNECTED;
+ }
}
ebone->parent = ebone_parent;
@@ -803,10 +1257,19 @@ static int armature_symmetrize_exec(bContext *C, wmOperator *op)
ebone->bbone_prev = get_symmetrized_bone(arm, ebone_iter->bbone_prev);
ebone->bbone_next = get_symmetrized_bone(arm, ebone_iter->bbone_next);
+ /* Sync bbone handle types */
+ ebone->bbone_prev_type = ebone_iter->bbone_prev_type;
+ ebone->bbone_next_type = ebone_iter->bbone_next_type;
+
/* Lets try to fix any constraint subtargets that might
* have been duplicated
*/
- updateDuplicateSubtarget(ebone, arm->edbo, obedit);
+ updateDuplicateSubtarget(ebone, arm->edbo, obedit, true);
+ /* Try to update constraint options so that they are mirrored as well
+ * (need to supply bone_iter as well in case we are working with existing bones) */
+ updateDuplicateConstraintSettings(ebone, ebone_iter, obedit);
+ /* Mirror bone shapes if possible */
+ updateDuplicateCustomBoneShapes(C, ebone, obedit);
}
}
@@ -1062,7 +1525,13 @@ static int armature_extrude_exec(bContext *C, wmOperator *op)
}
MEM_freeN(objects);
- return changed_multi ? OPERATOR_FINISHED : OPERATOR_CANCELLED;
+ if (!changed_multi) {
+ return OPERATOR_CANCELLED;
+ }
+
+ ED_outliner_select_sync_from_edit_bone_tag(C);
+
+ return OPERATOR_FINISHED;
}
void ARMATURE_OT_extrude(wmOperatorType *ot)
@@ -1116,7 +1585,7 @@ static int armature_bone_primitive_add_exec(bContext *C, wmOperator *op)
ED_armature_edit_deselect_all(obedit);
- /* Create a bone */
+ /* Create a bone. */
bone = ED_armature_ebone_add(obedit->data, name);
copy_v3_v3(bone->head, curs);
@@ -1133,6 +1602,7 @@ static int armature_bone_primitive_add_exec(bContext *C, wmOperator *op)
/* note, notifier might evolve */
WM_event_add_notifier(C, NC_OBJECT | ND_BONE_SELECT, obedit);
DEG_id_tag_update(&obedit->id, ID_RECALC_SELECT);
+ ED_outliner_select_sync_from_edit_bone_tag(C);
return OPERATOR_FINISHED;
}
@@ -1223,6 +1693,7 @@ static int armature_subdivide_exec(bContext *C, wmOperator *op)
/* note, notifier might evolve */
WM_event_add_notifier(C, NC_OBJECT | ND_BONE_SELECT, obedit);
DEG_id_tag_update(&obedit->id, ID_RECALC_SELECT);
+ ED_outliner_select_sync_from_edit_bone_tag(C);
return OPERATOR_FINISHED;
}
@@ -1232,7 +1703,7 @@ void ARMATURE_OT_subdivide(wmOperatorType *ot)
PropertyRNA *prop;
/* identifiers */
- ot->name = "Subdivide Multi";
+ ot->name = "Subdivide";
ot->idname = "ARMATURE_OT_subdivide";
ot->description = "Break selected bones into chains of smaller bones";
diff --git a/source/blender/editors/armature/armature_edit.c b/source/blender/editors/armature/armature_edit.c
index b8378c95a60..a7a705a6202 100644
--- a/source/blender/editors/armature/armature_edit.c
+++ b/source/blender/editors/armature/armature_edit.c
@@ -54,6 +54,7 @@
#include "WM_types.h"
#include "ED_armature.h"
+#include "ED_outliner.h"
#include "ED_screen.h"
#include "ED_view3d.h"
@@ -499,7 +500,7 @@ static int armature_roll_clear_exec(bContext *C, wmOperator *op)
bArmature *arm = ob->data;
bool changed = false;
- for (EditBone *ebone = arm->edbo->first; ebone; ebone = ebone->next) {
+ LISTBASE_FOREACH (EditBone *, ebone, arm->edbo) {
if (EBONE_VISIBLE(arm, ebone) && EBONE_EDITABLE(ebone)) {
/* Roll func is a callback which assumes that all is well. */
ebone->roll = roll;
@@ -508,7 +509,7 @@ static int armature_roll_clear_exec(bContext *C, wmOperator *op)
}
if (arm->flag & ARM_MIRROR_EDIT) {
- for (EditBone *ebone = arm->edbo->first; ebone; ebone = ebone->next) {
+ LISTBASE_FOREACH (EditBone *, ebone, arm->edbo) {
if ((EBONE_VISIBLE(arm, ebone) && EBONE_EDITABLE(ebone)) == 0) {
EditBone *ebone_mirr = ED_armature_ebone_get_mirrored(arm->edbo, ebone);
if (ebone_mirr && (EBONE_VISIBLE(arm, ebone_mirr) && EBONE_EDITABLE(ebone_mirr))) {
@@ -889,213 +890,6 @@ void ARMATURE_OT_fill(wmOperatorType *ot)
/** \} */
/* -------------------------------------------------------------------- */
-/** \name Merge Operator
- * \{ */
-
-/* this function merges between two bones, removes them and those in-between,
- * and adjusts the parent relationships for those in-between
- */
-static void bones_merge(
- Object *obedit, EditBone *start, EditBone *end, EditBone *endchild, ListBase *chains)
-{
- bArmature *arm = obedit->data;
- EditBone *ebo, *ebone, *newbone;
- LinkData *chain;
- float head[3], tail[3];
-
- /* check if same bone */
- if (start == end) {
- if (G.debug & G_DEBUG) {
- printf("Error: same bone!\n");
- printf("\tstart = %s, end = %s\n", start->name, end->name);
- }
- }
-
- /* step 1: add a new bone
- * - head = head/tail of start (default head)
- * - tail = head/tail of end (default tail)
- * - parent = parent of start
- */
- if ((start->flag & BONE_TIPSEL) && (start->flag & BONE_SELECTED) == 0) {
- copy_v3_v3(head, start->tail);
- }
- else {
- copy_v3_v3(head, start->head);
- }
- if ((end->flag & BONE_ROOTSEL) && (end->flag & BONE_SELECTED) == 0) {
- copy_v3_v3(tail, end->head);
- }
- else {
- copy_v3_v3(tail, end->tail);
- }
- newbone = add_points_bone(obedit, head, tail);
- newbone->parent = start->parent;
-
- /* TODO, copy more things to the new bone */
- newbone->flag = start->flag & (BONE_HINGE | BONE_NO_DEFORM | BONE_NO_CYCLICOFFSET |
- BONE_NO_LOCAL_LOCATION | BONE_DONE);
-
- newbone->inherit_scale_mode = start->inherit_scale_mode;
-
- /* Step 2a: reparent any side chains which may be parented to any bone in the chain
- * of bones to merge - potentially several tips for side chains leading to some tree exist.
- */
- for (chain = chains->first; chain; chain = chain->next) {
- /* Traverse down chain until we hit the bottom or if we run into the tip of the chain of bones
- * we're merging (need to stop in this case to avoid corrupting this chain too!).
- */
- for (ebone = chain->data; (ebone) && (ebone != end); ebone = ebone->parent) {
- short found = 0;
-
- /* Check if this bone is parented to one in the merging chain
- * ! WATCHIT: must only go check until end of checking chain
- */
- for (ebo = end; (ebo) && (ebo != start->parent); ebo = ebo->parent) {
- /* side-chain found? --> remap parent to new bone, then we're done with this chain :) */
- if (ebone->parent == ebo) {
- ebone->parent = newbone;
- found = 1;
- break;
- }
- }
-
- /* carry on to the next tip now */
- if (found) {
- break;
- }
- }
- }
-
- /* step 2b: parent child of end to newbone (child from this chain) */
- if (endchild) {
- endchild->parent = newbone;
- }
-
- /* step 3: delete all bones between and including start and end */
- for (ebo = end; ebo; ebo = ebone) {
- ebone = (ebo == start) ? (NULL) : (ebo->parent);
- bone_free(arm, ebo);
- }
-
- newbone->flag |= (BONE_ROOTSEL | BONE_TIPSEL | BONE_SELECTED);
- ED_armature_edit_sync_selection(arm->edbo);
-}
-
-static int armature_merge_exec(bContext *C, wmOperator *op)
-{
- ViewLayer *view_layer = CTX_data_view_layer(C);
- const short type = RNA_enum_get(op->ptr, "type");
-
- uint objects_len = 0;
- Object **objects = BKE_view_layer_array_from_objects_in_edit_mode_unique_data(
- view_layer, CTX_wm_view3d(C), &objects_len);
-
- for (uint ob_index = 0; ob_index < objects_len; ob_index++) {
- Object *obedit = objects[ob_index];
- bArmature *arm = obedit->data;
-
- /* for now, there's only really one type of merging that's performed... */
- if (type == 1) {
- /* go down chains, merging bones */
- ListBase chains = {NULL, NULL};
- LinkData *chain, *nchain;
- EditBone *ebo;
-
- armature_tag_select_mirrored(arm);
-
- /* get chains (ends on chains) */
- chains_find_tips(arm->edbo, &chains);
- if (BLI_listbase_is_empty(&chains)) {
- continue;
- }
-
- /* each 'chain' is the last bone in the chain (with no children) */
- for (chain = chains.first; chain; chain = nchain) {
- EditBone *bstart = NULL, *bend = NULL;
- EditBone *bchild = NULL, *child = NULL;
-
- /* temporarily remove chain from list of chains */
- nchain = chain->next;
- BLI_remlink(&chains, chain);
-
- /* only consider bones that are visible and selected */
- for (ebo = chain->data; ebo; child = ebo, ebo = ebo->parent) {
- /* check if visible + selected */
- if (EBONE_VISIBLE(arm, ebo) && ((ebo->flag & BONE_CONNECTED) || (ebo->parent == NULL)) &&
- (ebo->flag & BONE_SELECTED)) {
- /* set either end or start (end gets priority, unless it is already set) */
- if (bend == NULL) {
- bend = ebo;
- bchild = child;
- }
- else {
- bstart = ebo;
- }
- }
- else {
- /* chain is broken... merge any continuous segments then clear */
- if (bstart && bend) {
- bones_merge(obedit, bstart, bend, bchild, &chains);
- }
-
- bstart = NULL;
- bend = NULL;
- bchild = NULL;
- }
- }
-
- /* merge from bstart to bend if something not merged */
- if (bstart && bend) {
- bones_merge(obedit, bstart, bend, bchild, &chains);
- }
-
- /* put back link */
- BLI_insertlinkbefore(&chains, nchain, chain);
- }
-
- armature_tag_unselect(arm);
-
- BLI_freelistN(&chains);
- }
-
- /* updates */
- ED_armature_edit_sync_selection(arm->edbo);
- ED_armature_edit_refresh_layer_used(arm);
- WM_event_add_notifier(C, NC_OBJECT | ND_POSE, obedit);
- DEG_id_tag_update(&arm->id, ID_RECALC_COPY_ON_WRITE);
- }
- MEM_freeN(objects);
-
- return OPERATOR_FINISHED;
-}
-
-void ARMATURE_OT_merge(wmOperatorType *ot)
-{
- static const EnumPropertyItem merge_types[] = {
- {1, "WITHIN_CHAIN", 0, "Within Chains", ""},
- {0, NULL, 0, NULL, NULL},
- };
-
- /* identifiers */
- ot->name = "Merge Bones";
- ot->idname = "ARMATURE_OT_merge";
- ot->description = "Merge continuous chains of selected bones";
-
- /* callbacks */
- ot->invoke = WM_menu_invoke;
- ot->exec = armature_merge_exec;
- ot->poll = ED_operator_editarmature;
-
- /* flags */
- ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
-
- /* properties */
- ot->prop = RNA_def_enum(ot->srna, "type", merge_types, 0, "Type", "");
-}
-
-/** \} */
-
-/* -------------------------------------------------------------------- */
/** \name Switch Direction Operator
*
* Currently, this does not use context loops, as context loops do not make it
@@ -1396,13 +1190,13 @@ static int armature_split_exec(bContext *C, wmOperator *UNUSED(op))
Object *ob = objects[ob_index];
bArmature *arm = ob->data;
- for (EditBone *bone = arm->edbo->first; bone; bone = bone->next) {
+ LISTBASE_FOREACH (EditBone *, bone, arm->edbo) {
if (bone->parent && (bone->flag & BONE_SELECTED) != (bone->parent->flag & BONE_SELECTED)) {
bone->parent = NULL;
bone->flag &= ~BONE_CONNECTED;
}
}
- for (EditBone *bone = arm->edbo->first; bone; bone = bone->next) {
+ LISTBASE_FOREACH (EditBone *, bone, arm->edbo) {
ED_armature_ebone_select_set(bone, (bone->flag & BONE_SELECTED) != 0);
}
@@ -1490,6 +1284,7 @@ static int armature_delete_selected_exec(bContext *C, wmOperator *UNUSED(op))
BKE_pose_tag_recalc(CTX_data_main(C), obedit->pose);
WM_event_add_notifier(C, NC_OBJECT | ND_BONE_SELECT, obedit);
DEG_id_tag_update(&arm->id, ID_RECALC_SELECT);
+ ED_outliner_select_sync_from_edit_bone_tag(C);
}
}
MEM_freeN(objects);
@@ -1665,6 +1460,7 @@ static int armature_dissolve_selected_exec(bContext *C, wmOperator *UNUSED(op))
ED_armature_edit_refresh_layer_used(arm);
WM_event_add_notifier(C, NC_OBJECT | ND_BONE_SELECT, obedit);
DEG_id_tag_update(&arm->id, ID_RECALC_SELECT);
+ ED_outliner_select_sync_from_edit_bone_tag(C);
}
}
MEM_freeN(objects);
@@ -1715,7 +1511,7 @@ static int armature_hide_exec(bContext *C, wmOperator *op)
bArmature *arm = obedit->data;
bool changed = false;
- for (EditBone *ebone = arm->edbo->first; ebone; ebone = ebone->next) {
+ LISTBASE_FOREACH (EditBone *, ebone, arm->edbo) {
if (EBONE_VISIBLE(arm, ebone)) {
if ((ebone->flag & BONE_SELECTED) != invert) {
ebone->flag &= ~(BONE_TIPSEL | BONE_SELECTED | BONE_ROOTSEL);
@@ -1774,7 +1570,7 @@ static int armature_reveal_exec(bContext *C, wmOperator *op)
bArmature *arm = obedit->data;
bool changed = false;
- for (EditBone *ebone = arm->edbo->first; ebone; ebone = ebone->next) {
+ LISTBASE_FOREACH (EditBone *, ebone, arm->edbo) {
if (arm->layer & ebone->layer) {
if (ebone->flag & BONE_HIDDEN_A) {
if (!(ebone->flag & BONE_UNSELECTABLE)) {
diff --git a/source/blender/editors/armature/armature_intern.h b/source/blender/editors/armature/armature_intern.h
index fa562ab0f44..08d82bf13c9 100644
--- a/source/blender/editors/armature/armature_intern.h
+++ b/source/blender/editors/armature/armature_intern.h
@@ -59,6 +59,7 @@ void ARMATURE_OT_select_mirror(struct wmOperatorType *ot);
void ARMATURE_OT_select_more(struct wmOperatorType *ot);
void ARMATURE_OT_select_less(struct wmOperatorType *ot);
void ARMATURE_OT_select_hierarchy(struct wmOperatorType *ot);
+void ARMATURE_OT_select_linked_pick(struct wmOperatorType *ot);
void ARMATURE_OT_select_linked(struct wmOperatorType *ot);
void ARMATURE_OT_select_similar(struct wmOperatorType *ot);
void ARMATURE_OT_shortest_path_pick(struct wmOperatorType *ot);
@@ -72,7 +73,6 @@ void ARMATURE_OT_hide(struct wmOperatorType *ot);
void ARMATURE_OT_reveal(struct wmOperatorType *ot);
void ARMATURE_OT_click_extrude(struct wmOperatorType *ot);
void ARMATURE_OT_fill(struct wmOperatorType *ot);
-void ARMATURE_OT_merge(struct wmOperatorType *ot);
void ARMATURE_OT_separate(struct wmOperatorType *ot);
void ARMATURE_OT_split(struct wmOperatorType *ot);
@@ -104,6 +104,7 @@ void POSE_OT_select_all(struct wmOperatorType *ot);
void POSE_OT_select_parent(struct wmOperatorType *ot);
void POSE_OT_select_hierarchy(struct wmOperatorType *ot);
void POSE_OT_select_linked(struct wmOperatorType *ot);
+void POSE_OT_select_linked_pick(struct wmOperatorType *ot);
void POSE_OT_select_constraint_target(struct wmOperatorType *ot);
void POSE_OT_select_grouped(struct wmOperatorType *ot);
void POSE_OT_select_mirror(struct wmOperatorType *ot);
@@ -232,9 +233,6 @@ struct EditBone *duplicateEditBone(struct EditBone *curBone,
const char *name,
struct ListBase *editbones,
struct Object *ob);
-void updateDuplicateSubtarget(struct EditBone *dupBone,
- struct ListBase *editbones,
- struct Object *ob);
/* duplicate method (cross objects) */
/* editbones is the target list */
@@ -244,12 +242,6 @@ struct EditBone *duplicateEditBoneObjects(struct EditBone *curBone,
struct Object *src_ob,
struct Object *dst_ob);
-/* editbones is the source list */
-void updateDuplicateSubtargetObjects(struct EditBone *dupBone,
- struct ListBase *editbones,
- struct Object *src_ob,
- struct Object *dst_ob);
-
EditBone *add_points_bone(struct Object *obedit, float head[3], float tail[3]);
void bone_free(struct bArmature *arm, struct EditBone *bone);
@@ -258,16 +250,40 @@ void armature_select_mirrored_ex(struct bArmature *arm, const int flag);
void armature_select_mirrored(struct bArmature *arm);
void armature_tag_unselect(struct bArmature *arm);
-void *get_nearest_bone(struct bContext *C, const int xy[2], bool findunsel, struct Base **r_base);
-
-void *get_bone_from_selectbuffer(struct Base **bases,
- uint bases_len,
- bool is_editmode,
- const unsigned int *buffer,
- short hits,
+EditBone *ED_armature_pick_ebone(struct bContext *C,
+ const int xy[2],
bool findunsel,
- bool do_nearest,
struct Base **r_base);
+struct bPoseChannel *ED_armature_pick_pchan(struct bContext *C,
+ const int xy[2],
+ bool findunsel,
+ struct Base **r_base);
+struct Bone *ED_armature_pick_bone(struct bContext *C,
+ const int xy[2],
+ bool findunsel,
+ struct Base **r_base);
+
+struct EditBone *ED_armature_pick_ebone_from_selectbuffer(struct Base **bases,
+ uint bases_len,
+ const uint *buffer,
+ short hits,
+ bool findunsel,
+ bool do_nearest,
+ struct Base **r_base);
+struct bPoseChannel *ED_armature_pick_pchan_from_selectbuffer(struct Base **bases,
+ uint bases_len,
+ const uint *buffer,
+ short hits,
+ bool findunsel,
+ bool do_nearest,
+ struct Base **r_base);
+struct Bone *ED_armature_pick_bone_from_selectbuffer(struct Base **bases,
+ uint bases_len,
+ const uint *buffer,
+ short hits,
+ bool findunsel,
+ bool do_nearest,
+ struct Base **r_base);
int bone_looper(struct Object *ob,
struct Bone *bone,
diff --git a/source/blender/editors/armature/armature_naming.c b/source/blender/editors/armature/armature_naming.c
index 13660244547..544d86d4c47 100644
--- a/source/blender/editors/armature/armature_naming.c
+++ b/source/blender/editors/armature/armature_naming.c
@@ -20,6 +20,8 @@
/** \file
* \ingroup edarmature
+ *
+ * This file contains functions/API's for renaming bones and/or working with them.
*/
#include <string.h>
@@ -63,12 +65,11 @@
#include "armature_intern.h"
-/* This file contains functions/API's for renaming bones and/or working with them */
-
-/* ************************************************** */
-/* EditBone Names */
+/* -------------------------------------------------------------------- */
+/** \name Unique Bone Name Utility (Edit Mode)
+ * \{ */
-/* note: there's a unique_bone_name() too! */
+/* note: there's a ed_armature_bone_unique_name() too! */
static bool editbone_unique_check(void *arg, const char *name)
{
struct {
@@ -92,20 +93,29 @@ void ED_armature_ebone_unique_name(ListBase *edbo, char *name, EditBone *bone)
BLI_uniquename_cb(editbone_unique_check, &data, DATA_("Bone"), '.', name, sizeof(bone->name));
}
-/* ************************************************** */
-/* Bone Renaming - API */
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Unique Bone Name Utility (Object Mode)
+ * \{ */
static bool bone_unique_check(void *arg, const char *name)
{
return BKE_armature_find_bone_name((bArmature *)arg, name) != NULL;
}
-static void unique_bone_name(bArmature *arm, char *name)
+static void ed_armature_bone_unique_name(bArmature *arm, char *name)
{
BLI_uniquename_cb(
bone_unique_check, (void *)arm, DATA_("Bone"), '.', name, sizeof(((Bone *)NULL)->name));
}
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Bone Renaming (Object & Edit Mode API)
+ * \{ */
+
/* helper call for armature_bone_rename */
static void constraint_bone_name_fix(Object *ob,
ListBase *conlist,
@@ -180,7 +190,7 @@ void ED_armature_bone_rename(Main *bmain,
Bone *bone = BKE_armature_find_bone_name(arm, oldname);
if (bone) {
- unique_bone_name(arm, newname);
+ ed_armature_bone_unique_name(arm, newname);
if (arm->bonehash) {
BLI_assert(BLI_ghash_haskey(arm->bonehash, bone->name));
@@ -255,7 +265,7 @@ void ED_armature_bone_rename(Main *bmain,
}
}
- if (modifiers_usesArmature(ob, arm)) {
+ if (BKE_modifiers_uses_armature(ob, arm)) {
bDeformGroup *dg = BKE_object_defgroup_find_name(ob, oldname);
if (dg) {
BLI_strncpy(dg->name, newname, MAXBONENAME);
@@ -307,8 +317,7 @@ void ED_armature_bone_rename(Main *bmain,
}
}
- for (GpencilModifierData *gp_md = ob->greasepencil_modifiers.first; gp_md;
- gp_md = gp_md->next) {
+ LISTBASE_FOREACH (GpencilModifierData *, gp_md, &ob->greasepencil_modifiers) {
switch (gp_md->type) {
case eGpencilModifierType_Armature: {
ArmatureGpencilModifierData *mmd = (ArmatureGpencilModifierData *)gp_md;
@@ -352,11 +361,11 @@ void ED_armature_bone_rename(Main *bmain,
{
bScreen *screen;
for (screen = bmain->screens.first; screen; screen = screen->id.next) {
- ScrArea *sa;
+ ScrArea *area;
/* add regions */
- for (sa = screen->areabase.first; sa; sa = sa->next) {
+ for (area = screen->areabase.first; area; area = area->next) {
SpaceLink *sl;
- for (sl = sa->spacedata.first; sl; sl = sl->next) {
+ for (sl = area->spacedata.first; sl; sl = sl->next) {
if (sl->spacetype == SPACE_VIEW3D) {
View3D *v3d = (View3D *)sl;
if (v3d->ob_center && v3d->ob_center->data == arm) {
@@ -372,6 +381,12 @@ void ED_armature_bone_rename(Main *bmain,
}
}
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Bone Flipping (Object & Edit Mode API)
+ * \{ */
+
typedef struct BoneFlipNameData {
struct BoneFlipNameData *next, *prev;
char *name;
@@ -399,7 +414,7 @@ void ED_armature_bones_flip_names(Main *bmain,
/* First pass: generate flip names, and blindly rename.
* If rename did not yield expected result,
* store both bone's name and expected flipped one into temp list for second pass. */
- for (LinkData *link = bones_names->first; link; link = link->next) {
+ LISTBASE_FOREACH (LinkData *, link, bones_names) {
char name_flip[MAXBONENAME];
char *name = link->data;
@@ -426,8 +441,11 @@ void ED_armature_bones_flip_names(Main *bmain,
}
}
-/* ************************************************** */
-/* Bone Renaming - EditMode */
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Flip Bone Names (Edit Mode Operator)
+ * \{ */
static int armature_flip_names_exec(bContext *C, wmOperator *op)
{
@@ -451,7 +469,7 @@ static int armature_flip_names_exec(bContext *C, wmOperator *op)
ListBase bones_names = {NULL};
- for (EditBone *ebone = arm->edbo->first; ebone; ebone = ebone->next) {
+ LISTBASE_FOREACH (EditBone *, ebone, arm->edbo) {
if (EBONE_VISIBLE(arm, ebone)) {
if (ebone->flag & BONE_SELECTED) {
BLI_addtail(&bones_names, BLI_genericNodeN(ebone->name));
@@ -511,6 +529,12 @@ void ARMATURE_OT_flip_names(wmOperatorType *ot)
"(WARNING: may result in incoherent naming in some cases)");
}
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Bone Auto Side Names (Edit Mode Operator)
+ * \{ */
+
static int armature_autoside_names_exec(bContext *C, wmOperator *op)
{
ViewLayer *view_layer = CTX_data_view_layer(C);
@@ -532,7 +556,7 @@ static int armature_autoside_names_exec(bContext *C, wmOperator *op)
continue;
}
- for (EditBone *ebone = arm->edbo->first; ebone; ebone = ebone->next) {
+ LISTBASE_FOREACH (EditBone *, ebone, arm->edbo) {
if (EBONE_EDITABLE(ebone)) {
/* We first need to do the flipped bone, then the original one.
@@ -599,3 +623,5 @@ void ARMATURE_OT_autoside_names(wmOperatorType *ot)
/* settings */
ot->prop = RNA_def_enum(ot->srna, "type", axis_items, 0, "Axis", "Axis tag names with");
}
+
+/** \} */
diff --git a/source/blender/editors/armature/armature_ops.c b/source/blender/editors/armature/armature_ops.c
index a29d0f5f158..da1b29307b1 100644
--- a/source/blender/editors/armature/armature_ops.c
+++ b/source/blender/editors/armature/armature_ops.c
@@ -56,6 +56,7 @@ void ED_operatortypes_armature(void)
WM_operatortype_append(ARMATURE_OT_select_less);
WM_operatortype_append(ARMATURE_OT_select_hierarchy);
WM_operatortype_append(ARMATURE_OT_select_linked);
+ WM_operatortype_append(ARMATURE_OT_select_linked_pick);
WM_operatortype_append(ARMATURE_OT_select_similar);
WM_operatortype_append(ARMATURE_OT_shortest_path_pick);
@@ -68,7 +69,6 @@ void ED_operatortypes_armature(void)
WM_operatortype_append(ARMATURE_OT_reveal);
WM_operatortype_append(ARMATURE_OT_click_extrude);
WM_operatortype_append(ARMATURE_OT_fill);
- WM_operatortype_append(ARMATURE_OT_merge);
WM_operatortype_append(ARMATURE_OT_separate);
WM_operatortype_append(ARMATURE_OT_split);
@@ -100,6 +100,7 @@ void ED_operatortypes_armature(void)
WM_operatortype_append(POSE_OT_select_parent);
WM_operatortype_append(POSE_OT_select_hierarchy);
WM_operatortype_append(POSE_OT_select_linked);
+ WM_operatortype_append(POSE_OT_select_linked_pick);
WM_operatortype_append(POSE_OT_select_constraint_target);
WM_operatortype_append(POSE_OT_select_grouped);
WM_operatortype_append(POSE_OT_select_mirror);
diff --git a/source/blender/editors/armature/armature_relations.c b/source/blender/editors/armature/armature_relations.c
index 2c2bf3cd283..d3d00fc44f2 100644
--- a/source/blender/editors/armature/armature_relations.c
+++ b/source/blender/editors/armature/armature_relations.c
@@ -37,11 +37,12 @@
#include "BLT_translation.h"
#include "BKE_action.h"
+#include "BKE_anim_data.h"
#include "BKE_animsys.h"
#include "BKE_armature.h"
#include "BKE_constraint.h"
#include "BKE_context.h"
-#include "BKE_fcurve.h"
+#include "BKE_fcurve_driver.h"
#include "BKE_layer.h"
#include "BKE_main.h"
#include "BKE_report.h"
@@ -57,6 +58,7 @@
#include "ED_armature.h"
#include "ED_object.h"
+#include "ED_outliner.h"
#include "ED_screen.h"
#include "UI_interface.h"
@@ -280,7 +282,7 @@ int join_armature_exec(bContext *C, wmOperator *op)
float mat[4][4], oimat[4][4];
bool ok = false;
- /* Ensure we're not in editmode and that the active object is an armature*/
+ /* Ensure we're not in edit-mode and that the active object is an armature. */
if (!ob_active || ob_active->type != OB_ARMATURE) {
return OPERATOR_CANCELLED;
}
@@ -430,7 +432,6 @@ int join_armature_exec(bContext *C, wmOperator *op)
ED_armature_from_edit(bmain, arm);
ED_armature_edit_free(arm);
- BKE_armature_refresh_layer_used(arm);
DEG_id_tag_update(&scene->id, ID_RECALC_SELECT);
WM_event_add_notifier(C, NC_SCENE | ND_OB_ACTIVE, scene);
@@ -568,7 +569,7 @@ static void separate_armature_bones(Main *bmain, Object *ob, const bool is_selec
if (is_select == (EBONE_VISIBLE(arm, curbone) && (curbone->flag & BONE_SELECTED))) {
/* clear the bone->parent var of any bone that had this as its parent */
- for (EditBone *ebo = arm->edbo->first; ebo; ebo = ebo->next) {
+ LISTBASE_FOREACH (EditBone *, ebo, arm->edbo) {
if (ebo->parent == curbone) {
ebo->parent = NULL;
/* this is needed to prevent random crashes with in ED_armature_from_edit */
@@ -578,7 +579,7 @@ static void separate_armature_bones(Main *bmain, Object *ob, const bool is_selec
}
/* clear the pchan->parent var of any pchan that had this as its parent */
- for (bPoseChannel *pchn = ob->pose->chanbase.first; pchn; pchn = pchn->next) {
+ LISTBASE_FOREACH (bPoseChannel *, pchn, &ob->pose->chanbase) {
if (pchn->parent == pchan) {
pchn->parent = NULL;
}
@@ -629,7 +630,7 @@ static int separate_armature_exec(bContext *C, wmOperator *op)
bArmature *arm_old = ob_old->data;
bool has_selected_bone = false;
bool has_selected_any = false;
- for (EditBone *ebone = arm_old->edbo->first; ebone; ebone = ebone->next) {
+ LISTBASE_FOREACH (EditBone *, ebone, arm_old->edbo) {
if (EBONE_VISIBLE(arm_old, ebone)) {
if (ebone->flag & BONE_SELECTED) {
has_selected_bone = true;
@@ -687,9 +688,7 @@ static int separate_armature_exec(bContext *C, wmOperator *op)
/* 5) restore original conditions */
ED_armature_to_edit(ob_old->data);
-
ED_armature_edit_refresh_layer_used(ob_old->data);
- BKE_armature_refresh_layer_used(ob_new->data);
/* parents tips remain selected when connected children are removed. */
ED_armature_edit_deselect_all(ob_old);
@@ -706,6 +705,7 @@ static int separate_armature_exec(bContext *C, wmOperator *op)
if (ok) {
BKE_report(op->reports, RPT_INFO, "Separated bones");
+ ED_outliner_select_sync_from_object_tag(C);
}
return OPERATOR_FINISHED;
@@ -835,7 +835,7 @@ static int armature_parent_set_exec(bContext *C, wmOperator *op)
bool is_active_only_selected = false;
if (actbone->flag & BONE_SELECTED) {
is_active_only_selected = true;
- for (EditBone *ebone = arm->edbo->first; ebone; ebone = ebone->next) {
+ LISTBASE_FOREACH (EditBone *, ebone, arm->edbo) {
if (EBONE_EDITABLE(ebone) && (ebone->flag & BONE_SELECTED)) {
if (ebone != actbone) {
is_active_only_selected = false;
@@ -867,7 +867,7 @@ static int armature_parent_set_exec(bContext *C, wmOperator *op)
*/
/* Parent selected bones to the active one. */
- for (EditBone *ebone = arm->edbo->first; ebone; ebone = ebone->next) {
+ LISTBASE_FOREACH (EditBone *, ebone, arm->edbo) {
if (EBONE_EDITABLE(ebone) && (ebone->flag & BONE_SELECTED)) {
if (ebone != actbone) {
bone_connect_to_new_parent(arm->edbo, ebone, actbone, val);
@@ -901,7 +901,7 @@ static int armature_parent_set_invoke(bContext *C,
Object *ob = CTX_data_edit_object(C);
bArmature *arm = ob->data;
EditBone *actbone = arm->act_edbone;
- for (EditBone *ebone = arm->edbo->first; ebone; ebone = ebone->next) {
+ LISTBASE_FOREACH (EditBone *, ebone, arm->edbo) {
if (EBONE_EDITABLE(ebone) && (ebone->flag & BONE_SELECTED)) {
if (ebone != actbone) {
if (ebone->parent != actbone) {
@@ -983,7 +983,7 @@ static int armature_parent_clear_exec(bContext *C, wmOperator *op)
bArmature *arm = ob->data;
bool changed = false;
- for (EditBone *ebone = arm->edbo->first; ebone; ebone = ebone->next) {
+ LISTBASE_FOREACH (EditBone *, ebone, arm->edbo) {
if (EBONE_EDITABLE(ebone)) {
changed = true;
break;
diff --git a/source/blender/editors/armature/armature_select.c b/source/blender/editors/armature/armature_select.c
index 21eccd2ca1f..4b8bbe39a16 100644
--- a/source/blender/editors/armature/armature_select.c
+++ b/source/blender/editors/armature/armature_select.c
@@ -30,6 +30,7 @@
#include "BLI_blenlib.h"
#include "BLI_math.h"
+#include "BLI_rect.h"
#include "BLI_string_utils.h"
#include "BKE_action.h"
@@ -59,7 +60,9 @@
#define EBONE_PREV_FLAG_GET(ebone) ((void)0, (ebone)->temp.i)
#define EBONE_PREV_FLAG_SET(ebone, val) ((ebone)->temp.i = val)
-/* **************** PoseMode & EditMode Selection Buffer Queries *************************** */
+/* -------------------------------------------------------------------- */
+/** \name Select Buffer Queries for PoseMode & EditMode
+ * \{ */
Base *ED_armature_base_and_ebone_from_select_buffer(Base **bases,
uint bases_len,
@@ -109,14 +112,14 @@ Object *ED_armature_object_and_ebone_from_select_buffer(Object **objects,
return ob;
}
-Base *ED_armature_base_and_bone_from_select_buffer(Base **bases,
- uint bases_len,
- int hit,
- Bone **r_bone)
+Base *ED_armature_base_and_pchan_from_select_buffer(Base **bases,
+ uint bases_len,
+ int hit,
+ bPoseChannel **r_pchan)
{
const uint hit_object = hit & 0xFFFF;
Base *base = NULL;
- Bone *bone = NULL;
+ bPoseChannel *pchan = NULL;
/* TODO(campbell): optimize, eg: sort & binary search. */
for (uint base_index = 0; base_index < bases_len; base_index++) {
if (bases[base_index]->object->runtime.select_id == hit_object) {
@@ -127,30 +130,53 @@ Base *ED_armature_base_and_bone_from_select_buffer(Base **bases,
if (base != NULL) {
if (base->object->pose != NULL) {
const uint hit_bone = (hit & ~BONESEL_ANY) >> 16;
- bPoseChannel *pchan = BLI_findlink(&base->object->pose->chanbase, hit_bone);
- bone = pchan ? pchan->bone : NULL;
+ /* pchan may be NULL. */
+ pchan = BLI_findlink(&base->object->pose->chanbase, hit_bone);
}
}
- *r_bone = bone;
+ *r_pchan = pchan;
+ return base;
+}
+
+/* For callers that don't need the pose channel. */
+Base *ED_armature_base_and_bone_from_select_buffer(Base **bases,
+ uint bases_len,
+ int hit,
+ Bone **r_bone)
+{
+ bPoseChannel *pchan = NULL;
+ Base *base = ED_armature_base_and_pchan_from_select_buffer(bases, bases_len, hit, &pchan);
+ *r_bone = pchan ? pchan->bone : NULL;
return base;
}
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Cursor Pick from Select Buffer API
+ *
+ * Internal #ed_armature_pick_bone_from_selectbuffer_impl is exposed as:
+ * - #ED_armature_pick_ebone_from_selectbuffer
+ * - #ED_armature_pick_pchan_from_selectbuffer
+ * - #ED_armature_pick_bone_from_selectbuffer
+ * \{ */
+
/* See if there are any selected bones in this buffer */
/* only bones from base are checked on */
-void *get_bone_from_selectbuffer(Base **bases,
- uint bases_len,
- bool is_editmode,
- const unsigned int *buffer,
- short hits,
- bool findunsel,
- bool do_nearest,
- Base **r_base)
+static void *ed_armature_pick_bone_from_selectbuffer_impl(const bool is_editmode,
+ Base **bases,
+ uint bases_len,
+ const uint *buffer,
+ short hits,
+ bool findunsel,
+ bool do_nearest,
+ Base **r_base)
{
- Bone *bone;
+ bPoseChannel *pchan;
EditBone *ebone;
void *firstunSel = NULL, *firstSel = NULL, *data;
Base *firstunSel_base = NULL, *firstSel_base = NULL;
- unsigned int hitresult;
+ uint hitresult;
short i;
bool takeNext = false;
int minsel = 0xffffffff, minunsel = 0xffffffff;
@@ -158,77 +184,74 @@ void *get_bone_from_selectbuffer(Base **bases,
for (i = 0; i < hits; i++) {
hitresult = buffer[3 + (i * 4)];
- if (!(hitresult & BONESEL_NOSEL)) {
- if (hitresult & BONESEL_ANY) { /* to avoid including objects in selection */
- Base *base = NULL;
- bool sel;
+ if (hitresult & BONESEL_ANY) { /* to avoid including objects in selection */
+ Base *base = NULL;
+ bool sel;
- hitresult &= ~(BONESEL_ANY);
- /* Determine what the current bone is */
- if (is_editmode == false) {
- base = ED_armature_base_and_bone_from_select_buffer(bases, bases_len, hitresult, &bone);
- if (bone != NULL) {
- if (findunsel) {
- sel = (bone->flag & BONE_SELECTED);
- }
- else {
- sel = !(bone->flag & BONE_SELECTED);
- }
-
- data = bone;
+ hitresult &= ~(BONESEL_ANY);
+ /* Determine what the current bone is */
+ if (is_editmode == false) {
+ base = ED_armature_base_and_pchan_from_select_buffer(bases, bases_len, hitresult, &pchan);
+ if (pchan != NULL) {
+ if (findunsel) {
+ sel = (pchan->bone->flag & BONE_SELECTED);
}
else {
- data = NULL;
- sel = 0;
+ sel = !(pchan->bone->flag & BONE_SELECTED);
}
+
+ data = pchan;
}
else {
- base = ED_armature_base_and_ebone_from_select_buffer(
- bases, bases_len, hitresult, &ebone);
- if (findunsel) {
- sel = (ebone->flag & BONE_SELECTED);
+ data = NULL;
+ sel = 0;
+ }
+ }
+ else {
+ base = ED_armature_base_and_ebone_from_select_buffer(bases, bases_len, hitresult, &ebone);
+ if (findunsel) {
+ sel = (ebone->flag & BONE_SELECTED);
+ }
+ else {
+ sel = !(ebone->flag & BONE_SELECTED);
+ }
+
+ data = ebone;
+ }
+
+ if (data) {
+ if (sel) {
+ if (do_nearest) {
+ if (minsel > buffer[4 * i + 1]) {
+ firstSel = data;
+ firstSel_base = base;
+ minsel = buffer[4 * i + 1];
+ }
}
else {
- sel = !(ebone->flag & BONE_SELECTED);
+ if (!firstSel) {
+ firstSel = data;
+ firstSel_base = base;
+ }
+ takeNext = 1;
}
-
- data = ebone;
}
-
- if (data) {
- if (sel) {
- if (do_nearest) {
- if (minsel > buffer[4 * i + 1]) {
- firstSel = data;
- firstSel_base = base;
- minsel = buffer[4 * i + 1];
- }
- }
- else {
- if (!firstSel) {
- firstSel = data;
- firstSel_base = base;
- }
- takeNext = 1;
+ else {
+ if (do_nearest) {
+ if (minunsel > buffer[4 * i + 1]) {
+ firstunSel = data;
+ firstunSel_base = base;
+ minunsel = buffer[4 * i + 1];
}
}
else {
- if (do_nearest) {
- if (minunsel > buffer[4 * i + 1]) {
- firstunSel = data;
- firstunSel_base = base;
- minunsel = buffer[4 * i + 1];
- }
+ if (!firstunSel) {
+ firstunSel = data;
+ firstunSel_base = base;
}
- else {
- if (!firstunSel) {
- firstunSel = data;
- firstunSel_base = base;
- }
- if (takeNext) {
- *r_base = base;
- return data;
- }
+ if (takeNext) {
+ *r_base = base;
+ return data;
}
}
}
@@ -246,22 +269,74 @@ void *get_bone_from_selectbuffer(Base **bases,
}
}
-/* used by posemode as well editmode */
-/* only checks scene->basact! */
-/* x and y are mouse coords (area space) */
-void *get_nearest_bone(bContext *C, const int xy[2], bool findunsel, Base **r_base)
+EditBone *ED_armature_pick_ebone_from_selectbuffer(Base **bases,
+ uint bases_len,
+ const uint *buffer,
+ short hits,
+ bool findunsel,
+ bool do_nearest,
+ Base **r_base)
+{
+ const bool is_editmode = true;
+ return ed_armature_pick_bone_from_selectbuffer_impl(
+ is_editmode, bases, bases_len, buffer, hits, findunsel, do_nearest, r_base);
+}
+
+bPoseChannel *ED_armature_pick_pchan_from_selectbuffer(Base **bases,
+ uint bases_len,
+ const uint *buffer,
+ short hits,
+ bool findunsel,
+ bool do_nearest,
+ Base **r_base)
+{
+ const bool is_editmode = false;
+ return ed_armature_pick_bone_from_selectbuffer_impl(
+ is_editmode, bases, bases_len, buffer, hits, findunsel, do_nearest, r_base);
+}
+
+Bone *ED_armature_pick_bone_from_selectbuffer(Base **bases,
+ uint bases_len,
+ const uint *buffer,
+ short hits,
+ bool findunsel,
+ bool do_nearest,
+ Base **r_base)
+{
+ bPoseChannel *pchan = ED_armature_pick_pchan_from_selectbuffer(
+ bases, bases_len, buffer, hits, findunsel, do_nearest, r_base);
+ return pchan ? pchan->bone : NULL;
+}
+
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Cursor Pick API
+ *
+ * Internal #ed_armature_pick_bone_impl is exposed as:
+ * - #ED_armature_pick_ebone
+ * - #ED_armature_pick_pchan
+ * - #ED_armature_pick_bone
+ * \{ */
+
+/**
+ * \param xy: Cursor coordinates (area space).
+ * \return An #EditBone when is_editmode, otherwise a #bPoseChannel.
+ * \note Only checks objects in the current mode (edit-mode or pose-mode).
+ */
+static void *ed_armature_pick_bone_impl(
+ const bool is_editmode, bContext *C, const int xy[2], bool findunsel, Base **r_base)
{
Depsgraph *depsgraph = CTX_data_ensure_evaluated_depsgraph(C);
ViewContext vc;
rcti rect;
- unsigned int buffer[MAXPICKBUF];
+ uint buffer[MAXPICKBUF];
short hits;
ED_view3d_viewcontext_init(C, &vc, depsgraph);
+ BLI_assert((vc.obedit != NULL) == is_editmode);
- // rect.xmin = ... mouseco!
- rect.xmin = rect.xmax = xy[0];
- rect.ymin = rect.ymax = xy[1];
+ BLI_rcti_init_pt_radius(&rect, xy, 0);
hits = view3d_opengl_select(
&vc, buffer, MAXPICKBUF, &rect, VIEW3D_SELECT_PICK_NEAREST, VIEW3D_SELECT_FILTER_NOP);
@@ -284,123 +359,287 @@ void *get_nearest_bone(bContext *C, const int xy[2], bool findunsel, Base **r_ba
bases = BKE_object_pose_base_array_get(vc.view_layer, vc.v3d, &bases_len);
}
- void *bone = get_bone_from_selectbuffer(
- bases, bases_len, vc.obedit != NULL, buffer, hits, findunsel, true, r_base);
+ void *bone = ed_armature_pick_bone_from_selectbuffer_impl(
+ is_editmode, bases, bases_len, buffer, hits, findunsel, true, r_base);
MEM_freeN(bases);
+
return bone;
}
return NULL;
}
-/* **************** EditMode stuff ********************** */
+EditBone *ED_armature_pick_ebone(bContext *C, const int xy[2], bool findunsel, Base **r_base)
+{
+ const bool is_editmode = true;
+ return ed_armature_pick_bone_impl(is_editmode, C, xy, findunsel, r_base);
+}
-static int armature_select_linked_invoke(bContext *C, wmOperator *op, const wmEvent *event)
+bPoseChannel *ED_armature_pick_pchan(bContext *C, const int xy[2], bool findunsel, Base **r_base)
{
- bArmature *arm;
- EditBone *bone, *curBone, *next;
- const bool sel = !RNA_boolean_get(op->ptr, "deselect");
+ const bool is_editmode = false;
+ return ed_armature_pick_bone_impl(is_editmode, C, xy, findunsel, r_base);
+}
- view3d_operator_needs_opengl(C);
- BKE_object_update_select_id(CTX_data_main(C));
+Bone *ED_armature_pick_bone(bContext *C, const int xy[2], bool findunsel, Base **r_base)
+{
+ bPoseChannel *pchan = ED_armature_pick_pchan(C, xy, findunsel, r_base);
+ return pchan ? pchan->bone : NULL;
+}
- Base *base = NULL;
- bone = get_nearest_bone(C, event->mval, true, &base);
+/** \} */
- if (!bone) {
- return OPERATOR_CANCELLED;
+/* -------------------------------------------------------------------- */
+/** \name Select Linked Implementation
+ *
+ * Shared logic for select linked all/pick.
+ *
+ * Use #BONE_DONE flag to select linked.
+ * \{ */
+
+/**
+ * \param all_forks: Control how chains are stepped over.
+ * true: select all connected bones traveling up & down forks.
+ * false: select all parents and all children, but not the children of the root bone.
+ */
+static bool armature_select_linked_impl(Object *ob, const bool select, const bool all_forks)
+{
+ bool changed = false;
+ bArmature *arm = ob->data;
+
+ /* Implementation note, this flood-fills selected bones with the 'TOUCH' flag,
+ * even though this is a loop-within a loop, walking up the parent chain only touches new bones.
+ * Bones that have been touched are skipped, so the complexity is OK. */
+
+ enum {
+ /* Bone has been walked over, it's LINK value can be read. */
+ TOUCH = (1 << 0),
+ /* When TOUCH has been set, this flag can be checked to see if the bone is connected. */
+ LINK = (1 << 1),
+ };
+
+#define CHECK_PARENT(ebone) \
+ (((ebone)->flag & BONE_CONNECTED) && \
+ ((ebone)->parent ? EBONE_SELECTABLE(arm, (ebone)->parent) : false))
+
+ LISTBASE_FOREACH (EditBone *, ebone, arm->edbo) {
+ ebone->temp.i = 0;
}
- arm = base->object->data;
+ /* Select parents. */
+ LISTBASE_FOREACH (EditBone *, ebone_iter, arm->edbo) {
+ if (ebone_iter->temp.i & TOUCH) {
+ continue;
+ }
+ if ((ebone_iter->flag & BONE_DONE) == 0) {
+ continue;
+ }
+
+ ebone_iter->temp.i |= TOUCH | LINK;
- /* Select parents */
- for (curBone = bone; curBone; curBone = next) {
- if ((curBone->flag & BONE_UNSELECTABLE) == 0) {
- if (sel) {
- curBone->flag |= (BONE_SELECTED | BONE_TIPSEL | BONE_ROOTSEL);
+ /* We have an un-touched link. */
+ for (EditBone *ebone = ebone_iter; ebone; ebone = CHECK_PARENT(ebone) ? ebone->parent : NULL) {
+ ED_armature_ebone_select_set(ebone, select);
+ changed = true;
+
+ if (all_forks) {
+ ebone->temp.i |= (TOUCH | LINK);
}
else {
- curBone->flag &= ~(BONE_SELECTED | BONE_TIPSEL | BONE_ROOTSEL);
+ ebone->temp.i |= TOUCH;
+ }
+ /* Don't walk onto links (messes up 'all_forks' logic). */
+ if (ebone->parent && ebone->parent->temp.i & LINK) {
+ break;
}
}
+ }
- if (curBone->flag & BONE_CONNECTED) {
- next = curBone->parent;
+ /* Select children. */
+ LISTBASE_FOREACH (EditBone *, ebone_iter, arm->edbo) {
+ /* No need to 'touch' this bone as it won't be walked over when scanning up the chain. */
+ if (!CHECK_PARENT(ebone_iter)) {
+ continue;
}
- else {
- next = NULL;
+ if (ebone_iter->temp.i & TOUCH) {
+ continue;
}
- }
- /* Select children */
- while (bone) {
- for (curBone = arm->edbo->first; curBone; curBone = next) {
- next = curBone->next;
- if ((curBone->parent == bone) && (curBone->flag & BONE_UNSELECTABLE) == 0) {
- if (curBone->flag & BONE_CONNECTED) {
- if (sel) {
- curBone->flag |= (BONE_SELECTED | BONE_TIPSEL | BONE_ROOTSEL);
- }
- else {
- curBone->flag &= ~(BONE_SELECTED | BONE_TIPSEL | BONE_ROOTSEL);
- }
- bone = curBone;
- break;
- }
- else {
- bone = NULL;
- break;
+ /* First check if we're marked. */
+ EditBone *ebone_touched_parent = NULL;
+ for (EditBone *ebone = ebone_iter; ebone; ebone = CHECK_PARENT(ebone) ? ebone->parent : NULL) {
+ if (ebone->temp.i & TOUCH) {
+ ebone_touched_parent = ebone;
+ break;
+ }
+ ebone->temp.i |= TOUCH;
+ }
+
+ if ((ebone_touched_parent != NULL) && (ebone_touched_parent->temp.i & LINK)) {
+ for (EditBone *ebone = ebone_iter; ebone != ebone_touched_parent; ebone = ebone->parent) {
+ if ((ebone->temp.i & LINK) == 0) {
+ ebone->temp.i |= LINK;
+ ED_armature_ebone_select_set(ebone, select);
+ changed = true;
}
}
}
- if (!curBone) {
- bone = NULL;
+ }
+
+#undef CHECK_PARENT
+
+ if (changed) {
+ ED_armature_edit_sync_selection(arm->edbo);
+ DEG_id_tag_update(&arm->id, ID_RECALC_COPY_ON_WRITE);
+ WM_main_add_notifier(NC_GPENCIL | ND_DATA | NA_EDITED, ob);
+ }
+
+ return changed;
+}
+
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Select Linked Operator
+ * \{ */
+
+static int armature_select_linked_exec(bContext *C, wmOperator *op)
+{
+ const bool all_forks = RNA_boolean_get(op->ptr, "all_forks");
+
+ bool changed_multi = false;
+ ViewLayer *view_layer = CTX_data_view_layer(C);
+ uint objects_len = 0;
+ Object **objects = BKE_view_layer_array_from_objects_in_edit_mode_unique_data(
+ view_layer, CTX_wm_view3d(C), &objects_len);
+ for (uint ob_index = 0; ob_index < objects_len; ob_index++) {
+ Object *ob = objects[ob_index];
+ bArmature *arm = ob->data;
+
+ bool found = false;
+ LISTBASE_FOREACH (EditBone *, ebone, arm->edbo) {
+ if (EBONE_VISIBLE(arm, ebone) &&
+ (ebone->flag & (BONE_SELECTED | BONE_ROOTSEL | BONE_TIPSEL))) {
+ ebone->flag |= BONE_DONE;
+ found = true;
+ }
+ else {
+ ebone->flag &= ~BONE_DONE;
+ }
+ }
+
+ if (found) {
+ if (armature_select_linked_impl(ob, true, all_forks)) {
+ changed_multi = true;
+ }
}
}
+ MEM_freeN(objects);
- ED_outliner_select_sync_from_edit_bone_tag(C);
+ if (changed_multi) {
+ ED_outliner_select_sync_from_edit_bone_tag(C);
+ }
+ return OPERATOR_FINISHED;
+}
- ED_armature_edit_sync_selection(arm->edbo);
+void ARMATURE_OT_select_linked(wmOperatorType *ot)
+{
+ /* identifiers */
+ ot->name = "Select Linked All";
+ ot->idname = "ARMATURE_OT_select_linked";
+ ot->description = "Select all bones linked by parent/child connections to the current selection";
- WM_event_add_notifier(C, NC_OBJECT | ND_BONE_SELECT, base->object);
- DEG_id_tag_update(&arm->id, ID_RECALC_COPY_ON_WRITE);
+ /* api callbacks */
+ ot->exec = armature_select_linked_exec;
+ ot->poll = ED_operator_editarmature;
+
+ /* flags */
+ ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
+
+ /* Leave disabled by default as this matches pose mode. */
+ RNA_def_boolean(ot->srna, "all_forks", 0, "All Forks", "Follow forks in the parents chain");
+}
+
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Select Linked (Cursor Pick) Operator
+ * \{ */
+
+static int armature_select_linked_pick_invoke(bContext *C, wmOperator *op, const wmEvent *event)
+{
+ const bool select = !RNA_boolean_get(op->ptr, "deselect");
+ const bool all_forks = RNA_boolean_get(op->ptr, "all_forks");
+
+ view3d_operator_needs_opengl(C);
+ BKE_object_update_select_id(CTX_data_main(C));
+
+ Base *base = NULL;
+ EditBone *ebone_active = ED_armature_pick_ebone(C, event->mval, true, &base);
+
+ if (ebone_active == NULL) {
+ return OPERATOR_CANCELLED;
+ }
+
+ bArmature *arm = base->object->data;
+ if (!EBONE_SELECTABLE(arm, ebone_active)) {
+ return OPERATOR_CANCELLED;
+ }
+
+ /* Initialize flags. */
+ LISTBASE_FOREACH (EditBone *, ebone, arm->edbo) {
+ ebone->flag &= ~BONE_DONE;
+ }
+ ebone_active->flag |= BONE_DONE;
+
+ if (armature_select_linked_impl(base->object, select, all_forks)) {
+ ED_outliner_select_sync_from_edit_bone_tag(C);
+ }
return OPERATOR_FINISHED;
}
-static bool armature_select_linked_poll(bContext *C)
+static bool armature_select_linked_pick_poll(bContext *C)
{
return (ED_operator_view3d_active(C) && ED_operator_editarmature(C));
}
-void ARMATURE_OT_select_linked(wmOperatorType *ot)
+void ARMATURE_OT_select_linked_pick(wmOperatorType *ot)
{
/* identifiers */
- ot->name = "Select Connected";
- ot->idname = "ARMATURE_OT_select_linked";
- ot->description = "Select bones related to selected ones by parent/child relationships";
+ ot->name = "Select Linked";
+ ot->idname = "ARMATURE_OT_select_linked_pick";
+ ot->description = "(De)select bones linked by parent/child connections under the mouse cursor";
/* api callbacks */
/* leave 'exec' unset */
- ot->invoke = armature_select_linked_invoke;
- ot->poll = armature_select_linked_poll;
+ ot->invoke = armature_select_linked_pick_invoke;
+ ot->poll = armature_select_linked_pick_poll;
/* flags */
ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
RNA_def_boolean(ot->srna, "deselect", 0, "Deselect", "");
+ /* Leave disabled by default as this matches pose mode. */
+ RNA_def_boolean(ot->srna, "all_forks", 0, "All Forks", "Follow forks in the parents chain");
}
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Select Buffer Queries EditMode
+ * \{ */
+
/* utility function for get_nearest_editbonepoint */
-static int selectbuffer_ret_hits_12(unsigned int *UNUSED(buffer), const int hits12)
+static int selectbuffer_ret_hits_12(uint *UNUSED(buffer), const int hits12)
{
return hits12;
}
-static int selectbuffer_ret_hits_5(unsigned int *buffer, const int hits12, const int hits5)
+static int selectbuffer_ret_hits_5(uint *buffer, const int hits12, const int hits5)
{
const int offs = 4 * hits12;
- memcpy(buffer, buffer + offs, 4 * hits5 * sizeof(unsigned int));
+ memcpy(buffer, buffer + offs, 4 * hits5 * sizeof(uint));
return hits5;
}
@@ -414,45 +653,28 @@ static EditBone *get_nearest_editbonepoint(
uint hitresult;
Base *base;
EditBone *ebone;
- } best = {
- .hitresult = BONESEL_NOSEL,
- .base = NULL,
- .ebone = NULL,
- };
+ } *result = NULL,
+
+ result_cycle = {.hitresult = -1, .base = NULL, .ebone = NULL},
+ result_bias = {.hitresult = -1, .base = NULL, .ebone = NULL};
/* find the bone after the current active bone, so as to bump up its chances in selection.
* this way overlapping bones will cycle selection state as with objects. */
- EditBone *ebone_next_act = ((bArmature *)vc->obedit->data)->act_edbone;
- {
- bArmature *arm = (bArmature *)vc->obedit->data;
- if (ebone_next_act && EBONE_VISIBLE(arm, ebone_next_act) &&
- ebone_next_act->flag & (BONE_SELECTED | BONE_ROOTSEL | BONE_TIPSEL)) {
- ebone_next_act = ebone_next_act->next ? ebone_next_act->next : arm->edbo->first;
- }
- else {
- ebone_next_act = NULL;
- }
+ Object *obedit_orig = vc->obedit;
+ EditBone *ebone_active_orig = ((bArmature *)obedit_orig->data)->act_edbone;
+ if (ebone_active_orig == NULL) {
+ use_cycle = false;
}
- bool do_nearest = false;
-
- /* define if we use solid nearest select or not */
if (use_cycle) {
static int last_mval[2] = {-100, -100};
-
- if (!XRAY_ACTIVE(vc->v3d)) {
- do_nearest = true;
- if (len_manhattan_v2v2_int(vc->mval, last_mval) <= WM_EVENT_CURSOR_MOTION_THRESHOLD) {
- do_nearest = false;
- }
+ if ((len_manhattan_v2v2_int(vc->mval, last_mval) <= WM_EVENT_CURSOR_MOTION_THRESHOLD) == 0) {
+ use_cycle = false;
}
copy_v2_v2_int(last_mval, vc->mval);
}
- else {
- if (!XRAY_ACTIVE(vc->v3d)) {
- do_nearest = true;
- }
- }
+
+ const bool do_nearest = !(XRAY_ACTIVE(vc->v3d) || use_cycle);
/* matching logic from 'mixed_bones_object_selectbuffer' */
int hits = 0;
@@ -506,87 +728,144 @@ cache_end:
/* See if there are any selected bones in this group */
if (hits > 0) {
if (hits == 1) {
- if (!(buffer[3] & BONESEL_NOSEL)) {
- best.hitresult = buffer[3];
- best.base = ED_armature_base_and_ebone_from_select_buffer(
- bases, bases_len, best.hitresult, &best.ebone);
- }
+ result_bias.hitresult = buffer[3];
+ result_bias.base = ED_armature_base_and_ebone_from_select_buffer(
+ bases, bases_len, result_bias.hitresult, &result_bias.ebone);
}
else {
- int dep_min = 5;
+ int bias_max = INT_MIN;
+
+ /* Track Cycle Variables
+ * - Offset is always set to the active bone.
+ * - The object & bone indices subtracted by the 'offset.as_u32' value.
+ * Unsigned subtraction wrapping means we always select the next bone in the cycle.
+ */
+ struct {
+ union {
+ uint32_t as_u32;
+ struct {
+#ifdef __BIG_ENDIAN__
+ uint16_t ob;
+ uint16_t bone;
+#else
+ uint16_t bone;
+ uint16_t ob;
+#endif
+ };
+ } offset, test, best;
+ } cycle_order;
+
+ if (use_cycle) {
+ bArmature *arm = obedit_orig->data;
+ int ob_index = obedit_orig->runtime.select_id & 0xFFFF;
+ int bone_index = BLI_findindex(arm->edbo, ebone_active_orig);
+ /* Offset from the current active bone, so we cycle onto the next. */
+ cycle_order.offset.ob = ob_index;
+ cycle_order.offset.bone = bone_index;
+ /* The value of the active bone (with offset subtracted, a signal to always overwrite). */
+ cycle_order.best.as_u32 = 0;
+ }
+
for (int i = 0; i < hits; i++) {
const uint hitresult = buffer[3 + (i * 4)];
- if (!(hitresult & BONESEL_NOSEL)) {
- Base *base = NULL;
- EditBone *ebone;
- base = ED_armature_base_and_ebone_from_select_buffer(
- bases, bases_len, hitresult, &ebone);
- /* If this fails, selection code is setting the selection ID's incorrectly. */
- BLI_assert(base && ebone);
-
- int dep;
+
+ Base *base = NULL;
+ EditBone *ebone;
+ base = ED_armature_base_and_ebone_from_select_buffer(bases, bases_len, hitresult, &ebone);
+ /* If this fails, selection code is setting the selection ID's incorrectly. */
+ BLI_assert(base && ebone);
+
+ /* Prioritized selection. */
+ {
+ int bias;
/* clicks on bone points get advantage */
if (hitresult & (BONESEL_ROOT | BONESEL_TIP)) {
/* but also the unselected one */
if (findunsel) {
if ((hitresult & BONESEL_ROOT) && (ebone->flag & BONE_ROOTSEL) == 0) {
- dep = 1;
+ bias = 4;
}
else if ((hitresult & BONESEL_TIP) && (ebone->flag & BONE_TIPSEL) == 0) {
- dep = 1;
+ bias = 4;
}
else {
- dep = 2;
+ bias = 3;
}
}
else {
- dep = 1;
+ bias = 4;
}
}
else {
/* bone found */
if (findunsel) {
if ((ebone->flag & BONE_SELECTED) == 0) {
- dep = 3;
+ bias = 2;
}
else {
- dep = 4;
+ bias = 1;
}
}
else {
- dep = 3;
+ bias = 2;
}
}
- if (ebone == ebone_next_act) {
- dep -= 1;
+ if (bias > bias_max) {
+ bias_max = bias;
+
+ result_bias.hitresult = hitresult;
+ result_bias.base = base;
+ result_bias.ebone = ebone;
}
+ }
- if (dep < dep_min) {
- dep_min = dep;
- best.hitresult = hitresult;
- best.base = base;
- best.ebone = ebone;
+ /* Cycle selected items (objects & bones). */
+ if (use_cycle) {
+ cycle_order.test.ob = hitresult & 0xFFFF;
+ cycle_order.test.bone = (hitresult & ~BONESEL_ANY) >> 16;
+ if (ebone == ebone_active_orig) {
+ BLI_assert(cycle_order.test.ob == cycle_order.offset.ob);
+ BLI_assert(cycle_order.test.bone == cycle_order.offset.bone);
+ }
+ /* Subtraction as a single value is needed to support cycling through bones
+ * from multiple objects. So once the last bone is selected,
+ * the bits for the bone index wrap into the object,
+ * causing the next object to be stepped onto. */
+ cycle_order.test.as_u32 -= cycle_order.offset.as_u32;
+
+ /* Even though this logic avoids stepping onto the active bone,
+ * always set the 'best' value for the first time.
+ * Otherwise ensure the value is the smallest it can be,
+ * relative to the active bone, as long as it's not the active bone. */
+ if ((cycle_order.best.as_u32 == 0) ||
+ (cycle_order.test.as_u32 && (cycle_order.test.as_u32 < cycle_order.best.as_u32))) {
+ cycle_order.best = cycle_order.test;
+ result_cycle.hitresult = hitresult;
+ result_cycle.base = base;
+ result_cycle.ebone = ebone;
}
}
}
}
- if (!(best.hitresult & BONESEL_NOSEL)) {
- *r_base = best.base;
+ result = (use_cycle && result_cycle.ebone) ? &result_cycle : &result_bias;
+
+ if (result->hitresult != -1) {
+ *r_base = result->base;
*r_selmask = 0;
- if (best.hitresult & BONESEL_ROOT) {
+ if (result->hitresult & BONESEL_ROOT) {
*r_selmask |= BONE_ROOTSEL;
}
- if (best.hitresult & BONESEL_TIP) {
+ if (result->hitresult & BONESEL_TIP) {
*r_selmask |= BONE_TIPSEL;
}
- if (best.hitresult & BONESEL_BONE) {
+ if (result->hitresult & BONESEL_BONE) {
*r_selmask |= BONE_SELECTED;
}
MEM_freeN(bases);
- return best.ebone;
+ return result->ebone;
}
}
*r_selmask = 0;
@@ -595,11 +874,17 @@ cache_end:
return NULL;
}
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Select Utility Functions
+ * \{ */
+
bool ED_armature_edit_deselect_all(Object *obedit)
{
bArmature *arm = obedit->data;
bool changed = false;
- for (EditBone *ebone = arm->edbo->first; ebone; ebone = ebone->next) {
+ LISTBASE_FOREACH (EditBone *, ebone, arm->edbo) {
if (ebone->flag & (BONE_SELECTED | BONE_TIPSEL | BONE_ROOTSEL)) {
ebone->flag &= ~(BONE_SELECTED | BONE_TIPSEL | BONE_ROOTSEL);
changed = true;
@@ -612,7 +897,7 @@ bool ED_armature_edit_deselect_all_visible(Object *obedit)
{
bArmature *arm = obedit->data;
bool changed = false;
- for (EditBone *ebone = arm->edbo->first; ebone; ebone = ebone->next) {
+ LISTBASE_FOREACH (EditBone *, ebone, arm->edbo) {
/* first and foremost, bone must be visible and selected */
if (EBONE_VISIBLE(arm, ebone)) {
if (ebone->flag & (BONE_SELECTED | BONE_TIPSEL | BONE_ROOTSEL)) {
@@ -661,17 +946,11 @@ bool ED_armature_edit_deselect_all_visible_multi(bContext *C)
return changed_multi;
}
-/* accounts for connected parents */
-static int ebone_select_flag(EditBone *ebone)
-{
- if (ebone->parent && (ebone->flag & BONE_CONNECTED)) {
- return ((ebone->parent->flag & BONE_TIPSEL) ? BONE_ROOTSEL : 0) |
- (ebone->flag & (BONE_SELECTED | BONE_TIPSEL));
- }
- else {
- return ebone->flag & (BONE_SELECTED | BONE_ROOTSEL | BONE_TIPSEL);
- }
-}
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Select Cursor Pick API
+ * \{ */
/* context: editmode armature in view3d */
bool ED_armature_edit_select_pick(
@@ -784,7 +1063,7 @@ bool ED_armature_edit_select_pick(
ED_armature_edit_sync_selection(arm->edbo);
/* then now check for active status */
- if (ebone_select_flag(nearBone)) {
+ if (ED_armature_ebone_selectflag_get(nearBone)) {
arm->act_edbone = nearBone;
}
@@ -800,6 +1079,8 @@ bool ED_armature_edit_select_pick(
return false;
}
+/** \} */
+
/* -------------------------------------------------------------------- */
/** \name Select Op From Tagged
*
@@ -893,7 +1174,7 @@ bool ED_armature_edit_select_op_from_tagged(bArmature *arm, const int sel_op)
/* Initialize flags. */
{
- for (EditBone *ebone = arm->edbo->first; ebone; ebone = ebone->next) {
+ LISTBASE_FOREACH (EditBone *, ebone, arm->edbo) {
/* Flush the parent flag to this bone
* so we don't need to check the parent when adjusting the selection. */
@@ -915,7 +1196,7 @@ bool ED_armature_edit_select_op_from_tagged(bArmature *arm, const int sel_op)
}
/* Apply selection from bone selection flags. */
- for (EditBone *ebone = arm->edbo->first; ebone; ebone = ebone->next) {
+ LISTBASE_FOREACH (EditBone *, ebone, arm->edbo) {
if (ebone->temp.i != 0) {
int is_ignore_flag = ((ebone->temp.i << 16) & (BONESEL_ROOT | BONESEL_TIP));
int is_inside_flag = (ebone->temp.i & (BONESEL_ROOT | BONESEL_TIP | BONESEL_BONE));
@@ -935,7 +1216,7 @@ bool ED_armature_edit_select_op_from_tagged(bArmature *arm, const int sel_op)
if (changed) {
/* Cleanup flags. */
- for (EditBone *ebone = arm->edbo->first; ebone; ebone = ebone->next) {
+ LISTBASE_FOREACH (EditBone *, ebone, arm->edbo) {
if (ebone->flag & BONE_DONE) {
SWAP(int, ebone->temp.i, ebone->flag);
ebone->flag |= BONE_DONE;
@@ -948,7 +1229,7 @@ bool ED_armature_edit_select_op_from_tagged(bArmature *arm, const int sel_op)
}
}
- for (EditBone *ebone = arm->edbo->first; ebone; ebone = ebone->next) {
+ LISTBASE_FOREACH (EditBone *, ebone, arm->edbo) {
if (ebone->flag & BONE_DONE) {
if ((ebone->flag & BONE_CONNECTED) && ebone->parent) {
bool is_parent_tip_changed = (ebone->parent->flag & BONE_TIPSEL) !=
@@ -984,7 +1265,9 @@ bool ED_armature_edit_select_op_from_tagged(bArmature *arm, const int sel_op)
/** \} */
-/* **************** Selections ******************/
+/* -------------------------------------------------------------------- */
+/** \name (De)Select All Operator
+ * \{ */
static int armature_de_select_all_exec(bContext *C, wmOperator *op)
{
@@ -1003,7 +1286,7 @@ static int armature_de_select_all_exec(bContext *C, wmOperator *op)
CTX_DATA_END;
}
- /* Set the flags */
+ /* Set the flags. */
CTX_DATA_BEGIN (C, EditBone *, ebone, visible_bones) {
/* ignore bone if selection can't change */
switch (action) {
@@ -1063,7 +1346,11 @@ void ARMATURE_OT_select_all(wmOperatorType *ot)
WM_operator_properties_select_all(ot);
}
-/**************** Select more/less **************/
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Select More/Less Implementation
+ * \{ */
static void armature_select_more(bArmature *arm, EditBone *ebone)
{
@@ -1150,6 +1437,12 @@ static void armature_select_more_less(Object *ob, bool more)
ED_armature_edit_sync_selection(arm->edbo);
}
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Select More Operator
+ * \{ */
+
static int armature_de_select_more_exec(bContext *C, wmOperator *UNUSED(op))
{
ViewLayer *view_layer = CTX_data_view_layer(C);
@@ -1183,6 +1476,12 @@ void ARMATURE_OT_select_more(wmOperatorType *ot)
ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
}
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Select Less Operator
+ * \{ */
+
static int armature_de_select_less_exec(bContext *C, wmOperator *UNUSED(op))
{
ViewLayer *view_layer = CTX_data_view_layer(C);
@@ -1216,6 +1515,12 @@ void ARMATURE_OT_select_less(wmOperatorType *ot)
ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
}
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Select Similar
+ * \{ */
+
enum {
SIMEDBONE_CHILDREN = 1,
SIMEDBONE_CHILDREN_IMMEDIATE,
@@ -1270,7 +1575,7 @@ static void select_similar_length(bContext *C, const float thresh)
bArmature *arm = ob->data;
bool changed = false;
- for (EditBone *ebone = arm->edbo->first; ebone; ebone = ebone->next) {
+ LISTBASE_FOREACH (EditBone *, ebone, arm->edbo) {
if (EBONE_SELECTABLE(arm, ebone)) {
const float len_iter = bone_length_squared_worldspace_get(ob, ebone);
if ((len_iter > len_min) && (len_iter < len_max)) {
@@ -1318,7 +1623,7 @@ static void select_similar_direction(bContext *C, const float thresh)
bArmature *arm = ob->data;
bool changed = false;
- for (EditBone *ebone = arm->edbo->first; ebone; ebone = ebone->next) {
+ LISTBASE_FOREACH (EditBone *, ebone, arm->edbo) {
if (EBONE_SELECTABLE(arm, ebone)) {
float dir[3];
bone_direction_worldspace_get(ob, ebone, dir);
@@ -1352,7 +1657,7 @@ static void select_similar_layer(bContext *C)
bArmature *arm = ob->data;
bool changed = false;
- for (EditBone *ebone = arm->edbo->first; ebone; ebone = ebone->next) {
+ LISTBASE_FOREACH (EditBone *, ebone, arm->edbo) {
if (EBONE_SELECTABLE(arm, ebone)) {
if (ebone->layer & ebone_act->layer) {
ED_armature_ebone_select_set(ebone, true);
@@ -1392,7 +1697,7 @@ static void select_similar_prefix(bContext *C)
bool changed = false;
/* Find matches */
- for (EditBone *ebone = arm->edbo->first; ebone; ebone = ebone->next) {
+ LISTBASE_FOREACH (EditBone *, ebone, arm->edbo) {
if (EBONE_SELECTABLE(arm, ebone)) {
char prefix_other[MAXBONENAME];
BLI_string_split_prefix(ebone->name, prefix_other, body_tmp, sizeof(ebone->name));
@@ -1434,7 +1739,7 @@ static void select_similar_suffix(bContext *C)
bool changed = false;
/* Find matches */
- for (EditBone *ebone = arm->edbo->first; ebone; ebone = ebone->next) {
+ LISTBASE_FOREACH (EditBone *, ebone, arm->edbo) {
if (EBONE_SELECTABLE(arm, ebone)) {
char suffix_other[MAXBONENAME];
BLI_string_split_suffix(ebone->name, body_tmp, suffix_other, sizeof(ebone->name));
@@ -1469,7 +1774,7 @@ static void select_similar_data_pchan(bContext *C, const size_t bytes_size, cons
}
const char *data_active = (const char *)POINTER_OFFSET(pchan_active, offset);
- for (EditBone *ebone = arm->edbo->first; ebone; ebone = ebone->next) {
+ LISTBASE_FOREACH (EditBone *, ebone, arm->edbo) {
if (EBONE_SELECTABLE(arm, ebone)) {
const bPoseChannel *pchan = BKE_pose_channel_find_name(obedit->pose, ebone->name);
if (pchan) {
@@ -1504,11 +1809,11 @@ static void select_similar_children(bContext *C)
bArmature *arm = obedit->data;
EditBone *ebone_act = CTX_data_active_bone(C);
- for (EditBone *ebone_iter = arm->edbo->first; ebone_iter; ebone_iter = ebone_iter->next) {
+ LISTBASE_FOREACH (EditBone *, ebone_iter, arm->edbo) {
ebone_iter->temp.ebone = ebone_iter->parent;
}
- for (EditBone *ebone_iter = arm->edbo->first; ebone_iter; ebone_iter = ebone_iter->next) {
+ LISTBASE_FOREACH (EditBone *, ebone_iter, arm->edbo) {
is_ancestor(ebone_iter, ebone_act);
if (ebone_iter->temp.ebone == ebone_act && EBONE_SELECTABLE(arm, ebone_iter)) {
@@ -1526,7 +1831,7 @@ static void select_similar_children_immediate(bContext *C)
bArmature *arm = obedit->data;
EditBone *ebone_act = CTX_data_active_bone(C);
- for (EditBone *ebone_iter = arm->edbo->first; ebone_iter; ebone_iter = ebone_iter->next) {
+ LISTBASE_FOREACH (EditBone *, ebone_iter, arm->edbo) {
if (ebone_iter->parent == ebone_act && EBONE_SELECTABLE(arm, ebone_iter)) {
ED_armature_ebone_select_set(ebone_iter, true);
}
@@ -1546,7 +1851,7 @@ static void select_similar_siblings(bContext *C)
return;
}
- for (EditBone *ebone_iter = arm->edbo->first; ebone_iter; ebone_iter = ebone_iter->next) {
+ LISTBASE_FOREACH (EditBone *, ebone_iter, arm->edbo) {
if (ebone_iter->parent == ebone_act->parent && EBONE_SELECTABLE(arm, ebone_iter)) {
ED_armature_ebone_select_set(ebone_iter, true);
}
@@ -1631,7 +1936,11 @@ void ARMATURE_OT_select_similar(wmOperatorType *ot)
RNA_def_float(ot->srna, "threshold", 0.1f, 0.0f, 1.0f, "Threshold", "", 0.0f, 1.0f);
}
-/* ********************* select hierarchy operator ************** */
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Select Hierarchy Operator
+ * \{ */
/* No need to convert to multi-objects. Just like we keep the non-active bones
* selected we then keep the non-active objects untouched (selected/unselected). */
@@ -1737,7 +2046,11 @@ void ARMATURE_OT_select_hierarchy(wmOperatorType *ot)
RNA_def_boolean(ot->srna, "extend", false, "Extend", "Extend the selection");
}
-/****************** Mirror Select ****************/
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Select Mirror Operator
+ * \{ */
/**
* \note clone of #pose_select_mirror_exec keep in sync
@@ -1822,7 +2135,11 @@ void ARMATURE_OT_select_mirror(wmOperatorType *ot)
RNA_def_boolean(ot->srna, "extend", false, "Extend", "Extend the selection");
}
-/****************** Select Path ****************/
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Select Path Operator
+ * \{ */
static bool armature_shortest_path_select(
bArmature *arm, EditBone *ebone_parent, EditBone *ebone_child, bool use_parent, bool is_test)
@@ -1866,7 +2183,7 @@ static int armature_shortest_path_pick_invoke(bContext *C, wmOperator *op, const
BKE_object_update_select_id(CTX_data_main(C));
ebone_src = arm->act_edbone;
- ebone_dst = get_nearest_bone(C, event->mval, false, &base_dst);
+ ebone_dst = ED_armature_pick_ebone(C, event->mval, false, &base_dst);
/* fallback to object selection */
if (ELEM(NULL, ebone_src, ebone_dst) || (ebone_src == ebone_dst)) {
@@ -1948,3 +2265,5 @@ void ARMATURE_OT_shortest_path_pick(wmOperatorType *ot)
/* flags */
ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
}
+
+/** \} */
diff --git a/source/blender/editors/armature/armature_skinning.c b/source/blender/editors/armature/armature_skinning.c
index 87f980db7b9..61d8856afbc 100644
--- a/source/blender/editors/armature/armature_skinning.c
+++ b/source/blender/editors/armature/armature_skinning.c
@@ -418,7 +418,7 @@ static void add_verts_to_dgroups(ReportList *reports,
BKE_mesh_foreach_mapped_vert_coords_get(me_eval, verts, mesh->totvert);
vertsfilled = 1;
}
- else if (modifiers_findByType(ob, eModifierType_Subsurf)) {
+ else if (BKE_modifiers_findby_type(ob, eModifierType_Subsurf)) {
/* is subsurf on? Lets use the verts on the limit surface then.
* = same amount of vertices as mesh, but vertices moved to the
* subsurfed position, like for 'optimal'. */
@@ -459,7 +459,7 @@ static void add_verts_to_dgroups(ReportList *reports,
}
/* only generated in some cases but can call anyway */
- ED_mesh_mirror_spatial_table(ob, NULL, NULL, NULL, 'e');
+ ED_mesh_mirror_spatial_table_end(ob);
/* free the memory allocated */
MEM_freeN(bonelist);
diff --git a/source/blender/editors/armature/armature_utils.c b/source/blender/editors/armature/armature_utils.c
index 76361f6785b..cf7f6699e5e 100644
--- a/source/blender/editors/armature/armature_utils.c
+++ b/source/blender/editors/armature/armature_utils.c
@@ -92,7 +92,7 @@ void ED_armature_edit_validate_active(struct bArmature *arm)
void ED_armature_edit_refresh_layer_used(bArmature *arm)
{
arm->layer_used = 0;
- for (EditBone *ebo = arm->edbo->first; ebo; ebo = ebo->next) {
+ LISTBASE_FOREACH (EditBone *, ebo, arm->edbo) {
arm->layer_used |= ebo->layer;
}
}
@@ -142,7 +142,7 @@ void bone_free(bArmature *arm, EditBone *bone)
}
/* Clear references from other edit bones. */
- for (EditBone *ebone = arm->edbo->first; ebone; ebone = ebone->next) {
+ LISTBASE_FOREACH (EditBone *, ebone, arm->edbo) {
if (ebone->bbone_next == bone) {
ebone->bbone_next = NULL;
}
@@ -196,13 +196,12 @@ bool ED_armature_ebone_is_child_recursive(EditBone *ebone_parent, EditBone *ebon
* \param ebone_child_tot: Size of the ebone_child array
* \return The shared parent or NULL.
*/
-EditBone *ED_armature_ebone_find_shared_parent(EditBone *ebone_child[],
- const unsigned int ebone_child_tot)
+EditBone *ED_armature_ebone_find_shared_parent(EditBone *ebone_child[], const uint ebone_child_tot)
{
- unsigned int i;
+ uint i;
EditBone *ebone_iter;
-#define EBONE_TEMP_UINT(ebone) (*((unsigned int *)(&((ebone)->temp))))
+#define EBONE_TEMP_UINT(ebone) (*((uint *)(&((ebone)->temp))))
/* clear all */
for (i = 0; i < ebone_child_tot; i++) {
@@ -473,7 +472,7 @@ void ED_armature_ebone_transform_mirror_update(bArmature *arm, EditBone *ebo, bo
void ED_armature_edit_transform_mirror_update(Object *obedit)
{
bArmature *arm = obedit->data;
- for (EditBone *ebo = arm->edbo->first; ebo; ebo = ebo->next) {
+ LISTBASE_FOREACH (EditBone *, ebo, arm->edbo) {
ED_armature_ebone_transform_mirror_update(arm, ebo, true);
}
}
@@ -482,10 +481,10 @@ void ED_armature_edit_transform_mirror_update(Object *obedit)
/* Armature EditMode Conversions */
/* converts Bones to EditBone list, used for tools as well */
-static EditBone *make_boneList_rec(ListBase *edbo,
- ListBase *bones,
- EditBone *parent,
- Bone *actBone)
+static EditBone *make_boneList_recursive(ListBase *edbo,
+ ListBase *bones,
+ EditBone *parent,
+ Bone *actBone)
{
EditBone *eBone;
EditBone *eBoneAct = NULL;
@@ -562,9 +561,9 @@ static EditBone *make_boneList_rec(ListBase *edbo,
BLI_addtail(edbo, eBone);
- /* Add children if necessary */
+ /* Add children if necessary. */
if (curBone->childbase.first) {
- eBoneTest = make_boneList_rec(edbo, &curBone->childbase, eBone, actBone);
+ eBoneTest = make_boneList_recursive(edbo, &curBone->childbase, eBone, actBone);
if (eBoneTest) {
eBoneAct = eBoneTest;
}
@@ -581,7 +580,7 @@ static EditBone *make_boneList_rec(ListBase *edbo,
static EditBone *find_ebone_link(ListBase *edbo, Bone *link)
{
if (link != NULL) {
- for (EditBone *ebone = edbo->first; ebone; ebone = ebone->next) {
+ LISTBASE_FOREACH (EditBone *, ebone, edbo) {
if (ebone->temp.bone == link) {
return ebone;
}
@@ -595,9 +594,9 @@ EditBone *make_boneList(ListBase *edbo, ListBase *bones, struct Bone *actBone)
{
BLI_assert(!edbo->first && !edbo->last);
- EditBone *active = make_boneList_rec(edbo, bones, NULL, actBone);
+ EditBone *active = make_boneList_recursive(edbo, bones, NULL, actBone);
- for (EditBone *ebone = edbo->first; ebone; ebone = ebone->next) {
+ LISTBASE_FOREACH (EditBone *, ebone, edbo) {
Bone *bone = ebone->temp.bone;
/* Convert custom B-Bone handle links. */
@@ -721,7 +720,7 @@ void ED_armature_from_edit(Main *bmain, bArmature *arm)
}
}
- /* Copy the bones from the editData into the armature */
+ /* Copy the bones from the edit-data into the armature. */
for (eBone = arm->edbo->first; eBone; eBone = eBone->next) {
newBone = MEM_callocN(sizeof(Bone), "bone");
eBone->temp.bone = newBone; /* Associate the real Bones with the EditBones */
@@ -819,7 +818,7 @@ void ED_armature_edit_free(struct bArmature *arm)
{
EditBone *eBone;
- /* Clear the editbones list */
+ /* Clear the edit-bones list. */
if (arm->edbo) {
if (arm->edbo->first) {
for (eBone = arm->edbo->first; eBone; eBone = eBone->next) {
diff --git a/source/blender/editors/armature/editarmature_undo.c b/source/blender/editors/armature/editarmature_undo.c
index c73f8f69fdd..a3a73f8d509 100644
--- a/source/blender/editors/armature/editarmature_undo.c
+++ b/source/blender/editors/armature/editarmature_undo.c
@@ -29,6 +29,7 @@
#include "DNA_object_types.h"
#include "BLI_array_utils.h"
+#include "BLI_listbase.h"
#include "BKE_context.h"
#include "BKE_layer.h"
@@ -94,7 +95,7 @@ static void *undoarm_from_editarm(UndoArmature *uarm, bArmature *arm)
ED_armature_ebone_listbase_temp_clear(&uarm->lb);
- for (EditBone *ebone = uarm->lb.first; ebone; ebone = ebone->next) {
+ LISTBASE_FOREACH (EditBone *, ebone, &uarm->lb) {
uarm->undo_size += sizeof(EditBone);
}
diff --git a/source/blender/editors/armature/meshlaplacian.c b/source/blender/editors/armature/meshlaplacian.c
index 6028ddb216f..d8a6a22a7df 100644
--- a/source/blender/editors/armature/meshlaplacian.c
+++ b/source/blender/editors/armature/meshlaplacian.c
@@ -1549,7 +1549,7 @@ static void meshdeform_matrix_solve(MeshDeformModifierData *mmd, MeshDeformBind
}
}
else {
- modifier_setError(&mmd->modifier, "Failed to find bind solution (increase precision?)");
+ BKE_modifier_set_error(&mmd->modifier, "Failed to find bind solution (increase precision?)");
error("Mesh Deform: failed to find bind solution.");
break;
}
@@ -1753,7 +1753,7 @@ void ED_mesh_deform_bind_callback(MeshDeformModifierData *mmd,
int totvert,
float cagemat[4][4])
{
- MeshDeformModifierData *mmd_orig = (MeshDeformModifierData *)modifier_get_original(
+ MeshDeformModifierData *mmd_orig = (MeshDeformModifierData *)BKE_modifier_get_original(
&mmd->modifier);
MeshDeformBind mdb;
MVert *mvert;
@@ -1799,7 +1799,7 @@ void ED_mesh_deform_bind_callback(MeshDeformModifierData *mmd,
MEM_freeN(mdb.vertexcos);
/* compact weights */
- modifier_mdef_compact_influences((ModifierData *)mmd_orig);
+ BKE_modifier_mdef_compact_influences((ModifierData *)mmd_orig);
end_progress_bar();
waitcursor(0);
diff --git a/source/blender/editors/armature/pose_edit.c b/source/blender/editors/armature/pose_edit.c
index 09b6cd9c8cc..0cd3afc9cf9 100644
--- a/source/blender/editors/armature/pose_edit.c
+++ b/source/blender/editors/armature/pose_edit.c
@@ -33,7 +33,7 @@
#include "DNA_scene_types.h"
#include "BKE_action.h"
-#include "BKE_anim.h"
+#include "BKE_anim_visualization.h"
#include "BKE_armature.h"
#include "BKE_context.h"
#include "BKE_deform.h"
@@ -75,12 +75,12 @@
/* matches logic with ED_operator_posemode_context() */
Object *ED_pose_object_from_context(bContext *C)
{
- ScrArea *sa = CTX_wm_area(C);
+ ScrArea *area = CTX_wm_area(C);
Object *ob;
/* Since this call may also be used from the buttons window,
* we need to check for where to get the object. */
- if (sa && sa->spacetype == SPACE_PROPERTIES) {
+ if (area && area->spacetype == SPACE_PROPERTIES) {
ob = ED_object_context(C);
}
else {
@@ -665,6 +665,11 @@ static int pose_bone_rotmode_exec(bContext *C, wmOperator *op)
/* set rotation mode of selected bones */
CTX_DATA_BEGIN_WITH_ID (C, bPoseChannel *, pchan, selected_pose_bones, Object *, ob) {
+ /* use API Method for conversions... */
+ BKE_rotMode_change_values(
+ pchan->quat, pchan->eul, pchan->rotAxis, &pchan->rotAngle, pchan->rotmode, (short)mode);
+
+ /* finally, set the new rotation type */
pchan->rotmode = mode;
if (prev_ob != ob) {
@@ -901,8 +906,6 @@ static int pose_bone_layers_exec(bContext *C, wmOperator *op)
RNA_boolean_set_array(&ptr, "layers", layers);
if (prev_ob != ob) {
- BKE_armature_refresh_layer_used(ob->data);
-
/* Note, notifier might evolve. */
WM_event_add_notifier(C, NC_OBJECT | ND_POSE, ob);
DEG_id_tag_update((ID *)ob->data, ID_RECALC_COPY_ON_WRITE);
diff --git a/source/blender/editors/armature/pose_group.c b/source/blender/editors/armature/pose_group.c
index 9cd87f476d4..c10e204e3a4 100644
--- a/source/blender/editors/armature/pose_group.c
+++ b/source/blender/editors/armature/pose_group.c
@@ -44,6 +44,7 @@
#include "WM_types.h"
#include "ED_armature.h"
+#include "ED_outliner.h"
#include "ED_screen.h"
#include "UI_interface.h"
@@ -484,6 +485,7 @@ static int pose_group_select_exec(bContext *C, wmOperator *UNUSED(op))
bArmature *arm = ob->data;
DEG_id_tag_update(&arm->id, ID_RECALC_SELECT);
WM_event_add_notifier(C, NC_OBJECT | ND_POSE, ob);
+ ED_outliner_select_sync_from_pose_bone_tag(C);
return OPERATOR_FINISHED;
}
@@ -518,6 +520,7 @@ static int pose_group_deselect_exec(bContext *C, wmOperator *UNUSED(op))
bArmature *arm = ob->data;
DEG_id_tag_update(&arm->id, ID_RECALC_SELECT);
WM_event_add_notifier(C, NC_OBJECT | ND_POSE, ob);
+ ED_outliner_select_sync_from_pose_bone_tag(C);
return OPERATOR_FINISHED;
}
diff --git a/source/blender/editors/armature/pose_lib.c b/source/blender/editors/armature/pose_lib.c
index f759808d08e..aa57fb5844d 100644
--- a/source/blender/editors/armature/pose_lib.c
+++ b/source/blender/editors/armature/pose_lib.c
@@ -161,16 +161,16 @@ static TimeMarker *poselib_get_active_pose(bAction *act)
/* XXX C can be zero */
static Object *get_poselib_object(bContext *C)
{
- ScrArea *sa;
+ ScrArea *area;
/* sanity check */
if (C == NULL) {
return NULL;
}
- sa = CTX_wm_area(C);
+ area = CTX_wm_area(C);
- if (sa && (sa->spacetype == SPACE_PROPERTIES)) {
+ if (area && (area->spacetype == SPACE_PROPERTIES)) {
return ED_object_context(C);
}
else {
@@ -626,7 +626,7 @@ static int poselib_remove_exec(bContext *C, wmOperator *op)
/* remove relevant keyframes */
for (fcu = act->curves.first; fcu; fcu = fcu->next) {
BezTriple *bezt;
- unsigned int i;
+ uint i;
if (fcu->bezt) {
for (i = 0, bezt = fcu->bezt; i < fcu->totvert; i++, bezt++) {
@@ -870,7 +870,7 @@ typedef struct tPoseLib_PreviewData {
/** active scene. */
Scene *scene;
/** active area. */
- ScrArea *sa;
+ ScrArea *area;
/** RNA-Pointer to Object 'ob' .*/
PointerRNA rna_ptr;
@@ -1171,7 +1171,7 @@ static void poselib_preview_apply(bContext *C, wmOperator *op)
/* do header print - if interactively previewing */
if (pld->state == PL_PREVIEW_RUNNING) {
if (pld->flag & PL_PREVIEW_SHOWORIGINAL) {
- ED_area_status_text(pld->sa, TIP_("PoseLib Previewing Pose: [Showing Original Pose]"));
+ ED_area_status_text(pld->area, TIP_("PoseLib Previewing Pose: [Showing Original Pose]"));
ED_workspace_status_text(C, TIP_("Use Tab to start previewing poses again"));
}
else if (pld->searchstr[0]) {
@@ -1200,7 +1200,7 @@ static void poselib_preview_apply(bContext *C, wmOperator *op)
"Current Pose - \"%s\""),
tempstr,
markern);
- ED_area_status_text(pld->sa, pld->headerstr);
+ ED_area_status_text(pld->area, pld->headerstr);
ED_workspace_status_text(C, TIP_("Use ScrollWheel or PageUp/Down to change pose"));
}
else {
@@ -1208,7 +1208,7 @@ static void poselib_preview_apply(bContext *C, wmOperator *op)
sizeof(pld->headerstr),
TIP_("PoseLib Previewing Pose: \"%s\""),
pld->marker->name);
- ED_area_status_text(pld->sa, pld->headerstr);
+ ED_area_status_text(pld->area, pld->headerstr);
ED_workspace_status_text(C, NULL);
}
}
@@ -1323,9 +1323,7 @@ static void poselib_preview_get_next(tPoseLib_PreviewData *pld, int step)
}
/* specially handle events for searching */
-static void poselib_preview_handle_search(tPoseLib_PreviewData *pld,
- unsigned short event,
- char ascii)
+static void poselib_preview_handle_search(tPoseLib_PreviewData *pld, ushort event, char ascii)
{
/* try doing some form of string manipulation first */
switch (event) {
@@ -1633,7 +1631,7 @@ static void poselib_preview_init_data(bContext *C, wmOperator *op)
pld->act = (ob) ? (ob->poselib) : NULL;
pld->scene = CTX_data_scene(C);
- pld->sa = CTX_wm_area(C);
+ pld->area = CTX_wm_area(C);
/* get starting pose based on RNA-props for this operator */
if (pose_index == -1) {
@@ -1704,7 +1702,7 @@ static void poselib_preview_cleanup(bContext *C, wmOperator *op)
TimeMarker *marker = pld->marker;
/* redraw the header so that it doesn't show any of our stuff anymore */
- ED_area_status_text(pld->sa, NULL);
+ ED_area_status_text(pld->area, NULL);
ED_workspace_status_text(C, NULL);
/* this signal does one recalc on pose, then unlocks, so ESC or edit will work */
diff --git a/source/blender/editors/armature/pose_select.c b/source/blender/editors/armature/pose_select.c
index 07be2baf1ae..9525fcf2154 100644
--- a/source/blender/editors/armature/pose_select.c
+++ b/source/blender/editors/armature/pose_select.c
@@ -141,7 +141,7 @@ void ED_pose_bone_select(Object *ob, bPoseChannel *pchan, bool select)
bool ED_armature_pose_select_pick_with_buffer(ViewLayer *view_layer,
View3D *v3d,
Base *base,
- const unsigned int *buffer,
+ const uint *buffer,
short hits,
bool extend,
bool deselect,
@@ -156,12 +156,12 @@ bool ED_armature_pose_select_pick_with_buffer(ViewLayer *view_layer,
}
Object *ob_act = OBACT(view_layer);
- Object *obedit = OBEDIT_FROM_VIEW_LAYER(view_layer);
+ BLI_assert(OBEDIT_FROM_VIEW_LAYER(view_layer) == NULL);
/* Callers happen to already get the active base */
Base *base_dummy = NULL;
- nearBone = get_bone_from_selectbuffer(
- &base, 1, obedit != NULL, buffer, hits, 1, do_nearest, &base_dummy);
+ nearBone = ED_armature_pick_bone_from_selectbuffer(
+ &base, 1, buffer, hits, 1, do_nearest, &base_dummy);
/* if the bone cannot be affected, don't do anything */
if ((nearBone) && !(nearBone->flag & BONE_UNSELECTABLE)) {
@@ -263,7 +263,7 @@ void ED_armature_pose_select_in_wpaint_mode(ViewLayer *view_layer, Base *base_se
Object *ob_active = OBACT(view_layer);
BLI_assert(ob_active && (ob_active->mode & OB_MODE_WEIGHT_PAINT));
VirtualModifierData virtualModifierData;
- ModifierData *md = modifiers_getVirtualModifierList(ob_active, &virtualModifierData);
+ ModifierData *md = BKE_modifiers_get_virtual_modifierlist(ob_active, &virtualModifierData);
for (; md; md = md->next) {
if (md->type == eModifierType_Armature) {
ArmatureModifierData *amd = (ArmatureModifierData *)md;
@@ -323,7 +323,7 @@ bool ED_pose_deselect_all(Object *ob, int select_mode, const bool ignore_visibil
static bool ed_pose_is_any_selected(Object *ob, bool ignore_visibility)
{
bArmature *arm = ob->data;
- for (bPoseChannel *pchan = ob->pose->chanbase.first; pchan; pchan = pchan->next) {
+ LISTBASE_FOREACH (bPoseChannel *, pchan, &ob->pose->chanbase) {
if (ignore_visibility || PBONE_VISIBLE(arm, pchan->bone)) {
if (pchan->bone->flag & BONE_SELECTED) {
return true;
@@ -413,7 +413,7 @@ static int pose_select_connected_invoke(bContext *C, wmOperator *op, const wmEve
view3d_operator_needs_opengl(C);
Base *base = NULL;
- bone = get_nearest_bone(C, event->mval, !extend, &base);
+ bone = ED_armature_pick_bone(C, event->mval, !extend, &base);
if (!bone) {
return OPERATOR_CANCELLED;
@@ -443,7 +443,7 @@ static int pose_select_connected_invoke(bContext *C, wmOperator *op, const wmEve
}
/* Select children */
- for (curBone = bone->childbase.first; curBone; curBone = next) {
+ for (curBone = bone->childbase.first; curBone; curBone = curBone->next) {
selectconnected_posebonechildren(base->object, curBone, extend);
}
@@ -454,22 +454,22 @@ static int pose_select_connected_invoke(bContext *C, wmOperator *op, const wmEve
return OPERATOR_FINISHED;
}
-static bool pose_select_linked_poll(bContext *C)
+static bool pose_select_linked_pick_poll(bContext *C)
{
return (ED_operator_view3d_active(C) && ED_operator_posemode(C));
}
-void POSE_OT_select_linked(wmOperatorType *ot)
+void POSE_OT_select_linked_pick(wmOperatorType *ot)
{
/* identifiers */
ot->name = "Select Connected";
- ot->idname = "POSE_OT_select_linked";
- ot->description = "Select bones related to selected ones by parent/child relationships";
+ ot->idname = "POSE_OT_select_linked_pick";
+ ot->description = "Select bones linked by parent/child connections under the mouse cursor";
/* callbacks */
/* leave 'exec' unset */
ot->invoke = pose_select_connected_invoke;
- ot->poll = pose_select_linked_poll;
+ ot->poll = pose_select_linked_pick_poll;
/* flags */
ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
@@ -482,6 +482,62 @@ void POSE_OT_select_linked(wmOperatorType *ot)
"Extend selection instead of deselecting everything first");
}
+static int pose_select_linked_exec(bContext *C, wmOperator *UNUSED(op))
+{
+ Bone *curBone, *next = NULL;
+
+ CTX_DATA_BEGIN_WITH_ID (C, bPoseChannel *, pchan, visible_pose_bones, Object *, ob) {
+ if ((pchan->bone->flag & BONE_SELECTED) == 0) {
+ continue;
+ }
+
+ bArmature *arm = ob->data;
+
+ /* Select parents */
+ for (curBone = pchan->bone; curBone; curBone = next) {
+ if (PBONE_SELECTABLE(arm, curBone)) {
+ curBone->flag |= BONE_SELECTED;
+
+ if (curBone->flag & BONE_CONNECTED) {
+ next = curBone->parent;
+ }
+ else {
+ next = NULL;
+ }
+ }
+ else {
+ next = NULL;
+ }
+ }
+
+ /* Select children */
+ for (curBone = pchan->bone->childbase.first; curBone; curBone = curBone->next) {
+ selectconnected_posebonechildren(ob, curBone, false);
+ }
+ ED_pose_bone_select_tag_update(ob);
+ }
+ CTX_DATA_END;
+
+ ED_outliner_select_sync_from_pose_bone_tag(C);
+
+ return OPERATOR_FINISHED;
+}
+
+void POSE_OT_select_linked(wmOperatorType *ot)
+{
+ /* identifiers */
+ ot->name = "Select Connected";
+ ot->idname = "POSE_OT_select_linked";
+ ot->description = "Select all bones linked by parent/child connections to the current selection";
+
+ /* callbacks */
+ ot->exec = pose_select_linked_exec;
+ ot->poll = ED_operator_posemode;
+
+ /* flags */
+ ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
+}
+
/* -------------------------------------- */
static int pose_de_select_all_exec(bContext *C, wmOperator *op)
@@ -497,7 +553,7 @@ static int pose_de_select_all_exec(bContext *C, wmOperator *op)
Object *ob_prev = NULL;
- /* Set the flags */
+ /* Set the flags. */
CTX_DATA_BEGIN_WITH_ID (C, bPoseChannel *, pchan, visible_pose_bones, Object *, ob) {
bArmature *arm = ob->data;
pose_do_bone_select(pchan, action);
diff --git a/source/blender/editors/armature/pose_slide.c b/source/blender/editors/armature/pose_slide.c
index 336d09f71b5..d9621dba730 100644
--- a/source/blender/editors/armature/pose_slide.c
+++ b/source/blender/editors/armature/pose_slide.c
@@ -86,7 +86,7 @@ typedef struct tPoseSlideOp {
/** current scene */
Scene *scene;
/** area that we're operating in (needed for modal()) */
- ScrArea *sa;
+ ScrArea *area;
/** region that we're operating in (needed for modal()) */
ARegion *region;
/** len of the PoseSlideObject array. */
@@ -197,7 +197,7 @@ static int pose_slide_init(bContext *C, wmOperator *op, ePoseSlide_Modes mode)
/* get info from context */
pso->scene = CTX_data_scene(C);
- pso->sa = CTX_wm_area(C); /* only really needed when doing modal() */
+ pso->area = CTX_wm_area(C); /* only really needed when doing modal() */
pso->region = CTX_wm_region(C); /* only really needed when doing modal() */
pso->cframe = pso->scene->r.cfra;
@@ -544,71 +544,56 @@ static void pose_slide_apply_quat(tPoseSlideOp *pso, tPChanFCurveLink *pfl)
/* only if all channels exist, proceed */
if (fcu_w && fcu_x && fcu_y && fcu_z) {
- float quat_prev[4], quat_prev_orig[4];
- float quat_next[4], quat_next_orig[4];
- float quat_curr[4], quat_curr_orig[4];
float quat_final[4];
- copy_qt_qt(quat_curr_orig, pchan->quat);
-
- /* get 2 quats */
- quat_prev_orig[0] = evaluate_fcurve(fcu_w, prevFrameF);
- quat_prev_orig[1] = evaluate_fcurve(fcu_x, prevFrameF);
- quat_prev_orig[2] = evaluate_fcurve(fcu_y, prevFrameF);
- quat_prev_orig[3] = evaluate_fcurve(fcu_z, prevFrameF);
-
- quat_next_orig[0] = evaluate_fcurve(fcu_w, nextFrameF);
- quat_next_orig[1] = evaluate_fcurve(fcu_x, nextFrameF);
- quat_next_orig[2] = evaluate_fcurve(fcu_y, nextFrameF);
- quat_next_orig[3] = evaluate_fcurve(fcu_z, nextFrameF);
-
- normalize_qt_qt(quat_prev, quat_prev_orig);
- normalize_qt_qt(quat_next, quat_next_orig);
- normalize_qt_qt(quat_curr, quat_curr_orig);
-
/* perform blending */
if (pso->mode == POSESLIDE_BREAKDOWN) {
/* Just perform the interpolation between quat_prev and
* quat_next using pso->percentage as a guide. */
- interp_qt_qtqt(quat_final, quat_prev, quat_next, pso->percentage);
- }
- else if (pso->mode == POSESLIDE_PUSH) {
- float quat_diff[4];
+ float quat_prev[4];
+ float quat_next[4];
+
+ quat_prev[0] = evaluate_fcurve(fcu_w, prevFrameF);
+ quat_prev[1] = evaluate_fcurve(fcu_x, prevFrameF);
+ quat_prev[2] = evaluate_fcurve(fcu_y, prevFrameF);
+ quat_prev[3] = evaluate_fcurve(fcu_z, prevFrameF);
- /* calculate the delta transform from the previous to the current */
- /* TODO: investigate ways to favor one transform more? */
- sub_qt_qtqt(quat_diff, quat_curr, quat_prev);
+ quat_next[0] = evaluate_fcurve(fcu_w, nextFrameF);
+ quat_next[1] = evaluate_fcurve(fcu_x, nextFrameF);
+ quat_next[2] = evaluate_fcurve(fcu_y, nextFrameF);
+ quat_next[3] = evaluate_fcurve(fcu_z, nextFrameF);
- /* increase the original by the delta transform, by an amount determined by percentage */
- add_qt_qtqt(quat_final, quat_curr, quat_diff, pso->percentage);
+ normalize_qt(quat_prev);
+ normalize_qt(quat_next);
- normalize_qt(quat_final);
+ interp_qt_qtqt(quat_final, quat_prev, quat_next, pso->percentage);
}
else {
- BLI_assert(pso->mode == POSESLIDE_RELAX);
- float quat_interp[4], quat_final_prev[4];
- /* TODO: maybe a sensitivity ctrl on top of this is needed */
- int iters = (int)ceil(10.0f * pso->percentage);
+ /* POSESLIDE_PUSH and POSESLIDE_RELAX. */
+ float quat_breakdown[4];
+ float quat_curr[4];
- copy_qt_qt(quat_final, quat_curr);
+ copy_qt_qt(quat_curr, pchan->quat);
- /* perform this blending several times until a satisfactory result is reached */
- while (iters-- > 0) {
- /* calculate the interpolation between the endpoints */
- interp_qt_qtqt(quat_interp,
- quat_prev,
- quat_next,
- (cframe - pso->prevFrame) / (pso->nextFrame - pso->prevFrame));
+ quat_breakdown[0] = evaluate_fcurve(fcu_w, cframe);
+ quat_breakdown[1] = evaluate_fcurve(fcu_x, cframe);
+ quat_breakdown[2] = evaluate_fcurve(fcu_y, cframe);
+ quat_breakdown[3] = evaluate_fcurve(fcu_z, cframe);
- normalize_qt_qt(quat_final_prev, quat_final);
+ normalize_qt(quat_breakdown);
+ normalize_qt(quat_curr);
- /* tricky interpolations - blending between original and new */
- interp_qt_qtqt(quat_final, quat_final_prev, quat_interp, 1.0f / 6.0f);
+ if (pso->mode == POSESLIDE_PUSH) {
+ interp_qt_qtqt(quat_final, quat_breakdown, quat_curr, 1.0f + pso->percentage);
+ }
+ else {
+ BLI_assert(pso->mode == POSESLIDE_RELAX);
+ interp_qt_qtqt(quat_final, quat_curr, quat_breakdown, pso->percentage);
}
}
/* Apply final to the pose bone, keeping compatible for similar keyframe positions. */
- quat_to_compatible_quat(pchan->quat, quat_final, quat_curr_orig);
+ quat_to_compatible_quat(pchan->quat, quat_final, pchan->quat);
}
/* free the path now */
@@ -904,7 +889,7 @@ static void pose_slide_draw_status(tPoseSlideOp *pso)
limits_str);
}
- ED_area_status_text(pso->sa, status_str);
+ ED_area_status_text(pso->area, status_str);
}
/* common code for invoke() methods */
@@ -1071,7 +1056,7 @@ static int pose_slide_modal(bContext *C, wmOperator *op, const wmEvent *event)
case EVT_PADENTER: {
if (event->val == KM_PRESS) {
/* return to normal cursor and header status */
- ED_area_status_text(pso->sa, NULL);
+ ED_area_status_text(pso->area, NULL);
WM_cursor_modal_restore(win);
/* insert keyframes as required... */
@@ -1088,7 +1073,7 @@ static int pose_slide_modal(bContext *C, wmOperator *op, const wmEvent *event)
case RIGHTMOUSE: {
if (event->val == KM_PRESS) {
/* return to normal cursor and header status */
- ED_area_status_text(pso->sa, NULL);
+ ED_area_status_text(pso->area, NULL);
WM_cursor_modal_restore(win);
/* reset transforms back to original state */
@@ -1254,51 +1239,60 @@ static int pose_slide_exec_common(bContext *C, wmOperator *op, tPoseSlideOp *pso
return OPERATOR_FINISHED;
}
-/* common code for defining RNA properties */
-/* TODO: Skip save on these? */
+/**
+ * Common code for defining RNA properties.
+ */
static void pose_slide_opdef_properties(wmOperatorType *ot)
{
- RNA_def_float_percentage(ot->srna,
- "percentage",
- 0.5f,
- 0.0f,
- 1.0f,
- "Percentage",
- "Weighting factor for which keyframe is favored more",
- 0.0,
- 1.0);
-
- RNA_def_int(ot->srna,
- "prev_frame",
- 0,
- MINAFRAME,
- MAXFRAME,
- "Previous Keyframe",
- "Frame number of keyframe immediately before the current frame",
- 0,
- 50);
- RNA_def_int(ot->srna,
- "next_frame",
- 0,
- MINAFRAME,
- MAXFRAME,
- "Next Keyframe",
- "Frame number of keyframe immediately after the current frame",
- 0,
- 50);
-
- RNA_def_enum(ot->srna,
- "channels",
- prop_channels_types,
- PS_TFM_ALL,
- "Channels",
- "Set of properties that are affected");
- RNA_def_enum(ot->srna,
- "axis_lock",
- prop_axis_lock_types,
- 0,
- "Axis Lock",
- "Transform axis to restrict effects to");
+ PropertyRNA *prop;
+
+ prop = RNA_def_float_percentage(ot->srna,
+ "percentage",
+ 0.5f,
+ 0.0f,
+ 1.0f,
+ "Percentage",
+ "Weighting factor for which keyframe is favored more",
+ 0.0,
+ 1.0);
+ RNA_def_property_flag(prop, PROP_SKIP_SAVE);
+
+ prop = RNA_def_int(ot->srna,
+ "prev_frame",
+ 0,
+ MINAFRAME,
+ MAXFRAME,
+ "Previous Keyframe",
+ "Frame number of keyframe immediately before the current frame",
+ 0,
+ 50);
+ RNA_def_property_flag(prop, PROP_SKIP_SAVE);
+
+ prop = RNA_def_int(ot->srna,
+ "next_frame",
+ 0,
+ MINAFRAME,
+ MAXFRAME,
+ "Next Keyframe",
+ "Frame number of keyframe immediately after the current frame",
+ 0,
+ 50);
+ RNA_def_property_flag(prop, PROP_SKIP_SAVE);
+
+ prop = RNA_def_enum(ot->srna,
+ "channels",
+ prop_channels_types,
+ PS_TFM_ALL,
+ "Channels",
+ "Set of properties that are affected");
+ RNA_def_property_flag(prop, PROP_SKIP_SAVE);
+ prop = RNA_def_enum(ot->srna,
+ "axis_lock",
+ prop_axis_lock_types,
+ 0,
+ "Axis Lock",
+ "Transform axis to restrict effects to");
+ RNA_def_property_flag(prop, PROP_SKIP_SAVE);
}
/* ------------------------------------ */
diff --git a/source/blender/editors/armature/pose_transform.c b/source/blender/editors/armature/pose_transform.c
index fe79894a351..1d2bf152777 100644
--- a/source/blender/editors/armature/pose_transform.c
+++ b/source/blender/editors/armature/pose_transform.c
@@ -207,12 +207,12 @@ typedef struct ApplyArmature_ParentState {
} ApplyArmature_ParentState;
/* Recursive walk for Apply To Selected mode; pstate NULL unless child of an applied bone. */
-static void applyarmature_process_selected_rec(bArmature *arm,
- bPose *pose,
- bPose *pose_eval,
- Bone *bone,
- ListBase *selected,
- ApplyArmature_ParentState *pstate)
+static void applyarmature_process_selected_recursive(bArmature *arm,
+ bPose *pose,
+ bPose *pose_eval,
+ Bone *bone,
+ ListBase *selected,
+ ApplyArmature_ParentState *pstate)
{
bPoseChannel *pchan = BKE_pose_channel_find_name(pose, bone->name);
const bPoseChannel *pchan_eval = BKE_pose_channel_find_name(pose_eval, bone->name);
@@ -333,8 +333,8 @@ static void applyarmature_process_selected_rec(bArmature *arm,
pstate = &new_pstate;
}
- for (Bone *child = bone->childbase.first; child; child = child->next) {
- applyarmature_process_selected_rec(arm, pose, pose_eval, child, selected, pstate);
+ LISTBASE_FOREACH (Bone *, child, &bone->childbase) {
+ applyarmature_process_selected_recursive(arm, pose, pose_eval, child, selected, pstate);
}
}
@@ -389,8 +389,9 @@ static int apply_armature_pose2bones_exec(bContext *C, wmOperator *op)
if (use_selected) {
/* The selected only mode requires a recursive walk to handle parent-child relations. */
- for (Bone *bone = arm->bonebase.first; bone; bone = bone->next) {
- applyarmature_process_selected_rec(arm, pose, ob_eval->pose, bone, &selected_bones, NULL);
+ LISTBASE_FOREACH (Bone *, bone, &arm->bonebase) {
+ applyarmature_process_selected_recursive(
+ arm, pose, ob_eval->pose, bone, &selected_bones, NULL);
}
BLI_freelistN(&selected_bones);
@@ -1239,7 +1240,7 @@ static int pose_clear_user_transforms_exec(bContext *C, wmOperator *op)
workob.adt = ob->adt;
workob.pose = dummyPose;
- BKE_animsys_evaluate_animdata(scene, &workob.id, workob.adt, cframe, ADT_RECALC_ANIM, false);
+ BKE_animsys_evaluate_animdata(&workob.id, workob.adt, cframe, ADT_RECALC_ANIM, false);
/* copy back values, but on selected bones only */
for (pchan = dummyPose->chanbase.first; pchan; pchan = pchan->next) {
diff --git a/source/blender/editors/armature/pose_utils.c b/source/blender/editors/armature/pose_utils.c
index efb568178d9..e2038bdd2a3 100644
--- a/source/blender/editors/armature/pose_utils.c
+++ b/source/blender/editors/armature/pose_utils.c
@@ -32,7 +32,7 @@
#include "DNA_scene_types.h"
#include "BKE_action.h"
-#include "BKE_animsys.h"
+#include "BKE_anim_data.h"
#include "BKE_armature.h"
#include "BKE_idprop.h"
#include "BKE_layer.h"
diff --git a/source/blender/editors/curve/CMakeLists.txt b/source/blender/editors/curve/CMakeLists.txt
index 8c9309055c8..ff80c47baa8 100644
--- a/source/blender/editors/curve/CMakeLists.txt
+++ b/source/blender/editors/curve/CMakeLists.txt
@@ -40,6 +40,7 @@ set(SRC
editcurve.c
editcurve_add.c
editcurve_paint.c
+ editcurve_query.c
editcurve_select.c
editcurve_undo.c
editfont.c
diff --git a/source/blender/editors/curve/curve_intern.h b/source/blender/editors/curve/curve_intern.h
index 201ba2560dc..7d0a2e5edbc 100644
--- a/source/blender/editors/curve/curve_intern.h
+++ b/source/blender/editors/curve/curve_intern.h
@@ -142,14 +142,6 @@ void CURVE_OT_match_texture_space(struct wmOperatorType *ot);
struct GHash *ED_curve_keyindex_hash_duplicate(struct GHash *keyindex);
void ED_curve_keyindex_update_nurb(struct EditNurb *editnurb, struct Nurb *nu, struct Nurb *newnu);
-bool ED_curve_pick_vert(struct ViewContext *vc,
- short sel,
- struct Nurb **r_nurb,
- struct BezTriple **r_bezt,
- struct BPoint **r_bp,
- short *r_handle,
- struct Base **r_base);
-
/* helper functions */
void ed_editnurb_translate_flag(struct ListBase *editnurb, short flag, const float vec[3]);
bool ed_editnurb_extrude_flag(struct EditNurb *editnurb, const short flag);
@@ -189,6 +181,17 @@ void SURFACE_OT_primitive_nurbs_surface_cylinder_add(struct wmOperatorType *ot);
void SURFACE_OT_primitive_nurbs_surface_sphere_add(struct wmOperatorType *ot);
void SURFACE_OT_primitive_nurbs_surface_torus_add(struct wmOperatorType *ot);
+/* editcurve_query.c */
+bool ED_curve_pick_vert(struct ViewContext *vc,
+ short sel,
+ struct Nurb **r_nurb,
+ struct BezTriple **r_bezt,
+ struct BPoint **r_bp,
+ short *r_handle,
+ struct Base **r_base);
+void ED_curve_nurb_vert_selected_find(
+ Curve *cu, View3D *v3d, Nurb **r_nu, BezTriple **r_bezt, BPoint **r_bp);
+
/* editcurve_paint.c */
void CURVE_OT_draw(struct wmOperatorType *ot);
diff --git a/source/blender/editors/curve/editcurve.c b/source/blender/editors/curve/editcurve.c
index 2911611c516..4e1c07af001 100644
--- a/source/blender/editors/curve/editcurve.c
+++ b/source/blender/editors/curve/editcurve.c
@@ -36,7 +36,7 @@
#include "BLT_translation.h"
#include "BKE_action.h"
-#include "BKE_animsys.h"
+#include "BKE_anim_data.h"
#include "BKE_context.h"
#include "BKE_curve.h"
#include "BKE_displist.h"
@@ -58,6 +58,7 @@
#include "ED_curve.h"
#include "ED_object.h"
+#include "ED_outliner.h"
#include "ED_screen.h"
#include "ED_transform.h"
#include "ED_transform_snap_object_context.h"
@@ -81,6 +82,10 @@ static void adduplicateflagNurb(
static bool curve_delete_segments(Object *obedit, View3D *v3d, const bool split);
static bool curve_delete_vertices(Object *obedit, View3D *v3d);
+/* -------------------------------------------------------------------- */
+/** \name Utility Functions
+ * \{ */
+
ListBase *object_editcurve_get(Object *ob)
{
if (ob && ELEM(ob->type, OB_CURVE, OB_SURF)) {
@@ -90,7 +95,11 @@ ListBase *object_editcurve_get(Object *ob)
return NULL;
}
-/* ******************* PRINTS ********************* */
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Debug Printing
+ * \{ */
#if 0
void printknots(Object *obedit)
@@ -118,7 +127,11 @@ void printknots(Object *obedit)
}
#endif
-/* ********************* Shape keys *************** */
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Shape keys
+ * \{ */
static CVKeyIndex *init_cvKeyIndex(
void *cv, int key_index, int nu_index, int pt_index, int vertex_index)
@@ -897,7 +910,11 @@ static void calc_shapeKeys(Object *obedit, ListBase *newnurbs)
}
}
-/* ********************* Amimation data *************** */
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Animation Data
+ * \{ */
static bool curve_is_animated(Curve *cu)
{
@@ -919,13 +936,13 @@ static void fcurve_path_rename(AnimData *adt,
nextfcu = fcu->next;
if (STREQLEN(fcu->rna_path, orig_rna_path, len)) {
char *spath, *suffix = fcu->rna_path + len;
- nfcu = copy_fcurve(fcu);
+ nfcu = BKE_fcurve_copy(fcu);
spath = nfcu->rna_path;
nfcu->rna_path = BLI_sprintfN("%s%s", rna_path, suffix);
- /* copy_fcurve() sets nfcu->grp to NULL. To maintain the groups, we need to keep the pointer.
- * As a result, the group's 'channels' pointers will be wrong, which is fixed by calling
- * `action_groups_reconstruct(action)` later, after all fcurves have been renamed. */
+ /* BKE_fcurve_copy() sets nfcu->grp to NULL. To maintain the groups, we need to keep the
+ * pointer. As a result, the group's 'channels' pointers will be wrong, which is fixed by
+ * calling `action_groups_reconstruct(action)` later, after all fcurves have been renamed. */
nfcu->grp = fcu->grp;
BLI_addtail(curves, nfcu);
@@ -939,7 +956,7 @@ static void fcurve_path_rename(AnimData *adt,
BLI_remlink(&adt->drivers, fcu);
}
- free_fcurve(fcu);
+ BKE_fcurve_free(fcu);
MEM_freeN(spath);
}
@@ -955,7 +972,7 @@ static void fcurve_remove(AnimData *adt, ListBase *orig_curves, FCurve *fcu)
action_groups_remove_channel(adt->action, fcu);
}
- free_fcurve(fcu);
+ BKE_fcurve_free(fcu);
}
static void curve_rename_fcurves(Curve *cu, ListBase *orig_curves)
@@ -1114,7 +1131,11 @@ int ED_curve_updateAnimPaths(Main *bmain, Curve *cu)
return 1;
}
-/* ********************* LOAD and MAKE *************** */
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Edit Mode Conversion (Make & Load)
+ * \{ */
static int *initialize_index_map(Object *obedit, int *r_old_totvert)
{
@@ -1354,7 +1375,11 @@ void ED_curve_editnurb_free(Object *obedit)
BKE_curve_editNurb_free(cu);
}
-/******************** separate operator ***********************/
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Separate Operator
+ * \{ */
static int separate_exec(bContext *C, wmOperator *op)
{
@@ -1476,6 +1501,8 @@ static int separate_exec(bContext *C, wmOperator *op)
return OPERATOR_CANCELLED;
}
+ ED_outliner_select_sync_from_object_tag(C);
+
return OPERATOR_FINISHED;
}
@@ -1495,7 +1522,11 @@ void CURVE_OT_separate(wmOperatorType *ot)
ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
}
-/******************** split operator ***********************/
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Split Operator
+ * \{ */
static int curve_split_exec(bContext *C, wmOperator *op)
{
@@ -1563,7 +1594,11 @@ void CURVE_OT_split(wmOperatorType *ot)
ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
}
-/* ******************* FLAGS ********************* */
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Flag Utility Functions
+ * \{ */
static bool isNurbselUV(const Nurb *nu, int flag, int *r_u, int *r_v)
{
@@ -2532,7 +2567,11 @@ static void adduplicateflagNurb(
}
}
-/**************** switch direction operator ***************/
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Switch Direction Operator
+ * \{ */
static int switch_direction_exec(bContext *C, wmOperator *UNUSED(op))
{
@@ -2591,7 +2630,11 @@ void CURVE_OT_switch_direction(wmOperatorType *ot)
ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
}
-/****************** set weight operator *******************/
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Set Weight Operator
+ * \{ */
static int set_goal_weight_exec(bContext *C, wmOperator *op)
{
@@ -2654,7 +2697,11 @@ void CURVE_OT_spline_weight_set(wmOperatorType *ot)
RNA_def_float_factor(ot->srna, "weight", 1.0f, 0.0f, 1.0f, "Weight", "", 0.0f, 1.0f);
}
-/******************* set radius operator ******************/
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Set Radius Operator
+ * \{ */
static int set_radius_exec(bContext *C, wmOperator *op)
{
@@ -2718,7 +2765,11 @@ void CURVE_OT_radius_set(wmOperatorType *ot)
ot->srna, "radius", 1.0f, 0.0f, OBJECT_ADD_SIZE_MAXF, "Radius", "", 0.0001f, 10.0f);
}
-/********************* smooth operator ********************/
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Smooth Vertices Operator
+ * \{ */
static void smooth_single_bezt(BezTriple *bezt,
const BezTriple *bezt_orig_prev,
@@ -2875,12 +2926,15 @@ void CURVE_OT_smooth(wmOperatorType *ot)
ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
}
+/** \} */
+
/* -------------------------------------------------------------------- */
-/* Smooth radius/weight/tilt
+/** \name Smooth Operator (Radius/Weight/Tilt) Utilities
*
- * TODO: make smoothing distance based
- * TODO: support cyclic curves
- */
+ * To do:
+ * - Make smoothing distance based.
+ * - Support cyclic curves.
+ * \{ */
static void curve_smooth_value(ListBase *editnurb, const int bezt_offsetof, const int bp_offset)
{
@@ -3059,6 +3113,12 @@ static void curve_smooth_value(ListBase *editnurb, const int bezt_offsetof, cons
}
}
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Smooth Weight Operator
+ * \{ */
+
static int curve_smooth_weight_exec(bContext *C, wmOperator *UNUSED(op))
{
ViewLayer *view_layer = CTX_data_view_layer(C);
@@ -3096,6 +3156,12 @@ void CURVE_OT_smooth_weight(wmOperatorType *ot)
ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
}
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Smooth Radius Operator
+ * \{ */
+
static int curve_smooth_radius_exec(bContext *C, wmOperator *UNUSED(op))
{
ViewLayer *view_layer = CTX_data_view_layer(C);
@@ -3133,6 +3199,12 @@ void CURVE_OT_smooth_radius(wmOperatorType *ot)
ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
}
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Smooth Tilt Operator
+ * \{ */
+
static int curve_smooth_tilt_exec(bContext *C, wmOperator *UNUSED(op))
{
ViewLayer *view_layer = CTX_data_view_layer(C);
@@ -3170,7 +3242,11 @@ void CURVE_OT_smooth_tilt(wmOperatorType *ot)
ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
}
-/********************** hide operator *********************/
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Hide Operator
+ * \{ */
static int hide_exec(bContext *C, wmOperator *op)
{
@@ -3269,7 +3345,11 @@ void CURVE_OT_hide(wmOperatorType *ot)
RNA_def_boolean(ot->srna, "unselected", 0, "Unselected", "Hide unselected rather than selected");
}
-/********************** reveal operator *********************/
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Reveal Operator
+ * \{ */
static int reveal_exec(bContext *C, wmOperator *op)
{
@@ -3345,7 +3425,11 @@ void CURVE_OT_reveal(wmOperatorType *ot)
RNA_def_boolean(ot->srna, "select", true, "Select", "");
}
-/********************** subdivide operator *********************/
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Subdivide Operator
+ * \{ */
/**
* Divide the line segments associated with the currently selected
@@ -3508,6 +3592,7 @@ static void subdividenurb(Object *obedit, View3D *v3d, int number_cuts)
memcpy(bpn, nextbp, sizeof(BPoint));
interp_v4_v4v4(bpn->vec, bp->vec, nextbp->vec, factor);
+ bpn->radius = interpf(bp->radius, nextbp->radius, factor);
bpn++;
}
}
@@ -3800,179 +3885,11 @@ void CURVE_OT_subdivide(wmOperatorType *ot)
RNA_def_property_flag(prop, PROP_SKIP_SAVE);
}
-/******************** find nearest ************************/
+/** \} */
-static void ED_curve_pick_vert__doClosest(
- void *userData, Nurb *nu, BPoint *bp, BezTriple *bezt, int beztindex, const float screen_co[2])
-{
- struct {
- BPoint *bp;
- BezTriple *bezt;
- Nurb *nurb;
- float dist;
- int hpoint, select;
- float mval_fl[2];
- bool is_changed;
- } *data = userData;
-
- short flag;
- float dist_test;
-
- if (bp) {
- flag = bp->f1;
- }
- else {
- if (beztindex == 0) {
- flag = bezt->f1;
- }
- else if (beztindex == 1) {
- flag = bezt->f2;
- }
- else {
- flag = bezt->f3;
- }
- }
-
- dist_test = len_manhattan_v2v2(data->mval_fl, screen_co);
- if ((flag & SELECT) == data->select) {
- dist_test += 5.0f;
- }
- if (bezt && beztindex == 1) {
- dist_test += 3.0f; /* middle points get a small disadvantage */
- }
-
- if (dist_test < data->dist) {
- data->dist = dist_test;
-
- data->bp = bp;
- data->bezt = bezt;
- data->nurb = nu;
- data->hpoint = bezt ? beztindex : 0;
- data->is_changed = true;
- }
-}
-
-bool ED_curve_pick_vert(ViewContext *vc,
- short sel,
- Nurb **r_nurb,
- BezTriple **r_bezt,
- BPoint **r_bp,
- short *r_handle,
- Base **r_base)
-{
- /* (sel == 1): selected gets a disadvantage */
- /* in nurb and bezt or bp the nearest is written */
- /* return 0 1 2: handlepunt */
- struct {
- BPoint *bp;
- BezTriple *bezt;
- Nurb *nurb;
- float dist;
- int hpoint, select;
- float mval_fl[2];
- bool is_changed;
- } data = {NULL};
-
- data.dist = ED_view3d_select_dist_px();
- data.hpoint = 0;
- data.select = sel;
- data.mval_fl[0] = vc->mval[0];
- data.mval_fl[1] = vc->mval[1];
-
- uint bases_len;
- Base **bases = BKE_view_layer_array_from_bases_in_edit_mode_unique_data(
- vc->view_layer, vc->v3d, &bases_len);
- for (uint base_index = 0; base_index < bases_len; base_index++) {
- Base *base = bases[base_index];
- data.is_changed = false;
-
- ED_view3d_viewcontext_init_object(vc, base->object);
- ED_view3d_init_mats_rv3d(vc->obedit, vc->rv3d);
- nurbs_foreachScreenVert(vc, ED_curve_pick_vert__doClosest, &data, V3D_PROJ_TEST_CLIP_DEFAULT);
-
- if (r_base && data.is_changed) {
- *r_base = base;
- }
- }
- MEM_freeN(bases);
-
- *r_nurb = data.nurb;
- *r_bezt = data.bezt;
- *r_bp = data.bp;
-
- if (r_handle) {
- *r_handle = data.hpoint;
- }
-
- return (data.bezt || data.bp);
-}
-
-static void findselectedNurbvert(
- Curve *cu, View3D *v3d, Nurb **r_nu, BezTriple **r_bezt, BPoint **r_bp)
-{
- /* in nu and (bezt or bp) selected are written if there's 1 sel. */
- /* if more points selected in 1 spline: return only nu, bezt and bp are 0 */
- ListBase *editnurb = &cu->editnurb->nurbs;
- Nurb *nu1;
- BezTriple *bezt1;
- BPoint *bp1;
- int a;
-
- *r_nu = NULL;
- *r_bezt = NULL;
- *r_bp = NULL;
-
- for (nu1 = editnurb->first; nu1; nu1 = nu1->next) {
- if (nu1->type == CU_BEZIER) {
- bezt1 = nu1->bezt;
- a = nu1->pntsu;
- while (a--) {
- if (BEZT_ISSEL_ANY_HIDDENHANDLES(v3d, bezt1)) {
- if (*r_nu != NULL && *r_nu != nu1) {
- *r_nu = NULL;
- *r_bp = NULL;
- *r_bezt = NULL;
- return;
- }
- else if (*r_bezt || *r_bp) {
- *r_bp = NULL;
- *r_bezt = NULL;
- }
- else {
- *r_bezt = bezt1;
- *r_nu = nu1;
- }
- }
- bezt1++;
- }
- }
- else {
- bp1 = nu1->bp;
- a = nu1->pntsu * nu1->pntsv;
- while (a--) {
- if (bp1->f1 & SELECT) {
- if (*r_nu != NULL && *r_nu != nu1) {
- *r_bp = NULL;
- *r_bezt = NULL;
- *r_nu = NULL;
- return;
- }
- else if (*r_bezt || *r_bp) {
- *r_bp = NULL;
- *r_bezt = NULL;
- }
- else {
- *r_bp = bp1;
- *r_nu = nu1;
- }
- }
- bp1++;
- }
- }
- }
-}
-
-/***************** set spline type operator *******************/
+/* -------------------------------------------------------------------- */
+/** \name Set Spline Type Operator
+ * \{ */
static int set_spline_type_exec(bContext *C, wmOperator *op)
{
@@ -4069,7 +3986,11 @@ void CURVE_OT_spline_type_set(wmOperatorType *ot)
"Use handles when converting bezier curves into polygons");
}
-/***************** set handle type operator *******************/
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Set Handle Type Operator
+ * \{ */
static int set_handle_type_exec(bContext *C, wmOperator *op)
{
@@ -4127,7 +4048,11 @@ void CURVE_OT_handle_type_set(wmOperatorType *ot)
ot->prop = RNA_def_enum(ot->srna, "type", editcurve_handle_type_items, 1, "Type", "Spline type");
}
-/***************** recalculate handles operator **********************/
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Recalculate Handles Operator
+ * \{ */
static int curve_normals_make_consistent_exec(bContext *C, wmOperator *op)
{
@@ -4175,9 +4100,13 @@ void CURVE_OT_normals_make_consistent(wmOperatorType *ot)
RNA_def_boolean(ot->srna, "calc_length", false, "Length", "Recalculate handle length");
}
-/***************** make segment operator **********************/
+/** \} */
-/* ******************** SKINNING LOFTING!!! ******************** */
+/* -------------------------------------------------------------------- */
+/** \name Make Segment Operator
+ *
+ * Also handles skinning & lofting.
+ * \{ */
static void switchdirection_knots(float *base, int tot)
{
@@ -4271,10 +4200,7 @@ typedef struct NurbSort {
float vec[3];
} NurbSort;
-static ListBase nsortbase = {NULL, NULL};
-/* static NurbSort *nusmain; */ /* this var seems to go unused... at least in this file */
-
-static void make_selection_list_nurb(View3D *v3d, ListBase *editnurb)
+static void make_selection_list_nurb(View3D *v3d, ListBase *editnurb, ListBase *nsortbase)
{
ListBase nbase = {NULL, NULL};
NurbSort *nus, *nustest, *headdo, *taildo;
@@ -4303,7 +4229,7 @@ static void make_selection_list_nurb(View3D *v3d, ListBase *editnurb)
/* just add the first one */
nus = nbase.first;
BLI_remlink(&nbase, nus);
- BLI_addtail(&nsortbase, nus);
+ BLI_addtail(nsortbase, nus);
/* now add, either at head or tail, the closest one */
while (nbase.first) {
@@ -4313,13 +4239,13 @@ static void make_selection_list_nurb(View3D *v3d, ListBase *editnurb)
nustest = nbase.first;
while (nustest) {
- dist = len_v3v3(nustest->vec, ((NurbSort *)nsortbase.first)->vec);
+ dist = len_v3v3(nustest->vec, ((NurbSort *)nsortbase->first)->vec);
if (dist < headdist) {
headdist = dist;
headdo = nustest;
}
- dist = len_v3v3(nustest->vec, ((NurbSort *)nsortbase.last)->vec);
+ dist = len_v3v3(nustest->vec, ((NurbSort *)nsortbase->last)->vec);
if (dist < taildist) {
taildist = dist;
@@ -4330,11 +4256,11 @@ static void make_selection_list_nurb(View3D *v3d, ListBase *editnurb)
if (headdist < taildist) {
BLI_remlink(&nbase, headdo);
- BLI_addhead(&nsortbase, headdo);
+ BLI_addhead(nsortbase, headdo);
}
else {
BLI_remlink(&nbase, taildo);
- BLI_addtail(&nsortbase, taildo);
+ BLI_addtail(nsortbase, taildo);
}
}
}
@@ -4511,8 +4437,9 @@ static int merge_nurb(View3D *v3d, Object *obedit)
ListBase *editnurb = object_editcurve_get(obedit);
NurbSort *nus1, *nus2;
bool ok = true;
+ ListBase nsortbase = {NULL, NULL};
- make_selection_list_nurb(v3d, editnurb);
+ make_selection_list_nurb(v3d, editnurb, &nsortbase);
if (nsortbase.first == nsortbase.last) {
BLI_freelistN(&nsortbase);
@@ -4877,7 +4804,11 @@ void CURVE_OT_make_segment(wmOperatorType *ot)
ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
}
-/***************** pick select from 3d view **********************/
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Pick Select from 3D View
+ * \{ */
bool ED_curve_editnurb_select_pick(
bContext *C, const int mval[2], bool extend, bool deselect, bool toggle)
@@ -4992,7 +4923,7 @@ bool ED_curve_editnurb_select_pick(
}
}
else {
- BKE_nurbList_flag_set(editnurb, 0);
+ BKE_nurbList_flag_set(editnurb, SELECT, false);
if (bezt) {
@@ -5033,7 +4964,11 @@ bool ED_curve_editnurb_select_pick(
return false;
}
-/******************** spin operator ***********************/
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Spin Operator
+ * \{ */
/* 'cent' is in object space and 'dvec' in worldspace.
*/
@@ -5213,13 +5148,14 @@ void CURVE_OT_spin(wmOperatorType *ot)
ot->srna, "axis", 3, NULL, -1.0f, 1.0f, "Axis", "Axis in global view space", -1.0f, 1.0f);
}
-/***************** extrude vertex operator **********************/
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Extrude Vertex Operator
+ * \{ */
static bool ed_editcurve_extrude(Curve *cu, EditNurb *editnurb, View3D *v3d)
{
- Nurb *nu = NULL;
- Nurb *nu_last = NULL;
-
bool changed = false;
Nurb *cu_actnu;
@@ -5234,216 +5170,238 @@ static bool ed_editcurve_extrude(Curve *cu, EditNurb *editnurb, View3D *v3d)
}
BKE_curve_nurb_vert_active_get(cu, &cu_actnu, &cu_actvert.p);
- BKE_curve_nurb_vert_active_set(cu, NULL, NULL);
-
- /* first pass (endpoints) */
- for (nu = editnurb->nurbs.first; nu; nu = nu->next) {
-
- if ((nu->flagu & CU_NURB_CYCLIC) && (nu->pntsu > 1)) {
- continue;
- }
+ int act_offset = 0;
+ LISTBASE_FOREACH (Nurb *, nu, &editnurb->nurbs) {
+ BLI_assert(nu->pntsu > 0);
+ int i;
+ int pnt_len = nu->pntsu;
+ int new_points = 0;
+ int offset = 0;
+ bool is_prev_selected = false;
+ bool duplic_first = false;
+ bool duplic_last = false;
if (nu->type == CU_BEZIER) {
-
- /* Check to see if the first bezier point is selected */
- if (nu->pntsu > 0 && nu->bezt != NULL) {
- BezTriple *nu_bezt_old = nu->bezt;
- BezTriple *bezt = nu->bezt;
-
- if (BEZT_ISSEL_ANY_HIDDENHANDLES(v3d, bezt)) {
- BezTriple *bezt_new;
- BEZT_DESEL_ALL(bezt);
-
- bezt_new = MEM_mallocN((nu->pntsu + 1) * sizeof(BezTriple), __func__);
- ED_curve_beztcpy(editnurb, bezt_new + 1, bezt, nu->pntsu);
- *bezt_new = *bezt;
-
- MEM_freeN(nu->bezt);
- nu->bezt = bezt_new;
-
- nu->pntsu += 1;
-
- if (ARRAY_HAS_ITEM(cu_actvert.bezt, nu_bezt_old, nu->pntsu - 1)) {
- cu_actvert.bezt = (cu_actvert.bezt == bezt) ?
- bezt_new :
- &nu->bezt[(cu_actvert.bezt - nu_bezt_old) + 1];
- BKE_curve_nurb_vert_active_set(cu, nu, cu_actvert.bezt);
- }
-
- BEZT_SEL_ALL(bezt_new);
- changed = true;
- }
+ BezTriple *bezt, *bezt_prev = NULL;
+ BezTriple bezt_stack;
+ bool is_cyclic = false;
+ if (pnt_len == 1) {
+ /* Single point extrusion.
+ * Keep `is_prev_selected` false to force extrude. */
+ bezt_prev = &nu->bezt[0];
+ }
+ else if (nu->flagu & CU_NURB_CYCLIC) {
+ is_cyclic = true;
+ bezt_prev = &nu->bezt[pnt_len - 1];
+ is_prev_selected = BEZT_ISSEL_ANY_HIDDENHANDLES(v3d, bezt_prev);
}
+ else {
+ duplic_first = BEZT_ISSEL_ANY_HIDDENHANDLES(v3d, &nu->bezt[0]) &&
+ BEZT_ISSEL_ANY_HIDDENHANDLES(v3d, &nu->bezt[1]);
- /* Check to see if the last bezier point is selected */
- if (nu->pntsu > 1) {
- BezTriple *nu_bezt_old = nu->bezt;
- BezTriple *bezt = &nu->bezt[nu->pntsu - 1];
-
- if (BEZT_ISSEL_ANY_HIDDENHANDLES(v3d, bezt)) {
- BezTriple *bezt_new;
- BEZT_DESEL_ALL(bezt);
-
- bezt_new = MEM_mallocN((nu->pntsu + 1) * sizeof(BezTriple), __func__);
- ED_curve_beztcpy(editnurb, bezt_new, nu->bezt, nu->pntsu);
- bezt_new[nu->pntsu] = *bezt;
-
- MEM_freeN(nu->bezt);
- nu->bezt = bezt_new;
-
- bezt_new += nu->pntsu;
- nu->pntsu += 1;
-
- if (ARRAY_HAS_ITEM(cu_actvert.bezt, nu_bezt_old, nu->pntsu - 1)) {
- cu_actvert.bezt = (cu_actvert.bezt == bezt) ? bezt_new :
- &nu->bezt[cu_actvert.bezt - nu_bezt_old];
- BKE_curve_nurb_vert_active_set(cu, nu, cu_actvert.bezt);
- }
+ duplic_last = BEZT_ISSEL_ANY_HIDDENHANDLES(v3d, &nu->bezt[pnt_len - 2]) &&
+ BEZT_ISSEL_ANY_HIDDENHANDLES(v3d, &nu->bezt[pnt_len - 1]);
- BEZT_SEL_ALL(bezt_new);
- changed = true;
+ if (duplic_first) {
+ bezt_stack = nu->bezt[0];
+ BEZT_DESEL_ALL(&bezt_stack);
+ bezt_prev = &bezt_stack;
+ }
+ if (duplic_last) {
+ new_points++;
}
}
- }
- else {
-
- /* Check to see if the first bpoint is selected */
- if (nu->pntsu > 0 && nu->bp != NULL) {
- BPoint *nu_bp_old = nu->bp;
- BPoint *bp = nu->bp;
-
- if (bp->f1 & SELECT) {
- BPoint *bp_new;
- bp->f1 &= ~SELECT;
-
- bp_new = MEM_mallocN((nu->pntsu + 1) * sizeof(BPoint), __func__);
- ED_curve_bpcpy(editnurb, bp_new + 1, bp, nu->pntsu);
- *bp_new = *bp;
-
- MEM_freeN(nu->bp);
- nu->bp = bp_new;
-
- nu->pntsu += 1;
- BKE_nurb_knot_calc_u(nu);
-
- if (ARRAY_HAS_ITEM(cu_actvert.bp, nu_bp_old, nu->pntsu - 1)) {
- cu_actvert.bp = (cu_actvert.bp == bp) ? bp_new :
- &nu->bp[(cu_actvert.bp - nu_bp_old) + 1];
- BKE_curve_nurb_vert_active_set(cu, nu, cu_actvert.bp);
- }
-
- bp_new->f1 |= SELECT;
- changed = true;
+ i = pnt_len;
+ for (bezt = &nu->bezt[0]; i--; bezt++) {
+ bool is_selected = BEZT_ISSEL_ANY_HIDDENHANDLES(v3d, bezt);
+ if (bezt_prev && is_prev_selected != is_selected) {
+ new_points++;
}
+ if (bezt == cu_actvert.bezt) {
+ act_offset = new_points;
+ }
+ bezt_prev = bezt;
+ is_prev_selected = is_selected;
}
- /* Check to see if the last bpoint is selected */
- if (nu->pntsu > 1) {
- BPoint *nu_bp_old = nu->bp;
- BPoint *bp = &nu->bp[nu->pntsu - 1];
-
- if (bp->f1 & SELECT) {
- BPoint *bp_new;
- bp->f1 &= ~SELECT;
-
- bp_new = MEM_mallocN((nu->pntsu + 1) * sizeof(BPoint), __func__);
- ED_curve_bpcpy(editnurb, bp_new, nu->bp, nu->pntsu);
- bp_new[nu->pntsu] = *bp;
-
- MEM_freeN(nu->bp);
- nu->bp = bp_new;
+ if (new_points) {
+ if (pnt_len == 1) {
+ /* Single point extrusion.
+ * Set `is_prev_selected` as false to force extrude. */
+ BLI_assert(bezt_prev == &nu->bezt[0]);
+ is_prev_selected = false;
+ }
+ else if (is_cyclic) {
+ BLI_assert(bezt_prev == &nu->bezt[pnt_len - 1]);
+ BLI_assert(is_prev_selected == BEZT_ISSEL_ANY_HIDDENHANDLES(v3d, bezt_prev));
+ }
+ else if (duplic_first) {
+ bezt_prev = &bezt_stack;
+ is_prev_selected = false;
+ }
+ else {
+ bezt_prev = NULL;
+ }
+ BezTriple *bezt_src, *bezt_dst, *bezt_src_iter, *bezt_dst_iter;
+ const int new_len = pnt_len + new_points;
- bp_new += nu->pntsu;
- nu->pntsu += 1;
+ bezt_src = nu->bezt;
+ bezt_dst = MEM_mallocN(new_len * sizeof(BezTriple), __func__);
+ bezt_src_iter = &bezt_src[0];
+ bezt_dst_iter = &bezt_dst[0];
+ i = 0;
+ for (bezt = &nu->bezt[0]; i < pnt_len; i++, bezt++) {
+ bool is_selected = BEZT_ISSEL_ANY_HIDDENHANDLES(v3d, bezt);
+ /* While this gets de-selected, selecting here ensures newly created verts are selected.
+ * without this, the vertices are copied but only the handles are transformed.
+ * which seems buggy from a user perspective. */
+ if (is_selected) {
+ bezt->f2 |= SELECT;
+ }
+ if (bezt_prev && is_prev_selected != is_selected) {
+ int count = i - offset + 1;
+ if (is_prev_selected) {
+ ED_curve_beztcpy(editnurb, bezt_dst_iter, bezt_src_iter, count - 1);
+ ED_curve_beztcpy(editnurb, &bezt_dst_iter[count - 1], bezt_prev, 1);
+ }
+ else {
+ ED_curve_beztcpy(editnurb, bezt_dst_iter, bezt_src_iter, count);
+ }
+ ED_curve_beztcpy(editnurb, &bezt_dst_iter[count], bezt, 1);
+ BEZT_DESEL_ALL(&bezt_dst_iter[count - 1]);
- if (ARRAY_HAS_ITEM(cu_actvert.bp, nu_bp_old, nu->pntsu - 1)) {
- cu_actvert.bp = (cu_actvert.bp == bp) ? bp_new : &nu->bp[cu_actvert.bp - nu_bp_old];
- BKE_curve_nurb_vert_active_set(cu, nu, cu_actvert.bp);
+ bezt_dst_iter += count + 1;
+ bezt_src_iter += count;
+ offset = i + 1;
}
+ bezt_prev = bezt;
+ is_prev_selected = is_selected;
+ }
- BKE_nurb_knot_calc_u(nu);
-
- bp_new->f1 |= SELECT;
- changed = true;
+ int remain = pnt_len - offset;
+ if (remain) {
+ ED_curve_beztcpy(editnurb, bezt_dst_iter, bezt_src_iter, remain);
}
- }
- }
- }
- /* second pass (interior points) */
- nu_last = editnurb->nurbs.last;
- for (nu = editnurb->nurbs.first; (nu != nu_last->next); nu = nu->next) {
- int i, i_end;
+ if (duplic_last) {
+ ED_curve_beztcpy(editnurb, &bezt_dst[new_len - 1], &bezt_src[pnt_len - 1], 1);
+ BEZT_DESEL_ALL(&bezt_dst[new_len - 1]);
+ }
- if ((nu->flagu & CU_NURB_CYCLIC) && (nu->pntsu > 1)) {
- /* all points are interior */
- i = 0;
- i_end = nu->pntsu;
+ MEM_freeN(nu->bezt);
+ nu->bezt = bezt_dst;
+ nu->pntsu += new_points;
+ changed = true;
+ }
}
else {
- /* skip endpoints */
- i = 1;
- i_end = nu->pntsu - 1;
- }
+ BPoint *bp, *bp_prev = NULL;
+ BPoint bp_stack;
+ if (pnt_len == 1) {
+ /* Single point extrusion.
+ * Reference a `prev_bp` to force extrude. */
+ bp_prev = &nu->bp[0];
+ }
+ else {
+ duplic_first = (nu->bp[0].f1 & SELECT) && (nu->bp[1].f1 & SELECT);
+ duplic_last = (nu->bp[pnt_len - 2].f1 & SELECT) && (nu->bp[pnt_len - 1].f1 & SELECT);
+ if (duplic_first) {
+ bp_stack = nu->bp[0];
+ bp_stack.f1 &= ~SELECT;
+ bp_prev = &bp_stack;
+ }
+ if (duplic_last) {
+ new_points++;
+ }
+ }
- if (nu->type == CU_BEZIER) {
- BezTriple *bezt;
+ i = pnt_len;
+ for (bp = &nu->bp[0]; i--; bp++) {
+ bool is_selected = (bp->f1 & SELECT) != 0;
+ if (bp_prev && is_prev_selected != is_selected) {
+ new_points++;
+ }
+ if (bp == cu_actvert.bp) {
+ act_offset = new_points;
+ }
+ bp_prev = bp;
+ is_prev_selected = is_selected;
+ }
- for (bezt = &nu->bezt[i]; i < i_end; i++, bezt++) {
- if (BEZT_ISSEL_ANY_HIDDENHANDLES(v3d, bezt)) {
- Nurb *nurb_new;
- BezTriple *bezt_new;
+ if (new_points) {
+ BPoint *bp_src, *bp_dst, *bp_src_iter, *bp_dst_iter;
+ const int new_len = pnt_len + new_points;
- BEZT_DESEL_ALL(bezt);
- nurb_new = BKE_nurb_copy(nu, 1, 1);
- nurb_new->flagu &= ~CU_NURB_CYCLIC;
- BLI_addtail(&editnurb->nurbs, nurb_new);
- bezt_new = nurb_new->bezt;
- ED_curve_beztcpy(editnurb, bezt_new, bezt, 1);
- BEZT_SEL_ALL(bezt_new);
+ is_prev_selected = false;
+ if (pnt_len == 1) {
+ /* Single point extrusion.
+ * Keep `is_prev_selected` false to force extrude. */
+ BLI_assert(bp_prev == &nu->bp[0]);
+ }
+ else if (duplic_first) {
+ bp_prev = &bp_stack;
+ is_prev_selected = false;
+ }
+ else {
+ bp_prev = NULL;
+ }
+ bp_src = nu->bp;
+ bp_dst = MEM_mallocN(new_len * sizeof(BPoint), __func__);
+ bp_src_iter = &bp_src[0];
+ bp_dst_iter = &bp_dst[0];
+ i = 0;
+ for (bp = &nu->bp[0]; i < pnt_len; i++, bp++) {
+ bool is_selected = (bp->f1 & SELECT) != 0;
+ if (bp_prev && is_prev_selected != is_selected) {
+ int count = i - offset + 1;
+ if (is_prev_selected) {
+ ED_curve_bpcpy(editnurb, bp_dst_iter, bp_src_iter, count - 1);
+ ED_curve_bpcpy(editnurb, &bp_dst_iter[count - 1], bp_prev, 1);
+ }
+ else {
+ ED_curve_bpcpy(editnurb, bp_dst_iter, bp_src_iter, count);
+ }
+ ED_curve_bpcpy(editnurb, &bp_dst_iter[count], bp, 1);
+ bp_dst_iter[count - 1].f1 &= ~SELECT;
- if (cu_actvert.bezt == bezt || cu_actnu == NULL) {
- BKE_curve_nurb_vert_active_set(cu, nurb_new, bezt_new);
+ bp_dst_iter += count + 1;
+ bp_src_iter += count;
+ offset = i + 1;
}
-
- changed = true;
+ bp_prev = bp;
+ is_prev_selected = is_selected;
}
- }
- }
- else {
- BPoint *bp;
- for (bp = &nu->bp[i]; i < i_end; i++, bp++) {
- if (bp->f1 & SELECT) {
- Nurb *nurb_new;
- BPoint *bp_new;
+ int remain = pnt_len - offset;
+ if (remain) {
+ ED_curve_bpcpy(editnurb, bp_dst_iter, bp_src_iter, remain);
+ }
- bp->f1 &= ~SELECT;
- nurb_new = BKE_nurb_copy(nu, 1, 1);
- nurb_new->flagu &= ~CU_NURB_CYCLIC;
- BLI_addtail(&editnurb->nurbs, nurb_new);
- bp_new = nurb_new->bp;
- ED_curve_bpcpy(editnurb, bp_new, bp, 1);
- bp_new->f1 |= SELECT;
+ if (duplic_last) {
+ ED_curve_bpcpy(editnurb, &bp_dst[new_len - 1], &bp_src[pnt_len - 1], 1);
+ bp_dst[new_len - 1].f1 &= ~SELECT;
+ }
- if (cu_actvert.bp == bp || cu_actnu == NULL) {
- BKE_curve_nurb_vert_active_set(cu, nurb_new, bp_new);
- }
+ MEM_freeN(nu->bp);
+ nu->bp = bp_dst;
+ nu->pntsu += new_points;
- changed = true;
- }
+ BKE_nurb_knot_calc_u(nu);
+ changed = true;
}
}
}
- if (changed == false) {
- BKE_curve_nurb_vert_active_set(cu, cu_actnu, cu_actvert.p);
- }
+ cu->actvert += act_offset;
return changed;
}
-/***************** add vertex operator **********************/
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Add Vertex Operator
+ * \{ */
static int ed_editcurve_addvert(Curve *cu,
EditNurb *editnurb,
@@ -5659,7 +5617,7 @@ static int add_vertex_invoke(bContext *C, wmOperator *op, const wmEvent *event)
cu = vc.obedit->data;
- findselectedNurbvert(cu, vc.v3d, &nu, &bezt, &bp);
+ ED_curve_nurb_vert_selected_find(cu, vc.v3d, &nu, &bezt, &bp);
if (bezt) {
mul_v3_m4v3(location, vc.obedit->obmat, bezt->vec[1]);
@@ -5677,7 +5635,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(
- vc.bmain, vc.scene, 0, vc.region, vc.v3d);
+ vc.scene, 0, vc.region, vc.v3d);
ED_transform_snap_object_project_view3d(
snap_context,
@@ -5760,7 +5718,11 @@ void CURVE_OT_vertex_add(wmOperatorType *ot)
1.0e4f);
}
-/***************** extrude operator **********************/
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Extrude Operator
+ * \{ */
static int curve_extrude_exec(bContext *C, wmOperator *UNUSED(op))
{
@@ -5831,7 +5793,11 @@ void CURVE_OT_extrude(wmOperatorType *ot)
RNA_def_enum(ot->srna, "mode", rna_enum_transform_mode_types, TFM_TRANSLATION, "Mode", "");
}
-/***************** make cyclic operator **********************/
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Make Cyclic Operator
+ * \{ */
static bool curve_toggle_cyclic(View3D *v3d, ListBase *editnurb, int direction)
{
@@ -5997,7 +5963,11 @@ void CURVE_OT_cyclic_toggle(wmOperatorType *ot)
"Direction to make surface cyclic in");
}
-/********************** add duplicate operator *********************/
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Add Duplicate Operator
+ * \{ */
static int duplicate_exec(bContext *C, wmOperator *op)
{
@@ -6053,7 +6023,11 @@ void CURVE_OT_duplicate(wmOperatorType *ot)
ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
}
-/********************** delete operator *********************/
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Delete Operator
+ * \{ */
static bool curve_delete_vertices(Object *obedit, View3D *v3d)
{
@@ -6599,6 +6573,12 @@ void CURVE_OT_delete(wmOperatorType *ot)
ot->prop = prop;
}
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Dissolve Vertices
+ * \{ */
+
static bool test_bezt_is_sel_any(const void *bezt_v, void *user_data)
{
View3D *v3d = user_data;
@@ -6628,8 +6608,8 @@ static int curve_dissolve_exec(bContext *C, wmOperator *UNUSED(op))
for (nu = editnurb->first; nu; nu = nu->next) {
if ((nu->type == CU_BEZIER) && (nu->pntsu > 2)) {
- unsigned int span_step[2] = {nu->pntsu, nu->pntsu};
- unsigned int span_len;
+ uint span_step[2] = {nu->pntsu, nu->pntsu};
+ uint span_len;
while (BLI_array_iter_span(nu->bezt,
nu->pntsu,
@@ -6643,9 +6623,9 @@ static int curve_dissolve_exec(bContext *C, wmOperator *UNUSED(op))
BezTriple *bezt_next = &nu->bezt[mod_i(span_step[1] + 1, nu->pntsu)];
int i_span_edge_len = span_len + 1;
- const unsigned int dims = 3;
+ const uint dims = 3;
- const unsigned int points_len = ((cu->resolu - 1) * i_span_edge_len) + 1;
+ const uint points_len = ((cu->resolu - 1) * i_span_edge_len) + 1;
float *points = MEM_mallocN(points_len * dims * sizeof(float), __func__);
float *points_stride = points;
const int points_stride_len = (cu->resolu - 1);
@@ -6670,7 +6650,7 @@ static int curve_dissolve_exec(bContext *C, wmOperator *UNUSED(op))
BLI_assert(points_stride + dims == points + (points_len * dims));
float tan_l[3], tan_r[3], error_sq_dummy;
- unsigned int error_index_dummy;
+ uint error_index_dummy;
sub_v3_v3v3(tan_l, bezt_prev->vec[1], bezt_prev->vec[2]);
normalize_v3(tan_l);
@@ -6731,6 +6711,12 @@ void CURVE_OT_dissolve_verts(wmOperatorType *ot)
ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
}
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Decimate Operator
+ * \{ */
+
static bool nurb_bezt_flag_any(const Nurb *nu, const char flag_test)
{
BezTriple *bezt = nu->bezt;
@@ -6824,7 +6810,11 @@ void CURVE_OT_decimate(wmOperatorType *ot)
RNA_def_float_factor(ot->srna, "ratio", 1.0f, 0.0f, 1.0f, "Ratio", "", 0.0f, 1.0f);
}
-/********************** shade smooth/flat operator *********************/
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Shade Smooth/Flat Operator
+ * \{ */
static int shade_smooth_exec(bContext *C, wmOperator *op)
{
@@ -6844,7 +6834,7 @@ static int shade_smooth_exec(bContext *C, wmOperator *op)
continue;
}
- for (Nurb *nu = editnurb->first; nu; nu = nu->next) {
+ LISTBASE_FOREACH (Nurb *, nu, editnurb) {
if (ED_curve_nurb_select_check(v3d, nu)) {
if (!clear) {
nu->flag |= CU_SMOOTH;
@@ -6895,8 +6885,16 @@ void CURVE_OT_shade_flat(wmOperatorType *ot)
ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
}
-/************** join operator, to be used externally? ****************/
-/* TODO: shape keys - as with meshes */
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Join Operator
+ * \{ */
+
+/**
+ * This is used externally, by #OBJECT_OT_join.
+ * TODO: shape keys - as with meshes.
+ */
int join_curve_exec(bContext *C, wmOperator *op)
{
Main *bmain = CTX_data_main(C);
@@ -6996,7 +6994,11 @@ int join_curve_exec(bContext *C, wmOperator *op)
return OPERATOR_FINISHED;
}
-/***************** clear tilt operator ********************/
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Clear Tilt Operator
+ * \{ */
static int clear_tilt_exec(bContext *C, wmOperator *UNUSED(op))
{
@@ -7077,28 +7079,11 @@ void ED_curve_bpcpy(EditNurb *editnurb, BPoint *dst, BPoint *src, int count)
keyIndex_updateBP(editnurb, src, dst, count);
}
-bool ED_curve_active_center(Curve *cu, float center[3])
-{
- Nurb *nu = NULL;
- void *vert = NULL;
-
- if (!BKE_curve_nurb_vert_active_get(cu, &nu, &vert)) {
- return false;
- }
-
- if (nu->type == CU_BEZIER) {
- BezTriple *bezt = (BezTriple *)vert;
- copy_v3_v3(center, bezt->vec[1]);
- }
- else {
- BPoint *bp = (BPoint *)vert;
- copy_v3_v3(center, bp->vec);
- }
-
- return true;
-}
+/** \} */
-/******************** Match texture space operator ***********************/
+/* -------------------------------------------------------------------- */
+/** \name Match Texture Space Operator
+ * \{ */
static bool match_texture_space_poll(bContext *C)
{
@@ -7168,3 +7153,5 @@ void CURVE_OT_match_texture_space(wmOperatorType *ot)
/* flags */
ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
}
+
+/** \} */
diff --git a/source/blender/editors/curve/editcurve_add.c b/source/blender/editors/curve/editcurve_add.c
index 91d5ea58361..bacdd5b69b5 100644
--- a/source/blender/editors/curve/editcurve_add.c
+++ b/source/blender/editors/curve/editcurve_add.c
@@ -138,7 +138,7 @@ Nurb *ED_curve_add_nurbs_primitive(
copy_v3_v3(zvec, rv3d->viewinv[2]);
}
- BKE_nurbList_flag_set(editnurb, 0);
+ BKE_nurbList_flag_set(editnurb, SELECT, false);
/* these types call this function to return a Nurb */
if (stype != CU_PRIM_TUBE && stype != CU_PRIM_DONUT) {
@@ -521,7 +521,7 @@ static int curvesurf_prim_add(bContext *C, wmOperator *op, int type, int isSurf)
WM_operator_view3d_unit_defaults(C, op);
if (!ED_object_add_generic_get_opts(
- C, op, 'Z', loc, rot, &enter_editmode, &local_view_bits, NULL)) {
+ C, op, 'Z', loc, rot, NULL, &enter_editmode, &local_view_bits, NULL)) {
return OPERATOR_CANCELLED;
}
diff --git a/source/blender/editors/curve/editcurve_paint.c b/source/blender/editors/curve/editcurve_paint.c
index d028a88e322..748bf040fbb 100644
--- a/source/blender/editors/curve/editcurve_paint.c
+++ b/source/blender/editors/curve/editcurve_paint.c
@@ -205,7 +205,7 @@ static bool stroke_elem_project(const struct CurveDrawData *cdd,
}
else {
const ViewDepths *depths = rv3d->depths;
- if (depths && ((unsigned int)mval_i[0] < depths->w) && ((unsigned int)mval_i[1] < depths->h)) {
+ if (depths && ((uint)mval_i[0] < depths->w) && ((uint)mval_i[1] < depths->h)) {
const double depth = (double)ED_view3d_depth_read_cached(&cdd->vc, mval_i);
if ((depth > depths->depth_range[0]) && (depth < depths->depth_range[1])) {
if (ED_view3d_depth_unproject(region, mval_i, depth, r_location_world)) {
@@ -798,7 +798,7 @@ static int curve_draw_exec(bContext *C, wmOperator *op)
float *coords = MEM_mallocN(sizeof(*coords) * stroke_len * dims, __func__);
float *cubic_spline = NULL;
- unsigned int cubic_spline_len = 0;
+ uint cubic_spline_len = 0;
/* error in object local space */
const int fit_method = RNA_enum_get(op->ptr, "fit_method");
@@ -827,14 +827,14 @@ static int curve_draw_exec(bContext *C, wmOperator *op)
}
}
- unsigned int *corners = NULL;
- unsigned int corners_len = 0;
+ uint *corners = NULL;
+ uint corners_len = 0;
if ((fit_method == CURVE_PAINT_FIT_METHOD_SPLIT) && (corner_angle < (float)M_PI)) {
/* this could be configurable... */
const float corner_radius_min = error_threshold / 8;
const float corner_radius_max = error_threshold * 2;
- const unsigned int samples_max = 16;
+ const uint samples_max = 16;
curve_fit_corners_detect_fl(coords,
stroke_len,
@@ -847,9 +847,9 @@ static int curve_draw_exec(bContext *C, wmOperator *op)
&corners_len);
}
- unsigned int *corners_index = NULL;
- unsigned int corners_index_len = 0;
- unsigned int calc_flag = CURVE_FIT_CALC_HIGH_QUALIY;
+ uint *corners_index = NULL;
+ uint corners_index_len = 0;
+ uint calc_flag = CURVE_FIT_CALC_HIGH_QUALIY;
if ((stroke_len > 2) && use_cyclic) {
calc_flag |= CURVE_FIT_CALC_CYCLIC;
@@ -919,14 +919,14 @@ static int curve_draw_exec(bContext *C, wmOperator *op)
if (corners_index) {
/* ignore the first and last */
- unsigned int i_start = 0, i_end = corners_index_len;
+ uint i_start = 0, i_end = corners_index_len;
if ((corners_index_len >= 2) && (calc_flag & CURVE_FIT_CALC_CYCLIC) == 0) {
i_start += 1;
i_end -= 1;
}
- for (unsigned int i = i_start; i < i_end; i++) {
+ for (uint i = i_start; i < i_end; i++) {
bezt = &nu->bezt[corners_index[i]];
bezt->h1 = bezt->h2 = HD_FREE;
}
diff --git a/source/blender/editors/curve/editcurve_query.c b/source/blender/editors/curve/editcurve_query.c
new file mode 100644
index 00000000000..132f7e58e71
--- /dev/null
+++ b/source/blender/editors/curve/editcurve_query.c
@@ -0,0 +1,253 @@
+/*
+ * 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) 2001-2002 by NaN Holding BV.
+ * All rights reserved.
+ */
+
+/** \file
+ * \ingroup edcurve
+ */
+
+#include "DNA_object_types.h"
+#include "DNA_scene_types.h"
+
+#include "MEM_guardedalloc.h"
+
+#include "BLI_math.h"
+
+#include "BKE_curve.h"
+#include "BKE_fcurve.h"
+#include "BKE_layer.h"
+
+#include "DEG_depsgraph.h"
+#include "DEG_depsgraph_build.h"
+
+#include "ED_curve.h"
+#include "ED_view3d.h"
+
+#include "curve_intern.h"
+
+/* -------------------------------------------------------------------- */
+/** \name Cursor Picking API
+ * \{ */
+
+static void ED_curve_pick_vert__do_closest(void *userData,
+ Nurb *nu,
+ BPoint *bp,
+ BezTriple *bezt,
+ int beztindex,
+ bool handles_visible,
+ const float screen_co[2])
+{
+ struct {
+ BPoint *bp;
+ BezTriple *bezt;
+ Nurb *nurb;
+ float dist;
+ int hpoint, select;
+ float mval_fl[2];
+ bool is_changed;
+ } *data = userData;
+
+ short flag;
+ float dist_test;
+
+ if (bp) {
+ flag = bp->f1;
+ }
+ else {
+ BLI_assert(handles_visible || beztindex == 1);
+
+ if (beztindex == 0) {
+ flag = bezt->f1;
+ }
+ else if (beztindex == 1) {
+ flag = bezt->f2;
+ }
+ else {
+ flag = bezt->f3;
+ }
+ }
+
+ dist_test = len_manhattan_v2v2(data->mval_fl, screen_co);
+ if ((flag & SELECT) == data->select) {
+ dist_test += 5.0f;
+ }
+ if (bezt && beztindex == 1) {
+ dist_test += 3.0f; /* middle points get a small disadvantage */
+ }
+
+ if (dist_test < data->dist) {
+ data->dist = dist_test;
+
+ data->bp = bp;
+ data->bezt = bezt;
+ data->nurb = nu;
+ data->hpoint = bezt ? beztindex : 0;
+ data->is_changed = true;
+ }
+
+ UNUSED_VARS_NDEBUG(handles_visible);
+}
+
+bool ED_curve_pick_vert(ViewContext *vc,
+ short sel,
+ Nurb **r_nurb,
+ BezTriple **r_bezt,
+ BPoint **r_bp,
+ short *r_handle,
+ Base **r_base)
+{
+ /* (sel == 1): selected gets a disadvantage */
+ /* in nurb and bezt or bp the nearest is written */
+ /* return 0 1 2: handlepunt */
+ struct {
+ BPoint *bp;
+ BezTriple *bezt;
+ Nurb *nurb;
+ float dist;
+ int hpoint, select;
+ float mval_fl[2];
+ bool is_changed;
+ } data = {NULL};
+
+ data.dist = ED_view3d_select_dist_px();
+ data.hpoint = 0;
+ data.select = sel;
+ data.mval_fl[0] = vc->mval[0];
+ data.mval_fl[1] = vc->mval[1];
+
+ uint bases_len;
+ Base **bases = BKE_view_layer_array_from_bases_in_edit_mode_unique_data(
+ vc->view_layer, vc->v3d, &bases_len);
+ for (uint base_index = 0; base_index < bases_len; base_index++) {
+ Base *base = bases[base_index];
+ data.is_changed = false;
+
+ ED_view3d_viewcontext_init_object(vc, base->object);
+ ED_view3d_init_mats_rv3d(vc->obedit, vc->rv3d);
+ nurbs_foreachScreenVert(vc, ED_curve_pick_vert__do_closest, &data, V3D_PROJ_TEST_CLIP_DEFAULT);
+
+ if (r_base && data.is_changed) {
+ *r_base = base;
+ }
+ }
+ MEM_freeN(bases);
+
+ *r_nurb = data.nurb;
+ *r_bezt = data.bezt;
+ *r_bp = data.bp;
+
+ if (r_handle) {
+ *r_handle = data.hpoint;
+ }
+
+ return (data.bezt || data.bp);
+}
+
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Selection Queries
+ * \{ */
+
+void ED_curve_nurb_vert_selected_find(
+ Curve *cu, View3D *v3d, Nurb **r_nu, BezTriple **r_bezt, BPoint **r_bp)
+{
+ /* in nu and (bezt or bp) selected are written if there's 1 sel. */
+ /* if more points selected in 1 spline: return only nu, bezt and bp are 0 */
+ ListBase *editnurb = &cu->editnurb->nurbs;
+ Nurb *nu1;
+ BezTriple *bezt1;
+ BPoint *bp1;
+ int a;
+
+ *r_nu = NULL;
+ *r_bezt = NULL;
+ *r_bp = NULL;
+
+ for (nu1 = editnurb->first; nu1; nu1 = nu1->next) {
+ if (nu1->type == CU_BEZIER) {
+ bezt1 = nu1->bezt;
+ a = nu1->pntsu;
+ while (a--) {
+ if (BEZT_ISSEL_ANY_HIDDENHANDLES(v3d, bezt1)) {
+ if (*r_nu != NULL && *r_nu != nu1) {
+ *r_nu = NULL;
+ *r_bp = NULL;
+ *r_bezt = NULL;
+ return;
+ }
+ else if (*r_bezt || *r_bp) {
+ *r_bp = NULL;
+ *r_bezt = NULL;
+ }
+ else {
+ *r_bezt = bezt1;
+ *r_nu = nu1;
+ }
+ }
+ bezt1++;
+ }
+ }
+ else {
+ bp1 = nu1->bp;
+ a = nu1->pntsu * nu1->pntsv;
+ while (a--) {
+ if (bp1->f1 & SELECT) {
+ if (*r_nu != NULL && *r_nu != nu1) {
+ *r_bp = NULL;
+ *r_bezt = NULL;
+ *r_nu = NULL;
+ return;
+ }
+ else if (*r_bezt || *r_bp) {
+ *r_bp = NULL;
+ *r_bezt = NULL;
+ }
+ else {
+ *r_bp = bp1;
+ *r_nu = nu1;
+ }
+ }
+ bp1++;
+ }
+ }
+ }
+}
+
+bool ED_curve_active_center(Curve *cu, float center[3])
+{
+ Nurb *nu = NULL;
+ void *vert = NULL;
+
+ if (!BKE_curve_nurb_vert_active_get(cu, &nu, &vert)) {
+ return false;
+ }
+
+ if (nu->type == CU_BEZIER) {
+ BezTriple *bezt = (BezTriple *)vert;
+ copy_v3_v3(center, bezt->vec[1]);
+ }
+ else {
+ BPoint *bp = (BPoint *)vert;
+ copy_v3_v3(center, bp->vec);
+ }
+
+ return true;
+}
+
+/** \} */
diff --git a/source/blender/editors/curve/editcurve_select.c b/source/blender/editors/curve/editcurve_select.c
index 51bb1eafdb9..9294bc6e91b 100644
--- a/source/blender/editors/curve/editcurve_select.c
+++ b/source/blender/editors/curve/editcurve_select.c
@@ -29,6 +29,7 @@
#include "BLI_bitmap.h"
#include "BLI_heap_simple.h"
#include "BLI_kdtree.h"
+#include "BLI_listbase.h"
#include "BLI_math.h"
#include "BLI_rand.h"
@@ -198,7 +199,7 @@ bool ED_curve_nurb_select_all(const Nurb *nu)
bool ED_curve_select_all(EditNurb *editnurb)
{
bool changed = false;
- for (Nurb *nu = editnurb->nurbs.first; nu; nu = nu->next) {
+ LISTBASE_FOREACH (Nurb *, nu, &editnurb->nurbs) {
changed |= ED_curve_nurb_select_all(nu);
}
return changed;
@@ -257,7 +258,7 @@ bool ED_curve_select_check(View3D *v3d, struct EditNurb *editnurb)
bool ED_curve_deselect_all(EditNurb *editnurb)
{
bool changed = false;
- for (Nurb *nu = editnurb->nurbs.first; nu; nu = nu->next) {
+ LISTBASE_FOREACH (Nurb *, nu, &editnurb->nurbs) {
changed |= ED_curve_nurb_deselect_all(nu);
}
return changed;
@@ -589,8 +590,8 @@ static int de_select_all_exec(bContext *C, wmOperator *op)
changed = ED_curve_deselect_all(cu->editnurb);
break;
case SEL_INVERT:
- changed = ED_curve_select_swap(
- cu->editnurb, (v3d->overlay.edit_flag & V3D_OVERLAY_EDIT_CU_HANDLES) == 0);
+ changed = ED_curve_select_swap(cu->editnurb,
+ v3d->overlay.handle_display == CURVE_HANDLE_NONE);
break;
}
@@ -771,7 +772,7 @@ static int select_row_exec(bContext *C, wmOperator *UNUSED(op))
if (last == bp) {
direction = 1 - direction;
- BKE_nurbList_flag_set(editnurb, 0);
+ BKE_nurbList_flag_set(editnurb, SELECT, false);
}
last = bp;
@@ -825,8 +826,10 @@ static int select_next_exec(bContext *C, wmOperator *UNUSED(op))
for (uint ob_index = 0; ob_index < objects_len; ob_index++) {
Object *obedit = objects[ob_index];
+
ListBase *editnurb = object_editcurve_get(obedit);
select_adjacent_cp(editnurb, 1, 0, SELECT);
+
DEG_id_tag_update(obedit->data, ID_RECALC_SELECT);
WM_event_add_notifier(C, NC_GEOM | ND_SELECT, obedit->data);
}
@@ -860,8 +863,10 @@ static int select_previous_exec(bContext *C, wmOperator *UNUSED(op))
for (uint ob_index = 0; ob_index < objects_len; ob_index++) {
Object *obedit = objects[ob_index];
+
ListBase *editnurb = object_editcurve_get(obedit);
select_adjacent_cp(editnurb, -1, 0, SELECT);
+
DEG_id_tag_update(obedit->data, ID_RECALC_SELECT);
WM_event_add_notifier(C, NC_GEOM | ND_SELECT, obedit->data);
}
@@ -1391,6 +1396,7 @@ static int select_nth_exec(bContext *C, wmOperator *op)
if (ed_curve_select_nth(obedit->data, &op_params) == true) {
changed = true;
+
DEG_id_tag_update(obedit->data, ID_RECALC_SELECT);
WM_event_add_notifier(C, NC_GEOM | ND_SELECT, obedit->data);
}
@@ -1825,7 +1831,7 @@ static float curve_calc_dist_span(Nurb *nu, int vert_src, int vert_dst)
int i_prev, i;
float dist = 0.0f;
- BLI_assert(nu->pntsv == 1);
+ BLI_assert(nu->pntsv <= 1);
i_prev = vert_src;
i = (i_prev + 1) % u;
diff --git a/source/blender/editors/curve/editcurve_undo.c b/source/blender/editors/curve/editcurve_undo.c
index 94a0ef7a460..1fd1e217649 100644
--- a/source/blender/editors/curve/editcurve_undo.c
+++ b/source/blender/editors/curve/editcurve_undo.c
@@ -30,7 +30,7 @@
#include "BLI_blenlib.h"
#include "BLI_ghash.h"
-#include "BKE_animsys.h"
+#include "BKE_anim_data.h"
#include "BKE_context.h"
#include "BKE_curve.h"
#include "BKE_fcurve.h"
@@ -88,12 +88,12 @@ static void undocurve_to_editcurve(Main *bmain, UndoCurve *ucu, Curve *cu, short
if (ad) {
if (ad->action) {
- free_fcurves(&ad->action->curves);
- copy_fcurves(&ad->action->curves, &ucu->fcurves);
+ BKE_fcurves_free(&ad->action->curves);
+ BKE_fcurves_copy(&ad->action->curves, &ucu->fcurves);
}
- free_fcurves(&ad->drivers);
- copy_fcurves(&ad->drivers, &ucu->drivers);
+ BKE_fcurves_free(&ad->drivers);
+ BKE_fcurves_copy(&ad->drivers, &ucu->drivers);
}
/* copy */
@@ -132,10 +132,10 @@ static void undocurve_from_editcurve(UndoCurve *ucu, Curve *cu, const short shap
if (ad) {
if (ad->action) {
- copy_fcurves(&ucu->fcurves, &ad->action->curves);
+ BKE_fcurves_copy(&ucu->fcurves, &ad->action->curves);
}
- copy_fcurves(&ucu->drivers, &ad->drivers);
+ BKE_fcurves_copy(&ucu->drivers, &ad->drivers);
}
/* copy */
@@ -167,8 +167,8 @@ static void undocurve_free_data(UndoCurve *uc)
BKE_curve_editNurb_keyIndex_free(&uc->undoIndex);
- free_fcurves(&uc->fcurves);
- free_fcurves(&uc->drivers);
+ BKE_fcurves_free(&uc->fcurves);
+ BKE_fcurves_free(&uc->drivers);
}
static Object *editcurve_object_from_context(bContext *C)
diff --git a/source/blender/editors/curve/editfont.c b/source/blender/editors/curve/editfont.c
index 297af4cb72d..dc5dc71106f 100644
--- a/source/blender/editors/curve/editfont.c
+++ b/source/blender/editors/curve/editfont.c
@@ -76,7 +76,7 @@ static int kill_selection(Object *obedit, int ins);
/** \name Internal Utilities
* \{ */
-static wchar_t findaccent(wchar_t char1, unsigned int code)
+static wchar_t findaccent(wchar_t char1, uint code)
{
wchar_t new = 0;
diff --git a/source/blender/editors/curve/editfont_undo.c b/source/blender/editors/curve/editfont_undo.c
index af591e0c7c5..ef9bb7e0c88 100644
--- a/source/blender/editors/curve/editfont_undo.c
+++ b/source/blender/editors/curve/editfont_undo.c
@@ -359,7 +359,7 @@ static void font_undosys_step_decode(
struct bContext *C, struct Main *bmain, UndoStep *us_p, int UNUSED(dir), bool UNUSED(is_final))
{
/* TODO(campbell): undo_system: use low-level API to set mode. */
- ED_object_mode_set(C, OB_MODE_EDIT);
+ ED_object_mode_set_ex(C, OB_MODE_EDIT, false, NULL);
BLI_assert(font_undosys_poll(C));
FontUndoStep *us = (FontUndoStep *)us_p;
diff --git a/source/blender/editors/datafiles/CMakeLists.txt b/source/blender/editors/datafiles/CMakeLists.txt
index 1bc0465424d..1a5b3d6ac45 100644
--- a/source/blender/editors/datafiles/CMakeLists.txt
+++ b/source/blender/editors/datafiles/CMakeLists.txt
@@ -336,7 +336,7 @@ set(ICON_NAMES
force_boid
force_turbulence
force_drag
- force_smokeflow
+ force_fluidflow
image_plane
image_background
image_reference
@@ -779,7 +779,6 @@ if(WITH_BLENDER)
# images
data_to_c_simple(../../../../release/datafiles/splash.png SRC)
- data_to_c_simple(../../../../release/datafiles/splash_2x.png SRC)
data_to_c_simple(../../../../release/datafiles/alert_icons.png SRC)
# XXX These are handy, but give nasty "false changes" in svn :/
# svg_to_png(../../../../release/datafiles/blender_icons.svg
diff --git a/source/blender/editors/gizmo_library/CMakeLists.txt b/source/blender/editors/gizmo_library/CMakeLists.txt
index 68a204c04a7..1f3edf31b19 100644
--- a/source/blender/editors/gizmo_library/CMakeLists.txt
+++ b/source/blender/editors/gizmo_library/CMakeLists.txt
@@ -53,6 +53,7 @@ set(SRC
gizmo_types/dial3d_gizmo.c
gizmo_types/move3d_gizmo.c
gizmo_types/primitive3d_gizmo.c
+ gizmo_types/snap3d_gizmo.c
)
set(LIB
diff --git a/source/blender/editors/gizmo_library/geometry/geom_arrow_gizmo.c b/source/blender/editors/gizmo_library/geometry/geom_arrow_gizmo.c
index 90196988d94..668b59ac191 100644
--- a/source/blender/editors/gizmo_library/geometry/geom_arrow_gizmo.c
+++ b/source/blender/editors/gizmo_library/geometry/geom_arrow_gizmo.c
@@ -55,7 +55,7 @@ static float normals[][3] = {
{0.000000, 0.000000, 1.000000},
};
-static unsigned short indices[] = {
+static ushort indices[] = {
1, 3, 2, 3, 5, 4, 5, 7, 6, 7, 9, 8, 9, 11, 10, 11, 13, 12, 5, 18, 19, 15, 1,
0, 13, 15, 14, 6, 10, 14, 11, 21, 22, 7, 19, 20, 13, 22, 23, 3, 17, 18, 9, 20, 21, 15,
23, 16, 1, 16, 17, 23, 22, 24, 21, 20, 24, 19, 18, 24, 17, 16, 24, 16, 23, 24, 22, 21, 24,
diff --git a/source/blender/editors/gizmo_library/geometry/geom_cube_gizmo.c b/source/blender/editors/gizmo_library/geometry/geom_cube_gizmo.c
index ea1a3147148..51618e353f4 100644
--- a/source/blender/editors/gizmo_library/geometry/geom_cube_gizmo.c
+++ b/source/blender/editors/gizmo_library/geometry/geom_cube_gizmo.c
@@ -45,7 +45,7 @@ static const float normals[][3] = {
{-0.577349, 0.577349, 0.577349},
};
-static const unsigned short indices[] = {
+static const ushort indices[] = {
1, 2, 3, 7, 6, 5, 4, 5, 1, 5, 6, 2, 2, 6, 7, 0, 3, 7,
0, 1, 3, 4, 7, 5, 0, 4, 1, 1, 5, 2, 3, 2, 7, 4, 0, 7,
};
diff --git a/source/blender/editors/gizmo_library/geometry/geom_dial_gizmo.c b/source/blender/editors/gizmo_library/geometry/geom_dial_gizmo.c
index 273f957e9b6..7e37c233c2a 100644
--- a/source/blender/editors/gizmo_library/geometry/geom_dial_gizmo.c
+++ b/source/blender/editors/gizmo_library/geometry/geom_dial_gizmo.c
@@ -221,7 +221,7 @@ static const float normals[][3] = {
{-0.466689, 0.092807, -0.879513}, {0.512650, -0.101962, -0.852504},
};
-static const unsigned short indices[] = {
+static const ushort indices[] = {
6, 7, 1, 7, 8, 2, 8, 9, 3, 9, 10, 4, 10, 11, 5, 5, 11, 6, 12,
13, 7, 13, 14, 8, 14, 15, 9, 15, 16, 10, 16, 17, 11, 11, 17, 12, 18, 19,
13, 13, 19, 20, 20, 21, 15, 15, 21, 22, 22, 23, 17, 17, 23, 18, 24, 25, 19,
diff --git a/source/blender/editors/gizmo_library/gizmo_draw_utils.c b/source/blender/editors/gizmo_library/gizmo_draw_utils.c
index cffafc56693..01e5a7eacfd 100644
--- a/source/blender/editors/gizmo_library/gizmo_draw_utils.c
+++ b/source/blender/editors/gizmo_library/gizmo_draw_utils.c
@@ -66,7 +66,7 @@ void wm_gizmo_geometryinfo_draw(const GizmoGeomInfo *info,
/* Elements */
GPU_indexbuf_init(&elb, GPU_PRIM_TRIS, info->ntris, info->nverts);
for (int i = 0; i < info->ntris; i++) {
- const unsigned short *idx = &info->indices[i * 3];
+ const ushort *idx = &info->indices[i * 3];
GPU_indexbuf_add_tri_verts(&elb, idx[0], idx[1], idx[2]);
}
el = GPU_indexbuf_build(&elb);
diff --git a/source/blender/editors/gizmo_library/gizmo_geometry.h b/source/blender/editors/gizmo_library/gizmo_geometry.h
index ae8ba3c411b..a5f61158f66 100644
--- a/source/blender/editors/gizmo_library/gizmo_geometry.h
+++ b/source/blender/editors/gizmo_library/gizmo_geometry.h
@@ -30,12 +30,14 @@
#ifndef __GIZMO_GEOMETRY_H__
#define __GIZMO_GEOMETRY_H__
+#include "BLI_sys_types.h"
+
typedef struct GizmoGeomInfo {
int nverts;
int ntris;
const float (*verts)[3];
const float (*normals)[3];
- const unsigned short *indices;
+ const ushort *indices;
} GizmoGeomInfo;
/* arrow gizmo */
diff --git a/source/blender/editors/gizmo_library/gizmo_types/arrow3d_gizmo.c b/source/blender/editors/gizmo_library/gizmo_types/arrow3d_gizmo.c
index da6365d724d..e6333d7d3e0 100644
--- a/source/blender/editors/gizmo_library/gizmo_types/arrow3d_gizmo.c
+++ b/source/blender/editors/gizmo_library/gizmo_types/arrow3d_gizmo.c
@@ -88,9 +88,14 @@ static void arrow_draw_geom(const ArrowGizmo3D *arrow, const bool select, const
const int draw_style = RNA_enum_get(arrow->gizmo.ptr, "draw_style");
const int draw_options = RNA_enum_get(arrow->gizmo.ptr, "draw_options");
- immBindBuiltinProgram(GPU_SHADER_3D_UNIFORM_COLOR);
+ immBindBuiltinProgram(GPU_SHADER_3D_POLYLINE_UNIFORM_COLOR);
+
+ float viewport[4];
+ GPU_viewport_size_get_f(viewport);
+ immUniform2fv("viewportSize", &viewport[2]);
if (draw_style == ED_GIZMO_ARROW_STYLE_CROSS) {
+ immUniform1f("lineWidth", U.pixelsize);
immUniformColor4fv(color);
immBegin(GPU_PRIM_LINES, 4);
@@ -112,7 +117,7 @@ static void arrow_draw_geom(const ArrowGizmo3D *arrow, const bool select, const
{-unitx, unity, 0},
};
- GPU_line_width(arrow->gizmo.line_width);
+ immUniform1f("lineWidth", arrow->gizmo.line_width * U.pixelsize);
wm_gizmo_vec_draw(color, vec, ARRAY_SIZE(vec), pos, GPU_PRIM_LINE_LOOP);
}
else {
@@ -127,7 +132,7 @@ static void arrow_draw_geom(const ArrowGizmo3D *arrow, const bool select, const
};
if (draw_options & ED_GIZMO_ARROW_DRAW_FLAG_STEM) {
- GPU_line_width(arrow->gizmo.line_width);
+ immUniform1f("lineWidth", arrow->gizmo.line_width * U.pixelsize);
wm_gizmo_vec_draw(color, vec, ARRAY_SIZE(vec), pos, GPU_PRIM_LINE_STRIP);
}
else {
@@ -160,6 +165,10 @@ static void arrow_draw_geom(const ArrowGizmo3D *arrow, const bool select, const
/* translate to line end */
GPU_matrix_translate_3f(0.0f, 0.0f, arrow_length);
+ immUnbindProgram();
+ immBindBuiltinProgram(GPU_SHADER_3D_UNIFORM_COLOR);
+ immUniformColor4fv(color);
+
imm_draw_circle_fill_3d(pos, 0.0, 0.0, width, 8);
imm_draw_cylinder_fill_3d(pos, width, 0.0, len, 8, 1);
}
diff --git a/source/blender/editors/gizmo_library/gizmo_types/button2d_gizmo.c b/source/blender/editors/gizmo_library/gizmo_types/button2d_gizmo.c
index 11253f01bf2..04b93f35681 100644
--- a/source/blender/editors/gizmo_library/gizmo_types/button2d_gizmo.c
+++ b/source/blender/editors/gizmo_library/gizmo_types/button2d_gizmo.c
@@ -76,7 +76,8 @@ static void button2d_geom_draw_backdrop(const wmGizmo *gz,
const float fill_alpha,
const bool select)
{
- GPU_line_width(gz->line_width);
+ float viewport[4];
+ GPU_viewport_size_get_f(viewport);
GPUVertFormat *format = immVertexFormat();
uint pos = GPU_vertformat_attr_add(format, "pos", GPU_COMP_F32, 2, GPU_FETCH_FLOAT);
@@ -85,10 +86,14 @@ static void button2d_geom_draw_backdrop(const wmGizmo *gz,
if (color[3] == 1.0 && fill_alpha == 1.0 && select == false) {
immBindBuiltinProgram(GPU_SHADER_3D_UNIFORM_COLOR);
immUniformColor4fv(color);
- GPU_polygon_smooth(0);
imm_draw_circle_fill_2d(pos, 0, 0, 1.0f, CIRCLE_RESOLUTION);
+ immUnbindProgram();
+
+ immBindBuiltinProgram(GPU_SHADER_3D_POLYLINE_UNIFORM_COLOR);
+ immUniform2fv("viewportSize", &viewport[2]);
+ immUniform1f("lineWidth", gz->line_width * U.pixelsize);
+ immUniformColor4fv(color);
imm_draw_circle_wire_2d(pos, 0, 0, 1.0f, CIRCLE_RESOLUTION);
- GPU_polygon_smooth(1);
immUnbindProgram();
}
else {
@@ -103,9 +108,10 @@ static void button2d_geom_draw_backdrop(const wmGizmo *gz,
/* Draw outline. */
if ((fill_alpha != 1.0f) && (select == false)) {
- immBindBuiltinProgram(GPU_SHADER_3D_UNIFORM_COLOR);
+ immBindBuiltinProgram(GPU_SHADER_3D_POLYLINE_UNIFORM_COLOR);
+ immUniform2fv("viewportSize", &viewport[2]);
+ immUniform1f("lineWidth", gz->line_width * U.pixelsize);
immUniformColor4fv(color);
- GPU_line_width(gz->line_width);
imm_draw_circle_wire_2d(pos, 0, 0, 1.0f, CIRCLE_RESOLUTION);
immUnbindProgram();
}
@@ -120,6 +126,8 @@ static void button2d_draw_intern(const bContext *C,
const bool highlight)
{
ButtonGizmo2D *button = (ButtonGizmo2D *)gz;
+ float viewport[4];
+ GPU_viewport_size_get_f(viewport);
const int draw_options = RNA_enum_get(gz->ptr, "draw_options");
if (button->is_init == false) {
@@ -155,9 +163,9 @@ static void button2d_draw_intern(const bContext *C,
float matrix_final_no_offset[4][4];
WM_gizmo_calc_matrix_final_no_offset(gz, matrix_final_no_offset);
uint pos = GPU_vertformat_attr_add(immVertexFormat(), "pos", GPU_COMP_F32, 3, GPU_FETCH_FLOAT);
- immBindBuiltinProgram(GPU_SHADER_3D_UNIFORM_COLOR);
- immUniformColor4fv(color);
- GPU_line_width(gz->line_width);
+ immBindBuiltinProgram(GPU_SHADER_3D_POLYLINE_UNIFORM_COLOR);
+ immUniform2fv("viewportSize", &viewport[2]);
+ immUniform1f("lineWidth", gz->line_width * U.pixelsize);
immUniformColor4fv(color);
immBegin(GPU_PRIM_LINE_STRIP, 2);
immVertex3fv(pos, matrix_final[3]);
@@ -197,11 +205,19 @@ static void button2d_draw_intern(const bContext *C,
if (button->shape_batch[0] != NULL) {
GPU_line_smooth(true);
GPU_polygon_smooth(false);
- GPU_line_width(1.0f);
for (uint i = 0; i < ARRAY_SIZE(button->shape_batch) && button->shape_batch[i]; i++) {
- /* Invert line color for wire. */
- GPU_batch_program_set_builtin(button->shape_batch[i], GPU_SHADER_2D_UNIFORM_COLOR);
+ const bool do_wires = (i == 1);
+ if (do_wires) {
+ GPU_batch_program_set_builtin(button->shape_batch[i],
+ GPU_SHADER_3D_POLYLINE_UNIFORM_COLOR);
+ GPU_batch_uniform_2fv(button->shape_batch[i], "viewportSize", &viewport[2]);
+ GPU_batch_uniform_1f(button->shape_batch[i], "lineWidth", gz->line_width * U.pixelsize);
+ }
+ else {
+ GPU_batch_program_set_builtin(button->shape_batch[i], GPU_SHADER_2D_UNIFORM_COLOR);
+ }
+ /* Invert line color for wire. */
if (draw_options & ED_GIZMO_BUTTON_SHOW_BACKDROP) {
/* If we have a backdrop already,
* draw a contrasting shape over it instead of drawing it the same color.
diff --git a/source/blender/editors/gizmo_library/gizmo_types/cage2d_gizmo.c b/source/blender/editors/gizmo_library/gizmo_types/cage2d_gizmo.c
index 1b43479eedb..fd24149e9ea 100644
--- a/source/blender/editors/gizmo_library/gizmo_types/cage2d_gizmo.c
+++ b/source/blender/editors/gizmo_library/gizmo_types/cage2d_gizmo.c
@@ -162,13 +162,22 @@ static void gizmo_rect_pivot_from_scale_part(int part, float r_pt[2], bool r_con
* Useful for 3D views, see: #ED_GIZMO_CAGE2D_STYLE_BOX
* \{ */
-static void cage2d_draw_box_corners(const rctf *r, const float margin[2], const float color[3])
+static void cage2d_draw_box_corners(const rctf *r,
+ const float margin[2],
+ const float color[3],
+ const float line_width)
{
uint pos = GPU_vertformat_attr_add(immVertexFormat(), "pos", GPU_COMP_F32, 2, GPU_FETCH_FLOAT);
- immBindBuiltinProgram(GPU_SHADER_2D_UNIFORM_COLOR);
+ immBindBuiltinProgram(GPU_SHADER_3D_POLYLINE_UNIFORM_COLOR);
immUniformColor3fv(color);
+ float viewport[4];
+ GPU_viewport_size_get_f(viewport);
+ immUniform2fv("viewportSize", &viewport[2]);
+
+ immUniform1f("lineWidth", line_width * U.pixelsize);
+
immBegin(GPU_PRIM_LINES, 16);
immVertex2f(pos, r->xmin, r->ymin + margin[1]);
@@ -445,7 +454,7 @@ static void cage2d_draw_box_interaction(const float color[4],
.pos = GPU_vertformat_attr_add(format, "pos", GPU_COMP_F32, 2, GPU_FETCH_FLOAT),
.col = GPU_vertformat_attr_add(format, "color", GPU_COMP_F32, 3, GPU_FETCH_FLOAT),
};
- immBindBuiltinProgram(GPU_SHADER_2D_FLAT_COLOR);
+ immBindBuiltinProgram(is_solid ? GPU_SHADER_2D_FLAT_COLOR : GPU_SHADER_3D_POLYLINE_FLAT_COLOR);
{
if (is_solid) {
@@ -459,7 +468,12 @@ static void cage2d_draw_box_interaction(const float color[4],
}
else {
BLI_assert(ELEM(prim_type, GPU_PRIM_LINE_STRIP, GPU_PRIM_LINES));
- GPU_line_width(line_width + 3.0f);
+
+ float viewport[4];
+ GPU_viewport_size_get_f(viewport);
+ immUniform2fv("viewportSize", &viewport[2]);
+
+ immUniform1f("lineWidth", (line_width * 3.0f) * U.pixelsize);
immBegin(prim_type, verts_len);
immAttr3f(attr_id.col, 0.0f, 0.0f, 0.0f);
@@ -468,7 +482,7 @@ static void cage2d_draw_box_interaction(const float color[4],
}
immEnd();
- GPU_line_width(line_width);
+ immUniform1f("lineWidth", line_width * U.pixelsize);
immBegin(prim_type, verts_len);
immAttr3fv(attr_id.col, color);
@@ -505,13 +519,19 @@ static void cage2d_draw_circle_wire(const rctf *r,
const float margin[2],
const float color[3],
const int transform_flag,
- const int draw_options)
+ const int draw_options,
+ const float line_width)
{
uint pos = GPU_vertformat_attr_add(immVertexFormat(), "pos", GPU_COMP_F32, 2, GPU_FETCH_FLOAT);
- immBindBuiltinProgram(GPU_SHADER_2D_UNIFORM_COLOR);
+ immBindBuiltinProgram(GPU_SHADER_3D_POLYLINE_UNIFORM_COLOR);
immUniformColor3fv(color);
+ float viewport[4];
+ GPU_viewport_size_get_f(viewport);
+ immUniform2fv("viewportSize", &viewport[2]);
+ immUniform1f("lineWidth", line_width * U.pixelsize);
+
immBegin(GPU_PRIM_LINE_LOOP, 4);
immVertex2f(pos, r->xmin, r->ymin);
immVertex2f(pos, r->xmax, r->ymin);
@@ -662,15 +682,14 @@ static void gizmo_cage2d_draw_intern(wmGizmo *gz,
.ymax = size_real[1],
};
if (draw_style == ED_GIZMO_CAGE2D_STYLE_BOX) {
+ float color[4], black[3] = {0, 0, 0};
+ gizmo_color_get(gz, highlight, color);
+
/* corner gizmos */
- GPU_line_width(gz->line_width + 3.0f);
- cage2d_draw_box_corners(&r, margin, (const float[3]){0, 0, 0});
+ cage2d_draw_box_corners(&r, margin, black, gz->line_width + 3.0f);
/* corner gizmos */
- float color[4];
- gizmo_color_get(gz, highlight, color);
- GPU_line_width(gz->line_width);
- cage2d_draw_box_corners(&r, margin, color);
+ cage2d_draw_box_corners(&r, margin, color, gz->line_width);
bool show = false;
if (gz->highlight_part == ED_GIZMO_CAGE2D_PART_TRANSLATE) {
@@ -700,30 +719,26 @@ static void gizmo_cage2d_draw_intern(wmGizmo *gz,
}
}
else if (draw_style == ED_GIZMO_CAGE2D_STYLE_CIRCLE) {
- float color[4];
+ float color[4], black[3] = {0, 0, 0};
gizmo_color_get(gz, highlight, color);
- GPU_line_smooth(true);
GPU_blend(true);
- GPU_line_width(gz->line_width + 3.0f);
- cage2d_draw_circle_wire(&r, margin, (const float[3]){0, 0, 0}, transform_flag, draw_options);
- GPU_line_width(gz->line_width);
- cage2d_draw_circle_wire(&r, margin, color, transform_flag, draw_options);
+ float outline_line_width = gz->line_width + 3.0f;
+ cage2d_draw_circle_wire(&r, margin, black, transform_flag, draw_options, outline_line_width);
+ cage2d_draw_circle_wire(&r, margin, color, transform_flag, draw_options, gz->line_width);
/* corner gizmos */
cage2d_draw_circle_handles(&r, margin, color, transform_flag, true);
cage2d_draw_circle_handles(&r, margin, (const float[3]){0, 0, 0}, transform_flag, false);
GPU_blend(false);
- GPU_line_smooth(false);
}
else {
BLI_assert(0);
}
}
- GPU_line_width(1.0);
GPU_matrix_pop();
}
diff --git a/source/blender/editors/gizmo_library/gizmo_types/cage3d_gizmo.c b/source/blender/editors/gizmo_library/gizmo_types/cage3d_gizmo.c
index 6855268610e..b0af8641767 100644
--- a/source/blender/editors/gizmo_library/gizmo_types/cage3d_gizmo.c
+++ b/source/blender/editors/gizmo_library/gizmo_types/cage3d_gizmo.c
@@ -130,14 +130,22 @@ static void gizmo_rect_pivot_from_scale_part(int part, float r_pt[3], bool r_con
* Useful for 3D views, see: #ED_GIZMO_CAGE2D_STYLE_BOX
* \{ */
-static void cage3d_draw_box_corners(const float r[3], const float margin[3], const float color[3])
+static void cage3d_draw_box_corners(const float r[3],
+ const float margin[3],
+ const float color[3],
+ const float line_width)
{
uint pos = GPU_vertformat_attr_add(immVertexFormat(), "pos", GPU_COMP_F32, 3, GPU_FETCH_FLOAT);
UNUSED_VARS(margin);
- immBindBuiltinProgram(GPU_SHADER_3D_UNIFORM_COLOR);
+ immBindBuiltinProgram(GPU_SHADER_3D_POLYLINE_UNIFORM_COLOR);
immUniformColor3fv(color);
+ float viewport[4];
+ GPU_viewport_size_get_f(viewport);
+ immUniform2fv("viewportSize", &viewport[2]);
+ immUniform1f("lineWidth", line_width * U.pixelsize);
+
imm_draw_cube_wire_3d(pos, (float[3]){0}, r);
immUnbindProgram();
@@ -199,13 +207,19 @@ static void cage3d_draw_circle_wire(const float r[3],
const float margin[3],
const float color[3],
const int transform_flag,
- const int draw_options)
+ const int draw_options,
+ const float line_width)
{
uint pos = GPU_vertformat_attr_add(immVertexFormat(), "pos", GPU_COMP_F32, 3, GPU_FETCH_FLOAT);
- immBindBuiltinProgram(GPU_SHADER_3D_UNIFORM_COLOR);
+ immBindBuiltinProgram(GPU_SHADER_3D_POLYLINE_UNIFORM_COLOR);
immUniformColor3fv(color);
+ float viewport[4];
+ GPU_viewport_size_get_f(viewport);
+ immUniform2fv("viewportSize", &viewport[2]);
+ immUniform1f("lineWidth", line_width * U.pixelsize);
+
imm_draw_cube_wire_3d(pos, (float[3]){0}, r);
#if 0
@@ -339,15 +353,14 @@ static void gizmo_cage3d_draw_intern(
};
#endif
if (draw_style == ED_GIZMO_CAGE2D_STYLE_BOX) {
+ float color[4], black[3] = {0, 0, 0};
+ gizmo_color_get(gz, highlight, color);
+
/* corner gizmos */
- GPU_line_width(gz->line_width + 3.0f);
- cage3d_draw_box_corners(size_real, margin, (const float[3]){0, 0, 0});
+ cage3d_draw_box_corners(size_real, margin, black, gz->line_width + 3.0f);
/* corner gizmos */
- float color[4];
- gizmo_color_get(gz, highlight, color);
- GPU_line_width(gz->line_width);
- cage3d_draw_box_corners(size_real, margin, color);
+ cage3d_draw_box_corners(size_real, margin, color, gz->line_width);
bool show = false;
if (gz->highlight_part == ED_GIZMO_CAGE3D_PART_TRANSLATE) {
@@ -366,34 +379,29 @@ static void gizmo_cage3d_draw_intern(
}
}
else if (draw_style == ED_GIZMO_CAGE2D_STYLE_CIRCLE) {
- float color[4];
+ float color[4], black[3] = {0, 0, 0};
gizmo_color_get(gz, highlight, color);
- GPU_line_smooth(true);
- GPU_polygon_smooth(true);
GPU_blend(true);
- GPU_line_width(gz->line_width + 3.0f);
cage3d_draw_circle_wire(
- size_real, margin, (const float[3]){0, 0, 0}, transform_flag, draw_options);
- GPU_line_width(gz->line_width);
- cage3d_draw_circle_wire(size_real, margin, color, transform_flag, draw_options);
+ size_real, margin, black, transform_flag, draw_options, gz->line_width + 3.0f);
+ cage3d_draw_circle_wire(
+ size_real, margin, color, transform_flag, draw_options, gz->line_width);
/* corner gizmos */
- cage3d_draw_circle_handles(
- rv3d, matrix_final, size_real, margin, (const float[3]){0, 0, 0}, true, 60);
+ GPU_polygon_smooth(true);
+ cage3d_draw_circle_handles(rv3d, matrix_final, size_real, margin, black, true, 60);
cage3d_draw_circle_handles(rv3d, matrix_final, size_real, margin, color, true, 40);
+ GPU_polygon_smooth(false);
GPU_blend(false);
- GPU_polygon_smooth(false);
- GPU_line_smooth(false);
}
else {
BLI_assert(0);
}
}
- GPU_line_width(1.0);
GPU_matrix_pop();
}
diff --git a/source/blender/editors/gizmo_library/gizmo_types/dial3d_gizmo.c b/source/blender/editors/gizmo_library/gizmo_types/dial3d_gizmo.c
index 6b308308664..262f4b78b95 100644
--- a/source/blender/editors/gizmo_library/gizmo_types/dial3d_gizmo.c
+++ b/source/blender/editors/gizmo_library/gizmo_types/dial3d_gizmo.c
@@ -111,19 +111,18 @@ static void dial_geom_draw(const float color[4],
ED_GIZMO_DIAL_DRAW_FLAG_FILL_SELECT) :
ED_GIZMO_DIAL_DRAW_FLAG_FILL)));
- GPU_line_width(line_width);
-
GPUVertFormat *format = immVertexFormat();
uint pos = GPU_vertformat_attr_add(format, "pos", GPU_COMP_F32, 2, GPU_FETCH_FLOAT);
if (clip_plane) {
- immBindBuiltinProgram(GPU_SHADER_3D_CLIPPED_UNIFORM_COLOR);
+ immBindBuiltinProgram(filled ? GPU_SHADER_3D_CLIPPED_UNIFORM_COLOR :
+ GPU_SHADER_3D_POLYLINE_CLIPPED_UNIFORM_COLOR);
immUniform4fv("ClipPlane", clip_plane);
immUniformMatrix4fv("ModelMatrix", axis_modal_mat);
- glEnable(GL_CLIP_DISTANCE0);
}
else {
- immBindBuiltinProgram(GPU_SHADER_3D_UNIFORM_COLOR);
+ immBindBuiltinProgram(filled ? GPU_SHADER_3D_UNIFORM_COLOR :
+ GPU_SHADER_3D_POLYLINE_UNIFORM_COLOR);
}
immUniformColor4fv(color);
@@ -151,6 +150,11 @@ static void dial_geom_draw(const float color[4],
}
}
else {
+ float viewport[4];
+ GPU_viewport_size_get_f(viewport);
+ immUniform2fv("viewportSize", &viewport[2]);
+ immUniform1f("lineWidth", line_width * U.pixelsize);
+
if (arc_partial_angle == 0.0f) {
imm_draw_circle_wire_2d(pos, 0, 0, 1.0, DIAL_RESOLUTION);
if (arc_inner_factor != 0.0f) {
@@ -171,10 +175,6 @@ static void dial_geom_draw(const float color[4],
immUnbindProgram();
- if (clip_plane) {
- glDisable(GL_CLIP_DISTANCE0);
- }
-
UNUSED_VARS(select);
#endif
}
@@ -184,14 +184,20 @@ static void dial_geom_draw(const float color[4],
*/
static void dial_ghostarc_draw_helpline(const float angle,
const float co_outer[3],
- const float color[4])
+ const float color[4],
+ const float line_width)
{
GPU_matrix_push();
GPU_matrix_rotate_3f(RAD2DEGF(angle), 0.0f, 0.0f, -1.0f);
uint pos = GPU_vertformat_attr_add(immVertexFormat(), "pos", GPU_COMP_F32, 3, GPU_FETCH_FLOAT);
- immBindBuiltinProgram(GPU_SHADER_3D_UNIFORM_COLOR);
+ immBindBuiltinProgram(GPU_SHADER_3D_POLYLINE_UNIFORM_COLOR);
+
+ float viewport[4];
+ GPU_viewport_size_get_f(viewport);
+ immUniform2fv("viewportSize", &viewport[2]);
+ immUniform1f("lineWidth", line_width * U.pixelsize);
immUniformColor4fv(color);
@@ -211,11 +217,17 @@ static void dial_ghostarc_draw_helpline(const float angle,
static void dial_ghostarc_draw_incremental_angle(const float incremental_angle, const float offset)
{
const int tot_incr = (2 * M_PI) / incremental_angle;
- GPU_line_width(1.0f);
uint pos = GPU_vertformat_attr_add(immVertexFormat(), "pos", GPU_COMP_F32, 3, GPU_FETCH_FLOAT);
- immBindBuiltinProgram(GPU_SHADER_3D_UNIFORM_COLOR);
+ immBindBuiltinProgram(GPU_SHADER_3D_POLYLINE_UNIFORM_COLOR);
+
immUniformColor3f(1.0f, 1.0f, 1.0f);
+
+ float viewport[4];
+ GPU_viewport_size_get_f(viewport);
+ immUniform2fv("viewportSize", &viewport[2]);
+ immUniform1f("lineWidth", U.pixelsize);
+
immBegin(GPU_PRIM_LINES, tot_incr * 2);
float v[3] = {0};
@@ -369,14 +381,12 @@ static void dial_ghostarc_draw_with_helplines(const float angle_ofs,
{
/* Coordinate at which the arc drawing will be started. */
const float co_outer[4] = {0.0f, DIAL_WIDTH, 0.0f};
- dial_ghostarc_draw(
- angle_ofs, angle_delta, arc_inner_factor, (const float[4]){0.8f, 0.8f, 0.8f, 0.4f});
- GPU_line_width(1.0f);
- dial_ghostarc_draw_helpline(angle_ofs, co_outer, color_helpline);
- if (draw_options & ED_GIZMO_DIAL_DRAW_FLAG_ANGLE_VALUE) {
- GPU_line_width(3.0f);
- }
- dial_ghostarc_draw_helpline(angle_ofs + angle_delta, co_outer, color_helpline);
+ const float color_arc_inner[4] = {0.8f, 0.8f, 0.8f, 0.2f};
+ dial_ghostarc_draw(angle_ofs, angle_delta, arc_inner_factor, color_arc_inner);
+
+ float line_width = (draw_options & ED_GIZMO_DIAL_DRAW_FLAG_ANGLE_VALUE) ? 3.0f : 1.0f;
+ dial_ghostarc_draw_helpline(angle_ofs, co_outer, color_helpline, 1.0f);
+ dial_ghostarc_draw_helpline(angle_ofs + angle_delta, co_outer, color_helpline, line_width);
}
static void dial_draw_intern(
diff --git a/source/blender/editors/gizmo_library/gizmo_types/move3d_gizmo.c b/source/blender/editors/gizmo_library/gizmo_types/move3d_gizmo.c
index 4049a3b9dcb..db57a33f543 100644
--- a/source/blender/editors/gizmo_library/gizmo_types/move3d_gizmo.c
+++ b/source/blender/editors/gizmo_library/gizmo_types/move3d_gizmo.c
@@ -106,16 +106,21 @@ static void move_geom_draw(const wmGizmo *gz,
wm_gizmo_geometryinfo_draw(&wm_gizmo_geom_data_move3d, select);
#else
const int draw_style = RNA_enum_get(gz->ptr, "draw_style");
- const bool filled = ((draw_options & (select ? (ED_GIZMO_MOVE_DRAW_FLAG_FILL |
+ const bool filled = (draw_style != ED_GIZMO_MOVE_STYLE_CROSS_2D) &&
+ ((draw_options & (select ? (ED_GIZMO_MOVE_DRAW_FLAG_FILL |
ED_GIZMO_MOVE_DRAW_FLAG_FILL_SELECT) :
ED_GIZMO_MOVE_DRAW_FLAG_FILL)));
- GPU_line_width(gz->line_width);
-
GPUVertFormat *format = immVertexFormat();
uint pos = GPU_vertformat_attr_add(format, "pos", GPU_COMP_F32, 2, GPU_FETCH_FLOAT);
- immBindBuiltinProgram(GPU_SHADER_3D_UNIFORM_COLOR);
+ immBindBuiltinProgram(filled ? GPU_SHADER_3D_UNIFORM_COLOR :
+ GPU_SHADER_3D_POLYLINE_UNIFORM_COLOR);
+
+ float viewport[4];
+ GPU_viewport_size_get_f(viewport);
+ immUniform2fv("viewportSize", &viewport[2]);
+ immUniform1f("lineWidth", gz->line_width * U.pixelsize);
immUniformColor4fv(color);
@@ -372,12 +377,12 @@ static int gizmo_move_invoke(bContext *C, wmGizmo *gz, const wmEvent *event)
WM_gizmo_calc_matrix_final(gz, inter->init.matrix_final);
if (use_snap) {
- ScrArea *sa = CTX_wm_area(C);
- if (sa) {
- switch (sa->spacetype) {
+ ScrArea *area = CTX_wm_area(C);
+ if (area) {
+ switch (area->spacetype) {
case SPACE_VIEW3D: {
inter->snap_context_v3d = ED_transform_snap_object_context_create_view3d(
- CTX_data_main(C), CTX_data_scene(C), 0, CTX_wm_region(C), CTX_wm_view3d(C));
+ CTX_data_scene(C), 0, CTX_wm_region(C), CTX_wm_view3d(C));
break;
}
default:
diff --git a/source/blender/editors/gizmo_library/gizmo_types/snap3d_gizmo.c b/source/blender/editors/gizmo_library/gizmo_types/snap3d_gizmo.c
new file mode 100644
index 00000000000..a3921791427
--- /dev/null
+++ b/source/blender/editors/gizmo_library/gizmo_types/snap3d_gizmo.c
@@ -0,0 +1,560 @@
+/*
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * The Original Code is Copyright (C) 2020 Blender Foundation.
+ * All rights reserved.
+ */
+
+/** \file snap3d_gizmo.c
+ * \ingroup edgizmolib
+ *
+ * \name Snap Gizmo
+ *
+ * 3D Gizmo
+ *
+ * \brief Snap gizmo which exposes the location, normal and index in the props.
+ */
+
+#include "BLI_math.h"
+
+#include "DNA_scene_types.h"
+
+#include "BKE_context.h"
+
+#include "GPU_immediate.h"
+#include "GPU_state.h"
+
+#include "ED_gizmo_library.h"
+#include "ED_screen.h"
+#include "ED_transform_snap_object_context.h"
+#include "ED_view3d.h"
+
+#include "UI_resources.h" /* icons */
+
+#include "RNA_access.h"
+#include "RNA_define.h"
+
+#include "DEG_depsgraph_query.h"
+
+#include "WM_api.h"
+#include "WM_types.h"
+#include "wm.h"
+
+/* own includes */
+#include "../gizmo_geometry.h"
+#include "../gizmo_library_intern.h"
+
+typedef struct SnapGizmo3D {
+ wmGizmo gizmo;
+ PropertyRNA *prop_prevpoint;
+ PropertyRNA *prop_location;
+ PropertyRNA *prop_normal;
+ PropertyRNA *prop_elem_index;
+ PropertyRNA *prop_snap_force;
+
+ /* We could have other snap contexts, for now only support 3D view. */
+ SnapObjectContext *snap_context_v3d;
+ int mval[2];
+
+#ifdef USE_SNAP_DETECT_FROM_KEYMAP_HACK
+ wmKeyMap *keymap;
+ int snap_on;
+ bool invert_snap;
+#endif
+ int use_snap_override;
+ short snap_elem;
+} SnapGizmo3D;
+
+#ifdef USE_SNAP_DETECT_FROM_KEYMAP_HACK
+static bool invert_snap(const wmGizmo *gz, const wmWindowManager *wm, const wmEvent *event)
+{
+ SnapGizmo3D *gizmo_snap = (SnapGizmo3D *)gz;
+ wmKeyMap *keymap = WM_keymap_active(wm, gizmo_snap->keymap);
+
+ const int snap_on = gizmo_snap->snap_on;
+ for (wmKeyMapItem *kmi = keymap->items.first; kmi; kmi = kmi->next) {
+ if (kmi->flag & KMI_INACTIVE) {
+ continue;
+ }
+
+ if (kmi->propvalue == snap_on) {
+ if ((ELEM(kmi->type, EVT_LEFTCTRLKEY, EVT_RIGHTCTRLKEY) && event->ctrl) ||
+ (ELEM(kmi->type, EVT_LEFTSHIFTKEY, EVT_RIGHTSHIFTKEY) && event->shift) ||
+ (ELEM(kmi->type, EVT_LEFTALTKEY, EVT_RIGHTALTKEY) && event->alt) ||
+ ((kmi->type == EVT_OSKEY) && event->oskey)) {
+ return true;
+ }
+ }
+ }
+ return false;
+}
+#endif
+
+/* -------------------------------------------------------------------- */
+/** \name ED_gizmo_library specific API
+ * \{ */
+
+void ED_gizmotypes_snap_3d_draw_util(RegionView3D *rv3d,
+ const float loc_prev[3],
+ const float loc_curr[3],
+ const float normal[3],
+ const uchar color_line[4],
+ const uchar color_point[4],
+ const short snap_elem_type)
+{
+ if (!loc_prev && !loc_curr) {
+ return;
+ }
+
+ float view_inv[4][4];
+ copy_m4_m4(view_inv, rv3d->viewinv);
+
+ /* The size of the circle is larger than the vertex size.
+ * This prevents a drawing overlaps the other. */
+ float radius = 2.5f * UI_GetThemeValuef(TH_VERTEX_SIZE);
+ uint pos = GPU_vertformat_attr_add(immVertexFormat(), "pos", GPU_COMP_F32, 3, GPU_FETCH_FLOAT);
+
+ immBindBuiltinProgram(GPU_SHADER_3D_UNIFORM_COLOR);
+
+ if (loc_curr) {
+ immUniformColor4ubv(color_point);
+ imm_drawcircball(loc_curr, ED_view3d_pixel_size(rv3d, loc_curr) * radius, view_inv, pos);
+
+ /* draw normal if needed */
+ if (normal) {
+ immBegin(GPU_PRIM_LINES, 2);
+ immVertex3fv(pos, loc_curr);
+ immVertex3f(pos, loc_curr[0] + normal[0], loc_curr[1] + normal[1], loc_curr[2] + normal[2]);
+ immEnd();
+ }
+ }
+
+ if (loc_prev) {
+ /* Draw an "X" indicating where the previous snap point is.
+ * This is useful for indicating perpendicular snap. */
+
+ /* v1, v2, v3 and v4 indicate the coordinates of the ends of the "X". */
+ float vx[3], vy[3], v1[3], v2[3], v3[3], v4[4];
+
+ /* Multiply by 0.75f so that the final size of the "X" is close to that of
+ * the circle.
+ * (A closer value is 0.7071f, but we don't need to be exact here). */
+ float x_size = 0.75f * radius * ED_view3d_pixel_size(rv3d, loc_prev);
+
+ mul_v3_v3fl(vx, view_inv[0], x_size);
+ mul_v3_v3fl(vy, view_inv[1], x_size);
+
+ add_v3_v3v3(v1, vx, vy);
+ sub_v3_v3v3(v2, vx, vy);
+ negate_v3_v3(v3, v1);
+ negate_v3_v3(v4, v2);
+
+ add_v3_v3(v1, loc_prev);
+ add_v3_v3(v2, loc_prev);
+ add_v3_v3(v3, loc_prev);
+ add_v3_v3(v4, loc_prev);
+
+ immUniformColor4ubv(color_line);
+ immBegin(GPU_PRIM_LINES, 4);
+ immVertex3fv(pos, v3);
+ immVertex3fv(pos, v1);
+ immVertex3fv(pos, v4);
+ immVertex3fv(pos, v2);
+ immEnd();
+
+ if (loc_curr && (snap_elem_type & SCE_SNAP_MODE_EDGE_PERPENDICULAR)) {
+ /* Dashed line. */
+ immUnbindProgram();
+
+ immBindBuiltinProgram(GPU_SHADER_3D_LINE_DASHED_UNIFORM_COLOR);
+ float viewport_size[4];
+ GPU_viewport_size_get_f(viewport_size);
+ immUniform2f("viewport_size", viewport_size[2], viewport_size[3]);
+ immUniform1f("dash_width", 6.0f * U.pixelsize);
+ immUniform1f("dash_factor", 1.0f / 4.0f);
+ immUniformColor4ubv(color_line);
+
+ immBegin(GPU_PRIM_LINES, 2);
+ immVertex3fv(pos, loc_prev);
+ immVertex3fv(pos, loc_curr);
+ immEnd();
+ }
+ }
+
+ immUnbindProgram();
+}
+
+SnapObjectContext *ED_gizmotypes_snap_3d_context_ensure(Scene *scene,
+ const ARegion *region,
+ const View3D *v3d,
+ wmGizmo *gz)
+{
+ SnapGizmo3D *gizmo_snap = (SnapGizmo3D *)gz;
+ if (gizmo_snap->snap_context_v3d == NULL) {
+ gizmo_snap->snap_context_v3d = ED_transform_snap_object_context_create_view3d(
+ scene, 0, region, v3d);
+ }
+ return gizmo_snap->snap_context_v3d;
+}
+
+bool ED_gizmotypes_snap_3d_invert_snap_get(struct wmGizmo *gz)
+{
+ SnapGizmo3D *gizmo_snap = (SnapGizmo3D *)gz;
+ return gizmo_snap->invert_snap;
+}
+void ED_gizmotypes_snap_3d_toggle_set(wmGizmo *gz, bool enable)
+{
+ SnapGizmo3D *gizmo_snap = (SnapGizmo3D *)gz;
+ gizmo_snap->use_snap_override = (int)enable;
+}
+
+void ED_gizmotypes_snap_3d_toggle_clear(wmGizmo *gz)
+{
+ SnapGizmo3D *gizmo_snap = (SnapGizmo3D *)gz;
+ gizmo_snap->use_snap_override = -1;
+}
+
+short ED_gizmotypes_snap_3d_update(wmGizmo *gz,
+ struct Depsgraph *depsgraph,
+ const ARegion *region,
+ const View3D *v3d,
+ const wmWindowManager *wm,
+ const float mval_fl[2],
+ float r_loc[3],
+ float r_nor[3])
+{
+ SnapGizmo3D *gizmo_snap = (SnapGizmo3D *)gz;
+ Scene *scene = DEG_get_input_scene(depsgraph);
+ float co[3], no[3];
+ short snap_elem = 0;
+ int snap_elem_index[3] = {-1, -1, -1};
+ int index = -1;
+
+ if (gizmo_snap->use_snap_override != -1) {
+ if (gizmo_snap->use_snap_override == false) {
+ gizmo_snap->snap_elem = 0;
+ return 0;
+ }
+ }
+
+#ifdef USE_SNAP_DETECT_FROM_KEYMAP_HACK
+ if (wm && wm->winactive) {
+ gizmo_snap->invert_snap = invert_snap(gz, wm, wm->winactive->eventstate);
+ }
+
+ if (gizmo_snap->use_snap_override == -1) {
+ const ToolSettings *ts = scene->toolsettings;
+ if (gizmo_snap->invert_snap != !(ts->snap_flag & SCE_SNAP)) {
+ gizmo_snap->snap_elem = 0;
+ return 0;
+ }
+ }
+#else
+ UNUSED_VARS(wm);
+#endif
+
+ wmGizmoProperty *gz_prop = WM_gizmo_target_property_find(gz, "snap_elements");
+ int snap_elements = RNA_property_enum_get(&gz_prop->ptr, gz_prop->prop);
+ if (gz_prop->prop != gizmo_snap->prop_snap_force) {
+ int snap_elements_force = RNA_property_enum_get(gz->ptr, gizmo_snap->prop_snap_force);
+ snap_elements |= snap_elements_force;
+ }
+ snap_elements &= (SCE_SNAP_MODE_VERTEX | SCE_SNAP_MODE_EDGE | SCE_SNAP_MODE_FACE |
+ SCE_SNAP_MODE_EDGE_MIDPOINT | SCE_SNAP_MODE_EDGE_PERPENDICULAR);
+
+ if (snap_elements) {
+ float prev_co[3] = {0.0f};
+ if (RNA_property_is_set(gz->ptr, gizmo_snap->prop_prevpoint)) {
+ RNA_property_float_get_array(gz->ptr, gizmo_snap->prop_prevpoint, prev_co);
+ }
+ else {
+ snap_elements &= ~SCE_SNAP_MODE_EDGE_PERPENDICULAR;
+ }
+
+ float dist_px = 12.0f * U.pixelsize;
+
+ ED_gizmotypes_snap_3d_context_ensure(scene, region, v3d, gz);
+ snap_elem = ED_transform_snap_object_project_view3d_ex(gizmo_snap->snap_context_v3d,
+ depsgraph,
+ snap_elements,
+ &(const struct SnapObjectParams){
+ .snap_select = SNAP_ALL,
+ .use_object_edit_cage = true,
+ .use_occlusion_test = true,
+ },
+ mval_fl,
+ prev_co,
+ &dist_px,
+ co,
+ no,
+ &index,
+ NULL,
+ NULL);
+ }
+
+ if (snap_elem == 0) {
+ RegionView3D *rv3d = region->regiondata;
+ ED_view3d_win_to_3d(v3d, region, rv3d->ofs, mval_fl, co);
+ zero_v3(no);
+ }
+ else if (snap_elem == SCE_SNAP_MODE_VERTEX) {
+ snap_elem_index[0] = index;
+ }
+ else if (snap_elem &
+ (SCE_SNAP_MODE_EDGE | SCE_SNAP_MODE_EDGE_MIDPOINT | SCE_SNAP_MODE_EDGE_PERPENDICULAR)) {
+ snap_elem_index[1] = index;
+ }
+ else if (snap_elem == SCE_SNAP_MODE_FACE) {
+ snap_elem_index[2] = index;
+ }
+
+ gizmo_snap->snap_elem = snap_elem;
+ RNA_property_float_set_array(gz->ptr, gizmo_snap->prop_location, co);
+ RNA_property_float_set_array(gz->ptr, gizmo_snap->prop_normal, no);
+ RNA_property_int_set_array(gz->ptr, gizmo_snap->prop_elem_index, snap_elem_index);
+
+ if (r_loc) {
+ copy_v3_v3(r_loc, co);
+ }
+ if (r_nor) {
+ copy_v3_v3(r_nor, no);
+ }
+
+ return snap_elem;
+}
+
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name GIZMO_GT_snap_3d
+ * \{ */
+
+static void gizmo_snap_setup(wmGizmo *gz)
+{
+ SnapGizmo3D *gizmo_snap = (SnapGizmo3D *)gz;
+
+ /* For quick access to the props. */
+ gizmo_snap->prop_prevpoint = RNA_struct_find_property(gz->ptr, "prev_point");
+ gizmo_snap->prop_location = RNA_struct_find_property(gz->ptr, "location");
+ gizmo_snap->prop_normal = RNA_struct_find_property(gz->ptr, "normal");
+ gizmo_snap->prop_elem_index = RNA_struct_find_property(gz->ptr, "snap_elem_index");
+ gizmo_snap->prop_snap_force = RNA_struct_find_property(gz->ptr, "snap_elements_force");
+
+ gizmo_snap->use_snap_override = -1;
+
+ /* Prop fallback. */
+ WM_gizmo_target_property_def_rna(gz, "snap_elements", gz->ptr, "snap_elements_force", -1);
+
+ /* Flags. */
+ gz->flag |= WM_GIZMO_NO_TOOLTIP;
+}
+
+static void gizmo_snap_draw(const bContext *C, wmGizmo *gz)
+{
+ SnapGizmo3D *gizmo_snap = (SnapGizmo3D *)gz;
+ if (gizmo_snap->snap_elem == 0) {
+ return;
+ }
+
+ ARegion *region = CTX_wm_region(C);
+ RegionView3D *rv3d = region->regiondata;
+
+ /* Ideally, we shouldn't assign values here.
+ * But `test_select` is not called during navigation.
+ * And `snap_elem` is not really useful in this case. */
+ if ((rv3d->rflag & RV3D_NAVIGATING) ||
+ (!(gz->state & WM_GIZMO_STATE_HIGHLIGHT) && !wm_gizmomap_modal_get(region->gizmo_map))) {
+ gizmo_snap->snap_elem = 0;
+ return;
+ }
+
+ float location[3], prev_point_stack[3], *prev_point = NULL;
+ uchar color_line[4], color_point[4];
+
+ RNA_property_float_get_array(gz->ptr, gizmo_snap->prop_location, location);
+
+ UI_GetThemeColor3ubv(TH_TRANSFORM, color_line);
+ color_line[3] = 128;
+
+ rgba_float_to_uchar(color_point, gz->color);
+
+ if (RNA_property_is_set(gz->ptr, gizmo_snap->prop_prevpoint)) {
+ RNA_property_float_get_array(gz->ptr, gizmo_snap->prop_prevpoint, prev_point_stack);
+ prev_point = prev_point_stack;
+ }
+
+ GPU_line_smooth(false);
+
+ GPU_line_width(1.0f);
+ ED_gizmotypes_snap_3d_draw_util(
+ rv3d, prev_point, location, NULL, color_line, color_point, gizmo_snap->snap_elem);
+}
+
+static int gizmo_snap_test_select(bContext *C, wmGizmo *gz, const int mval[2])
+{
+ SnapGizmo3D *gizmo_snap = (SnapGizmo3D *)gz;
+
+#ifdef USE_SNAP_DETECT_FROM_KEYMAP_HACK
+ wmWindowManager *wm = CTX_wm_manager(C);
+ if (gizmo_snap->keymap == NULL) {
+ gizmo_snap->keymap = WM_modalkeymap_find(wm->defaultconf, "Generic Gizmo Tweak Modal Map");
+ RNA_enum_value_from_id(gizmo_snap->keymap->modal_items, "SNAP_ON", &gizmo_snap->snap_on);
+ }
+
+ const bool invert = wm->winactive ? invert_snap(gz, wm, wm->winactive->eventstate) : false;
+ if (gizmo_snap->invert_snap == invert && gizmo_snap->mval[0] == mval[0] &&
+ gizmo_snap->mval[1] == mval[1]) {
+ /* Performance, do not update. */
+ return gizmo_snap->snap_elem ? 0 : -1;
+ }
+
+ gizmo_snap->invert_snap = invert;
+#else
+ if (gizmo_snap->mval[0] == mval[0] && gizmo_snap->mval[1] == mval[1]) {
+ /* Performance, do not update. */
+ return gizmo_snap->snap_elem ? 0 : -1;
+ }
+#endif
+ copy_v2_v2_int(gizmo_snap->mval, mval);
+
+ ARegion *region = CTX_wm_region(C);
+ View3D *v3d = CTX_wm_view3d(C);
+ const float mval_fl[2] = {UNPACK2(mval)};
+ short snap_elem = ED_gizmotypes_snap_3d_update(
+ gz, CTX_data_ensure_evaluated_depsgraph(C), region, v3d, NULL, mval_fl, NULL, NULL);
+
+ if (snap_elem) {
+ ED_region_tag_redraw_editor_overlays(region);
+ return 0;
+ }
+
+ return -1;
+}
+
+static int gizmo_snap_modal(bContext *UNUSED(C),
+ wmGizmo *UNUSED(gz),
+ const wmEvent *UNUSED(event),
+ eWM_GizmoFlagTweak UNUSED(tweak_flag))
+{
+ return OPERATOR_RUNNING_MODAL;
+}
+
+static int gizmo_snap_invoke(bContext *UNUSED(C),
+ wmGizmo *UNUSED(gz),
+ const wmEvent *UNUSED(event))
+{
+ return OPERATOR_RUNNING_MODAL;
+}
+
+static void gizmo_snap_free(wmGizmo *gz)
+{
+ SnapGizmo3D *gizmo_snap = (SnapGizmo3D *)gz;
+ if (gizmo_snap->snap_context_v3d) {
+ ED_transform_snap_object_context_destroy(gizmo_snap->snap_context_v3d);
+ gizmo_snap->snap_context_v3d = NULL;
+ }
+}
+
+static void GIZMO_GT_snap_3d(wmGizmoType *gzt)
+{
+ /* identifiers */
+ gzt->idname = "GIZMO_GT_snap_3d";
+
+ /* api callbacks */
+ gzt->setup = gizmo_snap_setup;
+ gzt->draw = gizmo_snap_draw;
+ gzt->test_select = gizmo_snap_test_select;
+ gzt->modal = gizmo_snap_modal;
+ gzt->invoke = gizmo_snap_invoke;
+ gzt->free = gizmo_snap_free;
+
+ gzt->struct_size = sizeof(SnapGizmo3D);
+
+ const EnumPropertyItem *rna_enum_snap_element_items;
+ {
+ /* Get Snap Element Items enum. */
+ bool free;
+ PointerRNA toolsettings_ptr;
+ RNA_pointer_create(NULL, &RNA_ToolSettings, NULL, &toolsettings_ptr);
+ PropertyRNA *prop = RNA_struct_find_property(&toolsettings_ptr, "snap_elements");
+ RNA_property_enum_items(
+ NULL, &toolsettings_ptr, prop, &rna_enum_snap_element_items, NULL, &free);
+
+ BLI_assert(free == false);
+ }
+
+ /* Setup. */
+ RNA_def_enum_flag(gzt->srna,
+ "snap_elements_force",
+ rna_enum_snap_element_items,
+ SCE_SNAP_MODE_VERTEX | SCE_SNAP_MODE_EDGE | SCE_SNAP_MODE_FACE,
+ "Snap Elements",
+ "");
+
+ RNA_def_float_vector(gzt->srna,
+ "prev_point",
+ 3,
+ NULL,
+ FLT_MIN,
+ FLT_MAX,
+ "Previous Point",
+ "Point that defines the location of the perpendicular snap",
+ FLT_MIN,
+ FLT_MAX);
+
+ /* Returns. */
+ RNA_def_float_vector(gzt->srna,
+ "location",
+ 3,
+ NULL,
+ FLT_MIN,
+ FLT_MAX,
+ "Location",
+ "Snap Point Location",
+ FLT_MIN,
+ FLT_MAX);
+
+ RNA_def_float_vector(gzt->srna,
+ "normal",
+ 3,
+ NULL,
+ FLT_MIN,
+ FLT_MAX,
+ "Normal",
+ "Snap Point Normal",
+ FLT_MIN,
+ FLT_MAX);
+
+ RNA_def_int_vector(gzt->srna,
+ "snap_elem_index",
+ 3,
+ NULL,
+ INT_MIN,
+ INT_MAX,
+ "Snap Element",
+ "Array index of face, edge and vert snapped",
+ INT_MIN,
+ INT_MAX);
+
+ /* Read/Write. */
+ WM_gizmotype_target_property_def(gzt, "snap_elements", PROP_ENUM, 1);
+}
+
+void ED_gizmotypes_snap_3d(void)
+{
+ WM_gizmotype_append(GIZMO_GT_snap_3d);
+}
+
+/** \} */
diff --git a/source/blender/editors/gpencil/annotate_draw.c b/source/blender/editors/gpencil/annotate_draw.c
index 5c396ca9041..22df7bbbf31 100644
--- a/source/blender/editors/gpencil/annotate_draw.c
+++ b/source/blender/editors/gpencil/annotate_draw.c
@@ -90,14 +90,54 @@ typedef enum eDrawStrokeFlags {
/* ----- Tool Buffer Drawing ------ */
+static void annotation_draw_stroke_arrow_buffer(uint pos,
+ const float *corner_point,
+ const float *arrow_coords,
+ const int arrow_style)
+{
+ immBeginAtMost(GPU_PRIM_LINE_STRIP, arrow_style);
+
+ switch (arrow_style) {
+ case GP_STROKE_ARROWSTYLE_SEGMENT:
+ immVertex2f(pos, arrow_coords[0], arrow_coords[1]);
+ immVertex2f(pos, arrow_coords[2], arrow_coords[3]);
+ break;
+ case GP_STROKE_ARROWSTYLE_CLOSED:
+ immVertex2f(pos, arrow_coords[0], arrow_coords[1]);
+ immVertex2f(pos, arrow_coords[2], arrow_coords[3]);
+ immVertex2f(pos, arrow_coords[4], arrow_coords[5]);
+ immVertex2f(pos, arrow_coords[0], arrow_coords[1]);
+ break;
+ case GP_STROKE_ARROWSTYLE_OPEN:
+ immVertex2f(pos, arrow_coords[0], arrow_coords[1]);
+ immVertex2f(pos, corner_point[0], corner_point[1]);
+ immVertex2f(pos, arrow_coords[2], arrow_coords[3]);
+ break;
+ case GP_STROKE_ARROWSTYLE_SQUARE:
+ immVertex2f(pos, corner_point[0], corner_point[1]);
+ immVertex2f(pos, arrow_coords[0], arrow_coords[1]);
+ immVertex2f(pos, arrow_coords[4], arrow_coords[5]);
+ immVertex2f(pos, arrow_coords[6], arrow_coords[7]);
+ immVertex2f(pos, arrow_coords[2], arrow_coords[3]);
+ immVertex2f(pos, corner_point[0], corner_point[1]);
+ break;
+ default:
+ break;
+ }
+ immEnd();
+}
+
/* draw stroke defined in buffer (simple ogl lines/points for now, as dotted lines) */
-static void annotation_draw_stroke_buffer(const tGPspoint *points,
- int totpoints,
+static void annotation_draw_stroke_buffer(bGPdata *gps,
short thickness,
short dflag,
- short sflag,
const float ink[4])
{
+ bGPdata_Runtime runtime = gps->runtime;
+ const tGPspoint *points = runtime.sbuffer;
+ int totpoints = runtime.sbuffer_used;
+ short sflag = runtime.sbuffer_sflag;
+
int draw_points = 0;
/* error checking */
@@ -176,6 +216,26 @@ static void annotation_draw_stroke_buffer(const tGPspoint *points,
}
immEnd();
+
+ /* Draw arrow stroke. */
+ if (totpoints > 1) {
+ /* Draw ending arrow stroke. */
+ if ((sflag & GP_STROKE_USE_ARROW_END) &&
+ (runtime.arrow_end_style != GP_STROKE_ARROWSTYLE_NONE)) {
+ float end[2];
+ copy_v2_fl2(end, points[1].x, points[1].y);
+ annotation_draw_stroke_arrow_buffer(pos, end, runtime.arrow_end, runtime.arrow_end_style);
+ }
+ /* Draw starting arrow stroke. */
+ if ((sflag & GP_STROKE_USE_ARROW_START) &&
+ (runtime.arrow_start_style != GP_STROKE_ARROWSTYLE_NONE)) {
+ float start[2];
+ copy_v2_fl2(start, points[0].x, points[0].y);
+ annotation_draw_stroke_arrow_buffer(
+ pos, start, runtime.arrow_start, runtime.arrow_start_style);
+ }
+ }
+
immUnbindProgram();
}
@@ -209,7 +269,6 @@ static void annotation_calc_2d_stroke_fxy(
/* draw a given stroke - just a single dot (only one point) */
static void annotation_draw_stroke_point(const bGPDspoint *points,
short thickness,
- short UNUSED(dflag),
short sflag,
int offsx,
int offsy,
@@ -252,12 +311,8 @@ static void annotation_draw_stroke_point(const bGPDspoint *points,
}
/* draw a given stroke in 3d (i.e. in 3d-space), using simple ogl lines */
-static void annotation_draw_stroke_3d(const bGPDspoint *points,
- int totpoints,
- short thickness,
- short UNUSED(sflag),
- const float ink[4],
- bool cyclic)
+static void annotation_draw_stroke_3d(
+ const bGPDspoint *points, int totpoints, short thickness, const float ink[4], bool cyclic)
{
float curpressure = points[0].pressure;
float cyclic_fpt[3];
@@ -333,13 +388,10 @@ static void annotation_draw_stroke_3d(const bGPDspoint *points,
immUnbindProgram();
}
-/* ----- Fancy 2D-Stroke Drawing ------ */
-
-/* draw a given stroke in 2d */
+/* Draw a given stroke in 2d. */
static void annotation_draw_stroke_2d(const bGPDspoint *points,
int totpoints,
short thickness_s,
- short dflag,
short sflag,
int offsx,
int offsy,
@@ -347,167 +399,84 @@ static void annotation_draw_stroke_2d(const bGPDspoint *points,
int winy,
const float ink[4])
{
- /* otherwise thickness is twice that of the 3D view */
- float thickness = (float)thickness_s * 0.5f;
-
- /* strokes in Image Editor need a scale factor, since units there are not pixels! */
- float scalefac = 1.0f;
- if ((dflag & GP_DRAWDATA_IEDITHACK) && (dflag & GP_DRAWDATA_ONLYV2D)) {
- scalefac = 0.001f;
+ if (totpoints == 0) {
+ return;
}
+ float thickness = (float)thickness_s;
- /* Tessellation code - draw stroke as series of connected quads
- * (triangle strips in fact) with connection edges rotated to minimize shrinking artifacts,
- * and rounded endcaps.
- */
- {
- const bGPDspoint *pt1, *pt2;
- float s0[2], s1[2]; /* segment 'center' points */
- float pm[2]; /* normal from previous segment. */
- int i;
+ GPUVertFormat *format = immVertexFormat();
+ uint pos = GPU_vertformat_attr_add(format, "pos", GPU_COMP_F32, 2, GPU_FETCH_FLOAT);
+
+ const bGPDspoint *pt;
+ const bGPDspoint *pt_prev;
+ int draw_points = 0;
+ float co[2];
+ float oldpressure = points[0].pressure;
+ if (totpoints == 1) {
+ /* if drawing a single point, draw it larger */
+ GPU_point_size((float)(thickness + 2) * points->pressure);
+ immBindBuiltinProgram(GPU_SHADER_3D_POINT_UNIFORM_SIZE_UNIFORM_COLOR_AA);
+ immUniformColor3fvAlpha(ink, ink[3]);
+ immBegin(GPU_PRIM_POINTS, 1);
- GPUVertFormat *format = immVertexFormat();
- uint pos = GPU_vertformat_attr_add(format, "pos", GPU_COMP_F32, 2, GPU_FETCH_FLOAT);
+ annotation_calc_2d_stroke_fxy(&points->x, sflag, offsx, offsy, winx, winy, co);
+ immVertex2fv(pos, co);
+ }
+ else {
+ /* draw stroke curve */
+ GPU_line_width(max_ff(oldpressure * thickness, 1.0));
immBindBuiltinProgram(GPU_SHADER_2D_UNIFORM_COLOR);
immUniformColor3fvAlpha(ink, ink[3]);
- immBegin(GPU_PRIM_TRI_STRIP, totpoints * 2 + 4);
-
- /* get x and y coordinates from first point */
- annotation_calc_2d_stroke_fxy(&points->x, sflag, offsx, offsy, winx, winy, s0);
-
- for (i = 0, pt1 = points, pt2 = points + 1; i < (totpoints - 1); i++, pt1++, pt2++) {
- float t0[2], t1[2]; /* tessellated coordinates */
- float m1[2], m2[2]; /* gradient and normal */
- float mt[2], sc[2]; /* gradient for thickness, point for end-cap */
- float pthick; /* thickness at segment point */
-
- /* Get x and y coordinates from point2
- * (point1 has already been computed in previous iteration). */
- annotation_calc_2d_stroke_fxy(&pt2->x, sflag, offsx, offsy, winx, winy, s1);
-
- /* calculate gradient and normal - 'angle'=(ny/nx) */
- m1[1] = s1[1] - s0[1];
- m1[0] = s1[0] - s0[0];
- normalize_v2(m1);
- m2[1] = -m1[0];
- m2[0] = m1[1];
-
- /* always use pressure from first point here */
- pthick = (pt1->pressure * thickness * scalefac);
-
- /* if the first segment, start of segment is segment's normal */
- if (i == 0) {
- /* draw start cap first
- * - make points slightly closer to center (about halfway across)
- */
- mt[0] = m2[0] * pthick * 0.5f;
- mt[1] = m2[1] * pthick * 0.5f;
- sc[0] = s0[0] - (m1[0] * pthick * 0.75f);
- sc[1] = s0[1] - (m1[1] * pthick * 0.75f);
-
- t0[0] = sc[0] - mt[0];
- t0[1] = sc[1] - mt[1];
- t1[0] = sc[0] + mt[0];
- t1[1] = sc[1] + mt[1];
-
- /* First two points of cap. */
- immVertex2fv(pos, t0);
- immVertex2fv(pos, t1);
-
- /* calculate points for start of segment */
- mt[0] = m2[0] * pthick;
- mt[1] = m2[1] * pthick;
-
- t0[0] = s0[0] - mt[0];
- t0[1] = s0[1] - mt[1];
- t1[0] = s0[0] + mt[0];
- t1[1] = s0[1] + mt[1];
-
- /* Last two points of start cap (and first two points of first segment). */
- immVertex2fv(pos, t0);
- immVertex2fv(pos, t1);
- }
- /* if not the first segment, use bisector of angle between segments */
- else {
- float mb[2]; /* bisector normal */
- float athick, dfac; /* actual thickness, difference between thicknesses */
-
- /* calculate gradient of bisector (as average of normals) */
- mb[0] = (pm[0] + m2[0]) / 2;
- mb[1] = (pm[1] + m2[1]) / 2;
- normalize_v2(mb);
-
- /* calculate gradient to apply
- * - as basis, use just pthick * bisector gradient
- * - if cross-section not as thick as it should be, add extra padding to fix it
- */
- mt[0] = mb[0] * pthick;
- mt[1] = mb[1] * pthick;
- athick = len_v2(mt);
- dfac = pthick - (athick * 2);
-
- if (((athick * 2.0f) < pthick) && (IS_EQF(athick, pthick) == 0)) {
- mt[0] += (mb[0] * dfac);
- mt[1] += (mb[1] * dfac);
+
+ immBeginAtMost(GPU_PRIM_LINE_STRIP, totpoints);
+
+ for (int i = 0; i < totpoints; i++) {
+ pt = &points[i];
+ /* If there was a significant pressure change,
+ * stop the curve, change the thickness of the stroke,
+ * and continue drawing again (since line-width cannot change in middle of GL_LINE_STRIP).
+ */
+ if (fabsf(pt->pressure - oldpressure) > 0.2f) {
+ /* need to have 2 points to avoid immEnd assert error */
+ if (draw_points < 2) {
+ pt_prev = &points[i - 1];
+ annotation_calc_2d_stroke_fxy(&pt_prev->x, sflag, offsx, offsy, winx, winy, co);
+ immVertex2fv(pos, co);
}
- /* calculate points for start of segment */
- t0[0] = s0[0] - mt[0];
- t0[1] = s0[1] - mt[1];
- t1[0] = s0[0] + mt[0];
- t1[1] = s0[1] + mt[1];
+ immEnd();
+ draw_points = 0;
- /* Last two points of previous segment, and first two points of current segment. */
- immVertex2fv(pos, t0);
- immVertex2fv(pos, t1);
- }
+ GPU_line_width(max_ff(pt->pressure * thickness, 1.0f));
+ immBeginAtMost(GPU_PRIM_LINE_STRIP, totpoints - i + 1);
- /* if last segment, also draw end of segment (defined as segment's normal) */
- if (i == totpoints - 2) {
- /* for once, we use second point's pressure (otherwise it won't be drawn) */
- pthick = (pt2->pressure * thickness * scalefac);
-
- /* calculate points for end of segment */
- mt[0] = m2[0] * pthick;
- mt[1] = m2[1] * pthick;
-
- t0[0] = s1[0] - mt[0];
- t0[1] = s1[1] - mt[1];
- t1[0] = s1[0] + mt[0];
- t1[1] = s1[1] + mt[1];
-
- /* Last two points of last segment (and first two points of end cap). */
- immVertex2fv(pos, t0);
- immVertex2fv(pos, t1);
-
- /* draw end cap as last step
- * - make points slightly closer to center (about halfway across)
- */
- mt[0] = m2[0] * pthick * 0.5f;
- mt[1] = m2[1] * pthick * 0.5f;
- sc[0] = s1[0] + (m1[0] * pthick * 0.75f);
- sc[1] = s1[1] + (m1[1] * pthick * 0.75f);
-
- t0[0] = sc[0] - mt[0];
- t0[1] = sc[1] - mt[1];
- t1[0] = sc[0] + mt[0];
- t1[1] = sc[1] + mt[1];
-
- /* Last two points of end cap. */
- immVertex2fv(pos, t0);
- immVertex2fv(pos, t1);
+ /* need to roll-back one point to ensure that there are no gaps in the stroke */
+ if (i != 0) {
+ pt_prev = &points[i - 1];
+ annotation_calc_2d_stroke_fxy(&pt_prev->x, sflag, offsx, offsy, winx, winy, co);
+ immVertex2fv(pos, co);
+ draw_points++;
+ }
+
+ oldpressure = pt->pressure; /* reset our threshold */
}
- /* store computed point2 coordinates as point1 ones of next segment. */
- copy_v2_v2(s0, s1);
- /* store stroke's 'natural' normal for next stroke to use */
- copy_v2_v2(pm, m2);
+ /* now the point we want */
+ annotation_calc_2d_stroke_fxy(&pt->x, sflag, offsx, offsy, winx, winy, co);
+ immVertex2fv(pos, co);
+ draw_points++;
+ }
+ /* need to have 2 points to avoid immEnd assert error */
+ if (draw_points < 2) {
+ pt_prev = &points[0];
+ annotation_calc_2d_stroke_fxy(&pt_prev->x, sflag, offsx, offsy, winx, winy, co);
+ immVertex2fv(pos, co);
}
-
- immEnd();
- immUnbindProgram();
}
+
+ immEnd();
+ immUnbindProgram();
}
/* ----- Strokes Drawing ------ */
@@ -550,9 +519,7 @@ static bool annotation_can_draw_stroke(const bGPDstroke *gps, const int dflag)
}
/* draw a set of strokes */
-static void annotation_draw_strokes(bGPdata *UNUSED(gpd),
- bGPDlayer *UNUSED(gpl),
- const bGPDframe *gpf,
+static void annotation_draw_strokes(const bGPDframe *gpf,
int offsx,
int offsy,
int winx,
@@ -587,11 +554,11 @@ static void annotation_draw_strokes(bGPdata *UNUSED(gpd),
/* 3D Lines - OpenGL primitives-based */
if (gps->totpoints == 1) {
annotation_draw_stroke_point(
- gps->points, lthick, dflag, gps->flag, offsx, offsy, winx, winy, color);
+ gps->points, lthick, gps->flag, offsx, offsy, winx, winy, color);
}
else {
annotation_draw_stroke_3d(
- gps->points, gps->totpoints, lthick, gps->flag, color, gps->flag & GP_STROKE_CYCLIC);
+ gps->points, gps->totpoints, lthick, color, gps->flag & GP_STROKE_CYCLIC);
}
if (no_xray) {
@@ -605,164 +572,22 @@ static void annotation_draw_strokes(bGPdata *UNUSED(gpd),
/* 2D Strokes... */
if (gps->totpoints == 1) {
annotation_draw_stroke_point(
- gps->points, lthick, dflag, gps->flag, offsx, offsy, winx, winy, color);
- }
- else {
- annotation_draw_stroke_2d(gps->points,
- gps->totpoints,
- lthick,
- dflag,
- gps->flag,
- offsx,
- offsy,
- winx,
- winy,
- color);
- }
- }
- }
-
- GPU_program_point_size(false);
-}
-
-/* Draw selected verts for strokes being edited */
-static void annotation_draw_strokes_edit(bGPdata *UNUSED(gpd),
- bGPDlayer *gpl,
- const bGPDframe *gpf,
- int offsx,
- int offsy,
- int winx,
- int winy,
- short dflag,
- short UNUSED(lflag),
- float alpha)
-{
- /* if alpha 0 do not draw */
- if (alpha == 0.0f) {
- return;
- }
-
- const bool no_xray = (dflag & GP_DRAWDATA_NO_XRAY) != 0;
- int mask_orig = 0;
-
- /* set up depth masks... */
- if (dflag & GP_DRAWDATA_ONLY3D) {
- if (no_xray) {
- glGetIntegerv(GL_DEPTH_WRITEMASK, &mask_orig);
- glDepthMask(0);
- GPU_depth_test(true);
-
- /* first arg is normally rv3d->dist, but this isn't
- * available here and seems to work quite well without */
- bglPolygonOffset(1.0f, 1.0f);
- }
- }
-
- GPU_program_point_size(true);
-
- /* draw stroke verts */
- LISTBASE_FOREACH (bGPDstroke *, gps, &gpf->strokes) {
- /* check if stroke can be drawn */
- if (annotation_can_draw_stroke(gps, dflag) == false) {
- continue;
- }
-
- /* Optimization: only draw points for selected strokes
- * We assume that selected points can only occur in
- * strokes that are selected too.
- */
- if ((gps->flag & GP_STROKE_SELECT) == 0) {
- continue;
- }
-
- /* Get size of verts:
- * - The selected state needs to be larger than the unselected state so that
- * they stand out more.
- * - We use the theme setting for size of the unselected verts
- */
- float bsize = UI_GetThemeValuef(TH_GP_VERTEX_SIZE);
- float vsize;
- if ((int)bsize > 8) {
- vsize = 10.0f;
- bsize = 8.0f;
- }
- else {
- vsize = bsize + 2;
- }
-
- /* Why? */
- UNUSED_VARS(vsize);
-
- float selectColor[4];
- UI_GetThemeColor3fv(TH_GP_VERTEX_SELECT, selectColor);
- selectColor[3] = alpha;
-
- GPUVertFormat *format = immVertexFormat();
- uint pos; /* specified later */
- uint size = GPU_vertformat_attr_add(format, "size", GPU_COMP_F32, 1, GPU_FETCH_FLOAT);
- uint color = GPU_vertformat_attr_add(format, "color", GPU_COMP_F32, 3, GPU_FETCH_FLOAT);
-
- if (gps->flag & GP_STROKE_3DSPACE) {
- pos = GPU_vertformat_attr_add(format, "pos", GPU_COMP_F32, 3, GPU_FETCH_FLOAT);
- immBindBuiltinProgram(GPU_SHADER_3D_POINT_VARYING_SIZE_VARYING_COLOR);
- }
- else {
- pos = GPU_vertformat_attr_add(format, "pos", GPU_COMP_F32, 2, GPU_FETCH_FLOAT);
- immBindBuiltinProgram(GPU_SHADER_2D_POINT_VARYING_SIZE_VARYING_COLOR);
- }
-
- immBegin(GPU_PRIM_POINTS, gps->totpoints);
-
- /* Draw all the stroke points (selected or not) */
- bGPDspoint *pt = gps->points;
- for (int i = 0; i < gps->totpoints; i++, pt++) {
- /* size and color first */
- immAttr3fv(color, gpl->color);
- immAttr1f(size, bsize);
-
- /* then position */
- if (gps->flag & GP_STROKE_3DSPACE) {
- immVertex3fv(pos, &pt->x);
+ gps->points, lthick, gps->flag, offsx, offsy, winx, winy, color);
}
else {
- float co[2];
- annotation_calc_2d_stroke_fxy(&pt->x, gps->flag, offsx, offsy, winx, winy, co);
- immVertex2fv(pos, co);
+ annotation_draw_stroke_2d(
+ gps->points, gps->totpoints, lthick, gps->flag, offsx, offsy, winx, winy, color);
}
}
-
- immEnd();
- immUnbindProgram();
}
GPU_program_point_size(false);
-
- /* clear depth mask */
- if (dflag & GP_DRAWDATA_ONLY3D) {
- if (no_xray) {
- glDepthMask(mask_orig);
- GPU_depth_test(false);
-
- bglPolygonOffset(0.0, 0.0);
-#if 0
- glDisable(GL_POLYGON_OFFSET_LINE);
- glPolygonOffset(0, 0);
-#endif
- }
- }
}
/* ----- General Drawing ------ */
/* draw onion-skinning for a layer */
-static void annotation_draw_onionskins(bGPdata *gpd,
- bGPDlayer *gpl,
- bGPDframe *gpf,
- int offsx,
- int offsy,
- int winx,
- int winy,
- int UNUSED(cfra),
- int dflag)
+static void annotation_draw_onionskins(
+ bGPDlayer *gpl, bGPDframe *gpf, int offsx, int offsy, int winx, int winy, int dflag)
{
const float alpha = 1.0f;
float color[4];
@@ -781,8 +606,7 @@ static void annotation_draw_onionskins(bGPdata *gpd,
/* alpha decreases with distance from curframe index */
fac = 1.0f - ((float)(gpf->framenum - gf->framenum) / (float)(gpl->gstep + 1));
color[3] = alpha * fac * 0.66f;
- annotation_draw_strokes(
- gpd, gpl, gf, offsx, offsy, winx, winy, dflag, gpl->thickness, color);
+ annotation_draw_strokes(gf, offsx, offsy, winx, winy, dflag, gpl->thickness, color);
}
else {
break;
@@ -793,8 +617,7 @@ static void annotation_draw_onionskins(bGPdata *gpd,
/* draw the strokes for the ghost frames (at half of the alpha set by user) */
if (gpf->prev) {
color[3] = (alpha / 7);
- annotation_draw_strokes(
- gpd, gpl, gpf->prev, offsx, offsy, winx, winy, dflag, gpl->thickness, color);
+ annotation_draw_strokes(gpf->prev, offsx, offsy, winx, winy, dflag, gpl->thickness, color);
}
}
else {
@@ -815,8 +638,7 @@ static void annotation_draw_onionskins(bGPdata *gpd,
/* alpha decreases with distance from curframe index */
fac = 1.0f - ((float)(gf->framenum - gpf->framenum) / (float)(gpl->gstep_next + 1));
color[3] = alpha * fac * 0.66f;
- annotation_draw_strokes(
- gpd, gpl, gf, offsx, offsy, winx, winy, dflag, gpl->thickness, color);
+ annotation_draw_strokes(gf, offsx, offsy, winx, winy, dflag, gpl->thickness, color);
}
else {
break;
@@ -827,8 +649,7 @@ static void annotation_draw_onionskins(bGPdata *gpd,
/* draw the strokes for the ghost frames (at half of the alpha set by user) */
if (gpf->next) {
color[3] = (alpha / 4);
- annotation_draw_strokes(
- gpd, gpl, gpf->next, offsx, offsy, winx, winy, dflag, gpl->thickness, color);
+ annotation_draw_strokes(gpf->next, offsx, offsy, winx, winy, dflag, gpl->thickness, color);
}
}
else {
@@ -838,7 +659,7 @@ static void annotation_draw_onionskins(bGPdata *gpd,
/* loop over gpencil data layers, drawing them */
static void annotation_draw_data_layers(
- bGPdata *gpd, int offsx, int offsy, int winx, int winy, int cfra, int dflag, float alpha)
+ bGPdata *gpd, int offsx, int offsy, int winx, int winy, int cfra, int dflag)
{
float ink[4];
@@ -875,26 +696,11 @@ static void annotation_draw_data_layers(
/* Draw 'onionskins' (frame left + right) */
if (gpl->onion_flag & GP_LAYER_ONIONSKIN) {
- annotation_draw_onionskins(gpd, gpl, gpf, offsx, offsy, winx, winy, cfra, dflag);
+ annotation_draw_onionskins(gpl, gpf, offsx, offsy, winx, winy, dflag);
}
/* draw the strokes already in active frame */
- annotation_draw_strokes(gpd, gpl, gpf, offsx, offsy, winx, winy, dflag, lthick, ink);
-
- /* Draw verts of selected strokes:
- * - when doing OpenGL renders, we don't want to be showing these, as that ends up flickering
- * - locked layers can't be edited, so there's no point showing these verts
- * as they will have no bearings on what gets edited
- * - only show when in editmode, since operators shouldn't work otherwise
- * (NOTE: doing it this way means that the toggling editmode
- * shows visible change immediately).
- */
- /* XXX: perhaps we don't want to show these when users are drawing... */
- if ((G.f & G_FLAG_RENDER_VIEWPORT) == 0 && (gpl->flag & GP_LAYER_LOCKED) == 0 &&
- (gpd->flag & GP_DATA_STROKE_EDITMODE)) {
- annotation_draw_strokes_edit(
- gpd, gpl, gpf, offsx, offsy, winx, winy, dflag, gpl->flag, alpha);
- }
+ annotation_draw_strokes(gpf, offsx, offsy, winx, winy, dflag, lthick, ink);
/* Check if may need to draw the active stroke cache, only if this layer is the active layer
* that is being edited. (Stroke buffer is currently stored in gp-data)
@@ -907,67 +713,14 @@ static void annotation_draw_data_layers(
* It should also be noted that sbuffer contains temporary point types
* i.e. tGPspoints NOT bGPDspoints
*/
- annotation_draw_stroke_buffer(gpd->runtime.sbuffer,
- gpd->runtime.sbuffer_used,
- lthick,
- dflag,
- gpd->runtime.sbuffer_sflag,
- ink);
+ annotation_draw_stroke_buffer(gpd, lthick, dflag, ink);
}
}
}
-/* draw a short status message in the top-right corner */
-static void annotation_draw_status_text(const bGPdata *gpd, ARegion *region)
-{
-
- /* Cannot draw any status text when drawing OpenGL Renders */
- if (G.f & G_FLAG_RENDER_VIEWPORT) {
- return;
- }
-
- /* Get bounds of region - Necessary to avoid problems with region overlap */
- const rcti *rect = ED_region_visible_rect(region);
-
- /* for now, this should only be used to indicate when we are in stroke editmode */
- if (gpd->flag & GP_DATA_STROKE_EDITMODE) {
- const char *printable = IFACE_("GPencil Stroke Editing");
- float printable_size[2];
-
- int font_id = BLF_default();
-
- BLF_width_and_height(
- font_id, printable, BLF_DRAW_STR_DUMMY_MAX, &printable_size[0], &printable_size[1]);
-
- int xco = (rect->xmax - U.widget_unit) - (int)printable_size[0];
- int yco = (rect->ymax - U.widget_unit);
-
- /* text label */
- UI_FontThemeColor(font_id, TH_TEXT_HI);
-#ifdef WITH_INTERNATIONAL
- BLF_draw_default(xco, yco, 0.0f, printable, BLF_DRAW_STR_DUMMY_MAX);
-#else
- BLF_draw_default_ascii(xco, yco, 0.0f, printable, BLF_DRAW_STR_DUMMY_MAX);
-#endif
-
- /* grease pencil icon... */
- // XXX: is this too intrusive?
- GPU_blend_set_func_separate(
- GPU_SRC_ALPHA, GPU_ONE_MINUS_SRC_ALPHA, GPU_ONE, GPU_ONE_MINUS_SRC_ALPHA);
- GPU_blend(true);
-
- xco -= U.widget_unit;
- yco -= (int)printable_size[1] / 2;
-
- UI_icon_draw(xco, yco, ICON_GREASEPENCIL);
-
- GPU_blend(false);
- }
-}
-
/* draw grease-pencil datablock */
static void annotation_draw_data(
- bGPdata *gpd, int offsx, int offsy, int winx, int winy, int cfra, int dflag, float alpha)
+ bGPdata *gpd, int offsx, int offsy, int winx, int winy, int cfra, int dflag)
{
/* turn on smooth lines (i.e. anti-aliasing) */
GPU_line_smooth(true);
@@ -978,7 +731,7 @@ static void annotation_draw_data(
GPU_blend(true);
/* draw! */
- annotation_draw_data_layers(gpd, offsx, offsy, winx, winy, cfra, dflag, alpha);
+ annotation_draw_data_layers(gpd, offsx, offsy, winx, winy, cfra, dflag);
/* turn off alpha blending, then smooth lines */
GPU_blend(false); // alpha blending
@@ -998,7 +751,6 @@ static void annotation_draw_data_all(Scene *scene,
const char spacetype)
{
bGPdata *gpd_source = NULL;
- float alpha = 1.0f;
if (scene) {
if (spacetype == SPACE_VIEW3D) {
@@ -1011,14 +763,14 @@ static void annotation_draw_data_all(Scene *scene,
}
if (gpd_source) {
- annotation_draw_data(gpd_source, offsx, offsy, winx, winy, cfra, dflag, alpha);
+ annotation_draw_data(gpd_source, offsx, offsy, winx, winy, cfra, dflag);
}
}
/* scene/clip data has already been drawn, only object/track data is drawn here
* if gpd_source == gpd, we don't have any object/track data and we can skip */
if (gpd_source == NULL || (gpd_source && gpd_source != gpd)) {
- annotation_draw_data(gpd, offsx, offsy, winx, winy, cfra, dflag, alpha);
+ annotation_draw_data(gpd, offsx, offsy, winx, winy, cfra, dflag);
}
}
@@ -1034,7 +786,7 @@ static void annotation_draw_data_all(Scene *scene,
void ED_annotation_draw_2dimage(const bContext *C)
{
wmWindowManager *wm = CTX_wm_manager(C);
- ScrArea *sa = CTX_wm_area(C);
+ ScrArea *area = CTX_wm_area(C);
ARegion *region = CTX_wm_region(C);
Scene *scene = CTX_data_scene(C);
@@ -1047,7 +799,7 @@ void ED_annotation_draw_2dimage(const bContext *C)
}
/* calculate rect */
- switch (sa->spacetype) {
+ switch (area->spacetype) {
case SPACE_IMAGE: /* image */
case SPACE_CLIP: /* clip */
{
@@ -1096,7 +848,7 @@ void ED_annotation_draw_2dimage(const bContext *C)
}
/* draw it! */
- annotation_draw_data_all(scene, gpd, offsx, offsy, sizex, sizey, CFRA, dflag, sa->spacetype);
+ annotation_draw_data_all(scene, gpd, offsx, offsy, sizex, sizey, CFRA, dflag, area->spacetype);
}
/**
@@ -1109,13 +861,13 @@ void ED_annotation_draw_2dimage(const bContext *C)
void ED_annotation_draw_view2d(const bContext *C, bool onlyv2d)
{
wmWindowManager *wm = CTX_wm_manager(C);
- ScrArea *sa = CTX_wm_area(C);
+ ScrArea *area = CTX_wm_area(C);
ARegion *region = CTX_wm_region(C);
Scene *scene = CTX_data_scene(C);
int dflag = 0;
/* check that we have grease-pencil stuff to draw */
- if (sa == NULL) {
+ if (area == NULL) {
return;
}
bGPdata *gpd = ED_annotation_data_get_active(C);
@@ -1126,7 +878,7 @@ void ED_annotation_draw_view2d(const bContext *C, bool onlyv2d)
/* special hack for Image Editor */
/* FIXME: the opengl poly-strokes don't draw at right thickness when done this way,
* so disabled. */
- if (ELEM(sa->spacetype, SPACE_IMAGE, SPACE_CLIP)) {
+ if (ELEM(area->spacetype, SPACE_IMAGE, SPACE_CLIP)) {
dflag |= GP_DRAWDATA_IEDITHACK;
}
@@ -1139,16 +891,11 @@ void ED_annotation_draw_view2d(const bContext *C, bool onlyv2d)
}
annotation_draw_data_all(
- scene, gpd, 0, 0, region->winx, region->winy, CFRA, dflag, sa->spacetype);
-
- /* draw status text (if in screen/pixel-space) */
- if (!onlyv2d) {
- annotation_draw_status_text(gpd, region);
- }
+ scene, gpd, 0, 0, region->winx, region->winy, CFRA, dflag, area->spacetype);
}
-/* draw annotations sketches to specified 3d-view assuming that matrices are already set correctly
- * Note: this gets called twice - first time with only3d=true to draw 3d-strokes,
+/* draw annotations sketches to specified 3d-view assuming that matrices are already set
+ * correctly Note: this gets called twice - first time with only3d=true to draw 3d-strokes,
* second time with only3d=false for screen-aligned strokes */
void ED_annotation_draw_view3d(
Scene *scene, struct Depsgraph *depsgraph, View3D *v3d, ARegion *region, bool only3d)
@@ -1158,7 +905,8 @@ void ED_annotation_draw_view3d(
int offsx, offsy, winx, winy;
/* check that we have grease-pencil stuff to draw */
- /* XXX: Hardcoded reference here may get out of sync if we change how we fetch annotation data */
+ /* XXX: Hardcoded reference here may get out of sync if we change how we fetch annotation data
+ */
bGPdata *gpd = scene->gpd;
if (gpd == NULL) {
return;
diff --git a/source/blender/editors/gpencil/annotate_paint.c b/source/blender/editors/gpencil/annotate_paint.c
index 9f2c4070b18..723c7d214e3 100644
--- a/source/blender/editors/gpencil/annotate_paint.c
+++ b/source/blender/editors/gpencil/annotate_paint.c
@@ -100,6 +100,9 @@ typedef enum eGPencil_PaintFlags {
GP_PAINTFLAG_STROKEADDED = (1 << 1),
GP_PAINTFLAG_V3D_ERASER_DEPTH = (1 << 2),
GP_PAINTFLAG_SELECTMASK = (1 << 3),
+ /* Flags used to indicate if stabilization is being used. */
+ GP_PAINTFLAG_USE_STABILIZER = (1 << 7),
+ GP_PAINTFLAG_USE_STABILIZER_TEMP = (1 << 8),
} eGPencil_PaintFlags;
/* Temporary 'Stroke' Operation data
@@ -114,7 +117,7 @@ typedef struct tGPsdata {
/** window where painting originated. */
wmWindow *win;
/** area where painting originated. */
- ScrArea *sa;
+ ScrArea *area;
/** region where painting originated. */
ARegion *region;
/** needed for GP_STROKE_2DSPACE. */
@@ -148,6 +151,11 @@ typedef struct tGPsdata {
/** radius of influence for eraser. */
short radius;
+ /* Stabilizer. */
+ float stabilizer_factor;
+ char stabilizer_radius;
+ void *stabilizer_cursor;
+
/** current mouse-position. */
float mval[2];
/** previous recorded mouse-position. */
@@ -278,6 +286,18 @@ static bool gp_stroke_filtermval(tGPsdata *p, const float mval[2], float pmval[2
* - aims to eliminate some jitter-noise from input when trying to draw straight lines freehand
*/
}
+ /* If lazy mouse, check minimum distance. */
+ else if (p->flags & GP_PAINTFLAG_USE_STABILIZER_TEMP) {
+ if ((dx * dx + dy * dy) > (p->stabilizer_radius * p->stabilizer_radius)) {
+ return true;
+ }
+ else {
+ /* If the mouse is moving within the radius of the last move,
+ * don't update the mouse position. This allows sharp turns. */
+ copy_v2_v2(p->mval, p->mvalo);
+ return false;
+ }
+ }
else if ((dx > MIN_MANHATTEN_PX) && (dy > MIN_MANHATTEN_PX)) {
return true;
@@ -418,6 +438,85 @@ static void gp_smooth_buffer(tGPsdata *p, float inf, int idx)
copy_v2_v2(&ptc->x, c);
}
+static void gp_stroke_arrow_calc_points_segment(float stroke_points[8],
+ const float ref_point[2],
+ const float dir_cw[2],
+ const float dir_ccw[2],
+ const float lenght,
+ const float sign)
+{
+ stroke_points[0] = ref_point[0] + dir_cw[0] * lenght * sign;
+ stroke_points[1] = ref_point[1] + dir_cw[1] * lenght * sign;
+ stroke_points[2] = ref_point[0] + dir_ccw[0] * lenght * sign;
+ stroke_points[3] = ref_point[1] + dir_ccw[1] * lenght * sign;
+}
+
+static void gp_stroke_arrow_calc_points(tGPspoint *point,
+ const float stroke_dir[2],
+ float corner[2],
+ float stroke_points[8],
+ const int arrow_style)
+{
+ const int arrow_lenght = 8;
+ float norm_dir[2];
+ copy_v2_v2(norm_dir, stroke_dir);
+ normalize_v2(norm_dir);
+ const float inv_norm_dir_clockwise[2] = {norm_dir[1], -norm_dir[0]};
+ const float inv_norm_dir_counterclockwise[2] = {-norm_dir[1], norm_dir[0]};
+
+ switch (arrow_style) {
+ case GP_STROKE_ARROWSTYLE_OPEN:
+ mul_v2_fl(norm_dir, arrow_lenght);
+ stroke_points[0] = corner[0] + inv_norm_dir_clockwise[0] * arrow_lenght + norm_dir[0];
+ stroke_points[1] = corner[1] + inv_norm_dir_clockwise[1] * arrow_lenght + norm_dir[1];
+ stroke_points[2] = corner[0] + inv_norm_dir_counterclockwise[0] * arrow_lenght + norm_dir[0];
+ stroke_points[3] = corner[1] + inv_norm_dir_counterclockwise[1] * arrow_lenght + norm_dir[1];
+ break;
+ case GP_STROKE_ARROWSTYLE_SEGMENT:
+ gp_stroke_arrow_calc_points_segment(stroke_points,
+ corner,
+ inv_norm_dir_clockwise,
+ inv_norm_dir_counterclockwise,
+ arrow_lenght,
+ 1.0f);
+ break;
+ case GP_STROKE_ARROWSTYLE_CLOSED:
+ mul_v2_fl(norm_dir, arrow_lenght);
+ if (point != NULL) {
+ add_v2_v2(&point->x, norm_dir);
+ copy_v2_v2(corner, &point->x);
+ }
+ gp_stroke_arrow_calc_points_segment(stroke_points,
+ corner,
+ inv_norm_dir_clockwise,
+ inv_norm_dir_counterclockwise,
+ arrow_lenght,
+ -1.0f);
+ stroke_points[4] = corner[0] - norm_dir[0];
+ stroke_points[5] = corner[1] - norm_dir[1];
+ break;
+ case GP_STROKE_ARROWSTYLE_SQUARE:
+ mul_v2_fl(norm_dir, arrow_lenght * 1.5f);
+ if (point != NULL) {
+ add_v2_v2(&point->x, norm_dir);
+ copy_v2_v2(corner, &point->x);
+ }
+ gp_stroke_arrow_calc_points_segment(stroke_points,
+ corner,
+ inv_norm_dir_clockwise,
+ inv_norm_dir_counterclockwise,
+ arrow_lenght * 0.75f,
+ -1.0f);
+ stroke_points[4] = stroke_points[0] - norm_dir[0];
+ stroke_points[5] = stroke_points[1] - norm_dir[1];
+ stroke_points[6] = stroke_points[2] - norm_dir[0];
+ stroke_points[7] = stroke_points[3] - norm_dir[1];
+ break;
+ default:
+ break;
+ }
+}
+
/* add current stroke-point to buffer (returns whether point was successfully added) */
static short gp_stroke_addpoint(tGPsdata *p, const float mval[2], float pressure, double curtime)
{
@@ -457,6 +556,32 @@ static short gp_stroke_addpoint(tGPsdata *p, const float mval[2], float pressure
/* now the buffer has 2 points (and shouldn't be allowed to get any larger) */
gpd->runtime.sbuffer_used = 2;
+
+ /* Arrows. */
+ if (gpd->runtime.sbuffer_sflag & (GP_STROKE_USE_ARROW_START | GP_STROKE_USE_ARROW_END)) {
+ /* Store start and end point coords for arrows. */
+ float end[2];
+ copy_v2_v2(end, &pt->x);
+ pt = ((tGPspoint *)(gpd->runtime.sbuffer));
+ float start[2];
+ copy_v2_v2(start, &pt->x);
+
+ /* Arrow end corner. */
+ if (gpd->runtime.sbuffer_sflag & GP_STROKE_USE_ARROW_END) {
+ pt++;
+ float e_heading[2] = {start[0] - end[0], start[1] - end[1]};
+ /* Calculate points for ending arrow. */
+ gp_stroke_arrow_calc_points(
+ pt, e_heading, end, gpd->runtime.arrow_end, gpd->runtime.arrow_end_style);
+ }
+ /* Arrow start corner. */
+ if (gpd->runtime.sbuffer_sflag & GP_STROKE_USE_ARROW_START) {
+ float s_heading[2] = {end[0] - start[0], end[1] - start[1]};
+ /* Calculate points for starting arrow. */
+ gp_stroke_arrow_calc_points(
+ NULL, s_heading, start, gpd->runtime.arrow_start, gpd->runtime.arrow_start_style);
+ }
+ }
}
/* can keep carrying on this way :) */
@@ -481,16 +606,20 @@ static short gp_stroke_addpoint(tGPsdata *p, const float mval[2], float pressure
/* increment counters */
gpd->runtime.sbuffer_used++;
- /* smooth while drawing previous points with a reduction factor for previous */
- for (int s = 0; s < 3; s++) {
- gp_smooth_buffer(p, 0.5f * ((3.0f - s) / 3.0f), gpd->runtime.sbuffer_used - s);
+
+ /* Don't smooth if stabilizer is on. */
+ if ((p->flags & GP_PAINTFLAG_USE_STABILIZER_TEMP) == 0) {
+ /* smooth while drawing previous points with a reduction factor for previous */
+ for (int s = 0; s < 3; s++) {
+ gp_smooth_buffer(p, 0.5f * ((3.0f - s) / 3.0f), gpd->runtime.sbuffer_used - s);
+ }
}
return GP_STROKEADD_NORMAL;
}
else if (p->paintmode == GP_PAINTMODE_DRAW_POLY) {
/* get pointer to destination point */
- pt = (tGPspoint *)(gpd->runtime.sbuffer);
+ pt = (tGPspoint *)gpd->runtime.sbuffer;
/* store settings */
copy_v2_v2(&pt->x, mval);
@@ -521,7 +650,7 @@ static short gp_stroke_addpoint(tGPsdata *p, const float mval[2], float pressure
* so initialize depth buffer before converting coordinates
*/
if (gpencil_project_check(p)) {
- View3D *v3d = p->sa->spacedata.first;
+ View3D *v3d = p->area->spacedata.first;
view3d_region_operator_needs_opengl(p->win, p->region);
ED_view3d_autodist_init(p->depsgraph,
@@ -552,6 +681,123 @@ static short gp_stroke_addpoint(tGPsdata *p, const float mval[2], float pressure
return GP_STROKEADD_INVALID;
}
+static void gp_stroke_arrow_init_point_default(bGPDspoint *pt)
+{
+ pt->pressure = 1.0f;
+ pt->strength = 1.0f;
+ pt->time = 1.0f;
+}
+
+static void gp_stroke_arrow_init_conv_point(bGPDspoint *pt, const float point[3])
+{
+ copy_v3_v3(&pt->x, point);
+ gp_stroke_arrow_init_point_default(pt);
+}
+
+static void gp_stroke_arrow_init_point(
+ tGPsdata *p, tGPspoint *ptc, bGPDspoint *pt, const float co[8], const int co_idx)
+{
+ /* Note: provided co_idx should be always pair number as it's [x1, y1, x2, y2, x3, y3]. */
+ float real_co[2] = {co[co_idx], co[co_idx + 1]};
+ copy_v2_v2(&ptc->x, real_co);
+ gp_stroke_convertcoords(p, &ptc->x, &pt->x, NULL);
+ gp_stroke_arrow_init_point_default(pt);
+}
+
+static void gp_stroke_arrow_allocate(bGPDstroke *gps, const int totpoints)
+{
+ /* Copy appropriate settings for stroke. */
+ gps->totpoints = totpoints;
+ /* Allocate enough memory for a continuous array for storage points. */
+ gps->points = MEM_callocN(sizeof(bGPDspoint) * gps->totpoints, "gp_stroke_points");
+}
+
+static void gp_arrow_create_open(tGPsdata *p,
+ tGPspoint *ptc,
+ bGPDspoint *pt,
+ const float corner_point[3],
+ const float arrow_points[8])
+{
+ gp_stroke_arrow_init_point(p, ptc, pt, arrow_points, 0);
+ pt++;
+ gp_stroke_arrow_init_conv_point(pt, corner_point);
+ pt++;
+ gp_stroke_arrow_init_point(p, ptc, pt, arrow_points, 2);
+}
+
+static void gp_arrow_create_segm(tGPsdata *p,
+ tGPspoint *ptc,
+ bGPDspoint *pt,
+ const float arrow_points[8])
+{
+ gp_stroke_arrow_init_point(p, ptc, pt, arrow_points, 0);
+ pt++;
+ gp_stroke_arrow_init_point(p, ptc, pt, arrow_points, 2);
+}
+
+static void gp_arrow_create_closed(tGPsdata *p,
+ tGPspoint *ptc,
+ bGPDspoint *pt,
+ const float arrow_points[8])
+{
+ gp_stroke_arrow_init_point(p, ptc, pt, arrow_points, 0);
+ pt++;
+ gp_stroke_arrow_init_point(p, ptc, pt, arrow_points, 2);
+ pt++;
+ gp_stroke_arrow_init_point(p, ptc, pt, arrow_points, 4);
+ pt++;
+ gp_stroke_arrow_init_point(p, ptc, pt, arrow_points, 0);
+}
+
+static void gp_arrow_create_square(tGPsdata *p,
+ tGPspoint *ptc,
+ bGPDspoint *pt,
+ const float corner_point[3],
+ const float arrow_points[8])
+{
+ gp_stroke_arrow_init_conv_point(pt, corner_point);
+ pt++;
+ gp_stroke_arrow_init_point(p, ptc, pt, arrow_points, 0);
+ pt++;
+ gp_stroke_arrow_init_point(p, ptc, pt, arrow_points, 4);
+ pt++;
+ gp_stroke_arrow_init_point(p, ptc, pt, arrow_points, 6);
+ pt++;
+ gp_stroke_arrow_init_point(p, ptc, pt, arrow_points, 2);
+ pt++;
+ gp_stroke_arrow_init_conv_point(pt, corner_point);
+}
+
+static void gp_arrow_create(tGPsdata *p,
+ tGPspoint *ptc,
+ bGPDspoint *pt,
+ bGPDstroke *arrow_stroke,
+ const float arrow_points[8],
+ const int style)
+{
+ float corner_conv[3];
+ copy_v3_v3(corner_conv, &pt->x);
+
+ switch (style) {
+ case GP_STROKE_ARROWSTYLE_SEGMENT:
+ gp_arrow_create_segm(p, ptc, pt, arrow_points);
+ break;
+ case GP_STROKE_ARROWSTYLE_CLOSED:
+ gp_arrow_create_closed(p, ptc, pt, arrow_points);
+ break;
+ case GP_STROKE_ARROWSTYLE_OPEN:
+ gp_arrow_create_open(p, ptc, pt, corner_conv, arrow_points);
+ break;
+ case GP_STROKE_ARROWSTYLE_SQUARE:
+ gp_arrow_create_square(p, ptc, pt, corner_conv, arrow_points);
+ break;
+ default:
+ break;
+ }
+ /* Link stroke to frame. */
+ BLI_addtail(&p->gpf->strokes, arrow_stroke);
+}
+
/* make a new stroke from the buffer data */
static void gp_stroke_newfrombuffer(tGPsdata *p)
{
@@ -637,17 +883,61 @@ static void gp_stroke_newfrombuffer(tGPsdata *p)
}
if (totelem == 2) {
- /* last point if applicable */
- ptc = ((tGPspoint *)gpd->runtime.sbuffer) + (gpd->runtime.sbuffer_used - 1);
+ bGPdata_Runtime runtime = gpd->runtime;
- /* convert screen-coordinates to appropriate coordinates (and store them) */
+ /* Last point if applicable. */
+ ptc = ((tGPspoint *)runtime.sbuffer) + (runtime.sbuffer_used - 1);
+
+ /* Convert screen-coordinates to appropriate coordinates (and store them). */
gp_stroke_convertcoords(p, &ptc->x, &pt->x, NULL);
- /* copy pressure and time */
+ /* Copy pressure and time. */
pt->pressure = ptc->pressure;
pt->strength = ptc->strength;
CLAMP(pt->strength, GPENCIL_STRENGTH_MIN, 1.0f);
pt->time = ptc->time;
+
+ /** Create arrow strokes. **/
+ /* End arrow stroke. */
+ if ((runtime.sbuffer_sflag & GP_STROKE_USE_ARROW_END) &&
+ (runtime.arrow_end_style != GP_STROKE_ARROWSTYLE_NONE)) {
+ int totarrowpoints = runtime.arrow_end_style;
+
+ /* Setting up arrow stroke. */
+ bGPDstroke *e_arrow_gps = BKE_gpencil_stroke_duplicate(gps, false);
+ gp_stroke_arrow_allocate(e_arrow_gps, totarrowpoints);
+
+ /* Set pointer to first non-initialized point. */
+ pt = e_arrow_gps->points + (e_arrow_gps->totpoints - totarrowpoints);
+
+ /* End point. */
+ ptc = ((tGPspoint *)runtime.sbuffer) + (runtime.sbuffer_used - 1);
+ gp_stroke_convertcoords(p, &ptc->x, &pt->x, NULL);
+ gp_stroke_arrow_init_point_default(pt);
+
+ /* Fill and convert arrow points to create arrow shape. */
+ gp_arrow_create(p, ptc, pt, e_arrow_gps, runtime.arrow_end, runtime.arrow_end_style);
+ }
+ /* Start arrow stroke. */
+ if ((runtime.sbuffer_sflag & GP_STROKE_USE_ARROW_START) &&
+ (runtime.arrow_start_style != GP_STROKE_ARROWSTYLE_NONE)) {
+ int totarrowpoints = runtime.arrow_start_style;
+
+ /* Setting up arrow stroke. */
+ bGPDstroke *s_arrow_gps = BKE_gpencil_stroke_duplicate(gps, false);
+ gp_stroke_arrow_allocate(s_arrow_gps, totarrowpoints);
+
+ /* Set pointer to first non-initialized point. */
+ pt = s_arrow_gps->points + (s_arrow_gps->totpoints - totarrowpoints);
+
+ /* Start point. */
+ ptc = runtime.sbuffer;
+ gp_stroke_convertcoords(p, &ptc->x, &pt->x, NULL);
+ gp_stroke_arrow_init_point_default(pt);
+
+ /* Fill and convert arrow points to create arrow shape. */
+ gp_arrow_create(p, ptc, pt, s_arrow_gps, runtime.arrow_start, runtime.arrow_start_style);
+ }
}
}
else if (p->paintmode == GP_PAINTMODE_DRAW_POLY) {
@@ -793,7 +1083,7 @@ static bool gp_stroke_eraser_is_occluded(tGPsdata *p,
const int x,
const int y)
{
- if ((p->sa->spacetype == SPACE_VIEW3D) && (p->flags & GP_PAINTFLAG_V3D_ERASER_DEPTH)) {
+ if ((p->area->spacetype == SPACE_VIEW3D) && (p->flags & GP_PAINTFLAG_V3D_ERASER_DEPTH)) {
RegionView3D *rv3d = p->region->regiondata;
const int mval_i[2] = {x, y};
float mval_3d[3];
@@ -816,7 +1106,6 @@ static void gp_stroke_eraser_dostroke(tGPsdata *p,
bGPDframe *gpf,
bGPDstroke *gps,
const float mval[2],
- const float mvalo[2],
const int radius,
const rcti *rect)
{
@@ -885,7 +1174,7 @@ static void gp_stroke_eraser_dostroke(tGPsdata *p,
* eraser region (either within stroke painted, or on its lines)
* - this assumes that linewidth is irrelevant
*/
- if (gp_stroke_inside_circle(mval, mvalo, radius, pc1[0], pc1[1], pc2[0], pc2[1])) {
+ if (gp_stroke_inside_circle(mval, radius, pc1[0], pc1[1], pc2[0], pc2[1])) {
if ((gp_stroke_eraser_is_occluded(p, pt1, pc1[0], pc1[1]) == false) ||
(gp_stroke_eraser_is_occluded(p, pt2, pc2[0], pc2[1]) == false)) {
/* Edge is affected - Check individual points now */
@@ -921,9 +1210,9 @@ static void gp_stroke_doeraser(tGPsdata *p)
rect.xmax = p->mval[0] + p->radius;
rect.ymax = p->mval[1] + p->radius;
- if (p->sa->spacetype == SPACE_VIEW3D) {
+ if (p->area->spacetype == SPACE_VIEW3D) {
if (p->flags & GP_PAINTFLAG_V3D_ERASER_DEPTH) {
- View3D *v3d = p->sa->spacedata.first;
+ View3D *v3d = p->area->spacedata.first;
view3d_region_operator_needs_opengl(p->win, p->region);
ED_view3d_autodist_init(p->depsgraph, p->region, v3d, 0);
}
@@ -937,8 +1226,8 @@ static void gp_stroke_doeraser(tGPsdata *p)
/* Not all strokes in the datablock may be valid in the current editor/context
* (e.g. 2D space strokes in the 3D view, if the same datablock is shared)
*/
- if (ED_gpencil_stroke_can_use_direct(p->sa, gps)) {
- gp_stroke_eraser_dostroke(p, gpf, gps, p->mval, p->mvalo, p->radius, &rect);
+ if (ED_gpencil_stroke_can_use_direct(p->area, gps)) {
+ gp_stroke_eraser_dostroke(p, gpf, gps, p->mval, p->radius, &rect);
}
}
}
@@ -998,7 +1287,7 @@ static bool gp_session_initdata(bContext *C, tGPsdata *p)
* - must verify that region data is 3D-view (and not something else)
*/
/* CAUTION: If this is the "toolbar", then this will change on the first stroke */
- p->sa = curarea;
+ p->area = curarea;
p->region = region;
p->align_flag = &ts->annotate_v3d_align;
@@ -1017,7 +1306,7 @@ static bool gp_session_initdata(bContext *C, tGPsdata *p)
/* SpaceNode *snode = curarea->spacedata.first; */
/* set current area */
- p->sa = curarea;
+ p->area = curarea;
p->region = region;
p->v2d = &region->v2d;
p->align_flag = &ts->gpencil_v2d_align;
@@ -1027,7 +1316,7 @@ static bool gp_session_initdata(bContext *C, tGPsdata *p)
SpaceSeq *sseq = curarea->spacedata.first;
/* set current area */
- p->sa = curarea;
+ p->area = curarea;
p->region = region;
p->v2d = &region->v2d;
p->align_flag = &ts->gpencil_seq_align;
@@ -1046,7 +1335,7 @@ static bool gp_session_initdata(bContext *C, tGPsdata *p)
/* SpaceImage *sima = curarea->spacedata.first; */
/* set the current area */
- p->sa = curarea;
+ p->area = curarea;
p->region = region;
p->v2d = &region->v2d;
p->align_flag = &ts->gpencil_ima_align;
@@ -1062,7 +1351,7 @@ static bool gp_session_initdata(bContext *C, tGPsdata *p)
}
/* set the current area */
- p->sa = curarea;
+ p->area = curarea;
p->region = region;
p->v2d = &region->v2d;
p->align_flag = &ts->gpencil_v2d_align;
@@ -1280,7 +1569,7 @@ static void gp_paint_initstroke(tGPsdata *p, eGPencil_PaintModes paintmode, Deps
p->gpd->runtime.sbuffer_sflag |= GP_STROKE_ERASER;
/* check if we should respect depth while erasing */
- if (p->sa->spacetype == SPACE_VIEW3D) {
+ if (p->area->spacetype == SPACE_VIEW3D) {
if (p->gpl->flag & GP_LAYER_NO_XRAY) {
p->flags |= GP_PAINTFLAG_V3D_ERASER_DEPTH;
}
@@ -1290,7 +1579,7 @@ static void gp_paint_initstroke(tGPsdata *p, eGPencil_PaintModes paintmode, Deps
/* disable eraser flags - so that we can switch modes during a session */
p->gpd->runtime.sbuffer_sflag &= ~GP_STROKE_ERASER;
- if (p->sa->spacetype == SPACE_VIEW3D) {
+ if (p->area->spacetype == SPACE_VIEW3D) {
if (p->gpl->flag & GP_LAYER_NO_XRAY) {
p->flags &= ~GP_PAINTFLAG_V3D_ERASER_DEPTH;
}
@@ -1303,8 +1592,8 @@ static void gp_paint_initstroke(tGPsdata *p, eGPencil_PaintModes paintmode, Deps
/* when drawing in the camera view, in 2D space, set the subrect */
p->subrect = NULL;
if ((*p->align_flag & GP_PROJECT_VIEWSPACE) == 0) {
- if (p->sa->spacetype == SPACE_VIEW3D) {
- View3D *v3d = p->sa->spacedata.first;
+ if (p->area->spacetype == SPACE_VIEW3D) {
+ View3D *v3d = p->area->spacedata.first;
RegionView3D *rv3d = p->region->regiondata;
/* for camera view set the subrect */
@@ -1321,7 +1610,7 @@ static void gp_paint_initstroke(tGPsdata *p, eGPencil_PaintModes paintmode, Deps
p->gsc.gpd = p->gpd;
p->gsc.gpl = p->gpl;
- p->gsc.sa = p->sa;
+ p->gsc.area = p->area;
p->gsc.region = p->region;
p->gsc.v2d = p->v2d;
@@ -1332,7 +1621,7 @@ static void gp_paint_initstroke(tGPsdata *p, eGPencil_PaintModes paintmode, Deps
/* check if points will need to be made in view-aligned space */
if (*p->align_flag & GP_PROJECT_VIEWSPACE) {
- switch (p->sa->spacetype) {
+ switch (p->area->spacetype) {
case SPACE_VIEW3D: {
p->gpd->runtime.sbuffer_sflag |= GP_STROKE_3DSPACE;
break;
@@ -1356,7 +1645,7 @@ static void gp_paint_strokeend(tGPsdata *p)
* the conversions will project the values correctly...
*/
if (gpencil_project_check(p)) {
- View3D *v3d = p->sa->spacedata.first;
+ View3D *v3d = p->area->spacedata.first;
/* need to restore the original projection settings before packing up */
view3d_region_operator_needs_opengl(p->win, p->region);
@@ -1440,23 +1729,83 @@ static void gpencil_draw_eraser(bContext *UNUSED(C), int x, int y, void *p_ptr)
}
/* Turn brush cursor in 3D view on/off */
-static void gpencil_draw_toggle_eraser_cursor(bContext *C, tGPsdata *p, short enable)
+static void gpencil_draw_toggle_eraser_cursor(tGPsdata *p, short enable)
{
if (p->erasercursor && !enable) {
/* clear cursor */
- WM_paint_cursor_end(CTX_wm_manager(C), p->erasercursor);
+ WM_paint_cursor_end(p->erasercursor);
p->erasercursor = NULL;
}
else if (enable && !p->erasercursor) {
/* enable cursor */
- p->erasercursor = WM_paint_cursor_activate(CTX_wm_manager(C),
- SPACE_TYPE_ANY,
+ p->erasercursor = WM_paint_cursor_activate(SPACE_TYPE_ANY,
RGN_TYPE_ANY,
NULL, /* XXX */
gpencil_draw_eraser,
p);
}
}
+static void gpencil_draw_stabilizer(bContext *C, int x, int y, void *p_ptr)
+{
+ ARegion *region = CTX_wm_region(C);
+ tGPsdata *p = (tGPsdata *)p_ptr;
+ bGPdata_Runtime runtime = p->gpd->runtime;
+ const tGPspoint *points = runtime.sbuffer;
+ int totpoints = runtime.sbuffer_used;
+ if (totpoints < 2) {
+ return;
+ }
+ const tGPspoint *pt = &points[totpoints - 1];
+
+ GPUVertFormat *format = immVertexFormat();
+ uint pos = GPU_vertformat_attr_add(format, "pos", GPU_COMP_F32, 2, GPU_FETCH_FLOAT);
+ immBindBuiltinProgram(GPU_SHADER_2D_UNIFORM_COLOR);
+ GPU_line_smooth(true);
+ GPU_blend(true);
+ GPU_line_width(1.25f);
+ const float color[3] = {1.0f, 0.39f, 0.39f};
+
+ /* default radius and color */
+ float darkcolor[3];
+ const float radius = 4.0f;
+
+ /* Inner Ring: Color from UI panel */
+ immUniformColor4f(color[0], color[1], color[2], 0.8f);
+ imm_draw_circle_wire_2d(pos, x, y, radius, 40);
+
+ /* Outer Ring: Dark color for contrast on light backgrounds (e.g. gray on white) */
+ mul_v3_v3fl(darkcolor, color, 0.40f);
+ immUniformColor4f(darkcolor[0], darkcolor[1], darkcolor[2], 0.8f);
+ imm_draw_circle_wire_2d(pos, x, y, radius + 1, 40);
+
+ /* Rope Simple. */
+ immUniformColor4f(color[0], color[1], color[2], 0.8f);
+ immBegin(GPU_PRIM_LINES, 2);
+ immVertex2f(pos, pt->x + region->winrct.xmin, pt->y + region->winrct.ymin);
+ immVertex2f(pos, x, y);
+ immEnd();
+
+ /* Returns back all GPU settings */
+ GPU_blend(false);
+ GPU_line_smooth(false);
+
+ immUnbindProgram();
+}
+
+/* Turn *stabilizer* brush cursor in 3D view on/off */
+static void gpencil_draw_toggle_stabilizer_cursor(tGPsdata *p, short enable)
+{
+ if (p->stabilizer_cursor && !enable) {
+ /* clear cursor */
+ WM_paint_cursor_end(p->stabilizer_cursor);
+ p->stabilizer_cursor = NULL;
+ }
+ else if (enable && !p->stabilizer_cursor) {
+ /* enable cursor */
+ p->stabilizer_cursor = WM_paint_cursor_activate(
+ SPACE_TYPE_ANY, RGN_TYPE_ANY, NULL, gpencil_draw_stabilizer, p);
+ }
+}
/* Check if tablet eraser is being used (when processing events) */
static bool gpencil_is_tablet_eraser_active(const wmEvent *event)
@@ -1478,7 +1827,10 @@ static void gpencil_draw_exit(bContext *C, wmOperator *op)
/* check size of buffer before cleanup, to determine if anything happened here */
if (p->paintmode == GP_PAINTMODE_ERASER) {
/* turn off radial brush cursor */
- gpencil_draw_toggle_eraser_cursor(C, p, false);
+ gpencil_draw_toggle_eraser_cursor(p, false);
+ }
+ else if (p->paintmode == GP_PAINTMODE_DRAW) {
+ gpencil_draw_toggle_stabilizer_cursor(p, false);
}
/* always store the new eraser size to be used again next time
@@ -1567,8 +1919,8 @@ static void gpencil_draw_status_indicators(bContext *C, tGPsdata *p)
"ESC/Enter to end (or click outside this area)"));
break;
default:
- /* Do nothing - the others are self explanatory, exit quickly once the mouse is released
- * Showing any text would just be annoying as it would flicker.
+ /* Do nothing - the others are self explanatory, exit quickly once the mouse is
+ * released Showing any text would just be annoying as it would flicker.
*/
break;
}
@@ -1633,6 +1985,16 @@ static void gpencil_draw_apply(wmOperator *op, tGPsdata *p, Depsgraph *depsgraph
/* Only add current point to buffer if mouse moved
* (even though we got an event, it might be just noise). */
else if (gp_stroke_filtermval(p, p->mval, p->mvalo)) {
+ /* If lazy mouse, interpolate the last and current mouse positions. */
+ if (p->flags & GP_PAINTFLAG_USE_STABILIZER_TEMP) {
+ float now_mouse[2];
+ float last_mouse[2];
+ copy_v2_v2(now_mouse, p->mval);
+ copy_v2_v2(last_mouse, p->mvalo);
+ interp_v2_v2v2(now_mouse, now_mouse, last_mouse, min_ff(p->stabilizer_factor, .995f));
+ copy_v2_v2(p->mval, now_mouse);
+ }
+
/* try to add point */
short ok = gp_stroke_addpoint(p, p->mval, p->pressure, p->curtime);
@@ -1688,8 +2050,23 @@ static void annotation_draw_apply_event(
p->mval[0] = (float)event->mval[0] - x;
p->mval[1] = (float)event->mval[1] - y;
+ /* Key to toggle stabilization. */
+ if (event->shift > 0 && p->paintmode == GP_PAINTMODE_DRAW) {
+ /* Using permanent stabilization, shift will deactivate the flag. */
+ if (p->flags & (GP_PAINTFLAG_USE_STABILIZER)) {
+ if (p->flags & GP_PAINTFLAG_USE_STABILIZER_TEMP) {
+ gpencil_draw_toggle_stabilizer_cursor(p, false);
+ p->flags &= ~GP_PAINTFLAG_USE_STABILIZER_TEMP;
+ }
+ }
+ /* Not using any stabilization flag. Activate temporal one. */
+ else if ((p->flags & GP_PAINTFLAG_USE_STABILIZER_TEMP) == 0) {
+ p->flags |= GP_PAINTFLAG_USE_STABILIZER_TEMP;
+ gpencil_draw_toggle_stabilizer_cursor(p, true);
+ }
+ }
/* verify key status for straight lines */
- if ((event->ctrl > 0) || (event->alt > 0)) {
+ else if ((event->ctrl > 0) || (event->alt > 0)) {
if (p->straight[0] == 0) {
int dx = abs((int)(p->mval[0] - p->mvalo[0]));
int dy = abs((int)(p->mval[1] - p->mvalo[1]));
@@ -1710,6 +2087,22 @@ static void annotation_draw_apply_event(
}
else {
p->straight[0] = 0;
+ /* We were using shift while having permanent stabilization actived,
+ so activate the temp flag back again. */
+ if (p->flags & GP_PAINTFLAG_USE_STABILIZER) {
+ if ((p->flags & GP_PAINTFLAG_USE_STABILIZER_TEMP) == 0) {
+ gpencil_draw_toggle_stabilizer_cursor(p, true);
+ p->flags |= GP_PAINTFLAG_USE_STABILIZER_TEMP;
+ }
+ }
+ /* We are using the temporal stabilizer flag atm,
+ but shift is not pressed as well as the permanent flag is not used,
+ so we don't need the cursor anymore. */
+ else if (p->flags & GP_PAINTFLAG_USE_STABILIZER_TEMP) {
+ /* Reset temporal stabilizer flag and remove cursor. */
+ p->flags &= ~GP_PAINTFLAG_USE_STABILIZER_TEMP;
+ gpencil_draw_toggle_stabilizer_cursor(p, false);
+ }
}
p->curtime = PIL_check_seconds_timer();
@@ -1897,11 +2290,34 @@ static int gpencil_draw_invoke(bContext *C, wmOperator *op, const wmEvent *event
/* TODO: set any additional settings that we can take from the events?
* TODO? if tablet is erasing, force eraser to be on? */
- /* TODO: move cursor setting stuff to stroke-start so that paintmode can be changed midway... */
+ /* TODO: move cursor setting stuff to stroke-start so that paintmode can be changed midway...
+ */
/* if eraser is on, draw radial aid */
if (p->paintmode == GP_PAINTMODE_ERASER) {
- gpencil_draw_toggle_eraser_cursor(C, p, true);
+ gpencil_draw_toggle_eraser_cursor(p, true);
+ }
+ else if (p->paintmode == GP_PAINTMODE_DRAW_STRAIGHT) {
+ if (RNA_enum_get(op->ptr, "arrowstyle_start") != GP_STROKE_ARROWSTYLE_NONE) {
+ p->gpd->runtime.sbuffer_sflag |= GP_STROKE_USE_ARROW_START;
+ p->gpd->runtime.arrow_start_style = RNA_enum_get(op->ptr, "arrowstyle_start");
+ }
+ if (RNA_enum_get(op->ptr, "arrowstyle_end") != GP_STROKE_ARROWSTYLE_NONE) {
+ p->gpd->runtime.sbuffer_sflag |= GP_STROKE_USE_ARROW_END;
+ p->gpd->runtime.arrow_end_style = RNA_enum_get(op->ptr, "arrowstyle_end");
+ }
+ }
+ else if (p->paintmode == GP_PAINTMODE_DRAW) {
+ p->stabilizer_factor = RNA_float_get(op->ptr, "stabilizer_factor");
+ p->stabilizer_radius = RNA_int_get(op->ptr, "stabilizer_radius");
+ if (RNA_boolean_get(op->ptr, "use_stabilizer")) {
+ p->flags |= GP_PAINTFLAG_USE_STABILIZER | GP_PAINTFLAG_USE_STABILIZER_TEMP;
+ gpencil_draw_toggle_stabilizer_cursor(p, true);
+ }
+ else if (event->shift > 0) {
+ p->flags |= GP_PAINTFLAG_USE_STABILIZER_TEMP;
+ gpencil_draw_toggle_stabilizer_cursor(p, true);
+ }
}
/* set cursor
* NOTE: This may change later (i.e. intentionally via brush toggle,
@@ -1932,10 +2348,10 @@ static int gpencil_draw_invoke(bContext *C, wmOperator *op, const wmEvent *event
}
/* gpencil modal operator stores area, which can be removed while using it (like fullscreen) */
-static bool gpencil_area_exists(bContext *C, ScrArea *sa_test)
+static bool gpencil_area_exists(bContext *C, ScrArea *area_test)
{
- bScreen *sc = CTX_wm_screen(C);
- return (BLI_findindex(&sc->areabase, sa_test) != -1);
+ bScreen *screen = CTX_wm_screen(C);
+ return (BLI_findindex(&screen->areabase, area_test) != -1);
}
static tGPsdata *gpencil_stroke_begin(bContext *C, wmOperator *op)
@@ -1945,7 +2361,7 @@ static tGPsdata *gpencil_stroke_begin(bContext *C, wmOperator *op)
/* we must check that we're still within the area that we're set up to work from
* otherwise we could crash (see bug #20586)
*/
- if (CTX_wm_area(C) != p->sa) {
+ if (CTX_wm_area(C) != p->area) {
printf("\t\t\tGP - wrong area execution abort!\n");
p->status = GP_STATUS_ERROR;
}
@@ -2107,7 +2523,8 @@ static int gpencil_draw_modal(bContext *C, wmOperator *op, const wmEvent *event)
}
/* toggle painting mode upon mouse-button movement
- * - LEFTMOUSE = standard drawing (all) / straight line drawing (all) / polyline (toolbox only)
+ * - LEFTMOUSE = standard drawing (all) / straight line drawing (all) / polyline (toolbox
+ * only)
* - RIGHTMOUSE = polyline (hotkey) / eraser (all)
* (Disabling RIGHTMOUSE case here results in bugs like [#32647])
* also making sure we have a valid event value, to not exit too early
@@ -2144,7 +2561,7 @@ static int gpencil_draw_modal(bContext *C, wmOperator *op, const wmEvent *event)
* Just hiding this makes it seem like
* you can paint again...
*/
- gpencil_draw_toggle_eraser_cursor(C, p, false);
+ gpencil_draw_toggle_eraser_cursor(p, false);
}
}
@@ -2169,18 +2586,19 @@ static int gpencil_draw_modal(bContext *C, wmOperator *op, const wmEvent *event)
*/
if ((p->region) && (p->region->regiontype == RGN_TYPE_TOOLS)) {
/* Change to whatever region is now under the mouse */
- ARegion *current_region = BKE_area_find_region_xy(p->sa, RGN_TYPE_ANY, event->x, event->y);
+ ARegion *current_region = BKE_area_find_region_xy(
+ p->area, RGN_TYPE_ANY, event->x, event->y);
if (G.debug & G_DEBUG) {
- printf("found alternative region %p (old was %p) - at %d %d (sa: %d %d -> %d %d)\n",
+ printf("found alternative region %p (old was %p) - at %d %d (area: %d %d -> %d %d)\n",
current_region,
p->region,
event->x,
event->y,
- p->sa->totrct.xmin,
- p->sa->totrct.ymin,
- p->sa->totrct.xmax,
- p->sa->totrct.ymax);
+ p->area->totrct.xmin,
+ p->area->totrct.ymin,
+ p->area->totrct.xmax,
+ p->area->totrct.ymax);
}
if (current_region) {
@@ -2228,7 +2646,7 @@ static int gpencil_draw_modal(bContext *C, wmOperator *op, const wmEvent *event)
p->paintmode = RNA_enum_get(op->ptr, "mode");
}
- gpencil_draw_toggle_eraser_cursor(C, p, p->paintmode == GP_PAINTMODE_ERASER);
+ gpencil_draw_toggle_eraser_cursor(p, p->paintmode == GP_PAINTMODE_ERASER);
/* not painting, so start stroke (this should be mouse-button down) */
p = gpencil_stroke_begin(C, op);
@@ -2315,7 +2733,7 @@ static int gpencil_draw_modal(bContext *C, wmOperator *op, const wmEvent *event)
}
/* gpencil modal operator stores area, which can be removed while using it (like fullscreen) */
- if (0 == gpencil_area_exists(C, p->sa)) {
+ if (0 == gpencil_area_exists(C, p->area)) {
estate = OPERATOR_CANCELLED;
}
else {
@@ -2370,6 +2788,19 @@ static const EnumPropertyItem prop_gpencil_drawmodes[] = {
{0, NULL, 0, NULL, NULL},
};
+static const EnumPropertyItem arrow_types[] = {
+ {GP_STROKE_ARROWSTYLE_NONE, "NONE", 0, "None", "Don't use any arrow/style in corner"},
+ {GP_STROKE_ARROWSTYLE_CLOSED, "ARROW", 0, "Arrow", "Use closed arrow style"},
+ {GP_STROKE_ARROWSTYLE_OPEN, "ARROW_OPEN", 0, "Open Arrow", "Use open arrow style"},
+ {GP_STROKE_ARROWSTYLE_SEGMENT,
+ "ARROW_OPEN_INVERTED",
+ 0,
+ "Segment",
+ "Use perpendicular segment style"},
+ {GP_STROKE_ARROWSTYLE_SQUARE, "DIAMOND", 0, "Square", "Use square style"},
+ {0, NULL, 0, NULL, NULL},
+};
+
void GPENCIL_OT_annotate(wmOperatorType *ot)
{
PropertyRNA *prop;
@@ -2393,6 +2824,37 @@ void GPENCIL_OT_annotate(wmOperatorType *ot)
ot->prop = RNA_def_enum(
ot->srna, "mode", prop_gpencil_drawmodes, 0, "Mode", "Way to interpret mouse movements");
+ /* properties */
+ prop = RNA_def_enum(
+ ot->srna, "arrowstyle_start", arrow_types, 0, "Start Arrow Style", "Stroke start style");
+ prop = RNA_def_enum(
+ ot->srna, "arrowstyle_end", arrow_types, 0, "End Arrow Style", "Stroke end style");
+ prop = RNA_def_boolean(ot->srna,
+ "use_stabilizer",
+ false,
+ "Stabilize Stroke",
+ "Helper to draw smooth and clean lines. Press Shift for an invert effect "
+ "(even if this option is not active)");
+ prop = RNA_def_float(ot->srna,
+ "stabilizer_factor",
+ 0.75f,
+ 0.0f,
+ 1.0f,
+ "Stabilizer Stroke Factor",
+ "Higher values gives a smoother stroke",
+ 0.0f,
+ 1.0f);
+ prop = RNA_def_int(ot->srna,
+ "stabilizer_radius",
+ 35,
+ 0,
+ 200,
+ "Stabilizer Stroke Radius",
+ "Minimun distance from last point before stroke continues",
+ 1,
+ 100);
+ RNA_def_property_subtype(prop, PROP_PIXEL);
+
prop = RNA_def_collection_runtime(ot->srna, "stroke", &RNA_OperatorStrokeElement, "Stroke", "");
RNA_def_property_flag(prop, PROP_HIDDEN | PROP_SKIP_SAVE);
diff --git a/source/blender/editors/gpencil/drawgpencil.c b/source/blender/editors/gpencil/drawgpencil.c
index 896ef7a9ad3..6d41e9bddbe 100644
--- a/source/blender/editors/gpencil/drawgpencil.c
+++ b/source/blender/editors/gpencil/drawgpencil.c
@@ -114,13 +114,6 @@ typedef enum eDrawStrokeFlags {
/* ----- Tool Buffer Drawing ------ */
/* helper functions to set color of buffer point */
-static void gp_set_point_uniform_color(const bGPDspoint *pt, const float ink[4])
-{
- float alpha = ink[3] * pt->strength;
- CLAMP(alpha, GPENCIL_STRENGTH_MIN, 1.0f);
- immUniformColor3fvAlpha(ink, alpha);
-}
-
static void gp_set_point_varying_color(const bGPDspoint *pt,
const float ink[4],
uint attr_id,
@@ -134,74 +127,8 @@ static void gp_set_point_varying_color(const bGPDspoint *pt,
immAttr4ub(attr_id, F2UB(ink[0]), F2UB(ink[1]), F2UB(ink[2]), F2UB(alpha));
}
-/* --------- 2D Stroke Drawing Helpers --------- */
-/* change in parameter list */
-static void gp_calc_2d_stroke_fxy(
- const float pt[3], short sflag, int offsx, int offsy, int winx, int winy, float r_co[2])
-{
- if (sflag & GP_STROKE_2DSPACE) {
- r_co[0] = pt[0];
- r_co[1] = pt[1];
- }
- else if (sflag & GP_STROKE_2DIMAGE) {
- const float x = (float)((pt[0] * winx) + offsx);
- const float y = (float)((pt[1] * winy) + offsy);
-
- r_co[0] = x;
- r_co[1] = y;
- }
- else {
- const float x = (float)(pt[0] / 100 * winx) + offsx;
- const float y = (float)(pt[1] / 100 * winy) + offsy;
-
- r_co[0] = x;
- r_co[1] = y;
- }
-}
/* ----------- Volumetric Strokes --------------- */
-/* draw a 2D strokes in "volumetric" style */
-static void gp_draw_stroke_volumetric_2d(const bGPDspoint *points,
- int totpoints,
- short thickness,
- short UNUSED(dflag),
- short sflag,
- int offsx,
- int offsy,
- int winx,
- int winy,
- const float diff_mat[4][4],
- const float ink[4])
-{
- GPUVertFormat *format = immVertexFormat();
- uint pos = GPU_vertformat_attr_add(format, "pos", GPU_COMP_F32, 2, GPU_FETCH_FLOAT);
- uint size = GPU_vertformat_attr_add(format, "size", GPU_COMP_F32, 1, GPU_FETCH_FLOAT);
- uint color = GPU_vertformat_attr_add(
- format, "color", GPU_COMP_U8, 4, GPU_FETCH_INT_TO_FLOAT_UNIT);
-
- immBindBuiltinProgram(GPU_SHADER_3D_POINT_VARYING_SIZE_VARYING_COLOR);
- GPU_program_point_size(true);
- immBegin(GPU_PRIM_POINTS, totpoints);
-
- const bGPDspoint *pt = points;
- for (int i = 0; i < totpoints; i++, pt++) {
- /* transform position to 2D */
- float co[2];
- float fpt[3];
-
- mul_v3_m4v3(fpt, diff_mat, &pt->x);
- gp_calc_2d_stroke_fxy(fpt, sflag, offsx, offsy, winx, winy, co);
-
- gp_set_point_varying_color(pt, ink, color, false);
- immAttr1f(size, pt->pressure * thickness); /* TODO: scale based on view transform */
- immVertex2f(pos, co[0], co[1]);
- }
-
- immEnd();
- immUnbindProgram();
- GPU_program_point_size(false);
-}
-
/* draw a 3D stroke in "volumetric" style */
static void gp_draw_stroke_volumetric_3d(const bGPDspoint *points,
int totpoints,
@@ -232,136 +159,8 @@ static void gp_draw_stroke_volumetric_3d(const bGPDspoint *points,
GPU_program_point_size(false);
}
-/* --------------- Stroke Fills ----------------- */
-/* add a new fill point and texture coordinates to vertex buffer */
-static void gp_add_filldata_tobuffer(const bGPDspoint *pt,
- uint pos,
- uint texcoord,
- short flag,
- int offsx,
- int offsy,
- int winx,
- int winy,
- const float diff_mat[4][4])
-{
- float fpt[3];
- float co[2];
-
- mul_v3_m4v3(fpt, diff_mat, &pt->x);
- /* if 2d, need conversion */
- if (!(flag & GP_STROKE_3DSPACE)) {
- gp_calc_2d_stroke_fxy(fpt, flag, offsx, offsy, winx, winy, co);
- copy_v2_v2(fpt, co);
- fpt[2] = 0.0f; /* 2d always is z=0.0f */
- }
-
- immAttr2f(texcoord, pt->uv_fill[0], pt->uv_fill[1]); /* texture coordinates */
- immVertex3fv(pos, fpt); /* position */
-}
-
-/* draw fills for shapes */
-static void gp_draw_stroke_fill(bGPdata *gpd,
- bGPDstroke *gps,
- int offsx,
- int offsy,
- int winx,
- int winy,
- const float diff_mat[4][4],
- const float color[4])
-{
- BLI_assert(gps->totpoints >= 3);
- BLI_assert(gps->tot_triangles >= 1);
- const bool use_mat = (gpd->mat != NULL);
-
- Material *ma = (use_mat) ? gpd->mat[gps->mat_nr] : BKE_material_default_gpencil();
- MaterialGPencilStyle *gp_style = (ma) ? ma->gp_style : NULL;
-
- GPUVertFormat *format = immVertexFormat();
- uint pos = GPU_vertformat_attr_add(format, "pos", GPU_COMP_F32, 3, GPU_FETCH_FLOAT);
- uint texcoord = GPU_vertformat_attr_add(format, "texCoord", GPU_COMP_F32, 2, GPU_FETCH_FLOAT);
- immBindBuiltinProgram(GPU_SHADER_GPENCIL_FILL);
-
- immUniformColor4fv(color);
- immUniform4fv("color2", gp_style->mix_rgba);
- immUniform1i("fill_type", gp_style->fill_style);
- immUniform1f("mix_factor", gp_style->mix_factor);
-
- immUniform1f("texture_angle", gp_style->texture_angle);
- immUniform2fv("texture_scale", gp_style->texture_scale);
- immUniform2fv("texture_offset", gp_style->texture_offset);
- immUniform1f("texture_opacity", gp_style->texture_opacity);
- immUniform1i("t_mix", (gp_style->flag & GP_MATERIAL_FILL_TEX_MIX) != 0);
- immUniform1i("t_flip", (gp_style->flag & GP_MATERIAL_FLIP_FILL) != 0);
-
- /* Draw all triangles for filling the polygon (cache must be calculated before) */
- immBegin(GPU_PRIM_TRIS, gps->tot_triangles * 3);
- /* TODO: use batch instead of immediate mode, to share vertices */
-
- const bGPDtriangle *stroke_triangle = gps->triangles;
- for (int i = 0; i < gps->tot_triangles; i++, stroke_triangle++) {
- for (int j = 0; j < 3; j++) {
- gp_add_filldata_tobuffer(&gps->points[stroke_triangle->verts[j]],
- pos,
- texcoord,
- gps->flag,
- offsx,
- offsy,
- winx,
- winy,
- diff_mat);
- }
- }
-
- immEnd();
- immUnbindProgram();
-}
-
/* ----- Existing Strokes Drawing (3D and Point) ------ */
-/* draw a given stroke - just a single dot (only one point) */
-static void gp_draw_stroke_point(const bGPDspoint *points,
- short thickness,
- short UNUSED(dflag),
- short sflag,
- int offsx,
- int offsy,
- int winx,
- int winy,
- const float diff_mat[4][4],
- const float ink[4])
-{
- const bGPDspoint *pt = points;
-
- /* get final position using parent matrix */
- float fpt[3];
- mul_v3_m4v3(fpt, diff_mat, &pt->x);
-
- GPUVertFormat *format = immVertexFormat();
- uint pos = GPU_vertformat_attr_add(format, "pos", GPU_COMP_F32, 3, GPU_FETCH_FLOAT);
-
- if (sflag & GP_STROKE_3DSPACE) {
- immBindBuiltinProgram(GPU_SHADER_3D_POINT_UNIFORM_SIZE_UNIFORM_COLOR_AA);
- }
- else {
- immBindBuiltinProgram(GPU_SHADER_2D_POINT_UNIFORM_SIZE_UNIFORM_COLOR_AA);
-
- /* get 2D coordinates of point */
- float co[3] = {0.0f};
- gp_calc_2d_stroke_fxy(fpt, sflag, offsx, offsy, winx, winy, co);
- copy_v3_v3(fpt, co);
- }
-
- gp_set_point_uniform_color(pt, ink);
- /* set point thickness (since there's only one of these) */
- immUniform1f("size", (float)(thickness + 2) * pt->pressure);
-
- immBegin(GPU_PRIM_POINTS, 1);
- immVertex3fv(pos, fpt);
- immEnd();
-
- immUnbindProgram();
-}
-
/* draw a given stroke in 3d (i.e. in 3d-space) */
static void gp_draw_stroke_3d(tGPDdraw *tgpw, short thickness, const float ink[4], bool cyclic)
{
@@ -454,200 +253,6 @@ static void gp_draw_stroke_3d(tGPDdraw *tgpw, short thickness, const float ink[4
immUnbindProgram();
}
-/* ----- Fancy 2D-Stroke Drawing ------ */
-
-/* draw a given stroke in 2d */
-static void gp_draw_stroke_2d(const bGPDspoint *points,
- int totpoints,
- short thickness_s,
- short dflag,
- short sflag,
- bool UNUSED(debug),
- int offsx,
- int offsy,
- int winx,
- int winy,
- const float diff_mat[4][4],
- const float ink[4])
-{
- /* otherwise thickness is twice that of the 3D view */
- float thickness = (float)thickness_s * 0.5f;
-
- /* strokes in Image Editor need a scale factor, since units there are not pixels! */
- float scalefac = 1.0f;
- if ((dflag & GP_DRAWDATA_IEDITHACK) && (dflag & GP_DRAWDATA_ONLYV2D)) {
- scalefac = 0.001f;
- }
-
- /* TODO: fancy++ with the magic of shaders */
-
- /* tessellation code - draw stroke as series of connected quads (triangle strips in fact)
- * with connection edges rotated to minimize shrinking artifacts, and rounded endcaps.
- */
- {
- const bGPDspoint *pt1, *pt2;
- float s0[2], s1[2]; /* segment 'center' points */
- float pm[2]; /* normal from previous segment. */
- int i;
- float fpt[3];
-
- GPUVertFormat *format = immVertexFormat();
- const struct {
- uint pos, color;
- } attr_id = {
- .pos = GPU_vertformat_attr_add(format, "pos", GPU_COMP_F32, 2, GPU_FETCH_FLOAT),
- .color = GPU_vertformat_attr_add(
- format, "color", GPU_COMP_U8, 4, GPU_FETCH_INT_TO_FLOAT_UNIT),
- };
-
- immBindBuiltinProgram(GPU_SHADER_2D_FLAT_COLOR);
- immBegin(GPU_PRIM_TRI_STRIP, totpoints * 2 + 4);
-
- /* get x and y coordinates from first point */
- mul_v3_m4v3(fpt, diff_mat, &points->x);
- gp_calc_2d_stroke_fxy(fpt, sflag, offsx, offsy, winx, winy, s0);
-
- for (i = 0, pt1 = points, pt2 = points + 1; i < (totpoints - 1); i++, pt1++, pt2++) {
- float t0[2], t1[2]; /* tessellated coordinates */
- float m1[2], m2[2]; /* gradient and normal */
- float mt[2], sc[2]; /* gradient for thickness, point for end-cap */
- float pthick; /* thickness at segment point */
-
- /* Get x and y coordinates from point2
- * (point1 has already been computed in previous iteration). */
- mul_v3_m4v3(fpt, diff_mat, &pt2->x);
- gp_calc_2d_stroke_fxy(fpt, sflag, offsx, offsy, winx, winy, s1);
-
- /* calculate gradient and normal - 'angle'=(ny/nx) */
- m1[1] = s1[1] - s0[1];
- m1[0] = s1[0] - s0[0];
- normalize_v2(m1);
- m2[1] = -m1[0];
- m2[0] = m1[1];
-
- /* always use pressure from first point here */
- pthick = (pt1->pressure * thickness * scalefac);
-
- /* color of point */
- gp_set_point_varying_color(pt1, ink, attr_id.color, false);
-
- /* if the first segment, start of segment is segment's normal */
- if (i == 0) {
- /* draw start cap first
- * - make points slightly closer to center (about halfway across)
- */
- mt[0] = m2[0] * pthick * 0.5f;
- mt[1] = m2[1] * pthick * 0.5f;
- sc[0] = s0[0] - (m1[0] * pthick * 0.75f);
- sc[1] = s0[1] - (m1[1] * pthick * 0.75f);
-
- t0[0] = sc[0] - mt[0];
- t0[1] = sc[1] - mt[1];
- t1[0] = sc[0] + mt[0];
- t1[1] = sc[1] + mt[1];
-
- /* First two points of cap. */
- immVertex2fv(attr_id.pos, t0);
- immVertex2fv(attr_id.pos, t1);
-
- /* calculate points for start of segment */
- mt[0] = m2[0] * pthick;
- mt[1] = m2[1] * pthick;
-
- t0[0] = s0[0] - mt[0];
- t0[1] = s0[1] - mt[1];
- t1[0] = s0[0] + mt[0];
- t1[1] = s0[1] + mt[1];
-
- /* Last two points of start cap (and first two points of first segment). */
- immVertex2fv(attr_id.pos, t0);
- immVertex2fv(attr_id.pos, t1);
- }
- /* if not the first segment, use bisector of angle between segments */
- else {
- float mb[2]; /* bisector normal */
- float athick, dfac; /* actual thickness, difference between thicknesses */
-
- /* calculate gradient of bisector (as average of normals) */
- mb[0] = (pm[0] + m2[0]) / 2;
- mb[1] = (pm[1] + m2[1]) / 2;
- normalize_v2(mb);
-
- /* calculate gradient to apply
- * - as basis, use just pthick * bisector gradient
- * - if cross-section not as thick as it should be, add extra padding to fix it
- */
- mt[0] = mb[0] * pthick;
- mt[1] = mb[1] * pthick;
- athick = len_v2(mt);
- dfac = pthick - (athick * 2);
-
- if (((athick * 2.0f) < pthick) && (IS_EQF(athick, pthick) == 0)) {
- mt[0] += (mb[0] * dfac);
- mt[1] += (mb[1] * dfac);
- }
-
- /* calculate points for start of segment */
- t0[0] = s0[0] - mt[0];
- t0[1] = s0[1] - mt[1];
- t1[0] = s0[0] + mt[0];
- t1[1] = s0[1] + mt[1];
-
- /* Last two points of previous segment, and first two points of current segment. */
- immVertex2fv(attr_id.pos, t0);
- immVertex2fv(attr_id.pos, t1);
- }
-
- /* if last segment, also draw end of segment (defined as segment's normal) */
- if (i == totpoints - 2) {
- /* for once, we use second point's pressure (otherwise it won't be drawn) */
- pthick = (pt2->pressure * thickness * scalefac);
-
- /* color of point */
- gp_set_point_varying_color(pt2, ink, attr_id.color, false);
-
- /* calculate points for end of segment */
- mt[0] = m2[0] * pthick;
- mt[1] = m2[1] * pthick;
-
- t0[0] = s1[0] - mt[0];
- t0[1] = s1[1] - mt[1];
- t1[0] = s1[0] + mt[0];
- t1[1] = s1[1] + mt[1];
-
- /* Last two points of last segment (and first two points of end cap). */
- immVertex2fv(attr_id.pos, t0);
- immVertex2fv(attr_id.pos, t1);
-
- /* draw end cap as last step
- * - make points slightly closer to center (about halfway across)
- */
- mt[0] = m2[0] * pthick * 0.5f;
- mt[1] = m2[1] * pthick * 0.5f;
- sc[0] = s1[0] + (m1[0] * pthick * 0.75f);
- sc[1] = s1[1] + (m1[1] * pthick * 0.75f);
-
- t0[0] = sc[0] - mt[0];
- t0[1] = sc[1] - mt[1];
- t1[0] = sc[0] + mt[0];
- t1[1] = sc[1] + mt[1];
-
- /* Last two points of end cap. */
- immVertex2fv(attr_id.pos, t0);
- immVertex2fv(attr_id.pos, t1);
- }
-
- /* store computed point2 coordinates as point1 ones of next segment. */
- copy_v2_v2(s0, s1);
- /* store stroke's 'natural' normal for next stroke to use */
- copy_v2_v2(pm, m2);
- }
-
- immEnd();
- immUnbindProgram();
- }
-}
-
/* ----- Strokes Drawing ------ */
/* Helper for doing all the checks on whether a stroke can be drawn */
@@ -691,7 +296,6 @@ static bool gp_can_draw_stroke(const bGPDstroke *gps, const int dflag)
static void gp_draw_strokes(tGPDdraw *tgpw)
{
float tcolor[4];
- float tfill[4];
short sthickness;
float ink[4];
const bool is_unique = (tgpw->gps != NULL);
@@ -748,37 +352,6 @@ static void gp_draw_strokes(tGPDdraw *tgpw)
bglPolygonOffset(1.0f, 1.0f);
}
- /* 3D Fill */
- // if ((dflag & GP_DRAWDATA_FILL) && (gps->totpoints >= 3)) {
- if ((gps->totpoints >= 3) && (tgpw->disable_fill != 1)) {
- /* set color using material, tint color and opacity */
- interp_v3_v3v3(tfill, gp_style->fill_rgba, tgpw->tintcolor, tgpw->tintcolor[3]);
- tfill[3] = gp_style->fill_rgba[3] * tgpw->opacity;
- if ((tfill[3] > GPENCIL_ALPHA_OPACITY_THRESH) || (gp_style->fill_style > 0)) {
- const float *color;
- if (!tgpw->onion) {
- color = tfill;
- }
- else {
- if (tgpw->custonion) {
- color = tgpw->tintcolor;
- }
- else {
- ARRAY_SET_ITEMS(tfill, UNPACK3(gp_style->fill_rgba), tgpw->tintcolor[3]);
- color = tfill;
- }
- }
- gp_draw_stroke_fill(tgpw->gpd,
- gps,
- tgpw->offsx,
- tgpw->offsy,
- tgpw->winx,
- tgpw->winy,
- tgpw->diff_mat,
- color);
- }
- }
-
/* 3D Stroke */
/* set color using material tint color and opacity */
if (!tgpw->onion) {
@@ -811,21 +384,7 @@ static void gp_draw_strokes(tGPDdraw *tgpw)
}
else {
/* 3D Lines - OpenGL primitives-based */
- if (gps->totpoints == 1) {
- if (tgpw->disable_fill != 1) {
- gp_draw_stroke_point(gps->points,
- sthickness,
- tgpw->dflag,
- gps->flag,
- tgpw->offsx,
- tgpw->offsy,
- tgpw->winx,
- tgpw->winy,
- tgpw->diff_mat,
- ink);
- }
- }
- else {
+ if (gps->totpoints > 1) {
tgpw->gps = gps;
gp_draw_stroke_3d(tgpw, sthickness, ink, gps->flag & GP_STROKE_CYCLIC);
}
@@ -837,97 +396,6 @@ static void gp_draw_strokes(tGPDdraw *tgpw)
bglPolygonOffset(0.0, 0.0);
}
}
- else {
- /* 2D - Fill */
- if (gps->totpoints >= 3) {
- /* set color using material, tint color and opacity */
- interp_v3_v3v3(tfill, gp_style->fill_rgba, tgpw->tintcolor, tgpw->tintcolor[3]);
- tfill[3] = gp_style->fill_rgba[3] * tgpw->opacity;
- if ((tfill[3] > GPENCIL_ALPHA_OPACITY_THRESH) || (gp_style->fill_style > 0)) {
- const float *color;
- if (!tgpw->onion) {
- color = tfill;
- }
- else {
- if (tgpw->custonion) {
- color = tgpw->tintcolor;
- }
- else {
- ARRAY_SET_ITEMS(tfill, UNPACK3(gp_style->fill_rgba), tgpw->tintcolor[3]);
- color = tfill;
- }
- }
- gp_draw_stroke_fill(tgpw->gpd,
- gps,
- tgpw->offsx,
- tgpw->offsy,
- tgpw->winx,
- tgpw->winy,
- tgpw->diff_mat,
- color);
- }
- }
-
- /* 2D Strokes... */
- /* set color using material, tint color and opacity */
- if (!tgpw->onion) {
- interp_v3_v3v3(tcolor, gp_style->stroke_rgba, tgpw->tintcolor, tgpw->tintcolor[3]);
- tcolor[3] = gp_style->stroke_rgba[3] * tgpw->opacity;
- copy_v4_v4(ink, tcolor);
- }
- else {
- if (tgpw->custonion) {
- copy_v4_v4(ink, tgpw->tintcolor);
- }
- else {
- ARRAY_SET_ITEMS(tcolor, UNPACK3(gp_style->stroke_rgba), tgpw->opacity);
- copy_v4_v4(ink, tcolor);
- }
- }
- if (gp_style->mode == GP_MATERIAL_MODE_DOT) {
- /* blob/disk-based "volumetric" drawing */
- gp_draw_stroke_volumetric_2d(gps->points,
- gps->totpoints,
- sthickness,
- tgpw->dflag,
- gps->flag,
- tgpw->offsx,
- tgpw->offsy,
- tgpw->winx,
- tgpw->winy,
- tgpw->diff_mat,
- ink);
- }
- else {
- /* normal 2D strokes */
- if (gps->totpoints == 1) {
- gp_draw_stroke_point(gps->points,
- sthickness,
- tgpw->dflag,
- gps->flag,
- tgpw->offsx,
- tgpw->offsy,
- tgpw->winx,
- tgpw->winy,
- tgpw->diff_mat,
- ink);
- }
- else {
- gp_draw_stroke_2d(gps->points,
- gps->totpoints,
- sthickness,
- tgpw->dflag,
- gps->flag,
- false,
- tgpw->offsx,
- tgpw->offsy,
- tgpw->winx,
- tgpw->winy,
- tgpw->diff_mat,
- ink);
- }
- }
- }
/* if only one stroke, exit from loop */
if (is_unique) {
break;
diff --git a/source/blender/editors/gpencil/gpencil_armature.c b/source/blender/editors/gpencil/gpencil_armature.c
index 9566495715a..962a74d9e6f 100644
--- a/source/blender/editors/gpencil/gpencil_armature.c
+++ b/source/blender/editors/gpencil/gpencil_armature.c
@@ -481,8 +481,7 @@ static void gpencil_object_vgroup_calc_from_armature(const bContext *C,
DEG_relations_tag_update(CTX_data_main(C));
}
-bool ED_gpencil_add_armature_weights(
- const bContext *C, ReportList *reports, Object *ob, Object *ob_arm, int mode)
+bool ED_gpencil_add_armature(const bContext *C, ReportList *reports, Object *ob, Object *ob_arm)
{
Main *bmain = CTX_data_main(C);
Scene *scene = CTX_data_scene(C);
@@ -492,7 +491,7 @@ bool ED_gpencil_add_armature_weights(
}
/* if no armature modifier, add a new one */
- GpencilModifierData *md = BKE_gpencil_modifiers_findByType(ob, eGpencilModifierType_Armature);
+ GpencilModifierData *md = BKE_gpencil_modifiers_findby_type(ob, eGpencilModifierType_Armature);
if (md == NULL) {
md = ED_object_gpencil_modifier_add(
reports, bmain, scene, ob, "Armature", eGpencilModifierType_Armature);
@@ -516,11 +515,24 @@ bool ED_gpencil_add_armature_weights(
return false;
}
}
+ return true;
+}
+
+bool ED_gpencil_add_armature_weights(
+ const bContext *C, ReportList *reports, Object *ob, Object *ob_arm, int mode)
+{
+ if (ob == NULL) {
+ return false;
+ }
+
+ bool success = ED_gpencil_add_armature(C, reports, ob, ob_arm);
/* add weights */
- gpencil_object_vgroup_calc_from_armature(C, ob, ob_arm, mode, DEFAULT_RATIO, DEFAULT_DECAY);
+ if (success) {
+ gpencil_object_vgroup_calc_from_armature(C, ob, ob_arm, mode, DEFAULT_RATIO, DEFAULT_DECAY);
+ }
- return true;
+ return success;
}
/* ***************** Generate armature weights ************************** */
static bool gpencil_generate_weights_poll(bContext *C)
@@ -543,7 +555,7 @@ static bool gpencil_generate_weights_poll(bContext *C)
}
/* need some armature in the view layer */
- for (Base *base = view_layer->object_bases.first; base; base = base->next) {
+ LISTBASE_FOREACH (Base *, base, &view_layer->object_bases) {
if (base->object->type == OB_ARMATURE) {
return true;
}
@@ -578,8 +590,8 @@ static int gpencil_generate_weights_exec(bContext *C, wmOperator *op)
}
else {
/* get armature from modifier */
- GpencilModifierData *md = BKE_gpencil_modifiers_findByType(ob_eval,
- eGpencilModifierType_Armature);
+ GpencilModifierData *md = BKE_gpencil_modifiers_findby_type(ob_eval,
+ eGpencilModifierType_Armature);
if (md == NULL) {
BKE_report(op->reports, RPT_ERROR, "The grease pencil object need an Armature modifier");
return OPERATOR_CANCELLED;
@@ -630,7 +642,7 @@ static const EnumPropertyItem *gpencil_armatures_enum_itemf(bContext *C,
RNA_enum_item_add(&item, &totitem, &item_tmp);
i++;
- for (Base *base = view_layer->object_bases.first; base; base = base->next) {
+ LISTBASE_FOREACH (Base *, base, &view_layer->object_bases) {
Object *ob = base->object;
if (ob->type == OB_ARMATURE) {
item_tmp.identifier = item_tmp.name = ob->id.name + 2;
diff --git a/source/blender/editors/gpencil/gpencil_convert.c b/source/blender/editors/gpencil/gpencil_convert.c
index 6e2c6936b1a..5441d4e24a6 100644
--- a/source/blender/editors/gpencil/gpencil_convert.c
+++ b/source/blender/editors/gpencil/gpencil_convert.c
@@ -152,7 +152,6 @@ static const EnumPropertyItem *rna_GPConvert_mode_items(bContext *UNUSED(C),
* - assumes that the active space is the 3D-View
*/
static void gp_strokepoint_convertcoords(bContext *C,
- bGPdata *UNUSED(gpd),
bGPDlayer *gpl,
bGPDstroke *gps,
bGPDspoint *source_pt,
@@ -163,7 +162,7 @@ static void gp_strokepoint_convertcoords(bContext *C,
View3D *v3d = CTX_wm_view3d(C);
ARegion *region = CTX_wm_region(C);
/* TODO(sergey): This function might be called from a loop, but no tagging is happening in it,
- * so it's not that expensive to ensure evaluated depsgraph here. However, ideally all the
+ * so it's not that expensive to ensure evaluated depsgraph here. However, ideally all the
* parameters are to wrapped into a context style struct and queried from Context once.*/
Depsgraph *depsgraph = CTX_data_ensure_evaluated_depsgraph(C);
Object *obact = CTX_data_active_object(C);
@@ -633,7 +632,6 @@ static void gp_stroke_to_path_add_point(tGpTimingData *gtd,
}
static void gp_stroke_to_path(bContext *C,
- bGPdata *gpd,
bGPDlayer *gpl,
bGPDstroke *gps,
Curve *cu,
@@ -708,7 +706,7 @@ static void gp_stroke_to_path(bContext *C,
bp = &nu->bp[old_nbp - 1];
/* First point */
- gp_strokepoint_convertcoords(C, gpd, gpl, gps, gps->points, p, subrect);
+ gp_strokepoint_convertcoords(C, gpl, gps, gps->points, p, subrect);
if (prev_bp) {
interp_v3_v3v3(p1, bp->vec, prev_bp->vec, -GAP_DFAC);
if (do_gtd) {
@@ -737,7 +735,7 @@ static void gp_stroke_to_path(bContext *C,
/* Second point */
/* Note dt2 is always negative, which marks the gap. */
if (gps->totpoints > 1) {
- gp_strokepoint_convertcoords(C, gpd, gpl, gps, gps->points + 1, next_p, subrect);
+ gp_strokepoint_convertcoords(C, gpl, gps, gps->points + 1, next_p, subrect);
interp_v3_v3v3(p2, p, next_p, -GAP_DFAC);
if (do_gtd) {
dt2 = interpf(gps->points[1].time, gps->points[0].time, -GAP_DFAC);
@@ -759,9 +757,9 @@ static void gp_stroke_to_path(bContext *C,
float p[3], next_p[3];
float dt = 0.0f;
- gp_strokepoint_convertcoords(C, gpd, gpl, gps, gps->points, p, subrect);
+ gp_strokepoint_convertcoords(C, gpl, gps, gps->points, p, subrect);
if (gps->totpoints > 1) {
- gp_strokepoint_convertcoords(C, gpd, gpl, gps, gps->points + 1, next_p, subrect);
+ gp_strokepoint_convertcoords(C, gpl, gps, gps->points + 1, next_p, subrect);
interp_v3_v3v3(p, p, next_p, -GAP_DFAC);
if (do_gtd) {
dt = interpf(gps->points[1].time, gps->points[0].time, -GAP_DFAC);
@@ -794,7 +792,7 @@ static void gp_stroke_to_path(bContext *C,
float width = pt->pressure * (gps->thickness + gpl->line_change) * WIDTH_CORR_FAC;
/* get coordinates to add at */
- gp_strokepoint_convertcoords(C, gpd, gpl, gps, pt, p, subrect);
+ gp_strokepoint_convertcoords(C, gpl, gps, pt, p, subrect);
gp_stroke_to_path_add_point(gtd,
bp,
@@ -882,7 +880,6 @@ static void gp_stroke_to_bezier_add_point(tGpTimingData *gtd,
}
static void gp_stroke_to_bezier(bContext *C,
- bGPdata *gpd,
bGPDlayer *gpl,
bGPDstroke *gps,
Curve *cu,
@@ -934,13 +931,12 @@ static void gp_stroke_to_bezier(bContext *C,
/* get initial coordinates */
pt = gps->points;
if (tot) {
- gp_strokepoint_convertcoords(C, gpd, gpl, gps, pt, (stitch) ? p3d_prev : p3d_cur, subrect);
+ gp_strokepoint_convertcoords(C, gpl, gps, pt, (stitch) ? p3d_prev : p3d_cur, subrect);
if (tot > 1) {
- gp_strokepoint_convertcoords(
- C, gpd, gpl, gps, pt + 1, (stitch) ? p3d_cur : p3d_next, subrect);
+ gp_strokepoint_convertcoords(C, gpl, gps, pt + 1, (stitch) ? p3d_cur : p3d_next, subrect);
}
if (stitch && tot > 2) {
- gp_strokepoint_convertcoords(C, gpd, gpl, gps, pt + 2, p3d_next, subrect);
+ gp_strokepoint_convertcoords(C, gpl, gps, pt + 2, p3d_next, subrect);
}
}
@@ -1106,7 +1102,7 @@ static void gp_stroke_to_bezier(bContext *C,
copy_v3_v3(p3d_cur, p3d_next);
if (i + 2 < tot) {
- gp_strokepoint_convertcoords(C, gpd, gpl, gps, pt + 2, p3d_next, subrect);
+ gp_strokepoint_convertcoords(C, gpl, gps, pt + 2, p3d_next, subrect);
}
prev_bezt = bezt;
@@ -1334,7 +1330,6 @@ static void gp_layer_to_curve(bContext *C,
switch (mode) {
case GP_STROKECONVERT_PATH:
gp_stroke_to_path(C,
- gpd,
gpl,
gps,
cu,
@@ -1350,7 +1345,6 @@ static void gp_layer_to_curve(bContext *C,
case GP_STROKECONVERT_CURVE:
case GP_STROKECONVERT_POLY: /* convert after */
gp_stroke_to_bezier(C,
- gpd,
gpl,
gps,
cu,
@@ -1471,12 +1465,12 @@ static bool gp_convert_poll(bContext *C)
bGPdata *gpd = (bGPdata *)ob->data;
bGPDlayer *gpl = NULL;
bGPDframe *gpf = NULL;
- ScrArea *sa = CTX_wm_area(C);
+ ScrArea *area = CTX_wm_area(C);
/* only if the current view is 3D View, if there's valid data (i.e. at least one stroke!),
* and if we are not in edit mode!
*/
- return ((sa && sa->spacetype == SPACE_VIEW3D) && (gpl = BKE_gpencil_layer_active_get(gpd)) &&
+ return ((area && area->spacetype == SPACE_VIEW3D) && (gpl = BKE_gpencil_layer_active_get(gpd)) &&
(gpf = BKE_gpencil_layer_frame_get(gpl, CFRA, GP_GETFRAME_USE_PREV)) &&
(gpf->strokes.first) && (!GPENCIL_ANY_EDIT_MODE(gpd)));
}
@@ -1828,7 +1822,7 @@ void GPENCIL_OT_image_to_grease_pencil(wmOperatorType *ot)
0.0001f,
10.0f,
"Point Size",
- "Size used for graese pencil points",
+ "Size used for grease pencil points",
0.001f,
1.0f);
RNA_def_property_flag(ot->prop, PROP_SKIP_SAVE);
diff --git a/source/blender/editors/gpencil/gpencil_data.c b/source/blender/editors/gpencil/gpencil_data.c
index 898facb86e8..8c80334bf8a 100644
--- a/source/blender/editors/gpencil/gpencil_data.c
+++ b/source/blender/editors/gpencil/gpencil_data.c
@@ -50,11 +50,12 @@
#include "DNA_space_types.h"
#include "DNA_view3d_types.h"
+#include "BKE_anim_data.h"
#include "BKE_animsys.h"
#include "BKE_brush.h"
#include "BKE_context.h"
#include "BKE_deform.h"
-#include "BKE_fcurve.h"
+#include "BKE_fcurve_driver.h"
#include "BKE_gpencil.h"
#include "BKE_gpencil_modifier.h"
#include "BKE_lib_id.h"
@@ -240,10 +241,8 @@ static int gp_layer_add_exec(bContext *C, wmOperator *op)
if ((ob != NULL) && (ob->type == OB_GPENCIL)) {
gpd = (bGPdata *)ob->data;
bGPDlayer *gpl = BKE_gpencil_layer_addnew(gpd, DATA_("GP_Layer"), true);
- ScrArea *sa = CTX_wm_area(C);
-
- /* In dopesheet add a new frame. */
- if ((gpl != NULL) && (sa->spacetype == SPACE_ACTION)) {
+ /* Add a new frame to make it visible in Dopesheet. */
+ if (gpl != NULL) {
gpl->actframe = BKE_gpencil_layer_frame_get(gpl, CFRA, GP_GETFRAME_ADD_NEW);
}
}
@@ -331,6 +330,7 @@ static int gp_layer_remove_exec(bContext *C, wmOperator *op)
/* notifiers */
DEG_id_tag_update(&gpd->id, ID_RECALC_TRANSFORM | ID_RECALC_GEOMETRY);
WM_event_add_notifier(C, NC_GPENCIL | ND_DATA | NA_EDITED, NULL);
+ WM_event_add_notifier(C, NC_GPENCIL | ND_DATA | NA_SELECTED, NULL);
return OPERATOR_FINISHED;
}
@@ -478,6 +478,7 @@ static int gp_layer_copy_exec(bContext *C, wmOperator *UNUSED(op))
/* notifiers */
DEG_id_tag_update(&gpd->id, ID_RECALC_TRANSFORM | ID_RECALC_GEOMETRY);
WM_event_add_notifier(C, NC_GPENCIL | ND_DATA | NA_EDITED, NULL);
+ WM_event_add_notifier(C, NC_GPENCIL | ND_DATA | NA_SELECTED, NULL);
return OPERATOR_FINISHED;
}
@@ -519,7 +520,7 @@ static bool gp_layer_duplicate_object_poll(bContext *C)
}
/* check there are more grease pencil objects */
- for (Base *base = view_layer->object_bases.first; base; base = base->next) {
+ LISTBASE_FOREACH (Base *, base, &view_layer->object_bases) {
if ((base->object != ob) && (base->object->type == OB_GPENCIL)) {
return true;
}
@@ -568,7 +569,7 @@ static int gp_layer_duplicate_object_exec(bContext *C, wmOperator *op)
gpl_dst->opacity = gpl_src->opacity;
/* Create all frames. */
- for (bGPDframe *gpf_src = gpl_src->frames.first; gpf_src; gpf_src = gpf_src->next) {
+ LISTBASE_FOREACH (bGPDframe *, gpf_src, &gpl_src->frames) {
if ((mode == GP_LAYER_COPY_OBJECT_ACT_FRAME) && (gpf_src != gpl_src->actframe)) {
continue;
@@ -578,7 +579,7 @@ static int gp_layer_duplicate_object_exec(bContext *C, wmOperator *op)
bGPDframe *gpf_dst = BKE_gpencil_frame_addnew(gpl_dst, gpf_src->framenum);
/* Copy strokes. */
- for (bGPDstroke *gps_src = gpf_src->strokes.first; gps_src; gps_src = gps_src->next) {
+ LISTBASE_FOREACH (bGPDstroke *, gps_src, &gpf_src->strokes) {
/* Make copy of source stroke. */
bGPDstroke *gps_dst = BKE_gpencil_stroke_duplicate(gps_src, true);
@@ -1181,12 +1182,12 @@ static int gp_merge_layer_exec(bContext *C, wmOperator *op)
/* Collect frames of gpl_current in hash table to avoid O(n^2) lookups */
GHash *gh_frames_cur = BLI_ghash_int_new_ex(__func__, 64);
- for (bGPDframe *gpf = gpl_current->frames.first; gpf; gpf = gpf->next) {
+ LISTBASE_FOREACH (bGPDframe *, gpf, &gpl_current->frames) {
BLI_ghash_insert(gh_frames_cur, POINTER_FROM_INT(gpf->framenum), gpf);
}
/* read all frames from next layer and add any missing in current layer */
- for (bGPDframe *gpf = gpl_next->frames.first; gpf; gpf = gpf->next) {
+ LISTBASE_FOREACH (bGPDframe *, gpf, &gpl_next->frames) {
/* try to find frame in current layer */
bGPDframe *frame = BLI_ghash_lookup(gh_frames_cur, POINTER_FROM_INT(gpf->framenum));
if (!frame) {
@@ -1228,6 +1229,7 @@ static int gp_merge_layer_exec(bContext *C, wmOperator *op)
/* notifiers */
DEG_id_tag_update(&gpd->id, ID_RECALC_TRANSFORM | ID_RECALC_GEOMETRY);
WM_event_add_notifier(C, NC_GPENCIL | ND_DATA | NA_EDITED, NULL);
+ WM_event_add_notifier(C, NC_GPENCIL | ND_DATA | NA_SELECTED, NULL);
return OPERATOR_FINISHED;
}
@@ -1291,6 +1293,7 @@ static int gp_layer_change_exec(bContext *C, wmOperator *op)
/* updates */
DEG_id_tag_update(&gpd->id, ID_RECALC_TRANSFORM | ID_RECALC_GEOMETRY);
WM_event_add_notifier(C, NC_GPENCIL | ND_DATA | NA_EDITED, NULL);
+ WM_event_add_notifier(C, NC_GPENCIL | ND_DATA | NA_SELECTED, NULL);
return OPERATOR_FINISHED;
}
@@ -1336,6 +1339,7 @@ static int gp_layer_active_exec(bContext *C, wmOperator *op)
/* updates */
DEG_id_tag_update(&gpd->id, ID_RECALC_TRANSFORM | ID_RECALC_GEOMETRY);
WM_event_add_notifier(C, NC_GPENCIL | ND_DATA | NA_EDITED, NULL);
+ WM_event_add_notifier(C, NC_GPENCIL | ND_DATA | NA_SELECTED, NULL);
return OPERATOR_FINISHED;
}
@@ -1433,7 +1437,7 @@ static int gp_stroke_arrange_exec(bContext *C, wmOperator *op)
switch (direction) {
/* Bring to Front */
case GP_STROKE_MOVE_TOP:
- for (LinkData *link = selected.first; link; link = link->next) {
+ LISTBASE_FOREACH (LinkData *, link, &selected) {
gps = link->data;
BLI_remlink(&gpf->strokes, gps);
BLI_addtail(&gpf->strokes, gps);
@@ -1448,7 +1452,7 @@ static int gp_stroke_arrange_exec(bContext *C, wmOperator *op)
break;
/* Send Backward */
case GP_STROKE_MOVE_DOWN:
- for (LinkData *link = selected.first; link; link = link->next) {
+ LISTBASE_FOREACH (LinkData *, link, &selected) {
gps = link->data;
BLI_listbase_link_move(&gpf->strokes, gps, -1);
}
@@ -1903,19 +1907,19 @@ static int gp_brush_reset_all_exec(bContext *C, wmOperator *UNUSED(op))
switch (mode) {
case CTX_MODE_PAINT_GPENCIL: {
- BKE_brush_gpencil_paint_presets(bmain, ts);
+ BKE_brush_gpencil_paint_presets(bmain, ts, true);
break;
}
case CTX_MODE_SCULPT_GPENCIL: {
- BKE_brush_gpencil_sculpt_presets(bmain, ts);
+ BKE_brush_gpencil_sculpt_presets(bmain, ts, true);
break;
}
case CTX_MODE_WEIGHT_GPENCIL: {
- BKE_brush_gpencil_weight_presets(bmain, ts);
+ BKE_brush_gpencil_weight_presets(bmain, ts, true);
break;
}
case CTX_MODE_VERTEX_GPENCIL: {
- BKE_brush_gpencil_vertex_presets(bmain, ts);
+ BKE_brush_gpencil_vertex_presets(bmain, ts, true);
break;
}
default: {
@@ -2523,7 +2527,7 @@ static void joined_gpencil_fix_animdata_cb(ID *id, FCurve *fcu, void *user_data)
/* Fix driver targets */
if (fcu->driver) {
/* Fix driver references to invalid ID's */
- for (DriverVar *dvar = fcu->driver->variables.first; dvar; dvar = dvar->next) {
+ LISTBASE_FOREACH (DriverVar *, dvar, &fcu->driver->variables) {
/* Only change the used targets, since the others will need fixing manually anyway. */
DRIVER_TARGETS_USED_LOOPER_BEGIN (dvar) {
/* Change the ID's used. */
@@ -2614,8 +2618,8 @@ int ED_gpencil_join_objects_exec(bContext *C, wmOperator *op)
bGPdata *gpd_src = ob_iter->data;
/* Apply all GP modifiers before */
- for (GpencilModifierData *md = ob_iter->greasepencil_modifiers.first; md; md = md->next) {
- const GpencilModifierTypeInfo *mti = BKE_gpencil_modifierType_getInfo(md->type);
+ LISTBASE_FOREACH (GpencilModifierData *, md, &ob_iter->greasepencil_modifiers) {
+ const GpencilModifierTypeInfo *mti = BKE_gpencil_modifier_get_info(md->type);
if (mti->bakeModifier) {
mti->bakeModifier(bmain, depsgraph, md, ob_iter);
}
@@ -2623,7 +2627,7 @@ int ED_gpencil_join_objects_exec(bContext *C, wmOperator *op)
/* copy vertex groups to the base one's */
int old_idx = 0;
- for (bDeformGroup *dg = ob_iter->defbase.first; dg; dg = dg->next) {
+ LISTBASE_FOREACH (bDeformGroup *, dg, &ob_iter->defbase) {
bDeformGroup *vgroup = MEM_dupallocN(dg);
int idx = BLI_listbase_count(&ob_active->defbase);
BKE_object_defgroup_unique_name(vgroup, ob_active);
@@ -2675,7 +2679,7 @@ int ED_gpencil_join_objects_exec(bContext *C, wmOperator *op)
mul_m3_v3(imat, offset_global);
mul_v3_m3v3(offset_local, imat, offset_global);
- for (bGPDlayer *gpl_src = gpd_src->layers.first; gpl_src; gpl_src = gpl_src->next) {
+ LISTBASE_FOREACH (bGPDlayer *, gpl_src, &gpd_src->layers) {
bGPDlayer *gpl_new = BKE_gpencil_layer_duplicate(gpl_src);
float diff_mat[4][4];
float inverse_diff_mat[4][4];
@@ -2685,7 +2689,7 @@ int ED_gpencil_join_objects_exec(bContext *C, wmOperator *op)
invert_m4_m4(inverse_diff_mat, diff_mat);
Material *ma_src = NULL;
- for (bGPDframe *gpf = gpl_new->frames.first; gpf; gpf = gpf->next) {
+ LISTBASE_FOREACH (bGPDframe *, gpf, &gpl_new->frames) {
LISTBASE_FOREACH (bGPDstroke *, gps, &gpf->strokes) {
/* Reassign material. Look old material and try to find in destination. */
@@ -3189,7 +3193,7 @@ void GPENCIL_OT_material_unlock_all(wmOperatorType *ot)
/* ***************** Select all strokes using color ************************ */
-static int gpencil_select_material_exec(bContext *C, wmOperator *op)
+static int gpencil_material_select_exec(bContext *C, wmOperator *op)
{
bGPdata *gpd = ED_gpencil_data_get_active(C);
Object *ob = CTX_data_active_object(C);
@@ -3259,15 +3263,15 @@ static int gpencil_select_material_exec(bContext *C, wmOperator *op)
return OPERATOR_FINISHED;
}
-void GPENCIL_OT_select_material(wmOperatorType *ot)
+void GPENCIL_OT_material_select(wmOperatorType *ot)
{
/* identifiers */
ot->name = "Select Material";
- ot->idname = "GPENCIL_OT_select_material";
+ ot->idname = "GPENCIL_OT_material_select";
ot->description = "Select/Deselect all Grease Pencil strokes using current material";
/* callbacks */
- ot->exec = gpencil_select_material_exec;
+ ot->exec = gpencil_material_select_exec;
ot->poll = gpencil_active_material_poll;
/* flags */
@@ -3278,6 +3282,48 @@ void GPENCIL_OT_select_material(wmOperatorType *ot)
RNA_def_property_flag(ot->prop, PROP_HIDDEN | PROP_SKIP_SAVE);
}
+/* ***************** Set active material ************************* */
+static int gpencil_material_set_exec(bContext *C, wmOperator *op)
+{
+ Object *ob = CTX_data_active_object(C);
+ int slot = RNA_enum_get(op->ptr, "slot");
+
+ /* Try to get material */
+ if ((slot < 1) || (slot > ob->totcol)) {
+ BKE_reportf(
+ op->reports, RPT_ERROR, "Cannot change to non-existent material (index = %d)", slot);
+ return OPERATOR_CANCELLED;
+ }
+
+ /* Set active material. */
+ ob->actcol = slot;
+
+ /* updates */
+ WM_event_add_notifier(C, NC_GPENCIL | ND_DATA | NA_EDITED, NULL);
+ WM_event_add_notifier(C, NC_GPENCIL | ND_DATA | NA_SELECTED, NULL);
+
+ return OPERATOR_FINISHED;
+}
+
+void GPENCIL_OT_material_set(wmOperatorType *ot)
+{
+ /* identifiers */
+ ot->name = "Set Material";
+ ot->idname = "GPENCIL_OT_material_set";
+ ot->description = "Set active material";
+
+ /* callbacks */
+ ot->exec = gpencil_material_set_exec;
+ ot->poll = gpencil_active_material_poll;
+
+ /* flags */
+ ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
+
+ /* Material to use (dynamic enum) */
+ ot->prop = RNA_def_enum(ot->srna, "slot", DummyRNA_DEFAULT_items, 0, "Material Slot", "");
+ RNA_def_enum_funcs(ot->prop, ED_gpencil_material_enum_itemf);
+}
+
/* ***************** Set selected stroke material the active material ************************ */
static int gpencil_set_active_material_exec(bContext *C, wmOperator *op)
@@ -3340,7 +3386,7 @@ bool ED_gpencil_add_lattice_modifier(const bContext *C,
}
/* if no lattice modifier, add a new one */
- GpencilModifierData *md = BKE_gpencil_modifiers_findByType(ob, eGpencilModifierType_Lattice);
+ GpencilModifierData *md = BKE_gpencil_modifiers_findby_type(ob, eGpencilModifierType_Lattice);
if (md == NULL) {
md = ED_object_gpencil_modifier_add(
reports, bmain, scene, ob, "Lattice", eGpencilModifierType_Lattice);
diff --git a/source/blender/editors/gpencil/gpencil_edit.c b/source/blender/editors/gpencil/gpencil_edit.c
index 1b42334499e..8771fcb0c8d 100644
--- a/source/blender/editors/gpencil/gpencil_edit.c
+++ b/source/blender/editors/gpencil/gpencil_edit.c
@@ -77,6 +77,7 @@
#include "ED_gpencil.h"
#include "ED_object.h"
+#include "ED_outliner.h"
#include "ED_screen.h"
#include "ED_select_utils.h"
#include "ED_space_api.h"
@@ -89,8 +90,9 @@
#include "gpencil_intern.h"
-/* ************************************************ */
-/* Stroke Edit Mode Management */
+/* -------------------------------------------------------------------- */
+/** \name Stroke Edit Mode Management
+ * \{ */
/* poll callback for all stroke editing operators */
static bool gp_stroke_edit_poll(bContext *C)
@@ -137,6 +139,12 @@ static bool gpencil_editmode_toggle_poll(bContext *C)
return ED_gpencil_data_get_active(C) != NULL;
}
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Toggle Edit Mode Operator
+ * \{ */
+
static int gpencil_editmode_toggle_exec(bContext *C, wmOperator *op)
{
const int back = RNA_boolean_get(op->ptr, "back");
@@ -222,6 +230,12 @@ void GPENCIL_OT_editmode_toggle(wmOperatorType *ot)
RNA_def_property_flag(prop, PROP_HIDDEN | PROP_SKIP_SAVE);
}
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Toggle Select Mode Operator
+ * \{ */
+
/* set select mode */
static bool gpencil_selectmode_toggle_poll(bContext *C)
{
@@ -297,7 +311,11 @@ void GPENCIL_OT_selectmode_toggle(wmOperatorType *ot)
RNA_def_property_flag(prop, PROP_HIDDEN | PROP_SKIP_SAVE);
}
-/* Stroke Paint Mode Management */
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Toggle Stroke Paint Mode Operator
+ * \{ */
static bool gpencil_paintmode_toggle_poll(bContext *C)
{
@@ -351,12 +369,20 @@ static int gpencil_paintmode_toggle_exec(bContext *C, wmOperator *op)
}
if (mode == OB_MODE_PAINT_GPENCIL) {
- /* be sure we have brushes */
+ /* Be sure we have brushes and Paint settings.
+ * Need Draw and Vertex (used for Tint). */
BKE_paint_ensure(ts, (Paint **)&ts->gp_paint);
+ BKE_paint_ensure(ts, (Paint **)&ts->gp_vertexpaint);
+
+ BKE_brush_gpencil_paint_presets(bmain, ts, false);
+
+ /* Ensure Palette by default. */
+ BKE_gpencil_palette_ensure(bmain, CTX_data_scene(C));
+
Paint *paint = &ts->gp_paint->paint;
/* if not exist, create a new one */
if ((paint->brush == NULL) || (paint->brush->gpencil_settings == NULL)) {
- BKE_brush_gpencil_paint_presets(bmain, ts);
+ BKE_brush_gpencil_paint_presets(bmain, ts, true);
}
BKE_paint_toolslots_brush_validate(bmain, &ts->gp_paint->paint);
}
@@ -401,7 +427,11 @@ void GPENCIL_OT_paintmode_toggle(wmOperatorType *ot)
RNA_def_property_flag(prop, PROP_HIDDEN | PROP_SKIP_SAVE);
}
-/* Stroke Sculpt Mode Management */
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Toggle Stroke Sculpt Mode Operator
+ * \{ */
static bool gpencil_sculptmode_toggle_poll(bContext *C)
{
@@ -455,8 +485,12 @@ static int gpencil_sculptmode_toggle_exec(bContext *C, wmOperator *op)
}
if (mode == OB_MODE_SCULPT_GPENCIL) {
- /* be sure we have brushes */
+ /* Be sure we have brushes. */
BKE_paint_ensure(ts, (Paint **)&ts->gp_sculptpaint);
+
+ const bool reset_mode = (ts->gp_sculptpaint->paint.brush == NULL);
+ BKE_brush_gpencil_sculpt_presets(bmain, ts, reset_mode);
+
BKE_paint_toolslots_brush_validate(bmain, &ts->gp_sculptpaint->paint);
}
@@ -478,6 +512,12 @@ static int gpencil_sculptmode_toggle_exec(bContext *C, wmOperator *op)
return OPERATOR_FINISHED;
}
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Toggle Weight Paint Mode Operator
+ * \{ */
+
void GPENCIL_OT_sculptmode_toggle(wmOperatorType *ot)
{
PropertyRNA *prop;
@@ -554,8 +594,12 @@ static int gpencil_weightmode_toggle_exec(bContext *C, wmOperator *op)
}
if (mode == OB_MODE_WEIGHT_GPENCIL) {
- /* be sure we have brushes */
+ /* Be sure we have brushes. */
BKE_paint_ensure(ts, (Paint **)&ts->gp_weightpaint);
+
+ const bool reset_mode = (ts->gp_weightpaint->paint.brush == NULL);
+ BKE_brush_gpencil_weight_presets(bmain, ts, reset_mode);
+
BKE_paint_toolslots_brush_validate(bmain, &ts->gp_weightpaint->paint);
}
@@ -599,7 +643,11 @@ void GPENCIL_OT_weightmode_toggle(wmOperatorType *ot)
RNA_def_property_flag(prop, PROP_HIDDEN | PROP_SKIP_SAVE);
}
-/* Vertex Paint Mode Management */
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Toggle Vertex Paint Mode Operator
+ * \{ */
static bool gpencil_vertexmode_toggle_poll(bContext *C)
{
@@ -652,9 +700,16 @@ static int gpencil_vertexmode_toggle_exec(bContext *C, wmOperator *op)
}
if (mode == OB_MODE_VERTEX_GPENCIL) {
- /* be sure we have brushes */
+ /* Be sure we have brushes. */
BKE_paint_ensure(ts, (Paint **)&ts->gp_vertexpaint);
+
+ const bool reset_mode = (ts->gp_vertexpaint->paint.brush == NULL);
+ BKE_brush_gpencil_vertex_presets(bmain, ts, reset_mode);
+
BKE_paint_toolslots_brush_validate(bmain, &ts->gp_vertexpaint->paint);
+
+ /* Ensure Palette by default. */
+ BKE_gpencil_palette_ensure(bmain, CTX_data_scene(C));
}
/* setup other modes */
@@ -697,10 +752,11 @@ void GPENCIL_OT_vertexmode_toggle(wmOperatorType *ot)
RNA_def_property_flag(prop, PROP_HIDDEN | PROP_SKIP_SAVE);
}
-/* ************************************************ */
-/* Stroke Editing Operators */
+/** \} */
-/* ************ Stroke Hide selection Toggle ************** */
+/* -------------------------------------------------------------------- */
+/** \name Stroke Hide Selection Toggle Operator
+ * \{ */
static int gpencil_hideselect_toggle_exec(bContext *C, wmOperator *UNUSED(op))
{
@@ -739,7 +795,11 @@ void GPENCIL_OT_selection_opacity_toggle(wmOperatorType *ot)
ot->flag = OPTYPE_UNDO | OPTYPE_REGISTER;
}
-/* ************** Duplicate Selected Strokes **************** */
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Duplicate Selected Strokes Operator
+ * \{ */
/* Make copies of selected point segments in a selected stroke */
static void gp_duplicate_points(const bGPDstroke *gps,
@@ -916,7 +976,11 @@ void GPENCIL_OT_duplicate(wmOperatorType *ot)
ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
}
-/* ************** Extrude Selected Strokes **************** */
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Extrude Selected Strokes Operator
+ * \{ */
/* helper to copy a point to temp area */
static void copy_move_point(bGPDstroke *gps,
@@ -1137,14 +1201,18 @@ void GPENCIL_OT_extrude(wmOperatorType *ot)
ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
}
-/* ******************* Copy/Paste Strokes ************************* */
-/* Grease Pencil stroke data copy/paste buffer:
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Copy/Paste Strokes Utilities
+ *
+ * Grease Pencil stroke data copy/paste buffer:
* - The copy operation collects all segments of selected strokes,
* dumping "ready to be copied" copies of the strokes into the buffer.
* - The paste operation makes a copy of those elements, and adds them
* to the active layer. This effectively flattens down the strokes
* from several different layers into a single layer.
- */
+ * \{ */
/* list of bGPDstroke instances */
/* NOTE: is exposed within the editors/gpencil module so that other tools can use it too */
@@ -1256,8 +1324,11 @@ GHash *gp_copybuf_validate_colormap(bContext *C)
return new_colors;
}
-/* --------------------- */
-/* Copy selected strokes */
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Copy Selected Strokes Operator
+ * \{ */
static int gp_strokes_copy_exec(bContext *C, wmOperator *op)
{
@@ -1333,7 +1404,7 @@ static int gp_strokes_copy_exec(bContext *C, wmOperator *op)
if (gp_strokes_copypastebuf.first) {
gp_strokes_copypastebuf_colors = BLI_ghash_int_new("GPencil CopyBuf Colors");
GHash *ma_to_name = gp_strokes_copypastebuf_colors_material_to_name_create(bmain);
- for (bGPDstroke *gps = gp_strokes_copypastebuf.first; gps; gps = gps->next) {
+ LISTBASE_FOREACH (bGPDstroke *, gps, &gp_strokes_copypastebuf) {
if (ED_gpencil_stroke_can_use(C, gps)) {
Material *ma = BKE_object_material_get(ob, gps->mat_nr + 1);
/* Avoid default material. */
@@ -1374,13 +1445,16 @@ void GPENCIL_OT_copy(wmOperatorType *ot)
// ot->flag = OPTYPE_REGISTER;
}
-/* --------------------- */
-/* Paste selected strokes */
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Paste Selected Strokes Operator
+ * \{ */
static bool gp_strokes_paste_poll(bContext *C)
{
- ScrArea *sa = CTX_wm_area(C);
- if (!((sa != NULL) && (sa->spacetype == SPACE_VIEW3D))) {
+ ScrArea *area = CTX_wm_area(C);
+ if (!((area != NULL) && (area->spacetype == SPACE_VIEW3D))) {
return false;
}
/* 1) Must have GP datablock to paste to
@@ -1546,7 +1620,11 @@ void GPENCIL_OT_paste(wmOperatorType *ot)
RNA_def_property_flag(prop, PROP_SKIP_SAVE);
}
-/* ******************* Move To Layer ****************************** */
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Move To Layer Operator
+ * \{ */
static int gp_move_to_layer_exec(bContext *C, wmOperator *op)
{
@@ -1569,7 +1647,13 @@ static int gp_move_to_layer_exec(bContext *C, wmOperator *op)
}
/* Try to get layer */
- target_layer = BLI_findlink(&gpd->layers, layer_num);
+ if (layer_num > -1) {
+ target_layer = BLI_findlink(&gpd->layers, layer_num);
+ }
+ else {
+ /* Create a new layer. */
+ target_layer = BKE_gpencil_layer_addnew(gpd, "GP_Layer", true);
+ }
if (target_layer == NULL) {
/* back autolock status */
@@ -1655,11 +1739,16 @@ void GPENCIL_OT_move_to_layer(wmOperatorType *ot)
ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
/* GPencil layer to use. */
- ot->prop = RNA_def_int(ot->srna, "layer", 0, 0, INT_MAX, "Grease Pencil Layer", "", 0, INT_MAX);
+ ot->prop = RNA_def_int(
+ ot->srna, "layer", 0, -1, INT_MAX, "Grease Pencil Layer", "", -1, INT_MAX);
RNA_def_property_flag(ot->prop, PROP_HIDDEN | PROP_SKIP_SAVE);
}
-/* ********************* Add Blank Frame *************************** */
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Add Blank Frame Operator
+ * \{ */
static int gp_blank_frame_add_exec(bContext *C, wmOperator *op)
{
@@ -1733,7 +1822,11 @@ void GPENCIL_OT_blank_frame_add(wmOperatorType *ot)
RNA_def_property_flag(prop, PROP_SKIP_SAVE);
}
-/* ******************* Delete Active Frame ************************ */
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Delete Active Frame Operator
+ * \{ */
static bool gp_actframe_delete_poll(bContext *C)
{
@@ -1814,7 +1907,12 @@ void GPENCIL_OT_annotation_active_frame_delete(wmOperatorType *ot)
ot->exec = gp_actframe_delete_exec;
ot->poll = gp_annotation_actframe_delete_poll;
}
-/* **************** Delete All Active Frames ****************** */
+
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Delete All Active Frames
+ * \{ */
static bool gp_actframe_delete_all_poll(bContext *C)
{
@@ -1875,7 +1973,11 @@ void GPENCIL_OT_active_frames_delete_all(wmOperatorType *ot)
ot->poll = gp_actframe_delete_all_poll;
}
-/* ******************* Delete Operator ************************ */
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Delete/Dissolve Utilities
+ * \{ */
typedef enum eGP_DeleteMode {
/* delete selected stroke points */
@@ -1895,8 +1997,6 @@ typedef enum eGP_DissolveMode {
GP_DISSOLVE_UNSELECT = 2,
} eGP_DissolveMode;
-/* ----------------------------------- */
-
/* Delete selected strokes */
static int gp_delete_selected_strokes(bContext *C)
{
@@ -2490,7 +2590,11 @@ int gp_delete_selected_point_wrap(bContext *C)
return gp_delete_selected_points(C);
}
-/* ----------------------------------- */
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Delete Operator
+ * \{ */
static int gp_delete_exec(bContext *C, wmOperator *op)
{
@@ -2549,6 +2653,12 @@ void GPENCIL_OT_delete(wmOperatorType *ot)
"Method used for deleting Grease Pencil data");
}
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Dissolve Operator
+ * \{ */
+
static int gp_dissolve_exec(bContext *C, wmOperator *op)
{
eGP_DissolveMode mode = RNA_enum_get(op->ptr, "type");
@@ -2591,7 +2701,11 @@ void GPENCIL_OT_dissolve(wmOperatorType *ot)
"Method used for dissolving Stroke points");
}
-/* ****************** Snapping - Strokes <-> Cursor ************************ */
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Snapping Selection to Grid Operator
+ * \{ */
/* Poll callback for snap operators */
/* NOTE: For now, we only allow these in the 3D view, as other editors do not
@@ -2599,15 +2713,13 @@ void GPENCIL_OT_dissolve(wmOperatorType *ot)
*/
static bool gp_snap_poll(bContext *C)
{
- ScrArea *sa = CTX_wm_area(C);
+ ScrArea *area = CTX_wm_area(C);
Object *ob = CTX_data_active_object(C);
return (ob != NULL) && (ob->type == OB_GPENCIL) &&
- ((sa != NULL) && (sa->spacetype == SPACE_VIEW3D));
+ ((area != NULL) && (area->spacetype == SPACE_VIEW3D));
}
-/* --------------------------------- */
-
static int gp_snap_to_grid(bContext *C, wmOperator *UNUSED(op))
{
bGPdata *gpd = ED_gpencil_data_get_active(C);
@@ -2682,7 +2794,11 @@ void GPENCIL_OT_snap_to_grid(wmOperatorType *ot)
ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
}
-/* ------------------------------- */
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Snapping Selection to Cursor Operator
+ * \{ */
static int gp_snap_to_cursor(bContext *C, wmOperator *op)
{
@@ -2774,7 +2890,11 @@ void GPENCIL_OT_snap_to_cursor(wmOperatorType *ot)
"Offset the entire stroke instead of selected points only");
}
-/* ------------------------------- */
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Snapping Cursor to Selection Operator
+ * \{ */
static int gp_snap_cursor_to_sel(bContext *C, wmOperator *UNUSED(op))
{
@@ -2865,7 +2985,11 @@ void GPENCIL_OT_snap_cursor_to_selected(wmOperatorType *ot)
ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
}
-/* ******************* Apply layer thickness change to strokes ************************** */
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Apply Layer Thickness Change to Strokes Operator
+ * \{ */
static int gp_stroke_apply_thickness_exec(bContext *C, wmOperator *UNUSED(op))
{
@@ -2912,7 +3036,11 @@ void GPENCIL_OT_stroke_apply_thickness(wmOperatorType *ot)
ot->poll = gp_active_layer_poll;
}
-/* ******************* Close Strokes ************************** */
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Stroke Toggle Cyclic Operator
+ * \{ */
enum {
GP_STROKE_CYCLIC_CLOSE = 1,
@@ -3032,7 +3160,11 @@ void GPENCIL_OT_stroke_cyclical_set(wmOperatorType *ot)
RNA_def_property_flag(prop, PROP_SKIP_SAVE);
}
-/* ******************* Flat Stroke Caps ************************** */
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Stroke Toggle Flat Caps Operator
+ * \{ */
enum {
GP_STROKE_CAPS_TOGGLE_BOTH = 0,
@@ -3128,7 +3260,11 @@ void GPENCIL_OT_stroke_caps_set(wmOperatorType *ot)
ot->prop = RNA_def_enum(ot->srna, "type", toggle_type, GP_STROKE_CAPS_TOGGLE_BOTH, "Type", "");
}
-/* ******************* Stroke join ************************** */
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Stroke Join Operator
+ * \{ */
/* Helper: flip stroke */
static void gpencil_flip_stroke(bGPDstroke *gps)
@@ -3178,8 +3314,8 @@ static void gpencil_flip_stroke(bGPDstroke *gps)
/* Helper: copy point between strokes */
static void gpencil_stroke_copy_point(bGPDstroke *gps,
+ MDeformVert *dvert,
bGPDspoint *point,
- int idx,
const float delta[3],
float pressure,
float strength,
@@ -3191,6 +3327,13 @@ static void gpencil_stroke_copy_point(bGPDstroke *gps,
if (gps->dvert != NULL) {
gps->dvert = MEM_reallocN(gps->dvert, sizeof(MDeformVert) * (gps->totpoints + 1));
}
+ else {
+ /* If destination has weight add weight to origin. */
+ if (dvert != NULL) {
+ gps->dvert = MEM_callocN(sizeof(MDeformVert) * (gps->totpoints + 1), __func__);
+ }
+ }
+
gps->totpoints++;
newpoint = &gps->points[gps->totpoints - 1];
@@ -3204,11 +3347,16 @@ static void gpencil_stroke_copy_point(bGPDstroke *gps,
copy_v4_v4(newpoint->vert_color, point->vert_color);
if (gps->dvert != NULL) {
- MDeformVert *dvert = &gps->dvert[idx];
MDeformVert *newdvert = &gps->dvert[gps->totpoints - 1];
- newdvert->totweight = dvert->totweight;
- newdvert->dw = MEM_dupallocN(dvert->dw);
+ if (dvert != NULL) {
+ newdvert->totweight = dvert->totweight;
+ newdvert->dw = MEM_dupallocN(dvert->dw);
+ }
+ else {
+ newdvert->totweight = 0;
+ newdvert->dw = NULL;
+ }
}
}
@@ -3233,9 +3381,9 @@ static void gpencil_stroke_join_strokes(bGPDstroke *gps_a,
}
/* define start and end points of each stroke */
- float sa[3], sb[3], ea[3], eb[3];
+ float area[3], sb[3], ea[3], eb[3];
pt = &gps_a->points[0];
- copy_v3_v3(sa, &pt->x);
+ copy_v3_v3(area, &pt->x);
pt = &gps_a->points[gps_a->totpoints - 1];
copy_v3_v3(ea, &pt->x);
@@ -3259,16 +3407,18 @@ static void gpencil_stroke_join_strokes(bGPDstroke *gps_a,
/* 1st: add one tail point to start invisible area */
point = gps_a->points[gps_a->totpoints - 1];
deltatime = point.time;
- gpencil_stroke_copy_point(gps_a, &point, gps_a->totpoints - 1, delta, 0.0f, 0.0f, 0.0f);
+
+ gpencil_stroke_copy_point(gps_a, NULL, &point, delta, 0.0f, 0.0f, 0.0f);
/* 2nd: add one head point to finish invisible area */
point = gps_b->points[0];
- gpencil_stroke_copy_point(gps_a, &point, 0, delta, 0.0f, 0.0f, deltatime);
+ gpencil_stroke_copy_point(gps_a, NULL, &point, delta, 0.0f, 0.0f, deltatime);
}
/* 3rd: add all points */
for (i = 0, pt = gps_b->points; i < gps_b->totpoints && pt; i++, pt++) {
- gpencil_stroke_copy_point(gps_a, pt, i, delta, pt->pressure, pt->strength, deltatime);
+ MDeformVert *dvert = (gps_b->dvert) ? &gps_b->dvert[i] : NULL;
+ gpencil_stroke_copy_point(gps_a, dvert, pt, delta, pt->pressure, pt->strength, deltatime);
}
}
@@ -3414,7 +3564,11 @@ void GPENCIL_OT_stroke_join(wmOperatorType *ot)
"Leave gaps between joined strokes instead of linking them");
}
-/* ******************* Stroke flip ************************** */
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Stroke Flip Operator
+ * \{ */
static int gp_stroke_flip_exec(bContext *C, wmOperator *UNUSED(op))
{
@@ -3473,7 +3627,11 @@ void GPENCIL_OT_stroke_flip(wmOperatorType *ot)
ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
}
-/* ***************** Reproject Strokes ********************** */
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Stroke Re-project Operator
+ * \{ */
typedef enum eGP_ReprojectModes {
/* Axis */
@@ -3511,7 +3669,7 @@ static int gp_strokes_reproject_exec(bContext *C, wmOperator *op)
int cfra_prv = INT_MIN;
/* init snap context for geometry projection */
- sctx = ED_transform_snap_object_context_create_view3d(bmain, scene, 0, region, CTX_wm_view3d(C));
+ sctx = ED_transform_snap_object_context_create_view3d(scene, 0, region, CTX_wm_view3d(C));
/* Go through each editable + selected stroke, adjusting each of its points one by one... */
GP_EDITABLE_STROKES_BEGIN (gpstroke_iter, C, gpl, gps) {
@@ -3546,7 +3704,7 @@ static int gp_strokes_reproject_exec(bContext *C, wmOperator *op)
GP_REPROJECT_TOP,
GP_REPROJECT_CURSOR)) {
if (mode != GP_REPROJECT_CURSOR) {
- ED_gpencil_drawing_reference_get(scene, ob, gpl, ts->gpencil_v3d_align, origin);
+ ED_gpencil_drawing_reference_get(scene, ob, ts->gpencil_v3d_align, origin);
}
else {
copy_v3_v3(origin, scene->cursor.location);
@@ -3711,7 +3869,6 @@ static int gp_recalc_geometry_exec(bContext *C, wmOperator *UNUSED(op))
void GPENCIL_OT_recalc_geometry(wmOperatorType *ot)
{
-
/* identifiers */
ot->name = "Recalculate internal geometry";
ot->idname = "GPENCIL_OT_recalc_geometry";
@@ -3725,7 +3882,12 @@ void GPENCIL_OT_recalc_geometry(wmOperatorType *ot)
ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
}
-/* ******************* Stroke subdivide ************************** */
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Stroke Subdivide Operator
+ * \{ */
+
/* helper to smooth */
static void gp_smooth_stroke(bContext *C, wmOperator *op)
{
@@ -4106,7 +4268,12 @@ void GPENCIL_OT_stroke_sample(wmOperatorType *ot)
RNA_def_property_flag(prop, PROP_SKIP_SAVE);
}
-/* ******************* Stroke trim ************************** */
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Stroke Trim Operator
+ * \{ */
+
static int gp_stroke_trim_exec(bContext *C, wmOperator *UNUSED(op))
{
bGPdata *gpd = ED_gpencil_data_get_active(C);
@@ -4171,7 +4338,12 @@ void GPENCIL_OT_stroke_trim(wmOperatorType *ot)
ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
}
-/* ***************** Separate Strokes ********************** */
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Stroke Separate Operator
+ * \{ */
+
typedef enum eGP_SeparateModes {
/* Points */
GP_SEPARATE_POINT = 0,
@@ -4249,7 +4421,7 @@ static int gp_stroke_separate_exec(bContext *C, wmOperator *op)
if (ED_gpencil_stroke_color_use(ob, gpl, gps) == false) {
continue;
}
- /* separate selected strokes */
+ /* Separate selected strokes. */
if (gps->flag & GP_STROKE_SELECT) {
/* add layer if not created before */
if (gpl_dst == NULL) {
@@ -4357,6 +4529,8 @@ static int gp_stroke_separate_exec(bContext *C, wmOperator *op)
DEG_relations_tag_update(bmain);
WM_event_add_notifier(C, NC_OBJECT | ND_DRAW, NULL);
WM_event_add_notifier(C, NC_GPENCIL | ND_DATA | NA_EDITED, NULL);
+ WM_event_add_notifier(C, NC_GPENCIL | ND_DATA | NA_SELECTED, NULL);
+ ED_outliner_select_sync_from_object_tag(C);
return OPERATOR_FINISHED;
}
@@ -4387,7 +4561,12 @@ void GPENCIL_OT_stroke_separate(wmOperatorType *ot)
ot->prop = RNA_def_enum(ot->srna, "mode", separate_type, GP_SEPARATE_POINT, "Mode", "");
}
-/* ***************** Split Strokes ********************** */
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Stroke Split Operator
+ * \{ */
+
static int gp_stroke_split_exec(bContext *C, wmOperator *UNUSED(op))
{
Object *ob = CTX_data_active_object(C);
@@ -4422,7 +4601,7 @@ static int gp_stroke_split_exec(bContext *C, wmOperator *UNUSED(op))
if (ED_gpencil_stroke_color_use(ob, gpl, gps) == false) {
continue;
}
- /* split selected strokes */
+ /* Split selected strokes. */
if (gps->flag & GP_STROKE_SELECT) {
/* make copy of source stroke */
bGPDstroke *gps_dst = BKE_gpencil_stroke_duplicate(gps, true);
@@ -4484,6 +4663,12 @@ void GPENCIL_OT_stroke_split(wmOperatorType *ot)
ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
}
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Stroke Smooth Operator
+ * \{ */
+
static int gp_stroke_smooth_exec(bContext *C, wmOperator *op)
{
bGPdata *gpd = ED_gpencil_data_get_active(C);
@@ -4534,11 +4719,17 @@ void GPENCIL_OT_stroke_smooth(wmOperatorType *ot)
RNA_def_boolean(ot->srna, "smooth_uv", false, "UV", "");
}
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Stroke Cutter Operator
+ * \{ */
+
/* smart stroke cutter for trimming stroke ends */
struct GP_SelectLassoUserData {
rcti rect;
- const int (*mcords)[2];
- int mcords_len;
+ const int (*mcoords)[2];
+ int mcoords_len;
};
static bool gpencil_test_lasso(bGPDstroke *gps,
@@ -4554,7 +4745,7 @@ static bool gpencil_test_lasso(bGPDstroke *gps,
gp_point_to_xy(gsc, gps, &pt2, &x0, &y0);
/* test if in lasso */
return ((!ELEM(V2D_IS_CLIPPED, x0, y0)) && BLI_rcti_isect_pt(&data->rect, x0, y0) &&
- BLI_lasso_is_point_inside(data->mcords, data->mcords_len, x0, y0, INT_MAX));
+ BLI_lasso_is_point_inside(data->mcoords, data->mcoords_len, x0, y0, INT_MAX));
}
typedef bool (*GPencilTestFn)(bGPDstroke *gps,
@@ -4617,7 +4808,7 @@ static int gpencil_cutter_lasso_select(bContext *C,
void *user_data)
{
bGPdata *gpd = ED_gpencil_data_get_active(C);
- ScrArea *sa = CTX_wm_area(C);
+ ScrArea *area = CTX_wm_area(C);
ToolSettings *ts = CTX_data_tool_settings(C);
const float scale = ts->gp_sculpt.isect_threshold;
@@ -4628,7 +4819,7 @@ static int gpencil_cutter_lasso_select(bContext *C,
bool changed = false;
/* sanity checks */
- if (sa == NULL) {
+ if (area == NULL) {
BKE_report(op->reports, RPT_ERROR, "No active area");
return OPERATOR_CANCELLED;
}
@@ -4724,27 +4915,27 @@ static bool gpencil_cutter_poll(bContext *C)
static int gpencil_cutter_exec(bContext *C, wmOperator *op)
{
- ScrArea *sa = CTX_wm_area(C);
+ ScrArea *area = CTX_wm_area(C);
/* sanity checks */
- if (sa == NULL) {
+ if (area == NULL) {
BKE_report(op->reports, RPT_ERROR, "No active area");
return OPERATOR_CANCELLED;
}
struct GP_SelectLassoUserData data = {0};
- data.mcords = WM_gesture_lasso_path_to_array(C, op, &data.mcords_len);
+ data.mcoords = WM_gesture_lasso_path_to_array(C, op, &data.mcoords_len);
/* Sanity check. */
- if (data.mcords == NULL) {
+ if (data.mcoords == NULL) {
return OPERATOR_PASS_THROUGH;
}
/* Compute boundbox of lasso (for faster testing later). */
- BLI_lasso_boundbox(&data.rect, data.mcords, data.mcords_len);
+ BLI_lasso_boundbox(&data.rect, data.mcoords, data.mcoords_len);
gpencil_cutter_lasso_select(C, op, gpencil_test_lasso, &data);
- MEM_freeN((void *)data.mcords);
+ MEM_freeN((void *)data.mcoords);
return OPERATOR_FINISHED;
}
@@ -4790,7 +4981,12 @@ bool ED_object_gpencil_exit(struct Main *bmain, Object *ob)
return ok;
}
-/* ** merge by distance *** */
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Merge By Distance Operator
+ * \{ */
+
static bool gp_merge_by_distance_poll(bContext *C)
{
Object *ob = CTX_data_active_object(C);
@@ -4859,3 +5055,5 @@ void GPENCIL_OT_stroke_merge_by_distance(wmOperatorType *ot)
ot->srna, "use_unselected", 0, "Unselected", "Use whole stroke, not only selected points");
RNA_def_property_flag(prop, PROP_SKIP_SAVE);
}
+
+/** \} */
diff --git a/source/blender/editors/gpencil/gpencil_fill.c b/source/blender/editors/gpencil/gpencil_fill.c
index f61572fffca..d23a914fc49 100644
--- a/source/blender/editors/gpencil/gpencil_fill.c
+++ b/source/blender/editors/gpencil/gpencil_fill.c
@@ -45,6 +45,7 @@
#include "BKE_gpencil.h"
#include "BKE_gpencil_geom.h"
#include "BKE_image.h"
+#include "BKE_lib_id.h"
#include "BKE_main.h"
#include "BKE_material.h"
#include "BKE_paint.h"
@@ -92,7 +93,7 @@ typedef struct tGPDfill {
/** current active gp object */
struct Object *ob;
/** area where painting originated */
- struct ScrArea *sa;
+ struct ScrArea *area;
/** region where painting originated */
struct RegionView3D *rv3d;
/** view3 where painting originated */
@@ -294,18 +295,15 @@ static void gp_draw_datablock(tGPDfill *tgpf, const float ink[4])
tgpw.onion = true;
tgpw.custonion = true;
- bool textured_stroke = (gp_style->stroke_style == GP_MATERIAL_STROKE_STYLE_TEXTURE);
-
/* normal strokes */
- if (((tgpf->fill_draw_mode == GP_FILL_DMODE_STROKE) ||
- (tgpf->fill_draw_mode == GP_FILL_DMODE_BOTH)) &&
- !textured_stroke) {
+ if ((tgpf->fill_draw_mode == GP_FILL_DMODE_STROKE) ||
+ (tgpf->fill_draw_mode == GP_FILL_DMODE_BOTH)) {
ED_gp_draw_fill(&tgpw);
}
/* 3D Lines with basic shapes and invisible lines */
if ((tgpf->fill_draw_mode == GP_FILL_DMODE_CONTROL) ||
- (tgpf->fill_draw_mode == GP_FILL_DMODE_BOTH) || textured_stroke) {
+ (tgpf->fill_draw_mode == GP_FILL_DMODE_BOTH)) {
gp_draw_basic_stroke(tgpf,
gps,
tgpw.diff_mat,
@@ -620,40 +618,38 @@ static void gpencil_boundaryfill_area(tGPDfill *tgpf)
get_pixel(ibuf, v, rgba);
- if (true) { /* Was: 'rgba' */
- /* check if no border(red) or already filled color(green) */
- if ((rgba[0] != 1.0f) && (rgba[1] != 1.0f)) {
- /* fill current pixel with green */
- set_pixel(ibuf, v, fill_col);
-
- /* add contact pixels */
- /* pixel left */
- if (v - 1 >= 0) {
- index = v - 1;
- if (!is_leak_narrow(ibuf, maxpixel, tgpf->fill_leak, v, LEAK_HORZ)) {
- BLI_stack_push(stack, &index);
- }
+ /* check if no border(red) or already filled color(green) */
+ if ((rgba[0] != 1.0f) && (rgba[1] != 1.0f)) {
+ /* fill current pixel with green */
+ set_pixel(ibuf, v, fill_col);
+
+ /* add contact pixels */
+ /* pixel left */
+ if (v - 1 >= 0) {
+ index = v - 1;
+ if (!is_leak_narrow(ibuf, maxpixel, tgpf->fill_leak, v, LEAK_HORZ)) {
+ BLI_stack_push(stack, &index);
}
- /* pixel right */
- if (v + 1 <= maxpixel) {
- index = v + 1;
- if (!is_leak_narrow(ibuf, maxpixel, tgpf->fill_leak, v, LEAK_HORZ)) {
- BLI_stack_push(stack, &index);
- }
+ }
+ /* pixel right */
+ if (v + 1 <= maxpixel) {
+ index = v + 1;
+ if (!is_leak_narrow(ibuf, maxpixel, tgpf->fill_leak, v, LEAK_HORZ)) {
+ BLI_stack_push(stack, &index);
}
- /* pixel top */
- if (v + ibuf->x <= maxpixel) {
- index = v + ibuf->x;
- if (!is_leak_narrow(ibuf, maxpixel, tgpf->fill_leak, v, LEAK_VERT)) {
- BLI_stack_push(stack, &index);
- }
+ }
+ /* pixel top */
+ if (v + ibuf->x <= maxpixel) {
+ index = v + ibuf->x;
+ if (!is_leak_narrow(ibuf, maxpixel, tgpf->fill_leak, v, LEAK_VERT)) {
+ BLI_stack_push(stack, &index);
}
- /* pixel bottom */
- if (v - ibuf->x >= 0) {
- index = v - ibuf->x;
- if (!is_leak_narrow(ibuf, maxpixel, tgpf->fill_leak, v, LEAK_VERT)) {
- BLI_stack_push(stack, &index);
- }
+ }
+ /* pixel bottom */
+ if (v - ibuf->x >= 0) {
+ index = v - ibuf->x;
+ if (!is_leak_narrow(ibuf, maxpixel, tgpf->fill_leak, v, LEAK_VERT)) {
+ BLI_stack_push(stack, &index);
}
}
}
@@ -670,7 +666,7 @@ static void gpencil_boundaryfill_area(tGPDfill *tgpf)
}
/* Check if there are some pixel not filled with green. If no points, means nothing to fill. */
-static bool gpencil_check_borders(tGPDfill *tgpf)
+static bool UNUSED_FUNCTION(gpencil_check_borders)(tGPDfill *tgpf)
{
ImBuf *ibuf;
void *lock;
@@ -725,31 +721,32 @@ static bool gpencil_check_borders(tGPDfill *tgpf)
return found;
}
-/* clean external border of image to avoid infinite loops */
-static void gpencil_clean_borders(tGPDfill *tgpf)
+/* Set a border to create image limits. */
+static void gpencil_set_borders(tGPDfill *tgpf, const bool transparent)
{
ImBuf *ibuf;
void *lock;
- const float fill_col[4] = {0.0f, 0.0f, 0.0f, 0.0f};
+ const float fill_col[2][4] = {{1.0f, 0.0f, 0.0f, 1.0f}, {0.0f, 0.0f, 0.0f, 0.0f}};
ibuf = BKE_image_acquire_ibuf(tgpf->ima, NULL, &lock);
int idx;
int pixel = 0;
+ const int coloridx = transparent ? 0 : 1;
/* horizontal lines */
for (idx = 0; idx < ibuf->x; idx++) {
/* bottom line */
- set_pixel(ibuf, idx, fill_col);
+ set_pixel(ibuf, idx, fill_col[coloridx]);
/* top line */
pixel = idx + (ibuf->x * (ibuf->y - 1));
- set_pixel(ibuf, pixel, fill_col);
+ set_pixel(ibuf, pixel, fill_col[coloridx]);
}
/* vertical lines */
for (idx = 0; idx < ibuf->y; idx++) {
/* left line */
- set_pixel(ibuf, ibuf->x * idx, fill_col);
+ set_pixel(ibuf, ibuf->x * idx, fill_col[coloridx]);
/* right line */
pixel = ibuf->x * idx + (ibuf->x - 1);
- set_pixel(ibuf, pixel, fill_col);
+ set_pixel(ibuf, pixel, fill_col[coloridx]);
}
/* release ibuf */
@@ -1143,7 +1140,6 @@ static void gpencil_stroke_from_buffer(tGPDfill *tgpf)
gp_stroke_convertcoords_tpoint(tgpf->scene,
tgpf->region,
tgpf->ob,
- tgpf->gpl,
point2D,
tgpf->depth_arr ? tgpf->depth_arr + i : NULL,
&pt->x);
@@ -1153,7 +1149,7 @@ static void gpencil_stroke_from_buffer(tGPDfill *tgpf)
pt->time = 0.0f;
/* Apply the vertex color to point. */
- ED_gpencil_point_vertex_color_set(ts, brush, pt);
+ ED_gpencil_point_vertex_color_set(ts, brush, pt, NULL);
if ((ts->gpencil_flags & GP_TOOL_FLAG_CREATE_WEIGHTS) && (have_weight)) {
MDeformWeight *dw = BKE_defvert_ensure_index(dvert, def_nr);
@@ -1186,8 +1182,7 @@ static void gpencil_stroke_from_buffer(tGPDfill *tgpf)
if ((tgpf->lock_axis > GP_LOCKAXIS_VIEW) &&
((ts->gpencil_v3d_align & GP_PROJECT_DEPTH_VIEW) == 0)) {
float origin[3];
- ED_gpencil_drawing_reference_get(
- tgpf->scene, tgpf->ob, tgpf->gpl, ts->gpencil_v3d_align, origin);
+ ED_gpencil_drawing_reference_get(tgpf->scene, tgpf->ob, ts->gpencil_v3d_align, origin);
ED_gp_project_stroke_to_plane(
tgpf->scene, tgpf->ob, tgpf->rv3d, gps, origin, tgpf->lock_axis - 1);
}
@@ -1250,8 +1245,8 @@ static bool gpencil_fill_poll(bContext *C)
Object *obact = CTX_data_active_object(C);
if (ED_operator_regionactive(C)) {
- ScrArea *sa = CTX_wm_area(C);
- if (sa->spacetype == SPACE_VIEW3D) {
+ ScrArea *area = CTX_wm_area(C);
+ if (area->spacetype == SPACE_VIEW3D) {
if ((obact == NULL) || (obact->type != OB_GPENCIL) ||
(obact->mode != OB_MODE_PAINT_GPENCIL)) {
return false;
@@ -1285,10 +1280,10 @@ static tGPDfill *gp_session_init_fill(bContext *C, wmOperator *UNUSED(op))
tgpf->bmain = CTX_data_main(C);
tgpf->scene = CTX_data_scene(C);
tgpf->ob = CTX_data_active_object(C);
- tgpf->sa = CTX_wm_area(C);
+ tgpf->area = CTX_wm_area(C);
tgpf->region = CTX_wm_region(C);
tgpf->rv3d = tgpf->region->regiondata;
- tgpf->v3d = tgpf->sa->spacedata.first;
+ tgpf->v3d = tgpf->area->spacedata.first;
tgpf->depsgraph = CTX_data_ensure_evaluated_depsgraph(C);
tgpf->win = CTX_wm_window(C);
@@ -1362,19 +1357,9 @@ static void gpencil_fill_exit(bContext *C, wmOperator *op)
ED_region_draw_cb_exit(tgpf->region->type, tgpf->draw_handle_3d);
}
- /* delete temp image */
+ /* Delete temp image. */
if (tgpf->ima) {
- for (Image *ima = bmain->images.first; ima; ima = ima->id.next) {
- if (ima == tgpf->ima) {
- /* XXX This is super, super suspicious!
- * There should NEVER be any need to handle datablocks in Main in such custom code.
- * Please change to using BKE_id_free() or similar! */
- BLI_remlink(&bmain->images, ima);
- BKE_image_free(tgpf->ima);
- MEM_SAFE_FREE(tgpf->ima);
- break;
- }
- }
+ BKE_id_free(bmain, tgpf->ima);
}
/* finally, free memory used by temp data */
@@ -1514,30 +1499,26 @@ static int gpencil_fill_modal(bContext *C, wmOperator *op, const wmEvent *event)
/* render screen to temp image */
if (gp_render_offscreen(tgpf)) {
+ /* Set red borders to create a external limit. */
+ gpencil_set_borders(tgpf, true);
+
/* apply boundary fill */
gpencil_boundaryfill_area(tgpf);
- /* Check if detected some border to fill. */
- if (gpencil_check_borders(tgpf)) {
-
- /* clean borders to avoid infinite loops */
- gpencil_clean_borders(tgpf);
+ /* Clean borders to avoid infinite loops. */
+ gpencil_set_borders(tgpf, false);
- /* analyze outline */
- gpencil_get_outline_points(tgpf);
+ /* analyze outline */
+ gpencil_get_outline_points(tgpf);
- /* create array of points from stack */
- gpencil_points_from_stack(tgpf);
+ /* create array of points from stack */
+ gpencil_points_from_stack(tgpf);
- /* create z-depth array for reproject */
- gpencil_get_depth_array(tgpf);
+ /* create z-depth array for reproject */
+ gpencil_get_depth_array(tgpf);
- /* create stroke and reproject */
- gpencil_stroke_from_buffer(tgpf);
- }
- else {
- BKE_report(op->reports, RPT_ERROR, "Fill canceled. No edges detected");
- }
+ /* create stroke and reproject */
+ gpencil_stroke_from_buffer(tgpf);
}
/* free temp stack data */
diff --git a/source/blender/editors/gpencil/gpencil_intern.h b/source/blender/editors/gpencil/gpencil_intern.h
index 79f672274a7..473913c5459 100644
--- a/source/blender/editors/gpencil/gpencil_intern.h
+++ b/source/blender/editors/gpencil/gpencil_intern.h
@@ -68,6 +68,17 @@ struct PropertyRNA;
/* Internal Operator-State Data ------------------------ */
+/** Random settings by stroke */
+typedef struct GpRandomSettings {
+ /** Pressure used for evaluated curves. */
+ float pen_press;
+
+ float hsv[3];
+ float pressure;
+ float strength;
+ float uv;
+} GpRandomSettings;
+
/* Temporary draw data (no draw manager mode) */
typedef struct tGPDdraw {
struct RegionView3D *rv3d; /* region to draw */
@@ -116,7 +127,7 @@ typedef struct tGPDinterpolate {
/** current scene from context */
struct Scene *scene;
/** area where painting originated */
- struct ScrArea *sa;
+ struct ScrArea *area;
/** region where painting originated */
struct ARegion *region;
/** current GP datablock */
@@ -156,7 +167,7 @@ typedef struct tGPDprimitive {
/** current evaluated gp object */
struct Object *ob_eval;
/** area where painting originated */
- struct ScrArea *sa;
+ struct ScrArea *area;
/** region where painting originated */
struct RegionView3D *rv3d;
/** view3d where painting originated */
@@ -230,6 +241,10 @@ typedef struct tGPDprimitive {
/** size in pixels for uv calculation */
float totpixlen;
+
+ /** Random settings by stroke */
+ GpRandomSettings random_settings;
+
} tGPDprimitive;
/* Modal Operator Drawing Callbacks ------------------------ */
@@ -247,7 +262,7 @@ typedef struct GP_SpaceConversion {
struct bGPdata *gpd;
struct bGPDlayer *gpl;
- struct ScrArea *sa;
+ struct ScrArea *area;
struct ARegion *region;
struct View2D *v2d;
@@ -257,8 +272,7 @@ typedef struct GP_SpaceConversion {
float mat[4][4]; /* transform matrix on the strokes (introduced in [b770964]) */
} GP_SpaceConversion;
-bool gp_stroke_inside_circle(
- const float mval[2], const float UNUSED(mvalo[2]), int rad, int x0, int y0, int x1, int y1);
+bool gp_stroke_inside_circle(const float mval[2], int rad, int x0, int y0, int x1, int y1);
void gp_point_conversion_init(struct bContext *C, GP_SpaceConversion *r_gsc);
@@ -304,7 +318,6 @@ bool gp_point_xy_to_3d(const GP_SpaceConversion *gsc,
void gp_stroke_convertcoords_tpoint(struct Scene *scene,
struct ARegion *region,
struct Object *ob,
- bGPDlayer *gpl,
const struct tGPspoint *point2D,
float *depth,
float out[3]);
@@ -347,6 +360,10 @@ const struct EnumPropertyItem *ED_gpencil_layers_with_new_enum_itemf(struct bCon
struct PointerRNA *ptr,
struct PropertyRNA *prop,
bool *r_free);
+const struct EnumPropertyItem *ED_gpencil_material_enum_itemf(struct bContext *C,
+ struct PointerRNA *ptr,
+ struct PropertyRNA *prop,
+ bool *r_free);
/* ***************************************************** */
/* Operator Defines */
@@ -552,7 +569,8 @@ void GPENCIL_OT_material_reveal(struct wmOperatorType *ot);
void GPENCIL_OT_material_lock_all(struct wmOperatorType *ot);
void GPENCIL_OT_material_unlock_all(struct wmOperatorType *ot);
void GPENCIL_OT_material_lock_unused(struct wmOperatorType *ot);
-void GPENCIL_OT_select_material(struct wmOperatorType *ot);
+void GPENCIL_OT_material_select(struct wmOperatorType *ot);
+void GPENCIL_OT_material_set(struct wmOperatorType *ot);
void GPENCIL_OT_set_active_material(struct wmOperatorType *ot);
/* convert old 2.7 files to 2.8 */
@@ -681,16 +699,13 @@ struct GP_EditableStrokes_Iter {
const bool is_multiedit_ = (bool)GPENCIL_MULTIEDIT_SESSIONS_ON(gpd_); \
LISTBASE_FOREACH (bGPDlayer *, gpl, &gpd_->layers) { \
if (BKE_gpencil_layer_is_editable(gpl)) { \
- bGPDframe *init_gpf_ = gpl->actframe; \
- if (is_multiedit_) { \
- init_gpf_ = gpl->frames.first; \
- } \
+ bGPDframe *init_gpf_ = (is_multiedit_) ? gpl->frames.first : gpl->actframe; \
for (bGPDframe *gpf_ = init_gpf_; gpf_; gpf_ = gpf_->next) { \
if ((gpf_ == gpl->actframe) || ((gpf_->flag & GP_FRAME_SELECT) && is_multiedit_)) { \
BKE_gpencil_parent_matrix_get(depsgraph_, obact_, gpl, gpstroke_iter.diff_mat); \
invert_m4_m4(gpstroke_iter.inverse_diff_mat, gpstroke_iter.diff_mat); \
/* loop over strokes */ \
- for (bGPDstroke *gps = gpf_->strokes.first; gps; gps = gps->next) { \
+ LISTBASE_FOREACH (bGPDstroke *, gps, &gpf_->strokes) { \
/* skip strokes that are invalid for current view */ \
if (ED_gpencil_stroke_can_use(C, gps) == false) \
continue; \
diff --git a/source/blender/editors/gpencil/gpencil_interpolate.c b/source/blender/editors/gpencil/gpencil_interpolate.c
index fef88007542..5cb49600d05 100644
--- a/source/blender/editors/gpencil/gpencil_interpolate.c
+++ b/source/blender/editors/gpencil/gpencil_interpolate.c
@@ -86,8 +86,8 @@ static bool gpencil_view3d_poll(bContext *C)
bGPDlayer *gpl = CTX_data_active_gpencil_layer(C);
/* only 3D view */
- ScrArea *sa = CTX_wm_area(C);
- if (sa && sa->spacetype != SPACE_VIEW3D) {
+ ScrArea *area = CTX_wm_area(C);
+ if (area && area->spacetype != SPACE_VIEW3D) {
return 0;
}
@@ -134,6 +134,19 @@ static void gp_interpolate_free_temp_strokes(bGPDframe *gpf)
}
}
}
+
+/* Helper: Untag all strokes. */
+static void gp_interpolate_untag_strokes(bGPDframe *gpf)
+{
+ BLI_assert(gpf != NULL);
+
+ LISTBASE_FOREACH (bGPDstroke *, gps, &gpf->strokes) {
+ if (gps->flag & GP_STROKE_TAG) {
+ gps->flag &= ~GP_STROKE_TAG;
+ }
+ }
+}
+
/* Helper: Update all strokes interpolated */
static void gp_interpolate_update_strokes(bContext *C, tGPDinterpolate *tgpi)
{
@@ -265,6 +278,10 @@ static void gp_interpolate_set_points(bContext *C, tGPDinterpolate *tgpi)
tgpil->prevFrame = gpl->actframe;
tgpil->nextFrame = gpl->actframe->next;
+ /* Untag interpolated strokes to be sure nothing is pending. */
+ gp_interpolate_untag_strokes(tgpil->prevFrame);
+ gp_interpolate_untag_strokes(tgpil->nextFrame);
+
BLI_addtail(&tgpi->ilayers, tgpil);
/* create a new temporary frame */
@@ -383,7 +400,7 @@ static void gpencil_interpolate_status_indicators(bContext *C, tGPDinterpolate *
(int)((p->init_factor + p->shift) * 100.0f));
}
- ED_area_status_text(p->sa, status_str);
+ ED_area_status_text(p->area, status_str);
ED_workspace_status_text(
C, TIP_("ESC/RMB to cancel, Enter/LMB to confirm, WHEEL/MOVE to adjust factor"));
}
@@ -410,7 +427,7 @@ static void gpencil_interpolate_exit(bContext *C, wmOperator *op)
/* don't assume that operator data exists at all */
if (tgpi) {
/* clear status message area */
- ED_area_status_text(tgpi->sa, NULL);
+ ED_area_status_text(tgpi->area, NULL);
ED_workspace_status_text(C, NULL);
/* Clear any temp stroke. */
@@ -445,7 +462,7 @@ static bool gp_interpolate_set_init_values(bContext *C, wmOperator *op, tGPDinte
/* set current scene and window */
tgpi->depsgraph = CTX_data_ensure_evaluated_depsgraph(C);
tgpi->scene = CTX_data_scene(C);
- tgpi->sa = CTX_wm_area(C);
+ tgpi->area = CTX_wm_area(C);
tgpi->region = CTX_wm_region(C);
tgpi->flag = ts->gp_interpolate.flag;
@@ -567,7 +584,7 @@ static int gpencil_interpolate_modal(bContext *C, wmOperator *op, const wmEvent
case EVT_PADENTER:
case EVT_RETKEY: {
/* return to normal cursor and header status */
- ED_area_status_text(tgpi->sa, NULL);
+ ED_area_status_text(tgpi->area, NULL);
ED_workspace_status_text(C, NULL);
WM_cursor_modal_restore(win);
@@ -602,7 +619,7 @@ static int gpencil_interpolate_modal(bContext *C, wmOperator *op, const wmEvent
case EVT_ESCKEY: /* cancel */
case RIGHTMOUSE: {
/* return to normal cursor and header status */
- ED_area_status_text(tgpi->sa, NULL);
+ ED_area_status_text(tgpi->area, NULL);
ED_workspace_status_text(C, NULL);
WM_cursor_modal_restore(win);
@@ -953,12 +970,16 @@ static int gpencil_interpolate_seq_exec(bContext *C, wmOperator *op)
bGPDstroke *gps_from, *gps_to;
int cframe, fFrame;
+ /* Need a set of frames to interpolate. */
+ if ((gpl->actframe == NULL) || (gpl->actframe->next == NULL)) {
+ continue;
+ }
/* all layers or only active */
if (((flag & GP_TOOLFLAG_INTERPOLATE_ALL_LAYERS) == 0) && (gpl != active_gpl)) {
continue;
}
/* only editable and visible layers are considered */
- if (!BKE_gpencil_layer_is_editable(gpl) || (gpl->actframe == NULL)) {
+ if (!BKE_gpencil_layer_is_editable(gpl)) {
continue;
}
diff --git a/source/blender/editors/gpencil/gpencil_merge.c b/source/blender/editors/gpencil/gpencil_merge.c
index bd9daa83411..e71bf2098dd 100644
--- a/source/blender/editors/gpencil/gpencil_merge.c
+++ b/source/blender/editors/gpencil/gpencil_merge.c
@@ -117,7 +117,7 @@ static bGPDstroke *gpencil_prepare_stroke(bContext *C, wmOperator *op, int totpo
/* if not exist, create a new one */
if ((paint->brush == NULL) || (paint->brush->gpencil_settings == NULL)) {
/* create new brushes */
- BKE_brush_gpencil_paint_presets(bmain, ts);
+ BKE_brush_gpencil_paint_presets(bmain, ts, false);
}
Brush *brush = paint->brush;
@@ -132,18 +132,8 @@ static bGPDstroke *gpencil_prepare_stroke(bContext *C, wmOperator *op, int totpo
bGPDframe *gpf = BKE_gpencil_layer_frame_get(gpl, CFRA, add_frame_mode);
/* stroke */
- bGPDstroke *gps = MEM_callocN(sizeof(bGPDstroke), "gp_stroke");
- gps->totpoints = totpoints;
- gps->inittime = 0.0f;
- gps->thickness = brush->size;
- gps->hardeness = brush->gpencil_settings->hardeness;
- copy_v2_v2(gps->aspect_ratio, brush->gpencil_settings->aspect_ratio);
+ bGPDstroke *gps = BKE_gpencil_stroke_new(ob->actcol - 1, totpoints, brush->size);
gps->flag |= GP_STROKE_SELECT;
- gps->flag |= GP_STROKE_3DSPACE;
- gps->mat_nr = ob->actcol - 1;
-
- /* allocate memory for points */
- gps->points = MEM_callocN(sizeof(bGPDspoint) * totpoints, "gp_stroke_points");
if (cyclic) {
gps->flag |= GP_STROKE_CYCLIC;
@@ -529,6 +519,8 @@ static int gp_stroke_merge_exec(bContext *C, wmOperator *op)
gpencil_dissolve_points(C);
}
+ BKE_gpencil_stroke_geometry_update(gps);
+
/* free memory */
MEM_SAFE_FREE(original_array);
MEM_SAFE_FREE(sorted_array);
@@ -630,7 +622,7 @@ static int gp_stroke_merge_material_exec(bContext *C, wmOperator *op)
/* notifiers */
if (changed) {
- BKE_reportf(op->reports, RPT_INFO, "Merged %d materiales of %d", removed, *totcol);
+ BKE_reportf(op->reports, RPT_INFO, "Merged %d materials of %d", removed, *totcol);
DEG_id_tag_update(&gpd->id, ID_RECALC_TRANSFORM | ID_RECALC_GEOMETRY);
WM_event_add_notifier(C, NC_GPENCIL | ND_DATA | NA_EDITED, NULL);
}
diff --git a/source/blender/editors/gpencil/gpencil_ops.c b/source/blender/editors/gpencil/gpencil_ops.c
index 8b126912efc..94c86572fd3 100644
--- a/source/blender/editors/gpencil/gpencil_ops.c
+++ b/source/blender/editors/gpencil/gpencil_ops.c
@@ -178,10 +178,10 @@ static bool gp_stroke_sculptmode_poll(bContext *C)
{
bGPdata *gpd = CTX_data_gpencil_data(C);
Object *ob = CTX_data_active_object(C);
- ScrArea *sa = CTX_wm_area(C);
+ ScrArea *area = CTX_wm_area(C);
/* if not gpencil object and not view3d, need sculpt keys if edit mode */
- if (sa->spacetype != SPACE_VIEW3D) {
+ if (area->spacetype != SPACE_VIEW3D) {
return ((gpd) && (gpd->flag & GP_DATA_STROKE_EDITMODE));
}
else {
@@ -653,7 +653,8 @@ void ED_operatortypes_gpencil(void)
WM_operatortype_append(GPENCIL_OT_material_reveal);
WM_operatortype_append(GPENCIL_OT_material_lock_all);
WM_operatortype_append(GPENCIL_OT_material_unlock_all);
- WM_operatortype_append(GPENCIL_OT_select_material);
+ WM_operatortype_append(GPENCIL_OT_material_select);
+ WM_operatortype_append(GPENCIL_OT_material_set);
/* Editing (Time) --------------- */
diff --git a/source/blender/editors/gpencil/gpencil_ops_versioning.c b/source/blender/editors/gpencil/gpencil_ops_versioning.c
index df094ff5bd0..2dd98bb8df1 100644
--- a/source/blender/editors/gpencil/gpencil_ops_versioning.c
+++ b/source/blender/editors/gpencil/gpencil_ops_versioning.c
@@ -117,9 +117,8 @@ static int gpencil_convert_old_files_exec(bContext *C, wmOperator *op)
DEG_relations_tag_update(bmain); /* added object */
/* convert grease pencil palettes (version >= 2.78) to materials and weights */
- for (const bGPDpalette *palette = gpd->palettes.first; palette; palette = palette->next) {
- for (bGPDpalettecolor *palcolor = palette->colors.first; palcolor;
- palcolor = palcolor->next) {
+ LISTBASE_FOREACH (const bGPDpalette *, palette, &gpd->palettes) {
+ LISTBASE_FOREACH (bGPDpalettecolor *, palcolor, &palette->colors) {
/* create material slot */
Material *ma = BKE_gpencil_object_material_new(bmain, ob, palcolor->info, NULL);
@@ -134,7 +133,6 @@ static int gpencil_convert_old_files_exec(bContext *C, wmOperator *op)
ARRAY_SET_ITEMS(gp_style->mix_rgba, 1.0f, 1.0f, 1.0f, 0.2f);
ARRAY_SET_ITEMS(gp_style->gradient_scale, 1.0f, 1.0f);
ARRAY_SET_ITEMS(gp_style->texture_scale, 1.0f, 1.0f);
- gp_style->texture_opacity = 1.0f;
gp_style->texture_pixsize = 100.0f;
gp_style->flag |= GP_MATERIAL_STROKE_SHOW;
@@ -169,9 +167,8 @@ static int gpencil_convert_old_files_exec(bContext *C, wmOperator *op)
}
if (is_annotation) {
- for (const bGPDpalette *palette = gpd->palettes.first; palette; palette = palette->next) {
- for (bGPDpalettecolor *palcolor = palette->colors.first; palcolor;
- palcolor = palcolor->next) {
+ LISTBASE_FOREACH (const bGPDpalette *, palette, &gpd->palettes) {
+ LISTBASE_FOREACH (bGPDpalettecolor *, palcolor, &palette->colors) {
/* fix layers */
LISTBASE_FOREACH (bGPDlayer *, gpl, &gpd->layers) {
/* unlock/unhide layer */
diff --git a/source/blender/editors/gpencil/gpencil_paint.c b/source/blender/editors/gpencil/gpencil_paint.c
index 01b0fe80dfc..06079c34d12 100644
--- a/source/blender/editors/gpencil/gpencil_paint.c
+++ b/source/blender/editors/gpencil/gpencil_paint.c
@@ -30,6 +30,7 @@
#include "MEM_guardedalloc.h"
#include "BLI_blenlib.h"
+#include "BLI_hash.h"
#include "BLI_math.h"
#include "BLI_math_geom.h"
#include "BLI_rand.h"
@@ -155,7 +156,7 @@ typedef struct tGPsdata {
/** window where painting originated. */
wmWindow *win;
/** area where painting originated. */
- ScrArea *sa;
+ ScrArea *area;
/** region where painting originated. */
ARegion *region;
/** needed for GP_STROKE_2DSPACE. */
@@ -254,6 +255,10 @@ typedef struct tGPsdata {
tGPguide guide;
ReportList *reports;
+
+ /** Random settings by stroke */
+ GpRandomSettings random_settings;
+
} tGPsdata;
/* ------ */
@@ -296,9 +301,9 @@ static void gp_session_validatebuffer(tGPsdata *p);
static bool gpencil_draw_poll(bContext *C)
{
if (ED_operator_regionactive(C)) {
- ScrArea *sa = CTX_wm_area(C);
+ ScrArea *area = CTX_wm_area(C);
/* 3D Viewport */
- if (sa->spacetype != SPACE_VIEW3D) {
+ if (area->spacetype != SPACE_VIEW3D) {
return false;
}
@@ -353,7 +358,7 @@ static void gp_get_3d_reference(tGPsdata *p, float vec[3])
if (p->ownerPtr.type == &RNA_Object) {
ob = (Object *)p->ownerPtr.data;
}
- ED_gpencil_drawing_reference_get(p->scene, ob, p->gpl, *p->align_flag, vec);
+ ED_gpencil_drawing_reference_get(p->scene, ob, *p->align_flag, vec);
}
/* Stroke Editing ---------------------------- */
@@ -444,7 +449,10 @@ static void gp_stroke_convertcoords(tGPsdata *p, const float mval[2], float out[
}
int mval_i[2];
- round_v2i_v2fl(mval_i, mval);
+ float rmval[2];
+ rmval[0] = mval[0] - 0.5f;
+ rmval[1] = mval[1] - 0.5f;
+ round_v2i_v2fl(mval_i, rmval);
if (gpencil_project_check(p) &&
(ED_view3d_autodist_simple(p->region, mval_i, out, 0, depth))) {
@@ -486,6 +494,7 @@ static void gp_stroke_convertcoords(tGPsdata *p, const float mval[2], float out[
/* Apply jitter to stroke point. */
static void gp_brush_jitter(bGPdata *gpd, tGPspoint *pt, const float amplitude)
{
+ const float axis[2] = {0.0f, 1.0f};
/* Jitter is applied perpendicular to the mouse movement vector (2D space). */
float mvec[2];
/* Mouse movement in ints -> floats. */
@@ -493,16 +502,15 @@ static void gp_brush_jitter(bGPdata *gpd, tGPspoint *pt, const float amplitude)
tGPspoint *pt_prev = pt - 1;
sub_v2_v2v2(mvec, &pt->x, &pt_prev->x);
normalize_v2(mvec);
+ /* Rotate mvec by 90 degrees... */
+ float angle = angle_v2v2(mvec, axis);
+ /* Reduce noise in the direction of the stroke. */
+ mvec[0] *= cos(angle);
+ mvec[1] *= sin(angle);
+
+ /* Scale by displacement amount, and apply. */
+ madd_v2_v2fl(&pt->x, mvec, amplitude * 10.0f);
}
- else {
- mvec[0] = 0.0f;
- mvec[1] = 0.0f;
- }
- /* Rotate mvec by 90 degrees... */
- SWAP(float, mvec[0], mvec[1]);
- mvec[0] -= mvec[0];
- /* Scale by displacement amount, and apply. */
- madd_v2_v2fl(&pt->x, mvec, amplitude);
}
/* apply pressure change depending of the angle of the stroke to simulate a pen with shape */
@@ -511,7 +519,6 @@ static void gp_brush_angle(bGPdata *gpd, Brush *brush, tGPspoint *pt, const floa
float mvec[2];
float sen = brush->gpencil_settings->draw_angle_factor; /* sensitivity */
float fac;
- float mpressure;
/* default angle of brush in radians */
float angle = brush->gpencil_settings->draw_angle;
@@ -539,9 +546,7 @@ static void gp_brush_angle(bGPdata *gpd, Brush *brush, tGPspoint *pt, const floa
fac = 1.0f - fabs(dot_v2v2(v0, mvec)); /* 0.0 to 1.0 */
/* interpolate with previous point for smoother transitions */
- mpressure = interpf(pt->pressure - (sen * fac), (pt - 1)->pressure, 0.3f);
- pt->pressure = mpressure;
-
+ pt->pressure = interpf(pt->pressure - (sen * fac), (pt - 1)->pressure, 0.3f);
CLAMP(pt->pressure, GPENCIL_ALPHA_OPACITY_THRESH, 1.0f);
}
}
@@ -686,6 +691,78 @@ static void gp_smooth_segment(bGPdata *gpd, const float inf, int from_idx, int t
}
}
+static void gp_apply_randomness(tGPsdata *p,
+ BrushGpencilSettings *brush_settings,
+ tGPspoint *pt,
+ const bool press,
+ const bool strength,
+ const bool uv)
+{
+ bGPdata *gpd = p->gpd;
+ GpRandomSettings random_settings = p->random_settings;
+ float value = 0.0f;
+ /* Apply randomness to pressure. */
+ if ((brush_settings->draw_random_press > 0.0f) && (press)) {
+ if ((brush_settings->flag2 & GP_BRUSH_USE_PRESS_AT_STROKE) == 0) {
+ float rand = BLI_rng_get_float(p->rng) * 2.0f - 1.0f;
+ value = 1.0 + rand * 2.0 * brush_settings->draw_random_press;
+ }
+ else {
+ value = 1.0 + random_settings.pressure * brush_settings->draw_random_press;
+ }
+
+ /* Apply random curve. */
+ if (brush_settings->flag2 & GP_BRUSH_USE_PRESSURE_RAND_PRESS) {
+ value *= BKE_curvemapping_evaluateF(
+ brush_settings->curve_rand_pressure, 0, random_settings.pen_press);
+ }
+
+ pt->pressure *= value;
+ CLAMP(pt->pressure, 0.1f, 1.0f);
+ }
+
+ /* Apply randomness to color strength. */
+ if ((brush_settings->draw_random_strength) && (strength)) {
+ if ((brush_settings->flag2 & GP_BRUSH_USE_STRENGTH_AT_STROKE) == 0) {
+ float rand = BLI_rng_get_float(p->rng) * 2.0f - 1.0f;
+ value = 1.0 + rand * brush_settings->draw_random_strength;
+ }
+ else {
+ value = 1.0 + random_settings.strength * brush_settings->draw_random_strength;
+ }
+
+ /* Apply random curve. */
+ if (brush_settings->flag2 & GP_BRUSH_USE_STRENGTH_RAND_PRESS) {
+ value *= BKE_curvemapping_evaluateF(
+ brush_settings->curve_rand_pressure, 0, random_settings.pen_press);
+ }
+
+ pt->strength *= value;
+ CLAMP(pt->strength, GPENCIL_STRENGTH_MIN, 1.0f);
+ }
+
+ /* Apply randomness to uv texture rotation. */
+ if ((brush_settings->uv_random > 0.0f) && (uv)) {
+ if ((brush_settings->flag2 & GP_BRUSH_USE_UV_AT_STROKE) == 0) {
+ float rand = BLI_hash_int_01(BLI_hash_int_2d((int)pt->x, gpd->runtime.sbuffer_used)) * 2.0f -
+ 1.0f;
+ value = rand * M_PI_2 * brush_settings->uv_random;
+ }
+ else {
+ value = random_settings.uv * M_PI_2 * brush_settings->uv_random;
+ }
+
+ /* Apply random curve. */
+ if (brush_settings->flag2 & GP_BRUSH_USE_UV_RAND_PRESS) {
+ value *= BKE_curvemapping_evaluateF(
+ brush_settings->curve_rand_uv, 0, random_settings.pen_press);
+ }
+
+ pt->uv_rot += value;
+ CLAMP(pt->uv_rot, -M_PI_2, M_PI_2);
+ }
+}
+
/* add current stroke-point to buffer (returns whether point was successfully added) */
static short gp_stroke_addpoint(tGPsdata *p, const float mval[2], float pressure, double curtime)
{
@@ -743,10 +820,6 @@ static short gp_stroke_addpoint(tGPsdata *p, const float mval[2], float pressure
return GP_STROKEADD_INVALID;
}
- /* Set vertex colors for buffer. */
- ED_gpencil_sbuffer_vertex_color_set(
- p->depsgraph, p->ob, p->scene->toolsettings, p->brush, p->material);
-
/* get pointer to destination point */
pt = ((tGPspoint *)(gpd->runtime.sbuffer) + gpd->runtime.sbuffer_used);
@@ -767,6 +840,15 @@ static short gp_stroke_addpoint(tGPsdata *p, const float mval[2], float pressure
CLAMP(pt->strength, GPENCIL_STRENGTH_MIN, 1.0f);
}
+ /* Set vertex colors for buffer. */
+ ED_gpencil_sbuffer_vertex_color_set(p->depsgraph,
+ p->ob,
+ p->scene->toolsettings,
+ p->brush,
+ p->material,
+ p->random_settings.hsv,
+ p->random_settings.pen_press);
+
if (brush_settings->flag & GP_BRUSH_GROUP_RANDOM) {
/* Apply jitter to position */
if (brush_settings->draw_jitter > 0.0f) {
@@ -780,24 +862,9 @@ static short gp_stroke_addpoint(tGPsdata *p, const float mval[2], float pressure
const float fac = rand * square_f(exp_factor) * jitpress;
gp_brush_jitter(gpd, pt, fac);
}
- /* apply randomness to pressure */
- if (brush_settings->draw_random_press > 0.0f) {
- float rand = BLI_rng_get_float(p->rng) * 2.0f - 1.0f;
- pt->pressure *= 1.0 + rand * 2.0 * brush_settings->draw_random_press;
- CLAMP(pt->pressure, GPENCIL_STRENGTH_MIN, 1.0f);
- }
- /* apply randomness to uv texture rotation */
- if (brush_settings->uv_random > 0.0f) {
- float rand = BLI_rng_get_float(p->rng) * 2.0f - 1.0f;
- pt->uv_rot += rand * M_PI * brush_settings->uv_random;
- CLAMP(pt->uv_rot, -M_PI_2, M_PI_2);
- }
- /* apply randomness to color strength */
- if (brush_settings->draw_random_strength) {
- float rand = BLI_rng_get_float(p->rng) * 2.0f - 1.0f;
- pt->strength *= 1.0 + rand * brush_settings->draw_random_strength;
- CLAMP(pt->strength, GPENCIL_STRENGTH_MIN, 1.0f);
- }
+
+ /* Apply other randomness. */
+ gp_apply_randomness(p, brush_settings, pt, true, true, true);
}
/* apply angle of stroke to brush size */
@@ -809,7 +876,7 @@ static short gp_stroke_addpoint(tGPsdata *p, const float mval[2], float pressure
pt->time = (float)(curtime - p->inittime);
/* point uv (only 3d view) */
- if ((p->sa->spacetype == SPACE_VIEW3D) && (gpd->runtime.sbuffer_used > 0)) {
+ if ((p->area->spacetype == SPACE_VIEW3D) && (gpd->runtime.sbuffer_used > 0)) {
tGPspoint *ptb = (tGPspoint *)gpd->runtime.sbuffer + gpd->runtime.sbuffer_used - 1;
bGPDspoint spt, spt2;
@@ -956,9 +1023,10 @@ static void gp_stroke_newfrombuffer(tGPsdata *p)
pt->pressure = ptc->pressure;
pt->strength = ptc->strength;
CLAMP(pt->strength, GPENCIL_STRENGTH_MIN, 1.0f);
+ copy_v4_v4(pt->vert_color, ptc->vert_color);
pt->time = ptc->time;
/* Apply the vertex color to point. */
- ED_gpencil_point_vertex_color_set(ts, brush, pt);
+ ED_gpencil_point_vertex_color_set(ts, brush, pt, ptc);
pt++;
@@ -991,7 +1059,7 @@ static void gp_stroke_newfrombuffer(tGPsdata *p)
CLAMP(pt->strength, GPENCIL_STRENGTH_MIN, 1.0f);
pt->time = ptc->time;
/* Apply the vertex color to point. */
- ED_gpencil_point_vertex_color_set(ts, brush, pt);
+ ED_gpencil_point_vertex_color_set(ts, brush, pt, ptc);
if ((ts->gpencil_flags & GP_TOOL_FLAG_CREATE_WEIGHTS) && (have_weight)) {
BKE_gpencil_dvert_ensure(gps);
@@ -1110,11 +1178,12 @@ static void gp_stroke_newfrombuffer(tGPsdata *p)
pt->pressure = ptc->pressure;
pt->strength = ptc->strength;
CLAMP(pt->strength, GPENCIL_STRENGTH_MIN, 1.0f);
+ copy_v4_v4(pt->vert_color, ptc->vert_color);
pt->time = ptc->time;
pt->uv_fac = ptc->uv_fac;
pt->uv_rot = ptc->uv_rot;
/* Apply the vertex color to point. */
- ED_gpencil_point_vertex_color_set(ts, brush, pt);
+ ED_gpencil_point_vertex_color_set(ts, brush, pt, ptc);
if (dvert != NULL) {
dvert->totweight = 0;
@@ -1142,6 +1211,16 @@ static void gp_stroke_newfrombuffer(tGPsdata *p)
reduce += 0.25f; /* reduce the factor */
}
}
+ /* If reproject the stroke using Stroke mode, need to apply a smooth because
+ * the reprojection creates small jitter. */
+ if (ts->gpencil_v3d_align & GP_PROJECT_DEPTH_STROKE) {
+ float ifac = (float)brush->gpencil_settings->input_samples / 10.0f;
+ float sfac = interpf(1.0f, 0.2f, ifac);
+ for (i = 0; i < gps->totpoints - 1; i++) {
+ BKE_gpencil_stroke_smooth(gps, i, sfac);
+ BKE_gpencil_stroke_smooth_strength(gps, i, sfac);
+ }
+ }
/* Simplify adaptive */
if ((brush->gpencil_settings->flag & GP_BRUSH_GROUP_SETTINGS) &&
@@ -1239,7 +1318,7 @@ static bool gp_stroke_eraser_is_occluded(tGPsdata *p,
gp_settings = eraser->gpencil_settings;
}
- if ((gp_settings != NULL) && (p->sa->spacetype == SPACE_VIEW3D) &&
+ if ((gp_settings != NULL) && (p->area->spacetype == SPACE_VIEW3D) &&
(gp_settings->flag & GP_BRUSH_OCCLUDE_ERASER)) {
RegionView3D *rv3d = p->region->regiondata;
bGPDlayer *gpl = p->gpl;
@@ -1356,7 +1435,6 @@ static void gp_stroke_eraser_dostroke(tGPsdata *p,
bGPDframe *gpf,
bGPDstroke *gps,
const float mval[2],
- const float mvalo[2],
const int radius,
const rcti *rect)
{
@@ -1475,7 +1553,7 @@ static void gp_stroke_eraser_dostroke(tGPsdata *p,
* eraser region (either within stroke painted, or on its lines)
* - this assumes that linewidth is irrelevant
*/
- if (gp_stroke_inside_circle(mval, mvalo, radius, pc0[0], pc0[1], pc2[0], pc2[1])) {
+ if (gp_stroke_inside_circle(mval, radius, pc0[0], pc0[1], pc2[0], pc2[1])) {
if ((gp_stroke_eraser_is_occluded(p, pt0, pc0[0], pc0[1]) == false) ||
(gp_stroke_eraser_is_occluded(p, pt1, pc1[0], pc1[1]) == false) ||
(gp_stroke_eraser_is_occluded(p, pt2, pc2[0], pc2[1]) == false)) {
@@ -1591,9 +1669,9 @@ static void gp_stroke_doeraser(tGPsdata *p)
rect.xmax = p->mval[0] + calc_radius;
rect.ymax = p->mval[1] + calc_radius;
- if (p->sa->spacetype == SPACE_VIEW3D) {
+ if (p->area->spacetype == SPACE_VIEW3D) {
if ((gp_settings != NULL) && (gp_settings->flag & GP_BRUSH_OCCLUDE_ERASER)) {
- View3D *v3d = p->sa->spacedata.first;
+ View3D *v3d = p->area->spacedata.first;
view3d_region_operator_needs_opengl(p->win, p->region);
ED_view3d_autodist_init(p->depsgraph, p->region, v3d, 0);
}
@@ -1631,8 +1709,8 @@ static void gp_stroke_doeraser(tGPsdata *p)
/* Not all strokes in the datablock may be valid in the current editor/context
* (e.g. 2D space strokes in the 3D view, if the same datablock is shared)
*/
- if (ED_gpencil_stroke_can_use_direct(p->sa, gps)) {
- gp_stroke_eraser_dostroke(p, gpf, gps, p->mval, p->mvalo, calc_radius, &rect);
+ if (ED_gpencil_stroke_can_use_direct(p->area, gps)) {
+ gp_stroke_eraser_dostroke(p, gpf, gps, p->mval, calc_radius, &rect);
}
}
}
@@ -1736,13 +1814,19 @@ static void gp_init_drawing_brush(bContext *C, tGPsdata *p)
/* if not exist, create a new one */
if ((paint->brush == NULL) || (paint->brush->gpencil_settings == NULL)) {
/* create new brushes */
- BKE_brush_gpencil_paint_presets(bmain, ts);
+ BKE_brush_gpencil_paint_presets(bmain, ts, true);
changed = true;
}
- /* be sure curves are initializated */
+ /* Be sure curves are initializated. */
BKE_curvemapping_initialize(paint->brush->gpencil_settings->curve_sensitivity);
BKE_curvemapping_initialize(paint->brush->gpencil_settings->curve_strength);
BKE_curvemapping_initialize(paint->brush->gpencil_settings->curve_jitter);
+ BKE_curvemapping_initialize(paint->brush->gpencil_settings->curve_rand_pressure);
+ BKE_curvemapping_initialize(paint->brush->gpencil_settings->curve_rand_strength);
+ BKE_curvemapping_initialize(paint->brush->gpencil_settings->curve_rand_uv);
+ BKE_curvemapping_initialize(paint->brush->gpencil_settings->curve_rand_hue);
+ BKE_curvemapping_initialize(paint->brush->gpencil_settings->curve_rand_saturation);
+ BKE_curvemapping_initialize(paint->brush->gpencil_settings->curve_rand_value);
/* assign to temp tGPsdata */
p->brush = paint->brush;
@@ -1814,7 +1898,7 @@ static bool gp_session_initdata(bContext *C, wmOperator *op, tGPsdata *p)
* - must verify that region data is 3D-view (and not something else)
*/
/* CAUTION: If this is the "toolbar", then this will change on the first stroke */
- p->sa = curarea;
+ p->area = curarea;
p->region = region;
p->align_flag = &ts->gpencil_v3d_align;
@@ -1829,7 +1913,7 @@ static bool gp_session_initdata(bContext *C, wmOperator *op, tGPsdata *p)
}
if ((!obact) || (obact->type != OB_GPENCIL)) {
- View3D *v3d = p->sa->spacedata.first;
+ View3D *v3d = p->area->spacedata.first;
/* if active object doesn't exist or isn't a GP Object, create one */
const float *cur = p->scene->cursor.location;
@@ -1987,8 +2071,15 @@ static void gp_paint_initstroke(tGPsdata *p, eGPencil_PaintModes paintmode, Deps
return;
}
- /* Eraser mode: If no active strokes, just return. */
+ /* Eraser mode: If no active strokes, add one or just return. */
if (paintmode == GP_PAINTMODE_ERASER) {
+ /* Eraser mode:
+ * 1) Add new frames to all frames that we might touch,
+ * 2) Ensure that p->gpf refers to the frame used for the active layer
+ * (to avoid problems with other tools which expect it to exist)
+ *
+ * This is done only if additive drawing is enabled.
+ */
bool has_layer_to_erase = false;
LISTBASE_FOREACH (bGPDlayer *, gpl, &p->gpd->layers) {
@@ -1997,12 +2088,27 @@ static void gp_paint_initstroke(tGPsdata *p, eGPencil_PaintModes paintmode, Deps
continue;
}
+ /* Add a new frame if needed (and based off the active frame,
+ * as we need some existing strokes to erase)
+ *
+ * Note: We don't add a new frame if there's nothing there now, so
+ * -> If there are no frames at all, don't add one
+ * -> If there are no strokes in that frame, don't add a new empty frame
+ */
if (gpl->actframe && gpl->actframe->strokes.first) {
+ if (ts->gpencil_flags & GP_TOOL_FLAG_RETAIN_LAST) {
+ gpl->actframe = BKE_gpencil_layer_frame_get(gpl, CFRA, GP_GETFRAME_ADD_COPY);
+ }
has_layer_to_erase = true;
break;
}
}
+ /* Ensure this gets set. */
+ if (ts->gpencil_flags & GP_TOOL_FLAG_RETAIN_LAST) {
+ p->gpf = p->gpl->actframe;
+ }
+
if (has_layer_to_erase == false) {
p->status = GP_STATUS_ERROR;
return;
@@ -2056,8 +2162,8 @@ static void gp_paint_initstroke(tGPsdata *p, eGPencil_PaintModes paintmode, Deps
/* when drawing in the camera view, in 2D space, set the subrect */
p->subrect = NULL;
if ((*p->align_flag & GP_PROJECT_VIEWSPACE) == 0) {
- if (p->sa->spacetype == SPACE_VIEW3D) {
- View3D *v3d = p->sa->spacedata.first;
+ if (p->area->spacetype == SPACE_VIEW3D) {
+ View3D *v3d = p->area->spacedata.first;
RegionView3D *rv3d = p->region->regiondata;
/* for camera view set the subrect */
@@ -2074,7 +2180,7 @@ static void gp_paint_initstroke(tGPsdata *p, eGPencil_PaintModes paintmode, Deps
p->gsc.gpd = p->gpd;
p->gsc.gpl = p->gpl;
- p->gsc.sa = p->sa;
+ p->gsc.area = p->area;
p->gsc.region = p->region;
p->gsc.v2d = p->v2d;
@@ -2085,7 +2191,7 @@ static void gp_paint_initstroke(tGPsdata *p, eGPencil_PaintModes paintmode, Deps
/* check if points will need to be made in view-aligned space */
if (*p->align_flag & GP_PROJECT_VIEWSPACE) {
- switch (p->sa->spacetype) {
+ switch (p->area->spacetype) {
case SPACE_VIEW3D: {
p->gpd->runtime.sbuffer_sflag |= GP_STROKE_3DSPACE;
break;
@@ -2110,7 +2216,7 @@ static void gp_paint_strokeend(tGPsdata *p)
* the conversions will project the values correctly...
*/
if (gpencil_project_check(p)) {
- View3D *v3d = p->sa->spacedata.first;
+ View3D *v3d = p->area->spacedata.first;
/* need to restore the original projection settings before packing up */
view3d_region_operator_needs_opengl(p->win, p->region);
@@ -2193,18 +2299,17 @@ static void gpencil_draw_eraser(bContext *UNUSED(C), int x, int y, void *p_ptr)
}
/* Turn brush cursor in 3D view on/off */
-static void gpencil_draw_toggle_eraser_cursor(bContext *C, tGPsdata *p, short enable)
+static void gpencil_draw_toggle_eraser_cursor(tGPsdata *p, short enable)
{
if (p->erasercursor && !enable) {
/* clear cursor */
- WM_paint_cursor_end(CTX_wm_manager(C), p->erasercursor);
+ WM_paint_cursor_end(p->erasercursor);
p->erasercursor = NULL;
}
else if (enable && !p->erasercursor) {
ED_gpencil_toggle_brush_cursor(p->C, false, NULL);
/* enable cursor */
- p->erasercursor = WM_paint_cursor_activate(CTX_wm_manager(C),
- SPACE_TYPE_ANY,
+ p->erasercursor = WM_paint_cursor_activate(SPACE_TYPE_ANY,
RGN_TYPE_ANY,
NULL, /* XXX */
gpencil_draw_eraser,
@@ -2229,7 +2334,7 @@ static void gpencil_draw_exit(bContext *C, wmOperator *op)
/* check size of buffer before cleanup, to determine if anything happened here */
if (p->paintmode == GP_PAINTMODE_ERASER) {
/* turn off radial brush cursor */
- gpencil_draw_toggle_eraser_cursor(C, p, false);
+ gpencil_draw_toggle_eraser_cursor(p, false);
}
/* always store the new eraser size to be used again next time
@@ -2241,7 +2346,7 @@ static void gpencil_draw_exit(bContext *C, wmOperator *op)
}
/* restore cursor to indicate end of drawing */
- if (p->sa->spacetype != SPACE_VIEW3D) {
+ if (p->area->spacetype != SPACE_VIEW3D) {
WM_cursor_modal_restore(CTX_wm_window(C));
}
else {
@@ -2688,6 +2793,8 @@ static void gpencil_draw_apply_event(bContext *C,
/* handle pressure sensitivity (which is supplied by tablets or otherwise 1.0) */
p->pressure = event->tablet.pressure;
+ /* By default use pen pressure for random curves but attenuated. */
+ p->random_settings.pen_press = pow(p->pressure, 3.0f);
/* Hack for pressure sensitive eraser on D+RMB when using a tablet:
* The pen has to float over the tablet surface, resulting in
@@ -3040,11 +3147,13 @@ static int gpencil_draw_invoke(bContext *C, wmOperator *op, const wmEvent *event
else {
p = op->customdata;
}
+ /* Init random settings. */
+ ED_gpencil_init_random_settings(p->brush, event->mval, &p->random_settings);
/* TODO: set any additional settings that we can take from the events?
* if eraser is on, draw radial aid */
if (p->paintmode == GP_PAINTMODE_ERASER) {
- gpencil_draw_toggle_eraser_cursor(C, p, true);
+ gpencil_draw_toggle_eraser_cursor(p, true);
}
else {
ED_gpencil_toggle_brush_cursor(C, true, NULL);
@@ -3094,10 +3203,10 @@ static int gpencil_draw_invoke(bContext *C, wmOperator *op, const wmEvent *event
}
/* gpencil modal operator stores area, which can be removed while using it (like fullscreen) */
-static bool gpencil_area_exists(bContext *C, ScrArea *sa_test)
+static bool gpencil_area_exists(bContext *C, ScrArea *area_test)
{
- bScreen *sc = CTX_wm_screen(C);
- return (BLI_findindex(&sc->areabase, sa_test) != -1);
+ bScreen *screen = CTX_wm_screen(C);
+ return (BLI_findindex(&screen->areabase, area_test) != -1);
}
static tGPsdata *gpencil_stroke_begin(bContext *C, wmOperator *op)
@@ -3107,7 +3216,7 @@ static tGPsdata *gpencil_stroke_begin(bContext *C, wmOperator *op)
/* we must check that we're still within the area that we're set up to work from
* otherwise we could crash (see bug #20586)
*/
- if (CTX_wm_area(C) != p->sa) {
+ if (CTX_wm_area(C) != p->area) {
printf("\t\t\tGP - wrong area execution abort!\n");
p->status = GP_STATUS_ERROR;
}
@@ -3125,6 +3234,30 @@ static tGPsdata *gpencil_stroke_begin(bContext *C, wmOperator *op)
return op->customdata;
}
+/* Apply pressure change depending of the angle of the stroke for a segment. */
+static void gp_brush_angle_segment(tGPsdata *p, tGPspoint *pt_prev, tGPspoint *pt)
+{
+ Brush *brush = p->brush;
+ /* Sensitivity. */
+ const float sen = brush->gpencil_settings->draw_angle_factor;
+ /* Default angle of brush in radians */
+ const float angle = brush->gpencil_settings->draw_angle;
+
+ float mvec[2];
+ float fac;
+
+ /* angle vector of the brush with full thickness */
+ float v0[2] = {cos(angle), sin(angle)};
+
+ mvec[0] = pt->x - pt_prev->x;
+ mvec[1] = pt->y - pt_prev->y;
+ normalize_v2(mvec);
+ fac = 1.0f - fabs(dot_v2v2(v0, mvec)); /* 0.0 to 1.0 */
+ /* interpolate with previous point for smoother transitions */
+ pt->pressure = interpf(pt->pressure - (sen * fac), pt_prev->pressure, 0.3f);
+ CLAMP(pt->pressure, GPENCIL_ALPHA_OPACITY_THRESH, 1.0f);
+}
+
/* Add arc points between two mouse events using the previous segment to determine the vertice of
* the arc.
* /+ CTL
@@ -3139,10 +3272,17 @@ static tGPsdata *gpencil_stroke_begin(bContext *C, wmOperator *op)
static void gpencil_add_arc_points(tGPsdata *p, float mval[2], int segments)
{
bGPdata *gpd = p->gpd;
+ BrushGpencilSettings *brush_settings = p->brush->gpencil_settings;
+
if (gpd->runtime.sbuffer_used < 3) {
+ tGPspoint *points = (tGPspoint *)gpd->runtime.sbuffer;
+ /* Apply other randomness to first points. */
+ for (int i = 0; i < gpd->runtime.sbuffer_used; i++) {
+ tGPspoint *pt = &points[i];
+ gp_apply_randomness(p, brush_settings, pt, false, false, true);
+ }
return;
}
-
int idx_prev = gpd->runtime.sbuffer_used;
/* Add space for new arc points. */
@@ -3197,7 +3337,9 @@ static void gpencil_add_arc_points(tGPsdata *p, float mval[2], int segments)
corner[0] = midpoint[0] - (cp1[0] - midpoint[0]);
corner[1] = midpoint[1] - (cp1[1] - midpoint[1]);
+ float stepcolor = 1.0f / segments;
+ tGPspoint *pt_step = pt_prev;
for (int i = 0; i < segments; i++) {
pt = &points[idx_prev + i - 1];
pt->x = corner[0] + (end[0] - corner[0]) * sinf(a) + (start[0] - corner[0]) * cosf(a);
@@ -3206,6 +3348,20 @@ static void gpencil_add_arc_points(tGPsdata *p, float mval[2], int segments)
/* Set pressure and strength equals to previous. It will be smoothed later. */
pt->pressure = pt_prev->pressure;
pt->strength = pt_prev->strength;
+ /* Interpolate vertex color. */
+ interp_v4_v4v4(
+ pt->vert_color, pt_before->vert_color, pt_prev->vert_color, stepcolor * (i + 1));
+
+ /* Apply angle of stroke to brush size to interpolated points but slightly attenuated.. */
+ if (brush_settings->draw_angle_factor != 0.0f) {
+ gp_brush_angle_segment(p, pt_step, pt);
+ CLAMP(pt->pressure, pt_prev->pressure * 0.5f, 1.0f);
+ /* Use the previous interpolated point for next segment. */
+ pt_step = pt;
+ }
+
+ /* Apply other randomness. */
+ gp_apply_randomness(p, brush_settings, pt, false, false, true);
a += step;
}
@@ -3257,6 +3413,7 @@ static void gpencil_add_guide_points(const tGPsdata *p,
/* Set pressure and strength equals to previous. It will be smoothed later. */
pt->pressure = pt_before->pressure;
pt->strength = pt_before->strength;
+ copy_v4_v4(pt->vert_color, pt_before->vert_color);
}
}
else {
@@ -3273,6 +3430,7 @@ static void gpencil_add_guide_points(const tGPsdata *p,
/* Set pressure and strength equals to previous. It will be smoothed later. */
pt->pressure = pt_before->pressure;
pt->strength = pt_before->strength;
+ copy_v4_v4(pt->vert_color, pt_before->vert_color);
}
}
}
@@ -3481,18 +3639,19 @@ static int gpencil_draw_modal(bContext *C, wmOperator *op, const wmEvent *event)
*/
if ((p->region) && (p->region->regiontype == RGN_TYPE_TOOLS)) {
/* Change to whatever region is now under the mouse */
- ARegion *current_region = BKE_area_find_region_xy(p->sa, RGN_TYPE_ANY, event->x, event->y);
+ ARegion *current_region = BKE_area_find_region_xy(
+ p->area, RGN_TYPE_ANY, event->x, event->y);
if (G.debug & G_DEBUG) {
- printf("found alternative region %p (old was %p) - at %d %d (sa: %d %d -> %d %d)\n",
+ printf("found alternative region %p (old was %p) - at %d %d (area: %d %d -> %d %d)\n",
current_region,
p->region,
event->x,
event->y,
- p->sa->totrct.xmin,
- p->sa->totrct.ymin,
- p->sa->totrct.xmax,
- p->sa->totrct.ymax);
+ p->area->totrct.xmin,
+ p->area->totrct.ymin,
+ p->area->totrct.xmax,
+ p->area->totrct.ymax);
}
if (current_region) {
@@ -3540,7 +3699,7 @@ static int gpencil_draw_modal(bContext *C, wmOperator *op, const wmEvent *event)
p->paintmode = RNA_enum_get(op->ptr, "mode");
}
- gpencil_draw_toggle_eraser_cursor(C, p, p->paintmode == GP_PAINTMODE_ERASER);
+ gpencil_draw_toggle_eraser_cursor(p, p->paintmode == GP_PAINTMODE_ERASER);
/* not painting, so start stroke (this should be mouse-button down) */
p = gpencil_stroke_begin(C, op);
@@ -3637,7 +3796,7 @@ static int gpencil_draw_modal(bContext *C, wmOperator *op, const wmEvent *event)
}
/* gpencil modal operator stores area, which can be removed while using it (like fullscreen) */
- if (0 == gpencil_area_exists(C, p->sa)) {
+ if (0 == gpencil_area_exists(C, p->area)) {
estate = OPERATOR_CANCELLED;
}
else {
diff --git a/source/blender/editors/gpencil/gpencil_primitive.c b/source/blender/editors/gpencil/gpencil_primitive.c
index 2b30a415086..875a6265497 100644
--- a/source/blender/editors/gpencil/gpencil_primitive.c
+++ b/source/blender/editors/gpencil/gpencil_primitive.c
@@ -124,8 +124,13 @@ static void gp_session_validatebuffer(tGPDprimitive *p)
gpd->runtime.sbuffer_sflag |= GP_STROKE_3DSPACE;
/* Set vertex colors for buffer. */
- ED_gpencil_sbuffer_vertex_color_set(
- p->depsgraph, p->ob, p->scene->toolsettings, p->brush, p->material);
+ ED_gpencil_sbuffer_vertex_color_set(p->depsgraph,
+ p->ob,
+ p->scene->toolsettings,
+ p->brush,
+ p->material,
+ p->random_settings.hsv,
+ 1.0f);
if (ELEM(p->type, GP_STROKE_BOX, GP_STROKE_CIRCLE)) {
gpd->runtime.sbuffer_sflag |= GP_STROKE_CYCLIC;
@@ -240,8 +245,8 @@ static void gp_primitive_update_cps(tGPDprimitive *tgpi)
static bool gpencil_primitive_add_poll(bContext *C)
{
/* only 3D view */
- ScrArea *sa = CTX_wm_area(C);
- if (sa && sa->spacetype != SPACE_VIEW3D) {
+ ScrArea *area = CTX_wm_area(C);
+ if (area && area->spacetype != SPACE_VIEW3D) {
return 0;
}
@@ -681,6 +686,8 @@ static void gp_primitive_update_strokes(bContext *C, tGPDprimitive *tgpi)
ToolSettings *ts = tgpi->scene->toolsettings;
bGPdata *gpd = tgpi->gpd;
Brush *brush = tgpi->brush;
+ BrushGpencilSettings *brush_settings = brush->gpencil_settings;
+ GpRandomSettings random_settings = tgpi->random_settings;
bGPDstroke *gps = tgpi->gpf->strokes.first;
GP_Sculpt_Settings *gset = &ts->gp_sculpt;
int depth_margin = (ts->gpencil_v3d_align & GP_PROJECT_DEPTH_STROKE) ? 4 : 0;
@@ -735,11 +742,11 @@ static void gp_primitive_update_strokes(bContext *C, tGPDprimitive *tgpi)
if (gset->flag & GP_SCULPT_SETT_FLAG_PRIMITIVE_CURVE) {
BKE_curvemapping_initialize(ts->gp_sculpt.cur_primitive);
}
- if (tgpi->brush->gpencil_settings->flag & GP_BRUSH_USE_JITTER_PRESSURE) {
- BKE_curvemapping_initialize(tgpi->brush->gpencil_settings->curve_jitter);
+ if (brush_settings->flag & GP_BRUSH_USE_JITTER_PRESSURE) {
+ BKE_curvemapping_initialize(brush_settings->curve_jitter);
}
- if (tgpi->brush->gpencil_settings->flag & GP_BRUSH_USE_STENGTH_PRESSURE) {
- BKE_curvemapping_initialize(tgpi->brush->gpencil_settings->curve_strength);
+ if (brush_settings->flag & GP_BRUSH_USE_STENGTH_PRESSURE) {
+ BKE_curvemapping_initialize(brush_settings->curve_strength);
}
/* get an array of depths, far depths are blended */
@@ -841,10 +848,9 @@ static void gp_primitive_update_strokes(bContext *C, tGPDprimitive *tgpi)
tGPspoint *p2d = &points2D[i];
/* set rnd value for reuse */
- if ((brush->gpencil_settings->flag & GP_BRUSH_GROUP_RANDOM) && (p2d->rnd_dirty != true)) {
+ if ((brush_settings->flag & GP_BRUSH_GROUP_RANDOM) && (p2d->rnd_dirty != true)) {
p2d->rnd[0] = BLI_rng_get_float(tgpi->rng);
p2d->rnd[1] = BLI_rng_get_float(tgpi->rng);
- p2d->rnd[2] = BLI_rng_get_float(tgpi->rng);
p2d->rnd_dirty = true;
}
@@ -858,7 +864,7 @@ static void gp_primitive_update_strokes(bContext *C, tGPDprimitive *tgpi)
/* calc pressure */
float curve_pressure = 1.0;
float pressure = 1.0;
- float strength = brush->gpencil_settings->draw_strength;
+ float strength = brush_settings->draw_strength;
/* normalize value to evaluate curve */
if (gset->flag & GP_SCULPT_SETT_FLAG_PRIMITIVE_CURVE) {
@@ -868,20 +874,18 @@ static void gp_primitive_update_strokes(bContext *C, tGPDprimitive *tgpi)
}
/* apply jitter to position */
- if ((brush->gpencil_settings->flag & GP_BRUSH_GROUP_RANDOM) &&
- (brush->gpencil_settings->draw_jitter > 0.0f)) {
+ if ((brush_settings->flag & GP_BRUSH_GROUP_RANDOM) && (brush_settings->draw_jitter > 0.0f)) {
float jitter;
- if (brush->gpencil_settings->flag & GP_BRUSH_USE_JITTER_PRESSURE) {
- jitter = BKE_curvemapping_evaluateF(
- brush->gpencil_settings->curve_jitter, 0, curve_pressure);
+ if (brush_settings->flag & GP_BRUSH_USE_JITTER_PRESSURE) {
+ jitter = BKE_curvemapping_evaluateF(brush_settings->curve_jitter, 0, curve_pressure);
}
else {
- jitter = brush->gpencil_settings->draw_jitter;
+ jitter = brush_settings->draw_jitter;
}
/* exponential value */
- const float exfactor = square_f(brush->gpencil_settings->draw_jitter + 2.0f);
+ const float exfactor = square_f(brush_settings->draw_jitter + 2.0f);
const float fac = p2d->rnd[0] * exfactor * jitter;
/* vector */
@@ -906,47 +910,68 @@ static void gp_primitive_update_strokes(bContext *C, tGPDprimitive *tgpi)
add_v2_v2(&p2d->x, svec);
}
- /* apply randomness to pressure */
- if ((brush->gpencil_settings->flag & GP_BRUSH_GROUP_RANDOM) &&
- (brush->gpencil_settings->draw_random_press > 0.0f)) {
- if (p2d->rnd[0] > 0.5f) {
- pressure -= (brush->gpencil_settings->draw_random_press * 2.0f) * p2d->rnd[1];
- }
- else {
- pressure += (brush->gpencil_settings->draw_random_press * 2.0f) * p2d->rnd[2];
- }
- }
-
/* color strength */
- if (brush->gpencil_settings->flag & GP_BRUSH_USE_STENGTH_PRESSURE) {
- float curvef = BKE_curvemapping_evaluateF(
- brush->gpencil_settings->curve_strength, 0, curve_pressure);
+ if (brush_settings->flag & GP_BRUSH_USE_STENGTH_PRESSURE) {
+ float curvef = BKE_curvemapping_evaluateF(brush_settings->curve_strength, 0, curve_pressure);
strength *= curvef;
- strength *= brush->gpencil_settings->draw_strength;
+ strength *= brush_settings->draw_strength;
}
CLAMP(strength, GPENCIL_STRENGTH_MIN, 1.0f);
- /* apply randomness to color strength */
- if ((brush->gpencil_settings->flag & GP_BRUSH_GROUP_RANDOM) &&
- (brush->gpencil_settings->draw_random_strength > 0.0f)) {
- if (p2d->rnd[2] > 0.5f) {
- strength -= strength * brush->gpencil_settings->draw_random_strength * p2d->rnd[0];
+ if (brush_settings->flag & GP_BRUSH_GROUP_RANDOM) {
+ /* Apply randomness to pressure. */
+ if (brush_settings->draw_random_press > 0.0f) {
+ if ((brush_settings->flag2 & GP_BRUSH_USE_PRESS_AT_STROKE) == 0) {
+ float rand = BLI_rng_get_float(tgpi->rng) * 2.0f - 1.0f;
+ pressure *= 1.0 + rand * 2.0 * brush_settings->draw_random_press;
+ }
+ else {
+ pressure *= 1.0 + random_settings.pressure * brush_settings->draw_random_press;
+ }
+
+ /* Apply random curve. */
+ if (brush_settings->flag2 & GP_BRUSH_USE_PRESSURE_RAND_PRESS) {
+ pressure *= BKE_curvemapping_evaluateF(brush_settings->curve_rand_pressure, 0, pressure);
+ }
+
+ CLAMP(pressure, 0.1f, 1.0f);
}
- else {
- strength += strength * brush->gpencil_settings->draw_random_strength * p2d->rnd[1];
+
+ /* Apply randomness to color strength. */
+ if (brush_settings->draw_random_strength) {
+ if ((brush_settings->flag2 & GP_BRUSH_USE_STRENGTH_AT_STROKE) == 0) {
+ float rand = BLI_rng_get_float(tgpi->rng) * 2.0f - 1.0f;
+ strength *= 1.0 + rand * brush_settings->draw_random_strength;
+ }
+ else {
+ strength *= 1.0 + random_settings.strength * brush_settings->draw_random_strength;
+ }
+
+ /* Apply random curve. */
+ if (brush_settings->flag2 & GP_BRUSH_USE_STRENGTH_RAND_PRESS) {
+ strength *= BKE_curvemapping_evaluateF(brush_settings->curve_rand_strength, 0, pressure);
+ }
+
+ CLAMP(strength, GPENCIL_STRENGTH_MIN, 1.0f);
}
- CLAMP(strength, GPENCIL_STRENGTH_MIN, 1.0f);
}
copy_v2_v2(&tpt->x, &p2d->x);
- CLAMP_MIN(pressure, 0.1f);
-
tpt->pressure = pressure;
tpt->strength = strength;
tpt->time = p2d->time;
+ /* Set vertex colors for buffer. */
+ ED_gpencil_sbuffer_vertex_color_set(tgpi->depsgraph,
+ tgpi->ob,
+ tgpi->scene->toolsettings,
+ tgpi->brush,
+ tgpi->material,
+ tgpi->random_settings.hsv,
+ strength);
+
/* point uv */
if (gpd->runtime.sbuffer_used > 0) {
tGPspoint *tptb = (tGPspoint *)gpd->runtime.sbuffer + gpd->runtime.sbuffer_used - 1;
@@ -954,8 +979,7 @@ static void gp_primitive_update_strokes(bContext *C, tGPDprimitive *tgpi)
/* get origin to reproject point */
float origin[3];
- ED_gpencil_drawing_reference_get(
- tgpi->scene, tgpi->ob, tgpi->gpl, ts->gpencil_v3d_align, origin);
+ ED_gpencil_drawing_reference_get(tgpi->scene, tgpi->ob, ts->gpencil_v3d_align, origin);
/* reproject current */
ED_gpencil_tpoint_to_point(tgpi->region, origin, tpt, &spt);
ED_gp_project_point_to_plane(
@@ -987,21 +1011,15 @@ static void gp_primitive_update_strokes(bContext *C, tGPDprimitive *tgpi)
}
/* convert screen-coordinates to 3D coordinates */
- gp_stroke_convertcoords_tpoint(tgpi->scene,
- tgpi->region,
- tgpi->ob,
- tgpi->gpl,
- p2d,
- depth_arr ? depth_arr + i : NULL,
- &pt->x);
+ gp_stroke_convertcoords_tpoint(
+ tgpi->scene, tgpi->region, tgpi->ob, p2d, depth_arr ? depth_arr + i : NULL, &pt->x);
pt->pressure = pressure;
pt->strength = strength;
pt->time = 0.0f;
pt->flag = 0;
pt->uv_fac = tpt->uv_fac;
- /* Apply the vertex color to point. */
- ED_gpencil_point_vertex_color_set(ts, brush, pt);
+ copy_v4_v4(pt->vert_color, tpt->vert_color);
if (gps->dvert != NULL) {
MDeformVert *dvert = &gps->dvert[i];
@@ -1019,15 +1037,14 @@ static void gp_primitive_update_strokes(bContext *C, tGPDprimitive *tgpi)
for (int i = 0; i < tgpi->gpd->runtime.tot_cp_points; i++) {
bGPDcontrolpoint *cp = &cps[i];
gp_stroke_convertcoords_tpoint(
- tgpi->scene, tgpi->region, tgpi->ob, tgpi->gpl, (tGPspoint *)cp, NULL, &cp->x);
+ tgpi->scene, tgpi->region, tgpi->ob, (tGPspoint *)cp, NULL, &cp->x);
}
}
/* reproject to plane */
if (!is_depth) {
float origin[3];
- ED_gpencil_drawing_reference_get(
- tgpi->scene, tgpi->ob, tgpi->gpl, ts->gpencil_v3d_align, origin);
+ ED_gpencil_drawing_reference_get(tgpi->scene, tgpi->ob, ts->gpencil_v3d_align, origin);
ED_gp_project_stroke_to_plane(
tgpi->scene, tgpi->ob, tgpi->rv3d, gps, origin, ts->gp_sculpt.lock_axis - 1);
}
@@ -1144,10 +1161,10 @@ static void gpencil_primitive_init(bContext *C, wmOperator *op)
tgpi->scene = scene;
tgpi->ob = CTX_data_active_object(C);
tgpi->ob_eval = (Object *)DEG_get_evaluated_object(tgpi->depsgraph, tgpi->ob);
- tgpi->sa = CTX_wm_area(C);
+ tgpi->area = CTX_wm_area(C);
tgpi->region = CTX_wm_region(C);
tgpi->rv3d = tgpi->region->regiondata;
- tgpi->v3d = tgpi->sa->spacedata.first;
+ tgpi->v3d = tgpi->area->spacedata.first;
tgpi->win = CTX_wm_window(C);
/* save original type */
@@ -1161,11 +1178,12 @@ static void gpencil_primitive_init(bContext *C, wmOperator *op)
/* if brush doesn't exist, create a new set (fix damaged files from old versions) */
if ((paint->brush == NULL) || (paint->brush->gpencil_settings == NULL)) {
- BKE_brush_gpencil_paint_presets(bmain, ts);
+ BKE_brush_gpencil_paint_presets(bmain, ts, true);
}
/* Set Draw brush. */
Brush *brush = BKE_paint_toolslots_brush_get(paint, 0);
+
BKE_brush_tool_set(brush, paint, 0);
BKE_paint_brush_set(paint, brush);
tgpi->brush = brush;
@@ -1233,6 +1251,9 @@ static int gpencil_primitive_invoke(bContext *C, wmOperator *op, const wmEvent *
gpencil_primitive_init(C, op);
tgpi = op->customdata;
+ /* Init random settings. */
+ ED_gpencil_init_random_settings(tgpi->brush, event->mval, &tgpi->random_settings);
+
const bool is_modal = RNA_boolean_get(op->ptr, "wait_for_input");
if (!is_modal) {
tgpi->flag = IN_PROGRESS;
@@ -1269,6 +1290,7 @@ static void gpencil_primitive_interaction_end(bContext *C,
ToolSettings *ts = tgpi->scene->toolsettings;
Brush *brush = tgpi->brush;
+ BrushGpencilSettings *brush_settings = brush->gpencil_settings;
const int def_nr = tgpi->ob->actdef - 1;
const bool have_weight = (bool)BLI_findlink(&tgpi->ob->defbase, def_nr);
@@ -1292,8 +1314,8 @@ static void gpencil_primitive_interaction_end(bContext *C,
gps = tgpi->gpf->strokes.first;
if (gps) {
gps->thickness = brush->size;
- gps->hardeness = brush->gpencil_settings->hardeness;
- copy_v2_v2(gps->aspect_ratio, brush->gpencil_settings->aspect_ratio);
+ gps->hardeness = brush_settings->hardeness;
+ copy_v2_v2(gps->aspect_ratio, brush_settings->aspect_ratio);
/* Calc geometry data. */
BKE_gpencil_stroke_geometry_update(gps);
@@ -1456,23 +1478,25 @@ static void gpencil_primitive_edit_event_handling(
static void gpencil_primitive_strength(tGPDprimitive *tgpi, bool reset)
{
Brush *brush = tgpi->brush;
+ BrushGpencilSettings *brush_settings = brush->gpencil_settings;
+
if (brush) {
if (reset) {
- brush->gpencil_settings->draw_strength = tgpi->brush_strength;
+ brush_settings->draw_strength = tgpi->brush_strength;
tgpi->brush_strength = 0.0f;
}
else {
if (tgpi->brush_strength == 0.0f) {
- tgpi->brush_strength = brush->gpencil_settings->draw_strength;
+ tgpi->brush_strength = brush_settings->draw_strength;
}
float move[2];
sub_v2_v2v2(move, tgpi->mval, tgpi->mvalo);
float adjust = (move[1] > 0.0f) ? 0.01f : -0.01f;
- brush->gpencil_settings->draw_strength += adjust * fabsf(len_manhattan_v2(move));
+ brush_settings->draw_strength += adjust * fabsf(len_manhattan_v2(move));
}
/* limit low limit because below 0.2f the stroke is invisible */
- CLAMP(brush->gpencil_settings->draw_strength, 0.2f, 1.0f);
+ CLAMP(brush_settings->draw_strength, 0.2f, 1.0f);
}
}
diff --git a/source/blender/editors/gpencil/gpencil_sculpt_paint.c b/source/blender/editors/gpencil/gpencil_sculpt_paint.c
index 59b14a47d1d..f7f3b128351 100644
--- a/source/blender/editors/gpencil/gpencil_sculpt_paint.c
+++ b/source/blender/editors/gpencil/gpencil_sculpt_paint.c
@@ -91,7 +91,7 @@ typedef struct tGP_BrushEditData {
Scene *scene;
Object *object;
- ScrArea *sa;
+ ScrArea *area;
ARegion *region;
/* Current GPencil datablock */
@@ -1181,7 +1181,7 @@ static bool gpsculpt_brush_init(bContext *C, wmOperator *op)
gso->is_transformed = false;
}
- gso->sa = CTX_wm_area(C);
+ gso->area = CTX_wm_area(C);
gso->region = CTX_wm_region(C);
Paint *paint = &ts->gp_sculptpaint->paint;
@@ -1307,8 +1307,8 @@ static void gpsculpt_brush_exit(bContext *C, wmOperator *op)
/* poll callback for stroke sculpting operator(s) */
static bool gpsculpt_brush_poll(bContext *C)
{
- ScrArea *sa = CTX_wm_area(C);
- if (sa && sa->spacetype != SPACE_VIEW3D) {
+ ScrArea *area = CTX_wm_area(C);
+ if (area && area->spacetype != SPACE_VIEW3D) {
return false;
}
@@ -1371,7 +1371,7 @@ static float gpsculpt_rotation_eval_get(tGP_BrushEditData *gso,
}
GP_SpaceConversion *gsc = &gso->gsc;
- bGPDstroke *gps_orig = gps_eval->runtime.gps_orig;
+ bGPDstroke *gps_orig = (gps_eval->runtime.gps_orig) ? gps_eval->runtime.gps_orig : gps_eval;
bGPDspoint *pt_orig = &gps_orig->points[pt_eval->runtime.idx_orig];
bGPDspoint *pt_prev_eval = NULL;
bGPDspoint *pt_orig_prev = NULL;
@@ -1422,6 +1422,7 @@ static bool gpsculpt_brush_do_stroke(tGP_BrushEditData *gso,
GP_SpaceConversion *gsc = &gso->gsc;
rcti *rect = &gso->brush_rect;
Brush *brush = gso->brush;
+ char tool = gso->brush->gpencil_sculpt_tool;
const int radius = (brush->flag & GP_BRUSH_USE_PRESSURE) ? gso->brush->size * gso->pressure :
gso->brush->size;
@@ -1495,16 +1496,18 @@ static bool gpsculpt_brush_do_stroke(tGP_BrushEditData *gso,
* brush region (either within stroke painted, or on its lines)
* - this assumes that linewidth is irrelevant
*/
- if (gp_stroke_inside_circle(
- gso->mval, gso->mval_prev, radius, pc1[0], pc1[1], pc2[0], pc2[1])) {
+ if (gp_stroke_inside_circle(gso->mval, radius, pc1[0], pc1[1], pc2[0], pc2[1])) {
/* Apply operation to these points */
bool ok = false;
/* To each point individually... */
pt = &gps->points[i];
+ if ((pt->runtime.pt_orig == NULL) && (tool != GPSCULPT_TOOL_GRAB)) {
+ continue;
+ }
pt_active = (pt->runtime.pt_orig) ? pt->runtime.pt_orig : pt;
index = (pt->runtime.pt_orig) ? pt->runtime.idx_orig : i;
- if (pt_active != NULL) {
+ if ((pt_active != NULL) && (index < gps_active->totpoints)) {
rot_eval = gpsculpt_rotation_eval_get(gso, gps, pt, i);
ok = apply(gso, gps_active, rot_eval, index, radius, pc1);
}
@@ -1521,7 +1524,7 @@ static bool gpsculpt_brush_do_stroke(tGP_BrushEditData *gso,
pt = &gps->points[i + 1];
pt_active = (pt->runtime.pt_orig) ? pt->runtime.pt_orig : pt;
index = (pt->runtime.pt_orig) ? pt->runtime.idx_orig : i + 1;
- if (pt_active != NULL) {
+ if ((pt_active != NULL) && (index < gps_active->totpoints)) {
rot_eval = gpsculpt_rotation_eval_get(gso, gps, pt, i + 1);
ok |= apply(gso, gps_active, rot_eval, index, radius, pc2);
include_last = false;
@@ -1542,7 +1545,7 @@ static bool gpsculpt_brush_do_stroke(tGP_BrushEditData *gso,
pt = &gps->points[i];
pt_active = (pt->runtime.pt_orig) ? pt->runtime.pt_orig : pt;
index = (pt->runtime.pt_orig) ? pt->runtime.idx_orig : i;
- if (pt_active != NULL) {
+ if ((pt_active != NULL) && (index < gps_active->totpoints)) {
rot_eval = gpsculpt_rotation_eval_get(gso, gps, pt, i);
changed |= apply(gso, gps_active, rot_eval, index, radius, pc1);
include_last = false;
diff --git a/source/blender/editors/gpencil/gpencil_select.c b/source/blender/editors/gpencil/gpencil_select.c
index 03e8001341f..7accf48832a 100644
--- a/source/blender/editors/gpencil/gpencil_select.c
+++ b/source/blender/editors/gpencil/gpencil_select.c
@@ -43,6 +43,7 @@
#include "BKE_context.h"
#include "BKE_gpencil.h"
+#include "BKE_material.h"
#include "BKE_report.h"
#include "UI_interface.h"
@@ -67,6 +68,45 @@
/** \name Shared Utilities
* \{ */
+/* Check if mouse inside stroke. */
+static bool gpencil_point_inside_stroke(bGPDstroke *gps,
+ GP_SpaceConversion *gsc,
+ int mouse[2],
+ const float diff_mat[4][4])
+{
+ bool hit = false;
+ if (gps->totpoints == 0) {
+ return hit;
+ }
+
+ int(*mcoords)[2] = NULL;
+ int len = gps->totpoints;
+ mcoords = MEM_mallocN(sizeof(int) * 2 * len, __func__);
+
+ /* Convert stroke to 2D array of points. */
+ bGPDspoint *pt;
+ int i;
+ for (i = 0, pt = gps->points; i < gps->totpoints; i++, pt++) {
+ bGPDspoint pt2;
+ gp_point_to_parent_space(pt, diff_mat, &pt2);
+ gp_point_to_xy(gsc, gps, &pt2, &mcoords[i][0], &mcoords[i][1]);
+ }
+
+ /* Compute boundbox of lasso (for faster testing later). */
+ rcti rect;
+ BLI_lasso_boundbox(&rect, mcoords, len);
+
+ /* Test if point inside stroke. */
+ hit = ((!ELEM(V2D_IS_CLIPPED, mouse[0], mouse[1])) &&
+ BLI_rcti_isect_pt(&rect, mouse[0], mouse[1]) &&
+ BLI_lasso_is_point_inside(mcoords, len, mouse[0], mouse[1], INT_MAX));
+
+ /* Free memory. */
+ MEM_SAFE_FREE(mcoords);
+
+ return hit;
+}
+
/* Convert sculpt mask mode to Select mode */
static int gpencil_select_mode_from_sculpt(eGP_Sculpt_SelectMaskFlag mode)
{
@@ -919,13 +959,12 @@ static bool gp_stroke_do_circle_sel(bGPdata *UNUSED(gpd),
if (((!ELEM(V2D_IS_CLIPPED, x0, y0)) && BLI_rcti_isect_pt(rect, x0, y0)) ||
((!ELEM(V2D_IS_CLIPPED, x1, y1)) && BLI_rcti_isect_pt(rect, x1, y1))) {
float mval[2] = {(float)mx, (float)my};
- float mvalo[2] = {(float)mx, (float)my}; /* dummy - this isn't used... */
/* check if point segment of stroke had anything to do with
* eraser region (either within stroke painted, or on its lines)
* - this assumes that linewidth is irrelevant
*/
- if (gp_stroke_inside_circle(mval, mvalo, radius, x0, y0, x1, y1)) {
+ if (gp_stroke_inside_circle(mval, radius, x0, y0, x1, y1)) {
/* change selection of stroke, and then of both points
* (as the last point otherwise wouldn't get selected
* as we only do n-1 loops through).
@@ -1016,7 +1055,7 @@ static int gpencil_circle_select_exec(bContext *C, wmOperator *op)
return OPERATOR_CANCELLED;
}
- ScrArea *sa = CTX_wm_area(C);
+ ScrArea *area = CTX_wm_area(C);
const int mx = RNA_int_get(op->ptr, "x");
const int my = RNA_int_get(op->ptr, "y");
@@ -1029,7 +1068,7 @@ static int gpencil_circle_select_exec(bContext *C, wmOperator *op)
bool changed = false;
/* sanity checks */
- if (sa == NULL) {
+ if (area == NULL) {
BKE_report(op->reports, RPT_ERROR, "No active area");
return OPERATOR_CANCELLED;
}
@@ -1052,8 +1091,7 @@ static int gpencil_circle_select_exec(bContext *C, wmOperator *op)
rect.ymax = my + radius;
/* find visible strokes, and select if hit */
- GP_EVALUATED_STROKES_BEGIN(gpstroke_iter, C, gpl, gps)
- {
+ GP_EVALUATED_STROKES_BEGIN (gpstroke_iter, C, gpl, gps) {
changed |= gp_stroke_do_circle_sel(gpd,
gpl,
gps,
@@ -1120,15 +1158,13 @@ typedef bool (*GPencilTestFn)(bGPDstroke *gps,
const float diff_mat[4][4],
void *user_data);
-static int gpencil_generic_select_exec(bContext *C,
- wmOperator *op,
- GPencilTestFn is_inside_fn,
- void *user_data)
+static int gpencil_generic_select_exec(
+ bContext *C, wmOperator *op, GPencilTestFn is_inside_fn, rcti box, void *user_data)
{
Object *ob = CTX_data_active_object(C);
bGPdata *gpd = ED_gpencil_data_get_active(C);
ToolSettings *ts = CTX_data_tool_settings(C);
- ScrArea *sa = CTX_wm_area(C);
+ ScrArea *area = CTX_wm_area(C);
int selectmode;
if (ob && ob->mode == OB_MODE_SCULPT_GPENCIL) {
@@ -1145,7 +1181,6 @@ static int gpencil_generic_select_exec(bContext *C,
((gpd->flag & GP_DATA_STROKE_PAINTMODE) == 0));
const bool segmentmode = ((selectmode == GP_SELECTMODE_SEGMENT) &&
((gpd->flag & GP_DATA_STROKE_PAINTMODE) == 0));
- const bool is_multiedit = (bool)GPENCIL_MULTIEDIT_SESSIONS_ON(gpd);
const eSelectOp sel_op = RNA_enum_get(op->ptr, "mode");
const float scale = ts->gp_sculpt.isect_threshold;
@@ -1155,7 +1190,7 @@ static int gpencil_generic_select_exec(bContext *C,
bool changed = false;
/* sanity checks */
- if (sa == NULL) {
+ if (area == NULL) {
BKE_report(op->reports, RPT_ERROR, "No active area");
return OPERATOR_CANCELLED;
}
@@ -1180,18 +1215,15 @@ static int gpencil_generic_select_exec(bContext *C,
}
/* select/deselect points */
- GP_EVALUATED_STROKES_BEGIN(gpstroke_iter, C, gpl, gps)
- {
+ GP_EVALUATED_STROKES_BEGIN (gpstroke_iter, C, gpl, gps) {
bGPDstroke *gps_active = (gps->runtime.gps_orig) ? gps->runtime.gps_orig : gps;
+ bool whole = false;
bGPDspoint *pt;
int i;
bool hit = false;
for (i = 0, pt = gps->points; i < gps->totpoints; i++, pt++) {
- if (pt->runtime.pt_orig == NULL) {
- continue;
- }
- bGPDspoint *pt_active = pt->runtime.pt_orig;
+ bGPDspoint *pt_active = (pt->runtime.pt_orig) ? pt->runtime.pt_orig : pt;
/* convert point coords to screenspace */
const bool is_inside = is_inside_fn(gps, pt, &gsc, gpstroke_iter.diff_mat, user_data);
@@ -1201,9 +1233,10 @@ static int gpencil_generic_select_exec(bContext *C,
if (sel_op_result != -1) {
SET_FLAG_FROM_TEST(pt_active->flag, sel_op_result, GP_SPOINT_SELECT);
changed = true;
+ hit = true;
- /* expand selection to segment */
- if ((sel_op_result != -1) && (segmentmode)) {
+ /* Expand selection to segment. */
+ if (segmentmode) {
bool hit_select = (bool)(pt_active->flag & GP_SPOINT_SELECT);
float r_hita[3], r_hitb[3];
ED_gpencil_select_stroke_segment(
@@ -1219,16 +1252,28 @@ static int gpencil_generic_select_exec(bContext *C,
}
}
- /* if stroke mode expand selection */
- if (strokemode) {
- const bool is_select = BKE_gpencil_stroke_select_check(gps_active);
- const bool is_inside = hit;
+ /* If nothing hit, check if the mouse is inside a filled stroke using the center or
+ * Box or lasso area. */
+ if (!hit) {
+ /* Only check filled strokes. */
+ MaterialGPencilStyle *gp_style = BKE_gpencil_material_settings(ob, gps->mat_nr + 1);
+ if ((gp_style->flag & GP_MATERIAL_FILL_SHOW) == 0) {
+ continue;
+ }
+ int mval[2];
+ mval[0] = (box.xmax + box.xmin) / 2;
+ mval[1] = (box.ymax + box.ymin) / 2;
+
+ whole = gpencil_point_inside_stroke(gps_active, &gsc, mval, gpstroke_iter.diff_mat);
+ }
+
+ /* if stroke mode expand selection. */
+ if ((strokemode) || (whole)) {
+ const bool is_select = BKE_gpencil_stroke_select_check(gps_active) || whole;
+ const bool is_inside = hit || whole;
const int sel_op_result = ED_select_op_action_deselected(sel_op, is_select, is_inside);
if (sel_op_result != -1) {
for (i = 0, pt = gps->points; i < gps->totpoints; i++, pt++) {
- if ((!is_multiedit) && (pt->runtime.pt_orig == NULL)) {
- continue;
- }
bGPDspoint *pt_active = (pt->runtime.pt_orig) ? pt->runtime.pt_orig : pt;
if (sel_op_result) {
@@ -1264,7 +1309,6 @@ static int gpencil_generic_select_exec(bContext *C,
WM_event_add_notifier(C, NC_GPENCIL | NA_SELECTED, NULL);
WM_event_add_notifier(C, NC_GEOM | ND_SELECT, NULL);
}
-
return OPERATOR_FINISHED;
}
@@ -1296,7 +1340,8 @@ static int gpencil_box_select_exec(bContext *C, wmOperator *op)
{
struct GP_SelectBoxUserData data = {0};
WM_operator_properties_border_to_rcti(op, &data.rect);
- return gpencil_generic_select_exec(C, op, gpencil_test_box, &data);
+ rcti rect = data.rect;
+ return gpencil_generic_select_exec(C, op, gpencil_test_box, rect, &data);
}
void GPENCIL_OT_select_box(wmOperatorType *ot)
@@ -1330,8 +1375,8 @@ void GPENCIL_OT_select_box(wmOperatorType *ot)
struct GP_SelectLassoUserData {
rcti rect;
- const int (*mcords)[2];
- int mcords_len;
+ const int (*mcoords)[2];
+ int mcoords_len;
};
static bool gpencil_test_lasso(bGPDstroke *gps,
@@ -1347,25 +1392,26 @@ static bool gpencil_test_lasso(bGPDstroke *gps,
gp_point_to_xy(gsc, gps, &pt2, &x0, &y0);
/* test if in lasso boundbox + within the lasso noose */
return ((!ELEM(V2D_IS_CLIPPED, x0, y0)) && BLI_rcti_isect_pt(&data->rect, x0, y0) &&
- BLI_lasso_is_point_inside(data->mcords, data->mcords_len, x0, y0, INT_MAX));
+ BLI_lasso_is_point_inside(data->mcoords, data->mcoords_len, x0, y0, INT_MAX));
}
static int gpencil_lasso_select_exec(bContext *C, wmOperator *op)
{
struct GP_SelectLassoUserData data = {0};
- data.mcords = WM_gesture_lasso_path_to_array(C, op, &data.mcords_len);
+ data.mcoords = WM_gesture_lasso_path_to_array(C, op, &data.mcoords_len);
/* Sanity check. */
- if (data.mcords == NULL) {
+ if (data.mcoords == NULL) {
return OPERATOR_PASS_THROUGH;
}
/* Compute boundbox of lasso (for faster testing later). */
- BLI_lasso_boundbox(&data.rect, data.mcords, data.mcords_len);
+ BLI_lasso_boundbox(&data.rect, data.mcoords, data.mcoords_len);
- int ret = gpencil_generic_select_exec(C, op, gpencil_test_lasso, &data);
+ rcti rect = data.rect;
+ int ret = gpencil_generic_select_exec(C, op, gpencil_test_lasso, rect, &data);
- MEM_freeN((void *)data.mcords);
+ MEM_freeN((void *)data.mcoords);
return ret;
}
@@ -1419,7 +1465,7 @@ static void deselect_all_selected(bContext *C)
static int gpencil_select_exec(bContext *C, wmOperator *op)
{
- ScrArea *sa = CTX_wm_area(C);
+ ScrArea *area = CTX_wm_area(C);
Object *ob = CTX_data_active_object(C);
bGPdata *gpd = ED_gpencil_data_get_active(C);
ToolSettings *ts = CTX_data_tool_settings(C);
@@ -1427,7 +1473,7 @@ static int gpencil_select_exec(bContext *C, wmOperator *op)
const bool is_multiedit = (bool)GPENCIL_MULTIEDIT_SESSIONS_ON(gpd);
/* "radius" is simply a threshold (screen space) to make it easier to test with a tolerance */
- const float radius = 0.50f * U.widget_unit;
+ const float radius = 0.4f * U.widget_unit;
const int radius_squared = (int)(radius * radius);
const bool use_shift_extend = RNA_boolean_get(op->ptr, "use_shift_extend");
@@ -1447,7 +1493,7 @@ static int gpencil_select_exec(bContext *C, wmOperator *op)
int hit_distance = radius_squared;
/* sanity checks */
- if (sa == NULL) {
+ if (area == NULL) {
BKE_report(op->reports, RPT_ERROR, "No active area");
return OPERATOR_CANCELLED;
}
@@ -1472,13 +1518,19 @@ static int gpencil_select_exec(bContext *C, wmOperator *op)
RNA_int_get_array(op->ptr, "location", mval);
/* First Pass: Find stroke point which gets hit */
- /* XXX: maybe we should go from the top of the stack down instead... */
- GP_EVALUATED_STROKES_BEGIN(gpstroke_iter, C, gpl, gps)
- {
+ GP_EVALUATED_STROKES_BEGIN (gpstroke_iter, C, gpl, gps) {
bGPDstroke *gps_active = (gps->runtime.gps_orig) ? gps->runtime.gps_orig : gps;
bGPDspoint *pt;
int i;
+ /* Check boundbox to speedup. */
+ float fmval[2];
+ copy_v2fl_v2i(fmval, mval);
+ if (!ED_gpencil_stroke_check_collision(
+ &gsc, gps_active, fmval, radius, gpstroke_iter.diff_mat)) {
+ continue;
+ }
+
/* firstly, check for hit-point */
for (i = 0, pt = gps->points; i < gps->totpoints; i++, pt++) {
int xy[2];
@@ -1506,11 +1558,27 @@ static int gpencil_select_exec(bContext *C, wmOperator *op)
}
}
}
+ if (ELEM(NULL, hit_stroke, hit_point)) {
+ /* If nothing hit, check if the mouse is inside any filled stroke.
+ * Only check filling materials. */
+ MaterialGPencilStyle *gp_style = BKE_gpencil_material_settings(ob, gps->mat_nr + 1);
+ if ((gp_style->flag & GP_MATERIAL_FILL_SHOW) == 0) {
+ continue;
+ }
+ bool hit_fill = gpencil_point_inside_stroke(gps, &gsc, mval, gpstroke_iter.diff_mat);
+ if (hit_fill) {
+ hit_stroke = gps_active;
+ hit_point = &gps_active->points[0];
+ /* Extend selection to all stroke. */
+ whole = true;
+ }
+ }
}
GP_EVALUATED_STROKES_END(gpstroke_iter);
/* Abort if nothing hit... */
if (ELEM(NULL, hit_stroke, hit_point)) {
+
if (deselect_all) {
/* since left mouse select change, deselect all if click outside any hit */
deselect_all_selected(C);
diff --git a/source/blender/editors/gpencil/gpencil_utils.c b/source/blender/editors/gpencil/gpencil_utils.c
index 276be071e0b..1962eba5017 100644
--- a/source/blender/editors/gpencil/gpencil_utils.c
+++ b/source/blender/editors/gpencil/gpencil_utils.c
@@ -30,11 +30,14 @@
#include "BLI_blenlib.h"
#include "BLI_ghash.h"
+#include "BLI_hash.h"
#include "BLI_math.h"
#include "BLI_rand.h"
#include "BLI_utildefines.h"
#include "BLT_translation.h"
+#include "PIL_time.h"
+
#include "DNA_brush_types.h"
#include "DNA_gpencil_types.h"
#include "DNA_meshdata_types.h"
@@ -74,6 +77,7 @@
#include "ED_object.h"
#include "ED_screen.h"
#include "ED_select_utils.h"
+#include "ED_transform_snap_object_context.h"
#include "ED_view3d.h"
#include "GPU_immediate.h"
@@ -93,13 +97,13 @@
* and an RNA-pointer to trace back to whatever owns it,
* when context info is not available.
*/
-bGPdata **ED_gpencil_data_get_pointers_direct(ScrArea *sa, Object *ob, PointerRNA *r_ptr)
+bGPdata **ED_gpencil_data_get_pointers_direct(ScrArea *area, Object *ob, PointerRNA *r_ptr)
{
/* if there's an active area, check if the particular editor may
* have defined any special Grease Pencil context for editing...
*/
- if (sa) {
- switch (sa->spacetype) {
+ if (area) {
+ switch (area->spacetype) {
case SPACE_PROPERTIES: /* properties */
case SPACE_INFO: /* header info */
case SPACE_TOPBAR: /* Topbar */
@@ -132,16 +136,16 @@ bGPdata **ED_gpencil_data_get_pointers_direct(ScrArea *sa, Object *ob, PointerRN
* when context info is not available.
*/
bGPdata **ED_annotation_data_get_pointers_direct(ID *screen_id,
- ScrArea *sa,
+ ScrArea *area,
Scene *scene,
PointerRNA *r_ptr)
{
/* If there's an active area, check if the particular editor may
* have defined any special Grease Pencil context for editing. */
- if (sa) {
- SpaceLink *sl = sa->spacedata.first;
+ if (area) {
+ SpaceLink *sl = area->spacedata.first;
- switch (sa->spacetype) {
+ switch (area->spacetype) {
case SPACE_PROPERTIES: /* properties */
case SPACE_INFO: /* header info */
{
@@ -236,10 +240,10 @@ bGPdata **ED_annotation_data_get_pointers_direct(ID *screen_id,
* and an RNA-pointer to trace back to whatever owns it. */
bGPdata **ED_gpencil_data_get_pointers(const bContext *C, PointerRNA *r_ptr)
{
- ScrArea *sa = CTX_wm_area(C);
+ ScrArea *area = CTX_wm_area(C);
Object *ob = CTX_data_active_object(C);
- return ED_gpencil_data_get_pointers_direct(sa, ob, r_ptr);
+ return ED_gpencil_data_get_pointers_direct(area, ob, r_ptr);
}
/* Get pointer to active Grease Pencil datablock,
@@ -248,23 +252,23 @@ bGPdata **ED_annotation_data_get_pointers(const bContext *C, PointerRNA *r_ptr)
{
ID *screen_id = (ID *)CTX_wm_screen(C);
Scene *scene = CTX_data_scene(C);
- ScrArea *sa = CTX_wm_area(C);
+ ScrArea *area = CTX_wm_area(C);
- return ED_annotation_data_get_pointers_direct(screen_id, sa, scene, r_ptr);
+ return ED_annotation_data_get_pointers_direct(screen_id, area, scene, r_ptr);
}
/* -------------------------------------------------------- */
/* Get the active Grease Pencil datablock, when context is not available */
-bGPdata *ED_gpencil_data_get_active_direct(ScrArea *sa, Object *ob)
+bGPdata *ED_gpencil_data_get_active_direct(ScrArea *area, Object *ob)
{
- bGPdata **gpd_ptr = ED_gpencil_data_get_pointers_direct(sa, ob, NULL);
+ bGPdata **gpd_ptr = ED_gpencil_data_get_pointers_direct(area, ob, NULL);
return (gpd_ptr) ? *(gpd_ptr) : NULL;
}
/* Get the active Grease Pencil datablock, when context is not available */
-bGPdata *ED_annotation_data_get_active_direct(ID *screen_id, ScrArea *sa, Scene *scene)
+bGPdata *ED_annotation_data_get_active_direct(ID *screen_id, ScrArea *area, Scene *scene)
{
- bGPdata **gpd_ptr = ED_annotation_data_get_pointers_direct(screen_id, sa, scene, NULL);
+ bGPdata **gpd_ptr = ED_annotation_data_get_pointers_direct(screen_id, area, scene, NULL);
return (gpd_ptr) ? *(gpd_ptr) : NULL;
}
@@ -299,13 +303,13 @@ bGPdata *ED_annotation_data_get_active(const bContext *C)
*/
bGPdata *ED_gpencil_data_get_active_evaluated(const bContext *C)
{
- ScrArea *sa = CTX_wm_area(C);
+ ScrArea *area = CTX_wm_area(C);
const Depsgraph *depsgraph = CTX_data_ensure_evaluated_depsgraph(C);
Object *ob = CTX_data_active_object(C);
Object *ob_eval = DEG_get_evaluated_object(depsgraph, ob);
- return ED_gpencil_data_get_active_direct(sa, ob_eval);
+ return ED_gpencil_data_get_active_direct(area, ob_eval);
}
/* -------------------------------------------------------- */
@@ -481,6 +485,40 @@ const EnumPropertyItem *ED_gpencil_layers_with_new_enum_itemf(bContext *C,
return item;
}
+/* Just existing Materials */
+const EnumPropertyItem *ED_gpencil_material_enum_itemf(bContext *C,
+ PointerRNA *UNUSED(ptr),
+ PropertyRNA *UNUSED(prop),
+ bool *r_free)
+{
+ Object *ob = CTX_data_active_object(C);
+ EnumPropertyItem *item = NULL, item_tmp = {0};
+ int totitem = 0;
+ int i = 0;
+
+ if (ELEM(NULL, C, ob)) {
+ return DummyRNA_DEFAULT_items;
+ }
+
+ /* Existing materials */
+ for (i = 1; i <= ob->totcol; i++) {
+ Material *ma = BKE_object_material_get(ob, i);
+ if (ma) {
+ item_tmp.identifier = ma->id.name + 2;
+ item_tmp.name = ma->id.name + 2;
+ item_tmp.value = i;
+ item_tmp.icon = ma->preview ? ma->preview->icon_id : ICON_NONE;
+
+ RNA_enum_item_add(&item, &totitem, &item_tmp);
+ }
+ }
+
+ RNA_enum_item_end(&item, &totitem);
+ *r_free = true;
+
+ return item;
+}
+
/* ******************************************************** */
/* Brush Tool Core */
@@ -494,8 +532,7 @@ const EnumPropertyItem *ED_gpencil_layers_with_new_enum_itemf(bContext *C,
* \param x0, y0: The screen-space x and y coordinates of the start of the stroke segment
* \param x1, y1: The screen-space x and y coordinates of the end of the stroke segment
*/
-bool gp_stroke_inside_circle(
- const float mval[2], const float UNUSED(mvalo[2]), int rad, int x0, int y0, int x1, int y1)
+bool gp_stroke_inside_circle(const float mval[2], int rad, int x0, int y0, int x1, int y1)
{
/* simple within-radius check for now */
const float screen_co_a[2] = {x0, y0};
@@ -514,25 +551,25 @@ bool gp_stroke_inside_circle(
/* Check whether given stroke can be edited given the supplied context */
/* TODO: do we need additional flags for screenspace vs dataspace? */
-bool ED_gpencil_stroke_can_use_direct(const ScrArea *sa, const bGPDstroke *gps)
+bool ED_gpencil_stroke_can_use_direct(const ScrArea *area, const bGPDstroke *gps)
{
/* sanity check */
- if (ELEM(NULL, sa, gps)) {
+ if (ELEM(NULL, area, gps)) {
return false;
}
/* filter stroke types by flags + spacetype */
if (gps->flag & GP_STROKE_3DSPACE) {
/* 3D strokes - only in 3D view */
- return ((sa->spacetype == SPACE_VIEW3D) || (sa->spacetype == SPACE_PROPERTIES));
+ return ((area->spacetype == SPACE_VIEW3D) || (area->spacetype == SPACE_PROPERTIES));
}
else if (gps->flag & GP_STROKE_2DIMAGE) {
/* Special "image" strokes - only in Image Editor */
- return (sa->spacetype == SPACE_IMAGE);
+ return (area->spacetype == SPACE_IMAGE);
}
else if (gps->flag & GP_STROKE_2DSPACE) {
/* 2D strokes (dataspace) - for any 2D view (i.e. everything other than 3D view) */
- return (sa->spacetype != SPACE_VIEW3D);
+ return (area->spacetype != SPACE_VIEW3D);
}
else {
/* view aligned - anything goes */
@@ -543,8 +580,8 @@ bool ED_gpencil_stroke_can_use_direct(const ScrArea *sa, const bGPDstroke *gps)
/* Check whether given stroke can be edited in the current context */
bool ED_gpencil_stroke_can_use(const bContext *C, const bGPDstroke *gps)
{
- ScrArea *sa = CTX_wm_area(C);
- return ED_gpencil_stroke_can_use_direct(sa, gps);
+ ScrArea *area = CTX_wm_area(C);
+ return ED_gpencil_stroke_can_use_direct(area, gps);
}
/* Check whether given stroke can be edited for the current color */
@@ -575,7 +612,7 @@ bool ED_gpencil_stroke_color_use(Object *ob, const bGPDlayer *gpl, const bGPDstr
*/
void gp_point_conversion_init(bContext *C, GP_SpaceConversion *r_gsc)
{
- ScrArea *sa = CTX_wm_area(C);
+ ScrArea *area = CTX_wm_area(C);
ARegion *region = CTX_wm_region(C);
/* zero out the storage (just in case) */
@@ -586,12 +623,12 @@ void gp_point_conversion_init(bContext *C, GP_SpaceConversion *r_gsc)
r_gsc->scene = CTX_data_scene(C);
r_gsc->ob = CTX_data_active_object(C);
- r_gsc->sa = sa;
+ r_gsc->area = area;
r_gsc->region = region;
r_gsc->v2d = &region->v2d;
/* init region-specific stuff */
- if (sa->spacetype == SPACE_VIEW3D) {
+ if (area->spacetype == SPACE_VIEW3D) {
wmWindow *win = CTX_wm_window(C);
Scene *scene = CTX_data_scene(C);
struct Depsgraph *depsgraph = CTX_data_ensure_evaluated_depsgraph(C);
@@ -671,8 +708,8 @@ void gp_apply_parent_point(Depsgraph *depsgraph, Object *obact, bGPDlayer *gpl,
/**
* Convert a Grease Pencil coordinate (i.e. can be 2D or 3D) to screenspace (2D)
*
- * \param[out] r_x The screen-space x-coordinate of the point
- * \param[out] r_y The screen-space y-coordinate of the point
+ * \param[out] r_x: The screen-space x-coordinate of the point
+ * \param[out] r_y: The screen-space y-coordinate of the point
*
* \warning This assumes that the caller has already checked
* whether the stroke in question can be drawn.
@@ -686,8 +723,8 @@ void gp_point_to_xy(
int xyval[2];
/* sanity checks */
- BLI_assert(!(gps->flag & GP_STROKE_3DSPACE) || (gsc->sa->spacetype == SPACE_VIEW3D));
- BLI_assert(!(gps->flag & GP_STROKE_2DSPACE) || (gsc->sa->spacetype != SPACE_VIEW3D));
+ BLI_assert(!(gps->flag & GP_STROKE_3DSPACE) || (gsc->area->spacetype == SPACE_VIEW3D));
+ BLI_assert(!(gps->flag & GP_STROKE_2DSPACE) || (gsc->area->spacetype != SPACE_VIEW3D));
if (gps->flag & GP_STROKE_3DSPACE) {
if (ED_view3d_project_int_global(region, &pt->x, xyval, V3D_PROJ_TEST_NOP) ==
@@ -744,8 +781,8 @@ void gp_point_to_xy_fl(const GP_SpaceConversion *gsc,
float xyval[2];
/* sanity checks */
- BLI_assert(!(gps->flag & GP_STROKE_3DSPACE) || (gsc->sa->spacetype == SPACE_VIEW3D));
- BLI_assert(!(gps->flag & GP_STROKE_2DSPACE) || (gsc->sa->spacetype != SPACE_VIEW3D));
+ BLI_assert(!(gps->flag & GP_STROKE_3DSPACE) || (gsc->area->spacetype == SPACE_VIEW3D));
+ BLI_assert(!(gps->flag & GP_STROKE_2DSPACE) || (gsc->area->spacetype != SPACE_VIEW3D));
if (gps->flag & GP_STROKE_3DSPACE) {
if (ED_view3d_project_float_global(region, &pt->x, xyval, V3D_PROJ_TEST_NOP) ==
@@ -803,7 +840,7 @@ void gp_point_3d_to_xy(const GP_SpaceConversion *gsc,
float xyval[2];
/* sanity checks */
- BLI_assert((gsc->sa->spacetype == SPACE_VIEW3D));
+ BLI_assert((gsc->area->spacetype == SPACE_VIEW3D));
if (flag & GP_STROKE_3DSPACE) {
if (ED_view3d_project_float_global(region, pt, xyval, V3D_PROJ_TEST_NOP) == V3D_PROJ_RET_OK) {
@@ -869,8 +906,7 @@ bool gp_point_xy_to_3d(const GP_SpaceConversion *gsc,
const RegionView3D *rv3d = gsc->region->regiondata;
float rvec[3];
- ED_gpencil_drawing_reference_get(
- scene, gsc->ob, gsc->gpl, scene->toolsettings->gpencil_v3d_align, rvec);
+ ED_gpencil_drawing_reference_get(scene, gsc->ob, scene->toolsettings->gpencil_v3d_align, rvec);
float zfac = ED_view3d_calc_zfac(rv3d, rvec, NULL);
@@ -905,7 +941,6 @@ bool gp_point_xy_to_3d(const GP_SpaceConversion *gsc,
void gp_stroke_convertcoords_tpoint(Scene *scene,
ARegion *region,
Object *ob,
- bGPDlayer *gpl,
const tGPspoint *point2D,
float *depth,
float r_out[3])
@@ -929,7 +964,7 @@ void gp_stroke_convertcoords_tpoint(Scene *scene,
/* Current method just converts each point in screen-coordinates to
* 3D-coordinates using the 3D-cursor as reference.
*/
- ED_gpencil_drawing_reference_get(scene, ob, gpl, ts->gpencil_v3d_align, rvec);
+ ED_gpencil_drawing_reference_get(scene, ob, ts->gpencil_v3d_align, rvec);
zfac = ED_view3d_calc_zfac(region->regiondata, rvec, NULL);
if (ED_view3d_project_float_global(region, rvec, mval_prj, V3D_PROJ_TEST_NOP) ==
@@ -948,8 +983,10 @@ void gp_stroke_convertcoords_tpoint(Scene *scene,
* Get drawing reference point for conversion or projection of the stroke
* \param[out] r_vec : Reference point found
*/
-void ED_gpencil_drawing_reference_get(
- const Scene *scene, const Object *ob, bGPDlayer *UNUSED(gpl), char align_flag, float r_vec[3])
+void ED_gpencil_drawing_reference_get(const Scene *scene,
+ const Object *ob,
+ char align_flag,
+ float r_vec[3])
{
const float *fp = scene->cursor.location;
@@ -1328,7 +1365,7 @@ void ED_gpencil_add_defaults(bContext *C, Object *ob)
/* if not exist, create a new one */
if ((paint->brush == NULL) || (paint->brush->gpencil_settings == NULL)) {
/* create new brushes */
- BKE_brush_gpencil_paint_presets(bmain, ts);
+ BKE_brush_gpencil_paint_presets(bmain, ts, true);
}
/* ensure a color exists and is assigned to object */
@@ -1564,7 +1601,7 @@ void ED_gpencil_vgroup_deselect(bContext *C, Object *ob)
static bool gp_check_cursor_region(bContext *C, int mval_i[2])
{
ARegion *region = CTX_wm_region(C);
- ScrArea *sa = CTX_wm_area(C);
+ ScrArea *area = CTX_wm_area(C);
Object *ob = CTX_data_active_object(C);
if ((ob == NULL) || (!ELEM(ob->mode,
@@ -1576,7 +1613,7 @@ static bool gp_check_cursor_region(bContext *C, int mval_i[2])
}
/* TODO: add more spacetypes */
- if (!ELEM(sa->spacetype, SPACE_VIEW3D)) {
+ if (!ELEM(area->spacetype, SPACE_VIEW3D)) {
return false;
}
if ((region) && (region->regiontype != RGN_TYPE_WINDOW)) {
@@ -1834,19 +1871,18 @@ void ED_gpencil_toggle_brush_cursor(bContext *C, bool enable, void *customdata)
if (gset->paintcursor && !enable) {
/* clear cursor */
- WM_paint_cursor_end(CTX_wm_manager(C), gset->paintcursor);
+ WM_paint_cursor_end(gset->paintcursor);
gset->paintcursor = NULL;
}
else if (enable) {
/* in some situations cursor could be duplicated, so it is better disable first if exist */
if (gset->paintcursor) {
/* clear cursor */
- WM_paint_cursor_end(CTX_wm_manager(C), gset->paintcursor);
+ WM_paint_cursor_end(gset->paintcursor);
gset->paintcursor = NULL;
}
/* enable cursor */
- gset->paintcursor = WM_paint_cursor_activate(CTX_wm_manager(C),
- SPACE_TYPE_ANY,
+ gset->paintcursor = WM_paint_cursor_activate(SPACE_TYPE_ANY,
RGN_TYPE_ANY,
gp_brush_cursor_poll,
gp_brush_cursor_draw,
@@ -2174,7 +2210,8 @@ int ED_gpencil_select_stroke_segment(bGPDlayer *gpl,
float f = 0.0f;
int i2 = 0;
- bGPDframe *gpf = gpl->actframe;
+ bGPDlayer *gpl_orig = (gpl->runtime.gpl_orig) ? gpl->runtime.gpl_orig : gpl;
+ bGPDframe *gpf = gpl_orig->actframe;
if (gpf == NULL) {
return 0;
}
@@ -2187,7 +2224,7 @@ int ED_gpencil_select_stroke_segment(bGPDlayer *gpl,
/* Save list of strokes to check */
int totstrokes = 0;
- for (bGPDstroke *gps_iter = gpf->strokes.first; gps_iter; gps_iter = gps_iter->next) {
+ LISTBASE_FOREACH (bGPDstroke *, gps_iter, &gpf->strokes) {
if (gps_iter->totpoints < 2) {
continue;
}
@@ -2525,26 +2562,170 @@ void ED_gpencil_fill_vertex_color_set(ToolSettings *ts, Brush *brush, bGPDstroke
}
}
-void ED_gpencil_point_vertex_color_set(ToolSettings *ts, Brush *brush, bGPDspoint *pt)
+void ED_gpencil_point_vertex_color_set(ToolSettings *ts,
+ Brush *brush,
+ bGPDspoint *pt,
+ tGPspoint *tpt)
{
if (GPENCIL_USE_VERTEX_COLOR_STROKE(ts, brush)) {
- copy_v3_v3(pt->vert_color, brush->rgb);
- pt->vert_color[3] = brush->gpencil_settings->vertex_factor;
- srgb_to_linearrgb_v4(pt->vert_color, pt->vert_color);
+ if (tpt == NULL) {
+ copy_v3_v3(pt->vert_color, brush->rgb);
+ pt->vert_color[3] = brush->gpencil_settings->vertex_factor;
+ srgb_to_linearrgb_v4(pt->vert_color, pt->vert_color);
+ }
+ else {
+ copy_v3_v3(pt->vert_color, tpt->vert_color);
+ pt->vert_color[3] = brush->gpencil_settings->vertex_factor;
+ }
}
else {
zero_v4(pt->vert_color);
}
}
-void ED_gpencil_sbuffer_vertex_color_set(
- Depsgraph *depsgraph, Object *ob, ToolSettings *ts, Brush *brush, Material *material)
+void ED_gpencil_init_random_settings(Brush *brush,
+ const int mval[2],
+ GpRandomSettings *random_settings)
+{
+ int seed = ((uint)(ceil(PIL_check_seconds_timer())) + 1) % 128;
+ /* Use mouse position to get randomness. */
+ int ix = mval[0] * seed;
+ int iy = mval[1] * seed;
+ int iz = ix + iy * seed;
+ zero_v3(random_settings->hsv);
+
+ BrushGpencilSettings *brush_settings = brush->gpencil_settings;
+ /* Random to Hue. */
+ if (brush_settings->random_hue > 0.0f) {
+ float rand = BLI_hash_int_01(BLI_hash_int_2d(ix, iy)) * 2.0f - 1.0f;
+ random_settings->hsv[0] = rand * brush_settings->random_hue * 0.5f;
+ }
+ /* Random to Saturation. */
+ if (brush_settings->random_saturation > 0.0f) {
+ float rand = BLI_hash_int_01(BLI_hash_int_2d(iy, ix)) * 2.0f - 1.0f;
+ random_settings->hsv[1] = rand * brush_settings->random_saturation;
+ }
+ /* Random to Value. */
+ if (brush_settings->random_value > 0.0f) {
+ float rand = BLI_hash_int_01(BLI_hash_int_2d(ix * iz, iy * iz)) * 2.0f - 1.0f;
+ random_settings->hsv[2] = rand * brush_settings->random_value;
+ }
+
+ /* Random to pressure. */
+ if (brush_settings->draw_random_press > 0.0f) {
+ random_settings->pressure = BLI_hash_int_01(BLI_hash_int_2d(ix + iz, iy + iz)) * 2.0f - 1.0f;
+ }
+
+ /* Randomn to color strength. */
+ if (brush_settings->draw_random_strength) {
+ random_settings->strength = BLI_hash_int_01(BLI_hash_int_2d(ix + iy, iy + iz + ix)) * 2.0f -
+ 1.0f;
+ }
+
+ /* Random to uv texture rotation. */
+ if (brush_settings->uv_random > 0.0f) {
+ random_settings->uv = BLI_hash_int_01(BLI_hash_int_2d(iy + iz, ix * iz)) * 2.0f - 1.0f;
+ }
+}
+
+static void gpencil_sbuffer_vertex_color_random(
+ bGPdata *gpd, Brush *brush, tGPspoint *tpt, float random_color[3], float pen_pressure)
+{
+ BrushGpencilSettings *brush_settings = brush->gpencil_settings;
+ if (brush_settings->flag & GP_BRUSH_GROUP_RANDOM) {
+ int seed = ((uint)(ceil(PIL_check_seconds_timer())) + 1) % 128;
+
+ int ix = (int)(tpt->x * seed);
+ int iy = (int)(tpt->y * seed);
+ int iz = ix + iy * seed;
+ float hsv[3];
+ float factor_value[3];
+ zero_v3(factor_value);
+
+ /* Apply randomness to Hue. */
+ if (brush_settings->random_hue > 0.0f) {
+ if ((brush_settings->flag2 & GP_BRUSH_USE_HUE_AT_STROKE) == 0) {
+
+ float rand = BLI_hash_int_01(BLI_hash_int_2d(ix, gpd->runtime.sbuffer_used)) * 2.0f - 1.0f;
+ factor_value[0] = rand * brush_settings->random_hue * 0.5f;
+ }
+ else {
+ factor_value[0] = random_color[0];
+ }
+
+ /* Apply random curve. */
+ if (brush_settings->flag2 & GP_BRUSH_USE_HUE_RAND_PRESS) {
+ factor_value[0] *= BKE_curvemapping_evaluateF(
+ brush_settings->curve_rand_hue, 0, pen_pressure);
+ }
+ }
+
+ /* Apply randomness to Saturation. */
+ if (brush_settings->random_saturation > 0.0f) {
+ if ((brush_settings->flag2 & GP_BRUSH_USE_SAT_AT_STROKE) == 0) {
+ float rand = BLI_hash_int_01(BLI_hash_int_2d(iy, gpd->runtime.sbuffer_used)) * 2.0f - 1.0f;
+ factor_value[1] = rand * brush_settings->random_saturation;
+ }
+ else {
+ factor_value[1] = random_color[1];
+ }
+
+ /* Apply random curve. */
+ if (brush_settings->flag2 & GP_BRUSH_USE_SAT_RAND_PRESS) {
+ factor_value[1] *= BKE_curvemapping_evaluateF(
+ brush_settings->curve_rand_saturation, 0, pen_pressure);
+ }
+ }
+
+ /* Apply randomness to Value. */
+ if (brush_settings->random_value > 0.0f) {
+ if ((brush_settings->flag2 & GP_BRUSH_USE_VAL_AT_STROKE) == 0) {
+ float rand = BLI_hash_int_01(BLI_hash_int_2d(iz, gpd->runtime.sbuffer_used)) * 2.0f - 1.0f;
+ factor_value[2] = rand * brush_settings->random_value;
+ }
+ else {
+ factor_value[2] = random_color[2];
+ }
+
+ /* Apply random curve. */
+ if (brush_settings->flag2 & GP_BRUSH_USE_VAL_RAND_PRESS) {
+ factor_value[2] *= BKE_curvemapping_evaluateF(
+ brush_settings->curve_rand_value, 0, pen_pressure);
+ }
+ }
+
+ rgb_to_hsv_v(tpt->vert_color, hsv);
+ add_v3_v3(hsv, factor_value);
+ /* For Hue need to cover all range, but for Saturation and Value
+ * is not logic because the effect is too hard, so the value is just clamped. */
+ if (hsv[0] < 0.0f) {
+ hsv[0] += 1.0f;
+ }
+ else if (hsv[0] > 1.0f) {
+ hsv[0] -= 1.0f;
+ }
+
+ CLAMP3(hsv, 0.0f, 1.0f);
+ hsv_to_rgb_v(hsv, tpt->vert_color);
+ }
+}
+
+void ED_gpencil_sbuffer_vertex_color_set(Depsgraph *depsgraph,
+ Object *ob,
+ ToolSettings *ts,
+ Brush *brush,
+ Material *material,
+ float random_color[3],
+ float pen_pressure)
{
bGPdata *gpd = (bGPdata *)ob->data;
Object *ob_eval = (Object *)DEG_get_evaluated_id(depsgraph, &ob->id);
bGPdata *gpd_eval = (bGPdata *)ob_eval->data;
MaterialGPencilStyle *gp_style = material->gp_style;
+ int idx = gpd->runtime.sbuffer_used;
+ tGPspoint *tpt = (tGPspoint *)gpd->runtime.sbuffer + idx;
+
float vertex_color[4];
copy_v3_v3(vertex_color, brush->rgb);
vertex_color[3] = brush->gpencil_settings->vertex_factor;
@@ -2559,15 +2740,18 @@ void ED_gpencil_sbuffer_vertex_color_set(
}
/* Copy stroke vertex color. */
if (GPENCIL_USE_VERTEX_COLOR_STROKE(ts, brush)) {
- copy_v4_v4(gpd->runtime.vert_color, vertex_color);
+ copy_v4_v4(tpt->vert_color, vertex_color);
}
else {
- copy_v4_v4(gpd->runtime.vert_color, gp_style->stroke_rgba);
+ copy_v4_v4(tpt->vert_color, gp_style->stroke_rgba);
}
- /* Copy to eval data because paint operators don't tag refresh until end for speedup painting. */
+ /* Random Color. */
+ gpencil_sbuffer_vertex_color_random(gpd, brush, tpt, random_color, pen_pressure);
+
+ /* Copy to eval data because paint operators don't tag refresh until end for speedup
+ painting. */
if (gpd_eval != NULL) {
- copy_v4_v4(gpd_eval->runtime.vert_color, gpd->runtime.vert_color);
copy_v4_v4(gpd_eval->runtime.vert_color_fill, gpd->runtime.vert_color_fill);
gpd_eval->runtime.matid = gpd->runtime.matid;
}
diff --git a/source/blender/editors/gpencil/gpencil_uv.c b/source/blender/editors/gpencil/gpencil_uv.c
index 1da32dcc537..0dfc7e0728e 100644
--- a/source/blender/editors/gpencil/gpencil_uv.c
+++ b/source/blender/editors/gpencil/gpencil_uv.c
@@ -59,8 +59,8 @@ typedef struct GpUvData {
float ob_scale;
float initial_length;
+ float initial_transform[2];
float pixel_size; /* use when mouse input is interpreted as spatial distance */
- bool is_modal;
/* Arrays of original loc/rot/scale by stroke. */
float (*array_loc)[2];
@@ -92,9 +92,9 @@ static void gpencil_uv_transform_update_header(wmOperator *op, bContext *C)
const char *str = TIP_("Confirm: Enter/LClick, Cancel: (Esc/RClick) %s");
char msg[UI_MAX_DRAW_STR];
- ScrArea *sa = CTX_wm_area(C);
+ ScrArea *area = CTX_wm_area(C);
- if (sa) {
+ if (area) {
char flts_str[NUM_STR_REP_LEN * 2];
switch (mode) {
case GP_UV_TRANSLATE: {
@@ -120,7 +120,7 @@ static void gpencil_uv_transform_update_header(wmOperator *op, bContext *C)
break;
}
BLI_snprintf(msg, sizeof(msg), str, flts_str, flts_str + NUM_STR_REP_LEN);
- ED_area_status_text(sa, msg);
+ ED_area_status_text(area, msg);
}
}
@@ -140,19 +140,12 @@ static void gpencil_stroke_center(bGPDstroke *gps, float r_center[3])
}
}
-static bool gpencil_uv_transform_init(bContext *C, wmOperator *op, const bool is_modal)
+static bool gpencil_uv_transform_init(bContext *C, wmOperator *op)
{
GpUvData *opdata;
- if (is_modal) {
- float zero[2] = {0.0f};
- RNA_float_set_array(op->ptr, "location", zero);
- RNA_float_set(op->ptr, "rotation", 0.0f);
- RNA_float_set(op->ptr, "scale", 1.0f);
- }
op->customdata = opdata = MEM_mallocN(sizeof(GpUvData), __func__);
- opdata->is_modal = is_modal;
opdata->ob = CTX_data_active_object(C);
opdata->gpd = (bGPdata *)opdata->ob->data;
gp_point_conversion_init(C, &opdata->gsc);
@@ -164,20 +157,17 @@ static bool gpencil_uv_transform_init(bContext *C, wmOperator *op, const bool is
opdata->vinit_rotation[0] = 1.0f;
opdata->vinit_rotation[1] = 0.0f;
- if (is_modal) {
- ARegion *region = CTX_wm_region(C);
+ ARegion *region = CTX_wm_region(C);
- opdata->draw_handle_pixel = ED_region_draw_cb_activate(
- region->type, ED_region_draw_mouse_line_cb, opdata->mcenter, REGION_DRAW_POST_PIXEL);
- }
+ opdata->draw_handle_pixel = ED_region_draw_cb_activate(
+ region->type, ED_region_draw_mouse_line_cb, opdata->mcenter, REGION_DRAW_POST_PIXEL);
/* Calc selected strokes center. */
zero_v2(opdata->mcenter);
float center[3] = {0.0f};
int i = 0;
/* Need use evaluated to get the viewport final position. */
- GP_EVALUATED_STROKES_BEGIN(gpstroke_iter, C, gpl, gps)
- {
+ GP_EVALUATED_STROKES_BEGIN (gpstroke_iter, C, gpl, gps) {
if (gps->flag & GP_STROKE_SELECT) {
float r_center[3];
gpencil_stroke_center(gps, r_center);
@@ -206,7 +196,7 @@ static bool gpencil_uv_transform_init(bContext *C, wmOperator *op, const bool is
}
GP_EDITABLE_STROKES_END(gpstroke_iter);
}
- /* convert to 2D */
+ /* Convert to 2D. */
gp_point_3d_to_xy(&opdata->gsc, GP_STROKE_3DSPACE, center, opdata->mcenter);
return true;
@@ -215,20 +205,18 @@ static bool gpencil_uv_transform_init(bContext *C, wmOperator *op, const bool is
static void gpencil_uv_transform_exit(bContext *C, wmOperator *op)
{
GpUvData *opdata;
- ScrArea *sa = CTX_wm_area(C);
+ ScrArea *area = CTX_wm_area(C);
opdata = op->customdata;
- if (opdata->is_modal) {
- ARegion *region = CTX_wm_region(C);
+ ARegion *region = CTX_wm_region(C);
- ED_region_draw_cb_exit(region->type, opdata->draw_handle_pixel);
- }
+ ED_region_draw_cb_exit(region->type, opdata->draw_handle_pixel);
WM_cursor_set(CTX_wm_window(C), WM_CURSOR_DEFAULT);
- if (sa) {
- ED_area_status_text(sa, NULL);
+ if (area) {
+ ED_area_status_text(area, NULL);
}
WM_main_add_notifier(NC_GEOM | ND_DATA, NULL);
@@ -254,66 +242,54 @@ static bool gpencil_uv_transform_calc(bContext *C, wmOperator *op)
const int mode = RNA_enum_get(op->ptr, "mode");
GpUvData *opdata = op->customdata;
bGPdata *gpd = opdata->gpd;
+
bool changed = false;
/* Get actual vector. */
float vr[2];
+ float mdiff[2];
+
sub_v2_v2v2(vr, opdata->mouse, opdata->mcenter);
normalize_v2(vr);
- float location[2];
- RNA_float_get_array(op->ptr, "location", location);
-
- float uv_rotation = (opdata->is_modal) ? angle_signed_v2v2(opdata->vinit_rotation, vr) :
- RNA_float_get(op->ptr, "rotation");
- uv_rotation *= SMOOTH_FACTOR;
-
- if (opdata->is_modal) {
- RNA_float_set(op->ptr, "rotation", uv_rotation);
- }
+ float uv_rotation = angle_signed_v2v2(opdata->vinit_rotation, vr);
int i = 0;
- /* Apply transformations to all strokes. */
- if ((mode == GP_UV_TRANSLATE) || (!opdata->is_modal)) {
- float mdiff[2];
- mdiff[0] = opdata->mcenter[0] - opdata->mouse[0];
- mdiff[1] = opdata->mcenter[1] - opdata->mouse[1];
+ /* Translate. */
+ if (mode == GP_UV_TRANSLATE) {
+
+ mdiff[0] = opdata->mouse[0] - opdata->initial_transform[0];
+ /* Y axis is inverted. */
+ mdiff[1] = (opdata->mouse[1] - opdata->initial_transform[1]) * -1.0f;
/* Apply a big amount of smooth always for translate to get smooth result. */
- mul_v2_fl(mdiff, 0.006f);
+ mul_v2_fl(mdiff, 0.002f);
+ RNA_float_set_array(op->ptr, "location", mdiff);
- /* Apply angle in translation. */
- mdiff[0] *= cos(uv_rotation);
- mdiff[1] *= sin(uv_rotation);
- if (opdata->is_modal) {
- RNA_float_set_array(op->ptr, "location", mdiff);
- }
+ GP_EDITABLE_STROKES_BEGIN (gpstroke_iter, C, gpl, gps) {
+ if (gps->flag & GP_STROKE_SELECT) {
- changed = (bool)((mdiff[0] != 0.0f) || (mdiff[1] != 0.0f));
- if (changed) {
- GP_EDITABLE_STROKES_BEGIN (gpstroke_iter, C, gpl, gps) {
- if (gps->flag & GP_STROKE_SELECT) {
- if (opdata->is_modal) {
- add_v2_v2v2(gps->uv_translation, opdata->array_loc[i], mdiff);
- }
- else {
- copy_v2_v2(gps->uv_translation, location);
- }
- /* Calc geometry data. */
- BKE_gpencil_stroke_geometry_update(gps);
- i++;
- }
+ sub_v2_v2v2(gps->uv_translation, opdata->array_loc[i], mdiff);
+ changed = true;
+
+ /* Calc geometry data. */
+ BKE_gpencil_stroke_geometry_update(gps);
+ i++;
}
- GP_EDITABLE_STROKES_END(gpstroke_iter);
}
+ GP_EDITABLE_STROKES_END(gpstroke_iter);
}
- if ((mode == GP_UV_ROTATE) || (!opdata->is_modal)) {
- changed = (bool)(uv_rotation != 0.0f);
+ /* Rotate. */
+ if (mode == GP_UV_ROTATE) {
+ changed |= (bool)(uv_rotation != 0.0f);
+ RNA_float_set(op->ptr, "rotation", uv_rotation);
+
if (changed) {
GP_EDITABLE_STROKES_BEGIN (gpstroke_iter, C, gpl, gps) {
if (gps->flag & GP_STROKE_SELECT) {
- gps->uv_rotation = (opdata->is_modal) ? opdata->array_rot[i] + uv_rotation : uv_rotation;
+ gps->uv_rotation = opdata->array_rot[i] - uv_rotation;
+
/* Calc geometry data. */
BKE_gpencil_stroke_geometry_update(gps);
i++;
@@ -323,25 +299,22 @@ static bool gpencil_uv_transform_calc(bContext *C, wmOperator *op)
}
}
- if ((mode == GP_UV_SCALE) || (!opdata->is_modal)) {
- float mdiff[2];
+ /* Scale. */
+ if (mode == GP_UV_SCALE) {
mdiff[0] = opdata->mcenter[0] - opdata->mouse[0];
mdiff[1] = opdata->mcenter[1] - opdata->mouse[1];
- float scale = (opdata->is_modal) ?
- ((len_v2(mdiff) - opdata->initial_length) * opdata->pixel_size) /
- opdata->ob_scale :
- RNA_float_get(op->ptr, "scale");
+ float scale = ((len_v2(mdiff) - opdata->initial_length) * opdata->pixel_size) /
+ opdata->ob_scale;
+
scale *= SMOOTH_FACTOR;
+ RNA_float_set(op->ptr, "scale", scale);
- if (opdata->is_modal) {
- RNA_float_set(op->ptr, "scale", scale);
- }
+ changed |= (bool)(scale != 0.0f);
- changed = (bool)(scale != 0.0f);
if (changed) {
GP_EDITABLE_STROKES_BEGIN (gpstroke_iter, C, gpl, gps) {
if (gps->flag & GP_STROKE_SELECT) {
- gps->uv_scale = (opdata->is_modal) ? opdata->array_scale[i] + scale : scale;
+ gps->uv_scale = opdata->array_scale[i] + scale;
/* Calc geometry data. */
BKE_gpencil_stroke_geometry_update(gps);
i++;
@@ -351,7 +324,7 @@ static bool gpencil_uv_transform_calc(bContext *C, wmOperator *op)
}
}
- if ((!opdata->is_modal) || (changed)) {
+ if (changed) {
/* Update cursor line. */
DEG_id_tag_update(&gpd->id, ID_RECALC_GEOMETRY);
WM_main_add_notifier(NC_GEOM | ND_DATA, NULL);
@@ -361,23 +334,11 @@ static bool gpencil_uv_transform_calc(bContext *C, wmOperator *op)
return changed;
}
-static int gpencil_transform_fill_exec(bContext *C, wmOperator *op)
-{
- if (!gpencil_uv_transform_init(C, op, false)) {
- return OPERATOR_CANCELLED;
- }
-
- if (!gpencil_uv_transform_calc(C, op)) {
- gpencil_uv_transform_exit(C, op);
- return OPERATOR_CANCELLED;
- }
-
- gpencil_uv_transform_exit(C, op);
- return OPERATOR_FINISHED;
-}
-
static bool gpencil_transform_fill_poll(bContext *C)
{
+ if (!ED_operator_view3d_active(C)) {
+ return false;
+ }
Object *ob = CTX_data_active_object(C);
if ((ob == NULL) || (ob->type != OB_GPENCIL)) {
return false;
@@ -402,7 +363,7 @@ static int gpencil_transform_fill_invoke(bContext *C, wmOperator *op, const wmEv
float mlen[2];
float center_3d[3];
- if (!gpencil_uv_transform_init(C, op, true)) {
+ if (!gpencil_uv_transform_init(C, op)) {
return OPERATOR_CANCELLED;
}
@@ -412,16 +373,22 @@ static int gpencil_transform_fill_invoke(bContext *C, wmOperator *op, const wmEv
opdata->mouse[1] = event->mval[1];
copy_v3_v3(center_3d, opdata->ob->loc);
- mlen[0] = opdata->mcenter[0] - event->mval[0];
- mlen[1] = opdata->mcenter[1] - event->mval[1];
+ mlen[0] = event->mval[0] - opdata->mcenter[0];
+ mlen[1] = event->mval[1] - opdata->mcenter[1];
opdata->initial_length = len_v2(mlen);
- opdata->pixel_size = rv3d ? ED_view3d_pixel_size(rv3d, center_3d) : 1.0f;
+ /* Consider initial offset as zero position. */
+ copy_v2fl_v2i(opdata->initial_transform, event->mval);
+
+ /* Consider initial position as the orientation vector. */
+ const int mode = RNA_enum_get(op->ptr, "mode");
+ if (mode == GP_UV_ROTATE) {
+ opdata->vinit_rotation[0] = mlen[0];
+ opdata->vinit_rotation[1] = mlen[1];
+ normalize_v2(opdata->vinit_rotation);
+ }
- /* Calc init rotation vector. */
- float mouse[2] = {event->mval[0], event->mval[1]};
- sub_v2_v2v2(opdata->vinit_rotation, mouse, opdata->mcenter);
- normalize_v2(opdata->vinit_rotation);
+ opdata->pixel_size = rv3d ? ED_view3d_pixel_size(rv3d, center_3d) : 1.0f;
gpencil_uv_transform_calc(C, op);
@@ -490,7 +457,6 @@ void GPENCIL_OT_transform_fill(wmOperatorType *ot)
/* api callbacks */
ot->invoke = gpencil_transform_fill_invoke;
ot->modal = gpencil_transform_fill_modal;
- ot->exec = gpencil_transform_fill_exec;
ot->cancel = gpencil_transform_fill_cancel;
ot->poll = gpencil_transform_fill_poll;
diff --git a/source/blender/editors/gpencil/gpencil_vertex_ops.c b/source/blender/editors/gpencil/gpencil_vertex_ops.c
index 3039a83009e..4db88bd552f 100644
--- a/source/blender/editors/gpencil/gpencil_vertex_ops.c
+++ b/source/blender/editors/gpencil/gpencil_vertex_ops.c
@@ -844,7 +844,7 @@ void GPENCIL_OT_material_to_vertex_color(wmOperatorType *ot)
ot->prop = RNA_def_boolean(ot->srna,
"remove",
true,
- "Remove Unused Materiales",
+ "Remove Unused Materials",
"Remove any unused material after the conversion");
RNA_def_boolean(ot->srna, "palette", true, "Create Palette", "Create a new palette with colors");
RNA_def_boolean(ot->srna, "selected", false, "Only Selected", "Convert only selected strokes");
diff --git a/source/blender/editors/gpencil/gpencil_vertex_paint.c b/source/blender/editors/gpencil/gpencil_vertex_paint.c
index 0c3b29ab1ea..10867bd1e0d 100644
--- a/source/blender/editors/gpencil/gpencil_vertex_paint.c
+++ b/source/blender/editors/gpencil/gpencil_vertex_paint.c
@@ -897,8 +897,7 @@ static void gp_vertexpaint_select_stroke(tGP_BrushVertexpaintData *gso,
* brush region (either within stroke painted, or on its lines)
* - this assumes that linewidth is irrelevant
*/
- if (gp_stroke_inside_circle(
- gso->mval, gso->mval_prev, radius, pc1[0], pc1[1], pc2[0], pc2[1])) {
+ if (gp_stroke_inside_circle(gso->mval, radius, pc1[0], pc1[1], pc2[0], pc2[1])) {
/* To each point individually... */
pt = &gps->points[i];
diff --git a/source/blender/editors/gpencil/gpencil_weight_paint.c b/source/blender/editors/gpencil/gpencil_weight_paint.c
index 51d5df1f405..2ebf1aba353 100644
--- a/source/blender/editors/gpencil/gpencil_weight_paint.c
+++ b/source/blender/editors/gpencil/gpencil_weight_paint.c
@@ -449,8 +449,7 @@ static void gp_weightpaint_select_stroke(tGP_BrushWeightpaintData *gso,
* brush region (either within stroke painted, or on its lines)
* - this assumes that linewidth is irrelevant
*/
- if (gp_stroke_inside_circle(
- gso->mval, gso->mval_prev, radius, pc1[0], pc1[1], pc2[0], pc2[1])) {
+ if (gp_stroke_inside_circle(gso->mval, radius, pc1[0], pc1[1], pc2[0], pc2[1])) {
/* To each point individually... */
pt = &gps->points[i];
diff --git a/source/blender/editors/include/ED_anim_api.h b/source/blender/editors/include/ED_anim_api.h
index 7f4c3470020..426a470b128 100644
--- a/source/blender/editors/include/ED_anim_api.h
+++ b/source/blender/editors/include/ED_anim_api.h
@@ -74,13 +74,13 @@ typedef struct bAnimContext {
/** editor->mode */
short mode;
- /** sa->spacetype */
+ /** area->spacetype */
short spacetype;
/** active region -> type (channels or main) */
short regiontype;
/** editor host */
- struct ScrArea *sa;
+ struct ScrArea *area;
/** editor data */
struct SpaceLink *sl;
/** region within editor */
@@ -229,6 +229,7 @@ typedef enum eAnim_ChannelType {
ANIMTYPE_DSHAIR,
ANIMTYPE_DSPOINTCLOUD,
ANIMTYPE_DSVOLUME,
+ ANIMTYPE_DSSIMULATION,
ANIMTYPE_SHAPEKEY,
@@ -337,17 +338,17 @@ typedef enum eAnimFilter_Flags {
/* 'Object' channels */
#define SEL_OBJC(base) (CHECK_TYPE_INLINE(base, Base *), ((base->flag & SELECT)))
#define EXPANDED_OBJC(ob) \
- (CHECK_TYPE_INLINE(ob, Object *), ((ob->nlaflag & OB_ADS_COLLAPSED) == 0))
+ (CHECK_TYPE_INLINE(ob, Object *), (((ob)->nlaflag & OB_ADS_COLLAPSED) == 0))
/* 'Sub-object' channels (flags stored in Data block) */
#define FILTER_SKE_OBJD(key) (CHECK_TYPE_INLINE(key, Key *), ((key->flag & KEY_DS_EXPAND)))
#define FILTER_MAT_OBJD(ma) (CHECK_TYPE_INLINE(ma, Material *), ((ma->flag & MA_DS_EXPAND)))
#define FILTER_LAM_OBJD(la) (CHECK_TYPE_INLINE(la, Light *), ((la->flag & LA_DS_EXPAND)))
#define FILTER_CAM_OBJD(ca) (CHECK_TYPE_INLINE(ca, Camera *), ((ca->flag & CAM_DS_EXPAND)))
#define FILTER_CACHEFILE_OBJD(cf) \
- (CHECK_TYPE_INLINE(cf, CacheFile *), ((cf->flag & CACHEFILE_DS_EXPAND)))
+ (CHECK_TYPE_INLINE(cf, CacheFile *), (((cf)->flag & CACHEFILE_DS_EXPAND)))
#define FILTER_CUR_OBJD(cu) (CHECK_TYPE_INLINE(cu, Curve *), ((cu->flag & CU_DS_EXPAND)))
#define FILTER_PART_OBJD(part) \
- (CHECK_TYPE_INLINE(part, ParticleSettings *), ((part->flag & PART_DS_EXPAND)))
+ (CHECK_TYPE_INLINE(part, ParticleSettings *), (((part)->flag & PART_DS_EXPAND)))
#define FILTER_MBALL_OBJD(mb) (CHECK_TYPE_INLINE(mb, MetaBall *), ((mb->flag2 & MB_DS_EXPAND)))
#define FILTER_ARM_OBJD(arm) (CHECK_TYPE_INLINE(arm, bArmature *), ((arm->flag & ARM_DS_EXPAND)))
#define FILTER_MESH_OBJD(me) (CHECK_TYPE_INLINE(me, Mesh *), ((me->flag & ME_DS_EXPAND)))
@@ -356,9 +357,11 @@ typedef enum eAnimFilter_Flags {
#define FILTER_HAIR_OBJD(ha) (CHECK_TYPE_INLINE(ha, Hair *), ((ha->flag & HA_DS_EXPAND)))
#define FILTER_POINTS_OBJD(pt) (CHECK_TYPE_INLINE(pt, PointCloud *), ((pt->flag & PT_DS_EXPAND)))
#define FILTER_VOLUME_OBJD(vo) (CHECK_TYPE_INLINE(vo, Volume *), ((vo->flag & VO_DS_EXPAND)))
+#define FILTER_SIMULATION_OBJD(sim) \
+ (CHECK_TYPE_INLINE(sim, Simulation *), ((sim->flag & SIM_DS_EXPAND)))
/* Variable use expanders */
#define FILTER_NTREE_DATA(ntree) \
- (CHECK_TYPE_INLINE(ntree, bNodeTree *), ((ntree->flag & NTREE_DS_EXPAND)))
+ (CHECK_TYPE_INLINE(ntree, bNodeTree *), (((ntree)->flag & NTREE_DS_EXPAND)))
#define FILTER_TEX_DATA(tex) (CHECK_TYPE_INLINE(tex, Tex *), ((tex->flag & TEX_DS_EXPAND)))
/* 'Sub-object/Action' channels (flags stored in Action) */
@@ -369,11 +372,11 @@ typedef enum eAnimFilter_Flags {
/* Actions (also used for Dopesheet) */
/* Action Channel Group */
-#define EDITABLE_AGRP(agrp) ((agrp->flag & AGRP_PROTECTED) == 0)
+#define EDITABLE_AGRP(agrp) (((agrp)->flag & AGRP_PROTECTED) == 0)
#define EXPANDED_AGRP(ac, agrp) \
- (((!(ac) || ((ac)->spacetype != SPACE_GRAPH)) && (agrp->flag & AGRP_EXPANDED)) || \
- (((ac) && ((ac)->spacetype == SPACE_GRAPH)) && (agrp->flag & AGRP_EXPANDED_G)))
-#define SEL_AGRP(agrp) ((agrp->flag & AGRP_SELECTED) || (agrp->flag & AGRP_ACTIVE))
+ (((!(ac) || ((ac)->spacetype != SPACE_GRAPH)) && ((agrp)->flag & AGRP_EXPANDED)) || \
+ (((ac) && ((ac)->spacetype == SPACE_GRAPH)) && ((agrp)->flag & AGRP_EXPANDED_G)))
+#define SEL_AGRP(agrp) (((agrp)->flag & AGRP_SELECTED) || ((agrp)->flag & AGRP_ACTIVE))
/* F-Curve Channels */
#define EDITABLE_FCU(fcu) ((fcu->flag & FCURVE_PROTECTED) == 0)
#define SEL_FCU(fcu) (fcu->flag & FCURVE_SELECTED)
@@ -433,7 +436,8 @@ typedef enum eAnimFilter_Flags {
#define NLACHANNEL_FIRST_TOP(ac) \
(UI_view2d_scale_get_y(&(ac)->region->v2d) * -UI_TIME_SCRUB_MARGIN_Y - NLACHANNEL_SKIP)
#define NLACHANNEL_HEIGHT(snla) \
- ((snla && (snla->flag & SNLA_NOSTRIPCURVES)) ? (0.8f * U.widget_unit) : (1.2f * U.widget_unit))
+ (((snla) && ((snla)->flag & SNLA_NOSTRIPCURVES)) ? (0.8f * U.widget_unit) : \
+ (1.2f * U.widget_unit))
#define NLACHANNEL_SKIP (0.1f * U.widget_unit)
#define NLACHANNEL_STEP(snla) (NLACHANNEL_HEIGHT(snla) + NLACHANNEL_SKIP)
/* Additional offset to give some room at the end. */
@@ -648,9 +652,6 @@ enum eAnimEditDraw_CurrentFrame {
/* main call to draw current-frame indicator in an Animation Editor */
void ANIM_draw_cfra(const struct bContext *C, struct View2D *v2d, short flag);
-/* main call to draw "number box" in scrollbar for current frame indicator */
-void ANIM_draw_cfra_number(const struct bContext *C, struct View2D *v2d, short flag);
-
/* ------------- Preview Range Drawing -------------- */
/* main call to draw preview range curtains */
@@ -840,7 +841,7 @@ void ED_animedit_unlink_action(struct bContext *C,
bool force_delete);
/* Drivers Editor - Utility to set up UI correctly */
-void ED_drivers_editor_init(struct bContext *C, struct ScrArea *sa);
+void ED_drivers_editor_init(struct bContext *C, struct ScrArea *area);
/* ************************************************ */
diff --git a/source/blender/editors/include/ED_armature.h b/source/blender/editors/include/ED_armature.h
index 40f5cade0d5..ac9eb415b23 100644
--- a/source/blender/editors/include/ED_armature.h
+++ b/source/blender/editors/include/ED_armature.h
@@ -120,13 +120,11 @@ typedef struct EditBone {
} temp;
} EditBone;
-#define BONESEL_ROOT (1 << 28)
-#define BONESEL_TIP (1 << 29)
-#define BONESEL_BONE (1 << 30)
+#define BONESEL_ROOT (2 << 29u)
+#define BONESEL_TIP (1 << 30u)
+#define BONESEL_BONE (1 << 31u)
#define BONESEL_ANY (BONESEL_TIP | BONESEL_ROOT | BONESEL_BONE)
-#define BONESEL_NOSEL (1u << 31u)
-
/* useful macros */
#define EBONE_VISIBLE(arm, ebone) \
(CHECK_TYPE_INLINE(arm, bArmature *), \
@@ -134,7 +132,7 @@ typedef struct EditBone {
(((arm)->layer & (ebone)->layer) && !((ebone)->flag & BONE_HIDDEN_A)))
#define EBONE_SELECTABLE(arm, ebone) \
- (EBONE_VISIBLE(arm, ebone) && !(ebone->flag & BONE_UNSELECTABLE))
+ (EBONE_VISIBLE(arm, ebone) && !((ebone)->flag & BONE_UNSELECTABLE))
#define EBONE_EDITABLE(ebone) \
(CHECK_TYPE_INLINE(ebone, EditBone *), \
@@ -187,6 +185,10 @@ struct Object *ED_armature_object_and_ebone_from_select_buffer(struct Object **o
uint objects_len,
int hit,
struct EditBone **r_ebone);
+struct Base *ED_armature_base_and_pchan_from_select_buffer(struct Base **bases,
+ uint bases_len,
+ int hit,
+ struct bPoseChannel **r_pchan);
struct Base *ED_armature_base_and_bone_from_select_buffer(struct Base **bases,
uint bases_len,
int hit,
diff --git a/source/blender/editors/include/ED_datafiles.h b/source/blender/editors/include/ED_datafiles.h
index b6f9593c261..ad1cde5406d 100644
--- a/source/blender/editors/include/ED_datafiles.h
+++ b/source/blender/editors/include/ED_datafiles.h
@@ -54,9 +54,6 @@ extern char datatoc_alert_icons_png[];
extern int datatoc_splash_png_size;
extern char datatoc_splash_png[];
-extern int datatoc_splash_2x_png_size;
-extern char datatoc_splash_2x_png[];
-
extern int datatoc_bfont_pfb_size;
extern char datatoc_bfont_pfb[];
diff --git a/source/blender/editors/include/ED_gizmo_library.h b/source/blender/editors/include/ED_gizmo_library.h
index 07eade23506..a1a5d65b61d 100644
--- a/source/blender/editors/include/ED_gizmo_library.h
+++ b/source/blender/editors/include/ED_gizmo_library.h
@@ -40,9 +40,15 @@ void ED_gizmotypes_facemap_3d(void);
void ED_gizmotypes_preselect_3d(void);
void ED_gizmotypes_primitive_3d(void);
void ED_gizmotypes_blank_3d(void);
+void ED_gizmotypes_snap_3d(void);
-struct Object;
+struct ARegion;
struct bContext;
+struct Depsgraph;
+struct Object;
+struct SnapObjectContext;
+struct wmWindowManager;
+struct View3D;
struct wmGizmo;
/* -------------------------------------------------------------------- */
@@ -223,8 +229,9 @@ enum {
};
/* -------------------------------------------------------------------- */
-/* Gizmo Drawing Functions */
+/* Specific gizmos utils */
+/* dial3d_gizmo.c */
struct Dial3dParams {
int draw_options;
float angle_ofs;
@@ -241,6 +248,33 @@ void ED_gizmotypes_dial_3d_draw_util(const float matrix_basis[4][4],
const bool select,
struct Dial3dParams *params);
+/* snap3d_gizmo.c */
+#define USE_SNAP_DETECT_FROM_KEYMAP_HACK
+void ED_gizmotypes_snap_3d_draw_util(struct RegionView3D *rv3d,
+ const float loc_prev[3],
+ const float loc_curr[3],
+ const float normal[3],
+ const uchar color_line[4],
+ const uchar color_point[4],
+ const short snap_elem_type);
+struct SnapObjectContext *ED_gizmotypes_snap_3d_context_ensure(struct Scene *scene,
+ const struct ARegion *region,
+ const struct View3D *v3d,
+ struct wmGizmo *gz);
+
+bool ED_gizmotypes_snap_3d_invert_snap_get(struct wmGizmo *gz);
+void ED_gizmotypes_snap_3d_toggle_set(struct wmGizmo *gz, bool enable);
+void ED_gizmotypes_snap_3d_toggle_clear(struct wmGizmo *gz);
+
+short ED_gizmotypes_snap_3d_update(struct wmGizmo *gz,
+ struct Depsgraph *depsgraph,
+ const struct ARegion *region,
+ const struct View3D *v3d,
+ const struct wmWindowManager *wm,
+ const float mval_fl[2],
+ float r_loc[3],
+ float r_nor[3]);
+
#ifdef __cplusplus
}
#endif
diff --git a/source/blender/editors/include/ED_gpencil.h b/source/blender/editors/include/ED_gpencil.h
index 66aa301f08c..58364e69679 100644
--- a/source/blender/editors/include/ED_gpencil.h
+++ b/source/blender/editors/include/ED_gpencil.h
@@ -34,6 +34,7 @@ struct PointerRNA;
struct Brush;
struct GP_SpaceConversion;
+struct GpRandomSettings;
struct bGPDframe;
struct bGPDlayer;
struct bGPDspoint;
@@ -48,6 +49,7 @@ struct RegionView3D;
struct ReportList;
struct Scene;
struct ScrArea;
+struct SnapObjectContext;
struct ToolSettings;
struct View3D;
struct ViewLayer;
@@ -69,14 +71,15 @@ struct wmOperator;
* Used as part of the 'stroke cache' used during drawing of new strokes
*/
typedef struct tGPspoint {
- float x, y; /* x and y coordinates of cursor (in relative to area) */
- float pressure; /* pressure of tablet at this point */
- float strength; /* pressure of tablet at this point for alpha factor */
- float time; /* Time relative to stroke start (used when converting to path) */
- float uv_fac; /* factor of uv along the stroke */
- float uv_rot; /* uv rotation for dor mode */
- float rnd[3]; /* rnd value */
- bool rnd_dirty; /* rnd flag */
+ float x, y; /* x and y coordinates of cursor (in relative to area) */
+ float pressure; /* pressure of tablet at this point */
+ float strength; /* pressure of tablet at this point for alpha factor */
+ float time; /* Time relative to stroke start (used when converting to path) */
+ float uv_fac; /* factor of uv along the stroke */
+ float uv_rot; /* uv rotation for dor mode */
+ float rnd[3]; /* rnd value */
+ bool rnd_dirty; /* rnd flag */
+ float vert_color[4]; /* Point vertex color. */
} tGPspoint;
/* ----------- Grease Pencil Tools/Context ------------- */
@@ -88,20 +91,20 @@ struct bGPdata *ED_gpencil_data_get_active(const struct bContext *C);
struct bGPdata *ED_gpencil_data_get_active_evaluated(const struct bContext *C);
/* Context independent (i.e. each required part is passed in instead) */
-struct bGPdata **ED_gpencil_data_get_pointers_direct(struct ScrArea *sa,
+struct bGPdata **ED_gpencil_data_get_pointers_direct(struct ScrArea *area,
struct Object *ob,
struct PointerRNA *r_ptr);
-struct bGPdata *ED_gpencil_data_get_active_direct(struct ScrArea *sa, struct Object *ob);
+struct bGPdata *ED_gpencil_data_get_active_direct(struct ScrArea *area, struct Object *ob);
struct bGPdata *ED_annotation_data_get_active(const struct bContext *C);
struct bGPdata **ED_annotation_data_get_pointers(const struct bContext *C,
struct PointerRNA *r_ptr);
struct bGPdata **ED_annotation_data_get_pointers_direct(struct ID *screen_id,
- struct ScrArea *sa,
+ struct ScrArea *area,
struct Scene *scene,
struct PointerRNA *r_ptr);
struct bGPdata *ED_annotation_data_get_active_direct(struct ID *screen_id,
- struct ScrArea *sa,
+ struct ScrArea *area,
struct Scene *scene);
bool ED_gpencil_data_owner_is_annotation(struct PointerRNA *owner_ptr);
@@ -111,7 +114,7 @@ bool ED_gpencil_has_keyframe_v3d(struct Scene *scene, struct Object *ob, int cfr
/* ----------- Stroke Editing Utilities ---------------- */
-bool ED_gpencil_stroke_can_use_direct(const struct ScrArea *sa, const struct bGPDstroke *gps);
+bool ED_gpencil_stroke_can_use_direct(const struct ScrArea *area, const struct bGPDstroke *gps);
bool ED_gpencil_stroke_can_use(const struct bContext *C, const struct bGPDstroke *gps);
bool ED_gpencil_stroke_color_use(struct Object *ob,
const struct bGPDlayer *gpl,
@@ -178,7 +181,11 @@ bool ED_gpencil_anim_copybuf_paste(struct bAnimContext *ac, const short copy_mod
int ED_gpencil_session_active(void);
int ED_undo_gpencil_step(struct bContext *C, int step, const char *name);
-/* ------------ Grease-Pencil Armature weights ------------------ */
+/* ------------ Grease-Pencil Armature ------------------ */
+bool ED_gpencil_add_armature(const struct bContext *C,
+ struct ReportList *reports,
+ struct Object *ob,
+ struct Object *ob_arm);
bool ED_gpencil_add_armature_weights(const struct bContext *C,
struct ReportList *reports,
struct Object *ob,
@@ -233,7 +240,6 @@ void ED_gp_project_point_to_plane(const struct Scene *scene,
struct bGPDspoint *pt);
void ED_gpencil_drawing_reference_get(const struct Scene *scene,
const struct Object *ob,
- struct bGPDlayer *gpl,
char align_flag,
float vec[3]);
void ED_gpencil_project_stroke_to_view(struct bContext *C,
@@ -293,12 +299,18 @@ void ED_gpencil_fill_vertex_color_set(struct ToolSettings *ts,
struct bGPDstroke *gps);
void ED_gpencil_point_vertex_color_set(struct ToolSettings *ts,
struct Brush *brush,
- struct bGPDspoint *pt);
+ struct bGPDspoint *pt,
+ struct tGPspoint *tpt);
void ED_gpencil_sbuffer_vertex_color_set(struct Depsgraph *depsgraph,
struct Object *ob,
struct ToolSettings *ts,
struct Brush *brush,
- struct Material *material);
+ struct Material *material,
+ float random_color[3],
+ float pen_pressure);
+void ED_gpencil_init_random_settings(struct Brush *brush,
+ const int mval[2],
+ struct GpRandomSettings *random_settings);
bool ED_gpencil_stroke_check_collision(struct GP_SpaceConversion *gsc,
struct bGPDstroke *gps,
diff --git a/source/blender/editors/include/ED_image.h b/source/blender/editors/include/ED_image.h
index 910cf362a37..a8476e3d1ca 100644
--- a/source/blender/editors/include/ED_image.h
+++ b/source/blender/editors/include/ED_image.h
@@ -69,7 +69,7 @@ void ED_space_image_get_size(struct SpaceImage *sima, int *r_width, int *r_heigh
void ED_space_image_get_size_fl(struct SpaceImage *sima, float r_size[2]);
void ED_space_image_get_aspect(struct SpaceImage *sima, float *r_aspx, float *r_aspy);
void ED_space_image_get_zoom(struct SpaceImage *sima,
- struct ARegion *region,
+ const struct ARegion *region,
float *r_zoomx,
float *r_zoomy);
void ED_space_image_get_uv_aspect(struct SpaceImage *sima, float *r_aspx, float *r_aspy);
@@ -88,14 +88,18 @@ void ED_image_get_uv_aspect(struct Image *ima,
float *r_aspx,
float *r_aspy);
void ED_image_mouse_pos(struct SpaceImage *sima,
- struct ARegion *region,
+ const struct ARegion *region,
const int mval[2],
float co[2]);
void ED_image_view_center_to_point(struct SpaceImage *sima, float x, float y);
-void ED_image_point_pos(
- struct SpaceImage *sima, struct ARegion *region, float x, float y, float *r_x, float *r_y);
+void ED_image_point_pos(struct SpaceImage *sima,
+ const struct ARegion *region,
+ float x,
+ float y,
+ float *r_x,
+ float *r_y);
void ED_image_point_pos__reverse(struct SpaceImage *sima,
- struct ARegion *region,
+ const struct ARegion *region,
const float co[2],
float r_co[2]);
bool ED_image_slot_cycle(struct Image *image, int direction);
diff --git a/source/blender/editors/include/ED_info.h b/source/blender/editors/include/ED_info.h
index 82662a6b118..1146c49bef2 100644
--- a/source/blender/editors/include/ED_info.h
+++ b/source/blender/editors/include/ED_info.h
@@ -31,9 +31,9 @@ struct Main;
/* info_stats.c */
void ED_info_stats_clear(struct ViewLayer *view_layer);
-const char *ED_info_stats_string(struct Main *bmain,
- struct Scene *scene,
- struct ViewLayer *view_layer);
+const char *ED_info_footer_string(struct ViewLayer *view_layer);
+void ED_info_draw_stats(
+ Main *bmain, Scene *scene, ViewLayer *view_layer, int x, int *y, int height);
#ifdef __cplusplus
}
diff --git a/source/blender/editors/include/ED_keyframes_edit.h b/source/blender/editors/include/ED_keyframes_edit.h
index 3ae0c254000..28bc0b22790 100644
--- a/source/blender/editors/include/ED_keyframes_edit.h
+++ b/source/blender/editors/include/ED_keyframes_edit.h
@@ -24,12 +24,12 @@
#ifndef __ED_KEYFRAMES_EDIT_H__
#define __ED_KEYFRAMES_EDIT_H__
+#include "ED_anim_api.h" /* for enum eAnimFilter_Flags */
+
#ifdef __cplusplus
extern "C" {
#endif
-#include "ED_anim_api.h" /* for enum eAnimFilter_Flags */
-
struct BezTriple;
struct FCurve;
struct Scene;
@@ -106,8 +106,8 @@ typedef enum eEditKeyframes_Mirror {
typedef struct KeyframeEdit_LassoData {
rctf *rectf_scaled;
const rctf *rectf_view;
- const int (*mcords)[2];
- int mcords_tot;
+ const int (*mcoords)[2];
+ int mcoords_len;
} KeyframeEdit_LassoData;
/* use with BEZT_OK_REGION_CIRCLE */
diff --git a/source/blender/editors/include/ED_keyframing.h b/source/blender/editors/include/ED_keyframing.h
index 6cac3e60531..5635ef2800a 100644
--- a/source/blender/editors/include/ED_keyframing.h
+++ b/source/blender/editors/include/ED_keyframing.h
@@ -24,6 +24,9 @@
#ifndef __ED_KEYFRAMING_H__
#define __ED_KEYFRAMING_H__
+#include "DNA_anim_types.h"
+#include "RNA_types.h"
+
#ifdef __cplusplus
extern "C" {
#endif
@@ -50,9 +53,6 @@ struct PropertyRNA;
struct NlaKeyframingContext;
-#include "DNA_anim_types.h"
-#include "RNA_types.h"
-
/* ************ Keyframing Management **************** */
/* Get the active settings for keyframing settings from context (specifically the given scene)
@@ -198,7 +198,7 @@ typedef struct KeyingSetInfo {
cbKeyingSet_Generate generate;
/* RNA integration */
- struct ExtensionRNA ext;
+ struct ExtensionRNA rna_ext;
} KeyingSetInfo;
/* -------- */
@@ -430,14 +430,14 @@ void ANIM_copy_as_driver(struct ID *target_id, const char *target_path, const ch
/* Auto-Keying macros for use by various tools */
/* check if auto-keyframing is enabled (per scene takes precedence) */
#define IS_AUTOKEY_ON(scene) \
- ((scene) ? (scene->toolsettings->autokey_mode & AUTOKEY_ON) : (U.autokey_mode & AUTOKEY_ON))
+ ((scene) ? ((scene)->toolsettings->autokey_mode & AUTOKEY_ON) : (U.autokey_mode & AUTOKEY_ON))
/* check the mode for auto-keyframing (per scene takes precedence) */
#define IS_AUTOKEY_MODE(scene, mode) \
- ((scene) ? (scene->toolsettings->autokey_mode == AUTOKEY_MODE_##mode) : \
+ ((scene) ? ((scene)->toolsettings->autokey_mode == AUTOKEY_MODE_##mode) : \
(U.autokey_mode == AUTOKEY_MODE_##mode))
/* check if a flag is set for auto-keyframing (per scene takes precedence) */
#define IS_AUTOKEY_FLAG(scene, flag) \
- ((scene) ? ((scene->toolsettings->autokey_flag & AUTOKEY_FLAG_##flag) || \
+ ((scene) ? (((scene)->toolsettings->autokey_flag & AUTOKEY_FLAG_##flag) || \
(U.autokey_flag & AUTOKEY_FLAG_##flag)) : \
(U.autokey_flag & AUTOKEY_FLAG_##flag))
diff --git a/source/blender/editors/include/ED_mask.h b/source/blender/editors/include/ED_mask.h
index 7d314c0c462..5aafc0702da 100644
--- a/source/blender/editors/include/ED_mask.h
+++ b/source/blender/editors/include/ED_mask.h
@@ -43,22 +43,25 @@ void ED_keymap_mask(struct wmKeyConfig *keyconf);
void ED_operatormacros_mask(void);
/* mask_query.c */
-void ED_mask_get_size(struct ScrArea *sa, int *width, int *height);
-void ED_mask_zoom(struct ScrArea *sa, struct ARegion *region, float *zoomx, float *zoomy);
-void ED_mask_get_aspect(struct ScrArea *sa, struct ARegion *region, float *aspx, float *aspy);
+void ED_mask_get_size(struct ScrArea *area, int *width, int *height);
+void ED_mask_zoom(struct ScrArea *area, struct ARegion *region, float *zoomx, float *zoomy);
+void ED_mask_get_aspect(struct ScrArea *area, struct ARegion *region, float *aspx, float *aspy);
-void ED_mask_pixelspace_factor(struct ScrArea *sa,
+void ED_mask_pixelspace_factor(struct ScrArea *area,
struct ARegion *region,
float *scalex,
float *scaley);
-void ED_mask_mouse_pos(struct ScrArea *sa, struct ARegion *region, const int mval[2], float co[2]);
+void ED_mask_mouse_pos(struct ScrArea *area,
+ struct ARegion *region,
+ const int mval[2],
+ float co[2]);
void ED_mask_point_pos(
- struct ScrArea *sa, struct ARegion *region, float x, float y, float *xr, float *yr);
+ struct ScrArea *area, struct ARegion *region, float x, float y, float *xr, float *yr);
void ED_mask_point_pos__reverse(
- struct ScrArea *sa, struct ARegion *region, float x, float y, float *xr, float *yr);
+ struct ScrArea *area, struct ARegion *region, float x, float y, float *xr, float *yr);
-void ED_mask_cursor_location_get(struct ScrArea *sa, float cursor[2]);
+void ED_mask_cursor_location_get(struct ScrArea *area, float cursor[2]);
bool ED_mask_selected_minmax(const struct bContext *C, float min[2], float max[2]);
/* mask_draw.c */
diff --git a/source/blender/editors/include/ED_mesh.h b/source/blender/editors/include/ED_mesh.h
index 6d3396bb393..20e54df1ccb 100644
--- a/source/blender/editors/include/ED_mesh.h
+++ b/source/blender/editors/include/ED_mesh.h
@@ -139,6 +139,12 @@ bool BMBVH_EdgeVisible(struct BMBVHTree *tree,
struct View3D *v3d,
struct Object *obedit);
+void EDBM_project_snap_verts(struct bContext *C,
+ struct Depsgraph *depsgraph,
+ struct ARegion *region,
+ struct Object *obedit,
+ struct BMEditMesh *em);
+
/* editmesh_automerge.c */
void EDBM_automerge(struct Object *ob, bool update, const char hflag, const float dist);
void EDBM_automerge_and_split(struct Object *ob,
@@ -293,13 +299,6 @@ void ED_operatortypes_mesh(void);
void ED_operatormacros_mesh(void);
void ED_keymap_mesh(struct wmKeyConfig *keyconf);
-/* editmesh_tools.c (could be moved) */
-void EDBM_project_snap_verts(struct bContext *C,
- struct Depsgraph *depsgraph,
- struct ARegion *region,
- struct Object *obedit,
- struct BMEditMesh *em);
-
/* editface.c */
void paintface_flush_flags(struct bContext *C, struct Object *ob, short flag);
bool paintface_mouse_select(struct bContext *C,
@@ -450,9 +449,19 @@ int join_mesh_exec(struct bContext *C, struct wmOperator *op);
int join_mesh_shapes_exec(struct bContext *C, struct wmOperator *op);
/* mirror lookup api */
-int ED_mesh_mirror_spatial_table(
- struct Object *ob, struct BMEditMesh *em, struct Mesh *me_eval, const float co[3], char mode);
-int ED_mesh_mirror_topo_table(struct Object *ob, struct Mesh *me_eval, char mode);
+/* Spatial Mirror */
+void ED_mesh_mirror_spatial_table_begin(struct Object *ob,
+ struct BMEditMesh *em,
+ struct Mesh *me_eval);
+void ED_mesh_mirror_spatial_table_end(struct Object *ob);
+int ED_mesh_mirror_spatial_table_lookup(struct Object *ob,
+ struct BMEditMesh *em,
+ struct Mesh *me_eval,
+ const float co[3]);
+
+/* Topology Mirror */
+void ED_mesh_mirror_topo_table_begin(struct Object *ob, struct Mesh *me_eval);
+void ED_mesh_mirror_topo_table_end(struct Object *ob);
/* retrieves mirrored cache vert, or NULL if there isn't one.
* note: calling this without ensuring the mirror cache state
diff --git a/source/blender/editors/include/ED_node.h b/source/blender/editors/include/ED_node.h
index ae2b4989069..3471f9dcce9 100644
--- a/source/blender/editors/include/ED_node.h
+++ b/source/blender/editors/include/ED_node.h
@@ -37,6 +37,7 @@ struct Tex;
struct View2D;
struct bContext;
struct bNode;
+struct bNodeSocket;
struct bNodeSocketType;
struct bNodeTree;
struct bNodeTree;
@@ -79,6 +80,10 @@ void ED_node_draw_snap(
struct View2D *v2d, const float cent[2], float size, NodeBorder border, unsigned int pos);
/* node_draw.c */
+void ED_node_socket_draw(struct bNodeSocket *sock,
+ const struct rcti *rect,
+ const float color[4],
+ float scale);
void ED_node_tree_update(const struct bContext *C);
void ED_node_tag_update_id(struct ID *id);
void ED_node_tag_update_nodetree(struct Main *bmain, struct bNodeTree *ntree, struct bNode *node);
@@ -86,14 +91,15 @@ void ED_node_sort(struct bNodeTree *ntree);
float ED_node_grid_size(void);
/* node_relationships.c */
-void ED_node_link_intersect_test(struct ScrArea *sa, int test);
-void ED_node_link_insert(struct Main *bmain, struct ScrArea *sa);
+void ED_node_link_intersect_test(struct ScrArea *area, int test);
+void ED_node_link_insert(struct Main *bmain, struct ScrArea *area);
/* node_edit.c */
void ED_node_set_tree_type(struct SpaceNode *snode, struct bNodeTreeType *typeinfo);
bool ED_node_is_compositor(struct SpaceNode *snode);
bool ED_node_is_shader(struct SpaceNode *snode);
bool ED_node_is_texture(struct SpaceNode *snode);
+bool ED_node_is_simulation(struct SpaceNode *snode);
void ED_node_shader_default(const struct bContext *C, struct ID *id);
void ED_node_composit_default(const struct bContext *C, struct Scene *scene);
@@ -101,7 +107,10 @@ void ED_node_texture_default(const struct bContext *C, struct Tex *tex);
bool ED_node_select_check(ListBase *lb);
void ED_node_select_all(ListBase *lb, int action);
void ED_node_post_apply_transform(struct bContext *C, struct bNodeTree *ntree);
-void ED_node_set_active(struct Main *bmain, struct bNodeTree *ntree, struct bNode *node);
+void ED_node_set_active(struct Main *bmain,
+ struct bNodeTree *ntree,
+ struct bNode *node,
+ bool *r_active_texture_changed);
void ED_node_composite_job(const struct bContext *C,
struct bNodeTree *nodetree,
diff --git a/source/blender/editors/include/ED_object.h b/source/blender/editors/include/ED_object.h
index 3b38969d6bf..e027efce1d3 100644
--- a/source/blender/editors/include/ED_object.h
+++ b/source/blender/editors/include/ED_object.h
@@ -24,6 +24,9 @@
#ifndef __ED_OBJECT_H__
#define __ED_OBJECT_H__
+#include "BLI_compiler_attrs.h"
+#include "DNA_object_enums.h"
+
#ifdef __cplusplus
extern "C" {
#endif
@@ -54,9 +57,6 @@ struct wmOperator;
struct wmOperatorType;
struct wmWindowManager;
-#include "BLI_compiler_attrs.h"
-#include "DNA_object_enums.h"
-
/* object_edit.c */
/* context.object */
struct Object *ED_object_context(struct bContext *C);
@@ -212,13 +212,11 @@ bool ED_object_editmode_load(struct Main *bmain, struct Object *obedit);
void ED_object_vpaintmode_enter_ex(struct Main *bmain,
struct Depsgraph *depsgraph,
- struct wmWindowManager *wm,
struct Scene *scene,
struct Object *ob);
void ED_object_vpaintmode_enter(struct bContext *C, struct Depsgraph *depsgraph);
void ED_object_wpaintmode_enter_ex(struct Main *bmain,
struct Depsgraph *depsgraph,
- struct wmWindowManager *wm,
struct Scene *scene,
struct Object *ob);
void ED_object_wpaintmode_enter(struct bContext *C, struct Depsgraph *depsgraph);
@@ -228,6 +226,20 @@ void ED_object_vpaintmode_exit(struct bContext *C);
void ED_object_wpaintmode_exit_ex(struct Object *ob);
void ED_object_wpaintmode_exit(struct bContext *C);
+void ED_object_texture_paint_mode_enter_ex(struct Main *bmain, struct Scene *scene, Object *ob);
+void ED_object_texture_paint_mode_enter(struct bContext *C);
+
+void ED_object_texture_paint_mode_exit_ex(struct Main *bmain, struct Scene *scene, Object *ob);
+void ED_object_texture_paint_mode_exit(struct bContext *C);
+
+void ED_object_particle_edit_mode_enter_ex(struct Depsgraph *depsgraph,
+ struct Scene *scene,
+ Object *ob);
+void ED_object_particle_edit_mode_enter(struct bContext *C);
+
+void ED_object_particle_edit_mode_exit_ex(struct Scene *scene, Object *ob);
+void ED_object_particle_edit_mode_exit(struct bContext *C);
+
void ED_object_sculptmode_enter_ex(struct Main *bmain,
struct Depsgraph *depsgraph,
struct Scene *scene,
@@ -246,7 +258,7 @@ void ED_object_sculptmode_exit(struct bContext *C, struct Depsgraph *depsgraph);
void ED_object_location_from_view(struct bContext *C, float loc[3]);
void ED_object_rotation_from_quat(float rot[3], const float quat[4], const char align_axis);
void ED_object_rotation_from_view(struct bContext *C, float rot[3], const char align_axis);
-void ED_object_base_init_transform_on_add(struct Object *obejct,
+void ED_object_base_init_transform_on_add(struct Object *object,
const float loc[3],
const float rot[3]);
float ED_object_new_primitive_matrix(struct bContext *C,
@@ -260,6 +272,7 @@ float ED_object_new_primitive_matrix(struct bContext *C,
#define OBJECT_ADD_SIZE_MAXF 1.0e12f
void ED_object_add_unit_props_size(struct wmOperatorType *ot);
+void ED_object_add_unit_props_radius_ex(struct wmOperatorType *ot, float default_value);
void ED_object_add_unit_props_radius(struct wmOperatorType *ot);
void ED_object_add_generic_props(struct wmOperatorType *ot, bool do_editmode);
void ED_object_add_mesh_props(struct wmOperatorType *ot);
@@ -268,6 +281,7 @@ bool ED_object_add_generic_get_opts(struct bContext *C,
const char view_align_axis,
float loc[3],
float rot[3],
+ float scale[3],
bool *enter_editmode,
unsigned short *local_view_bits,
bool *is_view_aligned);
@@ -302,15 +316,15 @@ void ED_objects_recalculate_paths(struct bContext *C,
eObjectPathCalcRange range);
/* constraints */
-struct ListBase *get_active_constraints(struct Object *ob);
-struct ListBase *get_constraint_lb(struct Object *ob,
- struct bConstraint *con,
- struct bPoseChannel **r_pchan);
-struct bConstraint *get_active_constraint(struct Object *ob);
+struct ListBase *ED_object_constraint_list_from_context(struct Object *ob);
+struct ListBase *ED_object_constraint_list_from_constraint(struct Object *ob,
+ struct bConstraint *con,
+ struct bPoseChannel **r_pchan);
+struct bConstraint *ED_object_constraint_active_get(struct Object *ob);
void object_test_constraints(struct Main *bmain, struct Object *ob);
-void ED_object_constraint_set_active(struct Object *ob, struct bConstraint *con);
+void ED_object_constraint_active_set(struct Object *ob, struct bConstraint *con);
void ED_object_constraint_update(struct Main *bmain, struct Object *ob);
void ED_object_constraint_dependency_update(struct Main *bmain, struct Object *ob);
@@ -327,11 +341,12 @@ bool ED_object_mode_compat_set(struct bContext *C,
struct Object *ob,
eObjectMode mode,
struct ReportList *reports);
-void ED_object_mode_toggle(struct bContext *C, eObjectMode mode);
-void ED_object_mode_set(struct bContext *C, eObjectMode mode);
-void ED_object_mode_exit(struct bContext *C, struct Depsgraph *depsgraph);
+bool ED_object_mode_set_ex(struct bContext *C,
+ eObjectMode mode,
+ bool use_undo,
+ struct ReportList *reports);
+bool ED_object_mode_set(struct bContext *C, eObjectMode mode);
-bool ED_object_mode_generic_enter(struct bContext *C, eObjectMode object_mode);
void ED_object_mode_generic_exit(struct Main *bmain,
struct Depsgraph *depsgraph,
struct Scene *scene,
diff --git a/source/blender/editors/include/ED_outliner.h b/source/blender/editors/include/ED_outliner.h
index be1ee786a75..0325ad9fdba 100644
--- a/source/blender/editors/include/ED_outliner.h
+++ b/source/blender/editors/include/ED_outliner.h
@@ -27,14 +27,16 @@
extern "C" {
#endif
+struct Base;
struct ListBase;
+struct SpaceOutliner;
struct bContext;
bool ED_outliner_collections_editor_poll(struct bContext *C);
void ED_outliner_selected_objects_get(const struct bContext *C, struct ListBase *objects);
-Base *ED_outliner_give_base_under_cursor(struct bContext *C, const int mval[2]);
+struct Base *ED_outliner_give_base_under_cursor(struct bContext *C, const int mval[2]);
void ED_outliner_select_sync_from_object_tag(struct bContext *C);
void ED_outliner_select_sync_from_edit_bone_tag(struct bContext *C);
diff --git a/source/blender/editors/include/ED_particle.h b/source/blender/editors/include/ED_particle.h
index c8a4dc5b49d..789db5ae56e 100644
--- a/source/blender/editors/include/ED_particle.h
+++ b/source/blender/editors/include/ED_particle.h
@@ -71,8 +71,8 @@ bool PE_mouse_particles(
bool PE_box_select(struct bContext *C, const struct rcti *rect, const int sel_op);
bool PE_circle_select(struct bContext *C, const int sel_op, const int mval[2], float rad);
int PE_lasso_select(struct bContext *C,
- const int mcords[][2],
- const short moves,
+ const int mcoords[][2],
+ const int mcoords_len,
const int sel_op);
bool PE_deselect_all_visible_ex(struct PTCacheEdit *edit);
bool PE_deselect_all_visible(struct bContext *C);
diff --git a/source/blender/editors/include/ED_render.h b/source/blender/editors/include/ED_render.h
index 0645b256a15..f03739c74c4 100644
--- a/source/blender/editors/include/ED_render.h
+++ b/source/blender/editors/include/ED_render.h
@@ -48,8 +48,8 @@ void ED_operatortypes_render(void);
/* render_update.c */
void ED_render_engine_changed(struct Main *bmain);
-void ED_render_engine_area_exit(struct Main *bmain, struct ScrArea *sa);
-void ED_render_view_layer_changed(struct Main *bmain, struct bScreen *sc);
+void ED_render_engine_area_exit(struct Main *bmain, struct ScrArea *area);
+void ED_render_view_layer_changed(struct Main *bmain, struct bScreen *screen);
/* Callbacks handling data update events coming from depsgraph. */
diff --git a/source/blender/editors/include/ED_screen.h b/source/blender/editors/include/ED_screen.h
index 0785b0e97f7..bc6a4b23609 100644
--- a/source/blender/editors/include/ED_screen.h
+++ b/source/blender/editors/include/ED_screen.h
@@ -63,14 +63,14 @@ struct wmWindowManager;
/* regions */
void ED_region_do_listen(struct wmWindow *win,
- struct ScrArea *sa,
+ struct ScrArea *area,
struct ARegion *region,
struct wmNotifier *note,
const Scene *scene);
void ED_region_do_layout(struct bContext *C, struct ARegion *region);
void ED_region_do_draw(struct bContext *C, struct ARegion *region);
void ED_region_exit(struct bContext *C, struct ARegion *region);
-void ED_region_remove(struct bContext *C, struct ScrArea *sa, struct ARegion *region);
+void ED_region_remove(struct bContext *C, struct ScrArea *area, struct ARegion *region);
void ED_region_pixelspace(struct ARegion *region);
void ED_region_update_rect(struct ARegion *region);
void ED_region_floating_initialize(struct ARegion *region);
@@ -104,14 +104,14 @@ void ED_region_header(const struct bContext *C, struct ARegion *region);
void ED_region_header_layout(const struct bContext *C, struct ARegion *region);
void ED_region_header_draw(const struct bContext *C, struct ARegion *region);
-void ED_region_cursor_set(struct wmWindow *win, struct ScrArea *sa, struct ARegion *region);
+void ED_region_cursor_set(struct wmWindow *win, struct ScrArea *area, struct ARegion *region);
void ED_region_toggle_hidden(struct bContext *C, struct ARegion *region);
void ED_region_visibility_change_update(struct bContext *C,
- struct ScrArea *sa,
+ struct ScrArea *area,
struct ARegion *region);
/* screen_ops.c */
void ED_region_visibility_change_update_animated(struct bContext *C,
- struct ScrArea *sa,
+ struct ScrArea *area,
struct ARegion *region);
void ED_region_info_draw(struct ARegion *region,
@@ -146,14 +146,14 @@ void ED_area_do_mgs_subscribe_for_tool_header(const struct bContext *C,
struct WorkSpace *workspace,
struct Scene *scene,
struct bScreen *screen,
- struct ScrArea *sa,
+ struct ScrArea *area,
struct ARegion *region,
struct wmMsgBus *mbus);
void ED_area_do_mgs_subscribe_for_tool_ui(const struct bContext *C,
struct WorkSpace *workspace,
struct Scene *scene,
struct bScreen *screen,
- struct ScrArea *sa,
+ struct ScrArea *area,
struct ARegion *region,
struct wmMsgBus *mbus);
@@ -162,7 +162,7 @@ void ED_region_message_subscribe(struct bContext *C,
struct WorkSpace *workspace,
struct Scene *scene,
struct bScreen *screen,
- struct ScrArea *sa,
+ struct ScrArea *area,
struct ARegion *region,
struct wmMsgBus *mbus);
@@ -171,21 +171,21 @@ void ED_spacetypes_keymap(struct wmKeyConfig *keyconf);
int ED_area_header_switchbutton(const struct bContext *C, struct uiBlock *block, int yco);
/* areas */
-void ED_area_initialize(struct wmWindowManager *wm, struct wmWindow *win, struct ScrArea *sa);
-void ED_area_exit(struct bContext *C, struct ScrArea *sa);
+void ED_area_initialize(struct wmWindowManager *wm, struct wmWindow *win, struct ScrArea *area);
+void ED_area_exit(struct bContext *C, struct ScrArea *area);
int ED_screen_area_active(const struct bContext *C);
void ED_screen_global_areas_refresh(struct wmWindow *win);
void ED_screen_global_areas_sync(struct wmWindow *win);
-void ED_area_do_listen(struct wmWindow *win, ScrArea *sa, struct wmNotifier *note, Scene *scene);
-void ED_area_tag_redraw(ScrArea *sa);
-void ED_area_tag_redraw_no_rebuild(ScrArea *sa);
-void ED_area_tag_redraw_regiontype(ScrArea *sa, int type);
-void ED_area_tag_refresh(ScrArea *sa);
-void ED_area_do_refresh(struct bContext *C, ScrArea *sa);
-struct AZone *ED_area_azones_update(ScrArea *sa, const int mouse_xy[]);
-void ED_area_status_text(ScrArea *sa, const char *str);
-void ED_area_newspace(struct bContext *C, ScrArea *sa, int type, const bool skip_ar_exit);
-void ED_area_prevspace(struct bContext *C, ScrArea *sa);
+void ED_area_do_listen(struct wmWindow *win, ScrArea *area, struct wmNotifier *note, Scene *scene);
+void ED_area_tag_redraw(ScrArea *area);
+void ED_area_tag_redraw_no_rebuild(ScrArea *area);
+void ED_area_tag_redraw_regiontype(ScrArea *area, int type);
+void ED_area_tag_refresh(ScrArea *area);
+void ED_area_do_refresh(struct bContext *C, ScrArea *area);
+struct AZone *ED_area_azones_update(ScrArea *area, const int mouse_xy[]);
+void ED_area_status_text(ScrArea *area, const char *str);
+void ED_area_newspace(struct bContext *C, ScrArea *area, int type, const bool skip_region_exit);
+void ED_area_prevspace(struct bContext *C, ScrArea *area);
void ED_area_swapspace(struct bContext *C, ScrArea *sa1, ScrArea *sa2);
int ED_area_headersize(void);
int ED_area_header_alignment_or_fallback(const ScrArea *area, int fallback);
@@ -215,7 +215,7 @@ ScrArea *ED_screen_areas_iter_next(const bScreen *screen, const ScrArea *area);
#define ED_screen_verts_iter(win, screen, vert_name) \
for (ScrVert *vert_name = (win)->global_areas.vertbase.first ? \
(win)->global_areas.vertbase.first : \
- screen->vertbase.first; \
+ (screen)->vertbase.first; \
vert_name != NULL; \
vert_name = (vert_name == (win)->global_areas.vertbase.last) ? (screen)->vertbase.first : \
vert_name->next)
@@ -224,25 +224,25 @@ ScrArea *ED_screen_areas_iter_next(const bScreen *screen, const ScrArea *area);
void ED_screens_initialize(struct Main *bmain, struct wmWindowManager *wm);
void ED_screen_draw_edges(struct wmWindow *win);
void ED_screen_draw_join_shape(struct ScrArea *sa1, struct ScrArea *sa2);
-void ED_screen_draw_split_preview(struct ScrArea *sa, const int dir, const float fac);
+void ED_screen_draw_split_preview(struct ScrArea *area, const int dir, const float fac);
void ED_screen_refresh(struct wmWindowManager *wm, struct wmWindow *win);
void ED_screen_ensure_updated(struct wmWindowManager *wm,
struct wmWindow *win,
struct bScreen *screen);
void ED_screen_do_listen(struct bContext *C, struct wmNotifier *note);
-bool ED_screen_change(struct bContext *C, struct bScreen *sc);
+bool ED_screen_change(struct bContext *C, struct bScreen *screen);
void ED_screen_scene_change(struct bContext *C, struct wmWindow *win, struct Scene *scene);
void ED_screen_set_active_region(struct bContext *C, struct wmWindow *win, const int xy[2]);
void ED_screen_exit(struct bContext *C, struct wmWindow *window, struct bScreen *screen);
void ED_screen_animation_timer(struct bContext *C, int redraws, int sync, int enable);
void ED_screen_animation_timer_update(struct bScreen *screen, int redraws);
-void ED_screen_restore_temp_type(struct bContext *C, ScrArea *sa);
-ScrArea *ED_screen_full_newspace(struct bContext *C, ScrArea *sa, int type);
-void ED_screen_full_prevspace(struct bContext *C, ScrArea *sa);
-void ED_screen_full_restore(struct bContext *C, ScrArea *sa);
+void ED_screen_restore_temp_type(struct bContext *C, ScrArea *area);
+ScrArea *ED_screen_full_newspace(struct bContext *C, ScrArea *area, int type);
+void ED_screen_full_prevspace(struct bContext *C, ScrArea *area);
+void ED_screen_full_restore(struct bContext *C, ScrArea *area);
struct ScrArea *ED_screen_state_toggle(struct bContext *C,
struct wmWindow *win,
- struct ScrArea *sa,
+ struct ScrArea *area,
const short state);
ScrArea *ED_screen_temp_space_open(struct bContext *C,
const char *title,
@@ -347,6 +347,7 @@ bool ED_operator_info_active(struct bContext *C);
bool ED_operator_console_active(struct bContext *C);
bool ED_operator_object_active(struct bContext *C);
+bool ED_operator_object_active_editable_ex(struct bContext *C, const Object *ob);
bool ED_operator_object_active_editable(struct bContext *C);
bool ED_operator_object_active_editable_mesh(struct bContext *C);
bool ED_operator_object_active_editable_font(struct bContext *C);
@@ -422,7 +423,7 @@ void ED_region_generic_tools_region_message_subscribe(const struct bContext *C,
struct WorkSpace *workspace,
struct Scene *scene,
struct bScreen *screen,
- struct ScrArea *sa,
+ struct ScrArea *area,
struct ARegion *region,
struct wmMsgBus *mbus);
int ED_region_generic_tools_region_snap_size(const struct ARegion *region, int size, int axis);
@@ -442,15 +443,15 @@ bool ED_region_overlap_isect_xy_with_margin(const ARegion *region,
const int event_xy[2],
const int margin);
-bool ED_region_panel_category_gutter_calc_rect(const ARegion *region, rcti *r_ar_gutter);
+bool ED_region_panel_category_gutter_calc_rect(const ARegion *region, rcti *r_region_gutter);
bool ED_region_panel_category_gutter_isect_xy(const ARegion *region, const int event_xy[2]);
bool ED_region_contains_xy(const struct ARegion *region, const int event_xy[2]);
/* interface_region_hud.c */
struct ARegionType *ED_area_type_hud(int space_type);
-void ED_area_type_hud_clear(struct wmWindowManager *wm, ScrArea *sa_keep);
-void ED_area_type_hud_ensure(struct bContext *C, struct ScrArea *sa);
+void ED_area_type_hud_clear(struct wmWindowManager *wm, ScrArea *area_keep);
+void ED_area_type_hud_ensure(struct bContext *C, struct ScrArea *area);
/* default keymaps, bitflags (matches order of evaluation). */
enum {
diff --git a/source/blender/editors/include/ED_screen_types.h b/source/blender/editors/include/ED_screen_types.h
index 06c2c3039f5..51f3eea74fa 100644
--- a/source/blender/editors/include/ED_screen_types.h
+++ b/source/blender/editors/include/ED_screen_types.h
@@ -34,11 +34,11 @@ extern "C" {
typedef struct ScreenAnimData {
ARegion *region; /* do not read from this, only for comparing if region exists */
short redraws;
- short flag; /* flags for playback */
- int sfra; /* frame that playback was started from */
- int nextfra; /* next frame to go to (when ANIMPLAY_FLAG_USE_NEXT_FRAME is set) */
- double last_duration; /* used for frame dropping */
- bool from_anim_edit; /* playback was invoked from animation editor */
+ short flag; /* flags for playback */
+ int sfra; /* frame that playback was started from */
+ int nextfra; /* next frame to go to (when ANIMPLAY_FLAG_USE_NEXT_FRAME is set) */
+ double lagging_frame_count; /* used for frame dropping */
+ bool from_anim_edit; /* playback was invoked from animation editor */
} ScreenAnimData;
/* for animplayer */
diff --git a/source/blender/editors/include/ED_sculpt.h b/source/blender/editors/include/ED_sculpt.h
index 26871cf8dd0..e61c7be5216 100644
--- a/source/blender/editors/include/ED_sculpt.h
+++ b/source/blender/editors/include/ED_sculpt.h
@@ -54,6 +54,11 @@ void ED_sculpt_undosys_type(struct UndoType *ut);
void ED_sculpt_undo_geometry_begin(struct Object *ob, const char *name);
void ED_sculpt_undo_geometry_end(struct Object *ob);
+/* Undo for changes happening on a base mesh for multires sculpting.
+ * if there is no multires sculpt active regular undo is used. */
+void ED_sculpt_undo_push_multires_mesh_begin(struct bContext *C, const char *str);
+void ED_sculpt_undo_push_multires_mesh_end(struct bContext *C, const char *str);
+
#ifdef __cplusplus
}
#endif
diff --git a/source/blender/editors/include/ED_transform.h b/source/blender/editors/include/ED_transform.h
index 2a5803cbc4d..a62deb9d69f 100644
--- a/source/blender/editors/include/ED_transform.h
+++ b/source/blender/editors/include/ED_transform.h
@@ -123,7 +123,7 @@ struct bContext;
void BIF_clearTransformOrientation(struct bContext *C);
void BIF_removeTransformOrientation(struct bContext *C, struct TransformOrientation *ts);
void BIF_removeTransformOrientationIndex(struct bContext *C, int index);
-void BIF_createTransformOrientation(struct bContext *C,
+bool BIF_createTransformOrientation(struct bContext *C,
struct ReportList *reports,
const char *name,
const bool use_view,
@@ -157,9 +157,24 @@ int BIF_countTransformOrientation(const struct bContext *C);
#define P_GPENCIL_EDIT (1 << 13)
#define P_CURSOR_EDIT (1 << 14)
#define P_CLNOR_INVALIDATE (1 << 15)
+/* For properties performed when confirming the transformation. */
+#define P_POST_TRANSFORM (1 << 19)
void Transform_Properties(struct wmOperatorType *ot, int flags);
+/* *** transform_orientations.c *** */
+void ED_transform_calc_orientation_from_type(const struct bContext *C, float r_mat[3][3]);
+short ED_transform_calc_orientation_from_type_ex(const struct bContext *C,
+ float r_mat[3][3],
+ /* extra args */
+ struct Scene *scene,
+ struct RegionView3D *rv3d,
+ struct Object *ob,
+ struct Object *obedit,
+ const short orientation_type,
+ int orientation_index_custom,
+ const int pivot_point);
+
/* transform gizmos */
void VIEW3D_GGT_xform_gizmo(struct wmGizmoGroupType *gzgt);
@@ -178,18 +193,6 @@ void ED_widgetgroup_gizmo2d_rotate_callbacks_set(struct wmGizmoGroupType *gzgt);
#define SNAP_INCREMENTAL_ANGLE DEG2RAD(5.0)
-void ED_transform_calc_orientation_from_type(const struct bContext *C, float r_mat[3][3]);
-void ED_transform_calc_orientation_from_type_ex(const struct bContext *C,
- float r_mat[3][3],
- /* extra args */
- struct Scene *scene,
- struct RegionView3D *rv3d,
- struct Object *ob,
- struct Object *obedit,
- const short orientation_type,
- int orientation_index_custom,
- const int pivot_point);
-
struct TransformBounds {
float center[3]; /* Center for transform widget. */
float min[3], max[3]; /* Boundbox of selection for transform widget. */
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 b998ac87819..8feb73436a6 100644
--- a/source/blender/editors/include/ED_transform_snap_object_context.h
+++ b/source/blender/editors/include/ED_transform_snap_object_context.h
@@ -77,11 +77,8 @@ struct SnapObjectParams {
};
typedef struct SnapObjectContext SnapObjectContext;
-SnapObjectContext *ED_transform_snap_object_context_create(struct Main *bmain,
- struct Scene *scene,
- int flag);
-SnapObjectContext *ED_transform_snap_object_context_create_view3d(struct Main *bmain,
- struct Scene *scene,
+SnapObjectContext *ED_transform_snap_object_context_create(struct Scene *scene, int flag);
+SnapObjectContext *ED_transform_snap_object_context_create_view3d(struct Scene *scene,
int flag,
/* extra args for view3d */
const struct ARegion *region,
diff --git a/source/blender/editors/include/ED_util.h b/source/blender/editors/include/ED_util.h
index 8b4829446c3..1f2706957a7 100644
--- a/source/blender/editors/include/ED_util.h
+++ b/source/blender/editors/include/ED_util.h
@@ -48,7 +48,7 @@ bool ED_editors_flush_edits_for_object(struct Main *bmain, struct Object *ob);
bool ED_editors_flush_edits_ex(struct Main *bmain, bool for_render, bool check_needs_flush);
bool ED_editors_flush_edits(struct Main *bmain);
-void ED_spacedata_id_remap(struct ScrArea *sa,
+void ED_spacedata_id_remap(struct ScrArea *area,
struct SpaceLink *sl,
struct ID *old_id,
struct ID *new_id);
diff --git a/source/blender/editors/include/ED_util_imbuf.h b/source/blender/editors/include/ED_util_imbuf.h
new file mode 100644
index 00000000000..76171383b49
--- /dev/null
+++ b/source/blender/editors/include/ED_util_imbuf.h
@@ -0,0 +1,52 @@
+/*
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * The Original Code is Copyright (C) 2008 Blender Foundation.
+ * All rights reserved.
+ */
+
+/** \file
+ * \ingroup editors
+ */
+
+#ifndef __ED_UTIL_IMBUF_H__
+#define __ED_UTIL_IMBUF_H__
+
+#include "BLI_compiler_attrs.h"
+#include "BLI_sys_types.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+struct ARegion;
+struct Main;
+struct bContext;
+struct wmEvent;
+struct wmOperator;
+
+/* ed_util_imbuf.c */
+void ED_imbuf_sample_draw(const struct bContext *C, struct ARegion *region, void *arg_info);
+void ED_imbuf_sample_exit(struct bContext *C, struct wmOperator *op);
+int ED_imbuf_sample_invoke(struct bContext *C, struct wmOperator *op, const struct wmEvent *event);
+int ED_imbuf_sample_modal(struct bContext *C, struct wmOperator *op, const struct wmEvent *event);
+void ED_imbuf_sample_cancel(struct bContext *C, struct wmOperator *op);
+bool ED_imbuf_sample_poll(struct bContext *C);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* __ED_UTIL_IMBUF_H__ */
diff --git a/source/blender/editors/include/ED_uvedit.h b/source/blender/editors/include/ED_uvedit.h
index 8c565536c71..f656aaf9c07 100644
--- a/source/blender/editors/include/ED_uvedit.h
+++ b/source/blender/editors/include/ED_uvedit.h
@@ -50,20 +50,17 @@ void ED_operatortypes_uvedit(void);
void ED_keymap_uvedit(struct wmKeyConfig *keyconf);
bool ED_uvedit_minmax(const struct Scene *scene,
- struct Image *ima,
struct Object *obedit,
float min[2],
float max[2]);
void ED_uvedit_select_all(struct BMesh *bm);
bool ED_uvedit_minmax_multi(const struct Scene *scene,
- struct Image *ima,
struct Object **objects_edit,
uint objects_len,
float r_min[2],
float r_max[2]);
bool ED_uvedit_center_multi(const struct Scene *scene,
- Image *ima,
struct Object **objects_edit,
uint objects_len,
float r_cent[2],
@@ -95,11 +92,7 @@ void ED_object_assign_active_image(struct Main *bmain,
bool ED_uvedit_test(struct Object *obedit);
/* visibility and selection */
-bool uvedit_face_visible_nolocal_ex(const struct ToolSettings *ts, struct BMFace *efa);
-bool uvedit_face_visible_test_ex(const struct ToolSettings *ts,
- struct Object *obedit,
- struct Image *ima,
- struct BMFace *efa);
+bool uvedit_face_visible_test_ex(const struct ToolSettings *ts, struct BMFace *efa);
bool uvedit_face_select_test_ex(const struct ToolSettings *ts,
struct BMFace *efa,
const int cd_loop_uv_offset);
@@ -110,11 +103,7 @@ bool uvedit_uv_select_test_ex(const struct ToolSettings *ts,
struct BMLoop *l,
const int cd_loop_uv_offset);
-bool uvedit_face_visible_nolocal(const struct Scene *scene, struct BMFace *efa);
-bool uvedit_face_visible_test(const struct Scene *scene,
- struct Object *obedit,
- struct Image *ima,
- struct BMFace *efa);
+bool uvedit_face_visible_test(const struct Scene *scene, struct BMFace *efa);
bool uvedit_face_select_test(const struct Scene *scene,
struct BMFace *efa,
const int cd_loop_uv_offset);
@@ -175,12 +164,10 @@ void uvedit_uv_select_disable(struct BMEditMesh *em,
bool ED_uvedit_nearest_uv(const struct Scene *scene,
struct Object *obedit,
- struct Image *ima,
const float co[2],
float *dist_sq,
float r_uv[2]);
bool ED_uvedit_nearest_uv_multi(const struct Scene *scene,
- struct Image *ima,
struct Object **objects,
const uint objects_len,
const float co[2],
diff --git a/source/blender/editors/include/ED_view3d.h b/source/blender/editors/include/ED_view3d.h
index bb065ee0008..beca517f0a6 100644
--- a/source/blender/editors/include/ED_view3d.h
+++ b/source/blender/editors/include/ED_view3d.h
@@ -129,6 +129,9 @@ enum eV3DCursorOrient {
void ED_view3d_background_color_get(const struct Scene *scene,
const struct View3D *v3d,
float r_color[3]);
+bool ED_view3d_has_workbench_in_texture_color(const struct Scene *scene,
+ const struct Object *ob,
+ const struct View3D *v3d);
void ED_view3d_cursor3d_position(struct bContext *C,
const int mval[2],
const bool use_depth,
@@ -246,6 +249,7 @@ void nurbs_foreachScreenVert(struct ViewContext *vc,
struct BPoint *bp,
struct BezTriple *bezt,
int beztindex,
+ bool handle_visible,
const float screen_co[2]),
void *userData,
const eV3DProjTest clip_flag);
@@ -560,10 +564,10 @@ bool edge_inside_circle(const float cent[2],
struct RegionView3D *ED_view3d_context_rv3d(struct bContext *C);
bool ED_view3d_context_user_region(struct bContext *C,
struct View3D **r_v3d,
- struct ARegion **r_ar);
-bool ED_view3d_area_user_region(const struct ScrArea *sa,
+ struct ARegion **r_region);
+bool ED_view3d_area_user_region(const struct ScrArea *area,
const struct View3D *v3d,
- struct ARegion **r_ar);
+ struct ARegion **r_region);
bool ED_operator_rv3d_user_region_poll(struct bContext *C);
void ED_view3d_init_mats_rv3d(struct Object *ob, struct RegionView3D *rv3d);
@@ -600,7 +604,7 @@ void ED_view3d_draw_setup_view(const struct wmWindowManager *wm,
struct Base *ED_view3d_give_base_under_cursor(struct bContext *C, const int mval[2]);
struct Object *ED_view3d_give_object_under_cursor(struct bContext *C, const int mval[2]);
bool ED_view3d_is_object_under_cursor(struct bContext *C, const int mval[2]);
-void ED_view3d_quadview_update(struct ScrArea *sa, struct ARegion *region, bool do_clip);
+void ED_view3d_quadview_update(struct ScrArea *area, struct ARegion *region, bool do_clip);
void ED_view3d_update_viewmat(struct Depsgraph *depsgraph,
const struct Scene *scene,
struct View3D *v3d,
@@ -702,7 +706,7 @@ void ED_view3d_operator_properties_viewmat_get(struct wmOperator *op,
/* render */
void ED_view3d_stop_render_preview(struct wmWindowManager *wm, struct ARegion *region);
-void ED_view3d_shade_update(struct Main *bmain, struct View3D *v3d, struct ScrArea *sa);
+void ED_view3d_shade_update(struct Main *bmain, struct View3D *v3d, struct ScrArea *area);
#define XRAY_ALPHA(v3d) \
(((v3d)->shading.type == OB_WIRE) ? (v3d)->shading.xray_alpha_wire : (v3d)->shading.xray_alpha)
diff --git a/source/blender/editors/include/UI_icons.h b/source/blender/editors/include/UI_icons.h
index 6fdef4a06e0..452a1fca111 100644
--- a/source/blender/editors/include/UI_icons.h
+++ b/source/blender/editors/include/UI_icons.h
@@ -428,7 +428,7 @@ DEF_ICON(FORCE_CURVE)
DEF_ICON(FORCE_BOID)
DEF_ICON(FORCE_TURBULENCE)
DEF_ICON(FORCE_DRAG)
-DEF_ICON(FORCE_SMOKEFLOW)
+DEF_ICON(FORCE_FLUIDFLOW)
DEF_ICON_BLANK(673)
DEF_ICON_BLANK(674)
DEF_ICON(RIGID_BODY)
diff --git a/source/blender/editors/include/UI_interface.h b/source/blender/editors/include/UI_interface.h
index e9027fe571f..7632d14bfb6 100644
--- a/source/blender/editors/include/UI_interface.h
+++ b/source/blender/editors/include/UI_interface.h
@@ -49,6 +49,7 @@ struct PanelType;
struct PointerRNA;
struct PropertyRNA;
struct ReportList;
+struct ResultBLF;
struct ScrArea;
struct bContext;
struct bContextStore;
@@ -239,6 +240,8 @@ enum {
#define UI_PANEL_CATEGORY_MARGIN_WIDTH (U.widget_unit * 1.0f)
+#define UI_PANEL_BOX_STYLE_MARGIN (U.widget_unit * 0.2f)
+
/* but->drawflag - these flags should only affect how the button is drawn. */
/* Note: currently, these flags _are not passed_ to the widget's state() or draw() functions
* (except for the 'align' ones)!
@@ -250,6 +253,8 @@ enum {
UI_BUT_TEXT_RIGHT = 1 << 3,
/** Prevent the button to show any tooltip. */
UI_BUT_NO_TOOLTIP = 1 << 4,
+ /** Do not add the usual horizontal padding for text drawing. */
+ UI_BUT_NO_TEXT_PADDING = 1 << 5,
/* Button align flag, for drawing groups together.
* Used in 'uiBlock.flag', take care! */
@@ -500,15 +505,24 @@ typedef void (*uiButHandleRenameFunc)(struct bContext *C, void *arg, char *origs
typedef void (*uiButHandleNFunc)(struct bContext *C, void *argN, void *arg2);
typedef void (*uiButHandleHoldFunc)(struct bContext *C, struct ARegion *butregion, uiBut *but);
typedef int (*uiButCompleteFunc)(struct bContext *C, char *str, void *arg);
-typedef struct ARegion *(*uiButSearchCreateFunc)(struct bContext *C,
- struct ARegion *butregion,
- uiBut *but);
-typedef void (*uiButSearchFunc)(const struct bContext *C,
- void *arg,
- const char *str,
- uiSearchItems *items);
-typedef void (*uiButSearchArgFreeFunc)(void *arg);
+/* Search types. */
+typedef struct ARegion *(*uiButSearchCreateFn)(struct bContext *C,
+ struct ARegion *butregion,
+ uiBut *but);
+typedef void (*uiButSearchUpdateFn)(const struct bContext *C,
+ void *arg,
+ const char *str,
+ uiSearchItems *items);
+typedef void (*uiButSearchArgFreeFn)(void *arg);
+typedef bool (*uiButSearchContextMenuFn)(struct bContext *C,
+ void *arg,
+ void *active,
+ const struct wmEvent *event);
+typedef struct ARegion *(*uiButSearchTooltipFn)(struct bContext *C,
+ struct ARegion *region,
+ void *arg,
+ void *active);
/* Must return allocated string. */
typedef char *(*uiButToolTipFunc)(struct bContext *C, void *argN, const char *tip);
@@ -619,8 +633,7 @@ void UI_popup_block_invoke_ex(struct bContext *C,
uiBlockCreateFunc func,
void *arg,
void (*arg_free)(void *arg),
- const char *opname,
- int opcontext);
+ bool can_refresh);
void UI_popup_block_ex(struct bContext *C,
uiBlockCreateFunc func,
uiBlockHandleFunc popup_func,
@@ -1567,20 +1580,25 @@ eAutoPropButsReturn uiDefAutoButsRNA(uiLayout *layout,
/* use inside searchfunc to add items */
bool UI_search_item_add(uiSearchItems *items, const char *name, void *poin, int iconid, int state);
-/* bfunc gets search item *poin as arg2, or if NULL the old string */
void UI_but_func_search_set(uiBut *but,
- uiButSearchCreateFunc cfunc,
- uiButSearchFunc sfunc,
+ uiButSearchCreateFn search_create_fn,
+ uiButSearchUpdateFn search_update_fn,
void *arg,
- uiButSearchArgFreeFunc search_arg_free_func,
- uiButHandleFunc bfunc,
+ uiButSearchArgFreeFn search_arg_free_fn,
+ uiButHandleFunc search_exec_fn,
void *active);
+void UI_but_func_search_set_context_menu(uiBut *but, uiButSearchContextMenuFn context_menu_fn);
+void UI_but_func_search_set_tooltip(uiBut *but, uiButSearchTooltipFn tooltip_fn);
+void UI_but_func_search_set_sep_string(uiBut *but, const char *search_sep_string);
+
/* height in pixels, it's using hardcoded values still */
int UI_searchbox_size_y(void);
int UI_searchbox_size_x(void);
/* check if a string is in an existing search box */
int UI_search_items_find_index(uiSearchItems *items, const char *name);
+void UI_but_node_link_set(uiBut *but, struct bNodeSocket *socket, const float draw_color[4]);
+
void UI_block_func_handle_set(uiBlock *block, uiBlockHandleFunc func, void *arg);
void UI_block_func_butmenu_set(uiBlock *block, uiMenuHandleFunc func, void *arg);
void UI_block_func_set(uiBlock *block, uiButHandleFunc func, void *arg1, void *arg2);
@@ -1648,22 +1666,24 @@ void UI_panels_end(const struct bContext *C, struct ARegion *region, int *r_x, i
void UI_panels_draw(const struct bContext *C, struct ARegion *region);
struct Panel *UI_panel_find_by_type(struct ListBase *lb, struct PanelType *pt);
-struct Panel *UI_panel_begin(struct ScrArea *sa,
+struct Panel *UI_panel_begin(struct ScrArea *area,
struct ARegion *region,
struct ListBase *lb,
uiBlock *block,
struct PanelType *pt,
- struct Panel *pa,
+ struct Panel *panel,
bool *r_open);
-void UI_panel_end(const struct ScrArea *sa,
+void UI_panel_end(const struct ScrArea *area,
const struct ARegion *region,
uiBlock *block,
int width,
int height,
bool open);
+
void UI_panels_scale(struct ARegion *region, float new_width);
void UI_panel_label_offset(struct uiBlock *block, int *r_x, int *r_y);
-int UI_panel_size_y(const struct Panel *pa);
+int UI_panel_size_y(const struct Panel *panel);
+bool UI_panel_is_dragging(const struct Panel *panel);
bool UI_panel_category_is_visible(const struct ARegion *region);
void UI_panel_category_add(struct ARegion *region, const char *name);
@@ -1683,6 +1703,24 @@ void UI_panel_category_draw_all(struct ARegion *region, const char *category_id_
struct PanelType *UI_paneltype_find(int space_id, int region_id, const char *idname);
+/* Polyinstantiated panels for representing a list of data. */
+struct Panel *UI_panel_add_instanced(struct ScrArea *area,
+ struct ARegion *region,
+ struct ListBase *panels,
+ char *panel_idname,
+ int list_index);
+void UI_panels_free_instanced(struct bContext *C, struct ARegion *region);
+
+#define LIST_PANEL_UNIQUE_STR_LEN 4
+void UI_list_panel_unique_str(struct Panel *panel, char *r_name);
+
+void UI_panel_set_expand_from_list_data(const struct bContext *C, struct Panel *panel);
+
+typedef void (*uiListPanelIDFromDataFunc)(void *data_link, char *r_idname);
+bool UI_panel_list_matches_data(struct ARegion *region,
+ struct ListBase *data,
+ uiListPanelIDFromDataFunc panel_idname_func);
+
/* Handlers
*
* Handlers that can be registered in regions, areas and windows for
@@ -1768,6 +1806,10 @@ enum {
UI_ITEM_O_DEPRESS = 1 << 10,
UI_ITEM_R_COMPACT = 1 << 11,
UI_ITEM_R_CHECKBOX_INVERT = 1 << 12,
+ /** Don't add a real decorator item, just blank space. */
+ UI_ITEM_R_FORCE_BLANK_DECORATE = 1 << 13,
+ /* Even create the property split layout if there's no name to show there. */
+ UI_ITEM_R_SPLIT_EMPTY_NAME = 1 << 14,
};
#define UI_HEADER_OFFSET ((void)0, 0.4f * UI_UNIT_X)
@@ -1778,6 +1820,9 @@ enum {
UI_TEMPLATE_OP_PROPS_SHOW_EMPTY = 1 << 1,
UI_TEMPLATE_OP_PROPS_COMPACT = 1 << 2,
UI_TEMPLATE_OP_PROPS_HIDE_ADVANCED = 1 << 3,
+ /* Disable property split for the default layout (custom ui callbacks still have full control
+ * over the layout and can enable it). */
+ UI_TEMPLATE_OP_PROPS_NO_SPLIT_LAYOUT = 1 << 4,
};
/* used for transp checkers */
@@ -1865,7 +1910,9 @@ bool uiLayoutGetPropDecorate(uiLayout *layout);
/* layout specifiers */
uiLayout *uiLayoutRow(uiLayout *layout, bool align);
+uiLayout *uiLayoutRowWithHeading(uiLayout *layout, bool align, const char *heading);
uiLayout *uiLayoutColumn(uiLayout *layout, bool align);
+uiLayout *uiLayoutColumnWithHeading(uiLayout *layout, bool align, const char *heading);
uiLayout *uiLayoutColumnFlow(uiLayout *layout, int number, bool align);
uiLayout *uiLayoutGridFlow(uiLayout *layout,
bool row_major,
@@ -1889,7 +1936,7 @@ uiLayout *uiLayoutRadial(uiLayout *layout);
/* templates */
void uiTemplateHeader(uiLayout *layout, struct bContext *C);
void uiTemplateID(uiLayout *layout,
- struct bContext *C,
+ const struct bContext *C,
struct PointerRNA *ptr,
const char *propname,
const char *newop,
@@ -2040,11 +2087,11 @@ void uiTemplateOperatorSearch(uiLayout *layout);
void UI_but_func_menu_search(uiBut *but);
void uiTemplateMenuSearch(uiLayout *layout);
-eAutoPropButsReturn uiTemplateOperatorPropertyButs(const struct bContext *C,
- uiLayout *layout,
- struct wmOperator *op,
- const eButLabelAlign label_align,
- const short flag);
+void uiTemplateOperatorPropertyButs(const struct bContext *C,
+ uiLayout *layout,
+ struct wmOperator *op,
+ eButLabelAlign label_align,
+ short flag);
void uiTemplateHeader3D_mode(uiLayout *layout, struct bContext *C);
void uiTemplateEditModeSelection(uiLayout *layout, struct bContext *C);
void uiTemplateReportsBanner(uiLayout *layout, struct bContext *C);
@@ -2062,7 +2109,7 @@ void uiTemplateComponentMenu(uiLayout *layout,
const char *name);
void uiTemplateNodeSocket(uiLayout *layout, struct bContext *C, float *color);
void uiTemplateCacheFile(uiLayout *layout,
- struct bContext *C,
+ const struct bContext *C,
struct PointerRNA *ptr,
const char *propname);
@@ -2084,6 +2131,7 @@ void uiTemplateList(uiLayout *layout,
bool sort_reverse,
bool sort_lock);
void uiTemplateNodeLink(uiLayout *layout,
+ struct bContext *C,
struct bNodeTree *ntree,
struct bNode *node,
struct bNodeSocket *input);
@@ -2094,7 +2142,7 @@ void uiTemplateNodeView(uiLayout *layout,
struct bNodeSocket *input);
void uiTemplateTextureUser(uiLayout *layout, struct bContext *C);
void uiTemplateTextureShow(uiLayout *layout,
- struct bContext *C,
+ const struct bContext *C,
struct PointerRNA *ptr,
struct PropertyRNA *prop);
@@ -2293,6 +2341,14 @@ void uiItemsFullEnumO_items(uiLayout *layout,
const EnumPropertyItem *item_array,
int totitem);
+typedef struct uiPropertySplitWrapper {
+ uiLayout *label_column;
+ uiLayout *property_row;
+ uiLayout *decorate_column;
+} uiPropertySplitWrapper;
+
+uiPropertySplitWrapper uiItemPropertySplitWrapperCreate(uiLayout *parent_layout);
+
void uiItemL(uiLayout *layout, const char *name, int icon); /* label */
void uiItemL_ex(
uiLayout *layout, const char *name, int icon, const bool highlight, const bool redalert);
@@ -2304,6 +2360,9 @@ void uiItemM_ptr(uiLayout *layout, struct MenuType *mt, const char *name, int ic
void uiItemM(uiLayout *layout, const char *menuname, const char *name, int icon);
/* menu contents */
void uiItemMContents(uiLayout *layout, const char *menuname);
+/* Decorators */
+void uiItemDecoratorR_prop(uiLayout *layout, PointerRNA *ptr, PropertyRNA *prop, int index);
+void uiItemDecoratorR(uiLayout *layout, PointerRNA *ptr, const char *propname, int index);
/* value */
void uiItemV(uiLayout *layout, const char *name, int icon, int argval);
/* separator */
@@ -2378,11 +2437,14 @@ bool UI_context_copy_to_selected_list(struct bContext *C,
/* Helpers for Operators */
uiBut *UI_context_active_but_get(const struct bContext *C);
+uiBut *UI_context_active_but_get_respect_menu(const struct bContext *C);
uiBut *UI_context_active_but_prop_get(const struct bContext *C,
struct PointerRNA *r_ptr,
struct PropertyRNA **r_prop,
int *r_index);
void UI_context_active_but_prop_handle(struct bContext *C);
+void UI_context_active_but_clear(struct bContext *C, struct wmWindow *win, struct ARegion *region);
+
struct wmOperator *UI_context_active_operator_get(const struct bContext *C);
void UI_context_update_anim_flag(const struct bContext *C);
void UI_context_active_but_prop_get_filebrowser(const struct bContext *C,
@@ -2420,8 +2482,9 @@ void UI_fontstyle_draw_ex(const struct uiFontStyle *fs,
const uchar col[4],
const struct uiFontStyleDraw_Params *fs_params,
size_t len,
- float *r_xofs,
- float *r_yofs);
+ int *r_xofs,
+ int *r_yofs,
+ struct ResultBLF *r_info);
void UI_fontstyle_draw(const struct uiFontStyle *fs,
const struct rcti *rect,
const char *str,
@@ -2475,7 +2538,7 @@ struct ARegion *UI_tooltip_create_from_button(struct bContext *C,
uiBut *but,
bool is_label);
struct ARegion *UI_tooltip_create_from_gizmo(struct bContext *C, struct wmGizmo *gz);
-void UI_tooltip_free(struct bContext *C, struct bScreen *sc, struct ARegion *region);
+void UI_tooltip_free(struct bContext *C, struct bScreen *screen, struct ARegion *region);
/* How long before a tool-tip shows. */
#define UI_TOOLTIP_DELAY 0.5
diff --git a/source/blender/editors/include/UI_resources.h b/source/blender/editors/include/UI_resources.h
index b0995250979..c5c4ca79f14 100644
--- a/source/blender/editors/include/UI_resources.h
+++ b/source/blender/editors/include/UI_resources.h
@@ -26,10 +26,6 @@
#include "BLI_sys_types.h"
-#ifdef __cplusplus
-extern "C" {
-#endif
-
/* Define icon enum. */
#define DEF_ICON(name) ICON_##name,
#define DEF_ICON_VECTOR(name) ICON_##name,
@@ -47,6 +43,10 @@ typedef enum {
/* use to denote intentionally unset theme color */
#define TH_UNDEFINED -1
+#ifdef __cplusplus
+extern "C" {
+#endif
+
typedef enum ThemeColorID {
TH_REDALERT,
diff --git a/source/blender/editors/include/UI_view2d.h b/source/blender/editors/include/UI_view2d.h
index ff9719d4674..ffc06e94a90 100644
--- a/source/blender/editors/include/UI_view2d.h
+++ b/source/blender/editors/include/UI_view2d.h
@@ -119,7 +119,7 @@ void UI_view2d_region_reinit(struct View2D *v2d, short type, int winx, int winy)
void UI_view2d_curRect_validate(struct View2D *v2d);
void UI_view2d_curRect_reset(struct View2D *v2d);
-void UI_view2d_sync(struct bScreen *screen, struct ScrArea *sa, struct View2D *v2dcur, int flag);
+void UI_view2d_sync(struct bScreen *screen, struct ScrArea *area, struct View2D *v2dcur, int flag);
void UI_view2d_totRect_set(struct View2D *v2d, int width, int height);
void UI_view2d_totRect_set_resize(struct View2D *v2d, int width, int height, bool resize);
@@ -137,9 +137,9 @@ void UI_view2d_view_orthoSpecial(struct ARegion *region, struct View2D *v2d, con
void UI_view2d_view_restore(const struct bContext *C);
/* grid drawing */
-void UI_view2d_constant_grid_draw(struct View2D *v2d, float step);
+void UI_view2d_constant_grid_draw(const struct View2D *v2d, float step);
void UI_view2d_multi_grid_draw(
- struct View2D *v2d, int colorid, float step, int level_size, int totlevels);
+ const struct View2D *v2d, int colorid, float step, int level_size, int totlevels);
void UI_view2d_draw_lines_y__values(const struct View2D *v2d);
void UI_view2d_draw_lines_x__values(const struct View2D *v2d);
@@ -209,14 +209,17 @@ bool UI_view2d_view_to_region_clip(
const struct View2D *v2d, float x, float y, int *r_region_x, int *r_region_y) ATTR_NONNULL();
void UI_view2d_view_to_region(
- struct View2D *v2d, float x, float y, int *r_region_x, int *r_region_y) ATTR_NONNULL();
-void UI_view2d_view_to_region_fl(
- struct View2D *v2d, float x, float y, float *r_region_x, float *r_region_y) ATTR_NONNULL();
-void UI_view2d_view_to_region_m4(struct View2D *v2d, float matrix[4][4]) ATTR_NONNULL();
-void UI_view2d_view_to_region_rcti(struct View2D *v2d,
+ const struct View2D *v2d, float x, float y, int *r_region_x, int *r_region_y) ATTR_NONNULL();
+void UI_view2d_view_to_region_fl(const struct View2D *v2d,
+ float x,
+ float y,
+ float *r_region_x,
+ float *r_region_y) ATTR_NONNULL();
+void UI_view2d_view_to_region_m4(const struct View2D *v2d, float matrix[4][4]) ATTR_NONNULL();
+void UI_view2d_view_to_region_rcti(const struct View2D *v2d,
const struct rctf *rect_src,
struct rcti *rect_dst) ATTR_NONNULL();
-bool UI_view2d_view_to_region_rcti_clip(struct View2D *v2d,
+bool UI_view2d_view_to_region_rcti_clip(const struct View2D *v2d,
const struct rctf *rect_src,
struct rcti *rect_dst) ATTR_NONNULL();
@@ -228,9 +231,9 @@ void UI_view2d_scroller_size_get(const struct View2D *v2d, float *r_x, float *r_
void UI_view2d_scale_get(struct View2D *v2d, float *r_x, float *r_y);
float UI_view2d_scale_get_x(const struct View2D *v2d);
float UI_view2d_scale_get_y(const struct View2D *v2d);
-void UI_view2d_scale_get_inverse(struct View2D *v2d, float *r_x, float *r_y);
+void UI_view2d_scale_get_inverse(const struct View2D *v2d, float *r_x, float *r_y);
-void UI_view2d_center_get(struct View2D *v2d, float *r_x, float *r_y);
+void UI_view2d_center_get(const struct View2D *v2d, float *r_x, float *r_y);
void UI_view2d_center_set(struct View2D *v2d, float x, float y);
void UI_view2d_offset(struct View2D *v2d, float xfac, float yfac);
diff --git a/source/blender/editors/interface/CMakeLists.txt b/source/blender/editors/interface/CMakeLists.txt
index d33023c69a1..e4fb0631f06 100644
--- a/source/blender/editors/interface/CMakeLists.txt
+++ b/source/blender/editors/interface/CMakeLists.txt
@@ -68,7 +68,10 @@ set(SRC
interface_region_tooltip.c
interface_regions.c
interface_style.c
+ interface_template_search_menu.c
+ interface_template_search_operator.c
interface_templates.c
+ interface_undo.c
interface_utils.c
interface_widgets.c
resources.c
diff --git a/source/blender/editors/interface/interface.c b/source/blender/editors/interface/interface.c
index 41b7683dff7..04c259ab092 100644
--- a/source/blender/editors/interface/interface.c
+++ b/source/blender/editors/interface/interface.c
@@ -44,7 +44,6 @@
#include "BLI_utildefines.h"
-#include "BKE_animsys.h"
#include "BKE_context.h"
#include "BKE_idprop.h"
#include "BKE_main.h"
@@ -262,7 +261,7 @@ void ui_region_to_window(const ARegion *region, int *x, int *y)
static void ui_update_flexible_spacing(const ARegion *region, uiBlock *block)
{
int sepr_flex_len = 0;
- for (uiBut *but = block->buttons.first; but; but = but->next) {
+ LISTBASE_FOREACH (uiBut *, but, &block->buttons) {
if (but->type == UI_BTYPE_SEPR_SPACER) {
sepr_flex_len++;
}
@@ -284,7 +283,7 @@ static void ui_update_flexible_spacing(const ARegion *region, uiBlock *block)
/* We could get rid of this loop if we agree on a max number of spacer */
int *spacers_pos = alloca(sizeof(*spacers_pos) * (size_t)sepr_flex_len);
int i = 0;
- for (uiBut *but = block->buttons.first; but; but = but->next) {
+ LISTBASE_FOREACH (uiBut *, but, &block->buttons) {
if (but->type == UI_BTYPE_SEPR_SPACER) {
ui_but_to_pixelrect(&rect, region, block, but);
spacers_pos[i] = rect.xmax + UI_HEADER_OFFSET;
@@ -295,7 +294,7 @@ static void ui_update_flexible_spacing(const ARegion *region, uiBlock *block)
const float segment_width = region_width / (float)sepr_flex_len;
float offset = 0, remaining_space = region_width - buttons_width;
i = 0;
- for (uiBut *but = block->buttons.first; but; but = but->next) {
+ LISTBASE_FOREACH (uiBut *, but, &block->buttons) {
BLI_rctf_translate(&but->rect, offset, 0);
if (but->type == UI_BTYPE_SEPR_SPACER) {
/* How much the next block overlap with the current segment */
@@ -642,6 +641,26 @@ static int ui_but_calc_float_precision(uiBut *but, double value)
/* ************** BLOCK ENDING FUNCTION ************* */
+bool ui_but_rna_equals(const uiBut *a, const uiBut *b)
+{
+ return ui_but_rna_equals_ex(a, &b->rnapoin, b->rnaprop, b->rnaindex);
+}
+
+bool ui_but_rna_equals_ex(const uiBut *but,
+ const PointerRNA *ptr,
+ const PropertyRNA *prop,
+ int index)
+{
+ if (but->rnapoin.data != ptr->data) {
+ return false;
+ }
+ if (but->rnaprop != prop || but->rnaindex != index) {
+ return false;
+ }
+
+ return true;
+}
+
/* NOTE: if but->poin is allocated memory for every defbut, things fail... */
static bool ui_but_equals_old(const uiBut *but, const uiBut *oldbut)
{
@@ -650,10 +669,7 @@ static bool ui_but_equals_old(const uiBut *but, const uiBut *oldbut)
if (but->retval != oldbut->retval) {
return false;
}
- if (but->rnapoin.data != oldbut->rnapoin.data) {
- return false;
- }
- if (but->rnaprop != oldbut->rnaprop || but->rnaindex != oldbut->rnaindex) {
+ if (!ui_but_rna_equals(but, oldbut)) {
return false;
}
if (but->func != oldbut->func) {
@@ -791,6 +807,8 @@ static bool ui_but_update_from_old_block(const bContext *C,
SWAP(ListBase, but->extra_op_icons, oldbut->extra_op_icons);
+ SWAP(struct uiButSearchData *, oldbut->search, but->search);
+
/* copy hardmin for list rows to prevent 'sticking' highlight to mouse position
* when scrolling without moving mouse (see [#28432]) */
if (ELEM(oldbut->type, UI_BTYPE_ROW, UI_BTYPE_LISTROW)) {
@@ -899,7 +917,7 @@ bool UI_but_active_only(const bContext *C, ARegion *region, uiBlock *block, uiBu
bool UI_block_active_only_flagged_buttons(const bContext *C, ARegion *region, uiBlock *block)
{
bool done = false;
- for (uiBut *but = block->buttons.first; but; but = but->next) {
+ LISTBASE_FOREACH (uiBut *, but, &block->buttons) {
if (but->flag & UI_BUT_ACTIVATE_ON_INIT) {
but->flag &= ~UI_BUT_ACTIVATE_ON_INIT;
if (ui_but_is_editable(but)) {
@@ -914,7 +932,7 @@ bool UI_block_active_only_flagged_buttons(const bContext *C, ARegion *region, ui
if (done) {
/* Run this in a second pass since it's possible activating the button
* removes the buttons being looped over. */
- for (uiBut *but = block->buttons.first; but; but = but->next) {
+ LISTBASE_FOREACH (uiBut *, but, &block->buttons) {
but->flag &= ~UI_BUT_ACTIVATE_ON_INIT;
}
}
@@ -971,13 +989,15 @@ static void ui_menu_block_set_keyaccels(uiBlock *block)
/* 2 Passes, on for first letter only, second for any letter if first fails
* fun first pass on all buttons so first word chars always get first priority */
- for (uiBut *but = block->buttons.first; but; but = but->next) {
+ LISTBASE_FOREACH (uiBut *, but, &block->buttons) {
if (!ELEM(but->type,
UI_BTYPE_BUT,
UI_BTYPE_BUT_MENU,
UI_BTYPE_MENU,
UI_BTYPE_BLOCK,
- UI_BTYPE_PULLDOWN) ||
+ UI_BTYPE_PULLDOWN,
+ /* For PIE-menus. */
+ UI_BTYPE_ROW) ||
(but->flag & UI_HIDDEN)) {
/* pass */
}
@@ -1297,9 +1317,8 @@ static bool ui_but_event_property_operator_string(const bContext *C,
}
else if (GS(id->name) == ID_SCE) {
if (RNA_struct_is_a(ptr->type, &RNA_ToolSettings)) {
- /* toolsettings property
- * NOTE: toolsettings is usually accessed directly (i.e. not through scene)
- */
+ /* Tool-settings property:
+ * NOTE: tool-settings is usually accessed directly (i.e. not through scene). */
data_path = RNA_path_from_ID_to_property(ptr, prop);
}
else {
@@ -1664,7 +1683,7 @@ static void ui_but_predefined_extra_operator_icons_add(uiBut *but)
}
if (optype) {
- for (uiButExtraOpIcon *op_icon = but->extra_op_icons.first; op_icon; op_icon = op_icon->next) {
+ LISTBASE_FOREACH (uiButExtraOpIcon *, op_icon, &but->extra_op_icons) {
if ((op_icon->optype_params->optype == optype) && (op_icon->icon == icon)) {
/* Don't add the same operator icon twice (happens if button is kept alive while active).
*/
@@ -1935,7 +1954,7 @@ static void ui_block_message_subscribe(ARegion *region, struct wmMsgBus *mbus, u
{
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) {
+ LISTBASE_FOREACH (uiBut *, but, &block->buttons) {
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) &&
@@ -1960,7 +1979,7 @@ static void ui_block_message_subscribe(ARegion *region, struct wmMsgBus *mbus, u
void UI_region_message_subscribe(ARegion *region, struct wmMsgBus *mbus)
{
- for (uiBlock *block = region->uiblocks.first; block; block = block->next) {
+ LISTBASE_FOREACH (uiBlock *, block, &region->uiblocks) {
ui_block_message_subscribe(region, mbus, block);
}
}
@@ -3207,9 +3226,12 @@ static void ui_but_free(const bContext *C, uiBut *but)
MEM_freeN(but->hold_argN);
}
- if (but->search_arg_free_func) {
- but->search_arg_free_func(but->search_arg);
- but->search_arg = NULL;
+ if (but->search != NULL) {
+ if (but->search->arg_free_fn) {
+ but->search->arg_free_fn(but->search->arg);
+ but->search->arg = NULL;
+ }
+ MEM_freeN(but->search);
}
if (but->active) {
@@ -3275,7 +3297,7 @@ void UI_blocklist_update_window_matrix(const bContext *C, const ListBase *lb)
ARegion *region = CTX_wm_region(C);
wmWindow *window = CTX_wm_window(C);
- for (uiBlock *block = lb->first; block; block = block->next) {
+ LISTBASE_FOREACH (uiBlock *, block, lb) {
if (block->active) {
ui_update_window_matrix(window, region, block);
}
@@ -3284,7 +3306,7 @@ void UI_blocklist_update_window_matrix(const bContext *C, const ListBase *lb)
void UI_blocklist_draw(const bContext *C, const ListBase *lb)
{
- for (uiBlock *block = lb->first; block; block = block->next) {
+ LISTBASE_FOREACH (uiBlock *, block, lb) {
if (block->active) {
UI_block_draw(C, block);
}
@@ -6329,36 +6351,51 @@ uiBut *uiDefSearchBut(uiBlock *block,
}
/**
- * \param search_func, bfunc: both get it as \a arg.
- * \param arg: user value,
- * \param active: when set, button opens with this item visible and selected.
+ * \note The item-pointer (referred to below) is a per search item user pointer
+ * passed to #UI_search_item_add (stored in #uiSearchItems.pointers).
+ *
+ * \param search_create_fn: Function to create the menu.
+ * \param search_update_fn: Function to refresh search content after the search text has changed.
+ * \param arg: user value.
+ * \param search_arg_free_fn: When non-null, use this function to free \a arg.
+ * \param search_exec_fn: Function that executes the action, gets \a arg as the first argument.
+ * The second argument as the active item-pointer
+ * \param active: When non-null, this item-pointer item will be visible and selected,
+ * otherwise the first item will be selected.
*/
void UI_but_func_search_set(uiBut *but,
- uiButSearchCreateFunc search_create_func,
- uiButSearchFunc search_func,
+ uiButSearchCreateFn search_create_fn,
+ uiButSearchUpdateFn search_update_fn,
void *arg,
- uiButSearchArgFreeFunc search_arg_free_func,
- uiButHandleFunc bfunc,
+ uiButSearchArgFreeFn search_arg_free_fn,
+ uiButHandleFunc search_exec_fn,
void *active)
{
/* needed since callers don't have access to internal functions
* (as an alternative we could expose it) */
- if (search_create_func == NULL) {
- search_create_func = ui_searchbox_create_generic;
+ if (search_create_fn == NULL) {
+ search_create_fn = ui_searchbox_create_generic;
}
- if (but->search_arg_free_func != NULL) {
- but->search_arg_free_func(but->search_arg);
- but->search_arg = NULL;
+ struct uiButSearchData *search = but->search;
+ if (search != NULL) {
+ if (search->arg_free_fn != NULL) {
+ search->arg_free_fn(but->search->arg);
+ search->arg = NULL;
+ }
+ }
+ else {
+ search = MEM_callocN(sizeof(*but->search), __func__);
+ but->search = search;
}
- but->search_create_func = search_create_func;
- but->search_func = search_func;
+ search->create_fn = search_create_fn;
+ search->update_fn = search_update_fn;
- but->search_arg = arg;
- but->search_arg_free_func = search_arg_free_func;
+ search->arg = arg;
+ search->arg_free_fn = search_arg_free_fn;
- if (bfunc) {
+ if (search_exec_fn) {
#ifdef DEBUG
if (but->func) {
/* watch this, can be cause of much confusion, see: T47691 */
@@ -6366,7 +6403,7 @@ void UI_but_func_search_set(uiBut *but,
__func__);
}
#endif
- UI_but_func_set(but, bfunc, arg, active);
+ UI_but_func_set(but, search_exec_fn, search->arg, active);
}
/* search buttons show red-alert if item doesn't exist, not for menus */
@@ -6378,11 +6415,33 @@ void UI_but_func_search_set(uiBut *but,
}
}
+void UI_but_func_search_set_context_menu(uiBut *but, uiButSearchContextMenuFn context_menu_fn)
+{
+ struct uiButSearchData *search = but->search;
+ search->context_menu_fn = context_menu_fn;
+}
+
+/**
+ * \param separator_string: when not NULL, this string is used as a separator,
+ * showing the icon and highlighted text after the last instance of this string.
+ */
+void UI_but_func_search_set_sep_string(uiBut *but, const char *search_sep_string)
+{
+ struct uiButSearchData *search = but->search;
+ search->sep_string = search_sep_string;
+}
+
+void UI_but_func_search_set_tooltip(uiBut *but, uiButSearchTooltipFn tooltip_fn)
+{
+ struct uiButSearchData *search = but->search;
+ search->tooltip_fn = tooltip_fn;
+}
+
/* Callbacks for operator search button. */
-static void operator_enum_search_cb(const struct bContext *C,
- void *but,
- const char *str,
- uiSearchItems *items)
+static void operator_enum_search_update_fn(const struct bContext *C,
+ void *but,
+ const char *str,
+ uiSearchItems *items)
{
wmOperatorType *ot = ((uiBut *)but)->optype;
PropertyRNA *prop = ot->prop;
@@ -6419,7 +6478,7 @@ static void operator_enum_search_cb(const struct bContext *C,
}
}
-static void operator_enum_call_cb(struct bContext *UNUSED(C), void *but, void *arg2)
+static void operator_enum_search_exec_fn(struct bContext *UNUSED(C), void *but, void *arg2)
{
wmOperatorType *ot = ((uiBut *)but)->optype;
PointerRNA *opptr = UI_but_operator_ptr_get(but); /* Will create it if needed! */
@@ -6462,10 +6521,10 @@ uiBut *uiDefSearchButO_ptr(uiBlock *block,
but = uiDefSearchBut(block, arg, retval, icon, maxlen, x, y, width, height, a1, a2, tip);
UI_but_func_search_set(but,
ui_searchbox_create_generic,
- operator_enum_search_cb,
+ operator_enum_search_update_fn,
but,
NULL,
- operator_enum_call_cb,
+ operator_enum_search_exec_fn,
NULL);
but->optype = ot;
@@ -6480,6 +6539,13 @@ uiBut *uiDefSearchButO_ptr(uiBlock *block,
return but;
}
+void UI_but_node_link_set(uiBut *but, bNodeSocket *socket, const float draw_color[4])
+{
+ but->flag |= UI_BUT_NODE_LINK;
+ but->custom_data = socket;
+ rgba_float_to_uchar(but->col, draw_color);
+}
+
/**
* push a new event onto event queue to activate the given button
* (usually a text-field) upon entering a popup
@@ -6608,8 +6674,8 @@ void UI_but_string_info_get(bContext *C, uiBut *but, ...)
}
else {
/* Not all menus are from Python. */
- if (mt->ext.srna) {
- const char *t = RNA_struct_ui_description(mt->ext.srna);
+ if (mt->rna_ext.srna) {
+ const char *t = RNA_struct_ui_description(mt->rna_ext.srna);
if (t && t[0]) {
tmp = BLI_strdup(t);
}
@@ -6626,7 +6692,7 @@ void UI_but_string_info_get(bContext *C, uiBut *but, ...)
}
else {
/* Not all panels are from Python. */
- if (pt->ext.srna) {
+ if (pt->rna_ext.srna) {
/* Panels don't yet have descriptions, this may be added. */
}
}
@@ -6645,7 +6711,7 @@ void UI_but_string_info_get(bContext *C, uiBut *but, ...)
else if (ELEM(but->type, UI_BTYPE_MENU, UI_BTYPE_PULLDOWN)) {
MenuType *mt = UI_but_menutype_get(but);
if (mt) {
- _tmp = RNA_struct_translation_context(mt->ext.srna);
+ _tmp = RNA_struct_translation_context(mt->rna_ext.srna);
}
}
if (BLT_is_default_context(_tmp)) {
diff --git a/source/blender/editors/interface/interface_align.c b/source/blender/editors/interface/interface_align.c
index 09811fab52d..32cae609395 100644
--- a/source/blender/editors/interface/interface_align.c
+++ b/source/blender/editors/interface/interface_align.c
@@ -124,7 +124,11 @@ bool ui_but_can_align(const uiBut *but)
int ui_but_align_opposite_to_area_align_get(const ARegion *region)
{
- switch (RGN_ALIGN_ENUM_FROM_MASK(region->alignment)) {
+ const ARegion *align_region = (region->alignment & RGN_SPLIT_PREV && region->prev) ?
+ region->prev :
+ region;
+
+ switch (RGN_ALIGN_ENUM_FROM_MASK(align_region->alignment)) {
case RGN_ALIGN_TOP:
return UI_BUT_ALIGN_DOWN;
case RGN_ALIGN_BOTTOM:
@@ -502,7 +506,7 @@ void ui_block_align_calc(uiBlock *block, const ARegion *region)
butal->but->drawflag |= align;
butal_other->but->drawflag |= align_opp;
- if (butal->dists[side]) {
+ if (!IS_EQF(butal->dists[side], 0.0f)) {
float *delta = &butal->dists[side];
if (*butal->borders[side] < *butal_other->borders[side_opp]) {
@@ -513,7 +517,7 @@ void ui_block_align_calc(uiBlock *block, const ARegion *region)
}
co = (*butal->borders[side] += *delta);
- if (butal_other->dists[side_opp]) {
+ if (!IS_EQF(butal_other->dists[side_opp], 0.0f)) {
BLI_assert(butal_other->dists[side_opp] * 0.5f == fabsf(*delta));
*butal_other->borders[side_opp] = co;
butal_other->dists[side_opp] = 0.0f;
diff --git a/source/blender/editors/interface/interface_anim.c b/source/blender/editors/interface/interface_anim.c
index 15fc23bc539..5bf2147aff5 100644
--- a/source/blender/editors/interface/interface_anim.c
+++ b/source/blender/editors/interface/interface_anim.c
@@ -28,12 +28,14 @@
#include "DNA_scene_types.h"
#include "DNA_screen_types.h"
+#include "BLI_listbase.h"
#include "BLI_string.h"
#include "BLI_string_utf8.h"
#include "BLI_utildefines.h"
#include "BKE_context.h"
#include "BKE_fcurve.h"
+#include "BKE_fcurve_driver.h"
#include "BKE_global.h"
#include "BKE_main.h"
#include "BKE_nla.h"
@@ -59,7 +61,7 @@ static FCurve *ui_but_get_fcurve(
* but works well enough in typical cases */
int rnaindex = (but->rnaindex == -1) ? 0 : but->rnaindex;
- return rna_get_fcurve_context_ui(
+ return BKE_fcurve_find_by_rna_context_ui(
but->block->evil_C, &but->rnapoin, but->rnaprop, rnaindex, adt, action, r_driven, r_special);
}
@@ -114,10 +116,40 @@ void ui_but_anim_flag(uiBut *but, float cfra)
}
}
+static uiBut *ui_but_anim_decorate_find_attached_button(uiBut *but_decorate)
+{
+ uiBut *but_iter = NULL;
+
+ BLI_assert(UI_but_is_decorator(but_decorate));
+ BLI_assert(but_decorate->rnasearchpoin.data && but_decorate->rnasearchprop);
+
+ LISTBASE_CIRCULAR_BACKWARD_BEGIN (&but_decorate->block->buttons, but_iter, but_decorate->prev) {
+ if (but_iter != but_decorate &&
+ ui_but_rna_equals_ex(but_iter,
+ &but_decorate->rnasearchpoin,
+ but_decorate->rnasearchprop,
+ POINTER_AS_INT(but_decorate->custom_data))) {
+ return but_iter;
+ }
+ }
+ LISTBASE_CIRCULAR_BACKWARD_END(&but_decorate->block->buttons, but_iter, but_decorate->prev);
+
+ return NULL;
+}
+
void ui_but_anim_decorate_update_from_flag(uiBut *but)
{
- BLI_assert(UI_but_is_decorator(but) && but->prev);
- int flag = but->prev->flag;
+ const uiBut *but_anim = ui_but_anim_decorate_find_attached_button(but);
+
+ if (!but_anim) {
+ printf("Could not find button with matching property to decorate (%s.%s)\n",
+ RNA_struct_identifier(but->rnasearchpoin.type),
+ RNA_property_identifier(but->rnasearchprop));
+ return;
+ }
+
+ int flag = but_anim->flag;
+
if (flag & UI_BUT_DRIVEN) {
but->icon = ICON_DECORATE_DRIVER;
}
@@ -289,22 +321,26 @@ void ui_but_anim_paste_driver(bContext *C)
void ui_but_anim_decorate_cb(bContext *C, void *arg_but, void *UNUSED(arg_dummy))
{
wmWindowManager *wm = CTX_wm_manager(C);
- uiBut *but = arg_but;
- but = but->prev;
+ uiBut *but_decorate = arg_but;
+ uiBut *but_anim = ui_but_anim_decorate_find_attached_button(but_decorate);
+
+ if (!but_anim) {
+ return;
+ }
/* FIXME(campbell), swapping active pointer is weak. */
- SWAP(struct uiHandleButtonData *, but->active, but->next->active);
+ SWAP(struct uiHandleButtonData *, but_anim->active, but_decorate->active);
wm->op_undo_depth++;
- if (but->flag & UI_BUT_DRIVEN) {
+ if (but_anim->flag & UI_BUT_DRIVEN) {
/* pass */
/* TODO: report? */
}
- else if (but->flag & UI_BUT_ANIMATED_KEY) {
+ else if (but_anim->flag & UI_BUT_ANIMATED_KEY) {
PointerRNA props_ptr;
wmOperatorType *ot = WM_operatortype_find("ANIM_OT_keyframe_delete_button", false);
WM_operator_properties_create_ptr(&props_ptr, ot);
- RNA_boolean_set(&props_ptr, "all", but->rnaindex == -1);
+ RNA_boolean_set(&props_ptr, "all", but_anim->rnaindex == -1);
WM_operator_name_call_ptr(C, ot, WM_OP_INVOKE_DEFAULT, &props_ptr);
WM_operator_properties_free(&props_ptr);
}
@@ -312,11 +348,11 @@ void ui_but_anim_decorate_cb(bContext *C, void *arg_but, void *UNUSED(arg_dummy)
PointerRNA props_ptr;
wmOperatorType *ot = WM_operatortype_find("ANIM_OT_keyframe_insert_button", false);
WM_operator_properties_create_ptr(&props_ptr, ot);
- RNA_boolean_set(&props_ptr, "all", but->rnaindex == -1);
+ RNA_boolean_set(&props_ptr, "all", but_anim->rnaindex == -1);
WM_operator_name_call_ptr(C, ot, WM_OP_INVOKE_DEFAULT, &props_ptr);
WM_operator_properties_free(&props_ptr);
}
- SWAP(struct uiHandleButtonData *, but->active, but->next->active);
+ SWAP(struct uiHandleButtonData *, but_anim->active, but_decorate->active);
wm->op_undo_depth--;
}
diff --git a/source/blender/editors/interface/interface_context_menu.c b/source/blender/editors/interface/interface_context_menu.c
index 76107d190ba..cc370113422 100644
--- a/source/blender/editors/interface/interface_context_menu.c
+++ b/source/blender/editors/interface/interface_context_menu.c
@@ -962,7 +962,7 @@ bool ui_popup_context_menu_for_button(bContext *C, uiBut *but)
const PropertyType prop_type = RNA_property_type(but->rnaprop);
if (((prop_type == PROP_POINTER) ||
(prop_type == PROP_STRING && but->type == UI_BTYPE_SEARCH_MENU &&
- but->search_func == ui_rna_collection_search_cb)) &&
+ but->search->update_fn == ui_rna_collection_search_update_fn)) &&
ui_jump_to_target_button_poll(C)) {
uiItemO(layout,
CTX_IFACE_(BLT_I18NCONTEXT_OPERATOR_DEFAULT, "Jump to Target"),
@@ -1231,9 +1231,9 @@ bool ui_popup_context_menu_for_button(bContext *C, uiBut *but)
/**
* menu to show when right clicking on the panel header
*/
-void ui_popup_context_menu_for_panel(bContext *C, ARegion *region, Panel *pa)
+void ui_popup_context_menu_for_panel(bContext *C, ARegion *region, Panel *panel)
{
- bScreen *sc = CTX_wm_screen(C);
+ bScreen *screen = CTX_wm_screen(C);
const bool has_panel_category = UI_panel_category_is_visible(region);
const bool any_item_visible = has_panel_category;
PointerRNA ptr;
@@ -1243,11 +1243,11 @@ void ui_popup_context_menu_for_panel(bContext *C, ARegion *region, Panel *pa)
if (!any_item_visible) {
return;
}
- if (pa->type->parent != NULL) {
+ if (panel->type->parent != NULL) {
return;
}
- RNA_pointer_create(&sc->id, &RNA_Panel, pa, &ptr);
+ RNA_pointer_create(&screen->id, &RNA_Panel, panel, &ptr);
pup = UI_popup_menu_begin(C, IFACE_("Panel"), ICON_NONE);
layout = UI_popup_menu_layout(pup);
diff --git a/source/blender/editors/interface/interface_eyedropper.c b/source/blender/editors/interface/interface_eyedropper.c
index f69dbb94f19..817cb44db29 100644
--- a/source/blender/editors/interface/interface_eyedropper.c
+++ b/source/blender/editors/interface/interface_eyedropper.c
@@ -54,14 +54,14 @@ wmKeyMap *eyedropper_modal_keymap(wmKeyConfig *keyconf)
{0, NULL, 0, NULL, NULL},
};
- wmKeyMap *keymap = WM_modalkeymap_get(keyconf, "Eyedropper Modal Map");
+ wmKeyMap *keymap = WM_modalkeymap_find(keyconf, "Eyedropper Modal Map");
/* this function is called for each spacetype, only needs to add map once */
if (keymap && keymap->modal_items) {
return NULL;
}
- keymap = WM_modalkeymap_add(keyconf, "Eyedropper Modal Map", modal_items);
+ keymap = WM_modalkeymap_ensure(keyconf, "Eyedropper Modal Map", modal_items);
/* assign to operators */
WM_modalkeymap_assign(keymap, "UI_OT_eyedropper_colorramp");
@@ -84,12 +84,12 @@ wmKeyMap *eyedropper_colorband_modal_keymap(wmKeyConfig *keyconf)
{0, NULL, 0, NULL, NULL},
};
- wmKeyMap *keymap = WM_modalkeymap_get(keyconf, "Eyedropper ColorRamp PointSampling Map");
+ wmKeyMap *keymap = WM_modalkeymap_find(keyconf, "Eyedropper ColorRamp PointSampling Map");
if (keymap && keymap->modal_items) {
return keymap;
}
- keymap = WM_modalkeymap_add(
+ keymap = WM_modalkeymap_ensure(
keyconf, "Eyedropper ColorRamp PointSampling Map", modal_items_point);
/* assign to operators */
@@ -139,8 +139,8 @@ void eyedropper_draw_cursor_text(const struct bContext *C, const ARegion *region
uiBut *eyedropper_get_property_button_under_mouse(bContext *C, const wmEvent *event)
{
bScreen *screen = CTX_wm_screen(C);
- ScrArea *sa = BKE_screen_find_area_xy(screen, SPACE_TYPE_ANY, event->x, event->y);
- ARegion *region = BKE_area_find_region_xy(sa, RGN_TYPE_ANY, event->x, event->y);
+ ScrArea *area = BKE_screen_find_area_xy(screen, SPACE_TYPE_ANY, event->x, event->y);
+ ARegion *region = BKE_area_find_region_xy(area, RGN_TYPE_ANY, event->x, event->y);
uiBut *but = ui_but_find_mouse_over(region, event);
diff --git a/source/blender/editors/interface/interface_eyedropper_color.c b/source/blender/editors/interface/interface_eyedropper_color.c
index 372fd841bc1..c917ffb3f3e 100644
--- a/source/blender/editors/interface/interface_eyedropper_color.c
+++ b/source/blender/editors/interface/interface_eyedropper_color.c
@@ -82,11 +82,13 @@ static bool eyedropper_init(bContext *C, wmOperator *op)
eye->use_accum = RNA_boolean_get(op->ptr, "use_accumulate");
uiBut *but = UI_context_active_but_prop_get(C, &eye->ptr, &eye->prop, &eye->index);
+ const enum PropertySubType prop_subtype = eye->prop ? RNA_property_subtype(eye->prop) : 0;
if ((eye->ptr.data == NULL) || (eye->prop == NULL) ||
(RNA_property_editable(&eye->ptr, eye->prop) == false) ||
(RNA_property_array_length(&eye->ptr, eye->prop) < 3) ||
- (RNA_property_type(eye->prop) != PROP_FLOAT)) {
+ (RNA_property_type(eye->prop) != PROP_FLOAT) ||
+ (ELEM(prop_subtype, PROP_COLOR, PROP_COLOR_GAMMA) == 0)) {
MEM_freeN(eye);
return false;
}
@@ -96,7 +98,7 @@ static bool eyedropper_init(bContext *C, wmOperator *op)
float col[4];
RNA_property_float_get_array(&eye->ptr, eye->prop, col);
- if (RNA_property_subtype(eye->prop) != PROP_COLOR) {
+ if (prop_subtype != PROP_COLOR) {
Scene *scene = CTX_data_scene(C);
const char *display_device;
@@ -136,16 +138,31 @@ void eyedropper_color_sample_fl(bContext *C, int mx, int my, float r_col[3])
{
/* we could use some clever */
Main *bmain = CTX_data_main(C);
- bScreen *screen = CTX_wm_screen(C);
- ScrArea *sa = BKE_screen_find_area_xy(screen, SPACE_TYPE_ANY, mx, my);
+ wmWindowManager *wm = CTX_wm_manager(C);
const char *display_device = CTX_data_scene(C)->display_settings.display_device;
struct ColorManagedDisplay *display = IMB_colormanagement_display_get_named(display_device);
- if (sa) {
- if (sa->spacetype == SPACE_IMAGE) {
- ARegion *region = BKE_area_find_region_xy(sa, RGN_TYPE_WINDOW, mx, my);
+ wmWindow *win = CTX_wm_window(C);
+ bScreen *screen = CTX_wm_screen(C);
+ ScrArea *area = BKE_screen_find_area_xy(screen, SPACE_TYPE_ANY, mx, my);
+ if (area == NULL) {
+ int mval[2] = {mx, my};
+ if (WM_window_find_under_cursor(wm, NULL, win, mval, &win, mval)) {
+ mx = mval[0];
+ my = mval[1];
+ screen = WM_window_get_active_screen(win);
+ area = BKE_screen_find_area_xy(screen, SPACE_TYPE_ANY, mx, my);
+ }
+ else {
+ win = NULL;
+ }
+ }
+
+ if (area) {
+ if (area->spacetype == SPACE_IMAGE) {
+ ARegion *region = BKE_area_find_region_xy(area, RGN_TYPE_WINDOW, mx, my);
if (region) {
- SpaceImage *sima = sa->spacedata.first;
+ SpaceImage *sima = area->spacedata.first;
int mval[2] = {mx - region->winrct.xmin, my - region->winrct.ymin};
if (ED_space_image_color_sample(sima, region, mval, r_col)) {
@@ -153,10 +170,10 @@ void eyedropper_color_sample_fl(bContext *C, int mx, int my, float r_col[3])
}
}
}
- else if (sa->spacetype == SPACE_NODE) {
- ARegion *region = BKE_area_find_region_xy(sa, RGN_TYPE_WINDOW, mx, my);
+ else if (area->spacetype == SPACE_NODE) {
+ ARegion *region = BKE_area_find_region_xy(area, RGN_TYPE_WINDOW, mx, my);
if (region) {
- SpaceNode *snode = sa->spacedata.first;
+ SpaceNode *snode = area->spacedata.first;
int mval[2] = {mx - region->winrct.xmin, my - region->winrct.ymin};
if (ED_space_node_color_sample(bmain, snode, region, mval, r_col)) {
@@ -164,10 +181,10 @@ void eyedropper_color_sample_fl(bContext *C, int mx, int my, float r_col[3])
}
}
}
- else if (sa->spacetype == SPACE_CLIP) {
- ARegion *region = BKE_area_find_region_xy(sa, RGN_TYPE_WINDOW, mx, my);
+ else if (area->spacetype == SPACE_CLIP) {
+ ARegion *region = BKE_area_find_region_xy(area, RGN_TYPE_WINDOW, mx, my);
if (region) {
- SpaceClip *sc = sa->spacedata.first;
+ SpaceClip *sc = area->spacedata.first;
int mval[2] = {mx - region->winrct.xmin, my - region->winrct.ymin};
if (ED_space_clip_color_sample(sc, region, mval, r_col)) {
@@ -177,12 +194,15 @@ void eyedropper_color_sample_fl(bContext *C, int mx, int my, float r_col[3])
}
}
- /* fallback to simple opengl picker */
- glReadBuffer(GL_FRONT);
- glReadPixels(mx, my, 1, 1, GL_RGB, GL_FLOAT, r_col);
- glReadBuffer(GL_BACK);
-
- IMB_colormanagement_display_to_scene_linear_v3(r_col, display);
+ if (win) {
+ /* Fallback to simple opengl picker. */
+ int mval[2] = {mx, my};
+ WM_window_pixel_sample_read(wm, win, mval, r_col);
+ IMB_colormanagement_display_to_scene_linear_v3(r_col, display);
+ }
+ else {
+ zero_v3(r_col);
+ }
}
/* sets the sample color RGB, maintaining A */
@@ -290,7 +310,10 @@ static int eyedropper_invoke(bContext *C, wmOperator *op, const wmEvent *UNUSED(
{
/* init */
if (eyedropper_init(C, op)) {
- WM_cursor_modal_set(CTX_wm_window(C), WM_CURSOR_EYEDROPPER);
+ wmWindow *win = CTX_wm_window(C);
+ /* Workaround for de-activating the button clearing the cursor, see T76794 */
+ UI_context_active_but_clear(C, win, CTX_wm_region(C));
+ WM_cursor_modal_set(win, WM_CURSOR_EYEDROPPER);
/* add temp handler */
WM_event_add_modal_handler(C, op);
diff --git a/source/blender/editors/interface/interface_eyedropper_colorband.c b/source/blender/editors/interface/interface_eyedropper_colorband.c
index be23eacafff..24d06361c54 100644
--- a/source/blender/editors/interface/interface_eyedropper_colorband.c
+++ b/source/blender/editors/interface/interface_eyedropper_colorband.c
@@ -304,7 +304,10 @@ static int eyedropper_colorband_invoke(bContext *C, wmOperator *op, const wmEven
{
/* init */
if (eyedropper_colorband_init(C, op)) {
- WM_cursor_modal_set(CTX_wm_window(C), WM_CURSOR_EYEDROPPER);
+ wmWindow *win = CTX_wm_window(C);
+ /* Workaround for de-activating the button clearing the cursor, see T76794 */
+ UI_context_active_but_clear(C, win, CTX_wm_region(C));
+ WM_cursor_modal_set(win, WM_CURSOR_EYEDROPPER);
/* add temp handler */
WM_event_add_modal_handler(C, op);
diff --git a/source/blender/editors/interface/interface_eyedropper_datablock.c b/source/blender/editors/interface/interface_eyedropper_datablock.c
index 93599b8727a..f2217db9b7d 100644
--- a/source/blender/editors/interface/interface_eyedropper_datablock.c
+++ b/source/blender/editors/interface/interface_eyedropper_datablock.c
@@ -152,27 +152,27 @@ static void datadropper_id_sample_pt(bContext *C, DataDropper *ddr, int mx, int
{
/* we could use some clever */
bScreen *screen = CTX_wm_screen(C);
- ScrArea *sa = BKE_screen_find_area_xy(screen, -1, mx, my);
+ ScrArea *area = BKE_screen_find_area_xy(screen, -1, mx, my);
ScrArea *area_prev = CTX_wm_area(C);
- ARegion *ar_prev = CTX_wm_region(C);
+ ARegion *region_prev = CTX_wm_region(C);
ddr->name[0] = '\0';
- if (sa) {
- if (ELEM(sa->spacetype, SPACE_VIEW3D, SPACE_OUTLINER)) {
- ARegion *region = BKE_area_find_region_xy(sa, RGN_TYPE_WINDOW, mx, my);
+ if (area) {
+ if (ELEM(area->spacetype, SPACE_VIEW3D, SPACE_OUTLINER)) {
+ ARegion *region = BKE_area_find_region_xy(area, RGN_TYPE_WINDOW, mx, my);
if (region) {
const int mval[2] = {mx - region->winrct.xmin, my - region->winrct.ymin};
Base *base;
- CTX_wm_area_set(C, sa);
+ CTX_wm_area_set(C, area);
CTX_wm_region_set(C, region);
/* grr, always draw else we leave stale text */
ED_region_tag_redraw(region);
- if (sa->spacetype == SPACE_VIEW3D) {
+ if (area->spacetype == SPACE_VIEW3D) {
base = ED_view3d_give_base_under_cursor(C, mval);
}
else {
@@ -208,7 +208,7 @@ static void datadropper_id_sample_pt(bContext *C, DataDropper *ddr, int mx, int
}
CTX_wm_area_set(C, area_prev);
- CTX_wm_region_set(C, ar_prev);
+ CTX_wm_region_set(C, region_prev);
}
/* sets the ID, returns success */
@@ -250,11 +250,11 @@ static void datadropper_set_draw_callback_region(bContext *C,
const int my)
{
bScreen *screen = CTX_wm_screen(C);
- ScrArea *sa = BKE_screen_find_area_xy(screen, -1, mx, my);
+ ScrArea *area = BKE_screen_find_area_xy(screen, -1, mx, my);
- if (sa) {
+ if (area) {
/* If spacetype changed */
- if (sa->spacetype != ddr->cursor_area->spacetype) {
+ if (area->spacetype != ddr->cursor_area->spacetype) {
/* Remove old callback */
ED_region_draw_cb_exit(ddr->art, ddr->draw_handle_pixel);
@@ -263,9 +263,9 @@ static void datadropper_set_draw_callback_region(bContext *C,
ED_region_tag_redraw(region);
/* Set draw callback in new region */
- ARegionType *art = BKE_regiontype_from_id(sa->type, RGN_TYPE_WINDOW);
+ ARegionType *art = BKE_regiontype_from_id(area->type, RGN_TYPE_WINDOW);
- ddr->cursor_area = sa;
+ ddr->cursor_area = area;
ddr->art = art;
ddr->draw_handle_pixel = ED_region_draw_cb_activate(
art, datadropper_draw_cb, ddr, REGION_DRAW_POST_PIXEL);
@@ -316,7 +316,10 @@ static int datadropper_invoke(bContext *C, wmOperator *op, const wmEvent *UNUSED
{
/* init */
if (datadropper_init(C, op)) {
- WM_cursor_modal_set(CTX_wm_window(C), WM_CURSOR_EYEDROPPER);
+ wmWindow *win = CTX_wm_window(C);
+ /* Workaround for de-activating the button clearing the cursor, see T76794 */
+ UI_context_active_but_clear(C, win, CTX_wm_region(C));
+ WM_cursor_modal_set(win, WM_CURSOR_EYEDROPPER);
/* add temp handler */
WM_event_add_modal_handler(C, op);
diff --git a/source/blender/editors/interface/interface_eyedropper_depth.c b/source/blender/editors/interface/interface_eyedropper_depth.c
index a5e60adec55..5c85edc94a1 100644
--- a/source/blender/editors/interface/interface_eyedropper_depth.c
+++ b/source/blender/editors/interface/interface_eyedropper_depth.c
@@ -156,27 +156,27 @@ static void depthdropper_depth_sample_pt(
{
/* we could use some clever */
bScreen *screen = CTX_wm_screen(C);
- ScrArea *sa = BKE_screen_find_area_xy(screen, SPACE_TYPE_ANY, mx, my);
+ ScrArea *area = BKE_screen_find_area_xy(screen, SPACE_TYPE_ANY, mx, my);
Scene *scene = CTX_data_scene(C);
ScrArea *area_prev = CTX_wm_area(C);
- ARegion *ar_prev = CTX_wm_region(C);
+ ARegion *region_prev = CTX_wm_region(C);
ddr->name[0] = '\0';
- if (sa) {
- if (sa->spacetype == SPACE_VIEW3D) {
- ARegion *region = BKE_area_find_region_xy(sa, RGN_TYPE_WINDOW, mx, my);
+ if (area) {
+ if (area->spacetype == SPACE_VIEW3D) {
+ ARegion *region = BKE_area_find_region_xy(area, RGN_TYPE_WINDOW, mx, my);
if (region) {
struct Depsgraph *depsgraph = CTX_data_depsgraph_pointer(C);
- View3D *v3d = sa->spacedata.first;
+ View3D *v3d = area->spacedata.first;
RegionView3D *rv3d = region->regiondata;
/* weak, we could pass in some reference point */
const float *view_co = v3d->camera ? v3d->camera->obmat[3] : rv3d->viewinv[3];
const int mval[2] = {mx - region->winrct.xmin, my - region->winrct.ymin};
float co[3];
- CTX_wm_area_set(C, sa);
+ CTX_wm_area_set(C, area);
CTX_wm_region_set(C, region);
/* grr, always draw else we leave stale text */
@@ -209,7 +209,7 @@ static void depthdropper_depth_sample_pt(
}
CTX_wm_area_set(C, area_prev);
- CTX_wm_region_set(C, ar_prev);
+ CTX_wm_region_set(C, region_prev);
}
/* sets the sample depth RGB, maintaining A */
@@ -311,7 +311,10 @@ static int depthdropper_invoke(bContext *C, wmOperator *op, const wmEvent *UNUSE
{
/* init */
if (depthdropper_init(C, op)) {
- WM_cursor_modal_set(CTX_wm_window(C), WM_CURSOR_EYEDROPPER);
+ wmWindow *win = CTX_wm_window(C);
+ /* Workaround for de-activating the button clearing the cursor, see T76794 */
+ UI_context_active_but_clear(C, win, CTX_wm_region(C));
+ WM_cursor_modal_set(win, WM_CURSOR_EYEDROPPER);
/* add temp handler */
WM_event_add_modal_handler(C, op);
diff --git a/source/blender/editors/interface/interface_eyedropper_driver.c b/source/blender/editors/interface/interface_eyedropper_driver.c
index 89c087855bc..276cc70f2b5 100644
--- a/source/blender/editors/interface/interface_eyedropper_driver.c
+++ b/source/blender/editors/interface/interface_eyedropper_driver.c
@@ -180,7 +180,10 @@ static int driverdropper_invoke(bContext *C, wmOperator *op, const wmEvent *UNUS
{
/* init */
if (driverdropper_init(C, op)) {
- WM_cursor_modal_set(CTX_wm_window(C), WM_CURSOR_EYEDROPPER);
+ wmWindow *win = CTX_wm_window(C);
+ /* Workaround for de-activating the button clearing the cursor, see T76794 */
+ UI_context_active_but_clear(C, win, CTX_wm_region(C));
+ WM_cursor_modal_set(win, WM_CURSOR_EYEDROPPER);
/* add temp handler */
WM_event_add_modal_handler(C, op);
diff --git a/source/blender/editors/interface/interface_eyedropper_gpencil_color.c b/source/blender/editors/interface/interface_eyedropper_gpencil_color.c
index 2944186c701..3d32ede60c2 100644
--- a/source/blender/editors/interface/interface_eyedropper_gpencil_color.c
+++ b/source/blender/editors/interface/interface_eyedropper_gpencil_color.c
@@ -28,6 +28,7 @@
#include "MEM_guardedalloc.h"
+#include "BLI_listbase.h"
#include "BLI_string.h"
#include "BLT_translation.h"
@@ -211,7 +212,7 @@ static void eyedropper_add_palette_color(bContext *C, float col_conv[4])
}
/* Check if the color exist already. */
Palette *palette = paint->palette;
- for (PaletteColor *palcolor = palette->colors.first; palcolor; palcolor = palcolor->next) {
+ LISTBASE_FOREACH (PaletteColor *, palcolor, &palette->colors) {
if (compare_v3v3(palcolor->rgb, col_conv, 0.01f)) {
return;
}
diff --git a/source/blender/editors/interface/interface_handlers.c b/source/blender/editors/interface/interface_handlers.c
index 98d9418c3f5..a62130b9b13 100644
--- a/source/blender/editors/interface/interface_handlers.c
+++ b/source/blender/editors/interface/interface_handlers.c
@@ -335,12 +335,7 @@ typedef struct uiHandleButtonData {
int maxlen;
/* Button text selection:
* extension direction, selextend, inside ui_do_but_TEX */
- enum {
- EXTEND_NONE = 0,
- EXTEND_LEFT = 1,
- EXTEND_RIGHT = 2,
- } selextend;
- float selstartx;
+ int sel_pos_init;
/* allow to realloc str/editstr and use 'maxlen' to track alloc size (maxlen + 1) */
bool is_str_dynamic;
@@ -386,6 +381,9 @@ typedef struct uiHandleButtonData {
uiSelectContextStore select_others;
#endif
+ /* Text field undo. */
+ struct uiUndoStack_Text *undo_stack_text;
+
/* post activate */
uiButtonActivateType posttype;
uiBut *postbut;
@@ -422,7 +420,7 @@ typedef struct uiAfterFunc {
PropertyRNA *rnaprop;
void *search_arg;
- uiButSearchArgFreeFunc search_arg_free_func;
+ uiButSearchArgFreeFn search_arg_free_fn;
bContextStore *context;
@@ -758,10 +756,12 @@ static void ui_apply_but_func(bContext *C, uiBut *but)
after->rnapoin = but->rnapoin;
after->rnaprop = but->rnaprop;
- after->search_arg_free_func = but->search_arg_free_func;
- after->search_arg = but->search_arg;
- but->search_arg_free_func = NULL;
- but->search_arg = NULL;
+ if (but->search != NULL) {
+ after->search_arg_free_fn = but->search->arg_free_fn;
+ after->search_arg = but->search->arg;
+ but->search->arg_free_fn = NULL;
+ but->search->arg = NULL;
+ }
if (but->context) {
after->context = CTX_store_copy(but->context);
@@ -929,8 +929,8 @@ static void ui_apply_but_funcs_after(bContext *C)
MEM_freeN(after.rename_orig);
}
- if (after.search_arg_free_func) {
- after.search_arg_free_func(after.search_arg);
+ if (after.search_arg_free_fn) {
+ after.search_arg_free_fn(after.search_arg);
}
ui_afterfunc_update_preferences_dirty(&after);
@@ -1272,7 +1272,7 @@ static void ui_multibut_states_create(uiBut *but_active, uiHandleButtonData *dat
data->multi_data.bs_mbuts = UI_butstore_create(but_active->block);
- for (uiBut *but = but_active->block->buttons.first; but; but = but->next) {
+ LISTBASE_FOREACH (uiBut *, but, &but_active->block->buttons) {
if (but->flag & UI_BUT_DRAG_MULTI) {
ui_multibut_add(data, but);
}
@@ -1282,7 +1282,7 @@ static void ui_multibut_states_create(uiBut *but_active, uiHandleButtonData *dat
* note: if we mix buttons which are proportional and others which are not,
* this may work a bit strangely */
if ((but_active->rnaprop && (RNA_property_flag(but_active->rnaprop) & PROP_PROPORTIONAL)) ||
- ELEM(but_active->unit_type, PROP_UNIT_LENGTH)) {
+ ELEM(but_active->unit_type, RNA_SUBTYPE_UNIT_VALUE(PROP_UNIT_LENGTH))) {
if (data->origvalue != 0.0) {
data->multi_data.is_proportional = true;
}
@@ -1874,7 +1874,7 @@ static bool ui_but_drag_init(bContext *C,
#ifdef USE_DRAG_TOGGLE
if (ui_drag_toggle_but_is_supported(but)) {
uiDragToggleHandle *drag_info = MEM_callocN(sizeof(*drag_info), __func__);
- ARegion *ar_prev;
+ ARegion *region_prev;
/* call here because regular mouse-up event wont run,
* typically 'button_activate_exit()' handles this */
@@ -1887,7 +1887,7 @@ static bool ui_but_drag_init(bContext *C,
copy_v2_v2_int(drag_info->xy_last, &event->x);
/* needed for toggle drag on popups */
- ar_prev = CTX_wm_region(C);
+ region_prev = CTX_wm_region(C);
CTX_wm_region_set(C, data->region);
WM_event_add_ui_handler(C,
@@ -1897,7 +1897,7 @@ static bool ui_but_drag_init(bContext *C,
drag_info,
WM_HANDLER_BLOCKING);
- CTX_wm_region_set(C, ar_prev);
+ CTX_wm_region_set(C, region_prev);
/* Initialize alignment for single row/column regions,
* otherwise we use the relative position of the first other button dragged over. */
@@ -1906,13 +1906,13 @@ static bool ui_but_drag_init(bContext *C,
RGN_TYPE_HEADER,
RGN_TYPE_TOOL_HEADER,
RGN_TYPE_FOOTER)) {
- const int ar_alignment = RGN_ALIGN_ENUM_FROM_MASK(data->region->alignment);
+ const int region_alignment = RGN_ALIGN_ENUM_FROM_MASK(data->region->alignment);
int lock_axis = -1;
- if (ELEM(ar_alignment, RGN_ALIGN_LEFT, RGN_ALIGN_RIGHT)) {
+ if (ELEM(region_alignment, RGN_ALIGN_LEFT, RGN_ALIGN_RIGHT)) {
lock_axis = 0;
}
- else if (ELEM(ar_alignment, RGN_ALIGN_TOP, RGN_ALIGN_BOTTOM)) {
+ else if (ELEM(region_alignment, RGN_ALIGN_TOP, RGN_ALIGN_BOTTOM)) {
lock_axis = 1;
}
if (lock_axis != -1) {
@@ -2837,6 +2837,23 @@ static bool ui_textedit_delete_selection(uiBut *but, uiHandleButtonData *data)
return changed;
}
+static bool ui_textedit_set_cursor_pos_foreach_glyph(const char *UNUSED(str),
+ const size_t str_step_ofs,
+ const rcti *glyph_step_bounds,
+ const int UNUSED(glyph_advance_x),
+ const rctf *glyph_bounds,
+ const int UNUSED(glyph_bearing[2]),
+ void *user_data)
+{
+ int *cursor_data = user_data;
+ float center = glyph_step_bounds->xmin + (BLI_rctf_size_x(glyph_bounds) / 2.0f);
+ if (cursor_data[0] < center) {
+ cursor_data[1] = str_step_ofs;
+ return false;
+ }
+ return true;
+}
+
/**
* \param x: Screen space cursor location - #wmEvent.x
*
@@ -2872,8 +2889,7 @@ static void ui_textedit_set_cursor_pos(uiBut *but, uiHandleButtonData *data, con
startx += UI_DPI_ICON_SIZE / aspect;
}
}
- /* But this extra .05 makes clicks in between characters feel nicer. */
- startx += ((UI_TEXT_MARGIN_X + 0.05f) * U.widget_unit) / aspect;
+ startx += (UI_TEXT_MARGIN_X * U.widget_unit) / aspect;
/* mouse dragged outside the widget to the left */
if (x < startx) {
@@ -2896,48 +2912,24 @@ static void ui_textedit_set_cursor_pos(uiBut *but, uiHandleButtonData *data, con
but->pos = but->ofs;
}
/* mouse inside the widget, mouse coords mapped in widget space */
- else { /* (x >= startx) */
- int pos_i;
-
- /* keep track of previous distance from the cursor to the char */
- float cdist, cdist_prev = 0.0f;
- short pos_prev;
-
- str_last = &str[strlen(str)];
-
- but->pos = pos_prev = ((str_last - str) - but->ofs);
-
- while (true) {
- cdist = startx + BLF_width(fstyle.uifont_id, str + but->ofs, (str_last - str) - but->ofs);
-
- /* check if position is found */
- if (cdist < x) {
- /* check is previous location was in fact closer */
- if ((x - cdist) > (cdist_prev - x)) {
- but->pos = pos_prev;
- }
- break;
- }
- cdist_prev = cdist;
- pos_prev = but->pos;
- /* done with tricky distance checks */
-
- pos_i = but->pos;
- if (but->pos <= 0) {
- break;
- }
- if (BLI_str_cursor_step_prev_utf8(str, but->ofs, &pos_i)) {
- but->pos = pos_i;
- str_last = &str[but->pos + but->ofs];
- }
- else {
- break; /* unlikely but possible */
- }
- }
- but->pos += but->ofs;
- if (but->pos < 0) {
- but->pos = 0;
- }
+ else {
+ str_last = &str[but->ofs];
+ const int str_last_len = strlen(str_last);
+ int x_pos = (int)(x - startx);
+ int glyph_data[2] = {
+ x_pos, /* horizontal position to test. */
+ -1, /* Write the character offset here. */
+ };
+ BLF_boundbox_foreach_glyph(fstyle.uifont_id,
+ str + but->ofs,
+ INT_MAX,
+ ui_textedit_set_cursor_pos_foreach_glyph,
+ glyph_data);
+ /* If value untouched then we are to the right. */
+ if (glyph_data[1] == -1) {
+ glyph_data[1] = str_last_len;
+ }
+ but->pos = glyph_data[1] + but->ofs;
}
if (fstyle.kerning == 1) {
@@ -2949,20 +2941,12 @@ static void ui_textedit_set_cursor_pos(uiBut *but, uiHandleButtonData *data, con
static void ui_textedit_set_cursor_select(uiBut *but, uiHandleButtonData *data, const float x)
{
- if (x > data->selstartx) {
- data->selextend = EXTEND_RIGHT;
- }
- else if (x < data->selstartx) {
- data->selextend = EXTEND_LEFT;
- }
-
ui_textedit_set_cursor_pos(but, data, x);
- if (data->selextend == EXTEND_RIGHT) {
- but->selend = but->pos;
- }
- else if (data->selextend == EXTEND_LEFT) {
- but->selsta = but->pos;
+ but->selsta = but->pos;
+ but->selend = data->sel_pos_init;
+ if (but->selend < but->selsta) {
+ SWAP(short, but->selsta, but->selend);
}
ui_but_update(but);
@@ -3058,7 +3042,7 @@ static void ui_textedit_move(uiBut *but,
but->pos = but->selend = but->selsta;
}
}
- data->selextend = EXTEND_NONE;
+ data->sel_pos_init = but->pos;
}
else {
int pos_i = but->pos;
@@ -3066,48 +3050,14 @@ static void ui_textedit_move(uiBut *but,
but->pos = pos_i;
if (select) {
- /* existing selection */
- if (has_sel) {
-
- if (data->selextend == EXTEND_NONE) {
- data->selextend = EXTEND_RIGHT;
- }
-
- if (direction) {
- if (data->selextend == EXTEND_RIGHT) {
- but->selend = but->pos;
- }
- else {
- but->selsta = but->pos;
- }
- }
- else {
- if (data->selextend == EXTEND_LEFT) {
- but->selsta = but->pos;
- }
- else {
- but->selend = but->pos;
- }
- }
-
- if (but->selend < but->selsta) {
- SWAP(short, but->selsta, but->selend);
- data->selextend = (data->selextend == EXTEND_RIGHT) ? EXTEND_LEFT : EXTEND_RIGHT;
- }
-
- } /* new selection */
- else {
- if (direction) {
- data->selextend = EXTEND_RIGHT;
- but->selend = but->pos;
- but->selsta = pos_prev;
- }
- else {
- data->selextend = EXTEND_LEFT;
- but->selend = pos_prev;
- but->selsta = but->pos;
- }
+ if (has_sel == false) {
+ data->sel_pos_init = pos_prev;
}
+ but->selsta = but->pos;
+ but->selend = data->sel_pos_init;
+ }
+ if (but->selend < but->selsta) {
+ SWAP(short, but->selsta, but->selend);
}
}
}
@@ -3337,8 +3287,7 @@ static void ui_textedit_begin(bContext *C, uiBut *but, uiHandleButtonData *data)
len = strlen(data->str);
data->origstr = BLI_strdupn(data->str, len);
- data->selextend = EXTEND_NONE;
- data->selstartx = 0.0f;
+ data->sel_pos_init = 0;
/* set cursor pos to the end of the text */
but->editstr = data->str;
@@ -3346,9 +3295,13 @@ static void ui_textedit_begin(bContext *C, uiBut *but, uiHandleButtonData *data)
but->selsta = 0;
but->selend = len;
+ /* Initialize undo history tracking. */
+ data->undo_stack_text = ui_textedit_undo_stack_create();
+ ui_textedit_undo_push(data->undo_stack_text, but->editstr, but->pos);
+
/* optional searchbox */
if (but->type == UI_BTYPE_SEARCH_MENU) {
- data->searchbox = but->search_create_func(C, data->region, but);
+ data->searchbox = but->search->create_fn(C, data->region, but);
ui_searchbox_update(C, data->searchbox, but, true); /* true = reset */
}
@@ -3388,6 +3341,9 @@ static void ui_textedit_end(bContext *C, uiBut *but, uiHandleButtonData *data)
/* ensure menu (popup) too is closed! */
data->escapecancel = true;
+
+ WM_reportf(RPT_ERROR, "Failed to find '%s'", but->editstr);
+ WM_report_banner_show();
}
}
@@ -3401,6 +3357,10 @@ static void ui_textedit_end(bContext *C, uiBut *but, uiHandleButtonData *data)
WM_cursor_modal_restore(win);
+ /* Free text undo history text blocks. */
+ ui_textedit_undo_stack_destroy(data->undo_stack_text);
+ data->undo_stack_text = NULL;
+
#ifdef WITH_INPUT_IME
if (win->ime_data) {
ui_textedit_ime_end(win, but);
@@ -3480,7 +3440,7 @@ static void ui_do_but_textedit(
bContext *C, uiBlock *block, uiBut *but, uiHandleButtonData *data, const wmEvent *event)
{
int retval = WM_UI_HANDLER_CONTINUE;
- bool changed = false, inbox = false, update = false;
+ bool changed = false, inbox = false, update = false, skip_undo_push = false;
#ifdef WITH_INPUT_IME
wmWindow *win = CTX_wm_window(C);
@@ -3500,7 +3460,7 @@ static void ui_do_but_textedit(
/* pass */
}
else {
- ui_searchbox_event(C, data->searchbox, but, event);
+ ui_searchbox_event(C, data->searchbox, but, data->region, event);
}
#else
ui_searchbox_event(C, data->searchbox, but, event);
@@ -3511,6 +3471,16 @@ static void ui_do_but_textedit(
case RIGHTMOUSE:
case EVT_ESCKEY:
if (event->val == KM_PRESS) {
+ /* Support search context menu. */
+ if (event->type == RIGHTMOUSE) {
+ if (data->searchbox) {
+ if (ui_searchbox_event(C, data->searchbox, but, data->region, event)) {
+ /* Only break if the event was handled. */
+ break;
+ }
+ }
+ }
+
#ifdef WITH_INPUT_IME
/* skips button handling since it is not wanted */
if (is_ime_composing) {
@@ -3544,7 +3514,7 @@ static void ui_do_but_textedit(
if (ui_but_contains_pt(but, mx, my)) {
ui_textedit_set_cursor_pos(but, data, event->x);
but->selsta = but->selend = but->pos;
- data->selstartx = event->x;
+ data->sel_pos_init = but->pos;
button_activate_state(C, but, BUTTON_STATE_TEXT_SELECTING);
retval = WM_UI_HANDLER_BREAK;
@@ -3619,7 +3589,7 @@ static void ui_do_but_textedit(
#ifdef USE_KEYNAV_LIMIT
ui_mouse_motion_keynav_init(&data->searchbox_keynav_state, event);
#endif
- ui_searchbox_event(C, data->searchbox, but, event);
+ ui_searchbox_event(C, data->searchbox, but, data->region, event);
break;
}
if (event->type == WHEELDOWNMOUSE) {
@@ -3636,7 +3606,7 @@ static void ui_do_but_textedit(
#ifdef USE_KEYNAV_LIMIT
ui_mouse_motion_keynav_init(&data->searchbox_keynav_state, event);
#endif
- ui_searchbox_event(C, data->searchbox, but, event);
+ ui_searchbox_event(C, data->searchbox, but, data->region, event);
break;
}
if (event->type == WHEELUPMOUSE) {
@@ -3702,6 +3672,32 @@ static void ui_do_but_textedit(
}
retval = WM_UI_HANDLER_BREAK;
break;
+ case EVT_ZKEY: {
+ /* Ctrl-Z or Ctrl-Shift-Z: Undo/Redo (allowing for OS-Key on Apple). */
+
+ const bool is_redo = (event->shift != 0);
+ if (
+#if defined(__APPLE__)
+ (event->oskey && !IS_EVENT_MOD(event, alt, ctrl)) ||
+#endif
+ (event->ctrl && !IS_EVENT_MOD(event, alt, oskey))) {
+ int undo_pos;
+ const char *undo_str = ui_textedit_undo(
+ data->undo_stack_text, is_redo ? 1 : -1, &undo_pos);
+ if (undo_str != NULL) {
+ ui_textedit_string_set(but, data, undo_str);
+
+ /* Set the cursor & clear selection. */
+ but->pos = undo_pos;
+ but->selsta = but->pos;
+ but->selend = but->pos;
+ changed = true;
+ }
+ retval = WM_UI_HANDLER_BREAK;
+ skip_undo_push = true;
+ }
+ break;
+ }
}
if ((event->ascii || event->utf8_buf[0]) && (retval == WM_UI_HANDLER_CONTINUE)
@@ -3723,12 +3719,7 @@ static void ui_do_but_textedit(
if (utf8_buf && utf8_buf[0]) {
int utf8_buf_len = BLI_str_utf8_size(utf8_buf);
- /* keep this printf until utf8 is well tested */
- if (utf8_buf_len != 1) {
- printf("%s: utf8 char '%.*s'\n", __func__, utf8_buf_len, utf8_buf);
- }
-
- // strcpy(utf8_buf, "12345");
+ BLI_assert(utf8_buf_len != -1);
changed = ui_textedit_insert_buf(but, data, event->utf8_buf, utf8_buf_len);
}
else {
@@ -3760,6 +3751,11 @@ static void ui_do_but_textedit(
#endif
if (changed) {
+ /* The undo stack may be NULL if an event exits editing. */
+ if ((skip_undo_push == false) && (data->undo_stack_text != NULL)) {
+ ui_textedit_undo_push(data->undo_stack_text, data->str, but->pos);
+ }
+
/* only do live update when but flag request it (UI_BUT_TEXTEDIT_UPDATE). */
if (update && data->interactive) {
ui_apply_but(C, block, but, data, true);
@@ -4434,7 +4430,8 @@ static int ui_do_but_TOG(bContext *C, uiBut *but, uiHandleButtonData *data, cons
do_activate = (event->val == KM_RELEASE);
}
else {
- do_activate = (event->val == KM_PRESS);
+ /* Also use double-clicks to prevent fast clicks to leak to other handlers (T76481). */
+ do_activate = ELEM(event->val, KM_PRESS, KM_DBL_CLICK);
}
}
@@ -5546,7 +5543,7 @@ static int ui_do_but_BLOCK(bContext *C, uiBut *but, uiHandleButtonData *data, co
}
else if (but->type == UI_BTYPE_MENU) {
if (ELEM(event->type, WHEELDOWNMOUSE, WHEELUPMOUSE) && event->ctrl) {
- const int direction = (event->type == WHEELDOWNMOUSE) ? -1 : 1;
+ const int direction = (event->type == WHEELDOWNMOUSE) ? 1 : -1;
data->value = ui_but_menu_step(but, direction);
@@ -7691,8 +7688,8 @@ void UI_but_tooltip_refresh(bContext *C, uiBut *but)
{
uiHandleButtonData *data = but->active;
if (data) {
- bScreen *sc = WM_window_get_active_screen(data->window);
- if (sc->tool_tip && sc->tool_tip->region) {
+ bScreen *screen = WM_window_get_active_screen(data->window);
+ if (screen->tool_tip && screen->tool_tip->region) {
WM_tooltip_refresh(C, data->window);
}
}
@@ -7752,9 +7749,9 @@ static void button_tooltip_timer_reset(bContext *C, uiBut *but)
WM_tooltip_timer_init_ex(
C, data->window, data->area, data->region, ui_but_tooltip_init, delay);
if (is_label) {
- bScreen *sc = WM_window_get_active_screen(data->window);
- if (sc->tool_tip) {
- sc->tool_tip->pass = 1;
+ bScreen *screen = WM_window_get_active_screen(data->window);
+ if (screen->tool_tip) {
+ screen->tool_tip->pass = 1;
}
}
}
@@ -8040,11 +8037,11 @@ static void button_activate_init(bContext *C,
if (UI_but_has_tooltip_label(but)) {
/* Show a label for this button. */
- bScreen *sc = WM_window_get_active_screen(data->window);
+ bScreen *screen = WM_window_get_active_screen(data->window);
if ((PIL_check_seconds_timer() - WM_tooltip_time_closed()) < 0.1) {
WM_tooltip_immediate_init(C, CTX_wm_window(C), data->area, region, ui_but_tooltip_init);
- if (sc->tool_tip) {
- sc->tool_tip->pass = 1;
+ if (screen->tool_tip) {
+ screen->tool_tip->pass = 1;
}
}
}
@@ -8245,11 +8242,22 @@ static uiBut *ui_context_rna_button_active(const bContext *C)
return ui_context_button_active(CTX_wm_region(C), ui_context_rna_button_active_test);
}
-uiBut *UI_context_active_but_get(const struct bContext *C)
+uiBut *UI_context_active_but_get(const bContext *C)
{
return ui_context_button_active(CTX_wm_region(C), NULL);
}
+/*
+ * Version of #UI_context_active_get() that uses the result of #CTX_wm_menu()
+ * if set. Does not traverse into parent menus, which may be wanted in some
+ * cases.
+ */
+uiBut *UI_context_active_but_get_respect_menu(const bContext *C)
+{
+ ARegion *ar_menu = CTX_wm_menu(C);
+ return ui_context_button_active(ar_menu ? ar_menu : CTX_wm_region(C), NULL);
+}
+
uiBut *UI_region_active_but_get(ARegion *region)
{
return ui_context_button_active(region, NULL);
@@ -8308,18 +8316,23 @@ void UI_context_active_but_prop_handle(bContext *C)
}
}
+void UI_context_active_but_clear(bContext *C, wmWindow *win, ARegion *region)
+{
+ wm_event_handler_ui_cancel_ex(C, win, region, false);
+}
+
wmOperator *UI_context_active_operator_get(const struct bContext *C)
{
- ARegion *ar_ctx = CTX_wm_region(C);
+ ARegion *region_ctx = CTX_wm_region(C);
uiBlock *block;
/* background mode */
- if (ar_ctx == NULL) {
+ if (region_ctx == NULL) {
return NULL;
}
/* scan active regions ui */
- for (block = ar_ctx->uiblocks.first; block; block = block->next) {
+ for (block = region_ctx->uiblocks.first; block; block = block->next) {
if (block->ui_operator) {
return block->ui_operator;
}
@@ -8327,11 +8340,11 @@ wmOperator *UI_context_active_operator_get(const struct bContext *C)
/* scan popups */
{
- bScreen *sc = CTX_wm_screen(C);
+ bScreen *screen = CTX_wm_screen(C);
ARegion *region;
- for (region = sc->regionbase.first; region; region = region->next) {
- if (region == ar_ctx) {
+ for (region = screen->regionbase.first; region; region = region->next) {
+ if (region == region_ctx) {
continue;
}
for (block = region->uiblocks.first; block; block = block->next) {
@@ -8454,10 +8467,10 @@ void ui_but_activate_event(bContext *C, ARegion *region, uiBut *but)
event.customdata = but;
event.customdatafree = false;
- ARegion *ar_ctx = CTX_wm_region(C);
+ ARegion *region_ctx = CTX_wm_region(C);
CTX_wm_region_set(C, region);
ui_do_button(C, but->block, but, &event);
- CTX_wm_region_set(C, ar_ctx);
+ CTX_wm_region_set(C, region_ctx);
}
/**
@@ -8839,14 +8852,14 @@ static int ui_handle_button_event(bContext *C, const wmEvent *event, uiBut *but)
if (post_but) {
button_activate_init(C, region, post_but, post_type);
}
- else {
+ else if (!((event->type == EVT_BUT_CANCEL) && (event->val == 1))) {
/* XXX issue is because WM_event_add_mousemove(wm) is a bad hack and not reliable,
* if that gets coded better this bypass can go away too.
*
* This is needed to make sure if a button was active,
* it stays active while the mouse is over it.
* This avoids adding mousemoves, see: [#33466] */
- if (ELEM(state_orig, BUTTON_STATE_INIT, BUTTON_STATE_HIGHLIGHT)) {
+ if (ELEM(state_orig, BUTTON_STATE_INIT, BUTTON_STATE_HIGHLIGHT, BUTTON_STATE_WAIT_DRAG)) {
if (ui_but_find_mouse_over(region, event) == but) {
button_activate_init(C, region, but, BUTTON_ACTIVATE_OVER);
}
@@ -9225,7 +9238,7 @@ static void ui_menu_scroll_apply_offset_y(ARegion *region, uiBlock *block, float
if (dy < 0.0f) {
/* Stop at top item, extra 0.5 UI_UNIT_Y makes it snap nicer. */
float ymax = -FLT_MAX;
- for (uiBut *bt = block->buttons.first; bt; bt = bt->next) {
+ LISTBASE_FOREACH (uiBut *, bt, &block->buttons) {
ymax = max_ff(ymax, bt->rect.ymax);
}
if (ymax + dy - UI_UNIT_Y * 0.5f < block->rect.ymax - UI_MENU_SCROLL_PAD) {
@@ -9235,7 +9248,7 @@ static void ui_menu_scroll_apply_offset_y(ARegion *region, uiBlock *block, float
else {
/* Stop at bottom item, extra 0.5 UI_UNIT_Y makes it snap nicer. */
float ymin = FLT_MAX;
- for (uiBut *bt = block->buttons.first; bt; bt = bt->next) {
+ LISTBASE_FOREACH (uiBut *, bt, &block->buttons) {
ymin = min_ff(ymin, bt->rect.ymin);
}
if (ymin + dy + UI_UNIT_Y * 0.5f > block->rect.ymin + UI_MENU_SCROLL_PAD) {
@@ -9248,7 +9261,7 @@ static void ui_menu_scroll_apply_offset_y(ARegion *region, uiBlock *block, float
block->handle->scrolloffset += dy;
/* apply scroll offset */
- for (uiBut *bt = block->buttons.first; bt; bt = bt->next) {
+ LISTBASE_FOREACH (uiBut *, bt, &block->buttons) {
bt->rect.ymin += dy;
bt->rect.ymax += dy;
}
@@ -9329,7 +9342,7 @@ static bool ui_menu_scroll_step(ARegion *region, uiBlock *block, const int scrol
static void ui_region_auto_open_clear(ARegion *region)
{
- for (uiBlock *block = region->uiblocks.first; block; block = block->next) {
+ LISTBASE_FOREACH (uiBlock *, block, &region->uiblocks) {
block->auto_open = false;
}
}
@@ -9371,6 +9384,11 @@ static int ui_handle_menu_button(bContext *C, const wmEvent *event, uiPopupBlock
if (event->val == KM_RELEASE) {
/* pass, needed so we can exit active menu-items when click-dragging out of them */
}
+ else if (but->type == UI_BTYPE_SEARCH_MENU) {
+ /* Pass, needed so search popup can have RMB context menu.
+ * This may be useful for other interactions which happen in the search popup
+ * without being directly over the search button. */
+ }
else if (!ui_block_is_menu(but->block) || ui_block_is_pie_menu(but->block)) {
/* pass, skip for dialogs */
}
@@ -9783,7 +9801,11 @@ static int ui_handle_menu_event(bContext *C,
for (but = block->buttons.first; but; but = but->next) {
bool doit = false;
- if (!ELEM(but->type, UI_BTYPE_LABEL, UI_BTYPE_SEPR, UI_BTYPE_SEPR_LINE)) {
+ if (!ELEM(but->type,
+ UI_BTYPE_LABEL,
+ UI_BTYPE_SEPR,
+ UI_BTYPE_SEPR_LINE,
+ UI_BTYPE_IMAGE)) {
count++;
}
@@ -10624,7 +10646,7 @@ static int ui_region_handler(bContext *C, const wmEvent *event, void *UNUSED(use
static void ui_region_handler_remove(bContext *C, void *UNUSED(userdata))
{
- bScreen *sc;
+ bScreen *screen;
ARegion *region;
region = CTX_wm_region(C);
@@ -10634,15 +10656,15 @@ static void ui_region_handler_remove(bContext *C, void *UNUSED(userdata))
UI_blocklist_free(C, &region->uiblocks);
- sc = CTX_wm_screen(C);
- if (sc == NULL) {
+ screen = CTX_wm_screen(C);
+ if (screen == NULL) {
return;
}
/* delayed apply callbacks, but not for screen level regions, those
* we rather do at the very end after closing them all, which will
* be done in ui_region_handler/window */
- if (BLI_findindex(&sc->regionbase, region) == -1) {
+ if (BLI_findindex(&screen->regionbase, region) == -1) {
ui_apply_but_funcs_after(C);
}
}
@@ -10800,9 +10822,6 @@ static int ui_popup_handler(bContext *C, const wmEvent *event, void *userdata)
if (temp.popup_func) {
temp.popup_func(C, temp.popup_arg, temp.retvalue);
}
- if (temp.optype) {
- WM_operator_name_call_ptr(C, temp.optype, temp.opcontext, NULL);
- }
}
else if (temp.cancel_func) {
temp.cancel_func(C, temp.popup_arg);
@@ -10966,9 +10985,8 @@ void UI_screen_free_active_but(const bContext *C, bScreen *screen)
{
wmWindow *win = CTX_wm_window(C);
- ED_screen_areas_iter(win, screen, area)
- {
- for (ARegion *region = area->regionbase.first; region; region = region->next) {
+ ED_screen_areas_iter (win, screen, area) {
+ LISTBASE_FOREACH (ARegion *, region, &area->regionbase) {
uiBut *but = ui_region_find_active_but(region);
if (but) {
uiHandleButtonData *data = but->active;
diff --git a/source/blender/editors/interface/interface_icons.c b/source/blender/editors/interface/interface_icons.c
index edc5087c8dd..deea3028354 100644
--- a/source/blender/editors/interface/interface_icons.c
+++ b/source/blender/editors/interface/interface_icons.c
@@ -45,10 +45,8 @@
#include "DNA_object_types.h"
#include "DNA_screen_types.h"
#include "DNA_space_types.h"
-#include "DNA_workspace_types.h"
#include "RNA_access.h"
-#include "RNA_enum_types.h"
#include "BKE_appdir.h"
#include "BKE_context.h"
@@ -63,10 +61,6 @@
#include "BIF_glutil.h"
-#include "DEG_depsgraph.h"
-
-#include "DRW_engine.h"
-
#include "ED_datafiles.h"
#include "ED_keyframes_draw.h"
#include "ED_render.h"
@@ -759,11 +753,11 @@ static ImBuf *create_mono_icon_with_border(ImBuf *buf,
// blur alpha channel
const int write_offset = by * (ICON_GRID_W + 2 * ICON_MONO_BORDER_OUTSET) + bx;
float alpha_accum = 0.0;
- unsigned int alpha_samples = 0;
+ uint alpha_samples = 0;
for (int ax = asx; ax < aex; ax++) {
for (int ay = asy; ay < aey; ay++) {
const int offset_read = (sy + ay) * buf->x + (sx + ax);
- unsigned int color_read = buf->rect[offset_read];
+ uint color_read = buf->rect[offset_read];
const float alpha_read = ((color_read & 0xff000000) >> 24) / 255.0;
alpha_accum += alpha_read;
alpha_samples += 1;
@@ -782,8 +776,8 @@ static ImBuf *create_mono_icon_with_border(ImBuf *buf,
const float border_srgb[4] = {
0, 0, 0, MIN2(1.0, blurred_alpha * border_sharpness) * border_intensity};
- const unsigned int color_read = buf->rect[offset_write];
- const unsigned char *orig_color = (unsigned char *)&color_read;
+ const uint color_read = buf->rect[offset_write];
+ const uchar *orig_color = (uchar *)&color_read;
float border_rgba[4];
float orig_rgba[4];
@@ -795,8 +789,8 @@ static ImBuf *create_mono_icon_with_border(ImBuf *buf,
blend_color_interpolate_float(dest_rgba, orig_rgba, border_rgba, 1.0 - orig_rgba[3]);
linearrgb_to_srgb_v4(dest_srgb, dest_rgba);
- unsigned int alpha_mask = ((unsigned int)(dest_srgb[3] * 255)) << 24;
- unsigned int cpack = rgb_to_cpack(dest_srgb[0], dest_srgb[1], dest_srgb[2]) | alpha_mask;
+ uint alpha_mask = ((uint)(dest_srgb[3] * 255)) << 24;
+ uint cpack = rgb_to_cpack(dest_srgb[0], dest_srgb[1], dest_srgb[2]) | alpha_mask;
result->rect[offset_write] = cpack;
}
}
@@ -1129,8 +1123,8 @@ void UI_icons_free(void)
#ifndef WITH_HEADLESS
free_icons_textures();
free_iconfile_list(&iconfilelist);
- BKE_icons_free();
#endif
+ BKE_icons_free();
}
void UI_icons_free_drawinfo(void *drawinfo)
@@ -1609,8 +1603,8 @@ static void icon_draw_cache_texture_flush_ex(GLuint texture,
GPUShader *shader = GPU_shader_get_builtin_shader(GPU_SHADER_2D_IMAGE_MULTI_RECT_COLOR);
GPU_shader_bind(shader);
- int img_loc = GPU_shader_get_uniform_ensure(shader, "image");
- int data_loc = GPU_shader_get_uniform_ensure(shader, "calls_data[0]");
+ int img_loc = GPU_shader_get_uniform(shader, "image");
+ int data_loc = GPU_shader_get_uniform(shader, "calls_data");
glUniform1i(img_loc, 0);
glUniform4fv(data_loc, ICON_DRAW_CACHE_SIZE * 3, (float *)texture_draw_calls->drawcall_cache);
@@ -1756,9 +1750,9 @@ static void icon_draw_texture(float x,
GPU_shader_get_builtin_uniform(shader, GPU_UNIFORM_COLOR), alpha, alpha, alpha, alpha);
}
- glUniform1i(GPU_shader_get_uniform_ensure(shader, "image"), 0);
- glUniform4f(GPU_shader_get_uniform_ensure(shader, "rect_icon"), x1, y1, x2, y2);
- glUniform4f(GPU_shader_get_uniform_ensure(shader, "rect_geom"), x, y, x + w, y + h);
+ glUniform1i(GPU_shader_get_uniform(shader, "image"), 0);
+ glUniform4f(GPU_shader_get_uniform(shader, "rect_icon"), x1, y1, x2, y2);
+ glUniform4f(GPU_shader_get_uniform(shader, "rect_geom"), x, y, x + w, y + h);
GPU_draw_primitive(GPU_PRIM_TRI_STRIP, 4);
@@ -1892,7 +1886,7 @@ static void icon_draw_size(float x,
mul_v4_fl(color, alpha);
float border_outset = 0.0;
- unsigned int border_texel = 0;
+ uint border_texel = 0;
#ifndef WITH_HEADLESS
if (with_border) {
const float scale = (float)ICON_GRID_W / (float)ICON_DEFAULT_WIDTH;
@@ -2015,8 +2009,8 @@ static int ui_id_brush_get_icon(const bContext *C, ID *id)
Object *ob = CTX_data_active_object(C);
const EnumPropertyItem *items = NULL;
ePaintMode paint_mode = PAINT_MODE_INVALID;
- ScrArea *sa = CTX_wm_area(C);
- char space_type = sa->spacetype;
+ ScrArea *area = CTX_wm_area(C);
+ char space_type = area->spacetype;
/* Fallback to 3D view. */
if (space_type == SPACE_PROPERTIES) {
space_type = SPACE_VIEW3D;
@@ -2041,8 +2035,8 @@ static int ui_id_brush_get_icon(const bContext *C, ID *id)
}
}
else if (space_type == SPACE_IMAGE) {
- if (sa->spacetype == space_type) {
- const SpaceImage *sima = sa->spacedata.first;
+ if (area->spacetype == space_type) {
+ const SpaceImage *sima = area->spacedata.first;
if (sima->mode == SI_MODE_PAINT) {
paint_mode = PAINT_MODE_TEXTURE_2D;
}
@@ -2326,6 +2320,9 @@ int UI_idcode_icon_get(const int idcode)
return ICON_WORLD_DATA;
case ID_WS:
return ICON_WORKSPACE;
+ case ID_SIM:
+ /* TODO: Use correct icon. */
+ return ICON_PHYSICS;
default:
return ICON_NONE;
}
diff --git a/source/blender/editors/interface/interface_intern.h b/source/blender/editors/interface/interface_intern.h
index d22338e94fc..2f2297fc8bc 100644
--- a/source/blender/editors/interface/interface_intern.h
+++ b/source/blender/editors/interface/interface_intern.h
@@ -25,6 +25,8 @@
#define __INTERFACE_INTERN_H__
#include "BLI_compiler_attrs.h"
+#include "BLI_rect.h"
+
#include "DNA_listBase.h"
#include "RNA_types.h"
#include "UI_interface.h"
@@ -39,6 +41,7 @@ struct bContextStore;
struct uiHandleButtonData;
struct uiLayout;
struct uiStyle;
+struct uiUndoStack_Text;
struct uiWidgetColors;
struct wmEvent;
struct wmKeyConfig;
@@ -102,7 +105,6 @@ extern const char ui_radial_dir_to_numpad[8];
extern const short ui_radial_dir_to_angle[8];
/* internal panel drawing defines */
-#define PNL_GRID (UI_UNIT_Y / 5) /* 4 default */
#define PNL_HEADER (UI_UNIT_Y * 1.2) /* 24 default */
/* bit button defines */
@@ -145,6 +147,17 @@ enum {
/* max amount of items a radial menu (pie menu) can contain */
#define PIE_MAX_ITEMS 8
+struct uiButSearchData {
+ uiButSearchCreateFn create_fn;
+ uiButSearchUpdateFn update_fn;
+ void *arg;
+ uiButSearchArgFreeFn arg_free_fn;
+ uiButSearchContextMenuFn context_menu_fn;
+ uiButSearchTooltipFn tooltip_fn;
+
+ const char *sep_string;
+};
+
struct uiBut {
struct uiBut *next, *prev;
int flag, drawflag;
@@ -201,10 +214,7 @@ struct uiBut {
uiButCompleteFunc autocomplete_func;
void *autofunc_arg;
- uiButSearchCreateFunc search_create_func;
- uiButSearchFunc search_func;
- void *search_arg;
- uiButSearchArgFreeFunc search_arg_free_func;
+ struct uiButSearchData *search;
uiButHandleRenameFunc rename_func;
void *rename_arg1;
@@ -344,7 +354,7 @@ struct uiBlock {
uiBlock *next, *prev;
ListBase buttons;
- Panel *panel;
+ struct Panel *panel;
uiBlock *oldblock;
ListBase butstore; /* UI_butstore_* runtime function */
@@ -476,8 +486,10 @@ extern void ui_window_to_block_rctf(const struct ARegion *region,
uiBlock *block,
rctf *rct_dst,
const rctf *rct_src);
-extern void ui_window_to_region(const ARegion *region, int *x, int *y);
-extern void ui_window_to_region_rcti(const ARegion *region, rcti *rect_dst, const rcti *rct_src);
+extern void ui_window_to_region(const struct ARegion *region, int *x, int *y);
+extern void ui_window_to_region_rcti(const struct ARegion *region,
+ rcti *rect_dst,
+ const rcti *rct_src);
extern void ui_region_to_window(const struct ARegion *region, int *x, int *y);
extern void ui_region_winrct_get_no_margin(const struct ARegion *region, struct rcti *r_rect);
@@ -565,7 +577,7 @@ struct uiPopupBlockCreate {
int event_xy[2];
/* when popup is initialized from a button */
- ARegion *butregion;
+ struct ARegion *butregion;
uiBut *but;
};
@@ -596,10 +608,8 @@ struct uiPopupBlockHandle {
/* for operator popups */
struct wmOperator *popup_op;
- struct wmOperatorType *optype;
- ScrArea *ctx_area;
- ARegion *ctx_region;
- int opcontext;
+ struct ScrArea *ctx_area;
+ struct ARegion *ctx_region;
/* return values */
int butretval;
@@ -647,17 +657,24 @@ ColorPicker *ui_block_colorpicker_create(struct uiBlock *block);
/* interface_region_search.c */
/* Searchbox for string button */
-ARegion *ui_searchbox_create_generic(struct bContext *C, struct ARegion *butregion, uiBut *but);
-ARegion *ui_searchbox_create_operator(struct bContext *C, struct ARegion *butregion, uiBut *but);
-ARegion *ui_searchbox_create_menu(struct bContext *C, struct ARegion *butregion, uiBut *but);
+struct ARegion *ui_searchbox_create_generic(struct bContext *C,
+ struct ARegion *butregion,
+ uiBut *but);
+struct ARegion *ui_searchbox_create_operator(struct bContext *C,
+ struct ARegion *butregion,
+ uiBut *but);
+struct ARegion *ui_searchbox_create_menu(struct bContext *C,
+ struct ARegion *butregion,
+ uiBut *but);
bool ui_searchbox_inside(struct ARegion *region, int x, int y);
int ui_searchbox_find_index(struct ARegion *region, const char *name);
void ui_searchbox_update(struct bContext *C, struct ARegion *region, uiBut *but, const bool reset);
int ui_searchbox_autocomplete(struct bContext *C, struct ARegion *region, uiBut *but, char *str);
-void ui_searchbox_event(struct bContext *C,
+bool ui_searchbox_event(struct bContext *C,
struct ARegion *region,
uiBut *but,
+ struct ARegion *butregion,
const struct wmEvent *event);
bool ui_searchbox_apply(uiBut *but, struct ARegion *region);
void ui_searchbox_free(struct bContext *C, struct ARegion *region);
@@ -671,7 +688,7 @@ void ui_popup_menu_memory_set(uiBlock *block, struct uiBut *but);
uiBlock *ui_popup_block_refresh(struct bContext *C,
uiPopupBlockHandle *handle,
- ARegion *butregion,
+ struct ARegion *butregion,
uiBut *but);
uiPopupBlockHandle *ui_popup_block_create(struct bContext *C,
@@ -698,7 +715,7 @@ uiPopupBlockHandle *ui_popover_panel_create(struct bContext *C,
void ui_pie_menu_level_create(uiBlock *block,
struct wmOperatorType *ot,
const char *propname,
- IDProperty *properties,
+ struct IDProperty *properties,
const EnumPropertyItem *items,
int totitem,
int context,
@@ -732,37 +749,47 @@ void ui_draw_but_TAB_outline(const rcti *rect,
float rad,
uchar highlight[3],
uchar highlight_fade[3]);
-void ui_draw_but_HISTOGRAM(ARegion *region,
+void ui_draw_but_HISTOGRAM(struct ARegion *region,
uiBut *but,
const struct uiWidgetColors *wcol,
const rcti *rect);
-void ui_draw_but_WAVEFORM(ARegion *region,
+void ui_draw_but_WAVEFORM(struct ARegion *region,
uiBut *but,
const struct uiWidgetColors *wcol,
const rcti *rect);
-void ui_draw_but_VECTORSCOPE(ARegion *region,
+void ui_draw_but_VECTORSCOPE(struct ARegion *region,
uiBut *but,
const struct uiWidgetColors *wcol,
const rcti *rect);
void ui_draw_but_COLORBAND(uiBut *but, const struct uiWidgetColors *wcol, const rcti *rect);
void ui_draw_but_UNITVEC(uiBut *but, const struct uiWidgetColors *wcol, const rcti *rect);
-void ui_draw_but_CURVE(ARegion *region,
+void ui_draw_but_CURVE(struct ARegion *region,
uiBut *but,
const struct uiWidgetColors *wcol,
const rcti *rect);
-void ui_draw_but_CURVEPROFILE(ARegion *region,
+void ui_draw_but_CURVEPROFILE(struct ARegion *region,
uiBut *but,
const struct uiWidgetColors *wcol,
const rcti *rect);
-void ui_draw_but_IMAGE(ARegion *region,
+void ui_draw_but_IMAGE(struct ARegion *region,
uiBut *but,
const struct uiWidgetColors *wcol,
const rcti *rect);
-void ui_draw_but_TRACKPREVIEW(ARegion *region,
+void ui_draw_but_TRACKPREVIEW(struct ARegion *region,
uiBut *but,
const struct uiWidgetColors *wcol,
const rcti *rect);
+/* interface_undo.c */
+struct uiUndoStack_Text *ui_textedit_undo_stack_create(void);
+void ui_textedit_undo_stack_destroy(struct uiUndoStack_Text *undo_stack);
+void ui_textedit_undo_push(struct uiUndoStack_Text *undo_stack,
+ const char *text,
+ int cursor_index);
+const char *ui_textedit_undo(struct uiUndoStack_Text *undo_stack,
+ int direction,
+ int *r_cursor_index);
+
/* interface_handlers.c */
PointerRNA *ui_handle_afterfunc_add_operator(struct wmOperatorType *ot,
int opcontext,
@@ -790,6 +817,11 @@ void ui_but_set_text(struct bContext *C, uiBut *but, char *text);
void ui_but_add_shortcut(uiBut *but, const char *key_str, const bool do_strip);
void ui_but_clipboard_free(void);
+bool ui_but_rna_equals(const uiBut *a, const uiBut *b);
+bool ui_but_rna_equals_ex(const uiBut *but,
+ const PointerRNA *ptr,
+ const PropertyRNA *prop,
+ int index);
uiBut *ui_but_find_old(uiBlock *block_old, const uiBut *but_new);
uiBut *ui_but_find_new(uiBlock *block_old, const uiBut *but_new);
@@ -836,7 +868,11 @@ struct GPUBatch *ui_batch_roundbox_shadow_get(void);
void ui_draw_anti_tria_rect(const rctf *rect, char dir, const float color[4]);
void ui_draw_menu_back(struct uiStyle *style, uiBlock *block, rcti *rect);
-void ui_draw_popover_back(ARegion *region, struct uiStyle *style, uiBlock *block, rcti *rect);
+void ui_draw_box_opaque(rcti *rect, int roundboxalign);
+void ui_draw_popover_back(struct ARegion *region,
+ struct uiStyle *style,
+ uiBlock *block,
+ rcti *rect);
void ui_draw_pie_center(uiBlock *block);
const struct uiWidgetColors *ui_tooltip_get_theme(void);
@@ -844,15 +880,19 @@ void ui_draw_widget_menu_back_color(const rcti *rect, bool use_shadow, const flo
void ui_draw_widget_menu_back(const rcti *rect, bool use_shadow);
void ui_draw_tooltip_background(const struct uiStyle *UNUSED(style), uiBlock *block, rcti *rect);
-extern void ui_draw_but(
- const struct bContext *C, ARegion *region, struct uiStyle *style, uiBut *but, rcti *rect);
+extern void ui_draw_but(const struct bContext *C,
+ struct ARegion *region,
+ struct uiStyle *style,
+ uiBut *but,
+ rcti *rect);
void ui_draw_menu_item(const struct uiFontStyle *fstyle,
rcti *rect,
const char *name,
int iconid,
int state,
- bool use_sep);
+ bool use_sep,
+ int *r_xmax);
void ui_draw_preview_item(
const struct uiFontStyle *fstyle, rcti *rect, const char *name, int iconid, int state);
@@ -894,8 +934,8 @@ void ui_item_paneltype_func(struct bContext *C, struct uiLayout *layout, void *a
/* interface_align.c */
bool ui_but_can_align(const uiBut *but) ATTR_WARN_UNUSED_RESULT;
-int ui_but_align_opposite_to_area_align_get(const ARegion *region) ATTR_WARN_UNUSED_RESULT;
-void ui_block_align_calc(uiBlock *block, const ARegion *region);
+int ui_but_align_opposite_to_area_align_get(const struct ARegion *region) ATTR_WARN_UNUSED_RESULT;
+void ui_block_align_calc(uiBlock *block, const struct ARegion *region);
/* interface_anim.c */
void ui_but_anim_flag(uiBut *but, float cfra);
@@ -916,6 +956,7 @@ bool ui_but_is_toggle(const uiBut *but) ATTR_WARN_UNUSED_RESULT;
bool ui_but_is_interactive(const uiBut *but, const bool labeledit) ATTR_WARN_UNUSED_RESULT;
bool ui_but_is_popover_once_compat(const uiBut *but) ATTR_WARN_UNUSED_RESULT;
bool ui_but_has_array_value(const uiBut *but) ATTR_WARN_UNUSED_RESULT;
+int ui_but_icon(const uiBut *but);
void ui_but_pie_dir(RadialDirection dir, float vec[2]);
bool ui_but_is_cursor_warp(const uiBut *but) ATTR_WARN_UNUSED_RESULT;
@@ -971,12 +1012,15 @@ bool ui_region_contains_point_px(const struct ARegion *region,
int y) ATTR_WARN_UNUSED_RESULT;
bool ui_region_contains_rect_px(const struct ARegion *region, const rcti *rect_px);
-ARegion *ui_screen_region_find_mouse_over_ex(bScreen *screen, int x, int y);
-ARegion *ui_screen_region_find_mouse_over(bScreen *screen, const struct wmEvent *event);
+struct ARegion *ui_screen_region_find_mouse_over_ex(struct bScreen *screen, int x, int y);
+struct ARegion *ui_screen_region_find_mouse_over(struct bScreen *screen,
+ const struct wmEvent *event);
/* interface_context_menu.c */
bool ui_popup_context_menu_for_button(struct bContext *C, uiBut *but);
-void ui_popup_context_menu_for_panel(struct bContext *C, struct ARegion *region, struct Panel *pa);
+void ui_popup_context_menu_for_panel(struct bContext *C,
+ struct ARegion *region,
+ struct Panel *panel);
/* interface_eyedropper.c */
struct wmKeyMap *eyedropper_modal_keymap(struct wmKeyConfig *keyconf);
@@ -1002,9 +1046,10 @@ void UI_OT_eyedropper_driver(struct wmOperatorType *ot);
void UI_OT_eyedropper_gpencil_color(struct wmOperatorType *ot);
/* interface_util.c */
+bool ui_str_has_word_prefix(const char *haystack, const char *needle, size_t needle_len);
/**
- * For use with #ui_rna_collection_search_cb.
+ * For use with #ui_rna_collection_search_update_fn.
*/
typedef struct uiRNACollectionSearch {
PointerRNA target_ptr;
@@ -1013,12 +1058,16 @@ typedef struct uiRNACollectionSearch {
PointerRNA search_ptr;
PropertyRNA *search_prop;
- bool *but_changed; /* pointer to uiBut.changed */
+ uiBut *search_but;
+ /* Let UI_butstore_ API update search_but pointer above over redraws. */
+ uiButStore *butstore;
+ /* Block has to be stored for freeing butstore (uiBut.block doesn't work with undo). */
+ uiBlock *butstore_block;
} uiRNACollectionSearch;
-void ui_rna_collection_search_cb(const struct bContext *C,
- void *arg,
- const char *str,
- uiSearchItems *items);
+void ui_rna_collection_search_update_fn(const struct bContext *C,
+ void *arg,
+ const char *str,
+ uiSearchItems *items);
/* interface_ops.c */
bool ui_jump_to_target_button_poll(struct bContext *C);
diff --git a/source/blender/editors/interface/interface_layout.c b/source/blender/editors/interface/interface_layout.c
index fed35ccff59..884e43b4026 100644
--- a/source/blender/editors/interface/interface_layout.c
+++ b/source/blender/editors/interface/interface_layout.c
@@ -39,7 +39,7 @@
#include "BLT_translation.h"
-#include "BKE_animsys.h"
+#include "BKE_anim_data.h"
#include "BKE_context.h"
#include "BKE_global.h"
#include "BKE_idprop.h"
@@ -75,7 +75,7 @@
} \
(void)0
-#define UI_ITEM_PROP_SEP_DIVIDE 0.5f
+#define UI_ITEM_PROP_SEP_DIVIDE 0.4f
/* uiLayoutRoot */
@@ -135,10 +135,11 @@ enum {
UI_ITEM_BOX_ITEM = 1 << 2, /* The item is "inside" a box item */
UI_ITEM_PROP_SEP = 1 << 3,
+ UI_ITEM_INSIDE_PROP_SEP = 1 << 4,
/* Show an icon button next to each property (to set keyframes, show status).
* Enabled by default, depends on 'UI_ITEM_PROP_SEP'. */
- UI_ITEM_PROP_DECORATE = 1 << 4,
- UI_ITEM_PROP_DECORATE_NO_PAD = 1 << 5,
+ UI_ITEM_PROP_DECORATE = 1 << 5,
+ UI_ITEM_PROP_DECORATE_NO_PAD = 1 << 6,
};
typedef struct uiButtonItem {
@@ -151,8 +152,11 @@ struct uiLayout {
uiLayoutRoot *root;
bContextStore *context;
+ uiLayout *parent;
ListBase items;
+ char heading[UI_MAX_NAME_STR];
+
/** Sub layout to add child items, if not the layout itself. */
uiLayout *child_items_layout;
@@ -945,19 +949,25 @@ static uiBut *ui_item_with_label(uiLayout *layout,
PropertyType type;
PropertySubType subtype;
int prop_but_width = w_hint;
+#ifdef UI_PROP_DECORATE
+ uiLayout *layout_prop_decorate = NULL;
const bool use_prop_sep = ((layout->item.flag & UI_ITEM_PROP_SEP) != 0);
+#endif
/* Always align item with label since text is already given enough space not to overlap. */
sub = uiLayoutRow(layout, true);
UI_block_layout_set_current(block, sub);
+#ifdef UI_PROP_DECORATE
if (name[0]) {
- int w_label;
-
if (use_prop_sep) {
- w_label = (int)((w_hint * 2) * UI_ITEM_PROP_SEP_DIVIDE);
+ layout_prop_decorate = uiItemL_respect_property_split(layout, name, 0);
}
- else {
+ else
+#endif
+ {
+ int w_label;
+
if (ui_layout_variable_size(layout)) {
/* w_hint is width for label in this case.
* Use a default width for property button(s) */
@@ -967,13 +977,7 @@ static uiBut *ui_item_with_label(uiLayout *layout,
else {
w_label = w_hint / 3;
}
- }
-
- uiBut *but_label = uiDefBut(
- block, UI_BTYPE_LABEL, 0, name, x, y, w_label, h, NULL, 0.0, 0.0, 0, 0, "");
- if (use_prop_sep) {
- but_label->drawflag |= UI_BUT_TEXT_RIGHT;
- but_label->drawflag &= ~UI_BUT_TEXT_LEFT;
+ uiDefBut(block, UI_BTYPE_LABEL, 0, name, x, y, w_label, h, NULL, 0.0, 0.0, 0, 0, "");
}
}
@@ -1053,7 +1057,7 @@ static uiBut *ui_item_with_label(uiLayout *layout,
if (layout->item.flag & UI_ITEM_PROP_SEP) {
if ((layout->item.flag & UI_ITEM_PROP_DECORATE) &&
(layout->item.flag & UI_ITEM_PROP_DECORATE_NO_PAD) == 0) {
- uiItemL(sub, NULL, ICON_BLANK1);
+ uiItemL(layout_prop_decorate ? layout_prop_decorate : sub, NULL, ICON_BLANK1);
}
}
#endif /* UI_PROP_DECORATE */
@@ -1780,6 +1784,7 @@ static void ui_item_rna_size(uiLayout *layout,
PropertyType type;
PropertySubType subtype;
int len, w = 0, h;
+ bool is_checkbox_only = false;
/* arbitrary extended width by type */
type = RNA_property_type(prop);
@@ -1791,6 +1796,10 @@ static void ui_item_rna_size(uiLayout *layout,
name = "non-empty text";
}
else if (type == PROP_BOOLEAN) {
+ if (icon == ICON_NONE) {
+ /* Exception for checkboxes, they need a little less space to align nicely. */
+ is_checkbox_only = true;
+ }
icon = ICON_DOT;
}
else if (type == PROP_ENUM) {
@@ -1850,6 +1859,9 @@ static void ui_item_rna_size(uiLayout *layout,
if (type == PROP_BOOLEAN && name[0]) {
w += UI_UNIT_X / 5;
}
+ else if (is_checkbox_only) {
+ w -= UI_UNIT_X / 4;
+ }
else if (type == PROP_ENUM && !icon_only) {
w += UI_UNIT_X / 4;
}
@@ -1862,6 +1874,78 @@ static void ui_item_rna_size(uiLayout *layout,
*r_h = h;
}
+static bool ui_item_rna_is_expand(PropertyRNA *prop, int index, int item_flag)
+{
+ const bool is_array = RNA_property_array_check(prop);
+ const int subtype = RNA_property_subtype(prop);
+ return is_array && (index == RNA_NO_INDEX) &&
+ ((item_flag & UI_ITEM_R_EXPAND) ||
+ !ELEM(subtype, PROP_COLOR, PROP_COLOR_GAMMA, PROP_DIRECTION));
+}
+
+/**
+ * Find first layout ancestor (or self) with a heading set.
+ *
+ * \returns the layout to add the heading to as fallback (i.e. if it can't be placed in a split
+ * layout). Its #uiLayout.heading member can be cleared to mark the heading as added (so
+ * it's not added multiple times). Returns a pointer to the heading
+ */
+static uiLayout *ui_layout_heading_find(uiLayout *cur_layout)
+{
+ for (uiLayout *parent = cur_layout; parent; parent = parent->parent) {
+ if (parent->heading[0]) {
+ return parent;
+ }
+ }
+
+ return NULL;
+}
+
+static void ui_layout_heading_label_add(uiLayout *layout,
+ uiLayout *heading_layout,
+ bool right_align,
+ bool respect_prop_split)
+{
+ const int prev_alignment = layout->alignment;
+
+ if (right_align) {
+ uiLayoutSetAlignment(layout, UI_LAYOUT_ALIGN_RIGHT);
+ }
+
+ if (respect_prop_split) {
+ uiItemL_respect_property_split(layout, heading_layout->heading, ICON_NONE);
+ }
+ else {
+ uiItemL(layout, heading_layout->heading, ICON_NONE);
+ }
+ /* After adding the heading label, we have to mark it somehow as added, so it's not added again
+ * for other items in this layout. For now just clear it. */
+ heading_layout->heading[0] = '\0';
+
+ layout->alignment = prev_alignment;
+}
+
+/**
+ * Hack to add further items in a row into the second part of the split layout, so the label part
+ * keeps a fixed size.
+ * \return The layout to place further items in for the split layout.
+ */
+static uiLayout *ui_item_prop_split_layout_hack(uiLayout *layout_parent, uiLayout *layout_split)
+{
+ /* Tag item as using property split layout, this is inherited to children so they can get special
+ * treatment if needed. */
+ layout_parent->item.flag |= UI_ITEM_INSIDE_PROP_SEP;
+
+ if (layout_parent->item.type == ITEM_LAYOUT_ROW) {
+ /* Prevent further splits within the row. */
+ uiLayoutSetPropSep(layout_parent, false);
+
+ layout_parent->child_items_layout = uiLayoutRow(layout_split, true);
+ return layout_parent->child_items_layout;
+ }
+ return layout_split;
+}
+
void uiItemFullR(uiLayout *layout,
PointerRNA *ptr,
PropertyRNA *prop,
@@ -1874,13 +1958,18 @@ void uiItemFullR(uiLayout *layout,
uiBlock *block = layout->root->block;
char namestr[UI_MAX_NAME_STR];
const bool use_prop_sep = ((layout->item.flag & UI_ITEM_PROP_SEP) != 0);
-
- /* By default 'use_prop_sep' uses a separate column for labels.
- * This is an exception for check-boxes otherwise only the small checkbox region is clickable.
+ const bool inside_prop_sep = ((layout->item.flag & UI_ITEM_INSIDE_PROP_SEP) != 0);
+ /* Columns can define a heading to insert. If the first item added to a split layout doesn't have
+ * a label to display in the first column, the heading is inserted there. Otherwise it's inserted
+ * as a new row before the first item. */
+ uiLayout *heading_layout = ui_layout_heading_find(layout);
+ /* Although checkboxes use the split layout, they are an exception and should only place their
+ * label in the second column, to not make that almost empty.
*
* Keep using 'use_prop_sep' instead of disabling it entirely because
* we need the ability to have decorators still. */
bool use_prop_sep_split_label = use_prop_sep;
+ bool use_split_empty_name = (flag & UI_ITEM_R_SPLIT_EMPTY_NAME);
#ifdef UI_PROP_DECORATE
struct {
@@ -1991,6 +2080,9 @@ void uiItemFullR(uiLayout *layout,
if (use_prop_sep) {
if (type == PROP_BOOLEAN && (icon == ICON_NONE) && !icon_only) {
use_prop_sep_split_label = false;
+ /* For check-boxes we make an exception: We allow showing them in a split row even without
+ * label. It typically relates to its neighbor items, so no need for an extra label. */
+ use_split_empty_name = true;
}
}
#endif
@@ -2017,6 +2109,7 @@ void uiItemFullR(uiLayout *layout,
/* Split the label / property. */
uiLayout *layout_parent = layout;
+
if (use_prop_sep) {
uiLayout *layout_row = NULL;
#ifdef UI_PROP_DECORATE
@@ -2027,21 +2120,26 @@ void uiItemFullR(uiLayout *layout,
}
#endif /* UI_PROP_DECORATE */
- if ((name[0] == '\0') || (use_prop_sep_split_label == false)) {
+ if ((name[0] == '\0') && !use_split_empty_name) {
/* Ensure we get a column when text is not set. */
layout = uiLayoutColumn(layout_row ? layout_row : layout, true);
layout->space = 0;
+ if (heading_layout) {
+ ui_layout_heading_label_add(layout, heading_layout, false, false);
+ }
}
else {
- const PropertySubType subtype = RNA_property_subtype(prop);
uiLayout *layout_split = uiLayoutSplit(
layout_row ? layout_row : layout, UI_ITEM_PROP_SEP_DIVIDE, true);
+ bool label_added = false;
layout_split->space = 0;
uiLayout *layout_sub = uiLayoutColumn(layout_split, true);
layout_sub->space = 0;
- if ((index == RNA_NO_INDEX && is_array) &&
- ((!expand && ELEM(subtype, PROP_COLOR, PROP_COLOR_GAMMA, PROP_DIRECTION)) == 0)) {
+ if (!use_prop_sep_split_label) {
+ /* Pass */
+ }
+ else if (ui_item_rna_is_expand(prop, index, flag)) {
char name_with_suffix[UI_MAX_DRAW_STR + 2];
char str[2] = {'\0'};
for (int a = 0; a < len; a++) {
@@ -2070,6 +2168,8 @@ void uiItemFullR(uiLayout *layout,
"");
but->drawflag |= UI_BUT_TEXT_RIGHT;
but->drawflag &= ~UI_BUT_TEXT_LEFT;
+
+ label_added = true;
}
}
else {
@@ -2078,16 +2178,17 @@ void uiItemFullR(uiLayout *layout,
block, UI_BTYPE_LABEL, 0, name, 0, 0, w, UI_UNIT_Y, NULL, 0.0, 0.0, 0, 0, "");
but->drawflag |= UI_BUT_TEXT_RIGHT;
but->drawflag &= ~UI_BUT_TEXT_LEFT;
+
+ label_added = true;
}
}
- /* Hack to add further items in a row into the second part of
- * the split layout, so the label part keeps a fixed size. */
- if (layout_parent && layout_parent->item.type == ITEM_LAYOUT_ROW) {
- layout_split = uiLayoutRow(layout_split, true);
- layout_parent->child_items_layout = layout_split;
+ if (!label_added && heading_layout) {
+ ui_layout_heading_label_add(layout_sub, heading_layout, true, false);
}
+ layout_split = ui_item_prop_split_layout_hack(layout_parent, layout_split);
+
/* Watch out! We can only write into the new layout now. */
if ((type == PROP_ENUM) && (flag & UI_ITEM_R_EXPAND)) {
/* Expanded enums each have their own name. */
@@ -2102,7 +2203,9 @@ void uiItemFullR(uiLayout *layout,
}
}
else {
- name = "";
+ if (use_prop_sep_split_label) {
+ name = "";
+ }
layout = uiLayoutColumn(layout_split, true);
}
layout->space = 0;
@@ -2121,9 +2224,20 @@ void uiItemFullR(uiLayout *layout,
#endif /* UI_PROP_DECORATE */
}
/* End split. */
+ else if (heading_layout) {
+ /* Could not add heading to split layout, fallback to inserting it to the layout with the
+ * heading itself. */
+ ui_layout_heading_label_add(heading_layout, heading_layout, false, false);
+ }
/* array property */
if (index == RNA_NO_INDEX && is_array) {
+ if (inside_prop_sep) {
+ /* Within a split row, add array items to a column so they match the column layout of
+ * previous items (e.g. transform vector with lock icon for each item). */
+ layout = uiLayoutColumn(layout, true);
+ }
+
ui_item_array(layout,
block,
name,
@@ -2203,12 +2317,6 @@ void uiItemFullR(uiLayout *layout,
if (layout->activate_init) {
UI_but_flag_enable(but, UI_BUT_ACTIVATE_ON_INIT);
}
-
- if (use_prop_sep && (use_prop_sep_split_label == false)) {
- /* When the button uses it's own text right align it. */
- but->drawflag |= UI_BUT_TEXT_RIGHT;
- but->drawflag &= ~UI_BUT_TEXT_LEFT;
- }
}
/* The resulting button may have the icon set since boolean button drawing
@@ -2231,50 +2339,21 @@ void uiItemFullR(uiLayout *layout,
#ifdef UI_PROP_DECORATE
if (ui_decorate.use_prop_decorate) {
- const bool is_anim = RNA_property_animateable(ptr, prop);
uiBut *but_decorate = ui_decorate.but ? ui_decorate.but->next : block->buttons.first;
+ const bool use_blank_decorator = (flag & UI_ITEM_R_FORCE_BLANK_DECORATE);
uiLayout *layout_col = uiLayoutColumn(ui_decorate.layout, false);
layout_col->space = 0;
layout_col->emboss = UI_EMBOSS_NONE;
+
int i;
for (i = 0; i < ui_decorate.len && but_decorate; i++) {
+ PointerRNA *ptr_dec = use_blank_decorator ? NULL : &but_decorate->rnapoin;
+ PropertyRNA *prop_dec = use_blank_decorator ? NULL : but_decorate->rnaprop;
+
/* The icons are set in 'ui_but_anim_flag' */
- if (is_anim) {
- but = uiDefIconBut(block,
- UI_BTYPE_BUT,
- 0,
- ICON_DOT,
- 0,
- 0,
- UI_UNIT_X,
- UI_UNIT_Y,
- NULL,
- 0.0,
- 0.0,
- 0.0,
- 0.0,
- TIP_("Animate property"));
- UI_but_func_set(but, ui_but_anim_decorate_cb, but, NULL);
- but->flag |= UI_BUT_UNDO | UI_BUT_DRAG_LOCK;
- }
- else {
- /* We may show other information here in future, for now use empty space. */
- but = uiDefIconBut(block,
- UI_BTYPE_BUT,
- 0,
- ICON_BLANK1,
- 0,
- 0,
- UI_UNIT_X,
- UI_UNIT_Y,
- NULL,
- 0.0,
- 0.0,
- 0.0,
- 0.0,
- "");
- but->flag |= UI_BUT_DISABLED;
- }
+ uiItemDecoratorR_prop(layout_col, ptr_dec, prop_dec, but_decorate->rnaindex);
+ but = block->buttons.last;
+
/* Order the decorator after the button we decorate, this is used so we can always
* do a quick lookup. */
BLI_remlink(&block->buttons, but);
@@ -2566,6 +2645,13 @@ static void search_id_collection(StructRNA *ptype, PointerRNA *r_ptr, PropertyRN
RNA_STRUCT_END;
}
+static void ui_rna_collection_search_arg_free_fn(void *ptr)
+{
+ uiRNACollectionSearch *coll_search = ptr;
+ UI_butstore_free(coll_search->butstore_block, coll_search->butstore);
+ MEM_freeN(ptr);
+}
+
void ui_but_add_search(
uiBut *but, PointerRNA *ptr, PropertyRNA *prop, PointerRNA *searchptr, PropertyRNA *searchprop)
{
@@ -2598,7 +2684,10 @@ void ui_but_add_search(
coll_search->target_prop = prop;
coll_search->search_ptr = *searchptr;
coll_search->search_prop = searchprop;
- coll_search->but_changed = &but->changed;
+ coll_search->search_but = but;
+ coll_search->butstore_block = but->block;
+ coll_search->butstore = UI_butstore_create(coll_search->butstore_block);
+ UI_butstore_register(coll_search->butstore, &coll_search->search_but);
if (RNA_property_type(prop) == PROP_ENUM) {
/* XXX, this will have a menu string,
@@ -2608,9 +2697,9 @@ void ui_but_add_search(
UI_but_func_search_set(but,
ui_searchbox_create_generic,
- ui_rna_collection_search_cb,
+ ui_rna_collection_search_update_fn,
coll_search,
- MEM_freeN,
+ ui_rna_collection_search_arg_free_fn,
NULL,
NULL);
}
@@ -2737,6 +2826,7 @@ static uiBut *ui_item_menu(uiLayout *layout,
bool force_menu)
{
uiBlock *block = layout->root->block;
+ uiLayout *heading_layout = ui_layout_heading_find(layout);
uiBut *but;
int w, h;
@@ -2766,12 +2856,16 @@ static uiBut *ui_item_menu(uiLayout *layout,
}
}
+ if (heading_layout) {
+ ui_layout_heading_label_add(layout, heading_layout, true, true);
+ }
+
if (name[0] && icon) {
but = uiDefIconTextMenuBut(block, func, arg, icon, name, 0, 0, w, h, tip);
}
else if (icon) {
but = uiDefIconMenuBut(block, func, arg, icon, 0, 0, w, h, tip);
- if (force_menu) {
+ if (force_menu && name[0]) {
UI_but_drawflag_enable(but, UI_BUT_ICON_LEFT);
}
}
@@ -2839,6 +2933,91 @@ void uiItemMContents(uiLayout *layout, const char *menuname)
UI_menutype_draw(C, mt, layout);
}
+/**
+ * Insert a decorator item for a button with the same property as \a prop.
+ * To force inserting a blank dummy element, NULL can be passed for \a ptr and \a prop.
+ */
+void uiItemDecoratorR_prop(uiLayout *layout, PointerRNA *ptr, PropertyRNA *prop, int index)
+{
+ uiBlock *block = layout->root->block;
+ uiBut *but = NULL;
+
+ uiLayout *col;
+ UI_block_layout_set_current(block, layout);
+ col = uiLayoutColumn(layout, false);
+ col->space = 0;
+ col->emboss = UI_EMBOSS_NONE;
+
+ if (ELEM(NULL, ptr, prop) || !RNA_property_animateable(ptr, prop)) {
+ but = uiDefIconBut(block,
+ UI_BTYPE_BUT,
+ 0,
+ ICON_BLANK1,
+ 0,
+ 0,
+ UI_UNIT_X,
+ UI_UNIT_Y,
+ NULL,
+ 0.0,
+ 0.0,
+ 0.0,
+ 0.0,
+ "");
+ but->flag |= UI_BUT_DISABLED;
+ return;
+ }
+
+ const bool is_expand = ui_item_rna_is_expand(prop, index, 0);
+ const bool is_array = RNA_property_array_check(prop);
+
+ /* Loop for the array-case, but only do in case of an expanded array. */
+ for (int i = 0; i < (is_expand ? RNA_property_array_length(ptr, prop) : 1); i++) {
+ but = uiDefIconBut(block,
+ UI_BTYPE_BUT,
+ 0,
+ ICON_DOT,
+ 0,
+ 0,
+ UI_UNIT_X,
+ UI_UNIT_Y,
+ NULL,
+ 0.0,
+ 0.0,
+ 0.0,
+ 0.0,
+ TIP_("Animate property"));
+ UI_but_func_set(but, ui_but_anim_decorate_cb, but, NULL);
+ but->flag |= UI_BUT_UNDO | UI_BUT_DRAG_LOCK;
+ /* Reusing RNA search members, setting actual RNA data has many side-effects. */
+ but->rnasearchpoin = *ptr;
+ but->rnasearchprop = prop;
+ /* ui_def_but_rna() sets non-array buttons to have a RNA index of 0. */
+ but->custom_data = POINTER_FROM_INT((!is_array || is_expand) ? i : index);
+ }
+}
+
+/**
+ * Insert a decorator item for a button with the same property as \a prop.
+ * To force inserting a blank dummy element, NULL can be passed for \a ptr and \a propname.
+ */
+void uiItemDecoratorR(uiLayout *layout, PointerRNA *ptr, const char *propname, int index)
+{
+ PropertyRNA *prop = NULL;
+
+ if (ptr && propname) {
+ /* validate arguments */
+ prop = RNA_struct_find_property(ptr, propname);
+ if (!prop) {
+ ui_item_disabled(layout, propname);
+ RNA_warning("property not found: %s.%s", RNA_struct_identifier(ptr->type), propname);
+ return;
+ }
+ }
+
+ /* ptr and prop are allowed to be NULL here. */
+ uiItemDecoratorR_prop(layout, ptr, prop, index);
+}
+
/* popover */
void uiItemPopoverPanel_ptr(
uiLayout *layout, bContext *C, PanelType *pt, const char *name, int icon)
@@ -2897,7 +3076,7 @@ void uiItemPopoverPanelFromGroup(uiLayout *layout,
return;
}
- for (PanelType *pt = art->paneltypes.first; pt; pt = pt->next) {
+ LISTBASE_FOREACH (PanelType *, pt, &art->paneltypes) {
/* Causes too many panels, check context. */
if (pt->parent_id[0] == '\0') {
if (/* (*context == '\0') || */ STREQ(pt->context, context)) {
@@ -2982,28 +3161,40 @@ void uiItemL(uiLayout *layout, const char *name, int icon)
}
/**
- * Helper to add a label, which handles logic for split property layout if needed.
- *
- * Normally, we handle the split layout in #uiItemFullR(), but there are other cases where we may
- * want to use the logic. For those this helper was added, although it will likely have to be
- * extended to support more cases.
- * Ideally, #uiItemFullR() could just call this, but it currently has too many special needs.
- *
- * \return the layout to place the item(s) associated to the label in.
+ * Normally, we handle the split layout in #uiItemFullR(), but there are other cases where the
+ * logic is needed. Ideally, #uiItemFullR() could just call this, but it currently has too many
+ * special needs.
+ */
+uiPropertySplitWrapper uiItemPropertySplitWrapperCreate(uiLayout *parent_layout)
+{
+ uiPropertySplitWrapper split_wrapper = {NULL};
+
+ uiLayout *layout_row = uiLayoutRow(parent_layout, true);
+ uiLayout *layout_split = uiLayoutSplit(layout_row, UI_ITEM_PROP_SEP_DIVIDE, true);
+
+ layout_split->space = 0;
+ split_wrapper.label_column = uiLayoutColumn(layout_split, true);
+ split_wrapper.label_column->alignment = UI_LAYOUT_ALIGN_RIGHT;
+ split_wrapper.property_row = ui_item_prop_split_layout_hack(parent_layout, layout_split);
+ split_wrapper.decorate_column = uiLayoutColumn(layout_row, true);
+
+ return split_wrapper;
+}
+
+/*
+ * Helper to add a label and creates a property split layout if needed.
*/
uiLayout *uiItemL_respect_property_split(uiLayout *layout, const char *text, int icon)
{
if (layout->item.flag & UI_ITEM_PROP_SEP) {
- uiLayout *layout_split = uiLayoutSplit(layout, UI_ITEM_PROP_SEP_DIVIDE, true);
- uiLayout *layout_sub = uiLayoutColumn(layout_split, true);
-
- layout_split->space = layout_sub->space = layout->space = 0;
- layout_sub->alignment = UI_LAYOUT_ALIGN_RIGHT;
+ uiBlock *block = uiLayoutGetBlock(layout);
+ uiPropertySplitWrapper split_wrapper = uiItemPropertySplitWrapperCreate(layout);
+ /* Further items added to 'layout' will automatically be added to split_wrapper.property_row */
- uiItemL_(layout_sub, text, icon);
+ uiItemL_(split_wrapper.label_column, text, icon);
+ UI_block_layout_set_current(block, split_wrapper.property_row);
- /* Give caller a new sub-row to place items in. */
- return uiLayoutRow(layout_split, true);
+ return split_wrapper.decorate_column;
}
else {
char namestr[UI_MAX_NAME_STR];
@@ -4444,13 +4635,24 @@ static void ui_litem_init_from_parent(uiLayout *litem, uiLayout *layout, int ali
litem->redalert = layout->redalert;
litem->w = layout->w;
litem->emboss = layout->emboss;
- litem->item.flag = (layout->item.flag & (UI_ITEM_PROP_SEP | UI_ITEM_PROP_DECORATE));
+ litem->item.flag = (layout->item.flag &
+ (UI_ITEM_PROP_SEP | UI_ITEM_PROP_DECORATE | UI_ITEM_INSIDE_PROP_SEP));
if (layout->child_items_layout) {
BLI_addtail(&layout->child_items_layout->items, litem);
+ litem->parent = layout->child_items_layout;
}
else {
BLI_addtail(&layout->items, litem);
+ litem->parent = layout;
+ }
+}
+
+static void ui_layout_heading_set(uiLayout *layout, const char *heading)
+{
+ BLI_assert(layout->heading[0] == '\0');
+ if (heading) {
+ STRNCPY(layout->heading, heading);
}
}
@@ -4470,6 +4672,16 @@ uiLayout *uiLayoutRow(uiLayout *layout, bool align)
return litem;
}
+/**
+ * See #uiLayoutColumnWithHeading().
+ */
+uiLayout *uiLayoutRowWithHeading(uiLayout *layout, bool align, const char *heading)
+{
+ uiLayout *litem = uiLayoutRow(layout, align);
+ ui_layout_heading_set(litem, heading);
+ return litem;
+}
+
uiLayout *uiLayoutColumn(uiLayout *layout, bool align)
{
uiLayout *litem;
@@ -4485,6 +4697,19 @@ uiLayout *uiLayoutColumn(uiLayout *layout, bool align)
return litem;
}
+/**
+ * Variant of #uiLayoutColumn() that sets a heading label for the layout if the first item is
+ * added through #uiItemFullR(). If split layout is used and the item has no string to add to the
+ * first split-column, the heading is added there instead. Otherwise the heading inserted with a
+ * new row.
+ */
+uiLayout *uiLayoutColumnWithHeading(uiLayout *layout, bool align, const char *heading)
+{
+ uiLayout *litem = uiLayoutColumn(layout, align);
+ ui_layout_heading_set(litem, heading);
+ return litem;
+}
+
uiLayout *uiLayoutColumnFlow(uiLayout *layout, int number, bool align)
{
uiLayoutItemFlow *flow;
@@ -5352,7 +5577,7 @@ static void ui_paneltype_draw_impl(bContext *C, PanelType *pt, uiLayout *layout,
MEM_freeN(panel);
/* Draw child panels. */
- for (LinkData *link = pt->children.first; link; link = link->next) {
+ LISTBASE_FOREACH (LinkData *, link, &pt->children) {
PanelType *child_pt = link->data;
if (child_pt->poll == NULL || child_pt->poll(C, child_pt)) {
diff --git a/source/blender/editors/interface/interface_ops.c b/source/blender/editors/interface/interface_ops.c
index 3e3ca307cb3..6dc90bffe59 100644
--- a/source/blender/editors/interface/interface_ops.c
+++ b/source/blender/editors/interface/interface_ops.c
@@ -807,6 +807,9 @@ bool UI_context_copy_to_selected_list(bContext *C,
else if (RNA_struct_is_a(ptr->type, &RNA_FCurve)) {
*r_lb = CTX_data_collection_get(C, "selected_editable_fcurves");
}
+ else if (RNA_struct_is_a(ptr->type, &RNA_NlaStrip)) {
+ *r_lb = CTX_data_collection_get(C, "selected_nla_strips");
+ }
else if (RNA_struct_is_a(ptr->type, &RNA_Constraint) &&
(path_from_bone = RNA_path_resolve_from_type_to_property(ptr, prop, &RNA_PoseBone)) !=
NULL) {
@@ -1132,8 +1135,9 @@ static bool jump_to_target_button(bContext *C, bool poll)
else if (type == PROP_STRING) {
const uiBut *but = UI_context_active_but_get(C);
- if (but->type == UI_BTYPE_SEARCH_MENU && but->search_func == ui_rna_collection_search_cb) {
- uiRNACollectionSearch *coll_search = but->search_arg;
+ if (but->type == UI_BTYPE_SEARCH_MENU && but->search &&
+ but->search->update_fn == ui_rna_collection_search_update_fn) {
+ uiRNACollectionSearch *coll_search = but->search->arg;
char str_buf[MAXBONENAME];
char *str_ptr = RNA_property_string_get_alloc(&ptr, prop, str_buf, sizeof(str_buf), NULL);
@@ -1305,9 +1309,9 @@ static int editsource_text_edit(bContext *C,
else {
/* naughty!, find text area to set, not good behavior
* but since this is a dev tool lets allow it - campbell */
- ScrArea *sa = BKE_screen_find_big_area(CTX_wm_screen(C), SPACE_TEXT, 0);
- if (sa) {
- SpaceText *st = sa->spacedata.first;
+ ScrArea *area = BKE_screen_find_big_area(CTX_wm_screen(C), SPACE_TEXT, 0);
+ if (area) {
+ SpaceText *st = area->spacedata.first;
st->text = text;
}
else {
@@ -1617,13 +1621,14 @@ static void UI_OT_reloadtranslation(wmOperatorType *ot)
static int ui_button_press_invoke(bContext *C, wmOperator *op, const wmEvent *event)
{
- bScreen *sc = CTX_wm_screen(C);
+ bScreen *screen = CTX_wm_screen(C);
const bool skip_depressed = RNA_boolean_get(op->ptr, "skip_depressed");
- ARegion *ar_prev = CTX_wm_region(C);
- ARegion *region = sc ? BKE_screen_find_region_xy(sc, RGN_TYPE_ANY, event->x, event->y) : NULL;
+ ARegion *region_prev = CTX_wm_region(C);
+ ARegion *region = screen ? BKE_screen_find_region_xy(screen, RGN_TYPE_ANY, event->x, event->y) :
+ NULL;
if (region == NULL) {
- region = ar_prev;
+ region = region_prev;
}
if (region == NULL) {
@@ -1632,7 +1637,7 @@ static int ui_button_press_invoke(bContext *C, wmOperator *op, const wmEvent *ev
CTX_wm_region_set(C, region);
uiBut *but = UI_context_active_but_get(C);
- CTX_wm_region_set(C, ar_prev);
+ CTX_wm_region_set(C, region_prev);
if (but == NULL) {
return OPERATOR_PASS_THROUGH;
@@ -1674,7 +1679,7 @@ static void UI_OT_button_execute(wmOperatorType *ot)
static int button_string_clear_exec(bContext *C, wmOperator *UNUSED(op))
{
- uiBut *but = UI_context_active_but_get(C);
+ uiBut *but = UI_context_active_but_get_respect_menu(C);
if (but) {
ui_but_active_string_clear_and_exit(C, but);
diff --git a/source/blender/editors/interface/interface_panel.c b/source/blender/editors/interface/interface_panel.c
index d57b4d444bd..54f60a05cfd 100644
--- a/source/blender/editors/interface/interface_panel.c
+++ b/source/blender/editors/interface/interface_panel.c
@@ -39,6 +39,7 @@
#include "BLT_translation.h"
+#include "DNA_screen_types.h"
#include "DNA_userdef_types.h"
#include "BKE_context.h"
@@ -56,7 +57,9 @@
#include "UI_resources.h"
#include "UI_view2d.h"
+#include "GPU_batch_presets.h"
#include "GPU_immediate.h"
+#include "GPU_matrix.h"
#include "GPU_state.h"
#include "interface_intern.h"
@@ -100,13 +103,20 @@ typedef struct uiHandlePanelData {
double starttime;
/* dragging */
+ bool is_drag_drop;
int startx, starty;
int startofsx, startofsy;
int startsizex, startsizey;
} uiHandlePanelData;
-static int get_panel_real_size_y(const Panel *pa);
-static void panel_activate_state(const bContext *C, Panel *pa, uiHandlePanelState state);
+typedef struct PanelSort {
+ Panel *panel, *orig;
+} PanelSort;
+
+static int get_panel_real_size_y(const Panel *panel);
+static void panel_activate_state(const bContext *C, Panel *panel, uiHandlePanelState state);
+static int compare_panel(const void *a1, const void *a2);
+static bool panel_type_context_poll(PanelType *panel_type, const char *context);
static void panel_title_color_get(bool show_background, uchar color[4])
{
@@ -131,18 +141,18 @@ typedef enum eSpaceButtons_Align {
BUT_AUTO = 2,
} eSpaceButtons_Align;
-static int panel_aligned(const ScrArea *sa, const ARegion *region)
+static int panel_aligned(const ScrArea *area, const ARegion *region)
{
- if (sa->spacetype == SPACE_PROPERTIES && region->regiontype == RGN_TYPE_WINDOW) {
+ if (area->spacetype == SPACE_PROPERTIES && region->regiontype == RGN_TYPE_WINDOW) {
return BUT_VERTICAL;
}
- else if (sa->spacetype == SPACE_USERPREF && region->regiontype == RGN_TYPE_WINDOW) {
+ else if (area->spacetype == SPACE_USERPREF && region->regiontype == RGN_TYPE_WINDOW) {
return BUT_VERTICAL;
}
- else if (sa->spacetype == SPACE_FILE && region->regiontype == RGN_TYPE_CHANNELS) {
+ else if (area->spacetype == SPACE_FILE && region->regiontype == RGN_TYPE_CHANNELS) {
return BUT_VERTICAL;
}
- else if (sa->spacetype == SPACE_IMAGE && region->regiontype == RGN_TYPE_PREVIEW) {
+ else if (area->spacetype == SPACE_IMAGE && region->regiontype == RGN_TYPE_PREVIEW) {
return BUT_VERTICAL;
}
else if (ELEM(region->regiontype,
@@ -160,71 +170,71 @@ static int panel_aligned(const ScrArea *sa, const ARegion *region)
static bool panel_active_animation_changed(ListBase *lb, Panel **pa_animation, bool *no_animation)
{
- for (Panel *pa = lb->first; pa; pa = pa->next) {
+ LISTBASE_FOREACH (Panel *, panel, lb) {
/* Detect panel active flag changes. */
- if (!(pa->type && pa->type->parent)) {
- if ((pa->runtime_flag & PNL_WAS_ACTIVE) && !(pa->runtime_flag & PNL_ACTIVE)) {
+ if (!(panel->type && panel->type->parent)) {
+ if ((panel->runtime_flag & PNL_WAS_ACTIVE) && !(panel->runtime_flag & PNL_ACTIVE)) {
return true;
}
- if (!(pa->runtime_flag & PNL_WAS_ACTIVE) && (pa->runtime_flag & PNL_ACTIVE)) {
+ if (!(panel->runtime_flag & PNL_WAS_ACTIVE) && (panel->runtime_flag & PNL_ACTIVE)) {
return true;
}
}
- if ((pa->runtime_flag & PNL_ACTIVE) && !(pa->flag & PNL_CLOSED)) {
- if (panel_active_animation_changed(&pa->children, pa_animation, no_animation)) {
+ if ((panel->runtime_flag & PNL_ACTIVE) && !(panel->flag & PNL_CLOSED)) {
+ if (panel_active_animation_changed(&panel->children, pa_animation, no_animation)) {
return true;
}
}
/* Detect animation. */
- if (pa->activedata) {
- uiHandlePanelData *data = pa->activedata;
+ if (panel->activedata) {
+ uiHandlePanelData *data = panel->activedata;
if (data->state == PANEL_STATE_ANIMATION) {
- *pa_animation = pa;
+ *pa_animation = panel;
}
else {
/* Don't animate while handling other interaction. */
*no_animation = true;
}
}
- if ((pa->runtime_flag & PNL_ANIM_ALIGN) && !(*pa_animation)) {
- *pa_animation = pa;
+ if ((panel->runtime_flag & PNL_ANIM_ALIGN) && !(*pa_animation)) {
+ *pa_animation = panel;
}
}
return false;
}
-static bool panels_need_realign(ScrArea *sa, ARegion *region, Panel **r_pa_animate)
+static bool panels_need_realign(ScrArea *area, ARegion *region, Panel **r_panel_animation)
{
- *r_pa_animate = NULL;
+ *r_panel_animation = NULL;
- if (sa->spacetype == SPACE_PROPERTIES && region->regiontype == RGN_TYPE_WINDOW) {
- SpaceProperties *sbuts = sa->spacedata.first;
+ if (area->spacetype == SPACE_PROPERTIES && region->regiontype == RGN_TYPE_WINDOW) {
+ SpaceProperties *sbuts = area->spacedata.first;
if (sbuts->mainbo != sbuts->mainb) {
return true;
}
}
- else if (sa->spacetype == SPACE_IMAGE && region->regiontype == RGN_TYPE_PREVIEW) {
+ else if (area->spacetype == SPACE_IMAGE && region->regiontype == RGN_TYPE_PREVIEW) {
return true;
}
- else if (sa->spacetype == SPACE_FILE && region->regiontype == RGN_TYPE_CHANNELS) {
+ else if (area->spacetype == SPACE_FILE && region->regiontype == RGN_TYPE_CHANNELS) {
return true;
}
/* Detect if a panel was added or removed. */
- Panel *pa_animation = NULL;
+ Panel *panel_animation = NULL;
bool no_animation = false;
- if (panel_active_animation_changed(&region->panels, &pa_animation, &no_animation)) {
+ if (panel_active_animation_changed(&region->panels, &panel_animation, &no_animation)) {
return true;
}
/* Detect panel marked for animation, if we're not already animating. */
- if (pa_animation) {
+ if (panel_animation) {
if (!no_animation) {
- *r_pa_animate = pa_animation;
+ *r_panel_animation = panel_animation;
}
return true;
}
@@ -232,144 +242,479 @@ static bool panels_need_realign(ScrArea *sa, ARegion *region, Panel **r_pa_anima
return false;
}
+/********* Functions for instanced panels. ***********/
+
+static Panel *UI_panel_add_instanced_ex(
+ ScrArea *area, ARegion *region, ListBase *panels, PanelType *panel_type, int list_index)
+{
+ Panel *panel = MEM_callocN(sizeof(Panel), "instanced panel");
+ panel->type = panel_type;
+ BLI_strncpy(panel->panelname, panel_type->idname, sizeof(panel->panelname));
+
+ panel->runtime.list_index = list_index;
+
+ /* Add the panel's children too. Although they aren't instanced panels, we can still use this
+ * function to create them, as UI_panel_begin does other things we don't need to do. */
+ LISTBASE_FOREACH (LinkData *, child, &panel_type->children) {
+ PanelType *child_type = child->data;
+ UI_panel_add_instanced_ex(area, region, &panel->children, child_type, list_index);
+ }
+
+ /* Make sure the panel is added to the end of the display-order as well. This is needed for
+ * loading existing files.
+ *
+ * Note: We could use special behavior to place it after the panel that starts the list of
+ * instanced panels, but that would add complexity that isn't needed for now. */
+ int max_sortorder = 0;
+ LISTBASE_FOREACH (Panel *, existing_panel, panels) {
+ if (existing_panel->sortorder > max_sortorder) {
+ max_sortorder = existing_panel->sortorder;
+ }
+ }
+ panel->sortorder = max_sortorder + 1;
+
+ BLI_addtail(panels, panel);
+
+ return panel;
+}
+
+/**
+ * Called in situations where panels need to be added dynamically rather than having only one panel
+ * corresponding to each PanelType.
+ */
+Panel *UI_panel_add_instanced(
+ ScrArea *area, ARegion *region, ListBase *panels, char *panel_idname, int list_index)
+{
+ ARegionType *region_type = region->type;
+
+ PanelType *panel_type = BLI_findstring(
+ &region_type->paneltypes, panel_idname, offsetof(PanelType, idname));
+
+ if (panel_type == NULL) {
+ printf("Panel type '%s' not found.\n", panel_idname);
+ return NULL;
+ }
+
+ return UI_panel_add_instanced_ex(area, region, panels, panel_type, list_index);
+}
+
+/**
+ * Find a unique key to append to the idname for the lookup to the panel's #uiBlock. Needed for
+ * instanced panels, where there can be multiple with the same type and idname.
+ */
+void UI_list_panel_unique_str(Panel *panel, char *r_name)
+{
+ snprintf(r_name, LIST_PANEL_UNIQUE_STR_LEN, "%d", panel->runtime.list_index);
+}
+
+/**
+ * Remove the #uiBlock corresponding to a panel. The lookup is needed because panels don't store
+ * a reference to their corresponding #uiBlock.
+ */
+static void panel_free_block(ARegion *region, Panel *panel)
+{
+ BLI_assert(panel->type);
+
+ char block_name[BKE_ST_MAXNAME + LIST_PANEL_UNIQUE_STR_LEN];
+ strncpy(block_name, panel->type->idname, BKE_ST_MAXNAME);
+ char unique_panel_str[LIST_PANEL_UNIQUE_STR_LEN];
+ UI_list_panel_unique_str(panel, unique_panel_str);
+ strncat(block_name, unique_panel_str, LIST_PANEL_UNIQUE_STR_LEN);
+
+ LISTBASE_FOREACH (uiBlock *, block, &region->uiblocks) {
+ if (STREQ(block->name, block_name)) {
+ BLI_remlink(&region->uiblocks, block);
+ UI_block_free(NULL, block);
+ break; /* Only delete one block for this panel. */
+ }
+ }
+}
+
+/**
+ * Free a panel and it's children.
+ *
+ * \note The only panels that should need to be deleted at runtime are panels with the
+ * #PNL_INSTANCED flag set.
+ */
+static void panel_delete(ARegion *region, ListBase *panels, Panel *panel)
+{
+ /* Recursively delete children. */
+ LISTBASE_FOREACH_MUTABLE (Panel *, child, &panel->children) {
+ panel_delete(region, &panel->children, child);
+ }
+ BLI_freelistN(&panel->children);
+
+ panel_free_block(region, panel);
+
+ BLI_remlink(panels, panel);
+ if (panel->activedata) {
+ MEM_freeN(panel->activedata);
+ }
+ MEM_freeN(panel);
+}
+
+void UI_panels_free_instanced(bContext *C, ARegion *region)
+{
+ /* Delete panels with the instanced flag. */
+ LISTBASE_FOREACH_MUTABLE (Panel *, panel, &region->panels) {
+ if ((panel->type != NULL) && (panel->type->flag & PNL_INSTANCED)) {
+ /* Make sure the panel's handler is removed before deleting it. */
+ if (panel->activedata != NULL) {
+ panel_activate_state(C, panel, PANEL_STATE_EXIT);
+ }
+ panel_delete(region, &region->panels, panel);
+ }
+ }
+}
+
+/**
+ * Check if the instanced panels in the region's panels correspond to the list of data the panels
+ * represent. Returns false if the panels have been reordered or if the types from the list data
+ * don't match in any way.
+ *
+ * \param data: The list of data to check against the instanced panels.
+ * \param panel_idname_func: Function to find the panel type idname for each item in the data list.
+ * For a readability and generality, this lookup happens separately for each type of panel list.
+ */
+bool UI_panel_list_matches_data(ARegion *region,
+ ListBase *data,
+ uiListPanelIDFromDataFunc panel_idname_func)
+{
+ int data_len = BLI_listbase_count(data);
+ int i = 0;
+ Link *data_link = data->first;
+ LISTBASE_FOREACH (Panel *, panel, &region->panels) {
+ if (panel->type != NULL && panel->type->flag & PNL_INSTANCED) {
+ /* The panels were reordered by drag and drop. */
+ if (panel->flag & PNL_INSTANCED_LIST_ORDER_CHANGED) {
+ return false;
+ }
+
+ /* We reached the last data item before the last instanced panel. */
+ if (data_link == NULL) {
+ return false;
+ }
+
+ /* Check if the panel type matches the panel type from the data item. */
+ char panel_idname[MAX_NAME];
+ panel_idname_func(data_link, panel_idname);
+ if (!STREQ(panel_idname, panel->type->idname)) {
+ return false;
+ }
+
+ data_link = data_link->next;
+ i++;
+ }
+ }
+
+ /* If we didn't make it to the last list item, the panel list isn't complete. */
+ if (i != data_len) {
+ return false;
+ }
+
+ return true;
+}
+
+static void reorder_instanced_panel_list(bContext *C, ARegion *region, Panel *drag_panel)
+{
+ /* Without a type we cannot access the reorder callback. */
+ if (drag_panel->type == NULL) {
+ return;
+ }
+ /* Don't reorder if this instanced panel doesn't support drag and drop reordering. */
+ if (drag_panel->type->reorder == NULL) {
+ return;
+ }
+
+ char *context = drag_panel->type->context;
+
+ /* Find how many instanced panels with this context string. */
+ int list_panels_len = 0;
+ LISTBASE_FOREACH (Panel *, panel, &region->panels) {
+ if (panel->type) {
+ if (panel_type_context_poll(panel->type, context)) {
+ if (panel->type->flag & PNL_INSTANCED) {
+ list_panels_len++;
+ }
+ }
+ }
+ }
+
+ /* Sort the matching instanced panels by their display order. */
+ PanelSort *panel_sort = MEM_callocN(list_panels_len * sizeof(*panel_sort), "instancedpanelsort");
+ PanelSort *sort_index = panel_sort;
+ LISTBASE_FOREACH (Panel *, panel, &region->panels) {
+ if (panel->type) {
+ if (panel_type_context_poll(panel->type, context)) {
+ if (panel->type->flag & PNL_INSTANCED) {
+ sort_index->panel = MEM_dupallocN(panel);
+ sort_index->orig = panel;
+ sort_index++;
+ }
+ }
+ }
+ }
+ qsort(panel_sort, list_panels_len, sizeof(*panel_sort), compare_panel);
+
+ /* Find how many of those panels are above this panel. */
+ int move_to_index = 0;
+ for (; move_to_index < list_panels_len; move_to_index++) {
+ if (panel_sort[move_to_index].orig == drag_panel) {
+ break;
+ }
+ }
+
+ /* Free panel sort array. */
+ int i = 0;
+ for (sort_index = panel_sort; i < list_panels_len; i++, sort_index++) {
+ MEM_freeN(sort_index->panel);
+ }
+ MEM_freeN(panel_sort);
+
+ /* Don't reorder the panel didn't change order after being dropped. */
+ if (move_to_index == drag_panel->runtime.list_index) {
+ return;
+ }
+
+ /* Set the bit to tell the interface to instanced the list. */
+ drag_panel->flag |= PNL_INSTANCED_LIST_ORDER_CHANGED;
+
+ /* Finally, move this panel's list item to the new index in its list. */
+ drag_panel->type->reorder(C, drag_panel, move_to_index);
+}
+
+/**
+ * Recursive implementation for #UI_panel_set_expand_from_list_data.
+ */
+static void panel_set_expand_from_list_data_recursive(Panel *panel, short flag, short *flag_index)
+{
+ bool open = (flag & (1 << *flag_index));
+ if (open) {
+ panel->flag &= ~PNL_CLOSEDY;
+ }
+ else {
+ panel->flag |= PNL_CLOSEDY;
+ }
+ LISTBASE_FOREACH (Panel *, child, &panel->children) {
+ *flag_index = *flag_index + 1;
+ panel_set_expand_from_list_data_recursive(child, flag, flag_index);
+ }
+}
+
+/**
+ * Set the expansion of the panel and its subpanels from the flag stored by the list data
+ * corresponding to this panel. The flag has expansion stored in each bit in depth first
+ * order.
+ */
+void UI_panel_set_expand_from_list_data(const bContext *C, Panel *panel)
+{
+ BLI_assert(panel->type != NULL);
+ BLI_assert(panel->type->flag & PNL_INSTANCED);
+ if (panel->type->get_list_data_expand_flag == NULL) {
+ /* Instanced panel doesn't support loading expansion. */
+ return;
+ }
+
+ short expand_flag = panel->type->get_list_data_expand_flag(C, panel);
+ short flag_index = 0;
+ panel_set_expand_from_list_data_recursive(panel, expand_flag, &flag_index);
+}
+
+/**
+ * Recursive implementation for #set_panels_list_data_expand_flag.
+ */
+static void get_panel_expand_flag(Panel *panel, short *flag, short *flag_index)
+{
+ bool open = !(panel->flag & PNL_CLOSEDY);
+ if (open) {
+ *flag |= (1 << *flag_index);
+ }
+ else {
+ *flag &= ~(1 << *flag_index);
+ }
+ LISTBASE_FOREACH (Panel *, child, &panel->children) {
+ *flag_index = *flag_index + 1;
+ get_panel_expand_flag(child, flag, flag_index);
+ }
+}
+
+/**
+ * Call the callback to store the panel and subpanel expansion settings in the list item that
+ * corresponds to this panel.
+ *
+ * \note This needs to iterate through all of the regions panels because the panel with changed
+ * expansion could have been the subpanel of a instanced panel, meaning it might not know
+ * which list item it corresponds to.
+ */
+static void set_panels_list_data_expand_flag(const bContext *C, ARegion *region)
+{
+ LISTBASE_FOREACH (Panel *, panel, &region->panels) {
+ PanelType *panel_type = panel->type;
+ if (panel_type == NULL) {
+ continue;
+ }
+
+ if (panel->type->flag & PNL_INSTANCED) {
+ short expand_flag = 0; /* Initialize to quite complaining compiler, value not used. */
+ short flag_index = 0;
+ get_panel_expand_flag(panel, &expand_flag, &flag_index);
+ if (panel->type->set_list_data_expand_flag) {
+ panel->type->set_list_data_expand_flag(C, panel, expand_flag);
+ }
+ }
+ }
+}
+
/****************************** panels ******************************/
-static void panels_collapse_all(ScrArea *sa, ARegion *region, const Panel *from_pa)
+static void panels_collapse_all(const bContext *C,
+ ScrArea *area,
+ ARegion *region,
+ const Panel *from_panel)
{
const bool has_category_tabs = UI_panel_category_is_visible(region);
const char *category = has_category_tabs ? UI_panel_category_active_get(region, false) : NULL;
- const int flag = ((panel_aligned(sa, region) == BUT_HORIZONTAL) ? PNL_CLOSEDX : PNL_CLOSEDY);
- const PanelType *from_pt = from_pa->type;
- Panel *pa;
+ const int flag = ((panel_aligned(area, region) == BUT_HORIZONTAL) ? PNL_CLOSEDX : PNL_CLOSEDY);
+ const PanelType *from_pt = from_panel->type;
+ Panel *panel;
- for (pa = region->panels.first; pa; pa = pa->next) {
- PanelType *pt = pa->type;
+ for (panel = region->panels.first; panel; panel = panel->next) {
+ PanelType *pt = panel->type;
/* close panels with headers in the same context */
if (pt && from_pt && !(pt->flag & PNL_NO_HEADER)) {
if (!pt->context[0] || !from_pt->context[0] || STREQ(pt->context, from_pt->context)) {
- if ((pa->flag & PNL_PIN) || !category || !pt->category[0] ||
+ if ((panel->flag & PNL_PIN) || !category || !pt->category[0] ||
STREQ(pt->category, category)) {
- pa->flag &= ~PNL_CLOSED;
- pa->flag |= flag;
+ panel->flag &= ~PNL_CLOSED;
+ panel->flag |= flag;
}
}
}
}
+ set_panels_list_data_expand_flag(C, region);
+}
+
+static bool panel_type_context_poll(PanelType *panel_type, const char *context)
+{
+ if (panel_type->context[0] && STREQ(panel_type->context, context)) {
+ return true;
+ }
+ return false;
}
Panel *UI_panel_find_by_type(ListBase *lb, PanelType *pt)
{
- Panel *pa;
+ Panel *panel;
const char *idname = pt->idname;
- for (pa = lb->first; pa; pa = pa->next) {
- if (STREQLEN(pa->panelname, idname, sizeof(pa->panelname))) {
- return pa;
+ for (panel = lb->first; panel; panel = panel->next) {
+ if (STREQLEN(panel->panelname, idname, sizeof(panel->panelname))) {
+ return panel;
}
}
return NULL;
}
/**
- * \note \a pa should be return value from #UI_panel_find_by_type and can be NULL.
+ * \note \a panel should be return value from #UI_panel_find_by_type and can be NULL.
*/
-Panel *UI_panel_begin(ScrArea *sa,
+Panel *UI_panel_begin(ScrArea *area,
ARegion *region,
ListBase *lb,
uiBlock *block,
PanelType *pt,
- Panel *pa,
+ Panel *panel,
bool *r_open)
{
- Panel *palast, *panext;
+ Panel *panel_last, *panel_next;
const char *drawname = CTX_IFACE_(pt->translation_context, pt->label);
const char *idname = pt->idname;
- const bool newpanel = (pa == NULL);
- int align = panel_aligned(sa, region);
+ const bool newpanel = (panel == NULL);
+ int align = panel_aligned(area, region);
if (!newpanel) {
- pa->type = pt;
+ panel->type = pt;
}
else {
/* new panel */
- pa = MEM_callocN(sizeof(Panel), "new panel");
- pa->type = pt;
- BLI_strncpy(pa->panelname, idname, sizeof(pa->panelname));
+ panel = MEM_callocN(sizeof(Panel), "new panel");
+ panel->type = pt;
+ BLI_strncpy(panel->panelname, idname, sizeof(panel->panelname));
if (pt->flag & PNL_DEFAULT_CLOSED) {
if (align == BUT_VERTICAL) {
- pa->flag |= PNL_CLOSEDY;
+ panel->flag |= PNL_CLOSEDY;
}
else {
- pa->flag |= PNL_CLOSEDX;
+ panel->flag |= PNL_CLOSEDX;
}
}
- pa->ofsx = 0;
- pa->ofsy = 0;
- pa->sizex = 0;
- pa->sizey = 0;
- pa->blocksizex = 0;
- pa->blocksizey = 0;
- pa->runtime_flag |= PNL_NEW_ADDED;
+ panel->ofsx = 0;
+ panel->ofsy = 0;
+ panel->sizex = 0;
+ panel->sizey = 0;
+ panel->blocksizex = 0;
+ panel->blocksizey = 0;
+ panel->runtime_flag |= PNL_NEW_ADDED;
- BLI_addtail(lb, pa);
+ BLI_addtail(lb, panel);
}
/* Do not allow closed panels without headers! Else user could get "disappeared" UI! */
- if ((pt->flag & PNL_NO_HEADER) && (pa->flag & PNL_CLOSED)) {
- pa->flag &= ~PNL_CLOSED;
+ if ((pt->flag & PNL_NO_HEADER) && (panel->flag & PNL_CLOSED)) {
+ panel->flag &= ~PNL_CLOSED;
/* Force update of panels' positions! */
- pa->sizex = 0;
- pa->sizey = 0;
- pa->blocksizex = 0;
- pa->blocksizey = 0;
+ panel->sizex = 0;
+ panel->sizey = 0;
+ panel->blocksizex = 0;
+ panel->blocksizey = 0;
}
- BLI_strncpy(pa->drawname, drawname, sizeof(pa->drawname));
+ BLI_strncpy(panel->drawname, drawname, sizeof(panel->drawname));
/* if a new panel is added, we insert it right after the panel
* that was last added. this way new panels are inserted in the
* right place between versions */
- for (palast = lb->first; palast; palast = palast->next) {
- if (palast->runtime_flag & PNL_LAST_ADDED) {
- BLI_remlink(lb, pa);
- BLI_insertlinkafter(lb, palast, pa);
+ for (panel_last = lb->first; panel_last; panel_last = panel_last->next) {
+ if (panel_last->runtime_flag & PNL_LAST_ADDED) {
+ BLI_remlink(lb, panel);
+ BLI_insertlinkafter(lb, panel_last, panel);
break;
}
}
if (newpanel) {
- pa->sortorder = (palast) ? palast->sortorder + 1 : 0;
+ panel->sortorder = (panel_last) ? panel_last->sortorder + 1 : 0;
- for (panext = lb->first; panext; panext = panext->next) {
- if (panext != pa && panext->sortorder >= pa->sortorder) {
- panext->sortorder++;
+ for (panel_next = lb->first; panel_next; panel_next = panel_next->next) {
+ if (panel_next != panel && panel_next->sortorder >= panel->sortorder) {
+ panel_next->sortorder++;
}
}
}
- if (palast) {
- palast->runtime_flag &= ~PNL_LAST_ADDED;
+ if (panel_last) {
+ panel_last->runtime_flag &= ~PNL_LAST_ADDED;
}
/* assign to block */
- block->panel = pa;
- pa->runtime_flag |= PNL_ACTIVE | PNL_LAST_ADDED;
+ block->panel = panel;
+ panel->runtime_flag |= PNL_ACTIVE | PNL_LAST_ADDED;
if (region->alignment == RGN_ALIGN_FLOAT) {
UI_block_theme_style_set(block, UI_BLOCK_THEME_STYLE_POPUP);
}
*r_open = false;
- if (pa->flag & PNL_CLOSED) {
- return pa;
+ if (panel->flag & PNL_CLOSED) {
+ return panel;
}
*r_open = true;
- return pa;
+ return panel;
}
static float panel_region_offset_x_get(const ARegion *region, int align)
@@ -385,16 +730,16 @@ static float panel_region_offset_x_get(const ARegion *region, int align)
}
void UI_panel_end(
- const ScrArea *sa, const ARegion *region, uiBlock *block, int width, int height, bool open)
+ const ScrArea *area, const ARegion *region, uiBlock *block, int width, int height, bool open)
{
- Panel *pa = block->panel;
+ Panel *panel = block->panel;
/* Set panel size excluding children. */
- pa->blocksizex = width;
- pa->blocksizey = height;
+ panel->blocksizex = width;
+ panel->blocksizey = height;
/* Compute total panel size including children. */
- for (Panel *pachild = pa->children.first; pachild; pachild = pachild->next) {
+ LISTBASE_FOREACH (Panel *, pachild, &panel->children) {
if (pachild->runtime_flag & PNL_ACTIVE) {
width = max_ii(width, pachild->sizex);
height += get_panel_real_size_y(pachild);
@@ -402,32 +747,33 @@ void UI_panel_end(
}
/* Update total panel size. */
- if (pa->runtime_flag & PNL_NEW_ADDED) {
- pa->runtime_flag &= ~PNL_NEW_ADDED;
- pa->sizex = width;
- pa->sizey = height;
+ if (panel->runtime_flag & PNL_NEW_ADDED) {
+ panel->runtime_flag &= ~PNL_NEW_ADDED;
+ panel->sizex = width;
+ panel->sizey = height;
}
else {
- int old_sizex = pa->sizex, old_sizey = pa->sizey;
- int old_region_ofsx = pa->runtime.region_ofsx;
+ int old_sizex = panel->sizex, old_sizey = panel->sizey;
+ int old_region_ofsx = panel->runtime.region_ofsx;
/* update width/height if non-zero */
if (width != 0) {
- pa->sizex = width;
+ panel->sizex = width;
}
if (height != 0 || open) {
- pa->sizey = height;
+ panel->sizey = height;
}
/* check if we need to do an animation */
- if (pa->sizex != old_sizex || pa->sizey != old_sizey) {
- pa->runtime_flag |= PNL_ANIM_ALIGN;
- pa->ofsy += old_sizey - pa->sizey;
+ if (panel->sizex != old_sizex || panel->sizey != old_sizey) {
+ panel->runtime_flag |= PNL_ANIM_ALIGN;
+ panel->ofsy += old_sizey - panel->sizey;
}
- int align = panel_aligned(sa, region);
- if (old_region_ofsx != panel_region_offset_x_get(region, align)) {
- pa->runtime_flag |= PNL_ANIM_ALIGN;
+ int align = panel_aligned(area, region);
+ panel->runtime.region_ofsx = panel_region_offset_x_get(region, align);
+ if (old_region_ofsx != panel->runtime.region_ofsx) {
+ panel->runtime_flag |= PNL_ANIM_ALIGN;
}
}
}
@@ -441,7 +787,7 @@ static void ui_offset_panel_block(uiBlock *block)
int ofsy = block->panel->sizey - style->panelspace;
- for (uiBut *but = block->buttons.first; but; but = but->next) {
+ LISTBASE_FOREACH (uiBut *, but, &block->buttons) {
but->rect.ymin += ofsy;
but->rect.ymax += ofsy;
}
@@ -544,59 +890,6 @@ static void ui_draw_panel_scalewidget(uint pos, const rcti *rect)
GPU_blend(false);
}
-static void immRectf_tris_color_ex(
- uint pos, float x1, float y1, float x2, float y2, uint col, const float color[3])
-{
- immAttr4fv(col, color);
- immVertex2f(pos, x1, y1);
- immAttr4fv(col, color);
- immVertex2f(pos, x2, y1);
- immAttr4fv(col, color);
- immVertex2f(pos, x2, y2);
-
- immAttr4fv(col, color);
- immVertex2f(pos, x1, y1);
- immAttr4fv(col, color);
- immVertex2f(pos, x2, y2);
- immAttr4fv(col, color);
- immVertex2f(pos, x1, y2);
-}
-
-static void ui_draw_panel_dragwidget(uint pos, uint col, const rctf *rect)
-{
- float col_high[4], col_dark[4];
- const int col_tint = 84;
-
- const int px = (int)U.pixelsize;
- const int px_zoom = max_ii(round_fl_to_int(BLI_rctf_size_y(rect) / 22.0f), 1);
-
- const int box_margin = max_ii(round_fl_to_int((float)(px_zoom * 2.0f)), px);
- const int box_size = max_ii(round_fl_to_int((BLI_rctf_size_y(rect) / 8.0f) - px), px);
-
- const int x_min = rect->xmin;
- const int y_min = rect->ymin;
- const int y_ofs = max_ii(round_fl_to_int(BLI_rctf_size_y(rect) / 2.5f), px);
- const int x_ofs = y_ofs;
- int i_x, i_y;
-
- UI_GetThemeColorShade4fv(TH_PANEL_HEADER, col_tint, col_high);
- UI_GetThemeColorShade4fv(TH_PANEL_BACK, -col_tint, col_dark);
-
- /* draw multiple boxes */
- immBegin(GPU_PRIM_TRIS, 4 * 2 * (6 * 2));
- for (i_x = 0; i_x < 4; i_x++) {
- for (i_y = 0; i_y < 2; i_y++) {
- const int x_co = (x_min + x_ofs) + (i_x * (box_size + box_margin));
- const int y_co = (y_min + y_ofs) + (i_y * (box_size + box_margin));
-
- immRectf_tris_color_ex(
- pos, x_co - box_size, y_co - px_zoom, x_co, (y_co + box_size) - px_zoom, col, col_dark);
- immRectf_tris_color_ex(pos, x_co - box_size, y_co, x_co, y_co + box_size, col, col_high);
- }
- }
- immEnd();
-}
-
/* For button layout next to label. */
void UI_panel_label_offset(uiBlock *block, int *r_x, int *r_y)
{
@@ -617,7 +910,7 @@ static void ui_draw_aligned_panel_header(
Panel *panel = block->panel;
rcti hrect;
int pnl_icons;
- const char *activename = panel->drawname[0] ? panel->drawname : panel->panelname;
+ const char *activename = panel->drawname;
const bool is_subpanel = (panel->type && panel->type->parent);
uiFontStyle *fontstyle = (is_subpanel) ? &style->widgetlabel : &style->paneltitle;
uchar col_title[4];
@@ -663,7 +956,6 @@ void ui_draw_aligned_panel(uiStyle *style,
const bool show_background)
{
Panel *panel = block->panel;
- rcti headrect;
rctf itemrect;
float color[4];
const bool is_closed_x = (panel->flag & PNL_CLOSEDX) ? true : false;
@@ -674,11 +966,19 @@ void ui_draw_aligned_panel(uiStyle *style,
* can't be dragged. This may be changed in future. */
show_background);
const int panel_col = is_subpanel ? TH_PANEL_SUB_BACK : TH_PANEL_BACK;
+ const bool draw_box_style = (panel->type && panel->type->flag & (PNL_DRAW_BOX));
+
+ /* Use the theme for box widgets for box-style panels. */
+ uiWidgetColors *box_wcol = NULL;
+ if (draw_box_style) {
+ bTheme *btheme = UI_GetTheme();
+ box_wcol = &btheme->tui.wcol_box;
+ }
+
+ uint pos = GPU_vertformat_attr_add(immVertexFormat(), "pos", GPU_COMP_F32, 2, GPU_FETCH_FLOAT);
if (panel->type && (panel->type->flag & PNL_NO_HEADER)) {
if (show_background) {
- uint pos = GPU_vertformat_attr_add(
- immVertexFormat(), "pos", GPU_COMP_F32, 2, GPU_FETCH_FLOAT);
immBindBuiltinProgram(GPU_SHADER_2D_UNIFORM_COLOR);
immUniformThemeColor(panel_col);
immRectf(pos, rect->xmin, rect->ymin, rect->xmax, rect->ymax);
@@ -687,25 +987,47 @@ void ui_draw_aligned_panel(uiStyle *style,
return;
}
- /* calculate header rect */
- /* + 0.001f to prevent flicker due to float inaccuracy */
- headrect = *rect;
- headrect.ymin = headrect.ymax;
- headrect.ymax = headrect.ymin + floor(PNL_HEADER / block->aspect + 0.001f);
+ /* Calculate header rect with + 0.001f to prevent flicker due to float inaccuracy */
+ rcti headrect = {
+ rect->xmin, rect->xmax, rect->ymax, rect->ymax + floor(PNL_HEADER / block->aspect + 0.001f)};
- rcti titlerect = headrect;
- if (is_subpanel) {
- titlerect.xmin += (0.7f * UI_UNIT_X) / block->aspect + 0.001f;
- }
+ /* Draw a panel and header backdrops with an opaque box backdrop for box style panels. */
+ if (draw_box_style && !is_subpanel) {
+ /* Expand the top a tiny bit to give header buttons equal size above and below. */
+ rcti box_rect = {rect->xmin,
+ rect->xmax,
+ (is_closed_x || is_closed_y) ? headrect.ymin : rect->ymin,
+ headrect.ymax + U.pixelsize};
+ ui_draw_box_opaque(&box_rect, UI_CNR_ALL);
- uint pos = GPU_vertformat_attr_add(immVertexFormat(), "pos", GPU_COMP_F32, 2, GPU_FETCH_FLOAT);
- immBindBuiltinProgram(GPU_SHADER_2D_UNIFORM_COLOR);
+ /* Mimick the border between aligned box widgets for the bottom of the header. */
+ if (!(is_closed_x || is_closed_y)) {
+ immBindBuiltinProgram(GPU_SHADER_2D_UNIFORM_COLOR);
+ GPU_blend(true);
+
+ immUniformColor4ubv(box_wcol->outline);
+ immRectf(pos, rect->xmin, headrect.ymin - U.pixelsize, rect->xmax, headrect.ymin);
+ uchar emboss_col[4];
+ UI_GetThemeColor4ubv(TH_WIDGET_EMBOSS, emboss_col);
+ immUniformColor4ubv(emboss_col);
+ immRectf(pos,
+ rect->xmin,
+ headrect.ymin - U.pixelsize,
+ rect->xmax,
+ headrect.ymin - U.pixelsize - 1);
+
+ GPU_blend(false);
+ immUnbindProgram();
+ }
+ }
- if (show_background && !is_subpanel) {
+ /* Draw the header backdrop. */
+ if (show_background && !is_subpanel && !draw_box_style) {
float minx = rect->xmin;
float maxx = is_closed_x ? (minx + PNL_HEADER / block->aspect) : rect->xmax;
float y = headrect.ymax;
+ immBindBuiltinProgram(GPU_SHADER_2D_UNIFORM_COLOR);
GPU_blend(true);
/* draw with background color */
@@ -723,12 +1045,10 @@ void ui_draw_aligned_panel(uiStyle *style,
immEnd();
GPU_blend(false);
+ immUnbindProgram();
}
- immUnbindProgram();
-
- /* draw optional pin icon */
-
+/* draw optional pin icon */
#ifdef USE_PIN_HIDDEN
if (show_pin && (block->panel->flag & PNL_PIN))
#else
@@ -751,34 +1071,39 @@ void ui_draw_aligned_panel(uiStyle *style,
}
/* horizontal title */
+ rcti titlerect = headrect;
+ if (is_subpanel) {
+ titlerect.xmin += (0.7f * UI_UNIT_X) / block->aspect + 0.001f;
+ }
if (is_closed_x == false) {
ui_draw_aligned_panel_header(style, block, &titlerect, 'h', show_background);
if (show_drag) {
- uint col;
- GPUVertFormat *format = immVertexFormat();
- pos = GPU_vertformat_attr_add(format, "pos", GPU_COMP_F32, 2, GPU_FETCH_FLOAT);
- col = GPU_vertformat_attr_add(format, "color", GPU_COMP_F32, 4, GPU_FETCH_FLOAT);
-
/* itemrect smaller */
+ const float scale = 0.7;
itemrect.xmax = headrect.xmax - (0.2f * UI_UNIT_X);
itemrect.xmin = itemrect.xmax - BLI_rcti_size_y(&headrect);
itemrect.ymin = headrect.ymin;
itemrect.ymax = headrect.ymax;
+ BLI_rctf_scale(&itemrect, scale);
- BLI_rctf_scale(&itemrect, 0.7f);
- immBindBuiltinProgram(GPU_SHADER_2D_FLAT_COLOR);
- ui_draw_panel_dragwidget(pos, col, &itemrect);
- immUnbindProgram();
+ GPU_matrix_push();
+ GPU_matrix_translate_2f(itemrect.xmin, itemrect.ymin);
- /* Restore format for the following draws. */
- pos = GPU_vertformat_attr_add(immVertexFormat(), "pos", GPU_COMP_F32, 2, GPU_FETCH_FLOAT);
+ const int col_tint = 84;
+ float col_high[4], col_dark[4];
+ UI_GetThemeColorShade4fv(TH_PANEL_HEADER, col_tint, col_high);
+ UI_GetThemeColorShade4fv(TH_PANEL_BACK, -col_tint, col_dark);
+
+ GPUBatch *batch = GPU_batch_preset_panel_drag_widget(
+ U.pixelsize, col_high, col_dark, BLI_rcti_size_y(&headrect) * scale);
+ GPU_batch_program_set_builtin(batch, GPU_SHADER_2D_FLAT_COLOR);
+ GPU_batch_draw(batch);
+ GPU_matrix_pop();
}
}
- /* if the panel is minimized vertically:
- * (------)
- */
+ /* Draw panel backdrop. */
if (is_closed_y) {
/* skip */
}
@@ -790,12 +1115,19 @@ void ui_draw_aligned_panel(uiStyle *style,
/* an open panel */
else {
/* in some occasions, draw a border */
- if (panel->flag & PNL_SELECT) {
+ if (panel->flag & PNL_SELECT && !is_subpanel) {
+ float radius;
if (panel->control & UI_PNL_SOLID) {
UI_draw_roundbox_corner_set(UI_CNR_ALL);
+ radius = 8.0f;
+ }
+ else if (draw_box_style) {
+ UI_draw_roundbox_corner_set(UI_CNR_ALL);
+ radius = box_wcol->roundness * U.widget_unit;
}
else {
UI_draw_roundbox_corner_set(UI_CNR_NONE);
+ radius = 0.0f;
}
UI_GetThemeColorShade4fv(TH_BACK, -120, color);
@@ -804,18 +1136,40 @@ void ui_draw_aligned_panel(uiStyle *style,
0.5f + rect->ymin,
0.5f + rect->xmax,
0.5f + headrect.ymax + 1,
- 8,
+ radius,
color);
}
immBindBuiltinProgram(GPU_SHADER_2D_UNIFORM_COLOR);
-
GPU_blend(true);
- if (show_background) {
- /* panel backdrop */
- immUniformThemeColor(panel_col);
- immRectf(pos, rect->xmin, rect->ymin, rect->xmax, rect->ymax);
+ /* Draw panel backdrop if it wasn't already been drawn by the single opaque round box earlier.
+ * Note: Sub-panels blend with panels, so they can't be opaque. */
+ if (show_background && !(draw_box_style && !is_subpanel)) {
+ /* Draw the bottom subpanels . */
+ if (draw_box_style) {
+ if (panel->next) {
+ immUniformThemeColor(panel_col);
+ immRectf(
+ pos, rect->xmin + U.pixelsize, rect->ymin, rect->xmax - U.pixelsize, rect->ymax);
+ }
+ else {
+ /* Change the width a little bit to line up with sides. */
+ UI_draw_roundbox_corner_set(UI_CNR_BOTTOM_RIGHT | UI_CNR_BOTTOM_LEFT);
+ UI_GetThemeColor4fv(panel_col, color);
+ UI_draw_roundbox_aa(true,
+ rect->xmin + U.pixelsize,
+ rect->ymin + U.pixelsize,
+ rect->xmax - U.pixelsize,
+ rect->ymax,
+ box_wcol->roundness * U.widget_unit,
+ color);
+ }
+ }
+ else {
+ immUniformThemeColor(panel_col);
+ immRectf(pos, rect->xmin, rect->ymin, rect->xmax, rect->ymax);
+ }
}
if (panel->control & UI_PNL_SCALE) {
@@ -867,65 +1221,71 @@ void ui_draw_aligned_panel(uiStyle *style,
/************************** panel alignment *************************/
-static int get_panel_header(const Panel *pa)
+static int get_panel_header(const Panel *panel)
{
- if (pa->type && (pa->type->flag & PNL_NO_HEADER)) {
+ if (panel->type && (panel->type->flag & PNL_NO_HEADER)) {
return 0;
}
return PNL_HEADER;
}
-static int get_panel_size_y(const Panel *pa)
+static int get_panel_size_y(const Panel *panel)
{
- if (pa->type && (pa->type->flag & PNL_NO_HEADER)) {
- return pa->sizey;
+ if (panel->type && (panel->type->flag & PNL_NO_HEADER)) {
+ return panel->sizey;
}
- return PNL_HEADER + pa->sizey;
+ return PNL_HEADER + panel->sizey;
}
-static int get_panel_real_size_y(const Panel *pa)
+static int get_panel_real_size_y(const Panel *panel)
{
- int sizey = (pa->flag & PNL_CLOSED) ? 0 : pa->sizey;
+ int sizey = (panel->flag & PNL_CLOSED) ? 0 : panel->sizey;
- if (pa->type && (pa->type->flag & PNL_NO_HEADER)) {
+ if (panel->type && (panel->type->flag & PNL_NO_HEADER)) {
return sizey;
}
return PNL_HEADER + sizey;
}
-int UI_panel_size_y(const Panel *pa)
+int UI_panel_size_y(const Panel *panel)
{
- return get_panel_real_size_y(pa);
+ return get_panel_real_size_y(panel);
}
/* this function is needed because uiBlock and Panel itself don't
* change sizey or location when closed */
-static int get_panel_real_ofsy(Panel *pa)
+static int get_panel_real_ofsy(Panel *panel)
{
- if (pa->flag & PNL_CLOSEDY) {
- return pa->ofsy + pa->sizey;
+ if (panel->flag & PNL_CLOSEDY) {
+ return panel->ofsy + panel->sizey;
}
else {
- return pa->ofsy;
+ return panel->ofsy;
}
}
-static int get_panel_real_ofsx(Panel *pa)
+static int get_panel_real_ofsx(Panel *panel)
{
- if (pa->flag & PNL_CLOSEDX) {
- return pa->ofsx + get_panel_header(pa);
+ if (panel->flag & PNL_CLOSEDX) {
+ return panel->ofsx + get_panel_header(panel);
}
else {
- return pa->ofsx + pa->sizex;
+ return panel->ofsx + panel->sizex;
}
}
-typedef struct PanelSort {
- Panel *pa, *orig;
-} PanelSort;
+bool UI_panel_is_dragging(const struct Panel *panel)
+{
+ uiHandlePanelData *data = panel->activedata;
+ if (!data) {
+ return false;
+ }
+
+ return data->is_drag_drop;
+}
/**
* \note about sorting;
@@ -939,16 +1299,16 @@ static int find_leftmost_panel(const void *a1, const void *a2)
{
const PanelSort *ps1 = a1, *ps2 = a2;
- if (ps1->pa->ofsx > ps2->pa->ofsx) {
+ if (ps1->panel->ofsx > ps2->panel->ofsx) {
return 1;
}
- else if (ps1->pa->ofsx < ps2->pa->ofsx) {
+ else if (ps1->panel->ofsx < ps2->panel->ofsx) {
return -1;
}
- else if (ps1->pa->sortorder > ps2->pa->sortorder) {
+ else if (ps1->panel->sortorder > ps2->panel->sortorder) {
return 1;
}
- else if (ps1->pa->sortorder < ps2->pa->sortorder) {
+ else if (ps1->panel->sortorder < ps2->panel->sortorder) {
return -1;
}
@@ -961,26 +1321,26 @@ static int find_highest_panel(const void *a1, const void *a2)
/* stick uppermost header-less panels to the top of the region -
* prevent them from being sorted (multiple header-less panels have to be sorted though) */
- if (ps1->pa->type->flag & PNL_NO_HEADER && ps2->pa->type->flag & PNL_NO_HEADER) {
+ if (ps1->panel->type->flag & PNL_NO_HEADER && ps2->panel->type->flag & PNL_NO_HEADER) {
/* skip and check for ofs and sortorder below */
}
- else if (ps1->pa->type->flag & PNL_NO_HEADER) {
+ else if (ps1->panel->type->flag & PNL_NO_HEADER) {
return -1;
}
- else if (ps2->pa->type->flag & PNL_NO_HEADER) {
+ else if (ps2->panel->type->flag & PNL_NO_HEADER) {
return 1;
}
- if (ps1->pa->ofsy + ps1->pa->sizey < ps2->pa->ofsy + ps2->pa->sizey) {
+ if (ps1->panel->ofsy + ps1->panel->sizey < ps2->panel->ofsy + ps2->panel->sizey) {
return 1;
}
- else if (ps1->pa->ofsy + ps1->pa->sizey > ps2->pa->ofsy + ps2->pa->sizey) {
+ else if (ps1->panel->ofsy + ps1->panel->sizey > ps2->panel->ofsy + ps2->panel->sizey) {
return -1;
}
- else if (ps1->pa->sortorder > ps2->pa->sortorder) {
+ else if (ps1->panel->sortorder > ps2->panel->sortorder) {
return 1;
}
- else if (ps1->pa->sortorder < ps2->pa->sortorder) {
+ else if (ps1->panel->sortorder < ps2->panel->sortorder) {
return -1;
}
@@ -991,24 +1351,24 @@ static int compare_panel(const void *a1, const void *a2)
{
const PanelSort *ps1 = a1, *ps2 = a2;
- if (ps1->pa->sortorder > ps2->pa->sortorder) {
+ if (ps1->panel->sortorder > ps2->panel->sortorder) {
return 1;
}
- else if (ps1->pa->sortorder < ps2->pa->sortorder) {
+ else if (ps1->panel->sortorder < ps2->panel->sortorder) {
return -1;
}
return 0;
}
-static void align_sub_panels(Panel *pa)
+static void align_sub_panels(Panel *panel)
{
/* Position sub panels. */
- int ofsy = pa->ofsy + pa->sizey - pa->blocksizey;
+ int ofsy = panel->ofsy + panel->sizey - panel->blocksizey;
- for (Panel *pachild = pa->children.first; pachild; pachild = pachild->next) {
+ LISTBASE_FOREACH (Panel *, pachild, &panel->children) {
if (pachild->runtime_flag & PNL_ACTIVE) {
- pachild->ofsx = pa->ofsx;
+ pachild->ofsx = panel->ofsx;
pachild->ofsy = ofsy - get_panel_size_y(pachild);
ofsy -= get_panel_real_size_y(pachild);
@@ -1021,17 +1381,17 @@ static void align_sub_panels(Panel *pa)
/* this doesn't draw */
/* returns 1 when it did something */
-static bool uiAlignPanelStep(ScrArea *sa, ARegion *region, const float fac, const bool drag)
+static bool uiAlignPanelStep(ScrArea *area, ARegion *region, const float fac, const bool drag)
{
- Panel *pa;
+ Panel *panel;
PanelSort *ps, *panelsort, *psnext;
int a, tot = 0;
bool done;
- int align = panel_aligned(sa, region);
+ int align = panel_aligned(area, region);
/* count active, not tabbed panels */
- for (pa = region->panels.first; pa; pa = pa->next) {
- if (pa->runtime_flag & PNL_ACTIVE) {
+ for (panel = region->panels.first; panel; panel = panel->next) {
+ if (panel->runtime_flag & PNL_ACTIVE) {
tot++;
}
}
@@ -1041,13 +1401,13 @@ static bool uiAlignPanelStep(ScrArea *sa, ARegion *region, const float fac, cons
}
/* extra; change close direction? */
- for (pa = region->panels.first; pa; pa = pa->next) {
- if (pa->runtime_flag & PNL_ACTIVE) {
- if ((pa->flag & PNL_CLOSEDX) && (align == BUT_VERTICAL)) {
- pa->flag ^= PNL_CLOSED;
+ for (panel = region->panels.first; panel; panel = panel->next) {
+ if (panel->runtime_flag & PNL_ACTIVE) {
+ if ((panel->flag & PNL_CLOSEDX) && (align == BUT_VERTICAL)) {
+ panel->flag ^= PNL_CLOSED;
}
- else if ((pa->flag & PNL_CLOSEDY) && (align == BUT_HORIZONTAL)) {
- pa->flag ^= PNL_CLOSED;
+ else if ((panel->flag & PNL_CLOSEDY) && (align == BUT_HORIZONTAL)) {
+ panel->flag ^= PNL_CLOSED;
}
}
}
@@ -1056,10 +1416,10 @@ static bool uiAlignPanelStep(ScrArea *sa, ARegion *region, const float fac, cons
panelsort = MEM_callocN(tot * sizeof(PanelSort), "panelsort");
ps = panelsort;
- for (pa = region->panels.first; pa; pa = pa->next) {
- if (pa->runtime_flag & PNL_ACTIVE) {
- ps->pa = MEM_dupallocN(pa);
- ps->orig = pa;
+ for (panel = region->panels.first; panel; panel = panel->next) {
+ if (panel->runtime_flag & PNL_ACTIVE) {
+ ps->panel = MEM_dupallocN(panel);
+ ps->orig = panel;
ps++;
}
}
@@ -1084,21 +1444,39 @@ static bool uiAlignPanelStep(ScrArea *sa, ARegion *region, const float fac, cons
/* no smart other default start loc! this keeps switching f5/f6/etc compatible */
ps = panelsort;
- ps->pa->runtime.region_ofsx = panel_region_offset_x_get(region, align);
- ps->pa->ofsx = 0;
- ps->pa->ofsy = -get_panel_size_y(ps->pa);
- ps->pa->ofsx += ps->pa->runtime.region_ofsx;
+ ps->panel->runtime.region_ofsx = panel_region_offset_x_get(region, align);
+ ps->panel->ofsx = 0;
+ ps->panel->ofsy = -get_panel_size_y(ps->panel);
+ ps->panel->ofsx += ps->panel->runtime.region_ofsx;
+ /* Extra margin if the panel is a box style panel. */
+ if (ps->panel->type && ps->panel->type->flag & PNL_DRAW_BOX) {
+ ps->panel->ofsx += UI_PANEL_BOX_STYLE_MARGIN;
+ ps->panel->ofsy -= UI_PANEL_BOX_STYLE_MARGIN;
+ }
for (a = 0; a < tot - 1; a++, ps++) {
psnext = ps + 1;
if (align == BUT_VERTICAL) {
- psnext->pa->ofsx = ps->pa->ofsx;
- psnext->pa->ofsy = get_panel_real_ofsy(ps->pa) - get_panel_size_y(psnext->pa);
+ bool use_box = ps->panel->type && ps->panel->type->flag & PNL_DRAW_BOX;
+ bool use_box_next = psnext->panel->type && psnext->panel->type->flag & PNL_DRAW_BOX;
+ psnext->panel->ofsx = ps->panel->ofsx;
+ psnext->panel->ofsy = get_panel_real_ofsy(ps->panel) - get_panel_size_y(psnext->panel);
+ /* Extra margin for box style panels. */
+ if (use_box || use_box_next) {
+ psnext->panel->ofsy -= UI_PANEL_BOX_STYLE_MARGIN;
+ }
+ if (use_box && !use_box_next) {
+ psnext->panel->ofsx -= UI_PANEL_BOX_STYLE_MARGIN;
+ }
+ else if (!use_box && use_box_next) {
+ psnext->panel->ofsx += UI_PANEL_BOX_STYLE_MARGIN;
+ }
}
else {
- psnext->pa->ofsx = get_panel_real_ofsx(ps->pa);
- psnext->pa->ofsy = ps->pa->ofsy + get_panel_size_y(ps->pa) - get_panel_size_y(psnext->pa);
+ psnext->panel->ofsx = get_panel_real_ofsx(ps->panel);
+ psnext->panel->ofsy = ps->panel->ofsy + get_panel_size_y(ps->panel) -
+ get_panel_size_y(psnext->panel);
}
}
@@ -1106,11 +1484,11 @@ static bool uiAlignPanelStep(ScrArea *sa, ARegion *region, const float fac, cons
done = false;
ps = panelsort;
for (a = 0; a < tot; a++, ps++) {
- if ((ps->pa->flag & PNL_SELECT) == 0) {
- if ((ps->orig->ofsx != ps->pa->ofsx) || (ps->orig->ofsy != ps->pa->ofsy)) {
- ps->orig->ofsx = round_fl_to_int(fac * (float)ps->pa->ofsx +
+ if ((ps->panel->flag & PNL_SELECT) == 0) {
+ if ((ps->orig->ofsx != ps->panel->ofsx) || (ps->orig->ofsy != ps->panel->ofsy)) {
+ ps->orig->ofsx = round_fl_to_int(fac * (float)ps->panel->ofsx +
(1.0f - fac) * (float)ps->orig->ofsx);
- ps->orig->ofsy = round_fl_to_int(fac * (float)ps->pa->ofsy +
+ ps->orig->ofsy = round_fl_to_int(fac * (float)ps->panel->ofsy +
(1.0f - fac) * (float)ps->orig->ofsy);
done = true;
}
@@ -1118,42 +1496,42 @@ static bool uiAlignPanelStep(ScrArea *sa, ARegion *region, const float fac, cons
}
/* set locations for tabbed and sub panels */
- for (pa = region->panels.first; pa; pa = pa->next) {
- if (pa->runtime_flag & PNL_ACTIVE) {
- if (pa->children.first) {
- align_sub_panels(pa);
+ for (panel = region->panels.first; panel; panel = panel->next) {
+ if (panel->runtime_flag & PNL_ACTIVE) {
+ if (panel->children.first) {
+ align_sub_panels(panel);
}
}
}
/* free panelsort array */
for (ps = panelsort, a = 0; a < tot; a++, ps++) {
- MEM_freeN(ps->pa);
+ MEM_freeN(ps->panel);
}
MEM_freeN(panelsort);
return done;
}
-static void ui_panels_size(ScrArea *sa, ARegion *region, int *r_x, int *r_y)
+static void ui_panels_size(ScrArea *area, ARegion *region, int *r_x, int *r_y)
{
- Panel *pa;
- int align = panel_aligned(sa, region);
+ Panel *panel;
+ int align = panel_aligned(area, region);
int sizex = 0;
int sizey = 0;
/* compute size taken up by panels, for setting in view2d */
- for (pa = region->panels.first; pa; pa = pa->next) {
- if (pa->runtime_flag & PNL_ACTIVE) {
+ for (panel = region->panels.first; panel; panel = panel->next) {
+ if (panel->runtime_flag & PNL_ACTIVE) {
int pa_sizex, pa_sizey;
if (align == BUT_VERTICAL) {
- pa_sizex = pa->ofsx + pa->sizex;
- pa_sizey = get_panel_real_ofsy(pa);
+ pa_sizex = panel->ofsx + panel->sizex;
+ pa_sizey = get_panel_real_ofsy(panel);
}
else {
- pa_sizex = get_panel_real_ofsx(pa) + pa->sizex;
- pa_sizey = pa->ofsy + get_panel_size_y(pa);
+ pa_sizex = get_panel_real_ofsx(panel) + panel->sizex;
+ pa_sizey = panel->ofsy + get_panel_size_y(panel);
}
sizex = max_ii(sizex, pa_sizex);
@@ -1172,10 +1550,10 @@ static void ui_panels_size(ScrArea *sa, ARegion *region, int *r_x, int *r_y)
*r_y = sizey;
}
-static void ui_do_animate(const bContext *C, Panel *panel)
+static void ui_do_animate(bContext *C, Panel *panel)
{
uiHandlePanelData *data = panel->activedata;
- ScrArea *sa = CTX_wm_area(C);
+ ScrArea *area = CTX_wm_area(C);
ARegion *region = CTX_wm_region(C);
float fac;
@@ -1183,7 +1561,7 @@ static void ui_do_animate(const bContext *C, Panel *panel)
fac = min_ff(sqrtf(fac), 1.0f);
/* for max 1 second, interpolate positions */
- if (uiAlignPanelStep(sa, region, fac, false)) {
+ if (uiAlignPanelStep(area, region, fac, false)) {
ED_region_tag_redraw(region);
}
else {
@@ -1191,7 +1569,15 @@ static void ui_do_animate(const bContext *C, Panel *panel)
}
if (fac >= 1.0f) {
+ /* Store before data is freed. */
+ const bool is_drag_drop = data->is_drag_drop;
+
panel_activate_state(C, panel, PANEL_STATE_EXIT);
+ if (is_drag_drop) {
+ /* Note: doing this in #panel_activate_state would require removing const for context in many
+ * other places. */
+ reorder_instanced_panel_list(C, region, panel);
+ }
return;
}
}
@@ -1200,15 +1586,15 @@ static void panel_list_clear_active(ListBase *lb)
{
/* set all panels as inactive, so that at the end we know
* which ones were used */
- for (Panel *pa = lb->first; pa; pa = pa->next) {
- if (pa->runtime_flag & PNL_ACTIVE) {
- pa->runtime_flag = PNL_WAS_ACTIVE;
+ LISTBASE_FOREACH (Panel *, panel, lb) {
+ if (panel->runtime_flag & PNL_ACTIVE) {
+ panel->runtime_flag = PNL_WAS_ACTIVE;
}
else {
- pa->runtime_flag = 0;
+ panel->runtime_flag = 0;
}
- panel_list_clear_active(&pa->children);
+ panel_list_clear_active(&panel->children);
}
}
@@ -1220,9 +1606,9 @@ void UI_panels_begin(const bContext *UNUSED(C), ARegion *region)
/* only draws blocks with panels */
void UI_panels_end(const bContext *C, ARegion *region, int *r_x, int *r_y)
{
- ScrArea *sa = CTX_wm_area(C);
+ ScrArea *area = CTX_wm_area(C);
uiBlock *block;
- Panel *pa, *firstpa;
+ Panel *panel, *panel_first;
/* offset contents */
for (block = region->uiblocks.first; block; block = block->next) {
@@ -1232,31 +1618,31 @@ void UI_panels_end(const bContext *C, ARegion *region, int *r_x, int *r_y)
}
/* re-align, possibly with animation */
- if (panels_need_realign(sa, region, &pa)) {
- if (pa) {
- panel_activate_state(C, pa, PANEL_STATE_ANIMATION);
+ if (panels_need_realign(area, region, &panel)) {
+ if (panel) {
+ panel_activate_state(C, panel, PANEL_STATE_ANIMATION);
}
else {
- uiAlignPanelStep(sa, region, 1.0, false);
+ uiAlignPanelStep(area, region, 1.0, false);
}
}
/* tag first panel */
- firstpa = NULL;
+ panel_first = NULL;
for (block = region->uiblocks.first; block; block = block->next) {
if (block->active && block->panel) {
- if (!firstpa || block->panel->sortorder < firstpa->sortorder) {
- firstpa = block->panel;
+ if (!panel_first || block->panel->sortorder < panel_first->sortorder) {
+ panel_first = block->panel;
}
}
}
- if (firstpa) {
- firstpa->runtime_flag |= PNL_FIRST;
+ if (panel_first) {
+ panel_first->runtime_flag |= PNL_FIRST;
}
/* compute size taken up by panel */
- ui_panels_size(sa, region, r_x, r_y);
+ ui_panels_size(area, region, r_x, r_y);
}
void UI_panels_draw(const bContext *C, ARegion *region)
@@ -1305,20 +1691,20 @@ void UI_panels_scale(ARegion *region, float new_width)
static void check_panel_overlap(ARegion *region, Panel *panel)
{
- Panel *pa;
+ Panel *panel_list;
/* also called with (panel == NULL) for clear */
- for (pa = region->panels.first; pa; pa = pa->next) {
- pa->flag &= ~PNL_OVERLAP;
- if (panel && (pa != panel)) {
- if (pa->runtime_flag & PNL_ACTIVE) {
+ for (panel_list = region->panels.first; panel_list; panel_list = panel_list->next) {
+ panel_list->flag &= ~PNL_OVERLAP;
+ if (panel && (panel_list != panel)) {
+ if (panel_list->runtime_flag & PNL_ACTIVE) {
float safex = 0.2, safey = 0.2;
- if (pa->flag & PNL_CLOSEDX) {
+ if (panel_list->flag & PNL_CLOSEDX) {
safex = 0.05;
}
- else if (pa->flag & PNL_CLOSEDY) {
+ else if (panel_list->flag & PNL_CLOSEDY) {
safey = 0.05;
}
else if (panel->flag & PNL_CLOSEDX) {
@@ -1328,11 +1714,12 @@ static void check_panel_overlap(ARegion *region, Panel *panel)
safey = 0.05;
}
- if (pa->ofsx > panel->ofsx - safex * panel->sizex) {
- if (pa->ofsx + pa->sizex < panel->ofsx + (1.0f + safex) * panel->sizex) {
- if (pa->ofsy > panel->ofsy - safey * panel->sizey) {
- if (pa->ofsy + pa->sizey < panel->ofsy + (1.0f + safey) * panel->sizey) {
- pa->flag |= PNL_OVERLAP;
+ if (panel_list->ofsx > panel->ofsx - safex * panel->sizex) {
+ if (panel_list->ofsx + panel_list->sizex < panel->ofsx + (1.0f + safex) * panel->sizex) {
+ if (panel_list->ofsy > panel->ofsy - safey * panel->sizey) {
+ if (panel_list->ofsy + panel_list->sizey <
+ panel->ofsy + (1.0f + safey) * panel->sizey) {
+ panel_list->flag |= PNL_OVERLAP;
}
}
}
@@ -1347,17 +1734,17 @@ static void check_panel_overlap(ARegion *region, Panel *panel)
static void ui_do_drag(const bContext *C, const wmEvent *event, Panel *panel)
{
uiHandlePanelData *data = panel->activedata;
- ScrArea *sa = CTX_wm_area(C);
+ ScrArea *area = CTX_wm_area(C);
ARegion *region = CTX_wm_region(C);
- short align = panel_aligned(sa, region), dx = 0, dy = 0;
+ short align = panel_aligned(area, region), dx = 0, dy = 0;
/* first clip for window, no dragging outside */
if (!BLI_rcti_isect_pt_v(&region->winrct, &event->x)) {
return;
}
- dx = (event->x - data->startx) & ~(PNL_GRID - 1);
- dy = (event->y - data->starty) & ~(PNL_GRID - 1);
+ dx = (event->x - data->startx);
+ dy = (event->y - data->starty);
dx *= (float)BLI_rctf_size_x(&region->v2d.cur) / (float)BLI_rcti_size_x(&region->winrct);
dy *= (float)BLI_rctf_size_y(&region->v2d.cur) / (float)BLI_rcti_size_y(&region->winrct);
@@ -1381,7 +1768,7 @@ static void ui_do_drag(const bContext *C, const wmEvent *event, Panel *panel)
check_panel_overlap(region, panel);
if (align) {
- uiAlignPanelStep(sa, region, 0.2, true);
+ uiAlignPanelStep(area, region, 0.2, true);
}
}
@@ -1391,12 +1778,12 @@ static void ui_do_drag(const bContext *C, const wmEvent *event, Panel *panel)
/******************* region level panel interaction *****************/
static uiPanelMouseState ui_panel_mouse_state_get(const uiBlock *block,
- const Panel *pa,
+ const Panel *panel,
const int mx,
const int my)
{
/* open panel */
- if (pa->flag & PNL_CLOSEDX) {
+ if (panel->flag & PNL_CLOSEDX) {
if ((block->rect.xmin <= mx) && (block->rect.xmin + PNL_HEADER >= mx)) {
return PANEL_MOUSE_INSIDE_HEADER;
}
@@ -1409,8 +1796,8 @@ static uiPanelMouseState ui_panel_mouse_state_get(const uiBlock *block,
return PANEL_MOUSE_INSIDE_HEADER;
}
/* open panel */
- else if (!(pa->flag & PNL_CLOSEDY)) {
- if (pa->control & UI_PNL_SCALE) {
+ else if (!(panel->flag & PNL_CLOSEDY)) {
+ if (panel->control & UI_PNL_SCALE) {
if (block->rect.xmax - PNL_HEADER <= mx) {
if (block->rect.ymin + PNL_HEADER >= my) {
return PANEL_MOUSE_INSIDE_SCALE;
@@ -1441,22 +1828,22 @@ static void ui_panel_drag_collapse(bContext *C,
uiPanelDragCollapseHandle *dragcol_data,
const int xy_dst[2])
{
- ScrArea *sa = CTX_wm_area(C);
+ ScrArea *area = CTX_wm_area(C);
ARegion *region = CTX_wm_region(C);
uiBlock *block;
- Panel *pa;
+ Panel *panel;
for (block = region->uiblocks.first; block; block = block->next) {
float xy_a_block[2] = {UNPACK2(dragcol_data->xy_init)};
float xy_b_block[2] = {UNPACK2(xy_dst)};
rctf rect = block->rect;
int oldflag;
- const bool is_horizontal = (panel_aligned(sa, region) == BUT_HORIZONTAL);
+ const bool is_horizontal = (panel_aligned(area, region) == BUT_HORIZONTAL);
- if ((pa = block->panel) == 0 || (pa->type && (pa->type->flag & PNL_NO_HEADER))) {
+ if ((panel = block->panel) == 0 || (panel->type && (panel->type->flag & PNL_NO_HEADER))) {
continue;
}
- oldflag = pa->flag;
+ oldflag = panel->flag;
/* lock one axis */
if (is_horizontal) {
@@ -1473,7 +1860,7 @@ static void ui_panel_drag_collapse(bContext *C,
/* set up rect to match header size */
rect.ymin = rect.ymax;
rect.ymax = rect.ymin + PNL_HEADER;
- if (pa->flag & PNL_CLOSEDX) {
+ if (panel->flag & PNL_CLOSEDX) {
rect.xmax = rect.xmin + PNL_HEADER;
}
@@ -1481,19 +1868,21 @@ static void ui_panel_drag_collapse(bContext *C,
if (BLI_rctf_isect_segment(&rect, xy_a_block, xy_b_block)) {
/* force panel to close */
if (dragcol_data->was_first_open == true) {
- pa->flag |= (is_horizontal ? PNL_CLOSEDX : PNL_CLOSEDY);
+ panel->flag |= (is_horizontal ? PNL_CLOSEDX : PNL_CLOSEDY);
}
/* force panel to open */
else {
- pa->flag &= ~PNL_CLOSED;
+ panel->flag &= ~PNL_CLOSED;
}
- /* if pa->flag has changed this means a panel was opened/closed here */
- if (pa->flag != oldflag) {
- panel_activate_state(C, pa, PANEL_STATE_ANIMATION);
+ /* if panel->flag has changed this means a panel was opened/closed here */
+ if (panel->flag != oldflag) {
+ panel_activate_state(C, panel, PANEL_STATE_ANIMATION);
}
}
}
+ /* Update the instanced panel data expand flags with the changes made here. */
+ set_panels_list_data_expand_flag(C, region);
}
/**
@@ -1553,7 +1942,7 @@ static void ui_panel_drag_collapse_handler_add(const bContext *C, const bool was
static void ui_handle_panel_header(
const bContext *C, uiBlock *block, int mx, int my, int event, short ctrl, short shift)
{
- ScrArea *sa = CTX_wm_area(C);
+ ScrArea *area = CTX_wm_area(C);
ARegion *region = CTX_wm_region(C);
#ifdef USE_PIN_HIDDEN
const bool show_pin = UI_panel_category_is_visible(region) &&
@@ -1565,7 +1954,7 @@ static void ui_handle_panel_header(
const bool is_subpanel = (block->panel->type && block->panel->type->parent);
const bool show_drag = !is_subpanel;
- int align = panel_aligned(sa, region), button = 0;
+ int align = panel_aligned(area, region), button = 0;
rctf rect_drag, rect_pin;
float rect_leftmost;
@@ -1620,10 +2009,13 @@ static void ui_handle_panel_header(
}
else { /* collapse */
if (ctrl) {
- panels_collapse_all(sa, region, block->panel);
+ /* Only collapse all for parent panels. */
+ if (block->panel->type != NULL && block->panel->type->parent == NULL) {
+ panels_collapse_all(C, area, region, block->panel);
- /* reset the view - we don't want to display a view without content */
- UI_view2d_offset(&region->v2d, 0.0f, 1.0f);
+ /* reset the view - we don't want to display a view without content */
+ UI_view2d_offset(&region->v2d, 0.0f, 1.0f);
+ }
}
if (block->panel->flag & PNL_CLOSED) {
@@ -1655,6 +2047,8 @@ static void ui_handle_panel_header(
ui_panel_drag_collapse_handler_add(C, true);
}
}
+
+ set_panels_list_data_expand_flag(C, region);
}
if (align) {
@@ -2279,7 +2673,7 @@ int ui_handler_panel_region(bContext *C,
const uiBut *active_but)
{
uiBlock *block;
- Panel *pa;
+ Panel *panel;
int retval, mx, my;
bool has_category_tabs = UI_panel_category_is_visible(region);
@@ -2325,17 +2719,17 @@ int ui_handler_panel_region(bContext *C,
ui_window_to_block(region, block, &mx, &my);
/* checks for mouse position inside */
- pa = block->panel;
+ panel = block->panel;
- if (!pa) {
+ if (!panel) {
continue;
}
/* XXX - accessed freed panels when scripts reload, need to fix. */
- if (pa->type && pa->type->flag & PNL_NO_HEADER) {
+ if (panel->type && panel->type->flag & PNL_NO_HEADER) {
continue;
}
- mouse_state = ui_panel_mouse_state_get(block, pa, mx, my);
+ mouse_state = ui_panel_mouse_state_get(block, panel, mx, my);
/* XXX hardcoded key warning */
if (ELEM(mouse_state, PANEL_MOUSE_INSIDE_CONTENT, PANEL_MOUSE_INSIDE_HEADER) &&
@@ -2343,7 +2737,7 @@ int ui_handler_panel_region(bContext *C,
if (event->type == EVT_AKEY &&
((event->ctrl + event->oskey + event->shift + event->alt) == 0)) {
- if (pa->flag & PNL_CLOSEDY) {
+ if (panel->flag & PNL_CLOSEDY) {
if ((block->rect.ymax <= my) && (block->rect.ymax + PNL_HEADER >= my)) {
ui_handle_panel_header(C, block, mx, my, event->type, event->ctrl, event->shift);
}
@@ -2383,8 +2777,8 @@ int ui_handler_panel_region(bContext *C,
retval = WM_UI_HANDLER_BREAK;
break;
}
- else if ((mouse_state == PANEL_MOUSE_INSIDE_SCALE) && !(pa->flag & PNL_CLOSED)) {
- panel_activate_state(C, pa, PANEL_STATE_DRAG_SCALE);
+ else if ((mouse_state == PANEL_MOUSE_INSIDE_SCALE) && !(panel->flag & PNL_CLOSED)) {
+ panel_activate_state(C, panel, PANEL_STATE_DRAG_SCALE);
retval = WM_UI_HANDLER_BREAK;
break;
}
@@ -2400,7 +2794,7 @@ int ui_handler_panel_region(bContext *C,
/*XXX 2.50*/
#if 0
if (block->handler) {
- rem_blockhandler(sa, block->handler);
+ rem_blockhandler(area, block->handler);
ED_region_tag_redraw(region);
retval = WM_UI_HANDLER_BREAK;
}
@@ -2411,7 +2805,7 @@ int ui_handler_panel_region(bContext *C,
int zoom = 0;
/* if panel is closed, only zoom if mouse is over the header */
- if (pa->flag & (PNL_CLOSEDX | PNL_CLOSEDY)) {
+ if (panel->flag & (PNL_CLOSEDX | PNL_CLOSEDY)) {
if (inside_header) {
zoom = 1;
}
@@ -2421,11 +2815,11 @@ int ui_handler_panel_region(bContext *C,
}
if (zoom) {
- ScrArea *sa = CTX_wm_area(C);
- SpaceLink *sl = sa->spacedata.first;
+ ScrArea *area = CTX_wm_area(C);
+ SpaceLink *sl = area->spacedata.first;
- if (sa->spacetype != SPACE_PROPERTIES) {
- if (!(pa->control & UI_PNL_SCALE)) {
+ if (area->spacetype != SPACE_PROPERTIES) {
+ if (!(panel->control & UI_PNL_SCALE)) {
if (event->type == PADPLUSKEY) {
sl->blockscale += 0.1;
}
@@ -2458,9 +2852,9 @@ static int ui_handler_panel(bContext *C, const wmEvent *event, void *userdata)
/* verify if we can stop */
if (event->type == LEFTMOUSE && event->val == KM_RELEASE) {
- ScrArea *sa = CTX_wm_area(C);
+ ScrArea *area = CTX_wm_area(C);
ARegion *region = CTX_wm_region(C);
- int align = panel_aligned(sa, region);
+ int align = panel_aligned(area, region);
if (align) {
panel_activate_state(C, panel, PANEL_STATE_ANIMATION);
@@ -2495,14 +2889,32 @@ static int ui_handler_panel(bContext *C, const wmEvent *event, void *userdata)
static void ui_handler_remove_panel(bContext *C, void *userdata)
{
- Panel *pa = userdata;
+ Panel *panel = userdata;
- panel_activate_state(C, pa, PANEL_STATE_EXIT);
+ panel_activate_state(C, panel, PANEL_STATE_EXIT);
}
-static void panel_activate_state(const bContext *C, Panel *pa, uiHandlePanelState state)
+/**
+ * Set selection state for a panel and its subpanels. The subpanels need to know they are selected
+ * too so they can be drawn above their parent when it is dragged.
+ */
+static void set_panel_selection(Panel *panel, bool value)
{
- uiHandlePanelData *data = pa->activedata;
+ if (value) {
+ panel->flag |= PNL_SELECT;
+ }
+ else {
+ panel->flag &= ~PNL_SELECT;
+ }
+
+ LISTBASE_FOREACH (Panel *, child, &panel->children) {
+ set_panel_selection(child, value);
+ }
+}
+
+static void panel_activate_state(const bContext *C, Panel *panel, uiHandlePanelState state)
+{
+ uiHandlePanelData *data = panel->activedata;
wmWindow *win = CTX_wm_window(C);
ARegion *region = CTX_wm_region(C);
@@ -2510,6 +2922,8 @@ static void panel_activate_state(const bContext *C, Panel *pa, uiHandlePanelStat
return;
}
+ bool was_drag_drop = (data && data->state == PANEL_STATE_DRAG);
+
if (state == PANEL_STATE_EXIT || state == PANEL_STATE_ANIMATION) {
if (data && data->state != PANEL_STATE_ANIMATION) {
/* XXX:
@@ -2522,10 +2936,10 @@ static void panel_activate_state(const bContext *C, Panel *pa, uiHandlePanelStat
check_panel_overlap(region, NULL); /* clears */
}
- pa->flag &= ~PNL_SELECT;
+ set_panel_selection(panel, false);
}
else {
- pa->flag |= PNL_SELECT;
+ set_panel_selection(panel, true);
}
if (data && data->animtimer) {
@@ -2535,18 +2949,18 @@ static void panel_activate_state(const bContext *C, Panel *pa, uiHandlePanelStat
if (state == PANEL_STATE_EXIT) {
MEM_freeN(data);
- pa->activedata = NULL;
+ panel->activedata = NULL;
WM_event_remove_ui_handler(
- &win->modalhandlers, ui_handler_panel, ui_handler_remove_panel, pa, false);
+ &win->modalhandlers, ui_handler_panel, ui_handler_remove_panel, panel, false);
}
else {
if (!data) {
data = MEM_callocN(sizeof(uiHandlePanelData), "uiHandlePanelData");
- pa->activedata = data;
+ panel->activedata = data;
WM_event_add_ui_handler(
- C, &win->modalhandlers, ui_handler_panel, ui_handler_remove_panel, pa, 0);
+ C, &win->modalhandlers, ui_handler_panel, ui_handler_remove_panel, panel, 0);
}
if (ELEM(state, PANEL_STATE_ANIMATION, PANEL_STATE_DRAG)) {
@@ -2556,11 +2970,17 @@ static void panel_activate_state(const bContext *C, Panel *pa, uiHandlePanelStat
data->state = state;
data->startx = win->eventstate->x;
data->starty = win->eventstate->y;
- data->startofsx = pa->ofsx;
- data->startofsy = pa->ofsy;
- data->startsizex = pa->sizex;
- data->startsizey = pa->sizey;
+ data->startofsx = panel->ofsx;
+ data->startofsy = panel->ofsy;
+ data->startsizex = panel->sizex;
+ data->startsizey = panel->sizey;
data->starttime = PIL_check_seconds_timer();
+
+ /* Remember drag drop state even when animating to the aligned position after dragging. */
+ data->is_drag_drop = was_drag_drop;
+ if (state == PANEL_STATE_DRAG) {
+ data->is_drag_drop = true;
+ }
}
ED_region_tag_redraw(region);
diff --git a/source/blender/editors/interface/interface_query.c b/source/blender/editors/interface/interface_query.c
index de68b192f67..6d05fe15f97 100644
--- a/source/blender/editors/interface/interface_query.c
+++ b/source/blender/editors/interface/interface_query.c
@@ -20,6 +20,7 @@
* Utilities to inspect the interface, extract information.
*/
+#include "BLI_listbase.h"
#include "BLI_math.h"
#include "BLI_rect.h"
#include "BLI_utildefines.h"
@@ -160,6 +161,21 @@ bool UI_but_has_tooltip_label(const uiBut *but)
return false;
}
+int ui_but_icon(const uiBut *but)
+{
+ if (!(but->flag & UI_HAS_ICON)) {
+ return ICON_NONE;
+ }
+
+ /* Consecutive icons can be toggle between. */
+ if (but->drawflag & UI_BUT_ICON_REVERSE) {
+ return but->icon - but->iconadd;
+ }
+ else {
+ return but->icon + but->iconadd;
+ }
+}
+
/** \} */
/* -------------------------------------------------------------------- */
@@ -260,7 +276,7 @@ uiBut *ui_but_find_mouse_over_ex(ARegion *region, const int x, const int y, cons
if (!ui_region_contains_point_px(region, x, y)) {
return NULL;
}
- for (uiBlock *block = region->uiblocks.first; block; block = block->next) {
+ LISTBASE_FOREACH (uiBlock *, block, &region->uiblocks) {
float mx = x, my = y;
ui_window_to_block_fl(region, block, &mx, &my);
@@ -308,7 +324,7 @@ uiBut *ui_but_find_rect_over(const struct ARegion *region, const rcti *rect_px)
BLI_rctf_rcti_copy(&rect_px_fl, rect_px);
uiBut *butover = NULL;
- for (uiBlock *block = region->uiblocks.first; block; block = block->next) {
+ LISTBASE_FOREACH (uiBlock *, block, &region->uiblocks) {
rctf rect_block;
ui_window_to_block_rctf(region, block, &rect_block, &rect_px_fl);
@@ -339,7 +355,7 @@ uiBut *ui_list_find_mouse_over_ex(ARegion *region, int x, int y)
if (!ui_region_contains_point_px(region, x, y)) {
return NULL;
}
- for (uiBlock *block = region->uiblocks.first; block; block = block->next) {
+ LISTBASE_FOREACH (uiBlock *, block, &region->uiblocks) {
float mx = x, my = y;
ui_window_to_block_fl(region, block, &mx, &my);
for (uiBut *but = block->buttons.last; but; but = but->prev) {
@@ -516,7 +532,7 @@ uiBlock *ui_block_find_mouse_over_ex(const ARegion *region,
if (!ui_region_contains_point_px(region, x, y)) {
return NULL;
}
- for (uiBlock *block = region->uiblocks.first; block; block = block->next) {
+ LISTBASE_FOREACH (uiBlock *, block, &region->uiblocks) {
if (only_clip) {
if ((block->flag & UI_BLOCK_CLIP_EVENTS) == 0) {
continue;
@@ -544,8 +560,8 @@ uiBlock *ui_block_find_mouse_over(const ARegion *region, const wmEvent *event, b
uiBut *ui_region_find_active_but(ARegion *region)
{
- for (uiBlock *block = region->uiblocks.first; block; block = block->next) {
- for (uiBut *but = block->buttons.first; but; but = but->next) {
+ LISTBASE_FOREACH (uiBlock *, block, &region->uiblocks) {
+ LISTBASE_FOREACH (uiBut *, but, &block->buttons) {
if (but->active) {
return but;
}
@@ -557,8 +573,8 @@ uiBut *ui_region_find_active_but(ARegion *region)
uiBut *ui_region_find_first_but_test_flag(ARegion *region, int flag_include, int flag_exclude)
{
- for (uiBlock *block = region->uiblocks.first; block; block = block->next) {
- for (uiBut *but = block->buttons.first; but; but = but->next) {
+ LISTBASE_FOREACH (uiBlock *, block, &region->uiblocks) {
+ LISTBASE_FOREACH (uiBut *, but, &block->buttons) {
if (((but->flag & flag_include) == flag_include) && ((but->flag & flag_exclude) == 0)) {
return but;
}
@@ -632,7 +648,7 @@ bool ui_region_contains_rect_px(const ARegion *region, const rcti *rect_px)
/** Check if the cursor is over any popups. */
ARegion *ui_screen_region_find_mouse_over_ex(bScreen *screen, int x, int y)
{
- for (ARegion *region = screen->regionbase.first; region; region = region->next) {
+ LISTBASE_FOREACH (ARegion *, region, &screen->regionbase) {
rcti winrct;
ui_region_winrct_get_no_margin(region, &winrct);
diff --git a/source/blender/editors/interface/interface_region_color_picker.c b/source/blender/editors/interface/interface_region_color_picker.c
index ecdcd575d5c..f9873f8b96f 100644
--- a/source/blender/editors/interface/interface_region_color_picker.c
+++ b/source/blender/editors/interface/interface_region_color_picker.c
@@ -332,7 +332,7 @@ static void ui_popup_close_cb(bContext *UNUSED(C), void *bt1, void *UNUSED(arg))
static void ui_colorpicker_hide_reveal(uiBlock *block, enum ePickerType colormode)
{
/* tag buttons */
- for (uiBut *bt = block->buttons.first; bt; bt = bt->next) {
+ LISTBASE_FOREACH (uiBut *, bt, &block->buttons) {
if ((bt->func == ui_colorpicker_rna_cb) && (bt->type == UI_BTYPE_NUM_SLIDER) &&
(bt->rnaindex != 3)) {
/* RGB sliders (color circle and alpha are always shown) */
diff --git a/source/blender/editors/interface/interface_region_hud.c b/source/blender/editors/interface/interface_region_hud.c
index f77739b5114..1f8af7b9e6e 100644
--- a/source/blender/editors/interface/interface_region_hud.c
+++ b/source/blender/editors/interface/interface_region_hud.c
@@ -74,15 +74,15 @@ static bool last_redo_poll(const bContext *C, short region_type)
* operator call. Otherwise we would be polling the operator with the
* wrong context.
*/
- ScrArea *sa = CTX_wm_area(C);
- ARegion *ar_op = (region_type != -1) ? BKE_area_find_region_type(sa, region_type) : NULL;
- ARegion *ar_prev = CTX_wm_region(C);
- CTX_wm_region_set((bContext *)C, ar_op);
+ ScrArea *area = CTX_wm_area(C);
+ ARegion *region_op = (region_type != -1) ? BKE_area_find_region_type(area, region_type) : NULL;
+ ARegion *region_prev = CTX_wm_region(C);
+ CTX_wm_region_set((bContext *)C, region_op);
if (WM_operator_repeat_check(C, op) && WM_operator_check_ui_empty(op->type) == false) {
success = WM_operator_poll((bContext *)C, op->type);
}
- CTX_wm_region_set((bContext *)C, ar_prev);
+ CTX_wm_region_set((bContext *)C, region_prev);
}
return success;
}
@@ -103,8 +103,8 @@ static void hud_region_hide(ARegion *region)
static bool hud_panel_operator_redo_poll(const bContext *C, PanelType *UNUSED(pt))
{
- ScrArea *sa = CTX_wm_area(C);
- ARegion *region = BKE_area_find_region_type(sa, RGN_TYPE_HUD);
+ ScrArea *area = CTX_wm_area(C);
+ ARegion *region = BKE_area_find_region_type(area, RGN_TYPE_HUD);
if (region != NULL) {
struct HudRegionData *hrd = region->regiondata;
if (hrd != NULL) {
@@ -114,22 +114,22 @@ static bool hud_panel_operator_redo_poll(const bContext *C, PanelType *UNUSED(pt
return false;
}
-static void hud_panel_operator_redo_draw_header(const bContext *C, Panel *pa)
+static void hud_panel_operator_redo_draw_header(const bContext *C, Panel *panel)
{
wmOperator *op = WM_operator_last_redo(C);
- BLI_strncpy(pa->drawname, WM_operatortype_name(op->type, op->ptr), sizeof(pa->drawname));
+ BLI_strncpy(panel->drawname, WM_operatortype_name(op->type, op->ptr), sizeof(panel->drawname));
}
-static void hud_panel_operator_redo_draw(const bContext *C, Panel *pa)
+static void hud_panel_operator_redo_draw(const bContext *C, Panel *panel)
{
wmOperator *op = WM_operator_last_redo(C);
if (op == NULL) {
return;
}
if (!WM_operator_check_ui_enabled(C, op->type->name)) {
- uiLayoutSetEnabled(pa->layout, false);
+ uiLayoutSetEnabled(panel->layout, false);
}
- uiLayout *col = uiLayoutColumn(pa->layout, false);
+ uiLayout *col = uiLayoutColumn(panel->layout, false);
uiTemplateOperatorRedoProperties(col, C);
}
@@ -177,11 +177,13 @@ static void hud_region_layout(const bContext *C, ARegion *region)
return;
}
+ ScrArea *area = CTX_wm_area(C);
int size_y = region->sizey;
ED_region_panels_layout(C, region);
- if (region->panels.first && (region->sizey != size_y)) {
+ if (region->panels.first &&
+ ((area->flag & AREA_FLAG_REGION_SIZE_UPDATE) || (region->sizey != size_y))) {
int winx_new = UI_DPI_FAC * (region->sizex + 0.5f);
int winy_new = UI_DPI_FAC * (region->sizey + 0.5f);
View2D *v2d = &region->v2d;
@@ -250,25 +252,25 @@ ARegionType *ED_area_type_hud(int space_type)
return art;
}
-static ARegion *hud_region_add(ScrArea *sa)
+static ARegion *hud_region_add(ScrArea *area)
{
ARegion *region = MEM_callocN(sizeof(ARegion), "area region");
- ARegion *ar_win = BKE_area_find_region_type(sa, RGN_TYPE_WINDOW);
- if (ar_win) {
- BLI_insertlinkbefore(&sa->regionbase, ar_win, region);
+ ARegion *region_win = BKE_area_find_region_type(area, RGN_TYPE_WINDOW);
+ if (region_win) {
+ BLI_insertlinkbefore(&area->regionbase, region_win, region);
}
else {
- BLI_addtail(&sa->regionbase, region);
+ BLI_addtail(&area->regionbase, region);
}
region->regiontype = RGN_TYPE_HUD;
region->alignment = RGN_ALIGN_FLOAT;
region->overlap = true;
region->flag |= RGN_FLAG_DYNAMIC_SIZE;
- if (ar_win) {
+ if (region_win) {
float x, y;
- UI_view2d_scroller_size_get(&ar_win->v2d, &x, &y);
+ UI_view2d_scroller_size_get(&region_win->v2d, &x, &y);
region->runtime.offset_x = x;
region->runtime.offset_y = y;
}
@@ -276,18 +278,18 @@ static ARegion *hud_region_add(ScrArea *sa)
return region;
}
-void ED_area_type_hud_clear(wmWindowManager *wm, ScrArea *sa_keep)
+void ED_area_type_hud_clear(wmWindowManager *wm, ScrArea *area_keep)
{
- for (wmWindow *win = wm->windows.first; win; win = win->next) {
+ LISTBASE_FOREACH (wmWindow *, win, &wm->windows) {
bScreen *screen = WM_window_get_active_screen(win);
- for (ScrArea *sa = screen->areabase.first; sa; sa = sa->next) {
- if (sa != sa_keep) {
- for (ARegion *region = sa->regionbase.first; region; region = region->next) {
+ LISTBASE_FOREACH (ScrArea *, area, &screen->areabase) {
+ if (area != area_keep) {
+ LISTBASE_FOREACH (ARegion *, region, &area->regionbase) {
if (region->regiontype == RGN_TYPE_HUD) {
if ((region->flag & RGN_FLAG_HIDDEN) == 0) {
hud_region_hide(region);
ED_region_tag_redraw(region);
- ED_area_tag_redraw(sa);
+ ED_area_tag_redraw(area);
}
}
}
@@ -296,17 +298,17 @@ void ED_area_type_hud_clear(wmWindowManager *wm, ScrArea *sa_keep)
}
}
-void ED_area_type_hud_ensure(bContext *C, ScrArea *sa)
+void ED_area_type_hud_ensure(bContext *C, ScrArea *area)
{
wmWindowManager *wm = CTX_wm_manager(C);
- ED_area_type_hud_clear(wm, sa);
+ ED_area_type_hud_clear(wm, area);
- ARegionType *art = BKE_regiontype_from_id(sa->type, RGN_TYPE_HUD);
+ ARegionType *art = BKE_regiontype_from_id(area->type, RGN_TYPE_HUD);
if (art == NULL) {
return;
}
- ARegion *region = BKE_area_find_region_type(sa, RGN_TYPE_HUD);
+ ARegion *region = BKE_area_find_region_type(area, RGN_TYPE_HUD);
if (region && (region->flag & RGN_FLAG_HIDDEN_BY_USER)) {
/* The region is intentionally hidden by the user, don't show it. */
@@ -316,9 +318,9 @@ void ED_area_type_hud_ensure(bContext *C, ScrArea *sa)
bool init = false;
bool was_hidden = region == NULL || region->visible == false;
- ARegion *ar_op = CTX_wm_region(C);
- BLI_assert((ar_op == NULL) || (ar_op->regiontype != RGN_TYPE_HUD));
- if (!last_redo_poll(C, ar_op ? ar_op->regiontype : -1)) {
+ ARegion *region_op = CTX_wm_region(C);
+ BLI_assert((region_op == NULL) || (region_op->regiontype != RGN_TYPE_HUD));
+ if (!last_redo_poll(C, region_op ? region_op->regiontype : -1)) {
if (region) {
ED_region_tag_redraw(region);
hud_region_hide(region);
@@ -328,18 +330,19 @@ void ED_area_type_hud_ensure(bContext *C, ScrArea *sa)
if (region == NULL) {
init = true;
- region = hud_region_add(sa);
+ region = hud_region_add(area);
region->type = art;
}
/* Let 'ED_area_update_region_sizes' do the work of placing the region.
* Otherwise we could set the 'region->winrct' & 'region->winx/winy' here. */
if (init) {
- sa->flag |= AREA_FLAG_REGION_SIZE_UPDATE;
+ area->flag |= AREA_FLAG_REGION_SIZE_UPDATE;
}
else {
if (region->flag & RGN_FLAG_HIDDEN) {
- sa->flag |= AREA_FLAG_REGION_SIZE_UPDATE;
+ /* Also forces recalculating HUD size in hud_region_layout(). */
+ area->flag |= AREA_FLAG_REGION_SIZE_UPDATE;
}
region->flag &= ~RGN_FLAG_HIDDEN;
}
@@ -350,8 +353,8 @@ void ED_area_type_hud_ensure(bContext *C, ScrArea *sa)
hrd = MEM_callocN(sizeof(*hrd), __func__);
region->regiondata = hrd;
}
- if (ar_op) {
- hrd->regionid = ar_op->regiontype;
+ if (region_op) {
+ hrd->regionid = region_op->regiontype;
}
else {
hrd->regionid = -1;
@@ -361,7 +364,7 @@ void ED_area_type_hud_ensure(bContext *C, ScrArea *sa)
if (init) {
/* This is needed or 'winrct' will be invalid. */
wmWindow *win = CTX_wm_window(C);
- ED_area_update_region_sizes(wm, win, sa);
+ ED_area_update_region_sizes(wm, win, area);
}
ED_region_floating_initialize(region);
@@ -380,7 +383,7 @@ void ED_area_type_hud_ensure(bContext *C, ScrArea *sa)
/* We shouldn't need to do this every time :S */
/* XXX, this is evil! - it also makes the menu show on first draw. :( */
if (region->visible) {
- ARegion *ar_prev = CTX_wm_region(C);
+ ARegion *region_prev = CTX_wm_region(C);
CTX_wm_region_set((bContext *)C, region);
hud_region_layout(C, region);
if (was_hidden) {
@@ -391,7 +394,7 @@ void ED_area_type_hud_ensure(bContext *C, ScrArea *sa)
.ymax = region->winy,
};
}
- CTX_wm_region_set((bContext *)C, ar_prev);
+ CTX_wm_region_set((bContext *)C, region_prev);
}
region->visible = !((region->flag & RGN_FLAG_HIDDEN) || (region->flag & RGN_FLAG_TOO_SMALL));
diff --git a/source/blender/editors/interface/interface_region_menu_popup.c b/source/blender/editors/interface/interface_region_menu_popup.c
index b3c10e8d6b8..3e34b7f3f8a 100644
--- a/source/blender/editors/interface/interface_region_menu_popup.c
+++ b/source/blender/editors/interface/interface_region_menu_popup.c
@@ -88,11 +88,11 @@ int ui_but_menu_step(uiBut *but, int direction)
return 0;
}
-static uint ui_popup_string_hash(const char *str)
+static uint ui_popup_string_hash(const char *str, const bool use_sep)
{
/* sometimes button contains hotkey, sometimes not, strip for proper compare */
int hash;
- const char *delimit = strrchr(str, UI_SEP_CHAR);
+ const char *delimit = use_sep ? strrchr(str, UI_SEP_CHAR) : NULL;
if (delimit) {
hash = BLI_ghashutil_strhash_n(str, delimit - str);
@@ -126,13 +126,13 @@ static uiBut *ui_popup_menu_memory__internal(uiBlock *block, uiBut *but)
if (but) {
/* set */
- mem[hash_mod] = ui_popup_string_hash(but->str);
+ mem[hash_mod] = ui_popup_string_hash(but->str, but->flag & UI_BUT_HAS_SEP_CHAR);
return NULL;
}
else {
/* get */
for (but = block->buttons.first; but; but = but->next) {
- if (ui_popup_string_hash(but->str) == mem[hash_mod]) {
+ if (mem[hash_mod] == ui_popup_string_hash(but->str, but->flag & UI_BUT_HAS_SEP_CHAR)) {
return but;
}
}
@@ -276,17 +276,17 @@ static uiBlock *ui_block_func_POPUP(bContext *C, uiPopupBlockHandle *handle, voi
else {
/* for a header menu we set the direction automatic */
if (!pup->slideout && flip) {
- ScrArea *sa = CTX_wm_area(C);
+ ScrArea *area = CTX_wm_area(C);
ARegion *region = CTX_wm_region(C);
- if (sa && region) {
+ if (area && region) {
if (ELEM(region->regiontype, RGN_TYPE_HEADER, RGN_TYPE_TOOL_HEADER)) {
- if (RGN_ALIGN_ENUM_FROM_MASK(ED_area_header_alignment(sa)) == RGN_ALIGN_BOTTOM) {
+ if (RGN_ALIGN_ENUM_FROM_MASK(ED_area_header_alignment(area)) == RGN_ALIGN_BOTTOM) {
UI_block_direction_set(block, UI_DIR_UP);
UI_block_order_flip(block);
}
}
if (region->regiontype == RGN_TYPE_FOOTER) {
- if (RGN_ALIGN_ENUM_FROM_MASK(ED_area_footer_alignment(sa)) == RGN_ALIGN_BOTTOM) {
+ if (RGN_ALIGN_ENUM_FROM_MASK(ED_area_footer_alignment(area)) == RGN_ALIGN_BOTTOM) {
UI_block_direction_set(block, UI_DIR_UP);
UI_block_order_flip(block);
}
@@ -581,21 +581,18 @@ int UI_popup_menu_invoke(bContext *C, const char *idname, ReportList *reports)
/** \name Popup Block API
* \{ */
-void UI_popup_block_invoke_ex(bContext *C,
- uiBlockCreateFunc func,
- void *arg,
- void (*arg_free)(void *arg),
- const char *opname,
- int opcontext)
+void UI_popup_block_invoke_ex(
+ bContext *C, uiBlockCreateFunc func, void *arg, void (*arg_free)(void *arg), bool can_refresh)
{
wmWindow *window = CTX_wm_window(C);
uiPopupBlockHandle *handle;
handle = ui_popup_block_create(C, NULL, NULL, func, NULL, arg, arg_free);
handle->popup = true;
- handle->can_refresh = true;
- handle->optype = (opname) ? WM_operatortype_find(opname, 0) : NULL;
- handle->opcontext = opcontext;
+
+ /* It can be useful to disable refresh (even though it will work)
+ * as this exists text fields which can be disruptive if refresh isn't needed. */
+ handle->can_refresh = can_refresh;
UI_popup_handlers_add(C, &window->modalhandlers, handle, 0);
UI_block_active_only_flagged_buttons(C, handle->region, handle->region->uiblocks.first);
@@ -607,7 +604,7 @@ void UI_popup_block_invoke(bContext *C,
void *arg,
void (*arg_free)(void *arg))
{
- UI_popup_block_invoke_ex(C, func, arg, arg_free, NULL, WM_OP_INVOKE_DEFAULT);
+ UI_popup_block_invoke_ex(C, func, arg, arg_free, true);
}
void UI_popup_block_ex(bContext *C,
@@ -669,7 +666,7 @@ void UI_popup_block_close(bContext *C, wmWindow *win, uiBlock *block)
/* In the case we have nested popups,
* closing one may need to redraw another, see: T48874 */
- for (ARegion *region = screen->regionbase.first; region; region = region->next) {
+ LISTBASE_FOREACH (ARegion *, region, &screen->regionbase) {
ED_region_tag_refresh_ui(region);
}
}
@@ -678,8 +675,8 @@ void UI_popup_block_close(bContext *C, wmWindow *win, uiBlock *block)
bool UI_popup_block_name_exists(const bScreen *screen, const char *name)
{
- for (const ARegion *region = screen->regionbase.first; region; region = region->next) {
- for (const uiBlock *block = region->uiblocks.first; block; block = block->next) {
+ LISTBASE_FOREACH (const ARegion *, region, &screen->regionbase) {
+ LISTBASE_FOREACH (const uiBlock *, block, &region->uiblocks) {
if (STREQ(block->name, name)) {
return true;
}
diff --git a/source/blender/editors/interface/interface_region_popover.c b/source/blender/editors/interface/interface_region_popover.c
index b889f1d6d01..0ad7e570e80 100644
--- a/source/blender/editors/interface/interface_region_popover.c
+++ b/source/blender/editors/interface/interface_region_popover.c
@@ -171,7 +171,7 @@ static uiBlock *ui_block_func_POPOVER(bContext *C, uiPopupBlockHandle *handle, v
}
if (!slideout) {
- ScrArea *sa = CTX_wm_area(C);
+ ScrArea *area = CTX_wm_area(C);
ARegion *region = CTX_wm_region(C);
if (region && region->panels.first) {
@@ -180,14 +180,14 @@ static uiBlock *ui_block_func_POPOVER(bContext *C, uiPopupBlockHandle *handle, v
UI_block_direction_set(block, UI_DIR_UP | UI_DIR_CENTER_X);
}
/* Prefer popover from header to be positioned into the editor. */
- else if (sa && region) {
+ else if (area && region) {
if (ELEM(region->regiontype, RGN_TYPE_HEADER, RGN_TYPE_TOOL_HEADER)) {
- if (RGN_ALIGN_ENUM_FROM_MASK(ED_area_header_alignment(sa)) == RGN_ALIGN_BOTTOM) {
+ if (RGN_ALIGN_ENUM_FROM_MASK(ED_area_header_alignment(area)) == RGN_ALIGN_BOTTOM) {
UI_block_direction_set(block, UI_DIR_UP | UI_DIR_CENTER_X);
}
}
if (region->regiontype == RGN_TYPE_FOOTER) {
- if (RGN_ALIGN_ENUM_FROM_MASK(ED_area_footer_alignment(sa)) == RGN_ALIGN_BOTTOM) {
+ if (RGN_ALIGN_ENUM_FROM_MASK(ED_area_footer_alignment(area)) == RGN_ALIGN_BOTTOM) {
UI_block_direction_set(block, UI_DIR_UP | UI_DIR_CENTER_X);
}
}
diff --git a/source/blender/editors/interface/interface_region_popup.c b/source/blender/editors/interface/interface_region_popup.c
index ba9a5026ce3..2ad7e517c60 100644
--- a/source/blender/editors/interface/interface_region_popup.c
+++ b/source/blender/editors/interface/interface_region_popup.c
@@ -118,7 +118,7 @@ static void ui_popup_block_position(wmWindow *window,
if (block->buttons.first) {
BLI_rctf_init_minmax(&block->rect);
- for (uiBut *bt = block->buttons.first; bt; bt = bt->next) {
+ LISTBASE_FOREACH (uiBut *, bt, &block->buttons) {
if (block->content_hints & UI_BLOCK_CONTAINS_SUBMENU_BUT) {
bt->rect.xmax += UI_MENU_SUBMENU_PADDING;
}
@@ -294,7 +294,7 @@ static void ui_popup_block_position(wmWindow *window,
}
/* Apply offset, buttons in window coords. */
- for (uiBut *bt = block->buttons.first; bt; bt = bt->next) {
+ LISTBASE_FOREACH (uiBut *, bt, &block->buttons) {
ui_block_to_window_rctf(butregion, but->block, &bt->rect, &bt->rect);
BLI_rctf_translate(&bt->rect, offset_x, offset_y);
@@ -420,7 +420,7 @@ static void ui_block_region_draw(const bContext *C, ARegion *region)
* Use to refresh centered popups on screen resizing (for splash).
*/
static void ui_block_region_popup_window_listener(wmWindow *UNUSED(win),
- ScrArea *UNUSED(sa),
+ ScrArea *UNUSED(area),
ARegion *region,
wmNotifier *wmn,
const Scene *UNUSED(scene))
@@ -525,36 +525,36 @@ void ui_popup_block_scrolltest(uiBlock *block)
static void ui_popup_block_remove(bContext *C, uiPopupBlockHandle *handle)
{
wmWindow *ctx_win = CTX_wm_window(C);
- ScrArea *ctx_sa = CTX_wm_area(C);
- ARegion *ctx_ar = CTX_wm_region(C);
+ ScrArea *ctx_area = CTX_wm_area(C);
+ ARegion *ctx_region = CTX_wm_region(C);
wmWindowManager *wm = CTX_wm_manager(C);
wmWindow *win = ctx_win;
- bScreen *sc = CTX_wm_screen(C);
+ bScreen *screen = CTX_wm_screen(C);
/* There may actually be a different window active than the one showing the popup, so lookup real
* one. */
- if (BLI_findindex(&sc->regionbase, handle->region) == -1) {
+ if (BLI_findindex(&screen->regionbase, handle->region) == -1) {
for (win = wm->windows.first; win; win = win->next) {
- sc = WM_window_get_active_screen(win);
- if (BLI_findindex(&sc->regionbase, handle->region) != -1) {
+ screen = WM_window_get_active_screen(win);
+ if (BLI_findindex(&screen->regionbase, handle->region) != -1) {
break;
}
}
}
- BLI_assert(win && sc);
+ BLI_assert(win && screen);
CTX_wm_window_set(C, win);
- ui_region_temp_remove(C, sc, handle->region);
+ ui_region_temp_remove(C, screen, handle->region);
/* Reset context (area and region were NULL'ed when chaning context window). */
CTX_wm_window_set(C, ctx_win);
- CTX_wm_area_set(C, ctx_sa);
- CTX_wm_region_set(C, ctx_ar);
+ CTX_wm_area_set(C, ctx_area);
+ CTX_wm_region_set(C, ctx_region);
/* reset to region cursor (only if there's not another menu open) */
- if (BLI_listbase_is_empty(&sc->regionbase)) {
+ if (BLI_listbase_is_empty(&screen->regionbase)) {
win->tag_cursor_refresh = true;
}
@@ -698,7 +698,7 @@ uiBlock *ui_popup_block_refresh(bContext *C,
/* lastly set the buttons at the center of the pie menu, ready for animation */
if (U.pie_animation_timeout > 0) {
- for (uiBut *but_iter = block->buttons.first; but_iter; but_iter = but_iter->next) {
+ LISTBASE_FOREACH (uiBut *, but_iter, &block->buttons) {
if (but_iter->pie_dir != UI_RADIAL_NONE) {
BLI_rctf_recenter(&but_iter->rect, UNPACK2(block->pie_data.pie_center_spawned));
}
@@ -742,7 +742,7 @@ uiBlock *ui_popup_block_refresh(bContext *C,
/* apply scroll offset */
if (handle->scrolloffset != 0.0f) {
- for (uiBut *bt = block->buttons.first; bt; bt = bt->next) {
+ LISTBASE_FOREACH (uiBut *, bt, &block->buttons) {
bt->rect.ymin += handle->scrolloffset;
bt->rect.ymax += handle->scrolloffset;
}
@@ -846,7 +846,7 @@ void ui_popup_block_free(bContext *C, uiPopupBlockHandle *handle)
* then close the popover too. We could extend this to other popup types too. */
ARegion *region = handle->popup_create_vars.butregion;
if (region != NULL) {
- for (uiBlock *block = region->uiblocks.first; block; block = block->next) {
+ LISTBASE_FOREACH (uiBlock *, block, &region->uiblocks) {
if (block->handle && (block->flag & UI_BLOCK_POPOVER) &&
(block->flag & UI_BLOCK_KEEP_OPEN) == 0) {
uiPopupBlockHandle *menu = block->handle;
diff --git a/source/blender/editors/interface/interface_region_search.c b/source/blender/editors/interface/interface_region_search.c
index 48779fd86dc..0007f6ab9a2 100644
--- a/source/blender/editors/interface/interface_region_search.c
+++ b/source/blender/editors/interface/interface_region_search.c
@@ -28,12 +28,14 @@
#include <stdlib.h>
#include <string.h>
+#include "DNA_ID.h"
#include "MEM_guardedalloc.h"
#include "DNA_userdef_types.h"
#include "BLI_math.h"
+#include "BLI_listbase.h"
#include "BLI_rect.h"
#include "BLI_string.h"
#include "BLI_utildefines.h"
@@ -89,9 +91,14 @@ typedef struct uiSearchboxData {
bool noback;
/** draw thumbnail previews, rather than list */
bool preview;
- /** use the UI_SEP_CHAR char for splitting shortcuts (good for operators, bad for data) */
+ /** Use the #UI_SEP_CHAR char for splitting shortcuts (good for operators, bad for data). */
bool use_sep;
int prv_rows, prv_cols;
+ /**
+ * Show the active icon and text after the last instance of this string.
+ * Used so we can show leading text to menu items less prominently (not related to 'use_sep').
+ */
+ const char *sep_string;
} uiSearchboxData;
#define SEARCH_ITEMS 10
@@ -147,7 +154,8 @@ bool UI_search_item_add(uiSearchItems *items, const char *name, void *poin, int
/* Limit flags that can be set so flags such as 'UI_SELECT' aren't accidentally set
* which will cause problems, add others as needed. */
- BLI_assert((state & ~(UI_BUT_DISABLED | UI_BUT_INACTIVE | UI_BUT_REDALERT)) == 0);
+ BLI_assert(
+ (state & ~(UI_BUT_DISABLED | UI_BUT_INACTIVE | UI_BUT_REDALERT | UI_BUT_HAS_SEP_CHAR)) == 0);
if (items->states) {
items->states[items->totitem] = state;
}
@@ -289,10 +297,31 @@ bool ui_searchbox_apply(uiBut *but, ARegion *region)
}
}
-void ui_searchbox_event(bContext *C, ARegion *region, uiBut *but, const wmEvent *event)
+static struct ARegion *wm_searchbox_tooltip_init(struct bContext *C,
+ struct ARegion *region,
+ int *UNUSED(r_pass),
+ double *UNUSED(pass_delay),
+ bool *r_exit_on_event)
+{
+ *r_exit_on_event = true;
+
+ LISTBASE_FOREACH (uiBlock *, block, &region->uiblocks) {
+ LISTBASE_FOREACH (uiBut *, but, &block->buttons) {
+ if (but->search && but->search->tooltip_fn) {
+ return but->search->tooltip_fn(C, region, but->search->arg, but->func_arg2);
+ }
+ }
+ }
+ return NULL;
+}
+
+bool ui_searchbox_event(
+ bContext *C, ARegion *region, uiBut *but, ARegion *butregion, const wmEvent *event)
{
uiSearchboxData *data = region->regiondata;
int type = event->type, val = event->val;
+ bool handled = false;
+ bool tooltip_timer_started = false;
if (type == MOUSEPAN) {
ui_pan_to_scroll(event, &type, &val);
@@ -302,12 +331,36 @@ void ui_searchbox_event(bContext *C, ARegion *region, uiBut *but, const wmEvent
case WHEELUPMOUSE:
case EVT_UPARROWKEY:
ui_searchbox_select(C, region, but, -1);
+ handled = true;
break;
case WHEELDOWNMOUSE:
case EVT_DOWNARROWKEY:
ui_searchbox_select(C, region, but, 1);
+ handled = true;
+ break;
+ case RIGHTMOUSE:
+ if (val) {
+ if (but->search->context_menu_fn) {
+ if (data->active != -1) {
+ /* Check the cursor is over the active element
+ * (a little confusing if this isn't the case, although it does work). */
+ rcti rect;
+ ui_searchbox_butrect(&rect, data, data->active);
+ if (BLI_rcti_isect_pt(
+ &rect, event->x - region->winrct.xmin, event->y - region->winrct.ymin)) {
+
+ void *active = data->items.pointers[data->active];
+ if (but->search->context_menu_fn(C, but->search->arg, active, event)) {
+ handled = true;
+ }
+ }
+ }
+ }
+ }
break;
- case MOUSEMOVE:
+ case MOUSEMOVE: {
+ bool is_inside = false;
+
if (BLI_rcti_isect_pt(&region->winrct, event->x, event->y)) {
rcti rect;
int a;
@@ -316,16 +369,46 @@ void ui_searchbox_event(bContext *C, ARegion *region, uiBut *but, const wmEvent
ui_searchbox_butrect(&rect, data, a);
if (BLI_rcti_isect_pt(
&rect, event->x - region->winrct.xmin, event->y - region->winrct.ymin)) {
+ is_inside = true;
if (data->active != a) {
data->active = a;
ui_searchbox_select(C, region, but, 0);
+ handled = true;
break;
}
}
}
}
+
+ if (U.flag & USER_TOOLTIPS) {
+ if (is_inside) {
+ if (data->active != -1) {
+ ScrArea *area = CTX_wm_area(C);
+ but->func_arg2 = data->items.pointers[data->active];
+ WM_tooltip_timer_init(C, CTX_wm_window(C), area, butregion, wm_searchbox_tooltip_init);
+ tooltip_timer_started = true;
+ }
+ }
+ }
+
break;
+ }
+ }
+
+ if (handled && (tooltip_timer_started == false)) {
+ wmWindow *win = CTX_wm_window(C);
+ WM_tooltip_clear(C, win);
}
+
+ return handled;
+}
+
+/** Wrap #uiButSearchUpdateFn callback. */
+static void ui_searchbox_update_fn(bContext *C, uiBut *but, const char *str, uiSearchItems *items)
+{
+ wmWindow *win = CTX_wm_window(C);
+ WM_tooltip_clear(C, win);
+ but->search->update_fn(C, but->search->arg, str, items);
}
/* region is the search box itself */
@@ -344,9 +427,9 @@ void ui_searchbox_update(bContext *C, ARegion *region, uiBut *but, const bool re
data->active = -1;
/* handle active */
- if (but->search_func && but->func_arg2) {
+ if (but->search->update_fn && but->func_arg2) {
data->items.active = but->func_arg2;
- but->search_func(C, but->search_arg, but->editstr, &data->items);
+ ui_searchbox_update_fn(C, but, but->editstr, &data->items);
data->items.active = NULL;
/* found active item, calculate real offset by centering it */
@@ -375,8 +458,8 @@ void ui_searchbox_update(bContext *C, ARegion *region, uiBut *but, const bool re
}
/* callback */
- if (but->search_func) {
- but->search_func(C, but->search_arg, but->editstr, &data->items);
+ if (but->search->update_fn) {
+ ui_searchbox_update_fn(C, but, but->editstr, &data->items);
}
/* handle case where editstr is equal to one of items */
@@ -410,7 +493,7 @@ int ui_searchbox_autocomplete(bContext *C, ARegion *region, uiBut *but, char *st
if (str[0]) {
data->items.autocpl = UI_autocomplete_begin(str, ui_but_string_get_max_length(but));
- but->search_func(C, but->search_arg, but->editstr, &data->items);
+ ui_searchbox_update_fn(C, but, but->editstr, &data->items);
match = UI_autocomplete_end(data->items.autocpl, str);
data->items.autocpl = NULL;
@@ -465,19 +548,50 @@ static void ui_searchbox_region_draw_cb(const bContext *C, ARegion *region)
}
}
else {
+ const int search_sep_len = data->sep_string ? strlen(data->sep_string) : 0;
/* draw items */
for (a = 0; a < data->items.totitem; a++) {
const int state = ((a == data->active) ? UI_ACTIVE : 0) | data->items.states[a];
+ char *name = data->items.names[a];
+ int icon = data->items.icons[a];
+ char *name_sep_test = NULL;
ui_searchbox_butrect(&rect, data, a);
/* widget itself */
- ui_draw_menu_item(&data->fstyle,
- &rect,
- data->items.names[a],
- data->items.icons[a],
- state,
- data->use_sep);
+ if ((search_sep_len == 0) ||
+ !(name_sep_test = strstr(data->items.names[a], data->sep_string))) {
+
+ /* Simple menu item. */
+ ui_draw_menu_item(&data->fstyle, &rect, name, icon, state, data->use_sep, NULL);
+ }
+ else {
+ /* Split menu item, faded text before the separator. */
+ char *name_sep = NULL;
+ do {
+ name_sep = name_sep_test;
+ name_sep_test = strstr(name_sep + search_sep_len, data->sep_string);
+ } while (name_sep_test != NULL);
+
+ name_sep += search_sep_len;
+ const char name_sep_prev = *name_sep;
+ *name_sep = '\0';
+ int name_width = 0;
+ ui_draw_menu_item(
+ &data->fstyle, &rect, name, 0, state | UI_BUT_INACTIVE, false, &name_width);
+ *name_sep = name_sep_prev;
+ rect.xmin += name_width;
+ rect.xmin += UI_UNIT_X / 4;
+
+ if (icon == ICON_BLANK1) {
+ icon = ICON_NONE;
+ rect.xmin -= UI_DPI_ICON_SIZE / 4;
+ }
+
+ /* The previous menu item draws the active selection. */
+ ui_draw_menu_item(
+ &data->fstyle, &rect, name_sep, icon, state & ~UI_ACTIVE, data->use_sep, NULL);
+ }
}
/* indicate more */
if (data->items.more) {
@@ -566,6 +680,7 @@ ARegion *ui_searchbox_create_generic(bContext *C, ARegion *butregion, uiBut *but
if (but->optype != NULL || (but->drawflag & UI_BUT_HAS_SHORTCUT) != 0) {
data->use_sep = true;
}
+ data->sep_string = but->search->sep_string;
/* compute position */
if (but->block->flag & UI_BLOCK_SEARCH_MENU) {
@@ -762,9 +877,10 @@ static void ui_searchbox_region_draw_cb__operator(const bContext *UNUSED(C), ARe
CTX_IFACE_(BLT_I18NCONTEXT_OPERATOR_DEFAULT, text_pre),
data->items.icons[a],
state,
- false);
+ false,
+ NULL);
ui_draw_menu_item(
- &data->fstyle, &rect_post, data->items.names[a], 0, state, data->use_sep);
+ &data->fstyle, &rect_post, data->items.names[a], 0, state, data->use_sep, NULL);
}
}
/* indicate more */
@@ -842,7 +958,7 @@ void ui_but_search_refresh(uiBut *but)
items->names[x1] = MEM_callocN(but->hardmax + 1, "search names");
}
- but->search_func(but->block->evil_C, but->search_arg, but->drawstr, items);
+ ui_searchbox_update_fn(but->block->evil_C, but, but->drawstr, items);
/* only redalert when we are sure of it, this can miss cases when >10 matches */
if (items->totitem == 0) {
diff --git a/source/blender/editors/interface/interface_region_tooltip.c b/source/blender/editors/interface/interface_region_tooltip.c
index cf8ff51eccf..b64f080d9cc 100644
--- a/source/blender/editors/interface/interface_region_tooltip.c
+++ b/source/blender/editors/interface/interface_region_tooltip.c
@@ -42,6 +42,7 @@
#include "DNA_brush_types.h"
#include "DNA_userdef_types.h"
+#include "BLI_listbase.h"
#include "BLI_math.h"
#include "BLI_rect.h"
#include "BLI_string.h"
@@ -318,7 +319,7 @@ static bool ui_tooltip_data_append_from_keymap(bContext *C, uiTooltipData *data,
const int fields_len_init = data->fields_len;
char buf[512];
- for (wmKeyMapItem *kmi = keymap->items.first; kmi; kmi = kmi->next) {
+ LISTBASE_FOREACH (wmKeyMapItem *, kmi, &keymap->items) {
wmOperatorType *ot = WM_operatortype_find(kmi->idname, true);
if (ot != NULL) {
/* Tip */
@@ -393,15 +394,15 @@ static uiTooltipData *ui_tooltip_data_from_tool(bContext *C, uiBut *but, bool is
bool has_valid_context = true;
const char *has_valid_context_error = IFACE_("Unsupported context");
{
- ScrArea *sa = CTX_wm_area(C);
- if (sa == NULL) {
+ ScrArea *area = CTX_wm_area(C);
+ if (area == NULL) {
has_valid_context = false;
}
else {
PropertyRNA *prop = RNA_struct_find_property(but->opptr, "space_type");
if (RNA_property_is_set(but->opptr, prop)) {
const int space_type_prop = RNA_property_enum_get(but->opptr, prop);
- if (space_type_prop != sa->spacetype) {
+ if (space_type_prop != area->spacetype) {
has_valid_context = false;
}
}
@@ -596,7 +597,7 @@ static uiTooltipData *ui_tooltip_data_from_tool(bContext *C, uiBut *but, bool is
else if (BPY_execute_string_as_intptr(C, expr_imports, expr, true, &expr_result)) {
if (expr_result != 0) {
wmKeyMap *keymap = (wmKeyMap *)expr_result;
- for (wmKeyMapItem *kmi = keymap->items.first; kmi; kmi = kmi->next) {
+ LISTBASE_FOREACH (wmKeyMapItem *, kmi, &keymap->items) {
if (STREQ(kmi->idname, but->optype->idname)) {
char tool_id_test[MAX_NAME];
RNA_string_get(kmi->ptr, "name", tool_id_test);
@@ -755,7 +756,7 @@ static uiTooltipData *ui_tooltip_data_from_tool(bContext *C, uiBut *but, bool is
}
}
#else
- UNUSED_VARS(is_label);
+ UNUSED_VARS(is_label, has_valid_context, has_valid_context_error);
#endif /* WITH_PYTHON */
if (data->fields_len == 0) {
@@ -1450,11 +1451,12 @@ ARegion *UI_tooltip_create_from_button(bContext *C, ARegion *butregion, uiBut *b
}
else {
init_position[0] = BLI_rctf_cent_x(&but->rect);
- init_position[1] = but->rect.ymin - (UI_POPUP_MARGIN / 2);
+ init_position[1] = but->rect.ymin;
if (butregion) {
ui_block_to_window_fl(butregion, but->block, &init_position[0], &init_position[1]);
init_position[0] = win->eventstate->x;
}
+ init_position[1] -= (UI_POPUP_MARGIN / 2);
}
ARegion *region = ui_tooltip_create_with_data(
@@ -1480,9 +1482,9 @@ ARegion *UI_tooltip_create_from_gizmo(bContext *C, wmGizmo *gz)
return ui_tooltip_create_with_data(C, data, init_position, NULL, aspect);
}
-void UI_tooltip_free(bContext *C, bScreen *sc, ARegion *region)
+void UI_tooltip_free(bContext *C, bScreen *screen, ARegion *region)
{
- ui_region_temp_remove(C, sc, region);
+ ui_region_temp_remove(C, screen, region);
}
/** \} */
diff --git a/source/blender/editors/interface/interface_regions.c b/source/blender/editors/interface/interface_regions.c
index 2275f3fecdf..9ff58ddd24f 100644
--- a/source/blender/editors/interface/interface_regions.c
+++ b/source/blender/editors/interface/interface_regions.c
@@ -39,12 +39,12 @@
#include "interface_regions_intern.h"
-ARegion *ui_region_temp_add(bScreen *sc)
+ARegion *ui_region_temp_add(bScreen *screen)
{
ARegion *region;
region = MEM_callocN(sizeof(ARegion), "area region");
- BLI_addtail(&sc->regionbase, region);
+ BLI_addtail(&screen->regionbase, region);
region->regiontype = RGN_TYPE_TEMPORARY;
region->alignment = RGN_ALIGN_FLOAT;
@@ -52,17 +52,17 @@ ARegion *ui_region_temp_add(bScreen *sc)
return region;
}
-void ui_region_temp_remove(bContext *C, bScreen *sc, ARegion *region)
+void ui_region_temp_remove(bContext *C, bScreen *screen, ARegion *region)
{
wmWindow *win = CTX_wm_window(C);
BLI_assert(region->regiontype == RGN_TYPE_TEMPORARY);
- BLI_assert(BLI_findindex(&sc->regionbase, region) != -1);
+ BLI_assert(BLI_findindex(&screen->regionbase, region) != -1);
if (win) {
wm_draw_region_clear(win, region);
}
ED_region_exit(C, region);
BKE_area_region_free(NULL, region); /* NULL: no spacetype */
- BLI_freelinkN(&sc->regionbase, region);
+ BLI_freelinkN(&screen->regionbase, region);
}
diff --git a/source/blender/editors/interface/interface_regions_intern.h b/source/blender/editors/interface/interface_regions_intern.h
index 329ee3c08dc..c299562a357 100644
--- a/source/blender/editors/interface/interface_regions_intern.h
+++ b/source/blender/editors/interface/interface_regions_intern.h
@@ -27,7 +27,7 @@
uint ui_popup_menu_hash(const char *str);
/* interface_regions_intern.h */
-ARegion *ui_region_temp_add(bScreen *sc);
-void ui_region_temp_remove(struct bContext *C, bScreen *sc, ARegion *region);
+ARegion *ui_region_temp_add(bScreen *screen);
+void ui_region_temp_remove(struct bContext *C, bScreen *screen, ARegion *region);
#endif /* __INTERFACE_REGIONS_INTERN_H__ */
diff --git a/source/blender/editors/interface/interface_style.c b/source/blender/editors/interface/interface_style.c
index 63fc7825b26..e481ec08d72 100644
--- a/source/blender/editors/interface/interface_style.c
+++ b/source/blender/editors/interface/interface_style.c
@@ -28,7 +28,6 @@
#include "MEM_guardedalloc.h"
-#include "DNA_screen_types.h"
#include "DNA_userdef_types.h"
#include "BLI_listbase.h"
@@ -147,8 +146,9 @@ void UI_fontstyle_draw_ex(const uiFontStyle *fs,
const uchar col[4],
const struct uiFontStyleDraw_Params *fs_params,
size_t len,
- float *r_xofs,
- float *r_yofs)
+ int *r_xofs,
+ int *r_yofs,
+ struct ResultBLF *r_info)
{
int xofs = 0, yofs;
int font_flag = BLF_CLIPPING;
@@ -196,7 +196,7 @@ void UI_fontstyle_draw_ex(const uiFontStyle *fs,
BLF_position(fs->uifont_id, rect->xmin + xofs, rect->ymin + yofs, 0.0f);
BLF_color4ubv(fs->uifont_id, col);
- BLF_draw(fs->uifont_id, str, len);
+ BLF_draw_ex(fs->uifont_id, str, len, r_info);
BLF_disable(fs->uifont_id, font_flag);
@@ -210,9 +210,9 @@ void UI_fontstyle_draw(const uiFontStyle *fs,
const uchar col[4],
const struct uiFontStyleDraw_Params *fs_params)
{
- float xofs, yofs;
+ int xofs, yofs;
- UI_fontstyle_draw_ex(fs, rect, str, col, fs_params, BLF_DRAW_STR_DUMMY_MAX, &xofs, &yofs);
+ UI_fontstyle_draw_ex(fs, rect, str, col, fs_params, BLF_DRAW_STR_DUMMY_MAX, &xofs, &yofs, NULL);
}
/* drawn same as above, but at 90 degree angle */
diff --git a/source/blender/editors/interface/interface_template_search_menu.c b/source/blender/editors/interface/interface_template_search_menu.c
new file mode 100644
index 00000000000..2c6b09168f4
--- /dev/null
+++ b/source/blender/editors/interface/interface_template_search_menu.c
@@ -0,0 +1,1139 @@
+/*
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+
+/** \file
+ * \ingroup edinterface
+ *
+ * Search available menu items via the user interface & key-maps.
+ * Accessed via the #WM_OT_search_menu operator.
+ */
+
+#include <string.h>
+
+#include "MEM_guardedalloc.h"
+
+#include "DNA_action_types.h"
+#include "DNA_gpencil_modifier_types.h"
+#include "DNA_node_types.h"
+#include "DNA_object_types.h"
+#include "DNA_scene_types.h"
+#include "DNA_shader_fx_types.h"
+#include "DNA_texture_types.h"
+
+#include "BLI_alloca.h"
+#include "BLI_dynstr.h"
+#include "BLI_ghash.h"
+#include "BLI_linklist.h"
+#include "BLI_listbase.h"
+#include "BLI_math_matrix.h"
+#include "BLI_memarena.h"
+#include "BLI_string.h"
+#include "BLI_string_utils.h"
+#include "BLI_utildefines.h"
+
+#include "BLT_translation.h"
+
+#include "BKE_context.h"
+#include "BKE_global.h"
+#include "BKE_screen.h"
+
+#include "ED_screen.h"
+
+#include "RNA_access.h"
+
+#include "WM_api.h"
+#include "WM_types.h"
+
+#include "UI_interface.h"
+#include "interface_intern.h"
+
+/* For key-map item access. */
+#include "wm_event_system.h"
+
+/* -------------------------------------------------------------------- */
+/** \name Menu Search Template Implementation
+ * \{ */
+
+/* Unicode arrow. */
+#define MENU_SEP "\xe2\x96\xb6"
+
+/**
+ * Use when #menu_items_from_ui_create is called with `include_all_areas`.
+ * so we can run the menu item in the area it was extracted from.
+ */
+struct MenuSearch_Context {
+ /**
+ * Index into `Area.ui_type` #EnumPropertyItem or the top-bar when -1.
+ * Needed to get the display-name to use as a prefix for each menu item.
+ */
+ int space_type_ui_index;
+
+ ScrArea *area;
+ ARegion *region;
+};
+
+struct MenuSearch_Parent {
+ struct MenuSearch_Parent *parent;
+ MenuType *parent_mt;
+ const char *drawstr;
+
+ /** Set while writing menu items only. */
+ struct MenuSearch_Parent *temp_child;
+};
+
+struct MenuSearch_Item {
+ struct MenuSearch_Item *next, *prev;
+ const char *drawstr;
+ const char *drawwstr_full;
+ /** Support a single level sub-menu nesting (for operator buttons that expand). */
+ const char *drawstr_submenu;
+ int icon;
+ int state;
+
+ struct MenuSearch_Parent *menu_parent;
+ MenuType *mt;
+
+ enum {
+ MENU_SEARCH_TYPE_OP = 1,
+ MENU_SEARCH_TYPE_RNA = 2,
+ } type;
+
+ union {
+ /** Operator menu item. */
+ struct {
+ wmOperatorType *type;
+ PointerRNA *opptr;
+ short opcontext;
+ bContextStore *context;
+ } op;
+
+ /** Property (only for check-box/boolean). */
+ struct {
+ PointerRNA ptr;
+ PropertyRNA *prop;
+ int index;
+ /** Only for enum buttons. */
+ int enum_value;
+ } rna;
+ };
+
+ /** Set when we need each menu item to be able to set it's own context. may be NULL. */
+ struct MenuSearch_Context *wm_context;
+};
+
+struct MenuSearch_Data {
+ /** MenuSearch_Item */
+ ListBase items;
+ /** Use for all small allocations. */
+ MemArena *memarena;
+
+ /** Use for context menu, to fake a button to create a context menu. */
+ struct {
+ uiBut but;
+ uiBlock block;
+ } context_menu_data;
+};
+
+static int menu_item_sort_by_drawstr_full(const void *menu_item_a_v, const void *menu_item_b_v)
+{
+ const struct MenuSearch_Item *menu_item_a = menu_item_a_v;
+ const struct MenuSearch_Item *menu_item_b = menu_item_b_v;
+ return strcmp(menu_item_a->drawwstr_full, menu_item_b->drawwstr_full);
+}
+
+static const char *strdup_memarena(MemArena *memarena, const char *str)
+{
+ const uint str_size = strlen(str) + 1;
+ char *str_dst = BLI_memarena_alloc(memarena, str_size);
+ memcpy(str_dst, str, str_size);
+ return str_dst;
+}
+
+static const char *strdup_memarena_from_dynstr(MemArena *memarena, DynStr *dyn_str)
+{
+ const uint str_size = BLI_dynstr_get_len(dyn_str) + 1;
+ char *str_dst = BLI_memarena_alloc(memarena, str_size);
+ BLI_dynstr_get_cstring_ex(dyn_str, str_dst);
+ return str_dst;
+}
+
+static bool menu_items_from_ui_create_item_from_button(struct MenuSearch_Data *data,
+ MemArena *memarena,
+ struct MenuType *mt,
+ const char *drawstr_submenu,
+ uiBut *but,
+ struct MenuSearch_Context *wm_context)
+{
+ struct MenuSearch_Item *item = NULL;
+
+ /* Use override if the name is empty, this can happen with popovers. */
+ const char *drawstr_override = NULL;
+ const char *drawstr_sep = (but->flag & UI_BUT_HAS_SEP_CHAR) ?
+ strrchr(but->drawstr, UI_SEP_CHAR) :
+ NULL;
+ const bool drawstr_is_empty = (drawstr_sep == but->drawstr) || (but->drawstr[0] == '\0');
+
+ if (but->optype != NULL) {
+ if (drawstr_is_empty) {
+ drawstr_override = WM_operatortype_name(but->optype, but->opptr);
+ }
+
+ item = BLI_memarena_calloc(memarena, sizeof(*item));
+ item->type = MENU_SEARCH_TYPE_OP;
+
+ item->op.type = but->optype;
+ item->op.opcontext = but->opcontext;
+ item->op.context = but->context;
+ item->op.opptr = but->opptr;
+ but->opptr = NULL;
+ }
+ else if (but->rnaprop != NULL) {
+ const int prop_type = RNA_property_type(but->rnaprop);
+
+ if (drawstr_is_empty) {
+ if (prop_type == PROP_ENUM) {
+ const int value_enum = (int)but->hardmax;
+ EnumPropertyItem enum_item;
+ if (RNA_property_enum_item_from_value_gettexted(
+ but->block->evil_C, &but->rnapoin, but->rnaprop, value_enum, &enum_item)) {
+ drawstr_override = enum_item.name;
+ }
+ else {
+ /* Should never happen. */
+ drawstr_override = "Unknown";
+ }
+ }
+ else {
+ drawstr_override = RNA_property_ui_name(but->rnaprop);
+ }
+ }
+
+ if (!ELEM(prop_type, PROP_BOOLEAN, PROP_ENUM)) {
+ /* Note that these buttons are not prevented,
+ * but aren't typically used in menus. */
+ printf("Button '%s' in menu '%s' is a menu item with unsupported RNA type %d\n",
+ but->drawstr,
+ mt->idname,
+ prop_type);
+ }
+ else {
+ item = BLI_memarena_calloc(memarena, sizeof(*item));
+ item->type = MENU_SEARCH_TYPE_RNA;
+
+ item->rna.ptr = but->rnapoin;
+ item->rna.prop = but->rnaprop;
+ item->rna.index = but->rnaindex;
+
+ if (prop_type == PROP_ENUM) {
+ item->rna.enum_value = (int)but->hardmax;
+ }
+ }
+ }
+
+ if (item != NULL) {
+ /* Handle shared settings. */
+ if (drawstr_override != NULL) {
+ const char *drawstr_suffix = drawstr_sep ? drawstr_sep : "";
+ char *drawstr_alloc = BLI_string_joinN("(", drawstr_override, ")", drawstr_suffix);
+ item->drawstr = strdup_memarena(memarena, drawstr_alloc);
+ MEM_freeN(drawstr_alloc);
+ }
+ else {
+ item->drawstr = strdup_memarena(memarena, but->drawstr);
+ }
+
+ item->icon = ui_but_icon(but);
+ item->state = (but->flag &
+ (UI_BUT_DISABLED | UI_BUT_INACTIVE | UI_BUT_REDALERT | UI_BUT_HAS_SEP_CHAR));
+ item->mt = mt;
+ item->drawstr_submenu = drawstr_submenu ? strdup_memarena(memarena, drawstr_submenu) : NULL;
+
+ item->wm_context = wm_context;
+
+ BLI_addtail(&data->items, item);
+ return true;
+ }
+
+ return false;
+}
+
+/**
+ * Populate a fake button from a menu item (use for context menu).
+ */
+static bool menu_items_to_ui_button(struct MenuSearch_Item *item, uiBut *but)
+{
+ bool changed = false;
+ switch (item->type) {
+ case MENU_SEARCH_TYPE_OP: {
+ but->optype = item->op.type;
+ but->opcontext = item->op.opcontext;
+ but->context = item->op.context;
+ but->opptr = item->op.opptr;
+ changed = true;
+ break;
+ }
+ case MENU_SEARCH_TYPE_RNA: {
+ const int prop_type = RNA_property_type(item->rna.prop);
+
+ but->rnapoin = item->rna.ptr;
+ but->rnaprop = item->rna.prop;
+ but->rnaindex = item->rna.index;
+
+ if (prop_type == PROP_ENUM) {
+ but->hardmax = item->rna.enum_value;
+ }
+ changed = true;
+ break;
+ }
+ }
+
+ if (changed) {
+ STRNCPY(but->drawstr, item->drawstr);
+ char *drawstr_sep = (item->state & UI_BUT_HAS_SEP_CHAR) ? strrchr(but->drawstr, UI_SEP_CHAR) :
+ NULL;
+ if (drawstr_sep) {
+ *drawstr_sep = '\0';
+ }
+
+ but->icon = item->icon;
+ but->str = but->strdata;
+ }
+
+ return changed;
+}
+
+/**
+ * Populate \a menu_stack with menus from inspecting active key-maps for this context.
+ */
+static void menu_types_add_from_keymap_items(bContext *C,
+ wmWindow *win,
+ ScrArea *area,
+ ARegion *region,
+ LinkNode **menuid_stack_p,
+ GHash *menu_to_kmi,
+ GSet *menu_tagged)
+{
+ wmWindowManager *wm = CTX_wm_manager(C);
+ ListBase *handlers[] = {
+ region ? &region->handlers : NULL,
+ area ? &area->handlers : NULL,
+ &win->handlers,
+ };
+
+ for (int handler_index = 0; handler_index < ARRAY_SIZE(handlers); handler_index++) {
+ if (handlers[handler_index] == NULL) {
+ continue;
+ }
+ LISTBASE_FOREACH (wmEventHandler *, handler_base, handlers[handler_index]) {
+ /* During this loop, UI handlers for nested menus can tag multiple handlers free. */
+ if (handler_base->flag & WM_HANDLER_DO_FREE) {
+ continue;
+ }
+ if (handler_base->type != WM_HANDLER_TYPE_KEYMAP) {
+ continue;
+ }
+
+ else if (handler_base->poll == NULL || handler_base->poll(region, win->eventstate)) {
+ wmEventHandler_Keymap *handler = (wmEventHandler_Keymap *)handler_base;
+ wmKeyMap *keymap = WM_event_get_keymap_from_handler(wm, handler);
+ if (keymap && WM_keymap_poll(C, keymap)) {
+ LISTBASE_FOREACH (wmKeyMapItem *, kmi, &keymap->items) {
+ if (kmi->flag & KMI_INACTIVE) {
+ continue;
+ }
+ if (STR_ELEM(kmi->idname, "WM_OT_call_menu", "WM_OT_call_menu_pie")) {
+ char menu_idname[MAX_NAME];
+ RNA_string_get(kmi->ptr, "name", menu_idname);
+ MenuType *mt = WM_menutype_find(menu_idname, false);
+
+ if (mt && BLI_gset_add(menu_tagged, mt)) {
+ /* Unlikely, but possible this will be included twice. */
+ BLI_linklist_prepend(menuid_stack_p, mt);
+
+ void **kmi_p;
+ if (!BLI_ghash_ensure_p(menu_to_kmi, mt, &kmi_p)) {
+ *kmi_p = kmi;
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+}
+
+/**
+ * Display all operators (last). Developer-only convenience feature.
+ */
+static void menu_items_from_all_operators(bContext *C, struct MenuSearch_Data *data)
+{
+ /* Add to temporary list so we can sort them separately. */
+ ListBase operator_items = {NULL, NULL};
+
+ MemArena *memarena = data->memarena;
+ GHashIterator iter;
+ for (WM_operatortype_iter(&iter); !BLI_ghashIterator_done(&iter);
+ BLI_ghashIterator_step(&iter)) {
+ wmOperatorType *ot = BLI_ghashIterator_getValue(&iter);
+
+ if ((ot->flag & OPTYPE_INTERNAL) && (G.debug & G_DEBUG_WM) == 0) {
+ continue;
+ }
+
+ if (WM_operator_poll((bContext *)C, ot)) {
+ const char *ot_ui_name = CTX_IFACE_(ot->translation_context, ot->name);
+
+ struct MenuSearch_Item *item = NULL;
+ item = BLI_memarena_calloc(memarena, sizeof(*item));
+ item->type = MENU_SEARCH_TYPE_OP;
+
+ item->op.type = ot;
+ item->op.opcontext = WM_OP_INVOKE_DEFAULT;
+ item->op.context = NULL;
+
+ char idname_as_py[OP_MAX_TYPENAME];
+ char uiname[256];
+ WM_operator_py_idname(idname_as_py, ot->idname);
+
+ SNPRINTF(uiname, "%s " MENU_SEP "%s", idname_as_py, ot_ui_name);
+
+ item->drawwstr_full = strdup_memarena(memarena, uiname);
+ item->drawstr = ot_ui_name;
+
+ item->wm_context = NULL;
+
+ BLI_addtail(&operator_items, item);
+ }
+ }
+
+ BLI_listbase_sort(&operator_items, menu_item_sort_by_drawstr_full);
+
+ BLI_movelisttolist(&data->items, &operator_items);
+}
+
+/**
+ * Create #MenuSearch_Data by inspecting the current context, this uses two methods:
+ *
+ * - Look-up pre-defined editor-menus.
+ * - Look-up key-map items which call menus.
+ */
+static struct MenuSearch_Data *menu_items_from_ui_create(
+ bContext *C, wmWindow *win, ScrArea *area_init, ARegion *region_init, bool include_all_areas)
+{
+ MemArena *memarena = BLI_memarena_new(BLI_MEMARENA_STD_BUFSIZE, __func__);
+ /** Map (#MenuType to #MenuSearch_Parent) */
+ GHash *menu_parent_map = BLI_ghash_ptr_new(__func__);
+ GHash *menu_display_name_map = BLI_ghash_ptr_new(__func__);
+ const uiStyle *style = UI_style_get_dpi();
+
+ /* Convert into non-ui structure. */
+ struct MenuSearch_Data *data = MEM_callocN(sizeof(*data), __func__);
+
+ DynStr *dyn_str = BLI_dynstr_new_memarena();
+
+ /* Use a stack of menus to handle and discover new menus in passes. */
+ LinkNode *menu_stack = NULL;
+
+ /* Tag menu types not to add, either because they have already been added
+ * or they have been blacklisted.
+ * Set of #MenuType. */
+ GSet *menu_tagged = BLI_gset_ptr_new(__func__);
+ /** Map (#MenuType -> #wmKeyMapItem). */
+ GHash *menu_to_kmi = BLI_ghash_ptr_new(__func__);
+
+ /* Blacklist menus we don't want to show. */
+ {
+ const char *idname_array[] = {
+ /* While we could include this, it's just showing filenames to load. */
+ "TOPBAR_MT_file_open_recent",
+ };
+ for (int i = 0; i < ARRAY_SIZE(idname_array); i++) {
+ MenuType *mt = WM_menutype_find(idname_array[i], false);
+ if (mt != NULL) {
+ BLI_gset_add(menu_tagged, mt);
+ }
+ }
+ }
+
+ /* Collect contexts, one for each 'ui_type'. */
+ struct MenuSearch_Context *wm_contexts = NULL;
+
+ const EnumPropertyItem *space_type_ui_items = NULL;
+ int space_type_ui_items_len = 0;
+ bool space_type_ui_items_free = false;
+
+ /* Text used as prefix for top-bar menu items. */
+ const char *global_menu_prefix = NULL;
+
+ if (include_all_areas) {
+ /* First create arrays for ui_type. */
+ PropertyRNA *prop_ui_type = NULL;
+ {
+ PointerRNA ptr;
+ RNA_pointer_create(NULL, &RNA_Area, NULL, &ptr);
+ prop_ui_type = RNA_struct_find_property(&ptr, "ui_type");
+ RNA_property_enum_items(C,
+ &ptr,
+ prop_ui_type,
+ &space_type_ui_items,
+ &space_type_ui_items_len,
+ &space_type_ui_items_free);
+
+ wm_contexts = BLI_memarena_calloc(memarena, sizeof(*wm_contexts) * space_type_ui_items_len);
+ for (int i = 0; i < space_type_ui_items_len; i++) {
+ wm_contexts[i].space_type_ui_index = -1;
+ }
+ }
+
+ bScreen *screen = WM_window_get_active_screen(win);
+ LISTBASE_FOREACH (ScrArea *, area, &screen->areabase) {
+ ARegion *region = BKE_area_find_region_type(area, RGN_TYPE_WINDOW);
+ if (region != NULL) {
+ PointerRNA ptr;
+ RNA_pointer_create(&screen->id, &RNA_Area, area, &ptr);
+ const int space_type_ui = RNA_property_enum_get(&ptr, prop_ui_type);
+
+ int space_type_ui_index = RNA_enum_from_value(space_type_ui_items, space_type_ui);
+ if (space_type_ui_index == -1) {
+ continue;
+ }
+
+ if (wm_contexts[space_type_ui_index].space_type_ui_index != -1) {
+ ScrArea *area_best = wm_contexts[space_type_ui_index].area;
+ const uint value_best = (uint)area_best->winx * (uint)area_best->winy;
+ const uint value_test = (uint)area->winx * (uint)area->winy;
+ if (value_best > value_test) {
+ continue;
+ }
+ }
+
+ wm_contexts[space_type_ui_index].space_type_ui_index = space_type_ui_index;
+ wm_contexts[space_type_ui_index].area = area;
+ wm_contexts[space_type_ui_index].region = region;
+ }
+ }
+
+ global_menu_prefix = CTX_IFACE_(RNA_property_translation_context(prop_ui_type), "Top Bar");
+ }
+
+ GHashIterator iter;
+
+ for (int space_type_ui_index = -1; space_type_ui_index < space_type_ui_items_len;
+ space_type_ui_index += 1) {
+
+ ScrArea *area = NULL;
+ ARegion *region = NULL;
+ struct MenuSearch_Context *wm_context = NULL;
+
+ if (include_all_areas) {
+ if (space_type_ui_index == -1) {
+ /* First run without any context, to populate the top-bar without. */
+ wm_context = NULL;
+ area = NULL;
+ region = NULL;
+ }
+ else {
+ wm_context = &wm_contexts[space_type_ui_index];
+ if (wm_context->space_type_ui_index == -1) {
+ continue;
+ }
+
+ area = wm_context->area;
+ region = wm_context->region;
+
+ CTX_wm_area_set(C, area);
+ CTX_wm_region_set(C, region);
+ }
+ }
+ else {
+ area = area_init;
+ region = region_init;
+ }
+
+ /* Populate menus from the editors,
+ * note that we could create a fake header, draw the header and extract the menus
+ * from the buttons, however this is quite involved and can be avoided as by convention
+ * each space-type has a single root-menu that headers use. */
+ {
+ const char *idname_array[2] = {NULL};
+ int idname_array_len = 0;
+
+ /* Use negative for global (no area) context, populate the top-bar. */
+ if (space_type_ui_index == -1) {
+ idname_array[idname_array_len++] = "TOPBAR_MT_editor_menus";
+ }
+
+#define SPACE_MENU_MAP(space_type, menu_id) \
+ case space_type: \
+ idname_array[idname_array_len++] = menu_id; \
+ break
+#define SPACE_MENU_NOP(space_type) \
+ case space_type: \
+ break
+
+ if (area != NULL) {
+ SpaceLink *sl = area->spacedata.first;
+ switch ((eSpace_Type)area->spacetype) {
+ SPACE_MENU_MAP(SPACE_VIEW3D, "VIEW3D_MT_editor_menus");
+ SPACE_MENU_MAP(SPACE_GRAPH, "GRAPH_MT_editor_menus");
+ SPACE_MENU_MAP(SPACE_OUTLINER, "OUTLINER_MT_editor_menus");
+ SPACE_MENU_NOP(SPACE_PROPERTIES);
+ SPACE_MENU_MAP(SPACE_FILE, "FILEBROWSER_MT_editor_menus");
+ SPACE_MENU_MAP(SPACE_IMAGE, "IMAGE_MT_editor_menus");
+ SPACE_MENU_MAP(SPACE_INFO, "INFO_MT_editor_menus");
+ SPACE_MENU_MAP(SPACE_SEQ, "SEQUENCER_MT_editor_menus");
+ SPACE_MENU_MAP(SPACE_TEXT, "TEXT_MT_editor_menus");
+ SPACE_MENU_MAP(SPACE_ACTION,
+ (((const SpaceAction *)sl)->mode == SACTCONT_TIMELINE) ?
+ "TIME_MT_editor_menus" :
+ "DOPESHEET_MT_editor_menus");
+ SPACE_MENU_MAP(SPACE_NLA, "NLA_MT_editor_menus");
+ SPACE_MENU_MAP(SPACE_NODE, "NODE_MT_editor_menus");
+ SPACE_MENU_MAP(SPACE_CONSOLE, "CONSOLE_MT_editor_menus");
+ SPACE_MENU_MAP(SPACE_USERPREF, "USERPREF_MT_editor_menus");
+ SPACE_MENU_MAP(SPACE_CLIP,
+ (((const SpaceClip *)sl)->mode == SC_MODE_TRACKING) ?
+ "CLIP_MT_tracking_editor_menus" :
+ "CLIP_MT_masking_editor_menus");
+ SPACE_MENU_NOP(SPACE_EMPTY);
+ SPACE_MENU_NOP(SPACE_SCRIPT);
+ SPACE_MENU_NOP(SPACE_STATUSBAR);
+ SPACE_MENU_NOP(SPACE_TOPBAR);
+ }
+ }
+ for (int i = 0; i < idname_array_len; i++) {
+ MenuType *mt = WM_menutype_find(idname_array[i], false);
+ if (mt != NULL) {
+ /* Check if this exists because of 'include_all_areas'. */
+ if (BLI_gset_add(menu_tagged, mt)) {
+ BLI_linklist_prepend(&menu_stack, mt);
+ }
+ }
+ }
+ }
+#undef SPACE_MENU_MAP
+#undef SPACE_MENU_NOP
+
+ bool has_keymap_menu_items = false;
+
+ while (menu_stack != NULL) {
+ MenuType *mt = BLI_linklist_pop(&menu_stack);
+ if (!WM_menutype_poll(C, mt)) {
+ continue;
+ }
+
+ uiBlock *block = UI_block_begin(C, region, __func__, UI_EMBOSS);
+ uiLayout *layout = UI_block_layout(
+ block, UI_LAYOUT_VERTICAL, UI_LAYOUT_MENU, 0, 0, 200, 0, UI_MENU_PADDING, style);
+
+ UI_block_flag_enable(block, UI_BLOCK_SHOW_SHORTCUT_ALWAYS);
+
+ uiLayoutSetOperatorContext(layout, WM_OP_INVOKE_REGION_WIN);
+ UI_menutype_draw(C, mt, layout);
+
+ UI_block_end(C, block);
+
+ LISTBASE_FOREACH (uiBut *, but, &block->buttons) {
+ MenuType *mt_from_but = NULL;
+ /* Support menu titles with dynamic from initial labels
+ * (used by edit-mesh context menu). */
+ if (but->type == UI_BTYPE_LABEL) {
+
+ /* Check if the label is the title. */
+ uiBut *but_test = but->prev;
+ while (but_test && but_test->type == UI_BTYPE_SEPR) {
+ but_test = but_test->prev;
+ }
+
+ if (but_test == NULL) {
+ BLI_ghash_insert(
+ menu_display_name_map, mt, (void *)strdup_memarena(memarena, but->drawstr));
+ }
+ }
+ else if (menu_items_from_ui_create_item_from_button(
+ data, memarena, mt, NULL, but, wm_context)) {
+ /* pass */
+ }
+ else if ((mt_from_but = UI_but_menutype_get(but))) {
+
+ if (BLI_gset_add(menu_tagged, mt_from_but)) {
+ BLI_linklist_prepend(&menu_stack, mt_from_but);
+ }
+
+ if (!BLI_ghash_haskey(menu_parent_map, mt_from_but)) {
+ struct MenuSearch_Parent *menu_parent = BLI_memarena_calloc(memarena,
+ sizeof(*menu_parent));
+ /* Use brackets for menu key shortcuts,
+ * converting "Text|Some-Shortcut" to "Text (Some-Shortcut)".
+ * This is needed so we don't right align sub-menu contents
+ * we only want to do that for the last menu item, not the path that leads to it.
+ */
+ const char *drawstr_sep = but->flag & UI_BUT_HAS_SEP_CHAR ?
+ strrchr(but->drawstr, UI_SEP_CHAR) :
+ NULL;
+ bool drawstr_is_empty = false;
+ if (drawstr_sep != NULL) {
+ BLI_assert(BLI_dynstr_get_len(dyn_str) == 0);
+ /* Detect empty string, fallback to menu name. */
+ const char *drawstr = but->drawstr;
+ int drawstr_len = drawstr_sep - but->drawstr;
+ if (UNLIKELY(drawstr_len == 0)) {
+ drawstr = CTX_IFACE_(mt_from_but->translation_context, mt_from_but->label);
+ drawstr_len = strlen(drawstr);
+ if (drawstr[0] == '\0') {
+ drawstr_is_empty = true;
+ }
+ }
+ BLI_dynstr_nappend(dyn_str, drawstr, drawstr_len);
+ BLI_dynstr_appendf(dyn_str, " (%s)", drawstr_sep + 1);
+ menu_parent->drawstr = strdup_memarena_from_dynstr(memarena, dyn_str);
+ BLI_dynstr_clear(dyn_str);
+ }
+ else {
+ const char *drawstr = but->drawstr;
+ if (UNLIKELY(drawstr[0] == '\0')) {
+ drawstr = CTX_IFACE_(mt_from_but->translation_context, mt_from_but->label);
+ if (drawstr[0] == '\0') {
+ drawstr_is_empty = true;
+ }
+ }
+ menu_parent->drawstr = strdup_memarena(memarena, drawstr);
+ }
+ menu_parent->parent_mt = mt;
+ BLI_ghash_insert(menu_parent_map, mt_from_but, menu_parent);
+
+ if (drawstr_is_empty) {
+ printf("Warning: '%s' menu has empty 'bl_label'.\n", mt_from_but->idname);
+ }
+ }
+ }
+ else if (but->menu_create_func != NULL) {
+ /* A non 'MenuType' menu button. */
+
+ /* Only expand one level deep, this is mainly for expanding operator menus. */
+ const char *drawstr_submenu = but->drawstr;
+
+ /* +1 to avoid overlap with the current 'block'. */
+ uiBlock *sub_block = UI_block_begin(C, region, __func__ + 1, UI_EMBOSS);
+ uiLayout *sub_layout = UI_block_layout(
+ sub_block, UI_LAYOUT_VERTICAL, UI_LAYOUT_MENU, 0, 0, 200, 0, UI_MENU_PADDING, style);
+
+ UI_block_flag_enable(sub_block, UI_BLOCK_SHOW_SHORTCUT_ALWAYS);
+
+ uiLayoutSetOperatorContext(sub_layout, WM_OP_INVOKE_REGION_WIN);
+
+ but->menu_create_func(C, sub_layout, but->poin);
+
+ UI_block_end(C, sub_block);
+
+ LISTBASE_FOREACH (uiBut *, sub_but, &sub_block->buttons) {
+ menu_items_from_ui_create_item_from_button(
+ data, memarena, mt, drawstr_submenu, sub_but, wm_context);
+ }
+
+ if (region) {
+ BLI_remlink(&region->uiblocks, sub_block);
+ }
+ UI_block_free(NULL, sub_block);
+ }
+ }
+ if (region) {
+ BLI_remlink(&region->uiblocks, block);
+ }
+ UI_block_free(NULL, block);
+
+ /* Add key-map items as a second pass,
+ * so all menus are accessed from the header & top-bar before key shortcuts are expanded. */
+ if ((menu_stack == NULL) && (has_keymap_menu_items == false)) {
+ has_keymap_menu_items = true;
+ menu_types_add_from_keymap_items(
+ C, win, area, region, &menu_stack, menu_to_kmi, menu_tagged);
+ }
+ }
+ }
+
+ LISTBASE_FOREACH (struct MenuSearch_Item *, item, &data->items) {
+ item->menu_parent = BLI_ghash_lookup(menu_parent_map, item->mt);
+ }
+
+ GHASH_ITER (iter, menu_parent_map) {
+ struct MenuSearch_Parent *menu_parent = BLI_ghashIterator_getValue(&iter);
+ menu_parent->parent = BLI_ghash_lookup(menu_parent_map, menu_parent->parent_mt);
+ }
+
+ /* NOTE: currently this builds the full path for each menu item,
+ * that could be moved into the parent menu. */
+
+ /* Set names as full paths. */
+ LISTBASE_FOREACH (struct MenuSearch_Item *, item, &data->items) {
+ BLI_assert(BLI_dynstr_get_len(dyn_str) == 0);
+
+ if (include_all_areas) {
+ BLI_dynstr_appendf(dyn_str,
+ "%s: ",
+ (item->wm_context != NULL) ?
+ space_type_ui_items[item->wm_context->space_type_ui_index].name :
+ global_menu_prefix);
+ }
+
+ if (item->menu_parent != NULL) {
+ struct MenuSearch_Parent *menu_parent = item->menu_parent;
+ menu_parent->temp_child = NULL;
+ while (menu_parent && menu_parent->parent) {
+ menu_parent->parent->temp_child = menu_parent;
+ menu_parent = menu_parent->parent;
+ }
+ while (menu_parent) {
+ BLI_dynstr_append(dyn_str, menu_parent->drawstr);
+ BLI_dynstr_append(dyn_str, " " MENU_SEP " ");
+ menu_parent = menu_parent->temp_child;
+ }
+ }
+ else {
+ const char *drawstr = BLI_ghash_lookup(menu_display_name_map, item->mt);
+ if (drawstr == NULL) {
+ drawstr = CTX_IFACE_(item->mt->translation_context, item->mt->label);
+ }
+ BLI_dynstr_append(dyn_str, drawstr);
+
+ wmKeyMapItem *kmi = BLI_ghash_lookup(menu_to_kmi, item->mt);
+ if (kmi != NULL) {
+ char kmi_str[128];
+ WM_keymap_item_to_string(kmi, false, kmi_str, sizeof(kmi_str));
+ BLI_dynstr_appendf(dyn_str, " (%s)", kmi_str);
+ }
+
+ BLI_dynstr_append(dyn_str, " " MENU_SEP " ");
+ }
+
+ /* Optional nested menu. */
+ if (item->drawstr_submenu != NULL) {
+ BLI_dynstr_append(dyn_str, item->drawstr_submenu);
+ BLI_dynstr_append(dyn_str, " " MENU_SEP " ");
+ }
+
+ BLI_dynstr_append(dyn_str, item->drawstr);
+
+ item->drawwstr_full = strdup_memarena_from_dynstr(memarena, dyn_str);
+ BLI_dynstr_clear(dyn_str);
+ }
+ BLI_dynstr_free(dyn_str);
+
+ /* Finally sort menu items.
+ *
+ * Note: we might want to keep the in-menu order, for now sort all. */
+ BLI_listbase_sort(&data->items, menu_item_sort_by_drawstr_full);
+
+ BLI_ghash_free(menu_parent_map, NULL, NULL);
+ BLI_ghash_free(menu_display_name_map, NULL, NULL);
+
+ BLI_ghash_free(menu_to_kmi, NULL, NULL);
+
+ BLI_gset_free(menu_tagged, NULL);
+
+ data->memarena = memarena;
+
+ if (include_all_areas) {
+ CTX_wm_area_set(C, area_init);
+ CTX_wm_region_set(C, region_init);
+
+ if (space_type_ui_items_free) {
+ MEM_freeN((void *)space_type_ui_items);
+ }
+ }
+
+ /* Include all operators for developers,
+ * since it can be handy to have a quick way to access any operator,
+ * including operators being developed which haven't yet been added into the interface.
+ *
+ * These are added after all menu items so developers still get normal behavior by default,
+ * unless searching for something that isn't already in a menu (or scroll down).
+ *
+ * Keep this behind a developer only check:
+ * - Many operators need options to be set to give useful results, see: T74157.
+ * - User who really prefer to list all operators can use #WM_OT_search_operator.
+ */
+ if (U.flag & USER_DEVELOPER_UI) {
+ menu_items_from_all_operators(C, data);
+ }
+
+ return data;
+}
+
+static void menu_search_arg_free_fn(void *data_v)
+{
+ struct MenuSearch_Data *data = data_v;
+ LISTBASE_FOREACH (struct MenuSearch_Item *, item, &data->items) {
+ switch (item->type) {
+ case MENU_SEARCH_TYPE_OP: {
+ if (item->op.opptr != NULL) {
+ WM_operator_properties_free(item->op.opptr);
+ MEM_freeN(item->op.opptr);
+ }
+ }
+ case MENU_SEARCH_TYPE_RNA: {
+ break;
+ }
+ }
+ }
+
+ BLI_memarena_free(data->memarena);
+
+ MEM_freeN(data);
+}
+
+static void menu_search_exec_fn(bContext *C, void *UNUSED(arg1), void *arg2)
+{
+ struct MenuSearch_Item *item = arg2;
+ if (item == NULL) {
+ return;
+ }
+ if (item->state & UI_BUT_DISABLED) {
+ return;
+ }
+
+ ScrArea *area_prev = CTX_wm_area(C);
+ ARegion *region_prev = CTX_wm_region(C);
+
+ if (item->wm_context != NULL) {
+ CTX_wm_area_set(C, item->wm_context->area);
+ CTX_wm_region_set(C, item->wm_context->region);
+ }
+
+ switch (item->type) {
+ case MENU_SEARCH_TYPE_OP: {
+ CTX_store_set(C, item->op.context);
+ WM_operator_name_call_ptr(C, item->op.type, item->op.opcontext, item->op.opptr);
+ CTX_store_set(C, NULL);
+ break;
+ }
+ case MENU_SEARCH_TYPE_RNA: {
+ PointerRNA *ptr = &item->rna.ptr;
+ PropertyRNA *prop = item->rna.prop;
+ int index = item->rna.index;
+ const int prop_type = RNA_property_type(prop);
+ bool changed = false;
+
+ if (prop_type == PROP_BOOLEAN) {
+ const bool is_array = RNA_property_array_check(prop);
+ if (is_array) {
+ const bool value = RNA_property_boolean_get_index(ptr, prop, index);
+ RNA_property_boolean_set_index(ptr, prop, index, !value);
+ }
+ else {
+ const bool value = RNA_property_boolean_get(ptr, prop);
+ RNA_property_boolean_set(ptr, prop, !value);
+ }
+ changed = true;
+ }
+ else if (prop_type == PROP_ENUM) {
+ RNA_property_enum_set(ptr, prop, item->rna.enum_value);
+ changed = true;
+ }
+
+ if (changed) {
+ RNA_property_update(C, ptr, prop);
+ }
+ break;
+ }
+ }
+
+ if (item->wm_context != NULL) {
+ CTX_wm_area_set(C, area_prev);
+ CTX_wm_region_set(C, region_prev);
+ }
+}
+
+static void menu_search_update_fn(const bContext *UNUSED(C),
+ void *arg,
+ const char *str,
+ uiSearchItems *items)
+{
+ struct MenuSearch_Data *data = arg;
+ const size_t str_len = strlen(str);
+ const int words_max = (str_len / 2) + 1;
+ int(*words)[2] = BLI_array_alloca(words, words_max);
+
+ const int words_len = BLI_string_find_split_words(str, str_len, ' ', words, words_max);
+
+ for (struct MenuSearch_Item *item = data->items.first; item; item = item->next) {
+ int index;
+
+ /* match name against all search words */
+ for (index = 0; index < words_len; index++) {
+ if (!ui_str_has_word_prefix(item->drawwstr_full, str + words[index][0], words[index][1])) {
+ break;
+ }
+ }
+
+ if (index == words_len) {
+ if (!UI_search_item_add(items, item->drawwstr_full, item, item->icon, item->state)) {
+ break;
+ }
+ }
+ }
+}
+
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Context Menu
+ *
+ * This uses a fake button to create a context menu,
+ * if this ever causes hard to solve bugs we may need to create
+ * a separate context menu just for the search, however this is fairly involved.
+ * \{ */
+
+static bool ui_search_menu_create_context_menu(struct bContext *C,
+ void *arg,
+ void *active,
+ const struct wmEvent *UNUSED(event))
+{
+ struct MenuSearch_Data *data = arg;
+ struct MenuSearch_Item *item = active;
+ bool has_menu = false;
+
+ memset(&data->context_menu_data, 0x0, sizeof(data->context_menu_data));
+ uiBut *but = &data->context_menu_data.but;
+ uiBlock *block = &data->context_menu_data.block;
+
+ but->block = block;
+
+ if (menu_items_to_ui_button(item, but)) {
+ ScrArea *area_prev = CTX_wm_area(C);
+ ARegion *region_prev = CTX_wm_region(C);
+
+ if (item->wm_context != NULL) {
+ CTX_wm_area_set(C, item->wm_context->area);
+ CTX_wm_region_set(C, item->wm_context->region);
+ }
+
+ if (ui_popup_context_menu_for_button(C, but)) {
+ has_menu = true;
+ }
+
+ if (item->wm_context != NULL) {
+ CTX_wm_area_set(C, area_prev);
+ CTX_wm_region_set(C, region_prev);
+ }
+ }
+
+ return has_menu;
+}
+
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Tooltip
+ * \{ */
+
+static struct ARegion *ui_search_menu_create_tooltip(struct bContext *C,
+ struct ARegion *region,
+ void *arg,
+ void *active)
+{
+ struct MenuSearch_Data *data = arg;
+ struct MenuSearch_Item *item = active;
+
+ memset(&data->context_menu_data, 0x0, sizeof(data->context_menu_data));
+ uiBut *but = &data->context_menu_data.but;
+ uiBlock *block = &data->context_menu_data.block;
+ unit_m4(block->winmat);
+ block->aspect = 1;
+
+ but->block = block;
+
+ /* Place the fake button at the cursor so the tool-tip is places properly. */
+ float tip_init[2];
+ const wmEvent *event = CTX_wm_window(C)->eventstate;
+ tip_init[0] = event->x;
+ tip_init[1] = event->y - (UI_UNIT_Y / 2);
+ ui_window_to_block_fl(region, block, &tip_init[0], &tip_init[1]);
+
+ but->rect.xmin = tip_init[0];
+ but->rect.xmax = tip_init[0];
+ but->rect.ymin = tip_init[1];
+ but->rect.ymax = tip_init[1];
+
+ if (menu_items_to_ui_button(item, but)) {
+ ScrArea *area_prev = CTX_wm_area(C);
+ ARegion *region_prev = CTX_wm_region(C);
+
+ if (item->wm_context != NULL) {
+ CTX_wm_area_set(C, item->wm_context->area);
+ CTX_wm_region_set(C, item->wm_context->region);
+ }
+
+ ARegion *region_tip = UI_tooltip_create_from_button(C, region, but, false);
+
+ if (item->wm_context != NULL) {
+ CTX_wm_area_set(C, area_prev);
+ CTX_wm_region_set(C, region_prev);
+ }
+ return region_tip;
+ }
+
+ return NULL;
+}
+
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Menu Search Template Public API
+ * \{ */
+
+void UI_but_func_menu_search(uiBut *but)
+{
+ bContext *C = but->block->evil_C;
+ wmWindow *win = CTX_wm_window(C);
+ ScrArea *area = CTX_wm_area(C);
+ ARegion *region = CTX_wm_region(C);
+ /* When run from top-bar scan all areas in the current window. */
+ bool include_all_areas = (area && (area->spacetype == SPACE_TOPBAR));
+ struct MenuSearch_Data *data = menu_items_from_ui_create(
+ C, win, area, region, include_all_areas);
+ UI_but_func_search_set(but,
+ /* Generic callback. */
+ ui_searchbox_create_menu,
+ menu_search_update_fn,
+ data,
+ menu_search_arg_free_fn,
+ menu_search_exec_fn,
+ NULL);
+
+ UI_but_func_search_set_context_menu(but, ui_search_menu_create_context_menu);
+ UI_but_func_search_set_tooltip(but, ui_search_menu_create_tooltip);
+ UI_but_func_search_set_sep_string(but, MENU_SEP);
+}
+
+void uiTemplateMenuSearch(uiLayout *layout)
+{
+ uiBlock *block;
+ uiBut *but;
+ static char search[256] = "";
+
+ block = uiLayoutGetBlock(layout);
+ UI_block_layout_set_current(block, layout);
+
+ but = uiDefSearchBut(
+ block, search, 0, ICON_VIEWZOOM, sizeof(search), 0, 0, UI_UNIT_X * 6, UI_UNIT_Y, 0, 0, "");
+ UI_but_func_menu_search(but);
+}
+
+#undef MENU_SEP
+
+/** \} */
diff --git a/source/blender/editors/interface/interface_template_search_operator.c b/source/blender/editors/interface/interface_template_search_operator.c
new file mode 100644
index 00000000000..cdf87103587
--- /dev/null
+++ b/source/blender/editors/interface/interface_template_search_operator.c
@@ -0,0 +1,151 @@
+/*
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+
+/** \file
+ * \ingroup edinterface
+ *
+ * Search available operators by scanning all and checking their poll function.
+ * accessed via the #WM_OT_search_operator operator.
+ */
+
+#include <string.h>
+
+#include "DNA_gpencil_modifier_types.h"
+#include "DNA_node_types.h"
+#include "DNA_object_types.h"
+#include "DNA_scene_types.h"
+#include "DNA_shader_fx_types.h"
+#include "DNA_texture_types.h"
+
+#include "BLI_alloca.h"
+#include "BLI_ghash.h"
+#include "BLI_string.h"
+#include "BLI_utildefines.h"
+
+#include "BLT_translation.h"
+
+#include "BKE_context.h"
+#include "BKE_global.h"
+
+#include "WM_api.h"
+#include "WM_types.h"
+
+#include "UI_interface.h"
+#include "interface_intern.h"
+
+/* -------------------------------------------------------------------- */
+/** \name Operator Search Template Implementation
+ * \{ */
+
+static void operator_search_exec_fn(bContext *C, void *UNUSED(arg1), void *arg2)
+{
+ wmOperatorType *ot = arg2;
+
+ if (ot) {
+ WM_operator_name_call_ptr(C, ot, WM_OP_INVOKE_DEFAULT, NULL);
+ }
+}
+
+static void operator_search_update_fn(const bContext *C,
+ void *UNUSED(arg),
+ const char *str,
+ uiSearchItems *items)
+{
+ GHashIterator iter;
+ const size_t str_len = strlen(str);
+ const int words_max = (str_len / 2) + 1;
+ int(*words)[2] = BLI_array_alloca(words, words_max);
+
+ const int words_len = BLI_string_find_split_words(str, str_len, ' ', words, words_max);
+
+ for (WM_operatortype_iter(&iter); !BLI_ghashIterator_done(&iter);
+ BLI_ghashIterator_step(&iter)) {
+ wmOperatorType *ot = BLI_ghashIterator_getValue(&iter);
+ const char *ot_ui_name = CTX_IFACE_(ot->translation_context, ot->name);
+ int index;
+
+ if ((ot->flag & OPTYPE_INTERNAL) && (G.debug & G_DEBUG_WM) == 0) {
+ continue;
+ }
+
+ /* match name against all search words */
+ for (index = 0; index < words_len; index++) {
+ if (!ui_str_has_word_prefix(ot_ui_name, str + words[index][0], words[index][1])) {
+ break;
+ }
+ }
+
+ if (index == words_len) {
+ if (WM_operator_poll((bContext *)C, ot)) {
+ char name[256];
+ int len = strlen(ot_ui_name);
+
+ /* display name for menu, can hold hotkey */
+ BLI_strncpy(name, ot_ui_name, sizeof(name));
+
+ /* check for hotkey */
+ if (len < sizeof(name) - 6) {
+ if (WM_key_event_operator_string(C,
+ ot->idname,
+ WM_OP_EXEC_DEFAULT,
+ NULL,
+ true,
+ &name[len + 1],
+ sizeof(name) - len - 1)) {
+ name[len] = UI_SEP_CHAR;
+ }
+ }
+
+ if (!UI_search_item_add(items, name, ot, ICON_NONE, 0)) {
+ break;
+ }
+ }
+ }
+ }
+}
+
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Operator Search Template API
+ * \{ */
+
+void UI_but_func_operator_search(uiBut *but)
+{
+ UI_but_func_search_set(but,
+ ui_searchbox_create_operator,
+ operator_search_update_fn,
+ NULL,
+ false,
+ operator_search_exec_fn,
+ NULL);
+}
+
+void uiTemplateOperatorSearch(uiLayout *layout)
+{
+ uiBlock *block;
+ uiBut *but;
+ static char search[256] = "";
+
+ block = uiLayoutGetBlock(layout);
+ UI_block_layout_set_current(block, layout);
+
+ but = uiDefSearchBut(
+ block, search, 0, ICON_VIEWZOOM, sizeof(search), 0, 0, UI_UNIT_X * 6, UI_UNIT_Y, 0, 0, "");
+ UI_but_func_operator_search(but);
+}
+
+/** \} */
diff --git a/source/blender/editors/interface/interface_templates.c b/source/blender/editors/interface/interface_templates.c
index d7377a0e56e..6001e1ea1b5 100644
--- a/source/blender/editors/interface/interface_templates.c
+++ b/source/blender/editors/interface/interface_templates.c
@@ -37,18 +37,12 @@
#include "DNA_shader_fx_types.h"
#include "DNA_texture_types.h"
-#include "BLI_alloca.h"
-#include "BLI_dynstr.h"
#include "BLI_fnmatch.h"
-#include "BLI_ghash.h"
-#include "BLI_linklist.h"
#include "BLI_listbase.h"
#include "BLI_math.h"
-#include "BLI_memarena.h"
#include "BLI_path_util.h"
#include "BLI_rect.h"
#include "BLI_string.h"
-#include "BLI_string_utils.h"
#include "BLI_timecode.h"
#include "BLI_utildefines.h"
@@ -73,7 +67,6 @@
#include "BKE_modifier.h"
#include "BKE_object.h"
#include "BKE_packedFile.h"
-#include "BKE_paint.h"
#include "BKE_particle.h"
#include "BKE_report.h"
#include "BKE_scene.h"
@@ -103,9 +96,6 @@
#include "PIL_time.h"
-/* For key-map item access. */
-#include "wm_event_system.h"
-
// #define USE_OP_RESET_BUT // we may want to make this optional, disable for now.
/* defines for templateID/TemplateSearch */
@@ -213,9 +203,9 @@ static void template_add_button_search_menu(const bContext *C,
static uiBlock *template_common_search_menu(const bContext *C,
ARegion *region,
- uiButSearchFunc search_func,
+ uiButSearchUpdateFn search_update_fn,
void *search_arg,
- uiButHandleFunc handle_func,
+ uiButHandleFunc search_exec_fn,
void *active_item,
const int preview_rows,
const int preview_cols,
@@ -287,8 +277,13 @@ static uiBlock *template_common_search_menu(const bContext *C,
0,
"");
}
- UI_but_func_search_set(
- but, ui_searchbox_create_generic, search_func, search_arg, NULL, handle_func, active_item);
+ UI_but_func_search_set(but,
+ ui_searchbox_create_generic,
+ search_update_fn,
+ search_arg,
+ NULL,
+ search_exec_fn,
+ active_item);
UI_block_bounds_set_normal(block, 0.3f * U.widget_unit);
UI_block_direction_set(block, UI_DIR_DOWN);
@@ -320,7 +315,7 @@ typedef struct TemplateID {
} TemplateID;
/* Search browse menu, assign */
-static void template_ID_set_property_cb(bContext *C, void *arg_template, void *item)
+static void template_ID_set_property_exec_fn(bContext *C, void *arg_template, void *item)
{
TemplateID *template_ui = (TemplateID *)arg_template;
@@ -455,7 +450,8 @@ static uiBlock *id_search_menu(bContext *C, ARegion *region, void *arg_litem)
{
static TemplateID template_ui;
PointerRNA active_item_ptr;
- void (*id_search_cb_p)(const bContext *, void *, const char *, uiSearchItems *) = id_search_cb;
+ void (*id_search_update_fn)(
+ const bContext *, void *, const char *, uiSearchItems *) = id_search_cb;
/* arg_litem is malloced, can be freed by parent button */
template_ui = *((TemplateID *)arg_litem);
@@ -465,16 +461,16 @@ static uiBlock *id_search_menu(bContext *C, ARegion *region, void *arg_litem)
/* Currently only used for objects. */
if (template_ui.idcode == ID_OB) {
if (template_ui.filter == UI_TEMPLATE_ID_FILTER_AVAILABLE) {
- id_search_cb_p = id_search_cb_objects_from_scene;
+ id_search_update_fn = id_search_cb_objects_from_scene;
}
}
}
return template_common_search_menu(C,
region,
- id_search_cb_p,
+ id_search_update_fn,
&template_ui,
- template_ID_set_property_cb,
+ template_ID_set_property_exec_fn,
active_item_ptr.data,
template_ui.prv_rows,
template_ui.prv_cols,
@@ -530,6 +526,7 @@ static void template_id_cb(bContext *C, void *arg_litem, void *arg_event)
if (id && CTX_wm_window(C)->eventstate->shift) {
/* only way to force-remove data (on save) */
+ id_us_clear_real(id);
id_fake_user_clear(id);
id->us = 0;
}
@@ -681,6 +678,8 @@ static const char *template_id_browse_tip(const StructRNA *type)
return N_("Browse Point Cloud Data to be linked");
case ID_VO:
return N_("Browse Volume Data to be linked");
+ case ID_SIM:
+ return N_("Browse Simulation to be linked");
}
}
return N_("Browse ID data to be linked");
@@ -698,6 +697,8 @@ static const char *template_id_context(StructRNA *type)
}
return BLT_I18NCONTEXT_DEFAULT;
}
+#else
+# define template_id_context(type) 0
#endif
static uiBut *template_id_def_new_but(uiBlock *block,
@@ -746,7 +747,8 @@ static uiBut *template_id_def_new_but(uiBlock *block,
BLT_I18NCONTEXT_ID_LIGHTPROBE,
BLT_I18NCONTEXT_ID_HAIR,
BLT_I18NCONTEXT_ID_POINTCLOUD,
- BLT_I18NCONTEXT_ID_VOLUME, );
+ BLT_I18NCONTEXT_ID_VOLUME,
+ BLT_I18NCONTEXT_ID_SIMULATION, );
/* Note: BLT_I18N_MSGID_MULTI_CTXT takes a maximum number of parameters,
* check the definition to see if a new call must be added when the limit
* is exceeded. */
@@ -797,7 +799,7 @@ static uiBut *template_id_def_new_but(uiBlock *block,
return but;
}
-static void template_ID(bContext *C,
+static void template_ID(const bContext *C,
uiLayout *layout,
TemplateID *template_ui,
StructRNA *type,
@@ -831,7 +833,7 @@ static void template_ID(bContext *C,
if (text) {
/* Add label resepecting the separated layout property split state. */
- layout = uiItemL_respect_property_split(layout, text, ICON_NONE);
+ uiItemL_respect_property_split(layout, text, ICON_NONE);
}
if (flag & UI_ID_BROWSE) {
@@ -1138,7 +1140,7 @@ ID *UI_context_active_but_get_tab_ID(bContext *C)
}
}
-static void template_ID_tabs(bContext *C,
+static void template_ID_tabs(const bContext *C,
uiLayout *layout,
TemplateID *template,
StructRNA *type,
@@ -1148,7 +1150,7 @@ static void template_ID_tabs(bContext *C,
{
const ARegion *region = CTX_wm_region(C);
const PointerRNA active_ptr = RNA_property_pointer_get(&template->ptr, template->prop);
- MenuType *mt = WM_menutype_find(menu, false);
+ MenuType *mt = menu ? WM_menutype_find(menu, false) : NULL;
const int but_align = ui_but_align_opposite_to_area_align_get(region);
const int but_height = UI_UNIT_Y * 1.1;
@@ -1159,7 +1161,7 @@ static void template_ID_tabs(bContext *C,
ListBase ordered;
BKE_id_ordered_list(&ordered, template->idlb);
- for (LinkData *link = ordered.first; link; link = link->next) {
+ LISTBASE_FOREACH (LinkData *, link, &ordered) {
ID *id = link->data;
const int name_width = UI_fontstyle_string_width(&style->widgetlabel, id->name + 2);
const int but_width = name_width + UI_UNIT_X;
@@ -1180,7 +1182,7 @@ static void template_ID_tabs(bContext *C,
0.0f,
0.0f,
"");
- UI_but_funcN_set(&tab->but, template_ID_set_property_cb, MEM_dupallocN(template), id);
+ UI_but_funcN_set(&tab->but, template_ID_set_property_exec_fn, MEM_dupallocN(template), id);
tab->but.custom_data = (void *)id;
tab->but.dragpoin = id;
tab->menu = mt;
@@ -1212,12 +1214,14 @@ static void template_ID_tabs(bContext *C,
}
static void ui_template_id(uiLayout *layout,
- bContext *C,
+ const bContext *C,
PointerRNA *ptr,
const char *propname,
const char *newop,
const char *openop,
const char *unlinkop,
+ /* Only respected by tabs (use_tabs). */
+ const char *menu,
const char *text,
int flag,
int prv_rows,
@@ -1272,7 +1276,7 @@ static void ui_template_id(uiLayout *layout,
if (template_ui->idlb) {
if (use_tabs) {
layout = uiLayoutRow(layout, true);
- template_ID_tabs(C, layout, template_ui, type, flag, newop, unlinkop);
+ template_ID_tabs(C, layout, template_ui, type, flag, newop, menu);
}
else {
layout = uiLayoutRow(layout, true);
@@ -1294,7 +1298,7 @@ static void ui_template_id(uiLayout *layout,
}
void uiTemplateID(uiLayout *layout,
- bContext *C,
+ const bContext *C,
PointerRNA *ptr,
const char *propname,
const char *newop,
@@ -1311,6 +1315,7 @@ void uiTemplateID(uiLayout *layout,
newop,
openop,
unlinkop,
+ NULL,
text,
UI_ID_BROWSE | UI_ID_RENAME | UI_ID_DELETE,
0,
@@ -1339,6 +1344,7 @@ void uiTemplateIDBrowse(uiLayout *layout,
newop,
openop,
unlinkop,
+ NULL,
text,
UI_ID_BROWSE | UI_ID_RENAME,
0,
@@ -1370,6 +1376,7 @@ void uiTemplateIDPreview(uiLayout *layout,
openop,
unlinkop,
NULL,
+ NULL,
UI_ID_BROWSE | UI_ID_RENAME | UI_ID_DELETE | UI_ID_PREVIEWS,
rows,
cols,
@@ -1397,6 +1404,7 @@ void uiTemplateGpencilColorPreview(uiLayout *layout,
NULL,
NULL,
NULL,
+ NULL,
UI_ID_BROWSE | UI_ID_PREVIEWS | UI_ID_DELETE,
rows,
cols,
@@ -1415,7 +1423,7 @@ void uiTemplateIDTabs(uiLayout *layout,
PointerRNA *ptr,
const char *propname,
const char *newop,
- const char *unlinkop,
+ const char *menu,
int filter)
{
ui_template_id(layout,
@@ -1424,7 +1432,8 @@ void uiTemplateIDTabs(uiLayout *layout,
propname,
newop,
NULL,
- unlinkop,
+ NULL,
+ menu,
NULL,
UI_ID_BROWSE | UI_ID_RENAME,
0,
@@ -1526,7 +1535,7 @@ typedef struct TemplateSearch {
int preview_rows, preview_cols;
} TemplateSearch;
-static void template_search_handle_cb(bContext *C, void *arg_template, void *item)
+static void template_search_exec_fn(bContext *C, void *arg_template, void *item)
{
TemplateSearch *template_search = arg_template;
uiRNACollectionSearch *coll_search = &template_search->search_data;
@@ -1550,9 +1559,9 @@ static uiBlock *template_search_menu(bContext *C, ARegion *region, void *arg_tem
return template_common_search_menu(C,
region,
- ui_rna_collection_search_cb,
+ ui_rna_collection_search_update_fn,
&template_search,
- template_search_handle_cb,
+ template_search_exec_fn,
active_ptr.data,
template_search.preview_rows,
template_search.preview_cols,
@@ -1816,14 +1825,14 @@ static void modifiers_convertToReal(bContext *C, void *ob_v, void *md_v)
{
Object *ob = ob_v;
ModifierData *md = md_v;
- ModifierData *nmd = modifier_new(md->type);
+ ModifierData *nmd = BKE_modifier_new(md->type);
- modifier_copyData(md, nmd);
+ BKE_modifier_copydata(md, nmd);
nmd->mode &= ~eModifierMode_Virtual;
BLI_addhead(&ob->modifiers, nmd);
- modifier_unique_name(&ob->modifiers, nmd);
+ BKE_modifier_unique_name(&ob->modifiers, nmd);
ob->partype = PAROBJECT;
@@ -1833,20 +1842,26 @@ static void modifiers_convertToReal(bContext *C, void *ob_v, void *md_v)
ED_undo_push(C, "Modifier convert to real");
}
-static int modifier_can_delete(ModifierData *md)
+static bool modifier_can_delete(ModifierData *md)
{
/* fluid particle modifier can't be deleted here */
if (md->type == eModifierType_ParticleSystem) {
short particle_type = ((ParticleSystemModifierData *)md)->psys->part->type;
- if (particle_type == PART_FLUID || particle_type == PART_FLUID_FLIP ||
- particle_type == PART_FLUID_FOAM || particle_type == PART_FLUID_SPRAY ||
- particle_type == PART_FLUID_BUBBLE || particle_type == PART_FLUID_TRACER ||
- particle_type == PART_FLUID_SPRAYFOAM || particle_type == PART_FLUID_SPRAYBUBBLE ||
- particle_type == PART_FLUID_FOAMBUBBLE || particle_type == PART_FLUID_SPRAYFOAMBUBBLE) {
- return 0;
+ if (ELEM(particle_type,
+ PART_FLUID,
+ PART_FLUID_FLIP,
+ PART_FLUID_FOAM,
+ PART_FLUID_SPRAY,
+ PART_FLUID_BUBBLE,
+ PART_FLUID_TRACER,
+ PART_FLUID_SPRAYFOAM,
+ PART_FLUID_SPRAYBUBBLE,
+ PART_FLUID_FOAMBUBBLE,
+ PART_FLUID_SPRAYFOAMBUBBLE)) {
+ return false;
}
}
- return 1;
+ return true;
}
/* Check whether Modifier is a simulation or not,
@@ -1881,7 +1896,7 @@ static uiLayout *draw_modifier(uiLayout *layout,
int cageIndex,
int lastCageIndex)
{
- const ModifierTypeInfo *mti = modifierType_getInfo(md->type);
+ const ModifierTypeInfo *mti = BKE_modifier_get_info(md->type);
PointerRNA ptr;
uiBut *but;
uiBlock *block;
@@ -1975,9 +1990,9 @@ static uiLayout *draw_modifier(uiLayout *layout,
}
if (ob->type == OB_MESH) {
- if (modifier_supportsCage(scene, md) && (index <= lastCageIndex)) {
+ if (BKE_modifier_supports_cage(scene, md) && (index <= lastCageIndex)) {
sub = uiLayoutRow(row, true);
- if (index < cageIndex || !modifier_couldBeCage(scene, md)) {
+ if (index < cageIndex || !BKE_modifier_couldbe_cage(scene, md)) {
uiLayoutSetActive(sub, false);
}
uiItemR(sub, &ptr, "show_on_cage", 0, "", ICON_NONE);
@@ -2073,7 +2088,7 @@ static uiLayout *draw_modifier(uiLayout *layout,
"apply_as",
MODIFIER_APPLY_DATA);
- if (modifier_isSameTopology(md) && !modifier_isNonGeometrical(md)) {
+ if (BKE_modifier_is_same_topology(md) && !BKE_modifier_is_non_geometrical(md)) {
uiItemEnumO(row,
"OBJECT_OT_modifier_apply",
CTX_IFACE_(BLT_I18NCONTEXT_OPERATOR_DEFAULT, "Apply as Shape Key"),
@@ -2140,10 +2155,10 @@ uiLayout *uiTemplateModifier(uiLayout *layout, bContext *C, PointerRNA *ptr)
UI_block_lock_set(uiLayoutGetBlock(layout), (ob && ID_IS_LINKED(ob)), ERROR_LIBDATA_MESSAGE);
/* find modifier and draw it */
- cageIndex = modifiers_getCageIndex(scene, ob, &lastCageIndex, 0);
+ cageIndex = BKE_modifiers_get_cage_index(scene, ob, &lastCageIndex, 0);
/* XXX virtual modifiers are not accessible for python */
- vmd = modifiers_getVirtualModifierList(ob, &virtualModifierData);
+ vmd = BKE_modifiers_get_virtual_modifierlist(ob, &virtualModifierData);
for (i = 0; vmd; i++, vmd = vmd->next) {
if (md == vmd) {
@@ -2165,7 +2180,7 @@ uiLayout *uiTemplateModifier(uiLayout *layout, bContext *C, PointerRNA *ptr)
static uiLayout *gpencil_draw_modifier(uiLayout *layout, Object *ob, GpencilModifierData *md)
{
- const GpencilModifierTypeInfo *mti = BKE_gpencil_modifierType_getInfo(md->type);
+ const GpencilModifierTypeInfo *mti = BKE_gpencil_modifier_get_info(md->type);
PointerRNA ptr;
uiBlock *block;
uiLayout *box, *column, *row, *sub;
@@ -2242,6 +2257,10 @@ static uiLayout *gpencil_draw_modifier(uiLayout *layout, Object *ob, GpencilModi
0,
"apply_as",
MODIFIER_APPLY_DATA);
+
+ UI_block_lock_clear(block);
+ UI_block_lock_set(block, ob && ID_IS_LINKED(ob), ERROR_LIBDATA_MESSAGE);
+
uiItemO(row,
CTX_IFACE_(BLT_I18NCONTEXT_OPERATOR_DEFAULT, "Copy"),
ICON_NONE,
@@ -2304,7 +2323,7 @@ uiLayout *uiTemplateGpencilModifier(uiLayout *layout, bContext *UNUSED(C), Point
static uiLayout *gpencil_draw_shaderfx(uiLayout *layout, Object *ob, ShaderFxData *md)
{
- const ShaderFxTypeInfo *mti = BKE_shaderfxType_getInfo(md->type);
+ const ShaderFxTypeInfo *mti = BKE_shaderfx_get_info(md->type);
PointerRNA ptr;
uiBlock *block;
uiLayout *box, *column, *row, *sub;
@@ -2421,21 +2440,196 @@ uiLayout *uiTemplateShaderFx(uiLayout *layout, bContext *UNUSED(C), PointerRNA *
/** \} */
/* -------------------------------------------------------------------- */
-/** \name Operator Redo Buttons Template
+/** \name Operator Property Buttons Template
* \{ */
-static void template_operator_redo_property_buts_draw(
- const bContext *C, wmOperator *op, uiLayout *layout, int layout_flags, bool *r_has_advanced)
+typedef struct uiTemplateOperatorPropertyPollParam {
+ const bContext *C;
+ wmOperator *op;
+ short flag;
+} uiTemplateOperatorPropertyPollParam;
+
+#ifdef USE_OP_RESET_BUT
+static void ui_layout_operator_buts__reset_cb(bContext *UNUSED(C),
+ void *op_pt,
+ void *UNUSED(arg_dummy2))
+{
+ WM_operator_properties_reset((wmOperator *)op_pt);
+}
+#endif
+
+static bool ui_layout_operator_buts_poll_property(struct PointerRNA *UNUSED(ptr),
+ struct PropertyRNA *prop,
+ void *user_data)
+{
+ uiTemplateOperatorPropertyPollParam *params = user_data;
+
+ if ((params->flag & UI_TEMPLATE_OP_PROPS_HIDE_ADVANCED) &&
+ (RNA_property_tags(prop) & OP_PROP_TAG_ADVANCED)) {
+ return false;
+ }
+ return params->op->type->poll_property(params->C, params->op, prop);
+}
+
+static eAutoPropButsReturn template_operator_property_buts_draw_single(
+ const bContext *C,
+ wmOperator *op,
+ uiLayout *layout,
+ const eButLabelAlign label_align,
+ int layout_flags)
+{
+ uiBlock *block = uiLayoutGetBlock(layout);
+ eAutoPropButsReturn return_info = 0;
+
+ if (!op->properties) {
+ IDPropertyTemplate val = {0};
+ op->properties = IDP_New(IDP_GROUP, &val, "wmOperatorProperties");
+ }
+
+ /* poll() on this operator may still fail,
+ * at the moment there is no nice feedback when this happens just fails silently. */
+ if (!WM_operator_repeat_check(C, op)) {
+ UI_block_lock_set(block, true, "Operator can't' redo");
+ return return_info;
+ }
+ else {
+ /* useful for macros where only one of the steps can't be re-done */
+ UI_block_lock_clear(block);
+ }
+
+ if (layout_flags & UI_TEMPLATE_OP_PROPS_SHOW_TITLE) {
+ uiItemL(layout, WM_operatortype_name(op->type, op->ptr), ICON_NONE);
+ }
+
+ /* menu */
+ if (op->type->flag & OPTYPE_PRESET) {
+ /* XXX, no simple way to get WM_MT_operator_presets.bl_label
+ * from python! Label remains the same always! */
+ PointerRNA op_ptr;
+ uiLayout *row;
+
+ block->ui_operator = op;
+
+ row = uiLayoutRow(layout, true);
+ uiItemM(row, "WM_MT_operator_presets", NULL, ICON_NONE);
+
+ wmOperatorType *ot = WM_operatortype_find("WM_OT_operator_preset_add", false);
+ uiItemFullO_ptr(row, ot, "", ICON_ADD, NULL, WM_OP_INVOKE_DEFAULT, 0, &op_ptr);
+ RNA_string_set(&op_ptr, "operator", op->type->idname);
+
+ uiItemFullO_ptr(row, ot, "", ICON_REMOVE, NULL, WM_OP_INVOKE_DEFAULT, 0, &op_ptr);
+ RNA_string_set(&op_ptr, "operator", op->type->idname);
+ RNA_boolean_set(&op_ptr, "remove_active", true);
+ }
+
+ if (op->type->ui) {
+ op->layout = layout;
+ op->type->ui((bContext *)C, op);
+ op->layout = NULL;
+
+ /* UI_LAYOUT_OP_SHOW_EMPTY ignored. retun_info is ignored too. We could
+ * allow ot.ui callback to return this, but not needed right now. */
+ }
+ else {
+ wmWindowManager *wm = CTX_wm_manager(C);
+ PointerRNA ptr;
+ uiTemplateOperatorPropertyPollParam user_data = {.C = C, .op = op, .flag = layout_flags};
+ const bool use_prop_split = (layout_flags & UI_TEMPLATE_OP_PROPS_NO_SPLIT_LAYOUT) == 0;
+
+ RNA_pointer_create(&wm->id, op->type->srna, op->properties, &ptr);
+
+ uiLayoutSetPropSep(layout, use_prop_split);
+ uiLayoutSetPropDecorate(layout, false);
+
+ /* main draw call */
+ return_info = uiDefAutoButsRNA(
+ layout,
+ &ptr,
+ op->type->poll_property ? ui_layout_operator_buts_poll_property : NULL,
+ op->type->poll_property ? &user_data : NULL,
+ op->type->prop,
+ label_align,
+ (layout_flags & UI_TEMPLATE_OP_PROPS_COMPACT));
+
+ if ((return_info & UI_PROP_BUTS_NONE_ADDED) &&
+ (layout_flags & UI_TEMPLATE_OP_PROPS_SHOW_EMPTY)) {
+ uiItemL(layout, IFACE_("No Properties"), ICON_NONE);
+ }
+ }
+
+#ifdef USE_OP_RESET_BUT
+ /* its possible that reset can do nothing if all have PROP_SKIP_SAVE enabled
+ * but this is not so important if this button is drawn in those cases
+ * (which isn't all that likely anyway) - campbell */
+ if (op->properties->len) {
+ uiBut *but;
+ uiLayout *col; /* needed to avoid alignment errors with previous buttons */
+
+ col = uiLayoutColumn(layout, false);
+ block = uiLayoutGetBlock(col);
+ but = uiDefIconTextBut(block,
+ UI_BTYPE_BUT,
+ 0,
+ ICON_FILE_REFRESH,
+ IFACE_("Reset"),
+ 0,
+ 0,
+ UI_UNIT_X,
+ UI_UNIT_Y,
+ NULL,
+ 0.0,
+ 0.0,
+ 0.0,
+ 0.0,
+ TIP_("Reset operator defaults"));
+ UI_but_func_set(but, ui_layout_operator_buts__reset_cb, op, NULL);
+ }
+#endif
+
+ /* set various special settings for buttons */
+
+ /* Only do this if we're not refreshing an existing UI. */
+ if (block->oldblock == NULL) {
+ const bool is_popup = (block->flag & UI_BLOCK_KEEP_OPEN) != 0;
+ uiBut *but;
+
+ for (but = block->buttons.first; but; but = but->next) {
+ /* no undo for buttons for operator redo panels */
+ UI_but_flag_disable(but, UI_BUT_UNDO);
+
+ /* only for popups, see [#36109] */
+
+ /* if button is operator's default property, and a text-field, enable focus for it
+ * - this is used for allowing operators with popups to rename stuff with fewer clicks
+ */
+ if (is_popup) {
+ if ((but->rnaprop == op->type->prop) && (but->type == UI_BTYPE_TEXT)) {
+ UI_but_focus_on_enter_event(CTX_wm_window(C), but);
+ }
+ }
+ }
+ }
+
+ return return_info;
+}
+
+static void template_operator_property_buts_draw_recursive(const bContext *C,
+ wmOperator *op,
+ uiLayout *layout,
+ const eButLabelAlign label_align,
+ int layout_flags,
+ bool *r_has_advanced)
{
if (op->type->flag & OPTYPE_MACRO) {
- for (wmOperator *macro_op = op->macro.first; macro_op; macro_op = macro_op->next) {
- template_operator_redo_property_buts_draw(C, macro_op, layout, layout_flags, r_has_advanced);
+ LISTBASE_FOREACH (wmOperator *, macro_op, &op->macro) {
+ template_operator_property_buts_draw_recursive(
+ C, macro_op, layout, label_align, layout_flags, r_has_advanced);
}
}
else {
/* Might want to make label_align adjustable somehow. */
- eAutoPropButsReturn return_info = uiTemplateOperatorPropertyButs(
- C, layout, op, UI_BUT_LABEL_ALIGN_NONE, layout_flags);
+ eAutoPropButsReturn return_info = template_operator_property_buts_draw_single(
+ C, op, layout, label_align, layout_flags);
if (return_info & UI_PROP_BUTS_ANY_FAILED_CHECK) {
if (r_has_advanced) {
*r_has_advanced = true;
@@ -2444,6 +2638,61 @@ static void template_operator_redo_property_buts_draw(
}
}
+static bool ui_layout_operator_properties_only_booleans(const bContext *C,
+ wmWindowManager *wm,
+ wmOperator *op,
+ int layout_flags)
+{
+ if (op->type->flag & OPTYPE_MACRO) {
+ LISTBASE_FOREACH (wmOperator *, macro_op, &op->macro) {
+ if (!ui_layout_operator_properties_only_booleans(C, wm, macro_op, layout_flags)) {
+ return false;
+ }
+ }
+ }
+ else {
+ uiTemplateOperatorPropertyPollParam user_data = {.C = C, .op = op, .flag = layout_flags};
+ PointerRNA ptr;
+
+ RNA_pointer_create(&wm->id, op->type->srna, op->properties, &ptr);
+
+ RNA_STRUCT_BEGIN (&ptr, prop) {
+ if (RNA_property_flag(prop) & PROP_HIDDEN) {
+ continue;
+ }
+ if (op->type->poll_property &&
+ !ui_layout_operator_buts_poll_property(&ptr, prop, &user_data)) {
+ continue;
+ }
+ if (RNA_property_type(prop) != PROP_BOOLEAN) {
+ return false;
+ }
+ }
+ RNA_STRUCT_END;
+ }
+
+ return true;
+}
+
+/**
+ * Draw Operator property buttons for redoing execution with different settings.
+ * This function does not initialize the layout,
+ * functions can be called on the layout before and after.
+ */
+void uiTemplateOperatorPropertyButs(
+ const bContext *C, uiLayout *layout, wmOperator *op, eButLabelAlign label_align, short flag)
+{
+ wmWindowManager *wm = CTX_wm_manager(C);
+
+ /* If there are only checkbox items, don't use split layout by default. It looks weird if the
+ * checkboxes only use half the width. */
+ if (ui_layout_operator_properties_only_booleans(C, wm, op, flag)) {
+ flag |= UI_TEMPLATE_OP_PROPS_NO_SPLIT_LAYOUT;
+ }
+
+ template_operator_property_buts_draw_recursive(C, op, layout, label_align, flag, NULL);
+}
+
void uiTemplateOperatorRedoProperties(uiLayout *layout, const bContext *C)
{
wmOperator *op = WM_operator_last_redo(C);
@@ -2476,8 +2725,8 @@ void uiTemplateOperatorRedoProperties(uiLayout *layout, const bContext *C)
#endif
UI_block_func_handle_set(block, ED_undo_operator_repeat_cb_evt, op);
- template_operator_redo_property_buts_draw(
- C, op, layout, layout_flags, NULL /* &has_advanced */);
+ template_operator_property_buts_draw_recursive(
+ C, op, layout, UI_BUT_LABEL_ALIGN_NONE, layout_flags, NULL /* &has_advanced */);
/* Warning! this leaves the handle function for any other users of this block. */
#if 0
@@ -2496,7 +2745,7 @@ void uiTemplateOperatorRedoProperties(uiLayout *layout, const bContext *C)
static void constraint_active_func(bContext *UNUSED(C), void *ob_v, void *con_v)
{
- ED_object_constraint_set_active(ob_v, con_v);
+ ED_object_constraint_active_set(ob_v, con_v);
}
/* draw panel showing settings for a constraint */
@@ -6572,936 +6821,6 @@ void uiTemplateList(uiLayout *layout,
/** \} */
/* -------------------------------------------------------------------- */
-/** \name Operator Search Template
- * \{ */
-
-static void operator_call_cb(bContext *C, void *UNUSED(arg1), void *arg2)
-{
- wmOperatorType *ot = arg2;
-
- if (ot) {
- WM_operator_name_call_ptr(C, ot, WM_OP_INVOKE_DEFAULT, NULL);
- }
-}
-
-static bool has_word_prefix(const char *haystack, const char *needle, size_t needle_len)
-{
- const char *match = BLI_strncasestr(haystack, needle, needle_len);
- if (match) {
- if ((match == haystack) || (*(match - 1) == ' ') || ispunct(*(match - 1))) {
- return true;
- }
- else {
- return has_word_prefix(match + 1, needle, needle_len);
- }
- }
- else {
- return false;
- }
-}
-
-static void operator_search_cb(const bContext *C,
- void *UNUSED(arg),
- const char *str,
- uiSearchItems *items)
-{
- GHashIterator iter;
- const size_t str_len = strlen(str);
- const int words_max = (str_len / 2) + 1;
- int(*words)[2] = BLI_array_alloca(words, words_max);
-
- const int words_len = BLI_string_find_split_words(str, str_len, ' ', words, words_max);
-
- for (WM_operatortype_iter(&iter); !BLI_ghashIterator_done(&iter);
- BLI_ghashIterator_step(&iter)) {
- wmOperatorType *ot = BLI_ghashIterator_getValue(&iter);
- const char *ot_ui_name = CTX_IFACE_(ot->translation_context, ot->name);
- int index;
-
- if ((ot->flag & OPTYPE_INTERNAL) && (G.debug & G_DEBUG_WM) == 0) {
- continue;
- }
-
- /* match name against all search words */
- for (index = 0; index < words_len; index++) {
- if (!has_word_prefix(ot_ui_name, str + words[index][0], words[index][1])) {
- break;
- }
- }
-
- if (index == words_len) {
- if (WM_operator_poll((bContext *)C, ot)) {
- char name[256];
- int len = strlen(ot_ui_name);
-
- /* display name for menu, can hold hotkey */
- BLI_strncpy(name, ot_ui_name, sizeof(name));
-
- /* check for hotkey */
- if (len < sizeof(name) - 6) {
- if (WM_key_event_operator_string(C,
- ot->idname,
- WM_OP_EXEC_DEFAULT,
- NULL,
- true,
- &name[len + 1],
- sizeof(name) - len - 1)) {
- name[len] = UI_SEP_CHAR;
- }
- }
-
- if (!UI_search_item_add(items, name, ot, ICON_NONE, 0)) {
- break;
- }
- }
- }
- }
-}
-
-void UI_but_func_operator_search(uiBut *but)
-{
- UI_but_func_search_set(
- but, ui_searchbox_create_operator, operator_search_cb, NULL, false, operator_call_cb, NULL);
-}
-
-void uiTemplateOperatorSearch(uiLayout *layout)
-{
- uiBlock *block;
- uiBut *but;
- static char search[256] = "";
-
- block = uiLayoutGetBlock(layout);
- UI_block_layout_set_current(block, layout);
-
- but = uiDefSearchBut(
- block, search, 0, ICON_VIEWZOOM, sizeof(search), 0, 0, UI_UNIT_X * 6, UI_UNIT_Y, 0, 0, "");
- UI_but_func_operator_search(but);
-}
-
-/** \} */
-
-/* -------------------------------------------------------------------- */
-/** \name Menu Search Template
- * \{ */
-
-struct MenuSearch_Parent {
- struct MenuSearch_Parent *parent;
- MenuType *parent_mt;
- /* Set while writing menu items only. */
- struct MenuSearch_Parent *temp_child;
- const char *drawstr;
-};
-
-struct MenuSearch_Item {
- struct MenuSearch_Item *next, *prev;
- const char *drawstr;
- const char *drawwstr_full;
- /** Support a single level sub-menu nesting (for operator buttons that expand). */
- const char *drawstr_submenu;
- int icon;
- int state;
-
- struct MenuSearch_Parent *menu_parent;
- MenuType *mt;
-
- enum {
- MENU_SEARCH_TYPE_OP = 1,
- MENU_SEARCH_TYPE_RNA = 2,
- } type;
-
- union {
- /* Operator menu item. */
- struct {
- wmOperatorType *type;
- PointerRNA *opptr;
- short opcontext;
- bContextStore *context;
- } op;
-
- /* Property (only for check-boxe/boolean). */
- struct {
- PointerRNA ptr;
- PropertyRNA *prop;
- int index;
- /** Only for enum buttons. */
- int enum_value;
- } rna;
- };
-};
-
-struct MenuSearch_Data {
- /** MenuSearch_Item */
- ListBase items;
- /** Use for all small allocations. */
- MemArena *memarena;
-};
-
-static int menu_item_sort_by_drawstr_full(const void *menu_item_a_v, const void *menu_item_b_v)
-{
- const struct MenuSearch_Item *menu_item_a = menu_item_a_v;
- const struct MenuSearch_Item *menu_item_b = menu_item_b_v;
- return strcmp(menu_item_a->drawwstr_full, menu_item_b->drawwstr_full);
-}
-
-static const char *strdup_memarena(MemArena *memarena, const char *str)
-{
- const uint str_size = strlen(str) + 1;
- char *str_dst = BLI_memarena_alloc(memarena, str_size);
- memcpy(str_dst, str, str_size);
- return str_dst;
-}
-
-static const char *strdup_memarena_from_dynstr(MemArena *memarena, DynStr *dyn_str)
-{
- const uint str_size = BLI_dynstr_get_len(dyn_str) + 1;
- char *str_dst = BLI_memarena_alloc(memarena, str_size);
- BLI_dynstr_get_cstring_ex(dyn_str, str_dst);
- return str_dst;
-}
-
-static bool menu_items_from_ui_create_item_from_button(struct MenuSearch_Data *data,
- MemArena *memarena,
- struct MenuType *mt,
- const char *drawstr_submenu,
- uiBut *but)
-{
- struct MenuSearch_Item *item = NULL;
- if (but->optype != NULL) {
- item = BLI_memarena_calloc(memarena, sizeof(*item));
- item->type = MENU_SEARCH_TYPE_OP;
-
- item->op.type = but->optype;
- item->op.opcontext = but->opcontext;
- item->op.context = but->context;
- item->op.opptr = but->opptr;
- but->opptr = NULL;
- }
- else if (but->rnaprop != NULL) {
- const int prop_type = RNA_property_type(but->rnaprop);
- if (!ELEM(prop_type, PROP_BOOLEAN, PROP_ENUM)) {
- /* Note that these buttons are not prevented,
- * but aren't typically used in menus. */
- printf("Button '%s' in menu '%s' is a menu item with unsupported RNA type %d\n",
- but->drawstr,
- mt->idname,
- prop_type);
- }
- else {
- item = BLI_memarena_calloc(memarena, sizeof(*item));
- item->type = MENU_SEARCH_TYPE_RNA;
-
- item->rna.ptr = but->rnapoin;
- item->rna.prop = but->rnaprop;
- item->rna.index = but->rnaindex;
-
- if (prop_type == PROP_ENUM) {
- item->rna.enum_value = (int)but->hardmax;
- }
- }
- }
-
- if (item != NULL) {
- /* Handle shared settings. */
- item->drawstr = strdup_memarena(memarena, but->drawstr);
- item->icon = but->icon;
- item->state = (but->flag & (UI_BUT_DISABLED | UI_BUT_INACTIVE | UI_BUT_REDALERT));
- item->mt = mt;
- item->drawstr_submenu = drawstr_submenu ? strdup_memarena(memarena, drawstr_submenu) : NULL;
- BLI_addtail(&data->items, item);
- return true;
- }
-
- return false;
-}
-
-/**
- * Populate \a menu_stack with menus from inspecting active key-maps for this context.
- */
-static void menu_types_add_from_keymap_items(bContext *C,
- wmWindow *win,
- ScrArea *sa,
- ARegion *region,
- LinkNode **menuid_stack_p,
- GHash *menu_to_kmi,
- GSet *menu_tagged)
-{
- wmWindowManager *wm = CTX_wm_manager(C);
- ListBase *handlers[] = {
- &region->handlers,
- &sa->handlers,
- &win->handlers,
- };
-
- for (int handler_index = 0; handler_index < ARRAY_SIZE(handlers); handler_index++) {
- LISTBASE_FOREACH (wmEventHandler *, handler_base, handlers[handler_index]) {
- /* During this loop, ui handlers for nested menus can tag multiple handlers free. */
- if (handler_base->flag & WM_HANDLER_DO_FREE) {
- continue;
- }
- if (handler_base->type != WM_HANDLER_TYPE_KEYMAP) {
- continue;
- }
-
- else if (handler_base->poll == NULL || handler_base->poll(region, win->eventstate)) {
- wmEventHandler_Keymap *handler = (wmEventHandler_Keymap *)handler_base;
- wmKeyMap *keymap = WM_event_get_keymap_from_handler(wm, handler);
- if (keymap && WM_keymap_poll(C, keymap)) {
- LISTBASE_FOREACH (wmKeyMapItem *, kmi, &keymap->items) {
- if (kmi->flag & KMI_INACTIVE) {
- continue;
- }
- if (STR_ELEM(kmi->idname, "WM_OT_call_menu", "WM_OT_call_menu_pie")) {
- char menu_idname[MAX_NAME];
- RNA_string_get(kmi->ptr, "name", menu_idname);
- MenuType *mt = WM_menutype_find(menu_idname, false);
-
- if (mt && BLI_gset_add(menu_tagged, mt)) {
- /* Unlikely, but possible this will be included twice. */
- BLI_linklist_prepend(menuid_stack_p, mt);
-
- void **kmi_p;
- if (!BLI_ghash_ensure_p(menu_to_kmi, mt, &kmi_p)) {
- *kmi_p = kmi;
- }
- }
- }
- }
- }
- }
- }
- }
-}
-
-/**
- * Create #MenuSearch_Data by inspecting the current context, this uses two methods:
- *
- * - Look-up pre-defined editor-menus.
- * - Look-up key-map items which call menus.
- */
-static struct MenuSearch_Data *menu_items_from_ui_create(bContext *C,
- wmWindow *win,
- ScrArea *sa,
- ARegion *region)
-{
- MemArena *memarena = BLI_memarena_new(BLI_MEMARENA_STD_BUFSIZE, __func__);
- /** Map (#MenuType to #MenuSearch_Parent) */
- GHash *menu_parent_map = BLI_ghash_ptr_new(__func__);
- GHash *menu_display_name_map = BLI_ghash_ptr_new(__func__);
- const uiStyle *style = UI_style_get_dpi();
-
- /* Convert into non-ui structure. */
- struct MenuSearch_Data *data = MEM_callocN(sizeof(*data), __func__);
-
- DynStr *dyn_str = BLI_dynstr_new_memarena();
-
- /* Use a stack of menus to handle and discover new menus in passes. */
- LinkNode *menu_stack = NULL;
-
- /* Tag menu types not to add, either because they have already been added
- * or they have been blacklisted.
- * Set of #MenuType. */
- GSet *menu_tagged = BLI_gset_ptr_new(__func__);
- /** Map (#MenuType -> #wmKeyMapItem). */
- GHash *menu_to_kmi = BLI_ghash_ptr_new(__func__);
-
- /* Blacklist menus we don't want to show. */
- {
- const char *idname_array[] = {
- /* While we could include this, it's just showing filenames to load. */
- "TOPBAR_MT_file_open_recent",
- };
- for (int i = 0; i < ARRAY_SIZE(idname_array); i++) {
- MenuType *mt = WM_menutype_find(idname_array[i], false);
- if (mt != NULL) {
- BLI_gset_add(menu_tagged, mt);
- }
- }
- }
-
- /* Populate menus from the editors,
- * note that we could create a fake header, draw the header and extract the menus
- * from the buttons, however this is quite involved and can be avoided as by convention
- * each space-type has a single root-menu that headers use. */
- {
- const char *idname_array[] = {
- "TOPBAR_MT_editor_menus",
- /* Optional second menu for the space-type. */
- NULL,
- };
- int idname_array_len = 1;
-
-#define SPACE_MENU_MAP(space_type, menu_id) \
- case space_type: \
- idname_array[idname_array_len++] = menu_id; \
- break
-#define SPACE_MENU_NOP(space_type) \
- case space_type: \
- break
-
- if (sa != NULL) {
- switch (sa->spacetype) {
- SPACE_MENU_MAP(SPACE_VIEW3D, "VIEW3D_MT_editor_menus");
- SPACE_MENU_MAP(SPACE_GRAPH, "GRAPH_MT_editor_menus");
- SPACE_MENU_MAP(SPACE_OUTLINER, "OUTLINER_MT_editor_menus");
- SPACE_MENU_NOP(SPACE_PROPERTIES);
- SPACE_MENU_MAP(SPACE_FILE, "FILE_MT_editor_menus");
- SPACE_MENU_MAP(SPACE_IMAGE, "IMAGE_MT_editor_menus");
- SPACE_MENU_MAP(SPACE_INFO, "INFO_MT_editor_menus");
- SPACE_MENU_MAP(SPACE_SEQ, "SEQUENCER_MT_editor_menus");
- SPACE_MENU_MAP(SPACE_TEXT, "TEXT_MT_editor_menus");
- SPACE_MENU_MAP(SPACE_ACTION, "ACTION_MT_editor_menus");
- SPACE_MENU_MAP(SPACE_NLA, "NLA_MT_editor_menus");
- SPACE_MENU_MAP(SPACE_NODE, "NODE_MT_editor_menus");
- SPACE_MENU_MAP(SPACE_CONSOLE, "CONSOLE_MT_editor_menus");
- SPACE_MENU_MAP(SPACE_USERPREF, "USERPREF_MT_editor_menus");
- SPACE_MENU_MAP(SPACE_CLIP,
- (((const SpaceClip *)sa->spacedata.first)->mode == SC_MODE_TRACKING) ?
- "CLIP_MT_tracking_editor_menus" :
- "CLIP_MT_masking_editor_menus");
- SPACE_MENU_NOP(SPACE_TOPBAR);
- SPACE_MENU_NOP(SPACE_STATUSBAR);
- default:
- printf("Unknown space type '%d'\n", sa->spacetype);
- }
- }
- for (int i = 0; i < idname_array_len; i++) {
- MenuType *mt = WM_menutype_find(idname_array[i], false);
- if (mt != NULL) {
- BLI_linklist_prepend(&menu_stack, mt);
- BLI_gset_add(menu_tagged, mt);
- }
- }
- }
-#undef SPACE_MENU_MAP
-#undef SPACE_MENU_NOP
-
- bool has_keymap_menu_items = false;
-
- GHashIterator iter;
-
- while (menu_stack != NULL) {
- MenuType *mt = BLI_linklist_pop(&menu_stack);
- if (!WM_menutype_poll(C, mt)) {
- continue;
- }
-
- uiBlock *block = UI_block_begin(C, region, __func__, UI_EMBOSS);
- uiLayout *layout = UI_block_layout(
- block, UI_LAYOUT_VERTICAL, UI_LAYOUT_MENU, 0, 0, 200, 0, UI_MENU_PADDING, style);
-
- UI_block_flag_enable(block, UI_BLOCK_SHOW_SHORTCUT_ALWAYS);
-
- uiLayoutSetOperatorContext(layout, WM_OP_EXEC_REGION_WIN);
- UI_menutype_draw(C, mt, layout);
-
- UI_block_end(C, block);
-
- LISTBASE_FOREACH (uiBut *, but, &block->buttons) {
- MenuType *mt_from_but = NULL;
- /* Support menu titles with dynamic from initial labels
- * (used by edit-mesh context menu). */
- if (but->type == UI_BTYPE_LABEL) {
-
- /* Check if the label is the title. */
- uiBut *but_test = but->prev;
- while (but_test && but_test->type == UI_BTYPE_SEPR) {
- but_test = but_test->prev;
- }
-
- if (but_test == NULL) {
- BLI_ghash_insert(
- menu_display_name_map, mt, (void *)strdup_memarena(memarena, but->drawstr));
- }
- }
- else if (menu_items_from_ui_create_item_from_button(data, memarena, mt, NULL, but)) {
- /* pass */
- }
- else if ((mt_from_but = UI_but_menutype_get(but))) {
-
- if (BLI_gset_add(menu_tagged, mt_from_but)) {
- BLI_linklist_prepend(&menu_stack, mt_from_but);
- }
-
- if (!BLI_ghash_haskey(menu_parent_map, mt_from_but)) {
- struct MenuSearch_Parent *menu_parent = BLI_memarena_calloc(memarena,
- sizeof(*menu_parent));
- /* Use brackets for menu key shortcuts,
- * converting "Text|Some-Shortcut" to "Text (Some-Shortcut)".
- * This is needed so we don't right align sub-menu contents
- * we only want to do that for the last menu item, not the path that leads to it.
- */
- const char *drawstr_sep = but->flag & UI_BUT_HAS_SEP_CHAR ?
- strrchr(but->drawstr, UI_SEP_CHAR) :
- NULL;
- bool drawstr_is_empty = false;
- if (drawstr_sep != NULL) {
- BLI_assert(BLI_dynstr_get_len(dyn_str) == 0);
- /* Detect empty string, fallback to menu name. */
- const char *drawstr = but->drawstr;
- int drawstr_len = drawstr_sep - but->drawstr;
- if (UNLIKELY(drawstr_len == 0)) {
- drawstr = CTX_IFACE_(mt_from_but->translation_context, mt_from_but->label);
- drawstr_len = strlen(drawstr);
- if (drawstr[0] == '\0') {
- drawstr_is_empty = true;
- }
- }
- BLI_dynstr_nappend(dyn_str, drawstr, drawstr_len);
- BLI_dynstr_appendf(dyn_str, " (%s)", drawstr_sep + 1);
- menu_parent->drawstr = strdup_memarena_from_dynstr(memarena, dyn_str);
- BLI_dynstr_clear(dyn_str);
- }
- else {
- const char *drawstr = but->drawstr;
- if (UNLIKELY(drawstr[0] == '\0')) {
- drawstr = CTX_IFACE_(mt_from_but->translation_context, mt_from_but->label);
- if (drawstr[0] == '\0') {
- drawstr_is_empty = true;
- }
- }
- menu_parent->drawstr = strdup_memarena(memarena, drawstr);
- }
- menu_parent->parent_mt = mt;
- BLI_ghash_insert(menu_parent_map, mt_from_but, menu_parent);
-
- if (drawstr_is_empty) {
- printf("Warning: '%s' menu has empty 'bl_label'.\n", mt_from_but->idname);
- }
- }
- }
- else if (but->menu_create_func != NULL) {
- /* A non 'MenuType' menu button. */
-
- /* Only expand one level deep, this is mainly for expanding operator menus. */
- const char *drawstr_submenu = but->drawstr;
-
- /* +1 to avoid overlap with the current 'block'. */
- uiBlock *sub_block = UI_block_begin(C, region, __func__ + 1, UI_EMBOSS);
- uiLayout *sub_layout = UI_block_layout(
- sub_block, UI_LAYOUT_VERTICAL, UI_LAYOUT_MENU, 0, 0, 200, 0, UI_MENU_PADDING, style);
-
- UI_block_flag_enable(sub_block, UI_BLOCK_SHOW_SHORTCUT_ALWAYS);
-
- uiLayoutSetOperatorContext(sub_layout, WM_OP_INVOKE_REGION_WIN);
-
- but->menu_create_func(C, sub_layout, but->poin);
-
- UI_block_end(C, sub_block);
-
- LISTBASE_FOREACH (uiBut *, sub_but, &sub_block->buttons) {
- menu_items_from_ui_create_item_from_button(data, memarena, mt, drawstr_submenu, sub_but);
- }
-
- BLI_remlink(&region->uiblocks, sub_block);
- UI_block_free(NULL, sub_block);
- }
- }
- BLI_remlink(&region->uiblocks, block);
- UI_block_free(NULL, block);
-
- /* Add key-map items as a second pass,
- * so all menus are accessed from the header & top-bar before key shortcuts are expanded. */
- if ((menu_stack == NULL) && (has_keymap_menu_items == false)) {
- has_keymap_menu_items = true;
- menu_types_add_from_keymap_items(C, win, sa, region, &menu_stack, menu_to_kmi, menu_tagged);
- }
- }
-
- LISTBASE_FOREACH (struct MenuSearch_Item *, item, &data->items) {
- item->menu_parent = BLI_ghash_lookup(menu_parent_map, item->mt);
- }
-
- GHASH_ITER (iter, menu_parent_map) {
- struct MenuSearch_Parent *menu_parent = BLI_ghashIterator_getValue(&iter);
- menu_parent->parent = BLI_ghash_lookup(menu_parent_map, menu_parent->parent_mt);
- }
-
- /* NOTE: currently this builds the full path for each menu item,
- * that could be moved into the parent menu. */
-
- /* Unicode arrow. */
-#define MENU_SEP "\xe2\x86\x92"
-
- /* Set names as full paths. */
- LISTBASE_FOREACH (struct MenuSearch_Item *, item, &data->items) {
- if (item->menu_parent != NULL) {
- struct MenuSearch_Parent *menu_parent = item->menu_parent;
- menu_parent->temp_child = NULL;
- while (menu_parent && menu_parent->parent) {
- menu_parent->parent->temp_child = menu_parent;
- menu_parent = menu_parent->parent;
- }
- BLI_assert(BLI_dynstr_get_len(dyn_str) == 0);
- while (menu_parent) {
- BLI_dynstr_append(dyn_str, menu_parent->drawstr);
- BLI_dynstr_append(dyn_str, " " MENU_SEP " ");
- menu_parent = menu_parent->temp_child;
- }
- }
- else {
- BLI_assert(BLI_dynstr_get_len(dyn_str) == 0);
- const char *drawstr = BLI_ghash_lookup(menu_display_name_map, item->mt);
- if (drawstr == NULL) {
- drawstr = CTX_IFACE_(item->mt->translation_context, item->mt->label);
- }
- BLI_dynstr_append(dyn_str, drawstr);
-
- wmKeyMapItem *kmi = BLI_ghash_lookup(menu_to_kmi, item->mt);
- if (kmi != NULL) {
- char kmi_str[128];
- WM_keymap_item_to_string(kmi, false, kmi_str, sizeof(kmi_str));
- BLI_dynstr_appendf(dyn_str, " (%s)", kmi_str);
- }
-
- BLI_dynstr_append(dyn_str, " " MENU_SEP " ");
- }
-
- /* Optional nested menu. */
- if (item->drawstr_submenu != NULL) {
- BLI_dynstr_append(dyn_str, item->drawstr_submenu);
- BLI_dynstr_append(dyn_str, " " MENU_SEP " ");
- }
-
- BLI_dynstr_append(dyn_str, item->drawstr);
-
- item->drawwstr_full = strdup_memarena_from_dynstr(memarena, dyn_str);
- BLI_dynstr_clear(dyn_str);
- }
- BLI_dynstr_free(dyn_str);
-#undef MENU_SEP
-
- /* Finally sort menu items.
- *
- * Note: we might want to keep the in-menu order, for now sort all. */
- BLI_listbase_sort(&data->items, menu_item_sort_by_drawstr_full);
-
- BLI_ghash_free(menu_parent_map, NULL, NULL);
- BLI_ghash_free(menu_display_name_map, NULL, NULL);
-
- BLI_ghash_free(menu_to_kmi, NULL, NULL);
-
- BLI_gset_free(menu_tagged, NULL);
-
- data->memarena = memarena;
-
- return data;
-}
-
-static void menu_items_from_ui_destroy(void *data_v)
-{
- struct MenuSearch_Data *data = data_v;
- LISTBASE_FOREACH (struct MenuSearch_Item *, item, &data->items) {
- switch (item->type) {
- case MENU_SEARCH_TYPE_OP: {
- if (item->op.opptr != NULL) {
- WM_operator_properties_free(item->op.opptr);
- MEM_freeN(item->op.opptr);
- }
- }
- case MENU_SEARCH_TYPE_RNA: {
- break;
- }
- }
- }
-
- BLI_memarena_free(data->memarena);
-
- MEM_freeN(data);
-}
-
-static void menu_call_fn(bContext *C, void *UNUSED(arg1), void *arg2)
-{
- struct MenuSearch_Item *item = arg2;
- if (item == NULL) {
- return;
- }
- if (item->state & UI_BUT_DISABLED) {
- return;
- }
-
- switch (item->type) {
- case MENU_SEARCH_TYPE_OP: {
- CTX_store_set(C, item->op.context);
- WM_operator_name_call_ptr(C, item->op.type, item->op.opcontext, item->op.opptr);
- CTX_store_set(C, NULL);
- break;
- }
- case MENU_SEARCH_TYPE_RNA: {
- PointerRNA *ptr = &item->rna.ptr;
- PropertyRNA *prop = item->rna.prop;
- int index = item->rna.index;
- const int prop_type = RNA_property_type(prop);
- bool changed = false;
-
- if (prop_type == PROP_BOOLEAN) {
- const bool is_array = RNA_property_array_check(prop);
- if (is_array) {
- const bool value = RNA_property_boolean_get_index(ptr, prop, index);
- RNA_property_boolean_set_index(ptr, prop, index, !value);
- }
- else {
- const bool value = RNA_property_boolean_get(ptr, prop);
- RNA_property_boolean_set(ptr, prop, !value);
- }
- changed = true;
- }
- else if (prop_type == PROP_ENUM) {
- RNA_property_enum_set(ptr, prop, item->rna.enum_value);
- changed = true;
- }
-
- if (changed) {
- RNA_property_update(C, ptr, prop);
- }
- break;
- }
- }
-}
-
-static void menu_search_cb(const bContext *UNUSED(C),
- void *arg,
- const char *str,
- uiSearchItems *items)
-{
- struct MenuSearch_Data *data = arg;
- const size_t str_len = strlen(str);
- const int words_max = (str_len / 2) + 1;
- int(*words)[2] = BLI_array_alloca(words, words_max);
-
- const int words_len = BLI_string_find_split_words(str, str_len, ' ', words, words_max);
-
- for (struct MenuSearch_Item *item = data->items.first; item; item = item->next) {
- int index;
-
- /* match name against all search words */
- for (index = 0; index < words_len; index++) {
- if (!has_word_prefix(item->drawwstr_full, str + words[index][0], words[index][1])) {
- break;
- }
- }
-
- if (index == words_len) {
- if (!UI_search_item_add(items, item->drawwstr_full, item, item->icon, item->state)) {
- break;
- }
- }
- }
-}
-
-void UI_but_func_menu_search(uiBut *but)
-{
- bContext *C = but->block->evil_C;
- wmWindow *win = CTX_wm_window(C);
- ScrArea *sa = CTX_wm_area(C);
- ARegion *region = CTX_wm_region(C);
- struct MenuSearch_Data *data = menu_items_from_ui_create(C, win, sa, region);
- UI_but_func_search_set(but,
- ui_searchbox_create_menu,
- menu_search_cb,
- data,
- menu_items_from_ui_destroy,
- menu_call_fn,
- NULL);
-}
-
-void uiTemplateMenuSearch(uiLayout *layout)
-{
- uiBlock *block;
- uiBut *but;
- static char search[256] = "";
-
- block = uiLayoutGetBlock(layout);
- UI_block_layout_set_current(block, layout);
-
- but = uiDefSearchBut(
- block, search, 0, ICON_VIEWZOOM, sizeof(search), 0, 0, UI_UNIT_X * 6, UI_UNIT_Y, 0, 0, "");
- UI_but_func_menu_search(but);
-}
-
-/** \} */
-
-/* -------------------------------------------------------------------- */
-/** \name Operator Redo Properties Template
- * \{ */
-
-#ifdef USE_OP_RESET_BUT
-static void ui_layout_operator_buts__reset_cb(bContext *UNUSED(C),
- void *op_pt,
- void *UNUSED(arg_dummy2))
-{
- WM_operator_properties_reset((wmOperator *)op_pt);
-}
-#endif
-
-struct uiTemplateOperatorPropertyPollParam {
- const bContext *C;
- wmOperator *op;
- short flag;
-};
-
-static bool ui_layout_operator_buts_poll_property(struct PointerRNA *UNUSED(ptr),
- struct PropertyRNA *prop,
- void *user_data)
-{
- struct uiTemplateOperatorPropertyPollParam *params = user_data;
- if ((params->flag & UI_TEMPLATE_OP_PROPS_HIDE_ADVANCED) &&
- (RNA_property_tags(prop) & OP_PROP_TAG_ADVANCED)) {
- return false;
- }
- return params->op->type->poll_property(params->C, params->op, prop);
-}
-
-/**
- * Draw Operator property buttons for redoing execution with different settings.
- * This function does not initialize the layout,
- * functions can be called on the layout before and after.
- */
-eAutoPropButsReturn uiTemplateOperatorPropertyButs(const bContext *C,
- uiLayout *layout,
- wmOperator *op,
- const eButLabelAlign label_align,
- const short flag)
-{
- uiBlock *block = uiLayoutGetBlock(layout);
- eAutoPropButsReturn return_info = 0;
-
- if (!op->properties) {
- IDPropertyTemplate val = {0};
- op->properties = IDP_New(IDP_GROUP, &val, "wmOperatorProperties");
- }
-
- /* poll() on this operator may still fail,
- * at the moment there is no nice feedback when this happens just fails silently. */
- if (!WM_operator_repeat_check(C, op)) {
- UI_block_lock_set(block, true, "Operator can't' redo");
- return return_info;
- }
- else {
- /* useful for macros where only one of the steps can't be re-done */
- UI_block_lock_clear(block);
- }
-
- if (flag & UI_TEMPLATE_OP_PROPS_SHOW_TITLE) {
- uiItemL(layout, WM_operatortype_name(op->type, op->ptr), ICON_NONE);
- }
-
- /* menu */
- if (op->type->flag & OPTYPE_PRESET) {
- /* XXX, no simple way to get WM_MT_operator_presets.bl_label
- * from python! Label remains the same always! */
- PointerRNA op_ptr;
- uiLayout *row;
-
- block->ui_operator = op;
-
- row = uiLayoutRow(layout, true);
- uiItemM(row, "WM_MT_operator_presets", NULL, ICON_NONE);
-
- wmOperatorType *ot = WM_operatortype_find("WM_OT_operator_preset_add", false);
- uiItemFullO_ptr(row, ot, "", ICON_ADD, NULL, WM_OP_INVOKE_DEFAULT, 0, &op_ptr);
- RNA_string_set(&op_ptr, "operator", op->type->idname);
-
- uiItemFullO_ptr(row, ot, "", ICON_REMOVE, NULL, WM_OP_INVOKE_DEFAULT, 0, &op_ptr);
- RNA_string_set(&op_ptr, "operator", op->type->idname);
- RNA_boolean_set(&op_ptr, "remove_active", true);
- }
-
- if (op->type->ui) {
- op->layout = layout;
- op->type->ui((bContext *)C, op);
- op->layout = NULL;
-
- /* UI_LAYOUT_OP_SHOW_EMPTY ignored. return_info is ignored too. We could
- * allow ot.ui callback to return this, but not needed right now. */
- }
- else {
- wmWindowManager *wm = CTX_wm_manager(C);
- PointerRNA ptr;
- struct uiTemplateOperatorPropertyPollParam user_data = {
- .C = C,
- .op = op,
- .flag = flag,
- };
-
- RNA_pointer_create(&wm->id, op->type->srna, op->properties, &ptr);
-
- uiLayoutSetPropSep(layout, true);
- uiLayoutSetPropDecorate(layout, false);
-
- /* main draw call */
- return_info = uiDefAutoButsRNA(
- layout,
- &ptr,
- op->type->poll_property ? ui_layout_operator_buts_poll_property : NULL,
- op->type->poll_property ? &user_data : NULL,
- op->type->prop,
- label_align,
- (flag & UI_TEMPLATE_OP_PROPS_COMPACT));
-
- if ((return_info & UI_PROP_BUTS_NONE_ADDED) && (flag & UI_TEMPLATE_OP_PROPS_SHOW_EMPTY)) {
- uiItemL(layout, IFACE_("No Properties"), ICON_NONE);
- }
- }
-
-#ifdef USE_OP_RESET_BUT
- /* its possible that reset can do nothing if all have PROP_SKIP_SAVE enabled
- * but this is not so important if this button is drawn in those cases
- * (which isn't all that likely anyway) - campbell */
- if (op->properties->len) {
- uiBut *but;
- uiLayout *col; /* needed to avoid alignment errors with previous buttons */
-
- col = uiLayoutColumn(layout, false);
- block = uiLayoutGetBlock(col);
- but = uiDefIconTextBut(block,
- UI_BTYPE_BUT,
- 0,
- ICON_FILE_REFRESH,
- IFACE_("Reset"),
- 0,
- 0,
- UI_UNIT_X,
- UI_UNIT_Y,
- NULL,
- 0.0,
- 0.0,
- 0.0,
- 0.0,
- TIP_("Reset operator defaults"));
- UI_but_func_set(but, ui_layout_operator_buts__reset_cb, op, NULL);
- }
-#endif
-
- /* set various special settings for buttons */
-
- /* Only do this if we're not refreshing an existing UI. */
- if (block->oldblock == NULL) {
- const bool is_popup = (block->flag & UI_BLOCK_KEEP_OPEN) != 0;
- uiBut *but;
-
- for (but = block->buttons.first; but; but = but->next) {
- /* no undo for buttons for operator redo panels */
- UI_but_flag_disable(but, UI_BUT_UNDO);
-
- /* only for popups, see [#36109] */
-
- /* if button is operator's default property, and a text-field, enable focus for it
- * - this is used for allowing operators with popups to rename stuff with fewer clicks
- */
- if (is_popup) {
- if ((but->rnaprop == op->type->prop) && (but->type == UI_BTYPE_TEXT)) {
- UI_but_focus_on_enter_event(CTX_wm_window(C), but);
- }
- }
- }
- }
-
- return return_info;
-}
-
-/** \} */
-
-/* -------------------------------------------------------------------- */
/** \name Running Jobs Template
* \{ */
@@ -7579,7 +6898,7 @@ void uiTemplateRunningJobs(uiLayout *layout, bContext *C)
{
Main *bmain = CTX_data_main(C);
wmWindowManager *wm = CTX_wm_manager(C);
- ScrArea *sa = CTX_wm_area(C);
+ ScrArea *area = CTX_wm_area(C);
uiBlock *block;
void *owner = NULL;
int handle_event, icon = 0;
@@ -7653,7 +6972,7 @@ void uiTemplateRunningJobs(uiLayout *layout, bContext *C)
* progress bar which is not being updated (bake jobs only need
* to update NC_IMAGE context.
*/
- if (sa->spacetype != SPACE_NODE) {
+ if (area->spacetype != SPACE_NODE) {
handle_event = B_STOPOTHER;
icon = ICON_IMAGE;
break;
@@ -8204,7 +7523,10 @@ void uiTemplateNodeSocket(uiLayout *layout, bContext *UNUSED(C), float *color)
/** \name Cache File Template
* \{ */
-void uiTemplateCacheFile(uiLayout *layout, bContext *C, PointerRNA *ptr, const char *propname)
+void uiTemplateCacheFile(uiLayout *layout,
+ const bContext *C,
+ PointerRNA *ptr,
+ const char *propname)
{
if (!ptr->data) {
return;
diff --git a/source/blender/editors/interface/interface_undo.c b/source/blender/editors/interface/interface_undo.c
new file mode 100644
index 00000000000..016bc4159db
--- /dev/null
+++ b/source/blender/editors/interface/interface_undo.c
@@ -0,0 +1,139 @@
+/*
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * Copyright (C) 2020 Blender Foundation.
+ * All rights reserved.
+ */
+
+/** \file
+ * \ingroup edinterface
+ *
+ * Undo stack to use for UI widgets that manage their own editing state.
+ */
+
+#include <string.h>
+
+#include "BLI_listbase.h"
+
+#include "DNA_listBase.h"
+
+#include "MEM_guardedalloc.h"
+
+#include "interface_intern.h"
+
+/* -------------------------------------------------------------------- */
+/** \name Text Field Undo Stack
+ * \{ */
+
+typedef struct uiUndoStack_Text_State {
+ struct uiUndoStack_Text_State *next, *prev;
+ int cursor_index;
+ char text[0];
+} uiUndoStack_Text_State;
+
+typedef struct uiUndoStack_Text {
+ ListBase states;
+ uiUndoStack_Text_State *current;
+} uiUndoStack_Text;
+
+static const char *ui_textedit_undo_impl(uiUndoStack_Text *stack, int *r_cursor_index)
+{
+ /* Don't undo if no data has been pushed yet. */
+ if (stack->current == NULL) {
+ return NULL;
+ }
+
+ /* Travel backwards in the stack and copy information to the caller. */
+ if (stack->current->prev != NULL) {
+ stack->current = stack->current->prev;
+
+ *r_cursor_index = stack->current->cursor_index;
+ return stack->current->text;
+ }
+ return NULL;
+}
+
+static const char *ui_textedit_redo_impl(uiUndoStack_Text *stack, int *r_cursor_index)
+{
+ /* Don't redo if no data has been pushed yet. */
+ if (stack->current == NULL) {
+ return NULL;
+ }
+
+ /* Only redo if new data has not been entered since the last undo. */
+ if (stack->current->next) {
+ stack->current = stack->current->next;
+
+ *r_cursor_index = stack->current->cursor_index;
+ return stack->current->text;
+ }
+ return NULL;
+}
+
+const char *ui_textedit_undo(uiUndoStack_Text *stack, int direction, int *r_cursor_index)
+{
+ BLI_assert(ELEM(direction, -1, 1));
+ if (direction < 0) {
+ return ui_textedit_undo_impl(stack, r_cursor_index);
+ }
+ else {
+ return ui_textedit_redo_impl(stack, r_cursor_index);
+ }
+}
+
+/**
+ * Push the information in the arguments to a new state in the undo stack.
+ *
+ * \note Currently the total length of the undo stack is not limited.
+ */
+void ui_textedit_undo_push(uiUndoStack_Text *stack, const char *text, int cursor_index)
+{
+ /* Clear all redo actions from the current state. */
+ if (stack->current != NULL) {
+ while (stack->current->next) {
+ uiUndoStack_Text_State *state = stack->current->next;
+ BLI_remlink(&stack->states, state);
+ MEM_freeN(state);
+ }
+ }
+
+ /* Create the new state */
+ const int text_size = strlen(text) + 1;
+ stack->current = MEM_mallocN(sizeof(uiUndoStack_Text_State) + text_size, __func__);
+ stack->current->cursor_index = cursor_index;
+ memcpy(stack->current->text, text, text_size);
+ BLI_addtail(&stack->states, stack->current);
+}
+/**
+ * Start the undo stack.
+ *
+ * \note The current state should be pushed immediately after calling this.
+ */
+uiUndoStack_Text *ui_textedit_undo_stack_create(void)
+{
+ uiUndoStack_Text *stack = MEM_mallocN(sizeof(uiUndoStack_Text), __func__);
+ stack->current = NULL;
+ BLI_listbase_clear(&stack->states);
+
+ return stack;
+}
+
+void ui_textedit_undo_stack_destroy(uiUndoStack_Text *stack)
+{
+ BLI_freelistN(&stack->states);
+ MEM_freeN(stack);
+}
+
+/** \} */
diff --git a/source/blender/editors/interface/interface_utils.c b/source/blender/editors/interface/interface_utils.c
index a69837e9b51..4013e962ce5 100644
--- a/source/blender/editors/interface/interface_utils.c
+++ b/source/blender/editors/interface/interface_utils.c
@@ -22,6 +22,7 @@
*/
#include <assert.h>
+#include <ctype.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
@@ -36,6 +37,7 @@
#include "BLT_translation.h"
+#include "BKE_lib_id.h"
#include "BKE_report.h"
#include "MEM_guardedalloc.h"
@@ -50,6 +52,22 @@
#include "interface_intern.h"
+bool ui_str_has_word_prefix(const char *haystack, const char *needle, size_t needle_len)
+{
+ const char *match = BLI_strncasestr(haystack, needle, needle_len);
+ if (match) {
+ if ((match == haystack) || (*(match - 1) == ' ') || ispunct(*(match - 1))) {
+ return true;
+ }
+ else {
+ return ui_str_has_word_prefix(match + 1, needle, needle_len);
+ }
+ }
+ else {
+ return false;
+ }
+}
+
/*************************** RNA Utilities ******************************/
uiBut *uiDefAutoButR(uiBlock *block,
@@ -293,7 +311,7 @@ eAutoPropButsReturn uiDefAutoButsRNA(uiLayout *layout,
const bool compact)
{
eAutoPropButsReturn return_info = UI_PROP_BUTS_NONE_ADDED;
- uiLayout *split, *col;
+ uiLayout *col;
const char *name;
RNA_STRUCT_BEGIN (ptr, prop) {
@@ -324,19 +342,11 @@ eAutoPropButsReturn uiDefAutoButsRNA(uiLayout *layout,
}
else {
BLI_assert(label_align == UI_BUT_LABEL_ALIGN_SPLIT_COLUMN);
- split = uiLayoutSplit(layout, 0.5f, false);
-
- col = uiLayoutColumn(split, false);
- uiItemL(col, (is_boolean) ? "" : name, ICON_NONE);
- col = uiLayoutColumn(split, false);
+ col = uiLayoutColumn(layout, true);
+ /* Let uiItemFullR() create the split layout. */
+ uiLayoutSetPropSep(col, true);
}
- /* May need to add more cases here.
- * don't override enum flag names */
-
- /* name is shown above, empty name for button below */
- name = (flag & PROP_ENUM_FLAG || is_boolean) ? NULL : "";
-
break;
}
case UI_BUT_LABEL_ALIGN_NONE:
@@ -389,17 +399,23 @@ static int sort_search_items_list(const void *a, const void *b)
}
}
-void ui_rna_collection_search_cb(const struct bContext *C,
- void *arg,
- const char *str,
- uiSearchItems *items)
+void ui_rna_collection_search_update_fn(const struct bContext *C,
+ void *arg,
+ const char *str,
+ uiSearchItems *items)
{
uiRNACollectionSearch *data = arg;
- char *name;
int i = 0, iconid = 0, flag = RNA_property_flag(data->target_prop);
ListBase *items_list = MEM_callocN(sizeof(ListBase), "items_list");
CollItemSearch *cis;
- const bool skip_filter = (data->but_changed && !(*data->but_changed));
+ const bool is_ptr_target = (RNA_property_type(data->target_prop) == PROP_POINTER);
+ /* For non-pointer properties, UI code acts entirely based on the item's name. So the name has to
+ * match the RNA name exactly. So only for pointer properties, the name can be modified to add
+ * further UI hints. */
+ const bool requires_exact_data_name = !is_ptr_target;
+ const bool skip_filter = data->search_but && !data->search_but->changed;
+ char name_buf[UI_MAX_DRAW_STR];
+ char *name;
/* build a temporary list of relevant items first */
RNA_PROP_BEGIN (&data->search_ptr, itemptr, data->search_prop) {
@@ -411,30 +427,42 @@ void ui_rna_collection_search_cb(const struct bContext *C,
}
/* use filter */
- if (RNA_property_type(data->target_prop) == PROP_POINTER) {
+ if (is_ptr_target) {
if (RNA_property_pointer_poll(&data->target_ptr, data->target_prop, &itemptr) == 0) {
continue;
}
}
- /* Could use the string length here. */
- name = RNA_struct_name_get_alloc(&itemptr, NULL, 0, NULL);
-
iconid = 0;
if (itemptr.type && RNA_struct_is_ID(itemptr.type)) {
iconid = ui_id_icon_get(C, itemptr.data, false);
+
+ if (requires_exact_data_name) {
+ name = RNA_struct_name_get_alloc(&itemptr, name_buf, sizeof(name_buf), NULL);
+ }
+ else {
+ BKE_id_full_name_ui_prefix_get(name_buf, itemptr.data);
+ BLI_STATIC_ASSERT(sizeof(name_buf) >= MAX_ID_FULL_NAME_UI,
+ "Name string buffer should be big enough to hold full UI ID name");
+ name = name_buf;
+ }
+ }
+ else {
+ name = RNA_struct_name_get_alloc(&itemptr, name_buf, sizeof(name_buf), NULL);
}
if (name) {
if (skip_filter || BLI_strcasestr(name, str)) {
cis = MEM_callocN(sizeof(CollItemSearch), "CollectionItemSearch");
cis->data = itemptr.data;
- cis->name = MEM_dupallocN(name);
+ cis->name = BLI_strdup(name);
cis->index = i;
cis->iconid = iconid;
BLI_addtail(items_list, cis);
}
- MEM_freeN(name);
+ if (name != name_buf) {
+ MEM_freeN(name);
+ }
}
i++;
@@ -647,6 +675,7 @@ void UI_butstore_free(uiBlock *block, uiButStore *bs_handle)
}
BLI_freelistN(&bs_handle->items);
+ BLI_assert(BLI_findindex(&block->butstore, bs_handle) != -1);
BLI_remlink(&block->butstore, bs_handle);
MEM_freeN(bs_handle);
@@ -747,8 +776,7 @@ void UI_butstore_update(uiBlock *block)
/* move this list to the new block */
if (block->oldblock) {
if (block->oldblock->butstore.first) {
- block->butstore = block->oldblock->butstore;
- BLI_listbase_clear(&block->oldblock->butstore);
+ BLI_movelisttolist(&block->butstore, &block->oldblock->butstore);
}
}
diff --git a/source/blender/editors/interface/interface_widgets.c b/source/blender/editors/interface/interface_widgets.c
index 7e6ef11518a..0498b312618 100644
--- a/source/blender/editors/interface/interface_widgets.c
+++ b/source/blender/editors/interface/interface_widgets.c
@@ -27,7 +27,6 @@
#include <string.h>
#include "DNA_brush_types.h"
-#include "DNA_screen_types.h"
#include "DNA_userdef_types.h"
#include "BLI_math.h"
@@ -42,6 +41,8 @@
#include "BLF_api.h"
+#include "ED_node.h"
+
#include "UI_interface.h"
#include "UI_interface_icons.h"
@@ -1348,6 +1349,7 @@ void UI_widgetbase_draw_cache_flush(void)
(float *)g_widget_base_batch.params);
GPU_batch_uniform_3fv(batch, "checkerColorAndSize", checker_params);
GPU_matrix_bind(batch->interface);
+ GPU_shader_set_srgb_uniform(batch->interface);
GPU_batch_bind(batch);
GPU_batch_draw_advanced(batch, 0, 0, 0, g_widget_base_batch.count);
@@ -2091,6 +2093,25 @@ static void widget_draw_text_ime_underline(const uiFontStyle *fstyle,
}
#endif /* WITH_INPUT_IME */
+static bool widget_draw_text_underline_calc_center_x(const char *UNUSED(str),
+ const size_t str_step_ofs,
+ const rcti *glyph_step_bounds,
+ const int UNUSED(glyph_advance_x),
+ const rctf *glyph_bounds,
+ const int glyph_bearing[2],
+ void *user_data)
+{
+ /* The index of the character to get, set to the x-position. */
+ int *ul_data = user_data;
+ if (ul_data[0] == (int)str_step_ofs) {
+ ul_data[1] = glyph_step_bounds->xmin + glyph_bearing[0] +
+ (BLI_rctf_size_x(glyph_bounds) / 2.0f);
+ /* Early exit. */
+ return false;
+ }
+ return true;
+}
+
static void widget_draw_text(const uiFontStyle *fstyle,
const uiWidgetColors *wcol,
uiBut *but,
@@ -2300,7 +2321,7 @@ static void widget_draw_text(const uiFontStyle *fstyle,
if (!use_right_only) {
/* for underline drawing */
- float font_xofs, font_yofs;
+ int font_xofs, font_yofs;
int drawlen = (drawstr_left_len == INT_MAX) ? strlen(drawstr + but->ofs) :
(drawstr_left_len - but->ofs);
@@ -2315,34 +2336,44 @@ static void widget_draw_text(const uiFontStyle *fstyle,
},
drawlen,
&font_xofs,
- &font_yofs);
+ &font_yofs,
+ NULL);
if (but->menu_key != '\0') {
- char fixedbuf[128];
- const char *str;
-
- BLI_strncpy(fixedbuf, drawstr + but->ofs, min_ii(sizeof(fixedbuf), drawlen));
-
- str = strchr(fixedbuf, but->menu_key - 32); /* upper case */
- if (str == NULL) {
- str = strchr(fixedbuf, but->menu_key);
+ const char *drawstr_ofs = drawstr + but->ofs;
+ int ul_index = -1;
+
+ {
+ /* Find upper case, fallback to lower case. */
+ const char *drawstr_end = drawstr_ofs + drawlen;
+ const char keys[] = {but->menu_key - 32, but->menu_key};
+ for (int i = 0; i < ARRAY_SIZE(keys); i++) {
+ const char *drawstr_menu = strchr(drawstr_ofs, keys[i]);
+ if (drawstr_menu != NULL && drawstr_menu < drawstr_end) {
+ ul_index = (int)(drawstr_menu - drawstr_ofs);
+ break;
+ }
+ }
}
- if (str) {
- int ul_index = -1;
- float ul_advance;
-
- ul_index = (int)(str - fixedbuf);
-
+ if (ul_index != -1) {
if (fstyle->kerning == 1) {
BLF_enable(fstyle->uifont_id, BLF_KERNING_DEFAULT);
}
- fixedbuf[ul_index] = '\0';
- ul_advance = BLF_width(fstyle->uifont_id, fixedbuf, ul_index) + (1.0f * UI_DPI_FAC);
+ int ul_data[2] = {
+ ul_index, /* Character index to test. */
+ 0, /* Write the x-offset here. */
+ };
+ BLF_boundbox_foreach_glyph(fstyle->uifont_id,
+ drawstr_ofs,
+ ul_index + 1,
+ widget_draw_text_underline_calc_center_x,
+ ul_data);
+ ul_data[1] -= BLF_width(fstyle->uifont_id, "_", 2) / 2.0f;
BLF_position(fstyle->uifont_id,
- rect->xmin + font_xofs + ul_advance,
+ rect->xmin + font_xofs + ul_data[1],
rect->ymin + font_yofs,
0.0f);
BLF_color4ubv(fstyle->uifont_id, wcol->text);
@@ -2375,21 +2406,6 @@ static void widget_draw_text(const uiFontStyle *fstyle,
}
}
-static BIFIconID widget_icon_id(uiBut *but)
-{
- if (!(but->flag & UI_HAS_ICON)) {
- return ICON_NONE;
- }
-
- /* Consecutive icons can be toggle between. */
- if (but->drawflag & UI_BUT_ICON_REVERSE) {
- return but->icon - but->iconadd;
- }
- else {
- return but->icon + but->iconadd;
- }
-}
-
static void widget_draw_extra_icons(const uiWidgetColors *wcol,
uiBut *but,
rcti *rect,
@@ -2407,6 +2423,30 @@ static void widget_draw_extra_icons(const uiWidgetColors *wcol,
}
}
+static void widget_draw_node_link_socket(const uiWidgetColors *wcol,
+ const rcti *rect,
+ uiBut *but,
+ float alpha)
+{
+ /* Node socket pointer can be passed as custom_data, see UI_but_node_link_set(). */
+ if (but->custom_data) {
+ const float scale = 0.9f / but->block->aspect;
+
+ float col[4];
+ rgba_uchar_to_float(col, but->col);
+ col[3] *= alpha;
+
+ GPU_blend(true);
+ UI_widgetbase_draw_cache_flush();
+ GPU_blend(false);
+
+ ED_node_socket_draw(but->custom_data, rect, col, scale);
+ }
+ else {
+ widget_draw_icon(but, ICON_LAYER_USED, alpha, rect, wcol->text);
+ }
+}
+
/* draws text and icons for buttons */
static void widget_draw_text_icon(const uiFontStyle *fstyle,
const uiWidgetColors *wcol,
@@ -2416,15 +2456,27 @@ static void widget_draw_text_icon(const uiFontStyle *fstyle,
const bool show_menu_icon = ui_but_draw_menu_icon(but);
float alpha = (float)wcol->text[3] / 255.0f;
char password_str[UI_MAX_DRAW_STR];
+ bool no_text_padding = but->drawflag & UI_BUT_NO_TEXT_PADDING;
ui_but_text_password_hide(password_str, but, false);
/* check for button text label */
if (ELEM(but->type, UI_BTYPE_MENU, UI_BTYPE_POPOVER) && (but->flag & UI_BUT_NODE_LINK)) {
rcti temp = *rect;
- temp.xmin = rect->xmax - BLI_rcti_size_y(rect) - 1;
- widget_draw_icon(but, ICON_LAYER_USED, alpha, &temp, wcol->text);
- rect->xmax = temp.xmin;
+ const int size = BLI_rcti_size_y(rect) + 1; /* Not the icon size! */
+
+ if (but->drawflag & UI_BUT_ICON_LEFT) {
+ temp.xmax = rect->xmin + size;
+ rect->xmin = temp.xmax;
+ /* Further padding looks off. */
+ no_text_padding = true;
+ }
+ else {
+ temp.xmin = rect->xmax - size;
+ rect->xmax = temp.xmin;
+ }
+
+ widget_draw_node_link_socket(wcol, &temp, but, alpha);
}
/* If there's an icon too (made with uiDefIconTextBut) then draw the icon
@@ -2432,7 +2484,7 @@ static void widget_draw_text_icon(const uiFontStyle *fstyle,
/* Big previews with optional text label below */
if (but->flag & UI_BUT_ICON_PREVIEW && ui_block_is_menu(but->block)) {
- const BIFIconID icon = widget_icon_id(but);
+ const BIFIconID icon = ui_but_icon(but);
int icon_size = BLI_rcti_size_y(rect);
int text_size = 0;
@@ -2469,7 +2521,7 @@ static void widget_draw_text_icon(const uiFontStyle *fstyle,
}
#endif
- const BIFIconID icon = widget_icon_id(but);
+ const BIFIconID icon = ui_but_icon(but);
int icon_size_init = is_tool ? ICON_DEFAULT_HEIGHT_TOOLBAR : ICON_DEFAULT_HEIGHT;
const float icon_size = icon_size_init / (but->block->aspect * U.inv_dpi_fac);
const float icon_padding = 2 * UI_DPI_FAC;
@@ -2509,21 +2561,30 @@ static void widget_draw_text_icon(const uiFontStyle *fstyle,
rect->xmin += icon_size + icon_padding;
}
- int text_padding = (UI_TEXT_MARGIN_X * U.widget_unit) / but->block->aspect;
- if (but->editstr) {
- rect->xmin += text_padding;
- }
- else if (but->flag & UI_BUT_DRAG_MULTI) {
- bool text_is_edited = ui_but_drag_multi_edit_get(but) != NULL;
- if (text_is_edited) {
+ if (!no_text_padding) {
+ int text_padding = (UI_TEXT_MARGIN_X * U.widget_unit) / but->block->aspect;
+ if (but->editstr) {
rect->xmin += text_padding;
}
- }
- else if (but->drawflag & UI_BUT_TEXT_LEFT) {
- rect->xmin += text_padding;
- }
- else if (but->drawflag & UI_BUT_TEXT_RIGHT) {
- rect->xmax -= text_padding;
+ else if (but->flag & UI_BUT_DRAG_MULTI) {
+ bool text_is_edited = ui_but_drag_multi_edit_get(but) != NULL;
+ if (text_is_edited) {
+ rect->xmin += text_padding;
+ }
+ }
+ else if (but->drawflag & UI_BUT_TEXT_LEFT) {
+
+ /* Reduce the left padding for labels without an icon. */
+ if ((but->type == UI_BTYPE_LABEL) && !(but->flag & UI_HAS_ICON) &&
+ !ui_block_is_menu(but->block)) {
+ text_padding /= 2;
+ }
+
+ rect->xmin += text_padding;
+ }
+ else if (but->drawflag & UI_BUT_TEXT_RIGHT) {
+ rect->xmax -= text_padding;
+ }
}
/* Menu contains sub-menu items with triangle icon on their right. Shortcut
@@ -4127,10 +4188,10 @@ static void widget_optionbut(uiWidgetColors *wcol,
/* smaller */
delta = 1 + BLI_rcti_size_y(&recttemp) / 8;
- recttemp.xmin += delta;
- recttemp.ymin += delta;
- recttemp.xmax -= delta;
- recttemp.ymax -= delta;
+ BLI_rcti_resize(
+ &recttemp, BLI_rcti_size_x(&recttemp) - delta * 2, BLI_rcti_size_y(&recttemp) - delta * 2);
+ /* Keep one edge in place. */
+ BLI_rcti_translate(&recttemp, text_before_widget ? delta : -delta, 0);
rad = wcol->roundness * BLI_rcti_size_y(&recttemp);
round_box_edges(&wtb, UI_CNR_ALL, &recttemp, rad);
@@ -4142,13 +4203,13 @@ static void widget_optionbut(uiWidgetColors *wcol,
widgetbase_draw(&wtb, wcol);
- /* text space */
- const float offset = BLI_rcti_size_y(rect) * 0.7 + delta;
+ /* Text space - factor is really just eyeballed. */
+ const float offset = delta * 0.9;
if (text_before_widget) {
- rect->xmax -= offset;
+ rect->xmax = recttemp.xmin - offset;
}
else {
- rect->xmin += offset;
+ rect->xmin = recttemp.xmax + offset;
}
}
@@ -4204,7 +4265,7 @@ static void widget_box(
copy_v3_v3_uchar(old_col, wcol->inner);
/* abuse but->hsv - if it's non-zero, use this color as the box's background */
- if (but->col[3]) {
+ if (but != NULL && but->col[3]) {
wcol->inner[0] = but->col[0];
wcol->inner[1] = but->col[1];
wcol->inner[2] = but->col[2];
@@ -4597,7 +4658,7 @@ static int widget_roundbox_set(uiBut *but, rcti *rect)
* \{ */
/* conversion from old to new buttons, so still messy */
-void ui_draw_but(const bContext *C, ARegion *region, uiStyle *style, uiBut *but, rcti *rect)
+void ui_draw_but(const bContext *C, struct ARegion *region, uiStyle *style, uiBut *but, rcti *rect)
{
bTheme *btheme = UI_GetTheme();
const ThemeUI *tui = &btheme->tui;
@@ -4705,9 +4766,14 @@ void ui_draw_but(const bContext *C, ARegion *region, uiStyle *style, uiBut *but,
case UI_BTYPE_CHECKBOX_N:
if (!(but->flag & UI_HAS_ICON)) {
wt = widget_type(UI_WTYPE_CHECKBOX);
+
if ((but->drawflag & (UI_BUT_TEXT_LEFT | UI_BUT_TEXT_RIGHT)) == 0) {
but->drawflag |= UI_BUT_TEXT_LEFT;
}
+ /* widget_optionbut() carefully sets the text rectangle for fine tuned paddings. If the
+ * text drawing were to add its own padding, DPI and zoom factor would be applied twice
+ * in the final padding, so it's difficult to control it. */
+ but->drawflag |= UI_BUT_NO_TEXT_PADDING;
}
else {
wt = widget_type(UI_WTYPE_TOGGLE);
@@ -4955,6 +5021,30 @@ void ui_draw_menu_back(uiStyle *UNUSED(style), uiBlock *block, rcti *rect)
}
/**
+ * Uses the widget base drawing and colors from from the box widget, but ensures an opaque
+ * inner color.
+ */
+void ui_draw_box_opaque(rcti *rect, int roundboxalign)
+{
+ uiWidgetType *wt = widget_type(UI_WTYPE_BOX);
+
+ /* Alpha blend with the region's background color to force an opaque background. */
+ uiWidgetColors *wcol = &wt->wcol;
+ wt->state(wt, 0, 0);
+ float background[4];
+ UI_GetThemeColor4fv(TH_BACK, background);
+ float new_inner[4];
+ rgba_uchar_to_float(new_inner, wcol->inner);
+ new_inner[0] = (new_inner[0] * new_inner[3]) + (background[0] * (1.0f - new_inner[3]));
+ new_inner[1] = (new_inner[1] * new_inner[3]) + (background[1] * (1.0f - new_inner[3]));
+ new_inner[2] = (new_inner[2] * new_inner[3]) + (background[2] * (1.0f - new_inner[3]));
+ new_inner[3] = 1.0f;
+ rgba_float_to_uchar(wcol->inner, new_inner);
+
+ wt->custom(NULL, wcol, rect, 0, roundboxalign);
+}
+
+/**
* Similar to 'widget_menu_back', however we can't use the widget preset system
* because we need to pass in the original location so we know where to show the arrow.
*/
@@ -5027,7 +5117,10 @@ static void ui_draw_popover_back_impl(const uiWidgetColors *wcol,
GPU_blend(false);
}
-void ui_draw_popover_back(ARegion *region, uiStyle *UNUSED(style), uiBlock *block, rcti *rect)
+void ui_draw_popover_back(struct ARegion *region,
+ uiStyle *UNUSED(style),
+ uiBlock *block,
+ rcti *rect)
{
uiWidgetType *wt = widget_type(UI_WTYPE_MENU_BACK);
@@ -5258,10 +5351,23 @@ void ui_draw_tooltip_background(const uiStyle *UNUSED(style), uiBlock *UNUSED(bl
wt->draw(&wt->wcol, rect, 0, 0);
}
-/* helper call to draw a menu item without button */
-/* state: UI_ACTIVE or 0 */
-void ui_draw_menu_item(
- const uiFontStyle *fstyle, rcti *rect, const char *name, int iconid, int state, bool use_sep)
+/**
+ * Helper call to draw a menu item without a button.
+ *
+ * \param state: The state of the button,
+ * typically #UI_ACTIVE, #UI_BUT_DISABLED, #UI_BUT_INACTIVE.
+ * \param use_sep: When true, characters after the last #UI_SEP_CHAR are right aligned,
+ * use for displaying key shortcuts.
+ * \param r_xmax: The right hand position of the text, this takes into the icon,
+ * padding and text clipping when there is not enough room to display the full text.
+ */
+void ui_draw_menu_item(const uiFontStyle *fstyle,
+ rcti *rect,
+ const char *name,
+ int iconid,
+ int state,
+ bool use_sep,
+ int *r_xmax)
{
uiWidgetType *wt = widget_type(UI_WTYPE_MENU_ITEM);
rcti _rect = *rect;
@@ -5280,7 +5386,7 @@ void ui_draw_menu_item(
/* cut string in 2 parts? */
if (use_sep) {
- cpoin = strchr(name, UI_SEP_CHAR);
+ cpoin = strrchr(name, UI_SEP_CHAR);
if (cpoin) {
*cpoin = 0;
@@ -5311,27 +5417,21 @@ void ui_draw_menu_item(
UI_text_clip_middle_ex(fstyle, drawstr, okwidth, minwidth, max_len, '\0');
}
- UI_fontstyle_draw(fstyle,
- rect,
- drawstr,
- wt->wcol.text,
- &(struct uiFontStyleDraw_Params){
- .align = UI_STYLE_TEXT_LEFT,
- });
- }
-
- /* part text right aligned */
- if (use_sep) {
- if (cpoin) {
- rect->xmax = _rect.xmax - 5;
- UI_fontstyle_draw(fstyle,
- rect,
- cpoin + 1,
- wt->wcol.text,
- &(struct uiFontStyleDraw_Params){
- .align = UI_STYLE_TEXT_RIGHT,
- });
- *cpoin = UI_SEP_CHAR;
+ int xofs = 0, yofs = 0;
+ struct ResultBLF info;
+ UI_fontstyle_draw_ex(fstyle,
+ rect,
+ drawstr,
+ wt->wcol.text,
+ &(struct uiFontStyleDraw_Params){
+ .align = UI_STYLE_TEXT_LEFT,
+ },
+ BLF_DRAW_STR_DUMMY_MAX,
+ &xofs,
+ &yofs,
+ &info);
+ if (r_xmax != NULL) {
+ *r_xmax = xofs + info.width;
}
}
@@ -5351,6 +5451,24 @@ void ui_draw_menu_item(
UI_icon_draw_ex(xs, ys, iconid, aspect, 1.0f, 0.0f, wt->wcol.text, false);
GPU_blend(false);
}
+
+ /* part text right aligned */
+ if (use_sep) {
+ if (cpoin) {
+ /* Set inactive state for grayed out text. */
+ wt->state(wt, state | UI_BUT_INACTIVE, 0);
+
+ rect->xmax = _rect.xmax - 5;
+ UI_fontstyle_draw(fstyle,
+ rect,
+ cpoin + 1,
+ wt->wcol.text,
+ &(struct uiFontStyleDraw_Params){
+ .align = UI_STYLE_TEXT_RIGHT,
+ });
+ *cpoin = UI_SEP_CHAR;
+ }
+ }
}
void ui_draw_preview_item(
diff --git a/source/blender/editors/interface/resources.c b/source/blender/editors/interface/resources.c
index e5af8768e6e..01c9716ec86 100644
--- a/source/blender/editors/interface/resources.c
+++ b/source/blender/editors/interface/resources.c
@@ -1198,7 +1198,7 @@ void UI_GetThemeColor4fv(int colorid, float col[4])
void UI_GetThemeColorType4fv(int colorid, int spacetype, float col[4])
{
- const unsigned char *cp = UI_ThemeGetColorPtr(theme_active, spacetype, colorid);
+ const uchar *cp = UI_ThemeGetColorPtr(theme_active, spacetype, colorid);
col[0] = ((float)cp[0]) / 255.0f;
col[1] = ((float)cp[1]) / 255.0f;
col[2] = ((float)cp[2]) / 255.0f;
diff --git a/source/blender/editors/interface/view2d.c b/source/blender/editors/interface/view2d.c
index a93c80f02d2..f8419ba3eba 100644
--- a/source/blender/editors/interface/view2d.c
+++ b/source/blender/editors/interface/view2d.c
@@ -33,6 +33,7 @@
#include "BLI_array.h"
#include "BLI_link_utils.h"
+#include "BLI_listbase.h"
#include "BLI_math.h"
#include "BLI_memarena.h"
#include "BLI_rect.h"
@@ -59,7 +60,7 @@
#include "interface_intern.h"
-static void ui_view2d_curRect_validate_resize(View2D *v2d, bool resize, bool mask_scrollers);
+static void ui_view2d_curRect_validate_resize(View2D *v2d, bool resize);
/* -------------------------------------------------------------------- */
/** \name Internal Utilities
@@ -67,8 +68,8 @@ static void ui_view2d_curRect_validate_resize(View2D *v2d, bool resize, bool mas
BLI_INLINE int clamp_float_to_int(const float f)
{
- const float min = INT_MIN;
- const float max = INT_MAX;
+ const float min = (float)INT_MIN;
+ const float max = (float)INT_MAX;
if (UNLIKELY(f < min)) {
return min;
@@ -133,7 +134,7 @@ void UI_view2d_mask_from_win(const View2D *v2d, rcti *r_mask)
*
* \param mask_scroll: Optionally clamp scrollbars by this region.
*/
-static void view2d_masks(View2D *v2d, bool check_scrollers, const rcti *mask_scroll)
+static void view2d_masks(View2D *v2d, const rcti *mask_scroll)
{
int scroll;
@@ -143,26 +144,24 @@ static void view2d_masks(View2D *v2d, bool check_scrollers, const rcti *mask_scr
mask_scroll = &v2d->mask;
}
- if (check_scrollers) {
- /* check size if hiding flag is set: */
- if (v2d->scroll & V2D_SCROLL_HORIZONTAL_HIDE) {
- if (!(v2d->scroll & V2D_SCROLL_HORIZONTAL_HANDLES)) {
- if (BLI_rctf_size_x(&v2d->tot) > BLI_rctf_size_x(&v2d->cur)) {
- v2d->scroll &= ~V2D_SCROLL_HORIZONTAL_FULLR;
- }
- else {
- v2d->scroll |= V2D_SCROLL_HORIZONTAL_FULLR;
- }
+ /* check size if hiding flag is set: */
+ if (v2d->scroll & V2D_SCROLL_HORIZONTAL_HIDE) {
+ if (!(v2d->scroll & V2D_SCROLL_HORIZONTAL_HANDLES)) {
+ if (BLI_rctf_size_x(&v2d->tot) > BLI_rctf_size_x(&v2d->cur)) {
+ v2d->scroll &= ~V2D_SCROLL_HORIZONTAL_FULLR;
+ }
+ else {
+ v2d->scroll |= V2D_SCROLL_HORIZONTAL_FULLR;
}
}
- if (v2d->scroll & V2D_SCROLL_VERTICAL_HIDE) {
- if (!(v2d->scroll & V2D_SCROLL_VERTICAL_HANDLES)) {
- if (BLI_rctf_size_y(&v2d->tot) + 0.01f > BLI_rctf_size_y(&v2d->cur)) {
- v2d->scroll &= ~V2D_SCROLL_VERTICAL_FULLR;
- }
- else {
- v2d->scroll |= V2D_SCROLL_VERTICAL_FULLR;
- }
+ }
+ if (v2d->scroll & V2D_SCROLL_VERTICAL_HIDE) {
+ if (!(v2d->scroll & V2D_SCROLL_VERTICAL_HANDLES)) {
+ if (BLI_rctf_size_y(&v2d->tot) + 0.01f > BLI_rctf_size_y(&v2d->cur)) {
+ v2d->scroll &= ~V2D_SCROLL_VERTICAL_FULLR;
+ }
+ else {
+ v2d->scroll |= V2D_SCROLL_VERTICAL_FULLR;
}
}
}
@@ -268,7 +267,6 @@ void UI_view2d_region_reinit(View2D *v2d, short type, int winx, int winy)
*/
v2d->align = (V2D_ALIGN_NO_NEG_X | V2D_ALIGN_NO_NEG_Y);
v2d->keeptot = V2D_KEEPTOT_BOUNDS;
-
if (do_init) {
v2d->tot.xmin = v2d->tot.ymin = 0.0f;
v2d->tot.xmax = (float)(winx - 1);
@@ -385,8 +383,7 @@ void UI_view2d_region_reinit(View2D *v2d, short type, int winx, int winy)
v2d->winx = winx;
v2d->winy = winy;
- /* set masks (always do), but leave scroller scheck to totrect_set */
- view2d_masks(v2d, 0, NULL);
+ view2d_masks(v2d, NULL);
if (do_init) {
/* Visible by default. */
@@ -394,13 +391,12 @@ void UI_view2d_region_reinit(View2D *v2d, short type, int winx, int winy)
}
/* set 'tot' rect before setting cur? */
- /* XXX confusing stuff here still -
- * I made this function not check scroller hide - that happens in totrect_set */
+ /* XXX confusing stuff here still */
if (tot_changed) {
UI_view2d_totRect_set_resize(v2d, winx, winy, !do_init);
}
else {
- ui_view2d_curRect_validate_resize(v2d, !do_init, 0);
+ ui_view2d_curRect_validate_resize(v2d, !do_init);
}
}
@@ -409,7 +405,7 @@ void UI_view2d_region_reinit(View2D *v2d, short type, int winx, int winy)
* 'cur' is not allowed to be: larger than max, smaller than min, or outside of 'tot'
*/
// XXX pre2.5 -> this used to be called test_view2d()
-static void ui_view2d_curRect_validate_resize(View2D *v2d, bool resize, bool mask_scrollers)
+static void ui_view2d_curRect_validate_resize(View2D *v2d, bool resize)
{
float totwidth, totheight, curwidth, curheight, width, height;
float winx, winy;
@@ -851,12 +847,12 @@ static void ui_view2d_curRect_validate_resize(View2D *v2d, bool resize, bool mas
}
/* set masks */
- view2d_masks(v2d, mask_scrollers, NULL);
+ view2d_masks(v2d, NULL);
}
void UI_view2d_curRect_validate(View2D *v2d)
{
- ui_view2d_curRect_validate_resize(v2d, 0, 1);
+ ui_view2d_curRect_validate_resize(v2d, false);
}
/* ------------------ */
@@ -865,7 +861,6 @@ void UI_view2d_curRect_validate(View2D *v2d)
* to make sure 'related' views stay in synchrony */
void UI_view2d_sync(bScreen *screen, ScrArea *area, View2D *v2dcur, int flag)
{
- ScrArea *sa;
ARegion *region;
/* don't continue if no view syncing to be done */
@@ -900,8 +895,8 @@ void UI_view2d_sync(bScreen *screen, ScrArea *area, View2D *v2dcur, int flag)
/* check if doing whole screen syncing (i.e. time/horizontal) */
if ((v2dcur->flag & V2D_VIEWSYNC_SCREEN_TIME) && (screen)) {
- for (sa = screen->areabase.first; sa; sa = sa->next) {
- for (region = sa->regionbase.first; region; region = region->next) {
+ LISTBASE_FOREACH (ScrArea *, area_iter, &screen->areabase) {
+ for (region = area_iter->regionbase.first; region; region = region->next) {
/* don't operate on self */
if (v2dcur != &region->v2d) {
/* only if view has horizontal locks enabled */
@@ -983,22 +978,10 @@ void UI_view2d_curRect_reset(View2D *v2d)
/* Change the size of the maximum viewable area (i.e. 'tot' rect) */
void UI_view2d_totRect_set_resize(View2D *v2d, int width, int height, bool resize)
{
- // int scroll = view2d_scroll_mapped(v2d->scroll);
-
/* don't do anything if either value is 0 */
width = abs(width);
height = abs(height);
- /* hrumf! */
- /* XXX: there are work arounds for this in the panel and file browse code. */
- /* round to int, because this is called with width + V2D_SCROLL_WIDTH */
- // if (scroll & V2D_SCROLL_HORIZONTAL) {
- // width -= (int)V2D_SCROLL_WIDTH;
- // }
- // if (scroll & V2D_SCROLL_VERTICAL) {
- // height -= (int)V2D_SCROLL_HEIGHT;
- // }
-
if (ELEM(0, width, height)) {
if (G.debug & G_DEBUG) {
printf("Error: View2D totRect set exiting: v2d=%p width=%d height=%d\n",
@@ -1048,20 +1031,12 @@ void UI_view2d_totRect_set_resize(View2D *v2d, int width, int height, bool resiz
}
/* make sure that 'cur' rect is in a valid state as a result of these changes */
- ui_view2d_curRect_validate_resize(v2d, resize, 1);
+ ui_view2d_curRect_validate_resize(v2d, resize);
}
void UI_view2d_totRect_set(View2D *v2d, int width, int height)
{
- int scroll = view2d_scroll_mapped(v2d->scroll);
-
- UI_view2d_totRect_set_resize(v2d, width, height, 0);
-
- /* solve bad recursion... if scroller state changed,
- * mask is different, so you get different rects */
- if (scroll != view2d_scroll_mapped(v2d->scroll)) {
- UI_view2d_totRect_set_resize(v2d, width, height, 0);
- }
+ UI_view2d_totRect_set_resize(v2d, width, height, false);
}
bool UI_view2d_tab_set(View2D *v2d, int tab)
@@ -1259,7 +1234,7 @@ void UI_view2d_view_restore(const bContext *C)
* \{ */
/* Draw a constant grid in given 2d-region */
-void UI_view2d_constant_grid_draw(View2D *v2d, float step)
+void UI_view2d_constant_grid_draw(const View2D *v2d, float step)
{
float start_x, start_y;
int count_x, count_y;
@@ -1331,7 +1306,8 @@ void UI_view2d_constant_grid_draw(View2D *v2d, float step)
}
/* Draw a multi-level grid in given 2d-region */
-void UI_view2d_multi_grid_draw(View2D *v2d, int colorid, float step, int level_size, int totlevels)
+void UI_view2d_multi_grid_draw(
+ const View2D *v2d, int colorid, float step, int level_size, int totlevels)
{
/* Exit if there is nothing to draw */
if (totlevels == 0) {
@@ -1449,7 +1425,7 @@ View2DScrollers *UI_view2d_scrollers_calc(View2D *v2d, const rcti *mask_custom)
scrollers = MEM_callocN(sizeof(View2DScrollers), "View2DScrollers");
/* Always update before drawing (for dynamically sized scrollers). */
- view2d_masks(v2d, false, mask_custom);
+ view2d_masks(v2d, mask_custom);
vert = v2d->vert;
hor = v2d->hor;
@@ -1802,7 +1778,8 @@ bool UI_view2d_view_to_region_clip(
* \param x, y: Coordinates to convert.
* \param r_region_x, r_region_y: Resultant coordinates.
*/
-void UI_view2d_view_to_region(View2D *v2d, float x, float y, int *r_region_x, int *r_region_y)
+void UI_view2d_view_to_region(
+ const View2D *v2d, float x, float y, int *r_region_x, int *r_region_y)
{
/* step 1: express given coordinates as proportional values */
x = (x - v2d->cur.xmin) / BLI_rctf_size_x(&v2d->cur);
@@ -1818,7 +1795,7 @@ void UI_view2d_view_to_region(View2D *v2d, float x, float y, int *r_region_x, in
}
void UI_view2d_view_to_region_fl(
- View2D *v2d, float x, float y, float *r_region_x, float *r_region_y)
+ const View2D *v2d, float x, float y, float *r_region_x, float *r_region_y)
{
/* express given coordinates as proportional values */
x = (x - v2d->cur.xmin) / BLI_rctf_size_x(&v2d->cur);
@@ -1829,7 +1806,7 @@ void UI_view2d_view_to_region_fl(
*r_region_y = v2d->mask.ymin + (y * BLI_rcti_size_y(&v2d->mask));
}
-void UI_view2d_view_to_region_rcti(View2D *v2d, const rctf *rect_src, rcti *rect_dst)
+void UI_view2d_view_to_region_rcti(const View2D *v2d, const rctf *rect_src, rcti *rect_dst)
{
const float cur_size[2] = {BLI_rctf_size_x(&v2d->cur), BLI_rctf_size_y(&v2d->cur)};
const float mask_size[2] = {BLI_rcti_size_x(&v2d->mask), BLI_rcti_size_y(&v2d->mask)};
@@ -1850,7 +1827,7 @@ void UI_view2d_view_to_region_rcti(View2D *v2d, const rctf *rect_src, rcti *rect
clamp_rctf_to_rcti(rect_dst, &rect_tmp);
}
-void UI_view2d_view_to_region_m4(View2D *v2d, float matrix[4][4])
+void UI_view2d_view_to_region_m4(const View2D *v2d, float matrix[4][4])
{
rctf mask;
unit_m4(matrix);
@@ -1858,7 +1835,7 @@ void UI_view2d_view_to_region_m4(View2D *v2d, float matrix[4][4])
BLI_rctf_transform_calc_m4_pivot_min(&v2d->cur, &mask, matrix);
}
-bool UI_view2d_view_to_region_rcti_clip(View2D *v2d, const rctf *rect_src, rcti *rect_dst)
+bool UI_view2d_view_to_region_rcti_clip(const View2D *v2d, const rctf *rect_src, rcti *rect_dst)
{
const float cur_size[2] = {BLI_rctf_size_x(&v2d->cur), BLI_rctf_size_y(&v2d->cur)};
const float mask_size[2] = {BLI_rcti_size_x(&v2d->mask), BLI_rcti_size_y(&v2d->mask)};
@@ -1915,17 +1892,17 @@ View2D *UI_view2d_fromcontext(const bContext *C)
/* same as above, but it returns regionwindow. Utility for pulldowns or buttons */
View2D *UI_view2d_fromcontext_rwin(const bContext *C)
{
- ScrArea *sa = CTX_wm_area(C);
+ ScrArea *area = CTX_wm_area(C);
ARegion *region = CTX_wm_region(C);
- if (sa == NULL) {
+ if (area == NULL) {
return NULL;
}
if (region == NULL) {
return NULL;
}
if (region->regiontype != RGN_TYPE_WINDOW) {
- ARegion *region_win = BKE_area_find_region_type(sa, RGN_TYPE_WINDOW);
+ ARegion *region_win = BKE_area_find_region_type(area, RGN_TYPE_WINDOW);
return region_win ? &(region_win->v2d) : NULL;
}
return &(region->v2d);
@@ -1984,7 +1961,7 @@ float UI_view2d_scale_get_y(const View2D *v2d)
/**
* Same as ``UI_view2d_scale_get() - 1.0f / x, y``
*/
-void UI_view2d_scale_get_inverse(View2D *v2d, float *r_x, float *r_y)
+void UI_view2d_scale_get_inverse(const View2D *v2d, float *r_x, float *r_y)
{
if (r_x) {
*r_x = BLI_rctf_size_x(&v2d->cur) / BLI_rcti_size_x(&v2d->mask);
@@ -1998,7 +1975,7 @@ void UI_view2d_scale_get_inverse(View2D *v2d, float *r_x, float *r_y)
* Simple functions for consistent center offset access.
* Used by node editor to shift view center for each individual node tree.
*/
-void UI_view2d_center_get(struct View2D *v2d, float *r_x, float *r_y)
+void UI_view2d_center_get(const struct View2D *v2d, float *r_x, float *r_y)
{
/* get center */
if (r_x) {
diff --git a/source/blender/editors/interface/view2d_draw.c b/source/blender/editors/interface/view2d_draw.c
index 17a95ba3fff..677043c1ccf 100644
--- a/source/blender/editors/interface/view2d_draw.c
+++ b/source/blender/editors/interface/view2d_draw.c
@@ -40,6 +40,7 @@
#include "GPU_immediate.h"
#include "GPU_matrix.h"
+#include "GPU_state.h"
#include "WM_api.h"
@@ -196,7 +197,19 @@ static void draw_parallel_lines(const ParallelLinesSet *lines,
GPUVertFormat *format = immVertexFormat();
uint pos = GPU_vertformat_attr_add(format, "pos", GPU_COMP_F32, 2, GPU_FETCH_FLOAT);
- immBindBuiltinProgram(GPU_SHADER_2D_UNIFORM_COLOR);
+ if (U.pixelsize > 1.0f) {
+ float viewport[4];
+ GPU_viewport_size_get_f(viewport);
+
+ immBindBuiltinProgram(GPU_SHADER_3D_POLYLINE_UNIFORM_COLOR);
+ immUniform2fv("viewportSize", &viewport[2]);
+ /* -1.0f offset here is because the line is too fat due to the builtin anti-aliasing.
+ * TODO make a variant or a uniform to toggle it off. */
+ immUniform1f("lineWidth", U.pixelsize - 1.0f);
+ }
+ else {
+ immBindBuiltinProgram(GPU_SHADER_2D_UNIFORM_COLOR);
+ }
immUniformColor3ubv(color);
immBegin(GPU_PRIM_LINES, steps * 2);
diff --git a/source/blender/editors/interface/view2d_ops.c b/source/blender/editors/interface/view2d_ops.c
index 2adf441514b..5b1e5f746ef 100644
--- a/source/blender/editors/interface/view2d_ops.c
+++ b/source/blender/editors/interface/view2d_ops.c
@@ -79,9 +79,9 @@ static bool view2d_poll(bContext *C)
*/
typedef struct v2dViewPanData {
/** screen where view pan was initiated */
- bScreen *sc;
+ bScreen *screen;
/** area where view pan was initiated */
- ScrArea *sa;
+ ScrArea *area;
/** region where view pan was initiated */
ARegion *region;
/** view2d we're operating in */
@@ -126,8 +126,8 @@ static int view_pan_init(bContext *C, wmOperator *op)
op->customdata = vpd;
/* set pointers to owners */
- vpd->sc = CTX_wm_screen(C);
- vpd->sa = CTX_wm_area(C);
+ vpd->screen = CTX_wm_screen(C);
+ vpd->area = CTX_wm_area(C);
vpd->v2d = v2d;
vpd->region = region;
@@ -190,7 +190,7 @@ static void view_pan_apply_ex(bContext *C, v2dViewPanData *vpd, float dx, float
/* request updates to be done... */
WM_event_add_mousemove(CTX_wm_window(C));
- UI_view2d_sync(vpd->sc, vpd->sa, v2d, V2D_LOCK_COPY);
+ UI_view2d_sync(vpd->screen, vpd->area, v2d, V2D_LOCK_COPY);
}
static void view_pan_apply(bContext *C, wmOperator *op)
@@ -589,13 +589,13 @@ typedef struct v2dViewZoomData {
*/
static void view_zoom_axis_lock_defaults(bContext *C, bool r_do_zoom_xy[2])
{
- ScrArea *sa = CTX_wm_area(C);
+ ScrArea *area = CTX_wm_area(C);
r_do_zoom_xy[0] = true;
r_do_zoom_xy[1] = true;
/* default not to zoom the sequencer vertically */
- if (sa && sa->spacetype == SPACE_SEQ) {
+ if (area && area->spacetype == SPACE_SEQ) {
ARegion *region = CTX_wm_region(C);
if (region && region->regiontype == RGN_TYPE_WINDOW) {
@@ -758,8 +758,8 @@ static void view_zoomstep_apply_ex(
UI_view2d_curRect_validate(v2d);
if (ED_region_snap_size_apply(region, snap_test)) {
- ScrArea *sa = CTX_wm_area(C);
- ED_area_tag_redraw(sa);
+ ScrArea *area = CTX_wm_area(C);
+ ED_area_tag_redraw(area);
WM_event_add_notifier(C, NC_SCREEN | NA_EDITED, NULL);
}
@@ -1017,8 +1017,8 @@ static void view_zoomdrag_apply(bContext *C, wmOperator *op)
UI_view2d_curRect_validate(v2d);
if (ED_region_snap_size_apply(vzd->region, snap_test)) {
- ScrArea *sa = CTX_wm_area(C);
- ED_area_tag_redraw(sa);
+ ScrArea *area = CTX_wm_area(C);
+ ED_area_tag_redraw(area);
WM_event_add_notifier(C, NC_SCREEN | NA_EDITED, NULL);
}
@@ -2211,8 +2211,8 @@ static int reset_exec(bContext *C, wmOperator *UNUSED(op))
UI_view2d_curRect_validate(v2d);
if (ED_region_snap_size_apply(region, snap_test)) {
- ScrArea *sa = CTX_wm_area(C);
- ED_area_tag_redraw(sa);
+ ScrArea *area = CTX_wm_area(C);
+ ED_area_tag_redraw(area);
WM_event_add_notifier(C, NC_SCREEN | NA_EDITED, NULL);
}
diff --git a/source/blender/editors/io/io_alembic.c b/source/blender/editors/io/io_alembic.c
index af17303466b..dc8ad858a9f 100644
--- a/source/blender/editors/io/io_alembic.c
+++ b/source/blender/editors/io/io_alembic.c
@@ -10,7 +10,7 @@
* 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,
+ * 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 Blender Foundation.
@@ -663,7 +663,7 @@ static int wm_alembic_import_exec(bContext *C, wmOperator *op)
/* Switch out of edit mode to avoid being stuck in it (T54326). */
Object *obedit = CTX_data_edit_object(C);
if (obedit) {
- ED_object_mode_toggle(C, OB_MODE_EDIT);
+ ED_object_mode_set(C, OB_MODE_OBJECT);
}
bool ok = ABC_import(C,
diff --git a/source/blender/editors/io/io_alembic.h b/source/blender/editors/io/io_alembic.h
index 881712fe630..ecd8c1818f8 100644
--- a/source/blender/editors/io/io_alembic.h
+++ b/source/blender/editors/io/io_alembic.h
@@ -10,7 +10,7 @@
* 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,
+ * 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 Blender Foundation.
diff --git a/source/blender/editors/io/io_cache.c b/source/blender/editors/io/io_cache.c
index 6c5abf60272..045a293f71b 100644
--- a/source/blender/editors/io/io_cache.c
+++ b/source/blender/editors/io/io_cache.c
@@ -10,7 +10,7 @@
* 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,
+ * 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 Blender Foundation.
diff --git a/source/blender/editors/io/io_cache.h b/source/blender/editors/io/io_cache.h
index 25548dcdbce..c6fc50a236e 100644
--- a/source/blender/editors/io/io_cache.h
+++ b/source/blender/editors/io/io_cache.h
@@ -10,7 +10,7 @@
* 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,
+ * 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 Blender Foundation.
diff --git a/source/blender/editors/io/io_usd.c b/source/blender/editors/io/io_usd.c
index bb527ee6a3f..262b15c63e5 100644
--- a/source/blender/editors/io/io_usd.c
+++ b/source/blender/editors/io/io_usd.c
@@ -10,7 +10,7 @@
* 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,
+ * 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) 2019 Blender Foundation.
diff --git a/source/blender/editors/io/io_usd.h b/source/blender/editors/io/io_usd.h
index 4738e1c348d..c794dc744df 100644
--- a/source/blender/editors/io/io_usd.h
+++ b/source/blender/editors/io/io_usd.h
@@ -10,7 +10,7 @@
* 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,
+ * 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) 2019 Blender Foundation.
diff --git a/source/blender/editors/mask/mask_add.c b/source/blender/editors/mask/mask_add.c
index 5d461ffdb20..767976b5ae6 100644
--- a/source/blender/editors/mask/mask_add.c
+++ b/source/blender/editors/mask/mask_add.c
@@ -29,7 +29,6 @@
#include "BKE_mask.h"
#include "DEG_depsgraph.h"
-#include "DEG_depsgraph_query.h"
#include "DNA_mask_types.h"
#include "DNA_scene_types.h"
@@ -445,11 +444,11 @@ static void mask_point_make_pixel_space(bContext *C,
float point_normalized[2],
float point_pixel[2])
{
- ScrArea *sa = CTX_wm_area(C);
+ ScrArea *area = CTX_wm_area(C);
ARegion *region = CTX_wm_region(C);
float scalex, scaley;
- ED_mask_pixelspace_factor(sa, region, &scalex, &scaley);
+ ED_mask_pixelspace_factor(area, region, &scalex, &scaley);
point_pixel[0] = point_normalized[0] * scalex;
point_pixel[1] = point_normalized[1] * scaley;
@@ -557,12 +556,12 @@ static int add_vertex_exec(bContext *C, wmOperator *op)
static int add_vertex_invoke(bContext *C, wmOperator *op, const wmEvent *event)
{
- ScrArea *sa = CTX_wm_area(C);
+ ScrArea *area = CTX_wm_area(C);
ARegion *region = CTX_wm_region(C);
float co[2];
- ED_mask_mouse_pos(sa, region, event->mval, co);
+ ED_mask_mouse_pos(area, region, event->mval, co);
RNA_float_set_array(op->ptr, "location", co);
@@ -649,12 +648,12 @@ static int add_feather_vertex_exec(bContext *C, wmOperator *op)
static int add_feather_vertex_invoke(bContext *C, wmOperator *op, const wmEvent *event)
{
- ScrArea *sa = CTX_wm_area(C);
+ ScrArea *area = CTX_wm_area(C);
ARegion *region = CTX_wm_region(C);
float co[2];
- ED_mask_mouse_pos(sa, region, event->mval, co);
+ ED_mask_mouse_pos(area, region, event->mval, co);
RNA_float_set_array(op->ptr, "location", co);
@@ -694,7 +693,7 @@ void MASK_OT_add_feather_vertex(wmOperatorType *ot)
static int create_primitive_from_points(
bContext *C, wmOperator *op, const float (*points)[2], int num_points, char handle_type)
{
- ScrArea *sa = CTX_wm_area(C);
+ ScrArea *area = CTX_wm_area(C);
Mask *mask;
MaskLayer *mask_layer;
MaskSpline *new_spline;
@@ -702,7 +701,7 @@ static int create_primitive_from_points(
int i, width, height;
int size = RNA_float_get(op->ptr, "size");
- ED_mask_get_size(sa, &width, &height);
+ ED_mask_get_size(area, &width, &height);
scale = (float)size / max_ii(width, height);
/* Get location in mask space. */
@@ -763,12 +762,12 @@ static int create_primitive_from_points(
static int primitive_add_invoke(bContext *C, wmOperator *op, const wmEvent *UNUSED(event))
{
- ScrArea *sa = CTX_wm_area(C);
+ ScrArea *area = CTX_wm_area(C);
float cursor[2];
int width, height;
- ED_mask_get_size(sa, &width, &height);
- ED_mask_cursor_location_get(sa, cursor);
+ ED_mask_get_size(area, &width, &height);
+ ED_mask_cursor_location_get(area, cursor);
cursor[0] *= width;
cursor[1] *= height;
diff --git a/source/blender/editors/mask/mask_draw.c b/source/blender/editors/mask/mask_draw.c
index a532ff9e1f0..3786ed2789c 100644
--- a/source/blender/editors/mask/mask_draw.c
+++ b/source/blender/editors/mask/mask_draw.c
@@ -54,12 +54,10 @@
#include "DEG_depsgraph_query.h"
-#include "mask_intern.h" /* own include */
-
static void mask_spline_color_get(MaskLayer *mask_layer,
MaskSpline *spline,
const bool is_sel,
- unsigned char r_rgb[4])
+ uchar r_rgb[4])
{
if (is_sel) {
if (mask_layer->act_spline == spline) {
@@ -81,7 +79,7 @@ static void mask_spline_color_get(MaskLayer *mask_layer,
static void mask_spline_feather_color_get(MaskLayer *UNUSED(mask_layer),
MaskSpline *UNUSED(spline),
const bool is_sel,
- unsigned char r_rgb[4])
+ uchar r_rgb[4])
{
if (is_sel) {
r_rgb[1] = 255;
@@ -126,7 +124,7 @@ static void draw_single_handle(const MaskLayer *mask_layer,
GPUVertFormat *format = immVertexFormat();
uint pos = GPU_vertformat_attr_add(format, "pos", GPU_COMP_F32, 2, GPU_FETCH_FLOAT);
- const unsigned char rgb_gray[4] = {0x60, 0x60, 0x60, 0xff};
+ const uchar rgb_gray[4] = {0x60, 0x60, 0x60, 0xff};
immBindBuiltinProgram(GPU_SHADER_2D_UNIFORM_COLOR);
immUniformColor3ubv(rgb_gray);
@@ -196,7 +194,7 @@ static void draw_spline_points(const bContext *C,
(mask_layer->restrictflag & MASK_RESTRICT_SELECT) == 0;
const bool is_smooth = (draw_flag & MASK_DRAWFLAG_SMOOTH) != 0;
- unsigned char rgb_spline[4];
+ uchar rgb_spline[4];
MaskSplinePoint *points_array = BKE_mask_spline_point_array(spline);
SpaceClip *sc = CTX_wm_space_clip(C);
bool undistort = false;
@@ -370,28 +368,26 @@ static void draw_spline_points(const bContext *C,
}
}
-static void mask_color_active_tint(unsigned char r_rgb[4],
- const unsigned char rgb[4],
- const bool is_active)
+static void mask_color_active_tint(uchar r_rgb[4], const uchar rgb[4], const bool is_active)
{
if (!is_active) {
- r_rgb[0] = (unsigned char)((((int)(rgb[0])) + 128) / 2);
- r_rgb[1] = (unsigned char)((((int)(rgb[1])) + 128) / 2);
- r_rgb[2] = (unsigned char)((((int)(rgb[2])) + 128) / 2);
+ r_rgb[0] = (uchar)((((int)(rgb[0])) + 128) / 2);
+ r_rgb[1] = (uchar)((((int)(rgb[1])) + 128) / 2);
+ r_rgb[2] = (uchar)((((int)(rgb[2])) + 128) / 2);
r_rgb[3] = rgb[3];
}
else {
- *(unsigned int *)r_rgb = *(const unsigned int *)rgb;
+ *(uint *)r_rgb = *(const uint *)rgb;
}
}
-static void mask_draw_array(unsigned int pos,
+static void mask_draw_array(uint pos,
GPUPrimType prim_type,
const float (*points)[2],
- unsigned int vertex_len)
+ uint vertex_len)
{
immBegin(prim_type, vertex_len);
- for (unsigned int i = 0; i < vertex_len; i++) {
+ for (uint i = 0; i < vertex_len; i++) {
immVertex2fv(pos, points[i]);
}
immEnd();
@@ -403,13 +399,13 @@ static void mask_draw_curve_type(const bContext *C,
int tot_point,
const bool is_feather,
const bool is_active,
- const unsigned char rgb_spline[4],
+ const uchar rgb_spline[4],
const char draw_type)
{
const GPUPrimType draw_method = (spline->flag & MASK_SPLINE_CYCLIC) ? GPU_PRIM_LINE_LOOP :
GPU_PRIM_LINE_STRIP;
- const unsigned char rgb_black[4] = {0x00, 0x00, 0x00, 0xff};
- unsigned char rgb_tmp[4];
+ const uchar rgb_black[4] = {0x00, 0x00, 0x00, 0xff};
+ uchar rgb_tmp[4];
SpaceClip *sc = CTX_wm_space_clip(C);
float(*points)[2] = orig_points;
@@ -471,9 +467,9 @@ static void mask_draw_curve_type(const bContext *C,
}
if (is_feather) {
- rgb_tmp[0] = (unsigned char)(((short)rgb_tmp[0] + (short)rgb_spline[0]) / 2);
- rgb_tmp[1] = (unsigned char)(((short)rgb_tmp[1] + (short)rgb_spline[1]) / 2);
- rgb_tmp[2] = (unsigned char)(((short)rgb_tmp[2] + (short)rgb_spline[2]) / 2);
+ rgb_tmp[0] = (uchar)(((short)rgb_tmp[0] + (short)rgb_spline[0]) / 2);
+ rgb_tmp[1] = (uchar)(((short)rgb_tmp[1] + (short)rgb_spline[1]) / 2);
+ rgb_tmp[2] = (uchar)(((short)rgb_tmp[2] + (short)rgb_spline[2]) / 2);
}
mask_color_active_tint(rgb_tmp, rgb_tmp, is_active);
@@ -527,20 +523,20 @@ static void draw_spline_curve(const bContext *C,
const int width,
const int height)
{
- const unsigned int resol = max_ii(BKE_mask_spline_feather_resolution(spline, width, height),
- BKE_mask_spline_resolution(spline, width, height));
+ const uint resol = max_ii(BKE_mask_spline_feather_resolution(spline, width, height),
+ BKE_mask_spline_resolution(spline, width, height));
- unsigned char rgb_tmp[4];
+ uchar rgb_tmp[4];
const bool is_spline_sel = (spline->flag & SELECT) &&
(mask_layer->restrictflag & MASK_RESTRICT_SELECT) == 0;
const bool is_smooth = (draw_flag & MASK_DRAWFLAG_SMOOTH) != 0;
const bool is_fill = (spline->flag & MASK_SPLINE_NOFILL) == 0;
- unsigned int tot_diff_point;
+ uint tot_diff_point;
float(*diff_points)[2];
- unsigned int tot_feather_point;
+ uint tot_feather_point;
float(*feather_points)[2];
diff_points = BKE_mask_spline_differentiate_with_resolution(spline, &tot_diff_point, resol);
@@ -614,7 +610,7 @@ static void draw_mask_layers(const bContext *C,
continue;
}
- for (MaskSpline *spline = mask_layer->splines.first; spline; spline = spline->next) {
+ LISTBASE_FOREACH (MaskSpline *, spline, &mask_layer->splines) {
/* draw curve itself first... */
draw_spline_curve(C, mask_layer, spline, draw_flag, draw_type, is_active, width, height);
@@ -642,7 +638,7 @@ static void draw_mask_layers(const bContext *C,
void ED_mask_draw(const bContext *C, const char draw_flag, const char draw_type)
{
- ScrArea *sa = CTX_wm_area(C);
+ ScrArea *area = CTX_wm_area(C);
Mask *mask = CTX_data_edit_mask(C);
int width, height;
@@ -650,7 +646,7 @@ void ED_mask_draw(const bContext *C, const char draw_flag, const char draw_type)
return;
}
- ED_mask_get_size(sa, &width, &height);
+ ED_mask_get_size(area, &width, &height);
draw_mask_layers(C, mask, draw_flag, draw_type, width, height);
}
@@ -756,7 +752,7 @@ void ED_mask_draw_region(
}
IMMDrawPixelsTexState state = immDrawPixelsTexSetup(GPU_SHADER_2D_IMAGE_SHUFFLE_COLOR);
GPU_shader_uniform_vector(
- state.shader, GPU_shader_get_uniform_ensure(state.shader, "shuffle"), 4, 1, red);
+ state.shader, GPU_shader_get_uniform(state.shader, "shuffle"), 4, 1, red);
immDrawPixelsTex(
&state, 0.0f, 0.0f, width, height, GL_RED, GL_FLOAT, GL_NEAREST, buffer, 1.0f, 1.0f, NULL);
@@ -803,7 +799,7 @@ void ED_mask_draw_frames(
return;
}
- unsigned int num_lines = BLI_listbase_count(&mask_layer->splines_shapes);
+ uint num_lines = BLI_listbase_count(&mask_layer->splines_shapes);
if (num_lines == 0) {
return;
}
diff --git a/source/blender/editors/mask/mask_edit.c b/source/blender/editors/mask/mask_edit.c
index e18c4992671..663ae0097ad 100644
--- a/source/blender/editors/mask/mask_edit.c
+++ b/source/blender/editors/mask/mask_edit.c
@@ -21,12 +21,9 @@
* \ingroup edmask
*/
-#include "BLI_math.h"
-
#include "BKE_context.h"
#include "BKE_mask.h"
-#include "DNA_mask_types.h"
#include "DNA_scene_types.h"
#include "WM_api.h"
@@ -34,14 +31,8 @@
#include "ED_clip.h"
#include "ED_image.h"
-#include "ED_mask.h" /* own include */
-#include "ED_object.h" /* ED_keymap_proportional_maskmode only */
-#include "ED_screen.h"
-#include "ED_select_utils.h"
+#include "ED_mask.h" /* own include */
#include "ED_sequencer.h"
-#include "ED_transform.h"
-
-#include "UI_view2d.h"
#include "RNA_access.h"
@@ -53,9 +44,9 @@
bool ED_maskedit_poll(bContext *C)
{
- ScrArea *sa = CTX_wm_area(C);
- if (sa) {
- switch (sa->spacetype) {
+ ScrArea *area = CTX_wm_area(C);
+ if (area) {
+ switch (area->spacetype) {
case SPACE_CLIP:
return ED_space_clip_maskedit_poll(C);
case SPACE_SEQ:
@@ -69,9 +60,9 @@ bool ED_maskedit_poll(bContext *C)
bool ED_maskedit_mask_poll(bContext *C)
{
- ScrArea *sa = CTX_wm_area(C);
- if (sa) {
- switch (sa->spacetype) {
+ ScrArea *area = CTX_wm_area(C);
+ if (area) {
+ switch (area->spacetype) {
case SPACE_CLIP:
return ED_space_clip_maskedit_mask_poll(C);
case SPACE_SEQ:
diff --git a/source/blender/editors/mask/mask_ops.c b/source/blender/editors/mask/mask_ops.c
index 758d0abbab7..68dfe0d151f 100644
--- a/source/blender/editors/mask/mask_ops.c
+++ b/source/blender/editors/mask/mask_ops.c
@@ -31,7 +31,6 @@
#include "BKE_mask.h"
#include "DEG_depsgraph.h"
-#include "DEG_depsgraph_query.h"
#include "DNA_mask_types.h"
#include "DNA_object_types.h" /* SELECT */
@@ -56,16 +55,16 @@
Mask *ED_mask_new(bContext *C, const char *name)
{
- ScrArea *sa = CTX_wm_area(C);
+ ScrArea *area = CTX_wm_area(C);
Main *bmain = CTX_data_main(C);
Mask *mask;
mask = BKE_mask_new(bmain, name);
- if (sa && sa->spacedata.first) {
- switch (sa->spacetype) {
+ if (area && area->spacedata.first) {
+ switch (area->spacetype) {
case SPACE_CLIP: {
- SpaceClip *sc = sa->spacedata.first;
+ SpaceClip *sc = area->spacedata.first;
ED_space_clip_set_mask(C, sc, mask);
break;
}
@@ -74,7 +73,7 @@ Mask *ED_mask_new(bContext *C, const char *name)
break;
}
case SPACE_IMAGE: {
- SpaceImage *sima = sa->spacedata.first;
+ SpaceImage *sima = area->spacedata.first;
ED_space_image_set_mask(C, sima, mask);
break;
}
@@ -261,7 +260,7 @@ static bool spline_under_mouse_get(const bContext *C,
MaskSpline **r_mask_spline)
{
const float threshold = 19.0f;
- ScrArea *sa = CTX_wm_area(C);
+ ScrArea *area = CTX_wm_area(C);
SpaceClip *sc = CTX_wm_space_clip(C);
int width, height;
float pixel_co[2];
@@ -271,7 +270,7 @@ static bool spline_under_mouse_get(const bContext *C,
bool undistort = false;
*r_mask_layer = NULL;
*r_mask_spline = NULL;
- ED_mask_get_size(sa, &width, &height);
+ ED_mask_get_size(area, &width, &height);
pixel_co[0] = co[0] * width;
pixel_co[1] = co[1] * height;
if (sc != NULL) {
@@ -421,7 +420,7 @@ static void check_sliding_handle_type(MaskSplinePoint *point, eMaskWhichHandle w
static void *slide_point_customdata(bContext *C, wmOperator *op, const wmEvent *event)
{
- ScrArea *sa = CTX_wm_area(C);
+ ScrArea *area = CTX_wm_area(C);
ARegion *region = CTX_wm_region(C);
Mask *mask = CTX_data_edit_mask(C);
@@ -436,8 +435,8 @@ static void *slide_point_customdata(bContext *C, wmOperator *op, const wmEvent *
const float threshold = 19;
eMaskWhichHandle which_handle;
- ED_mask_mouse_pos(sa, region, event->mval, co);
- ED_mask_get_size(sa, &width, &height);
+ ED_mask_mouse_pos(area, region, event->mval, co);
+ ED_mask_get_size(area, &width, &height);
cv_point = ED_mask_point_find_nearest(
C, mask, co, threshold, &cv_mask_layer, &cv_spline, &which_handle, &cv_score);
@@ -535,7 +534,7 @@ static void *slide_point_customdata(bContext *C, wmOperator *op, const wmEvent *
}
customdata->which_handle = which_handle;
- ED_mask_mouse_pos(sa, region, event->mval, customdata->prev_mouse_coord);
+ ED_mask_mouse_pos(area, region, event->mval, customdata->prev_mouse_coord);
}
return customdata;
@@ -659,11 +658,11 @@ static int slide_point_modal(bContext *C, wmOperator *op, const wmEvent *event)
ATTR_FALLTHROUGH; /* update CV position */
case MOUSEMOVE: {
- ScrArea *sa = CTX_wm_area(C);
+ ScrArea *area = CTX_wm_area(C);
ARegion *region = CTX_wm_region(C);
float delta[2];
- ED_mask_mouse_pos(sa, region, event->mval, co);
+ ED_mask_mouse_pos(area, region, event->mval, co);
sub_v2_v2v2(delta, co, data->prev_mouse_coord);
if (data->is_accurate) {
mul_v2_fl(delta, 0.2f);
@@ -1294,12 +1293,12 @@ static int cyclic_toggle_exec(bContext *C, wmOperator *UNUSED(op))
{
Mask *mask = CTX_data_edit_mask(C);
- for (MaskLayer *mask_layer = mask->masklayers.first; mask_layer; mask_layer = mask_layer->next) {
+ LISTBASE_FOREACH (MaskLayer *, mask_layer, &mask->masklayers) {
if (mask_layer->restrictflag & (MASK_RESTRICT_VIEW | MASK_RESTRICT_SELECT)) {
continue;
}
- for (MaskSpline *spline = mask_layer->splines.first; spline; spline = spline->next) {
+ LISTBASE_FOREACH (MaskSpline *, spline, &mask_layer->splines) {
if (ED_mask_spline_select_check(spline)) {
spline->flag ^= MASK_SPLINE_CYCLIC;
}
@@ -1372,7 +1371,7 @@ static int delete_exec(bContext *C, wmOperator *UNUSED(op))
Mask *mask = CTX_data_edit_mask(C);
bool changed = false;
- for (MaskLayer *mask_layer = mask->masklayers.first; mask_layer; mask_layer = mask_layer->next) {
+ LISTBASE_FOREACH (MaskLayer *, mask_layer, &mask->masklayers) {
MaskSpline *spline;
int mask_layer_shape_ofs = 0;
@@ -1494,14 +1493,14 @@ static int mask_switch_direction_exec(bContext *C, wmOperator *UNUSED(op))
bool changed = false;
/* do actual selection */
- for (MaskLayer *mask_layer = mask->masklayers.first; mask_layer; mask_layer = mask_layer->next) {
+ LISTBASE_FOREACH (MaskLayer *, mask_layer, &mask->masklayers) {
bool changed_layer = false;
if (mask_layer->restrictflag & (MASK_RESTRICT_VIEW | MASK_RESTRICT_SELECT)) {
continue;
}
- for (MaskSpline *spline = mask_layer->splines.first; spline; spline = spline->next) {
+ LISTBASE_FOREACH (MaskSpline *, spline, &mask_layer->splines) {
if (ED_mask_spline_select_check(spline)) {
BKE_mask_spline_direction_switch(mask_layer, spline);
changed = true;
@@ -1552,14 +1551,14 @@ static int mask_normals_make_consistent_exec(bContext *C, wmOperator *UNUSED(op)
bool changed = false;
/* do actual selection */
- for (MaskLayer *mask_layer = mask->masklayers.first; mask_layer; mask_layer = mask_layer->next) {
+ LISTBASE_FOREACH (MaskLayer *, mask_layer, &mask->masklayers) {
bool changed_layer = false;
if (mask_layer->restrictflag & (MASK_RESTRICT_VIEW | MASK_RESTRICT_SELECT)) {
continue;
}
- for (MaskSpline *spline = mask_layer->splines.first; spline; spline = spline->next) {
+ LISTBASE_FOREACH (MaskSpline *, spline, &mask_layer->splines) {
for (int i = 0; i < spline->tot_point; i++) {
MaskSplinePoint *point = &spline->points[i];
@@ -1615,12 +1614,12 @@ static int set_handle_type_exec(bContext *C, wmOperator *op)
bool changed = false;
- for (MaskLayer *mask_layer = mask->masklayers.first; mask_layer; mask_layer = mask_layer->next) {
+ LISTBASE_FOREACH (MaskLayer *, mask_layer, &mask->masklayers) {
if (mask_layer->restrictflag & (MASK_RESTRICT_VIEW | MASK_RESTRICT_SELECT)) {
continue;
}
- for (MaskSpline *spline = mask_layer->splines.first; spline; spline = spline->next) {
+ LISTBASE_FOREACH (MaskSpline *, spline, &mask_layer->splines) {
for (int i = 0; i < spline->tot_point; i++) {
MaskSplinePoint *point = &spline->points[i];
@@ -1696,7 +1695,7 @@ static int mask_hide_view_clear_exec(bContext *C, wmOperator *op)
bool changed = false;
const bool select = RNA_boolean_get(op->ptr, "select");
- for (MaskLayer *mask_layer = mask->masklayers.first; mask_layer; mask_layer = mask_layer->next) {
+ LISTBASE_FOREACH (MaskLayer *, mask_layer, &mask->masklayers) {
if (mask_layer->restrictflag & OB_RESTRICT_VIEWPORT) {
ED_mask_layer_select_set(mask_layer, select);
@@ -1740,7 +1739,7 @@ static int mask_hide_view_set_exec(bContext *C, wmOperator *op)
const bool unselected = RNA_boolean_get(op->ptr, "unselected");
bool changed = false;
- for (MaskLayer *mask_layer = mask->masklayers.first; mask_layer; mask_layer = mask_layer->next) {
+ LISTBASE_FOREACH (MaskLayer *, mask_layer, &mask->masklayers) {
if (mask_layer->restrictflag & MASK_RESTRICT_SELECT) {
continue;
@@ -1802,12 +1801,12 @@ static int mask_feather_weight_clear_exec(bContext *C, wmOperator *UNUSED(op))
Mask *mask = CTX_data_edit_mask(C);
bool changed = false;
- for (MaskLayer *mask_layer = mask->masklayers.first; mask_layer; mask_layer = mask_layer->next) {
+ LISTBASE_FOREACH (MaskLayer *, mask_layer, &mask->masklayers) {
if (mask_layer->restrictflag & (MASK_RESTRICT_SELECT | MASK_RESTRICT_VIEW)) {
continue;
}
- for (MaskSpline *spline = mask_layer->splines.first; spline; spline = spline->next) {
+ LISTBASE_FOREACH (MaskSpline *, spline, &mask_layer->splines) {
for (int i = 0; i < spline->tot_point; i++) {
MaskSplinePoint *point = &spline->points[i];
@@ -1936,7 +1935,7 @@ static int mask_duplicate_exec(bContext *C, wmOperator *UNUSED(op))
{
Mask *mask = CTX_data_edit_mask(C);
- for (MaskLayer *mask_layer = mask->masklayers.first; mask_layer; mask_layer = mask_layer->next) {
+ LISTBASE_FOREACH (MaskLayer *, mask_layer, &mask->masklayers) {
for (MaskSpline *spline = mask_layer->splines.last; spline; spline = spline->prev) {
MaskSplinePoint *point = spline->points;
int i = 0;
diff --git a/source/blender/editors/mask/mask_query.c b/source/blender/editors/mask/mask_query.c
index 4459607191f..cf5997d8a18 100644
--- a/source/blender/editors/mask/mask_query.c
+++ b/source/blender/editors/mask/mask_query.c
@@ -35,20 +35,12 @@
#include "DNA_scene_types.h"
#include "DNA_screen_types.h"
-#include "WM_api.h"
-#include "WM_types.h"
-
#include "ED_clip.h"
#include "ED_image.h"
#include "ED_mask.h" /* own include */
-#include "ED_screen.h"
-#include "ED_select_utils.h"
#include "UI_view2d.h"
-#include "RNA_access.h"
-#include "RNA_define.h"
-
#include "mask_intern.h" /* own include */
/* -------------------------------------------------------------------- */
@@ -69,7 +61,7 @@ bool ED_mask_find_nearest_diff_point(const bContext *C,
float *r_u,
float *r_score)
{
- ScrArea *sa = CTX_wm_area(C);
+ ScrArea *area = CTX_wm_area(C);
ARegion *region = CTX_wm_region(C);
MaskLayer *point_mask_layer;
@@ -83,8 +75,8 @@ bool ED_mask_find_nearest_diff_point(const bContext *C,
Depsgraph *depsgraph = CTX_data_ensure_evaluated_depsgraph(C);
Mask *mask_eval = (Mask *)DEG_get_evaluated_id(depsgraph, &mask_orig->id);
- ED_mask_get_size(sa, &width, &height);
- ED_mask_pixelspace_factor(sa, region, &scalex, &scaley);
+ ED_mask_get_size(area, &width, &height);
+ ED_mask_pixelspace_factor(area, region, &scalex, &scaley);
co[0] = normal_co[0] * scalex;
co[1] = normal_co[1] * scaley;
@@ -107,13 +99,13 @@ bool ED_mask_find_nearest_diff_point(const bContext *C,
for (i = 0, cur_point_eval = use_deform ? spline_eval->points_deform : spline_eval->points;
i < spline_eval->tot_point;
i++, cur_point_eval++) {
- unsigned int tot_diff_point;
+ uint tot_diff_point;
float *diff_points = BKE_mask_point_segment_diff(
spline_eval, cur_point_eval, width, height, &tot_diff_point);
if (diff_points) {
int j, tot_point;
- unsigned int tot_feather_point;
+ uint tot_feather_point;
float *feather_points = NULL, *points;
if (feather) {
@@ -227,7 +219,7 @@ MaskSplinePoint *ED_mask_point_find_nearest(const bContext *C,
eMaskWhichHandle *r_which_handle,
float *r_score)
{
- ScrArea *sa = CTX_wm_area(C);
+ ScrArea *area = CTX_wm_area(C);
ARegion *region = CTX_wm_region(C);
MaskLayer *point_mask_layer = NULL;
@@ -242,8 +234,8 @@ MaskSplinePoint *ED_mask_point_find_nearest(const bContext *C,
Depsgraph *depsgraph = CTX_data_ensure_evaluated_depsgraph(C);
Mask *mask_eval = (Mask *)DEG_get_evaluated_id(depsgraph, &mask_orig->id);
- ED_mask_get_size(sa, &width, &height);
- ED_mask_pixelspace_factor(sa, region, &scalex, &scaley);
+ ED_mask_get_size(area, &width, &height);
+ ED_mask_pixelspace_factor(area, region, &scalex, &scaley);
co[0] = normal_co[0] * scalex;
co[1] = normal_co[1] * scaley;
@@ -382,7 +374,7 @@ bool ED_mask_feather_find_nearest(const bContext *C,
MaskSplinePointUW **r_uw,
float *r_score)
{
- ScrArea *sa = CTX_wm_area(C);
+ ScrArea *area = CTX_wm_area(C);
ARegion *region = CTX_wm_region(C);
MaskLayer *point_mask_layer = NULL;
@@ -397,8 +389,8 @@ bool ED_mask_feather_find_nearest(const bContext *C,
Depsgraph *depsgraph = CTX_data_ensure_evaluated_depsgraph(C);
Mask *mask_eval = (Mask *)DEG_get_evaluated_id(depsgraph, &mask_orig->id);
- ED_mask_get_size(sa, &width, &height);
- ED_mask_pixelspace_factor(sa, region, &scalex, &scaley);
+ ED_mask_get_size(area, &width, &height);
+ ED_mask_pixelspace_factor(area, region, &scalex, &scaley);
co[0] = normal_co[0] * scalex;
co[1] = normal_co[1] * scaley;
@@ -498,12 +490,12 @@ bool ED_mask_feather_find_nearest(const bContext *C,
}
/* takes event->mval */
-void ED_mask_mouse_pos(ScrArea *sa, ARegion *region, const int mval[2], float co[2])
+void ED_mask_mouse_pos(ScrArea *area, ARegion *region, const int mval[2], float co[2])
{
- if (sa) {
- switch (sa->spacetype) {
+ if (area) {
+ switch (area->spacetype) {
case SPACE_CLIP: {
- SpaceClip *sc = sa->spacedata.first;
+ SpaceClip *sc = area->spacedata.first;
ED_clip_mouse_pos(sc, region, mval, co);
BKE_mask_coord_from_movieclip(sc->clip, &sc->user, co, co);
break;
@@ -513,7 +505,7 @@ void ED_mask_mouse_pos(ScrArea *sa, ARegion *region, const int mval[2], float co
break;
}
case SPACE_IMAGE: {
- SpaceImage *sima = sa->spacedata.first;
+ SpaceImage *sima = area->spacedata.first;
ED_image_mouse_pos(sima, region, mval, co);
BKE_mask_coord_from_image(sima->image, &sima->iuser, co, co);
break;
@@ -533,14 +525,14 @@ void ED_mask_mouse_pos(ScrArea *sa, ARegion *region, const int mval[2], float co
/* input: x/y - mval space
* output: xr/yr - mask point space */
-void ED_mask_point_pos(ScrArea *sa, ARegion *region, float x, float y, float *xr, float *yr)
+void ED_mask_point_pos(ScrArea *area, ARegion *region, float x, float y, float *xr, float *yr)
{
float co[2];
- if (sa) {
- switch (sa->spacetype) {
+ if (area) {
+ switch (area->spacetype) {
case SPACE_CLIP: {
- SpaceClip *sc = sa->spacedata.first;
+ SpaceClip *sc = area->spacedata.first;
ED_clip_point_stable_pos(sc, region, x, y, &co[0], &co[1]);
BKE_mask_coord_from_movieclip(sc->clip, &sc->user, co, co);
break;
@@ -549,7 +541,7 @@ void ED_mask_point_pos(ScrArea *sa, ARegion *region, float x, float y, float *xr
zero_v2(co); /* MASKTODO */
break;
case SPACE_IMAGE: {
- SpaceImage *sima = sa->spacedata.first;
+ SpaceImage *sima = area->spacedata.first;
ED_image_point_pos(sima, region, x, y, &co[0], &co[1]);
BKE_mask_coord_from_image(sima->image, &sima->iuser, co, co);
break;
@@ -571,14 +563,14 @@ void ED_mask_point_pos(ScrArea *sa, ARegion *region, float x, float y, float *xr
}
void ED_mask_point_pos__reverse(
- ScrArea *sa, ARegion *region, float x, float y, float *xr, float *yr)
+ ScrArea *area, ARegion *region, float x, float y, float *xr, float *yr)
{
float co[2];
- if (sa) {
- switch (sa->spacetype) {
+ if (area) {
+ switch (area->spacetype) {
case SPACE_CLIP: {
- SpaceClip *sc = sa->spacedata.first;
+ SpaceClip *sc = area->spacedata.first;
co[0] = x;
co[1] = y;
BKE_mask_coord_to_movieclip(sc->clip, &sc->user, co, co);
@@ -589,7 +581,7 @@ void ED_mask_point_pos__reverse(
zero_v2(co); /* MASKTODO */
break;
case SPACE_IMAGE: {
- SpaceImage *sima = sa->spacedata.first;
+ SpaceImage *sima = area->spacedata.first;
co[0] = x;
co[1] = y;
BKE_mask_coord_to_image(sima->image, &sima->iuser, co, co);
@@ -667,12 +659,12 @@ bool ED_mask_selected_minmax(const bContext *C, float min[2], float max[2])
/** \name Generic 2D View Queries
* \{ */
-void ED_mask_get_size(ScrArea *sa, int *width, int *height)
+void ED_mask_get_size(ScrArea *area, int *width, int *height)
{
- if (sa && sa->spacedata.first) {
- switch (sa->spacetype) {
+ if (area && area->spacedata.first) {
+ switch (area->spacetype) {
case SPACE_CLIP: {
- SpaceClip *sc = sa->spacedata.first;
+ SpaceClip *sc = area->spacedata.first;
ED_space_clip_get_size(sc, width, height);
break;
}
@@ -683,7 +675,7 @@ void ED_mask_get_size(ScrArea *sa, int *width, int *height)
break;
}
case SPACE_IMAGE: {
- SpaceImage *sima = sa->spacedata.first;
+ SpaceImage *sima = area->spacedata.first;
ED_space_image_get_size(sima, width, height);
break;
}
@@ -702,12 +694,12 @@ void ED_mask_get_size(ScrArea *sa, int *width, int *height)
}
}
-void ED_mask_zoom(ScrArea *sa, ARegion *region, float *zoomx, float *zoomy)
+void ED_mask_zoom(ScrArea *area, ARegion *region, float *zoomx, float *zoomy)
{
- if (sa && sa->spacedata.first) {
- switch (sa->spacetype) {
+ if (area && area->spacedata.first) {
+ switch (area->spacetype) {
case SPACE_CLIP: {
- SpaceClip *sc = sa->spacedata.first;
+ SpaceClip *sc = area->spacedata.first;
ED_space_clip_get_zoom(sc, region, zoomx, zoomy);
break;
}
@@ -716,7 +708,7 @@ void ED_mask_zoom(ScrArea *sa, ARegion *region, float *zoomx, float *zoomy)
break;
}
case SPACE_IMAGE: {
- SpaceImage *sima = sa->spacedata.first;
+ SpaceImage *sima = area->spacedata.first;
ED_space_image_get_zoom(sima, region, zoomx, zoomy);
break;
}
@@ -733,12 +725,12 @@ void ED_mask_zoom(ScrArea *sa, ARegion *region, float *zoomx, float *zoomy)
}
}
-void ED_mask_get_aspect(ScrArea *sa, ARegion *UNUSED(region), float *aspx, float *aspy)
+void ED_mask_get_aspect(ScrArea *area, ARegion *UNUSED(region), float *aspx, float *aspy)
{
- if (sa && sa->spacedata.first) {
- switch (sa->spacetype) {
+ if (area && area->spacedata.first) {
+ switch (area->spacetype) {
case SPACE_CLIP: {
- SpaceClip *sc = sa->spacedata.first;
+ SpaceClip *sc = area->spacedata.first;
ED_space_clip_get_aspect(sc, aspx, aspy);
break;
}
@@ -747,7 +739,7 @@ void ED_mask_get_aspect(ScrArea *sa, ARegion *UNUSED(region), float *aspx, float
break;
}
case SPACE_IMAGE: {
- SpaceImage *sima = sa->spacedata.first;
+ SpaceImage *sima = area->spacedata.first;
ED_space_image_get_aspect(sima, aspx, aspy);
break;
}
@@ -764,12 +756,12 @@ void ED_mask_get_aspect(ScrArea *sa, ARegion *UNUSED(region), float *aspx, float
}
}
-void ED_mask_pixelspace_factor(ScrArea *sa, ARegion *region, float *scalex, float *scaley)
+void ED_mask_pixelspace_factor(ScrArea *area, ARegion *region, float *scalex, float *scaley)
{
- if (sa && sa->spacedata.first) {
- switch (sa->spacetype) {
+ if (area && area->spacedata.first) {
+ switch (area->spacetype) {
case SPACE_CLIP: {
- SpaceClip *sc = sa->spacedata.first;
+ SpaceClip *sc = area->spacedata.first;
float aspx, aspy;
UI_view2d_scale_get(&region->v2d, scalex, scaley);
@@ -784,7 +776,7 @@ void ED_mask_pixelspace_factor(ScrArea *sa, ARegion *region, float *scalex, floa
break;
}
case SPACE_IMAGE: {
- SpaceImage *sima = sa->spacedata.first;
+ SpaceImage *sima = area->spacedata.first;
float aspx, aspy;
UI_view2d_scale_get(&region->v2d, scalex, scaley);
@@ -807,12 +799,12 @@ void ED_mask_pixelspace_factor(ScrArea *sa, ARegion *region, float *scalex, floa
}
}
-void ED_mask_cursor_location_get(ScrArea *sa, float cursor[2])
+void ED_mask_cursor_location_get(ScrArea *area, float cursor[2])
{
- if (sa) {
- switch (sa->spacetype) {
+ if (area) {
+ switch (area->spacetype) {
case SPACE_CLIP: {
- SpaceClip *space_clip = sa->spacedata.first;
+ SpaceClip *space_clip = area->spacedata.first;
copy_v2_v2(cursor, space_clip->cursor);
break;
}
@@ -821,7 +813,7 @@ void ED_mask_cursor_location_get(ScrArea *sa, float cursor[2])
break;
}
case SPACE_IMAGE: {
- SpaceImage *space_image = sa->spacedata.first;
+ SpaceImage *space_image = area->spacedata.first;
copy_v2_v2(cursor, space_image->cursor);
break;
}
diff --git a/source/blender/editors/mask/mask_relationships.c b/source/blender/editors/mask/mask_relationships.c
index 49eb4fbd4ca..971e1c948c9 100644
--- a/source/blender/editors/mask/mask_relationships.c
+++ b/source/blender/editors/mask/mask_relationships.c
@@ -21,6 +21,7 @@
* \ingroup edmask
*/
+#include "BLI_listbase.h"
#include "BLI_math.h"
#include "BLI_string.h"
@@ -44,12 +45,12 @@ static int mask_parent_clear_exec(bContext *C, wmOperator *UNUSED(op))
{
Mask *mask = CTX_data_edit_mask(C);
- for (MaskLayer *mask_layer = mask->masklayers.first; mask_layer; mask_layer = mask_layer->next) {
+ LISTBASE_FOREACH (MaskLayer *, mask_layer, &mask->masklayers) {
if (mask_layer->restrictflag & (MASK_RESTRICT_VIEW | MASK_RESTRICT_SELECT)) {
continue;
}
- for (MaskSpline *spline = mask_layer->splines.first; spline; spline = spline->next) {
+ LISTBASE_FOREACH (MaskSpline *, spline, &mask_layer->splines) {
for (int i = 0; i < spline->tot_point; i++) {
MaskSplinePoint *point = &spline->points[i];
@@ -136,12 +137,12 @@ static int mask_parent_set_exec(bContext *C, wmOperator *UNUSED(op))
return OPERATOR_CANCELLED;
}
- for (MaskLayer *mask_layer = mask->masklayers.first; mask_layer; mask_layer = mask_layer->next) {
+ LISTBASE_FOREACH (MaskLayer *, mask_layer, &mask->masklayers) {
if (mask_layer->restrictflag & (MASK_RESTRICT_VIEW | MASK_RESTRICT_SELECT)) {
continue;
}
- for (MaskSpline *spline = mask_layer->splines.first; spline; spline = spline->next) {
+ LISTBASE_FOREACH (MaskSpline *, spline, &mask_layer->splines) {
for (int i = 0; i < spline->tot_point; i++) {
MaskSplinePoint *point = &spline->points[i];
diff --git a/source/blender/editors/mask/mask_select.c b/source/blender/editors/mask/mask_select.c
index 53ef398ccd6..c8cddced99c 100644
--- a/source/blender/editors/mask/mask_select.c
+++ b/source/blender/editors/mask/mask_select.c
@@ -24,6 +24,7 @@
#include "MEM_guardedalloc.h"
#include "BLI_lasso_2d.h"
+#include "BLI_listbase.h"
#include "BLI_math.h"
#include "BLI_rect.h"
#include "BLI_utildefines.h"
@@ -38,7 +39,6 @@
#include "ED_clip.h"
#include "ED_mask.h" /* own include */
-#include "ED_screen.h"
#include "ED_select_utils.h"
#include "RNA_access.h"
@@ -74,7 +74,7 @@ bool ED_mask_layer_select_check(const MaskLayer *mask_layer)
return false;
}
- for (const MaskSpline *spline = mask_layer->splines.first; spline; spline = spline->next) {
+ LISTBASE_FOREACH (const MaskSpline *, spline, &mask_layer->splines) {
if (ED_mask_spline_select_check(spline)) {
return true;
}
@@ -85,8 +85,7 @@ bool ED_mask_layer_select_check(const MaskLayer *mask_layer)
bool ED_mask_select_check(const Mask *mask)
{
- for (const MaskLayer *mask_layer = mask->masklayers.first; mask_layer;
- mask_layer = mask_layer->next) {
+ LISTBASE_FOREACH (const MaskLayer *, mask_layer, &mask->masklayers) {
if (ED_mask_layer_select_check(mask_layer)) {
return true;
}
@@ -122,7 +121,7 @@ void ED_mask_layer_select_set(MaskLayer *mask_layer, const bool do_select)
}
}
- for (MaskSpline *spline = mask_layer->splines.first; spline; spline = spline->next) {
+ LISTBASE_FOREACH (MaskSpline *, spline, &mask_layer->splines) {
ED_mask_spline_select_set(spline, do_select);
}
}
@@ -138,7 +137,7 @@ void ED_mask_select_toggle_all(Mask *mask, int action)
}
}
- for (MaskLayer *mask_layer = mask->masklayers.first; mask_layer; mask_layer = mask_layer->next) {
+ LISTBASE_FOREACH (MaskLayer *, mask_layer, &mask->masklayers) {
if (mask_layer->restrictflag & MASK_RESTRICT_VIEW) {
continue;
@@ -151,7 +150,7 @@ void ED_mask_select_toggle_all(Mask *mask, int action)
if (mask_layer->restrictflag & MASK_RESTRICT_SELECT) {
continue;
}
- for (MaskSpline *spline = mask_layer->splines.first; spline; spline = spline->next) {
+ LISTBASE_FOREACH (MaskSpline *, spline, &mask_layer->splines) {
int i;
for (i = 0; i < spline->tot_point; i++) {
MaskSplinePoint *point = &spline->points[i];
@@ -167,8 +166,8 @@ void ED_mask_select_toggle_all(Mask *mask, int action)
void ED_mask_select_flush_all(Mask *mask)
{
- for (MaskLayer *mask_layer = mask->masklayers.first; mask_layer; mask_layer = mask_layer->next) {
- for (MaskSpline *spline = mask_layer->splines.first; spline; spline = spline->next) {
+ LISTBASE_FOREACH (MaskLayer *, mask_layer, &mask->masklayers) {
+ LISTBASE_FOREACH (MaskSpline *, spline, &mask_layer->splines) {
spline->flag &= ~SELECT;
/* intentionally _dont_ do this in the mask layer loop
@@ -386,12 +385,12 @@ static int select_exec(bContext *C, wmOperator *op)
static int select_invoke(bContext *C, wmOperator *op, const wmEvent *event)
{
- ScrArea *sa = CTX_wm_area(C);
+ ScrArea *area = CTX_wm_area(C);
ARegion *region = CTX_wm_region(C);
float co[2];
- ED_mask_mouse_pos(sa, region, event->mval, co);
+ ED_mask_mouse_pos(area, region, event->mval, co);
RNA_float_set_array(op->ptr, "location", co);
@@ -436,7 +435,7 @@ void MASK_OT_select(wmOperatorType *ot)
static int box_select_exec(bContext *C, wmOperator *op)
{
- ScrArea *sa = CTX_wm_area(C);
+ ScrArea *area = CTX_wm_area(C);
ARegion *region = CTX_wm_region(C);
Mask *mask = CTX_data_edit_mask(C);
@@ -455,16 +454,16 @@ static int box_select_exec(bContext *C, wmOperator *op)
/* get rectangle from operator */
WM_operator_properties_border_to_rcti(op, &rect);
- ED_mask_point_pos(sa, region, rect.xmin, rect.ymin, &rectf.xmin, &rectf.ymin);
- ED_mask_point_pos(sa, region, rect.xmax, rect.ymax, &rectf.xmax, &rectf.ymax);
+ ED_mask_point_pos(area, region, rect.xmin, rect.ymin, &rectf.xmin, &rectf.ymin);
+ ED_mask_point_pos(area, region, rect.xmax, rect.ymax, &rectf.xmax, &rectf.ymax);
/* do actual selection */
- for (MaskLayer *mask_layer = mask->masklayers.first; mask_layer; mask_layer = mask_layer->next) {
+ LISTBASE_FOREACH (MaskLayer *, mask_layer, &mask->masklayers) {
if (mask_layer->restrictflag & (MASK_RESTRICT_VIEW | MASK_RESTRICT_SELECT)) {
continue;
}
- for (MaskSpline *spline = mask_layer->splines.first; spline; spline = spline->next) {
+ LISTBASE_FOREACH (MaskSpline *, spline, &mask_layer->splines) {
MaskSplinePoint *points_array = BKE_mask_spline_point_array(spline);
for (int i = 0; i < spline->tot_point; i++) {
@@ -522,11 +521,11 @@ void MASK_OT_select_box(wmOperatorType *ot)
* \{ */
static bool do_lasso_select_mask(bContext *C,
- const int mcords[][2],
- short moves,
+ const int mcoords[][2],
+ const int mcoords_len,
const eSelectOp sel_op)
{
- ScrArea *sa = CTX_wm_area(C);
+ ScrArea *area = CTX_wm_area(C);
ARegion *region = CTX_wm_region(C);
Mask *mask = CTX_data_edit_mask(C);
@@ -541,15 +540,15 @@ static bool do_lasso_select_mask(bContext *C,
}
/* get rectangle from operator */
- BLI_lasso_boundbox(&rect, mcords, moves);
+ BLI_lasso_boundbox(&rect, mcoords, mcoords_len);
/* do actual selection */
- for (MaskLayer *mask_layer = mask->masklayers.first; mask_layer; mask_layer = mask_layer->next) {
+ LISTBASE_FOREACH (MaskLayer *, mask_layer, &mask->masklayers) {
if (mask_layer->restrictflag & (MASK_RESTRICT_VIEW | MASK_RESTRICT_SELECT)) {
continue;
}
- for (MaskSpline *spline = mask_layer->splines.first; spline; spline = spline->next) {
+ LISTBASE_FOREACH (MaskSpline *, spline, &mask_layer->splines) {
MaskSplinePoint *points_array = BKE_mask_spline_point_array(spline);
for (int i = 0; i < spline->tot_point; i++) {
@@ -566,7 +565,7 @@ static bool do_lasso_select_mask(bContext *C,
float screen_co[2];
/* point in screen coords */
- ED_mask_point_pos__reverse(sa,
+ ED_mask_point_pos__reverse(area,
region,
point_deform->bezt.vec[1][0],
point_deform->bezt.vec[1][1],
@@ -574,7 +573,7 @@ static bool do_lasso_select_mask(bContext *C,
&screen_co[1]);
if (BLI_rcti_isect_pt(&rect, screen_co[0], screen_co[1]) &&
- BLI_lasso_is_point_inside(mcords, moves, screen_co[0], screen_co[1], INT_MAX)) {
+ BLI_lasso_is_point_inside(mcoords, mcoords_len, screen_co[0], screen_co[1], INT_MAX)) {
BKE_mask_point_select_set(point, select);
BKE_mask_point_select_set_handle(point, MASK_WHICH_HANDLE_BOTH, select);
changed = true;
@@ -595,14 +594,14 @@ static bool do_lasso_select_mask(bContext *C,
static int clip_lasso_select_exec(bContext *C, wmOperator *op)
{
- int mcords_tot;
- const int(*mcords)[2] = WM_gesture_lasso_path_to_array(C, op, &mcords_tot);
+ int mcoords_len;
+ const int(*mcoords)[2] = WM_gesture_lasso_path_to_array(C, op, &mcoords_len);
- if (mcords) {
+ if (mcoords) {
const eSelectOp sel_op = RNA_enum_get(op->ptr, "mode");
- do_lasso_select_mask(C, mcords, mcords_tot, sel_op);
+ do_lasso_select_mask(C, mcoords, mcoords_len, sel_op);
- MEM_freeN((void *)mcords);
+ MEM_freeN((void *)mcoords);
return OPERATOR_FINISHED;
}
@@ -652,7 +651,7 @@ static int mask_spline_point_inside_ellipse(BezTriple *bezt,
static int circle_select_exec(bContext *C, wmOperator *op)
{
- ScrArea *sa = CTX_wm_area(C);
+ ScrArea *area = CTX_wm_area(C);
ARegion *region = CTX_wm_region(C);
Mask *mask = CTX_data_edit_mask(C);
@@ -668,14 +667,14 @@ static int circle_select_exec(bContext *C, wmOperator *op)
const int radius = RNA_int_get(op->ptr, "radius");
/* compute ellipse and position in unified coordinates */
- ED_mask_get_size(sa, &width, &height);
- ED_mask_zoom(sa, region, &zoomx, &zoomy);
+ ED_mask_get_size(area, &width, &height);
+ ED_mask_zoom(area, region, &zoomx, &zoomy);
width = height = max_ii(width, height);
ellipse[0] = width * zoomx / radius;
ellipse[1] = height * zoomy / radius;
- ED_mask_point_pos(sa, region, x, y, &offset[0], &offset[1]);
+ ED_mask_point_pos(area, region, x, y, &offset[0], &offset[1]);
const eSelectOp sel_op = ED_select_op_modal(RNA_enum_get(op->ptr, "mode"),
WM_gesture_is_modal_first(op->customdata));
@@ -686,12 +685,12 @@ static int circle_select_exec(bContext *C, wmOperator *op)
}
/* do actual selection */
- for (MaskLayer *mask_layer = mask->masklayers.first; mask_layer; mask_layer = mask_layer->next) {
+ LISTBASE_FOREACH (MaskLayer *, mask_layer, &mask->masklayers) {
if (mask_layer->restrictflag & (MASK_RESTRICT_VIEW | MASK_RESTRICT_SELECT)) {
continue;
}
- for (MaskSpline *spline = mask_layer->splines.first; spline; spline = spline->next) {
+ LISTBASE_FOREACH (MaskSpline *, spline, &mask_layer->splines) {
MaskSplinePoint *points_array = BKE_mask_spline_point_array(spline);
for (i = 0; i < spline->tot_point; i++) {
@@ -749,7 +748,7 @@ void MASK_OT_select_circle(wmOperatorType *ot)
static int mask_select_linked_pick_invoke(bContext *C, wmOperator *op, const wmEvent *event)
{
- ScrArea *sa = CTX_wm_area(C);
+ ScrArea *area = CTX_wm_area(C);
ARegion *region = CTX_wm_region(C);
Mask *mask = CTX_data_edit_mask(C);
@@ -761,7 +760,7 @@ static int mask_select_linked_pick_invoke(bContext *C, wmOperator *op, const wmE
const float threshold = 19;
bool changed = false;
- ED_mask_mouse_pos(sa, region, event->mval, co);
+ ED_mask_mouse_pos(area, region, event->mval, co);
point = ED_mask_point_find_nearest(C, mask, co, threshold, &mask_layer, &spline, NULL, NULL);
@@ -815,12 +814,12 @@ static int mask_select_linked_exec(bContext *C, wmOperator *UNUSED(op))
bool changed = false;
/* do actual selection */
- for (MaskLayer *mask_layer = mask->masklayers.first; mask_layer; mask_layer = mask_layer->next) {
+ LISTBASE_FOREACH (MaskLayer *, mask_layer, &mask->masklayers) {
if (mask_layer->restrictflag & (MASK_RESTRICT_VIEW | MASK_RESTRICT_SELECT)) {
continue;
}
- for (MaskSpline *spline = mask_layer->splines.first; spline; spline = spline->next) {
+ LISTBASE_FOREACH (MaskSpline *, spline, &mask_layer->splines) {
if (ED_mask_spline_select_check(spline)) {
ED_mask_spline_select_set(spline, true);
changed = true;
@@ -865,12 +864,12 @@ static int mask_select_more_less(bContext *C, bool more)
{
Mask *mask = CTX_data_edit_mask(C);
- for (MaskLayer *mask_layer = mask->masklayers.first; mask_layer; mask_layer = mask_layer->next) {
+ LISTBASE_FOREACH (MaskLayer *, mask_layer, &mask->masklayers) {
if (mask_layer->restrictflag & (MASK_RESTRICT_VIEW | MASK_RESTRICT_SELECT)) {
continue;
}
- for (MaskSpline *spline = mask_layer->splines.first; spline; spline = spline->next) {
+ LISTBASE_FOREACH (MaskSpline *, spline, &mask_layer->splines) {
const bool cyclic = (spline->flag & MASK_SPLINE_CYCLIC) != 0;
bool start_sel, end_sel, prev_sel, cur_sel;
int i;
diff --git a/source/blender/editors/mask/mask_shapekey.c b/source/blender/editors/mask/mask_shapekey.c
index 25b602d63c3..f264e67d35c 100644
--- a/source/blender/editors/mask/mask_shapekey.c
+++ b/source/blender/editors/mask/mask_shapekey.c
@@ -53,7 +53,7 @@ static int mask_shape_key_insert_exec(bContext *C, wmOperator *UNUSED(op))
Mask *mask = CTX_data_edit_mask(C);
bool changed = false;
- for (MaskLayer *mask_layer = mask->masklayers.first; mask_layer; mask_layer = mask_layer->next) {
+ LISTBASE_FOREACH (MaskLayer *, mask_layer, &mask->masklayers) {
MaskLayerShape *mask_layer_shape;
if (!ED_mask_layer_select_check(mask_layer)) {
@@ -98,7 +98,7 @@ static int mask_shape_key_clear_exec(bContext *C, wmOperator *UNUSED(op))
Mask *mask = CTX_data_edit_mask(C);
bool changed = false;
- for (MaskLayer *mask_layer = mask->masklayers.first; mask_layer; mask_layer = mask_layer->next) {
+ LISTBASE_FOREACH (MaskLayer *, mask_layer, &mask->masklayers) {
MaskLayerShape *mask_layer_shape;
if (!ED_mask_layer_select_check(mask_layer)) {
@@ -146,7 +146,7 @@ static int mask_shape_key_feather_reset_exec(bContext *C, wmOperator *UNUSED(op)
Mask *mask = CTX_data_edit_mask(C);
bool changed = false;
- for (MaskLayer *mask_layer = mask->masklayers.first; mask_layer; mask_layer = mask_layer->next) {
+ LISTBASE_FOREACH (MaskLayer *, mask_layer, &mask->masklayers) {
if (mask_layer->restrictflag & (MASK_RESTRICT_VIEW | MASK_RESTRICT_SELECT)) {
continue;
@@ -172,7 +172,7 @@ static int mask_shape_key_feather_reset_exec(bContext *C, wmOperator *UNUSED(op)
shape_ele_src = (MaskLayerShapeElem *)mask_layer_shape_reset->data;
shape_ele_dst = (MaskLayerShapeElem *)mask_layer_shape->data;
- for (MaskSpline *spline = mask_layer->splines.first; spline; spline = spline->next) {
+ LISTBASE_FOREACH (MaskSpline *, spline, &mask_layer->splines) {
for (int i = 0; i < spline->tot_point; i++) {
MaskSplinePoint *point = &spline->points[i];
@@ -243,7 +243,7 @@ static int mask_shape_key_rekey_exec(bContext *C, wmOperator *op)
const bool do_feather = RNA_boolean_get(op->ptr, "feather");
const bool do_location = RNA_boolean_get(op->ptr, "location");
- for (MaskLayer *mask_layer = mask->masklayers.first; mask_layer; mask_layer = mask_layer->next) {
+ LISTBASE_FOREACH (MaskLayer *, mask_layer, &mask->masklayers) {
if (mask_layer->restrictflag & (MASK_RESTRICT_VIEW | MASK_RESTRICT_SELECT)) {
continue;
}
@@ -324,7 +324,7 @@ static int mask_shape_key_rekey_exec(bContext *C, wmOperator *op)
shape_ele_src = (MaskLayerShapeElem *)mask_layer_shape_tmp->data;
shape_ele_dst = (MaskLayerShapeElem *)mask_layer_shape_tmp_rekey->data;
- for (MaskSpline *spline = mask_layer->splines.first; spline; spline = spline->next) {
+ LISTBASE_FOREACH (MaskSpline *, spline, &mask_layer->splines) {
for (int i = 0; i < spline->tot_point; i++) {
MaskSplinePoint *point = &spline->points[i];
@@ -404,7 +404,7 @@ bool ED_mask_layer_shape_auto_key_all(Mask *mask, const int frame)
{
bool changed = false;
- for (MaskLayer *mask_layer = mask->masklayers.first; mask_layer; mask_layer = mask_layer->next) {
+ LISTBASE_FOREACH (MaskLayer *, mask_layer, &mask->masklayers) {
ED_mask_layer_shape_auto_key(mask_layer, frame);
changed = true;
}
@@ -416,7 +416,7 @@ bool ED_mask_layer_shape_auto_key_select(Mask *mask, const int frame)
{
bool changed = false;
- for (MaskLayer *mask_layer = mask->masklayers.first; mask_layer; mask_layer = mask_layer->next) {
+ LISTBASE_FOREACH (MaskLayer *, mask_layer, &mask->masklayers) {
if (!ED_mask_layer_select_check(mask_layer)) {
continue;
diff --git a/source/blender/editors/mesh/editface.c b/source/blender/editors/mesh/editface.c
index 987447c3663..b303c4c7e4e 100644
--- a/source/blender/editors/mesh/editface.c
+++ b/source/blender/editors/mesh/editface.c
@@ -190,7 +190,7 @@ void paintface_reveal(bContext *C, Object *ob, const bool select)
/* Set tface seams based on edge data, uses hash table to find seam edges. */
-static void select_linked_tfaces_with_seams(Mesh *me, const unsigned int index, const bool select)
+static void select_linked_tfaces_with_seams(Mesh *me, const uint index, const bool select)
{
MPoly *mp;
MLoop *ml;
@@ -201,7 +201,7 @@ static void select_linked_tfaces_with_seams(Mesh *me, const unsigned int index,
BLI_bitmap *edge_tag = BLI_BITMAP_NEW(me->totedge, __func__);
BLI_bitmap *poly_tag = BLI_BITMAP_NEW(me->totpoly, __func__);
- if (index != (unsigned int)-1) {
+ if (index != (uint)-1) {
/* only put face under cursor in array */
mp = &me->mpoly[index];
BKE_mesh_poly_edgebitmap_insert(edge_tag, mp, me->mloop + mp->loopstart);
@@ -267,7 +267,7 @@ static void select_linked_tfaces_with_seams(Mesh *me, const unsigned int index,
void paintface_select_linked(bContext *C, Object *ob, const int mval[2], const bool select)
{
Mesh *me;
- unsigned int index = (unsigned int)-1;
+ uint index = (uint)-1;
me = BKE_mesh_from_object(ob);
if (me == NULL || me->totpoly == 0) {
@@ -493,8 +493,10 @@ void paintvert_tag_select_update(struct bContext *C, struct Object *ob)
WM_event_add_notifier(C, NC_GEOM | ND_SELECT, ob->data);
}
-/* note: if the caller passes false to flush_flags,
- * then they will need to run paintvert_flush_flags(ob) themselves */
+/**
+ * \note if the caller passes false to flush_flags,
+ * then they will need to run #paintvert_flush_flags(ob) themselves.
+ */
bool paintvert_deselect_all_visible(Object *ob, int action, bool flush_flags)
{
Mesh *me;
diff --git a/source/blender/editors/mesh/editmesh_add.c b/source/blender/editors/mesh/editmesh_add.c
index 1484dcfa92d..3c426e5d2b1 100644
--- a/source/blender/editors/mesh/editmesh_add.c
+++ b/source/blender/editors/mesh/editmesh_add.c
@@ -59,6 +59,7 @@ static Object *make_prim_init(bContext *C,
const char *idname,
const float loc[3],
const float rot[3],
+ const float scale[3],
ushort local_view_bits,
MakePrimitiveData *r_creation_data)
{
@@ -76,6 +77,13 @@ static Object *make_prim_init(bContext *C,
ED_object_new_primitive_matrix(C, obedit, loc, rot, r_creation_data->mat);
+ if (scale && !equals_v3v3(scale, (const float[3]){1.0f, 1.0f, 1.0f})) {
+ float scale_half[3];
+ copy_v3_v3(scale_half, scale);
+ mul_v3_fl(scale_half, 0.5f);
+ rescale_m4(r_creation_data->mat, scale_half);
+ }
+
return obedit;
}
@@ -112,9 +120,16 @@ static int add_primitive_plane_exec(bContext *C, wmOperator *op)
const bool calc_uvs = RNA_boolean_get(op->ptr, "calc_uvs");
WM_operator_view3d_unit_defaults(C, op);
- ED_object_add_generic_get_opts(C, op, 'Z', loc, rot, &enter_editmode, &local_view_bits, NULL);
- obedit = make_prim_init(
- C, CTX_DATA_(BLT_I18NCONTEXT_ID_MESH, "Plane"), loc, rot, local_view_bits, &creation_data);
+ ED_object_add_generic_get_opts(
+ C, op, 'Z', loc, rot, NULL, &enter_editmode, &local_view_bits, NULL);
+ obedit = make_prim_init(C,
+ CTX_DATA_(BLT_I18NCONTEXT_ID_MESH, "Plane"),
+ loc,
+ rot,
+ NULL,
+ local_view_bits,
+ &creation_data);
+
em = BKE_editmesh_from_object(obedit);
if (calc_uvs) {
@@ -164,15 +179,22 @@ static int add_primitive_cube_exec(bContext *C, wmOperator *op)
MakePrimitiveData creation_data;
Object *obedit;
BMEditMesh *em;
- float loc[3], rot[3];
+ float loc[3], rot[3], scale[3];
bool enter_editmode;
ushort local_view_bits;
const bool calc_uvs = RNA_boolean_get(op->ptr, "calc_uvs");
WM_operator_view3d_unit_defaults(C, op);
- ED_object_add_generic_get_opts(C, op, 'Z', loc, rot, &enter_editmode, &local_view_bits, NULL);
- obedit = make_prim_init(
- C, CTX_DATA_(BLT_I18NCONTEXT_ID_MESH, "Cube"), loc, rot, local_view_bits, &creation_data);
+ ED_object_add_generic_get_opts(
+ C, op, 'Z', loc, rot, scale, &enter_editmode, &local_view_bits, NULL);
+ obedit = make_prim_init(C,
+ CTX_DATA_(BLT_I18NCONTEXT_ID_MESH, "Cube"),
+ loc,
+ rot,
+ scale,
+ local_view_bits,
+ &creation_data);
+
em = BKE_editmesh_from_object(obedit);
if (calc_uvs) {
@@ -237,9 +259,16 @@ static int add_primitive_circle_exec(bContext *C, wmOperator *op)
cap_tri = (cap_end == 2);
WM_operator_view3d_unit_defaults(C, op);
- ED_object_add_generic_get_opts(C, op, 'Z', loc, rot, &enter_editmode, &local_view_bits, NULL);
- obedit = make_prim_init(
- C, CTX_DATA_(BLT_I18NCONTEXT_ID_MESH, "Circle"), loc, rot, local_view_bits, &creation_data);
+ ED_object_add_generic_get_opts(
+ C, op, 'Z', loc, rot, NULL, &enter_editmode, &local_view_bits, NULL);
+ obedit = make_prim_init(C,
+ CTX_DATA_(BLT_I18NCONTEXT_ID_MESH, "Circle"),
+ loc,
+ rot,
+ NULL,
+ local_view_bits,
+ &creation_data);
+
em = BKE_editmesh_from_object(obedit);
if (calc_uvs) {
@@ -294,7 +323,7 @@ static int add_primitive_cylinder_exec(bContext *C, wmOperator *op)
MakePrimitiveData creation_data;
Object *obedit;
BMEditMesh *em;
- float loc[3], rot[3];
+ float loc[3], rot[3], scale[3];
bool enter_editmode;
ushort local_view_bits;
const int end_fill_type = RNA_enum_get(op->ptr, "end_fill_type");
@@ -303,11 +332,13 @@ static int add_primitive_cylinder_exec(bContext *C, wmOperator *op)
const bool calc_uvs = RNA_boolean_get(op->ptr, "calc_uvs");
WM_operator_view3d_unit_defaults(C, op);
- ED_object_add_generic_get_opts(C, op, 'Z', loc, rot, &enter_editmode, &local_view_bits, NULL);
+ ED_object_add_generic_get_opts(
+ C, op, 'Z', loc, rot, scale, &enter_editmode, &local_view_bits, NULL);
obedit = make_prim_init(C,
CTX_DATA_(BLT_I18NCONTEXT_ID_MESH, "Cylinder"),
loc,
rot,
+ scale,
local_view_bits,
&creation_data);
em = BKE_editmesh_from_object(obedit);
@@ -368,7 +399,7 @@ static int add_primitive_cone_exec(bContext *C, wmOperator *op)
MakePrimitiveData creation_data;
Object *obedit;
BMEditMesh *em;
- float loc[3], rot[3];
+ float loc[3], rot[3], scale[3];
bool enter_editmode;
ushort local_view_bits;
const int end_fill_type = RNA_enum_get(op->ptr, "end_fill_type");
@@ -377,9 +408,15 @@ static int add_primitive_cone_exec(bContext *C, wmOperator *op)
const bool calc_uvs = RNA_boolean_get(op->ptr, "calc_uvs");
WM_operator_view3d_unit_defaults(C, op);
- ED_object_add_generic_get_opts(C, op, 'Z', loc, rot, &enter_editmode, &local_view_bits, NULL);
- obedit = make_prim_init(
- C, CTX_DATA_(BLT_I18NCONTEXT_ID_MESH, "Cone"), loc, rot, local_view_bits, &creation_data);
+ ED_object_add_generic_get_opts(
+ C, op, 'Z', loc, rot, scale, &enter_editmode, &local_view_bits, NULL);
+ obedit = make_prim_init(C,
+ CTX_DATA_(BLT_I18NCONTEXT_ID_MESH, "Cone"),
+ loc,
+ rot,
+ scale,
+ local_view_bits,
+ &creation_data);
em = BKE_editmesh_from_object(obedit);
if (calc_uvs) {
@@ -447,9 +484,15 @@ static int add_primitive_grid_exec(bContext *C, wmOperator *op)
const bool calc_uvs = RNA_boolean_get(op->ptr, "calc_uvs");
WM_operator_view3d_unit_defaults(C, op);
- ED_object_add_generic_get_opts(C, op, 'Z', loc, rot, &enter_editmode, &local_view_bits, NULL);
- obedit = make_prim_init(
- C, CTX_DATA_(BLT_I18NCONTEXT_ID_MESH, "Grid"), loc, rot, local_view_bits, &creation_data);
+ ED_object_add_generic_get_opts(
+ C, op, 'Z', loc, rot, NULL, &enter_editmode, &local_view_bits, NULL);
+ obedit = make_prim_init(C,
+ CTX_DATA_(BLT_I18NCONTEXT_ID_MESH, "Grid"),
+ loc,
+ rot,
+ NULL,
+ local_view_bits,
+ &creation_data);
em = BKE_editmesh_from_object(obedit);
if (calc_uvs) {
@@ -514,10 +557,16 @@ static int add_primitive_monkey_exec(bContext *C, wmOperator *op)
const bool calc_uvs = RNA_boolean_get(op->ptr, "calc_uvs");
WM_operator_view3d_unit_defaults(C, op);
- ED_object_add_generic_get_opts(C, op, 'Y', loc, rot, &enter_editmode, &local_view_bits, NULL);
+ ED_object_add_generic_get_opts(
+ C, op, 'Y', loc, rot, NULL, &enter_editmode, &local_view_bits, NULL);
- obedit = make_prim_init(
- C, CTX_DATA_(BLT_I18NCONTEXT_ID_MESH, "Suzanne"), loc, rot, local_view_bits, &creation_data);
+ obedit = make_prim_init(C,
+ CTX_DATA_(BLT_I18NCONTEXT_ID_MESH, "Suzanne"),
+ loc,
+ rot,
+ NULL,
+ local_view_bits,
+ &creation_data);
dia = RNA_float_get(op->ptr, "size") / 2.0f;
mul_mat3_m4_fl(creation_data.mat, dia);
@@ -567,15 +616,21 @@ static int add_primitive_uvsphere_exec(bContext *C, wmOperator *op)
MakePrimitiveData creation_data;
Object *obedit;
BMEditMesh *em;
- float loc[3], rot[3];
+ float loc[3], rot[3], scale[3];
bool enter_editmode;
ushort local_view_bits;
const bool calc_uvs = RNA_boolean_get(op->ptr, "calc_uvs");
WM_operator_view3d_unit_defaults(C, op);
- ED_object_add_generic_get_opts(C, op, 'Z', loc, rot, &enter_editmode, &local_view_bits, NULL);
- obedit = make_prim_init(
- C, CTX_DATA_(BLT_I18NCONTEXT_ID_MESH, "Sphere"), loc, rot, local_view_bits, &creation_data);
+ ED_object_add_generic_get_opts(
+ C, op, 'Z', loc, rot, scale, &enter_editmode, &local_view_bits, NULL);
+ obedit = make_prim_init(C,
+ CTX_DATA_(BLT_I18NCONTEXT_ID_MESH, "Sphere"),
+ loc,
+ rot,
+ scale,
+ local_view_bits,
+ &creation_data);
em = BKE_editmesh_from_object(obedit);
if (calc_uvs) {
@@ -629,17 +684,19 @@ static int add_primitive_icosphere_exec(bContext *C, wmOperator *op)
MakePrimitiveData creation_data;
Object *obedit;
BMEditMesh *em;
- float loc[3], rot[3];
+ float loc[3], rot[3], scale[3];
bool enter_editmode;
ushort local_view_bits;
const bool calc_uvs = RNA_boolean_get(op->ptr, "calc_uvs");
WM_operator_view3d_unit_defaults(C, op);
- ED_object_add_generic_get_opts(C, op, 'Z', loc, rot, &enter_editmode, &local_view_bits, NULL);
+ ED_object_add_generic_get_opts(
+ C, op, 'Z', loc, rot, scale, &enter_editmode, &local_view_bits, NULL);
obedit = make_prim_init(C,
CTX_DATA_(BLT_I18NCONTEXT_ID_MESH, "Icosphere"),
loc,
rot,
+ scale,
local_view_bits,
&creation_data);
em = BKE_editmesh_from_object(obedit);
diff --git a/source/blender/editors/mesh/editmesh_bevel.c b/source/blender/editors/mesh/editmesh_bevel.c
index 10c290e2be9..e94412233ff 100644
--- a/source/blender/editors/mesh/editmesh_bevel.c
+++ b/source/blender/editors/mesh/editmesh_bevel.c
@@ -416,10 +416,10 @@ static bool edbm_bevel_calc(wmOperator *op)
static void edbm_bevel_exit(bContext *C, wmOperator *op)
{
BevelData *opdata = op->customdata;
- ScrArea *sa = CTX_wm_area(C);
+ ScrArea *area = CTX_wm_area(C);
- if (sa) {
- ED_area_status_text(sa, NULL);
+ if (area) {
+ ED_area_status_text(area, NULL);
}
for (uint ob_index = 0; ob_index < opdata->ob_store_len; ob_index++) {
@@ -690,14 +690,14 @@ wmKeyMap *bevel_modal_keymap(wmKeyConfig *keyconf)
{0, NULL, 0, NULL, NULL},
};
- wmKeyMap *keymap = WM_modalkeymap_get(keyconf, "Bevel Modal Map");
+ wmKeyMap *keymap = WM_modalkeymap_find(keyconf, "Bevel Modal Map");
/* This function is called for each spacetype, only needs to add map once */
if (keymap && keymap->modal_items) {
return NULL;
}
- keymap = WM_modalkeymap_add(keyconf, "Bevel Modal Map", modal_items);
+ keymap = WM_modalkeymap_ensure(keyconf, "Bevel Modal Map", modal_items);
WM_modalkeymap_assign(keymap, "MESH_OT_bevel");
diff --git a/source/blender/editors/mesh/editmesh_extrude.c b/source/blender/editors/mesh/editmesh_extrude.c
index 1ea1501fc66..bf6c5a2f829 100644
--- a/source/blender/editors/mesh/editmesh_extrude.c
+++ b/source/blender/editors/mesh/editmesh_extrude.c
@@ -226,6 +226,7 @@ static bool edbm_extrude_ex(Object *obedit,
char htype,
const char hflag,
const bool use_normal_flip,
+ const bool use_dissolve_ortho_edges,
const bool use_mirror,
const bool use_select_history)
{
@@ -241,6 +242,7 @@ static bool edbm_extrude_ex(Object *obedit,
BMO_op_init(bm, &extop, BMO_FLAG_DEFAULTS, "extrude_face_region");
BMO_slot_bool_set(extop.slots_in, "use_normal_flip", use_normal_flip);
+ BMO_slot_bool_set(extop.slots_in, "use_dissolve_ortho_edges", use_dissolve_ortho_edges);
BMO_slot_bool_set(extop.slots_in, "use_select_history", use_select_history);
BMO_slot_buffer_from_enabled_hflag(bm, &extop, extop.slots_in, "geom", htype, hflag);
@@ -274,11 +276,27 @@ static bool edbm_extrude_ex(Object *obedit,
static int edbm_extrude_repeat_exec(bContext *C, wmOperator *op)
{
- RegionView3D *rv3d = CTX_wm_region_view3d(C);
+
+ PropertyRNA *prop = RNA_struct_find_property(op->ptr, "offset");
const int steps = RNA_int_get(op->ptr, "steps");
- const float offs = RNA_float_get(op->ptr, "offset");
- float dvec[3], tmat[3][3], bmat[3][3];
- short a;
+ const float scale_offset = RNA_float_get(op->ptr, "scale_offset");
+ float offset[3];
+
+ if (!RNA_property_is_set(op->ptr, prop)) {
+ RegionView3D *rv3d = CTX_wm_region_view3d(C);
+ if (rv3d != NULL) {
+ normalize_v3_v3(offset, rv3d->persinv[2]);
+ }
+ else {
+ copy_v3_v3(offset, (const float[3]){0, 0, 1});
+ }
+ RNA_property_float_set_array(op->ptr, prop, offset);
+ }
+ else {
+ RNA_property_float_get_array(op->ptr, prop, offset);
+ }
+
+ mul_v3_fl(offset, scale_offset);
ViewLayer *view_layer = CTX_data_view_layer(C);
uint objects_len = 0;
@@ -286,22 +304,19 @@ static int edbm_extrude_repeat_exec(bContext *C, wmOperator *op)
view_layer, CTX_wm_view3d(C), &objects_len);
for (uint ob_index = 0; ob_index < objects_len; ob_index++) {
+ float offset_local[3], tmat[3][3];
Object *obedit = objects[ob_index];
BMEditMesh *em = BKE_editmesh_from_object(obedit);
- /* dvec */
- normalize_v3_v3_length(dvec, rv3d->persinv[2], offs);
+ copy_m3_m4(tmat, obedit->obmat);
+ invert_m3(tmat);
+ mul_v3_m3v3(offset_local, tmat, offset);
- /* base correction */
- copy_m3_m4(bmat, obedit->obmat);
- invert_m3_m3(tmat, bmat);
- mul_m3_v3(tmat, dvec);
-
- for (a = 0; a < steps; a++) {
- edbm_extrude_ex(obedit, em, BM_ALL_NOLOOP, BM_ELEM_SELECT, false, false, false);
-
- BMO_op_callf(em->bm, BMO_FLAG_DEFAULTS, "translate vec=%v verts=%hv", dvec, BM_ELEM_SELECT);
+ for (int a = 0; a < steps; a++) {
+ edbm_extrude_ex(obedit, em, BM_ALL_NOLOOP, BM_ELEM_SELECT, false, false, false, true);
+ BMO_op_callf(
+ em->bm, BMO_FLAG_DEFAULTS, "translate vec=%v verts=%hv", offset_local, BM_ELEM_SELECT);
}
EDBM_mesh_normals_update(em);
@@ -317,20 +332,23 @@ static int edbm_extrude_repeat_exec(bContext *C, wmOperator *op)
void MESH_OT_extrude_repeat(wmOperatorType *ot)
{
/* identifiers */
- ot->name = "Extrude Repeat Mesh";
+ ot->name = "Extrude Repeat";
ot->description = "Extrude selected vertices, edges or faces repeatedly";
ot->idname = "MESH_OT_extrude_repeat";
/* api callbacks */
ot->exec = edbm_extrude_repeat_exec;
- ot->poll = ED_operator_editmesh_view3d;
+ ot->poll = ED_operator_editmesh;
/* flags */
ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
/* props */
- RNA_def_float_distance(ot->srna, "offset", 2.0f, 0.0f, 1e12f, "Offset", "", 0.0f, 100.0f);
RNA_def_int(ot->srna, "steps", 10, 0, 1000000, "Steps", "", 0, 180);
+ PropertyRNA *prop = RNA_def_float_vector_xyz(
+ ot->srna, "offset", 3, NULL, -100000, 100000, "Offset", "Offset vector", -1000.0f, 1000.0f);
+ RNA_def_property_flag(prop, PROP_SKIP_SAVE);
+ RNA_def_float(ot->srna, "scale_offset", 1.0f, 0.0f, 1e12f, "Scale Offset", "", 0.0f, 100.0f);
}
/** \} */
@@ -343,6 +361,7 @@ void MESH_OT_extrude_repeat(wmOperatorType *ot)
static bool edbm_extrude_mesh(Object *obedit, BMEditMesh *em, wmOperator *op)
{
const bool use_normal_flip = RNA_boolean_get(op->ptr, "use_normal_flip");
+ const bool use_dissolve_ortho_edges = RNA_boolean_get(op->ptr, "use_dissolve_ortho_edges");
const char htype = edbm_extrude_htype_from_em_select(em);
enum { NONE = 0, ELEM_FLAG, VERT_ONLY, EDGE_ONLY } nr;
bool changed = false;
@@ -385,7 +404,14 @@ static bool edbm_extrude_mesh(Object *obedit, BMEditMesh *em, wmOperator *op)
case NONE:
return false;
case ELEM_FLAG:
- changed = edbm_extrude_ex(obedit, em, htype, BM_ELEM_SELECT, use_normal_flip, true, true);
+ changed = edbm_extrude_ex(obedit,
+ em,
+ htype,
+ BM_ELEM_SELECT,
+ use_normal_flip,
+ use_dissolve_ortho_edges,
+ true,
+ true);
break;
case VERT_ONLY:
changed = edbm_extrude_verts_indiv(em, op, BM_ELEM_SELECT);
@@ -449,6 +475,7 @@ void MESH_OT_extrude_region(wmOperatorType *ot)
ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
RNA_def_boolean(ot->srna, "use_normal_flip", false, "Flip Normals", "");
+ RNA_def_boolean(ot->srna, "use_dissolve_ortho_edges", false, "Dissolve Orthogonal Edges", "");
Transform_Properties(ot, P_NO_DEFAULTS | P_MIRROR_DUMMY);
}
@@ -503,6 +530,7 @@ void MESH_OT_extrude_context(wmOperatorType *ot)
ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
RNA_def_boolean(ot->srna, "use_normal_flip", false, "Flip Normals", "");
+ RNA_def_boolean(ot->srna, "use_dissolve_ortho_edges", false, "Dissolve Orthogonal Edges", "");
Transform_Properties(ot, P_NO_DEFAULTS | P_MIRROR_DUMMY);
}
@@ -824,7 +852,7 @@ static int edbm_dupli_extrude_cursor_invoke(bContext *C, wmOperator *op, const w
}
}
- edbm_extrude_ex(vc.obedit, vc.em, extrude_htype, BM_ELEM_SELECT, false, true, true);
+ edbm_extrude_ex(vc.obedit, vc.em, extrude_htype, BM_ELEM_SELECT, false, false, true, true);
EDBM_op_callf(
vc.em, op, "rotate verts=%hv cent=%v matrix=%m3", BM_ELEM_SELECT, local_center, mat);
EDBM_op_callf(vc.em, op, "translate verts=%hv vec=%v", BM_ELEM_SELECT, ofs);
diff --git a/source/blender/editors/mesh/editmesh_extrude_spin_gizmo.c b/source/blender/editors/mesh/editmesh_extrude_spin_gizmo.c
index 75a36b68f8b..feb6b5aaca9 100644
--- a/source/blender/editors/mesh/editmesh_extrude_spin_gizmo.c
+++ b/source/blender/editors/mesh/editmesh_extrude_spin_gizmo.c
@@ -18,6 +18,7 @@
* \ingroup edmesh
*/
+#include "BLI_listbase.h"
#include "BLI_math.h"
#include "BKE_context.h"
@@ -1030,7 +1031,7 @@ static void gizmo_mesh_spin_redo_draw_prepare(const bContext *UNUSED(C), wmGizmo
* could shift because of float precision.
* Updates in this case are also redundant. */
bool is_modal = false;
- for (wmGizmo *gz = gzgroup->gizmos.first; gz; gz = gz->next) {
+ LISTBASE_FOREACH (wmGizmo *, gz, &gzgroup->gizmos) {
if (gz->state & WM_GIZMO_STATE_MODAL) {
is_modal = true;
break;
diff --git a/source/blender/editors/mesh/editmesh_inset.c b/source/blender/editors/mesh/editmesh_inset.c
index f2983f06da6..2eeada95eda 100644
--- a/source/blender/editors/mesh/editmesh_inset.c
+++ b/source/blender/editors/mesh/editmesh_inset.c
@@ -88,10 +88,10 @@ static void edbm_inset_update_header(wmOperator *op, bContext *C)
"(%s)");
char msg[UI_MAX_DRAW_STR];
- ScrArea *sa = CTX_wm_area(C);
+ ScrArea *area = CTX_wm_area(C);
Scene *sce = CTX_data_scene(C);
- if (sa) {
+ if (area) {
char flts_str[NUM_STR_REP_LEN * 2];
if (hasNumInput(&opdata->num_input)) {
outputNumInput(&opdata->num_input, flts_str, &sce->unit);
@@ -111,7 +111,7 @@ static void edbm_inset_update_header(wmOperator *op, bContext *C)
WM_bool_as_string(RNA_boolean_get(op->ptr, "use_boundary")),
WM_bool_as_string(RNA_boolean_get(op->ptr, "use_individual")));
- ED_area_status_text(sa, msg);
+ ED_area_status_text(area, msg);
}
}
@@ -189,7 +189,7 @@ static bool edbm_inset_init(bContext *C, wmOperator *op, const bool is_modal)
static void edbm_inset_exit(bContext *C, wmOperator *op)
{
InsetData *opdata;
- ScrArea *sa = CTX_wm_area(C);
+ ScrArea *area = CTX_wm_area(C);
opdata = op->customdata;
@@ -206,8 +206,8 @@ static void edbm_inset_exit(bContext *C, wmOperator *op)
G.moving = 0;
}
- if (sa) {
- ED_area_status_text(sa, NULL);
+ if (area) {
+ ED_area_status_text(area, NULL);
}
MEM_SAFE_FREE(opdata->ob_store);
diff --git a/source/blender/editors/mesh/editmesh_intersect.c b/source/blender/editors/mesh/editmesh_intersect.c
index 7718a07a55e..fd7cc2733ec 100644
--- a/source/blender/editors/mesh/editmesh_intersect.c
+++ b/source/blender/editors/mesh/editmesh_intersect.c
@@ -479,7 +479,7 @@ static bool bm_vert_in_faces_radial(BMVert *v, BMEdge *e_radial, BMFace *f_ignor
struct LinkBase {
LinkNode *list;
- unsigned int list_len;
+ uint list_len;
};
static void ghash_insert_face_edge_link(GHash *gh,
@@ -535,7 +535,7 @@ static void bm_face_split_by_edges_island_connect(
}
{
- unsigned int edge_arr_holes_len;
+ uint edge_arr_holes_len;
BMEdge **edge_arr_holes;
if (BM_face_split_edgenet_connect_islands(bm,
f,
@@ -704,6 +704,8 @@ static int edbm_face_split_by_edges_exec(bContext *C, wmOperator *UNUSED(op))
BMEdge *e;
BMIter iter;
+ BLI_SMALLSTACK_DECLARE(loop_stack, BMLoop *);
+
ViewLayer *view_layer = CTX_data_view_layer(C);
uint objects_len = 0;
Object **objects = BKE_view_layer_array_from_objects_in_edit_mode_unique_data(
@@ -717,8 +719,6 @@ static int edbm_face_split_by_edges_exec(bContext *C, wmOperator *UNUSED(op))
continue;
}
- BLI_SMALLSTACK_DECLARE(loop_stack, BMLoop *);
-
{
BMVert *v;
BM_ITER_MESH (v, &iter, bm, BM_VERTS_OF_MESH) {
@@ -765,7 +765,7 @@ static int edbm_face_split_by_edges_exec(bContext *C, wmOperator *UNUSED(op))
BMIter liter;
BMLoop *l;
- unsigned int loop_stack_len;
+ uint loop_stack_len;
BMLoop *l_best = NULL;
BLI_assert(BLI_SMALLSTACK_IS_EMPTY(loop_stack));
diff --git a/source/blender/editors/mesh/editmesh_knife.c b/source/blender/editors/mesh/editmesh_knife.c
index 6230eacba94..5f5599b53df 100644
--- a/source/blender/editors/mesh/editmesh_knife.c
+++ b/source/blender/editors/mesh/editmesh_knife.c
@@ -1162,6 +1162,7 @@ static void knifetool_draw(const bContext *UNUSED(C), ARegion *UNUSED(region), v
rgba_uchar_to_float(fcol, kcd->colors.point_a);
GPU_batch_uniform_4fv(batch, "color", fcol);
GPU_matrix_bind(batch->interface);
+ GPU_shader_set_srgb_uniform(batch->interface);
GPU_point_size(11);
if (snapped_verts_count > 0) {
GPU_batch_draw_advanced(batch, 0, snapped_verts_count, 0, 0);
@@ -1579,7 +1580,7 @@ static void knife_find_line_hits(KnifeTool_OpData *kcd)
float line_tol, line_tol_sq;
float face_tol, face_tol_sq;
int isect_kind;
- unsigned int tot;
+ uint tot;
int i;
const bool use_hit_prev = true;
const bool use_hit_curr = (kcd->is_drag_hold == false);
@@ -2419,7 +2420,7 @@ static void knife_make_face_cuts(KnifeTool_OpData *kcd, BMFace *f, ListBase *kfe
edge_array_len = i;
#ifdef USE_NET_ISLAND_CONNECT
- unsigned int edge_array_holes_len;
+ uint edge_array_holes_len;
BMEdge **edge_array_holes;
if (BM_face_split_edgenet_connect_islands(bm,
f,
@@ -2824,14 +2825,14 @@ wmKeyMap *knifetool_modal_keymap(wmKeyConfig *keyconf)
{0, NULL, 0, NULL, NULL},
};
- wmKeyMap *keymap = WM_modalkeymap_get(keyconf, "Knife Tool Modal Map");
+ wmKeyMap *keymap = WM_modalkeymap_find(keyconf, "Knife Tool Modal Map");
/* this function is called for each spacetype, only needs to add map once */
if (keymap && keymap->modal_items) {
return NULL;
}
- keymap = WM_modalkeymap_add(keyconf, "Knife Tool Modal Map", modal_items);
+ keymap = WM_modalkeymap_ensure(keyconf, "Knife Tool Modal Map", modal_items);
WM_modalkeymap_assign(keymap, "MESH_OT_knife_tool");
@@ -2997,6 +2998,7 @@ static int knifetool_modal(bContext *C, wmOperator *op, const wmEvent *event)
case MOUSEROTATE:
case WHEELUPMOUSE:
case WHEELDOWNMOUSE:
+ case NDOF_MOTION:
return OPERATOR_PASS_THROUGH;
case MOUSEMOVE: /* mouse moved somewhere to select another loop */
if (kcd->mode != MODE_PANNING) {
diff --git a/source/blender/editors/mesh/editmesh_loopcut.c b/source/blender/editors/mesh/editmesh_loopcut.c
index 37bacb4af55..0f52911c603 100644
--- a/source/blender/editors/mesh/editmesh_loopcut.c
+++ b/source/blender/editors/mesh/editmesh_loopcut.c
@@ -372,7 +372,8 @@ static int loopcut_init(bContext *C, wmOperator *op, const wmEvent *event)
if (is_interactive) {
for (uint base_index = 0; base_index < bases_len; base_index++) {
Object *ob_iter = bases[base_index]->object;
- if (modifiers_isDeformedByLattice(ob_iter) || modifiers_isDeformedByArmature(ob_iter)) {
+ if (BKE_modifiers_is_deformed_by_lattice(ob_iter) ||
+ BKE_modifiers_is_deformed_by_armature(ob_iter)) {
BKE_report(
op->reports, RPT_WARNING, "Loop cut does not work well on deformed edit mesh display");
break;
@@ -514,6 +515,10 @@ static int loopcut_finish(RingSelOpData *lcd, bContext *C, wmOperator *op)
static int loopcut_modal(bContext *C, wmOperator *op, const wmEvent *event)
{
+ if (event->type == NDOF_MOTION) {
+ return OPERATOR_PASS_THROUGH;
+ }
+
RingSelOpData *lcd = op->customdata;
float cuts = lcd->cuts;
float smoothness = lcd->smoothness;
@@ -605,7 +610,8 @@ static int loopcut_modal(bContext *C, wmOperator *op, const wmEvent *event)
}
handled = true;
break;
- case MOUSEMOVE: /* mouse moved somewhere to select another loop */
+ case MOUSEMOVE: {
+ /* mouse moved somewhere to select another loop */
/* This is normally disabled for all modal operators.
* This is an exception since mouse movement doesn't relate to numeric input.
@@ -614,14 +620,16 @@ static int loopcut_modal(bContext *C, wmOperator *op, const wmEvent *event)
#if 0
if (!has_numinput)
#endif
- {
- lcd->vc.mval[0] = event->mval[0];
- lcd->vc.mval[1] = event->mval[1];
- loopcut_mouse_move(lcd, (int)lcd->cuts);
+ {
+ lcd->vc.mval[0] = event->mval[0];
+ lcd->vc.mval[1] = event->mval[1];
+ loopcut_mouse_move(lcd, (int)lcd->cuts);
- ED_region_tag_redraw(lcd->region);
- handled = true;
- } break;
+ ED_region_tag_redraw(lcd->region);
+ handled = true;
+ }
+ break;
+ }
}
/* Modal numinput inactive, try to handle numeric inputs last... */
diff --git a/source/blender/editors/mesh/editmesh_mask_extract.c b/source/blender/editors/mesh/editmesh_mask_extract.c
index 3a0a028468d..739bc5bdf7c 100644
--- a/source/blender/editors/mesh/editmesh_mask_extract.c
+++ b/source/blender/editors/mesh/editmesh_mask_extract.c
@@ -67,10 +67,10 @@ static bool paint_mask_extract_poll(bContext *C)
return false;
}
else {
- return true;
+ return ED_operator_object_active_editable_mesh(C);
}
}
- return ED_operator_object_active_editable_mesh(C);
+ return false;
}
static int paint_mask_extract_exec(bContext *C, wmOperator *op)
@@ -224,7 +224,7 @@ static int paint_mask_extract_exec(bContext *C, wmOperator *op)
if (RNA_boolean_get(op->ptr, "add_solidify")) {
ED_object_modifier_add(
op->reports, bmain, scene, new_ob, "mask_extract_solidify", eModifierType_Solidify);
- SolidifyModifierData *sfmd = (SolidifyModifierData *)modifiers_findByName(
+ SolidifyModifierData *sfmd = (SolidifyModifierData *)BKE_modifiers_findby_name(
new_ob, "mask_extract_solidify");
if (sfmd) {
sfmd->offset = -0.05f;
diff --git a/source/blender/editors/mesh/editmesh_rip.c b/source/blender/editors/mesh/editmesh_rip.c
index a1ea6074044..5d9923c6a7d 100644
--- a/source/blender/editors/mesh/editmesh_rip.c
+++ b/source/blender/editors/mesh/editmesh_rip.c
@@ -402,7 +402,7 @@ static UnorderedLoopPair *edbm_tagged_loop_pairs_to_fill(BMesh *bm)
BMIter iter;
BMEdge *e;
- unsigned int total_tag = 0;
+ uint total_tag = 0;
/* count tags, could be pre-calculated */
BM_ITER_MESH (e, &iter, bm, BM_EDGES_OF_MESH) {
if (BM_elem_flag_test(e, BM_ELEM_TAG)) {
@@ -441,8 +441,8 @@ static UnorderedLoopPair *edbm_tagged_loop_pairs_to_fill(BMesh *bm)
static void edbm_tagged_loop_pairs_do_fill_faces(BMesh *bm, UnorderedLoopPair *uloop_pairs)
{
UnorderedLoopPair *ulp;
- unsigned int total_tag = MEM_allocN_len(uloop_pairs) / sizeof(UnorderedLoopPair);
- unsigned int i;
+ uint total_tag = MEM_allocN_len(uloop_pairs) / sizeof(UnorderedLoopPair);
+ uint i;
for (i = 0, ulp = uloop_pairs; i < total_tag; i++, ulp++) {
if ((ulp->l_pair[0] && ulp->l_pair[1]) && (ulp->l_pair[0]->e != ulp->l_pair[1]->e)) {
diff --git a/source/blender/editors/mesh/editmesh_select.c b/source/blender/editors/mesh/editmesh_select.c
index f01511fa513..6b029cdef16 100644
--- a/source/blender/editors/mesh/editmesh_select.c
+++ b/source/blender/editors/mesh/editmesh_select.c
@@ -2335,6 +2335,8 @@ void EDBM_selectmode_convert(BMEditMesh *em,
BM_edge_select_set(bm, eed, false);
}
}
+ /* Deselect faces without edges selected. */
+ BM_mesh_deselect_flush(bm);
}
else if (selectmode_new == SCE_SELECT_VERTEX) {
/* flush down (face -> vert) */
@@ -2668,8 +2670,9 @@ bool EDBM_selectmode_disable_multi_ex(Scene *scene,
Object *ob_iter = base_iter->object;
BMEditMesh *em_iter = BKE_editmesh_from_object(ob_iter);
- EDBM_selectmode_disable(scene, em_iter, selectmode_disable, selectmode_fallback);
- changed_multi = true;
+ if (EDBM_selectmode_disable(scene, em_iter, selectmode_disable, selectmode_fallback)) {
+ changed_multi = true;
+ }
}
return changed_multi;
}
@@ -3201,8 +3204,12 @@ static int edbm_select_linked_exec(bContext *C, wmOperator *op)
BMEdge *e;
BM_ITER_MESH (e, &iter, em->bm, BM_EDGES_OF_MESH) {
if (!BMO_edge_flag_test(bm, e, BMO_ELE_TAG)) {
- BM_elem_flag_disable(e->v1, BM_ELEM_TAG);
- BM_elem_flag_disable(e->v2, BM_ELEM_TAG);
+ /* Check the edge for selected faces,
+ * this supports stepping off isolated vertices which would otherwise be ignored. */
+ if (BM_edge_is_any_face_flag_test(e, BM_ELEM_SELECT)) {
+ BM_elem_flag_disable(e->v1, BM_ELEM_TAG);
+ BM_elem_flag_disable(e->v2, BM_ELEM_TAG);
+ }
}
}
}
@@ -3258,10 +3265,13 @@ static int edbm_select_linked_exec(bContext *C, wmOperator *op)
if (delimit) {
BM_ITER_MESH (e, &iter, em->bm, BM_EDGES_OF_MESH) {
- BM_elem_flag_set(
- e,
- BM_ELEM_TAG,
- (BM_elem_flag_test(e, BM_ELEM_SELECT) && BMO_edge_flag_test(bm, e, BMO_ELE_TAG)));
+ /* Check the edge for selected faces,
+ * this supports stepping off isolated edges which would otherwise be ignored. */
+ BM_elem_flag_set(e,
+ BM_ELEM_TAG,
+ (BM_elem_flag_test(e, BM_ELEM_SELECT) &&
+ (BMO_edge_flag_test(bm, e, BMO_ELE_TAG) ||
+ !BM_edge_is_any_face_flag_test(e, BM_ELEM_SELECT))));
}
}
else {
diff --git a/source/blender/editors/mesh/editmesh_select_similar.c b/source/blender/editors/mesh/editmesh_select_similar.c
index 5106108a16c..365c5b5d264 100644
--- a/source/blender/editors/mesh/editmesh_select_similar.c
+++ b/source/blender/editors/mesh/editmesh_select_similar.c
@@ -1059,7 +1059,7 @@ static int similar_vert_select_exec(bContext *C, wmOperator *op)
if (type == SIMVERT_VGROUP) {
/* We store the names of the vertex groups, so we can select
- * vertex groups with the same name in different objects. */
+ * vertex groups with the same name in different objects. */
const int dvert_tot = BLI_listbase_count(&ob->defbase);
for (int i = 0; i < dvert_tot; i++) {
if (dvert_selected & (1 << i)) {
diff --git a/source/blender/editors/mesh/editmesh_tools.c b/source/blender/editors/mesh/editmesh_tools.c
index b52f63e0a1b..684bb73dc0e 100644
--- a/source/blender/editors/mesh/editmesh_tools.c
+++ b/source/blender/editors/mesh/editmesh_tools.c
@@ -69,9 +69,9 @@
#include "ED_mesh.h"
#include "ED_object.h"
+#include "ED_outliner.h"
#include "ED_screen.h"
#include "ED_transform.h"
-#include "ED_transform_snap_object_context.h"
#include "ED_uvedit.h"
#include "ED_view3d.h"
@@ -410,45 +410,6 @@ void MESH_OT_unsubdivide(wmOperatorType *ot)
ot->srna, "iterations", 2, 1, 1000, "Iterations", "Number of times to unsubdivide", 1, 100);
}
-void EDBM_project_snap_verts(
- bContext *C, Depsgraph *depsgraph, ARegion *region, Object *obedit, BMEditMesh *em)
-{
- Main *bmain = CTX_data_main(C);
- BMIter iter;
- BMVert *eve;
-
- ED_view3d_init_mats_rv3d(obedit, region->regiondata);
-
- struct SnapObjectContext *snap_context = ED_transform_snap_object_context_create_view3d(
- bmain, CTX_data_scene(C), 0, region, CTX_wm_view3d(C));
-
- BM_ITER_MESH (eve, &iter, em->bm, BM_VERTS_OF_MESH) {
- if (BM_elem_flag_test(eve, BM_ELEM_SELECT)) {
- float mval[2], co_proj[3];
- if (ED_view3d_project_float_object(region, eve->co, mval, V3D_PROJ_TEST_NOP) ==
- V3D_PROJ_RET_OK) {
- if (ED_transform_snap_object_project_view3d(snap_context,
- depsgraph,
- SCE_SNAP_MODE_FACE,
- &(const struct SnapObjectParams){
- .snap_select = SNAP_NOT_ACTIVE,
- .use_object_edit_cage = false,
- .use_occlusion_test = true,
- },
- mval,
- NULL,
- NULL,
- co_proj,
- NULL)) {
- mul_v3_m4v3(eve->co, obedit->imat, co_proj);
- }
- }
- }
- }
-
- ED_transform_snap_object_context_destroy(snap_context);
-}
-
/** \} */
/* -------------------------------------------------------------------- */
@@ -731,8 +692,10 @@ static int edbm_collapse_edge_exec(bContext *C, wmOperator *op)
void MESH_OT_edge_collapse(wmOperatorType *ot)
{
/* identifiers */
- ot->name = "Edge Collapse";
- ot->description = "Collapse selected edges";
+ ot->name = "Collapse Edges & Faces";
+ ot->description =
+ "Collapse isolated edges & faces regions, merging data such as UV's and vertex colors. "
+ "This can collapse edge-rings as well as regions of connected faces into vertices";
ot->idname = "MESH_OT_edge_collapse";
/* api callbacks */
@@ -754,7 +717,7 @@ static bool edbm_add_edge_face__smooth_get(BMesh *bm)
BMEdge *e;
BMIter iter;
- unsigned int vote_on_smooth[2] = {0, 0};
+ uint vote_on_smooth[2] = {0, 0};
BM_ITER_MESH (e, &iter, bm, BM_EDGES_OF_MESH) {
if (BM_elem_flag_test(e, BM_ELEM_SELECT) && e->l) {
@@ -1184,6 +1147,12 @@ void MESH_OT_mark_sharp(wmOperatorType *ot)
RNA_def_property_flag(prop, PROP_SKIP_SAVE);
}
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Connect Vertex Path Operator
+ * \{ */
+
static bool edbm_connect_vert_pair(BMEditMesh *em, struct Mesh *me, wmOperator *op)
{
BMesh *bm = em->bm;
@@ -1309,7 +1278,7 @@ void MESH_OT_vert_connect(wmOperatorType *ot)
/** \} */
/* -------------------------------------------------------------------- */
-/** \name Split Concave Faces Operator
+/** \name Connect Vertex Path Operator
* \{ */
/**
@@ -1598,6 +1567,12 @@ void MESH_OT_vert_connect_path(wmOperatorType *ot)
ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
}
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Connect Concave Operator
+ * \{ */
+
static int edbm_vert_connect_concave_exec(bContext *C, wmOperator *op)
{
ViewLayer *view_layer = CTX_data_view_layer(C);
@@ -1771,8 +1746,93 @@ void MESH_OT_face_make_planar(wmOperatorType *ot)
/** \name Split Edge Operator
* \{ */
+static bool edbm_edge_split_selected_edges(wmOperator *op, Object *obedit, BMEditMesh *em)
+{
+ BMesh *bm = em->bm;
+ if (bm->totedgesel == 0) {
+ return false;
+ }
+ if (!EDBM_op_call_and_selectf(
+ em, op, "edges.out", false, "split_edges edges=%he", BM_ELEM_SELECT)) {
+ return false;
+ }
+
+ EDBM_select_flush(em);
+ EDBM_update_generic(obedit->data, true, true);
+
+ return true;
+}
+
+static bool edbm_edge_split_selected_verts(wmOperator *op, Object *obedit, BMEditMesh *em)
+{
+ BMesh *bm = em->bm;
+
+ /* Note that tracking vertices through the 'split_edges' operator is complicated.
+ * Instead, tag loops for selection. */
+ if (bm->totvertsel == 0) {
+ return false;
+ }
+
+ /* Flush from vertices to edges. */
+ BMIter iter;
+ BMEdge *eed;
+ BM_ITER_MESH (eed, &iter, bm, BM_EDGES_OF_MESH) {
+ BM_elem_flag_disable(eed, BM_ELEM_TAG);
+ if (eed->l != NULL) {
+ if (!BM_elem_flag_test(eed, BM_ELEM_HIDDEN) &&
+ (BM_elem_flag_test(eed->v1, BM_ELEM_SELECT) ||
+ BM_elem_flag_test(eed->v2, BM_ELEM_SELECT))) {
+ BM_elem_flag_enable(eed, BM_ELEM_TAG);
+ }
+ /* Store selection in loop tags. */
+ BMLoop *l_iter = eed->l;
+ do {
+ BM_elem_flag_set(l_iter, BM_ELEM_TAG, BM_elem_flag_test(l_iter->v, BM_ELEM_SELECT));
+ } while ((l_iter = l_iter->radial_next) != eed->l);
+ }
+ }
+
+ if (!EDBM_op_callf(em,
+ op,
+ "split_edges edges=%he verts=%hv use_verts=%b",
+ BM_ELEM_TAG,
+ BM_ELEM_SELECT,
+ true)) {
+ return false;
+ }
+
+ BM_ITER_MESH (eed, &iter, em->bm, BM_EDGES_OF_MESH) {
+ if (eed->l != NULL) {
+ BMLoop *l_iter = eed->l;
+ do {
+ if (BM_elem_flag_test(l_iter, BM_ELEM_TAG)) {
+ BM_vert_select_set(em->bm, l_iter->v, true);
+ }
+ } while ((l_iter = l_iter->radial_next) != eed->l);
+ }
+ else {
+ /* Split out wire. */
+ for (int i = 0; i < 2; i++) {
+ BMVert *v = *(&eed->v1 + i);
+ if (BM_elem_flag_test(v, BM_ELEM_SELECT)) {
+ if (eed != BM_DISK_EDGE_NEXT(eed, v)) {
+ BM_vert_separate(bm, v, &eed, 1, true, NULL, NULL);
+ }
+ }
+ }
+ }
+ }
+
+ EDBM_select_flush(em);
+ EDBM_update_generic(obedit->data, true, true);
+
+ return true;
+}
+
static int edbm_edge_split_exec(bContext *C, wmOperator *op)
{
+ const int type = RNA_enum_get(op->ptr, "type");
+
ViewLayer *view_layer = CTX_data_view_layer(C);
uint objects_len = 0;
Object **objects = BKE_view_layer_array_from_objects_in_edit_mode_unique_data(
@@ -1780,20 +1840,21 @@ static int edbm_edge_split_exec(bContext *C, wmOperator *op)
for (uint ob_index = 0; ob_index < objects_len; ob_index++) {
Object *obedit = objects[ob_index];
BMEditMesh *em = BKE_editmesh_from_object(obedit);
- if (em->bm->totedgesel == 0) {
- continue;
- }
-
- if (!EDBM_op_call_and_selectf(
- em, op, "edges.out", false, "split_edges edges=%he", BM_ELEM_SELECT)) {
- continue;
- }
- if (em->selectmode == SCE_SELECT_FACE) {
- EDBM_select_flush(em);
+ switch (type) {
+ case BM_VERT:
+ if (!edbm_edge_split_selected_verts(op, obedit, em)) {
+ continue;
+ }
+ break;
+ case BM_EDGE:
+ if (!edbm_edge_split_selected_edges(op, obedit, em)) {
+ continue;
+ }
+ break;
+ default:
+ BLI_assert(0);
}
-
- EDBM_update_generic(obedit->data, true, true);
}
MEM_freeN(objects);
@@ -1813,6 +1874,20 @@ void MESH_OT_edge_split(wmOperatorType *ot)
/* flags */
ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
+
+ /* properties */
+ static const EnumPropertyItem merge_type_items[] = {
+ {BM_EDGE, "EDGE", 0, "Faces by Edges", "Split faces along selected edges"},
+ {BM_VERT,
+ "VERT",
+ 0,
+ "Faces & Edges by Vertices",
+ "Split faces & edges connected to selected vertices"},
+ {0, NULL, 0, NULL, NULL},
+ };
+
+ ot->prop = RNA_def_enum(
+ ot->srna, "type", merge_type_items, BM_EDGE, "Type", "Method to use for splitting");
}
/** \} */
@@ -1895,6 +1970,84 @@ void MESH_OT_duplicate(wmOperatorType *ot)
RNA_def_int(ot->srna, "mode", TFM_TRANSLATION, 0, INT_MAX, "Mode", "", 0, INT_MAX);
}
+static BMLoopNorEditDataArray *flip_custom_normals_init_data(BMesh *bm)
+{
+ BMLoopNorEditDataArray *lnors_ed_arr = NULL;
+ if (CustomData_has_layer(&bm->ldata, CD_CUSTOMLOOPNORMAL)) {
+ /* The mesh has custom normal data, update these too.
+ * Otherwise they will be left in a mangled state.
+ */
+ BM_lnorspace_update(bm);
+ lnors_ed_arr = BM_loop_normal_editdata_array_init(bm, true);
+ }
+
+ return lnors_ed_arr;
+}
+
+static bool flip_custom_normals(BMesh *bm, BMLoopNorEditDataArray *lnors_ed_arr)
+{
+ if (!lnors_ed_arr) {
+ return false;
+ }
+
+ if (lnors_ed_arr->totloop == 0) {
+ /* No loops normals to flip, exit early! */
+ return false;
+ }
+
+ bm->spacearr_dirty |= BM_SPACEARR_DIRTY_ALL;
+ BM_lnorspace_update(bm);
+
+ /* We need to recreate the custom normal array because the clnors_data will
+ * be mangled because we swapped the loops around when we flipped the faces. */
+ BMLoopNorEditDataArray *lnors_ed_arr_new_full = BM_loop_normal_editdata_array_init(bm, true);
+
+ {
+ /* We need to recalculate all loop normals in the affected area. Even the ones that are not
+ * going to be flipped because the clnors data is mangled. */
+
+ BMLoopNorEditData *lnor_ed_new_full = lnors_ed_arr_new_full->lnor_editdata;
+ for (int i = 0; i < lnors_ed_arr_new_full->totloop; i++, lnor_ed_new_full++) {
+
+ BMLoopNorEditData *lnor_ed =
+ lnors_ed_arr->lidx_to_lnor_editdata[lnor_ed_new_full->loop_index];
+
+ BLI_assert(lnor_ed != NULL);
+
+ BKE_lnor_space_custom_normal_to_data(
+ bm->lnor_spacearr->lspacearr[lnor_ed_new_full->loop_index],
+ lnor_ed->nloc,
+ lnor_ed_new_full->clnors_data);
+ }
+ }
+
+ BMFace *f;
+ BMLoop *l;
+ BMIter iter_f, iter_l;
+ BM_ITER_MESH (f, &iter_f, bm, BM_FACES_OF_MESH) {
+ if (!BM_elem_flag_test(f, BM_ELEM_SELECT)) {
+ continue;
+ }
+ /* Flip all the custom loop normals on the selected faces. */
+
+ BM_ITER_ELEM (l, &iter_l, f, BM_LOOPS_OF_FACE) {
+
+ int loop_index = BM_elem_index_get(l);
+
+ BMLoopNorEditData *lnor_ed = lnors_ed_arr->lidx_to_lnor_editdata[loop_index];
+ BMLoopNorEditData *lnor_ed_new = lnors_ed_arr_new_full->lidx_to_lnor_editdata[loop_index];
+ BLI_assert(lnor_ed != NULL && lnor_ed_new != NULL);
+
+ negate_v3(lnor_ed->nloc);
+
+ BKE_lnor_space_custom_normal_to_data(
+ bm->lnor_spacearr->lspacearr[loop_index], lnor_ed->nloc, lnor_ed_new->clnors_data);
+ }
+ }
+ BM_loop_normal_editdata_array_free(lnors_ed_arr_new_full);
+ return true;
+}
+
/** \} */
/* -------------------------------------------------------------------- */
@@ -1902,6 +2055,8 @@ void MESH_OT_duplicate(wmOperatorType *ot)
* \{ */
static int edbm_flip_normals_exec(bContext *C, wmOperator *op)
{
+ const bool only_clnors = RNA_boolean_get(op->ptr, "only_clnors");
+
ViewLayer *view_layer = CTX_data_view_layer(C);
uint objects_len = 0;
Object **objects = BKE_view_layer_array_from_objects_in_edit_mode_unique_data(
@@ -1911,15 +2066,48 @@ static int edbm_flip_normals_exec(bContext *C, wmOperator *op)
Object *obedit = objects[ob_index];
BMEditMesh *em = BKE_editmesh_from_object(obedit);
- if (em->bm->totfacesel == 0) {
+ if (only_clnors) {
+ if (CustomData_has_layer(&em->bm->ldata, CD_CUSTOMLOOPNORMAL)) {
+ /* The mesh has custom normal data, flip them. */
+ BMesh *bm = em->bm;
+
+ BM_lnorspace_update(bm);
+ BMLoopNorEditDataArray *lnors_ed_arr = BM_loop_normal_editdata_array_init(bm, false);
+ BMLoopNorEditData *lnor_ed = lnors_ed_arr->lnor_editdata;
+
+ for (int i = 0; i < lnors_ed_arr->totloop; i++, lnor_ed++) {
+ negate_v3(lnor_ed->nloc);
+
+ BKE_lnor_space_custom_normal_to_data(bm->lnor_spacearr->lspacearr[lnor_ed->loop_index],
+ lnor_ed->nloc,
+ lnor_ed->clnors_data);
+ }
+ BM_loop_normal_editdata_array_free(lnors_ed_arr);
+ EDBM_update_generic(obedit->data, true, false);
+ }
continue;
}
- if (!EDBM_op_callf(em, op, "reverse_faces faces=%hf flip_multires=%b", BM_ELEM_SELECT, true)) {
+ if (em->bm->totfacesel == 0) {
continue;
}
- EDBM_update_generic(obedit->data, true, false);
+ bool has_flipped_faces = false;
+
+ /* See if we have any custom normals to flip. */
+ BMLoopNorEditDataArray *lnors_ed_arr = flip_custom_normals_init_data(em->bm);
+
+ if (EDBM_op_callf(em, op, "reverse_faces faces=%hf flip_multires=%b", BM_ELEM_SELECT, true)) {
+ has_flipped_faces = true;
+ }
+
+ if (flip_custom_normals(em->bm, lnors_ed_arr) || has_flipped_faces) {
+ EDBM_update_generic(obedit->data, true, false);
+ }
+
+ if (lnors_ed_arr != NULL) {
+ BM_loop_normal_editdata_array_free(lnors_ed_arr);
+ }
}
MEM_freeN(objects);
@@ -1939,6 +2127,12 @@ void MESH_OT_flip_normals(wmOperatorType *ot)
/* flags */
ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
+
+ RNA_def_boolean(ot->srna,
+ "only_clnors",
+ false,
+ "Custom Normals Only",
+ "Only flip the custom loop normals of the selected elements");
}
/** \} */
@@ -2201,6 +2395,7 @@ void MESH_OT_reveal(wmOperatorType *ot)
static int edbm_normals_make_consistent_exec(bContext *C, wmOperator *op)
{
ViewLayer *view_layer = CTX_data_view_layer(C);
+ const bool inside = RNA_boolean_get(op->ptr, "inside");
uint objects_len = 0;
Object **objects = BKE_view_layer_array_from_objects_in_edit_mode_unique_data(
@@ -2213,11 +2408,23 @@ static int edbm_normals_make_consistent_exec(bContext *C, wmOperator *op)
continue;
}
+ BMLoopNorEditDataArray *lnors_ed_arr = NULL;
+
+ if (inside) {
+ /* Save custom normal data for later so we can flip them correctly. */
+ lnors_ed_arr = flip_custom_normals_init_data(em->bm);
+ }
+
if (!EDBM_op_callf(em, op, "recalc_face_normals faces=%hf", BM_ELEM_SELECT)) {
continue;
}
- if (RNA_boolean_get(op->ptr, "inside")) {
+
+ if (inside) {
EDBM_op_callf(em, op, "reverse_faces faces=%hf flip_multires=%b", BM_ELEM_SELECT, true);
+ flip_custom_normals(em->bm, lnors_ed_arr);
+ if (lnors_ed_arr != NULL) {
+ BM_loop_normal_editdata_array_free(lnors_ed_arr);
+ }
}
EDBM_update_generic(obedit->data, true, false);
@@ -3108,7 +3315,7 @@ void MESH_OT_merge(wmOperatorType *ot)
/** \} */
/* -------------------------------------------------------------------- */
-/** \name Remove Doubles Operator
+/** \name Merge By Distance Operator
* \{ */
static int edbm_remove_doubles_exec(bContext *C, wmOperator *op)
@@ -4330,6 +4537,7 @@ static int edbm_separate_exec(bContext *C, wmOperator *op)
/* delay depsgraph recalc until all objects are duplicated */
DEG_relations_tag_update(bmain);
WM_event_add_notifier(C, NC_OBJECT | ND_DRAW, NULL);
+ ED_outliner_select_sync_from_object_tag(C);
return OPERATOR_FINISHED;
}
@@ -4455,7 +4663,7 @@ void MESH_OT_fill(wmOperatorType *ot)
static bool bm_edge_test_fill_grid_cb(BMEdge *e, void *UNUSED(bm_v))
{
- return BM_elem_flag_test_bool(e, BM_ELEM_TAG);
+ return BM_elem_flag_test_bool(e, BM_ELEM_SELECT);
}
static float edbm_fill_grid_vert_tag_angle(BMVert *v)
@@ -4477,7 +4685,7 @@ static float edbm_fill_grid_vert_tag_angle(BMVert *v)
/**
* non-essential utility function to select 2 open edge loops from a closed loop.
*/
-static void edbm_fill_grid_prepare(BMesh *bm, int offset, int *r_span, bool span_calc)
+static bool edbm_fill_grid_prepare(BMesh *bm, int offset, int *span_p, const bool span_calc)
{
/* angle differences below this value are considered 'even'
* in that they shouldn't be used to calculate corners used for the 'span' */
@@ -4485,28 +4693,48 @@ static void edbm_fill_grid_prepare(BMesh *bm, int offset, int *r_span, bool span
BMEdge *e;
BMIter iter;
int count;
- int span = *r_span;
+ int span = *span_p;
ListBase eloops = {NULL};
struct BMEdgeLoopStore *el_store;
// LinkData *el_store;
- /* select -> tag */
+ count = BM_mesh_edgeloops_find(bm, &eloops, bm_edge_test_fill_grid_cb, bm);
+ el_store = eloops.first;
+
+ if (count != 1) {
+ /* Let the operator use the selection flags,
+ * most likely failing with an error in this case. */
+ BM_mesh_edgeloops_free(&eloops);
+ return false;
+ }
+
+ /* Only tag edges that are part of a loop. */
BM_ITER_MESH (e, &iter, bm, BM_EDGES_OF_MESH) {
- BM_elem_flag_set(e, BM_ELEM_TAG, BM_elem_flag_test(e, BM_ELEM_SELECT));
+ BM_elem_flag_disable(e, BM_ELEM_TAG);
+ }
+ const int verts_len = BM_edgeloop_length_get(el_store);
+ const int edges_len = verts_len - (BM_edgeloop_is_closed(el_store) ? 0 : 1);
+ BMEdge **edges = MEM_mallocN(sizeof(*edges) * edges_len, __func__);
+ BM_edgeloop_edges_get(el_store, edges);
+ for (int i = 0; i < edges_len; i++) {
+ BM_elem_flag_enable(edges[i], BM_ELEM_TAG);
}
- count = BM_mesh_edgeloops_find(bm, &eloops, bm_edge_test_fill_grid_cb, bm);
- el_store = eloops.first;
+ if (span_calc) {
+ span = verts_len / 4;
+ }
+ else {
+ span = min_ii(span, (verts_len / 2) - 1);
+ }
+ offset = mod_i(offset, verts_len);
+
+ if ((count == 1) && ((verts_len & 1) == 0) && (verts_len == edges_len)) {
- if (count == 1 && BM_edgeloop_is_closed(el_store) &&
- (BM_edgeloop_length_get(el_store) & 1) == 0) {
/* be clever! detect 2 edge loops from one closed edge loop */
- const int verts_len = BM_edgeloop_length_get(el_store);
ListBase *verts = BM_edgeloop_verts_get(el_store);
BMVert *v_act = BM_mesh_active_vert_get(bm);
LinkData *v_act_link;
- BMEdge **edges = MEM_mallocN(sizeof(*edges) * verts_len, __func__);
int i;
if (v_act && (v_act_link = BLI_findptr(verts, v_act, offsetof(LinkData, data)))) {
@@ -4537,6 +4765,7 @@ static void edbm_fill_grid_prepare(BMesh *bm, int offset, int *r_span, bool span
BLI_listbase_rotate_first(verts, v_act_link);
}
+ /* Run again to update the edge order from the rotated vertex list. */
BM_edgeloop_edges_get(el_store, edges);
if (span_calc) {
@@ -4589,18 +4818,19 @@ static void edbm_fill_grid_prepare(BMesh *bm, int offset, int *r_span, bool span
BM_elem_flag_disable(edges[i], BM_ELEM_TAG);
BM_elem_flag_disable(edges[(verts_len / 2) + i], BM_ELEM_TAG);
}
- MEM_freeN(edges);
}
/* else let the bmesh-operator handle it */
BM_mesh_edgeloops_free(&eloops);
+ MEM_freeN(edges);
- *r_span = span;
+ *span_p = span;
+
+ return true;
}
static int edbm_fill_grid_exec(bContext *C, wmOperator *op)
{
- const bool use_prepare = true;
const bool use_interp_simple = RNA_boolean_get(op->ptr, "use_interp_simple");
ViewLayer *view_layer = CTX_data_view_layer(C);
@@ -4612,6 +4842,7 @@ static int edbm_fill_grid_exec(bContext *C, wmOperator *op)
Object *obedit = objects[ob_index];
BMEditMesh *em = BKE_editmesh_from_object(obedit);
+ bool use_prepare = true;
const bool use_smooth = edbm_add_edge_face__smooth_get(em->bm);
const int totedge_orig = em->bm->totedge;
const int totface_orig = em->bm->totface;
@@ -4626,7 +4857,6 @@ static int edbm_fill_grid_exec(bContext *C, wmOperator *op)
PropertyRNA *prop_offset = RNA_struct_find_property(op->ptr, "offset");
bool calc_span;
- const int clamp = em->bm->totvertsel;
int span;
int offset;
@@ -4635,19 +4865,18 @@ static int edbm_fill_grid_exec(bContext *C, wmOperator *op)
if (((op->flag & OP_IS_INVOKE) || (op->flag & OP_IS_REPEAT_LAST) == 0) &&
RNA_property_is_set(op->ptr, prop_span)) {
span = RNA_property_int_get(op->ptr, prop_span);
- span = min_ii(span, (clamp / 2) - 1);
calc_span = false;
}
else {
- span = clamp / 4;
+ /* Will be overwritten if possible. */
+ span = 0;
calc_span = true;
}
offset = RNA_property_int_get(op->ptr, prop_offset);
- offset = clamp ? mod_i(offset, clamp) : 0;
/* in simple cases, move selection for tags, but also support more advanced cases */
- edbm_fill_grid_prepare(em->bm, offset, &span, calc_span);
+ use_prepare = edbm_fill_grid_prepare(em->bm, offset, &span, calc_span);
RNA_property_int_set(op->ptr, prop_span, span);
}
@@ -6020,7 +6249,7 @@ static void sort_bmelem_flag(bContext *C,
const int flag,
const int action,
const int reverse,
- const unsigned int seed)
+ const uint seed)
{
BMEditMesh *em = BKE_editmesh_from_object(ob);
@@ -6033,7 +6262,7 @@ static void sort_bmelem_flag(bContext *C,
/* Just to mark protected elements. */
char *pblock[3] = {NULL, NULL, NULL}, *pb;
BMElemSort *sblock[3] = {NULL, NULL, NULL}, *sb;
- unsigned int *map[3] = {NULL, NULL, NULL}, *mp;
+ uint *map[3] = {NULL, NULL, NULL}, *mp;
int totelem[3] = {0, 0, 0};
int affected[3] = {0, 0, 0};
int i, j;
@@ -6210,7 +6439,7 @@ static void sort_bmelem_flag(bContext *C,
}
else if (action == SRT_SELECTED) {
- unsigned int *tbuf[3] = {NULL, NULL, NULL}, *tb;
+ uint *tbuf[3] = {NULL, NULL, NULL}, *tb;
if (totelem[0]) {
tb = tbuf[0] = MEM_callocN(sizeof(int) * totelem[0], "sort_bmelem vert tbuf");
@@ -6474,7 +6703,7 @@ static int edbm_sort_elements_exec(bContext *C, wmOperator *op)
const int action = RNA_enum_get(op->ptr, "type");
PropertyRNA *prop_elem_types = RNA_struct_find_property(op->ptr, "elements");
const bool use_reverse = RNA_boolean_get(op->ptr, "reverse");
- unsigned int seed = RNA_int_get(op->ptr, "seed");
+ uint seed = RNA_int_get(op->ptr, "seed");
int elem_types = 0;
if (ELEM(action, SRT_VIEW_ZAXIS, SRT_VIEW_XAXIS)) {
@@ -6984,37 +7213,17 @@ void MESH_OT_wireframe(wmOperatorType *ot)
static int edbm_offset_edgeloop_exec(bContext *C, wmOperator *op)
{
- bool mode_change = false;
const bool use_cap_endpoint = RNA_boolean_get(op->ptr, "use_cap_endpoint");
- int ret = OPERATOR_CANCELLED;
-
- {
- Object *obedit = CTX_data_edit_object(C);
- BMEditMesh *em = BKE_editmesh_from_object(obedit);
- if (em->selectmode == SCE_SELECT_FACE) {
- EDBM_selectmode_to_scene(C);
- mode_change = true;
- }
- }
-
+ bool changed_multi = false;
+ Scene *scene = CTX_data_scene(C);
ViewLayer *view_layer = CTX_data_view_layer(C);
- uint objects_len = 0;
- Object **objects = BKE_view_layer_array_from_objects_in_edit_mode_unique_data(
- view_layer, CTX_wm_view3d(C), &objects_len);
- for (uint ob_index = 0; ob_index < objects_len; ob_index++) {
- Object *obedit = objects[ob_index];
+ uint bases_len = 0;
+ Base **bases = BKE_view_layer_array_from_bases_in_edit_mode_unique_data(
+ view_layer, CTX_wm_view3d(C), &bases_len);
+ for (uint base_index = 0; base_index < bases_len; base_index++) {
+ Object *obedit = bases[base_index]->object;
BMEditMesh *em = BKE_editmesh_from_object(obedit);
- /** If in face-only select mode, switch to edge select mode so that
- * an edge-only selection is not inconsistent state.
- *
- * We need to run this for all objects, even when nothing is selected.
- * This way we keep them in sync. */
- if (mode_change) {
- em->selectmode = SCE_SELECT_EDGE;
- EDBM_selectmode_set(em);
- }
-
if (em->bm->totedgesel == 0) {
continue;
}
@@ -7034,16 +7243,26 @@ static int edbm_offset_edgeloop_exec(bContext *C, wmOperator *op)
BMO_slot_buffer_hflag_enable(
em->bm, bmop.slots_out, "edges.out", BM_EDGE, BM_ELEM_SELECT, true);
- if (!EDBM_op_finish(em, &bmop, op, true)) {
- continue;
- }
- else {
+ if (EDBM_op_finish(em, &bmop, op, true)) {
EDBM_update_generic(obedit->data, true, true);
- ret = OPERATOR_FINISHED;
+ changed_multi = true;
}
}
- MEM_freeN(objects);
- return ret;
+
+ if (changed_multi) {
+ /** If in face-only select mode, switch to edge select mode so that
+ * an edge-only selection is not inconsistent state.
+ *
+ * We need to run this for all objects, even when nothing is selected.
+ * This way we keep them in sync. */
+ if (scene->toolsettings->selectmode == SCE_SELECT_FACE) {
+ EDBM_selectmode_disable_multi_ex(scene, bases, bases_len, SCE_SELECT_FACE, SCE_SELECT_EDGE);
+ }
+ }
+
+ MEM_freeN(bases);
+
+ return changed_multi ? OPERATOR_FINISHED : OPERATOR_CANCELLED;
}
void MESH_OT_offset_edge_loops(wmOperatorType *ot)
@@ -7694,14 +7913,14 @@ wmKeyMap *point_normals_modal_keymap(wmKeyConfig *keyconf)
};
static const char *keymap_name = "Custom Normals Modal Map";
- wmKeyMap *keymap = WM_modalkeymap_get(keyconf, keymap_name);
+ wmKeyMap *keymap = WM_modalkeymap_find(keyconf, keymap_name);
/* We only need to add map once */
if (keymap && keymap->modal_items) {
return NULL;
}
- keymap = WM_modalkeymap_add(keyconf, keymap_name, modal_items);
+ keymap = WM_modalkeymap_ensure(keyconf, keymap_name, modal_items);
WM_modalkeymap_assign(keymap, "MESH_OT_point_normals");
@@ -7710,7 +7929,11 @@ wmKeyMap *point_normals_modal_keymap(wmKeyConfig *keyconf)
#define CLNORS_VALID_VEC_LEN (1e-4f)
-/********************** 'Point to' Loop Normals **********************/
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Loop Normals 'Point To' Operator
+ * \{ */
enum {
EDBM_CLNOR_POINTTO_MODE_COORDINATES = 1,
@@ -7728,7 +7951,7 @@ static EnumPropertyItem clnors_pointto_mode_items[] = {
};
/* Initialize loop normal data */
-static int point_normals_init(bContext *C, wmOperator *op, const wmEvent *UNUSED(event))
+static bool point_normals_init(bContext *C, wmOperator *op)
{
Object *obedit = CTX_data_edit_object(C);
BMEditMesh *em = BKE_editmesh_from_object(obedit);
@@ -7740,14 +7963,29 @@ static int point_normals_init(bContext *C, wmOperator *op, const wmEvent *UNUSED
op->customdata = lnors_ed_arr;
- return lnors_ed_arr->totloop;
+ return (lnors_ed_arr->totloop != 0);
}
-static void point_normals_free(bContext *C, wmOperator *op)
+static bool point_normals_ensure(bContext *C, wmOperator *op)
{
- BMLoopNorEditDataArray *lnors_ed_arr = op->customdata;
- BM_loop_normal_editdata_array_free(lnors_ed_arr);
- op->customdata = NULL;
+ if (op->customdata != NULL) {
+ return true;
+ }
+ return point_normals_init(C, op);
+}
+
+static void point_normals_free(wmOperator *op)
+{
+ if (op->customdata != NULL) {
+ BMLoopNorEditDataArray *lnors_ed_arr = op->customdata;
+ BM_loop_normal_editdata_array_free(lnors_ed_arr);
+ op->customdata = NULL;
+ }
+}
+
+static void point_normals_cancel(bContext *C, wmOperator *op)
+{
+ point_normals_free(op);
ED_area_status_text(CTX_wm_area(C), NULL);
}
@@ -7864,6 +8102,13 @@ static void point_normals_apply(bContext *C, wmOperator *op, float target[3], co
static int edbm_point_normals_modal(bContext *C, wmOperator *op, const wmEvent *event)
{
+ /* As this operator passes events through, we can't be sure the user didn't exit edit-mode.
+ * or performed some other operation. */
+ if (!WM_operator_poll(C, op->type)) {
+ point_normals_cancel(C, op);
+ return OPERATOR_CANCELLED;
+ }
+
View3D *v3d = CTX_wm_view3d(C);
Scene *scene = CTX_data_scene(C);
Object *obedit = CTX_data_edit_object(C);
@@ -8034,23 +8279,37 @@ static int edbm_point_normals_modal(bContext *C, wmOperator *op, const wmEvent *
if (!ELEM(ret, OPERATOR_CANCELLED, OPERATOR_FINISHED)) {
RNA_property_float_set_array(op->ptr, prop_target, target);
}
- point_normals_apply(C, op, target, do_reset);
- EDBM_update_generic(obedit->data, true, false); /* Recheck bools. */
- point_normals_update_header(C, op);
+ if (point_normals_ensure(C, op)) {
+ point_normals_apply(C, op, target, do_reset);
+ EDBM_update_generic(obedit->data, true, false); /* Recheck bools. */
+ point_normals_update_header(C, op);
+ }
+ else {
+ ret = OPERATOR_CANCELLED;
+ }
}
if (ELEM(ret, OPERATOR_CANCELLED, OPERATOR_FINISHED)) {
- point_normals_free(C, op);
+ point_normals_cancel(C, op);
}
+ /* If we allow other tools to run, we can't be sure if they will re-allocate
+ * the data this operator uses, see: T68159.
+ * Free the data here, then use #point_normals_ensure to add it back on demand. */
+ if (ret == OPERATOR_PASS_THROUGH) {
+ /* Don't free on mouse-move, causes creation/freeing of the loop data in an inefficient way. */
+ if (!ELEM(event->type, MOUSEMOVE, INBETWEEN_MOUSEMOVE)) {
+ point_normals_free(op);
+ }
+ }
return ret;
}
-static int edbm_point_normals_invoke(bContext *C, wmOperator *op, const wmEvent *event)
+static int edbm_point_normals_invoke(bContext *C, wmOperator *op, const wmEvent *UNUSED(event))
{
- if (!point_normals_init(C, op, event)) {
- point_normals_free(C, op);
+ if (!point_normals_init(C, op)) {
+ point_normals_cancel(C, op);
return OPERATOR_CANCELLED;
}
@@ -8067,8 +8326,8 @@ static int edbm_point_normals_exec(bContext *C, wmOperator *op)
{
Object *obedit = CTX_data_edit_object(C);
- if (!point_normals_init(C, op, NULL)) {
- point_normals_free(C, op);
+ if (!point_normals_init(C, op)) {
+ point_normals_cancel(C, op);
return OPERATOR_CANCELLED;
}
@@ -8081,7 +8340,7 @@ static int edbm_point_normals_exec(bContext *C, wmOperator *op)
point_normals_apply(C, op, target, false);
EDBM_update_generic(obedit->data, true, false);
- point_normals_free(C, op);
+ point_normals_cancel(C, op);
return OPERATOR_FINISHED;
}
@@ -8126,7 +8385,7 @@ void MESH_OT_point_normals(struct wmOperatorType *ot)
ot->modal = edbm_point_normals_modal;
ot->poll = ED_operator_editmesh;
ot->ui = edbm_point_normals_ui;
- ot->cancel = point_normals_free;
+ ot->cancel = point_normals_cancel;
/* flags */
ot->flag = OPTYPE_BLOCKING | OPTYPE_REGISTER | OPTYPE_UNDO;
@@ -8171,7 +8430,7 @@ void MESH_OT_point_normals(struct wmOperatorType *ot)
/** \} */
/* -------------------------------------------------------------------- */
-/** \name Split/Merge Loop Normals
+/** \name Split/Merge Loop Normals Operator
* \{ */
static void normals_merge(BMesh *bm, BMLoopNorEditDataArray *lnors_ed_arr)
@@ -8185,6 +8444,8 @@ static void normals_merge(BMesh *bm, BMLoopNorEditDataArray *lnors_ed_arr)
BM_normals_loops_edges_tag(bm, false);
for (int i = 0; i < lnors_ed_arr->totloop; i++, lnor_ed++) {
+ BLI_assert(BLI_SMALLSTACK_IS_EMPTY(clnors));
+
if (BM_elem_flag_test(lnor_ed->loop, BM_ELEM_TAG)) {
continue;
}
@@ -8227,8 +8488,12 @@ static void normals_split(BMesh *bm)
BM_normals_loops_edges_tag(bm, true);
+ BLI_SMALLSTACK_DECLARE(loop_stack, BMLoop *);
+
const int cd_clnors_offset = CustomData_get_offset(&bm->ldata, CD_CUSTOMLOOPNORMAL);
BM_ITER_MESH (f, &fiter, bm, BM_FACES_OF_MESH) {
+ BLI_assert(BLI_SMALLSTACK_IS_EMPTY(loop_stack));
+
l_curr = l_first = BM_FACE_FIRST_LOOP(f);
do {
if (BM_elem_flag_test(l_curr->v, BM_ELEM_SELECT) &&
@@ -8250,7 +8515,6 @@ static void normals_split(BMesh *bm)
lfan_pivot = l_curr;
e_next = lfan_pivot->e;
- BLI_SMALLSTACK_DECLARE(loops, BMLoop *);
float avg_normal[3] = {0.0f};
while (true) {
@@ -8262,7 +8526,7 @@ static void normals_split(BMesh *bm)
e_next = (lfan_pivot->e == e_next) ? lfan_pivot->prev->e : lfan_pivot->e;
}
- BLI_SMALLSTACK_PUSH(loops, lfan_pivot);
+ BLI_SMALLSTACK_PUSH(loop_stack, lfan_pivot);
add_v3_v3(avg_normal, lfan_pivot->f->no);
if (!BM_elem_flag_test(e_next, BM_ELEM_TAG) || (e_next == e_org)) {
@@ -8274,7 +8538,7 @@ static void normals_split(BMesh *bm)
/* If avg normal is nearly 0, set clnor to default value. */
zero_v3(avg_normal);
}
- while ((l = BLI_SMALLSTACK_POP(loops))) {
+ while ((l = BLI_SMALLSTACK_POP(loop_stack))) {
const int l_index = BM_elem_index_get(l);
short *clnors = BM_ELEM_CD_GET_VOID_P(l, cd_clnors_offset);
BKE_lnor_space_custom_normal_to_data(
@@ -8382,7 +8646,7 @@ void MESH_OT_split_normals(struct wmOperatorType *ot)
/** \} */
/* -------------------------------------------------------------------- */
-/** \name Average Loop Normals
+/** \name Average Loop Normals Operator
* \{ */
enum {
@@ -8416,7 +8680,13 @@ static int edbm_average_normals_exec(bContext *C, wmOperator *op)
const float absweight = (float)RNA_int_get(op->ptr, "weight");
const float threshold = RNA_float_get(op->ptr, "threshold");
+ HeapSimple *loop_weight = BLI_heapsimple_new();
+ BLI_SMALLSTACK_DECLARE(loop_stack, BMLoop *);
+
for (uint ob_index = 0; ob_index < objects_len; ob_index++) {
+ BLI_assert(BLI_SMALLSTACK_IS_EMPTY(loop_stack));
+ BLI_assert(BLI_heapsimple_is_empty(loop_weight));
+
Object *obedit = objects[ob_index];
BMEditMesh *em = BKE_editmesh_from_object(obedit);
BMesh *bm = em->bm;
@@ -8443,8 +8713,6 @@ static int edbm_average_normals_exec(bContext *C, wmOperator *op)
BM_normals_loops_edges_tag(bm, true);
- HeapSimple *loop_weight = BLI_heapsimple_new();
-
BM_ITER_MESH (f, &fiter, bm, BM_FACES_OF_MESH) {
l_curr = l_first = BM_FACE_FIRST_LOOP(f);
do {
@@ -8494,7 +8762,6 @@ static int edbm_average_normals_exec(bContext *C, wmOperator *op)
lfan_pivot = lfan_pivot_next;
}
- BLI_SMALLSTACK_DECLARE(loops, BMLoop *);
float wnor[3], avg_normal[3] = {0.0f}, count = 0;
float val = BLI_heapsimple_top_value(loop_weight);
@@ -8505,7 +8772,7 @@ static int edbm_average_normals_exec(bContext *C, wmOperator *op)
val = cur_val;
}
l = BLI_heapsimple_pop_min(loop_weight);
- BLI_SMALLSTACK_PUSH(loops, l);
+ BLI_SMALLSTACK_PUSH(loop_stack, l);
const float n_weight = pow(weight, count);
@@ -8526,7 +8793,7 @@ static int edbm_average_normals_exec(bContext *C, wmOperator *op)
/* If avg normal is nearly 0, set clnor to default value. */
zero_v3(avg_normal);
}
- while ((l = BLI_SMALLSTACK_POP(loops))) {
+ while ((l = BLI_SMALLSTACK_POP(loop_stack))) {
const int l_index = BM_elem_index_get(l);
short *clnors = BM_ELEM_CD_GET_VOID_P(l, cd_clnors_offset);
BKE_lnor_space_custom_normal_to_data(
@@ -8537,10 +8804,11 @@ static int edbm_average_normals_exec(bContext *C, wmOperator *op)
} while ((l_curr = l_curr->next) != l_first);
}
- BLI_heapsimple_free(loop_weight, NULL);
EDBM_update_generic(obedit->data, true, false);
}
+ BLI_heapsimple_free(loop_weight, NULL);
+
MEM_freeN(objects);
return OPERATOR_FINISHED;
}
@@ -8614,7 +8882,7 @@ void MESH_OT_average_normals(struct wmOperatorType *ot)
/** \} */
/* -------------------------------------------------------------------- */
-/** \name Custom Normal Interface Tools
+/** \name Custom Normal Interface Tools Operator
* \{ */
enum {
@@ -8850,6 +9118,12 @@ void MESH_OT_normals_tools(struct wmOperatorType *ot)
"Copy Absolute coordinates or Normal vector");
}
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Set Normals from Faces Operator
+ * \{ */
+
static int edbm_set_normals_from_faces_exec(bContext *C, wmOperator *op)
{
ViewLayer *view_layer = CTX_data_view_layer(C);
@@ -8957,7 +9231,13 @@ void MESH_OT_set_normals_from_faces(struct wmOperatorType *ot)
RNA_def_boolean(ot->srna, "keep_sharp", 0, "Keep Sharp Edges", "Do not set sharp edges to face");
}
-static int edbm_smoothen_normals_exec(bContext *C, wmOperator *op)
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Smooth Normal Vectors Operator
+ * \{ */
+
+static int edbm_smooth_normals_exec(bContext *C, wmOperator *op)
{
ViewLayer *view_layer = CTX_data_view_layer(C);
uint objects_len = 0;
@@ -9010,7 +9290,7 @@ static int edbm_smoothen_normals_exec(bContext *C, wmOperator *op)
float current_normal[3];
if (normalize_v3(smooth_normal[i]) < CLNORS_VALID_VEC_LEN) {
- /* Skip in case smoothen normal is invalid... */
+ /* Skip in case the smooth normal is invalid. */
continue;
}
@@ -9024,7 +9304,7 @@ static int edbm_smoothen_normals_exec(bContext *C, wmOperator *op)
add_v3_v3(current_normal, smooth_normal[i]);
if (normalize_v3(current_normal) < CLNORS_VALID_VEC_LEN) {
- /* Skip in case smoothen normal is invalid... */
+ /* Skip in case the smoothed normal is invalid. */
continue;
}
@@ -9042,15 +9322,15 @@ static int edbm_smoothen_normals_exec(bContext *C, wmOperator *op)
return OPERATOR_FINISHED;
}
-void MESH_OT_smoothen_normals(struct wmOperatorType *ot)
+void MESH_OT_smooth_normals(struct wmOperatorType *ot)
{
/* identifiers */
ot->name = "Smooth Normals Vectors";
- ot->description = "Smoothen custom normals based on adjacent vertex normals";
- ot->idname = "MESH_OT_smoothen_normals";
+ ot->description = "Smooth custom normals based on adjacent vertex normals";
+ ot->idname = "MESH_OT_smooth_normals";
/* api callbacks */
- ot->exec = edbm_smoothen_normals_exec;
+ ot->exec = edbm_smooth_normals_exec;
ot->poll = ED_operator_editmesh;
/* flags */
diff --git a/source/blender/editors/mesh/editmesh_undo.c b/source/blender/editors/mesh/editmesh_undo.c
index 1f857ad4710..e4ecfa9c680 100644
--- a/source/blender/editors/mesh/editmesh_undo.c
+++ b/source/blender/editors/mesh/editmesh_undo.c
@@ -397,9 +397,7 @@ struct UMArrayData {
UndoMesh *um;
const UndoMesh *um_ref; /* can be NULL */
};
-static void um_arraystore_compact_cb(TaskPool *__restrict UNUSED(pool),
- void *taskdata,
- int UNUSED(threadid))
+static void um_arraystore_compact_cb(TaskPool *__restrict UNUSED(pool), void *taskdata)
{
struct UMArrayData *um_data = taskdata;
um_arraystore_compact_with_info(um_data->um, um_data->um_ref);
@@ -541,16 +539,14 @@ static void *undomesh_from_editmesh(UndoMesh *um, BMEditMesh *em, Key *key)
# ifdef USE_ARRAY_STORE_THREAD
if (um_arraystore.task_pool == NULL) {
- TaskScheduler *scheduler = BLI_task_scheduler_get();
- um_arraystore.task_pool = BLI_task_pool_create_background(scheduler, NULL);
+ um_arraystore.task_pool = BLI_task_pool_create_background(NULL, TASK_PRIORITY_LOW);
}
struct UMArrayData *um_data = MEM_mallocN(sizeof(*um_data), __func__);
um_data->um = um;
um_data->um_ref = um_ref;
- BLI_task_pool_push(
- um_arraystore.task_pool, um_arraystore_compact_cb, um_data, true, TASK_PRIORITY_LOW);
+ BLI_task_pool_push(um_arraystore.task_pool, um_arraystore_compact_cb, um_data, true, NULL);
# else
um_arraystore_compact_with_info(um, um_ref);
# endif
diff --git a/source/blender/editors/mesh/editmesh_utils.c b/source/blender/editors/mesh/editmesh_utils.c
index f44a94a63f8..b5346a9061a 100644
--- a/source/blender/editors/mesh/editmesh_utils.c
+++ b/source/blender/editors/mesh/editmesh_utils.c
@@ -52,6 +52,7 @@
#include "ED_mesh.h"
#include "ED_screen.h"
+#include "ED_transform_snap_object_context.h"
#include "ED_uvedit.h"
#include "ED_view3d.h"
@@ -370,8 +371,7 @@ void EDBM_mesh_load_ex(Main *bmain, Object *ob, bool free_data)
* cycles.
*/
#if 0
- for (Object *other_object = bmain->objects.first; other_object != NULL;
- other_object = other_object->id.next) {
+ for (Object *other_object = bmain->objects.first; other_object != NULL; other_object = other_object->id.next) {
if (other_object->data == ob->data) {
BKE_object_free_derived_caches(other_object);
}
@@ -406,10 +406,10 @@ void EDBM_mesh_load(Main *bmain, Object *ob)
void EDBM_mesh_free(BMEditMesh *em)
{
/* These tables aren't used yet, so it's not strictly necessary
- * to 'end' them (with 'e' param) but if someone tries to start
- * using them, having these in place will save a lot of pain */
- ED_mesh_mirror_spatial_table(NULL, NULL, NULL, NULL, 'e');
- ED_mesh_mirror_topo_table(NULL, NULL, 'e');
+ * to 'end' them but if someone tries to start using them,
+ * having these in place will save a lot of pain. */
+ ED_mesh_mirror_spatial_table_end(NULL);
+ ED_mesh_mirror_topo_table_end(NULL);
BKE_editmesh_free(em);
}
@@ -539,7 +539,7 @@ UvVertMap *BM_uv_vert_map_create(BMesh *bm,
UvVertMap *vmap;
UvMapVert *buf;
MLoopUV *luv;
- unsigned int a;
+ uint a;
int totverts, i, totuv, totfaces;
const int cd_loop_uv_offset = CustomData_get_offset(&bm->ldata, CD_MLOOPUV);
bool *winding = NULL;
@@ -669,7 +669,7 @@ UvVertMap *BM_uv_vert_map_create(BMesh *bm,
return vmap;
}
-UvMapVert *BM_uv_vert_map_at_index(UvVertMap *vmap, unsigned int v)
+UvMapVert *BM_uv_vert_map_at_index(UvVertMap *vmap, uint v)
{
return vmap->vert[v];
}
@@ -832,7 +832,7 @@ UvElementMap *BM_uv_element_map_create(BMesh *bm,
}
if (do_islands) {
- unsigned int *map;
+ uint *map;
BMFace **stack;
int stacksize = 0;
UvElement *islandbuf;
@@ -1224,7 +1224,7 @@ BMFace *EDBM_verts_mirror_get_face(BMEditMesh *em, BMFace *f)
BMVert **v_mirr_arr = BLI_array_alloca(v_mirr_arr, f->len);
BMLoop *l_iter, *l_first;
- unsigned int i = 0;
+ uint i = 0;
l_iter = l_first = BM_FACE_FIRST_LOOP(f);
do {
@@ -1639,3 +1639,47 @@ bool BMBVH_EdgeVisible(struct BMBVHTree *tree,
}
/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name BMesh Vertex Projection API
+ * \{ */
+
+void EDBM_project_snap_verts(
+ bContext *C, Depsgraph *depsgraph, ARegion *region, Object *obedit, BMEditMesh *em)
+{
+ BMIter iter;
+ BMVert *eve;
+
+ ED_view3d_init_mats_rv3d(obedit, region->regiondata);
+
+ struct SnapObjectContext *snap_context = ED_transform_snap_object_context_create_view3d(
+ CTX_data_scene(C), 0, region, CTX_wm_view3d(C));
+
+ BM_ITER_MESH (eve, &iter, em->bm, BM_VERTS_OF_MESH) {
+ if (BM_elem_flag_test(eve, BM_ELEM_SELECT)) {
+ float mval[2], co_proj[3];
+ if (ED_view3d_project_float_object(region, eve->co, mval, V3D_PROJ_TEST_NOP) ==
+ V3D_PROJ_RET_OK) {
+ if (ED_transform_snap_object_project_view3d(snap_context,
+ depsgraph,
+ SCE_SNAP_MODE_FACE,
+ &(const struct SnapObjectParams){
+ .snap_select = SNAP_NOT_ACTIVE,
+ .use_object_edit_cage = false,
+ .use_occlusion_test = true,
+ },
+ mval,
+ NULL,
+ NULL,
+ co_proj,
+ NULL)) {
+ mul_v3_m4v3(eve->co, obedit->imat, co_proj);
+ }
+ }
+ }
+ }
+
+ ED_transform_snap_object_context_destroy(snap_context);
+}
+
+/** \} */
diff --git a/source/blender/editors/mesh/mesh_intern.h b/source/blender/editors/mesh/mesh_intern.h
index 594429d4925..5e70069456b 100644
--- a/source/blender/editors/mesh/mesh_intern.h
+++ b/source/blender/editors/mesh/mesh_intern.h
@@ -248,7 +248,7 @@ void MESH_OT_split_normals(struct wmOperatorType *ot);
void MESH_OT_normals_tools(struct wmOperatorType *ot);
void MESH_OT_set_normals_from_faces(struct wmOperatorType *ot);
void MESH_OT_average_normals(struct wmOperatorType *ot);
-void MESH_OT_smoothen_normals(struct wmOperatorType *ot);
+void MESH_OT_smooth_normals(struct wmOperatorType *ot);
void MESH_OT_mod_weighted_strength(struct wmOperatorType *ot);
/* *** editmesh_mask_extract.c *** */
diff --git a/source/blender/editors/mesh/mesh_mirror.c b/source/blender/editors/mesh/mesh_mirror.c
index 9b599d8df7f..0bbc8b0df76 100644
--- a/source/blender/editors/mesh/mesh_mirror.c
+++ b/source/blender/editors/mesh/mesh_mirror.c
@@ -44,73 +44,71 @@ static struct {
void *tree;
} MirrKdStore = {NULL};
-/* mode is 's' start, or 'e' end, or 'u' use */
-/* if end, ob can be NULL */
-int ED_mesh_mirror_spatial_table(
- Object *ob, BMEditMesh *em, Mesh *me_eval, const float co[3], char mode)
+void ED_mesh_mirror_spatial_table_begin(Object *ob, BMEditMesh *em, Mesh *me_eval)
{
- if (mode == 'u') { /* use table */
- if (MirrKdStore.tree == NULL) {
- ED_mesh_mirror_spatial_table(ob, em, me_eval, NULL, 's');
- }
-
- if (MirrKdStore.tree) {
- KDTreeNearest_3d nearest;
- const int i = BLI_kdtree_3d_find_nearest(MirrKdStore.tree, co, &nearest);
+ Mesh *me = ob->data;
+ const bool use_em = (!me_eval && em && me->edit_mesh == em);
+ const int totvert = use_em ? em->bm->totvert : me_eval ? me_eval->totvert : me->totvert;
- if (i != -1) {
- if (nearest.dist < KD_THRESH) {
- return i;
- }
- }
- }
- return -1;
+ if (MirrKdStore.tree) { /* happens when entering this call without ending it */
+ ED_mesh_mirror_spatial_table_end(ob);
}
- else if (mode == 's') { /* start table */
- Mesh *me = ob->data;
- const bool use_em = (!me_eval && em && me->edit_mesh == em);
- const int totvert = use_em ? em->bm->totvert : me_eval ? me_eval->totvert : me->totvert;
-
- if (MirrKdStore.tree) { /* happens when entering this call without ending it */
- ED_mesh_mirror_spatial_table(ob, em, me_eval, co, 'e');
- }
- MirrKdStore.tree = BLI_kdtree_3d_new(totvert);
+ MirrKdStore.tree = BLI_kdtree_3d_new(totvert);
- if (use_em) {
- BMVert *eve;
- BMIter iter;
- int i;
+ if (use_em) {
+ BMVert *eve;
+ BMIter iter;
+ int i;
- /* this needs to be valid for index lookups later (callers need) */
- BM_mesh_elem_table_ensure(em->bm, BM_VERT);
+ /* this needs to be valid for index lookups later (callers need) */
+ BM_mesh_elem_table_ensure(em->bm, BM_VERT);
- BM_ITER_MESH_INDEX (eve, &iter, em->bm, BM_VERTS_OF_MESH, i) {
- BLI_kdtree_3d_insert(MirrKdStore.tree, i, eve->co);
- }
+ BM_ITER_MESH_INDEX (eve, &iter, em->bm, BM_VERTS_OF_MESH, i) {
+ BLI_kdtree_3d_insert(MirrKdStore.tree, i, eve->co);
}
- else {
- MVert *mvert = me_eval ? me_eval->mvert : me->mvert;
- int i;
+ }
+ else {
+ MVert *mvert = me_eval ? me_eval->mvert : me->mvert;
+ int i;
- for (i = 0; i < totvert; i++, mvert++) {
- BLI_kdtree_3d_insert(MirrKdStore.tree, i, mvert->co);
- }
+ for (i = 0; i < totvert; i++, mvert++) {
+ BLI_kdtree_3d_insert(MirrKdStore.tree, i, mvert->co);
}
+ }
+
+ BLI_kdtree_3d_balance(MirrKdStore.tree);
+}
- BLI_kdtree_3d_balance(MirrKdStore.tree);
+int ED_mesh_mirror_spatial_table_lookup(Object *ob,
+ BMEditMesh *em,
+ Mesh *me_eval,
+ const float co[3])
+{
+ if (MirrKdStore.tree == NULL) {
+ ED_mesh_mirror_spatial_table_begin(ob, em, me_eval);
}
- else if (mode == 'e') { /* end table */
- if (MirrKdStore.tree) {
- BLI_kdtree_3d_free(MirrKdStore.tree);
- MirrKdStore.tree = NULL;
+
+ if (MirrKdStore.tree) {
+ KDTreeNearest_3d nearest;
+ const int i = BLI_kdtree_3d_find_nearest(MirrKdStore.tree, co, &nearest);
+
+ if (i != -1) {
+ if (nearest.dist < KD_THRESH) {
+ return i;
+ }
}
}
- else {
- BLI_assert(0);
- }
+ return -1;
+}
- return 0;
+void ED_mesh_mirror_spatial_table_end(Object *UNUSED(ob))
+{
+ /* TODO: store this in object/object-data (keep unused argument for now). */
+ if (MirrKdStore.tree) {
+ BLI_kdtree_3d_free(MirrKdStore.tree);
+ MirrKdStore.tree = NULL;
+ }
}
/** \} */
@@ -119,7 +117,7 @@ int ED_mesh_mirror_spatial_table(
/** \name Mesh Topology Mirror API
* \{ */
-typedef unsigned int MirrTopoHash_t;
+typedef uint MirrTopoHash_t;
typedef struct MirrTopoVert_t {
MirrTopoHash_t hash;
@@ -231,7 +229,7 @@ void ED_mesh_mirrtopo_init(BMEditMesh *em,
medge = me->medge;
for (a = 0, med = medge; a < totedge; a++, med++) {
- const unsigned int i1 = med->v1, i2 = med->v2;
+ const uint i1 = med->v1, i2 = med->v2;
topo_hash[i1]++;
topo_hash[i2]++;
}
@@ -257,7 +255,7 @@ void ED_mesh_mirrtopo_init(BMEditMesh *em,
}
else {
for (a = 0, med = medge; a < totedge; a++, med++) {
- const unsigned int i1 = med->v1, i2 = med->v2;
+ const uint i1 = med->v1, i2 = med->v2;
topo_hash[i1] += topo_hash_prev[i2] * topo_pass;
topo_hash[i2] += topo_hash_prev[i1] * topo_pass;
tot_unique_edges += (topo_hash[i1] != topo_hash[i2]);
diff --git a/source/blender/editors/mesh/mesh_ops.c b/source/blender/editors/mesh/mesh_ops.c
index c61fe39b5fd..c52a5956ac4 100644
--- a/source/blender/editors/mesh/mesh_ops.c
+++ b/source/blender/editors/mesh/mesh_ops.c
@@ -203,7 +203,7 @@ void ED_operatortypes_mesh(void)
WM_operatortype_append(MESH_OT_normals_tools);
WM_operatortype_append(MESH_OT_set_normals_from_faces);
WM_operatortype_append(MESH_OT_average_normals);
- WM_operatortype_append(MESH_OT_smoothen_normals);
+ WM_operatortype_append(MESH_OT_smooth_normals);
WM_operatortype_append(MESH_OT_mod_weighted_strength);
}
@@ -277,6 +277,18 @@ void ED_operatormacros_mesh(void)
RNA_boolean_set(otmacro->ptr, "use_proportional_edit", false);
RNA_boolean_set(otmacro->ptr, "mirror", false);
+ ot = WM_operatortype_append_macro(
+ "MESH_OT_extrude_region_dissolve_move_intersect",
+ "Extrude, Dissolve, Move and Intersect",
+ "Extrude, dissolves edges whose faces form a flat surface and intersect new edges",
+ OPTYPE_UNDO | OPTYPE_REGISTER);
+ otmacro = WM_operatortype_macro_define(ot, "MESH_OT_extrude_region");
+ RNA_boolean_set(otmacro->ptr, "use_dissolve_ortho_edges", true);
+ otmacro = WM_operatortype_macro_define(ot, "TRANSFORM_OT_translate");
+ RNA_boolean_set(otmacro->ptr, "use_proportional_edit", false);
+ RNA_boolean_set(otmacro->ptr, "mirror", false);
+ RNA_boolean_set(otmacro->ptr, "use_automerge_and_split", true);
+
ot = WM_operatortype_append_macro("MESH_OT_extrude_context_move",
"Extrude Region and Move",
"Extrude region together along the average normal",
diff --git a/source/blender/editors/mesh/meshtools.c b/source/blender/editors/mesh/meshtools.c
index 6c5106d3eec..917bbe61e3d 100644
--- a/source/blender/editors/mesh/meshtools.c
+++ b/source/blender/editors/mesh/meshtools.c
@@ -161,7 +161,7 @@ static void join_mesh_single(Depsgraph *depsgraph,
*/
if (key) {
/* if this mesh has any shapekeys, check first, otherwise just copy coordinates */
- for (KeyBlock *kb = key->block.first; kb; kb = kb->next) {
+ LISTBASE_FOREACH (KeyBlock *, kb, &key->block) {
/* get pointer to where to write data for this mesh in shapekey's data array */
float(*cos)[3] = ((float(*)[3])kb->data) + *vertofs;
@@ -191,7 +191,7 @@ static void join_mesh_single(Depsgraph *depsgraph,
* - otherwise, copy across plain coordinates (no need to transform coordinates)
*/
if (key) {
- for (KeyBlock *kb = key->block.first; kb; kb = kb->next) {
+ LISTBASE_FOREACH (KeyBlock *, kb, &key->block) {
/* get pointer to where to write data for this mesh in shapekey's data array */
float(*cos)[3] = ((float(*)[3])kb->data) + *vertofs;
@@ -314,7 +314,7 @@ int join_mesh_exec(bContext *C, wmOperator *op)
int a, b, totcol, totmat = 0, totedge = 0, totvert = 0;
int totloop = 0, totpoly = 0, vertofs, *matmap = NULL;
int i, haskey = 0, edgeofs, loopofs, polyofs;
- bool ok = false;
+ bool ok = false, join_parent = false;
bDeformGroup *dg, *odg;
CustomData vdata, edata, fdata, ldata, pdata;
@@ -346,6 +346,10 @@ int join_mesh_exec(bContext *C, wmOperator *op)
ok = true;
}
+ if ((ob->parent != NULL) && (ob_iter == ob->parent)) {
+ join_parent = true;
+ }
+
/* check for shapekeys */
if (me->key) {
haskey++;
@@ -354,6 +358,13 @@ int join_mesh_exec(bContext *C, wmOperator *op)
}
CTX_DATA_END;
+ /* Apply parent transform if the active object's parent was joined to it.
+ * Note: This doesn't apply recursive parenting. */
+ if (join_parent) {
+ ob->parent = NULL;
+ BKE_object_apply_mat4_ex(ob, ob->obmat, ob->parent, ob->parentinv, false);
+ }
+
/* that way the active object is always selected */
if (ok == false) {
BKE_report(op->reports, RPT_WARNING, "Active object is not a selected mesh");
@@ -440,7 +451,7 @@ int join_mesh_exec(bContext *C, wmOperator *op)
}
/* Join this object's face maps to the base one's. */
- for (bFaceMap *fmap = ob_iter->fmaps.first; fmap; fmap = fmap->next) {
+ LISTBASE_FOREACH (bFaceMap *, fmap, &ob_iter->fmaps) {
/* See if this group exists in the object (if it doesn't, add it to the end) */
if (BKE_object_facemap_find_name(ob, fmap->name) == NULL) {
bFaceMap *fmap_new = MEM_mallocN(sizeof(bFaceMap), "join faceMap");
@@ -786,62 +797,73 @@ int join_mesh_shapes_exec(bContext *C, wmOperator *op)
}
/* -------------------------------------------------------------------- */
-/* Mesh Mirror (Topology) */
-
/** \name Mesh Topology Mirror API
* \{ */
static MirrTopoStore_t mesh_topo_store = {NULL, -1. - 1, -1};
+BLI_INLINE void mesh_mirror_topo_table_get_meshes(Object *ob,
+ Mesh *me_eval,
+ Mesh **r_me_mirror,
+ BMEditMesh **r_em_mirror)
+{
+ Mesh *me_mirror = NULL;
+ BMEditMesh *em_mirror = NULL;
+
+ Mesh *me = ob->data;
+ if (me_eval != NULL) {
+ me_mirror = me_eval;
+ }
+ else if (me->edit_mesh != NULL) {
+ em_mirror = me->edit_mesh;
+ }
+ else {
+ me_mirror = me;
+ }
+
+ *r_me_mirror = me_mirror;
+ *r_em_mirror = em_mirror;
+}
+
/**
* Mode is 's' start, or 'e' end, or 'u' use
* if end, ob can be NULL.
* \note This is supposed return -1 on error,
* which callers are currently checking for, but is not used so far.
*/
-int ED_mesh_mirror_topo_table(Object *ob, Mesh *me_eval, char mode)
+void ED_mesh_mirror_topo_table_begin(Object *ob, Mesh *me_eval)
{
+ Mesh *me_mirror;
+ BMEditMesh *em_mirror;
+ mesh_mirror_topo_table_get_meshes(ob, me_eval, &me_mirror, &em_mirror);
- Mesh *me_mirror = NULL;
- BMEditMesh *em_mirror = NULL;
+ ED_mesh_mirrtopo_init(em_mirror, me_mirror, &mesh_topo_store, false);
+}
- if (mode != 'e') {
- Mesh *me = ob->data;
- if (me_eval != NULL) {
- me_mirror = me_eval;
- }
- else if (me->edit_mesh != NULL) {
- em_mirror = me->edit_mesh;
- }
- else {
- me_mirror = me;
- }
- }
+void ED_mesh_mirror_topo_table_end(Object *UNUSED(ob))
+{
+ /* TODO: store this in object/object-data (keep unused argument for now). */
+ ED_mesh_mirrtopo_free(&mesh_topo_store);
+}
- if (mode == 'u') { /* use table */
- if (ED_mesh_mirrtopo_recalc_check(em_mirror, me_mirror, &mesh_topo_store)) {
- ED_mesh_mirror_topo_table(ob, me_eval, 's');
- }
- }
- else if (mode == 's') { /* start table */
- ED_mesh_mirrtopo_init(em_mirror, me_mirror, &mesh_topo_store, false);
- }
- else if (mode == 'e') { /* end table */
- ED_mesh_mirrtopo_free(&mesh_topo_store);
- }
- else {
- BLI_assert(0);
- }
+static int ed_mesh_mirror_topo_table_update(Object *ob, Mesh *me_eval)
+{
+ Mesh *me_mirror;
+ BMEditMesh *em_mirror;
+ mesh_mirror_topo_table_get_meshes(ob, me_eval, &me_mirror, &em_mirror);
+ if (ED_mesh_mirrtopo_recalc_check(em_mirror, me_mirror, &mesh_topo_store)) {
+ ED_mesh_mirror_topo_table_begin(ob, me_eval);
+ }
return 0;
}
/** \} */
-static int mesh_get_x_mirror_vert_spatial(Object *ob, Mesh *mesh, int index)
+static int mesh_get_x_mirror_vert_spatial(Object *ob, Mesh *me_eval, int index)
{
Mesh *me = ob->data;
- MVert *mvert = mesh ? mesh->mvert : me->mvert;
+ MVert *mvert = me_eval ? me_eval->mvert : me->mvert;
float vec[3];
mvert = &mvert[index];
@@ -849,12 +871,12 @@ static int mesh_get_x_mirror_vert_spatial(Object *ob, Mesh *mesh, int index)
vec[1] = mvert->co[1];
vec[2] = mvert->co[2];
- return ED_mesh_mirror_spatial_table(ob, NULL, mesh, vec, 'u');
+ return ED_mesh_mirror_spatial_table_lookup(ob, NULL, me_eval, vec);
}
static int mesh_get_x_mirror_vert_topo(Object *ob, Mesh *mesh, int index)
{
- if (ED_mesh_mirror_topo_table(ob, mesh, 'u') == -1) {
+ if (ed_mesh_mirror_topo_table_update(ob, mesh) == -1) {
return -1;
}
@@ -885,7 +907,7 @@ static BMVert *editbmesh_get_x_mirror_vert_spatial(Object *ob, BMEditMesh *em, c
vec[1] = co[1];
vec[2] = co[2];
- i = ED_mesh_mirror_spatial_table(ob, em, NULL, vec, 'u');
+ i = ED_mesh_mirror_spatial_table_lookup(ob, em, NULL, vec);
if (i != -1) {
return BM_vert_at_index(em->bm, i);
}
@@ -898,7 +920,7 @@ static BMVert *editbmesh_get_x_mirror_vert_topo(Object *ob,
int index)
{
intptr_t poinval;
- if (ED_mesh_mirror_topo_table(ob, NULL, 'u') == -1) {
+ if (ed_mesh_mirror_topo_table_update(ob, NULL) == -1) {
return NULL;
}
@@ -1023,10 +1045,10 @@ static float *editmesh_get_mirror_uv(
#endif
-static unsigned int mirror_facehash(const void *ptr)
+static uint mirror_facehash(const void *ptr)
{
const MFace *mf = ptr;
- unsigned int v0, v1;
+ uint v0, v1;
if (mf->v4) {
v0 = MIN4(mf->v1, mf->v2, mf->v3, mf->v4);
@@ -1098,13 +1120,13 @@ int *mesh_get_x_mirror_faces(Object *ob, BMEditMesh *em, Mesh *me_eval)
mvert = me_eval ? me_eval->mvert : me->mvert;
mface = me_eval ? me_eval->mface : me->mface;
- ED_mesh_mirror_spatial_table(ob, em, me_eval, NULL, 's');
+ ED_mesh_mirror_spatial_table_begin(ob, em, me_eval);
for (a = 0, mv = mvert; a < totvert; a++, mv++) {
mirrorverts[a] = mesh_get_x_mirror_vert(ob, me_eval, a, use_topology);
}
- ED_mesh_mirror_spatial_table(ob, em, me_eval, NULL, 'e');
+ ED_mesh_mirror_spatial_table_end(ob);
fhash = BLI_ghash_new_ex(mirror_facehash, mirror_facecmp, "mirror_facehash gh", me->totface);
for (a = 0, mf = mface; a < totface; a++, mf++) {
@@ -1119,8 +1141,8 @@ int *mesh_get_x_mirror_faces(Object *ob, BMEditMesh *em, Mesh *me_eval)
/* make sure v4 is not 0 if a quad */
if (mf->v4 && mirrormf.v4 == 0) {
- SWAP(unsigned int, mirrormf.v1, mirrormf.v3);
- SWAP(unsigned int, mirrormf.v2, mirrormf.v4);
+ SWAP(uint, mirrormf.v1, mirrormf.v3);
+ SWAP(uint, mirrormf.v2, mirrormf.v4);
}
hashmf = BLI_ghash_lookup(fhash, &mirrormf);
@@ -1174,7 +1196,7 @@ bool ED_mesh_pick_face(bContext *C, Object *ob, const int mval[2], uint dist_px,
*r_index = DRW_select_buffer_sample_point(vc.depsgraph, vc.region, vc.v3d, mval);
}
- if ((*r_index) == 0 || (*r_index) > (unsigned int)me->totpoly) {
+ if ((*r_index) == 0 || (*r_index) > (uint)me->totpoly) {
return false;
}
@@ -1218,7 +1240,7 @@ bool ED_mesh_pick_face_vert(
bContext *C, Object *ob, const int mval[2], uint dist_px, uint *r_index)
{
Depsgraph *depsgraph = CTX_data_ensure_evaluated_depsgraph(C);
- unsigned int poly_index;
+ uint poly_index;
Mesh *me = ob->data;
BLI_assert(me && GS(me->id.name) == ID_ME);
@@ -1241,7 +1263,7 @@ bool ED_mesh_pick_face_vert(
MPoly *me_eval_mpoly;
MLoop *me_eval_mloop;
MVert *me_eval_mvert;
- unsigned int me_eval_mpoly_len;
+ uint me_eval_mpoly_len;
const int *index_mp_to_orig;
me_eval_mpoly = me_eval->mpoly;
@@ -1254,7 +1276,7 @@ bool ED_mesh_pick_face_vert(
/* tag all verts using this face */
if (index_mp_to_orig) {
- unsigned int i;
+ uint i;
for (i = 0; i < me_eval_mpoly_len; i++) {
if (index_mp_to_orig[i] == poly_index) {
diff --git a/source/blender/editors/metaball/mball_edit.c b/source/blender/editors/metaball/mball_edit.c
index a64674deda4..9386c466f95 100644
--- a/source/blender/editors/metaball/mball_edit.c
+++ b/source/blender/editors/metaball/mball_edit.c
@@ -456,7 +456,7 @@ static int select_random_metaelems_exec(bContext *C, wmOperator *op)
RNG *rng = BLI_rng_new_srandom(seed_iter);
- for (MetaElem *ml = mb->editelems->first; ml; ml = ml->next) {
+ LISTBASE_FOREACH (MetaElem *, ml, mb->editelems) {
if (BLI_rng_get_float(rng) < randfac) {
if (select) {
ml->flag |= SELECT;
@@ -656,7 +656,7 @@ static int reveal_metaelems_exec(bContext *C, wmOperator *op)
const bool select = RNA_boolean_get(op->ptr, "select");
bool changed = false;
- for (MetaElem *ml = mb->editelems->first; ml; ml = ml->next) {
+ LISTBASE_FOREACH (MetaElem *, ml, mb->editelems) {
if (ml->flag & MB_HIDE) {
SET_FLAG_FROM_TEST(ml->flag, select, SELECT);
ml->flag &= ~MB_HIDE;
@@ -697,7 +697,7 @@ bool ED_mball_select_pick(bContext *C, const int mval[2], bool extend, bool dese
static MetaElem *startelem = NULL;
ViewContext vc;
int a, hits;
- unsigned int buffer[MAXPICKBUF];
+ uint buffer[MAXPICKBUF];
rcti rect;
ED_view3d_viewcontext_init(C, &vc, depsgraph);
diff --git a/source/blender/editors/object/CMakeLists.txt b/source/blender/editors/object/CMakeLists.txt
index a5b6fa55aa9..fb273cf49a8 100644
--- a/source/blender/editors/object/CMakeLists.txt
+++ b/source/blender/editors/object/CMakeLists.txt
@@ -17,6 +17,7 @@
set(INC
../include
+ ../../blenfont
../../blenkernel
../../blenlib
../../blentranslation
@@ -33,6 +34,7 @@ set(INC
../../shader_fx
../../render/extern/include
../../windowmanager
+ ../../../../intern/clog
../../../../intern/glew-mx
../../../../intern/guardedalloc
)
diff --git a/source/blender/editors/object/object_add.c b/source/blender/editors/object/object_add.c
index ac2958282c1..8289f52b0c8 100644
--- a/source/blender/editors/object/object_add.c
+++ b/source/blender/editors/object/object_add.c
@@ -53,8 +53,7 @@
#include "BLT_translation.h"
#include "BKE_action.h"
-#include "BKE_anim.h"
-#include "BKE_animsys.h"
+#include "BKE_anim_data.h"
#include "BKE_armature.h"
#include "BKE_camera.h"
#include "BKE_collection.h"
@@ -62,9 +61,10 @@
#include "BKE_context.h"
#include "BKE_curve.h"
#include "BKE_displist.h"
+#include "BKE_duplilist.h"
#include "BKE_effect.h"
#include "BKE_font.h"
-#include "BKE_gpencil_geom.h"
+#include "BKE_gpencil_curve.h"
#include "BKE_hair.h"
#include "BKE_key.h"
#include "BKE_lattice.h"
@@ -146,7 +146,7 @@ static const EnumPropertyItem field_type_items[] = {
{PFIELD_BOID, "BOID", ICON_FORCE_BOID, "Boid", ""},
{PFIELD_TURBULENCE, "TURBULENCE", ICON_FORCE_TURBULENCE, "Turbulence", ""},
{PFIELD_DRAG, "DRAG", ICON_FORCE_DRAG, "Drag", ""},
- {PFIELD_SMOKEFLOW, "SMOKE", ICON_FORCE_SMOKEFLOW, "Smoke Flow", ""},
+ {PFIELD_FLUIDFLOW, "FLUID", ICON_FORCE_FLUIDFLOW, "Fluid Flow", ""},
{0, NULL, 0, NULL, NULL},
};
@@ -303,10 +303,15 @@ void ED_object_add_unit_props_size(wmOperatorType *ot)
ot->srna, "size", 2.0f, 0.0, OBJECT_ADD_SIZE_MAXF, "Size", "", 0.001, 100.00);
}
-void ED_object_add_unit_props_radius(wmOperatorType *ot)
+void ED_object_add_unit_props_radius_ex(wmOperatorType *ot, float default_value)
{
RNA_def_float_distance(
- ot->srna, "radius", 1.0f, 0.0, OBJECT_ADD_SIZE_MAXF, "Radius", "", 0.001, 100.00);
+ ot->srna, "radius", default_value, 0.0, OBJECT_ADD_SIZE_MAXF, "Radius", "", 0.001, 100.00);
+}
+
+void ED_object_add_unit_props_radius(wmOperatorType *ot)
+{
+ ED_object_add_unit_props_radius_ex(ot, 1.0f);
}
void ED_object_add_generic_props(wmOperatorType *ot, bool do_editmode)
@@ -345,6 +350,18 @@ void ED_object_add_generic_props(wmOperatorType *ot, bool do_editmode)
DEG2RADF(-360.0f),
DEG2RADF(360.0f));
RNA_def_property_flag(prop, PROP_SKIP_SAVE);
+
+ prop = RNA_def_float_vector_xyz(ot->srna,
+ "scale",
+ 3,
+ NULL,
+ -OBJECT_ADD_SIZE_MAXF,
+ OBJECT_ADD_SIZE_MAXF,
+ "Scale",
+ "Scale for the newly added object",
+ -1000.0f,
+ 1000.0f);
+ RNA_def_property_flag(prop, PROP_HIDDEN | PROP_SKIP_SAVE);
}
void ED_object_add_mesh_props(wmOperatorType *ot)
@@ -357,6 +374,7 @@ bool ED_object_add_generic_get_opts(bContext *C,
const char view_align_axis,
float loc[3],
float rot[3],
+ float scale[3],
bool *enter_editmode,
ushort *local_view_bits,
bool *is_view_aligned)
@@ -465,6 +483,26 @@ bool ED_object_add_generic_get_opts(bContext *C,
}
}
+ /* Scale! */
+ {
+ float _scale[3];
+ if (!scale) {
+ scale = _scale;
+ }
+
+ /* For now this is optional, we can make it always use. */
+ copy_v3_fl(scale, 1.0f);
+ if ((prop = RNA_struct_find_property(op->ptr, "scale"))) {
+ if (RNA_property_is_set(op->ptr, prop)) {
+ RNA_property_float_get_array(op->ptr, prop, scale);
+ }
+ else {
+ copy_v3_fl(scale, 1.0f);
+ RNA_property_float_set_array(op->ptr, prop, scale);
+ }
+ }
+ }
+
return true;
}
@@ -530,7 +568,7 @@ static int object_add_exec(bContext *C, wmOperator *op)
WM_operator_view3d_unit_defaults(C, op);
if (!ED_object_add_generic_get_opts(
- C, op, 'Z', loc, rot, &enter_editmode, &local_view_bits, NULL)) {
+ C, op, 'Z', loc, rot, NULL, &enter_editmode, &local_view_bits, NULL)) {
return OPERATOR_CANCELLED;
}
radius = RNA_float_get(op->ptr, "radius");
@@ -604,7 +642,7 @@ static int lightprobe_add_exec(bContext *C, wmOperator *op)
WM_operator_view3d_unit_defaults(C, op);
if (!ED_object_add_generic_get_opts(
- C, op, 'Z', loc, rot, &enter_editmode, &local_view_bits, NULL)) {
+ C, op, 'Z', loc, rot, NULL, &enter_editmode, &local_view_bits, NULL)) {
return OPERATOR_CANCELLED;
}
type = RNA_enum_get(op->ptr, "type");
@@ -663,7 +701,7 @@ static int effector_add_exec(bContext *C, wmOperator *op)
WM_operator_view3d_unit_defaults(C, op);
if (!ED_object_add_generic_get_opts(
- C, op, 'Z', loc, rot, &enter_editmode, &local_view_bits, NULL)) {
+ C, op, 'Z', loc, rot, NULL, &enter_editmode, &local_view_bits, NULL)) {
return OPERATOR_CANCELLED;
}
type = RNA_enum_get(op->ptr, "type");
@@ -741,7 +779,7 @@ static int object_camera_add_exec(bContext *C, wmOperator *op)
RNA_enum_set(op->ptr, "align", ALIGN_VIEW);
if (!ED_object_add_generic_get_opts(
- C, op, 'Z', loc, rot, &enter_editmode, &local_view_bits, NULL)) {
+ C, op, 'Z', loc, rot, NULL, &enter_editmode, &local_view_bits, NULL)) {
return OPERATOR_CANCELLED;
}
ob = ED_object_add_type(C, OB_CAMERA, NULL, loc, rot, false, local_view_bits);
@@ -802,7 +840,7 @@ static int object_metaball_add_exec(bContext *C, wmOperator *op)
WM_operator_view3d_unit_defaults(C, op);
if (!ED_object_add_generic_get_opts(
- C, op, 'Z', loc, rot, &enter_editmode, &local_view_bits, NULL)) {
+ C, op, 'Z', loc, rot, NULL, &enter_editmode, &local_view_bits, NULL)) {
return OPERATOR_CANCELLED;
}
if (obedit == NULL || obedit->type != OB_MBALL) {
@@ -814,7 +852,10 @@ static int object_metaball_add_exec(bContext *C, wmOperator *op)
}
ED_object_new_primitive_matrix(C, obedit, loc, rot, mat);
- dia = RNA_float_get(op->ptr, "radius");
+ /* Halving here is done to account for constant values from #BKE_mball_element_add.
+ * While the default radius of the resulting meta element is 2,
+ * we want to pass in 1 so other values such as resolution are scaled by 1.0. */
+ dia = RNA_float_get(op->ptr, "radius") / 2;
ED_mball_add_primitive(C, obedit, mat, dia, RNA_enum_get(op->ptr, "type"));
@@ -845,7 +886,7 @@ void OBJECT_OT_metaball_add(wmOperatorType *ot)
ot->prop = RNA_def_enum(ot->srna, "type", rna_enum_metaelem_type_items, 0, "Primitive", "");
- ED_object_add_unit_props_radius(ot);
+ ED_object_add_unit_props_radius_ex(ot, 2.0f);
ED_object_add_generic_props(ot, true);
}
@@ -864,7 +905,7 @@ static int object_add_text_exec(bContext *C, wmOperator *op)
WM_operator_view3d_unit_defaults(C, op);
if (!ED_object_add_generic_get_opts(
- C, op, 'Z', loc, rot, &enter_editmode, &local_view_bits, NULL)) {
+ C, op, 'Z', loc, rot, NULL, &enter_editmode, &local_view_bits, NULL)) {
return OPERATOR_CANCELLED;
}
if (obedit && obedit->type == OB_FONT) {
@@ -916,7 +957,7 @@ static int object_armature_add_exec(bContext *C, wmOperator *op)
WM_operator_view3d_unit_defaults(C, op);
if (!ED_object_add_generic_get_opts(
- C, op, 'Z', loc, rot, &enter_editmode, &local_view_bits, NULL)) {
+ C, op, 'Z', loc, rot, NULL, &enter_editmode, &local_view_bits, NULL)) {
return OPERATOR_CANCELLED;
}
if ((obedit == NULL) || (obedit->type != OB_ARMATURE)) {
@@ -979,7 +1020,7 @@ static int object_empty_add_exec(bContext *C, wmOperator *op)
float loc[3], rot[3];
WM_operator_view3d_unit_defaults(C, op);
- if (!ED_object_add_generic_get_opts(C, op, 'Z', loc, rot, NULL, &local_view_bits, NULL)) {
+ if (!ED_object_add_generic_get_opts(C, op, 'Z', loc, rot, NULL, NULL, &local_view_bits, NULL)) {
return OPERATOR_CANCELLED;
}
ob = ED_object_add_type(C, OB_EMPTY, NULL, loc, rot, false, local_view_bits);
@@ -1039,7 +1080,8 @@ static int empty_drop_named_image_invoke(bContext *C, wmOperator *op, const wmEv
ushort local_view_bits;
float rot[3];
- if (!ED_object_add_generic_get_opts(C, op, 'Z', NULL, rot, NULL, &local_view_bits, NULL)) {
+ if (!ED_object_add_generic_get_opts(
+ C, op, 'Z', NULL, rot, NULL, NULL, &local_view_bits, NULL)) {
return OPERATOR_CANCELLED;
}
ob = ED_object_add_type(C, OB_EMPTY, NULL, NULL, rot, false, local_view_bits);
@@ -1126,7 +1168,7 @@ static int object_gpencil_add_exec(bContext *C, wmOperator *op)
/* Note: We use 'Y' here (not 'Z'), as */
WM_operator_view3d_unit_defaults(C, op);
- if (!ED_object_add_generic_get_opts(C, op, 'Y', loc, rot, NULL, &local_view_bits, NULL)) {
+ if (!ED_object_add_generic_get_opts(C, op, 'Y', loc, rot, NULL, NULL, &local_view_bits, NULL)) {
return OPERATOR_CANCELLED;
}
/* add new object if not currently editing a GP object,
@@ -1256,7 +1298,7 @@ static int object_light_add_exec(bContext *C, wmOperator *op)
float loc[3], rot[3];
WM_operator_view3d_unit_defaults(C, op);
- if (!ED_object_add_generic_get_opts(C, op, 'Z', loc, rot, NULL, &local_view_bits, NULL)) {
+ if (!ED_object_add_generic_get_opts(C, op, 'Z', loc, rot, NULL, NULL, &local_view_bits, NULL)) {
return OPERATOR_CANCELLED;
}
ob = ED_object_add_type(C, OB_LAMP, get_light_defname(type), loc, rot, false, local_view_bits);
@@ -1341,7 +1383,7 @@ static int collection_instance_add_exec(bContext *C, wmOperator *op)
collection = BLI_findlink(&bmain->collections, RNA_enum_get(op->ptr, "collection"));
}
- if (!ED_object_add_generic_get_opts(C, op, 'Z', loc, rot, NULL, &local_view_bits, NULL)) {
+ if (!ED_object_add_generic_get_opts(C, op, 'Z', loc, rot, NULL, NULL, &local_view_bits, NULL)) {
return OPERATOR_CANCELLED;
}
if (collection) {
@@ -1357,6 +1399,7 @@ static int collection_instance_add_exec(bContext *C, wmOperator *op)
Object *ob = ED_object_add_type(
C, OB_EMPTY, collection->id.name + 2, loc, rot, false, local_view_bits);
ob->instance_collection = collection;
+ ob->empty_drawsize = U.collection_instance_empty_size;
ob->transflag |= OB_DUPLICOLLECTION;
id_us_plus(&collection->id);
@@ -1413,7 +1456,7 @@ static int object_speaker_add_exec(bContext *C, wmOperator *op)
float loc[3], rot[3];
Scene *scene = CTX_data_scene(C);
- if (!ED_object_add_generic_get_opts(C, op, 'Z', loc, rot, NULL, &local_view_bits, NULL)) {
+ if (!ED_object_add_generic_get_opts(C, op, 'Z', loc, rot, NULL, NULL, &local_view_bits, NULL)) {
return OPERATOR_CANCELLED;
}
ob = ED_object_add_type(C, OB_SPEAKER, NULL, loc, rot, false, local_view_bits);
@@ -1470,7 +1513,7 @@ static int object_hair_add_exec(bContext *C, wmOperator *op)
ushort local_view_bits;
float loc[3], rot[3];
- if (!ED_object_add_generic_get_opts(C, op, 'Z', loc, rot, NULL, &local_view_bits, NULL)) {
+ if (!ED_object_add_generic_get_opts(C, op, 'Z', loc, rot, NULL, NULL, &local_view_bits, NULL)) {
return OPERATOR_CANCELLED;
}
Object *object = ED_object_add_type(C, OB_HAIR, NULL, loc, rot, false, local_view_bits);
@@ -1507,7 +1550,7 @@ static int object_pointcloud_add_exec(bContext *C, wmOperator *op)
ushort local_view_bits;
float loc[3], rot[3];
- if (!ED_object_add_generic_get_opts(C, op, 'Z', loc, rot, NULL, &local_view_bits, NULL)) {
+ if (!ED_object_add_generic_get_opts(C, op, 'Z', loc, rot, NULL, NULL, &local_view_bits, NULL)) {
return OPERATOR_CANCELLED;
}
Object *object = ED_object_add_type(C, OB_POINTCLOUD, NULL, loc, rot, false, local_view_bits);
@@ -1738,10 +1781,10 @@ static void copy_object_set_idnew(bContext *C)
* In other words, we consider each group of objects from a same item as being
* the 'local group' where to check for parents.
*/
-static unsigned int dupliobject_hash(const void *ptr)
+static uint dupliobject_hash(const void *ptr)
{
const DupliObject *dob = ptr;
- unsigned int hash = BLI_ghashutil_ptrhash(dob->ob);
+ uint hash = BLI_ghashutil_ptrhash(dob->ob);
if (dob->type == OB_DUPLICOLLECTION) {
for (int i = 1; (i < MAX_DUPLI_RECUR) && dob->persistent_id[i] != INT_MAX; i++) {
@@ -1760,10 +1803,10 @@ static unsigned int dupliobject_hash(const void *ptr)
* since its a unique index and we only want to know if the group objects are from the same
* dupli-group instance.
*/
-static unsigned int dupliobject_instancer_hash(const void *ptr)
+static uint dupliobject_instancer_hash(const void *ptr)
{
const DupliObject *dob = ptr;
- unsigned int hash = BLI_ghashutil_inthash(dob->persistent_id[0]);
+ uint hash = BLI_ghashutil_inthash(dob->persistent_id[0]);
for (int i = 1; (i < MAX_DUPLI_RECUR) && dob->persistent_id[i] != INT_MAX; i++) {
hash ^= (dob->persistent_id[i] ^ i);
}
@@ -2048,6 +2091,7 @@ static int object_duplicates_make_real_exec(bContext *C, wmOperator *op)
DEG_relations_tag_update(bmain);
WM_event_add_notifier(C, NC_SCENE, scene);
WM_main_add_notifier(NC_OBJECT | ND_DRAW, NULL);
+ ED_outliner_select_sync_from_object_tag(C);
return OPERATOR_FINISHED;
}
@@ -2255,7 +2299,7 @@ static int convert_exec(bContext *C, wmOperator *op)
* needed since re-evaluating single modifiers causes bugs if they depend
* on other objects data masks too, see: T50950. */
{
- for (CollectionPointerLink *link = selected_editable_bases.first; link; link = link->next) {
+ LISTBASE_FOREACH (CollectionPointerLink *, link, &selected_editable_bases) {
Base *base = link->ptr.data;
Object *ob = base->object;
@@ -2282,7 +2326,7 @@ static int convert_exec(bContext *C, wmOperator *op)
scene->customdata_mask = customdata_mask_prev;
}
- for (CollectionPointerLink *link = selected_editable_bases.first; link; link = link->next) {
+ LISTBASE_FOREACH (CollectionPointerLink *, link, &selected_editable_bases) {
Object *newob = NULL;
Base *base = link->ptr.data;
Object *ob = base->object;
@@ -2380,13 +2424,8 @@ static int convert_exec(bContext *C, wmOperator *op)
cu = newob->data;
- /* TODO(sergey): Ideally DAG will create nurbs list for a curve data
- * datablock, but for until we've got granular update
- * lets take care by selves.
- */
- /* XXX This may fail/crash, since BKE_vfont_to_curve()
- * accesses evaluated data in some cases (bastien). */
- BKE_vfont_to_curve(newob, FO_EDIT);
+ Object *ob_eval = DEG_get_evaluated_object(depsgraph, ob);
+ BKE_vfont_to_curve_ex(ob_eval, ob_eval->data, FO_EDIT, &cu->nurb, NULL, NULL, NULL, NULL);
newob->type = OB_CURVE;
cu->type = OB_CURVE;
@@ -2543,7 +2582,12 @@ static int convert_exec(bContext *C, wmOperator *op)
}
if (!keep_original && (ob->flag & OB_DONE)) {
- DEG_id_tag_update(&ob->id, ID_RECALC_GEOMETRY);
+ /* NOTE: Tag transform for update because object parenting to curve with path is handled
+ * differently from all other cases. Converting curve to mesh and mesh to curve will likely
+ * affect the way children are evaluated.
+ * It is not enough to tag only geometry and rely on the curve parenting relations because
+ * this relation is lost when curve is converted to mesh. */
+ DEG_id_tag_update(&ob->id, ID_RECALC_GEOMETRY | ID_RECALC_TRANSFORM);
((ID *)ob->data)->tag &= ~LIB_TAG_DOIT; /* flag not to convert this datablock again */
}
}
@@ -2855,6 +2899,7 @@ static int add_named_exec(bContext *C, wmOperator *op)
DEG_id_tag_update(&scene->id, ID_RECALC_SELECT);
WM_event_add_notifier(C, NC_SCENE | ND_OB_SELECT, scene);
WM_event_add_notifier(C, NC_SCENE | ND_OB_ACTIVE, scene);
+ ED_outliner_select_sync_from_object_tag(C);
return OPERATOR_FINISHED;
}
diff --git a/source/blender/editors/object/object_bake.c b/source/blender/editors/object/object_bake.c
index 2cb0229126d..baa24ab2f4e 100644
--- a/source/blender/editors/object/object_bake.c
+++ b/source/blender/editors/object/object_bake.c
@@ -156,7 +156,7 @@ static bool multiresbake_check(bContext *C, wmOperator *op)
ok = mmd->totlvl > 0;
for (md = (ModifierData *)mmd->modifier.next; md && ok; md = md->next) {
- if (modifier_isEnabled(scene, md, eModifierMode_Realtime)) {
+ if (BKE_modifier_is_enabled(scene, md, eModifierMode_Realtime)) {
ok = false;
}
}
diff --git a/source/blender/editors/object/object_bake_api.c b/source/blender/editors/object/object_bake_api.c
index 7d39d2546b6..e84dbca2469 100644
--- a/source/blender/editors/object/object_bake_api.c
+++ b/source/blender/editors/object/object_bake_api.c
@@ -96,6 +96,7 @@ typedef struct BakeAPIRender {
bool is_cage;
float cage_extrusion;
+ float max_ray_distance;
int normal_space;
eBakeNormalSwizzle normal_swizzle[3];
@@ -116,7 +117,7 @@ typedef struct BakeAPIRender {
short *do_update;
/* for redrawing */
- ScrArea *sa;
+ ScrArea *area;
} BakeAPIRender;
/* callbacks */
@@ -161,10 +162,10 @@ static int bake_break(void *UNUSED(rjv))
return 0;
}
-static void bake_update_image(ScrArea *sa, Image *image)
+static void bake_update_image(ScrArea *area, Image *image)
{
- if (sa && sa->spacetype == SPACE_IMAGE) { /* in case the user changed while baking */
- SpaceImage *sima = sa->spacedata.first;
+ if (area && area->spacetype == SPACE_IMAGE) { /* in case the user changed while baking */
+ SpaceImage *sima = area->spacedata.first;
if (sima) {
sima->image = image;
}
@@ -234,7 +235,7 @@ static bool write_internal_bake_pixels(Image *image,
ibuf->x);
}
else {
- IMB_buffer_byte_from_float((unsigned char *)ibuf->rect,
+ IMB_buffer_byte_from_float((uchar *)ibuf->rect,
buffer,
ibuf->channels,
ibuf->dither,
@@ -259,7 +260,7 @@ static bool write_internal_bake_pixels(Image *image,
mask_buffer);
}
else {
- IMB_buffer_byte_from_float_mask((unsigned char *)ibuf->rect,
+ IMB_buffer_byte_from_float_mask((uchar *)ibuf->rect,
buffer,
ibuf->channels,
ibuf->dither,
@@ -359,7 +360,7 @@ static bool write_external_bake_pixels(const char *filepath,
buffer, ibuf->x, ibuf->y, ibuf->channels, from_colorspace, to_colorspace, false);
}
- IMB_buffer_byte_from_float((unsigned char *)ibuf->rect,
+ IMB_buffer_byte_from_float((uchar *)ibuf->rect,
buffer,
ibuf->channels,
ibuf->dither,
@@ -446,7 +447,8 @@ static bool bake_object_check(ViewLayer *view_layer, Object *ob, ReportList *rep
for (i = 0; i < ob->totcol; i++) {
bNodeTree *ntree = NULL;
bNode *node = NULL;
- ED_object_get_active_image(ob, i + 1, &image, NULL, &node, &ntree);
+ const int mat_nr = i + 1;
+ ED_object_get_active_image(ob, mat_nr, &image, NULL, &node, &ntree);
if (image) {
ImBuf *ibuf;
@@ -481,7 +483,7 @@ static bool bake_object_check(ViewLayer *view_layer, Object *ob, ReportList *rep
}
}
else {
- Material *mat = BKE_object_material_get(ob, i);
+ Material *mat = BKE_object_material_get(ob, mat_nr);
if (mat != NULL) {
BKE_reportf(reports,
RPT_INFO,
@@ -736,6 +738,7 @@ static int bake(Render *re,
const bool is_selected_to_active,
const bool is_cage,
const float cage_extrusion,
+ const float max_ray_distance,
const int normal_space,
const eBakeNormalSwizzle normal_swizzle[],
const char *custom_cage,
@@ -743,7 +746,7 @@ static int bake(Render *re,
const int width,
const int height,
const char *identifier,
- ScrArea *sa,
+ ScrArea *area,
const char *uv_layer)
{
/* We build a depsgraph for the baking,
@@ -894,7 +897,7 @@ static int bake(Render *re,
/* for multires bake, use linear UV subdivision to match low res UVs */
if (pass_type == SCE_PASS_NORMAL && normal_space == R_BAKE_SPACE_TANGENT &&
!is_selected_to_active) {
- mmd_low = (MultiresModifierData *)modifiers_findByType(ob_low, eModifierType_Multires);
+ mmd_low = (MultiresModifierData *)BKE_modifiers_findby_type(ob_low, eModifierType_Multires);
if (mmd_low) {
mmd_flags_low = mmd_low->flags;
mmd_low->uv_smooth = SUBSURF_UV_SMOOTH_NONE;
@@ -944,7 +947,7 @@ static int bake(Render *re,
if (md->type == eModifierType_EdgeSplit) {
BLI_remlink(&ob_low_eval->modifiers, md);
- modifier_free(md);
+ BKE_modifier_free(md);
is_changed = true;
}
md = md_next;
@@ -1009,6 +1012,7 @@ static int bake(Render *re,
num_pixels,
ob_cage != NULL,
cage_extrusion,
+ max_ray_distance,
ob_low_eval->obmat,
(ob_cage ? ob_cage->obmat : ob_low_eval->obmat),
me_cage)) {
@@ -1023,7 +1027,7 @@ static int bake(Render *re,
highpoly[i].ob,
i,
pixel_array_high,
- num_pixels,
+ &bake_images,
depth,
pass_type,
pass_filter,
@@ -1045,7 +1049,7 @@ static int bake(Render *re,
ob_low_eval,
0,
pixel_array_low,
- num_pixels,
+ &bake_images,
depth,
pass_type,
pass_filter,
@@ -1095,7 +1099,7 @@ static int bake(Render *re,
int mode;
BKE_object_eval_reset(ob_low_eval);
- md = modifiers_findByType(ob_low_eval, eModifierType_Multires);
+ md = BKE_modifiers_findby_type(ob_low_eval, eModifierType_Multires);
if (md) {
mode = md->mode;
@@ -1146,7 +1150,7 @@ static int bake(Render *re,
is_noncolor);
/* might be read by UI to set active image for display */
- bake_update_image(sa, bk_image->image);
+ bake_update_image(area, bk_image->image);
if (!ok) {
BKE_reportf(reports,
@@ -1283,13 +1287,13 @@ cleanup:
static void bake_init_api_data(wmOperator *op, bContext *C, BakeAPIRender *bkr)
{
bool is_save_internal;
- bScreen *sc = CTX_wm_screen(C);
+ bScreen *screen = CTX_wm_screen(C);
bkr->ob = CTX_data_active_object(C);
bkr->main = CTX_data_main(C);
bkr->view_layer = CTX_data_view_layer(C);
bkr->scene = CTX_data_scene(C);
- bkr->sa = sc ? BKE_screen_find_big_area(sc, SPACE_IMAGE, 10) : NULL;
+ bkr->area = screen ? BKE_screen_find_big_area(screen, SPACE_IMAGE, 10) : NULL;
bkr->pass_type = RNA_enum_get(op->ptr, "type");
bkr->pass_filter = RNA_enum_get(op->ptr, "pass_filter");
@@ -1304,6 +1308,7 @@ static void bake_init_api_data(wmOperator *op, bContext *C, BakeAPIRender *bkr)
bkr->is_selected_to_active = RNA_boolean_get(op->ptr, "use_selected_to_active");
bkr->is_cage = RNA_boolean_get(op->ptr, "use_cage");
bkr->cage_extrusion = RNA_float_get(op->ptr, "cage_extrusion");
+ bkr->max_ray_distance = RNA_float_get(op->ptr, "max_ray_distance");
bkr->normal_space = RNA_enum_get(op->ptr, "normal_space");
bkr->normal_swizzle[0] = RNA_enum_get(op->ptr, "normal_r");
@@ -1393,6 +1398,7 @@ static int bake_exec(bContext *C, wmOperator *op)
true,
bkr.is_cage,
bkr.cage_extrusion,
+ bkr.max_ray_distance,
bkr.normal_space,
bkr.normal_swizzle,
bkr.custom_cage,
@@ -1400,7 +1406,7 @@ static int bake_exec(bContext *C, wmOperator *op)
bkr.width,
bkr.height,
bkr.identifier,
- bkr.sa,
+ bkr.area,
bkr.uv_layer);
}
else {
@@ -1425,6 +1431,7 @@ static int bake_exec(bContext *C, wmOperator *op)
false,
bkr.is_cage,
bkr.cage_extrusion,
+ bkr.max_ray_distance,
bkr.normal_space,
bkr.normal_swizzle,
bkr.custom_cage,
@@ -1432,7 +1439,7 @@ static int bake_exec(bContext *C, wmOperator *op)
bkr.width,
bkr.height,
bkr.identifier,
- bkr.sa,
+ bkr.area,
bkr.uv_layer);
}
}
@@ -1494,6 +1501,7 @@ static void bake_startjob(void *bkv, short *UNUSED(stop), short *do_update, floa
true,
bkr->is_cage,
bkr->cage_extrusion,
+ bkr->max_ray_distance,
bkr->normal_space,
bkr->normal_swizzle,
bkr->custom_cage,
@@ -1501,7 +1509,7 @@ static void bake_startjob(void *bkv, short *UNUSED(stop), short *do_update, floa
bkr->width,
bkr->height,
bkr->identifier,
- bkr->sa,
+ bkr->area,
bkr->uv_layer);
}
else {
@@ -1526,6 +1534,7 @@ static void bake_startjob(void *bkv, short *UNUSED(stop), short *do_update, floa
false,
bkr->is_cage,
bkr->cage_extrusion,
+ bkr->max_ray_distance,
bkr->normal_space,
bkr->normal_swizzle,
bkr->custom_cage,
@@ -1533,7 +1542,7 @@ static void bake_startjob(void *bkv, short *UNUSED(stop), short *do_update, floa
bkr->width,
bkr->height,
bkr->identifier,
- bkr->sa,
+ bkr->area,
bkr->uv_layer);
if (bkr->result == OPERATOR_CANCELLED) {
@@ -1585,6 +1594,11 @@ static void bake_set_props(wmOperator *op, Scene *scene)
RNA_property_boolean_set(op->ptr, prop, (bake->flag & R_BAKE_TO_ACTIVE) != 0);
}
+ prop = RNA_struct_find_property(op->ptr, "max_ray_distance");
+ if (!RNA_property_is_set(op->ptr, prop)) {
+ RNA_property_float_set(op->ptr, prop, bake->max_ray_distance);
+ }
+
prop = RNA_struct_find_property(op->ptr, "cage_extrusion");
if (!RNA_property_is_set(op->ptr, prop)) {
RNA_property_float_set(op->ptr, prop, bake->cage_extrusion);
@@ -1765,12 +1779,23 @@ void OBJECT_OT_bake(wmOperatorType *ot)
"Selected to Active",
"Bake shading on the surface of selected objects to the active object");
RNA_def_float(ot->srna,
+ "max_ray_distance",
+ 0.0f,
+ 0.0f,
+ FLT_MAX,
+ "Max Ray Distance",
+ "The maximum ray distance for matching points between the active and selected "
+ "objects. If zero, there is no limit",
+ 0.0f,
+ 1.0f);
+ RNA_def_float(ot->srna,
"cage_extrusion",
0.0f,
0.0f,
FLT_MAX,
"Cage Extrusion",
- "Distance to use for the inward ray cast when using selected to active",
+ "Inflate the active object by the specified distance for baking. This helps "
+ "matching to points nearer to the outside of the selected object meshes",
0.0f,
1.0f);
RNA_def_string(ot->srna,
diff --git a/source/blender/editors/object/object_collection.c b/source/blender/editors/object/object_collection.c
index 7c12a4839f0..7a83d582299 100644
--- a/source/blender/editors/object/object_collection.c
+++ b/source/blender/editors/object/object_collection.c
@@ -302,8 +302,8 @@ static int collection_objects_remove_all_exec(bContext *C, wmOperator *UNUSED(op
void COLLECTION_OT_objects_remove_all(wmOperatorType *ot)
{
/* identifiers */
- ot->name = "Remove from All Unlinked Collections";
- ot->description = "Remove selected objects from all collections not used in a scene";
+ ot->name = "Remove from All Collections";
+ ot->description = "Remove selected objects from all collections";
ot->idname = "COLLECTION_OT_objects_remove_all";
/* api callbacks */
@@ -481,9 +481,21 @@ static int collection_link_exec(bContext *C, wmOperator *op)
return OPERATOR_FINISHED;
}
+ /* Currently this should not be allowed (might be supported in the future though...). */
+ if (ID_IS_OVERRIDE_LIBRARY(&collection->id)) {
+ BKE_report(op->reports, RPT_ERROR, "Could not add the collection because it is overridden.");
+ return OPERATOR_CANCELLED;
+ }
+ /* Linked collections are already checked for by using RNA_collection_local_itemf
+ * but operator can be called without invoke */
+ if (ID_IS_LINKED(&collection->id)) {
+ BKE_report(op->reports, RPT_ERROR, "Could not add the collection because it is linked.");
+ return OPERATOR_CANCELLED;
+ }
+
/* Adding object to collection which is used as dupli-collection for self is bad idea.
*
- * It is also bad idea to add object to collection which is in collection which
+ * It is also bad idea to add object to collection which is in collection which
* contains our current object.
*/
if (BKE_collection_object_cyclic_check(bmain, ob, collection)) {
diff --git a/source/blender/editors/object/object_constraint.c b/source/blender/editors/object/object_constraint.c
index ba641fb2a39..76e95b0105a 100644
--- a/source/blender/editors/object/object_constraint.c
+++ b/source/blender/editors/object/object_constraint.c
@@ -81,7 +81,7 @@
* \{ */
/* if object in posemode, active bone constraints, else object constraints */
-ListBase *get_active_constraints(Object *ob)
+ListBase *ED_object_constraint_list_from_context(Object *ob)
{
if (ob == NULL) {
return NULL;
@@ -104,7 +104,9 @@ ListBase *get_active_constraints(Object *ob)
/* Find the list that a given constraint belongs to,
* and/or also get the posechannel this is from (if applicable) */
-ListBase *get_constraint_lb(Object *ob, bConstraint *con, bPoseChannel **r_pchan)
+ListBase *ED_object_constraint_list_from_constraint(Object *ob,
+ bConstraint *con,
+ bPoseChannel **r_pchan)
{
if (r_pchan) {
*r_pchan = NULL;
@@ -143,9 +145,9 @@ ListBase *get_constraint_lb(Object *ob, bConstraint *con, bPoseChannel **r_pchan
}
/* single constraint */
-bConstraint *get_active_constraint(Object *ob)
+bConstraint *ED_object_constraint_active_get(Object *ob)
{
- return BKE_constraints_active_get(get_active_constraints(ob));
+ return BKE_constraints_active_get(ED_object_constraint_list_from_context(ob));
}
/** \} */
@@ -721,7 +723,7 @@ static int edit_constraint_invoke_properties(bContext *C, wmOperator *op)
con = ptr.data;
RNA_string_set(op->ptr, "constraint", con->name);
- list = get_constraint_lb(ob, con, NULL);
+ list = ED_object_constraint_list_from_constraint(ob, con, NULL);
if (&ob->constraints == list) {
RNA_enum_set(op->ptr, "owner", EDIT_CONSTRAINT_OWNER_OBJECT);
@@ -769,7 +771,7 @@ static bConstraint *edit_constraint_property_get(wmOperator *op, Object *ob, int
printf("edit_constraint_property_get: defaulting to getting list in the standard way\n");
}
#endif
- list = get_active_constraints(ob);
+ list = ED_object_constraint_list_from_context(ob);
}
con = BKE_constraints_find_name(list, constraint_name);
@@ -1061,7 +1063,7 @@ static int followpath_path_animate_exec(bContext *C, wmOperator *op)
Curve *cu = (Curve *)data->tar->data;
if (ELEM(NULL, cu->adt, cu->adt->action) ||
- (list_find_fcurve(&cu->adt->action->curves, "eval_time", 0) == NULL)) {
+ (BKE_fcurve_find(&cu->adt->action->curves, "eval_time", 0) == NULL)) {
/* create F-Curve for path animation */
act = ED_id_action_ensure(bmain, &cu->id);
fcu = ED_action_fcurve_ensure(bmain, act, NULL, NULL, "eval_time", 0);
@@ -1305,9 +1307,9 @@ void CONSTRAINT_OT_objectsolver_clear_inverse(wmOperatorType *ot)
/** \name Constraint Management Utilities
* \{ */
-void ED_object_constraint_set_active(Object *ob, bConstraint *con)
+void ED_object_constraint_active_set(Object *ob, bConstraint *con)
{
- ListBase *lb = get_constraint_lb(ob, con, NULL);
+ ListBase *lb = ED_object_constraint_list_from_constraint(ob, con, NULL);
/* lets be nice and escape if its active already */
/* NOTE: this assumes that the stack doesn't have other active ones set... */
@@ -1409,7 +1411,7 @@ static int constraint_delete_exec(bContext *C, wmOperator *UNUSED(op))
PointerRNA ptr = CTX_data_pointer_get_type(C, "constraint", &RNA_Constraint);
Object *ob = (Object *)ptr.owner_id;
bConstraint *con = ptr.data;
- ListBase *lb = get_constraint_lb(ob, con, NULL);
+ ListBase *lb = ED_object_constraint_list_from_constraint(ob, con, NULL);
/* free the constraint */
if (BKE_constraint_remove_ex(lb, ob, con, true)) {
@@ -1459,7 +1461,7 @@ static int constraint_move_down_exec(bContext *C, wmOperator *op)
bConstraint *con = edit_constraint_property_get(op, ob, 0);
if (con && con->next) {
- ListBase *conlist = get_constraint_lb(ob, con, NULL);
+ ListBase *conlist = ED_object_constraint_list_from_constraint(ob, con, NULL);
bConstraint *nextCon = con->next;
/* insert the nominated constraint after the one that used to be after it */
@@ -1515,7 +1517,7 @@ static int constraint_move_up_exec(bContext *C, wmOperator *op)
bConstraint *con = edit_constraint_property_get(op, ob, 0);
if (con && con->prev) {
- ListBase *conlist = get_constraint_lb(ob, con, NULL);
+ ListBase *conlist = ED_object_constraint_list_from_constraint(ob, con, NULL);
bConstraint *prevCon = con->prev;
/* insert the nominated constraint before the one that used to be before it */
@@ -2055,7 +2057,8 @@ static int pose_constraint_add_exec(bContext *C, wmOperator *op)
with_targets = 1;
}
- return constraint_add_exec(C, op, ob, get_active_constraints(ob), type, with_targets);
+ return constraint_add_exec(
+ C, op, ob, ED_object_constraint_list_from_context(ob), type, with_targets);
}
/* ------------------ */
@@ -2256,8 +2259,12 @@ static int pose_ik_add_exec(bContext *C, wmOperator *op)
/* add the constraint - all necessary checks should have
* been done by the invoke() callback already... */
- return constraint_add_exec(
- C, op, ob, get_active_constraints(ob), CONSTRAINT_TYPE_KINEMATIC, with_targets);
+ return constraint_add_exec(C,
+ op,
+ ob,
+ ED_object_constraint_list_from_context(ob),
+ CONSTRAINT_TYPE_KINEMATIC,
+ with_targets);
}
void POSE_OT_ik_add(wmOperatorType *ot)
diff --git a/source/blender/editors/object/object_data_transform.c b/source/blender/editors/object/object_data_transform.c
index fc91cbb9666..54fd1fe6671 100644
--- a/source/blender/editors/object/object_data_transform.c
+++ b/source/blender/editors/object/object_data_transform.c
@@ -92,7 +92,7 @@ static struct ElemData_Armature *armature_coords_and_quats_get_recurse(
const ListBase *bone_base, struct ElemData_Armature *elem_array)
{
struct ElemData_Armature *elem = elem_array;
- for (const Bone *bone = bone_base->first; bone; bone = bone->next) {
+ LISTBASE_FOREACH (const Bone *, bone, bone_base) {
#define COPY_PTR(member) memcpy(elem->member, bone->member, sizeof(bone->member))
#define COPY_VAL(member) memcpy(&elem->member, &bone->member, sizeof(bone->member))
@@ -125,7 +125,7 @@ static const struct ElemData_Armature *armature_coords_and_quats_apply_with_mat4
ListBase *bone_base, const struct ElemData_Armature *elem_array, const float mat[4][4])
{
const struct ElemData_Armature *elem = elem_array;
- for (Bone *bone = bone_base->first; bone; bone = bone->next) {
+ LISTBASE_FOREACH (Bone *, bone, bone_base) {
#define COPY_PTR(member) memcpy(bone->member, elem->member, sizeof(bone->member))
#define COPY_VAL(member) memcpy(&bone->member, &elem->member, sizeof(bone->member))
diff --git a/source/blender/editors/object/object_edit.c b/source/blender/editors/object/object_edit.c
index 7faad5cdd0e..d522dcabae3 100644
--- a/source/blender/editors/object/object_edit.c
+++ b/source/blender/editors/object/object_edit.c
@@ -54,7 +54,7 @@
#include "IMB_imbuf_types.h"
-#include "BKE_anim.h"
+#include "BKE_anim_visualization.h"
#include "BKE_collection.h"
#include "BKE_constraint.h"
#include "BKE_context.h"
@@ -100,6 +100,8 @@
#include "RNA_define.h"
#include "RNA_enum_types.h"
+#include "CLG_log.h"
+
/* for menu/popup icons etc etc*/
#include "UI_interface.h"
@@ -112,21 +114,17 @@
#include "object_intern.h" // own include
+static CLG_LogRef LOG = {"ed.object.edit"};
+
/* prototypes */
typedef struct MoveToCollectionData MoveToCollectionData;
static void move_to_collection_menus_items(struct uiLayout *layout,
struct MoveToCollectionData *menu);
static ListBase selected_objects_get(bContext *C);
-/* ************* XXX **************** */
-static void error(const char *UNUSED(arg))
-{
-}
-
-/* port over here */
-static void error_libdata(void)
-{
-}
+/* -------------------------------------------------------------------- */
+/** \name Internal Utilities
+ * \{ */
Object *ED_object_context(bContext *C)
{
@@ -147,7 +145,11 @@ Object *ED_object_active_context(bContext *C)
return ob;
}
-/* ********************** object hiding *************************** */
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Hide Operator
+ * \{ */
static bool object_hide_poll(bContext *C)
{
@@ -166,7 +168,7 @@ static int object_hide_view_clear_exec(bContext *C, wmOperator *op)
const bool select = RNA_boolean_get(op->ptr, "select");
bool changed = false;
- for (Base *base = view_layer->object_bases.first; base; base = base->next) {
+ LISTBASE_FOREACH (Base *, base, &view_layer->object_bases) {
if (base->flag & BASE_HIDDEN) {
base->flag &= ~BASE_HIDDEN;
changed = true;
@@ -217,7 +219,7 @@ static int object_hide_view_set_exec(bContext *C, wmOperator *op)
bool changed = false;
/* Hide selected or unselected objects. */
- for (Base *base = view_layer->object_bases.first; base; base = base->next) {
+ LISTBASE_FOREACH (Base *, base, &view_layer->object_bases) {
if (!(base->flag & BASE_VISIBLE_VIEWLAYER)) {
continue;
}
@@ -321,7 +323,7 @@ void ED_collection_hide_menu_draw(const bContext *C, uiLayout *layout)
uiLayoutSetOperatorContext(layout, WM_OP_EXEC_REGION_WIN);
- for (LayerCollection *lc = lc_scene->layer_collections.first; lc; lc = lc->next) {
+ LISTBASE_FOREACH (LayerCollection *, lc, &lc_scene->layer_collections) {
int index = BKE_layer_collection_findindex(view_layer, lc);
uiLayout *row = uiLayoutRow(layout, false);
@@ -401,7 +403,11 @@ void OBJECT_OT_hide_collection(wmOperatorType *ot)
RNA_def_property_flag(prop, PROP_SKIP_SAVE | PROP_HIDDEN);
}
-/* ******************* toggle editmode operator ***************** */
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Toggle Edit-Mode Operator
+ * \{ */
static bool mesh_needs_keyindex(Main *bmain, const Mesh *me)
{
@@ -414,7 +420,7 @@ static bool mesh_needs_keyindex(Main *bmain, const Mesh *me)
return true;
}
if (ob->data == me) {
- for (const ModifierData *md = ob->modifiers.first; md; md = md->next) {
+ LISTBASE_FOREACH (const ModifierData *, md, &ob->modifiers) {
if (md->type == eModifierType_Hook) {
return true;
}
@@ -441,7 +447,11 @@ static bool ED_object_editmode_load_ex(Main *bmain, Object *obedit, const bool f
}
if (me->edit_mesh->bm->totvert > MESH_MAX_VERTS) {
- error("Too many vertices");
+ /* This used to be warned int the UI, we could warn again although it's quite rare. */
+ CLOG_WARN(&LOG,
+ "Too many vertices for mesh '%s' (%d)",
+ me->id.name + 2,
+ me->edit_mesh->bm->totvert);
return false;
}
@@ -454,8 +464,8 @@ static bool ED_object_editmode_load_ex(Main *bmain, Object *obedit, const bool f
}
/* will be recalculated as needed. */
{
- ED_mesh_mirror_spatial_table(NULL, NULL, NULL, NULL, 'e');
- ED_mesh_mirror_topo_table(NULL, NULL, 'e');
+ ED_mesh_mirror_spatial_table_end(obedit);
+ ED_mesh_mirror_topo_table_end(obedit);
}
}
else if (obedit->type == OB_ARMATURE) {
@@ -600,7 +610,8 @@ bool ED_object_editmode_enter_ex(Main *bmain, Scene *scene, Object *ob, int flag
}
if (BKE_object_obdata_is_libdata(ob)) {
- error_libdata();
+ /* Ideally the caller should check this. */
+ CLOG_WARN(&LOG, "Unable to enter edit-mode on library data for object '%s'", ob->id.name + 2);
return false;
}
@@ -777,7 +788,11 @@ void OBJECT_OT_editmode_toggle(wmOperatorType *ot)
ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
}
-/* *************************** */
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Toggle Pose-Mode Operator
+ * \{ */
static int posemode_exec(bContext *C, wmOperator *op)
{
@@ -861,12 +876,16 @@ void OBJECT_OT_posemode_toggle(wmOperatorType *ot)
ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
}
-/* ******************* force field toggle operator ***************** */
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Force Field Toggle Operator
+ * \{ */
void ED_object_check_force_modifiers(Main *bmain, Scene *scene, Object *object)
{
PartDeflect *pd = object->pd;
- ModifierData *md = modifiers_findByType(object, eModifierType_Surface);
+ ModifierData *md = BKE_modifiers_findby_type(object, eModifierType_Surface);
/* add/remove modifier as needed */
if (!md) {
@@ -924,8 +943,11 @@ void OBJECT_OT_forcefield_toggle(wmOperatorType *ot)
ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
}
-/* ********************************************** */
-/* Motion Paths */
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Calculate Motion Paths Operator
+ * \{ */
static eAnimvizCalcRange object_path_convert_range(eObjectPathCalcRange range)
{
@@ -1019,7 +1041,7 @@ static int object_calculate_paths_invoke(bContext *C, wmOperator *op, const wmEv
}
/* show popup dialog to allow editing of range... */
- /* FIXME: hardcoded dimensions here are just arbitrary */
+ /* FIXME: hard-coded dimensions here are just arbitrary. */
return WM_operator_props_dialog_popup(C, op, 200);
}
@@ -1088,7 +1110,11 @@ void OBJECT_OT_paths_calculate(wmOperatorType *ot)
MAXFRAME / 2.0);
}
-/* --------- */
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Update Motion Paths Operator
+ * \{ */
static bool object_update_paths_poll(bContext *C)
{
@@ -1132,7 +1158,11 @@ void OBJECT_OT_paths_update(wmOperatorType *ot)
ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
}
-/* --------- */
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Clear Motion Paths Operator
+ * \{ */
/* Helper for ED_objects_clear_paths() */
static void object_clear_mpath(Object *ob)
@@ -1151,14 +1181,14 @@ static void object_clear_mpath(Object *ob)
void ED_objects_clear_paths(bContext *C, bool only_selected)
{
if (only_selected) {
- /* loop over all selected + sedtiable objects in scene */
+ /* Loop over all selected + editable objects in scene. */
CTX_DATA_BEGIN (C, Object *, ob, selected_editable_objects) {
object_clear_mpath(ob);
}
CTX_DATA_END;
}
else {
- /* loop over all edtiable objects in scene */
+ /* Loop over all editable objects in scene. */
CTX_DATA_BEGIN (C, Object *, ob, editable_objects) {
object_clear_mpath(ob);
}
@@ -1210,13 +1240,17 @@ void OBJECT_OT_paths_clear(wmOperatorType *ot)
RNA_def_property_flag(ot->prop, PROP_SKIP_SAVE);
}
-/* --------- */
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Update Motion Paths Range from Scene Operator
+ * \{ */
static int object_update_paths_range_exec(bContext *C, wmOperator *UNUSED(op))
{
Scene *scene = CTX_data_scene(C);
- /* loop over all edtiable objects in scene */
+ /* Loop over all editable objects in scene. */
CTX_DATA_BEGIN (C, Object *, ob, editable_objects) {
/* use Preview Range or Full Frame Range - whichever is in use */
ob->avs.path_sf = PSFRA;
@@ -1246,63 +1280,99 @@ void OBJECT_OT_paths_range_update(wmOperatorType *ot)
ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
}
-/********************** Smooth/Flat *********************/
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Object Shade Smooth/Flat Operator
+ * \{ */
static int shade_smooth_exec(bContext *C, wmOperator *op)
{
- ID *data;
- Curve *cu;
- Nurb *nu;
- int clear = (STREQ(op->idname, "OBJECT_OT_shade_flat"));
- bool done = false, linked_data = false;
+ const bool use_smooth = STREQ(op->idname, "OBJECT_OT_shade_smooth");
+ bool changed_multi = false;
+ bool has_linked_data = false;
- CTX_DATA_BEGIN (C, Object *, ob, selected_editable_objects) {
- data = ob->data;
+ ListBase ctx_objects = {NULL, NULL};
+ CollectionPointerLink ctx_ob_single_active = {NULL};
+
+ /* For modes that only use an active object, don't handle the whole selection. */
+ {
+ ViewLayer *view_layer = CTX_data_view_layer(C);
+ Object *obact = OBACT(view_layer);
+ if (obact && ((obact->mode & OB_MODE_ALL_PAINT))) {
+ ctx_ob_single_active.ptr.data = obact;
+ BLI_addtail(&ctx_objects, &ctx_ob_single_active);
+ }
+ }
+
+ if (ctx_objects.first != &ctx_ob_single_active) {
+ CTX_data_selected_editable_objects(C, &ctx_objects);
+ }
+
+ for (CollectionPointerLink *ctx_ob = ctx_objects.first; ctx_ob; ctx_ob = ctx_ob->next) {
+ Object *ob = ctx_ob->ptr.data;
+ ID *data = ob->data;
+ if (data != NULL) {
+ data->tag |= LIB_TAG_DOIT;
+ }
+ }
+
+ for (CollectionPointerLink *ctx_ob = ctx_objects.first; ctx_ob; ctx_ob = ctx_ob->next) {
+ /* Always un-tag all object data-blocks irrespective of our ability to operate on them. */
+ Object *ob = ctx_ob->ptr.data;
+ ID *data = ob->data;
+ if ((data == NULL) || ((data->tag & LIB_TAG_DOIT) == 0)) {
+ continue;
+ }
+ data->tag &= ~LIB_TAG_DOIT;
+ /* Finished un-tagging, continue with regular logic. */
if (data && ID_IS_LINKED(data)) {
- linked_data = true;
+ has_linked_data = true;
continue;
}
+ bool changed = false;
if (ob->type == OB_MESH) {
- BKE_mesh_smooth_flag_set(ob->data, !clear);
-
+ BKE_mesh_smooth_flag_set(ob->data, use_smooth);
BKE_mesh_batch_cache_dirty_tag(ob->data, BKE_MESH_BATCH_DIRTY_ALL);
- DEG_id_tag_update(&ob->id, ID_RECALC_GEOMETRY);
- WM_event_add_notifier(C, NC_OBJECT | ND_DRAW, ob);
-
- done = true;
+ changed = true;
}
else if (ELEM(ob->type, OB_SURF, OB_CURVE)) {
- cu = ob->data;
+ BKE_curve_smooth_flag_set(ob->data, use_smooth);
+ changed = true;
+ }
- for (nu = cu->nurb.first; nu; nu = nu->next) {
- if (!clear) {
- nu->flag |= ME_SMOOTH;
- }
- else {
- nu->flag &= ~ME_SMOOTH;
- }
- }
+ if (changed) {
+ changed_multi = true;
DEG_id_tag_update(&ob->id, ID_RECALC_GEOMETRY);
WM_event_add_notifier(C, NC_OBJECT | ND_DRAW, ob);
-
- done = true;
}
}
- CTX_DATA_END;
- if (linked_data) {
+ if (ctx_objects.first != &ctx_ob_single_active) {
+ BLI_freelistN(&ctx_objects);
+ }
+
+ if (has_linked_data) {
BKE_report(op->reports, RPT_WARNING, "Can't edit linked mesh or curve data");
}
- return (done) ? OPERATOR_FINISHED : OPERATOR_CANCELLED;
+ return (changed_multi) ? OPERATOR_FINISHED : OPERATOR_CANCELLED;
}
static bool shade_poll(bContext *C)
{
- return (CTX_data_edit_object(C) == NULL);
+ ViewLayer *view_layer = CTX_data_view_layer(C);
+ Object *obact = OBACT(view_layer);
+ if (obact != NULL) {
+ /* Doesn't handle edit-data, sculpt dynamic-topology, or their undo systems. */
+ if (obact->mode & (OB_MODE_EDIT | OB_MODE_SCULPT)) {
+ return false;
+ }
+ }
+ return true;
}
void OBJECT_OT_shade_flat(wmOperatorType *ot)
@@ -1335,7 +1405,11 @@ void OBJECT_OT_shade_smooth(wmOperatorType *ot)
ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
}
-/* ********************** */
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Object Mode Set Operator
+ * \{ */
static const EnumPropertyItem *object_mode_set_itemsf(bContext *C,
PointerRNA *UNUSED(ptr),
@@ -1355,7 +1429,8 @@ static const EnumPropertyItem *object_mode_set_itemsf(bContext *C,
if (ob) {
const bool use_mode_particle_edit = (BLI_listbase_is_empty(&ob->particlesystem) == false) ||
(ob->soft != NULL) ||
- (modifiers_findByType(ob, eModifierType_Cloth) != NULL);
+ (BKE_modifiers_findby_type(ob, eModifierType_Cloth) !=
+ NULL);
while (input->identifier) {
if ((input->value == OB_MODE_EDIT && OB_TYPE_SUPPORT_EDITMODE(ob->type)) ||
(input->value == OB_MODE_POSE && (ob->type == OB_ARMATURE)) ||
@@ -1393,67 +1468,84 @@ static const EnumPropertyItem *object_mode_set_itemsf(bContext *C,
static bool object_mode_set_poll(bContext *C)
{
- /* Since Grease Pencil editmode is also handled here,
- * we have a special exception for allowing this operator
- * to still work in that case when there's no active object
- * so that users can exit editmode this way as per normal.
- */
- if (ED_operator_object_active_editable(C)) {
- return true;
- }
- else {
- return (CTX_data_gpencil_data(C) != NULL);
- }
+ /* Needed as #ED_operator_object_active_editable doesn't call use 'active_object'. */
+ Object *ob = CTX_data_active_object(C);
+ return ED_operator_object_active_editable_ex(C, ob);
}
static int object_mode_set_exec(bContext *C, wmOperator *op)
{
- bool use_submode = STREQ(op->idname, "OBJECT_OT_mode_set_with_submode");
+ const bool use_submode = STREQ(op->idname, "OBJECT_OT_mode_set_with_submode");
Object *ob = CTX_data_active_object(C);
eObjectMode mode = RNA_enum_get(op->ptr, "mode");
- eObjectMode restore_mode = (ob) ? ob->mode : OB_MODE_OBJECT;
const bool toggle = RNA_boolean_get(op->ptr, "toggle");
/* by default the operator assume is a mesh, but if gp object change mode */
- if ((ob != NULL) && (ob->type == OB_GPENCIL) && (mode == OB_MODE_EDIT)) {
+ if ((ob->type == OB_GPENCIL) && (mode == OB_MODE_EDIT)) {
mode = OB_MODE_EDIT_GPENCIL;
}
- if (!ob || !ED_object_mode_compat_test(ob, mode)) {
+ if (!ED_object_mode_compat_test(ob, mode)) {
return OPERATOR_PASS_THROUGH;
}
- if (ob->mode != mode) {
- /* we should be able to remove this call, each operator calls */
- ED_object_mode_compat_set(C, ob, mode, op->reports);
- }
-
- /* Exit current mode if it's not the mode we're setting */
- if (mode != OB_MODE_OBJECT && (ob->mode != mode || toggle)) {
- /* Enter new mode */
- ED_object_mode_toggle(C, mode);
- }
-
- if (toggle) {
- /* Special case for Object mode! */
- if (mode == OB_MODE_OBJECT && restore_mode == OB_MODE_OBJECT &&
- ob->restore_mode != OB_MODE_OBJECT) {
- ED_object_mode_toggle(C, ob->restore_mode);
- }
- else if (ob->mode == mode) {
- /* For toggling, store old mode so we know what to go back to */
- ob->restore_mode = restore_mode;
- }
- else if (ob->restore_mode != OB_MODE_OBJECT && ob->restore_mode != mode) {
- ED_object_mode_toggle(C, ob->restore_mode);
+ /**
+ * Mode Switching Logic (internal details).
+ *
+ * Notes:
+ * - Code below avoids calling mode switching functions more than once,
+ * as this causes unnecessary calculations and undo steps to be added.
+ * - The previous mode (#Object.restore_mode) is object mode by default.
+ *
+ * Supported Cases:
+ * - Setting the mode (when the 'toggle' setting is off).
+ * - Toggle the mode:
+ * - Toggle between object mode and non-object mode property.
+ * - Toggle between the previous mode (#Object.restore_mode) and the mode property.
+ * - Toggle object mode.
+ * While this is similar to regular toggle,
+ * this operator depends on there being a previous mode set
+ * (this isn't bound to a key with the default key-map).
+ */
+ if (toggle == false) {
+ if (ob->mode != mode) {
+ ED_object_mode_set_ex(C, mode, true, op->reports);
}
}
-
- /* if type is OB_GPENCIL, set cursor mode */
- if ((ob) && (ob->type == OB_GPENCIL)) {
- if (ob->data) {
- bGPdata *gpd = (bGPdata *)ob->data;
- ED_gpencil_setup_modes(C, gpd, ob->mode);
+ else {
+ const eObjectMode mode_prev = ob->mode;
+ /* When toggling object mode, we always use the restore mode,
+ * otherwise there is nothing to do. */
+ if (mode == OB_MODE_OBJECT) {
+ if (ob->mode != OB_MODE_OBJECT) {
+ if (ED_object_mode_set_ex(C, OB_MODE_OBJECT, true, op->reports)) {
+ /* Store old mode so we know what to go back to. */
+ ob->restore_mode = mode_prev;
+ }
+ }
+ else {
+ if (ob->restore_mode != OB_MODE_OBJECT) {
+ ED_object_mode_set_ex(C, ob->restore_mode, true, op->reports);
+ }
+ }
+ }
+ else {
+ /* Non-object modes, enter the 'mode' unless it's already set,
+ * in that case use restore mode. */
+ if (ob->mode != mode) {
+ if (ED_object_mode_set_ex(C, mode, true, op->reports)) {
+ /* Store old mode so we know what to go back to. */
+ ob->restore_mode = mode_prev;
+ }
+ }
+ else {
+ if (ob->restore_mode != OB_MODE_OBJECT) {
+ ED_object_mode_set_ex(C, ob->restore_mode, true, op->reports);
+ }
+ else {
+ ED_object_mode_set_ex(C, OB_MODE_OBJECT, true, op->reports);
+ }
+ }
}
}
@@ -1485,8 +1577,7 @@ void OBJECT_OT_mode_set(wmOperatorType *ot)
/* api callbacks */
ot->exec = object_mode_set_exec;
-
- ot->poll = object_mode_set_poll; // ED_operator_object_active_editable;
+ ot->poll = object_mode_set_poll;
/* flags */
ot->flag = 0; /* no register/undo here, leave it to operators being called */
@@ -1516,6 +1607,12 @@ void OBJECT_OT_mode_set_with_submode(wmOperatorType *ot)
RNA_def_property_flag(prop, PROP_HIDDEN | PROP_SKIP_SAVE);
}
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Object Link/Move to Collection Operator
+ * \{ */
+
static ListBase selected_objects_get(bContext *C)
{
ListBase objects = {NULL};
@@ -1593,7 +1690,7 @@ static int move_to_collection_exec(bContext *C, wmOperator *op)
return OPERATOR_CANCELLED;
}
- for (LinkData *link = objects.first; link; link = link->next) {
+ LISTBASE_FOREACH (LinkData *, link, &objects) {
Object *ob = link->data;
if (!is_link) {
@@ -1856,3 +1953,5 @@ void OBJECT_OT_link_to_collection(wmOperatorType *ot)
RNA_def_property_flag(prop, PROP_SKIP_SAVE);
ot->prop = prop;
}
+
+/** \} */
diff --git a/source/blender/editors/object/object_gpencil_modifier.c b/source/blender/editors/object/object_gpencil_modifier.c
index 5bf5c4bd95a..6d0f53cfa1e 100644
--- a/source/blender/editors/object/object_gpencil_modifier.c
+++ b/source/blender/editors/object/object_gpencil_modifier.c
@@ -65,7 +65,7 @@ GpencilModifierData *ED_object_gpencil_modifier_add(
ReportList *reports, Main *bmain, Scene *UNUSED(scene), Object *ob, const char *name, int type)
{
GpencilModifierData *new_md = NULL;
- const GpencilModifierTypeInfo *mti = BKE_gpencil_modifierType_getInfo(type);
+ const GpencilModifierTypeInfo *mti = BKE_gpencil_modifier_get_info(type);
if (ob->type != OB_GPENCIL) {
BKE_reportf(reports, RPT_WARNING, "Modifiers cannot be added to object '%s'", ob->id.name + 2);
@@ -73,7 +73,7 @@ GpencilModifierData *ED_object_gpencil_modifier_add(
}
if (mti->flags & eGpencilModifierTypeFlag_Single) {
- if (BKE_gpencil_modifiers_findByType(ob, type)) {
+ if (BKE_gpencil_modifiers_findby_type(ob, type)) {
BKE_report(reports, RPT_WARNING, "Only one modifier of this type is allowed");
return NULL;
}
@@ -214,7 +214,7 @@ int ED_object_gpencil_modifier_move_down(ReportList *UNUSED(reports),
static int gpencil_modifier_apply_obdata(
ReportList *reports, Main *bmain, Depsgraph *depsgraph, Object *ob, GpencilModifierData *md)
{
- const GpencilModifierTypeInfo *mti = BKE_gpencil_modifierType_getInfo(md->type);
+ const GpencilModifierTypeInfo *mti = BKE_gpencil_modifier_get_info(md->type);
if (mti->isDisabled && mti->isDisabled(md, 0)) {
BKE_report(reports, RPT_ERROR, "Modifier is disabled, skipping apply");
@@ -281,18 +281,18 @@ int ED_object_gpencil_modifier_apply(Main *bmain,
int ED_object_gpencil_modifier_copy(ReportList *reports, Object *ob, GpencilModifierData *md)
{
GpencilModifierData *nmd;
- const GpencilModifierTypeInfo *mti = BKE_gpencil_modifierType_getInfo(md->type);
+ const GpencilModifierTypeInfo *mti = BKE_gpencil_modifier_get_info(md->type);
GpencilModifierType type = md->type;
if (mti->flags & eGpencilModifierTypeFlag_Single) {
- if (BKE_gpencil_modifiers_findByType(ob, type)) {
+ if (BKE_gpencil_modifiers_findby_type(ob, type)) {
BKE_report(reports, RPT_WARNING, "Only one modifier of this type is allowed");
return 0;
}
}
nmd = BKE_gpencil_modifier_new(md->type);
- BKE_gpencil_modifier_copyData(md, nmd);
+ BKE_gpencil_modifier_copydata(md, nmd);
BLI_insertlinkafter(&ob->greasepencil_modifiers, md, nmd);
BKE_gpencil_modifier_unique_name(&ob->greasepencil_modifiers, nmd);
@@ -335,7 +335,7 @@ static const EnumPropertyItem *gpencil_modifier_add_itemf(bContext *C,
for (a = 0; rna_enum_object_greasepencil_modifier_type_items[a].identifier; a++) {
md_item = &rna_enum_object_greasepencil_modifier_type_items[a];
if (md_item->identifier[0]) {
- mti = BKE_gpencil_modifierType_getInfo(md_item->value);
+ mti = BKE_gpencil_modifier_get_info(md_item->value);
if (mti->flags & eGpencilModifierTypeFlag_NoUserAdd) {
continue;
@@ -455,7 +455,7 @@ static GpencilModifierData *gpencil_edit_modifier_property_get(wmOperator *op,
GpencilModifierData *md;
RNA_string_get(op->ptr, "modifier", modifier_name);
- md = BKE_gpencil_modifiers_findByName(ob, modifier_name);
+ md = BKE_gpencil_modifiers_findby_name(ob, modifier_name);
if (md && type != 0 && md->type != type) {
md = NULL;
diff --git a/source/blender/editors/object/object_hook.c b/source/blender/editors/object/object_hook.c
index 4414acff115..9d2e5e74352 100644
--- a/source/blender/editors/object/object_hook.c
+++ b/source/blender/editors/object/object_hook.c
@@ -552,14 +552,14 @@ static int add_hook_object(const bContext *C,
}
md = obedit->modifiers.first;
- while (md && modifierType_getInfo(md->type)->type == eModifierTypeType_OnlyDeform) {
+ while (md && BKE_modifier_get_info(md->type)->type == eModifierTypeType_OnlyDeform) {
md = md->next;
}
- hmd = (HookModifierData *)modifier_new(eModifierType_Hook);
+ hmd = (HookModifierData *)BKE_modifier_new(eModifierType_Hook);
BLI_insertlinkbefore(&obedit->modifiers, md, hmd);
BLI_snprintf(hmd->modifier.name, sizeof(hmd->modifier.name), "Hook-%s", ob->id.name + 2);
- modifier_unique_name(&obedit->modifiers, (ModifierData *)hmd);
+ BKE_modifier_unique_name(&obedit->modifiers, (ModifierData *)hmd);
hmd->object = ob;
hmd->indexar = indexar;
@@ -725,7 +725,7 @@ static int object_hook_remove_exec(bContext *C, wmOperator *op)
/* remove functionality */
BLI_remlink(&ob->modifiers, (ModifierData *)hmd);
- modifier_free((ModifierData *)hmd);
+ BKE_modifier_free((ModifierData *)hmd);
DEG_id_tag_update(&ob->id, ID_RECALC_GEOMETRY);
WM_event_add_notifier(C, NC_OBJECT | ND_MODIFIER, ob);
diff --git a/source/blender/editors/object/object_intern.h b/source/blender/editors/object/object_intern.h
index 559bb434f9d..d7a7b4ca110 100644
--- a/source/blender/editors/object/object_intern.h
+++ b/source/blender/editors/object/object_intern.h
@@ -169,6 +169,8 @@ void OBJECT_OT_multires_subdivide(struct wmOperatorType *ot);
void OBJECT_OT_multires_reshape(struct wmOperatorType *ot);
void OBJECT_OT_multires_higher_levels_delete(struct wmOperatorType *ot);
void OBJECT_OT_multires_base_apply(struct wmOperatorType *ot);
+void OBJECT_OT_multires_unsubdivide(struct wmOperatorType *ot);
+void OBJECT_OT_multires_rebuild_subdiv(struct wmOperatorType *ot);
void OBJECT_OT_multires_external_save(struct wmOperatorType *ot);
void OBJECT_OT_multires_external_pack(struct wmOperatorType *ot);
void OBJECT_OT_correctivesmooth_bind(struct wmOperatorType *ot);
@@ -291,6 +293,7 @@ void TRANSFORM_OT_vertex_random(struct wmOperatorType *ot);
/* object_remesh.c */
void OBJECT_OT_voxel_remesh(struct wmOperatorType *ot);
+void OBJECT_OT_voxel_size_edit(struct wmOperatorType *ot);
void OBJECT_OT_quadriflow_remesh(struct wmOperatorType *ot);
/* object_transfer_data.c */
diff --git a/source/blender/editors/object/object_modes.c b/source/blender/editors/object/object_modes.c
index f06b6a4db2a..c518fd32c7f 100644
--- a/source/blender/editors/object/object_modes.c
+++ b/source/blender/editors/object/object_modes.c
@@ -167,41 +167,6 @@ bool ED_object_mode_compat_set(bContext *C, Object *ob, eObjectMode mode, Report
return ok;
}
-void ED_object_mode_toggle(bContext *C, eObjectMode mode)
-{
- if (mode != OB_MODE_OBJECT) {
- const char *opstring = object_mode_op_string(mode);
-
- if (opstring) {
- wmOperatorType *ot = WM_operatortype_find(opstring, false);
- WM_operator_name_call_ptr(C, ot, WM_OP_EXEC_REGION_WIN, NULL);
- }
- }
-}
-
-/* Wrapper for operator */
-void ED_object_mode_set(bContext *C, eObjectMode mode)
-{
- wmWindowManager *wm = CTX_wm_manager(C);
- wm->op_undo_depth++;
- /* needed so we don't do undo pushes. */
- ED_object_mode_generic_enter(C, mode);
- wm->op_undo_depth--;
-}
-
-void ED_object_mode_exit(bContext *C, Depsgraph *depsgraph)
-{
- struct Main *bmain = CTX_data_main(C);
- Scene *scene = CTX_data_scene(C);
- ViewLayer *view_layer = CTX_data_view_layer(C);
- FOREACH_OBJECT_BEGIN (view_layer, ob) {
- if (ob->mode & OB_MODE_ALL_MODE_DATA) {
- ED_object_mode_generic_exit(bmain, depsgraph, scene, ob);
- }
- }
- FOREACH_OBJECT_END;
-}
-
/** \} */
/* -------------------------------------------------------------------- */
@@ -212,23 +177,50 @@ void ED_object_mode_exit(bContext *C, Depsgraph *depsgraph)
*
* \{ */
-bool ED_object_mode_generic_enter(struct bContext *C, eObjectMode object_mode)
+bool ED_object_mode_set_ex(bContext *C, eObjectMode mode, bool use_undo, ReportList *reports)
{
+ wmWindowManager *wm = CTX_wm_manager(C);
ViewLayer *view_layer = CTX_data_view_layer(C);
Object *ob = OBACT(view_layer);
if (ob == NULL) {
- return (object_mode == OB_MODE_OBJECT);
+ return (mode == OB_MODE_OBJECT);
}
- if (ob->mode == object_mode) {
+
+ if ((ob->type == OB_GPENCIL) && (mode == OB_MODE_EDIT)) {
+ mode = OB_MODE_EDIT_GPENCIL;
+ }
+
+ if (ob->mode == mode) {
return true;
}
- wmOperatorType *ot = WM_operatortype_find("OBJECT_OT_mode_set", false);
- PointerRNA ptr;
- WM_operator_properties_create_ptr(&ptr, ot);
- RNA_enum_set(&ptr, "mode", object_mode);
- WM_operator_name_call_ptr(C, ot, WM_OP_INVOKE_DEFAULT, &ptr);
- WM_operator_properties_free(&ptr);
- return (ob->mode == object_mode);
+
+ if (!ED_object_mode_compat_test(ob, mode)) {
+ return false;
+ }
+
+ const char *opstring = object_mode_op_string((mode == OB_MODE_OBJECT) ? ob->mode : mode);
+ wmOperatorType *ot = WM_operatortype_find(opstring, false);
+
+ if (!use_undo) {
+ wm->op_undo_depth++;
+ }
+ WM_operator_name_call_ptr(C, ot, WM_OP_EXEC_REGION_WIN, NULL);
+ if (!use_undo) {
+ wm->op_undo_depth--;
+ }
+
+ if (ob->mode != mode) {
+ BKE_reportf(reports, RPT_ERROR, "Unable to execute '%s', error changing modes", ot->name);
+ return false;
+ }
+
+ return true;
+}
+
+bool ED_object_mode_set(bContext *C, eObjectMode mode)
+{
+ /* Don't do undo push by default, since this may be called by lower level code. */
+ return ED_object_mode_set_ex(C, mode, true, NULL);
}
/**
@@ -282,6 +274,18 @@ static bool ed_object_mode_generic_exit_ex(struct Main *bmain,
ED_object_posemode_exit_ex(bmain, ob);
}
}
+ else if (ob->mode & OB_MODE_TEXTURE_PAINT) {
+ if (only_test) {
+ return true;
+ }
+ ED_object_texture_paint_mode_exit_ex(bmain, scene, ob);
+ }
+ else if (ob->mode & OB_MODE_PARTICLE_EDIT) {
+ if (only_test) {
+ return true;
+ }
+ ED_object_particle_edit_mode_exit_ex(scene, ob);
+ }
else if (ob->type == OB_GPENCIL) {
/* Accounted for above. */
BLI_assert((ob->mode & OB_MODE_OBJECT) == 0);
diff --git a/source/blender/editors/object/object_modifier.c b/source/blender/editors/object/object_modifier.c
index 0de2f114b94..9398a5f2ce7 100644
--- a/source/blender/editors/object/object_modifier.c
+++ b/source/blender/editors/object/object_modifier.c
@@ -86,6 +86,7 @@
#include "ED_mesh.h"
#include "ED_object.h"
#include "ED_screen.h"
+#include "ED_sculpt.h"
#include "WM_api.h"
#include "WM_types.h"
@@ -134,23 +135,24 @@ static void object_force_modifier_bind_simple_options(Depsgraph *depsgraph,
Object *object,
ModifierData *md)
{
- ModifierData *md_eval = (ModifierData *)modifier_get_evaluated(depsgraph, object, md);
+ ModifierData *md_eval = (ModifierData *)BKE_modifier_get_evaluated(depsgraph, object, md);
const int mode = md_eval->mode;
md_eval->mode |= eModifierMode_Realtime;
object_force_modifier_update_for_bind(depsgraph, object);
md_eval->mode = mode;
}
-/** Add a modifier to given object, including relevant extra processing needed by some physics
- * types (particles, simulations...).
+/**
+ * Add a modifier to given object, including relevant extra processing needed by some physics types
+ * (particles, simulations...).
*
- * \param scene is only used to set current frame in some cases, and may be NULL.
+ * \param scene: is only used to set current frame in some cases, and may be NULL.
*/
ModifierData *ED_object_modifier_add(
ReportList *reports, Main *bmain, Scene *scene, Object *ob, const char *name, int type)
{
ModifierData *md = NULL, *new_md = NULL;
- const ModifierTypeInfo *mti = modifierType_getInfo(type);
+ const ModifierTypeInfo *mti = BKE_modifier_get_info(type);
/* Check compatibility of modifier [T25291, T50373]. */
if (!BKE_object_support_modifier_type_check(ob, type)) {
@@ -159,7 +161,7 @@ ModifierData *ED_object_modifier_add(
}
if (mti->flags & eModifierTypeFlag_Single) {
- if (modifiers_findByType(ob, type)) {
+ if (BKE_modifiers_findby_type(ob, type)) {
BKE_report(reports, RPT_WARNING, "Only one modifier of this type is allowed");
return NULL;
}
@@ -173,12 +175,12 @@ ModifierData *ED_object_modifier_add(
}
else {
/* get new modifier data to add */
- new_md = modifier_new(type);
+ new_md = BKE_modifier_new(type);
if (mti->flags & eModifierTypeFlag_RequiresOriginalData) {
md = ob->modifiers.first;
- while (md && modifierType_getInfo(md->type)->type == eModifierTypeType_OnlyDeform) {
+ while (md && BKE_modifier_get_info(md->type)->type == eModifierTypeType_OnlyDeform) {
md = md->next;
}
@@ -194,7 +196,7 @@ ModifierData *ED_object_modifier_add(
/* make sure modifier data has unique name */
- modifier_unique_name(&ob->modifiers, new_md);
+ BKE_modifier_unique_name(&ob->modifiers, new_md);
/* special cases */
if (type == eModifierType_Softbody) {
@@ -381,7 +383,7 @@ static bool object_modifier_remove(Main *bmain,
}
BLI_remlink(&ob->modifiers, md);
- modifier_free(md);
+ BKE_modifier_free(md);
BKE_object_free_derived_caches(ob);
return 1;
@@ -431,10 +433,10 @@ void ED_object_modifier_clear(Main *bmain, Object *ob)
int ED_object_modifier_move_up(ReportList *reports, Object *ob, ModifierData *md)
{
if (md->prev) {
- const ModifierTypeInfo *mti = modifierType_getInfo(md->type);
+ const ModifierTypeInfo *mti = BKE_modifier_get_info(md->type);
if (mti->type != eModifierTypeType_OnlyDeform) {
- const ModifierTypeInfo *nmti = modifierType_getInfo(md->prev->type);
+ const ModifierTypeInfo *nmti = BKE_modifier_get_info(md->prev->type);
if (nmti->flags & eModifierTypeFlag_RequiresOriginalData) {
BKE_report(reports, RPT_WARNING, "Cannot move above a modifier requiring original data");
@@ -452,10 +454,10 @@ int ED_object_modifier_move_up(ReportList *reports, Object *ob, ModifierData *md
int ED_object_modifier_move_down(ReportList *reports, Object *ob, ModifierData *md)
{
if (md->next) {
- const ModifierTypeInfo *mti = modifierType_getInfo(md->type);
+ const ModifierTypeInfo *mti = BKE_modifier_get_info(md->type);
if (mti->flags & eModifierTypeFlag_RequiresOriginalData) {
- const ModifierTypeInfo *nmti = modifierType_getInfo(md->next->type);
+ const ModifierTypeInfo *nmti = BKE_modifier_get_info(md->next->type);
if (nmti->type != eModifierTypeType_OnlyDeform) {
BKE_report(reports, RPT_WARNING, "Cannot move beyond a non-deforming modifier");
@@ -618,7 +620,7 @@ static int modifier_apply_shape(Main *bmain,
Object *ob,
ModifierData *md_eval)
{
- const ModifierTypeInfo *mti = modifierType_getInfo(md_eval->type);
+ const ModifierTypeInfo *mti = BKE_modifier_get_info(md_eval->type);
if (mti->isDisabled && mti->isDisabled(scene, md_eval, 0)) {
BKE_report(reports, RPT_ERROR, "Modifier is disabled, skipping apply");
@@ -642,7 +644,7 @@ static int modifier_apply_shape(Main *bmain,
Key *key = me->key;
KeyBlock *kb;
- if (!modifier_isSameTopology(md_eval) || mti->type == eModifierTypeType_NonGeometrical) {
+ if (!BKE_modifier_is_same_topology(md_eval) || mti->type == eModifierTypeType_NonGeometrical) {
BKE_report(reports, RPT_ERROR, "Only deforming modifiers can be applied to shapes");
return 0;
}
@@ -678,7 +680,7 @@ static int modifier_apply_shape(Main *bmain,
static int modifier_apply_obdata(
ReportList *reports, Depsgraph *depsgraph, Scene *scene, Object *ob, ModifierData *md_eval)
{
- const ModifierTypeInfo *mti = modifierType_getInfo(md_eval->type);
+ const ModifierTypeInfo *mti = BKE_modifier_get_info(md_eval->type);
if (mti->isDisabled && mti->isDisabled(scene, md_eval, 0)) {
BKE_report(reports, RPT_ERROR, "Modifier is disabled, skipping apply");
@@ -789,7 +791,7 @@ bool ED_object_modifier_apply(Main *bmain,
return false;
}
else if ((ob->mode & OB_MODE_SCULPT) && (find_multires_modifier_before(scene, md)) &&
- (modifier_isSameTopology(md) == false)) {
+ (BKE_modifier_is_same_topology(md) == false)) {
BKE_report(reports,
RPT_ERROR,
"Constructive modifier cannot be applied to multi-res data in sculpt mode");
@@ -803,7 +805,7 @@ bool ED_object_modifier_apply(Main *bmain,
/* Get evaluated modifier, so object links pointer to evaluated data,
* but still use original object it is applied to the original mesh. */
Object *ob_eval = DEG_get_evaluated_object(depsgraph, ob);
- ModifierData *md_eval = (ob_eval) ? modifiers_findByName(ob_eval, md->name) : md;
+ ModifierData *md_eval = (ob_eval) ? BKE_modifiers_findby_name(ob_eval, md->name) : md;
/* allow apply of a not-realtime modifier, by first re-enabling realtime. */
prev_mode = md_eval->mode;
@@ -824,7 +826,7 @@ bool ED_object_modifier_apply(Main *bmain,
md_eval->mode = prev_mode;
BLI_remlink(&ob->modifiers, md);
- modifier_free(md);
+ BKE_modifier_free(md);
BKE_object_free_derived_caches(ob);
@@ -835,10 +837,10 @@ int ED_object_modifier_copy(ReportList *UNUSED(reports), Object *ob, ModifierDat
{
ModifierData *nmd;
- nmd = modifier_new(md->type);
- modifier_copyData(md, nmd);
+ nmd = BKE_modifier_new(md->type);
+ BKE_modifier_copydata(md, nmd);
BLI_insertlinkafter(&ob->modifiers, md, nmd);
- modifier_unique_name(&ob->modifiers, nmd);
+ BKE_modifier_unique_name(&ob->modifiers, nmd);
return 1;
}
@@ -884,7 +886,7 @@ static const EnumPropertyItem *modifier_add_itemf(bContext *C,
md_item = &rna_enum_object_modifier_type_items[a];
if (md_item->identifier[0]) {
- mti = modifierType_getInfo(md_item->value);
+ mti = BKE_modifier_get_info(md_item->value);
if (mti->flags & eModifierTypeFlag_NoUserAdd) {
continue;
@@ -1018,7 +1020,7 @@ ModifierData *edit_modifier_property_get(wmOperator *op, Object *ob, int type)
ModifierData *md;
RNA_string_get(op->ptr, "modifier", modifier_name);
- md = modifiers_findByName(ob, modifier_name);
+ md = BKE_modifiers_findby_name(ob, modifier_name);
if (md && type != 0 && md->type != type) {
md = NULL;
@@ -1198,7 +1200,7 @@ static bool modifier_apply_poll(bContext *C)
}
else if (md != NULL) {
if ((ob->mode & OB_MODE_SCULPT) && (find_multires_modifier_before(scene, md)) &&
- (modifier_isSameTopology(md) == false)) {
+ (BKE_modifier_is_same_topology(md) == false)) {
CTX_wm_operator_poll_msg_set(
C, "Constructive modifier cannot be applied to multi-res data in sculpt mode");
return false;
@@ -1431,6 +1433,25 @@ void OBJECT_OT_multires_higher_levels_delete(wmOperatorType *ot)
/** \name Multires Subdivide Operator
* \{ */
+static EnumPropertyItem prop_multires_subdivide_mode_type[] = {
+ {MULTIRES_SUBDIVIDE_CATMULL_CLARK,
+ "CATMULL_CLARK",
+ 0,
+ "Catmull-Clark",
+ "Create a new level using Catmull-Clark subdivisions"},
+ {MULTIRES_SUBDIVIDE_SIMPLE,
+ "SIMPLE",
+ 0,
+ "Simple",
+ "Create a new level using simple subdivisions"},
+ {MULTIRES_SUBDIVIDE_LINEAR,
+ "LINEAR",
+ 0,
+ "Linear",
+ "Create a new level using linear interpolation of the sculpted displacement"},
+ {0, NULL, 0, NULL, NULL},
+};
+
static int multires_subdivide_exec(bContext *C, wmOperator *op)
{
Object *object = ED_object_active_context(C);
@@ -1441,7 +1462,9 @@ static int multires_subdivide_exec(bContext *C, wmOperator *op)
return OPERATOR_CANCELLED;
}
- multiresModifier_subdivide(object, mmd);
+ const eMultiresSubdivideModeType subdivide_mode = (eMultiresSubdivideModeType)(
+ RNA_enum_get(op->ptr, "mode"));
+ multiresModifier_subdivide(object, mmd, subdivide_mode);
ED_object_iter_other(
CTX_data_main(C), object, true, ED_object_multires_update_totlevels_cb, &mmd->totlvl);
@@ -1480,6 +1503,12 @@ void OBJECT_OT_multires_subdivide(wmOperatorType *ot)
/* flags */
ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO | OPTYPE_INTERNAL;
edit_modifier_properties(ot);
+ RNA_def_enum(ot->srna,
+ "mode",
+ prop_multires_subdivide_mode_type,
+ MULTIRES_SUBDIVIDE_CATMULL_CLARK,
+ "Subdivision Mode",
+ "How the mesh is going to be subdivided to create a new level");
}
/** \} */
@@ -1697,8 +1726,12 @@ static int multires_base_apply_exec(bContext *C, wmOperator *op)
return OPERATOR_CANCELLED;
}
+ ED_sculpt_undo_push_multires_mesh_begin(C, op->type->name);
+
multiresModifier_base_apply(depsgraph, object, mmd);
+ ED_sculpt_undo_push_multires_mesh_end(C, op->type->name);
+
DEG_id_tag_update(&object->id, ID_RECALC_GEOMETRY);
WM_event_add_notifier(C, NC_OBJECT | ND_MODIFIER, object);
@@ -1726,6 +1759,119 @@ void OBJECT_OT_multires_base_apply(wmOperatorType *ot)
ot->exec = multires_base_apply_exec;
/* flags */
+ ot->flag = OPTYPE_REGISTER | OPTYPE_INTERNAL;
+ edit_modifier_properties(ot);
+}
+
+/** \} */
+
+/* ------------------------------------------------------------------- */
+/** \name Multires Unsubdivide
+ * \{ */
+
+static int multires_unsubdivide_exec(bContext *C, wmOperator *op)
+{
+ Depsgraph *depsgraph = CTX_data_depsgraph_pointer(C);
+ Object *object = ED_object_active_context(C);
+ MultiresModifierData *mmd = (MultiresModifierData *)edit_modifier_property_get(
+ op, object, eModifierType_Multires);
+
+ if (!mmd) {
+ return OPERATOR_CANCELLED;
+ }
+
+ int new_levels = multiresModifier_rebuild_subdiv(depsgraph, object, mmd, 1, true);
+ if (new_levels == 0) {
+ BKE_report(op->reports, RPT_ERROR, "Not valid subdivisions found to rebuild a lower level");
+ return OPERATOR_CANCELLED;
+ }
+
+ DEG_id_tag_update(&object->id, ID_RECALC_GEOMETRY);
+ WM_event_add_notifier(C, NC_OBJECT | ND_MODIFIER, object);
+
+ return OPERATOR_FINISHED;
+}
+
+static int multires_unsubdivide_invoke(bContext *C, wmOperator *op, const wmEvent *UNUSED(event))
+{
+ if (edit_modifier_invoke_properties(C, op)) {
+ return multires_unsubdivide_exec(C, op);
+ }
+ else {
+ return OPERATOR_CANCELLED;
+ }
+}
+
+void OBJECT_OT_multires_unsubdivide(wmOperatorType *ot)
+{
+ ot->name = "Unsubdivide";
+ ot->description = "Rebuild a lower subdivision level of the current base mesh";
+ ot->idname = "OBJECT_OT_multires_unsubdivide";
+
+ ot->poll = multires_poll;
+ ot->invoke = multires_unsubdivide_invoke;
+ ot->exec = multires_unsubdivide_exec;
+
+ /* flags */
+ ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO | OPTYPE_INTERNAL;
+ edit_modifier_properties(ot);
+}
+
+/** \} */
+
+/* ------------------------------------------------------------------- */
+/** \name Multires Rebuild Subdivisions
+ * \{ */
+
+static int multires_rebuild_subdiv_exec(bContext *C, wmOperator *op)
+{
+ Depsgraph *depsgraph = CTX_data_depsgraph_pointer(C);
+ Object *object = ED_object_active_context(C);
+ MultiresModifierData *mmd = (MultiresModifierData *)edit_modifier_property_get(
+ op, object, eModifierType_Multires);
+
+ if (!mmd) {
+ return OPERATOR_CANCELLED;
+ }
+
+ int new_levels = multiresModifier_rebuild_subdiv(depsgraph, object, mmd, INT_MAX, false);
+ if (new_levels == 0) {
+ BKE_report(op->reports, RPT_ERROR, "Not valid subdivisions found to rebuild lower levels");
+ return OPERATOR_CANCELLED;
+ }
+
+ BKE_reportf(op->reports, RPT_INFO, "%d new levels rebuilt", new_levels);
+
+ DEG_id_tag_update(&object->id, ID_RECALC_GEOMETRY);
+ WM_event_add_notifier(C, NC_OBJECT | ND_MODIFIER, object);
+
+ return OPERATOR_FINISHED;
+}
+
+static int multires_rebuild_subdiv_invoke(bContext *C,
+ wmOperator *op,
+ const wmEvent *UNUSED(event))
+{
+ if (edit_modifier_invoke_properties(C, op)) {
+ return multires_rebuild_subdiv_exec(C, op);
+ }
+ else {
+ return OPERATOR_CANCELLED;
+ }
+}
+
+void OBJECT_OT_multires_rebuild_subdiv(wmOperatorType *ot)
+{
+ ot->name = "Rebuild Lower Subdivisions";
+ ot->description =
+ "Rebuilds all possible subdivisions levels to generate a lower resolution base mesh";
+ ot->idname = "OBJECT_OT_multires_rebuild_subdiv";
+
+ ot->poll = multires_poll;
+ ot->invoke = multires_rebuild_subdiv_invoke;
+ ot->exec = multires_rebuild_subdiv_exec;
+
+ /* flags */
ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO | OPTYPE_INTERNAL;
edit_modifier_properties(ot);
}
@@ -2066,7 +2212,7 @@ static int skin_armature_create_exec(bContext *C, wmOperator *op)
arm_ob = modifier_skin_armature_create(depsgraph, bmain, scene, ob);
/* add a modifier to connect the new armature to the mesh */
- arm_md = (ArmatureModifierData *)modifier_new(eModifierType_Armature);
+ arm_md = (ArmatureModifierData *)BKE_modifier_new(eModifierType_Armature);
if (arm_md) {
skin_md = edit_modifier_property_get(op, ob, eModifierType_Skin);
BLI_insertlinkafter(&ob->modifiers, skin_md, arm_md);
@@ -2130,7 +2276,7 @@ static int correctivesmooth_bind_exec(bContext *C, wmOperator *op)
return OPERATOR_CANCELLED;
}
- if (!modifier_isEnabled(scene, &csmd->modifier, eModifierMode_Realtime)) {
+ if (!BKE_modifier_is_enabled(scene, &csmd->modifier, eModifierMode_Realtime)) {
BKE_report(op->reports, RPT_ERROR, "Modifier is disabled");
return OPERATOR_CANCELLED;
}
@@ -2147,8 +2293,8 @@ static int correctivesmooth_bind_exec(bContext *C, wmOperator *op)
else {
/* Signal to modifier to recalculate. */
CorrectiveSmoothModifierData *csmd_eval = (CorrectiveSmoothModifierData *)
- modifier_get_evaluated(depsgraph, ob, &csmd->modifier);
- csmd_eval->bind_coords_num = (unsigned int)-1;
+ BKE_modifier_get_evaluated(depsgraph, ob, &csmd->modifier);
+ csmd_eval->bind_coords_num = (uint)-1;
/* Force modifier to run, it will call binding routine
* (this has to happen outside of depsgraph evaluation). */
@@ -2226,7 +2372,7 @@ static int meshdeform_bind_exec(bContext *C, wmOperator *op)
else {
/* Force modifier to run, it will call binding routine
* (this has to happen outside of depsgraph evaluation). */
- MeshDeformModifierData *mmd_eval = (MeshDeformModifierData *)modifier_get_evaluated(
+ MeshDeformModifierData *mmd_eval = (MeshDeformModifierData *)BKE_modifier_get_evaluated(
depsgraph, ob, &mmd->modifier);
mmd_eval->bindfunc = ED_mesh_deform_bind_callback;
object_force_modifier_bind_simple_options(depsgraph, ob, &mmd->modifier);
@@ -2431,7 +2577,7 @@ static int ocean_bake_exec(bContext *C, wmOperator *op)
}
och = BKE_ocean_init_cache(omd->cachepath,
- modifier_path_relbase(bmain, ob),
+ BKE_modifier_path_relbase(bmain, ob),
omd->bakestart,
omd->bakeend,
omd->wave_scale,
@@ -2450,7 +2596,7 @@ static int ocean_bake_exec(bContext *C, wmOperator *op)
* No drivers or other modifier parameters. */
/* TODO(sergey): This operates on an original data, so no flush is needed. However, baking
* usually should happen on an evaluated objects, so this seems to be deeper issue here. */
- BKE_animsys_evaluate_animdata(scene, (ID *)ob, ob->adt, f, ADT_RECALC_ANIM, false);
+ BKE_animsys_evaluate_animdata((ID *)ob, ob->adt, f, ADT_RECALC_ANIM, false);
och->time[i] = omd->time;
i++;
@@ -2554,8 +2700,8 @@ static int laplaciandeform_bind_exec(bContext *C, wmOperator *op)
lmd->flag |= MOD_LAPLACIANDEFORM_BIND;
}
- LaplacianDeformModifierData *lmd_eval = (LaplacianDeformModifierData *)modifier_get_evaluated(
- depsgraph, ob, &lmd->modifier);
+ LaplacianDeformModifierData *lmd_eval = (LaplacianDeformModifierData *)
+ BKE_modifier_get_evaluated(depsgraph, ob, &lmd->modifier);
lmd_eval->flag = lmd->flag;
/* Force modifier to run, it will call binding routine
@@ -2633,7 +2779,7 @@ static int surfacedeform_bind_exec(bContext *C, wmOperator *op)
smd->flags |= MOD_SDEF_BIND;
}
- SurfaceDeformModifierData *smd_eval = (SurfaceDeformModifierData *)modifier_get_evaluated(
+ SurfaceDeformModifierData *smd_eval = (SurfaceDeformModifierData *)BKE_modifier_get_evaluated(
depsgraph, ob, &smd->modifier);
smd_eval->flags = smd->flags;
diff --git a/source/blender/editors/object/object_ops.c b/source/blender/editors/object/object_ops.c
index cacf7b67777..819b6c18a44 100644
--- a/source/blender/editors/object/object_ops.c
+++ b/source/blender/editors/object/object_ops.c
@@ -137,6 +137,8 @@ void ED_operatortypes_object(void)
WM_operatortype_append(OBJECT_OT_multires_reshape);
WM_operatortype_append(OBJECT_OT_multires_higher_levels_delete);
WM_operatortype_append(OBJECT_OT_multires_base_apply);
+ WM_operatortype_append(OBJECT_OT_multires_unsubdivide);
+ WM_operatortype_append(OBJECT_OT_multires_rebuild_subdiv);
WM_operatortype_append(OBJECT_OT_multires_external_save);
WM_operatortype_append(OBJECT_OT_multires_external_pack);
WM_operatortype_append(OBJECT_OT_skin_root_mark);
@@ -265,6 +267,8 @@ void ED_operatortypes_object(void)
WM_operatortype_append(OBJECT_OT_hide_collection);
WM_operatortype_append(OBJECT_OT_voxel_remesh);
+ WM_operatortype_append(OBJECT_OT_voxel_size_edit);
+
WM_operatortype_append(OBJECT_OT_quadriflow_remesh);
}
diff --git a/source/blender/editors/object/object_random.c b/source/blender/editors/object/object_random.c
index 43aaecb887b..a6958c798f1 100644
--- a/source/blender/editors/object/object_random.c
+++ b/source/blender/editors/object/object_random.c
@@ -50,7 +50,7 @@ static bool object_rand_transverts(TransVertStore *tvs,
const float offset,
const float uniform,
const float normal_factor,
- const unsigned int seed)
+ const uint seed)
{
bool use_normal = (normal_factor != 0.0f);
struct RNG *rng;
@@ -100,7 +100,7 @@ static int object_rand_verts_exec(bContext *C, wmOperator *op)
const float offset = RNA_float_get(op->ptr, "offset");
const float uniform = RNA_float_get(op->ptr, "uniform");
const float normal_factor = RNA_float_get(op->ptr, "normal");
- const unsigned int seed = RNA_int_get(op->ptr, "seed");
+ const uint seed = RNA_int_get(op->ptr, "seed");
bool changed_multi = false;
uint objects_len = 0;
diff --git a/source/blender/editors/object/object_relations.c b/source/blender/editors/object/object_relations.c
index 3166c9ddea1..0e8545e07ba 100644
--- a/source/blender/editors/object/object_relations.c
+++ b/source/blender/editors/object/object_relations.c
@@ -55,7 +55,7 @@
#include "BKE_DerivedMesh.h"
#include "BKE_action.h"
-#include "BKE_animsys.h"
+#include "BKE_anim_data.h"
#include "BKE_armature.h"
#include "BKE_camera.h"
#include "BKE_collection.h"
@@ -557,7 +557,7 @@ static void object_remove_parent_deform_modifiers(Object *ob, const Object *par)
/* free modifier if match */
if (free) {
BLI_remlink(&ob->modifiers, md);
- modifier_free(md);
+ BKE_modifier_free(md);
}
}
}
@@ -803,7 +803,7 @@ bool ED_object_parent_set(ReportList *reports,
switch (partype) {
case PAR_CURVE: /* curve deform */
- if (modifiers_isDeformedByCurve(ob) != par) {
+ if (BKE_modifiers_is_deformed_by_curve(ob) != par) {
md = ED_object_modifier_add(reports, bmain, scene, ob, NULL, eModifierType_Curve);
if (md) {
((CurveModifierData *)md)->object = par;
@@ -814,7 +814,7 @@ bool ED_object_parent_set(ReportList *reports,
}
break;
case PAR_LATTICE: /* lattice deform */
- if (modifiers_isDeformedByLattice(ob) != par) {
+ if (BKE_modifiers_is_deformed_by_lattice(ob) != par) {
md = ED_object_modifier_add(
reports, bmain, scene, ob, NULL, eModifierType_Lattice);
if (md) {
@@ -823,7 +823,7 @@ bool ED_object_parent_set(ReportList *reports,
}
break;
default: /* armature deform */
- if (modifiers_isDeformedByArmature(ob) != par) {
+ if (BKE_modifiers_is_deformed_by_armature(ob) != par) {
md = ED_object_modifier_add(
reports, bmain, scene, ob, NULL, eModifierType_Armature);
if (md) {
@@ -899,7 +899,10 @@ bool ED_object_parent_set(ReportList *reports,
invert_m4_m4(ob->parentinv, workob.obmat);
}
else if (pararm && (ob->type == OB_GPENCIL) && (par->type == OB_ARMATURE)) {
- if (partype == PAR_ARMATURE_NAME) {
+ if (partype == PAR_ARMATURE) {
+ ED_gpencil_add_armature(C, reports, ob, par);
+ }
+ else if (partype == PAR_ARMATURE_NAME) {
ED_gpencil_add_armature_weights(C, reports, ob, par, GP_PAR_ARMATURE_NAME);
}
else if ((partype == PAR_ARMATURE_AUTO) || (partype == PAR_ARMATURE_ENVELOPE)) {
@@ -1424,7 +1427,7 @@ void OBJECT_OT_track_set(wmOperatorType *ot)
* \{ */
#if 0
-static void link_to_scene(Main *UNUSED(bmain), unsigned short UNUSED(nr))
+static void link_to_scene(Main *UNUSED(bmain), ushort UNUSED(nr))
{
Scene *sce = (Scene *)BLI_findlink(&bmain->scene, G.curscreen->scenenr - 1);
Base *base, *nbase;
@@ -1753,7 +1756,7 @@ static void libblock_relink_collection(Collection *collection, const bool do_col
BKE_libblock_relink_to_newid(&cob->ob->id);
}
- for (CollectionChild *child = collection->children.first; child; child = child->next) {
+ LISTBASE_FOREACH (CollectionChild *, child, &collection->children) {
libblock_relink_collection(child->collection, true);
}
}
@@ -1772,7 +1775,7 @@ static Collection *single_object_users_collection(Main *bmain,
}
/* We do not remap to new objects here, this is done in separate step. */
- for (CollectionObject *cob = collection->gobject.first; cob; cob = cob->next) {
+ LISTBASE_FOREACH (CollectionObject *, cob, &collection->gobject) {
Object *ob = cob->ob;
/* an object may be in more than one collection */
if ((ob->id.newid == NULL) && ((ob->flag & flag) == flag)) {
@@ -2069,7 +2072,7 @@ void ED_object_single_users(Main *bmain,
/* Duplicating obdata and other IDs may require another update of the collections and objects
* pointers, especially regarding drivers and custom props, see T66641.
- * Note that this whole scene duplication code and 'make single user' functions have te be
+ * Note that this whole scene duplication code and 'make single user' functions have to be
* rewritten at some point to make use of proper modern ID management code,
* but that is no small task.
* For now we are doomed to that kind of band-aid to try to cover most of remapping cases. */
@@ -2106,7 +2109,7 @@ void ED_object_single_users(Main *bmain,
if (scene->nodetree) {
IDP_RelinkProperty(scene->nodetree->id.properties);
- for (bNode *node = scene->nodetree->nodes.first; node; node = node->next) {
+ LISTBASE_FOREACH (bNode *, node, &scene->nodetree->nodes) {
IDP_RelinkProperty(node->prop);
}
}
@@ -2245,7 +2248,7 @@ static void make_local_animdata_tag(AnimData *adt)
/* TODO: need to handle the ID-targets too? */
/* NLA Data */
- for (NlaTrack *nlt = adt->nla_tracks.first; nlt; nlt = nlt->next) {
+ LISTBASE_FOREACH (NlaTrack *, nlt, &adt->nla_tracks) {
make_local_animdata_tag_strips(&nlt->strips);
}
}
@@ -2513,7 +2516,8 @@ static int make_override_library_exec(bContext *C, wmOperator *op)
ViewLayer *view_layer = CTX_data_view_layer(C);
Collection *new_collection = (Collection *)collection->id.newid;
- BKE_collection_child_add(bmain, scene->master_collection, new_collection);
+ BKE_collection_add_from_object(bmain, scene, obcollection, new_collection);
+
FOREACH_COLLECTION_OBJECT_RECURSIVE_BEGIN (new_collection, new_ob) {
if (new_ob != NULL && new_ob->id.override_library != NULL) {
if ((base = BKE_view_layer_base_find(view_layer, new_ob)) == NULL) {
@@ -2521,14 +2525,7 @@ static int make_override_library_exec(bContext *C, wmOperator *op)
base = BKE_view_layer_base_find(view_layer, new_ob);
DEG_id_tag_update_ex(bmain, &new_ob->id, ID_RECALC_TRANSFORM | ID_RECALC_BASE_FLAGS);
}
- /* parent to 'collection' empty */
- /* Disabled for now, according to some artist this is probably not really useful anyway.
- * And it breaks things like objects parented to bones
- * (most likely due to missing proper setting of inverse parent matrix?)... */
- /* Note: we might even actually want to get rid of that instantiating empty... */
- if (0 && new_ob->parent == NULL) {
- new_ob->parent = obcollection;
- }
+
if (new_ob == (Object *)obact->id.newid) {
/* TODO: is setting active needed? */
BKE_view_layer_base_select_and_set_active(view_layer, base);
@@ -2543,9 +2540,9 @@ static int make_override_library_exec(bContext *C, wmOperator *op)
}
FOREACH_COLLECTION_OBJECT_RECURSIVE_END;
- /* obcollection is no more duplicollection-ing,
- * it merely parents whole collection of overriding instantiated objects. */
- obcollection->instance_collection = NULL;
+ /* Remove the instance empty from this scene, the items now have an overridden collection
+ * instead. */
+ ED_object_base_free_and_unlink(bmain, scene, obcollection);
/* Also, we'd likely want to lock by default things like
* transformations of implicitly overridden objects? */
diff --git a/source/blender/editors/object/object_remesh.c b/source/blender/editors/object/object_remesh.c
index a9f2319d926..22869748b22 100644
--- a/source/blender/editors/object/object_remesh.c
+++ b/source/blender/editors/object/object_remesh.c
@@ -37,6 +37,9 @@
#include "DNA_meshdata_types.h"
#include "DNA_object_types.h"
#include "DNA_scene_types.h"
+#include "DNA_userdef_types.h"
+
+#include "BLT_translation.h"
#include "BKE_context.h"
#include "BKE_customdata.h"
@@ -61,22 +64,38 @@
#include "ED_object.h"
#include "ED_screen.h"
#include "ED_sculpt.h"
+#include "ED_space_api.h"
#include "ED_undo.h"
+#include "ED_view3d.h"
#include "RNA_access.h"
#include "RNA_define.h"
#include "RNA_enum_types.h"
+#include "GPU_draw.h"
+#include "GPU_immediate.h"
+#include "GPU_immediate_util.h"
+#include "GPU_matrix.h"
+#include "GPU_state.h"
+
#include "WM_api.h"
#include "WM_message.h"
#include "WM_toolsystem.h"
#include "WM_types.h"
+#include "UI_interface.h"
+
+#include "BLF_api.h"
+
#include "object_intern.h" // own include
/* TODO(sebpa): unstable, can lead to unrecoverable errors. */
// #define USE_MESH_CURVATURE
+/* -------------------------------------------------------------------- */
+/** \name Voxel Remesh Operator
+ * \{ */
+
static bool object_remesh_poll(bContext *C)
{
Object *ob = CTX_data_active_object(C);
@@ -95,7 +114,7 @@ static bool object_remesh_poll(bContext *C)
return false;
}
- if (modifiers_usesMultires(ob)) {
+ if (BKE_modifiers_uses_multires(ob)) {
CTX_wm_operator_poll_msg_set(
C, "The remesher cannot run with a Multires modifier in the modifier stack");
return false;
@@ -188,16 +207,413 @@ void OBJECT_OT_voxel_remesh(wmOperatorType *ot)
ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
}
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Voxel Size Operator
+ * \{ */
+
+#define VOXEL_SIZE_EDIT_MAX_GRIDS_LINES 500
+#define VOXEL_SIZE_EDIT_MAX_STR_LEN 20
+
+typedef struct VoxelSizeEditCustomData {
+ void *draw_handle;
+ Object *active_object;
+
+ float init_mval[2];
+ float slow_mval[2];
+
+ bool slow_mode;
+
+ float init_voxel_size;
+ float slow_voxel_size;
+ float voxel_size;
+
+ float preview_plane[4][3];
+
+ float text_mat[4][4];
+} VoxelSizeEditCustomData;
+
+static void voxel_size_parallel_lines_draw(uint pos3d,
+ const float initial_co[3],
+ const float end_co[3],
+ const float length_co[3],
+ const float spacing)
+{
+ const float total_len = len_v3v3(initial_co, end_co);
+ const int tot_lines = (int)(total_len / spacing);
+ const int tot_lines_half = (tot_lines / 2) + 1;
+ float spacing_dir[3], lines_start[3];
+ float line_dir[3];
+ sub_v3_v3v3(spacing_dir, end_co, initial_co);
+ normalize_v3(spacing_dir);
+
+ sub_v3_v3v3(line_dir, length_co, initial_co);
+
+ if (tot_lines > VOXEL_SIZE_EDIT_MAX_GRIDS_LINES || tot_lines <= 1) {
+ return;
+ }
+
+ mid_v3_v3v3(lines_start, initial_co, end_co);
+
+ immBegin(GPU_PRIM_LINES, (uint)tot_lines_half * 2);
+ for (int i = 0; i < tot_lines_half; i++) {
+ float line_start[3];
+ float line_end[3];
+ madd_v3_v3v3fl(line_start, lines_start, spacing_dir, spacing * i);
+ add_v3_v3v3(line_end, line_start, line_dir);
+ immVertex3fv(pos3d, line_start);
+ immVertex3fv(pos3d, line_end);
+ }
+ immEnd();
+
+ mul_v3_fl(spacing_dir, -1.0f);
+
+ immBegin(GPU_PRIM_LINES, (uint)(tot_lines_half - 1) * 2);
+ for (int i = 1; i < tot_lines_half; i++) {
+ float line_start[3];
+ float line_end[3];
+ madd_v3_v3v3fl(line_start, lines_start, spacing_dir, spacing * i);
+ add_v3_v3v3(line_end, line_start, line_dir);
+ immVertex3fv(pos3d, line_start);
+ immVertex3fv(pos3d, line_end);
+ }
+ immEnd();
+}
+
+static void voxel_size_edit_draw(const bContext *UNUSED(C), ARegion *UNUSED(ar), void *arg)
+{
+ VoxelSizeEditCustomData *cd = arg;
+
+ GPU_blend(true);
+ GPU_line_smooth(true);
+
+ uint pos3d = GPU_vertformat_attr_add(immVertexFormat(), "pos", GPU_COMP_F32, 3, GPU_FETCH_FLOAT);
+ immBindBuiltinProgram(GPU_SHADER_3D_UNIFORM_COLOR);
+ GPU_matrix_push();
+ GPU_matrix_mul(cd->active_object->obmat);
+
+ /* Draw Rect */
+ immUniformColor4f(0.9f, 0.9f, 0.9f, 0.8f);
+ GPU_line_width(3.0f);
+
+ immBegin(GPU_PRIM_LINES, 8);
+ immVertex3fv(pos3d, cd->preview_plane[0]);
+ immVertex3fv(pos3d, cd->preview_plane[1]);
+
+ immVertex3fv(pos3d, cd->preview_plane[1]);
+ immVertex3fv(pos3d, cd->preview_plane[2]);
+
+ immVertex3fv(pos3d, cd->preview_plane[2]);
+ immVertex3fv(pos3d, cd->preview_plane[3]);
+
+ immVertex3fv(pos3d, cd->preview_plane[3]);
+ immVertex3fv(pos3d, cd->preview_plane[0]);
+ immEnd();
+
+ /* Draw Grid */
+ GPU_line_width(1.0f);
+
+ const float total_len = len_v3v3(cd->preview_plane[0], cd->preview_plane[1]);
+ const int tot_lines = (int)(total_len / cd->voxel_size);
+
+ /* Smoothstep to reduce the alpha of the grid as the line number increases. */
+ const float a = VOXEL_SIZE_EDIT_MAX_GRIDS_LINES * 0.1f;
+ const float b = VOXEL_SIZE_EDIT_MAX_GRIDS_LINES;
+ const float x = clamp_f((tot_lines - a) / (b - a), 0.0f, 1.0);
+ const float alpha_factor = 1.0f - (x * x * (3.0f - 2.0f * x));
+
+ immUniformColor4f(0.9f, 0.9f, 0.9f, 0.75f * alpha_factor);
+ voxel_size_parallel_lines_draw(
+ pos3d, cd->preview_plane[0], cd->preview_plane[1], cd->preview_plane[3], cd->voxel_size);
+ voxel_size_parallel_lines_draw(
+ pos3d, cd->preview_plane[1], cd->preview_plane[2], cd->preview_plane[0], cd->voxel_size);
+
+ /* Draw text */
+ const uiStyle *style = UI_style_get();
+ const uiFontStyle *fstyle = &style->widget;
+ const int fontid = fstyle->uifont_id;
+ float strwidth, strheight;
+ short fstyle_points = fstyle->points;
+ char str[VOXEL_SIZE_EDIT_MAX_STR_LEN];
+ short strdrawlen = 0;
+
+ BLI_snprintf(str, VOXEL_SIZE_EDIT_MAX_STR_LEN, "%3.4f%%", cd->voxel_size);
+ strdrawlen = BLI_strlen_utf8(str);
+
+ immUnbindProgram();
+
+ GPU_matrix_push();
+ GPU_matrix_mul(cd->text_mat);
+ BLF_size(fontid, 10.0f * fstyle_points, U.dpi);
+ BLF_color3f(fontid, 1.0f, 1.0f, 1.0f);
+ BLF_width_and_height(fontid, str, strdrawlen, &strwidth, &strheight);
+ BLF_position(fontid, -0.5f * strwidth, -0.5f * strheight, 0.0f);
+ BLF_draw(fontid, str, strdrawlen);
+ GPU_matrix_pop();
+
+ GPU_matrix_pop();
+
+ GPU_blend(false);
+ GPU_line_smooth(false);
+}
+
+static void voxel_size_edit_cancel(bContext *C, wmOperator *op)
+{
+ ARegion *ar = CTX_wm_region(C);
+ VoxelSizeEditCustomData *cd = op->customdata;
+
+ ED_region_draw_cb_exit(ar->type, cd->draw_handle);
+
+ MEM_freeN(op->customdata);
+
+ ED_workspace_status_text(C, NULL);
+}
+
+static int voxel_size_edit_modal(bContext *C, wmOperator *op, const wmEvent *event)
+{
+ ARegion *ar = CTX_wm_region(C);
+ VoxelSizeEditCustomData *cd = op->customdata;
+ Object *active_object = cd->active_object;
+ Mesh *mesh = (Mesh *)active_object->data;
+
+ /* Cancel modal operator */
+ if ((event->type == EVT_ESCKEY && event->val == KM_PRESS) ||
+ (event->type == RIGHTMOUSE && event->val == KM_PRESS)) {
+ voxel_size_edit_cancel(C, op);
+ ED_region_tag_redraw(ar);
+ return OPERATOR_FINISHED;
+ }
+
+ /* Finish modal operator */
+ if ((event->type == LEFTMOUSE && event->val == KM_RELEASE) ||
+ (event->type == EVT_RETKEY && event->val == KM_PRESS) ||
+ (event->type == EVT_PADENTER && event->val == KM_PRESS)) {
+ ED_region_draw_cb_exit(ar->type, cd->draw_handle);
+ mesh->remesh_voxel_size = cd->voxel_size;
+ MEM_freeN(op->customdata);
+ ED_region_tag_redraw(ar);
+ return OPERATOR_FINISHED;
+ }
+
+ float mval[2] = {event->mval[0], event->mval[1]};
+
+ float d = cd->init_mval[0] - mval[0];
+
+ if (cd->slow_mode) {
+ d = cd->slow_mval[0] - mval[0];
+ }
+
+ if (event->ctrl) {
+ /* Linear mode, enables jumping to any voxel size. */
+ d = d * 0.0005f;
+ }
+ else {
+ /* Multiply d by the initial voxel size to prevent uncontrollable speeds when using low voxel
+ * sizes. */
+ /* When the voxel size is slower, it needs more precision. */
+ d = d * min_ff(pow2f(cd->init_voxel_size), 0.1f) * 0.05f;
+ }
+ if (cd->slow_mode) {
+ cd->voxel_size = cd->slow_voxel_size + d * 0.05f;
+ }
+ else {
+ cd->voxel_size = cd->init_voxel_size + d;
+ }
+
+ if (event->type == EVT_LEFTSHIFTKEY && event->val == KM_PRESS) {
+ cd->slow_mode = true;
+ copy_v2_v2(cd->slow_mval, mval);
+ cd->slow_voxel_size = cd->voxel_size;
+ }
+ if (event->type == EVT_LEFTSHIFTKEY && event->val == KM_RELEASE) {
+ cd->slow_mode = false;
+ cd->slow_voxel_size = 0.0f;
+ }
+
+ cd->voxel_size = clamp_f(cd->voxel_size, 0.0001f, 1.0f);
+
+ ED_region_tag_redraw(ar);
+ return OPERATOR_RUNNING_MODAL;
+}
+
+static int voxel_size_edit_invoke(bContext *C, wmOperator *op, const wmEvent *event)
+{
+ ARegion *ar = CTX_wm_region(C);
+ Object *active_object = CTX_data_active_object(C);
+ Mesh *mesh = (Mesh *)active_object->data;
+
+ VoxelSizeEditCustomData *cd = MEM_callocN(sizeof(VoxelSizeEditCustomData),
+ "Voxel Size Edit OP Custom Data");
+
+ /* Initial operator Custom Data setup. */
+ cd->draw_handle = ED_region_draw_cb_activate(
+ ar->type, voxel_size_edit_draw, cd, REGION_DRAW_POST_VIEW);
+ cd->active_object = active_object;
+ cd->init_mval[0] = event->mval[0];
+ cd->init_mval[1] = event->mval[1];
+ cd->init_voxel_size = mesh->remesh_voxel_size;
+ cd->voxel_size = mesh->remesh_voxel_size;
+ op->customdata = cd;
+
+ /* Select the front facing face of the mesh boundig box. */
+ BoundBox *bb = BKE_mesh_boundbox_get(cd->active_object);
+
+ /* Indices of the Bounding Box faces. */
+ int BB_faces[6][4] = {
+ {3, 0, 4, 7},
+ {1, 2, 6, 5},
+ {3, 2, 1, 0},
+ {4, 5, 6, 7},
+ {0, 1, 5, 4},
+ {2, 3, 7, 6},
+ };
+
+ copy_v3_v3(cd->preview_plane[0], bb->vec[BB_faces[0][0]]);
+ copy_v3_v3(cd->preview_plane[1], bb->vec[BB_faces[0][1]]);
+ copy_v3_v3(cd->preview_plane[2], bb->vec[BB_faces[0][2]]);
+ copy_v3_v3(cd->preview_plane[3], bb->vec[BB_faces[0][3]]);
+
+ RegionView3D *rv3d = CTX_wm_region_view3d(C);
+
+ float mat[3][3];
+ float current_normal[3];
+ float view_normal[3] = {0.0f, 0.0f, 1.0f};
+
+ /* Calculate the view normal. */
+ invert_m4_m4(active_object->imat, active_object->obmat);
+ copy_m3_m4(mat, rv3d->viewinv);
+ mul_m3_v3(mat, view_normal);
+ copy_m3_m4(mat, active_object->imat);
+ mul_m3_v3(mat, view_normal);
+ normalize_v3(view_normal);
+
+ normal_tri_v3(current_normal, cd->preview_plane[0], cd->preview_plane[1], cd->preview_plane[2]);
+
+ float min_dot = dot_v3v3(current_normal, view_normal);
+ float current_dot = 1;
+
+ /* Check if there is a face that is more aligned towards the view. */
+ for (int i = 0; i < 6; i++) {
+ normal_tri_v3(
+ current_normal, bb->vec[BB_faces[i][0]], bb->vec[BB_faces[i][1]], bb->vec[BB_faces[i][2]]);
+ current_dot = dot_v3v3(current_normal, view_normal);
+
+ if (current_dot < min_dot) {
+ min_dot = current_dot;
+ copy_v3_v3(cd->preview_plane[0], bb->vec[BB_faces[i][0]]);
+ copy_v3_v3(cd->preview_plane[1], bb->vec[BB_faces[i][1]]);
+ copy_v3_v3(cd->preview_plane[2], bb->vec[BB_faces[i][2]]);
+ copy_v3_v3(cd->preview_plane[3], bb->vec[BB_faces[i][3]]);
+ }
+ }
+
+ /* Matrix calculation to position the text in 3D space. */
+ float text_pos[3];
+ float scale_mat[4][4];
+
+ float d_a[3], d_b[3];
+ float d_a_proj[2], d_b_proj[2];
+ float preview_plane_proj[4][3];
+ float y_axis_proj[2] = {0.0f, 1.0f};
+
+ mid_v3_v3v3(text_pos, cd->preview_plane[0], cd->preview_plane[2]);
+
+ /* Project the selected face in the previous step of the Bounding Box. */
+ for (int i = 0; i < 4; i++) {
+ ED_view3d_project(ar, cd->preview_plane[i], preview_plane_proj[i]);
+ }
+
+ /* Get the initial X and Y axis of the basis from the edges of the Bounding Box face. */
+ sub_v3_v3v3(d_a, cd->preview_plane[1], cd->preview_plane[0]);
+ sub_v3_v3v3(d_b, cd->preview_plane[3], cd->preview_plane[0]);
+ normalize_v3(d_a);
+ normalize_v3(d_b);
+
+ /* Project the X and Y axis. */
+ sub_v2_v2v2(d_a_proj, preview_plane_proj[1], preview_plane_proj[0]);
+ sub_v2_v2v2(d_b_proj, preview_plane_proj[3], preview_plane_proj[0]);
+ normalize_v2(d_a_proj);
+ normalize_v2(d_b_proj);
+
+ unit_m4(cd->text_mat);
+
+ /* Select the axis that is aligned with the view Y axis to use it as the basis Y. */
+ if (fabsf(dot_v2v2(d_a_proj, y_axis_proj)) > fabsf(dot_v2v2(d_b_proj, y_axis_proj))) {
+ copy_v3_v3(cd->text_mat[0], d_b);
+ copy_v3_v3(cd->text_mat[1], d_a);
+
+ /* Flip the X and Y basis vectors to make sure they always point upwards and to the right. */
+ if (d_b_proj[0] < 0.0f) {
+ mul_v3_fl(cd->text_mat[0], -1.0f);
+ }
+ if (d_a_proj[1] < 0.0f) {
+ mul_v3_fl(cd->text_mat[1], -1.0f);
+ }
+ }
+ else {
+ copy_v3_v3(cd->text_mat[0], d_a);
+ copy_v3_v3(cd->text_mat[1], d_b);
+ if (d_a_proj[0] < 0.0f) {
+ mul_v3_fl(cd->text_mat[0], -1.0f);
+ }
+ if (d_b_proj[1] < 0.0f) {
+ mul_v3_fl(cd->text_mat[1], -1.0f);
+ }
+ }
+
+ /* Use the Bounding Box face normal as the basis Z. */
+ normal_tri_v3(cd->text_mat[2], cd->preview_plane[0], cd->preview_plane[1], cd->preview_plane[2]);
+
+ /* Write the text position into the matrix. */
+ copy_v3_v3(cd->text_mat[3], text_pos);
+
+ /* Scale the text. */
+ unit_m4(scale_mat);
+ scale_m4_fl(scale_mat, 0.0008f);
+ mul_m4_m4_post(cd->text_mat, scale_mat);
+
+ WM_event_add_modal_handler(C, op);
+
+ ED_region_tag_redraw(ar);
+
+ const char *status_str = TIP_(
+ "Move the mouse to change the voxel size. LMB: confirm size, ESC/RMB: cancel");
+ ED_workspace_status_text(C, status_str);
+
+ return OPERATOR_RUNNING_MODAL;
+}
+
+void OBJECT_OT_voxel_size_edit(wmOperatorType *ot)
+{
+ /* identifiers */
+ ot->name = "Edit Voxel Size";
+ ot->description = "Modify the mesh voxel size interactively used in the voxel remesher";
+ ot->idname = "OBJECT_OT_voxel_size_edit";
+
+ /* api callbacks */
+ ot->poll = object_remesh_poll;
+ ot->invoke = voxel_size_edit_invoke;
+ ot->modal = voxel_size_edit_modal;
+ ot->cancel = voxel_size_edit_cancel;
+
+ ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
+}
+
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Quadriflow Remesh Operator
+ * \{ */
+
+#define QUADRIFLOW_MIRROR_BISECT_TOLERANCE 0.005f
+
enum {
QUADRIFLOW_REMESH_RATIO = 1,
QUADRIFLOW_REMESH_EDGE_LENGTH,
QUADRIFLOW_REMESH_FACES,
};
-/****************** quadriflow remesh operator *********************/
-
-#define QUADRIFLOW_MIRROR_BISECT_TOLERANCE 0.005f
-
typedef enum eSymmetryAxes {
SYMMETRY_AXES_X = (1 << 0),
SYMMETRY_AXES_Y = (1 << 1),
@@ -237,13 +653,13 @@ static bool mesh_is_manifold_consistent(Mesh *mesh)
const MLoop *mloop = mesh->mloop;
char *edge_faces = (char *)MEM_callocN(mesh->totedge * sizeof(char), "remesh_manifold_check");
int *edge_vert = (int *)MEM_malloc_arrayN(
- mesh->totedge, sizeof(unsigned int), "remesh_consistent_check");
+ mesh->totedge, sizeof(uint), "remesh_consistent_check");
- for (unsigned int i = 0; i < mesh->totedge; i++) {
+ for (uint i = 0; i < mesh->totedge; i++) {
edge_vert[i] = -1;
}
- for (unsigned int loop_idx = 0; loop_idx < mesh->totloop; loop_idx++) {
+ for (uint loop_idx = 0; loop_idx < mesh->totloop; loop_idx++) {
const MLoop *loop = &mloop[loop_idx];
edge_faces[loop->e] += 1;
if (edge_faces[loop->e] > 2) {
@@ -263,7 +679,7 @@ static bool mesh_is_manifold_consistent(Mesh *mesh)
if (is_manifold_consistent) {
/* check for wire edges */
- for (unsigned int i = 0; i < mesh->totedge; i++) {
+ for (uint i = 0; i < mesh->totedge; i++) {
if (edge_faces[i] == 0) {
is_manifold_consistent = false;
break;
@@ -764,3 +1180,5 @@ void OBJECT_OT_quadriflow_remesh(wmOperatorType *ot)
0,
255);
}
+
+/** \} */
diff --git a/source/blender/editors/object/object_select.c b/source/blender/editors/object/object_select.c
index 8f01adb202e..5f9799710dc 100644
--- a/source/blender/editors/object/object_select.c
+++ b/source/blender/editors/object/object_select.c
@@ -246,7 +246,7 @@ Base *ED_object_find_first_by_data_id(ViewLayer *view_layer, ID *id)
Base *base_best = NULL;
int priority_best = 0;
- for (Base *base = view_layer->object_bases.first; base; base = base->next) {
+ LISTBASE_FOREACH (Base *, base, &view_layer->object_bases) {
if (base->object && base->object->data == id) {
if (base->flag & BASE_SELECTED) {
return base;
@@ -1325,7 +1325,7 @@ static bool object_select_more_less(bContext *C, const bool select)
{
ViewLayer *view_layer = CTX_data_view_layer(C);
- for (Base *base = view_layer->object_bases.first; base; base = base->next) {
+ LISTBASE_FOREACH (Base *, base, &view_layer->object_bases) {
Object *ob = base->object;
ob->flag &= ~OB_DONE;
ob->id.tag &= ~LIB_TAG_DOIT;
diff --git a/source/blender/editors/object/object_shader_fx.c b/source/blender/editors/object/object_shader_fx.c
index cd71ab674ba..30fcdfc88bc 100644
--- a/source/blender/editors/object/object_shader_fx.c
+++ b/source/blender/editors/object/object_shader_fx.c
@@ -66,7 +66,7 @@ ShaderFxData *ED_object_shaderfx_add(
ReportList *reports, Main *bmain, Scene *UNUSED(scene), Object *ob, const char *name, int type)
{
ShaderFxData *new_fx = NULL;
- const ShaderFxTypeInfo *fxi = BKE_shaderfxType_getInfo(type);
+ const ShaderFxTypeInfo *fxi = BKE_shaderfx_get_info(type);
if (ob->type != OB_GPENCIL) {
BKE_reportf(reports, RPT_WARNING, "Effect cannot be added to object '%s'", ob->id.name + 2);
@@ -74,7 +74,7 @@ ShaderFxData *ED_object_shaderfx_add(
}
if (fxi->flags & eShaderFxTypeFlag_Single) {
- if (BKE_shaderfx_findByType(ob, type)) {
+ if (BKE_shaderfx_findby_type(ob, type)) {
BKE_report(reports, RPT_WARNING, "Only one Effect of this type is allowed");
return NULL;
}
@@ -236,7 +236,7 @@ static const EnumPropertyItem *shaderfx_add_itemf(bContext *C,
for (a = 0; rna_enum_object_shaderfx_type_items[a].identifier; a++) {
fx_item = &rna_enum_object_shaderfx_type_items[a];
if (fx_item->identifier[0]) {
- mti = BKE_shaderfxType_getInfo(fx_item->value);
+ mti = BKE_shaderfx_get_info(fx_item->value);
if (mti->flags & eShaderFxTypeFlag_NoUserAdd) {
continue;
@@ -356,7 +356,7 @@ static ShaderFxData *edit_shaderfx_property_get(wmOperator *op, Object *ob, int
ShaderFxData *fx;
RNA_string_get(op->ptr, "shaderfx", shaderfx_name);
- fx = BKE_shaderfx_findByName(ob, shaderfx_name);
+ fx = BKE_shaderfx_findby_name(ob, shaderfx_name);
if (fx && type != 0 && fx->type != type) {
fx = NULL;
diff --git a/source/blender/editors/object/object_shapekey.c b/source/blender/editors/object/object_shapekey.c
index abce985b65a..26d33bbc375 100644
--- a/source/blender/editors/object/object_shapekey.c
+++ b/source/blender/editors/object/object_shapekey.c
@@ -126,7 +126,7 @@ static bool object_shape_key_mirror(
float *fp1, *fp2;
float tvec[3];
- ED_mesh_mirror_spatial_table(ob, NULL, NULL, NULL, 's');
+ ED_mesh_mirror_spatial_table_begin(ob, NULL, NULL);
for (i1 = 0, mv = me->mvert; i1 < me->totvert; i1++, mv++) {
i2 = mesh_get_x_mirror_vert(ob, NULL, i1, use_topology);
@@ -157,7 +157,7 @@ static bool object_shape_key_mirror(
}
}
- ED_mesh_mirror_spatial_table(ob, NULL, NULL, NULL, 'e');
+ ED_mesh_mirror_spatial_table_end(ob);
}
else if (ob->type == OB_LATTICE) {
Lattice *lt = ob->data;
diff --git a/source/blender/editors/object/object_transform.c b/source/blender/editors/object/object_transform.c
index 28bb28a0298..132b530455e 100644
--- a/source/blender/editors/object/object_transform.c
+++ b/source/blender/editors/object/object_transform.c
@@ -1608,6 +1608,7 @@ struct XFormAxisItem {
float rot_mat[3][3];
void *obtfm;
float xform_dist;
+ bool is_z_flip;
#ifdef USE_RELATIVE_ROTATION
/* use when translating multiple */
@@ -1727,14 +1728,19 @@ static void object_apply_location(Object *ob, const float loc[3])
copy_v3_v3(ob->loc, mat[3]);
}
-static void object_orient_to_location(Object *ob,
+static bool object_orient_to_location(Object *ob,
const float rot_orig[3][3],
const float axis[3],
- const float location[3])
+ const float location[3],
+ const bool z_flip)
{
float delta[3];
sub_v3_v3v3(delta, ob->obmat[3], location);
if (normalize_v3(delta) != 0.0f) {
+ if (z_flip) {
+ negate_v3(delta);
+ }
+
if (len_squared_v3v3(delta, axis) > FLT_EPSILON) {
float delta_rot[3][3];
float final_rot[3][3];
@@ -1744,9 +1750,10 @@ static void object_orient_to_location(Object *ob,
object_apply_rotation(ob, final_rot);
- DEG_id_tag_update(&ob->id, ID_RECALC_TRANSFORM);
+ return true;
}
}
+ return false;
}
static void object_transform_axis_target_cancel(bContext *C, wmOperator *op)
@@ -1840,6 +1847,11 @@ static int object_transform_axis_target_invoke(bContext *C, wmOperator *op, cons
for (int i = 0; i < xfd->object_data_len; i++, item++) {
item->obtfm = BKE_object_tfm_backup(item->ob);
BKE_object_rot_to_mat3(item->ob, item->rot_mat, true);
+
+ /* Detect negative scale matrix. */
+ float full_mat3[3][3];
+ BKE_object_to_mat3(item->ob, full_mat3);
+ item->is_z_flip = dot_v3v3(item->rot_mat[2], full_mat3[2]) < 0.0f;
}
}
@@ -1860,8 +1872,7 @@ static int object_transform_axis_target_modal(bContext *C, wmOperator *op, const
if (event->type == MOUSEMOVE || is_translate_init) {
const ViewDepths *depths = xfd->vc.rv3d->depths;
- if (depths && ((unsigned int)event->mval[0] < depths->w) &&
- ((unsigned int)event->mval[1] < depths->h)) {
+ if (depths && ((uint)event->mval[0] < depths->w) && ((uint)event->mval[1] < depths->h)) {
double depth = (double)ED_view3d_depth_read_cached(&xfd->vc, event->mval);
float location_world[3];
if (depth == 1.0f) {
@@ -1894,9 +1905,9 @@ static int object_transform_axis_target_modal(bContext *C, wmOperator *op, const
normal_found = true;
/* cheap attempt to smooth normals out a bit! */
- const uint ofs = 2;
- for (uint x = -ofs; x <= ofs; x += ofs / 2) {
- for (uint y = -ofs; y <= ofs; y += ofs / 2) {
+ const int ofs = 2;
+ for (int x = -ofs; x <= ofs; x += ofs / 2) {
+ for (int y = -ofs; y <= ofs; y += ofs / 2) {
if (x != 0 && y != 0) {
int mval_ofs[2] = {event->mval[0] + x, event->mval[1] + y};
float n[3];
@@ -1913,7 +1924,7 @@ static int object_transform_axis_target_modal(bContext *C, wmOperator *op, const
normal_found = true;
}
- if (normal_found) {
+ {
#ifdef USE_RELATIVE_ROTATION
if (is_translate_init && xfd->object_data_len > 1) {
float xform_rot_offset_inv_first[3][3];
@@ -1942,16 +1953,26 @@ static int object_transform_axis_target_modal(bContext *C, wmOperator *op, const
item->xform_dist = len_v3v3(item->ob->obmat[3], location_world);
normalize_v3_v3(ob_axis, item->ob->obmat[2]);
/* Scale to avoid adding distance when moving between surfaces. */
- float scale = fabsf(dot_v3v3(ob_axis, normal));
- item->xform_dist *= scale;
+ if (normal_found) {
+ float scale = fabsf(dot_v3v3(ob_axis, normal));
+ item->xform_dist *= scale;
+ }
}
float target_normal[3];
- copy_v3_v3(target_normal, normal);
+
+ if (normal_found) {
+ copy_v3_v3(target_normal, normal);
+ }
+ else {
+ normalize_v3_v3(target_normal, item->ob->obmat[2]);
+ }
#ifdef USE_RELATIVE_ROTATION
- if (i != 0) {
- mul_m3_v3(item->xform_rot_offset, target_normal);
+ if (normal_found) {
+ if (i != 0) {
+ mul_m3_v3(item->xform_rot_offset, target_normal);
+ }
}
#endif
{
@@ -1965,18 +1986,28 @@ static int object_transform_axis_target_modal(bContext *C, wmOperator *op, const
}
object_orient_to_location(
- item->ob, item->rot_mat, item->rot_mat[2], location_world);
+ item->ob, item->rot_mat, item->rot_mat[2], location_world, item->is_z_flip);
+
+ DEG_id_tag_update(&item->ob->id, ID_RECALC_TRANSFORM);
WM_event_add_notifier(C, NC_OBJECT | ND_TRANSFORM, item->ob);
}
- copy_v3_v3(xfd->prev.normal, normal);
- xfd->prev.is_normal_valid = true;
+ if (normal_found) {
+ copy_v3_v3(xfd->prev.normal, normal);
+ xfd->prev.is_normal_valid = true;
+ }
}
}
else {
struct XFormAxisItem *item = xfd->object_data;
for (int i = 0; i < xfd->object_data_len; i++, item++) {
- object_orient_to_location(item->ob, item->rot_mat, item->rot_mat[2], location_world);
- WM_event_add_notifier(C, NC_OBJECT | ND_TRANSFORM, item->ob);
+ if (object_orient_to_location(item->ob,
+ item->rot_mat,
+ item->rot_mat[2],
+ location_world,
+ item->is_z_flip)) {
+ DEG_id_tag_update(&item->ob->id, ID_RECALC_TRANSFORM);
+ WM_event_add_notifier(C, NC_OBJECT | ND_TRANSFORM, item->ob);
+ }
}
xfd->prev.is_normal_valid = false;
}
diff --git a/source/blender/editors/object/object_utils.c b/source/blender/editors/object/object_utils.c
index d6056f85932..00aafc2120f 100644
--- a/source/blender/editors/object/object_utils.c
+++ b/source/blender/editors/object/object_utils.c
@@ -28,6 +28,7 @@
#include "DNA_object_types.h"
#include "DNA_scene_types.h"
+#include "BLI_listbase.h"
#include "BLI_math.h"
#include "BLI_utildefines.h"
@@ -193,7 +194,7 @@ void ED_object_xform_skip_child_container_item_ensure_from_array(
BLI_gset_add(objects_in_transdata, ob);
}
- for (Base *base = view_layer->object_bases.first; base; base = base->next) {
+ LISTBASE_FOREACH (Base *, base, &view_layer->object_bases) {
Object *ob = base->object;
if (ob->parent != NULL) {
if (!BLI_gset_haskey(objects_in_transdata, ob)) {
@@ -223,7 +224,7 @@ void ED_object_xform_skip_child_container_item_ensure_from_array(
}
}
- for (Base *base = view_layer->object_bases.first; base; base = base->next) {
+ LISTBASE_FOREACH (Base *, base, &view_layer->object_bases) {
Object *ob = base->object;
if (BLI_gset_haskey(objects_in_transdata, ob)) {
diff --git a/source/blender/editors/object/object_vgroup.c b/source/blender/editors/object/object_vgroup.c
index 3ec55d42849..fb79cfb910e 100644
--- a/source/blender/editors/object/object_vgroup.c
+++ b/source/blender/editors/object/object_vgroup.c
@@ -3945,7 +3945,7 @@ static int vgroup_sort_name(const void *def_a_ptr, const void *def_b_ptr)
static void vgroup_sort_bone_hierarchy(Object *ob, ListBase *bonebase)
{
if (bonebase == NULL) {
- Object *armobj = modifiers_isDeformedByArmature(ob);
+ Object *armobj = BKE_modifiers_is_deformed_by_armature(ob);
if (armobj != NULL) {
bArmature *armature = armobj->data;
bonebase = &armature->bonebase;
diff --git a/source/blender/editors/object/object_volume.c b/source/blender/editors/object/object_volume.c
index 92fb0788f6b..4cdbbea492b 100644
--- a/source/blender/editors/object/object_volume.c
+++ b/source/blender/editors/object/object_volume.c
@@ -59,7 +59,7 @@ static Object *object_volume_add(bContext *C, wmOperator *op, const char *name)
ushort local_view_bits;
float loc[3], rot[3];
- if (!ED_object_add_generic_get_opts(C, op, 'Z', loc, rot, NULL, &local_view_bits, NULL)) {
+ if (!ED_object_add_generic_get_opts(C, op, 'Z', loc, rot, NULL, NULL, &local_view_bits, NULL)) {
return false;
}
return ED_object_add_type(C, OB_VOLUME, name, loc, rot, false, local_view_bits);
@@ -96,7 +96,7 @@ static int volume_import_exec(bContext *C, wmOperator *op)
bool imported = false;
ListBase ranges = ED_image_filesel_detect_sequences(bmain, op, false);
- for (ImageFrameRange *range = ranges.first; range; range = range->next) {
+ LISTBASE_FOREACH (ImageFrameRange *, range, &ranges) {
char filename[FILE_MAX];
BLI_split_file_part(range->filepath, filename, sizeof(filename));
BLI_path_extension_replace(filename, sizeof(filename), "");
@@ -109,11 +109,6 @@ static int volume_import_exec(bContext *C, wmOperator *op)
BLI_path_rel(volume->filepath, BKE_main_blendfile_path(bmain));
}
- volume->is_sequence = (range->length > 1);
- volume->frame_duration = (volume->is_sequence) ? range->length : 0;
- volume->frame_start = 1;
- volume->frame_offset = (volume->is_sequence) ? range->offset - 1 : 0;
-
if (!BKE_volume_load(volume, bmain)) {
BKE_reportf(op->reports,
RPT_WARNING,
@@ -134,10 +129,19 @@ static int volume_import_exec(bContext *C, wmOperator *op)
continue;
}
+ /* Set sequence parameters after trying to load the first frame, for file validation we want
+ * to use a consistent frame rather than whatever corresponds to the current scene frame. */
+ volume->is_sequence = (range->length > 1);
+ volume->frame_duration = (volume->is_sequence) ? range->length : 0;
+ volume->frame_start = 1;
+ volume->frame_offset = (volume->is_sequence) ? range->offset - 1 : 0;
+
if (BKE_volume_is_y_up(volume)) {
object->rot[0] += M_PI_2;
}
+ BKE_volume_unload(volume);
+
imported = true;
}
BLI_freelistN(&ranges);
diff --git a/source/blender/editors/physics/dynamicpaint_ops.c b/source/blender/editors/physics/dynamicpaint_ops.c
index 37845e8d74e..6922a03b12f 100644
--- a/source/blender/editors/physics/dynamicpaint_ops.c
+++ b/source/blender/editors/physics/dynamicpaint_ops.c
@@ -72,7 +72,7 @@ static int surface_slot_add_exec(bContext *C, wmOperator *UNUSED(op))
DynamicPaintSurface *surface;
/* Make sure we're dealing with a canvas */
- pmd = (DynamicPaintModifierData *)modifiers_findByType(cObject, eModifierType_DynamicPaint);
+ pmd = (DynamicPaintModifierData *)BKE_modifiers_findby_type(cObject, eModifierType_DynamicPaint);
if (!pmd || !pmd->canvas) {
return OPERATOR_CANCELLED;
}
@@ -117,7 +117,7 @@ static int surface_slot_remove_exec(bContext *C, wmOperator *UNUSED(op))
int id = 0;
/* Make sure we're dealing with a canvas */
- pmd = (DynamicPaintModifierData *)modifiers_findByType(obj_ctx, eModifierType_DynamicPaint);
+ pmd = (DynamicPaintModifierData *)BKE_modifiers_findby_type(obj_ctx, eModifierType_DynamicPaint);
if (!pmd || !pmd->canvas) {
return OPERATOR_CANCELLED;
}
@@ -162,7 +162,7 @@ static int type_toggle_exec(bContext *C, wmOperator *op)
Object *cObject = ED_object_context(C);
Scene *scene = CTX_data_scene(C);
- DynamicPaintModifierData *pmd = (DynamicPaintModifierData *)modifiers_findByType(
+ DynamicPaintModifierData *pmd = (DynamicPaintModifierData *)BKE_modifiers_findby_type(
cObject, eModifierType_DynamicPaint);
int type = RNA_enum_get(op->ptr, "type");
@@ -222,7 +222,7 @@ static int output_toggle_exec(bContext *C, wmOperator *op)
{
Object *ob = ED_object_context(C);
DynamicPaintSurface *surface;
- DynamicPaintModifierData *pmd = (DynamicPaintModifierData *)modifiers_findByType(
+ DynamicPaintModifierData *pmd = (DynamicPaintModifierData *)BKE_modifiers_findby_type(
ob, eModifierType_DynamicPaint);
int output = RNA_enum_get(op->ptr, "output"); /* currently only 1/0 */
@@ -483,7 +483,7 @@ static int dynamicpaint_bake_exec(struct bContext *C, struct wmOperator *op)
/*
* Get modifier data
*/
- DynamicPaintModifierData *pmd = (DynamicPaintModifierData *)modifiers_findByType(
+ DynamicPaintModifierData *pmd = (DynamicPaintModifierData *)BKE_modifiers_findby_type(
object_eval, eModifierType_DynamicPaint);
if (pmd == NULL) {
BKE_report(op->reports, RPT_ERROR, "Bake failed: no Dynamic Paint modifier found");
diff --git a/source/blender/editors/physics/particle_edit.c b/source/blender/editors/physics/particle_edit.c
index 8a40f65fc8a..ef5ed806c1e 100644
--- a/source/blender/editors/physics/particle_edit.c
+++ b/source/blender/editors/physics/particle_edit.c
@@ -135,10 +135,10 @@ bool PE_hair_poll(bContext *C)
bool PE_poll_view3d(bContext *C)
{
- ScrArea *sa = CTX_wm_area(C);
+ ScrArea *area = CTX_wm_area(C);
ARegion *region = CTX_wm_region(C);
- return (PE_poll(C) && (sa && sa->spacetype == SPACE_VIEW3D) &&
+ return (PE_poll(C) && (area && area->spacetype == SPACE_VIEW3D) &&
(region && region->regiontype == RGN_TYPE_WINDOW));
}
@@ -849,7 +849,6 @@ static void foreach_mouse_hit_key(PEData *data, ForHitKeyMatFunc func, int selec
TaskParallelSettings settings;
BLI_parallel_range_settings_defaults(&settings);
- settings.scheduling_mode = TASK_SCHEDULING_DYNAMIC;
BLI_task_parallel_range(0, edit->totpoint, &iter_data, foreach_mouse_hit_key_iter, &settings);
}
@@ -1229,7 +1228,6 @@ static void pe_deflect_emitter(Scene *scene, Object *ob, PTCacheEdit *edit)
TaskParallelSettings settings;
BLI_parallel_range_settings_defaults(&settings);
- settings.scheduling_mode = TASK_SCHEDULING_DYNAMIC;
BLI_task_parallel_range(0, edit->totpoint, &iter_data, deflect_emitter_iter, &settings);
}
@@ -1278,7 +1276,6 @@ static void PE_apply_lengths(Scene *scene, PTCacheEdit *edit)
TaskParallelSettings settings;
BLI_parallel_range_settings_defaults(&settings);
- settings.scheduling_mode = TASK_SCHEDULING_DYNAMIC;
BLI_task_parallel_range(0, edit->totpoint, &iter_data, apply_lengths_iter, &settings);
}
@@ -1353,7 +1350,6 @@ static void pe_iterate_lengths(Scene *scene, PTCacheEdit *edit)
TaskParallelSettings settings;
BLI_parallel_range_settings_defaults(&settings);
- settings.scheduling_mode = TASK_SCHEDULING_DYNAMIC;
BLI_task_parallel_range(0, edit->totpoint, &iter_data, iterate_lengths_iter, &settings);
}
@@ -2256,7 +2252,7 @@ bool PE_circle_select(bContext *C, const int sel_op, const int mval[2], float ra
/************************ lasso select operator ************************/
-int PE_lasso_select(bContext *C, const int mcords[][2], const short moves, const int sel_op)
+int PE_lasso_select(bContext *C, const int mcoords[][2], const int mcoords_len, const int sel_op)
{
Depsgraph *depsgraph = CTX_data_depsgraph_pointer(C);
Scene *scene = CTX_data_scene(C);
@@ -2300,7 +2296,8 @@ int PE_lasso_select(bContext *C, const int mcords[][2], const short moves, const
const bool is_inside =
((ED_view3d_project_int_global(region, co, screen_co, V3D_PROJ_TEST_CLIP_WIN) ==
V3D_PROJ_RET_OK) &&
- BLI_lasso_is_point_inside(mcords, moves, screen_co[0], screen_co[1], IS_CLIPPED) &&
+ BLI_lasso_is_point_inside(
+ mcoords, mcoords_len, screen_co[0], screen_co[1], IS_CLIPPED) &&
key_test_depth(&data, co, screen_co));
const int sel_op_result = ED_select_op_action_deselected(sel_op, is_select, is_inside);
if (sel_op_result != -1) {
@@ -2319,7 +2316,8 @@ int PE_lasso_select(bContext *C, const int mcords[][2], const short moves, const
const bool is_inside =
((ED_view3d_project_int_global(region, co, screen_co, V3D_PROJ_TEST_CLIP_WIN) ==
V3D_PROJ_RET_OK) &&
- BLI_lasso_is_point_inside(mcords, moves, screen_co[0], screen_co[1], IS_CLIPPED) &&
+ BLI_lasso_is_point_inside(
+ mcoords, mcoords_len, screen_co[0], screen_co[1], IS_CLIPPED) &&
key_test_depth(&data, co, screen_co));
const int sel_op_result = ED_select_op_action_deselected(sel_op, is_select, is_inside);
if (sel_op_result != -1) {
@@ -2833,8 +2831,8 @@ static void remove_tagged_keys(Depsgraph *depsgraph, Object *ob, ParticleSystem
if (pe_x_mirror(ob)) {
/* mirror key tags */
ParticleSystemModifierData *psmd = psys_get_modifier(ob, psys);
- ParticleSystemModifierData *psmd_eval = (ParticleSystemModifierData *)modifier_get_evaluated(
- depsgraph, ob, &psmd->modifier);
+ ParticleSystemModifierData *psmd_eval = (ParticleSystemModifierData *)
+ BKE_modifier_get_evaluated(depsgraph, ob, &psmd->modifier);
LOOP_POINTS {
LOOP_TAGGED_KEYS {
@@ -3232,17 +3230,17 @@ static void brush_drawcursor(bContext *C, int x, int y, void *UNUSED(customdata)
}
}
-static void toggle_particle_cursor(bContext *C, int enable)
+static void toggle_particle_cursor(Scene *scene, bool enable)
{
- ParticleEditSettings *pset = PE_settings(CTX_data_scene(C));
+ ParticleEditSettings *pset = PE_settings(scene);
if (pset->paintcursor && !enable) {
- WM_paint_cursor_end(CTX_wm_manager(C), pset->paintcursor);
+ WM_paint_cursor_end(pset->paintcursor);
pset->paintcursor = NULL;
}
else if (enable) {
pset->paintcursor = WM_paint_cursor_activate(
- CTX_wm_manager(C), SPACE_VIEW3D, RGN_TYPE_WINDOW, PE_poll_view3d, brush_drawcursor, NULL);
+ SPACE_VIEW3D, RGN_TYPE_WINDOW, PE_poll_view3d, brush_drawcursor, NULL);
}
}
@@ -4084,7 +4082,6 @@ typedef struct BrushAddCountIterData {
short size;
float imat[4][4];
ParticleData *add_pars;
- int num_added;
} BrushAddCountIterData;
typedef struct BrushAddCountIterTLSData {
@@ -4113,7 +4110,7 @@ static void brush_add_count_iter(void *__restrict iter_data_v,
dmy = size;
if (tls->rng == NULL) {
tls->rng = BLI_rng_new_srandom(psys->seed + data->mval[0] + data->mval[1] +
- tls_v->thread_id);
+ BLI_task_parallel_thread_id(tls_v));
}
/* rejection sampling to get points in circle */
while (dmx * dmx + dmy * dmy > size2) {
@@ -4176,12 +4173,19 @@ static void brush_add_count_iter(void *__restrict iter_data_v,
}
}
-static void brush_add_count_iter_finalize(void *__restrict userdata_v,
- void *__restrict userdata_chunk_v)
+static void brush_add_count_iter_reduce(const void *__restrict UNUSED(userdata),
+ void *__restrict join_v,
+ void *__restrict chunk_v)
+{
+ BrushAddCountIterTLSData *join = (BrushAddCountIterTLSData *)join_v;
+ BrushAddCountIterTLSData *tls = (BrushAddCountIterTLSData *)chunk_v;
+ join->num_added += tls->num_added;
+}
+
+static void brush_add_count_iter_free(const void *__restrict UNUSED(userdata_v),
+ void *__restrict chunk_v)
{
- BrushAddCountIterData *iter_data = (BrushAddCountIterData *)userdata_v;
- BrushAddCountIterTLSData *tls = (BrushAddCountIterTLSData *)userdata_chunk_v;
- iter_data->num_added += tls->num_added;
+ BrushAddCountIterTLSData *tls = (BrushAddCountIterTLSData *)chunk_v;
if (tls->rng != NULL) {
BLI_rng_free(tls->rng);
}
@@ -4245,23 +4249,22 @@ static int brush_add(const bContext *C, PEData *data, short number)
iter_data.number = number;
iter_data.size = size;
iter_data.add_pars = add_pars;
- iter_data.num_added = 0;
copy_m4_m4(iter_data.imat, imat);
BrushAddCountIterTLSData tls = {NULL};
TaskParallelSettings settings;
BLI_parallel_range_settings_defaults(&settings);
- settings.scheduling_mode = TASK_SCHEDULING_DYNAMIC;
settings.userdata_chunk = &tls;
settings.userdata_chunk_size = sizeof(BrushAddCountIterTLSData);
- settings.func_finalize = brush_add_count_iter_finalize;
+ settings.func_reduce = brush_add_count_iter_reduce;
+ settings.func_free = brush_add_count_iter_free;
BLI_task_parallel_range(0, number, &iter_data, brush_add_count_iter, &settings);
/* Convert add_parse to a dense array, where all new particles are in the
* beginning of the array.
*/
- n = iter_data.num_added;
+ n = tls.num_added;
for (int current_iter = 0, new_index = 0; current_iter < number; current_iter++) {
if (add_pars[current_iter].num == DMCACHE_NOTFOUND) {
continue;
@@ -5124,7 +5127,8 @@ void PE_create_particle_edit(
int totpoint;
if (psmd != NULL) {
- psmd_eval = (ParticleSystemModifierData *)modifiers_findByName(ob_eval, psmd->modifier.name);
+ psmd_eval = (ParticleSystemModifierData *)BKE_modifiers_findby_name(ob_eval,
+ psmd->modifier.name);
}
/* no psmd->dm happens in case particle system modifier is not enabled */
@@ -5247,12 +5251,9 @@ static bool particle_edit_toggle_poll(bContext *C)
if (!ob->data || ID_IS_LINKED(ob->data)) {
return 0;
}
- if (CTX_data_edit_object(C)) {
- return 0;
- }
- return (ob->particlesystem.first || modifiers_findByType(ob, eModifierType_Cloth) ||
- modifiers_findByType(ob, eModifierType_Softbody));
+ return (ob->particlesystem.first || BKE_modifiers_findby_type(ob, eModifierType_Cloth) ||
+ BKE_modifiers_findby_type(ob, eModifierType_Softbody));
}
static void free_all_psys_edit(Object *object)
@@ -5267,10 +5268,60 @@ static void free_all_psys_edit(Object *object)
}
}
+void ED_object_particle_edit_mode_enter_ex(Depsgraph *depsgraph, Scene *scene, Object *ob)
+{
+ PTCacheEdit *edit;
+
+ ob->mode |= OB_MODE_PARTICLE_EDIT;
+
+ edit = PE_create_current(depsgraph, scene, ob);
+
+ /* Mesh may have changed since last entering editmode.
+ * note, this may have run before if the edit data was just created,
+ * so could avoid this and speed up a little. */
+ if (edit && edit->psys) {
+ /* Make sure pointer to the evaluated modifier data is up to date,
+ * with possible changes applied when object was outside of the
+ * edit mode. */
+ Object *object_eval = DEG_get_evaluated_object(depsgraph, ob);
+ edit->psmd_eval = (ParticleSystemModifierData *)BKE_modifiers_findby_name(
+ object_eval, edit->psmd->modifier.name);
+ recalc_emitter_field(depsgraph, ob, edit->psys);
+ }
+
+ toggle_particle_cursor(scene, true);
+ DEG_id_tag_update(&ob->id, ID_RECALC_GEOMETRY | ID_RECALC_COPY_ON_WRITE);
+ WM_main_add_notifier(NC_SCENE | ND_MODE | NS_MODE_PARTICLE, NULL);
+}
+
+void ED_object_particle_edit_mode_enter(bContext *C)
+{
+ Depsgraph *depsgraph = CTX_data_depsgraph_pointer(C);
+ Scene *scene = CTX_data_scene(C);
+ Object *ob = CTX_data_active_object(C);
+ ED_object_particle_edit_mode_enter_ex(depsgraph, scene, ob);
+}
+
+void ED_object_particle_edit_mode_exit_ex(Scene *scene, Object *ob)
+{
+ ob->mode &= ~OB_MODE_PARTICLE_EDIT;
+ toggle_particle_cursor(scene, false);
+ free_all_psys_edit(ob);
+
+ DEG_id_tag_update(&ob->id, ID_RECALC_GEOMETRY | ID_RECALC_COPY_ON_WRITE);
+ WM_main_add_notifier(NC_SCENE | ND_MODE | NS_MODE_OBJECT, NULL);
+}
+
+void ED_object_particle_edit_mode_exit(bContext *C)
+{
+ Scene *scene = CTX_data_scene(C);
+ Object *ob = CTX_data_active_object(C);
+ ED_object_particle_edit_mode_exit_ex(scene, ob);
+}
+
static int particle_edit_toggle_exec(bContext *C, wmOperator *op)
{
struct wmMsgBus *mbus = CTX_wm_message_bus(C);
- Depsgraph *depsgraph = CTX_data_depsgraph_pointer(C);
Scene *scene = CTX_data_scene(C);
Object *ob = CTX_data_active_object(C);
const int mode_flag = OB_MODE_PARTICLE_EDIT;
@@ -5283,37 +5334,13 @@ static int particle_edit_toggle_exec(bContext *C, wmOperator *op)
}
if (!is_mode_set) {
- PTCacheEdit *edit;
-
- ob->mode |= mode_flag;
-
- edit = PE_create_current(depsgraph, scene, ob);
-
- /* Mesh may have changed since last entering editmode.
- * note, this may have run before if the edit data was just created,
- * so could avoid this and speed up a little. */
- if (edit && edit->psys) {
- /* Make sure pointer to the evaluated modifier data is up to date,
- * with possible changes applied when object was outside of the
- * edit mode. */
- Object *object_eval = DEG_get_evaluated_object(depsgraph, ob);
- edit->psmd_eval = (ParticleSystemModifierData *)modifiers_findByName(
- object_eval, edit->psmd->modifier.name);
- recalc_emitter_field(depsgraph, ob, edit->psys);
- }
-
- toggle_particle_cursor(C, 1);
- WM_event_add_notifier(C, NC_SCENE | ND_MODE | NS_MODE_PARTICLE, NULL);
+ Depsgraph *depsgraph = CTX_data_depsgraph_pointer(C);
+ ED_object_particle_edit_mode_enter_ex(depsgraph, scene, ob);
}
else {
- ob->mode &= ~mode_flag;
- toggle_particle_cursor(C, 0);
- free_all_psys_edit(ob);
- WM_event_add_notifier(C, NC_SCENE | ND_MODE | NS_MODE_OBJECT, NULL);
+ ED_object_particle_edit_mode_exit_ex(scene, ob);
}
- DEG_id_tag_update(&ob->id, ID_RECALC_GEOMETRY | ID_RECALC_COPY_ON_WRITE);
-
WM_msg_publish_rna_prop(mbus, &ob->id, ob, Object, mode);
WM_toolsystem_update_from_context_view3d(C);
diff --git a/source/blender/editors/physics/particle_edit_undo.c b/source/blender/editors/physics/particle_edit_undo.c
index 5b363bdca78..205c04f54a9 100644
--- a/source/blender/editors/physics/particle_edit_undo.c
+++ b/source/blender/editors/physics/particle_edit_undo.c
@@ -253,7 +253,7 @@ static void particle_undosys_step_decode(struct bContext *C,
{
Depsgraph *depsgraph = CTX_data_depsgraph_pointer(C);
/* TODO(campbell): undo_system: use low-level API to set mode. */
- ED_object_mode_set(C, OB_MODE_PARTICLE_EDIT);
+ ED_object_mode_set_ex(C, OB_MODE_PARTICLE_EDIT, false, NULL);
BLI_assert(particle_undosys_poll(C));
ParticleUndoStep *us = (ParticleUndoStep *)us_p;
diff --git a/source/blender/editors/physics/particle_object.c b/source/blender/editors/physics/particle_object.c
index f37a20bf43e..e75169a476b 100644
--- a/source/blender/editors/physics/particle_object.c
+++ b/source/blender/editors/physics/particle_object.c
@@ -1064,7 +1064,7 @@ static void remove_particle_systems_from_object(Object *ob_to)
eModifierType_DynamicPaint,
eModifierType_Fluid)) {
BLI_remlink(&ob_to->modifiers, md);
- modifier_free(md);
+ BKE_modifier_free(md);
}
}
@@ -1138,13 +1138,13 @@ static bool copy_particle_systems_to_object(const bContext *C,
psys_unique_name(ob_to, psys, psys->name);
/* add a particle system modifier for each system */
- md = modifier_new(eModifierType_ParticleSystem);
+ md = BKE_modifier_new(eModifierType_ParticleSystem);
psmd = (ParticleSystemModifierData *)md;
/* push on top of the stack, no use trying to reproduce old stack order */
BLI_addtail(&ob_to->modifiers, md);
BLI_snprintf(md->name, sizeof(md->name), "ParticleSystem %i", i);
- modifier_unique_name(&ob_to->modifiers, (ModifierData *)psmd);
+ BKE_modifier_unique_name(&ob_to->modifiers, (ModifierData *)psmd);
psmd->psys = psys;
diff --git a/source/blender/editors/physics/physics_fluid.c b/source/blender/editors/physics/physics_fluid.c
index eb808398254..8524870c15e 100644
--- a/source/blender/editors/physics/physics_fluid.c
+++ b/source/blender/editors/physics/physics_fluid.c
@@ -52,6 +52,7 @@
#include "DEG_depsgraph.h"
+#include "ED_object.h"
#include "ED_screen.h"
#include "PIL_time.h"
@@ -154,9 +155,9 @@ static bool fluid_initjob(
{
FluidModifierData *mmd = NULL;
FluidDomainSettings *mds;
- Object *ob = CTX_data_active_object(C);
+ Object *ob = ED_object_active_context(C);
- mmd = (FluidModifierData *)modifiers_findByType(ob, eModifierType_Fluid);
+ mmd = (FluidModifierData *)BKE_modifiers_findby_type(ob, eModifierType_Fluid);
if (!mmd) {
BLI_strncpy(error_msg, N_("Bake failed: no Fluid modifier found"), error_size);
return false;
@@ -170,7 +171,7 @@ static bool fluid_initjob(
job->bmain = CTX_data_main(C);
job->scene = CTX_data_scene(C);
job->depsgraph = CTX_data_depsgraph_pointer(C);
- job->ob = CTX_data_active_object(C);
+ job->ob = ob;
job->mmd = mmd;
job->type = op->type->idname;
job->name = op->type->name;
@@ -185,13 +186,13 @@ static bool fluid_validatepaths(FluidJob *job, ReportList *reports)
temp_dir[0] = '\0';
bool is_relative = false;
- const char *relbase = modifier_path_relbase(job->bmain, job->ob);
+ const char *relbase = BKE_modifier_path_relbase(job->bmain, job->ob);
/* We do not accept empty paths, they can end in random places silently, see T51176. */
if (mds->cache_directory[0] == '\0') {
char cache_name[64];
BKE_fluid_cache_new_name_for_current_session(sizeof(cache_name), cache_name);
- modifier_path_init(mds->cache_directory, sizeof(mds->cache_directory), cache_name);
+ BKE_modifier_path_init(mds->cache_directory, sizeof(mds->cache_directory), cache_name);
BKE_reportf(reports,
RPT_WARNING,
"Fluid: Empty cache path, reset to default '%s'",
@@ -209,7 +210,7 @@ static bool fluid_validatepaths(FluidJob *job, ReportList *reports)
if (!dir_exists) {
char cache_name[64];
BKE_fluid_cache_new_name_for_current_session(sizeof(cache_name), cache_name);
- modifier_path_init(mds->cache_directory, sizeof(mds->cache_directory), cache_name);
+ BKE_modifier_path_init(mds->cache_directory, sizeof(mds->cache_directory), cache_name);
BKE_reportf(reports,
RPT_ERROR,
@@ -361,7 +362,7 @@ static void fluid_bake_endjob(void *customdata)
RPT_INFO, "Fluid: %s complete! (%.2f)", job->name, PIL_check_seconds_timer() - job->start);
}
else {
- if (mds->error != NULL && mds->error[0] != '\0') {
+ if (mds->error[0] != '\0') {
WM_reportf(RPT_ERROR, "Fluid: %s failed: %s", job->name, mds->error);
}
else { /* User canceled the bake */
@@ -376,7 +377,7 @@ static void fluid_bake_startjob(void *customdata, short *stop, short *do_update,
FluidDomainSettings *mds = job->mmd->domain;
char temp_dir[FILE_MAX];
- const char *relbase = modifier_path_relbase_from_global(job->ob);
+ const char *relbase = BKE_modifier_path_relbase_from_global(job->ob);
job->stop = stop;
job->do_update = do_update;
@@ -473,7 +474,7 @@ static void fluid_free_endjob(void *customdata)
RPT_INFO, "Fluid: %s complete! (%.2f)", job->name, PIL_check_seconds_timer() - job->start);
}
else {
- if (mds->error != NULL && mds->error[0] != '\0') {
+ if (mds->error[0] != '\0') {
WM_reportf(RPT_ERROR, "Fluid: %s failed: %s", job->name, mds->error);
}
else { /* User canceled the free job */
@@ -616,13 +617,13 @@ static int fluid_free_exec(struct bContext *C, struct wmOperator *op)
{
FluidModifierData *mmd = NULL;
FluidDomainSettings *mds;
- Object *ob = CTX_data_active_object(C);
+ Object *ob = ED_object_active_context(C);
Scene *scene = CTX_data_scene(C);
/*
* Get modifier data
*/
- mmd = (FluidModifierData *)modifiers_findByType(ob, eModifierType_Fluid);
+ mmd = (FluidModifierData *)BKE_modifiers_findby_type(ob, eModifierType_Fluid);
if (!mmd) {
BKE_report(op->reports, RPT_ERROR, "Bake free failed: no Fluid modifier found");
return OPERATOR_CANCELLED;
@@ -679,12 +680,12 @@ static int fluid_pause_exec(struct bContext *C, struct wmOperator *op)
{
FluidModifierData *mmd = NULL;
FluidDomainSettings *mds;
- Object *ob = CTX_data_active_object(C);
+ Object *ob = ED_object_active_context(C);
/*
* Get modifier data
*/
- mmd = (FluidModifierData *)modifiers_findByType(ob, eModifierType_Fluid);
+ mmd = (FluidModifierData *)BKE_modifiers_findby_type(ob, eModifierType_Fluid);
if (!mmd) {
BKE_report(op->reports, RPT_ERROR, "Bake free failed: no Fluid modifier found");
return OPERATOR_CANCELLED;
diff --git a/source/blender/editors/render/render_internal.c b/source/blender/editors/render/render_internal.c
index 8a8fd703845..1db7bf5a766 100644
--- a/source/blender/editors/render/render_internal.c
+++ b/source/blender/editors/render/render_internal.c
@@ -112,7 +112,7 @@ typedef struct RenderJob {
ReportList *reports;
int orig_layer;
int last_layer;
- ScrArea *sa;
+ ScrArea *area;
ColorManagedViewSettings view_settings;
ColorManagedDisplaySettings display_settings;
bool supports_glsl_draw;
@@ -349,7 +349,6 @@ static int screen_render_exec(bContext *C, wmOperator *op)
RE_SetReports(re, op->reports);
- BLI_threaded_malloc_begin();
if (is_animation) {
RE_RenderAnim(re,
mainp,
@@ -363,7 +362,6 @@ static int screen_render_exec(bContext *C, wmOperator *op)
else {
RE_RenderFrame(re, mainp, scene, single_layer, camera_override, scene->r.cfra, is_write_still);
}
- BLI_threaded_malloc_end();
RE_SetReports(re, NULL);
@@ -391,16 +389,14 @@ static void make_renderinfo_string(const RenderStats *rs,
char *str)
{
char info_time_str[32]; // used to be extern to header_info.c
- uintptr_t mem_in_use, mmap_in_use, peak_memory;
- float megs_used_memory, mmap_used_memory, megs_peak_memory;
+ uintptr_t mem_in_use, peak_memory;
+ float megs_used_memory, megs_peak_memory;
char *spos = str;
mem_in_use = MEM_get_memory_in_use();
- mmap_in_use = MEM_get_mapped_memory_in_use();
peak_memory = MEM_get_peak_memory();
- megs_used_memory = (mem_in_use - mmap_in_use) / (1024.0 * 1024.0);
- mmap_used_memory = (mmap_in_use) / (1024.0 * 1024.0);
+ megs_used_memory = (mem_in_use) / (1024.0 * 1024.0);
megs_peak_memory = (peak_memory) / (1024.0 * 1024.0);
/* local view */
@@ -441,7 +437,7 @@ static void make_renderinfo_string(const RenderStats *rs,
}
}
else {
- if (rs->totvert || rs->totface || rs->tothalo || rs->totstrand || rs->totlamp) {
+ if (rs->totvert || rs->totface || rs->totlamp) {
spos += sprintf(spos, "| ");
}
@@ -451,38 +447,16 @@ static void make_renderinfo_string(const RenderStats *rs,
if (rs->totface) {
spos += sprintf(spos, TIP_("Fa:%d "), rs->totface);
}
- if (rs->tothalo) {
- spos += sprintf(spos, TIP_("Ha:%d "), rs->tothalo);
- }
- if (rs->totstrand) {
- spos += sprintf(spos, TIP_("St:%d "), rs->totstrand);
- }
if (rs->totlamp) {
spos += sprintf(spos, TIP_("Li:%d "), rs->totlamp);
}
if (rs->mem_peak == 0.0f) {
- spos += sprintf(spos,
- TIP_("| Mem:%.2fM (%.2fM, Peak %.2fM) "),
- megs_used_memory,
- mmap_used_memory,
- megs_peak_memory);
+ spos += sprintf(spos, TIP_("| Mem:%.2fM (Peak %.2fM) "), megs_used_memory, megs_peak_memory);
}
else {
spos += sprintf(spos, TIP_("| Mem:%.2fM, Peak: %.2fM "), rs->mem_used, rs->mem_peak);
}
-
- if (rs->curfield) {
- spos += sprintf(spos, TIP_("Field %d "), rs->curfield);
- }
- if (rs->curblur) {
- spos += sprintf(spos, TIP_("Blur %d "), rs->curblur);
- }
- }
-
- /* full sample */
- if (rs->curfsa) {
- spos += sprintf(spos, TIP_("| Full Sample %d "), rs->curfsa);
}
/* extra info */
@@ -543,24 +517,24 @@ static void render_progress_update(void *rjv, float progress)
static void render_image_update_pass_and_layer(RenderJob *rj, RenderResult *rr, ImageUser *iuser)
{
wmWindowManager *wm;
- ScrArea *first_sa = NULL, *matched_sa = NULL;
+ ScrArea *first_area = NULL, *matched_area = NULL;
/* image window, compo node users */
- for (wm = rj->main->wm.first; wm && matched_sa == NULL; wm = wm->id.next) { /* only 1 wm */
+ for (wm = rj->main->wm.first; wm && matched_area == NULL; wm = wm->id.next) { /* only 1 wm */
wmWindow *win;
- for (win = wm->windows.first; win && matched_sa == NULL; win = win->next) {
+ for (win = wm->windows.first; win && matched_area == NULL; win = win->next) {
const bScreen *screen = WM_window_get_active_screen(win);
- for (ScrArea *sa = screen->areabase.first; sa; sa = sa->next) {
- if (sa->spacetype == SPACE_IMAGE) {
- SpaceImage *sima = sa->spacedata.first;
- // sa->spacedata might be empty when toggling fullscreen mode.
+ LISTBASE_FOREACH (ScrArea *, area, &screen->areabase) {
+ if (area->spacetype == SPACE_IMAGE) {
+ SpaceImage *sima = area->spacedata.first;
+ // area->spacedata might be empty when toggling fullscreen mode.
if (sima != NULL && sima->image == rj->image) {
- if (first_sa == NULL) {
- first_sa = sa;
+ if (first_area == NULL) {
+ first_area = area;
}
- if (sa == rj->sa) {
- matched_sa = sa;
+ if (area == rj->area) {
+ matched_area = area;
break;
}
}
@@ -569,12 +543,12 @@ static void render_image_update_pass_and_layer(RenderJob *rj, RenderResult *rr,
}
}
- if (matched_sa == NULL) {
- matched_sa = first_sa;
+ if (matched_area == NULL) {
+ matched_area = first_area;
}
- if (matched_sa) {
- SpaceImage *sima = matched_sa->spacedata.first;
+ if (matched_area) {
+ SpaceImage *sima = matched_area->spacedata.first;
RenderResult *main_rr = RE_AcquireResultRead(rj->re);
/* TODO(sergey): is there faster way to get the layer index? */
@@ -689,10 +663,10 @@ static void render_image_restore_layer(RenderJob *rj)
for (win = wm->windows.first; win; win = win->next) {
const bScreen *screen = WM_window_get_active_screen(win);
- for (ScrArea *sa = screen->areabase.first; sa; sa = sa->next) {
- if (sa == rj->sa) {
- if (sa->spacetype == SPACE_IMAGE) {
- SpaceImage *sima = sa->spacedata.first;
+ LISTBASE_FOREACH (ScrArea *, area, &screen->areabase) {
+ if (area == rj->area) {
+ if (area->spacetype == SPACE_IMAGE) {
+ SpaceImage *sima = area->spacedata.first;
if (RE_HasSingleLayer(rj->re)) {
/* For single layer renders keep the active layer
@@ -748,7 +722,7 @@ static void render_endjob(void *rjv)
WM_main_add_notifier(NC_NODE | NA_EDITED, rj->scene);
}
- if (rj->sa) {
+ if (rj->area) {
render_image_restore_layer(rj);
}
@@ -887,7 +861,7 @@ static void clean_viewport_memory(Main *bmain, Scene *scene)
/* Go over all the visible objects. */
for (wmWindowManager *wm = bmain->wm.first; wm; wm = wm->id.next) {
- for (wmWindow *win = wm->windows.first; win; win = win->next) {
+ LISTBASE_FOREACH (wmWindow *, win, &wm->windows) {
ViewLayer *view_layer = WM_window_get_active_view_layer(win);
for (base = view_layer->object_bases.first; base; base = base->next) {
@@ -920,7 +894,7 @@ static int screen_render_invoke(bContext *C, wmOperator *op, const wmEvent *even
View3D *v3d = use_viewport ? CTX_wm_view3d(C) : NULL;
struct Object *camera_override = v3d ? V3D_CAMERA_LOCAL(v3d) : NULL;
const char *name;
- ScrArea *sa;
+ ScrArea *area;
/* Cannot do render if there is not this function. */
if (re_type->render == NULL) {
@@ -945,6 +919,12 @@ static int screen_render_invoke(bContext *C, wmOperator *op, const wmEvent *even
return OPERATOR_CANCELLED;
}
+ /* Reports are done inside check function, and it will return false if there are other strips to
+ * render. */
+ if ((scene->r.scemode & R_DOSEQ) && BKE_sequencer_check_scene_recursion(scene, op->reports)) {
+ return OPERATOR_CANCELLED;
+ }
+
/* stop all running jobs, except screen one. currently previews frustrate Render */
WM_jobs_kill_all_except(CTX_wm_manager(C), CTX_wm_screen(C));
@@ -970,7 +950,7 @@ static int screen_render_invoke(bContext *C, wmOperator *op, const wmEvent *even
// store spare
/* ensure at least 1 area shows result */
- sa = render_view_open(C, event->x, event->y, op->reports);
+ area = render_view_open(C, event->x, event->y, op->reports);
/* job custom data */
rj = MEM_callocN(sizeof(RenderJob), "render job");
@@ -991,14 +971,14 @@ static int screen_render_invoke(bContext *C, wmOperator *op, const wmEvent *even
rj->reports = op->reports;
rj->orig_layer = 0;
rj->last_layer = 0;
- rj->sa = sa;
+ rj->area = area;
rj->supports_glsl_draw = IMB_colormanagement_support_glsl_draw(&scene->view_settings);
BKE_color_managed_display_settings_copy(&rj->display_settings, &scene->display_settings);
BKE_color_managed_view_settings_copy(&rj->view_settings, &scene->view_settings);
- if (sa) {
- SpaceImage *sima = sa->spacedata.first;
+ if (area) {
+ SpaceImage *sima = area->spacedata.first;
rj->orig_layer = sima->iuser.layer;
}
diff --git a/source/blender/editors/render/render_opengl.c b/source/blender/editors/render/render_opengl.c
index 442f700ad6f..2861e851282 100644
--- a/source/blender/editors/render/render_opengl.c
+++ b/source/blender/editors/render/render_opengl.c
@@ -43,7 +43,7 @@
#include "DNA_object_types.h"
#include "DNA_scene_types.h"
-#include "BKE_animsys.h"
+#include "BKE_anim_data.h"
#include "BKE_camera.h"
#include "BKE_context.h"
#include "BKE_customdata.h"
@@ -144,14 +144,13 @@ typedef struct OGLRender {
wmTimer *timer; /* use to check if running modal or not (invoke'd or exec'd)*/
void **movie_ctx_arr;
- TaskScheduler *task_scheduler;
TaskPool *task_pool;
bool pool_ok;
bool is_animation;
eImageFormatDepth color_depth;
SpinLock reports_lock;
- unsigned int num_scheduled_frames;
+ uint num_scheduled_frames;
ThreadMutex task_mutex;
ThreadCondition task_condition;
@@ -296,7 +295,7 @@ static void screen_opengl_render_doit(const bContext *C, OGLRender *oglrender, R
const short view_context = (v3d != NULL);
bool draw_sky = (scene->r.alphamode == R_ADDSKY);
float *rectf = NULL;
- unsigned char *rect = NULL;
+ uchar *rect = NULL;
const char *viewname = RE_GetActiveRenderView(oglrender->re);
ImBuf *ibuf_result = NULL;
@@ -334,9 +333,8 @@ static void screen_opengl_render_doit(const bContext *C, OGLRender *oglrender, R
if (gpd) {
int i;
- unsigned char *gp_rect;
- unsigned char *render_rect =
- (unsigned char *)RE_RenderViewGetById(rr, oglrender->view_id)->rect32;
+ uchar *gp_rect;
+ uchar *render_rect = (uchar *)RE_RenderViewGetById(rr, oglrender->view_id)->rect32;
DRW_opengl_context_enable();
GPU_offscreen_bind(oglrender->ofs, true);
@@ -352,7 +350,7 @@ static void screen_opengl_render_doit(const bContext *C, OGLRender *oglrender, R
ED_annotation_draw_ex(scene, gpd, sizex, sizey, scene->r.cfra, SPACE_SEQ);
G.f &= ~G_FLAG_RENDER_VIEWPORT;
- gp_rect = MEM_mallocN(sizex * sizey * sizeof(unsigned char) * 4, "offscreen rect");
+ gp_rect = MEM_mallocN(sizex * sizey * sizeof(uchar) * 4, "offscreen rect");
GPU_offscreen_read_pixels(oglrender->ofs, GL_UNSIGNED_BYTE, gp_rect);
for (i = 0; i < sizex * sizey * 4; i += 4) {
@@ -414,7 +412,7 @@ static void screen_opengl_render_doit(const bContext *C, OGLRender *oglrender, R
rectf = ibuf_view->rect_float;
}
else {
- rect = (unsigned char *)ibuf_view->rect;
+ rect = (uchar *)ibuf_view->rect;
}
}
else {
@@ -496,7 +494,7 @@ static void screen_opengl_render_apply(const bContext *C, OGLRender *oglrender)
scene,
oglrender->sizex,
oglrender->sizey,
- 100.0f,
+ 100,
false,
&context);
@@ -631,6 +629,7 @@ static int gather_frames_to_render_for_id(LibraryIDLinkCallbackData *cb_data)
case ID_HA: /* Hair */
case ID_PT: /* PointCloud */
case ID_VO: /* Volume */
+ case ID_SIM: /* Simulation */
break;
/* Blacklist: */
@@ -856,21 +855,16 @@ static bool screen_opengl_render_init(bContext *C, wmOperator *op)
gather_frames_to_render(C, oglrender);
}
- TaskScheduler *task_scheduler = BLI_task_scheduler_get();
if (BKE_imtype_is_movie(scene->r.im_format.imtype)) {
- task_scheduler = BLI_task_scheduler_create(1);
- oglrender->task_scheduler = task_scheduler;
- oglrender->task_pool = BLI_task_pool_create_background(task_scheduler, oglrender);
+ oglrender->task_pool = BLI_task_pool_create_background_serial(oglrender, TASK_PRIORITY_LOW);
}
else {
- oglrender->task_scheduler = NULL;
- oglrender->task_pool = BLI_task_pool_create(task_scheduler, oglrender);
+ oglrender->task_pool = BLI_task_pool_create(oglrender, TASK_PRIORITY_LOW);
}
oglrender->pool_ok = true;
BLI_spin_init(&oglrender->reports_lock);
}
else {
- oglrender->task_scheduler = NULL;
oglrender->task_pool = NULL;
}
oglrender->num_scheduled_frames = 0;
@@ -909,10 +903,6 @@ static void screen_opengl_render_end(bContext *C, OGLRender *oglrender)
}
BLI_task_pool_work_and_wait(oglrender->task_pool);
BLI_task_pool_free(oglrender->task_pool);
- /* Depending on various things we might or might not use global scheduler. */
- if (oglrender->task_scheduler != NULL) {
- BLI_task_scheduler_free(oglrender->task_scheduler);
- }
BLI_spin_end(&oglrender->reports_lock);
}
BLI_mutex_end(&oglrender->task_mutex);
@@ -1032,9 +1022,9 @@ typedef struct WriteTaskData {
Scene tmp_scene;
} WriteTaskData;
-static void write_result_func(TaskPool *__restrict pool, void *task_data_v, int UNUSED(thread_id))
+static void write_result_func(TaskPool *__restrict pool, void *task_data_v)
{
- OGLRender *oglrender = (OGLRender *)BLI_task_pool_userdata(pool);
+ OGLRender *oglrender = (OGLRender *)BLI_task_pool_user_data(pool);
WriteTaskData *task_data = (WriteTaskData *)task_data_v;
Scene *scene = &task_data->tmp_scene;
RenderResult *rr = task_data->rr;
@@ -1124,7 +1114,7 @@ static bool schedule_write_result(OGLRender *oglrender, RenderResult *rr)
BLI_condition_wait(&oglrender->task_condition, &oglrender->task_mutex);
}
BLI_mutex_unlock(&oglrender->task_mutex);
- BLI_task_pool_push(oglrender->task_pool, write_result_func, task_data, true, TASK_PRIORITY_LOW);
+ BLI_task_pool_push(oglrender->task_pool, write_result_func, task_data, true, NULL);
return true;
}
diff --git a/source/blender/editors/render/render_preview.c b/source/blender/editors/render/render_preview.c
index 1427c6ed500..0432057bb47 100644
--- a/source/blender/editors/render/render_preview.c
+++ b/source/blender/editors/render/render_preview.c
@@ -167,7 +167,7 @@ typedef struct ShaderPreview {
float color[4];
int sizex, sizey;
- unsigned int *pr_rect;
+ uint *pr_rect;
int pr_method;
bool own_id_copy;
@@ -178,7 +178,7 @@ typedef struct ShaderPreview {
typedef struct IconPreviewSize {
struct IconPreviewSize *next, *prev;
int sizex, sizey;
- unsigned int *rect;
+ uint *rect;
} IconPreviewSize;
typedef struct IconPreview {
@@ -304,7 +304,7 @@ static void set_preview_visibility(Scene *scene,
}
/* Hide floor for icon renders. */
- for (Base *base = view_layer->object_bases.first; base; base = base->next) {
+ LISTBASE_FOREACH (Base *, base, &view_layer->object_bases) {
if (STREQ(base->object->id.name + 2, "Floor")) {
if (pr_method == PR_ICON_RENDER) {
base->object->restrictflag |= OB_RESTRICT_RENDER;
@@ -463,7 +463,7 @@ static Scene *preview_prepare_scene(
sce->display.render_aa = SCE_DISPLAY_AA_OFF;
}
- for (Base *base = view_layer->object_bases.first; base; base = base->next) {
+ LISTBASE_FOREACH (Base *, base, &view_layer->object_bases) {
if (base->object->id.name[2] == 'p') {
/* copy over object color, in case material uses it */
copy_v4_v4(base->object->color, sp->color);
@@ -522,7 +522,7 @@ static Scene *preview_prepare_scene(
sce->world->horb = 0.0f;
}
- for (Base *base = view_layer->object_bases.first; base; base = base->next) {
+ LISTBASE_FOREACH (Base *, base, &view_layer->object_bases) {
if (base->object->id.name[2] == 'p') {
if (base->object->type == OB_LAMP) {
base->object->data = la;
@@ -566,7 +566,7 @@ static Scene *preview_prepare_scene(
/* new UI convention: draw is in pixel space already. */
/* uses UI_BTYPE_ROUNDBOX button in block to get the rect */
-static bool ed_preview_draw_rect(ScrArea *sa, int split, int first, rcti *rect, rcti *newrect)
+static bool ed_preview_draw_rect(ScrArea *area, int split, int first, rcti *rect, rcti *newrect)
{
Render *re;
RenderView *rv;
@@ -578,10 +578,10 @@ static bool ed_preview_draw_rect(ScrArea *sa, int split, int first, rcti *rect,
bool ok = false;
if (!split || first) {
- sprintf(name, "Preview %p", (void *)sa);
+ sprintf(name, "Preview %p", (void *)area);
}
else {
- sprintf(name, "SecondPreview %p", (void *)sa);
+ sprintf(name, "SecondPreview %p", (void *)area);
}
if (split) {
@@ -621,14 +621,14 @@ static bool ed_preview_draw_rect(ScrArea *sa, int split, int first, rcti *rect,
newrect->ymax = max_ii(newrect->ymax, rect->ymin + rres.recty);
if (rres.rectx && rres.recty) {
- unsigned char *rect_byte = MEM_mallocN(rres.rectx * rres.recty * sizeof(int),
- "ed_preview_draw_rect");
+ uchar *rect_byte = MEM_mallocN(rres.rectx * rres.recty * sizeof(int),
+ "ed_preview_draw_rect");
float fx = rect->xmin + offx;
float fy = rect->ymin;
/* material preview only needs monoscopy (view 0) */
if (re) {
- RE_AcquiredResultGet32(re, &rres, (unsigned int *)rect_byte, 0);
+ RE_AcquiredResultGet32(re, &rres, (uint *)rect_byte, 0);
}
IMMDrawPixelsTexState state = immDrawPixelsTexSetup(GPU_SHADER_2D_IMAGE_COLOR);
@@ -661,12 +661,12 @@ void ED_preview_draw(const bContext *C, void *idp, void *parentp, void *slotp, r
{
if (idp) {
wmWindowManager *wm = CTX_wm_manager(C);
- ScrArea *sa = CTX_wm_area(C);
+ ScrArea *area = CTX_wm_area(C);
ID *id = (ID *)idp;
ID *parent = (ID *)parentp;
MTex *slot = (MTex *)slotp;
SpaceProperties *sbuts = CTX_wm_space_properties(C);
- ShaderPreview *sp = WM_jobs_customdata(wm, sa);
+ ShaderPreview *sp = WM_jobs_customdata(wm, area);
rcti newrect;
int ok;
int newx = BLI_rcti_size_x(rect);
@@ -678,11 +678,11 @@ void ED_preview_draw(const bContext *C, void *idp, void *parentp, void *slotp, r
newrect.ymax = rect->ymin;
if (parent) {
- ok = ed_preview_draw_rect(sa, 1, 1, rect, &newrect);
- ok &= ed_preview_draw_rect(sa, 1, 0, rect, &newrect);
+ ok = ed_preview_draw_rect(area, 1, 1, rect, &newrect);
+ ok &= ed_preview_draw_rect(area, 1, 0, rect, &newrect);
}
else {
- ok = ed_preview_draw_rect(sa, 0, 0, rect, &newrect);
+ ok = ed_preview_draw_rect(area, 0, 0, rect, &newrect);
}
if (ok) {
@@ -693,12 +693,12 @@ void ED_preview_draw(const bContext *C, void *idp, void *parentp, void *slotp, r
* if no render result was found and no preview render job is running,
* or if the job is running and the size of preview changed */
if ((sbuts != NULL && sbuts->preview) ||
- (!ok && !WM_jobs_test(wm, sa, WM_JOB_TYPE_RENDER_PREVIEW)) ||
+ (!ok && !WM_jobs_test(wm, area, WM_JOB_TYPE_RENDER_PREVIEW)) ||
(sp && (abs(sp->sizex - newx) >= 2 || abs(sp->sizey - newy) > 2))) {
if (sbuts != NULL) {
sbuts->preview = 0;
}
- ED_preview_shader_job(C, sa, id, parent, slot, newx, newy, PR_BUTS_RENDER);
+ ED_preview_shader_job(C, area, id, parent, slot, newx, newy, PR_BUTS_RENDER);
}
}
}
@@ -1014,10 +1014,10 @@ static void shader_preview_free(void *customdata)
/* ************************* icon preview ********************** */
-static void icon_copy_rect(ImBuf *ibuf, unsigned int w, unsigned int h, unsigned int *rect)
+static void icon_copy_rect(ImBuf *ibuf, uint w, uint h, uint *rect)
{
struct ImBuf *ima;
- unsigned int *drect, *srect;
+ uint *drect, *srect;
float scaledx, scaledy;
short ex, ey, dx, dy;
@@ -1144,7 +1144,7 @@ static void icon_preview_startjob(void *customdata, short *stop, short *do_updat
br->icon_imbuf = get_brush_icon(br);
- memset(sp->pr_rect, 0x88, sp->sizex * sp->sizey * sizeof(unsigned int));
+ memset(sp->pr_rect, 0x88, sp->sizex * sp->sizey * sizeof(uint));
if (!(br->icon_imbuf) || !(br->icon_imbuf->rect)) {
return;
@@ -1193,7 +1193,7 @@ static void common_preview_startjob(void *customdata,
/* exported functions */
-static void icon_preview_add_size(IconPreview *ip, unsigned int *rect, int sizex, int sizey)
+static void icon_preview_add_size(IconPreview *ip, uint *rect, int sizex, int sizey)
{
IconPreviewSize *cur_size = ip->sizes.first, *new_size;
@@ -1324,8 +1324,7 @@ static void icon_preview_free(void *customdata)
MEM_freeN(ip);
}
-void ED_preview_icon_render(
- Main *bmain, Scene *scene, ID *id, unsigned int *rect, int sizex, int sizey)
+void ED_preview_icon_render(Main *bmain, Scene *scene, ID *id, uint *rect, int sizex, int sizey)
{
IconPreview ip = {NULL};
short stop = false, update = false;
@@ -1348,13 +1347,8 @@ void ED_preview_icon_render(
BLI_freelistN(&ip.sizes);
}
-void ED_preview_icon_job(const bContext *C,
- void *owner,
- ID *id,
- unsigned int *rect,
- int sizex,
- int sizey,
- const bool delay)
+void ED_preview_icon_job(
+ const bContext *C, void *owner, ID *id, uint *rect, int sizex, int sizey, const bool delay)
{
wmJob *wm_job;
IconPreview *ip, *old_ip;
diff --git a/source/blender/editors/render/render_shading.c b/source/blender/editors/render/render_shading.c
index e1fa4caafbd..49ab2c485b1 100644
--- a/source/blender/editors/render/render_shading.c
+++ b/source/blender/editors/render/render_shading.c
@@ -42,6 +42,7 @@
#include "BLT_translation.h"
+#include "BKE_anim_data.h"
#include "BKE_animsys.h"
#include "BKE_brush.h"
#include "BKE_context.h"
@@ -100,15 +101,15 @@
*/
static Object **object_array_for_shading(bContext *C, uint *r_objects_len)
{
- ScrArea *sa = CTX_wm_area(C);
+ ScrArea *area = CTX_wm_area(C);
SpaceProperties *sbuts = NULL;
View3D *v3d = NULL;
- if (sa != NULL) {
- if (sa->spacetype == SPACE_PROPERTIES) {
- sbuts = sa->spacedata.first;
+ if (area != NULL) {
+ if (area->spacetype == SPACE_PROPERTIES) {
+ sbuts = area->spacedata.first;
}
- else if (sa->spacetype == SPACE_VIEW3D) {
- v3d = sa->spacedata.first;
+ else if (area->spacetype == SPACE_VIEW3D) {
+ v3d = area->spacedata.first;
}
}
@@ -506,7 +507,7 @@ static int material_slot_move_exec(bContext *C, wmOperator *op)
{
Object *ob = ED_object_context(C);
- unsigned int *slot_remap;
+ uint *slot_remap;
int index_pair[2];
int dir = RNA_enum_get(op->ptr, "direction");
@@ -531,7 +532,7 @@ static int material_slot_move_exec(bContext *C, wmOperator *op)
return OPERATOR_CANCELLED;
}
- slot_remap = MEM_mallocN(sizeof(unsigned int) * ob->totcol, __func__);
+ slot_remap = MEM_mallocN(sizeof(uint) * ob->totcol, __func__);
range_vn_u(slot_remap, ob->totcol, 0);
diff --git a/source/blender/editors/render/render_update.c b/source/blender/editors/render/render_update.c
index d2bb53de06f..10f69f3fe9d 100644
--- a/source/blender/editors/render/render_update.c
+++ b/source/blender/editors/render/render_update.c
@@ -105,18 +105,18 @@ void ED_render_scene_update(const DEGEditorUpdateContext *update_ctx, int update
wm = bmain->wm.first;
for (win = wm->windows.first; win; win = win->next) {
- bScreen *sc = WM_window_get_active_screen(win);
- ScrArea *sa;
+ bScreen *screen = WM_window_get_active_screen(win);
+ ScrArea *area;
ARegion *region;
CTX_wm_window_set(C, win);
- for (sa = sc->areabase.first; sa; sa = sa->next) {
- if (sa->spacetype != SPACE_VIEW3D) {
+ for (area = screen->areabase.first; area; area = area->next) {
+ if (area->spacetype != SPACE_VIEW3D) {
continue;
}
- View3D *v3d = sa->spacedata.first;
- for (region = sa->regionbase.first; region; region = region->next) {
+ View3D *v3d = area->spacedata.first;
+ for (region = area->regionbase.first; region; region = region->next) {
if (region->regiontype != RGN_TYPE_WINDOW) {
continue;
}
@@ -127,8 +127,8 @@ void ED_render_scene_update(const DEGEditorUpdateContext *update_ctx, int update
* time of the last update) */
if (engine && (updated || (engine->flag & RE_ENGINE_DO_UPDATE))) {
- CTX_wm_screen_set(C, sc);
- CTX_wm_area_set(C, sa);
+ CTX_wm_screen_set(C, screen);
+ CTX_wm_area_set(C, area);
CTX_wm_region_set(C, region);
engine->flag &= ~RE_ENGINE_DO_UPDATE;
@@ -146,7 +146,7 @@ void ED_render_scene_update(const DEGEditorUpdateContext *update_ctx, int update
.scene = scene,
.view_layer = view_layer,
.region = region,
- .v3d = (View3D *)sa->spacedata.first,
+ .v3d = (View3D *)area->spacedata.first,
.engine_type = engine_type,
}));
}
@@ -160,17 +160,17 @@ void ED_render_scene_update(const DEGEditorUpdateContext *update_ctx, int update
recursive_check = false;
}
-void ED_render_engine_area_exit(Main *bmain, ScrArea *sa)
+void ED_render_engine_area_exit(Main *bmain, ScrArea *area)
{
/* clear all render engines in this area */
ARegion *region;
wmWindowManager *wm = bmain->wm.first;
- if (sa->spacetype != SPACE_VIEW3D) {
+ if (area->spacetype != SPACE_VIEW3D) {
return;
}
- for (region = sa->regionbase.first; region; region = region->next) {
+ for (region = area->regionbase.first; region; region = region->next) {
if (region->regiontype != RGN_TYPE_WINDOW || !(region->regiondata)) {
continue;
}
@@ -181,9 +181,9 @@ 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 */
- for (bScreen *sc = bmain->screens.first; sc; sc = sc->id.next) {
- for (ScrArea *sa = sc->areabase.first; sa; sa = sa->next) {
- ED_render_engine_area_exit(bmain, sa);
+ for (bScreen *screen = bmain->screens.first; screen; screen = screen->id.next) {
+ LISTBASE_FOREACH (ScrArea *, area, &screen->areabase) {
+ ED_render_engine_area_exit(bmain, area);
}
}
RE_FreePersistentData();
@@ -204,10 +204,10 @@ void ED_render_engine_changed(Main *bmain)
}
}
-void ED_render_view_layer_changed(Main *bmain, bScreen *sc)
+void ED_render_view_layer_changed(Main *bmain, bScreen *screen)
{
- for (ScrArea *sa = sc->areabase.first; sa; sa = sa->next) {
- ED_render_engine_area_exit(bmain, sa);
+ LISTBASE_FOREACH (ScrArea *, area, &screen->areabase) {
+ ED_render_engine_area_exit(bmain, area);
}
}
diff --git a/source/blender/editors/render/render_view.c b/source/blender/editors/render/render_view.c
index a93ea343229..a9c855b14b0 100644
--- a/source/blender/editors/render/render_view.c
+++ b/source/blender/editors/render/render_view.c
@@ -56,23 +56,23 @@
/* would use BKE_screen_find_big_area(...) but this is too specific */
static ScrArea *biggest_non_image_area(bContext *C)
{
- bScreen *sc = CTX_wm_screen(C);
- ScrArea *sa, *big = NULL;
+ bScreen *screen = CTX_wm_screen(C);
+ ScrArea *area, *big = NULL;
int size, maxsize = 0, bwmaxsize = 0;
short foundwin = 0;
- for (sa = sc->areabase.first; sa; sa = sa->next) {
- if (sa->winx > 30 && sa->winy > 30) {
- size = sa->winx * sa->winy;
- if (!sa->full && sa->spacetype == SPACE_PROPERTIES) {
+ for (area = screen->areabase.first; area; area = area->next) {
+ if (area->winx > 30 && area->winy > 30) {
+ size = area->winx * area->winy;
+ if (!area->full && area->spacetype == SPACE_PROPERTIES) {
if (foundwin == 0 && size > bwmaxsize) {
bwmaxsize = size;
- big = sa;
+ big = area;
}
}
- else if (sa->spacetype != SPACE_IMAGE && size > maxsize) {
+ else if (area->spacetype != SPACE_IMAGE && size > maxsize) {
maxsize = size;
- big = sa;
+ big = area;
foundwin = 1;
}
}
@@ -84,7 +84,7 @@ static ScrArea *biggest_non_image_area(bContext *C)
static ScrArea *find_area_showing_r_result(bContext *C, Scene *scene, wmWindow **win)
{
wmWindowManager *wm = CTX_wm_manager(C);
- ScrArea *sa = NULL;
+ ScrArea *area = NULL;
SpaceImage *sima;
/* find an imagewindow showing render result */
@@ -92,40 +92,40 @@ static ScrArea *find_area_showing_r_result(bContext *C, Scene *scene, wmWindow *
if (WM_window_get_active_scene(*win) == scene) {
const bScreen *screen = WM_window_get_active_screen(*win);
- for (sa = screen->areabase.first; sa; sa = sa->next) {
- if (sa->spacetype == SPACE_IMAGE) {
- sima = sa->spacedata.first;
+ for (area = screen->areabase.first; area; area = area->next) {
+ if (area->spacetype == SPACE_IMAGE) {
+ sima = area->spacedata.first;
if (sima->image && sima->image->type == IMA_TYPE_R_RESULT) {
break;
}
}
}
- if (sa) {
+ if (area) {
break;
}
}
}
- return sa;
+ return area;
}
static ScrArea *find_area_image_empty(bContext *C)
{
- bScreen *sc = CTX_wm_screen(C);
- ScrArea *sa;
+ bScreen *screen = CTX_wm_screen(C);
+ ScrArea *area;
SpaceImage *sima;
/* find an imagewindow showing render result */
- for (sa = sc->areabase.first; sa; sa = sa->next) {
- if (sa->spacetype == SPACE_IMAGE) {
- sima = sa->spacedata.first;
+ for (area = screen->areabase.first; area; area = area->next) {
+ if (area->spacetype == SPACE_IMAGE) {
+ sima = area->spacedata.first;
if ((sima->mode == SI_MODE_VIEW) && !sima->image) {
break;
}
}
}
- return sa;
+ return area;
}
/********************** open image editor for render *************************/
@@ -136,7 +136,7 @@ ScrArea *render_view_open(bContext *C, int mx, int my, ReportList *reports)
Main *bmain = CTX_data_main(C);
Scene *scene = CTX_data_scene(C);
wmWindow *win = NULL;
- ScrArea *sa = NULL;
+ ScrArea *area = NULL;
SpaceImage *sima;
bool area_was_image = false;
@@ -163,34 +163,34 @@ ScrArea *render_view_open(bContext *C, int mx, int my, ReportList *reports)
return NULL;
}
- sa = CTX_wm_area(C);
- if (BLI_listbase_is_single(&sa->spacedata) == false) {
- sima = sa->spacedata.first;
+ area = CTX_wm_area(C);
+ if (BLI_listbase_is_single(&area->spacedata) == false) {
+ sima = area->spacedata.first;
sima->flag |= SI_PREVSPACE;
}
}
else if (U.render_display_type == USER_RENDER_DISPLAY_SCREEN) {
- sa = CTX_wm_area(C);
+ area = CTX_wm_area(C);
/* if the active screen is already in fullscreen mode, skip this and
* unset the area, so that the fullscreen area is just changed later */
- if (sa && sa->full) {
- sa = NULL;
+ if (area && area->full) {
+ area = NULL;
}
else {
- if (sa && sa->spacetype == SPACE_IMAGE) {
+ if (area && area->spacetype == SPACE_IMAGE) {
area_was_image = true;
}
/* this function returns with changed context */
- sa = ED_screen_full_newspace(C, sa, SPACE_IMAGE);
+ area = ED_screen_full_newspace(C, area, SPACE_IMAGE);
}
}
- if (!sa) {
- sa = find_area_showing_r_result(C, scene, &win);
- if (sa == NULL) {
- sa = find_area_image_empty(C);
+ if (!area) {
+ area = find_area_showing_r_result(C, scene, &win);
+ if (area == NULL) {
+ area = find_area_image_empty(C);
}
/* if area found in other window, we make that one show in front */
@@ -198,27 +198,27 @@ ScrArea *render_view_open(bContext *C, int mx, int my, ReportList *reports)
wm_window_raise(win);
}
- if (sa == NULL) {
+ if (area == NULL) {
/* find largest open non-image area */
- sa = biggest_non_image_area(C);
- if (sa) {
- ED_area_newspace(C, sa, SPACE_IMAGE, true);
- sima = sa->spacedata.first;
+ area = biggest_non_image_area(C);
+ if (area) {
+ ED_area_newspace(C, area, SPACE_IMAGE, true);
+ sima = area->spacedata.first;
/* makes ESC go back to prev space */
sima->flag |= SI_PREVSPACE;
/* we already had a fullscreen here -> mark new space as a stacked fullscreen */
- if (sa->full) {
- sa->flag |= AREA_FLAG_STACKED_FULLSCREEN;
+ if (area->full) {
+ area->flag |= AREA_FLAG_STACKED_FULLSCREEN;
}
}
else {
/* use any area of decent size */
- sa = BKE_screen_find_big_area(CTX_wm_screen(C), SPACE_TYPE_ANY, 0);
- if (sa->spacetype != SPACE_IMAGE) {
- // XXX newspace(sa, SPACE_IMAGE);
- sima = sa->spacedata.first;
+ area = BKE_screen_find_big_area(CTX_wm_screen(C), SPACE_TYPE_ANY, 0);
+ if (area->spacetype != SPACE_IMAGE) {
+ // XXX newspace(area, SPACE_IMAGE);
+ sima = area->spacedata.first;
/* makes ESC go back to prev space */
sima->flag |= SI_PREVSPACE;
@@ -226,7 +226,7 @@ ScrArea *render_view_open(bContext *C, int mx, int my, ReportList *reports)
}
}
}
- sima = sa->spacedata.first;
+ sima = area->spacedata.first;
sima->link_flag |= SPACE_FLAG_TYPE_TEMPORARY;
/* get the correct image, and scale it */
@@ -234,7 +234,7 @@ ScrArea *render_view_open(bContext *C, int mx, int my, ReportList *reports)
/* If we're rendering to full screen, set appropriate hints on image editor
* so it can restore properly on pressing escape. */
- if (sa->full) {
+ if (area->full) {
sima->flag |= SI_FULLWINDOW;
/* Tell the image editor to revert to previous space in space list on close
@@ -253,7 +253,7 @@ ScrArea *render_view_open(bContext *C, int mx, int my, ReportList *reports)
old_sl->link_flag |= SPACE_FLAG_TYPE_WAS_ACTIVE;
}
- return sa;
+ return area;
}
/*************************** cancel render viewer **********************/
@@ -261,11 +261,11 @@ ScrArea *render_view_open(bContext *C, int mx, int my, ReportList *reports)
static int render_view_cancel_exec(bContext *C, wmOperator *UNUSED(op))
{
wmWindow *win = CTX_wm_window(C);
- ScrArea *sa = CTX_wm_area(C);
- SpaceImage *sima = sa->spacedata.first;
+ ScrArea *area = CTX_wm_area(C);
+ SpaceImage *sima = area->spacedata.first;
/* ensure image editor fullscreen and area fullscreen states are in sync */
- if ((sima->flag & SI_FULLWINDOW) && !sa->full) {
+ if ((sima->flag & SI_FULLWINDOW) && !area->full) {
sima->flag &= ~SI_FULLWINDOW;
}
@@ -275,17 +275,17 @@ static int render_view_cancel_exec(bContext *C, wmOperator *UNUSED(op))
if (sima->flag & SI_FULLWINDOW) {
sima->flag &= ~SI_FULLWINDOW;
- ED_screen_full_prevspace(C, sa);
+ ED_screen_full_prevspace(C, area);
}
else {
- ED_area_prevspace(C, sa);
+ ED_area_prevspace(C, area);
}
return OPERATOR_FINISHED;
}
else if (sima->flag & SI_FULLWINDOW) {
sima->flag &= ~SI_FULLWINDOW;
- ED_screen_state_toggle(C, win, sa, SCREENMAXIMIZED);
+ ED_screen_state_toggle(C, win, area, SCREENMAXIMIZED);
return OPERATOR_FINISHED;
}
else if (WM_window_is_temp_screen(win)) {
@@ -320,14 +320,14 @@ static int render_view_show_invoke(bContext *C, wmOperator *op, const wmEvent *e
}
else {
wmWindow *win, *winshow;
- ScrArea *sa = find_area_showing_r_result(C, CTX_data_scene(C), &winshow);
+ ScrArea *area = find_area_showing_r_result(C, CTX_data_scene(C), &winshow);
/* is there another window on current scene showing result? */
for (win = CTX_wm_manager(C)->windows.first; win; win = win->next) {
- const bScreen *sc = WM_window_get_active_screen(win);
+ const bScreen *screen = WM_window_get_active_screen(win);
if ((WM_window_is_temp_screen(win) &&
- ((ScrArea *)sc->areabase.first)->spacetype == SPACE_IMAGE) ||
+ ((ScrArea *)screen->areabase.first)->spacetype == SPACE_IMAGE) ||
(win == winshow && winshow != wincur)) {
wm_window_raise(win);
return OPERATOR_FINISHED;
@@ -335,20 +335,20 @@ static int render_view_show_invoke(bContext *C, wmOperator *op, const wmEvent *e
}
/* determine if render already shows */
- if (sa) {
+ if (area) {
/* but don't close it when rendering */
if (G.is_rendering == false) {
- SpaceImage *sima = sa->spacedata.first;
+ SpaceImage *sima = area->spacedata.first;
if (sima->flag & SI_PREVSPACE) {
sima->flag &= ~SI_PREVSPACE;
if (sima->flag & SI_FULLWINDOW) {
sima->flag &= ~SI_FULLWINDOW;
- ED_screen_full_prevspace(C, sa);
+ ED_screen_full_prevspace(C, area);
}
else {
- ED_area_prevspace(C, sa);
+ ED_area_prevspace(C, area);
}
}
}
diff --git a/source/blender/editors/scene/scene_edit.c b/source/blender/editors/scene/scene_edit.c
index 114cb54636a..d78b1532a39 100644
--- a/source/blender/editors/scene/scene_edit.c
+++ b/source/blender/editors/scene/scene_edit.c
@@ -99,7 +99,7 @@ bool ED_scene_delete(bContext *C, Main *bmain, Scene *scene)
return false;
}
- for (wmWindow *win = wm->windows.first; win; win = win->next) {
+ LISTBASE_FOREACH (wmWindow *, win, &wm->windows) {
if (win->parent != NULL) { /* We only care about main windows here... */
continue;
}
@@ -175,7 +175,7 @@ bool ED_scene_view_layer_delete(Main *bmain, Scene *scene, ViewLayer *layer, Rep
/* Remove from windows. */
wmWindowManager *wm = bmain->wm.first;
- for (wmWindow *win = wm->windows.first; win; win = win->next) {
+ LISTBASE_FOREACH (wmWindow *, win, &wm->windows) {
if (win->scene == scene && STREQ(win->view_layer_name, layer->name)) {
ViewLayer *first_layer = BKE_view_layer_default_view(scene);
STRNCPY(win->view_layer_name, first_layer->name);
diff --git a/source/blender/editors/screen/area.c b/source/blender/editors/screen/area.c
index ec875cfae2c..d403cdbc315 100644
--- a/source/blender/editors/screen/area.c
+++ b/source/blender/editors/screen/area.c
@@ -146,7 +146,7 @@ void ED_region_pixelspace(ARegion *region)
/* only exported for WM */
void ED_region_do_listen(
- wmWindow *win, ScrArea *sa, ARegion *region, wmNotifier *note, const Scene *scene)
+ wmWindow *win, ScrArea *area, ARegion *region, wmNotifier *note, const Scene *scene)
{
/* generic notes first */
switch (note->category) {
@@ -161,27 +161,27 @@ void ED_region_do_listen(
}
if (region->type && region->type->listener) {
- region->type->listener(win, sa, region, note, scene);
+ region->type->listener(win, area, region, note, scene);
}
}
/* only exported for WM */
-void ED_area_do_listen(wmWindow *win, ScrArea *sa, wmNotifier *note, Scene *scene)
+void ED_area_do_listen(wmWindow *win, ScrArea *area, wmNotifier *note, Scene *scene)
{
/* no generic notes? */
- if (sa->type && sa->type->listener) {
- sa->type->listener(win, sa, note, scene);
+ if (area->type && area->type->listener) {
+ area->type->listener(win, area, note, scene);
}
}
/* only exported for WM */
-void ED_area_do_refresh(bContext *C, ScrArea *sa)
+void ED_area_do_refresh(bContext *C, ScrArea *area)
{
/* no generic notes? */
- if (sa->type && sa->type->refresh) {
- sa->type->refresh(C, sa);
+ if (area->type && area->type->refresh) {
+ area->type->refresh(C, area);
}
- sa->do_refresh = false;
+ area->do_refresh = false;
}
/**
@@ -249,7 +249,9 @@ static void draw_azone_arrow(float x1, float y1, float x2, float y2, AZEdge edge
uint pos = GPU_vertformat_attr_add(format, "pos", GPU_COMP_F32, 2, GPU_FETCH_FLOAT);
GPU_blend(true);
- immBindBuiltinProgram(GPU_SHADER_2D_UNIFORM_COLOR);
+ /* NOTE(fclem): There is something strange going on with Mesa and GPU_SHADER_2D_UNIFORM_COLOR
+ * that causes a crash on some GPUs (see T76113). Using 3D variant avoid the issue. */
+ immBindBuiltinProgram(GPU_SHADER_3D_UNIFORM_COLOR);
immUniformColor4f(0.8f, 0.8f, 0.8f, 0.4f);
immBegin(GPU_PRIM_TRI_FAN, 6);
@@ -267,7 +269,7 @@ static void draw_azone_arrow(float x1, float y1, float x2, float y2, AZEdge edge
GPU_blend(false);
}
-static void region_draw_azone_tab_arrow(AZone *az)
+static void region_draw_azone_tab_arrow(ScrArea *area, ARegion *region, AZone *az)
{
GPU_blend(true);
@@ -287,23 +289,25 @@ static void region_draw_azone_tab_arrow(AZone *az)
break;
}
- float color[4] = {0.05f, 0.05f, 0.05f, 0.4f};
+ /* Workaround for different color spaces between normal areas and the ones using GPUViewports. */
+ float alpha = WM_region_use_viewport(area, region) ? 0.6f : 0.4f;
+ float color[4] = {0.05f, 0.05f, 0.05f, alpha};
UI_draw_roundbox_aa(
true, (float)az->x1, (float)az->y1, (float)az->x2, (float)az->y2, 4.0f, color);
draw_azone_arrow((float)az->x1, (float)az->y1, (float)az->x2, (float)az->y2, az->edge);
}
-static void area_azone_tag_update(ScrArea *sa)
+static void area_azone_tag_update(ScrArea *area)
{
- sa->flag |= AREA_FLAG_ACTIONZONES_UPDATE;
+ area->flag |= AREA_FLAG_ACTIONZONES_UPDATE;
}
-static void region_draw_azones(ScrArea *sa, ARegion *region)
+static void region_draw_azones(ScrArea *area, ARegion *region)
{
AZone *az;
- if (!sa) {
+ if (!area) {
return;
}
@@ -315,7 +319,7 @@ static void region_draw_azones(ScrArea *sa, ARegion *region)
GPU_matrix_push();
GPU_matrix_translate_2f(-region->winrct.xmin, -region->winrct.ymin);
- for (az = sa->actionzones.first; az; az = az->next) {
+ for (az = area->actionzones.first; az; az = az->next) {
/* test if action zone is over this region */
rcti azrct;
BLI_rcti_init(&azrct, az->x1, az->x2, az->y1, az->y2);
@@ -328,7 +332,7 @@ static void region_draw_azones(ScrArea *sa, ARegion *region)
if (az->region) {
/* only display tab or icons when the region is hidden */
if (az->region->flag & (RGN_FLAG_HIDDEN | RGN_FLAG_TOO_SMALL)) {
- region_draw_azone_tab_arrow(az);
+ region_draw_azone_tab_arrow(area, region, az);
}
}
}
@@ -339,7 +343,7 @@ static void region_draw_azones(ScrArea *sa, ARegion *region)
}
}
if (!IS_EQF(az->alpha, 0.0f) && ELEM(az->type, AZONE_FULLSCREEN, AZONE_REGION_SCROLL)) {
- area_azone_tag_update(sa);
+ area_azone_tag_update(area);
}
}
@@ -348,9 +352,9 @@ static void region_draw_azones(ScrArea *sa, ARegion *region)
GPU_blend(false);
}
-static void region_draw_status_text(ScrArea *sa, ARegion *region)
+static void region_draw_status_text(ScrArea *area, ARegion *region)
{
- bool overlap = ED_region_is_overlap(sa->spacetype, region->regiontype);
+ bool overlap = ED_region_is_overlap(area->spacetype, region->regiontype);
if (overlap) {
GPU_clear_color(0.0, 0.0, 0.0, 0.0);
@@ -421,8 +425,8 @@ void ED_area_do_msg_notify_tag_refresh(
wmMsgSubscribeKey *UNUSED(msg_key),
wmMsgSubscribeValue *msg_val)
{
- ScrArea *sa = msg_val->user_data;
- ED_area_tag_refresh(sa);
+ ScrArea *area = msg_val->user_data;
+ ED_area_tag_refresh(area);
}
void ED_area_do_mgs_subscribe_for_tool_header(
@@ -431,7 +435,7 @@ void ED_area_do_mgs_subscribe_for_tool_header(
struct WorkSpace *workspace,
struct Scene *UNUSED(scene),
struct bScreen *UNUSED(screen),
- struct ScrArea *UNUSED(sa),
+ struct ScrArea *UNUSED(area),
struct ARegion *region,
struct wmMsgBus *mbus)
{
@@ -451,7 +455,7 @@ void ED_area_do_mgs_subscribe_for_tool_ui(
struct WorkSpace *workspace,
struct Scene *UNUSED(scene),
struct bScreen *UNUSED(screen),
- struct ScrArea *UNUSED(sa),
+ struct ScrArea *UNUSED(area),
struct ARegion *region,
struct wmMsgBus *mbus)
{
@@ -483,20 +487,20 @@ static bool area_is_pseudo_minimized(const ScrArea *area)
void ED_region_do_layout(bContext *C, ARegion *region)
{
/* This is optional, only needed for dynamically sized regions. */
- ScrArea *sa = CTX_wm_area(C);
+ ScrArea *area = CTX_wm_area(C);
ARegionType *at = region->type;
if (!at->layout) {
return;
}
- if (at->do_lock || (sa && area_is_pseudo_minimized(sa))) {
+ if (at->do_lock || (area && area_is_pseudo_minimized(area))) {
return;
}
region->do_draw |= RGN_DRAWING;
- UI_SetTheme(sa ? sa->spacetype : 0, at->regionid);
+ UI_SetTheme(area ? area->spacetype : 0, at->regionid);
at->layout(C, region);
}
@@ -504,7 +508,7 @@ void ED_region_do_layout(bContext *C, ARegion *region)
void ED_region_do_draw(bContext *C, ARegion *region)
{
wmWindow *win = CTX_wm_window(C);
- ScrArea *sa = CTX_wm_area(C);
+ ScrArea *area = CTX_wm_area(C);
ARegionType *at = region->type;
/* see BKE_spacedata_draw_locks() */
@@ -519,16 +523,16 @@ void ED_region_do_draw(bContext *C, ARegion *region)
wmOrtho2_region_pixelspace(region);
- UI_SetTheme(sa ? sa->spacetype : 0, at->regionid);
+ UI_SetTheme(area ? area->spacetype : 0, at->regionid);
- if (sa && area_is_pseudo_minimized(sa)) {
+ if (area && area_is_pseudo_minimized(area)) {
UI_ThemeClearColor(TH_EDITOR_OUTLINE);
glClear(GL_COLOR_BUFFER_BIT);
return;
}
/* optional header info instead? */
else if (region->headerstr) {
- region_draw_status_text(sa, region);
+ region_draw_status_text(area, region);
}
else if (at->draw) {
at->draw(C, region);
@@ -540,7 +544,7 @@ void ED_region_do_draw(bContext *C, ARegion *region)
ED_region_draw_cb_draw(C, region, REGION_DRAW_POST_PIXEL);
- region_draw_azones(sa, region);
+ region_draw_azones(area, region);
/* for debugging unneeded area redraws and partial redraw */
if (G.debug_value == 888) {
@@ -562,11 +566,11 @@ void ED_region_do_draw(bContext *C, ARegion *region)
UI_blocklist_free_inactive(C, &region->uiblocks);
- if (sa) {
+ if (area) {
const bScreen *screen = WM_window_get_active_screen(win);
/* Only region emboss for top-bar */
- if ((screen->state != SCREENFULL) && ED_area_is_global(sa)) {
+ if ((screen->state != SCREENFULL) && ED_area_is_global(area)) {
region_draw_emboss(region, &region->winrct, (REGION_EMBOSS_LEFT | REGION_EMBOSS_RIGHT));
}
else if ((region->regiontype == RGN_TYPE_WINDOW) && (region->alignment == RGN_ALIGN_QSPLIT)) {
@@ -604,7 +608,7 @@ void ED_region_do_draw(bContext *C, ARegion *region)
*/
if (ELEM(
region->regiontype, RGN_TYPE_WINDOW, RGN_TYPE_CHANNELS, RGN_TYPE_UI, RGN_TYPE_TOOLS)) {
- SpaceLink *sl = sa->spacedata.first;
+ SpaceLink *sl = area->spacedata.first;
PointerRNA ptr;
RNA_pointer_create(&screen->id, &RNA_Space, sl, &ptr);
@@ -618,7 +622,7 @@ void ED_region_do_draw(bContext *C, ARegion *region)
WM_msg_subscribe_rna(mbus, &ptr, NULL, &msg_sub_value_region_tag_redraw, __func__);
}
- ED_region_message_subscribe(C, workspace, scene, screen, sa, region, mbus);
+ ED_region_message_subscribe(C, workspace, scene, screen, area, region, mbus);
}
}
@@ -705,34 +709,34 @@ void ED_region_tag_redraw_partial(ARegion *region, const rcti *rct, bool rebuild
}
}
-void ED_area_tag_redraw(ScrArea *sa)
+void ED_area_tag_redraw(ScrArea *area)
{
ARegion *region;
- if (sa) {
- for (region = sa->regionbase.first; region; region = region->next) {
+ if (area) {
+ for (region = area->regionbase.first; region; region = region->next) {
ED_region_tag_redraw(region);
}
}
}
-void ED_area_tag_redraw_no_rebuild(ScrArea *sa)
+void ED_area_tag_redraw_no_rebuild(ScrArea *area)
{
ARegion *region;
- if (sa) {
- for (region = sa->regionbase.first; region; region = region->next) {
+ if (area) {
+ for (region = area->regionbase.first; region; region = region->next) {
ED_region_tag_redraw_no_rebuild(region);
}
}
}
-void ED_area_tag_redraw_regiontype(ScrArea *sa, int regiontype)
+void ED_area_tag_redraw_regiontype(ScrArea *area, int regiontype)
{
ARegion *region;
- if (sa) {
- for (region = sa->regionbase.first; region; region = region->next) {
+ if (area) {
+ for (region = area->regionbase.first; region; region = region->next) {
if (region->regiontype == regiontype) {
ED_region_tag_redraw(region);
}
@@ -740,26 +744,26 @@ void ED_area_tag_redraw_regiontype(ScrArea *sa, int regiontype)
}
}
-void ED_area_tag_refresh(ScrArea *sa)
+void ED_area_tag_refresh(ScrArea *area)
{
- if (sa) {
- sa->do_refresh = true;
+ if (area) {
+ area->do_refresh = true;
}
}
/* *************************************************************** */
/* use NULL to disable it */
-void ED_area_status_text(ScrArea *sa, const char *str)
+void ED_area_status_text(ScrArea *area, const char *str)
{
ARegion *region;
/* happens when running transform operators in background mode */
- if (sa == NULL) {
+ if (area == NULL) {
return;
}
- for (region = sa->regionbase.first; region; region = region->next) {
+ for (region = area->regionbase.first; region; region = region->next) {
if (region->regiontype == RGN_TYPE_HEADER) {
if (str) {
if (region->headerstr == NULL) {
@@ -799,9 +803,9 @@ void ED_workspace_status_text(bContext *C, const char *str)
}
/* Redraw status bar. */
- for (ScrArea *sa = win->global_areas.areabase.first; sa; sa = sa->next) {
- if (sa->spacetype == SPACE_STATUSBAR) {
- ED_area_tag_redraw(sa);
+ LISTBASE_FOREACH (ScrArea *, area, &win->global_areas.areabase) {
+ if (area->spacetype == SPACE_STATUSBAR) {
+ ED_area_tag_redraw(area);
break;
}
}
@@ -809,12 +813,12 @@ void ED_workspace_status_text(bContext *C, const char *str)
/* ************************************************************ */
-static void area_azone_initialize(wmWindow *win, const bScreen *screen, ScrArea *sa)
+static void area_azone_initialize(wmWindow *win, const bScreen *screen, ScrArea *area)
{
AZone *az;
/* reinitialize entirely, regions and fullscreen add azones too */
- BLI_freelistN(&sa->actionzones);
+ BLI_freelistN(&area->actionzones);
if (screen->state != SCREENNORMAL) {
return;
@@ -824,7 +828,7 @@ static void area_azone_initialize(wmWindow *win, const bScreen *screen, ScrArea
return;
}
- if (ED_area_is_global(sa)) {
+ if (ED_area_is_global(area)) {
return;
}
@@ -834,25 +838,25 @@ static void area_azone_initialize(wmWindow *win, const bScreen *screen, ScrArea
const float coords[4][4] = {
/* Bottom-left. */
- {sa->totrct.xmin - U.pixelsize,
- sa->totrct.ymin - U.pixelsize,
- sa->totrct.xmin + AZONESPOTW,
- sa->totrct.ymin + AZONESPOTH},
+ {area->totrct.xmin - U.pixelsize,
+ area->totrct.ymin - U.pixelsize,
+ area->totrct.xmin + AZONESPOTW,
+ area->totrct.ymin + AZONESPOTH},
/* Bottom-right. */
- {sa->totrct.xmax - AZONESPOTW,
- sa->totrct.ymin - U.pixelsize,
- sa->totrct.xmax + U.pixelsize,
- sa->totrct.ymin + AZONESPOTH},
+ {area->totrct.xmax - AZONESPOTW,
+ area->totrct.ymin - U.pixelsize,
+ area->totrct.xmax + U.pixelsize,
+ area->totrct.ymin + AZONESPOTH},
/* Top-left. */
- {sa->totrct.xmin - U.pixelsize,
- sa->totrct.ymax - AZONESPOTH,
- sa->totrct.xmin + AZONESPOTW,
- sa->totrct.ymax + U.pixelsize},
+ {area->totrct.xmin - U.pixelsize,
+ area->totrct.ymax - AZONESPOTH,
+ area->totrct.xmin + AZONESPOTW,
+ area->totrct.ymax + U.pixelsize},
/* Top-right. */
- {sa->totrct.xmax - AZONESPOTW,
- sa->totrct.ymax - AZONESPOTH,
- sa->totrct.xmax + U.pixelsize,
- sa->totrct.ymax + U.pixelsize},
+ {area->totrct.xmax - AZONESPOTW,
+ area->totrct.ymax - AZONESPOTH,
+ area->totrct.xmax + U.pixelsize,
+ area->totrct.ymax + U.pixelsize},
};
for (int i = 0; i < 4; i++) {
@@ -869,7 +873,7 @@ static void area_azone_initialize(wmWindow *win, const bScreen *screen, ScrArea
/* set area action zones */
az = (AZone *)MEM_callocN(sizeof(AZone), "actionzone");
- BLI_addtail(&(sa->actionzones), az);
+ BLI_addtail(&(area->actionzones), az);
az->type = AZONE_AREA;
az->x1 = coords[i][0];
az->y1 = coords[i][1];
@@ -879,16 +883,16 @@ static void area_azone_initialize(wmWindow *win, const bScreen *screen, ScrArea
}
}
-static void fullscreen_azone_initialize(ScrArea *sa, ARegion *region)
+static void fullscreen_azone_initialize(ScrArea *area, ARegion *region)
{
AZone *az;
- if (ED_area_is_global(sa) || (region->regiontype != RGN_TYPE_WINDOW)) {
+ if (ED_area_is_global(area) || (region->regiontype != RGN_TYPE_WINDOW)) {
return;
}
az = (AZone *)MEM_callocN(sizeof(AZone), "fullscreen action zone");
- BLI_addtail(&(sa->actionzones), az);
+ BLI_addtail(&(area->actionzones), az);
az->type = AZONE_FULLSCREEN;
az->region = region;
az->alpha = 0.0f;
@@ -942,7 +946,7 @@ static void region_azone_edge(AZone *az, ARegion *region)
}
/* region already made zero sized, in shape of edge */
-static void region_azone_tab_plus(ScrArea *sa, AZone *az, ARegion *region)
+static void region_azone_tab_plus(ScrArea *area, AZone *az, ARegion *region)
{
AZone *azt;
int tot = 0, add;
@@ -952,7 +956,7 @@ static void region_azone_tab_plus(ScrArea *sa, AZone *az, ARegion *region)
const float tab_size_x = 0.7f * U.widget_unit;
const float tab_size_y = 0.4f * U.widget_unit;
- for (azt = sa->actionzones.first; azt; azt = azt->next) {
+ for (azt = area->actionzones.first; azt; azt = azt->next) {
if (azt->edge == az->edge) {
tot++;
}
@@ -960,7 +964,7 @@ static void region_azone_tab_plus(ScrArea *sa, AZone *az, ARegion *region)
switch (az->edge) {
case AE_TOP_TO_BOTTOMRIGHT:
- add = (region->winrct.ymax == sa->totrct.ymin) ? 1 : 0;
+ add = (region->winrct.ymax == area->totrct.ymin) ? 1 : 0;
az->x1 = region->winrct.xmax - ((edge_offset + 1.0f) * tab_size_x);
az->y1 = region->winrct.ymax - add;
az->x2 = region->winrct.xmax - (edge_offset * tab_size_x);
@@ -1003,7 +1007,7 @@ static bool region_azone_edge_poll(const ARegion *region, const bool is_fullscre
return true;
}
-static void region_azone_edge_initialize(ScrArea *sa,
+static void region_azone_edge_initialize(ScrArea *area,
ARegion *region,
AZEdge edge,
const bool is_fullscreen)
@@ -1016,27 +1020,27 @@ static void region_azone_edge_initialize(ScrArea *sa,
}
az = (AZone *)MEM_callocN(sizeof(AZone), "actionzone");
- BLI_addtail(&(sa->actionzones), az);
+ BLI_addtail(&(area->actionzones), az);
az->type = AZONE_REGION;
az->region = region;
az->edge = edge;
if (is_hidden) {
- region_azone_tab_plus(sa, az, region);
+ region_azone_tab_plus(area, az, region);
}
else {
region_azone_edge(az, region);
}
}
-static void region_azone_scrollbar_initialize(ScrArea *sa,
+static void region_azone_scrollbar_initialize(ScrArea *area,
ARegion *region,
AZScrollDirection direction)
{
rcti scroller_vert = (direction == AZ_SCROLL_VERT) ? region->v2d.vert : region->v2d.hor;
AZone *az = MEM_callocN(sizeof(*az), __func__);
- BLI_addtail(&sa->actionzones, az);
+ BLI_addtail(&area->actionzones, az);
az->type = AZONE_REGION_SCROLL;
az->region = region;
az->direction = direction;
@@ -1057,21 +1061,21 @@ static void region_azone_scrollbar_initialize(ScrArea *sa,
BLI_rcti_init(&az->rect, az->x1, az->x2, az->y1, az->y2);
}
-static void region_azones_scrollbars_initialize(ScrArea *sa, ARegion *region)
+static void region_azones_scrollbars_initialize(ScrArea *area, ARegion *region)
{
const View2D *v2d = &region->v2d;
if ((v2d->scroll & V2D_SCROLL_VERTICAL) && ((v2d->scroll & V2D_SCROLL_VERTICAL_HANDLES) == 0)) {
- region_azone_scrollbar_initialize(sa, region, AZ_SCROLL_VERT);
+ region_azone_scrollbar_initialize(area, region, AZ_SCROLL_VERT);
}
if ((v2d->scroll & V2D_SCROLL_HORIZONTAL) &&
((v2d->scroll & V2D_SCROLL_HORIZONTAL_HANDLES) == 0)) {
- region_azone_scrollbar_initialize(sa, region, AZ_SCROLL_HOR);
+ region_azone_scrollbar_initialize(area, region, AZ_SCROLL_HOR);
}
}
/* *************************************************************** */
-static void region_azones_add_edge(ScrArea *sa,
+static void region_azones_add_edge(ScrArea *area,
ARegion *region,
const int alignment,
const bool is_fullscreen)
@@ -1079,20 +1083,20 @@ static void region_azones_add_edge(ScrArea *sa,
/* edge code (t b l r) is along which area edge azone will be drawn */
if (alignment == RGN_ALIGN_TOP) {
- region_azone_edge_initialize(sa, region, AE_BOTTOM_TO_TOPLEFT, is_fullscreen);
+ region_azone_edge_initialize(area, region, AE_BOTTOM_TO_TOPLEFT, is_fullscreen);
}
else if (alignment == RGN_ALIGN_BOTTOM) {
- region_azone_edge_initialize(sa, region, AE_TOP_TO_BOTTOMRIGHT, is_fullscreen);
+ region_azone_edge_initialize(area, region, AE_TOP_TO_BOTTOMRIGHT, is_fullscreen);
}
else if (alignment == RGN_ALIGN_RIGHT) {
- region_azone_edge_initialize(sa, region, AE_LEFT_TO_TOPRIGHT, is_fullscreen);
+ region_azone_edge_initialize(area, region, AE_LEFT_TO_TOPRIGHT, is_fullscreen);
}
else if (alignment == RGN_ALIGN_LEFT) {
- region_azone_edge_initialize(sa, region, AE_RIGHT_TO_TOPLEFT, is_fullscreen);
+ region_azone_edge_initialize(area, region, AE_RIGHT_TO_TOPLEFT, is_fullscreen);
}
}
-static void region_azones_add(const bScreen *screen, ScrArea *sa, ARegion *region)
+static void region_azones_add(const bScreen *screen, ScrArea *area, ARegion *region)
{
const bool is_fullscreen = screen->state == SCREENFULL;
@@ -1102,20 +1106,20 @@ static void region_azones_add(const bScreen *screen, ScrArea *sa, ARegion *regio
return;
}
- region_azones_add_edge(sa, region, RGN_ALIGN_ENUM_FROM_MASK(region->alignment), is_fullscreen);
+ region_azones_add_edge(area, region, RGN_ALIGN_ENUM_FROM_MASK(region->alignment), is_fullscreen);
/* For a split region also continue the azone edge from the next region if this region is aligned
* with the next */
if ((region->alignment & RGN_SPLIT_PREV) && region->prev) {
region_azones_add_edge(
- sa, region, RGN_ALIGN_ENUM_FROM_MASK(region->prev->alignment), is_fullscreen);
+ area, region, RGN_ALIGN_ENUM_FROM_MASK(region->prev->alignment), is_fullscreen);
}
if (is_fullscreen) {
- fullscreen_azone_initialize(sa, region);
+ fullscreen_azone_initialize(area, region);
}
- region_azones_scrollbars_initialize(sa, region);
+ region_azones_scrollbars_initialize(area, region);
}
/* dir is direction to check, not the splitting edge direction! */
@@ -1133,7 +1137,7 @@ static int rct_fits(const rcti *rect, char dir, int size)
/* region should be overlapping */
/* function checks if some overlapping region was defined before - on same place */
-static void region_overlap_fix(ScrArea *sa, ARegion *region)
+static void region_overlap_fix(ScrArea *area, ARegion *region)
{
ARegion *ar1;
const int align = RGN_ALIGN_ENUM_FROM_MASK(region->alignment);
@@ -1168,7 +1172,7 @@ static void region_overlap_fix(ScrArea *sa, ARegion *region)
/* translate or close */
if (ar1) {
if (align1 == RGN_ALIGN_LEFT) {
- if (region->winrct.xmax + ar1->winx > sa->winx - U.widget_unit) {
+ if (region->winrct.xmax + ar1->winx > area->winx - U.widget_unit) {
region->flag |= RGN_FLAG_TOO_SMALL;
return;
}
@@ -1235,7 +1239,7 @@ bool ED_region_is_overlap(int spacetype, int regiontype)
}
static void region_rect_recursive(
- ScrArea *sa, ARegion *region, rcti *remainder, rcti *overlap_remainder, int quad)
+ ScrArea *area, ARegion *region, rcti *remainder, rcti *overlap_remainder, int quad)
{
rcti *remainder_prev = remainder;
@@ -1259,7 +1263,7 @@ static void region_rect_recursive(
int alignment = RGN_ALIGN_ENUM_FROM_MASK(region->alignment);
/* set here, assuming userpref switching forces to call this again */
- region->overlap = ED_region_is_overlap(sa->spacetype, region->regiontype);
+ region->overlap = ED_region_is_overlap(area->spacetype, region->regiontype);
/* clear state flags first */
region->flag &= ~(RGN_FLAG_TOO_SMALL | RGN_FLAG_SIZE_CLAMP_X | RGN_FLAG_SIZE_CLAMP_Y);
@@ -1300,7 +1304,7 @@ static void region_rect_recursive(
else if (region->regiontype == RGN_TYPE_FOOTER) {
prefsizey = ED_area_footersize();
}
- else if (ED_area_is_global(sa)) {
+ else if (ED_area_is_global(area)) {
prefsizey = ED_region_global_size_y();
}
else {
@@ -1501,7 +1505,7 @@ static void region_rect_recursive(
/* exception for multiple overlapping regions on same spot */
if (region->overlap && (alignment != RGN_ALIGN_FLOAT)) {
- region_overlap_fix(sa, region);
+ region_overlap_fix(area, region);
}
/* set winrect for azones */
@@ -1548,7 +1552,7 @@ static void region_rect_recursive(
BLI_assert(BLI_rcti_is_valid(&region->winrct));
- region_rect_recursive(sa, region->next, remainder, overlap_remainder, quad);
+ region_rect_recursive(area, region->next, remainder, overlap_remainder, quad);
/* Tag for redraw if size changes. */
if (region->winx != prev_winx || region->winy != prev_winy) {
@@ -1559,42 +1563,42 @@ static void region_rect_recursive(
memset(&region->runtime.visible_rect, 0, sizeof(region->runtime.visible_rect));
}
-static void area_calc_totrct(ScrArea *sa, const rcti *window_rect)
+static void area_calc_totrct(ScrArea *area, const rcti *window_rect)
{
short px = (short)U.pixelsize;
- sa->totrct.xmin = sa->v1->vec.x;
- sa->totrct.xmax = sa->v4->vec.x;
- sa->totrct.ymin = sa->v1->vec.y;
- sa->totrct.ymax = sa->v2->vec.y;
+ area->totrct.xmin = area->v1->vec.x;
+ area->totrct.xmax = area->v4->vec.x;
+ area->totrct.ymin = area->v1->vec.y;
+ area->totrct.ymax = area->v2->vec.y;
/* scale down totrct by 1 pixel on all sides not matching window borders */
- if (sa->totrct.xmin > window_rect->xmin) {
- sa->totrct.xmin += px;
+ if (area->totrct.xmin > window_rect->xmin) {
+ area->totrct.xmin += px;
}
- if (sa->totrct.xmax < (window_rect->xmax - 1)) {
- sa->totrct.xmax -= px;
+ if (area->totrct.xmax < (window_rect->xmax - 1)) {
+ area->totrct.xmax -= px;
}
- if (sa->totrct.ymin > window_rect->ymin) {
- sa->totrct.ymin += px;
+ if (area->totrct.ymin > window_rect->ymin) {
+ area->totrct.ymin += px;
}
- if (sa->totrct.ymax < (window_rect->ymax - 1)) {
- sa->totrct.ymax -= px;
+ if (area->totrct.ymax < (window_rect->ymax - 1)) {
+ area->totrct.ymax -= px;
}
/* Although the following asserts are correct they lead to a very unstable Blender.
* And the asserts would fail even in 2.7x
* (they were added in 2.8x as part of the top-bar commit).
* For more details see T54864. */
#if 0
- BLI_assert(sa->totrct.xmin >= 0);
- BLI_assert(sa->totrct.xmax >= 0);
- BLI_assert(sa->totrct.ymin >= 0);
- BLI_assert(sa->totrct.ymax >= 0);
+ BLI_assert(area->totrct.xmin >= 0);
+ BLI_assert(area->totrct.xmax >= 0);
+ BLI_assert(area->totrct.ymin >= 0);
+ BLI_assert(area->totrct.ymax >= 0);
#endif
/* for speedup */
- sa->winx = BLI_rcti_size_x(&sa->totrct) + 1;
- sa->winy = BLI_rcti_size_y(&sa->totrct) + 1;
+ area->winx = BLI_rcti_size_x(&area->totrct) + 1;
+ area->winy = BLI_rcti_size_y(&area->totrct) + 1;
}
/* used for area initialize below */
@@ -1617,12 +1621,12 @@ static bool event_in_markers_region(const ARegion *region, const wmEvent *event)
}
/**
- * \param region: Region, may be NULL when adding handlers for \a sa.
+ * \param region: Region, may be NULL when adding handlers for \a area.
*/
static void ed_default_handlers(
- wmWindowManager *wm, ScrArea *sa, ARegion *region, ListBase *handlers, int flag)
+ wmWindowManager *wm, ScrArea *area, ARegion *region, ListBase *handlers, int flag)
{
- BLI_assert(region ? (&region->handlers == handlers) : (&sa->handlers == handlers));
+ BLI_assert(region ? (&region->handlers == handlers) : (&area->handlers == handlers));
/* note, add-handler checks if it already exists */
@@ -1641,7 +1645,7 @@ static void ed_default_handlers(
BLI_assert(&region->handlers == handlers);
if (region->gizmo_map == NULL) {
region->gizmo_map = WM_gizmomap_new_from_type(
- &(const struct wmGizmoMapType_Params){sa->spacetype, region->type->regionid});
+ &(const struct wmGizmoMapType_Params){area->spacetype, region->type->regionid});
}
WM_gizmomap_add_handlers(region, region->gizmo_map);
}
@@ -1668,9 +1672,9 @@ static void ed_default_handlers(
}
if (flag & ED_KEYMAP_TOOL) {
WM_event_add_keymap_handler_dynamic(
- &region->handlers, WM_event_get_keymap_from_toolsystem_fallback, sa);
+ &region->handlers, WM_event_get_keymap_from_toolsystem_fallback, area);
WM_event_add_keymap_handler_dynamic(
- &region->handlers, WM_event_get_keymap_from_toolsystem, sa);
+ &region->handlers, WM_event_get_keymap_from_toolsystem, area);
}
if (flag & ED_KEYMAP_FRAMES) {
/* frame changing/jumping (for all spaces) */
@@ -1826,7 +1830,7 @@ void ED_area_update_region_sizes(wmWindowManager *wm, wmWindow *win, ScrArea *ar
/* Dynamically sized regions may have changed region sizes, so we have to force azone update. */
area_azone_initialize(win, screen, area);
- for (ARegion *region = area->regionbase.first; region; region = region->next) {
+ LISTBASE_FOREACH (ARegion *, region, &area->regionbase) {
region_subwindow(region);
/* region size may have changed, init does necessary adjustments */
@@ -1843,7 +1847,7 @@ void ED_area_update_region_sizes(wmWindowManager *wm, wmWindow *win, ScrArea *ar
}
/* called in screen_refresh, or screens_init, also area size changes */
-void ED_area_initialize(wmWindowManager *wm, wmWindow *win, ScrArea *sa)
+void ED_area_initialize(wmWindowManager *wm, wmWindow *win, ScrArea *area)
{
WorkSpace *workspace = WM_window_get_active_workspace(win);
const bScreen *screen = BKE_workspace_active_screen_get(win->workspace_hook);
@@ -1852,49 +1856,49 @@ void ED_area_initialize(wmWindowManager *wm, wmWindow *win, ScrArea *sa)
rcti rect, overlap_rect;
rcti window_rect;
- if (ED_area_is_global(sa) && (sa->global->flag & GLOBAL_AREA_IS_HIDDEN)) {
+ if (ED_area_is_global(area) && (area->global->flag & GLOBAL_AREA_IS_HIDDEN)) {
return;
}
WM_window_rect_calc(win, &window_rect);
/* set typedefinitions */
- sa->type = BKE_spacetype_from_id(sa->spacetype);
+ area->type = BKE_spacetype_from_id(area->spacetype);
- if (sa->type == NULL) {
- sa->spacetype = SPACE_VIEW3D;
- sa->type = BKE_spacetype_from_id(sa->spacetype);
+ if (area->type == NULL) {
+ area->spacetype = SPACE_VIEW3D;
+ area->type = BKE_spacetype_from_id(area->spacetype);
}
- for (region = sa->regionbase.first; region; region = region->next) {
- region->type = BKE_regiontype_from_id_or_first(sa->type, region->regiontype);
+ for (region = area->regionbase.first; region; region = region->next) {
+ region->type = BKE_regiontype_from_id_or_first(area->type, region->regiontype);
}
/* area sizes */
- area_calc_totrct(sa, &window_rect);
+ area_calc_totrct(area, &window_rect);
/* region rect sizes */
- rect = sa->totrct;
+ rect = area->totrct;
overlap_rect = rect;
- region_rect_recursive(sa, sa->regionbase.first, &rect, &overlap_rect, 0);
- sa->flag &= ~AREA_FLAG_REGION_SIZE_UPDATE;
+ region_rect_recursive(area, area->regionbase.first, &rect, &overlap_rect, 0);
+ area->flag &= ~AREA_FLAG_REGION_SIZE_UPDATE;
/* default area handlers */
- ed_default_handlers(wm, sa, NULL, &sa->handlers, sa->type->keymapflag);
+ ed_default_handlers(wm, area, NULL, &area->handlers, area->type->keymapflag);
/* checks spacedata, adds own handlers */
- if (sa->type->init) {
- sa->type->init(wm, sa);
+ if (area->type->init) {
+ area->type->init(wm, area);
}
/* clear all azones, add the area triangle widgets */
- area_azone_initialize(win, screen, sa);
+ area_azone_initialize(win, screen, area);
/* region windows, default and own handlers */
- for (region = sa->regionbase.first; region; region = region->next) {
+ for (region = area->regionbase.first; region; region = region->next) {
region_subwindow(region);
if (region->visible) {
/* default region handlers */
- ed_default_handlers(wm, sa, region, &region->handlers, region->type->keymapflag);
+ ed_default_handlers(wm, area, region, &region->handlers, region->type->keymapflag);
/* own handlers */
if (region->type->init) {
region->type->init(wm, region);
@@ -1906,18 +1910,18 @@ void ED_area_initialize(wmWindowManager *wm, wmWindow *win, ScrArea *sa)
}
/* Some AZones use View2D data which is only updated in region init, so call that first! */
- region_azones_add(screen, sa, region);
+ region_azones_add(screen, area, region);
}
/* Avoid re-initializing tools while resizing the window. */
if ((G.moving & G_TRANSFORM_WM) == 0) {
- if ((1 << sa->spacetype) & WM_TOOLSYSTEM_SPACE_MASK) {
- WM_toolsystem_refresh_screen_area(workspace, view_layer, sa);
- sa->flag |= AREA_FLAG_ACTIVE_TOOL_UPDATE;
+ if ((1 << area->spacetype) & WM_TOOLSYSTEM_SPACE_MASK) {
+ WM_toolsystem_refresh_screen_area(workspace, view_layer, area);
+ area->flag |= AREA_FLAG_ACTIVE_TOOL_UPDATE;
}
else {
- sa->runtime.tool = NULL;
- sa->runtime.is_tool_set = true;
+ area->runtime.tool = NULL;
+ area->runtime.is_tool_set = true;
}
}
}
@@ -1950,19 +1954,19 @@ void ED_region_floating_initialize(ARegion *region)
region_update_rect(region);
}
-void ED_region_cursor_set(wmWindow *win, ScrArea *sa, ARegion *region)
+void ED_region_cursor_set(wmWindow *win, ScrArea *area, ARegion *region)
{
if (region != NULL) {
if ((region->gizmo_map != NULL) && WM_gizmomap_cursor_set(region->gizmo_map, win)) {
return;
}
- if (sa && region->type && region->type->cursor) {
- region->type->cursor(win, sa, region);
+ if (area && region->type && region->type->cursor) {
+ region->type->cursor(win, area, region);
return;
}
}
- if (WM_cursor_set_from_tool(win, sa, region)) {
+ if (WM_cursor_set_from_tool(win, area, region)) {
return;
}
@@ -1970,29 +1974,29 @@ void ED_region_cursor_set(wmWindow *win, ScrArea *sa, ARegion *region)
}
/* for use after changing visibility of regions */
-void ED_region_visibility_change_update(bContext *C, ScrArea *sa, ARegion *region)
+void ED_region_visibility_change_update(bContext *C, ScrArea *area, ARegion *region)
{
if (region->flag & RGN_FLAG_HIDDEN) {
WM_event_remove_handlers(C, &region->handlers);
}
- ED_area_initialize(CTX_wm_manager(C), CTX_wm_window(C), sa);
- ED_area_tag_redraw(sa);
+ ED_area_initialize(CTX_wm_manager(C), CTX_wm_window(C), area);
+ ED_area_tag_redraw(area);
}
/* for quick toggle, can skip fades */
void region_toggle_hidden(bContext *C, ARegion *region, const bool do_fade)
{
- ScrArea *sa = CTX_wm_area(C);
+ ScrArea *area = CTX_wm_area(C);
region->flag ^= RGN_FLAG_HIDDEN;
if (do_fade && region->overlap) {
/* starts a timer, and in end calls the stuff below itself (region_sblend_invoke()) */
- ED_region_visibility_change_update_animated(C, sa, region);
+ ED_region_visibility_change_update_animated(C, area, region);
}
else {
- ED_region_visibility_change_update(C, sa, region);
+ ED_region_visibility_change_update(C, area, region);
}
}
@@ -2005,48 +2009,48 @@ void ED_region_toggle_hidden(bContext *C, ARegion *region)
/**
* we swap spaces for fullscreen to keep all allocated data area vertices were set
*/
-void ED_area_data_copy(ScrArea *sa_dst, ScrArea *sa_src, const bool do_free)
+void ED_area_data_copy(ScrArea *area_dst, ScrArea *area_src, const bool do_free)
{
SpaceType *st;
ARegion *region;
- const char spacetype = sa_dst->spacetype;
+ const char spacetype = area_dst->spacetype;
const short flag_copy = HEADER_NO_PULLDOWN;
- sa_dst->spacetype = sa_src->spacetype;
- sa_dst->type = sa_src->type;
+ area_dst->spacetype = area_src->spacetype;
+ area_dst->type = area_src->type;
- sa_dst->flag = (sa_dst->flag & ~flag_copy) | (sa_src->flag & flag_copy);
+ area_dst->flag = (area_dst->flag & ~flag_copy) | (area_src->flag & flag_copy);
/* area */
if (do_free) {
- BKE_spacedata_freelist(&sa_dst->spacedata);
+ BKE_spacedata_freelist(&area_dst->spacedata);
}
- BKE_spacedata_copylist(&sa_dst->spacedata, &sa_src->spacedata);
+ BKE_spacedata_copylist(&area_dst->spacedata, &area_src->spacedata);
/* Note; SPACE_EMPTY is possible on new screens */
/* regions */
if (do_free) {
st = BKE_spacetype_from_id(spacetype);
- for (region = sa_dst->regionbase.first; region; region = region->next) {
+ for (region = area_dst->regionbase.first; region; region = region->next) {
BKE_area_region_free(st, region);
}
- BLI_freelistN(&sa_dst->regionbase);
+ BLI_freelistN(&area_dst->regionbase);
}
- st = BKE_spacetype_from_id(sa_src->spacetype);
- for (region = sa_src->regionbase.first; region; region = region->next) {
+ st = BKE_spacetype_from_id(area_src->spacetype);
+ for (region = area_src->regionbase.first; region; region = region->next) {
ARegion *newar = BKE_area_region_copy(st, region);
- BLI_addtail(&sa_dst->regionbase, newar);
+ BLI_addtail(&area_dst->regionbase, newar);
}
}
-void ED_area_data_swap(ScrArea *sa_dst, ScrArea *sa_src)
+void ED_area_data_swap(ScrArea *area_dst, ScrArea *area_src)
{
- SWAP(char, sa_dst->spacetype, sa_src->spacetype);
- SWAP(SpaceType *, sa_dst->type, sa_src->type);
+ SWAP(char, area_dst->spacetype, area_src->spacetype);
+ SWAP(SpaceType *, area_dst->type, area_src->type);
- SWAP(ListBase, sa_dst->spacedata, sa_src->spacedata);
- SWAP(ListBase, sa_dst->regionbase, sa_src->regionbase);
+ SWAP(ListBase, area_dst->spacedata, area_src->spacedata);
+ SWAP(ListBase, area_dst->regionbase, area_src->regionbase);
}
/* *********** Space switching code *********** */
@@ -2078,18 +2082,18 @@ void ED_area_swapspace(bContext *C, ScrArea *sa1, ScrArea *sa2)
}
/**
- * \param skip_ar_exit: Skip calling area exit callback. Set for opening temp spaces.
+ * \param skip_region_exit: Skip calling area exit callback. Set for opening temp spaces.
*/
-void ED_area_newspace(bContext *C, ScrArea *sa, int type, const bool skip_ar_exit)
+void ED_area_newspace(bContext *C, ScrArea *area, int type, const bool skip_region_exit)
{
wmWindow *win = CTX_wm_window(C);
- if (sa->spacetype != type) {
+ if (area->spacetype != type) {
SpaceType *st;
- SpaceLink *slold = sa->spacedata.first;
+ SpaceLink *slold = area->spacedata.first;
SpaceLink *sl;
- /* store sa->type->exit callback */
- void *sa_exit = sa->type ? sa->type->exit : NULL;
+ /* store area->type->exit callback */
+ void *area_exit = area->type ? area->type->exit : NULL;
/* When the user switches between space-types from the type-selector,
* changing the header-type is jarring (especially when using Ctrl-MouseWheel).
*
@@ -2100,34 +2104,34 @@ void ED_area_newspace(bContext *C, ScrArea *sa, int type, const bool skip_ar_exi
* the space type defaults to in this case instead
* (needed for preferences to have space-type on bottom).
*/
- int header_alignment = ED_area_header_alignment_or_fallback(sa, -1);
+ int header_alignment = ED_area_header_alignment_or_fallback(area, -1);
const bool sync_header_alignment = ((header_alignment != -1) &&
((slold->link_flag & SPACE_FLAG_TYPE_TEMPORARY) == 0));
/* in some cases (opening temp space) we don't want to
* call area exit callback, so we temporarily unset it */
- if (skip_ar_exit && sa->type) {
- sa->type->exit = NULL;
+ if (skip_region_exit && area->type) {
+ area->type->exit = NULL;
}
- ED_area_exit(C, sa);
+ ED_area_exit(C, area);
/* restore old area exit callback */
- if (skip_ar_exit && sa->type) {
- sa->type->exit = sa_exit;
+ if (skip_region_exit && area->type) {
+ area->type->exit = area_exit;
}
st = BKE_spacetype_from_id(type);
- sa->spacetype = type;
- sa->type = st;
+ area->spacetype = type;
+ area->type = st;
/* If st->new may be called, don't use context until then. The
- * sa->type->context() callback has changed but data may be invalid
+ * area->type->context() callback has changed but data may be invalid
* (e.g. with properties editor) until space-data is properly created */
/* check previously stored space */
- for (sl = sa->spacedata.first; sl; sl = sl->next) {
+ for (sl = area->spacedata.first; sl; sl = sl->next) {
if (sl->spacetype == type) {
break;
}
@@ -2136,7 +2140,7 @@ void ED_area_newspace(bContext *C, ScrArea *sa, int type, const bool skip_ar_exi
/* old spacedata... happened during work on 2.50, remove */
if (sl && BLI_listbase_is_empty(&sl->regionbase)) {
st->free(sl);
- BLI_freelinkN(&sa->spacedata, sl);
+ BLI_freelinkN(&area->spacedata, sl);
if (slold == sl) {
slold = NULL;
}
@@ -2145,8 +2149,8 @@ void ED_area_newspace(bContext *C, ScrArea *sa, int type, const bool skip_ar_exi
if (sl) {
/* swap regions */
- slold->regionbase = sa->regionbase;
- sa->regionbase = sl->regionbase;
+ slold->regionbase = area->regionbase;
+ area->regionbase = sl->regionbase;
BLI_listbase_clear(&sl->regionbase);
/* SPACE_FLAG_TYPE_WAS_ACTIVE is only used to go back to a previously active space that is
* overlapped by temporary ones. It's now properly activated, so the flag should be cleared
@@ -2154,22 +2158,22 @@ void ED_area_newspace(bContext *C, ScrArea *sa, int type, const bool skip_ar_exi
sl->link_flag &= ~SPACE_FLAG_TYPE_WAS_ACTIVE;
/* put in front of list */
- BLI_remlink(&sa->spacedata, sl);
- BLI_addhead(&sa->spacedata, sl);
+ BLI_remlink(&area->spacedata, sl);
+ BLI_addhead(&area->spacedata, sl);
}
else {
/* new space */
if (st) {
/* Don't get scene from context here which may depend on space-data. */
Scene *scene = WM_window_get_active_scene(win);
- sl = st->new (sa, scene);
- BLI_addhead(&sa->spacedata, sl);
+ sl = st->new (area, scene);
+ BLI_addhead(&area->spacedata, sl);
/* swap regions */
if (slold) {
- slold->regionbase = sa->regionbase;
+ slold->regionbase = area->regionbase;
}
- sa->regionbase = sl->regionbase;
+ area->regionbase = sl->regionbase;
BLI_listbase_clear(&sl->regionbase);
}
}
@@ -2178,7 +2182,7 @@ void ED_area_newspace(bContext *C, ScrArea *sa, int type, const bool skip_ar_exi
if (sync_header_alignment) {
/* Spaces with footer. */
if (st->spaceid == SPACE_TEXT) {
- for (ARegion *region = sa->regionbase.first; region; region = region->next) {
+ LISTBASE_FOREACH (ARegion *, region, &area->regionbase) {
if (ELEM(region->regiontype, RGN_TYPE_HEADER, RGN_TYPE_TOOL_HEADER)) {
region->alignment = header_alignment;
}
@@ -2191,7 +2195,7 @@ void ED_area_newspace(bContext *C, ScrArea *sa, int type, const bool skip_ar_exi
}
}
else {
- for (ARegion *region = sa->regionbase.first; region; region = region->next) {
+ LISTBASE_FOREACH (ARegion *, region, &area->regionbase) {
if (ELEM(region->regiontype, RGN_TYPE_HEADER, RGN_TYPE_TOOL_HEADER)) {
region->alignment = header_alignment;
break;
@@ -2200,24 +2204,24 @@ void ED_area_newspace(bContext *C, ScrArea *sa, int type, const bool skip_ar_exi
}
}
- ED_area_initialize(CTX_wm_manager(C), win, sa);
+ ED_area_initialize(CTX_wm_manager(C), win, area);
/* tell WM to refresh, cursor types etc */
WM_event_add_mousemove(win);
/* send space change notifier */
- WM_event_add_notifier(C, NC_SPACE | ND_SPACE_CHANGED, sa);
+ WM_event_add_notifier(C, NC_SPACE | ND_SPACE_CHANGED, area);
- ED_area_tag_refresh(sa);
+ ED_area_tag_refresh(area);
}
/* also redraw when re-used */
- ED_area_tag_redraw(sa);
+ ED_area_tag_redraw(area);
}
-static SpaceLink *area_get_prevspace(ScrArea *sa)
+static SpaceLink *area_get_prevspace(ScrArea *area)
{
- SpaceLink *sl = sa->spacedata.first;
+ SpaceLink *sl = area->spacedata.first;
/* First toggle to the next temporary space in the list. */
for (SpaceLink *sl_iter = sl->next; sl_iter; sl_iter = sl_iter->next) {
@@ -2237,13 +2241,13 @@ static SpaceLink *area_get_prevspace(ScrArea *sa)
return sl->next;
}
-void ED_area_prevspace(bContext *C, ScrArea *sa)
+void ED_area_prevspace(bContext *C, ScrArea *area)
{
- SpaceLink *sl = sa->spacedata.first;
- SpaceLink *prevspace = sl ? area_get_prevspace(sa) : NULL;
+ SpaceLink *sl = area->spacedata.first;
+ SpaceLink *prevspace = sl ? area_get_prevspace(area) : NULL;
if (prevspace) {
- ED_area_newspace(C, sa, prevspace->spacetype, false);
+ ED_area_newspace(C, area, prevspace->spacetype, false);
/* We've exited the space, so it can't be considered temporary anymore. */
sl->link_flag &= ~SPACE_FLAG_TYPE_TEMPORARY;
}
@@ -2253,23 +2257,23 @@ void ED_area_prevspace(bContext *C, ScrArea *sa)
}
/* If this is a stacked fullscreen, changing to previous area exits it (meaning we're still in a
* fullscreen, but not in a stacked one). */
- sa->flag &= ~AREA_FLAG_STACKED_FULLSCREEN;
+ area->flag &= ~AREA_FLAG_STACKED_FULLSCREEN;
- ED_area_tag_redraw(sa);
+ ED_area_tag_redraw(area);
/* send space change notifier */
- WM_event_add_notifier(C, NC_SPACE | ND_SPACE_CHANGED, sa);
+ WM_event_add_notifier(C, NC_SPACE | ND_SPACE_CHANGED, area);
}
/* returns offset for next button in header */
int ED_area_header_switchbutton(const bContext *C, uiBlock *block, int yco)
{
- ScrArea *sa = CTX_wm_area(C);
- bScreen *scr = CTX_wm_screen(C);
+ ScrArea *area = CTX_wm_area(C);
+ bScreen *screen = CTX_wm_screen(C);
PointerRNA areaptr;
int xco = 0.4 * U.widget_unit;
- RNA_pointer_create(&(scr->id), &RNA_Area, sa, &areaptr);
+ RNA_pointer_create(&(screen->id), &RNA_Area, area, &areaptr);
uiDefButR(block,
UI_BTYPE_MENU,
@@ -2343,26 +2347,44 @@ BLI_INLINE bool streq_array_any(const char *s, const char *arr[])
return false;
}
+/**
+ * Builds the panel layout for the input \a panel or type \a pt.
+ *
+ * \param panel The panel to draw. Can be null, in which case a panel with the type of \a pt will
+ * be created.
+ * \param unique_panel_str A unique identifier for the name of the \a uiBlock associated with the
+ * panel. Used when the panel is an instanced panel so a unique identifier is needed to find the
+ * correct old \a uiBlock, and NULL otherwise.
+ */
static void ed_panel_draw(const bContext *C,
- ScrArea *sa,
+ ScrArea *area,
ARegion *region,
ListBase *lb,
PanelType *pt,
Panel *panel,
int w,
int em,
- bool vertical)
+ bool vertical,
+ char *unique_panel_str)
{
const uiStyle *style = UI_style_get_dpi();
- /* draw panel */
- uiBlock *block = UI_block_begin(C, region, pt->idname, UI_EMBOSS);
+ /* Draw panel. */
+
+ char block_name[BKE_ST_MAXNAME + LIST_PANEL_UNIQUE_STR_LEN];
+ strncpy(block_name, pt->idname, BKE_ST_MAXNAME);
+ if (unique_panel_str != NULL) {
+ /* Instanced panels should have already been added at this point. */
+ strncat(block_name, unique_panel_str, LIST_PANEL_UNIQUE_STR_LEN);
+ }
+ uiBlock *block = UI_block_begin(C, region, block_name, UI_EMBOSS);
bool open;
- panel = UI_panel_begin(sa, region, lb, block, pt, panel, &open);
+ panel = UI_panel_begin(area, region, lb, block, pt, panel, &open);
/* bad fixed values */
int xco, yco, h = 0;
+ int headerend = w - UI_UNIT_X;
if (pt->draw_header_preset && !(pt->flag & PNL_NO_HEADER) && (open || vertical)) {
/* for preset menu */
@@ -2378,8 +2400,6 @@ static void ed_panel_draw(const bContext *C,
pt->draw_header_preset(C, panel);
- int headerend = w - UI_UNIT_X;
-
UI_block_layout_resolve(block, &xco, &yco);
UI_block_translate(block, headerend - xco, 0);
panel->layout = NULL;
@@ -2389,9 +2409,24 @@ static void ed_panel_draw(const bContext *C,
int labelx, labely;
UI_panel_label_offset(block, &labelx, &labely);
- /* for enabled buttons */
- panel->layout = UI_block_layout(
- block, UI_LAYOUT_HORIZONTAL, UI_LAYOUT_HEADER, labelx, labely, UI_UNIT_Y, 1, 0, style);
+ /* Unusual case: Use expanding layout (buttons stretch to available width). */
+ if (pt->flag & PNL_LAYOUT_HEADER_EXPAND) {
+ uiLayout *layout = UI_block_layout(block,
+ UI_LAYOUT_VERTICAL,
+ UI_LAYOUT_PANEL,
+ labelx,
+ labely,
+ headerend - 2 * style->panelspace,
+ 1,
+ 0,
+ style);
+ panel->layout = uiLayoutRow(layout, false);
+ }
+ /* Regular case: Normal panel with fixed size buttons. */
+ else {
+ panel->layout = UI_block_layout(
+ block, UI_LAYOUT_HORIZONTAL, UI_LAYOUT_HEADER, labelx, labely, UI_UNIT_Y, 1, 0, style);
+ }
pt->draw_header(C, panel);
@@ -2442,17 +2477,26 @@ static void ed_panel_draw(const bContext *C,
/* Draw child panels. */
if (open) {
- for (LinkData *link = pt->children.first; link; link = link->next) {
+ LISTBASE_FOREACH (LinkData *, link, &pt->children) {
PanelType *child_pt = link->data;
Panel *child_panel = UI_panel_find_by_type(&panel->children, child_pt);
if (child_pt->draw && (!child_pt->poll || child_pt->poll(C, child_pt))) {
- ed_panel_draw(C, sa, region, &panel->children, child_pt, child_panel, w, em, vertical);
+ ed_panel_draw(C,
+ area,
+ region,
+ &panel->children,
+ child_pt,
+ child_panel,
+ w,
+ em,
+ vertical,
+ unique_panel_str);
}
}
}
- UI_panel_end(sa, region, block, w, h, open);
+ UI_panel_end(area, region, block, w, h, open);
}
/**
@@ -2501,7 +2545,7 @@ void ED_region_panels_layout_ex(const bContext *C,
region->runtime.category = NULL;
- ScrArea *sa = CTX_wm_area(C);
+ ScrArea *area = CTX_wm_area(C);
View2D *v2d = &region->v2d;
int x, y, w, em;
@@ -2510,13 +2554,14 @@ void ED_region_panels_layout_ex(const bContext *C,
bool use_category_tabs = (category_override == NULL) &&
((((1 << region->regiontype) & RGN_TYPE_HAS_CATEGORY_MASK) ||
(region->regiontype == RGN_TYPE_TOOLS &&
- sa->spacetype == SPACE_CLIP)));
+ area->spacetype == SPACE_CLIP)));
/* offset panels for small vertical tab area */
const char *category = NULL;
const int category_tabs_width = UI_PANEL_CATEGORY_MARGIN_WIDTH;
int margin_x = 0;
const bool region_layout_based = region->flag & RGN_FLAG_DYNAMIC_SIZE;
const bool is_context_new = (contextnr != -1) ? UI_view2d_tab_set(v2d, contextnr) : false;
+ bool update_tot_size = true;
/* before setting the view */
if (vertical) {
@@ -2534,7 +2579,6 @@ void ED_region_panels_layout_ex(const bContext *C,
v2d->scroll |= (V2D_SCROLL_BOTTOM);
v2d->scroll &= ~(V2D_SCROLL_RIGHT);
}
- const int scroll = v2d->scroll;
/* collect categories */
if (use_category_tabs) {
@@ -2569,6 +2613,7 @@ void ED_region_panels_layout_ex(const bContext *C,
}
w -= margin_x;
+ int w_box_panel = w - UI_PANEL_BOX_STYLE_MARGIN * 2.0f;
/* create panels */
UI_panels_begin(C, region);
@@ -2576,8 +2621,14 @@ void ED_region_panels_layout_ex(const bContext *C,
/* set view2d view matrix - UI_block_begin() stores it */
UI_view2d_view_ortho(v2d);
+ bool has_instanced_panel = false;
for (LinkNode *pt_link = panel_types_stack; pt_link; pt_link = pt_link->next) {
PanelType *pt = pt_link->link;
+
+ if (pt->flag & PNL_INSTANCED) {
+ has_instanced_panel = true;
+ continue;
+ }
Panel *panel = UI_panel_find_by_type(&region->panels, pt);
if (use_category_tabs && pt->category[0] && !STREQ(category, pt->category)) {
@@ -2586,7 +2637,51 @@ void ED_region_panels_layout_ex(const bContext *C,
}
}
- ed_panel_draw(C, sa, region, &region->panels, pt, panel, w, em, vertical);
+ if (panel && UI_panel_is_dragging(panel)) {
+ /* Prevent View2d.tot rectangle size changes while dragging panels. */
+ update_tot_size = false;
+ }
+
+ ed_panel_draw(C,
+ area,
+ region,
+ &region->panels,
+ pt,
+ panel,
+ (pt->flag & PNL_DRAW_BOX) ? w_box_panel : w,
+ em,
+ vertical,
+ NULL);
+ }
+
+ /* Draw "polyinstantaited" panels that don't have a 1 to 1 correspondence with their types. */
+ if (has_instanced_panel) {
+ LISTBASE_FOREACH (Panel *, panel, &region->panels) {
+ if (panel->type == NULL) {
+ continue; /* Some panels don't have a type.. */
+ }
+ if (panel->type->flag & PNL_INSTANCED) {
+ if (panel && UI_panel_is_dragging(panel)) {
+ /* Prevent View2d.tot rectangle size changes while dragging panels. */
+ update_tot_size = false;
+ }
+
+ /* Use a unique identifier for instanced panels, otherwise an old block for a different
+ * panel of the same type might be found. */
+ char unique_panel_str[8];
+ UI_list_panel_unique_str(panel, unique_panel_str);
+ ed_panel_draw(C,
+ area,
+ region,
+ &region->panels,
+ panel->type,
+ panel,
+ (panel->type->flag & PNL_DRAW_BOX) ? w_box_panel : w,
+ em,
+ vertical,
+ unique_panel_str);
+ }
+ }
}
/* align panels and return size */
@@ -2607,7 +2702,7 @@ void ED_region_panels_layout_ex(const bContext *C,
if ((region->sizex != size_dyn[0]) || (region->sizey != size_dyn[1])) {
region->sizex = size_dyn[0];
region->sizey = size_dyn[1];
- sa->flag |= AREA_FLAG_REGION_SIZE_UPDATE;
+ area->flag |= AREA_FLAG_REGION_SIZE_UPDATE;
}
y = fabsf(region->sizey * UI_DPI_FAC - 1);
}
@@ -2641,17 +2736,9 @@ void ED_region_panels_layout_ex(const bContext *C,
y = -y;
}
- /* this also changes the 'cur' */
- UI_view2d_totRect_set(v2d, x, y);
-
- if (scroll != v2d->scroll) {
- /* Note: this code scales fine, but because of rounding differences, positions of elements
- * flip +1 or -1 pixel compared to redoing the entire layout again.
- * Leaving in commented code for future tests */
-#if 0
- UI_panels_scale(region, BLI_rctf_size_x(&v2d->cur));
- break;
-#endif
+ if (update_tot_size) {
+ /* this also changes the 'cur' */
+ UI_view2d_totRect_set(v2d, x, y);
}
if (use_category_tabs) {
@@ -2801,10 +2888,10 @@ void ED_region_header_layout(const bContext *C, ARegion *region)
if (region_layout_based && (region->sizex != new_sizex)) {
/* region size is layout based and needs to be updated */
- ScrArea *sa = CTX_wm_area(C);
+ ScrArea *area = CTX_wm_area(C);
region->sizex = new_sizex;
- sa->flag |= AREA_FLAG_REGION_SIZE_UPDATE;
+ area->flag |= AREA_FLAG_REGION_SIZE_UPDATE;
}
UI_block_end(C, block);
@@ -2858,7 +2945,7 @@ int ED_area_headersize(void)
int ED_area_header_alignment_or_fallback(const ScrArea *area, int fallback)
{
- for (ARegion *region = area->regionbase.first; region; region = region->next) {
+ LISTBASE_FOREACH (ARegion *, region, &area->regionbase) {
if (region->regiontype == RGN_TYPE_HEADER) {
return region->alignment;
}
@@ -2879,7 +2966,7 @@ int ED_area_footersize(void)
int ED_area_footer_alignment_or_fallback(const ScrArea *area, int fallback)
{
- for (ARegion *region = area->regionbase.first; region; region = region->next) {
+ LISTBASE_FOREACH (ARegion *, region, &area->regionbase) {
if (region->regiontype == RGN_TYPE_FOOTER) {
return region->alignment;
}
@@ -3577,7 +3664,7 @@ void ED_region_message_subscribe(bContext *C,
struct WorkSpace *workspace,
struct Scene *scene,
struct bScreen *screen,
- struct ScrArea *sa,
+ struct ScrArea *area,
struct ARegion *region,
struct wmMsgBus *mbus)
{
@@ -3590,7 +3677,7 @@ void ED_region_message_subscribe(bContext *C,
}
if (region->type->message_subscribe != NULL) {
- region->type->message_subscribe(C, workspace, scene, screen, sa, region, mbus);
+ region->type->message_subscribe(C, workspace, scene, screen, area, region, mbus);
}
}
diff --git a/source/blender/editors/screen/area_query.c b/source/blender/editors/screen/area_query.c
index 739f1b93e07..d569e56e11b 100644
--- a/source/blender/editors/screen/area_query.c
+++ b/source/blender/editors/screen/area_query.c
@@ -73,19 +73,19 @@ bool ED_region_overlap_isect_any_xy(const ScrArea *area, const int event_xy[2])
return false;
}
-bool ED_region_panel_category_gutter_calc_rect(const ARegion *region, rcti *r_ar_gutter)
+bool ED_region_panel_category_gutter_calc_rect(const ARegion *region, rcti *r_region_gutter)
{
- *r_ar_gutter = region->winrct;
+ *r_region_gutter = region->winrct;
if (UI_panel_category_is_visible(region)) {
const int category_tabs_width = round_fl_to_int(UI_view2d_scale_get_x(&region->v2d) *
UI_PANEL_CATEGORY_MARGIN_WIDTH);
const int alignment = RGN_ALIGN_ENUM_FROM_MASK(region->alignment);
if (alignment == RGN_ALIGN_LEFT) {
- r_ar_gutter->xmax = r_ar_gutter->xmin + category_tabs_width;
+ r_region_gutter->xmax = r_region_gutter->xmin + category_tabs_width;
}
else if (alignment == RGN_ALIGN_RIGHT) {
- r_ar_gutter->xmin = r_ar_gutter->xmax - category_tabs_width;
+ r_region_gutter->xmin = r_region_gutter->xmax - category_tabs_width;
}
else {
BLI_assert(!"Unsupported alignment");
@@ -97,9 +97,9 @@ bool ED_region_panel_category_gutter_calc_rect(const ARegion *region, rcti *r_ar
bool ED_region_panel_category_gutter_isect_xy(const ARegion *region, const int event_xy[2])
{
- rcti ar_gutter;
- if (ED_region_panel_category_gutter_calc_rect(region, &ar_gutter)) {
- return BLI_rcti_isect_pt_v(&ar_gutter, event_xy);
+ rcti region_gutter;
+ if (ED_region_panel_category_gutter_calc_rect(region, &region_gutter)) {
+ return BLI_rcti_isect_pt_v(&region_gutter, event_xy);
}
return false;
}
diff --git a/source/blender/editors/screen/area_utils.c b/source/blender/editors/screen/area_utils.c
index cacd6b1edd7..075759f1120 100644
--- a/source/blender/editors/screen/area_utils.c
+++ b/source/blender/editors/screen/area_utils.c
@@ -46,7 +46,7 @@ void ED_region_generic_tools_region_message_subscribe(const struct bContext *UNU
struct WorkSpace *UNUSED(workspace),
struct Scene *UNUSED(scene),
struct bScreen *UNUSED(screen),
- struct ScrArea *UNUSED(sa),
+ struct ScrArea *UNUSED(area),
struct ARegion *region,
struct wmMsgBus *mbus)
{
diff --git a/source/blender/editors/screen/glutil.c b/source/blender/editors/screen/glutil.c
index f757b856dcf..a9380debbdc 100644
--- a/source/blender/editors/screen/glutil.c
+++ b/source/blender/editors/screen/glutil.c
@@ -83,7 +83,7 @@ static void immDrawPixelsTexSetupAttributes(IMMDrawPixelsTexState *state)
/* To be used before calling immDrawPixelsTex
* Default shader is GPU_SHADER_2D_IMAGE_COLOR
* You can still set uniforms with :
- * GPU_shader_uniform_int(shader, GPU_shader_get_uniform_ensure(shader, "name"), 0);
+ * GPU_shader_uniform_int(shader, GPU_shader_get_uniform(shader, "name"), 0);
* */
IMMDrawPixelsTexState immDrawPixelsTexSetup(int builtin)
{
@@ -132,7 +132,7 @@ void immDrawPixelsTexScaled_clipping(IMMDrawPixelsTexState *state,
float yzoom,
float color[4])
{
- unsigned char *uc_rect = (unsigned char *)rect;
+ uchar *uc_rect = (uchar *)rect;
const float *f_rect = (float *)rect;
int subpart_x, subpart_y, tex_w, tex_h;
int seamless, offset_x, offset_y, nsubparts_x, nsubparts_y;
@@ -185,13 +185,13 @@ void immDrawPixelsTexScaled_clipping(IMMDrawPixelsTexState *state,
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA8, tex_w, tex_h, 0, format, GL_UNSIGNED_BYTE, NULL);
}
- unsigned int pos = state->pos, texco = state->texco;
+ uint pos = state->pos, texco = state->texco;
/* optional */
/* NOTE: Shader could be null for GLSL OCIO drawing, it is fine, since
* it does not need color.
*/
- if (state->shader != NULL && GPU_shader_get_uniform_ensure(state->shader, "color") != -1) {
+ if (state->shader != NULL && GPU_shader_get_uniform(state->shader, "color") != -1) {
immUniformColor4fv((color) ? color : white);
}
@@ -650,7 +650,7 @@ void ED_draw_imbuf_clipping(ImBuf *ibuf,
/* In case GLSL failed or not usable, fallback to glaDrawPixelsAuto */
if (need_fallback) {
- unsigned char *display_buffer;
+ uchar *display_buffer;
void *cache_handle;
display_buffer = IMB_display_buffer_acquire(
@@ -758,7 +758,7 @@ int ED_draw_imbuf_method(ImBuf *ibuf)
/* don't move to GPU_immediate_util.h because this uses user-prefs
* and isn't very low level */
-void immDrawBorderCorners(unsigned int pos, const rcti *border, float zoomx, float zoomy)
+void immDrawBorderCorners(uint pos, const rcti *border, float zoomx, float zoomy)
{
float delta_x = 4.0f * UI_DPI_FAC / zoomx;
float delta_y = 4.0f * UI_DPI_FAC / zoomy;
diff --git a/source/blender/editors/screen/screen_context.c b/source/blender/editors/screen/screen_context.c
index 9536772be3d..3202dc68f37 100644
--- a/source/blender/editors/screen/screen_context.c
+++ b/source/blender/editors/screen/screen_context.c
@@ -27,6 +27,7 @@
#include "MEM_guardedalloc.h"
+#include "DNA_anim_types.h"
#include "DNA_armature_types.h"
#include "DNA_gpencil_types.h"
#include "DNA_object_types.h"
@@ -36,6 +37,7 @@
#include "DNA_space_types.h"
#include "DNA_windowmanager_types.h"
+#include "BLI_listbase.h"
#include "BLI_utildefines.h"
#include "BKE_action.h"
@@ -88,6 +90,7 @@ const char *screen_context_dir[] = {
"sequences",
"selected_sequences",
"selected_editable_sequences", /* sequencer */
+ "selected_nla_strips", /* nla editor */
"gpencil_data",
"gpencil_data_owner", /* grease pencil data */
"annotation_data",
@@ -111,12 +114,12 @@ int ed_screen_context(const bContext *C, const char *member, bContextDataResult
{
wmWindow *win = CTX_wm_window(C);
View3D *v3d = CTX_wm_view3d(C); /* This may be NULL in a lot of cases. */
- bScreen *sc = CTX_wm_screen(C);
- ScrArea *sa = CTX_wm_area(C);
+ bScreen *screen = CTX_wm_screen(C);
+ ScrArea *area = CTX_wm_area(C);
Scene *scene = WM_window_get_active_scene(win);
ViewLayer *view_layer = WM_window_get_active_view_layer(win);
- Object *obact = (view_layer && view_layer->basact) ? view_layer->basact->object : NULL;
- Object *obedit = view_layer ? OBEDIT_FROM_VIEW_LAYER(view_layer) : NULL;
+ Object *obact = view_layer->basact ? view_layer->basact->object : NULL;
+ Object *obedit = OBEDIT_FROM_VIEW_LAYER(view_layer);
if (CTX_data_dir(member)) {
CTX_data_dir_set(result, screen_context_dir);
@@ -127,7 +130,7 @@ int ed_screen_context(const bContext *C, const char *member, bContextDataResult
return 1;
}
else if (CTX_data_equals(member, "visible_objects")) {
- for (Base *base = view_layer->object_bases.first; base; base = base->next) {
+ LISTBASE_FOREACH (Base *, base, &view_layer->object_bases) {
if (BASE_VISIBLE(v3d, base)) {
CTX_data_id_list_add(result, &base->object->id);
}
@@ -136,7 +139,7 @@ int ed_screen_context(const bContext *C, const char *member, bContextDataResult
return 1;
}
else if (CTX_data_equals(member, "selectable_objects")) {
- for (Base *base = view_layer->object_bases.first; base; base = base->next) {
+ LISTBASE_FOREACH (Base *, base, &view_layer->object_bases) {
if (BASE_SELECTABLE(v3d, base)) {
CTX_data_id_list_add(result, &base->object->id);
}
@@ -145,7 +148,7 @@ int ed_screen_context(const bContext *C, const char *member, bContextDataResult
return 1;
}
else if (CTX_data_equals(member, "selected_objects")) {
- for (Base *base = view_layer->object_bases.first; base; base = base->next) {
+ LISTBASE_FOREACH (Base *, base, &view_layer->object_bases) {
if (BASE_SELECTED(v3d, base)) {
CTX_data_id_list_add(result, &base->object->id);
}
@@ -154,7 +157,7 @@ int ed_screen_context(const bContext *C, const char *member, bContextDataResult
return 1;
}
else if (CTX_data_equals(member, "selected_editable_objects")) {
- for (Base *base = view_layer->object_bases.first; base; base = base->next) {
+ LISTBASE_FOREACH (Base *, base, &view_layer->object_bases) {
if (BASE_SELECTED_EDITABLE(v3d, base)) {
CTX_data_id_list_add(result, &base->object->id);
}
@@ -164,7 +167,7 @@ int ed_screen_context(const bContext *C, const char *member, bContextDataResult
}
else if (CTX_data_equals(member, "editable_objects")) {
/* Visible + Editable, but not necessarily selected */
- for (Base *base = view_layer->object_bases.first; base; base = base->next) {
+ LISTBASE_FOREACH (Base *, base, &view_layer->object_bases) {
if (BASE_EDITABLE(v3d, base)) {
CTX_data_id_list_add(result, &base->object->id);
}
@@ -503,13 +506,38 @@ int ed_screen_context(const bContext *C, const char *member, bContextDataResult
return 1;
}
}
+ else if (CTX_data_equals(member, "selected_nla_strips")) {
+ bAnimContext ac;
+ if (ANIM_animdata_get_context(C, &ac) != 0) {
+ ListBase anim_data = {NULL, NULL};
+ bAnimListElem *ale;
+
+ ANIM_animdata_filter(&ac, &anim_data, ANIMFILTER_DATA_VISIBLE, ac.data, ac.datatype);
+ for (ale = anim_data.first; ale; ale = ale->next) {
+ if (ale->datatype != ALE_NLASTRIP) {
+ continue;
+ }
+ NlaTrack *nlt = (NlaTrack *)ale->data;
+ NlaStrip *strip;
+ for (strip = nlt->strips.first; strip; strip = strip->next) {
+ if (strip->flag & NLASTRIP_FLAG_SELECT) {
+ CTX_data_list_add(result, &scene->id, &RNA_NlaStrip, strip);
+ }
+ }
+ }
+ ANIM_animdata_freelist(&anim_data);
+
+ CTX_data_type_set(result, CTX_DATA_TYPE_COLLECTION);
+ return 1;
+ }
+ }
else if (CTX_data_equals(member, "gpencil_data")) {
/* FIXME: for some reason, CTX_data_active_object(C) returns NULL when called from these
* situations (as outlined above - see Campbell's #ifdefs).
* That causes the get_active function to fail when called from context.
* For that reason, we end up using an alternative where we pass everything in!
*/
- bGPdata *gpd = ED_gpencil_data_get_active_direct(sa, obact);
+ bGPdata *gpd = ED_gpencil_data_get_active_direct(area, obact);
if (gpd) {
CTX_data_id_pointer_set(result, &gpd->id);
@@ -523,7 +551,7 @@ int ed_screen_context(const bContext *C, const char *member, bContextDataResult
PointerRNA ptr;
/* get pointer to Grease Pencil Data */
- gpd_ptr = ED_gpencil_data_get_pointers_direct(sa, obact, &ptr);
+ gpd_ptr = ED_gpencil_data_get_pointers_direct(area, obact, &ptr);
if (gpd_ptr) {
CTX_data_pointer_set(result, ptr.owner_id, ptr.type, ptr.data);
@@ -531,7 +559,7 @@ int ed_screen_context(const bContext *C, const char *member, bContextDataResult
}
}
else if (CTX_data_equals(member, "annotation_data")) {
- bGPdata *gpd = ED_annotation_data_get_active_direct((ID *)sc, sa, scene);
+ bGPdata *gpd = ED_annotation_data_get_active_direct((ID *)screen, area, scene);
if (gpd) {
CTX_data_id_pointer_set(result, &gpd->id);
@@ -544,7 +572,7 @@ int ed_screen_context(const bContext *C, const char *member, bContextDataResult
PointerRNA ptr;
/* Get pointer to Grease Pencil Data. */
- gpd_ptr = ED_annotation_data_get_pointers_direct((ID *)sc, sa, scene, &ptr);
+ gpd_ptr = ED_annotation_data_get_pointers_direct((ID *)screen, area, scene, &ptr);
if (gpd_ptr) {
CTX_data_pointer_set(result, ptr.owner_id, ptr.type, ptr.data);
@@ -552,7 +580,7 @@ int ed_screen_context(const bContext *C, const char *member, bContextDataResult
}
}
else if (CTX_data_equals(member, "active_gpencil_layer")) {
- bGPdata *gpd = ED_gpencil_data_get_active_direct(sa, obact);
+ bGPdata *gpd = ED_gpencil_data_get_active_direct(area, obact);
if (gpd) {
bGPDlayer *gpl = BKE_gpencil_layer_active_get(gpd);
@@ -564,7 +592,7 @@ int ed_screen_context(const bContext *C, const char *member, bContextDataResult
}
}
else if (CTX_data_equals(member, "active_annotation_layer")) {
- bGPdata *gpd = ED_annotation_data_get_active_direct((ID *)sc, sa, scene);
+ bGPdata *gpd = ED_annotation_data_get_active_direct((ID *)screen, area, scene);
if (gpd) {
bGPDlayer *gpl = BKE_gpencil_layer_active_get(gpd);
@@ -576,7 +604,7 @@ int ed_screen_context(const bContext *C, const char *member, bContextDataResult
}
}
else if (CTX_data_equals(member, "active_gpencil_frame")) {
- bGPdata *gpd = ED_gpencil_data_get_active_direct(sa, obact);
+ bGPdata *gpd = ED_gpencil_data_get_active_direct(area, obact);
if (gpd) {
bGPDlayer *gpl = BKE_gpencil_layer_active_get(gpd);
@@ -588,7 +616,7 @@ int ed_screen_context(const bContext *C, const char *member, bContextDataResult
}
}
else if (CTX_data_equals(member, "visible_gpencil_layers")) {
- bGPdata *gpd = ED_gpencil_data_get_active_direct(sa, obact);
+ bGPdata *gpd = ED_gpencil_data_get_active_direct(area, obact);
if (gpd) {
bGPDlayer *gpl;
@@ -603,7 +631,7 @@ int ed_screen_context(const bContext *C, const char *member, bContextDataResult
}
}
else if (CTX_data_equals(member, "editable_gpencil_layers")) {
- bGPdata *gpd = ED_gpencil_data_get_active_direct(sa, obact);
+ bGPdata *gpd = ED_gpencil_data_get_active_direct(area, obact);
if (gpd) {
bGPDlayer *gpl;
@@ -618,7 +646,7 @@ int ed_screen_context(const bContext *C, const char *member, bContextDataResult
}
}
else if (CTX_data_equals(member, "editable_gpencil_strokes")) {
- bGPdata *gpd = ED_gpencil_data_get_active_direct(sa, obact);
+ bGPdata *gpd = ED_gpencil_data_get_active_direct(area, obact);
const bool is_multiedit = (bool)GPENCIL_MULTIEDIT_SESSIONS_ON(gpd);
if (gpd) {
@@ -636,7 +664,7 @@ int ed_screen_context(const bContext *C, const char *member, bContextDataResult
for (gpf = init_gpf; gpf; gpf = gpf->next) {
if ((gpf == gpl->actframe) || ((gpf->flag & GP_FRAME_SELECT) && (is_multiedit))) {
for (gps = gpf->strokes.first; gps; gps = gps->next) {
- if (ED_gpencil_stroke_can_use_direct(sa, gps)) {
+ if (ED_gpencil_stroke_can_use_direct(area, gps)) {
/* check if the color is editable */
if (ED_gpencil_stroke_color_use(obact, gpl, gps) == false) {
continue;
@@ -701,7 +729,7 @@ int ed_screen_context(const bContext *C, const char *member, bContextDataResult
ANIM_animdata_filter(&ac, &anim_data, filter, ac.data, ac.datatype);
- for (bAnimListElem *ale = anim_data.first; ale; ale = ale->next) {
+ LISTBASE_FOREACH (bAnimListElem *, ale, &anim_data) {
if (ELEM(ale->type, ANIMTYPE_FCURVE, ANIMTYPE_NLACURVE)) {
CTX_data_list_add(result, ale->fcurve_owner_id, &RNA_FCurve, ale->data);
}
@@ -724,7 +752,7 @@ int ed_screen_context(const bContext *C, const char *member, bContextDataResult
ANIM_animdata_filter(&ac, &anim_data, filter, ac.data, ac.datatype);
- for (bAnimListElem *ale = anim_data.first; ale; ale = ale->next) {
+ LISTBASE_FOREACH (bAnimListElem *, ale, &anim_data) {
if (ELEM(ale->type, ANIMTYPE_FCURVE, ANIMTYPE_NLACURVE)) {
CTX_data_pointer_set(result, ale->fcurve_owner_id, &RNA_FCurve, ale->data);
break;
diff --git a/source/blender/editors/screen/screen_draw.c b/source/blender/editors/screen/screen_draw.c
index 3331f4db11b..2452302561b 100644
--- a/source/blender/editors/screen/screen_draw.c
+++ b/source/blender/editors/screen/screen_draw.c
@@ -41,10 +41,10 @@
* Draw horizontal shape visualizing future joining
* (left as well right direction of future joining).
*/
-static void draw_horizontal_join_shape(ScrArea *sa, char dir, unsigned int pos)
+static void draw_horizontal_join_shape(ScrArea *area, char dir, uint pos)
{
- const float width = screen_geom_area_width(sa) - 1;
- const float height = screen_geom_area_height(sa) - 1;
+ const float width = screen_geom_area_width(area) - 1;
+ const float height = screen_geom_area_height(area) - 1;
vec2f points[10];
short i;
float w, h;
@@ -58,43 +58,43 @@ static void draw_horizontal_join_shape(ScrArea *sa, char dir, unsigned int pos)
w = width / 4;
}
- points[0].x = sa->v1->vec.x;
- points[0].y = sa->v1->vec.y + height / 2;
+ points[0].x = area->v1->vec.x;
+ points[0].y = area->v1->vec.y + height / 2;
- points[1].x = sa->v1->vec.x;
- points[1].y = sa->v1->vec.y;
+ points[1].x = area->v1->vec.x;
+ points[1].y = area->v1->vec.y;
- points[2].x = sa->v4->vec.x - w;
- points[2].y = sa->v4->vec.y;
+ points[2].x = area->v4->vec.x - w;
+ points[2].y = area->v4->vec.y;
- points[3].x = sa->v4->vec.x - w;
- points[3].y = sa->v4->vec.y + height / 2 - 2 * h;
+ points[3].x = area->v4->vec.x - w;
+ points[3].y = area->v4->vec.y + height / 2 - 2 * h;
- points[4].x = sa->v4->vec.x - 2 * w;
- points[4].y = sa->v4->vec.y + height / 2;
+ points[4].x = area->v4->vec.x - 2 * w;
+ points[4].y = area->v4->vec.y + height / 2;
- points[5].x = sa->v4->vec.x - w;
- points[5].y = sa->v4->vec.y + height / 2 + 2 * h;
+ points[5].x = area->v4->vec.x - w;
+ points[5].y = area->v4->vec.y + height / 2 + 2 * h;
- points[6].x = sa->v3->vec.x - w;
- points[6].y = sa->v3->vec.y;
+ points[6].x = area->v3->vec.x - w;
+ points[6].y = area->v3->vec.y;
- points[7].x = sa->v2->vec.x;
- points[7].y = sa->v2->vec.y;
+ points[7].x = area->v2->vec.x;
+ points[7].y = area->v2->vec.y;
- points[8].x = sa->v4->vec.x;
- points[8].y = sa->v4->vec.y + height / 2 - h;
+ points[8].x = area->v4->vec.x;
+ points[8].y = area->v4->vec.y + height / 2 - h;
- points[9].x = sa->v4->vec.x;
- points[9].y = sa->v4->vec.y + height / 2 + h;
+ points[9].x = area->v4->vec.x;
+ points[9].y = area->v4->vec.y + height / 2 + h;
if (dir == 'l') {
/* when direction is left, then we flip direction of arrow */
- float cx = sa->v1->vec.x + width;
+ float cx = area->v1->vec.x + width;
for (i = 0; i < 10; i++) {
points[i].x -= cx;
points[i].x = -points[i].x;
- points[i].x += sa->v1->vec.x;
+ points[i].x += area->v1->vec.x;
}
}
@@ -122,10 +122,10 @@ static void draw_horizontal_join_shape(ScrArea *sa, char dir, unsigned int pos)
/**
* Draw vertical shape visualizing future joining (up/down direction).
*/
-static void draw_vertical_join_shape(ScrArea *sa, char dir, unsigned int pos)
+static void draw_vertical_join_shape(ScrArea *area, char dir, uint pos)
{
- const float width = screen_geom_area_width(sa) - 1;
- const float height = screen_geom_area_height(sa) - 1;
+ const float width = screen_geom_area_width(area) - 1;
+ const float height = screen_geom_area_height(area) - 1;
vec2f points[10];
short i;
float w, h;
@@ -139,43 +139,43 @@ static void draw_vertical_join_shape(ScrArea *sa, char dir, unsigned int pos)
w = width / 8;
}
- points[0].x = sa->v1->vec.x + width / 2;
- points[0].y = sa->v3->vec.y;
+ points[0].x = area->v1->vec.x + width / 2;
+ points[0].y = area->v3->vec.y;
- points[1].x = sa->v2->vec.x;
- points[1].y = sa->v2->vec.y;
+ points[1].x = area->v2->vec.x;
+ points[1].y = area->v2->vec.y;
- points[2].x = sa->v1->vec.x;
- points[2].y = sa->v1->vec.y + h;
+ points[2].x = area->v1->vec.x;
+ points[2].y = area->v1->vec.y + h;
- points[3].x = sa->v1->vec.x + width / 2 - 2 * w;
- points[3].y = sa->v1->vec.y + h;
+ points[3].x = area->v1->vec.x + width / 2 - 2 * w;
+ points[3].y = area->v1->vec.y + h;
- points[4].x = sa->v1->vec.x + width / 2;
- points[4].y = sa->v1->vec.y + 2 * h;
+ points[4].x = area->v1->vec.x + width / 2;
+ points[4].y = area->v1->vec.y + 2 * h;
- points[5].x = sa->v1->vec.x + width / 2 + 2 * w;
- points[5].y = sa->v1->vec.y + h;
+ points[5].x = area->v1->vec.x + width / 2 + 2 * w;
+ points[5].y = area->v1->vec.y + h;
- points[6].x = sa->v4->vec.x;
- points[6].y = sa->v4->vec.y + h;
+ points[6].x = area->v4->vec.x;
+ points[6].y = area->v4->vec.y + h;
- points[7].x = sa->v3->vec.x;
- points[7].y = sa->v3->vec.y;
+ points[7].x = area->v3->vec.x;
+ points[7].y = area->v3->vec.y;
- points[8].x = sa->v1->vec.x + width / 2 - w;
- points[8].y = sa->v1->vec.y;
+ points[8].x = area->v1->vec.x + width / 2 - w;
+ points[8].y = area->v1->vec.y;
- points[9].x = sa->v1->vec.x + width / 2 + w;
- points[9].y = sa->v1->vec.y;
+ points[9].x = area->v1->vec.x + width / 2 + w;
+ points[9].y = area->v1->vec.y;
if (dir == 'u') {
/* when direction is up, then we flip direction of arrow */
- float cy = sa->v1->vec.y + height;
+ float cy = area->v1->vec.y + height;
for (i = 0; i < 10; i++) {
points[i].y -= cy;
points[i].y = -points[i].y;
- points[i].y += sa->v1->vec.y;
+ points[i].y += area->v1->vec.y;
}
}
@@ -203,13 +203,13 @@ static void draw_vertical_join_shape(ScrArea *sa, char dir, unsigned int pos)
/**
* Draw join shape due to direction of joining.
*/
-static void draw_join_shape(ScrArea *sa, char dir, unsigned int pos)
+static void draw_join_shape(ScrArea *area, char dir, uint pos)
{
if (dir == 'u' || dir == 'd') {
- draw_vertical_join_shape(sa, dir, pos);
+ draw_vertical_join_shape(area, dir, pos);
}
else {
- draw_horizontal_join_shape(sa, dir, pos);
+ draw_horizontal_join_shape(area, dir, pos);
}
}
@@ -294,26 +294,26 @@ static GPUBatch *batch_screen_edges_get(int *corner_len)
/**
* Draw screen area darker with arrow (visualization of future joining).
*/
-static void scrarea_draw_shape_dark(ScrArea *sa, char dir, unsigned int pos)
+static void scrarea_draw_shape_dark(ScrArea *area, char dir, uint pos)
{
GPU_blend_set_func_separate(
GPU_SRC_ALPHA, GPU_ONE_MINUS_SRC_ALPHA, GPU_ONE, GPU_ONE_MINUS_SRC_ALPHA);
immUniformColor4ub(0, 0, 0, 50);
- draw_join_shape(sa, dir, pos);
+ draw_join_shape(area, dir, pos);
}
/**
* Draw screen area lighter with arrow shape ("eraser" of previous dark shape).
*/
-static void scrarea_draw_shape_light(ScrArea *sa, char UNUSED(dir), unsigned int pos)
+static void scrarea_draw_shape_light(ScrArea *area, char UNUSED(dir), uint pos)
{
GPU_blend_set_func(GPU_DST_COLOR, GPU_SRC_ALPHA);
/* value 181 was hardly computed: 181~105 */
immUniformColor4ub(255, 255, 255, 50);
- /* draw_join_shape(sa, dir); */
+ /* draw_join_shape(area, dir); */
- immRectf(pos, sa->v1->vec.x, sa->v1->vec.y, sa->v3->vec.x, sa->v3->vec.y);
+ immRectf(pos, area->v1->vec.x, area->v1->vec.y, area->v3->vec.x, area->v3->vec.y);
}
static void drawscredge_area_draw(
@@ -350,12 +350,12 @@ static void drawscredge_area_draw(
/**
* \brief Screen edges drawing.
*/
-static void drawscredge_area(ScrArea *sa, int sizex, int sizey, float edge_thickness)
+static void drawscredge_area(ScrArea *area, int sizex, int sizey, float edge_thickness)
{
- short x1 = sa->v1->vec.x;
- short y1 = sa->v1->vec.y;
- short x2 = sa->v3->vec.x;
- short y2 = sa->v3->vec.y;
+ short x1 = area->v1->vec.x;
+ short y1 = area->v1->vec.y;
+ short x2 = area->v3->vec.x;
+ short y2 = area->v3->vec.y;
drawscredge_area_draw(sizex, sizey, x1, y1, x2, y2, edge_thickness);
}
@@ -381,13 +381,13 @@ void ED_screen_draw_edges(wmWindow *win)
float col[4], corner_scale, edge_thickness;
int verts_per_corner = 0;
- ScrArea *sa;
+ ScrArea *area;
rcti scissor_rect;
BLI_rcti_init_minmax(&scissor_rect);
- for (sa = screen->areabase.first; sa; sa = sa->next) {
- BLI_rcti_do_minmax_v(&scissor_rect, (int[2]){sa->v1->vec.x, sa->v1->vec.y});
- BLI_rcti_do_minmax_v(&scissor_rect, (int[2]){sa->v3->vec.x, sa->v3->vec.y});
+ for (area = screen->areabase.first; area; area = area->next) {
+ BLI_rcti_do_minmax_v(&scissor_rect, (int[2]){area->v1->vec.x, area->v1->vec.y});
+ BLI_rcti_do_minmax_v(&scissor_rect, (int[2]){area->v3->vec.x, area->v3->vec.y});
}
if (GPU_type_matches(GPU_DEVICE_INTEL_UHD, GPU_OS_UNIX, GPU_DRIVER_ANY)) {
@@ -422,8 +422,8 @@ void ED_screen_draw_edges(wmWindow *win)
GPU_batch_uniform_1f(batch, "scale", corner_scale);
GPU_batch_uniform_4fv(batch, "color", col);
- for (sa = screen->areabase.first; sa; sa = sa->next) {
- drawscredge_area(sa, winsize_x, winsize_y, edge_thickness);
+ for (area = screen->areabase.first; area; area = area->next) {
+ drawscredge_area(area, winsize_x, winsize_y, edge_thickness);
}
GPU_blend(false);
@@ -480,7 +480,7 @@ void ED_screen_draw_join_shape(ScrArea *sa1, ScrArea *sa2)
immUnbindProgram();
}
-void ED_screen_draw_split_preview(ScrArea *sa, const int dir, const float fac)
+void ED_screen_draw_split_preview(ScrArea *area, const int dir, const float fac)
{
uint pos = GPU_vertformat_attr_add(immVertexFormat(), "pos", GPU_COMP_F32, 2, GPU_FETCH_FLOAT);
immBindBuiltinProgram(GPU_SHADER_2D_UNIFORM_COLOR);
@@ -495,10 +495,10 @@ void ED_screen_draw_split_preview(ScrArea *sa, const int dir, const float fac)
immBegin(GPU_PRIM_LINES, 2);
if (dir == 'h') {
- const float y = (1 - fac) * sa->totrct.ymin + fac * sa->totrct.ymax;
+ const float y = (1 - fac) * area->totrct.ymin + fac * area->totrct.ymax;
- immVertex2f(pos, sa->totrct.xmin, y);
- immVertex2f(pos, sa->totrct.xmax, y);
+ immVertex2f(pos, area->totrct.xmin, y);
+ immVertex2f(pos, area->totrct.xmax, y);
immEnd();
@@ -506,17 +506,17 @@ void ED_screen_draw_split_preview(ScrArea *sa, const int dir, const float fac)
immBegin(GPU_PRIM_LINES, 2);
- immVertex2f(pos, sa->totrct.xmin, y + 1);
- immVertex2f(pos, sa->totrct.xmax, y + 1);
+ immVertex2f(pos, area->totrct.xmin, y + 1);
+ immVertex2f(pos, area->totrct.xmax, y + 1);
immEnd();
}
else {
BLI_assert(dir == 'v');
- const float x = (1 - fac) * sa->totrct.xmin + fac * sa->totrct.xmax;
+ const float x = (1 - fac) * area->totrct.xmin + fac * area->totrct.xmax;
- immVertex2f(pos, x, sa->totrct.ymin);
- immVertex2f(pos, x, sa->totrct.ymax);
+ immVertex2f(pos, x, area->totrct.ymin);
+ immVertex2f(pos, x, area->totrct.ymax);
immEnd();
@@ -524,8 +524,8 @@ void ED_screen_draw_split_preview(ScrArea *sa, const int dir, const float fac)
immBegin(GPU_PRIM_LINES, 2);
- immVertex2f(pos, x + 1, sa->totrct.ymin);
- immVertex2f(pos, x + 1, sa->totrct.ymax);
+ immVertex2f(pos, x + 1, area->totrct.ymin);
+ immVertex2f(pos, x + 1, area->totrct.ymax);
immEnd();
}
@@ -547,9 +547,9 @@ static void screen_preview_scale_get(
{
float max_x = 0, max_y = 0;
- for (ScrArea *sa = screen->areabase.first; sa; sa = sa->next) {
- max_x = MAX2(max_x, sa->totrct.xmax);
- max_y = MAX2(max_y, sa->totrct.ymax);
+ LISTBASE_FOREACH (ScrArea *, area, &screen->areabase) {
+ max_x = MAX2(max_x, area->totrct.xmax);
+ max_y = MAX2(max_y, area->totrct.ymax);
}
r_scale[0] = (size_x * asp[0]) / max_x;
r_scale[1] = (size_y * asp[1]) / max_y;
@@ -566,12 +566,12 @@ static void screen_preview_draw_areas(const bScreen *screen,
immBindBuiltinProgram(GPU_SHADER_2D_UNIFORM_COLOR);
immUniformColor4fv(col);
- for (ScrArea *sa = screen->areabase.first; sa; sa = sa->next) {
+ LISTBASE_FOREACH (ScrArea *, area, &screen->areabase) {
rctf rect = {
- .xmin = sa->totrct.xmin * scale[0] + ofs_h,
- .xmax = sa->totrct.xmax * scale[0] - ofs_h,
- .ymin = sa->totrct.ymin * scale[1] + ofs_h,
- .ymax = sa->totrct.ymax * scale[1] - ofs_h,
+ .xmin = area->totrct.xmin * scale[0] + ofs_h,
+ .xmax = area->totrct.xmax * scale[0] - ofs_h,
+ .ymin = area->totrct.ymin * scale[1] + ofs_h,
+ .ymax = area->totrct.ymax * scale[1] - ofs_h,
};
immBegin(GPU_PRIM_TRI_FAN, 4);
@@ -608,7 +608,7 @@ static void screen_preview_draw(const bScreen *screen, int size_x, int size_y)
/**
* Render the preview for a screen layout in \a screen.
*/
-void ED_screen_preview_render(const bScreen *screen, int size_x, int size_y, unsigned int *r_rect)
+void ED_screen_preview_render(const bScreen *screen, int size_x, int size_y, uint *r_rect)
{
char err_out[256] = "unknown";
GPUOffScreen *offscreen = GPU_offscreen_create(size_x, size_y, 0, true, false, err_out);
diff --git a/source/blender/editors/screen/screen_edit.c b/source/blender/editors/screen/screen_edit.c
index 0151a0fcb0d..6f004238522 100644
--- a/source/blender/editors/screen/screen_edit.c
+++ b/source/blender/editors/screen/screen_edit.c
@@ -70,19 +70,19 @@ static ScrArea *screen_addarea_ex(ScrAreaMap *area_map,
ScrVert *bottom_right,
short spacetype)
{
- ScrArea *sa = MEM_callocN(sizeof(ScrArea), "addscrarea");
+ ScrArea *area = MEM_callocN(sizeof(ScrArea), "addscrarea");
- sa->v1 = bottom_left;
- sa->v2 = top_left;
- sa->v3 = top_right;
- sa->v4 = bottom_right;
- sa->spacetype = spacetype;
+ area->v1 = bottom_left;
+ area->v2 = top_left;
+ area->v3 = top_right;
+ area->v4 = bottom_right;
+ area->spacetype = spacetype;
- BLI_addtail(&area_map->areabase, sa);
+ BLI_addtail(&area_map->areabase, area);
- return sa;
+ return area;
}
-static ScrArea *screen_addarea(bScreen *sc,
+static ScrArea *screen_addarea(bScreen *screen,
ScrVert *left_bottom,
ScrVert *left_top,
ScrVert *right_top,
@@ -90,34 +90,35 @@ static ScrArea *screen_addarea(bScreen *sc,
short spacetype)
{
return screen_addarea_ex(
- AREAMAP_FROM_SCREEN(sc), left_bottom, left_top, right_top, right_bottom, spacetype);
+ AREAMAP_FROM_SCREEN(screen), left_bottom, left_top, right_top, right_bottom, spacetype);
}
-static void screen_delarea(bContext *C, bScreen *sc, ScrArea *sa)
+static void screen_delarea(bContext *C, bScreen *screen, ScrArea *area)
{
- ED_area_exit(C, sa);
+ ED_area_exit(C, area);
- BKE_screen_area_free(sa);
+ BKE_screen_area_free(area);
- BLI_remlink(&sc->areabase, sa);
- MEM_freeN(sa);
+ BLI_remlink(&screen->areabase, area);
+ MEM_freeN(area);
}
-ScrArea *area_split(const wmWindow *win, bScreen *sc, ScrArea *sa, char dir, float fac, int merge)
+ScrArea *area_split(
+ const wmWindow *win, bScreen *screen, ScrArea *area, char dir, float fac, int merge)
{
ScrArea *newa = NULL;
ScrVert *sv1, *sv2;
short split;
rcti window_rect;
- if (sa == NULL) {
+ if (area == NULL) {
return NULL;
}
WM_window_rect_calc(win, &window_rect);
- split = screen_geom_find_area_split_point(sa, &window_rect, dir, fac);
+ split = screen_geom_find_area_split_point(area, &window_rect, dir, fac);
if (split == 0) {
return NULL;
}
@@ -128,73 +129,73 @@ ScrArea *area_split(const wmWindow *win, bScreen *sc, ScrArea *sa, char dir, flo
if (dir == 'h') {
/* new vertices */
- sv1 = screen_geom_vertex_add(sc, sa->v1->vec.x, split);
- sv2 = screen_geom_vertex_add(sc, sa->v4->vec.x, split);
+ sv1 = screen_geom_vertex_add(screen, area->v1->vec.x, split);
+ sv2 = screen_geom_vertex_add(screen, area->v4->vec.x, split);
/* new edges */
- screen_geom_edge_add(sc, sa->v1, sv1);
- screen_geom_edge_add(sc, sv1, sa->v2);
- screen_geom_edge_add(sc, sa->v3, sv2);
- screen_geom_edge_add(sc, sv2, sa->v4);
- screen_geom_edge_add(sc, sv1, sv2);
+ screen_geom_edge_add(screen, area->v1, sv1);
+ screen_geom_edge_add(screen, sv1, area->v2);
+ screen_geom_edge_add(screen, area->v3, sv2);
+ screen_geom_edge_add(screen, sv2, area->v4);
+ screen_geom_edge_add(screen, sv1, sv2);
if (fac > 0.5f) {
/* new areas: top */
- newa = screen_addarea(sc, sv1, sa->v2, sa->v3, sv2, sa->spacetype);
+ newa = screen_addarea(screen, sv1, area->v2, area->v3, sv2, area->spacetype);
/* area below */
- sa->v2 = sv1;
- sa->v3 = sv2;
+ area->v2 = sv1;
+ area->v3 = sv2;
}
else {
/* new areas: bottom */
- newa = screen_addarea(sc, sa->v1, sv1, sv2, sa->v4, sa->spacetype);
+ newa = screen_addarea(screen, area->v1, sv1, sv2, area->v4, area->spacetype);
/* area above */
- sa->v1 = sv1;
- sa->v4 = sv2;
+ area->v1 = sv1;
+ area->v4 = sv2;
}
- ED_area_data_copy(newa, sa, true);
+ ED_area_data_copy(newa, area, true);
}
else {
/* new vertices */
- sv1 = screen_geom_vertex_add(sc, split, sa->v1->vec.y);
- sv2 = screen_geom_vertex_add(sc, split, sa->v2->vec.y);
+ sv1 = screen_geom_vertex_add(screen, split, area->v1->vec.y);
+ sv2 = screen_geom_vertex_add(screen, split, area->v2->vec.y);
/* new edges */
- screen_geom_edge_add(sc, sa->v1, sv1);
- screen_geom_edge_add(sc, sv1, sa->v4);
- screen_geom_edge_add(sc, sa->v2, sv2);
- screen_geom_edge_add(sc, sv2, sa->v3);
- screen_geom_edge_add(sc, sv1, sv2);
+ screen_geom_edge_add(screen, area->v1, sv1);
+ screen_geom_edge_add(screen, sv1, area->v4);
+ screen_geom_edge_add(screen, area->v2, sv2);
+ screen_geom_edge_add(screen, sv2, area->v3);
+ screen_geom_edge_add(screen, sv1, sv2);
if (fac > 0.5f) {
/* new areas: right */
- newa = screen_addarea(sc, sv1, sv2, sa->v3, sa->v4, sa->spacetype);
+ newa = screen_addarea(screen, sv1, sv2, area->v3, area->v4, area->spacetype);
/* area left */
- sa->v3 = sv2;
- sa->v4 = sv1;
+ area->v3 = sv2;
+ area->v4 = sv1;
}
else {
/* new areas: left */
- newa = screen_addarea(sc, sa->v1, sa->v2, sv2, sv1, sa->spacetype);
+ newa = screen_addarea(screen, area->v1, area->v2, sv2, sv1, area->spacetype);
/* area right */
- sa->v1 = sv1;
- sa->v2 = sv2;
+ area->v1 = sv1;
+ area->v2 = sv2;
}
- ED_area_data_copy(newa, sa, true);
+ ED_area_data_copy(newa, area, true);
}
/* remove double vertices en edges */
if (merge) {
- BKE_screen_remove_double_scrverts(sc);
+ BKE_screen_remove_double_scrverts(screen);
}
- BKE_screen_remove_double_scredges(sc);
- BKE_screen_remove_unused_scredges(sc);
+ BKE_screen_remove_double_scredges(screen);
+ BKE_screen_remove_unused_scredges(screen);
return newa;
}
@@ -204,34 +205,34 @@ ScrArea *area_split(const wmWindow *win, bScreen *sc, ScrArea *sa, char dir, flo
*/
bScreen *screen_add(Main *bmain, const char *name, const rcti *rect)
{
- bScreen *sc;
+ bScreen *screen;
ScrVert *sv1, *sv2, *sv3, *sv4;
- sc = BKE_libblock_alloc(bmain, ID_SCR, name, 0);
- sc->do_refresh = true;
- sc->redraws_flag = TIME_ALL_3D_WIN | TIME_ALL_ANIM_WIN;
+ screen = BKE_libblock_alloc(bmain, ID_SCR, name, 0);
+ screen->do_refresh = true;
+ screen->redraws_flag = TIME_ALL_3D_WIN | TIME_ALL_ANIM_WIN;
- sv1 = screen_geom_vertex_add(sc, rect->xmin, rect->ymin);
- sv2 = screen_geom_vertex_add(sc, rect->xmin, rect->ymax - 1);
- sv3 = screen_geom_vertex_add(sc, rect->xmax - 1, rect->ymax - 1);
- sv4 = screen_geom_vertex_add(sc, rect->xmax - 1, rect->ymin);
+ sv1 = screen_geom_vertex_add(screen, rect->xmin, rect->ymin);
+ sv2 = screen_geom_vertex_add(screen, rect->xmin, rect->ymax - 1);
+ sv3 = screen_geom_vertex_add(screen, rect->xmax - 1, rect->ymax - 1);
+ sv4 = screen_geom_vertex_add(screen, rect->xmax - 1, rect->ymin);
- screen_geom_edge_add(sc, sv1, sv2);
- screen_geom_edge_add(sc, sv2, sv3);
- screen_geom_edge_add(sc, sv3, sv4);
- screen_geom_edge_add(sc, sv4, sv1);
+ screen_geom_edge_add(screen, sv1, sv2);
+ screen_geom_edge_add(screen, sv2, sv3);
+ screen_geom_edge_add(screen, sv3, sv4);
+ screen_geom_edge_add(screen, sv4, sv1);
/* dummy type, no spacedata */
- screen_addarea(sc, sv1, sv2, sv3, sv4, SPACE_EMPTY);
+ screen_addarea(screen, sv1, sv2, sv3, sv4, SPACE_EMPTY);
- return sc;
+ return screen;
}
void screen_data_copy(bScreen *to, bScreen *from)
{
ScrVert *s1, *s2;
ScrEdge *se;
- ScrArea *sa, *saf;
+ ScrArea *area, *saf;
/* free contents of 'to', is from blenkernel screen.c */
BKE_screen_free(to);
@@ -255,18 +256,18 @@ void screen_data_copy(bScreen *to, bScreen *from)
}
saf = from->areabase.first;
- for (sa = to->areabase.first; sa; sa = sa->next, saf = saf->next) {
- sa->v1 = sa->v1->newv;
- sa->v2 = sa->v2->newv;
- sa->v3 = sa->v3->newv;
- sa->v4 = sa->v4->newv;
+ for (area = to->areabase.first; area; area = area->next, saf = saf->next) {
+ area->v1 = area->v1->newv;
+ area->v2 = area->v2->newv;
+ area->v3 = area->v3->newv;
+ area->v4 = area->v4->newv;
- BLI_listbase_clear(&sa->spacedata);
- BLI_listbase_clear(&sa->regionbase);
- BLI_listbase_clear(&sa->actionzones);
- BLI_listbase_clear(&sa->handlers);
+ BLI_listbase_clear(&area->spacedata);
+ BLI_listbase_clear(&area->regionbase);
+ BLI_listbase_clear(&area->actionzones);
+ BLI_listbase_clear(&area->handlers);
- ED_area_data_copy(sa, saf, true);
+ ED_area_data_copy(area, saf, true);
}
/* put at zero (needed?) */
@@ -285,48 +286,47 @@ void screen_new_activate_prepare(const wmWindow *win, bScreen *screen_new)
screen_new->do_draw = true;
}
-/* with sa as center, sb is located at: 0=W, 1=N, 2=E, 3=S */
+/* with area as center, sb is located at: 0=W, 1=N, 2=E, 3=S */
/* -1 = not valid check */
/* used with join operator */
-int area_getorientation(ScrArea *sa, ScrArea *sb)
+int area_getorientation(ScrArea *area, ScrArea *sb)
{
- if (sa == NULL || sb == NULL) {
+ if (area == NULL || sb == NULL) {
return -1;
}
- ScrVert *saBL = sa->v1;
- ScrVert *saTL = sa->v2;
- ScrVert *saTR = sa->v3;
- ScrVert *saBR = sa->v4;
+ ScrVert *saBL = area->v1;
+ ScrVert *saTL = area->v2;
+ ScrVert *saTR = area->v3;
+ ScrVert *saBR = area->v4;
ScrVert *sbBL = sb->v1;
ScrVert *sbTL = sb->v2;
ScrVert *sbTR = sb->v3;
ScrVert *sbBR = sb->v4;
- int tolerance = U.pixelsize * 4;
-
- if (saBL->vec.x == sbBR->vec.x && saTL->vec.x == sbTR->vec.x) { /* sa to right of sb = W */
- if ((abs(saBL->vec.y - sbBR->vec.y) <= tolerance) &&
- (abs(saTL->vec.y - sbTR->vec.y) <= tolerance)) {
+ if (saBL->vec.x == sbBR->vec.x && saTL->vec.x == sbTR->vec.x) { /* area to right of sb = W */
+ if ((abs(saBL->vec.y - sbBR->vec.y) <= AREAJOINTOLERANCE) &&
+ (abs(saTL->vec.y - sbTR->vec.y) <= AREAJOINTOLERANCE)) {
return 0;
}
}
- else if (saTL->vec.y == sbBL->vec.y && saTR->vec.y == sbBR->vec.y) { /* sa to bottom of sb = N */
- if ((abs(saTL->vec.x - sbBL->vec.x) <= tolerance) &&
- (abs(saTR->vec.x - sbBR->vec.x) <= tolerance)) {
+ else if (saTL->vec.y == sbBL->vec.y &&
+ saTR->vec.y == sbBR->vec.y) { /* area to bottom of sb = N */
+ if ((abs(saTL->vec.x - sbBL->vec.x) <= AREAJOINTOLERANCE) &&
+ (abs(saTR->vec.x - sbBR->vec.x) <= AREAJOINTOLERANCE)) {
return 1;
}
}
- else if (saTR->vec.x == sbTL->vec.x && saBR->vec.x == sbBL->vec.x) { /* sa to left of sb = E */
- if ((abs(saTR->vec.y - sbTL->vec.y) <= tolerance) &&
- (abs(saBR->vec.y - sbBL->vec.y) <= tolerance)) {
+ else if (saTR->vec.x == sbTL->vec.x && saBR->vec.x == sbBL->vec.x) { /* area to left of sb = E */
+ if ((abs(saTR->vec.y - sbTL->vec.y) <= AREAJOINTOLERANCE) &&
+ (abs(saBR->vec.y - sbBL->vec.y) <= AREAJOINTOLERANCE)) {
return 2;
}
}
- else if (saBL->vec.y == sbTL->vec.y && saBR->vec.y == sbTR->vec.y) { /* sa on top of sb = S*/
- if ((abs(saBL->vec.x - sbTL->vec.x) <= tolerance) &&
- (abs(saBR->vec.x - sbTR->vec.x) <= tolerance)) {
+ else if (saBL->vec.y == sbTL->vec.y && saBR->vec.y == sbTR->vec.y) { /* area on top of sb = S*/
+ if ((abs(saBL->vec.x - sbTL->vec.x) <= AREAJOINTOLERANCE) &&
+ (abs(saBR->vec.x - sbTR->vec.x) <= AREAJOINTOLERANCE)) {
return 3;
}
}
@@ -334,10 +334,73 @@ int area_getorientation(ScrArea *sa, ScrArea *sb)
return -1;
}
+/* Screen verts with horizontal position equal to from_x are moved to to_x. */
+static void screen_verts_halign(const wmWindow *win,
+ const bScreen *screen,
+ const short from_x,
+ const short to_x)
+{
+ ED_screen_verts_iter(win, screen, v1)
+ {
+ if (v1->vec.x == from_x) {
+ v1->vec.x = to_x;
+ }
+ }
+}
+
+/* Screen verts with vertical position equal to from_y are moved to to_y. */
+static void screen_verts_valign(const wmWindow *win,
+ const bScreen *screen,
+ const short from_y,
+ const short to_y)
+{
+ ED_screen_verts_iter(win, screen, v1)
+ {
+ if (v1->vec.y == from_y) {
+ v1->vec.y = to_y;
+ }
+ }
+}
+
+/* Adjust all screen edges to allow joining two areas. 'dir' value is like area_getorientation().
+ */
+static void screen_areas_align(
+ bContext *C, bScreen *screen, ScrArea *sa1, ScrArea *sa2, const int dir)
+{
+ wmWindow *win = CTX_wm_window(C);
+
+ if (dir == 0 || dir == 2) {
+ /* horizontal join, use average for new top and bottom. */
+ int top = (sa1->v2->vec.y + sa2->v2->vec.y) / 2;
+ int bottom = (sa1->v4->vec.y + sa2->v4->vec.y) / 2;
+
+ /* Move edges exactly matching source top and bottom. */
+ screen_verts_valign(win, screen, sa1->v2->vec.y, top);
+ screen_verts_valign(win, screen, sa1->v4->vec.y, bottom);
+
+ /* Move edges exactly matching target top and bottom. */
+ screen_verts_valign(win, screen, sa2->v2->vec.y, top);
+ screen_verts_valign(win, screen, sa2->v4->vec.y, bottom);
+ }
+ else {
+ /* Vertical join, use averages for new left and right. */
+ int left = (sa1->v1->vec.x + sa2->v1->vec.x) / 2;
+ int right = (sa1->v3->vec.x + sa2->v3->vec.x) / 2;
+
+ /* Move edges exactly matching source left and right. */
+ screen_verts_halign(win, screen, sa1->v1->vec.x, left);
+ screen_verts_halign(win, screen, sa1->v3->vec.x, right);
+
+ /* Move edges exactly matching target left and right */
+ screen_verts_halign(win, screen, sa2->v1->vec.x, left);
+ screen_verts_halign(win, screen, sa2->v3->vec.x, right);
+ }
+}
+
/* Helper function to join 2 areas, it has a return value, 0=failed 1=success
* used by the split, join operators
*/
-int screen_area_join(bContext *C, bScreen *scr, ScrArea *sa1, ScrArea *sa2)
+int screen_area_join(bContext *C, bScreen *screen, ScrArea *sa1, ScrArea *sa2)
{
int dir = area_getorientation(sa1, sa2);
@@ -346,51 +409,37 @@ int screen_area_join(bContext *C, bScreen *scr, ScrArea *sa1, ScrArea *sa2)
}
/* Align areas if they are not. Do sanity checking before getting here. */
-
- if (dir == 0 || dir == 2) {
- /* horizontal join, so vertically align source vert to target */
- sa2->v1->vec.y = sa1->v1->vec.y; /* vertical align sa1 BL */
- sa2->v2->vec.y = sa1->v2->vec.y; /* vertical align sa1 TL */
- sa2->v3->vec.y = sa1->v3->vec.y; /* vertical align sa1 TR */
- sa2->v4->vec.y = sa1->v4->vec.y; /* vertical align sa1 BR */
- }
- else {
- /* vertical join, so horizontally align source verts to target */
- sa2->v1->vec.x = sa1->v1->vec.x; /* vertical align sa1 BL */
- sa2->v2->vec.x = sa1->v2->vec.x; /* vertical align sa1 TL */
- sa2->v3->vec.x = sa1->v3->vec.x; /* vertical align sa1 TR */
- sa2->v4->vec.x = sa1->v4->vec.x; /* vertical align sa1 BR */
- }
+ screen_areas_align(C, screen, sa1, sa2, dir);
if (dir == 0) { /* sa1 to right of sa2 = W */
sa1->v1 = sa2->v1; /* BL */
sa1->v2 = sa2->v2; /* TL */
- screen_geom_edge_add(scr, sa1->v2, sa1->v3);
- screen_geom_edge_add(scr, sa1->v1, sa1->v4);
+ screen_geom_edge_add(screen, sa1->v2, sa1->v3);
+ screen_geom_edge_add(screen, sa1->v1, sa1->v4);
}
else if (dir == 1) { /* sa1 to bottom of sa2 = N */
sa1->v2 = sa2->v2; /* TL */
sa1->v3 = sa2->v3; /* TR */
- screen_geom_edge_add(scr, sa1->v1, sa1->v2);
- screen_geom_edge_add(scr, sa1->v3, sa1->v4);
+ screen_geom_edge_add(screen, sa1->v1, sa1->v2);
+ screen_geom_edge_add(screen, sa1->v3, sa1->v4);
}
else if (dir == 2) { /* sa1 to left of sa2 = E */
sa1->v3 = sa2->v3; /* TR */
sa1->v4 = sa2->v4; /* BR */
- screen_geom_edge_add(scr, sa1->v2, sa1->v3);
- screen_geom_edge_add(scr, sa1->v1, sa1->v4);
+ screen_geom_edge_add(screen, sa1->v2, sa1->v3);
+ screen_geom_edge_add(screen, sa1->v1, sa1->v4);
}
else if (dir == 3) { /* sa1 on top of sa2 = S */
sa1->v1 = sa2->v1; /* BL */
sa1->v4 = sa2->v4; /* BR */
- screen_geom_edge_add(scr, sa1->v1, sa1->v2);
- screen_geom_edge_add(scr, sa1->v3, sa1->v4);
+ screen_geom_edge_add(screen, sa1->v1, sa1->v2);
+ screen_geom_edge_add(screen, sa1->v3, sa1->v4);
}
- screen_delarea(C, scr, sa2);
- BKE_screen_remove_double_scrverts(scr);
+ screen_delarea(C, screen, sa2);
+ BKE_screen_remove_double_scrverts(screen);
/* Update preview thumbnail */
- BKE_icon_changed(scr->id.icon_id);
+ BKE_icon_changed(screen->id.icon_id);
return 1;
}
@@ -398,12 +447,12 @@ int screen_area_join(bContext *C, bScreen *scr, ScrArea *sa1, ScrArea *sa2)
/* ****************** EXPORTED API TO OTHER MODULES *************************** */
/* screen sets cursor based on active region */
-static void region_cursor_set_ex(wmWindow *win, ScrArea *sa, ARegion *region, bool swin_changed)
+static void region_cursor_set_ex(wmWindow *win, ScrArea *area, ARegion *region, bool swin_changed)
{
BLI_assert(WM_window_get_active_screen(win)->active_region == region);
if (win->tag_cursor_refresh || swin_changed || (region->type && region->type->event_cursor)) {
win->tag_cursor_refresh = false;
- ED_region_cursor_set(win, sa, region);
+ ED_region_cursor_set(win, area, region);
}
}
@@ -411,11 +460,10 @@ static void region_cursor_set(wmWindow *win, bool swin_changed)
{
bScreen *screen = WM_window_get_active_screen(win);
- ED_screen_areas_iter(win, screen, sa)
- {
- for (ARegion *region = sa->regionbase.first; region; region = region->next) {
+ ED_screen_areas_iter (win, screen, area) {
+ LISTBASE_FOREACH (ARegion *, region, &area->regionbase) {
if (region == screen->active_region) {
- region_cursor_set_ex(win, sa, region, swin_changed);
+ region_cursor_set_ex(win, area, region, swin_changed);
return;
}
}
@@ -465,8 +513,7 @@ void ED_screen_refresh(wmWindowManager *wm, wmWindow *win)
screen_geom_vertices_scale(win, screen);
- ED_screen_areas_iter(win, screen, area)
- {
+ ED_screen_areas_iter (win, screen, area) {
/* set spacetype and region callbacks, calls init() */
/* sets subwindows for regions, adds handlers */
ED_area_initialize(wm, win, area);
@@ -522,11 +569,11 @@ void ED_screen_ensure_updated(wmWindowManager *wm, wmWindow *win, bScreen *scree
* Utility to exit and free an area-region. Screen level regions (menus/popups) need to be treated
* slightly differently, see #ui_region_temp_remove().
*/
-void ED_region_remove(bContext *C, ScrArea *sa, ARegion *region)
+void ED_region_remove(bContext *C, ScrArea *area, ARegion *region)
{
ED_region_exit(C, region);
- BKE_area_region_free(sa->type, region);
- BLI_freelinkN(&sa->regionbase, region);
+ BKE_area_region_free(area->type, region);
+ BLI_freelinkN(&area->regionbase, region);
}
/* *********** exit calls are for closing running stuff ******** */
@@ -545,7 +592,7 @@ void ED_region_exit(bContext *C, ARegion *region)
WM_event_remove_handlers(C, &region->handlers);
WM_event_modal_handler_region_replace(win, region, NULL);
- WM_draw_region_free(region);
+ WM_draw_region_free(region, true);
if (region->headerstr) {
MEM_freeN(region->headerstr);
@@ -562,25 +609,25 @@ void ED_region_exit(bContext *C, ARegion *region)
CTX_wm_region_set(C, prevar);
}
-void ED_area_exit(bContext *C, ScrArea *sa)
+void ED_area_exit(bContext *C, ScrArea *area)
{
wmWindowManager *wm = CTX_wm_manager(C);
wmWindow *win = CTX_wm_window(C);
ScrArea *prevsa = CTX_wm_area(C);
ARegion *region;
- if (sa->type && sa->type->exit) {
- sa->type->exit(wm, sa);
+ if (area->type && area->type->exit) {
+ area->type->exit(wm, area);
}
- CTX_wm_area_set(C, sa);
+ CTX_wm_area_set(C, area);
- for (region = sa->regionbase.first; region; region = region->next) {
+ for (region = area->regionbase.first; region; region = region->next) {
ED_region_exit(C, region);
}
- WM_event_remove_handlers(C, &sa->handlers);
- WM_event_modal_handler_area_replace(win, sa, NULL);
+ WM_event_remove_handlers(C, &area->handlers);
+ WM_event_modal_handler_area_replace(win, area, NULL);
CTX_wm_area_set(C, prevsa);
}
@@ -605,15 +652,15 @@ void ED_screen_exit(bContext *C, wmWindow *window, bScreen *screen)
screen->active_region = NULL;
- for (ARegion *region = screen->regionbase.first; region; region = region->next) {
+ LISTBASE_FOREACH (ARegion *, region, &screen->regionbase) {
ED_region_exit(C, region);
}
- for (ScrArea *sa = screen->areabase.first; sa; sa = sa->next) {
- ED_area_exit(C, sa);
+ LISTBASE_FOREACH (ScrArea *, area, &screen->areabase) {
+ ED_area_exit(C, area);
}
/* Don't use ED_screen_areas_iter here, it skips hidden areas. */
- for (ScrArea *sa = window->global_areas.areabase.first; sa; sa = sa->next) {
- ED_area_exit(C, sa);
+ LISTBASE_FOREACH (ScrArea *, area, &window->global_areas.areabase) {
+ ED_area_exit(C, area);
}
/* mark it available for use for other windows */
@@ -636,15 +683,15 @@ static void screen_cursor_set(wmWindow *win, const int xy[2])
{
const bScreen *screen = WM_window_get_active_screen(win);
AZone *az = NULL;
- ScrArea *sa;
+ ScrArea *area;
- for (sa = screen->areabase.first; sa; sa = sa->next) {
- if ((az = ED_area_actionzone_find_xy(sa, xy))) {
+ for (area = screen->areabase.first; area; area = area->next) {
+ if ((az = ED_area_actionzone_find_xy(area, xy))) {
break;
}
}
- if (sa) {
+ if (area) {
if (az->type == AZONE_AREA) {
WM_cursor_set(win, WM_CURSOR_EDIT);
}
@@ -680,63 +727,63 @@ static void screen_cursor_set(wmWindow *win, const int xy[2])
*/
void ED_screen_set_active_region(bContext *C, wmWindow *win, const int xy[2])
{
- bScreen *scr = WM_window_get_active_screen(win);
- if (scr == NULL) {
+ bScreen *screen = WM_window_get_active_screen(win);
+ if (screen == NULL) {
return;
}
- ScrArea *sa = NULL;
+ ScrArea *area = NULL;
ARegion *region;
- ARegion *ar_prev = scr->active_region;
+ ARegion *region_prev = screen->active_region;
- ED_screen_areas_iter(win, scr, area_iter)
- {
- if (xy[0] > area_iter->totrct.xmin && xy[0] < area_iter->totrct.xmax) {
- if (xy[1] > area_iter->totrct.ymin && xy[1] < area_iter->totrct.ymax) {
+ ED_screen_areas_iter (win, screen, area_iter) {
+ if (xy[0] > (area_iter->totrct.xmin + BORDERPADDING) &&
+ xy[0] < (area_iter->totrct.xmax - BORDERPADDING)) {
+ if (xy[1] > (area_iter->totrct.ymin + BORDERPADDING) &&
+ xy[1] < (area_iter->totrct.ymax - BORDERPADDING)) {
if (ED_area_azones_update(area_iter, xy) == NULL) {
- sa = area_iter;
+ area = area_iter;
break;
}
}
}
}
- if (sa) {
+ if (area) {
/* Make overlap active when mouse over. */
- for (region = sa->regionbase.first; region; region = region->next) {
+ for (region = area->regionbase.first; region; region = region->next) {
if (ED_region_contains_xy(region, xy)) {
- scr->active_region = region;
+ screen->active_region = region;
break;
}
}
}
else {
- scr->active_region = NULL;
+ screen->active_region = NULL;
}
/* Check for redraw headers. */
- if (ar_prev != scr->active_region) {
+ if (region_prev != screen->active_region) {
- ED_screen_areas_iter(win, scr, area_iter)
- {
+ ED_screen_areas_iter (win, screen, area_iter) {
bool do_draw = false;
for (region = area_iter->regionbase.first; region; region = region->next) {
/* Call old area's deactivate if assigned. */
- if (region == ar_prev && area_iter->type->deactivate) {
+ if (region == region_prev && area_iter->type->deactivate) {
area_iter->type->deactivate(area_iter);
}
- if (region == ar_prev && region != scr->active_region) {
- wmGizmoMap *gzmap = ar_prev->gizmo_map;
+ if (region == region_prev && region != screen->active_region) {
+ wmGizmoMap *gzmap = region_prev->gizmo_map;
if (gzmap) {
if (WM_gizmo_highlight_set(gzmap, NULL)) {
- ED_region_tag_redraw_no_rebuild(ar_prev);
+ ED_region_tag_redraw_no_rebuild(region_prev);
}
}
}
- if (region == ar_prev || region == scr->active_region) {
+ if (region == region_prev || region == screen->active_region) {
do_draw = true;
}
}
@@ -753,19 +800,19 @@ void ED_screen_set_active_region(bContext *C, wmWindow *win, const int xy[2])
/* Cursors, for time being set always on edges,
* otherwise the active region doesn't switch. */
- if (scr->active_region == NULL) {
+ if (screen->active_region == NULL) {
screen_cursor_set(win, xy);
}
else {
/* Notifier invokes freeing the buttons... causing a bit too much redraws. */
- region_cursor_set_ex(win, sa, scr->active_region, ar_prev != scr->active_region);
+ region_cursor_set_ex(win, area, screen->active_region, region_prev != screen->active_region);
- if (ar_prev != scr->active_region) {
+ if (region_prev != screen->active_region) {
/* This used to be a notifier, but needs to be done immediate
* because it can undo setting the right button as active due
* to delayed notifier handling. */
if (C) {
- UI_screen_free_active_but(C, scr);
+ UI_screen_free_active_but(C, screen);
}
}
}
@@ -774,19 +821,19 @@ void ED_screen_set_active_region(bContext *C, wmWindow *win, const int xy[2])
int ED_screen_area_active(const bContext *C)
{
wmWindow *win = CTX_wm_window(C);
- bScreen *sc = CTX_wm_screen(C);
- ScrArea *sa = CTX_wm_area(C);
+ bScreen *screen = CTX_wm_screen(C);
+ ScrArea *area = CTX_wm_area(C);
- if (win && sc && sa) {
- AZone *az = ED_area_actionzone_find_xy(sa, &win->eventstate->x);
+ if (win && screen && area) {
+ AZone *az = ED_area_actionzone_find_xy(area, &win->eventstate->x);
ARegion *region;
if (az && az->type == AZONE_REGION) {
return 1;
}
- for (region = sa->regionbase.first; region; region = region->next) {
- if (region == sc->active_region) {
+ for (region = area->regionbase.first; region; region = region->next) {
+ if (region == screen->active_region) {
return 1;
}
}
@@ -815,16 +862,16 @@ static ScrArea *screen_area_create_with_geometry(ScrAreaMap *area_map,
return screen_addarea_ex(area_map, bottom_left, top_left, top_right, bottom_right, spacetype);
}
-static void screen_area_set_geometry_rect(ScrArea *sa, const rcti *rect)
+static void screen_area_set_geometry_rect(ScrArea *area, const rcti *rect)
{
- sa->v1->vec.x = rect->xmin;
- sa->v1->vec.y = rect->ymin;
- sa->v2->vec.x = rect->xmin;
- sa->v2->vec.y = rect->ymax;
- sa->v3->vec.x = rect->xmax;
- sa->v3->vec.y = rect->ymax;
- sa->v4->vec.x = rect->xmax;
- sa->v4->vec.y = rect->ymin;
+ area->v1->vec.x = rect->xmin;
+ area->v1->vec.y = rect->ymin;
+ area->v2->vec.x = rect->xmin;
+ area->v2->vec.y = rect->ymax;
+ area->v3->vec.x = rect->xmax;
+ area->v3->vec.y = rect->ymax;
+ area->v4->vec.x = rect->xmax;
+ area->v4->vec.y = rect->ymin;
}
static void screen_global_area_refresh(wmWindow *win,
@@ -910,7 +957,7 @@ void ED_screen_global_areas_sync(wmWindow *win)
screen->flag &= ~SCREEN_COLLAPSE_STATUSBAR;
- for (ScrArea *area = win->global_areas.areabase.first; area; area = area->next) {
+ LISTBASE_FOREACH (ScrArea *, area, &win->global_areas.areabase) {
if (area->global->cur_fixed_height == area->global->size_min) {
if (area->spacetype == SPACE_STATUSBAR) {
screen->flag |= SCREEN_COLLAPSE_STATUSBAR;
@@ -943,8 +990,8 @@ static bScreen *screen_fullscreen_find_associated_normal_screen(const Main *bmai
for (bScreen *screen_iter = bmain->screens.first; screen_iter;
screen_iter = screen_iter->id.next) {
if ((screen_iter != screen) && ELEM(screen_iter->state, SCREENMAXIMIZED, SCREENFULL)) {
- ScrArea *sa = screen_iter->areabase.first;
- if (sa && sa->full == screen) {
+ ScrArea *area = screen_iter->areabase.first;
+ if (area && area->full == screen) {
return screen_iter;
}
}
@@ -976,8 +1023,8 @@ bScreen *screen_change_prepare(
wmTimer *wt = screen_old->animtimer;
/* remove handlers referencing areas in old screen */
- for (ScrArea *sa = screen_old->areabase.first; sa; sa = sa->next) {
- WM_event_remove_area_handler(&win->modalhandlers, sa);
+ LISTBASE_FOREACH (ScrArea *, area, &screen_old->areabase) {
+ WM_event_remove_area_handler(&win->modalhandlers, area);
}
/* we put timer to sleep, so screen_exit has to think there's no timer */
@@ -998,17 +1045,17 @@ bScreen *screen_change_prepare(
return NULL;
}
-void screen_change_update(bContext *C, wmWindow *win, bScreen *sc)
+void screen_change_update(bContext *C, wmWindow *win, bScreen *screen)
{
Scene *scene = WM_window_get_active_scene(win);
WorkSpace *workspace = BKE_workspace_active_get(win->workspace_hook);
- WorkSpaceLayout *layout = BKE_workspace_layout_find(workspace, sc);
+ WorkSpaceLayout *layout = BKE_workspace_layout_find(workspace, screen);
CTX_wm_window_set(C, win); /* stores C->wm.screen... hrmf */
ED_screen_refresh(CTX_wm_manager(C), win);
- BKE_screen_view3d_scene_sync(sc, scene); /* sync new screen with scene data */
+ BKE_screen_view3d_scene_sync(screen, scene); /* sync new screen with scene data */
WM_event_add_notifier(C, NC_WINDOW, NULL);
WM_event_add_notifier(C, NC_SCREEN | ND_LAYOUTSET, layout);
@@ -1024,16 +1071,16 @@ void screen_change_update(bContext *C, wmWindow *win, bScreen *sc)
* \warning Do NOT call in area/region queues!
* \returns if screen changing was successful.
*/
-bool ED_screen_change(bContext *C, bScreen *sc)
+bool ED_screen_change(bContext *C, bScreen *screen)
{
Main *bmain = CTX_data_main(C);
wmWindow *win = CTX_wm_window(C);
bScreen *screen_old = CTX_wm_screen(C);
- bScreen *screen_new = screen_change_prepare(screen_old, sc, bmain, C, win);
+ bScreen *screen_new = screen_change_prepare(screen_old, screen, bmain, C, win);
if (screen_new) {
WorkSpace *workspace = BKE_workspace_active_get(win->workspace_hook);
- WM_window_set_active_screen(win, workspace, sc);
+ WM_window_set_active_screen(win, workspace, screen);
screen_change_update(C, win, screen_new);
return true;
@@ -1042,21 +1089,24 @@ bool ED_screen_change(bContext *C, bScreen *sc)
return false;
}
-static void screen_set_3dview_camera(Scene *scene, ViewLayer *view_layer, ScrArea *sa, View3D *v3d)
+static void screen_set_3dview_camera(Scene *scene,
+ ViewLayer *view_layer,
+ ScrArea *area,
+ View3D *v3d)
{
/* fix any cameras that are used in the 3d view but not in the scene */
BKE_screen_view3d_sync(v3d, scene);
if (!v3d->camera || !BKE_view_layer_base_find(view_layer, v3d->camera)) {
v3d->camera = BKE_view_layer_camera_find(view_layer);
- // XXX if (sc == curscreen) handle_view3d_lock();
+ // XXX if (screen == curscreen) handle_view3d_lock();
if (!v3d->camera) {
ARegion *region;
ListBase *regionbase;
/* regionbase is in different place depending if space is active */
- if (v3d == sa->spacedata.first) {
- regionbase = &sa->regionbase;
+ if (v3d == area->spacedata.first) {
+ regionbase = &area->regionbase;
}
else {
regionbase = &v3d->regionbase;
@@ -1104,28 +1154,28 @@ void ED_screen_scene_change(bContext *C, wmWindow *win, Scene *scene)
/* Update 3D view cameras. */
const bScreen *screen = WM_window_get_active_screen(win);
- for (ScrArea *sa = screen->areabase.first; sa; sa = sa->next) {
- for (SpaceLink *sl = sa->spacedata.first; sl; sl = sl->next) {
+ LISTBASE_FOREACH (ScrArea *, area, &screen->areabase) {
+ LISTBASE_FOREACH (SpaceLink *, sl, &area->spacedata) {
if (sl->spacetype == SPACE_VIEW3D) {
View3D *v3d = (View3D *)sl;
- screen_set_3dview_camera(scene, view_layer, sa, v3d);
+ screen_set_3dview_camera(scene, view_layer, area, v3d);
}
}
}
}
-ScrArea *ED_screen_full_newspace(bContext *C, ScrArea *sa, int type)
+ScrArea *ED_screen_full_newspace(bContext *C, ScrArea *area, int type)
{
wmWindow *win = CTX_wm_window(C);
ScrArea *newsa = NULL;
SpaceLink *newsl;
- if (!sa || sa->full == NULL) {
- newsa = ED_screen_state_toggle(C, win, sa, SCREENMAXIMIZED);
+ if (!area || area->full == NULL) {
+ newsa = ED_screen_state_toggle(C, win, area, SCREENMAXIMIZED);
}
if (!newsa) {
- newsa = sa;
+ newsa = area;
}
BLI_assert(newsa);
@@ -1144,40 +1194,40 @@ ScrArea *ED_screen_full_newspace(bContext *C, ScrArea *sa, int type)
/**
* \a was_prev_temp for the case previous space was a temporary fullscreen as well
*/
-void ED_screen_full_prevspace(bContext *C, ScrArea *sa)
+void ED_screen_full_prevspace(bContext *C, ScrArea *area)
{
- BLI_assert(sa->full);
+ BLI_assert(area->full);
- if (sa->flag & AREA_FLAG_STACKED_FULLSCREEN) {
+ if (area->flag & AREA_FLAG_STACKED_FULLSCREEN) {
/* stacked fullscreen -> only go back to previous area and don't toggle out of fullscreen */
- ED_area_prevspace(C, sa);
+ ED_area_prevspace(C, area);
}
else {
- ED_screen_restore_temp_type(C, sa);
+ ED_screen_restore_temp_type(C, area);
}
}
-void ED_screen_restore_temp_type(bContext *C, ScrArea *sa)
+void ED_screen_restore_temp_type(bContext *C, ScrArea *area)
{
- SpaceLink *sl = sa->spacedata.first;
+ SpaceLink *sl = area->spacedata.first;
/* In case nether functions below run. */
- ED_area_tag_redraw(sa);
+ ED_area_tag_redraw(area);
if (sl->link_flag & SPACE_FLAG_TYPE_TEMPORARY) {
- ED_area_prevspace(C, sa);
+ ED_area_prevspace(C, area);
}
- if (sa->full) {
- ED_screen_state_toggle(C, CTX_wm_window(C), sa, SCREENMAXIMIZED);
+ if (area->full) {
+ ED_screen_state_toggle(C, CTX_wm_window(C), area, SCREENMAXIMIZED);
}
}
/* restore a screen / area back to default operation, after temp fullscreen modes */
-void ED_screen_full_restore(bContext *C, ScrArea *sa)
+void ED_screen_full_restore(bContext *C, ScrArea *area)
{
wmWindow *win = CTX_wm_window(C);
- SpaceLink *sl = sa->spacedata.first;
+ SpaceLink *sl = area->spacedata.first;
bScreen *screen = CTX_wm_screen(C);
short state = (screen ? screen->state : SCREENMAXIMIZED);
@@ -1186,37 +1236,37 @@ void ED_screen_full_restore(bContext *C, ScrArea *sa)
if (sl->next) {
if (sl->link_flag & SPACE_FLAG_TYPE_TEMPORARY) {
- ED_screen_full_prevspace(C, sa);
+ ED_screen_full_prevspace(C, area);
}
else {
- ED_screen_state_toggle(C, win, sa, state);
+ ED_screen_state_toggle(C, win, area, state);
}
- /* warning: 'sa' may be freed */
+ /* warning: 'area' may be freed */
}
/* otherwise just tile the area again */
else {
- ED_screen_state_toggle(C, win, sa, state);
+ ED_screen_state_toggle(C, win, area, state);
}
}
/**
* this function toggles: if area is maximized/full then the parent will be restored
*
- * \warning \a sa may be freed.
+ * \warning \a area may be freed.
*/
-ScrArea *ED_screen_state_toggle(bContext *C, wmWindow *win, ScrArea *sa, const short state)
+ScrArea *ED_screen_state_toggle(bContext *C, wmWindow *win, ScrArea *area, const short state)
{
Main *bmain = CTX_data_main(C);
wmWindowManager *wm = CTX_wm_manager(C);
WorkSpace *workspace = WM_window_get_active_workspace(win);
- bScreen *sc, *oldscreen;
+ bScreen *screen, *oldscreen;
ARegion *region;
- if (sa) {
+ if (area) {
/* ensure we don't have a button active anymore, can crash when
* switching screens with tooltip open because region and tooltip
* are no longer in the same screen */
- for (region = sa->regionbase.first; region; region = region->next) {
+ for (region = area->regionbase.first; region; region = region->next) {
UI_blocklist_free(C, &region->uiblocks);
if (region->regiontimer) {
@@ -1226,25 +1276,25 @@ ScrArea *ED_screen_state_toggle(bContext *C, wmWindow *win, ScrArea *sa, const s
}
/* prevent hanging status prints */
- ED_area_status_text(sa, NULL);
+ ED_area_status_text(area, NULL);
ED_workspace_status_text(C, NULL);
}
- if (sa && sa->full) {
+ if (area && area->full) {
WorkSpaceLayout *layout_old = WM_window_get_active_layout(win);
/* restoring back to SCREENNORMAL */
- sc = sa->full; /* the old screen to restore */
+ screen = area->full; /* the old screen to restore */
oldscreen = WM_window_get_active_screen(win); /* the one disappearing */
- BLI_assert(BKE_workspace_layout_screen_get(layout_old) != sc);
+ BLI_assert(BKE_workspace_layout_screen_get(layout_old) != screen);
BLI_assert(BKE_workspace_layout_screen_get(layout_old)->state != SCREENNORMAL);
- sc->state = SCREENNORMAL;
- sc->flag = oldscreen->flag;
+ screen->state = SCREENNORMAL;
+ screen->flag = oldscreen->flag;
/* find old area to restore from */
ScrArea *fullsa = NULL;
- for (ScrArea *old = sc->areabase.first; old; old = old->next) {
+ LISTBASE_FOREACH (ScrArea *, old, &screen->areabase) {
/* area to restore from is always first */
if (old->full && !fullsa) {
fullsa = old;
@@ -1254,7 +1304,7 @@ ScrArea *ED_screen_state_toggle(bContext *C, wmWindow *win, ScrArea *sa, const s
old->full = NULL;
}
- sa->full = NULL;
+ area->full = NULL;
if (fullsa == NULL) {
if (G.debug & G_DEBUG) {
@@ -1265,23 +1315,22 @@ ScrArea *ED_screen_state_toggle(bContext *C, wmWindow *win, ScrArea *sa, const s
if (state == SCREENFULL) {
/* unhide global areas */
- for (ScrArea *glob_area = win->global_areas.areabase.first; glob_area;
- glob_area = glob_area->next) {
+ LISTBASE_FOREACH (ScrArea *, glob_area, &win->global_areas.areabase) {
glob_area->global->flag &= ~GLOBAL_AREA_IS_HIDDEN;
}
/* restore the old side panels/header visibility */
- for (region = sa->regionbase.first; region; region = region->next) {
+ for (region = area->regionbase.first; region; region = region->next) {
region->flag = region->flagfullscreen;
}
}
- ED_area_data_swap(fullsa, sa);
+ ED_area_data_swap(fullsa, area);
/* animtimer back */
- sc->animtimer = oldscreen->animtimer;
+ screen->animtimer = oldscreen->animtimer;
oldscreen->animtimer = NULL;
- ED_screen_change(C, sc);
+ ED_screen_change(C, screen);
BKE_workspace_layout_remove(CTX_data_main(C), workspace, layout_old);
@@ -1289,7 +1338,7 @@ ScrArea *ED_screen_state_toggle(bContext *C, wmWindow *win, ScrArea *sa, const s
* screen handling as it uses the area coords which aren't updated yet.
* Without doing so, the screen handling gets wrong area coords,
* which in worst case can lead to crashes (see T43139) */
- sc->skip_handling = true;
+ screen->skip_handling = true;
}
else {
/* change from SCREENNORMAL to new state */
@@ -1306,32 +1355,31 @@ ScrArea *ED_screen_state_toggle(bContext *C, wmWindow *win, ScrArea *sa, const s
layout_new = ED_workspace_layout_add(bmain, workspace, win, newname);
- sc = BKE_workspace_layout_screen_get(layout_new);
- sc->state = state;
- sc->redraws_flag = oldscreen->redraws_flag;
- sc->temp = oldscreen->temp;
- sc->flag = oldscreen->flag;
+ screen = BKE_workspace_layout_screen_get(layout_new);
+ screen->state = state;
+ screen->redraws_flag = oldscreen->redraws_flag;
+ screen->temp = oldscreen->temp;
+ screen->flag = oldscreen->flag;
/* timer */
- sc->animtimer = oldscreen->animtimer;
+ screen->animtimer = oldscreen->animtimer;
oldscreen->animtimer = NULL;
/* use random area when we have no active one, e.g. when the
* mouse is outside of the window and we open a file browser */
- if (!sa || sa->global) {
- sa = oldscreen->areabase.first;
+ if (!area || area->global) {
+ area = oldscreen->areabase.first;
}
- newa = (ScrArea *)sc->areabase.first;
+ newa = (ScrArea *)screen->areabase.first;
/* copy area */
- ED_area_data_swap(newa, sa);
- newa->flag = sa->flag; /* mostly for AREA_FLAG_WASFULLSCREEN */
+ ED_area_data_swap(newa, area);
+ newa->flag = area->flag; /* mostly for AREA_FLAG_WASFULLSCREEN */
if (state == SCREENFULL) {
/* temporarily hide global areas */
- for (ScrArea *glob_area = win->global_areas.areabase.first; glob_area;
- glob_area = glob_area->next) {
+ LISTBASE_FOREACH (ScrArea *, glob_area, &win->global_areas.areabase) {
glob_area->global->flag |= GLOBAL_AREA_IS_HIDDEN;
}
/* temporarily hide the side panels/header */
@@ -1351,16 +1399,16 @@ ScrArea *ED_screen_state_toggle(bContext *C, wmWindow *win, ScrArea *sa, const s
}
}
- sa->full = oldscreen;
+ area->full = oldscreen;
newa->full = oldscreen;
- ED_screen_change(C, sc);
+ ED_screen_change(C, screen);
}
/* XXX bad code: setscreen() ends with first area active. fullscreen render assumes this too */
- CTX_wm_area_set(C, sc->areabase.first);
+ CTX_wm_area_set(C, screen->areabase.first);
- return sc->areabase.first;
+ return screen->areabase.first;
}
/**
@@ -1381,35 +1429,35 @@ ScrArea *ED_screen_temp_space_open(bContext *C,
int display_type,
bool dialog)
{
- ScrArea *sa = NULL;
+ ScrArea *area = NULL;
switch (display_type) {
case USER_TEMP_SPACE_DISPLAY_WINDOW:
if (WM_window_open_temp(C, title, x, y, sizex, sizey, (int)space_type, dialog)) {
- sa = CTX_wm_area(C);
+ area = CTX_wm_area(C);
}
break;
case USER_TEMP_SPACE_DISPLAY_FULLSCREEN: {
- ScrArea *ctx_sa = CTX_wm_area(C);
+ ScrArea *ctx_area = CTX_wm_area(C);
- if (ctx_sa != NULL && ctx_sa->full) {
- sa = ctx_sa;
- ED_area_newspace(C, ctx_sa, space_type, true);
- sa->flag |= AREA_FLAG_STACKED_FULLSCREEN;
- ((SpaceLink *)sa->spacedata.first)->link_flag |= SPACE_FLAG_TYPE_TEMPORARY;
+ if (ctx_area != NULL && ctx_area->full) {
+ area = ctx_area;
+ ED_area_newspace(C, ctx_area, space_type, true);
+ area->flag |= AREA_FLAG_STACKED_FULLSCREEN;
+ ((SpaceLink *)area->spacedata.first)->link_flag |= SPACE_FLAG_TYPE_TEMPORARY;
}
- else if (ctx_sa != NULL && ctx_sa->spacetype == space_type) {
- sa = ED_screen_state_toggle(C, CTX_wm_window(C), ctx_sa, SCREENMAXIMIZED);
+ else if (ctx_area != NULL && ctx_area->spacetype == space_type) {
+ area = ED_screen_state_toggle(C, CTX_wm_window(C), ctx_area, SCREENMAXIMIZED);
}
else {
- sa = ED_screen_full_newspace(C, ctx_sa, (int)space_type);
- ((SpaceLink *)sa->spacedata.first)->link_flag |= SPACE_FLAG_TYPE_TEMPORARY;
+ area = ED_screen_full_newspace(C, ctx_area, (int)space_type);
+ ((SpaceLink *)area->spacedata.first)->link_flag |= SPACE_FLAG_TYPE_TEMPORARY;
}
break;
}
}
- return sa;
+ return area;
}
/* update frame rate info for viewport drawing */
@@ -1487,12 +1535,12 @@ void ED_screen_animation_timer(bContext *C, int redraws, int sync, int enable)
sad->flag |= (enable < 0) ? ANIMPLAY_FLAG_REVERSE : 0;
sad->flag |= (sync == 0) ? ANIMPLAY_FLAG_NO_SYNC : (sync == 1) ? ANIMPLAY_FLAG_SYNC : 0;
- ScrArea *sa = CTX_wm_area(C);
+ ScrArea *area = CTX_wm_area(C);
char spacetype = -1;
- if (sa) {
- spacetype = sa->spacetype;
+ if (area) {
+ spacetype = area->spacetype;
}
sad->from_anim_edit = (ELEM(spacetype, SPACE_GRAPH, SPACE_ACTION, SPACE_NLA));
@@ -1508,13 +1556,13 @@ void ED_screen_animation_timer(bContext *C, int redraws, int sync, int enable)
static ARegion *time_top_left_3dwindow(bScreen *screen)
{
ARegion *aret = NULL;
- ScrArea *sa;
+ ScrArea *area;
int min = 10000;
- for (sa = screen->areabase.first; sa; sa = sa->next) {
- if (sa->spacetype == SPACE_VIEW3D) {
+ for (area = screen->areabase.first; area; area = area->next) {
+ if (area->spacetype == SPACE_VIEW3D) {
ARegion *region;
- for (region = sa->regionbase.first; region; region = region->next) {
+ for (region = area->regionbase.first; region; region = region->next) {
if (region->regiontype == RGN_TYPE_WINDOW) {
if (region->winrct.xmin - region->winrct.ymin < min) {
aret = region;
@@ -1552,11 +1600,11 @@ void ED_update_for_newframe(Main *bmain, Depsgraph *depsgraph)
#ifdef DURIAN_CAMERA_SWITCH
void *camera = BKE_scene_camera_switch_find(scene);
if (camera && scene->camera != camera) {
- bScreen *sc;
+ bScreen *screen;
scene->camera = camera;
/* are there cameras in the views that are not in the scene? */
- for (sc = bmain->screens.first; sc; sc = sc->id.next) {
- BKE_screen_view3d_scene_sync(sc, scene);
+ for (screen = bmain->screens.first; screen; screen = screen->id.next) {
+ BKE_screen_view3d_scene_sync(screen, scene);
}
DEG_id_tag_update(&scene->id, ID_RECALC_COPY_ON_WRITE);
}
@@ -1573,11 +1621,11 @@ void ED_update_for_newframe(Main *bmain, Depsgraph *depsgraph)
*/
bool ED_screen_stereo3d_required(const bScreen *screen, const Scene *scene)
{
- ScrArea *sa;
+ ScrArea *area;
const bool is_multiview = (scene->r.scemode & R_MULTIVIEW) != 0;
- for (sa = screen->areabase.first; sa; sa = sa->next) {
- switch (sa->spacetype) {
+ for (area = screen->areabase.first; area; area = area->next) {
+ switch (area->spacetype) {
case SPACE_VIEW3D: {
View3D *v3d;
@@ -1585,10 +1633,10 @@ bool ED_screen_stereo3d_required(const bScreen *screen, const Scene *scene)
continue;
}
- v3d = sa->spacedata.first;
+ v3d = area->spacedata.first;
if (v3d->camera && v3d->stereo3d_camera == STEREO_3D_ID) {
ARegion *region;
- for (region = sa->regionbase.first; region; region = region->next) {
+ for (region = area->regionbase.first; region; region = region->next) {
if (region->regiondata && region->regiontype == RGN_TYPE_WINDOW) {
RegionView3D *rv3d = region->regiondata;
if (rv3d->persp == RV3D_CAMOB) {
@@ -1604,7 +1652,7 @@ bool ED_screen_stereo3d_required(const bScreen *screen, const Scene *scene)
/* images should always show in stereo, even if
* the file doesn't have views enabled */
- sima = sa->spacedata.first;
+ sima = area->spacedata.first;
if (sima->image && BKE_image_is_stereo(sima->image) &&
(sima->iuser.flag & IMA_SHOW_STEREO)) {
return true;
@@ -1618,7 +1666,7 @@ bool ED_screen_stereo3d_required(const bScreen *screen, const Scene *scene)
continue;
}
- snode = sa->spacedata.first;
+ snode = area->spacedata.first;
if ((snode->flag & SNODE_BACKDRAW) && ED_node_is_compositor(snode)) {
return true;
}
@@ -1631,7 +1679,7 @@ bool ED_screen_stereo3d_required(const bScreen *screen, const Scene *scene)
continue;
}
- sseq = sa->spacedata.first;
+ sseq = area->spacedata.first;
if (ELEM(sseq->view, SEQ_VIEW_PREVIEW, SEQ_VIEW_SEQUENCE_PREVIEW)) {
return true;
}
@@ -1657,7 +1705,7 @@ Scene *ED_screen_scene_find_with_window(const bScreen *screen,
const wmWindowManager *wm,
struct wmWindow **r_window)
{
- for (wmWindow *win = wm->windows.first; win; win = win->next) {
+ LISTBASE_FOREACH (wmWindow *, win, &wm->windows) {
if (WM_window_get_active_screen(win) == screen) {
if (r_window) {
*r_window = win;
@@ -1675,16 +1723,16 @@ ScrArea *ED_screen_area_find_with_spacedata(const bScreen *screen,
const bool only_visible)
{
if (only_visible) {
- for (ScrArea *sa = screen->areabase.first; sa; sa = sa->next) {
- if (sa->spacedata.first == sl) {
- return sa;
+ LISTBASE_FOREACH (ScrArea *, area, &screen->areabase) {
+ if (area->spacedata.first == sl) {
+ return area;
}
}
}
else {
- for (ScrArea *sa = screen->areabase.first; sa; sa = sa->next) {
- if (BLI_findindex(&sa->spacedata, sl) != -1) {
- return sa;
+ LISTBASE_FOREACH (ScrArea *, area, &screen->areabase) {
+ if (BLI_findindex(&area->spacedata, sl) != -1) {
+ return area;
}
}
}
@@ -1698,7 +1746,7 @@ Scene *ED_screen_scene_find(const bScreen *screen, const wmWindowManager *wm)
wmWindow *ED_screen_window_find(const bScreen *screen, const wmWindowManager *wm)
{
- for (wmWindow *win = wm->windows.first; win; win = win->next) {
+ LISTBASE_FOREACH (wmWindow *, win, &wm->windows) {
if (WM_window_get_active_screen(win) == screen) {
return win;
}
diff --git a/source/blender/editors/screen/screen_geometry.c b/source/blender/editors/screen/screen_geometry.c
index 25855382307..47580c2f4b3 100644
--- a/source/blender/editors/screen/screen_geometry.c
+++ b/source/blender/editors/screen/screen_geometry.c
@@ -57,9 +57,9 @@ ScrVert *screen_geom_vertex_add_ex(ScrAreaMap *area_map, short x, short y)
BLI_addtail(&area_map->vertbase, sv);
return sv;
}
-ScrVert *screen_geom_vertex_add(bScreen *sc, short x, short y)
+ScrVert *screen_geom_vertex_add(bScreen *screen, short x, short y)
{
- return screen_geom_vertex_add_ex(AREAMAP_FROM_SCREEN(sc), x, y);
+ return screen_geom_vertex_add_ex(AREAMAP_FROM_SCREEN(screen), x, y);
}
ScrEdge *screen_geom_edge_add_ex(ScrAreaMap *area_map, ScrVert *v1, ScrVert *v2)
@@ -73,9 +73,9 @@ ScrEdge *screen_geom_edge_add_ex(ScrAreaMap *area_map, ScrVert *v1, ScrVert *v2)
BLI_addtail(&area_map->edgebase, se);
return se;
}
-ScrEdge *screen_geom_edge_add(bScreen *sc, ScrVert *v1, ScrVert *v2)
+ScrEdge *screen_geom_edge_add(bScreen *screen, ScrVert *v1, ScrVert *v2)
{
- return screen_geom_edge_add_ex(AREAMAP_FROM_SCREEN(sc), v1, v2);
+ return screen_geom_edge_add_ex(AREAMAP_FROM_SCREEN(screen), v1, v2);
}
bool screen_geom_edge_is_horizontal(ScrEdge *se)
@@ -92,11 +92,11 @@ ScrEdge *screen_geom_area_map_find_active_scredge(const ScrAreaMap *area_map,
const int mx,
const int my)
{
- int safety = U.widget_unit / 10;
+ int safety = BORDERPADDING;
CLAMP_MIN(safety, 2);
- for (ScrEdge *se = area_map->edgebase.first; se; se = se->next) {
+ LISTBASE_FOREACH (ScrEdge *, se, &area_map->edgebase) {
if (screen_geom_edge_is_horizontal(se)) {
if ((se->v1->vec.y > bounds_rect->ymin) && (se->v1->vec.y < (bounds_rect->ymax - 1))) {
short min, max;
@@ -153,7 +153,7 @@ ScrEdge *screen_geom_find_active_scredge(const wmWindow *win,
* * Ensure areas have a minimum height.
* * Correctly set global areas to their fixed height.
*/
-void screen_geom_vertices_scale(const wmWindow *win, bScreen *sc)
+void screen_geom_vertices_scale(const wmWindow *win, bScreen *screen)
{
rcti window_rect, screen_rect;
@@ -163,7 +163,6 @@ void screen_geom_vertices_scale(const wmWindow *win, bScreen *sc)
const int screen_size_x = BLI_rcti_size_x(&screen_rect);
const int screen_size_y = BLI_rcti_size_y(&screen_rect);
ScrVert *sv = NULL;
- ScrArea *sa;
int screen_size_x_prev, screen_size_y_prev;
float min[2], max[2];
@@ -171,7 +170,7 @@ void screen_geom_vertices_scale(const wmWindow *win, bScreen *sc)
min[0] = min[1] = 20000.0f;
max[0] = max[1] = 0.0f;
- for (sv = sc->vertbase.first; sv; sv = sv->next) {
+ for (sv = screen->vertbase.first; sv; sv = sv->next) {
const float fv[2] = {(float)sv->vec.x, (float)sv->vec.y};
minmax_v2v2_v2(min, max, fv);
}
@@ -184,7 +183,7 @@ void screen_geom_vertices_scale(const wmWindow *win, bScreen *sc)
const float facy = ((float)screen_size_y - 1) / ((float)screen_size_y_prev - 1);
/* make sure it fits! */
- for (sv = sc->vertbase.first; sv; sv = sv->next) {
+ for (sv = screen->vertbase.first; sv; sv = sv->next) {
sv->vec.x = screen_rect.xmin + round_fl_to_short((sv->vec.x - min[0]) * facx);
CLAMP(sv->vec.x, screen_rect.xmin, screen_rect.xmax - 1);
@@ -199,19 +198,19 @@ void screen_geom_vertices_scale(const wmWindow *win, bScreen *sc)
if (facy > 1) {
/* Keep timeline small in video edit workspace. */
- for (sa = sc->areabase.first; sa; sa = sa->next) {
- if (sa->spacetype == SPACE_ACTION && sa->v1->vec.y == screen_rect.ymin &&
- screen_geom_area_height(sa) <= headery * facy + 1) {
- ScrEdge *se = BKE_screen_find_edge(sc, sa->v2, sa->v3);
+ LISTBASE_FOREACH (ScrArea *, area, &screen->areabase) {
+ if (area->spacetype == SPACE_ACTION && area->v1->vec.y == screen_rect.ymin &&
+ screen_geom_area_height(area) <= headery * facy + 1) {
+ ScrEdge *se = BKE_screen_find_edge(screen, area->v2, area->v3);
if (se) {
- const int yval = sa->v1->vec.y + headery - 1;
+ const int yval = area->v1->vec.y + headery - 1;
screen_geom_select_connected_edge(win, se);
/* all selected vertices get the right offset */
- for (sv = sc->vertbase.first; sv; sv = sv->next) {
+ for (sv = screen->vertbase.first; sv; sv = sv->next) {
/* if is a collapsed area */
- if (sv != sa->v1 && sv != sa->v4) {
+ if (sv != area->v1 && sv != area->v4) {
if (sv->flag) {
sv->vec.y = yval;
}
@@ -223,19 +222,19 @@ void screen_geom_vertices_scale(const wmWindow *win, bScreen *sc)
}
if (facy < 1) {
/* make each window at least ED_area_headersize() high */
- for (sa = sc->areabase.first; sa; sa = sa->next) {
- if (screen_geom_area_height(sa) < headery) {
+ LISTBASE_FOREACH (ScrArea *, area, &screen->areabase) {
+ if (screen_geom_area_height(area) < headery) {
/* lower edge */
- ScrEdge *se = BKE_screen_find_edge(sc, sa->v4, sa->v1);
- if (se && sa->v1 != sa->v2) {
- const int yval = sa->v2->vec.y - headery + 1;
+ ScrEdge *se = BKE_screen_find_edge(screen, area->v4, area->v1);
+ if (se && area->v1 != area->v2) {
+ const int yval = area->v2->vec.y - headery + 1;
screen_geom_select_connected_edge(win, se);
/* all selected vertices get the right offset */
- for (sv = sc->vertbase.first; sv; sv = sv->next) {
+ for (sv = screen->vertbase.first; sv; sv = sv->next) {
/* if is not a collapsed area */
- if (sv != sa->v2 && sv != sa->v3) {
+ if (sv != area->v2 && sv != area->v3) {
if (sv->flag) {
sv->vec.y = yval;
}
@@ -249,7 +248,7 @@ void screen_geom_vertices_scale(const wmWindow *win, bScreen *sc)
/* Global areas have a fixed size that only changes with the DPI.
* Here we ensure that exactly this size is set. */
- for (ScrArea *area = win->global_areas.areabase.first; area; area = area->next) {
+ LISTBASE_FOREACH (ScrArea *, area, &win->global_areas.areabase) {
if (area->global->flag & GLOBAL_AREA_IS_HIDDEN) {
continue;
}
@@ -284,14 +283,14 @@ void screen_geom_vertices_scale(const wmWindow *win, bScreen *sc)
/**
* \return 0 if no split is possible, otherwise the screen-coordinate at which to split.
*/
-short screen_geom_find_area_split_point(const ScrArea *sa,
+short screen_geom_find_area_split_point(const ScrArea *area,
const rcti *window_rect,
char dir,
float fac)
{
short x, y;
- const int cur_area_width = screen_geom_area_width(sa);
- const int cur_area_height = screen_geom_area_height(sa);
+ const int cur_area_width = screen_geom_area_width(area);
+ const int cur_area_height = screen_geom_area_height(area);
const short area_min_x = AREAMINX;
const short area_min_y = ED_area_headersize();
int area_min;
@@ -308,43 +307,43 @@ short screen_geom_find_area_split_point(const ScrArea *sa,
CLAMP(fac, 0.0f, 1.0f);
if (dir == 'h') {
- y = sa->v1->vec.y + round_fl_to_short(fac * cur_area_height);
+ y = area->v1->vec.y + round_fl_to_short(fac * cur_area_height);
area_min = area_min_y;
- if (sa->v1->vec.y > window_rect->ymin) {
+ if (area->v1->vec.y > window_rect->ymin) {
area_min += U.pixelsize;
}
- if (sa->v2->vec.y < (window_rect->ymax - 1)) {
+ if (area->v2->vec.y < (window_rect->ymax - 1)) {
area_min += U.pixelsize;
}
- if (y - sa->v1->vec.y < area_min) {
- y = sa->v1->vec.y + area_min;
+ if (y - area->v1->vec.y < area_min) {
+ y = area->v1->vec.y + area_min;
}
- else if (sa->v2->vec.y - y < area_min) {
- y = sa->v2->vec.y - area_min;
+ else if (area->v2->vec.y - y < area_min) {
+ y = area->v2->vec.y - area_min;
}
return y;
}
else {
- x = sa->v1->vec.x + round_fl_to_short(fac * cur_area_width);
+ x = area->v1->vec.x + round_fl_to_short(fac * cur_area_width);
area_min = area_min_x;
- if (sa->v1->vec.x > window_rect->xmin) {
+ if (area->v1->vec.x > window_rect->xmin) {
area_min += U.pixelsize;
}
- if (sa->v4->vec.x < (window_rect->xmax - 1)) {
+ if (area->v4->vec.x < (window_rect->xmax - 1)) {
area_min += U.pixelsize;
}
- if (x - sa->v1->vec.x < area_min) {
- x = sa->v1->vec.x + area_min;
+ if (x - area->v1->vec.x < area_min) {
+ x = area->v1->vec.x + area_min;
}
- else if (sa->v4->vec.x - x < area_min) {
- x = sa->v4->vec.x - area_min;
+ else if (area->v4->vec.x - x < area_min) {
+ x = area->v4->vec.x - area_min;
}
return x;
@@ -356,7 +355,7 @@ short screen_geom_find_area_split_point(const ScrArea *sa,
*/
void screen_geom_select_connected_edge(const wmWindow *win, ScrEdge *edge)
{
- bScreen *sc = WM_window_get_active_screen(win);
+ bScreen *screen = WM_window_get_active_screen(win);
bool oneselected = true;
char dir;
@@ -370,7 +369,7 @@ void screen_geom_select_connected_edge(const wmWindow *win, ScrEdge *edge)
dir = 'h';
}
- ED_screen_verts_iter(win, sc, sv)
+ ED_screen_verts_iter(win, screen, sv)
{
sv->flag = 0;
}
@@ -380,7 +379,7 @@ void screen_geom_select_connected_edge(const wmWindow *win, ScrEdge *edge)
while (oneselected) {
oneselected = false;
- for (ScrEdge *se = sc->edgebase.first; se; se = se->next) {
+ LISTBASE_FOREACH (ScrEdge *, se, &screen->edgebase) {
if (se->v1->flag + se->v2->flag == 1) {
if (dir == 'h') {
if (se->v1->vec.y == se->v2->vec.y) {
diff --git a/source/blender/editors/screen/screen_intern.h b/source/blender/editors/screen/screen_intern.h
index e1a75e51cf2..2d42313d528 100644
--- a/source/blender/editors/screen/screen_intern.h
+++ b/source/blender/editors/screen/screen_intern.h
@@ -35,8 +35,13 @@ struct bContextDataResult;
#define AZONEFADEIN (5.0f * U.widget_unit) /* when azone is totally visible */
#define AZONEFADEOUT (6.5f * U.widget_unit) /* when we start seeing the azone */
+#define AREAJOINTOLERANCE (1.0f * U.widget_unit) /* Edges must be close to allow joining. */
+
+/* Expanded interaction influence of area borders. */
+#define BORDERPADDING (U.dpi_fac + U.pixelsize)
+
/* area.c */
-void ED_area_data_copy(ScrArea *sa_dst, ScrArea *sa_src, const bool do_free);
+void ED_area_data_copy(ScrArea *area_dst, ScrArea *area_src, const bool do_free);
void ED_area_data_swap(ScrArea *sa1, ScrArea *sa2);
void region_toggle_hidden(struct bContext *C, ARegion *region, const bool do_fade);
@@ -44,25 +49,26 @@ void region_toggle_hidden(struct bContext *C, ARegion *region, const bool do_fad
bScreen *screen_add(struct Main *bmain, const char *name, const rcti *rect);
void screen_data_copy(bScreen *to, bScreen *from);
void screen_new_activate_prepare(const wmWindow *win, bScreen *screen_new);
-void screen_change_update(struct bContext *C, wmWindow *win, bScreen *sc);
+void screen_change_update(struct bContext *C, wmWindow *win, bScreen *screen);
bScreen *screen_change_prepare(bScreen *screen_old,
bScreen *screen_new,
struct Main *bmain,
struct bContext *C,
wmWindow *win);
-ScrArea *area_split(const wmWindow *win, bScreen *sc, ScrArea *sa, char dir, float fac, int merge);
-int screen_area_join(struct bContext *C, bScreen *scr, ScrArea *sa1, ScrArea *sa2);
-int area_getorientation(ScrArea *sa, ScrArea *sb);
+ScrArea *area_split(
+ const wmWindow *win, bScreen *screen, ScrArea *area, char dir, float fac, int merge);
+int screen_area_join(struct bContext *C, bScreen *screen, ScrArea *sa1, ScrArea *sa2);
+int area_getorientation(ScrArea *area, ScrArea *sb);
-struct AZone *ED_area_actionzone_find_xy(ScrArea *sa, const int xy[2]);
+struct AZone *ED_area_actionzone_find_xy(ScrArea *area, const int xy[2]);
/* screen_geometry.c */
int screen_geom_area_height(const ScrArea *area);
int screen_geom_area_width(const ScrArea *area);
ScrVert *screen_geom_vertex_add_ex(ScrAreaMap *area_map, short x, short y);
-ScrVert *screen_geom_vertex_add(bScreen *sc, short x, short y);
+ScrVert *screen_geom_vertex_add(bScreen *screen, short x, short y);
ScrEdge *screen_geom_edge_add_ex(ScrAreaMap *area_map, ScrVert *v1, ScrVert *v2);
-ScrEdge *screen_geom_edge_add(bScreen *sc, ScrVert *v1, ScrVert *v2);
+ScrEdge *screen_geom_edge_add(bScreen *screen, ScrVert *v1, ScrVert *v2);
bool screen_geom_edge_is_horizontal(ScrEdge *se);
ScrEdge *screen_geom_area_map_find_active_scredge(const struct ScrAreaMap *area_map,
const rcti *bounds_rect,
@@ -72,8 +78,8 @@ ScrEdge *screen_geom_find_active_scredge(const wmWindow *win,
const bScreen *screen,
const int mx,
const int my);
-void screen_geom_vertices_scale(const wmWindow *win, bScreen *sc);
-short screen_geom_find_area_split_point(const ScrArea *sa,
+void screen_geom_vertices_scale(const wmWindow *win, bScreen *screen);
+short screen_geom_find_area_split_point(const ScrArea *area,
const rcti *window_rect,
char dir,
float fac);
diff --git a/source/blender/editors/screen/screen_ops.c b/source/blender/editors/screen/screen_ops.c
index f2f35f45d12..ace11ffe577 100644
--- a/source/blender/editors/screen/screen_ops.c
+++ b/source/blender/editors/screen/screen_ops.c
@@ -339,7 +339,7 @@ bool ED_operator_console_active(bContext *C)
return ed_spacetype_test(C, SPACE_CONSOLE);
}
-static bool ed_object_hidden(Object *ob)
+static bool ed_object_hidden(const Object *ob)
{
/* if hidden but in edit mode, we still display, can happen with animation */
return ((ob->restrictflag & OB_RESTRICT_VIEWPORT) && !(ob->mode & OB_MODE_EDIT));
@@ -351,10 +351,15 @@ bool ED_operator_object_active(bContext *C)
return ((ob != NULL) && !ed_object_hidden(ob));
}
+bool ED_operator_object_active_editable_ex(bContext *UNUSED(C), const Object *ob)
+{
+ return ((ob != NULL) && !ID_IS_LINKED(ob) && !ed_object_hidden(ob));
+}
+
bool ED_operator_object_active_editable(bContext *C)
{
Object *ob = ED_object_active_context(C);
- return ((ob != NULL) && !ID_IS_LINKED(ob) && !ed_object_hidden(ob));
+ return ED_operator_object_active_editable_ex(C, ob);
}
bool ED_operator_object_active_editable_mesh(bContext *C)
@@ -590,20 +595,20 @@ bool ED_operator_editmball(bContext *C)
bool ED_operator_mask(bContext *C)
{
- ScrArea *sa = CTX_wm_area(C);
- if (sa && sa->spacedata.first) {
- switch (sa->spacetype) {
+ ScrArea *area = CTX_wm_area(C);
+ if (area && area->spacedata.first) {
+ switch (area->spacetype) {
case SPACE_CLIP: {
- SpaceClip *sc = sa->spacedata.first;
- return ED_space_clip_check_show_maskedit(sc);
+ SpaceClip *screen = area->spacedata.first;
+ return ED_space_clip_check_show_maskedit(screen);
}
case SPACE_SEQ: {
- SpaceSeq *sseq = sa->spacedata.first;
+ SpaceSeq *sseq = area->spacedata.first;
Scene *scene = CTX_data_scene(C);
return ED_space_sequencer_check_show_maskedit(sseq, scene);
}
case SPACE_IMAGE: {
- SpaceImage *sima = sa->spacedata.first;
+ SpaceImage *sima = area->spacedata.first;
ViewLayer *view_layer = CTX_data_view_layer(C);
return ED_space_image_check_show_maskedit(sima, view_layer);
}
@@ -681,8 +686,8 @@ static bool actionzone_area_poll(bContext *C)
const int *xy = &win->eventstate->x;
AZone *az;
- for (ScrArea *sa = screen->areabase.first; sa; sa = sa->next) {
- for (az = sa->actionzones.first; az; az = az->next) {
+ LISTBASE_FOREACH (ScrArea *, area, &screen->areabase) {
+ for (az = area->actionzones.first; az; az = az->next) {
if (BLI_rcti_isect_pt_v(&az->rect, xy)) {
return 1;
}
@@ -743,11 +748,11 @@ static bool azone_clipped_rect_calc(const AZone *az, rcti *r_rect_clip)
return false;
}
-static AZone *area_actionzone_refresh_xy(ScrArea *sa, const int xy[2], const bool test_only)
+static AZone *area_actionzone_refresh_xy(ScrArea *area, const int xy[2], const bool test_only)
{
AZone *az = NULL;
- for (az = sa->actionzones.first; az; az = az->next) {
+ for (az = area->actionzones.first; az; az = az->next) {
rcti az_rect_clip;
if (BLI_rcti_isect_pt_v(&az->rect, xy) &&
/* Check clipping if this is clipped */
@@ -798,7 +803,7 @@ static AZone *area_actionzone_refresh_xy(ScrArea *sa, const int xy[2], const boo
}
/* XXX force redraw to show/hide the action zone */
- ED_area_tag_redraw(sa);
+ ED_area_tag_redraw(area);
break;
}
}
@@ -868,18 +873,18 @@ static AZone *area_actionzone_refresh_xy(ScrArea *sa, const int xy[2], const boo
else if (!test_only && !IS_EQF(az->alpha, 0.0f)) {
if (az->type == AZONE_FULLSCREEN) {
az->alpha = 0.0f;
- sa->flag &= ~AREA_FLAG_ACTIONZONES_UPDATE;
- ED_area_tag_redraw_no_rebuild(sa);
+ area->flag &= ~AREA_FLAG_ACTIONZONES_UPDATE;
+ ED_area_tag_redraw_no_rebuild(area);
}
else if (az->type == AZONE_REGION_SCROLL) {
if (az->direction == AZ_SCROLL_VERT) {
az->alpha = az->region->v2d.alpha_vert = 0;
- sa->flag &= ~AREA_FLAG_ACTIONZONES_UPDATE;
+ area->flag &= ~AREA_FLAG_ACTIONZONES_UPDATE;
ED_region_tag_redraw_no_rebuild(az->region);
}
else if (az->direction == AZ_SCROLL_HOR) {
az->alpha = az->region->v2d.alpha_hor = 0;
- sa->flag &= ~AREA_FLAG_ACTIONZONES_UPDATE;
+ area->flag &= ~AREA_FLAG_ACTIONZONES_UPDATE;
ED_region_tag_redraw_no_rebuild(az->region);
}
else {
@@ -893,10 +898,10 @@ static AZone *area_actionzone_refresh_xy(ScrArea *sa, const int xy[2], const boo
}
/* Finds an action-zone by position in entire screen so azones can overlap. */
-static AZone *screen_actionzone_find_xy(bScreen *sc, const int xy[2])
+static AZone *screen_actionzone_find_xy(bScreen *screen, const int xy[2])
{
- for (ScrArea *sa = sc->areabase.first; sa; sa = sa->next) {
- AZone *az = area_actionzone_refresh_xy(sa, xy, true);
+ LISTBASE_FOREACH (ScrArea *, area, &screen->areabase) {
+ AZone *az = area_actionzone_refresh_xy(area, xy, true);
if (az != NULL) {
return az;
}
@@ -905,10 +910,10 @@ static AZone *screen_actionzone_find_xy(bScreen *sc, const int xy[2])
}
/* Returns the area that the azone belongs to */
-static ScrArea *screen_actionzone_area(bScreen *sc, const AZone *az)
+static ScrArea *screen_actionzone_area(bScreen *screen, const AZone *az)
{
- for (ScrArea *area = sc->areabase.first; area; area = area->next) {
- for (AZone *zone = area->actionzones.first; zone; zone = zone->next) {
+ LISTBASE_FOREACH (ScrArea *, area, &screen->areabase) {
+ LISTBASE_FOREACH (AZone *, zone, &area->actionzones) {
if (zone == az) {
return area;
}
@@ -917,14 +922,14 @@ static ScrArea *screen_actionzone_area(bScreen *sc, const AZone *az)
return NULL;
}
-AZone *ED_area_actionzone_find_xy(ScrArea *sa, const int xy[2])
+AZone *ED_area_actionzone_find_xy(ScrArea *area, const int xy[2])
{
- return area_actionzone_refresh_xy(sa, xy, true);
+ return area_actionzone_refresh_xy(area, xy, true);
}
-AZone *ED_area_azones_update(ScrArea *sa, const int xy[2])
+AZone *ED_area_azones_update(ScrArea *area, const int xy[2])
{
- return area_actionzone_refresh_xy(sa, xy, false);
+ return area_actionzone_refresh_xy(area, xy, false);
}
static void actionzone_exit(wmOperator *op)
@@ -968,8 +973,8 @@ static void actionzone_apply(bContext *C, wmOperator *op, int type)
static int actionzone_invoke(bContext *C, wmOperator *op, const wmEvent *event)
{
- bScreen *sc = CTX_wm_screen(C);
- AZone *az = screen_actionzone_find_xy(sc, &event->x);
+ bScreen *screen = CTX_wm_screen(C);
+ AZone *az = screen_actionzone_find_xy(screen, &event->x);
sActionzoneData *sad;
/* Quick escape - Scroll azones only hide/unhide the scroll-bars,
@@ -980,7 +985,7 @@ static int actionzone_invoke(bContext *C, wmOperator *op, const wmEvent *event)
/* ok we do the action-zone */
sad = op->customdata = MEM_callocN(sizeof(sActionzoneData), "sActionzoneData");
- sad->sa1 = screen_actionzone_area(sc, az);
+ sad->sa1 = screen_actionzone_area(screen, az);
sad->az = az;
sad->x = event->x;
sad->y = event->y;
@@ -1003,7 +1008,7 @@ static int actionzone_invoke(bContext *C, wmOperator *op, const wmEvent *event)
static int actionzone_modal(bContext *C, wmOperator *op, const wmEvent *event)
{
- bScreen *sc = CTX_wm_screen(C);
+ bScreen *screen = CTX_wm_screen(C);
sActionzoneData *sad = op->customdata;
switch (event->type) {
@@ -1044,9 +1049,9 @@ static int actionzone_modal(bContext *C, wmOperator *op, const wmEvent *event)
/* Have we dragged off the zone and are not on an edge? */
if ((ED_area_actionzone_find_xy(sad->sa1, &event->x) != sad->az) &&
(screen_geom_area_map_find_active_scredge(
- AREAMAP_FROM_SCREEN(sc), &screen_rect, event->x, event->y) == NULL)) {
+ AREAMAP_FROM_SCREEN(screen), &screen_rect, event->x, event->y) == NULL)) {
/* Are we still in same area? */
- if (BKE_screen_find_area_xy(sc, SPACE_TYPE_ANY, event->x, event->y) == sad->sa1) {
+ if (BKE_screen_find_area_xy(screen, SPACE_TYPE_ANY, event->x, event->y) == sad->sa1) {
/* Same area, so possible split. */
WM_cursor_set(
win, (ELEM(sad->gesture_dir, 'n', 's')) ? WM_CURSOR_H_SPLIT : WM_CURSOR_V_SPLIT);
@@ -1081,7 +1086,7 @@ static int actionzone_modal(bContext *C, wmOperator *op, const wmEvent *event)
/* gesture is large enough? */
if (is_gesture) {
/* second area, for join when (sa1 != sa2) */
- sad->sa2 = BKE_screen_find_area_xy(sc, SPACE_TYPE_ANY, event->x, event->y);
+ sad->sa2 = BKE_screen_find_area_xy(screen, SPACE_TYPE_ANY, event->x, event->y);
/* apply sends event */
actionzone_apply(C, op, sad->az->type);
actionzone_exit(op);
@@ -1136,12 +1141,12 @@ static ScrEdge *screen_area_edge_from_cursor(const bContext *C,
ScrArea **r_sa2)
{
wmWindow *win = CTX_wm_window(C);
- bScreen *sc = CTX_wm_screen(C);
+ bScreen *screen = CTX_wm_screen(C);
ScrEdge *actedge;
rcti window_rect;
WM_window_rect_calc(win, &window_rect);
actedge = screen_geom_area_map_find_active_scredge(
- AREAMAP_FROM_SCREEN(sc), &window_rect, cursor[0], cursor[1]);
+ AREAMAP_FROM_SCREEN(screen), &window_rect, cursor[0], cursor[1]);
*r_sa1 = NULL;
*r_sa2 = NULL;
if (actedge == NULL) {
@@ -1150,12 +1155,12 @@ static ScrEdge *screen_area_edge_from_cursor(const bContext *C,
int borderwidth = (4 * UI_DPI_FAC);
ScrArea *sa1, *sa2;
if (screen_geom_edge_is_horizontal(actedge)) {
- sa1 = BKE_screen_find_area_xy(sc, SPACE_TYPE_ANY, cursor[0], cursor[1] + borderwidth);
- sa2 = BKE_screen_find_area_xy(sc, SPACE_TYPE_ANY, cursor[0], cursor[1] - borderwidth);
+ sa1 = BKE_screen_find_area_xy(screen, SPACE_TYPE_ANY, cursor[0], cursor[1] + borderwidth);
+ sa2 = BKE_screen_find_area_xy(screen, SPACE_TYPE_ANY, cursor[0], cursor[1] - borderwidth);
}
else {
- sa1 = BKE_screen_find_area_xy(sc, SPACE_TYPE_ANY, cursor[0] + borderwidth, cursor[1]);
- sa2 = BKE_screen_find_area_xy(sc, SPACE_TYPE_ANY, cursor[0] - borderwidth, cursor[1]);
+ sa1 = BKE_screen_find_area_xy(screen, SPACE_TYPE_ANY, cursor[0] + borderwidth, cursor[1]);
+ sa2 = BKE_screen_find_area_xy(screen, SPACE_TYPE_ANY, cursor[0] - borderwidth, cursor[1]);
}
bool isGlobal = ((sa1 && ED_area_is_global(sa1)) || (sa2 && ED_area_is_global(sa2)));
if (!isGlobal) {
@@ -1327,12 +1332,12 @@ static int area_dupli_invoke(bContext *C, wmOperator *op, const wmEvent *event)
WorkSpaceLayout *layout_old = WM_window_get_active_layout(win);
WorkSpaceLayout *layout_new;
bScreen *newsc;
- ScrArea *sa;
+ ScrArea *area;
rcti rect;
win = CTX_wm_window(C);
scene = CTX_data_scene(C);
- sa = CTX_wm_area(C);
+ area = CTX_wm_area(C);
/* XXX hrmf! */
if (event->type == EVT_ACTIONZONE_AREA) {
@@ -1342,11 +1347,11 @@ static int area_dupli_invoke(bContext *C, wmOperator *op, const wmEvent *event)
return OPERATOR_PASS_THROUGH;
}
- sa = sad->sa1;
+ area = sad->sa1;
}
/* adds window to WM */
- rect = sa->totrct;
+ rect = area->totrct;
BLI_rcti_translate(&rect, win->posx, win->posy);
rect.xmax = rect.xmin + BLI_rcti_size_x(&rect) / U.pixelsize;
rect.ymax = rect.ymin + BLI_rcti_size_y(&rect) / U.pixelsize;
@@ -1371,7 +1376,7 @@ static int area_dupli_invoke(bContext *C, wmOperator *op, const wmEvent *event)
WM_window_set_active_layout(newwin, workspace, layout_new);
/* copy area to new screen */
- ED_area_data_copy((ScrArea *)newsc->areabase.first, sa, true);
+ ED_area_data_copy((ScrArea *)newsc->areabase.first, area, true);
ED_area_tag_redraw((ScrArea *)newsc->areabase.first);
@@ -1454,8 +1459,12 @@ typedef struct sAreaMoveData {
/* helper call to move area-edge, sets limits
* need window bounds in order to get correct limits */
-static void area_move_set_limits(
- wmWindow *win, bScreen *sc, int dir, int *bigger, int *smaller, bool *use_bigger_smaller_snap)
+static void area_move_set_limits(wmWindow *win,
+ bScreen *screen,
+ int dir,
+ int *bigger,
+ int *smaller,
+ bool *use_bigger_smaller_snap)
{
rcti window_rect;
int areaminy = ED_area_headersize();
@@ -1466,7 +1475,7 @@ static void area_move_set_limits(
if (use_bigger_smaller_snap != NULL) {
*use_bigger_smaller_snap = false;
- for (ScrArea *area = win->global_areas.areabase.first; area; area = area->next) {
+ LISTBASE_FOREACH (ScrArea *, area, &win->global_areas.areabase) {
int size_min = ED_area_global_min_size_y(area) - 1;
int size_max = ED_area_global_max_size_y(area) - 1;
@@ -1507,25 +1516,25 @@ static void area_move_set_limits(
WM_window_rect_calc(win, &window_rect);
- for (ScrArea *sa = sc->areabase.first; sa; sa = sa->next) {
+ LISTBASE_FOREACH (ScrArea *, area, &screen->areabase) {
if (dir == 'h') {
int y1;
areamin = areaminy;
- if (sa->v1->vec.y > window_rect.ymin) {
+ if (area->v1->vec.y > window_rect.ymin) {
areamin += U.pixelsize;
}
- if (sa->v2->vec.y < (window_rect.ymax - 1)) {
+ if (area->v2->vec.y < (window_rect.ymax - 1)) {
areamin += U.pixelsize;
}
- y1 = screen_geom_area_height(sa) - areamin;
+ y1 = screen_geom_area_height(area) - areamin;
/* if top or down edge selected, test height */
- if (sa->v1->editflag && sa->v4->editflag) {
+ if (area->v1->editflag && area->v4->editflag) {
*bigger = min_ii(*bigger, y1);
}
- else if (sa->v2->editflag && sa->v3->editflag) {
+ else if (area->v2->editflag && area->v3->editflag) {
*smaller = min_ii(*smaller, y1);
}
}
@@ -1533,20 +1542,20 @@ static void area_move_set_limits(
int x1;
areamin = AREAMINX;
- if (sa->v1->vec.x > window_rect.xmin) {
+ if (area->v1->vec.x > window_rect.xmin) {
areamin += U.pixelsize;
}
- if (sa->v4->vec.x < (window_rect.xmax - 1)) {
+ if (area->v4->vec.x < (window_rect.xmax - 1)) {
areamin += U.pixelsize;
}
- x1 = screen_geom_area_width(sa) - areamin;
+ x1 = screen_geom_area_width(area) - areamin;
/* if left or right edge selected, test width */
- if (sa->v1->editflag && sa->v2->editflag) {
+ if (area->v1->editflag && area->v2->editflag) {
*bigger = min_ii(*bigger, x1);
}
- else if (sa->v3->editflag && sa->v4->editflag) {
+ else if (area->v3->editflag && area->v4->editflag) {
*smaller = min_ii(*smaller, x1);
}
}
@@ -1557,7 +1566,7 @@ static void area_move_set_limits(
/* return 0: init failed */
static int area_move_init(bContext *C, wmOperator *op)
{
- bScreen *sc = CTX_wm_screen(C);
+ bScreen *screen = CTX_wm_screen(C);
wmWindow *win = CTX_wm_window(C);
ScrEdge *actedge;
sAreaMoveData *md;
@@ -1568,7 +1577,7 @@ static int area_move_init(bContext *C, wmOperator *op)
y = RNA_int_get(op->ptr, "y");
/* setup */
- actedge = screen_geom_find_active_scredge(win, sc, x, y);
+ actedge = screen_geom_find_active_scredge(win, screen, x, y);
if (actedge == NULL) {
return 0;
}
@@ -1586,20 +1595,20 @@ static int area_move_init(bContext *C, wmOperator *op)
screen_geom_select_connected_edge(win, actedge);
/* now all vertices with 'flag == 1' are the ones that can be moved. Move this to editflag */
- ED_screen_verts_iter(win, sc, v1)
+ ED_screen_verts_iter(win, screen, v1)
{
v1->editflag = v1->flag;
}
bool use_bigger_smaller_snap = false;
- area_move_set_limits(win, sc, md->dir, &md->bigger, &md->smaller, &use_bigger_smaller_snap);
+ area_move_set_limits(win, screen, md->dir, &md->bigger, &md->smaller, &use_bigger_smaller_snap);
md->snap_type = use_bigger_smaller_snap ? SNAP_BIGGER_SMALLER_ONLY : SNAP_AREAGRID;
return 1;
}
-static int area_snap_calc_location(const bScreen *sc,
+static int area_snap_calc_location(const bScreen *screen,
const enum AreaMoveSnapType snap_type,
const int delta,
const int origval,
@@ -1657,13 +1666,13 @@ static int area_snap_calc_location(const bScreen *sc,
}
}
- for (const ScrVert *v1 = sc->vertbase.first; v1; v1 = v1->next) {
+ LISTBASE_FOREACH (const ScrVert *, v1, &screen->vertbase) {
if (!v1->editflag) {
continue;
}
const int v_loc = (&v1->vec.x)[!axis];
- for (const ScrVert *v2 = sc->vertbase.first; v2; v2 = v2->next) {
+ LISTBASE_FOREACH (const ScrVert *, v2, &screen->vertbase) {
if (v2->editflag) {
continue;
}
@@ -1702,7 +1711,7 @@ static void area_move_apply_do(const bContext *C,
const enum AreaMoveSnapType snap_type)
{
wmWindow *win = CTX_wm_window(C);
- bScreen *sc = CTX_wm_screen(C);
+ bScreen *screen = CTX_wm_screen(C);
short final_loc = -1;
bool doredraw = false;
@@ -1714,13 +1723,13 @@ static void area_move_apply_do(const bContext *C,
final_loc = origval + delta;
}
else {
- final_loc = area_snap_calc_location(sc, snap_type, delta, origval, dir, bigger, smaller);
+ final_loc = area_snap_calc_location(screen, snap_type, delta, origval, dir, bigger, smaller);
}
BLI_assert(final_loc != -1);
short axis = (dir == 'v') ? 0 : 1;
- ED_screen_verts_iter(win, sc, v1)
+ ED_screen_verts_iter(win, screen, v1)
{
if (v1->editflag) {
short oldval = (&v1->vec.x)[axis];
@@ -1737,29 +1746,27 @@ static void area_move_apply_do(const bContext *C,
/* only redraw if we actually moved a screen vert, for AREAGRID */
if (doredraw) {
bool redraw_all = false;
- ED_screen_areas_iter(win, sc, sa)
- {
- if (sa->v1->editflag || sa->v2->editflag || sa->v3->editflag || sa->v4->editflag) {
- if (ED_area_is_global(sa)) {
+ ED_screen_areas_iter (win, screen, area) {
+ if (area->v1->editflag || area->v2->editflag || area->v3->editflag || area->v4->editflag) {
+ if (ED_area_is_global(area)) {
/* Snap to minimum or maximum for global areas. */
- int height = round_fl_to_int(screen_geom_area_height(sa) / UI_DPI_FAC);
- if (abs(height - sa->global->size_min) < abs(height - sa->global->size_max)) {
- sa->global->cur_fixed_height = sa->global->size_min;
+ int height = round_fl_to_int(screen_geom_area_height(area) / UI_DPI_FAC);
+ if (abs(height - area->global->size_min) < abs(height - area->global->size_max)) {
+ area->global->cur_fixed_height = area->global->size_min;
}
else {
- sa->global->cur_fixed_height = sa->global->size_max;
+ area->global->cur_fixed_height = area->global->size_max;
}
- sc->do_refresh = true;
+ screen->do_refresh = true;
redraw_all = true;
}
- ED_area_tag_redraw(sa);
+ ED_area_tag_redraw(area);
}
}
if (redraw_all) {
- ED_screen_areas_iter(win, sc, sa)
- {
- ED_area_tag_redraw(sa);
+ ED_screen_areas_iter (win, screen, area) {
+ ED_area_tag_redraw(area);
}
}
@@ -1767,7 +1774,7 @@ static void area_move_apply_do(const bContext *C,
WM_event_add_notifier(C, NC_SCREEN | NA_EDITED, NULL); /* redraw everything */
/* Update preview thumbnail */
- BKE_icon_changed(sc->id.icon_id);
+ BKE_icon_changed(screen->id.icon_id);
}
}
@@ -1984,13 +1991,13 @@ static int area_split_menu_init(bContext *C, wmOperator *op)
/* generic init, no UI stuff here, assumes active area */
static int area_split_init(bContext *C, wmOperator *op)
{
- ScrArea *sa = CTX_wm_area(C);
+ ScrArea *area = CTX_wm_area(C);
sAreaSplitData *sd;
int areaminy = ED_area_headersize();
int dir;
/* required context */
- if (sa == NULL) {
+ if (area == NULL) {
return 0;
}
@@ -1998,10 +2005,10 @@ static int area_split_init(bContext *C, wmOperator *op)
dir = RNA_enum_get(op->ptr, "direction");
/* minimal size */
- if (dir == 'v' && sa->winx < 2 * AREAMINX) {
+ if (dir == 'v' && area->winx < 2 * AREAMINX) {
return 0;
}
- if (dir == 'h' && sa->winy < 2 * areaminy) {
+ if (dir == 'h' && area->winy < 2 * areaminy) {
return 0;
}
@@ -2009,42 +2016,42 @@ static int area_split_init(bContext *C, wmOperator *op)
sd = (sAreaSplitData *)MEM_callocN(sizeof(sAreaSplitData), "op_area_split");
op->customdata = sd;
- sd->sarea = sa;
+ sd->sarea = area;
if (dir == 'v') {
- sd->origmin = sa->v1->vec.x;
- sd->origsize = sa->v4->vec.x - sd->origmin;
+ sd->origmin = area->v1->vec.x;
+ sd->origsize = area->v4->vec.x - sd->origmin;
}
else {
- sd->origmin = sa->v1->vec.y;
- sd->origsize = sa->v2->vec.y - sd->origmin;
+ sd->origmin = area->v1->vec.y;
+ sd->origsize = area->v2->vec.y - sd->origmin;
}
return 1;
}
-/* with sa as center, sb is located at: 0=W, 1=N, 2=E, 3=S */
+/* with area as center, sb is located at: 0=W, 1=N, 2=E, 3=S */
/* used with split operator */
-static ScrEdge *area_findsharededge(bScreen *screen, ScrArea *sa, ScrArea *sb)
+static ScrEdge *area_findsharededge(bScreen *screen, ScrArea *area, ScrArea *sb)
{
- ScrVert *sav1 = sa->v1;
- ScrVert *sav2 = sa->v2;
- ScrVert *sav3 = sa->v3;
- ScrVert *sav4 = sa->v4;
+ ScrVert *sav1 = area->v1;
+ ScrVert *sav2 = area->v2;
+ ScrVert *sav3 = area->v3;
+ ScrVert *sav4 = area->v4;
ScrVert *sbv1 = sb->v1;
ScrVert *sbv2 = sb->v2;
ScrVert *sbv3 = sb->v3;
ScrVert *sbv4 = sb->v4;
- if (sav1 == sbv4 && sav2 == sbv3) { /* sa to right of sb = W */
+ if (sav1 == sbv4 && sav2 == sbv3) { /* area to right of sb = W */
return BKE_screen_find_edge(screen, sav1, sav2);
}
- else if (sav2 == sbv1 && sav3 == sbv4) { /* sa to bottom of sb = N */
+ else if (sav2 == sbv1 && sav3 == sbv4) { /* area to bottom of sb = N */
return BKE_screen_find_edge(screen, sav2, sav3);
}
- else if (sav3 == sbv2 && sav4 == sbv1) { /* sa to left of sb = E */
+ else if (sav3 == sbv2 && sav4 == sbv1) { /* area to left of sb = E */
return BKE_screen_find_edge(screen, sav3, sav4);
}
- else if (sav1 == sbv2 && sav4 == sbv3) { /* sa on top of sb = S*/
+ else if (sav1 == sbv2 && sav4 == sbv3) { /* area on top of sb = S*/
return BKE_screen_find_edge(screen, sav1, sav4);
}
@@ -2055,7 +2062,7 @@ static ScrEdge *area_findsharededge(bScreen *screen, ScrArea *sa, ScrArea *sb)
static int area_split_apply(bContext *C, wmOperator *op)
{
const wmWindow *win = CTX_wm_window(C);
- bScreen *sc = CTX_wm_screen(C);
+ bScreen *screen = CTX_wm_screen(C);
sAreaSplitData *sd = (sAreaSplitData *)op->customdata;
float fac;
int dir;
@@ -2063,13 +2070,13 @@ static int area_split_apply(bContext *C, wmOperator *op)
fac = RNA_float_get(op->ptr, "factor");
dir = RNA_enum_get(op->ptr, "direction");
- sd->narea = area_split(win, sc, sd->sarea, dir, fac, 0); /* 0 = no merge */
+ sd->narea = area_split(win, screen, sd->sarea, dir, fac, 0); /* 0 = no merge */
if (sd->narea) {
- sd->nedge = area_findsharededge(sc, sd->sarea, sd->narea);
+ sd->nedge = area_findsharededge(screen, sd->sarea, sd->narea);
/* select newly created edge, prepare for moving edge */
- ED_screen_verts_iter(win, sc, sv)
+ ED_screen_verts_iter(win, screen, sv)
{
sv->editflag = 0;
}
@@ -2089,7 +2096,7 @@ static int area_split_apply(bContext *C, wmOperator *op)
WM_event_add_notifier(C, NC_SCREEN | NA_EDITED, NULL);
/* Update preview thumbnail */
- BKE_icon_changed(sc->id.icon_id);
+ BKE_icon_changed(screen->id.icon_id);
return 1;
}
@@ -2137,12 +2144,12 @@ static void area_split_preview_update_cursor(bContext *C, wmOperator *op)
static int area_split_invoke(bContext *C, wmOperator *op, const wmEvent *event)
{
wmWindow *win = CTX_wm_window(C);
- bScreen *sc = CTX_wm_screen(C);
+ bScreen *screen = CTX_wm_screen(C);
sAreaSplitData *sd;
int dir;
/* no full window splitting allowed */
- BLI_assert(sc->state == SCREENNORMAL);
+ BLI_assert(screen->state == SCREENNORMAL);
PropertyRNA *prop_dir = RNA_struct_find_property(op->ptr, "direction");
PropertyRNA *prop_factor = RNA_struct_find_property(op->ptr, "factor");
@@ -2198,18 +2205,18 @@ static int area_split_invoke(bContext *C, wmOperator *op, const wmEvent *event)
}
}
else if (RNA_property_is_set(op->ptr, prop_dir)) {
- ScrArea *sa = CTX_wm_area(C);
- if (sa == NULL) {
+ ScrArea *area = CTX_wm_area(C);
+ if (area == NULL) {
return OPERATOR_CANCELLED;
}
dir = RNA_property_enum_get(op->ptr, prop_dir);
if (dir == 'h') {
RNA_property_float_set(
- op->ptr, prop_factor, ((float)(event->x - sa->v1->vec.x)) / (float)sa->winx);
+ op->ptr, prop_factor, ((float)(event->x - area->v1->vec.x)) / (float)area->winx);
}
else {
RNA_property_float_set(
- op->ptr, prop_factor, ((float)(event->y - sa->v1->vec.y)) / (float)sa->winy);
+ op->ptr, prop_factor, ((float)(event->y - area->v1->vec.y)) / (float)area->winy);
}
if (!area_split_init(C, op)) {
@@ -2232,7 +2239,7 @@ static int area_split_invoke(bContext *C, wmOperator *op, const wmEvent *event)
WM_window_rect_calc(win, &window_rect);
actedge = screen_geom_area_map_find_active_scredge(
- AREAMAP_FROM_SCREEN(sc), &window_rect, event_co[0], event_co[1]);
+ AREAMAP_FROM_SCREEN(screen), &window_rect, event_co[0], event_co[1]);
if (actedge == NULL) {
return OPERATOR_CANCELLED;
}
@@ -2253,7 +2260,7 @@ static int area_split_invoke(bContext *C, wmOperator *op, const wmEvent *event)
/* do the split */
if (area_split_apply(C, op)) {
- area_move_set_limits(win, sc, dir, &sd->bigger, &sd->smaller, NULL);
+ area_move_set_limits(win, screen, dir, &sd->bigger, &sd->smaller, NULL);
/* add temp handler for edge move or cancel */
G.moving |= G_TRANSFORM_WM;
@@ -2389,18 +2396,18 @@ static int area_split_modal(bContext *C, wmOperator *op, const wmEvent *event)
sd->sarea = BKE_screen_find_area_xy(CTX_wm_screen(C), SPACE_TYPE_ANY, event->x, event->y);
if (sd->sarea) {
- ScrArea *sa = sd->sarea;
+ ScrArea *area = sd->sarea;
if (dir == 'v') {
- sd->origmin = sa->v1->vec.x;
- sd->origsize = sa->v4->vec.x - sd->origmin;
+ sd->origmin = area->v1->vec.x;
+ sd->origsize = area->v4->vec.x - sd->origmin;
}
else {
- sd->origmin = sa->v1->vec.y;
- sd->origsize = sa->v2->vec.y - sd->origmin;
+ sd->origmin = area->v1->vec.y;
+ sd->origsize = area->v2->vec.y - sd->origmin;
}
if (sd->do_snap) {
- sa->v1->editflag = sa->v2->editflag = sa->v3->editflag = sa->v4->editflag = 1;
+ area->v1->editflag = area->v2->editflag = area->v3->editflag = area->v4->editflag = 1;
const int snap_loc = area_snap_calc_location(CTX_wm_screen(C),
SNAP_FRACTION_AND_ADJACENT,
@@ -2410,7 +2417,7 @@ static int area_split_modal(bContext *C, wmOperator *op, const wmEvent *event)
sd->origmin + sd->origsize,
-sd->origmin);
- sa->v1->editflag = sa->v2->editflag = sa->v3->editflag = sa->v4->editflag = 0;
+ area->v1->editflag = area->v2->editflag = area->v3->editflag = area->v4->editflag = 0;
sd->delta = snap_loc - sd->origval;
}
@@ -2465,7 +2472,7 @@ static void SCREEN_OT_area_split(wmOperatorType *ot)
typedef struct RegionMoveData {
AZone *az;
ARegion *region;
- ScrArea *sa;
+ ScrArea *area;
int bigger, smaller, origval;
int origx, origy;
int maxsize;
@@ -2473,7 +2480,7 @@ typedef struct RegionMoveData {
} RegionMoveData;
-static int area_max_regionsize(ScrArea *sa, ARegion *scalear, AZEdge edge)
+static int area_max_regionsize(ScrArea *area, ARegion *scalear, AZEdge edge)
{
int dist;
@@ -2492,15 +2499,15 @@ static int area_max_regionsize(ScrArea *sa, ARegion *scalear, AZEdge edge)
}
else {
if (edge == AE_RIGHT_TO_TOPLEFT || edge == AE_LEFT_TO_TOPRIGHT) {
- dist = BLI_rcti_size_x(&sa->totrct);
+ dist = BLI_rcti_size_x(&area->totrct);
}
else { /* AE_BOTTOM_TO_TOPLEFT, AE_TOP_TO_BOTTOMRIGHT */
- dist = BLI_rcti_size_y(&sa->totrct);
+ dist = BLI_rcti_size_y(&area->totrct);
}
/* subtractwidth of regions on opposite side
* prevents dragging regions into other opposite regions */
- for (ARegion *region = sa->regionbase.first; region; region = region->next) {
+ LISTBASE_FOREACH (ARegion *, region, &area->regionbase) {
if (region == scalear) {
continue;
}
@@ -2574,11 +2581,11 @@ static int region_scale_invoke(bContext *C, wmOperator *op, const wmEvent *event
else {
rmd->region = az->region;
}
- rmd->sa = sad->sa1;
+ rmd->area = sad->sa1;
rmd->edge = az->edge;
rmd->origx = event->x;
rmd->origy = event->y;
- rmd->maxsize = area_max_regionsize(rmd->sa, rmd->region, rmd->edge);
+ rmd->maxsize = area_max_regionsize(rmd->area, rmd->region, rmd->edge);
/* if not set we do now, otherwise it uses type */
if (rmd->region->sizex == 0) {
@@ -2641,11 +2648,11 @@ static void region_scale_toggle_hidden(bContext *C, RegionMoveData *rmd)
if ((rmd->region->flag & RGN_FLAG_HIDDEN) == 0) {
if (rmd->region->regiontype == RGN_TYPE_HEADER) {
- ARegion *ar_tool_header = BKE_area_find_region_type(rmd->sa, RGN_TYPE_TOOL_HEADER);
- if (ar_tool_header != NULL) {
- if ((ar_tool_header->flag & RGN_FLAG_HIDDEN_BY_USER) == 0 &&
- (ar_tool_header->flag & RGN_FLAG_HIDDEN) != 0) {
- region_toggle_hidden(C, ar_tool_header, 0);
+ ARegion *region_tool_header = BKE_area_find_region_type(rmd->area, RGN_TYPE_TOOL_HEADER);
+ if (region_tool_header != NULL) {
+ if ((region_tool_header->flag & RGN_FLAG_HIDDEN_BY_USER) == 0 &&
+ (region_tool_header->flag & RGN_FLAG_HIDDEN) != 0) {
+ region_toggle_hidden(C, region_tool_header, 0);
}
}
}
@@ -2732,7 +2739,7 @@ static int region_scale_modal(bContext *C, wmOperator *op, const wmEvent *event)
rmd->region->sizey = rmd->origval;
}
}
- ED_area_tag_redraw(rmd->sa);
+ ED_area_tag_redraw(rmd->area);
WM_event_add_notifier(C, NC_SCREEN | NA_EDITED, NULL);
break;
@@ -2747,7 +2754,7 @@ static int region_scale_modal(bContext *C, wmOperator *op, const wmEvent *event)
region_scale_validate_size(rmd);
}
- ED_area_tag_redraw(rmd->sa);
+ ED_area_tag_redraw(rmd->area);
WM_event_add_notifier(C, NC_SCREEN | NA_EDITED, NULL);
}
@@ -2794,19 +2801,19 @@ static void SCREEN_OT_region_scale(wmOperatorType *ot)
static void areas_do_frame_follow(bContext *C, bool middle)
{
- bScreen *scr = CTX_wm_screen(C);
+ bScreen *screen_ctx = CTX_wm_screen(C);
Scene *scene = CTX_data_scene(C);
wmWindowManager *wm = CTX_wm_manager(C);
- for (wmWindow *window = wm->windows.first; window; window = window->next) {
+ LISTBASE_FOREACH (wmWindow *, window, &wm->windows) {
const bScreen *screen = WM_window_get_active_screen(window);
- for (ScrArea *sa = screen->areabase.first; sa; sa = sa->next) {
- for (ARegion *region = sa->regionbase.first; region; region = region->next) {
+ LISTBASE_FOREACH (ScrArea *, area, &screen->areabase) {
+ LISTBASE_FOREACH (ARegion *, region, &area->regionbase) {
/* do follow here if editor type supports it */
- if ((scr->redraws_flag & TIME_FOLLOW)) {
+ if ((screen_ctx->redraws_flag & TIME_FOLLOW)) {
if ((region->regiontype == RGN_TYPE_WINDOW &&
- ELEM(sa->spacetype, SPACE_SEQ, SPACE_GRAPH, SPACE_ACTION, SPACE_NLA)) ||
- (sa->spacetype == SPACE_CLIP && region->regiontype == RGN_TYPE_PREVIEW)) {
+ ELEM(area->spacetype, SPACE_SEQ, SPACE_GRAPH, SPACE_ACTION, SPACE_NLA)) ||
+ (area->spacetype == SPACE_CLIP && region->regiontype == RGN_TYPE_PREVIEW)) {
float w = BLI_rctf_size_x(&region->v2d.cur);
if (middle) {
@@ -3155,32 +3162,32 @@ static void SCREEN_OT_screen_set(wmOperatorType *ot)
static int screen_maximize_area_exec(bContext *C, wmOperator *op)
{
bScreen *screen = CTX_wm_screen(C);
- ScrArea *sa = NULL;
+ ScrArea *area = NULL;
const bool hide_panels = RNA_boolean_get(op->ptr, "use_hide_panels");
/* search current screen for 'fullscreen' areas */
/* prevents restoring info header, when mouse is over it */
- for (sa = screen->areabase.first; sa; sa = sa->next) {
- if (sa->full) {
+ for (area = screen->areabase.first; area; area = area->next) {
+ if (area->full) {
break;
}
}
- if (sa == NULL) {
- sa = CTX_wm_area(C);
+ if (area == NULL) {
+ area = CTX_wm_area(C);
}
if (hide_panels) {
if (!ELEM(screen->state, SCREENNORMAL, SCREENFULL)) {
return OPERATOR_CANCELLED;
}
- ED_screen_state_toggle(C, CTX_wm_window(C), sa, SCREENFULL);
+ ED_screen_state_toggle(C, CTX_wm_window(C), area, SCREENFULL);
}
else {
if (!ELEM(screen->state, SCREENNORMAL, SCREENMAXIMIZED)) {
return OPERATOR_CANCELLED;
}
- ED_screen_state_toggle(C, CTX_wm_window(C), sa, SCREENMAXIMIZED);
+ ED_screen_state_toggle(C, CTX_wm_window(C), area, SCREENMAXIMIZED);
}
return OPERATOR_FINISHED;
@@ -3381,7 +3388,7 @@ static void area_join_cancel(bContext *C, wmOperator *op)
/* modal callback while selecting area (space) that will be removed */
static int area_join_modal(bContext *C, wmOperator *op, const wmEvent *event)
{
- bScreen *sc = CTX_wm_screen(C);
+ bScreen *screen = CTX_wm_screen(C);
wmWindow *win = CTX_wm_window(C);
sAreaJoinData *jd;
@@ -3396,24 +3403,24 @@ static int area_join_modal(bContext *C, wmOperator *op, const wmEvent *event)
switch (event->type) {
case MOUSEMOVE: {
- ScrArea *sa = BKE_screen_find_area_xy(sc, SPACE_TYPE_ANY, event->x, event->y);
+ ScrArea *area = BKE_screen_find_area_xy(screen, SPACE_TYPE_ANY, event->x, event->y);
int dir = -1;
- if (sa) {
- if (jd->sa1 != sa) {
- dir = area_getorientation(jd->sa1, sa);
+ if (area) {
+ if (jd->sa1 != area) {
+ dir = area_getorientation(jd->sa1, area);
if (dir != -1) {
- jd->sa2 = sa;
+ jd->sa2 = area;
}
else {
/* we are not bordering on the previously selected area
* we check if area has common border with the one marked for removal
* in this case we can swap areas.
*/
- dir = area_getorientation(sa, jd->sa2);
+ dir = area_getorientation(area, jd->sa2);
if (dir != -1) {
jd->sa1 = jd->sa2;
- jd->sa2 = sa;
+ jd->sa2 = area;
}
else {
jd->sa2 = NULL;
@@ -3426,16 +3433,16 @@ static int area_join_modal(bContext *C, wmOperator *op, const wmEvent *event)
* we swap the areas if possible to allow user to choose */
if (jd->sa2 != NULL) {
jd->sa1 = jd->sa2;
- jd->sa2 = sa;
+ jd->sa2 = area;
dir = area_getorientation(jd->sa1, jd->sa2);
if (dir == -1) {
printf("oops, didn't expect that!\n");
}
}
else {
- dir = area_getorientation(jd->sa1, sa);
+ dir = area_getorientation(jd->sa1, area);
if (dir != -1) {
- jd->sa2 = sa;
+ jd->sa2 = area;
}
}
WM_event_add_notifier(C, NC_WINDOW, NULL);
@@ -3612,18 +3619,18 @@ static int spacedata_cleanup_exec(bContext *C, wmOperator *op)
{
Main *bmain = CTX_data_main(C);
bScreen *screen;
- ScrArea *sa;
+ ScrArea *area;
int tot = 0;
for (screen = bmain->screens.first; screen; screen = screen->id.next) {
- for (sa = screen->areabase.first; sa; sa = sa->next) {
- if (sa->spacedata.first != sa->spacedata.last) {
- SpaceLink *sl = sa->spacedata.first;
-
- BLI_remlink(&sa->spacedata, sl);
- tot += BLI_listbase_count(&sa->spacedata);
- BKE_spacedata_freelist(&sa->spacedata);
- BLI_addtail(&sa->spacedata, sl);
+ for (area = screen->areabase.first; area; area = area->next) {
+ if (area->spacedata.first != area->spacedata.last) {
+ SpaceLink *sl = area->spacedata.first;
+
+ BLI_remlink(&area->spacedata, sl);
+ tot += BLI_listbase_count(&area->spacedata);
+ BKE_spacedata_freelist(&area->spacedata);
+ BLI_addtail(&area->spacedata, sl);
}
}
}
@@ -3809,7 +3816,7 @@ static void view3d_localview_update_rv3d(struct RegionView3D *rv3d)
}
static void region_quadview_init_rv3d(
- ScrArea *sa, ARegion *region, const char viewlock, const char view, const char persp)
+ ScrArea *area, ARegion *region, const char viewlock, const char view, const char persp)
{
RegionView3D *rv3d = region->regiondata;
@@ -3826,7 +3833,7 @@ static void region_quadview_init_rv3d(
ED_view3d_lock(rv3d);
view3d_localview_update_rv3d(rv3d);
if ((viewlock & RV3D_BOXCLIP) && (persp == RV3D_ORTHO)) {
- ED_view3d_quadview_update(sa, region, true);
+ ED_view3d_quadview_update(area, region, true);
}
}
@@ -3841,24 +3848,24 @@ static int region_quadview_exec(bContext *C, wmOperator *op)
}
else if (region->alignment == RGN_ALIGN_QSPLIT) {
/* Exit quad-view */
- ScrArea *sa = CTX_wm_area(C);
+ ScrArea *area = CTX_wm_area(C);
ARegion *arn;
/* keep current region */
region->alignment = 0;
- if (sa->spacetype == SPACE_VIEW3D) {
- ARegion *ar_iter;
+ if (area->spacetype == SPACE_VIEW3D) {
+ ARegion *region_iter;
RegionView3D *rv3d = region->regiondata;
/* if this is a locked view, use settings from 'User' view */
if (rv3d->viewlock) {
View3D *v3d_user;
- ARegion *ar_user;
+ ARegion *region_user;
- if (ED_view3d_context_user_region(C, &v3d_user, &ar_user)) {
- if (region != ar_user) {
- SWAP(void *, region->regiondata, ar_user->regiondata);
+ if (ED_view3d_context_user_region(C, &v3d_user, &region_user)) {
+ if (region != region_user) {
+ SWAP(void *, region->regiondata, region_user->regiondata);
rv3d = region->regiondata;
}
}
@@ -3866,24 +3873,27 @@ static int region_quadview_exec(bContext *C, wmOperator *op)
rv3d->viewlock_quad = RV3D_VIEWLOCK_INIT;
rv3d->viewlock = 0;
- rv3d->rflag &= ~RV3D_CLIPPING;
+
+ /* FIXME: This fixes missing update to workbench TAA. (see T76216)
+ * However, it would be nice if the tagging should be done in a more conventional way. */
+ rv3d->rflag |= RV3D_GPULIGHT_UPDATE;
/* Accumulate locks, in case they're mixed. */
- for (ar_iter = sa->regionbase.first; ar_iter; ar_iter = ar_iter->next) {
- if (ar_iter->regiontype == RGN_TYPE_WINDOW) {
- RegionView3D *rv3d_iter = ar_iter->regiondata;
+ for (region_iter = area->regionbase.first; region_iter; region_iter = region_iter->next) {
+ if (region_iter->regiontype == RGN_TYPE_WINDOW) {
+ RegionView3D *rv3d_iter = region_iter->regiondata;
rv3d->viewlock_quad |= rv3d_iter->viewlock;
}
}
}
- for (region = sa->regionbase.first; region; region = arn) {
+ for (region = area->regionbase.first; region; region = arn) {
arn = region->next;
if (region->alignment == RGN_ALIGN_QSPLIT) {
- ED_region_remove(C, sa, region);
+ ED_region_remove(C, area, region);
}
}
- ED_area_tag_redraw(sa);
+ ED_area_tag_redraw(area);
WM_event_add_notifier(C, NC_SCREEN | NA_EDITED, NULL);
}
else if (region->next) {
@@ -3891,20 +3901,20 @@ static int region_quadview_exec(bContext *C, wmOperator *op)
}
else {
/* Enter quad-view */
- ScrArea *sa = CTX_wm_area(C);
+ ScrArea *area = CTX_wm_area(C);
ARegion *newar;
int count;
region->alignment = RGN_ALIGN_QSPLIT;
for (count = 0; count < 3; count++) {
- newar = BKE_area_region_copy(sa->type, region);
- BLI_addtail(&sa->regionbase, newar);
+ newar = BKE_area_region_copy(area->type, region);
+ BLI_addtail(&area->regionbase, newar);
}
/* lock views and set them */
- if (sa->spacetype == SPACE_VIEW3D) {
- View3D *v3d = sa->spacedata.first;
+ if (area->spacetype == SPACE_VIEW3D) {
+ View3D *v3d = area->spacedata.first;
int index_qsplit = 0;
/* run ED_view3d_lock() so the correct 'rv3d->viewquat' is set,
@@ -3919,13 +3929,13 @@ static int region_quadview_exec(bContext *C, wmOperator *op)
RV3D_LOCK_ROTATION;
region_quadview_init_rv3d(
- sa, region, viewlock, ED_view3d_lock_view_from_index(index_qsplit++), RV3D_ORTHO);
- region_quadview_init_rv3d(sa,
+ area, region, viewlock, ED_view3d_lock_view_from_index(index_qsplit++), RV3D_ORTHO);
+ region_quadview_init_rv3d(area,
(region = region->next),
viewlock,
ED_view3d_lock_view_from_index(index_qsplit++),
RV3D_ORTHO);
- region_quadview_init_rv3d(sa,
+ region_quadview_init_rv3d(area,
(region = region->next),
viewlock,
ED_view3d_lock_view_from_index(index_qsplit++),
@@ -3933,16 +3943,16 @@ static int region_quadview_exec(bContext *C, wmOperator *op)
/* forcing camera is distracting */
#if 0
if (v3d->camera) {
- region_quadview_init_rv3d(sa, (region = region->next), 0, RV3D_VIEW_CAMERA, RV3D_CAMOB);
+ region_quadview_init_rv3d(area, (region = region->next), 0, RV3D_VIEW_CAMERA, RV3D_CAMOB);
}
else {
- region_quadview_init_rv3d(sa, (region = region->next), 0, RV3D_VIEW_USER, RV3D_PERSP);
+ region_quadview_init_rv3d(area, (region = region->next), 0, RV3D_VIEW_USER, RV3D_PERSP);
}
#else
(void)v3d;
#endif
}
- ED_area_tag_redraw(sa);
+ ED_area_tag_redraw(area);
WM_event_add_notifier(C, NC_SCREEN | NA_EDITED, NULL);
}
@@ -4091,11 +4101,11 @@ static void SCREEN_OT_region_flip(wmOperatorType *ot)
/* show/hide header text menus */
static int header_toggle_menus_exec(bContext *C, wmOperator *UNUSED(op))
{
- ScrArea *sa = CTX_wm_area(C);
+ ScrArea *area = CTX_wm_area(C);
- sa->flag = sa->flag ^ HEADER_NO_PULLDOWN;
+ area->flag = area->flag ^ HEADER_NO_PULLDOWN;
- ED_area_tag_redraw(sa);
+ ED_area_tag_redraw(area);
WM_event_add_notifier(C, NC_SCREEN | NA_EDITED, NULL);
return OPERATOR_FINISHED;
@@ -4122,42 +4132,42 @@ static void SCREEN_OT_header_toggle_menus(wmOperatorType *ot)
static bool screen_region_context_menu_poll(bContext *C)
{
- ScrArea *sa = CTX_wm_area(C);
- return (sa && sa->spacetype != SPACE_STATUSBAR);
+ ScrArea *area = CTX_wm_area(C);
+ return (area && area->spacetype != SPACE_STATUSBAR);
}
void ED_screens_header_tools_menu_create(bContext *C, uiLayout *layout, void *UNUSED(arg))
{
- ScrArea *sa = CTX_wm_area(C);
+ ScrArea *area = CTX_wm_area(C);
ARegion *region = CTX_wm_region(C);
const char *but_flip_str = (RGN_ALIGN_ENUM_FROM_MASK(region->alignment) == RGN_ALIGN_TOP) ?
IFACE_("Flip to Bottom") :
IFACE_("Flip to Top");
{
PointerRNA ptr;
- RNA_pointer_create((ID *)CTX_wm_screen(C), &RNA_Space, sa->spacedata.first, &ptr);
- if (!ELEM(sa->spacetype, SPACE_TOPBAR)) {
+ RNA_pointer_create((ID *)CTX_wm_screen(C), &RNA_Space, area->spacedata.first, &ptr);
+ if (!ELEM(area->spacetype, SPACE_TOPBAR)) {
uiItemR(layout, &ptr, "show_region_header", 0, IFACE_("Show Header"), ICON_NONE);
}
- ARegion *ar_header = BKE_area_find_region_type(sa, RGN_TYPE_HEADER);
+ ARegion *region_header = BKE_area_find_region_type(area, RGN_TYPE_HEADER);
uiLayout *col = uiLayoutColumn(layout, 0);
- uiLayoutSetActive(col, (ar_header->flag & RGN_FLAG_HIDDEN) == 0);
+ uiLayoutSetActive(col, (region_header->flag & RGN_FLAG_HIDDEN) == 0);
- if (BKE_area_find_region_type(sa, RGN_TYPE_TOOL_HEADER)) {
+ if (BKE_area_find_region_type(area, RGN_TYPE_TOOL_HEADER)) {
uiItemR(col, &ptr, "show_region_tool_header", 0, IFACE_("Show Tool Settings"), ICON_NONE);
}
uiItemO(col,
IFACE_("Show Menus"),
- (sa->flag & HEADER_NO_PULLDOWN) ? ICON_CHECKBOX_DEHLT : ICON_CHECKBOX_HLT,
+ (area->flag & HEADER_NO_PULLDOWN) ? ICON_CHECKBOX_DEHLT : ICON_CHECKBOX_HLT,
"SCREEN_OT_header_toggle_menus");
}
/* default is WM_OP_INVOKE_REGION_WIN, which we don't want here. */
uiLayoutSetOperatorContext(layout, WM_OP_INVOKE_DEFAULT);
- if (!ELEM(sa->spacetype, SPACE_TOPBAR)) {
+ if (!ELEM(area->spacetype, SPACE_TOPBAR)) {
uiItemS(layout);
uiItemO(layout, but_flip_str, ICON_NONE, "SCREEN_OT_region_flip");
@@ -4165,24 +4175,24 @@ void ED_screens_header_tools_menu_create(bContext *C, uiLayout *layout, void *UN
/* File browser should be fullscreen all the time, top-bar should
* never be. But other regions can be maximized/restored. */
- if (!ELEM(sa->spacetype, SPACE_FILE, SPACE_TOPBAR)) {
+ if (!ELEM(area->spacetype, SPACE_FILE, SPACE_TOPBAR)) {
uiItemS(layout);
- const char *but_str = sa->full ? IFACE_("Tile Area") : IFACE_("Maximize Area");
+ const char *but_str = area->full ? IFACE_("Tile Area") : IFACE_("Maximize Area");
uiItemO(layout, but_str, ICON_NONE, "SCREEN_OT_screen_full_area");
}
}
void ED_screens_footer_tools_menu_create(bContext *C, uiLayout *layout, void *UNUSED(arg))
{
- ScrArea *sa = CTX_wm_area(C);
+ ScrArea *area = CTX_wm_area(C);
ARegion *region = CTX_wm_region(C);
const char *but_flip_str = (RGN_ALIGN_ENUM_FROM_MASK(region->alignment) == RGN_ALIGN_TOP) ?
IFACE_("Flip to Bottom") :
IFACE_("Flip to Top");
{
PointerRNA ptr;
- RNA_pointer_create((ID *)CTX_wm_screen(C), &RNA_Space, sa->spacedata.first, &ptr);
+ RNA_pointer_create((ID *)CTX_wm_screen(C), &RNA_Space, area->spacedata.first, &ptr);
uiItemR(layout, &ptr, "show_region_footer", 0, IFACE_("Show Footer"), ICON_NONE);
}
@@ -4193,10 +4203,10 @@ void ED_screens_footer_tools_menu_create(bContext *C, uiLayout *layout, void *UN
/* File browser should be fullscreen all the time, top-bar should
* never be. But other regions can be maximized/restored... */
- if (!ELEM(sa->spacetype, SPACE_FILE, SPACE_TOPBAR)) {
+ if (!ELEM(area->spacetype, SPACE_FILE, SPACE_TOPBAR)) {
uiItemS(layout);
- const char *but_str = sa->full ? IFACE_("Tile Area") : IFACE_("Maximize Area");
+ const char *but_str = area->full ? IFACE_("Tile Area") : IFACE_("Maximize Area");
uiItemO(layout, but_str, ICON_NONE, "SCREEN_OT_screen_full_area");
}
}
@@ -4383,9 +4393,9 @@ static int screen_animation_step(bContext *C, wmOperator *UNUSED(op), const wmEv
ScreenAnimData *sad = wt->customdata;
wmWindowManager *wm = CTX_wm_manager(C);
wmWindow *window;
- ScrArea *sa;
+ ScrArea *area;
int sync;
- float time;
+ double time;
/* sync, don't sync, or follow scene setting */
if (sad->flag & ANIMPLAY_FLAG_SYNC) {
@@ -4408,7 +4418,7 @@ static int screen_animation_step(bContext *C, wmOperator *UNUSED(op), const wmEv
}
else if ((scene->audio.flag & AUDIO_SYNC) && (sad->flag & ANIMPLAY_FLAG_REVERSE) == false &&
isfinite(time = BKE_sound_sync_scene(scene_eval))) {
- double newfra = (double)time * FPS;
+ double newfra = time * FPS;
/* give some space here to avoid jumps */
if (newfra + 0.5 > scene->r.cfra && newfra - 0.5 < scene->r.cfra) {
@@ -4432,10 +4442,29 @@ static int screen_animation_step(bContext *C, wmOperator *UNUSED(op), const wmEv
}
else {
if (sync) {
- /* note: this is very simplistic,
- * its has problem that it may skip too many frames.
- * however at least this gives a less jittery playback */
- const int step = max_ii(1, floor((wt->duration - sad->last_duration) * FPS));
+ /* Try to keep the playback in realtime by dropping frames. */
+
+ /* How much time (in frames) has passed since the last frame was drawn? */
+ double delta_frames = wt->delta * FPS;
+
+ /* Add the remaining fraction from the last time step. */
+ delta_frames += sad->lagging_frame_count;
+
+ if (delta_frames < 1.0) {
+ /* We can render faster than the scene frame rate. However skipping or delaying frames
+ * here seems to in practice lead to jittery playback so just step forward a minimum of
+ * one frame. (Even though this can lead to too fast playback, the jitteryness is more
+ * annoying)
+ */
+ delta_frames = 1.0f;
+ sad->lagging_frame_count = 0;
+ }
+ else {
+ /* Extract the delta frame fractions that will be skipped when converting to int. */
+ sad->lagging_frame_count = delta_frames - (int)delta_frames;
+ }
+
+ const int step = delta_frames;
/* skip frames */
if (sad->flag & ANIMPLAY_FLAG_REVERSE) {
@@ -4456,8 +4485,6 @@ static int screen_animation_step(bContext *C, wmOperator *UNUSED(op), const wmEv
}
}
- sad->last_duration = wt->duration;
-
/* reset 'jumped' flag before checking if we need to jump... */
sad->flag &= ~ANIMPLAY_FLAG_JUMPED;
@@ -4514,15 +4541,15 @@ static int screen_animation_step(bContext *C, wmOperator *UNUSED(op), const wmEv
for (window = wm->windows.first; window; window = window->next) {
const bScreen *win_screen = WM_window_get_active_screen(window);
- for (sa = win_screen->areabase.first; sa; sa = sa->next) {
+ for (area = win_screen->areabase.first; area; area = area->next) {
ARegion *region;
- for (region = sa->regionbase.first; region; region = region->next) {
+ for (region = area->regionbase.first; region; region = region->next) {
bool redraw = false;
if (region == sad->region) {
redraw = true;
}
else if (match_region_with_redraws(
- sa->spacetype, region->regiontype, sad->redraws, sad->from_anim_edit)) {
+ area->spacetype, region->regiontype, sad->redraws, sad->from_anim_edit)) {
redraw = true;
}
@@ -4531,8 +4558,8 @@ static int screen_animation_step(bContext *C, wmOperator *UNUSED(op), const wmEv
/* do follow here if editor type supports it */
if ((sad->redraws & TIME_FOLLOW)) {
if ((region->regiontype == RGN_TYPE_WINDOW &&
- ELEM(sa->spacetype, SPACE_SEQ, SPACE_GRAPH, SPACE_ACTION, SPACE_NLA)) ||
- (sa->spacetype == SPACE_CLIP && region->regiontype == RGN_TYPE_PREVIEW)) {
+ ELEM(area->spacetype, SPACE_SEQ, SPACE_GRAPH, SPACE_ACTION, SPACE_NLA)) ||
+ (area->spacetype == SPACE_CLIP && region->regiontype == RGN_TYPE_PREVIEW)) {
float w = BLI_rctf_size_x(&region->v2d.cur);
if (scene->r.cfra < region->v2d.cur.xmin) {
region->v2d.cur.xmax = scene->r.cfra;
@@ -4591,7 +4618,7 @@ static void SCREEN_OT_animation_step(wmOperatorType *ot)
/* find window that owns the animation timer */
bScreen *ED_screen_animation_playing(const wmWindowManager *wm)
{
- for (wmWindow *win = wm->windows.first; win; win = win->next) {
+ LISTBASE_FOREACH (wmWindow *, win, &wm->windows) {
bScreen *screen = WM_window_get_active_screen(win);
if (screen->animtimer || screen->scrubbing) {
@@ -4604,7 +4631,7 @@ bScreen *ED_screen_animation_playing(const wmWindowManager *wm)
bScreen *ED_screen_animation_no_scrub(const wmWindowManager *wm)
{
- for (wmWindow *win = wm->windows.first; win; win = win->next) {
+ LISTBASE_FOREACH (wmWindow *, win, &wm->windows) {
bScreen *screen = WM_window_get_active_screen(win);
if (screen->animtimer) {
@@ -4803,20 +4830,20 @@ static void SCREEN_OT_box_select(wmOperatorType *ot)
static int fullscreen_back_exec(bContext *C, wmOperator *op)
{
bScreen *screen = CTX_wm_screen(C);
- ScrArea *sa = NULL;
+ ScrArea *area = NULL;
/* search current screen for 'fullscreen' areas */
- for (sa = screen->areabase.first; sa; sa = sa->next) {
- if (sa->full) {
+ for (area = screen->areabase.first; area; area = area->next) {
+ if (area->full) {
break;
}
}
- if (!sa) {
+ if (!area) {
BKE_report(op->reports, RPT_ERROR, "No fullscreen areas were found");
return OPERATOR_CANCELLED;
}
- ED_screen_full_prevspace(C, sa);
+ ED_screen_full_prevspace(C, area);
return OPERATOR_FINISHED;
}
@@ -4839,8 +4866,11 @@ static void SCREEN_OT_back_to_previous(struct wmOperatorType *ot)
/** \name Show User Preferences Operator
* \{ */
-static int userpref_show_invoke(bContext *C, wmOperator *op, const wmEvent *event)
+static int userpref_show_exec(bContext *C, wmOperator *op)
{
+ wmWindow *win_cur = CTX_wm_window(C);
+ /* Use eventstate, not event from _invoke, so this can be called through exec(). */
+ const wmEvent *event = win_cur->eventstate;
int sizex = (500 + UI_NAVIGATION_REGION_WIDTH) * UI_DPI_FAC;
int sizey = 520 * UI_DPI_FAC;
@@ -4877,7 +4907,7 @@ static void SCREEN_OT_userpref_show(struct wmOperatorType *ot)
ot->idname = "SCREEN_OT_userpref_show";
/* api callbacks */
- ot->invoke = userpref_show_invoke;
+ ot->exec = userpref_show_exec;
ot->poll = ED_operator_screenactive;
}
@@ -4887,8 +4917,11 @@ static void SCREEN_OT_userpref_show(struct wmOperatorType *ot)
/** \name Show Drivers Editor Operator
* \{ */
-static int drivers_editor_show_invoke(bContext *C, wmOperator *op, const wmEvent *event)
+static int drivers_editor_show_exec(bContext *C, wmOperator *op)
{
+ wmWindow *win_cur = CTX_wm_window(C);
+ /* Use eventstate, not event from _invoke, so this can be called through exec(). */
+ const wmEvent *event = win_cur->eventstate;
PointerRNA ptr = {NULL};
PropertyRNA *prop = NULL;
int index = -1;
@@ -4919,7 +4952,7 @@ static int drivers_editor_show_invoke(bContext *C, wmOperator *op, const wmEvent
FCurve *fcu;
bool driven, special;
- fcu = rna_get_fcurve_context_ui(C, &ptr, prop, index, NULL, NULL, &driven, &special);
+ fcu = BKE_fcurve_find_by_rna_context_ui(C, &ptr, prop, index, NULL, NULL, &driven, &special);
if (fcu) {
/* Isolate this F-Curve... */
bAnimContext ac;
@@ -4952,7 +4985,7 @@ static void SCREEN_OT_drivers_editor_show(struct wmOperatorType *ot)
ot->idname = "SCREEN_OT_drivers_editor_show";
/* api callbacks */
- ot->invoke = drivers_editor_show_invoke;
+ ot->exec = drivers_editor_show_exec;
ot->poll = ED_operator_screenactive;
}
@@ -4962,8 +4995,11 @@ static void SCREEN_OT_drivers_editor_show(struct wmOperatorType *ot)
/** \name Show Info Log Operator
* \{ */
-static int info_log_show_invoke(bContext *C, wmOperator *op, const wmEvent *event)
+static int info_log_show_exec(bContext *C, wmOperator *op)
{
+ wmWindow *win_cur = CTX_wm_window(C);
+ /* Use eventstate, not event from _invoke, so this can be called through exec(). */
+ const wmEvent *event = win_cur->eventstate;
int sizex = 900 * UI_DPI_FAC;
int sizey = 580 * UI_DPI_FAC;
int shift_y = 480;
@@ -4993,7 +5029,7 @@ static void SCREEN_OT_info_log_show(struct wmOperatorType *ot)
ot->idname = "SCREEN_OT_info_log_show";
/* api callbacks */
- ot->invoke = info_log_show_invoke;
+ ot->exec = info_log_show_exec;
ot->poll = ED_operator_screenactive;
}
@@ -5037,9 +5073,9 @@ static void SCREEN_OT_new(wmOperatorType *ot)
static int screen_delete_exec(bContext *C, wmOperator *UNUSED(op))
{
- bScreen *sc = CTX_wm_screen(C);
+ bScreen *screen = CTX_wm_screen(C);
WorkSpace *workspace = CTX_wm_workspace(C);
- WorkSpaceLayout *layout = BKE_workspace_layout_find(workspace, sc);
+ WorkSpaceLayout *layout = BKE_workspace_layout_find(workspace, screen);
WM_event_add_notifier(C, NC_SCREEN | ND_LAYOUTDELETE, layout);
@@ -5069,8 +5105,8 @@ static void SCREEN_OT_delete(wmOperatorType *ot)
* \{ */
typedef struct RegionAlphaInfo {
- ScrArea *sa;
- ARegion *region, *child_ar; /* other region */
+ ScrArea *area;
+ ARegion *region, *child_region; /* other region */
int hidden;
} RegionAlphaInfo;
@@ -5107,8 +5143,8 @@ static void region_blend_end(bContext *C, ARegion *region, const bool is_running
/* always send redraw */
ED_region_tag_redraw(region);
- if (rgi->child_ar) {
- ED_region_tag_redraw(rgi->child_ar);
+ if (rgi->child_region) {
+ ED_region_tag_redraw(rgi->child_region);
}
/* if running timer was hiding, the flag toggle went wrong */
@@ -5120,10 +5156,10 @@ static void region_blend_end(bContext *C, ARegion *region, const bool is_running
else {
if (rgi->hidden) {
rgi->region->flag |= rgi->hidden;
- ED_area_initialize(CTX_wm_manager(C), CTX_wm_window(C), rgi->sa);
+ ED_area_initialize(CTX_wm_manager(C), CTX_wm_window(C), rgi->area);
}
/* area decoration needs redraw in end */
- ED_area_tag_redraw(rgi->sa);
+ ED_area_tag_redraw(rgi->area);
}
WM_event_remove_timer(CTX_wm_manager(C), NULL, region->regiontimer); /* frees rgi */
region->regiontimer = NULL;
@@ -5131,7 +5167,7 @@ static void region_blend_end(bContext *C, ARegion *region, const bool is_running
/**
* \note Assumes that \a region itself is not a split version from previous region.
*/
-void ED_region_visibility_change_update_animated(bContext *C, ScrArea *sa, ARegion *region)
+void ED_region_visibility_change_update_animated(bContext *C, ScrArea *area, ARegion *region)
{
wmWindowManager *wm = CTX_wm_manager(C);
wmWindow *win = CTX_wm_window(C);
@@ -5145,13 +5181,13 @@ void ED_region_visibility_change_update_animated(bContext *C, ScrArea *sa, ARegi
rgi = MEM_callocN(sizeof(RegionAlphaInfo), "RegionAlphaInfo");
rgi->hidden = region->flag & RGN_FLAG_HIDDEN;
- rgi->sa = sa;
+ rgi->area = area;
rgi->region = region;
region->flag &= ~RGN_FLAG_HIDDEN;
/* blend in, reinitialize regions because it got unhidden */
if (rgi->hidden == 0) {
- ED_area_initialize(wm, win, sa);
+ ED_area_initialize(wm, win, area);
}
else {
WM_event_remove_handlers(C, &region->handlers);
@@ -5159,7 +5195,7 @@ void ED_region_visibility_change_update_animated(bContext *C, ScrArea *sa, ARegi
if (region->next) {
if (region->next->alignment & RGN_SPLIT_PREV) {
- rgi->child_ar = region->next;
+ rgi->child_region = region->next;
}
}
@@ -5183,8 +5219,8 @@ static int region_blend_invoke(bContext *C, wmOperator *UNUSED(op), const wmEven
/* always send redraws */
ED_region_tag_redraw(rgi->region);
- if (rgi->child_ar) {
- ED_region_tag_redraw(rgi->child_ar);
+ if (rgi->child_region) {
+ ED_region_tag_redraw(rgi->child_region);
}
/* end timer? */
@@ -5220,8 +5256,8 @@ static void SCREEN_OT_region_blend(wmOperatorType *ot)
static bool space_type_set_or_cycle_poll(bContext *C)
{
- ScrArea *sa = CTX_wm_area(C);
- return (sa && !ELEM(sa->spacetype, SPACE_TOPBAR, SPACE_STATUSBAR));
+ ScrArea *area = CTX_wm_area(C);
+ return (area && !ELEM(area->spacetype, SPACE_TOPBAR, SPACE_STATUSBAR));
}
static int space_type_set_or_cycle_exec(bContext *C, wmOperator *op)
@@ -5229,12 +5265,12 @@ static int space_type_set_or_cycle_exec(bContext *C, wmOperator *op)
const int space_type = RNA_enum_get(op->ptr, "space_type");
PointerRNA ptr;
- ScrArea *sa = CTX_wm_area(C);
- RNA_pointer_create((ID *)CTX_wm_screen(C), &RNA_Area, sa, &ptr);
+ ScrArea *area = CTX_wm_area(C);
+ RNA_pointer_create((ID *)CTX_wm_screen(C), &RNA_Area, area, &ptr);
PropertyRNA *prop_type = RNA_struct_find_property(&ptr, "type");
PropertyRNA *prop_ui_type = RNA_struct_find_property(&ptr, "ui_type");
- if (sa->spacetype != space_type) {
+ if (area->spacetype != space_type) {
/* Set the type. */
RNA_property_enum_set(&ptr, prop_type, space_type);
RNA_property_update(C, &ptr, prop_type);
@@ -5293,25 +5329,25 @@ static const EnumPropertyItem space_context_cycle_direction[] = {
static bool space_context_cycle_poll(bContext *C)
{
- ScrArea *sa = CTX_wm_area(C);
- /* sa might be NULL if called out of window bounds */
- return (sa && ELEM(sa->spacetype, SPACE_PROPERTIES, SPACE_USERPREF));
+ ScrArea *area = CTX_wm_area(C);
+ /* area might be NULL if called out of window bounds */
+ return (area && ELEM(area->spacetype, SPACE_PROPERTIES, SPACE_USERPREF));
}
/**
* Helper to get the correct RNA pointer/property pair for changing
- * the display context of active space type in \a sa.
+ * the display context of active space type in \a area.
*/
static void context_cycle_prop_get(bScreen *screen,
- const ScrArea *sa,
+ const ScrArea *area,
PointerRNA *r_ptr,
PropertyRNA **r_prop)
{
const char *propname;
- switch (sa->spacetype) {
+ switch (area->spacetype) {
case SPACE_PROPERTIES:
- RNA_pointer_create(&screen->id, &RNA_SpaceProperties, sa->spacedata.first, r_ptr);
+ RNA_pointer_create(&screen->id, &RNA_SpaceProperties, area->spacedata.first, r_ptr);
propname = "context";
break;
case SPACE_USERPREF:
@@ -5384,7 +5420,7 @@ static int space_workspace_cycle_invoke(bContext *C, wmOperator *op, const wmEve
ListBase ordered;
BKE_id_ordered_list(&ordered, &bmain->workspaces);
- for (LinkData *link = ordered.first; link; link = link->next) {
+ LISTBASE_FOREACH (LinkData *, link, &ordered) {
if (link->data == workspace_src) {
if (direction == SPACE_CONTEXT_CYCLE_PREV) {
workspace_dst = (link->prev) ? link->prev->data : NULL;
@@ -5517,7 +5553,7 @@ static void keymap_modal_set(wmKeyConfig *keyconf)
wmKeyMap *keymap;
/* Standard Modal keymap ------------------------------------------------ */
- keymap = WM_modalkeymap_add(keyconf, "Standard Modal Map", modal_items);
+ keymap = WM_modalkeymap_ensure(keyconf, "Standard Modal Map", modal_items);
WM_modalkeymap_assign(keymap, "SCREEN_OT_area_move");
}
diff --git a/source/blender/editors/screen/screen_user_menu.c b/source/blender/editors/screen/screen_user_menu.c
index 38d83801f2b..733e8b694a6 100644
--- a/source/blender/editors/screen/screen_user_menu.c
+++ b/source/blender/editors/screen/screen_user_menu.c
@@ -113,7 +113,7 @@ bUserMenuItem_Op *ED_screen_user_menu_item_find_operator(ListBase *lb,
IDProperty *prop,
short opcontext)
{
- for (bUserMenuItem *umi = lb->first; umi; umi = umi->next) {
+ LISTBASE_FOREACH (bUserMenuItem *, umi, lb) {
if (umi->type == USER_MENU_TYPE_OPERATOR) {
bUserMenuItem_Op *umi_op = (bUserMenuItem_Op *)umi;
if (STREQ(ot->idname, umi_op->op_idname) && (opcontext == umi_op->opcontext) &&
@@ -128,7 +128,7 @@ bUserMenuItem_Op *ED_screen_user_menu_item_find_operator(ListBase *lb,
struct bUserMenuItem_Menu *ED_screen_user_menu_item_find_menu(struct ListBase *lb,
const struct MenuType *mt)
{
- for (bUserMenuItem *umi = lb->first; umi; umi = umi->next) {
+ LISTBASE_FOREACH (bUserMenuItem *, umi, lb) {
if (umi->type == USER_MENU_TYPE_MENU) {
bUserMenuItem_Menu *umi_mt = (bUserMenuItem_Menu *)umi;
if (STREQ(mt->idname, umi_mt->mt_idname)) {
@@ -144,7 +144,7 @@ struct bUserMenuItem_Prop *ED_screen_user_menu_item_find_prop(struct ListBase *l
const char *prop_id,
int prop_index)
{
- for (bUserMenuItem *umi = lb->first; umi; umi = umi->next) {
+ LISTBASE_FOREACH (bUserMenuItem *, umi, lb) {
if (umi->type == USER_MENU_TYPE_PROP) {
bUserMenuItem_Prop *umi_pr = (bUserMenuItem_Prop *)umi;
if (STREQ(context_data_path, umi_pr->context_data_path) && STREQ(prop_id, umi_pr->prop_id) &&
@@ -222,7 +222,7 @@ static void screen_user_menu_draw(const bContext *C, Menu *menu)
if (um == NULL) {
continue;
}
- for (bUserMenuItem *umi = um->items.first; umi; umi = umi->next) {
+ LISTBASE_FOREACH (bUserMenuItem *, umi, &um->items) {
const char *ui_name = umi->ui_name[0] ? umi->ui_name : NULL;
if (umi->type == USER_MENU_TYPE_OPERATOR) {
bUserMenuItem_Op *umi_op = (bUserMenuItem_Op *)umi;
diff --git a/source/blender/editors/screen/screendump.c b/source/blender/editors/screen/screendump.c
index d52dc262c3f..83ded5b3503 100644
--- a/source/blender/editors/screen/screendump.c
+++ b/source/blender/editors/screen/screendump.c
@@ -54,7 +54,7 @@
#include "screen_intern.h"
typedef struct ScreenshotData {
- unsigned int *dumprect;
+ uint *dumprect;
int dumpsx, dumpsy;
rcti crop;
@@ -76,13 +76,13 @@ static int screenshot_data_create(bContext *C, wmOperator *op)
if (dumprect) {
ScreenshotData *scd = MEM_callocN(sizeof(ScreenshotData), "screenshot");
- ScrArea *sa = CTX_wm_area(C);
+ ScrArea *area = CTX_wm_area(C);
scd->dumpsx = dumprect_size[0];
scd->dumpsy = dumprect_size[1];
scd->dumprect = dumprect;
- if (sa) {
- scd->crop = sa->totrct;
+ if (area) {
+ scd->crop = area->totrct;
}
BKE_imformat_defaults(&scd->im_format);
diff --git a/source/blender/editors/screen/workspace_edit.c b/source/blender/editors/screen/workspace_edit.c
index 784fa60999d..478a0adfd9a 100644
--- a/source/blender/editors/screen/workspace_edit.c
+++ b/source/blender/editors/screen/workspace_edit.c
@@ -83,8 +83,7 @@ static void workspace_change_update(WorkSpace *workspace_new,
eObjectMode mode_new = workspace_new->object_mode;
if (mode_old != mode_new) {
- ED_object_mode_compat_set(C, ob_act, mode_new, &wm->reports);
- ED_object_mode_toggle(C, mode_new);
+ ED_object_mode_set(C, mode_new);
}
#endif
}
@@ -109,9 +108,9 @@ static WorkSpaceLayout *workspace_change_get_new_layout(Main *bmain,
layout_new = win->workspace_hook->temp_layout_store;
}
else {
- layout_new = BKE_workspace_hook_layout_for_workspace_get(win->workspace_hook, workspace_new);
+ layout_new = BKE_workspace_active_layout_for_workspace_get(win->workspace_hook, workspace_new);
if (!layout_new) {
- layout_new = BKE_workspace_layouts_get(workspace_new)->first;
+ layout_new = workspace_new->layouts.first;
}
}
screen_new = BKE_workspace_layout_screen_get(layout_new);
@@ -163,7 +162,7 @@ bool ED_workspace_change(WorkSpace *workspace_new, bContext *C, wmWindowManager
return false;
}
- BKE_workspace_hook_layout_for_workspace_set(win->workspace_hook, workspace_new, layout_new);
+ BKE_workspace_active_layout_set(win->workspace_hook, workspace_new, layout_new);
BKE_workspace_active_set(win->workspace_hook, workspace_new);
/* update screen *after* changing workspace - which also causes the
@@ -175,7 +174,7 @@ bool ED_workspace_change(WorkSpace *workspace_new, bContext *C, wmWindowManager
/* Automatic mode switching. */
if (workspace_new->object_mode != workspace_old->object_mode) {
- ED_object_mode_generic_enter(C, workspace_new->object_mode);
+ ED_object_mode_set(C, workspace_new->object_mode);
}
return true;
@@ -188,7 +187,6 @@ bool ED_workspace_change(WorkSpace *workspace_new, bContext *C, wmWindowManager
WorkSpace *ED_workspace_duplicate(WorkSpace *workspace_old, Main *bmain, wmWindow *win)
{
WorkSpaceLayout *layout_active_old = BKE_workspace_active_layout_get(win->workspace_hook);
- ListBase *layouts_old = BKE_workspace_layouts_get(workspace_old);
WorkSpace *workspace_new = ED_workspace_add(bmain, workspace_old->id.name + 2);
workspace_new->flags = workspace_old->flags;
@@ -198,8 +196,7 @@ WorkSpace *ED_workspace_duplicate(WorkSpace *workspace_old, Main *bmain, wmWindo
/* TODO(campbell): tools */
- for (WorkSpaceLayout *layout_old = layouts_old->first; layout_old;
- layout_old = layout_old->next) {
+ LISTBASE_FOREACH (WorkSpaceLayout *, layout_old, &workspace_old->layouts) {
WorkSpaceLayout *layout_new = ED_workspace_layout_duplicate(
bmain, workspace_new, layout_old, win);
@@ -222,7 +219,7 @@ bool ED_workspace_delete(WorkSpace *workspace, Main *bmain, bContext *C, wmWindo
ListBase ordered;
BKE_id_ordered_list(&ordered, &bmain->workspaces);
WorkSpace *prev = NULL, *next = NULL;
- for (LinkData *link = ordered.first; link; link = link->next) {
+ LISTBASE_FOREACH (LinkData *, link, &ordered) {
if (link->data == workspace) {
prev = link->prev ? link->prev->data : NULL;
next = link->next ? link->next->data : NULL;
@@ -232,7 +229,7 @@ bool ED_workspace_delete(WorkSpace *workspace, Main *bmain, bContext *C, wmWindo
BLI_freelistN(&ordered);
BLI_assert((prev != NULL) || (next != NULL));
- for (wmWindow *win = wm->windows.first; win; win = win->next) {
+ LISTBASE_FOREACH (wmWindow *, win, &wm->windows) {
WorkSpace *workspace_active = WM_window_get_active_workspace(win);
if (workspace_active == workspace) {
ED_workspace_change((prev != NULL) ? prev : next, C, wm, win);
@@ -481,7 +478,7 @@ static int workspace_add_invoke(bContext *C, wmOperator *op, const wmEvent *UNUS
ListBase templates;
BKE_appdir_app_templates(&templates);
- for (LinkData *link = templates.first; link; link = link->next) {
+ LISTBASE_FOREACH (LinkData *, link, &templates) {
char *template = link->data;
char display_name[FILE_MAX];
diff --git a/source/blender/editors/screen/workspace_layout_edit.c b/source/blender/editors/screen/workspace_layout_edit.c
index 276e36b97dc..7ce92bc3e4d 100644
--- a/source/blender/editors/screen/workspace_layout_edit.c
+++ b/source/blender/editors/screen/workspace_layout_edit.c
@@ -68,7 +68,7 @@ WorkSpaceLayout *ED_workspace_layout_duplicate(Main *bmain,
screen_new = BKE_workspace_layout_screen_get(layout_new);
if (BKE_screen_is_fullscreen_area(screen_old)) {
- for (ScrArea *area_old = screen_old->areabase.first; area_old; area_old = area_old->next) {
+ LISTBASE_FOREACH (ScrArea *, area_old, &screen_old->areabase) {
if (area_old->full) {
ScrArea *area_new = (ScrArea *)screen_new->areabase.first;
ED_area_data_copy(area_new, area_old, true);
@@ -140,7 +140,7 @@ bool ED_workspace_layout_delete(WorkSpace *workspace, WorkSpaceLayout *layout_ol
const bScreen *screen_old = BKE_workspace_layout_screen_get(layout_old);
WorkSpaceLayout *layout_new;
- BLI_assert(BLI_findindex(BKE_workspace_layouts_get(workspace), layout_old) != -1);
+ BLI_assert(BLI_findindex(&workspace->layouts, layout_old) != -1);
/* don't allow deleting temp fullscreens for now */
if (BKE_screen_is_fullscreen_area(screen_old)) {
@@ -172,9 +172,9 @@ bool ED_workspace_layout_cycle(WorkSpace *workspace, const short direction, bCon
WorkSpaceLayout *old_layout = BKE_workspace_active_layout_get(win->workspace_hook);
WorkSpaceLayout *new_layout;
const bScreen *old_screen = BKE_workspace_layout_screen_get(old_layout);
- ScrArea *sa = CTX_wm_area(C);
+ ScrArea *area = CTX_wm_area(C);
- if (old_screen->temp || (sa && sa->full && sa->full->temp)) {
+ if (old_screen->temp || (area && area->full && area->full->temp)) {
return false;
}
@@ -188,9 +188,9 @@ bool ED_workspace_layout_cycle(WorkSpace *workspace, const short direction, bCon
if (new_layout && (old_layout != new_layout)) {
bScreen *new_screen = BKE_workspace_layout_screen_get(new_layout);
- if (sa && sa->full) {
+ if (area && area->full) {
/* return to previous state before switching screens */
- ED_screen_full_restore(C, sa); /* may free screen of old_layout */
+ ED_screen_full_restore(C, area); /* may free screen of old_layout */
}
ED_screen_change(C, new_screen);
diff --git a/source/blender/editors/sculpt_paint/CMakeLists.txt b/source/blender/editors/sculpt_paint/CMakeLists.txt
index de9e70f8e06..b8754953741 100644
--- a/source/blender/editors/sculpt_paint/CMakeLists.txt
+++ b/source/blender/editors/sculpt_paint/CMakeLists.txt
@@ -59,9 +59,18 @@ set(SRC
paint_vertex_weight_ops.c
paint_vertex_weight_utils.c
sculpt.c
+ sculpt_automasking.c
sculpt_cloth.c
+ sculpt_detail.c
+ sculpt_dyntopo.c
+ sculpt_face_set.c
+ sculpt_filter_mask.c
+ sculpt_filter_mesh.c
+ sculpt_mask_expand.c
sculpt_multiplane_scrape.c
sculpt_pose.c
+ sculpt_smooth.c
+ sculpt_transform.c
sculpt_undo.c
sculpt_uv.c
diff --git a/source/blender/editors/sculpt_paint/paint_cursor.c b/source/blender/editors/sculpt_paint/paint_cursor.c
index c035863203b..4222a466a7b 100644
--- a/source/blender/editors/sculpt_paint/paint_cursor.c
+++ b/source/blender/editors/sculpt_paint/paint_cursor.c
@@ -10,7 +10,7 @@
* 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,
+ * 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) 2009 by Nicholas Bishop
@@ -171,6 +171,8 @@ static void load_tex_task_cb_ex(void *__restrict userdata,
bool convert_to_linear = false;
struct ColorSpace *colorspace = NULL;
+ const int thread_id = BLI_task_parallel_thread_id(tls);
+
if (mtex->tex && mtex->tex->type == TEX_IMAGE && mtex->tex->ima) {
ImBuf *tex_ibuf = BKE_image_pool_acquire_ibuf(mtex->tex->ima, &mtex->tex->iuser, pool);
/* For consistency, sampling always returns color in linear space. */
@@ -214,8 +216,7 @@ static void load_tex_task_cb_ex(void *__restrict userdata,
if (col) {
float rgba[4];
- paint_get_tex_pixel_col(
- mtex, x, y, rgba, pool, tls->thread_id, convert_to_linear, colorspace);
+ paint_get_tex_pixel_col(mtex, x, y, rgba, pool, thread_id, convert_to_linear, colorspace);
buffer[index * 4] = rgba[0] * 255;
buffer[index * 4 + 1] = rgba[1] * 255;
@@ -223,7 +224,7 @@ static void load_tex_task_cb_ex(void *__restrict userdata,
buffer[index * 4 + 3] = rgba[3] * 255;
}
else {
- float avg = paint_get_tex_pixel(mtex, x, y, pool, tls->thread_id);
+ float avg = paint_get_tex_pixel(mtex, x, y, pool, thread_id);
avg += br->texture_sample_bias;
@@ -876,12 +877,8 @@ static bool paint_draw_alpha_overlay(UnifiedPaintSettings *ups,
return alpha_overlay_active;
}
-BLI_INLINE void draw_tri_point(unsigned int pos,
- const float sel_col[4],
- float pivot_col[4],
- float *co,
- float width,
- bool selected)
+BLI_INLINE void draw_tri_point(
+ uint pos, const float sel_col[4], float pivot_col[4], float *co, float width, bool selected)
{
immUniformColor4fv(selected ? sel_col : pivot_col);
@@ -910,12 +907,8 @@ BLI_INLINE void draw_tri_point(unsigned int pos,
immEnd();
}
-BLI_INLINE void draw_rect_point(unsigned int pos,
- const float sel_col[4],
- float handle_col[4],
- float *co,
- float width,
- bool selected)
+BLI_INLINE void draw_rect_point(
+ uint pos, const float sel_col[4], float handle_col[4], float *co, float width, bool selected)
{
immUniformColor4fv(selected ? sel_col : handle_col);
@@ -935,7 +928,7 @@ BLI_INLINE void draw_rect_point(unsigned int pos,
imm_draw_box_wire_2d(pos, minx, miny, maxx, maxy);
}
-BLI_INLINE void draw_bezier_handle_lines(unsigned int pos, float sel_col[4], BezTriple *bez)
+BLI_INLINE void draw_bezier_handle_lines(uint pos, float sel_col[4], BezTriple *bez)
{
immUniformColor4f(0.0f, 0.0f, 0.0f, 0.5f);
GPU_line_width(3.0f);
@@ -1224,6 +1217,34 @@ static void sculpt_geometry_preview_lines_draw(const uint gpuattr, SculptSession
}
}
+static void SCULPT_layer_brush_height_preview_draw(const uint gpuattr,
+ const Brush *brush,
+ const float obmat[4][4],
+ const float location[3],
+ const float normal[3],
+ const float rds,
+ const float line_width,
+ const float outline_col[3],
+ const float alpha)
+{
+ float cursor_trans[4][4], cursor_rot[4][4];
+ float z_axis[4] = {0.0f, 0.0f, 1.0f, 0.0f};
+ float quat[4];
+ float height_preview_trans[3];
+ copy_m4_m4(cursor_trans, obmat);
+ madd_v3_v3v3fl(height_preview_trans, location, normal, brush->height);
+ translate_m4(
+ cursor_trans, height_preview_trans[0], height_preview_trans[1], height_preview_trans[2]);
+ rotation_between_vecs_to_quat(quat, z_axis, normal);
+ quat_to_mat4(cursor_rot, quat);
+ GPU_matrix_mul(cursor_trans);
+ GPU_matrix_mul(cursor_rot);
+
+ GPU_line_width(line_width);
+ immUniformColor3fvAlpha(outline_col, alpha * 0.5f);
+ imm_draw_circle_wire_3d(gpuattr, 0, 0, rds, 80);
+}
+
static bool paint_use_2d_cursor(ePaintMode mode)
{
if (mode >= PAINT_MODE_TEXTURE_3D) {
@@ -1484,6 +1505,21 @@ static void paint_draw_cursor(bContext *C, int x, int y, void *UNUSED(unused))
GPU_matrix_pop();
}
+ /* Layer brush height. */
+ if (brush->sculpt_tool == SCULPT_TOOL_LAYER) {
+ GPU_matrix_push();
+ SCULPT_layer_brush_height_preview_draw(pos,
+ brush,
+ vc.obact->obmat,
+ gi.location,
+ gi.normal,
+ rds,
+ 1.0f,
+ outline_col,
+ outline_alpha);
+ GPU_matrix_pop();
+ }
+
/* Update and draw dynamic mesh preview lines. */
GPU_matrix_push();
GPU_matrix_mul(vc.obact->obmat);
@@ -1638,23 +1674,13 @@ static void paint_draw_cursor(bContext *C, int x, int y, void *UNUSED(unused))
/* Public API */
-void paint_cursor_start(bContext *C, bool (*poll)(bContext *C))
+void paint_cursor_start(Paint *p, bool (*poll)(bContext *C))
{
- Paint *p = BKE_paint_get_active_from_context(C);
-
if (p && !p->paint_cursor) {
p->paint_cursor = WM_paint_cursor_activate(
- CTX_wm_manager(C), SPACE_TYPE_ANY, RGN_TYPE_ANY, poll, paint_draw_cursor, NULL);
+ SPACE_TYPE_ANY, RGN_TYPE_ANY, poll, paint_draw_cursor, NULL);
}
/* Invalidate the paint cursors. */
BKE_paint_invalidate_overlay_all();
}
-
-void paint_cursor_start_explicit(Paint *p, wmWindowManager *wm, bool (*poll)(bContext *C))
-{
- if (p && !p->paint_cursor) {
- p->paint_cursor = WM_paint_cursor_activate(
- wm, SPACE_TYPE_ANY, RGN_TYPE_ANY, poll, paint_draw_cursor, NULL);
- }
-}
diff --git a/source/blender/editors/sculpt_paint/paint_curve_undo.c b/source/blender/editors/sculpt_paint/paint_curve_undo.c
index 5797eb68dd3..a3daef19f11 100644
--- a/source/blender/editors/sculpt_paint/paint_curve_undo.c
+++ b/source/blender/editors/sculpt_paint/paint_curve_undo.c
@@ -179,6 +179,7 @@ void ED_paintcurve_undo_push_end(void)
{
UndoStack *ustack = ED_undo_stack_get();
BKE_undosys_step_push(ustack, NULL, NULL);
+ BKE_undosys_stack_limit_steps_and_memory_defaults(ustack);
WM_file_tag_modified();
}
diff --git a/source/blender/editors/sculpt_paint/paint_hide.c b/source/blender/editors/sculpt_paint/paint_hide.c
index 69ca86efa9d..e9dcc4a356a 100644
--- a/source/blender/editors/sculpt_paint/paint_hide.c
+++ b/source/blender/editors/sculpt_paint/paint_hide.c
@@ -10,7 +10,7 @@
* 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,
+ * 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) 2010 by Nicholas Bishop
diff --git a/source/blender/editors/sculpt_paint/paint_image.c b/source/blender/editors/sculpt_paint/paint_image.c
index cbb0ce84156..08af3bdd16c 100644
--- a/source/blender/editors/sculpt_paint/paint_image.c
+++ b/source/blender/editors/sculpt_paint/paint_image.c
@@ -388,6 +388,10 @@ void paint_brush_color_get(struct Scene *scene,
break;
}
}
+ /* Gradient / Colorband colors are not considered PROP_COLOR_GAMMA.
+ * Brush colors are expected to be in sRGB though. */
+ IMB_colormanagement_scene_linear_to_srgb_v3(color_gr);
+
copy_v3_v3(color, color_gr);
}
else {
@@ -507,12 +511,8 @@ static PaintOperation *texture_paint_init(bContext *C, wmOperator *op, const flo
}
if ((brush->imagepaint_tool == PAINT_TOOL_FILL) && (brush->flag & BRUSH_USE_GRADIENT)) {
- pop->cursor = WM_paint_cursor_activate(CTX_wm_manager(C),
- SPACE_TYPE_ANY,
- RGN_TYPE_ANY,
- image_paint_poll,
- gradient_draw_line,
- pop);
+ pop->cursor = WM_paint_cursor_activate(
+ SPACE_TYPE_ANY, RGN_TYPE_ANY, image_paint_poll, gradient_draw_line, pop);
}
settings->imapaint.flag |= IMAGEPAINT_DRAWING;
@@ -651,7 +651,7 @@ static void paint_stroke_done(const bContext *C, struct PaintStroke *stroke)
}
if (pop->cursor) {
- WM_paint_cursor_end(CTX_wm_manager(C), pop->cursor);
+ WM_paint_cursor_end(pop->cursor);
}
ED_image_undo_push_end();
@@ -764,9 +764,9 @@ void PAINT_OT_image_paint(wmOperatorType *ot)
bool get_imapaint_zoom(bContext *C, float *zoomx, float *zoomy)
{
- ScrArea *sa = CTX_wm_area(C);
- if (sa && sa->spacetype == SPACE_IMAGE) {
- SpaceImage *sima = sa->spacedata.first;
+ ScrArea *area = CTX_wm_area(C);
+ if (area && area->spacetype == SPACE_IMAGE) {
+ SpaceImage *sima = area->spacedata.first;
if (sima->mode == SI_MODE_PAINT) {
ARegion *region = CTX_wm_region(C);
ED_space_image_get_zoom(sima, region, zoomx, zoomy);
@@ -781,19 +781,18 @@ bool get_imapaint_zoom(bContext *C, float *zoomx, float *zoomy)
/************************ cursor drawing *******************************/
-static void toggle_paint_cursor(bContext *C, int enable)
+static void toggle_paint_cursor(Scene *scene, bool enable)
{
- wmWindowManager *wm = CTX_wm_manager(C);
- Scene *scene = CTX_data_scene(C);
ToolSettings *settings = scene->toolsettings;
+ Paint *p = &settings->imapaint.paint;
- if (settings->imapaint.paintcursor && !enable) {
- WM_paint_cursor_end(wm, settings->imapaint.paintcursor);
- settings->imapaint.paintcursor = NULL;
+ if (p->paint_cursor && !enable) {
+ WM_paint_cursor_end(p->paint_cursor);
+ p->paint_cursor = NULL;
paint_cursor_delete_textures();
}
else if (enable) {
- paint_cursor_start(C, image_paint_poll);
+ paint_cursor_start(p, image_paint_poll);
}
}
@@ -808,12 +807,12 @@ void ED_space_image_paint_update(Main *bmain, wmWindowManager *wm, Scene *scene)
ImagePaintSettings *imapaint = &settings->imapaint;
bool enabled = false;
- for (wmWindow *win = wm->windows.first; win; win = win->next) {
+ LISTBASE_FOREACH (wmWindow *, win, &wm->windows) {
bScreen *screen = WM_window_get_active_screen(win);
- for (ScrArea *sa = screen->areabase.first; sa; sa = sa->next) {
- if (sa->spacetype == SPACE_IMAGE) {
- if (((SpaceImage *)sa->spacedata.first)->mode == SI_MODE_PAINT) {
+ LISTBASE_FOREACH (ScrArea *, area, &screen->areabase) {
+ if (area->spacetype == SPACE_IMAGE) {
+ if (((SpaceImage *)area->spacedata.first)->mode == SI_MODE_PAINT) {
enabled = true;
}
}
@@ -823,7 +822,7 @@ void ED_space_image_paint_update(Main *bmain, wmWindowManager *wm, Scene *scene)
if (enabled) {
BKE_paint_init(bmain, scene, PAINT_MODE_TEXTURE_2D, PAINT_CURSOR_TEXTURE_PAINT);
- paint_cursor_start_explicit(&imapaint->paint, wm, image_paint_poll);
+ paint_cursor_start(&imapaint->paint, image_paint_poll);
}
else {
paint_cursor_delete_textures();
@@ -949,9 +948,9 @@ typedef struct {
static void sample_color_update_header(SampleColorData *data, bContext *C)
{
char msg[UI_MAX_DRAW_STR];
- ScrArea *sa = CTX_wm_area(C);
+ ScrArea *area = CTX_wm_area(C);
- if (sa) {
+ if (area) {
BLI_snprintf(msg,
sizeof(msg),
TIP_("Sample color for %s"),
@@ -1117,6 +1116,100 @@ void PAINT_OT_sample_color(wmOperatorType *ot)
/******************** texture paint toggle operator ********************/
+void ED_object_texture_paint_mode_enter_ex(Main *bmain, Scene *scene, Object *ob)
+{
+ bScreen *screen;
+ Image *ima = NULL;
+ ImagePaintSettings *imapaint = &scene->toolsettings->imapaint;
+
+ /* This has to stay here to regenerate the texture paint
+ * cache in case we are loading a file */
+ BKE_texpaint_slots_refresh_object(scene, ob);
+
+ BKE_paint_proj_mesh_data_check(scene, ob, NULL, NULL, NULL, NULL);
+
+ /* entering paint mode also sets image to editors */
+ if (imapaint->mode == IMAGEPAINT_MODE_MATERIAL) {
+ /* set the current material active paint slot on image editor */
+ Material *ma = BKE_object_material_get(ob, ob->actcol);
+
+ if (ma && ma->texpaintslot) {
+ ima = ma->texpaintslot[ma->paint_active_slot].ima;
+ }
+ }
+ else if (imapaint->mode == IMAGEPAINT_MODE_IMAGE) {
+ ima = imapaint->canvas;
+ }
+
+ if (ima) {
+ for (screen = bmain->screens.first; screen; screen = screen->id.next) {
+ ScrArea *area;
+ for (area = screen->areabase.first; area; area = area->next) {
+ SpaceLink *sl;
+ for (sl = area->spacedata.first; sl; sl = sl->next) {
+ if (sl->spacetype == SPACE_IMAGE) {
+ SpaceImage *sima = (SpaceImage *)sl;
+
+ if (!sima->pin) {
+ ED_space_image_set(bmain, sima, NULL, ima, true);
+ }
+ }
+ }
+ }
+ }
+ }
+
+ ob->mode |= OB_MODE_TEXTURE_PAINT;
+
+ BKE_paint_init(bmain, scene, PAINT_MODE_TEXTURE_3D, PAINT_CURSOR_TEXTURE_PAINT);
+
+ BKE_paint_toolslots_brush_validate(bmain, &imapaint->paint);
+
+ if (U.glreslimit != 0) {
+ GPU_free_images(bmain);
+ }
+ GPU_paint_set_mipmap(bmain, 0);
+
+ toggle_paint_cursor(scene, true);
+
+ Mesh *me = BKE_mesh_from_object(ob);
+ BLI_assert(me != NULL);
+ DEG_id_tag_update(&me->id, ID_RECALC_COPY_ON_WRITE);
+ WM_main_add_notifier(NC_SCENE | ND_MODE, scene);
+}
+
+void ED_object_texture_paint_mode_enter(bContext *C)
+{
+ Main *bmain = CTX_data_main(C);
+ Object *ob = CTX_data_active_object(C);
+ Scene *scene = CTX_data_scene(C);
+ ED_object_texture_paint_mode_enter_ex(bmain, scene, ob);
+}
+
+void ED_object_texture_paint_mode_exit_ex(Main *bmain, Scene *scene, Object *ob)
+{
+ ob->mode &= ~OB_MODE_TEXTURE_PAINT;
+
+ if (U.glreslimit != 0) {
+ GPU_free_images(bmain);
+ }
+ GPU_paint_set_mipmap(bmain, 1);
+ toggle_paint_cursor(scene, false);
+
+ Mesh *me = BKE_mesh_from_object(ob);
+ BLI_assert(me != NULL);
+ DEG_id_tag_update(&me->id, ID_RECALC_COPY_ON_WRITE);
+ WM_main_add_notifier(NC_SCENE | ND_MODE, scene);
+}
+
+void ED_object_texture_paint_mode_exit(bContext *C)
+{
+ Main *bmain = CTX_data_main(C);
+ Object *ob = CTX_data_active_object(C);
+ Scene *scene = CTX_data_scene(C);
+ ED_object_texture_paint_mode_exit_ex(bmain, scene, ob);
+}
+
static bool texture_paint_toggle_poll(bContext *C)
{
Object *ob = CTX_data_active_object(C);
@@ -1126,9 +1219,6 @@ static bool texture_paint_toggle_poll(bContext *C)
if (!ob->data || ID_IS_LINKED(ob->data)) {
return 0;
}
- if (CTX_data_edit_object(C)) {
- return 0;
- }
return 1;
}
@@ -1149,78 +1239,12 @@ static int texture_paint_toggle_exec(bContext *C, wmOperator *op)
}
if (ob->mode & mode_flag) {
- ob->mode &= ~mode_flag;
-
- if (U.glreslimit != 0) {
- GPU_free_images(bmain);
- }
- GPU_paint_set_mipmap(bmain, 1);
-
- toggle_paint_cursor(C, 0);
+ ED_object_texture_paint_mode_exit_ex(bmain, scene, ob);
}
else {
- bScreen *sc;
- Image *ima = NULL;
- ImagePaintSettings *imapaint = &scene->toolsettings->imapaint;
-
- /* This has to stay here to regenerate the texture paint
- * cache in case we are loading a file */
- BKE_texpaint_slots_refresh_object(scene, ob);
-
- BKE_paint_proj_mesh_data_check(scene, ob, NULL, NULL, NULL, NULL);
-
- /* entering paint mode also sets image to editors */
- if (imapaint->mode == IMAGEPAINT_MODE_MATERIAL) {
- /* set the current material active paint slot on image editor */
- Material *ma = BKE_object_material_get(ob, ob->actcol);
-
- if (ma && ma->texpaintslot) {
- ima = ma->texpaintslot[ma->paint_active_slot].ima;
- }
- }
- else if (imapaint->mode == IMAGEPAINT_MODE_IMAGE) {
- ima = imapaint->canvas;
- }
-
- if (ima) {
- for (sc = bmain->screens.first; sc; sc = sc->id.next) {
- ScrArea *sa;
- for (sa = sc->areabase.first; sa; sa = sa->next) {
- SpaceLink *sl;
- for (sl = sa->spacedata.first; sl; sl = sl->next) {
- if (sl->spacetype == SPACE_IMAGE) {
- SpaceImage *sima = (SpaceImage *)sl;
-
- if (!sima->pin) {
- Object *obedit = CTX_data_edit_object(C);
- ED_space_image_set(bmain, sima, obedit, ima, true);
- }
- }
- }
- }
- }
- }
-
- ob->mode |= mode_flag;
-
- BKE_paint_init(bmain, scene, PAINT_MODE_TEXTURE_3D, PAINT_CURSOR_TEXTURE_PAINT);
-
- BKE_paint_toolslots_brush_validate(bmain, &imapaint->paint);
-
- if (U.glreslimit != 0) {
- GPU_free_images(bmain);
- }
- GPU_paint_set_mipmap(bmain, 0);
-
- toggle_paint_cursor(C, 1);
+ ED_object_texture_paint_mode_enter_ex(bmain, scene, ob);
}
- Mesh *me = BKE_mesh_from_object(ob);
- BLI_assert(me != NULL);
- DEG_id_tag_update(&me->id, ID_RECALC_COPY_ON_WRITE);
-
- WM_event_add_notifier(C, NC_SCENE | ND_MODE, scene);
-
WM_msg_publish_rna_prop(mbus, &ob->id, ob, Object, mode);
WM_toolsystem_update_from_context_view3d(C);
@@ -1288,9 +1312,9 @@ static bool brush_colors_flip_poll(bContext *C)
void PAINT_OT_brush_colors_flip(wmOperatorType *ot)
{
/* identifiers */
- ot->name = "Brush Colors Flip";
+ ot->name = "Swap Colors";
ot->idname = "PAINT_OT_brush_colors_flip";
- ot->description = "Toggle foreground and background brush colors";
+ ot->description = "Swap primary and secondary brush colors";
/* api callbacks */
ot->exec = brush_colors_flip_exec;
@@ -1305,20 +1329,20 @@ void ED_imapaint_bucket_fill(struct bContext *C,
wmOperator *op,
const int mouse[2])
{
- wmWindowManager *wm = CTX_wm_manager(C);
SpaceImage *sima = CTX_wm_space_image(C);
- Image *ima = sima->image;
- BKE_undosys_step_push_init_with_type(wm->undo_stack, C, op->type->name, BKE_UNDOSYS_TYPE_IMAGE);
+ if (sima && sima->image) {
+ Image *ima = sima->image;
- ED_image_undo_push_begin(op->type->name, PAINT_MODE_TEXTURE_2D);
+ ED_image_undo_push_begin(op->type->name, PAINT_MODE_TEXTURE_2D);
- float mouse_init[2] = {mouse[0], mouse[1]};
- paint_2d_bucket_fill(C, color, NULL, mouse_init, NULL, NULL);
+ float mouse_init[2] = {mouse[0], mouse[1]};
+ paint_2d_bucket_fill(C, color, NULL, mouse_init, NULL, NULL);
- BKE_undosys_step_push(wm->undo_stack, C, op->type->name);
+ ED_image_undo_push_end();
- DEG_id_tag_update(&ima->id, 0);
+ DEG_id_tag_update(&ima->id, 0);
+ }
}
static bool texture_paint_poll(bContext *C)
diff --git a/source/blender/editors/sculpt_paint/paint_image_2d.c b/source/blender/editors/sculpt_paint/paint_image_2d.c
index 73c099c9407..16ccfaf8286 100644
--- a/source/blender/editors/sculpt_paint/paint_image_2d.c
+++ b/source/blender/editors/sculpt_paint/paint_image_2d.c
@@ -80,11 +80,11 @@ typedef struct BrushPainterCache {
ImBuf *ibuf;
ImBuf *texibuf;
- unsigned short *curve_mask;
- unsigned short *tex_mask;
- unsigned short *tex_mask_old;
- unsigned int tex_mask_old_w;
- unsigned int tex_mask_old_h;
+ ushort *curve_mask;
+ ushort *tex_mask;
+ ushort *tex_mask_old;
+ uint tex_mask_old_w;
+ uint tex_mask_old_h;
int image_size[2];
} BrushPainterCache;
@@ -228,7 +228,7 @@ static void brush_imbuf_tex_co(rctf *mapping, int x, int y, float texco[3])
}
/* create a mask with the mask texture */
-static unsigned short *brush_painter_mask_ibuf_new(BrushPainter *painter, const int size)
+static ushort *brush_painter_mask_ibuf_new(BrushPainter *painter, const int size)
{
Scene *scene = painter->scene;
Brush *brush = painter->brush;
@@ -236,10 +236,10 @@ static unsigned short *brush_painter_mask_ibuf_new(BrushPainter *painter, const
struct ImagePool *pool = painter->pool;
float texco[3];
- unsigned short *mask, *m;
+ ushort *mask, *m;
int x, y, thread = 0;
- mask = MEM_mallocN(sizeof(unsigned short) * size * size, "brush_painter_mask");
+ mask = MEM_mallocN(sizeof(ushort) * size * size, "brush_painter_mask");
m = mask;
for (y = 0; y < size; y++) {
@@ -247,7 +247,7 @@ static unsigned short *brush_painter_mask_ibuf_new(BrushPainter *painter, const
float res;
brush_imbuf_tex_co(&mask_mapping, x, y, texco);
res = BKE_brush_sample_masktex(scene, brush, texco, thread, pool);
- *m = (unsigned short)(65535.0f * res);
+ *m = (ushort)(65535.0f * res);
}
}
@@ -257,7 +257,7 @@ static unsigned short *brush_painter_mask_ibuf_new(BrushPainter *painter, const
/* update rectangular section of the brush image */
static void brush_painter_mask_imbuf_update(BrushPainter *painter,
ImagePaintTile *tile,
- unsigned short *tex_mask_old,
+ ushort *tex_mask_old,
int origx,
int origy,
int w,
@@ -271,14 +271,14 @@ static void brush_painter_mask_imbuf_update(BrushPainter *painter,
BrushPainterCache *cache = &tile->cache;
rctf tex_mapping = painter->mask_mapping;
struct ImagePool *pool = painter->pool;
- unsigned short res;
+ ushort res;
bool use_texture_old = (tex_mask_old != NULL);
int x, y, thread = 0;
- unsigned short *tex_mask = cache->tex_mask;
- unsigned short *tex_mask_cur = cache->tex_mask_old;
+ ushort *tex_mask = cache->tex_mask;
+ ushort *tex_mask_cur = cache->tex_mask_old;
/* fill pixels */
for (y = origy; y < h; y++) {
@@ -287,13 +287,12 @@ static void brush_painter_mask_imbuf_update(BrushPainter *painter,
float texco[3];
/* handle byte pixel */
- unsigned short *b = tex_mask + (y * diameter + x);
- unsigned short *t = tex_mask_cur + (y * diameter + x);
+ ushort *b = tex_mask + (y * diameter + x);
+ ushort *t = tex_mask_cur + (y * diameter + x);
if (!use_texture_old) {
brush_imbuf_tex_co(&tex_mapping, x, y, texco);
- res = (unsigned short)(65535.0f *
- BKE_brush_sample_masktex(scene, brush, texco, thread, pool));
+ res = (ushort)(65535.0f * BKE_brush_sample_masktex(scene, brush, texco, thread, pool));
}
/* read from old texture buffer */
@@ -320,19 +319,17 @@ static void brush_painter_mask_imbuf_partial_update(BrushPainter *painter,
const int diameter)
{
BrushPainterCache *cache = &tile->cache;
- unsigned short *tex_mask_old;
+ ushort *tex_mask_old;
int destx, desty, srcx, srcy, w, h, x1, y1, x2, y2;
/* create brush image buffer if it didn't exist yet */
if (!cache->tex_mask) {
- cache->tex_mask = MEM_mallocN(sizeof(unsigned short) * diameter * diameter,
- "brush_painter_mask");
+ cache->tex_mask = MEM_mallocN(sizeof(ushort) * diameter * diameter, "brush_painter_mask");
}
/* create new texture image buffer with coordinates relative to old */
tex_mask_old = cache->tex_mask_old;
- cache->tex_mask_old = MEM_mallocN(sizeof(unsigned short) * diameter * diameter,
- "brush_painter_mask");
+ cache->tex_mask_old = MEM_mallocN(sizeof(ushort) * diameter * diameter, "brush_painter_mask");
if (tex_mask_old) {
ImBuf maskibuf;
@@ -393,18 +390,18 @@ static void brush_painter_mask_imbuf_partial_update(BrushPainter *painter,
}
/* create a mask with the falloff strength */
-static unsigned short *brush_painter_curve_mask_new(BrushPainter *painter,
- int diameter,
- float radius,
- const float pos[2])
+static ushort *brush_painter_curve_mask_new(BrushPainter *painter,
+ int diameter,
+ float radius,
+ const float pos[2])
{
Brush *brush = painter->brush;
int offset = (int)floorf(diameter / 2.0f);
- unsigned short *mask, *m;
+ ushort *mask, *m;
- mask = MEM_mallocN(sizeof(unsigned short) * diameter * diameter, "brush_painter_mask");
+ mask = MEM_mallocN(sizeof(ushort) * diameter * diameter, "brush_painter_mask");
m = mask;
int aa_samples = 1.0f / (radius * 0.20f);
@@ -458,7 +455,7 @@ static unsigned short *brush_painter_curve_mask_new(BrushPainter *painter,
total_samples += curve * hardness_factor;
}
}
- *m = (unsigned short)(total_samples * norm_factor);
+ *m = (ushort)(total_samples * norm_factor);
}
}
@@ -528,7 +525,7 @@ static ImBuf *brush_painter_imbuf_new(
}
else {
/* write to byte pixel */
- unsigned char *dst = (unsigned char *)ibuf->rect + (y * size + x) * 4;
+ uchar *dst = (uchar *)ibuf->rect + (y * size + x) * 4;
rgb_float_to_uchar(dst, rgba);
dst[3] = unit_float_to_uchar_clamp(rgba[3]);
@@ -624,16 +621,16 @@ static void brush_painter_imbuf_update(BrushPainter *painter,
bf[3] = rgba[3];
}
else {
- unsigned char crgba[4];
+ uchar crgba[4];
/* handle byte pixel */
- unsigned char *b = (unsigned char *)ibuf->rect + (y * ibuf->x + x) * 4;
- unsigned char *t = (unsigned char *)texibuf->rect + (y * texibuf->x + x) * 4;
+ uchar *b = (uchar *)ibuf->rect + (y * ibuf->x + x) * 4;
+ uchar *t = (uchar *)texibuf->rect + (y * texibuf->x + x) * 4;
/* read from old texture buffer */
if (use_texture_old) {
- unsigned char *ot = (unsigned char *)oldtexibuf->rect +
- ((y - origy + yt) * oldtexibuf->x + (x - origx + xt)) * 4;
+ uchar *ot = (uchar *)oldtexibuf->rect +
+ ((y - origy + yt) * oldtexibuf->x + (x - origx + xt)) * 4;
crgba[0] = ot[0];
crgba[1] = ot[1];
crgba[2] = ot[2];
@@ -975,7 +972,7 @@ static void paint_2d_ibuf_rgb_get(ImBuf *ibuf, int x, int y, float r_rgb[4])
copy_v4_v4(r_rgb, rrgbf);
}
else {
- unsigned char *rrgb = (unsigned char *)ibuf->rect + (ibuf->x * y + x) * 4;
+ uchar *rrgb = (uchar *)ibuf->rect + (ibuf->x * y + x) * 4;
straight_uchar_to_premul_float(r_rgb, rrgb);
}
}
@@ -1001,8 +998,8 @@ static void paint_2d_ibuf_rgb_set(
rrgbf[3] = rgb[3];
}
else {
- unsigned char straight[4];
- unsigned char *rrgb = (unsigned char *)ibuf->rect + (ibuf->x * y + x) * 4;
+ uchar straight[4];
+ uchar *rrgb = (uchar *)ibuf->rect + (ibuf->x * y + x) * 4;
premul_float_to_straight_uchar(straight, rgb);
rrgb[0] = straight[0];
@@ -1329,7 +1326,7 @@ static void paint_2d_do_making_brush(ImagePaintState *s,
for (int ty = tiley; ty <= tileh; ty++) {
for (int tx = tilex; tx <= tilew; tx++) {
/* retrieve original pixels + mask from undo buffer */
- unsigned short *mask;
+ ushort *mask;
int origx = region->destx - tx * ED_IMAGE_UNDO_TILE_SIZE;
int origy = region->desty - ty * ED_IMAGE_UNDO_TILE_SIZE;
@@ -1829,7 +1826,7 @@ static void paint_2d_fill_add_pixel_byte(const int x_px,
if (!BLI_BITMAP_TEST(touched, coordinate)) {
float color_f[4];
- unsigned char *color_b = (unsigned char *)(ibuf->rect + coordinate);
+ uchar *color_b = (uchar *)(ibuf->rect + coordinate);
rgba_uchar_to_float(color_f, color_b);
straight_to_premul_v4(color_f);
@@ -1895,9 +1892,9 @@ void paint_2d_bucket_fill(const bContext *C,
ImBuf *ibuf;
int x_px, y_px;
- unsigned int color_b;
+ uint color_b;
float color_f[4];
- float strength = br ? BKE_brush_alpha_get(s->scene, br) : 1.0f;
+ float strength = (s && br) ? BKE_brush_alpha_get(s->scene, br) : 1.0f;
bool do_float;
@@ -1935,7 +1932,7 @@ void paint_2d_bucket_fill(const bContext *C,
* be in gamma space. strictly speaking this is not correct, but blender does not paint
* byte images in linear space */
if (!do_float) {
- linearrgb_to_srgb_uchar3((unsigned char *)&color_b, color);
+ linearrgb_to_srgb_uchar3((uchar *)&color_b, color);
*(((char *)&color_b) + 3) = strength * 255;
}
else {
@@ -1959,9 +1956,9 @@ void paint_2d_bucket_fill(const bContext *C,
else {
for (x_px = 0; x_px < ibuf->x; x_px++) {
for (y_px = 0; y_px < ibuf->y; y_px++) {
- blend_color_mix_byte((unsigned char *)(ibuf->rect + ((size_t)y_px) * ibuf->x + x_px),
- (unsigned char *)(ibuf->rect + ((size_t)y_px) * ibuf->x + x_px),
- (unsigned char *)&color_b);
+ blend_color_mix_byte((uchar *)(ibuf->rect + ((size_t)y_px) * ibuf->x + x_px),
+ (uchar *)(ibuf->rect + ((size_t)y_px) * ibuf->x + x_px),
+ (uchar *)&color_b);
}
}
}
@@ -2000,7 +1997,7 @@ void paint_2d_bucket_fill(const bContext *C,
}
else {
int pixel_color_b = *(ibuf->rect + coordinate);
- rgba_uchar_to_float(pixel_color, (unsigned char *)&pixel_color_b);
+ rgba_uchar_to_float(pixel_color, (uchar *)&pixel_color_b);
straight_to_premul_v4(pixel_color);
}
@@ -2055,9 +2052,9 @@ void paint_2d_bucket_fill(const bContext *C,
while (!BLI_stack_is_empty(stack)) {
BLI_stack_pop(stack, &coordinate);
- IMB_blend_color_byte((unsigned char *)(ibuf->rect + coordinate),
- (unsigned char *)(ibuf->rect + coordinate),
- (unsigned char *)&color_b,
+ IMB_blend_color_byte((uchar *)(ibuf->rect + coordinate),
+ (uchar *)(ibuf->rect + coordinate),
+ (uchar *)&color_b,
br->blend);
/* reconstruct the coordinates here */
@@ -2117,7 +2114,7 @@ void paint_2d_gradient_fill(
ImBuf *ibuf;
int x_px, y_px;
- unsigned int color_b;
+ uint color_b;
float color_f[4];
float image_init[2], image_final[2];
float tangent[2];
@@ -2212,11 +2209,11 @@ void paint_2d_gradient_fill(
BKE_colorband_evaluate(br->gradient, f, color_f);
linearrgb_to_srgb_v3_v3(color_f, color_f);
- rgba_float_to_uchar((unsigned char *)&color_b, color_f);
- ((unsigned char *)&color_b)[3] *= brush_alpha;
- IMB_blend_color_byte((unsigned char *)(ibuf->rect + ((size_t)y_px) * ibuf->x + x_px),
- (unsigned char *)(ibuf->rect + ((size_t)y_px) * ibuf->x + x_px),
- (unsigned char *)&color_b,
+ rgba_float_to_uchar((uchar *)&color_b, color_f);
+ ((uchar *)&color_b)[3] *= brush_alpha;
+ IMB_blend_color_byte((uchar *)(ibuf->rect + ((size_t)y_px) * ibuf->x + x_px),
+ (uchar *)(ibuf->rect + ((size_t)y_px) * ibuf->x + x_px),
+ (uchar *)&color_b,
br->blend);
}
}
diff --git a/source/blender/editors/sculpt_paint/paint_image_proj.c b/source/blender/editors/sculpt_paint/paint_image_proj.c
index c56ce8fd183..5e3204b6d5a 100644
--- a/source/blender/editors/sculpt_paint/paint_image_proj.c
+++ b/source/blender/editors/sculpt_paint/paint_image_proj.c
@@ -112,7 +112,7 @@ static void partial_redraw_array_init(ImagePaintPartialRedraw *pr);
/* Defines and Structs */
/* unit_float_to_uchar_clamp as inline function */
-BLI_INLINE unsigned char f_to_char(const float val)
+BLI_INLINE uchar f_to_char(const float val)
{
return unit_float_to_uchar_clamp(val);
}
@@ -206,7 +206,7 @@ typedef struct ProjPaintImage {
volatile void **undoRect;
/** The mask accumulation must happen on canvas, not on space screen bucket.
* Here we store the mask rectangle. */
- unsigned short **maskRect;
+ ushort **maskRect;
/** Store flag to enforce validation of undo rectangle. */
bool **valid;
bool touch;
@@ -279,7 +279,7 @@ typedef struct ProjPaintState {
/** bucketRect aligned array linkList of faces overlapping each bucket. */
LinkNode **bucketFaces;
/** store if the bucks have been initialized. */
- unsigned char *bucketFlags;
+ uchar *bucketFlags;
/** store options per vert, now only store if the vert is pointing away from the view. */
char *vertFlags;
@@ -443,13 +443,13 @@ typedef union pixelPointer {
/** float buffer. */
float *f_pt;
/** 2 ways to access a char buffer. */
- unsigned int *uint_pt;
- unsigned char *ch_pt;
+ uint *uint_pt;
+ uchar *ch_pt;
} PixelPointer;
typedef union pixelStore {
- unsigned char ch[4];
- unsigned int uint;
+ uchar ch[4];
+ uint uint;
float f[4];
} PixelStore;
@@ -461,17 +461,17 @@ typedef struct ProjPixel {
short x_px, y_px;
/** if anyone wants to paint onto more than 65535 images they can bite me. */
- unsigned short image_index;
- unsigned char bb_cell_index;
+ ushort image_index;
+ uchar bb_cell_index;
/* for various reasons we may want to mask out painting onto this pixel */
- unsigned short mask;
+ ushort mask;
/* Only used when the airbrush is disabled.
* Store the max mask value to avoid painting over an area with a lower opacity
* with an advantage that we can avoid touching the pixel at all, if the
* new mask value is lower then mask_accum */
- unsigned short *mask_accum;
+ ushort *mask_accum;
/* horrible hack, store tile valid flag pointer here to re-validate tiles
* used for anchored and drag-dot strokes */
@@ -491,7 +491,7 @@ typedef struct ProjPixelClone {
typedef struct {
SpinLock *lock;
bool masked;
- unsigned short tile_width;
+ ushort tile_width;
ImBuf **tmpibuf;
ProjPaintImage *pjima;
} TileInfo;
@@ -717,11 +717,8 @@ static void uvco_to_wrapped_pxco(const float uv[2], int ibuf_x, int ibuf_y, floa
/* Set the top-most face color that the screen space coord 'pt' touches
* (or return 0 if none touch) */
-static bool project_paint_PickColor(const ProjPaintState *ps,
- const float pt[2],
- float *rgba_fp,
- unsigned char *rgba,
- const bool interp)
+static bool project_paint_PickColor(
+ const ProjPaintState *ps, const float pt[2], float *rgba_fp, uchar *rgba, const bool interp)
{
const MLoopTri *lt;
const float *lt_tri_uv[3];
@@ -774,7 +771,7 @@ static bool project_paint_PickColor(const ProjPaintState *ps,
bilinear_interpolation_color_wrap(ibuf, rgba, NULL, x, y);
}
else {
- unsigned char rgba_tmp[4];
+ uchar rgba_tmp[4];
bilinear_interpolation_color_wrap(ibuf, rgba_tmp, NULL, x, y);
straight_uchar_to_premul_float(rgba_fp, rgba_tmp);
}
@@ -795,8 +792,7 @@ static bool project_paint_PickColor(const ProjPaintState *ps,
premul_float_to_straight_uchar(rgba, rgba_tmp_fp);
}
else {
- *((unsigned int *)rgba) = *(unsigned int *)(((char *)ibuf->rect) +
- ((xi + yi * ibuf->x) * 4));
+ *((uint *)rgba) = *(uint *)(((char *)ibuf->rect) + ((xi + yi * ibuf->x) * 4));
}
}
@@ -805,7 +801,7 @@ static bool project_paint_PickColor(const ProjPaintState *ps,
copy_v4_v4(rgba_fp, (ibuf->rect_float + ((xi + yi * ibuf->x) * 4)));
}
else {
- unsigned char *tmp_ch = ((unsigned char *)ibuf->rect) + ((xi + yi * ibuf->x) * 4);
+ uchar *tmp_ch = ((uchar *)ibuf->rect) + ((xi + yi * ibuf->x) * 4);
straight_uchar_to_premul_float(rgba_fp, tmp_ch);
}
}
@@ -1150,8 +1146,8 @@ static bool check_seam(const ProjPaintState *ps,
const MLoopTri *orig_lt = &ps->mlooptri_eval[orig_face];
const float *orig_lt_tri_uv[3] = {PS_LOOPTRI_AS_UV_3(ps->poly_to_loop_uv, orig_lt)};
/* vert indices from face vert order indices */
- const unsigned int i1 = ps->mloop_eval[orig_lt->tri[orig_i1_fidx]].v;
- const unsigned int i2 = ps->mloop_eval[orig_lt->tri[orig_i2_fidx]].v;
+ const uint i1 = ps->mloop_eval[orig_lt->tri[orig_i1_fidx]].v;
+ const uint i2 = ps->mloop_eval[orig_lt->tri[orig_i2_fidx]].v;
LinkNode *node;
/* index in face */
int i1_fidx = -1, i2_fidx = -1;
@@ -1641,7 +1637,7 @@ static float screen_px_line_point_factor_v2_persp(const ProjPaintState *ps,
static void project_face_pixel(const float *lt_tri_uv[3],
ImBuf *ibuf_other,
const float w[3],
- unsigned char rgba_ub[4],
+ uchar rgba_ub[4],
float rgba_f[4])
{
float uv_other[2], x, y;
@@ -1677,7 +1673,7 @@ static float project_paint_uvpixel_mask(const ProjPaintState *ps,
const float *lt_other_tri_uv[3] = {PS_LOOPTRI_AS_UV_3(ps->poly_to_loop_uv, lt_other)};
/* BKE_image_acquire_ibuf - TODO - this may be slow */
- unsigned char rgba_ub[4];
+ uchar rgba_ub[4];
float rgba_f[4];
project_face_pixel(lt_other_tri_uv, ibuf_other, w, rgba_ub, rgba_f);
@@ -1937,8 +1933,8 @@ static ProjPixel *project_paint_uvpixel_init(const ProjPaintState *ps,
zero_v4(projPixel->newColor.f);
}
else {
- projPixel->pixel.ch_pt = (unsigned char *)(ibuf->rect + (x_px + y_px * ibuf->x));
- projPixel->origColor.uint_pt = (unsigned int *)projima->undoRect[tile_index] + tile_offset;
+ projPixel->pixel.ch_pt = (uchar *)(ibuf->rect + (x_px + y_px * ibuf->x));
+ projPixel->origColor.uint_pt = (uint *)projima->undoRect[tile_index] + tile_offset;
projPixel->newColor.uint = 0;
}
@@ -1952,7 +1948,7 @@ static ProjPixel *project_paint_uvpixel_init(const ProjPaintState *ps,
projPixel->x_px = x_px;
projPixel->y_px = y_px;
- projPixel->mask = (unsigned short)(mask * 65535);
+ projPixel->mask = (ushort)(mask * 65535);
if (ps->do_masking) {
projPixel->mask_accum = projima->maskRect[tile_index] + tile_offset;
}
@@ -1984,7 +1980,7 @@ static ProjPixel *project_paint_uvpixel_init(const ProjPaintState *ps,
lt_other_tri_uv, ibuf_other, w, NULL, ((ProjPixelClone *)projPixel)->clonepx.f);
}
else { /* from char to float */
- unsigned char rgba_ub[4];
+ uchar rgba_ub[4];
float rgba[4];
project_face_pixel(lt_other_tri_uv, ibuf_other, w, rgba_ub, NULL);
if (ps->use_colormanagement) {
@@ -4026,7 +4022,7 @@ static void project_paint_bleed_add_face_user(const ProjPaintState *ps,
* Ideally this would be checked later, not to add to the cost of computing non-degenerate
* triangles, but that would allow other triangles to still find adjacent seams on degenerate
* triangles, potentially causing incorrect results. */
- if (area_tri_v2(UNPACK3(lt_tri_uv)) > FLT_EPSILON) {
+ if (area_tri_v2(UNPACK3(lt_tri_uv)) > 0.0f) {
const int lt_vtri[3] = {PS_LOOPTRI_AS_VERT_INDEX_3(ps, lt)};
void *tri_index_p = POINTER_FROM_INT(tri_index);
@@ -4844,15 +4840,15 @@ typedef struct ProjectHandle {
static void do_projectpaint_clone(ProjPaintState *ps, ProjPixel *projPixel, float mask)
{
- const unsigned char *clone_pt = ((ProjPixelClone *)projPixel)->clonepx.ch;
+ const uchar *clone_pt = ((ProjPixelClone *)projPixel)->clonepx.ch;
if (clone_pt[3]) {
- unsigned char clone_rgba[4];
+ uchar clone_rgba[4];
clone_rgba[0] = clone_pt[0];
clone_rgba[1] = clone_pt[1];
clone_rgba[2] = clone_pt[2];
- clone_rgba[3] = (unsigned char)(clone_pt[3] * mask);
+ clone_rgba[3] = (uchar)(clone_pt[3] * mask);
if (ps->do_masking) {
IMB_blend_color_byte(
@@ -4895,7 +4891,7 @@ static void do_projectpaint_smear(ProjPaintState *ps,
LinkNode **smearPixels,
const float co[2])
{
- unsigned char rgba_ub[4];
+ uchar rgba_ub[4];
if (project_paint_PickColor(ps, co, NULL, rgba_ub, 1) == 0) {
return;
@@ -5016,7 +5012,7 @@ static void do_projectpaint_soften(ProjPaintState *ps,
}
if (LIKELY(accum_tot != 0)) {
- unsigned char *rgba_ub = projPixel->newColor.ch;
+ uchar *rgba_ub = projPixel->newColor.ch;
mul_v4_fl(rgba, 1.0f / (float)accum_tot);
@@ -5061,7 +5057,7 @@ static void do_projectpaint_draw(ProjPaintState *ps,
float v)
{
float rgb[3];
- unsigned char rgba_ub[4];
+ uchar rgba_ub[4];
if (ps->is_texbrush) {
mul_v3_v3v3(rgb, texrgb, ps->paint_color_linear);
@@ -5119,7 +5115,7 @@ static void do_projectpaint_draw_f(ProjPaintState *ps,
static void do_projectpaint_mask(ProjPaintState *ps, ProjPixel *projPixel, float mask)
{
- unsigned char rgba_ub[4];
+ uchar rgba_ub[4];
rgba_ub[0] = rgba_ub[1] = rgba_ub[2] = ps->stencil_value * 255.0f;
rgba_ub[3] = f_to_char(mask);
@@ -5172,9 +5168,7 @@ static void copy_original_alpha_channel(ProjPixel *pixel, bool is_floatbuf)
}
/* Run this for single and multi-threaded painting. */
-static void do_projectpaint_thread(TaskPool *__restrict UNUSED(pool),
- void *ph_v,
- int UNUSED(threadid))
+static void do_projectpaint_thread(TaskPool *__restrict UNUSED(pool), void *ph_v)
{
/* First unpack args from the struct */
ProjPaintState *ps = ((ProjectHandle *)ph_v)->ps;
@@ -5204,7 +5198,7 @@ static void do_projectpaint_thread(TaskPool *__restrict UNUSED(pool),
/* for smear only */
float pos_ofs[2] = {0};
float co[2];
- unsigned short mask_short;
+ ushort mask_short;
const float brush_alpha = BKE_brush_alpha_get(ps->scene, brush);
const float brush_radius = ps->brush_size;
/* avoid a square root with every dist comparison */
@@ -5468,7 +5462,7 @@ static void do_projectpaint_thread(TaskPool *__restrict UNUSED(pool),
}
mask = min_ff(mask, 65535.0f);
- mask_short = (unsigned short)mask;
+ mask_short = (ushort)mask;
if (mask_short > *projPixel->mask_accum) {
*projPixel->mask_accum = mask_short;
@@ -5609,7 +5603,6 @@ static bool project_paint_op(void *state, const float lastpos[2], const float po
bool touch_any = false;
ProjectHandle handles[BLENDER_MAX_THREADS];
- TaskScheduler *scheduler = NULL;
TaskPool *task_pool = NULL;
int a, i;
@@ -5620,8 +5613,7 @@ static bool project_paint_op(void *state, const float lastpos[2], const float po
}
if (ps->thread_tot > 1) {
- scheduler = BLI_task_scheduler_get();
- task_pool = BLI_task_pool_create_suspended(scheduler, NULL);
+ task_pool = BLI_task_pool_create_suspended(NULL, TASK_PRIORITY_HIGH);
}
image_pool = BKE_image_pool_new();
@@ -5656,8 +5648,7 @@ static bool project_paint_op(void *state, const float lastpos[2], const float po
handles[a].pool = image_pool;
if (task_pool != NULL) {
- BLI_task_pool_push(
- task_pool, do_projectpaint_thread, &handles[a], false, TASK_PRIORITY_HIGH);
+ BLI_task_pool_push(task_pool, do_projectpaint_thread, &handles[a], false, NULL);
}
}
@@ -5666,7 +5657,7 @@ static bool project_paint_op(void *state, const float lastpos[2], const float po
BLI_task_pool_free(task_pool);
}
else {
- do_projectpaint_thread(NULL, &handles[0], 0);
+ do_projectpaint_thread(NULL, &handles[0]);
}
BKE_image_pool_free(image_pool);
@@ -6228,13 +6219,13 @@ static int texture_paint_image_from_view_exec(bContext *C, wmOperator *op)
int maxsize;
char err_out[256] = "unknown";
- ScrArea *sa = BKE_screen_find_big_area(CTX_wm_screen(C), SPACE_VIEW3D, 0);
- if (!sa) {
+ ScrArea *area = BKE_screen_find_big_area(CTX_wm_screen(C), SPACE_VIEW3D, 0);
+ if (!area) {
BKE_report(op->reports, RPT_ERROR, "No 3D viewport found to create image from");
return OPERATOR_CANCELLED;
}
- ARegion *region = BKE_area_find_region_active_win(sa);
+ ARegion *region = BKE_area_find_region_active_win(area);
if (!region) {
BKE_report(op->reports, RPT_ERROR, "No 3D viewport found to create image from");
return OPERATOR_CANCELLED;
@@ -6254,7 +6245,7 @@ static int texture_paint_image_from_view_exec(bContext *C, wmOperator *op)
/* Create a copy of the overlays where they are all turned off, except the
* texture paint overlay opacity */
- View3D *v3d = sa->spacedata.first;
+ View3D *v3d = area->spacedata.first;
View3D v3d_copy = *v3d;
v3d_copy.gridflag = 0;
v3d_copy.flag2 = 0;
diff --git a/source/blender/editors/sculpt_paint/paint_intern.h b/source/blender/editors/sculpt_paint/paint_intern.h
index 018d7f72bb6..0d4e957c77b 100644
--- a/source/blender/editors/sculpt_paint/paint_intern.h
+++ b/source/blender/editors/sculpt_paint/paint_intern.h
@@ -90,10 +90,7 @@ void *paint_stroke_mode_data(struct PaintStroke *stroke);
float paint_stroke_distance_get(struct PaintStroke *stroke);
void paint_stroke_set_mode_data(struct PaintStroke *stroke, void *mode_data);
bool paint_poll(struct bContext *C);
-void paint_cursor_start(struct bContext *C, bool (*poll)(struct bContext *C));
-void paint_cursor_start_explicit(struct Paint *p,
- struct wmWindowManager *wm,
- bool (*poll)(struct bContext *C));
+void paint_cursor_start(struct Paint *p, bool (*poll)(struct bContext *C));
void paint_cursor_delete_textures(void);
/* paint_vertex.c */
diff --git a/source/blender/editors/sculpt_paint/paint_mask.c b/source/blender/editors/sculpt_paint/paint_mask.c
index fb8cc3a639b..c32e496f4f5 100644
--- a/source/blender/editors/sculpt_paint/paint_mask.c
+++ b/source/blender/editors/sculpt_paint/paint_mask.c
@@ -10,7 +10,7 @@
* 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,
+ * 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) 2012 by Nicholas Bishop
@@ -168,9 +168,9 @@ static int mask_flood_fill_exec(bContext *C, wmOperator *op)
.value = value,
};
- PBVHParallelSettings settings;
+ TaskParallelSettings settings;
BKE_pbvh_parallel_range_settings(&settings, (sd->flags & SCULPT_USE_OPENMP), totnode);
- BKE_pbvh_parallel_range(0, totnode, &data, mask_flood_fill_task_cb, &settings);
+ BLI_task_parallel_range(0, totnode, &data, mask_flood_fill_task_cb, &settings);
if (multires) {
multires_mark_as_modified(depsgraph, ob, MULTIRES_COORDS_MODIFIED);
@@ -343,9 +343,9 @@ bool ED_sculpt_mask_box_select(struct bContext *C, ViewContext *vc, const rcti *
.clip_planes_final = clip_planes_final,
};
- PBVHParallelSettings settings;
+ TaskParallelSettings settings;
BKE_pbvh_parallel_range_settings(&settings, (sd->flags & SCULPT_USE_OPENMP), totnode);
- BKE_pbvh_parallel_range(0, totnode, &data, mask_box_select_task_cb, &settings);
+ BLI_task_parallel_range(0, totnode, &data, mask_box_select_task_cb, &settings);
if (nodes) {
MEM_freeN(nodes);
@@ -456,10 +456,10 @@ static void mask_gesture_lasso_task_cb(void *__restrict userdata,
static int paint_mask_gesture_lasso_exec(bContext *C, wmOperator *op)
{
- int mcords_tot;
- const int(*mcords)[2] = WM_gesture_lasso_path_to_array(C, op, &mcords_tot);
+ int mcoords_len;
+ const int(*mcoords)[2] = WM_gesture_lasso_path_to_array(C, op, &mcoords_len);
- if (mcords) {
+ if (mcoords) {
Depsgraph *depsgraph = CTX_data_ensure_evaluated_depsgraph(C);
float clip_planes[4][4], clip_planes_final[4][4];
BoundBox bb;
@@ -485,7 +485,7 @@ static int paint_mask_gesture_lasso_exec(bContext *C, wmOperator *op)
ob = vc.obact;
ED_view3d_ob_project_mat_get(vc.rv3d, ob, data.projviewobjmat);
- BLI_lasso_boundbox(&data.rect, mcords, mcords_tot);
+ BLI_lasso_boundbox(&data.rect, mcoords, mcoords_len);
data.width = data.rect.xmax - data.rect.xmin;
data.px = BLI_BITMAP_NEW(data.width * (data.rect.ymax - data.rect.ymin), __func__);
@@ -493,8 +493,8 @@ static int paint_mask_gesture_lasso_exec(bContext *C, wmOperator *op)
data.rect.ymin,
data.rect.xmax,
data.rect.ymax,
- mcords,
- mcords_tot,
+ mcoords,
+ mcoords_len,
mask_lasso_px_cb,
&data);
@@ -532,9 +532,9 @@ static int paint_mask_gesture_lasso_exec(bContext *C, wmOperator *op)
data.task_data.mode = mode;
data.task_data.value = value;
- PBVHParallelSettings settings;
+ TaskParallelSettings settings;
BKE_pbvh_parallel_range_settings(&settings, (sd->flags & SCULPT_USE_OPENMP), totnode);
- BKE_pbvh_parallel_range(0, totnode, &data, mask_gesture_lasso_task_cb, &settings);
+ BLI_task_parallel_range(0, totnode, &data, mask_gesture_lasso_task_cb, &settings);
if (nodes) {
MEM_freeN(nodes);
@@ -551,7 +551,7 @@ static int paint_mask_gesture_lasso_exec(bContext *C, wmOperator *op)
SCULPT_undo_push_end();
ED_region_tag_redraw(vc.region);
- MEM_freeN((void *)mcords);
+ MEM_freeN((void *)mcoords);
MEM_freeN(data.px);
WM_event_add_notifier(C, NC_OBJECT | ND_DRAW, ob);
diff --git a/source/blender/editors/sculpt_paint/paint_ops.c b/source/blender/editors/sculpt_paint/paint_ops.c
index cc848b80bb3..0f54d5e0821 100644
--- a/source/blender/editors/sculpt_paint/paint_ops.c
+++ b/source/blender/editors/sculpt_paint/paint_ops.c
@@ -397,7 +397,7 @@ static int palette_sort_exec(bContext *C, wmOperator *op)
color_array = MEM_calloc_arrayN(totcol, sizeof(tPaletteColorHSV), __func__);
/* Put all colors in an array. */
int t = 0;
- for (PaletteColor *color = palette->colors.first; color; color = color->next) {
+ LISTBASE_FOREACH (PaletteColor *, color, &palette->colors) {
float h, s, v;
rgb_to_hsv(color->rgb[0], color->rgb[1], color->rgb[2], &h, &s, &v);
col_elm = &color_array[t];
@@ -543,7 +543,7 @@ static int palette_join_exec(bContext *C, wmOperator *op)
const int totcol = BLI_listbase_count(&palette_join->colors);
if (totcol > 0) {
- for (PaletteColor *color = palette_join->colors.first; color; color = color->next) {
+ LISTBASE_FOREACH (PaletteColor *, color, &palette_join->colors) {
PaletteColor *palcol = BKE_palette_color_add(palette);
if (palcol) {
copy_v3_v3(palcol->rgb, color->rgb);
@@ -731,7 +731,14 @@ static bool brush_generic_tool_set(bContext *C,
WM_main_add_notifier(NC_BRUSH | NA_EDITED, brush);
/* Tool System
- * This is needed for when there is a non-sculpt tool active (transform for e.g.) */
+ * This is needed for when there is a non-sculpt tool active (transform for e.g.).
+ * In case we are toggling (and the brush changed to the toggle_brush), we need to get the
+ * tool_name again. */
+ int tool_result = brush_tool(brush, paint->runtime.tool_offset);
+ ePaintMode paint_mode = BKE_paintmode_get_active_from_context(C);
+ const EnumPropertyItem *items = BKE_paint_get_tool_enum_from_paintmode(paint_mode);
+ RNA_enum_name_from_value(items, tool_result, &tool_name);
+
char tool_id[MAX_NAME];
SNPRINTF(tool_id, "builtin_brush.%s", tool_name);
WM_toolsystem_ref_set_by_id(C, tool_id);
@@ -1140,24 +1147,24 @@ static int stencil_fit_image_aspect_exec(bContext *C, wmOperator *op)
aspy *= tex->yrepeat;
}
- orig_area = aspx * aspy;
+ orig_area = fabsf(aspx * aspy);
if (do_mask) {
- stencil_area = br->mask_stencil_dimension[0] * br->mask_stencil_dimension[1];
+ stencil_area = fabsf(br->mask_stencil_dimension[0] * br->mask_stencil_dimension[1]);
}
else {
- stencil_area = br->stencil_dimension[0] * br->stencil_dimension[1];
+ stencil_area = fabsf(br->stencil_dimension[0] * br->stencil_dimension[1]);
}
factor = sqrtf(stencil_area / orig_area);
if (do_mask) {
- br->mask_stencil_dimension[0] = factor * aspx;
- br->mask_stencil_dimension[1] = factor * aspy;
+ br->mask_stencil_dimension[0] = fabsf(factor * aspx);
+ br->mask_stencil_dimension[1] = fabsf(factor * aspy);
}
else {
- br->stencil_dimension[0] = factor * aspx;
- br->stencil_dimension[1] = factor * aspy;
+ br->stencil_dimension[0] = fabsf(factor * aspx);
+ br->stencil_dimension[1] = fabsf(factor * aspy);
}
}
diff --git a/source/blender/editors/sculpt_paint/paint_stroke.c b/source/blender/editors/sculpt_paint/paint_stroke.c
index 01a0e8ddd5b..2c6f708d82a 100644
--- a/source/blender/editors/sculpt_paint/paint_stroke.c
+++ b/source/blender/editors/sculpt_paint/paint_stroke.c
@@ -10,7 +10,7 @@
* 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,
+ * 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) 2009 by Nicholas Bishop
@@ -230,8 +230,7 @@ static bool paint_tool_require_location(Brush *brush, ePaintMode mode)
SCULPT_TOOL_THUMB)) {
return false;
}
- else if (brush->sculpt_tool == SCULPT_TOOL_CLOTH &&
- brush->cloth_deform_type == BRUSH_CLOTH_DEFORM_GRAB) {
+ else if (SCULPT_is_cloth_deform_brush(brush)) {
return false;
}
else {
@@ -963,7 +962,7 @@ void paint_stroke_free(bContext *C, wmOperator *op)
}
if (stroke->stroke_cursor) {
- WM_paint_cursor_end(CTX_wm_manager(C), stroke->stroke_cursor);
+ WM_paint_cursor_end(stroke->stroke_cursor);
}
BLI_freelistN(&stroke->line);
@@ -1103,11 +1102,11 @@ struct wmKeyMap *paint_stroke_modal_keymap(struct wmKeyConfig *keyconf)
static const char *name = "Paint Stroke Modal";
- struct wmKeyMap *keymap = WM_modalkeymap_get(keyconf, name);
+ struct wmKeyMap *keymap = WM_modalkeymap_find(keyconf, name);
/* this function is called for each spacetype, only needs to add map once */
if (!keymap) {
- keymap = WM_modalkeymap_add(keyconf, name, modal_items);
+ keymap = WM_modalkeymap_ensure(keyconf, name, modal_items);
}
return keymap;
@@ -1340,7 +1339,7 @@ int paint_stroke_modal(bContext *C, wmOperator *op, const wmEvent *event)
Paint *p = BKE_paint_get_active_from_context(C);
ePaintMode mode = BKE_paintmode_get_active_from_context(C);
PaintStroke *stroke = op->customdata;
- Brush *br = stroke->brush;
+ Brush *br = stroke->brush = BKE_paint_brush(p);
PaintSample sample_average;
float mouse[2];
bool first_dab = false;
@@ -1386,12 +1385,8 @@ int paint_stroke_modal(bContext *C, wmOperator *op, const wmEvent *event)
}
if (paint_supports_smooth_stroke(br, mode)) {
- stroke->stroke_cursor = WM_paint_cursor_activate(CTX_wm_manager(C),
- SPACE_TYPE_ANY,
- RGN_TYPE_ANY,
- paint_poll,
- paint_draw_smooth_cursor,
- stroke);
+ stroke->stroke_cursor = WM_paint_cursor_activate(
+ SPACE_TYPE_ANY, RGN_TYPE_ANY, paint_poll, paint_draw_smooth_cursor, stroke);
}
stroke->stroke_init = true;
@@ -1417,12 +1412,8 @@ int paint_stroke_modal(bContext *C, wmOperator *op, const wmEvent *event)
}
if (br->flag & BRUSH_LINE) {
- stroke->stroke_cursor = WM_paint_cursor_activate(CTX_wm_manager(C),
- SPACE_TYPE_ANY,
- RGN_TYPE_ANY,
- paint_poll,
- paint_draw_line_cursor,
- stroke);
+ stroke->stroke_cursor = WM_paint_cursor_activate(
+ SPACE_TYPE_ANY, RGN_TYPE_ANY, paint_poll, paint_draw_line_cursor, stroke);
}
first_dab = true;
@@ -1597,13 +1588,14 @@ bool paint_poll(bContext *C)
{
Paint *p = BKE_paint_get_active_from_context(C);
Object *ob = CTX_data_active_object(C);
- ScrArea *sa = CTX_wm_area(C);
+ ScrArea *area = CTX_wm_area(C);
ARegion *region = CTX_wm_region(C);
- if (p && ob && BKE_paint_brush(p) && (sa && ELEM(sa->spacetype, SPACE_VIEW3D, SPACE_IMAGE)) &&
+ if (p && ob && BKE_paint_brush(p) &&
+ (area && ELEM(area->spacetype, SPACE_VIEW3D, SPACE_IMAGE)) &&
(region && region->regiontype == RGN_TYPE_WINDOW)) {
/* Check the current tool is a brush. */
- bToolRef *tref = sa->runtime.tool;
+ bToolRef *tref = area->runtime.tool;
if (tref && tref->runtime && tref->runtime->data_block[0]) {
return true;
}
diff --git a/source/blender/editors/sculpt_paint/paint_utils.c b/source/blender/editors/sculpt_paint/paint_utils.c
index e67d43d4571..c84a3b9cbfc 100644
--- a/source/blender/editors/sculpt_paint/paint_utils.c
+++ b/source/blender/editors/sculpt_paint/paint_utils.c
@@ -166,10 +166,11 @@ float paint_calc_object_space_radius(ViewContext *vc, const float center[3], flo
float paint_get_tex_pixel(const MTex *mtex, float u, float v, struct ImagePool *pool, int thread)
{
- float intensity, rgba[4];
+ float intensity;
+ float rgba_dummy[4];
float co[3] = {u, v, 0.0f};
- externtex(mtex, co, &intensity, rgba, rgba + 1, rgba + 2, rgba + 3, thread, pool, false, false);
+ RE_texture_evaluate(mtex, co, thread, pool, false, false, &intensity, rgba_dummy);
return intensity;
}
@@ -184,11 +185,10 @@ void paint_get_tex_pixel_col(const MTex *mtex,
struct ColorSpace *colorspace)
{
float co[3] = {u, v, 0.0f};
- int hasrgb;
float intensity;
- hasrgb = externtex(
- mtex, co, &intensity, rgba, rgba + 1, rgba + 2, rgba + 3, thread, pool, false, false);
+ const bool hasrgb = RE_texture_evaluate(mtex, co, thread, pool, false, false, &intensity, rgba);
+
if (!hasrgb) {
rgba[0] = intensity;
rgba[1] = intensity;
@@ -294,12 +294,8 @@ static void imapaint_tri_weights(float matrix[4][4],
}
/* compute uv coordinates of mouse in face */
-static void imapaint_pick_uv(Mesh *me_eval,
- Scene *scene,
- Object *ob_eval,
- unsigned int faceindex,
- const int xy[2],
- float uv[2])
+static void imapaint_pick_uv(
+ Mesh *me_eval, Scene *scene, Object *ob_eval, uint faceindex, const int xy[2], float uv[2])
{
int i, findex;
float p[2], w[3], absw, minabsw;
@@ -376,10 +372,7 @@ static void imapaint_pick_uv(Mesh *me_eval,
}
/* returns 0 if not found, otherwise 1 */
-static int imapaint_pick_face(ViewContext *vc,
- const int mval[2],
- unsigned int *r_index,
- unsigned int totpoly)
+static int imapaint_pick_face(ViewContext *vc, const int mval[2], uint *r_index, uint totpoly)
{
if (totpoly == 0) {
return 0;
@@ -389,7 +382,7 @@ static int imapaint_pick_face(ViewContext *vc,
ED_view3d_select_id_validate(vc);
*r_index = DRW_select_buffer_sample_point(vc->depsgraph, vc->region, vc->v3d, mval);
- if ((*r_index) == 0 || (*r_index) > (unsigned int)totpoly) {
+ if ((*r_index) == 0 || (*r_index) > (uint)totpoly) {
return 0;
}
@@ -464,8 +457,8 @@ void paint_sample_color(
Palette *palette = BKE_paint_palette(paint);
PaletteColor *color = NULL;
Brush *br = BKE_paint_brush(BKE_paint_get_active_from_context(C));
- unsigned int col;
- const unsigned char *cp;
+ uint col;
+ const uchar *cp;
CLAMP(x, 0, region->winx);
CLAMP(y, 0, region->winy);
@@ -497,8 +490,8 @@ void paint_sample_color(
ViewContext vc;
const int mval[2] = {x, y};
- unsigned int faceindex;
- unsigned int totpoly = me->totpoly;
+ uint faceindex;
+ uint totpoly = me->totpoly;
if (CustomData_has_layer(&me_eval->ldata, CD_MLOOPUV)) {
ED_view3d_viewcontext_init(C, &vc, depsgraph);
@@ -563,7 +556,7 @@ void paint_sample_color(
}
}
else {
- unsigned char rgba[4];
+ uchar rgba[4];
bilinear_interpolation_color_wrap(ibuf, rgba, NULL, u, v);
if (use_palette) {
rgb_uchar_to_float(color->rgb, rgba);
@@ -598,7 +591,7 @@ void paint_sample_color(
x + region->winrct.xmin, y + region->winrct.ymin, 1, 1, GL_RGBA, GL_UNSIGNED_BYTE, &col);
glReadBuffer(GL_BACK);
}
- cp = (unsigned char *)&col;
+ cp = (uchar *)&col;
if (use_palette) {
rgb_uchar_to_float(color->rgb, cp);
diff --git a/source/blender/editors/sculpt_paint/paint_vertex.c b/source/blender/editors/sculpt_paint/paint_vertex.c
index 604146e2ca6..6de54b3ae6a 100644
--- a/source/blender/editors/sculpt_paint/paint_vertex.c
+++ b/source/blender/editors/sculpt_paint/paint_vertex.c
@@ -214,8 +214,8 @@ bool vertex_paint_mode_poll(bContext *C)
static bool vertex_paint_poll_ex(bContext *C, bool check_tool)
{
if (vertex_paint_mode_poll(C) && BKE_paint_brush(&CTX_data_tool_settings(C)->vpaint->paint)) {
- ScrArea *sa = CTX_wm_area(C);
- if (sa && sa->spacetype == SPACE_VIEW3D) {
+ ScrArea *area = CTX_wm_area(C);
+ if (area && area->spacetype == SPACE_VIEW3D) {
ARegion *region = CTX_wm_region(C);
if (region->regiontype == RGN_TYPE_WINDOW) {
if (!check_tool || WM_toolsystem_active_tool_is_brush(C)) {
@@ -247,11 +247,11 @@ bool weight_paint_mode_poll(bContext *C)
static bool weight_paint_poll_ex(bContext *C, bool check_tool)
{
Object *ob = CTX_data_active_object(C);
- ScrArea *sa;
+ ScrArea *area;
if ((ob != NULL) && (ob->mode & OB_MODE_WEIGHT_PAINT) &&
(BKE_paint_brush(&CTX_data_tool_settings(C)->wpaint->paint) != NULL) &&
- (sa = CTX_wm_area(C)) && (sa->spacetype == SPACE_VIEW3D)) {
+ (area = CTX_wm_area(C)) && (area->spacetype == SPACE_VIEW3D)) {
ARegion *region = CTX_wm_region(C);
if (ELEM(region->regiontype, RGN_TYPE_WINDOW, RGN_TYPE_HUD)) {
if (!check_tool || WM_toolsystem_active_tool_is_brush(C)) {
@@ -1193,12 +1193,8 @@ static void vertex_paint_init_session_data(const ToolSettings *ts, Object *ob)
/** \name Enter Vertex/Weight Paint Mode
* \{ */
-static void ed_vwpaintmode_enter_generic(Main *bmain,
- Depsgraph *depsgraph,
- wmWindowManager *wm,
- Scene *scene,
- Object *ob,
- const eObjectMode mode_flag)
+static void ed_vwpaintmode_enter_generic(
+ Main *bmain, Depsgraph *depsgraph, Scene *scene, Object *ob, const eObjectMode mode_flag)
{
ob->mode |= mode_flag;
Mesh *me = BKE_mesh_from_object(ob);
@@ -1214,7 +1210,7 @@ static void ed_vwpaintmode_enter_generic(Main *bmain,
BKE_paint_ensure(scene->toolsettings, (Paint **)&scene->toolsettings->vpaint);
Paint *paint = BKE_paint_get_active_from_paintmode(scene, paint_mode);
- paint_cursor_start_explicit(paint, wm, vertex_paint_poll);
+ paint_cursor_start(paint, vertex_paint_poll);
BKE_paint_init(bmain, scene, paint_mode, PAINT_CURSOR_VERTEX_PAINT);
}
else if (mode_flag == OB_MODE_WEIGHT_PAINT) {
@@ -1222,11 +1218,11 @@ static void ed_vwpaintmode_enter_generic(Main *bmain,
BKE_paint_ensure(scene->toolsettings, (Paint **)&scene->toolsettings->wpaint);
Paint *paint = BKE_paint_get_active_from_paintmode(scene, paint_mode);
- paint_cursor_start_explicit(paint, wm, weight_paint_poll);
+ paint_cursor_start(paint, weight_paint_poll);
BKE_paint_init(bmain, scene, paint_mode, PAINT_CURSOR_WEIGHT_PAINT);
/* weight paint specific */
- ED_mesh_mirror_spatial_table(ob, NULL, NULL, NULL, 's');
+ ED_mesh_mirror_spatial_table_end(ob);
ED_vgroup_sync_from_pose(ob);
}
else {
@@ -1248,32 +1244,28 @@ static void ed_vwpaintmode_enter_generic(Main *bmain,
DEG_id_tag_update(&ob->id, ID_RECALC_COPY_ON_WRITE);
}
-void ED_object_vpaintmode_enter_ex(
- Main *bmain, Depsgraph *depsgraph, wmWindowManager *wm, Scene *scene, Object *ob)
+void ED_object_vpaintmode_enter_ex(Main *bmain, Depsgraph *depsgraph, Scene *scene, Object *ob)
{
- ed_vwpaintmode_enter_generic(bmain, depsgraph, wm, scene, ob, OB_MODE_VERTEX_PAINT);
+ ed_vwpaintmode_enter_generic(bmain, depsgraph, scene, ob, OB_MODE_VERTEX_PAINT);
}
void ED_object_vpaintmode_enter(struct bContext *C, Depsgraph *depsgraph)
{
Main *bmain = CTX_data_main(C);
- wmWindowManager *wm = CTX_wm_manager(C);
Scene *scene = CTX_data_scene(C);
Object *ob = CTX_data_active_object(C);
- ED_object_vpaintmode_enter_ex(bmain, depsgraph, wm, scene, ob);
+ ED_object_vpaintmode_enter_ex(bmain, depsgraph, scene, ob);
}
-void ED_object_wpaintmode_enter_ex(
- Main *bmain, Depsgraph *depsgraph, wmWindowManager *wm, Scene *scene, Object *ob)
+void ED_object_wpaintmode_enter_ex(Main *bmain, Depsgraph *depsgraph, Scene *scene, Object *ob)
{
- ed_vwpaintmode_enter_generic(bmain, depsgraph, wm, scene, ob, OB_MODE_WEIGHT_PAINT);
+ ed_vwpaintmode_enter_generic(bmain, depsgraph, scene, ob, OB_MODE_WEIGHT_PAINT);
}
void ED_object_wpaintmode_enter(struct bContext *C, Depsgraph *depsgraph)
{
Main *bmain = CTX_data_main(C);
- wmWindowManager *wm = CTX_wm_manager(C);
Scene *scene = CTX_data_scene(C);
Object *ob = CTX_data_active_object(C);
- ED_object_wpaintmode_enter_ex(bmain, depsgraph, wm, scene, ob);
+ ED_object_wpaintmode_enter_ex(bmain, depsgraph, scene, ob);
}
/** \} */
@@ -1318,8 +1310,8 @@ static void ed_vwpaintmode_exit_generic(Object *ob, const eObjectMode mode_flag)
paint_cursor_delete_textures();
if (mode_flag == OB_MODE_WEIGHT_PAINT) {
- ED_mesh_mirror_spatial_table(NULL, NULL, NULL, NULL, 'e');
- ED_mesh_mirror_topo_table(NULL, NULL, 'e');
+ ED_mesh_mirror_spatial_table_end(ob);
+ ED_mesh_mirror_topo_table_end(ob);
}
/* Never leave derived meshes behind. */
@@ -1384,8 +1376,7 @@ static int wpaint_mode_toggle_exec(bContext *C, wmOperator *op)
if (depsgraph) {
depsgraph = CTX_data_ensure_evaluated_depsgraph(C);
}
- wmWindowManager *wm = CTX_wm_manager(C);
- ED_object_wpaintmode_enter_ex(bmain, depsgraph, wm, scene, ob);
+ ED_object_wpaintmode_enter_ex(bmain, depsgraph, scene, ob);
BKE_paint_toolslots_brush_validate(bmain, &ts->wpaint->paint);
}
@@ -1398,7 +1389,7 @@ static int wpaint_mode_toggle_exec(bContext *C, wmOperator *op)
*/
{
VirtualModifierData virtualModifierData;
- ModifierData *md = modifiers_getVirtualModifierList(ob, &virtualModifierData);
+ ModifierData *md = BKE_modifiers_get_virtual_modifierlist(ob, &virtualModifierData);
if (md != NULL) {
/* Can be NULL. */
View3D *v3d = CTX_wm_view3d(C);
@@ -1450,8 +1441,7 @@ static int wpaint_mode_toggle_exec(bContext *C, wmOperator *op)
return OPERATOR_FINISHED;
}
-/* for switching to/from mode */
-static bool paint_poll_test(bContext *C)
+static bool paint_mode_toggle_poll_test(bContext *C)
{
Object *ob = CTX_data_active_object(C);
if (ob == NULL || ob->type != OB_MESH) {
@@ -1460,9 +1450,6 @@ static bool paint_poll_test(bContext *C)
if (!ob->data || ID_IS_LINKED(ob->data)) {
return 0;
}
- if (CTX_data_edit_object(C)) {
- return 0;
- }
return 1;
}
@@ -1476,7 +1463,7 @@ void PAINT_OT_weight_paint_toggle(wmOperatorType *ot)
/* api callbacks */
ot->exec = wpaint_mode_toggle_exec;
- ot->poll = paint_poll_test;
+ ot->poll = paint_mode_toggle_poll_test;
/* flags */
ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
@@ -2183,9 +2170,9 @@ static void calculate_average_weight(SculptThreadedTaskData *data,
struct WPaintAverageAccum *accum = MEM_mallocN(sizeof(*accum) * totnode, __func__);
data->custom_data = accum;
- PBVHParallelSettings settings;
+ TaskParallelSettings settings;
BKE_pbvh_parallel_range_settings(&settings, (data->sd->flags & SCULPT_USE_OPENMP), totnode);
- BKE_pbvh_parallel_range(0, totnode, data, do_wpaint_brush_calc_average_weight_cb_ex, &settings);
+ BLI_task_parallel_range(0, totnode, data, do_wpaint_brush_calc_average_weight_cb_ex, &settings);
uint accum_len = 0;
double accum_weight = 0.0;
@@ -2231,22 +2218,22 @@ static void wpaint_paint_leaves(bContext *C,
data.strength = BKE_brush_weight_get(scene, brush);
/* NOTE: current mirroring code cannot be run in parallel */
- PBVHParallelSettings settings;
+ TaskParallelSettings settings;
BKE_pbvh_parallel_range_settings(&settings, !(me->editflag & ME_EDIT_MIRROR_X), totnode);
switch ((eBrushWeightPaintTool)brush->weightpaint_tool) {
case WPAINT_TOOL_AVERAGE:
calculate_average_weight(&data, nodes, totnode);
- BKE_pbvh_parallel_range(0, totnode, &data, do_wpaint_brush_draw_task_cb_ex, &settings);
+ BLI_task_parallel_range(0, totnode, &data, do_wpaint_brush_draw_task_cb_ex, &settings);
break;
case WPAINT_TOOL_SMEAR:
- BKE_pbvh_parallel_range(0, totnode, &data, do_wpaint_brush_smear_task_cb_ex, &settings);
+ BLI_task_parallel_range(0, totnode, &data, do_wpaint_brush_smear_task_cb_ex, &settings);
break;
case WPAINT_TOOL_BLUR:
- BKE_pbvh_parallel_range(0, totnode, &data, do_wpaint_brush_blur_task_cb_ex, &settings);
+ BLI_task_parallel_range(0, totnode, &data, do_wpaint_brush_blur_task_cb_ex, &settings);
break;
case WPAINT_TOOL_DRAW:
- BKE_pbvh_parallel_range(0, totnode, &data, do_wpaint_brush_draw_task_cb_ex, &settings);
+ BLI_task_parallel_range(0, totnode, &data, do_wpaint_brush_draw_task_cb_ex, &settings);
break;
}
}
@@ -2655,8 +2642,7 @@ static int vpaint_mode_toggle_exec(bContext *C, wmOperator *op)
if (depsgraph) {
depsgraph = CTX_data_ensure_evaluated_depsgraph(C);
}
- wmWindowManager *wm = CTX_wm_manager(C);
- ED_object_vpaintmode_enter_ex(bmain, depsgraph, wm, scene, ob);
+ ED_object_vpaintmode_enter_ex(bmain, depsgraph, scene, ob);
BKE_paint_toolslots_brush_validate(bmain, &ts->vpaint->paint);
}
@@ -2683,7 +2669,7 @@ void PAINT_OT_vertex_paint_toggle(wmOperatorType *ot)
/* api callbacks */
ot->exec = vpaint_mode_toggle_exec;
- ot->poll = paint_poll_test;
+ ot->poll = paint_mode_toggle_poll_test;
/* flags */
ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
@@ -2698,19 +2684,19 @@ void PAINT_OT_vertex_paint_toggle(wmOperatorType *ot)
/* Implementation notes:
*
* Operator->invoke()
- * - validate context (add mcol)
- * - create customdata storage
- * - call paint once (mouse click)
- * - add modal handler
+ * - Validate context (add #Mesh.mloopcol).
+ * - Create custom-data storage.
+ * - Call paint once (mouse click).
+ * - Add modal handler.
*
* Operator->modal()
- * - for every mousemove, apply vertex paint
- * - exit on mouse release, free customdata
+ * - For every mouse-move, apply vertex paint.
+ * - Exit on mouse release, free custom-data.
* (return OPERATOR_FINISHED also removes handler and operator)
*
* For future:
- * - implement a stroke event (or mousemove with past positions)
- * - revise whether op->customdata should be added in object, in set_vpaint
+ * - implement a stroke event (or mouse-move with past positions).
+ * - revise whether op->customdata should be added in object, in set_vpaint.
*/
struct VPaintData {
@@ -2722,8 +2708,10 @@ struct VPaintData {
struct VertProjHandle *vp_handle;
struct CoNo *vertexcosnos;
- /* modify 'me->mcol' directly, since the derived mesh is drawing from this
- * array, otherwise we need to refresh the modifier stack */
+ /**
+ * Modify #Mesh.mloopcol directly, since the derived mesh is drawing from this
+ * array, otherwise we need to refresh the modifier stack.
+ */
bool use_fast_update;
/* loops tagged as having been painted, to apply shared vertex color
@@ -3252,9 +3240,9 @@ static void calculate_average_color(SculptThreadedTaskData *data,
struct VPaintAverageAccum *accum = MEM_mallocN(sizeof(*accum) * totnode, __func__);
data->custom_data = accum;
- PBVHParallelSettings settings;
+ TaskParallelSettings settings;
BKE_pbvh_parallel_range_settings(&settings, true, totnode);
- BKE_pbvh_parallel_range(0, totnode, data, do_vpaint_brush_calc_average_color_cb_ex, &settings);
+ BLI_task_parallel_range(0, totnode, data, do_vpaint_brush_calc_average_color_cb_ex, &settings);
uint accum_len = 0;
uint accum_value[3] = {0};
@@ -3298,21 +3286,21 @@ static void vpaint_paint_leaves(bContext *C,
.lcol = (uint *)me->mloopcol,
.me = me,
};
- PBVHParallelSettings settings;
+ TaskParallelSettings settings;
BKE_pbvh_parallel_range_settings(&settings, true, totnode);
switch ((eBrushVertexPaintTool)brush->vertexpaint_tool) {
case VPAINT_TOOL_AVERAGE:
calculate_average_color(&data, nodes, totnode);
- BKE_pbvh_parallel_range(0, totnode, &data, do_vpaint_brush_draw_task_cb_ex, &settings);
+ BLI_task_parallel_range(0, totnode, &data, do_vpaint_brush_draw_task_cb_ex, &settings);
break;
case VPAINT_TOOL_BLUR:
- BKE_pbvh_parallel_range(0, totnode, &data, do_vpaint_brush_blur_task_cb_ex, &settings);
+ BLI_task_parallel_range(0, totnode, &data, do_vpaint_brush_blur_task_cb_ex, &settings);
break;
case VPAINT_TOOL_SMEAR:
- BKE_pbvh_parallel_range(0, totnode, &data, do_vpaint_brush_smear_task_cb_ex, &settings);
+ BLI_task_parallel_range(0, totnode, &data, do_vpaint_brush_smear_task_cb_ex, &settings);
break;
case VPAINT_TOOL_DRAW:
- BKE_pbvh_parallel_range(0, totnode, &data, do_vpaint_brush_draw_task_cb_ex, &settings);
+ BLI_task_parallel_range(0, totnode, &data, do_vpaint_brush_draw_task_cb_ex, &settings);
break;
}
}
diff --git a/source/blender/editors/sculpt_paint/paint_vertex_color_ops.c b/source/blender/editors/sculpt_paint/paint_vertex_color_ops.c
index 6e706c907dd..addf7e9f868 100644
--- a/source/blender/editors/sculpt_paint/paint_vertex_color_ops.c
+++ b/source/blender/editors/sculpt_paint/paint_vertex_color_ops.c
@@ -109,7 +109,7 @@ static int vertex_color_set_exec(bContext *C, wmOperator *UNUSED(op))
{
Scene *scene = CTX_data_scene(C);
Object *obact = CTX_data_active_object(C);
- unsigned int paintcol = vpaint_get_current_col(scene, scene->toolsettings->vpaint, false);
+ uint paintcol = vpaint_get_current_col(scene, scene->toolsettings->vpaint, false);
if (vertex_color_set(obact, paintcol)) {
WM_event_add_notifier(C, NC_OBJECT | ND_DRAW, obact);
diff --git a/source/blender/editors/sculpt_paint/paint_vertex_weight_ops.c b/source/blender/editors/sculpt_paint/paint_vertex_weight_ops.c
index 103f312975a..08ffd8e620e 100644
--- a/source/blender/editors/sculpt_paint/paint_vertex_weight_ops.c
+++ b/source/blender/editors/sculpt_paint/paint_vertex_weight_ops.c
@@ -108,7 +108,7 @@ static bool weight_from_bones_poll(bContext *C)
{
Object *ob = CTX_data_active_object(C);
- return (ob && (ob->mode & OB_MODE_WEIGHT_PAINT) && modifiers_isDeformedByArmature(ob));
+ return (ob && (ob->mode & OB_MODE_WEIGHT_PAINT) && BKE_modifiers_is_deformed_by_armature(ob));
}
static int weight_from_bones_exec(bContext *C, wmOperator *op)
@@ -116,7 +116,7 @@ static int weight_from_bones_exec(bContext *C, wmOperator *op)
Depsgraph *depsgraph = CTX_data_ensure_evaluated_depsgraph(C);
Scene *scene = CTX_data_scene(C);
Object *ob = CTX_data_active_object(C);
- Object *armob = modifiers_isDeformedByArmature(ob);
+ Object *armob = BKE_modifiers_is_deformed_by_armature(ob);
Mesh *me = ob->data;
int type = RNA_enum_get(op->ptr, "type");
diff --git a/source/blender/editors/sculpt_paint/paint_vertex_weight_utils.c b/source/blender/editors/sculpt_paint/paint_vertex_weight_utils.c
index 5a3067ef193..a483f63bc06 100644
--- a/source/blender/editors/sculpt_paint/paint_vertex_weight_utils.c
+++ b/source/blender/editors/sculpt_paint/paint_vertex_weight_utils.c
@@ -82,7 +82,7 @@ bool ED_wpaint_ensure_data(bContext *C,
/* this happens on a Bone select, when no vgroup existed yet */
if (ob->actdef <= 0) {
Object *modob;
- if ((modob = modifiers_isDeformedByArmature(ob))) {
+ if ((modob = BKE_modifiers_is_deformed_by_armature(ob))) {
Bone *actbone = ((bArmature *)modob->data)->act_bone;
if (actbone) {
bPoseChannel *pchan = BKE_pose_channel_find_name(modob->pose, actbone->name);
diff --git a/source/blender/editors/sculpt_paint/sculpt.c b/source/blender/editors/sculpt_paint/sculpt.c
index c7b15d0c096..b4ae9c96ba7 100644
--- a/source/blender/editors/sculpt_paint/sculpt.c
+++ b/source/blender/editors/sculpt_paint/sculpt.c
@@ -10,7 +10,7 @@
* 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,
+ * 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) 2006 by Nicholas Bishop
@@ -153,12 +153,19 @@ const float *SCULPT_vertex_co_get(SculptSession *ss, int index)
return NULL;
}
-static void SCULPT_vertex_normal_get(SculptSession *ss, int index, float no[3])
+void SCULPT_vertex_normal_get(SculptSession *ss, int index, float no[3])
{
switch (BKE_pbvh_type(ss->pbvh)) {
- case PBVH_FACES:
- normal_short_to_float_v3(no, ss->mvert[index].no);
- return;
+ case PBVH_FACES: {
+ if (ss->shapekey_active || ss->deform_modifiers_active) {
+ const MVert *mverts = BKE_pbvh_get_verts(ss->pbvh);
+ normal_short_to_float_v3(no, mverts[index].no);
+ }
+ else {
+ normal_short_to_float_v3(no, ss->mvert[index].no);
+ }
+ break;
+ }
case PBVH_BMESH:
copy_v3_v3(no, BM_vert_at_index(BKE_pbvh_get_bmesh(ss->pbvh), index)->no);
break;
@@ -196,33 +203,43 @@ float SCULPT_vertex_mask_get(SculptSession *ss, int index)
return 0.0f;
}
-static int SCULPT_active_vertex_get(SculptSession *ss)
+int SCULPT_active_vertex_get(SculptSession *ss)
{
- switch (BKE_pbvh_type(ss->pbvh)) {
- case PBVH_FACES:
- return ss->active_vertex_index;
- case PBVH_BMESH:
- return ss->active_vertex_index;
- case PBVH_GRIDS:
- return ss->active_vertex_index;
+ if (ELEM(BKE_pbvh_type(ss->pbvh), PBVH_FACES, PBVH_BMESH, PBVH_GRIDS)) {
+ return ss->active_vertex_index;
}
-
return 0;
}
-static const float *SCULPT_active_vertex_co_get(SculptSession *ss)
+const float *SCULPT_active_vertex_co_get(SculptSession *ss)
{
return SCULPT_vertex_co_get(ss, SCULPT_active_vertex_get(ss));
}
-static void SCULPT_active_vertex_normal_get(SculptSession *ss, float normal[3])
+void SCULPT_active_vertex_normal_get(SculptSession *ss, float normal[3])
{
SCULPT_vertex_normal_get(ss, SCULPT_active_vertex_get(ss), normal);
}
/* Sculpt Face Sets and Visibility. */
-static void SCULPT_vertex_visible_set(SculptSession *ss, int index, bool visible)
+int SCULPT_active_face_set_get(SculptSession *ss)
+{
+ switch (BKE_pbvh_type(ss->pbvh)) {
+ case PBVH_FACES:
+ return ss->face_sets[ss->active_face_index];
+ case PBVH_GRIDS: {
+ const int face_index = BKE_subdiv_ccg_grid_to_face_index(ss->subdiv_ccg,
+ ss->active_grid_index);
+ return ss->face_sets[face_index];
+ }
+ case PBVH_BMESH:
+ return SCULPT_FACE_SET_NONE;
+ }
+ return SCULPT_FACE_SET_NONE;
+}
+
+void SCULPT_vertex_visible_set(SculptSession *ss, int index, bool visible)
{
switch (BKE_pbvh_type(ss->pbvh)) {
case PBVH_FACES:
@@ -237,24 +254,32 @@ static void SCULPT_vertex_visible_set(SculptSession *ss, int index, bool visible
}
}
-static bool SCULPT_vertex_visible_get(SculptSession *ss, int index)
+bool SCULPT_vertex_visible_get(SculptSession *ss, int index)
{
switch (BKE_pbvh_type(ss->pbvh)) {
case PBVH_FACES:
return !(ss->mvert[index].flag & ME_HIDE);
case PBVH_BMESH:
return !BM_elem_flag_test(BM_vert_at_index(ss->bm, index), BM_ELEM_HIDDEN);
- case PBVH_GRIDS:
- return true;
+ case PBVH_GRIDS: {
+ const CCGKey *key = BKE_pbvh_get_grid_key(ss->pbvh);
+ const int grid_index = index / key->grid_area;
+ const int vertex_index = index - grid_index * key->grid_area;
+ BLI_bitmap **grid_hidden = BKE_pbvh_get_grid_visibility(ss->pbvh);
+ if (grid_hidden && grid_hidden[grid_index]) {
+ return !BLI_BITMAP_TEST(grid_hidden[grid_index], vertex_index);
+ }
+ }
}
return true;
}
-static void SCULPT_face_set_visibility_set(SculptSession *ss, int face_set, bool visible)
+void SCULPT_face_set_visibility_set(SculptSession *ss, int face_set, bool visible)
{
switch (BKE_pbvh_type(ss->pbvh)) {
case PBVH_FACES:
- for (int i = 0; i < ss->totpoly; i++) {
+ case PBVH_GRIDS:
+ for (int i = 0; i < ss->totfaces; i++) {
if (abs(ss->face_sets[i]) == face_set) {
if (visible) {
ss->face_sets[i] = abs(ss->face_sets[i]);
@@ -267,31 +292,29 @@ static void SCULPT_face_set_visibility_set(SculptSession *ss, int face_set, bool
break;
case PBVH_BMESH:
break;
- case PBVH_GRIDS:
- break;
}
}
-static void SCULPT_face_sets_visibility_invert(SculptSession *ss)
+void SCULPT_face_sets_visibility_invert(SculptSession *ss)
{
switch (BKE_pbvh_type(ss->pbvh)) {
case PBVH_FACES:
- for (int i = 0; i < ss->totpoly; i++) {
+ case PBVH_GRIDS:
+ for (int i = 0; i < ss->totfaces; i++) {
ss->face_sets[i] *= -1;
}
break;
case PBVH_BMESH:
break;
- case PBVH_GRIDS:
- break;
}
}
-static void SCULPT_face_sets_visibility_all_set(SculptSession *ss, bool visible)
+void SCULPT_face_sets_visibility_all_set(SculptSession *ss, bool visible)
{
switch (BKE_pbvh_type(ss->pbvh)) {
case PBVH_FACES:
- for (int i = 0; i < ss->totpoly; i++) {
+ case PBVH_GRIDS:
+ for (int i = 0; i < ss->totfaces; i++) {
/* This can run on geometry without a face set assigned, so its ID sign can't be changed to
* modify the visibility. Force that geometry to the ID 1 to enable changing the visibility
@@ -310,12 +333,10 @@ static void SCULPT_face_sets_visibility_all_set(SculptSession *ss, bool visible)
break;
case PBVH_BMESH:
break;
- case PBVH_GRIDS:
- break;
}
}
-static bool SCULPT_vertex_any_face_set_visible_get(SculptSession *ss, int index)
+bool SCULPT_vertex_any_face_set_visible_get(SculptSession *ss, int index)
{
switch (BKE_pbvh_type(ss->pbvh)) {
case PBVH_FACES: {
@@ -335,7 +356,7 @@ static bool SCULPT_vertex_any_face_set_visible_get(SculptSession *ss, int index)
return true;
}
-static bool SCULPT_vertex_all_face_sets_visible_get(SculptSession *ss, int index)
+bool SCULPT_vertex_all_face_sets_visible_get(SculptSession *ss, int index)
{
switch (BKE_pbvh_type(ss->pbvh)) {
case PBVH_FACES: {
@@ -349,13 +370,17 @@ static bool SCULPT_vertex_all_face_sets_visible_get(SculptSession *ss, int index
}
case PBVH_BMESH:
return true;
- case PBVH_GRIDS:
- return true;
+ case PBVH_GRIDS: {
+ const CCGKey *key = BKE_pbvh_get_grid_key(ss->pbvh);
+ const int grid_index = index / key->grid_area;
+ const int face_index = BKE_subdiv_ccg_grid_to_face_index(ss->subdiv_ccg, grid_index);
+ return ss->face_sets[face_index] > 0;
+ }
}
return true;
}
-static void SCULPT_vertex_face_set_set(SculptSession *ss, int index, int face_set)
+void SCULPT_vertex_face_set_set(SculptSession *ss, int index, int face_set)
{
switch (BKE_pbvh_type(ss->pbvh)) {
case PBVH_FACES: {
@@ -368,12 +393,19 @@ static void SCULPT_vertex_face_set_set(SculptSession *ss, int index, int face_se
} break;
case PBVH_BMESH:
break;
- case PBVH_GRIDS:
- break;
+ case PBVH_GRIDS: {
+ const CCGKey *key = BKE_pbvh_get_grid_key(ss->pbvh);
+ const int grid_index = index / key->grid_area;
+ const int face_index = BKE_subdiv_ccg_grid_to_face_index(ss->subdiv_ccg, grid_index);
+ if (ss->face_sets[face_index] > 0) {
+ ss->face_sets[face_index] = abs(face_set);
+ }
+
+ } break;
}
}
-static int SCULPT_vertex_face_set_get(SculptSession *ss, int index)
+int SCULPT_vertex_face_set_get(SculptSession *ss, int index)
{
switch (BKE_pbvh_type(ss->pbvh)) {
case PBVH_FACES: {
@@ -388,13 +420,17 @@ static int SCULPT_vertex_face_set_get(SculptSession *ss, int index)
}
case PBVH_BMESH:
return 0;
- case PBVH_GRIDS:
- return 0;
+ case PBVH_GRIDS: {
+ const CCGKey *key = BKE_pbvh_get_grid_key(ss->pbvh);
+ const int grid_index = index / key->grid_area;
+ const int face_index = BKE_subdiv_ccg_grid_to_face_index(ss->subdiv_ccg, grid_index);
+ return ss->face_sets[face_index];
+ }
}
return 0;
}
-static bool SCULPT_vertex_has_face_set(SculptSession *ss, int index, int face_set)
+bool SCULPT_vertex_has_face_set(SculptSession *ss, int index, int face_set)
{
switch (BKE_pbvh_type(ss->pbvh)) {
case PBVH_FACES: {
@@ -408,8 +444,12 @@ static bool SCULPT_vertex_has_face_set(SculptSession *ss, int index, int face_se
}
case PBVH_BMESH:
return true;
- case PBVH_GRIDS:
- return true;
+ case PBVH_GRIDS: {
+ const CCGKey *key = BKE_pbvh_get_grid_key(ss->pbvh);
+ const int grid_index = index / key->grid_area;
+ const int face_index = BKE_subdiv_ccg_grid_to_face_index(ss->subdiv_ccg, grid_index);
+ return ss->face_sets[face_index] == face_set;
+ }
}
return true;
}
@@ -421,12 +461,23 @@ static void sculpt_visibility_sync_face_sets_to_vertex(SculptSession *ss, int in
void SCULPT_visibility_sync_all_face_sets_to_vertices(SculptSession *ss)
{
- for (int i = 0; i < ss->totvert; i++) {
- sculpt_visibility_sync_face_sets_to_vertex(ss, i);
+ switch (BKE_pbvh_type(ss->pbvh)) {
+ case PBVH_FACES: {
+ for (int i = 0; i < ss->totvert; i++) {
+ sculpt_visibility_sync_face_sets_to_vertex(ss, i);
+ }
+ break;
+ }
+ case PBVH_GRIDS: {
+ BKE_pbvh_sync_face_sets_to_grids(ss->pbvh);
+ }
+ case PBVH_BMESH:
+ break;
}
}
-static void sculpt_visibility_sync_vertex_to_face_sets(SculptSession *ss, int index)
+static void UNUSED_FUNCTION(sculpt_visibility_sync_vertex_to_face_sets)(SculptSession *ss,
+ int index)
{
MeshElemMap *vert_map = &ss->pmap[index];
const bool visible = SCULPT_vertex_visible_get(ss, index);
@@ -444,7 +495,7 @@ static void sculpt_visibility_sync_vertex_to_face_sets(SculptSession *ss, int in
void SCULPT_visibility_sync_all_vertex_to_face_sets(SculptSession *ss)
{
if (BKE_pbvh_type(ss->pbvh) == PBVH_FACES) {
- for (int i = 0; i < ss->totpoly; i++) {
+ for (int i = 0; i < ss->totfaces; i++) {
MPoly *poly = &ss->mpoly[i];
bool poly_visible = true;
for (int l = 0; l < poly->totloop; l++) {
@@ -463,7 +514,7 @@ void SCULPT_visibility_sync_all_vertex_to_face_sets(SculptSession *ss)
}
}
-static bool sculpt_vertex_has_unique_face_set(SculptSession *ss, int index)
+bool SCULPT_vertex_has_unique_face_set(SculptSession *ss, int index)
{
switch (BKE_pbvh_type(ss->pbvh)) {
case PBVH_FACES: {
@@ -484,17 +535,18 @@ static bool sculpt_vertex_has_unique_face_set(SculptSession *ss, int index)
case PBVH_BMESH:
return false;
case PBVH_GRIDS:
- return false;
+ return true;
}
return false;
}
-static int SCULPT_face_set_next_available_get(SculptSession *ss)
+int SCULPT_face_set_next_available_get(SculptSession *ss)
{
switch (BKE_pbvh_type(ss->pbvh)) {
- case PBVH_FACES: {
+ case PBVH_FACES:
+ case PBVH_GRIDS: {
int next_face_set = 0;
- for (int i = 0; i < ss->totpoly; i++) {
+ for (int i = 0; i < ss->totfaces; i++) {
if (abs(ss->face_sets[i]) > next_face_set) {
next_face_set = abs(ss->face_sets[i]);
}
@@ -504,8 +556,6 @@ static int SCULPT_face_set_next_available_get(SculptSession *ss)
}
case PBVH_BMESH:
return 0;
- case PBVH_GRIDS:
- return 0;
}
return 0;
}
@@ -638,7 +688,7 @@ void SCULPT_vertex_neighbors_get(SculptSession *ss,
}
}
-static bool sculpt_vertex_is_boundary(SculptSession *ss, const int index)
+bool SCULPT_vertex_is_boundary(SculptSession *ss, const int index)
{
switch (BKE_pbvh_type(ss->pbvh)) {
case PBVH_FACES: {
@@ -770,12 +820,12 @@ int SCULPT_nearest_vertex_get(
nvtd.nearest_vertex_index = -1;
nvtd.nearest_vertex_distance_squared = FLT_MAX;
- PBVHParallelSettings settings;
+ TaskParallelSettings settings;
BKE_pbvh_parallel_range_settings(&settings, (sd->flags & SCULPT_USE_OPENMP), totnode);
settings.func_reduce = nearest_vertex_get_reduce;
settings.userdata_chunk = &nvtd;
settings.userdata_chunk_size = sizeof(NearestVertexTLSData);
- BKE_pbvh_parallel_range(0, totnode, &task_data, do_nearest_vertex_get_task_cb, &settings);
+ BLI_task_parallel_range(0, totnode, &task_data, do_nearest_vertex_get_task_cb, &settings);
MEM_SAFE_FREE(nodes);
@@ -788,10 +838,10 @@ bool SCULPT_is_symmetry_iteration_valid(char i, char symm)
}
/* Checks if a vertex is inside the brush radius from any of its mirrored axis. */
-static bool sculpt_is_vertex_inside_brush_radius_symm(const float vertex[3],
- const float br_co[3],
- float radius,
- char symm)
+bool SCULPT_is_vertex_inside_brush_radius_symm(const float vertex[3],
+ const float br_co[3],
+ float radius,
+ char symm)
{
for (char i = 0; i <= symm; ++i) {
if (SCULPT_is_symmetry_iteration_valid(i, symm)) {
@@ -815,14 +865,38 @@ void SCULPT_floodfill_init(SculptSession *ss, SculptFloodFill *flood)
SCULPT_vertex_random_access_init(ss);
flood->queue = BLI_gsqueue_new(sizeof(int));
- flood->visited_vertices = MEM_callocN(vertex_count * sizeof(char), "visited vertices");
+ flood->visited_vertices = BLI_BITMAP_NEW(vertex_count, "visited vertices");
}
-static void sculpt_floodfill_add_initial(SculptFloodFill *flood, int index)
+void SCULPT_floodfill_add_initial(SculptFloodFill *flood, int index)
{
BLI_gsqueue_push(flood->queue, &index);
}
+void SCULPT_floodfill_add_initial_with_symmetry(
+ Sculpt *sd, Object *ob, SculptSession *ss, SculptFloodFill *flood, int index, float radius)
+{
+ /* Add active vertex and symmetric vertices to the queue. */
+ const char symm = sd->paint.symmetry_flags & PAINT_SYMM_AXIS_ALL;
+ for (char i = 0; i <= symm; ++i) {
+ if (SCULPT_is_symmetry_iteration_valid(i, symm)) {
+ int v = -1;
+ if (i == 0) {
+ v = index;
+ }
+ else if (radius > 0.0f) {
+ float radius_squared = (radius == FLT_MAX) ? FLT_MAX : radius * radius;
+ float location[3];
+ flip_v3_v3(location, SCULPT_vertex_co_get(ss, index), i);
+ v = SCULPT_nearest_vertex_get(sd, ob, location, radius_squared, false);
+ }
+ if (v != -1) {
+ SCULPT_floodfill_add_initial(flood, v);
+ }
+ }
+ }
+}
+
void SCULPT_floodfill_add_active(
Sculpt *sd, Object *ob, SculptSession *ss, SculptFloodFill *flood, float radius)
{
@@ -841,7 +915,7 @@ void SCULPT_floodfill_add_active(
v = SCULPT_nearest_vertex_get(sd, ob, location, radius_squared, false);
}
if (v != -1) {
- sculpt_floodfill_add_initial(flood, v);
+ SCULPT_floodfill_add_initial(flood, v);
}
}
}
@@ -857,18 +931,17 @@ void SCULPT_floodfill_execute(
int from_v;
BLI_gsqueue_pop(flood->queue, &from_v);
SculptVertexNeighborIter ni;
- sculpt_vertex_duplicates_and_neighbors_iter_begin(ss, from_v, ni)
- {
+ SCULPT_VERTEX_DUPLICATES_AND_NEIGHBORS_ITER_BEGIN (ss, from_v, ni) {
const int to_v = ni.index;
- if (flood->visited_vertices[to_v] == 0 && SCULPT_vertex_visible_get(ss, to_v)) {
- flood->visited_vertices[to_v] = 1;
+ if (!BLI_BITMAP_TEST(flood->visited_vertices, to_v) && SCULPT_vertex_visible_get(ss, to_v)) {
+ BLI_BITMAP_ENABLE(flood->visited_vertices, to_v);
if (func(ss, from_v, to_v, ni.is_duplicate, userdata)) {
BLI_gsqueue_push(flood->queue, &to_v);
}
}
}
- sculpt_vertex_neighbors_iter_end(ni);
+ SCULPT_VERTEX_NEIGHBORS_ITER_END(ni);
}
}
@@ -893,11 +966,11 @@ static bool sculpt_has_active_modifiers(Scene *scene, Object *ob)
ModifierData *md;
VirtualModifierData virtualModifierData;
- md = modifiers_getVirtualModifierList(ob, &virtualModifierData);
+ md = BKE_modifiers_get_virtual_modifierlist(ob, &virtualModifierData);
/* Exception for shape keys because we can edit those. */
for (; md; md = md->next) {
- if (modifier_isEnabled(scene, md, eModifierMode_Realtime)) {
+ if (BKE_modifier_is_enabled(scene, md, eModifierMode_Realtime)) {
return true;
}
}
@@ -1137,7 +1210,7 @@ static void sculpt_project_v3(const SculptProjectVector *spvc, const float vec[3
* Factors: some brushes like grab cannot do dynamic topology.
* Others, like smooth, are better without. Same goes for alt-
* key smoothing. */
-static bool sculpt_stroke_is_dynamic_topology(const SculptSession *ss, const Brush *brush)
+bool SCULPT_stroke_is_dynamic_topology(const SculptSession *ss, const Brush *brush)
{
return ((BKE_pbvh_type(ss->pbvh) == PBVH_BMESH) &&
@@ -1224,9 +1297,9 @@ static void paint_mesh_restore_co(Sculpt *sd, Object *ob)
.nodes = nodes,
};
- PBVHParallelSettings settings;
+ TaskParallelSettings settings;
BKE_pbvh_parallel_range_settings(&settings, (sd->flags & SCULPT_USE_OPENMP) && !ss->bm, totnode);
- BKE_pbvh_parallel_range(0, totnode, &data, paint_mesh_restore_co_task_cb, &settings);
+ BLI_task_parallel_range(0, totnode, &data, paint_mesh_restore_co_task_cb, &settings);
MEM_SAFE_FREE(nodes);
}
@@ -1301,6 +1374,8 @@ void SCULPT_brush_test_init(SculptSession *ss, SculptBrushTest *test)
test->radius_squared = ss->cache ? ss->cache->radius_squared :
ss->cursor_radius * ss->cursor_radius;
+ test->radius = sqrtf(test->radius_squared);
+
if (ss->cache) {
copy_v3_v3(test->location, ss->cache->location);
test->mirror_symmetry_pass = ss->cache->mirror_symmetry_pass;
@@ -1524,221 +1599,6 @@ static bool sculpt_brush_test_cyl(SculptBrushTest *test,
#endif
-/* Automasking */
-
-static bool sculpt_automasking_enabled(SculptSession *ss, const Brush *br)
-{
- if (sculpt_stroke_is_dynamic_topology(ss, br)) {
- return false;
- }
- if (br->automasking_flags & BRUSH_AUTOMASKING_TOPOLOGY) {
- return true;
- }
- if (br->automasking_flags & BRUSH_AUTOMASKING_FACE_SETS) {
- return true;
- }
- if (br->automasking_flags & BRUSH_AUTOMASKING_BOUNDARY_EDGES) {
- return true;
- }
- return false;
-}
-
-float SCULPT_automasking_factor_get(SculptSession *ss, int vert)
-{
- if (ss->cache->automask) {
- return ss->cache->automask[vert];
- }
- else {
- return 1.0f;
- }
-}
-
-static void sculpt_automasking_end(Object *ob)
-{
- SculptSession *ss = ob->sculpt;
- if (ss->cache && ss->cache->automask) {
- MEM_freeN(ss->cache->automask);
- }
-}
-
-static bool sculpt_automasking_is_constrained_by_radius(Brush *br)
-{
- /* 2D falloff is not constrained by radius. */
- if (br->falloff_shape == PAINT_FALLOFF_SHAPE_TUBE) {
- return false;
- }
-
- if (ELEM(br->sculpt_tool, SCULPT_TOOL_GRAB, SCULPT_TOOL_THUMB, SCULPT_TOOL_ROTATE)) {
- return true;
- }
- return false;
-}
-
-typedef struct AutomaskFloodFillData {
- float *automask_factor;
- float radius;
- bool use_radius;
- float location[3];
- char symm;
-} AutomaskFloodFillData;
-
-static bool automask_floodfill_cb(
- SculptSession *ss, int UNUSED(from_v), int to_v, bool UNUSED(is_duplicate), void *userdata)
-{
- AutomaskFloodFillData *data = userdata;
-
- data->automask_factor[to_v] = 1.0f;
- return (!data->use_radius ||
- sculpt_is_vertex_inside_brush_radius_symm(
- SCULPT_vertex_co_get(ss, to_v), data->location, data->radius, data->symm));
-}
-
-static float *sculpt_topology_automasking_init(Sculpt *sd, Object *ob, float *automask_factor)
-{
- SculptSession *ss = ob->sculpt;
- Brush *brush = BKE_paint_brush(&sd->paint);
-
- if (!sculpt_automasking_enabled(ss, brush)) {
- return NULL;
- }
-
- if (BKE_pbvh_type(ss->pbvh) == PBVH_FACES && !ss->pmap) {
- BLI_assert(!"Topology masking: pmap missing");
- return NULL;
- }
-
- const int totvert = SCULPT_vertex_count_get(ss);
- for (int i = 0; i < totvert; i++) {
- ss->cache->automask[i] = 0.0f;
- }
-
- /* Flood fill automask to connected vertices. Limited to vertices inside
- * the brush radius if the tool requires it. */
- SculptFloodFill flood;
- SCULPT_floodfill_init(ss, &flood);
- SCULPT_floodfill_add_active(sd, ob, ss, &flood, ss->cache->radius);
-
- AutomaskFloodFillData fdata = {
- .automask_factor = automask_factor,
- .radius = ss->cache->radius,
- .use_radius = sculpt_automasking_is_constrained_by_radius(brush),
- .symm = sd->paint.symmetry_flags & PAINT_SYMM_AXIS_ALL,
- };
- copy_v3_v3(fdata.location, SCULPT_active_vertex_co_get(ss));
- SCULPT_floodfill_execute(ss, &flood, automask_floodfill_cb, &fdata);
- SCULPT_floodfill_free(&flood);
-
- return automask_factor;
-}
-
-static float *sculpt_face_sets_automasking_init(Sculpt *sd, Object *ob, float *automask_factor)
-{
- SculptSession *ss = ob->sculpt;
- Brush *brush = BKE_paint_brush(&sd->paint);
-
- if (!sculpt_automasking_enabled(ss, brush)) {
- return NULL;
- }
-
- if (BKE_pbvh_type(ss->pbvh) == PBVH_FACES && !ss->pmap) {
- BLI_assert(!"Face Sets automasking: pmap missing");
- return NULL;
- }
-
- int tot_vert = SCULPT_vertex_count_get(ss);
- int active_face_set = SCULPT_vertex_face_set_get(ss, SCULPT_active_vertex_get(ss));
- for (int i = 0; i < tot_vert; i++) {
- if (!SCULPT_vertex_has_face_set(ss, i, active_face_set)) {
- automask_factor[i] *= 0.0f;
- }
- }
-
- return automask_factor;
-}
-
-#define EDGE_DISTANCE_INF -1
-
-static float *sculpt_boundary_edges_automasking_init(Object *ob,
- int propagation_steps,
- float *automask_factor)
-{
- SculptSession *ss = ob->sculpt;
-
- if (BKE_pbvh_type(ss->pbvh) == PBVH_FACES && !ss->pmap) {
- BLI_assert(!"Boundary Edges masking: pmap missing");
- return NULL;
- }
-
- const int totvert = SCULPT_vertex_count_get(ss);
- int *edge_distance = MEM_callocN(sizeof(int) * totvert, "automask_factor");
-
- for (int i = 0; i < totvert; i++) {
- edge_distance[i] = EDGE_DISTANCE_INF;
- if (!sculpt_vertex_is_boundary(ss, i)) {
- edge_distance[i] = 0;
- }
- }
-
- for (int propagation_it = 0; propagation_it < propagation_steps; propagation_it++) {
- for (int i = 0; i < totvert; i++) {
- if (edge_distance[i] == EDGE_DISTANCE_INF) {
- SculptVertexNeighborIter ni;
- sculpt_vertex_neighbors_iter_begin(ss, i, ni)
- {
- if (edge_distance[ni.index] == propagation_it) {
- edge_distance[i] = propagation_it + 1;
- }
- }
- sculpt_vertex_neighbors_iter_end(ni);
- }
- }
- }
-
- for (int i = 0; i < totvert; i++) {
- if (edge_distance[i] != EDGE_DISTANCE_INF) {
- const float p = 1.0f - ((float)edge_distance[i] / (float)propagation_steps);
- const float edge_boundary_automask = 3.0f * p * p - 2.0f * p * p * p;
- automask_factor[i] *= (1.0f - edge_boundary_automask);
- }
- }
-
- MEM_SAFE_FREE(edge_distance);
- return automask_factor;
-}
-
-static void sculpt_automasking_init(Sculpt *sd, Object *ob)
-{
- SculptSession *ss = ob->sculpt;
- Brush *brush = BKE_paint_brush(&sd->paint);
- const int totvert = SCULPT_vertex_count_get(ss);
-
- if (!sculpt_automasking_enabled(ss, brush)) {
- return;
- }
-
- ss->cache->automask = MEM_callocN(sizeof(float) * SCULPT_vertex_count_get(ss),
- "automask_factor");
-
- for (int i = 0; i < totvert; i++) {
- ss->cache->automask[i] = 1.0f;
- }
-
- if (brush->automasking_flags & BRUSH_AUTOMASKING_TOPOLOGY) {
- SCULPT_vertex_random_access_init(ss);
- sculpt_topology_automasking_init(sd, ob, ss->cache->automask);
- }
- if (brush->automasking_flags & BRUSH_AUTOMASKING_FACE_SETS) {
- SCULPT_vertex_random_access_init(ss);
- sculpt_face_sets_automasking_init(sd, ob, ss->cache->automask);
- }
-
- if (brush->automasking_flags & BRUSH_AUTOMASKING_BOUNDARY_EDGES) {
- SCULPT_vertex_random_access_init(ss);
- sculpt_boundary_edges_automasking_init(
- ob, brush->automasking_boundary_edges_propagation_steps, ss->cache->automask);
- }
-}
-
/* ===== Sculpting =====
*/
static void flip_v3(float v[3], const ePaintSymmetryFlags symm)
@@ -1863,10 +1723,8 @@ static void calc_area_normal_and_center_task_cb(void *__restrict userdata,
/* Update the test radius to sample the normal using the normal radius of the brush. */
if (data->brush->ob_mode == OB_MODE_SCULPT) {
float test_radius = sqrtf(normal_test.radius_squared);
- /* Layer brush produces artifacts with normal and area radius. */
- if (!(ss->cache && data->brush->sculpt_tool == SCULPT_TOOL_LAYER)) {
- test_radius *= data->brush->normal_radius_factor;
- }
+ test_radius *= data->brush->normal_radius_factor;
+ normal_test.radius = test_radius;
normal_test.radius_squared = test_radius * test_radius;
}
@@ -1877,16 +1735,15 @@ static void calc_area_normal_and_center_task_cb(void *__restrict userdata,
if (data->brush->ob_mode == OB_MODE_SCULPT) {
float test_radius = sqrtf(area_test.radius_squared);
/* Layer brush produces artifacts with normal and area radius */
- if (!(ss->cache && data->brush->sculpt_tool == SCULPT_TOOL_LAYER)) {
- /* Enable area radius control only on Scrape for now */
- if (ELEM(data->brush->sculpt_tool, SCULPT_TOOL_SCRAPE, SCULPT_TOOL_FILL) &&
- data->brush->area_radius_factor > 0.0f) {
- test_radius *= data->brush->area_radius_factor;
- }
- else {
- test_radius *= data->brush->normal_radius_factor;
- }
+ /* Enable area radius control only on Scrape for now */
+ if (ELEM(data->brush->sculpt_tool, SCULPT_TOOL_SCRAPE, SCULPT_TOOL_FILL) &&
+ data->brush->area_radius_factor > 0.0f) {
+ test_radius *= data->brush->area_radius_factor;
}
+ else {
+ test_radius *= data->brush->normal_radius_factor;
+ }
+ area_test.radius = test_radius;
area_test.radius_squared = test_radius * test_radius;
}
@@ -1920,10 +1777,26 @@ static void calc_area_normal_and_center_task_cb(void *__restrict userdata,
flip_index = (dot_v3v3(ss->cache->view_normal, no) <= 0.0f);
if (use_area_cos && area_test_r) {
+ /* Weight the coordinates towards the center. */
+ float p = 1.0f - (sqrtf(area_test.dist) / area_test.radius);
+ float afactor = 3.0f * p * p - 2.0f * p * p * p;
+ CLAMP(afactor, 0.0f, 1.0f);
+
+ float disp[3];
+ sub_v3_v3v3(disp, co, area_test.location);
+ mul_v3_fl(disp, 1.0f - afactor);
+ add_v3_v3v3(co, area_test.location, disp);
add_v3_v3(anctd->area_cos[flip_index], co);
+
anctd->count_co[flip_index] += 1;
}
if (use_area_nos && normal_test_r) {
+ /* Weight the normals towards the center. */
+ float p = 1.0f - (sqrtf(normal_test.dist) / normal_test.radius);
+ float nfactor = 3.0f * p * p - 2.0f * p * p * p;
+ CLAMP(nfactor, 0.0f, 1.0f);
+ mul_v3_fl(no, nfactor);
+
add_v3_v3(anctd->area_nos[flip_index], no);
anctd->count_no[flip_index] += 1;
}
@@ -1933,54 +1806,73 @@ static void calc_area_normal_and_center_task_cb(void *__restrict userdata,
else {
BKE_pbvh_vertex_iter_begin(ss->pbvh, data->nodes[n], vd, PBVH_ITER_UNIQUE)
{
- const float *co;
+ float co[3];
+
/* For bm_vert only. */
- const short *no_s;
+ short no_s[3];
if (use_original) {
if (unode->bm_entry) {
- BM_log_original_vert_data(ss->bm_log, vd.bm_vert, &co, &no_s);
+ const float *temp_co;
+ const short *temp_no_s;
+ BM_log_original_vert_data(ss->bm_log, vd.bm_vert, &temp_co, &temp_no_s);
+ copy_v3_v3(co, temp_co);
+ copy_v3_v3_short(no_s, temp_no_s);
}
else {
- co = unode->co[vd.i];
- no_s = unode->no[vd.i];
+ copy_v3_v3(co, unode->co[vd.i]);
+ copy_v3_v3_short(no_s, unode->no[vd.i]);
}
}
else {
- co = vd.co;
+ copy_v3_v3(co, vd.co);
}
normal_test_r = sculpt_brush_normal_test_sq_fn(&normal_test, co);
area_test_r = sculpt_brush_area_test_sq_fn(&area_test, co);
if (normal_test_r || area_test_r) {
- float no_buf[3];
- const float *no;
+ float no[3];
int flip_index;
data->any_vertex_sampled = true;
if (use_original) {
- normal_short_to_float_v3(no_buf, no_s);
- no = no_buf;
+ normal_short_to_float_v3(no, no_s);
}
else {
if (vd.no) {
- normal_short_to_float_v3(no_buf, vd.no);
- no = no_buf;
+ normal_short_to_float_v3(no, vd.no);
}
else {
- no = vd.fno;
+ copy_v3_v3(no, vd.fno);
}
}
flip_index = (dot_v3v3(ss->cache ? ss->cache->view_normal : ss->cursor_view_normal, no) <=
0.0f);
+
if (use_area_cos && area_test_r) {
+ /* Weight the coordinates towards the center. */
+ float p = 1.0f - (sqrtf(area_test.dist) / area_test.radius);
+ float afactor = 3.0f * p * p - 2.0f * p * p * p;
+ CLAMP(afactor, 0.0f, 1.0f);
+
+ float disp[3];
+ sub_v3_v3v3(disp, co, area_test.location);
+ mul_v3_fl(disp, 1.0f - afactor);
+ add_v3_v3v3(co, area_test.location, disp);
+
add_v3_v3(anctd->area_cos[flip_index], co);
anctd->count_co[flip_index] += 1;
}
if (use_area_nos && normal_test_r) {
+ /* Weight the normals towards the center. */
+ float p = 1.0f - (sqrtf(normal_test.dist) / normal_test.radius);
+ float nfactor = 3.0f * p * p - 2.0f * p * p * p;
+ CLAMP(nfactor, 0.0f, 1.0f);
+ mul_v3_fl(no, nfactor);
+
add_v3_v3(anctd->area_nos[flip_index], no);
anctd->count_no[flip_index] += 1;
}
@@ -2015,7 +1907,7 @@ static void calc_area_center(
{
const Brush *brush = BKE_paint_brush(&sd->paint);
SculptSession *ss = ob->sculpt;
- const bool has_bm_orco = ss->bm && sculpt_stroke_is_dynamic_topology(ss, brush);
+ const bool has_bm_orco = ss->bm && SCULPT_stroke_is_dynamic_topology(ss, brush);
int n;
/* Intentionally set 'sd' to NULL since we share logic with vertex paint. */
@@ -2031,12 +1923,12 @@ static void calc_area_center(
AreaNormalCenterTLSData anctd = {{{0}}};
- PBVHParallelSettings settings;
+ TaskParallelSettings settings;
BKE_pbvh_parallel_range_settings(&settings, (sd->flags & SCULPT_USE_OPENMP), totnode);
settings.func_reduce = calc_area_normal_and_center_reduce;
settings.userdata_chunk = &anctd;
settings.userdata_chunk_size = sizeof(AreaNormalCenterTLSData);
- BKE_pbvh_parallel_range(0, totnode, &data, calc_area_normal_and_center_task_cb, &settings);
+ BLI_task_parallel_range(0, totnode, &data, calc_area_normal_and_center_task_cb, &settings);
/* For flatten center. */
for (n = 0; n < ARRAY_SIZE(anctd.area_cos); n++) {
@@ -2074,7 +1966,7 @@ bool SCULPT_pbvh_calc_area_normal(const Brush *brush,
float r_area_no[3])
{
SculptSession *ss = ob->sculpt;
- const bool has_bm_orco = ss->bm && sculpt_stroke_is_dynamic_topology(ss, brush);
+ const bool has_bm_orco = ss->bm && SCULPT_stroke_is_dynamic_topology(ss, brush);
/* Intentionally set 'sd' to NULL since this is used for vertex paint too. */
SculptThreadedTaskData data = {
@@ -2090,12 +1982,12 @@ bool SCULPT_pbvh_calc_area_normal(const Brush *brush,
AreaNormalCenterTLSData anctd = {{{0}}};
- PBVHParallelSettings settings;
+ TaskParallelSettings settings;
BKE_pbvh_parallel_range_settings(&settings, use_threading, totnode);
settings.func_reduce = calc_area_normal_and_center_reduce;
settings.userdata_chunk = &anctd;
settings.userdata_chunk_size = sizeof(AreaNormalCenterTLSData);
- BKE_pbvh_parallel_range(0, totnode, &data, calc_area_normal_and_center_task_cb, &settings);
+ BLI_task_parallel_range(0, totnode, &data, calc_area_normal_and_center_task_cb, &settings);
/* For area normal. */
for (int i = 0; i < ARRAY_SIZE(anctd.area_nos); i++) {
@@ -2114,7 +2006,7 @@ static void calc_area_normal_and_center(
{
const Brush *brush = BKE_paint_brush(&sd->paint);
SculptSession *ss = ob->sculpt;
- const bool has_bm_orco = ss->bm && sculpt_stroke_is_dynamic_topology(ss, brush);
+ const bool has_bm_orco = ss->bm && SCULPT_stroke_is_dynamic_topology(ss, brush);
int n;
/* Intentionally set 'sd' to NULL since this is used for vertex paint too. */
@@ -2131,12 +2023,12 @@ static void calc_area_normal_and_center(
AreaNormalCenterTLSData anctd = {{{0}}};
- PBVHParallelSettings settings;
+ TaskParallelSettings settings;
BKE_pbvh_parallel_range_settings(&settings, (sd->flags & SCULPT_USE_OPENMP), totnode);
settings.func_reduce = calc_area_normal_and_center_reduce;
settings.userdata_chunk = &anctd;
settings.userdata_chunk_size = sizeof(AreaNormalCenterTLSData);
- BKE_pbvh_parallel_range(0, totnode, &data, calc_area_normal_and_center_task_cb, &settings);
+ BLI_task_parallel_range(0, totnode, &data, calc_area_normal_and_center_task_cb, &settings);
/* For flatten center. */
for (n = 0; n < ARRAY_SIZE(anctd.area_cos); n++) {
@@ -2206,9 +2098,13 @@ static float brush_strength(const Sculpt *sd,
case SCULPT_TOOL_LAYER:
return alpha * flip * pressure * overlap * feather;
case SCULPT_TOOL_CLOTH:
- /* Expand is more sensible to strength as it keeps expanding the cloth when sculpting over
- * the same vertices. */
- if (brush->cloth_deform_type == BRUSH_CLOTH_DEFORM_EXPAND) {
+ if (brush->cloth_deform_type == BRUSH_CLOTH_DEFORM_GRAB) {
+ /* Grab deform uses the same falloff as a regular grab brush. */
+ return root_alpha * feather;
+ }
+ else if (brush->cloth_deform_type == BRUSH_CLOTH_DEFORM_EXPAND) {
+ /* Expand is more sensible to strength as it keeps expanding the cloth when sculpting over
+ * the same vertices. */
return 0.1f * alpha * flip * pressure * overlap * feather;
}
else {
@@ -2222,7 +2118,7 @@ static float brush_strength(const Sculpt *sd,
return alpha * pressure * overlap * feather * 2.0f;
case SCULPT_TOOL_CLAY_STRIPS:
/* Clay Strips needs less strength to compensate the curve. */
- final_pressure = pressure * pressure * pressure;
+ final_pressure = powf(pressure, 1.5f);
return alpha * flip * final_pressure * overlap * feather * 0.3f;
case SCULPT_TOOL_CLAY_THUMB:
final_pressure = pressure * pressure;
@@ -2476,7 +2372,7 @@ bool SCULPT_search_circle_cb(PBVHNode *node, void *data_v)
}
/* Handles clipping against a mirror modifier and SCULPT_LOCK axis flags. */
-static void sculpt_clip(Sculpt *sd, SculptSession *ss, float co[3], const float val[3])
+void SCULPT_clip(Sculpt *sd, SculptSession *ss, float co[3], const float val[3])
{
for (int i = 0; i < 3; i++) {
if (sd->flags & (SCULPT_LOCK_X << i)) {
@@ -2681,227 +2577,6 @@ static void update_brush_local_mat(Sculpt *sd, Object *ob)
}
}
-/* For the smooth brush, uses the neighboring vertices around vert to calculate
- * a smoothed location for vert. Skips corner vertices (used by only one
- * polygon). */
-static void neighbor_average(SculptSession *ss, float avg[3], uint vert)
-{
- const MeshElemMap *vert_map = &ss->pmap[vert];
- const MVert *mvert = ss->mvert;
- float(*deform_co)[3] = ss->deform_cos;
-
- /* Don't modify corner vertices. */
- if (vert_map->count > 1) {
- int total = 0;
-
- zero_v3(avg);
-
- for (int i = 0; i < vert_map->count; i++) {
- const MPoly *p = &ss->mpoly[vert_map->indices[i]];
- uint f_adj_v[2];
-
- if (poly_get_adj_loops_from_vert(p, ss->mloop, vert, f_adj_v) != -1) {
- for (int j = 0; j < ARRAY_SIZE(f_adj_v); j += 1) {
- if (vert_map->count != 2 || ss->pmap[f_adj_v[j]].count <= 2) {
- add_v3_v3(avg, deform_co ? deform_co[f_adj_v[j]] : mvert[f_adj_v[j]].co);
-
- total++;
- }
- }
- }
- }
-
- if (total > 0) {
- mul_v3_fl(avg, 1.0f / total);
- return;
- }
- }
-
- copy_v3_v3(avg, deform_co ? deform_co[vert] : mvert[vert].co);
-}
-
-/* Similar to neighbor_average(), but returns an averaged mask value
- * instead of coordinate. Also does not restrict based on border or
- * corner vertices. */
-static float neighbor_average_mask(SculptSession *ss, uint vert)
-{
- const float *vmask = ss->vmask;
- float avg = 0.0f;
- int total = 0;
-
- for (int i = 0; i < ss->pmap[vert].count; i++) {
- const MPoly *p = &ss->mpoly[ss->pmap[vert].indices[i]];
- uint f_adj_v[2];
-
- if (poly_get_adj_loops_from_vert(p, ss->mloop, vert, f_adj_v) != -1) {
- for (int j = 0; j < ARRAY_SIZE(f_adj_v); j += 1) {
- avg += vmask[f_adj_v[j]];
- total++;
- }
- }
- }
-
- if (total > 0) {
- return avg / (float)total;
- }
- else {
- return vmask[vert];
- }
-}
-
-/* Same logic as neighbor_average(), but for bmesh rather than mesh. */
-static void bmesh_neighbor_average(float avg[3], BMVert *v)
-{
- /* logic for 3 or more is identical. */
- const int vfcount = BM_vert_face_count_at_most(v, 3);
-
- /* Don't modify corner vertices. */
- if (vfcount > 1) {
- BMIter liter;
- BMLoop *l;
- int total = 0;
-
- zero_v3(avg);
-
- BM_ITER_ELEM (l, &liter, v, BM_LOOPS_OF_VERT) {
- const BMVert *adj_v[2] = {l->prev->v, l->next->v};
-
- for (int i = 0; i < ARRAY_SIZE(adj_v); i++) {
- const BMVert *v_other = adj_v[i];
- if (vfcount != 2 || BM_vert_face_count_at_most(v_other, 2) <= 2) {
- add_v3_v3(avg, v_other->co);
- total++;
- }
- }
- }
-
- if (total > 0) {
- mul_v3_fl(avg, 1.0f / total);
- return;
- }
- }
-
- copy_v3_v3(avg, v->co);
-}
-
-/* For bmesh: Average surrounding verts based on an orthogonality measure.
- * Naturally converges to a quad-like structure. */
-static void bmesh_four_neighbor_average(float avg[3], float direction[3], BMVert *v)
-{
-
- float avg_co[3] = {0.0f, 0.0f, 0.0f};
- float tot_co = 0.0f;
-
- BMIter eiter;
- BMEdge *e;
-
- BM_ITER_ELEM (e, &eiter, v, BM_EDGES_OF_VERT) {
- if (BM_edge_is_boundary(e)) {
- copy_v3_v3(avg, v->co);
- return;
- }
- BMVert *v_other = (e->v1 == v) ? e->v2 : e->v1;
- float vec[3];
- sub_v3_v3v3(vec, v_other->co, v->co);
- madd_v3_v3fl(vec, v->no, -dot_v3v3(vec, v->no));
- normalize_v3(vec);
-
- /* fac is a measure of how orthogonal or parallel the edge is
- * relative to the direction. */
- float fac = dot_v3v3(vec, direction);
- fac = fac * fac - 0.5f;
- fac *= fac;
- madd_v3_v3fl(avg_co, v_other->co, fac);
- tot_co += fac;
- }
-
- /* In case vert has no Edge s. */
- if (tot_co > 0.0f) {
- mul_v3_v3fl(avg, avg_co, 1.0f / tot_co);
-
- /* Preserve volume. */
- float vec[3];
- sub_v3_v3(avg, v->co);
- mul_v3_v3fl(vec, v->no, dot_v3v3(avg, v->no));
- sub_v3_v3(avg, vec);
- add_v3_v3(avg, v->co);
- }
- else {
- zero_v3(avg);
- }
-}
-
-/* Same logic as neighbor_average_mask(), but for bmesh rather than mesh. */
-static float bmesh_neighbor_average_mask(BMVert *v, const int cd_vert_mask_offset)
-{
- BMIter liter;
- BMLoop *l;
- float avg = 0.0f;
- int total = 0;
-
- BM_ITER_ELEM (l, &liter, v, BM_LOOPS_OF_VERT) {
- /* Skip this vertex. */
- const BMVert *adj_v[2] = {l->prev->v, l->next->v};
-
- for (int i = 0; i < ARRAY_SIZE(adj_v); i++) {
- const BMVert *v_other = adj_v[i];
- const float *vmask = BM_ELEM_CD_GET_VOID_P(v_other, cd_vert_mask_offset);
- avg += (*vmask);
- total++;
- }
- }
-
- if (total > 0) {
- return avg / (float)total;
- }
- else {
- const float *vmask = BM_ELEM_CD_GET_VOID_P(v, cd_vert_mask_offset);
- return (*vmask);
- }
-}
-
-static void SCULPT_neighbor_coords_average(SculptSession *ss, float result[3], int index)
-{
- float avg[3] = {0.0f, 0.0f, 0.0f};
- int total = 0;
-
- SculptVertexNeighborIter ni;
- sculpt_vertex_neighbors_iter_begin(ss, index, ni)
- {
- add_v3_v3(avg, SCULPT_vertex_co_get(ss, ni.index));
- total++;
- }
- sculpt_vertex_neighbors_iter_end(ni);
-
- if (total > 0) {
- mul_v3_v3fl(result, avg, 1.0f / (float)total);
- }
- else {
- copy_v3_v3(result, SCULPT_vertex_co_get(ss, index));
- }
-}
-
-static float grids_neighbor_average_mask(SculptSession *ss, int index)
-{
- float avg = 0.0f;
- int total = 0;
-
- SculptVertexNeighborIter ni;
- sculpt_vertex_neighbors_iter_begin(ss, index, ni)
- {
- avg += SCULPT_vertex_mask_get(ss, ni.index);
- total++;
- }
- sculpt_vertex_neighbors_iter_end(ni);
-
- if (total > 0) {
- return avg / (float)total;
- }
- else {
- return SCULPT_vertex_mask_get(ss, index);
- }
-}
-
/* Note: uses after-struct allocated mem to store actual cache... */
typedef struct SculptDoBrushSmoothGridDataChunk {
size_t tmpgrid_size;
@@ -2918,17 +2593,10 @@ typedef struct {
int active_vertex_index;
float *face_normal;
- struct IsectRayPrecalc isect_precalc;
-} SculptRaycastData;
-
-typedef struct {
- const float *ray_start;
- bool hit;
- float depth;
- float edge_length;
+ int active_face_grid_index;
struct IsectRayPrecalc isect_precalc;
-} SculptDetailRaycastData;
+} SculptRaycastData;
typedef struct {
SculptSession *ss;
@@ -2939,119 +2607,6 @@ typedef struct {
bool original;
} SculptFindNearestToRayData;
-static void do_smooth_brush_mesh_task_cb_ex(void *__restrict userdata,
- const int n,
- const TaskParallelTLS *__restrict tls)
-{
- SculptThreadedTaskData *data = userdata;
- SculptSession *ss = data->ob->sculpt;
- Sculpt *sd = data->sd;
- const Brush *brush = data->brush;
- const bool smooth_mask = data->smooth_mask;
- float bstrength = data->strength;
-
- PBVHVertexIter vd;
-
- CLAMP(bstrength, 0.0f, 1.0f);
-
- SculptBrushTest test;
- SculptBrushTestFn sculpt_brush_test_sq_fn = SCULPT_brush_test_init_with_falloff_shape(
- ss, &test, data->brush->falloff_shape);
-
- BKE_pbvh_vertex_iter_begin(ss->pbvh, data->nodes[n], vd, PBVH_ITER_UNIQUE)
- {
- if (sculpt_brush_test_sq_fn(&test, vd.co)) {
- const float fade = bstrength * SCULPT_brush_strength_factor(
- ss,
- brush,
- vd.co,
- sqrtf(test.dist),
- vd.no,
- vd.fno,
- smooth_mask ? 0.0f : (vd.mask ? *vd.mask : 0.0f),
- vd.index,
- tls->thread_id);
- if (smooth_mask) {
- float val = neighbor_average_mask(ss, vd.vert_indices[vd.i]) - *vd.mask;
- val *= fade * bstrength;
- *vd.mask += val;
- CLAMP(*vd.mask, 0.0f, 1.0f);
- }
- else {
- float avg[3], val[3];
-
- neighbor_average(ss, avg, vd.vert_indices[vd.i]);
- sub_v3_v3v3(val, avg, vd.co);
-
- madd_v3_v3v3fl(val, vd.co, val, fade);
-
- sculpt_clip(sd, ss, vd.co, val);
- }
-
- if (vd.mvert) {
- vd.mvert->flag |= ME_VERT_PBVH_UPDATE;
- }
- }
- }
- BKE_pbvh_vertex_iter_end;
-}
-
-static void do_smooth_brush_bmesh_task_cb_ex(void *__restrict userdata,
- const int n,
- const TaskParallelTLS *__restrict tls)
-{
- SculptThreadedTaskData *data = userdata;
- SculptSession *ss = data->ob->sculpt;
- Sculpt *sd = data->sd;
- const Brush *brush = data->brush;
- const bool smooth_mask = data->smooth_mask;
- float bstrength = data->strength;
-
- PBVHVertexIter vd;
-
- CLAMP(bstrength, 0.0f, 1.0f);
-
- SculptBrushTest test;
- SculptBrushTestFn sculpt_brush_test_sq_fn = SCULPT_brush_test_init_with_falloff_shape(
- ss, &test, data->brush->falloff_shape);
-
- BKE_pbvh_vertex_iter_begin(ss->pbvh, data->nodes[n], vd, PBVH_ITER_UNIQUE)
- {
- if (sculpt_brush_test_sq_fn(&test, vd.co)) {
- const float fade = bstrength * SCULPT_brush_strength_factor(ss,
- brush,
- vd.co,
- sqrtf(test.dist),
- vd.no,
- vd.fno,
- smooth_mask ? 0.0f : *vd.mask,
- vd.index,
- tls->thread_id);
- if (smooth_mask) {
- float val = bmesh_neighbor_average_mask(vd.bm_vert, vd.cd_vert_mask_offset) - *vd.mask;
- val *= fade * bstrength;
- *vd.mask += val;
- CLAMP(*vd.mask, 0.0f, 1.0f);
- }
- else {
- float avg[3], val[3];
-
- bmesh_neighbor_average(avg, vd.bm_vert);
- sub_v3_v3v3(val, avg, vd.co);
-
- madd_v3_v3v3fl(val, vd.co, val, fade);
-
- sculpt_clip(sd, ss, vd.co, val);
- }
-
- if (vd.mvert) {
- vd.mvert->flag |= ME_VERT_PBVH_UPDATE;
- }
- }
- }
- BKE_pbvh_vertex_iter_end;
-}
-
static void do_topology_rake_bmesh_task_cb_ex(void *__restrict userdata,
const int n,
const TaskParallelTLS *__restrict tls)
@@ -3081,32 +2636,27 @@ static void do_topology_rake_bmesh_task_cb_ex(void *__restrict userdata,
SculptBrushTest test;
SculptBrushTestFn sculpt_brush_test_sq_fn = SCULPT_brush_test_init_with_falloff_shape(
ss, &test, data->brush->falloff_shape);
+ const int thread_id = BLI_task_parallel_thread_id(tls);
PBVHVertexIter vd;
BKE_pbvh_vertex_iter_begin(ss->pbvh, data->nodes[n], vd, PBVH_ITER_UNIQUE)
{
if (sculpt_brush_test_sq_fn(&test, vd.co)) {
- const float fade = bstrength *
- SCULPT_brush_strength_factor(ss,
- brush,
- vd.co,
- sqrtf(test.dist),
- vd.no,
- vd.fno,
- *vd.mask,
- vd.index,
- tls->thread_id) *
- ss->cache->pressure;
+ const float fade =
+ bstrength *
+ SCULPT_brush_strength_factor(
+ ss, brush, vd.co, sqrtf(test.dist), vd.no, vd.fno, *vd.mask, vd.index, thread_id) *
+ ss->cache->pressure;
float avg[3], val[3];
- bmesh_four_neighbor_average(avg, direction, vd.bm_vert);
+ SCULPT_bmesh_four_neighbor_average(avg, direction, vd.bm_vert);
sub_v3_v3v3(val, avg, vd.co);
madd_v3_v3v3fl(val, vd.co, val, fade);
- sculpt_clip(sd, ss, vd.co, val);
+ SCULPT_clip(sd, ss, vd.co, val);
if (vd.mvert) {
vd.mvert->flag |= ME_VERT_PBVH_UPDATE;
@@ -3116,111 +2666,6 @@ static void do_topology_rake_bmesh_task_cb_ex(void *__restrict userdata,
BKE_pbvh_vertex_iter_end;
}
-static void do_smooth_brush_multires_task_cb_ex(void *__restrict userdata,
- const int n,
- const TaskParallelTLS *__restrict tls)
-{
- SculptThreadedTaskData *data = userdata;
- SculptSession *ss = data->ob->sculpt;
- Sculpt *sd = data->sd;
- const Brush *brush = data->brush;
- const bool smooth_mask = data->smooth_mask;
- float bstrength = data->strength;
-
- PBVHVertexIter vd;
-
- CLAMP(bstrength, 0.0f, 1.0f);
-
- SculptBrushTest test;
- SculptBrushTestFn sculpt_brush_test_sq_fn = SCULPT_brush_test_init_with_falloff_shape(
- ss, &test, data->brush->falloff_shape);
-
- BKE_pbvh_vertex_iter_begin(ss->pbvh, data->nodes[n], vd, PBVH_ITER_UNIQUE)
- {
- if (sculpt_brush_test_sq_fn(&test, vd.co)) {
- const float fade = bstrength * SCULPT_brush_strength_factor(
- ss,
- brush,
- vd.co,
- sqrtf(test.dist),
- vd.no,
- vd.fno,
- smooth_mask ? 0.0f : (vd.mask ? *vd.mask : 0.0f),
- vd.index,
- tls->thread_id);
- if (smooth_mask) {
- float val = grids_neighbor_average_mask(ss, vd.index) - *vd.mask;
- val *= fade * bstrength;
- *vd.mask += val;
- CLAMP(*vd.mask, 0.0f, 1.0f);
- }
- else {
- float avg[3], val[3];
- SCULPT_neighbor_coords_average(ss, avg, vd.index);
- sub_v3_v3v3(val, avg, vd.co);
- madd_v3_v3v3fl(val, vd.co, val, fade);
- sculpt_clip(sd, ss, vd.co, val);
- }
- }
- }
- BKE_pbvh_vertex_iter_end;
-}
-
-static void smooth(Sculpt *sd,
- Object *ob,
- PBVHNode **nodes,
- const int totnode,
- float bstrength,
- const bool smooth_mask)
-{
- SculptSession *ss = ob->sculpt;
- Brush *brush = BKE_paint_brush(&sd->paint);
-
- const int max_iterations = 4;
- const float fract = 1.0f / max_iterations;
- PBVHType type = BKE_pbvh_type(ss->pbvh);
- int iteration, count;
- float last;
-
- CLAMP(bstrength, 0.0f, 1.0f);
-
- count = (int)(bstrength * max_iterations);
- last = max_iterations * (bstrength - count * fract);
-
- if (type == PBVH_FACES && !ss->pmap) {
- BLI_assert(!"sculpt smooth: pmap missing");
- return;
- }
-
- for (iteration = 0; iteration <= count; iteration++) {
- const float strength = (iteration != count) ? 1.0f : last;
-
- SculptThreadedTaskData data = {
- .sd = sd,
- .ob = ob,
- .brush = brush,
- .nodes = nodes,
- .smooth_mask = smooth_mask,
- .strength = strength,
- };
-
- PBVHParallelSettings settings;
- BKE_pbvh_parallel_range_settings(&settings, (sd->flags & SCULPT_USE_OPENMP), totnode);
-
- switch (type) {
- case PBVH_GRIDS:
- BKE_pbvh_parallel_range(0, totnode, &data, do_smooth_brush_multires_task_cb_ex, &settings);
- break;
- case PBVH_FACES:
- BKE_pbvh_parallel_range(0, totnode, &data, do_smooth_brush_mesh_task_cb_ex, &settings);
- break;
- case PBVH_BMESH:
- BKE_pbvh_parallel_range(0, totnode, &data, do_smooth_brush_bmesh_task_cb_ex, &settings);
- break;
- }
- }
-}
-
static void bmesh_topology_rake(
Sculpt *sd, Object *ob, PBVHNode **nodes, const int totnode, float bstrength)
{
@@ -3243,163 +2688,10 @@ static void bmesh_topology_rake(
.nodes = nodes,
.strength = factor,
};
- PBVHParallelSettings settings;
+ TaskParallelSettings settings;
BKE_pbvh_parallel_range_settings(&settings, (sd->flags & SCULPT_USE_OPENMP), totnode);
- BKE_pbvh_parallel_range(0, totnode, &data, do_topology_rake_bmesh_task_cb_ex, &settings);
- }
-}
-
-static void do_smooth_brush(Sculpt *sd, Object *ob, PBVHNode **nodes, int totnode)
-{
- SculptSession *ss = ob->sculpt;
- smooth(sd, ob, nodes, totnode, ss->cache->bstrength, false);
-}
-/* HC Smooth Algorithm. */
-/* From: Improved Laplacian Smoothing of Noisy Surface Meshes */
-
-static void surface_smooth_laplacian_step(SculptSession *ss,
- float *disp,
- const float co[3],
- float (*laplacian_disp)[3],
- const int v_index,
- const float origco[3],
- const float alpha)
-{
- float laplacian_smooth_co[3];
- float weigthed_o[3], weigthed_q[3], d[3];
- SCULPT_neighbor_coords_average(ss, laplacian_smooth_co, v_index);
-
- mul_v3_v3fl(weigthed_o, origco, alpha);
- mul_v3_v3fl(weigthed_q, co, 1.0f - alpha);
- add_v3_v3v3(d, weigthed_o, weigthed_q);
- sub_v3_v3v3(laplacian_disp[v_index], laplacian_smooth_co, d);
-
- sub_v3_v3v3(disp, laplacian_smooth_co, co);
-}
-
-static void surface_smooth_displace_step(SculptSession *ss,
- float *co,
- float (*laplacian_disp)[3],
- const int v_index,
- const float beta,
- const float fade)
-{
- float b_avg[3] = {0.0f, 0.0f, 0.0f};
- float b_current_vertex[3];
- int total = 0;
- SculptVertexNeighborIter ni;
- sculpt_vertex_neighbors_iter_begin(ss, v_index, ni)
- {
- add_v3_v3(b_avg, laplacian_disp[ni.index]);
- total++;
- }
- sculpt_vertex_neighbors_iter_end(ni);
- if (total > 0) {
- mul_v3_v3fl(b_current_vertex, b_avg, (1.0f - beta) / (float)total);
- madd_v3_v3fl(b_current_vertex, laplacian_disp[v_index], beta);
- mul_v3_fl(b_current_vertex, clamp_f(fade, 0.0f, 1.0f));
- sub_v3_v3(co, b_current_vertex);
- }
-}
-
-static void do_surface_smooth_brush_laplacian_task_cb_ex(void *__restrict userdata,
- const int n,
- const TaskParallelTLS *__restrict tls)
-{
- SculptThreadedTaskData *data = userdata;
- SculptSession *ss = data->ob->sculpt;
- const Brush *brush = data->brush;
- const float bstrength = ss->cache->bstrength;
- float alpha = brush->surface_smooth_shape_preservation;
-
- PBVHVertexIter vd;
- SculptOrigVertData orig_data;
-
- SculptBrushTest test;
- SculptBrushTestFn sculpt_brush_test_sq_fn = SCULPT_brush_test_init_with_falloff_shape(
- ss, &test, data->brush->falloff_shape);
-
- SCULPT_orig_vert_data_init(&orig_data, data->ob, data->nodes[n]);
-
- BKE_pbvh_vertex_iter_begin(ss->pbvh, data->nodes[n], vd, PBVH_ITER_UNIQUE)
- {
- SCULPT_orig_vert_data_update(&orig_data, &vd);
- if (sculpt_brush_test_sq_fn(&test, vd.co)) {
- const float fade =
- bstrength *
- SCULPT_brush_strength_factor(
- ss, brush, vd.co, sqrtf(test.dist), vd.no, vd.fno, 0.0f, vd.index, tls->thread_id);
-
- float disp[3];
- surface_smooth_laplacian_step(ss,
- disp,
- vd.co,
- ss->cache->surface_smooth_laplacian_disp,
- vd.index,
- orig_data.co,
- alpha);
- madd_v3_v3fl(vd.co, disp, clamp_f(fade, 0.0f, 1.0f));
- }
- BKE_pbvh_vertex_iter_end;
- }
-}
-
-static void do_surface_smooth_brush_displace_task_cb_ex(void *__restrict userdata,
- const int n,
- const TaskParallelTLS *__restrict tls)
-{
- SculptThreadedTaskData *data = userdata;
- SculptSession *ss = data->ob->sculpt;
- const Brush *brush = data->brush;
- const float bstrength = ss->cache->bstrength;
- const float beta = brush->surface_smooth_current_vertex;
-
- PBVHVertexIter vd;
-
- SculptBrushTest test;
- SculptBrushTestFn sculpt_brush_test_sq_fn = SCULPT_brush_test_init_with_falloff_shape(
- ss, &test, data->brush->falloff_shape);
-
- BKE_pbvh_vertex_iter_begin(ss->pbvh, data->nodes[n], vd, PBVH_ITER_UNIQUE)
- {
- if (sculpt_brush_test_sq_fn(&test, vd.co)) {
- const float fade =
- bstrength *
- SCULPT_brush_strength_factor(
- ss, brush, vd.co, sqrtf(test.dist), vd.no, vd.fno, 0.0f, vd.index, tls->thread_id);
- surface_smooth_displace_step(
- ss, vd.co, ss->cache->surface_smooth_laplacian_disp, vd.index, beta, fade);
- }
- }
- BKE_pbvh_vertex_iter_end;
-}
-
-static void do_surface_smooth_brush(Sculpt *sd, Object *ob, PBVHNode **nodes, int totnode)
-{
- Brush *brush = BKE_paint_brush(&sd->paint);
- SculptSession *ss = ob->sculpt;
-
- if (ss->cache->mirror_symmetry_pass == 0 && ss->cache->radial_symmetry_pass == 0) {
- ss->cache->surface_smooth_laplacian_disp = MEM_callocN(
- SCULPT_vertex_count_get(ss) * 3 * sizeof(float), "HC smooth laplacian b");
- }
-
- /* Threaded loop over nodes. */
- SculptThreadedTaskData data = {
- .sd = sd,
- .ob = ob,
- .brush = brush,
- .nodes = nodes,
- };
-
- PBVHParallelSettings settings;
- BKE_pbvh_parallel_range_settings(&settings, (sd->flags & SCULPT_USE_OPENMP), totnode);
- for (int i = 0; i < brush->surface_smooth_iterations; i++) {
- BKE_pbvh_parallel_range(
- 0, totnode, &data, do_surface_smooth_brush_laplacian_task_cb_ex, &settings);
- BKE_pbvh_parallel_range(
- 0, totnode, &data, do_surface_smooth_brush_displace_task_cb_ex, &settings);
+ BLI_task_parallel_range(0, totnode, &data, do_topology_rake_bmesh_task_cb_ex, &settings);
}
}
@@ -3417,12 +2709,13 @@ static void do_mask_brush_draw_task_cb_ex(void *__restrict userdata,
SculptBrushTest test;
SculptBrushTestFn sculpt_brush_test_sq_fn = SCULPT_brush_test_init_with_falloff_shape(
ss, &test, data->brush->falloff_shape);
+ const int thread_id = BLI_task_parallel_thread_id(tls);
BKE_pbvh_vertex_iter_begin(ss->pbvh, data->nodes[n], vd, PBVH_ITER_UNIQUE)
{
if (sculpt_brush_test_sq_fn(&test, vd.co)) {
const float fade = SCULPT_brush_strength_factor(
- ss, brush, vd.co, sqrtf(test.dist), vd.no, vd.fno, 0.0f, vd.index, tls->thread_id);
+ ss, brush, vd.co, sqrtf(test.dist), vd.no, vd.fno, 0.0f, vd.index, thread_id);
if (bstrength > 0.0f) {
(*vd.mask) += fade * bstrength * (1.0f - *vd.mask);
@@ -3452,9 +2745,9 @@ static void do_mask_brush_draw(Sculpt *sd, Object *ob, PBVHNode **nodes, int tot
.nodes = nodes,
};
- PBVHParallelSettings settings;
+ TaskParallelSettings settings;
BKE_pbvh_parallel_range_settings(&settings, (sd->flags & SCULPT_USE_OPENMP), totnode);
- BKE_pbvh_parallel_range(0, totnode, &data, do_mask_brush_draw_task_cb_ex, &settings);
+ BLI_task_parallel_range(0, totnode, &data, do_mask_brush_draw_task_cb_ex, &settings);
}
static void do_mask_brush(Sculpt *sd, Object *ob, PBVHNode **nodes, int totnode)
@@ -3467,7 +2760,7 @@ static void do_mask_brush(Sculpt *sd, Object *ob, PBVHNode **nodes, int totnode)
do_mask_brush_draw(sd, ob, nodes, totnode);
break;
case BRUSH_MASK_SMOOTH:
- smooth(sd, ob, nodes, totnode, ss->cache->bstrength, true);
+ SCULPT_smooth(sd, ob, nodes, totnode, ss->cache->bstrength, true);
break;
}
}
@@ -3489,6 +2782,7 @@ static void do_draw_brush_task_cb_ex(void *__restrict userdata,
SculptBrushTest test;
SculptBrushTestFn sculpt_brush_test_sq_fn = SCULPT_brush_test_init_with_falloff_shape(
ss, &test, data->brush->falloff_shape);
+ const int thread_id = BLI_task_parallel_thread_id(tls);
BKE_pbvh_vertex_iter_begin(ss->pbvh, data->nodes[n], vd, PBVH_ITER_UNIQUE)
{
@@ -3502,7 +2796,7 @@ static void do_draw_brush_task_cb_ex(void *__restrict userdata,
vd.fno,
vd.mask ? *vd.mask : 0.0f,
vd.index,
- tls->thread_id);
+ thread_id);
mul_v3_v3fl(proxy[vd.i], offset, fade);
@@ -3539,129 +2833,9 @@ static void do_draw_brush(Sculpt *sd, Object *ob, PBVHNode **nodes, int totnode)
.offset = offset,
};
- PBVHParallelSettings settings;
- BKE_pbvh_parallel_range_settings(&settings, (sd->flags & SCULPT_USE_OPENMP), totnode);
- BKE_pbvh_parallel_range(0, totnode, &data, do_draw_brush_task_cb_ex, &settings);
-}
-
-static void do_draw_face_sets_brush_task_cb_ex(void *__restrict userdata,
- const int n,
- const TaskParallelTLS *__restrict tls)
-{
- SculptThreadedTaskData *data = userdata;
- SculptSession *ss = data->ob->sculpt;
- const Brush *brush = data->brush;
- const float bstrength = ss->cache->bstrength;
-
- PBVHVertexIter vd;
-
- SculptBrushTest test;
- SculptBrushTestFn sculpt_brush_test_sq_fn = SCULPT_brush_test_init_with_falloff_shape(
- ss, &test, data->brush->falloff_shape);
-
- BKE_pbvh_vertex_iter_begin(ss->pbvh, data->nodes[n], vd, PBVH_ITER_UNIQUE)
- {
- if (sculpt_brush_test_sq_fn(&test, vd.co)) {
- const float fade = bstrength * SCULPT_brush_strength_factor(ss,
- brush,
- vd.co,
- sqrtf(test.dist),
- vd.no,
- vd.fno,
- vd.mask ? *vd.mask : 0.0f,
- vd.index,
- tls->thread_id);
-
- if (fade > 0.05f) {
- SCULPT_vertex_face_set_set(ss, vd.index, ss->cache->paint_face_set);
- }
- }
- }
- BKE_pbvh_vertex_iter_end;
-}
-
-static void do_relax_face_sets_brush_task_cb_ex(void *__restrict userdata,
- const int n,
- const TaskParallelTLS *__restrict tls)
-{
- SculptThreadedTaskData *data = userdata;
- SculptSession *ss = data->ob->sculpt;
- const Brush *brush = data->brush;
- float bstrength = ss->cache->bstrength;
-
- PBVHVertexIter vd;
-
- SculptBrushTest test;
- SculptBrushTestFn sculpt_brush_test_sq_fn = SCULPT_brush_test_init_with_falloff_shape(
- ss, &test, data->brush->falloff_shape);
-
- const bool relax_face_sets = !(ss->cache->iteration_count % 3 == 0);
- /* This operations needs a stregth tweak as the relax deformation is too weak by default. */
- if (relax_face_sets) {
- bstrength *= 2.0f;
- }
-
- BKE_pbvh_vertex_iter_begin(ss->pbvh, data->nodes[n], vd, PBVH_ITER_UNIQUE)
- {
- if (sculpt_brush_test_sq_fn(&test, vd.co)) {
- if (relax_face_sets != sculpt_vertex_has_unique_face_set(ss, vd.index)) {
- const float fade = bstrength * SCULPT_brush_strength_factor(ss,
- brush,
- vd.co,
- sqrtf(test.dist),
- vd.no,
- vd.fno,
- vd.mask ? *vd.mask : 0.0f,
- vd.index,
- tls->thread_id);
-
- SCULPT_relax_vertex(ss, &vd, fade * bstrength, relax_face_sets, vd.co);
- if (vd.mvert) {
- vd.mvert->flag |= ME_VERT_PBVH_UPDATE;
- }
- }
- }
- }
- BKE_pbvh_vertex_iter_end;
-}
-
-static void do_draw_face_sets_brush(Sculpt *sd, Object *ob, PBVHNode **nodes, int totnode)
-{
- SculptSession *ss = ob->sculpt;
- Brush *brush = BKE_paint_brush(&sd->paint);
-
- if (ss->cache->first_time && ss->cache->mirror_symmetry_pass == 0 &&
- ss->cache->radial_symmetry_pass == 0) {
- if (ss->cache->invert) {
- /* When inverting the brush, pick the paint face mask ID from the mesh. */
- ss->cache->paint_face_set = SCULPT_vertex_face_set_get(ss, SCULPT_active_vertex_get(ss));
- }
- else {
- /* By default create a new Face Sets. */
- ss->cache->paint_face_set = SCULPT_face_set_next_available_get(ss);
- }
- }
-
- BKE_curvemapping_initialize(brush->curve);
-
- /* Threaded loop over nodes. */
- SculptThreadedTaskData data = {
- .sd = sd,
- .ob = ob,
- .brush = brush,
- .nodes = nodes,
- };
-
- PBVHParallelSettings settings;
+ TaskParallelSettings settings;
BKE_pbvh_parallel_range_settings(&settings, (sd->flags & SCULPT_USE_OPENMP), totnode);
- if (ss->cache->alt_smooth) {
- for (int i = 0; i < 4; i++) {
- BKE_pbvh_parallel_range(0, totnode, &data, do_relax_face_sets_brush_task_cb_ex, &settings);
- }
- }
- else {
- BKE_pbvh_parallel_range(0, totnode, &data, do_draw_face_sets_brush_task_cb_ex, &settings);
- }
+ BLI_task_parallel_range(0, totnode, &data, do_draw_brush_task_cb_ex, &settings);
}
static void do_draw_sharp_brush_task_cb_ex(void *__restrict userdata,
@@ -3684,6 +2858,7 @@ static void do_draw_sharp_brush_task_cb_ex(void *__restrict userdata,
SculptBrushTest test;
SculptBrushTestFn sculpt_brush_test_sq_fn = SCULPT_brush_test_init_with_falloff_shape(
ss, &test, data->brush->falloff_shape);
+ const int thread_id = BLI_task_parallel_thread_id(tls);
BKE_pbvh_vertex_iter_begin(ss->pbvh, data->nodes[n], vd, PBVH_ITER_UNIQUE)
{
@@ -3698,7 +2873,7 @@ static void do_draw_sharp_brush_task_cb_ex(void *__restrict userdata,
NULL,
vd.mask ? *vd.mask : 0.0f,
vd.index,
- tls->thread_id);
+ thread_id);
mul_v3_v3fl(proxy[vd.i], offset, fade);
@@ -3735,9 +2910,9 @@ static void do_draw_sharp_brush(Sculpt *sd, Object *ob, PBVHNode **nodes, int to
.offset = offset,
};
- PBVHParallelSettings settings;
+ TaskParallelSettings settings;
BKE_pbvh_parallel_range_settings(&settings, (sd->flags & SCULPT_USE_OPENMP), totnode);
- BKE_pbvh_parallel_range(0, totnode, &data, do_draw_sharp_brush_task_cb_ex, &settings);
+ BLI_task_parallel_range(0, totnode, &data, do_draw_sharp_brush_task_cb_ex, &settings);
}
/* -------------------------------------------------------------------- */
@@ -3764,6 +2939,7 @@ static void do_topology_slide_task_cb_ex(void *__restrict userdata,
SculptBrushTest test;
SculptBrushTestFn sculpt_brush_test_sq_fn = SCULPT_brush_test_init_with_falloff_shape(
ss, &test, data->brush->falloff_shape);
+ const int thread_id = BLI_task_parallel_thread_id(tls);
BKE_pbvh_vertex_iter_begin(ss->pbvh, data->nodes[n], vd, PBVH_ITER_UNIQUE)
{
@@ -3777,7 +2953,7 @@ static void do_topology_slide_task_cb_ex(void *__restrict userdata,
NULL,
vd.mask ? *vd.mask : 0.0f,
vd.index,
- tls->thread_id);
+ thread_id);
float current_disp[3];
float current_disp_norm[3];
float final_disp[3];
@@ -3786,8 +2962,7 @@ static void do_topology_slide_task_cb_ex(void *__restrict userdata,
normalize_v3_v3(current_disp_norm, current_disp);
mul_v3_v3fl(current_disp, current_disp_norm, ss->cache->bstrength);
SculptVertexNeighborIter ni;
- sculpt_vertex_neighbors_iter_begin(ss, vd.index, ni)
- {
+ SCULPT_VERTEX_NEIGHBORS_ITER_BEGIN (ss, vd.index, ni) {
float vertex_disp[3];
float vertex_disp_norm[3];
sub_v3_v3v3(vertex_disp, SCULPT_vertex_co_get(ss, ni.index), vd.co);
@@ -3796,7 +2971,7 @@ static void do_topology_slide_task_cb_ex(void *__restrict userdata,
madd_v3_v3fl(final_disp, vertex_disp_norm, dot_v3v3(current_disp, vertex_disp));
}
}
- sculpt_vertex_neighbors_iter_end(ni);
+ SCULPT_VERTEX_NEIGHBORS_ITER_END(ni);
mul_v3_v3fl(proxy[vd.i], final_disp, fade);
@@ -3820,15 +2995,14 @@ void SCULPT_relax_vertex(SculptSession *ss,
zero_v3(smooth_pos);
SculptVertexNeighborIter ni;
- sculpt_vertex_neighbors_iter_begin(ss, vd->index, ni)
- {
+ SCULPT_VERTEX_NEIGHBORS_ITER_BEGIN (ss, vd->index, ni) {
if (!filter_boundary_face_sets ||
- (filter_boundary_face_sets && !sculpt_vertex_has_unique_face_set(ss, ni.index))) {
+ (filter_boundary_face_sets && !SCULPT_vertex_has_unique_face_set(ss, ni.index))) {
add_v3_v3(smooth_pos, SCULPT_vertex_co_get(ss, ni.index));
count++;
}
}
- sculpt_vertex_neighbors_iter_end(ni);
+ SCULPT_VERTEX_NEIGHBORS_ITER_END(ni);
if (count > 0) {
mul_v3_fl(smooth_pos, 1.0f / (float)count);
@@ -3880,6 +3054,7 @@ static void do_topology_relax_task_cb_ex(void *__restrict userdata,
SculptBrushTest test;
SculptBrushTestFn sculpt_brush_test_sq_fn = SCULPT_brush_test_init_with_falloff_shape(
ss, &test, data->brush->falloff_shape);
+ const int thread_id = BLI_task_parallel_thread_id(tls);
BKE_pbvh_vertex_iter_begin(ss->pbvh, data->nodes[n], vd, PBVH_ITER_UNIQUE)
{
@@ -3893,7 +3068,7 @@ static void do_topology_relax_task_cb_ex(void *__restrict userdata,
NULL,
vd.mask ? *vd.mask : 0.0f,
vd.index,
- tls->thread_id);
+ thread_id);
SCULPT_relax_vertex(ss, &vd, fade * bstrength, false, vd.co);
if (vd.mvert) {
@@ -3922,15 +3097,15 @@ static void do_slide_relax_brush(Sculpt *sd, Object *ob, PBVHNode **nodes, int t
.nodes = nodes,
};
- PBVHParallelSettings settings;
+ TaskParallelSettings settings;
BKE_pbvh_parallel_range_settings(&settings, (sd->flags & SCULPT_USE_OPENMP), totnode);
if (ss->cache->alt_smooth) {
for (int i = 0; i < 4; i++) {
- BKE_pbvh_parallel_range(0, totnode, &data, do_topology_relax_task_cb_ex, &settings);
+ BLI_task_parallel_range(0, totnode, &data, do_topology_relax_task_cb_ex, &settings);
}
}
else {
- BKE_pbvh_parallel_range(0, totnode, &data, do_topology_slide_task_cb_ex, &settings);
+ BLI_task_parallel_range(0, totnode, &data, do_topology_slide_task_cb_ex, &settings);
}
}
@@ -4043,6 +3218,7 @@ static void do_crease_brush_task_cb_ex(void *__restrict userdata,
SculptBrushTest test;
SculptBrushTestFn sculpt_brush_test_sq_fn = SCULPT_brush_test_init_with_falloff_shape(
ss, &test, data->brush->falloff_shape);
+ const int thread_id = BLI_task_parallel_thread_id(tls);
BKE_pbvh_vertex_iter_begin(ss->pbvh, data->nodes[n], vd, PBVH_ITER_UNIQUE)
{
@@ -4056,7 +3232,7 @@ static void do_crease_brush_task_cb_ex(void *__restrict userdata,
vd.fno,
vd.mask ? *vd.mask : 0.0f,
vd.index,
- tls->thread_id);
+ thread_id);
float val1[3];
float val2[3];
@@ -4131,9 +3307,9 @@ static void do_crease_brush(Sculpt *sd, Object *ob, PBVHNode **nodes, int totnod
.flippedbstrength = flippedbstrength,
};
- PBVHParallelSettings settings;
+ TaskParallelSettings settings;
BKE_pbvh_parallel_range_settings(&settings, (sd->flags & SCULPT_USE_OPENMP), totnode);
- BKE_pbvh_parallel_range(0, totnode, &data, do_crease_brush_task_cb_ex, &settings);
+ BLI_task_parallel_range(0, totnode, &data, do_crease_brush_task_cb_ex, &settings);
}
static void do_pinch_brush_task_cb_ex(void *__restrict userdata,
@@ -4154,6 +3330,7 @@ static void do_pinch_brush_task_cb_ex(void *__restrict userdata,
SculptBrushTest test;
SculptBrushTestFn sculpt_brush_test_sq_fn = SCULPT_brush_test_init_with_falloff_shape(
ss, &test, data->brush->falloff_shape);
+ const int thread_id = BLI_task_parallel_thread_id(tls);
float x_object_space[3];
float z_object_space[3];
@@ -4171,7 +3348,7 @@ static void do_pinch_brush_task_cb_ex(void *__restrict userdata,
vd.fno,
vd.mask ? *vd.mask : 0.0f,
vd.index,
- tls->thread_id);
+ thread_id);
float disp_center[3];
float x_disp[3];
float z_disp[3];
@@ -4244,9 +3421,9 @@ static void do_pinch_brush(Sculpt *sd, Object *ob, PBVHNode **nodes, int totnode
.stroke_xz = stroke_xz,
};
- PBVHParallelSettings settings;
+ TaskParallelSettings settings;
BKE_pbvh_parallel_range_settings(&settings, (sd->flags & SCULPT_USE_OPENMP), totnode);
- BKE_pbvh_parallel_range(0, totnode, &data, do_pinch_brush_task_cb_ex, &settings);
+ BLI_task_parallel_range(0, totnode, &data, do_pinch_brush_task_cb_ex, &settings);
}
static void do_grab_brush_task_cb_ex(void *__restrict userdata,
@@ -4270,6 +3447,7 @@ static void do_grab_brush_task_cb_ex(void *__restrict userdata,
SculptBrushTest test;
SculptBrushTestFn sculpt_brush_test_sq_fn = SCULPT_brush_test_init_with_falloff_shape(
ss, &test, data->brush->falloff_shape);
+ const int thread_id = BLI_task_parallel_thread_id(tls);
BKE_pbvh_vertex_iter_begin(ss->pbvh, data->nodes[n], vd, PBVH_ITER_UNIQUE)
{
@@ -4284,7 +3462,7 @@ static void do_grab_brush_task_cb_ex(void *__restrict userdata,
NULL,
vd.mask ? *vd.mask : 0.0f,
vd.index,
- tls->thread_id);
+ thread_id);
mul_v3_v3fl(proxy[vd.i], grab_delta, fade);
@@ -4316,9 +3494,9 @@ static void do_grab_brush(Sculpt *sd, Object *ob, PBVHNode **nodes, int totnode)
.grab_delta = grab_delta,
};
- PBVHParallelSettings settings;
+ TaskParallelSettings settings;
BKE_pbvh_parallel_range_settings(&settings, (sd->flags & SCULPT_USE_OPENMP), totnode);
- BKE_pbvh_parallel_range(0, totnode, &data, do_grab_brush_task_cb_ex, &settings);
+ BLI_task_parallel_range(0, totnode, &data, do_grab_brush_task_cb_ex, &settings);
}
static void do_elastic_deform_brush_task_cb_ex(void *__restrict userdata,
@@ -4425,9 +3603,9 @@ static void do_elastic_deform_brush(Sculpt *sd, Object *ob, PBVHNode **nodes, in
.grab_delta = grab_delta,
};
- PBVHParallelSettings settings;
+ TaskParallelSettings settings;
BKE_pbvh_parallel_range_settings(&settings, (sd->flags & SCULPT_USE_OPENMP), totnode);
- BKE_pbvh_parallel_range(0, totnode, &data, do_elastic_deform_brush_task_cb_ex, &settings);
+ BLI_task_parallel_range(0, totnode, &data, do_elastic_deform_brush_task_cb_ex, &settings);
}
ePaintSymmetryAreas SCULPT_get_vertex_symm_area(const float co[3])
@@ -4587,6 +3765,7 @@ static void do_nudge_brush_task_cb_ex(void *__restrict userdata,
SculptBrushTest test;
SculptBrushTestFn sculpt_brush_test_sq_fn = SCULPT_brush_test_init_with_falloff_shape(
ss, &test, data->brush->falloff_shape);
+ const int thread_id = BLI_task_parallel_thread_id(tls);
BKE_pbvh_vertex_iter_begin(ss->pbvh, data->nodes[n], vd, PBVH_ITER_UNIQUE)
{
@@ -4599,7 +3778,7 @@ static void do_nudge_brush_task_cb_ex(void *__restrict userdata,
vd.fno,
vd.mask ? *vd.mask : 0.0f,
vd.index,
- tls->thread_id);
+ thread_id);
mul_v3_v3fl(proxy[vd.i], cono, fade);
@@ -4631,9 +3810,9 @@ static void do_nudge_brush(Sculpt *sd, Object *ob, PBVHNode **nodes, int totnode
.cono = cono,
};
- PBVHParallelSettings settings;
+ TaskParallelSettings settings;
BKE_pbvh_parallel_range_settings(&settings, (sd->flags & SCULPT_USE_OPENMP), totnode);
- BKE_pbvh_parallel_range(0, totnode, &data, do_nudge_brush_task_cb_ex, &settings);
+ BLI_task_parallel_range(0, totnode, &data, do_nudge_brush_task_cb_ex, &settings);
}
static void do_snake_hook_brush_task_cb_ex(void *__restrict userdata,
@@ -4660,6 +3839,7 @@ static void do_snake_hook_brush_task_cb_ex(void *__restrict userdata,
SculptBrushTest test;
SculptBrushTestFn sculpt_brush_test_sq_fn = SCULPT_brush_test_init_with_falloff_shape(
ss, &test, data->brush->falloff_shape);
+ const int thread_id = BLI_task_parallel_thread_id(tls);
BKE_pbvh_vertex_iter_begin(ss->pbvh, data->nodes[n], vd, PBVH_ITER_UNIQUE)
{
@@ -4672,7 +3852,7 @@ static void do_snake_hook_brush_task_cb_ex(void *__restrict userdata,
vd.fno,
vd.mask ? *vd.mask : 0.0f,
vd.index,
- tls->thread_id);
+ thread_id);
mul_v3_v3fl(proxy[vd.i], grab_delta, fade);
@@ -4752,9 +3932,9 @@ static void do_snake_hook_brush(Sculpt *sd, Object *ob, PBVHNode **nodes, int to
.grab_delta = grab_delta,
};
- PBVHParallelSettings settings;
+ TaskParallelSettings settings;
BKE_pbvh_parallel_range_settings(&settings, (sd->flags & SCULPT_USE_OPENMP), totnode);
- BKE_pbvh_parallel_range(0, totnode, &data, do_snake_hook_brush_task_cb_ex, &settings);
+ BLI_task_parallel_range(0, totnode, &data, do_snake_hook_brush_task_cb_ex, &settings);
}
static void do_thumb_brush_task_cb_ex(void *__restrict userdata,
@@ -4778,6 +3958,7 @@ static void do_thumb_brush_task_cb_ex(void *__restrict userdata,
SculptBrushTest test;
SculptBrushTestFn sculpt_brush_test_sq_fn = SCULPT_brush_test_init_with_falloff_shape(
ss, &test, data->brush->falloff_shape);
+ const int thread_id = BLI_task_parallel_thread_id(tls);
BKE_pbvh_vertex_iter_begin(ss->pbvh, data->nodes[n], vd, PBVH_ITER_UNIQUE)
{
@@ -4792,7 +3973,7 @@ static void do_thumb_brush_task_cb_ex(void *__restrict userdata,
NULL,
vd.mask ? *vd.mask : 0.0f,
vd.index,
- tls->thread_id);
+ thread_id);
mul_v3_v3fl(proxy[vd.i], cono, fade);
@@ -4824,9 +4005,9 @@ static void do_thumb_brush(Sculpt *sd, Object *ob, PBVHNode **nodes, int totnode
.cono = cono,
};
- PBVHParallelSettings settings;
+ TaskParallelSettings settings;
BKE_pbvh_parallel_range_settings(&settings, (sd->flags & SCULPT_USE_OPENMP), totnode);
- BKE_pbvh_parallel_range(0, totnode, &data, do_thumb_brush_task_cb_ex, &settings);
+ BLI_task_parallel_range(0, totnode, &data, do_thumb_brush_task_cb_ex, &settings);
}
static void do_rotate_brush_task_cb_ex(void *__restrict userdata,
@@ -4850,6 +4031,7 @@ static void do_rotate_brush_task_cb_ex(void *__restrict userdata,
SculptBrushTest test;
SculptBrushTestFn sculpt_brush_test_sq_fn = SCULPT_brush_test_init_with_falloff_shape(
ss, &test, data->brush->falloff_shape);
+ const int thread_id = BLI_task_parallel_thread_id(tls);
BKE_pbvh_vertex_iter_begin(ss->pbvh, data->nodes[n], vd, PBVH_ITER_UNIQUE)
{
@@ -4865,7 +4047,7 @@ static void do_rotate_brush_task_cb_ex(void *__restrict userdata,
NULL,
vd.mask ? *vd.mask : 0.0f,
vd.index,
- tls->thread_id);
+ thread_id);
sub_v3_v3v3(vec, orig_data.co, ss->cache->location);
axis_angle_normalized_to_mat3(rot, ss->cache->sculpt_normal_symm, angle * fade);
@@ -4897,9 +4079,9 @@ static void do_rotate_brush(Sculpt *sd, Object *ob, PBVHNode **nodes, int totnod
.angle = angle,
};
- PBVHParallelSettings settings;
+ TaskParallelSettings settings;
BKE_pbvh_parallel_range_settings(&settings, (sd->flags & SCULPT_USE_OPENMP), totnode);
- BKE_pbvh_parallel_range(0, totnode, &data, do_rotate_brush_task_cb_ex, &settings);
+ BLI_task_parallel_range(0, totnode, &data, do_rotate_brush_task_cb_ex, &settings);
}
static void do_layer_brush_task_cb_ex(void *__restrict userdata,
@@ -4910,64 +4092,83 @@ static void do_layer_brush_task_cb_ex(void *__restrict userdata,
SculptSession *ss = data->ob->sculpt;
Sculpt *sd = data->sd;
const Brush *brush = data->brush;
- const float *offset = data->offset;
+
+ const bool use_persistent_base = ss->layer_base && brush->flag & BRUSH_PERSISTENT;
PBVHVertexIter vd;
SculptOrigVertData orig_data;
- float *layer_disp;
const float bstrength = ss->cache->bstrength;
- const float lim = (bstrength < 0.0f) ? -data->brush->height : data->brush->height;
- /* XXX: layer brush needs conversion to proxy but its more complicated */
- /* proxy = BKE_pbvh_node_add_proxy(ss->pbvh, nodes[n])->co; */
-
SCULPT_orig_vert_data_init(&orig_data, data->ob, data->nodes[n]);
- /* Why does this have to be thread-protected? */
- BLI_mutex_lock(&data->mutex);
- layer_disp = BKE_pbvh_node_layer_disp_get(ss->pbvh, data->nodes[n]);
- BLI_mutex_unlock(&data->mutex);
-
SculptBrushTest test;
SculptBrushTestFn sculpt_brush_test_sq_fn = SCULPT_brush_test_init_with_falloff_shape(
ss, &test, data->brush->falloff_shape);
+ const int thread_id = BLI_task_parallel_thread_id(tls);
BKE_pbvh_vertex_iter_begin(ss->pbvh, data->nodes[n], vd, PBVH_ITER_UNIQUE)
{
SCULPT_orig_vert_data_update(&orig_data, &vd);
if (sculpt_brush_test_sq_fn(&test, orig_data.co)) {
- const float fade = bstrength * SCULPT_brush_strength_factor(ss,
- brush,
- vd.co,
- sqrtf(test.dist),
- vd.no,
- vd.fno,
- vd.mask ? *vd.mask : 0.0f,
- vd.index,
- tls->thread_id);
- float *disp = &layer_disp[vd.i];
- float val[3];
-
- *disp += fade;
+ const float fade = SCULPT_brush_strength_factor(ss,
+ brush,
+ vd.co,
+ sqrtf(test.dist),
+ vd.no,
+ vd.fno,
+ vd.mask ? *vd.mask : 0.0f,
+ vd.index,
+ thread_id);
- /* Don't let the displacement go past the limit. */
- if ((lim < 0.0f && *disp < lim) || (lim >= 0.0f && *disp > lim)) {
- *disp = lim;
+ const int vi = vd.index;
+ float *disp_factor;
+ if (use_persistent_base) {
+ disp_factor = &ss->layer_base[vi].disp;
+ }
+ else {
+ disp_factor = &ss->cache->layer_displacement_factor[vi];
}
- mul_v3_v3fl(val, offset, *disp);
+ /* When using persistent base, the layer brush Ctrl invert mode resets the height of the
+ * layer to 0. This makes possible to clean edges of previously added layers on top of the
+ * base. */
+ /* The main direction of the layers is inverted using the regular brush strength with the
+ * brush direction property. */
+ if (use_persistent_base && ss->cache->invert) {
+ (*disp_factor) += fabsf(fade * bstrength * (*disp_factor)) *
+ ((*disp_factor) > 0.0f ? -1.0f : 1.0f);
+ }
+ else {
+ (*disp_factor) += fade * bstrength * (1.05f - fabsf(*disp_factor));
+ }
+ if (vd.mask) {
+ const float clamp_mask = 1.0f - *vd.mask;
+ CLAMP(*disp_factor, -clamp_mask, clamp_mask);
+ }
+ else {
+ CLAMP(*disp_factor, -1.0f, 1.0f);
+ }
- if (!ss->multires && !ss->bm && ss->layer_co && (brush->flag & BRUSH_PERSISTENT)) {
- int index = vd.vert_indices[vd.i];
+ float final_co[3];
+ float normal[3];
- /* Persistent base. */
- add_v3_v3(val, ss->layer_co[index]);
+ if (use_persistent_base) {
+ copy_v3_v3(normal, ss->layer_base[vi].no);
+ mul_v3_fl(normal, brush->height);
+ madd_v3_v3v3fl(final_co, ss->layer_base[vi].co, normal, *disp_factor);
}
else {
- add_v3_v3(val, orig_data.co);
+ normal_short_to_float_v3(normal, orig_data.no);
+ mul_v3_fl(normal, brush->height);
+ madd_v3_v3v3fl(final_co, orig_data.co, normal, *disp_factor);
}
- sculpt_clip(sd, ss, vd.co, val);
+ float vdisp[3];
+ sub_v3_v3v3(vdisp, final_co, vd.co);
+ mul_v3_fl(vdisp, fabsf(fade));
+ add_v3_v3v3(final_co, vd.co, vdisp);
+
+ SCULPT_clip(sd, ss, vd.co, final_co);
if (vd.mvert) {
vd.mvert->flag |= ME_VERT_PBVH_UPDATE;
@@ -4981,24 +4182,22 @@ static void do_layer_brush(Sculpt *sd, Object *ob, PBVHNode **nodes, int totnode
{
SculptSession *ss = ob->sculpt;
Brush *brush = BKE_paint_brush(&sd->paint);
- float offset[3];
- mul_v3_v3v3(offset, ss->cache->scale, ss->cache->sculpt_normal_symm);
+ if (ss->cache->layer_displacement_factor == NULL) {
+ ss->cache->layer_displacement_factor = MEM_callocN(sizeof(float) * SCULPT_vertex_count_get(ss),
+ "layer displacement factor");
+ }
SculptThreadedTaskData data = {
.sd = sd,
.ob = ob,
.brush = brush,
.nodes = nodes,
- .offset = offset,
};
- BLI_mutex_init(&data.mutex);
- PBVHParallelSettings settings;
+ TaskParallelSettings settings;
BKE_pbvh_parallel_range_settings(&settings, (sd->flags & SCULPT_USE_OPENMP), totnode);
- BKE_pbvh_parallel_range(0, totnode, &data, do_layer_brush_task_cb_ex, &settings);
-
- BLI_mutex_end(&data.mutex);
+ BLI_task_parallel_range(0, totnode, &data, do_layer_brush_task_cb_ex, &settings);
}
static void do_inflate_brush_task_cb_ex(void *__restrict userdata,
@@ -5018,6 +4217,7 @@ static void do_inflate_brush_task_cb_ex(void *__restrict userdata,
SculptBrushTest test;
SculptBrushTestFn sculpt_brush_test_sq_fn = SCULPT_brush_test_init_with_falloff_shape(
ss, &test, data->brush->falloff_shape);
+ const int thread_id = BLI_task_parallel_thread_id(tls);
BKE_pbvh_vertex_iter_begin(ss->pbvh, data->nodes[n], vd, PBVH_ITER_UNIQUE)
{
@@ -5030,7 +4230,7 @@ static void do_inflate_brush_task_cb_ex(void *__restrict userdata,
vd.fno,
vd.mask ? *vd.mask : 0.0f,
vd.index,
- tls->thread_id);
+ thread_id);
float val[3];
if (vd.fno) {
@@ -5062,9 +4262,9 @@ static void do_inflate_brush(Sculpt *sd, Object *ob, PBVHNode **nodes, int totno
.nodes = nodes,
};
- PBVHParallelSettings settings;
+ TaskParallelSettings settings;
BKE_pbvh_parallel_range_settings(&settings, (sd->flags & SCULPT_USE_OPENMP), totnode);
- BKE_pbvh_parallel_range(0, totnode, &data, do_inflate_brush_task_cb_ex, &settings);
+ BLI_task_parallel_range(0, totnode, &data, do_inflate_brush_task_cb_ex, &settings);
}
int SCULPT_plane_trim(const StrokeCache *cache, const Brush *brush, const float val[3])
@@ -5120,6 +4320,7 @@ static void do_flatten_brush_task_cb_ex(void *__restrict userdata,
SculptBrushTest test;
SculptBrushTestFn sculpt_brush_test_sq_fn = SCULPT_brush_test_init_with_falloff_shape(
ss, &test, data->brush->falloff_shape);
+ const int thread_id = BLI_task_parallel_thread_id(tls);
plane_from_point_normal_v3(test.plane_tool, area_co, area_no);
@@ -5142,7 +4343,7 @@ static void do_flatten_brush_task_cb_ex(void *__restrict userdata,
vd.fno,
vd.mask ? *vd.mask : 0.0f,
vd.index,
- tls->thread_id);
+ thread_id);
mul_v3_v3fl(proxy[vd.i], val, fade);
@@ -5186,9 +4387,9 @@ static void do_flatten_brush(Sculpt *sd, Object *ob, PBVHNode **nodes, int totno
.area_co = area_co,
};
- PBVHParallelSettings settings;
+ TaskParallelSettings settings;
BKE_pbvh_parallel_range_settings(&settings, (sd->flags & SCULPT_USE_OPENMP), totnode);
- BKE_pbvh_parallel_range(0, totnode, &data, do_flatten_brush_task_cb_ex, &settings);
+ BLI_task_parallel_range(0, totnode, &data, do_flatten_brush_task_cb_ex, &settings);
}
/* -------------------------------------------------------------------- */
@@ -5274,6 +4475,7 @@ static void do_clay_brush_task_cb_ex(void *__restrict userdata,
SculptBrushTest test;
SculptBrushTestFn sculpt_brush_test_sq_fn = SCULPT_brush_test_init_with_falloff_shape(
ss, &test, data->brush->falloff_shape);
+ const int thread_id = BLI_task_parallel_thread_id(tls);
plane_from_point_normal_v3(test.plane_tool, area_co, area_no);
@@ -5294,7 +4496,7 @@ static void do_clay_brush_task_cb_ex(void *__restrict userdata,
vd.fno,
vd.mask ? *vd.mask : 0.0f,
vd.index,
- tls->thread_id);
+ thread_id);
mul_v3_v3fl(proxy[vd.i], val, fade);
@@ -5336,13 +4538,13 @@ static void do_clay_brush(Sculpt *sd, Object *ob, PBVHNode **nodes, int totnode)
ClaySampleData csd = {{0}};
- PBVHParallelSettings sample_settings;
+ TaskParallelSettings sample_settings;
BKE_pbvh_parallel_range_settings(&sample_settings, (sd->flags & SCULPT_USE_OPENMP), totnode);
sample_settings.func_reduce = calc_clay_surface_reduce;
sample_settings.userdata_chunk = &csd;
sample_settings.userdata_chunk_size = sizeof(ClaySampleData);
- BKE_pbvh_parallel_range(0, totnode, &sample_data, calc_clay_surface_task_cb, &sample_settings);
+ BLI_task_parallel_range(0, totnode, &sample_data, calc_clay_surface_task_cb, &sample_settings);
float d_offset = (csd.plane_dist[0] + csd.plane_dist[1]);
d_offset = min_ff(radius, d_offset);
@@ -5367,9 +4569,9 @@ static void do_clay_brush(Sculpt *sd, Object *ob, PBVHNode **nodes, int totnode)
.area_co = area_co,
};
- PBVHParallelSettings settings;
+ TaskParallelSettings settings;
BKE_pbvh_parallel_range_settings(&settings, (sd->flags & SCULPT_USE_OPENMP), totnode);
- BKE_pbvh_parallel_range(0, totnode, &data, do_clay_brush_task_cb_ex, &settings);
+ BLI_task_parallel_range(0, totnode, &data, do_clay_brush_task_cb_ex, &settings);
}
static void do_clay_strips_brush_task_cb_ex(void *__restrict userdata,
@@ -5393,6 +4595,7 @@ static void do_clay_strips_brush_task_cb_ex(void *__restrict userdata,
SCULPT_brush_test_init(ss, &test);
plane_from_point_normal_v3(test.plane_tool, area_co, area_no_sp);
+ const int thread_id = BLI_task_parallel_thread_id(tls);
BKE_pbvh_vertex_iter_begin(ss->pbvh, data->nodes[n], vd, PBVH_ITER_UNIQUE)
{
@@ -5416,7 +4619,7 @@ static void do_clay_strips_brush_task_cb_ex(void *__restrict userdata,
vd.fno,
vd.mask ? *vd.mask : 0.0f,
vd.index,
- tls->thread_id);
+ thread_id);
mul_v3_v3fl(proxy[vd.i], val, fade);
@@ -5438,7 +4641,7 @@ static void do_clay_strips_brush(Sculpt *sd, Object *ob, PBVHNode **nodes, int t
const bool flip = (ss->cache->bstrength < 0.0f);
const float radius = flip ? -ss->cache->radius : ss->cache->radius;
const float offset = SCULPT_brush_plane_offset_get(sd, ss);
- const float displace = radius * (0.25f + offset);
+ const float displace = radius * (0.18f + offset);
/* The sculpt-plane normal (whatever its set to). */
float area_no_sp[3];
@@ -5500,9 +4703,9 @@ static void do_clay_strips_brush(Sculpt *sd, Object *ob, PBVHNode **nodes, int t
.mat = mat,
};
- PBVHParallelSettings settings;
+ TaskParallelSettings settings;
BKE_pbvh_parallel_range_settings(&settings, (sd->flags & SCULPT_USE_OPENMP), totnode);
- BKE_pbvh_parallel_range(0, totnode, &data, do_clay_strips_brush_task_cb_ex, &settings);
+ BLI_task_parallel_range(0, totnode, &data, do_clay_strips_brush_task_cb_ex, &settings);
}
static void do_fill_brush_task_cb_ex(void *__restrict userdata,
@@ -5524,6 +4727,7 @@ static void do_fill_brush_task_cb_ex(void *__restrict userdata,
SculptBrushTest test;
SculptBrushTestFn sculpt_brush_test_sq_fn = SCULPT_brush_test_init_with_falloff_shape(
ss, &test, data->brush->falloff_shape);
+ const int thread_id = BLI_task_parallel_thread_id(tls);
plane_from_point_normal_v3(test.plane_tool, area_co, area_no);
@@ -5547,7 +4751,7 @@ static void do_fill_brush_task_cb_ex(void *__restrict userdata,
vd.fno,
vd.mask ? *vd.mask : 0.0f,
vd.index,
- tls->thread_id);
+ thread_id);
mul_v3_v3fl(proxy[vd.i], val, fade);
@@ -5593,9 +4797,9 @@ static void do_fill_brush(Sculpt *sd, Object *ob, PBVHNode **nodes, int totnode)
.area_co = area_co,
};
- PBVHParallelSettings settings;
+ TaskParallelSettings settings;
BKE_pbvh_parallel_range_settings(&settings, (sd->flags & SCULPT_USE_OPENMP), totnode);
- BKE_pbvh_parallel_range(0, totnode, &data, do_fill_brush_task_cb_ex, &settings);
+ BLI_task_parallel_range(0, totnode, &data, do_fill_brush_task_cb_ex, &settings);
}
static void do_scrape_brush_task_cb_ex(void *__restrict userdata,
@@ -5617,6 +4821,7 @@ static void do_scrape_brush_task_cb_ex(void *__restrict userdata,
SculptBrushTest test;
SculptBrushTestFn sculpt_brush_test_sq_fn = SCULPT_brush_test_init_with_falloff_shape(
ss, &test, data->brush->falloff_shape);
+ const int thread_id = BLI_task_parallel_thread_id(tls);
plane_from_point_normal_v3(test.plane_tool, area_co, area_no);
BKE_pbvh_vertex_iter_begin(ss->pbvh, data->nodes[n], vd, PBVH_ITER_UNIQUE)
@@ -5639,7 +4844,7 @@ static void do_scrape_brush_task_cb_ex(void *__restrict userdata,
vd.fno,
vd.mask ? *vd.mask : 0.0f,
vd.index,
- tls->thread_id);
+ thread_id);
mul_v3_v3fl(proxy[vd.i], val, fade);
@@ -5685,9 +4890,9 @@ static void do_scrape_brush(Sculpt *sd, Object *ob, PBVHNode **nodes, int totnod
.area_co = area_co,
};
- PBVHParallelSettings settings;
+ TaskParallelSettings settings;
BKE_pbvh_parallel_range_settings(&settings, (sd->flags & SCULPT_USE_OPENMP), totnode);
- BKE_pbvh_parallel_range(0, totnode, &data, do_scrape_brush_task_cb_ex, &settings);
+ BLI_task_parallel_range(0, totnode, &data, do_scrape_brush_task_cb_ex, &settings);
}
/* -------------------------------------------------------------------- */
@@ -5715,6 +4920,7 @@ static void do_clay_thumb_brush_task_cb_ex(void *__restrict userdata,
SculptBrushTest test;
SculptBrushTestFn sculpt_brush_test_sq_fn = SCULPT_brush_test_init_with_falloff_shape(
ss, &test, data->brush->falloff_shape);
+ const int thread_id = BLI_task_parallel_thread_id(tls);
float plane_tilt[4];
float normal_tilt[3];
@@ -5755,7 +4961,7 @@ static void do_clay_thumb_brush_task_cb_ex(void *__restrict userdata,
vd.fno,
vd.mask ? *vd.mask : 0.0f,
vd.index,
- tls->thread_id);
+ thread_id);
mul_v3_v3fl(proxy[vd.i], val, fade);
@@ -5770,10 +4976,10 @@ static void do_clay_thumb_brush_task_cb_ex(void *__restrict userdata,
static float sculpt_clay_thumb_get_stabilized_pressure(StrokeCache *cache)
{
float final_pressure = 0.0f;
- for (int i = 0; i < CLAY_STABILIZER_LEN; i++) {
+ for (int i = 0; i < SCULPT_CLAY_STABILIZER_LEN; i++) {
final_pressure += cache->clay_pressure_stabilizer[i];
}
- return final_pressure / (float)CLAY_STABILIZER_LEN;
+ return final_pressure / (float)SCULPT_CLAY_STABILIZER_LEN;
}
static void do_clay_thumb_brush(Sculpt *sd, Object *ob, PBVHNode **nodes, int totnode)
@@ -5857,9 +5063,9 @@ static void do_clay_thumb_brush(Sculpt *sd, Object *ob, PBVHNode **nodes, int to
.clay_strength = clay_strength,
};
- PBVHParallelSettings settings;
+ TaskParallelSettings settings;
BKE_pbvh_parallel_range_settings(&settings, (sd->flags & SCULPT_USE_OPENMP), totnode);
- BKE_pbvh_parallel_range(0, totnode, &data, do_clay_thumb_brush_task_cb_ex, &settings);
+ BLI_task_parallel_range(0, totnode, &data, do_clay_thumb_brush_task_cb_ex, &settings);
}
/** \} */
@@ -5881,6 +5087,7 @@ static void do_gravity_task_cb_ex(void *__restrict userdata,
SculptBrushTest test;
SculptBrushTestFn sculpt_brush_test_sq_fn = SCULPT_brush_test_init_with_falloff_shape(
ss, &test, data->brush->falloff_shape);
+ const int thread_id = BLI_task_parallel_thread_id(tls);
BKE_pbvh_vertex_iter_begin(ss->pbvh, data->nodes[n], vd, PBVH_ITER_UNIQUE)
{
@@ -5893,7 +5100,7 @@ static void do_gravity_task_cb_ex(void *__restrict userdata,
vd.fno,
vd.mask ? *vd.mask : 0.0f,
vd.index,
- tls->thread_id);
+ thread_id);
mul_v3_v3fl(proxy[vd.i], offset, fade);
@@ -5928,9 +5135,9 @@ static void do_gravity(Sculpt *sd, Object *ob, PBVHNode **nodes, int totnode, fl
.offset = offset,
};
- PBVHParallelSettings settings;
+ TaskParallelSettings settings;
BKE_pbvh_parallel_range_settings(&settings, (sd->flags & SCULPT_USE_OPENMP), totnode);
- BKE_pbvh_parallel_range(0, totnode, &data, do_gravity_task_cb_ex, &settings);
+ BLI_task_parallel_range(0, totnode, &data, do_gravity_task_cb_ex, &settings);
}
void SCULPT_vertcos_to_key(Object *ob, KeyBlock *kb, const float (*vertCos)[3])
@@ -6109,6 +5316,23 @@ static void do_brush_action(Sculpt *sd, Object *ob, Brush *brush, UnifiedPaintSe
nodes = sculpt_pbvh_gather_generic(ob, sd, brush, use_original, radius_scale, &totnode);
}
+ /* Draw Face Sets in draw mode makes a single undo push, in alt-smooth mode deforms the
+ * vertices and uses regular coords undo. */
+ /* It also assigns the paint_face_set here as it needs to be done regardless of the stroke type
+ * and the number of nodes under the brush influence. */
+ if (brush->sculpt_tool == SCULPT_TOOL_DRAW_FACE_SETS && ss->cache->first_time &&
+ ss->cache->mirror_symmetry_pass == 0 && !ss->cache->alt_smooth) {
+ SCULPT_undo_push_node(ob, NULL, SCULPT_UNDO_FACE_SETS);
+ if (ss->cache->invert) {
+ /* When inverting the brush, pick the paint face mask ID from the mesh. */
+ ss->cache->paint_face_set = SCULPT_active_face_set_get(ss);
+ }
+ else {
+ /* By default create a new Face Sets. */
+ ss->cache->paint_face_set = SCULPT_face_set_next_available_get(ss);
+ }
+ }
+
/* Only act if some verts are inside the brush area. */
if (totnode) {
float location[3];
@@ -6120,16 +5344,9 @@ static void do_brush_action(Sculpt *sd, Object *ob, Brush *brush, UnifiedPaintSe
.nodes = nodes,
};
- PBVHParallelSettings settings;
+ TaskParallelSettings settings;
BKE_pbvh_parallel_range_settings(&settings, (sd->flags & SCULPT_USE_OPENMP), totnode);
- BKE_pbvh_parallel_range(0, totnode, &task_data, do_brush_action_task_cb, &settings);
-
- /* Draw Face Sets in draw mode makes a single undo push, in alt-smooth mode deforms the
- * vertices and uses regular coords undo. */
- if (brush->sculpt_tool == SCULPT_TOOL_DRAW_FACE_SETS && ss->cache->first_time &&
- ss->cache->mirror_symmetry_pass == 0 && !ss->cache->alt_smooth) {
- SCULPT_undo_push_node(ob, nodes[0], SCULPT_UNDO_FACE_SETS);
- }
+ BLI_task_parallel_range(0, totnode, &task_data, do_brush_action_task_cb, &settings);
if (sculpt_brush_needs_normal(ss, brush)) {
update_sculpt_normal(sd, ob, nodes, totnode);
@@ -6140,8 +5357,8 @@ static void do_brush_action(Sculpt *sd, Object *ob, Brush *brush, UnifiedPaintSe
}
if (ss->cache->first_time && ss->cache->mirror_symmetry_pass == 0) {
- if (sculpt_automasking_enabled(ss, brush)) {
- sculpt_automasking_init(sd, ob);
+ if (SCULPT_is_automasking_enabled(sd, ss, brush)) {
+ SCULPT_automasking_init(sd, ob);
}
}
@@ -6159,10 +5376,10 @@ static void do_brush_action(Sculpt *sd, Object *ob, Brush *brush, UnifiedPaintSe
break;
case SCULPT_TOOL_SMOOTH:
if (brush->smooth_deform_type == BRUSH_SMOOTH_DEFORM_LAPLACIAN) {
- do_smooth_brush(sd, ob, nodes, totnode);
+ SCULPT_do_smooth_brush(sd, ob, nodes, totnode);
}
else if (brush->smooth_deform_type == BRUSH_SMOOTH_DEFORM_SURFACE) {
- do_surface_smooth_brush(sd, ob, nodes, totnode);
+ SCULPT_do_surface_smooth_brush(sd, ob, nodes, totnode);
}
break;
case SCULPT_TOOL_CREASE:
@@ -6245,22 +5462,22 @@ static void do_brush_action(Sculpt *sd, Object *ob, Brush *brush, UnifiedPaintSe
SCULPT_do_cloth_brush(sd, ob, nodes, totnode);
break;
case SCULPT_TOOL_DRAW_FACE_SETS:
- do_draw_face_sets_brush(sd, ob, nodes, totnode);
+ SCULPT_do_draw_face_sets_brush(sd, ob, nodes, totnode);
break;
}
if (!ELEM(brush->sculpt_tool, SCULPT_TOOL_SMOOTH, SCULPT_TOOL_MASK) &&
brush->autosmooth_factor > 0) {
if (brush->flag & BRUSH_INVERSE_SMOOTH_PRESSURE) {
- smooth(sd,
- ob,
- nodes,
- totnode,
- brush->autosmooth_factor * (1.0f - ss->cache->pressure),
- false);
+ SCULPT_smooth(sd,
+ ob,
+ nodes,
+ totnode,
+ brush->autosmooth_factor * (1.0f - ss->cache->pressure),
+ false);
}
else {
- smooth(sd, ob, nodes, totnode, brush->autosmooth_factor, false);
+ SCULPT_smooth(sd, ob, nodes, totnode, brush->autosmooth_factor, false);
}
}
@@ -6269,7 +5486,8 @@ static void do_brush_action(Sculpt *sd, Object *ob, Brush *brush, UnifiedPaintSe
}
/* The cloth brush adds the gravity as a regular force and it is processed in the solver. */
- if (ss->cache->supports_gravity && brush->sculpt_tool != SCULPT_TOOL_CLOTH) {
+ if (ss->cache->supports_gravity &&
+ !ELEM(brush->sculpt_tool, SCULPT_TOOL_CLOTH, SCULPT_TOOL_DRAW_FACE_SETS)) {
do_gravity(sd, ob, nodes, totnode, sd->gravity_factor);
}
@@ -6354,7 +5572,7 @@ static void sculpt_combine_proxies_task_cb(void *__restrict userdata,
add_v3_v3(val, proxies[p].co[vd.i]);
}
- sculpt_clip(sd, ss, vd.co, val);
+ SCULPT_clip(sd, ss, vd.co, val);
if (ss->deform_modifiers_active) {
sculpt_flush_pbvhvert_deform(ob, &vd);
@@ -6383,9 +5601,9 @@ static void sculpt_combine_proxies(Sculpt *sd, Object *ob)
.nodes = nodes,
};
- PBVHParallelSettings settings;
+ TaskParallelSettings settings;
BKE_pbvh_parallel_range_settings(&settings, (sd->flags & SCULPT_USE_OPENMP), totnode);
- BKE_pbvh_parallel_range(0, totnode, &data, sculpt_combine_proxies_task_cb, &settings);
+ BLI_task_parallel_range(0, totnode, &data, sculpt_combine_proxies_task_cb, &settings);
}
MEM_SAFE_FREE(nodes);
@@ -6415,7 +5633,7 @@ static void sculpt_update_keyblock(Object *ob)
}
}
-static void sculpt_flush_stroke_deform_task_cb(void *__restrict userdata,
+static void SCULPT_flush_stroke_deform_task_cb(void *__restrict userdata,
const int n,
const TaskParallelTLS *__restrict UNUSED(tls))
{
@@ -6439,7 +5657,7 @@ static void sculpt_flush_stroke_deform_task_cb(void *__restrict userdata,
}
/* Flush displacement from deformed PBVH to original layer. */
-static void sculpt_flush_stroke_deform(Sculpt *sd, Object *ob, bool is_proxy_used)
+void SCULPT_flush_stroke_deform(Sculpt *sd, Object *ob, bool is_proxy_used)
{
SculptSession *ss = ob->sculpt;
Brush *brush = BKE_paint_brush(&sd->paint);
@@ -6471,9 +5689,9 @@ static void sculpt_flush_stroke_deform(Sculpt *sd, Object *ob, bool is_proxy_use
.vertCos = vertCos,
};
- PBVHParallelSettings settings;
+ TaskParallelSettings settings;
BKE_pbvh_parallel_range_settings(&settings, (sd->flags & SCULPT_USE_OPENMP), totnode);
- BKE_pbvh_parallel_range(0, totnode, &data, sculpt_flush_stroke_deform_task_cb, &settings);
+ BLI_task_parallel_range(0, totnode, &data, SCULPT_flush_stroke_deform_task_cb, &settings);
if (vertCos) {
SCULPT_vertcos_to_key(ob, ss->shapekey_active, vertCos);
@@ -6632,7 +5850,7 @@ static void sculpt_fix_noise_tear(Sculpt *sd, Object *ob)
Brush *brush = BKE_paint_brush(&sd->paint);
MTex *mtex = &brush->mtex;
- if (ss->multires && mtex->tex && mtex->tex->type == TEX_NOISE) {
+ if (ss->multires.active && mtex->tex && mtex->tex->type == TEX_NOISE) {
multires_stitch_grids(ob);
}
}
@@ -6784,9 +6002,10 @@ static const char *sculpt_tool_name(Sculpt *sd)
void SCULPT_cache_free(StrokeCache *cache)
{
- if (cache->dial) {
- MEM_freeN(cache->dial);
- }
+ MEM_SAFE_FREE(cache->dial);
+ MEM_SAFE_FREE(cache->surface_smooth_laplacian_disp);
+ MEM_SAFE_FREE(cache->layer_displacement_factor);
+
if (cache->pose_ik_chain) {
SCULPT_pose_ik_chain_free(cache->pose_ik_chain);
}
@@ -6844,14 +6063,9 @@ static void sculpt_update_cache_invariants(
ss->cache = cache;
/* Set scaling adjustment. */
- if (brush->sculpt_tool == SCULPT_TOOL_LAYER) {
- max_scale = 1.0f;
- }
- else {
- max_scale = 0.0f;
- for (int i = 0; i < 3; i++) {
- max_scale = max_ff(max_scale, fabsf(ob->scale[i]));
- }
+ max_scale = 0.0f;
+ for (int i = 0; i < 3; i++) {
+ max_scale = max_ff(max_scale, fabsf(ob->scale[i]));
}
cache->scale[0] = max_scale / ob->scale[0];
cache->scale[1] = max_scale / ob->scale[1];
@@ -6967,32 +6181,6 @@ static void sculpt_update_cache_invariants(
normalize_v3(cache->true_gravity_direction);
}
- /* Initialize layer brush displacements and persistent coords. */
- if (brush->sculpt_tool == SCULPT_TOOL_LAYER) {
- /* Not supported yet for multires or dynamic topology. */
- if (!ss->multires && !ss->bm && !ss->layer_co && (brush->flag & BRUSH_PERSISTENT)) {
- if (!ss->layer_co) {
- ss->layer_co = MEM_mallocN(sizeof(float) * 3 * ss->totvert, "sculpt mesh vertices copy");
- }
-
- if (ss->deform_cos) {
- memcpy(ss->layer_co, ss->deform_cos, ss->totvert);
- }
- else {
- for (int i = 0; i < ss->totvert; i++) {
- copy_v3_v3(ss->layer_co[i], ss->mvert[i].co);
- }
- }
- }
-
- if (ss->bm) {
- /* Free any remaining layer displacements from nodes. If not and topology changes
- * from using another tool, then next layer toolstroke
- * can access past disp array bounds. */
- BKE_pbvh_free_layer_disp(ss->pbvh);
- }
- }
-
/* Make copies of the mesh vertex locations and normals for some tools. */
if (brush->flag & BRUSH_ANCHORED) {
cache->original = true;
@@ -7029,7 +6217,7 @@ static float sculpt_brush_dynamic_size_get(Brush *brush, StrokeCache *cache, flo
case SCULPT_TOOL_CLAY:
return max_ff(initial_size * 0.20f, initial_size * pow3f(cache->pressure));
case SCULPT_TOOL_CLAY_STRIPS:
- return max_ff(initial_size * 0.30f, initial_size * pow2f(cache->pressure));
+ return max_ff(initial_size * 0.30f, initial_size * powf(cache->pressure, 1.5f));
case SCULPT_TOOL_CLAY_THUMB: {
float clay_stabilized_pressure = sculpt_clay_thumb_get_stabilized_pressure(cache);
return initial_size * clay_stabilized_pressure;
@@ -7039,6 +6227,34 @@ static float sculpt_brush_dynamic_size_get(Brush *brush, StrokeCache *cache, flo
}
}
+/* In these brushes the grab delta is calculated always from the initial stroke location, which is
+ * generally used to create grab deformations. */
+static bool sculpt_needs_delta_from_anchored_origin(Brush *brush)
+{
+ return ELEM(brush->sculpt_tool,
+ SCULPT_TOOL_GRAB,
+ SCULPT_TOOL_POSE,
+ SCULPT_TOOL_THUMB,
+ SCULPT_TOOL_ELASTIC_DEFORM) ||
+ SCULPT_is_cloth_deform_brush(brush);
+}
+
+/* In these brushes the grab delta is calculated from the previous stroke location, which is used
+ * to calculate to orientate the brush tip and deformation towards the stroke direction. */
+static bool sculpt_needs_delta_for_tip_orientation(Brush *brush)
+{
+ if (brush->sculpt_tool == SCULPT_TOOL_CLOTH) {
+ return !SCULPT_is_cloth_deform_brush(brush);
+ }
+ return ELEM(brush->sculpt_tool,
+ SCULPT_TOOL_CLAY_STRIPS,
+ SCULPT_TOOL_PINCH,
+ SCULPT_TOOL_MULTIPLANE_SCRAPE,
+ SCULPT_TOOL_CLAY_THUMB,
+ SCULPT_TOOL_NUDGE,
+ SCULPT_TOOL_SNAKE_HOOK);
+}
+
static void sculpt_update_brush_delta(UnifiedPaintSettings *ups, Object *ob, Brush *brush)
{
SculptSession *ss = ob->sculpt;
@@ -7082,38 +6298,27 @@ static void sculpt_update_brush_delta(UnifiedPaintSettings *ups, Object *ob, Bru
/* Compute delta to move verts by. */
if (!cache->first_time) {
- switch (tool) {
- case SCULPT_TOOL_GRAB:
- case SCULPT_TOOL_POSE:
- case SCULPT_TOOL_THUMB:
- case SCULPT_TOOL_ELASTIC_DEFORM:
- sub_v3_v3v3(delta, grab_location, cache->old_grab_location);
- invert_m4_m4(imat, ob->obmat);
- mul_mat3_m4_v3(imat, delta);
- add_v3_v3(cache->grab_delta, delta);
- break;
- case SCULPT_TOOL_CLAY_STRIPS:
- case SCULPT_TOOL_PINCH:
- case SCULPT_TOOL_CLOTH:
- case SCULPT_TOOL_MULTIPLANE_SCRAPE:
- case SCULPT_TOOL_CLAY_THUMB:
- case SCULPT_TOOL_NUDGE:
- case SCULPT_TOOL_SNAKE_HOOK:
- if (brush->flag & BRUSH_ANCHORED) {
- float orig[3];
- mul_v3_m4v3(orig, ob->obmat, cache->orig_grab_location);
- sub_v3_v3v3(cache->grab_delta, grab_location, orig);
- }
- else {
- sub_v3_v3v3(cache->grab_delta, grab_location, cache->old_grab_location);
- }
- invert_m4_m4(imat, ob->obmat);
- mul_mat3_m4_v3(imat, cache->grab_delta);
- break;
- default:
- /* Use for 'Brush.topology_rake_factor'. */
+ if (sculpt_needs_delta_from_anchored_origin(brush)) {
+ sub_v3_v3v3(delta, grab_location, cache->old_grab_location);
+ invert_m4_m4(imat, ob->obmat);
+ mul_mat3_m4_v3(imat, delta);
+ add_v3_v3(cache->grab_delta, delta);
+ }
+ else if (sculpt_needs_delta_for_tip_orientation(brush)) {
+ if (brush->flag & BRUSH_ANCHORED) {
+ float orig[3];
+ mul_v3_m4v3(orig, ob->obmat, cache->orig_grab_location);
+ sub_v3_v3v3(cache->grab_delta, grab_location, orig);
+ }
+ else {
sub_v3_v3v3(cache->grab_delta, grab_location, cache->old_grab_location);
- break;
+ }
+ invert_m4_m4(imat, ob->obmat);
+ mul_mat3_m4_v3(imat, cache->grab_delta);
+ }
+ else {
+ /* Use for 'Brush.topology_rake_factor'. */
+ sub_v3_v3v3(cache->grab_delta, grab_location, cache->old_grab_location);
}
}
else {
@@ -7134,18 +6339,14 @@ static void sculpt_update_brush_delta(UnifiedPaintSettings *ups, Object *ob, Bru
copy_v3_v3(cache->anchored_location, cache->true_location);
}
}
- else if (tool == SCULPT_TOOL_ELASTIC_DEFORM) {
+ else if (tool == SCULPT_TOOL_ELASTIC_DEFORM || SCULPT_is_cloth_deform_brush(brush)) {
copy_v3_v3(cache->anchored_location, cache->true_location);
}
else if (tool == SCULPT_TOOL_THUMB) {
copy_v3_v3(cache->anchored_location, cache->orig_grab_location);
}
- if (ELEM(tool,
- SCULPT_TOOL_GRAB,
- SCULPT_TOOL_THUMB,
- SCULPT_TOOL_ELASTIC_DEFORM,
- SCULPT_TOOL_POSE)) {
+ if (sculpt_needs_delta_from_anchored_origin(brush)) {
/* Location stays the same for finding vertices in brush radius. */
copy_v3_v3(cache->true_location, cache->orig_grab_location);
@@ -7216,9 +6417,7 @@ static void sculpt_update_cache_variants(bContext *C, Sculpt *sd, Object *ob, Po
if (cache->first_time ||
!((brush->flag & BRUSH_ANCHORED) || (brush->sculpt_tool == SCULPT_TOOL_SNAKE_HOOK) ||
- (brush->sculpt_tool == SCULPT_TOOL_ROTATE) ||
- (brush->sculpt_tool == SCULPT_TOOL_CLOTH &&
- brush->cloth_deform_type == BRUSH_CLOTH_DEFORM_GRAB))) {
+ (brush->sculpt_tool == SCULPT_TOOL_ROTATE) || SCULPT_is_cloth_deform_brush(brush))) {
RNA_float_get_array(ptr, "location", cache->true_location);
}
@@ -7248,7 +6447,7 @@ static void sculpt_update_cache_variants(bContext *C, Sculpt *sd, Object *ob, Po
/* Clay stabilized pressure. */
if (brush->sculpt_tool == SCULPT_TOOL_CLAY_THUMB) {
if (ss->cache->first_time) {
- for (int i = 0; i < CLAY_STABILIZER_LEN; i++) {
+ for (int i = 0; i < SCULPT_CLAY_STABILIZER_LEN; i++) {
ss->cache->clay_pressure_stabilizer[i] = 0.0f;
}
ss->cache->clay_pressure_stabilizer_index = 0;
@@ -7256,7 +6455,7 @@ static void sculpt_update_cache_variants(bContext *C, Sculpt *sd, Object *ob, Po
else {
cache->clay_pressure_stabilizer[cache->clay_pressure_stabilizer_index] = cache->pressure;
cache->clay_pressure_stabilizer_index += 1;
- if (cache->clay_pressure_stabilizer_index >= CLAY_STABILIZER_LEN) {
+ if (cache->clay_pressure_stabilizer_index >= SCULPT_CLAY_STABILIZER_LEN) {
cache->clay_pressure_stabilizer_index = 0;
}
}
@@ -7307,9 +6506,12 @@ static void sculpt_update_cache_variants(bContext *C, Sculpt *sd, Object *ob, Po
/* Returns true if any of the smoothing modes are active (currently
* one of smooth brush, autosmooth, mask smooth, or shift-key
* smooth). */
-static bool sculpt_needs_connectivity_info(const Brush *brush, SculptSession *ss, int stroke_mode)
+static bool sculpt_needs_connectivity_info(const Sculpt *sd,
+ const Brush *brush,
+ SculptSession *ss,
+ int stroke_mode)
{
- if (ss && ss->pbvh && sculpt_automasking_enabled(ss, brush)) {
+ if (ss && ss->pbvh && SCULPT_is_automasking_enabled(sd, ss, brush)) {
return true;
}
return ((stroke_mode == BRUSH_STROKE_SMOOTH) || (ss && ss->cache && ss->cache->alt_smooth) ||
@@ -7321,12 +6523,13 @@ static bool sculpt_needs_connectivity_info(const Brush *brush, SculptSession *ss
(brush->sculpt_tool == SCULPT_TOOL_DRAW_FACE_SETS));
}
-static void sculpt_stroke_modifiers_check(const bContext *C, Object *ob, const Brush *brush)
+void SCULPT_stroke_modifiers_check(const bContext *C, Object *ob, const Brush *brush)
{
SculptSession *ss = ob->sculpt;
View3D *v3d = CTX_wm_view3d(C);
+ Sculpt *sd = CTX_data_tool_settings(C)->sculpt;
- bool need_pmap = sculpt_needs_connectivity_info(brush, ss, 0);
+ bool need_pmap = sculpt_needs_connectivity_info(sd, brush, ss, 0);
if (ss->shapekey_active || ss->deform_modifiers_active ||
(!BKE_sculptsession_use_pbvh_draw(ob, v3d) && need_pmap)) {
Depsgraph *depsgraph = CTX_data_depsgraph_pointer(C);
@@ -7362,6 +6565,7 @@ static void sculpt_raycast_cb(PBVHNode *node, void *data_v, float *tmin)
&srd->isect_precalc,
&srd->depth,
&srd->active_vertex_index,
+ &srd->active_face_grid_index,
srd->face_normal)) {
srd->hit = true;
*tmin = srd->depth;
@@ -7402,24 +6606,12 @@ static void sculpt_find_nearest_to_ray_cb(PBVHNode *node, void *data_v, float *t
}
}
-static void sculpt_raycast_detail_cb(PBVHNode *node, void *data_v, float *tmin)
-{
- if (BKE_pbvh_node_get_tmin(node) < *tmin) {
- SculptDetailRaycastData *srd = data_v;
- if (BKE_pbvh_bmesh_node_raycast_detail(
- node, srd->ray_start, &srd->isect_precalc, &srd->depth, &srd->edge_length)) {
- srd->hit = true;
- *tmin = srd->depth;
- }
- }
-}
-
-static float sculpt_raycast_init(ViewContext *vc,
- const float mouse[2],
- float ray_start[3],
- float ray_end[3],
- float ray_normal[3],
- bool original)
+float SCULPT_raycast_init(ViewContext *vc,
+ const float mouse[2],
+ float ray_start[3],
+ float ray_end[3],
+ float ray_normal[3],
+ bool original)
{
float obimat[4][4];
float dist;
@@ -7485,8 +6677,8 @@ bool SCULPT_cursor_geometry_info_update(bContext *C,
}
/* PBVH raycast to get active vertex and face normal. */
- depth = sculpt_raycast_init(&vc, mouse, ray_start, ray_end, ray_normal, original);
- sculpt_stroke_modifiers_check(C, ob, brush);
+ depth = SCULPT_raycast_init(&vc, mouse, ray_start, ray_end, ray_normal, original);
+ SCULPT_stroke_modifiers_check(C, ob, brush);
SculptRaycastData srd = {
.original = original,
@@ -7512,6 +6704,21 @@ bool SCULPT_cursor_geometry_info_update(bContext *C,
ss->active_vertex_index = srd.active_vertex_index;
copy_v3_v3(out->active_vertex_co, SCULPT_active_vertex_co_get(ss));
+ switch (BKE_pbvh_type(ss->pbvh)) {
+ case PBVH_FACES:
+ ss->active_face_index = srd.active_face_grid_index;
+ ss->active_grid_index = 0;
+ break;
+ case PBVH_GRIDS:
+ ss->active_face_index = 0;
+ ss->active_grid_index = srd.active_face_grid_index;
+ break;
+ case PBVH_BMESH:
+ ss->active_face_index = 0;
+ ss->active_grid_index = 0;
+ break;
+ }
+
copy_v3_v3(out->location, ray_normal);
mul_v3_fl(out->location, srd.depth);
add_v3_v3(out->location, ray_start);
@@ -7590,9 +6797,9 @@ bool SCULPT_stroke_get_location(bContext *C, float out[3], const float mouse[2])
const Brush *brush = BKE_paint_brush(BKE_paint_get_active_from_context(C));
- sculpt_stroke_modifiers_check(C, ob, brush);
+ SCULPT_stroke_modifiers_check(C, ob, brush);
- depth = sculpt_raycast_init(&vc, mouse, ray_start, ray_end, ray_normal, original);
+ depth = SCULPT_raycast_init(&vc, mouse, ray_start, ray_end, ray_normal, original);
if (BKE_pbvh_type(ss->pbvh) == PBVH_BMESH) {
BM_mesh_elem_table_ensure(ss->bm, BM_VERT);
@@ -7684,12 +6891,13 @@ static void sculpt_brush_stroke_init(bContext *C, wmOperator *op)
view3d_operator_needs_opengl(C);
sculpt_brush_init_tex(scene, sd, ss);
- is_smooth = sculpt_needs_connectivity_info(brush, ss, mode);
+ is_smooth = sculpt_needs_connectivity_info(sd, brush, ss, mode);
BKE_sculpt_update_object_for_edit(depsgraph, ob, is_smooth, need_mask);
}
static void sculpt_restore_mesh(Sculpt *sd, Object *ob)
{
+ SculptSession *ss = ob->sculpt;
Brush *brush = BKE_paint_brush(&sd->paint);
/* Restore the mesh before continuing with anchored stroke. */
@@ -7699,7 +6907,19 @@ static void sculpt_restore_mesh(Sculpt *sd, Object *ob)
brush->sculpt_tool == SCULPT_TOOL_CLOTH) &&
BKE_brush_use_size_pressure(brush)) ||
(brush->flag & BRUSH_DRAG_DOT)) {
+
+ SculptUndoNode *unode = SCULPT_undo_get_first_node();
+ if (unode && unode->type == SCULPT_UNDO_FACE_SETS) {
+ for (int i = 0; i < ss->totfaces; i++) {
+ ss->face_sets[i] = unode->face_sets[i];
+ }
+ }
+
paint_mesh_restore_co(sd, ob);
+
+ if (ss->cache) {
+ MEM_SAFE_FREE(ss->cache->layer_displacement_factor);
+ }
}
}
@@ -7714,13 +6934,13 @@ void SCULPT_update_object_bounding_box(Object *ob)
}
}
-static void sculpt_flush_update_step(bContext *C, SculptUpdateType update_flags)
+void SCULPT_flush_update_step(bContext *C, SculptUpdateType update_flags)
{
Depsgraph *depsgraph = CTX_data_depsgraph_pointer(C);
Object *ob = CTX_data_active_object(C);
SculptSession *ss = ob->sculpt;
ARegion *region = CTX_wm_region(C);
- MultiresModifierData *mmd = ss->multires;
+ MultiresModifierData *mmd = ss->multires.modifier;
View3D *v3d = CTX_wm_view3d(C);
RegionView3D *rv3d = CTX_wm_region_view3d(C);
@@ -7774,7 +6994,7 @@ static void sculpt_flush_update_step(bContext *C, SculptUpdateType update_flags)
}
}
-static void sculpt_flush_update_done(const bContext *C, Object *ob, SculptUpdateType update_flags)
+void SCULPT_flush_update_done(const bContext *C, Object *ob, SculptUpdateType update_flags)
{
/* After we are done drawing the stroke, check if we need to do a more
* expensive depsgraph tag to update geometry. */
@@ -7791,10 +7011,10 @@ static void sculpt_flush_update_done(const bContext *C, Object *ob, SculptUpdate
rv3d->rflag &= ~RV3D_PAINTING;
}
- for (wmWindow *win = wm->windows.first; win; win = win->next) {
+ LISTBASE_FOREACH (wmWindow *, win, &wm->windows) {
bScreen *screen = WM_window_get_active_screen(win);
- for (ScrArea *sa = screen->areabase.first; sa; sa = sa->next) {
- SpaceLink *sl = sa->spacedata.first;
+ LISTBASE_FOREACH (ScrArea *, area, &screen->areabase) {
+ SpaceLink *sl = area->spacedata.first;
if (sl->spacetype == SPACE_VIEW3D) {
View3D *v3d = (View3D *)sl;
if (v3d != current_v3d) {
@@ -7804,7 +7024,7 @@ static void sculpt_flush_update_done(const bContext *C, Object *ob, SculptUpdate
/* Tag all 3D viewports for redraw now that we are done. Others
* viewports did not get a full redraw, and anti-aliasing for the
* current viewport was deactivated. */
- for (ARegion *region = sa->regionbase.first; region; region = region->next) {
+ LISTBASE_FOREACH (ARegion *, region, &area->regionbase) {
if (region->regiontype == RGN_TYPE_WINDOW) {
ED_region_tag_redraw(region);
}
@@ -7884,7 +7104,7 @@ static void sculpt_stroke_update_step(bContext *C,
SculptSession *ss = ob->sculpt;
const Brush *brush = BKE_paint_brush(&sd->paint);
- sculpt_stroke_modifiers_check(C, ob, brush);
+ SCULPT_stroke_modifiers_check(C, ob, brush);
sculpt_update_cache_variants(C, sd, ob, itemptr);
sculpt_restore_mesh(sd, ob);
@@ -7901,7 +7121,7 @@ static void sculpt_stroke_update_step(bContext *C,
(float)(sd->detail_size * U.pixelsize) / 0.4f);
}
- if (sculpt_stroke_is_dynamic_topology(ss, brush)) {
+ if (SCULPT_stroke_is_dynamic_topology(ss, brush)) {
do_symmetrical_brush_actions(sd, ob, sculpt_topology_update, ups);
}
@@ -7922,7 +7142,7 @@ static void sculpt_stroke_update_step(bContext *C,
* sculpt_flush_update_step().
*/
if (ss->deform_modifiers_active) {
- sculpt_flush_stroke_deform(sd, ob, sculpt_tool_is_proxy_used(brush->sculpt_tool));
+ SCULPT_flush_stroke_deform(sd, ob, sculpt_tool_is_proxy_used(brush->sculpt_tool));
}
else if (ss->shapekey_active) {
sculpt_update_keyblock(ob);
@@ -7933,10 +7153,10 @@ static void sculpt_stroke_update_step(bContext *C,
/* Cleanup. */
if (brush->sculpt_tool == SCULPT_TOOL_MASK) {
- sculpt_flush_update_step(C, SCULPT_UPDATE_MASK);
+ SCULPT_flush_update_step(C, SCULPT_UPDATE_MASK);
}
else {
- sculpt_flush_update_step(C, SCULPT_UPDATE_COORDS);
+ SCULPT_flush_update_step(C, SCULPT_UPDATE_COORDS);
}
}
@@ -7965,7 +7185,7 @@ static void sculpt_stroke_done(const bContext *C, struct PaintStroke *UNUSED(str
BLI_assert(brush == ss->cache->brush); /* const, so we shouldn't change. */
ups->draw_inverted = false;
- sculpt_stroke_modifiers_check(C, ob, brush);
+ SCULPT_stroke_modifiers_check(C, ob, brush);
/* Alt-Smooth. */
if (ss->cache->alt_smooth) {
@@ -7984,8 +7204,8 @@ static void sculpt_stroke_done(const bContext *C, struct PaintStroke *UNUSED(str
}
}
- if (sculpt_automasking_enabled(ss, brush)) {
- sculpt_automasking_end(ob);
+ if (SCULPT_is_automasking_enabled(sd, ss, brush)) {
+ SCULPT_automasking_end(ob);
}
SCULPT_cache_free(ss->cache);
@@ -7994,10 +7214,10 @@ static void sculpt_stroke_done(const bContext *C, struct PaintStroke *UNUSED(str
SCULPT_undo_push_end();
if (brush->sculpt_tool == SCULPT_TOOL_MASK) {
- sculpt_flush_update_done(C, ob, SCULPT_UPDATE_MASK);
+ SCULPT_flush_update_done(C, ob, SCULPT_UPDATE_MASK);
}
else {
- sculpt_flush_update_done(C, ob, SCULPT_UPDATE_COORDS);
+ SCULPT_flush_update_done(C, ob, SCULPT_UPDATE_COORDS);
}
WM_event_add_notifier(C, NC_OBJECT | ND_DRAW, ob);
@@ -8074,7 +7294,7 @@ static void sculpt_brush_stroke_cancel(bContext *C, wmOperator *op)
/* XXX Canceling strokes that way does not work with dynamic topology,
* user will have to do real undo for now. See T46456. */
- if (ss->cache && !sculpt_stroke_is_dynamic_topology(ss, brush)) {
+ if (ss->cache && !SCULPT_stroke_is_dynamic_topology(ss, brush)) {
paint_mesh_restore_co(sd, ob);
}
@@ -8120,13 +7340,25 @@ static void SCULPT_OT_brush_stroke(wmOperatorType *ot)
static int sculpt_set_persistent_base_exec(bContext *C, wmOperator *UNUSED(op))
{
- SculptSession *ss = CTX_data_active_object(C)->sculpt;
+ Depsgraph *depsgraph = CTX_data_depsgraph_pointer(C);
+ Object *ob = CTX_data_active_object(C);
+ SculptSession *ss = ob->sculpt;
if (ss) {
- if (ss->layer_co) {
- MEM_freeN(ss->layer_co);
+ SCULPT_vertex_random_access_init(ss);
+ BKE_sculpt_update_object_for_edit(depsgraph, ob, false, false);
+
+ MEM_SAFE_FREE(ss->layer_base);
+
+ const int totvert = SCULPT_vertex_count_get(ss);
+ ss->layer_base = MEM_mallocN(sizeof(SculptLayerPersistentBase) * totvert,
+ "layer persistent base");
+
+ for (int i = 0; i < totvert; i++) {
+ copy_v3_v3(ss->layer_base[i].co, SCULPT_vertex_co_get(ss, i));
+ SCULPT_vertex_normal_get(ss, i, ss->layer_base[i].no);
+ ss->layer_base[i].disp = 0.0f;
}
- ss->layer_co = NULL;
}
return OPERATOR_FINISHED;
@@ -8146,384 +7378,18 @@ static void SCULPT_OT_set_persistent_base(wmOperatorType *ot)
ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
}
-/************************** Dynamic Topology **************************/
-
-static void sculpt_dynamic_topology_triangulate(BMesh *bm)
-{
- if (bm->totloop != bm->totface * 3) {
- BM_mesh_triangulate(
- bm, MOD_TRIANGULATE_QUAD_BEAUTY, MOD_TRIANGULATE_NGON_EARCLIP, 4, false, NULL, NULL, NULL);
- }
-}
-
-void sculpt_pbvh_clear(Object *ob)
-{
- SculptSession *ss = ob->sculpt;
-
- /* Clear out any existing DM and PBVH. */
- if (ss->pbvh) {
- BKE_pbvh_free(ss->pbvh);
- ss->pbvh = NULL;
- }
-
- if (ss->pmap) {
- MEM_freeN(ss->pmap);
- ss->pmap = NULL;
- }
-
- if (ss->pmap_mem) {
- MEM_freeN(ss->pmap_mem);
- ss->pmap_mem = NULL;
- }
-
- BKE_object_free_derived_caches(ob);
-
- /* Tag to rebuild PBVH in depsgraph. */
- DEG_id_tag_update(&ob->id, ID_RECALC_GEOMETRY);
-}
-
-void sculpt_dyntopo_node_layers_add(SculptSession *ss)
-{
- int cd_node_layer_index;
-
- char layer_id[] = "_dyntopo_node_id";
-
- cd_node_layer_index = CustomData_get_named_layer_index(&ss->bm->vdata, CD_PROP_INT, layer_id);
- if (cd_node_layer_index == -1) {
- BM_data_layer_add_named(ss->bm, &ss->bm->vdata, CD_PROP_INT, layer_id);
- cd_node_layer_index = CustomData_get_named_layer_index(&ss->bm->vdata, CD_PROP_INT, layer_id);
- }
-
- ss->cd_vert_node_offset = CustomData_get_n_offset(
- &ss->bm->vdata,
- CD_PROP_INT,
- cd_node_layer_index - CustomData_get_layer_index(&ss->bm->vdata, CD_PROP_INT));
-
- ss->bm->vdata.layers[cd_node_layer_index].flag |= CD_FLAG_TEMPORARY;
-
- cd_node_layer_index = CustomData_get_named_layer_index(&ss->bm->pdata, CD_PROP_INT, layer_id);
- if (cd_node_layer_index == -1) {
- BM_data_layer_add_named(ss->bm, &ss->bm->pdata, CD_PROP_INT, layer_id);
- cd_node_layer_index = CustomData_get_named_layer_index(&ss->bm->pdata, CD_PROP_INT, layer_id);
- }
-
- ss->cd_face_node_offset = CustomData_get_n_offset(
- &ss->bm->pdata,
- CD_PROP_INT,
- cd_node_layer_index - CustomData_get_layer_index(&ss->bm->pdata, CD_PROP_INT));
-
- ss->bm->pdata.layers[cd_node_layer_index].flag |= CD_FLAG_TEMPORARY;
-}
-
-static void sculpt_dynamic_topology_enable_ex(Main *bmain,
- Depsgraph *depsgraph,
- Scene *scene,
- Object *ob)
-{
- SculptSession *ss = ob->sculpt;
- Mesh *me = ob->data;
- const BMAllocTemplate allocsize = BMALLOC_TEMPLATE_FROM_ME(me);
-
- sculpt_pbvh_clear(ob);
-
- ss->bm_smooth_shading = (scene->toolsettings->sculpt->flags & SCULPT_DYNTOPO_SMOOTH_SHADING) !=
- 0;
-
- /* Dynamic topology doesn't ensure selection state is valid, so remove [#36280]. */
- BKE_mesh_mselect_clear(me);
-
- /* Create triangles-only BMesh. */
- ss->bm = BM_mesh_create(&allocsize,
- &((struct BMeshCreateParams){
- .use_toolflags = false,
- }));
-
- BM_mesh_bm_from_me(ss->bm,
- me,
- (&(struct BMeshFromMeshParams){
- .calc_face_normal = true,
- .use_shapekey = true,
- .active_shapekey = ob->shapenr,
- }));
- sculpt_dynamic_topology_triangulate(ss->bm);
- BM_data_layer_add(ss->bm, &ss->bm->vdata, CD_PAINT_MASK);
- sculpt_dyntopo_node_layers_add(ss);
- /* Make sure the data for existing faces are initialized. */
- if (me->totpoly != ss->bm->totface) {
- BM_mesh_normals_update(ss->bm);
- }
-
- /* Enable dynamic topology. */
- me->flag |= ME_SCULPT_DYNAMIC_TOPOLOGY;
-
- /* Enable logging for undo/redo. */
- ss->bm_log = BM_log_create(ss->bm);
-
- /* Update dependency graph, so modifiers that depend on dyntopo being enabled
- * are re-evaluated and the PBVH is re-created. */
- DEG_id_tag_update(&ob->id, ID_RECALC_GEOMETRY);
- BKE_scene_graph_update_tagged(depsgraph, bmain);
-}
-
-/* Free the sculpt BMesh and BMLog
- *
- * If 'unode' is given, the BMesh's data is copied out to the unode
- * before the BMesh is deleted so that it can be restored from. */
-static void sculpt_dynamic_topology_disable_ex(
- Main *bmain, Depsgraph *depsgraph, Scene *scene, Object *ob, SculptUndoNode *unode)
-{
- SculptSession *ss = ob->sculpt;
- Mesh *me = ob->data;
-
- sculpt_pbvh_clear(ob);
-
- if (unode) {
- /* Free all existing custom data. */
- CustomData_free(&me->vdata, me->totvert);
- CustomData_free(&me->edata, me->totedge);
- CustomData_free(&me->fdata, me->totface);
- CustomData_free(&me->ldata, me->totloop);
- CustomData_free(&me->pdata, me->totpoly);
-
- /* Copy over stored custom data. */
- me->totvert = unode->geom_totvert;
- me->totloop = unode->geom_totloop;
- me->totpoly = unode->geom_totpoly;
- me->totedge = unode->geom_totedge;
- me->totface = 0;
- CustomData_copy(
- &unode->geom_vdata, &me->vdata, CD_MASK_MESH.vmask, CD_DUPLICATE, unode->geom_totvert);
- CustomData_copy(
- &unode->geom_edata, &me->edata, CD_MASK_MESH.emask, CD_DUPLICATE, unode->geom_totedge);
- CustomData_copy(
- &unode->geom_ldata, &me->ldata, CD_MASK_MESH.lmask, CD_DUPLICATE, unode->geom_totloop);
- CustomData_copy(
- &unode->geom_pdata, &me->pdata, CD_MASK_MESH.pmask, CD_DUPLICATE, unode->geom_totpoly);
-
- BKE_mesh_update_customdata_pointers(me, false);
- }
- else {
- BKE_sculptsession_bm_to_me(ob, true);
- }
-
- /* Clear data. */
- me->flag &= ~ME_SCULPT_DYNAMIC_TOPOLOGY;
-
- /* Typically valid but with global-undo they can be NULL. [#36234] */
- if (ss->bm) {
- BM_mesh_free(ss->bm);
- ss->bm = NULL;
- }
- if (ss->bm_log) {
- BM_log_free(ss->bm_log);
- ss->bm_log = NULL;
- }
-
- BKE_particlesystem_reset_all(ob);
- BKE_ptcache_object_reset(scene, ob, PTCACHE_RESET_OUTDATED);
-
- /* Update dependency graph, so modifiers that depend on dyntopo being enabled
- * are re-evaluated and the PBVH is re-created. */
- DEG_id_tag_update(&ob->id, ID_RECALC_GEOMETRY);
- BKE_scene_graph_update_tagged(depsgraph, bmain);
-}
-
-void sculpt_dynamic_topology_disable(bContext *C, SculptUndoNode *unode)
-{
- Main *bmain = CTX_data_main(C);
- Depsgraph *depsgraph = CTX_data_ensure_evaluated_depsgraph(C);
- Scene *scene = CTX_data_scene(C);
- Object *ob = CTX_data_active_object(C);
- sculpt_dynamic_topology_disable_ex(bmain, depsgraph, scene, ob, unode);
-}
-
-static void sculpt_dynamic_topology_disable_with_undo(Main *bmain,
- Depsgraph *depsgraph,
- Scene *scene,
- Object *ob)
-{
- SculptSession *ss = ob->sculpt;
- if (ss->bm) {
- SCULPT_undo_push_begin("Dynamic topology disable");
- SCULPT_undo_push_node(ob, NULL, SCULPT_UNDO_DYNTOPO_END);
- sculpt_dynamic_topology_disable_ex(bmain, depsgraph, scene, ob, NULL);
- SCULPT_undo_push_end();
- }
-}
-
-static void sculpt_dynamic_topology_enable_with_undo(Main *bmain,
- Depsgraph *depsgraph,
- Scene *scene,
- Object *ob)
-{
- SculptSession *ss = ob->sculpt;
- if (ss->bm == NULL) {
- SCULPT_undo_push_begin("Dynamic topology enable");
- sculpt_dynamic_topology_enable_ex(bmain, depsgraph, scene, ob);
- SCULPT_undo_push_node(ob, NULL, SCULPT_UNDO_DYNTOPO_BEGIN);
- SCULPT_undo_push_end();
- }
-}
-
-static int sculpt_dynamic_topology_toggle_exec(bContext *C, wmOperator *UNUSED(op))
-{
- Main *bmain = CTX_data_main(C);
- Depsgraph *depsgraph = CTX_data_ensure_evaluated_depsgraph(C);
- Scene *scene = CTX_data_scene(C);
- Object *ob = CTX_data_active_object(C);
- SculptSession *ss = ob->sculpt;
-
- WM_cursor_wait(true);
-
- if (ss->bm) {
- sculpt_dynamic_topology_disable_with_undo(bmain, depsgraph, scene, ob);
- }
- else {
- sculpt_dynamic_topology_enable_with_undo(bmain, depsgraph, scene, ob);
- }
-
- WM_cursor_wait(false);
- WM_main_add_notifier(NC_SCENE | ND_TOOLSETTINGS, NULL);
-
- return OPERATOR_FINISHED;
-}
-
-enum eDynTopoWarnFlag {
- DYNTOPO_WARN_VDATA = (1 << 0),
- DYNTOPO_WARN_EDATA = (1 << 1),
- DYNTOPO_WARN_LDATA = (1 << 2),
- DYNTOPO_WARN_MODIFIER = (1 << 3),
-};
-
-static int dyntopo_warning_popup(bContext *C, wmOperatorType *ot, enum eDynTopoWarnFlag flag)
-{
- uiPopupMenu *pup = UI_popup_menu_begin(C, IFACE_("Warning!"), ICON_ERROR);
- uiLayout *layout = UI_popup_menu_layout(pup);
-
- if (flag & (DYNTOPO_WARN_VDATA | DYNTOPO_WARN_EDATA | DYNTOPO_WARN_LDATA)) {
- const char *msg_error = TIP_("Vertex Data Detected!");
- const char *msg = TIP_("Dyntopo will not preserve vertex colors, UVs, or other customdata");
- uiItemL(layout, msg_error, ICON_INFO);
- uiItemL(layout, msg, ICON_NONE);
- uiItemS(layout);
- }
-
- if (flag & DYNTOPO_WARN_MODIFIER) {
- const char *msg_error = TIP_("Generative Modifiers Detected!");
- const char *msg = TIP_(
- "Keeping the modifiers will increase polycount when returning to object mode");
-
- uiItemL(layout, msg_error, ICON_INFO);
- uiItemL(layout, msg, ICON_NONE);
- uiItemS(layout);
- }
-
- uiItemFullO_ptr(layout, ot, IFACE_("OK"), ICON_NONE, NULL, WM_OP_EXEC_DEFAULT, 0, NULL);
-
- UI_popup_menu_end(C, pup);
-
- return OPERATOR_INTERFACE;
-}
-
-static enum eDynTopoWarnFlag sculpt_dynamic_topology_check(Scene *scene, Object *ob)
-{
- Mesh *me = ob->data;
- SculptSession *ss = ob->sculpt;
-
- enum eDynTopoWarnFlag flag = 0;
-
- BLI_assert(ss->bm == NULL);
- UNUSED_VARS_NDEBUG(ss);
-
- for (int i = 0; i < CD_NUMTYPES; i++) {
- if (!ELEM(i, CD_MVERT, CD_MEDGE, CD_MFACE, CD_MLOOP, CD_MPOLY, CD_PAINT_MASK, CD_ORIGINDEX)) {
- if (CustomData_has_layer(&me->vdata, i)) {
- flag |= DYNTOPO_WARN_VDATA;
- }
- if (CustomData_has_layer(&me->edata, i)) {
- flag |= DYNTOPO_WARN_EDATA;
- }
- if (CustomData_has_layer(&me->ldata, i)) {
- flag |= DYNTOPO_WARN_LDATA;
- }
- }
- }
-
- {
- VirtualModifierData virtualModifierData;
- ModifierData *md = modifiers_getVirtualModifierList(ob, &virtualModifierData);
-
- /* Exception for shape keys because we can edit those. */
- for (; md; md = md->next) {
- const ModifierTypeInfo *mti = modifierType_getInfo(md->type);
- if (!modifier_isEnabled(scene, md, eModifierMode_Realtime)) {
- continue;
- }
-
- if (mti->type == eModifierTypeType_Constructive) {
- flag |= DYNTOPO_WARN_MODIFIER;
- break;
- }
- }
- }
-
- return flag;
-}
-
-static int sculpt_dynamic_topology_toggle_invoke(bContext *C,
- wmOperator *op,
- const wmEvent *UNUSED(event))
-{
- Object *ob = CTX_data_active_object(C);
- SculptSession *ss = ob->sculpt;
-
- if (!ss->bm) {
- Scene *scene = CTX_data_scene(C);
- enum eDynTopoWarnFlag flag = sculpt_dynamic_topology_check(scene, ob);
-
- if (flag) {
- /* The mesh has customdata that will be lost, let the user confirm this is OK. */
- return dyntopo_warning_popup(C, op->type, flag);
- }
- }
-
- return sculpt_dynamic_topology_toggle_exec(C, op);
-}
-
-static void SCULPT_OT_dynamic_topology_toggle(wmOperatorType *ot)
-{
- /* Identifiers. */
- ot->name = "Dynamic Topology Toggle";
- ot->idname = "SCULPT_OT_dynamic_topology_toggle";
- ot->description = "Dynamic topology alters the mesh topology while sculpting";
-
- /* API callbacks. */
- ot->invoke = sculpt_dynamic_topology_toggle_invoke;
- ot->exec = sculpt_dynamic_topology_toggle_exec;
- ot->poll = SCULPT_mode_poll;
-
- ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
-}
-
/************************* SCULPT_OT_optimize *************************/
static int sculpt_optimize_exec(bContext *C, wmOperator *UNUSED(op))
{
Object *ob = CTX_data_active_object(C);
- sculpt_pbvh_clear(ob);
+ SCULPT_pbvh_clear(ob);
WM_event_add_notifier(C, NC_OBJECT | ND_DRAW, ob);
return OPERATOR_FINISHED;
}
-static bool sculpt_and_dynamic_topology_poll(bContext *C)
-{
- Object *ob = CTX_data_active_object(C);
-
- return SCULPT_mode_poll(C) && ob->sculpt->bm;
-}
-
/* The BVH gets less optimal more quickly with dynamic topology than
* regular sculpting. There is no doubt more clever stuff we can do to
* optimize it on the fly, but for now this gives the user a nicer way
@@ -8553,7 +7419,7 @@ static bool sculpt_no_multires_poll(bContext *C)
return false;
}
-static int sculpt_symmetrize_exec(bContext *C, wmOperator *UNUSED(op))
+static int sculpt_symmetrize_exec(bContext *C, wmOperator *op)
{
Object *ob = CTX_data_active_object(C);
const Sculpt *sd = CTX_data_tool_settings(C)->sculpt;
@@ -8584,7 +7450,7 @@ static int sculpt_symmetrize_exec(bContext *C, wmOperator *UNUSED(op))
"symmetrize input=%avef direction=%i dist=%f",
sd->symmetrize_direction,
0.00001f);
- sculpt_dynamic_topology_triangulate(ss->bm);
+ SCULPT_dynamic_topology_triangulate(ss->bm);
/* Bisect operator flags edges (keep tags clean for edge queue). */
BM_mesh_elem_hflag_disable_all(ss->bm, BM_EDGE, BM_ELEM_TAG, false);
@@ -8604,7 +7470,7 @@ static int sculpt_symmetrize_exec(bContext *C, wmOperator *UNUSED(op))
MirrorModifierData mmd = {{0}};
int axis = 0;
mmd.flag = 0;
- mmd.tolerance = 0.005f;
+ mmd.tolerance = RNA_float_get(op->ptr, "merge_tolerance");
switch (sd->symmetrize_direction) {
case BMO_SYMMETRIZE_NEGATIVE_X:
axis = 0;
@@ -8645,7 +7511,7 @@ static int sculpt_symmetrize_exec(bContext *C, wmOperator *UNUSED(op))
}
/* Redraw. */
- sculpt_pbvh_clear(ob);
+ SCULPT_pbvh_clear(ob);
WM_event_add_notifier(C, NC_OBJECT | ND_DRAW, ob);
return OPERATOR_FINISHED;
@@ -8661,6 +7527,16 @@ static void SCULPT_OT_symmetrize(wmOperatorType *ot)
/* API callbacks. */
ot->exec = sculpt_symmetrize_exec;
ot->poll = sculpt_no_multires_poll;
+
+ RNA_def_float(ot->srna,
+ "merge_tolerance",
+ 0.001f,
+ 0.0f,
+ FLT_MAX,
+ "Merge Limit",
+ "Distance within which symmetrical vertices are merged",
+ 0.0f,
+ 1.0f);
}
/**** Toggle operator for turning sculpt mode on or off ****/
@@ -8673,6 +7549,28 @@ static void sculpt_init_session(Depsgraph *depsgraph, Scene *scene, Object *ob)
ob->sculpt = MEM_callocN(sizeof(SculptSession), "sculpt session");
ob->sculpt->mode_type = OB_MODE_SCULPT;
BKE_sculpt_update_object_for_edit(depsgraph, ob, false, false);
+
+ /* Here we can detect geometry that was just added to Sculpt Mode as it has the
+ * SCULPT_FACE_SET_NONE assigned, so we can create a new Face Set for it. */
+ /* In sculpt mode all geometry that is assigned to SCULPT_FACE_SET_NONE is considered as not
+ * initialized, which is used is some operators that modify the mesh topology to preform certain
+ * actions in the new polys. After these operations are finished, all polys should have a valid
+ * face set ID assigned (different from SCULPT_FACE_SET_NONE) to manage their visibility
+ * correctly. */
+ /* TODO(pablodp606): Based on this we can improve the UX in future tools for creating new
+ * objects, like moving the transform pivot position to the new area or masking existing
+ * geometry. */
+ SculptSession *ss = ob->sculpt;
+ const int new_face_set = SCULPT_face_set_next_available_get(ss);
+ for (int i = 0; i < ss->totfaces; i++) {
+ if (ss->face_sets[i] == SCULPT_FACE_SET_NONE) {
+ ss->face_sets[i] = new_face_set;
+ }
+ }
+
+ /* Update the Face Sets visibility with the vertex visibility changes that may have been done
+ * outside Sculpt Mode */
+ SCULPT_visibility_sync_all_vertex_to_face_sets(ob->sculpt);
}
static int ed_object_sculptmode_flush_recalc_flag(Scene *scene,
@@ -8681,7 +7579,7 @@ static int ed_object_sculptmode_flush_recalc_flag(Scene *scene,
{
int flush_recalc = 0;
/* Multires in sculpt mode could have different from object mode subdivision level. */
- flush_recalc |= mmd && BKE_multires_sculpt_level_get(mmd) != mmd->lvl;
+ flush_recalc |= mmd && mmd->sculptlvl != mmd->lvl;
/* If object has got active modifiers, it's dm could be different in sculpt mode. */
flush_recalc |= sculpt_has_active_modifiers(scene, ob);
return flush_recalc;
@@ -8738,7 +7636,7 @@ void ED_object_sculptmode_enter_ex(Main *bmain,
Paint *paint = BKE_paint_get_active_from_paintmode(scene, PAINT_MODE_SCULPT);
BKE_paint_init(bmain, scene, PAINT_MODE_SCULPT, PAINT_CURSOR_SCULPT);
- paint_cursor_start_explicit(paint, bmain->wm.first, SCULPT_poll_view3d);
+ paint_cursor_start(paint, SCULPT_poll_view3d);
/* Check dynamic-topology flag; re-enter dynamic-topology mode when changing modes,
* As long as no data was added that is not supported. */
@@ -8751,7 +7649,7 @@ void ED_object_sculptmode_enter_ex(Main *bmain,
message_unsupported = TIP_("multi-res modifier");
}
else {
- enum eDynTopoWarnFlag flag = sculpt_dynamic_topology_check(scene, ob);
+ enum eDynTopoWarnFlag flag = SCULPT_dynamic_topology_check(scene, ob);
if (flag == 0) {
/* pass */
}
@@ -8780,7 +7678,7 @@ void ED_object_sculptmode_enter_ex(Main *bmain,
if (has_undo) {
SCULPT_undo_push_begin("Dynamic topology enable");
}
- sculpt_dynamic_topology_enable_ex(bmain, depsgraph, scene, ob);
+ SCULPT_dynamic_topology_enable_ex(bmain, depsgraph, scene, ob);
if (has_undo) {
SCULPT_undo_push_node(ob, NULL, SCULPT_UNDO_DYNTOPO_BEGIN);
SCULPT_undo_push_end();
@@ -8923,1764 +7821,6 @@ static void SCULPT_OT_sculptmode_toggle(wmOperatorType *ot)
ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
}
-static bool sculpt_and_constant_or_manual_detail_poll(bContext *C)
-{
- Object *ob = CTX_data_active_object(C);
- Sculpt *sd = CTX_data_tool_settings(C)->sculpt;
-
- return SCULPT_mode_poll(C) && ob->sculpt->bm &&
- (sd->flags & (SCULPT_DYNTOPO_DETAIL_CONSTANT | SCULPT_DYNTOPO_DETAIL_MANUAL));
-}
-
-static int sculpt_detail_flood_fill_exec(bContext *C, wmOperator *UNUSED(op))
-{
- Sculpt *sd = CTX_data_tool_settings(C)->sculpt;
- Object *ob = CTX_data_active_object(C);
- SculptSession *ss = ob->sculpt;
- float size;
- float bb_min[3], bb_max[3], center[3], dim[3];
- int totnodes;
- PBVHNode **nodes;
-
- BKE_pbvh_search_gather(ss->pbvh, NULL, NULL, &nodes, &totnodes);
-
- if (!totnodes) {
- return OPERATOR_CANCELLED;
- }
-
- for (int i = 0; i < totnodes; i++) {
- BKE_pbvh_node_mark_topology_update(nodes[i]);
- }
- /* Get the bounding box, it's center and size. */
- BKE_pbvh_bounding_box(ob->sculpt->pbvh, bb_min, bb_max);
- add_v3_v3v3(center, bb_min, bb_max);
- mul_v3_fl(center, 0.5f);
- sub_v3_v3v3(dim, bb_max, bb_min);
- size = max_fff(dim[0], dim[1], dim[2]);
-
- /* Update topology size. */
- float object_space_constant_detail = 1.0f / (sd->constant_detail * mat4_to_scale(ob->obmat));
- BKE_pbvh_bmesh_detail_size_set(ss->pbvh, object_space_constant_detail);
-
- SCULPT_undo_push_begin("Dynamic topology flood fill");
- SCULPT_undo_push_node(ob, NULL, SCULPT_UNDO_COORDS);
-
- while (BKE_pbvh_bmesh_update_topology(
- ss->pbvh, PBVH_Collapse | PBVH_Subdivide, center, NULL, size, false, false)) {
- for (int i = 0; i < totnodes; i++) {
- BKE_pbvh_node_mark_topology_update(nodes[i]);
- }
- }
-
- MEM_SAFE_FREE(nodes);
- SCULPT_undo_push_end();
-
- /* Force rebuild of pbvh for better BB placement. */
- sculpt_pbvh_clear(ob);
- /* Redraw. */
- WM_event_add_notifier(C, NC_OBJECT | ND_DRAW, ob);
-
- return OPERATOR_FINISHED;
-}
-
-static void SCULPT_OT_detail_flood_fill(wmOperatorType *ot)
-{
- /* Identifiers. */
- ot->name = "Detail Flood Fill";
- ot->idname = "SCULPT_OT_detail_flood_fill";
- ot->description = "Flood fill the mesh with the selected detail setting";
-
- /* API callbacks. */
- ot->exec = sculpt_detail_flood_fill_exec;
- ot->poll = sculpt_and_constant_or_manual_detail_poll;
-
- ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
-}
-
-typedef enum eSculptSampleDetailModeTypes {
- SAMPLE_DETAIL_DYNTOPO = 0,
- SAMPLE_DETAIL_VOXEL = 1,
-} eSculptSampleDetailModeTypes;
-
-static EnumPropertyItem prop_sculpt_sample_detail_mode_types[] = {
- {SAMPLE_DETAIL_DYNTOPO, "DYNTOPO", 0, "Dyntopo", "Sample dyntopo detail"},
- {SAMPLE_DETAIL_VOXEL, "VOXEL", 0, "Voxel", "Sample mesh voxel size"},
- {0, NULL, 0, NULL, NULL},
-};
-
-static void sample_detail_voxel(bContext *C, ViewContext *vc, int mx, int my)
-{
- Depsgraph *depsgraph = CTX_data_depsgraph_pointer(C);
- Object *ob = vc->obact;
- Mesh *mesh = ob->data;
-
- SculptSession *ss = ob->sculpt;
- SculptCursorGeometryInfo sgi;
- SCULPT_vertex_random_access_init(ss);
-
- /* Update the active vertex. */
- float mouse[2] = {mx, my};
- SCULPT_cursor_geometry_info_update(C, &sgi, mouse, false);
- BKE_sculpt_update_object_for_edit(depsgraph, ob, true, false);
-
- /* Average the edge length of the connected edges to the active vertex. */
- int active_vertex = SCULPT_active_vertex_get(ss);
- const float *active_vertex_co = SCULPT_active_vertex_co_get(ss);
- float edge_length = 0.0f;
- int tot = 0;
- SculptVertexNeighborIter ni;
- sculpt_vertex_neighbors_iter_begin(ss, active_vertex, ni)
- {
- edge_length += len_v3v3(active_vertex_co, SCULPT_vertex_co_get(ss, ni.index));
- tot += 1;
- }
- sculpt_vertex_neighbors_iter_end(ni);
- if (tot > 0) {
- mesh->remesh_voxel_size = edge_length / (float)tot;
- }
-}
-
-static void sample_detail_dyntopo(bContext *C, ViewContext *vc, ARegion *region, int mx, int my)
-{
- Sculpt *sd = CTX_data_tool_settings(C)->sculpt;
- Object *ob = vc->obact;
- Brush *brush = BKE_paint_brush(&sd->paint);
-
- sculpt_stroke_modifiers_check(C, ob, brush);
-
- float mouse[2] = {mx - region->winrct.xmin, my - region->winrct.ymin};
- float ray_start[3], ray_end[3], ray_normal[3];
- float depth = sculpt_raycast_init(vc, mouse, ray_start, ray_end, ray_normal, false);
-
- SculptDetailRaycastData srd;
- srd.hit = 0;
- srd.ray_start = ray_start;
- srd.depth = depth;
- srd.edge_length = 0.0f;
- isect_ray_tri_watertight_v3_precalc(&srd.isect_precalc, ray_normal);
-
- BKE_pbvh_raycast(ob->sculpt->pbvh, sculpt_raycast_detail_cb, &srd, ray_start, ray_normal, false);
-
- if (srd.hit && srd.edge_length > 0.0f) {
- /* Convert edge length to world space detail resolution. */
- sd->constant_detail = 1 / (srd.edge_length * mat4_to_scale(ob->obmat));
- }
-}
-
-static int sample_detail(bContext *C, int mx, int my, int mode)
-{
- /* Find 3D view to pick from. */
- bScreen *screen = CTX_wm_screen(C);
- ScrArea *sa = BKE_screen_find_area_xy(screen, SPACE_VIEW3D, mx, my);
- ARegion *region = (sa) ? BKE_area_find_region_xy(sa, RGN_TYPE_WINDOW, mx, my) : NULL;
- if (region == NULL) {
- return OPERATOR_CANCELLED;
- }
-
- /* Set context to 3D view. */
- ScrArea *prev_sa = CTX_wm_area(C);
- ARegion *prev_ar = CTX_wm_region(C);
- CTX_wm_area_set(C, sa);
- CTX_wm_region_set(C, region);
-
- Depsgraph *depsgraph = CTX_data_ensure_evaluated_depsgraph(C);
- ViewContext vc;
- ED_view3d_viewcontext_init(C, &vc, depsgraph);
-
- Object *ob = vc.obact;
- SculptSession *ss = ob->sculpt;
-
- if (!ss->pbvh) {
- return OPERATOR_CANCELLED;
- }
-
- /* Pick sample detail. */
- switch (mode) {
- case SAMPLE_DETAIL_DYNTOPO:
- if (BKE_pbvh_type(ss->pbvh) != PBVH_BMESH) {
- CTX_wm_area_set(C, prev_sa);
- CTX_wm_region_set(C, prev_ar);
- return OPERATOR_CANCELLED;
- }
- sample_detail_dyntopo(C, &vc, region, mx, my);
- break;
- case SAMPLE_DETAIL_VOXEL:
- if (BKE_pbvh_type(ss->pbvh) != PBVH_FACES) {
- CTX_wm_area_set(C, prev_sa);
- CTX_wm_region_set(C, prev_ar);
- return OPERATOR_CANCELLED;
- }
- sample_detail_voxel(C, &vc, mx, my);
- break;
- }
-
- /* Restore context. */
- CTX_wm_area_set(C, prev_sa);
- CTX_wm_region_set(C, prev_ar);
-
- return OPERATOR_FINISHED;
-}
-
-static int sculpt_sample_detail_size_exec(bContext *C, wmOperator *op)
-{
- int ss_co[2];
- RNA_int_get_array(op->ptr, "location", ss_co);
- int mode = RNA_enum_get(op->ptr, "mode");
- return sample_detail(C, ss_co[0], ss_co[1], mode);
-}
-
-static int sculpt_sample_detail_size_invoke(bContext *C, wmOperator *op, const wmEvent *UNUSED(e))
-{
- ED_workspace_status_text(C, TIP_("Click on the mesh to set the detail"));
- WM_cursor_modal_set(CTX_wm_window(C), WM_CURSOR_EYEDROPPER);
- WM_event_add_modal_handler(C, op);
- return OPERATOR_RUNNING_MODAL;
-}
-
-static int sculpt_sample_detail_size_modal(bContext *C, wmOperator *op, const wmEvent *event)
-{
- switch (event->type) {
- case LEFTMOUSE:
- if (event->val == KM_PRESS) {
- int ss_co[2] = {event->x, event->y};
-
- int mode = RNA_enum_get(op->ptr, "mode");
- sample_detail(C, ss_co[0], ss_co[1], mode);
-
- RNA_int_set_array(op->ptr, "location", ss_co);
- WM_cursor_modal_restore(CTX_wm_window(C));
- ED_workspace_status_text(C, NULL);
- WM_main_add_notifier(NC_SCENE | ND_TOOLSETTINGS, NULL);
-
- return OPERATOR_FINISHED;
- }
- break;
-
- case RIGHTMOUSE: {
- WM_cursor_modal_restore(CTX_wm_window(C));
- ED_workspace_status_text(C, NULL);
-
- return OPERATOR_CANCELLED;
- }
- }
-
- return OPERATOR_RUNNING_MODAL;
-}
-
-static void SCULPT_OT_sample_detail_size(wmOperatorType *ot)
-{
- /* Identifiers. */
- ot->name = "Sample Detail Size";
- ot->idname = "SCULPT_OT_sample_detail_size";
- ot->description = "Sample the mesh detail on clicked point";
-
- /* API callbacks. */
- ot->invoke = sculpt_sample_detail_size_invoke;
- ot->exec = sculpt_sample_detail_size_exec;
- ot->modal = sculpt_sample_detail_size_modal;
- ot->poll = SCULPT_mode_poll;
-
- ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
-
- RNA_def_int_array(ot->srna,
- "location",
- 2,
- NULL,
- 0,
- SHRT_MAX,
- "Location",
- "Screen Coordinates of sampling",
- 0,
- SHRT_MAX);
- RNA_def_enum(ot->srna,
- "mode",
- prop_sculpt_sample_detail_mode_types,
- SAMPLE_DETAIL_DYNTOPO,
- "Detail Mode",
- "Target sculpting workflow that is going to use the sampled size");
-}
-
-/* Dynamic-topology detail size.
- *
- * This should be improved further, perhaps by showing a triangle
- * grid rather than brush alpha. */
-static void set_brush_rc_props(PointerRNA *ptr, const char *prop)
-{
- char *path = BLI_sprintfN("tool_settings.sculpt.brush.%s", prop);
- RNA_string_set(ptr, "data_path_primary", path);
- MEM_freeN(path);
-}
-
-static int sculpt_set_detail_size_exec(bContext *C, wmOperator *UNUSED(op))
-{
- Sculpt *sd = CTX_data_tool_settings(C)->sculpt;
-
- PointerRNA props_ptr;
- wmOperatorType *ot = WM_operatortype_find("WM_OT_radial_control", true);
-
- WM_operator_properties_create_ptr(&props_ptr, ot);
-
- if (sd->flags & (SCULPT_DYNTOPO_DETAIL_CONSTANT | SCULPT_DYNTOPO_DETAIL_MANUAL)) {
- set_brush_rc_props(&props_ptr, "constant_detail_resolution");
- RNA_string_set(
- &props_ptr, "data_path_primary", "tool_settings.sculpt.constant_detail_resolution");
- }
- else if (sd->flags & SCULPT_DYNTOPO_DETAIL_BRUSH) {
- set_brush_rc_props(&props_ptr, "constant_detail_resolution");
- RNA_string_set(&props_ptr, "data_path_primary", "tool_settings.sculpt.detail_percent");
- }
- else {
- set_brush_rc_props(&props_ptr, "detail_size");
- RNA_string_set(&props_ptr, "data_path_primary", "tool_settings.sculpt.detail_size");
- }
-
- WM_operator_name_call_ptr(C, ot, WM_OP_INVOKE_DEFAULT, &props_ptr);
-
- WM_operator_properties_free(&props_ptr);
-
- return OPERATOR_FINISHED;
-}
-
-static void SCULPT_OT_set_detail_size(wmOperatorType *ot)
-{
- /* Identifiers. */
- ot->name = "Set Detail Size";
- ot->idname = "SCULPT_OT_set_detail_size";
- ot->description =
- "Set the mesh detail (either relative or constant one, depending on current dyntopo mode)";
-
- /* API callbacks. */
- ot->exec = sculpt_set_detail_size_exec;
- ot->poll = sculpt_and_dynamic_topology_poll;
-
- ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
-}
-static void filter_cache_init_task_cb(void *__restrict userdata,
- const int i,
- const TaskParallelTLS *__restrict UNUSED(tls))
-{
- SculptThreadedTaskData *data = userdata;
- PBVHNode *node = data->nodes[i];
-
- SCULPT_undo_push_node(data->ob, node, SCULPT_UNDO_COORDS);
-}
-
-static void sculpt_filter_cache_init(Object *ob, Sculpt *sd)
-{
- SculptSession *ss = ob->sculpt;
- PBVH *pbvh = ob->sculpt->pbvh;
-
- ss->filter_cache = MEM_callocN(sizeof(FilterCache), "filter cache");
-
- ss->filter_cache->random_seed = rand();
-
- float center[3] = {0.0f};
- SculptSearchSphereData search_data = {
- .original = true,
- .center = center,
- .radius_squared = FLT_MAX,
- .ignore_fully_masked = true,
-
- };
- BKE_pbvh_search_gather(pbvh,
- SCULPT_search_sphere_cb,
- &search_data,
- &ss->filter_cache->nodes,
- &ss->filter_cache->totnode);
-
- for (int i = 0; i < ss->filter_cache->totnode; i++) {
- BKE_pbvh_node_mark_normals_update(ss->filter_cache->nodes[i]);
- }
-
- /* mesh->runtime.subdiv_ccg is not available. Updating of the normals is done during drawing.
- * Filters can't use normals in multires. */
- if (BKE_pbvh_type(ss->pbvh) != PBVH_GRIDS) {
- BKE_pbvh_update_normals(ss->pbvh, NULL);
- }
-
- SculptThreadedTaskData data = {
- .sd = sd,
- .ob = ob,
- .nodes = ss->filter_cache->nodes,
- };
-
- PBVHParallelSettings settings;
- BKE_pbvh_parallel_range_settings(
- &settings, (sd->flags & SCULPT_USE_OPENMP), ss->filter_cache->totnode);
- BKE_pbvh_parallel_range(
- 0, ss->filter_cache->totnode, &data, filter_cache_init_task_cb, &settings);
-}
-
-static void sculpt_filter_cache_free(SculptSession *ss)
-{
- if (ss->filter_cache->nodes) {
- MEM_freeN(ss->filter_cache->nodes);
- }
- if (ss->filter_cache->mask_update_it) {
- MEM_freeN(ss->filter_cache->mask_update_it);
- }
- if (ss->filter_cache->prev_mask) {
- MEM_freeN(ss->filter_cache->prev_mask);
- }
- if (ss->filter_cache->normal_factor) {
- MEM_freeN(ss->filter_cache->normal_factor);
- }
- if (ss->filter_cache->prev_face_set) {
- MEM_freeN(ss->filter_cache->prev_face_set);
- }
- if (ss->filter_cache->automask) {
- MEM_freeN(ss->filter_cache->automask);
- }
- if (ss->filter_cache->surface_smooth_laplacian_disp) {
- MEM_freeN(ss->filter_cache->surface_smooth_laplacian_disp);
- }
- MEM_freeN(ss->filter_cache);
- ss->filter_cache = NULL;
-}
-
-typedef enum eSculptMeshFilterTypes {
- MESH_FILTER_SMOOTH = 0,
- MESH_FILTER_SCALE = 1,
- MESH_FILTER_INFLATE = 2,
- MESH_FILTER_SPHERE = 3,
- MESH_FILTER_RANDOM = 4,
- MESH_FILTER_RELAX = 5,
- MESH_FILTER_RELAX_FACE_SETS = 6,
- MESH_FILTER_SURFACE_SMOOTH = 7,
-} eSculptMeshFilterTypes;
-
-static EnumPropertyItem prop_mesh_filter_types[] = {
- {MESH_FILTER_SMOOTH, "SMOOTH", 0, "Smooth", "Smooth mesh"},
- {MESH_FILTER_SCALE, "SCALE", 0, "Scale", "Scale mesh"},
- {MESH_FILTER_INFLATE, "INFLATE", 0, "Inflate", "Inflate mesh"},
- {MESH_FILTER_SPHERE, "SPHERE", 0, "Sphere", "Morph into sphere"},
- {MESH_FILTER_RANDOM, "RANDOM", 0, "Random", "Randomize vertex positions"},
- {MESH_FILTER_RELAX, "RELAX", 0, "Relax", "Relax mesh"},
- {MESH_FILTER_RELAX_FACE_SETS,
- "RELAX_FACE_SETS",
- 0,
- "Relax Face Sets",
- "Smooth the edges of all the Face Sets"},
- {MESH_FILTER_SURFACE_SMOOTH,
- "SURFACE_SMOOTH",
- 0,
- "Surface Smooth",
- "Smooth the surface of the mesh, preserving the volume"},
- {0, NULL, 0, NULL, NULL},
-};
-
-typedef enum eMeshFilterDeformAxis {
- MESH_FILTER_DEFORM_X = 1 << 0,
- MESH_FILTER_DEFORM_Y = 1 << 1,
- MESH_FILTER_DEFORM_Z = 1 << 2,
-} eMeshFilterDeformAxis;
-
-static EnumPropertyItem prop_mesh_filter_deform_axis_items[] = {
- {MESH_FILTER_DEFORM_X, "X", 0, "X", "Deform in the X axis"},
- {MESH_FILTER_DEFORM_Y, "Y", 0, "Y", "Deform in the Y axis"},
- {MESH_FILTER_DEFORM_Z, "Z", 0, "Z", "Deform in the Z axis"},
- {0, NULL, 0, NULL, NULL},
-};
-
-static bool sculpt_mesh_filter_needs_pmap(int filter_type, bool use_face_sets)
-{
- return use_face_sets || ELEM(filter_type,
- MESH_FILTER_SMOOTH,
- MESH_FILTER_RELAX,
- MESH_FILTER_RELAX_FACE_SETS,
- MESH_FILTER_SURFACE_SMOOTH);
-}
-
-static void mesh_filter_task_cb(void *__restrict userdata,
- const int i,
- const TaskParallelTLS *__restrict UNUSED(tls))
-{
- SculptThreadedTaskData *data = userdata;
- SculptSession *ss = data->ob->sculpt;
- PBVHNode *node = data->nodes[i];
-
- const int filter_type = data->filter_type;
-
- SculptOrigVertData orig_data;
- SCULPT_orig_vert_data_init(&orig_data, data->ob, data->nodes[i]);
-
- /* When using the relax face sets mehs filter, each 3 iterations, do a whole mesh relax to smooth
- * the contents of the Face Set. */
- /* This produces better results as the relax operation is no completely focused on the
- * boundaries. */
- const bool relax_face_sets = !(ss->filter_cache->iteration_count % 3 == 0);
-
- PBVHVertexIter vd;
- BKE_pbvh_vertex_iter_begin(ss->pbvh, node, vd, PBVH_ITER_UNIQUE)
- {
- SCULPT_orig_vert_data_update(&orig_data, &vd);
- float orig_co[3], val[3], avg[3], normal[3], disp[3], disp2[3], transform[3][3], final_pos[3];
- float fade = vd.mask ? *vd.mask : 0.0f;
- fade = 1.0f - fade;
- fade *= data->filter_strength;
-
- if (fade == 0.0f) {
- continue;
- }
-
- if (ss->filter_cache->active_face_set != SCULPT_FACE_SET_NONE) {
- if (!SCULPT_vertex_has_face_set(ss, vd.index, ss->filter_cache->active_face_set)) {
- continue;
- }
- /* Skip the edges of the face set when relaxing or smoothing. There is a relax face set
- * option to relax the boindaries independently. */
- if (filter_type == MESH_FILTER_RELAX) {
- if (!sculpt_vertex_has_unique_face_set(ss, vd.index)) {
- continue;
- }
- }
- }
-
- if (ELEM(filter_type, MESH_FILTER_RELAX, MESH_FILTER_RELAX_FACE_SETS)) {
- copy_v3_v3(orig_co, vd.co);
- }
- else {
- copy_v3_v3(orig_co, orig_data.co);
- }
-
- if (filter_type == MESH_FILTER_RELAX_FACE_SETS) {
- if (relax_face_sets == sculpt_vertex_has_unique_face_set(ss, vd.index)) {
- continue;
- }
- }
-
- switch (filter_type) {
- case MESH_FILTER_SMOOTH:
- CLAMP(fade, -1.0f, 1.0f);
- switch (BKE_pbvh_type(ss->pbvh)) {
- case PBVH_FACES:
- neighbor_average(ss, avg, vd.index);
- break;
- case PBVH_BMESH:
- bmesh_neighbor_average(avg, vd.bm_vert);
- break;
- case PBVH_GRIDS:
- SCULPT_neighbor_coords_average(ss, avg, vd.index);
- break;
- }
- sub_v3_v3v3(val, avg, orig_co);
- madd_v3_v3v3fl(val, orig_co, val, fade);
- sub_v3_v3v3(disp, val, orig_co);
- break;
- case MESH_FILTER_INFLATE:
- normal_short_to_float_v3(normal, orig_data.no);
- mul_v3_v3fl(disp, normal, fade);
- break;
- case MESH_FILTER_SCALE:
- unit_m3(transform);
- scale_m3_fl(transform, 1.0f + fade);
- copy_v3_v3(val, orig_co);
- mul_m3_v3(transform, val);
- sub_v3_v3v3(disp, val, orig_co);
- break;
- case MESH_FILTER_SPHERE:
- normalize_v3_v3(disp, orig_co);
- if (fade > 0.0f) {
- mul_v3_v3fl(disp, disp, fade);
- }
- else {
- mul_v3_v3fl(disp, disp, -fade);
- }
-
- unit_m3(transform);
- if (fade > 0.0f) {
- scale_m3_fl(transform, 1.0f - fade);
- }
- else {
- scale_m3_fl(transform, 1.0f + fade);
- }
- copy_v3_v3(val, orig_co);
- mul_m3_v3(transform, val);
- sub_v3_v3v3(disp2, val, orig_co);
-
- mid_v3_v3v3(disp, disp, disp2);
- break;
- case MESH_FILTER_RANDOM: {
- normal_short_to_float_v3(normal, orig_data.no);
- /* Index is not unique for multires, so hash by vertex coordinates. */
- const uint *hash_co = (const uint *)orig_co;
- const uint hash = BLI_hash_int_2d(hash_co[0], hash_co[1]) ^
- BLI_hash_int_2d(hash_co[2], ss->filter_cache->random_seed);
- mul_v3_fl(normal, hash * (1.0f / (float)0xFFFFFFFF) - 0.5f);
- mul_v3_v3fl(disp, normal, fade);
- break;
- }
- case MESH_FILTER_RELAX: {
- SCULPT_relax_vertex(
- ss, &vd, clamp_f(fade * ss->filter_cache->automask[vd.index], 0.0f, 1.0f), false, val);
- sub_v3_v3v3(disp, val, vd.co);
- break;
- }
- case MESH_FILTER_RELAX_FACE_SETS: {
- SCULPT_relax_vertex(ss, &vd, clamp_f(fade, 0.0f, 1.0f), relax_face_sets, val);
- sub_v3_v3v3(disp, val, vd.co);
- break;
- }
- case MESH_FILTER_SURFACE_SMOOTH: {
- surface_smooth_laplacian_step(ss,
- disp,
- vd.co,
- ss->filter_cache->surface_smooth_laplacian_disp,
- vd.index,
- orig_data.co,
- ss->filter_cache->surface_smooth_shape_preservation);
- break;
- }
- }
-
- for (int it = 0; it < 3; it++) {
- if (!ss->filter_cache->enabled_axis[it]) {
- disp[it] = 0.0f;
- }
- }
-
- if (filter_type == MESH_FILTER_SURFACE_SMOOTH) {
- madd_v3_v3v3fl(final_pos, vd.co, disp, clamp_f(fade, 0.0f, 1.0f));
- }
- else {
- add_v3_v3v3(final_pos, orig_co, disp);
- }
- copy_v3_v3(vd.co, final_pos);
- if (vd.mvert) {
- vd.mvert->flag |= ME_VERT_PBVH_UPDATE;
- }
- }
- BKE_pbvh_vertex_iter_end;
-
- BKE_pbvh_node_mark_update(node);
-}
-
-static void mesh_filter_surface_smooth_displace_task_cb(
- void *__restrict userdata, const int i, const TaskParallelTLS *__restrict UNUSED(tls))
-{
- SculptThreadedTaskData *data = userdata;
- SculptSession *ss = data->ob->sculpt;
- PBVHNode *node = data->nodes[i];
- PBVHVertexIter vd;
-
- BKE_pbvh_vertex_iter_begin(ss->pbvh, node, vd, PBVH_ITER_UNIQUE)
- {
- float fade = vd.mask ? *vd.mask : 0.0f;
- fade = 1.0f - fade;
- fade *= data->filter_strength;
- if (fade == 0.0f) {
- continue;
- }
- surface_smooth_displace_step(ss,
- vd.co,
- ss->filter_cache->surface_smooth_laplacian_disp,
- vd.index,
- ss->filter_cache->surface_smooth_current_vertex,
- clamp_f(fade, 0.0f, 1.0f));
- }
- BKE_pbvh_vertex_iter_end;
-}
-
-static int sculpt_mesh_filter_modal(bContext *C, wmOperator *op, const wmEvent *event)
-{
- Object *ob = CTX_data_active_object(C);
- Depsgraph *depsgraph = CTX_data_depsgraph_pointer(C);
- SculptSession *ss = ob->sculpt;
- Sculpt *sd = CTX_data_tool_settings(C)->sculpt;
- int filter_type = RNA_enum_get(op->ptr, "type");
- float filter_strength = RNA_float_get(op->ptr, "strength");
- const bool use_face_sets = RNA_boolean_get(op->ptr, "use_face_sets");
-
- if (event->type == LEFTMOUSE && event->val == KM_RELEASE) {
- sculpt_filter_cache_free(ss);
- SCULPT_undo_push_end();
- sculpt_flush_update_done(C, ob, SCULPT_UPDATE_COORDS);
- return OPERATOR_FINISHED;
- }
-
- if (event->type != MOUSEMOVE) {
- return OPERATOR_RUNNING_MODAL;
- }
-
- float len = event->prevclickx - event->mval[0];
- filter_strength = filter_strength * -len * 0.001f * UI_DPI_FAC;
-
- SCULPT_vertex_random_access_init(ss);
-
- bool needs_pmap = sculpt_mesh_filter_needs_pmap(filter_type, use_face_sets);
- BKE_sculpt_update_object_for_edit(depsgraph, ob, needs_pmap, false);
-
- SculptThreadedTaskData data = {
- .sd = sd,
- .ob = ob,
- .nodes = ss->filter_cache->nodes,
- .filter_type = filter_type,
- .filter_strength = filter_strength,
- };
-
- PBVHParallelSettings settings;
- BKE_pbvh_parallel_range_settings(
- &settings, (sd->flags & SCULPT_USE_OPENMP), ss->filter_cache->totnode);
- BKE_pbvh_parallel_range(0, ss->filter_cache->totnode, &data, mesh_filter_task_cb, &settings);
-
- if (filter_type == MESH_FILTER_SURFACE_SMOOTH) {
- BKE_pbvh_parallel_range(0,
- ss->filter_cache->totnode,
- &data,
- mesh_filter_surface_smooth_displace_task_cb,
- &settings);
- }
-
- ss->filter_cache->iteration_count++;
-
- if (ss->deform_modifiers_active || ss->shapekey_active) {
- sculpt_flush_stroke_deform(sd, ob, true);
- }
-
- /* The relax mesh filter needs the updated normals of the modified mesh after each iteration. */
- if (ELEM(MESH_FILTER_RELAX, MESH_FILTER_RELAX_FACE_SETS)) {
- BKE_pbvh_update_normals(ss->pbvh, ss->subdiv_ccg);
- }
-
- sculpt_flush_update_step(C, SCULPT_UPDATE_COORDS);
-
- return OPERATOR_RUNNING_MODAL;
-}
-
-static int sculpt_mesh_filter_invoke(bContext *C, wmOperator *op, const wmEvent *event)
-{
- Object *ob = CTX_data_active_object(C);
- Depsgraph *depsgraph = CTX_data_depsgraph_pointer(C);
- Sculpt *sd = CTX_data_tool_settings(C)->sculpt;
- int filter_type = RNA_enum_get(op->ptr, "type");
- SculptSession *ss = ob->sculpt;
- PBVH *pbvh = ob->sculpt->pbvh;
-
- int deform_axis = RNA_enum_get(op->ptr, "deform_axis");
- if (deform_axis == 0) {
- return OPERATOR_CANCELLED;
- }
-
- if (RNA_boolean_get(op->ptr, "use_face_sets")) {
- /* Update the active vertex */
- float mouse[2];
- SculptCursorGeometryInfo sgi;
- mouse[0] = event->mval[0];
- mouse[1] = event->mval[1];
- SCULPT_cursor_geometry_info_update(C, &sgi, mouse, false);
- }
-
- const bool use_face_sets = RNA_boolean_get(op->ptr, "use_face_sets");
-
- SCULPT_vertex_random_access_init(ss);
-
- bool needs_pmap = sculpt_mesh_filter_needs_pmap(filter_type, use_face_sets);
- BKE_sculpt_update_object_for_edit(depsgraph, ob, needs_pmap, false);
-
- if (BKE_pbvh_type(pbvh) == PBVH_FACES && needs_pmap && !ob->sculpt->pmap) {
- return OPERATOR_CANCELLED;
- }
-
- SCULPT_undo_push_begin("Mesh filter");
-
- sculpt_filter_cache_init(ob, sd);
-
- if (use_face_sets) {
- ss->filter_cache->active_face_set = SCULPT_vertex_face_set_get(ss,
- SCULPT_active_vertex_get(ss));
- }
- else {
- ss->filter_cache->active_face_set = SCULPT_FACE_SET_NONE;
- }
-
- if (RNA_enum_get(op->ptr, "type") == MESH_FILTER_SURFACE_SMOOTH) {
- ss->filter_cache->surface_smooth_laplacian_disp = MEM_mallocN(
- 3 * sizeof(float) * SCULPT_vertex_count_get(ss), "surface smooth disp");
- ss->filter_cache->surface_smooth_shape_preservation = RNA_float_get(
- op->ptr, "surface_smooth_shape_preservation");
- ss->filter_cache->surface_smooth_current_vertex = RNA_float_get(
- op->ptr, "surface_smooth_current_vertex");
- }
-
- ss->filter_cache->enabled_axis[0] = deform_axis & MESH_FILTER_DEFORM_X;
- ss->filter_cache->enabled_axis[1] = deform_axis & MESH_FILTER_DEFORM_Y;
- ss->filter_cache->enabled_axis[2] = deform_axis & MESH_FILTER_DEFORM_Z;
-
- if (RNA_enum_get(op->ptr, "type") == MESH_FILTER_RELAX) {
- const int totvert = SCULPT_vertex_count_get(ss);
- ss->filter_cache->automask = MEM_mallocN(totvert * sizeof(float),
- "Relax filter edge automask");
- for (int i = 0; i < totvert; i++) {
- ss->filter_cache->automask[i] = 1.0f;
- }
- sculpt_boundary_edges_automasking_init(ob, 1, ss->filter_cache->automask);
- }
-
- WM_event_add_modal_handler(C, op);
- return OPERATOR_RUNNING_MODAL;
-}
-
-static void SCULPT_OT_mesh_filter(struct wmOperatorType *ot)
-{
- /* Identifiers. */
- ot->name = "Filter mesh";
- ot->idname = "SCULPT_OT_mesh_filter";
- ot->description = "Applies a filter to modify the current mesh";
-
- /* API callbacks. */
- ot->invoke = sculpt_mesh_filter_invoke;
- ot->modal = sculpt_mesh_filter_modal;
- ot->poll = SCULPT_mode_poll;
-
- ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
-
- /* RNA. */
- RNA_def_enum(ot->srna,
- "type",
- prop_mesh_filter_types,
- MESH_FILTER_INFLATE,
- "Filter type",
- "Operation that is going to be applied to the mesh");
- RNA_def_float(
- ot->srna, "strength", 1.0f, -10.0f, 10.0f, "Strength", "Filter Strength", -10.0f, 10.0f);
- RNA_def_enum_flag(ot->srna,
- "deform_axis",
- prop_mesh_filter_deform_axis_items,
- MESH_FILTER_DEFORM_X | MESH_FILTER_DEFORM_Y | MESH_FILTER_DEFORM_Z,
- "Deform axis",
- "Apply the deformation in the selected axis");
- ot->prop = RNA_def_boolean(ot->srna,
- "use_face_sets",
- false,
- "Use Face Sets",
- "Apply the filter only to the Face Mask under the cursor");
-
- /* Surface Smooth Mesh Filter properties. */
- RNA_def_float(ot->srna,
- "surface_smooth_shape_preservation",
- 0.5f,
- 0.0f,
- 1.0f,
- "Shape Preservation",
- "How much of the original shape is preserved when smoothing",
- 0.0f,
- 1.0f);
- RNA_def_float(ot->srna,
- "surface_smooth_current_vertex",
- 0.5f,
- 0.0f,
- 1.0f,
- "Per Vertex Displacement",
- "How much the position of each individual vertex influences the final result",
- 0.0f,
- 1.0f);
-}
-
-typedef enum eSculptMaskFilterTypes {
- MASK_FILTER_SMOOTH = 0,
- MASK_FILTER_SHARPEN = 1,
- MASK_FILTER_GROW = 2,
- MASK_FILTER_SHRINK = 3,
- MASK_FILTER_CONTRAST_INCREASE = 5,
- MASK_FILTER_CONTRAST_DECREASE = 6,
-} eSculptMaskFilterTypes;
-
-static EnumPropertyItem prop_mask_filter_types[] = {
- {MASK_FILTER_SMOOTH, "SMOOTH", 0, "Smooth Mask", "Smooth mask"},
- {MASK_FILTER_SHARPEN, "SHARPEN", 0, "Sharpen Mask", "Sharpen mask"},
- {MASK_FILTER_GROW, "GROW", 0, "Grow Mask", "Grow mask"},
- {MASK_FILTER_SHRINK, "SHRINK", 0, "Shrink Mask", "Shrink mask"},
- {MASK_FILTER_CONTRAST_INCREASE,
- "CONTRAST_INCREASE",
- 0,
- "Increase contrast",
- "Increase the contrast of the paint mask"},
- {MASK_FILTER_CONTRAST_DECREASE,
- "CONTRAST_DECREASE",
- 0,
- "Decrease contrast",
- "Decrease the contrast of the paint mask"},
- {0, NULL, 0, NULL, NULL},
-};
-
-static void mask_filter_task_cb(void *__restrict userdata,
- const int i,
- const TaskParallelTLS *__restrict UNUSED(tls))
-{
- SculptThreadedTaskData *data = userdata;
- SculptSession *ss = data->ob->sculpt;
- PBVHNode *node = data->nodes[i];
- bool update = false;
-
- const int mode = data->filter_type;
- float contrast = 0.0f;
-
- PBVHVertexIter vd;
-
- if (mode == MASK_FILTER_CONTRAST_INCREASE) {
- contrast = 0.1f;
- }
-
- if (mode == MASK_FILTER_CONTRAST_DECREASE) {
- contrast = -0.1f;
- }
-
- BKE_pbvh_vertex_iter_begin(ss->pbvh, node, vd, PBVH_ITER_UNIQUE)
- {
- float delta, gain, offset, max, min;
- float prev_val = *vd.mask;
- SculptVertexNeighborIter ni;
- switch (mode) {
- case MASK_FILTER_SMOOTH:
- case MASK_FILTER_SHARPEN: {
- float val = 0.0f;
-
- switch (BKE_pbvh_type(ss->pbvh)) {
- case PBVH_FACES:
- val = neighbor_average_mask(ss, vd.index);
- break;
- case PBVH_BMESH:
- val = bmesh_neighbor_average_mask(vd.bm_vert, vd.cd_vert_mask_offset);
- break;
- case PBVH_GRIDS:
- val = grids_neighbor_average_mask(ss, vd.index);
- break;
- }
-
- val -= *vd.mask;
-
- if (mode == MASK_FILTER_SMOOTH) {
- *vd.mask += val;
- }
- else if (mode == MASK_FILTER_SHARPEN) {
- if (*vd.mask > 0.5f) {
- *vd.mask += 0.05f;
- }
- else {
- *vd.mask -= 0.05f;
- }
- *vd.mask += val / 2.0f;
- }
- break;
- }
- case MASK_FILTER_GROW:
- max = 0.0f;
- sculpt_vertex_neighbors_iter_begin(ss, vd.index, ni)
- {
- float vmask_f = data->prev_mask[ni.index];
- if (vmask_f > max) {
- max = vmask_f;
- }
- }
- sculpt_vertex_neighbors_iter_end(ni);
- *vd.mask = max;
- break;
- case MASK_FILTER_SHRINK:
- min = 1.0f;
- sculpt_vertex_neighbors_iter_begin(ss, vd.index, ni)
- {
- float vmask_f = data->prev_mask[ni.index];
- if (vmask_f < min) {
- min = vmask_f;
- }
- }
- sculpt_vertex_neighbors_iter_end(ni);
- *vd.mask = min;
- break;
- case MASK_FILTER_CONTRAST_INCREASE:
- case MASK_FILTER_CONTRAST_DECREASE:
- delta = contrast / 2.0f;
- gain = 1.0f - delta * 2.0f;
- if (contrast > 0) {
- gain = 1.0f / ((gain != 0.0f) ? gain : FLT_EPSILON);
- offset = gain * (-delta);
- }
- else {
- delta *= -1.0f;
- offset = gain * (delta);
- }
- *vd.mask = gain * (*vd.mask) + offset;
- break;
- }
- CLAMP(*vd.mask, 0.0f, 1.0f);
- if (*vd.mask != prev_val) {
- update = true;
- }
- if (vd.mvert) {
- vd.mvert->flag |= ME_VERT_PBVH_UPDATE;
- }
- }
- BKE_pbvh_vertex_iter_end;
-
- if (update) {
- BKE_pbvh_node_mark_update_mask(node);
- }
-}
-
-static int sculpt_mask_filter_exec(bContext *C, wmOperator *op)
-{
- ARegion *region = CTX_wm_region(C);
- Object *ob = CTX_data_active_object(C);
- SculptSession *ss = ob->sculpt;
- Depsgraph *depsgraph = CTX_data_depsgraph_pointer(C);
- PBVH *pbvh = ob->sculpt->pbvh;
- PBVHNode **nodes;
- Sculpt *sd = CTX_data_tool_settings(C)->sculpt;
- int totnode;
- int filter_type = RNA_enum_get(op->ptr, "filter_type");
-
- BKE_sculpt_update_object_for_edit(depsgraph, ob, true, true);
-
- SCULPT_vertex_random_access_init(ss);
-
- if (!ob->sculpt->pmap) {
- return OPERATOR_CANCELLED;
- }
-
- int num_verts = SCULPT_vertex_count_get(ss);
-
- BKE_pbvh_search_gather(pbvh, NULL, NULL, &nodes, &totnode);
- SCULPT_undo_push_begin("Mask filter");
-
- for (int i = 0; i < totnode; i++) {
- SCULPT_undo_push_node(ob, nodes[i], SCULPT_UNDO_MASK);
- }
-
- float *prev_mask = NULL;
- int iterations = RNA_int_get(op->ptr, "iterations");
-
- /* Auto iteration count calculates the number of iteration based on the vertices of the mesh to
- * avoid adding an unnecessary amount of undo steps when using the operator from a shortcut.
- * One iteration per 50000 vertices in the mesh should be fine in most cases.
- * Maybe we want this to be configurable. */
- if (RNA_boolean_get(op->ptr, "auto_iteration_count")) {
- iterations = (int)(num_verts / 50000.0f) + 1;
- }
-
- for (int i = 0; i < iterations; i++) {
- if (ELEM(filter_type, MASK_FILTER_GROW, MASK_FILTER_SHRINK)) {
- prev_mask = MEM_mallocN(num_verts * sizeof(float), "prevmask");
- for (int j = 0; j < num_verts; j++) {
- prev_mask[j] = SCULPT_vertex_mask_get(ss, j);
- }
- }
-
- SculptThreadedTaskData data = {
- .sd = sd,
- .ob = ob,
- .nodes = nodes,
- .filter_type = filter_type,
- .prev_mask = prev_mask,
- };
-
- PBVHParallelSettings settings;
- BKE_pbvh_parallel_range_settings(&settings, (sd->flags & SCULPT_USE_OPENMP), totnode);
- BKE_pbvh_parallel_range(0, totnode, &data, mask_filter_task_cb, &settings);
-
- if (ELEM(filter_type, MASK_FILTER_GROW, MASK_FILTER_SHRINK)) {
- MEM_freeN(prev_mask);
- }
- }
-
- MEM_SAFE_FREE(nodes);
-
- SCULPT_undo_push_end();
-
- ED_region_tag_redraw(region);
- WM_event_add_notifier(C, NC_OBJECT | ND_DRAW, ob);
- return OPERATOR_FINISHED;
-}
-
-static void SCULPT_OT_mask_filter(struct wmOperatorType *ot)
-{
- /* Identifiers. */
- ot->name = "Mask Filter";
- ot->idname = "SCULPT_OT_mask_filter";
- ot->description = "Applies a filter to modify the current mask";
-
- /* API callbacks. */
- ot->exec = sculpt_mask_filter_exec;
- ot->poll = SCULPT_mode_poll;
-
- ot->flag = OPTYPE_REGISTER;
-
- /* RNA. */
- RNA_def_enum(ot->srna,
- "filter_type",
- prop_mask_filter_types,
- MASK_FILTER_SMOOTH,
- "Type",
- "Filter that is going to be applied to the mask");
- RNA_def_int(ot->srna,
- "iterations",
- 1,
- 1,
- 100,
- "Iterations",
- "Number of times that the filter is going to be applied",
- 1,
- 100);
- RNA_def_boolean(
- ot->srna,
- "auto_iteration_count",
- false,
- "Auto Iteration Count",
- "Use a automatic number of iterations based on the number of vertices of the sculpt");
-}
-
-static float neighbor_dirty_mask(SculptSession *ss, PBVHVertexIter *vd)
-{
- int total = 0;
- float avg[3];
- zero_v3(avg);
-
- SculptVertexNeighborIter ni;
- sculpt_vertex_neighbors_iter_begin(ss, vd->index, ni)
- {
- float normalized[3];
- sub_v3_v3v3(normalized, SCULPT_vertex_co_get(ss, ni.index), vd->co);
- normalize_v3(normalized);
- add_v3_v3(avg, normalized);
- total++;
- }
- sculpt_vertex_neighbors_iter_end(ni);
-
- if (total > 0) {
- mul_v3_fl(avg, 1.0f / total);
- float normal[3];
- if (vd->no) {
- normal_short_to_float_v3(normal, vd->no);
- }
- else {
- copy_v3_v3(normal, vd->fno);
- }
- float dot = dot_v3v3(avg, normal);
- float angle = max_ff(saacosf(dot), 0.0f);
- return angle;
- }
- return 0.0f;
-}
-
-typedef struct DirtyMaskRangeData {
- float min, max;
-} DirtyMaskRangeData;
-
-static void dirty_mask_compute_range_task_cb(void *__restrict userdata,
- const int i,
- const TaskParallelTLS *__restrict tls)
-{
- SculptThreadedTaskData *data = userdata;
- SculptSession *ss = data->ob->sculpt;
- PBVHNode *node = data->nodes[i];
- DirtyMaskRangeData *range = tls->userdata_chunk;
- PBVHVertexIter vd;
-
- BKE_pbvh_vertex_iter_begin(ss->pbvh, node, vd, PBVH_ITER_UNIQUE)
- {
- float dirty_mask = neighbor_dirty_mask(ss, &vd);
- range->min = min_ff(dirty_mask, range->min);
- range->max = max_ff(dirty_mask, range->max);
- }
- BKE_pbvh_vertex_iter_end;
-}
-
-static void dirty_mask_compute_range_reduce(const void *__restrict UNUSED(userdata),
- void *__restrict chunk_join,
- void *__restrict chunk)
-{
- DirtyMaskRangeData *join = chunk_join;
- DirtyMaskRangeData *range = chunk;
- join->min = min_ff(range->min, join->min);
- join->max = max_ff(range->max, join->max);
-}
-
-static void dirty_mask_apply_task_cb(void *__restrict userdata,
- const int i,
- const TaskParallelTLS *__restrict UNUSED(tls))
-{
- SculptThreadedTaskData *data = userdata;
- SculptSession *ss = data->ob->sculpt;
- PBVHNode *node = data->nodes[i];
- PBVHVertexIter vd;
-
- const bool dirty_only = data->dirty_mask_dirty_only;
- const float min = data->dirty_mask_min;
- const float max = data->dirty_mask_max;
-
- float range = max - min;
- if (range < 0.0001f) {
- range = 0.0f;
- }
- else {
- range = 1.0f / range;
- }
-
- BKE_pbvh_vertex_iter_begin(ss->pbvh, node, vd, PBVH_ITER_UNIQUE)
- {
- float dirty_mask = neighbor_dirty_mask(ss, &vd);
- float mask = *vd.mask + (1.0f - ((dirty_mask - min) * range));
- if (dirty_only) {
- mask = fminf(mask, 0.5f) * 2.0f;
- }
- *vd.mask = CLAMPIS(mask, 0.0f, 1.0f);
-
- if (vd.mvert) {
- vd.mvert->flag |= ME_VERT_PBVH_UPDATE;
- }
- }
- BKE_pbvh_vertex_iter_end;
- BKE_pbvh_node_mark_update_mask(node);
-}
-
-static int sculpt_dirty_mask_exec(bContext *C, wmOperator *op)
-{
- ARegion *region = CTX_wm_region(C);
- Object *ob = CTX_data_active_object(C);
- SculptSession *ss = ob->sculpt;
- Depsgraph *depsgraph = CTX_data_depsgraph_pointer(C);
- PBVH *pbvh = ob->sculpt->pbvh;
- PBVHNode **nodes;
- Sculpt *sd = CTX_data_tool_settings(C)->sculpt;
- int totnode;
-
- BKE_sculpt_update_object_for_edit(depsgraph, ob, true, true);
-
- SCULPT_vertex_random_access_init(ss);
-
- if (!ob->sculpt->pmap) {
- return OPERATOR_CANCELLED;
- }
-
- BKE_pbvh_search_gather(pbvh, NULL, NULL, &nodes, &totnode);
- SCULPT_undo_push_begin("Dirty Mask");
-
- for (int i = 0; i < totnode; i++) {
- SCULPT_undo_push_node(ob, nodes[i], SCULPT_UNDO_MASK);
- }
-
- SculptThreadedTaskData data = {
- .sd = sd,
- .ob = ob,
- .nodes = nodes,
- .dirty_mask_dirty_only = RNA_boolean_get(op->ptr, "dirty_only"),
- };
- DirtyMaskRangeData range = {
- .min = FLT_MAX,
- .max = -FLT_MAX,
- };
-
- PBVHParallelSettings settings;
- BKE_pbvh_parallel_range_settings(&settings, (sd->flags & SCULPT_USE_OPENMP), totnode);
-
- settings.func_reduce = dirty_mask_compute_range_reduce;
- settings.userdata_chunk = &range;
- settings.userdata_chunk_size = sizeof(DirtyMaskRangeData);
-
- BKE_pbvh_parallel_range(0, totnode, &data, dirty_mask_compute_range_task_cb, &settings);
- data.dirty_mask_min = range.min;
- data.dirty_mask_max = range.max;
- BKE_pbvh_parallel_range(0, totnode, &data, dirty_mask_apply_task_cb, &settings);
-
- MEM_SAFE_FREE(nodes);
-
- BKE_pbvh_update_vertex_data(pbvh, PBVH_UpdateMask);
-
- SCULPT_undo_push_end();
-
- ED_region_tag_redraw(region);
-
- WM_event_add_notifier(C, NC_OBJECT | ND_DRAW, ob);
-
- return OPERATOR_FINISHED;
-}
-
-static void SCULPT_OT_dirty_mask(struct wmOperatorType *ot)
-{
- /* Identifiers. */
- ot->name = "Dirty Mask";
- ot->idname = "SCULPT_OT_dirty_mask";
- ot->description = "Generates a mask based on the geometry cavity and pointiness";
-
- /* API callbacks. */
- ot->exec = sculpt_dirty_mask_exec;
- ot->poll = SCULPT_mode_poll;
-
- ot->flag = OPTYPE_REGISTER;
-
- /* RNA. */
- RNA_def_boolean(
- ot->srna, "dirty_only", false, "Dirty Only", "Don't calculate cleans for convex areas");
-}
-
-static void sculpt_mask_expand_cancel(bContext *C, wmOperator *op)
-{
- Object *ob = CTX_data_active_object(C);
- SculptSession *ss = ob->sculpt;
- const bool create_face_set = RNA_boolean_get(op->ptr, "create_face_set");
-
- MEM_freeN(op->customdata);
-
- for (int n = 0; n < ss->filter_cache->totnode; n++) {
- PBVHNode *node = ss->filter_cache->nodes[n];
- if (create_face_set) {
- for (int i = 0; i < ss->totpoly; i++) {
- ss->face_sets[i] = ss->filter_cache->prev_face_set[i];
- }
- }
- else {
- PBVHVertexIter vd;
- BKE_pbvh_vertex_iter_begin(ss->pbvh, node, vd, PBVH_ITER_UNIQUE)
- {
- *vd.mask = ss->filter_cache->prev_mask[vd.index];
- }
- BKE_pbvh_vertex_iter_end;
- }
-
- BKE_pbvh_node_mark_redraw(node);
- }
-
- if (!create_face_set) {
- sculpt_flush_update_step(C, SCULPT_UPDATE_MASK);
- }
- sculpt_filter_cache_free(ss);
- SCULPT_undo_push_end();
- sculpt_flush_update_done(C, ob, SCULPT_UPDATE_MASK);
- ED_workspace_status_text(C, NULL);
-}
-
-static void sculpt_expand_task_cb(void *__restrict userdata,
- const int i,
- const TaskParallelTLS *__restrict UNUSED(tls))
-{
- SculptThreadedTaskData *data = userdata;
- SculptSession *ss = data->ob->sculpt;
- PBVHNode *node = data->nodes[i];
- PBVHVertexIter vd;
- int update_it = data->mask_expand_update_it;
-
- BKE_pbvh_vertex_iter_begin(ss->pbvh, node, vd, PBVH_ITER_ALL)
- {
- int vi = vd.index;
- float final_mask = *vd.mask;
- if (data->mask_expand_use_normals) {
- if (ss->filter_cache->normal_factor[SCULPT_active_vertex_get(ss)] <
- ss->filter_cache->normal_factor[vd.index]) {
- final_mask = 1.0f;
- }
- else {
- final_mask = 0.0f;
- }
- }
- else {
- if (ss->filter_cache->mask_update_it[vi] <= update_it &&
- ss->filter_cache->mask_update_it[vi] != 0) {
- final_mask = 1.0f;
- }
- else {
- final_mask = 0.0f;
- }
- }
-
- if (data->mask_expand_create_face_set) {
- if (final_mask == 1.0f) {
- SCULPT_vertex_face_set_set(ss, vd.index, ss->filter_cache->new_face_set);
- }
- BKE_pbvh_node_mark_redraw(node);
- }
- else {
-
- if (data->mask_expand_keep_prev_mask) {
- final_mask = MAX2(ss->filter_cache->prev_mask[vd.index], final_mask);
- }
-
- if (data->mask_expand_invert_mask) {
- final_mask = 1.0f - final_mask;
- }
-
- if (*vd.mask != final_mask) {
- if (vd.mvert) {
- vd.mvert->flag |= ME_VERT_PBVH_UPDATE;
- }
- *vd.mask = final_mask;
- BKE_pbvh_node_mark_update_mask(node);
- }
- }
- }
- BKE_pbvh_vertex_iter_end;
-}
-
-static int sculpt_mask_expand_modal(bContext *C, wmOperator *op, const wmEvent *event)
-{
- Depsgraph *depsgraph = CTX_data_depsgraph_pointer(C);
- Object *ob = CTX_data_active_object(C);
- SculptSession *ss = ob->sculpt;
- Sculpt *sd = CTX_data_tool_settings(C)->sculpt;
- ARegion *region = CTX_wm_region(C);
- float prevclick_f[2];
- copy_v2_v2(prevclick_f, op->customdata);
- int prevclick[2] = {(int)prevclick_f[0], (int)prevclick_f[1]};
- int len = (int)len_v2v2_int(prevclick, event->mval);
- len = abs(len);
- int mask_speed = RNA_int_get(op->ptr, "mask_speed");
- int mask_expand_update_it = len / mask_speed;
- mask_expand_update_it = mask_expand_update_it + 1;
-
- const bool create_face_set = RNA_boolean_get(op->ptr, "create_face_set");
-
- if (RNA_boolean_get(op->ptr, "use_cursor")) {
- SculptCursorGeometryInfo sgi;
- float mouse[2];
- mouse[0] = event->mval[0];
- mouse[1] = event->mval[1];
- SCULPT_cursor_geometry_info_update(C, &sgi, mouse, false);
- mask_expand_update_it = ss->filter_cache->mask_update_it[(int)SCULPT_active_vertex_get(ss)];
- }
-
- if ((event->type == EVT_ESCKEY && event->val == KM_PRESS) ||
- (event->type == RIGHTMOUSE && event->val == KM_PRESS)) {
- /* Returning OPERATOR_CANCELLED will leak memory due to not finishing
- * undo. Better solution could be to make paint_mesh_restore_co work
- * for this case. */
- sculpt_mask_expand_cancel(C, op);
- return OPERATOR_FINISHED;
- }
-
- if ((event->type == LEFTMOUSE && event->val == KM_RELEASE) ||
- (event->type == EVT_RETKEY && event->val == KM_PRESS) ||
- (event->type == EVT_PADENTER && event->val == KM_PRESS)) {
-
- /* Smooth iterations. */
- SculptThreadedTaskData data = {
- .sd = sd,
- .ob = ob,
- .nodes = ss->filter_cache->nodes,
- .filter_type = MASK_FILTER_SMOOTH,
- };
-
- int smooth_iterations = RNA_int_get(op->ptr, "smooth_iterations");
- BKE_sculpt_update_object_for_edit(depsgraph, ob, true, false);
- for (int i = 0; i < smooth_iterations; i++) {
- PBVHParallelSettings settings;
- BKE_pbvh_parallel_range_settings(
- &settings, (sd->flags & SCULPT_USE_OPENMP), ss->filter_cache->totnode);
- BKE_pbvh_parallel_range(0, ss->filter_cache->totnode, &data, mask_filter_task_cb, &settings);
- }
-
- /* Pivot position. */
- if (RNA_boolean_get(op->ptr, "update_pivot")) {
- const char symm = sd->paint.symmetry_flags & PAINT_SYMM_AXIS_ALL;
- const float threshold = 0.2f;
- float avg[3];
- int total = 0;
- zero_v3(avg);
-
- for (int n = 0; n < ss->filter_cache->totnode; n++) {
- PBVHVertexIter vd;
- BKE_pbvh_vertex_iter_begin(ss->pbvh, ss->filter_cache->nodes[n], vd, PBVH_ITER_UNIQUE)
- {
- const float mask = (vd.mask) ? *vd.mask : 0.0f;
- if (mask < (0.5f + threshold) && mask > (0.5f - threshold)) {
- if (SCULPT_check_vertex_pivot_symmetry(
- vd.co, ss->filter_cache->mask_expand_initial_co, symm)) {
- add_v3_v3(avg, vd.co);
- total++;
- }
- }
- }
- BKE_pbvh_vertex_iter_end;
- }
-
- if (total > 0) {
- mul_v3_fl(avg, 1.0f / total);
- copy_v3_v3(ss->pivot_pos, avg);
- }
- WM_event_add_notifier(C, NC_GEOM | ND_SELECT, ob->data);
- }
-
- MEM_freeN(op->customdata);
-
- for (int i = 0; i < ss->filter_cache->totnode; i++) {
- BKE_pbvh_node_mark_redraw(ss->filter_cache->nodes[i]);
- }
-
- sculpt_filter_cache_free(ss);
-
- SCULPT_undo_push_end();
- sculpt_flush_update_done(C, ob, SCULPT_UPDATE_MASK);
- ED_workspace_status_text(C, NULL);
- return OPERATOR_FINISHED;
- }
-
- /* When pressing Ctrl, expand directly to the max number of iterations. This allows to flood fill
- * mask and face sets by connectivity directly. */
- if (event->ctrl) {
- mask_expand_update_it = ss->filter_cache->mask_update_last_it - 1;
- }
-
- if (!ELEM(event->type, MOUSEMOVE, EVT_LEFTCTRLKEY, EVT_RIGHTCTRLKEY)) {
- return OPERATOR_RUNNING_MODAL;
- }
-
- if (mask_expand_update_it == ss->filter_cache->mask_update_current_it) {
- ED_region_tag_redraw(region);
- return OPERATOR_RUNNING_MODAL;
- }
-
- if (mask_expand_update_it < ss->filter_cache->mask_update_last_it) {
-
- if (create_face_set) {
- for (int i = 0; i < ss->totpoly; i++) {
- ss->face_sets[i] = ss->filter_cache->prev_face_set[i];
- }
- }
- SculptThreadedTaskData data = {
- .sd = sd,
- .ob = ob,
- .nodes = ss->filter_cache->nodes,
- .mask_expand_update_it = mask_expand_update_it,
- .mask_expand_use_normals = RNA_boolean_get(op->ptr, "use_normals"),
- .mask_expand_invert_mask = RNA_boolean_get(op->ptr, "invert"),
- .mask_expand_keep_prev_mask = RNA_boolean_get(op->ptr, "keep_previous_mask"),
- .mask_expand_create_face_set = RNA_boolean_get(op->ptr, "create_face_set"),
- };
- PBVHParallelSettings settings;
- BKE_pbvh_parallel_range_settings(
- &settings, (sd->flags & SCULPT_USE_OPENMP), ss->filter_cache->totnode);
- BKE_pbvh_parallel_range(0, ss->filter_cache->totnode, &data, sculpt_expand_task_cb, &settings);
- ss->filter_cache->mask_update_current_it = mask_expand_update_it;
- }
-
- sculpt_flush_update_step(C, SCULPT_UPDATE_MASK);
-
- return OPERATOR_RUNNING_MODAL;
-}
-
-typedef struct MaskExpandFloodFillData {
- float original_normal[3];
- float edge_sensitivity;
- bool use_normals;
-} MaskExpandFloodFillData;
-
-static bool mask_expand_floodfill_cb(
- SculptSession *ss, int from_v, int to_v, bool is_duplicate, void *userdata)
-{
- MaskExpandFloodFillData *data = userdata;
-
- if (!is_duplicate) {
- int to_it = ss->filter_cache->mask_update_it[from_v] + 1;
- ss->filter_cache->mask_update_it[to_v] = to_it;
- if (to_it > ss->filter_cache->mask_update_last_it) {
- ss->filter_cache->mask_update_last_it = to_it;
- }
-
- if (data->use_normals) {
- float current_normal[3], prev_normal[3];
- SCULPT_vertex_normal_get(ss, to_v, current_normal);
- SCULPT_vertex_normal_get(ss, from_v, prev_normal);
- const float from_edge_factor = ss->filter_cache->edge_factor[from_v];
- ss->filter_cache->edge_factor[to_v] = dot_v3v3(current_normal, prev_normal) *
- from_edge_factor;
- ss->filter_cache->normal_factor[to_v] = dot_v3v3(data->original_normal, current_normal) *
- powf(from_edge_factor, data->edge_sensitivity);
- CLAMP(ss->filter_cache->normal_factor[to_v], 0.0f, 1.0f);
- }
- }
- else {
- /* PBVH_GRIDS duplicate handling. */
- ss->filter_cache->mask_update_it[to_v] = ss->filter_cache->mask_update_it[from_v];
- if (data->use_normals) {
- ss->filter_cache->edge_factor[to_v] = ss->filter_cache->edge_factor[from_v];
- ss->filter_cache->normal_factor[to_v] = ss->filter_cache->normal_factor[from_v];
- }
- }
-
- return true;
-}
-
-static int sculpt_mask_expand_invoke(bContext *C, wmOperator *op, const wmEvent *event)
-{
- Depsgraph *depsgraph = CTX_data_depsgraph_pointer(C);
- Object *ob = CTX_data_active_object(C);
- SculptSession *ss = ob->sculpt;
- Sculpt *sd = CTX_data_tool_settings(C)->sculpt;
- PBVH *pbvh = ob->sculpt->pbvh;
-
- const bool use_normals = RNA_boolean_get(op->ptr, "use_normals");
- const bool create_face_set = RNA_boolean_get(op->ptr, "create_face_set");
-
- SculptCursorGeometryInfo sgi;
- float mouse[2];
- mouse[0] = event->mval[0];
- mouse[1] = event->mval[1];
-
- SCULPT_vertex_random_access_init(ss);
-
- op->customdata = MEM_mallocN(2 * sizeof(float), "initial mouse position");
- copy_v2_v2(op->customdata, mouse);
-
- SCULPT_cursor_geometry_info_update(C, &sgi, mouse, false);
-
- BKE_sculpt_update_object_for_edit(depsgraph, ob, true, true);
-
- int vertex_count = SCULPT_vertex_count_get(ss);
-
- ss->filter_cache = MEM_callocN(sizeof(FilterCache), "filter cache");
-
- BKE_pbvh_search_gather(pbvh, NULL, NULL, &ss->filter_cache->nodes, &ss->filter_cache->totnode);
-
- SCULPT_undo_push_begin("Mask Expand");
-
- if (create_face_set) {
- SCULPT_undo_push_node(ob, ss->filter_cache->nodes[0], SCULPT_UNDO_FACE_SETS);
- for (int i = 0; i < ss->filter_cache->totnode; i++) {
- BKE_pbvh_node_mark_redraw(ss->filter_cache->nodes[i]);
- }
- }
- else {
- for (int i = 0; i < ss->filter_cache->totnode; i++) {
- SCULPT_undo_push_node(ob, ss->filter_cache->nodes[i], SCULPT_UNDO_MASK);
- BKE_pbvh_node_mark_redraw(ss->filter_cache->nodes[i]);
- }
- }
-
- ss->filter_cache->mask_update_it = MEM_callocN(sizeof(int) * vertex_count,
- "mask update iteration");
- if (use_normals) {
- ss->filter_cache->normal_factor = MEM_callocN(sizeof(float) * vertex_count,
- "mask update normal factor");
- ss->filter_cache->edge_factor = MEM_callocN(sizeof(float) * vertex_count,
- "mask update normal factor");
- for (int i = 0; i < vertex_count; i++) {
- ss->filter_cache->edge_factor[i] = 1.0f;
- }
- }
-
- if (create_face_set) {
- ss->filter_cache->prev_face_set = MEM_callocN(sizeof(float) * ss->totpoly, "prev face mask");
- for (int i = 0; i < ss->totpoly; i++) {
- ss->filter_cache->prev_face_set[i] = ss->face_sets[i];
- }
- ss->filter_cache->new_face_set = SCULPT_face_set_next_available_get(ss);
- }
- else {
- ss->filter_cache->prev_mask = MEM_callocN(sizeof(float) * vertex_count, "prev mask");
- for (int i = 0; i < vertex_count; i++) {
- ss->filter_cache->prev_mask[i] = SCULPT_vertex_mask_get(ss, i);
- }
- }
-
- ss->filter_cache->mask_update_last_it = 1;
- ss->filter_cache->mask_update_current_it = 1;
- ss->filter_cache->mask_update_it[SCULPT_active_vertex_get(ss)] = 0;
-
- copy_v3_v3(ss->filter_cache->mask_expand_initial_co, SCULPT_active_vertex_co_get(ss));
-
- SculptFloodFill flood;
- SCULPT_floodfill_init(ss, &flood);
- SCULPT_floodfill_add_active(sd, ob, ss, &flood, FLT_MAX);
-
- MaskExpandFloodFillData fdata = {
- .use_normals = use_normals,
- .edge_sensitivity = RNA_int_get(op->ptr, "edge_sensitivity"),
- };
- SCULPT_active_vertex_normal_get(ss, fdata.original_normal);
- SCULPT_floodfill_execute(ss, &flood, mask_expand_floodfill_cb, &fdata);
- SCULPT_floodfill_free(&flood);
-
- if (use_normals) {
- for (int repeat = 0; repeat < 2; repeat++) {
- for (int i = 0; i < vertex_count; i++) {
- float avg = 0.0f;
- SculptVertexNeighborIter ni;
- sculpt_vertex_neighbors_iter_begin(ss, i, ni)
- {
- avg += ss->filter_cache->normal_factor[ni.index];
- }
- sculpt_vertex_neighbors_iter_end(ni);
- ss->filter_cache->normal_factor[i] = avg / ni.size;
- }
- }
-
- MEM_SAFE_FREE(ss->filter_cache->edge_factor);
- }
-
- SculptThreadedTaskData data = {
- .sd = sd,
- .ob = ob,
- .nodes = ss->filter_cache->nodes,
- .mask_expand_update_it = 0,
- .mask_expand_use_normals = RNA_boolean_get(op->ptr, "use_normals"),
- .mask_expand_invert_mask = RNA_boolean_get(op->ptr, "invert"),
- .mask_expand_keep_prev_mask = RNA_boolean_get(op->ptr, "keep_previous_mask"),
- .mask_expand_create_face_set = RNA_boolean_get(op->ptr, "create_face_set"),
- };
- PBVHParallelSettings settings;
- BKE_pbvh_parallel_range_settings(
- &settings, (sd->flags & SCULPT_USE_OPENMP), ss->filter_cache->totnode);
- BKE_pbvh_parallel_range(0, ss->filter_cache->totnode, &data, sculpt_expand_task_cb, &settings);
-
- const char *status_str = TIP_(
- "Move the mouse to expand the mask from the active vertex. LMB: confirm mask, ESC/RMB: "
- "cancel");
- ED_workspace_status_text(C, status_str);
-
- sculpt_flush_update_step(C, SCULPT_UPDATE_MASK);
- WM_event_add_modal_handler(C, op);
- return OPERATOR_RUNNING_MODAL;
-}
-
-static void SCULPT_OT_mask_expand(wmOperatorType *ot)
-{
- /* Identifiers. */
- ot->name = "Mask Expand";
- ot->idname = "SCULPT_OT_mask_expand";
- ot->description = "Expands a mask from the initial active vertex under the cursor";
-
- /* API callbacks. */
- ot->invoke = sculpt_mask_expand_invoke;
- ot->modal = sculpt_mask_expand_modal;
- ot->cancel = sculpt_mask_expand_cancel;
- ot->poll = SCULPT_mode_poll;
-
- ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
- ot->prop = RNA_def_boolean(ot->srna, "invert", true, "Invert", "Invert the new mask");
- ot->prop = RNA_def_boolean(
- ot->srna, "use_cursor", true, "Use Cursor", "Expand the mask to the cursor position");
- ot->prop = RNA_def_boolean(ot->srna,
- "update_pivot",
- true,
- "Update Pivot Position",
- "Set the pivot position to the mask border after creating the mask");
- ot->prop = RNA_def_int(ot->srna, "smooth_iterations", 2, 0, 10, "Smooth iterations", "", 0, 10);
- ot->prop = RNA_def_int(ot->srna, "mask_speed", 5, 1, 10, "Mask speed", "", 1, 10);
-
- ot->prop = RNA_def_boolean(ot->srna,
- "use_normals",
- true,
- "Use Normals",
- "Generate the mask using the normals and curvature of the model");
- ot->prop = RNA_def_boolean(ot->srna,
- "keep_previous_mask",
- false,
- "Keep Previous Mask",
- "Generate the new mask on top of the current one");
- ot->prop = RNA_def_int(ot->srna,
- "edge_sensitivity",
- 300,
- 0,
- 2000,
- "Edge Detection Sensitivity",
- "Sensitivity for expanding the mask across sculpted sharp edges when "
- "using normals to generate the mask",
- 0,
- 2000);
- ot->prop = RNA_def_boolean(ot->srna,
- "create_face_set",
- false,
- "Expand Face Mask",
- "Expand a new Face Mask instead of the sculpt mask");
-}
-
void SCULPT_geometry_preview_lines_update(bContext *C, SculptSession *ss, float radius)
{
Depsgraph *depsgraph = CTX_data_depsgraph_pointer(C);
@@ -10703,8 +7843,7 @@ void SCULPT_geometry_preview_lines_update(bContext *C, SculptSession *ss, float
float brush_co[3];
copy_v3_v3(brush_co, SCULPT_active_vertex_co_get(ss));
- char *visited_vertices = MEM_callocN(SCULPT_vertex_count_get(ss) * sizeof(char),
- "visited vertices");
+ BLI_bitmap *visited_vertices = BLI_BITMAP_NEW(SCULPT_vertex_count_get(ss), "visited_vertices");
/* Assuming an average of 6 edges per vertex in a triangulated mesh. */
const int max_preview_vertices = SCULPT_vertex_count_get(ss) * 3 * 2;
@@ -10721,16 +7860,15 @@ void SCULPT_geometry_preview_lines_update(bContext *C, SculptSession *ss, float
int from_v;
BLI_gsqueue_pop(not_visited_vertices, &from_v);
SculptVertexNeighborIter ni;
- sculpt_vertex_neighbors_iter_begin(ss, from_v, ni)
- {
+ SCULPT_VERTEX_NEIGHBORS_ITER_BEGIN (ss, from_v, ni) {
if (totpoints + (ni.size * 2) < max_preview_vertices) {
int to_v = ni.index;
ss->preview_vert_index_list[totpoints] = from_v;
totpoints++;
ss->preview_vert_index_list[totpoints] = to_v;
totpoints++;
- if (visited_vertices[to_v] == 0) {
- visited_vertices[to_v] = 1;
+ if (!BLI_BITMAP_TEST(visited_vertices, to_v)) {
+ BLI_BITMAP_ENABLE(visited_vertices, to_v);
const float *co = SCULPT_vertex_co_get(ss, to_v);
if (len_squared_v3v3(brush_co, co) < radius * radius) {
BLI_gsqueue_push(not_visited_vertices, &to_v);
@@ -10738,7 +7876,7 @@ void SCULPT_geometry_preview_lines_update(bContext *C, SculptSession *ss, float
}
}
}
- sculpt_vertex_neighbors_iter_end(ni);
+ SCULPT_VERTEX_NEIGHBORS_ITER_END(ni);
}
BLI_gsqueue_free(not_visited_vertices);
@@ -10747,1069 +7885,6 @@ void SCULPT_geometry_preview_lines_update(bContext *C, SculptSession *ss, float
ss->preview_vert_index_count = totpoints;
}
-void ED_sculpt_init_transform(struct bContext *C)
-{
- Sculpt *sd = CTX_data_tool_settings(C)->sculpt;
- Object *ob = CTX_data_active_object(C);
- SculptSession *ss = ob->sculpt;
- Depsgraph *depsgraph = CTX_data_depsgraph_pointer(C);
-
- copy_v3_v3(ss->init_pivot_pos, ss->pivot_pos);
- copy_v4_v4(ss->init_pivot_rot, ss->pivot_rot);
-
- SCULPT_undo_push_begin("Transform");
- BKE_sculpt_update_object_for_edit(depsgraph, ob, false, false);
-
- ss->pivot_rot[3] = 1.0f;
-
- SCULPT_vertex_random_access_init(ss);
- sculpt_filter_cache_init(ob, sd);
-}
-
-static void sculpt_transform_task_cb(void *__restrict userdata,
- const int i,
- const TaskParallelTLS *__restrict UNUSED(tls))
-{
-
- SculptThreadedTaskData *data = userdata;
- SculptSession *ss = data->ob->sculpt;
- PBVHNode *node = data->nodes[i];
-
- SculptOrigVertData orig_data;
- SCULPT_orig_vert_data_init(&orig_data, data->ob, data->nodes[i]);
-
- PBVHVertexIter vd;
-
- SCULPT_undo_push_node(data->ob, node, SCULPT_UNDO_COORDS);
- BKE_pbvh_vertex_iter_begin(ss->pbvh, node, vd, PBVH_ITER_UNIQUE)
- {
- SCULPT_orig_vert_data_update(&orig_data, &vd);
- float transformed_co[3], orig_co[3], disp[3];
- float fade = vd.mask ? *vd.mask : 0.0f;
- copy_v3_v3(orig_co, orig_data.co);
- char symm_area = SCULPT_get_vertex_symm_area(orig_co);
-
- copy_v3_v3(transformed_co, orig_co);
- mul_m4_v3(data->transform_mats[(int)symm_area], transformed_co);
- sub_v3_v3v3(disp, transformed_co, orig_co);
- mul_v3_fl(disp, 1.0f - fade);
-
- add_v3_v3v3(vd.co, orig_co, disp);
-
- if (vd.mvert) {
- vd.mvert->flag |= ME_VERT_PBVH_UPDATE;
- }
- }
- BKE_pbvh_vertex_iter_end;
-
- BKE_pbvh_node_mark_update(node);
-}
-
-void ED_sculpt_update_modal_transform(struct bContext *C)
-{
- Sculpt *sd = CTX_data_tool_settings(C)->sculpt;
- Object *ob = CTX_data_active_object(C);
- SculptSession *ss = ob->sculpt;
- Depsgraph *depsgraph = CTX_data_depsgraph_pointer(C);
- const char symm = sd->paint.symmetry_flags & PAINT_SYMM_AXIS_ALL;
-
- SCULPT_vertex_random_access_init(ss);
- BKE_sculpt_update_object_for_edit(depsgraph, ob, false, false);
-
- SculptThreadedTaskData data = {
- .sd = sd,
- .ob = ob,
- .nodes = ss->filter_cache->nodes,
- };
-
- float final_pivot_pos[3], d_t[3], d_r[4];
- float t_mat[4][4], r_mat[4][4], s_mat[4][4], pivot_mat[4][4], pivot_imat[4][4],
- transform_mat[4][4];
-
- copy_v3_v3(final_pivot_pos, ss->pivot_pos);
- for (int i = 0; i < PAINT_SYMM_AREAS; i++) {
- ePaintSymmetryAreas v_symm = i;
-
- copy_v3_v3(final_pivot_pos, ss->pivot_pos);
-
- unit_m4(pivot_mat);
-
- unit_m4(t_mat);
- unit_m4(r_mat);
- unit_m4(s_mat);
-
- /* Translation matrix. */
- sub_v3_v3v3(d_t, ss->pivot_pos, ss->init_pivot_pos);
- SCULPT_flip_v3_by_symm_area(d_t, symm, v_symm, ss->init_pivot_pos);
- translate_m4(t_mat, d_t[0], d_t[1], d_t[2]);
-
- /* Rotation matrix. */
- sub_qt_qtqt(d_r, ss->pivot_rot, ss->init_pivot_rot);
- normalize_qt(d_r);
- SCULPT_flip_quat_by_symm_area(d_r, symm, v_symm, ss->init_pivot_pos);
- quat_to_mat4(r_mat, d_r);
-
- /* Scale matrix. */
- size_to_mat4(s_mat, ss->pivot_scale);
-
- /* Pivot matrix. */
- SCULPT_flip_v3_by_symm_area(final_pivot_pos, symm, v_symm, ss->init_pivot_pos);
- translate_m4(pivot_mat, final_pivot_pos[0], final_pivot_pos[1], final_pivot_pos[2]);
- invert_m4_m4(pivot_imat, pivot_mat);
-
- /* Final transform matrix. */
- mul_m4_m4m4(transform_mat, r_mat, t_mat);
- mul_m4_m4m4(transform_mat, transform_mat, s_mat);
- mul_m4_m4m4(data.transform_mats[i], transform_mat, pivot_imat);
- mul_m4_m4m4(data.transform_mats[i], pivot_mat, data.transform_mats[i]);
- }
-
- PBVHParallelSettings settings;
- BKE_pbvh_parallel_range_settings(
- &settings, (sd->flags & SCULPT_USE_OPENMP), ss->filter_cache->totnode);
- BKE_pbvh_parallel_range(
- 0, ss->filter_cache->totnode, &data, sculpt_transform_task_cb, &settings);
-
- if (ss->deform_modifiers_active || ss->shapekey_active) {
- sculpt_flush_stroke_deform(sd, ob, true);
- }
-
- sculpt_flush_update_step(C, SCULPT_UPDATE_COORDS);
-}
-
-void ED_sculpt_end_transform(struct bContext *C)
-{
- Object *ob = CTX_data_active_object(C);
- SculptSession *ss = ob->sculpt;
- if (ss->filter_cache) {
- sculpt_filter_cache_free(ss);
- }
- SCULPT_undo_push_end();
- sculpt_flush_update_done(C, ob, SCULPT_UPDATE_COORDS);
-}
-
-typedef enum eSculptPivotPositionModes {
- SCULPT_PIVOT_POSITION_ORIGIN = 0,
- SCULPT_PIVOT_POSITION_UNMASKED = 1,
- SCULPT_PIVOT_POSITION_MASK_BORDER = 2,
- SCULPT_PIVOT_POSITION_ACTIVE_VERTEX = 3,
- SCULPT_PIVOT_POSITION_CURSOR_SURFACE = 4,
-} eSculptPivotPositionModes;
-
-static EnumPropertyItem prop_sculpt_pivot_position_types[] = {
- {SCULPT_PIVOT_POSITION_ORIGIN,
- "ORIGIN",
- 0,
- "Origin",
- "Sets the pivot to the origin of the sculpt"},
- {SCULPT_PIVOT_POSITION_UNMASKED,
- "UNMASKED",
- 0,
- "Unmasked",
- "Sets the pivot position to the average position of the unmasked vertices"},
- {SCULPT_PIVOT_POSITION_MASK_BORDER,
- "BORDER",
- 0,
- "Mask border",
- "Sets the pivot position to the center of the border of the mask"},
- {SCULPT_PIVOT_POSITION_ACTIVE_VERTEX,
- "ACTIVE",
- 0,
- "Active vertex",
- "Sets the pivot position to the active vertex position"},
- {SCULPT_PIVOT_POSITION_CURSOR_SURFACE,
- "SURFACE",
- 0,
- "Surface",
- "Sets the pivot position to the surface under the cursor"},
- {0, NULL, 0, NULL, NULL},
-};
-
-static int sculpt_set_pivot_position_exec(bContext *C, wmOperator *op)
-{
- Sculpt *sd = CTX_data_tool_settings(C)->sculpt;
- Object *ob = CTX_data_active_object(C);
- SculptSession *ss = ob->sculpt;
- ARegion *region = CTX_wm_region(C);
- Depsgraph *depsgraph = CTX_data_ensure_evaluated_depsgraph(C);
- const char symm = sd->paint.symmetry_flags & PAINT_SYMM_AXIS_ALL;
-
- int mode = RNA_enum_get(op->ptr, "mode");
-
- BKE_sculpt_update_object_for_edit(depsgraph, ob, false, true);
-
- /* Pivot to center. */
- if (mode == SCULPT_PIVOT_POSITION_ORIGIN) {
- zero_v3(ss->pivot_pos);
- }
- /* Pivot to active vertex. */
- else if (mode == SCULPT_PIVOT_POSITION_ACTIVE_VERTEX) {
- copy_v3_v3(ss->pivot_pos, SCULPT_active_vertex_co_get(ss));
- }
- /* Pivot to raycast surface. */
- else if (mode == SCULPT_PIVOT_POSITION_CURSOR_SURFACE) {
- float stroke_location[3];
- float mouse[2];
- mouse[0] = RNA_float_get(op->ptr, "mouse_x");
- mouse[1] = RNA_float_get(op->ptr, "mouse_y");
- if (SCULPT_stroke_get_location(C, stroke_location, mouse)) {
- copy_v3_v3(ss->pivot_pos, stroke_location);
- }
- }
- else {
- PBVHNode **nodes;
- int totnode;
- BKE_pbvh_search_gather(ss->pbvh, NULL, NULL, &nodes, &totnode);
-
- float avg[3];
- int total = 0;
- zero_v3(avg);
-
- /* Pivot to unmasked. */
- if (mode == SCULPT_PIVOT_POSITION_UNMASKED) {
- for (int n = 0; n < totnode; n++) {
- PBVHVertexIter vd;
- BKE_pbvh_vertex_iter_begin(ss->pbvh, nodes[n], vd, PBVH_ITER_UNIQUE)
- {
- const float mask = (vd.mask) ? *vd.mask : 0.0f;
- if (mask < 1.0f) {
- if (SCULPT_check_vertex_pivot_symmetry(vd.co, ss->pivot_pos, symm)) {
- add_v3_v3(avg, vd.co);
- total++;
- }
- }
- }
- BKE_pbvh_vertex_iter_end;
- }
- }
- /* Pivot to mask border. */
- else if (mode == SCULPT_PIVOT_POSITION_MASK_BORDER) {
- const float threshold = 0.2f;
-
- for (int n = 0; n < totnode; n++) {
- PBVHVertexIter vd;
- BKE_pbvh_vertex_iter_begin(ss->pbvh, nodes[n], vd, PBVH_ITER_UNIQUE)
- {
- const float mask = (vd.mask) ? *vd.mask : 0.0f;
- if (mask < (0.5f + threshold) && mask > (0.5f - threshold)) {
- if (SCULPT_check_vertex_pivot_symmetry(vd.co, ss->pivot_pos, symm)) {
- add_v3_v3(avg, vd.co);
- total++;
- }
- }
- }
- BKE_pbvh_vertex_iter_end;
- }
- }
-
- if (total > 0) {
- mul_v3_fl(avg, 1.0f / total);
- copy_v3_v3(ss->pivot_pos, avg);
- }
-
- MEM_SAFE_FREE(nodes);
- }
-
- ED_region_tag_redraw(region);
- WM_event_add_notifier(C, NC_GEOM | ND_SELECT, ob->data);
-
- return OPERATOR_FINISHED;
-}
-
-static int sculpt_set_pivot_position_invoke(bContext *C, wmOperator *op, const wmEvent *event)
-{
- RNA_float_set(op->ptr, "mouse_x", event->mval[0]);
- RNA_float_set(op->ptr, "mouse_y", event->mval[1]);
- return sculpt_set_pivot_position_exec(C, op);
-}
-
-static void SCULPT_OT_set_pivot_position(wmOperatorType *ot)
-{
- /* Identifiers. */
- ot->name = "Set Pivot Position";
- ot->idname = "SCULPT_OT_set_pivot_position";
- ot->description = "Sets the sculpt transform pivot position";
-
- /* API callbacks. */
- ot->invoke = sculpt_set_pivot_position_invoke;
- ot->exec = sculpt_set_pivot_position_exec;
- ot->poll = SCULPT_mode_poll;
-
- ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
- RNA_def_enum(ot->srna,
- "mode",
- prop_sculpt_pivot_position_types,
- SCULPT_PIVOT_POSITION_UNMASKED,
- "Mode",
- "");
-
- RNA_def_float(ot->srna,
- "mouse_x",
- 0.0f,
- 0.0f,
- FLT_MAX,
- "Mouse Position X",
- "Position of the mouse used for \"Surface\" mode",
- 0.0f,
- 10000.0f);
- RNA_def_float(ot->srna,
- "mouse_y",
- 0.0f,
- 0.0f,
- FLT_MAX,
- "Mouse Position Y",
- "Position of the mouse used for \"Surface\" mode",
- 0.0f,
- 10000.0f);
-}
-
-typedef enum eSculptFaceGroupsCreateModes {
- SCULPT_FACE_SET_MASKED = 0,
- SCULPT_FACE_SET_VISIBLE = 1,
- SCULPT_FACE_SET_ALL = 2,
- SCULPT_FACE_SET_SELECTION = 3,
-} eSculptFaceGroupsCreateModes;
-
-static EnumPropertyItem prop_sculpt_face_set_create_types[] = {
- {
- SCULPT_FACE_SET_MASKED,
- "MASKED",
- 0,
- "Face Set From Masked",
- "Create a new Face Set from the masked faces",
- },
- {
- SCULPT_FACE_SET_VISIBLE,
- "VISIBLE",
- 0,
- "Face Set From Visible",
- "Create a new Face Set from the visible vertices",
- },
- {
- SCULPT_FACE_SET_ALL,
- "ALL",
- 0,
- "Face Set Full Mesh",
- "Create an unique Face Set with all faces in the sculpt",
- },
- {
- SCULPT_FACE_SET_SELECTION,
- "SELECTION",
- 0,
- "Face Set From Edit Mode Selection",
- "Create an Face Set corresponding to the Edit Mode face selection",
- },
- {0, NULL, 0, NULL, NULL},
-};
-
-static int sculpt_face_set_create_invoke(bContext *C, wmOperator *op, const wmEvent *UNUSED(event))
-{
- Object *ob = CTX_data_active_object(C);
- SculptSession *ss = ob->sculpt;
- ARegion *region = CTX_wm_region(C);
- Depsgraph *depsgraph = CTX_data_depsgraph_pointer(C);
-
- const int mode = RNA_enum_get(op->ptr, "mode");
-
- /* Dyntopo and Multires not supported for now. */
- if (BKE_pbvh_type(ss->pbvh) != PBVH_FACES) {
- return OPERATOR_CANCELLED;
- }
-
- BKE_sculpt_update_object_for_edit(depsgraph, ob, true, mode == SCULPT_FACE_SET_MASKED);
-
- const int tot_vert = SCULPT_vertex_count_get(ss);
- float threshold = 0.5f;
-
- PBVH *pbvh = ob->sculpt->pbvh;
- PBVHNode **nodes;
- int totnode;
- BKE_pbvh_search_gather(pbvh, NULL, NULL, &nodes, &totnode);
-
- if (!nodes) {
- return OPERATOR_CANCELLED;
- }
-
- SCULPT_undo_push_begin("face set change");
- SCULPT_undo_push_node(ob, nodes[0], SCULPT_UNDO_FACE_SETS);
-
- const int next_face_set = SCULPT_face_set_next_available_get(ss);
-
- if (mode == SCULPT_FACE_SET_MASKED) {
- for (int i = 0; i < tot_vert; i++) {
- if (SCULPT_vertex_mask_get(ss, i) >= threshold && SCULPT_vertex_visible_get(ss, i)) {
- SCULPT_vertex_face_set_set(ss, i, next_face_set);
- }
- }
- }
-
- if (mode == SCULPT_FACE_SET_VISIBLE) {
- for (int i = 0; i < tot_vert; i++) {
- if (SCULPT_vertex_visible_get(ss, i)) {
- SCULPT_vertex_face_set_set(ss, i, next_face_set);
- }
- }
- }
-
- if (mode == SCULPT_FACE_SET_ALL) {
- for (int i = 0; i < tot_vert; i++) {
- SCULPT_vertex_face_set_set(ss, i, next_face_set);
- }
- }
-
- if (mode == SCULPT_FACE_SET_SELECTION) {
- Mesh *mesh = ob->data;
- BMesh *bm;
- const BMAllocTemplate allocsize = BMALLOC_TEMPLATE_FROM_ME(mesh);
- bm = BM_mesh_create(&allocsize,
- &((struct BMeshCreateParams){
- .use_toolflags = true,
- }));
-
- BM_mesh_bm_from_me(bm,
- mesh,
- (&(struct BMeshFromMeshParams){
- .calc_face_normal = true,
- }));
-
- BMIter iter;
- BMFace *f;
- BM_ITER_MESH (f, &iter, bm, BM_FACES_OF_MESH) {
- if (BM_elem_flag_test(f, BM_ELEM_SELECT)) {
- ss->face_sets[BM_elem_index_get(f)] = next_face_set;
- }
- }
- BM_mesh_free(bm);
- }
-
- for (int i = 0; i < totnode; i++) {
- BKE_pbvh_node_mark_redraw(nodes[i]);
- }
-
- MEM_SAFE_FREE(nodes);
-
- SCULPT_undo_push_end();
-
- ED_region_tag_redraw(region);
- WM_event_add_notifier(C, NC_OBJECT | ND_DRAW, ob);
-
- return OPERATOR_FINISHED;
-}
-
-static void SCULPT_OT_face_sets_create(wmOperatorType *ot)
-{
- /* identifiers */
- ot->name = "Create Face Set";
- ot->idname = "SCULPT_OT_face_sets_create";
- ot->description = "Create a new Face Set";
-
- /* api callbacks */
- ot->invoke = sculpt_face_set_create_invoke;
- ot->poll = SCULPT_mode_poll;
-
- ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
-
- RNA_def_enum(
- ot->srna, "mode", prop_sculpt_face_set_create_types, SCULPT_FACE_SET_MASKED, "Mode", "");
-}
-
-typedef enum eSculptFaceSetsInitMode {
- SCULPT_FACE_SETS_FROM_LOOSE_PARTS = 0,
- SCULPT_FACE_SETS_FROM_MATERIALS = 1,
- SCULPT_FACE_SETS_FROM_NORMALS = 2,
- SCULPT_FACE_SETS_FROM_UV_SEAMS = 3,
- SCULPT_FACE_SETS_FROM_CREASES = 4,
- SCULPT_FACE_SETS_FROM_SHARP_EDGES = 5,
- SCULPT_FACE_SETS_FROM_BEVEL_WEIGHT = 6,
- SCULPT_FACE_SETS_FROM_FACE_MAPS = 7,
-} eSculptFaceSetsInitMode;
-
-static EnumPropertyItem prop_sculpt_face_sets_init_types[] = {
- {
- SCULPT_FACE_SETS_FROM_LOOSE_PARTS,
- "LOOSE_PARTS",
- 0,
- "Face Sets From Loose Parts",
- "Create a Face Set per loose part in the mesh",
- },
- {
- SCULPT_FACE_SETS_FROM_MATERIALS,
- "MATERIALS",
- 0,
- "Face Sets From Material Slots",
- "Create a Face Set per Material Slot",
- },
- {
- SCULPT_FACE_SETS_FROM_NORMALS,
- "NORMALS",
- 0,
- "Face Sets From Mesh Normals",
- "Create Face Sets for Faces that have similar normal",
- },
- {
- SCULPT_FACE_SETS_FROM_UV_SEAMS,
- "UV_SEAMS",
- 0,
- "Face Sets From UV Seams",
- "Create Face Sets using UV Seams as boundaries",
- },
- {
- SCULPT_FACE_SETS_FROM_CREASES,
- "CREASES",
- 0,
- "Face Sets From Edge Creases",
- "Create Face Sets using Edge Creases as boundaries",
- },
- {
- SCULPT_FACE_SETS_FROM_BEVEL_WEIGHT,
- "BEVEL_WEIGHT",
- 0,
- "Face Sets From Bevel Weight",
- "Create Face Sets using Bevel Weights as boundaries",
- },
- {
- SCULPT_FACE_SETS_FROM_SHARP_EDGES,
- "SHARP_EDGES",
- 0,
- "Face Sets From Sharp Edges",
- "Create Face Sets using Sharp Edges as boundaries",
- },
- {
- SCULPT_FACE_SETS_FROM_FACE_MAPS,
- "FACE_MAPS",
- 0,
- "Face Sets From Face Maps",
- "Create a Face Set per Face Map",
- },
- {0, NULL, 0, NULL, NULL},
-};
-
-typedef bool (*face_sets_flood_fill_test)(
- BMesh *bm, BMFace *from_f, BMEdge *from_e, BMFace *to_f, const float threshold);
-
-static bool sculpt_face_sets_init_loose_parts_test(BMesh *UNUSED(bm),
- BMFace *UNUSED(from_f),
- BMEdge *UNUSED(from_e),
- BMFace *UNUSED(to_f),
- const float UNUSED(threshold))
-{
- return true;
-}
-
-static bool sculpt_face_sets_init_normals_test(
- BMesh *UNUSED(bm), BMFace *from_f, BMEdge *UNUSED(from_e), BMFace *to_f, const float threshold)
-{
- return fabsf(dot_v3v3(from_f->no, to_f->no)) > threshold;
-}
-
-static bool sculpt_face_sets_init_uv_seams_test(BMesh *UNUSED(bm),
- BMFace *UNUSED(from_f),
- BMEdge *from_e,
- BMFace *UNUSED(to_f),
- const float UNUSED(threshold))
-{
- return !BM_elem_flag_test(from_e, BM_ELEM_SEAM);
-}
-
-static bool sculpt_face_sets_init_crease_test(
- BMesh *bm, BMFace *UNUSED(from_f), BMEdge *from_e, BMFace *UNUSED(to_f), const float threshold)
-{
- return BM_elem_float_data_get(&bm->edata, from_e, CD_CREASE) < threshold;
-}
-
-static bool sculpt_face_sets_init_bevel_weight_test(
- BMesh *bm, BMFace *UNUSED(from_f), BMEdge *from_e, BMFace *UNUSED(to_f), const float threshold)
-{
- return BM_elem_float_data_get(&bm->edata, from_e, CD_BWEIGHT) < threshold;
-}
-
-static bool sculpt_face_sets_init_sharp_edges_test(BMesh *UNUSED(bm),
- BMFace *UNUSED(from_f),
- BMEdge *from_e,
- BMFace *UNUSED(to_f),
- const float UNUSED(threshold))
-{
- return BM_elem_flag_test(from_e, BM_ELEM_SMOOTH);
-}
-
-static void sculpt_face_sets_init_flood_fill(Object *ob,
- face_sets_flood_fill_test test,
- const float threshold)
-{
- SculptSession *ss = ob->sculpt;
- Mesh *mesh = ob->data;
- BMesh *bm;
- const BMAllocTemplate allocsize = BMALLOC_TEMPLATE_FROM_ME(mesh);
- bm = BM_mesh_create(&allocsize,
- &((struct BMeshCreateParams){
- .use_toolflags = true,
- }));
-
- BM_mesh_bm_from_me(bm,
- mesh,
- (&(struct BMeshFromMeshParams){
- .calc_face_normal = true,
- }));
-
- bool *visited_faces = MEM_callocN(sizeof(bool) * mesh->totpoly, "visited faces");
- const int totfaces = mesh->totpoly;
-
- int *face_sets = ss->face_sets;
-
- BM_mesh_elem_table_init(bm, BM_FACE);
- BM_mesh_elem_table_ensure(bm, BM_FACE);
-
- int next_face_set = 1;
-
- for (int i = 0; i < totfaces; i++) {
- if (!visited_faces[i]) {
- GSQueue *queue;
- queue = BLI_gsqueue_new(sizeof(int));
-
- face_sets[i] = next_face_set;
- visited_faces[i] = true;
- BLI_gsqueue_push(queue, &i);
-
- while (!BLI_gsqueue_is_empty(queue)) {
- int from_f;
- BLI_gsqueue_pop(queue, &from_f);
-
- BMFace *f, *f_neighbor;
- BMEdge *ed;
- BMIter iter_a, iter_b;
-
- f = BM_face_at_index(bm, from_f);
-
- BM_ITER_ELEM (ed, &iter_a, f, BM_EDGES_OF_FACE) {
- BM_ITER_ELEM (f_neighbor, &iter_b, ed, BM_FACES_OF_EDGE) {
- if (f_neighbor != f) {
- int neighbor_face_index = BM_elem_index_get(f_neighbor);
- if (!visited_faces[neighbor_face_index]) {
- if (test(bm, f, ed, f_neighbor, threshold)) {
- face_sets[neighbor_face_index] = next_face_set;
- visited_faces[neighbor_face_index] = true;
- BLI_gsqueue_push(queue, &neighbor_face_index);
- }
- }
- }
- }
- }
- }
-
- next_face_set += 1;
-
- BLI_gsqueue_free(queue);
- }
- }
-
- MEM_SAFE_FREE(visited_faces);
-
- BM_mesh_free(bm);
-}
-
-static void sculpt_face_sets_init_loop(Object *ob, const int mode)
-{
- Mesh *mesh = ob->data;
- SculptSession *ss = ob->sculpt;
- BMesh *bm;
- const BMAllocTemplate allocsize = BMALLOC_TEMPLATE_FROM_ME(mesh);
- bm = BM_mesh_create(&allocsize,
- &((struct BMeshCreateParams){
- .use_toolflags = true,
- }));
-
- BM_mesh_bm_from_me(bm,
- mesh,
- (&(struct BMeshFromMeshParams){
- .calc_face_normal = true,
- }));
- BMIter iter;
- BMFace *f;
-
- const int cd_fmaps_offset = CustomData_get_offset(&bm->pdata, CD_FACEMAP);
-
- BM_ITER_MESH (f, &iter, bm, BM_FACES_OF_MESH) {
- if (mode == SCULPT_FACE_SETS_FROM_MATERIALS) {
- ss->face_sets[BM_elem_index_get(f)] = (int)(f->mat_nr + 1);
- }
- else if (mode == SCULPT_FACE_SETS_FROM_FACE_MAPS) {
- if (cd_fmaps_offset != -1) {
- ss->face_sets[BM_elem_index_get(f)] = BM_ELEM_CD_GET_INT(f, cd_fmaps_offset) + 2;
- }
- else {
- ss->face_sets[BM_elem_index_get(f)] = 1;
- }
- }
- }
- BM_mesh_free(bm);
-}
-
-static int sculpt_face_set_init_invoke(bContext *C, wmOperator *op, const wmEvent *UNUSED(event))
-{
- Object *ob = CTX_data_active_object(C);
- SculptSession *ss = ob->sculpt;
- ARegion *region = CTX_wm_region(C);
- Depsgraph *depsgraph = CTX_data_depsgraph_pointer(C);
-
- const int mode = RNA_enum_get(op->ptr, "mode");
-
- /* Dyntopo and Multires not supported for now. */
- if (BKE_pbvh_type(ss->pbvh) != PBVH_FACES) {
- return OPERATOR_CANCELLED;
- }
-
- BKE_sculpt_update_object_for_edit(depsgraph, ob, true, false);
-
- PBVH *pbvh = ob->sculpt->pbvh;
- PBVHNode **nodes;
- int totnode;
- BKE_pbvh_search_gather(pbvh, NULL, NULL, &nodes, &totnode);
-
- if (!nodes) {
- return OPERATOR_CANCELLED;
- }
-
- SCULPT_undo_push_begin("face set change");
- SCULPT_undo_push_node(ob, nodes[0], SCULPT_UNDO_FACE_SETS);
-
- const float threshold = RNA_float_get(op->ptr, "threshold");
-
- switch (mode) {
- case SCULPT_FACE_SETS_FROM_LOOSE_PARTS:
- sculpt_face_sets_init_flood_fill(ob, sculpt_face_sets_init_loose_parts_test, threshold);
- break;
- case SCULPT_FACE_SETS_FROM_MATERIALS:
- sculpt_face_sets_init_loop(ob, SCULPT_FACE_SETS_FROM_MATERIALS);
- break;
- case SCULPT_FACE_SETS_FROM_NORMALS:
- sculpt_face_sets_init_flood_fill(ob, sculpt_face_sets_init_normals_test, threshold);
- break;
- case SCULPT_FACE_SETS_FROM_UV_SEAMS:
- sculpt_face_sets_init_flood_fill(ob, sculpt_face_sets_init_uv_seams_test, threshold);
- break;
- case SCULPT_FACE_SETS_FROM_CREASES:
- sculpt_face_sets_init_flood_fill(ob, sculpt_face_sets_init_crease_test, threshold);
- break;
- case SCULPT_FACE_SETS_FROM_SHARP_EDGES:
- sculpt_face_sets_init_flood_fill(ob, sculpt_face_sets_init_sharp_edges_test, threshold);
- break;
- case SCULPT_FACE_SETS_FROM_BEVEL_WEIGHT:
- sculpt_face_sets_init_flood_fill(ob, sculpt_face_sets_init_bevel_weight_test, threshold);
- break;
- case SCULPT_FACE_SETS_FROM_FACE_MAPS:
- sculpt_face_sets_init_loop(ob, SCULPT_FACE_SETS_FROM_FACE_MAPS);
- break;
- }
-
- SCULPT_undo_push_end();
-
- /* Sync face sets visibility and vertex visibility as now all Face Sets are visible. */
- SCULPT_visibility_sync_all_face_sets_to_vertices(ss);
-
- for (int i = 0; i < totnode; i++) {
- BKE_pbvh_node_mark_update_visibility(nodes[i]);
- }
-
- BKE_pbvh_update_vertex_data(ss->pbvh, PBVH_UpdateVisibility);
-
- MEM_SAFE_FREE(nodes);
-
- if (BKE_pbvh_type(pbvh) == PBVH_FACES) {
- BKE_mesh_flush_hidden_from_verts(ob->data);
- }
-
- ED_region_tag_redraw(region);
- DEG_id_tag_update(&ob->id, ID_RECALC_SHADING);
-
- View3D *v3d = CTX_wm_view3d(C);
- if (!BKE_sculptsession_use_pbvh_draw(ob, v3d)) {
- DEG_id_tag_update(&ob->id, ID_RECALC_GEOMETRY);
- }
-
- return OPERATOR_FINISHED;
-}
-
-static void SCULPT_OT_face_sets_init(wmOperatorType *ot)
-{
- /* identifiers */
- ot->name = "Init Face Sets";
- ot->idname = "SCULPT_OT_face_sets_init";
- ot->description = "Initializes all Face Sets in the mesh";
-
- /* api callbacks */
- ot->invoke = sculpt_face_set_init_invoke;
- ot->poll = SCULPT_mode_poll;
-
- ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
-
- RNA_def_enum(
- ot->srna, "mode", prop_sculpt_face_sets_init_types, SCULPT_FACE_SET_MASKED, "Mode", "");
- RNA_def_float(
- ot->srna,
- "threshold",
- 0.5f,
- 0.0f,
- 1.0f,
- "Threshold",
- "Minimum value to consider a certain atribute a boundary when creating the Face Sets",
- 0.0f,
- 1.0f);
-}
-
-typedef enum eSculptFaceGroupVisibilityModes {
- SCULPT_FACE_SET_VISIBILITY_TOGGLE = 0,
- SCULPT_FACE_SET_VISIBILITY_SHOW_ACTIVE = 1,
- SCULPT_FACE_SET_VISIBILITY_HIDE_ACTIVE = 2,
- SCULPT_FACE_SET_VISIBILITY_INVERT = 3,
- SCULPT_FACE_SET_VISIBILITY_SHOW_ALL = 4,
-} eSculptFaceGroupVisibilityModes;
-
-static EnumPropertyItem prop_sculpt_face_sets_change_visibility_types[] = {
- {
- SCULPT_FACE_SET_VISIBILITY_TOGGLE,
- "TOGGLE",
- 0,
- "Toggle Visibility",
- "Hide all Face Sets except for the active one",
- },
- {
- SCULPT_FACE_SET_VISIBILITY_SHOW_ACTIVE,
- "SHOW_ACTIVE",
- 0,
- "Show Active Face Set",
- "Show Active Face Set",
- },
- {
- SCULPT_FACE_SET_VISIBILITY_HIDE_ACTIVE,
- "HIDE_ACTIVE",
- 0,
- "Hide Active Face Sets",
- "Hide Active Face Sets",
- },
- {
- SCULPT_FACE_SET_VISIBILITY_INVERT,
- "INVERT",
- 0,
- "Invert Face Set Visibility",
- "Invert Face Set Visibility",
- },
- {
- SCULPT_FACE_SET_VISIBILITY_SHOW_ALL,
- "SHOW_ALL",
- 0,
- "Show All Face Sets",
- "Show All Face Sets",
- },
- {0, NULL, 0, NULL, NULL},
-};
-
-static int sculpt_face_sets_change_visibility_invoke(bContext *C,
- wmOperator *op,
- const wmEvent *UNUSED(event))
-{
- Object *ob = CTX_data_active_object(C);
- SculptSession *ss = ob->sculpt;
- ARegion *region = CTX_wm_region(C);
- Depsgraph *depsgraph = CTX_data_depsgraph_pointer(C);
-
- /* Dyntopo and Multires not supported for now. */
- if (BKE_pbvh_type(ss->pbvh) != PBVH_FACES) {
- return OPERATOR_CANCELLED;
- }
-
- BKE_sculpt_update_object_for_edit(depsgraph, ob, true, true);
-
- const int tot_vert = SCULPT_vertex_count_get(ss);
- const int mode = RNA_enum_get(op->ptr, "mode");
- int active_vertex_index = SCULPT_active_vertex_get(ss);
- int active_face_set = SCULPT_vertex_face_set_get(ss, active_vertex_index);
-
- SCULPT_undo_push_begin("Hide area");
-
- PBVH *pbvh = ob->sculpt->pbvh;
- PBVHNode **nodes;
- int totnode;
-
- BKE_pbvh_search_gather(pbvh, NULL, NULL, &nodes, &totnode);
-
- if (totnode == 0) {
- MEM_SAFE_FREE(nodes);
- return OPERATOR_CANCELLED;
- }
-
- SCULPT_undo_push_node(ob, nodes[0], SCULPT_UNDO_FACE_SETS);
-
- if (mode == SCULPT_FACE_SET_VISIBILITY_TOGGLE) {
- bool hidden_vertex = false;
-
- /* This can fail with regular meshes with non-manifold geometry as the visibility state can't
- * be synced from face sets to non-manifold vertices. */
- if (BKE_pbvh_type(ss->pbvh) == PBVH_GRIDS) {
- for (int i = 0; i < tot_vert; i++) {
- if (!SCULPT_vertex_visible_get(ss, i)) {
- hidden_vertex = true;
- break;
- }
- }
- }
-
- for (int i = 0; i < ss->totpoly; i++) {
- if (ss->face_sets[i] <= 0) {
- hidden_vertex = true;
- break;
- }
- }
-
- if (hidden_vertex) {
- SCULPT_face_sets_visibility_all_set(ss, true);
- }
- else {
- SCULPT_face_sets_visibility_all_set(ss, false);
- SCULPT_face_set_visibility_set(ss, active_face_set, true);
- }
- }
-
- if (mode == SCULPT_FACE_SET_VISIBILITY_SHOW_ALL) {
- SCULPT_face_sets_visibility_all_set(ss, true);
- }
-
- if (mode == SCULPT_FACE_SET_VISIBILITY_SHOW_ACTIVE) {
- SCULPT_face_sets_visibility_all_set(ss, false);
- SCULPT_face_set_visibility_set(ss, active_face_set, true);
- for (int i = 0; i < tot_vert; i++) {
- SCULPT_vertex_visible_set(ss,
- i,
- SCULPT_vertex_visible_get(ss, i) &&
- SCULPT_vertex_has_face_set(ss, i, active_face_set));
- }
- }
-
- if (mode == SCULPT_FACE_SET_VISIBILITY_HIDE_ACTIVE) {
- SCULPT_face_set_visibility_set(ss, active_face_set, false);
- }
-
- if (mode == SCULPT_FACE_SET_VISIBILITY_INVERT) {
- SCULPT_face_sets_visibility_invert(ss);
- }
-
- /* For modes that use the cursor active vertex, update the rotation origin for viewport
- * navigation. */
- if (ELEM(mode, SCULPT_FACE_SET_VISIBILITY_TOGGLE, SCULPT_FACE_SET_VISIBILITY_SHOW_ACTIVE)) {
- UnifiedPaintSettings *ups = &CTX_data_tool_settings(C)->unified_paint_settings;
- float location[3];
- copy_v3_v3(location, SCULPT_active_vertex_co_get(ss));
- mul_m4_v3(ob->obmat, location);
- copy_v3_v3(ups->average_stroke_accum, location);
- ups->average_stroke_counter = 1;
- ups->last_stroke_valid = true;
- }
-
- /* Sync face sets visibility and vertex visibility. */
- SCULPT_visibility_sync_all_face_sets_to_vertices(ss);
-
- SCULPT_undo_push_end();
-
- for (int i = 0; i < totnode; i++) {
- BKE_pbvh_node_mark_update_visibility(nodes[i]);
- }
-
- BKE_pbvh_update_vertex_data(ss->pbvh, PBVH_UpdateVisibility);
-
- MEM_SAFE_FREE(nodes);
-
- if (BKE_pbvh_type(pbvh) == PBVH_FACES) {
- BKE_mesh_flush_hidden_from_verts(ob->data);
- }
-
- ED_region_tag_redraw(region);
- DEG_id_tag_update(&ob->id, ID_RECALC_SHADING);
-
- View3D *v3d = CTX_wm_view3d(C);
- if (!BKE_sculptsession_use_pbvh_draw(ob, v3d)) {
- DEG_id_tag_update(&ob->id, ID_RECALC_GEOMETRY);
- }
- return OPERATOR_FINISHED;
-}
-
-static void SCULPT_OT_face_sets_change_visibility(wmOperatorType *ot)
-{
- /* Identifiers. */
- ot->name = "Face Sets Visibility";
- ot->idname = "SCULPT_OT_face_set_change_visibility";
- ot->description = "Change the visibility of the Face Sets of the sculpt";
-
- /* Api callbacks. */
- ot->invoke = sculpt_face_sets_change_visibility_invoke;
- ot->poll = SCULPT_mode_poll;
-
- ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
-
- RNA_def_enum(ot->srna,
- "mode",
- prop_sculpt_face_sets_change_visibility_types,
- SCULPT_FACE_SET_VISIBILITY_TOGGLE,
- "Mode",
- "");
-}
-
-static int sculpt_face_sets_randomize_colors_invoke(bContext *C,
- wmOperator *UNUSED(op),
- const wmEvent *UNUSED(event))
-{
-
- Object *ob = CTX_data_active_object(C);
- SculptSession *ss = ob->sculpt;
- ARegion *region = CTX_wm_region(C);
-
- /* Dyntopo and Multires not supported for now. */
- if (BKE_pbvh_type(ss->pbvh) != PBVH_FACES) {
- return OPERATOR_CANCELLED;
- }
-
- PBVH *pbvh = ob->sculpt->pbvh;
- PBVHNode **nodes;
- int totnode;
- Mesh *mesh = ob->data;
-
- mesh->face_sets_color_seed += 1;
- if (ss->face_sets) {
- const int random_index = clamp_i(
- ss->totpoly * BLI_hash_int_01(mesh->face_sets_color_seed), 0, max_ii(0, ss->totpoly - 1));
- mesh->face_sets_color_default = ss->face_sets[random_index];
- }
- BKE_pbvh_face_sets_color_set(pbvh, mesh->face_sets_color_seed, mesh->face_sets_color_default);
-
- BKE_pbvh_search_gather(pbvh, NULL, NULL, &nodes, &totnode);
- for (int i = 0; i < totnode; i++) {
- BKE_pbvh_node_mark_redraw(nodes[i]);
- }
-
- MEM_SAFE_FREE(nodes);
-
- View3D *v3d = CTX_wm_view3d(C);
- if (!BKE_sculptsession_use_pbvh_draw(ob, v3d)) {
- DEG_id_tag_update(&ob->id, ID_RECALC_SHADING);
- }
-
- ED_region_tag_redraw(region);
- WM_event_add_notifier(C, NC_GEOM | ND_DATA, ob->data);
-
- return OPERATOR_FINISHED;
-}
-
-static void SCULPT_OT_face_sets_randomize_colors(wmOperatorType *ot)
-{
- /* Identifiers. */
- ot->name = "Randomize Face Sets Colors";
- ot->idname = "SCULPT_OT_face_sets_randomize_colors";
- ot->description = "Generates a new set of random colors to render the Face Sets in the viewport";
-
- /* Api callbacks. */
- ot->invoke = sculpt_face_sets_randomize_colors_invoke;
- ot->poll = SCULPT_mode_poll;
-
- ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
-}
void ED_operatortypes_sculpt(void)
{
@@ -11831,4 +7906,5 @@ void ED_operatortypes_sculpt(void)
WM_operatortype_append(SCULPT_OT_face_sets_change_visibility);
WM_operatortype_append(SCULPT_OT_face_sets_randomize_colors);
WM_operatortype_append(SCULPT_OT_face_sets_init);
+ WM_operatortype_append(SCULPT_OT_cloth_filter);
}
diff --git a/source/blender/editors/sculpt_paint/sculpt_automasking.c b/source/blender/editors/sculpt_paint/sculpt_automasking.c
new file mode 100644
index 00000000000..bfa657147fd
--- /dev/null
+++ b/source/blender/editors/sculpt_paint/sculpt_automasking.c
@@ -0,0 +1,304 @@
+/*
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * The Original Code is Copyright (C) 2020 Blender Foundation.
+ * All rights reserved.
+ */
+
+/** \file
+ * \ingroup edsculpt
+ */
+
+#include "MEM_guardedalloc.h"
+
+#include "BLI_blenlib.h"
+#include "BLI_hash.h"
+#include "BLI_math.h"
+#include "BLI_task.h"
+
+#include "DNA_brush_types.h"
+#include "DNA_mesh_types.h"
+#include "DNA_meshdata_types.h"
+
+#include "BKE_brush.h"
+#include "BKE_context.h"
+#include "BKE_mesh.h"
+#include "BKE_mesh_mapping.h"
+#include "BKE_object.h"
+#include "BKE_paint.h"
+#include "BKE_pbvh.h"
+#include "BKE_scene.h"
+
+#include "DEG_depsgraph.h"
+
+#include "WM_api.h"
+#include "WM_message.h"
+#include "WM_toolsystem.h"
+#include "WM_types.h"
+
+#include "ED_object.h"
+#include "ED_screen.h"
+#include "ED_sculpt.h"
+#include "paint_intern.h"
+#include "sculpt_intern.h"
+
+#include "RNA_access.h"
+#include "RNA_define.h"
+
+#include "bmesh.h"
+
+#include <math.h>
+#include <stdlib.h>
+
+bool SCULPT_is_automasking_mode_enabled(const Sculpt *sd,
+ const Brush *br,
+ const eAutomasking_flag mode)
+{
+ return br->automasking_flags & mode || sd->automasking_flags & mode;
+}
+
+bool SCULPT_is_automasking_enabled(const Sculpt *sd, const SculptSession *ss, const Brush *br)
+{
+ if (SCULPT_stroke_is_dynamic_topology(ss, br)) {
+ return false;
+ }
+ if (SCULPT_is_automasking_mode_enabled(sd, br, BRUSH_AUTOMASKING_TOPOLOGY)) {
+ return true;
+ }
+ if (SCULPT_is_automasking_mode_enabled(sd, br, BRUSH_AUTOMASKING_FACE_SETS)) {
+ return true;
+ }
+ if (SCULPT_is_automasking_mode_enabled(sd, br, BRUSH_AUTOMASKING_BOUNDARY_EDGES)) {
+ return true;
+ }
+ if (SCULPT_is_automasking_mode_enabled(sd, br, BRUSH_AUTOMASKING_BOUNDARY_FACE_SETS)) {
+ return true;
+ }
+ return false;
+}
+
+float SCULPT_automasking_factor_get(SculptSession *ss, int vert)
+{
+ if (ss->cache && ss->cache->automask) {
+ return ss->cache->automask[vert];
+ }
+ else {
+ return 1.0f;
+ }
+}
+
+void SCULPT_automasking_end(Object *ob)
+{
+ SculptSession *ss = ob->sculpt;
+ if (ss->cache && ss->cache->automask) {
+ MEM_freeN(ss->cache->automask);
+ }
+}
+
+static bool sculpt_automasking_is_constrained_by_radius(Brush *br)
+{
+ /* 2D falloff is not constrained by radius. */
+ if (br->falloff_shape == PAINT_FALLOFF_SHAPE_TUBE) {
+ return false;
+ }
+
+ if (ELEM(br->sculpt_tool, SCULPT_TOOL_GRAB, SCULPT_TOOL_THUMB, SCULPT_TOOL_ROTATE)) {
+ return true;
+ }
+ return false;
+}
+
+typedef struct AutomaskFloodFillData {
+ float *automask_factor;
+ float radius;
+ bool use_radius;
+ float location[3];
+ char symm;
+} AutomaskFloodFillData;
+
+static bool automask_floodfill_cb(
+ SculptSession *ss, int UNUSED(from_v), int to_v, bool UNUSED(is_duplicate), void *userdata)
+{
+ AutomaskFloodFillData *data = userdata;
+
+ data->automask_factor[to_v] = 1.0f;
+ return (!data->use_radius ||
+ SCULPT_is_vertex_inside_brush_radius_symm(
+ SCULPT_vertex_co_get(ss, to_v), data->location, data->radius, data->symm));
+}
+
+static float *SCULPT_topology_automasking_init(Sculpt *sd, Object *ob, float *automask_factor)
+{
+ SculptSession *ss = ob->sculpt;
+ Brush *brush = BKE_paint_brush(&sd->paint);
+
+ if (!SCULPT_is_automasking_enabled(sd, ss, brush)) {
+ return NULL;
+ }
+
+ if (BKE_pbvh_type(ss->pbvh) == PBVH_FACES && !ss->pmap) {
+ BLI_assert(!"Topology masking: pmap missing");
+ return NULL;
+ }
+
+ const int totvert = SCULPT_vertex_count_get(ss);
+ for (int i = 0; i < totvert; i++) {
+ ss->cache->automask[i] = 0.0f;
+ }
+
+ /* Flood fill automask to connected vertices. Limited to vertices inside
+ * the brush radius if the tool requires it. */
+ SculptFloodFill flood;
+ SCULPT_floodfill_init(ss, &flood);
+ SCULPT_floodfill_add_active(sd, ob, ss, &flood, ss->cache->radius);
+
+ AutomaskFloodFillData fdata = {
+ .automask_factor = automask_factor,
+ .radius = ss->cache->radius,
+ .use_radius = sculpt_automasking_is_constrained_by_radius(brush),
+ .symm = sd->paint.symmetry_flags & PAINT_SYMM_AXIS_ALL,
+ };
+ copy_v3_v3(fdata.location, SCULPT_active_vertex_co_get(ss));
+ SCULPT_floodfill_execute(ss, &flood, automask_floodfill_cb, &fdata);
+ SCULPT_floodfill_free(&flood);
+
+ return automask_factor;
+}
+
+static float *sculpt_face_sets_automasking_init(Sculpt *sd, Object *ob, float *automask_factor)
+{
+ SculptSession *ss = ob->sculpt;
+ Brush *brush = BKE_paint_brush(&sd->paint);
+
+ if (!SCULPT_is_automasking_enabled(sd, ss, brush)) {
+ return NULL;
+ }
+
+ if (BKE_pbvh_type(ss->pbvh) == PBVH_FACES && !ss->pmap) {
+ BLI_assert(!"Face Sets automasking: pmap missing");
+ return NULL;
+ }
+
+ int tot_vert = SCULPT_vertex_count_get(ss);
+ int active_face_set = SCULPT_active_face_set_get(ss);
+ for (int i = 0; i < tot_vert; i++) {
+ if (!SCULPT_vertex_has_face_set(ss, i, active_face_set)) {
+ automask_factor[i] *= 0.0f;
+ }
+ }
+
+ return automask_factor;
+}
+
+#define EDGE_DISTANCE_INF -1
+
+float *SCULPT_boundary_automasking_init(Object *ob,
+ eBoundaryAutomaskMode mode,
+ int propagation_steps,
+ float *automask_factor)
+{
+ SculptSession *ss = ob->sculpt;
+
+ if (BKE_pbvh_type(ss->pbvh) == PBVH_FACES && !ss->pmap) {
+ BLI_assert(!"Boundary Edges masking: pmap missing");
+ return NULL;
+ }
+
+ const int totvert = SCULPT_vertex_count_get(ss);
+ int *edge_distance = MEM_callocN(sizeof(int) * totvert, "automask_factor");
+
+ for (int i = 0; i < totvert; i++) {
+ edge_distance[i] = EDGE_DISTANCE_INF;
+ switch (mode) {
+ case AUTOMASK_INIT_BOUNDARY_EDGES:
+ if (!SCULPT_vertex_is_boundary(ss, i)) {
+ edge_distance[i] = 0;
+ }
+ break;
+ case AUTOMASK_INIT_BOUNDARY_FACE_SETS:
+ if (!SCULPT_vertex_has_unique_face_set(ss, i)) {
+ edge_distance[i] = 0;
+ }
+ break;
+ }
+ }
+
+ for (int propagation_it = 0; propagation_it < propagation_steps; propagation_it++) {
+ for (int i = 0; i < totvert; i++) {
+ if (edge_distance[i] == EDGE_DISTANCE_INF) {
+ SculptVertexNeighborIter ni;
+ SCULPT_VERTEX_NEIGHBORS_ITER_BEGIN (ss, i, ni) {
+ if (edge_distance[ni.index] == propagation_it) {
+ edge_distance[i] = propagation_it + 1;
+ }
+ }
+ SCULPT_VERTEX_NEIGHBORS_ITER_END(ni);
+ }
+ }
+ }
+
+ for (int i = 0; i < totvert; i++) {
+ if (edge_distance[i] != EDGE_DISTANCE_INF) {
+ const float p = 1.0f - ((float)edge_distance[i] / (float)propagation_steps);
+ const float edge_boundary_automask = pow2f(p);
+ automask_factor[i] *= (1.0f - edge_boundary_automask);
+ }
+ }
+
+ MEM_SAFE_FREE(edge_distance);
+ return automask_factor;
+}
+
+void SCULPT_automasking_init(Sculpt *sd, Object *ob)
+{
+ SculptSession *ss = ob->sculpt;
+ Brush *brush = BKE_paint_brush(&sd->paint);
+ const int totvert = SCULPT_vertex_count_get(ss);
+
+ if (!SCULPT_is_automasking_enabled(sd, ss, brush)) {
+ return;
+ }
+
+ ss->cache->automask = MEM_callocN(sizeof(float) * SCULPT_vertex_count_get(ss),
+ "automask_factor");
+
+ for (int i = 0; i < totvert; i++) {
+ ss->cache->automask[i] = 1.0f;
+ }
+
+ if (SCULPT_is_automasking_mode_enabled(sd, brush, BRUSH_AUTOMASKING_TOPOLOGY)) {
+ SCULPT_vertex_random_access_init(ss);
+ SCULPT_topology_automasking_init(sd, ob, ss->cache->automask);
+ }
+ if (SCULPT_is_automasking_mode_enabled(sd, brush, BRUSH_AUTOMASKING_FACE_SETS)) {
+ SCULPT_vertex_random_access_init(ss);
+ sculpt_face_sets_automasking_init(sd, ob, ss->cache->automask);
+ }
+
+ if (SCULPT_is_automasking_mode_enabled(sd, brush, BRUSH_AUTOMASKING_BOUNDARY_EDGES)) {
+ SCULPT_vertex_random_access_init(ss);
+ SCULPT_boundary_automasking_init(ob,
+ AUTOMASK_INIT_BOUNDARY_EDGES,
+ brush->automasking_boundary_edges_propagation_steps,
+ ss->cache->automask);
+ }
+ if (SCULPT_is_automasking_mode_enabled(sd, brush, BRUSH_AUTOMASKING_BOUNDARY_FACE_SETS)) {
+ SCULPT_vertex_random_access_init(ss);
+ SCULPT_boundary_automasking_init(ob,
+ AUTOMASK_INIT_BOUNDARY_FACE_SETS,
+ brush->automasking_boundary_edges_propagation_steps,
+ ss->cache->automask);
+ }
+}
diff --git a/source/blender/editors/sculpt_paint/sculpt_cloth.c b/source/blender/editors/sculpt_paint/sculpt_cloth.c
index 12aaf756cf3..3203282c30c 100644
--- a/source/blender/editors/sculpt_paint/sculpt_cloth.c
+++ b/source/blender/editors/sculpt_paint/sculpt_cloth.c
@@ -10,7 +10,7 @@
* 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,
+ * along with this program; if not, write to the Free Software Foundation,
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*
* The Original Code is Copyright (C) 2020 Blender Foundation.
@@ -106,9 +106,11 @@
#define CLOTH_MAX_CONSTRAINTS_PER_VERTEX 1024
#define CLOTH_SIMULATION_TIME_STEP 0.01f
-static void cloth_brush_add_length_constraint(SculptSession *ss, const int v1, const int v2)
+static void cloth_brush_add_length_constraint(SculptSession *ss,
+ SculptClothSimulation *cloth_sim,
+ const int v1,
+ const int v2)
{
- SculptClothSimulation *cloth_sim = ss->cache->cloth_sim;
cloth_sim->length_constraints[cloth_sim->tot_length_constraints].v1 = v1;
cloth_sim->length_constraints[cloth_sim->tot_length_constraints].v2 = v2;
cloth_sim->length_constraints[cloth_sim->tot_length_constraints].length = len_v3v3(
@@ -133,24 +135,22 @@ static void do_cloth_brush_build_constraints_task_cb_ex(
SculptSession *ss = data->ob->sculpt;
PBVHVertexIter vd;
- const float radius = ss->cache->initial_radius;
- const float limit = radius + (radius * data->brush->cloth_sim_limit);
BKE_pbvh_vertex_iter_begin(ss->pbvh, data->nodes[n], vd, PBVH_ITER_UNIQUE)
{
- if (len_squared_v3v3(vd.co, ss->cache->initial_location) < limit * limit) {
+ if (len_squared_v3v3(vd.co, data->cloth_sim_initial_location) <
+ data->cloth_sim_radius * data->cloth_sim_radius) {
SculptVertexNeighborIter ni;
int build_indices[CLOTH_MAX_CONSTRAINTS_PER_VERTEX];
int tot_indices = 0;
build_indices[tot_indices] = vd.index;
tot_indices++;
- sculpt_vertex_neighbors_iter_begin(ss, vd.index, ni)
- {
+ SCULPT_VERTEX_NEIGHBORS_ITER_BEGIN (ss, vd.index, ni) {
build_indices[tot_indices] = ni.index;
tot_indices++;
}
- sculpt_vertex_neighbors_iter_end(ni);
+ SCULPT_VERTEX_NEIGHBORS_ITER_END(ni);
/* As we don't know the order of the neighbor vertices, we create all possible combinations
* between the neighbor and the original vertex as length constraints. */
@@ -160,7 +160,8 @@ static void do_cloth_brush_build_constraints_task_cb_ex(
for (int c_i = 0; c_i < tot_indices; c_i++) {
for (int c_j = 0; c_j < tot_indices; c_j++) {
if (c_i != c_j) {
- cloth_brush_add_length_constraint(ss, build_indices[c_i], build_indices[c_j]);
+ cloth_brush_add_length_constraint(
+ ss, data->cloth_sim, build_indices[c_i], build_indices[c_j]);
}
}
}
@@ -193,11 +194,11 @@ static float cloth_brush_simulation_falloff_get(const Brush *brush,
}
}
-static void cloth_brush_apply_force_to_vertex(SculptSession *ss,
+static void cloth_brush_apply_force_to_vertex(SculptSession *UNUSED(ss),
+ SculptClothSimulation *cloth_sim,
const float force[3],
const int vertex_index)
{
- SculptClothSimulation *cloth_sim = ss->cache->cloth_sim;
madd_v3_v3fl(cloth_sim->acceleration[vertex_index], force, 1.0f / cloth_sim->mass);
}
@@ -213,8 +214,9 @@ static void do_cloth_brush_apply_forces_task_cb_ex(void *__restrict userdata,
const float *grab_delta = data->grab_delta;
float(*imat)[4] = data->mat;
- const bool use_falloff_plane = brush->cloth_force_falloff_type ==
- BRUSH_CLOTH_FORCE_FALLOFF_PLANE;
+ const bool use_falloff_plane = !SCULPT_is_cloth_deform_brush(brush) &&
+ brush->cloth_force_falloff_type ==
+ BRUSH_CLOTH_FORCE_FALLOFF_PLANE;
PBVHVertexIter vd;
const float bstrength = ss->cache->bstrength;
@@ -222,6 +224,7 @@ static void do_cloth_brush_apply_forces_task_cb_ex(void *__restrict userdata,
SculptBrushTest test;
SculptBrushTestFn sculpt_brush_test_sq_fn = SCULPT_brush_test_init_with_falloff_shape(
ss, &test, data->brush->falloff_shape);
+ const int thread_id = BLI_task_parallel_thread_id(tls);
/* For Pich Perpendicular Deform Type. */
float x_object_space[3];
@@ -246,14 +249,29 @@ static void do_cloth_brush_apply_forces_task_cb_ex(void *__restrict userdata,
gravity, ss->cache->gravity_direction, -ss->cache->radius * data->sd->gravity_factor);
}
+ /* Original data for deform brushes. */
+ SculptOrigVertData orig_data;
+ if (SCULPT_is_cloth_deform_brush(brush)) {
+ SCULPT_orig_vert_data_init(&orig_data, data->ob, data->nodes[n]);
+ }
+
BKE_pbvh_vertex_iter_begin(ss->pbvh, data->nodes[n], vd, PBVH_ITER_UNIQUE)
{
float force[3];
const float sim_factor = cloth_brush_simulation_falloff_get(
brush, ss->cache->radius, ss->cache->initial_location, cloth_sim->init_pos[vd.index]);
+ float current_vertex_location[3];
+ if (SCULPT_is_cloth_deform_brush(brush)) {
+ SCULPT_orig_vert_data_update(&orig_data, &vd);
+ copy_v3_v3(current_vertex_location, orig_data.co);
+ }
+ else {
+ copy_v3_v3(current_vertex_location, vd.co);
+ }
+
/* When using the plane falloff mode the falloff is not constrained by the brush radius. */
- if (sculpt_brush_test_sq_fn(&test, vd.co) || use_falloff_plane) {
+ if (sculpt_brush_test_sq_fn(&test, current_vertex_location) || use_falloff_plane) {
float dist = sqrtf(test.dist);
@@ -264,17 +282,16 @@ static void do_cloth_brush_apply_forces_task_cb_ex(void *__restrict userdata,
const float fade = sim_factor * bstrength *
SCULPT_brush_strength_factor(ss,
brush,
- vd.co,
+ current_vertex_location,
dist,
vd.no,
vd.fno,
vd.mask ? *vd.mask : 0.0f,
vd.index,
- tls->thread_id);
+ thread_id);
float brush_disp[3];
float normal[3];
-
if (vd.no) {
normal_short_to_float_v3(normal, vd.no);
}
@@ -293,7 +310,10 @@ static void do_cloth_brush_apply_forces_task_cb_ex(void *__restrict userdata,
mul_v3_v3fl(force, offset, -fade);
break;
case BRUSH_CLOTH_DEFORM_GRAB:
- mul_v3_v3fl(force, grab_delta, fade);
+ /* Grab writes the positions in the simulation directly without applying forces. */
+ madd_v3_v3v3fl(
+ cloth_sim->pos[vd.index], orig_data.co, ss->cache->grab_delta_symmetry, fade);
+ zero_v3(force);
break;
case BRUSH_CLOTH_DEFORM_PINCH_POINT:
if (use_falloff_plane) {
@@ -329,13 +349,15 @@ static void do_cloth_brush_apply_forces_task_cb_ex(void *__restrict userdata,
madd_v3_v3fl(force, gravity, fade);
- cloth_brush_apply_force_to_vertex(ss, force, vd.index);
+ cloth_brush_apply_force_to_vertex(ss, ss->cache->cloth_sim, force, vd.index);
}
}
BKE_pbvh_vertex_iter_end;
}
-static SculptClothSimulation *cloth_brush_simulation_create(SculptSession *ss, Brush *brush)
+static SculptClothSimulation *cloth_brush_simulation_create(SculptSession *ss,
+ const float cloth_mass,
+ const float cloth_damping)
{
const int totverts = SCULPT_vertex_count_get(ss);
SculptClothSimulation *cloth_sim;
@@ -354,8 +376,8 @@ static SculptClothSimulation *cloth_brush_simulation_create(SculptSession *ss, B
cloth_sim->length_constraint_tweak = MEM_callocN(sizeof(float) * totverts,
"cloth sim length tweak");
- cloth_sim->mass = brush->cloth_mass;
- cloth_sim->damping = brush->cloth_damping;
+ cloth_sim->mass = cloth_mass;
+ cloth_sim->damping = cloth_damping;
return cloth_sim;
}
@@ -367,12 +389,16 @@ static void do_cloth_brush_solve_simulation_task_cb_ex(
SculptSession *ss = data->ob->sculpt;
const Brush *brush = data->brush;
PBVHVertexIter vd;
- SculptClothSimulation *cloth_sim = ss->cache->cloth_sim;
+ SculptClothSimulation *cloth_sim = data->cloth_sim;
const float time_step = data->cloth_time_step;
BKE_pbvh_vertex_iter_begin(ss->pbvh, data->nodes[n], vd, PBVH_ITER_UNIQUE)
{
- const float sim_factor = cloth_brush_simulation_falloff_get(
- brush, ss->cache->radius, ss->cache->initial_location, cloth_sim->init_pos[vd.index]);
+ const float sim_factor = ss->cache ? cloth_brush_simulation_falloff_get(
+ brush,
+ ss->cache->radius,
+ ss->cache->initial_location,
+ cloth_sim->init_pos[vd.index]) :
+ 1.0f;
if (sim_factor > 0.0f) {
int i = vd.index;
float temp[3];
@@ -393,7 +419,7 @@ static void do_cloth_brush_solve_simulation_task_cb_ex(
copy_v3_fl(cloth_sim->acceleration[i], 0.0f);
- copy_v3_v3(vd.co, ss->cache->cloth_sim->pos[vd.index]);
+ copy_v3_v3(vd.co, cloth_sim->pos[vd.index]);
if (vd.mvert) {
vd.mvert->flag |= ME_VERT_PBVH_UPDATE;
}
@@ -405,7 +431,10 @@ static void do_cloth_brush_solve_simulation_task_cb_ex(
static void cloth_brush_build_nodes_constraints(Sculpt *sd,
Object *ob,
PBVHNode **nodes,
- int totnode)
+ int totnode,
+ SculptClothSimulation *cloth_sim,
+ float initial_location[3],
+ const float radius)
{
Brush *brush = BKE_paint_brush(&sd->paint);
@@ -413,7 +442,7 @@ static void cloth_brush_build_nodes_constraints(Sculpt *sd,
* storing the constraints per node. */
/* Currently all constrains are added to the same global array which can't be accessed from
* different threads. */
- PBVHParallelSettings settings;
+ TaskParallelSettings settings;
BKE_pbvh_parallel_range_settings(&settings, false, totnode);
SculptThreadedTaskData build_constraints_data = {
@@ -421,8 +450,11 @@ static void cloth_brush_build_nodes_constraints(Sculpt *sd,
.ob = ob,
.brush = brush,
.nodes = nodes,
+ .cloth_sim = cloth_sim,
+ .cloth_sim_initial_location = initial_location,
+ .cloth_sim_radius = radius,
};
- BKE_pbvh_parallel_range(
+ BLI_task_parallel_range(
0, totnode, &build_constraints_data, do_cloth_brush_build_constraints_task_cb_ex, &settings);
}
@@ -461,10 +493,18 @@ static void cloth_brush_satisfy_constraints(SculptSession *ss,
const float mask_v2 = (1.0f - SCULPT_vertex_mask_get(ss, v2)) *
SCULPT_automasking_factor_get(ss, v2);
- const float sim_factor_v1 = cloth_brush_simulation_falloff_get(
- brush, ss->cache->radius, ss->cache->initial_location, cloth_sim->init_pos[v1]);
- const float sim_factor_v2 = cloth_brush_simulation_falloff_get(
- brush, ss->cache->radius, ss->cache->initial_location, cloth_sim->init_pos[v2]);
+ const float sim_factor_v1 = ss->cache ? cloth_brush_simulation_falloff_get(
+ brush,
+ ss->cache->radius,
+ ss->cache->initial_location,
+ cloth_sim->init_pos[v1]) :
+ 1.0f;
+ const float sim_factor_v2 = ss->cache ? cloth_brush_simulation_falloff_get(
+ brush,
+ ss->cache->radius,
+ ss->cache->initial_location,
+ cloth_sim->init_pos[v2]) :
+ 1.0f;
madd_v3_v3fl(cloth_sim->pos[v1], correction_vector_half, 1.0f * mask_v1 * sim_factor_v1);
madd_v3_v3fl(cloth_sim->pos[v2], correction_vector_half, -1.0f * mask_v2 * sim_factor_v2);
@@ -472,13 +512,12 @@ static void cloth_brush_satisfy_constraints(SculptSession *ss,
}
}
-static void cloth_brush_do_simulation_step(Sculpt *sd, Object *ob, PBVHNode **nodes, int totnode)
+static void cloth_brush_do_simulation_step(
+ Sculpt *sd, Object *ob, SculptClothSimulation *cloth_sim, PBVHNode **nodes, int totnode)
{
SculptSession *ss = ob->sculpt;
Brush *brush = BKE_paint_brush(&sd->paint);
- SculptClothSimulation *cloth_sim = ss->cache->cloth_sim;
-
/* Update the constraints. */
cloth_brush_satisfy_constraints(ss, brush, cloth_sim);
@@ -489,11 +528,12 @@ static void cloth_brush_do_simulation_step(Sculpt *sd, Object *ob, PBVHNode **no
.brush = brush,
.nodes = nodes,
.cloth_time_step = CLOTH_SIMULATION_TIME_STEP,
+ .cloth_sim = cloth_sim,
};
- PBVHParallelSettings settings;
+ TaskParallelSettings settings;
BKE_pbvh_parallel_range_settings(&settings, (sd->flags & SCULPT_USE_OPENMP), totnode);
- BKE_pbvh_parallel_range(
+ BLI_task_parallel_range(
0, totnode, &solve_simulation_data, do_cloth_brush_solve_simulation_task_cb_ex, &settings);
}
@@ -566,9 +606,9 @@ static void cloth_brush_apply_brush_foces(Sculpt *sd, Object *ob, PBVHNode **nod
}
}
- PBVHParallelSettings settings;
+ TaskParallelSettings settings;
BKE_pbvh_parallel_range_settings(&settings, (sd->flags & SCULPT_USE_OPENMP), totnode);
- BKE_pbvh_parallel_range(
+ BLI_task_parallel_range(
0, totnode, &apply_forces_data, do_cloth_brush_apply_forces_task_cb_ex, &settings);
}
@@ -589,7 +629,8 @@ void SCULPT_do_cloth_brush(Sculpt *sd, Object *ob, PBVHNode **nodes, int totnode
/* The simulation structure only needs to be created on the first symmetry pass. */
if (ss->cache->mirror_symmetry_pass == 0) {
- ss->cache->cloth_sim = cloth_brush_simulation_create(ss, brush);
+ ss->cache->cloth_sim = cloth_brush_simulation_create(
+ ss, brush->cloth_mass, brush->cloth_damping);
for (int i = 0; i < totverts; i++) {
copy_v3_v3(ss->cache->cloth_sim->prev_pos[i], SCULPT_vertex_co_get(ss, i));
copy_v3_v3(ss->cache->cloth_sim->init_pos[i], SCULPT_vertex_co_get(ss, i));
@@ -597,7 +638,10 @@ void SCULPT_do_cloth_brush(Sculpt *sd, Object *ob, PBVHNode **nodes, int totnode
}
/* Build the constraints. */
- cloth_brush_build_nodes_constraints(sd, ob, nodes, totnode);
+ const float radius = ss->cache->initial_radius;
+ const float limit = radius + (radius * brush->cloth_sim_limit);
+ cloth_brush_build_nodes_constraints(
+ sd, ob, nodes, totnode, ss->cache->cloth_sim, ss->cache->location, limit);
return;
}
@@ -611,7 +655,7 @@ void SCULPT_do_cloth_brush(Sculpt *sd, Object *ob, PBVHNode **nodes, int totnode
cloth_brush_apply_brush_foces(sd, ob, nodes, totnode);
/* Update and write the simulation to the nodes. */
- cloth_brush_do_simulation_step(sd, ob, nodes, totnode);
+ cloth_brush_do_simulation_step(sd, ob, ss->cache->cloth_sim, nodes, totnode);
return;
}
@@ -687,3 +731,246 @@ void SCULPT_cloth_plane_falloff_preview_draw(const uint gpuattr,
immEnd();
}
+
+/* Cloth Filter. */
+
+typedef enum eSculpClothFilterType {
+ CLOTH_FILTER_GRAVITY,
+ CLOTH_FILTER_INFLATE,
+ CLOTH_FILTER_EXPAND,
+ CLOTH_FILTER_PINCH,
+} eSculptClothFilterType;
+
+static EnumPropertyItem prop_cloth_filter_type[] = {
+ {CLOTH_FILTER_GRAVITY, "GRAVITY", 0, "Gravity", "Applies gravity to the simulation"},
+ {CLOTH_FILTER_INFLATE, "INFLATE", 0, "Inflate", "Inflates the cloth"},
+ {CLOTH_FILTER_EXPAND, "EXPAND", 0, "Expand", "Expands the cloth's dimensions"},
+ {CLOTH_FILTER_PINCH,
+ "PINCH",
+ 0,
+ "Pinch",
+ "Pinches the cloth to the point were the cursor was when the filter started"},
+ {0, NULL, 0, NULL, NULL},
+};
+
+static void cloth_filter_apply_forces_task_cb(void *__restrict userdata,
+ const int i,
+ const TaskParallelTLS *__restrict UNUSED(tls))
+{
+ SculptThreadedTaskData *data = userdata;
+ Sculpt *sd = data->sd;
+ SculptSession *ss = data->ob->sculpt;
+ PBVHNode *node = data->nodes[i];
+
+ SculptClothSimulation *cloth_sim = ss->filter_cache->cloth_sim;
+ const int filter_type = data->filter_type;
+
+ float sculpt_gravity[3] = {0.0f};
+ if (sd->gravity_object) {
+ copy_v3_v3(sculpt_gravity, sd->gravity_object->obmat[2]);
+ }
+ else {
+ sculpt_gravity[2] = -1.0f;
+ }
+ mul_v3_fl(sculpt_gravity, sd->gravity_factor * data->filter_strength);
+
+ PBVHVertexIter vd;
+ BKE_pbvh_vertex_iter_begin(ss->pbvh, node, vd, PBVH_ITER_UNIQUE)
+ {
+ float fade = vd.mask ? *vd.mask : 0.0f;
+ fade = 1.0f - fade;
+ float force[3] = {0.0f, 0.0f, 0.0f};
+
+ if (ss->filter_cache->active_face_set != SCULPT_FACE_SET_NONE) {
+ if (!SCULPT_vertex_has_face_set(ss, vd.index, ss->filter_cache->active_face_set)) {
+ continue;
+ }
+ }
+
+ switch (filter_type) {
+ case CLOTH_FILTER_GRAVITY:
+ force[2] = -data->filter_strength * fade;
+ break;
+ case CLOTH_FILTER_INFLATE: {
+ float normal[3];
+ SCULPT_vertex_normal_get(ss, vd.index, normal);
+ mul_v3_v3fl(force, normal, fade * data->filter_strength);
+ } break;
+ case CLOTH_FILTER_EXPAND:
+ cloth_sim->length_constraint_tweak[vd.index] += fade * data->filter_strength * 0.01f;
+ zero_v3(force);
+ break;
+ case CLOTH_FILTER_PINCH:
+ sub_v3_v3v3(force, ss->filter_cache->cloth_sim_pinch_point, vd.co);
+ normalize_v3(force);
+ mul_v3_fl(force, fade * data->filter_strength);
+ break;
+ }
+
+ add_v3_v3(force, sculpt_gravity);
+
+ cloth_brush_apply_force_to_vertex(ss, cloth_sim, force, vd.index);
+ }
+ BKE_pbvh_vertex_iter_end;
+
+ BKE_pbvh_node_mark_update(node);
+}
+
+static int sculpt_cloth_filter_modal(bContext *C, wmOperator *op, const wmEvent *event)
+{
+ Object *ob = CTX_data_active_object(C);
+ Depsgraph *depsgraph = CTX_data_depsgraph_pointer(C);
+ SculptSession *ss = ob->sculpt;
+ Sculpt *sd = CTX_data_tool_settings(C)->sculpt;
+ int filter_type = RNA_enum_get(op->ptr, "type");
+ float filter_strength = RNA_float_get(op->ptr, "strength");
+
+ if (event->type == LEFTMOUSE && event->val == KM_RELEASE) {
+ SCULPT_filter_cache_free(ss);
+ SCULPT_undo_push_end();
+ SCULPT_flush_update_done(C, ob, SCULPT_UPDATE_COORDS);
+ return OPERATOR_FINISHED;
+ }
+
+ if (event->type != MOUSEMOVE) {
+ return OPERATOR_RUNNING_MODAL;
+ }
+
+ float len = event->prevclickx - event->mval[0];
+ filter_strength = filter_strength * -len * 0.001f * UI_DPI_FAC;
+
+ SCULPT_vertex_random_access_init(ss);
+
+ BKE_sculpt_update_object_for_edit(depsgraph, ob, true, true);
+
+ const int totverts = SCULPT_vertex_count_get(ss);
+ for (int i = 0; i < totverts; i++) {
+ copy_v3_v3(ss->filter_cache->cloth_sim->pos[i], SCULPT_vertex_co_get(ss, i));
+ }
+
+ SculptThreadedTaskData data = {
+ .sd = sd,
+ .ob = ob,
+ .nodes = ss->filter_cache->nodes,
+ .filter_type = filter_type,
+ .filter_strength = filter_strength,
+ };
+
+ TaskParallelSettings settings;
+ BKE_pbvh_parallel_range_settings(
+ &settings, (sd->flags & SCULPT_USE_OPENMP), ss->filter_cache->totnode);
+ BLI_task_parallel_range(
+ 0, ss->filter_cache->totnode, &data, cloth_filter_apply_forces_task_cb, &settings);
+
+ /* Update and write the simulation to the nodes. */
+ cloth_brush_do_simulation_step(
+ sd, ob, ss->filter_cache->cloth_sim, ss->filter_cache->nodes, ss->filter_cache->totnode);
+
+ if (ss->deform_modifiers_active || ss->shapekey_active) {
+ SCULPT_flush_stroke_deform(sd, ob, true);
+ }
+ SCULPT_flush_update_step(C, SCULPT_UPDATE_COORDS);
+ return OPERATOR_RUNNING_MODAL;
+}
+
+static int sculpt_cloth_filter_invoke(bContext *C, wmOperator *op, const wmEvent *event)
+{
+ Object *ob = CTX_data_active_object(C);
+ Depsgraph *depsgraph = CTX_data_depsgraph_pointer(C);
+ Sculpt *sd = CTX_data_tool_settings(C)->sculpt;
+ SculptSession *ss = ob->sculpt;
+
+ /* Update the active vertex */
+ float mouse[2];
+ SculptCursorGeometryInfo sgi;
+ mouse[0] = event->mval[0];
+ mouse[1] = event->mval[1];
+ SCULPT_cursor_geometry_info_update(C, &sgi, mouse, false);
+
+ SCULPT_vertex_random_access_init(ss);
+
+ /* Needs mask data to be available as it is used when solving the constraints. */
+ BKE_sculpt_update_object_for_edit(depsgraph, ob, true, true);
+
+ SCULPT_undo_push_begin("Cloth filter");
+ SCULPT_filter_cache_init(ob, sd);
+
+ const float cloth_mass = RNA_float_get(op->ptr, "cloth_mass");
+ const float cloth_damping = RNA_float_get(op->ptr, "cloth_damping");
+ ss->filter_cache->cloth_sim = cloth_brush_simulation_create(ss, cloth_mass, cloth_damping);
+ copy_v3_v3(ss->filter_cache->cloth_sim_pinch_point, SCULPT_active_vertex_co_get(ss));
+
+ const int totverts = SCULPT_vertex_count_get(ss);
+ for (int i = 0; i < totverts; i++) {
+ copy_v3_v3(ss->filter_cache->cloth_sim->prev_pos[i], SCULPT_vertex_co_get(ss, i));
+ copy_v3_v3(ss->filter_cache->cloth_sim->init_pos[i], SCULPT_vertex_co_get(ss, i));
+ }
+
+ float origin[3] = {0.0f, 0.0f, 0.0f};
+ cloth_brush_build_nodes_constraints(sd,
+ ob,
+ ss->filter_cache->nodes,
+ ss->filter_cache->totnode,
+ ss->filter_cache->cloth_sim,
+ origin,
+ FLT_MAX);
+
+ const bool use_face_sets = RNA_boolean_get(op->ptr, "use_face_sets");
+ if (use_face_sets) {
+ ss->filter_cache->active_face_set = SCULPT_active_face_set_get(ss);
+ }
+ else {
+ ss->filter_cache->active_face_set = SCULPT_FACE_SET_NONE;
+ }
+
+ WM_event_add_modal_handler(C, op);
+ return OPERATOR_RUNNING_MODAL;
+}
+
+void SCULPT_OT_cloth_filter(struct wmOperatorType *ot)
+{
+ /* Identifiers. */
+ ot->name = "Filter cloth";
+ ot->idname = "SCULPT_OT_cloth_filter";
+ ot->description = "Applies a cloth simulation deformation to the entire mesh";
+
+ /* API callbacks. */
+ ot->invoke = sculpt_cloth_filter_invoke;
+ ot->modal = sculpt_cloth_filter_modal;
+ ot->poll = SCULPT_mode_poll;
+
+ ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
+
+ /* RNA. */
+ RNA_def_enum(ot->srna,
+ "type",
+ prop_cloth_filter_type,
+ CLOTH_FILTER_GRAVITY,
+ "Filter type",
+ "Operation that is going to be applied to the mesh");
+ RNA_def_float(
+ ot->srna, "strength", 1.0f, -10.0f, 10.0f, "Strength", "Filter Strength", -10.0f, 10.0f);
+ RNA_def_float(ot->srna,
+ "cloth_mass",
+ 1.0f,
+ 0.0f,
+ 2.0f,
+ "Cloth Mass",
+ "Mass of each simulation particle",
+ 0.0f,
+ 1.0f);
+ RNA_def_float(ot->srna,
+ "cloth_damping",
+ 0.0f,
+ 0.0f,
+ 1.0f,
+ "Cloth Damping",
+ "How much the applied forces are propagated through the cloth",
+ 0.0f,
+ 1.0f);
+ ot->prop = RNA_def_boolean(ot->srna,
+ "use_face_sets",
+ false,
+ "Use Face Sets",
+ "Apply the filter only to the Face Set under the cursor");
+}
diff --git a/source/blender/editors/sculpt_paint/sculpt_detail.c b/source/blender/editors/sculpt_paint/sculpt_detail.c
new file mode 100644
index 00000000000..b7d1cd8c005
--- /dev/null
+++ b/source/blender/editors/sculpt_paint/sculpt_detail.c
@@ -0,0 +1,428 @@
+/*
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * The Original Code is Copyright (C) 2020 Blender Foundation.
+ * All rights reserved.
+ */
+
+/** \file
+ * \ingroup edsculpt
+ */
+
+#include "MEM_guardedalloc.h"
+
+#include "BLI_blenlib.h"
+#include "BLI_hash.h"
+#include "BLI_math.h"
+#include "BLI_task.h"
+
+#include "BLT_translation.h"
+
+#include "DNA_mesh_types.h"
+#include "DNA_meshdata_types.h"
+
+#include "BKE_brush.h"
+#include "BKE_context.h"
+#include "BKE_mesh.h"
+#include "BKE_mesh_mapping.h"
+#include "BKE_object.h"
+#include "BKE_paint.h"
+#include "BKE_pbvh.h"
+#include "BKE_scene.h"
+#include "BKE_screen.h"
+
+#include "DEG_depsgraph.h"
+
+#include "WM_api.h"
+#include "WM_message.h"
+#include "WM_toolsystem.h"
+#include "WM_types.h"
+
+#include "ED_object.h"
+#include "ED_screen.h"
+#include "ED_sculpt.h"
+#include "ED_view3d.h"
+#include "paint_intern.h"
+#include "sculpt_intern.h"
+
+#include "RNA_access.h"
+#include "RNA_define.h"
+
+#include "UI_interface.h"
+
+#include "bmesh.h"
+
+#include <math.h>
+#include <stdlib.h>
+
+typedef struct {
+ const float *ray_start;
+ bool hit;
+ float depth;
+ float edge_length;
+
+ struct IsectRayPrecalc isect_precalc;
+} SculptDetailRaycastData;
+
+static bool sculpt_and_constant_or_manual_detail_poll(bContext *C)
+{
+ Object *ob = CTX_data_active_object(C);
+ Sculpt *sd = CTX_data_tool_settings(C)->sculpt;
+
+ return SCULPT_mode_poll(C) && ob->sculpt->bm &&
+ (sd->flags & (SCULPT_DYNTOPO_DETAIL_CONSTANT | SCULPT_DYNTOPO_DETAIL_MANUAL));
+}
+
+static bool sculpt_and_dynamic_topology_poll(bContext *C)
+{
+ Object *ob = CTX_data_active_object(C);
+
+ return SCULPT_mode_poll(C) && ob->sculpt->bm;
+}
+
+static int sculpt_detail_flood_fill_exec(bContext *C, wmOperator *UNUSED(op))
+{
+ Sculpt *sd = CTX_data_tool_settings(C)->sculpt;
+ Object *ob = CTX_data_active_object(C);
+ SculptSession *ss = ob->sculpt;
+ float size;
+ float bb_min[3], bb_max[3], center[3], dim[3];
+ int totnodes;
+ PBVHNode **nodes;
+
+ BKE_pbvh_search_gather(ss->pbvh, NULL, NULL, &nodes, &totnodes);
+
+ if (!totnodes) {
+ return OPERATOR_CANCELLED;
+ }
+
+ for (int i = 0; i < totnodes; i++) {
+ BKE_pbvh_node_mark_topology_update(nodes[i]);
+ }
+ /* Get the bounding box, it's center and size. */
+ BKE_pbvh_bounding_box(ob->sculpt->pbvh, bb_min, bb_max);
+ add_v3_v3v3(center, bb_min, bb_max);
+ mul_v3_fl(center, 0.5f);
+ sub_v3_v3v3(dim, bb_max, bb_min);
+ size = max_fff(dim[0], dim[1], dim[2]);
+
+ /* Update topology size. */
+ float object_space_constant_detail = 1.0f / (sd->constant_detail * mat4_to_scale(ob->obmat));
+ BKE_pbvh_bmesh_detail_size_set(ss->pbvh, object_space_constant_detail);
+
+ SCULPT_undo_push_begin("Dynamic topology flood fill");
+ SCULPT_undo_push_node(ob, NULL, SCULPT_UNDO_COORDS);
+
+ while (BKE_pbvh_bmesh_update_topology(
+ ss->pbvh, PBVH_Collapse | PBVH_Subdivide, center, NULL, size, false, false)) {
+ for (int i = 0; i < totnodes; i++) {
+ BKE_pbvh_node_mark_topology_update(nodes[i]);
+ }
+ }
+
+ MEM_SAFE_FREE(nodes);
+ SCULPT_undo_push_end();
+
+ /* Force rebuild of pbvh for better BB placement. */
+ SCULPT_pbvh_clear(ob);
+ /* Redraw. */
+ WM_event_add_notifier(C, NC_OBJECT | ND_DRAW, ob);
+
+ return OPERATOR_FINISHED;
+}
+
+void SCULPT_OT_detail_flood_fill(wmOperatorType *ot)
+{
+ /* Identifiers. */
+ ot->name = "Detail Flood Fill";
+ ot->idname = "SCULPT_OT_detail_flood_fill";
+ ot->description = "Flood fill the mesh with the selected detail setting";
+
+ /* API callbacks. */
+ ot->exec = sculpt_detail_flood_fill_exec;
+ ot->poll = sculpt_and_constant_or_manual_detail_poll;
+
+ ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
+}
+
+typedef enum eSculptSampleDetailModeTypes {
+ SAMPLE_DETAIL_DYNTOPO = 0,
+ SAMPLE_DETAIL_VOXEL = 1,
+} eSculptSampleDetailModeTypes;
+
+static EnumPropertyItem prop_sculpt_sample_detail_mode_types[] = {
+ {SAMPLE_DETAIL_DYNTOPO, "DYNTOPO", 0, "Dyntopo", "Sample dyntopo detail"},
+ {SAMPLE_DETAIL_VOXEL, "VOXEL", 0, "Voxel", "Sample mesh voxel size"},
+ {0, NULL, 0, NULL, NULL},
+};
+
+static void sample_detail_voxel(bContext *C, ViewContext *vc, int mx, int my)
+{
+ Depsgraph *depsgraph = CTX_data_depsgraph_pointer(C);
+ Object *ob = vc->obact;
+ Mesh *mesh = ob->data;
+
+ SculptSession *ss = ob->sculpt;
+ SculptCursorGeometryInfo sgi;
+ SCULPT_vertex_random_access_init(ss);
+
+ /* Update the active vertex. */
+ float mouse[2] = {mx, my};
+ SCULPT_cursor_geometry_info_update(C, &sgi, mouse, false);
+ BKE_sculpt_update_object_for_edit(depsgraph, ob, true, false);
+
+ /* Average the edge length of the connected edges to the active vertex. */
+ int active_vertex = SCULPT_active_vertex_get(ss);
+ const float *active_vertex_co = SCULPT_active_vertex_co_get(ss);
+ float edge_length = 0.0f;
+ int tot = 0;
+ SculptVertexNeighborIter ni;
+ SCULPT_VERTEX_NEIGHBORS_ITER_BEGIN (ss, active_vertex, ni) {
+ edge_length += len_v3v3(active_vertex_co, SCULPT_vertex_co_get(ss, ni.index));
+ tot += 1;
+ }
+ SCULPT_VERTEX_NEIGHBORS_ITER_END(ni);
+ if (tot > 0) {
+ mesh->remesh_voxel_size = edge_length / (float)tot;
+ }
+}
+
+static void sculpt_raycast_detail_cb(PBVHNode *node, void *data_v, float *tmin)
+{
+ if (BKE_pbvh_node_get_tmin(node) < *tmin) {
+ SculptDetailRaycastData *srd = data_v;
+ if (BKE_pbvh_bmesh_node_raycast_detail(
+ node, srd->ray_start, &srd->isect_precalc, &srd->depth, &srd->edge_length)) {
+ srd->hit = true;
+ *tmin = srd->depth;
+ }
+ }
+}
+
+static void sample_detail_dyntopo(bContext *C, ViewContext *vc, ARegion *region, int mx, int my)
+{
+ Sculpt *sd = CTX_data_tool_settings(C)->sculpt;
+ Object *ob = vc->obact;
+ Brush *brush = BKE_paint_brush(&sd->paint);
+
+ SCULPT_stroke_modifiers_check(C, ob, brush);
+
+ float mouse[2] = {mx - region->winrct.xmin, my - region->winrct.ymin};
+ float ray_start[3], ray_end[3], ray_normal[3];
+ float depth = SCULPT_raycast_init(vc, mouse, ray_start, ray_end, ray_normal, false);
+
+ SculptDetailRaycastData srd;
+ srd.hit = 0;
+ srd.ray_start = ray_start;
+ srd.depth = depth;
+ srd.edge_length = 0.0f;
+ isect_ray_tri_watertight_v3_precalc(&srd.isect_precalc, ray_normal);
+
+ BKE_pbvh_raycast(ob->sculpt->pbvh, sculpt_raycast_detail_cb, &srd, ray_start, ray_normal, false);
+
+ if (srd.hit && srd.edge_length > 0.0f) {
+ /* Convert edge length to world space detail resolution. */
+ sd->constant_detail = 1 / (srd.edge_length * mat4_to_scale(ob->obmat));
+ }
+}
+
+static int sample_detail(bContext *C, int mx, int my, int mode)
+{
+ /* Find 3D view to pick from. */
+ bScreen *screen = CTX_wm_screen(C);
+ ScrArea *area = BKE_screen_find_area_xy(screen, SPACE_VIEW3D, mx, my);
+ ARegion *region = (area) ? BKE_area_find_region_xy(area, RGN_TYPE_WINDOW, mx, my) : NULL;
+ if (region == NULL) {
+ return OPERATOR_CANCELLED;
+ }
+
+ /* Set context to 3D view. */
+ ScrArea *prev_area = CTX_wm_area(C);
+ ARegion *prev_region = CTX_wm_region(C);
+ CTX_wm_area_set(C, area);
+ CTX_wm_region_set(C, region);
+
+ Depsgraph *depsgraph = CTX_data_ensure_evaluated_depsgraph(C);
+ ViewContext vc;
+ ED_view3d_viewcontext_init(C, &vc, depsgraph);
+
+ Object *ob = vc.obact;
+ SculptSession *ss = ob->sculpt;
+
+ if (!ss->pbvh) {
+ return OPERATOR_CANCELLED;
+ }
+
+ /* Pick sample detail. */
+ switch (mode) {
+ case SAMPLE_DETAIL_DYNTOPO:
+ if (BKE_pbvh_type(ss->pbvh) != PBVH_BMESH) {
+ CTX_wm_area_set(C, prev_area);
+ CTX_wm_region_set(C, prev_region);
+ return OPERATOR_CANCELLED;
+ }
+ sample_detail_dyntopo(C, &vc, region, mx, my);
+ break;
+ case SAMPLE_DETAIL_VOXEL:
+ if (BKE_pbvh_type(ss->pbvh) != PBVH_FACES) {
+ CTX_wm_area_set(C, prev_area);
+ CTX_wm_region_set(C, prev_region);
+ return OPERATOR_CANCELLED;
+ }
+ sample_detail_voxel(C, &vc, mx, my);
+ break;
+ }
+
+ /* Restore context. */
+ CTX_wm_area_set(C, prev_area);
+ CTX_wm_region_set(C, prev_region);
+
+ return OPERATOR_FINISHED;
+}
+
+static int sculpt_sample_detail_size_exec(bContext *C, wmOperator *op)
+{
+ int ss_co[2];
+ RNA_int_get_array(op->ptr, "location", ss_co);
+ int mode = RNA_enum_get(op->ptr, "mode");
+ return sample_detail(C, ss_co[0], ss_co[1], mode);
+}
+
+static int sculpt_sample_detail_size_invoke(bContext *C, wmOperator *op, const wmEvent *UNUSED(e))
+{
+ ED_workspace_status_text(C, TIP_("Click on the mesh to set the detail"));
+ WM_cursor_modal_set(CTX_wm_window(C), WM_CURSOR_EYEDROPPER);
+ WM_event_add_modal_handler(C, op);
+ return OPERATOR_RUNNING_MODAL;
+}
+
+static int sculpt_sample_detail_size_modal(bContext *C, wmOperator *op, const wmEvent *event)
+{
+ switch (event->type) {
+ case LEFTMOUSE:
+ if (event->val == KM_PRESS) {
+ int ss_co[2] = {event->x, event->y};
+
+ int mode = RNA_enum_get(op->ptr, "mode");
+ sample_detail(C, ss_co[0], ss_co[1], mode);
+
+ RNA_int_set_array(op->ptr, "location", ss_co);
+ WM_cursor_modal_restore(CTX_wm_window(C));
+ ED_workspace_status_text(C, NULL);
+ WM_main_add_notifier(NC_SCENE | ND_TOOLSETTINGS, NULL);
+
+ return OPERATOR_FINISHED;
+ }
+ break;
+
+ case RIGHTMOUSE: {
+ WM_cursor_modal_restore(CTX_wm_window(C));
+ ED_workspace_status_text(C, NULL);
+
+ return OPERATOR_CANCELLED;
+ }
+ }
+
+ return OPERATOR_RUNNING_MODAL;
+}
+
+void SCULPT_OT_sample_detail_size(wmOperatorType *ot)
+{
+ /* Identifiers. */
+ ot->name = "Sample Detail Size";
+ ot->idname = "SCULPT_OT_sample_detail_size";
+ ot->description = "Sample the mesh detail on clicked point";
+
+ /* API callbacks. */
+ ot->invoke = sculpt_sample_detail_size_invoke;
+ ot->exec = sculpt_sample_detail_size_exec;
+ ot->modal = sculpt_sample_detail_size_modal;
+ ot->poll = SCULPT_mode_poll;
+
+ ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
+
+ RNA_def_int_array(ot->srna,
+ "location",
+ 2,
+ NULL,
+ 0,
+ SHRT_MAX,
+ "Location",
+ "Screen Coordinates of sampling",
+ 0,
+ SHRT_MAX);
+ RNA_def_enum(ot->srna,
+ "mode",
+ prop_sculpt_sample_detail_mode_types,
+ SAMPLE_DETAIL_DYNTOPO,
+ "Detail Mode",
+ "Target sculpting workflow that is going to use the sampled size");
+}
+
+/* Dynamic-topology detail size.
+ *
+ * This should be improved further, perhaps by showing a triangle
+ * grid rather than brush alpha. */
+static void set_brush_rc_props(PointerRNA *ptr, const char *prop)
+{
+ char *path = BLI_sprintfN("tool_settings.sculpt.brush.%s", prop);
+ RNA_string_set(ptr, "data_path_primary", path);
+ MEM_freeN(path);
+}
+
+static int sculpt_set_detail_size_exec(bContext *C, wmOperator *UNUSED(op))
+{
+ Sculpt *sd = CTX_data_tool_settings(C)->sculpt;
+
+ PointerRNA props_ptr;
+ wmOperatorType *ot = WM_operatortype_find("WM_OT_radial_control", true);
+
+ WM_operator_properties_create_ptr(&props_ptr, ot);
+
+ if (sd->flags & (SCULPT_DYNTOPO_DETAIL_CONSTANT | SCULPT_DYNTOPO_DETAIL_MANUAL)) {
+ set_brush_rc_props(&props_ptr, "constant_detail_resolution");
+ RNA_string_set(
+ &props_ptr, "data_path_primary", "tool_settings.sculpt.constant_detail_resolution");
+ }
+ else if (sd->flags & SCULPT_DYNTOPO_DETAIL_BRUSH) {
+ set_brush_rc_props(&props_ptr, "constant_detail_resolution");
+ RNA_string_set(&props_ptr, "data_path_primary", "tool_settings.sculpt.detail_percent");
+ }
+ else {
+ set_brush_rc_props(&props_ptr, "detail_size");
+ RNA_string_set(&props_ptr, "data_path_primary", "tool_settings.sculpt.detail_size");
+ }
+
+ WM_operator_name_call_ptr(C, ot, WM_OP_INVOKE_DEFAULT, &props_ptr);
+
+ WM_operator_properties_free(&props_ptr);
+
+ return OPERATOR_FINISHED;
+}
+
+void SCULPT_OT_set_detail_size(wmOperatorType *ot)
+{
+ /* Identifiers. */
+ ot->name = "Set Detail Size";
+ ot->idname = "SCULPT_OT_set_detail_size";
+ ot->description =
+ "Set the mesh detail (either relative or constant one, depending on current dyntopo mode)";
+
+ /* API callbacks. */
+ ot->exec = sculpt_set_detail_size_exec;
+ ot->poll = sculpt_and_dynamic_topology_poll;
+
+ ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
+}
diff --git a/source/blender/editors/sculpt_paint/sculpt_dyntopo.c b/source/blender/editors/sculpt_paint/sculpt_dyntopo.c
new file mode 100644
index 00000000000..eefd8529dbf
--- /dev/null
+++ b/source/blender/editors/sculpt_paint/sculpt_dyntopo.c
@@ -0,0 +1,439 @@
+/*
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * The Original Code is Copyright (C) 2020 Blender Foundation.
+ * All rights reserved.
+ */
+
+/** \file
+ * \ingroup edsculpt
+ */
+
+#include "MEM_guardedalloc.h"
+
+#include "BLI_blenlib.h"
+#include "BLI_hash.h"
+#include "BLI_math.h"
+#include "BLI_task.h"
+
+#include "BLT_translation.h"
+
+#include "DNA_mesh_types.h"
+#include "DNA_meshdata_types.h"
+#include "DNA_modifier_types.h"
+
+#include "BKE_brush.h"
+#include "BKE_context.h"
+#include "BKE_main.h"
+#include "BKE_mesh.h"
+#include "BKE_mesh_mapping.h"
+#include "BKE_modifier.h"
+#include "BKE_object.h"
+#include "BKE_paint.h"
+#include "BKE_particle.h"
+#include "BKE_pbvh.h"
+#include "BKE_pointcache.h"
+#include "BKE_scene.h"
+#include "BKE_screen.h"
+
+#include "DEG_depsgraph.h"
+
+#include "WM_api.h"
+#include "WM_message.h"
+#include "WM_toolsystem.h"
+#include "WM_types.h"
+
+#include "ED_object.h"
+#include "ED_screen.h"
+#include "ED_sculpt.h"
+#include "ED_view3d.h"
+#include "paint_intern.h"
+#include "sculpt_intern.h"
+
+#include "RNA_access.h"
+#include "RNA_define.h"
+
+#include "UI_interface.h"
+#include "UI_resources.h"
+
+#include "bmesh.h"
+#include "bmesh_tools.h"
+
+#include <math.h>
+#include <stdlib.h>
+
+void SCULPT_dynamic_topology_triangulate(BMesh *bm)
+{
+ if (bm->totloop != bm->totface * 3) {
+ BM_mesh_triangulate(
+ bm, MOD_TRIANGULATE_QUAD_BEAUTY, MOD_TRIANGULATE_NGON_EARCLIP, 4, false, NULL, NULL, NULL);
+ }
+}
+
+void SCULPT_pbvh_clear(Object *ob)
+{
+ SculptSession *ss = ob->sculpt;
+
+ /* Clear out any existing DM and PBVH. */
+ if (ss->pbvh) {
+ BKE_pbvh_free(ss->pbvh);
+ ss->pbvh = NULL;
+ }
+
+ if (ss->pmap) {
+ MEM_freeN(ss->pmap);
+ ss->pmap = NULL;
+ }
+
+ if (ss->pmap_mem) {
+ MEM_freeN(ss->pmap_mem);
+ ss->pmap_mem = NULL;
+ }
+
+ BKE_object_free_derived_caches(ob);
+
+ /* Tag to rebuild PBVH in depsgraph. */
+ DEG_id_tag_update(&ob->id, ID_RECALC_GEOMETRY);
+}
+
+void SCULPT_dyntopo_node_layers_add(SculptSession *ss)
+{
+ int cd_node_layer_index;
+
+ char layer_id[] = "_dyntopo_node_id";
+
+ cd_node_layer_index = CustomData_get_named_layer_index(&ss->bm->vdata, CD_PROP_INT, layer_id);
+ if (cd_node_layer_index == -1) {
+ BM_data_layer_add_named(ss->bm, &ss->bm->vdata, CD_PROP_INT, layer_id);
+ cd_node_layer_index = CustomData_get_named_layer_index(&ss->bm->vdata, CD_PROP_INT, layer_id);
+ }
+
+ ss->cd_vert_node_offset = CustomData_get_n_offset(
+ &ss->bm->vdata,
+ CD_PROP_INT,
+ cd_node_layer_index - CustomData_get_layer_index(&ss->bm->vdata, CD_PROP_INT));
+
+ ss->bm->vdata.layers[cd_node_layer_index].flag |= CD_FLAG_TEMPORARY;
+
+ cd_node_layer_index = CustomData_get_named_layer_index(&ss->bm->pdata, CD_PROP_INT, layer_id);
+ if (cd_node_layer_index == -1) {
+ BM_data_layer_add_named(ss->bm, &ss->bm->pdata, CD_PROP_INT, layer_id);
+ cd_node_layer_index = CustomData_get_named_layer_index(&ss->bm->pdata, CD_PROP_INT, layer_id);
+ }
+
+ ss->cd_face_node_offset = CustomData_get_n_offset(
+ &ss->bm->pdata,
+ CD_PROP_INT,
+ cd_node_layer_index - CustomData_get_layer_index(&ss->bm->pdata, CD_PROP_INT));
+
+ ss->bm->pdata.layers[cd_node_layer_index].flag |= CD_FLAG_TEMPORARY;
+}
+
+void SCULPT_dynamic_topology_enable_ex(Main *bmain, Depsgraph *depsgraph, Scene *scene, Object *ob)
+{
+ SculptSession *ss = ob->sculpt;
+ Mesh *me = ob->data;
+ const BMAllocTemplate allocsize = BMALLOC_TEMPLATE_FROM_ME(me);
+
+ SCULPT_pbvh_clear(ob);
+
+ ss->bm_smooth_shading = (scene->toolsettings->sculpt->flags & SCULPT_DYNTOPO_SMOOTH_SHADING) !=
+ 0;
+
+ /* Dynamic topology doesn't ensure selection state is valid, so remove [#36280]. */
+ BKE_mesh_mselect_clear(me);
+
+ /* Create triangles-only BMesh. */
+ ss->bm = BM_mesh_create(&allocsize,
+ &((struct BMeshCreateParams){
+ .use_toolflags = false,
+ }));
+
+ BM_mesh_bm_from_me(ss->bm,
+ me,
+ (&(struct BMeshFromMeshParams){
+ .calc_face_normal = true,
+ .use_shapekey = true,
+ .active_shapekey = ob->shapenr,
+ }));
+ SCULPT_dynamic_topology_triangulate(ss->bm);
+ BM_data_layer_add(ss->bm, &ss->bm->vdata, CD_PAINT_MASK);
+ SCULPT_dyntopo_node_layers_add(ss);
+ /* Make sure the data for existing faces are initialized. */
+ if (me->totpoly != ss->bm->totface) {
+ BM_mesh_normals_update(ss->bm);
+ }
+
+ /* Enable dynamic topology. */
+ me->flag |= ME_SCULPT_DYNAMIC_TOPOLOGY;
+
+ /* Enable logging for undo/redo. */
+ ss->bm_log = BM_log_create(ss->bm);
+
+ /* Update dependency graph, so modifiers that depend on dyntopo being enabled
+ * are re-evaluated and the PBVH is re-created. */
+ DEG_id_tag_update(&ob->id, ID_RECALC_GEOMETRY);
+ BKE_scene_graph_update_tagged(depsgraph, bmain);
+}
+
+/* Free the sculpt BMesh and BMLog
+ *
+ * If 'unode' is given, the BMesh's data is copied out to the unode
+ * before the BMesh is deleted so that it can be restored from. */
+static void SCULPT_dynamic_topology_disable_ex(
+ Main *bmain, Depsgraph *depsgraph, Scene *scene, Object *ob, SculptUndoNode *unode)
+{
+ SculptSession *ss = ob->sculpt;
+ Mesh *me = ob->data;
+
+ SCULPT_pbvh_clear(ob);
+
+ if (unode) {
+ /* Free all existing custom data. */
+ CustomData_free(&me->vdata, me->totvert);
+ CustomData_free(&me->edata, me->totedge);
+ CustomData_free(&me->fdata, me->totface);
+ CustomData_free(&me->ldata, me->totloop);
+ CustomData_free(&me->pdata, me->totpoly);
+
+ /* Copy over stored custom data. */
+ SculptUndoNodeGeometry *geometry = &unode->geometry_bmesh_enter;
+ me->totvert = geometry->totvert;
+ me->totloop = geometry->totloop;
+ me->totpoly = geometry->totpoly;
+ me->totedge = geometry->totedge;
+ me->totface = 0;
+ CustomData_copy(
+ &geometry->vdata, &me->vdata, CD_MASK_MESH.vmask, CD_DUPLICATE, geometry->totvert);
+ CustomData_copy(
+ &geometry->edata, &me->edata, CD_MASK_MESH.emask, CD_DUPLICATE, geometry->totedge);
+ CustomData_copy(
+ &geometry->ldata, &me->ldata, CD_MASK_MESH.lmask, CD_DUPLICATE, geometry->totloop);
+ CustomData_copy(
+ &geometry->pdata, &me->pdata, CD_MASK_MESH.pmask, CD_DUPLICATE, geometry->totpoly);
+
+ BKE_mesh_update_customdata_pointers(me, false);
+ }
+ else {
+ BKE_sculptsession_bm_to_me(ob, true);
+
+ /* Reset Face Sets as they are no longer valid. */
+ if (!CustomData_has_layer(&me->pdata, CD_SCULPT_FACE_SETS)) {
+ CustomData_add_layer(&me->pdata, CD_SCULPT_FACE_SETS, CD_CALLOC, NULL, me->totpoly);
+ }
+ ss->face_sets = CustomData_get_layer(&me->pdata, CD_SCULPT_FACE_SETS);
+ for (int i = 0; i < me->totpoly; i++) {
+ ss->face_sets[i] = 1;
+ }
+ me->face_sets_color_default = 1;
+
+ /* Sync the visibility to vertices manually as the pmap is still not initialized. */
+ for (int i = 0; i < me->totvert; i++) {
+ me->mvert[i].flag &= ~ME_HIDE;
+ me->mvert[i].flag |= ME_VERT_PBVH_UPDATE;
+ }
+ }
+
+ /* Clear data. */
+ me->flag &= ~ME_SCULPT_DYNAMIC_TOPOLOGY;
+
+ /* Typically valid but with global-undo they can be NULL. [#36234] */
+ if (ss->bm) {
+ BM_mesh_free(ss->bm);
+ ss->bm = NULL;
+ }
+ if (ss->bm_log) {
+ BM_log_free(ss->bm_log);
+ ss->bm_log = NULL;
+ }
+
+ BKE_particlesystem_reset_all(ob);
+ BKE_ptcache_object_reset(scene, ob, PTCACHE_RESET_OUTDATED);
+
+ /* Update dependency graph, so modifiers that depend on dyntopo being enabled
+ * are re-evaluated and the PBVH is re-created. */
+ DEG_id_tag_update(&ob->id, ID_RECALC_GEOMETRY);
+ BKE_scene_graph_update_tagged(depsgraph, bmain);
+}
+
+void SCULPT_dynamic_topology_disable(bContext *C, SculptUndoNode *unode)
+{
+ Main *bmain = CTX_data_main(C);
+ Depsgraph *depsgraph = CTX_data_ensure_evaluated_depsgraph(C);
+ Scene *scene = CTX_data_scene(C);
+ Object *ob = CTX_data_active_object(C);
+ SCULPT_dynamic_topology_disable_ex(bmain, depsgraph, scene, ob, unode);
+}
+
+void sculpt_dynamic_topology_disable_with_undo(Main *bmain,
+ Depsgraph *depsgraph,
+ Scene *scene,
+ Object *ob)
+{
+ SculptSession *ss = ob->sculpt;
+ if (ss->bm) {
+ SCULPT_undo_push_begin("Dynamic topology disable");
+ SCULPT_undo_push_node(ob, NULL, SCULPT_UNDO_DYNTOPO_END);
+ SCULPT_dynamic_topology_disable_ex(bmain, depsgraph, scene, ob, NULL);
+ SCULPT_undo_push_end();
+ }
+}
+
+static void sculpt_dynamic_topology_enable_with_undo(Main *bmain,
+ Depsgraph *depsgraph,
+ Scene *scene,
+ Object *ob)
+{
+ SculptSession *ss = ob->sculpt;
+ if (ss->bm == NULL) {
+ SCULPT_undo_push_begin("Dynamic topology enable");
+ SCULPT_dynamic_topology_enable_ex(bmain, depsgraph, scene, ob);
+ SCULPT_undo_push_node(ob, NULL, SCULPT_UNDO_DYNTOPO_BEGIN);
+ SCULPT_undo_push_end();
+ }
+}
+
+static int sculpt_dynamic_topology_toggle_exec(bContext *C, wmOperator *UNUSED(op))
+{
+ Main *bmain = CTX_data_main(C);
+ Depsgraph *depsgraph = CTX_data_ensure_evaluated_depsgraph(C);
+ Scene *scene = CTX_data_scene(C);
+ Object *ob = CTX_data_active_object(C);
+ SculptSession *ss = ob->sculpt;
+
+ WM_cursor_wait(true);
+
+ if (ss->bm) {
+ sculpt_dynamic_topology_disable_with_undo(bmain, depsgraph, scene, ob);
+ }
+ else {
+ sculpt_dynamic_topology_enable_with_undo(bmain, depsgraph, scene, ob);
+ }
+
+ WM_cursor_wait(false);
+ WM_main_add_notifier(NC_SCENE | ND_TOOLSETTINGS, NULL);
+
+ return OPERATOR_FINISHED;
+}
+
+static int dyntopo_warning_popup(bContext *C, wmOperatorType *ot, enum eDynTopoWarnFlag flag)
+{
+ uiPopupMenu *pup = UI_popup_menu_begin(C, IFACE_("Warning!"), ICON_ERROR);
+ uiLayout *layout = UI_popup_menu_layout(pup);
+
+ if (flag & (DYNTOPO_WARN_VDATA | DYNTOPO_WARN_EDATA | DYNTOPO_WARN_LDATA)) {
+ const char *msg_error = TIP_("Vertex Data Detected!");
+ const char *msg = TIP_("Dyntopo will not preserve vertex colors, UVs, or other customdata");
+ uiItemL(layout, msg_error, ICON_INFO);
+ uiItemL(layout, msg, ICON_NONE);
+ uiItemS(layout);
+ }
+
+ if (flag & DYNTOPO_WARN_MODIFIER) {
+ const char *msg_error = TIP_("Generative Modifiers Detected!");
+ const char *msg = TIP_(
+ "Keeping the modifiers will increase polycount when returning to object mode");
+
+ uiItemL(layout, msg_error, ICON_INFO);
+ uiItemL(layout, msg, ICON_NONE);
+ uiItemS(layout);
+ }
+
+ uiItemFullO_ptr(layout, ot, IFACE_("OK"), ICON_NONE, NULL, WM_OP_EXEC_DEFAULT, 0, NULL);
+
+ UI_popup_menu_end(C, pup);
+
+ return OPERATOR_INTERFACE;
+}
+
+enum eDynTopoWarnFlag SCULPT_dynamic_topology_check(Scene *scene, Object *ob)
+{
+ Mesh *me = ob->data;
+ SculptSession *ss = ob->sculpt;
+
+ enum eDynTopoWarnFlag flag = 0;
+
+ BLI_assert(ss->bm == NULL);
+ UNUSED_VARS_NDEBUG(ss);
+
+ for (int i = 0; i < CD_NUMTYPES; i++) {
+ if (!ELEM(i, CD_MVERT, CD_MEDGE, CD_MFACE, CD_MLOOP, CD_MPOLY, CD_PAINT_MASK, CD_ORIGINDEX)) {
+ if (CustomData_has_layer(&me->vdata, i)) {
+ flag |= DYNTOPO_WARN_VDATA;
+ }
+ if (CustomData_has_layer(&me->edata, i)) {
+ flag |= DYNTOPO_WARN_EDATA;
+ }
+ if (CustomData_has_layer(&me->ldata, i)) {
+ flag |= DYNTOPO_WARN_LDATA;
+ }
+ }
+ }
+
+ {
+ VirtualModifierData virtualModifierData;
+ ModifierData *md = BKE_modifiers_get_virtual_modifierlist(ob, &virtualModifierData);
+
+ /* Exception for shape keys because we can edit those. */
+ for (; md; md = md->next) {
+ const ModifierTypeInfo *mti = BKE_modifier_get_info(md->type);
+ if (!BKE_modifier_is_enabled(scene, md, eModifierMode_Realtime)) {
+ continue;
+ }
+
+ if (mti->type == eModifierTypeType_Constructive) {
+ flag |= DYNTOPO_WARN_MODIFIER;
+ break;
+ }
+ }
+ }
+
+ return flag;
+}
+
+static int sculpt_dynamic_topology_toggle_invoke(bContext *C,
+ wmOperator *op,
+ const wmEvent *UNUSED(event))
+{
+ Object *ob = CTX_data_active_object(C);
+ SculptSession *ss = ob->sculpt;
+
+ if (!ss->bm) {
+ Scene *scene = CTX_data_scene(C);
+ enum eDynTopoWarnFlag flag = SCULPT_dynamic_topology_check(scene, ob);
+
+ if (flag) {
+ /* The mesh has customdata that will be lost, let the user confirm this is OK. */
+ return dyntopo_warning_popup(C, op->type, flag);
+ }
+ }
+
+ return sculpt_dynamic_topology_toggle_exec(C, op);
+}
+
+void SCULPT_OT_dynamic_topology_toggle(wmOperatorType *ot)
+{
+ /* Identifiers. */
+ ot->name = "Dynamic Topology Toggle";
+ ot->idname = "SCULPT_OT_dynamic_topology_toggle";
+ ot->description = "Dynamic topology alters the mesh topology while sculpting";
+
+ /* API callbacks. */
+ ot->invoke = sculpt_dynamic_topology_toggle_invoke;
+ ot->exec = sculpt_dynamic_topology_toggle_exec;
+ ot->poll = SCULPT_mode_poll;
+
+ ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
+}
diff --git a/source/blender/editors/sculpt_paint/sculpt_face_set.c b/source/blender/editors/sculpt_paint/sculpt_face_set.c
new file mode 100644
index 00000000000..cbdbab14690
--- /dev/null
+++ b/source/blender/editors/sculpt_paint/sculpt_face_set.c
@@ -0,0 +1,980 @@
+/*
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * The Original Code is Copyright (C) 2020 Blender Foundation.
+ * All rights reserved.
+ */
+
+/** \file
+ * \ingroup edsculpt
+ */
+
+#include "MEM_guardedalloc.h"
+
+#include "BLI_blenlib.h"
+#include "BLI_hash.h"
+#include "BLI_math.h"
+#include "BLI_task.h"
+
+#include "DNA_brush_types.h"
+#include "DNA_customdata_types.h"
+#include "DNA_mesh_types.h"
+#include "DNA_meshdata_types.h"
+#include "DNA_object_types.h"
+#include "DNA_scene_types.h"
+
+#include "BKE_brush.h"
+#include "BKE_ccg.h"
+#include "BKE_colortools.h"
+#include "BKE_context.h"
+#include "BKE_customdata.h"
+#include "BKE_mesh.h"
+#include "BKE_mesh_mapping.h"
+#include "BKE_multires.h"
+#include "BKE_node.h"
+#include "BKE_object.h"
+#include "BKE_paint.h"
+#include "BKE_pbvh.h"
+#include "BKE_scene.h"
+
+#include "DEG_depsgraph.h"
+
+#include "WM_api.h"
+#include "WM_message.h"
+#include "WM_toolsystem.h"
+#include "WM_types.h"
+
+#include "ED_object.h"
+#include "ED_screen.h"
+#include "ED_sculpt.h"
+#include "ED_view3d.h"
+#include "paint_intern.h"
+#include "sculpt_intern.h"
+
+#include "RNA_access.h"
+#include "RNA_define.h"
+
+#include "bmesh.h"
+
+#include <math.h>
+#include <stdlib.h>
+
+/* Draw Face Sets Brush. */
+
+static void do_draw_face_sets_brush_task_cb_ex(void *__restrict userdata,
+ const int n,
+ const TaskParallelTLS *__restrict tls)
+{
+ SculptThreadedTaskData *data = userdata;
+ SculptSession *ss = data->ob->sculpt;
+ const Brush *brush = data->brush;
+ const float bstrength = ss->cache->bstrength;
+
+ PBVHVertexIter vd;
+
+ SculptBrushTest test;
+ SculptBrushTestFn sculpt_brush_test_sq_fn = SCULPT_brush_test_init_with_falloff_shape(
+ ss, &test, data->brush->falloff_shape);
+ const int thread_id = BLI_task_parallel_thread_id(tls);
+
+ BKE_pbvh_vertex_iter_begin(ss->pbvh, data->nodes[n], vd, PBVH_ITER_UNIQUE)
+ {
+ if (BKE_pbvh_type(ss->pbvh) == PBVH_FACES) {
+ MeshElemMap *vert_map = &ss->pmap[vd.index];
+ for (int j = 0; j < ss->pmap[vd.index].count; j++) {
+ const MPoly *p = &ss->mpoly[vert_map->indices[j]];
+
+ float poly_center[3];
+ BKE_mesh_calc_poly_center(p, &ss->mloop[p->loopstart], ss->mvert, poly_center);
+
+ if (sculpt_brush_test_sq_fn(&test, poly_center)) {
+ const float fade = bstrength * SCULPT_brush_strength_factor(ss,
+ brush,
+ vd.co,
+ sqrtf(test.dist),
+ vd.no,
+ vd.fno,
+ vd.mask ? *vd.mask : 0.0f,
+ vd.index,
+ thread_id);
+
+ if (fade > 0.05f && ss->face_sets[vert_map->indices[j]] > 0) {
+ ss->face_sets[vert_map->indices[j]] = abs(ss->cache->paint_face_set);
+ }
+ }
+ }
+ }
+
+ else if (BKE_pbvh_type(ss->pbvh) == PBVH_GRIDS) {
+ {
+ if (sculpt_brush_test_sq_fn(&test, vd.co)) {
+ const float fade = bstrength * SCULPT_brush_strength_factor(ss,
+ brush,
+ vd.co,
+ sqrtf(test.dist),
+ vd.no,
+ vd.fno,
+ vd.mask ? *vd.mask : 0.0f,
+ vd.index,
+ thread_id);
+
+ if (fade > 0.05f) {
+ SCULPT_vertex_face_set_set(ss, vd.index, ss->cache->paint_face_set);
+ }
+ }
+ }
+ }
+ }
+ BKE_pbvh_vertex_iter_end;
+}
+
+static void do_relax_face_sets_brush_task_cb_ex(void *__restrict userdata,
+ const int n,
+ const TaskParallelTLS *__restrict tls)
+{
+ SculptThreadedTaskData *data = userdata;
+ SculptSession *ss = data->ob->sculpt;
+ const Brush *brush = data->brush;
+ float bstrength = ss->cache->bstrength;
+
+ PBVHVertexIter vd;
+
+ SculptBrushTest test;
+ SculptBrushTestFn sculpt_brush_test_sq_fn = SCULPT_brush_test_init_with_falloff_shape(
+ ss, &test, data->brush->falloff_shape);
+
+ const bool relax_face_sets = !(ss->cache->iteration_count % 3 == 0);
+ /* This operations needs a stregth tweak as the relax deformation is too weak by default. */
+ if (relax_face_sets) {
+ bstrength *= 2.0f;
+ }
+
+ const int thread_id = BLI_task_parallel_thread_id(tls);
+
+ BKE_pbvh_vertex_iter_begin(ss->pbvh, data->nodes[n], vd, PBVH_ITER_UNIQUE)
+ {
+ if (sculpt_brush_test_sq_fn(&test, vd.co)) {
+ if (relax_face_sets != SCULPT_vertex_has_unique_face_set(ss, vd.index)) {
+ const float fade = bstrength * SCULPT_brush_strength_factor(ss,
+ brush,
+ vd.co,
+ sqrtf(test.dist),
+ vd.no,
+ vd.fno,
+ vd.mask ? *vd.mask : 0.0f,
+ vd.index,
+ thread_id);
+
+ SCULPT_relax_vertex(ss, &vd, fade * bstrength, relax_face_sets, vd.co);
+ if (vd.mvert) {
+ vd.mvert->flag |= ME_VERT_PBVH_UPDATE;
+ }
+ }
+ }
+ }
+ BKE_pbvh_vertex_iter_end;
+}
+
+void SCULPT_do_draw_face_sets_brush(Sculpt *sd, Object *ob, PBVHNode **nodes, int totnode)
+{
+ SculptSession *ss = ob->sculpt;
+ Brush *brush = BKE_paint_brush(&sd->paint);
+
+ BKE_curvemapping_initialize(brush->curve);
+
+ /* Threaded loop over nodes. */
+ SculptThreadedTaskData data = {
+ .sd = sd,
+ .ob = ob,
+ .brush = brush,
+ .nodes = nodes,
+ };
+
+ TaskParallelSettings settings;
+ BKE_pbvh_parallel_range_settings(&settings, (sd->flags & SCULPT_USE_OPENMP), totnode);
+ if (ss->cache->alt_smooth) {
+ for (int i = 0; i < 4; i++) {
+ BLI_task_parallel_range(0, totnode, &data, do_relax_face_sets_brush_task_cb_ex, &settings);
+ }
+ }
+ else {
+ BLI_task_parallel_range(0, totnode, &data, do_draw_face_sets_brush_task_cb_ex, &settings);
+ }
+}
+
+/* Face Sets Operators */
+
+typedef enum eSculptFaceGroupsCreateModes {
+ SCULPT_FACE_SET_MASKED = 0,
+ SCULPT_FACE_SET_VISIBLE = 1,
+ SCULPT_FACE_SET_ALL = 2,
+ SCULPT_FACE_SET_SELECTION = 3,
+} eSculptFaceGroupsCreateModes;
+
+static EnumPropertyItem prop_sculpt_face_set_create_types[] = {
+ {
+ SCULPT_FACE_SET_MASKED,
+ "MASKED",
+ 0,
+ "Face Set From Masked",
+ "Create a new Face Set from the masked faces",
+ },
+ {
+ SCULPT_FACE_SET_VISIBLE,
+ "VISIBLE",
+ 0,
+ "Face Set From Visible",
+ "Create a new Face Set from the visible vertices",
+ },
+ {
+ SCULPT_FACE_SET_ALL,
+ "ALL",
+ 0,
+ "Face Set Full Mesh",
+ "Create an unique Face Set with all faces in the sculpt",
+ },
+ {
+ SCULPT_FACE_SET_SELECTION,
+ "SELECTION",
+ 0,
+ "Face Set From Edit Mode Selection",
+ "Create an Face Set corresponding to the Edit Mode face selection",
+ },
+ {0, NULL, 0, NULL, NULL},
+};
+
+static int sculpt_face_set_create_exec(bContext *C, wmOperator *op)
+{
+ Object *ob = CTX_data_active_object(C);
+ SculptSession *ss = ob->sculpt;
+ ARegion *region = CTX_wm_region(C);
+ Depsgraph *depsgraph = CTX_data_depsgraph_pointer(C);
+
+ const int mode = RNA_enum_get(op->ptr, "mode");
+
+ /* Dyntopo not suported. */
+ if (BKE_pbvh_type(ss->pbvh) == PBVH_BMESH) {
+ return OPERATOR_CANCELLED;
+ }
+
+ BKE_sculpt_update_object_for_edit(depsgraph, ob, true, mode == SCULPT_FACE_SET_MASKED);
+
+ const int tot_vert = SCULPT_vertex_count_get(ss);
+ float threshold = 0.5f;
+
+ PBVH *pbvh = ob->sculpt->pbvh;
+ PBVHNode **nodes;
+ int totnode;
+ BKE_pbvh_search_gather(pbvh, NULL, NULL, &nodes, &totnode);
+
+ if (!nodes) {
+ return OPERATOR_CANCELLED;
+ }
+
+ SCULPT_undo_push_begin("face set change");
+ SCULPT_undo_push_node(ob, nodes[0], SCULPT_UNDO_FACE_SETS);
+
+ const int next_face_set = SCULPT_face_set_next_available_get(ss);
+
+ if (mode == SCULPT_FACE_SET_MASKED) {
+ for (int i = 0; i < tot_vert; i++) {
+ if (SCULPT_vertex_mask_get(ss, i) >= threshold && SCULPT_vertex_visible_get(ss, i)) {
+ SCULPT_vertex_face_set_set(ss, i, next_face_set);
+ }
+ }
+ }
+
+ if (mode == SCULPT_FACE_SET_VISIBLE) {
+
+ /* If all vertices in the sculpt are visible, create the new face set and update the default
+ * color. This way the new face set will be white, which is a quick way of disabling all face
+ * sets and the performance hit of rendering the overlay. */
+ bool all_visible = true;
+ for (int i = 0; i < tot_vert; i++) {
+ if (!SCULPT_vertex_visible_get(ss, i)) {
+ all_visible = false;
+ break;
+ }
+ }
+
+ if (all_visible) {
+ Mesh *mesh = ob->data;
+ mesh->face_sets_color_default = next_face_set;
+ BKE_pbvh_face_sets_color_set(
+ ss->pbvh, mesh->face_sets_color_seed, mesh->face_sets_color_default);
+ }
+
+ for (int i = 0; i < tot_vert; i++) {
+ if (SCULPT_vertex_visible_get(ss, i)) {
+ SCULPT_vertex_face_set_set(ss, i, next_face_set);
+ }
+ }
+ }
+
+ if (mode == SCULPT_FACE_SET_ALL) {
+ for (int i = 0; i < tot_vert; i++) {
+ SCULPT_vertex_face_set_set(ss, i, next_face_set);
+ }
+ }
+
+ if (mode == SCULPT_FACE_SET_SELECTION) {
+ Mesh *mesh = ob->data;
+ BMesh *bm;
+ const BMAllocTemplate allocsize = BMALLOC_TEMPLATE_FROM_ME(mesh);
+ bm = BM_mesh_create(&allocsize,
+ &((struct BMeshCreateParams){
+ .use_toolflags = true,
+ }));
+
+ BM_mesh_bm_from_me(bm,
+ mesh,
+ (&(struct BMeshFromMeshParams){
+ .calc_face_normal = true,
+ }));
+
+ BMIter iter;
+ BMFace *f;
+ BM_ITER_MESH (f, &iter, bm, BM_FACES_OF_MESH) {
+ if (BM_elem_flag_test(f, BM_ELEM_SELECT)) {
+ ss->face_sets[BM_elem_index_get(f)] = next_face_set;
+ }
+ }
+ BM_mesh_free(bm);
+ }
+
+ for (int i = 0; i < totnode; i++) {
+ BKE_pbvh_node_mark_redraw(nodes[i]);
+ }
+
+ MEM_SAFE_FREE(nodes);
+
+ SCULPT_undo_push_end();
+
+ ED_region_tag_redraw(region);
+ WM_event_add_notifier(C, NC_OBJECT | ND_DRAW, ob);
+
+ return OPERATOR_FINISHED;
+}
+
+void SCULPT_OT_face_sets_create(wmOperatorType *ot)
+{
+ /* identifiers */
+ ot->name = "Create Face Set";
+ ot->idname = "SCULPT_OT_face_sets_create";
+ ot->description = "Create a new Face Set";
+
+ /* api callbacks */
+ ot->exec = sculpt_face_set_create_exec;
+ ot->poll = SCULPT_mode_poll;
+
+ ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
+
+ RNA_def_enum(
+ ot->srna, "mode", prop_sculpt_face_set_create_types, SCULPT_FACE_SET_MASKED, "Mode", "");
+}
+
+typedef enum eSculptFaceSetsInitMode {
+ SCULPT_FACE_SETS_FROM_LOOSE_PARTS = 0,
+ SCULPT_FACE_SETS_FROM_MATERIALS = 1,
+ SCULPT_FACE_SETS_FROM_NORMALS = 2,
+ SCULPT_FACE_SETS_FROM_UV_SEAMS = 3,
+ SCULPT_FACE_SETS_FROM_CREASES = 4,
+ SCULPT_FACE_SETS_FROM_SHARP_EDGES = 5,
+ SCULPT_FACE_SETS_FROM_BEVEL_WEIGHT = 6,
+ SCULPT_FACE_SETS_FROM_FACE_MAPS = 7,
+} eSculptFaceSetsInitMode;
+
+static EnumPropertyItem prop_sculpt_face_sets_init_types[] = {
+ {
+ SCULPT_FACE_SETS_FROM_LOOSE_PARTS,
+ "LOOSE_PARTS",
+ 0,
+ "Face Sets From Loose Parts",
+ "Create a Face Set per loose part in the mesh",
+ },
+ {
+ SCULPT_FACE_SETS_FROM_MATERIALS,
+ "MATERIALS",
+ 0,
+ "Face Sets From Material Slots",
+ "Create a Face Set per Material Slot",
+ },
+ {
+ SCULPT_FACE_SETS_FROM_NORMALS,
+ "NORMALS",
+ 0,
+ "Face Sets From Mesh Normals",
+ "Create Face Sets for Faces that have similar normal",
+ },
+ {
+ SCULPT_FACE_SETS_FROM_UV_SEAMS,
+ "UV_SEAMS",
+ 0,
+ "Face Sets From UV Seams",
+ "Create Face Sets using UV Seams as boundaries",
+ },
+ {
+ SCULPT_FACE_SETS_FROM_CREASES,
+ "CREASES",
+ 0,
+ "Face Sets From Edge Creases",
+ "Create Face Sets using Edge Creases as boundaries",
+ },
+ {
+ SCULPT_FACE_SETS_FROM_BEVEL_WEIGHT,
+ "BEVEL_WEIGHT",
+ 0,
+ "Face Sets From Bevel Weight",
+ "Create Face Sets using Bevel Weights as boundaries",
+ },
+ {
+ SCULPT_FACE_SETS_FROM_SHARP_EDGES,
+ "SHARP_EDGES",
+ 0,
+ "Face Sets From Sharp Edges",
+ "Create Face Sets using Sharp Edges as boundaries",
+ },
+ {
+ SCULPT_FACE_SETS_FROM_FACE_MAPS,
+ "FACE_MAPS",
+ 0,
+ "Face Sets From Face Maps",
+ "Create a Face Set per Face Map",
+ },
+ {0, NULL, 0, NULL, NULL},
+};
+
+typedef bool (*face_sets_flood_fill_test)(
+ BMesh *bm, BMFace *from_f, BMEdge *from_e, BMFace *to_f, const float threshold);
+
+static bool sculpt_face_sets_init_loose_parts_test(BMesh *UNUSED(bm),
+ BMFace *UNUSED(from_f),
+ BMEdge *UNUSED(from_e),
+ BMFace *UNUSED(to_f),
+ const float UNUSED(threshold))
+{
+ return true;
+}
+
+static bool sculpt_face_sets_init_normals_test(
+ BMesh *UNUSED(bm), BMFace *from_f, BMEdge *UNUSED(from_e), BMFace *to_f, const float threshold)
+{
+ return fabsf(dot_v3v3(from_f->no, to_f->no)) > threshold;
+}
+
+static bool sculpt_face_sets_init_uv_seams_test(BMesh *UNUSED(bm),
+ BMFace *UNUSED(from_f),
+ BMEdge *from_e,
+ BMFace *UNUSED(to_f),
+ const float UNUSED(threshold))
+{
+ return !BM_elem_flag_test(from_e, BM_ELEM_SEAM);
+}
+
+static bool sculpt_face_sets_init_crease_test(
+ BMesh *bm, BMFace *UNUSED(from_f), BMEdge *from_e, BMFace *UNUSED(to_f), const float threshold)
+{
+ return BM_elem_float_data_get(&bm->edata, from_e, CD_CREASE) < threshold;
+}
+
+static bool sculpt_face_sets_init_bevel_weight_test(
+ BMesh *bm, BMFace *UNUSED(from_f), BMEdge *from_e, BMFace *UNUSED(to_f), const float threshold)
+{
+ return BM_elem_float_data_get(&bm->edata, from_e, CD_BWEIGHT) < threshold;
+}
+
+static bool sculpt_face_sets_init_sharp_edges_test(BMesh *UNUSED(bm),
+ BMFace *UNUSED(from_f),
+ BMEdge *from_e,
+ BMFace *UNUSED(to_f),
+ const float UNUSED(threshold))
+{
+ return BM_elem_flag_test(from_e, BM_ELEM_SMOOTH);
+}
+
+static void sculpt_face_sets_init_flood_fill(Object *ob,
+ face_sets_flood_fill_test test,
+ const float threshold)
+{
+ SculptSession *ss = ob->sculpt;
+ Mesh *mesh = ob->data;
+ BMesh *bm;
+ const BMAllocTemplate allocsize = BMALLOC_TEMPLATE_FROM_ME(mesh);
+ bm = BM_mesh_create(&allocsize,
+ &((struct BMeshCreateParams){
+ .use_toolflags = true,
+ }));
+
+ BM_mesh_bm_from_me(bm,
+ mesh,
+ (&(struct BMeshFromMeshParams){
+ .calc_face_normal = true,
+ }));
+
+ BLI_bitmap *visited_faces = BLI_BITMAP_NEW(mesh->totpoly, "visited faces");
+ const int totfaces = mesh->totpoly;
+
+ int *face_sets = ss->face_sets;
+
+ BM_mesh_elem_table_init(bm, BM_FACE);
+ BM_mesh_elem_table_ensure(bm, BM_FACE);
+
+ int next_face_set = 1;
+
+ for (int i = 0; i < totfaces; i++) {
+ if (!BLI_BITMAP_TEST(visited_faces, i)) {
+ GSQueue *queue;
+ queue = BLI_gsqueue_new(sizeof(int));
+
+ face_sets[i] = next_face_set;
+ BLI_BITMAP_ENABLE(visited_faces, i);
+ BLI_gsqueue_push(queue, &i);
+
+ while (!BLI_gsqueue_is_empty(queue)) {
+ int from_f;
+ BLI_gsqueue_pop(queue, &from_f);
+
+ BMFace *f, *f_neighbor;
+ BMEdge *ed;
+ BMIter iter_a, iter_b;
+
+ f = BM_face_at_index(bm, from_f);
+
+ BM_ITER_ELEM (ed, &iter_a, f, BM_EDGES_OF_FACE) {
+ BM_ITER_ELEM (f_neighbor, &iter_b, ed, BM_FACES_OF_EDGE) {
+ if (f_neighbor != f) {
+ int neighbor_face_index = BM_elem_index_get(f_neighbor);
+ if (!BLI_BITMAP_TEST(visited_faces, neighbor_face_index)) {
+ if (test(bm, f, ed, f_neighbor, threshold)) {
+ face_sets[neighbor_face_index] = next_face_set;
+ BLI_BITMAP_ENABLE(visited_faces, neighbor_face_index);
+ BLI_gsqueue_push(queue, &neighbor_face_index);
+ }
+ }
+ }
+ }
+ }
+ }
+
+ next_face_set += 1;
+
+ BLI_gsqueue_free(queue);
+ }
+ }
+
+ MEM_SAFE_FREE(visited_faces);
+
+ BM_mesh_free(bm);
+}
+
+static void sculpt_face_sets_init_loop(Object *ob, const int mode)
+{
+ Mesh *mesh = ob->data;
+ SculptSession *ss = ob->sculpt;
+ BMesh *bm;
+ const BMAllocTemplate allocsize = BMALLOC_TEMPLATE_FROM_ME(mesh);
+ bm = BM_mesh_create(&allocsize,
+ &((struct BMeshCreateParams){
+ .use_toolflags = true,
+ }));
+
+ BM_mesh_bm_from_me(bm,
+ mesh,
+ (&(struct BMeshFromMeshParams){
+ .calc_face_normal = true,
+ }));
+ BMIter iter;
+ BMFace *f;
+
+ const int cd_fmaps_offset = CustomData_get_offset(&bm->pdata, CD_FACEMAP);
+
+ BM_ITER_MESH (f, &iter, bm, BM_FACES_OF_MESH) {
+ if (mode == SCULPT_FACE_SETS_FROM_MATERIALS) {
+ ss->face_sets[BM_elem_index_get(f)] = (int)(f->mat_nr + 1);
+ }
+ else if (mode == SCULPT_FACE_SETS_FROM_FACE_MAPS) {
+ if (cd_fmaps_offset != -1) {
+ ss->face_sets[BM_elem_index_get(f)] = BM_ELEM_CD_GET_INT(f, cd_fmaps_offset) + 2;
+ }
+ else {
+ ss->face_sets[BM_elem_index_get(f)] = 1;
+ }
+ }
+ }
+ BM_mesh_free(bm);
+}
+
+static int sculpt_face_set_init_exec(bContext *C, wmOperator *op)
+{
+ Object *ob = CTX_data_active_object(C);
+ SculptSession *ss = ob->sculpt;
+ ARegion *region = CTX_wm_region(C);
+ Depsgraph *depsgraph = CTX_data_depsgraph_pointer(C);
+
+ const int mode = RNA_enum_get(op->ptr, "mode");
+
+ /* Dyntopo not supported. */
+ if (BKE_pbvh_type(ss->pbvh) == PBVH_BMESH) {
+ return OPERATOR_CANCELLED;
+ }
+
+ BKE_sculpt_update_object_for_edit(depsgraph, ob, true, false);
+
+ PBVH *pbvh = ob->sculpt->pbvh;
+ PBVHNode **nodes;
+ int totnode;
+ BKE_pbvh_search_gather(pbvh, NULL, NULL, &nodes, &totnode);
+
+ if (!nodes) {
+ return OPERATOR_CANCELLED;
+ }
+
+ SCULPT_undo_push_begin("face set change");
+ SCULPT_undo_push_node(ob, nodes[0], SCULPT_UNDO_FACE_SETS);
+
+ const float threshold = RNA_float_get(op->ptr, "threshold");
+
+ switch (mode) {
+ case SCULPT_FACE_SETS_FROM_LOOSE_PARTS:
+ sculpt_face_sets_init_flood_fill(ob, sculpt_face_sets_init_loose_parts_test, threshold);
+ break;
+ case SCULPT_FACE_SETS_FROM_MATERIALS:
+ sculpt_face_sets_init_loop(ob, SCULPT_FACE_SETS_FROM_MATERIALS);
+ break;
+ case SCULPT_FACE_SETS_FROM_NORMALS:
+ sculpt_face_sets_init_flood_fill(ob, sculpt_face_sets_init_normals_test, threshold);
+ break;
+ case SCULPT_FACE_SETS_FROM_UV_SEAMS:
+ sculpt_face_sets_init_flood_fill(ob, sculpt_face_sets_init_uv_seams_test, threshold);
+ break;
+ case SCULPT_FACE_SETS_FROM_CREASES:
+ sculpt_face_sets_init_flood_fill(ob, sculpt_face_sets_init_crease_test, threshold);
+ break;
+ case SCULPT_FACE_SETS_FROM_SHARP_EDGES:
+ sculpt_face_sets_init_flood_fill(ob, sculpt_face_sets_init_sharp_edges_test, threshold);
+ break;
+ case SCULPT_FACE_SETS_FROM_BEVEL_WEIGHT:
+ sculpt_face_sets_init_flood_fill(ob, sculpt_face_sets_init_bevel_weight_test, threshold);
+ break;
+ case SCULPT_FACE_SETS_FROM_FACE_MAPS:
+ sculpt_face_sets_init_loop(ob, SCULPT_FACE_SETS_FROM_FACE_MAPS);
+ break;
+ }
+
+ SCULPT_undo_push_end();
+
+ /* Sync face sets visibility and vertex visibility as now all Face Sets are visible. */
+ SCULPT_visibility_sync_all_face_sets_to_vertices(ss);
+
+ for (int i = 0; i < totnode; i++) {
+ BKE_pbvh_node_mark_update_visibility(nodes[i]);
+ }
+
+ BKE_pbvh_update_vertex_data(ss->pbvh, PBVH_UpdateVisibility);
+
+ MEM_SAFE_FREE(nodes);
+
+ if (BKE_pbvh_type(pbvh) == PBVH_FACES) {
+ BKE_mesh_flush_hidden_from_verts(ob->data);
+ }
+
+ ED_region_tag_redraw(region);
+ DEG_id_tag_update(&ob->id, ID_RECALC_SHADING);
+
+ View3D *v3d = CTX_wm_view3d(C);
+ if (!BKE_sculptsession_use_pbvh_draw(ob, v3d)) {
+ DEG_id_tag_update(&ob->id, ID_RECALC_GEOMETRY);
+ }
+
+ return OPERATOR_FINISHED;
+}
+
+void SCULPT_OT_face_sets_init(wmOperatorType *ot)
+{
+ /* identifiers */
+ ot->name = "Init Face Sets";
+ ot->idname = "SCULPT_OT_face_sets_init";
+ ot->description = "Initializes all Face Sets in the mesh";
+
+ /* api callbacks */
+ ot->exec = sculpt_face_set_init_exec;
+ ot->poll = SCULPT_mode_poll;
+
+ ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
+
+ RNA_def_enum(
+ ot->srna, "mode", prop_sculpt_face_sets_init_types, SCULPT_FACE_SET_MASKED, "Mode", "");
+ RNA_def_float(
+ ot->srna,
+ "threshold",
+ 0.5f,
+ 0.0f,
+ 1.0f,
+ "Threshold",
+ "Minimum value to consider a certain attribute a boundary when creating the Face Sets",
+ 0.0f,
+ 1.0f);
+}
+
+typedef enum eSculptFaceGroupVisibilityModes {
+ SCULPT_FACE_SET_VISIBILITY_TOGGLE = 0,
+ SCULPT_FACE_SET_VISIBILITY_SHOW_ACTIVE = 1,
+ SCULPT_FACE_SET_VISIBILITY_HIDE_ACTIVE = 2,
+ SCULPT_FACE_SET_VISIBILITY_INVERT = 3,
+ SCULPT_FACE_SET_VISIBILITY_SHOW_ALL = 4,
+} eSculptFaceGroupVisibilityModes;
+
+static EnumPropertyItem prop_sculpt_face_sets_change_visibility_types[] = {
+ {
+ SCULPT_FACE_SET_VISIBILITY_TOGGLE,
+ "TOGGLE",
+ 0,
+ "Toggle Visibility",
+ "Hide all Face Sets except for the active one",
+ },
+ {
+ SCULPT_FACE_SET_VISIBILITY_SHOW_ACTIVE,
+ "SHOW_ACTIVE",
+ 0,
+ "Show Active Face Set",
+ "Show Active Face Set",
+ },
+ {
+ SCULPT_FACE_SET_VISIBILITY_HIDE_ACTIVE,
+ "HIDE_ACTIVE",
+ 0,
+ "Hide Active Face Sets",
+ "Hide Active Face Sets",
+ },
+ {
+ SCULPT_FACE_SET_VISIBILITY_INVERT,
+ "INVERT",
+ 0,
+ "Invert Face Set Visibility",
+ "Invert Face Set Visibility",
+ },
+ {
+ SCULPT_FACE_SET_VISIBILITY_SHOW_ALL,
+ "SHOW_ALL",
+ 0,
+ "Show All Face Sets",
+ "Show All Face Sets",
+ },
+ {0, NULL, 0, NULL, NULL},
+};
+
+static int sculpt_face_sets_change_visibility_exec(bContext *C, wmOperator *op)
+{
+ Object *ob = CTX_data_active_object(C);
+ SculptSession *ss = ob->sculpt;
+ ARegion *region = CTX_wm_region(C);
+ Depsgraph *depsgraph = CTX_data_depsgraph_pointer(C);
+
+ /* Dyntopo not supported. */
+ if (BKE_pbvh_type(ss->pbvh) == PBVH_BMESH) {
+ return OPERATOR_CANCELLED;
+ }
+
+ BKE_sculpt_update_object_for_edit(depsgraph, ob, true, true);
+
+ const int tot_vert = SCULPT_vertex_count_get(ss);
+ const int mode = RNA_enum_get(op->ptr, "mode");
+ const int active_face_set = SCULPT_active_face_set_get(ss);
+
+ SCULPT_undo_push_begin("Hide area");
+
+ PBVH *pbvh = ob->sculpt->pbvh;
+ PBVHNode **nodes;
+ int totnode;
+
+ BKE_pbvh_search_gather(pbvh, NULL, NULL, &nodes, &totnode);
+
+ if (totnode == 0) {
+ MEM_SAFE_FREE(nodes);
+ return OPERATOR_CANCELLED;
+ }
+
+ SCULPT_undo_push_node(ob, nodes[0], SCULPT_UNDO_FACE_SETS);
+
+ if (mode == SCULPT_FACE_SET_VISIBILITY_TOGGLE) {
+ bool hidden_vertex = false;
+
+ /* This can fail with regular meshes with non-manifold geometry as the visibility state can't
+ * be synced from face sets to non-manifold vertices. */
+ if (BKE_pbvh_type(ss->pbvh) == PBVH_GRIDS) {
+ for (int i = 0; i < tot_vert; i++) {
+ if (!SCULPT_vertex_visible_get(ss, i)) {
+ hidden_vertex = true;
+ break;
+ }
+ }
+ }
+
+ for (int i = 0; i < ss->totfaces; i++) {
+ if (ss->face_sets[i] <= 0) {
+ hidden_vertex = true;
+ break;
+ }
+ }
+
+ if (hidden_vertex) {
+ SCULPT_face_sets_visibility_all_set(ss, true);
+ }
+ else {
+ SCULPT_face_sets_visibility_all_set(ss, false);
+ SCULPT_face_set_visibility_set(ss, active_face_set, true);
+ }
+ }
+
+ if (mode == SCULPT_FACE_SET_VISIBILITY_SHOW_ALL) {
+ SCULPT_face_sets_visibility_all_set(ss, true);
+ }
+
+ if (mode == SCULPT_FACE_SET_VISIBILITY_SHOW_ACTIVE) {
+ SCULPT_face_sets_visibility_all_set(ss, false);
+ SCULPT_face_set_visibility_set(ss, active_face_set, true);
+ for (int i = 0; i < tot_vert; i++) {
+ SCULPT_vertex_visible_set(ss,
+ i,
+ SCULPT_vertex_visible_get(ss, i) &&
+ SCULPT_vertex_has_face_set(ss, i, active_face_set));
+ }
+ }
+
+ if (mode == SCULPT_FACE_SET_VISIBILITY_HIDE_ACTIVE) {
+ SCULPT_face_set_visibility_set(ss, active_face_set, false);
+ }
+
+ if (mode == SCULPT_FACE_SET_VISIBILITY_INVERT) {
+ SCULPT_face_sets_visibility_invert(ss);
+ }
+
+ /* For modes that use the cursor active vertex, update the rotation origin for viewport
+ * navigation. */
+ if (ELEM(mode, SCULPT_FACE_SET_VISIBILITY_TOGGLE, SCULPT_FACE_SET_VISIBILITY_SHOW_ACTIVE)) {
+ UnifiedPaintSettings *ups = &CTX_data_tool_settings(C)->unified_paint_settings;
+ float location[3];
+ copy_v3_v3(location, SCULPT_active_vertex_co_get(ss));
+ mul_m4_v3(ob->obmat, location);
+ copy_v3_v3(ups->average_stroke_accum, location);
+ ups->average_stroke_counter = 1;
+ ups->last_stroke_valid = true;
+ }
+
+ /* Sync face sets visibility and vertex visibility. */
+ SCULPT_visibility_sync_all_face_sets_to_vertices(ss);
+
+ SCULPT_undo_push_end();
+
+ for (int i = 0; i < totnode; i++) {
+ BKE_pbvh_node_mark_update_visibility(nodes[i]);
+ }
+
+ BKE_pbvh_update_vertex_data(ss->pbvh, PBVH_UpdateVisibility);
+
+ MEM_SAFE_FREE(nodes);
+
+ if (BKE_pbvh_type(pbvh) == PBVH_FACES) {
+ BKE_mesh_flush_hidden_from_verts(ob->data);
+ }
+
+ ED_region_tag_redraw(region);
+ DEG_id_tag_update(&ob->id, ID_RECALC_SHADING);
+
+ View3D *v3d = CTX_wm_view3d(C);
+ if (!BKE_sculptsession_use_pbvh_draw(ob, v3d)) {
+ DEG_id_tag_update(&ob->id, ID_RECALC_GEOMETRY);
+ }
+ return OPERATOR_FINISHED;
+}
+
+void SCULPT_OT_face_sets_change_visibility(wmOperatorType *ot)
+{
+ /* Identifiers. */
+ ot->name = "Face Sets Visibility";
+ ot->idname = "SCULPT_OT_face_set_change_visibility";
+ ot->description = "Change the visibility of the Face Sets of the sculpt";
+
+ /* Api callbacks. */
+ ot->exec = sculpt_face_sets_change_visibility_exec;
+ ot->poll = SCULPT_mode_poll;
+
+ ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
+
+ RNA_def_enum(ot->srna,
+ "mode",
+ prop_sculpt_face_sets_change_visibility_types,
+ SCULPT_FACE_SET_VISIBILITY_TOGGLE,
+ "Mode",
+ "");
+}
+
+static int sculpt_face_sets_randomize_colors_exec(bContext *C, wmOperator *UNUSED(op))
+{
+
+ Object *ob = CTX_data_active_object(C);
+ SculptSession *ss = ob->sculpt;
+ ARegion *region = CTX_wm_region(C);
+
+ /* Dyntopo not supported. */
+ if (BKE_pbvh_type(ss->pbvh) == PBVH_BMESH) {
+ return OPERATOR_CANCELLED;
+ }
+
+ PBVH *pbvh = ob->sculpt->pbvh;
+ PBVHNode **nodes;
+ int totnode;
+ Mesh *mesh = ob->data;
+
+ mesh->face_sets_color_seed += 1;
+ if (ss->face_sets) {
+ const int random_index = clamp_i(ss->totfaces * BLI_hash_int_01(mesh->face_sets_color_seed),
+ 0,
+ max_ii(0, ss->totfaces - 1));
+ mesh->face_sets_color_default = ss->face_sets[random_index];
+ }
+ BKE_pbvh_face_sets_color_set(pbvh, mesh->face_sets_color_seed, mesh->face_sets_color_default);
+
+ BKE_pbvh_search_gather(pbvh, NULL, NULL, &nodes, &totnode);
+ for (int i = 0; i < totnode; i++) {
+ BKE_pbvh_node_mark_redraw(nodes[i]);
+ }
+
+ MEM_SAFE_FREE(nodes);
+
+ View3D *v3d = CTX_wm_view3d(C);
+ if (!BKE_sculptsession_use_pbvh_draw(ob, v3d)) {
+ DEG_id_tag_update(&ob->id, ID_RECALC_SHADING);
+ }
+
+ ED_region_tag_redraw(region);
+ WM_event_add_notifier(C, NC_GEOM | ND_DATA, ob->data);
+
+ return OPERATOR_FINISHED;
+}
+
+void SCULPT_OT_face_sets_randomize_colors(wmOperatorType *ot)
+{
+ /* Identifiers. */
+ ot->name = "Randomize Face Sets Colors";
+ ot->idname = "SCULPT_OT_face_sets_randomize_colors";
+ ot->description = "Generates a new set of random colors to render the Face Sets in the viewport";
+
+ /* Api callbacks. */
+ ot->exec = sculpt_face_sets_randomize_colors_exec;
+ ot->poll = SCULPT_mode_poll;
+
+ ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
+}
diff --git a/source/blender/editors/sculpt_paint/sculpt_filter_mask.c b/source/blender/editors/sculpt_paint/sculpt_filter_mask.c
new file mode 100644
index 00000000000..d2a683461a7
--- /dev/null
+++ b/source/blender/editors/sculpt_paint/sculpt_filter_mask.c
@@ -0,0 +1,502 @@
+/*
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * The Original Code is Copyright (C) 2020 Blender Foundation.
+ * All rights reserved.
+ */
+
+/** \file
+ * \ingroup edsculpt
+ */
+
+#include "MEM_guardedalloc.h"
+
+#include "BLI_blenlib.h"
+#include "BLI_hash.h"
+#include "BLI_math.h"
+#include "BLI_task.h"
+
+#include "DNA_mesh_types.h"
+#include "DNA_meshdata_types.h"
+
+#include "BKE_brush.h"
+#include "BKE_context.h"
+#include "BKE_mesh.h"
+#include "BKE_mesh_mapping.h"
+#include "BKE_object.h"
+#include "BKE_paint.h"
+#include "BKE_pbvh.h"
+#include "BKE_scene.h"
+
+#include "DEG_depsgraph.h"
+
+#include "WM_api.h"
+#include "WM_message.h"
+#include "WM_toolsystem.h"
+#include "WM_types.h"
+
+#include "ED_object.h"
+#include "ED_screen.h"
+#include "ED_sculpt.h"
+#include "paint_intern.h"
+#include "sculpt_intern.h"
+
+#include "RNA_access.h"
+#include "RNA_define.h"
+
+#include "UI_interface.h"
+
+#include "bmesh.h"
+
+#include <math.h>
+#include <stdlib.h>
+
+typedef enum eSculptMaskFilterTypes {
+ MASK_FILTER_SMOOTH = 0,
+ MASK_FILTER_SHARPEN = 1,
+ MASK_FILTER_GROW = 2,
+ MASK_FILTER_SHRINK = 3,
+ MASK_FILTER_CONTRAST_INCREASE = 5,
+ MASK_FILTER_CONTRAST_DECREASE = 6,
+} eSculptMaskFilterTypes;
+
+static EnumPropertyItem prop_mask_filter_types[] = {
+ {MASK_FILTER_SMOOTH, "SMOOTH", 0, "Smooth Mask", "Smooth mask"},
+ {MASK_FILTER_SHARPEN, "SHARPEN", 0, "Sharpen Mask", "Sharpen mask"},
+ {MASK_FILTER_GROW, "GROW", 0, "Grow Mask", "Grow mask"},
+ {MASK_FILTER_SHRINK, "SHRINK", 0, "Shrink Mask", "Shrink mask"},
+ {MASK_FILTER_CONTRAST_INCREASE,
+ "CONTRAST_INCREASE",
+ 0,
+ "Increase contrast",
+ "Increase the contrast of the paint mask"},
+ {MASK_FILTER_CONTRAST_DECREASE,
+ "CONTRAST_DECREASE",
+ 0,
+ "Decrease contrast",
+ "Decrease the contrast of the paint mask"},
+ {0, NULL, 0, NULL, NULL},
+};
+
+static void mask_filter_task_cb(void *__restrict userdata,
+ const int i,
+ const TaskParallelTLS *__restrict UNUSED(tls))
+{
+ SculptThreadedTaskData *data = userdata;
+ SculptSession *ss = data->ob->sculpt;
+ PBVHNode *node = data->nodes[i];
+ bool update = false;
+
+ const int mode = data->filter_type;
+ float contrast = 0.0f;
+
+ PBVHVertexIter vd;
+
+ if (mode == MASK_FILTER_CONTRAST_INCREASE) {
+ contrast = 0.1f;
+ }
+
+ if (mode == MASK_FILTER_CONTRAST_DECREASE) {
+ contrast = -0.1f;
+ }
+
+ BKE_pbvh_vertex_iter_begin(ss->pbvh, node, vd, PBVH_ITER_UNIQUE)
+ {
+ float delta, gain, offset, max, min;
+ float prev_val = *vd.mask;
+ SculptVertexNeighborIter ni;
+ switch (mode) {
+ case MASK_FILTER_SMOOTH:
+ case MASK_FILTER_SHARPEN: {
+ float val = SCULPT_neighbor_mask_average(ss, vd.index);
+
+ val -= *vd.mask;
+
+ if (mode == MASK_FILTER_SMOOTH) {
+ *vd.mask += val;
+ }
+ else if (mode == MASK_FILTER_SHARPEN) {
+ if (*vd.mask > 0.5f) {
+ *vd.mask += 0.05f;
+ }
+ else {
+ *vd.mask -= 0.05f;
+ }
+ *vd.mask += val / 2.0f;
+ }
+ break;
+ }
+ case MASK_FILTER_GROW:
+ max = 0.0f;
+ SCULPT_VERTEX_NEIGHBORS_ITER_BEGIN (ss, vd.index, ni) {
+ float vmask_f = data->prev_mask[ni.index];
+ if (vmask_f > max) {
+ max = vmask_f;
+ }
+ }
+ SCULPT_VERTEX_NEIGHBORS_ITER_END(ni);
+ *vd.mask = max;
+ break;
+ case MASK_FILTER_SHRINK:
+ min = 1.0f;
+ SCULPT_VERTEX_NEIGHBORS_ITER_BEGIN (ss, vd.index, ni) {
+ float vmask_f = data->prev_mask[ni.index];
+ if (vmask_f < min) {
+ min = vmask_f;
+ }
+ }
+ SCULPT_VERTEX_NEIGHBORS_ITER_END(ni);
+ *vd.mask = min;
+ break;
+ case MASK_FILTER_CONTRAST_INCREASE:
+ case MASK_FILTER_CONTRAST_DECREASE:
+ delta = contrast / 2.0f;
+ gain = 1.0f - delta * 2.0f;
+ if (contrast > 0) {
+ gain = 1.0f / ((gain != 0.0f) ? gain : FLT_EPSILON);
+ offset = gain * (-delta);
+ }
+ else {
+ delta *= -1.0f;
+ offset = gain * (delta);
+ }
+ *vd.mask = gain * (*vd.mask) + offset;
+ break;
+ }
+ CLAMP(*vd.mask, 0.0f, 1.0f);
+ if (*vd.mask != prev_val) {
+ update = true;
+ }
+ if (vd.mvert) {
+ vd.mvert->flag |= ME_VERT_PBVH_UPDATE;
+ }
+ }
+ BKE_pbvh_vertex_iter_end;
+
+ if (update) {
+ BKE_pbvh_node_mark_update_mask(node);
+ }
+}
+
+static int sculpt_mask_filter_exec(bContext *C, wmOperator *op)
+{
+ ARegion *region = CTX_wm_region(C);
+ Object *ob = CTX_data_active_object(C);
+ SculptSession *ss = ob->sculpt;
+ Depsgraph *depsgraph = CTX_data_depsgraph_pointer(C);
+ PBVH *pbvh = ob->sculpt->pbvh;
+ PBVHNode **nodes;
+ Sculpt *sd = CTX_data_tool_settings(C)->sculpt;
+ int totnode;
+ int filter_type = RNA_enum_get(op->ptr, "filter_type");
+
+ BKE_sculpt_update_object_for_edit(depsgraph, ob, true, true);
+
+ SCULPT_vertex_random_access_init(ss);
+
+ if (!ob->sculpt->pmap) {
+ return OPERATOR_CANCELLED;
+ }
+
+ int num_verts = SCULPT_vertex_count_get(ss);
+
+ BKE_pbvh_search_gather(pbvh, NULL, NULL, &nodes, &totnode);
+ SCULPT_undo_push_begin("Mask filter");
+
+ for (int i = 0; i < totnode; i++) {
+ SCULPT_undo_push_node(ob, nodes[i], SCULPT_UNDO_MASK);
+ }
+
+ float *prev_mask = NULL;
+ int iterations = RNA_int_get(op->ptr, "iterations");
+
+ /* Auto iteration count calculates the number of iteration based on the vertices of the mesh to
+ * avoid adding an unnecessary amount of undo steps when using the operator from a shortcut.
+ * One iteration per 50000 vertices in the mesh should be fine in most cases.
+ * Maybe we want this to be configurable. */
+ if (RNA_boolean_get(op->ptr, "auto_iteration_count")) {
+ iterations = (int)(num_verts / 50000.0f) + 1;
+ }
+
+ for (int i = 0; i < iterations; i++) {
+ if (ELEM(filter_type, MASK_FILTER_GROW, MASK_FILTER_SHRINK)) {
+ prev_mask = MEM_mallocN(num_verts * sizeof(float), "prevmask");
+ for (int j = 0; j < num_verts; j++) {
+ prev_mask[j] = SCULPT_vertex_mask_get(ss, j);
+ }
+ }
+
+ SculptThreadedTaskData data = {
+ .sd = sd,
+ .ob = ob,
+ .nodes = nodes,
+ .filter_type = filter_type,
+ .prev_mask = prev_mask,
+ };
+
+ TaskParallelSettings settings;
+ BKE_pbvh_parallel_range_settings(&settings, (sd->flags & SCULPT_USE_OPENMP), totnode);
+ BLI_task_parallel_range(0, totnode, &data, mask_filter_task_cb, &settings);
+
+ if (ELEM(filter_type, MASK_FILTER_GROW, MASK_FILTER_SHRINK)) {
+ MEM_freeN(prev_mask);
+ }
+ }
+
+ MEM_SAFE_FREE(nodes);
+
+ SCULPT_undo_push_end();
+
+ ED_region_tag_redraw(region);
+ WM_event_add_notifier(C, NC_OBJECT | ND_DRAW, ob);
+ return OPERATOR_FINISHED;
+}
+
+void SCULPT_mask_filter_smooth_apply(
+ Sculpt *sd, Object *ob, PBVHNode **nodes, const int totnode, const int smooth_iterations)
+{
+ SculptThreadedTaskData data = {
+ .sd = sd,
+ .ob = ob,
+ .nodes = nodes,
+ .filter_type = MASK_FILTER_SMOOTH,
+ };
+
+ for (int i = 0; i < smooth_iterations; i++) {
+ TaskParallelSettings settings;
+ BKE_pbvh_parallel_range_settings(&settings, (sd->flags & SCULPT_USE_OPENMP), totnode);
+ BLI_task_parallel_range(0, totnode, &data, mask_filter_task_cb, &settings);
+ }
+}
+
+void SCULPT_OT_mask_filter(struct wmOperatorType *ot)
+{
+ /* Identifiers. */
+ ot->name = "Mask Filter";
+ ot->idname = "SCULPT_OT_mask_filter";
+ ot->description = "Applies a filter to modify the current mask";
+
+ /* API callbacks. */
+ ot->exec = sculpt_mask_filter_exec;
+ ot->poll = SCULPT_mode_poll;
+
+ ot->flag = OPTYPE_REGISTER;
+
+ /* RNA. */
+ RNA_def_enum(ot->srna,
+ "filter_type",
+ prop_mask_filter_types,
+ MASK_FILTER_SMOOTH,
+ "Type",
+ "Filter that is going to be applied to the mask");
+ RNA_def_int(ot->srna,
+ "iterations",
+ 1,
+ 1,
+ 100,
+ "Iterations",
+ "Number of times that the filter is going to be applied",
+ 1,
+ 100);
+ RNA_def_boolean(
+ ot->srna,
+ "auto_iteration_count",
+ false,
+ "Auto Iteration Count",
+ "Use a automatic number of iterations based on the number of vertices of the sculpt");
+}
+
+static float neighbor_dirty_mask(SculptSession *ss, PBVHVertexIter *vd)
+{
+ int total = 0;
+ float avg[3];
+ zero_v3(avg);
+
+ SculptVertexNeighborIter ni;
+ SCULPT_VERTEX_NEIGHBORS_ITER_BEGIN (ss, vd->index, ni) {
+ float normalized[3];
+ sub_v3_v3v3(normalized, SCULPT_vertex_co_get(ss, ni.index), vd->co);
+ normalize_v3(normalized);
+ add_v3_v3(avg, normalized);
+ total++;
+ }
+ SCULPT_VERTEX_NEIGHBORS_ITER_END(ni);
+
+ if (total > 0) {
+ mul_v3_fl(avg, 1.0f / total);
+ float normal[3];
+ if (vd->no) {
+ normal_short_to_float_v3(normal, vd->no);
+ }
+ else {
+ copy_v3_v3(normal, vd->fno);
+ }
+ float dot = dot_v3v3(avg, normal);
+ float angle = max_ff(saacosf(dot), 0.0f);
+ return angle;
+ }
+ return 0.0f;
+}
+
+typedef struct DirtyMaskRangeData {
+ float min, max;
+} DirtyMaskRangeData;
+
+static void dirty_mask_compute_range_task_cb(void *__restrict userdata,
+ const int i,
+ const TaskParallelTLS *__restrict tls)
+{
+ SculptThreadedTaskData *data = userdata;
+ SculptSession *ss = data->ob->sculpt;
+ PBVHNode *node = data->nodes[i];
+ DirtyMaskRangeData *range = tls->userdata_chunk;
+ PBVHVertexIter vd;
+
+ BKE_pbvh_vertex_iter_begin(ss->pbvh, node, vd, PBVH_ITER_UNIQUE)
+ {
+ float dirty_mask = neighbor_dirty_mask(ss, &vd);
+ range->min = min_ff(dirty_mask, range->min);
+ range->max = max_ff(dirty_mask, range->max);
+ }
+ BKE_pbvh_vertex_iter_end;
+}
+
+static void dirty_mask_compute_range_reduce(const void *__restrict UNUSED(userdata),
+ void *__restrict chunk_join,
+ void *__restrict chunk)
+{
+ DirtyMaskRangeData *join = chunk_join;
+ DirtyMaskRangeData *range = chunk;
+ join->min = min_ff(range->min, join->min);
+ join->max = max_ff(range->max, join->max);
+}
+
+static void dirty_mask_apply_task_cb(void *__restrict userdata,
+ const int i,
+ const TaskParallelTLS *__restrict UNUSED(tls))
+{
+ SculptThreadedTaskData *data = userdata;
+ SculptSession *ss = data->ob->sculpt;
+ PBVHNode *node = data->nodes[i];
+ PBVHVertexIter vd;
+
+ const bool dirty_only = data->dirty_mask_dirty_only;
+ const float min = data->dirty_mask_min;
+ const float max = data->dirty_mask_max;
+
+ float range = max - min;
+ if (range < 0.0001f) {
+ range = 0.0f;
+ }
+ else {
+ range = 1.0f / range;
+ }
+
+ BKE_pbvh_vertex_iter_begin(ss->pbvh, node, vd, PBVH_ITER_UNIQUE)
+ {
+ float dirty_mask = neighbor_dirty_mask(ss, &vd);
+ float mask = *vd.mask + (1.0f - ((dirty_mask - min) * range));
+ if (dirty_only) {
+ mask = fminf(mask, 0.5f) * 2.0f;
+ }
+ *vd.mask = CLAMPIS(mask, 0.0f, 1.0f);
+
+ if (vd.mvert) {
+ vd.mvert->flag |= ME_VERT_PBVH_UPDATE;
+ }
+ }
+ BKE_pbvh_vertex_iter_end;
+ BKE_pbvh_node_mark_update_mask(node);
+}
+
+static int sculpt_dirty_mask_exec(bContext *C, wmOperator *op)
+{
+ ARegion *region = CTX_wm_region(C);
+ Object *ob = CTX_data_active_object(C);
+ SculptSession *ss = ob->sculpt;
+ Depsgraph *depsgraph = CTX_data_depsgraph_pointer(C);
+ PBVH *pbvh = ob->sculpt->pbvh;
+ PBVHNode **nodes;
+ Sculpt *sd = CTX_data_tool_settings(C)->sculpt;
+ int totnode;
+
+ BKE_sculpt_update_object_for_edit(depsgraph, ob, true, true);
+
+ SCULPT_vertex_random_access_init(ss);
+
+ if (!ob->sculpt->pmap) {
+ return OPERATOR_CANCELLED;
+ }
+
+ BKE_pbvh_search_gather(pbvh, NULL, NULL, &nodes, &totnode);
+ SCULPT_undo_push_begin("Dirty Mask");
+
+ for (int i = 0; i < totnode; i++) {
+ SCULPT_undo_push_node(ob, nodes[i], SCULPT_UNDO_MASK);
+ }
+
+ SculptThreadedTaskData data = {
+ .sd = sd,
+ .ob = ob,
+ .nodes = nodes,
+ .dirty_mask_dirty_only = RNA_boolean_get(op->ptr, "dirty_only"),
+ };
+ DirtyMaskRangeData range = {
+ .min = FLT_MAX,
+ .max = -FLT_MAX,
+ };
+
+ TaskParallelSettings settings;
+ BKE_pbvh_parallel_range_settings(&settings, (sd->flags & SCULPT_USE_OPENMP), totnode);
+
+ settings.func_reduce = dirty_mask_compute_range_reduce;
+ settings.userdata_chunk = &range;
+ settings.userdata_chunk_size = sizeof(DirtyMaskRangeData);
+
+ BLI_task_parallel_range(0, totnode, &data, dirty_mask_compute_range_task_cb, &settings);
+ data.dirty_mask_min = range.min;
+ data.dirty_mask_max = range.max;
+ BLI_task_parallel_range(0, totnode, &data, dirty_mask_apply_task_cb, &settings);
+
+ MEM_SAFE_FREE(nodes);
+
+ BKE_pbvh_update_vertex_data(pbvh, PBVH_UpdateMask);
+
+ SCULPT_undo_push_end();
+
+ ED_region_tag_redraw(region);
+
+ WM_event_add_notifier(C, NC_OBJECT | ND_DRAW, ob);
+
+ return OPERATOR_FINISHED;
+}
+
+void SCULPT_OT_dirty_mask(struct wmOperatorType *ot)
+{
+ /* Identifiers. */
+ ot->name = "Dirty Mask";
+ ot->idname = "SCULPT_OT_dirty_mask";
+ ot->description = "Generates a mask based on the geometry cavity and pointiness";
+
+ /* API callbacks. */
+ ot->exec = sculpt_dirty_mask_exec;
+ ot->poll = SCULPT_mode_poll;
+
+ ot->flag = OPTYPE_REGISTER;
+
+ /* RNA. */
+ RNA_def_boolean(
+ ot->srna, "dirty_only", false, "Dirty Only", "Don't calculate cleans for convex areas");
+}
diff --git a/source/blender/editors/sculpt_paint/sculpt_filter_mesh.c b/source/blender/editors/sculpt_paint/sculpt_filter_mesh.c
new file mode 100644
index 00000000000..fd0f67f040a
--- /dev/null
+++ b/source/blender/editors/sculpt_paint/sculpt_filter_mesh.c
@@ -0,0 +1,660 @@
+/*
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * The Original Code is Copyright (C) 2020 Blender Foundation.
+ * All rights reserved.
+ */
+
+/** \file
+ * \ingroup edsculpt
+ */
+
+#include "MEM_guardedalloc.h"
+
+#include "BLI_blenlib.h"
+#include "BLI_hash.h"
+#include "BLI_math.h"
+#include "BLI_task.h"
+
+#include "DNA_mesh_types.h"
+#include "DNA_meshdata_types.h"
+
+#include "BKE_brush.h"
+#include "BKE_context.h"
+#include "BKE_mesh.h"
+#include "BKE_mesh_mapping.h"
+#include "BKE_object.h"
+#include "BKE_paint.h"
+#include "BKE_pbvh.h"
+#include "BKE_scene.h"
+
+#include "DEG_depsgraph.h"
+
+#include "WM_api.h"
+#include "WM_message.h"
+#include "WM_toolsystem.h"
+#include "WM_types.h"
+
+#include "ED_object.h"
+#include "ED_screen.h"
+#include "ED_sculpt.h"
+#include "paint_intern.h"
+#include "sculpt_intern.h"
+
+#include "RNA_access.h"
+#include "RNA_define.h"
+
+#include "UI_interface.h"
+
+#include "bmesh.h"
+
+#include <math.h>
+#include <stdlib.h>
+
+static void filter_cache_init_task_cb(void *__restrict userdata,
+ const int i,
+ const TaskParallelTLS *__restrict UNUSED(tls))
+{
+ SculptThreadedTaskData *data = userdata;
+ PBVHNode *node = data->nodes[i];
+
+ SCULPT_undo_push_node(data->ob, node, SCULPT_UNDO_COORDS);
+}
+
+void SCULPT_filter_cache_init(Object *ob, Sculpt *sd)
+{
+ SculptSession *ss = ob->sculpt;
+ PBVH *pbvh = ob->sculpt->pbvh;
+
+ ss->filter_cache = MEM_callocN(sizeof(FilterCache), "filter cache");
+
+ ss->filter_cache->random_seed = rand();
+
+ float center[3] = {0.0f};
+ SculptSearchSphereData search_data = {
+ .original = true,
+ .center = center,
+ .radius_squared = FLT_MAX,
+ .ignore_fully_masked = true,
+
+ };
+ BKE_pbvh_search_gather(pbvh,
+ SCULPT_search_sphere_cb,
+ &search_data,
+ &ss->filter_cache->nodes,
+ &ss->filter_cache->totnode);
+
+ for (int i = 0; i < ss->filter_cache->totnode; i++) {
+ BKE_pbvh_node_mark_normals_update(ss->filter_cache->nodes[i]);
+ }
+
+ /* mesh->runtime.subdiv_ccg is not available. Updating of the normals is done during drawing.
+ * Filters can't use normals in multires. */
+ if (BKE_pbvh_type(ss->pbvh) != PBVH_GRIDS) {
+ BKE_pbvh_update_normals(ss->pbvh, NULL);
+ }
+
+ SculptThreadedTaskData data = {
+ .sd = sd,
+ .ob = ob,
+ .nodes = ss->filter_cache->nodes,
+ };
+
+ TaskParallelSettings settings;
+ BKE_pbvh_parallel_range_settings(
+ &settings, (sd->flags & SCULPT_USE_OPENMP), ss->filter_cache->totnode);
+ BLI_task_parallel_range(
+ 0, ss->filter_cache->totnode, &data, filter_cache_init_task_cb, &settings);
+}
+
+void SCULPT_filter_cache_free(SculptSession *ss)
+{
+ if (ss->filter_cache->cloth_sim) {
+ SCULPT_cloth_simulation_free(ss->filter_cache->cloth_sim);
+ }
+ MEM_SAFE_FREE(ss->filter_cache->nodes);
+ MEM_SAFE_FREE(ss->filter_cache->mask_update_it);
+ MEM_SAFE_FREE(ss->filter_cache->prev_mask);
+ MEM_SAFE_FREE(ss->filter_cache->normal_factor);
+ MEM_SAFE_FREE(ss->filter_cache->prev_face_set);
+ MEM_SAFE_FREE(ss->filter_cache->automask);
+ MEM_SAFE_FREE(ss->filter_cache->surface_smooth_laplacian_disp);
+ MEM_SAFE_FREE(ss->filter_cache->sharpen_factor);
+ MEM_SAFE_FREE(ss->filter_cache);
+}
+
+typedef enum eSculptMeshFilterTypes {
+ MESH_FILTER_SMOOTH = 0,
+ MESH_FILTER_SCALE = 1,
+ MESH_FILTER_INFLATE = 2,
+ MESH_FILTER_SPHERE = 3,
+ MESH_FILTER_RANDOM = 4,
+ MESH_FILTER_RELAX = 5,
+ MESH_FILTER_RELAX_FACE_SETS = 6,
+ MESH_FILTER_SURFACE_SMOOTH = 7,
+ MESH_FILTER_SHARPEN = 8,
+} eSculptMeshFilterTypes;
+
+static EnumPropertyItem prop_mesh_filter_types[] = {
+ {MESH_FILTER_SMOOTH, "SMOOTH", 0, "Smooth", "Smooth mesh"},
+ {MESH_FILTER_SCALE, "SCALE", 0, "Scale", "Scale mesh"},
+ {MESH_FILTER_INFLATE, "INFLATE", 0, "Inflate", "Inflate mesh"},
+ {MESH_FILTER_SPHERE, "SPHERE", 0, "Sphere", "Morph into sphere"},
+ {MESH_FILTER_RANDOM, "RANDOM", 0, "Random", "Randomize vertex positions"},
+ {MESH_FILTER_RELAX, "RELAX", 0, "Relax", "Relax mesh"},
+ {MESH_FILTER_RELAX_FACE_SETS,
+ "RELAX_FACE_SETS",
+ 0,
+ "Relax Face Sets",
+ "Smooth the edges of all the Face Sets"},
+ {MESH_FILTER_SURFACE_SMOOTH,
+ "SURFACE_SMOOTH",
+ 0,
+ "Surface Smooth",
+ "Smooth the surface of the mesh, preserving the volume"},
+ {MESH_FILTER_SHARPEN, "SHARPEN", 0, "Sharpen", "Sharpen the cavities of the mesh"},
+ {0, NULL, 0, NULL, NULL},
+};
+
+typedef enum eMeshFilterDeformAxis {
+ MESH_FILTER_DEFORM_X = 1 << 0,
+ MESH_FILTER_DEFORM_Y = 1 << 1,
+ MESH_FILTER_DEFORM_Z = 1 << 2,
+} eMeshFilterDeformAxis;
+
+static EnumPropertyItem prop_mesh_filter_deform_axis_items[] = {
+ {MESH_FILTER_DEFORM_X, "X", 0, "X", "Deform in the X axis"},
+ {MESH_FILTER_DEFORM_Y, "Y", 0, "Y", "Deform in the Y axis"},
+ {MESH_FILTER_DEFORM_Z, "Z", 0, "Z", "Deform in the Z axis"},
+ {0, NULL, 0, NULL, NULL},
+};
+
+static bool sculpt_mesh_filter_needs_pmap(int filter_type, bool use_face_sets)
+{
+ return use_face_sets || ELEM(filter_type,
+ MESH_FILTER_SMOOTH,
+ MESH_FILTER_RELAX,
+ MESH_FILTER_RELAX_FACE_SETS,
+ MESH_FILTER_SURFACE_SMOOTH,
+ MESH_FILTER_SHARPEN);
+}
+
+static void mesh_filter_task_cb(void *__restrict userdata,
+ const int i,
+ const TaskParallelTLS *__restrict UNUSED(tls))
+{
+ SculptThreadedTaskData *data = userdata;
+ SculptSession *ss = data->ob->sculpt;
+ PBVHNode *node = data->nodes[i];
+
+ const int filter_type = data->filter_type;
+
+ SculptOrigVertData orig_data;
+ SCULPT_orig_vert_data_init(&orig_data, data->ob, data->nodes[i]);
+
+ /* When using the relax face sets meshes filter,
+ * each 3 iterations, do a whole mesh relax to smooth the contents of the Face Set. */
+ /* This produces better results as the relax operation is no completely focused on the
+ * boundaries. */
+ const bool relax_face_sets = !(ss->filter_cache->iteration_count % 3 == 0);
+
+ PBVHVertexIter vd;
+ BKE_pbvh_vertex_iter_begin(ss->pbvh, node, vd, PBVH_ITER_UNIQUE)
+ {
+ SCULPT_orig_vert_data_update(&orig_data, &vd);
+ float orig_co[3], val[3], avg[3], normal[3], disp[3], disp2[3], transform[3][3], final_pos[3];
+ float fade = vd.mask ? *vd.mask : 0.0f;
+ fade = 1.0f - fade;
+ fade *= data->filter_strength;
+
+ if (fade == 0.0f) {
+ continue;
+ }
+
+ if (ss->filter_cache->active_face_set != SCULPT_FACE_SET_NONE) {
+ if (!SCULPT_vertex_has_face_set(ss, vd.index, ss->filter_cache->active_face_set)) {
+ /* Surface Smooth can't skip the loop for this vertex as it needs to calculate its
+ * laplacian_disp. This value is accessed from the vertex neighbors when deforming the
+ * vertices, so it is needed for all vertices even if they are not going to be displaced.
+ */
+ if (filter_type == MESH_FILTER_SURFACE_SMOOTH) {
+ fade = 0.0f;
+ }
+ else {
+ continue;
+ }
+ }
+ /* Skip the edges of the face set when relaxing or smoothing.
+ * There is a relax face set option to relax the boundaries independently. */
+ if (filter_type == MESH_FILTER_RELAX) {
+ if (!SCULPT_vertex_has_unique_face_set(ss, vd.index)) {
+ continue;
+ }
+ }
+ }
+
+ if (ELEM(filter_type, MESH_FILTER_RELAX, MESH_FILTER_RELAX_FACE_SETS)) {
+ copy_v3_v3(orig_co, vd.co);
+ }
+ else {
+ copy_v3_v3(orig_co, orig_data.co);
+ }
+
+ if (filter_type == MESH_FILTER_RELAX_FACE_SETS) {
+ if (relax_face_sets == SCULPT_vertex_has_unique_face_set(ss, vd.index)) {
+ continue;
+ }
+ }
+
+ switch (filter_type) {
+ case MESH_FILTER_SMOOTH:
+ CLAMP(fade, -1.0f, 1.0f);
+ switch (BKE_pbvh_type(ss->pbvh)) {
+ case PBVH_FACES:
+ SCULPT_neighbor_average(ss, avg, vd.index);
+ break;
+ case PBVH_BMESH:
+ SCULPT_bmesh_neighbor_average(avg, vd.bm_vert);
+ break;
+ case PBVH_GRIDS:
+ SCULPT_neighbor_coords_average(ss, avg, vd.index);
+ break;
+ }
+ sub_v3_v3v3(val, avg, orig_co);
+ madd_v3_v3v3fl(val, orig_co, val, fade);
+ sub_v3_v3v3(disp, val, orig_co);
+ break;
+ case MESH_FILTER_INFLATE:
+ normal_short_to_float_v3(normal, orig_data.no);
+ mul_v3_v3fl(disp, normal, fade);
+ break;
+ case MESH_FILTER_SCALE:
+ unit_m3(transform);
+ scale_m3_fl(transform, 1.0f + fade);
+ copy_v3_v3(val, orig_co);
+ mul_m3_v3(transform, val);
+ sub_v3_v3v3(disp, val, orig_co);
+ break;
+ case MESH_FILTER_SPHERE:
+ normalize_v3_v3(disp, orig_co);
+ if (fade > 0.0f) {
+ mul_v3_v3fl(disp, disp, fade);
+ }
+ else {
+ mul_v3_v3fl(disp, disp, -fade);
+ }
+
+ unit_m3(transform);
+ if (fade > 0.0f) {
+ scale_m3_fl(transform, 1.0f - fade);
+ }
+ else {
+ scale_m3_fl(transform, 1.0f + fade);
+ }
+ copy_v3_v3(val, orig_co);
+ mul_m3_v3(transform, val);
+ sub_v3_v3v3(disp2, val, orig_co);
+
+ mid_v3_v3v3(disp, disp, disp2);
+ break;
+ case MESH_FILTER_RANDOM: {
+ normal_short_to_float_v3(normal, orig_data.no);
+ /* Index is not unique for multires, so hash by vertex coordinates. */
+ const uint *hash_co = (const uint *)orig_co;
+ const uint hash = BLI_hash_int_2d(hash_co[0], hash_co[1]) ^
+ BLI_hash_int_2d(hash_co[2], ss->filter_cache->random_seed);
+ mul_v3_fl(normal, hash * (1.0f / (float)0xFFFFFFFF) - 0.5f);
+ mul_v3_v3fl(disp, normal, fade);
+ break;
+ }
+ case MESH_FILTER_RELAX: {
+ SCULPT_relax_vertex(
+ ss, &vd, clamp_f(fade * ss->filter_cache->automask[vd.index], 0.0f, 1.0f), false, val);
+ sub_v3_v3v3(disp, val, vd.co);
+ break;
+ }
+ case MESH_FILTER_RELAX_FACE_SETS: {
+ SCULPT_relax_vertex(ss, &vd, clamp_f(fade, 0.0f, 1.0f), relax_face_sets, val);
+ sub_v3_v3v3(disp, val, vd.co);
+ break;
+ }
+ case MESH_FILTER_SURFACE_SMOOTH: {
+ SCULPT_surface_smooth_laplacian_step(ss,
+ disp,
+ vd.co,
+ ss->filter_cache->surface_smooth_laplacian_disp,
+ vd.index,
+ orig_data.co,
+ ss->filter_cache->surface_smooth_shape_preservation);
+ break;
+ }
+ case MESH_FILTER_SHARPEN: {
+ const float smooth_ratio = ss->filter_cache->sharpen_smooth_ratio;
+
+ /* This filter can't work at full strength as it needs multiple iterations to reach a
+ * stable state. */
+ fade = clamp_f(fade, 0.0f, 0.5f);
+ float disp_sharpen[3] = {0.0f, 0.0f, 0.0f};
+
+ SculptVertexNeighborIter ni;
+ SCULPT_VERTEX_NEIGHBORS_ITER_BEGIN (ss, vd.index, ni) {
+ float disp_n[3];
+ sub_v3_v3v3(
+ disp_n, SCULPT_vertex_co_get(ss, ni.index), SCULPT_vertex_co_get(ss, vd.index));
+ mul_v3_fl(disp_n, ss->filter_cache->sharpen_factor[ni.index]);
+ add_v3_v3(disp_sharpen, disp_n);
+ }
+ SCULPT_VERTEX_NEIGHBORS_ITER_END(ni);
+
+ mul_v3_fl(disp_sharpen, 1.0f - ss->filter_cache->sharpen_factor[vd.index]);
+
+ float disp_avg[3];
+ float avg_co[3];
+ SCULPT_neighbor_coords_average(ss, avg_co, vd.index);
+ sub_v3_v3v3(disp_avg, avg_co, vd.co);
+ mul_v3_v3fl(
+ disp_avg, disp_avg, smooth_ratio * pow2f(ss->filter_cache->sharpen_factor[vd.index]));
+ add_v3_v3v3(disp, disp_avg, disp_sharpen);
+ break;
+ }
+ }
+
+ for (int it = 0; it < 3; it++) {
+ if (!ss->filter_cache->enabled_axis[it]) {
+ disp[it] = 0.0f;
+ }
+ }
+
+ if (ELEM(filter_type, MESH_FILTER_SURFACE_SMOOTH, MESH_FILTER_SHARPEN)) {
+ madd_v3_v3v3fl(final_pos, vd.co, disp, clamp_f(fade, 0.0f, 1.0f));
+ }
+ else {
+ add_v3_v3v3(final_pos, orig_co, disp);
+ }
+ copy_v3_v3(vd.co, final_pos);
+ if (vd.mvert) {
+ vd.mvert->flag |= ME_VERT_PBVH_UPDATE;
+ }
+ }
+ BKE_pbvh_vertex_iter_end;
+
+ BKE_pbvh_node_mark_update(node);
+}
+
+static void mesh_filter_sharpen_init_factors(SculptSession *ss)
+{
+ const int totvert = SCULPT_vertex_count_get(ss);
+ for (int i = 0; i < totvert; i++) {
+ float avg[3];
+ SCULPT_neighbor_coords_average(ss, avg, i);
+ ss->filter_cache->sharpen_factor[i] = len_v3v3(avg, SCULPT_vertex_co_get(ss, i));
+ }
+ float max_factor = 0.0f;
+ for (int i = 0; i < totvert; i++) {
+ if (ss->filter_cache->sharpen_factor[i] > max_factor) {
+ max_factor = ss->filter_cache->sharpen_factor[i];
+ }
+ }
+
+ max_factor = 1.0f / max_factor;
+ for (int i = 0; i < totvert; i++) {
+ ss->filter_cache->sharpen_factor[i] *= max_factor;
+ ss->filter_cache->sharpen_factor[i] = 1.0f - pow2f(1.0f - ss->filter_cache->sharpen_factor[i]);
+ }
+}
+
+static void mesh_filter_surface_smooth_displace_task_cb(
+ void *__restrict userdata, const int i, const TaskParallelTLS *__restrict UNUSED(tls))
+{
+ SculptThreadedTaskData *data = userdata;
+ SculptSession *ss = data->ob->sculpt;
+ PBVHNode *node = data->nodes[i];
+ PBVHVertexIter vd;
+
+ BKE_pbvh_vertex_iter_begin(ss->pbvh, node, vd, PBVH_ITER_UNIQUE)
+ {
+ float fade = vd.mask ? *vd.mask : 0.0f;
+ fade = 1.0f - fade;
+ fade *= data->filter_strength;
+ if (fade == 0.0f) {
+ continue;
+ }
+
+ if (ss->filter_cache->active_face_set != SCULPT_FACE_SET_NONE) {
+ if (!SCULPT_vertex_has_face_set(ss, vd.index, ss->filter_cache->active_face_set)) {
+ continue;
+ }
+ }
+
+ SCULPT_surface_smooth_displace_step(ss,
+ vd.co,
+ ss->filter_cache->surface_smooth_laplacian_disp,
+ vd.index,
+ ss->filter_cache->surface_smooth_current_vertex,
+ clamp_f(fade, 0.0f, 1.0f));
+ }
+ BKE_pbvh_vertex_iter_end;
+}
+
+static int sculpt_mesh_filter_modal(bContext *C, wmOperator *op, const wmEvent *event)
+{
+ Object *ob = CTX_data_active_object(C);
+ Depsgraph *depsgraph = CTX_data_depsgraph_pointer(C);
+ SculptSession *ss = ob->sculpt;
+ Sculpt *sd = CTX_data_tool_settings(C)->sculpt;
+ int filter_type = RNA_enum_get(op->ptr, "type");
+ float filter_strength = RNA_float_get(op->ptr, "strength");
+ const bool use_face_sets = RNA_boolean_get(op->ptr, "use_face_sets");
+
+ if (event->type == LEFTMOUSE && event->val == KM_RELEASE) {
+ SCULPT_filter_cache_free(ss);
+ SCULPT_undo_push_end();
+ SCULPT_flush_update_done(C, ob, SCULPT_UPDATE_COORDS);
+ return OPERATOR_FINISHED;
+ }
+
+ if (event->type != MOUSEMOVE) {
+ return OPERATOR_RUNNING_MODAL;
+ }
+
+ float len = event->prevclickx - event->mval[0];
+ filter_strength = filter_strength * -len * 0.001f * UI_DPI_FAC;
+
+ SCULPT_vertex_random_access_init(ss);
+
+ bool needs_pmap = sculpt_mesh_filter_needs_pmap(filter_type, use_face_sets);
+ BKE_sculpt_update_object_for_edit(depsgraph, ob, needs_pmap, false);
+
+ SculptThreadedTaskData data = {
+ .sd = sd,
+ .ob = ob,
+ .nodes = ss->filter_cache->nodes,
+ .filter_type = filter_type,
+ .filter_strength = filter_strength,
+ };
+
+ TaskParallelSettings settings;
+ BKE_pbvh_parallel_range_settings(
+ &settings, (sd->flags & SCULPT_USE_OPENMP), ss->filter_cache->totnode);
+ BLI_task_parallel_range(0, ss->filter_cache->totnode, &data, mesh_filter_task_cb, &settings);
+
+ if (filter_type == MESH_FILTER_SURFACE_SMOOTH) {
+ BLI_task_parallel_range(0,
+ ss->filter_cache->totnode,
+ &data,
+ mesh_filter_surface_smooth_displace_task_cb,
+ &settings);
+ }
+
+ ss->filter_cache->iteration_count++;
+
+ if (ss->deform_modifiers_active || ss->shapekey_active) {
+ SCULPT_flush_stroke_deform(sd, ob, true);
+ }
+
+ /* The relax mesh filter needs the updated normals of the modified mesh after each iteration. */
+ if (ELEM(MESH_FILTER_RELAX, MESH_FILTER_RELAX_FACE_SETS)) {
+ BKE_pbvh_update_normals(ss->pbvh, ss->subdiv_ccg);
+ }
+
+ SCULPT_flush_update_step(C, SCULPT_UPDATE_COORDS);
+
+ return OPERATOR_RUNNING_MODAL;
+}
+
+static int sculpt_mesh_filter_invoke(bContext *C, wmOperator *op, const wmEvent *event)
+{
+ Object *ob = CTX_data_active_object(C);
+ Depsgraph *depsgraph = CTX_data_depsgraph_pointer(C);
+ Sculpt *sd = CTX_data_tool_settings(C)->sculpt;
+ int filter_type = RNA_enum_get(op->ptr, "type");
+ SculptSession *ss = ob->sculpt;
+ PBVH *pbvh = ob->sculpt->pbvh;
+
+ int deform_axis = RNA_enum_get(op->ptr, "deform_axis");
+ if (deform_axis == 0) {
+ return OPERATOR_CANCELLED;
+ }
+
+ if (RNA_boolean_get(op->ptr, "use_face_sets")) {
+ /* Update the active vertex */
+ float mouse[2];
+ SculptCursorGeometryInfo sgi;
+ mouse[0] = event->mval[0];
+ mouse[1] = event->mval[1];
+ SCULPT_cursor_geometry_info_update(C, &sgi, mouse, false);
+ }
+
+ const bool use_face_sets = RNA_boolean_get(op->ptr, "use_face_sets");
+
+ SCULPT_vertex_random_access_init(ss);
+
+ bool needs_pmap = sculpt_mesh_filter_needs_pmap(filter_type, use_face_sets);
+ BKE_sculpt_update_object_for_edit(depsgraph, ob, needs_pmap, false);
+
+ const int totvert = SCULPT_vertex_count_get(ss);
+ if (BKE_pbvh_type(pbvh) == PBVH_FACES && needs_pmap && !ob->sculpt->pmap) {
+ return OPERATOR_CANCELLED;
+ }
+
+ SCULPT_undo_push_begin("Mesh filter");
+
+ SCULPT_filter_cache_init(ob, sd);
+
+ if (use_face_sets) {
+ ss->filter_cache->active_face_set = SCULPT_active_face_set_get(ss);
+ }
+ else {
+ ss->filter_cache->active_face_set = SCULPT_FACE_SET_NONE;
+ }
+
+ if (RNA_enum_get(op->ptr, "type") == MESH_FILTER_SURFACE_SMOOTH) {
+ ss->filter_cache->surface_smooth_laplacian_disp = MEM_mallocN(3 * sizeof(float) * totvert,
+ "surface smooth disp");
+ ss->filter_cache->surface_smooth_shape_preservation = RNA_float_get(
+ op->ptr, "surface_smooth_shape_preservation");
+ ss->filter_cache->surface_smooth_current_vertex = RNA_float_get(
+ op->ptr, "surface_smooth_current_vertex");
+ }
+
+ if (RNA_enum_get(op->ptr, "type") == MESH_FILTER_SHARPEN) {
+ ss->filter_cache->sharpen_smooth_ratio = RNA_float_get(op->ptr, "sharpen_smooth_ratio");
+ ss->filter_cache->sharpen_factor = MEM_mallocN(sizeof(float) * totvert, "sharpen factor");
+
+ mesh_filter_sharpen_init_factors(ss);
+ }
+
+ ss->filter_cache->enabled_axis[0] = deform_axis & MESH_FILTER_DEFORM_X;
+ ss->filter_cache->enabled_axis[1] = deform_axis & MESH_FILTER_DEFORM_Y;
+ ss->filter_cache->enabled_axis[2] = deform_axis & MESH_FILTER_DEFORM_Z;
+
+ if (RNA_enum_get(op->ptr, "type") == MESH_FILTER_RELAX) {
+ ss->filter_cache->automask = MEM_mallocN(totvert * sizeof(float),
+ "Relax filter edge automask");
+ for (int i = 0; i < totvert; i++) {
+ ss->filter_cache->automask[i] = 1.0f;
+ }
+ SCULPT_boundary_automasking_init(
+ ob, AUTOMASK_INIT_BOUNDARY_EDGES, 1, ss->filter_cache->automask);
+ }
+
+ WM_event_add_modal_handler(C, op);
+ return OPERATOR_RUNNING_MODAL;
+}
+
+void SCULPT_OT_mesh_filter(struct wmOperatorType *ot)
+{
+ /* Identifiers. */
+ ot->name = "Filter mesh";
+ ot->idname = "SCULPT_OT_mesh_filter";
+ ot->description = "Applies a filter to modify the current mesh";
+
+ /* API callbacks. */
+ ot->invoke = sculpt_mesh_filter_invoke;
+ ot->modal = sculpt_mesh_filter_modal;
+ ot->poll = SCULPT_mode_poll;
+
+ ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
+
+ /* RNA. */
+ RNA_def_enum(ot->srna,
+ "type",
+ prop_mesh_filter_types,
+ MESH_FILTER_INFLATE,
+ "Filter type",
+ "Operation that is going to be applied to the mesh");
+ RNA_def_float(
+ ot->srna, "strength", 1.0f, -10.0f, 10.0f, "Strength", "Filter Strength", -10.0f, 10.0f);
+ RNA_def_enum_flag(ot->srna,
+ "deform_axis",
+ prop_mesh_filter_deform_axis_items,
+ MESH_FILTER_DEFORM_X | MESH_FILTER_DEFORM_Y | MESH_FILTER_DEFORM_Z,
+ "Deform axis",
+ "Apply the deformation in the selected axis");
+ ot->prop = RNA_def_boolean(ot->srna,
+ "use_face_sets",
+ false,
+ "Use Face Sets",
+ "Apply the filter only to the Face Mask under the cursor");
+
+ /* Surface Smooth Mesh Filter properties. */
+ RNA_def_float(ot->srna,
+ "surface_smooth_shape_preservation",
+ 0.5f,
+ 0.0f,
+ 1.0f,
+ "Shape Preservation",
+ "How much of the original shape is preserved when smoothing",
+ 0.0f,
+ 1.0f);
+ RNA_def_float(ot->srna,
+ "surface_smooth_current_vertex",
+ 0.5f,
+ 0.0f,
+ 1.0f,
+ "Per Vertex Displacement",
+ "How much the position of each individual vertex influences the final result",
+ 0.0f,
+ 1.0f);
+ RNA_def_float(ot->srna,
+ "sharpen_smooth_ratio",
+ 0.35f,
+ 0.0f,
+ 1.0f,
+ "Smooth Ratio",
+ "How much smoothing is applied to polished surfaces",
+ 0.0f,
+ 1.0f);
+}
diff --git a/source/blender/editors/sculpt_paint/sculpt_intern.h b/source/blender/editors/sculpt_paint/sculpt_intern.h
index d8e29d0e773..50808b04276 100644
--- a/source/blender/editors/sculpt_paint/sculpt_intern.h
+++ b/source/blender/editors/sculpt_paint/sculpt_intern.h
@@ -10,7 +10,7 @@
* 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,
+ * 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) 2006 by Nicholas Bishop
@@ -24,6 +24,7 @@
#ifndef __SCULPT_INTERN_H__
#define __SCULPT_INTERN_H__
+#include "DNA_brush_types.h"
#include "DNA_key_types.h"
#include "DNA_listBase.h"
#include "DNA_vec_types.h"
@@ -57,6 +58,10 @@ typedef enum SculptUpdateType {
SCULPT_UPDATE_VISIBILITY = 1 << 2,
} SculptUpdateType;
+void SCULPT_flush_update_step(bContext *C, SculptUpdateType update_flags);
+void SCULPT_flush_update_done(const bContext *C, Object *ob, SculptUpdateType update_flags);
+void SCULPT_flush_stroke_deform(struct Sculpt *sd, Object *ob, bool is_proxy_used);
+
/* Stroke */
typedef struct SculptCursorGeometryInfo {
@@ -72,11 +77,20 @@ bool SCULPT_cursor_geometry_info_update(bContext *C,
bool use_sampled_normal);
void SCULPT_geometry_preview_lines_update(bContext *C, struct SculptSession *ss, float radius);
+void SCULPT_stroke_modifiers_check(const bContext *C, Object *ob, const Brush *brush);
+float SCULPT_raycast_init(struct ViewContext *vc,
+ const float mouse[2],
+ float ray_start[3],
+ float ray_end[3],
+ float ray_normal[3],
+ bool original);
+
/* Sculpt PBVH abstraction API */
void SCULPT_vertex_random_access_init(struct SculptSession *ss);
int SCULPT_vertex_count_get(struct SculptSession *ss);
const float *SCULPT_vertex_co_get(struct SculptSession *ss, int index);
+void SCULPT_vertex_normal_get(SculptSession *ss, int index, float no[3]);
float SCULPT_vertex_mask_get(struct SculptSession *ss, int index);
#define SCULPT_VERTEX_NEIGHBOR_FIXED_CAPACITY 256
@@ -102,29 +116,61 @@ void SCULPT_vertex_neighbors_get(struct SculptSession *ss,
SculptVertexNeighborIter *iter);
/* Iterator over neighboring vertices. */
-#define sculpt_vertex_neighbors_iter_begin(ss, v_index, neighbor_iterator) \
+#define SCULPT_VERTEX_NEIGHBORS_ITER_BEGIN(ss, v_index, neighbor_iterator) \
SCULPT_vertex_neighbors_get(ss, v_index, false, &neighbor_iterator); \
for (neighbor_iterator.i = 0; neighbor_iterator.i < neighbor_iterator.size; \
neighbor_iterator.i++) { \
- neighbor_iterator.index = ni.neighbors[ni.i];
+ neighbor_iterator.index = neighbor_iterator.neighbors[neighbor_iterator.i];
/* Iterate over neighboring and duplicate vertices (for PBVH_GRIDS). Duplicates come
* first since they are nearest for floodfill. */
-#define sculpt_vertex_duplicates_and_neighbors_iter_begin(ss, v_index, neighbor_iterator) \
+#define SCULPT_VERTEX_DUPLICATES_AND_NEIGHBORS_ITER_BEGIN(ss, v_index, neighbor_iterator) \
SCULPT_vertex_neighbors_get(ss, v_index, true, &neighbor_iterator); \
for (neighbor_iterator.i = neighbor_iterator.size - 1; neighbor_iterator.i >= 0; \
neighbor_iterator.i--) { \
- neighbor_iterator.index = ni.neighbors[ni.i]; \
- neighbor_iterator.is_duplicate = (ni.i >= \
+ neighbor_iterator.index = neighbor_iterator.neighbors[neighbor_iterator.i]; \
+ neighbor_iterator.is_duplicate = (neighbor_iterator.i >= \
neighbor_iterator.size - neighbor_iterator.num_duplicates);
-#define sculpt_vertex_neighbors_iter_end(neighbor_iterator) \
+#define SCULPT_VERTEX_NEIGHBORS_ITER_END(neighbor_iterator) \
} \
if (neighbor_iterator.neighbors != neighbor_iterator.neighbors_fixed) { \
MEM_freeN(neighbor_iterator.neighbors); \
} \
((void)0)
+int SCULPT_active_vertex_get(SculptSession *ss);
+const float *SCULPT_active_vertex_co_get(SculptSession *ss);
+void SCULPT_active_vertex_normal_get(SculptSession *ss, float normal[3]);
+
+bool SCULPT_vertex_is_boundary(SculptSession *ss, const int index);
+
+/* Sculpt Visibility API */
+
+void SCULPT_vertex_visible_set(SculptSession *ss, int index, bool visible);
+bool SCULPT_vertex_visible_get(SculptSession *ss, int index);
+
+void SCULPT_visibility_sync_all_face_sets_to_vertices(struct SculptSession *ss);
+void SCULPT_visibility_sync_all_vertex_to_face_sets(struct SculptSession *ss);
+
+/* Face Sets API */
+
+int SCULPT_active_face_set_get(SculptSession *ss);
+int SCULPT_vertex_face_set_get(SculptSession *ss, int index);
+void SCULPT_vertex_face_set_set(SculptSession *ss, int index, int face_set);
+
+bool SCULPT_vertex_has_face_set(SculptSession *ss, int index, int face_set);
+bool SCULPT_vertex_has_unique_face_set(SculptSession *ss, int index);
+
+int SCULPT_face_set_next_available_get(SculptSession *ss);
+
+void SCULPT_face_set_visibility_set(SculptSession *ss, int face_set, bool visible);
+bool SCULPT_vertex_all_face_sets_visible_get(SculptSession *ss, int index);
+bool SCULPT_vertex_any_face_set_visible_get(SculptSession *ss, int index);
+
+void SCULPT_face_sets_visibility_invert(SculptSession *ss);
+void SCULPT_face_sets_visibility_all_set(SculptSession *ss, bool visible);
+
/* Sculpt Original Data */
typedef struct {
struct BMLog *bm_log;
@@ -143,11 +189,6 @@ typedef struct {
void SCULPT_orig_vert_data_init(SculptOrigVertData *data, Object *ob, PBVHNode *node);
void SCULPT_orig_vert_data_update(SculptOrigVertData *orig_data, PBVHVertexIter *iter);
-/* Dynamic topology */
-void sculpt_pbvh_clear(Object *ob);
-void sculpt_dyntopo_node_layers_add(struct SculptSession *ss);
-void sculpt_dynamic_topology_disable(bContext *C, struct SculptUndoNode *unode);
-
/* Utils. */
void SCULPT_calc_brush_plane(struct Sculpt *sd,
struct Object *ob,
@@ -169,11 +210,16 @@ int SCULPT_plane_point_side(const float co[3], const float plane[4]);
int SCULPT_plane_trim(const struct StrokeCache *cache,
const struct Brush *brush,
const float val[3]);
+void SCULPT_clip(Sculpt *sd, SculptSession *ss, float co[3], const float val[3]);
float SCULPT_brush_plane_offset_get(Sculpt *sd, SculptSession *ss);
ePaintSymmetryAreas SCULPT_get_vertex_symm_area(const float co[3]);
bool SCULPT_check_vertex_pivot_symmetry(const float vco[3], const float pco[3], const char symm);
+bool SCULPT_is_vertex_inside_brush_radius_symm(const float vertex[3],
+ const float br_co[3],
+ float radius,
+ char symm);
bool SCULPT_is_symmetry_iteration_valid(char i, char symm);
void SCULPT_flip_v3_by_symm_area(float v[3],
const ePaintSymmetryFlags symm,
@@ -187,7 +233,7 @@ void SCULPT_flip_quat_by_symm_area(float quat[3],
/* Flood Fill. */
typedef struct {
GSQueue *queue;
- char *visited_vertices;
+ BLI_bitmap *visited_vertices;
} SculptFloodFill;
void SCULPT_floodfill_init(struct SculptSession *ss, SculptFloodFill *flood);
@@ -196,6 +242,13 @@ void SCULPT_floodfill_add_active(struct Sculpt *sd,
struct SculptSession *ss,
SculptFloodFill *flood,
float radius);
+void SCULPT_floodfill_add_initial_with_symmetry(struct Sculpt *sd,
+ struct Object *ob,
+ struct SculptSession *ss,
+ SculptFloodFill *flood,
+ int index,
+ float radius);
+void SCULPT_floodfill_add_initial(SculptFloodFill *flood, int index);
void SCULPT_floodfill_execute(
struct SculptSession *ss,
SculptFloodFill *flood,
@@ -203,9 +256,61 @@ void SCULPT_floodfill_execute(
void *userdata);
void SCULPT_floodfill_free(SculptFloodFill *flood);
+/* Dynamic topology */
+
+enum eDynTopoWarnFlag {
+ DYNTOPO_WARN_VDATA = (1 << 0),
+ DYNTOPO_WARN_EDATA = (1 << 1),
+ DYNTOPO_WARN_LDATA = (1 << 2),
+ DYNTOPO_WARN_MODIFIER = (1 << 3),
+};
+
+void SCULPT_dynamic_topology_enable_ex(struct Main *bmain,
+ struct Depsgraph *depsgraph,
+ Scene *scene,
+ Object *ob);
+void SCULPT_dynamic_topology_disable(bContext *C, struct SculptUndoNode *unode);
+void sculpt_dynamic_topology_disable_with_undo(struct Main *bmain,
+ struct Depsgraph *depsgraph,
+ Scene *scene,
+ Object *ob);
+
+bool SCULPT_stroke_is_dynamic_topology(const SculptSession *ss, const Brush *brush);
+
+void SCULPT_dynamic_topology_triangulate(struct BMesh *bm);
+void SCULPT_dyntopo_node_layers_add(struct SculptSession *ss);
+
+enum eDynTopoWarnFlag SCULPT_dynamic_topology_check(Scene *scene, Object *ob);
+
+void SCULPT_pbvh_clear(Object *ob);
+
/* Automasking. */
float SCULPT_automasking_factor_get(SculptSession *ss, int vert);
+void SCULPT_automasking_init(Sculpt *sd, Object *ob);
+void SCULPT_automasking_end(Object *ob);
+
+bool SCULPT_is_automasking_mode_enabled(const Sculpt *sd,
+ const Brush *br,
+ const eAutomasking_flag mode);
+bool SCULPT_is_automasking_enabled(const Sculpt *sd, const SculptSession *ss, const Brush *br);
+
+typedef enum eBoundaryAutomaskMode {
+ AUTOMASK_INIT_BOUNDARY_EDGES = 1,
+ AUTOMASK_INIT_BOUNDARY_FACE_SETS = 2,
+} eBoundaryAutomaskMode;
+float *SCULPT_boundary_automasking_init(Object *ob,
+ eBoundaryAutomaskMode mode,
+ int propagation_steps,
+ float *automask_factor);
+
+/* Filters. */
+void SCULPT_filter_cache_init(Object *ob, Sculpt *sd);
+void SCULPT_filter_cache_free(SculptSession *ss);
+
+void SCULPT_mask_filter_smooth_apply(
+ Sculpt *sd, Object *ob, PBVHNode **nodes, const int totnode, const int smooth_iterations);
+
/* Brushes. */
/* Cloth Brush. */
@@ -228,6 +333,13 @@ void SCULPT_cloth_plane_falloff_preview_draw(const uint gpuattr,
struct SculptSession *ss,
const float outline_col[3],
float outline_alpha);
+
+BLI_INLINE bool SCULPT_is_cloth_deform_brush(const Brush *brush)
+{
+ return brush->sculpt_tool == SCULPT_TOOL_CLOTH &&
+ brush->cloth_deform_type == BRUSH_CLOTH_DEFORM_GRAB;
+}
+
/* Pose Brush. */
void SCULPT_do_pose_brush(struct Sculpt *sd,
struct Object *ob,
@@ -259,6 +371,43 @@ void SCULPT_multiplane_scrape_preview_draw(const uint gpuattr,
SculptSession *ss,
const float outline_col[3],
const float outline_alpha);
+/* Draw Face Sets Brush. */
+void SCULPT_do_draw_face_sets_brush(Sculpt *sd, Object *ob, PBVHNode **nodes, int totnode);
+
+/* Smooth Brush. */
+
+void SCULPT_neighbor_average(SculptSession *ss, float avg[3], uint vert);
+void SCULPT_bmesh_neighbor_average(float avg[3], struct BMVert *v);
+
+void SCULPT_bmesh_four_neighbor_average(float avg[3], float direction[3], struct BMVert *v);
+
+void SCULPT_neighbor_coords_average(SculptSession *ss, float result[3], int index);
+float SCULPT_neighbor_mask_average(SculptSession *ss, int index);
+
+void SCULPT_smooth(Sculpt *sd,
+ Object *ob,
+ PBVHNode **nodes,
+ const int totnode,
+ float bstrength,
+ const bool smooth_mask);
+void SCULPT_do_smooth_brush(Sculpt *sd, Object *ob, PBVHNode **nodes, int totnode);
+
+/* Surface Smooth Brush. */
+
+void SCULPT_surface_smooth_laplacian_step(SculptSession *ss,
+ float *disp,
+ const float co[3],
+ float (*laplacian_disp)[3],
+ const int v_index,
+ const float origco[3],
+ const float alpha);
+void SCULPT_surface_smooth_displace_step(SculptSession *ss,
+ float *co,
+ float (*laplacian_disp)[3],
+ const int v_index,
+ const float beta,
+ const float fade);
+void SCULPT_do_surface_smooth_brush(Sculpt *sd, Object *ob, PBVHNode **nodes, int totnode);
/* Slide/Relax */
void SCULPT_relax_vertex(struct SculptSession *ss,
@@ -267,10 +416,6 @@ void SCULPT_relax_vertex(struct SculptSession *ss,
bool filter_boundary_face_sets,
float *r_final_pos);
-/* Sculpt Visibility API */
-void SCULPT_visibility_sync_all_face_sets_to_vertices(struct SculptSession *ss);
-void SCULPT_visibility_sync_all_vertex_to_face_sets(struct SculptSession *ss);
-
/* Undo */
typedef enum {
@@ -284,6 +429,23 @@ typedef enum {
SCULPT_UNDO_FACE_SETS,
} SculptUndoType;
+/* Storage of geometry for the undo node.
+ * Is used as a storage for either original or modified geometry. */
+typedef struct SculptUndoNodeGeometry {
+ /* Is used for sanity check, helping with ensuring that two and only two
+ * geometry pushes happened in the undo stack. */
+ bool is_initialized;
+
+ CustomData vdata;
+ CustomData edata;
+ CustomData ldata;
+ CustomData pdata;
+ int totvert;
+ int totedge;
+ int totloop;
+ int totpoly;
+} SculptUndoNodeGeometry;
+
typedef struct SculptUndoNode {
struct SculptUndoNode *next, *prev;
@@ -317,15 +479,18 @@ typedef struct SculptUndoNode {
/* shape keys */
char shapeName[sizeof(((KeyBlock *)0))->name];
- /* geometry modification operations and bmesh enter data */
- CustomData geom_vdata;
- CustomData geom_edata;
- CustomData geom_ldata;
- CustomData geom_pdata;
- int geom_totvert;
- int geom_totedge;
- int geom_totloop;
- int geom_totpoly;
+ /* Geometry modification operations.
+ *
+ * Original geometry is stored before some modification is run and is used to restore state of
+ * the object when undoing the operation
+ *
+ * Modified geometry is stored after the modification and is used to redo the modification. */
+ bool geometry_clear_pbvh;
+ SculptUndoNodeGeometry geometry_original;
+ SculptUndoNodeGeometry geometry_modified;
+
+ /* Geometry at the bmesh enter moment. */
+ SculptUndoNodeGeometry geometry_bmesh_enter;
/* pivot */
float pivot_pos[3];
@@ -427,6 +592,9 @@ typedef struct SculptThreadedTaskData {
float transform_mats[8][4][4];
float cloth_time_step;
+ SculptClothSimulation *cloth_sim;
+ float *cloth_sim_initial_location;
+ float cloth_sim_radius;
float dirty_mask_min;
float dirty_mask_max;
@@ -441,6 +609,7 @@ typedef struct SculptThreadedTaskData {
/*************** Brush testing declarations ****************/
typedef struct SculptBrushTest {
float radius_squared;
+ float radius;
float location[3];
float dist;
int mirror_symmetry_pass;
@@ -517,7 +686,7 @@ bool SCULPT_pbvh_calc_area_normal(const struct Brush *brush,
* For descriptions of these settings, check the operator properties.
*/
-#define CLAY_STABILIZER_LEN 10
+#define SCULPT_CLAY_STABILIZER_LEN 10
typedef struct StrokeCache {
/* Invariants */
@@ -608,7 +777,7 @@ typedef struct StrokeCache {
/* Angle of the front tilting plane of the brush to simulate clay accumulation. */
float clay_thumb_front_angle;
/* Stores pressure samples to get an stabilized strength and radius variation. */
- float clay_pressure_stabilizer[CLAY_STABILIZER_LEN];
+ float clay_pressure_stabilizer[SCULPT_CLAY_STABILIZER_LEN];
int clay_pressure_stabilizer_index;
/* Cloth brush */
@@ -622,6 +791,9 @@ typedef struct StrokeCache {
/* Stores the displacement produced by the laplacian step of HC smooth. */
float (*surface_smooth_laplacian_disp)[3];
+ /* Layer brush */
+ float *layer_displacement_factor;
+
float vertex_rotation; /* amount to rotate the vertices when using rotate brush */
struct Dial *dial;
@@ -659,10 +831,18 @@ typedef struct FilterCache {
float surface_smooth_shape_preservation;
float surface_smooth_current_vertex;
+ /* Sharpen mesh filter. */
+ float sharpen_smooth_ratio;
+ float *sharpen_factor;
+
/* unmasked nodes */
PBVHNode **nodes;
int totnode;
+ /* Cloth filter. */
+ SculptClothSimulation *cloth_sim;
+ float cloth_sim_pinch_point[3];
+
/* mask expand iteration caches */
int mask_update_current_it;
int mask_update_last_it;
@@ -689,8 +869,10 @@ void SCULPT_cache_free(StrokeCache *cache);
SculptUndoNode *SCULPT_undo_push_node(Object *ob, PBVHNode *node, SculptUndoType type);
SculptUndoNode *SCULPT_undo_get_node(PBVHNode *node);
+SculptUndoNode *SCULPT_undo_get_first_node(void);
void SCULPT_undo_push_begin(const char *name);
void SCULPT_undo_push_end(void);
+void SCULPT_undo_push_end_ex(const bool use_nested_undo);
void SCULPT_vertcos_to_key(Object *ob, KeyBlock *kb, const float (*vertCos)[3]);
@@ -701,4 +883,36 @@ bool SCULPT_get_redraw_rect(struct ARegion *region,
Object *ob,
rcti *rect);
+/* Operators. */
+
+/* Face Sets. */
+void SCULPT_OT_face_sets_randomize_colors(struct wmOperatorType *ot);
+void SCULPT_OT_face_sets_change_visibility(struct wmOperatorType *ot);
+void SCULPT_OT_face_sets_init(struct wmOperatorType *ot);
+void SCULPT_OT_face_sets_create(struct wmOperatorType *ot);
+
+/* Transform. */
+void SCULPT_OT_set_pivot_position(struct wmOperatorType *ot);
+
+/* Mesh Filter. */
+void SCULPT_OT_mesh_filter(struct wmOperatorType *ot);
+
+/* Cloth Filter. */
+void SCULPT_OT_cloth_filter(struct wmOperatorType *ot);
+
+/* Mask filter and Dirty Mask. */
+void SCULPT_OT_mask_filter(struct wmOperatorType *ot);
+void SCULPT_OT_dirty_mask(struct wmOperatorType *ot);
+
+/* Mask and Face Sets Expand. */
+void SCULPT_OT_mask_expand(struct wmOperatorType *ot);
+
+/* Detail size. */
+void SCULPT_OT_detail_flood_fill(struct wmOperatorType *ot);
+void SCULPT_OT_sample_detail_size(struct wmOperatorType *ot);
+void SCULPT_OT_set_detail_size(struct wmOperatorType *ot);
+
+/* Dyntopo. */
+void SCULPT_OT_dynamic_topology_toggle(struct wmOperatorType *ot);
+
#endif
diff --git a/source/blender/editors/sculpt_paint/sculpt_mask_expand.c b/source/blender/editors/sculpt_paint/sculpt_mask_expand.c
new file mode 100644
index 00000000000..cbb198e14a3
--- /dev/null
+++ b/source/blender/editors/sculpt_paint/sculpt_mask_expand.c
@@ -0,0 +1,526 @@
+/*
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * The Original Code is Copyright (C) 2020 Blender Foundation.
+ * All rights reserved.
+ */
+
+/** \file
+ * \ingroup edsculpt
+ */
+
+#include "MEM_guardedalloc.h"
+
+#include "BLI_blenlib.h"
+#include "BLI_math.h"
+#include "BLI_task.h"
+
+#include "BLT_translation.h"
+
+#include "DNA_brush_types.h"
+#include "DNA_mesh_types.h"
+#include "DNA_meshdata_types.h"
+#include "DNA_object_types.h"
+
+#include "BKE_brush.h"
+#include "BKE_ccg.h"
+#include "BKE_colortools.h"
+#include "BKE_context.h"
+#include "BKE_mesh.h"
+#include "BKE_multires.h"
+#include "BKE_node.h"
+#include "BKE_object.h"
+#include "BKE_paint.h"
+#include "BKE_pbvh.h"
+#include "BKE_scene.h"
+
+#include "DEG_depsgraph.h"
+
+#include "WM_api.h"
+#include "WM_message.h"
+#include "WM_toolsystem.h"
+#include "WM_types.h"
+
+#include "RNA_access.h"
+#include "RNA_define.h"
+
+#include "ED_object.h"
+#include "ED_screen.h"
+#include "ED_sculpt.h"
+#include "ED_view3d.h"
+#include "paint_intern.h"
+#include "sculpt_intern.h"
+
+#include "bmesh.h"
+
+#include <math.h>
+#include <stdlib.h>
+
+static void sculpt_mask_expand_cancel(bContext *C, wmOperator *op)
+{
+ Object *ob = CTX_data_active_object(C);
+ SculptSession *ss = ob->sculpt;
+ const bool create_face_set = RNA_boolean_get(op->ptr, "create_face_set");
+
+ MEM_freeN(op->customdata);
+
+ for (int n = 0; n < ss->filter_cache->totnode; n++) {
+ PBVHNode *node = ss->filter_cache->nodes[n];
+ if (create_face_set) {
+ for (int i = 0; i < ss->totfaces; i++) {
+ ss->face_sets[i] = ss->filter_cache->prev_face_set[i];
+ }
+ }
+ else {
+ PBVHVertexIter vd;
+ BKE_pbvh_vertex_iter_begin(ss->pbvh, node, vd, PBVH_ITER_UNIQUE)
+ {
+ *vd.mask = ss->filter_cache->prev_mask[vd.index];
+ }
+ BKE_pbvh_vertex_iter_end;
+ }
+
+ BKE_pbvh_node_mark_redraw(node);
+ }
+
+ if (!create_face_set) {
+ SCULPT_flush_update_step(C, SCULPT_UPDATE_MASK);
+ }
+ SCULPT_filter_cache_free(ss);
+ SCULPT_undo_push_end();
+ SCULPT_flush_update_done(C, ob, SCULPT_UPDATE_MASK);
+ ED_workspace_status_text(C, NULL);
+}
+
+static void sculpt_expand_task_cb(void *__restrict userdata,
+ const int i,
+ const TaskParallelTLS *__restrict UNUSED(tls))
+{
+ SculptThreadedTaskData *data = userdata;
+ SculptSession *ss = data->ob->sculpt;
+ PBVHNode *node = data->nodes[i];
+ PBVHVertexIter vd;
+ int update_it = data->mask_expand_update_it;
+
+ BKE_pbvh_vertex_iter_begin(ss->pbvh, node, vd, PBVH_ITER_ALL)
+ {
+ int vi = vd.index;
+ float final_mask = *vd.mask;
+ if (data->mask_expand_use_normals) {
+ if (ss->filter_cache->normal_factor[SCULPT_active_vertex_get(ss)] <
+ ss->filter_cache->normal_factor[vd.index]) {
+ final_mask = 1.0f;
+ }
+ else {
+ final_mask = 0.0f;
+ }
+ }
+ else {
+ if (ss->filter_cache->mask_update_it[vi] <= update_it &&
+ ss->filter_cache->mask_update_it[vi] != 0) {
+ final_mask = 1.0f;
+ }
+ else {
+ final_mask = 0.0f;
+ }
+ }
+
+ if (data->mask_expand_create_face_set) {
+ if (final_mask == 1.0f) {
+ SCULPT_vertex_face_set_set(ss, vd.index, ss->filter_cache->new_face_set);
+ }
+ BKE_pbvh_node_mark_redraw(node);
+ }
+ else {
+
+ if (data->mask_expand_keep_prev_mask) {
+ final_mask = MAX2(ss->filter_cache->prev_mask[vd.index], final_mask);
+ }
+
+ if (data->mask_expand_invert_mask) {
+ final_mask = 1.0f - final_mask;
+ }
+
+ if (*vd.mask != final_mask) {
+ if (vd.mvert) {
+ vd.mvert->flag |= ME_VERT_PBVH_UPDATE;
+ }
+ *vd.mask = final_mask;
+ BKE_pbvh_node_mark_update_mask(node);
+ }
+ }
+ }
+ BKE_pbvh_vertex_iter_end;
+}
+
+static int sculpt_mask_expand_modal(bContext *C, wmOperator *op, const wmEvent *event)
+{
+ Depsgraph *depsgraph = CTX_data_depsgraph_pointer(C);
+ Object *ob = CTX_data_active_object(C);
+ SculptSession *ss = ob->sculpt;
+ Sculpt *sd = CTX_data_tool_settings(C)->sculpt;
+ ARegion *region = CTX_wm_region(C);
+ float prevclick_f[2];
+ copy_v2_v2(prevclick_f, op->customdata);
+ int prevclick[2] = {(int)prevclick_f[0], (int)prevclick_f[1]};
+ int len = (int)len_v2v2_int(prevclick, event->mval);
+ len = abs(len);
+ int mask_speed = RNA_int_get(op->ptr, "mask_speed");
+ int mask_expand_update_it = len / mask_speed;
+ mask_expand_update_it = mask_expand_update_it + 1;
+
+ const bool create_face_set = RNA_boolean_get(op->ptr, "create_face_set");
+
+ if (RNA_boolean_get(op->ptr, "use_cursor")) {
+ SculptCursorGeometryInfo sgi;
+ float mouse[2];
+ mouse[0] = event->mval[0];
+ mouse[1] = event->mval[1];
+ SCULPT_cursor_geometry_info_update(C, &sgi, mouse, false);
+ mask_expand_update_it = ss->filter_cache->mask_update_it[(int)SCULPT_active_vertex_get(ss)];
+ }
+
+ if ((event->type == EVT_ESCKEY && event->val == KM_PRESS) ||
+ (event->type == RIGHTMOUSE && event->val == KM_PRESS)) {
+ /* Returning OPERATOR_CANCELLED will leak memory due to not finishing
+ * undo. Better solution could be to make paint_mesh_restore_co work
+ * for this case. */
+ sculpt_mask_expand_cancel(C, op);
+ return OPERATOR_FINISHED;
+ }
+
+ if ((event->type == LEFTMOUSE && event->val == KM_RELEASE) ||
+ (event->type == EVT_RETKEY && event->val == KM_PRESS) ||
+ (event->type == EVT_PADENTER && event->val == KM_PRESS)) {
+
+ /* Smooth iterations. */
+ BKE_sculpt_update_object_for_edit(depsgraph, ob, true, false);
+ const int smooth_iterations = RNA_int_get(op->ptr, "smooth_iterations");
+ SCULPT_mask_filter_smooth_apply(
+ sd, ob, ss->filter_cache->nodes, ss->filter_cache->totnode, smooth_iterations);
+
+ /* Pivot position. */
+ if (RNA_boolean_get(op->ptr, "update_pivot")) {
+ const char symm = sd->paint.symmetry_flags & PAINT_SYMM_AXIS_ALL;
+ const float threshold = 0.2f;
+ float avg[3];
+ int total = 0;
+ zero_v3(avg);
+
+ for (int n = 0; n < ss->filter_cache->totnode; n++) {
+ PBVHVertexIter vd;
+ BKE_pbvh_vertex_iter_begin(ss->pbvh, ss->filter_cache->nodes[n], vd, PBVH_ITER_UNIQUE)
+ {
+ const float mask = (vd.mask) ? *vd.mask : 0.0f;
+ if (mask < (0.5f + threshold) && mask > (0.5f - threshold)) {
+ if (SCULPT_check_vertex_pivot_symmetry(
+ vd.co, ss->filter_cache->mask_expand_initial_co, symm)) {
+ add_v3_v3(avg, vd.co);
+ total++;
+ }
+ }
+ }
+ BKE_pbvh_vertex_iter_end;
+ }
+
+ if (total > 0) {
+ mul_v3_fl(avg, 1.0f / total);
+ copy_v3_v3(ss->pivot_pos, avg);
+ }
+ WM_event_add_notifier(C, NC_GEOM | ND_SELECT, ob->data);
+ }
+
+ MEM_freeN(op->customdata);
+
+ for (int i = 0; i < ss->filter_cache->totnode; i++) {
+ BKE_pbvh_node_mark_redraw(ss->filter_cache->nodes[i]);
+ }
+
+ SCULPT_filter_cache_free(ss);
+
+ SCULPT_undo_push_end();
+ SCULPT_flush_update_done(C, ob, SCULPT_UPDATE_MASK);
+ ED_workspace_status_text(C, NULL);
+ return OPERATOR_FINISHED;
+ }
+
+ /* When pressing Ctrl, expand directly to the max number of iterations. This allows to flood fill
+ * mask and face sets by connectivity directly. */
+ if (event->ctrl) {
+ mask_expand_update_it = ss->filter_cache->mask_update_last_it - 1;
+ }
+
+ if (!ELEM(event->type, MOUSEMOVE, EVT_LEFTCTRLKEY, EVT_RIGHTCTRLKEY)) {
+ return OPERATOR_RUNNING_MODAL;
+ }
+
+ if (mask_expand_update_it == ss->filter_cache->mask_update_current_it) {
+ ED_region_tag_redraw(region);
+ return OPERATOR_RUNNING_MODAL;
+ }
+
+ if (mask_expand_update_it < ss->filter_cache->mask_update_last_it) {
+
+ if (create_face_set) {
+ for (int i = 0; i < ss->totfaces; i++) {
+ ss->face_sets[i] = ss->filter_cache->prev_face_set[i];
+ }
+ }
+ SculptThreadedTaskData data = {
+ .sd = sd,
+ .ob = ob,
+ .nodes = ss->filter_cache->nodes,
+ .mask_expand_update_it = mask_expand_update_it,
+ .mask_expand_use_normals = RNA_boolean_get(op->ptr, "use_normals"),
+ .mask_expand_invert_mask = RNA_boolean_get(op->ptr, "invert"),
+ .mask_expand_keep_prev_mask = RNA_boolean_get(op->ptr, "keep_previous_mask"),
+ .mask_expand_create_face_set = RNA_boolean_get(op->ptr, "create_face_set"),
+ };
+ TaskParallelSettings settings;
+ BKE_pbvh_parallel_range_settings(
+ &settings, (sd->flags & SCULPT_USE_OPENMP), ss->filter_cache->totnode);
+ BLI_task_parallel_range(0, ss->filter_cache->totnode, &data, sculpt_expand_task_cb, &settings);
+ ss->filter_cache->mask_update_current_it = mask_expand_update_it;
+ }
+
+ SCULPT_flush_update_step(C, SCULPT_UPDATE_MASK);
+
+ return OPERATOR_RUNNING_MODAL;
+}
+
+typedef struct MaskExpandFloodFillData {
+ float original_normal[3];
+ float edge_sensitivity;
+ bool use_normals;
+} MaskExpandFloodFillData;
+
+static bool mask_expand_floodfill_cb(
+ SculptSession *ss, int from_v, int to_v, bool is_duplicate, void *userdata)
+{
+ MaskExpandFloodFillData *data = userdata;
+
+ if (!is_duplicate) {
+ int to_it = ss->filter_cache->mask_update_it[from_v] + 1;
+ ss->filter_cache->mask_update_it[to_v] = to_it;
+ if (to_it > ss->filter_cache->mask_update_last_it) {
+ ss->filter_cache->mask_update_last_it = to_it;
+ }
+
+ if (data->use_normals) {
+ float current_normal[3], prev_normal[3];
+ SCULPT_vertex_normal_get(ss, to_v, current_normal);
+ SCULPT_vertex_normal_get(ss, from_v, prev_normal);
+ const float from_edge_factor = ss->filter_cache->edge_factor[from_v];
+ ss->filter_cache->edge_factor[to_v] = dot_v3v3(current_normal, prev_normal) *
+ from_edge_factor;
+ ss->filter_cache->normal_factor[to_v] = dot_v3v3(data->original_normal, current_normal) *
+ powf(from_edge_factor, data->edge_sensitivity);
+ CLAMP(ss->filter_cache->normal_factor[to_v], 0.0f, 1.0f);
+ }
+ }
+ else {
+ /* PBVH_GRIDS duplicate handling. */
+ ss->filter_cache->mask_update_it[to_v] = ss->filter_cache->mask_update_it[from_v];
+ if (data->use_normals) {
+ ss->filter_cache->edge_factor[to_v] = ss->filter_cache->edge_factor[from_v];
+ ss->filter_cache->normal_factor[to_v] = ss->filter_cache->normal_factor[from_v];
+ }
+ }
+
+ return true;
+}
+
+static int sculpt_mask_expand_invoke(bContext *C, wmOperator *op, const wmEvent *event)
+{
+ Depsgraph *depsgraph = CTX_data_depsgraph_pointer(C);
+ Object *ob = CTX_data_active_object(C);
+ SculptSession *ss = ob->sculpt;
+ Sculpt *sd = CTX_data_tool_settings(C)->sculpt;
+ PBVH *pbvh = ob->sculpt->pbvh;
+
+ const bool use_normals = RNA_boolean_get(op->ptr, "use_normals");
+ const bool create_face_set = RNA_boolean_get(op->ptr, "create_face_set");
+
+ SculptCursorGeometryInfo sgi;
+ float mouse[2];
+ mouse[0] = event->mval[0];
+ mouse[1] = event->mval[1];
+
+ SCULPT_vertex_random_access_init(ss);
+
+ op->customdata = MEM_mallocN(2 * sizeof(float), "initial mouse position");
+ copy_v2_v2(op->customdata, mouse);
+
+ SCULPT_cursor_geometry_info_update(C, &sgi, mouse, false);
+
+ BKE_sculpt_update_object_for_edit(depsgraph, ob, true, true);
+
+ int vertex_count = SCULPT_vertex_count_get(ss);
+
+ ss->filter_cache = MEM_callocN(sizeof(FilterCache), "filter cache");
+
+ BKE_pbvh_search_gather(pbvh, NULL, NULL, &ss->filter_cache->nodes, &ss->filter_cache->totnode);
+
+ SCULPT_undo_push_begin("Mask Expand");
+
+ if (create_face_set) {
+ SCULPT_undo_push_node(ob, ss->filter_cache->nodes[0], SCULPT_UNDO_FACE_SETS);
+ for (int i = 0; i < ss->filter_cache->totnode; i++) {
+ BKE_pbvh_node_mark_redraw(ss->filter_cache->nodes[i]);
+ }
+ }
+ else {
+ for (int i = 0; i < ss->filter_cache->totnode; i++) {
+ SCULPT_undo_push_node(ob, ss->filter_cache->nodes[i], SCULPT_UNDO_MASK);
+ BKE_pbvh_node_mark_redraw(ss->filter_cache->nodes[i]);
+ }
+ }
+
+ ss->filter_cache->mask_update_it = MEM_callocN(sizeof(int) * vertex_count,
+ "mask update iteration");
+ if (use_normals) {
+ ss->filter_cache->normal_factor = MEM_callocN(sizeof(float) * vertex_count,
+ "mask update normal factor");
+ ss->filter_cache->edge_factor = MEM_callocN(sizeof(float) * vertex_count,
+ "mask update normal factor");
+ for (int i = 0; i < vertex_count; i++) {
+ ss->filter_cache->edge_factor[i] = 1.0f;
+ }
+ }
+
+ if (create_face_set) {
+ ss->filter_cache->prev_face_set = MEM_callocN(sizeof(float) * ss->totfaces, "prev face mask");
+ for (int i = 0; i < ss->totfaces; i++) {
+ ss->filter_cache->prev_face_set[i] = ss->face_sets[i];
+ }
+ ss->filter_cache->new_face_set = SCULPT_face_set_next_available_get(ss);
+ }
+ else {
+ ss->filter_cache->prev_mask = MEM_callocN(sizeof(float) * vertex_count, "prev mask");
+ for (int i = 0; i < vertex_count; i++) {
+ ss->filter_cache->prev_mask[i] = SCULPT_vertex_mask_get(ss, i);
+ }
+ }
+
+ ss->filter_cache->mask_update_last_it = 1;
+ ss->filter_cache->mask_update_current_it = 1;
+ ss->filter_cache->mask_update_it[SCULPT_active_vertex_get(ss)] = 0;
+
+ copy_v3_v3(ss->filter_cache->mask_expand_initial_co, SCULPT_active_vertex_co_get(ss));
+
+ SculptFloodFill flood;
+ SCULPT_floodfill_init(ss, &flood);
+ SCULPT_floodfill_add_active(sd, ob, ss, &flood, FLT_MAX);
+
+ MaskExpandFloodFillData fdata = {
+ .use_normals = use_normals,
+ .edge_sensitivity = RNA_int_get(op->ptr, "edge_sensitivity"),
+ };
+ SCULPT_active_vertex_normal_get(ss, fdata.original_normal);
+ SCULPT_floodfill_execute(ss, &flood, mask_expand_floodfill_cb, &fdata);
+ SCULPT_floodfill_free(&flood);
+
+ if (use_normals) {
+ for (int repeat = 0; repeat < 2; repeat++) {
+ for (int i = 0; i < vertex_count; i++) {
+ float avg = 0.0f;
+ SculptVertexNeighborIter ni;
+ SCULPT_VERTEX_NEIGHBORS_ITER_BEGIN (ss, i, ni) {
+ avg += ss->filter_cache->normal_factor[ni.index];
+ }
+ SCULPT_VERTEX_NEIGHBORS_ITER_END(ni);
+ ss->filter_cache->normal_factor[i] = avg / ni.size;
+ }
+ }
+
+ MEM_SAFE_FREE(ss->filter_cache->edge_factor);
+ }
+
+ SculptThreadedTaskData data = {
+ .sd = sd,
+ .ob = ob,
+ .nodes = ss->filter_cache->nodes,
+ .mask_expand_update_it = 0,
+ .mask_expand_use_normals = RNA_boolean_get(op->ptr, "use_normals"),
+ .mask_expand_invert_mask = RNA_boolean_get(op->ptr, "invert"),
+ .mask_expand_keep_prev_mask = RNA_boolean_get(op->ptr, "keep_previous_mask"),
+ .mask_expand_create_face_set = RNA_boolean_get(op->ptr, "create_face_set"),
+ };
+ TaskParallelSettings settings;
+ BKE_pbvh_parallel_range_settings(
+ &settings, (sd->flags & SCULPT_USE_OPENMP), ss->filter_cache->totnode);
+ BLI_task_parallel_range(0, ss->filter_cache->totnode, &data, sculpt_expand_task_cb, &settings);
+
+ const char *status_str = TIP_(
+ "Move the mouse to expand the mask from the active vertex. LMB: confirm mask, ESC/RMB: "
+ "cancel");
+ ED_workspace_status_text(C, status_str);
+
+ SCULPT_flush_update_step(C, SCULPT_UPDATE_MASK);
+ WM_event_add_modal_handler(C, op);
+ return OPERATOR_RUNNING_MODAL;
+}
+
+void SCULPT_OT_mask_expand(wmOperatorType *ot)
+{
+ /* Identifiers. */
+ ot->name = "Mask Expand";
+ ot->idname = "SCULPT_OT_mask_expand";
+ ot->description = "Expands a mask from the initial active vertex under the cursor";
+
+ /* API callbacks. */
+ ot->invoke = sculpt_mask_expand_invoke;
+ ot->modal = sculpt_mask_expand_modal;
+ ot->cancel = sculpt_mask_expand_cancel;
+ ot->poll = SCULPT_mode_poll;
+
+ ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
+ ot->prop = RNA_def_boolean(ot->srna, "invert", true, "Invert", "Invert the new mask");
+ ot->prop = RNA_def_boolean(
+ ot->srna, "use_cursor", true, "Use Cursor", "Expand the mask to the cursor position");
+ ot->prop = RNA_def_boolean(ot->srna,
+ "update_pivot",
+ true,
+ "Update Pivot Position",
+ "Set the pivot position to the mask border after creating the mask");
+ ot->prop = RNA_def_int(ot->srna, "smooth_iterations", 2, 0, 10, "Smooth iterations", "", 0, 10);
+ ot->prop = RNA_def_int(ot->srna, "mask_speed", 5, 1, 10, "Mask speed", "", 1, 10);
+
+ ot->prop = RNA_def_boolean(ot->srna,
+ "use_normals",
+ true,
+ "Use Normals",
+ "Generate the mask using the normals and curvature of the model");
+ ot->prop = RNA_def_boolean(ot->srna,
+ "keep_previous_mask",
+ false,
+ "Keep Previous Mask",
+ "Generate the new mask on top of the current one");
+ ot->prop = RNA_def_int(ot->srna,
+ "edge_sensitivity",
+ 300,
+ 0,
+ 2000,
+ "Edge Detection Sensitivity",
+ "Sensitivity for expanding the mask across sculpted sharp edges when "
+ "using normals to generate the mask",
+ 0,
+ 2000);
+ ot->prop = RNA_def_boolean(ot->srna,
+ "create_face_set",
+ false,
+ "Expand Face Mask",
+ "Expand a new Face Mask instead of the sculpt mask");
+}
diff --git a/source/blender/editors/sculpt_paint/sculpt_multiplane_scrape.c b/source/blender/editors/sculpt_paint/sculpt_multiplane_scrape.c
index c74a2ba503a..f3327706102 100644
--- a/source/blender/editors/sculpt_paint/sculpt_multiplane_scrape.c
+++ b/source/blender/editors/sculpt_paint/sculpt_multiplane_scrape.c
@@ -10,7 +10,7 @@
* 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,
+ * along with this program; if not, write to the Free Software Foundation,
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*
* The Original Code is Copyright (C) 2020 Blender Foundation.
@@ -79,6 +79,7 @@ static void calc_multiplane_scrape_surface_task_cb(void *__restrict userdata,
SculptBrushTest test;
SculptBrushTestFn sculpt_brush_test_sq_fn = SCULPT_brush_test_init_with_falloff_shape(
ss, &test, brush->falloff_shape);
+ const int thread_id = BLI_task_parallel_thread_id(tls);
/* Apply the brush normal radius to the test before sampling. */
float test_radius = sqrtf(test.radius_squared);
@@ -107,7 +108,7 @@ static void calc_multiplane_scrape_surface_task_cb(void *__restrict userdata,
vd.fno,
vd.mask ? *vd.mask : 0.0f,
vd.index,
- tls->thread_id);
+ thread_id);
/* Sample the normal and area of the +X and -X axis individually. */
if (local_co[0] > 0.0f) {
@@ -163,6 +164,7 @@ static void do_multiplane_scrape_brush_task_cb_ex(void *__restrict userdata,
SculptBrushTest test;
SculptBrushTestFn sculpt_brush_test_sq_fn = SCULPT_brush_test_init_with_falloff_shape(
ss, &test, data->brush->falloff_shape);
+ const int thread_id = BLI_task_parallel_thread_id(tls);
BKE_pbvh_vertex_iter_begin(ss->pbvh, data->nodes[n], vd, PBVH_ITER_UNIQUE)
{
@@ -208,7 +210,7 @@ static void do_multiplane_scrape_brush_task_cb_ex(void *__restrict userdata,
vd.fno,
vd.mask ? *vd.mask : 0.0f,
vd.index,
- tls->thread_id);
+ thread_id);
mul_v3_v3fl(proxy[vd.i], val, fade);
@@ -301,13 +303,13 @@ void SCULPT_do_multiplane_scrape_brush(Sculpt *sd, Object *ob, PBVHNode **nodes,
MultiplaneScrapeSampleData mssd = {{{0}}};
- PBVHParallelSettings sample_settings;
+ TaskParallelSettings sample_settings;
BKE_pbvh_parallel_range_settings(&sample_settings, (sd->flags & SCULPT_USE_OPENMP), totnode);
sample_settings.func_reduce = calc_multiplane_scrape_surface_reduce;
sample_settings.userdata_chunk = &mssd;
sample_settings.userdata_chunk_size = sizeof(MultiplaneScrapeSampleData);
- BKE_pbvh_parallel_range(
+ BLI_task_parallel_range(
0, totnode, &sample_data, calc_multiplane_scrape_surface_task_cb, &sample_settings);
float sampled_plane_normals[2][3];
@@ -392,9 +394,9 @@ void SCULPT_do_multiplane_scrape_brush(Sculpt *sd, Object *ob, PBVHNode **nodes,
normalize_v3(plane_no);
plane_from_point_normal_v3(data.multiplane_scrape_planes[0], area_co, plane_no);
- PBVHParallelSettings settings;
+ TaskParallelSettings settings;
BKE_pbvh_parallel_range_settings(&settings, (sd->flags & SCULPT_USE_OPENMP), totnode);
- BKE_pbvh_parallel_range(0, totnode, &data, do_multiplane_scrape_brush_task_cb_ex, &settings);
+ BLI_task_parallel_range(0, totnode, &data, do_multiplane_scrape_brush_task_cb_ex, &settings);
}
void SCULPT_multiplane_scrape_preview_draw(const uint gpuattr,
diff --git a/source/blender/editors/sculpt_paint/sculpt_pose.c b/source/blender/editors/sculpt_paint/sculpt_pose.c
index f1c884f9897..56ba15bef70 100644
--- a/source/blender/editors/sculpt_paint/sculpt_pose.c
+++ b/source/blender/editors/sculpt_paint/sculpt_pose.c
@@ -10,7 +10,7 @@
* 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,
+ * along with this program; if not, write to the Free Software Foundation,
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*
* The Original Code is Copyright (C) 2020 Blender Foundation.
@@ -131,6 +131,32 @@ static void pose_solve_roll_chain(SculptPoseIKChain *ik_chain,
}
}
+static void pose_solve_translate_chain(SculptPoseIKChain *ik_chain, const float delta[3])
+{
+ SculptPoseIKChainSegment *segments = ik_chain->segments;
+ const int tot_segments = ik_chain->tot_segments;
+
+ for (int i = 0; i < tot_segments; i++) {
+ /* Move the origin and head of each segment by delta. */
+ add_v3_v3v3(segments[i].head, segments[i].initial_head, delta);
+ add_v3_v3v3(segments[i].orig, segments[i].initial_orig, delta);
+
+ /* Reset the segment rotation. */
+ unit_qt(segments[i].rot);
+ }
+}
+
+static void pose_solve_scale_chain(SculptPoseIKChain *ik_chain, const float scale)
+{
+ SculptPoseIKChainSegment *segments = ik_chain->segments;
+ const int tot_segments = ik_chain->tot_segments;
+
+ for (int i = 0; i < tot_segments; i++) {
+ /* Assign the scale to each segment. */
+ segments[i].scale = scale;
+ }
+}
+
static void do_pose_brush_task_cb_ex(void *__restrict userdata,
const int n,
const TaskParallelTLS *__restrict UNUSED(tls))
@@ -209,12 +235,11 @@ static void pose_brush_grow_factor_task_cb_ex(void *__restrict userdata,
float max = 0.0f;
/* Grow the factor. */
- sculpt_vertex_neighbors_iter_begin(ss, vd.index, ni)
- {
+ SCULPT_VERTEX_NEIGHBORS_ITER_BEGIN (ss, vd.index, ni) {
float vmask_f = data->prev_mask[ni.index];
max = MAX2(vmask_f, max);
}
- sculpt_vertex_neighbors_iter_end(ni);
+ SCULPT_VERTEX_NEIGHBORS_ITER_END(ni);
/* Keep the count of the vertices that where added to the factors in this grow iteration. */
if (max > data->prev_mask[vd.index]) {
@@ -264,7 +289,7 @@ static void sculpt_pose_grow_pose_factor(Sculpt *sd,
};
data.pose_initial_co = pose_target;
- PBVHParallelSettings settings;
+ TaskParallelSettings settings;
PoseGrowFactorTLSData gftd;
gftd.pos_count = 0;
zero_v3(gftd.pos_avg);
@@ -280,7 +305,7 @@ static void sculpt_pose_grow_pose_factor(Sculpt *sd,
zero_v3(gftd.pos_avg);
gftd.pos_count = 0;
memcpy(data.prev_mask, pose_factor, SCULPT_vertex_count_get(ss) * sizeof(float));
- BKE_pbvh_parallel_range(0, totnode, &data, pose_brush_grow_factor_task_cb_ex, &settings);
+ BLI_task_parallel_range(0, totnode, &data, pose_brush_grow_factor_task_cb_ex, &settings);
if (gftd.pos_count != 0) {
mul_v3_fl(gftd.pos_avg, 1.0f / (float)gftd.pos_count);
@@ -352,18 +377,55 @@ typedef struct PoseFloodFillData {
float *pose_factor;
float pose_origin[3];
int tot_co;
+
+ int current_face_set;
+ int next_face_set;
+ int prev_face_set;
+ int next_vertex;
+
+ bool next_face_set_found;
+
+ /* Store the visited face sets to avoid going back when calculating the chain. */
+ GSet *visited_face_sets;
+
+ /* In face sets origin mode, each vertex can only be assigned to one face set. */
+ BLI_bitmap *is_weighted;
+
+ bool is_first_iteration;
+
+ /* In topology mode this stores the furthest point from the stroke origin for cases when a pose
+ * origin based on the brush radius can't be set. */
+ float fallback_floodfill_origin[3];
+
+ /* Fallback origin. If we can't find any face set to continue, use the position of all vertices
+ * that have the current face set. */
+ float fallback_origin[3];
+ int fallback_count;
+
+ /* Face Set FK mode. */
+ int *floodfill_it;
+ float *fk_weights;
+ int initial_face_set;
+ int masked_face_set_it;
+ int masked_face_set;
+ int target_face_set;
} PoseFloodFillData;
-static bool pose_floodfill_cb(
+static bool pose_topology_floodfill_cb(
SculptSession *ss, int UNUSED(from_v), int to_v, bool is_duplicate, void *userdata)
{
PoseFloodFillData *data = userdata;
+ const float *co = SCULPT_vertex_co_get(ss, to_v);
if (data->pose_factor) {
data->pose_factor[to_v] = 1.0f;
}
- const float *co = SCULPT_vertex_co_get(ss, to_v);
+ if (len_squared_v3v3(data->pose_initial_co, data->fallback_floodfill_origin) <
+ len_squared_v3v3(data->pose_initial_co, co)) {
+ copy_v3_v3(data->fallback_floodfill_origin, co);
+ }
+
if (sculpt_pose_brush_is_vertex_inside_brush_radius(
co, data->pose_initial_co, data->radius, data->symm)) {
return true;
@@ -378,6 +440,100 @@ static bool pose_floodfill_cb(
return false;
}
+static bool pose_face_sets_floodfill_cb(
+ SculptSession *ss, int UNUSED(from_v), int to_v, bool is_duplicate, void *userdata)
+{
+ PoseFloodFillData *data = userdata;
+
+ const int index = to_v;
+ bool visit_next = false;
+
+ const float *co = SCULPT_vertex_co_get(ss, index);
+ const bool symmetry_check = SCULPT_check_vertex_pivot_symmetry(
+ co, data->pose_initial_co, data->symm) &&
+ !is_duplicate;
+
+ /* First iteration. Continue expanding using topology until a vertex is outside the brush radius
+ * to determine the first face set. */
+ if (data->current_face_set == SCULPT_FACE_SET_NONE) {
+
+ data->pose_factor[index] = 1.0f;
+ BLI_BITMAP_ENABLE(data->is_weighted, index);
+
+ if (sculpt_pose_brush_is_vertex_inside_brush_radius(
+ co, data->pose_initial_co, data->radius, data->symm)) {
+ const int visited_face_set = SCULPT_vertex_face_set_get(ss, index);
+ BLI_gset_add(data->visited_face_sets, POINTER_FROM_INT(visited_face_set));
+ }
+ else if (symmetry_check) {
+ data->current_face_set = SCULPT_vertex_face_set_get(ss, index);
+ BLI_gset_add(data->visited_face_sets, POINTER_FROM_INT(data->current_face_set));
+ }
+ return true;
+ }
+
+ /* We already have a current face set, so we can start checking the face sets of the vertices. */
+ /* In the first iteration we need to check all face sets we already visited as the flood fill may
+ * still not be finished in some of them. */
+ bool is_vertex_valid = false;
+ if (data->is_first_iteration) {
+ GSetIterator gs_iter;
+ GSET_ITER (gs_iter, data->visited_face_sets) {
+ const int visited_face_set = POINTER_AS_INT(BLI_gsetIterator_getKey(&gs_iter));
+ is_vertex_valid |= SCULPT_vertex_has_face_set(ss, index, visited_face_set);
+ }
+ }
+ else {
+ is_vertex_valid = SCULPT_vertex_has_face_set(ss, index, data->current_face_set);
+ }
+
+ if (is_vertex_valid) {
+
+ if (!BLI_BITMAP_TEST(data->is_weighted, index)) {
+ data->pose_factor[index] = 1.0f;
+ BLI_BITMAP_ENABLE(data->is_weighted, index);
+ visit_next = true;
+ }
+
+ /* Fallback origin accumulation. */
+ if (symmetry_check) {
+ add_v3_v3(data->fallback_origin, SCULPT_vertex_co_get(ss, index));
+ data->fallback_count++;
+ }
+
+ if (symmetry_check && !SCULPT_vertex_has_unique_face_set(ss, index)) {
+
+ /* We only add coordinates for calculating the origin when it is possible to go from this
+ * vertex to another vertex in a valid face set for the next iteration. */
+ bool count_as_boundary = false;
+
+ SculptVertexNeighborIter ni;
+ SCULPT_VERTEX_NEIGHBORS_ITER_BEGIN (ss, index, ni) {
+ int next_face_set_candidate = SCULPT_vertex_face_set_get(ss, ni.index);
+
+ /* Check if we can get a valid face set for the next iteration from this neighbor. */
+ if (SCULPT_vertex_has_unique_face_set(ss, ni.index) &&
+ !BLI_gset_haskey(data->visited_face_sets, POINTER_FROM_INT(next_face_set_candidate))) {
+ if (!data->next_face_set_found) {
+ data->next_face_set = next_face_set_candidate;
+ data->next_vertex = ni.index;
+ data->next_face_set_found = true;
+ }
+ count_as_boundary = true;
+ }
+ }
+ SCULPT_VERTEX_NEIGHBORS_ITER_END(ni);
+
+ /* Origin accumulation. */
+ if (count_as_boundary) {
+ add_v3_v3(data->pose_origin, SCULPT_vertex_co_get(ss, index));
+ data->tot_co++;
+ }
+ }
+ }
+ return visit_next;
+}
+
/* Public functions. */
/* Calculate the pose origin and (Optionaly the pose factor) that is used when using the pose brush
@@ -408,12 +564,16 @@ void SCULPT_pose_calc_pose_data(Sculpt *sd,
};
zero_v3(fdata.pose_origin);
copy_v3_v3(fdata.pose_initial_co, initial_location);
- SCULPT_floodfill_execute(ss, &flood, pose_floodfill_cb, &fdata);
+ copy_v3_v3(fdata.fallback_floodfill_origin, initial_location);
+ SCULPT_floodfill_execute(ss, &flood, pose_topology_floodfill_cb, &fdata);
SCULPT_floodfill_free(&flood);
if (fdata.tot_co > 0) {
mul_v3_fl(fdata.pose_origin, 1.0f / (float)fdata.tot_co);
}
+ else {
+ copy_v3_v3(fdata.pose_origin, fdata.fallback_floodfill_origin);
+ }
/* Offset the pose origin. */
float pose_d[3];
@@ -442,12 +602,11 @@ static void pose_brush_init_task_cb_ex(void *__restrict userdata,
SculptVertexNeighborIter ni;
float avg = 0.0f;
int total = 0;
- sculpt_vertex_neighbors_iter_begin(ss, vd.index, ni)
- {
+ SCULPT_VERTEX_NEIGHBORS_ITER_BEGIN (ss, vd.index, ni) {
avg += data->pose_factor[ni.index];
total++;
}
- sculpt_vertex_neighbors_iter_end(ni);
+ SCULPT_VERTEX_NEIGHBORS_ITER_END(ni);
if (total > 0) {
data->pose_factor[vd.index] = avg / total;
@@ -456,12 +615,59 @@ static void pose_brush_init_task_cb_ex(void *__restrict userdata,
BKE_pbvh_vertex_iter_end;
}
-SculptPoseIKChain *SCULPT_pose_ik_chain_init(Sculpt *sd,
- Object *ob,
- SculptSession *ss,
- Brush *br,
- const float initial_location[3],
- const float radius)
+/* Init the IK chain with empty weights. */
+static SculptPoseIKChain *pose_ik_chain_new(const int totsegments, const int totverts)
+{
+ SculptPoseIKChain *ik_chain = MEM_callocN(sizeof(SculptPoseIKChain), "Pose IK Chain");
+ ik_chain->tot_segments = totsegments;
+ ik_chain->segments = MEM_callocN(totsegments * sizeof(SculptPoseIKChainSegment),
+ "Pose IK Chain Segments");
+ for (int i = 0; i < totsegments; i++) {
+ ik_chain->segments[i].weights = MEM_callocN(totverts * sizeof(float), "Pose IK weights");
+ }
+ return ik_chain;
+}
+
+/* Init the origin/head pairs of all the segments from the calculated origins. */
+static void pose_ik_chain_origin_heads_init(SculptPoseIKChain *ik_chain,
+ const float initial_location[3])
+{
+ float origin[3];
+ float head[3];
+ for (int i = 0; i < ik_chain->tot_segments; i++) {
+ if (i == 0) {
+ copy_v3_v3(head, initial_location);
+ copy_v3_v3(origin, ik_chain->segments[i].orig);
+ }
+ else {
+ copy_v3_v3(head, ik_chain->segments[i - 1].orig);
+ copy_v3_v3(origin, ik_chain->segments[i].orig);
+ }
+ copy_v3_v3(ik_chain->segments[i].orig, origin);
+ copy_v3_v3(ik_chain->segments[i].initial_orig, origin);
+ copy_v3_v3(ik_chain->segments[i].initial_head, head);
+ ik_chain->segments[i].len = len_v3v3(head, origin);
+ ik_chain->segments[i].scale = 1.0f;
+ }
+}
+
+static int pose_brush_num_effective_segments(const Brush *brush)
+{
+ /* Scaling multiple segments at the same time is not supported as the IK solver can't handle
+ * changes in the segment's length. It will also required a better weight distribution to avoid
+ * artifacts in the areas affected by multiple segments. */
+ if (brush->pose_deform_type == BRUSH_POSE_DEFORM_SCALE_TRASLATE) {
+ return 1;
+ }
+ return brush->pose_ik_segments;
+}
+
+static SculptPoseIKChain *pose_ik_chain_init_topology(Sculpt *sd,
+ Object *ob,
+ SculptSession *ss,
+ Brush *br,
+ const float initial_location[3],
+ const float radius)
{
const float chain_segment_len = radius * (1.0f + br->pose_offset);
@@ -482,14 +688,8 @@ SculptPoseIKChain *SCULPT_pose_ik_chain_init(Sculpt *sd,
pose_factor_grow[nearest_vertex_index] = 1.0f;
- /* Init the IK chain with empty weights. */
- SculptPoseIKChain *ik_chain = MEM_callocN(sizeof(SculptPoseIKChain), "Pose IK Chain");
- ik_chain->tot_segments = br->pose_ik_segments;
- ik_chain->segments = MEM_callocN(ik_chain->tot_segments * sizeof(SculptPoseIKChainSegment),
- "Pose IK Chain Segments");
- for (int i = 0; i < br->pose_ik_segments; i++) {
- ik_chain->segments[i].weights = MEM_callocN(totvert * sizeof(float), "Pose IK weights");
- }
+ const int tot_segments = pose_brush_num_effective_segments(br);
+ SculptPoseIKChain *ik_chain = pose_ik_chain_new(tot_segments, totvert);
/* Calculate the first segment in the chain using the brush radius and the pose origin offset. */
copy_v3_v3(next_chain_segment_target, initial_location);
@@ -534,30 +734,220 @@ SculptPoseIKChain *SCULPT_pose_ik_chain_init(Sculpt *sd,
}
}
- /* Init the origin/head pairs of all the segments from the calculated origins. */
- float origin[3];
- float head[3];
- for (int i = 0; i < ik_chain->tot_segments; i++) {
- if (i == 0) {
- copy_v3_v3(head, initial_location);
- copy_v3_v3(origin, ik_chain->segments[i].orig);
+ pose_ik_chain_origin_heads_init(ik_chain, initial_location);
+
+ MEM_freeN(pose_factor_grow);
+ MEM_freeN(pose_factor_grow_prev);
+
+ return ik_chain;
+}
+
+static SculptPoseIKChain *pose_ik_chain_init_face_sets(
+ Sculpt *sd, Object *ob, SculptSession *ss, Brush *br, const float radius)
+{
+
+ int totvert = SCULPT_vertex_count_get(ss);
+
+ const int tot_segments = pose_brush_num_effective_segments(br);
+
+ SculptPoseIKChain *ik_chain = pose_ik_chain_new(tot_segments, totvert);
+
+ GSet *visited_face_sets = BLI_gset_int_new_ex("visited_face_sets", ik_chain->tot_segments);
+
+ BLI_bitmap *is_weighted = BLI_BITMAP_NEW(totvert, "weighted");
+
+ int current_face_set = SCULPT_FACE_SET_NONE;
+ int prev_face_set = SCULPT_FACE_SET_NONE;
+
+ int current_vertex = SCULPT_active_vertex_get(ss);
+
+ for (int s = 0; s < ik_chain->tot_segments; s++) {
+
+ SculptFloodFill flood;
+ SCULPT_floodfill_init(ss, &flood);
+ SCULPT_floodfill_add_initial_with_symmetry(sd, ob, ss, &flood, current_vertex, FLT_MAX);
+
+ BLI_gset_add(visited_face_sets, POINTER_FROM_INT(current_face_set));
+
+ PoseFloodFillData fdata = {
+ .radius = radius,
+ .symm = sd->paint.symmetry_flags & PAINT_SYMM_AXIS_ALL,
+ .pose_factor = ik_chain->segments[s].weights,
+ .tot_co = 0,
+ .fallback_count = 0,
+ .current_face_set = current_face_set,
+ .prev_face_set = prev_face_set,
+ .visited_face_sets = visited_face_sets,
+ .is_weighted = is_weighted,
+ .next_face_set_found = false,
+ .is_first_iteration = s == 0,
+ };
+ zero_v3(fdata.pose_origin);
+ zero_v3(fdata.fallback_origin);
+ copy_v3_v3(fdata.pose_initial_co, SCULPT_vertex_co_get(ss, current_vertex));
+ SCULPT_floodfill_execute(ss, &flood, pose_face_sets_floodfill_cb, &fdata);
+ SCULPT_floodfill_free(&flood);
+
+ if (fdata.tot_co > 0) {
+ mul_v3_fl(fdata.pose_origin, 1.0f / (float)fdata.tot_co);
+ copy_v3_v3(ik_chain->segments[s].orig, fdata.pose_origin);
+ }
+ else if (fdata.fallback_count > 0) {
+ mul_v3_fl(fdata.fallback_origin, 1.0f / (float)fdata.fallback_count);
+ copy_v3_v3(ik_chain->segments[s].orig, fdata.fallback_origin);
}
else {
- copy_v3_v3(head, ik_chain->segments[i - 1].orig);
- copy_v3_v3(origin, ik_chain->segments[i].orig);
+ zero_v3(ik_chain->segments[s].orig);
}
- copy_v3_v3(ik_chain->segments[i].orig, origin);
- copy_v3_v3(ik_chain->segments[i].initial_orig, origin);
- copy_v3_v3(ik_chain->segments[i].initial_head, head);
- ik_chain->segments[i].len = len_v3v3(head, origin);
+
+ prev_face_set = fdata.current_face_set;
+ current_face_set = fdata.next_face_set;
+ current_vertex = fdata.next_vertex;
}
- MEM_freeN(pose_factor_grow);
- MEM_freeN(pose_factor_grow_prev);
+ BLI_gset_free(visited_face_sets, NULL);
+
+ pose_ik_chain_origin_heads_init(ik_chain, SCULPT_active_vertex_co_get(ss));
+
+ MEM_SAFE_FREE(is_weighted);
return ik_chain;
}
+static bool pose_face_sets_fk_find_masked_floodfill_cb(
+ SculptSession *ss, int from_v, int to_v, bool is_duplicate, void *userdata)
+{
+ PoseFloodFillData *data = userdata;
+
+ if (!is_duplicate) {
+ data->floodfill_it[to_v] = data->floodfill_it[from_v] + 1;
+ }
+ else {
+ data->floodfill_it[to_v] = data->floodfill_it[from_v];
+ }
+
+ const int to_face_set = SCULPT_vertex_face_set_get(ss, to_v);
+ if (SCULPT_vertex_has_unique_face_set(ss, to_v) &&
+ !SCULPT_vertex_has_unique_face_set(ss, from_v) &&
+ SCULPT_vertex_has_face_set(ss, from_v, to_face_set)) {
+
+ if (data->floodfill_it[to_v] > data->masked_face_set_it) {
+ data->masked_face_set = to_face_set;
+ data->masked_face_set_it = data->floodfill_it[to_v];
+ }
+
+ if (data->target_face_set == SCULPT_FACE_SET_NONE) {
+ data->target_face_set = to_face_set;
+ }
+ }
+
+ return SCULPT_vertex_has_face_set(ss, to_v, data->initial_face_set);
+}
+
+static bool pose_face_sets_fk_set_weights_floodfill_cb(
+ SculptSession *ss, int UNUSED(from_v), int to_v, bool UNUSED(is_duplicate), void *userdata)
+{
+ PoseFloodFillData *data = userdata;
+ data->fk_weights[to_v] = 1.0f;
+ return !SCULPT_vertex_has_face_set(ss, to_v, data->masked_face_set);
+}
+
+static SculptPoseIKChain *pose_ik_chain_init_face_sets_fk(
+ Sculpt *sd, Object *ob, SculptSession *ss, const float radius, const float *initial_location)
+{
+ const int totvert = SCULPT_vertex_count_get(ss);
+
+ SculptPoseIKChain *ik_chain = pose_ik_chain_new(1, totvert);
+
+ const int active_vertex = SCULPT_active_vertex_get(ss);
+ const int active_face_set = SCULPT_active_face_set_get(ss);
+
+ SculptFloodFill flood;
+ SCULPT_floodfill_init(ss, &flood);
+ SCULPT_floodfill_add_initial(&flood, active_vertex);
+ PoseFloodFillData fdata;
+ fdata.floodfill_it = MEM_calloc_arrayN(totvert, sizeof(int), "floodfill iteration");
+ fdata.floodfill_it[active_vertex] = 1;
+ fdata.initial_face_set = active_face_set;
+ fdata.masked_face_set = SCULPT_FACE_SET_NONE;
+ fdata.target_face_set = SCULPT_FACE_SET_NONE;
+ fdata.masked_face_set_it = 0;
+ SCULPT_floodfill_execute(ss, &flood, pose_face_sets_fk_find_masked_floodfill_cb, &fdata);
+ SCULPT_floodfill_free(&flood);
+
+ int origin_count = 0;
+ float origin_acc[3] = {0.0f};
+ for (int i = 0; i < totvert; i++) {
+ if (fdata.floodfill_it[i] != 0 && SCULPT_vertex_has_face_set(ss, i, fdata.initial_face_set) &&
+ SCULPT_vertex_has_face_set(ss, i, fdata.masked_face_set)) {
+ add_v3_v3(origin_acc, SCULPT_vertex_co_get(ss, i));
+ origin_count++;
+ }
+ }
+
+ int target_count = 0;
+ float target_acc[3] = {0.0f};
+ if (fdata.target_face_set != fdata.masked_face_set) {
+ for (int i = 0; i < totvert; i++) {
+ if (fdata.floodfill_it[i] != 0 &&
+ SCULPT_vertex_has_face_set(ss, i, fdata.initial_face_set) &&
+ SCULPT_vertex_has_face_set(ss, i, fdata.target_face_set)) {
+ add_v3_v3(target_acc, SCULPT_vertex_co_get(ss, i));
+ target_count++;
+ }
+ }
+ }
+
+ MEM_freeN(fdata.floodfill_it);
+
+ if (origin_count > 0) {
+ copy_v3_v3(ik_chain->segments[0].orig, origin_acc);
+ mul_v3_fl(ik_chain->segments[0].orig, 1.0f / origin_count);
+ }
+ else {
+ zero_v3(ik_chain->segments[0].orig);
+ }
+
+ if (target_count > 0) {
+ copy_v3_v3(ik_chain->segments[0].head, target_acc);
+ mul_v3_fl(ik_chain->segments[0].head, 1.0f / target_count);
+ sub_v3_v3v3(ik_chain->grab_delta_offset, ik_chain->segments[0].head, initial_location);
+ }
+ else {
+ copy_v3_v3(ik_chain->segments[0].head, initial_location);
+ }
+
+ SCULPT_floodfill_init(ss, &flood);
+ SCULPT_floodfill_add_active(sd, ob, ss, &flood, radius);
+ fdata.fk_weights = ik_chain->segments[0].weights;
+ SCULPT_floodfill_execute(ss, &flood, pose_face_sets_fk_set_weights_floodfill_cb, &fdata);
+ SCULPT_floodfill_free(&flood);
+
+ pose_ik_chain_origin_heads_init(ik_chain, ik_chain->segments[0].head);
+ return ik_chain;
+}
+
+SculptPoseIKChain *SCULPT_pose_ik_chain_init(Sculpt *sd,
+ Object *ob,
+ SculptSession *ss,
+ Brush *br,
+ const float initial_location[3],
+ const float radius)
+{
+ switch (br->pose_origin_type) {
+ case BRUSH_POSE_ORIGIN_TOPOLOGY:
+ return pose_ik_chain_init_topology(sd, ob, ss, br, initial_location, radius);
+ break;
+ case BRUSH_POSE_ORIGIN_FACE_SETS:
+ return pose_ik_chain_init_face_sets(sd, ob, ss, br, radius);
+ break;
+ case BRUSH_POSE_ORIGIN_FACE_SETS_FK:
+ return pose_ik_chain_init_face_sets_fk(sd, ob, ss, radius, initial_location);
+ break;
+ }
+ return NULL;
+}
+
void SCULPT_pose_brush_init(Sculpt *sd, Object *ob, SculptSession *ss, Brush *br)
{
PBVHNode **nodes;
@@ -581,22 +971,95 @@ void SCULPT_pose_brush_init(Sculpt *sd, Object *ob, SculptSession *ss, Brush *br
for (int ik = 0; ik < ss->cache->pose_ik_chain->tot_segments; ik++) {
data.pose_factor = ss->cache->pose_ik_chain->segments[ik].weights;
for (int i = 0; i < br->pose_smooth_iterations; i++) {
- PBVHParallelSettings settings;
+ TaskParallelSettings settings;
BKE_pbvh_parallel_range_settings(&settings, (sd->flags & SCULPT_USE_OPENMP), totnode);
- BKE_pbvh_parallel_range(0, totnode, &data, pose_brush_init_task_cb_ex, &settings);
+ BLI_task_parallel_range(0, totnode, &data, pose_brush_init_task_cb_ex, &settings);
}
}
MEM_SAFE_FREE(nodes);
}
+static void sculpt_pose_do_translate_deform(SculptSession *ss, Brush *brush)
+{
+ SculptPoseIKChain *ik_chain = ss->cache->pose_ik_chain;
+ BKE_curvemapping_initialize(brush->curve);
+ pose_solve_translate_chain(ik_chain, ss->cache->grab_delta);
+}
+
+static void sculpt_pose_do_scale_deform(SculptSession *ss, Brush *brush)
+{
+ float ik_target[3];
+ SculptPoseIKChain *ik_chain = ss->cache->pose_ik_chain;
+
+ copy_v3_v3(ik_target, ss->cache->true_location);
+ add_v3_v3(ik_target, ss->cache->grab_delta);
+
+ /* Solve the IK for the first segment to include rotation as part of scale. */
+ pose_solve_ik_chain(ik_chain, ik_target, brush->flag2 & BRUSH_POSE_IK_ANCHORED);
+
+ /* Calculate a scale factor based on the grab delta. */
+ float plane[4];
+ float segment_dir[3];
+ sub_v3_v3v3(segment_dir, ik_chain->segments[0].initial_head, ik_chain->segments[0].initial_orig);
+ normalize_v3(segment_dir);
+ plane_from_point_normal_v3(plane, ik_chain->segments[0].initial_head, segment_dir);
+ const float segment_len = ik_chain->segments[0].len;
+ const float scale = segment_len / (segment_len - dist_signed_to_plane_v3(ik_target, plane));
+
+ /* Write the scale into the segments. */
+ pose_solve_scale_chain(ik_chain, scale);
+}
+
+static void sculpt_pose_do_twist_deform(SculptSession *ss, Brush *brush)
+{
+ SculptPoseIKChain *ik_chain = ss->cache->pose_ik_chain;
+
+ /* Calculate the maximum roll. 0.02 radians per pixel works fine. */
+ float roll = (ss->cache->initial_mouse[0] - ss->cache->mouse[0]) * ss->cache->bstrength * 0.02f;
+ BKE_curvemapping_initialize(brush->curve);
+ pose_solve_roll_chain(ik_chain, brush, roll);
+}
+
+static void sculpt_pose_do_rotate_deform(SculptSession *ss, Brush *brush)
+{
+ float ik_target[3];
+ SculptPoseIKChain *ik_chain = ss->cache->pose_ik_chain;
+
+ /* Calculate the IK target. */
+ copy_v3_v3(ik_target, ss->cache->true_location);
+ add_v3_v3(ik_target, ss->cache->grab_delta);
+ add_v3_v3(ik_target, ik_chain->grab_delta_offset);
+
+ /* Solve the IK positions. */
+ pose_solve_ik_chain(ik_chain, ik_target, brush->flag2 & BRUSH_POSE_IK_ANCHORED);
+}
+
+static void sculpt_pose_do_rotate_twist_deform(SculptSession *ss, Brush *brush)
+{
+ if (ss->cache->invert) {
+ sculpt_pose_do_twist_deform(ss, brush);
+ }
+ else {
+ sculpt_pose_do_rotate_deform(ss, brush);
+ }
+}
+
+static void sculpt_pose_do_scale_translate_deform(SculptSession *ss, Brush *brush)
+{
+ if (ss->cache->invert) {
+ sculpt_pose_do_translate_deform(ss, brush);
+ }
+ else {
+ sculpt_pose_do_scale_deform(ss, brush);
+ }
+}
+
/* Main Brush Function. */
void SCULPT_do_pose_brush(Sculpt *sd, Object *ob, PBVHNode **nodes, int totnode)
{
SculptSession *ss = ob->sculpt;
Brush *brush = BKE_paint_brush(&sd->paint);
- float grab_delta[3];
- float ik_target[3];
const ePaintSymmetryFlags symm = sd->paint.symmetry_flags & PAINT_SYMM_AXIS_ALL;
/* The pose brush applies all enabled symmetry axis in a single iteration, so the rest can be
@@ -607,25 +1070,13 @@ void SCULPT_do_pose_brush(Sculpt *sd, Object *ob, PBVHNode **nodes, int totnode)
SculptPoseIKChain *ik_chain = ss->cache->pose_ik_chain;
- /* Solve the positions and rotations of the IK chain. */
- if (ss->cache->invert) {
- /* Roll Mode. */
- /* Calculate the maximum roll. 0.02 radians per pixel works fine. */
- float roll = (ss->cache->initial_mouse[0] - ss->cache->mouse[0]) * ss->cache->bstrength *
- 0.02f;
- BKE_curvemapping_initialize(brush->curve);
- pose_solve_roll_chain(ik_chain, brush, roll);
- }
- else {
- /* IK follow target mode. */
- /* Calculate the IK target. */
-
- copy_v3_v3(grab_delta, ss->cache->grab_delta);
- copy_v3_v3(ik_target, ss->cache->true_location);
- add_v3_v3(ik_target, ss->cache->grab_delta);
-
- /* Solve the IK positions. */
- pose_solve_ik_chain(ik_chain, ik_target, brush->flag2 & BRUSH_POSE_IK_ANCHORED);
+ switch (brush->pose_deform_type) {
+ case BRUSH_POSE_DEFORM_ROTATE_TWIST:
+ sculpt_pose_do_rotate_twist_deform(ss, brush);
+ break;
+ case BRUSH_POSE_DEFORM_SCALE_TRASLATE:
+ sculpt_pose_do_scale_translate_deform(ss, brush);
+ break;
}
/* Flip the segment chain in all symmetry axis and calculate the transform matrices for each
@@ -633,7 +1084,7 @@ void SCULPT_do_pose_brush(Sculpt *sd, Object *ob, PBVHNode **nodes, int totnode)
/* This can be optimized by skipping the calculation of matrices where the symmetry is not
* enabled. */
for (int symm_it = 0; symm_it < PAINT_SYMM_AREAS; symm_it++) {
- for (int i = 0; i < brush->pose_ik_segments; i++) {
+ for (int i = 0; i < ik_chain->tot_segments; i++) {
float symm_rot[4];
float symm_orig[3];
float symm_initial_orig[3];
@@ -653,6 +1104,7 @@ void SCULPT_do_pose_brush(Sculpt *sd, Object *ob, PBVHNode **nodes, int totnode)
/* Create the transform matrix and store it in the segment. */
unit_m4(ik_chain->segments[i].pivot_mat[symm_it]);
quat_to_mat4(ik_chain->segments[i].trans_mat[symm_it], symm_rot);
+ mul_m4_fl(ik_chain->segments[i].trans_mat[symm_it], ik_chain->segments[i].scale);
translate_m4(ik_chain->segments[i].trans_mat[symm_it],
symm_orig[0] - symm_initial_orig[0],
@@ -670,12 +1122,11 @@ void SCULPT_do_pose_brush(Sculpt *sd, Object *ob, PBVHNode **nodes, int totnode)
.ob = ob,
.brush = brush,
.nodes = nodes,
- .grab_delta = grab_delta,
};
- PBVHParallelSettings settings;
+ TaskParallelSettings settings;
BKE_pbvh_parallel_range_settings(&settings, (sd->flags & SCULPT_USE_OPENMP), totnode);
- BKE_pbvh_parallel_range(0, totnode, &data, do_pose_brush_task_cb_ex, &settings);
+ BLI_task_parallel_range(0, totnode, &data, do_pose_brush_task_cb_ex, &settings);
}
void SCULPT_pose_ik_chain_free(SculptPoseIKChain *ik_chain)
diff --git a/source/blender/editors/sculpt_paint/sculpt_smooth.c b/source/blender/editors/sculpt_paint/sculpt_smooth.c
new file mode 100644
index 00000000000..17451cb40ae
--- /dev/null
+++ b/source/blender/editors/sculpt_paint/sculpt_smooth.c
@@ -0,0 +1,608 @@
+/*
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * The Original Code is Copyright (C) 2020 Blender Foundation.
+ * All rights reserved.
+ */
+
+/** \file
+ * \ingroup edsculpt
+ */
+
+#include "MEM_guardedalloc.h"
+
+#include "BLI_blenlib.h"
+#include "BLI_hash.h"
+#include "BLI_math.h"
+#include "BLI_task.h"
+
+#include "DNA_brush_types.h"
+#include "DNA_mesh_types.h"
+#include "DNA_meshdata_types.h"
+
+#include "BKE_brush.h"
+#include "BKE_context.h"
+#include "BKE_mesh.h"
+#include "BKE_mesh_mapping.h"
+#include "BKE_object.h"
+#include "BKE_paint.h"
+#include "BKE_pbvh.h"
+#include "BKE_scene.h"
+
+#include "DEG_depsgraph.h"
+
+#include "WM_api.h"
+#include "WM_message.h"
+#include "WM_toolsystem.h"
+#include "WM_types.h"
+
+#include "ED_object.h"
+#include "ED_screen.h"
+#include "ED_sculpt.h"
+#include "paint_intern.h"
+#include "sculpt_intern.h"
+
+#include "RNA_access.h"
+#include "RNA_define.h"
+
+#include "bmesh.h"
+
+#include <math.h>
+#include <stdlib.h>
+
+/* For the smooth brush, uses the neighboring vertices around vert to calculate
+ * a smoothed location for vert. Skips corner vertices (used by only one
+ * polygon). */
+void SCULPT_neighbor_average(SculptSession *ss, float avg[3], uint vert)
+{
+ const MeshElemMap *vert_map = &ss->pmap[vert];
+ const MVert *mvert = ss->mvert;
+ float(*deform_co)[3] = ss->deform_cos;
+
+ /* Don't modify corner vertices. */
+ if (vert_map->count > 1) {
+ int total = 0;
+
+ zero_v3(avg);
+
+ for (int i = 0; i < vert_map->count; i++) {
+ const MPoly *p = &ss->mpoly[vert_map->indices[i]];
+ uint f_adj_v[2];
+
+ if (poly_get_adj_loops_from_vert(p, ss->mloop, vert, f_adj_v) != -1) {
+ for (int j = 0; j < ARRAY_SIZE(f_adj_v); j += 1) {
+ if (vert_map->count != 2 || ss->pmap[f_adj_v[j]].count <= 2) {
+ add_v3_v3(avg, deform_co ? deform_co[f_adj_v[j]] : mvert[f_adj_v[j]].co);
+
+ total++;
+ }
+ }
+ }
+ }
+
+ if (total > 0) {
+ mul_v3_fl(avg, 1.0f / total);
+ return;
+ }
+ }
+
+ copy_v3_v3(avg, deform_co ? deform_co[vert] : mvert[vert].co);
+}
+
+/* Same logic as neighbor_average(), but for bmesh rather than mesh. */
+void SCULPT_bmesh_neighbor_average(float avg[3], BMVert *v)
+{
+ /* logic for 3 or more is identical. */
+ const int vfcount = BM_vert_face_count_at_most(v, 3);
+
+ /* Don't modify corner vertices. */
+ if (vfcount > 1) {
+ BMIter liter;
+ BMLoop *l;
+ int total = 0;
+
+ zero_v3(avg);
+
+ BM_ITER_ELEM (l, &liter, v, BM_LOOPS_OF_VERT) {
+ const BMVert *adj_v[2] = {l->prev->v, l->next->v};
+
+ for (int i = 0; i < ARRAY_SIZE(adj_v); i++) {
+ const BMVert *v_other = adj_v[i];
+ if (vfcount != 2 || BM_vert_face_count_at_most(v_other, 2) <= 2) {
+ add_v3_v3(avg, v_other->co);
+ total++;
+ }
+ }
+ }
+
+ if (total > 0) {
+ mul_v3_fl(avg, 1.0f / total);
+ return;
+ }
+ }
+
+ copy_v3_v3(avg, v->co);
+}
+
+/* For bmesh: Average surrounding verts based on an orthogonality measure.
+ * Naturally converges to a quad-like structure. */
+void SCULPT_bmesh_four_neighbor_average(float avg[3], float direction[3], BMVert *v)
+{
+
+ float avg_co[3] = {0.0f, 0.0f, 0.0f};
+ float tot_co = 0.0f;
+
+ BMIter eiter;
+ BMEdge *e;
+
+ BM_ITER_ELEM (e, &eiter, v, BM_EDGES_OF_VERT) {
+ if (BM_edge_is_boundary(e)) {
+ copy_v3_v3(avg, v->co);
+ return;
+ }
+ BMVert *v_other = (e->v1 == v) ? e->v2 : e->v1;
+ float vec[3];
+ sub_v3_v3v3(vec, v_other->co, v->co);
+ madd_v3_v3fl(vec, v->no, -dot_v3v3(vec, v->no));
+ normalize_v3(vec);
+
+ /* fac is a measure of how orthogonal or parallel the edge is
+ * relative to the direction. */
+ float fac = dot_v3v3(vec, direction);
+ fac = fac * fac - 0.5f;
+ fac *= fac;
+ madd_v3_v3fl(avg_co, v_other->co, fac);
+ tot_co += fac;
+ }
+
+ /* In case vert has no Edge s. */
+ if (tot_co > 0.0f) {
+ mul_v3_v3fl(avg, avg_co, 1.0f / tot_co);
+
+ /* Preserve volume. */
+ float vec[3];
+ sub_v3_v3(avg, v->co);
+ mul_v3_v3fl(vec, v->no, dot_v3v3(avg, v->no));
+ sub_v3_v3(avg, vec);
+ add_v3_v3(avg, v->co);
+ }
+ else {
+ zero_v3(avg);
+ }
+}
+
+/* Generic functions for laplacian smoothing. These functions do not take boundary vertices into
+ * account. */
+
+void SCULPT_neighbor_coords_average(SculptSession *ss, float result[3], int index)
+{
+ float avg[3] = {0.0f, 0.0f, 0.0f};
+ int total = 0;
+
+ SculptVertexNeighborIter ni;
+ SCULPT_VERTEX_NEIGHBORS_ITER_BEGIN (ss, index, ni) {
+ add_v3_v3(avg, SCULPT_vertex_co_get(ss, ni.index));
+ total++;
+ }
+ SCULPT_VERTEX_NEIGHBORS_ITER_END(ni);
+
+ if (total > 0) {
+ mul_v3_v3fl(result, avg, 1.0f / (float)total);
+ }
+ else {
+ copy_v3_v3(result, SCULPT_vertex_co_get(ss, index));
+ }
+}
+
+float SCULPT_neighbor_mask_average(SculptSession *ss, int index)
+{
+ float avg = 0.0f;
+ int total = 0;
+
+ SculptVertexNeighborIter ni;
+ SCULPT_VERTEX_NEIGHBORS_ITER_BEGIN (ss, index, ni) {
+ avg += SCULPT_vertex_mask_get(ss, ni.index);
+ total++;
+ }
+ SCULPT_VERTEX_NEIGHBORS_ITER_END(ni);
+
+ if (total > 0) {
+ return avg / (float)total;
+ }
+ else {
+ return SCULPT_vertex_mask_get(ss, index);
+ }
+}
+
+static void do_smooth_brush_mesh_task_cb_ex(void *__restrict userdata,
+ const int n,
+ const TaskParallelTLS *__restrict tls)
+{
+ SculptThreadedTaskData *data = userdata;
+ SculptSession *ss = data->ob->sculpt;
+ Sculpt *sd = data->sd;
+ const Brush *brush = data->brush;
+ const bool smooth_mask = data->smooth_mask;
+ float bstrength = data->strength;
+
+ PBVHVertexIter vd;
+
+ CLAMP(bstrength, 0.0f, 1.0f);
+
+ SculptBrushTest test;
+ SculptBrushTestFn sculpt_brush_test_sq_fn = SCULPT_brush_test_init_with_falloff_shape(
+ ss, &test, data->brush->falloff_shape);
+
+ const int thread_id = BLI_task_parallel_thread_id(tls);
+
+ BKE_pbvh_vertex_iter_begin(ss->pbvh, data->nodes[n], vd, PBVH_ITER_UNIQUE)
+ {
+ if (sculpt_brush_test_sq_fn(&test, vd.co)) {
+ const float fade = bstrength * SCULPT_brush_strength_factor(
+ ss,
+ brush,
+ vd.co,
+ sqrtf(test.dist),
+ vd.no,
+ vd.fno,
+ smooth_mask ? 0.0f : (vd.mask ? *vd.mask : 0.0f),
+ vd.index,
+ thread_id);
+ if (smooth_mask) {
+ float val = SCULPT_neighbor_mask_average(ss, vd.vert_indices[vd.i]) - *vd.mask;
+ val *= fade * bstrength;
+ *vd.mask += val;
+ CLAMP(*vd.mask, 0.0f, 1.0f);
+ }
+ else {
+ float avg[3], val[3];
+
+ SCULPT_neighbor_average(ss, avg, vd.vert_indices[vd.i]);
+ sub_v3_v3v3(val, avg, vd.co);
+
+ madd_v3_v3v3fl(val, vd.co, val, fade);
+
+ SCULPT_clip(sd, ss, vd.co, val);
+ }
+
+ if (vd.mvert) {
+ vd.mvert->flag |= ME_VERT_PBVH_UPDATE;
+ }
+ }
+ }
+ BKE_pbvh_vertex_iter_end;
+}
+
+static void do_smooth_brush_bmesh_task_cb_ex(void *__restrict userdata,
+ const int n,
+ const TaskParallelTLS *__restrict tls)
+{
+ SculptThreadedTaskData *data = userdata;
+ SculptSession *ss = data->ob->sculpt;
+ Sculpt *sd = data->sd;
+ const Brush *brush = data->brush;
+ const bool smooth_mask = data->smooth_mask;
+ float bstrength = data->strength;
+
+ PBVHVertexIter vd;
+
+ CLAMP(bstrength, 0.0f, 1.0f);
+
+ SculptBrushTest test;
+ SculptBrushTestFn sculpt_brush_test_sq_fn = SCULPT_brush_test_init_with_falloff_shape(
+ ss, &test, data->brush->falloff_shape);
+ const int thread_id = BLI_task_parallel_thread_id(tls);
+
+ BKE_pbvh_vertex_iter_begin(ss->pbvh, data->nodes[n], vd, PBVH_ITER_UNIQUE)
+ {
+ if (sculpt_brush_test_sq_fn(&test, vd.co)) {
+ const float fade = bstrength * SCULPT_brush_strength_factor(ss,
+ brush,
+ vd.co,
+ sqrtf(test.dist),
+ vd.no,
+ vd.fno,
+ smooth_mask ? 0.0f : *vd.mask,
+ vd.index,
+ thread_id);
+ if (smooth_mask) {
+ float val = SCULPT_neighbor_mask_average(ss, vd.index) - *vd.mask;
+ val *= fade * bstrength;
+ *vd.mask += val;
+ CLAMP(*vd.mask, 0.0f, 1.0f);
+ }
+ else {
+ float avg[3], val[3];
+
+ SCULPT_bmesh_neighbor_average(avg, vd.bm_vert);
+ sub_v3_v3v3(val, avg, vd.co);
+
+ madd_v3_v3v3fl(val, vd.co, val, fade);
+
+ SCULPT_clip(sd, ss, vd.co, val);
+ }
+
+ if (vd.mvert) {
+ vd.mvert->flag |= ME_VERT_PBVH_UPDATE;
+ }
+ }
+ }
+ BKE_pbvh_vertex_iter_end;
+}
+
+static void do_smooth_brush_multires_task_cb_ex(void *__restrict userdata,
+ const int n,
+ const TaskParallelTLS *__restrict tls)
+{
+ SculptThreadedTaskData *data = userdata;
+ SculptSession *ss = data->ob->sculpt;
+ Sculpt *sd = data->sd;
+ const Brush *brush = data->brush;
+ const bool smooth_mask = data->smooth_mask;
+ float bstrength = data->strength;
+
+ PBVHVertexIter vd;
+
+ CLAMP(bstrength, 0.0f, 1.0f);
+
+ SculptBrushTest test;
+ SculptBrushTestFn sculpt_brush_test_sq_fn = SCULPT_brush_test_init_with_falloff_shape(
+ ss, &test, data->brush->falloff_shape);
+
+ const int thread_id = BLI_task_parallel_thread_id(tls);
+
+ BKE_pbvh_vertex_iter_begin(ss->pbvh, data->nodes[n], vd, PBVH_ITER_UNIQUE)
+ {
+ if (sculpt_brush_test_sq_fn(&test, vd.co)) {
+ const float fade = bstrength * SCULPT_brush_strength_factor(
+ ss,
+ brush,
+ vd.co,
+ sqrtf(test.dist),
+ vd.no,
+ vd.fno,
+ smooth_mask ? 0.0f : (vd.mask ? *vd.mask : 0.0f),
+ vd.index,
+ thread_id);
+ if (smooth_mask) {
+ float val = SCULPT_neighbor_mask_average(ss, vd.index) - *vd.mask;
+ val *= fade * bstrength;
+ *vd.mask += val;
+ CLAMP(*vd.mask, 0.0f, 1.0f);
+ }
+ else {
+ float avg[3], val[3];
+ SCULPT_neighbor_coords_average(ss, avg, vd.index);
+ sub_v3_v3v3(val, avg, vd.co);
+ madd_v3_v3v3fl(val, vd.co, val, fade);
+ SCULPT_clip(sd, ss, vd.co, val);
+ }
+ }
+ }
+ BKE_pbvh_vertex_iter_end;
+}
+
+void SCULPT_smooth(Sculpt *sd,
+ Object *ob,
+ PBVHNode **nodes,
+ const int totnode,
+ float bstrength,
+ const bool smooth_mask)
+{
+ SculptSession *ss = ob->sculpt;
+ Brush *brush = BKE_paint_brush(&sd->paint);
+
+ const int max_iterations = 4;
+ const float fract = 1.0f / max_iterations;
+ PBVHType type = BKE_pbvh_type(ss->pbvh);
+ int iteration, count;
+ float last;
+
+ CLAMP(bstrength, 0.0f, 1.0f);
+
+ count = (int)(bstrength * max_iterations);
+ last = max_iterations * (bstrength - count * fract);
+
+ if (type == PBVH_FACES && !ss->pmap) {
+ BLI_assert(!"sculpt smooth: pmap missing");
+ return;
+ }
+
+ for (iteration = 0; iteration <= count; iteration++) {
+ const float strength = (iteration != count) ? 1.0f : last;
+
+ SculptThreadedTaskData data = {
+ .sd = sd,
+ .ob = ob,
+ .brush = brush,
+ .nodes = nodes,
+ .smooth_mask = smooth_mask,
+ .strength = strength,
+ };
+
+ TaskParallelSettings settings;
+ BKE_pbvh_parallel_range_settings(&settings, (sd->flags & SCULPT_USE_OPENMP), totnode);
+
+ switch (type) {
+ case PBVH_GRIDS:
+ BLI_task_parallel_range(0, totnode, &data, do_smooth_brush_multires_task_cb_ex, &settings);
+ break;
+ case PBVH_FACES:
+ BLI_task_parallel_range(0, totnode, &data, do_smooth_brush_mesh_task_cb_ex, &settings);
+ break;
+ case PBVH_BMESH:
+ BLI_task_parallel_range(0, totnode, &data, do_smooth_brush_bmesh_task_cb_ex, &settings);
+ break;
+ }
+ }
+}
+
+void SCULPT_do_smooth_brush(Sculpt *sd, Object *ob, PBVHNode **nodes, int totnode)
+{
+ SculptSession *ss = ob->sculpt;
+ SCULPT_smooth(sd, ob, nodes, totnode, ss->cache->bstrength, false);
+}
+
+/* HC Smooth Algorithm. */
+/* From: Improved Laplacian Smoothing of Noisy Surface Meshes */
+
+void SCULPT_surface_smooth_laplacian_step(SculptSession *ss,
+ float *disp,
+ const float co[3],
+ float (*laplacian_disp)[3],
+ const int v_index,
+ const float origco[3],
+ const float alpha)
+{
+ float laplacian_smooth_co[3];
+ float weigthed_o[3], weigthed_q[3], d[3];
+ SCULPT_neighbor_coords_average(ss, laplacian_smooth_co, v_index);
+
+ mul_v3_v3fl(weigthed_o, origco, alpha);
+ mul_v3_v3fl(weigthed_q, co, 1.0f - alpha);
+ add_v3_v3v3(d, weigthed_o, weigthed_q);
+ sub_v3_v3v3(laplacian_disp[v_index], laplacian_smooth_co, d);
+
+ sub_v3_v3v3(disp, laplacian_smooth_co, co);
+}
+
+void SCULPT_surface_smooth_displace_step(SculptSession *ss,
+ float *co,
+ float (*laplacian_disp)[3],
+ const int v_index,
+ const float beta,
+ const float fade)
+{
+ float b_avg[3] = {0.0f, 0.0f, 0.0f};
+ float b_current_vertex[3];
+ int total = 0;
+ SculptVertexNeighborIter ni;
+ SCULPT_VERTEX_NEIGHBORS_ITER_BEGIN (ss, v_index, ni) {
+ add_v3_v3(b_avg, laplacian_disp[ni.index]);
+ total++;
+ }
+ SCULPT_VERTEX_NEIGHBORS_ITER_END(ni);
+ if (total > 0) {
+ mul_v3_v3fl(b_current_vertex, b_avg, (1.0f - beta) / (float)total);
+ madd_v3_v3fl(b_current_vertex, laplacian_disp[v_index], beta);
+ mul_v3_fl(b_current_vertex, clamp_f(fade, 0.0f, 1.0f));
+ sub_v3_v3(co, b_current_vertex);
+ }
+}
+
+static void SCULPT_do_surface_smooth_brush_laplacian_task_cb_ex(
+ void *__restrict userdata, const int n, const TaskParallelTLS *__restrict tls)
+{
+ SculptThreadedTaskData *data = userdata;
+ SculptSession *ss = data->ob->sculpt;
+ const Brush *brush = data->brush;
+ const float bstrength = ss->cache->bstrength;
+ float alpha = brush->surface_smooth_shape_preservation;
+
+ PBVHVertexIter vd;
+ SculptOrigVertData orig_data;
+
+ SculptBrushTest test;
+ SculptBrushTestFn sculpt_brush_test_sq_fn = SCULPT_brush_test_init_with_falloff_shape(
+ ss, &test, data->brush->falloff_shape);
+ const int thread_id = BLI_task_parallel_thread_id(tls);
+
+ SCULPT_orig_vert_data_init(&orig_data, data->ob, data->nodes[n]);
+
+ BKE_pbvh_vertex_iter_begin(ss->pbvh, data->nodes[n], vd, PBVH_ITER_UNIQUE)
+ {
+ SCULPT_orig_vert_data_update(&orig_data, &vd);
+ if (sculpt_brush_test_sq_fn(&test, vd.co)) {
+ const float fade =
+ bstrength *
+ SCULPT_brush_strength_factor(
+ ss, brush, vd.co, sqrtf(test.dist), vd.no, vd.fno, 0.0f, vd.index, thread_id);
+
+ float disp[3];
+ SCULPT_surface_smooth_laplacian_step(ss,
+ disp,
+ vd.co,
+ ss->cache->surface_smooth_laplacian_disp,
+ vd.index,
+ orig_data.co,
+ alpha);
+ madd_v3_v3fl(vd.co, disp, clamp_f(fade, 0.0f, 1.0f));
+ if (vd.mvert) {
+ vd.mvert->flag |= ME_VERT_PBVH_UPDATE;
+ }
+ }
+ BKE_pbvh_vertex_iter_end;
+ }
+}
+
+static void SCULPT_do_surface_smooth_brush_displace_task_cb_ex(
+ void *__restrict userdata, const int n, const TaskParallelTLS *__restrict tls)
+{
+ SculptThreadedTaskData *data = userdata;
+ SculptSession *ss = data->ob->sculpt;
+ const Brush *brush = data->brush;
+ const float bstrength = ss->cache->bstrength;
+ const float beta = brush->surface_smooth_current_vertex;
+
+ PBVHVertexIter vd;
+
+ SculptBrushTest test;
+ SculptBrushTestFn sculpt_brush_test_sq_fn = SCULPT_brush_test_init_with_falloff_shape(
+ ss, &test, data->brush->falloff_shape);
+ const int thread_id = BLI_task_parallel_thread_id(tls);
+
+ BKE_pbvh_vertex_iter_begin(ss->pbvh, data->nodes[n], vd, PBVH_ITER_UNIQUE)
+ {
+ if (sculpt_brush_test_sq_fn(&test, vd.co)) {
+ const float fade =
+ bstrength *
+ SCULPT_brush_strength_factor(
+ ss, brush, vd.co, sqrtf(test.dist), vd.no, vd.fno, 0.0f, vd.index, thread_id);
+ SCULPT_surface_smooth_displace_step(
+ ss, vd.co, ss->cache->surface_smooth_laplacian_disp, vd.index, beta, fade);
+ }
+ }
+ BKE_pbvh_vertex_iter_end;
+}
+
+void SCULPT_do_surface_smooth_brush(Sculpt *sd, Object *ob, PBVHNode **nodes, int totnode)
+{
+ Brush *brush = BKE_paint_brush(&sd->paint);
+ SculptSession *ss = ob->sculpt;
+
+ if (ss->cache->first_time && ss->cache->mirror_symmetry_pass == 0 &&
+ ss->cache->radial_symmetry_pass == 0) {
+ BLI_assert(ss->cache->surface_smooth_laplacian_disp == NULL);
+ ss->cache->surface_smooth_laplacian_disp = MEM_callocN(
+ SCULPT_vertex_count_get(ss) * 3 * sizeof(float), "HC smooth laplacian b");
+ }
+
+ /* Threaded loop over nodes. */
+ SculptThreadedTaskData data = {
+ .sd = sd,
+ .ob = ob,
+ .brush = brush,
+ .nodes = nodes,
+ };
+
+ TaskParallelSettings settings;
+ BKE_pbvh_parallel_range_settings(&settings, (sd->flags & SCULPT_USE_OPENMP), totnode);
+ for (int i = 0; i < brush->surface_smooth_iterations; i++) {
+ BLI_task_parallel_range(
+ 0, totnode, &data, SCULPT_do_surface_smooth_brush_laplacian_task_cb_ex, &settings);
+ BLI_task_parallel_range(
+ 0, totnode, &data, SCULPT_do_surface_smooth_brush_displace_task_cb_ex, &settings);
+ }
+}
diff --git a/source/blender/editors/sculpt_paint/sculpt_transform.c b/source/blender/editors/sculpt_paint/sculpt_transform.c
new file mode 100644
index 00000000000..2eb1191b950
--- /dev/null
+++ b/source/blender/editors/sculpt_paint/sculpt_transform.c
@@ -0,0 +1,381 @@
+/*
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * The Original Code is Copyright (C) 2020 Blender Foundation.
+ * All rights reserved.
+ */
+
+/** \file
+ * \ingroup edsculpt
+ */
+
+#include "MEM_guardedalloc.h"
+
+#include "BLI_blenlib.h"
+#include "BLI_math.h"
+#include "BLI_task.h"
+
+#include "DNA_mesh_types.h"
+#include "DNA_meshdata_types.h"
+
+#include "BKE_brush.h"
+#include "BKE_context.h"
+#include "BKE_mesh.h"
+#include "BKE_mesh_mapping.h"
+#include "BKE_object.h"
+#include "BKE_paint.h"
+#include "BKE_pbvh.h"
+#include "BKE_scene.h"
+
+#include "DEG_depsgraph.h"
+
+#include "WM_api.h"
+#include "WM_message.h"
+#include "WM_toolsystem.h"
+#include "WM_types.h"
+
+#include "ED_object.h"
+#include "ED_screen.h"
+#include "ED_sculpt.h"
+#include "paint_intern.h"
+#include "sculpt_intern.h"
+
+#include "RNA_access.h"
+#include "RNA_define.h"
+
+#include "bmesh.h"
+
+#include <math.h>
+#include <stdlib.h>
+
+void ED_sculpt_init_transform(struct bContext *C)
+{
+ Sculpt *sd = CTX_data_tool_settings(C)->sculpt;
+ Object *ob = CTX_data_active_object(C);
+ SculptSession *ss = ob->sculpt;
+ Depsgraph *depsgraph = CTX_data_depsgraph_pointer(C);
+
+ copy_v3_v3(ss->init_pivot_pos, ss->pivot_pos);
+ copy_v4_v4(ss->init_pivot_rot, ss->pivot_rot);
+
+ SCULPT_undo_push_begin("Transform");
+ BKE_sculpt_update_object_for_edit(depsgraph, ob, false, false);
+
+ ss->pivot_rot[3] = 1.0f;
+
+ SCULPT_vertex_random_access_init(ss);
+ SCULPT_filter_cache_init(ob, sd);
+}
+
+static void sculpt_transform_task_cb(void *__restrict userdata,
+ const int i,
+ const TaskParallelTLS *__restrict UNUSED(tls))
+{
+
+ SculptThreadedTaskData *data = userdata;
+ SculptSession *ss = data->ob->sculpt;
+ PBVHNode *node = data->nodes[i];
+
+ SculptOrigVertData orig_data;
+ SCULPT_orig_vert_data_init(&orig_data, data->ob, data->nodes[i]);
+
+ PBVHVertexIter vd;
+
+ SCULPT_undo_push_node(data->ob, node, SCULPT_UNDO_COORDS);
+ BKE_pbvh_vertex_iter_begin(ss->pbvh, node, vd, PBVH_ITER_UNIQUE)
+ {
+ SCULPT_orig_vert_data_update(&orig_data, &vd);
+ float transformed_co[3], orig_co[3], disp[3];
+ float fade = vd.mask ? *vd.mask : 0.0f;
+ copy_v3_v3(orig_co, orig_data.co);
+ char symm_area = SCULPT_get_vertex_symm_area(orig_co);
+
+ copy_v3_v3(transformed_co, orig_co);
+ mul_m4_v3(data->transform_mats[(int)symm_area], transformed_co);
+ sub_v3_v3v3(disp, transformed_co, orig_co);
+ mul_v3_fl(disp, 1.0f - fade);
+
+ add_v3_v3v3(vd.co, orig_co, disp);
+
+ if (vd.mvert) {
+ vd.mvert->flag |= ME_VERT_PBVH_UPDATE;
+ }
+ }
+ BKE_pbvh_vertex_iter_end;
+
+ BKE_pbvh_node_mark_update(node);
+}
+
+void ED_sculpt_update_modal_transform(struct bContext *C)
+{
+ Sculpt *sd = CTX_data_tool_settings(C)->sculpt;
+ Object *ob = CTX_data_active_object(C);
+ SculptSession *ss = ob->sculpt;
+ Depsgraph *depsgraph = CTX_data_depsgraph_pointer(C);
+ const char symm = sd->paint.symmetry_flags & PAINT_SYMM_AXIS_ALL;
+
+ SCULPT_vertex_random_access_init(ss);
+ BKE_sculpt_update_object_for_edit(depsgraph, ob, false, false);
+
+ SculptThreadedTaskData data = {
+ .sd = sd,
+ .ob = ob,
+ .nodes = ss->filter_cache->nodes,
+ };
+
+ float final_pivot_pos[3], d_t[3], d_r[4];
+ float t_mat[4][4], r_mat[4][4], s_mat[4][4], pivot_mat[4][4], pivot_imat[4][4],
+ transform_mat[4][4];
+
+ copy_v3_v3(final_pivot_pos, ss->pivot_pos);
+ for (int i = 0; i < PAINT_SYMM_AREAS; i++) {
+ ePaintSymmetryAreas v_symm = i;
+
+ copy_v3_v3(final_pivot_pos, ss->pivot_pos);
+
+ unit_m4(pivot_mat);
+
+ unit_m4(t_mat);
+ unit_m4(r_mat);
+ unit_m4(s_mat);
+
+ /* Translation matrix. */
+ sub_v3_v3v3(d_t, ss->pivot_pos, ss->init_pivot_pos);
+ SCULPT_flip_v3_by_symm_area(d_t, symm, v_symm, ss->init_pivot_pos);
+ translate_m4(t_mat, d_t[0], d_t[1], d_t[2]);
+
+ /* Rotation matrix. */
+ sub_qt_qtqt(d_r, ss->pivot_rot, ss->init_pivot_rot);
+ normalize_qt(d_r);
+ SCULPT_flip_quat_by_symm_area(d_r, symm, v_symm, ss->init_pivot_pos);
+ quat_to_mat4(r_mat, d_r);
+
+ /* Scale matrix. */
+ size_to_mat4(s_mat, ss->pivot_scale);
+
+ /* Pivot matrix. */
+ SCULPT_flip_v3_by_symm_area(final_pivot_pos, symm, v_symm, ss->init_pivot_pos);
+ translate_m4(pivot_mat, final_pivot_pos[0], final_pivot_pos[1], final_pivot_pos[2]);
+ invert_m4_m4(pivot_imat, pivot_mat);
+
+ /* Final transform matrix. */
+ mul_m4_m4m4(transform_mat, r_mat, t_mat);
+ mul_m4_m4m4(transform_mat, transform_mat, s_mat);
+ mul_m4_m4m4(data.transform_mats[i], transform_mat, pivot_imat);
+ mul_m4_m4m4(data.transform_mats[i], pivot_mat, data.transform_mats[i]);
+ }
+
+ TaskParallelSettings settings;
+ BKE_pbvh_parallel_range_settings(
+ &settings, (sd->flags & SCULPT_USE_OPENMP), ss->filter_cache->totnode);
+ BLI_task_parallel_range(
+ 0, ss->filter_cache->totnode, &data, sculpt_transform_task_cb, &settings);
+
+ if (ss->deform_modifiers_active || ss->shapekey_active) {
+ SCULPT_flush_stroke_deform(sd, ob, true);
+ }
+
+ SCULPT_flush_update_step(C, SCULPT_UPDATE_COORDS);
+}
+
+void ED_sculpt_end_transform(struct bContext *C)
+{
+ Object *ob = CTX_data_active_object(C);
+ SculptSession *ss = ob->sculpt;
+ if (ss->filter_cache) {
+ SCULPT_filter_cache_free(ss);
+ }
+ /* Force undo push to happen even inside transform operator, since the sculpt
+ * undo system works separate from regular undo and this is require to properly
+ * finish an undo step also when cancelling. */
+ const bool use_nested_undo = true;
+ SCULPT_undo_push_end_ex(use_nested_undo);
+ SCULPT_flush_update_done(C, ob, SCULPT_UPDATE_COORDS);
+}
+
+typedef enum eSculptPivotPositionModes {
+ SCULPT_PIVOT_POSITION_ORIGIN = 0,
+ SCULPT_PIVOT_POSITION_UNMASKED = 1,
+ SCULPT_PIVOT_POSITION_MASK_BORDER = 2,
+ SCULPT_PIVOT_POSITION_ACTIVE_VERTEX = 3,
+ SCULPT_PIVOT_POSITION_CURSOR_SURFACE = 4,
+} eSculptPivotPositionModes;
+
+static EnumPropertyItem prop_sculpt_pivot_position_types[] = {
+ {SCULPT_PIVOT_POSITION_ORIGIN,
+ "ORIGIN",
+ 0,
+ "Origin",
+ "Sets the pivot to the origin of the sculpt"},
+ {SCULPT_PIVOT_POSITION_UNMASKED,
+ "UNMASKED",
+ 0,
+ "Unmasked",
+ "Sets the pivot position to the average position of the unmasked vertices"},
+ {SCULPT_PIVOT_POSITION_MASK_BORDER,
+ "BORDER",
+ 0,
+ "Mask border",
+ "Sets the pivot position to the center of the border of the mask"},
+ {SCULPT_PIVOT_POSITION_ACTIVE_VERTEX,
+ "ACTIVE",
+ 0,
+ "Active vertex",
+ "Sets the pivot position to the active vertex position"},
+ {SCULPT_PIVOT_POSITION_CURSOR_SURFACE,
+ "SURFACE",
+ 0,
+ "Surface",
+ "Sets the pivot position to the surface under the cursor"},
+ {0, NULL, 0, NULL, NULL},
+};
+
+static int sculpt_set_pivot_position_exec(bContext *C, wmOperator *op)
+{
+ Sculpt *sd = CTX_data_tool_settings(C)->sculpt;
+ Object *ob = CTX_data_active_object(C);
+ SculptSession *ss = ob->sculpt;
+ ARegion *region = CTX_wm_region(C);
+ Depsgraph *depsgraph = CTX_data_ensure_evaluated_depsgraph(C);
+ const char symm = sd->paint.symmetry_flags & PAINT_SYMM_AXIS_ALL;
+
+ int mode = RNA_enum_get(op->ptr, "mode");
+
+ BKE_sculpt_update_object_for_edit(depsgraph, ob, false, true);
+
+ /* Pivot to center. */
+ if (mode == SCULPT_PIVOT_POSITION_ORIGIN) {
+ zero_v3(ss->pivot_pos);
+ }
+ /* Pivot to active vertex. */
+ else if (mode == SCULPT_PIVOT_POSITION_ACTIVE_VERTEX) {
+ copy_v3_v3(ss->pivot_pos, SCULPT_active_vertex_co_get(ss));
+ }
+ /* Pivot to raycast surface. */
+ else if (mode == SCULPT_PIVOT_POSITION_CURSOR_SURFACE) {
+ float stroke_location[3];
+ float mouse[2];
+ mouse[0] = RNA_float_get(op->ptr, "mouse_x");
+ mouse[1] = RNA_float_get(op->ptr, "mouse_y");
+ if (SCULPT_stroke_get_location(C, stroke_location, mouse)) {
+ copy_v3_v3(ss->pivot_pos, stroke_location);
+ }
+ }
+ else {
+ PBVHNode **nodes;
+ int totnode;
+ BKE_pbvh_search_gather(ss->pbvh, NULL, NULL, &nodes, &totnode);
+
+ float avg[3];
+ int total = 0;
+ zero_v3(avg);
+
+ /* Pivot to unmasked. */
+ if (mode == SCULPT_PIVOT_POSITION_UNMASKED) {
+ for (int n = 0; n < totnode; n++) {
+ PBVHVertexIter vd;
+ BKE_pbvh_vertex_iter_begin(ss->pbvh, nodes[n], vd, PBVH_ITER_UNIQUE)
+ {
+ const float mask = (vd.mask) ? *vd.mask : 0.0f;
+ if (mask < 1.0f) {
+ if (SCULPT_check_vertex_pivot_symmetry(vd.co, ss->pivot_pos, symm)) {
+ add_v3_v3(avg, vd.co);
+ total++;
+ }
+ }
+ }
+ BKE_pbvh_vertex_iter_end;
+ }
+ }
+ /* Pivot to mask border. */
+ else if (mode == SCULPT_PIVOT_POSITION_MASK_BORDER) {
+ const float threshold = 0.2f;
+
+ for (int n = 0; n < totnode; n++) {
+ PBVHVertexIter vd;
+ BKE_pbvh_vertex_iter_begin(ss->pbvh, nodes[n], vd, PBVH_ITER_UNIQUE)
+ {
+ const float mask = (vd.mask) ? *vd.mask : 0.0f;
+ if (mask < (0.5f + threshold) && mask > (0.5f - threshold)) {
+ if (SCULPT_check_vertex_pivot_symmetry(vd.co, ss->pivot_pos, symm)) {
+ add_v3_v3(avg, vd.co);
+ total++;
+ }
+ }
+ }
+ BKE_pbvh_vertex_iter_end;
+ }
+ }
+
+ if (total > 0) {
+ mul_v3_fl(avg, 1.0f / total);
+ copy_v3_v3(ss->pivot_pos, avg);
+ }
+
+ MEM_SAFE_FREE(nodes);
+ }
+
+ ED_region_tag_redraw(region);
+ WM_event_add_notifier(C, NC_GEOM | ND_SELECT, ob->data);
+
+ return OPERATOR_FINISHED;
+}
+
+static int sculpt_set_pivot_position_invoke(bContext *C, wmOperator *op, const wmEvent *event)
+{
+ RNA_float_set(op->ptr, "mouse_x", event->mval[0]);
+ RNA_float_set(op->ptr, "mouse_y", event->mval[1]);
+ return sculpt_set_pivot_position_exec(C, op);
+}
+
+void SCULPT_OT_set_pivot_position(wmOperatorType *ot)
+{
+ /* Identifiers. */
+ ot->name = "Set Pivot Position";
+ ot->idname = "SCULPT_OT_set_pivot_position";
+ ot->description = "Sets the sculpt transform pivot position";
+
+ /* API callbacks. */
+ ot->invoke = sculpt_set_pivot_position_invoke;
+ ot->exec = sculpt_set_pivot_position_exec;
+ ot->poll = SCULPT_mode_poll;
+
+ ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
+ RNA_def_enum(ot->srna,
+ "mode",
+ prop_sculpt_pivot_position_types,
+ SCULPT_PIVOT_POSITION_UNMASKED,
+ "Mode",
+ "");
+
+ RNA_def_float(ot->srna,
+ "mouse_x",
+ 0.0f,
+ 0.0f,
+ FLT_MAX,
+ "Mouse Position X",
+ "Position of the mouse used for \"Surface\" mode",
+ 0.0f,
+ 10000.0f);
+ RNA_def_float(ot->srna,
+ "mouse_y",
+ 0.0f,
+ 0.0f,
+ FLT_MAX,
+ "Mouse Position Y",
+ "Position of the mouse used for \"Surface\" mode",
+ 0.0f,
+ 10000.0f);
+}
diff --git a/source/blender/editors/sculpt_paint/sculpt_undo.c b/source/blender/editors/sculpt_paint/sculpt_undo.c
index af404c64fb0..d21552efafe 100644
--- a/source/blender/editors/sculpt_paint/sculpt_undo.c
+++ b/source/blender/editors/sculpt_paint/sculpt_undo.c
@@ -10,7 +10,7 @@
* 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,
+ * 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) 2006 by Nicholas Bishop
@@ -48,12 +48,16 @@
#include "BKE_main.h"
#include "BKE_mesh.h"
#include "BKE_multires.h"
+#include "BKE_object.h"
#include "BKE_paint.h"
#include "BKE_scene.h"
#include "BKE_subdiv_ccg.h"
#include "BKE_subsurf.h"
#include "BKE_undo_system.h"
+// XXX: Ideally should be no direct call to such low level things.
+#include "BKE_subdiv_eval.h"
+
#include "DEG_depsgraph.h"
#include "WM_api.h"
@@ -66,6 +70,45 @@
#include "bmesh.h"
#include "sculpt_intern.h"
+/* Implementation of undo system for objects in sculpt mode.
+ *
+ * Each undo step in sculpt mode consists of list of nodes, each node contains:
+ * - Node type
+ * - Data for this type.
+ *
+ * Node type used for undo depends on specific operation and active sculpt mode
+ * ("regular" or dynamic topology).
+ *
+ * Regular sculpt brushes will use COORDS, HIDDEN or MASK nodes. These nodes are
+ * created for every BVH node which is affected by the brush. The undo push for
+ * the node happens BEFORE modifications. This makes the operation undo to work
+ * in the following way: for every node in the undo step swap happens between
+ * node in the undo stack and the corresponding value in the BVH. This is how
+ * redo is possible after undo.
+ *
+ * The COORDS, HIDDEN or MASK type of nodes contains arrays of the corresponding
+ * values.
+ *
+ * Operations like Symmetrize are using GEOMETRY type of nodes which pushes the
+ * entire state of the mesh to the undo stack. This node contains all CustomData
+ * layers.
+ *
+ * The tricky aspect of this undo node type is that it stores mesh before and
+ * after modification. This allows the undo system to both undo and redo the
+ * symmetrize operation within the pre-modified-push of other node type
+ * behavior, but it uses more memory that it seems it should be.
+ *
+ * The dynamic topology undo nodes are handled somewhat separately from all
+ * other ones and the idea there is to store log of operations: which vertices
+ * and faces have been added or removed.
+ *
+ * Begin of dynamic topology sculpting mode have own node type. It contains an
+ * entire copy of mesh since just enabling the dynamic topology mode already
+ * does modifications on it.
+ *
+ * End of dynamic topology and symmetrize in this mode are handled in a special
+ * manner as well. */
+
typedef struct UndoSculpt {
ListBase nodes;
@@ -335,8 +378,11 @@ static bool sculpt_undo_restore_face_sets(bContext *C, SculptUndoNode *unode)
{
ViewLayer *view_layer = CTX_data_view_layer(C);
Object *ob = OBACT(view_layer);
- SculptSession *ss = ob->sculpt;
- memcpy(ss->face_sets, unode->face_sets, ss->totpoly * sizeof(int));
+ Mesh *me = BKE_object_get_original_mesh(ob);
+ int *face_sets = CustomData_get_layer(&me->pdata, CD_SCULPT_FACE_SETS);
+ for (int i = 0; i < me->totpoly; i++) {
+ face_sets[i] = unode->face_sets[i];
+ }
return false;
}
@@ -369,9 +415,9 @@ static void sculpt_undo_bmesh_restore_generic(bContext *C,
BKE_pbvh_search_gather(ss->pbvh, NULL, NULL, &nodes, &totnode);
- PBVHParallelSettings settings;
+ TaskParallelSettings settings;
BKE_pbvh_parallel_range_settings(&settings, (sd->flags & SCULPT_USE_OPENMP), totnode);
- BKE_pbvh_parallel_range(
+ BLI_task_parallel_range(
0, totnode, nodes, sculpt_undo_bmesh_restore_generic_task_cb, &settings);
if (nodes) {
@@ -379,7 +425,7 @@ static void sculpt_undo_bmesh_restore_generic(bContext *C,
}
}
else {
- sculpt_pbvh_clear(ob);
+ SCULPT_pbvh_clear(ob);
}
}
@@ -389,7 +435,7 @@ static void sculpt_undo_bmesh_enable(Object *ob, SculptUndoNode *unode)
SculptSession *ss = ob->sculpt;
Mesh *me = ob->data;
- sculpt_pbvh_clear(ob);
+ SCULPT_pbvh_clear(ob);
/* Create empty BMesh and enable logging. */
ss->bm = BM_mesh_create(&bm_mesh_allocsize_default,
@@ -397,7 +443,7 @@ static void sculpt_undo_bmesh_enable(Object *ob, SculptUndoNode *unode)
.use_toolflags = false,
}));
BM_data_layer_add(ss->bm, &ss->bm->vdata, CD_PAINT_MASK);
- sculpt_dyntopo_node_layers_add(ss);
+ SCULPT_dyntopo_node_layers_add(ss);
me->flag |= ME_SCULPT_DYNAMIC_TOPOLOGY;
/* Restore the BMLog using saved entries. */
@@ -410,7 +456,7 @@ static void sculpt_undo_bmesh_restore_begin(bContext *C,
SculptSession *ss)
{
if (unode->applied) {
- sculpt_dynamic_topology_disable(C, unode);
+ SCULPT_dynamic_topology_disable(C, unode);
unode->applied = false;
}
else {
@@ -438,35 +484,89 @@ static void sculpt_undo_bmesh_restore_end(bContext *C,
}
else {
/* Disable dynamic topology sculpting. */
- sculpt_dynamic_topology_disable(C, NULL);
+ SCULPT_dynamic_topology_disable(C, NULL);
unode->applied = true;
}
}
-static void sculpt_undo_geometry_restore(SculptUndoNode *unode, Object *ob)
+static void sculpt_undo_geometry_store_data(SculptUndoNodeGeometry *geometry, Object *object)
{
- Mesh *me;
- sculpt_pbvh_clear(ob);
- me = ob->data;
- CustomData_free(&me->vdata, me->totvert);
- CustomData_free(&me->edata, me->totedge);
- CustomData_free(&me->fdata, me->totface);
- CustomData_free(&me->ldata, me->totloop);
- CustomData_free(&me->pdata, me->totpoly);
- me->totvert = unode->geom_totvert;
- me->totedge = unode->geom_totedge;
- me->totloop = unode->geom_totloop;
- me->totpoly = unode->geom_totpoly;
- me->totface = 0;
+ Mesh *mesh = object->data;
+
+ BLI_assert(!geometry->is_initialized);
+ geometry->is_initialized = true;
+
+ CustomData_copy(&mesh->vdata, &geometry->vdata, CD_MASK_MESH.vmask, CD_DUPLICATE, mesh->totvert);
+ CustomData_copy(&mesh->edata, &geometry->edata, CD_MASK_MESH.emask, CD_DUPLICATE, mesh->totedge);
+ CustomData_copy(&mesh->ldata, &geometry->ldata, CD_MASK_MESH.lmask, CD_DUPLICATE, mesh->totloop);
+ CustomData_copy(&mesh->pdata, &geometry->pdata, CD_MASK_MESH.pmask, CD_DUPLICATE, mesh->totpoly);
+
+ geometry->totvert = mesh->totvert;
+ geometry->totedge = mesh->totedge;
+ geometry->totloop = mesh->totloop;
+ geometry->totpoly = mesh->totpoly;
+}
+
+static void sculpt_undo_geometry_restore_data(SculptUndoNodeGeometry *geometry, Object *object)
+{
+ Mesh *mesh = object->data;
+
+ BLI_assert(geometry->is_initialized);
+
+ CustomData_free(&mesh->vdata, mesh->totvert);
+ CustomData_free(&mesh->edata, mesh->totedge);
+ CustomData_free(&mesh->fdata, mesh->totface);
+ CustomData_free(&mesh->ldata, mesh->totloop);
+ CustomData_free(&mesh->pdata, mesh->totpoly);
+
+ mesh->totvert = geometry->totvert;
+ mesh->totedge = geometry->totedge;
+ mesh->totloop = geometry->totloop;
+ mesh->totpoly = geometry->totpoly;
+ mesh->totface = 0;
+
CustomData_copy(
- &unode->geom_vdata, &me->vdata, CD_MASK_MESH.vmask, CD_DUPLICATE, unode->geom_totvert);
+ &geometry->vdata, &mesh->vdata, CD_MASK_MESH.vmask, CD_DUPLICATE, geometry->totvert);
CustomData_copy(
- &unode->geom_edata, &me->edata, CD_MASK_MESH.emask, CD_DUPLICATE, unode->geom_totedge);
+ &geometry->edata, &mesh->edata, CD_MASK_MESH.emask, CD_DUPLICATE, geometry->totedge);
CustomData_copy(
- &unode->geom_ldata, &me->ldata, CD_MASK_MESH.lmask, CD_DUPLICATE, unode->geom_totloop);
+ &geometry->ldata, &mesh->ldata, CD_MASK_MESH.lmask, CD_DUPLICATE, geometry->totloop);
CustomData_copy(
- &unode->geom_pdata, &me->pdata, CD_MASK_MESH.pmask, CD_DUPLICATE, unode->geom_totpoly);
- BKE_mesh_update_customdata_pointers(me, false);
+ &geometry->pdata, &mesh->pdata, CD_MASK_MESH.pmask, CD_DUPLICATE, geometry->totpoly);
+
+ BKE_mesh_update_customdata_pointers(mesh, false);
+}
+
+static void sculpt_undo_geometry_free_data(SculptUndoNodeGeometry *geometry)
+{
+ if (geometry->totvert) {
+ CustomData_free(&geometry->vdata, geometry->totvert);
+ }
+ if (geometry->totedge) {
+ CustomData_free(&geometry->edata, geometry->totedge);
+ }
+ if (geometry->totloop) {
+ CustomData_free(&geometry->ldata, geometry->totloop);
+ }
+ if (geometry->totpoly) {
+ CustomData_free(&geometry->pdata, geometry->totpoly);
+ }
+}
+
+static void sculpt_undo_geometry_restore(SculptUndoNode *unode, Object *object)
+{
+ if (unode->geometry_clear_pbvh) {
+ SCULPT_pbvh_clear(object);
+ }
+
+ if (unode->applied) {
+ sculpt_undo_geometry_restore_data(&unode->geometry_modified, object);
+ unode->applied = false;
+ }
+ else {
+ sculpt_undo_geometry_restore_data(&unode->geometry_original, object);
+ unode->applied = true;
+ }
}
/* Handle all dynamic-topology updates
@@ -527,22 +627,7 @@ static void sculpt_undo_restore_list(bContext *C, Depsgraph *depsgraph, ListBase
if (lb->first) {
unode = lb->first;
- if (unode->type == SCULPT_UNDO_GEOMETRY) {
- if (unode->applied) {
- sculpt_undo_geometry_restore(unode->next, ob);
- unode->next->applied = true;
- unode->applied = false;
- }
- else {
- sculpt_undo_geometry_restore(unode, ob);
- unode->next->applied = false;
- unode->applied = true;
- }
- BKE_sculpt_update_object_for_edit(depsgraph, ob, false, need_mask);
- return;
- }
- else if (unode->type == SCULPT_UNDO_FACE_SETS) {
-
+ if (unode->type == SCULPT_UNDO_FACE_SETS) {
sculpt_undo_restore_face_sets(C, unode);
rebuild = true;
@@ -551,14 +636,15 @@ static void sculpt_undo_restore_list(bContext *C, Depsgraph *depsgraph, ListBase
BKE_sculpt_update_object_for_edit(depsgraph, ob, true, need_mask);
SCULPT_visibility_sync_all_face_sets_to_vertices(ss);
+
BKE_pbvh_update_vertex_data(ss->pbvh, PBVH_UpdateVisibility);
if (BKE_pbvh_type(ss->pbvh) == PBVH_FACES) {
BKE_mesh_flush_hidden_from_verts(ob->data);
}
+ DEG_id_tag_update(&ob->id, ID_RECALC_SHADING);
if (!BKE_sculptsession_use_pbvh_draw(ob, v3d)) {
- DEG_id_tag_update(&ob->id, ID_RECALC_SHADING);
DEG_id_tag_update(&ob->id, ID_RECALC_GEOMETRY);
}
@@ -567,10 +653,18 @@ static void sculpt_undo_restore_list(bContext *C, Depsgraph *depsgraph, ListBase
}
}
- BKE_sculpt_update_object_for_edit(depsgraph, ob, false, need_mask);
+ if (lb->first != NULL) {
+ /* Only do early object update for edits if first node needs this.
+ * Undo steps like geometry does not need object to be updated before they run and will
+ * ensure object is updated after the node is handled. */
+ const SculptUndoNode *first_unode = (const SculptUndoNode *)lb->first;
+ if (first_unode->type != SCULPT_UNDO_GEOMETRY) {
+ BKE_sculpt_update_object_for_edit(depsgraph, ob, false, need_mask);
+ }
- if (lb->first && sculpt_undo_bmesh_restore(C, lb->first, ob, ss)) {
- return;
+ if (sculpt_undo_bmesh_restore(C, lb->first, ob, ss)) {
+ return;
+ }
}
char *undo_modified_grids = NULL;
@@ -619,28 +713,42 @@ static void sculpt_undo_restore_list(bContext *C, Depsgraph *depsgraph, ListBase
case SCULPT_UNDO_FACE_SETS:
break;
+ case SCULPT_UNDO_GEOMETRY:
+ sculpt_undo_geometry_restore(unode, ob);
+ BKE_sculpt_update_object_for_edit(depsgraph, ob, false, need_mask);
+ break;
+
case SCULPT_UNDO_DYNTOPO_BEGIN:
case SCULPT_UNDO_DYNTOPO_END:
case SCULPT_UNDO_DYNTOPO_SYMMETRIZE:
BLI_assert(!"Dynamic topology should've already been handled");
break;
- case SCULPT_UNDO_GEOMETRY:
- break;
}
}
if (use_multires_undo) {
- int max_grid;
- unode = lb->first;
- max_grid = unode->maxgrid;
- undo_modified_grids = MEM_callocN(sizeof(char) * max_grid, "undo_grids");
for (unode = lb->first; unode; unode = unode->next) {
+ if (!STREQ(unode->idname, ob->id.name)) {
+ continue;
+ }
+ if (unode->maxgrid == 0) {
+ continue;
+ }
+
+ if (undo_modified_grids == NULL) {
+ undo_modified_grids = MEM_callocN(sizeof(char) * unode->maxgrid, "undo_grids");
+ }
+
for (int i = 0; i < unode->totgrid; i++) {
undo_modified_grids[unode->grids[i]] = 1;
}
}
}
+ if (subdiv_ccg != NULL) {
+ BKE_subdiv_eval_refine_from_mesh(subdiv_ccg->subdiv, ob->data, NULL);
+ }
+
if (update || rebuild) {
bool tag_update = false;
/* We update all nodes still, should be more clever, but also
@@ -737,18 +845,9 @@ static void sculpt_undo_free_list(ListBase *lb)
BM_log_entry_drop(unode->bm_entry);
}
- if (unode->geom_totvert) {
- CustomData_free(&unode->geom_vdata, unode->geom_totvert);
- }
- if (unode->geom_totedge) {
- CustomData_free(&unode->geom_edata, unode->geom_totedge);
- }
- if (unode->geom_totloop) {
- CustomData_free(&unode->geom_ldata, unode->geom_totloop);
- }
- if (unode->geom_totpoly) {
- CustomData_free(&unode->geom_pdata, unode->geom_totpoly);
- }
+ sculpt_undo_geometry_free_data(&unode->geometry_original);
+ sculpt_undo_geometry_free_data(&unode->geometry_modified);
+ sculpt_undo_geometry_free_data(&unode->geometry_bmesh_enter);
if (unode->face_sets) {
MEM_freeN(unode->face_sets);
@@ -794,6 +893,17 @@ SculptUndoNode *SCULPT_undo_get_node(PBVHNode *node)
return BLI_findptr(&usculpt->nodes, node, offsetof(SculptUndoNode, node));
}
+SculptUndoNode *SCULPT_undo_get_first_node()
+{
+ UndoSculpt *usculpt = sculpt_undo_get_nodes();
+
+ if (usculpt == NULL) {
+ return NULL;
+ }
+
+ return usculpt->nodes.first;
+}
+
static void sculpt_undo_alloc_and_store_hidden(PBVH *pbvh, SculptUndoNode *unode)
{
PBVHNode *node = unode->node;
@@ -804,7 +914,7 @@ static void sculpt_undo_alloc_and_store_hidden(PBVH *pbvh, SculptUndoNode *unode
BKE_pbvh_node_get_grids(pbvh, node, &grid_indices, &totgrid, NULL, NULL, NULL);
- unode->grid_hidden = MEM_mapallocN(sizeof(*unode->grid_hidden) * totgrid, "unode->grid_hidden");
+ unode->grid_hidden = MEM_callocN(sizeof(*unode->grid_hidden) * totgrid, "unode->grid_hidden");
for (i = 0; i < totgrid; i++) {
if (grid_hidden[grid_indices[i]]) {
@@ -816,16 +926,43 @@ static void sculpt_undo_alloc_and_store_hidden(PBVH *pbvh, SculptUndoNode *unode
}
}
+/* Allocate node and initialize its default fields specific for the given undo type.
+ * Will also add the node to the list in the undo step. */
+static SculptUndoNode *sculpt_undo_alloc_node_type(Object *object, SculptUndoType type)
+{
+ SculptUndoNode *unode = MEM_callocN(sizeof(SculptUndoNode), "SculptUndoNode");
+ BLI_strncpy(unode->idname, object->id.name, sizeof(unode->idname));
+ unode->type = type;
+
+ UndoSculpt *usculpt = sculpt_undo_get_nodes();
+ BLI_addtail(&usculpt->nodes, unode);
+
+ return unode;
+}
+
+/* Will return first existing undo node of the given type.
+ * If such node does not exist will allocate node of this type, register it in the undo step and
+ * return it. */
+static SculptUndoNode *sculpt_undo_find_or_alloc_node_type(Object *object, SculptUndoType type)
+{
+ UndoSculpt *usculpt = sculpt_undo_get_nodes();
+
+ LISTBASE_FOREACH (SculptUndoNode *, unode, &usculpt->nodes) {
+ if (unode->type == type) {
+ return unode;
+ }
+ }
+
+ return sculpt_undo_alloc_node_type(object, type);
+}
+
static SculptUndoNode *sculpt_undo_alloc_node(Object *ob, PBVHNode *node, SculptUndoType type)
{
UndoSculpt *usculpt = sculpt_undo_get_nodes();
- SculptUndoNode *unode;
SculptSession *ss = ob->sculpt;
int totvert, allvert, totgrid, maxgrid, gridsize, *grids;
- unode = MEM_callocN(sizeof(SculptUndoNode), "SculptUndoNode");
- BLI_strncpy(unode->idname, ob->id.name, sizeof(unode->idname));
- unode->type = type;
+ SculptUndoNode *unode = sculpt_undo_alloc_node_type(ob, type);
unode->node = node;
if (node) {
@@ -838,13 +975,11 @@ static SculptUndoNode *sculpt_undo_alloc_node(Object *ob, PBVHNode *node, Sculpt
maxgrid = 0;
}
- /* We will use this while sculpting, is mapalloc slow to access then? */
-
/* General TODO, fix count_alloc. */
switch (type) {
case SCULPT_UNDO_COORDS:
- unode->co = MEM_mapallocN(sizeof(float[3]) * allvert, "SculptUndoNode.co");
- unode->no = MEM_mapallocN(sizeof(short[3]) * allvert, "SculptUndoNode.no");
+ unode->co = MEM_callocN(sizeof(float[3]) * allvert, "SculptUndoNode.co");
+ unode->no = MEM_callocN(sizeof(short[3]) * allvert, "SculptUndoNode.no");
usculpt->undo_size = (sizeof(float[3]) + sizeof(short[3]) + sizeof(int)) * allvert;
break;
@@ -858,7 +993,7 @@ static SculptUndoNode *sculpt_undo_alloc_node(Object *ob, PBVHNode *node, Sculpt
break;
case SCULPT_UNDO_MASK:
- unode->mask = MEM_mapallocN(sizeof(float) * allvert, "SculptUndoNode.mask");
+ unode->mask = MEM_callocN(sizeof(float) * allvert, "SculptUndoNode.mask");
usculpt->undo_size += (sizeof(float) * sizeof(int)) * allvert;
@@ -872,19 +1007,17 @@ static SculptUndoNode *sculpt_undo_alloc_node(Object *ob, PBVHNode *node, Sculpt
break;
}
- BLI_addtail(&usculpt->nodes, unode);
-
if (maxgrid) {
/* Multires. */
unode->maxgrid = maxgrid;
unode->totgrid = totgrid;
unode->gridsize = gridsize;
- unode->grids = MEM_mapallocN(sizeof(int) * totgrid, "SculptUndoNode.grids");
+ unode->grids = MEM_callocN(sizeof(int) * totgrid, "SculptUndoNode.grids");
}
else {
/* Regular mesh. */
unode->maxvert = ss->totvert;
- unode->index = MEM_mapallocN(sizeof(int) * allvert, "SculptUndoNode.index");
+ unode->index = MEM_callocN(sizeof(int) * allvert, "SculptUndoNode.index");
}
if (ss->deform_modifiers_active) {
@@ -950,32 +1083,25 @@ static void sculpt_undo_store_mask(Object *ob, SculptUndoNode *unode)
BKE_pbvh_vertex_iter_end;
}
-static SculptUndoNode *sculpt_undo_geometry_push(Object *ob, SculptUndoType type)
+static SculptUndoNodeGeometry *sculpt_undo_geometry_get(SculptUndoNode *unode)
{
- UndoSculpt *usculpt = sculpt_undo_get_nodes();
- Mesh *me = ob->data;
- bool applied;
-
- SculptUndoNode *unode = usculpt->nodes.first;
- /* Store the original mesh in the first node, modifications in the second. */
- applied = unode != NULL;
+ if (!unode->geometry_original.is_initialized) {
+ return &unode->geometry_original;
+ }
- unode = MEM_callocN(sizeof(*unode), __func__);
+ BLI_assert(!unode->geometry_modified.is_initialized);
- BLI_strncpy(unode->idname, ob->id.name, sizeof(unode->idname));
- unode->type = type;
- unode->applied = applied;
+ return &unode->geometry_modified;
+}
- CustomData_copy(&me->vdata, &unode->geom_vdata, CD_MASK_MESH.vmask, CD_DUPLICATE, me->totvert);
- CustomData_copy(&me->edata, &unode->geom_edata, CD_MASK_MESH.emask, CD_DUPLICATE, me->totedge);
- CustomData_copy(&me->ldata, &unode->geom_ldata, CD_MASK_MESH.lmask, CD_DUPLICATE, me->totloop);
- CustomData_copy(&me->pdata, &unode->geom_pdata, CD_MASK_MESH.pmask, CD_DUPLICATE, me->totpoly);
- unode->geom_totvert = me->totvert;
- unode->geom_totedge = me->totedge;
- unode->geom_totloop = me->totloop;
- unode->geom_totpoly = me->totpoly;
+static SculptUndoNode *sculpt_undo_geometry_push(Object *object, SculptUndoType type)
+{
+ SculptUndoNode *unode = sculpt_undo_find_or_alloc_node_type(object, type);
+ unode->applied = false;
+ unode->geometry_clear_pbvh = true;
- BLI_addtail(&usculpt->nodes, unode);
+ SculptUndoNodeGeometry *geometry = sculpt_undo_geometry_get(unode);
+ sculpt_undo_geometry_store_data(geometry, object);
return unode;
}
@@ -983,8 +1109,6 @@ static SculptUndoNode *sculpt_undo_geometry_push(Object *ob, SculptUndoType type
static SculptUndoNode *sculpt_undo_face_sets_push(Object *ob, SculptUndoType type)
{
UndoSculpt *usculpt = sculpt_undo_get_nodes();
- SculptSession *ss = ob->sculpt;
-
SculptUndoNode *unode = usculpt->nodes.first;
unode = MEM_callocN(sizeof(*unode), __func__);
@@ -993,8 +1117,14 @@ static SculptUndoNode *sculpt_undo_face_sets_push(Object *ob, SculptUndoType typ
unode->type = type;
unode->applied = true;
- unode->face_sets = MEM_callocN(ss->totpoly * sizeof(int), "sculpt face sets");
- memcpy(unode->face_sets, ss->face_sets, ss->totpoly * sizeof(int));
+ Mesh *me = BKE_object_get_original_mesh(ob);
+
+ unode->face_sets = MEM_callocN(me->totpoly * sizeof(int), "sculpt face sets");
+
+ int *face_sets = CustomData_get_layer(&me->pdata, CD_SCULPT_FACE_SETS);
+ for (int i = 0; i < me->totpoly; i++) {
+ unode->face_sets[i] = face_sets[i];
+ }
BLI_addtail(&usculpt->nodes, unode);
@@ -1021,25 +1151,13 @@ static SculptUndoNode *sculpt_undo_bmesh_push(Object *ob, PBVHNode *node, Sculpt
BM_log_before_all_removed(ss->bm, ss->bm_log);
}
else if (type == SCULPT_UNDO_DYNTOPO_BEGIN) {
- Mesh *me = ob->data;
-
/* Store a copy of the mesh's current vertices, loops, and
* polys. A full copy like this is needed because entering
* dynamic-topology immediately does topological edits
* (converting polys to triangles) that the BMLog can't
* fully restore from. */
- CustomData_copy(
- &me->vdata, &unode->geom_vdata, CD_MASK_MESH.vmask, CD_DUPLICATE, me->totvert);
- CustomData_copy(
- &me->edata, &unode->geom_edata, CD_MASK_MESH.emask, CD_DUPLICATE, me->totedge);
- CustomData_copy(
- &me->ldata, &unode->geom_ldata, CD_MASK_MESH.lmask, CD_DUPLICATE, me->totloop);
- CustomData_copy(
- &me->pdata, &unode->geom_pdata, CD_MASK_MESH.pmask, CD_DUPLICATE, me->totpoly);
- unode->geom_totvert = me->totvert;
- unode->geom_totedge = me->totedge;
- unode->geom_totloop = me->totloop;
- unode->geom_totpoly = me->totpoly;
+ SculptUndoNodeGeometry *geometry = &unode->geometry_bmesh_enter;
+ sculpt_undo_geometry_store_data(geometry, ob);
unode->bm_entry = BM_log_entry_add(ss->bm_log);
BM_log_all_added(ss->bm, ss->bm_log);
@@ -1192,6 +1310,11 @@ void SCULPT_undo_push_begin(const char *name)
void SCULPT_undo_push_end(void)
{
+ SCULPT_undo_push_end_ex(false);
+}
+
+void SCULPT_undo_push_end_ex(const bool use_nested_undo)
+{
UndoSculpt *usculpt = sculpt_undo_get_nodes();
SculptUndoNode *unode;
@@ -1201,17 +1324,16 @@ void SCULPT_undo_push_end(void)
MEM_freeN(unode->no);
unode->no = NULL;
}
-
- if (unode->node) {
- BKE_pbvh_node_layer_disp_free(unode->node);
- }
}
/* We could remove this and enforce all callers run in an operator using 'OPTYPE_UNDO'. */
wmWindowManager *wm = G_MAIN->wm.first;
- if (wm->op_undo_depth == 0) {
+ if (wm->op_undo_depth == 0 || use_nested_undo) {
UndoStack *ustack = ED_undo_stack_get();
BKE_undosys_step_push(ustack, NULL, NULL);
+ if (wm->op_undo_depth == 0) {
+ BKE_undosys_stack_limit_steps_and_memory_defaults(ustack);
+ }
WM_file_tag_modified();
}
}
@@ -1407,3 +1529,96 @@ static UndoSculpt *sculpt_undo_get_nodes(void)
}
/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Undo for changes happening on a base mesh for multires sculpting.
+ *
+ * Use this for multires operators which changes base mesh and which are to be
+ * possible. Example of such operators is Apply Base.
+ *
+ * Usage:
+ *
+ * static int operator_exec((bContext *C, wmOperator *op) {
+ *
+ * ED_sculpt_undo_push_mixed_begin(C, op->type->name);
+ * // Modify base mesh.
+ * ED_sculpt_undo_push_mixed_end(C, op->type->name);
+ *
+ * return OPERATOR_FINISHED;
+ * }
+ *
+ * If object is not in sculpt mode or sculpt does not happen on multires then
+ * regular ED_undo_push() is used.
+ * *
+ * \{ */
+
+static bool sculpt_undo_use_multires_mesh(bContext *C)
+{
+ if (BKE_paintmode_get_active_from_context(C) != PAINT_MODE_SCULPT) {
+ return false;
+ }
+
+ Object *object = CTX_data_active_object(C);
+ SculptSession *sculpt_session = object->sculpt;
+
+ return sculpt_session->multires.active;
+}
+
+static void sculpt_undo_push_all_grids(Object *object)
+{
+ SculptSession *ss = object->sculpt;
+
+ /* It is possible that undo push is done from an object state where there is no PBVH. This
+ * happens, for example, when an operation which tagged for geometry update was performed prior
+ * to the current operation without making any stroke in between.
+ *
+ * Skip pushing nodes based on the following logic: on redo SCULPT_UNDO_COORDS will ensure
+ * PBVH for the new base geometry, which will have same coordinates as if we create PBVH here. */
+ if (ss->pbvh == NULL) {
+ return;
+ }
+
+ PBVHNode **nodes;
+ int totnodes;
+
+ BKE_pbvh_search_gather(ss->pbvh, NULL, NULL, &nodes, &totnodes);
+ for (int i = 0; i < totnodes; i++) {
+ SculptUndoNode *unode = SCULPT_undo_push_node(object, nodes[i], SCULPT_UNDO_COORDS);
+ unode->node = NULL;
+ }
+
+ MEM_SAFE_FREE(nodes);
+}
+
+void ED_sculpt_undo_push_multires_mesh_begin(bContext *C, const char *str)
+{
+ if (!sculpt_undo_use_multires_mesh(C)) {
+ return;
+ }
+
+ Object *object = CTX_data_active_object(C);
+
+ SCULPT_undo_push_begin(str);
+
+ SculptUndoNode *geometry_unode = SCULPT_undo_push_node(object, NULL, SCULPT_UNDO_GEOMETRY);
+ geometry_unode->geometry_clear_pbvh = false;
+
+ sculpt_undo_push_all_grids(object);
+}
+
+void ED_sculpt_undo_push_multires_mesh_end(bContext *C, const char *str)
+{
+ if (!sculpt_undo_use_multires_mesh(C)) {
+ ED_undo_push(C, str);
+ return;
+ }
+
+ Object *object = CTX_data_active_object(C);
+
+ SculptUndoNode *geometry_unode = SCULPT_undo_push_node(object, NULL, SCULPT_UNDO_GEOMETRY);
+ geometry_unode->geometry_clear_pbvh = false;
+
+ SCULPT_undo_push_end();
+}
+
+/** \} */
diff --git a/source/blender/editors/sculpt_paint/sculpt_uv.c b/source/blender/editors/sculpt_paint/sculpt_uv.c
index f364c174f0f..d6b259c9ac0 100644
--- a/source/blender/editors/sculpt_paint/sculpt_uv.c
+++ b/source/blender/editors/sculpt_paint/sculpt_uv.c
@@ -10,7 +10,7 @@
* 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,
+ * 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) Blender Foundation, 2002-2009
@@ -70,8 +70,8 @@ typedef struct UvAdjacencyElement {
} UvAdjacencyElement;
typedef struct UvEdge {
- unsigned int uv1;
- unsigned int uv2;
+ uint uv1;
+ uint uv2;
/* general use flag
* (Used to check if edge is boundary here, and propagates to adjacency elements) */
char flag;
@@ -315,7 +315,7 @@ static void uv_sculpt_stroke_apply(bContext *C,
Scene *scene = CTX_data_scene(C);
ARegion *region = CTX_wm_region(C);
BMEditMesh *em = BKE_editmesh_from_object(obedit);
- unsigned int tool;
+ uint tool;
UvSculptData *sculptdata = (UvSculptData *)op->customdata;
SpaceImage *sima;
int invert;
@@ -386,7 +386,7 @@ static void uv_sculpt_stroke_apply(bContext *C,
* Smooth Tool
*/
else if (tool == UV_SCULPT_TOOL_RELAX) {
- unsigned int method = toolsettings->uv_relax_method;
+ uint method = toolsettings->uv_relax_method;
if (method == UV_SCULPT_TOOL_RELAX_HC) {
HC_relaxation_iteration_uv(em, sculptdata, co, alpha, radius, aspectRatio);
}
@@ -464,7 +464,7 @@ static int uv_element_offset_from_face_get(
return element - map->buf;
}
-static unsigned int uv_edge_hash(const void *key)
+static uint uv_edge_hash(const void *key)
{
const UvEdge *edge = key;
return (BLI_ghashutil_uinthash(edge->uv2) + BLI_ghashutil_uinthash(edge->uv1));
@@ -548,8 +548,7 @@ static UvSculptData *uv_sculpt_stroke_init(bContext *C, wmOperator *op, const wm
if (do_island_optimization) {
UvElement *element;
UvNearestHit hit = UV_NEAREST_HIT_INIT;
- Image *ima = CTX_data_edit_image(C);
- uv_find_nearest_vert(scene, ima, obedit, co, 0.0f, &hit);
+ uv_find_nearest_vert(scene, obedit, co, 0.0f, &hit);
element = BM_uv_element_get(data->elementMap, hit.efa, hit.l);
island_index = element->island;
diff --git a/source/blender/editors/sound/sound_ops.c b/source/blender/editors/sound/sound_ops.c
index e6e36309fec..81ac8a16d8a 100644
--- a/source/blender/editors/sound/sound_ops.c
+++ b/source/blender/editors/sound/sound_ops.c
@@ -206,7 +206,7 @@ static void SOUND_OT_open_mono(wmOperatorType *ot)
static void sound_update_animation_flags(Scene *scene);
-static int sound_update_animation_flags_cb(Sequence *seq, void *user_data)
+static int sound_update_animation_flags_fn(Sequence *seq, void *user_data)
{
struct FCurve *fcu;
Scene *scene = (Scene *)user_data;
@@ -258,7 +258,7 @@ static void sound_update_animation_flags(Scene *scene)
scene->id.tag |= LIB_TAG_DOIT;
SEQ_BEGIN (scene->ed, seq) {
- BKE_sequencer_recursive_apply(seq, sound_update_animation_flags_cb, scene);
+ BKE_sequencer_recursive_apply(seq, sound_update_animation_flags_fn, scene);
}
SEQ_END;
diff --git a/source/blender/editors/space_action/action_data.c b/source/blender/editors/space_action/action_data.c
index 6c2cee4042b..b5a0c4a9e22 100644
--- a/source/blender/editors/space_action/action_data.c
+++ b/source/blender/editors/space_action/action_data.c
@@ -42,7 +42,6 @@
#include "RNA_enum_types.h"
#include "BKE_action.h"
-#include "BKE_animsys.h"
#include "BKE_context.h"
#include "BKE_fcurve.h"
#include "BKE_key.h"
@@ -100,7 +99,7 @@ AnimData *ED_actedit_animdata_from_context(bContext *C)
/* Create new action */
static bAction *action_create_new(bContext *C, bAction *oldact)
{
- ScrArea *sa = CTX_wm_area(C);
+ ScrArea *area = CTX_wm_area(C);
bAction *action;
/* create action - the way to do this depends on whether we've got an
@@ -124,8 +123,8 @@ static bAction *action_create_new(bContext *C, bAction *oldact)
id_us_min(&action->id);
/* set ID-Root type */
- if (sa->spacetype == SPACE_ACTION) {
- SpaceAction *saction = (SpaceAction *)sa->spacedata.first;
+ if (area->spacetype == SPACE_ACTION) {
+ SpaceAction *saction = (SpaceAction *)area->spacedata.first;
if (saction->mode == SACTCONT_SHAPEKEY) {
action->idroot = ID_KE;
@@ -165,13 +164,13 @@ static void actedit_change_action(bContext *C, bAction *act)
* 1) There must be an dopesheet/action editor, and it must be in a mode which uses actions...
* OR
* The NLA Editor is active (i.e. Animation Data panel -> new action)
- * 2) The associated AnimData block must not be in tweakmode
+ * 2) The associated AnimData block must not be in tweak-mode.
*/
static bool action_new_poll(bContext *C)
{
Scene *scene = CTX_data_scene(C);
- /* Check tweakmode is off (as you don't want to be tampering with the action in that case) */
+ /* Check tweak-mode is off (as you don't want to be tampering with the action in that case) */
/* NOTE: unlike for pushdown,
* this operator needs to be run when creating an action from nothing... */
if (ED_operator_action_active(C)) {
@@ -301,7 +300,7 @@ void ACTION_OT_new(wmOperatorType *ot)
/* Criteria:
* 1) There must be an dopesheet/action editor, and it must be in a mode which uses actions
* 2) There must be an action active
- * 3) The associated AnimData block must not be in tweakmode
+ * 3) The associated AnimData block must not be in tweak-mode
*/
static bool action_pushdown_poll(bContext *C)
{
@@ -309,7 +308,7 @@ static bool action_pushdown_poll(bContext *C)
SpaceAction *saction = (SpaceAction *)CTX_wm_space_data(C);
AnimData *adt = ED_actedit_animdata_from_context(C);
- /* Check for AnimData, Actions, and that tweakmode is off */
+ /* Check for AnimData, Actions, and that tweak-mode is off. */
if (adt && saction->action) {
/* NOTE: We check this for the AnimData block in question and not the global flag,
* as the global flag may be left dirty by some of the browsing ops here.
@@ -331,9 +330,8 @@ static int action_pushdown_exec(bContext *C, wmOperator *op)
/* Do the deed... */
if (adt) {
- /* Perform the pushdown operation
- * - This will deal with all the AnimData-side usercounts
- */
+ /* Perform the push-down operation
+ * - This will deal with all the AnimData-side user-counts. */
if (action_has_motion(adt->action) == 0) {
/* action may not be suitable... */
BKE_report(op->reports, RPT_WARNING, "Action must have at least one keyframe or F-Modifier");
@@ -390,7 +388,7 @@ static int action_stash_exec(bContext *C, wmOperator *op)
if (BKE_nla_action_stash(adt)) {
/* The stash operation will remove the user already,
* so the flushing step later shouldn't double up
- * the usercount fixes. Hence, we must unset this ref
+ * the user-count fixes. Hence, we must unset this ref
* first before setting the new action.
*/
saction->action = NULL;
@@ -436,14 +434,14 @@ void ACTION_OT_stash(wmOperatorType *ot)
/* Criteria:
* 1) There must be an dopesheet/action editor, and it must be in a mode which uses actions
- * 2) The associated AnimData block must not be in tweakmode
+ * 2) The associated AnimData block must not be in tweak-mode
*/
static bool action_stash_create_poll(bContext *C)
{
if (ED_operator_action_active(C)) {
AnimData *adt = ED_actedit_animdata_from_context(C);
- /* Check tweakmode is off (as you don't want to be tampering with the action in that case) */
+ /* Check tweak-mode is off (as you don't want to be tampering with the action in that case) */
/* NOTE: unlike for pushdown,
* this operator needs to be run when creating an action from nothing... */
if (adt) {
@@ -499,7 +497,7 @@ static int action_stash_create_exec(bContext *C, wmOperator *op)
/* The stash operation will remove the user already,
* so the flushing step later shouldn't double up
- * the usercount fixes. Hence, we must unset this ref
+ * the user-count fixes. Hence, we must unset this ref
* first before setting the new action.
*/
saction->action = NULL;
@@ -550,7 +548,7 @@ void ACTION_OT_stash_and_create(wmOperatorType *ot)
void ED_animedit_unlink_action(
bContext *C, ID *id, AnimData *adt, bAction *act, ReportList *reports, bool force_delete)
{
- ScrArea *sa = CTX_wm_area(C);
+ ScrArea *area = CTX_wm_area(C);
/* If the old action only has a single user (that it's about to lose),
* warn user about it
@@ -609,13 +607,13 @@ void ED_animedit_unlink_action(
BKE_nla_tweakmode_exit(adt);
/* Flush this to the Action Editor (if that's where this change was initiated) */
- if (sa->spacetype == SPACE_ACTION) {
+ if (area->spacetype == SPACE_ACTION) {
actedit_change_action(C, NULL);
}
}
else {
/* Unlink normally - Setting it to NULL should be enough to get the old one unlinked */
- if (sa->spacetype == SPACE_ACTION) {
+ if (area->spacetype == SPACE_ACTION) {
/* clear action editor -> action */
actedit_change_action(C, NULL);
}
@@ -729,8 +727,8 @@ static NlaStrip *action_layer_get_nlastrip(ListBase *strips, float ctime)
static void action_layer_switch_strip(
AnimData *adt, NlaTrack *old_track, NlaStrip *old_strip, NlaTrack *nlt, NlaStrip *strip)
{
- /* Exit tweakmode on old strip
- * NOTE: We need to manually clear this stuff ourselves, as tweakmode exit doesn't do it
+ /* Exit tweak-mode on old strip
+ * NOTE: We need to manually clear this stuff ourselves, as tweak-mode exit doesn't do it
*/
BKE_nla_tweakmode_exit(adt);
@@ -762,11 +760,11 @@ static void action_layer_switch_strip(
adt->flag |= ADT_NLA_SOLO_TRACK;
nlt->flag |= NLATRACK_SOLO;
- // TODO: Needs restpose flushing (when we get reference track)
+ // TODO: Needs rest-pose flushing (when we get reference track)
}
}
- /* Enter tweakmode again - hopefully we're now "it" */
+ /* Enter tweak-mode again - hopefully we're now "it" */
BKE_nla_tweakmode_enter(adt);
BLI_assert(adt->actstrip == strip);
}
@@ -779,7 +777,7 @@ static bool action_layer_next_poll(bContext *C)
if (ED_operator_action_active(C)) {
AnimData *adt = ED_actedit_animdata_from_context(C);
if (adt) {
- /* only allow if we're in tweakmode, and there's something above us... */
+ /* only allow if we're in tweak-mode, and there's something above us... */
if (adt->flag & ADT_NLA_EDIT_ON) {
/* We need to check if there are any tracks above the active one
* since the track the action comes from is not stored in AnimData
@@ -841,7 +839,7 @@ static int action_layer_next_exec(bContext *C, wmOperator *op)
}
else {
/* No more actions (strips) - Go back to editing the original active action
- * NOTE: This will mean exiting tweakmode...
+ * NOTE: This will mean exiting tweak-mode...
*/
BKE_nla_tweakmode_exit(adt);
@@ -856,13 +854,12 @@ static int action_layer_next_exec(bContext *C, wmOperator *op)
/* turn on NLA muting (to keep same effect) */
adt->flag |= ADT_NLA_EVAL_OFF;
- // TODO: Needs restpose flushing (when we get reference track)
+ // TODO: Needs rest-pose flushing (when we get reference track)
}
}
/* Update the action that this editor now uses
- * NOTE: The calls above have already handled the usercount/animdata side of things
- */
+ * NOTE: The calls above have already handled the user-count/anim-data side of things. */
actedit_change_action(C, adt->action);
return OPERATOR_FINISHED;
}
@@ -961,8 +958,7 @@ static int action_layer_prev_exec(bContext *C, wmOperator *op)
}
/* Update the action that this editor now uses
- * NOTE: The calls above have already handled the usercount/animdata side of things
- */
+ * NOTE: The calls above have already handled the user-count/animdata side of things. */
actedit_change_action(C, adt->action);
return OPERATOR_FINISHED;
}
diff --git a/source/blender/editors/space_action/action_draw.c b/source/blender/editors/space_action/action_draw.c
index 75eeb125609..52287b07b28 100644
--- a/source/blender/editors/space_action/action_draw.c
+++ b/source/blender/editors/space_action/action_draw.c
@@ -81,7 +81,7 @@ void draw_channel_names(bContext *C, bAnimContext *ac, ARegion *region)
v2d->tot.ymin = -height;
/* need to do a view-sync here, so that the keys area doesn't jump around (it must copy this) */
- UI_view2d_sync(NULL, ac->sa, v2d, V2D_LOCK_COPY);
+ UI_view2d_sync(NULL, ac->area, v2d, V2D_LOCK_COPY);
/* loop through channels, and set up drawing depending on their type */
{ /* first pass: just the standard GL-drawing for backdrop + text */
@@ -141,9 +141,9 @@ void draw_channel_strips(bAnimContext *ac, SpaceAction *saction, ARegion *region
bDopeSheet *ads = &saction->ads;
AnimData *adt = NULL;
- unsigned char col1[4], col2[4];
- unsigned char col1a[4], col2a[4];
- unsigned char col1b[4], col2b[4];
+ uchar col1[4], col2[4];
+ uchar col1a[4], col2a[4];
+ uchar col1b[4], col2b[4];
const bool show_group_colors = !(saction->flag & SACTION_NODRAWGCOLORS);
@@ -212,10 +212,10 @@ void draw_channel_strips(bAnimContext *ac, SpaceAction *saction, ARegion *region
bActionGroup *agrp = ale->data;
if (show_group_colors && agrp->customCol) {
if (sel) {
- immUniformColor3ubvAlpha((unsigned char *)agrp->cs.select, col1a[3]);
+ immUniformColor3ubvAlpha((uchar *)agrp->cs.select, col1a[3]);
}
else {
- immUniformColor3ubvAlpha((unsigned char *)agrp->cs.solid, col2a[3]);
+ immUniformColor3ubvAlpha((uchar *)agrp->cs.solid, col2a[3]);
}
}
else {
@@ -226,8 +226,7 @@ void draw_channel_strips(bAnimContext *ac, SpaceAction *saction, ARegion *region
case ANIMTYPE_FCURVE: {
FCurve *fcu = ale->data;
if (show_group_colors && fcu->grp && fcu->grp->customCol) {
- immUniformColor3ubvAlpha((unsigned char *)fcu->grp->cs.active,
- sel ? col1[3] : col2[3]);
+ immUniformColor3ubvAlpha((uchar *)fcu->grp->cs.active, sel ? col1[3] : col2[3]);
}
else {
immUniformColor4ubv(sel ? col1 : col2);
@@ -243,8 +242,8 @@ void draw_channel_strips(bAnimContext *ac, SpaceAction *saction, ARegion *region
immRectf(pos, v2d->cur.xmin, ymin, v2d->cur.xmax + EXTRA_SCROLL_PAD, ymax);
}
else if (ac->datatype == ANIMCONT_GPENCIL) {
- unsigned char *color;
- unsigned char gpl_col[4];
+ uchar *color;
+ uchar gpl_col[4];
if ((show_group_colors) && (ale->type == ANIMTYPE_GPLAYER)) {
bGPDlayer *gpl = (bGPDlayer *)ale->data;
rgb_float_to_uchar(gpl_col, gpl->color);
@@ -266,7 +265,7 @@ void draw_channel_strips(bAnimContext *ac, SpaceAction *saction, ARegion *region
else if (ac->datatype == ANIMCONT_MASK) {
/* TODO --- this is a copy of gpencil */
/* frames less than one get less saturated background */
- unsigned char *color = sel ? col1 : col2;
+ uchar *color = sel ? col1 : col2;
immUniformColor4ubv(color);
immRectf(pos, 0.0f, ymin, v2d->cur.xmin, ymax);
@@ -562,7 +561,7 @@ void timeline_draw_cache(SpaceAction *saction, Object *ob, Scene *scene)
/* Iterate over pointcaches on the active object, and draw each one's range. */
float y_offset = 0.0f;
const float cache_draw_height = 4.0f * UI_DPI_FAC * U.pixelsize;
- for (PTCacheID *pid = pidlist.first; pid; pid = pid->next) {
+ LISTBASE_FOREACH (PTCacheID *, pid, &pidlist) {
if (timeline_cache_is_hidden_by_setting(saction, pid)) {
continue;
}
diff --git a/source/blender/editors/space_action/action_edit.c b/source/blender/editors/space_action/action_edit.c
index 927e51a3e04..b390e4b56d6 100644
--- a/source/blender/editors/space_action/action_edit.c
+++ b/source/blender/editors/space_action/action_edit.c
@@ -218,7 +218,7 @@ static bool get_keyframe_extents(bAnimContext *ac, float *min, float *max, const
float tmin, tmax;
/* get range and apply necessary scaling before processing */
- if (calc_fcurve_range(fcu, &tmin, &tmax, onlySel, false)) {
+ if (BKE_fcurve_calc_range(fcu, &tmin, &tmax, onlySel, false)) {
if (adt) {
tmin = BKE_nla_tweakedit_remap(adt, tmin, NLATIME_CONVERT_MAP);
@@ -313,8 +313,8 @@ void ACTION_OT_previewrange_set(wmOperatorType *ot)
/**
* Find the extents of the active channel
*
- * \param[out] min Bottom y-extent of channel
- * \param[out] max Top y-extent of channel
+ * \param[out] min: Bottom y-extent of channel
+ * \param[out] max: Top y-extent of channel
* \return Success of finding a selected channel
*/
static bool actkeys_channels_get_selected_extents(bAnimContext *ac, float *min, float *max)
@@ -448,7 +448,7 @@ static int actkeys_viewsel_exec(bContext *C, wmOperator *UNUSED(op))
void ACTION_OT_view_all(wmOperatorType *ot)
{
/* identifiers */
- ot->name = "View All";
+ ot->name = "Frame All";
ot->idname = "ACTION_OT_view_all";
ot->description = "Reset viewable area to show full keyframe range";
@@ -490,7 +490,7 @@ void ACTION_OT_view_frame(wmOperatorType *ot)
/* identifiers */
ot->name = "Go to Current Frame";
ot->idname = "ACTION_OT_view_frame";
- ot->description = "Move the view to the playhead";
+ ot->description = "Move the view to the current frame";
/* api callbacks */
ot->exec = actkeys_view_frame_exec;
diff --git a/source/blender/editors/space_action/action_select.c b/source/blender/editors/space_action/action_select.c
index 173c2f1b5dc..bbb68f632fb 100644
--- a/source/blender/editors/space_action/action_select.c
+++ b/source/blender/editors/space_action/action_select.c
@@ -437,7 +437,7 @@ static void box_select_elem(
ListBase anim_data = {NULL, NULL};
ANIM_animdata_filter(ac, &anim_data, ANIMFILTER_DATA_VISIBLE, ac->data, ac->datatype);
- for (bAnimListElem *ale2 = anim_data.first; ale2; ale2 = ale2->next) {
+ LISTBASE_FOREACH (bAnimListElem *, ale2, &anim_data) {
box_select_elem(sel_data, ale2, xmin, xmax, true);
}
@@ -675,7 +675,7 @@ static void region_select_elem(RegionSelectData *sel_data, bAnimListElem *ale, b
ListBase anim_data = {NULL, NULL};
ANIM_animdata_filter(ac, &anim_data, ANIMFILTER_DATA_VISIBLE, ac->data, ac->datatype);
- for (bAnimListElem *ale2 = anim_data.first; ale2; ale2 = ale2->next) {
+ LISTBASE_FOREACH (bAnimListElem *, ale2, &anim_data) {
region_select_elem(sel_data, ale2, true);
}
@@ -793,8 +793,8 @@ static int actkeys_lassoselect_exec(bContext *C, wmOperator *op)
}
data_lasso.rectf_view = &rect_fl;
- data_lasso.mcords = WM_gesture_lasso_path_to_array(C, op, &data_lasso.mcords_tot);
- if (data_lasso.mcords == NULL) {
+ data_lasso.mcoords = WM_gesture_lasso_path_to_array(C, op, &data_lasso.mcoords_len);
+ if (data_lasso.mcoords == NULL) {
return OPERATOR_CANCELLED;
}
@@ -805,13 +805,13 @@ static int actkeys_lassoselect_exec(bContext *C, wmOperator *op)
}
/* get settings from operator */
- BLI_lasso_boundbox(&rect, data_lasso.mcords, data_lasso.mcords_tot);
+ BLI_lasso_boundbox(&rect, data_lasso.mcoords, data_lasso.mcoords_len);
BLI_rctf_rcti_copy(&rect_fl, &rect);
/* apply box_select action */
region_select_action_keys(&ac, &rect_fl, BEZT_OK_CHANNEL_LASSO, selectmode, &data_lasso);
- MEM_freeN((void *)data_lasso.mcords);
+ MEM_freeN((void *)data_lasso.mcoords);
/* send notifier that keyframe selection has changed */
WM_event_add_notifier(C, NC_ANIMATION | ND_KEYFRAME | NA_SELECTED, NULL);
diff --git a/source/blender/editors/space_action/space_action.c b/source/blender/editors/space_action/space_action.c
index 64c81797bb4..e92ea906237 100644
--- a/source/blender/editors/space_action/space_action.c
+++ b/source/blender/editors/space_action/space_action.c
@@ -60,7 +60,7 @@
/* ******************** default callbacks for action space ***************** */
-static SpaceLink *action_new(const ScrArea *sa, const Scene *scene)
+static SpaceLink *action_new(const ScrArea *area, const Scene *scene)
{
SpaceAction *saction;
ARegion *region;
@@ -113,7 +113,7 @@ static SpaceLink *action_new(const ScrArea *sa, const Scene *scene)
region->regiontype = RGN_TYPE_WINDOW;
region->v2d.tot.xmin = (float)(SFRA - 10);
- region->v2d.tot.ymin = (float)(-sa->winy) / 3.0f;
+ region->v2d.tot.ymin = (float)(-area->winy) / 3.0f;
region->v2d.tot.xmax = (float)(EFRA + 10);
region->v2d.tot.ymax = 0.0f;
@@ -144,9 +144,9 @@ static void action_free(SpaceLink *UNUSED(sl))
}
/* spacetype; init callback */
-static void action_init(struct wmWindowManager *UNUSED(wm), ScrArea *sa)
+static void action_init(struct wmWindowManager *UNUSED(wm), ScrArea *area)
{
- SpaceAction *saction = sa->spacedata.first;
+ SpaceAction *saction = area->spacedata.first;
saction->runtime.flag |= SACTION_RUNTIME_FLAG_NEED_CHAN_SYNC;
}
@@ -301,7 +301,7 @@ static void action_header_region_draw(const bContext *C, ARegion *region)
}
static void action_channel_region_listener(wmWindow *UNUSED(win),
- ScrArea *UNUSED(sa),
+ ScrArea *UNUSED(area),
ARegion *region,
wmNotifier *wmn,
const Scene *UNUSED(scene))
@@ -355,12 +355,12 @@ static void saction_channel_region_message_subscribe(const struct bContext *UNUS
struct WorkSpace *UNUSED(workspace),
struct Scene *UNUSED(scene),
struct bScreen *screen,
- struct ScrArea *sa,
+ struct ScrArea *area,
struct ARegion *region,
struct wmMsgBus *mbus)
{
PointerRNA ptr;
- RNA_pointer_create(&screen->id, &RNA_SpaceDopeSheetEditor, sa->spacedata.first, &ptr);
+ RNA_pointer_create(&screen->id, &RNA_SpaceDopeSheetEditor, area->spacedata.first, &ptr);
wmMsgSubscribeValue msg_sub_value_region_tag_redraw = {
.owner = region,
@@ -397,7 +397,7 @@ static void saction_channel_region_message_subscribe(const struct bContext *UNUS
}
static void action_main_region_listener(wmWindow *UNUSED(win),
- ScrArea *UNUSED(sa),
+ ScrArea *UNUSED(area),
ARegion *region,
wmNotifier *wmn,
const Scene *UNUSED(scene))
@@ -459,12 +459,12 @@ static void saction_main_region_message_subscribe(const struct bContext *C,
struct WorkSpace *workspace,
struct Scene *scene,
struct bScreen *screen,
- struct ScrArea *sa,
+ struct ScrArea *area,
struct ARegion *region,
struct wmMsgBus *mbus)
{
PointerRNA ptr;
- RNA_pointer_create(&screen->id, &RNA_SpaceDopeSheetEditor, sa->spacedata.first, &ptr);
+ RNA_pointer_create(&screen->id, &RNA_SpaceDopeSheetEditor, area->spacedata.first, &ptr);
wmMsgSubscribeValue msg_sub_value_region_tag_redraw = {
.owner = region,
@@ -497,16 +497,16 @@ static void saction_main_region_message_subscribe(const struct bContext *C,
}
/* Now run the general "channels region" one - since channels and main should be in sync */
- saction_channel_region_message_subscribe(C, workspace, scene, screen, sa, region, mbus);
+ saction_channel_region_message_subscribe(C, workspace, scene, screen, area, region, mbus);
}
/* editor level listener */
static void action_listener(wmWindow *UNUSED(win),
- ScrArea *sa,
+ ScrArea *area,
wmNotifier *wmn,
Scene *UNUSED(scene))
{
- SpaceAction *saction = (SpaceAction *)sa->spacedata.first;
+ SpaceAction *saction = (SpaceAction *)area->spacedata.first;
/* context changes */
switch (wmn->category) {
@@ -514,11 +514,11 @@ static void action_listener(wmWindow *UNUSED(win),
/* only handle these events in GPencil mode for performance considerations */
if (saction->mode == SACTCONT_GPENCIL) {
if (wmn->action == NA_EDITED) {
- ED_area_tag_redraw(sa);
+ ED_area_tag_redraw(area);
}
else if (wmn->action == NA_SELECTED) {
saction->runtime.flag |= SACTION_RUNTIME_FLAG_NEED_CHAN_SYNC;
- ED_area_tag_refresh(sa);
+ ED_area_tag_refresh(area);
}
}
break;
@@ -526,7 +526,7 @@ static void action_listener(wmWindow *UNUSED(win),
/* for NLA tweakmode enter/exit, need complete refresh */
if (wmn->data == ND_NLA_ACTCHANGE) {
saction->runtime.flag |= SACTION_RUNTIME_FLAG_NEED_CHAN_SYNC;
- ED_area_tag_refresh(sa);
+ ED_area_tag_refresh(area);
}
/* autocolor only really needs to change when channels are added/removed,
* or previously hidden stuff appears
@@ -534,14 +534,14 @@ static void action_listener(wmWindow *UNUSED(win),
*/
else if (((wmn->data == ND_KEYFRAME) && ELEM(wmn->action, NA_ADDED, NA_REMOVED)) ||
((wmn->data == ND_ANIMCHAN) && (wmn->action != NA_SELECTED))) {
- ED_area_tag_refresh(sa);
+ ED_area_tag_refresh(area);
}
/* for simple edits to the curve data though (or just plain selections),
* a simple redraw should work
* (see T39851 for an example of how this can go wrong)
*/
else {
- ED_area_tag_redraw(sa);
+ ED_area_tag_redraw(area);
}
break;
case NC_SCENE:
@@ -549,7 +549,7 @@ static void action_listener(wmWindow *UNUSED(win),
case ND_SEQUENCER:
if (wmn->action == NA_SELECTED) {
saction->runtime.flag |= SACTION_RUNTIME_FLAG_NEED_CHAN_SYNC;
- ED_area_tag_refresh(sa);
+ ED_area_tag_refresh(area);
}
break;
case ND_OB_ACTIVE:
@@ -557,13 +557,13 @@ static void action_listener(wmWindow *UNUSED(win),
/* Selection changed, so force refresh to flush
* (needs flag set to do syncing). */
saction->runtime.flag |= SACTION_RUNTIME_FLAG_NEED_CHAN_SYNC;
- ED_area_tag_refresh(sa);
+ ED_area_tag_refresh(area);
break;
case ND_RENDER_RESULT:
- ED_area_tag_redraw(sa);
+ ED_area_tag_redraw(area);
break;
case ND_FRAME_RANGE:
- for (ARegion *region = sa->regionbase.first; region; region = region->next) {
+ LISTBASE_FOREACH (ARegion *, region, &area->regionbase) {
if (region->regiontype == RGN_TYPE_WINDOW) {
Scene *scene = wmn->reference;
region->v2d.tot.xmin = (float)(SFRA - 4);
@@ -575,7 +575,7 @@ static void action_listener(wmWindow *UNUSED(win),
default:
if (saction->mode != SACTCONT_TIMELINE) {
/* Just redrawing the view will do. */
- ED_area_tag_redraw(sa);
+ ED_area_tag_redraw(area);
}
break;
}
@@ -586,7 +586,7 @@ static void action_listener(wmWindow *UNUSED(win),
* (needs flag set to do syncing). */
case ND_BONE_ACTIVE:
saction->runtime.flag |= SACTION_RUNTIME_FLAG_NEED_CHAN_SYNC;
- ED_area_tag_refresh(sa);
+ ED_area_tag_refresh(area);
break;
case ND_TRANSFORM:
/* moving object shouldn't need to redraw action */
@@ -596,12 +596,12 @@ static void action_listener(wmWindow *UNUSED(win),
case ND_PARTICLE:
/* only needed in timeline mode */
if (saction->mode == SACTCONT_TIMELINE) {
- ED_area_tag_refresh(sa);
- ED_area_tag_redraw(sa);
+ ED_area_tag_refresh(area);
+ ED_area_tag_redraw(area);
}
break;
default: /* just redrawing the view will do */
- ED_area_tag_redraw(sa);
+ ED_area_tag_redraw(area);
break;
}
break;
@@ -609,11 +609,11 @@ static void action_listener(wmWindow *UNUSED(win),
if (saction->mode == SACTCONT_MASK) {
switch (wmn->data) {
case ND_DATA:
- ED_area_tag_refresh(sa);
- ED_area_tag_redraw(sa);
+ ED_area_tag_refresh(area);
+ ED_area_tag_redraw(area);
break;
default: /* just redrawing the view will do */
- ED_area_tag_redraw(sa);
+ ED_area_tag_redraw(area);
break;
}
}
@@ -622,33 +622,33 @@ static void action_listener(wmWindow *UNUSED(win),
if (wmn->action == NA_SELECTED) {
/* selection changed, so force refresh to flush (needs flag set to do syncing) */
saction->runtime.flag |= SACTION_RUNTIME_FLAG_NEED_CHAN_SYNC;
- ED_area_tag_refresh(sa);
+ ED_area_tag_refresh(area);
}
break;
case NC_SPACE:
switch (wmn->data) {
case ND_SPACE_DOPESHEET:
- ED_area_tag_redraw(sa);
+ ED_area_tag_redraw(area);
break;
case ND_SPACE_TIME:
- ED_area_tag_redraw(sa);
+ ED_area_tag_redraw(area);
break;
case ND_SPACE_CHANGED:
saction->runtime.flag |= SACTION_RUNTIME_FLAG_NEED_CHAN_SYNC;
- ED_area_tag_refresh(sa);
+ ED_area_tag_refresh(area);
break;
}
break;
case NC_WINDOW:
if (saction->runtime.flag & SACTION_RUNTIME_FLAG_NEED_CHAN_SYNC) {
/* force redraw/refresh after undo/redo - [#28962] */
- ED_area_tag_refresh(sa);
+ ED_area_tag_refresh(area);
}
break;
case NC_WM:
switch (wmn->data) {
case ND_FILEREAD:
- ED_area_tag_refresh(sa);
+ ED_area_tag_refresh(area);
break;
}
break;
@@ -656,12 +656,12 @@ static void action_listener(wmWindow *UNUSED(win),
}
static void action_header_region_listener(wmWindow *UNUSED(win),
- ScrArea *sa,
+ ScrArea *area,
ARegion *region,
wmNotifier *wmn,
const Scene *UNUSED(scene))
{
- SpaceAction *saction = (SpaceAction *)sa->spacedata.first;
+ SpaceAction *saction = (SpaceAction *)area->spacedata.first;
/* context changes */
switch (wmn->category) {
@@ -733,7 +733,7 @@ static void action_buttons_area_draw(const bContext *C, ARegion *region)
}
static void action_region_listener(wmWindow *UNUSED(win),
- ScrArea *UNUSED(sa),
+ ScrArea *UNUSED(area),
ARegion *region,
wmNotifier *wmn,
const Scene *UNUSED(scene))
@@ -769,9 +769,9 @@ static void action_region_listener(wmWindow *UNUSED(win),
}
}
-static void action_refresh(const bContext *C, ScrArea *sa)
+static void action_refresh(const bContext *C, ScrArea *area)
{
- SpaceAction *saction = (SpaceAction *)sa->spacedata.first;
+ SpaceAction *saction = (SpaceAction *)area->spacedata.first;
/* Update the state of the animchannels in response to changes from the data they represent
* NOTE: the temp flag is used to indicate when this needs to be done,
@@ -789,8 +789,8 @@ static void action_refresh(const bContext *C, ScrArea *sa)
* - Regions (such as header) need to be manually tagged for redraw too
* or else they don't update [#28962]
*/
- ED_area_tag_redraw(sa);
- for (region = sa->regionbase.first; region; region = region->next) {
+ ED_area_tag_redraw(area);
+ for (region = area->regionbase.first; region; region = region->next) {
ED_region_tag_redraw(region);
}
}
@@ -799,7 +799,7 @@ static void action_refresh(const bContext *C, ScrArea *sa)
// XXX re-sizing y-extents of tot should go here?
}
-static void action_id_remap(ScrArea *UNUSED(sa), SpaceLink *slink, ID *old_id, ID *new_id)
+static void action_id_remap(ScrArea *UNUSED(area), SpaceLink *slink, ID *old_id, ID *new_id)
{
SpaceAction *sact = (SpaceAction *)slink;
@@ -820,15 +820,15 @@ static void action_id_remap(ScrArea *UNUSED(sa), SpaceLink *slink, ID *old_id, I
* The previous non-timeline mode is stored so switching back to the
* dope-sheet doesn't always reset the sub-mode.
*/
-static int action_space_subtype_get(ScrArea *sa)
+static int action_space_subtype_get(ScrArea *area)
{
- SpaceAction *sact = sa->spacedata.first;
+ SpaceAction *sact = area->spacedata.first;
return sact->mode == SACTCONT_TIMELINE ? SACTCONT_TIMELINE : SACTCONT_DOPESHEET;
}
-static void action_space_subtype_set(ScrArea *sa, int value)
+static void action_space_subtype_set(ScrArea *area, int value)
{
- SpaceAction *sact = sa->spacedata.first;
+ SpaceAction *sact = area->spacedata.first;
if (value == SACTCONT_TIMELINE) {
if (sact->mode != SACTCONT_TIMELINE) {
sact->mode_prev = sact->mode;
diff --git a/source/blender/editors/space_api/spacetypes.c b/source/blender/editors/space_api/spacetypes.c
index 5b83c082339..acc2281b2da 100644
--- a/source/blender/editors/space_api/spacetypes.c
+++ b/source/blender/editors/space_api/spacetypes.c
@@ -135,6 +135,7 @@ void ED_spacetypes_init(void)
ED_gizmotypes_blank_3d();
ED_gizmotypes_cage_2d();
ED_gizmotypes_cage_3d();
+ ED_gizmotypes_snap_3d();
/* register types for operators and gizmos */
spacetypes = BKE_spacetypes_list();
@@ -268,7 +269,7 @@ void ED_region_draw_cb_draw(const bContext *C, ARegion *region, int type)
void ED_spacetype_xxx(void);
/* allocate and init some vars */
-static SpaceLink *xxx_new(const ScrArea *UNUSED(sa), const Scene *UNUSED(scene))
+static SpaceLink *xxx_new(const ScrArea *UNUSED(area), const Scene *UNUSED(scene))
{
return NULL;
}
@@ -279,7 +280,7 @@ static void xxx_free(SpaceLink *UNUSED(sl))
}
/* spacetype; init callback for usage, should be redoable */
-static void xxx_init(wmWindowManager *UNUSED(wm), ScrArea *UNUSED(sa))
+static void xxx_init(wmWindowManager *UNUSED(wm), ScrArea *UNUSED(area))
{
/* link area to SpaceXXX struct */
diff --git a/source/blender/editors/space_buttons/buttons_context.c b/source/blender/editors/space_buttons/buttons_context.c
index 587ba5b0b79..7e6088bc3cc 100644
--- a/source/blender/editors/space_buttons/buttons_context.c
+++ b/source/blender/editors/space_buttons/buttons_context.c
@@ -1041,7 +1041,7 @@ int buttons_context(const bContext *C, const char *member, bContextDataResult *r
if (ptr && ptr->data) {
Object *ob = ptr->data;
- ModifierData *md = modifiers_findByType(ob, eModifierType_Cloth);
+ ModifierData *md = BKE_modifiers_findby_type(ob, eModifierType_Cloth);
CTX_data_pointer_set(result, &ob->id, &RNA_ClothModifier, md);
return 1;
}
@@ -1051,7 +1051,7 @@ int buttons_context(const bContext *C, const char *member, bContextDataResult *r
if (ptr && ptr->data) {
Object *ob = ptr->data;
- ModifierData *md = modifiers_findByType(ob, eModifierType_Softbody);
+ ModifierData *md = BKE_modifiers_findby_type(ob, eModifierType_Softbody);
CTX_data_pointer_set(result, &ob->id, &RNA_SoftBodyModifier, md);
return 1;
}
@@ -1062,7 +1062,7 @@ int buttons_context(const bContext *C, const char *member, bContextDataResult *r
if (ptr && ptr->data) {
Object *ob = ptr->data;
- ModifierData *md = modifiers_findByType(ob, eModifierType_Fluid);
+ ModifierData *md = BKE_modifiers_findby_type(ob, eModifierType_Fluid);
CTX_data_pointer_set(result, &ob->id, &RNA_FluidModifier, md);
return 1;
}
@@ -1072,7 +1072,7 @@ int buttons_context(const bContext *C, const char *member, bContextDataResult *r
if (ptr && ptr->data) {
Object *ob = ptr->data;
- ModifierData *md = modifiers_findByType(ob, eModifierType_Collision);
+ ModifierData *md = BKE_modifiers_findby_type(ob, eModifierType_Collision);
CTX_data_pointer_set(result, &ob->id, &RNA_CollisionModifier, md);
return 1;
}
@@ -1086,7 +1086,7 @@ int buttons_context(const bContext *C, const char *member, bContextDataResult *r
if (ptr && ptr->data) {
Object *ob = ptr->data;
- ModifierData *md = modifiers_findByType(ob, eModifierType_DynamicPaint);
+ ModifierData *md = BKE_modifiers_findby_type(ob, eModifierType_DynamicPaint);
CTX_data_pointer_set(result, &ob->id, &RNA_DynamicPaintModifier, md);
return 1;
}
diff --git a/source/blender/editors/space_buttons/buttons_ops.c b/source/blender/editors/space_buttons/buttons_ops.c
index e2affa7bc36..9af623d8065 100644
--- a/source/blender/editors/space_buttons/buttons_ops.c
+++ b/source/blender/editors/space_buttons/buttons_ops.c
@@ -110,7 +110,7 @@ static int file_browse_exec(bContext *C, wmOperator *op)
if (BLI_is_dir(path)) {
/* do this first so '//' isnt converted to '//\' on windows */
- BLI_add_slash(path);
+ BLI_path_slash_ensure(path);
if (is_relative) {
BLI_strncpy(path, str, FILE_MAX);
BLI_path_rel(path, BKE_main_blendfile_path(bmain));
@@ -122,7 +122,7 @@ static int file_browse_exec(bContext *C, wmOperator *op)
}
}
else {
- char *const lslash = (char *)BLI_last_slash(str);
+ char *const lslash = (char *)BLI_path_slash_rfind(str);
if (lslash) {
lslash[1] = '\0';
}
@@ -187,7 +187,7 @@ static int file_browse_invoke(bContext *C, wmOperator *op, const wmEvent *event)
PointerRNA props_ptr;
if (event->alt) {
- char *lslash = (char *)BLI_last_slash(str);
+ char *lslash = (char *)BLI_path_slash_rfind(str);
if (lslash) {
*lslash = '\0';
}
diff --git a/source/blender/editors/space_buttons/buttons_texture.c b/source/blender/editors/space_buttons/buttons_texture.c
index 00818ac77b5..3dc5eca8a8b 100644
--- a/source/blender/editors/space_buttons/buttons_texture.c
+++ b/source/blender/editors/space_buttons/buttons_texture.c
@@ -236,10 +236,10 @@ static void buttons_texture_users_from_context(ListBase *users,
int a;
/* modifiers */
- modifiers_foreachTexLink(ob, buttons_texture_modifier_foreach, users);
+ BKE_modifiers_foreach_tex_link(ob, buttons_texture_modifier_foreach, users);
/* grease pencil modifiers */
- BKE_gpencil_modifiers_foreachTexLink(ob, buttons_texture_modifier_gpencil_foreach, users);
+ BKE_gpencil_modifiers_foreach_tex_link(ob, buttons_texture_modifier_gpencil_foreach, users);
/* particle systems */
if (psys && !limited_mode) {
@@ -373,7 +373,7 @@ static void template_texture_select(bContext *C, void *user_p, void *UNUSED(arg)
/* set user as active */
if (user->node) {
- ED_node_set_active(CTX_data_main(C), user->ntree, user->node);
+ ED_node_set_active(CTX_data_main(C), user->ntree, user->node, NULL);
ct->texture = NULL;
}
else {
@@ -545,7 +545,7 @@ static void template_texture_show(bContext *C, void *data_p, void *prop_p)
}
}
-void uiTemplateTextureShow(uiLayout *layout, bContext *C, PointerRNA *ptr, PropertyRNA *prop)
+void uiTemplateTextureShow(uiLayout *layout, const bContext *C, PointerRNA *ptr, PropertyRNA *prop)
{
/* button to quickly show texture in texture tab */
SpaceProperties *sbuts = CTX_wm_space_properties(C);
diff --git a/source/blender/editors/space_buttons/space_buttons.c b/source/blender/editors/space_buttons/space_buttons.c
index 2fd54db667b..c06c107d4a3 100644
--- a/source/blender/editors/space_buttons/space_buttons.c
+++ b/source/blender/editors/space_buttons/space_buttons.c
@@ -110,7 +110,7 @@ static void buttons_free(SpaceLink *sl)
}
/* spacetype; init callback */
-static void buttons_init(struct wmWindowManager *UNUSED(wm), ScrArea *UNUSED(sa))
+static void buttons_init(struct wmWindowManager *UNUSED(wm), ScrArea *UNUSED(area))
{
}
@@ -219,7 +219,7 @@ static void buttons_main_region_layout(const bContext *C, ARegion *region)
}
static void buttons_main_region_listener(wmWindow *UNUSED(win),
- ScrArea *UNUSED(sa),
+ ScrArea *UNUSED(area),
ARegion *region,
wmNotifier *wmn,
const Scene *UNUSED(scene))
@@ -274,11 +274,11 @@ static void buttons_header_region_message_subscribe(const bContext *UNUSED(C),
WorkSpace *UNUSED(workspace),
Scene *UNUSED(scene),
bScreen *UNUSED(screen),
- ScrArea *sa,
+ ScrArea *area,
ARegion *region,
struct wmMsgBus *mbus)
{
- SpaceProperties *sbuts = sa->spacedata.first;
+ SpaceProperties *sbuts = area->spacedata.first;
wmMsgSubscribeValue msg_sub_value_region_tag_redraw = {
.owner = region,
.user_data = region,
@@ -312,7 +312,7 @@ static void buttons_navigation_bar_region_init(wmWindowManager *wm, ARegion *reg
static void buttons_navigation_bar_region_draw(const bContext *C, ARegion *region)
{
- for (PanelType *pt = region->type->paneltypes.first; pt; pt = pt->next) {
+ LISTBASE_FOREACH (PanelType *, pt, &region->type->paneltypes) {
pt->flag |= PNL_LAYOUT_VERT_BAR;
}
@@ -326,7 +326,7 @@ static void buttons_navigation_bar_region_message_subscribe(const bContext *UNUS
WorkSpace *UNUSED(workspace),
Scene *UNUSED(scene),
bScreen *UNUSED(screen),
- ScrArea *UNUSED(sa),
+ ScrArea *UNUSED(area),
ARegion *region,
struct wmMsgBus *mbus)
{
@@ -341,96 +341,96 @@ static void buttons_navigation_bar_region_message_subscribe(const bContext *UNUS
/* draw a certain button set only if properties area is currently
* showing that button set, to reduce unnecessary drawing. */
-static void buttons_area_redraw(ScrArea *sa, short buttons)
+static void buttons_area_redraw(ScrArea *area, short buttons)
{
- SpaceProperties *sbuts = sa->spacedata.first;
+ SpaceProperties *sbuts = area->spacedata.first;
/* if the area's current button set is equal to the one to redraw */
if (sbuts->mainb == buttons) {
- ED_area_tag_redraw(sa);
+ ED_area_tag_redraw(area);
}
}
/* reused! */
static void buttons_area_listener(wmWindow *UNUSED(win),
- ScrArea *sa,
+ ScrArea *area,
wmNotifier *wmn,
Scene *UNUSED(scene))
{
- SpaceProperties *sbuts = sa->spacedata.first;
+ SpaceProperties *sbuts = area->spacedata.first;
/* context changes */
switch (wmn->category) {
case NC_SCENE:
switch (wmn->data) {
case ND_RENDER_OPTIONS:
- buttons_area_redraw(sa, BCONTEXT_RENDER);
- buttons_area_redraw(sa, BCONTEXT_OUTPUT);
- buttons_area_redraw(sa, BCONTEXT_VIEW_LAYER);
+ buttons_area_redraw(area, BCONTEXT_RENDER);
+ buttons_area_redraw(area, BCONTEXT_OUTPUT);
+ buttons_area_redraw(area, BCONTEXT_VIEW_LAYER);
break;
case ND_WORLD:
- buttons_area_redraw(sa, BCONTEXT_WORLD);
+ buttons_area_redraw(area, BCONTEXT_WORLD);
sbuts->preview = 1;
break;
case ND_FRAME:
/* any buttons area can have animated properties so redraw all */
- ED_area_tag_redraw(sa);
+ ED_area_tag_redraw(area);
sbuts->preview = 1;
break;
case ND_OB_ACTIVE:
- ED_area_tag_redraw(sa);
+ ED_area_tag_redraw(area);
sbuts->preview = 1;
break;
case ND_KEYINGSET:
- buttons_area_redraw(sa, BCONTEXT_SCENE);
+ buttons_area_redraw(area, BCONTEXT_SCENE);
break;
case ND_RENDER_RESULT:
break;
case ND_MODE:
case ND_LAYER:
default:
- ED_area_tag_redraw(sa);
+ ED_area_tag_redraw(area);
break;
}
break;
case NC_OBJECT:
switch (wmn->data) {
case ND_TRANSFORM:
- buttons_area_redraw(sa, BCONTEXT_OBJECT);
- buttons_area_redraw(sa, BCONTEXT_DATA); /* autotexpace flag */
+ buttons_area_redraw(area, BCONTEXT_OBJECT);
+ buttons_area_redraw(area, BCONTEXT_DATA); /* autotexpace flag */
break;
case ND_POSE:
case ND_BONE_ACTIVE:
case ND_BONE_SELECT:
- buttons_area_redraw(sa, BCONTEXT_BONE);
- buttons_area_redraw(sa, BCONTEXT_BONE_CONSTRAINT);
- buttons_area_redraw(sa, BCONTEXT_DATA);
+ buttons_area_redraw(area, BCONTEXT_BONE);
+ buttons_area_redraw(area, BCONTEXT_BONE_CONSTRAINT);
+ buttons_area_redraw(area, BCONTEXT_DATA);
break;
case ND_MODIFIER:
if (wmn->action == NA_RENAME) {
- ED_area_tag_redraw(sa);
+ ED_area_tag_redraw(area);
}
else {
- buttons_area_redraw(sa, BCONTEXT_MODIFIER);
+ buttons_area_redraw(area, BCONTEXT_MODIFIER);
}
- buttons_area_redraw(sa, BCONTEXT_PHYSICS);
+ buttons_area_redraw(area, BCONTEXT_PHYSICS);
break;
case ND_CONSTRAINT:
- buttons_area_redraw(sa, BCONTEXT_CONSTRAINT);
- buttons_area_redraw(sa, BCONTEXT_BONE_CONSTRAINT);
+ buttons_area_redraw(area, BCONTEXT_CONSTRAINT);
+ buttons_area_redraw(area, BCONTEXT_BONE_CONSTRAINT);
break;
case ND_PARTICLE:
if (wmn->action == NA_EDITED) {
- buttons_area_redraw(sa, BCONTEXT_PARTICLE);
+ buttons_area_redraw(area, BCONTEXT_PARTICLE);
}
sbuts->preview = 1;
break;
case ND_DRAW:
- buttons_area_redraw(sa, BCONTEXT_OBJECT);
- buttons_area_redraw(sa, BCONTEXT_DATA);
- buttons_area_redraw(sa, BCONTEXT_PHYSICS);
+ buttons_area_redraw(area, BCONTEXT_OBJECT);
+ buttons_area_redraw(area, BCONTEXT_DATA);
+ buttons_area_redraw(area, BCONTEXT_PHYSICS);
/* Needed to refresh context path when changing active particle system index. */
- buttons_area_redraw(sa, BCONTEXT_PARTICLE);
+ buttons_area_redraw(area, BCONTEXT_PARTICLE);
break;
case ND_SHADING:
case ND_SHADING_DRAW:
@@ -441,7 +441,7 @@ static void buttons_area_listener(wmWindow *UNUSED(win),
break;
default:
/* Not all object RNA props have a ND_ notifier (yet) */
- ED_area_tag_redraw(sa);
+ ED_area_tag_redraw(area);
break;
}
break;
@@ -450,12 +450,12 @@ static void buttons_area_listener(wmWindow *UNUSED(win),
case ND_SELECT:
case ND_DATA:
case ND_VERTEX_GROUP:
- ED_area_tag_redraw(sa);
+ ED_area_tag_redraw(area);
break;
}
break;
case NC_MATERIAL:
- ED_area_tag_redraw(sa);
+ ED_area_tag_redraw(area);
switch (wmn->data) {
case ND_SHADING:
case ND_SHADING_DRAW:
@@ -468,43 +468,43 @@ static void buttons_area_listener(wmWindow *UNUSED(win),
}
break;
case NC_WORLD:
- buttons_area_redraw(sa, BCONTEXT_WORLD);
+ buttons_area_redraw(area, BCONTEXT_WORLD);
sbuts->preview = 1;
break;
case NC_LAMP:
- buttons_area_redraw(sa, BCONTEXT_DATA);
+ buttons_area_redraw(area, BCONTEXT_DATA);
sbuts->preview = 1;
break;
case NC_GROUP:
- buttons_area_redraw(sa, BCONTEXT_OBJECT);
+ buttons_area_redraw(area, BCONTEXT_OBJECT);
break;
case NC_BRUSH:
- buttons_area_redraw(sa, BCONTEXT_TEXTURE);
- buttons_area_redraw(sa, BCONTEXT_TOOL);
+ buttons_area_redraw(area, BCONTEXT_TEXTURE);
+ buttons_area_redraw(area, BCONTEXT_TOOL);
sbuts->preview = 1;
break;
case NC_TEXTURE:
case NC_IMAGE:
if (wmn->action != NA_PAINTING) {
- ED_area_tag_redraw(sa);
+ ED_area_tag_redraw(area);
sbuts->preview = 1;
}
break;
case NC_SPACE:
if (wmn->data == ND_SPACE_PROPERTIES) {
- ED_area_tag_redraw(sa);
+ ED_area_tag_redraw(area);
}
break;
case NC_ID:
if (wmn->action == NA_RENAME) {
- ED_area_tag_redraw(sa);
+ ED_area_tag_redraw(area);
}
break;
case NC_ANIMATION:
switch (wmn->data) {
case ND_KEYFRAME:
if (ELEM(wmn->action, NA_EDITED, NA_ADDED, NA_REMOVED)) {
- ED_area_tag_redraw(sa);
+ ED_area_tag_redraw(area);
}
break;
}
@@ -513,14 +513,14 @@ static void buttons_area_listener(wmWindow *UNUSED(win),
switch (wmn->data) {
case ND_DATA:
if (ELEM(wmn->action, NA_EDITED, NA_ADDED, NA_REMOVED, NA_SELECTED)) {
- ED_area_tag_redraw(sa);
+ ED_area_tag_redraw(area);
}
break;
}
break;
case NC_NODE:
if (wmn->action == NA_SELECTED) {
- ED_area_tag_redraw(sa);
+ ED_area_tag_redraw(area);
/* new active node, update texture preview */
if (sbuts->mainb == BCONTEXT_TEXTURE) {
sbuts->preview = 1;
@@ -530,24 +530,24 @@ static void buttons_area_listener(wmWindow *UNUSED(win),
/* Listener for preview render, when doing an global undo. */
case NC_WM:
if (wmn->data == ND_UNDO) {
- ED_area_tag_redraw(sa);
+ ED_area_tag_redraw(area);
sbuts->preview = 1;
}
break;
#ifdef WITH_FREESTYLE
case NC_LINESTYLE:
- ED_area_tag_redraw(sa);
+ ED_area_tag_redraw(area);
sbuts->preview = 1;
break;
#endif
}
if (wmn->data == ND_KEYS) {
- ED_area_tag_redraw(sa);
+ ED_area_tag_redraw(area);
}
}
-static void buttons_id_remap(ScrArea *UNUSED(sa), SpaceLink *slink, ID *old_id, ID *new_id)
+static void buttons_id_remap(ScrArea *UNUSED(area), SpaceLink *slink, ID *old_id, ID *new_id)
{
SpaceProperties *sbuts = (SpaceProperties *)slink;
diff --git a/source/blender/editors/space_clip/clip_buttons.c b/source/blender/editors/space_clip/clip_buttons.c
index dc85b3959e1..3b1cc6fcab0 100644
--- a/source/blender/editors/space_clip/clip_buttons.c
+++ b/source/blender/editors/space_clip/clip_buttons.c
@@ -872,7 +872,7 @@ void uiTemplateMovieclipInformation(uiLayout *layout,
if (framenr <= clip->len) {
BKE_movieclip_filename_for_frame(clip, user, filepath);
- file = BLI_last_slash(filepath);
+ file = BLI_path_slash_rfind(filepath);
}
else {
file = "-";
diff --git a/source/blender/editors/space_clip/clip_dopesheet_draw.c b/source/blender/editors/space_clip/clip_dopesheet_draw.c
index eba0f33d6cc..84ab5e6524b 100644
--- a/source/blender/editors/space_clip/clip_dopesheet_draw.c
+++ b/source/blender/editors/space_clip/clip_dopesheet_draw.c
@@ -68,7 +68,7 @@ static void track_channel_color(MovieTrackingTrack *track, float default_color[3
}
static void draw_keyframe_shape(
- float x, float y, bool sel, float alpha, unsigned int pos_id, unsigned int color_id)
+ float x, float y, bool sel, float alpha, uint pos_id, uint color_id)
{
float color[4] = {0.91f, 0.91f, 0.91f, alpha};
if (sel) {
@@ -79,7 +79,7 @@ static void draw_keyframe_shape(
immVertex2f(pos_id, x, y);
}
-static void clip_draw_dopesheet_background(ARegion *region, MovieClip *clip, unsigned int pos_id)
+static void clip_draw_dopesheet_background(ARegion *region, MovieClip *clip, uint pos_id)
{
View2D *v2d = &region->v2d;
MovieTracking *tracking = &clip->tracking;
@@ -292,7 +292,7 @@ void clip_draw_dopesheet_main(SpaceClip *sc, ARegion *region, Scene *scene)
void clip_draw_dopesheet_channels(const bContext *C, ARegion *region)
{
- ScrArea *sa = CTX_wm_area(C);
+ ScrArea *area = CTX_wm_area(C);
SpaceClip *sc = CTX_wm_space_clip(C);
View2D *v2d = &region->v2d;
MovieClip *clip = ED_space_clip_get_clip(sc);
@@ -316,7 +316,7 @@ void clip_draw_dopesheet_channels(const bContext *C, ARegion *region)
/* need to do a view-sync here, so that the keys area doesn't jump around
* (it must copy this) */
- UI_view2d_sync(NULL, sa, v2d, V2D_LOCK_COPY);
+ UI_view2d_sync(NULL, area, v2d, V2D_LOCK_COPY);
/* loop through channels, and set up drawing depending on their type
* first pass: just the standard GL-drawing for backdrop + text
diff --git a/source/blender/editors/space_clip/clip_dopesheet_ops.c b/source/blender/editors/space_clip/clip_dopesheet_ops.c
index cd95a00c62a..c3323491085 100644
--- a/source/blender/editors/space_clip/clip_dopesheet_ops.c
+++ b/source/blender/editors/space_clip/clip_dopesheet_ops.c
@@ -204,7 +204,7 @@ static int dopesheet_view_all_exec(bContext *C, wmOperator *UNUSED(op))
void CLIP_OT_dopesheet_view_all(wmOperatorType *ot)
{
/* identifiers */
- ot->name = "View All";
+ ot->name = "Frame All";
ot->description = "Reset viewable area to show full keyframe range";
ot->idname = "CLIP_OT_dopesheet_view_all";
diff --git a/source/blender/editors/space_clip/clip_draw.c b/source/blender/editors/space_clip/clip_draw.c
index 2a6cf4d5a55..fe7ae7096a0 100644
--- a/source/blender/editors/space_clip/clip_draw.c
+++ b/source/blender/editors/space_clip/clip_draw.c
@@ -66,8 +66,7 @@
/*********************** main area drawing *************************/
-static void draw_keyframe(
- int frame, int cfra, int sfra, float framelen, int width, unsigned int pos)
+static void draw_keyframe(int frame, int cfra, int sfra, float framelen, int width, uint pos)
{
int height = (frame == cfra) ? 22 : 10;
int x = (frame - sfra) * framelen;
@@ -592,7 +591,7 @@ static void draw_marker_outline(SpaceClip *sc,
const float marker_pos[2],
int width,
int height,
- unsigned int position)
+ uint position)
{
int tiny = sc->flag & SC_SHOW_TINY_MARKER;
bool show_search = false;
@@ -895,7 +894,7 @@ static float get_shortest_pattern_side(MovieTrackingMarker *marker)
}
static void draw_marker_slide_square(
- float x, float y, float dx, float dy, int outline, const float px[2], unsigned int pos)
+ float x, float y, float dx, float dy, int outline, const float px[2], uint pos)
{
float tdx, tdy;
@@ -911,7 +910,7 @@ static void draw_marker_slide_square(
}
static void draw_marker_slide_triangle(
- float x, float y, float dx, float dy, int outline, const float px[2], unsigned int pos)
+ float x, float y, float dx, float dy, int outline, const float px[2], uint pos)
{
float tdx, tdy;
@@ -939,7 +938,7 @@ static void draw_marker_slide_zones(SpaceClip *sc,
int act,
int width,
int height,
- unsigned int pos)
+ uint pos)
{
float dx, dy, patdx, patdy, searchdx, searchdy;
int tiny = sc->flag & SC_SHOW_TINY_MARKER;
@@ -1056,7 +1055,7 @@ static void draw_marker_texts(SpaceClip *sc,
UI_FontThemeColor(fontid, TH_ACT_MARKER);
}
else {
- unsigned char color[4];
+ uchar color[4];
UI_GetThemeColorShade4ubv(TH_DIS_MARKER, 128, color);
BLF_color4ubv(fontid, color);
}
@@ -1191,7 +1190,7 @@ static void draw_plane_marker_image(Scene *scene,
ibuf = BKE_image_acquire_ibuf(image, NULL, &lock);
if (ibuf) {
- unsigned char *display_buffer;
+ uchar *display_buffer;
void *cache_handle;
if (image->flag & IMA_VIEW_AS_RENDER) {
@@ -1652,7 +1651,7 @@ static void draw_tracking_tracks(SpaceClip *sc,
pos[0] = (pos[0] / (pos[3] * 2.0f) + 0.5f) * width;
pos[1] = (pos[1] / (pos[3] * 2.0f) + 0.5f) * height * aspy;
- BKE_tracking_distort_v2(tracking, pos, npos);
+ BKE_tracking_distort_v2(tracking, width, height, pos, npos);
if (npos[0] >= 0.0f && npos[1] >= 0.0f && npos[0] <= width && npos[1] <= height * aspy) {
vec[0] = (marker->pos[0] + track->offset[0]) * width;
@@ -1731,8 +1730,7 @@ static void draw_distortion(SpaceClip *sc,
{
float x, y;
const int n = 10;
- int i, j, a;
- float pos[2], tpos[2], grid[11][11][2];
+ float tpos[2], grid[11][11][2];
MovieTracking *tracking = &clip->tracking;
bGPdata *gpd = NULL;
float aspy = 1.0f / tracking->camera.pixel_aspect;
@@ -1765,7 +1763,7 @@ static void draw_distortion(SpaceClip *sc,
float val[4][2], idx[4][2];
float min[2], max[2];
- for (a = 0; a < 4; a++) {
+ for (int a = 0; a < 4; a++) {
if (a < 2) {
val[a][a % 2] = FLT_MAX;
}
@@ -1774,13 +1772,13 @@ static void draw_distortion(SpaceClip *sc,
}
}
- zero_v2(pos);
- for (i = 0; i <= n; i++) {
- for (j = 0; j <= n; j++) {
+ for (int i = 0; i <= n; i++) {
+ for (int j = 0; j <= n; j++) {
if (i == 0 || j == 0 || i == n || j == n) {
- BKE_tracking_distort_v2(tracking, pos, tpos);
+ const float pos[2] = {dx * j, dy * i};
+ BKE_tracking_distort_v2(tracking, width, height, pos, tpos);
- for (a = 0; a < 4; a++) {
+ for (int a = 0; a < 4; a++) {
int ok;
if (a < 2) {
@@ -1797,59 +1795,49 @@ static void draw_distortion(SpaceClip *sc,
}
}
}
-
- pos[0] += dx;
}
-
- pos[0] = 0.0f;
- pos[1] += dy;
}
INIT_MINMAX2(min, max);
- for (a = 0; a < 4; a++) {
- pos[0] = idx[a][0] * dx;
- pos[1] = idx[a][1] * dy;
+ for (int a = 0; a < 4; a++) {
+ const float pos[2] = {idx[a][0] * dx, idx[a][1] * dy};
- BKE_tracking_undistort_v2(tracking, pos, tpos);
+ BKE_tracking_undistort_v2(tracking, width, height, pos, tpos);
minmax_v2v2_v2(min, max, tpos);
}
- copy_v2_v2(pos, min);
dx = (max[0] - min[0]) / n;
dy = (max[1] - min[1]) / n;
- for (i = 0; i <= n; i++) {
- for (j = 0; j <= n; j++) {
- BKE_tracking_distort_v2(tracking, pos, grid[i][j]);
+ for (int i = 0; i <= n; i++) {
+ for (int j = 0; j <= n; j++) {
+ const float pos[2] = {min[0] + dx * j, min[1] + dy * i};
+
+ BKE_tracking_distort_v2(tracking, width, height, pos, grid[i][j]);
grid[i][j][0] /= width;
grid[i][j][1] /= height * aspy;
-
- pos[0] += dx;
}
-
- pos[0] = min[0];
- pos[1] += dy;
}
immUniformColor3f(1.0f, 0.0f, 0.0f);
- for (i = 0; i <= n; i++) {
+ for (int i = 0; i <= n; i++) {
immBegin(GPU_PRIM_LINE_STRIP, n + 1);
- for (j = 0; j <= n; j++) {
+ for (int j = 0; j <= n; j++) {
immVertex2fv(position, grid[i][j]);
}
immEnd();
}
- for (j = 0; j <= n; j++) {
+ for (int j = 0; j <= n; j++) {
immBegin(GPU_PRIM_LINE_STRIP, n + 1);
- for (i = 0; i <= n; i++) {
+ for (int i = 0; i <= n; i++) {
immVertex2fv(position, grid[i][j]);
}
@@ -1883,8 +1871,8 @@ static void draw_distortion(SpaceClip *sc,
while (stroke) {
if (stroke->flag & GP_STROKE_2DSPACE) {
if (stroke->totpoints > 1) {
- for (i = 0; i < stroke->totpoints - 1; i++) {
- float npos[2], dpos[2], len;
+ for (int i = 0; i < stroke->totpoints - 1; i++) {
+ float pos[2], npos[2], dpos[2], len;
int steps;
pos[0] = (stroke->points[i].x + offsx) * width;
@@ -1898,8 +1886,8 @@ static void draw_distortion(SpaceClip *sc,
/* we want to distort only long straight lines */
if (stroke->totpoints == 2) {
- BKE_tracking_undistort_v2(tracking, pos, pos);
- BKE_tracking_undistort_v2(tracking, npos, npos);
+ BKE_tracking_undistort_v2(tracking, width, height, pos, pos);
+ BKE_tracking_undistort_v2(tracking, width, height, npos, npos);
}
sub_v2_v2v2(dpos, npos, pos);
@@ -1907,8 +1895,8 @@ static void draw_distortion(SpaceClip *sc,
immBegin(GPU_PRIM_LINE_STRIP, steps + 1);
- for (j = 0; j <= steps; j++) {
- BKE_tracking_distort_v2(tracking, pos, tpos);
+ for (int j = 0; j <= steps; j++) {
+ BKE_tracking_distort_v2(tracking, width, height, pos, tpos);
immVertex2f(position, tpos[0] / width, tpos[1] / (height * aspy));
add_v2_v2(pos, dpos);
diff --git a/source/blender/editors/space_clip/clip_editor.c b/source/blender/editors/space_clip/clip_editor.c
index 6336f1bff3a..5be4b2d5df0 100644
--- a/source/blender/editors/space_clip/clip_editor.c
+++ b/source/blender/editors/space_clip/clip_editor.c
@@ -37,6 +37,7 @@
#include "DNA_mask_types.h"
#include "BLI_fileops.h"
+#include "BLI_listbase.h"
#include "BLI_math.h"
#include "BLI_rect.h"
#include "BLI_task.h"
@@ -282,7 +283,7 @@ bool ED_space_clip_color_sample(SpaceClip *sc, ARegion *region, int mval[2], flo
if (fx >= 0.0f && fy >= 0.0f && fx < 1.0f && fy < 1.0f) {
const float *fp;
- unsigned char *cp;
+ uchar *cp;
int x = (int)(fx * ibuf->x), y = (int)(fy * ibuf->y);
CLAMP(x, 0, ibuf->x - 1);
@@ -294,7 +295,7 @@ bool ED_space_clip_color_sample(SpaceClip *sc, ARegion *region, int mval[2], flo
ret = true;
}
else if (ibuf->rect) {
- cp = (unsigned char *)(ibuf->rect + y * ibuf->x + x);
+ cp = (uchar *)(ibuf->rect + y * ibuf->x + x);
rgb_uchar_to_float(r_col, cp);
IMB_colormanagement_colorspace_to_scene_linear_v3(r_col, ibuf->rect_colorspace);
ret = true;
@@ -310,12 +311,12 @@ void ED_clip_update_frame(const Main *mainp, int cfra)
{
/* image window, compo node users */
for (wmWindowManager *wm = mainp->wm.first; wm; wm = wm->id.next) { /* only 1 wm */
- for (wmWindow *win = wm->windows.first; win; win = win->next) {
+ LISTBASE_FOREACH (wmWindow *, win, &wm->windows) {
bScreen *screen = WM_window_get_active_screen(win);
- for (ScrArea *sa = screen->areabase.first; sa; sa = sa->next) {
- if (sa->spacetype == SPACE_CLIP) {
- SpaceClip *sc = sa->spacedata.first;
+ LISTBASE_FOREACH (ScrArea *, area, &screen->areabase) {
+ if (area->spacetype == SPACE_CLIP) {
+ SpaceClip *sc = area->spacedata.first;
sc->scopes.ok = false;
@@ -545,7 +546,7 @@ void ED_clip_point_undistorted_pos(SpaceClip *sc, const float co[2], float r_co[
r_co[0] *= width;
r_co[1] *= height * aspy;
- BKE_tracking_undistort_v2(&clip->tracking, r_co, r_co);
+ BKE_tracking_undistort_v2(&clip->tracking, width, height, r_co, r_co);
r_co[0] /= width;
r_co[1] /= height * aspy;
@@ -579,7 +580,7 @@ void ED_clip_point_stable_pos(
float aspy = 1.0f / tracking->camera.pixel_aspect;
float tmp[2] = {*xr * width, *yr * height * aspy};
- BKE_tracking_distort_v2(tracking, tmp, tmp);
+ BKE_tracking_distort_v2(tracking, width, height, tmp, tmp);
*xr = tmp[0] / width;
*yr = tmp[1] / (height * aspy);
@@ -744,7 +745,7 @@ static bool check_prefetch_break(void)
}
/* read file for specified frame number to the memory */
-static unsigned char *prefetch_read_file_to_memory(
+static uchar *prefetch_read_file_to_memory(
MovieClip *clip, int current_frame, short render_size, short render_flag, size_t *r_size)
{
MovieClipUser user = {0};
@@ -766,7 +767,7 @@ static unsigned char *prefetch_read_file_to_memory(
return NULL;
}
- unsigned char *mem = MEM_mallocN(size, "movieclip prefetch memory file");
+ uchar *mem = MEM_mallocN(size, "movieclip prefetch memory file");
if (mem == NULL) {
close(file);
return NULL;
@@ -822,12 +823,12 @@ static int prefetch_find_uncached_frame(MovieClip *clip,
}
/* get memory buffer for first uncached frame within prefetch frame range */
-static unsigned char *prefetch_thread_next_frame(PrefetchQueue *queue,
- MovieClip *clip,
- size_t *r_size,
- int *r_current_frame)
+static uchar *prefetch_thread_next_frame(PrefetchQueue *queue,
+ MovieClip *clip,
+ size_t *r_size,
+ int *r_current_frame)
{
- unsigned char *mem = NULL;
+ uchar *mem = NULL;
BLI_spin_lock(&queue->spin);
if (!*queue->stop && !check_prefetch_break() &&
@@ -884,11 +885,11 @@ static unsigned char *prefetch_thread_next_frame(PrefetchQueue *queue,
return mem;
}
-static void prefetch_task_func(TaskPool *__restrict pool, void *task_data, int UNUSED(threadid))
+static void prefetch_task_func(TaskPool *__restrict pool, void *task_data)
{
- PrefetchQueue *queue = (PrefetchQueue *)BLI_task_pool_userdata(pool);
+ PrefetchQueue *queue = (PrefetchQueue *)BLI_task_pool_user_data(pool);
MovieClip *clip = (MovieClip *)task_data;
- unsigned char *mem;
+ uchar *mem;
size_t size;
int current_frame;
@@ -941,9 +942,8 @@ static void start_prefetch_threads(MovieClip *clip,
float *progress)
{
PrefetchQueue queue;
- TaskScheduler *task_scheduler = BLI_task_scheduler_get();
TaskPool *task_pool;
- int i, tot_thread = BLI_task_scheduler_num_threads(task_scheduler);
+ int i, tot_thread = BLI_task_scheduler_num_threads();
/* initialize queue */
BLI_spin_init(&queue.spin);
@@ -960,9 +960,9 @@ static void start_prefetch_threads(MovieClip *clip,
queue.do_update = do_update;
queue.progress = progress;
- task_pool = BLI_task_pool_create(task_scheduler, &queue);
+ task_pool = BLI_task_pool_create(&queue, TASK_PRIORITY_LOW);
for (i = 0; i < tot_thread; i++) {
- BLI_task_pool_push(task_pool, prefetch_task_func, clip, false, TASK_PRIORITY_LOW);
+ BLI_task_pool_push(task_pool, prefetch_task_func, clip, false, NULL);
}
BLI_task_pool_work_and_wait(task_pool);
BLI_task_pool_free(task_pool);
diff --git a/source/blender/editors/space_clip/clip_graph_draw.c b/source/blender/editors/space_clip/clip_graph_draw.c
index 7f3d3f3d651..277930495bd 100644
--- a/source/blender/editors/space_clip/clip_graph_draw.c
+++ b/source/blender/editors/space_clip/clip_graph_draw.c
@@ -52,7 +52,7 @@ typedef struct TrackMotionCurveUserData {
MovieTrackingTrack *act_track;
bool sel;
float xscale, yscale, hsize;
- unsigned int pos;
+ uint pos;
} TrackMotionCurveUserData;
static void tracking_segment_point_cb(void *userdata,
@@ -159,7 +159,7 @@ static void tracking_segment_knot_cb(void *userdata,
}
}
-static void draw_tracks_motion_and_error_curves(View2D *v2d, SpaceClip *sc, unsigned int pos)
+static void draw_tracks_motion_and_error_curves(View2D *v2d, SpaceClip *sc, uint pos)
{
MovieClip *clip = ED_space_clip_get_clip(sc);
MovieTracking *tracking = &clip->tracking;
@@ -215,36 +215,51 @@ static void draw_tracks_motion_and_error_curves(View2D *v2d, SpaceClip *sc, unsi
}
}
-static void draw_frame_curves(SpaceClip *sc, unsigned int pos)
+static void draw_frame_curves(SpaceClip *sc, uint pos)
{
MovieClip *clip = ED_space_clip_get_clip(sc);
MovieTracking *tracking = &clip->tracking;
MovieTrackingReconstruction *reconstruction = BKE_tracking_get_active_reconstruction(tracking);
- int i, lines = 0, prevfra = 0;
+
+ int previous_frame;
+ float previous_error;
+ bool have_previous_point = false;
+
+ /* Indicates whether immBegin() was called. */
+ bool is_lines_segment_open = false;
immUniformColor3f(0.0f, 0.0f, 1.0f);
- for (i = 0; i < reconstruction->camnr; i++) {
+ for (int i = 0; i < reconstruction->camnr; i++) {
MovieReconstructedCamera *camera = &reconstruction->cameras[i];
- int framenr;
- if (lines && camera->framenr != prevfra + 1) {
- immEnd();
- lines = 0;
- }
+ const int current_frame = BKE_movieclip_remap_clip_to_scene_frame(clip, camera->framenr);
+ const float current_error = camera->error;
- if (!lines) {
- immBeginAtMost(GPU_PRIM_LINE_STRIP, reconstruction->camnr);
- lines = 1;
+ if (have_previous_point && current_frame != previous_frame + 1) {
+ if (is_lines_segment_open) {
+ immEnd();
+ is_lines_segment_open = false;
+ }
+ have_previous_point = false;
}
- framenr = BKE_movieclip_remap_clip_to_scene_frame(clip, camera->framenr);
- immVertex2f(pos, framenr, camera->error);
+ if (have_previous_point) {
+ if (!is_lines_segment_open) {
+ immBeginAtMost(GPU_PRIM_LINE_STRIP, reconstruction->camnr);
+ is_lines_segment_open = true;
+
+ immVertex2f(pos, previous_frame, previous_error);
+ }
+ immVertex2f(pos, current_frame, current_error);
+ }
- prevfra = camera->framenr;
+ previous_frame = current_frame;
+ previous_error = current_error;
+ have_previous_point = true;
}
- if (lines) {
+ if (is_lines_segment_open) {
immEnd();
}
}
diff --git a/source/blender/editors/space_clip/clip_graph_ops.c b/source/blender/editors/space_clip/clip_graph_ops.c
index e974480a233..589831b1c45 100644
--- a/source/blender/editors/space_clip/clip_graph_ops.c
+++ b/source/blender/editors/space_clip/clip_graph_ops.c
@@ -671,7 +671,7 @@ static int view_all_exec(bContext *C, wmOperator *UNUSED(op))
void CLIP_OT_graph_view_all(wmOperatorType *ot)
{
/* identifiers */
- ot->name = "View All";
+ ot->name = "Frame All";
ot->description = "View all curves in editor";
ot->idname = "CLIP_OT_graph_view_all";
diff --git a/source/blender/editors/space_clip/clip_intern.h b/source/blender/editors/space_clip/clip_intern.h
index 4dc8d367f2b..27493bb5ccd 100644
--- a/source/blender/editors/space_clip/clip_intern.h
+++ b/source/blender/editors/space_clip/clip_intern.h
@@ -112,7 +112,7 @@ void CLIP_OT_cursor_set(struct wmOperatorType *ot);
void CLIP_OT_lock_selection_toggle(struct wmOperatorType *ot);
/* clip_toolbar.c */
-struct ARegion *ED_clip_has_properties_region(struct ScrArea *sa);
+struct ARegion *ED_clip_has_properties_region(struct ScrArea *area);
/* clip_utils.c */
diff --git a/source/blender/editors/space_clip/clip_ops.c b/source/blender/editors/space_clip/clip_ops.c
index 4e5c6513695..984aa0a63ad 100644
--- a/source/blender/editors/space_clip/clip_ops.c
+++ b/source/blender/editors/space_clip/clip_ops.c
@@ -286,7 +286,7 @@ static int open_invoke(bContext *C, wmOperator *op, const wmEvent *UNUSED(event)
BLI_strncpy(path, clip->name, sizeof(path));
BLI_path_abs(path, CTX_data_main(C)->name);
- BLI_parent_dir(path);
+ BLI_path_parent_dir(path);
}
else {
BLI_strncpy(path, U.textudir, sizeof(path));
@@ -784,7 +784,7 @@ void CLIP_OT_view_zoom_in(wmOperatorType *ot)
PropertyRNA *prop;
/* identifiers */
- ot->name = "View Zoom In";
+ ot->name = "Zoom In";
ot->idname = "CLIP_OT_view_zoom_in";
ot->description = "Zoom in the view";
@@ -841,7 +841,7 @@ void CLIP_OT_view_zoom_out(wmOperatorType *ot)
PropertyRNA *prop;
/* identifiers */
- ot->name = "View Zoom Out";
+ ot->name = "Zoom Out";
ot->idname = "CLIP_OT_view_zoom_out";
ot->description = "Zoom out the view";
@@ -975,7 +975,7 @@ void CLIP_OT_view_all(wmOperatorType *ot)
PropertyRNA *prop;
/* identifiers */
- ot->name = "View All";
+ ot->name = "Frame All";
ot->idname = "CLIP_OT_view_all";
ot->description = "View whole image with markers";
@@ -1313,12 +1313,12 @@ typedef struct ProxyThread {
int *build_undistort_sizes, build_undistort_count;
} ProxyThread;
-static unsigned char *proxy_thread_next_frame(ProxyQueue *queue,
- MovieClip *clip,
- size_t *r_size,
- int *r_cfra)
+static uchar *proxy_thread_next_frame(ProxyQueue *queue,
+ MovieClip *clip,
+ size_t *r_size,
+ int *r_cfra)
{
- unsigned char *mem = NULL;
+ uchar *mem = NULL;
BLI_spin_lock(&queue->spin);
if (!*queue->stop && queue->cfra <= queue->efra) {
@@ -1367,11 +1367,11 @@ static unsigned char *proxy_thread_next_frame(ProxyQueue *queue,
return mem;
}
-static void proxy_task_func(TaskPool *__restrict pool, void *task_data, int UNUSED(threadid))
+static void proxy_task_func(TaskPool *__restrict pool, void *task_data)
{
ProxyThread *data = (ProxyThread *)task_data;
- ProxyQueue *queue = (ProxyQueue *)BLI_task_pool_userdata(pool);
- unsigned char *mem;
+ ProxyQueue *queue = (ProxyQueue *)BLI_task_pool_user_data(pool);
+ uchar *mem;
size_t size;
int cfra;
@@ -1413,11 +1413,10 @@ static void do_sequence_proxy(void *pjv,
ProxyJob *pj = pjv;
MovieClip *clip = pj->clip;
Scene *scene = pj->scene;
- TaskScheduler *task_scheduler = BLI_task_scheduler_get();
TaskPool *task_pool;
int sfra = SFRA, efra = EFRA;
ProxyThread *handles;
- int i, tot_thread = BLI_task_scheduler_num_threads(task_scheduler);
+ int i, tot_thread = BLI_task_scheduler_num_threads();
int width, height;
ProxyQueue queue;
@@ -1434,7 +1433,7 @@ static void do_sequence_proxy(void *pjv,
queue.do_update = do_update;
queue.progress = progress;
- task_pool = BLI_task_pool_create(task_scheduler, &queue);
+ task_pool = BLI_task_pool_create(&queue, TASK_PRIORITY_LOW);
handles = MEM_callocN(sizeof(ProxyThread) * tot_thread, "proxy threaded handles");
for (i = 0; i < tot_thread; i++) {
ProxyThread *handle = &handles[i];
@@ -1451,7 +1450,7 @@ static void do_sequence_proxy(void *pjv,
handle->distortion = BKE_tracking_distortion_new(&clip->tracking, width, height);
}
- BLI_task_pool_push(task_pool, proxy_task_func, handle, false, TASK_PRIORITY_LOW);
+ BLI_task_pool_push(task_pool, proxy_task_func, handle, false, NULL);
}
BLI_task_pool_work_and_wait(task_pool);
@@ -1533,7 +1532,7 @@ static int clip_rebuild_proxy_exec(bContext *C, wmOperator *UNUSED(op))
wmJob *wm_job;
ProxyJob *pj;
Scene *scene = CTX_data_scene(C);
- ScrArea *sa = CTX_wm_area(C);
+ ScrArea *area = CTX_wm_area(C);
SpaceClip *sc = CTX_wm_space_clip(C);
MovieClip *clip = ED_space_clip_get_clip(sc);
@@ -1570,7 +1569,7 @@ static int clip_rebuild_proxy_exec(bContext *C, wmOperator *UNUSED(op))
G.is_break = false;
WM_jobs_start(CTX_wm_manager(C), wm_job);
- ED_area_tag_redraw(sa);
+ ED_area_tag_redraw(area);
return OPERATOR_FINISHED;
}
diff --git a/source/blender/editors/space_clip/clip_toolbar.c b/source/blender/editors/space_clip/clip_toolbar.c
index 1e3911863fc..b02f3fe16f6 100644
--- a/source/blender/editors/space_clip/clip_toolbar.c
+++ b/source/blender/editors/space_clip/clip_toolbar.c
@@ -53,17 +53,17 @@
/************************** properties ******************************/
-ARegion *ED_clip_has_properties_region(ScrArea *sa)
+ARegion *ED_clip_has_properties_region(ScrArea *area)
{
ARegion *region, *arnew;
- region = BKE_area_find_region_type(sa, RGN_TYPE_UI);
+ region = BKE_area_find_region_type(area, RGN_TYPE_UI);
if (region) {
return region;
}
/* add subdiv level; after header */
- region = BKE_area_find_region_type(sa, RGN_TYPE_HEADER);
+ region = BKE_area_find_region_type(area, RGN_TYPE_HEADER);
/* is error! */
if (region == NULL) {
@@ -72,7 +72,7 @@ ARegion *ED_clip_has_properties_region(ScrArea *sa)
arnew = MEM_callocN(sizeof(ARegion), "clip properties region");
- BLI_insertlinkafter(&sa->regionbase, region, arnew);
+ BLI_insertlinkafter(&area->regionbase, region, arnew);
arnew->regiontype = RGN_TYPE_UI;
arnew->alignment = RGN_ALIGN_RIGHT;
diff --git a/source/blender/editors/space_clip/clip_utils.c b/source/blender/editors/space_clip/clip_utils.c
index 4a0df454a78..03f791ad70d 100644
--- a/source/blender/editors/space_clip/clip_utils.c
+++ b/source/blender/editors/space_clip/clip_utils.c
@@ -166,7 +166,8 @@ static float calculate_reprojection_error_at_marker(MovieClip *clip,
reprojected_position[1] = (reprojected_position[1] / (reprojected_position[3] * 2.0f) + 0.5f) *
clip_height * aspy;
- BKE_tracking_distort_v2(tracking, reprojected_position, reprojected_position);
+ BKE_tracking_distort_v2(
+ tracking, clip_width, clip_height, reprojected_position, reprojected_position);
marker_position[0] = (marker->pos[0] + track->offset[0]) * clip_width;
marker_position[1] = (marker->pos[1] + track->offset[1]) * clip_height * aspy;
diff --git a/source/blender/editors/space_clip/space_clip.c b/source/blender/editors/space_clip/space_clip.c
index dad361db7e3..0dccd45578e 100644
--- a/source/blender/editors/space_clip/space_clip.c
+++ b/source/blender/editors/space_clip/space_clip.c
@@ -71,7 +71,7 @@
#include "clip_intern.h" /* own include */
static void init_preview_region(const Scene *scene,
- const ScrArea *sa,
+ const ScrArea *area,
const SpaceClip *sc,
ARegion *region)
{
@@ -81,8 +81,8 @@ static void init_preview_region(const Scene *scene,
if (sc->view == SC_VIEW_DOPESHEET) {
region->v2d.tot.xmin = -10.0f;
- region->v2d.tot.ymin = (float)(-sa->winy) / 3.0f;
- region->v2d.tot.xmax = (float)(sa->winx);
+ region->v2d.tot.ymin = (float)(-area->winy) / 3.0f;
+ region->v2d.tot.xmax = (float)(area->winx);
region->v2d.tot.ymax = 0.0f;
region->v2d.cur = region->v2d.tot;
@@ -133,32 +133,32 @@ static void init_preview_region(const Scene *scene,
static void reinit_preview_region(const bContext *C, ARegion *region)
{
Scene *scene = CTX_data_scene(C);
- ScrArea *sa = CTX_wm_area(C);
+ ScrArea *area = CTX_wm_area(C);
SpaceClip *sc = CTX_wm_space_clip(C);
if (sc->view == SC_VIEW_DOPESHEET) {
if ((region->v2d.flag & V2D_VIEWSYNC_AREA_VERTICAL) == 0) {
- init_preview_region(scene, sa, sc, region);
+ init_preview_region(scene, area, sc, region);
}
}
else {
if (region->v2d.flag & V2D_VIEWSYNC_AREA_VERTICAL) {
- init_preview_region(scene, sa, sc, region);
+ init_preview_region(scene, area, sc, region);
}
}
}
-static ARegion *ED_clip_has_preview_region(const bContext *C, ScrArea *sa)
+static ARegion *ED_clip_has_preview_region(const bContext *C, ScrArea *area)
{
ARegion *region, *arnew;
- region = BKE_area_find_region_type(sa, RGN_TYPE_PREVIEW);
+ region = BKE_area_find_region_type(area, RGN_TYPE_PREVIEW);
if (region) {
return region;
}
/* add subdiv level; after header */
- region = BKE_area_find_region_type(sa, RGN_TYPE_WINDOW);
+ region = BKE_area_find_region_type(area, RGN_TYPE_WINDOW);
/* is error! */
if (region == NULL) {
@@ -167,23 +167,23 @@ static ARegion *ED_clip_has_preview_region(const bContext *C, ScrArea *sa)
arnew = MEM_callocN(sizeof(ARegion), "clip preview region");
- BLI_insertlinkbefore(&sa->regionbase, region, arnew);
- init_preview_region(CTX_data_scene(C), sa, CTX_wm_space_clip(C), arnew);
+ BLI_insertlinkbefore(&area->regionbase, region, arnew);
+ init_preview_region(CTX_data_scene(C), area, CTX_wm_space_clip(C), arnew);
return arnew;
}
-static ARegion *ED_clip_has_channels_region(ScrArea *sa)
+static ARegion *ED_clip_has_channels_region(ScrArea *area)
{
ARegion *region, *arnew;
- region = BKE_area_find_region_type(sa, RGN_TYPE_CHANNELS);
+ region = BKE_area_find_region_type(area, RGN_TYPE_CHANNELS);
if (region) {
return region;
}
/* add subdiv level; after header */
- region = BKE_area_find_region_type(sa, RGN_TYPE_PREVIEW);
+ region = BKE_area_find_region_type(area, RGN_TYPE_PREVIEW);
/* is error! */
if (region == NULL) {
@@ -192,7 +192,7 @@ static ARegion *ED_clip_has_channels_region(ScrArea *sa)
arnew = MEM_callocN(sizeof(ARegion), "clip channels region");
- BLI_insertlinkbefore(&sa->regionbase, region, arnew);
+ BLI_insertlinkbefore(&area->regionbase, region, arnew);
arnew->regiontype = RGN_TYPE_CHANNELS;
arnew->alignment = RGN_ALIGN_LEFT;
@@ -202,9 +202,9 @@ static ARegion *ED_clip_has_channels_region(ScrArea *sa)
return arnew;
}
-static void clip_scopes_tag_refresh(ScrArea *sa)
+static void clip_scopes_tag_refresh(ScrArea *area)
{
- SpaceClip *sc = (SpaceClip *)sa->spacedata.first;
+ SpaceClip *sc = (SpaceClip *)area->spacedata.first;
ARegion *region;
if (sc->mode != SC_MODE_TRACKING) {
@@ -212,7 +212,7 @@ static void clip_scopes_tag_refresh(ScrArea *sa)
}
/* only while properties are visible */
- for (region = sa->regionbase.first; region; region = region->next) {
+ for (region = area->regionbase.first; region; region = region->next) {
if (region->regiontype == RGN_TYPE_UI && region->flag & RGN_FLAG_HIDDEN) {
return;
}
@@ -221,24 +221,24 @@ static void clip_scopes_tag_refresh(ScrArea *sa)
sc->scopes.ok = false;
}
-static void clip_scopes_check_gpencil_change(ScrArea *sa)
+static void clip_scopes_check_gpencil_change(ScrArea *area)
{
- SpaceClip *sc = (SpaceClip *)sa->spacedata.first;
+ SpaceClip *sc = (SpaceClip *)area->spacedata.first;
if (sc->gpencil_src == SC_GPENCIL_SRC_TRACK) {
- clip_scopes_tag_refresh(sa);
+ clip_scopes_tag_refresh(area);
}
}
-static void clip_area_sync_frame_from_scene(ScrArea *sa, Scene *scene)
+static void clip_area_sync_frame_from_scene(ScrArea *area, Scene *scene)
{
- SpaceClip *space_clip = (SpaceClip *)sa->spacedata.first;
+ SpaceClip *space_clip = (SpaceClip *)area->spacedata.first;
BKE_movieclip_user_set_frame(&space_clip->user, scene->r.cfra);
}
/* ******************** default callbacks for clip space ***************** */
-static SpaceLink *clip_new(const ScrArea *sa, const Scene *scene)
+static SpaceLink *clip_new(const ScrArea *area, const Scene *scene)
{
ARegion *region;
SpaceClip *sc;
@@ -287,7 +287,7 @@ static SpaceLink *clip_new(const ScrArea *sa, const Scene *scene)
region = MEM_callocN(sizeof(ARegion), "preview for clip");
BLI_addtail(&sc->regionbase, region);
- init_preview_region(scene, sa, sc, region);
+ init_preview_region(scene, area, sc, region);
/* main region */
region = MEM_callocN(sizeof(ARegion), "main region for clip");
@@ -326,18 +326,18 @@ static SpaceLink *clip_duplicate(SpaceLink *sl)
return (SpaceLink *)scn;
}
-static void clip_listener(wmWindow *UNUSED(win), ScrArea *sa, wmNotifier *wmn, Scene *scene)
+static void clip_listener(wmWindow *UNUSED(win), ScrArea *area, wmNotifier *wmn, Scene *scene)
{
/* context changes */
switch (wmn->category) {
case NC_SCENE:
switch (wmn->data) {
case ND_FRAME:
- clip_scopes_tag_refresh(sa);
+ clip_scopes_tag_refresh(area);
ATTR_FALLTHROUGH;
case ND_FRAME_RANGE:
- ED_area_tag_redraw(sa);
+ ED_area_tag_redraw(area);
break;
}
break;
@@ -345,8 +345,8 @@ static void clip_listener(wmWindow *UNUSED(win), ScrArea *sa, wmNotifier *wmn, S
switch (wmn->data) {
case ND_DISPLAY:
case ND_SELECT:
- clip_scopes_tag_refresh(sa);
- ED_area_tag_redraw(sa);
+ clip_scopes_tag_refresh(area);
+ ED_area_tag_redraw(area);
break;
}
switch (wmn->action) {
@@ -356,8 +356,8 @@ static void clip_listener(wmWindow *UNUSED(win), ScrArea *sa, wmNotifier *wmn, S
/* fall-through */
case NA_SELECTED:
- clip_scopes_tag_refresh(sa);
- ED_area_tag_redraw(sa);
+ clip_scopes_tag_refresh(area);
+ ED_area_tag_redraw(area);
break;
}
break;
@@ -366,56 +366,56 @@ static void clip_listener(wmWindow *UNUSED(win), ScrArea *sa, wmNotifier *wmn, S
case ND_SELECT:
case ND_DATA:
case ND_DRAW:
- ED_area_tag_redraw(sa);
+ ED_area_tag_redraw(area);
break;
}
switch (wmn->action) {
case NA_SELECTED:
- ED_area_tag_redraw(sa);
+ ED_area_tag_redraw(area);
break;
case NA_EDITED:
- ED_area_tag_redraw(sa);
+ ED_area_tag_redraw(area);
break;
}
break;
case NC_GEOM:
switch (wmn->data) {
case ND_SELECT:
- clip_scopes_tag_refresh(sa);
- ED_area_tag_redraw(sa);
+ clip_scopes_tag_refresh(area);
+ ED_area_tag_redraw(area);
break;
}
break;
case NC_SCREEN:
switch (wmn->data) {
case ND_ANIMPLAY:
- ED_area_tag_redraw(sa);
+ ED_area_tag_redraw(area);
break;
case ND_LAYOUTSET:
- clip_area_sync_frame_from_scene(sa, scene);
+ clip_area_sync_frame_from_scene(area, scene);
break;
}
break;
case NC_SPACE:
if (wmn->data == ND_SPACE_CLIP) {
- clip_scopes_tag_refresh(sa);
- ED_area_tag_redraw(sa);
+ clip_scopes_tag_refresh(area);
+ ED_area_tag_redraw(area);
}
break;
case NC_GPENCIL:
if (wmn->action == NA_EDITED) {
- clip_scopes_check_gpencil_change(sa);
- ED_area_tag_redraw(sa);
+ clip_scopes_check_gpencil_change(area);
+ ED_area_tag_redraw(area);
}
else if (wmn->data & ND_GPENCIL_EDITMODE) {
- ED_area_tag_redraw(sa);
+ ED_area_tag_redraw(area);
}
break;
case NC_WM:
switch (wmn->data) {
case ND_FILEREAD:
case ND_UNDO:
- clip_area_sync_frame_from_scene(sa, scene);
+ clip_area_sync_frame_from_scene(area, scene);
break;
}
break;
@@ -592,17 +592,17 @@ static int clip_context(const bContext *C, const char *member, bContextDataResul
return false;
}
-static void clip_refresh(const bContext *C, ScrArea *sa)
+static void clip_refresh(const bContext *C, ScrArea *area)
{
wmWindowManager *wm = CTX_wm_manager(C);
wmWindow *window = CTX_wm_window(C);
Scene *scene = CTX_data_scene(C);
- SpaceClip *sc = (SpaceClip *)sa->spacedata.first;
- ARegion *ar_main = BKE_area_find_region_type(sa, RGN_TYPE_WINDOW);
- ARegion *ar_tools = BKE_area_find_region_type(sa, RGN_TYPE_TOOLS);
- ARegion *ar_preview = ED_clip_has_preview_region(C, sa);
- ARegion *ar_properties = ED_clip_has_properties_region(sa);
- ARegion *ar_channels = ED_clip_has_channels_region(sa);
+ SpaceClip *sc = (SpaceClip *)area->spacedata.first;
+ ARegion *region_main = BKE_area_find_region_type(area, RGN_TYPE_WINDOW);
+ ARegion *region_tools = BKE_area_find_region_type(area, RGN_TYPE_TOOLS);
+ ARegion *region_preview = ED_clip_has_preview_region(C, area);
+ ARegion *region_properties = ED_clip_has_properties_region(area);
+ ARegion *region_channels = ED_clip_has_channels_region(area);
bool main_visible = false, preview_visible = false, tools_visible = false;
bool properties_visible = false, channels_visible = false;
bool view_changed = false;
@@ -622,7 +622,7 @@ static void clip_refresh(const bContext *C, ScrArea *sa)
properties_visible = false;
channels_visible = false;
- reinit_preview_region(C, ar_preview);
+ reinit_preview_region(C, region_preview);
break;
case SC_VIEW_DOPESHEET:
main_visible = false;
@@ -631,135 +631,135 @@ static void clip_refresh(const bContext *C, ScrArea *sa)
properties_visible = false;
channels_visible = true;
- reinit_preview_region(C, ar_preview);
+ reinit_preview_region(C, region_preview);
break;
}
if (main_visible) {
- if (ar_main && (ar_main->flag & RGN_FLAG_HIDDEN)) {
- ar_main->flag &= ~RGN_FLAG_HIDDEN;
- ar_main->v2d.flag &= ~V2D_IS_INITIALISED;
+ if (region_main && (region_main->flag & RGN_FLAG_HIDDEN)) {
+ region_main->flag &= ~RGN_FLAG_HIDDEN;
+ region_main->v2d.flag &= ~V2D_IS_INITIALISED;
view_changed = true;
}
- if (ar_main && ar_main->alignment != RGN_ALIGN_NONE) {
- ar_main->alignment = RGN_ALIGN_NONE;
+ if (region_main && region_main->alignment != RGN_ALIGN_NONE) {
+ region_main->alignment = RGN_ALIGN_NONE;
view_changed = true;
}
}
else {
- if (ar_main && !(ar_main->flag & RGN_FLAG_HIDDEN)) {
- ar_main->flag |= RGN_FLAG_HIDDEN;
- ar_main->v2d.flag &= ~V2D_IS_INITIALISED;
- WM_event_remove_handlers((bContext *)C, &ar_main->handlers);
+ if (region_main && !(region_main->flag & RGN_FLAG_HIDDEN)) {
+ region_main->flag |= RGN_FLAG_HIDDEN;
+ region_main->v2d.flag &= ~V2D_IS_INITIALISED;
+ WM_event_remove_handlers((bContext *)C, &region_main->handlers);
view_changed = true;
}
- if (ar_main && ar_main->alignment != RGN_ALIGN_NONE) {
- ar_main->alignment = RGN_ALIGN_NONE;
+ if (region_main && region_main->alignment != RGN_ALIGN_NONE) {
+ region_main->alignment = RGN_ALIGN_NONE;
view_changed = true;
}
}
if (properties_visible) {
- if (ar_properties && (ar_properties->flag & RGN_FLAG_HIDDEN)) {
- ar_properties->flag &= ~RGN_FLAG_HIDDEN;
- ar_properties->v2d.flag &= ~V2D_IS_INITIALISED;
+ if (region_properties && (region_properties->flag & RGN_FLAG_HIDDEN)) {
+ region_properties->flag &= ~RGN_FLAG_HIDDEN;
+ region_properties->v2d.flag &= ~V2D_IS_INITIALISED;
view_changed = true;
}
- if (ar_properties && ar_properties->alignment != RGN_ALIGN_RIGHT) {
- ar_properties->alignment = RGN_ALIGN_RIGHT;
+ if (region_properties && region_properties->alignment != RGN_ALIGN_RIGHT) {
+ region_properties->alignment = RGN_ALIGN_RIGHT;
view_changed = true;
}
}
else {
- if (ar_properties && !(ar_properties->flag & RGN_FLAG_HIDDEN)) {
- ar_properties->flag |= RGN_FLAG_HIDDEN;
- ar_properties->v2d.flag &= ~V2D_IS_INITIALISED;
- WM_event_remove_handlers((bContext *)C, &ar_properties->handlers);
+ if (region_properties && !(region_properties->flag & RGN_FLAG_HIDDEN)) {
+ region_properties->flag |= RGN_FLAG_HIDDEN;
+ region_properties->v2d.flag &= ~V2D_IS_INITIALISED;
+ WM_event_remove_handlers((bContext *)C, &region_properties->handlers);
view_changed = true;
}
- if (ar_properties && ar_properties->alignment != RGN_ALIGN_NONE) {
- ar_properties->alignment = RGN_ALIGN_NONE;
+ if (region_properties && region_properties->alignment != RGN_ALIGN_NONE) {
+ region_properties->alignment = RGN_ALIGN_NONE;
view_changed = true;
}
}
if (tools_visible) {
- if (ar_tools && (ar_tools->flag & RGN_FLAG_HIDDEN)) {
- ar_tools->flag &= ~RGN_FLAG_HIDDEN;
- ar_tools->v2d.flag &= ~V2D_IS_INITIALISED;
+ if (region_tools && (region_tools->flag & RGN_FLAG_HIDDEN)) {
+ region_tools->flag &= ~RGN_FLAG_HIDDEN;
+ region_tools->v2d.flag &= ~V2D_IS_INITIALISED;
view_changed = true;
}
- if (ar_tools && ar_tools->alignment != RGN_ALIGN_LEFT) {
- ar_tools->alignment = RGN_ALIGN_LEFT;
+ if (region_tools && region_tools->alignment != RGN_ALIGN_LEFT) {
+ region_tools->alignment = RGN_ALIGN_LEFT;
view_changed = true;
}
}
else {
- if (ar_tools && !(ar_tools->flag & RGN_FLAG_HIDDEN)) {
- ar_tools->flag |= RGN_FLAG_HIDDEN;
- ar_tools->v2d.flag &= ~V2D_IS_INITIALISED;
- WM_event_remove_handlers((bContext *)C, &ar_tools->handlers);
+ if (region_tools && !(region_tools->flag & RGN_FLAG_HIDDEN)) {
+ region_tools->flag |= RGN_FLAG_HIDDEN;
+ region_tools->v2d.flag &= ~V2D_IS_INITIALISED;
+ WM_event_remove_handlers((bContext *)C, &region_tools->handlers);
view_changed = true;
}
- if (ar_tools && ar_tools->alignment != RGN_ALIGN_NONE) {
- ar_tools->alignment = RGN_ALIGN_NONE;
+ if (region_tools && region_tools->alignment != RGN_ALIGN_NONE) {
+ region_tools->alignment = RGN_ALIGN_NONE;
view_changed = true;
}
}
if (preview_visible) {
- if (ar_preview && (ar_preview->flag & RGN_FLAG_HIDDEN)) {
- ar_preview->flag &= ~RGN_FLAG_HIDDEN;
- ar_preview->v2d.flag &= ~V2D_IS_INITIALISED;
- ar_preview->v2d.cur = ar_preview->v2d.tot;
+ if (region_preview && (region_preview->flag & RGN_FLAG_HIDDEN)) {
+ region_preview->flag &= ~RGN_FLAG_HIDDEN;
+ region_preview->v2d.flag &= ~V2D_IS_INITIALISED;
+ region_preview->v2d.cur = region_preview->v2d.tot;
view_changed = true;
}
- if (ar_preview && ar_preview->alignment != RGN_ALIGN_NONE) {
- ar_preview->alignment = RGN_ALIGN_NONE;
+ if (region_preview && region_preview->alignment != RGN_ALIGN_NONE) {
+ region_preview->alignment = RGN_ALIGN_NONE;
view_changed = true;
}
}
else {
- if (ar_preview && !(ar_preview->flag & RGN_FLAG_HIDDEN)) {
- ar_preview->flag |= RGN_FLAG_HIDDEN;
- ar_preview->v2d.flag &= ~V2D_IS_INITIALISED;
- WM_event_remove_handlers((bContext *)C, &ar_preview->handlers);
+ if (region_preview && !(region_preview->flag & RGN_FLAG_HIDDEN)) {
+ region_preview->flag |= RGN_FLAG_HIDDEN;
+ region_preview->v2d.flag &= ~V2D_IS_INITIALISED;
+ WM_event_remove_handlers((bContext *)C, &region_preview->handlers);
view_changed = true;
}
- if (ar_preview && ar_preview->alignment != RGN_ALIGN_NONE) {
- ar_preview->alignment = RGN_ALIGN_NONE;
+ if (region_preview && region_preview->alignment != RGN_ALIGN_NONE) {
+ region_preview->alignment = RGN_ALIGN_NONE;
view_changed = true;
}
}
if (channels_visible) {
- if (ar_channels && (ar_channels->flag & RGN_FLAG_HIDDEN)) {
- ar_channels->flag &= ~RGN_FLAG_HIDDEN;
- ar_channels->v2d.flag &= ~V2D_IS_INITIALISED;
+ if (region_channels && (region_channels->flag & RGN_FLAG_HIDDEN)) {
+ region_channels->flag &= ~RGN_FLAG_HIDDEN;
+ region_channels->v2d.flag &= ~V2D_IS_INITIALISED;
view_changed = true;
}
- if (ar_channels && ar_channels->alignment != RGN_ALIGN_LEFT) {
- ar_channels->alignment = RGN_ALIGN_LEFT;
+ if (region_channels && region_channels->alignment != RGN_ALIGN_LEFT) {
+ region_channels->alignment = RGN_ALIGN_LEFT;
view_changed = true;
}
}
else {
- if (ar_channels && !(ar_channels->flag & RGN_FLAG_HIDDEN)) {
- ar_channels->flag |= RGN_FLAG_HIDDEN;
- ar_channels->v2d.flag &= ~V2D_IS_INITIALISED;
- WM_event_remove_handlers((bContext *)C, &ar_channels->handlers);
+ if (region_channels && !(region_channels->flag & RGN_FLAG_HIDDEN)) {
+ region_channels->flag |= RGN_FLAG_HIDDEN;
+ region_channels->v2d.flag &= ~V2D_IS_INITIALISED;
+ WM_event_remove_handlers((bContext *)C, &region_channels->handlers);
view_changed = true;
}
- if (ar_channels && ar_channels->alignment != RGN_ALIGN_NONE) {
- ar_channels->alignment = RGN_ALIGN_NONE;
+ if (region_channels && region_channels->alignment != RGN_ALIGN_NONE) {
+ region_channels->alignment = RGN_ALIGN_NONE;
view_changed = true;
}
}
if (view_changed) {
- ED_area_initialize(wm, window, sa);
- ED_area_tag_redraw(sa);
+ ED_area_initialize(wm, window, area);
+ ED_area_tag_redraw(area);
}
BKE_movieclip_user_set_frame(&sc->user, scene->r.cfra);
@@ -899,9 +899,9 @@ static void clip_main_region_draw(const bContext *C, ARegion *region)
if (sc->mode == SC_MODE_MASKEDIT) {
Mask *mask = CTX_data_edit_mask(C);
if (mask && clip) {
- ScrArea *sa = CTX_wm_area(C);
+ ScrArea *area = CTX_wm_area(C);
int mask_width, mask_height;
- ED_mask_get_size(sa, &mask_width, &mask_height);
+ ED_mask_get_size(area, &mask_width, &mask_height);
ED_mask_draw_region(CTX_data_expect_evaluated_depsgraph(C),
mask,
region,
@@ -954,7 +954,7 @@ static void clip_main_region_draw(const bContext *C, ARegion *region)
}
static void clip_main_region_listener(wmWindow *UNUSED(win),
- ScrArea *UNUSED(sa),
+ ScrArea *UNUSED(area),
ARegion *region,
wmNotifier *wmn,
const Scene *UNUSED(scene))
@@ -1098,7 +1098,7 @@ static void clip_preview_region_draw(const bContext *C, ARegion *region)
}
static void clip_preview_region_listener(wmWindow *UNUSED(win),
- ScrArea *UNUSED(sa),
+ ScrArea *UNUSED(area),
ARegion *UNUSED(region),
wmNotifier *UNUSED(wmn),
const Scene *UNUSED(scene))
@@ -1144,7 +1144,7 @@ static void clip_channels_region_draw(const bContext *C, ARegion *region)
}
static void clip_channels_region_listener(wmWindow *UNUSED(win),
- ScrArea *UNUSED(sa),
+ ScrArea *UNUSED(area),
ARegion *UNUSED(region),
wmNotifier *UNUSED(wmn),
const Scene *UNUSED(scene))
@@ -1165,7 +1165,7 @@ static void clip_header_region_draw(const bContext *C, ARegion *region)
}
static void clip_header_region_listener(wmWindow *UNUSED(win),
- ScrArea *UNUSED(sa),
+ ScrArea *UNUSED(area),
ARegion *region,
wmNotifier *wmn,
const Scene *UNUSED(scene))
@@ -1208,7 +1208,7 @@ static void clip_tools_region_draw(const bContext *C, ARegion *region)
/****************** tool properties region ******************/
static void clip_props_region_listener(wmWindow *UNUSED(win),
- ScrArea *UNUSED(sa),
+ ScrArea *UNUSED(area),
ARegion *region,
wmNotifier *wmn,
const Scene *UNUSED(scene))
@@ -1261,7 +1261,7 @@ static void clip_properties_region_draw(const bContext *C, ARegion *region)
}
static void clip_properties_region_listener(wmWindow *UNUSED(win),
- ScrArea *UNUSED(sa),
+ ScrArea *UNUSED(area),
ARegion *region,
wmNotifier *wmn,
const Scene *UNUSED(scene))
@@ -1283,7 +1283,7 @@ static void clip_properties_region_listener(wmWindow *UNUSED(win),
/********************* registration ********************/
-static void clip_id_remap(ScrArea *UNUSED(sa), SpaceLink *slink, ID *old_id, ID *new_id)
+static void clip_id_remap(ScrArea *UNUSED(area), SpaceLink *slink, ID *old_id, ID *new_id)
{
SpaceClip *sclip = (SpaceClip *)slink;
diff --git a/source/blender/editors/space_clip/tracking_select.c b/source/blender/editors/space_clip/tracking_select.c
index 67c453825f7..81cc858c69f 100644
--- a/source/blender/editors/space_clip/tracking_select.c
+++ b/source/blender/editors/space_clip/tracking_select.c
@@ -387,7 +387,8 @@ static int mouse_select(bContext *C, const float co[2], const bool extend, const
WM_event_add_notifier(C, NC_GEOM | ND_SELECT, NULL);
DEG_id_tag_update(&clip->id, ID_RECALC_SELECT);
- return OPERATOR_FINISHED;
+ /* Pass-through + finished to allow tweak to transform. */
+ return OPERATOR_FINISHED | OPERATOR_PASS_THROUGH;
}
static bool select_poll(bContext *C)
@@ -597,8 +598,8 @@ void CLIP_OT_select_box(wmOperatorType *ot)
/********************** lasso select operator *********************/
static int do_lasso_select_marker(bContext *C,
- const int mcords[][2],
- const short moves,
+ const int mcoords[][2],
+ const int mcoords_len,
bool select)
{
SpaceClip *sc = CTX_wm_space_clip(C);
@@ -615,7 +616,7 @@ static int do_lasso_select_marker(bContext *C,
int framenr = ED_space_clip_get_clip_frame_number(sc);
/* get rectangle from operator */
- BLI_lasso_boundbox(&rect, mcords, moves);
+ BLI_lasso_boundbox(&rect, mcoords, mcoords_len);
/* do actual selection */
track = tracksbase->first;
@@ -630,7 +631,8 @@ static int do_lasso_select_marker(bContext *C,
ED_clip_point_stable_pos__reverse(sc, region, marker->pos, screen_co);
if (BLI_rcti_isect_pt(&rect, screen_co[0], screen_co[1]) &&
- BLI_lasso_is_point_inside(mcords, moves, screen_co[0], screen_co[1], V2D_IS_CLIPPED)) {
+ BLI_lasso_is_point_inside(
+ mcoords, mcoords_len, screen_co[0], screen_co[1], V2D_IS_CLIPPED)) {
if (select) {
BKE_tracking_track_flag_set(track, TRACK_AREA_ALL, SELECT);
}
@@ -658,7 +660,8 @@ static int do_lasso_select_marker(bContext *C,
ED_clip_point_stable_pos__reverse(sc, region, plane_marker->corners[i], screen_co);
if (BLI_rcti_isect_pt(&rect, screen_co[0], screen_co[1]) &&
- BLI_lasso_is_point_inside(mcords, moves, screen_co[0], screen_co[1], V2D_IS_CLIPPED)) {
+ BLI_lasso_is_point_inside(
+ mcoords, mcoords_len, screen_co[0], screen_co[1], V2D_IS_CLIPPED)) {
if (select) {
plane_track->flag |= SELECT;
}
@@ -684,10 +687,10 @@ static int do_lasso_select_marker(bContext *C,
static int clip_lasso_select_exec(bContext *C, wmOperator *op)
{
- int mcords_tot;
- const int(*mcords)[2] = WM_gesture_lasso_path_to_array(C, op, &mcords_tot);
+ int mcoords_len;
+ const int(*mcoords)[2] = WM_gesture_lasso_path_to_array(C, op, &mcoords_len);
- if (mcords) {
+ if (mcoords) {
const eSelectOp sel_op = RNA_enum_get(op->ptr, "mode");
const bool select = (sel_op != SEL_OP_SUB);
if (SEL_OP_USE_PRE_DESELECT(sel_op)) {
@@ -695,9 +698,9 @@ static int clip_lasso_select_exec(bContext *C, wmOperator *op)
ED_clip_select_all(sc, SEL_DESELECT, NULL);
}
- do_lasso_select_marker(C, mcords, mcords_tot, select);
+ do_lasso_select_marker(C, mcoords, mcoords_len, select);
- MEM_freeN((void *)mcords);
+ MEM_freeN((void *)mcoords);
return OPERATOR_FINISHED;
}
diff --git a/source/blender/editors/space_console/console_draw.c b/source/blender/editors/space_console/console_draw.c
index 6c56e8dfb79..805e9608fec 100644
--- a/source/blender/editors/space_console/console_draw.c
+++ b/source/blender/editors/space_console/console_draw.c
@@ -91,7 +91,6 @@ void console_scrollback_prompt_end(SpaceConsole *sc, ConsoleLine *cl_dummy)
static int console_textview_begin(TextViewContext *tvc)
{
SpaceConsole *sc = (SpaceConsole *)tvc->arg1;
- tvc->lheight = sc->lheight * UI_DPI_FAC;
tvc->sel_start = sc->sel_start;
tvc->sel_end = sc->sel_end;
@@ -143,10 +142,7 @@ static void console_cursor_wrap_offset(
return;
}
-static void console_textview_draw_cursor(TextViewContext *tvc,
- int cwidth,
- int columns,
- int descender)
+static void console_textview_draw_cursor(TextViewContext *tvc, int cwidth, int columns)
{
int pen[2];
{
@@ -157,10 +153,10 @@ static void console_textview_draw_cursor(TextViewContext *tvc,
console_cursor_wrap_offset(sc->prompt, columns, &offl, &offc, NULL);
console_cursor_wrap_offset(cl->line, columns, &offl, &offc, cl->line + cl->cursor);
pen[0] = cwidth * offc;
- pen[1] = -2 - (tvc->lheight + descender) * offl;
+ pen[1] = -tvc->lheight * offl;
console_cursor_wrap_offset(cl->line + cl->cursor, columns, &offl, &offc, NULL);
- pen[1] += (tvc->lheight + descender) * offl;
+ pen[1] += tvc->lheight * offl;
pen[0] += tvc->draw_rect.xmin;
pen[1] += tvc->draw_rect.ymin;
@@ -172,8 +168,7 @@ static void console_textview_draw_cursor(TextViewContext *tvc,
immBindBuiltinProgram(GPU_SHADER_2D_UNIFORM_COLOR);
immUniformThemeColor(TH_CONSOLE_CURSOR);
- immRectf(
- pos, pen[0] - U.pixelsize, pen[1], pen[0] + U.pixelsize, pen[1] + tvc->lheight + descender);
+ immRectf(pos, pen[0] - U.pixelsize, pen[1], pen[0] + U.pixelsize, pen[1] + tvc->lheight);
immUnbindProgram();
}
@@ -229,7 +224,7 @@ static int console_textview_main__internal(SpaceConsole *sc,
/* view */
tvc.sel_start = sc->sel_start;
tvc.sel_end = sc->sel_end;
- tvc.lheight = sc->lheight * 1.2f * UI_DPI_FAC;
+ tvc.lheight = sc->lheight * UI_DPI_FAC;
tvc.scroll_ymin = v2d->cur.ymin;
tvc.scroll_ymax = v2d->cur.ymax;
diff --git a/source/blender/editors/space_console/console_ops.c b/source/blender/editors/space_console/console_ops.c
index 58d6fb425b0..981e056fa63 100644
--- a/source/blender/editors/space_console/console_ops.c
+++ b/source/blender/editors/space_console/console_ops.c
@@ -353,10 +353,10 @@ static int console_move_exec(bContext *C, wmOperator *op)
}
if (done) {
- ScrArea *sa = CTX_wm_area(C);
+ ScrArea *area = CTX_wm_area(C);
ARegion *region = CTX_wm_region(C);
- ED_area_tag_redraw(sa);
+ ED_area_tag_redraw(area);
console_scroll_bottom(region);
}
@@ -860,7 +860,7 @@ static int console_history_append_exec(bContext *C, wmOperator *op)
{
SpaceConsole *sc = CTX_wm_space_console(C);
ARegion *region = CTX_wm_region(C);
- ScrArea *sa = CTX_wm_area(C);
+ ScrArea *area = CTX_wm_area(C);
ConsoleLine *ci = console_history_verify(C);
/* own this text in the new line, don't free */
char *str = RNA_string_get_alloc(op->ptr, "text", NULL, 0);
@@ -885,7 +885,7 @@ static int console_history_append_exec(bContext *C, wmOperator *op)
console_select_offset(sc, ci->len - prev_len);
console_line_cursor_set(ci, cursor);
- ED_area_tag_redraw(sa);
+ ED_area_tag_redraw(area);
/* when calling render modally this can be NULL when calling:
* bpy.ops.render.render('INVOKE_DEFAULT') */
diff --git a/source/blender/editors/space_console/space_console.c b/source/blender/editors/space_console/space_console.c
index 4214d43fe5f..3f1e4f8292f 100644
--- a/source/blender/editors/space_console/space_console.c
+++ b/source/blender/editors/space_console/space_console.c
@@ -98,7 +98,7 @@ static void console_free(SpaceLink *sl)
}
/* spacetype; init callback */
-static void console_init(struct wmWindowManager *UNUSED(wm), ScrArea *UNUSED(sa))
+static void console_init(struct wmWindowManager *UNUSED(wm), ScrArea *UNUSED(area))
{
}
@@ -140,7 +140,7 @@ static void console_main_region_init(wmWindowManager *wm, ARegion *region)
}
/* same as 'text_cursor' */
-static void console_cursor(wmWindow *win, ScrArea *UNUSED(sa), ARegion *region)
+static void console_cursor(wmWindow *win, ScrArea *UNUSED(area), ARegion *region)
{
int wmcursor = WM_CURSOR_TEXT_EDIT;
const wmEvent *event = win->eventstate;
@@ -228,19 +228,19 @@ static void console_header_region_draw(const bContext *C, ARegion *region)
}
static void console_main_region_listener(wmWindow *UNUSED(win),
- ScrArea *sa,
+ ScrArea *area,
ARegion *region,
wmNotifier *wmn,
const Scene *UNUSED(scene))
{
- // SpaceInfo *sinfo = sa->spacedata.first;
+ // SpaceInfo *sinfo = area->spacedata.first;
/* context changes */
switch (wmn->category) {
case NC_SPACE: {
if (wmn->data == ND_SPACE_CONSOLE) {
if (wmn->action == NA_EDITED) {
- if ((wmn->reference && sa) && (wmn->reference == sa->spacedata.first)) {
+ if ((wmn->reference && area) && (wmn->reference == area->spacedata.first)) {
/* we've modified the geometry (font size), re-calculate rect */
console_textview_update_rect(wmn->reference, region);
ED_region_tag_redraw(region);
diff --git a/source/blender/editors/space_file/file_draw.c b/source/blender/editors/space_file/file_draw.c
index 5f5aced292d..8d14664c0fa 100644
--- a/source/blender/editors/space_file/file_draw.c
+++ b/source/blender/editors/space_file/file_draw.c
@@ -220,7 +220,8 @@ static void file_draw_preview(uiBlock *block,
const bool is_icon,
const int typeflags,
const bool drag,
- const bool dimmed)
+ const bool dimmed,
+ const bool is_link)
{
uiBut *but;
float fx, fy;
@@ -312,37 +313,57 @@ static void file_draw_preview(uiBlock *block,
GPU_blend_set_func_separate(
GPU_SRC_ALPHA, GPU_ONE_MINUS_SRC_ALPHA, GPU_ONE, GPU_ONE_MINUS_SRC_ALPHA);
- if (icon && !(typeflags & FILE_TYPE_FTFONT)) {
- /* size of center icon is scaled to fit container and UI scale */
+ if (icon && is_icon) {
+ /* Small icon in the middle of large image, scaled to fit container and UI scale */
float icon_x, icon_y;
-
- if (is_icon) {
- const float icon_size = 16.0f / icon_aspect * U.dpi_fac;
- float icon_opacity = 0.3f;
- uchar icon_color[4] = {0, 0, 0, 255};
- float bgcolor[4];
- UI_GetThemeColor4fv(TH_ICON_FOLDER, bgcolor);
- if (rgb_to_grayscale(bgcolor) < 0.5f) {
- icon_color[0] = 255;
- icon_color[1] = 255;
- icon_color[2] = 255;
- }
- icon_x = xco + (ex / 2.0f) - (icon_size / 2.0f);
- icon_y = yco + (ey / 2.0f) - (icon_size * ((typeflags & FILE_TYPE_DIR) ? 0.78f : 0.75f));
- UI_icon_draw_ex(
- icon_x, icon_y, icon, icon_aspect / U.dpi_fac, icon_opacity, 0.0f, icon_color, false);
+ const float icon_size = 16.0f / icon_aspect * U.dpi_fac;
+ float icon_opacity = 0.3f;
+ uchar icon_color[4] = {0, 0, 0, 255};
+ float bgcolor[4];
+ UI_GetThemeColor4fv(TH_ICON_FOLDER, bgcolor);
+ if (rgb_to_grayscale(bgcolor) < 0.5f) {
+ icon_color[0] = 255;
+ icon_color[1] = 255;
+ icon_color[2] = 255;
}
- else {
+ icon_x = xco + (ex / 2.0f) - (icon_size / 2.0f);
+ icon_y = yco + (ey / 2.0f) - (icon_size * ((typeflags & FILE_TYPE_DIR) ? 0.78f : 0.75f));
+ UI_icon_draw_ex(
+ icon_x, icon_y, icon, icon_aspect / U.dpi_fac, icon_opacity, 0.0f, icon_color, false);
+ }
+
+ if (is_link) {
+ /* Arrow icon to indicate it is a shortcut, link, or alias. */
+ float icon_x, icon_y;
+ icon_x = xco + (2.0f * UI_DPI_FAC);
+ icon_y = yco + (2.0f * UI_DPI_FAC);
+ const int arrow = ICON_LOOP_FORWARDS;
+ if (!is_icon) {
+ /* Arrow at very bottom-left if preview style. */
const uchar dark[4] = {0, 0, 0, 255};
const uchar light[4] = {255, 255, 255, 255};
-
- /* Smaller, fainter icon for preview image thumbnail. */
- icon_x = xco + (2.0f * UI_DPI_FAC);
- icon_y = yco + (2.0f * UI_DPI_FAC);
-
- UI_icon_draw_ex(icon_x + 1, icon_y - 1, icon, 1.0f / U.dpi_fac, 0.2f, 0.0f, dark, false);
- UI_icon_draw_ex(icon_x, icon_y, icon, 1.0f / U.dpi_fac, 0.6f, 0.0f, light, false);
+ UI_icon_draw_ex(icon_x + 1, icon_y - 1, arrow, 1.0f / U.dpi_fac, 0.2f, 0.0f, dark, false);
+ UI_icon_draw_ex(icon_x, icon_y, arrow, 1.0f / U.dpi_fac, 0.6f, 0.0f, light, false);
}
+ else {
+ /* Link to folder or non-previewed file. */
+ uchar icon_color[4];
+ UI_GetThemeColor4ubv(TH_BACK, icon_color);
+ icon_x = xco + ((typeflags & FILE_TYPE_DIR) ? 0.14f : 0.23f) * scaledx;
+ icon_y = yco + ((typeflags & FILE_TYPE_DIR) ? 0.24f : 0.14f) * scaledy;
+ UI_icon_draw_ex(
+ icon_x, icon_y, arrow, icon_aspect / U.dpi_fac * 1.8, 0.3f, 0.0f, icon_color, false);
+ }
+ }
+ else if (icon && !is_icon && !(typeflags & FILE_TYPE_FTFONT)) {
+ /* Smaller, fainter icon at bottom-left for preview image thumbnail, but not for fonts. */
+ float icon_x, icon_y;
+ const uchar dark[4] = {0, 0, 0, 255};
+ const uchar light[4] = {255, 255, 255, 255};
+ icon_x = xco + (2.0f * UI_DPI_FAC);
+ icon_y = yco + (2.0f * UI_DPI_FAC);
+ UI_icon_draw_ex(icon_x + 1, icon_y - 1, icon, 1.0f / U.dpi_fac, 0.2f, 0.0f, dark, false);
+ UI_icon_draw_ex(icon_x, icon_y, icon, 1.0f / U.dpi_fac, 0.6f, 0.0f, light, false);
}
/* Contrasting outline around some preview types. */
@@ -448,7 +469,7 @@ static void draw_dividers(FileLayout *layout, View2D *v2d)
const int step = (layout->tile_w + 2 * layout->tile_border_x);
- unsigned int vertex_len = 0;
+ uint vertex_len = 0;
int sx = (int)v2d->tot.xmin;
while (sx < v2d->cur.xmax) {
sx += step;
@@ -457,7 +478,7 @@ static void draw_dividers(FileLayout *layout, View2D *v2d)
if (vertex_len > 0) {
int v1[2], v2[2];
- unsigned char col_hi[3], col_lo[3];
+ uchar col_hi[3], col_lo[3];
UI_GetThemeColorShade3ubv(TH_BACK, 30, col_hi);
UI_GetThemeColorShade3ubv(TH_BACK, -30, col_lo);
@@ -685,7 +706,7 @@ void file_draw_list(const bContext *C, ARegion *region)
bool is_icon;
eFontStyle_Align align;
bool do_drag;
- unsigned char text_col[4];
+ uchar text_col[4];
const bool draw_columnheader = (params->display == FILE_VERTICALDISPLAY);
const float thumb_icon_aspect = MIN2(64.0f / (float)(params->thumbnail_size), 1.0f);
@@ -753,7 +774,7 @@ void file_draw_list(const bContext *C, ARegion *region)
UI_GetThemeColor4ubv(TH_TEXT, text_col);
for (i = offset; (i < numfiles) && (i < offset + numfiles_layout); i++) {
- unsigned int file_selflag;
+ uint file_selflag;
char path[FILE_MAX_LIBEXTRA];
int padx = 0.1f * UI_UNIT_X;
int icon_ofs = 0;
@@ -788,6 +809,7 @@ void file_draw_list(const bContext *C, ARegion *region)
/* don't drag parent or refresh items */
do_drag = !(FILENAME_IS_CURRPAR(file->relpath));
const bool is_hidden = (file->attributes & FILE_ATTR_HIDDEN);
+ const bool is_link = (file->attributes & FILE_ATTR_ANY_LINK);
if (FILE_IMGDISPLAY == params->display) {
const int icon = filelist_geticon(files, i, false);
@@ -809,7 +831,8 @@ void file_draw_list(const bContext *C, ARegion *region)
is_icon,
file->typeflag,
do_drag,
- is_hidden);
+ is_hidden,
+ is_link);
}
else {
file_draw_icon(block,
diff --git a/source/blender/editors/space_file/file_ops.c b/source/blender/editors/space_file/file_ops.c
index 5258892d55d..41d32fda088 100644
--- a/source/blender/editors/space_file/file_ops.c
+++ b/source/blender/editors/space_file/file_ops.c
@@ -103,7 +103,7 @@ static FileSelection find_file_mouse_rect(SpaceFile *sfile,
return sel;
}
-static void file_deselect_all(SpaceFile *sfile, unsigned int flag)
+static void file_deselect_all(SpaceFile *sfile, uint flag)
{
FileSelection sel;
sel.first = 0;
@@ -211,7 +211,7 @@ static FileSelect file_select_do(bContext *C, int selected_idx, bool do_diropen)
else {
if (is_parent_dir) {
/* avoids /../../ */
- BLI_parent_dir(params->dir);
+ BLI_path_parent_dir(params->dir);
if (params->recursion_level > 1) {
/* Disable 'dirtree' recursion when going up in tree. */
@@ -220,9 +220,9 @@ static FileSelect file_select_do(bContext *C, int selected_idx, bool do_diropen)
}
}
else {
- BLI_cleanup_dir(BKE_main_blendfile_path(bmain), params->dir);
+ BLI_path_normalize_dir(BKE_main_blendfile_path(bmain), params->dir);
strcat(params->dir, file->relpath);
- BLI_add_slash(params->dir);
+ BLI_path_slash_ensure(params->dir);
}
ED_file_change_dir(C);
@@ -851,7 +851,7 @@ void FILE_OT_select_walk(wmOperatorType *ot)
static int file_select_all_exec(bContext *C, wmOperator *op)
{
- ScrArea *sa = CTX_wm_area(C);
+ ScrArea *area = CTX_wm_area(C);
SpaceFile *sfile = CTX_wm_space_file(C);
FileSelection sel;
const int numfiles = filelist_files_ensure(sfile->files);
@@ -900,7 +900,7 @@ static int file_select_all_exec(bContext *C, wmOperator *op)
file_draw_check(C);
WM_event_add_mousemove(CTX_wm_window(C));
- ED_area_tag_redraw(sa);
+ ED_area_tag_redraw(area);
return OPERATOR_FINISHED;
}
@@ -940,7 +940,7 @@ static int bookmark_select_exec(bContext *C, wmOperator *op)
RNA_property_string_get(op->ptr, prop, entry);
BLI_strncpy(params->dir, entry, sizeof(params->dir));
- BLI_cleanup_dir(BKE_main_blendfile_path(bmain), params->dir);
+ BLI_path_normalize_dir(BKE_main_blendfile_path(bmain), params->dir);
ED_file_change_dir(C);
WM_event_add_notifier(C, NC_SPACE | ND_SPACE_FILE_LIST, NULL);
@@ -975,7 +975,7 @@ void FILE_OT_select_bookmark(wmOperatorType *ot)
static int bookmark_add_exec(bContext *C, wmOperator *UNUSED(op))
{
- ScrArea *sa = CTX_wm_area(C);
+ ScrArea *area = CTX_wm_area(C);
SpaceFile *sfile = CTX_wm_space_file(C);
struct FSMenu *fsmenu = ED_fsmenu_get();
struct FileSelectParams *params = ED_fileselect_get_params(sfile);
@@ -992,8 +992,8 @@ static int bookmark_add_exec(bContext *C, wmOperator *UNUSED(op))
fsmenu_write_file(fsmenu, name);
}
- ED_area_tag_refresh(sa);
- ED_area_tag_redraw(sa);
+ ED_area_tag_refresh(area);
+ ED_area_tag_redraw(area);
return OPERATOR_FINISHED;
}
@@ -1017,7 +1017,7 @@ void FILE_OT_bookmark_add(wmOperatorType *ot)
static int bookmark_delete_exec(bContext *C, wmOperator *op)
{
- ScrArea *sa = CTX_wm_area(C);
+ ScrArea *area = CTX_wm_area(C);
SpaceFile *sfile = CTX_wm_space_file(C);
struct FSMenu *fsmenu = ED_fsmenu_get();
int nentries = ED_fsmenu_get_nentries(fsmenu, FS_CATEGORY_BOOKMARKS);
@@ -1041,8 +1041,8 @@ static int bookmark_delete_exec(bContext *C, wmOperator *op)
BKE_appdir_folder_id_create(BLENDER_USER_CONFIG, NULL),
BLENDER_BOOKMARK_FILE);
fsmenu_write_file(fsmenu, name);
- ED_area_tag_refresh(sa);
- ED_area_tag_redraw(sa);
+ ED_area_tag_refresh(area);
+ ED_area_tag_redraw(area);
}
}
@@ -1075,7 +1075,7 @@ void FILE_OT_bookmark_delete(wmOperatorType *ot)
static int bookmark_cleanup_exec(bContext *C, wmOperator *UNUSED(op))
{
- ScrArea *sa = CTX_wm_area(C);
+ ScrArea *area = CTX_wm_area(C);
struct FSMenu *fsmenu = ED_fsmenu_get();
struct FSMenuEntry *fsme_next, *fsme = ED_fsmenu_get_category(fsmenu, FS_CATEGORY_BOOKMARKS);
int index;
@@ -1102,8 +1102,8 @@ static int bookmark_cleanup_exec(bContext *C, wmOperator *UNUSED(op))
BLENDER_BOOKMARK_FILE);
fsmenu_write_file(fsmenu, name);
fsmenu_refresh_bookmarks_status(CTX_wm_manager(C), fsmenu);
- ED_area_tag_refresh(sa);
- ED_area_tag_redraw(sa);
+ ED_area_tag_refresh(area);
+ ED_area_tag_redraw(area);
}
return OPERATOR_FINISHED;
@@ -1138,7 +1138,7 @@ enum {
static int bookmark_move_exec(bContext *C, wmOperator *op)
{
- ScrArea *sa = CTX_wm_area(C);
+ ScrArea *area = CTX_wm_area(C);
SpaceFile *sfile = CTX_wm_space_file(C);
struct FSMenu *fsmenu = ED_fsmenu_get();
struct FSMenuEntry *fsmentry = ED_fsmenu_get_category(fsmenu, FS_CATEGORY_BOOKMARKS);
@@ -1187,7 +1187,7 @@ static int bookmark_move_exec(bContext *C, wmOperator *op)
BLENDER_BOOKMARK_FILE);
fsmenu_write_file(fsmenu, fname);
- ED_area_tag_redraw(sa);
+ ED_area_tag_redraw(area);
return OPERATOR_FINISHED;
}
@@ -1228,7 +1228,7 @@ void FILE_OT_bookmark_move(wmOperatorType *ot)
static int reset_recent_exec(bContext *C, wmOperator *UNUSED(op))
{
- ScrArea *sa = CTX_wm_area(C);
+ ScrArea *area = CTX_wm_area(C);
char name[FILE_MAX];
struct FSMenu *fsmenu = ED_fsmenu_get();
@@ -1240,7 +1240,7 @@ static int reset_recent_exec(bContext *C, wmOperator *UNUSED(op))
BKE_appdir_folder_id_create(BLENDER_USER_CONFIG, NULL),
BLENDER_BOOKMARK_FILE);
fsmenu_write_file(fsmenu, name);
- ED_area_tag_redraw(sa);
+ ED_area_tag_redraw(area);
return OPERATOR_FINISHED;
}
@@ -1469,9 +1469,12 @@ void file_sfile_to_operator_ex(bContext *C, wmOperator *op, SpaceFile *sfile, ch
for (i = 0; i < numfiles; i++) {
if (filelist_entry_select_index_get(sfile->files, i, CHECK_FILES)) {
FileDirEntry *file = filelist_file(sfile->files, i);
- RNA_property_collection_add(op->ptr, prop, &itemptr);
- RNA_string_set(&itemptr, "name", file->relpath);
- num_files++;
+ /* Cannot (currently) mix regular items and alias/shortcuts in multiple selection. */
+ if (!file->redirection_path) {
+ RNA_property_collection_add(op->ptr, prop, &itemptr);
+ RNA_string_set(&itemptr, "name", file->relpath);
+ num_files++;
+ }
}
}
/* make sure the file specified in the filename button is added even if no
@@ -1617,9 +1620,23 @@ static int file_exec(bContext *C, wmOperator *exec_op)
Main *bmain = CTX_data_main(C);
wmWindowManager *wm = CTX_wm_manager(C);
SpaceFile *sfile = CTX_wm_space_file(C);
- const struct FileDirEntry *file = filelist_file(sfile->files, sfile->params->active_file);
+ struct FileDirEntry *file = filelist_file(sfile->files, sfile->params->active_file);
char filepath[FILE_MAX];
+ if (file && file->redirection_path) {
+ /* redirection_path is an absolute path that takes precedence
+ * over using sfile->params->dir + sfile->params->file. */
+ BLI_split_dirfile(file->redirection_path,
+ sfile->params->dir,
+ sfile->params->file,
+ sizeof(sfile->params->dir),
+ sizeof(sfile->params->file));
+ /* Update relpath with redirected filename as well so that the alternative
+ * combination of sfile->params->dir + relpath remains valid as well. */
+ MEM_freeN(file->relpath);
+ file->relpath = BLI_strdup(sfile->params->file);
+ }
+
/* directory change */
if (file && (file->typeflag & FILE_TYPE_DIR)) {
if (!file->relpath) {
@@ -1627,15 +1644,12 @@ static int file_exec(bContext *C, wmOperator *exec_op)
}
if (FILENAME_IS_PARENT(file->relpath)) {
- BLI_parent_dir(sfile->params->dir);
+ BLI_path_parent_dir(sfile->params->dir);
}
else {
- BLI_cleanup_path(BKE_main_blendfile_path(bmain), sfile->params->dir);
+ BLI_path_normalize(BKE_main_blendfile_path(bmain), sfile->params->dir);
BLI_path_append(sfile->params->dir, sizeof(sfile->params->dir) - 1, file->relpath);
- BLI_add_slash(sfile->params->dir);
- }
- if (file->redirection_path) {
- STRNCPY(sfile->params->dir, file->redirection_path);
+ BLI_path_slash_ensure(sfile->params->dir);
}
ED_file_change_dir(C);
}
@@ -1754,8 +1768,8 @@ static int file_parent_exec(bContext *C, wmOperator *UNUSED(unused))
SpaceFile *sfile = CTX_wm_space_file(C);
if (sfile->params) {
- if (BLI_parent_dir(sfile->params->dir)) {
- BLI_cleanup_dir(BKE_main_blendfile_path(bmain), sfile->params->dir);
+ if (BLI_path_parent_dir(sfile->params->dir)) {
+ BLI_path_normalize_dir(BKE_main_blendfile_path(bmain), sfile->params->dir);
ED_file_change_dir(C);
if (sfile->params->recursion_level > 1) {
/* Disable 'dirtree' recursion when going up in tree. */
@@ -1867,9 +1881,9 @@ void FILE_OT_next(struct wmOperatorType *ot)
/* only meant for timer usage */
static int file_smoothscroll_invoke(bContext *C, wmOperator *UNUSED(op), const wmEvent *event)
{
- ScrArea *sa = CTX_wm_area(C);
+ ScrArea *area = CTX_wm_area(C);
SpaceFile *sfile = CTX_wm_space_file(C);
- ARegion *region, *ar_ctx = CTX_wm_region(C);
+ ARegion *region, *region_ctx = CTX_wm_region(C);
const bool is_horizontal = (sfile->layout->flag & FILE_LAYOUT_HOR) != 0;
int i;
@@ -1911,7 +1925,7 @@ static int file_smoothscroll_invoke(bContext *C, wmOperator *UNUSED(op), const w
}
/* we need the correct area for scrolling */
- region = BKE_area_find_region_type(sa, RGN_TYPE_WINDOW);
+ region = BKE_area_find_region_type(area, RGN_TYPE_WINDOW);
if (!region || region->regiontype != RGN_TYPE_WINDOW) {
WM_event_remove_timer(CTX_wm_manager(C), CTX_wm_window(C), sfile->smoothscroll_timer);
sfile->smoothscroll_timer = NULL;
@@ -2033,7 +2047,7 @@ static int file_smoothscroll_invoke(bContext *C, wmOperator *UNUSED(op), const w
ED_region_tag_redraw(region);
/* and restore context */
- CTX_wm_region_set(C, ar_ctx);
+ CTX_wm_region_set(C, region_ctx);
return OPERATOR_FINISHED;
}
@@ -2274,7 +2288,7 @@ static void file_expand_directory(bContext *C)
sfile->params->dir[3] = '\0';
}
else if (BLI_path_is_unc(sfile->params->dir)) {
- BLI_cleanup_unc(sfile->params->dir, FILE_MAX_LIBEXTRA);
+ BLI_path_normalize_unc(sfile->params->dir, FILE_MAX_LIBEXTRA);
}
#endif
}
@@ -2291,7 +2305,7 @@ static bool can_create_dir(const char *dir)
if (BLI_path_is_unc(dir)) {
char parent[PATH_MAX];
BLI_strncpy(parent, dir, PATH_MAX);
- BLI_parent_dir(parent);
+ BLI_path_parent_dir(parent);
return BLI_is_dir(parent);
}
return true;
@@ -2338,7 +2352,7 @@ void file_directory_enter_handle(bContext *C, void *UNUSED(arg_unused), void *UN
}
}
- BLI_cleanup_dir(BKE_main_blendfile_path(bmain), sfile->params->dir);
+ BLI_path_normalize_dir(BKE_main_blendfile_path(bmain), sfile->params->dir);
if (filelist_is_dir(sfile->files, sfile->params->dir)) {
if (!STREQ(sfile->params->dir, old_dir)) { /* Avoids flickering when nothing's changed. */
@@ -2423,7 +2437,7 @@ void file_filename_enter_handle(bContext *C, void *UNUSED(arg_unused), void *arg
/* if directory, open it and empty filename field */
if (filelist_is_dir(sfile->files, filepath)) {
- BLI_cleanup_dir(BKE_main_blendfile_path(bmain), filepath);
+ BLI_path_normalize_dir(BKE_main_blendfile_path(bmain), filepath);
BLI_strncpy(sfile->params->dir, filepath, sizeof(sfile->params->dir));
sfile->params->file[0] = '\0';
ED_file_change_dir(C);
@@ -2487,16 +2501,16 @@ static bool file_filenum_poll(bContext *C)
}
/**
- * Looks for a string of digits within name (using BLI_stringdec) and adjusts it by add.
+ * Looks for a string of digits within name (using BLI_path_sequence_decode) and adjusts it by add.
*/
static void filenum_newname(char *name, size_t name_size, int add)
{
char head[FILE_MAXFILE], tail[FILE_MAXFILE];
char name_temp[FILE_MAXFILE];
int pic;
- unsigned short digits;
+ ushort digits;
- pic = BLI_stringdec(name, head, tail, &digits);
+ pic = BLI_path_sequence_decode(name, head, tail, &digits);
/* are we going from 100 -> 99 or from 10 -> 9 */
if (add < 0 && digits > 0) {
@@ -2514,19 +2528,19 @@ static void filenum_newname(char *name, size_t name_size, int add)
if (pic < 0) {
pic = 0;
}
- BLI_stringenc(name_temp, head, tail, digits, pic);
+ BLI_path_sequence_encode(name_temp, head, tail, digits, pic);
BLI_strncpy(name, name_temp, name_size);
}
static int file_filenum_exec(bContext *C, wmOperator *op)
{
SpaceFile *sfile = CTX_wm_space_file(C);
- ScrArea *sa = CTX_wm_area(C);
+ ScrArea *area = CTX_wm_area(C);
int inc = RNA_int_get(op->ptr, "increment");
if (sfile->params && (inc != 0)) {
filenum_newname(sfile->params->file, sizeof(sfile->params->file), inc);
- ED_area_tag_redraw(sa);
+ ED_area_tag_redraw(area);
file_draw_check(C);
// WM_event_add_notifier(C, NC_WINDOW, NULL);
}
@@ -2576,12 +2590,12 @@ static void file_rename_state_activate(SpaceFile *sfile, int file_idx, bool requ
static int file_rename_invoke(bContext *C, wmOperator *UNUSED(op), const wmEvent *UNUSED(event))
{
- ScrArea *sa = CTX_wm_area(C);
+ ScrArea *area = CTX_wm_area(C);
SpaceFile *sfile = (SpaceFile *)CTX_wm_space_data(C);
if (sfile->params) {
file_rename_state_activate(sfile, sfile->params->active_file, true);
- ED_area_tag_redraw(sa);
+ ED_area_tag_redraw(area);
}
return OPERATOR_FINISHED;
@@ -2589,12 +2603,12 @@ static int file_rename_invoke(bContext *C, wmOperator *UNUSED(op), const wmEvent
static int file_rename_exec(bContext *C, wmOperator *UNUSED(op))
{
- ScrArea *sa = CTX_wm_area(C);
+ ScrArea *area = CTX_wm_area(C);
SpaceFile *sfile = (SpaceFile *)CTX_wm_space_data(C);
if (sfile->params) {
file_rename_state_activate(sfile, sfile->params->highlight_file, false);
- ED_area_tag_redraw(sa);
+ ED_area_tag_redraw(area);
}
return OPERATOR_FINISHED;
@@ -2708,8 +2722,8 @@ void FILE_OT_delete(struct wmOperatorType *ot)
static int file_start_filter_exec(bContext *C, wmOperator *UNUSED(op))
{
- ScrArea *sa = CTX_wm_area(C);
- ARegion *region = BKE_area_find_region_type(sa, RGN_TYPE_UI);
+ ScrArea *area = CTX_wm_area(C);
+ ARegion *region = BKE_area_find_region_type(area, RGN_TYPE_UI);
SpaceFile *sf = CTX_wm_space_file(C);
UI_textbutton_activate_rna(C, region, sf->params, "filter_search");
diff --git a/source/blender/editors/space_file/file_panels.c b/source/blender/editors/space_file/file_panels.c
index 9ba098fcf45..ff9454cd922 100644
--- a/source/blender/editors/space_file/file_panels.c
+++ b/source/blender/editors/space_file/file_panels.c
@@ -57,20 +57,20 @@ static bool file_panel_operator_poll(const bContext *C, PanelType *UNUSED(pt))
return (sfile && sfile->op);
}
-static void file_panel_operator_header(const bContext *C, Panel *pa)
+static void file_panel_operator_header(const bContext *C, Panel *panel)
{
SpaceFile *sfile = CTX_wm_space_file(C);
wmOperator *op = sfile->op;
- BLI_strncpy(pa->drawname, WM_operatortype_name(op->type, op->ptr), sizeof(pa->drawname));
+ BLI_strncpy(panel->drawname, WM_operatortype_name(op->type, op->ptr), sizeof(panel->drawname));
}
-static void file_panel_operator(const bContext *C, Panel *pa)
+static void file_panel_operator(const bContext *C, Panel *panel)
{
SpaceFile *sfile = CTX_wm_space_file(C);
wmOperator *op = sfile->op;
- UI_block_func_set(uiLayoutGetBlock(pa->layout), file_draw_check_cb, NULL, NULL);
+ UI_block_func_set(uiLayoutGetBlock(panel->layout), file_draw_check_cb, NULL, NULL);
/* Hack: temporary hide.*/
const char *hide[] = {"filepath", "files", "directory", "filename"};
@@ -82,7 +82,7 @@ static void file_panel_operator(const bContext *C, Panel *pa)
}
uiTemplateOperatorPropertyButs(
- C, pa->layout, op, UI_BUT_LABEL_ALIGN_NONE, UI_TEMPLATE_OP_PROPS_SHOW_EMPTY);
+ C, panel->layout, op, UI_BUT_LABEL_ALIGN_NONE, UI_TEMPLATE_OP_PROPS_SHOW_EMPTY);
/* Hack: temporary hide.*/
for (int i = 0; i < ARRAY_SIZE(hide); i++) {
@@ -92,7 +92,7 @@ static void file_panel_operator(const bContext *C, Panel *pa)
}
}
- UI_block_func_set(uiLayoutGetBlock(pa->layout), NULL, NULL, NULL);
+ UI_block_func_set(uiLayoutGetBlock(panel->layout), NULL, NULL, NULL);
}
void file_tool_props_region_panels_register(ARegionType *art)
@@ -128,12 +128,12 @@ static void file_panel_execution_execute_button(uiLayout *layout, const char *ti
uiItemO(row, title, ICON_NONE, "FILE_OT_execute");
}
-static void file_panel_execution_buttons_draw(const bContext *C, Panel *pa)
+static void file_panel_execution_buttons_draw(const bContext *C, Panel *panel)
{
bScreen *screen = CTX_wm_screen(C);
SpaceFile *sfile = CTX_wm_space_file(C);
FileSelectParams *params = ED_fileselect_get_params(sfile);
- uiBlock *block = uiLayoutGetBlock(pa->layout);
+ uiBlock *block = uiLayoutGetBlock(panel->layout);
uiBut *but;
uiLayout *row;
PointerRNA params_rna_ptr, *but_extra_rna_ptr;
@@ -148,7 +148,7 @@ static void file_panel_execution_buttons_draw(const bContext *C, Panel *pa)
RNA_pointer_create(&screen->id, &RNA_FileSelectParams, params, &params_rna_ptr);
- row = uiLayoutRow(pa->layout, false);
+ row = uiLayoutRow(panel->layout, false);
uiLayoutSetScaleY(row, 1.3f);
/* callbacks for operator check functions */
diff --git a/source/blender/editors/space_file/filelist.c b/source/blender/editors/space_file/filelist.c
index dec38501d38..d8d7ef01a2e 100644
--- a/source/blender/editors/space_file/filelist.c
+++ b/source/blender/editors/space_file/filelist.c
@@ -264,7 +264,7 @@ enum {
typedef struct FileListEntryPreview {
char path[FILE_MAX];
- unsigned int flags;
+ uint flags;
int index;
ImBuf *img;
} FileListEntryPreview;
@@ -635,7 +635,7 @@ static bool is_hidden_dot_filename(const char *filename, FileListInternEntry *fi
/* filename might actually be a piece of path, in which case we have to check all its parts. */
bool hidden = false;
- char *sep = (char *)BLI_last_slash(filename);
+ char *sep = (char *)BLI_path_slash_rfind(filename);
if (!hidden && sep) {
char tmp_filename[FILE_MAX_LIBEXTRA];
@@ -654,7 +654,7 @@ static bool is_hidden_dot_filename(const char *filename, FileListInternEntry *fi
break;
}
*sep = '\0';
- sep = (char *)BLI_last_slash(tmp_filename);
+ sep = (char *)BLI_path_slash_rfind(tmp_filename);
}
}
return hidden;
@@ -1015,6 +1015,7 @@ static int filelist_geticon_ex(FileDirEntry *file,
/* If this path is in System list or path cache then use that icon. */
struct FSMenu *fsmenu = ED_fsmenu_get();
FSMenuCategory categories[] = {
+ FS_CATEGORY_SYSTEM,
FS_CATEGORY_SYSTEM_BOOKMARKS,
FS_CATEGORY_OTHER,
};
@@ -1022,10 +1023,16 @@ static int filelist_geticon_ex(FileDirEntry *file,
for (int i = 0; i < ARRAY_SIZE(categories); i++) {
FSMenuEntry *tfsm = ED_fsmenu_get_category(fsmenu, categories[i]);
char fullpath[FILE_MAX_LIBEXTRA];
- BLI_join_dirfile(fullpath, sizeof(fullpath), root, file->relpath);
- BLI_add_slash(fullpath);
+ char *target = fullpath;
+ if (file->redirection_path) {
+ target = file->redirection_path;
+ }
+ else {
+ BLI_join_dirfile(fullpath, sizeof(fullpath), root, file->relpath);
+ BLI_path_slash_ensure(fullpath);
+ }
for (; tfsm; tfsm = tfsm->next) {
- if (STREQ(tfsm->path, fullpath)) {
+ if (STREQ(tfsm->path, target)) {
/* Never want a little folder inside a large one. */
return (tfsm->icon == ICON_FILE_FOLDER) ? ICON_NONE : tfsm->icon;
}
@@ -1033,10 +1040,7 @@ static int filelist_geticon_ex(FileDirEntry *file,
}
}
- if (file->attributes & FILE_ATTR_ANY_LINK) {
- return ICON_LOOP_FORWARDS;
- }
- else if (file->attributes & FILE_ATTR_OFFLINE) {
+ if (file->attributes & FILE_ATTR_OFFLINE) {
return ICON_ERROR;
}
else if (file->attributes & FILE_ATTR_TEMPORARY) {
@@ -1112,7 +1116,7 @@ int filelist_geticon(struct FileList *filelist, const int index, const bool is_m
static void parent_dir_until_exists_or_default_root(char *dir)
{
- if (!BLI_parent_dir_until_exists(dir)) {
+ if (!BLI_path_parent_dir_until_exists(dir)) {
#ifdef WIN32
get_default_root(dir);
#else
@@ -1264,11 +1268,9 @@ static void filelist_intern_free(FileListIntern *filelist_intern)
MEM_SAFE_FREE(filelist_intern->filtered);
}
-static void filelist_cache_preview_runf(TaskPool *__restrict pool,
- void *taskdata,
- int UNUSED(threadid))
+static void filelist_cache_preview_runf(TaskPool *__restrict pool, void *taskdata)
{
- FileListEntryCache *cache = BLI_task_pool_userdata(pool);
+ FileListEntryCache *cache = BLI_task_pool_user_data(pool);
FileListEntryPreviewTaskData *preview_taskdata = taskdata;
FileListEntryPreview *preview = preview_taskdata->preview;
@@ -1306,9 +1308,7 @@ static void filelist_cache_preview_runf(TaskPool *__restrict pool,
// printf("%s: End (%d)...\n", __func__, threadid);
}
-static void filelist_cache_preview_freef(TaskPool *__restrict UNUSED(pool),
- void *taskdata,
- int UNUSED(threadid))
+static void filelist_cache_preview_freef(TaskPool *__restrict UNUSED(pool), void *taskdata)
{
FileListEntryPreviewTaskData *preview_taskdata = taskdata;
FileListEntryPreview *preview = preview_taskdata->preview;
@@ -1327,9 +1327,7 @@ static void filelist_cache_preview_freef(TaskPool *__restrict UNUSED(pool),
static void filelist_cache_preview_ensure_running(FileListEntryCache *cache)
{
if (!cache->previews_pool) {
- TaskScheduler *scheduler = BLI_task_scheduler_get();
-
- cache->previews_pool = BLI_task_pool_create_background(scheduler, cache);
+ cache->previews_pool = BLI_task_pool_create_background(cache, TASK_PRIORITY_LOW);
cache->previews_done = BLI_thread_queue_init();
IMB_thumb_locks_acquire();
@@ -1381,8 +1379,15 @@ static void filelist_cache_previews_push(FileList *filelist, FileDirEntry *entry
(entry->typeflag & (FILE_TYPE_IMAGE | FILE_TYPE_MOVIE | FILE_TYPE_FTFONT |
FILE_TYPE_BLENDER | FILE_TYPE_BLENDER_BACKUP | FILE_TYPE_BLENDERLIB))) {
FileListEntryPreview *preview = MEM_mallocN(sizeof(*preview), __func__);
- BLI_join_dirfile(
- preview->path, sizeof(preview->path), filelist->filelist.root, entry->relpath);
+
+ if (entry->redirection_path) {
+ BLI_strncpy(preview->path, entry->redirection_path, FILE_MAXDIR);
+ }
+ else {
+ BLI_join_dirfile(
+ preview->path, sizeof(preview->path), filelist->filelist.root, entry->relpath);
+ }
+
preview->index = index;
preview->flags = entry->typeflag;
preview->img = NULL;
@@ -1393,12 +1398,11 @@ static void filelist_cache_previews_push(FileList *filelist, FileDirEntry *entry
FileListEntryPreviewTaskData *preview_taskdata = MEM_mallocN(sizeof(*preview_taskdata),
__func__);
preview_taskdata->preview = preview;
- BLI_task_pool_push_ex(cache->previews_pool,
- filelist_cache_preview_runf,
- preview_taskdata,
- true,
- filelist_cache_preview_freef,
- TASK_PRIORITY_LOW);
+ BLI_task_pool_push(cache->previews_pool,
+ filelist_cache_preview_runf,
+ preview_taskdata,
+ true,
+ filelist_cache_preview_freef);
}
}
@@ -1624,7 +1628,7 @@ void filelist_setdir(struct FileList *filelist, char *r_dir)
{
BLI_assert(strlen(r_dir) < FILE_MAX_LIBEXTRA);
- BLI_cleanup_dir(BKE_main_blendfile_path_from_global(), r_dir);
+ BLI_path_normalize_dir(BKE_main_blendfile_path_from_global(), r_dir);
const bool is_valid_path = filelist->checkdirf(filelist, r_dir, true);
BLI_assert(is_valid_path);
UNUSED_VARS_NDEBUG(is_valid_path);
@@ -2277,13 +2281,6 @@ int ED_path_extension_type(const char *path)
return 0;
}
-static int file_extension_type(const char *dir, const char *relpath)
-{
- char path[FILE_MAX];
- BLI_join_dirfile(path, sizeof(path), dir, relpath);
- return ED_path_extension_type(path);
-}
-
int ED_file_extension_icon(const char *path)
{
const int type = ED_path_extension_type(path);
@@ -2325,16 +2322,16 @@ int filelist_empty(struct FileList *filelist)
return (filelist->filelist.nbr_entries == 0);
}
-unsigned int filelist_entry_select_set(const FileList *filelist,
- const FileDirEntry *entry,
- FileSelType select,
- unsigned int flag,
- FileCheckType check)
+uint filelist_entry_select_set(const FileList *filelist,
+ const FileDirEntry *entry,
+ FileSelType select,
+ uint flag,
+ FileCheckType check)
{
/* Default NULL pointer if not found is fine here! */
void **es_p = BLI_ghash_lookup_p(filelist->selection_state, entry->uuid);
- unsigned int entry_flag = es_p ? POINTER_AS_UINT(*es_p) : 0;
- const unsigned int org_entry_flag = entry_flag;
+ uint entry_flag = es_p ? POINTER_AS_UINT(*es_p) : 0;
+ const uint org_entry_flag = entry_flag;
BLI_assert(entry);
BLI_assert(ELEM(check, CHECK_DIRS, CHECK_FILES, CHECK_ALL));
@@ -2373,11 +2370,8 @@ unsigned int filelist_entry_select_set(const FileList *filelist,
return entry_flag;
}
-void filelist_entry_select_index_set(FileList *filelist,
- const int index,
- FileSelType select,
- unsigned int flag,
- FileCheckType check)
+void filelist_entry_select_index_set(
+ FileList *filelist, const int index, FileSelType select, uint flag, FileCheckType check)
{
FileDirEntry *entry = filelist_file(filelist, index);
@@ -2386,11 +2380,8 @@ void filelist_entry_select_index_set(FileList *filelist,
}
}
-void filelist_entries_select_index_range_set(FileList *filelist,
- FileSelection *sel,
- FileSelType select,
- unsigned int flag,
- FileCheckType check)
+void filelist_entries_select_index_range_set(
+ FileList *filelist, FileSelection *sel, FileSelType select, uint flag, FileCheckType check)
{
/* select all valid files between first and last indicated */
if ((sel->first >= 0) && (sel->first < filelist->filelist.nbr_entries_filtered) &&
@@ -2402,9 +2393,7 @@ void filelist_entries_select_index_range_set(FileList *filelist,
}
}
-unsigned int filelist_entry_select_get(FileList *filelist,
- FileDirEntry *entry,
- FileCheckType check)
+uint filelist_entry_select_get(FileList *filelist, FileDirEntry *entry, FileCheckType check)
{
BLI_assert(entry);
BLI_assert(ELEM(check, CHECK_DIRS, CHECK_FILES, CHECK_ALL));
@@ -2418,9 +2407,7 @@ unsigned int filelist_entry_select_get(FileList *filelist,
return 0;
}
-unsigned int filelist_entry_select_index_get(FileList *filelist,
- const int index,
- FileCheckType check)
+uint filelist_entry_select_index_get(FileList *filelist, const int index, FileCheckType check)
{
FileDirEntry *entry = filelist_file(filelist, index);
@@ -2436,7 +2423,7 @@ unsigned int filelist_entry_select_index_get(FileList *filelist,
*/
void filelist_entry_parent_select_set(FileList *filelist,
FileSelType select,
- unsigned int flag,
+ uint flag,
FileCheckType check)
{
if ((filelist->filter_data.flags & FLF_HIDE_PARENT) == 0) {
@@ -2458,7 +2445,7 @@ static int groupname_to_code(const char *group)
BLI_assert(group);
BLI_strncpy(buf, group, sizeof(buf));
- lslash = (char *)BLI_last_slash(buf);
+ lslash = (char *)BLI_path_slash_rfind(buf);
if (lslash) {
lslash[0] = '\0';
}
@@ -2492,7 +2479,8 @@ static int filelist_readjob_list_dir(const char *root,
{
struct direntry *files;
int nbr_files, nbr_entries = 0;
- char path[FILE_MAX];
+ /* Full path of the item. */
+ char full_path[FILE_MAX];
nbr_files = BLI_filelist_dir_contents(root, &files);
if (files) {
@@ -2508,38 +2496,53 @@ static int filelist_readjob_list_dir(const char *root,
entry->relpath = MEM_dupallocN(files[i].relname);
entry->st = files[i].s;
- BLI_join_dirfile(path, sizeof(path), root, entry->relpath);
+ BLI_join_dirfile(full_path, FILE_MAX, root, entry->relpath);
+ char *target = full_path;
- /* Set file type. */
+ /* Set initial file type and attributes. */
+ entry->attributes = BLI_file_attributes(full_path);
if (S_ISDIR(files[i].s.st_mode)) {
entry->typeflag = FILE_TYPE_DIR;
}
- else if (do_lib && BLO_has_bfile_extension(entry->relpath)) {
- /* If we are considering .blend files as libs, promote them to directory status. */
- entry->typeflag = FILE_TYPE_BLENDER;
- /* prevent current file being used as acceptable dir */
- if (BLI_path_cmp(main_name, path) != 0) {
- entry->typeflag |= FILE_TYPE_DIR;
- }
- }
- /* Otherwise, do not check extensions for directories! */
- else if (!(entry->typeflag & FILE_TYPE_DIR)) {
- entry->typeflag = file_extension_type(root, entry->relpath);
- if (filter_glob[0] && BLI_path_extension_check_glob(entry->relpath, filter_glob)) {
- entry->typeflag |= FILE_TYPE_OPERATOR;
- }
- }
- /* Set file attributes. */
- entry->attributes = BLI_file_attributes(path);
+ /* Is this a file that points to another file? */
if (entry->attributes & FILE_ATTR_ALIAS) {
entry->redirection_path = MEM_callocN(FILE_MAXDIR, __func__);
- if (BLI_file_alias_target(entry->redirection_path, path)) {
+ if (BLI_file_alias_target(entry->redirection_path, full_path)) {
if (BLI_is_dir(entry->redirection_path)) {
entry->typeflag = FILE_TYPE_DIR;
+ BLI_path_slash_ensure(entry->redirection_path);
}
- else
+ else {
entry->typeflag = ED_path_extension_type(entry->redirection_path);
+ }
+ target = entry->redirection_path;
+#ifdef WIN32
+ /* On Windows don't show ".lnk" extension for valid shortcuts. */
+ BLI_path_extension_replace(entry->relpath, FILE_MAXDIR, "");
+#endif
+ }
+ else {
+ MEM_freeN(entry->redirection_path);
+ entry->redirection_path = NULL;
+ entry->attributes |= FILE_ATTR_HIDDEN;
+ }
+ }
+
+ if (!(entry->typeflag & FILE_TYPE_DIR)) {
+ if (do_lib && BLO_has_bfile_extension(target)) {
+ /* If we are considering .blend files as libs, promote them to directory status. */
+ entry->typeflag = FILE_TYPE_BLENDER;
+ /* prevent current file being used as acceptable dir */
+ if (BLI_path_cmp(main_name, target) != 0) {
+ entry->typeflag |= FILE_TYPE_DIR;
+ }
+ }
+ else {
+ entry->typeflag = ED_path_extension_type(target);
+ if (filter_glob[0] && BLI_path_extension_check_glob(target, filter_glob)) {
+ entry->typeflag |= FILE_TYPE_OPERATOR;
+ }
}
}
@@ -2627,7 +2630,7 @@ static int filelist_readjob_list_lib(const char *root, ListBase *entries, const
/* Kept for reference here, in case we want to add back that feature later.
* We do not need it currently. */
/* Code ***NOT*** updated for job stuff! */
-static void filelist_readjob_main_rec(Main *bmain, FileList *filelist)
+static void filelist_readjob_main_recursive(Main *bmain, FileList *filelist)
{
ID *id;
FileDirEntry *files, *firstlib = NULL;
@@ -2826,7 +2829,7 @@ static void filelist_readjob_do(const bool do_lib,
BLI_strncpy(dir, filelist->filelist.root, sizeof(dir));
BLI_strncpy(filter_glob, filelist->filter_data.filter_glob, sizeof(filter_glob));
- BLI_cleanup_dir(main_name, dir);
+ BLI_path_normalize_dir(main_name, dir);
td_dir->dir = BLI_strdup(dir);
while (!BLI_stack_is_empty(todo_dirs) && !(*stop)) {
@@ -2852,7 +2855,7 @@ static void filelist_readjob_do(const bool do_lib,
* Note that in the end, this means we 'cache' valid relative subdir once here,
* this is actually better. */
BLI_strncpy(rel_subdir, subdir, sizeof(rel_subdir));
- BLI_cleanup_dir(root, rel_subdir);
+ BLI_path_normalize_dir(root, rel_subdir);
BLI_path_rel(rel_subdir, root);
if (do_lib) {
@@ -2894,7 +2897,7 @@ static void filelist_readjob_do(const bool do_lib,
else {
/* We have a directory we want to list, add it to todo list! */
BLI_join_dirfile(dir, sizeof(dir), root, entry->relpath);
- BLI_cleanup_dir(main_name, dir);
+ BLI_path_normalize_dir(main_name, dir);
td_dir = BLI_stack_push_r(todo_dirs);
td_dir->level = recursion_level + 1;
td_dir->dir = BLI_strdup(dir);
diff --git a/source/blender/editors/space_file/filesel.c b/source/blender/editors/space_file/filesel.c
index 67c0fae3565..3b62941af83 100644
--- a/source/blender/editors/space_file/filesel.c
+++ b/source/blender/editors/space_file/filesel.c
@@ -47,6 +47,7 @@
#include "BLI_blenlib.h"
#include "BLI_fnmatch.h"
+#include "BLI_math_base.h"
#include "BLI_utildefines.h"
#include "BLO_readfile.h"
@@ -156,7 +157,7 @@ short ED_fileselect_set_params(SpaceFile *sfile)
}
if (params->dir[0]) {
- BLI_cleanup_dir(blendfile_path, params->dir);
+ BLI_path_normalize_dir(blendfile_path, params->dir);
BLI_path_abs(params->dir, blendfile_path);
}
@@ -758,11 +759,11 @@ void ED_fileselect_init_layout(struct SpaceFile *sfile, ARegion *region)
layout->attribute_column_header_h = 0;
layout->offset_top = 0;
if (layout->flow_columns > 0) {
- layout->rows = numfiles / layout->flow_columns + 1; // XXX dirty, modulo is zero
+ layout->rows = divide_ceil_u(numfiles, layout->flow_columns);
}
else {
layout->flow_columns = 1;
- layout->rows = numfiles + 1; // XXX dirty, modulo is zero
+ layout->rows = numfiles;
}
layout->height = sfile->layout->rows * (layout->tile_h + 2 * layout->tile_border_y) +
layout->tile_border_y * 2 - layout->offset_top;
@@ -807,11 +808,11 @@ void ED_fileselect_init_layout(struct SpaceFile *sfile, ARegion *region)
file_attribute_columns_init(params, layout);
if (layout->rows > 0) {
- layout->flow_columns = numfiles / layout->rows + 1; // XXX dirty, modulo is zero
+ layout->flow_columns = divide_ceil_u(numfiles, layout->rows);
}
else {
layout->rows = 1;
- layout->flow_columns = numfiles + 1; // XXX dirty, modulo is zero
+ layout->flow_columns = numfiles;
}
layout->width = sfile->layout->flow_columns * (layout->tile_w + 2 * layout->tile_border_x) +
layout->tile_border_x * 2;
@@ -924,7 +925,7 @@ int autocomplete_directory(struct bContext *C, char *str, void *UNUSED(arg_v))
match = UI_autocomplete_end(autocpl, str);
if (match == AUTOCOMPLETE_FULL_MATCH) {
- BLI_add_slash(str);
+ BLI_path_slash_ensure(str);
}
}
}
diff --git a/source/blender/editors/space_file/fsmenu.c b/source/blender/editors/space_file/fsmenu.c
index 66157296064..b03df01a02b 100644
--- a/source/blender/editors/space_file/fsmenu.c
+++ b/source/blender/editors/space_file/fsmenu.c
@@ -418,7 +418,7 @@ void fsmenu_insert_entry(struct FSMenu *fsmenu,
else {
/* if we're bookmarking this, file should come
* before the last separator, only automatically added
- * current dir go after the last sep. */
+ * current dir go after the last separator. */
if (flag & FS_INSERT_SAVE) {
break;
}
@@ -848,6 +848,10 @@ void fsmenu_read_system(struct FSMenu *fsmenu, int read_bookmarks)
CFRelease(volEnum);
+ /* kLSSharedFileListFavoriteItems is deprecated, but available till macOS 10.15.
+ * Will have to find a new method to sync the Finder Favorites with File Browser. */
+# pragma GCC diagnostic push
+# pragma GCC diagnostic ignored "-Wdeprecated-declarations"
/* Finally get user favorite places */
if (read_bookmarks) {
UInt32 seed;
@@ -891,6 +895,7 @@ void fsmenu_read_system(struct FSMenu *fsmenu, int read_bookmarks)
CFRelease(pathesArray);
CFRelease(list);
}
+# pragma GCC diagnostic pop
}
# else
/* unix */
diff --git a/source/blender/editors/space_file/space_file.c b/source/blender/editors/space_file/space_file.c
index 0ac838f9d0c..319d74f5fad 100644
--- a/source/blender/editors/space_file/space_file.c
+++ b/source/blender/editors/space_file/space_file.c
@@ -55,16 +55,16 @@
#include "filelist.h"
#include "fsmenu.h"
-static ARegion *file_execute_region_ensure(ScrArea *sa, ARegion *ar_prev)
+static ARegion *file_execute_region_ensure(ScrArea *area, ARegion *region_prev)
{
ARegion *region;
- if ((region = BKE_area_find_region_type(sa, RGN_TYPE_EXECUTE)) != NULL) {
+ if ((region = BKE_area_find_region_type(area, RGN_TYPE_EXECUTE)) != NULL) {
return region;
}
region = MEM_callocN(sizeof(ARegion), "execute region for file");
- BLI_insertlinkafter(&sa->regionbase, ar_prev, region);
+ BLI_insertlinkafter(&area->regionbase, region_prev, region);
region->regiontype = RGN_TYPE_EXECUTE;
region->alignment = RGN_ALIGN_BOTTOM;
region->flag = RGN_FLAG_DYNAMIC_SIZE;
@@ -72,17 +72,17 @@ static ARegion *file_execute_region_ensure(ScrArea *sa, ARegion *ar_prev)
return region;
}
-static ARegion *file_tool_props_region_ensure(ScrArea *sa, ARegion *ar_prev)
+static ARegion *file_tool_props_region_ensure(ScrArea *area, ARegion *region_prev)
{
ARegion *region;
- if ((region = BKE_area_find_region_type(sa, RGN_TYPE_TOOL_PROPS)) != NULL) {
+ if ((region = BKE_area_find_region_type(area, RGN_TYPE_TOOL_PROPS)) != NULL) {
return region;
}
/* add subdiv level; after execute region */
region = MEM_callocN(sizeof(ARegion), "tool props for file");
- BLI_insertlinkafter(&sa->regionbase, ar_prev, region);
+ BLI_insertlinkafter(&area->regionbase, region_prev, region);
region->regiontype = RGN_TYPE_TOOL_PROPS;
region->alignment = RGN_ALIGN_RIGHT;
@@ -173,18 +173,18 @@ static void file_free(SpaceLink *sl)
}
/* spacetype; init callback, area size changes, screen set, etc */
-static void file_init(wmWindowManager *UNUSED(wm), ScrArea *sa)
+static void file_init(wmWindowManager *UNUSED(wm), ScrArea *area)
{
- SpaceFile *sfile = (SpaceFile *)sa->spacedata.first;
+ SpaceFile *sfile = (SpaceFile *)area->spacedata.first;
if (sfile->layout) {
sfile->layout->dirty = true;
}
}
-static void file_exit(wmWindowManager *wm, ScrArea *sa)
+static void file_exit(wmWindowManager *wm, ScrArea *area)
{
- SpaceFile *sfile = (SpaceFile *)sa->spacedata.first;
+ SpaceFile *sfile = (SpaceFile *)area->spacedata.first;
if (sfile->previews_timer) {
WM_event_remove_timer_notifier(wm, NULL, sfile->previews_timer);
@@ -228,44 +228,44 @@ static SpaceLink *file_duplicate(SpaceLink *sl)
static void file_ensure_valid_region_state(bContext *C,
wmWindowManager *wm,
wmWindow *win,
- ScrArea *sa,
+ ScrArea *area,
SpaceFile *sfile,
FileSelectParams *params)
{
- ARegion *ar_ui = BKE_area_find_region_type(sa, RGN_TYPE_UI);
- ARegion *ar_props = BKE_area_find_region_type(sa, RGN_TYPE_TOOL_PROPS);
- ARegion *ar_execute = BKE_area_find_region_type(sa, RGN_TYPE_EXECUTE);
+ ARegion *region_ui = BKE_area_find_region_type(area, RGN_TYPE_UI);
+ ARegion *region_props = BKE_area_find_region_type(area, RGN_TYPE_TOOL_PROPS);
+ ARegion *region_execute = BKE_area_find_region_type(area, RGN_TYPE_EXECUTE);
bool needs_init = false; /* To avoid multiple ED_area_initialize() calls. */
/* If there's an file-operation, ensure we have the option and execute region */
- if (sfile->op && (ar_props == NULL)) {
- ar_execute = file_execute_region_ensure(sa, ar_ui);
- ar_props = file_tool_props_region_ensure(sa, ar_execute);
+ if (sfile->op && (region_props == NULL)) {
+ region_execute = file_execute_region_ensure(area, region_ui);
+ region_props = file_tool_props_region_ensure(area, region_execute);
if (params->flag & FILE_HIDE_TOOL_PROPS) {
- ar_props->flag |= RGN_FLAG_HIDDEN;
+ region_props->flag |= RGN_FLAG_HIDDEN;
}
else {
- ar_props->flag &= ~RGN_FLAG_HIDDEN;
+ region_props->flag &= ~RGN_FLAG_HIDDEN;
}
needs_init = true;
}
/* If there's _no_ file-operation, ensure we _don't_ have the option and execute region */
- else if ((sfile->op == NULL) && (ar_props != NULL)) {
- BLI_assert(ar_execute != NULL);
+ else if ((sfile->op == NULL) && (region_props != NULL)) {
+ BLI_assert(region_execute != NULL);
- ED_region_remove(C, sa, ar_props);
- ED_region_remove(C, sa, ar_execute);
+ ED_region_remove(C, area, region_props);
+ ED_region_remove(C, area, region_execute);
needs_init = true;
}
if (needs_init) {
- ED_area_initialize(wm, win, sa);
+ ED_area_initialize(wm, win, area);
}
}
-static void file_refresh(const bContext *C, ScrArea *sa)
+static void file_refresh(const bContext *C, ScrArea *area)
{
wmWindowManager *wm = CTX_wm_manager(C);
wmWindow *win = CTX_wm_window(C);
@@ -333,34 +333,34 @@ static void file_refresh(const bContext *C, ScrArea *sa)
sfile->layout->dirty = true;
}
- /* Might be called with NULL sa, see file_main_region_draw() below. */
- if (sa) {
- file_ensure_valid_region_state((bContext *)C, wm, win, sa, sfile, params);
+ /* Might be called with NULL area, see file_main_region_draw() below. */
+ if (area) {
+ file_ensure_valid_region_state((bContext *)C, wm, win, area, sfile, params);
}
- ED_area_tag_redraw(sa);
+ ED_area_tag_redraw(area);
}
static void file_listener(wmWindow *UNUSED(win),
- ScrArea *sa,
+ ScrArea *area,
wmNotifier *wmn,
Scene *UNUSED(scene))
{
- SpaceFile *sfile = (SpaceFile *)sa->spacedata.first;
+ SpaceFile *sfile = (SpaceFile *)area->spacedata.first;
/* context changes */
switch (wmn->category) {
case NC_SPACE:
switch (wmn->data) {
case ND_SPACE_FILE_LIST:
- ED_area_tag_refresh(sa);
+ ED_area_tag_refresh(area);
break;
case ND_SPACE_FILE_PARAMS:
- ED_area_tag_refresh(sa);
+ ED_area_tag_refresh(area);
break;
case ND_SPACE_FILE_PREVIEW:
if (sfile->files && filelist_cache_previews_update(sfile->files)) {
- ED_area_tag_refresh(sa);
+ ED_area_tag_refresh(area);
}
break;
}
@@ -384,7 +384,7 @@ static void file_main_region_init(wmWindowManager *wm, ARegion *region)
}
static void file_main_region_listener(wmWindow *UNUSED(win),
- ScrArea *UNUSED(sa),
+ ScrArea *UNUSED(area),
ARegion *region,
wmNotifier *wmn,
const Scene *UNUSED(scene))
@@ -408,18 +408,18 @@ 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 ScrArea *area,
struct ARegion *region,
struct wmMsgBus *mbus)
{
- SpaceFile *sfile = sa->spacedata.first;
+ SpaceFile *sfile = area->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 = region,
- .user_data = sa,
+ .user_data = area,
.notify = ED_area_do_msg_notify_tag_refresh,
};
@@ -575,7 +575,7 @@ static void file_tools_region_draw(const bContext *C, ARegion *region)
}
static void file_tools_region_listener(wmWindow *UNUSED(win),
- ScrArea *UNUSED(sa),
+ ScrArea *UNUSED(area),
ARegion *UNUSED(region),
wmNotifier *UNUSED(wmn),
const Scene *UNUSED(scene))
@@ -643,7 +643,7 @@ static void file_execution_region_draw(const bContext *C, ARegion *region)
}
static void file_ui_region_listener(wmWindow *UNUSED(win),
- ScrArea *UNUSED(sa),
+ ScrArea *UNUSED(area),
ARegion *region,
wmNotifier *wmn,
const Scene *UNUSED(scene))
diff --git a/source/blender/editors/space_graph/graph_buttons.c b/source/blender/editors/space_graph/graph_buttons.c
index c2aa74a695e..179d73a38ba 100644
--- a/source/blender/editors/space_graph/graph_buttons.c
+++ b/source/blender/editors/space_graph/graph_buttons.c
@@ -38,10 +38,11 @@
#include "BLT_translation.h"
-#include "BKE_animsys.h"
+#include "BKE_anim_data.h"
#include "BKE_context.h"
#include "BKE_curve.h"
#include "BKE_fcurve.h"
+#include "BKE_fcurve_driver.h"
#include "BKE_global.h"
#include "BKE_main.h"
#include "BKE_screen.h"
@@ -111,9 +112,9 @@ static bool graph_panel_poll(const bContext *C, PanelType *UNUSED(pt))
/* -------------- */
-static void graph_panel_cursor_header(const bContext *C, Panel *pa)
+static void graph_panel_cursor_header(const bContext *C, Panel *panel)
{
- bScreen *sc = CTX_wm_screen(C);
+ bScreen *screen = CTX_wm_screen(C);
SpaceGraph *sipo = CTX_wm_space_graph(C);
Scene *scene = CTX_data_scene(C);
PointerRNA spaceptr, sceneptr;
@@ -121,25 +122,25 @@ static void graph_panel_cursor_header(const bContext *C, Panel *pa)
/* get RNA pointers for use when creating the UI elements */
RNA_id_pointer_create(&scene->id, &sceneptr);
- RNA_pointer_create(&sc->id, &RNA_SpaceGraphEditor, sipo, &spaceptr);
+ RNA_pointer_create(&screen->id, &RNA_SpaceGraphEditor, sipo, &spaceptr);
/* 2D-Cursor */
- col = uiLayoutColumn(pa->layout, false);
+ col = uiLayoutColumn(panel->layout, false);
uiItemR(col, &spaceptr, "show_cursor", 0, "", ICON_NONE);
}
-static void graph_panel_cursor(const bContext *C, Panel *pa)
+static void graph_panel_cursor(const bContext *C, Panel *panel)
{
- bScreen *sc = CTX_wm_screen(C);
+ bScreen *screen = CTX_wm_screen(C);
SpaceGraph *sipo = CTX_wm_space_graph(C);
Scene *scene = CTX_data_scene(C);
PointerRNA spaceptr, sceneptr;
- uiLayout *layout = pa->layout;
+ uiLayout *layout = panel->layout;
uiLayout *col, *sub;
/* get RNA pointers for use when creating the UI elements */
RNA_id_pointer_create(&scene->id, &sceneptr);
- RNA_pointer_create(&sc->id, &RNA_SpaceGraphEditor, sipo, &spaceptr);
+ RNA_pointer_create(&screen->id, &RNA_SpaceGraphEditor, sipo, &spaceptr);
uiLayoutSetPropSep(layout, true);
uiLayoutSetPropDecorate(layout, false);
@@ -164,12 +165,12 @@ static void graph_panel_cursor(const bContext *C, Panel *pa)
/* ******************* active F-Curve ************** */
-static void graph_panel_properties(const bContext *C, Panel *pa)
+static void graph_panel_properties(const bContext *C, Panel *panel)
{
bAnimListElem *ale;
FCurve *fcu;
PointerRNA fcu_ptr;
- uiLayout *layout = pa->layout;
+ uiLayout *layout = panel->layout;
uiLayout *col;
char name[256];
int icon = 0;
@@ -294,7 +295,7 @@ static void graphedit_activekey_handles_cb(bContext *C, void *fcu_ptr, void *bez
bezt->h2 = HD_ALIGN;
}
else {
- BKE_nurb_bezt_handle_test(bezt, SELECT, true);
+ BKE_nurb_bezt_handle_test(bezt, SELECT, true, false);
}
/* now call standard updates */
@@ -345,13 +346,13 @@ static void graphedit_activekey_right_handle_coord_cb(bContext *C, void *fcu_ptr
bezt->f3 = f3;
}
-static void graph_panel_key_properties(const bContext *C, Panel *pa)
+static void graph_panel_key_properties(const bContext *C, Panel *panel)
{
bAnimListElem *ale;
FCurve *fcu;
BezTriple *bezt, *prevbezt;
- uiLayout *layout = pa->layout;
+ uiLayout *layout = panel->layout;
const ARegion *region = CTX_wm_region(C);
/* Just a width big enough so buttons use entire layout width (will be clamped by it then). */
const int but_max_width = region->winx;
@@ -422,8 +423,7 @@ static void graph_panel_key_properties(const bContext *C, Panel *pa)
col = uiLayoutColumn(layout, true);
/* keyframe itself */
{
-
- uiItemL_respect_property_split(col, IFACE_("Key Value"), ICON_NONE);
+ uiItemL_respect_property_split(col, IFACE_("Key Frame"), ICON_NONE);
but = uiDefButR(block,
UI_BTYPE_NUM,
B_REDR,
@@ -434,16 +434,14 @@ static void graph_panel_key_properties(const bContext *C, Panel *pa)
UI_UNIT_Y,
&bezt_ptr,
"co",
- 1,
+ 0,
0,
0,
-1,
-1,
NULL);
- UI_but_func_set(but, graphedit_activekey_update_cb, fcu, bezt);
- UI_but_unit_type_set(but, unit);
- uiItemL_respect_property_split(col, IFACE_("Frame"), ICON_NONE);
+ uiItemL_respect_property_split(col, IFACE_("Value"), ICON_NONE);
but = uiDefButR(block,
UI_BTYPE_NUM,
B_REDR,
@@ -454,21 +452,42 @@ static void graph_panel_key_properties(const bContext *C, Panel *pa)
UI_UNIT_Y,
&bezt_ptr,
"co",
- 0,
+ 1,
0,
0,
-1,
-1,
NULL);
UI_but_func_set(but, graphedit_activekey_update_cb, fcu, bezt);
+ UI_but_unit_type_set(but, unit);
+
+ UI_but_func_set(but, graphedit_activekey_update_cb, fcu, bezt);
}
/* previous handle - only if previous was Bezier interpolation */
if ((prevbezt) && (prevbezt->ipo == BEZT_IPO_BEZ)) {
col = uiLayoutColumn(layout, true);
+ uiItemL_respect_property_split(col, IFACE_("Left Handle Type"), ICON_NONE);
+ but = uiDefButR(block,
+ UI_BTYPE_MENU,
+ B_REDR,
+ NULL,
+ 0,
+ 0,
+ but_max_width,
+ UI_UNIT_Y,
+ &bezt_ptr,
+ "handle_left_type",
+ 0,
+ 0,
+ 0,
+ -1,
+ -1,
+ "Type of left handle");
+ UI_but_func_set(but, graphedit_activekey_handles_cb, fcu, bezt);
- uiItemL_respect_property_split(col, IFACE_("Left Handle X"), ICON_NONE);
+ uiItemL_respect_property_split(col, IFACE_("Frame"), ICON_NONE);
but = uiDefButR(block,
UI_BTYPE_NUM,
B_REDR,
@@ -487,7 +506,7 @@ static void graph_panel_key_properties(const bContext *C, Panel *pa)
NULL);
UI_but_func_set(but, graphedit_activekey_left_handle_coord_cb, fcu, bezt);
- uiItemL_respect_property_split(col, IFACE_("Y"), ICON_NONE);
+ uiItemL_respect_property_split(col, IFACE_("Value"), ICON_NONE);
but = uiDefButR(block,
UI_BTYPE_NUM,
B_REDR,
@@ -506,8 +525,14 @@ static void graph_panel_key_properties(const bContext *C, Panel *pa)
NULL);
UI_but_func_set(but, graphedit_activekey_left_handle_coord_cb, fcu, bezt);
UI_but_unit_type_set(but, unit);
+ }
+
+ /* next handle - only if current is Bezier interpolation */
+ if (bezt->ipo == BEZT_IPO_BEZ) {
+ /* NOTE: special update callbacks are needed on the coords here due to T39911 */
- uiItemL_respect_property_split(col, IFACE_("Type"), ICON_NONE);
+ col = uiLayoutColumn(layout, true);
+ uiItemL_respect_property_split(col, IFACE_("Right Handle Type"), ICON_NONE);
but = uiDefButR(block,
UI_BTYPE_MENU,
B_REDR,
@@ -517,22 +542,16 @@ static void graph_panel_key_properties(const bContext *C, Panel *pa)
but_max_width,
UI_UNIT_Y,
&bezt_ptr,
- "handle_left_type",
+ "handle_right_type",
0,
0,
0,
-1,
-1,
- "Type of left handle");
+ "Type of right handle");
UI_but_func_set(but, graphedit_activekey_handles_cb, fcu, bezt);
- }
- /* next handle - only if current is Bezier interpolation */
- if (bezt->ipo == BEZT_IPO_BEZ) {
- /* NOTE: special update callbacks are needed on the coords here due to T39911 */
-
- col = uiLayoutColumn(layout, true);
- uiItemL_respect_property_split(col, IFACE_("Right Handle X"), ICON_NONE);
+ uiItemL_respect_property_split(col, IFACE_("Frame"), ICON_NONE);
but = uiDefButR(block,
UI_BTYPE_NUM,
B_REDR,
@@ -551,7 +570,7 @@ static void graph_panel_key_properties(const bContext *C, Panel *pa)
NULL);
UI_but_func_set(but, graphedit_activekey_right_handle_coord_cb, fcu, bezt);
- uiItemL_respect_property_split(col, IFACE_("Y"), ICON_NONE);
+ uiItemL_respect_property_split(col, IFACE_("Value"), ICON_NONE);
but = uiDefButR(block,
UI_BTYPE_NUM,
B_REDR,
@@ -570,25 +589,6 @@ static void graph_panel_key_properties(const bContext *C, Panel *pa)
NULL);
UI_but_func_set(but, graphedit_activekey_right_handle_coord_cb, fcu, bezt);
UI_but_unit_type_set(but, unit);
-
- uiItemL_respect_property_split(col, IFACE_("Type"), ICON_NONE);
- but = uiDefButR(block,
- UI_BTYPE_MENU,
- B_REDR,
- NULL,
- 0,
- 0,
- but_max_width,
- UI_UNIT_Y,
- &bezt_ptr,
- "handle_right_type",
- 0,
- 0,
- 0,
- -1,
- -1,
- "Type of right handle");
- UI_but_func_set(but, graphedit_activekey_handles_cb, fcu, bezt);
}
}
else {
@@ -1227,7 +1227,7 @@ static void graph_draw_driver_settings_panel(uiLayout *layout,
/* Panel to show property driven by the driver (in Drivers Editor) - duplicates Active FCurve,
* but useful for clarity. */
-static void graph_panel_driven_property(const bContext *C, Panel *pa)
+static void graph_panel_driven_property(const bContext *C, Panel *panel)
{
bAnimListElem *ale;
FCurve *fcu;
@@ -1236,14 +1236,14 @@ static void graph_panel_driven_property(const bContext *C, Panel *pa)
return;
}
- graph_draw_driven_property_panel(pa->layout, ale->id, fcu);
+ graph_draw_driven_property_panel(panel->layout, ale->id, fcu);
MEM_freeN(ale);
}
/* driver settings for active F-Curve
* (only for 'Drivers' mode in Graph Editor, i.e. the full "Drivers Editor") */
-static void graph_panel_drivers(const bContext *C, Panel *pa)
+static void graph_panel_drivers(const bContext *C, Panel *panel)
{
bAnimListElem *ale;
FCurve *fcu;
@@ -1253,7 +1253,7 @@ static void graph_panel_drivers(const bContext *C, Panel *pa)
return;
}
- graph_draw_driver_settings_panel(pa->layout, ale->id, fcu, false);
+ graph_draw_driver_settings_panel(panel->layout, ale->id, fcu, false);
/* cleanup */
MEM_freeN(ale);
@@ -1269,9 +1269,9 @@ static bool graph_panel_drivers_popover_poll(const bContext *C, PanelType *UNUSE
}
/* popover panel for driver editing anywhere in ui */
-static void graph_panel_drivers_popover(const bContext *C, Panel *pa)
+static void graph_panel_drivers_popover(const bContext *C, Panel *panel)
{
- uiLayout *layout = pa->layout;
+ uiLayout *layout = panel->layout;
PointerRNA ptr = {NULL};
PropertyRNA *prop = NULL;
@@ -1284,7 +1284,7 @@ static void graph_panel_drivers_popover(const bContext *C, Panel *pa)
FCurve *fcu;
bool driven, special;
- fcu = rna_get_fcurve_context_ui(
+ fcu = BKE_fcurve_find_by_rna_context_ui(
(bContext *)C, &ptr, prop, index, NULL, NULL, &driven, &special);
/* Hack: Force all buttons in this panel to be able to know the driver button
@@ -1303,7 +1303,7 @@ static void graph_panel_drivers_popover(const bContext *C, Panel *pa)
/* Driven Property Settings */
uiItemL(layout, IFACE_("Driven Property:"), ICON_NONE);
- graph_draw_driven_property_panel(pa->layout, id, fcu);
+ graph_draw_driven_property_panel(panel->layout, id, fcu);
/* TODO: All vs Single */
uiItemS(layout);
@@ -1311,7 +1311,7 @@ static void graph_panel_drivers_popover(const bContext *C, Panel *pa)
/* Drivers Settings */
uiItemL(layout, IFACE_("Driver Settings:"), ICON_NONE);
- graph_draw_driver_settings_panel(pa->layout, id, fcu, true);
+ graph_draw_driver_settings_panel(panel->layout, id, fcu, true);
}
}
@@ -1334,7 +1334,7 @@ static void do_graph_region_modifier_buttons(bContext *C, void *UNUSED(arg), int
}
}
-static void graph_panel_modifiers(const bContext *C, Panel *pa)
+static void graph_panel_modifiers(const bContext *C, Panel *panel)
{
bAnimListElem *ale;
FCurve *fcu;
@@ -1347,12 +1347,12 @@ static void graph_panel_modifiers(const bContext *C, Panel *pa)
return;
}
- block = uiLayoutGetBlock(pa->layout);
+ block = uiLayoutGetBlock(panel->layout);
UI_block_func_handle_set(block, do_graph_region_modifier_buttons, NULL);
/* 'add modifier' button at top of panel */
{
- row = uiLayoutRow(pa->layout, false);
+ row = uiLayoutRow(panel->layout, false);
/* this is an operator button which calls a 'add modifier' operator...
* a menu might be nicer but would be tricky as we need some custom filtering
@@ -1369,7 +1369,7 @@ static void graph_panel_modifiers(const bContext *C, Panel *pa)
active = !(fcu->flag & FCURVE_MOD_OFF);
/* draw each modifier */
for (fcm = fcu->modifiers.first; fcm; fcm = fcm->next) {
- col = uiLayoutColumn(pa->layout, true);
+ col = uiLayoutColumn(panel->layout, true);
uiLayoutSetActive(col, active);
ANIM_uiTemplate_fmodifier_draw(col, ale->fcurve_owner_id, &fcu->modifiers, fcm);
diff --git a/source/blender/editors/space_graph/graph_draw.c b/source/blender/editors/space_graph/graph_draw.c
index eac87caf777..f2071d292ca 100644
--- a/source/blender/editors/space_graph/graph_draw.c
+++ b/source/blender/editors/space_graph/graph_draw.c
@@ -343,6 +343,10 @@ static void draw_fcurve_handles(SpaceGraph *sipo, FCurve *fcu)
uint color = GPU_vertformat_attr_add(
format, "color", GPU_COMP_U8, 4, GPU_FETCH_INT_TO_FLOAT_UNIT);
immBindBuiltinProgram(GPU_SHADER_2D_FLAT_COLOR);
+ if ((sipo->flag & SIPO_BEAUTYDRAW_OFF) == 0) {
+ GPU_line_smooth(true);
+ }
+ GPU_blend(true);
immBeginAtMost(GPU_PRIM_LINES, 4 * 2 * fcu->totvert);
@@ -419,6 +423,10 @@ static void draw_fcurve_handles(SpaceGraph *sipo, FCurve *fcu)
immEnd();
immUnbindProgram();
+ GPU_blend(false);
+ if ((sipo->flag & SIPO_BEAUTYDRAW_OFF) == 0) {
+ GPU_line_smooth(false);
+ }
}
/* Samples ---------------- */
@@ -1151,7 +1159,7 @@ void graph_draw_curves(bAnimContext *ac, SpaceGraph *sipo, ARegion *region, shor
* we must obey this.
*/
if (!(sipo->flag & SIPO_SELCUVERTSONLY) || (fcu->flag & FCURVE_SELECTED)) {
- if (!fcurve_are_keyframes_usable(fcu) && !(fcu->fpt && fcu->totvert)) {
+ if (!BKE_fcurve_are_keyframes_usable(fcu) && !(fcu->fpt && fcu->totvert)) {
/* only draw controls if this is the active modifier */
if ((fcu->flag & FCURVE_ACTIVE) && (fcm)) {
switch (fcm->type) {
@@ -1181,9 +1189,7 @@ void graph_draw_curves(bAnimContext *ac, SpaceGraph *sipo, ARegion *region, shor
if (do_handles) {
/* only draw handles/vertices on keyframes */
- GPU_blend(true);
draw_fcurve_handles(sipo, fcu);
- GPU_blend(false);
}
draw_fcurve_vertices(region, fcu, do_handles, (sipo->flag & SIPO_SELVHANDLESONLY));
diff --git a/source/blender/editors/space_graph/graph_edit.c b/source/blender/editors/space_graph/graph_edit.c
index 8c64fb5bb40..03151da8d4d 100644
--- a/source/blender/editors/space_graph/graph_edit.c
+++ b/source/blender/editors/space_graph/graph_edit.c
@@ -126,7 +126,8 @@ void get_graph_keyframe_extents(bAnimContext *ac,
float unitFac, offset;
/* get range */
- if (calc_fcurve_bounds(fcu, &txmin, &txmax, &tymin, &tymax, do_sel_only, include_handles)) {
+ if (BKE_fcurve_calc_bounds(
+ fcu, &txmin, &txmax, &tymin, &tymax, do_sel_only, include_handles)) {
short mapping_flag = ANIM_get_normalization_flags(ac);
/* apply NLA scaling */
@@ -328,7 +329,7 @@ static int graphkeys_view_selected_exec(bContext *C, wmOperator *op)
void GRAPH_OT_view_all(wmOperatorType *ot)
{
/* identifiers */
- ot->name = "View All";
+ ot->name = "Frame All";
ot->idname = "GRAPH_OT_view_all";
ot->description = "Reset viewable area to show full keyframe range";
@@ -385,7 +386,7 @@ void GRAPH_OT_view_frame(wmOperatorType *ot)
/* identifiers */
ot->name = "Go to Current Frame";
ot->idname = "GRAPH_OT_view_frame";
- ot->description = "Move the view to the playhead";
+ ot->description = "Move the view to the current frame";
/* api callbacks */
ot->exec = graphkeys_view_frame_exec;
@@ -409,7 +410,7 @@ static void create_ghost_curves(bAnimContext *ac, int start, int end)
int filter;
/* free existing ghost curves */
- free_fcurves(&sipo->runtime.ghost_curves);
+ BKE_fcurves_free(&sipo->runtime.ghost_curves);
/* sanity check */
if (start >= end) {
@@ -425,7 +426,7 @@ static void create_ghost_curves(bAnimContext *ac, int start, int end)
/* loop through filtered data and add keys between selected keyframes on every frame */
for (ale = anim_data.first; ale; ale = ale->next) {
FCurve *fcu = (FCurve *)ale->key_data;
- FCurve *gcu = MEM_callocN(sizeof(FCurve), "Ghost FCurve");
+ FCurve *gcu = BKE_fcurve_create();
AnimData *adt = ANIM_nla_mapping_get(ac, ale);
ChannelDriver *driver = fcu->driver;
FPoint *fpt;
@@ -536,7 +537,7 @@ static int graphkeys_clear_ghostcurves_exec(bContext *C, wmOperator *UNUSED(op))
return OPERATOR_CANCELLED;
}
/* free ghost curves */
- free_fcurves(&sipo->runtime.ghost_curves);
+ BKE_fcurves_free(&sipo->runtime.ghost_curves);
/* update this editor only */
ED_area_tag_redraw(CTX_wm_area(C));
@@ -806,7 +807,7 @@ static int graphkeys_click_insert_exec(bContext *C, wmOperator *op)
/* when there are F-Modifiers on the curve, only allow adding
* keyframes if these will be visible after doing so...
*/
- if (fcurve_is_keyframable(fcu)) {
+ if (BKE_fcurve_is_keyframable(fcu)) {
ListBase anim_data;
ToolSettings *ts = ac.scene->toolsettings;
@@ -1336,7 +1337,7 @@ static void decimate_graph_keys(bAnimContext *ac, float remove_ratio, float erro
typedef struct tDecimateGraphOp {
bAnimContext ac;
Scene *scene;
- ScrArea *sa;
+ ScrArea *area;
ARegion *region;
/** A 0-1 value for determining how much we should decimate. */
@@ -1409,7 +1410,7 @@ static void decimate_exit(bContext *C, wmOperator *op)
return;
}
- ScrArea *sa = dgo->sa;
+ ScrArea *area = dgo->area;
LinkData *link;
for (link = dgo->bezt_arr_list.first; link != NULL; link = link->next) {
@@ -1423,7 +1424,7 @@ static void decimate_exit(bContext *C, wmOperator *op)
/* Return to normal cursor and header status. */
WM_cursor_modal_restore(win);
- ED_area_status_text(sa, NULL);
+ ED_area_status_text(area, NULL);
/* cleanup */
op->customdata = NULL;
@@ -1450,7 +1451,7 @@ static void decimate_draw_status_header(wmOperator *op, tDecimateGraphOp *dgo)
status_str, sizeof(status_str), "%s: %d %%", mode_str, (int)(percentage * 100.0f));
}
- ED_area_status_text(dgo->sa, status_str);
+ ED_area_status_text(dgo->area, status_str);
}
/* Calculate percentage based on position of mouse (we only use x-axis for now.
@@ -1482,7 +1483,7 @@ static int graphkeys_decimate_invoke(bContext *C, wmOperator *op, const wmEvent
dgo->percentage_prop = RNA_struct_find_property(op->ptr, "remove_ratio");
dgo->scene = CTX_data_scene(C);
- dgo->sa = CTX_wm_area(C);
+ dgo->area = CTX_wm_area(C);
dgo->region = CTX_wm_region(C);
/* initialise percentage so that it will have the correct value before the first mouse move. */
@@ -2647,7 +2648,7 @@ static int graphkeys_euler_filter_exec(bContext *C, wmOperator *op)
for (f = 0; f < 3; f++) {
FCurve *fcu = euf->fcurves[f];
BezTriple *bezt, *prev;
- unsigned int i;
+ uint i;
/* skip if not enough vets to do a decent analysis of... */
if (fcu->totvert <= 2) {
@@ -3569,7 +3570,7 @@ static int graph_driver_delete_invalid_exec(bContext *C, wmOperator *op)
bAnimListElem *ale;
int filter;
bool ok = false;
- unsigned int deleted = 0;
+ uint deleted = 0;
/* get editor data */
if (ANIM_animdata_get_context(C, &ac) == 0) {
@@ -3623,10 +3624,10 @@ static int graph_driver_delete_invalid_exec(bContext *C, wmOperator *op)
static bool graph_driver_delete_invalid_poll(bContext *C)
{
bAnimContext ac;
- ScrArea *sa = CTX_wm_area(C);
+ ScrArea *area = CTX_wm_area(C);
/* firstly, check if in Graph Editor */
- if ((sa == NULL) || (sa->spacetype != SPACE_GRAPH)) {
+ if ((area == NULL) || (area->spacetype != SPACE_GRAPH)) {
return 0;
}
diff --git a/source/blender/editors/space_graph/graph_select.c b/source/blender/editors/space_graph/graph_select.c
index a2e9ba86dec..ae435b5624a 100644
--- a/source/blender/editors/space_graph/graph_select.c
+++ b/source/blender/editors/space_graph/graph_select.c
@@ -760,8 +760,8 @@ static int graphkeys_lassoselect_exec(bContext *C, wmOperator *op)
}
data_lasso.rectf_view = &rect_fl;
- data_lasso.mcords = WM_gesture_lasso_path_to_array(C, op, &data_lasso.mcords_tot);
- if (data_lasso.mcords == NULL) {
+ data_lasso.mcoords = WM_gesture_lasso_path_to_array(C, op, &data_lasso.mcoords_len);
+ if (data_lasso.mcoords == NULL) {
return OPERATOR_CANCELLED;
}
@@ -782,13 +782,13 @@ static int graphkeys_lassoselect_exec(bContext *C, wmOperator *op)
}
/* get settings from operator */
- BLI_lasso_boundbox(&rect, data_lasso.mcords, data_lasso.mcords_tot);
+ BLI_lasso_boundbox(&rect, data_lasso.mcoords, data_lasso.mcoords_len);
BLI_rctf_rcti_copy(&rect_fl, &rect);
/* apply box_select action */
box_select_graphkeys(&ac, &rect_fl, BEZT_OK_REGION_LASSO, selectmode, incl_handles, &data_lasso);
- MEM_freeN((void *)data_lasso.mcords);
+ MEM_freeN((void *)data_lasso.mcoords);
/* send notifier that keyframe selection has changed */
WM_event_add_notifier(C, NC_ANIMATION | ND_KEYFRAME | NA_SELECTED, NULL);
diff --git a/source/blender/editors/space_graph/graph_utils.c b/source/blender/editors/space_graph/graph_utils.c
index 0af94904ba6..03ed8870d67 100644
--- a/source/blender/editors/space_graph/graph_utils.c
+++ b/source/blender/editors/space_graph/graph_utils.c
@@ -54,40 +54,40 @@
/* Set up UI configuration for Drivers Editor */
/* NOTE: Currently called from windowmanager
* (new drivers editor window) and RNA (mode switching) */
-void ED_drivers_editor_init(bContext *C, ScrArea *sa)
+void ED_drivers_editor_init(bContext *C, ScrArea *area)
{
- SpaceGraph *sipo = (SpaceGraph *)sa->spacedata.first;
+ SpaceGraph *sipo = (SpaceGraph *)area->spacedata.first;
/* Set mode */
sipo->mode = SIPO_MODE_DRIVERS;
/* Show Properties Region (or else the settings can't be edited) */
- ARegion *ar_props = BKE_area_find_region_type(sa, RGN_TYPE_UI);
- if (ar_props) {
- UI_panel_category_active_set(ar_props, "Drivers");
+ ARegion *region_props = BKE_area_find_region_type(area, RGN_TYPE_UI);
+ if (region_props) {
+ UI_panel_category_active_set(region_props, "Drivers");
- ar_props->flag &= ~RGN_FLAG_HIDDEN;
+ region_props->flag &= ~RGN_FLAG_HIDDEN;
/* XXX: Adjust width of this too? */
- ED_region_visibility_change_update(C, sa, ar_props);
+ ED_region_visibility_change_update(C, area, region_props);
}
else {
- printf("%s: Couldn't find properties region for Drivers Editor - %p\n", __func__, sa);
+ printf("%s: Couldn't find properties region for Drivers Editor - %p\n", __func__, area);
}
/* Adjust framing in graph region */
/* TODO: Have a way of not resetting this every time?
* (e.g. So that switching back and forth between editors doesn't keep jumping?)
*/
- ARegion *ar_main = BKE_area_find_region_type(sa, RGN_TYPE_WINDOW);
- if (ar_main) {
+ ARegion *region_main = BKE_area_find_region_type(area, RGN_TYPE_WINDOW);
+ if (region_main) {
/* XXX: Ideally we recenter based on the range instead... */
- ar_main->v2d.tot.xmin = -2.0f;
- ar_main->v2d.tot.ymin = -2.0f;
- ar_main->v2d.tot.xmax = 2.0f;
- ar_main->v2d.tot.ymax = 2.0f;
+ region_main->v2d.tot.xmin = -2.0f;
+ region_main->v2d.tot.ymin = -2.0f;
+ region_main->v2d.tot.xmax = 2.0f;
+ region_main->v2d.tot.ymax = 2.0f;
- ar_main->v2d.cur = ar_main->v2d.tot;
+ region_main->v2d.cur = region_main->v2d.tot;
}
}
@@ -135,14 +135,14 @@ bool graphop_visible_keyframes_poll(bContext *C)
bAnimContext ac;
bAnimListElem *ale;
ListBase anim_data = {NULL, NULL};
- ScrArea *sa = CTX_wm_area(C);
+ ScrArea *area = CTX_wm_area(C);
size_t items;
int filter;
short found = 0;
/* firstly, check if in Graph Editor */
// TODO: also check for region?
- if ((sa == NULL) || (sa->spacetype != SPACE_GRAPH)) {
+ if ((area == NULL) || (area->spacetype != SPACE_GRAPH)) {
return 0;
}
@@ -171,7 +171,7 @@ bool graphop_visible_keyframes_poll(bContext *C)
if (fcu->bezt == NULL) {
continue;
}
- if (fcurve_are_keyframes_usable(fcu)) {
+ if (BKE_fcurve_are_keyframes_usable(fcu)) {
found = 1;
break;
}
@@ -188,14 +188,14 @@ bool graphop_editable_keyframes_poll(bContext *C)
bAnimContext ac;
bAnimListElem *ale;
ListBase anim_data = {NULL, NULL};
- ScrArea *sa = CTX_wm_area(C);
+ ScrArea *area = CTX_wm_area(C);
size_t items;
int filter;
short found = 0;
/* firstly, check if in Graph Editor */
// TODO: also check for region?
- if ((sa == NULL) || (sa->spacetype != SPACE_GRAPH)) {
+ if ((area == NULL) || (area->spacetype != SPACE_GRAPH)) {
return 0;
}
@@ -225,7 +225,7 @@ bool graphop_editable_keyframes_poll(bContext *C)
if (fcu->bezt == NULL) {
continue;
}
- if (fcurve_is_keyframable(fcu)) {
+ if (BKE_fcurve_is_keyframable(fcu)) {
found = 1;
break;
}
@@ -241,12 +241,12 @@ bool graphop_active_fcurve_poll(bContext *C)
{
bAnimContext ac;
bAnimListElem *ale;
- ScrArea *sa = CTX_wm_area(C);
+ ScrArea *area = CTX_wm_area(C);
bool has_fcurve = 0;
/* firstly, check if in Graph Editor */
// TODO: also check for region?
- if ((sa == NULL) || (sa->spacetype != SPACE_GRAPH)) {
+ if ((area == NULL) || (area->spacetype != SPACE_GRAPH)) {
return 0;
}
@@ -293,13 +293,13 @@ bool graphop_selected_fcurve_poll(bContext *C)
{
bAnimContext ac;
ListBase anim_data = {NULL, NULL};
- ScrArea *sa = CTX_wm_area(C);
+ ScrArea *area = CTX_wm_area(C);
size_t items;
int filter;
/* firstly, check if in Graph Editor */
// TODO: also check for region?
- if ((sa == NULL) || (sa->spacetype != SPACE_GRAPH)) {
+ if ((area == NULL) || (area->spacetype != SPACE_GRAPH)) {
return 0;
}
diff --git a/source/blender/editors/space_graph/space_graph.c b/source/blender/editors/space_graph/space_graph.c
index 05edfccd6a8..b9c7c529620 100644
--- a/source/blender/editors/space_graph/space_graph.c
+++ b/source/blender/editors/space_graph/space_graph.c
@@ -64,7 +64,7 @@
/* ******************** default callbacks for ipo space ***************** */
-static SpaceLink *graph_new(const ScrArea *UNUSED(sa), const Scene *scene)
+static SpaceLink *graph_new(const ScrArea *UNUSED(area), const Scene *scene)
{
ARegion *region;
SpaceGraph *sipo;
@@ -145,14 +145,14 @@ static void graph_free(SpaceLink *sl)
}
if (si->runtime.ghost_curves.first) {
- free_fcurves(&si->runtime.ghost_curves);
+ BKE_fcurves_free(&si->runtime.ghost_curves);
}
}
/* spacetype; init callback */
-static void graph_init(struct wmWindowManager *wm, ScrArea *sa)
+static void graph_init(struct wmWindowManager *wm, ScrArea *area)
{
- SpaceGraph *sipo = (SpaceGraph *)sa->spacedata.first;
+ SpaceGraph *sipo = (SpaceGraph *)area->spacedata.first;
/* init dopesheet data if non-existent (i.e. for old files) */
if (sipo->ads == NULL) {
@@ -165,7 +165,7 @@ static void graph_init(struct wmWindowManager *wm, ScrArea *sa)
* as this is run on each region resize; setting this here will cause selection
* state to be lost on area/region resizing. [#35744]
*/
- ED_area_tag_refresh(sa);
+ ED_area_tag_refresh(area);
}
static SpaceLink *graph_duplicate(SpaceLink *sl)
@@ -413,7 +413,7 @@ static void graph_buttons_region_draw(const bContext *C, ARegion *region)
}
static void graph_region_listener(wmWindow *UNUSED(win),
- ScrArea *UNUSED(sa),
+ ScrArea *UNUSED(area),
ARegion *region,
wmNotifier *wmn,
const Scene *UNUSED(scene))
@@ -483,12 +483,12 @@ static void graph_region_message_subscribe(const struct bContext *UNUSED(C),
struct WorkSpace *UNUSED(workspace),
struct Scene *scene,
struct bScreen *screen,
- struct ScrArea *sa,
+ struct ScrArea *area,
struct ARegion *region,
struct wmMsgBus *mbus)
{
PointerRNA ptr;
- RNA_pointer_create(&screen->id, &RNA_SpaceGraphEditor, sa->spacedata.first, &ptr);
+ RNA_pointer_create(&screen->id, &RNA_SpaceGraphEditor, area->spacedata.first, &ptr);
wmMsgSubscribeValue msg_sub_value_region_tag_redraw = {
.owner = region,
@@ -556,11 +556,11 @@ static void graph_region_message_subscribe(const struct bContext *UNUSED(C),
/* editor level listener */
static void graph_listener(wmWindow *UNUSED(win),
- ScrArea *sa,
+ ScrArea *area,
wmNotifier *wmn,
Scene *UNUSED(scene))
{
- SpaceGraph *sipo = (SpaceGraph *)sa->spacedata.first;
+ SpaceGraph *sipo = (SpaceGraph *)area->spacedata.first;
/* context changes */
switch (wmn->category) {
@@ -568,10 +568,10 @@ static void graph_listener(wmWindow *UNUSED(win),
/* for selection changes of animation data, we can just redraw...
* otherwise autocolor might need to be done again */
if (ELEM(wmn->data, ND_KEYFRAME, ND_ANIMCHAN) && (wmn->action == NA_SELECTED)) {
- ED_area_tag_redraw(sa);
+ ED_area_tag_redraw(area);
}
else {
- ED_area_tag_refresh(sa);
+ ED_area_tag_refresh(area);
}
break;
case NC_SCENE:
@@ -580,11 +580,11 @@ static void graph_listener(wmWindow *UNUSED(win),
* (needs flag set to do syncing). */
case ND_OB_SELECT:
sipo->runtime.flag |= SIPO_RUNTIME_FLAG_NEED_CHAN_SYNC;
- ED_area_tag_refresh(sa);
+ ED_area_tag_refresh(area);
break;
default: /* just redrawing the view will do */
- ED_area_tag_redraw(sa);
+ ED_area_tag_redraw(area);
break;
}
break;
@@ -594,13 +594,13 @@ static void graph_listener(wmWindow *UNUSED(win),
* (needs flag set to do syncing). */
case ND_BONE_ACTIVE:
sipo->runtime.flag |= SIPO_RUNTIME_FLAG_NEED_CHAN_SYNC;
- ED_area_tag_refresh(sa);
+ ED_area_tag_refresh(area);
break;
case ND_TRANSFORM:
break; /*do nothing*/
default: /* just redrawing the view will do */
- ED_area_tag_redraw(sa);
+ ED_area_tag_redraw(area);
break;
}
break;
@@ -608,26 +608,26 @@ static void graph_listener(wmWindow *UNUSED(win),
if (wmn->action == NA_SELECTED) {
/* selection changed, so force refresh to flush (needs flag set to do syncing) */
sipo->runtime.flag |= SIPO_RUNTIME_FLAG_NEED_CHAN_SYNC;
- ED_area_tag_refresh(sa);
+ ED_area_tag_refresh(area);
}
break;
case NC_SPACE:
if (wmn->data == ND_SPACE_GRAPH) {
- ED_area_tag_redraw(sa);
+ ED_area_tag_redraw(area);
}
break;
case NC_WINDOW:
if (sipo->runtime.flag &
(SIPO_RUNTIME_FLAG_NEED_CHAN_SYNC | SIPO_RUNTIME_FLAG_NEED_CHAN_SYNC_COLOR)) {
/* force redraw/refresh after undo/redo - prevents "black curve" problem */
- ED_area_tag_refresh(sa);
+ ED_area_tag_refresh(area);
}
break;
// XXX: restore the case below if not enough updates occur...
// default:
// if (wmn->data == ND_KEYS)
- // ED_area_tag_redraw(sa);
+ // ED_area_tag_redraw(area);
}
}
@@ -754,9 +754,9 @@ static void graph_refresh_fcurve_colors(const bContext *C)
ANIM_animdata_freelist(&anim_data);
}
-static void graph_refresh(const bContext *C, ScrArea *sa)
+static void graph_refresh(const bContext *C, ScrArea *area)
{
- SpaceGraph *sipo = (SpaceGraph *)sa->spacedata.first;
+ SpaceGraph *sipo = (SpaceGraph *)area->spacedata.first;
/* updates to data needed depends on Graph Editor mode... */
switch (sipo->mode) {
@@ -780,7 +780,7 @@ static void graph_refresh(const bContext *C, ScrArea *sa)
if (sipo->runtime.flag & SIPO_RUNTIME_FLAG_NEED_CHAN_SYNC) {
ANIM_sync_animchannels_to_data(C);
sipo->runtime.flag &= ~SIPO_RUNTIME_FLAG_NEED_CHAN_SYNC;
- ED_area_tag_redraw(sa);
+ ED_area_tag_redraw(area);
}
/* We could check 'SIPO_RUNTIME_FLAG_NEED_CHAN_SYNC_COLOR', but color is recalculated anyway. */
@@ -789,7 +789,7 @@ static void graph_refresh(const bContext *C, ScrArea *sa)
#if 0 /* Done below. */
graph_refresh_fcurve_colors(C);
#endif
- ED_area_tag_redraw(sa);
+ ED_area_tag_redraw(area);
}
sipo->runtime.flag &= ~(SIPO_RUNTIME_FLAG_TWEAK_HANDLES_LEFT |
@@ -799,7 +799,7 @@ static void graph_refresh(const bContext *C, ScrArea *sa)
graph_refresh_fcurve_colors(C);
}
-static void graph_id_remap(ScrArea *UNUSED(sa), SpaceLink *slink, ID *old_id, ID *new_id)
+static void graph_id_remap(ScrArea *UNUSED(area), SpaceLink *slink, ID *old_id, ID *new_id)
{
SpaceGraph *sgraph = (SpaceGraph *)slink;
@@ -813,15 +813,15 @@ static void graph_id_remap(ScrArea *UNUSED(sa), SpaceLink *slink, ID *old_id, ID
}
}
-static int graph_space_subtype_get(ScrArea *sa)
+static int graph_space_subtype_get(ScrArea *area)
{
- SpaceGraph *sgraph = sa->spacedata.first;
+ SpaceGraph *sgraph = area->spacedata.first;
return sgraph->mode;
}
-static void graph_space_subtype_set(ScrArea *sa, int value)
+static void graph_space_subtype_set(ScrArea *area, int value)
{
- SpaceGraph *sgraph = sa->spacedata.first;
+ SpaceGraph *sgraph = area->spacedata.first;
sgraph->mode = value;
}
diff --git a/source/blender/editors/space_image/image_buttons.c b/source/blender/editors/space_image/image_buttons.c
index 873091bd68d..6f3ef44fe94 100644
--- a/source/blender/editors/space_image/image_buttons.c
+++ b/source/blender/editors/space_image/image_buttons.c
@@ -656,8 +656,8 @@ static void uiblock_layer_pass_buttons(
/* pass */
rpass = (rl ? BLI_findlink(&rl->passes, iuser->pass) : NULL);
- if (rpass && RE_passes_have_name(rl)) {
- display_name = rpass->name;
+ if (rl && RE_passes_have_name(rl)) {
+ display_name = rpass ? rpass->name : "";
rnd_pt = ui_imageuser_data_copy(&rnd_pt_local);
but = uiDefMenuBut(block,
ui_imageuser_pass_menu,
@@ -1276,7 +1276,7 @@ void uiTemplateImageInfo(uiLayout *layout, bContext *C, Image *ima, ImageUser *i
}
else if (ima->source == IMA_SRC_SEQUENCE && ibuf) {
/* Image sequence frame number + filename */
- const char *filename = BLI_last_slash(ibuf->name);
+ const char *filename = BLI_path_slash_rfind(ibuf->name);
filename = (filename == NULL) ? ibuf->name : filename + 1;
BLI_snprintf(str, MAX_IMAGE_INFO_LEN, TIP_("Frame %d: %s"), framenr, filename);
}
diff --git a/source/blender/editors/space_image/image_draw.c b/source/blender/editors/space_image/image_draw.c
index 85f7f744abc..9040ca5e79c 100644
--- a/source/blender/editors/space_image/image_draw.c
+++ b/source/blender/editors/space_image/image_draw.c
@@ -476,7 +476,7 @@ static void sima_draw_zbuf_pixels(
IMMDrawPixelsTexState state = immDrawPixelsTexSetup(GPU_SHADER_2D_IMAGE_SHUFFLE_COLOR);
GPU_shader_uniform_vector(
- state.shader, GPU_shader_get_uniform_ensure(state.shader, "shuffle"), 4, 1, red);
+ state.shader, GPU_shader_get_uniform(state.shader, "shuffle"), 4, 1, red);
immDrawPixelsTex(
&state, x1, y1, rectx, recty, GL_RED, GL_INT, GL_NEAREST, recti, zoomx, zoomy, NULL);
@@ -524,7 +524,7 @@ static void sima_draw_zbuffloat_pixels(Scene *scene,
IMMDrawPixelsTexState state = immDrawPixelsTexSetup(GPU_SHADER_2D_IMAGE_SHUFFLE_COLOR);
GPU_shader_uniform_vector(
- state.shader, GPU_shader_get_uniform_ensure(state.shader, "shuffle"), 4, 1, red);
+ state.shader, GPU_shader_get_uniform(state.shader, "shuffle"), 4, 1, red);
immDrawPixelsTex(
&state, x1, y1, rectx, recty, GL_RED, GL_FLOAT, GL_NEAREST, rectf, zoomx, zoomy, NULL);
@@ -575,6 +575,9 @@ static void draw_image_buffer(const bContext *C,
float zoomx,
float zoomy)
{
+ /* Image are still drawn in display space. */
+ glDisable(GL_FRAMEBUFFER_SRGB);
+
int x, y;
int sima_flag = sima->flag & ED_space_image_get_display_channel_mask(ibuf);
@@ -634,7 +637,7 @@ static void draw_image_buffer(const bContext *C,
IMMDrawPixelsTexState state = immDrawPixelsTexSetup(GPU_SHADER_2D_IMAGE_SHUFFLE_COLOR);
GPU_shader_uniform_vector(
- state.shader, GPU_shader_get_uniform_ensure(state.shader, "shuffle"), 4, 1, shuffle);
+ state.shader, GPU_shader_get_uniform(state.shader, "shuffle"), 4, 1, shuffle);
IMB_colormanagement_display_settings_from_ctx(C, &view_settings, &display_settings);
display_buffer = IMB_display_buffer_acquire(
@@ -666,6 +669,8 @@ static void draw_image_buffer(const bContext *C,
GPU_blend(false);
}
}
+
+ glEnable(GL_FRAMEBUFFER_SRGB);
}
static void draw_image_buffer_repeated(const bContext *C,
diff --git a/source/blender/editors/space_image/image_edit.c b/source/blender/editors/space_image/image_edit.c
index 7f911113b7c..c9f2ec38354 100644
--- a/source/blender/editors/space_image/image_edit.c
+++ b/source/blender/editors/space_image/image_edit.c
@@ -264,7 +264,10 @@ void ED_space_image_get_aspect(SpaceImage *sima, float *r_aspx, float *r_aspy)
}
}
-void ED_space_image_get_zoom(SpaceImage *sima, ARegion *region, float *r_zoomx, float *r_zoomy)
+void ED_space_image_get_zoom(SpaceImage *sima,
+ const ARegion *region,
+ float *r_zoomx,
+ float *r_zoomy)
{
int width, height;
@@ -314,7 +317,7 @@ void ED_image_get_uv_aspect(Image *ima, ImageUser *iuser, float *r_aspx, float *
}
/* takes event->mval */
-void ED_image_mouse_pos(SpaceImage *sima, ARegion *region, const int mval[2], float co[2])
+void ED_image_mouse_pos(SpaceImage *sima, const ARegion *region, const int mval[2], float co[2])
{
int sx, sy, width, height;
float zoomx, zoomy;
@@ -341,7 +344,7 @@ void ED_image_view_center_to_point(SpaceImage *sima, float x, float y)
}
void ED_image_point_pos(
- SpaceImage *sima, ARegion *region, float x, float y, float *r_x, float *r_y)
+ SpaceImage *sima, const ARegion *region, float x, float y, float *r_x, float *r_y)
{
int sx, sy, width, height;
float zoomx, zoomy;
@@ -356,7 +359,7 @@ void ED_image_point_pos(
}
void ED_image_point_pos__reverse(SpaceImage *sima,
- ARegion *region,
+ const ARegion *region,
const float co[2],
float r_co[2])
{
diff --git a/source/blender/editors/space_image/image_ops.c b/source/blender/editors/space_image/image_ops.c
index 7bd1b8e8291..8cb85ce9800 100644
--- a/source/blender/editors/space_image/image_ops.c
+++ b/source/blender/editors/space_image/image_ops.c
@@ -58,6 +58,7 @@
#include "BKE_icons.h"
#include "BKE_image.h"
#include "BKE_image_save.h"
+#include "BKE_layer.h"
#include "BKE_lib_id.h"
#include "BKE_main.h"
#include "BKE_packedFile.h"
@@ -91,6 +92,7 @@
#include "ED_screen.h"
#include "ED_space_api.h"
#include "ED_util.h"
+#include "ED_util_imbuf.h"
#include "ED_uvedit.h"
#include "UI_interface.h"
@@ -277,28 +279,6 @@ static bool space_image_main_area_not_uv_brush_poll(bContext *C)
return 0;
}
-static bool image_sample_poll(bContext *C)
-{
- SpaceImage *sima = CTX_wm_space_image(C);
- if (sima == NULL) {
- return false;
- }
-
- Object *obedit = CTX_data_edit_object(C);
- if (obedit) {
- /* Disable when UV editing so it doesn't swallow all click events
- * (use for setting cursor). */
- if (ED_space_image_show_uvedit(sima, obedit)) {
- return false;
- }
- }
- else if (sima->mode != SI_MODE_VIEW) {
- return false;
- }
-
- return true;
-}
-
/** \} */
/* -------------------------------------------------------------------- */
@@ -846,7 +826,7 @@ void IMAGE_OT_view_all(wmOperatorType *ot)
PropertyRNA *prop;
/* identifiers */
- ot->name = "View All";
+ ot->name = "Frame All";
ot->idname = "IMAGE_OT_view_all";
ot->description = "View the entire image";
@@ -905,7 +885,6 @@ static int image_view_selected_exec(bContext *C, wmOperator *UNUSED(op))
Scene *scene;
ViewLayer *view_layer;
Object *obedit;
- Image *ima;
/* retrieve state */
sima = CTX_wm_space_image(C);
@@ -914,12 +893,15 @@ static int image_view_selected_exec(bContext *C, wmOperator *UNUSED(op))
view_layer = CTX_data_view_layer(C);
obedit = CTX_data_edit_object(C);
- ima = ED_space_image(sima);
-
/* get bounds */
float min[2], max[2];
if (ED_space_image_show_uvedit(sima, obedit)) {
- if (!ED_uvedit_minmax(scene, ima, obedit, min, max)) {
+ uint objects_len = 0;
+ Object **objects = BKE_view_layer_array_from_objects_in_edit_mode_unique_data_with_uvs(
+ view_layer, ((View3D *)NULL), &objects_len);
+ bool success = ED_uvedit_minmax_multi(scene, objects, objects_len, min, max);
+ MEM_freeN(objects);
+ if (!success) {
return OPERATOR_CANCELLED;
}
}
@@ -1001,7 +983,7 @@ void IMAGE_OT_view_zoom_in(wmOperatorType *ot)
PropertyRNA *prop;
/* identifiers */
- ot->name = "View Zoom In";
+ ot->name = "Zoom In";
ot->idname = "IMAGE_OT_view_zoom_in";
ot->description = "Zoom in the image (centered around 2D cursor)";
@@ -1060,7 +1042,7 @@ void IMAGE_OT_view_zoom_out(wmOperatorType *ot)
PropertyRNA *prop;
/* identifiers */
- ot->name = "View Zoom Out";
+ ot->name = "Zoom Out";
ot->idname = "IMAGE_OT_view_zoom_out";
ot->description = "Zoom out the image (centered around 2D cursor)";
@@ -1275,7 +1257,7 @@ static Image *image_open_single(Main *bmain,
if ((range->length > 1) && (ima->source == IMA_SRC_FILE)) {
if (range->udim_tiles.first && range->offset == 1001) {
ima->source = IMA_SRC_TILED;
- for (LinkData *node = range->udim_tiles.first; node; node = node->next) {
+ LISTBASE_FOREACH (LinkData *, node, &range->udim_tiles) {
BKE_image_add_tile(ima, POINTER_AS_INT(node->data), NULL);
}
}
@@ -1291,7 +1273,7 @@ static Image *image_open_single(Main *bmain,
static int image_open_exec(bContext *C, wmOperator *op)
{
Main *bmain = CTX_data_main(C);
- ScrArea *sa = CTX_wm_area(C);
+ ScrArea *area = CTX_wm_area(C);
Scene *scene = CTX_data_scene(C);
Object *obedit = CTX_data_edit_object(C);
ImageUser *iuser = NULL;
@@ -1309,7 +1291,7 @@ static int image_open_exec(bContext *C, wmOperator *op)
}
ListBase ranges = ED_image_filesel_detect_sequences(bmain, op, use_udim);
- for (ImageFrameRange *range = ranges.first; range; range = range->next) {
+ LISTBASE_FOREACH (ImageFrameRange *, range, &ranges) {
Image *ima_range = image_open_single(
bmain, op, range, BKE_main_blendfile_path(bmain), is_relative_path, use_multiview);
@@ -1345,8 +1327,8 @@ static int image_open_exec(bContext *C, wmOperator *op)
if (iod->iuser) {
iuser = iod->iuser;
}
- else if (sa && sa->spacetype == SPACE_IMAGE) {
- SpaceImage *sima = sa->spacedata.first;
+ else if (area && area->spacetype == SPACE_IMAGE) {
+ SpaceImage *sima = area->spacedata.first;
ED_space_image_set(bmain, sima, obedit, ima, false);
iuser = &sima->iuser;
}
@@ -1359,7 +1341,7 @@ static int image_open_exec(bContext *C, wmOperator *op)
if (iuser == NULL) {
Camera *cam = CTX_data_pointer_get_type(C, "camera", &RNA_Camera).data;
if (cam) {
- for (CameraBGImage *bgpic = cam->bg_images.first; bgpic; bgpic = bgpic->next) {
+ LISTBASE_FOREACH (CameraBGImage *, bgpic, &cam->bg_images) {
if (bgpic->ima == ima) {
iuser = &bgpic->iuser;
break;
@@ -1794,7 +1776,8 @@ static int image_save_options_init(Main *bmain,
}
/* append UDIM numbering if not present */
- if (ima->source == IMA_SRC_TILED && (BLI_stringdec(ima->name, NULL, NULL, NULL) != 1001)) {
+ if (ima->source == IMA_SRC_TILED &&
+ (BLI_path_sequence_decode(ima->name, NULL, NULL, NULL) != 1001)) {
int len = strlen(opts->filepath);
STR_CONCAT(opts->filepath, len, ".1001");
}
@@ -3098,85 +3081,6 @@ void IMAGE_OT_unpack(wmOperatorType *ot)
/** \name Sample Image Operator
* \{ */
-typedef struct ImageSampleInfo {
- ARegionType *art;
- void *draw_handle;
- int x, y;
- int channels;
-
- int width, height;
- int sample_size;
-
- unsigned char col[4];
- float colf[4];
- float linearcol[4];
- int z;
- float zf;
-
- unsigned char *colp;
- const float *colfp;
- int *zp;
- float *zfp;
-
- bool draw;
- bool color_manage;
- int use_default_view;
-} ImageSampleInfo;
-
-static void image_sample_draw(const bContext *C, ARegion *region, void *arg_info)
-{
- ImageSampleInfo *info = arg_info;
- if (!info->draw) {
- return;
- }
-
- Scene *scene = CTX_data_scene(C);
- ED_image_draw_info(scene,
- region,
- info->color_manage,
- info->use_default_view,
- info->channels,
- info->x,
- info->y,
- info->colp,
- info->colfp,
- info->linearcol,
- info->zp,
- info->zfp);
-
- if (info->sample_size > 1) {
- const wmWindow *win = CTX_wm_window(C);
- const wmEvent *event = win->eventstate;
-
- SpaceImage *sima = CTX_wm_space_image(C);
- GPUVertFormat *format = immVertexFormat();
- uint pos = GPU_vertformat_attr_add(format, "pos", GPU_COMP_F32, 2, GPU_FETCH_FLOAT);
-
- const float color[3] = {1, 1, 1};
- immBindBuiltinProgram(GPU_SHADER_2D_UNIFORM_COLOR);
- immUniformColor3fv(color);
-
- /* TODO(campbell): lock to pixels. */
- rctf sample_rect_fl;
- BLI_rctf_init_pt_radius(
- &sample_rect_fl,
- (float[2]){event->x - region->winrct.xmin, event->y - region->winrct.ymin},
- (float)(info->sample_size / 2.0f) * sima->zoom);
-
- glEnable(GL_COLOR_LOGIC_OP);
- glLogicOp(GL_XOR);
- GPU_line_width(1.0f);
- imm_draw_box_wire_2d(pos,
- (float)sample_rect_fl.xmin,
- (float)sample_rect_fl.ymin,
- (float)sample_rect_fl.xmax,
- (float)sample_rect_fl.ymax);
- glDisable(GL_COLOR_LOGIC_OP);
-
- immUnbindProgram();
- }
-}
-
/* Returns color in linear space, matching ED_space_node_color_sample(). */
bool ED_space_image_color_sample(SpaceImage *sima, ARegion *region, int mval[2], float r_col[3])
{
@@ -3198,7 +3102,7 @@ bool ED_space_image_color_sample(SpaceImage *sima, ARegion *region, int mval[2],
if (uv[0] >= 0.0f && uv[1] >= 0.0f && uv[0] < 1.0f && uv[1] < 1.0f) {
const float *fp;
- unsigned char *cp;
+ uchar *cp;
int x = (int)(uv[0] * ibuf->x), y = (int)(uv[1] * ibuf->y);
CLAMP(x, 0, ibuf->x - 1);
@@ -3210,7 +3114,7 @@ bool ED_space_image_color_sample(SpaceImage *sima, ARegion *region, int mval[2],
ret = true;
}
else if (ibuf->rect) {
- cp = (unsigned char *)(ibuf->rect + y * ibuf->x + x);
+ cp = (uchar *)(ibuf->rect + y * ibuf->x + x);
rgb_uchar_to_float(r_col, cp);
IMB_colormanagement_colorspace_to_scene_linear_v3(r_col, ibuf->rect_colorspace);
ret = true;
@@ -3221,279 +3125,6 @@ bool ED_space_image_color_sample(SpaceImage *sima, ARegion *region, int mval[2],
return ret;
}
-/* -------------------------------------------------------------------- */
-/** \name Image Pixel Sample
- * \{ */
-
-static void image_sample_pixel_color_ubyte(const ImBuf *ibuf,
- const int coord[2],
- uchar r_col[4],
- float r_col_linear[4])
-{
- const uchar *cp = (unsigned char *)(ibuf->rect + coord[1] * ibuf->x + coord[0]);
- copy_v4_v4_uchar(r_col, cp);
- rgba_uchar_to_float(r_col_linear, r_col);
- IMB_colormanagement_colorspace_to_scene_linear_v4(r_col_linear, false, ibuf->rect_colorspace);
-}
-
-static void image_sample_pixel_color_float(ImBuf *ibuf, const int coord[2], float r_col[4])
-{
- const float *cp = ibuf->rect_float + (ibuf->channels) * (coord[1] * ibuf->x + coord[0]);
- copy_v4_v4(r_col, cp);
-}
-
-/** \} */
-
-/* -------------------------------------------------------------------- */
-/** \name Image Pixel Region Sample
- * \{ */
-
-static void image_sample_rect_color_ubyte(const ImBuf *ibuf,
- const rcti *rect,
- uchar r_col[4],
- float r_col_linear[4])
-{
- uint col_accum_ub[4] = {0, 0, 0, 0};
- zero_v4(r_col_linear);
- int col_tot = 0;
- int coord[2];
- for (coord[0] = rect->xmin; coord[0] <= rect->xmax; coord[0]++) {
- for (coord[1] = rect->ymin; coord[1] <= rect->ymax; coord[1]++) {
- float col_temp_fl[4];
- uchar col_temp_ub[4];
- image_sample_pixel_color_ubyte(ibuf, coord, col_temp_ub, col_temp_fl);
- add_v4_v4(r_col_linear, col_temp_fl);
- col_accum_ub[0] += (uint)col_temp_ub[0];
- col_accum_ub[1] += (uint)col_temp_ub[1];
- col_accum_ub[2] += (uint)col_temp_ub[2];
- col_accum_ub[3] += (uint)col_temp_ub[3];
- col_tot += 1;
- }
- }
- mul_v4_fl(r_col_linear, 1.0 / (float)col_tot);
-
- r_col[0] = MIN2(col_accum_ub[0] / col_tot, 255);
- r_col[1] = MIN2(col_accum_ub[1] / col_tot, 255);
- r_col[2] = MIN2(col_accum_ub[2] / col_tot, 255);
- r_col[3] = MIN2(col_accum_ub[3] / col_tot, 255);
-}
-
-static void image_sample_rect_color_float(ImBuf *ibuf, const rcti *rect, float r_col[4])
-{
- zero_v4(r_col);
- int col_tot = 0;
- int coord[2];
- for (coord[0] = rect->xmin; coord[0] <= rect->xmax; coord[0]++) {
- for (coord[1] = rect->ymin; coord[1] <= rect->ymax; coord[1]++) {
- float col_temp_fl[4];
- image_sample_pixel_color_float(ibuf, coord, col_temp_fl);
- add_v4_v4(r_col, col_temp_fl);
- col_tot += 1;
- }
- }
- mul_v4_fl(r_col, 1.0 / (float)col_tot);
-}
-
-/** \} */
-
-static void image_sample_apply(bContext *C, wmOperator *op, const wmEvent *event)
-{
- SpaceImage *sima = CTX_wm_space_image(C);
- ARegion *region = CTX_wm_region(C);
- Image *image = ED_space_image(sima);
-
- float uv[2];
- UI_view2d_region_to_view(&region->v2d, event->mval[0], event->mval[1], &uv[0], &uv[1]);
- int tile = BKE_image_get_tile_from_pos(sima->image, uv, uv, NULL);
-
- void *lock;
- ImBuf *ibuf = ED_space_image_acquire_buffer(sima, &lock, tile);
- ImageSampleInfo *info = op->customdata;
- Scene *scene = CTX_data_scene(C);
- CurveMapping *curve_mapping = scene->view_settings.curve_mapping;
-
- if (ibuf == NULL) {
- ED_space_image_release_buffer(sima, ibuf, lock);
- info->draw = false;
- return;
- }
-
- if (uv[0] >= 0.0f && uv[1] >= 0.0f && uv[0] < 1.0f && uv[1] < 1.0f) {
- int x = (int)(uv[0] * ibuf->x), y = (int)(uv[1] * ibuf->y);
-
- CLAMP(x, 0, ibuf->x - 1);
- CLAMP(y, 0, ibuf->y - 1);
-
- info->width = ibuf->x;
- info->height = ibuf->y;
- info->x = x;
- info->y = y;
-
- info->draw = true;
- info->channels = ibuf->channels;
-
- info->colp = NULL;
- info->colfp = NULL;
- info->zp = NULL;
- info->zfp = NULL;
-
- info->use_default_view = (image->flag & IMA_VIEW_AS_RENDER) ? false : true;
-
- rcti sample_rect;
- sample_rect.xmin = max_ii(0, x - info->sample_size / 2);
- sample_rect.ymin = max_ii(0, y - info->sample_size / 2);
- sample_rect.xmax = min_ii(ibuf->x, sample_rect.xmin + info->sample_size) - 1;
- sample_rect.ymax = min_ii(ibuf->y, sample_rect.ymin + info->sample_size) - 1;
-
- if (ibuf->rect) {
- image_sample_rect_color_ubyte(ibuf, &sample_rect, info->col, info->linearcol);
- rgba_uchar_to_float(info->colf, info->col);
-
- info->colp = info->col;
- info->colfp = info->colf;
- info->color_manage = true;
- }
- if (ibuf->rect_float) {
- image_sample_rect_color_float(ibuf, &sample_rect, info->colf);
-
- if (ibuf->channels == 4) {
- /* pass */
- }
- else if (ibuf->channels == 3) {
- info->colf[3] = 1.0f;
- }
- else {
- info->colf[1] = info->colf[0];
- info->colf[2] = info->colf[0];
- info->colf[3] = 1.0f;
- }
- info->colfp = info->colf;
-
- copy_v4_v4(info->linearcol, info->colf);
-
- info->color_manage = true;
- }
-
- if (ibuf->zbuf) {
- /* TODO, blend depth (not urgent). */
- info->z = ibuf->zbuf[y * ibuf->x + x];
- info->zp = &info->z;
- if (ibuf->zbuf == (int *)ibuf->rect) {
- info->colp = NULL;
- }
- }
- if (ibuf->zbuf_float) {
- /* TODO, blend depth (not urgent). */
- info->zf = ibuf->zbuf_float[y * ibuf->x + x];
- info->zfp = &info->zf;
- if (ibuf->zbuf_float == ibuf->rect_float) {
- info->colfp = NULL;
- }
- }
-
- if (curve_mapping && ibuf->channels == 4) {
- /* we reuse this callback for set curves point operators */
- if (RNA_struct_find_property(op->ptr, "point")) {
- int point = RNA_enum_get(op->ptr, "point");
-
- if (point == 1) {
- BKE_curvemapping_set_black_white(curve_mapping, NULL, info->linearcol);
- }
- else if (point == 0) {
- BKE_curvemapping_set_black_white(curve_mapping, info->linearcol, NULL);
- }
- WM_event_add_notifier(C, NC_WINDOW, NULL);
- }
- }
-
- // XXX node curve integration ..
-#if 0
- {
- ScrArea *sa, *cur = curarea;
-
- node_curvemap_sample(fp); /* sends global to node editor */
- for (sa = G.curscreen->areabase.first; sa; sa = sa->next) {
- if (sa->spacetype == SPACE_NODE) {
- areawinset(sa->win);
- scrarea_do_windraw(sa);
- }
- }
- node_curvemap_sample(NULL); /* clears global in node editor */
- curarea = cur;
- }
-#endif
- }
- else {
- info->draw = 0;
- }
-
- ED_space_image_release_buffer(sima, ibuf, lock);
- ED_area_tag_redraw(CTX_wm_area(C));
-}
-
-static void image_sample_exit(bContext *C, wmOperator *op)
-{
- ImageSampleInfo *info = op->customdata;
-
- ED_region_draw_cb_exit(info->art, info->draw_handle);
- ED_area_tag_redraw(CTX_wm_area(C));
- MEM_freeN(info);
-}
-
-static int image_sample_invoke(bContext *C, wmOperator *op, const wmEvent *event)
-{
- SpaceImage *sima = CTX_wm_space_image(C);
- ARegion *region = CTX_wm_region(C);
- ImageSampleInfo *info;
-
- if (region->regiontype == RGN_TYPE_WINDOW) {
- if (event->mval[1] <= 16 && ED_space_image_show_cache(sima)) {
- return OPERATOR_PASS_THROUGH;
- }
- }
-
- if (!ED_space_image_has_buffer(sima)) {
- return OPERATOR_CANCELLED;
- }
-
- info = MEM_callocN(sizeof(ImageSampleInfo), "ImageSampleInfo");
-
- info->art = region->type;
- info->draw_handle = ED_region_draw_cb_activate(
- region->type, image_sample_draw, info, REGION_DRAW_POST_PIXEL);
- info->sample_size = RNA_int_get(op->ptr, "size");
- op->customdata = info;
-
- image_sample_apply(C, op, event);
-
- WM_event_add_modal_handler(C, op);
-
- return OPERATOR_RUNNING_MODAL;
-}
-
-static int image_sample_modal(bContext *C, wmOperator *op, const wmEvent *event)
-{
- switch (event->type) {
- case LEFTMOUSE:
- case RIGHTMOUSE: // XXX hardcoded
- if (event->val == KM_RELEASE) {
- image_sample_exit(C, op);
- return OPERATOR_CANCELLED;
- }
- break;
- case MOUSEMOVE:
- image_sample_apply(C, op, event);
- break;
- }
-
- return OPERATOR_RUNNING_MODAL;
-}
-
-static void image_sample_cancel(bContext *C, wmOperator *op)
-{
- image_sample_exit(C, op);
-}
-
void IMAGE_OT_sample(wmOperatorType *ot)
{
/* identifiers */
@@ -3502,10 +3133,10 @@ void IMAGE_OT_sample(wmOperatorType *ot)
ot->description = "Use mouse to sample a color in current image";
/* api callbacks */
- ot->invoke = image_sample_invoke;
- ot->modal = image_sample_modal;
- ot->cancel = image_sample_cancel;
- ot->poll = image_sample_poll;
+ ot->invoke = ED_imbuf_sample_invoke;
+ ot->modal = ED_imbuf_sample_modal;
+ ot->cancel = ED_imbuf_sample_cancel;
+ ot->poll = ED_imbuf_sample_poll;
/* flags */
ot->flag = OPTYPE_BLOCKING;
@@ -3631,9 +3262,9 @@ void IMAGE_OT_curves_point_set(wmOperatorType *ot)
ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
/* api callbacks */
- ot->invoke = image_sample_invoke;
- ot->modal = image_sample_modal;
- ot->cancel = image_sample_cancel;
+ ot->invoke = ED_imbuf_sample_invoke;
+ ot->modal = ED_imbuf_sample_modal;
+ ot->cancel = ED_imbuf_sample_cancel;
ot->poll = space_image_main_area_not_uv_brush_poll;
/* properties */
diff --git a/source/blender/editors/space_image/image_sequence.c b/source/blender/editors/space_image/image_sequence.c
index cc6fe38866d..0817bdda88d 100644
--- a/source/blender/editors/space_image/image_sequence.c
+++ b/source/blender/editors/space_image/image_sequence.c
@@ -64,22 +64,27 @@ static void image_sequence_get_frame_ranges(wmOperator *op, ListBase *ranges)
char dir[FILE_MAXDIR];
const bool do_frame_range = RNA_boolean_get(op->ptr, "use_sequence_detection");
ImageFrameRange *range = NULL;
+ int range_first_frame = 0;
RNA_string_get(op->ptr, "directory", dir);
RNA_BEGIN (op->ptr, itemptr, "files") {
char base_head[FILE_MAX], base_tail[FILE_MAX];
char head[FILE_MAX], tail[FILE_MAX];
- unsigned short digits;
+ ushort digits;
char *filename = RNA_string_get_alloc(&itemptr, "name", NULL, 0);
ImageFrame *frame = MEM_callocN(sizeof(ImageFrame), "image_frame");
/* use the first file in the list as base filename */
- frame->framenr = BLI_stringdec(filename, head, tail, &digits);
+ frame->framenr = BLI_path_sequence_decode(filename, head, tail, &digits);
/* still in the same sequence */
if (do_frame_range && (range != NULL) && (STREQLEN(base_head, head, FILE_MAX)) &&
(STREQLEN(base_tail, tail, FILE_MAX))) {
- /* pass */
+ /* Set filepath to first frame in the range. */
+ if (frame->framenr < range_first_frame) {
+ BLI_join_dirfile(range->filepath, sizeof(range->filepath), dir, filename);
+ range_first_frame = frame->framenr;
+ }
}
else {
/* start a new frame range */
@@ -89,6 +94,8 @@ static void image_sequence_get_frame_ranges(wmOperator *op, ListBase *ranges)
BLI_strncpy(base_head, head, sizeof(base_head));
BLI_strncpy(base_tail, tail, sizeof(base_tail));
+
+ range_first_frame = frame->framenr;
}
BLI_addtail(&range->frames, frame);
@@ -125,9 +132,9 @@ static int image_get_udim(char *filepath, ListBase *udim_tiles)
char filename[FILE_MAX], dirname[FILE_MAXDIR];
BLI_split_dirfile(filepath, dirname, filename, sizeof(dirname), sizeof(filename));
- unsigned short digits;
+ ushort digits;
char base_head[FILE_MAX], base_tail[FILE_MAX];
- int id = BLI_stringdec(filename, base_head, base_tail, &digits);
+ int id = BLI_path_sequence_decode(filename, base_head, base_tail, &digits);
if (id < 1001 || id >= IMA_UDIM_MAX) {
return 0;
@@ -144,7 +151,7 @@ static int image_get_udim(char *filepath, ListBase *udim_tiles)
continue;
}
char head[FILE_MAX], tail[FILE_MAX];
- id = BLI_stringdec(dir[i].relname, head, tail, &digits);
+ id = BLI_path_sequence_decode(dir[i].relname, head, tail, &digits);
if (digits > 4 || !(STREQLEN(base_head, head, FILE_MAX)) ||
!(STREQLEN(base_tail, tail, FILE_MAX))) {
@@ -166,7 +173,7 @@ static int image_get_udim(char *filepath, ListBase *udim_tiles)
if (is_udim && has_primary) {
char primary_filename[FILE_MAX];
- BLI_stringenc(primary_filename, base_head, base_tail, digits, 1001);
+ BLI_path_sequence_encode(primary_filename, base_head, base_tail, digits, 1001);
BLI_join_dirfile(filepath, FILE_MAX, dirname, primary_filename);
return max_udim - 1000;
}
@@ -226,7 +233,7 @@ ListBase ED_image_filesel_detect_sequences(Main *bmain, wmOperator *op, const bo
const bool was_relative = BLI_path_is_rel(filepath);
image_sequence_get_frame_ranges(op, &ranges);
- for (ImageFrameRange *range = ranges.first; range; range = range->next) {
+ LISTBASE_FOREACH (ImageFrameRange *, range, &ranges) {
image_detect_frame_range(range, detect_udim);
BLI_freelistN(&range->frames);
diff --git a/source/blender/editors/space_image/image_undo.c b/source/blender/editors/space_image/image_undo.c
index 1394c05d7bc..e0c44c3a0ba 100644
--- a/source/blender/editors/space_image/image_undo.c
+++ b/source/blender/editors/space_image/image_undo.c
@@ -145,7 +145,7 @@ static void ptile_free_list(ListBase *paint_tiles)
static void ptile_invalidate_list(ListBase *paint_tiles)
{
- for (PaintTile *ptile = paint_tiles->first; ptile; ptile = ptile->next) {
+ LISTBASE_FOREACH (PaintTile *, ptile, paint_tiles) {
ptile->valid = false;
}
}
@@ -159,7 +159,7 @@ void *ED_image_paint_tile_find(ListBase *paint_tiles,
ushort **r_mask,
bool validate)
{
- for (PaintTile *ptile = paint_tiles->first; ptile; ptile = ptile->next) {
+ LISTBASE_FOREACH (PaintTile *, ptile, paint_tiles) {
if (ptile->x_tile == x_tile && ptile->y_tile == y_tile) {
if (ptile->image == image && ptile->ibuf == ibuf && ptile->iuser.tile == iuser->tile) {
if (r_mask) {
@@ -225,9 +225,9 @@ void *ED_image_paint_tile_push(ListBase *paint_tiles,
"PaintTile.mask");
}
- ptile->rect.pt = MEM_mapallocN((ibuf->rect_float ? sizeof(float[4]) : sizeof(char[4])) *
- square_i(ED_IMAGE_UNDO_TILE_SIZE),
- "PaintTile.rect");
+ ptile->rect.pt = MEM_callocN((ibuf->rect_float ? sizeof(float[4]) : sizeof(char[4])) *
+ square_i(ED_IMAGE_UNDO_TILE_SIZE),
+ "PaintTile.rect");
ptile->use_float = has_float;
ptile->valid = true;
@@ -267,7 +267,7 @@ static void ptile_restore_runtime_list(ListBase *paint_tiles)
{
ImBuf *tmpibuf = imbuf_alloc_temp_tile();
- for (PaintTile *ptile = paint_tiles->first; ptile; ptile = ptile->next) {
+ LISTBASE_FOREACH (PaintTile *, ptile, paint_tiles) {
Image *image = ptile->image;
ImBuf *ibuf = BKE_image_acquire_ibuf(image, &ptile->iuser, NULL);
const bool has_float = (ibuf->rect_float != NULL);
@@ -542,7 +542,7 @@ static void uhandle_restore_list(ListBase *undo_handles, bool use_init)
{
ImBuf *tmpibuf = imbuf_alloc_temp_tile();
- for (UndoImageHandle *uh = undo_handles->first; uh; uh = uh->next) {
+ LISTBASE_FOREACH (UndoImageHandle *, uh, undo_handles) {
/* Tiles only added to second set of tiles. */
Image *image = uh->image_ref.ptr;
@@ -552,7 +552,7 @@ static void uhandle_restore_list(ListBase *undo_handles, bool use_init)
continue;
}
bool changed = false;
- for (UndoImageBuf *ubuf_iter = uh->buffers.first; ubuf_iter; ubuf_iter = ubuf_iter->next) {
+ LISTBASE_FOREACH (UndoImageBuf *, ubuf_iter, &uh->buffers) {
UndoImageBuf *ubuf = use_init ? ubuf_iter : ubuf_iter->post;
ubuf_ensure_compat_ibuf(ubuf, ibuf);
@@ -611,7 +611,7 @@ static UndoImageBuf *uhandle_lookup_ubuf(UndoImageHandle *uh,
const Image *UNUSED(image),
const char *ibuf_name)
{
- for (UndoImageBuf *ubuf = uh->buffers.first; ubuf; ubuf = ubuf->next) {
+ LISTBASE_FOREACH (UndoImageBuf *, ubuf, &uh->buffers) {
if (STREQ(ubuf->ibuf_name, ibuf_name)) {
return ubuf;
}
@@ -643,7 +643,7 @@ static UndoImageHandle *uhandle_lookup_by_name(ListBase *undo_handles,
const Image *image,
int tile_number)
{
- for (UndoImageHandle *uh = undo_handles->first; uh; uh = uh->next) {
+ LISTBASE_FOREACH (UndoImageHandle *, uh, undo_handles) {
if (STREQ(image->id.name + 2, uh->image_ref.name + 2) && uh->iuser.tile == tile_number) {
return uh;
}
@@ -653,7 +653,7 @@ static UndoImageHandle *uhandle_lookup_by_name(ListBase *undo_handles,
static UndoImageHandle *uhandle_lookup(ListBase *undo_handles, const Image *image, int tile_number)
{
- for (UndoImageHandle *uh = undo_handles->first; uh; uh = uh->next) {
+ LISTBASE_FOREACH (UndoImageHandle *, uh, undo_handles) {
if (image == uh->image_ref.ptr && uh->iuser.tile == tile_number) {
return uh;
}
@@ -667,7 +667,7 @@ static UndoImageHandle *uhandle_add(ListBase *undo_handles, Image *image, ImageU
UndoImageHandle *uh = MEM_callocN(sizeof(*uh), __func__);
uh->image_ref.ptr = image;
uh->iuser = *iuser;
- BLI_assert(uh->iuser.scene == NULL);
+ uh->iuser.scene = NULL;
uh->iuser.ok = 1;
BLI_addtail(undo_handles, uh);
return uh;
@@ -714,7 +714,7 @@ static UndoImageBuf *ubuf_lookup_from_reference(ImageUndoStep *us_prev,
int tile_number,
const UndoImageBuf *ubuf)
{
- /* Use name lookup because because the pointer is cleared for previous steps. */
+ /* Use name lookup because the pointer is cleared for previous steps. */
UndoImageHandle *uh_prev = uhandle_lookup_by_name(&us_prev->handles, image, tile_number);
if (uh_prev != NULL) {
UndoImageBuf *ubuf_reference = uhandle_lookup_ubuf(uh_prev, image, ubuf->ibuf_name);
@@ -733,9 +733,9 @@ static bool image_undosys_poll(bContext *C)
{
Object *obact = CTX_data_active_object(C);
- ScrArea *sa = CTX_wm_area(C);
- if (sa && (sa->spacetype == SPACE_IMAGE)) {
- SpaceImage *sima = (SpaceImage *)sa->spacedata.first;
+ ScrArea *area = CTX_wm_area(C);
+ if (area && (area->spacetype == SPACE_IMAGE)) {
+ SpaceImage *sima = (SpaceImage *)area->spacedata.first;
if ((obact && (obact->mode & OB_MODE_TEXTURE_PAINT)) || (sima->mode == SI_MODE_PAINT)) {
return true;
}
@@ -799,8 +799,8 @@ static bool image_undosys_step_encode(struct bContext *C,
}
BLI_listbase_clear(&us->paint_tiles);
- for (UndoImageHandle *uh = us->handles.first; uh; uh = uh->next) {
- for (UndoImageBuf *ubuf_pre = uh->buffers.first; ubuf_pre; ubuf_pre = ubuf_pre->next) {
+ LISTBASE_FOREACH (UndoImageHandle *, uh, &us->handles) {
+ LISTBASE_FOREACH (UndoImageBuf *, ubuf_pre, &uh->buffers) {
ImBuf *ibuf = BKE_image_acquire_ibuf(uh->image_ref.ptr, &uh->iuser, NULL);
@@ -958,7 +958,7 @@ static void image_undosys_step_decode(
}
if (us->paint_mode == PAINT_MODE_TEXTURE_3D) {
- ED_object_mode_set(C, OB_MODE_TEXTURE_PAINT);
+ ED_object_mode_set_ex(C, OB_MODE_TEXTURE_PAINT, false, NULL);
}
/* Refresh texture slots. */
@@ -979,7 +979,7 @@ static void image_undosys_foreach_ID_ref(UndoStep *us_p,
void *user_data)
{
ImageUndoStep *us = (ImageUndoStep *)us_p;
- for (UndoImageHandle *uh = us->handles.first; uh; uh = uh->next) {
+ LISTBASE_FOREACH (UndoImageHandle *, uh, &us->handles) {
foreach_ID_ref_fn(user_data, ((UndoRefID *)&uh->image_ref));
}
}
@@ -1083,6 +1083,7 @@ void ED_image_undo_push_end(void)
{
UndoStack *ustack = ED_undo_stack_get();
BKE_undosys_step_push(ustack, NULL, NULL);
+ BKE_undosys_stack_limit_steps_and_memory_defaults(ustack);
WM_file_tag_modified();
}
diff --git a/source/blender/editors/space_image/space_image.c b/source/blender/editors/space_image/space_image.c
index 14cc6a9e151..51da5270f6e 100644
--- a/source/blender/editors/space_image/space_image.c
+++ b/source/blender/editors/space_image/space_image.c
@@ -83,13 +83,13 @@
/**************************** common state *****************************/
-static void image_scopes_tag_refresh(ScrArea *sa)
+static void image_scopes_tag_refresh(ScrArea *area)
{
- SpaceImage *sima = (SpaceImage *)sa->spacedata.first;
+ SpaceImage *sima = (SpaceImage *)area->spacedata.first;
ARegion *region;
/* only while histogram is visible */
- for (region = sa->regionbase.first; region; region = region->next) {
+ for (region = area->regionbase.first; region; region = region->next) {
if (region->regiontype == RGN_TYPE_TOOL_PROPS && region->flag & RGN_FLAG_HIDDEN) {
return;
}
@@ -127,6 +127,7 @@ static SpaceLink *image_new(const ScrArea *UNUSED(area), const Scene *UNUSED(sce
simage->zoom = 1.0f;
simage->lock = true;
simage->flag = SI_SHOW_GPENCIL | SI_USE_ALPHA | SI_COORDFLOATS;
+ simage->uv_opacity = 1.0f;
BKE_imageuser_default(&simage->iuser);
simage->iuser.flag = IMA_SHOW_STEREO | IMA_ANIM_ALWAYS;
@@ -256,10 +257,10 @@ static void image_keymap(struct wmKeyConfig *keyconf)
* \note take care not to get into feedback loop here,
* calling composite job causes viewer to refresh.
*/
-static void image_refresh(const bContext *C, ScrArea *sa)
+static void image_refresh(const bContext *C, ScrArea *area)
{
Scene *scene = CTX_data_scene(C);
- SpaceImage *sima = sa->spacedata.first;
+ SpaceImage *sima = area->spacedata.first;
Image *ima;
ima = ED_space_image(sima);
@@ -276,53 +277,53 @@ static void image_refresh(const bContext *C, ScrArea *sa)
}
}
-static void image_listener(wmWindow *win, ScrArea *sa, wmNotifier *wmn, Scene *UNUSED(scene))
+static void image_listener(wmWindow *win, ScrArea *area, wmNotifier *wmn, Scene *UNUSED(scene))
{
- SpaceImage *sima = (SpaceImage *)sa->spacedata.first;
+ SpaceImage *sima = (SpaceImage *)area->spacedata.first;
/* context changes */
switch (wmn->category) {
case NC_WINDOW:
/* notifier comes from editing color space */
- image_scopes_tag_refresh(sa);
- ED_area_tag_redraw(sa);
+ image_scopes_tag_refresh(area);
+ ED_area_tag_redraw(area);
break;
case NC_SCENE:
switch (wmn->data) {
case ND_FRAME:
- image_scopes_tag_refresh(sa);
- ED_area_tag_refresh(sa);
- ED_area_tag_redraw(sa);
+ image_scopes_tag_refresh(area);
+ ED_area_tag_refresh(area);
+ ED_area_tag_redraw(area);
break;
case ND_MODE:
if (wmn->subtype == NS_EDITMODE_MESH) {
- ED_area_tag_refresh(sa);
+ ED_area_tag_refresh(area);
}
- ED_area_tag_redraw(sa);
+ ED_area_tag_redraw(area);
break;
case ND_RENDER_RESULT:
case ND_RENDER_OPTIONS:
case ND_COMPO_RESULT:
if (ED_space_image_show_render(sima)) {
- image_scopes_tag_refresh(sa);
+ image_scopes_tag_refresh(area);
}
- ED_area_tag_redraw(sa);
+ ED_area_tag_redraw(area);
break;
}
break;
case NC_IMAGE:
if (wmn->reference == sima->image || !wmn->reference) {
if (wmn->action != NA_PAINTING) {
- image_scopes_tag_refresh(sa);
- ED_area_tag_refresh(sa);
- ED_area_tag_redraw(sa);
+ image_scopes_tag_refresh(area);
+ ED_area_tag_refresh(area);
+ ED_area_tag_redraw(area);
}
}
break;
case NC_SPACE:
if (wmn->data == ND_SPACE_IMAGE) {
- image_scopes_tag_refresh(sa);
- ED_area_tag_redraw(sa);
+ image_scopes_tag_refresh(area);
+ ED_area_tag_redraw(area);
}
break;
case NC_MASK: {
@@ -332,23 +333,23 @@ static void image_listener(wmWindow *win, ScrArea *sa, wmNotifier *wmn, Scene *U
if (sima->mode == SI_MODE_MASK) {
switch (wmn->data) {
case ND_SELECT:
- ED_area_tag_redraw(sa);
+ ED_area_tag_redraw(area);
break;
case ND_DATA:
case ND_DRAW:
/* causes node-recalc */
- ED_area_tag_redraw(sa);
- ED_area_tag_refresh(sa);
+ ED_area_tag_redraw(area);
+ ED_area_tag_refresh(area);
break;
}
switch (wmn->action) {
case NA_SELECTED:
- ED_area_tag_redraw(sa);
+ ED_area_tag_redraw(area);
break;
case NA_EDITED:
/* causes node-recalc */
- ED_area_tag_redraw(sa);
- ED_area_tag_refresh(sa);
+ ED_area_tag_redraw(area);
+ ED_area_tag_refresh(area);
break;
}
}
@@ -358,9 +359,9 @@ static void image_listener(wmWindow *win, ScrArea *sa, wmNotifier *wmn, Scene *U
switch (wmn->data) {
case ND_DATA:
case ND_SELECT:
- image_scopes_tag_refresh(sa);
- ED_area_tag_refresh(sa);
- ED_area_tag_redraw(sa);
+ image_scopes_tag_refresh(area);
+ ED_area_tag_refresh(area);
+ ED_area_tag_redraw(area);
break;
}
break;
@@ -373,8 +374,8 @@ static void image_listener(wmWindow *win, ScrArea *sa, wmNotifier *wmn, Scene *U
Object *ob = OBACT(view_layer);
if (ob && (ob == wmn->reference) && (ob->mode & OB_MODE_EDIT)) {
if (sima->lock && (sima->flag & SI_DRAWSHADOW)) {
- ED_area_tag_refresh(sa);
- ED_area_tag_redraw(sa);
+ ED_area_tag_refresh(area);
+ ED_area_tag_redraw(area);
}
}
break;
@@ -385,14 +386,14 @@ static void image_listener(wmWindow *win, ScrArea *sa, wmNotifier *wmn, Scene *U
}
case NC_ID: {
if (wmn->action == NA_RENAME) {
- ED_area_tag_redraw(sa);
+ ED_area_tag_redraw(area);
}
break;
}
case NC_WM:
if (wmn->data == ND_UNDO) {
- ED_area_tag_redraw(sa);
- ED_area_tag_refresh(sa);
+ ED_area_tag_redraw(area);
+ ED_area_tag_refresh(area);
}
break;
}
@@ -611,13 +612,13 @@ static void image_main_region_draw(const bContext *C, ARegion *region)
GPU_clear(GPU_COLOR_BIT);
GPU_framebuffer_bind(fbl->overlay_fb);
- glDisable(GL_FRAMEBUFFER_SRGB);
/* XXX not supported yet, disabling for now */
scene->r.scemode &= ~R_COMP_CROP;
/* clear and setup matrix */
UI_GetThemeColor3fv(TH_BACK, col);
+ srgb_to_linearrgb_v3_v3(col, col);
GPU_clear_color(col[0], col[1], col[2], 1.0f);
GPU_clear(GPU_COLOR_BIT);
GPU_depth_test(false);
@@ -714,7 +715,7 @@ static void image_main_region_draw(const bContext *C, ARegion *region)
}
static void image_main_region_listener(wmWindow *UNUSED(win),
- ScrArea *sa,
+ ScrArea *area,
ARegion *region,
wmNotifier *wmn,
const Scene *UNUSED(scene))
@@ -742,7 +743,7 @@ static void image_main_region_listener(wmWindow *UNUSED(win),
break;
case NC_MATERIAL:
if (wmn->data == ND_SHADING_LINKS) {
- SpaceImage *sima = sa->spacedata.first;
+ SpaceImage *sima = area->spacedata.first;
if (sima->iuser.scene && (sima->iuser.scene->toolsettings->uv_flag & UV_SHOW_SAME_IMAGE)) {
ED_region_tag_redraw(region);
@@ -831,7 +832,7 @@ static void image_buttons_region_draw(const bContext *C, ARegion *region)
}
static void image_buttons_region_listener(wmWindow *UNUSED(win),
- ScrArea *UNUSED(sa),
+ ScrArea *UNUSED(area),
ARegion *region,
wmNotifier *wmn,
const Scene *UNUSED(scene))
@@ -894,7 +895,7 @@ static void image_tools_region_draw(const bContext *C, ARegion *region)
}
static void image_tools_region_listener(wmWindow *UNUSED(win),
- ScrArea *UNUSED(sa),
+ ScrArea *UNUSED(area),
ARegion *region,
wmNotifier *wmn,
const Scene *UNUSED(scene))
@@ -942,8 +943,8 @@ static void image_header_region_init(wmWindowManager *UNUSED(wm), ARegion *regio
static void image_header_region_draw(const bContext *C, ARegion *region)
{
- ScrArea *sa = CTX_wm_area(C);
- SpaceImage *sima = sa->spacedata.first;
+ ScrArea *area = CTX_wm_area(C);
+ SpaceImage *sima = area->spacedata.first;
image_user_refresh_scene(C, sima);
@@ -951,7 +952,7 @@ static void image_header_region_draw(const bContext *C, ARegion *region)
}
static void image_header_region_listener(wmWindow *UNUSED(win),
- ScrArea *UNUSED(sa),
+ ScrArea *UNUSED(area),
ARegion *region,
wmNotifier *wmn,
const Scene *UNUSED(scene))
@@ -982,7 +983,7 @@ static void image_header_region_listener(wmWindow *UNUSED(win),
}
}
-static void image_id_remap(ScrArea *UNUSED(sa), SpaceLink *slink, ID *old_id, ID *new_id)
+static void image_id_remap(ScrArea *UNUSED(area), SpaceLink *slink, ID *old_id, ID *new_id)
{
SpaceImage *simg = (SpaceImage *)slink;
@@ -1012,15 +1013,15 @@ static void image_id_remap(ScrArea *UNUSED(sa), SpaceLink *slink, ID *old_id, ID
* The previous non-uv-edit mode is stored so switching back to the
* image doesn't always reset the sub-mode.
*/
-static int image_space_subtype_get(ScrArea *sa)
+static int image_space_subtype_get(ScrArea *area)
{
- SpaceImage *sima = sa->spacedata.first;
+ SpaceImage *sima = area->spacedata.first;
return sima->mode == SI_MODE_UV ? SI_MODE_UV : SI_MODE_VIEW;
}
-static void image_space_subtype_set(ScrArea *sa, int value)
+static void image_space_subtype_set(ScrArea *area, int value)
{
- SpaceImage *sima = sa->spacedata.first;
+ SpaceImage *sima = area->spacedata.first;
if (value == SI_MODE_UV) {
if (sima->mode != SI_MODE_UV) {
sima->mode_prev = sima->mode;
diff --git a/source/blender/editors/space_info/info_draw.c b/source/blender/editors/space_info/info_draw.c
index 2a3f6d6e365..3685e5de852 100644
--- a/source/blender/editors/space_info/info_draw.c
+++ b/source/blender/editors/space_info/info_draw.c
@@ -141,7 +141,6 @@ static int report_textview_begin(TextViewContext *tvc)
{
const ReportList *reports = tvc->arg2;
- tvc->lheight = 14 * UI_DPI_FAC;
tvc->sel_start = 0;
tvc->sel_end = 0;
diff --git a/source/blender/editors/space_info/info_report.c b/source/blender/editors/space_info/info_report.c
index 7499c057950..adc6391a0f6 100644
--- a/source/blender/editors/space_info/info_report.c
+++ b/source/blender/editors/space_info/info_report.c
@@ -250,7 +250,7 @@ static int box_select_exec(bContext *C, wmOperator *op)
const eSelectOp sel_op = RNA_enum_get(op->ptr, "mode");
const int select = (sel_op != SEL_OP_SUB);
if (SEL_OP_USE_PRE_DESELECT(sel_op)) {
- for (Report *report = reports->list.first; report; report = report->next) {
+ LISTBASE_FOREACH (Report *, report, &reports->list) {
if ((report->type & report_mask) == 0) {
continue;
}
@@ -264,7 +264,7 @@ static int box_select_exec(bContext *C, wmOperator *op)
/* get the first report if none found */
if (report_min == NULL) {
// printf("find_min\n");
- for (Report *report = reports->list.first; report; report = report->next) {
+ LISTBASE_FOREACH (Report *, report, &reports->list) {
if (report->type & report_mask) {
report_min = report;
break;
diff --git a/source/blender/editors/space_info/info_stats.c b/source/blender/editors/space_info/info_stats.c
index 78bc0961cb3..e1937dffb37 100644
--- a/source/blender/editors/space_info/info_stats.c
+++ b/source/blender/editors/space_info/info_stats.c
@@ -33,6 +33,8 @@
#include "DNA_scene_types.h"
#include "DNA_windowmanager_types.h"
+#include "BLF_api.h"
+
#include "BLI_listbase.h"
#include "BLI_math.h"
#include "BLI_string.h"
@@ -40,7 +42,6 @@
#include "BLT_translation.h"
-#include "BKE_anim.h"
#include "BKE_blender_version.h"
#include "BKE_curve.h"
#include "BKE_displist.h"
@@ -60,9 +61,10 @@
#include "ED_armature.h"
#include "ED_info.h"
+#include "UI_resources.h"
+
#include "GPU_extensions.h"
-#define MAX_INFO_LEN 512
#define MAX_INFO_NUM_LEN 16
typedef struct SceneStats {
@@ -74,8 +76,6 @@ typedef struct SceneStats {
uint64_t totlamp, totlampsel;
uint64_t tottri;
uint64_t totgplayer, totgpframe, totgpstroke, totgppoint;
-
- char infostr[MAX_INFO_LEN];
} SceneStats;
typedef struct SceneStatsFmt {
@@ -369,10 +369,16 @@ static void stats_update(Depsgraph *depsgraph, ViewLayer *view_layer)
if (obedit) {
/* Edit Mode */
- FOREACH_OBJECT_IN_MODE_BEGIN (view_layer, ((View3D *)NULL), ob->type, ob->mode, ob_iter) {
- stats_object_edit(ob_iter, &stats);
+ FOREACH_OBJECT_BEGIN (view_layer, ob_iter) {
+ if (ob_iter->base_flag & BASE_VISIBLE_VIEWLAYER) {
+ if (ob_iter->mode == OB_MODE_EDIT) {
+ stats_object_edit(ob_iter, &stats);
+ stats.totobjsel++;
+ }
+ stats.totobj++;
+ }
}
- FOREACH_OBJECT_IN_MODE_END;
+ FOREACH_OBJECT_END;
}
else if (ob && (ob->mode & OB_MODE_POSE)) {
/* Pose Mode */
@@ -399,26 +405,92 @@ static void stats_update(Depsgraph *depsgraph, ViewLayer *view_layer)
*(view_layer->stats) = stats;
}
-static void stats_string(ViewLayer *view_layer)
+static const char *footer_string(ViewLayer *view_layer)
{
#define MAX_INFO_MEM_LEN 64
- SceneStats *stats = view_layer->stats;
- SceneStatsFmt stats_fmt;
- LayerCollection *layer_collection = view_layer->active_collection;
- Object *ob = OBACT(view_layer);
- Object *obedit = OBEDIT_FROM_OBACT(ob);
- eObjectMode object_mode = ob ? ob->mode : OB_MODE_OBJECT;
- uintptr_t mem_in_use, mmap_in_use;
char memstr[MAX_INFO_MEM_LEN];
char gpumemstr[MAX_INFO_MEM_LEN] = "";
char formatted_mem[15];
- char *s;
size_t ofs = 0;
- mem_in_use = MEM_get_memory_in_use();
- mmap_in_use = MEM_get_mapped_memory_in_use();
+ uintptr_t mem_in_use = MEM_get_memory_in_use();
+
+ /* get memory statistics */
+ BLI_str_format_byte_unit(formatted_mem, mem_in_use, false);
+ ofs = BLI_snprintf(memstr, MAX_INFO_MEM_LEN, TIP_("Mem: %s"), formatted_mem);
+
+ if (GPU_mem_stats_supported()) {
+ int gpu_free_mem, gpu_tot_memory;
+
+ GPU_mem_stats_get(&gpu_tot_memory, &gpu_free_mem);
+
+ BLI_str_format_byte_unit(formatted_mem, gpu_free_mem, false);
+ ofs = BLI_snprintf(gpumemstr, MAX_INFO_MEM_LEN, TIP_(" | Free GPU Mem: %s"), formatted_mem);
+
+ if (gpu_tot_memory) {
+ BLI_str_format_byte_unit(formatted_mem, gpu_tot_memory, false);
+ BLI_snprintf(gpumemstr + ofs, MAX_INFO_MEM_LEN - ofs, TIP_("/%s"), formatted_mem);
+ }
+ }
+
+ BLI_snprintf(view_layer->footer_str,
+ sizeof(view_layer->footer_str),
+ "%s%s | %s",
+ memstr,
+ gpumemstr,
+ BKE_blender_version_string());
+
+ return view_layer->footer_str;
+
+#undef MAX_INFO_MEM_LEN
+}
+
+void ED_info_stats_clear(ViewLayer *view_layer)
+{
+ if (view_layer->stats) {
+ MEM_freeN(view_layer->stats);
+ view_layer->stats = NULL;
+ }
+}
+
+const char *ED_info_footer_string(ViewLayer *view_layer)
+{
+ return footer_string(view_layer);
+}
+
+static void stats_row(int col1,
+ const char *key,
+ int col2,
+ const char *value1,
+ const char *value2,
+ int *y,
+ int height)
+{
+ *y -= height;
+ BLF_draw_default(col1, *y, 0.0f, key, 128);
+ char values[128];
+ BLI_snprintf(values, sizeof(values), (value2) ? "%s / %s" : "%s", value1, value2);
+ BLF_draw_default(col2, *y, 0.0f, values, sizeof(values));
+}
+
+void ED_info_draw_stats(
+ Main *bmain, Scene *scene, ViewLayer *view_layer, int x, int *y, int height)
+{
+ /* Create stats if they don't already exist. */
+ if (!view_layer->stats) {
+ /* Do not not access dependency graph if interface is marked as locked. */
+ wmWindowManager *wm = bmain->wm.first;
+ if (wm->is_interface_locked) {
+ return;
+ }
+ Depsgraph *depsgraph = BKE_scene_get_depsgraph(bmain, scene, view_layer, true);
+ stats_update(depsgraph, view_layer);
+ }
+
+ SceneStats *stats = view_layer->stats;
+ SceneStatsFmt stats_fmt;
- /* Generate formatted numbers */
+ /* Generate formatted numbers. */
#define SCENE_STATS_FMT_INT(_id) BLI_str_format_uint64_grouped(stats_fmt._id, stats->_id)
SCENE_STATS_FMT_INT(totvert);
@@ -448,151 +520,94 @@ static void stats_string(ViewLayer *view_layer)
#undef SCENE_STATS_FMT_INT
- /* get memory statistics */
- BLI_str_format_byte_unit(formatted_mem, mem_in_use - mmap_in_use, false);
- ofs = BLI_snprintf(memstr, MAX_INFO_MEM_LEN, TIP_(" | Mem: %s"), formatted_mem);
-
- if (mmap_in_use) {
- BLI_str_format_byte_unit(formatted_mem, mmap_in_use, false);
- BLI_snprintf(memstr + ofs, MAX_INFO_MEM_LEN - ofs, TIP_(" (%s)"), formatted_mem);
+ Object *ob = OBACT(view_layer);
+ Object *obedit = OBEDIT_FROM_OBACT(ob);
+ eObjectMode object_mode = ob ? ob->mode : OB_MODE_OBJECT;
+ const int font_id = BLF_default();
+
+ UI_FontThemeColor(font_id, TH_TEXT_HI);
+ BLF_enable(font_id, BLF_SHADOW);
+ BLF_shadow(font_id, 5, (const float[4]){0.0f, 0.0f, 0.0f, 1.0f});
+ BLF_shadow_offset(font_id, 1, -1);
+
+ /* Translated labels for each stat row. */
+ enum {
+ OBJ,
+ VERTS,
+ EDGES,
+ FACES,
+ TRIS,
+ BONES,
+ LAYERS,
+ FRAMES,
+ STROKES,
+ POINTS,
+ MAX_LABELS_COUNT
+ };
+ char labels[MAX_LABELS_COUNT][64];
+
+ STRNCPY(labels[OBJ], IFACE_("Objects"));
+ STRNCPY(labels[VERTS], IFACE_("Vertices"));
+ STRNCPY(labels[EDGES], IFACE_("Edges"));
+ STRNCPY(labels[FACES], IFACE_("Faces"));
+ STRNCPY(labels[TRIS], IFACE_("Triangles"));
+ STRNCPY(labels[BONES], IFACE_("Bones"));
+ STRNCPY(labels[LAYERS], IFACE_("Layers"));
+ STRNCPY(labels[FRAMES], IFACE_("Frames"));
+ STRNCPY(labels[STROKES], IFACE_("Strokes"));
+ STRNCPY(labels[POINTS], IFACE_("Points"));
+
+ int longest_label = 0;
+ int i;
+ for (i = 0; i < MAX_LABELS_COUNT; ++i) {
+ longest_label = max_ii(longest_label, BLF_width(font_id, labels[i], sizeof(labels[i])));
}
- if (GPU_mem_stats_supported()) {
- int gpu_free_mem, gpu_tot_memory;
-
- GPU_mem_stats_get(&gpu_tot_memory, &gpu_free_mem);
-
- BLI_str_format_byte_unit(formatted_mem, gpu_free_mem, false);
- ofs = BLI_snprintf(gpumemstr, MAX_INFO_MEM_LEN, TIP_(" | Free GPU Mem: %s"), formatted_mem);
+ int col1 = x;
+ int col2 = x + longest_label + (0.5f * U.widget_unit);
- if (gpu_tot_memory) {
- BLI_str_format_byte_unit(formatted_mem, gpu_tot_memory, false);
- BLI_snprintf(gpumemstr + ofs, MAX_INFO_MEM_LEN - ofs, TIP_("/%s"), formatted_mem);
- }
- }
-
- s = stats->infostr;
- ofs = 0;
+ /* Add some extra margin above this section. */
+ *y -= (0.6f * height);
if (object_mode == OB_MODE_OBJECT) {
- ofs += BLI_snprintf(s + ofs,
- MAX_INFO_LEN - ofs,
- "%s | ",
- BKE_collection_ui_name_get(layer_collection->collection));
- }
-
- if (ob) {
- ofs += BLI_snprintf(s + ofs, MAX_INFO_LEN - ofs, "%s | ", ob->id.name + 2);
+ stats_row(col1, labels[OBJ], col2, stats_fmt.totobjsel, stats_fmt.totobj, y, height);
}
if (obedit) {
- if (BKE_keyblock_from_object(obedit)) {
- ofs += BLI_strncpy_rlen(s + ofs, TIP_("(Key) "), MAX_INFO_LEN - ofs);
- }
-
if (obedit->type == OB_MESH) {
- ofs += BLI_snprintf(s + ofs,
- MAX_INFO_LEN - ofs,
- TIP_("Verts:%s/%s | Edges:%s/%s | Faces:%s/%s | Tris:%s"),
- stats_fmt.totvertsel,
- stats_fmt.totvert,
- stats_fmt.totedgesel,
- stats_fmt.totedge,
- stats_fmt.totfacesel,
- stats_fmt.totface,
- stats_fmt.tottri);
+ stats_row(col1, labels[OBJ], col2, stats_fmt.totobjsel, stats_fmt.totobj, y, height);
+ stats_row(col1, labels[VERTS], col2, stats_fmt.totvertsel, stats_fmt.totvert, y, height);
+ stats_row(col1, labels[EDGES], col2, stats_fmt.totedgesel, stats_fmt.totedge, y, height);
+ stats_row(col1, labels[FACES], col2, stats_fmt.totfacesel, stats_fmt.totface, y, height);
+ stats_row(col1, labels[TRIS], col2, stats_fmt.tottri, NULL, y, height);
}
else if (obedit->type == OB_ARMATURE) {
- ofs += BLI_snprintf(s + ofs,
- MAX_INFO_LEN - ofs,
- TIP_("Verts:%s/%s | Bones:%s/%s"),
- stats_fmt.totvertsel,
- stats_fmt.totvert,
- stats_fmt.totbonesel,
- stats_fmt.totbone);
+ stats_row(col1, labels[VERTS], col2, stats_fmt.totvertsel, stats_fmt.totvert, y, height);
+ stats_row(col1, labels[BONES], col2, stats_fmt.totbonesel, stats_fmt.totbone, y, height);
}
else {
- ofs += BLI_snprintf(s + ofs,
- MAX_INFO_LEN - ofs,
- TIP_("Verts:%s/%s"),
- stats_fmt.totvertsel,
- stats_fmt.totvert);
+ stats_row(col1, labels[VERTS], col2, stats_fmt.totvertsel, stats_fmt.totvert, y, height);
}
-
- ofs += BLI_strncpy_rlen(s + ofs, memstr, MAX_INFO_LEN - ofs);
- ofs += BLI_strncpy_rlen(s + ofs, gpumemstr, MAX_INFO_LEN - ofs);
}
else if (ob && (object_mode & OB_MODE_POSE)) {
- ofs += BLI_snprintf(s + ofs,
- MAX_INFO_LEN - ofs,
- TIP_("Bones:%s/%s %s%s"),
- stats_fmt.totbonesel,
- stats_fmt.totbone,
- memstr,
- gpumemstr);
+ stats_row(col1, labels[BONES], col2, stats_fmt.totbonesel, stats_fmt.totbone, y, height);
}
else if ((ob) && (ob->type == OB_GPENCIL)) {
- ofs += BLI_snprintf(s + ofs,
- MAX_INFO_LEN - ofs,
- TIP_("Layers:%s | Frames:%s | Strokes:%s | Points:%s | Objects:%s/%s"),
- stats_fmt.totgplayer,
- stats_fmt.totgpframe,
- stats_fmt.totgpstroke,
- stats_fmt.totgppoint,
- stats_fmt.totobjsel,
- stats_fmt.totobj);
-
- ofs += BLI_strncpy_rlen(s + ofs, memstr, MAX_INFO_LEN - ofs);
- ofs += BLI_strncpy_rlen(s + ofs, gpumemstr, MAX_INFO_LEN - ofs);
+ stats_row(col1, labels[LAYERS], col2, stats_fmt.totgplayer, NULL, y, height);
+ stats_row(col1, labels[FRAMES], col2, stats_fmt.totgpframe, NULL, y, height);
+ stats_row(col1, labels[STROKES], col2, stats_fmt.totgpstroke, NULL, y, height);
+ stats_row(col1, labels[POINTS], col2, stats_fmt.totgppoint, NULL, y, height);
}
else if (stats_is_object_dynamic_topology_sculpt(ob, object_mode)) {
- ofs += BLI_snprintf(s + ofs,
- MAX_INFO_LEN - ofs,
- TIP_("Verts:%s | Tris:%s%s"),
- stats_fmt.totvert,
- stats_fmt.tottri,
- gpumemstr);
+ stats_row(col1, labels[VERTS], col2, stats_fmt.totvert, NULL, y, height);
+ stats_row(col1, labels[TRIS], col2, stats_fmt.tottri, NULL, y, height);
}
else {
- ofs += BLI_snprintf(s + ofs,
- MAX_INFO_LEN - ofs,
- TIP_("Verts:%s | Faces:%s | Tris:%s | Objects:%s/%s%s%s"),
- stats_fmt.totvert,
- stats_fmt.totface,
- stats_fmt.tottri,
- stats_fmt.totobjsel,
- stats_fmt.totobj,
- memstr,
- gpumemstr);
+ stats_row(col1, labels[VERTS], col2, stats_fmt.totvert, NULL, y, height);
+ stats_row(col1, labels[EDGES], col2, stats_fmt.totedge, NULL, y, height);
+ stats_row(col1, labels[FACES], col2, stats_fmt.totface, NULL, y, height);
+ stats_row(col1, labels[TRIS], col2, stats_fmt.tottri, NULL, y, height);
}
- ofs += BLI_snprintf(s + ofs, MAX_INFO_LEN - ofs, " | %s", versionstr);
-#undef MAX_INFO_MEM_LEN
-}
-
-#undef MAX_INFO_LEN
-
-void ED_info_stats_clear(ViewLayer *view_layer)
-{
- if (view_layer->stats) {
- MEM_freeN(view_layer->stats);
- view_layer->stats = NULL;
- }
-}
-
-const char *ED_info_stats_string(Main *bmain, Scene *scene, ViewLayer *view_layer)
-{
- /* Looping through dependency graph when interface is locked in not safe.
- * Thew interface is marked as locked when jobs wants to modify the
- * dependency graph. */
- wmWindowManager *wm = bmain->wm.first;
- if (wm->is_interface_locked) {
- return "";
- }
- Depsgraph *depsgraph = BKE_scene_get_depsgraph(bmain, scene, view_layer, true);
- if (!view_layer->stats) {
- stats_update(depsgraph, view_layer);
- }
- stats_string(view_layer);
- return view_layer->stats->infostr;
+ BLF_disable(font_id, BLF_SHADOW);
}
diff --git a/source/blender/editors/space_info/space_info.c b/source/blender/editors/space_info/space_info.c
index 58ce3316c4b..04df0f0d4f0 100644
--- a/source/blender/editors/space_info/space_info.c
+++ b/source/blender/editors/space_info/space_info.c
@@ -97,7 +97,7 @@ static void info_free(SpaceLink *UNUSED(sl))
}
/* spacetype; init callback */
-static void info_init(struct wmWindowManager *UNUSED(wm), ScrArea *UNUSED(sa))
+static void info_init(struct wmWindowManager *UNUSED(wm), ScrArea *UNUSED(area))
{
}
@@ -209,12 +209,12 @@ static void info_header_region_draw(const bContext *C, ARegion *region)
}
static void info_main_region_listener(wmWindow *UNUSED(win),
- ScrArea *UNUSED(sa),
+ ScrArea *UNUSED(area),
ARegion *region,
wmNotifier *wmn,
const Scene *UNUSED(scene))
{
- // SpaceInfo *sinfo = sa->spacedata.first;
+ // SpaceInfo *sinfo = area->spacedata.first;
/* context changes */
switch (wmn->category) {
@@ -228,7 +228,7 @@ static void info_main_region_listener(wmWindow *UNUSED(win),
}
static void info_header_listener(wmWindow *UNUSED(win),
- ScrArea *UNUSED(sa),
+ ScrArea *UNUSED(area),
ARegion *region,
wmNotifier *wmn,
const Scene *UNUSED(scene))
@@ -267,7 +267,7 @@ static void info_header_region_message_subscribe(const bContext *UNUSED(C),
WorkSpace *UNUSED(workspace),
Scene *UNUSED(scene),
bScreen *UNUSED(screen),
- ScrArea *UNUSED(sa),
+ ScrArea *UNUSED(area),
ARegion *region,
struct wmMsgBus *mbus)
{
diff --git a/source/blender/editors/space_info/textview.c b/source/blender/editors/space_info/textview.c
index c842fa8b4ac..8076d3d7eaf 100644
--- a/source/blender/editors/space_info/textview.c
+++ b/source/blender/editors/space_info/textview.c
@@ -394,25 +394,26 @@ int textview_draw(TextViewContext *tvc,
tvc->line_get(tvc, &ext_line, &ext_len);
- if (!textview_draw_string(&tds,
- ext_line,
- ext_len,
- (data_flag & TVC_LINE_FG) ? fg : NULL,
- (data_flag & TVC_LINE_BG) ? bg : NULL,
- (data_flag & TVC_LINE_ICON) ? icon : 0,
- (data_flag & TVC_LINE_ICON_FG) ? icon_fg : NULL,
- (data_flag & TVC_LINE_ICON_BG) ? icon_bg : NULL,
- bg_sel)) {
- /* When drawing, if we pass v2d->cur.ymax, then quit. */
- if (do_draw) {
- /* Past the y limits. */
- break;
- }
- }
+ const bool is_out_of_view_y = !textview_draw_string(
+ &tds,
+ ext_line,
+ ext_len,
+ (data_flag & TVC_LINE_FG) ? fg : NULL,
+ (data_flag & TVC_LINE_BG) ? bg : NULL,
+ (data_flag & TVC_LINE_ICON) ? icon : 0,
+ (data_flag & TVC_LINE_ICON_FG) ? icon_fg : NULL,
+ (data_flag & TVC_LINE_ICON_BG) ? icon_bg : NULL,
+ bg_sel);
if (do_draw) {
+ /* We always want the cursor to draw. */
if (tvc->draw_cursor && iter_index == 0) {
- tvc->draw_cursor(tvc, tds.cwidth, tds.columns, tds.lofs);
+ tvc->draw_cursor(tvc, tds.cwidth, tds.columns);
+ }
+
+ /* When drawing, if we pass v2d->cur.ymax, then quit. */
+ if (is_out_of_view_y) {
+ break;
}
}
@@ -428,6 +429,11 @@ int textview_draw(TextViewContext *tvc,
tvc->end(tvc);
+ /* Sanity checks (bugs here can be tricky to track down). */
+ BLI_assert(tds.lheight == tvc->lheight);
+ BLI_assert(tds.row_vpadding == tvc->row_vpadding);
+ BLI_assert(tds.do_draw == do_draw);
+
xy[1] += tvc->lheight * 2;
return xy[1] - y_orig;
diff --git a/source/blender/editors/space_info/textview.h b/source/blender/editors/space_info/textview.h
index 8eef4ef5d56..41f8baf634e 100644
--- a/source/blender/editors/space_info/textview.h
+++ b/source/blender/editors/space_info/textview.h
@@ -60,7 +60,7 @@ typedef struct TextViewContext {
int *r_icon,
uchar r_icon_fg[4],
uchar r_icon_bg[4]);
- void (*draw_cursor)(struct TextViewContext *tvc, int cwidth, int columns, int descender);
+ void (*draw_cursor)(struct TextViewContext *tvc, int cwidth, int columns);
/* constant theme colors */
void (*const_colors)(struct TextViewContext *tvc, unsigned char bg_sel[4]);
const void *iter;
diff --git a/source/blender/editors/space_nla/nla_buttons.c b/source/blender/editors/space_nla/nla_buttons.c
index ca7f8791f75..307b6d9bc21 100644
--- a/source/blender/editors/space_nla/nla_buttons.c
+++ b/source/blender/editors/space_nla/nla_buttons.c
@@ -143,7 +143,8 @@ bool nla_panel_context(const bContext *C,
case ANIMTYPE_PALETTE:
case ANIMTYPE_DSHAIR:
case ANIMTYPE_DSPOINTCLOUD:
- case ANIMTYPE_DSVOLUME: {
+ case ANIMTYPE_DSVOLUME:
+ case ANIMTYPE_DSSIMULATION: {
/* for these channels, we only do AnimData */
if (ale->adt && adt_ptr) {
ID *id;
@@ -242,11 +243,11 @@ static bool nla_strip_eval_panel_poll(const bContext *C, PanelType *UNUSED(pt))
/* -------------- */
/* active AnimData */
-static void nla_panel_animdata(const bContext *C, Panel *pa)
+static void nla_panel_animdata(const bContext *C, Panel *panel)
{
PointerRNA adt_ptr;
/* AnimData *adt; */
- uiLayout *layout = pa->layout;
+ uiLayout *layout = panel->layout;
uiLayout *row;
uiBlock *block;
@@ -312,10 +313,10 @@ static void nla_panel_animdata(const bContext *C, Panel *pa)
}
/* generic settings for active NLA-Strip */
-static void nla_panel_stripname(const bContext *C, Panel *pa)
+static void nla_panel_stripname(const bContext *C, Panel *panel)
{
PointerRNA strip_ptr;
- uiLayout *layout = pa->layout;
+ uiLayout *layout = panel->layout;
uiLayout *row;
uiBlock *block;
@@ -350,11 +351,11 @@ static void nla_panel_stripname(const bContext *C, Panel *pa)
}
/* generic settings for active NLA-Strip */
-static void nla_panel_properties(const bContext *C, Panel *pa)
+static void nla_panel_properties(const bContext *C, Panel *panel)
{
PointerRNA strip_ptr;
- uiLayout *layout = pa->layout;
- uiLayout *column;
+ uiLayout *layout = panel->layout;
+ uiLayout *column, *row;
uiBlock *block;
short showEvalProps = 1;
@@ -401,28 +402,27 @@ static void nla_panel_properties(const bContext *C, Panel *pa)
uiItemR(column, &strip_ptr, "blend_in", 0, IFACE_("Blend In"), ICON_NONE);
uiItemR(column, &strip_ptr, "blend_out", 0, IFACE_("Out"), ICON_NONE);
- column = uiLayoutColumn(layout, true);
- uiLayoutSetActive(column, RNA_boolean_get(&strip_ptr, "use_animated_influence") == false);
- uiItemR(column, &strip_ptr, "use_auto_blend", 0, NULL, ICON_NONE); // XXX as toggle?
-
- uiItemS(layout);
+ row = uiLayoutRow(column, true);
+ uiLayoutSetActive(row, RNA_boolean_get(&strip_ptr, "use_animated_influence") == false);
+ uiItemR(row, &strip_ptr, "use_auto_blend", 0, NULL, ICON_NONE); // XXX as toggle?
/* settings */
- column = uiLayoutColumn(layout, true);
- uiLayoutSetActive(column,
+ column = uiLayoutColumnWithHeading(layout, true, "Playback");
+ row = uiLayoutRow(column, true);
+ uiLayoutSetActive(row,
!(RNA_boolean_get(&strip_ptr, "use_animated_influence") ||
RNA_boolean_get(&strip_ptr, "use_animated_time")));
- uiItemR(column, &strip_ptr, "use_reverse", 0, NULL, ICON_NONE);
+ uiItemR(row, &strip_ptr, "use_reverse", 0, NULL, ICON_NONE);
- uiItemR(layout, &strip_ptr, "use_animated_time_cyclic", 0, NULL, ICON_NONE);
+ uiItemR(column, &strip_ptr, "use_animated_time_cyclic", 0, NULL, ICON_NONE);
}
}
/* action-clip only settings for active NLA-Strip */
-static void nla_panel_actclip(const bContext *C, Panel *pa)
+static void nla_panel_actclip(const bContext *C, Panel *panel)
{
PointerRNA strip_ptr;
- uiLayout *layout = pa->layout;
+ uiLayout *layout = panel->layout;
uiLayout *column, *row;
uiBlock *block;
@@ -442,15 +442,12 @@ static void nla_panel_actclip(const bContext *C, Panel *pa)
uiItemR(row, &strip_ptr, "action", 0, NULL, ICON_ACTION);
/* action extents */
- // XXX custom names were used here (to avoid the prefixes)... probably not necessary in future?
column = uiLayoutColumn(layout, true);
uiItemR(column, &strip_ptr, "action_frame_start", 0, IFACE_("Frame Start"), ICON_NONE);
uiItemR(column, &strip_ptr, "action_frame_end", 0, IFACE_("End"), ICON_NONE);
- /* XXX: this layout may actually be too abstract and confusing,
- * and may be better using standard column layout. */
- row = uiLayoutRow(layout, false);
- uiItemR(row, &strip_ptr, "use_sync_length", 0, IFACE_("Sync Length"), ICON_NONE);
+ row = uiLayoutRowWithHeading(layout, false, "Sync Length");
+ uiItemR(row, &strip_ptr, "use_sync_length", 0, "", ICON_NONE);
uiItemO(row, IFACE_("Now"), ICON_FILE_REFRESH, "NLA_OT_action_sync_length");
/* action usage */
@@ -461,10 +458,10 @@ static void nla_panel_actclip(const bContext *C, Panel *pa)
}
/* evaluation settings for active NLA-Strip */
-static void nla_panel_animated_influence_header(const bContext *C, Panel *pa)
+static void nla_panel_animated_influence_header(const bContext *C, Panel *panel)
{
PointerRNA strip_ptr;
- uiLayout *layout = pa->layout;
+ uiLayout *layout = panel->layout;
uiLayout *col;
uiBlock *block;
@@ -481,10 +478,10 @@ static void nla_panel_animated_influence_header(const bContext *C, Panel *pa)
}
/* evaluation settings for active NLA-Strip */
-static void nla_panel_evaluation(const bContext *C, Panel *pa)
+static void nla_panel_evaluation(const bContext *C, Panel *panel)
{
PointerRNA strip_ptr;
- uiLayout *layout = pa->layout;
+ uiLayout *layout = panel->layout;
uiBlock *block;
/* check context and also validity of pointer */
@@ -500,10 +497,10 @@ static void nla_panel_evaluation(const bContext *C, Panel *pa)
uiItemR(layout, &strip_ptr, "influence", 0, NULL, ICON_NONE);
}
-static void nla_panel_animated_strip_time_header(const bContext *C, Panel *pa)
+static void nla_panel_animated_strip_time_header(const bContext *C, Panel *panel)
{
PointerRNA strip_ptr;
- uiLayout *layout = pa->layout;
+ uiLayout *layout = panel->layout;
uiLayout *col;
uiBlock *block;
@@ -519,10 +516,10 @@ static void nla_panel_animated_strip_time_header(const bContext *C, Panel *pa)
uiItemR(col, &strip_ptr, "use_animated_time", 0, "", ICON_NONE);
}
-static void nla_panel_animated_strip_time(const bContext *C, Panel *pa)
+static void nla_panel_animated_strip_time(const bContext *C, Panel *panel)
{
PointerRNA strip_ptr;
- uiLayout *layout = pa->layout;
+ uiLayout *layout = panel->layout;
uiBlock *block;
/* check context and also validity of pointer */
@@ -539,7 +536,7 @@ static void nla_panel_animated_strip_time(const bContext *C, Panel *pa)
}
/* F-Modifiers for active NLA-Strip */
-static void nla_panel_modifiers(const bContext *C, Panel *pa)
+static void nla_panel_modifiers(const bContext *C, Panel *panel)
{
PointerRNA strip_ptr;
NlaStrip *strip;
@@ -553,12 +550,12 @@ static void nla_panel_modifiers(const bContext *C, Panel *pa)
}
strip = strip_ptr.data;
- block = uiLayoutGetBlock(pa->layout);
+ block = uiLayoutGetBlock(panel->layout);
UI_block_func_handle_set(block, do_nla_region_buttons, NULL);
/* 'add modifier' button at top of panel */
{
- row = uiLayoutRow(pa->layout, false);
+ row = uiLayoutRow(panel->layout, false);
block = uiLayoutGetBlock(row);
// FIXME: we need to set the only-active property so that this
@@ -574,7 +571,7 @@ static void nla_panel_modifiers(const bContext *C, Panel *pa)
/* draw each modifier */
for (fcm = strip->modifiers.first; fcm; fcm = fcm->next) {
- col = uiLayoutColumn(pa->layout, true);
+ col = uiLayoutColumn(panel->layout, true);
ANIM_uiTemplate_fmodifier_draw(col, strip_ptr.owner_id, &strip->modifiers, fcm);
}
diff --git a/source/blender/editors/space_nla/nla_channels.c b/source/blender/editors/space_nla/nla_channels.c
index a69aed38cab..d399ea47d7e 100644
--- a/source/blender/editors/space_nla/nla_channels.c
+++ b/source/blender/editors/space_nla/nla_channels.c
@@ -33,7 +33,7 @@
#include "BLI_blenlib.h"
#include "BLI_utildefines.h"
-#include "BKE_animsys.h"
+#include "BKE_anim_data.h"
#include "BKE_context.h"
#include "BKE_global.h"
#include "BKE_nla.h"
@@ -146,7 +146,7 @@ static int mouse_nla_channels(
else {
/* deselect all */
/* TODO: should this deselect all other types of channels too? */
- for (Base *b = view_layer->object_bases.first; b; b = b->next) {
+ LISTBASE_FOREACH (Base *, b, &view_layer->object_bases) {
ED_object_base_select(b, BA_DESELECT);
if (b->object->adt) {
b->object->adt->flag &= ~(ADT_UI_SELECTED | ADT_UI_ACTIVE);
@@ -193,7 +193,8 @@ static int mouse_nla_channels(
case ANIMTYPE_PALETTE:
case ANIMTYPE_DSHAIR:
case ANIMTYPE_DSPOINTCLOUD:
- case ANIMTYPE_DSVOLUME: {
+ case ANIMTYPE_DSVOLUME:
+ case ANIMTYPE_DSSIMULATION: {
/* sanity checking... */
if (ale->adt) {
/* select/deselect */
diff --git a/source/blender/editors/space_nla/nla_draw.c b/source/blender/editors/space_nla/nla_draw.c
index 4ccf752a916..a56b7f8422e 100644
--- a/source/blender/editors/space_nla/nla_draw.c
+++ b/source/blender/editors/space_nla/nla_draw.c
@@ -150,7 +150,7 @@ static void nla_action_draw_keyframes(
/* - disregard the selection status of keyframes so they draw a certain way
* - size is 6.0f which is smaller than the editable keyframes, so that there is a distinction
*/
- for (ActKeyColumn *ak = keys.first; ak; ak = ak->next) {
+ LISTBASE_FOREACH (ActKeyColumn *, ak, &keys) {
draw_keyframe_shape(ak->cfra,
y,
6.0f,
@@ -207,7 +207,7 @@ static void nla_actionclip_draw_markers(
immUniformThemeColorShade(TH_STRIP_SELECT, shade);
immBeginAtMost(GPU_PRIM_LINES, BLI_listbase_count(&act->markers) * 2);
- for (TimeMarker *marker = act->markers.first; marker; marker = marker->next) {
+ LISTBASE_FOREACH (TimeMarker *, marker, &act->markers) {
if ((marker->frame > strip->actstart) && (marker->frame < strip->actend)) {
float frame = nlastrip_get_frame(strip, marker->frame, NLATIME_CONVERT_MAP);
@@ -238,7 +238,7 @@ static void nla_strip_draw_markers(NlaStrip *strip, float yminc, float ymaxc)
/* just a solid color, so that it is very easy to spot */
int shade = 20;
/* draw the markers in the first level of strips only (if they are actions) */
- for (NlaStrip *nls = strip->strips.first; nls; nls = nls->next) {
+ LISTBASE_FOREACH (NlaStrip *, nls, &strip->strips) {
if (nls->type == NLASTRIP_TYPE_CLIP) {
nla_actionclip_draw_markers(nls, yminc, ymaxc, shade, false);
}
@@ -313,7 +313,7 @@ static void nla_strip_get_color_inside(AnimData *adt, NlaStrip *strip, float col
}
/* helper call for drawing influence/time control curves for a given NLA-strip */
-static void nla_draw_strip_curves(NlaStrip *strip, float yminc, float ymaxc, unsigned int pos)
+static void nla_draw_strip_curves(NlaStrip *strip, float yminc, float ymaxc, uint pos)
{
const float yheight = ymaxc - yminc;
@@ -325,7 +325,7 @@ static void nla_draw_strip_curves(NlaStrip *strip, float yminc, float ymaxc, uns
/* influence -------------------------- */
if (strip->flag & NLASTRIP_FLAG_USR_INFLUENCE) {
- FCurve *fcu = list_find_fcurve(&strip->fcurves, "influence", 0);
+ FCurve *fcu = BKE_fcurve_find(&strip->fcurves, "influence", 0);
float cfra;
/* plot the curve (over the strip's main region) */
@@ -565,7 +565,7 @@ static void nla_draw_strip(SpaceNla *snla,
immBeginAtMost(GPU_PRIM_LINES, 4 * BLI_listbase_count(&strip->strips));
/* only draw first-level of child-strips, but don't draw any lines on the endpoints */
- for (NlaStrip *cs = strip->strips.first; cs; cs = cs->next) {
+ LISTBASE_FOREACH (NlaStrip *, cs, &strip->strips) {
/* draw start-line if not same as end of previous (and only if not the first strip)
* - on upper half of strip
*/
@@ -828,7 +828,7 @@ void draw_nla_channel_list(const bContext *C, bAnimContext *ac, ARegion *region)
/* need to do a view-sync here, so that the keys area doesn't jump around
* (it must copy this) */
- UI_view2d_sync(NULL, ac->sa, v2d, V2D_LOCK_COPY);
+ UI_view2d_sync(NULL, ac->area, v2d, V2D_LOCK_COPY);
/* draw channels */
{ /* first pass: just the standard GL-drawing for backdrop + text */
diff --git a/source/blender/editors/space_nla/nla_edit.c b/source/blender/editors/space_nla/nla_edit.c
index 2427001657a..dec7a0fd93c 100644
--- a/source/blender/editors/space_nla/nla_edit.c
+++ b/source/blender/editors/space_nla/nla_edit.c
@@ -410,8 +410,8 @@ void NLA_OT_previewrange_set(wmOperatorType *ot)
/**
* Find the extents of the active channel
*
- * \param[out] min Bottom y-extent of channel
- * \param[out] max Top y-extent of channel
+ * \param[out] min: Bottom y-extent of channel.
+ * \param[out] max: Top y-extent of channel.
* \return Success of finding a selected channel
*/
static bool nla_channels_get_selected_extents(bAnimContext *ac, float *min, float *max)
@@ -526,7 +526,7 @@ static int nlaedit_viewsel_exec(bContext *C, wmOperator *UNUSED(op))
void NLA_OT_view_all(wmOperatorType *ot)
{
/* identifiers */
- ot->name = "View All";
+ ot->name = "Frame All";
ot->idname = "NLA_OT_view_all";
ot->description = "Reset viewable area to show full strips range";
@@ -567,7 +567,7 @@ void NLA_OT_view_frame(wmOperatorType *ot)
/* identifiers */
ot->name = "Go to Current Frame";
ot->idname = "NLA_OT_view_frame";
- ot->description = "Move the view to the playhead";
+ ot->description = "Move the view to the current frame";
/* api callbacks */
ot->exec = nlaedit_viewframe_exec;
@@ -1506,7 +1506,7 @@ static int nlaedit_swap_exec(bContext *C, wmOperator *op)
NlaTrack *nlt = (NlaTrack *)ale->data;
NlaStrip *strip, *stripN = NULL;
- NlaStrip *sa = NULL, *sb = NULL;
+ NlaStrip *area = NULL, *sb = NULL;
/* make temporary metastrips so that entire islands of selections can be moved around */
BKE_nlastrips_make_metas(&nlt->strips, 1);
@@ -1533,9 +1533,9 @@ static int nlaedit_swap_exec(bContext *C, wmOperator *op)
if (strip->flag & NLASTRIP_FLAG_SELECT) {
/* first or second strip? */
- if (sa == NULL) {
+ if (area == NULL) {
/* store as first */
- sa = strip;
+ area = strip;
}
else if (sb == NULL) {
/* store as second */
@@ -1556,7 +1556,7 @@ static int nlaedit_swap_exec(bContext *C, wmOperator *op)
"Too many clusters of strips selected in NLA Track (%s): needs exactly 2 to be selected",
nlt->name);
}
- else if (sa == NULL) {
+ else if (area == NULL) {
/* no warning as this is just a common case,
* and it may get annoying when doing multiple tracks */
}
@@ -1573,24 +1573,24 @@ static int nlaedit_swap_exec(bContext *C, wmOperator *op)
/* remove these strips from the track,
* so that we can test if they can fit in the proposed places */
- BLI_remlink(&nlt->strips, sa);
+ BLI_remlink(&nlt->strips, area);
BLI_remlink(&nlt->strips, sb);
/* calculate new extents for strips */
/* a --> b */
nsa[0] = sb->start;
- nsa[1] = sb->start + (sa->end - sa->start);
+ nsa[1] = sb->start + (area->end - area->start);
/* b --> a */
- nsb[0] = sa->start;
- nsb[1] = sa->start + (sb->end - sb->start);
+ nsb[0] = area->start;
+ nsb[1] = area->start + (sb->end - sb->start);
/* check if the track has room for the strips to be swapped */
if (BKE_nlastrips_has_space(&nlt->strips, nsa[0], nsa[1]) &&
BKE_nlastrips_has_space(&nlt->strips, nsb[0], nsb[1])) {
/* set new extents for strips then */
- sa->start = nsa[0];
- sa->end = nsa[1];
- BKE_nlameta_flush_transforms(sa);
+ area->start = nsa[0];
+ area->end = nsa[1];
+ BKE_nlameta_flush_transforms(area);
sb->start = nsb[0];
sb->end = nsb[1];
@@ -1598,7 +1598,7 @@ static int nlaedit_swap_exec(bContext *C, wmOperator *op)
}
else {
/* not enough room to swap, so show message */
- if ((sa->flag & NLASTRIP_FLAG_TEMP_META) || (sb->flag & NLASTRIP_FLAG_TEMP_META)) {
+ if ((area->flag & NLASTRIP_FLAG_TEMP_META) || (sb->flag & NLASTRIP_FLAG_TEMP_META)) {
BKE_report(
op->reports,
RPT_WARNING,
@@ -1609,13 +1609,13 @@ static int nlaedit_swap_exec(bContext *C, wmOperator *op)
RPT_WARNING,
"Cannot swap '%s' and '%s' as one or both will not be able to fit in their "
"new places",
- sa->name,
+ area->name,
sb->name);
}
}
/* add strips back to track now */
- BKE_nlatrack_add_strip(nlt, sa);
+ BKE_nlatrack_add_strip(nlt, area);
BKE_nlatrack_add_strip(nlt, sb);
}
diff --git a/source/blender/editors/space_nla/nla_select.c b/source/blender/editors/space_nla/nla_select.c
index 09abfc300c7..ec41368b9f0 100644
--- a/source/blender/editors/space_nla/nla_select.c
+++ b/source/blender/editors/space_nla/nla_select.c
@@ -308,7 +308,7 @@ static void nlaedit_strip_at_region_position(
if (ale->type == ANIMTYPE_NLATRACK) {
NlaTrack *nlt = (NlaTrack *)ale->data;
- for (NlaStrip *strip = nlt->strips.first; strip; strip = strip->next) {
+ LISTBASE_FOREACH (NlaStrip *, strip, &nlt->strips) {
if (BKE_nlastrip_within_bounds(strip, xmin, xmax)) {
*r_ale = ale;
*r_strip = strip;
diff --git a/source/blender/editors/space_nla/space_nla.c b/source/blender/editors/space_nla/space_nla.c
index c4e1431ee26..f060693d9f4 100644
--- a/source/blender/editors/space_nla/space_nla.c
+++ b/source/blender/editors/space_nla/space_nla.c
@@ -57,7 +57,7 @@
/* ******************** default callbacks for nla space ***************** */
-static SpaceLink *nla_new(const ScrArea *sa, const Scene *scene)
+static SpaceLink *nla_new(const ScrArea *area, const Scene *scene)
{
ARegion *region;
SpaceNla *snla;
@@ -105,7 +105,7 @@ static SpaceLink *nla_new(const ScrArea *sa, const Scene *scene)
region->regiontype = RGN_TYPE_WINDOW;
region->v2d.tot.xmin = (float)(SFRA - 10);
- region->v2d.tot.ymin = (float)(-sa->winy) / 3.0f;
+ region->v2d.tot.ymin = (float)(-area->winy) / 3.0f;
region->v2d.tot.xmax = (float)(EFRA + 10);
region->v2d.tot.ymax = 0.0f;
@@ -141,9 +141,9 @@ static void nla_free(SpaceLink *sl)
}
/* spacetype; init callback */
-static void nla_init(struct wmWindowManager *wm, ScrArea *sa)
+static void nla_init(struct wmWindowManager *wm, ScrArea *area)
{
- SpaceNla *snla = (SpaceNla *)sa->spacedata.first;
+ SpaceNla *snla = (SpaceNla *)area->spacedata.first;
/* init dopesheet data if non-existent (i.e. for old files) */
if (snla->ads == NULL) {
@@ -151,7 +151,7 @@ static void nla_init(struct wmWindowManager *wm, ScrArea *sa)
snla->ads->source = (ID *)WM_window_get_active_scene(wm->winactive);
}
- ED_area_tag_refresh(sa);
+ ED_area_tag_refresh(area);
}
static SpaceLink *nla_duplicate(SpaceLink *sl)
@@ -325,7 +325,7 @@ static void nla_buttons_region_draw(const bContext *C, ARegion *region)
}
static void nla_region_listener(wmWindow *UNUSED(win),
- ScrArea *UNUSED(sa),
+ ScrArea *UNUSED(area),
ARegion *region,
wmNotifier *wmn,
const Scene *UNUSED(scene))
@@ -365,7 +365,7 @@ static void nla_region_listener(wmWindow *UNUSED(win),
}
static void nla_main_region_listener(wmWindow *UNUSED(win),
- ScrArea *UNUSED(sa),
+ ScrArea *UNUSED(area),
ARegion *region,
wmNotifier *wmn,
const Scene *UNUSED(scene))
@@ -427,12 +427,12 @@ static void nla_main_region_message_subscribe(const struct bContext *UNUSED(C),
struct WorkSpace *UNUSED(workspace),
struct Scene *scene,
struct bScreen *screen,
- struct ScrArea *sa,
+ struct ScrArea *area,
struct ARegion *region,
struct wmMsgBus *mbus)
{
PointerRNA ptr;
- RNA_pointer_create(&screen->id, &RNA_SpaceNLA, sa->spacedata.first, &ptr);
+ RNA_pointer_create(&screen->id, &RNA_SpaceNLA, area->spacedata.first, &ptr);
wmMsgSubscribeValue msg_sub_value_region_tag_redraw = {
.owner = region,
@@ -466,7 +466,7 @@ static void nla_main_region_message_subscribe(const struct bContext *UNUSED(C),
}
static void nla_channel_region_listener(wmWindow *UNUSED(win),
- ScrArea *UNUSED(sa),
+ ScrArea *UNUSED(area),
ARegion *region,
wmNotifier *wmn,
const Scene *UNUSED(scene))
@@ -512,12 +512,12 @@ static void nla_channel_region_message_subscribe(const struct bContext *UNUSED(C
struct WorkSpace *UNUSED(workspace),
struct Scene *UNUSED(scene),
struct bScreen *screen,
- struct ScrArea *sa,
+ struct ScrArea *area,
struct ARegion *region,
struct wmMsgBus *mbus)
{
PointerRNA ptr;
- RNA_pointer_create(&screen->id, &RNA_SpaceNLA, sa->spacedata.first, &ptr);
+ RNA_pointer_create(&screen->id, &RNA_SpaceNLA, area->spacedata.first, &ptr);
wmMsgSubscribeValue msg_sub_value_region_tag_redraw = {
.owner = region,
@@ -543,24 +543,27 @@ static void nla_channel_region_message_subscribe(const struct bContext *UNUSED(C
}
/* editor level listener */
-static void nla_listener(wmWindow *UNUSED(win), ScrArea *sa, wmNotifier *wmn, Scene *UNUSED(scene))
+static void nla_listener(wmWindow *UNUSED(win),
+ ScrArea *area,
+ wmNotifier *wmn,
+ Scene *UNUSED(scene))
{
/* context changes */
switch (wmn->category) {
case NC_ANIMATION:
// TODO: filter specific types of changes?
- ED_area_tag_refresh(sa);
+ ED_area_tag_refresh(area);
break;
case NC_SCENE:
#if 0
switch (wmn->data) {
case ND_OB_ACTIVE:
case ND_OB_SELECT:
- ED_area_tag_refresh(sa);
+ ED_area_tag_refresh(area);
break;
}
#endif
- ED_area_tag_refresh(sa);
+ ED_area_tag_refresh(area);
break;
case NC_OBJECT:
switch (wmn->data) {
@@ -568,19 +571,19 @@ static void nla_listener(wmWindow *UNUSED(win), ScrArea *sa, wmNotifier *wmn, Sc
/* do nothing */
break;
default:
- ED_area_tag_refresh(sa);
+ ED_area_tag_refresh(area);
break;
}
break;
case NC_SPACE:
if (wmn->data == ND_SPACE_NLA) {
- ED_area_tag_redraw(sa);
+ ED_area_tag_redraw(area);
}
break;
}
}
-static void nla_id_remap(ScrArea *UNUSED(sa), SpaceLink *slink, ID *old_id, ID *new_id)
+static void nla_id_remap(ScrArea *UNUSED(area), SpaceLink *slink, ID *old_id, ID *new_id)
{
SpaceNla *snla = (SpaceNla *)slink;
diff --git a/source/blender/editors/space_node/CMakeLists.txt b/source/blender/editors/space_node/CMakeLists.txt
index f8c30f9a688..4e21cdc9d16 100644
--- a/source/blender/editors/space_node/CMakeLists.txt
+++ b/source/blender/editors/space_node/CMakeLists.txt
@@ -75,6 +75,10 @@ if(WITH_OPENIMAGEDENOISE)
add_definitions(-DWITH_OPENIMAGEDENOISE)
endif()
+if (WITH_NEW_SIMULATION_TYPE)
+ add_definitions(-DWITH_NEW_SIMULATION_TYPE)
+endif()
+
add_definitions(${GL_DEFINITIONS})
blender_add_lib(bf_editor_space_node "${SRC}" "${INC}" "${INC_SYS}" "${LIB}")
diff --git a/source/blender/editors/space_node/drawnode.c b/source/blender/editors/space_node/drawnode.c
index 55a5a043014..01ac3a80871 100644
--- a/source/blender/editors/space_node/drawnode.c
+++ b/source/blender/editors/space_node/drawnode.c
@@ -69,9 +69,13 @@
#include "NOD_composite.h"
#include "NOD_shader.h"
+#include "NOD_simulation.h"
#include "NOD_texture.h"
#include "node_intern.h" /* own include */
+/* Default flags for uiItemR(). Name is kept short since this is used a lot in this file. */
+#define DEFAULT_FLAGS UI_ITEM_R_SPLIT_EMPTY_NAME
+
/* ****************** SOCKET BUTTON DRAW FUNCTIONS ***************** */
static void node_socket_button_label(bContext *UNUSED(C),
@@ -93,7 +97,7 @@ static void node_buts_value(uiLayout *layout, bContext *UNUSED(C), PointerRNA *p
PointerRNA sockptr;
RNA_pointer_create(ptr->owner_id, &RNA_NodeSocket, output, &sockptr);
- uiItemR(layout, &sockptr, "default_value", 0, "", ICON_NONE);
+ uiItemR(layout, &sockptr, "default_value", DEFAULT_FLAGS, "", ICON_NONE);
}
static void node_buts_rgb(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr)
@@ -107,7 +111,7 @@ static void node_buts_rgb(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr
col = uiLayoutColumn(layout, false);
uiTemplateColorPicker(col, &sockptr, "default_value", 1, 0, 0, 0);
- uiItemR(col, &sockptr, "default_value", UI_ITEM_R_SLIDER, "", ICON_NONE);
+ uiItemR(col, &sockptr, "default_value", DEFAULT_FLAGS | UI_ITEM_R_SLIDER, "", ICON_NONE);
}
static void node_buts_mix_rgb(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr)
@@ -118,12 +122,12 @@ static void node_buts_mix_rgb(uiLayout *layout, bContext *UNUSED(C), PointerRNA
col = uiLayoutColumn(layout, false);
row = uiLayoutRow(col, true);
- uiItemR(row, ptr, "blend_type", 0, "", ICON_NONE);
+ uiItemR(row, ptr, "blend_type", DEFAULT_FLAGS, "", ICON_NONE);
if (ELEM(ntree->type, NTREE_COMPOSIT, NTREE_TEXTURE)) {
- uiItemR(row, ptr, "use_alpha", 0, "", ICON_IMAGE_RGB_ALPHA);
+ uiItemR(row, ptr, "use_alpha", DEFAULT_FLAGS, "", ICON_IMAGE_RGB_ALPHA);
}
- uiItemR(col, ptr, "use_clamp", 0, NULL, ICON_NONE);
+ uiItemR(col, ptr, "use_clamp", DEFAULT_FLAGS, NULL, ICON_NONE);
}
static void node_buts_time(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr)
@@ -145,8 +149,8 @@ static void node_buts_time(uiLayout *layout, bContext *UNUSED(C), PointerRNA *pt
uiTemplateCurveMapping(layout, ptr, "curve", 's', false, false, false, false);
row = uiLayoutRow(layout, true);
- uiItemR(row, ptr, "frame_start", 0, IFACE_("Sta"), ICON_NONE);
- uiItemR(row, ptr, "frame_end", 0, IFACE_("End"), ICON_NONE);
+ uiItemR(row, ptr, "frame_start", DEFAULT_FLAGS, IFACE_("Sta"), ICON_NONE);
+ uiItemR(row, ptr, "frame_end", DEFAULT_FLAGS, IFACE_("End"), ICON_NONE);
}
static void node_buts_colorramp(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr)
@@ -196,7 +200,7 @@ static void node_buts_normal(uiLayout *layout, bContext *UNUSED(C), PointerRNA *
PointerRNA sockptr;
RNA_pointer_create(ptr->owner_id, &RNA_NodeSocket, output, &sockptr);
- uiItemR(layout, &sockptr, "default_value", 0, "", ICON_NONE);
+ uiItemR(layout, &sockptr, "default_value", DEFAULT_FLAGS, "", ICON_NONE);
}
#if 0 /* not used in 2.5x yet */
@@ -242,33 +246,33 @@ static void node_buts_texture(uiLayout *layout, bContext *UNUSED(C), PointerRNA
short multi = (node->id && ((Tex *)node->id)->use_nodes && (node->type != CMP_NODE_TEXTURE) &&
(node->type != TEX_NODE_TEXTURE));
- uiItemR(layout, ptr, "texture", 0, "", ICON_NONE);
+ uiItemR(layout, ptr, "texture", DEFAULT_FLAGS, "", ICON_NONE);
if (multi) {
/* Number Drawing not optimal here, better have a list*/
- uiItemR(layout, ptr, "node_output", 0, "", ICON_NONE);
+ uiItemR(layout, ptr, "node_output", DEFAULT_FLAGS, "", ICON_NONE);
}
}
static void node_shader_buts_clamp(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr)
{
- uiItemR(layout, ptr, "clamp_type", 0, "", ICON_NONE);
+ uiItemR(layout, ptr, "clamp_type", DEFAULT_FLAGS, "", ICON_NONE);
}
static void node_shader_buts_map_range(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr)
{
- uiItemR(layout, ptr, "interpolation_type", 0, "", ICON_NONE);
+ uiItemR(layout, ptr, "interpolation_type", DEFAULT_FLAGS, "", ICON_NONE);
if (!ELEM(RNA_enum_get(ptr, "interpolation_type"),
NODE_MAP_RANGE_SMOOTHSTEP,
NODE_MAP_RANGE_SMOOTHERSTEP)) {
- uiItemR(layout, ptr, "clamp", 0, NULL, ICON_NONE);
+ uiItemR(layout, ptr, "clamp", DEFAULT_FLAGS, NULL, ICON_NONE);
}
}
static void node_buts_math(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr)
{
- uiItemR(layout, ptr, "operation", 0, "", ICON_NONE);
- uiItemR(layout, ptr, "use_clamp", 0, NULL, ICON_NONE);
+ uiItemR(layout, ptr, "operation", DEFAULT_FLAGS, "", ICON_NONE);
+ uiItemR(layout, ptr, "use_clamp", DEFAULT_FLAGS, NULL, ICON_NONE);
}
static int node_resize_area_default(bNode *node, int x, int y)
@@ -534,9 +538,9 @@ static int node_resize_area_frame(bNode *node, int x, int y)
static void node_buts_frame_ex(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr)
{
- uiItemR(layout, ptr, "label_size", 0, IFACE_("Label Size"), ICON_NONE);
- uiItemR(layout, ptr, "shrink", 0, IFACE_("Shrink"), ICON_NONE);
- uiItemR(layout, ptr, "text", 0, NULL, ICON_NONE);
+ uiItemR(layout, ptr, "label_size", DEFAULT_FLAGS, IFACE_("Label Size"), ICON_NONE);
+ uiItemR(layout, ptr, "shrink", DEFAULT_FLAGS, IFACE_("Shrink"), ICON_NONE);
+ uiItemR(layout, ptr, "text", DEFAULT_FLAGS, NULL, ICON_NONE);
}
#define NODE_REROUTE_SIZE 8.0f
@@ -697,7 +701,7 @@ static void node_buts_image_user(uiLayout *layout,
col = uiLayoutColumn(layout, false);
- uiItemR(col, imaptr, "source", 0, "", ICON_NONE);
+ uiItemR(col, imaptr, "source", DEFAULT_FLAGS, "", ICON_NONE);
source = RNA_enum_get(imaptr, "source");
@@ -716,23 +720,23 @@ static void node_buts_image_user(uiLayout *layout,
if (ELEM(source, IMA_SRC_SEQUENCE, IMA_SRC_MOVIE)) {
col = uiLayoutColumn(layout, true);
- uiItemR(col, ptr, "frame_duration", 0, NULL, ICON_NONE);
- uiItemR(col, ptr, "frame_start", 0, NULL, ICON_NONE);
- uiItemR(col, ptr, "frame_offset", 0, NULL, ICON_NONE);
- uiItemR(col, ptr, "use_cyclic", 0, NULL, ICON_NONE);
- uiItemR(col, ptr, "use_auto_refresh", 0, NULL, ICON_NONE);
+ uiItemR(col, ptr, "frame_duration", DEFAULT_FLAGS, NULL, ICON_NONE);
+ uiItemR(col, ptr, "frame_start", DEFAULT_FLAGS, NULL, ICON_NONE);
+ uiItemR(col, ptr, "frame_offset", DEFAULT_FLAGS, NULL, ICON_NONE);
+ uiItemR(col, ptr, "use_cyclic", DEFAULT_FLAGS, NULL, ICON_NONE);
+ uiItemR(col, ptr, "use_auto_refresh", DEFAULT_FLAGS, NULL, ICON_NONE);
}
if (compositor && RNA_enum_get(imaptr, "type") == IMA_TYPE_MULTILAYER &&
RNA_boolean_get(ptr, "has_layers")) {
col = uiLayoutColumn(layout, false);
- uiItemR(col, ptr, "layer", 0, NULL, ICON_NONE);
+ uiItemR(col, ptr, "layer", DEFAULT_FLAGS, NULL, ICON_NONE);
}
uiLayout *split = uiLayoutSplit(layout, 0.5f, true);
PointerRNA colorspace_settings_ptr = RNA_pointer_get(imaptr, "colorspace_settings");
uiItemL(split, IFACE_("Color Space"), ICON_NONE);
- uiItemR(split, &colorspace_settings_ptr, "name", 0, "", ICON_NONE);
+ uiItemR(split, &colorspace_settings_ptr, "name", DEFAULT_FLAGS, "", ICON_NONE);
/* Avoid losing changes image is painted. */
if (BKE_image_is_dirty(imaptr->data)) {
@@ -742,35 +746,35 @@ static void node_buts_image_user(uiLayout *layout,
static void node_shader_buts_mapping(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr)
{
- uiItemR(layout, ptr, "vector_type", 0, NULL, ICON_NONE);
+ uiItemR(layout, ptr, "vector_type", DEFAULT_FLAGS, NULL, ICON_NONE);
}
static void node_shader_buts_vector_rotate(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr)
{
- uiItemR(layout, ptr, "rotation_type", 0, NULL, ICON_NONE);
- uiItemR(layout, ptr, "invert", 0, NULL, 0);
+ uiItemR(layout, ptr, "rotation_type", DEFAULT_FLAGS, NULL, ICON_NONE);
+ uiItemR(layout, ptr, "invert", DEFAULT_FLAGS, NULL, 0);
}
static void node_shader_buts_vect_math(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr)
{
- uiItemR(layout, ptr, "operation", 0, "", ICON_NONE);
+ uiItemR(layout, ptr, "operation", DEFAULT_FLAGS, "", ICON_NONE);
}
static void node_shader_buts_vect_transform(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr)
{
- uiItemR(layout, ptr, "vector_type", UI_ITEM_R_EXPAND, NULL, ICON_NONE);
- uiItemR(layout, ptr, "convert_from", 0, "", ICON_NONE);
- uiItemR(layout, ptr, "convert_to", 0, "", ICON_NONE);
+ uiItemR(layout, ptr, "vector_type", DEFAULT_FLAGS | UI_ITEM_R_EXPAND, NULL, ICON_NONE);
+ uiItemR(layout, ptr, "convert_from", DEFAULT_FLAGS, "", ICON_NONE);
+ uiItemR(layout, ptr, "convert_to", DEFAULT_FLAGS, "", ICON_NONE);
}
static void node_shader_buts_attribute(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr)
{
- uiItemR(layout, ptr, "attribute_name", 0, IFACE_("Name"), ICON_NONE);
+ uiItemR(layout, ptr, "attribute_name", DEFAULT_FLAGS, IFACE_("Name"), ICON_NONE);
}
static void node_shader_buts_wireframe(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr)
{
- uiItemR(layout, ptr, "use_pixel_size", 0, NULL, 0);
+ uiItemR(layout, ptr, "use_pixel_size", DEFAULT_FLAGS, NULL, 0);
}
static void node_shader_buts_tex_image(uiLayout *layout, bContext *C, PointerRNA *ptr)
@@ -789,14 +793,14 @@ static void node_shader_buts_tex_image(uiLayout *layout, bContext *C, PointerRNA
UI_TEMPLATE_ID_FILTER_ALL,
false,
NULL);
- uiItemR(layout, ptr, "interpolation", 0, "", ICON_NONE);
- uiItemR(layout, ptr, "projection", 0, "", ICON_NONE);
+ uiItemR(layout, ptr, "interpolation", DEFAULT_FLAGS, "", ICON_NONE);
+ uiItemR(layout, ptr, "projection", DEFAULT_FLAGS, "", ICON_NONE);
if (RNA_enum_get(ptr, "projection") == SHD_PROJ_BOX) {
- uiItemR(layout, ptr, "projection_blend", 0, "Blend", ICON_NONE);
+ uiItemR(layout, ptr, "projection_blend", DEFAULT_FLAGS, "Blend", ICON_NONE);
}
- uiItemR(layout, ptr, "extension", 0, "", ICON_NONE);
+ uiItemR(layout, ptr, "extension", DEFAULT_FLAGS, "", ICON_NONE);
/* note: image user properties used directly here, unlike compositor image node,
* which redefines them in the node struct RNA to get proper updates.
@@ -827,8 +831,8 @@ static void node_shader_buts_tex_environment(uiLayout *layout, bContext *C, Poin
false,
NULL);
- uiItemR(layout, ptr, "interpolation", 0, "", ICON_NONE);
- uiItemR(layout, ptr, "projection", 0, "", ICON_NONE);
+ uiItemR(layout, ptr, "interpolation", DEFAULT_FLAGS, "", ICON_NONE);
+ uiItemR(layout, ptr, "projection", DEFAULT_FLAGS, "", ICON_NONE);
node_buts_image_user(layout, C, &iuserptr, &imaptr, &iuserptr, false);
}
@@ -838,29 +842,29 @@ static void node_shader_buts_tex_environment_ex(uiLayout *layout, bContext *C, P
PointerRNA iuserptr = RNA_pointer_get(ptr, "image_user");
uiTemplateImage(layout, C, ptr, "image", &iuserptr, 0, 0);
- uiItemR(layout, ptr, "interpolation", 0, IFACE_("Interpolation"), ICON_NONE);
- uiItemR(layout, ptr, "projection", 0, IFACE_("Projection"), ICON_NONE);
+ uiItemR(layout, ptr, "interpolation", DEFAULT_FLAGS, IFACE_("Interpolation"), ICON_NONE);
+ uiItemR(layout, ptr, "projection", DEFAULT_FLAGS, IFACE_("Projection"), ICON_NONE);
}
static void node_shader_buts_tex_sky(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr)
{
- uiItemR(layout, ptr, "sky_type", 0, "", ICON_NONE);
- uiItemR(layout, ptr, "sun_direction", 0, "", ICON_NONE);
- uiItemR(layout, ptr, "turbidity", 0, NULL, ICON_NONE);
+ uiItemR(layout, ptr, "sky_type", DEFAULT_FLAGS, "", ICON_NONE);
+ uiItemR(layout, ptr, "sun_direction", DEFAULT_FLAGS, "", ICON_NONE);
+ uiItemR(layout, ptr, "turbidity", DEFAULT_FLAGS, NULL, ICON_NONE);
if (RNA_enum_get(ptr, "sky_type") == SHD_SKY_NEW) {
- uiItemR(layout, ptr, "ground_albedo", 0, NULL, ICON_NONE);
+ uiItemR(layout, ptr, "ground_albedo", DEFAULT_FLAGS, NULL, ICON_NONE);
}
}
static void node_shader_buts_tex_gradient(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr)
{
- uiItemR(layout, ptr, "gradient_type", 0, "", ICON_NONE);
+ uiItemR(layout, ptr, "gradient_type", DEFAULT_FLAGS, "", ICON_NONE);
}
static void node_shader_buts_tex_magic(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr)
{
- uiItemR(layout, ptr, "turbulence_depth", 0, NULL, ICON_NONE);
+ uiItemR(layout, ptr, "turbulence_depth", DEFAULT_FLAGS, NULL, ICON_NONE);
}
static void node_shader_buts_tex_brick(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr)
@@ -868,48 +872,48 @@ static void node_shader_buts_tex_brick(uiLayout *layout, bContext *UNUSED(C), Po
uiLayout *col;
col = uiLayoutColumn(layout, true);
- uiItemR(col, ptr, "offset", UI_ITEM_R_SLIDER, IFACE_("Offset"), ICON_NONE);
- uiItemR(col, ptr, "offset_frequency", 0, IFACE_("Frequency"), ICON_NONE);
+ uiItemR(col, ptr, "offset", DEFAULT_FLAGS | UI_ITEM_R_SLIDER, IFACE_("Offset"), ICON_NONE);
+ uiItemR(col, ptr, "offset_frequency", DEFAULT_FLAGS, IFACE_("Frequency"), ICON_NONE);
col = uiLayoutColumn(layout, true);
- uiItemR(col, ptr, "squash", 0, IFACE_("Squash"), ICON_NONE);
- uiItemR(col, ptr, "squash_frequency", 0, IFACE_("Frequency"), ICON_NONE);
+ uiItemR(col, ptr, "squash", DEFAULT_FLAGS, IFACE_("Squash"), ICON_NONE);
+ uiItemR(col, ptr, "squash_frequency", DEFAULT_FLAGS, IFACE_("Frequency"), ICON_NONE);
}
static void node_shader_buts_tex_wave(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr)
{
- uiItemR(layout, ptr, "wave_type", 0, "", ICON_NONE);
+ uiItemR(layout, ptr, "wave_type", DEFAULT_FLAGS, "", ICON_NONE);
int type = RNA_enum_get(ptr, "wave_type");
if (type == SHD_WAVE_BANDS) {
- uiItemR(layout, ptr, "bands_direction", 0, "", ICON_NONE);
+ uiItemR(layout, ptr, "bands_direction", DEFAULT_FLAGS, "", ICON_NONE);
}
else { /* SHD_WAVE_RINGS */
- uiItemR(layout, ptr, "rings_direction", 0, "", ICON_NONE);
+ uiItemR(layout, ptr, "rings_direction", DEFAULT_FLAGS, "", ICON_NONE);
}
- uiItemR(layout, ptr, "wave_profile", 0, "", ICON_NONE);
+ uiItemR(layout, ptr, "wave_profile", DEFAULT_FLAGS, "", ICON_NONE);
}
static void node_shader_buts_tex_musgrave(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr)
{
- uiItemR(layout, ptr, "musgrave_dimensions", 0, "", ICON_NONE);
- uiItemR(layout, ptr, "musgrave_type", 0, "", ICON_NONE);
+ uiItemR(layout, ptr, "musgrave_dimensions", DEFAULT_FLAGS, "", ICON_NONE);
+ uiItemR(layout, ptr, "musgrave_type", DEFAULT_FLAGS, "", ICON_NONE);
}
static void node_shader_buts_tex_voronoi(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr)
{
- uiItemR(layout, ptr, "voronoi_dimensions", 0, "", ICON_NONE);
- uiItemR(layout, ptr, "feature", 0, "", ICON_NONE);
+ uiItemR(layout, ptr, "voronoi_dimensions", DEFAULT_FLAGS, "", ICON_NONE);
+ uiItemR(layout, ptr, "feature", DEFAULT_FLAGS, "", ICON_NONE);
int feature = RNA_enum_get(ptr, "feature");
if (!ELEM(feature, SHD_VORONOI_DISTANCE_TO_EDGE, SHD_VORONOI_N_SPHERE_RADIUS) &&
RNA_enum_get(ptr, "voronoi_dimensions") != 1) {
- uiItemR(layout, ptr, "distance", 0, "", ICON_NONE);
+ uiItemR(layout, ptr, "distance", DEFAULT_FLAGS, "", ICON_NONE);
}
}
static void node_shader_buts_tex_noise(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr)
{
- uiItemR(layout, ptr, "noise_dimensions", 0, "", ICON_NONE);
+ uiItemR(layout, ptr, "noise_dimensions", DEFAULT_FLAGS, "", ICON_NONE);
}
static void node_shader_buts_tex_pointdensity(uiLayout *layout,
@@ -925,7 +929,7 @@ static void node_shader_buts_tex_pointdensity(uiLayout *layout,
RNA_id_pointer_create(ob ? (ID *)ob->data : NULL, &obdata_ptr);
uiItemR(layout, ptr, "point_source", UI_ITEM_R_EXPAND, NULL, ICON_NONE);
- uiItemR(layout, ptr, "object", 0, NULL, ICON_NONE);
+ uiItemR(layout, ptr, "object", DEFAULT_FLAGS, NULL, ICON_NONE);
if (node->id && shader_point_density->point_source == SHD_POINTDENSITY_SOURCE_PSYS) {
PointerRNA dataptr;
@@ -933,15 +937,15 @@ static void node_shader_buts_tex_pointdensity(uiLayout *layout,
uiItemPointerR(layout, ptr, "particle_system", &dataptr, "particle_systems", NULL, ICON_NONE);
}
- uiItemR(layout, ptr, "space", 0, NULL, ICON_NONE);
- uiItemR(layout, ptr, "radius", 0, NULL, ICON_NONE);
- uiItemR(layout, ptr, "interpolation", 0, NULL, ICON_NONE);
- uiItemR(layout, ptr, "resolution", 0, NULL, ICON_NONE);
+ uiItemR(layout, ptr, "space", DEFAULT_FLAGS, NULL, ICON_NONE);
+ uiItemR(layout, ptr, "radius", DEFAULT_FLAGS, NULL, ICON_NONE);
+ uiItemR(layout, ptr, "interpolation", DEFAULT_FLAGS, NULL, ICON_NONE);
+ uiItemR(layout, ptr, "resolution", DEFAULT_FLAGS, NULL, ICON_NONE);
if (shader_point_density->point_source == SHD_POINTDENSITY_SOURCE_PSYS) {
- uiItemR(layout, ptr, "particle_color_source", 0, NULL, ICON_NONE);
+ uiItemR(layout, ptr, "particle_color_source", DEFAULT_FLAGS, NULL, ICON_NONE);
}
else {
- uiItemR(layout, ptr, "vertex_color_source", 0, NULL, ICON_NONE);
+ uiItemR(layout, ptr, "vertex_color_source", DEFAULT_FLAGS, NULL, ICON_NONE);
if (shader_point_density->ob_color_source == SHD_POINTDENSITY_COLOR_VERTWEIGHT) {
if (ob_ptr.data) {
uiItemPointerR(
@@ -959,18 +963,18 @@ static void node_shader_buts_tex_pointdensity(uiLayout *layout,
static void node_shader_buts_tex_coord(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr)
{
- uiItemR(layout, ptr, "object", 0, NULL, 0);
- uiItemR(layout, ptr, "from_instancer", 0, NULL, 0);
+ uiItemR(layout, ptr, "object", DEFAULT_FLAGS, NULL, 0);
+ uiItemR(layout, ptr, "from_instancer", DEFAULT_FLAGS, NULL, 0);
}
static void node_shader_buts_bump(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr)
{
- uiItemR(layout, ptr, "invert", 0, NULL, 0);
+ uiItemR(layout, ptr, "invert", DEFAULT_FLAGS, NULL, 0);
}
static void node_shader_buts_uvmap(uiLayout *layout, bContext *C, PointerRNA *ptr)
{
- uiItemR(layout, ptr, "from_instancer", 0, NULL, 0);
+ uiItemR(layout, ptr, "from_instancer", DEFAULT_FLAGS, NULL, 0);
if (!RNA_boolean_get(ptr, "from_instancer")) {
PointerRNA obptr = CTX_data_pointer_get(C, "active_object");
@@ -996,12 +1000,12 @@ static void node_shader_buts_vertex_color(uiLayout *layout, bContext *C, Pointer
static void node_shader_buts_uvalongstroke(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr)
{
- uiItemR(layout, ptr, "use_tips", 0, NULL, 0);
+ uiItemR(layout, ptr, "use_tips", DEFAULT_FLAGS, NULL, 0);
}
static void node_shader_buts_normal_map(uiLayout *layout, bContext *C, PointerRNA *ptr)
{
- uiItemR(layout, ptr, "space", 0, "", 0);
+ uiItemR(layout, ptr, "space", DEFAULT_FLAGS, "", 0);
if (RNA_enum_get(ptr, "space") == SHD_SPACE_TANGENT) {
PointerRNA obptr = CTX_data_pointer_get(C, "active_object");
@@ -1011,14 +1015,14 @@ static void node_shader_buts_normal_map(uiLayout *layout, bContext *C, PointerRN
uiItemPointerR(layout, ptr, "uv_map", &dataptr, "uv_layers", "", ICON_NONE);
}
else {
- uiItemR(layout, ptr, "uv_map", 0, "", 0);
+ uiItemR(layout, ptr, "uv_map", DEFAULT_FLAGS, "", 0);
}
}
}
static void node_shader_buts_displacement(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr)
{
- uiItemR(layout, ptr, "space", 0, "", 0);
+ uiItemR(layout, ptr, "space", DEFAULT_FLAGS, "", 0);
}
static void node_shader_buts_tangent(uiLayout *layout, bContext *C, PointerRNA *ptr)
@@ -1027,7 +1031,7 @@ static void node_shader_buts_tangent(uiLayout *layout, bContext *C, PointerRNA *
split = uiLayoutSplit(layout, 0.0f, false);
- uiItemR(split, ptr, "direction_type", 0, "", 0);
+ uiItemR(split, ptr, "direction_type", DEFAULT_FLAGS, "", 0);
row = uiLayoutRow(split, false);
@@ -1039,50 +1043,50 @@ static void node_shader_buts_tangent(uiLayout *layout, bContext *C, PointerRNA *
uiItemPointerR(row, ptr, "uv_map", &dataptr, "uv_layers", "", ICON_NONE);
}
else {
- uiItemR(row, ptr, "uv_map", 0, "", 0);
+ uiItemR(row, ptr, "uv_map", DEFAULT_FLAGS, "", 0);
}
}
else {
- uiItemR(row, ptr, "axis", UI_ITEM_R_EXPAND, NULL, 0);
+ uiItemR(row, ptr, "axis", DEFAULT_FLAGS | UI_ITEM_R_EXPAND, NULL, 0);
}
}
static void node_shader_buts_glossy(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr)
{
- uiItemR(layout, ptr, "distribution", 0, "", ICON_NONE);
+ uiItemR(layout, ptr, "distribution", DEFAULT_FLAGS, "", ICON_NONE);
}
static void node_shader_buts_principled(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr)
{
- uiItemR(layout, ptr, "distribution", 0, "", ICON_NONE);
- uiItemR(layout, ptr, "subsurface_method", 0, "", ICON_NONE);
+ uiItemR(layout, ptr, "distribution", DEFAULT_FLAGS, "", ICON_NONE);
+ uiItemR(layout, ptr, "subsurface_method", DEFAULT_FLAGS, "", ICON_NONE);
}
static void node_shader_buts_anisotropic(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr)
{
- uiItemR(layout, ptr, "distribution", 0, "", ICON_NONE);
+ uiItemR(layout, ptr, "distribution", DEFAULT_FLAGS, "", ICON_NONE);
}
static void node_shader_buts_subsurface(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr)
{
- uiItemR(layout, ptr, "falloff", 0, "", ICON_NONE);
+ uiItemR(layout, ptr, "falloff", DEFAULT_FLAGS, "", ICON_NONE);
}
static void node_shader_buts_toon(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr)
{
- uiItemR(layout, ptr, "component", 0, "", ICON_NONE);
+ uiItemR(layout, ptr, "component", DEFAULT_FLAGS, "", ICON_NONE);
}
static void node_shader_buts_hair(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr)
{
- uiItemR(layout, ptr, "component", 0, "", ICON_NONE);
+ uiItemR(layout, ptr, "component", DEFAULT_FLAGS, "", ICON_NONE);
}
static void node_shader_buts_principled_hair(uiLayout *layout,
bContext *UNUSED(C),
PointerRNA *ptr)
{
- uiItemR(layout, ptr, "parametrization", 0, "", ICON_NONE);
+ uiItemR(layout, ptr, "parametrization", DEFAULT_FLAGS, "", ICON_NONE);
}
static void node_shader_buts_ies(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr)
@@ -1090,15 +1094,15 @@ static void node_shader_buts_ies(uiLayout *layout, bContext *UNUSED(C), PointerR
uiLayout *row;
row = uiLayoutRow(layout, false);
- uiItemR(row, ptr, "mode", UI_ITEM_R_EXPAND, NULL, ICON_NONE);
+ uiItemR(row, ptr, "mode", DEFAULT_FLAGS | UI_ITEM_R_EXPAND, NULL, ICON_NONE);
row = uiLayoutRow(layout, true);
if (RNA_enum_get(ptr, "mode") == NODE_IES_INTERNAL) {
- uiItemR(row, ptr, "ies", 0, "", ICON_NONE);
+ uiItemR(row, ptr, "ies", DEFAULT_FLAGS, "", ICON_NONE);
}
else {
- uiItemR(row, ptr, "filepath", 0, "", ICON_NONE);
+ uiItemR(row, ptr, "filepath", DEFAULT_FLAGS, "", ICON_NONE);
}
}
@@ -1107,15 +1111,15 @@ static void node_shader_buts_script(uiLayout *layout, bContext *UNUSED(C), Point
uiLayout *row;
row = uiLayoutRow(layout, false);
- uiItemR(row, ptr, "mode", UI_ITEM_R_EXPAND, NULL, ICON_NONE);
+ uiItemR(row, ptr, "mode", DEFAULT_FLAGS | UI_ITEM_R_EXPAND, NULL, ICON_NONE);
row = uiLayoutRow(layout, true);
if (RNA_enum_get(ptr, "mode") == NODE_SCRIPT_INTERNAL) {
- uiItemR(row, ptr, "script", 0, "", ICON_NONE);
+ uiItemR(row, ptr, "script", DEFAULT_FLAGS, "", ICON_NONE);
}
else {
- uiItemR(row, ptr, "filepath", 0, "", ICON_NONE);
+ uiItemR(row, ptr, "filepath", DEFAULT_FLAGS, "", ICON_NONE);
}
uiItemO(row, "", ICON_FILE_REFRESH, "node.shader_script_update");
@@ -1129,14 +1133,14 @@ static void node_shader_buts_script_ex(uiLayout *layout, bContext *C, PointerRNA
#if 0 /* not implemented yet */
if (RNA_enum_get(ptr, "mode") == NODE_SCRIPT_EXTERNAL) {
- uiItemR(layout, ptr, "use_auto_update", 0, NULL, ICON_NONE);
+ uiItemR(layout, ptr, "use_auto_update", DEFAULT_FLAGS, NULL, ICON_NONE);
}
#endif
}
static void node_buts_output_shader(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr)
{
- uiItemR(layout, ptr, "target", 0, "", ICON_NONE);
+ uiItemR(layout, ptr, "target", DEFAULT_FLAGS, "", ICON_NONE);
}
static void node_buts_output_linestyle(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr)
@@ -1145,32 +1149,32 @@ static void node_buts_output_linestyle(uiLayout *layout, bContext *UNUSED(C), Po
col = uiLayoutColumn(layout, false);
row = uiLayoutRow(col, true);
- uiItemR(row, ptr, "blend_type", 0, "", ICON_NONE);
- uiItemR(col, ptr, "use_clamp", 0, NULL, ICON_NONE);
+ uiItemR(row, ptr, "blend_type", DEFAULT_FLAGS, "", ICON_NONE);
+ uiItemR(col, ptr, "use_clamp", DEFAULT_FLAGS, NULL, ICON_NONE);
}
static void node_shader_buts_bevel(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr)
{
- uiItemR(layout, ptr, "samples", 0, NULL, ICON_NONE);
+ uiItemR(layout, ptr, "samples", DEFAULT_FLAGS, NULL, ICON_NONE);
}
static void node_shader_buts_ambient_occlusion(uiLayout *layout,
bContext *UNUSED(C),
PointerRNA *ptr)
{
- uiItemR(layout, ptr, "samples", 0, NULL, ICON_NONE);
- uiItemR(layout, ptr, "inside", 0, NULL, ICON_NONE);
- uiItemR(layout, ptr, "only_local", 0, NULL, ICON_NONE);
+ uiItemR(layout, ptr, "samples", DEFAULT_FLAGS, NULL, ICON_NONE);
+ uiItemR(layout, ptr, "inside", DEFAULT_FLAGS, NULL, ICON_NONE);
+ uiItemR(layout, ptr, "only_local", DEFAULT_FLAGS, NULL, ICON_NONE);
}
static void node_shader_buts_white_noise(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr)
{
- uiItemR(layout, ptr, "noise_dimensions", 0, "", ICON_NONE);
+ uiItemR(layout, ptr, "noise_dimensions", DEFAULT_FLAGS, "", ICON_NONE);
}
static void node_shader_buts_output_aov(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr)
{
- uiItemR(layout, ptr, "name", 0, NULL, ICON_NONE);
+ uiItemR(layout, ptr, "name", DEFAULT_FLAGS, NULL, ICON_NONE);
}
/* only once called */
@@ -1355,10 +1359,10 @@ static void node_buts_image_views(uiLayout *layout,
if (RNA_boolean_get(ptr, "has_views")) {
if (RNA_enum_get(ptr, "view") == 0) {
- uiItemR(col, ptr, "view", 0, NULL, ICON_CAMERA_STEREO);
+ uiItemR(col, ptr, "view", DEFAULT_FLAGS, NULL, ICON_CAMERA_STEREO);
}
else {
- uiItemR(col, ptr, "view", 0, NULL, ICON_SCENE);
+ uiItemR(col, ptr, "view", DEFAULT_FLAGS, NULL, ICON_SCENE);
}
}
}
@@ -1419,7 +1423,7 @@ static void node_composit_buts_viewlayers(uiLayout *layout, bContext *C, Pointer
col = uiLayoutColumn(layout, false);
row = uiLayoutRow(col, true);
- uiItemR(row, ptr, "layer", 0, "", ICON_NONE);
+ uiItemR(row, ptr, "layer", DEFAULT_FLAGS, "", ICON_NONE);
prop = RNA_struct_find_property(ptr, "layer");
if (!(RNA_property_enum_identifier(
@@ -1446,56 +1450,56 @@ static void node_composit_buts_blur(uiLayout *layout, bContext *UNUSED(C), Point
filter = RNA_enum_get(ptr, "filter_type");
reference = RNA_boolean_get(ptr, "use_variable_size");
- uiItemR(col, ptr, "filter_type", 0, "", ICON_NONE);
+ uiItemR(col, ptr, "filter_type", DEFAULT_FLAGS, "", ICON_NONE);
if (filter != R_FILTER_FAST_GAUSS) {
- uiItemR(col, ptr, "use_variable_size", 0, NULL, ICON_NONE);
+ uiItemR(col, ptr, "use_variable_size", DEFAULT_FLAGS, NULL, ICON_NONE);
if (!reference) {
- uiItemR(col, ptr, "use_bokeh", 0, NULL, ICON_NONE);
+ uiItemR(col, ptr, "use_bokeh", DEFAULT_FLAGS, NULL, ICON_NONE);
}
- uiItemR(col, ptr, "use_gamma_correction", 0, NULL, ICON_NONE);
+ uiItemR(col, ptr, "use_gamma_correction", DEFAULT_FLAGS, NULL, ICON_NONE);
}
- uiItemR(col, ptr, "use_relative", 0, NULL, ICON_NONE);
+ uiItemR(col, ptr, "use_relative", DEFAULT_FLAGS, NULL, ICON_NONE);
if (RNA_boolean_get(ptr, "use_relative")) {
uiItemL(col, IFACE_("Aspect Correction"), ICON_NONE);
row = uiLayoutRow(layout, true);
- uiItemR(row, ptr, "aspect_correction", UI_ITEM_R_EXPAND, NULL, ICON_NONE);
+ uiItemR(row, ptr, "aspect_correction", DEFAULT_FLAGS | UI_ITEM_R_EXPAND, NULL, ICON_NONE);
col = uiLayoutColumn(layout, true);
- uiItemR(col, ptr, "factor_x", 0, IFACE_("X"), ICON_NONE);
- uiItemR(col, ptr, "factor_y", 0, IFACE_("Y"), ICON_NONE);
+ uiItemR(col, ptr, "factor_x", DEFAULT_FLAGS, IFACE_("X"), ICON_NONE);
+ uiItemR(col, ptr, "factor_y", DEFAULT_FLAGS, IFACE_("Y"), ICON_NONE);
}
else {
col = uiLayoutColumn(layout, true);
- uiItemR(col, ptr, "size_x", 0, IFACE_("X"), ICON_NONE);
- uiItemR(col, ptr, "size_y", 0, IFACE_("Y"), ICON_NONE);
+ uiItemR(col, ptr, "size_x", DEFAULT_FLAGS, IFACE_("X"), ICON_NONE);
+ uiItemR(col, ptr, "size_y", DEFAULT_FLAGS, IFACE_("Y"), ICON_NONE);
}
- uiItemR(col, ptr, "use_extended_bounds", 0, NULL, ICON_NONE);
+ uiItemR(col, ptr, "use_extended_bounds", DEFAULT_FLAGS, NULL, ICON_NONE);
}
static void node_composit_buts_dblur(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr)
{
uiLayout *col;
- uiItemR(layout, ptr, "iterations", 0, NULL, ICON_NONE);
- uiItemR(layout, ptr, "use_wrap", 0, NULL, ICON_NONE);
+ uiItemR(layout, ptr, "iterations", DEFAULT_FLAGS, NULL, ICON_NONE);
+ uiItemR(layout, ptr, "use_wrap", DEFAULT_FLAGS, NULL, ICON_NONE);
col = uiLayoutColumn(layout, true);
uiItemL(col, IFACE_("Center:"), ICON_NONE);
- uiItemR(col, ptr, "center_x", 0, IFACE_("X"), ICON_NONE);
- uiItemR(col, ptr, "center_y", 0, IFACE_("Y"), ICON_NONE);
+ uiItemR(col, ptr, "center_x", DEFAULT_FLAGS, IFACE_("X"), ICON_NONE);
+ uiItemR(col, ptr, "center_y", DEFAULT_FLAGS, IFACE_("Y"), ICON_NONE);
uiItemS(layout);
col = uiLayoutColumn(layout, true);
- uiItemR(col, ptr, "distance", 0, NULL, ICON_NONE);
- uiItemR(col, ptr, "angle", 0, NULL, ICON_NONE);
+ uiItemR(col, ptr, "distance", DEFAULT_FLAGS, NULL, ICON_NONE);
+ uiItemR(col, ptr, "angle", DEFAULT_FLAGS, NULL, ICON_NONE);
uiItemS(layout);
- uiItemR(layout, ptr, "spin", 0, NULL, ICON_NONE);
- uiItemR(layout, ptr, "zoom", 0, NULL, ICON_NONE);
+ uiItemR(layout, ptr, "spin", DEFAULT_FLAGS, NULL, ICON_NONE);
+ uiItemR(layout, ptr, "zoom", DEFAULT_FLAGS, NULL, ICON_NONE);
}
static void node_composit_buts_bilateralblur(uiLayout *layout,
@@ -1505,9 +1509,9 @@ static void node_composit_buts_bilateralblur(uiLayout *layout,
uiLayout *col;
col = uiLayoutColumn(layout, true);
- uiItemR(col, ptr, "iterations", 0, NULL, ICON_NONE);
- uiItemR(col, ptr, "sigma_color", 0, NULL, ICON_NONE);
- uiItemR(col, ptr, "sigma_space", 0, NULL, ICON_NONE);
+ uiItemR(col, ptr, "iterations", DEFAULT_FLAGS, NULL, ICON_NONE);
+ uiItemR(col, ptr, "sigma_color", DEFAULT_FLAGS, NULL, ICON_NONE);
+ uiItemR(col, ptr, "sigma_space", DEFAULT_FLAGS, NULL, ICON_NONE);
}
static void node_composit_buts_defocus(uiLayout *layout, bContext *C, PointerRNA *ptr)
@@ -1516,60 +1520,60 @@ static void node_composit_buts_defocus(uiLayout *layout, bContext *C, PointerRNA
col = uiLayoutColumn(layout, false);
uiItemL(col, IFACE_("Bokeh Type:"), ICON_NONE);
- uiItemR(col, ptr, "bokeh", 0, "", ICON_NONE);
- uiItemR(col, ptr, "angle", 0, NULL, ICON_NONE);
+ uiItemR(col, ptr, "bokeh", DEFAULT_FLAGS, "", ICON_NONE);
+ uiItemR(col, ptr, "angle", DEFAULT_FLAGS, NULL, ICON_NONE);
- uiItemR(layout, ptr, "use_gamma_correction", 0, NULL, ICON_NONE);
+ uiItemR(layout, ptr, "use_gamma_correction", DEFAULT_FLAGS, NULL, ICON_NONE);
col = uiLayoutColumn(layout, false);
uiLayoutSetActive(col, RNA_boolean_get(ptr, "use_zbuffer") == true);
- uiItemR(col, ptr, "f_stop", 0, NULL, ICON_NONE);
+ uiItemR(col, ptr, "f_stop", DEFAULT_FLAGS, NULL, ICON_NONE);
- uiItemR(layout, ptr, "blur_max", 0, NULL, ICON_NONE);
- uiItemR(layout, ptr, "threshold", 0, NULL, ICON_NONE);
+ uiItemR(layout, ptr, "blur_max", DEFAULT_FLAGS, NULL, ICON_NONE);
+ uiItemR(layout, ptr, "threshold", DEFAULT_FLAGS, NULL, ICON_NONE);
col = uiLayoutColumn(layout, false);
- uiItemR(col, ptr, "use_preview", 0, NULL, ICON_NONE);
+ uiItemR(col, ptr, "use_preview", DEFAULT_FLAGS, NULL, ICON_NONE);
uiTemplateID(layout, C, ptr, "scene", NULL, NULL, NULL, UI_TEMPLATE_ID_FILTER_ALL, false, NULL);
col = uiLayoutColumn(layout, false);
- uiItemR(col, ptr, "use_zbuffer", 0, NULL, ICON_NONE);
+ uiItemR(col, ptr, "use_zbuffer", DEFAULT_FLAGS, NULL, ICON_NONE);
sub = uiLayoutColumn(col, false);
uiLayoutSetActive(sub, RNA_boolean_get(ptr, "use_zbuffer") == false);
- uiItemR(sub, ptr, "z_scale", 0, NULL, ICON_NONE);
+ uiItemR(sub, ptr, "z_scale", DEFAULT_FLAGS, NULL, ICON_NONE);
}
/* qdn: glare node */
static void node_composit_buts_glare(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr)
{
- uiItemR(layout, ptr, "glare_type", 0, "", ICON_NONE);
- uiItemR(layout, ptr, "quality", 0, "", ICON_NONE);
+ uiItemR(layout, ptr, "glare_type", DEFAULT_FLAGS, "", ICON_NONE);
+ uiItemR(layout, ptr, "quality", DEFAULT_FLAGS, "", ICON_NONE);
if (RNA_enum_get(ptr, "glare_type") != 1) {
- uiItemR(layout, ptr, "iterations", 0, NULL, ICON_NONE);
+ uiItemR(layout, ptr, "iterations", DEFAULT_FLAGS, NULL, ICON_NONE);
if (RNA_enum_get(ptr, "glare_type") != 0) {
- uiItemR(layout, ptr, "color_modulation", UI_ITEM_R_SLIDER, NULL, ICON_NONE);
+ uiItemR(layout, ptr, "color_modulation", DEFAULT_FLAGS | UI_ITEM_R_SLIDER, NULL, ICON_NONE);
}
}
- uiItemR(layout, ptr, "mix", 0, NULL, ICON_NONE);
- uiItemR(layout, ptr, "threshold", 0, NULL, ICON_NONE);
+ uiItemR(layout, ptr, "mix", DEFAULT_FLAGS, NULL, ICON_NONE);
+ uiItemR(layout, ptr, "threshold", DEFAULT_FLAGS, NULL, ICON_NONE);
if (RNA_enum_get(ptr, "glare_type") == 2) {
- uiItemR(layout, ptr, "streaks", 0, NULL, ICON_NONE);
- uiItemR(layout, ptr, "angle_offset", 0, NULL, ICON_NONE);
+ uiItemR(layout, ptr, "streaks", DEFAULT_FLAGS, NULL, ICON_NONE);
+ uiItemR(layout, ptr, "angle_offset", DEFAULT_FLAGS, NULL, ICON_NONE);
}
if (RNA_enum_get(ptr, "glare_type") == 0 || RNA_enum_get(ptr, "glare_type") == 2) {
- uiItemR(layout, ptr, "fade", UI_ITEM_R_SLIDER, NULL, ICON_NONE);
+ uiItemR(layout, ptr, "fade", DEFAULT_FLAGS | UI_ITEM_R_SLIDER, NULL, ICON_NONE);
if (RNA_enum_get(ptr, "glare_type") == 0) {
- uiItemR(layout, ptr, "use_rotate_45", 0, NULL, ICON_NONE);
+ uiItemR(layout, ptr, "use_rotate_45", DEFAULT_FLAGS, NULL, ICON_NONE);
}
}
if (RNA_enum_get(ptr, "glare_type") == 1) {
- uiItemR(layout, ptr, "size", 0, NULL, ICON_NONE);
+ uiItemR(layout, ptr, "size", DEFAULT_FLAGS, NULL, ICON_NONE);
}
}
@@ -1578,17 +1582,17 @@ static void node_composit_buts_tonemap(uiLayout *layout, bContext *UNUSED(C), Po
uiLayout *col;
col = uiLayoutColumn(layout, false);
- uiItemR(col, ptr, "tonemap_type", 0, "", ICON_NONE);
+ uiItemR(col, ptr, "tonemap_type", DEFAULT_FLAGS, "", ICON_NONE);
if (RNA_enum_get(ptr, "tonemap_type") == 0) {
- uiItemR(col, ptr, "key", UI_ITEM_R_SLIDER, NULL, ICON_NONE);
- uiItemR(col, ptr, "offset", 0, NULL, ICON_NONE);
- uiItemR(col, ptr, "gamma", 0, NULL, ICON_NONE);
+ uiItemR(col, ptr, "key", DEFAULT_FLAGS | UI_ITEM_R_SLIDER, NULL, ICON_NONE);
+ uiItemR(col, ptr, "offset", DEFAULT_FLAGS, NULL, ICON_NONE);
+ uiItemR(col, ptr, "gamma", DEFAULT_FLAGS, NULL, ICON_NONE);
}
else {
- uiItemR(col, ptr, "intensity", 0, NULL, ICON_NONE);
- uiItemR(col, ptr, "contrast", UI_ITEM_R_SLIDER, NULL, ICON_NONE);
- uiItemR(col, ptr, "adaptation", UI_ITEM_R_SLIDER, NULL, ICON_NONE);
- uiItemR(col, ptr, "correction", UI_ITEM_R_SLIDER, NULL, ICON_NONE);
+ uiItemR(col, ptr, "intensity", DEFAULT_FLAGS, NULL, ICON_NONE);
+ uiItemR(col, ptr, "contrast", DEFAULT_FLAGS | UI_ITEM_R_SLIDER, NULL, ICON_NONE);
+ uiItemR(col, ptr, "adaptation", DEFAULT_FLAGS | UI_ITEM_R_SLIDER, NULL, ICON_NONE);
+ uiItemR(col, ptr, "correction", DEFAULT_FLAGS | UI_ITEM_R_SLIDER, NULL, ICON_NONE);
}
}
@@ -1597,12 +1601,12 @@ static void node_composit_buts_lensdist(uiLayout *layout, bContext *UNUSED(C), P
uiLayout *col;
col = uiLayoutColumn(layout, false);
- uiItemR(col, ptr, "use_projector", 0, NULL, ICON_NONE);
+ uiItemR(col, ptr, "use_projector", DEFAULT_FLAGS, NULL, ICON_NONE);
col = uiLayoutColumn(col, false);
uiLayoutSetActive(col, RNA_boolean_get(ptr, "use_projector") == false);
- uiItemR(col, ptr, "use_jitter", 0, NULL, ICON_NONE);
- uiItemR(col, ptr, "use_fit", 0, NULL, ICON_NONE);
+ uiItemR(col, ptr, "use_jitter", DEFAULT_FLAGS, NULL, ICON_NONE);
+ uiItemR(col, ptr, "use_fit", DEFAULT_FLAGS, NULL, ICON_NONE);
}
static void node_composit_buts_vecblur(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr)
@@ -1610,46 +1614,46 @@ static void node_composit_buts_vecblur(uiLayout *layout, bContext *UNUSED(C), Po
uiLayout *col;
col = uiLayoutColumn(layout, false);
- uiItemR(col, ptr, "samples", 0, NULL, ICON_NONE);
- uiItemR(col, ptr, "factor", 0, IFACE_("Blur"), ICON_NONE);
+ uiItemR(col, ptr, "samples", DEFAULT_FLAGS, NULL, ICON_NONE);
+ uiItemR(col, ptr, "factor", DEFAULT_FLAGS, IFACE_("Blur"), ICON_NONE);
col = uiLayoutColumn(layout, true);
uiItemL(col, IFACE_("Speed:"), ICON_NONE);
- uiItemR(col, ptr, "speed_min", 0, IFACE_("Min"), ICON_NONE);
- uiItemR(col, ptr, "speed_max", 0, IFACE_("Max"), ICON_NONE);
+ uiItemR(col, ptr, "speed_min", DEFAULT_FLAGS, IFACE_("Min"), ICON_NONE);
+ uiItemR(col, ptr, "speed_max", DEFAULT_FLAGS, IFACE_("Max"), ICON_NONE);
- uiItemR(layout, ptr, "use_curved", 0, NULL, ICON_NONE);
+ uiItemR(layout, ptr, "use_curved", DEFAULT_FLAGS, NULL, ICON_NONE);
}
static void node_composit_buts_filter(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr)
{
- uiItemR(layout, ptr, "filter_type", 0, "", ICON_NONE);
+ uiItemR(layout, ptr, "filter_type", DEFAULT_FLAGS, "", ICON_NONE);
}
static void node_composit_buts_flip(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr)
{
- uiItemR(layout, ptr, "axis", 0, "", ICON_NONE);
+ uiItemR(layout, ptr, "axis", DEFAULT_FLAGS, "", ICON_NONE);
}
static void node_composit_buts_crop(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr)
{
uiLayout *col;
- uiItemR(layout, ptr, "use_crop_size", 0, NULL, ICON_NONE);
- uiItemR(layout, ptr, "relative", 0, NULL, ICON_NONE);
+ uiItemR(layout, ptr, "use_crop_size", DEFAULT_FLAGS, NULL, ICON_NONE);
+ uiItemR(layout, ptr, "relative", DEFAULT_FLAGS, NULL, ICON_NONE);
col = uiLayoutColumn(layout, true);
if (RNA_boolean_get(ptr, "relative")) {
- uiItemR(col, ptr, "rel_min_x", 0, IFACE_("Left"), ICON_NONE);
- uiItemR(col, ptr, "rel_max_x", 0, IFACE_("Right"), ICON_NONE);
- uiItemR(col, ptr, "rel_min_y", 0, IFACE_("Up"), ICON_NONE);
- uiItemR(col, ptr, "rel_max_y", 0, IFACE_("Down"), ICON_NONE);
+ uiItemR(col, ptr, "rel_min_x", DEFAULT_FLAGS, IFACE_("Left"), ICON_NONE);
+ uiItemR(col, ptr, "rel_max_x", DEFAULT_FLAGS, IFACE_("Right"), ICON_NONE);
+ uiItemR(col, ptr, "rel_min_y", DEFAULT_FLAGS, IFACE_("Up"), ICON_NONE);
+ uiItemR(col, ptr, "rel_max_y", DEFAULT_FLAGS, IFACE_("Down"), ICON_NONE);
}
else {
- uiItemR(col, ptr, "min_x", 0, IFACE_("Left"), ICON_NONE);
- uiItemR(col, ptr, "max_x", 0, IFACE_("Right"), ICON_NONE);
- uiItemR(col, ptr, "min_y", 0, IFACE_("Up"), ICON_NONE);
- uiItemR(col, ptr, "max_y", 0, IFACE_("Down"), ICON_NONE);
+ uiItemR(col, ptr, "min_x", DEFAULT_FLAGS, IFACE_("Left"), ICON_NONE);
+ uiItemR(col, ptr, "max_x", DEFAULT_FLAGS, IFACE_("Right"), ICON_NONE);
+ uiItemR(col, ptr, "min_y", DEFAULT_FLAGS, IFACE_("Up"), ICON_NONE);
+ uiItemR(col, ptr, "max_y", DEFAULT_FLAGS, IFACE_("Down"), ICON_NONE);
}
}
@@ -1659,8 +1663,8 @@ static void node_composit_buts_splitviewer(uiLayout *layout, bContext *UNUSED(C)
col = uiLayoutColumn(layout, false);
row = uiLayoutRow(col, false);
- uiItemR(row, ptr, "axis", UI_ITEM_R_EXPAND, NULL, ICON_NONE);
- uiItemR(col, ptr, "factor", 0, NULL, ICON_NONE);
+ uiItemR(row, ptr, "axis", DEFAULT_FLAGS | UI_ITEM_R_EXPAND, NULL, ICON_NONE);
+ uiItemR(col, ptr, "factor", DEFAULT_FLAGS, NULL, ICON_NONE);
}
static void node_composit_buts_double_edge_mask(uiLayout *layout,
@@ -1672,9 +1676,9 @@ static void node_composit_buts_double_edge_mask(uiLayout *layout,
col = uiLayoutColumn(layout, false);
uiItemL(col, IFACE_("Inner Edge:"), ICON_NONE);
- uiItemR(col, ptr, "inner_mode", 0, "", ICON_NONE);
+ uiItemR(col, ptr, "inner_mode", DEFAULT_FLAGS, "", ICON_NONE);
uiItemL(col, IFACE_("Buffer Edge:"), ICON_NONE);
- uiItemR(col, ptr, "edge_mode", 0, "", ICON_NONE);
+ uiItemR(col, ptr, "edge_mode", DEFAULT_FLAGS, "", ICON_NONE);
}
static void node_composit_buts_map_range(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr)
@@ -1682,7 +1686,7 @@ static void node_composit_buts_map_range(uiLayout *layout, bContext *UNUSED(C),
uiLayout *col;
col = uiLayoutColumn(layout, true);
- uiItemR(col, ptr, "use_clamp", 0, NULL, ICON_NONE);
+ uiItemR(col, ptr, "use_clamp", DEFAULT_FLAGS, NULL, ICON_NONE);
}
static void node_composit_buts_map_value(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr)
@@ -1690,20 +1694,20 @@ static void node_composit_buts_map_value(uiLayout *layout, bContext *UNUSED(C),
uiLayout *sub, *col;
col = uiLayoutColumn(layout, true);
- uiItemR(col, ptr, "offset", 0, NULL, ICON_NONE);
- uiItemR(col, ptr, "size", 0, NULL, ICON_NONE);
+ uiItemR(col, ptr, "offset", DEFAULT_FLAGS, NULL, ICON_NONE);
+ uiItemR(col, ptr, "size", DEFAULT_FLAGS, NULL, ICON_NONE);
col = uiLayoutColumn(layout, true);
- uiItemR(col, ptr, "use_min", 0, NULL, ICON_NONE);
+ uiItemR(col, ptr, "use_min", DEFAULT_FLAGS, NULL, ICON_NONE);
sub = uiLayoutColumn(col, false);
uiLayoutSetActive(sub, RNA_boolean_get(ptr, "use_min"));
- uiItemR(sub, ptr, "min", 0, "", ICON_NONE);
+ uiItemR(sub, ptr, "min", DEFAULT_FLAGS, "", ICON_NONE);
col = uiLayoutColumn(layout, true);
- uiItemR(col, ptr, "use_max", 0, NULL, ICON_NONE);
+ uiItemR(col, ptr, "use_max", DEFAULT_FLAGS, NULL, ICON_NONE);
sub = uiLayoutColumn(col, false);
uiLayoutSetActive(sub, RNA_boolean_get(ptr, "use_max"));
- uiItemR(sub, ptr, "max", 0, "", ICON_NONE);
+ uiItemR(sub, ptr, "max", DEFAULT_FLAGS, "", ICON_NONE);
}
static void node_composit_buts_alphaover(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr)
@@ -1711,8 +1715,8 @@ static void node_composit_buts_alphaover(uiLayout *layout, bContext *UNUSED(C),
uiLayout *col;
col = uiLayoutColumn(layout, true);
- uiItemR(col, ptr, "use_premultiply", 0, NULL, ICON_NONE);
- uiItemR(col, ptr, "premul", 0, NULL, ICON_NONE);
+ uiItemR(col, ptr, "use_premultiply", DEFAULT_FLAGS, NULL, ICON_NONE);
+ uiItemR(col, ptr, "premul", DEFAULT_FLAGS, NULL, ICON_NONE);
}
static void node_composit_buts_zcombine(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr)
@@ -1720,27 +1724,27 @@ static void node_composit_buts_zcombine(uiLayout *layout, bContext *UNUSED(C), P
uiLayout *col;
col = uiLayoutColumn(layout, true);
- uiItemR(col, ptr, "use_alpha", 0, NULL, ICON_NONE);
- uiItemR(col, ptr, "use_antialias_z", 0, NULL, ICON_NONE);
+ uiItemR(col, ptr, "use_alpha", DEFAULT_FLAGS, NULL, ICON_NONE);
+ uiItemR(col, ptr, "use_antialias_z", DEFAULT_FLAGS, NULL, ICON_NONE);
}
static void node_composit_buts_dilateerode(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr)
{
- uiItemR(layout, ptr, "mode", 0, NULL, ICON_NONE);
- uiItemR(layout, ptr, "distance", 0, NULL, ICON_NONE);
+ uiItemR(layout, ptr, "mode", DEFAULT_FLAGS, NULL, ICON_NONE);
+ uiItemR(layout, ptr, "distance", DEFAULT_FLAGS, NULL, ICON_NONE);
switch (RNA_enum_get(ptr, "mode")) {
case CMP_NODE_DILATEERODE_DISTANCE_THRESH:
- uiItemR(layout, ptr, "edge", 0, NULL, ICON_NONE);
+ uiItemR(layout, ptr, "edge", DEFAULT_FLAGS, NULL, ICON_NONE);
break;
case CMP_NODE_DILATEERODE_DISTANCE_FEATHER:
- uiItemR(layout, ptr, "falloff", 0, NULL, ICON_NONE);
+ uiItemR(layout, ptr, "falloff", DEFAULT_FLAGS, NULL, ICON_NONE);
break;
}
}
static void node_composit_buts_inpaint(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr)
{
- uiItemR(layout, ptr, "distance", 0, NULL, ICON_NONE);
+ uiItemR(layout, ptr, "distance", DEFAULT_FLAGS, NULL, ICON_NONE);
}
static void node_composit_buts_despeckle(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr)
@@ -1748,8 +1752,8 @@ static void node_composit_buts_despeckle(uiLayout *layout, bContext *UNUSED(C),
uiLayout *col;
col = uiLayoutColumn(layout, false);
- uiItemR(col, ptr, "threshold", 0, NULL, ICON_NONE);
- uiItemR(col, ptr, "threshold_neighbor", 0, NULL, ICON_NONE);
+ uiItemR(col, ptr, "threshold", DEFAULT_FLAGS, NULL, ICON_NONE);
+ uiItemR(col, ptr, "threshold_neighbor", DEFAULT_FLAGS, NULL, ICON_NONE);
}
static void node_composit_buts_diff_matte(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr)
@@ -1757,8 +1761,8 @@ static void node_composit_buts_diff_matte(uiLayout *layout, bContext *UNUSED(C),
uiLayout *col;
col = uiLayoutColumn(layout, true);
- uiItemR(col, ptr, "tolerance", UI_ITEM_R_SLIDER, NULL, ICON_NONE);
- uiItemR(col, ptr, "falloff", UI_ITEM_R_SLIDER, NULL, ICON_NONE);
+ uiItemR(col, ptr, "tolerance", DEFAULT_FLAGS | UI_ITEM_R_SLIDER, NULL, ICON_NONE);
+ uiItemR(col, ptr, "falloff", DEFAULT_FLAGS | UI_ITEM_R_SLIDER, NULL, ICON_NONE);
}
static void node_composit_buts_distance_matte(uiLayout *layout,
@@ -1771,10 +1775,10 @@ static void node_composit_buts_distance_matte(uiLayout *layout,
uiItemL(layout, IFACE_("Color Space:"), ICON_NONE);
row = uiLayoutRow(layout, false);
- uiItemR(row, ptr, "channel", UI_ITEM_R_EXPAND, NULL, ICON_NONE);
+ uiItemR(row, ptr, "channel", DEFAULT_FLAGS | UI_ITEM_R_EXPAND, NULL, ICON_NONE);
- uiItemR(col, ptr, "tolerance", UI_ITEM_R_SLIDER, NULL, ICON_NONE);
- uiItemR(col, ptr, "falloff", UI_ITEM_R_SLIDER, NULL, ICON_NONE);
+ uiItemR(col, ptr, "tolerance", DEFAULT_FLAGS | UI_ITEM_R_SLIDER, NULL, ICON_NONE);
+ uiItemR(col, ptr, "falloff", DEFAULT_FLAGS | UI_ITEM_R_SLIDER, NULL, ICON_NONE);
}
static void node_composit_buts_color_spill(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr)
@@ -1783,23 +1787,23 @@ static void node_composit_buts_color_spill(uiLayout *layout, bContext *UNUSED(C)
uiItemL(layout, IFACE_("Despill Channel:"), ICON_NONE);
row = uiLayoutRow(layout, false);
- uiItemR(row, ptr, "channel", UI_ITEM_R_EXPAND, NULL, ICON_NONE);
+ uiItemR(row, ptr, "channel", DEFAULT_FLAGS | UI_ITEM_R_EXPAND, NULL, ICON_NONE);
col = uiLayoutColumn(layout, false);
- uiItemR(col, ptr, "limit_method", 0, NULL, ICON_NONE);
+ uiItemR(col, ptr, "limit_method", DEFAULT_FLAGS, NULL, ICON_NONE);
if (RNA_enum_get(ptr, "limit_method") == 0) {
uiItemL(col, IFACE_("Limiting Channel:"), ICON_NONE);
row = uiLayoutRow(col, false);
- uiItemR(row, ptr, "limit_channel", UI_ITEM_R_EXPAND, NULL, ICON_NONE);
+ uiItemR(row, ptr, "limit_channel", DEFAULT_FLAGS | UI_ITEM_R_EXPAND, NULL, ICON_NONE);
}
- uiItemR(col, ptr, "ratio", UI_ITEM_R_SLIDER, NULL, ICON_NONE);
- uiItemR(col, ptr, "use_unspill", 0, NULL, ICON_NONE);
+ uiItemR(col, ptr, "ratio", DEFAULT_FLAGS | UI_ITEM_R_SLIDER, NULL, ICON_NONE);
+ uiItemR(col, ptr, "use_unspill", DEFAULT_FLAGS, NULL, ICON_NONE);
if (RNA_boolean_get(ptr, "use_unspill") == true) {
- uiItemR(col, ptr, "unspill_red", UI_ITEM_R_SLIDER, NULL, ICON_NONE);
- uiItemR(col, ptr, "unspill_green", UI_ITEM_R_SLIDER, NULL, ICON_NONE);
- uiItemR(col, ptr, "unspill_blue", UI_ITEM_R_SLIDER, NULL, ICON_NONE);
+ uiItemR(col, ptr, "unspill_red", DEFAULT_FLAGS | UI_ITEM_R_SLIDER, NULL, ICON_NONE);
+ uiItemR(col, ptr, "unspill_green", DEFAULT_FLAGS | UI_ITEM_R_SLIDER, NULL, ICON_NONE);
+ uiItemR(col, ptr, "unspill_blue", DEFAULT_FLAGS | UI_ITEM_R_SLIDER, NULL, ICON_NONE);
}
}
@@ -1808,12 +1812,12 @@ static void node_composit_buts_chroma_matte(uiLayout *layout, bContext *UNUSED(C
uiLayout *col;
col = uiLayoutColumn(layout, false);
- uiItemR(col, ptr, "tolerance", 0, NULL, ICON_NONE);
- uiItemR(col, ptr, "threshold", 0, NULL, ICON_NONE);
+ uiItemR(col, ptr, "tolerance", DEFAULT_FLAGS, NULL, ICON_NONE);
+ uiItemR(col, ptr, "threshold", DEFAULT_FLAGS, NULL, ICON_NONE);
col = uiLayoutColumn(layout, true);
/*uiItemR(col, ptr, "lift", UI_ITEM_R_SLIDER, NULL, ICON_NONE); Removed for now */
- uiItemR(col, ptr, "gain", UI_ITEM_R_SLIDER, NULL, ICON_NONE);
+ uiItemR(col, ptr, "gain", DEFAULT_FLAGS | UI_ITEM_R_SLIDER, NULL, ICON_NONE);
/*uiItemR(col, ptr, "shadow_adjust", UI_ITEM_R_SLIDER, NULL, ICON_NONE); Removed for now*/
}
@@ -1822,9 +1826,9 @@ static void node_composit_buts_color_matte(uiLayout *layout, bContext *UNUSED(C)
uiLayout *col;
col = uiLayoutColumn(layout, true);
- uiItemR(col, ptr, "color_hue", UI_ITEM_R_SLIDER, NULL, ICON_NONE);
- uiItemR(col, ptr, "color_saturation", UI_ITEM_R_SLIDER, NULL, ICON_NONE);
- uiItemR(col, ptr, "color_value", UI_ITEM_R_SLIDER, NULL, ICON_NONE);
+ uiItemR(col, ptr, "color_hue", DEFAULT_FLAGS | UI_ITEM_R_SLIDER, NULL, ICON_NONE);
+ uiItemR(col, ptr, "color_saturation", DEFAULT_FLAGS | UI_ITEM_R_SLIDER, NULL, ICON_NONE);
+ uiItemR(col, ptr, "color_value", DEFAULT_FLAGS | UI_ITEM_R_SLIDER, NULL, ICON_NONE);
}
static void node_composit_buts_channel_matte(uiLayout *layout,
@@ -1835,24 +1839,24 @@ static void node_composit_buts_channel_matte(uiLayout *layout,
uiItemL(layout, IFACE_("Color Space:"), ICON_NONE);
row = uiLayoutRow(layout, false);
- uiItemR(row, ptr, "color_space", UI_ITEM_R_EXPAND, NULL, ICON_NONE);
+ uiItemR(row, ptr, "color_space", DEFAULT_FLAGS | UI_ITEM_R_EXPAND, NULL, ICON_NONE);
col = uiLayoutColumn(layout, false);
uiItemL(col, IFACE_("Key Channel:"), ICON_NONE);
row = uiLayoutRow(col, false);
- uiItemR(row, ptr, "matte_channel", UI_ITEM_R_EXPAND, NULL, ICON_NONE);
+ uiItemR(row, ptr, "matte_channel", DEFAULT_FLAGS | UI_ITEM_R_EXPAND, NULL, ICON_NONE);
col = uiLayoutColumn(layout, false);
- uiItemR(col, ptr, "limit_method", 0, NULL, ICON_NONE);
+ uiItemR(col, ptr, "limit_method", DEFAULT_FLAGS, NULL, ICON_NONE);
if (RNA_enum_get(ptr, "limit_method") == 0) {
uiItemL(col, IFACE_("Limiting Channel:"), ICON_NONE);
row = uiLayoutRow(col, false);
- uiItemR(row, ptr, "limit_channel", UI_ITEM_R_EXPAND, NULL, ICON_NONE);
+ uiItemR(row, ptr, "limit_channel", DEFAULT_FLAGS | UI_ITEM_R_EXPAND, NULL, ICON_NONE);
}
- uiItemR(col, ptr, "limit_max", UI_ITEM_R_SLIDER, NULL, ICON_NONE);
- uiItemR(col, ptr, "limit_min", UI_ITEM_R_SLIDER, NULL, ICON_NONE);
+ uiItemR(col, ptr, "limit_max", DEFAULT_FLAGS | UI_ITEM_R_SLIDER, NULL, ICON_NONE);
+ uiItemR(col, ptr, "limit_min", DEFAULT_FLAGS | UI_ITEM_R_SLIDER, NULL, ICON_NONE);
}
static void node_composit_buts_luma_matte(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr)
@@ -1860,19 +1864,19 @@ static void node_composit_buts_luma_matte(uiLayout *layout, bContext *UNUSED(C),
uiLayout *col;
col = uiLayoutColumn(layout, true);
- uiItemR(col, ptr, "limit_max", UI_ITEM_R_SLIDER, NULL, ICON_NONE);
- uiItemR(col, ptr, "limit_min", UI_ITEM_R_SLIDER, NULL, ICON_NONE);
+ uiItemR(col, ptr, "limit_max", DEFAULT_FLAGS | UI_ITEM_R_SLIDER, NULL, ICON_NONE);
+ uiItemR(col, ptr, "limit_min", DEFAULT_FLAGS | UI_ITEM_R_SLIDER, NULL, ICON_NONE);
}
static void node_composit_buts_map_uv(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr)
{
- uiItemR(layout, ptr, "alpha", 0, NULL, ICON_NONE);
+ uiItemR(layout, ptr, "alpha", DEFAULT_FLAGS, NULL, ICON_NONE);
}
static void node_composit_buts_id_mask(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr)
{
- uiItemR(layout, ptr, "index", 0, NULL, ICON_NONE);
- uiItemR(layout, ptr, "use_antialiasing", 0, NULL, ICON_NONE);
+ uiItemR(layout, ptr, "index", DEFAULT_FLAGS, NULL, ICON_NONE);
+ uiItemR(layout, ptr, "use_antialiasing", DEFAULT_FLAGS, NULL, ICON_NONE);
}
static void node_composit_buts_file_output(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr)
@@ -1886,7 +1890,7 @@ static void node_composit_buts_file_output(uiLayout *layout, bContext *UNUSED(C)
else {
uiItemL(layout, IFACE_("Base Path:"), ICON_NONE);
}
- uiItemR(layout, ptr, "base_path", 0, "", ICON_NONE);
+ uiItemR(layout, ptr, "base_path", DEFAULT_FLAGS, "", ICON_NONE);
}
static void node_composit_buts_file_output_ex(uiLayout *layout, bContext *C, PointerRNA *ptr)
{
@@ -1972,7 +1976,7 @@ static void node_composit_buts_file_output_ex(uiLayout *layout, bContext *C, Poi
uiItemL(col, IFACE_("Layer:"), ICON_NONE);
row = uiLayoutRow(col, false);
- uiItemR(row, &active_input_ptr, "name", 0, "", ICON_NONE);
+ uiItemR(row, &active_input_ptr, "name", DEFAULT_FLAGS, "", ICON_NONE);
uiItemFullO(row,
"NODE_OT_output_file_remove_active_socket",
"",
@@ -1987,7 +1991,7 @@ static void node_composit_buts_file_output_ex(uiLayout *layout, bContext *C, Poi
uiItemL(col, IFACE_("File Subpath:"), ICON_NONE);
row = uiLayoutRow(col, false);
- uiItemR(row, &active_input_ptr, "path", 0, "", ICON_NONE);
+ uiItemR(row, &active_input_ptr, "path", DEFAULT_FLAGS, "", ICON_NONE);
uiItemFullO(row,
"NODE_OT_output_file_remove_active_socket",
"",
@@ -2002,7 +2006,7 @@ static void node_composit_buts_file_output_ex(uiLayout *layout, bContext *C, Poi
col = uiLayoutColumn(layout, true);
uiItemL(col, IFACE_("Format:"), ICON_NONE);
- uiItemR(col, &active_input_ptr, "use_node_format", 0, NULL, ICON_NONE);
+ uiItemR(col, &active_input_ptr, "use_node_format", DEFAULT_FLAGS, NULL, ICON_NONE);
col = uiLayoutColumn(layout, false);
uiLayoutSetActive(col, RNA_boolean_get(&active_input_ptr, "use_node_format") == false);
@@ -2017,20 +2021,20 @@ static void node_composit_buts_file_output_ex(uiLayout *layout, bContext *C, Poi
static void node_composit_buts_scale(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr)
{
- uiItemR(layout, ptr, "space", 0, "", ICON_NONE);
+ uiItemR(layout, ptr, "space", DEFAULT_FLAGS, "", ICON_NONE);
if (RNA_enum_get(ptr, "space") == CMP_SCALE_RENDERPERCENT) {
uiLayout *row;
- uiItemR(layout, ptr, "frame_method", UI_ITEM_R_EXPAND, NULL, ICON_NONE);
+ uiItemR(layout, ptr, "frame_method", DEFAULT_FLAGS | UI_ITEM_R_EXPAND, NULL, ICON_NONE);
row = uiLayoutRow(layout, true);
- uiItemR(row, ptr, "offset_x", 0, "X", ICON_NONE);
- uiItemR(row, ptr, "offset_y", 0, "Y", ICON_NONE);
+ uiItemR(row, ptr, "offset_x", DEFAULT_FLAGS, "X", ICON_NONE);
+ uiItemR(row, ptr, "offset_y", DEFAULT_FLAGS, "Y", ICON_NONE);
}
}
static void node_composit_buts_rotate(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr)
{
- uiItemR(layout, ptr, "filter_type", 0, "", ICON_NONE);
+ uiItemR(layout, ptr, "filter_type", DEFAULT_FLAGS, "", ICON_NONE);
}
static void node_composit_buts_invert(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr)
@@ -2038,25 +2042,25 @@ static void node_composit_buts_invert(uiLayout *layout, bContext *UNUSED(C), Poi
uiLayout *col;
col = uiLayoutColumn(layout, false);
- uiItemR(col, ptr, "invert_rgb", 0, NULL, ICON_NONE);
- uiItemR(col, ptr, "invert_alpha", 0, NULL, ICON_NONE);
+ uiItemR(col, ptr, "invert_rgb", DEFAULT_FLAGS, NULL, ICON_NONE);
+ uiItemR(col, ptr, "invert_alpha", DEFAULT_FLAGS, NULL, ICON_NONE);
}
static void node_composit_buts_premulkey(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr)
{
- uiItemR(layout, ptr, "mapping", 0, "", ICON_NONE);
+ uiItemR(layout, ptr, "mapping", DEFAULT_FLAGS, "", ICON_NONE);
}
static void node_composit_buts_view_levels(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr)
{
- uiItemR(layout, ptr, "channel", UI_ITEM_R_EXPAND, NULL, ICON_NONE);
+ uiItemR(layout, ptr, "channel", DEFAULT_FLAGS | UI_ITEM_R_EXPAND, NULL, ICON_NONE);
}
static void node_composit_buts_colorbalance(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr)
{
uiLayout *split, *col, *row;
- uiItemR(layout, ptr, "correction_method", 0, NULL, ICON_NONE);
+ uiItemR(layout, ptr, "correction_method", DEFAULT_FLAGS, NULL, ICON_NONE);
if (RNA_enum_get(ptr, "correction_method") == 0) {
@@ -2064,17 +2068,17 @@ static void node_composit_buts_colorbalance(uiLayout *layout, bContext *UNUSED(C
col = uiLayoutColumn(split, false);
uiTemplateColorPicker(col, ptr, "lift", 1, 1, 0, 1);
row = uiLayoutRow(col, false);
- uiItemR(row, ptr, "lift", 0, NULL, ICON_NONE);
+ uiItemR(row, ptr, "lift", DEFAULT_FLAGS, NULL, ICON_NONE);
col = uiLayoutColumn(split, false);
uiTemplateColorPicker(col, ptr, "gamma", 1, 1, 1, 1);
row = uiLayoutRow(col, false);
- uiItemR(row, ptr, "gamma", 0, NULL, ICON_NONE);
+ uiItemR(row, ptr, "gamma", DEFAULT_FLAGS, NULL, ICON_NONE);
col = uiLayoutColumn(split, false);
uiTemplateColorPicker(col, ptr, "gain", 1, 1, 1, 1);
row = uiLayoutRow(col, false);
- uiItemR(row, ptr, "gain", 0, NULL, ICON_NONE);
+ uiItemR(row, ptr, "gain", DEFAULT_FLAGS, NULL, ICON_NONE);
}
else {
@@ -2082,46 +2086,46 @@ static void node_composit_buts_colorbalance(uiLayout *layout, bContext *UNUSED(C
col = uiLayoutColumn(split, false);
uiTemplateColorPicker(col, ptr, "offset", 1, 1, 0, 1);
row = uiLayoutRow(col, false);
- uiItemR(row, ptr, "offset", 0, NULL, ICON_NONE);
- uiItemR(col, ptr, "offset_basis", 0, NULL, ICON_NONE);
+ uiItemR(row, ptr, "offset", DEFAULT_FLAGS, NULL, ICON_NONE);
+ uiItemR(col, ptr, "offset_basis", DEFAULT_FLAGS, NULL, ICON_NONE);
col = uiLayoutColumn(split, false);
uiTemplateColorPicker(col, ptr, "power", 1, 1, 0, 1);
row = uiLayoutRow(col, false);
- uiItemR(row, ptr, "power", 0, NULL, ICON_NONE);
+ uiItemR(row, ptr, "power", DEFAULT_FLAGS, NULL, ICON_NONE);
col = uiLayoutColumn(split, false);
uiTemplateColorPicker(col, ptr, "slope", 1, 1, 0, 1);
row = uiLayoutRow(col, false);
- uiItemR(row, ptr, "slope", 0, NULL, ICON_NONE);
+ uiItemR(row, ptr, "slope", DEFAULT_FLAGS, NULL, ICON_NONE);
}
}
static void node_composit_buts_colorbalance_ex(uiLayout *layout,
bContext *UNUSED(C),
PointerRNA *ptr)
{
- uiItemR(layout, ptr, "correction_method", 0, NULL, ICON_NONE);
+ uiItemR(layout, ptr, "correction_method", DEFAULT_FLAGS, NULL, ICON_NONE);
if (RNA_enum_get(ptr, "correction_method") == 0) {
uiTemplateColorPicker(layout, ptr, "lift", 1, 1, 0, 1);
- uiItemR(layout, ptr, "lift", 0, NULL, ICON_NONE);
+ uiItemR(layout, ptr, "lift", DEFAULT_FLAGS, NULL, ICON_NONE);
uiTemplateColorPicker(layout, ptr, "gamma", 1, 1, 1, 1);
- uiItemR(layout, ptr, "gamma", 0, NULL, ICON_NONE);
+ uiItemR(layout, ptr, "gamma", DEFAULT_FLAGS, NULL, ICON_NONE);
uiTemplateColorPicker(layout, ptr, "gain", 1, 1, 1, 1);
- uiItemR(layout, ptr, "gain", 0, NULL, ICON_NONE);
+ uiItemR(layout, ptr, "gain", DEFAULT_FLAGS, NULL, ICON_NONE);
}
else {
uiTemplateColorPicker(layout, ptr, "offset", 1, 1, 0, 1);
- uiItemR(layout, ptr, "offset", 0, NULL, ICON_NONE);
+ uiItemR(layout, ptr, "offset", DEFAULT_FLAGS, NULL, ICON_NONE);
uiTemplateColorPicker(layout, ptr, "power", 1, 1, 0, 1);
- uiItemR(layout, ptr, "power", 0, NULL, ICON_NONE);
+ uiItemR(layout, ptr, "power", DEFAULT_FLAGS, NULL, ICON_NONE);
uiTemplateColorPicker(layout, ptr, "slope", 1, 1, 0, 1);
- uiItemR(layout, ptr, "slope", 0, NULL, ICON_NONE);
+ uiItemR(layout, ptr, "slope", DEFAULT_FLAGS, NULL, ICON_NONE);
}
}
@@ -2143,7 +2147,7 @@ static void node_composit_buts_huecorrect(uiLayout *layout, bContext *UNUSED(C),
static void node_composit_buts_ycc(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr)
{
- uiItemR(layout, ptr, "mode", 0, "", ICON_NONE);
+ uiItemR(layout, ptr, "mode", DEFAULT_FLAGS, "", ICON_NONE);
}
static void node_composit_buts_movieclip(uiLayout *layout, bContext *C, PointerRNA *ptr)
@@ -2180,19 +2184,19 @@ static void node_composit_buts_stabilize2d(uiLayout *layout, bContext *C, Pointe
return;
}
- uiItemR(layout, ptr, "filter_type", 0, "", ICON_NONE);
- uiItemR(layout, ptr, "invert", 0, NULL, ICON_NONE);
+ uiItemR(layout, ptr, "filter_type", DEFAULT_FLAGS, "", ICON_NONE);
+ uiItemR(layout, ptr, "invert", DEFAULT_FLAGS, NULL, ICON_NONE);
}
static void node_composit_buts_translate(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr)
{
- uiItemR(layout, ptr, "use_relative", 0, NULL, ICON_NONE);
- uiItemR(layout, ptr, "wrap_axis", 0, NULL, ICON_NONE);
+ uiItemR(layout, ptr, "use_relative", DEFAULT_FLAGS, NULL, ICON_NONE);
+ uiItemR(layout, ptr, "wrap_axis", DEFAULT_FLAGS, NULL, ICON_NONE);
}
static void node_composit_buts_transform(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr)
{
- uiItemR(layout, ptr, "filter_type", 0, "", ICON_NONE);
+ uiItemR(layout, ptr, "filter_type", DEFAULT_FLAGS, "", ICON_NONE);
}
static void node_composit_buts_moviedistortion(uiLayout *layout, bContext *C, PointerRNA *ptr)
@@ -2206,7 +2210,7 @@ static void node_composit_buts_moviedistortion(uiLayout *layout, bContext *C, Po
return;
}
- uiItemR(layout, ptr, "distortion_type", 0, "", ICON_NONE);
+ uiItemR(layout, ptr, "distortion_type", DEFAULT_FLAGS, "", ICON_NONE);
}
static void node_composit_buts_colorcorrection(uiLayout *layout,
@@ -2216,9 +2220,9 @@ static void node_composit_buts_colorcorrection(uiLayout *layout,
uiLayout *row;
row = uiLayoutRow(layout, false);
- uiItemR(row, ptr, "red", 0, NULL, ICON_NONE);
- uiItemR(row, ptr, "green", 0, NULL, ICON_NONE);
- uiItemR(row, ptr, "blue", 0, NULL, ICON_NONE);
+ uiItemR(row, ptr, "red", DEFAULT_FLAGS, NULL, ICON_NONE);
+ uiItemR(row, ptr, "green", DEFAULT_FLAGS, NULL, ICON_NONE);
+ uiItemR(row, ptr, "blue", DEFAULT_FLAGS, NULL, ICON_NONE);
row = uiLayoutRow(layout, false);
uiItemL(row, "", ICON_NONE);
@@ -2230,39 +2234,39 @@ static void node_composit_buts_colorcorrection(uiLayout *layout,
row = uiLayoutRow(layout, false);
uiItemL(row, IFACE_("Master"), ICON_NONE);
- uiItemR(row, ptr, "master_saturation", UI_ITEM_R_SLIDER, "", ICON_NONE);
- uiItemR(row, ptr, "master_contrast", UI_ITEM_R_SLIDER, "", ICON_NONE);
- uiItemR(row, ptr, "master_gamma", UI_ITEM_R_SLIDER, "", ICON_NONE);
- uiItemR(row, ptr, "master_gain", UI_ITEM_R_SLIDER, "", ICON_NONE);
- uiItemR(row, ptr, "master_lift", UI_ITEM_R_SLIDER, "", ICON_NONE);
+ uiItemR(row, ptr, "master_saturation", DEFAULT_FLAGS | UI_ITEM_R_SLIDER, "", ICON_NONE);
+ uiItemR(row, ptr, "master_contrast", DEFAULT_FLAGS | UI_ITEM_R_SLIDER, "", ICON_NONE);
+ uiItemR(row, ptr, "master_gamma", DEFAULT_FLAGS | UI_ITEM_R_SLIDER, "", ICON_NONE);
+ uiItemR(row, ptr, "master_gain", DEFAULT_FLAGS | UI_ITEM_R_SLIDER, "", ICON_NONE);
+ uiItemR(row, ptr, "master_lift", DEFAULT_FLAGS | UI_ITEM_R_SLIDER, "", ICON_NONE);
row = uiLayoutRow(layout, false);
uiItemL(row, IFACE_("Highlights"), ICON_NONE);
- uiItemR(row, ptr, "highlights_saturation", UI_ITEM_R_SLIDER, "", ICON_NONE);
- uiItemR(row, ptr, "highlights_contrast", UI_ITEM_R_SLIDER, "", ICON_NONE);
- uiItemR(row, ptr, "highlights_gamma", UI_ITEM_R_SLIDER, "", ICON_NONE);
- uiItemR(row, ptr, "highlights_gain", UI_ITEM_R_SLIDER, "", ICON_NONE);
- uiItemR(row, ptr, "highlights_lift", UI_ITEM_R_SLIDER, "", ICON_NONE);
+ uiItemR(row, ptr, "highlights_saturation", DEFAULT_FLAGS | UI_ITEM_R_SLIDER, "", ICON_NONE);
+ uiItemR(row, ptr, "highlights_contrast", DEFAULT_FLAGS | UI_ITEM_R_SLIDER, "", ICON_NONE);
+ uiItemR(row, ptr, "highlights_gamma", DEFAULT_FLAGS | UI_ITEM_R_SLIDER, "", ICON_NONE);
+ uiItemR(row, ptr, "highlights_gain", DEFAULT_FLAGS | UI_ITEM_R_SLIDER, "", ICON_NONE);
+ uiItemR(row, ptr, "highlights_lift", DEFAULT_FLAGS | UI_ITEM_R_SLIDER, "", ICON_NONE);
row = uiLayoutRow(layout, false);
uiItemL(row, IFACE_("Midtones"), ICON_NONE);
- uiItemR(row, ptr, "midtones_saturation", UI_ITEM_R_SLIDER, "", ICON_NONE);
- uiItemR(row, ptr, "midtones_contrast", UI_ITEM_R_SLIDER, "", ICON_NONE);
- uiItemR(row, ptr, "midtones_gamma", UI_ITEM_R_SLIDER, "", ICON_NONE);
- uiItemR(row, ptr, "midtones_gain", UI_ITEM_R_SLIDER, "", ICON_NONE);
- uiItemR(row, ptr, "midtones_lift", UI_ITEM_R_SLIDER, "", ICON_NONE);
+ uiItemR(row, ptr, "midtones_saturation", DEFAULT_FLAGS | UI_ITEM_R_SLIDER, "", ICON_NONE);
+ uiItemR(row, ptr, "midtones_contrast", DEFAULT_FLAGS | UI_ITEM_R_SLIDER, "", ICON_NONE);
+ uiItemR(row, ptr, "midtones_gamma", DEFAULT_FLAGS | UI_ITEM_R_SLIDER, "", ICON_NONE);
+ uiItemR(row, ptr, "midtones_gain", DEFAULT_FLAGS | UI_ITEM_R_SLIDER, "", ICON_NONE);
+ uiItemR(row, ptr, "midtones_lift", DEFAULT_FLAGS | UI_ITEM_R_SLIDER, "", ICON_NONE);
row = uiLayoutRow(layout, false);
uiItemL(row, IFACE_("Shadows"), ICON_NONE);
- uiItemR(row, ptr, "shadows_saturation", UI_ITEM_R_SLIDER, "", ICON_NONE);
- uiItemR(row, ptr, "shadows_contrast", UI_ITEM_R_SLIDER, "", ICON_NONE);
- uiItemR(row, ptr, "shadows_gamma", UI_ITEM_R_SLIDER, "", ICON_NONE);
- uiItemR(row, ptr, "shadows_gain", UI_ITEM_R_SLIDER, "", ICON_NONE);
- uiItemR(row, ptr, "shadows_lift", UI_ITEM_R_SLIDER, "", ICON_NONE);
+ uiItemR(row, ptr, "shadows_saturation", DEFAULT_FLAGS | UI_ITEM_R_SLIDER, "", ICON_NONE);
+ uiItemR(row, ptr, "shadows_contrast", DEFAULT_FLAGS | UI_ITEM_R_SLIDER, "", ICON_NONE);
+ uiItemR(row, ptr, "shadows_gamma", DEFAULT_FLAGS | UI_ITEM_R_SLIDER, "", ICON_NONE);
+ uiItemR(row, ptr, "shadows_gain", DEFAULT_FLAGS | UI_ITEM_R_SLIDER, "", ICON_NONE);
+ uiItemR(row, ptr, "shadows_lift", DEFAULT_FLAGS | UI_ITEM_R_SLIDER, "", ICON_NONE);
row = uiLayoutRow(layout, false);
- uiItemR(row, ptr, "midtones_start", UI_ITEM_R_SLIDER, NULL, ICON_NONE);
- uiItemR(row, ptr, "midtones_end", UI_ITEM_R_SLIDER, NULL, ICON_NONE);
+ uiItemR(row, ptr, "midtones_start", DEFAULT_FLAGS | UI_ITEM_R_SLIDER, NULL, ICON_NONE);
+ uiItemR(row, ptr, "midtones_end", DEFAULT_FLAGS | UI_ITEM_R_SLIDER, NULL, ICON_NONE);
}
static void node_composit_buts_colorcorrection_ex(uiLayout *layout,
@@ -2272,48 +2276,48 @@ static void node_composit_buts_colorcorrection_ex(uiLayout *layout,
uiLayout *row;
row = uiLayoutRow(layout, false);
- uiItemR(row, ptr, "red", 0, NULL, ICON_NONE);
- uiItemR(row, ptr, "green", 0, NULL, ICON_NONE);
- uiItemR(row, ptr, "blue", 0, NULL, ICON_NONE);
+ uiItemR(row, ptr, "red", DEFAULT_FLAGS, NULL, ICON_NONE);
+ uiItemR(row, ptr, "green", DEFAULT_FLAGS, NULL, ICON_NONE);
+ uiItemR(row, ptr, "blue", DEFAULT_FLAGS, NULL, ICON_NONE);
row = layout;
uiItemL(row, IFACE_("Saturation"), ICON_NONE);
- uiItemR(row, ptr, "master_saturation", UI_ITEM_R_SLIDER, NULL, ICON_NONE);
- uiItemR(row, ptr, "highlights_saturation", UI_ITEM_R_SLIDER, NULL, ICON_NONE);
- uiItemR(row, ptr, "midtones_saturation", UI_ITEM_R_SLIDER, NULL, ICON_NONE);
- uiItemR(row, ptr, "shadows_saturation", UI_ITEM_R_SLIDER, NULL, ICON_NONE);
+ uiItemR(row, ptr, "master_saturation", DEFAULT_FLAGS | UI_ITEM_R_SLIDER, NULL, ICON_NONE);
+ uiItemR(row, ptr, "highlights_saturation", DEFAULT_FLAGS | UI_ITEM_R_SLIDER, NULL, ICON_NONE);
+ uiItemR(row, ptr, "midtones_saturation", DEFAULT_FLAGS | UI_ITEM_R_SLIDER, NULL, ICON_NONE);
+ uiItemR(row, ptr, "shadows_saturation", DEFAULT_FLAGS | UI_ITEM_R_SLIDER, NULL, ICON_NONE);
uiItemL(row, IFACE_("Contrast"), ICON_NONE);
- uiItemR(row, ptr, "master_contrast", UI_ITEM_R_SLIDER, NULL, ICON_NONE);
- uiItemR(row, ptr, "highlights_contrast", UI_ITEM_R_SLIDER, NULL, ICON_NONE);
- uiItemR(row, ptr, "midtones_contrast", UI_ITEM_R_SLIDER, NULL, ICON_NONE);
- uiItemR(row, ptr, "shadows_contrast", UI_ITEM_R_SLIDER, NULL, ICON_NONE);
+ uiItemR(row, ptr, "master_contrast", DEFAULT_FLAGS | UI_ITEM_R_SLIDER, NULL, ICON_NONE);
+ uiItemR(row, ptr, "highlights_contrast", DEFAULT_FLAGS | UI_ITEM_R_SLIDER, NULL, ICON_NONE);
+ uiItemR(row, ptr, "midtones_contrast", DEFAULT_FLAGS | UI_ITEM_R_SLIDER, NULL, ICON_NONE);
+ uiItemR(row, ptr, "shadows_contrast", DEFAULT_FLAGS | UI_ITEM_R_SLIDER, NULL, ICON_NONE);
uiItemL(row, IFACE_("Gamma"), ICON_NONE);
- uiItemR(row, ptr, "master_gamma", UI_ITEM_R_SLIDER, NULL, ICON_NONE);
- uiItemR(row, ptr, "highlights_gamma", UI_ITEM_R_SLIDER, NULL, ICON_NONE);
- uiItemR(row, ptr, "midtones_gamma", UI_ITEM_R_SLIDER, NULL, ICON_NONE);
- uiItemR(row, ptr, "shadows_gamma", UI_ITEM_R_SLIDER, NULL, ICON_NONE);
+ uiItemR(row, ptr, "master_gamma", DEFAULT_FLAGS | UI_ITEM_R_SLIDER, NULL, ICON_NONE);
+ uiItemR(row, ptr, "highlights_gamma", DEFAULT_FLAGS | UI_ITEM_R_SLIDER, NULL, ICON_NONE);
+ uiItemR(row, ptr, "midtones_gamma", DEFAULT_FLAGS | UI_ITEM_R_SLIDER, NULL, ICON_NONE);
+ uiItemR(row, ptr, "shadows_gamma", DEFAULT_FLAGS | UI_ITEM_R_SLIDER, NULL, ICON_NONE);
uiItemL(row, IFACE_("Gain"), ICON_NONE);
- uiItemR(row, ptr, "master_gain", UI_ITEM_R_SLIDER, NULL, ICON_NONE);
- uiItemR(row, ptr, "highlights_gain", UI_ITEM_R_SLIDER, NULL, ICON_NONE);
- uiItemR(row, ptr, "midtones_gain", UI_ITEM_R_SLIDER, NULL, ICON_NONE);
- uiItemR(row, ptr, "shadows_gain", UI_ITEM_R_SLIDER, NULL, ICON_NONE);
+ uiItemR(row, ptr, "master_gain", DEFAULT_FLAGS | UI_ITEM_R_SLIDER, NULL, ICON_NONE);
+ uiItemR(row, ptr, "highlights_gain", DEFAULT_FLAGS | UI_ITEM_R_SLIDER, NULL, ICON_NONE);
+ uiItemR(row, ptr, "midtones_gain", DEFAULT_FLAGS | UI_ITEM_R_SLIDER, NULL, ICON_NONE);
+ uiItemR(row, ptr, "shadows_gain", DEFAULT_FLAGS | UI_ITEM_R_SLIDER, NULL, ICON_NONE);
uiItemL(row, IFACE_("Lift"), ICON_NONE);
- uiItemR(row, ptr, "master_lift", UI_ITEM_R_SLIDER, NULL, ICON_NONE);
- uiItemR(row, ptr, "highlights_lift", UI_ITEM_R_SLIDER, NULL, ICON_NONE);
- uiItemR(row, ptr, "midtones_lift", UI_ITEM_R_SLIDER, NULL, ICON_NONE);
- uiItemR(row, ptr, "shadows_lift", UI_ITEM_R_SLIDER, NULL, ICON_NONE);
+ uiItemR(row, ptr, "master_lift", DEFAULT_FLAGS | UI_ITEM_R_SLIDER, NULL, ICON_NONE);
+ uiItemR(row, ptr, "highlights_lift", DEFAULT_FLAGS | UI_ITEM_R_SLIDER, NULL, ICON_NONE);
+ uiItemR(row, ptr, "midtones_lift", DEFAULT_FLAGS | UI_ITEM_R_SLIDER, NULL, ICON_NONE);
+ uiItemR(row, ptr, "shadows_lift", DEFAULT_FLAGS | UI_ITEM_R_SLIDER, NULL, ICON_NONE);
row = uiLayoutRow(layout, false);
- uiItemR(row, ptr, "midtones_start", 0, NULL, ICON_NONE);
- uiItemR(row, ptr, "midtones_end", 0, NULL, ICON_NONE);
+ uiItemR(row, ptr, "midtones_start", DEFAULT_FLAGS, NULL, ICON_NONE);
+ uiItemR(row, ptr, "midtones_end", DEFAULT_FLAGS, NULL, ICON_NONE);
}
static void node_composit_buts_switch(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr)
{
- uiItemR(layout, ptr, "check", 0, NULL, ICON_NONE);
+ uiItemR(layout, ptr, "check", DEFAULT_FLAGS, NULL, ICON_NONE);
}
static void node_composit_buts_switch_view_ex(uiLayout *layout,
@@ -2335,32 +2339,32 @@ static void node_composit_buts_boxmask(uiLayout *layout, bContext *UNUSED(C), Po
uiLayout *row;
row = uiLayoutRow(layout, true);
- uiItemR(row, ptr, "x", 0, NULL, ICON_NONE);
- uiItemR(row, ptr, "y", 0, NULL, ICON_NONE);
+ uiItemR(row, ptr, "x", DEFAULT_FLAGS, NULL, ICON_NONE);
+ uiItemR(row, ptr, "y", DEFAULT_FLAGS, NULL, ICON_NONE);
row = uiLayoutRow(layout, true);
- uiItemR(row, ptr, "width", UI_ITEM_R_SLIDER, NULL, ICON_NONE);
- uiItemR(row, ptr, "height", UI_ITEM_R_SLIDER, NULL, ICON_NONE);
+ uiItemR(row, ptr, "width", DEFAULT_FLAGS | UI_ITEM_R_SLIDER, NULL, ICON_NONE);
+ uiItemR(row, ptr, "height", DEFAULT_FLAGS | UI_ITEM_R_SLIDER, NULL, ICON_NONE);
- uiItemR(layout, ptr, "rotation", 0, NULL, ICON_NONE);
- uiItemR(layout, ptr, "mask_type", 0, NULL, ICON_NONE);
+ uiItemR(layout, ptr, "rotation", DEFAULT_FLAGS, NULL, ICON_NONE);
+ uiItemR(layout, ptr, "mask_type", DEFAULT_FLAGS, NULL, ICON_NONE);
}
static void node_composit_buts_bokehimage(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr)
{
- uiItemR(layout, ptr, "flaps", 0, NULL, ICON_NONE);
- uiItemR(layout, ptr, "angle", 0, NULL, ICON_NONE);
- uiItemR(layout, ptr, "rounding", UI_ITEM_R_SLIDER, NULL, ICON_NONE);
- uiItemR(layout, ptr, "catadioptric", UI_ITEM_R_SLIDER, NULL, ICON_NONE);
- uiItemR(layout, ptr, "shift", UI_ITEM_R_SLIDER, NULL, ICON_NONE);
+ uiItemR(layout, ptr, "flaps", DEFAULT_FLAGS, NULL, ICON_NONE);
+ uiItemR(layout, ptr, "angle", DEFAULT_FLAGS, NULL, ICON_NONE);
+ uiItemR(layout, ptr, "rounding", DEFAULT_FLAGS | UI_ITEM_R_SLIDER, NULL, ICON_NONE);
+ uiItemR(layout, ptr, "catadioptric", DEFAULT_FLAGS | UI_ITEM_R_SLIDER, NULL, ICON_NONE);
+ uiItemR(layout, ptr, "shift", DEFAULT_FLAGS | UI_ITEM_R_SLIDER, NULL, ICON_NONE);
}
static void node_composit_buts_bokehblur(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr)
{
- uiItemR(layout, ptr, "use_variable_size", 0, NULL, ICON_NONE);
- // uiItemR(layout, ptr, "f_stop", 0, NULL, ICON_NONE); // UNUSED
- uiItemR(layout, ptr, "blur_max", 0, NULL, ICON_NONE);
- uiItemR(layout, ptr, "use_extended_bounds", 0, NULL, ICON_NONE);
+ uiItemR(layout, ptr, "use_variable_size", DEFAULT_FLAGS, NULL, ICON_NONE);
+ // uiItemR(layout, ptr, "f_stop", DEFAULT_FLAGS, NULL, ICON_NONE); // UNUSED
+ uiItemR(layout, ptr, "blur_max", DEFAULT_FLAGS, NULL, ICON_NONE);
+ uiItemR(layout, ptr, "use_extended_bounds", DEFAULT_FLAGS, NULL, ICON_NONE);
}
static void node_composit_backdrop_viewer(
@@ -2486,36 +2490,36 @@ static void node_composit_buts_ellipsemask(uiLayout *layout, bContext *UNUSED(C)
{
uiLayout *row;
row = uiLayoutRow(layout, true);
- uiItemR(row, ptr, "x", 0, NULL, ICON_NONE);
- uiItemR(row, ptr, "y", 0, NULL, ICON_NONE);
+ uiItemR(row, ptr, "x", DEFAULT_FLAGS, NULL, ICON_NONE);
+ uiItemR(row, ptr, "y", DEFAULT_FLAGS, NULL, ICON_NONE);
row = uiLayoutRow(layout, true);
- uiItemR(row, ptr, "width", UI_ITEM_R_SLIDER, NULL, ICON_NONE);
- uiItemR(row, ptr, "height", UI_ITEM_R_SLIDER, NULL, ICON_NONE);
+ uiItemR(row, ptr, "width", DEFAULT_FLAGS | UI_ITEM_R_SLIDER, NULL, ICON_NONE);
+ uiItemR(row, ptr, "height", DEFAULT_FLAGS | UI_ITEM_R_SLIDER, NULL, ICON_NONE);
- uiItemR(layout, ptr, "rotation", 0, NULL, ICON_NONE);
- uiItemR(layout, ptr, "mask_type", 0, NULL, ICON_NONE);
+ uiItemR(layout, ptr, "rotation", DEFAULT_FLAGS, NULL, ICON_NONE);
+ uiItemR(layout, ptr, "mask_type", DEFAULT_FLAGS, NULL, ICON_NONE);
}
static void node_composit_buts_composite(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr)
{
- uiItemR(layout, ptr, "use_alpha", 0, NULL, ICON_NONE);
+ uiItemR(layout, ptr, "use_alpha", DEFAULT_FLAGS, NULL, ICON_NONE);
}
static void node_composit_buts_viewer(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr)
{
- uiItemR(layout, ptr, "use_alpha", 0, NULL, ICON_NONE);
+ uiItemR(layout, ptr, "use_alpha", DEFAULT_FLAGS, NULL, ICON_NONE);
}
static void node_composit_buts_viewer_ex(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr)
{
uiLayout *col;
- uiItemR(layout, ptr, "use_alpha", 0, NULL, ICON_NONE);
- uiItemR(layout, ptr, "tile_order", 0, NULL, ICON_NONE);
+ uiItemR(layout, ptr, "use_alpha", DEFAULT_FLAGS, NULL, ICON_NONE);
+ uiItemR(layout, ptr, "tile_order", DEFAULT_FLAGS, NULL, ICON_NONE);
if (RNA_enum_get(ptr, "tile_order") == 0) {
col = uiLayoutColumn(layout, true);
- uiItemR(col, ptr, "center_x", 0, NULL, ICON_NONE);
- uiItemR(col, ptr, "center_y", 0, NULL, ICON_NONE);
+ uiItemR(col, ptr, "center_x", DEFAULT_FLAGS, NULL, ICON_NONE);
+ uiItemR(col, ptr, "center_y", DEFAULT_FLAGS, NULL, ICON_NONE);
}
}
@@ -2524,19 +2528,19 @@ static void node_composit_buts_mask(uiLayout *layout, bContext *C, PointerRNA *p
bNode *node = ptr->data;
uiTemplateID(layout, C, ptr, "mask", NULL, NULL, NULL, UI_TEMPLATE_ID_FILTER_ALL, false, NULL);
- uiItemR(layout, ptr, "use_feather", 0, NULL, ICON_NONE);
+ uiItemR(layout, ptr, "use_feather", DEFAULT_FLAGS, NULL, ICON_NONE);
- uiItemR(layout, ptr, "size_source", 0, "", ICON_NONE);
+ uiItemR(layout, ptr, "size_source", DEFAULT_FLAGS, "", ICON_NONE);
if (node->custom1 & (CMP_NODEFLAG_MASK_FIXED | CMP_NODEFLAG_MASK_FIXED_SCENE)) {
- uiItemR(layout, ptr, "size_x", 0, NULL, ICON_NONE);
- uiItemR(layout, ptr, "size_y", 0, NULL, ICON_NONE);
+ uiItemR(layout, ptr, "size_x", DEFAULT_FLAGS, NULL, ICON_NONE);
+ uiItemR(layout, ptr, "size_y", DEFAULT_FLAGS, NULL, ICON_NONE);
}
- uiItemR(layout, ptr, "use_motion_blur", 0, NULL, ICON_NONE);
+ uiItemR(layout, ptr, "use_motion_blur", DEFAULT_FLAGS, NULL, ICON_NONE);
if (node->custom1 & CMP_NODEFLAG_MASK_MOTION_BLUR) {
- uiItemR(layout, ptr, "motion_blur_samples", 0, NULL, ICON_NONE);
- uiItemR(layout, ptr, "motion_blur_shutter", 0, NULL, ICON_NONE);
+ uiItemR(layout, ptr, "motion_blur_samples", DEFAULT_FLAGS, NULL, ICON_NONE);
+ uiItemR(layout, ptr, "motion_blur_shutter", DEFAULT_FLAGS, NULL, ICON_NONE);
}
}
@@ -2562,18 +2566,18 @@ static void node_composit_buts_keying(uiLayout *layout, bContext *UNUSED(C), Poi
{
/* bNode *node = ptr->data; */ /* UNUSED */
- uiItemR(layout, ptr, "blur_pre", 0, NULL, ICON_NONE);
- uiItemR(layout, ptr, "screen_balance", 0, NULL, ICON_NONE);
- uiItemR(layout, ptr, "despill_factor", 0, NULL, ICON_NONE);
- uiItemR(layout, ptr, "despill_balance", 0, NULL, ICON_NONE);
- uiItemR(layout, ptr, "edge_kernel_radius", 0, NULL, ICON_NONE);
- uiItemR(layout, ptr, "edge_kernel_tolerance", 0, NULL, ICON_NONE);
- uiItemR(layout, ptr, "clip_black", 0, NULL, ICON_NONE);
- uiItemR(layout, ptr, "clip_white", 0, NULL, ICON_NONE);
- uiItemR(layout, ptr, "dilate_distance", 0, NULL, ICON_NONE);
- uiItemR(layout, ptr, "feather_falloff", 0, NULL, ICON_NONE);
- uiItemR(layout, ptr, "feather_distance", 0, NULL, ICON_NONE);
- uiItemR(layout, ptr, "blur_post", 0, NULL, ICON_NONE);
+ uiItemR(layout, ptr, "blur_pre", DEFAULT_FLAGS, NULL, ICON_NONE);
+ uiItemR(layout, ptr, "screen_balance", DEFAULT_FLAGS, NULL, ICON_NONE);
+ uiItemR(layout, ptr, "despill_factor", DEFAULT_FLAGS, NULL, ICON_NONE);
+ uiItemR(layout, ptr, "despill_balance", DEFAULT_FLAGS, NULL, ICON_NONE);
+ uiItemR(layout, ptr, "edge_kernel_radius", DEFAULT_FLAGS, NULL, ICON_NONE);
+ uiItemR(layout, ptr, "edge_kernel_tolerance", DEFAULT_FLAGS, NULL, ICON_NONE);
+ uiItemR(layout, ptr, "clip_black", DEFAULT_FLAGS, NULL, ICON_NONE);
+ uiItemR(layout, ptr, "clip_white", DEFAULT_FLAGS, NULL, ICON_NONE);
+ uiItemR(layout, ptr, "dilate_distance", DEFAULT_FLAGS, NULL, ICON_NONE);
+ uiItemR(layout, ptr, "feather_falloff", DEFAULT_FLAGS, NULL, ICON_NONE);
+ uiItemR(layout, ptr, "feather_distance", DEFAULT_FLAGS, NULL, ICON_NONE);
+ uiItemR(layout, ptr, "blur_post", DEFAULT_FLAGS, NULL, ICON_NONE);
}
static void node_composit_buts_trackpos(uiLayout *layout, bContext *C, PointerRNA *ptr)
@@ -2605,13 +2609,13 @@ static void node_composit_buts_trackpos(uiLayout *layout, bContext *C, PointerRN
uiItemPointerR(col, ptr, "track_name", &object_ptr, "tracks", "", ICON_ANIM_DATA);
}
else {
- uiItemR(layout, ptr, "track_name", 0, "", ICON_ANIM_DATA);
+ uiItemR(layout, ptr, "track_name", DEFAULT_FLAGS, "", ICON_ANIM_DATA);
}
- uiItemR(layout, ptr, "position", 0, NULL, ICON_NONE);
+ uiItemR(layout, ptr, "position", DEFAULT_FLAGS, NULL, ICON_NONE);
if (ELEM(node->custom1, CMP_TRACKPOS_RELATIVE_FRAME, CMP_TRACKPOS_ABSOLUTE_FRAME)) {
- uiItemR(layout, ptr, "frame_relative", 0, NULL, ICON_NONE);
+ uiItemR(layout, ptr, "frame_relative", DEFAULT_FLAGS, NULL, ICON_NONE);
}
}
}
@@ -2650,10 +2654,10 @@ static void node_composit_buts_planetrackdeform(uiLayout *layout, bContext *C, P
}
}
- uiItemR(layout, ptr, "use_motion_blur", 0, NULL, ICON_NONE);
+ uiItemR(layout, ptr, "use_motion_blur", DEFAULT_FLAGS, NULL, ICON_NONE);
if (data->flag & CMP_NODEFLAG_PLANETRACKDEFORM_MOTION_BLUR) {
- uiItemR(layout, ptr, "motion_blur_samples", 0, NULL, ICON_NONE);
- uiItemR(layout, ptr, "motion_blur_shutter", 0, NULL, ICON_NONE);
+ uiItemR(layout, ptr, "motion_blur_samples", DEFAULT_FLAGS, NULL, ICON_NONE);
+ uiItemR(layout, ptr, "motion_blur_shutter", DEFAULT_FLAGS, NULL, ICON_NONE);
}
}
@@ -2665,8 +2669,8 @@ static void node_composit_buts_cornerpin(uiLayout *UNUSED(layout),
static void node_composit_buts_sunbeams(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr)
{
- uiItemR(layout, ptr, "source", UI_ITEM_R_EXPAND, "", ICON_NONE);
- uiItemR(layout, ptr, "ray_length", UI_ITEM_R_SLIDER, NULL, ICON_NONE);
+ uiItemR(layout, ptr, "source", DEFAULT_FLAGS | UI_ITEM_R_EXPAND, "", ICON_NONE);
+ uiItemR(layout, ptr, "ray_length", DEFAULT_FLAGS | UI_ITEM_R_SLIDER, NULL, ICON_NONE);
}
static void node_composit_buts_cryptomatte(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr)
@@ -2679,7 +2683,7 @@ static void node_composit_buts_cryptomatte(uiLayout *layout, bContext *UNUSED(C)
uiTemplateCryptoPicker(row, ptr, "add");
uiTemplateCryptoPicker(row, ptr, "remove");
- uiItemR(col, ptr, "matte_id", 0, "", ICON_NONE);
+ uiItemR(col, ptr, "matte_id", DEFAULT_FLAGS, "", ICON_NONE);
}
static void node_composit_buts_cryptomatte_ex(uiLayout *layout,
@@ -2694,7 +2698,7 @@ static void node_composit_buts_brightcontrast(uiLayout *layout,
bContext *UNUSED(C),
PointerRNA *ptr)
{
- uiItemR(layout, ptr, "use_premultiply", 0, NULL, ICON_NONE);
+ uiItemR(layout, ptr, "use_premultiply", DEFAULT_FLAGS, NULL, ICON_NONE);
}
static void node_composit_buts_denoise(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr)
@@ -2707,7 +2711,7 @@ static void node_composit_buts_denoise(uiLayout *layout, bContext *UNUSED(C), Po
}
#endif
- uiItemR(layout, ptr, "use_hdr", 0, NULL, ICON_NONE);
+ uiItemR(layout, ptr, "use_hdr", DEFAULT_FLAGS, NULL, ICON_NONE);
}
/* only once called */
@@ -2957,12 +2961,12 @@ static void node_texture_buts_bricks(uiLayout *layout, bContext *UNUSED(C), Poin
uiLayout *col;
col = uiLayoutColumn(layout, true);
- uiItemR(col, ptr, "offset", UI_ITEM_R_SLIDER, IFACE_("Offset"), ICON_NONE);
- uiItemR(col, ptr, "offset_frequency", 0, IFACE_("Frequency"), ICON_NONE);
+ uiItemR(col, ptr, "offset", DEFAULT_FLAGS | UI_ITEM_R_SLIDER, IFACE_("Offset"), ICON_NONE);
+ uiItemR(col, ptr, "offset_frequency", DEFAULT_FLAGS, IFACE_("Frequency"), ICON_NONE);
col = uiLayoutColumn(layout, true);
- uiItemR(col, ptr, "squash", 0, IFACE_("Squash"), ICON_NONE);
- uiItemR(col, ptr, "squash_frequency", 0, IFACE_("Frequency"), ICON_NONE);
+ uiItemR(col, ptr, "squash", DEFAULT_FLAGS, IFACE_("Squash"), ICON_NONE);
+ uiItemR(col, ptr, "squash_frequency", DEFAULT_FLAGS, IFACE_("Frequency"), ICON_NONE);
}
static void node_texture_buts_proc(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr)
@@ -2979,68 +2983,73 @@ static void node_texture_buts_proc(uiLayout *layout, bContext *UNUSED(C), Pointe
switch (tex->type) {
case TEX_BLEND:
- uiItemR(col, &tex_ptr, "progression", 0, "", ICON_NONE);
+ uiItemR(col, &tex_ptr, "progression", DEFAULT_FLAGS, "", ICON_NONE);
row = uiLayoutRow(col, false);
- uiItemR(row, &tex_ptr, "use_flip_axis", UI_ITEM_R_EXPAND, NULL, ICON_NONE);
+ uiItemR(row, &tex_ptr, "use_flip_axis", DEFAULT_FLAGS | UI_ITEM_R_EXPAND, NULL, ICON_NONE);
break;
case TEX_MARBLE:
row = uiLayoutRow(col, false);
- uiItemR(row, &tex_ptr, "marble_type", UI_ITEM_R_EXPAND, NULL, ICON_NONE);
+ uiItemR(row, &tex_ptr, "marble_type", DEFAULT_FLAGS | UI_ITEM_R_EXPAND, NULL, ICON_NONE);
row = uiLayoutRow(col, false);
- uiItemR(row, &tex_ptr, "noise_type", UI_ITEM_R_EXPAND, NULL, ICON_NONE);
+ uiItemR(row, &tex_ptr, "noise_type", DEFAULT_FLAGS | UI_ITEM_R_EXPAND, NULL, ICON_NONE);
row = uiLayoutRow(col, false);
- uiItemR(row, &tex_ptr, "noise_basis", 0, "", ICON_NONE);
+ uiItemR(row, &tex_ptr, "noise_basis", DEFAULT_FLAGS, "", ICON_NONE);
row = uiLayoutRow(col, false);
- uiItemR(row, &tex_ptr, "noise_basis_2", UI_ITEM_R_EXPAND, NULL, ICON_NONE);
+ uiItemR(row, &tex_ptr, "noise_basis_2", DEFAULT_FLAGS | UI_ITEM_R_EXPAND, NULL, ICON_NONE);
break;
case TEX_MAGIC:
- uiItemR(col, &tex_ptr, "noise_depth", 0, NULL, ICON_NONE);
+ uiItemR(col, &tex_ptr, "noise_depth", DEFAULT_FLAGS, NULL, ICON_NONE);
break;
case TEX_STUCCI:
row = uiLayoutRow(col, false);
- uiItemR(row, &tex_ptr, "stucci_type", UI_ITEM_R_EXPAND, NULL, ICON_NONE);
+ uiItemR(row, &tex_ptr, "stucci_type", DEFAULT_FLAGS | UI_ITEM_R_EXPAND, NULL, ICON_NONE);
row = uiLayoutRow(col, false);
- uiItemR(row, &tex_ptr, "noise_type", UI_ITEM_R_EXPAND, NULL, ICON_NONE);
- uiItemR(col, &tex_ptr, "noise_basis", 0, "", ICON_NONE);
+ uiItemR(row, &tex_ptr, "noise_type", DEFAULT_FLAGS | UI_ITEM_R_EXPAND, NULL, ICON_NONE);
+ uiItemR(col, &tex_ptr, "noise_basis", DEFAULT_FLAGS, "", ICON_NONE);
break;
case TEX_WOOD:
- uiItemR(col, &tex_ptr, "noise_basis", 0, "", ICON_NONE);
- uiItemR(col, &tex_ptr, "wood_type", 0, "", ICON_NONE);
+ uiItemR(col, &tex_ptr, "noise_basis", DEFAULT_FLAGS, "", ICON_NONE);
+ uiItemR(col, &tex_ptr, "wood_type", DEFAULT_FLAGS, "", ICON_NONE);
row = uiLayoutRow(col, false);
- uiItemR(row, &tex_ptr, "noise_basis_2", UI_ITEM_R_EXPAND, NULL, ICON_NONE);
+ uiItemR(row, &tex_ptr, "noise_basis_2", DEFAULT_FLAGS | UI_ITEM_R_EXPAND, NULL, ICON_NONE);
row = uiLayoutRow(col, false);
uiLayoutSetActive(row, !(ELEM(tex->stype, TEX_BAND, TEX_RING)));
- uiItemR(row, &tex_ptr, "noise_type", UI_ITEM_R_EXPAND, NULL, ICON_NONE);
+ uiItemR(row, &tex_ptr, "noise_type", DEFAULT_FLAGS | UI_ITEM_R_EXPAND, NULL, ICON_NONE);
break;
case TEX_CLOUDS:
- uiItemR(col, &tex_ptr, "noise_basis", 0, "", ICON_NONE);
+ uiItemR(col, &tex_ptr, "noise_basis", DEFAULT_FLAGS, "", ICON_NONE);
row = uiLayoutRow(col, false);
- uiItemR(row, &tex_ptr, "cloud_type", UI_ITEM_R_EXPAND, NULL, ICON_NONE);
+ uiItemR(row, &tex_ptr, "cloud_type", DEFAULT_FLAGS | UI_ITEM_R_EXPAND, NULL, ICON_NONE);
row = uiLayoutRow(col, false);
- uiItemR(row, &tex_ptr, "noise_type", UI_ITEM_R_EXPAND, NULL, ICON_NONE);
- uiItemR(col, &tex_ptr, "noise_depth", UI_ITEM_R_EXPAND, IFACE_("Depth"), ICON_NONE);
+ uiItemR(row, &tex_ptr, "noise_type", DEFAULT_FLAGS | UI_ITEM_R_EXPAND, NULL, ICON_NONE);
+ uiItemR(col,
+ &tex_ptr,
+ "noise_depth",
+ DEFAULT_FLAGS | UI_ITEM_R_EXPAND,
+ IFACE_("Depth"),
+ ICON_NONE);
break;
case TEX_DISTNOISE:
- uiItemR(col, &tex_ptr, "noise_basis", 0, "", ICON_NONE);
- uiItemR(col, &tex_ptr, "noise_distortion", 0, "", ICON_NONE);
+ uiItemR(col, &tex_ptr, "noise_basis", DEFAULT_FLAGS, "", ICON_NONE);
+ uiItemR(col, &tex_ptr, "noise_distortion", DEFAULT_FLAGS, "", ICON_NONE);
break;
case TEX_MUSGRAVE:
- uiItemR(col, &tex_ptr, "musgrave_type", 0, "", ICON_NONE);
- uiItemR(col, &tex_ptr, "noise_basis", 0, "", ICON_NONE);
+ uiItemR(col, &tex_ptr, "musgrave_type", DEFAULT_FLAGS, "", ICON_NONE);
+ uiItemR(col, &tex_ptr, "noise_basis", DEFAULT_FLAGS, "", ICON_NONE);
break;
case TEX_VORONOI:
- uiItemR(col, &tex_ptr, "distance_metric", 0, "", ICON_NONE);
+ uiItemR(col, &tex_ptr, "distance_metric", DEFAULT_FLAGS, "", ICON_NONE);
if (tex->vn_distm == TEX_MINKOVSKY) {
- uiItemR(col, &tex_ptr, "minkovsky_exponent", 0, NULL, ICON_NONE);
+ uiItemR(col, &tex_ptr, "minkovsky_exponent", DEFAULT_FLAGS, NULL, ICON_NONE);
}
- uiItemR(col, &tex_ptr, "color_mode", 0, "", ICON_NONE);
+ uiItemR(col, &tex_ptr, "color_mode", DEFAULT_FLAGS, "", ICON_NONE);
break;
}
}
@@ -3070,7 +3079,7 @@ static void node_texture_buts_image_ex(uiLayout *layout, bContext *C, PointerRNA
static void node_texture_buts_output(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr)
{
- uiItemR(layout, ptr, "filepath", 0, "", ICON_NONE);
+ uiItemR(layout, ptr, "filepath", DEFAULT_FLAGS, "", ICON_NONE);
}
/* only once called */
@@ -3122,6 +3131,96 @@ static void node_texture_set_butfunc(bNodeType *ntype)
}
}
+/* ****************** BUTTON CALLBACKS FOR SIMULATION NODES ***************** */
+
+static void node_simulation_buts_particle_simulation(uiLayout *layout,
+ bContext *UNUSED(C),
+ PointerRNA *ptr)
+{
+ uiItemR(layout, ptr, "name", DEFAULT_FLAGS, "", ICON_NONE);
+}
+
+static void node_simulation_buts_particle_time_step_event(uiLayout *layout,
+ bContext *UNUSED(C),
+ PointerRNA *ptr)
+{
+ uiItemR(layout, ptr, "mode", DEFAULT_FLAGS, "", ICON_NONE);
+}
+
+static void node_simulation_buts_particle_attribute(uiLayout *layout,
+ bContext *UNUSED(C),
+ PointerRNA *ptr)
+{
+ uiItemR(layout, ptr, "data_type", DEFAULT_FLAGS, "", ICON_NONE);
+}
+
+static void node_simulation_buts_set_particle_attribute(uiLayout *layout,
+ bContext *UNUSED(C),
+ PointerRNA *ptr)
+{
+ uiItemR(layout, ptr, "data_type", DEFAULT_FLAGS, "", ICON_NONE);
+}
+
+static void node_simulation_buts_time(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr)
+{
+ uiItemR(layout, ptr, "mode", DEFAULT_FLAGS, "", ICON_NONE);
+}
+
+static void node_simulation_set_butfunc(bNodeType *ntype)
+{
+ switch (ntype->type) {
+ case SIM_NODE_PARTICLE_SIMULATION:
+ ntype->draw_buttons = node_simulation_buts_particle_simulation;
+ break;
+ case SIM_NODE_PARTICLE_TIME_STEP_EVENT:
+ ntype->draw_buttons = node_simulation_buts_particle_time_step_event;
+ break;
+ case SIM_NODE_PARTICLE_ATTRIBUTE:
+ ntype->draw_buttons = node_simulation_buts_particle_attribute;
+ break;
+ case SIM_NODE_SET_PARTICLE_ATTRIBUTE:
+ ntype->draw_buttons = node_simulation_buts_set_particle_attribute;
+ break;
+ case SIM_NODE_TIME:
+ ntype->draw_buttons = node_simulation_buts_time;
+ break;
+ }
+}
+
+/* ****************** BUTTON CALLBACKS FOR FUNCTION NODES ***************** */
+
+static void node_function_buts_boolean_math(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr)
+{
+ uiItemR(layout, ptr, "operation", DEFAULT_FLAGS, "", ICON_NONE);
+}
+
+static void node_function_buts_float_compare(uiLayout *layout,
+ bContext *UNUSED(C),
+ PointerRNA *ptr)
+{
+ uiItemR(layout, ptr, "operation", DEFAULT_FLAGS, "", ICON_NONE);
+}
+
+static void node_function_buts_switch(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr)
+{
+ uiItemR(layout, ptr, "data_type", DEFAULT_FLAGS, "", ICON_NONE);
+}
+
+static void node_function_set_butfunc(bNodeType *ntype)
+{
+ switch (ntype->type) {
+ case FN_NODE_BOOLEAN_MATH:
+ ntype->draw_buttons = node_function_buts_boolean_math;
+ break;
+ case FN_NODE_FLOAT_COMPARE:
+ ntype->draw_buttons = node_function_buts_float_compare;
+ break;
+ case FN_NODE_SWITCH:
+ ntype->draw_buttons = node_function_buts_switch;
+ break;
+ }
+}
+
/* ****** init draw callbacks for all tree types, only called in usiblender.c, once ************ */
static void node_property_update_default(Main *bmain, Scene *UNUSED(scene), PointerRNA *ptr)
@@ -3133,7 +3232,7 @@ static void node_property_update_default(Main *bmain, Scene *UNUSED(scene), Poin
static void node_socket_template_properties_update(bNodeType *ntype, bNodeSocketTemplate *stemp)
{
- StructRNA *srna = ntype->ext.srna;
+ StructRNA *srna = ntype->rna_ext.srna;
PropertyRNA *prop = RNA_struct_type_find_property(srna, stemp->identifier);
if (prop) {
@@ -3230,6 +3329,8 @@ void ED_node_init_butfuncs(void)
node_composit_set_butfunc(ntype);
node_shader_set_butfunc(ntype);
node_texture_set_butfunc(ntype);
+ node_simulation_set_butfunc(ntype);
+ node_function_set_butfunc(ntype);
/* define update callbacks for socket properties */
node_template_properties_update(ntype);
@@ -3240,6 +3341,7 @@ void ED_node_init_butfuncs(void)
ntreeType_Composite->ui_icon = ICON_NODE_COMPOSITING;
ntreeType_Shader->ui_icon = ICON_NODE_MATERIAL;
ntreeType_Texture->ui_icon = ICON_NODE_TEXTURE;
+ ntreeType_Simulation->ui_icon = ICON_PHYSICS; /* TODO: Use correct icon. */
}
void ED_init_custom_node_type(bNodeType *ntype)
@@ -3268,6 +3370,12 @@ static const float std_node_socket_colors[][4] = {
{0.0, 0.0, 0.0, 1.0}, /*__SOCK_MESH (deprecated) */
{0.06, 0.52, 0.15, 1.0}, /* SOCK_INT */
{0.39, 0.39, 0.39, 1.0}, /* SOCK_STRING */
+ {0.40, 0.10, 0.10, 1.0}, /* SOCK_OBJECT */
+ {0.10, 0.40, 0.10, 1.0}, /* SOCK_IMAGE */
+ {0.80, 0.80, 0.20, 1.0}, /* SOCK_EMITTERS */
+ {0.80, 0.20, 0.80, 1.0}, /* SOCK_EVENTS */
+ {0.20, 0.80, 0.80, 1.0}, /* SOCK_FORCES */
+ {0.30, 0.30, 0.30, 1.0}, /* SOCK_CONTROL_FLOW */
};
/* common color callbacks for standard types */
@@ -3362,7 +3470,7 @@ static void std_node_socket_draw(
case SOCK_FLOAT:
case SOCK_INT:
case SOCK_BOOLEAN:
- uiItemR(layout, ptr, "default_value", 0, text, 0);
+ uiItemR(layout, ptr, "default_value", DEFAULT_FLAGS, text, 0);
break;
case SOCK_VECTOR:
if (sock->flag & SOCK_COMPACT) {
@@ -3370,11 +3478,11 @@ static void std_node_socket_draw(
}
else {
if (sock->typeinfo->subtype == PROP_DIRECTION) {
- uiItemR(layout, ptr, "default_value", 0, "", ICON_NONE);
+ uiItemR(layout, ptr, "default_value", DEFAULT_FLAGS, "", ICON_NONE);
}
else {
uiLayout *column = uiLayoutColumn(layout, true);
- uiItemR(column, ptr, "default_value", 0, text, ICON_NONE);
+ uiItemR(column, ptr, "default_value", DEFAULT_FLAGS, text, ICON_NONE);
}
}
break;
@@ -3382,7 +3490,15 @@ static void std_node_socket_draw(
case SOCK_STRING: {
uiLayout *row = uiLayoutSplit(layout, 0.5f, false);
uiItemL(row, text, 0);
- uiItemR(row, ptr, "default_value", 0, "", 0);
+ uiItemR(row, ptr, "default_value", DEFAULT_FLAGS, "", 0);
+ break;
+ }
+ case SOCK_OBJECT: {
+ uiItemR(layout, ptr, "default_value", DEFAULT_FLAGS, text, 0);
+ break;
+ }
+ case SOCK_IMAGE: {
+ uiItemR(layout, ptr, "default_value", DEFAULT_FLAGS, text, 0);
break;
}
default:
@@ -3400,32 +3516,32 @@ static void std_node_socket_interface_draw(bContext *UNUSED(C), uiLayout *layout
switch (type) {
case SOCK_FLOAT: {
uiLayout *row;
- uiItemR(layout, ptr, "default_value", 0, NULL, 0);
+ uiItemR(layout, ptr, "default_value", DEFAULT_FLAGS, NULL, 0);
row = uiLayoutRow(layout, true);
- uiItemR(row, ptr, "min_value", 0, IFACE_("Min"), 0);
- uiItemR(row, ptr, "max_value", 0, IFACE_("Max"), 0);
+ uiItemR(row, ptr, "min_value", DEFAULT_FLAGS, IFACE_("Min"), 0);
+ uiItemR(row, ptr, "max_value", DEFAULT_FLAGS, IFACE_("Max"), 0);
break;
}
case SOCK_INT: {
uiLayout *row;
- uiItemR(layout, ptr, "default_value", 0, NULL, 0);
+ uiItemR(layout, ptr, "default_value", DEFAULT_FLAGS, NULL, 0);
row = uiLayoutRow(layout, true);
- uiItemR(row, ptr, "min_value", 0, IFACE_("Min"), 0);
- uiItemR(row, ptr, "max_value", 0, IFACE_("Max"), 0);
+ uiItemR(row, ptr, "min_value", DEFAULT_FLAGS, IFACE_("Min"), 0);
+ uiItemR(row, ptr, "max_value", DEFAULT_FLAGS, IFACE_("Max"), 0);
break;
}
case SOCK_VECTOR: {
uiLayout *row;
- uiItemR(layout, ptr, "default_value", UI_ITEM_R_EXPAND, NULL, 0);
+ uiItemR(layout, ptr, "default_value", UI_ITEM_R_EXPAND, NULL, DEFAULT_FLAGS);
row = uiLayoutRow(layout, true);
- uiItemR(row, ptr, "min_value", 0, IFACE_("Min"), 0);
- uiItemR(row, ptr, "max_value", 0, IFACE_("Max"), 0);
+ uiItemR(row, ptr, "min_value", DEFAULT_FLAGS, IFACE_("Min"), 0);
+ uiItemR(row, ptr, "max_value", DEFAULT_FLAGS, IFACE_("Max"), 0);
break;
}
case SOCK_BOOLEAN:
case SOCK_RGBA:
case SOCK_STRING: {
- uiItemR(layout, ptr, "default_value", 0, NULL, 0);
+ uiItemR(layout, ptr, "default_value", DEFAULT_FLAGS, NULL, 0);
break;
}
}
@@ -3522,7 +3638,7 @@ void draw_nodespace_back_pix(const bContext *C,
IMMDrawPixelsTexState state = immDrawPixelsTexSetup(GPU_SHADER_2D_IMAGE_SHUFFLE_COLOR);
GPU_shader_uniform_vector(
- state.shader, GPU_shader_get_uniform_ensure(state.shader, "shuffle"), 4, 1, shuffle);
+ state.shader, GPU_shader_get_uniform(state.shader, "shuffle"), 4, 1, shuffle);
immDrawPixelsTex(&state,
x,
diff --git a/source/blender/editors/space_node/node_add.c b/source/blender/editors/space_node/node_add.c
index 1d73937d762..95a37f85828 100644
--- a/source/blender/editors/space_node/node_add.c
+++ b/source/blender/editors/space_node/node_add.c
@@ -82,7 +82,7 @@ bNode *node_add_node(const bContext *C, const char *idname, int type, float locx
nodeSetSelected(node, true);
ntreeUpdateTree(bmain, snode->edittree);
- ED_node_set_active(bmain, snode->edittree, node);
+ ED_node_set_active(bmain, snode->edittree, node, NULL);
snode_update(snode, node);
diff --git a/source/blender/editors/space_node/node_buttons.c b/source/blender/editors/space_node/node_buttons.c
index ee1d2b43c5f..8fc343a9ed4 100644
--- a/source/blender/editors/space_node/node_buttons.c
+++ b/source/blender/editors/space_node/node_buttons.c
@@ -66,13 +66,13 @@ static bool node_sockets_poll(const bContext *C, PanelType *UNUSED(pt))
return (snode && snode->nodetree && G.debug_value == 777);
}
-static void node_sockets_panel(const bContext *C, Panel *pa)
+static void node_sockets_panel(const bContext *C, Panel *panel)
{
SpaceNode *snode = CTX_wm_space_node(C);
bNodeTree *ntree = (snode) ? snode->edittree : NULL;
bNode *node = (ntree) ? nodeGetActive(ntree) : NULL;
bNodeSocket *sock;
- uiLayout *layout = pa->layout, *split;
+ uiLayout *layout = panel->layout, *split;
char name[UI_MAX_NAME_STR];
if (ELEM(NULL, ntree, node)) {
@@ -84,7 +84,7 @@ static void node_sockets_panel(const bContext *C, Panel *pa)
split = uiLayoutSplit(layout, 0.35f, false);
uiItemL(split, name, ICON_NONE);
- uiTemplateNodeLink(split, ntree, node, sock);
+ uiTemplateNodeLink(split, (bContext *)C, ntree, node, sock);
}
}
@@ -119,13 +119,13 @@ static bool node_tree_find_active_socket(bNodeTree *ntree, bNodeSocket **r_sock,
return false;
}
-static void node_tree_interface_panel(const bContext *C, Panel *pa)
+static void node_tree_interface_panel(const bContext *C, Panel *panel)
{
SpaceNode *snode = CTX_wm_space_node(C);
bNodeTree *ntree = (snode) ? snode->edittree : NULL;
bNodeSocket *sock;
int in_out;
- uiLayout *layout = pa->layout, *row, *split, *col;
+ uiLayout *layout = panel->layout, *row, *split, *col;
PointerRNA ptr, sockptr, opptr;
wmOperatorType *ot;
diff --git a/source/blender/editors/space_node/node_draw.c b/source/blender/editors/space_node/node_draw.c
index 0552660b9bf..bd8950c5085 100644
--- a/source/blender/editors/space_node/node_draw.c
+++ b/source/blender/editors/space_node/node_draw.c
@@ -94,23 +94,11 @@ void ED_node_tree_update(const bContext *C)
static bNodeTree *node_tree_from_ID(ID *id)
{
if (id) {
- short idtype = GS(id->name);
-
- switch (idtype) {
- case ID_NT:
- return (bNodeTree *)id;
- case ID_MA:
- return ((Material *)id)->nodetree;
- case ID_LA:
- return ((Light *)id)->nodetree;
- case ID_WO:
- return ((World *)id)->nodetree;
- case ID_SCE:
- return ((Scene *)id)->nodetree;
- case ID_TE:
- return ((Tex *)id)->nodetree;
- case ID_LS:
- return ((FreestyleLineStyle *)id)->nodetree;
+ if (GS(id->name) == ID_NT) {
+ return (bNodeTree *)id;
+ }
+ else {
+ return ntreeFromID(id);
}
}
@@ -719,39 +707,19 @@ static void node_draw_mute_line(View2D *v2d, SpaceNode *snode, bNode *node)
#define MARKER_SHAPE_CIRCLE 0x2
#define MARKER_SHAPE_INNER_DOT 0x10
-static void node_socket_draw(const bContext *C,
- bNodeTree *ntree,
- PointerRNA node_ptr,
- bNodeSocket *sock,
+static void node_socket_draw(const bNodeSocket *sock,
+ const float color[4],
+ const float color_outline[4],
+ float size,
+ int locx,
+ int locy,
uint pos_id,
uint col_id,
uint shape_id,
uint size_id,
- uint outline_col_id,
- float size,
- bool selected)
+ uint outline_col_id)
{
- PointerRNA ptr;
- float color[4];
- float outline_color[4];
- uint flags = 0;
-
- RNA_pointer_create((ID *)ntree, &RNA_NodeSocket, sock, &ptr);
- sock->typeinfo->draw_color((bContext *)C, &ptr, &node_ptr, color);
-
- bNode *node = node_ptr.data;
- if (node->flag & NODE_MUTED) {
- color[3] *= 0.25f;
- }
-
- if (selected) {
- UI_GetThemeColor4fv(TH_TEXT_HI, outline_color);
- outline_color[3] = 0.9f;
- }
- else {
- copy_v4_fl(outline_color, 0.0f);
- outline_color[3] = 0.6f;
- }
+ int flags;
/* sets shape flags */
switch (sock->display_shape) {
@@ -780,8 +748,120 @@ static void node_socket_draw(const bContext *C,
immAttr4fv(col_id, color);
immAttr1u(shape_id, flags);
immAttr1f(size_id, size);
- immAttr4fv(outline_col_id, outline_color);
- immVertex2f(pos_id, sock->locx, sock->locy);
+ immAttr4fv(outline_col_id, color_outline);
+ immVertex2f(pos_id, locx, locy);
+}
+
+static void node_socket_outline_color_get(bool selected, float r_outline_color[4])
+{
+ if (selected) {
+ UI_GetThemeColor4fv(TH_TEXT_HI, r_outline_color);
+ r_outline_color[3] = 0.9f;
+ }
+ else {
+ copy_v4_fl(r_outline_color, 0.0f);
+ r_outline_color[3] = 0.6f;
+ }
+}
+
+/* Usual convention here would be node_socket_get_color(), but that's already used (for setting a
+ * color property socket). */
+void node_socket_color_get(
+ bContext *C, bNodeTree *ntree, PointerRNA *node_ptr, bNodeSocket *sock, float r_color[4])
+{
+ PointerRNA ptr;
+
+ BLI_assert(RNA_struct_is_a(node_ptr->type, &RNA_Node));
+ RNA_pointer_create((ID *)ntree, &RNA_NodeSocket, sock, &ptr);
+
+ sock->typeinfo->draw_color(C, &ptr, node_ptr, r_color);
+
+ bNode *node = node_ptr->data;
+ if (node->flag & NODE_MUTED) {
+ r_color[3] *= 0.25f;
+ }
+}
+
+static void node_socket_draw_nested(const bContext *C,
+ bNodeTree *ntree,
+ PointerRNA *node_ptr,
+ bNodeSocket *sock,
+ uint pos_id,
+ uint col_id,
+ uint shape_id,
+ uint size_id,
+ uint outline_col_id,
+ float size,
+ bool selected)
+{
+ float color[4];
+ float outline_color[4];
+
+ node_socket_color_get((bContext *)C, ntree, node_ptr, sock, color);
+ node_socket_outline_color_get(selected, outline_color);
+
+ node_socket_draw(sock,
+ color,
+ outline_color,
+ size,
+ sock->locx,
+ sock->locy,
+ pos_id,
+ col_id,
+ shape_id,
+ size_id,
+ outline_col_id);
+}
+
+/**
+ * Draw a single node socket at default size.
+ * \note this is only called from external code, internally #node_socket_draw_nested() is used for
+ * optimized drawing of multiple/all sockets of a node.
+ */
+void ED_node_socket_draw(bNodeSocket *sock, const rcti *rect, const float color[4], float scale)
+{
+ const float size = 2.25f * NODE_SOCKSIZE * scale;
+ rcti draw_rect = *rect;
+ float outline_color[4] = {0};
+
+ node_socket_outline_color_get(sock->flag & SELECT, outline_color);
+
+ BLI_rcti_resize(&draw_rect, size, size);
+
+ GPUVertFormat *format = immVertexFormat();
+ uint pos_id = GPU_vertformat_attr_add(format, "pos", GPU_COMP_F32, 2, GPU_FETCH_FLOAT);
+ uint col_id = GPU_vertformat_attr_add(format, "color", GPU_COMP_F32, 4, GPU_FETCH_FLOAT);
+ uint shape_id = GPU_vertformat_attr_add(format, "flags", GPU_COMP_U32, 1, GPU_FETCH_INT);
+ uint size_id = GPU_vertformat_attr_add(format, "size", GPU_COMP_F32, 1, GPU_FETCH_FLOAT);
+ uint outline_col_id = GPU_vertformat_attr_add(
+ format, "outlineColor", GPU_COMP_F32, 4, GPU_FETCH_FLOAT);
+
+ gpuPushAttr(GPU_BLEND_BIT);
+ GPU_blend(true);
+ GPU_program_point_size(true);
+
+ immBindBuiltinProgram(GPU_SHADER_KEYFRAME_DIAMOND);
+ immUniform1f("outline_scale", 0.7f);
+ immUniform2f("ViewportSize", -1.0f, -1.0f);
+
+ /* Single point */
+ immBegin(GPU_PRIM_POINTS, 1);
+ node_socket_draw(sock,
+ color,
+ outline_color,
+ BLI_rcti_size_y(&draw_rect),
+ BLI_rcti_cent_x(&draw_rect),
+ BLI_rcti_cent_y(&draw_rect),
+ pos_id,
+ col_id,
+ shape_id,
+ size_id,
+ outline_col_id);
+ immEnd();
+
+ immUnbindProgram();
+ GPU_program_point_size(false);
+ gpuPopAttr();
}
/* ************** Socket callbacks *********** */
@@ -974,17 +1054,17 @@ void node_draw_sockets(View2D *v2d,
continue;
}
- node_socket_draw(C,
- ntree,
- node_ptr,
- sock,
- pos_id,
- col_id,
- shape_id,
- size_id,
- outline_col_id,
- scale,
- selected);
+ node_socket_draw_nested(C,
+ ntree,
+ &node_ptr,
+ sock,
+ pos_id,
+ col_id,
+ shape_id,
+ size_id,
+ outline_col_id,
+ scale,
+ selected);
}
/* socket outputs */
@@ -999,17 +1079,17 @@ void node_draw_sockets(View2D *v2d,
continue;
}
- node_socket_draw(C,
- ntree,
- node_ptr,
- sock,
- pos_id,
- col_id,
- shape_id,
- size_id,
- outline_col_id,
- scale,
- selected);
+ node_socket_draw_nested(C,
+ ntree,
+ &node_ptr,
+ sock,
+ pos_id,
+ col_id,
+ shape_id,
+ size_id,
+ outline_col_id,
+ scale,
+ selected);
}
}
@@ -1032,17 +1112,17 @@ void node_draw_sockets(View2D *v2d,
continue;
}
if (select_all || (sock->flag & SELECT)) {
- node_socket_draw(C,
- ntree,
- node_ptr,
- sock,
- pos_id,
- col_id,
- shape_id,
- size_id,
- outline_col_id,
- scale,
- selected);
+ node_socket_draw_nested(C,
+ ntree,
+ &node_ptr,
+ sock,
+ pos_id,
+ col_id,
+ shape_id,
+ size_id,
+ outline_col_id,
+ scale,
+ selected);
if (--selected_input_len == 0) {
break; /* stop as soon as last one is drawn */
}
@@ -1057,17 +1137,17 @@ void node_draw_sockets(View2D *v2d,
continue;
}
if (select_all || (sock->flag & SELECT)) {
- node_socket_draw(C,
- ntree,
- node_ptr,
- sock,
- pos_id,
- col_id,
- shape_id,
- size_id,
- outline_col_id,
- scale,
- selected);
+ node_socket_draw_nested(C,
+ ntree,
+ &node_ptr,
+ sock,
+ pos_id,
+ col_id,
+ shape_id,
+ size_id,
+ outline_col_id,
+ scale,
+ selected);
if (--selected_output_len == 0) {
break; /* stop as soon as last one is drawn */
}
diff --git a/source/blender/editors/space_node/node_edit.c b/source/blender/editors/space_node/node_edit.c
index e50f5a818aa..ac58ec1e636 100644
--- a/source/blender/editors/space_node/node_edit.c
+++ b/source/blender/editors/space_node/node_edit.c
@@ -69,6 +69,7 @@
#include "NOD_composite.h"
#include "NOD_shader.h"
+#include "NOD_simulation.h"
#include "NOD_texture.h"
#include "node_intern.h" /* own include */
@@ -127,12 +128,12 @@ static int compo_get_recalc_flags(const bContext *C)
int recalc_flags = 0;
for (win = wm->windows.first; win; win = win->next) {
- const bScreen *sc = WM_window_get_active_screen(win);
- ScrArea *sa;
+ const bScreen *screen = WM_window_get_active_screen(win);
+ ScrArea *area;
- for (sa = sc->areabase.first; sa; sa = sa->next) {
- if (sa->spacetype == SPACE_IMAGE) {
- SpaceImage *sima = sa->spacedata.first;
+ for (area = screen->areabase.first; area; area = area->next) {
+ if (area->spacetype == SPACE_IMAGE) {
+ SpaceImage *sima = area->spacedata.first;
if (sima->image) {
if (sima->image->type == IMA_TYPE_R_RESULT) {
recalc_flags |= COM_RECALC_COMPOSITE;
@@ -142,8 +143,8 @@ static int compo_get_recalc_flags(const bContext *C)
}
}
}
- else if (sa->spacetype == SPACE_NODE) {
- SpaceNode *snode = sa->spacedata.first;
+ else if (area->spacetype == SPACE_NODE) {
+ SpaceNode *snode = area->spacedata.first;
if (snode->flag & SNODE_BACKDRAW) {
recalc_flags |= COM_RECALC_VIEWER;
}
@@ -438,6 +439,11 @@ bool ED_node_is_texture(struct SpaceNode *snode)
return STREQ(snode->tree_idname, ntreeType_Texture->idname);
}
+bool ED_node_is_simulation(struct SpaceNode *snode)
+{
+ return STREQ(snode->tree_idname, ntreeType_Simulation->idname);
+}
+
/* assumes nothing being done in ntree yet, sets the default in/out node */
/* called from shading buttons or header */
void ED_node_shader_default(const bContext *C, ID *id)
@@ -642,9 +648,12 @@ void snode_update(SpaceNode *snode, bNode *node)
}
}
-void ED_node_set_active(Main *bmain, bNodeTree *ntree, bNode *node)
+void ED_node_set_active(Main *bmain, bNodeTree *ntree, bNode *node, bool *r_active_texture_changed)
{
const bool was_active_texture = (node->flag & NODE_ACTIVE_TEXTURE) != 0;
+ if (r_active_texture_changed) {
+ *r_active_texture_changed = false;
+ }
nodeSetActive(ntree, node);
@@ -713,6 +722,9 @@ void ED_node_set_active(Main *bmain, bNodeTree *ntree, bNode *node)
}
}
+ if (r_active_texture_changed) {
+ *r_active_texture_changed = true;
+ }
ED_node_tag_update_nodetree(bmain, ntree, node);
WM_main_add_notifier(NC_IMAGE, NULL);
}
@@ -1284,7 +1296,7 @@ static int node_duplicate_exec(bContext *C, wmOperator *op)
newnode = node->new_node;
nodeSetSelected(node, false);
- node->flag &= ~NODE_ACTIVE;
+ node->flag &= ~(NODE_ACTIVE | NODE_ACTIVE_TEXTURE);
nodeSetSelected(newnode, true);
do_tag_update |= (do_tag_update || node_connected_to_output(bmain, ntree, newnode));
@@ -1326,7 +1338,7 @@ void NODE_OT_duplicate(wmOperatorType *ot)
bool ED_node_select_check(ListBase *lb)
{
- for (bNode *node = lb->first; node; node = node->next) {
+ LISTBASE_FOREACH (bNode *, node, lb) {
if (node->flag & NODE_SELECT) {
return true;
}
@@ -1346,7 +1358,7 @@ void ED_node_select_all(ListBase *lb, int action)
}
}
- for (bNode *node = lb->first; node; node = node->next) {
+ LISTBASE_FOREACH (bNode *, node, lb) {
switch (action) {
case SEL_SELECT:
nodeSetSelected(node, true);
diff --git a/source/blender/editors/space_node/node_group.c b/source/blender/editors/space_node/node_group.c
index 2a4c6147d5d..2617384d046 100644
--- a/source/blender/editors/space_node/node_group.c
+++ b/source/blender/editors/space_node/node_group.c
@@ -69,7 +69,8 @@ static bool node_group_operator_active(bContext *C)
*/
if (STREQ(snode->tree_idname, "ShaderNodeTree") ||
STREQ(snode->tree_idname, "CompositorNodeTree") ||
- STREQ(snode->tree_idname, "TextureNodeTree")) {
+ STREQ(snode->tree_idname, "TextureNodeTree") ||
+ STREQ(snode->tree_idname, "SimulationNodeTree")) {
return true;
}
}
@@ -85,7 +86,8 @@ static bool node_group_operator_editable(bContext *C)
* Disabled otherwise to allow pynodes define their own operators
* with same keymap.
*/
- if (ED_node_is_shader(snode) || ED_node_is_compositor(snode) || ED_node_is_texture(snode)) {
+ if (ED_node_is_shader(snode) || ED_node_is_compositor(snode) || ED_node_is_texture(snode) ||
+ ED_node_is_simulation(snode)) {
return true;
}
}
@@ -111,6 +113,9 @@ static const char *group_node_idname(bContext *C)
else if (ED_node_is_texture(snode)) {
return "TextureNodeGroup";
}
+ else if (ED_node_is_simulation(snode)) {
+ return "SimulationNodeGroup";
+ }
return "";
}
@@ -193,11 +198,11 @@ static int node_group_ungroup(Main *bmain, bNodeTree *ntree, bNode *gnode)
}
/* wgroup is a temporary copy of the NodeTree we're merging in
- * - all of wgroup's nodes are transferred across to their new home
+ * - all of wgroup's nodes are copied across to their new home
* - ngroup (i.e. the source NodeTree) is left unscathed
- * - temp copy. don't change ID usercount
+ * - temp copy. do change ID usercount for the copies
*/
- wgroup = ntreeCopyTree_ex_new_pointers(ngroup, bmain, false);
+ wgroup = ntreeCopyTree_ex_new_pointers(ngroup, bmain, true);
/* Add the nodes into the ntree */
for (node = wgroup->nodes.first; node; node = nextnode) {
@@ -351,8 +356,8 @@ static int node_group_ungroup(Main *bmain, bNodeTree *ntree, bNode *gnode)
nodeRemoveNode(bmain, ntree, node, false);
}
- /* delete the group instance */
- nodeRemoveNode(bmain, ntree, gnode, false);
+ /* delete the group instance and dereference group tree */
+ nodeRemoveNode(bmain, ntree, gnode, true);
ntree->update |= NTREE_UPDATE_NODES | NTREE_UPDATE_LINKS;
diff --git a/source/blender/editors/space_node/node_intern.h b/source/blender/editors/space_node/node_intern.h
index 8c7c490b181..04186c3a727 100644
--- a/source/blender/editors/space_node/node_intern.h
+++ b/source/blender/editors/space_node/node_intern.h
@@ -38,6 +38,7 @@ struct bContext;
struct bNode;
struct bNodeLink;
struct bNodeSocket;
+struct wmGizmoGroupType;
struct wmKeyConfig;
struct wmWindow;
@@ -77,6 +78,11 @@ void node_draw_sockets(struct View2D *v2d,
void node_update_default(const struct bContext *C, struct bNodeTree *ntree, struct bNode *node);
int node_select_area_default(struct bNode *node, int x, int y);
int node_tweak_area_default(struct bNode *node, int x, int y);
+void node_socket_color_get(struct bContext *C,
+ struct bNodeTree *ntree,
+ struct PointerRNA *node_ptr,
+ struct bNodeSocket *sock,
+ float r_color[4]);
void node_update_nodetree(const struct bContext *C, struct bNodeTree *ntree);
void node_draw_nodetree(const struct bContext *C,
struct ARegion *region,
@@ -122,7 +128,7 @@ void NODE_OT_find_node(struct wmOperatorType *ot);
/* node_view.c */
int space_node_view_flag(struct bContext *C,
- SpaceNode *snode,
+ struct SpaceNode *snode,
ARegion *region,
const int node_flag,
const int smooth_viewtx);
@@ -196,7 +202,7 @@ void NODE_OT_detach(struct wmOperatorType *ot);
void NODE_OT_link_viewer(struct wmOperatorType *ot);
-void NODE_OT_insert_offset(wmOperatorType *ot);
+void NODE_OT_insert_offset(struct wmOperatorType *ot);
/* node_edit.c */
void snode_notify(struct bContext *C, struct SpaceNode *snode);
@@ -207,8 +213,8 @@ void snode_update(struct SpaceNode *snode, struct bNode *node);
bool composite_node_active(struct bContext *C);
bool composite_node_editable(struct bContext *C);
-int node_has_hidden_sockets(bNode *node);
-void node_set_hidden_sockets(SpaceNode *snode, bNode *node, int set);
+int node_has_hidden_sockets(struct bNode *node);
+void node_set_hidden_sockets(struct SpaceNode *snode, bNode *node, int set);
int node_render_changed_exec(bContext *, struct wmOperator *);
int node_find_indicated_socket(struct SpaceNode *snode,
struct bNode **nodep,
@@ -271,7 +277,7 @@ extern const char *node_context_dir[];
#define NODE_SOCKDY (0.08f * U.widget_unit)
#define NODE_WIDTH(node) (node->width * UI_DPI_FAC)
#define NODE_HEIGHT(node) (node->height * UI_DPI_FAC)
-#define NODE_MARGIN_X (0.75f * U.widget_unit)
+#define NODE_MARGIN_X (0.95f * U.widget_unit)
#define NODE_SOCKSIZE (0.25f * U.widget_unit)
#define NODE_RESIZE_MARGIN (0.20f * U.widget_unit)
#define NODE_LINK_RESOL 12
diff --git a/source/blender/editors/space_node/node_relationships.c b/source/blender/editors/space_node/node_relationships.c
index 5dc98a3905a..144e3bd3506 100644
--- a/source/blender/editors/space_node/node_relationships.c
+++ b/source/blender/editors/space_node/node_relationships.c
@@ -30,7 +30,7 @@
#include "BLI_easing.h"
#include "BLI_math.h"
-#include "BKE_animsys.h"
+#include "BKE_anim_data.h"
#include "BKE_context.h"
#include "BKE_lib_id.h"
#include "BKE_main.h"
@@ -466,7 +466,7 @@ static int node_link_viewer(const bContext *C, bNode *tonode)
if (tonode) {
/* Find a selected socket that overrides the socket to connect to */
- for (bNodeSocket *sock2 = tonode->outputs.first; sock2; sock2 = sock2->next) {
+ LISTBASE_FOREACH (bNodeSocket *, sock2, &tonode->outputs) {
if (!nodeSocketIsHidden(sock2) && sock2->flag & SELECT) {
sock = sock2;
break;
@@ -1446,9 +1446,12 @@ void NODE_OT_detach(wmOperatorType *ot)
/* ********************* automatic node insert on dragging ******************* */
/* prevent duplicate testing code below */
-static bool ed_node_link_conditions(ScrArea *sa, bool test, SpaceNode **r_snode, bNode **r_select)
+static bool ed_node_link_conditions(ScrArea *area,
+ bool test,
+ SpaceNode **r_snode,
+ bNode **r_select)
{
- SpaceNode *snode = sa ? sa->spacedata.first : NULL;
+ SpaceNode *snode = area ? area->spacedata.first : NULL;
bNode *node, *select = NULL;
bNodeLink *link;
@@ -1456,7 +1459,7 @@ static bool ed_node_link_conditions(ScrArea *sa, bool test, SpaceNode **r_snode,
*r_select = NULL;
/* no unlucky accidents */
- if (sa == NULL || sa->spacetype != SPACE_NODE) {
+ if (area == NULL || area->spacetype != SPACE_NODE) {
return false;
}
@@ -1501,14 +1504,14 @@ static bool ed_node_link_conditions(ScrArea *sa, bool test, SpaceNode **r_snode,
}
/* test == 0, clear all intersect flags */
-void ED_node_link_intersect_test(ScrArea *sa, int test)
+void ED_node_link_intersect_test(ScrArea *area, int test)
{
bNode *select;
SpaceNode *snode;
bNodeLink *link, *selink = NULL;
float dist_best = FLT_MAX;
- if (!ed_node_link_conditions(sa, test, &snode, &select)) {
+ if (!ed_node_link_conditions(area, test, &snode, &select)) {
return;
}
@@ -1619,8 +1622,8 @@ static void node_parent_offset_apply(NodeInsertOfsData *data, bNode *parent, con
node_offset_apply(parent, offset_x);
- /* flag all childs as offset to prevent them from being offset
- * separately (they've already moved with the parent) */
+ /* Flag all children as offset to prevent them from being offset
+ * separately (they've already moved with the parent). */
for (node = data->ntree->nodes.first; node; node = node->next) {
if (nodeIsChildOf(parent, node)) {
/* NODE_TEST is used to flag nodes that shouldn't be offset (again) */
@@ -1654,7 +1657,7 @@ static bool node_link_insert_offset_frame_chain_cb(bNode *fromnode,
}
/**
- * Applies NodeInsertOfsData.offset_x to all childs of \a parent
+ * Applies #NodeInsertOfsData.offset_x to all children of \a parent.
*/
static void node_link_insert_offset_frame_chains(const bNodeTree *ntree,
const bNode *parent,
@@ -1919,14 +1922,14 @@ void NODE_OT_insert_offset(wmOperatorType *ot)
}
/* assumes link with NODE_LINKFLAG_HILITE set */
-void ED_node_link_insert(Main *bmain, ScrArea *sa)
+void ED_node_link_insert(Main *bmain, ScrArea *area)
{
bNode *node, *select;
SpaceNode *snode;
bNodeLink *link;
bNodeSocket *sockto;
- if (!ed_node_link_conditions(sa, true, &snode, &select)) {
+ if (!ed_node_link_conditions(area, true, &snode, &select)) {
return;
}
diff --git a/source/blender/editors/space_node/node_select.c b/source/blender/editors/space_node/node_select.c
index 98fcf862290..06f568c80f3 100644
--- a/source/blender/editors/space_node/node_select.c
+++ b/source/blender/editors/space_node/node_select.c
@@ -24,8 +24,10 @@
#include <stdlib.h>
#include "DNA_node_types.h"
+#include "DNA_windowmanager_types.h"
#include "BLI_lasso_2d.h"
+#include "BLI_listbase.h"
#include "BLI_math.h"
#include "BLI_rect.h"
#include "BLI_string.h"
@@ -35,10 +37,12 @@
#include "BKE_context.h"
#include "BKE_main.h"
#include "BKE_node.h"
+#include "BKE_workspace.h"
#include "ED_node.h" /* own include */
#include "ED_screen.h"
#include "ED_select_utils.h"
+#include "ED_view3d.h"
#include "RNA_access.h"
#include "RNA_define.h"
@@ -50,10 +54,42 @@
#include "UI_resources.h"
#include "UI_view2d.h"
+#include "DEG_depsgraph.h"
+
#include "MEM_guardedalloc.h"
#include "node_intern.h" /* own include */
+/* Function to detect if there is a visible view3d that uses workbench in texture mode.
+ * This function is for fixing T76970 for Blender 2.83. The actual fix should add a mechanism in
+ * the depsgraph that can be used by the draw engines to check if they need to be redrawn.
+ *
+ * We don't want to add these risky changes this close before releasing 2.83 without good testing
+ * hence this workaround. There are still cases were too many updates happen. For example when you
+ * have both a Cycles and workbench with textures viewport.
+ * */
+static bool has_workbench_in_texture_color(const wmWindowManager *wm,
+ const Scene *scene,
+ const Object *ob)
+{
+ LISTBASE_FOREACH (wmWindow *, win, &wm->windows) {
+ if (win->scene != scene) {
+ continue;
+ }
+ const bScreen *screen = BKE_workspace_active_screen_get(win->workspace_hook);
+ LISTBASE_FOREACH (ScrArea *, area, &screen->areabase) {
+ if (area->spacetype == SPACE_VIEW3D) {
+ const View3D *v3d = area->spacedata.first;
+
+ if (ED_view3d_has_workbench_in_texture_color(scene, ob, v3d)) {
+ return true;
+ }
+ }
+ }
+ }
+ return false;
+}
+
/* -------------------------------------------------------------------- */
/** \name Public Node Selection API
* \{ */
@@ -284,7 +320,7 @@ static bool node_select_grouped_name(SpaceNode *snode, bNode *node_act, const bo
{
bNode *node;
bool changed = false;
- const unsigned int delims[] = {'.', '-', '_', '\0'};
+ const uint delims[] = {'.', '-', '_', '\0'};
size_t pref_len_act, pref_len_curr;
const char *sep, *suf_act, *suf_curr;
@@ -412,6 +448,10 @@ void node_select_single(bContext *C, bNode *node)
{
Main *bmain = CTX_data_main(C);
SpaceNode *snode = CTX_wm_space_node(C);
+ const Object *ob = CTX_data_active_object(C);
+ const Scene *scene = CTX_data_scene(C);
+ const wmWindowManager *wm = CTX_wm_manager(C);
+ bool active_texture_changed = false;
bNode *tnode;
for (tnode = snode->edittree->nodes.first; tnode; tnode = tnode->next) {
@@ -421,10 +461,13 @@ void node_select_single(bContext *C, bNode *node)
}
nodeSetSelected(node, true);
- ED_node_set_active(bmain, snode->edittree, node);
+ ED_node_set_active(bmain, snode->edittree, node, &active_texture_changed);
ED_node_set_active_viewer_key(snode);
ED_node_sort(snode->edittree);
+ if (active_texture_changed && has_workbench_in_texture_color(wm, scene, ob)) {
+ DEG_id_tag_update(&snode->edittree->id, ID_RECALC_COPY_ON_WRITE);
+ }
WM_event_add_notifier(C, NC_NODE | NA_SELECTED, NULL);
}
@@ -437,6 +480,9 @@ static int node_mouse_select(bContext *C,
Main *bmain = CTX_data_main(C);
SpaceNode *snode = CTX_wm_space_node(C);
ARegion *region = CTX_wm_region(C);
+ const Object *ob = CTX_data_active_object(C);
+ const Scene *scene = CTX_data_scene(C);
+ const wmWindowManager *wm = CTX_wm_manager(C);
bNode *node, *tnode;
bNodeSocket *sock = NULL;
bNodeSocket *tsock;
@@ -543,11 +589,15 @@ static int node_mouse_select(bContext *C,
/* update node order */
if (ret_value != OPERATOR_CANCELLED) {
+ bool active_texture_changed = false;
if (node != NULL && ret_value != OPERATOR_RUNNING_MODAL) {
- ED_node_set_active(bmain, snode->edittree, node);
+ ED_node_set_active(bmain, snode->edittree, node, &active_texture_changed);
}
ED_node_set_active_viewer_key(snode);
ED_node_sort(snode->edittree);
+ if (active_texture_changed && has_workbench_in_texture_color(wm, scene, ob)) {
+ DEG_id_tag_update(&snode->edittree->id, ID_RECALC_COPY_ON_WRITE);
+ }
WM_event_add_notifier(C, NC_NODE | NA_SELECTED, NULL);
}
@@ -622,7 +672,7 @@ static int node_box_select_exec(bContext *C, wmOperator *op)
ED_node_select_all(&snode->edittree->nodes, SEL_DESELECT);
}
- for (bNode *node = snode->edittree->nodes.first; node; node = node->next) {
+ LISTBASE_FOREACH (bNode *, node, &snode->edittree->nodes) {
bool is_inside;
if (node->type == NODE_FRAME) {
is_inside = BLI_rctf_inside_rctf(&rectf, &node->totr);
@@ -765,7 +815,10 @@ static int node_lasso_select_invoke(bContext *C, wmOperator *op, const wmEvent *
return WM_gesture_lasso_invoke(C, op, event);
}
-static bool do_lasso_select_node(bContext *C, const int mcords[][2], short moves, eSelectOp sel_op)
+static bool do_lasso_select_node(bContext *C,
+ const int mcoords[][2],
+ const int mcoords_len,
+ eSelectOp sel_op)
{
SpaceNode *snode = CTX_wm_space_node(C);
bNode *node;
@@ -782,7 +835,7 @@ static bool do_lasso_select_node(bContext *C, const int mcords[][2], short moves
}
/* get rectangle from operator */
- BLI_lasso_boundbox(&rect, mcords, moves);
+ BLI_lasso_boundbox(&rect, mcoords, mcoords_len);
/* do actual selection */
for (node = snode->edittree->nodes.first; node; node = node->next) {
@@ -798,7 +851,7 @@ static bool do_lasso_select_node(bContext *C, const int mcords[][2], short moves
if (UI_view2d_view_to_region_clip(
&region->v2d, cent[0], cent[1], &screen_co[0], &screen_co[1]) &&
BLI_rcti_isect_pt(&rect, screen_co[0], screen_co[1]) &&
- BLI_lasso_is_point_inside(mcords, moves, screen_co[0], screen_co[1], INT_MAX)) {
+ BLI_lasso_is_point_inside(mcoords, mcoords_len, screen_co[0], screen_co[1], INT_MAX)) {
nodeSetSelected(node, select);
changed = true;
}
@@ -813,15 +866,15 @@ static bool do_lasso_select_node(bContext *C, const int mcords[][2], short moves
static int node_lasso_select_exec(bContext *C, wmOperator *op)
{
- int mcords_tot;
- const int(*mcords)[2] = WM_gesture_lasso_path_to_array(C, op, &mcords_tot);
+ int mcoords_len;
+ const int(*mcoords)[2] = WM_gesture_lasso_path_to_array(C, op, &mcoords_len);
- if (mcords) {
+ if (mcoords) {
const eSelectOp sel_op = RNA_enum_get(op->ptr, "mode");
- do_lasso_select_node(C, mcords, mcords_tot, sel_op);
+ do_lasso_select_node(C, mcoords, mcoords_len, sel_op);
- MEM_freeN((void *)mcords);
+ MEM_freeN((void *)mcoords);
return OPERATOR_FINISHED;
}
@@ -1112,10 +1165,10 @@ void NODE_OT_select_same_type_step(wmOperatorType *ot)
* \{ */
/* generic search invoke */
-static void node_find_cb(const struct bContext *C,
- void *UNUSED(arg),
- const char *str,
- uiSearchItems *items)
+static void node_find_update_fn(const struct bContext *C,
+ void *UNUSED(arg),
+ const char *str,
+ uiSearchItems *items)
{
SpaceNode *snode = CTX_wm_space_node(C);
bNode *node;
@@ -1138,7 +1191,7 @@ static void node_find_cb(const struct bContext *C,
}
}
-static void node_find_call_cb(struct bContext *C, void *UNUSED(arg1), void *arg2)
+static void node_find_exec_fn(struct bContext *C, void *UNUSED(arg1), void *arg2)
{
SpaceNode *snode = CTX_wm_space_node(C);
bNode *active = arg2;
@@ -1178,7 +1231,7 @@ static uiBlock *node_find_menu(bContext *C, ARegion *region, void *arg_op)
0,
0,
"");
- UI_but_func_search_set(but, NULL, node_find_cb, op->type, NULL, node_find_call_cb, NULL);
+ UI_but_func_search_set(but, NULL, node_find_update_fn, op->type, NULL, node_find_exec_fn, NULL);
UI_but_flag_enable(but, UI_BUT_ACTIVATE_ON_INIT);
/* fake button, it holds space for search items */
diff --git a/source/blender/editors/space_node/node_templates.c b/source/blender/editors/space_node/node_templates.c
index 7d4095326f8..87b1f662b59 100644
--- a/source/blender/editors/space_node/node_templates.c
+++ b/source/blender/editors/space_node/node_templates.c
@@ -45,6 +45,7 @@
#include "UI_interface.h"
#include "ED_node.h" /* own include */
+#include "node_intern.h"
#include "ED_undo.h"
@@ -662,17 +663,23 @@ static void ui_template_node_link_menu(bContext *C, uiLayout *layout, void *but_
ui_node_menu_column(arg, NODE_CLASS_GROUP, N_("Group"));
}
-void uiTemplateNodeLink(uiLayout *layout, bNodeTree *ntree, bNode *node, bNodeSocket *sock)
+void uiTemplateNodeLink(
+ uiLayout *layout, bContext *C, bNodeTree *ntree, bNode *node, bNodeSocket *sock)
{
uiBlock *block = uiLayoutGetBlock(layout);
NodeLinkArg *arg;
uiBut *but;
+ float socket_col[4];
arg = MEM_callocN(sizeof(NodeLinkArg), "NodeLinkArg");
arg->ntree = ntree;
arg->node = node;
arg->sock = sock;
+ PointerRNA node_ptr;
+ RNA_pointer_create((ID *)ntree, &RNA_Node, node, &node_ptr);
+ node_socket_color_get(C, ntree, &node_ptr, sock, socket_col);
+
UI_block_layout_set_current(block, layout);
if (sock->link || sock->type == SOCK_SHADER || (sock->flag & SOCK_HIDE_VALUE)) {
@@ -687,8 +694,9 @@ void uiTemplateNodeLink(uiLayout *layout, bNodeTree *ntree, bNode *node, bNodeSo
}
UI_but_type_set_menu_from_pulldown(but);
+ UI_but_node_link_set(but, sock, socket_col);
+ UI_but_drawflag_enable(but, UI_BUT_ICON_LEFT);
- but->flag |= UI_BUT_NODE_LINK;
but->poin = (char *)but;
but->func_argN = arg;
@@ -708,18 +716,14 @@ static void ui_node_draw_node(
uiLayout *layout, bContext *C, bNodeTree *ntree, bNode *node, int depth)
{
bNodeSocket *input;
- uiLayout *col, *split;
PointerRNA nodeptr;
RNA_pointer_create(&ntree->id, &RNA_Node, node, &nodeptr);
if (node->typeinfo->draw_buttons) {
if (node->type != NODE_GROUP) {
- split = uiLayoutSplit(layout, 0.5f, false);
- col = uiLayoutColumn(split, false);
- col = uiLayoutColumn(split, false);
-
- node->typeinfo->draw_buttons(col, C, &nodeptr);
+ uiLayoutSetPropSep(layout, true);
+ node->typeinfo->draw_buttons(layout, C, &nodeptr);
}
}
@@ -733,12 +737,9 @@ static void ui_node_draw_input(
{
PointerRNA inputptr, nodeptr;
uiBlock *block = uiLayoutGetBlock(layout);
- uiBut *bt;
- uiLayout *split, *row, *col;
+ uiLayout *row = NULL;
bNode *lnode;
- char label[UI_MAX_NAME_STR];
- int i, indent = (depth > 1) ? 2 * (depth - 1) : 0;
- int dependency_loop;
+ bool dependency_loop;
if (input->flag & SOCK_UNAVAIL) {
return;
@@ -757,48 +758,43 @@ static void ui_node_draw_input(
RNA_pointer_create(&ntree->id, &RNA_NodeSocket, input, &inputptr);
RNA_pointer_create(&ntree->id, &RNA_Node, node, &nodeptr);
- /* indented label */
- for (i = 0; i < indent; i++) {
- label[i] = ' ';
- }
- label[indent] = '\0';
- BLI_snprintf(label + indent, UI_MAX_NAME_STR - indent, "%s", IFACE_(input->name));
+ row = uiLayoutRow(layout, true);
+ /* Decorations are added manually here. */
+ uiLayoutSetPropDecorate(row, false);
- /* split in label and value */
- split = uiLayoutSplit(layout, 0.5f, false);
+ uiPropertySplitWrapper split_wrapper = uiItemPropertySplitWrapperCreate(row);
+ /* Empty decorator item for alignment. */
+ bool add_dummy_decorator = false;
- row = uiLayoutRow(split, true);
+ {
+ uiLayout *sub = uiLayoutRow(split_wrapper.label_column, true);
- if (depth > 0) {
- UI_block_emboss_set(block, UI_EMBOSS_NONE);
+ if (depth > 0) {
+ UI_block_emboss_set(block, UI_EMBOSS_NONE);
- if (lnode &&
- (lnode->inputs.first || (lnode->typeinfo->draw_buttons && lnode->type != NODE_GROUP))) {
- int icon = (input->flag & SOCK_COLLAPSED) ? ICON_DISCLOSURE_TRI_RIGHT :
- ICON_DISCLOSURE_TRI_DOWN;
- uiItemR(row, &inputptr, "show_expanded", UI_ITEM_R_ICON_ONLY, "", icon);
- }
- else {
- uiItemL(row, "", ICON_BLANK1);
- }
+ if (lnode &&
+ (lnode->inputs.first || (lnode->typeinfo->draw_buttons && lnode->type != NODE_GROUP))) {
+ int icon = (input->flag & SOCK_COLLAPSED) ? ICON_DISCLOSURE_TRI_RIGHT :
+ ICON_DISCLOSURE_TRI_DOWN;
+ uiItemR(sub, &inputptr, "show_expanded", UI_ITEM_R_ICON_ONLY, "", icon);
+ }
- bt = block->buttons.last;
- bt->rect.xmax = UI_UNIT_X / 2;
+ UI_block_emboss_set(block, UI_EMBOSS);
+ }
- UI_block_emboss_set(block, UI_EMBOSS);
+ sub = uiLayoutRow(sub, true);
+ uiLayoutSetAlignment(sub, UI_LAYOUT_ALIGN_RIGHT);
+ uiItemL(sub, IFACE_(input->name), ICON_NONE);
}
- uiItemL(row, label, ICON_NONE);
- bt = block->buttons.last;
- bt->drawflag = UI_BUT_TEXT_RIGHT;
-
if (dependency_loop) {
- row = uiLayoutRow(split, false);
uiItemL(row, IFACE_("Dependency Loop"), ICON_ERROR);
+ add_dummy_decorator = true;
}
else if (lnode) {
/* input linked to a node */
- uiTemplateNodeLink(split, ntree, node, input);
+ uiTemplateNodeLink(row, C, ntree, node, input);
+ add_dummy_decorator = true;
if (depth == 0 || !(input->flag & SOCK_COLLAPSED)) {
if (depth == 0) {
@@ -809,33 +805,41 @@ static void ui_node_draw_input(
}
}
else {
+ row = uiLayoutRow(row, true);
+
+ uiTemplateNodeLink(row, C, ntree, node, input);
+
+ if (input->flag & SOCK_HIDE_VALUE) {
+ add_dummy_decorator = true;
+ }
/* input not linked, show value */
- if (!(input->flag & SOCK_HIDE_VALUE)) {
+ else {
+ uiLayout *sub = row;
+
switch (input->type) {
+ case SOCK_VECTOR:
+ if (input->type == SOCK_VECTOR) {
+ uiItemS(row);
+ sub = uiLayoutColumn(row, true);
+ }
+ ATTR_FALLTHROUGH;
case SOCK_FLOAT:
case SOCK_INT:
case SOCK_BOOLEAN:
case SOCK_RGBA:
case SOCK_STRING:
- row = uiLayoutRow(split, true);
- uiItemR(row, &inputptr, "default_value", 0, "", ICON_NONE);
- break;
- case SOCK_VECTOR:
- row = uiLayoutRow(split, false);
- col = uiLayoutColumn(row, false);
- uiItemR(col, &inputptr, "default_value", 0, "", ICON_NONE);
+ uiItemR(sub, &inputptr, "default_value", 0, "", ICON_NONE);
+ uiItemDecoratorR(
+ split_wrapper.decorate_column, &inputptr, "default_value", RNA_NO_INDEX);
break;
-
default:
- row = uiLayoutRow(split, false);
- break;
+ add_dummy_decorator = true;
}
}
- else {
- row = uiLayoutRow(split, false);
- }
+ }
- uiTemplateNodeLink(row, ntree, node, input);
+ if (add_dummy_decorator) {
+ uiItemDecoratorR(split_wrapper.decorate_column, NULL, NULL, 0);
}
/* clear */
diff --git a/source/blender/editors/space_node/node_view.c b/source/blender/editors/space_node/node_view.c
index 9283b073e86..e879e01ecc4 100644
--- a/source/blender/editors/space_node/node_view.c
+++ b/source/blender/editors/space_node/node_view.c
@@ -141,7 +141,7 @@ static int node_view_all_exec(bContext *C, wmOperator *op)
void NODE_OT_view_all(wmOperatorType *ot)
{
/* identifiers */
- ot->name = "View All";
+ ot->name = "Frame All";
ot->idname = "NODE_OT_view_all";
ot->description = "Resize view so you can see all nodes";
@@ -209,6 +209,7 @@ static int snode_bg_viewmove_modal(bContext *C, wmOperator *op, const wmEvent *e
ED_region_tag_redraw(region);
WM_main_add_notifier(NC_NODE | ND_DISPLAY, NULL);
+ WM_main_add_notifier(NC_SPACE | ND_SPACE_NODE_VIEW, NULL);
break;
@@ -354,6 +355,7 @@ static int backimage_fit_exec(bContext *C, wmOperator *UNUSED(op))
ED_region_tag_redraw(region);
WM_main_add_notifier(NC_NODE | ND_DISPLAY, NULL);
+ WM_main_add_notifier(NC_SPACE | ND_SPACE_NODE_VIEW, NULL);
return OPERATOR_FINISHED;
}
@@ -382,7 +384,7 @@ typedef struct ImageSampleInfo {
int x, y;
int channels;
- unsigned char col[4];
+ uchar col[4];
float colf[4];
float linearcol[4];
@@ -450,7 +452,7 @@ bool ED_space_node_color_sample(
if (fx >= 0.0f && fy >= 0.0f && fx < 1.0f && fy < 1.0f) {
const float *fp;
- unsigned char *cp;
+ uchar *cp;
int x = (int)(fx * ibuf->x), y = (int)(fy * ibuf->y);
CLAMP(x, 0, ibuf->x - 1);
@@ -463,7 +465,7 @@ bool ED_space_node_color_sample(
ret = true;
}
else if (ibuf->rect) {
- cp = (unsigned char *)(ibuf->rect + y * ibuf->x + x);
+ cp = (uchar *)(ibuf->rect + y * ibuf->x + x);
rgb_uchar_to_float(r_col, cp);
IMB_colormanagement_colorspace_to_scene_linear_v3(r_col, ibuf->rect_colorspace);
ret = true;
@@ -507,7 +509,7 @@ static void sample_apply(bContext *C, wmOperator *op, const wmEvent *event)
if (fx >= 0.0f && fy >= 0.0f && fx < 1.0f && fy < 1.0f) {
const float *fp;
- unsigned char *cp;
+ uchar *cp;
int x = (int)(fx * ibuf->x), y = (int)(fy * ibuf->y);
CLAMP(x, 0, ibuf->x - 1);
@@ -522,7 +524,7 @@ static void sample_apply(bContext *C, wmOperator *op, const wmEvent *event)
info->zfp = NULL;
if (ibuf->rect) {
- cp = (unsigned char *)(ibuf->rect + y * ibuf->x + x);
+ cp = (uchar *)(ibuf->rect + y * ibuf->x + x);
info->col[0] = cp[0];
info->col[1] = cp[1];
diff --git a/source/blender/editors/space_node/space_node.c b/source/blender/editors/space_node/space_node.c
index f6f13a8ba20..5da187c166d 100644
--- a/source/blender/editors/space_node/space_node.c
+++ b/source/blender/editors/space_node/space_node.c
@@ -328,17 +328,17 @@ static void node_free(SpaceLink *sl)
}
/* spacetype; init callback */
-static void node_init(struct wmWindowManager *UNUSED(wm), ScrArea *UNUSED(sa))
+static void node_init(struct wmWindowManager *UNUSED(wm), ScrArea *UNUSED(area))
{
}
static void node_area_listener(wmWindow *UNUSED(win),
- ScrArea *sa,
+ ScrArea *area,
wmNotifier *wmn,
Scene *UNUSED(scene))
{
/* note, ED_area_tag_refresh will re-execute compositor */
- SpaceNode *snode = sa->spacedata.first;
+ SpaceNode *snode = area->spacedata.first;
/* shaderfrom is only used for new shading nodes, otherwise all shaders are from objects */
short shader_type = snode->shaderfrom;
@@ -347,32 +347,32 @@ static void node_area_listener(wmWindow *UNUSED(win),
case NC_SCENE:
switch (wmn->data) {
case ND_NODES: {
- ARegion *region = BKE_area_find_region_type(sa, RGN_TYPE_WINDOW);
+ ARegion *region = BKE_area_find_region_type(area, RGN_TYPE_WINDOW);
bNodeTreePath *path = snode->treepath.last;
/* shift view to node tree center */
if (region && path) {
UI_view2d_center_set(&region->v2d, path->view_center[0], path->view_center[1]);
}
- ED_area_tag_refresh(sa);
+ ED_area_tag_refresh(area);
break;
}
case ND_FRAME:
- ED_area_tag_refresh(sa);
+ ED_area_tag_refresh(area);
break;
case ND_COMPO_RESULT:
- ED_area_tag_redraw(sa);
+ ED_area_tag_redraw(area);
break;
case ND_TRANSFORM_DONE:
if (ED_node_is_compositor(snode)) {
if (snode->flag & SNODE_AUTO_RENDER) {
snode->recalc = 1;
- ED_area_tag_refresh(sa);
+ ED_area_tag_refresh(area);
}
}
break;
case ND_LAYER_CONTENT:
- ED_area_tag_refresh(sa);
+ ED_area_tag_refresh(area);
break;
}
break;
@@ -381,13 +381,13 @@ static void node_area_listener(wmWindow *UNUSED(win),
case NC_MATERIAL:
if (ED_node_is_shader(snode)) {
if (wmn->data == ND_SHADING) {
- ED_area_tag_refresh(sa);
+ ED_area_tag_refresh(area);
}
else if (wmn->data == ND_SHADING_DRAW) {
- ED_area_tag_refresh(sa);
+ ED_area_tag_refresh(area);
}
else if (wmn->data == ND_SHADING_LINKS) {
- ED_area_tag_refresh(sa);
+ ED_area_tag_refresh(area);
}
else if (wmn->action == NA_ADDED && snode->edittree) {
nodeSetActiveID(snode->edittree, ID_MA, wmn->reference);
@@ -397,49 +397,49 @@ static void node_area_listener(wmWindow *UNUSED(win),
case NC_TEXTURE:
if (ED_node_is_shader(snode) || ED_node_is_texture(snode)) {
if (wmn->data == ND_NODES) {
- ED_area_tag_refresh(sa);
+ ED_area_tag_refresh(area);
}
}
break;
case NC_WORLD:
if (ED_node_is_shader(snode) && shader_type == SNODE_SHADER_WORLD) {
- ED_area_tag_refresh(sa);
+ ED_area_tag_refresh(area);
}
break;
case NC_OBJECT:
if (ED_node_is_shader(snode)) {
if (wmn->data == ND_OB_SHADING) {
- ED_area_tag_refresh(sa);
+ ED_area_tag_refresh(area);
}
}
break;
case NC_SPACE:
if (wmn->data == ND_SPACE_NODE) {
- ED_area_tag_refresh(sa);
+ ED_area_tag_refresh(area);
}
else if (wmn->data == ND_SPACE_NODE_VIEW) {
- ED_area_tag_redraw(sa);
+ ED_area_tag_redraw(area);
}
break;
case NC_NODE:
if (wmn->action == NA_EDITED) {
- ED_area_tag_refresh(sa);
+ ED_area_tag_refresh(area);
}
else if (wmn->action == NA_SELECTED) {
- ED_area_tag_redraw(sa);
+ ED_area_tag_redraw(area);
}
break;
case NC_SCREEN:
switch (wmn->data) {
case ND_ANIMPLAY:
- ED_area_tag_refresh(sa);
+ ED_area_tag_refresh(area);
break;
}
break;
case NC_MASK:
if (wmn->action == NA_EDITED) {
if (snode->nodetree && snode->nodetree->type == NTREE_COMPOSIT) {
- ED_area_tag_refresh(sa);
+ ED_area_tag_refresh(area);
}
}
break;
@@ -451,7 +451,7 @@ static void node_area_listener(wmWindow *UNUSED(win),
* scenes so really this is just to know if the images is used in the compo else
* painting on images could become very slow when the compositor is open. */
if (nodeUpdateID(snode->nodetree, wmn->reference)) {
- ED_area_tag_refresh(sa);
+ ED_area_tag_refresh(area);
}
}
}
@@ -461,7 +461,7 @@ static void node_area_listener(wmWindow *UNUSED(win),
if (wmn->action == NA_EDITED) {
if (ED_node_is_compositor(snode)) {
if (nodeUpdateID(snode->nodetree, wmn->reference)) {
- ED_area_tag_refresh(sa);
+ ED_area_tag_refresh(area);
}
}
}
@@ -469,26 +469,26 @@ static void node_area_listener(wmWindow *UNUSED(win),
case NC_LINESTYLE:
if (ED_node_is_shader(snode) && shader_type == SNODE_SHADER_LINESTYLE) {
- ED_area_tag_refresh(sa);
+ ED_area_tag_refresh(area);
}
break;
case NC_WM:
if (wmn->data == ND_UNDO) {
- ED_area_tag_refresh(sa);
+ ED_area_tag_refresh(area);
}
break;
case NC_GPENCIL:
if (ELEM(wmn->action, NA_EDITED, NA_SELECTED)) {
- ED_area_tag_redraw(sa);
+ ED_area_tag_redraw(area);
}
break;
}
}
-static void node_area_refresh(const struct bContext *C, ScrArea *sa)
+static void node_area_refresh(const struct bContext *C, ScrArea *area)
{
/* default now: refresh node is starting preview */
- SpaceNode *snode = sa->spacedata.first;
+ SpaceNode *snode = area->spacedata.first;
snode_set_context(C);
@@ -497,19 +497,19 @@ static void node_area_refresh(const struct bContext *C, ScrArea *sa)
if (GS(snode->id->name) == ID_MA) {
Material *ma = (Material *)snode->id;
if (ma->use_nodes) {
- ED_preview_shader_job(C, sa, snode->id, NULL, NULL, 100, 100, PR_NODE_RENDER);
+ ED_preview_shader_job(C, area, snode->id, NULL, NULL, 100, 100, PR_NODE_RENDER);
}
}
else if (GS(snode->id->name) == ID_LA) {
Light *la = (Light *)snode->id;
if (la->use_nodes) {
- ED_preview_shader_job(C, sa, snode->id, NULL, NULL, 100, 100, PR_NODE_RENDER);
+ ED_preview_shader_job(C, area, snode->id, NULL, NULL, 100, 100, PR_NODE_RENDER);
}
}
else if (GS(snode->id->name) == ID_WO) {
World *wo = (World *)snode->id;
if (wo->use_nodes) {
- ED_preview_shader_job(C, sa, snode->id, NULL, NULL, 100, 100, PR_NODE_RENDER);
+ ED_preview_shader_job(C, area, snode->id, NULL, NULL, 100, 100, PR_NODE_RENDER);
}
}
}
@@ -529,7 +529,7 @@ static void node_area_refresh(const struct bContext *C, ScrArea *sa)
else if (snode->nodetree->type == NTREE_TEXTURE) {
Tex *tex = (Tex *)snode->id;
if (tex->use_nodes) {
- ED_preview_shader_job(C, sa, snode->id, NULL, NULL, 100, 100, PR_NODE_RENDER);
+ ED_preview_shader_job(C, area, snode->id, NULL, NULL, 100, 100, PR_NODE_RENDER);
}
}
}
@@ -585,9 +585,9 @@ static void node_toolbar_region_draw(const bContext *C, ARegion *region)
ED_region_panels(C, region);
}
-static void node_cursor(wmWindow *win, ScrArea *sa, ARegion *region)
+static void node_cursor(wmWindow *win, ScrArea *area, ARegion *region)
{
- SpaceNode *snode = sa->spacedata.first;
+ SpaceNode *snode = area->spacedata.first;
/* convert mouse coordinates to v2d space */
UI_view2d_region_to_view(&region->v2d,
@@ -642,7 +642,7 @@ static void node_header_region_draw(const bContext *C, ARegion *region)
/* used for header + main region */
static void node_region_listener(wmWindow *UNUSED(win),
- ScrArea *UNUSED(sa),
+ ScrArea *UNUSED(area),
ARegion *region,
wmNotifier *wmn,
const Scene *UNUSED(scene))
@@ -791,23 +791,21 @@ static void node_widgets(void)
WM_gizmogrouptype_append_and_link(gzmap_type, NODE_GGT_backdrop_corner_pin);
}
-static void node_id_remap(ScrArea *UNUSED(sa), SpaceLink *slink, ID *old_id, ID *new_id)
+static void node_id_remap(ScrArea *UNUSED(area), SpaceLink *slink, ID *old_id, ID *new_id)
{
SpaceNode *snode = (SpaceNode *)slink;
- if (GS(old_id->name) == ID_SCE) {
- if (snode->id == old_id) {
- /* nasty DNA logic for SpaceNode:
- * ideally should be handled by editor code, but would be bad level call
- */
- BLI_freelistN(&snode->treepath);
-
- /* XXX Untested in case new_id != NULL... */
- snode->id = new_id;
- snode->from = NULL;
- snode->nodetree = NULL;
- snode->edittree = NULL;
- }
+ if (snode->id == old_id) {
+ /* nasty DNA logic for SpaceNode:
+ * ideally should be handled by editor code, but would be bad level call
+ */
+ BLI_freelistN(&snode->treepath);
+
+ /* XXX Untested in case new_id != NULL... */
+ snode->id = new_id;
+ snode->from = NULL;
+ snode->nodetree = NULL;
+ snode->edittree = NULL;
}
else if (GS(old_id->name) == ID_OB) {
if (snode->from == old_id) {
@@ -830,8 +828,7 @@ static void node_id_remap(ScrArea *UNUSED(sa), SpaceLink *slink, ID *old_id, ID
for (path = snode->treepath.first; path; path = path->next) {
if ((ID *)path->nodetree == old_id) {
path->nodetree = (bNodeTree *)new_id;
- id_us_min(old_id);
- id_us_plus(new_id);
+ id_us_ensure_real(new_id);
}
if (path == snode->treepath.first) {
/* first nodetree in path is same as snode->nodetree */
@@ -862,15 +859,15 @@ static void node_id_remap(ScrArea *UNUSED(sa), SpaceLink *slink, ID *old_id, ID
}
}
-static int node_space_subtype_get(ScrArea *sa)
+static int node_space_subtype_get(ScrArea *area)
{
- SpaceNode *snode = sa->spacedata.first;
+ SpaceNode *snode = area->spacedata.first;
return rna_node_tree_idname_to_enum(snode->tree_idname);
}
-static void node_space_subtype_set(ScrArea *sa, int value)
+static void node_space_subtype_set(ScrArea *area, int value)
{
- SpaceNode *snode = sa->spacedata.first;
+ SpaceNode *snode = area->spacedata.first;
ED_node_set_tree_type(snode, rna_node_tree_type_from_enum(value));
}
@@ -879,6 +876,11 @@ static void node_space_subtype_item_extend(bContext *C, EnumPropertyItem **item,
bool free;
const EnumPropertyItem *item_src = RNA_enum_node_tree_types_itemf_impl(C, &free);
for (const EnumPropertyItem *item_iter = item_src; item_iter->identifier; item_iter++) {
+#ifndef WITH_NEW_SIMULATION_TYPE
+ if (STREQ(item_iter->identifier, "SimulationNodeTree")) {
+ continue;
+ }
+#endif
RNA_enum_item_add(item, totitem, item_iter);
}
if (free) {
diff --git a/source/blender/editors/space_outliner/outliner_collections.c b/source/blender/editors/space_outliner/outliner_collections.c
index 8563b7d8c24..82ff9e06194 100644
--- a/source/blender/editors/space_outliner/outliner_collections.c
+++ b/source/blender/editors/space_outliner/outliner_collections.c
@@ -300,19 +300,15 @@ static TreeTraversalAction collection_find_data_to_edit(TreeElement *te, void *c
return TRAVERSE_CONTINUE;
}
-static int collection_delete_exec(bContext *C, wmOperator *op)
+void outliner_collection_delete(
+ bContext *C, Main *bmain, Scene *scene, ReportList *reports, bool hierarchy)
{
- struct wmMsgBus *mbus = CTX_wm_message_bus(C);
- Main *bmain = CTX_data_main(C);
- Scene *scene = CTX_data_scene(C);
- ViewLayer *view_layer = CTX_data_view_layer(C);
- const Base *basact_prev = BASACT(view_layer);
SpaceOutliner *soops = CTX_wm_space_outliner(C);
+
struct CollectionEditData data = {
.scene = scene,
.soops = soops,
};
- bool hierarchy = RNA_boolean_get(op->ptr, "hierarchy");
data.collections_to_edit = BLI_gset_ptr_new(__func__);
@@ -336,8 +332,7 @@ static int collection_delete_exec(bContext *C, wmOperator *op)
skip = true;
}
else {
- for (CollectionParent *cparent = collection->parents.first; cparent;
- cparent = cparent->next) {
+ LISTBASE_FOREACH (CollectionParent *, cparent, &collection->parents) {
Collection *parent = cparent->collection;
if (ID_IS_LINKED(parent)) {
skip = true;
@@ -359,7 +354,7 @@ static int collection_delete_exec(bContext *C, wmOperator *op)
}
else {
BKE_reportf(
- op->reports,
+ reports,
RPT_WARNING,
"Cannot delete linked collection '%s', it is used by other linked scenes/collections",
collection->id.name + 2);
@@ -368,6 +363,17 @@ static int collection_delete_exec(bContext *C, wmOperator *op)
}
BLI_gset_free(data.collections_to_edit, NULL);
+}
+
+static int collection_hierarchy_delete_exec(bContext *C, wmOperator *op)
+{
+ Main *bmain = CTX_data_main(C);
+ Scene *scene = CTX_data_scene(C);
+ ViewLayer *view_layer = CTX_data_view_layer(C);
+ struct wmMsgBus *mbus = CTX_wm_message_bus(C);
+ const Base *basact_prev = BASACT(view_layer);
+
+ outliner_collection_delete(C, bmain, scene, op->reports, true);
DEG_id_tag_update(&scene->id, ID_RECALC_COPY_ON_WRITE);
DEG_relations_tag_update(bmain);
@@ -378,27 +384,24 @@ static int collection_delete_exec(bContext *C, wmOperator *op)
WM_msg_publish_rna_prop(mbus, &scene->id, view_layer, LayerObjects, active);
}
+ ED_outliner_select_sync_from_object_tag(C);
+
return OPERATOR_FINISHED;
}
-void OUTLINER_OT_collection_delete(wmOperatorType *ot)
+void OUTLINER_OT_collection_hierarchy_delete(wmOperatorType *ot)
{
/* identifiers */
- ot->name = "Delete Collection";
- ot->idname = "OUTLINER_OT_collection_delete";
- ot->description = "Delete selected collections";
+ ot->name = "Delete Hierarchy";
+ ot->idname = "OUTLINER_OT_collection_hierarchy_delete";
+ ot->description = "Delete selected collection hierarchies";
/* api callbacks */
- ot->exec = collection_delete_exec;
+ ot->exec = collection_hierarchy_delete_exec;
ot->poll = ED_outliner_collections_editor_poll;
/* flags */
ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
-
- /* properties */
- PropertyRNA *prop = RNA_def_boolean(
- ot->srna, "hierarchy", false, "Hierarchy", "Delete child objects and collections");
- RNA_def_property_flag(prop, PROP_SKIP_SAVE);
}
/** \} */
@@ -459,6 +462,7 @@ static int collection_objects_select_exec(bContext *C, wmOperator *op)
Scene *scene = CTX_data_scene(C);
DEG_id_tag_update(&scene->id, ID_RECALC_SELECT);
WM_main_add_notifier(NC_SCENE | ND_OB_SELECT, scene);
+ ED_outliner_select_sync_from_object_tag(C);
return OPERATOR_FINISHED;
}
@@ -581,6 +585,7 @@ static int collection_duplicate_exec(bContext *C, wmOperator *op)
DEG_relations_tag_update(bmain);
WM_main_add_notifier(NC_SCENE | ND_LAYER, CTX_data_scene(C));
+ ED_outliner_select_sync_from_object_tag(C);
return OPERATOR_FINISHED;
}
@@ -846,20 +851,6 @@ static bool collections_indirect_only_clear_poll(bContext *C)
return collections_view_layer_poll(C, true, LAYER_COLLECTION_INDIRECT_ONLY);
}
-static void layer_collection_flag_recursive_set(LayerCollection *lc, int flag)
-{
- for (LayerCollection *nlc = lc->layer_collections.first; nlc; nlc = nlc->next) {
- if (lc->flag & flag) {
- nlc->flag |= flag;
- }
- else {
- nlc->flag &= ~flag;
- }
-
- layer_collection_flag_recursive_set(nlc, flag);
- }
-}
-
static int collection_view_layer_exec(bContext *C, wmOperator *op)
{
Main *bmain = CTX_data_main(C);
@@ -884,15 +875,7 @@ static int collection_view_layer_exec(bContext *C, wmOperator *op)
GSetIterator collections_to_edit_iter;
GSET_ITER (collections_to_edit_iter, data.collections_to_edit) {
LayerCollection *lc = BLI_gsetIterator_getKey(&collections_to_edit_iter);
-
- if (clear) {
- lc->flag &= ~flag;
- }
- else {
- lc->flag |= flag;
- }
-
- layer_collection_flag_recursive_set(lc, flag);
+ BKE_layer_collection_set_flag(lc, flag, !clear);
}
BLI_gset_free(data.collections_to_edit, NULL);
@@ -1468,14 +1451,12 @@ static int outliner_unhide_all_exec(bContext *C, wmOperator *UNUSED(op))
/* Unhide all the collections. */
LayerCollection *lc_master = view_layer->layer_collections.first;
- for (LayerCollection *lc_iter = lc_master->layer_collections.first; lc_iter;
- lc_iter = lc_iter->next) {
- lc_iter->flag &= ~LAYER_COLLECTION_HIDE;
- layer_collection_flag_recursive_set(lc_iter, LAYER_COLLECTION_HIDE);
+ LISTBASE_FOREACH (LayerCollection *, lc_iter, &lc_master->layer_collections) {
+ BKE_layer_collection_set_flag(lc_iter, LAYER_COLLECTION_HIDE, false);
}
/* Unhide all objects. */
- for (Base *base = view_layer->object_bases.first; base; base = base->next) {
+ LISTBASE_FOREACH (Base *, base, &view_layer->object_bases) {
base->flag &= ~BASE_HIDDEN;
}
diff --git a/source/blender/editors/space_outliner/outliner_dragdrop.c b/source/blender/editors/space_outliner/outliner_dragdrop.c
index 68a02e7614c..9fb1d1cf8cf 100644
--- a/source/blender/editors/space_outliner/outliner_dragdrop.c
+++ b/source/blender/editors/space_outliner/outliner_dragdrop.c
@@ -264,8 +264,7 @@ static bool parent_drop_allowed(TreeElement *te, Object *potential_child)
* element for object it means that all displayed objects belong to
* active scene and parenting them is allowed (sergey) */
if (scene) {
- for (ViewLayer *view_layer = scene->view_layers.first; view_layer;
- view_layer = view_layer->next) {
+ LISTBASE_FOREACH (ViewLayer *, view_layer, &scene->view_layers) {
if (BKE_view_layer_base_find(view_layer, potential_child)) {
return true;
}
@@ -482,7 +481,7 @@ static int parent_clear_invoke(bContext *C, wmOperator *UNUSED(op), const wmEven
ListBase *lb = event->customdata;
wmDrag *drag = lb->first;
- for (wmDragID *drag_id = drag->ids.first; drag_id; drag_id = drag_id->next) {
+ LISTBASE_FOREACH (wmDragID *, drag_id, &drag->ids) {
if (GS(drag_id->id->name) == ID_OB) {
Object *object = (Object *)drag_id->id;
@@ -549,8 +548,7 @@ static int scene_drop_invoke(bContext *C, wmOperator *UNUSED(op), const wmEvent
BKE_collection_object_add(bmain, collection, ob);
- for (ViewLayer *view_layer = scene->view_layers.first; view_layer;
- view_layer = view_layer->next) {
+ LISTBASE_FOREACH (ViewLayer *, view_layer, &scene->view_layers) {
Base *base = BKE_view_layer_base_find(view_layer, ob);
if (base) {
ED_object_base_select(base, BA_SELECT);
@@ -678,6 +676,10 @@ static bool collection_drop_init(bContext *C,
if (ID_IS_LINKED(to_collection)) {
return false;
}
+ /* Currently this should not be allowed (might be supported in the future though...). */
+ if (ID_IS_OVERRIDE_LIBRARY(to_collection)) {
+ return false;
+ }
/* Get drag datablocks. */
if (drag->type != WM_DRAG_ID) {
@@ -818,7 +820,7 @@ static int collection_drop_invoke(bContext *C, wmOperator *UNUSED(op), const wmE
TREESTORE(data.te)->flag &= ~TSE_CLOSED;
}
- for (wmDragID *drag_id = drag->ids.first; drag_id; drag_id = drag_id->next) {
+ LISTBASE_FOREACH (wmDragID *, drag_id, &drag->ids) {
/* Ctrl enables linking, so we don't need a from collection then. */
Collection *from = (event->ctrl) ? NULL : collection_parent_from_ID(drag_id->from_parent);
@@ -985,6 +987,8 @@ static int outliner_item_drag_drop_invoke(bContext *C,
WM_drag_add_ID(drag, data.drag_id, data.drag_parent);
}
+ ED_outliner_select_sync_from_all_tag(C);
+
return (OPERATOR_FINISHED | OPERATOR_PASS_THROUGH);
}
diff --git a/source/blender/editors/space_outliner/outliner_draw.c b/source/blender/editors/space_outliner/outliner_draw.c
index 3c569a71e93..7d3b95721c6 100644
--- a/source/blender/editors/space_outliner/outliner_draw.c
+++ b/source/blender/editors/space_outliner/outliner_draw.c
@@ -91,7 +91,7 @@ static void outliner_tree_dimensions_impl(SpaceOutliner *soops,
int *width,
int *height)
{
- for (TreeElement *te = lb->first; te; te = te->next) {
+ LISTBASE_FOREACH (TreeElement *, te, lb) {
*width = MAX2(*width, te->xend);
if (height != NULL) {
*height += UI_UNIT_Y;
@@ -178,20 +178,13 @@ static void restrictbutton_r_lay_cb(bContext *C, void *poin, void *UNUSED(poin2)
WM_event_add_notifier(C, NC_SCENE | ND_RENDER_OPTIONS, poin);
}
-static void restrictbutton_bone_visibility_cb(bContext *C, void *poin, void *poin2)
+static void restrictbutton_bone_visibility_cb(bContext *C, void *poin, void *UNUSED(poin2))
{
- bArmature *arm = (bArmature *)poin;
- Bone *bone = (Bone *)poin2;
- if (bone->flag & BONE_HIDDEN_P) {
- bone->flag &= ~(BONE_SELECTED | BONE_TIPSEL | BONE_ROOTSEL);
- }
+ Bone *bone = (Bone *)poin;
if (CTX_wm_window(C)->eventstate->ctrl) {
restrictbutton_recursive_bone(bone, BONE_HIDDEN_P, (bone->flag & BONE_HIDDEN_P) != 0);
}
-
- WM_event_add_notifier(C, NC_OBJECT | ND_POSE, NULL);
- DEG_id_tag_update(&arm->id, ID_RECALC_COPY_ON_WRITE);
}
static void restrictbutton_bone_select_cb(bContext *C, void *UNUSED(poin), void *poin2)
@@ -387,8 +380,7 @@ static void outliner_collection_set_flag_recursive(Scene *scene,
if (base_or_object_prop) {
/* Note: We can't use BKE_collection_object_cache_get()
* otherwise we would not take collection exclusion into account. */
- for (CollectionObject *cob = layer_collection->collection->gobject.first; cob;
- cob = cob->next) {
+ LISTBASE_FOREACH (CollectionObject *, cob, &layer_collection->collection->gobject) {
outliner_base_or_object_pointer_create(view_layer, collection, cob->ob, &ptr);
RNA_property_boolean_set(&ptr, base_or_object_prop, value);
@@ -401,7 +393,7 @@ static void outliner_collection_set_flag_recursive(Scene *scene,
/* Keep going recursively. */
ListBase *lb = (layer_collection ? &layer_collection->layer_collections : &collection->children);
- for (Link *link = lb->first; link; link = link->next) {
+ LISTBASE_FOREACH (Link *, link, lb) {
LayerCollection *layer_collection_iter = layer_collection ? (LayerCollection *)link : NULL;
Collection *collection_iter = layer_collection ?
(collection ? layer_collection_iter->collection : NULL) :
@@ -467,7 +459,7 @@ static bool outliner_collection_is_isolated(Scene *scene,
/* Keep going recursively. */
ListBase *lb = (layer_collection ? &layer_collection->layer_collections : &collection->children);
- for (Link *link = lb->first; link; link = link->next) {
+ LISTBASE_FOREACH (Link *, link, lb) {
LayerCollection *layer_collection_iter = layer_collection ? (LayerCollection *)link : NULL;
Collection *collection_iter = layer_collection ?
(collection ? layer_collection_iter->collection : NULL) :
@@ -542,8 +534,7 @@ void outliner_collection_isolate_flag(Scene *scene,
/* Make this collection direct parents also "visible". */
if (layer_collection) {
LayerCollection *lc_parent = layer_collection;
- for (LayerCollection *lc_iter = top_layer_collection->layer_collections.first; lc_iter;
- lc_iter = lc_iter->next) {
+ LISTBASE_FOREACH (LayerCollection *, lc_iter, &top_layer_collection->layer_collections) {
if (BKE_layer_collection_has_layer_collection(lc_iter, layer_collection)) {
lc_parent = lc_iter;
break;
@@ -555,8 +546,7 @@ void outliner_collection_isolate_flag(Scene *scene,
scene, lc_parent, collection ? lc_parent->collection : NULL, &ptr);
RNA_property_boolean_set(&ptr, layer_or_collection_prop, !is_hide);
- for (LayerCollection *lc_iter = lc_parent->layer_collections.first; lc_iter;
- lc_iter = lc_iter->next) {
+ LISTBASE_FOREACH (LayerCollection *, lc_iter, &lc_parent->layer_collections) {
if (BKE_layer_collection_has_layer_collection(lc_iter, layer_collection)) {
lc_parent = lc_iter;
break;
@@ -862,6 +852,7 @@ typedef struct RestrictProperties {
*layer_collection_hide_viewport;
PropertyRNA *modifier_show_viewport, *modifier_show_render;
PropertyRNA *constraint_enable;
+ PropertyRNA *bone_hide_viewport;
} RestrictProperties;
/* We don't care about the value of the property
@@ -880,6 +871,7 @@ typedef struct RestrictPropertiesActive {
bool modifier_show_viewport;
bool modifier_show_render;
bool constraint_enable;
+ bool bone_hide_viewport;
} RestrictPropertiesActive;
static void outliner_restrict_properties_enable_collection_set(
@@ -1014,6 +1006,8 @@ static void outliner_draw_restrictbuts(uiBlock *block,
props.constraint_enable = RNA_struct_type_find_property(&RNA_Constraint, "mute");
+ props.bone_hide_viewport = RNA_struct_type_find_property(&RNA_Bone, "hide");
+
props.initialized = true;
}
@@ -1054,7 +1048,7 @@ static void outliner_draw_restrictbuts(uiBlock *block,
/* Create buttons. */
uiBut *bt;
- for (TreeElement *te = lb->first; te; te = te->next) {
+ LISTBASE_FOREACH (TreeElement *, te, lb) {
TreeStoreElem *tselem = TREESTORE(te);
RestrictPropertiesActive props_active = props_active_parent;
@@ -1282,27 +1276,32 @@ static void outliner_draw_restrictbuts(uiBlock *block,
}
}
else if (tselem->type == TSE_POSE_CHANNEL) {
+ PointerRNA ptr;
bPoseChannel *pchan = (bPoseChannel *)te->directdata;
Bone *bone = pchan->bone;
Object *ob = (Object *)tselem->id;
+ bArmature *arm = ob->data;
+
+ RNA_pointer_create(&arm->id, &RNA_Bone, bone, &ptr);
if (soops->show_restrict_flags & SO_RESTRICT_VIEWPORT) {
- bt = uiDefIconButBitI(block,
- UI_BTYPE_ICON_TOGGLE,
- BONE_HIDDEN_P,
- 0,
- ICON_RESTRICT_VIEW_OFF,
- (int)(region->v2d.cur.xmax - restrict_offsets.viewport),
- te->ys,
- UI_UNIT_X,
- UI_UNIT_Y,
- &(bone->flag),
- 0,
- 0,
- 0,
- 0,
- TIP_("Restrict visibility in the 3D View"));
- UI_but_func_set(bt, restrictbutton_bone_visibility_cb, ob->data, bone);
+ bt = uiDefIconButR_prop(block,
+ UI_BTYPE_ICON_TOGGLE,
+ 0,
+ 0,
+ (int)(region->v2d.cur.xmax - restrict_offsets.viewport),
+ te->ys,
+ UI_UNIT_X,
+ UI_UNIT_Y,
+ &ptr,
+ props.bone_hide_viewport,
+ -1,
+ 0,
+ 0,
+ -1,
+ -1,
+ TIP_("Restrict visibility in the 3D View"));
+ UI_but_func_set(bt, restrictbutton_bone_visibility_cb, bone, NULL);
UI_but_flag_enable(bt, UI_BUT_DRAG_LOCK);
UI_but_drawflag_enable(bt, UI_BUT_ICON_REVERSE);
}
@@ -1651,7 +1650,7 @@ static void outliner_draw_userbuts(uiBlock *block,
ListBase *lb)
{
- for (TreeElement *te = lb->first; te; te = te->next) {
+ LISTBASE_FOREACH (TreeElement *, te, lb) {
TreeStoreElem *tselem = TREESTORE(te);
if (te->ys + 2 * UI_UNIT_Y >= region->v2d.cur.ymin && te->ys <= region->v2d.cur.ymax) {
if (tselem->type == 0) {
@@ -1770,7 +1769,7 @@ static void outliner_draw_rnabuts(
PointerRNA *ptr;
PropertyRNA *prop;
- for (TreeElement *te = lb->first; te; te = te->next) {
+ LISTBASE_FOREACH (TreeElement *, te, lb) {
TreeStoreElem *tselem = TREESTORE(te);
if (te->ys + 2 * UI_UNIT_Y >= region->v2d.cur.ymin && te->ys <= region->v2d.cur.ymax) {
if (tselem->type == TSE_RNA_PROPERTY) {
@@ -2194,6 +2193,9 @@ TreeElementIcon tree_element_get_icon(TreeStoreElem *tselem, TreeElement *te)
case eModifierType_WeightedNormal:
data.icon = ICON_MOD_NORMALEDIT;
break;
+ case eModifierType_Simulation:
+ data.icon = ICON_PHYSICS; /* TODO: Use correct icon. */
+ break;
/* Default */
case eModifierType_None:
case eModifierType_ShapeKey:
@@ -2584,6 +2586,10 @@ TreeElementIcon tree_element_get_icon(TreeStoreElem *tselem, TreeElement *te)
case ID_PC:
data.icon = ICON_CURVE_BEZCURVE;
break;
+ case ID_SIM:
+ /* TODO: Use correct icon. */
+ data.icon = ICON_PHYSICS;
+ break;
default:
break;
}
@@ -2861,7 +2867,7 @@ static void outliner_draw_iconrow(bContext *C,
{
eOLDrawState active = OL_DRAWSEL_NONE;
- for (TreeElement *te = lb->first; te; te = te->next) {
+ LISTBASE_FOREACH (TreeElement *, te, lb) {
TreeStoreElem *tselem = TREESTORE(te);
/* object hierarchy always, further constrained on level */
@@ -3204,7 +3210,7 @@ static void outliner_draw_tree_element(bContext *C,
if (TSELEM_OPEN(tselem, soops)) {
*starty -= UI_UNIT_Y;
- for (TreeElement *ten = te->subtree.first; ten; ten = ten->next) {
+ LISTBASE_FOREACH (TreeElement *, ten, &te->subtree) {
/* check if element needs to be drawn grayed out, but also gray out
* childs of a grayed out parent (pass on draw_grayed_out to childs) */
bool draw_childs_grayed_out = draw_grayed_out || (ten->flag & TE_DRAGGING);
@@ -3223,7 +3229,7 @@ static void outliner_draw_tree_element(bContext *C,
}
}
else {
- for (TreeElement *ten = te->subtree.first; ten; ten = ten->next) {
+ LISTBASE_FOREACH (TreeElement *, ten, &te->subtree) {
outliner_set_coord_tree_element(ten, startx, *starty);
}
@@ -3357,7 +3363,7 @@ static void outliner_draw_struct_marks(ARegion *region,
ListBase *lb,
int *starty)
{
- for (TreeElement *te = lb->first; te; te = te->next) {
+ LISTBASE_FOREACH (TreeElement *, te, lb) {
TreeStoreElem *tselem = TREESTORE(te);
/* selection status */
@@ -3406,7 +3412,7 @@ static void outliner_draw_highlights_recursive(uint pos,
const bool is_searching = (SEARCHING_OUTLINER(soops) ||
(soops->outlinevis == SO_DATA_API && soops->search_string[0] != 0));
- for (TreeElement *te = lb->first; te; te = te->next) {
+ LISTBASE_FOREACH (TreeElement *, te, lb) {
const TreeStoreElem *tselem = TREESTORE(te);
const int start_y = *io_start_y;
@@ -3555,7 +3561,7 @@ static void outliner_draw_tree(bContext *C,
// items themselves
starty = (int)region->v2d.tot.ymax - UI_UNIT_Y - OL_Y_OFFSET;
startx = 0;
- for (TreeElement *te = soops->tree.first; te; te = te->next) {
+ LISTBASE_FOREACH (TreeElement *, te, &soops->tree) {
outliner_draw_tree_element(C,
block,
fstyle,
diff --git a/source/blender/editors/space_outliner/outliner_edit.c b/source/blender/editors/space_outliner/outliner_edit.c
index 20dbfb71fa6..7c729612255 100644
--- a/source/blender/editors/space_outliner/outliner_edit.c
+++ b/source/blender/editors/space_outliner/outliner_edit.c
@@ -54,6 +54,7 @@
#include "BKE_outliner_treehash.h"
#include "BKE_report.h"
#include "BKE_scene.h"
+#include "BKE_workspace.h"
#include "DEG_depsgraph.h"
#include "DEG_depsgraph_build.h"
@@ -82,9 +83,11 @@
#include "outliner_intern.h"
-/* ************************************************************** */
+/** \} */
-/* Highlight --------------------------------------------------- */
+/* -------------------------------------------------------------------- */
+/** \name Highlight on Cursor Motion Operator
+ * \{ */
static int outliner_highlight_update(bContext *C, wmOperator *UNUSED(op), const wmEvent *event)
{
@@ -139,7 +142,11 @@ void OUTLINER_OT_highlight_update(wmOperatorType *ot)
ot->poll = ED_operator_outliner_active;
}
-/* Toggle Open/Closed ------------------------------------------- */
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Toggle Open/Closed Operator
+ * \{ */
/* Open or close a tree element, optionally toggling all children recursively */
void outliner_item_openclose(TreeElement *te, bool open, bool toggle_all)
@@ -261,8 +268,10 @@ void OUTLINER_OT_item_openclose(wmOperatorType *ot)
RNA_def_boolean(ot->srna, "all", false, "All", "Close or open all items");
}
+/** \} */
+
/* -------------------------------------------------------------------- */
-/** \name Object Mode Enter/Exit
+/** \name Object Mode Enter/Exit Utilities
* \{ */
static void item_object_mode_enter_exit(bContext *C, ReportList *reports, Object *ob, bool enter)
@@ -316,7 +325,9 @@ void item_object_mode_exit_cb(bContext *C,
/** \} */
-/* Rename --------------------------------------------------- */
+/* -------------------------------------------------------------------- */
+/** \name Rename Operator
+ * \{ */
static void do_item_rename(ARegion *region,
TreeElement *te,
@@ -351,6 +362,12 @@ static void do_item_rename(ARegion *region,
else if (ELEM(tselem->type, TSE_SEQUENCE, TSE_SEQ_STRIP, TSE_SEQUENCE_DUP)) {
BKE_report(reports, RPT_WARNING, "Cannot edit sequence name");
}
+ else if (ID_IS_LINKED(tselem->id)) {
+ BKE_report(reports, RPT_WARNING, "Cannot edit external library data");
+ }
+ else if (ID_IS_OVERRIDE_LIBRARY(tselem->id)) {
+ BKE_report(reports, RPT_WARNING, "Cannot edit name of an override data-block");
+ }
else if (outliner_is_collection_tree_element(te)) {
Collection *collection = outliner_collection_from_tree_element(te);
@@ -361,9 +378,6 @@ static void do_item_rename(ARegion *region,
add_textbut = true;
}
}
- else if (ID_IS_LINKED(tselem->id)) {
- BKE_report(reports, RPT_WARNING, "Cannot edit external library data");
- }
else if (te->idcode == ID_LI && ((Library *)tselem->id)->parent) {
BKE_report(reports, RPT_WARNING, "Cannot edit the path of an indirectly linked library");
}
@@ -446,9 +460,16 @@ void OUTLINER_OT_item_rename(wmOperatorType *ot)
ot->invoke = outliner_item_rename;
ot->poll = ED_operator_outliner_active;
+
+ /* Flags. */
+ ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
}
-/* ID delete --------------------------------------------------- */
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name ID Delete Operator
+ * \{ */
static void id_delete(bContext *C, ReportList *reports, TreeElement *te, TreeStoreElem *tselem)
{
@@ -473,6 +494,14 @@ static void id_delete(bContext *C, ReportList *reports, TreeElement *te, TreeSto
id->name);
return;
}
+ else if (te->idcode == ID_WS) {
+ BKE_workspace_id_tag_all_visible(bmain, LIB_TAG_DOIT);
+ if (id->tag & LIB_TAG_DOIT) {
+ BKE_reportf(
+ reports, RPT_WARNING, "Cannot delete currently visible workspace id '%s'", id->name);
+ return;
+ }
+ }
BKE_id_delete(bmain, id);
@@ -552,9 +581,16 @@ void OUTLINER_OT_id_delete(wmOperatorType *ot)
ot->invoke = outliner_id_delete_invoke;
ot->poll = ED_operator_outliner_active;
+
+ /* Flags. */
+ ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
}
-/* ID remap --------------------------------------------------- */
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name ID Remap Operator
+ * \{ */
static int outliner_id_remap_exec(bContext *C, wmOperator *op)
{
@@ -685,7 +721,8 @@ void OUTLINER_OT_id_remap(wmOperatorType *ot)
ot->exec = outliner_id_remap_exec;
ot->poll = ED_operator_outliner_active;
- ot->flag = 0;
+ /* Flags. */
+ ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
prop = RNA_def_enum(ot->srna, "id_type", rna_enum_id_type_items, ID_OB, "ID Type", "");
RNA_def_property_translation_context(prop, BLT_I18NCONTEXT_ID_ID);
@@ -727,7 +764,11 @@ void id_remap_cb(bContext *C,
WM_operator_properties_free(&op_props);
}
-/* ID copy/Paste ------------------------------------------------------------- */
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name ID Copy Operator
+ * \{ */
static int outliner_id_copy_tag(SpaceOutliner *soops, ListBase *tree)
{
@@ -789,9 +830,16 @@ void OUTLINER_OT_id_copy(wmOperatorType *ot)
ot->exec = outliner_id_copy_exec;
ot->poll = ED_operator_outliner_active;
+ /* Flags, don't need any undo here (this operator does not change anything in Blender data). */
ot->flag = 0;
}
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name ID Paste Operator
+ * \{ */
+
static int outliner_id_paste_exec(bContext *C, wmOperator *op)
{
char str[FILE_MAX];
@@ -808,6 +856,7 @@ static int outliner_id_paste_exec(bContext *C, wmOperator *op)
WM_event_add_notifier(C, NC_WINDOW, NULL);
BKE_reportf(op->reports, RPT_INFO, "%d data-block(s) pasted", num_pasted);
+
return OPERATOR_FINISHED;
}
@@ -822,10 +871,15 @@ void OUTLINER_OT_id_paste(wmOperatorType *ot)
ot->exec = outliner_id_paste_exec;
ot->poll = ED_operator_outliner_active;
- ot->flag = 0;
+ /* flags */
+ ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
}
-/* Library relocate/reload --------------------------------------------------- */
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Library Relocate Operator
+ * \{ */
static int lib_relocate(
bContext *C, TreeElement *te, TreeStoreElem *tselem, wmOperatorType *ot, const bool reload)
@@ -929,6 +983,9 @@ void OUTLINER_OT_lib_relocate(wmOperatorType *ot)
ot->invoke = outliner_lib_relocate_invoke;
ot->poll = ED_operator_outliner_active;
+
+ /* Flags. */
+ ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
}
/* XXX This does not work with several items
@@ -969,6 +1026,12 @@ static int outliner_lib_reload_invoke(bContext *C, wmOperator *op, const wmEvent
return OPERATOR_CANCELLED;
}
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Library Reload Operator
+ * \{ */
+
void OUTLINER_OT_lib_reload(wmOperatorType *ot)
{
ot->name = "Reload Library";
@@ -977,6 +1040,9 @@ void OUTLINER_OT_lib_reload(wmOperatorType *ot)
ot->invoke = outliner_lib_reload_invoke;
ot->poll = ED_operator_outliner_active;
+
+ /* Flags. */
+ ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
}
void lib_reload_cb(bContext *C,
@@ -992,13 +1058,11 @@ void lib_reload_cb(bContext *C,
lib_relocate(C, te, tselem, ot, true);
}
-/* ************************************************************** */
-/* Setting Toggling Operators */
-
-/* =============================================== */
-/* Toggling Utilities (Exported) */
+/** \} */
-/* Apply Settings ------------------------------- */
+/* -------------------------------------------------------------------- */
+/** \name Apply Settings Utilities
+ * \{ */
static int outliner_count_levels(ListBase *lb, const int curlevel)
{
@@ -1080,7 +1144,11 @@ bool outliner_flag_flip(ListBase *lb, short flag)
return changed;
}
-/* Restriction Columns ------------------------------- */
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Restriction Column Utility
+ * \{ */
/* same check needed for both object operation and restrict column button func
* return 0 when in edit mode (cannot restrict view or select)
@@ -1106,10 +1174,11 @@ int common_restrict_check(bContext *C, Object *ob)
return 1;
}
-/* =============================================== */
-/* Outliner setting toggles */
+/** \} */
-/* Toggle Expanded (Outliner) ---------------------------------------- */
+/* -------------------------------------------------------------------- */
+/** \name Toggle Expanded (Outliner) Operator
+ * \{ */
static int outliner_toggle_expanded_exec(bContext *C, wmOperator *UNUSED(op))
{
@@ -1142,7 +1211,11 @@ void OUTLINER_OT_expanded_toggle(wmOperatorType *ot)
/* no undo or registry, UI option */
}
-/* Toggle Selected (Outliner) ---------------------------------------- */
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Toggle Selected (Outliner) Operator
+ * \{ */
static int outliner_select_all_exec(bContext *C, wmOperator *op)
{
@@ -1166,9 +1239,7 @@ static int outliner_select_all_exec(bContext *C, wmOperator *op)
break;
}
- if (soops->flag & SO_SYNC_SELECT) {
- ED_outliner_select_sync_from_outliner(C, soops);
- }
+ ED_outliner_select_sync_from_outliner(C, soops);
DEG_id_tag_update(&scene->id, ID_RECALC_SELECT);
WM_event_add_notifier(C, NC_SCENE | ND_OB_SELECT, scene);
@@ -1194,10 +1265,11 @@ void OUTLINER_OT_select_all(wmOperatorType *ot)
WM_operator_properties_select_all(ot);
}
-/* ************************************************************** */
-/* Hotkey Only Operators */
+/** \} */
-/* Show Active --------------------------------------------------- */
+/* -------------------------------------------------------------------- */
+/** \name View Show Active (Outliner) Operator
+ * \{ */
static void outliner_set_coordinates_element_recursive(SpaceOutliner *soops,
TreeElement *te,
@@ -1292,7 +1364,7 @@ static void outliner_show_active(SpaceOutliner *so, ARegion *region, TreeElement
return;
}
- for (TreeElement *ten = te->subtree.first; ten; ten = ten->next) {
+ LISTBASE_FOREACH (TreeElement *, ten, &te->subtree) {
outliner_show_active(so, region, ten, id);
}
}
@@ -1310,7 +1382,7 @@ static int outliner_show_active_exec(bContext *C, wmOperator *UNUSED(op))
ID *id = TREESTORE(active_element)->id;
/* Expand all elements in the outliner with matching ID */
- for (TreeElement *te = so->tree.first; te; te = te->next) {
+ LISTBASE_FOREACH (TreeElement *, te, &so->tree) {
outliner_show_active(so, region, te, id);
}
@@ -1347,7 +1419,11 @@ void OUTLINER_OT_show_active(wmOperatorType *ot)
ot->poll = ED_operator_outliner_active;
}
-/* View Panning --------------------------------------------------- */
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name View Panning (Outliner) Operator
+ * \{ */
static int outliner_scroll_page_exec(bContext *C, wmOperator *op)
{
@@ -1385,10 +1461,14 @@ void OUTLINER_OT_scroll_page(wmOperatorType *ot)
RNA_def_property_flag(prop, PROP_SKIP_SAVE);
}
-/* Search ------------------------------------------------------- */
-// TODO: probably obsolete now with filtering?
+/** \} */
+
+#if 0 // TODO: probably obsolete now with filtering?
+
+/* -------------------------------------------------------------------- */
+/** \name Search
+ * \{ */
-#if 0
/* find next element that has this name */
static TreeElement *outliner_find_name(
@@ -1501,9 +1581,14 @@ static void outliner_find_panel(
BKE_reportf(reports, RPT_WARNING, "Not found: %s", name);
}
}
-#endif
-/* Show One Level ----------------------------------------------- */
+/** \} */
+
+#endif /* if 0 */
+
+/* -------------------------------------------------------------------- */
+/** \name Show One Level Operator
+ * \{ */
/* helper function for Show/Hide one level operator */
static void outliner_openclose_level(ListBase *lb, int curlevel, int level, int open)
@@ -1576,7 +1661,11 @@ void OUTLINER_OT_show_one_level(wmOperatorType *ot)
RNA_def_property_flag(prop, PROP_SKIP_SAVE);
}
-/* Show Hierarchy ----------------------------------------------- */
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Show Hierarchy Operator
+ * \{ */
/* Helper function for tree_element_shwo_hierarchy() -
* recursively checks whether subtrees have any objects. */
@@ -1668,15 +1757,19 @@ void OUTLINER_OT_show_hierarchy(wmOperatorType *ot)
/* no undo or registry, UI option */
}
-/* ************************************************************** */
-/* ANIMATO OPERATIONS */
-/* KeyingSet and Driver Creation - Helper functions */
+/** \} */
-/* specialized poll callback for these operators to work in Datablocks view only */
+/* -------------------------------------------------------------------- */
+/** \name Animation Internal Utilities
+ * \{ */
+
+/**
+ * Specialized poll callback for these operators to work in data-blocks view only.
+ */
static bool ed_operator_outliner_datablocks_active(bContext *C)
{
- ScrArea *sa = CTX_wm_area(C);
- if ((sa) && (sa->spacetype == SPACE_OUTLINER)) {
+ ScrArea *area = CTX_wm_area(C);
+ if ((area) && (area->spacetype == SPACE_OUTLINER)) {
SpaceOutliner *so = CTX_wm_space_outliner(C);
return (so->outlinevis == SO_DATA_API);
}
@@ -1834,19 +1927,23 @@ static void tree_element_to_path(TreeElement *te,
BLI_freelistN(&hierarchy);
}
-/* =============================================== */
-/* Driver Operations */
+/** \} */
-/* These operators are only available in databrowser mode for now, as
- * they depend on having RNA paths and/or hierarchies available.
+/* -------------------------------------------------------------------- */
+/** \name Driver Internal Utilities
+ * \{ */
+
+/**
+ * Driver Operations
+ *
+ * These operators are only available in data-browser mode for now,
+ * as they depend on having RNA paths and/or hierarchies available.
*/
enum {
DRIVERS_EDITMODE_ADD = 0,
DRIVERS_EDITMODE_REMOVE,
} /*eDrivers_EditModes*/;
-/* Utilities ---------------------------------- */
-
/* Recursively iterate over tree, finding and working on selected items */
static void do_outliner_drivers_editop(SpaceOutliner *soops,
ListBase *tree,
@@ -1922,7 +2019,11 @@ static void do_outliner_drivers_editop(SpaceOutliner *soops,
}
}
-/* Add Operator ---------------------------------- */
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Driver Add Operator
+ * \{ */
static int outliner_drivers_addsel_exec(bContext *C, wmOperator *op)
{
@@ -1957,7 +2058,11 @@ void OUTLINER_OT_drivers_add_selected(wmOperatorType *ot)
ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
}
-/* Remove Operator ---------------------------------- */
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Driver Remove Operator
+ * \{ */
static int outliner_drivers_deletesel_exec(bContext *C, wmOperator *op)
{
@@ -1992,10 +2097,16 @@ void OUTLINER_OT_drivers_delete_selected(wmOperatorType *ot)
ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
}
-/* =============================================== */
-/* Keying Set Operations */
+/** \} */
-/* These operators are only available in databrowser mode for now, as
+/* -------------------------------------------------------------------- */
+/** \name Keying-Set Internal Utilities
+ * \{ */
+
+/**
+ * Keying-Set Operations
+ *
+ * These operators are only available in data-browser mode for now, as
* they depend on having RNA paths and/or hierarchies available.
*/
enum {
@@ -2003,8 +2114,6 @@ enum {
KEYINGSET_EDITMODE_REMOVE,
} /*eKeyingSet_EditModes*/;
-/* Utilities ---------------------------------- */
-
/* find the 'active' KeyingSet, and add if not found (if adding is allowed) */
// TODO: should this be an API func?
static KeyingSet *verify_active_keyingset(Scene *scene, short add)
@@ -2096,7 +2205,11 @@ static void do_outliner_keyingset_editop(SpaceOutliner *soops,
}
}
-/* Add Operator ---------------------------------- */
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Keying-Set Add Operator
+ * \{ */
static int outliner_keyingset_additems_exec(bContext *C, wmOperator *op)
{
@@ -2137,7 +2250,11 @@ void OUTLINER_OT_keyingset_add_selected(wmOperatorType *ot)
ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
}
-/* Remove Operator ---------------------------------- */
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Keying-Set Remove Operator
+ * \{ */
static int outliner_keyingset_removeitems_exec(bContext *C, wmOperator *UNUSED(op))
{
@@ -2174,20 +2291,23 @@ void OUTLINER_OT_keyingset_remove_selected(wmOperatorType *ot)
ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
}
-/* ************************************************************** */
-/* ORPHANED DATABLOCKS */
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Purge Orphan Data-Blocks Operator
+ * \{ */
static bool ed_operator_outliner_id_orphans_active(bContext *C)
{
- ScrArea *sa = CTX_wm_area(C);
- if (sa != NULL && sa->spacetype == SPACE_OUTLINER) {
+ ScrArea *area = CTX_wm_area(C);
+ if (area != NULL && area->spacetype == SPACE_OUTLINER) {
SpaceOutliner *so = CTX_wm_space_outliner(C);
return (so->outlinevis == SO_ID_ORPHANS);
}
return true;
}
-/* Purge Orphans Operator --------------------------------------- */
+/** \} */
static void outliner_orphans_purge_tag(ID *id, int *num_tagged)
{
@@ -2249,7 +2369,7 @@ static int outliner_orphans_purge_invoke(bContext *C, wmOperator *op, const wmEv
static int outliner_orphans_purge_exec(bContext *C, wmOperator *op)
{
Main *bmain = CTX_data_main(C);
- ScrArea *sa = CTX_wm_area(C);
+ ScrArea *area = CTX_wm_area(C);
SpaceOutliner *soops = CTX_wm_space_outliner(C);
int num_tagged[INDEX_ID_MAX] = {0};
@@ -2276,7 +2396,7 @@ static int outliner_orphans_purge_exec(bContext *C, wmOperator *op)
* outliner several mouse events can be handled in one cycle without
* handling notifiers/redraw which leads to deleting the same object twice.
* cleanup tree here to prevent such cases. */
- if ((sa != NULL) && (sa->spacetype == SPACE_OUTLINER)) {
+ if ((area != NULL) && (area->spacetype == SPACE_OUTLINER)) {
outliner_cleanup_tree(soops);
}
@@ -2305,3 +2425,5 @@ void OUTLINER_OT_orphans_purge(wmOperatorType *ot)
PropertyRNA *prop = RNA_def_int(ot->srna, "num_deleted", 0, 0, INT_MAX, "", "", 0, INT_MAX);
RNA_def_property_flag(prop, PROP_SKIP_SAVE | PROP_HIDDEN);
}
+
+/** \} */
diff --git a/source/blender/editors/space_outliner/outliner_intern.h b/source/blender/editors/space_outliner/outliner_intern.h
index ae252d3dd30..8df0c3ec9ba 100644
--- a/source/blender/editors/space_outliner/outliner_intern.h
+++ b/source/blender/editors/space_outliner/outliner_intern.h
@@ -108,7 +108,8 @@ typedef struct TreeElementIcon {
ID_LP, \
ID_HA, \
ID_PT, \
- ID_VO) || /* Only in 'blendfile' mode ... :/ */ \
+ ID_VO, \
+ ID_SIM) || /* Only in 'blendfile' mode ... :/ */ \
ELEM(GS((_id)->name), \
ID_SCR, \
ID_WM, \
@@ -193,7 +194,8 @@ typedef enum {
/* is the current element open? if so we also show children */
#define TSELEM_OPEN(telm, sv) \
- ((telm->flag & TSE_CLOSED) == 0 || (SEARCHING_OUTLINER(sv) && (telm->flag & TSE_CHILDSEARCH)))
+ (((telm)->flag & TSE_CLOSED) == 0 || \
+ (SEARCHING_OUTLINER(sv) && ((telm)->flag & TSE_CHILDSEARCH)))
/**
* Container to avoid passing around these variables to many functions.
@@ -426,6 +428,7 @@ void OUTLINER_OT_animdata_operation(struct wmOperatorType *ot);
void OUTLINER_OT_action_set(struct wmOperatorType *ot);
void OUTLINER_OT_constraint_operation(struct wmOperatorType *ot);
void OUTLINER_OT_modifier_operation(struct wmOperatorType *ot);
+void OUTLINER_OT_delete(struct wmOperatorType *ot);
/* ---------------------------------------------------------------- */
@@ -437,11 +440,16 @@ void outliner_keymap(struct wmKeyConfig *keyconf);
bool outliner_is_collection_tree_element(const TreeElement *te);
struct Collection *outliner_collection_from_tree_element(const TreeElement *te);
+void outliner_collection_delete(struct bContext *C,
+ struct Main *bmain,
+ struct Scene *scene,
+ struct ReportList *reports,
+ bool hierarchy);
void OUTLINER_OT_collection_new(struct wmOperatorType *ot);
void OUTLINER_OT_collection_duplicate_linked(struct wmOperatorType *ot);
void OUTLINER_OT_collection_duplicate(struct wmOperatorType *ot);
-void OUTLINER_OT_collection_delete(struct wmOperatorType *ot);
+void OUTLINER_OT_collection_hierarchy_delete(struct wmOperatorType *ot);
void OUTLINER_OT_collection_objects_select(struct wmOperatorType *ot);
void OUTLINER_OT_collection_objects_deselect(struct wmOperatorType *ot);
void OUTLINER_OT_collection_link(struct wmOperatorType *ot);
diff --git a/source/blender/editors/space_outliner/outliner_ops.c b/source/blender/editors/space_outliner/outliner_ops.c
index f2c833e48af..e62d400e881 100644
--- a/source/blender/editors/space_outliner/outliner_ops.c
+++ b/source/blender/editors/space_outliner/outliner_ops.c
@@ -66,6 +66,7 @@ void outliner_operatortypes(void)
WM_operatortype_append(OUTLINER_OT_action_set);
WM_operatortype_append(OUTLINER_OT_constraint_operation);
WM_operatortype_append(OUTLINER_OT_modifier_operation);
+ WM_operatortype_append(OUTLINER_OT_delete);
WM_operatortype_append(OUTLINER_OT_show_one_level);
WM_operatortype_append(OUTLINER_OT_show_active);
@@ -87,7 +88,7 @@ void outliner_operatortypes(void)
WM_operatortype_append(OUTLINER_OT_collection_new);
WM_operatortype_append(OUTLINER_OT_collection_duplicate_linked);
WM_operatortype_append(OUTLINER_OT_collection_duplicate);
- WM_operatortype_append(OUTLINER_OT_collection_delete);
+ WM_operatortype_append(OUTLINER_OT_collection_hierarchy_delete);
WM_operatortype_append(OUTLINER_OT_collection_objects_select);
WM_operatortype_append(OUTLINER_OT_collection_objects_deselect);
WM_operatortype_append(OUTLINER_OT_collection_link);
diff --git a/source/blender/editors/space_outliner/outliner_select.c b/source/blender/editors/space_outliner/outliner_select.c
index d50a097e6f6..fa8422573ab 100644
--- a/source/blender/editors/space_outliner/outliner_select.c
+++ b/source/blender/editors/space_outliner/outliner_select.c
@@ -308,10 +308,11 @@ static eOLDrawState tree_element_set_active_object(bContext *C,
bool recursive)
{
TreeStoreElem *tselem = TREESTORE(te);
- TreeStoreElem *parent_tselem;
+ TreeStoreElem *parent_tselem = NULL;
Scene *sce;
Base *base;
Object *ob = NULL;
+ TreeElement *te_ob = NULL;
/* if id is not object, we search back */
if (te->idcode == ID_OB) {
@@ -355,17 +356,25 @@ static eOLDrawState tree_element_set_active_object(bContext *C,
}
}
- parent_tselem = TREESTORE(outliner_find_id(soops, &soops->tree, (ID *)ob));
+ te_ob = outliner_find_id(soops, &soops->tree, (ID *)ob);
+ if (te_ob != NULL && te_ob != te) {
+ parent_tselem = TREESTORE(te_ob);
+ }
+
if (base) {
if (set == OL_SETSEL_EXTEND) {
/* swap select */
if (base->flag & BASE_SELECTED) {
ED_object_base_select(base, BA_DESELECT);
- parent_tselem->flag &= ~TSE_SELECTED;
+ if (parent_tselem) {
+ parent_tselem->flag &= ~TSE_SELECTED;
+ }
}
else {
ED_object_base_select(base, BA_SELECT);
- parent_tselem->flag |= TSE_SELECTED;
+ if (parent_tselem) {
+ parent_tselem->flag |= TSE_SELECTED;
+ }
}
}
else {
@@ -381,7 +390,9 @@ static eOLDrawState tree_element_set_active_object(bContext *C,
BKE_view_layer_base_deselect_all(view_layer);
}
ED_object_base_select(base, BA_SELECT);
- parent_tselem->flag |= TSE_SELECTED;
+ if (parent_tselem) {
+ parent_tselem->flag |= TSE_SELECTED;
+ }
}
if (recursive) {
@@ -1252,7 +1263,7 @@ static bool do_outliner_range_select_recursive(ListBase *lb,
TreeElement *cursor,
bool selecting)
{
- for (TreeElement *te = lb->first; te; te = te->next) {
+ LISTBASE_FOREACH (TreeElement *, te, lb) {
TreeStoreElem *tselem = TREESTORE(te);
if (selecting) {
@@ -1412,9 +1423,7 @@ static int outliner_item_do_activate_from_cursor(bContext *C,
ED_region_tag_redraw_no_rebuild(region);
}
- if (soops->flag & SO_SYNC_SELECT) {
- ED_outliner_select_sync_from_outliner(C, soops);
- }
+ ED_outliner_select_sync_from_outliner(C, soops);
}
return OPERATOR_FINISHED;
@@ -1496,7 +1505,7 @@ static int outliner_box_select_exec(bContext *C, wmOperator *op)
WM_operator_properties_border_to_rctf(op, &rectf);
UI_view2d_region_to_view_rctf(&region->v2d, &rectf, &rectf);
- for (TreeElement *te = soops->tree.first; te; te = te->next) {
+ LISTBASE_FOREACH (TreeElement *, te, &soops->tree) {
outliner_item_box_select(soops, scene, &rectf, te, select);
}
@@ -1504,9 +1513,7 @@ static int outliner_box_select_exec(bContext *C, wmOperator *op)
WM_event_add_notifier(C, NC_SCENE | ND_OB_SELECT, scene);
ED_region_tag_redraw(region);
- if (soops->flag & SO_SYNC_SELECT) {
- ED_outliner_select_sync_from_outliner(C, soops);
- }
+ ED_outliner_select_sync_from_outliner(C, soops);
return OPERATOR_FINISHED;
}
@@ -1744,9 +1751,7 @@ static int outliner_walk_select_invoke(bContext *C, wmOperator *op, const wmEven
/* Scroll outliner to focus on walk element */
outliner_walk_scroll(region, walk_element);
- if (soops->flag & SO_SYNC_SELECT) {
- ED_outliner_select_sync_from_outliner(C, soops);
- }
+ ED_outliner_select_sync_from_outliner(C, soops);
ED_region_tag_redraw(region);
return OPERATOR_FINISHED;
diff --git a/source/blender/editors/space_outliner/outliner_sync.c b/source/blender/editors/space_outliner/outliner_sync.c
index 745a527cc15..852773d3979 100644
--- a/source/blender/editors/space_outliner/outliner_sync.c
+++ b/source/blender/editors/space_outliner/outliner_sync.c
@@ -32,6 +32,7 @@
#include "BLI_compiler_compat.h"
#include "BLI_ghash.h"
+#include "BLI_listbase.h"
#include "BKE_armature.h"
#include "BKE_context.h"
@@ -95,8 +96,8 @@ void ED_outliner_select_sync_flag_outliners(const bContext *C)
wmWindowManager *wm = CTX_wm_manager(C);
for (bScreen *screen = bmain->screens.first; screen; screen = screen->id.next) {
- for (ScrArea *sa = screen->areabase.first; sa; sa = sa->next) {
- for (SpaceLink *sl = sa->spacedata.first; sl; sl = sl->next) {
+ LISTBASE_FOREACH (ScrArea *, area, &screen->areabase) {
+ LISTBASE_FOREACH (SpaceLink *, sl, &area->spacedata) {
if (sl->spacetype == SPACE_OUTLINER) {
SpaceOutliner *soutliner = (SpaceOutliner *)sl;
@@ -318,7 +319,7 @@ static void outliner_sync_selection_from_outliner(Scene *scene,
SelectedItems *selected_items)
{
- for (TreeElement *te = tree->first; te; te = te->next) {
+ LISTBASE_FOREACH (TreeElement *, te, tree) {
TreeStoreElem *tselem = TREESTORE(te);
if (tselem->type == 0 && te->idcode == ID_OB) {
@@ -350,8 +351,9 @@ static void outliner_sync_selection_from_outliner(Scene *scene,
/* Set clean outliner and mark other outliners for syncing */
void ED_outliner_select_sync_from_outliner(bContext *C, SpaceOutliner *soops)
{
- /* Don't sync in certain outliner display modes */
- if (ELEM(soops->outlinevis, SO_LIBRARIES, SO_DATA_API, SO_ID_ORPHANS)) {
+ /* Don't sync if not checked or in certain outliner display modes */
+ if (!(soops->flag & SO_SYNC_SELECT) ||
+ ELEM(soops->outlinevis, SO_LIBRARIES, SO_DATA_API, SO_ID_ORPHANS)) {
return;
}
@@ -499,7 +501,7 @@ static void outliner_sync_selection_to_outliner(ViewLayer *view_layer,
SyncSelectActiveData *active_data,
const SyncSelectTypes *sync_types)
{
- for (TreeElement *te = tree->first; te; te = te->next) {
+ LISTBASE_FOREACH (TreeElement *, te, tree) {
TreeStoreElem *tselem = TREESTORE(te);
if (tselem->type == 0 && te->idcode == ID_OB) {
diff --git a/source/blender/editors/space_outliner/outliner_tools.c b/source/blender/editors/space_outliner/outliner_tools.c
index 12be08550af..80a63af3f42 100644
--- a/source/blender/editors/space_outliner/outliner_tools.c
+++ b/source/blender/editors/space_outliner/outliner_tools.c
@@ -39,12 +39,14 @@
#include "DNA_pointcloud_types.h"
#include "DNA_scene_types.h"
#include "DNA_sequence_types.h"
+#include "DNA_simulation_types.h"
#include "DNA_volume_types.h"
#include "DNA_world_types.h"
#include "BLI_blenlib.h"
#include "BLI_utildefines.h"
+#include "BKE_anim_data.h"
#include "BKE_animsys.h"
#include "BKE_collection.h"
#include "BKE_constraint.h"
@@ -87,9 +89,9 @@
#include "outliner_intern.h"
-/* ****************************************************** */
-
-/* ************ SELECTION OPERATIONS ********* */
+/* -------------------------------------------------------------------- */
+/** \name ID/Library/Data Set/Un-link Utilities
+ * \{ */
static void set_operation_types(SpaceOutliner *soops,
ListBase *lb,
@@ -159,6 +161,7 @@ static void set_operation_types(SpaceOutliner *soops,
case ID_HA:
case ID_PT:
case ID_VO:
+ case ID_SIM:
is_standard_id = true;
break;
case ID_WM:
@@ -411,7 +414,12 @@ static void outliner_do_libdata_operation(bContext *C,
}
}
-/* ******************************************** */
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Scene Menu Operator
+ * \{ */
+
typedef enum eOutliner_PropSceneOps {
OL_SCENE_OP_DELETE = 1,
} eOutliner_PropSceneOps;
@@ -499,7 +507,12 @@ void OUTLINER_OT_scene_operation(wmOperatorType *ot)
ot->prop = RNA_def_enum(ot->srna, "type", prop_scene_op_types, 0, "Scene Operation", "");
}
-/* ******************************************** */
+
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Search Utilities
+ * \{ */
/**
* Stores the parent and a child element of a merged icon-row icon for
@@ -517,7 +530,7 @@ static void merged_element_search_cb_recursive(
char name[64];
int iconid;
- for (TreeElement *te = tree->first; te; te = te->next) {
+ LISTBASE_FOREACH (TreeElement *, te, tree) {
TreeStoreElem *tselem = TREESTORE(te);
if (tree_element_id_type_to_index(te) == type && tselem_type == tselem->type) {
@@ -540,10 +553,10 @@ static void merged_element_search_cb_recursive(
}
/* Get a list of elements that match the search string */
-static void merged_element_search_cb(const bContext *UNUSED(C),
- void *data,
- const char *str,
- uiSearchItems *items)
+static void merged_element_search_update_fn(const bContext *UNUSED(C),
+ void *data,
+ const char *str,
+ uiSearchItems *items)
{
MergedSearchData *search_data = (MergedSearchData *)data;
TreeElement *parent = search_data->parent_element;
@@ -555,7 +568,7 @@ static void merged_element_search_cb(const bContext *UNUSED(C),
}
/* Activate an element from the merged element search menu */
-static void merged_element_search_call_cb(struct bContext *C, void *UNUSED(arg1), void *element)
+static void merged_element_search_exec_fn(struct bContext *C, void *UNUSED(arg1), void *element)
{
SpaceOutliner *soops = CTX_wm_space_outliner(C);
TreeElement *te = (TreeElement *)element;
@@ -563,9 +576,7 @@ static void merged_element_search_call_cb(struct bContext *C, void *UNUSED(arg1)
outliner_item_select(soops, te, false, false);
outliner_item_do_activate_from_tree_element(C, te, te->store_elem, false, false);
- if (soops->flag & SO_SYNC_SELECT) {
- ED_outliner_select_sync_from_outliner(C, soops);
- }
+ ED_outliner_select_sync_from_outliner(C, soops);
}
/**
@@ -589,7 +600,7 @@ static uiBlock *merged_element_search_menu(bContext *C, ARegion *region, void *d
but = uiDefSearchBut(
block, search, 0, ICON_VIEWZOOM, sizeof(search), 10, 10, menu_width, UI_UNIT_Y, 0, 0, "");
UI_but_func_search_set(
- but, NULL, merged_element_search_cb, data, NULL, merged_element_search_call_cb, NULL);
+ but, NULL, merged_element_search_update_fn, data, NULL, merged_element_search_exec_fn, NULL);
UI_but_flag_enable(but, UI_BUT_ACTIVATE_ON_INIT);
/* Fake button to hold space for search items */
@@ -642,6 +653,12 @@ static void object_select_cb(bContext *C,
}
}
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Callbacks (Selection, Users & Library) Utilities
+ * \{ */
+
static void object_select_hierarchy_cb(bContext *C,
ReportList *UNUSED(reports),
Scene *UNUSED(scene),
@@ -672,13 +689,10 @@ static void object_deselect_cb(bContext *C,
}
}
-static void object_delete_cb(bContext *C,
- ReportList *reports,
- Scene *scene,
- TreeElement *UNUSED(te),
- TreeStoreElem *UNUSED(tsep),
- TreeStoreElem *tselem,
- void *UNUSED(user_data))
+static void outliner_object_delete(bContext *C,
+ ReportList *reports,
+ Scene *scene,
+ TreeStoreElem *tselem)
{
Object *ob = (Object *)tselem->id;
if (ob) {
@@ -884,7 +898,11 @@ void outliner_do_object_operation(bContext *C,
outliner_do_object_operation_ex(C, reports, scene_act, soops, lb, operation_cb, NULL, true);
}
-/* ******************************************** */
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Internal Tagging Utilities
+ * \{ */
static void clear_animdata_cb(int UNUSED(event),
TreeElement *UNUSED(te),
@@ -913,7 +931,7 @@ static void cleardrivers_animdata_cb(int UNUSED(event),
IdAdtTemplate *iat = (IdAdtTemplate *)tselem->id;
/* just free drivers - stored as a list of F-Curves */
- free_fcurves(&iat->adt->drivers);
+ BKE_fcurves_free(&iat->adt->drivers);
DEG_id_tag_update(tselem->id, ID_RECALC_ANIMATION);
}
@@ -936,7 +954,11 @@ static void refreshdrivers_animdata_cb(int UNUSED(event),
}
}
-/* --------------------------------- */
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Object Operation Utilities
+ * \{ */
typedef enum eOutliner_PropDataOps {
OL_DOP_SELECT = 1,
@@ -1309,13 +1331,16 @@ static void object_batch_delete_hierarchy_cb(bContext *C,
}
}
-/* **************************************** */
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Object Menu Operator
+ * \{ */
enum {
OL_OP_SELECT = 1,
OL_OP_DESELECT,
OL_OP_SELECT_HIERARCHY,
- OL_OP_DELETE,
OL_OP_DELETE_HIERARCHY,
OL_OP_REMAP,
OL_OP_LOCALIZED, /* disabled, see below */
@@ -1331,7 +1356,6 @@ static const EnumPropertyItem prop_object_op_types[] = {
{OL_OP_SELECT, "SELECT", ICON_RESTRICT_SELECT_OFF, "Select", ""},
{OL_OP_DESELECT, "DESELECT", 0, "Deselect", ""},
{OL_OP_SELECT_HIERARCHY, "SELECT_HIERARCHY", 0, "Select Hierarchy", ""},
- {OL_OP_DELETE, "DELETE", ICON_X, "Delete", ""},
{OL_OP_DELETE_HIERARCHY, "DELETE_HIERARCHY", 0, "Delete Hierarchy", ""},
{OL_OP_REMAP,
"REMAP",
@@ -1353,6 +1377,7 @@ static int outliner_object_operation_exec(bContext *C, wmOperator *op)
SpaceOutliner *soops = CTX_wm_space_outliner(C);
int event;
const char *str = NULL;
+ bool selection_changed = false;
/* check for invalid states */
if (soops == NULL) {
@@ -1369,8 +1394,7 @@ static int outliner_object_operation_exec(bContext *C, wmOperator *op)
}
str = "Select Objects";
- DEG_id_tag_update(&scene->id, ID_RECALC_SELECT);
- WM_event_add_notifier(C, NC_SCENE | ND_OB_SELECT, scene);
+ selection_changed = true;
}
else if (event == OL_OP_SELECT_HIERARCHY) {
Scene *sce = scene; // to be able to delete, scenes are set...
@@ -1380,36 +1404,12 @@ static int outliner_object_operation_exec(bContext *C, wmOperator *op)
WM_window_set_active_scene(bmain, C, win, sce);
}
str = "Select Object Hierarchy";
- DEG_id_tag_update(&scene->id, ID_RECALC_SELECT);
- WM_event_add_notifier(C, NC_SCENE | ND_OB_SELECT, scene);
+ selection_changed = true;
}
else if (event == OL_OP_DESELECT) {
outliner_do_object_operation(C, op->reports, scene, soops, &soops->tree, object_deselect_cb);
str = "Deselect Objects";
- DEG_id_tag_update(&scene->id, ID_RECALC_SELECT);
- WM_event_add_notifier(C, NC_SCENE | ND_OB_SELECT, scene);
- }
- else if (event == OL_OP_DELETE) {
- ViewLayer *view_layer = CTX_data_view_layer(C);
- const Base *basact_prev = BASACT(view_layer);
-
- outliner_do_object_operation(C, op->reports, scene, soops, &soops->tree, object_delete_cb);
-
- /* XXX: tree management normally happens from draw_outliner(), but when
- * you're clicking to fast on Delete object from context menu in
- * outliner several mouse events can be handled in one cycle without
- * handling notifiers/redraw which leads to deleting the same object twice.
- * cleanup tree here to prevent such cases. */
- outliner_cleanup_tree(soops);
-
- DEG_relations_tag_update(bmain);
- str = "Delete Objects";
- DEG_id_tag_update(&scene->id, ID_RECALC_SELECT);
- WM_event_add_notifier(C, NC_SCENE | ND_OB_SELECT, scene);
- if (basact_prev != BASACT(view_layer)) {
- WM_event_add_notifier(C, NC_SCENE | ND_OB_ACTIVE, scene);
- WM_msg_publish_rna_prop(mbus, &scene->id, view_layer, LayerObjects, active);
- }
+ selection_changed = true;
}
else if (event == OL_OP_DELETE_HIERARCHY) {
ViewLayer *view_layer = CTX_data_view_layer(C);
@@ -1435,7 +1435,7 @@ static int outliner_object_operation_exec(bContext *C, wmOperator *op)
BKE_id_multi_tagged_delete(bmain);
}
- /* XXX: See OL_OP_DELETE comment above. */
+ /* XXX: See outliner_delete_exec comment below. */
outliner_cleanup_tree(soops);
DEG_relations_tag_update(bmain);
@@ -1446,10 +1446,12 @@ static int outliner_object_operation_exec(bContext *C, wmOperator *op)
WM_event_add_notifier(C, NC_SCENE | ND_OB_ACTIVE, scene);
WM_msg_publish_rna_prop(mbus, &scene->id, view_layer, LayerObjects, active);
}
+ selection_changed = true;
}
else if (event == OL_OP_REMAP) {
outliner_do_libdata_operation(C, op->reports, scene, soops, &soops->tree, id_remap_cb, NULL);
- str = "Remap ID";
+ /* No undo push here, operator does it itself (since it's a modal one, the op_undo_depth trick
+ * does not work here). */
}
else if (event == OL_OP_LOCALIZED) { /* disabled, see above enum (ton) */
outliner_do_object_operation(C, op->reports, scene, soops, &soops->tree, id_local_cb);
@@ -1474,7 +1476,15 @@ static int outliner_object_operation_exec(bContext *C, wmOperator *op)
return OPERATOR_CANCELLED;
}
- ED_undo_push(C, str);
+ if (selection_changed) {
+ DEG_id_tag_update(&scene->id, ID_RECALC_SELECT);
+ WM_event_add_notifier(C, NC_SCENE | ND_OB_SELECT, scene);
+ ED_outliner_select_sync_from_object_tag(C);
+ }
+
+ if (str != NULL) {
+ ED_undo_push(C, str);
+ }
return OPERATOR_FINISHED;
}
@@ -1495,7 +1505,85 @@ void OUTLINER_OT_object_operation(wmOperatorType *ot)
ot->prop = RNA_def_enum(ot->srna, "type", prop_object_op_types, 0, "Object Operation", "");
}
-/* **************************************** */
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Delete Object/Collection Operator
+ * \{ */
+
+static void outliner_objects_delete(
+ bContext *C, Scene *scene, SpaceOutliner *soops, ReportList *reports, ListBase *lb)
+{
+ LISTBASE_FOREACH (TreeElement *, te, lb) {
+ TreeStoreElem *tselem = TREESTORE(te);
+
+ if (tselem->flag & TSE_SELECTED) {
+ if (tselem->type == 0 && te->idcode == ID_OB) {
+ outliner_object_delete(C, reports, scene, tselem);
+ }
+ }
+
+ if (TSELEM_OPEN(tselem, soops)) {
+ outliner_objects_delete(C, scene, soops, reports, &te->subtree);
+ }
+ }
+}
+
+static int outliner_delete_exec(bContext *C, wmOperator *op)
+{
+ Main *bmain = CTX_data_main(C);
+ Scene *scene = CTX_data_scene(C);
+ SpaceOutliner *soops = CTX_wm_space_outliner(C);
+ struct wmMsgBus *mbus = CTX_wm_message_bus(C);
+
+ ViewLayer *view_layer = CTX_data_view_layer(C);
+ const Base *basact_prev = BASACT(view_layer);
+
+ outliner_collection_delete(C, bmain, scene, op->reports, false);
+ outliner_objects_delete(C, scene, soops, op->reports, &soops->tree);
+
+ /* Tree management normally happens from draw_outliner(), but when
+ * you're clicking too fast on Delete object from context menu in
+ * outliner several mouse events can be handled in one cycle without
+ * handling notifiers/redraw which leads to deleting the same object twice.
+ * cleanup tree here to prevent such cases. */
+ outliner_cleanup_tree(soops);
+
+ DEG_id_tag_update(&scene->id, ID_RECALC_COPY_ON_WRITE);
+ DEG_relations_tag_update(bmain);
+
+ if (basact_prev != BASACT(view_layer)) {
+ WM_event_add_notifier(C, NC_SCENE | ND_OB_ACTIVE, scene);
+ WM_msg_publish_rna_prop(mbus, &scene->id, view_layer, LayerObjects, active);
+ }
+
+ DEG_id_tag_update(&scene->id, ID_RECALC_SELECT);
+ WM_event_add_notifier(C, NC_SCENE | ND_OB_SELECT, scene);
+ ED_outliner_select_sync_from_object_tag(C);
+
+ return OPERATOR_FINISHED;
+}
+
+void OUTLINER_OT_delete(wmOperatorType *ot)
+{
+ /* identifiers */
+ ot->name = "Delete";
+ ot->idname = "OUTLINER_OT_delete";
+ ot->description = "Delete selected objects and collections";
+
+ /* callbacks */
+ ot->exec = outliner_delete_exec;
+ ot->poll = ED_operator_outliner_active;
+
+ /* flags */
+ ot->flag |= OPTYPE_REGISTER | OPTYPE_UNDO;
+}
+
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name ID-Data Menu Operator
+ * \{ */
typedef enum eOutlinerIdOpTypes {
OUTLINER_IDOP_INVALID = 0,
@@ -1596,6 +1684,7 @@ static const EnumPropertyItem *outliner_id_operation_itemf(bContext *C,
static int outliner_id_operation_exec(bContext *C, wmOperator *op)
{
+ wmWindowManager *wm = CTX_wm_manager(C);
Scene *scene = CTX_data_scene(C);
SpaceOutliner *soops = CTX_wm_space_outliner(C);
int scenelevel = 0, objectlevel = 0, idlevel = 0, datalevel = 0;
@@ -1716,16 +1805,23 @@ static int outliner_id_operation_exec(bContext *C, wmOperator *op)
if (idlevel > 0) {
outliner_do_libdata_operation(
C, op->reports, scene, soops, &soops->tree, id_remap_cb, NULL);
- ED_undo_push(C, "Remap");
+ /* No undo push here, operator does it itself (since it's a modal one, the op_undo_depth
+ * trick does not work here). */
}
break;
}
case OUTLINER_IDOP_COPY: {
+ wm->op_undo_depth++;
WM_operator_name_call(C, "OUTLINER_OT_id_copy", WM_OP_INVOKE_DEFAULT, NULL);
+ wm->op_undo_depth--;
+ /* No need for undo, this operation does not change anything... */
break;
}
case OUTLINER_IDOP_PASTE: {
+ wm->op_undo_depth++;
WM_operator_name_call(C, "OUTLINER_OT_id_paste", WM_OP_INVOKE_DEFAULT, NULL);
+ wm->op_undo_depth--;
+ ED_outliner_select_sync_from_all_tag(C);
ED_undo_push(C, "Paste");
break;
}
@@ -1759,6 +1855,7 @@ static int outliner_id_operation_exec(bContext *C, wmOperator *op)
case OUTLINER_IDOP_SELECT_LINKED:
outliner_do_libdata_operation(
C, op->reports, scene, soops, &soops->tree, id_select_linked_cb, NULL);
+ ED_outliner_select_sync_from_all_tag(C);
ED_undo_push(C, "Select");
break;
@@ -1793,7 +1890,11 @@ void OUTLINER_OT_id_operation(wmOperatorType *ot)
RNA_def_enum_funcs(ot->prop, outliner_id_operation_itemf);
}
-/* **************************************** */
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Library Menu Operator
+ * \{ */
typedef enum eOutlinerLibOpTypes {
OL_LIB_INVALID = 0,
@@ -1838,7 +1939,6 @@ static int outliner_lib_operation_exec(bContext *C, wmOperator *op)
switch (event) {
case OL_LIB_RENAME: {
- /* rename */
outliner_do_libdata_operation(
C, op->reports, scene, soops, &soops->tree, item_rename_cb, NULL);
@@ -1853,16 +1953,17 @@ static int outliner_lib_operation_exec(bContext *C, wmOperator *op)
break;
}
case OL_LIB_RELOCATE: {
- /* rename */
outliner_do_libdata_operation(
C, op->reports, scene, soops, &soops->tree, lib_relocate_cb, NULL);
- ED_undo_push(C, "Relocate Library");
+ /* No undo push here, operator does it itself (since it's a modal one, the op_undo_depth
+ * trick does not work here). */
break;
}
case OL_LIB_RELOAD: {
- /* rename */
outliner_do_libdata_operation(
C, op->reports, scene, soops, &soops->tree, lib_reload_cb, NULL);
+ /* No undo push here, operator does it itself (since it's a modal one, the op_undo_depth
+ * trick does not work here). */
break;
}
default:
@@ -1894,7 +1995,11 @@ void OUTLINER_OT_lib_operation(wmOperatorType *ot)
ot->srna, "type", outliner_lib_op_type_items, 0, "Library Operation", "");
}
-/* **************************************** */
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Outliner Set Active Action Operator
+ * \{ */
static void outliner_do_id_set_operation(
SpaceOutliner *soops,
@@ -1920,8 +2025,6 @@ static void outliner_do_id_set_operation(
}
}
-/* ------------------------------------------ */
-
static void actionset_id_cb(TreeElement *UNUSED(te),
TreeStoreElem *tselem,
TreeStoreElem *tsep,
@@ -2009,7 +2112,7 @@ void OUTLINER_OT_action_set(wmOperatorType *ot)
ot->poll = ED_operator_outliner_active;
/* flags */
- ot->flag = 0;
+ ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
/* props */
// TODO: this would be nicer as an ID-pointer...
@@ -2019,7 +2122,11 @@ void OUTLINER_OT_action_set(wmOperatorType *ot)
ot->prop = prop;
}
-/* **************************************** */
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Animation Menu Operator
+ * \{ */
typedef enum eOutliner_AnimDataOps {
OUTLINER_ANIMOP_INVALID = 0,
@@ -2053,6 +2160,7 @@ static const EnumPropertyItem prop_animdata_op_types[] = {
static int outliner_animdata_operation_exec(bContext *C, wmOperator *op)
{
+ wmWindowManager *wm = CTX_wm_manager(C);
SpaceOutliner *soops = CTX_wm_space_outliner(C);
int scenelevel = 0, objectlevel = 0, idlevel = 0, datalevel = 0;
eOutliner_AnimDataOps event;
@@ -2081,7 +2189,10 @@ static int outliner_animdata_operation_exec(bContext *C, wmOperator *op)
case OUTLINER_ANIMOP_SET_ACT:
/* delegate once again... */
+ wm->op_undo_depth++;
WM_operator_name_call(C, "OUTLINER_OT_action_set", WM_OP_INVOKE_REGION_WIN, NULL);
+ wm->op_undo_depth--;
+ ED_undo_push(C, "Set active action");
break;
case OUTLINER_ANIMOP_CLEAR_ACT:
@@ -2135,7 +2246,11 @@ void OUTLINER_OT_animdata_operation(wmOperatorType *ot)
ot->prop = RNA_def_enum(ot->srna, "type", prop_animdata_op_types, 0, "Animation Operation", "");
}
-/* **************************************** */
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Constraint Menu Operator
+ * \{ */
static const EnumPropertyItem prop_constraint_op_types[] = {
{OL_CONSTRAINTOP_ENABLE, "ENABLE", ICON_HIDE_OFF, "Enable", ""},
@@ -2181,7 +2296,11 @@ void OUTLINER_OT_constraint_operation(wmOperatorType *ot)
ot->srna, "type", prop_constraint_op_types, 0, "Constraint Operation", "");
}
-/* ******************** */
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Modifier Menu Operator
+ * \{ */
static const EnumPropertyItem prop_modifier_op_types[] = {
{OL_MODIFIER_OP_TOGVIS, "TOGVIS", ICON_RESTRICT_VIEW_OFF, "Toggle viewport use", ""},
@@ -2226,7 +2345,11 @@ void OUTLINER_OT_modifier_operation(wmOperatorType *ot)
ot->prop = RNA_def_enum(ot->srna, "type", prop_modifier_op_types, 0, "Modifier Operation", "");
}
-/* ******************** */
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Data Menu Operator
+ * \{ */
// XXX: select linked is for RNA structs only
static const EnumPropertyItem prop_data_op_types[] = {
@@ -2319,7 +2442,11 @@ void OUTLINER_OT_data_operation(wmOperatorType *ot)
ot->prop = RNA_def_enum(ot->srna, "type", prop_data_op_types, 0, "Data Operation", "");
}
-/* ******************** */
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Context Menu Operator
+ * \{ */
static int outliner_operator_menu(bContext *C, const char *opname)
{
@@ -2331,11 +2458,9 @@ static int outliner_operator_menu(bContext *C, const char *opname)
uiLayoutSetOperatorContext(layout, WM_OP_INVOKE_REGION_WIN);
uiItemsEnumO(layout, ot->idname, RNA_property_identifier(ot->prop));
- MenuType *mt = WM_menutype_find("OUTLINER_MT_context", false);
- if (mt) {
- uiItemS(layout);
- UI_menutype_draw(C, mt, layout);
- }
+ uiItemS(layout);
+
+ uiItemMContents(layout, "OUTLINER_MT_context_menu");
UI_popup_menu_end(C, pup);
@@ -2363,6 +2488,7 @@ static int do_outliner_operation_event(
/* Only redraw, don't rebuild here because TreeElement pointers will
* become invalid and operations will crash. */
ED_region_tag_redraw_no_rebuild(region);
+ ED_outliner_select_sync_from_outliner(C, soops);
}
set_operation_types(soops, &soops->tree, &scenelevel, &objectlevel, &idlevel, &datalevel);
@@ -2470,14 +2596,8 @@ static int outliner_operation(bContext *C, wmOperator *UNUSED(op), const wmEvent
}
}
- /* Menus for clicking in empty space. */
- if (soops->outlinevis == SO_VIEW_LAYER) {
- WM_menu_name_call(C, "OUTLINER_MT_collection_new", WM_OP_INVOKE_REGION_WIN);
- return OPERATOR_FINISHED;
- }
-
- WM_menu_name_call(C, "OUTLINER_MT_context", WM_OP_INVOKE_REGION_WIN);
- return OPERATOR_FINISHED;
+ /* Let this fall through to 'OUTLINER_MT_context_menu'. */
+ return OPERATOR_PASS_THROUGH;
}
/* Menu only! Calls other operators */
@@ -2492,4 +2612,4 @@ void OUTLINER_OT_operation(wmOperatorType *ot)
ot->poll = ED_operator_outliner_active;
}
-/* ****************************************************** */
+/** \} */
diff --git a/source/blender/editors/space_outliner/outliner_tree.c b/source/blender/editors/space_outliner/outliner_tree.c
index d89a755f1c6..d6efe683673 100644
--- a/source/blender/editors/space_outliner/outliner_tree.c
+++ b/source/blender/editors/space_outliner/outliner_tree.c
@@ -46,6 +46,7 @@
#include "DNA_pointcloud_types.h"
#include "DNA_scene_types.h"
#include "DNA_sequence_types.h"
+#include "DNA_simulation_types.h"
#include "DNA_speaker_types.h"
#include "DNA_volume_types.h"
#include "DNA_world_types.h"
@@ -58,7 +59,7 @@
#include "BLT_translation.h"
-#include "BKE_fcurve.h"
+#include "BKE_fcurve_driver.h"
#include "BKE_idtype.h"
#include "BKE_layer.h"
#include "BKE_lib_id.h"
@@ -773,6 +774,13 @@ static void outliner_add_id_contents(SpaceOutliner *soops,
outliner_add_element(soops, &te->subtree, volume, te, TSE_ANIM_DATA, 0);
break;
}
+ case ID_SIM: {
+ Simulation *simulation = (Simulation *)id;
+ if (outliner_animdata_test(simulation->adt)) {
+ outliner_add_element(soops, &te->subtree, simulation, te, TSE_ANIM_DATA, 0);
+ }
+ break;
+ }
default:
break;
}
@@ -1254,7 +1262,7 @@ static bool outliner_library_id_show(Library *lib, ID *id, short filter_id_type)
Collection *collection = (Collection *)id;
bool has_non_scene_parent = false;
- for (CollectionParent *cparent = collection->parents.first; cparent; cparent = cparent->next) {
+ LISTBASE_FOREACH (CollectionParent *, cparent, &collection->parents) {
if (!(cparent->collection->flag & COLLECTION_IS_MASTER)) {
has_non_scene_parent = true;
}
@@ -1387,7 +1395,7 @@ static void outliner_add_orphaned_datablocks(Main *mainvar, SpaceOutliner *soops
static void outliner_add_layer_collection_objects(
SpaceOutliner *soops, ListBase *tree, ViewLayer *layer, LayerCollection *lc, TreeElement *ten)
{
- for (CollectionObject *cob = lc->collection->gobject.first; cob; cob = cob->next) {
+ LISTBASE_FOREACH (CollectionObject *, cob, &lc->collection->gobject) {
Base *base = BKE_view_layer_base_find(layer, cob->ob);
TreeElement *te_object = outliner_add_element(soops, tree, base->object, ten, 0, 0);
te_object->directdata = base;
@@ -1405,7 +1413,7 @@ static void outliner_add_layer_collections_recursive(SpaceOutliner *soops,
TreeElement *parent_ten,
const bool show_objects)
{
- for (LayerCollection *lc = layer_collections->first; lc; lc = lc->next) {
+ LISTBASE_FOREACH (LayerCollection *, lc, layer_collections) {
const bool exclude = (lc->flag & LAYER_COLLECTION_EXCLUDE) != 0;
TreeElement *ten;
@@ -1419,9 +1427,9 @@ static void outliner_add_layer_collections_recursive(SpaceOutliner *soops,
ten->name = id->name + 2;
ten->directdata = lc;
- /* Open by default. */
+ /* Open by default, except linked collections, which may contain many elements. */
TreeStoreElem *tselem = TREESTORE(ten);
- if (!tselem->used) {
+ if (!(tselem->used || ID_IS_LINKED(id) || ID_IS_OVERRIDE_LIBRARY(id))) {
tselem->flag &= ~TSE_CLOSED;
}
@@ -1468,7 +1476,7 @@ BLI_INLINE void outliner_add_collection_objects(SpaceOutliner *soops,
Collection *collection,
TreeElement *parent)
{
- for (CollectionObject *cob = collection->gobject.first; cob; cob = cob->next) {
+ LISTBASE_FOREACH (CollectionObject *, cob, &collection->gobject) {
outliner_add_element(soops, tree, cob->ob, parent, 0, 0);
}
}
@@ -1479,7 +1487,7 @@ static TreeElement *outliner_add_collection_recursive(SpaceOutliner *soops,
{
outliner_add_collection_init(ten, collection);
- for (CollectionChild *child = collection->children.first; child; child = child->next) {
+ LISTBASE_FOREACH (CollectionChild *, child, &collection->children) {
outliner_add_element(soops, &ten->subtree, &child->collection->id, ten, 0, 0);
}
@@ -1542,7 +1550,7 @@ static void outliner_make_object_parent_hierarchy_collections(SpaceOutliner *soo
continue;
}
- for (LinkData *link = parent_ob_tree_elements->first; link; link = link->next) {
+ LISTBASE_FOREACH (LinkData *, link, parent_ob_tree_elements) {
TreeElement *parent_ob_tree_element = link->data;
TreeElement *parent_ob_collection_tree_element = NULL;
bool found = false;
@@ -1556,8 +1564,7 @@ static void outliner_make_object_parent_hierarchy_collections(SpaceOutliner *soo
parent_ob_collection_tree_element = parent_ob_collection_tree_element->parent;
}
- for (LinkData *link_iter = child_ob_tree_elements->first; link_iter;
- link_iter = link_iter->next) {
+ LISTBASE_FOREACH (LinkData *, link_iter, child_ob_tree_elements) {
TreeElement *child_ob_tree_element = link_iter->data;
if (child_ob_tree_element->parent == parent_ob_collection_tree_element) {
@@ -1589,7 +1596,7 @@ static void outliner_make_object_parent_hierarchy_collections(SpaceOutliner *soo
static void outliner_object_tree_elements_lookup_create_recursive(GHash *object_tree_elements_hash,
TreeElement *te_parent)
{
- for (TreeElement *te = te_parent->subtree.first; te; te = te->next) {
+ LISTBASE_FOREACH (TreeElement *, te, &te_parent->subtree) {
TreeStoreElem *tselem = TREESTORE(te);
if (tselem->type == TSE_LAYER_COLLECTION) {
@@ -2427,7 +2434,7 @@ void outliner_build_tree(
else if (soops->outlinevis == SO_VIEW_LAYER) {
if (soops->filter & SO_FILTER_NO_COLLECTION) {
/* Show objects in the view layer. */
- for (Base *base = view_layer->object_bases.first; base; base = base->next) {
+ LISTBASE_FOREACH (Base *, base, &view_layer->object_bases) {
TreeElement *te_object = outliner_add_element(
soops, &soops->tree, base->object, NULL, 0, 0);
te_object->directdata = base;
diff --git a/source/blender/editors/space_outliner/outliner_utils.c b/source/blender/editors/space_outliner/outliner_utils.c
index 45b46788c8f..a058c30cef2 100644
--- a/source/blender/editors/space_outliner/outliner_utils.c
+++ b/source/blender/editors/space_outliner/outliner_utils.c
@@ -23,6 +23,7 @@
#include <string.h>
+#include "BLI_listbase.h"
#include "BLI_utildefines.h"
#include "DNA_action_types.h"
@@ -77,7 +78,7 @@ TreeElement *outliner_find_item_at_y(const SpaceOutliner *soops,
const ListBase *tree,
float view_co_y)
{
- for (TreeElement *te_iter = tree->first; te_iter; te_iter = te_iter->next) {
+ LISTBASE_FOREACH (TreeElement *, te_iter, tree) {
if (view_co_y < (te_iter->ys + UI_UNIT_Y)) {
if (view_co_y >= te_iter->ys) {
/* co_y is inside this element */
@@ -203,7 +204,7 @@ TreeElement *outliner_find_tse(SpaceOutliner *soops, const TreeStoreElem *tse)
/* Find treestore that refers to given ID */
TreeElement *outliner_find_id(SpaceOutliner *soops, ListBase *lb, const ID *id)
{
- for (TreeElement *te = lb->first; te; te = te->next) {
+ LISTBASE_FOREACH (TreeElement *, te, lb) {
TreeStoreElem *tselem = TREESTORE(te);
if (tselem->type == 0) {
if (tselem->id == id) {
@@ -221,7 +222,7 @@ TreeElement *outliner_find_id(SpaceOutliner *soops, ListBase *lb, const ID *id)
TreeElement *outliner_find_posechannel(ListBase *lb, const bPoseChannel *pchan)
{
- for (TreeElement *te = lb->first; te; te = te->next) {
+ LISTBASE_FOREACH (TreeElement *, te, lb) {
if (te->directdata == pchan) {
return te;
}
@@ -239,7 +240,7 @@ TreeElement *outliner_find_posechannel(ListBase *lb, const bPoseChannel *pchan)
TreeElement *outliner_find_editbone(ListBase *lb, const EditBone *ebone)
{
- for (TreeElement *te = lb->first; te; te = te->next) {
+ LISTBASE_FOREACH (TreeElement *, te, lb) {
if (te->directdata == ebone) {
return te;
}
@@ -360,7 +361,7 @@ float outliner_restrict_columns_width(const SpaceOutliner *soops)
/* Find first tree element in tree with matching treestore flag */
TreeElement *outliner_find_element_with_flag(const ListBase *lb, short flag)
{
- for (TreeElement *te = lb->first; te; te = te->next) {
+ LISTBASE_FOREACH (TreeElement *, te, lb) {
if ((TREESTORE(te)->flag & flag) == flag) {
return te;
}
diff --git a/source/blender/editors/space_outliner/space_outliner.c b/source/blender/editors/space_outliner/space_outliner.c
index 62268a1d455..00b62bc32ce 100644
--- a/source/blender/editors/space_outliner/space_outliner.c
+++ b/source/blender/editors/space_outliner/space_outliner.c
@@ -101,7 +101,7 @@ static void outliner_main_region_free(ARegion *UNUSED(region))
}
static void outliner_main_region_listener(wmWindow *UNUSED(win),
- ScrArea *UNUSED(sa),
+ ScrArea *UNUSED(area),
ARegion *region,
wmNotifier *wmn,
const Scene *UNUSED(scene))
@@ -236,11 +236,11 @@ static void outliner_main_region_message_subscribe(const struct bContext *UNUSED
struct WorkSpace *UNUSED(workspace),
struct Scene *UNUSED(scene),
struct bScreen *UNUSED(screen),
- struct ScrArea *sa,
+ struct ScrArea *area,
struct ARegion *region,
struct wmMsgBus *mbus)
{
- SpaceOutliner *soops = sa->spacedata.first;
+ SpaceOutliner *soops = area->spacedata.first;
wmMsgSubscribeValue msg_sub_value_region_tag_redraw = {
.owner = region,
.user_data = region,
@@ -270,7 +270,7 @@ static void outliner_header_region_free(ARegion *UNUSED(region))
}
static void outliner_header_region_listener(wmWindow *UNUSED(win),
- ScrArea *UNUSED(sa),
+ ScrArea *UNUSED(area),
ARegion *region,
wmNotifier *wmn,
const Scene *UNUSED(scene))
@@ -336,7 +336,7 @@ static void outliner_free(SpaceLink *sl)
}
/* spacetype; init callback */
-static void outliner_init(wmWindowManager *UNUSED(wm), ScrArea *UNUSED(sa))
+static void outliner_init(wmWindowManager *UNUSED(wm), ScrArea *UNUSED(area))
{
}
@@ -355,7 +355,7 @@ static SpaceLink *outliner_duplicate(SpaceLink *sl)
return (SpaceLink *)soutlinern;
}
-static void outliner_id_remap(ScrArea *UNUSED(sa), SpaceLink *slink, ID *old_id, ID *new_id)
+static void outliner_id_remap(ScrArea *UNUSED(area), SpaceLink *slink, ID *old_id, ID *new_id)
{
SpaceOutliner *so = (SpaceOutliner *)slink;
@@ -388,12 +388,12 @@ static void outliner_id_remap(ScrArea *UNUSED(sa), SpaceLink *slink, ID *old_id,
}
}
-static void outliner_deactivate(struct ScrArea *sa)
+static void outliner_deactivate(struct ScrArea *area)
{
/* Remove hover highlights */
- SpaceOutliner *soops = sa->spacedata.first;
+ SpaceOutliner *soops = area->spacedata.first;
outliner_flag_set(&soops->tree, TSE_HIGHLIGHTED, false);
- ED_region_tag_redraw(BKE_area_find_region_type(sa, RGN_TYPE_WINDOW));
+ ED_region_tag_redraw(BKE_area_find_region_type(area, RGN_TYPE_WINDOW));
}
/* only called once, from space_api/spacetypes.c */
diff --git a/source/blender/editors/space_script/script_edit.c b/source/blender/editors/space_script/script_edit.c
index 79311cac6b5..e9ed1cec228 100644
--- a/source/blender/editors/space_script/script_edit.c
+++ b/source/blender/editors/space_script/script_edit.c
@@ -92,7 +92,7 @@ static bool script_test_modal_operators(bContext *C)
wmEventHandler_Op *handler = (wmEventHandler_Op *)handler_base;
if (handler->op != NULL) {
wmOperatorType *ot = handler->op->type;
- if (ot->ext.srna) {
+ if (ot->rna_ext.srna) {
return true;
}
}
diff --git a/source/blender/editors/space_script/space_script.c b/source/blender/editors/space_script/space_script.c
index d872facd488..343f35421a4 100644
--- a/source/blender/editors/space_script/space_script.c
+++ b/source/blender/editors/space_script/space_script.c
@@ -94,7 +94,7 @@ static void script_free(SpaceLink *sl)
}
/* spacetype; init callback */
-static void script_init(struct wmWindowManager *UNUSED(wm), ScrArea *UNUSED(sa))
+static void script_init(struct wmWindowManager *UNUSED(wm), ScrArea *UNUSED(area))
{
}
@@ -160,7 +160,7 @@ static void script_header_region_draw(const bContext *C, ARegion *region)
}
static void script_main_region_listener(wmWindow *UNUSED(win),
- ScrArea *UNUSED(sa),
+ ScrArea *UNUSED(area),
ARegion *UNUSED(region),
wmNotifier *UNUSED(wmn),
const Scene *UNUSED(scene))
diff --git a/source/blender/editors/space_sequencer/sequencer_add.c b/source/blender/editors/space_sequencer/sequencer_add.c
index ac9b605b193..6202a3556a4 100644
--- a/source/blender/editors/space_sequencer/sequencer_add.c
+++ b/source/blender/editors/space_sequencer/sequencer_add.c
@@ -51,8 +51,7 @@
#include "RNA_define.h"
#include "RNA_enum_types.h"
-/* for menu/popup icons etc etc*/
-
+/* For menu, popup, icons, etc. */
#include "ED_screen.h"
#include "ED_sequencer.h"
@@ -67,16 +66,16 @@
#include "DEG_depsgraph.h"
#include "DEG_depsgraph_build.h"
-/* own include */
+/* Own include. */
#include "sequencer_intern.h"
typedef struct SequencerAddData {
ImageFormatData im_format;
} SequencerAddData;
-/* Generic functions, reused by add strip operators */
+/* Generic functions, reused by add strip operators. */
-/* avoid passing multiple args and be more verbose */
+/* Avoid passing multiple args and be more verbose. */
#define SEQPROP_STARTFRAME (1 << 0)
#define SEQPROP_ENDFRAME (1 << 1)
#define SEQPROP_NOPATHS (1 << 2)
@@ -101,7 +100,7 @@ static void sequencer_generic_props__internal(wmOperatorType *ot, int flag)
}
if (flag & SEQPROP_ENDFRAME) {
- /* not usual since most strips have a fixed length */
+ /* Not usual since most strips have a fixed length. */
RNA_def_int(ot->srna,
"frame_end",
0,
@@ -119,7 +118,7 @@ static void sequencer_generic_props__internal(wmOperatorType *ot, int flag)
RNA_def_boolean(
ot->srna, "replace_sel", 1, "Replace Selection", "Replace the current selection");
- /* only for python scripts which import strips and place them after */
+ /* Only for python scripts which import strips and place them after. */
prop = RNA_def_boolean(
ot->srna, "overlap", 0, "Allow Overlap", "Don't correct overlap on new sequence strips");
RNA_def_property_flag(prop, PROP_HIDDEN);
@@ -175,7 +174,7 @@ static void sequencer_generic_invoke_xy__internal(bContext *C, wmOperator *op, i
int cfra = (int)CFRA;
- /* effect strips don't need a channel initialized from the mouse */
+ /* Effect strips don't need a channel initialized from the mouse. */
if (!(flag & SEQPROP_NOCHAN) && RNA_struct_property_is_set(op->ptr, "channel") == 0) {
RNA_int_set(op->ptr, "channel", sequencer_generic_invoke_xy_guess_channel(C, type));
}
@@ -203,18 +202,17 @@ static void seq_load_operator_info(SeqLoadInfo *seq_load, bContext *C, wmOperato
memset(seq_load, 0, sizeof(SeqLoadInfo));
seq_load->start_frame = RNA_int_get(op->ptr, "frame_start");
- seq_load->end_frame = seq_load->start_frame; /* un-set */
-
+ seq_load->end_frame = seq_load->start_frame;
seq_load->channel = RNA_int_get(op->ptr, "channel");
- seq_load->len = 1; // images only, if endframe isn't set!
+ seq_load->len = 1;
if ((prop = RNA_struct_find_property(op->ptr, "filepath"))) {
- /* full path, file is set by the caller */
+ /* Full path, file is set by the caller. */
RNA_property_string_get(op->ptr, prop, seq_load->path);
is_file = 1;
}
else if ((prop = RNA_struct_find_property(op->ptr, "directory"))) {
- /* full path, file is set by the caller */
+ /* Full path, file is set by the caller. */
RNA_property_string_get(op->ptr, prop, seq_load->path);
is_file = 0;
}
@@ -252,15 +250,13 @@ static void seq_load_operator_info(SeqLoadInfo *seq_load, bContext *C, wmOperato
seq_load->flag |= SEQ_LOAD_SYNC_FPS;
}
- /* always use this for ops */
+ /* Create consecutive array of strips. */
seq_load->flag |= SEQ_LOAD_FRAME_ADVANCE;
if (is_file == 1) {
BLI_strncpy(seq_load->name, BLI_path_basename(seq_load->path), sizeof(seq_load->name));
}
else if ((prop = RNA_struct_find_property(op->ptr, "files"))) {
- /* used for image strip */
- /* best guess, first images name */
RNA_PROP_BEGIN (op->ptr, itemptr, prop) {
char *name = RNA_string_get_alloc(&itemptr, "name", NULL, 0);
BLI_strncpy(seq_load->name, name, sizeof(seq_load->name));
@@ -278,9 +274,6 @@ static void seq_load_operator_info(SeqLoadInfo *seq_load, bContext *C, wmOperato
seq_load->views_format = imf->views_format;
seq_load->flag |= SEQ_USE_VIEWS;
-
- /* operator custom data is always released after the SeqLoadInfo,
- * no need to handle the memory here */
seq_load->stereo3d_format = &imf->stereo3d_format;
}
}
@@ -332,22 +325,17 @@ static bool seq_effect_add_properties_poll(const bContext *UNUSED(C),
return true;
}
-/* add scene operator */
static int sequencer_add_scene_strip_exec(bContext *C, wmOperator *op)
{
Main *bmain = CTX_data_main(C);
Scene *scene = CTX_data_scene(C);
Editing *ed = BKE_sequencer_editing_get(scene, true);
-
Scene *sce_seq;
+ Sequence *seq;
- Sequence *seq; /* generic strip vars */
-
- int start_frame, channel; /* operator props */
-
+ int start_frame, channel;
start_frame = RNA_int_get(op->ptr, "frame_start");
channel = RNA_int_get(op->ptr, "channel");
-
sce_seq = BLI_findlink(&bmain->scenes, RNA_enum_get(op->ptr, "scene"));
if (sce_seq == NULL) {
@@ -356,11 +344,8 @@ static int sequencer_add_scene_strip_exec(bContext *C, wmOperator *op)
}
seq = BKE_sequence_alloc(ed->seqbasep, start_frame, channel, SEQ_TYPE_SCENE);
- seq->blend_mode = SEQ_TYPE_CROSS; /* so alpha adjustment fade to the strip below */
-
+ seq->blend_mode = SEQ_TYPE_CROSS;
seq->scene = sce_seq;
-
- /* basic defaults */
seq->len = sce_seq->r.efra - sce_seq->r.sfra + 1;
BLI_strncpy(seq->name + 2, sce_seq->id.name + 2, sizeof(seq->name) - 2);
@@ -388,26 +373,23 @@ static int sequencer_add_scene_strip_invoke(bContext *C, wmOperator *op, const w
sequencer_generic_invoke_xy__internal(C, op, 0, SEQ_TYPE_SCENE);
return sequencer_add_scene_strip_exec(C, op);
- // needs a menu
- // return WM_menu_invoke(C, op, event);
}
void SEQUENCER_OT_scene_strip_add(struct wmOperatorType *ot)
{
PropertyRNA *prop;
- /* identifiers */
+ /* Identifiers. */
ot->name = "Add Scene Strip";
ot->idname = "SEQUENCER_OT_scene_strip_add";
ot->description = "Add a strip to the sequencer using a blender scene as a source";
- /* api callbacks */
+ /* Api callbacks. */
ot->invoke = sequencer_add_scene_strip_invoke;
ot->exec = sequencer_add_scene_strip_exec;
-
ot->poll = ED_operator_sequencer_active_editable;
- /* flags */
+ /* Flags. */
ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
sequencer_generic_props__internal(ot, SEQPROP_STARTFRAME);
@@ -417,22 +399,17 @@ void SEQUENCER_OT_scene_strip_add(struct wmOperatorType *ot)
ot->prop = prop;
}
-/* add movieclip operator */
static int sequencer_add_movieclip_strip_exec(bContext *C, wmOperator *op)
{
Main *bmain = CTX_data_main(C);
Scene *scene = CTX_data_scene(C);
Editing *ed = BKE_sequencer_editing_get(scene, true);
-
MovieClip *clip;
+ Sequence *seq;
- Sequence *seq; /* generic strip vars */
-
- int start_frame, channel; /* operator props */
-
+ int start_frame, channel;
start_frame = RNA_int_get(op->ptr, "frame_start");
channel = RNA_int_get(op->ptr, "channel");
-
clip = BLI_findlink(&bmain->movieclips, RNA_enum_get(op->ptr, "clip"));
if (clip == NULL) {
@@ -443,12 +420,10 @@ static int sequencer_add_movieclip_strip_exec(bContext *C, wmOperator *op)
seq = BKE_sequence_alloc(ed->seqbasep, start_frame, channel, SEQ_TYPE_MOVIECLIP);
seq->blend_mode = SEQ_TYPE_CROSS;
seq->clip = clip;
+ seq->len = BKE_movieclip_get_duration(clip);
id_us_ensure_real(&seq->clip->id);
- /* basic defaults */
- seq->len = BKE_movieclip_get_duration(clip);
-
BLI_strncpy(seq->name + 2, clip->id.name + 2, sizeof(seq->name) - 2);
BKE_sequence_base_unique_name_recursive(&ed->seqbase, seq);
@@ -473,26 +448,23 @@ static int sequencer_add_movieclip_strip_invoke(bContext *C, wmOperator *op, con
sequencer_generic_invoke_xy__internal(C, op, 0, SEQ_TYPE_MOVIECLIP);
return sequencer_add_movieclip_strip_exec(C, op);
- // needs a menu
- // return WM_menu_invoke(C, op, event);
}
void SEQUENCER_OT_movieclip_strip_add(struct wmOperatorType *ot)
{
PropertyRNA *prop;
- /* identifiers */
+ /* Identifiers. */
ot->name = "Add MovieClip Strip";
ot->idname = "SEQUENCER_OT_movieclip_strip_add";
ot->description = "Add a movieclip strip to the sequencer";
- /* api callbacks */
+ /* Api callbacks. */
ot->invoke = sequencer_add_movieclip_strip_invoke;
ot->exec = sequencer_add_movieclip_strip_exec;
-
ot->poll = ED_operator_sequencer_active_editable;
- /* flags */
+ /* Flags. */
ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
sequencer_generic_props__internal(ot, SEQPROP_STARTFRAME);
@@ -508,16 +480,12 @@ static int sequencer_add_mask_strip_exec(bContext *C, wmOperator *op)
Main *bmain = CTX_data_main(C);
Scene *scene = CTX_data_scene(C);
Editing *ed = BKE_sequencer_editing_get(scene, true);
-
Mask *mask;
+ Sequence *seq;
- Sequence *seq; /* generic strip vars */
-
- int start_frame, channel; /* operator props */
-
+ int start_frame, channel;
start_frame = RNA_int_get(op->ptr, "frame_start");
channel = RNA_int_get(op->ptr, "channel");
-
mask = BLI_findlink(&bmain->masks, RNA_enum_get(op->ptr, "mask"));
if (mask == NULL) {
@@ -528,12 +496,10 @@ static int sequencer_add_mask_strip_exec(bContext *C, wmOperator *op)
seq = BKE_sequence_alloc(ed->seqbasep, start_frame, channel, SEQ_TYPE_MASK);
seq->blend_mode = SEQ_TYPE_CROSS;
seq->mask = mask;
+ seq->len = BKE_mask_get_duration(mask);
id_us_ensure_real(&seq->mask->id);
- /* basic defaults */
- seq->len = BKE_mask_get_duration(mask);
-
BLI_strncpy(seq->name + 2, mask->id.name + 2, sizeof(seq->name) - 2);
BKE_sequence_base_unique_name_recursive(&ed->seqbase, seq);
@@ -558,26 +524,23 @@ static int sequencer_add_mask_strip_invoke(bContext *C, wmOperator *op, const wm
sequencer_generic_invoke_xy__internal(C, op, 0, SEQ_TYPE_MASK);
return sequencer_add_mask_strip_exec(C, op);
- // needs a menu
- // return WM_menu_invoke(C, op, event);
}
void SEQUENCER_OT_mask_strip_add(struct wmOperatorType *ot)
{
PropertyRNA *prop;
- /* identifiers */
+ /* Identifiers. */
ot->name = "Add Mask Strip";
ot->idname = "SEQUENCER_OT_mask_strip_add";
ot->description = "Add a mask strip to the sequencer";
- /* api callbacks */
+ /* Api callbacks. */
ot->invoke = sequencer_add_mask_strip_invoke;
ot->exec = sequencer_add_mask_strip_exec;
-
ot->poll = ED_operator_sequencer_active_editable;
- /* flags */
+ /* Flags. */
ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
sequencer_generic_props__internal(ot, SEQPROP_STARTFRAME);
@@ -587,9 +550,9 @@ void SEQUENCER_OT_mask_strip_add(struct wmOperatorType *ot)
ot->prop = prop;
}
-static int sequencer_add_generic_strip_exec(bContext *C, wmOperator *op, SeqLoadFunc seq_load_func)
+static int sequencer_add_generic_strip_exec(bContext *C, wmOperator *op, SeqLoadFn seq_load_fn)
{
- Scene *scene = CTX_data_scene(C); /* only for sound */
+ Scene *scene = CTX_data_scene(C);
Editing *ed = BKE_sequencer_editing_get(scene, true);
SeqLoadInfo seq_load;
int tot_files;
@@ -603,7 +566,6 @@ static int sequencer_add_generic_strip_exec(bContext *C, wmOperator *op, SeqLoad
tot_files = RNA_property_collection_length(op->ptr, RNA_struct_find_property(op->ptr, "files"));
if (tot_files > 1) {
- /* multiple files */
char dir_only[FILE_MAX];
char file_only[FILE_MAX];
@@ -614,10 +576,10 @@ static int sequencer_add_generic_strip_exec(bContext *C, wmOperator *op, SeqLoad
RNA_string_get(&itemptr, "name", file_only);
BLI_join_dirfile(seq_load.path, sizeof(seq_load.path), dir_only, file_only);
- /* Set seq_load.name, else all video/audio files get the same name! ugly! */
+ /* Set seq_load.name, otherwise all video/audio files get the same name. */
BLI_strncpy(seq_load.name, file_only, sizeof(seq_load.name));
- seq = seq_load_func(C, ed->seqbasep, &seq_load);
+ seq = seq_load_fn(C, ed->seqbasep, &seq_load);
if (seq) {
sequencer_add_apply_overlap(C, op, seq);
if (seq_load.seq_sound) {
@@ -627,11 +589,10 @@ static int sequencer_add_generic_strip_exec(bContext *C, wmOperator *op, SeqLoad
}
RNA_END;
}
- else {
+ else { /* Single file./ */
Sequence *seq;
+ seq = seq_load_fn(C, ed->seqbasep, &seq_load);
- /* single file */
- seq = seq_load_func(C, ed->seqbasep, &seq_load);
if (seq) {
sequencer_add_apply_overlap(C, op, seq);
if (seq_load.seq_sound) {
@@ -658,7 +619,6 @@ static int sequencer_add_generic_strip_exec(bContext *C, wmOperator *op, SeqLoad
return OPERATOR_FINISHED;
}
-/* add sequencer operators */
static void sequencer_add_init(bContext *UNUSED(C), wmOperator *op)
{
op->customdata = MEM_callocN(sizeof(SequencerAddData), __func__);
@@ -672,9 +632,9 @@ static void sequencer_add_cancel(bContext *UNUSED(C), wmOperator *op)
op->customdata = NULL;
}
-static bool sequencer_add_draw_check_prop(PointerRNA *UNUSED(ptr),
- PropertyRNA *prop,
- void *UNUSED(user_data))
+static bool sequencer_add_draw_check_fn(PointerRNA *UNUSED(ptr),
+ PropertyRNA *prop,
+ void *UNUSED(user_data))
{
const char *prop_id = RNA_property_identifier(prop);
@@ -682,7 +642,6 @@ static bool sequencer_add_draw_check_prop(PointerRNA *UNUSED(ptr),
STREQ(prop_id, "filename"));
}
-/* add movie operator */
static int sequencer_add_movie_strip_exec(bContext *C, wmOperator *op)
{
return sequencer_add_generic_strip_exec(C, op, BKE_sequencer_add_movie_strip);
@@ -696,20 +655,12 @@ static int sequencer_add_movie_strip_invoke(bContext *C,
Scene *scene = CTX_data_scene(C);
Editing *ed = BKE_sequencer_editing_get(scene, false);
- /* only enable "use_framerate" if there aren't any existing strips
- * - When there are no strips yet, there is no harm in enabling this,
- * and it makes the single-strip case really nice for casual users
- * - When there are strips, it's best we don't touch the framerate,
- * as all hell may break loose (e.g. audio strips start overlapping
- * and can't be restored)
- * - These initial guesses can still be manually overridden by users
- * from the modal options panel
- */
+ /* Only enable "use_framerate" if there aren't any existing strips, unless overridden by user. */
if (ed && ed->seqbasep && ed->seqbasep->first) {
RNA_boolean_set(op->ptr, "use_framerate", false);
}
- /* This is for drag and drop */
+ /* This is for drag and drop. */
if ((RNA_struct_property_is_set(op->ptr, "files") && RNA_collection_length(op->ptr, "files")) ||
RNA_struct_property_is_set(op->ptr, "filepath")) {
sequencer_generic_invoke_xy__internal(C, op, SEQPROP_NOPATHS, SEQ_TYPE_MOVIE);
@@ -717,17 +668,14 @@ static int sequencer_add_movie_strip_invoke(bContext *C,
}
sequencer_generic_invoke_xy__internal(C, op, 0, SEQ_TYPE_MOVIE);
-
sequencer_add_init(C, op);
- /* show multiview save options only if scene has multiviews */
+ /* Show multiview save options only if scene use multiview. */
prop = RNA_struct_find_property(op->ptr, "show_multiview");
RNA_property_boolean_set(op->ptr, prop, (scene->r.scemode & R_MULTIVIEW) != 0);
WM_event_add_fileselect(C, op);
return OPERATOR_RUNNING_MODAL;
-
- // return sequencer_add_movie_strip_exec(C, op);
}
static void sequencer_add_draw(bContext *UNUSED(C), wmOperator *op)
@@ -737,15 +685,15 @@ static void sequencer_add_draw(bContext *UNUSED(C), wmOperator *op)
ImageFormatData *imf = &sad->im_format;
PointerRNA imf_ptr, ptr;
- /* main draw call */
+ /* Main draw call. */
RNA_pointer_create(NULL, op->type->srna, op->properties, &ptr);
uiDefAutoButsRNA(
- layout, &ptr, sequencer_add_draw_check_prop, NULL, NULL, UI_BUT_LABEL_ALIGN_NONE, false);
+ layout, &ptr, sequencer_add_draw_check_fn, NULL, NULL, UI_BUT_LABEL_ALIGN_NONE, false);
- /* image template */
+ /* Image template. */
RNA_pointer_create(NULL, &RNA_ImageFormatSettings, imf, &imf_ptr);
- /* multiview template */
+ /* Multiview template. */
if (RNA_boolean_get(op->ptr, "show_multiview")) {
uiTemplateImageFormatViews(layout, &imf_ptr, op->ptr);
}
@@ -754,20 +702,19 @@ static void sequencer_add_draw(bContext *UNUSED(C), wmOperator *op)
void SEQUENCER_OT_movie_strip_add(struct wmOperatorType *ot)
{
- /* identifiers */
+ /* Identifiers. */
ot->name = "Add Movie Strip";
ot->idname = "SEQUENCER_OT_movie_strip_add";
ot->description = "Add a movie strip to the sequencer";
- /* api callbacks */
+ /* Api callbacks. */
ot->invoke = sequencer_add_movie_strip_invoke;
ot->exec = sequencer_add_movie_strip_exec;
ot->cancel = sequencer_add_cancel;
ot->ui = sequencer_add_draw;
-
ot->poll = ED_operator_sequencer_active_editable;
- /* flags */
+ /* Flags. */
ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
WM_operator_properties_filesel(ot,
@@ -787,8 +734,6 @@ void SEQUENCER_OT_movie_strip_add(struct wmOperatorType *ot)
"Use framerate from the movie to keep sound and video in sync");
}
-/* add sound operator */
-
static int sequencer_add_sound_strip_exec(bContext *C, wmOperator *op)
{
return sequencer_add_generic_strip_exec(C, op, BKE_sequencer_add_sound_strip);
@@ -798,7 +743,7 @@ static int sequencer_add_sound_strip_invoke(bContext *C,
wmOperator *op,
const wmEvent *UNUSED(event))
{
- /* This is for drag and drop */
+ /* This is for drag and drop. */
if ((RNA_struct_property_is_set(op->ptr, "files") && RNA_collection_length(op->ptr, "files")) ||
RNA_struct_property_is_set(op->ptr, "filepath")) {
sequencer_generic_invoke_xy__internal(C, op, SEQPROP_NOPATHS, SEQ_TYPE_SOUND_RAM);
@@ -809,25 +754,22 @@ static int sequencer_add_sound_strip_invoke(bContext *C,
WM_event_add_fileselect(C, op);
return OPERATOR_RUNNING_MODAL;
-
- // return sequencer_add_sound_strip_exec(C, op);
}
void SEQUENCER_OT_sound_strip_add(struct wmOperatorType *ot)
{
- /* identifiers */
+ /* Identifiers. */
ot->name = "Add Sound Strip";
ot->idname = "SEQUENCER_OT_sound_strip_add";
ot->description = "Add a sound strip to the sequencer";
- /* api callbacks */
+ /* Api callbacks. */
ot->invoke = sequencer_add_sound_strip_invoke;
ot->exec = sequencer_add_sound_strip_exec;
-
ot->poll = ED_operator_sequencer_active_editable;
- /* flags */
+ /* Flags. */
ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
WM_operator_properties_filesel(ot,
@@ -854,7 +796,6 @@ int sequencer_image_seq_get_minmax_frame(wmOperator *op,
RNA_BEGIN (op->ptr, itemptr, "files") {
char *filename;
int frame;
- /* just get the first filename */
filename = RNA_string_get_alloc(&itemptr, "name", NULL, 0);
if (filename) {
@@ -885,7 +826,6 @@ void sequencer_image_seq_reserve_frames(
int i;
char *filename = NULL;
RNA_BEGIN (op->ptr, itemptr, "files") {
- /* just get the first filename */
filename = RNA_string_get_alloc(&itemptr, "name", NULL, 0);
break;
}
@@ -894,7 +834,7 @@ void sequencer_image_seq_reserve_frames(
if (filename) {
char ext[PATH_MAX];
char filename_stripped[PATH_MAX];
- /* strip the frame from filename and substitute with # */
+ /* Strip the frame from filename and substitute with `#`. */
BLI_path_frame_strip(filename, ext);
for (i = 0; i < len; i++, se++) {
@@ -907,23 +847,20 @@ void sequencer_image_seq_reserve_frames(
}
}
-/* add image operator */
static int sequencer_add_image_strip_exec(bContext *C, wmOperator *op)
{
int minframe, numdigits;
- /* cant use the generic function for this */
- Scene *scene = CTX_data_scene(C); /* only for sound */
+ Scene *scene = CTX_data_scene(C);
Editing *ed = BKE_sequencer_editing_get(scene, true);
SeqLoadInfo seq_load;
Sequence *seq;
-
Strip *strip;
StripElem *se;
const bool use_placeholders = RNA_boolean_get(op->ptr, "use_placeholders");
seq_load_operator_info(&seq_load, C, op);
- /* images are unique in how they handle this - 1 per strip elem */
+ /* Images are unique in how they handle this - 1 per strip elem. */
if (use_placeholders) {
seq_load.len = sequencer_image_seq_get_minmax_frame(
op, seq_load.start_frame, &minframe, &numdigits);
@@ -941,11 +878,10 @@ static int sequencer_add_image_strip_exec(bContext *C, wmOperator *op)
ED_sequencer_deselect_all(scene);
}
- /* main adding function */
+ /* Main adding function. */
seq = BKE_sequencer_add_image_strip(C, ed->seqbasep, &seq_load);
strip = seq->strip;
se = strip->stripdata;
-
seq->blend_mode = SEQ_TYPE_ALPHAOVER;
if (use_placeholders) {
@@ -968,21 +904,18 @@ static int sequencer_add_image_strip_exec(bContext *C, wmOperator *op)
}
BKE_sequence_init_colorspace(seq);
-
BKE_sequence_calc_disp(scene, seq);
-
BKE_sequencer_sort(scene);
- /* last active name */
+ /* Last active name. */
BLI_strncpy(ed->act_imagedir, strip->dir, sizeof(ed->act_imagedir));
-
sequencer_add_apply_overlap(C, op, seq);
if (op->customdata) {
MEM_freeN(op->customdata);
}
- BKE_sequence_invalidate_cache_composite(scene, seq);
+ BKE_sequence_invalidate_cache_composite(scene, seq);
DEG_id_tag_update(&scene->id, ID_RECALC_SEQUENCER_STRIPS);
WM_event_add_notifier(C, NC_SCENE | ND_SEQUENCER, scene);
@@ -996,7 +929,7 @@ static int sequencer_add_image_strip_invoke(bContext *C,
PropertyRNA *prop;
Scene *scene = CTX_data_scene(C);
- /* drag drop has set the names */
+ /* Name set already by drag and drop. */
if (RNA_struct_property_is_set(op->ptr, "files") && RNA_collection_length(op->ptr, "files")) {
sequencer_generic_invoke_xy__internal(
C, op, SEQPROP_ENDFRAME | SEQPROP_NOPATHS, SEQ_TYPE_IMAGE);
@@ -1004,10 +937,9 @@ static int sequencer_add_image_strip_invoke(bContext *C,
}
sequencer_generic_invoke_xy__internal(C, op, SEQPROP_ENDFRAME, SEQ_TYPE_IMAGE);
-
sequencer_add_init(C, op);
- /* show multiview save options only if scene has multiviews */
+ /* Show multiview save options only if scene use multiview. */
prop = RNA_struct_find_property(op->ptr, "show_multiview");
RNA_property_boolean_set(op->ptr, prop, (scene->r.scemode & R_MULTIVIEW) != 0);
@@ -1018,20 +950,19 @@ static int sequencer_add_image_strip_invoke(bContext *C,
void SEQUENCER_OT_image_strip_add(struct wmOperatorType *ot)
{
- /* identifiers */
+ /* Identifiers. */
ot->name = "Add Image Strip";
ot->idname = "SEQUENCER_OT_image_strip_add";
ot->description = "Add an image or image sequence to the sequencer";
- /* api callbacks */
+ /* Api callbacks. */
ot->invoke = sequencer_add_image_strip_invoke;
ot->exec = sequencer_add_image_strip_exec;
ot->cancel = sequencer_add_cancel;
ot->ui = sequencer_add_draw;
-
ot->poll = ED_operator_sequencer_active_editable;
- /* flags */
+ /* Flags. */
ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
WM_operator_properties_filesel(ot,
@@ -1051,65 +982,54 @@ void SEQUENCER_OT_image_strip_add(struct wmOperatorType *ot)
"Use placeholders for missing frames of the strip");
}
-/* add_effect_strip operator */
static int sequencer_add_effect_strip_exec(bContext *C, wmOperator *op)
{
Scene *scene = CTX_data_scene(C);
Editing *ed = BKE_sequencer_editing_get(scene, true);
-
- Sequence *seq; /* generic strip vars */
+ Sequence *seq;
struct SeqEffectHandle sh;
-
- int start_frame, end_frame, channel, type; /* operator props */
-
Sequence *seq1, *seq2, *seq3;
const char *error_msg;
+ int start_frame, end_frame, channel, type;
start_frame = RNA_int_get(op->ptr, "frame_start");
end_frame = RNA_int_get(op->ptr, "frame_end");
channel = RNA_int_get(op->ptr, "channel");
-
type = RNA_enum_get(op->ptr, "type");
- // XXX move to invoke
if (!seq_effect_find_selected(scene, NULL, type, &seq1, &seq2, &seq3, &error_msg)) {
BKE_report(op->reports, RPT_ERROR, error_msg);
return OPERATOR_CANCELLED;
}
- /* If seq1 is NULL and no error was raised it means the seq is standalone
- * (like color strips) and we need to check its start and end frames are valid */
+ /* Check its start and end frames are valid. */
if (seq1 == NULL && end_frame <= start_frame) {
end_frame = start_frame + 1;
RNA_int_set(op->ptr, "frame_end", end_frame);
}
seq = BKE_sequence_alloc(ed->seqbasep, start_frame, channel, type);
-
BLI_strncpy(seq->name + 2, BKE_sequence_give_name(seq), sizeof(seq->name) - 2);
BKE_sequence_base_unique_name_recursive(&ed->seqbase, seq);
sh = BKE_sequence_get_effect(seq);
-
+ sh.init(seq);
seq->seq1 = seq1;
seq->seq2 = seq2;
seq->seq3 = seq3;
- sh.init(seq);
-
- if (!seq1) { /* effect has no deps */
- seq->len = 1;
+ if (!seq1) {
+ seq->len = 1; /* Effect is generator, set non zero length. */
BKE_sequence_tx_set_final_right(seq, end_frame);
}
seq->flag |= SEQ_USE_EFFECT_DEFAULT_FADE;
-
BKE_sequence_calc(scene, seq);
if (seq->type == SEQ_TYPE_COLOR) {
SolidColorVars *colvars = (SolidColorVars *)seq->effectdata;
RNA_float_get_array(op->ptr, "color", colvars->col);
- seq->blend_mode = SEQ_TYPE_CROSS; /* so alpha adjustment fade to the strip below */
+ seq->blend_mode = SEQ_TYPE_CROSS;
}
else if (seq->type == SEQ_TYPE_ADJUSTMENT) {
seq->blend_mode = SEQ_TYPE_CROSS;
@@ -1118,8 +1038,7 @@ static int sequencer_add_effect_strip_exec(bContext *C, wmOperator *op)
seq->blend_mode = SEQ_TYPE_ALPHAOVER;
}
- /* an unset channel is a special case where we automatically go above
- * the other strips. */
+ /* Set channel. If unset, use lowest free one above strips. */
if (!RNA_struct_property_is_set(op->ptr, "channel")) {
if (seq->seq1) {
int chan = max_iii(seq->seq1 ? seq->seq1->machine : 0,
@@ -1134,20 +1053,16 @@ static int sequencer_add_effect_strip_exec(bContext *C, wmOperator *op)
sequencer_add_apply_replace_sel(C, op, seq);
sequencer_add_apply_overlap(C, op, seq);
- BKE_sequencer_update_changed_seq_and_deps(scene, seq, 1, 1); /* runs BKE_sequence_calc */
-
- /* not sure if this is needed with update_changed_seq_and_deps.
- * it was NOT called in blender 2.4x, but wont hurt */
+ BKE_sequencer_update_changed_seq_and_deps(scene, seq, 1, 1); /* Runs BKE_sequence_calc. */
BKE_sequencer_sort(scene);
- BKE_sequence_invalidate_cache_composite(scene, seq);
+ BKE_sequence_invalidate_cache_composite(scene, seq);
DEG_id_tag_update(&scene->id, ID_RECALC_SEQUENCER_STRIPS);
WM_event_add_notifier(C, NC_SCENE | ND_SEQUENCER, scene);
return OPERATOR_FINISHED;
}
-/* add color */
static int sequencer_add_effect_strip_invoke(bContext *C,
wmOperator *op,
const wmEvent *UNUSED(event))
@@ -1159,10 +1074,8 @@ static int sequencer_add_effect_strip_invoke(bContext *C,
if (is_type_set) {
type = RNA_enum_get(op->ptr, "type");
- /* when invoking an effect strip which uses inputs,
- * skip initializing the channel from the mouse.
- * Instead leave the property unset so exec() initializes it to be
- * above the strips its applied to. */
+ /* When invoking an effect strip which uses inputs, skip initializing the channel from the
+ * mouse. */
if (BKE_sequence_effect_get_num_inputs(type) != 0) {
prop_flag |= SEQPROP_NOCHAN;
}
@@ -1177,19 +1090,18 @@ void SEQUENCER_OT_effect_strip_add(struct wmOperatorType *ot)
{
PropertyRNA *prop;
- /* identifiers */
+ /* Identifiers. */
ot->name = "Add Effect Strip";
ot->idname = "SEQUENCER_OT_effect_strip_add";
ot->description = "Add an effect to the sequencer, most are applied on top of existing strips";
- /* api callbacks */
+ /* Api callbacks. */
ot->invoke = sequencer_add_effect_strip_invoke;
ot->exec = sequencer_add_effect_strip_exec;
-
ot->poll = ED_operator_sequencer_active_editable;
ot->poll_property = seq_effect_add_properties_poll;
- /* flags */
+ /* Flags. */
ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
RNA_def_enum(ot->srna,
diff --git a/source/blender/editors/space_sequencer/sequencer_buttons.c b/source/blender/editors/space_sequencer/sequencer_buttons.c
index a2568e2e827..dce8aa16985 100644
--- a/source/blender/editors/space_sequencer/sequencer_buttons.c
+++ b/source/blender/editors/space_sequencer/sequencer_buttons.c
@@ -54,7 +54,7 @@ static bool sequencer_grease_pencil_panel_poll(const bContext *C, PanelType *UNU
{
SpaceSeq *sseq = CTX_wm_space_seq(C);
- /* don't show the gpencil if we are not showing the image */
+ /* Don't show the gpencil if we are not showing the image. */
return ED_space_sequencer_check_show_imbuf(sseq);
}
#endif
diff --git a/source/blender/editors/space_sequencer/sequencer_draw.c b/source/blender/editors/space_sequencer/sequencer_draw.c
index 0766996c00b..1f06ab68516 100644
--- a/source/blender/editors/space_sequencer/sequencer_draw.c
+++ b/source/blender/editors/space_sequencer/sequencer_draw.c
@@ -79,29 +79,26 @@
#include "MEM_guardedalloc.h"
-/* own include */
+/* Own include. */
#include "sequencer_intern.h"
#define SEQ_LEFTHANDLE 1
#define SEQ_RIGHTHANDLE 2
-
#define SEQ_HANDLE_SIZE 8.0f
-
#define SEQ_SCROLLER_TEXT_OFFSET 8
-
#define MUTE_ALPHA 120
/* Note, Don't use SEQ_BEGIN/SEQ_END while drawing!
- * it messes up transform, - Campbell */
+ * it messes up transform. */
#undef SEQ_BEGIN
#undef SEQP_BEGIN
#undef SEQ_END
static Sequence *special_seq_update = NULL;
-void color3ubv_from_seq(Scene *curscene, Sequence *seq, unsigned char col[3])
+void color3ubv_from_seq(Scene *curscene, Sequence *seq, uchar col[3])
{
- unsigned char blendcol[3];
+ uchar blendcol[3];
switch (seq->type) {
case SEQ_TYPE_IMAGE:
@@ -141,7 +138,7 @@ void color3ubv_from_seq(Scene *curscene, Sequence *seq, unsigned char col[3])
col[2] = 130;
break;
- /* effects */
+ /* Effects. */
case SEQ_TYPE_TRANSFORM:
case SEQ_TYPE_SPEED:
case SEQ_TYPE_ADD:
@@ -223,6 +220,10 @@ void color3ubv_from_seq(Scene *curscene, Sequence *seq, unsigned char col[3])
}
}
+/**
+ * \param x1, x2, y1, y2: The starting and end X value to draw the wave, same for y1 and y2.
+ * \param stepsize: The width of a pixel.
+ */
static void draw_seq_waveform(View2D *v2d,
const bContext *C,
SpaceSeq *sseq,
@@ -234,13 +235,7 @@ static void draw_seq_waveform(View2D *v2d,
float y2,
float stepsize)
{
- /*
- * x1 is the starting x value to draw the wave,
- * x2 the end x value, same for y1 and y2
- * stepsize is width of a pixel.
- */
-
- /* offset x1 and x2 values, to match view min/max, if strip is out of bounds */
+ /* Offset x1 and x2 values, to match view min/max, if strip is out of bounds. */
int x1_offset = max_ff(v2d->cur.xmin, x1);
int x2_offset = min_ff(v2d->cur.xmax + 1.0f, x2);
@@ -254,8 +249,6 @@ static void draw_seq_waveform(View2D *v2d,
float volume = seq->volume;
float value1, value2;
bSound *sound = seq->sound;
- FCurve *fcu = id_data_find_fcurve(&scene->id, seq, &RNA_Sequence, "volume", 0, NULL);
-
SoundWaveform *waveform;
if (length < 2) {
@@ -265,7 +258,7 @@ static void draw_seq_waveform(View2D *v2d,
BLI_spin_lock(sound->spinlock);
if (!sound->waveform) {
if (!(sound->tags & SOUND_TAGS_WAVEFORM_LOADING)) {
- /* prevent sounds from reloading */
+ /* Prevent sounds from reloading. */
sound->tags |= SOUND_TAGS_WAVEFORM_LOADING;
BLI_spin_unlock(sound->spinlock);
sequencer_preview_add_sound(C, seq);
@@ -273,15 +266,14 @@ static void draw_seq_waveform(View2D *v2d,
else {
BLI_spin_unlock(sound->spinlock);
}
- return; /* nothing to draw */
+ return; /* Nothing to draw. */
}
BLI_spin_unlock(sound->spinlock);
waveform = sound->waveform;
+ /* Waveform could not be built. */
if (waveform->length == 0) {
- /* BKE_sound_read_waveform() set an empty SoundWaveform data in case it cannot generate a
- * valid one. See T45726. */
return;
}
@@ -299,6 +291,9 @@ static void draw_seq_waveform(View2D *v2d,
return;
}
+ /* Fcurve lookup is quite expensive, so do this after precondition. */
+ FCurve *fcu = id_data_find_fcurve(&scene->id, seq, &RNA_Sequence, "volume", 0, NULL);
+
GPU_blend(true);
GPUVertFormat *format = immVertexFormat();
uint pos = GPU_vertformat_attr_add(format, "pos", GPU_COMP_F32, 2, GPU_FETCH_FLOAT);
@@ -325,7 +320,7 @@ static void draw_seq_waveform(View2D *v2d,
}
}
else if (p + 1 < waveform->length) {
- /* use simple linear interpolation */
+ /* Use simple linear interpolation. */
float f = sampleoffset - p;
value1 = (1.0f - f) * value1 + f * waveform->data[p * 3 + 3];
value2 = (1.0f - f) * value2 + f * waveform->data[p * 3 + 4];
@@ -361,12 +356,10 @@ static void draw_seq_waveform(View2D *v2d,
static void drawmeta_contents(Scene *scene, Sequence *seqm, float x1, float y1, float x2, float y2)
{
- /* note: this used to use SEQ_BEGIN/SEQ_END, but it messes up the
- * seq->depth value, (needed by transform when doing overlap checks)
- * so for now, just use the meta's immediate children, could be fixed but
- * its only drawing - campbell */
+ /* Don't use SEQ_BEGIN/SEQ_END here,
+ * because it changes seq->depth, which is needed for transform. */
Sequence *seq;
- unsigned char col[4];
+ uchar col[4];
int chan_min = MAXSEQ;
int chan_max = 0;
@@ -400,12 +393,12 @@ static void drawmeta_contents(Scene *scene, Sequence *seqm, float x1, float y1,
chan_range = (chan_max - chan_min) + 1;
draw_height = draw_range / chan_range;
- col[3] = 196; /* alpha, used for all meta children */
+ col[3] = 196; /* Alpha, used for all meta children. */
uint pos = GPU_vertformat_attr_add(immVertexFormat(), "pos", GPU_COMP_F32, 2, GPU_FETCH_FLOAT);
-
immBindBuiltinProgram(GPU_SHADER_2D_UNIFORM_COLOR);
+ /* Draw only immediate children (1 level depth). */
for (seq = seqbase->first; seq; seq = seq->next) {
const int startdisp = seq->startdisp + offset;
const int enddisp = seq->enddisp + offset;
@@ -433,7 +426,7 @@ static void drawmeta_contents(Scene *scene, Sequence *seqm, float x1, float y1,
immUniformColor4ubv(col);
- /* clamp within parent sequence strip bounds */
+ /* Clamp within parent sequence strip bounds. */
if (x1_chan < x1) {
x1_chan = x1;
}
@@ -453,29 +446,29 @@ static void drawmeta_contents(Scene *scene, Sequence *seqm, float x1, float y1,
GPU_blend(false);
}
-/* clamp handles to defined size in pixel space */
+/* Get handle width in pixels. */
float sequence_handle_size_get_clamped(Sequence *seq, const float pixelx)
{
const float maxhandle = (pixelx * SEQ_HANDLE_SIZE) * U.pixelsize;
- /* ensure we're not greater than half width */
+ /* Ensure that handle is not wider, than half of strip. */
return min_ff(maxhandle, ((float)(seq->enddisp - seq->startdisp) / 2.0f) / pixelx);
}
-/* draw a handle, for each end of a sequence strip */
+/* Draw a handle, on left or right side of strip. */
static void draw_seq_handle(View2D *v2d,
Sequence *seq,
const float handsize_clamped,
const short direction,
- unsigned int pos,
+ uint pos,
bool seq_active,
float pixelx,
bool y_threshold)
{
float rx1 = 0, rx2 = 0;
float x1, x2, y1, y2;
- unsigned int whichsel = 0;
- unsigned char col[4];
+ uint whichsel = 0;
+ uchar col[4];
x1 = seq->startdisp;
x2 = seq->enddisp;
@@ -483,7 +476,7 @@ static void draw_seq_handle(View2D *v2d,
y1 = seq->machine + SEQ_STRIP_OFSBOTTOM;
y2 = seq->machine + SEQ_STRIP_OFSTOP;
- /* set up co-ordinates/dimensions for either left or right handle */
+ /* Set up co-ordinates and dimensions for either left or right handle. */
if (direction == SEQ_LEFTHANDLE) {
rx1 = x1;
rx2 = x1 + handsize_clamped;
@@ -495,7 +488,6 @@ static void draw_seq_handle(View2D *v2d,
whichsel = SEQ_RIGHTSEL;
}
- /* draw! */
if (!(seq->type & SEQ_TYPE_EFFECT) || BKE_sequence_effect_get_num_inputs(seq->type) == 0) {
GPU_blend(true);
@@ -522,9 +514,7 @@ static void draw_seq_handle(View2D *v2d,
GPU_blend(false);
}
- /* Draw numbers for start and end of the strip next to its handles.
- * - Draw only when handles are selected or while translating the strip.
- */
+ /* Draw numbers for start and end of the strip next to its handles. */
if (y_threshold &&
(((seq->flag & SELECT) && (G.moving & G_TRANSFORM_SEQ)) || (seq->flag & whichsel))) {
@@ -557,7 +547,7 @@ static void draw_seq_handle(View2D *v2d,
}
static void draw_seq_outline(Sequence *seq,
- unsigned int pos,
+ uint pos,
float x1,
float x2,
float y1,
@@ -566,7 +556,7 @@ static void draw_seq_outline(Sequence *seq,
float pixely,
bool seq_active)
{
- unsigned char col[3];
+ uchar col[3];
/* Get the color for the outline. */
if (seq_active && (seq->flag & SELECT)) {
@@ -575,8 +565,8 @@ static void draw_seq_outline(Sequence *seq,
else if (seq->flag & SELECT) {
UI_GetThemeColor3ubv(TH_SEQ_SELECTED, col);
}
- /* Regular color for unselected strips: a bit darker than the background. */
else {
+ /* Color for unselected strips is a bit darker than the background. */
UI_GetThemeColor3ubv(TH_BACK, col);
UI_GetColorPtrShade3ubv(col, col, -40);
}
@@ -610,13 +600,13 @@ static void draw_seq_outline(Sequence *seq,
/* Top */
immRectf(pos, x1 - pixelx, y2 - 2 * pixely, x2 + pixelx, y2);
}
- /* 1px wide outline for unselected strips. */
else {
+ /* 1px wide outline for unselected strips. */
imm_draw_box_wire_2d(pos, x1, y1, x2, y2);
}
}
-/* draw info text on a sequence strip */
+/* Draw info text on a sequence strip. */
static void draw_seq_text(View2D *v2d,
Sequence *seq,
SpaceSeq *sseq,
@@ -633,7 +623,7 @@ static void draw_seq_text(View2D *v2d,
const char *name = seq->name + 2;
uchar col[4];
- /* note, all strings should include 'name' */
+ /* All strings should include name. */
if (name[0] == '\0') {
name = BKE_sequence_give_name(seq);
}
@@ -723,7 +713,7 @@ static void draw_seq_text(View2D *v2d,
seq->len);
}
else {
- /* should never get here!, but might with files from future */
+ /* Should never get here!, but might with files from future. */
BLI_assert(0);
str_len = BLI_snprintf(str, sizeof(str), "%s | %d", name, seq->len);
@@ -751,10 +741,10 @@ static void draw_seq_text(View2D *v2d,
UI_view2d_text_cache_add_rectf(v2d, &rect, str, str_len, col);
}
-static void draw_sequence_extensions(Scene *scene, Sequence *seq, unsigned int pos, float pixely)
+static void draw_sequence_extensions(Scene *scene, Sequence *seq, uint pos, float pixely)
{
float x1, x2, y1, y2;
- unsigned char col[4], blend_col[3];
+ uchar col[4], blend_col[3];
x1 = seq->startdisp;
x2 = seq->enddisp;
@@ -793,9 +783,9 @@ static void draw_sequence_extensions(Scene *scene, Sequence *seq, unsigned int p
GPU_blend(false);
}
-static void draw_color_strip_band(Sequence *seq, unsigned int pos, float text_margin_y, float y1)
+static void draw_color_strip_band(Sequence *seq, uint pos, float text_margin_y, float y1)
{
- unsigned char col[4];
+ uchar col[4];
SolidColorVars *colvars = (SolidColorVars *)seq->effectdata;
rgb_float_to_uchar(col, colvars->col);
@@ -827,14 +817,14 @@ static void draw_color_strip_band(Sequence *seq, unsigned int pos, float text_ma
static void draw_seq_background(Scene *scene,
Sequence *seq,
- unsigned int pos,
+ uint pos,
float x1,
float x2,
float y1,
float y2,
bool is_single_image)
{
- unsigned char col[4];
+ uchar col[4];
/* Get the correct color per strip type, transitions use their inputs ones. */
if (ELEM(seq->type, SEQ_TYPE_CROSS, SEQ_TYPE_GAMCROSS, SEQ_TYPE_WIPE)) {
@@ -888,7 +878,7 @@ static void draw_seq_background(Scene *scene,
}
}
- /* Transition strips.. Draw right half. */
+ /* Draw right half of transition strips. */
if (ELEM(seq->type, SEQ_TYPE_CROSS, SEQ_TYPE_GAMCROSS, SEQ_TYPE_WIPE)) {
float vert_pos[3][2];
Sequence *seq1 = seq->seq1;
@@ -966,7 +956,7 @@ static void calculate_seq_text_offsets(
float scroller_vert_xoffs = (V2D_SCROLL_HANDLE_WIDTH + SEQ_SCROLLER_TEXT_OFFSET) * pixelx;
- /* info text on the strip */
+ /* Info text on the strip. */
if (*x1 < v2d->cur.xmin + scroller_vert_xoffs) {
*x1 = v2d->cur.xmin + scroller_vert_xoffs;
}
@@ -981,11 +971,102 @@ static void calculate_seq_text_offsets(
}
}
-/*
- * Draw a sequence strip, bounds check already made
- * ARegion is currently only used to get the windows width in pixels
- * so wave file sample drawing precision is zoom adjusted
+static void fcurve_batch_add_verts(GPUVertBuf *vbo,
+ float y1,
+ float y2,
+ float y_height,
+ int cfra,
+ float curve_val,
+ unsigned int *vert_count)
+{
+ float vert_pos[2][2];
+
+ copy_v2_fl2(vert_pos[0], cfra, (curve_val * y_height) + y1);
+ copy_v2_fl2(vert_pos[1], cfra, y2);
+
+ GPU_vertbuf_vert_set(vbo, *vert_count, vert_pos[0]);
+ GPU_vertbuf_vert_set(vbo, *vert_count + 1, vert_pos[1]);
+ *vert_count += 2;
+}
+
+/**
+ * Draw f-curves as darkened regions of the strip:
+ * - Volume for sound strips.
+ * - Opacity for the other types.
*/
+static void draw_seq_fcurve(
+ Scene *scene, View2D *v2d, Sequence *seq, float x1, float y1, float x2, float y2, float pixelx)
+{
+ FCurve *fcu;
+
+ if (seq->type == SEQ_TYPE_SOUND_RAM) {
+ fcu = id_data_find_fcurve(&scene->id, seq, &RNA_Sequence, "volume", 0, NULL);
+ }
+ else {
+ fcu = id_data_find_fcurve(&scene->id, seq, &RNA_Sequence, "blend_alpha", 0, NULL);
+ }
+
+ if (fcu && !BKE_fcurve_is_empty(fcu)) {
+
+ /* Clamp curve evaluation to the editor's borders. */
+ int eval_start = max_ff(x1, v2d->cur.xmin);
+ int eval_end = min_ff(x2, v2d->cur.xmax + 1);
+
+ int eval_step = max_ii(1, floor(pixelx));
+
+ if (eval_start >= eval_end) {
+ return;
+ }
+
+ GPUVertFormat format = {0};
+ GPU_vertformat_attr_add(&format, "pos", GPU_COMP_F32, 2, GPU_FETCH_FLOAT);
+ GPUVertBuf *vbo = GPU_vertbuf_create_with_format(&format);
+
+ uint max_verts = 2 * ((eval_end - eval_start) / eval_step + 1);
+ GPU_vertbuf_data_alloc(vbo, max_verts);
+ uint vert_count = 0;
+
+ const float y_height = y2 - y1;
+ float curve_val;
+ float prev_val = INT_MIN;
+ bool skip = false;
+
+ for (int cfra = eval_start; cfra <= eval_end; cfra += eval_step) {
+ curve_val = evaluate_fcurve(fcu, cfra);
+ CLAMP(curve_val, 0.0f, 1.0f);
+
+ /* Avoid adding adjacent verts that have the same value. */
+ if (curve_val == prev_val && cfra < eval_end - eval_step) {
+ skip = true;
+ continue;
+ }
+
+ /* If some frames were skipped above, we need to close the shape. */
+ if (skip) {
+ fcurve_batch_add_verts(vbo, y1, y2, y_height, cfra - eval_step, prev_val, &vert_count);
+ skip = false;
+ }
+
+ fcurve_batch_add_verts(vbo, y1, y2, y_height, cfra, curve_val, &vert_count);
+ prev_val = curve_val;
+ }
+
+ GPUBatch *batch = GPU_batch_create_ex(GPU_PRIM_TRI_STRIP, vbo, NULL, GPU_BATCH_OWNS_VBO);
+ GPU_vertbuf_data_len_set(vbo, vert_count);
+ GPU_batch_program_set_builtin(batch, GPU_SHADER_2D_UNIFORM_COLOR);
+ GPU_batch_uniform_4f(batch, "color", 0.0f, 0.0f, 0.0f, 0.15f);
+ GPU_blend(true);
+
+ if (vert_count > 0) {
+ GPU_batch_draw(batch);
+ }
+
+ GPU_blend(false);
+ GPU_batch_discard(batch);
+ }
+}
+
+/* Draw visible strips. Bounds check are already made. */
static void draw_seq_strip(const bContext *C,
SpaceSeq *sseq,
Scene *scene,
@@ -999,20 +1080,19 @@ static void draw_seq_strip(const bContext *C,
const float handsize_clamped = sequence_handle_size_get_clamped(seq, pixelx);
float pixely = BLI_rctf_size_y(&v2d->cur) / BLI_rcti_size_y(&v2d->mask);
- /* We need to know if this is a single image/color or not for drawing. */
+ /* Check if we are doing "solo preview". */
bool is_single_image = (char)BKE_sequence_single_check(seq);
- /* body */
+ /* Draw strip body. */
x1 = (seq->startstill) ? seq->start : seq->startdisp;
y1 = seq->machine + SEQ_STRIP_OFSBOTTOM;
x2 = (seq->endstill) ? (seq->start + seq->len) : seq->enddisp;
y2 = seq->machine + SEQ_STRIP_OFSTOP;
- /* Position of the text,
- * make sure that the strip content is visible also when the strip height gets lower. */
+ /* Calculate height needed for drawing text on strip. */
float text_margin_y = y2 - min_ff(0.40f, 20 * U.dpi_fac * pixely);
- /* Show some content only when the strip is high enough. */
+ /* Is there enough space for drawing something else than text? */
bool y_threshold = ((y2 - y1) / pixely) > 20 * U.dpi_fac;
uint pos = GPU_vertformat_attr_add(immVertexFormat(), "pos", GPU_COMP_F32, 2, GPU_FETCH_FLOAT);
@@ -1020,12 +1100,12 @@ static void draw_seq_strip(const bContext *C,
draw_seq_background(scene, seq, pos, x1, x2, y1, y2, is_single_image);
- /* Color strips.. Draw a band with the strip's color on its lower part. */
+ /* Draw a color band inside color strip. */
if (seq->type == SEQ_TYPE_COLOR && y_threshold) {
draw_color_strip_band(seq, pos, text_margin_y, y1);
}
- /* Draw strip's offsets when flag is enabled or during "solo preview". */
+ /* Draw strip offsets when flag is enabled or during "solo preview". */
if (!is_single_image && (seq->startofs || seq->endofs) && pixely > 0) {
if ((sseq->draw_flag & SEQ_DRAW_OFFSET_EXT) || (seq == special_seq_update)) {
draw_sequence_extensions(scene, seq, pos, pixely);
@@ -1042,7 +1122,11 @@ static void draw_seq_strip(const bContext *C,
drawmeta_contents(scene, seq, x1, y1, x2, y2);
}
- /* Sound strips.. Draw waveforms. */
+ if (sseq->flag & SEQ_SHOW_FCURVES) {
+ draw_seq_fcurve(scene, v2d, seq, x1, y1, x2, y2, pixelx);
+ }
+
+ /* Draw sound strip waveform. */
if ((seq->type == SEQ_TYPE_SOUND_RAM) && (sseq->flag & SEQ_NO_WAVEFORMS) == 0) {
draw_seq_waveform(v2d,
C,
@@ -1061,7 +1145,7 @@ static void draw_seq_strip(const bContext *C,
draw_seq_locked(x1, y1, x2, y2);
}
- /* Missing media indication.. Draw a red line on the top of the strip. */
+ /* Draw Red line on the top of invalid strip (Missing media). */
if (!BKE_sequence_is_valid_check(seq)) {
draw_seq_invalid(x1, x2, y2, text_margin_y);
}
@@ -1082,11 +1166,9 @@ static void draw_seq_strip(const bContext *C,
calculate_seq_text_offsets(v2d, seq, &x1, &x2, pixelx);
- /* Draw the text on the top section of the strip,
- * - depending on the vertical space, move it to the center or don't draw it.
- * - don't draw it when there is not enough horizontal space.
- */
+ /* Don't draw strip if there is not enough vertical or horizontal space. */
if (((x2 - x1) > 32 * pixelx * U.dpi_fac) && ((y2 - y1) > 8 * pixely * U.dpi_fac)) {
+ /* Depending on the vertical space, draw text on top or in the center of strip. */
draw_seq_text(
v2d, seq, sseq, x1, x2, y_threshold ? text_margin_y : y1, y2, seq_active, y_threshold);
}
@@ -1203,7 +1285,7 @@ ImBuf *sequencer_ibuf_get(struct Main *bmain,
GPU_framebuffer_bind(fb);
}
- /* restore state so real rendering would be canceled (if needed) */
+ /* Restore state so real rendering would be canceled if needed. */
G.is_break = is_break;
return ibuf;
@@ -1239,7 +1321,7 @@ static void sequencer_check_scopes(SequencerScopes *scopes, ImBuf *ibuf)
}
}
-static ImBuf *sequencer_make_scope(Scene *scene, ImBuf *ibuf, ImBuf *(*make_scope_cb)(ImBuf *ibuf))
+static ImBuf *sequencer_make_scope(Scene *scene, ImBuf *ibuf, ImBuf *(*make_scope_fn)(ImBuf *ibuf))
{
ImBuf *display_ibuf = IMB_dupImBuf(ibuf);
ImBuf *scope;
@@ -1247,7 +1329,7 @@ static ImBuf *sequencer_make_scope(Scene *scene, ImBuf *ibuf, ImBuf *(*make_scop
IMB_colormanagement_imbuf_make_display_space(
display_ibuf, &scene->view_settings, &scene->display_settings);
- scope = make_scope_cb(display_ibuf);
+ scope = make_scope_fn(display_ibuf);
IMB_freeImBuf(display_ibuf);
@@ -1264,17 +1346,17 @@ static void sequencer_display_size(Scene *scene, float r_viewrect[2])
static void sequencer_draw_gpencil(const bContext *C)
{
- /* draw grease-pencil (image aligned) */
+ /* Draw grease-pencil (image aligned). */
ED_annotation_draw_2dimage(C);
- /* ortho at pixel level */
+ /* Ortho at pixel level. */
UI_view2d_view_restore(C);
- /* draw grease-pencil (screen aligned) */
+ /* Draw grease-pencil (screen aligned). */
ED_annotation_draw_view2d(C, 0);
}
-/* draws content borders plus safety borders if needed */
+/* Draw content and safety borders borders. */
static void sequencer_draw_borders(const SpaceSeq *sseq, const View2D *v2d, const Scene *scene)
{
float x1 = v2d->tot.xmin;
@@ -1284,7 +1366,7 @@ static void sequencer_draw_borders(const SpaceSeq *sseq, const View2D *v2d, cons
GPU_line_width(1.0f);
- /* border */
+ /* Draw border. */
const uint shdr_pos = GPU_vertformat_attr_add(
immVertexFormat(), "pos", GPU_COMP_F32, 2, GPU_FETCH_FLOAT);
@@ -1301,7 +1383,7 @@ static void sequencer_draw_borders(const SpaceSeq *sseq, const View2D *v2d, cons
imm_draw_box_wire_2d(shdr_pos, x1 - 0.5f, y1 - 0.5f, x2 + 0.5f, y2 + 0.5f);
- /* safety border */
+ /* Draw safety border. */
if (sseq->flag & SEQ_SHOW_SAFE_MARGINS) {
immUniformThemeColorBlend(TH_VIEW_OVERLAY, TH_BACK, 0.25f);
@@ -1325,8 +1407,8 @@ static void sequencer_draw_borders(const SpaceSeq *sseq, const View2D *v2d, cons
#if 0
void sequencer_draw_maskedit(const bContext *C, Scene *scene, ARegion *region, SpaceSeq *sseq)
{
- /* NOTE: sequencer mask editing isnt finished, the draw code is working but editing not,
- * for now just disable drawing since the strip frame will likely be offset */
+ /* NOTE: sequencer mask editing isnt finished, the draw code is working but editing not.
+ * For now just disable drawing since the strip frame will likely be offset. */
// if (sc->mode == SC_MODE_MASKEDIT)
if (0 && sseq->mainb == SEQ_DRAW_IMG_IMBUF) {
@@ -1377,8 +1459,8 @@ static void *sequencer_OCIO_transform_ibuf(
force_fallback |= (ED_draw_imbuf_method(ibuf) != IMAGE_DRAW_METHOD_GLSL);
force_fallback |= (ibuf->dither != 0.0f);
+ /* Fallback to CPU based color space conversion. */
if (force_fallback) {
- /* Fallback to CPU based color space conversion */
*r_glsl_used = false;
*r_format = GL_RGBA;
*r_type = GL_UNSIGNED_BYTE;
@@ -1423,9 +1505,8 @@ static void *sequencer_OCIO_transform_ibuf(
display_buffer = NULL;
}
- /* there's a data to be displayed, but GLSL is not initialized
- * properly, in this case we fallback to CPU-based display transform
- */
+ /* There is data to be displayed, but GLSL is not initialized
+ * properly, in this case we fallback to CPU-based display transform. */
if ((ibuf->rect || ibuf->rect_float) && !*r_glsl_used) {
display_buffer = IMB_display_buffer_acquire_ctx(C, ibuf, &cache_handle);
*r_format = GL_RGBA;
@@ -1441,14 +1522,12 @@ static void *sequencer_OCIO_transform_ibuf(
static void sequencer_stop_running_jobs(const bContext *C, Scene *scene)
{
if (G.is_rendering == false && (scene->r.seq_prev_type) == OB_RENDER) {
- /* stop all running jobs, except screen one. currently previews frustrate Render
- * needed to make so sequencer's rendering doesn't conflict with compositor
- */
+ /* Stop all running jobs, except screen one. Currently previews frustrate Render.
+ * Need to make so sequencer's rendering doesn't conflict with compositor. */
WM_jobs_kill_type(CTX_wm_manager(C), NULL, WM_JOB_TYPE_COMPOSITE);
- /* in case of final rendering used for preview, kill all previews,
- * otherwise threading conflict will happen in rendering module
- */
+ /* In case of final rendering used for preview, kill all previews,
+ * otherwise threading conflict will happen in rendering module. */
WM_jobs_kill_type(CTX_wm_manager(C), NULL, WM_JOB_TYPE_RENDER_PREVIEW);
}
}
@@ -1521,8 +1600,7 @@ static void sequencer_draw_display_buffer(const bContext *C,
}
/* Format needs to be created prior to any immBindProgram call.
- * Do it here because OCIO binds it's own shader.
- */
+ * Do it here because OCIO binds it's own shader. */
int format, type;
bool glsl_used = false;
GLuint texid;
@@ -1538,7 +1616,7 @@ static void sequencer_draw_display_buffer(const bContext *C,
IMB_rect_from_float(ibuf);
}
- display_buffer = (unsigned char *)ibuf->rect;
+ display_buffer = (uchar *)ibuf->rect;
format = GL_RGBA;
type = GL_UNSIGNED_BYTE;
}
@@ -1671,7 +1749,7 @@ static ImBuf *sequencer_get_scope(Scene *scene, SpaceSeq *sseq, ImBuf *ibuf, boo
break;
}
- /* future files may have new scopes we don't catch above */
+ /* Future files may have new scopes we don't catch above. */
if (scope) {
scopes->reference_ibuf = ibuf;
}
@@ -1708,13 +1786,13 @@ void sequencer_draw_preview(const bContext *C,
return;
}
- /* Setup view */
+ /* Setup view. */
sequencer_display_size(scene, viewrect);
UI_view2d_totRect_set(v2d, viewrect[0] + 0.5f, viewrect[1] + 0.5f);
UI_view2d_curRect_validate(v2d);
UI_view2d_view_ortho(v2d);
- /* Draw background */
+ /* Draw background. */
if (!draw_backdrop && (!draw_overlay || sseq->overlay_type == SEQ_DRAW_OVERLAY_REFERENCE)) {
sequencer_preview_clear();
@@ -1722,18 +1800,18 @@ void sequencer_draw_preview(const bContext *C,
imm_draw_box_checker_2d(v2d->tot.xmin, v2d->tot.ymin, v2d->tot.xmax, v2d->tot.ymax);
}
}
- /* Get image */
+ /* Get image. */
ibuf = sequencer_ibuf_get(
bmain, depsgraph, scene, sseq, cfra, frame_ofs, names[sseq->multiview_eye]);
if (ibuf) {
scope = sequencer_get_scope(scene, sseq, ibuf, draw_backdrop);
- /* Draw image */
+ /* Draw image. */
sequencer_draw_display_buffer(
C, scene, region, sseq, ibuf, scope, draw_overlay, draw_backdrop);
- /* Draw over image */
+ /* Draw over image. */
if (sseq->flag & SEQ_SHOW_METADATA) {
ED_region_image_metadata_draw(0.0, 0.0, ibuf, &v2d->tot, 1.0, 1.0);
}
@@ -1746,12 +1824,11 @@ void sequencer_draw_preview(const bContext *C,
if (draw_gpencil && show_imbuf) {
sequencer_draw_gpencil(C);
}
+#if 0
+ sequencer_draw_maskedit(C, scene, region, sseq);
+#endif
- /* TODO */
- /* sequencer_draw_maskedit(C, scene, region, sseq); */
-
- /* Scope is freed in sequencer_check_scopes when ibuf changes and
- * scope image is to be replaced. */
+ /* Scope is freed in sequencer_check_scopes when ibuf changes and redraw is needed. */
if (ibuf) {
IMB_freeImBuf(ibuf);
}
@@ -1760,7 +1837,7 @@ void sequencer_draw_preview(const bContext *C,
seq_prefetch_wm_notify(C, scene);
}
-/* draw backdrop of the sequencer strips view */
+/* Draw backdrop in sequencer timeline. */
static void draw_seq_backdrop(View2D *v2d)
{
int i;
@@ -1768,11 +1845,11 @@ static void draw_seq_backdrop(View2D *v2d)
uint pos = GPU_vertformat_attr_add(immVertexFormat(), "pos", GPU_COMP_F32, 2, GPU_FETCH_FLOAT);
immBindBuiltinProgram(GPU_SHADER_2D_UNIFORM_COLOR);
- /* darker gray overlay over the view backdrop */
+ /* Darker gray overlay over the view backdrop. */
immUniformThemeColorShade(TH_BACK, -20);
immRectf(pos, v2d->cur.xmin, -1.0, v2d->cur.xmax, 1.0);
- /* Alternating horizontal stripes */
+ /* Alternating horizontal stripes. */
i = max_ii(1, ((int)v2d->cur.ymin) - 1);
while (i < v2d->cur.ymax) {
@@ -1788,7 +1865,7 @@ static void draw_seq_backdrop(View2D *v2d)
i++;
}
- /* Darker lines separating the horizontal bands */
+ /* Darker lines separating the horizontal bands. */
i = max_ii(1, ((int)v2d->cur.ymin) - 1);
int line_len = (int)v2d->cur.ymax - i + 1;
immUniformThemeColor(TH_GRID);
@@ -1802,7 +1879,6 @@ static void draw_seq_backdrop(View2D *v2d)
immUnbindProgram();
}
-/* draw the contents of the sequencer strips view */
static void draw_seq_strips(const bContext *C, Editing *ed, ARegion *region)
{
Scene *scene = CTX_data_scene(C);
@@ -1812,12 +1888,12 @@ static void draw_seq_strips(const bContext *C, Editing *ed, ARegion *region)
int sel = 0, j;
float pixelx = BLI_rctf_size_x(&v2d->cur) / BLI_rcti_size_x(&v2d->mask);
- /* loop through twice, first unselected, then selected */
+ /* Loop through twice, first unselected, then selected. */
for (j = 0; j < 2; j++) {
Sequence *seq;
- /* loop through strips, checking for those that are visible */
+ /* Loop through strips, checking for those that are visible. */
for (seq = ed->seqbasep->first; seq; seq = seq->next) {
- /* boundbox and selection tests for NOT drawing the strip... */
+ /* Boundbox and selection tests for NOT drawing the strip. */
if ((seq->flag & SELECT) != sel) {
continue;
}
@@ -1837,11 +1913,11 @@ static void draw_seq_strips(const bContext *C, Editing *ed, ARegion *region)
continue;
}
- /* strip passed all tests unscathed... so draw it now */
+ /* Strip passed all tests, draw it now. */
draw_seq_strip(C, sseq, scene, region, seq, pixelx, seq == last_seq ? true : false);
}
- /* draw selected next time round */
+ /* Draw selected next time round. */
sel = SELECT;
}
@@ -1872,7 +1948,7 @@ static void draw_seq_strips(const bContext *C, Editing *ed, ARegion *region)
}
}
- /* draw highlight when previewing a single strip */
+ /* Draw highlight if "solo preview" is used. */
if (special_seq_update) {
const Sequence *seq = special_seq_update;
GPU_blend(true);
@@ -1904,8 +1980,7 @@ static void seq_draw_sfra_efra(Scene *scene, View2D *v2d)
uint pos = GPU_vertformat_attr_add(immVertexFormat(), "pos", GPU_COMP_F32, 2, GPU_FETCH_FLOAT);
immBindBuiltinProgram(GPU_SHADER_2D_UNIFORM_COLOR);
- /* draw darkened area outside of active timeline
- * frame range used is preview range or scene range */
+ /* Draw overlay outside of frame range. */
immUniformThemeColorShadeAlpha(TH_BACK, -25, -100);
if (frame_sta < frame_end) {
@@ -1918,7 +1993,7 @@ static void seq_draw_sfra_efra(Scene *scene, View2D *v2d)
immUniformThemeColorShade(TH_BACK, -60);
- /* thin lines where the actual frames are */
+ /* Draw frame range boundary. */
immBegin(GPU_PRIM_LINES, 4);
immVertex2f(pos, frame_sta, v2d->cur.ymin);
@@ -1929,7 +2004,7 @@ static void seq_draw_sfra_efra(Scene *scene, View2D *v2d)
immEnd();
- /* While inside a meta strip, draw a checkerboard pattern outside of its range. */
+ /* While in meta strip, draw a checkerboard overlay outside of frame range. */
if (ed && !BLI_listbase_is_empty(&ed->metastack)) {
MetaStack *ms = ed->metastack.last;
immUnbindProgram();
@@ -1979,8 +2054,8 @@ typedef struct CacheDrawData {
size_t final_out_vert_count;
} CacheDrawData;
-/* Called as a callback */
-static bool draw_cache_view_init_cb(void *userdata, size_t item_count)
+/* Called as a callback. */
+static bool draw_cache_view_init_fn(void *userdata, size_t item_count)
{
if (item_count == 0) {
return true;
@@ -1998,7 +2073,7 @@ static bool draw_cache_view_init_cb(void *userdata, size_t item_count)
}
/* Called as a callback */
-static bool draw_cache_view_iter_cb(
+static bool draw_cache_view_iter_fn(
void *userdata, struct Sequence *seq, int nfra, int cache_type, float UNUSED(cost))
{
CacheDrawData *drawdata = userdata;
@@ -2162,7 +2237,7 @@ static void draw_cache_view(const bContext *C)
userdata.composite_vbo = GPU_vertbuf_create_with_format(&format);
userdata.final_out_vbo = GPU_vertbuf_create_with_format(&format);
- BKE_sequencer_cache_iterate(scene, &userdata, draw_cache_view_init_cb, draw_cache_view_iter_cb);
+ BKE_sequencer_cache_iterate(scene, &userdata, draw_cache_view_init_fn, draw_cache_view_iter_fn);
draw_cache_view_batch(userdata.raw_vbo, userdata.raw_vert_count, 1.0f, 0.1f, 0.02f, 0.4f);
draw_cache_view_batch(
@@ -2175,7 +2250,7 @@ static void draw_cache_view(const bContext *C)
GPU_blend(false);
}
-/* Draw Timeline/Strip Editor Mode for Sequencer */
+/* Draw sequencer timeline. */
void draw_timeline_seq(const bContext *C, ARegion *region)
{
Scene *scene = CTX_data_scene(C);
@@ -2188,7 +2263,6 @@ void draw_timeline_seq(const bContext *C, ARegion *region)
seq_prefetch_wm_notify(C, scene);
- /* clear and setup matrix */
UI_GetThemeColor3fv(TH_BACK, col);
if (ed && ed->metastack.first) {
GPU_clear_color(col[0], col[1], col[2] - 0.1f, 0.0f);
@@ -2199,44 +2273,36 @@ void draw_timeline_seq(const bContext *C, ARegion *region)
GPU_clear(GPU_COLOR_BIT);
UI_view2d_view_ortho(v2d);
-
- /* calculate extents of sequencer strips/data
- * NOTE: needed for the scrollers later
- */
+ /* Get timeline boundbox, needed for the scrollers. */
boundbox_seq(scene, &v2d->tot);
-
- /* draw backdrop */
draw_seq_backdrop(v2d);
-
- /* regular grid-pattern over the rest of the view (i.e. 1-second grid lines) */
UI_view2d_constant_grid_draw(v2d, FPS);
- /* Only draw backdrop in pure sequence view. */
+ /* Only draw backdrop in timeline view. */
if (sseq->view == SEQ_VIEW_SEQUENCE && sseq->draw_flag & SEQ_DRAW_BACKDROP) {
sequencer_draw_preview(C, scene, region, sseq, scene->r.cfra, 0, false, true);
UI_view2d_view_ortho(v2d);
}
+ /* Draw attached callbacks. */
ED_region_draw_cb_draw(C, region, REGION_DRAW_PRE_VIEW);
-
seq_draw_sfra_efra(scene, v2d);
- /* sequence strips (if there is data available to be drawn) */
if (ed) {
- /* draw the data */
draw_seq_strips(C, ed, region);
- /* text draw cached (for sequence names), in pixelspace now */
+ /* Draw text added in previous function. */
UI_view2d_text_cache_draw(region);
}
- /* current frame */
UI_view2d_view_ortho(v2d);
if ((sseq->flag & SEQ_DRAWFRAMES) == 0) {
cfra_flag |= DRAWCFRA_UNIT_SECONDS;
}
+
+ /* Draw the current frame indicator. */
ANIM_draw_cfra(C, v2d, cfra_flag);
- /* overlap playhead */
+ /* Draw overlap frame frame indicator. */
if (scene->ed && scene->ed->over_flag & SEQ_EDIT_OVERLAY_SHOW) {
int cfra_over = (scene->ed->over_flag & SEQ_EDIT_OVERLAY_ABS) ?
scene->ed->over_cfra :
@@ -2247,7 +2313,8 @@ void draw_timeline_seq(const bContext *C, ARegion *region)
float viewport_size[4];
GPU_viewport_size_get_f(viewport_size);
immUniform2f("viewport_size", viewport_size[2], viewport_size[3]);
- immUniform1i("colors_len", 0); /* "simple" mode */
+ /* Shader may have color set from past usage - reset it. */
+ immUniform1i("colors_len", 0);
immUniform1f("dash_width", 20.0f * U.pixelsize);
immUniform1f("dash_factor", 0.5f);
immUniformThemeColor(TH_CFRAME);
@@ -2260,7 +2327,6 @@ void draw_timeline_seq(const bContext *C, ARegion *region)
immUnbindProgram();
}
- /* markers */
UI_view2d_view_orthoSpecial(region, v2d, 1);
int marker_draw_flag = DRAW_MARKERS_MARGIN;
if (sseq->flag & SEQ_SHOW_MARKERS) {
@@ -2268,28 +2334,22 @@ void draw_timeline_seq(const bContext *C, ARegion *region)
}
UI_view2d_view_ortho(v2d);
- /* draw cache on top of markers area */
+
if (ed) {
draw_cache_view(C);
}
- /* preview range */
+
ANIM_draw_previewrange(C, v2d, 1);
- /* callback */
+ /* Draw registered callbacks. */
ED_region_draw_cb_draw(C, region, REGION_DRAW_POST_VIEW);
-
- /* reset view matrix */
UI_view2d_view_restore(C);
-
- /* scrubbing region */
ED_time_scrub_draw(region, scene, !(sseq->flag & SEQ_DRAWFRAMES), true);
-
- /* scrollers */
scrollers = UI_view2d_scrollers_calc(v2d, NULL);
UI_view2d_scrollers_draw(v2d, scrollers);
UI_view2d_scrollers_free(scrollers);
- /* channel numbers */
+ /* Draw channel numbers. */
{
rcti rect;
BLI_rcti_init(
diff --git a/source/blender/editors/space_sequencer/sequencer_edit.c b/source/blender/editors/space_sequencer/sequencer_edit.c
index 71e63547eae..ea0d5785d22 100644
--- a/source/blender/editors/space_sequencer/sequencer_edit.c
+++ b/source/blender/editors/space_sequencer/sequencer_edit.c
@@ -52,10 +52,11 @@
#include "RNA_define.h"
#include "RNA_enum_types.h"
-/* for menu/popup icons etc etc*/
+/* For menu, popup, icons, etc. */
#include "ED_anim_api.h"
#include "ED_numinput.h"
+#include "ED_outliner.h"
#include "ED_screen.h"
#include "ED_sequencer.h"
#include "ED_space_api.h"
@@ -67,11 +68,11 @@
#include "DEG_depsgraph.h"
#include "DEG_depsgraph_build.h"
-/* own include */
+/* Own include. */
#include "sequencer_intern.h"
/* XXX */
-/* RNA Enums, used in multiple files */
+/* RNA Enums, used in multiple files. */
EnumPropertyItem sequencer_prop_effect_types[] = {
{SEQ_TYPE_CROSS, "CROSS", 0, "Crossfade", "Crossfade effect strip type"},
{SEQ_TYPE_ADD, "ADD", 0, "Add", "Add effect strip type"},
@@ -94,8 +95,6 @@ EnumPropertyItem sequencer_prop_effect_types[] = {
{0, NULL, 0, NULL, NULL},
};
-/* mute operator */
-
#define SEQ_SIDE_MOUSE -1
EnumPropertyItem prop_side_types[] = {
@@ -144,7 +143,7 @@ static void proxy_freejob(void *pjv)
MEM_freeN(pj);
}
-/* only this runs inside thread */
+/* Only this runs inside thread. */
static void proxy_startjob(void *pjv, short *stop, short *do_update, float *progress)
{
ProxyJob *pj = pjv;
@@ -185,7 +184,7 @@ static void seq_proxy_build_job(const bContext *C, ReportList *reports)
struct Depsgraph *depsgraph = CTX_data_depsgraph_pointer(C);
Scene *scene = CTX_data_scene(C);
Editing *ed = BKE_sequencer_editing_get(scene, false);
- ScrArea *sa = CTX_wm_area(C);
+ ScrArea *area = CTX_wm_area(C);
Sequence *seq;
GSet *file_list;
@@ -215,25 +214,46 @@ static void seq_proxy_build_job(const bContext *C, ReportList *reports)
}
file_list = BLI_gset_new(BLI_ghashutil_strhash_p, BLI_ghashutil_strcmp, "file list");
+ bool selected = false; /* Check for no selected strips */
+
SEQP_BEGIN (ed, seq) {
- if ((seq->flag & SELECT)) {
- bool success = BKE_sequencer_proxy_rebuild_context(
- pj->main, pj->depsgraph, pj->scene, seq, file_list, &pj->queue);
- if (!success) {
- BKE_reportf(reports, RPT_ERROR, "Could not build proxy for strip %s", seq->name);
- }
+ if (!ELEM(seq->type, SEQ_TYPE_MOVIE, SEQ_TYPE_IMAGE, SEQ_TYPE_META) ||
+ (seq->flag & SELECT) == 0) {
+ continue;
+ }
+
+ selected = true;
+ if (!(seq->flag & SEQ_USE_PROXY)) {
+ BKE_reportf(reports, RPT_WARNING, "Proxy is not enabled for %s, skipping.", seq->name);
+ continue;
+ }
+ else if (seq->strip->proxy->build_size_flags == 0) {
+ BKE_reportf(reports, RPT_WARNING, "Resolution is not selected for %s, skipping.", seq->name);
+ continue;
+ }
+
+ bool success = BKE_sequencer_proxy_rebuild_context(
+ pj->main, pj->depsgraph, pj->scene, seq, file_list, &pj->queue);
+
+ if (!success && (seq->strip->proxy->build_flags & SEQ_PROXY_SKIP_EXISTING) != 0) {
+ BKE_reportf(reports, RPT_WARNING, "Overwrite is not checked for %s, skipping.", seq->name);
}
}
SEQ_END;
+ if (!selected) {
+ BKE_reportf(reports, RPT_WARNING, "Select movie or image strips.");
+ return;
+ }
+
BLI_gset_free(file_list, MEM_freeN);
- if (!WM_jobs_is_running(wm_job)) {
+ if (selected && !WM_jobs_is_running(wm_job)) {
G.is_break = false;
WM_jobs_start(CTX_wm_manager(C), wm_job);
}
- ED_area_tag_redraw(sa);
+ ED_area_tag_redraw(area);
}
/* ********************************************************************** */
@@ -256,7 +276,7 @@ void boundbox_seq(Scene *scene, rctf *rect)
return;
}
- min[0] = 0.0;
+ min[0] = SFRA;
max[0] = EFRA + 1;
min[1] = 0.0;
max[1] = 8.0;
@@ -291,7 +311,7 @@ static int mouse_frame_side(View2D *v2d, short mouse_x, int frame)
mval[0] = mouse_x;
mval[1] = 0;
- /* choose the side based on which side of the playhead the mouse is on */
+ /* Choose the side based on which side of the current frame the mouse is on. */
UI_view2d_region_to_view(v2d, mval[0], mval[1], &mouseloc[0], &mouseloc[1]);
return mouseloc[0] > frame ? SEQ_SIDE_RIGHT : SEQ_SIDE_LEFT;
@@ -299,7 +319,7 @@ static int mouse_frame_side(View2D *v2d, short mouse_x, int frame)
Sequence *find_neighboring_sequence(Scene *scene, Sequence *test, int lr, int sel)
{
- /* sel - 0==unselected, 1==selected, -1==done care*/
+ /* sel: 0==unselected, 1==selected, -1==don't care. */
Sequence *seq;
Editing *ed = BKE_sequencer_editing_get(scene, false);
@@ -334,7 +354,7 @@ Sequence *find_neighboring_sequence(Scene *scene, Sequence *test, int lr, int se
static Sequence *find_next_prev_sequence(Scene *scene, Sequence *test, int lr, int sel)
{
- /* sel - 0==unselected, 1==selected, -1==done care*/
+ /* sel: 0==unselected, 1==selected, -1==don't care. */
Sequence *seq, *best_seq = NULL;
Editing *ed = BKE_sequencer_editing_get(scene, false);
@@ -375,7 +395,7 @@ static Sequence *find_next_prev_sequence(Scene *scene, Sequence *test, int lr, i
}
seq = seq->next;
}
- return best_seq; /* can be null */
+ return best_seq; /* Can be null. */
}
Sequence *find_nearest_seq(Scene *scene, View2D *v2d, int *hand, const int mval[2])
@@ -400,22 +420,21 @@ Sequence *find_nearest_seq(Scene *scene, View2D *v2d, int *hand, const int mval[
while (seq) {
if (seq->machine == (int)y) {
- /* check for both normal strips, and strips that have been flipped horizontally */
+ /* Check for both normal strips, and strips that have been flipped horizontally. */
if (((seq->startdisp < seq->enddisp) && (seq->startdisp <= x && seq->enddisp >= x)) ||
((seq->startdisp > seq->enddisp) && (seq->startdisp >= x && seq->enddisp <= x))) {
if (BKE_sequence_tx_test(seq)) {
- /* clamp handles to defined size in pixel space */
-
+ /* Clamp handles to defined size in pixel space. */
handsize = 2.0f * sequence_handle_size_get_clamped(seq, pixelx);
displen = (float)abs(seq->startdisp - seq->enddisp);
- /* don't even try to grab the handles of small strips */
+ /* Don't even try to grab the handles of small strips. */
if (displen / pixelx > 16) {
+
/* Set the max value to handle to 1/3 of the total len when its
* less than 28. This is important because otherwise selecting
* handles happens even when you click in the middle. */
-
if ((displen / 3) < 30 * pixelx) {
handsize = displen / 3;
}
@@ -510,7 +529,6 @@ void recurs_sel_seq(Sequence *seqm)
bool ED_space_sequencer_maskedit_mask_poll(bContext *C)
{
- /* in this case both funcs are the same, for clip editor not */
return ED_space_sequencer_maskedit_poll(C);
}
@@ -535,7 +553,7 @@ bool ED_space_sequencer_maskedit_poll(bContext *C)
return false;
}
-/* are we displaying the seq output (not channels or histogram)*/
+/* Are we displaying the seq output (not channels or histogram). */
bool ED_space_sequencer_check_show_imbuf(SpaceSeq *sseq)
{
return (ELEM(sseq->view, SEQ_VIEW_PREVIEW, SEQ_VIEW_SEQUENCE_PREVIEW) &&
@@ -589,8 +607,8 @@ int seq_effect_find_selected(Scene *scene,
}
}
- /* make sequence selection a little bit more intuitive
- * for 3 strips: the last-strip should be sequence3 */
+ /* Make sequence selection a little bit more intuitive
+ * for 3 strips: the last-strip should be seq3. */
if (seq3 != NULL && seq2 != NULL) {
Sequence *tmp = seq2;
seq2 = seq3;
@@ -600,7 +618,7 @@ int seq_effect_find_selected(Scene *scene,
switch (BKE_sequence_effect_get_num_inputs(type)) {
case 0:
*r_selseq1 = *r_selseq2 = *r_selseq3 = NULL;
- return 1; /* success */
+ return 1; /* Success. */
case 1:
if (seq2 == NULL) {
*r_error_str = N_("At least one selected sequence strip is needed");
@@ -640,8 +658,8 @@ static Sequence *del_seq_find_replace_recurs(Scene *scene, Sequence *seq)
{
Sequence *seq1, *seq2, *seq3;
- /* try to find a replacement input sequence, and flag for later deletion if
- * no replacement can be found */
+ /* Try to find a replacement input sequence, and flag for later deletion if
+ * no replacement can be found. */
if (!seq) {
return NULL;
@@ -650,13 +668,13 @@ static Sequence *del_seq_find_replace_recurs(Scene *scene, Sequence *seq)
return ((seq->flag & SELECT) ? NULL : seq);
}
else if (!(seq->flag & SELECT)) {
- /* try to find replacement for effect inputs */
+ /* Try to find replacement for effect inputs. */
seq1 = del_seq_find_replace_recurs(scene, seq->seq1);
seq2 = del_seq_find_replace_recurs(scene, seq->seq2);
seq3 = del_seq_find_replace_recurs(scene, seq->seq3);
if (seq1 == seq->seq1 && seq2 == seq->seq2 && seq3 == seq->seq3) {
- /* pass */
+ /* Pass. */
}
else if (seq1 || seq2 || seq3) {
seq->seq1 = (seq1) ? seq1 : (seq2) ? seq2 : seq3;
@@ -666,7 +684,7 @@ static Sequence *del_seq_find_replace_recurs(Scene *scene, Sequence *seq)
BKE_sequencer_update_changed_seq_and_deps(scene, seq, 1, 1);
}
else {
- seq->flag |= SELECT; /* mark for delete */
+ seq->flag |= SELECT; /* Mark for delete. */
}
}
@@ -724,7 +742,7 @@ static void recurs_del_seq_flag(Scene *scene, ListBase *lb, short flag, short de
if (seq->type == SEQ_TYPE_META) {
recurs_del_seq_flag(scene, &seq->seqbase, flag, 1);
}
- BKE_sequence_free(scene, seq);
+ BKE_sequence_free(scene, seq, true);
}
seq = seqn;
}
@@ -740,7 +758,7 @@ static Sequence *split_seq_hard(
/* Unlike soft-split, it's important to use the same value for both strips. */
const bool is_end_exact = ((seq->start + seq->len) == split_frame);
- /* backup values */
+ /* Backup values. */
ts.start = seq->start;
ts.machine = seq->machine;
ts.startstill = seq->startstill;
@@ -753,21 +771,19 @@ static Sequence *split_seq_hard(
ts.anim_endofs = seq->anim_endofs;
ts.len = seq->len;
- /* First Strip! */
- /* strips with extended stillfames before */
-
- /* Precaution, needed because the length saved on-disk may not match the length saved in the
- * blend file, or our code may have minor differences reading file length between versions.
- * This causes hard-split to fail, see: T47862 */
if (seq->type != SEQ_TYPE_META) {
+ /* Precaution, needed because the length saved on-disk may not match the length saved in the
+ * blend file, or our code may have minor differences reading file length between versions.
+ * This causes hard-split to fail, see: T47862. */
BKE_sequence_reload_new_file(bmain, scene, seq, true);
BKE_sequence_calc(scene, seq);
}
+ /* First Strip. */
/* Important to offset the start when 'split_frame == seq->start'
* because we need at least one frame of content after start/end still have clipped it. */
if ((seq->startstill) && (split_frame <= seq->start)) {
- /* don't do funny things with METAs ... */
+ /* Don't do funny things with METAs. */
if (seq->type == SEQ_TYPE_META) {
skip_dup = true;
seq->startstill = seq->start - split_frame;
@@ -779,18 +795,18 @@ static Sequence *split_seq_hard(
seq->endstill = 0;
}
}
- /* normal strip */
+ /* Normal strip. */
else if ((is_end_exact == false) &&
((split_frame >= seq->start) && (split_frame <= (seq->start + seq->len)))) {
seq->endofs = 0;
seq->endstill = 0;
seq->anim_endofs += (seq->start + seq->len) - split_frame;
}
- /* strips with extended stillframes after */
+ /* Strips with extended stillframes. */
else if ((is_end_exact == true) ||
(((seq->start + seq->len) < split_frame) && (seq->endstill))) {
seq->endstill -= seq->enddisp - split_frame;
- /* don't do funny things with METAs ... */
+ /* Don't do funny things with METAs. */
if (seq->type == SEQ_TYPE_META) {
skip_dup = true;
}
@@ -800,7 +816,7 @@ static Sequence *split_seq_hard(
BKE_sequence_calc(scene, seq);
if (!skip_dup) {
- /* Duplicate AFTER the first change */
+ /* Duplicate AFTER the first change. */
seqn = BKE_sequence_dupli_recursive(
scene, scene, new_seq_list, seq, SEQ_DUPE_UNIQUE_NAME | SEQ_DUPE_ANIM);
}
@@ -808,12 +824,11 @@ static Sequence *split_seq_hard(
if (seqn) {
seqn->flag |= SELECT;
- /* Important not to re-assign this (unlike soft-split) */
#if 0
is_end_exact = ((seqn->start + seqn->len) == split_frame);
#endif
- /* Second Strip! */
- /* strips with extended stillframes before */
+ /* Second Strip. */
+ /* strips with extended stillframes. */
if ((seqn->startstill) && (split_frame == seqn->start + 1)) {
seqn->start = ts.start;
seqn->startstill = ts.start - split_frame;
@@ -821,7 +836,7 @@ static Sequence *split_seq_hard(
seqn->endstill = ts.endstill;
}
- /* normal strip */
+ /* Normal strip. */
else if ((is_end_exact == false) &&
((split_frame >= seqn->start) && (split_frame <= (seqn->start + seqn->len)))) {
seqn->start = split_frame;
@@ -833,7 +848,7 @@ static Sequence *split_seq_hard(
seqn->endstill = ts.endstill;
}
- /* strips with extended stillframes after */
+ /* Strips with extended stillframes after. */
else if ((is_end_exact == true) ||
(((seqn->start + seqn->len) < split_frame) && (seqn->endstill))) {
seqn->start = split_frame;
@@ -845,6 +860,7 @@ static Sequence *split_seq_hard(
BKE_sequence_reload_new_file(bmain, scene, seqn, false);
BKE_sequence_calc(scene, seqn);
+ BKE_sequence_invalidate_cache_in_range(scene, seq, seqn, SEQ_CACHE_ALL_TYPES);
}
return seqn;
}
@@ -858,7 +874,7 @@ static Sequence *split_seq_soft(
bool is_end_exact = ((seq->start + seq->len) == split_frame);
- /* backup values */
+ /* Backup values. */
ts.start = seq->start;
ts.machine = seq->machine;
ts.startstill = seq->startstill;
@@ -871,9 +887,8 @@ static Sequence *split_seq_soft(
ts.anim_endofs = seq->anim_endofs;
ts.len = seq->len;
- /* First Strip! */
- /* strips with extended stillfames before */
-
+ /* First Strip. */
+ /* Strips with extended stillfames. */
/* Important to offset the start when 'split_frame == seq->start'
* because we need at least one frame of content after start/end still have clipped it. */
if ((seq->startstill) && (split_frame <= seq->start)) {
@@ -889,16 +904,16 @@ static Sequence *split_seq_soft(
seq->endstill = 0;
}
}
- /* normal strip */
+ /* Normal strip. */
else if ((is_end_exact == false) && (split_frame >= seq->start) &&
(split_frame <= (seq->start + seq->len))) {
seq->endofs = (seq->start + seq->len) - split_frame;
}
- /* strips with extended stillframes after */
+ /* Strips with extended stillframes. */
else if ((is_end_exact == true) ||
(((seq->start + seq->len) < split_frame) && (seq->endstill))) {
seq->endstill -= seq->enddisp - split_frame;
- /* don't do funny things with METAs ... */
+ /* Don't do funny things with METAs. */
if (seq->type == SEQ_TYPE_META) {
skip_dup = true;
}
@@ -907,7 +922,7 @@ static Sequence *split_seq_soft(
BKE_sequence_calc(scene, seq);
if (!skip_dup) {
- /* Duplicate AFTER the first change */
+ /* Duplicate AFTER the first change. */
seqn = BKE_sequence_dupli_recursive(
scene, scene, new_seq_list, seq, SEQ_DUPE_UNIQUE_NAME | SEQ_DUPE_ANIM);
}
@@ -917,8 +932,8 @@ static Sequence *split_seq_soft(
is_end_exact = ((seqn->start + seqn->len) == split_frame);
- /* Second Strip! */
- /* strips with extended stillframes before */
+ /* Second Strip. */
+ /* Strips with extended stillframes. */
if ((seqn->startstill) && (split_frame == seqn->start + 1)) {
seqn->start = ts.start;
seqn->startstill = ts.start - split_frame;
@@ -926,7 +941,7 @@ static Sequence *split_seq_soft(
seqn->endstill = ts.endstill;
}
- /* normal strip */
+ /* Normal strip. */
else if ((is_end_exact == false) && (split_frame >= seqn->start) &&
(split_frame <= (seqn->start + seqn->len))) {
seqn->startstill = 0;
@@ -935,7 +950,7 @@ static Sequence *split_seq_soft(
seqn->endstill = ts.endstill;
}
- /* strips with extended stillframes after */
+ /* Strips with extended stillframes. */
else if ((is_end_exact == true) ||
(((seqn->start + seqn->len) < split_frame) && (seqn->endstill))) {
seqn->start = split_frame - ts.len + 1;
@@ -945,16 +960,17 @@ static Sequence *split_seq_soft(
}
BKE_sequence_calc(scene, seqn);
+ BKE_sequence_invalidate_cache_in_range(scene, seq, seqn, SEQ_CACHE_ALL_TYPES);
}
return seqn;
}
-/* like duplicate, but only duplicate and split overlapping strips,
+/* Like duplicate, but only duplicate and split overlapping strips,
* strips to the left of the split_frame are ignored and strips to the right
- * are moved to the end of slist
- * we have to work on the same slist (not using a separate list), since
+ * are moved to the end of slist.
+ * We have to work on the same slist (not using a separate list), since
* otherwise dupli_seq can't check for duplicate names properly and
- * may generate strips with the same name (which will mess up animdata)
+ * may generate strips with the same name which will mess up animdata.
*/
static bool split_seq_list(
@@ -973,7 +989,7 @@ static bool split_seq_list(
seq = slist->first;
while (seq && seq != seq_first_new) {
- seq_next_iter = seq->next; /* we need this because we may remove seq */
+ seq_next_iter = seq->next; /* We need this because we may remove seq. */
seq->tmp = NULL;
if (use_cursor_position) {
if (seq->machine == channel && seq->startdisp < split_frame && seq->enddisp > split_frame) {
@@ -996,10 +1012,10 @@ static bool split_seq_list(
}
}
else if (seq->enddisp <= split_frame) {
- /* do nothing */
+ /* Pass. */
}
else if (seq->startdisp >= split_frame) {
- /* move to tail */
+ /* Move to tail. */
BLI_remlink(slist, seq);
BLI_addtail(slist, seq);
@@ -1022,7 +1038,7 @@ static bool sequence_offset_after_frame(Scene *scene, const int delta, const int
bool done = false;
TimeMarker *marker;
- /* all strips >= cfra are shifted */
+ /* All strips >= cfra are shifted. */
if (ed == NULL) {
return 0;
@@ -1085,12 +1101,12 @@ static void UNUSED_FUNCTION(seq_remap_paths)(Scene *scene)
}
BLI_strncpy(from, last_seq->strip->dir, sizeof(from));
- // XXX if (0 == sbutton(from, 0, sizeof(from) - 1, "From: "))
- // return;
+ /* XXX if (0 == sbutton(from, 0, sizeof(from) - 1, "From: "))
+ * return; */
BLI_strncpy(to, from, sizeof(to));
- // XXX if (0 == sbutton(to, 0, sizeof(to) - 1, "To: "))
- // return;
+ /* XXX if (0 == sbutton(to, 0, sizeof(to) - 1, "To: "))
+ * return; */
if (STREQ(to, from)) {
return;
@@ -1101,11 +1117,11 @@ static void UNUSED_FUNCTION(seq_remap_paths)(Scene *scene)
if (STREQLEN(seq->strip->dir, from, strlen(from))) {
printf("found %s\n", seq->strip->dir);
- /* strip off the beginning */
+ /* Strip off the beginning. */
stripped[0] = 0;
BLI_strncpy(stripped, seq->strip->dir + strlen(from), FILE_MAX);
- /* new path */
+ /* New path. */
BLI_snprintf(seq->strip->dir, sizeof(seq->strip->dir), "%s%s", to, stripped);
printf("new %s\n", seq->strip->dir);
}
@@ -1122,12 +1138,12 @@ static int sequencer_gap_remove_exec(bContext *C, wmOperator *op)
bool first = false, done;
bool do_all = RNA_boolean_get(op->ptr, "all");
- /* get first and last frame */
+ /* Get first and last frame. */
boundbox_seq(scene, &rectf);
sfra = (int)rectf.xmin;
efra = (int)rectf.xmax;
- /* first check if the current frame has a gap already */
+ /* Check if the current frame has a gap already. */
for (cfra = CFRA; cfra >= sfra; cfra--) {
if (BKE_sequencer_evaluate_frame(scene, cfra)) {
first = true;
@@ -1136,7 +1152,7 @@ static int sequencer_gap_remove_exec(bContext *C, wmOperator *op)
}
for (; cfra < efra; cfra++) {
- /* first == 0 means there's still no strip to remove a gap for */
+ /* There's still no strip to remove a gap for. */
if (first == false) {
if (BKE_sequencer_evaluate_frame(scene, cfra)) {
first = true;
@@ -1164,19 +1180,19 @@ static int sequencer_gap_remove_exec(bContext *C, wmOperator *op)
void SEQUENCER_OT_gap_remove(struct wmOperatorType *ot)
{
- /* identifiers */
+ /* Identifiers. */
ot->name = "Remove Gaps";
ot->idname = "SEQUENCER_OT_gap_remove";
ot->description =
"Remove gap at current frame to first strip at the right, independent of selection or "
"locked state of strips";
- /* api callbacks */
+ /* Api callbacks. */
// ot->invoke = sequencer_snap_invoke;
ot->exec = sequencer_gap_remove_exec;
ot->poll = sequencer_edit_poll;
- /* flags */
+ /* Flags. */
ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
RNA_def_boolean(ot->srna, "all", 0, "All Gaps", "Do all gaps to right of current frame");
@@ -1196,19 +1212,19 @@ static int sequencer_gap_insert_exec(bContext *C, wmOperator *op)
void SEQUENCER_OT_gap_insert(struct wmOperatorType *ot)
{
- /* identifiers */
+ /* Identifiers. */
ot->name = "Insert Gaps";
ot->idname = "SEQUENCER_OT_gap_insert";
ot->description =
"Insert gap at current frame to first strips at the right, independent of selection or "
"locked state of strips";
- /* api callbacks */
+ /* Api callbacks. */
// ot->invoke = sequencer_snap_invoke;
ot->exec = sequencer_gap_insert_exec;
ot->poll = sequencer_edit_poll;
- /* flags */
+ /* Flags. */
ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
RNA_def_int(ot->srna,
@@ -1238,7 +1254,7 @@ static int seq_get_snaplimit(View2D *v2d)
}
#endif
-/* Operator functions */
+/* Operator functions. */
bool sequencer_edit_poll(bContext *C)
{
return (BKE_sequencer_editing_get(CTX_data_scene(C), false) != NULL);
@@ -1282,7 +1298,7 @@ bool sequencer_view_strips_poll(bContext *C)
return 0;
}
-/* snap operator*/
+/* Snap operator. */
static int sequencer_snap_exec(bContext *C, wmOperator *op)
{
Scene *scene = CTX_data_scene(C);
@@ -1293,14 +1309,11 @@ static int sequencer_snap_exec(bContext *C, wmOperator *op)
snap_frame = RNA_int_get(op->ptr, "frame");
- /* also check metas */
+ /* Check metas. */
for (seq = ed->seqbasep->first; seq; seq = seq->next) {
if (seq->flag & SELECT && !(seq->depth == 0 && seq->flag & SEQ_LOCK) &&
BKE_sequence_tx_test(seq)) {
if ((seq->flag & (SEQ_LEFTSEL + SEQ_RIGHTSEL)) == 0) {
- /* simple but no anim update */
- /* seq->start = snap_frame-seq->startofs+seq->startstill; */
-
BKE_sequence_translate(
scene, seq, (snap_frame - seq->startofs + seq->startstill) - seq->start);
}
@@ -1318,8 +1331,8 @@ static int sequencer_snap_exec(bContext *C, wmOperator *op)
}
}
- /* test for effects and overlap
- * don't use SEQP_BEGIN since that would be recursive */
+ /* Test for effects and overlap.
+ * Don't use SEQP_BEGIN since that would be recursive. */
for (seq = ed->seqbasep->first; seq; seq = seq->next) {
if (seq->flag & SELECT && !(seq->depth == 0 && seq->flag & SEQ_LOCK)) {
seq->flag &= ~SEQ_OVERLAP;
@@ -1340,7 +1353,6 @@ static int sequencer_snap_exec(bContext *C, wmOperator *op)
}
}
- /* as last: */
BKE_sequencer_sort(scene);
DEG_id_tag_update(&scene->id, ID_RECALC_SEQUENCER_STRIPS);
@@ -1363,17 +1375,17 @@ static int sequencer_snap_invoke(bContext *C, wmOperator *op, const wmEvent *UNU
void SEQUENCER_OT_snap(struct wmOperatorType *ot)
{
- /* identifiers */
- ot->name = "Snap Strips to Playhead";
+ /* Identifiers. */
+ ot->name = "Snap Strips to the Current Frame";
ot->idname = "SEQUENCER_OT_snap";
ot->description = "Frame where selected strips will be snapped";
- /* api callbacks */
+ /* Api callbacks. */
ot->invoke = sequencer_snap_invoke;
ot->exec = sequencer_snap_exec;
ot->poll = sequencer_edit_poll;
- /* flags */
+ /* Flags. */
ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
RNA_def_int(ot->srna,
@@ -1395,7 +1407,7 @@ typedef struct SlipData {
bool *trim;
int num_seq;
bool slow;
- int slow_offset; /* offset at the point where offset was turned on */
+ int slow_offset; /* Offset at the point where offset was turned on. */
NumInput num_input;
} SlipData;
@@ -1429,7 +1441,7 @@ static void transseq_restore(TransSeq *ts, Sequence *seq)
seq->len = ts->len;
}
-static int slip_add_sequences_rec(
+static int slip_add_sequences_recursive(
ListBase *seqbasep, Sequence **seq_array, bool *trim, int offset, bool do_trim)
{
Sequence *seq;
@@ -1442,8 +1454,8 @@ static int slip_add_sequences_rec(
num_items++;
if (seq->type == SEQ_TYPE_META) {
- /* trim the sub-sequences */
- num_items += slip_add_sequences_rec(
+ /* Trim the sub-sequences. */
+ num_items += slip_add_sequences_recursive(
&seq->seqbase, seq_array, trim, num_items + offset, false);
}
else if (seq->type & SEQ_TYPE_EFFECT) {
@@ -1455,7 +1467,7 @@ static int slip_add_sequences_rec(
return num_items;
}
-static int slip_count_sequences_rec(ListBase *seqbasep, bool first_level)
+static int slip_count_sequences_recursive(ListBase *seqbasep, bool first_level)
{
Sequence *seq;
int trimmed_sequences = 0;
@@ -1465,8 +1477,8 @@ static int slip_count_sequences_rec(ListBase *seqbasep, bool first_level)
trimmed_sequences++;
if (seq->type == SEQ_TYPE_META) {
- /* trim the sub-sequences */
- trimmed_sequences += slip_count_sequences_rec(&seq->seqbase, false);
+ /* Trim the sub-sequences. */
+ trimmed_sequences += slip_count_sequences_recursive(&seq->seqbase, false);
}
}
}
@@ -1483,8 +1495,8 @@ static int sequencer_slip_invoke(bContext *C, wmOperator *op, const wmEvent *eve
int num_seq, i;
View2D *v2d = UI_view2d_fromcontext(C);
- /* first recursively count the trimmed elements */
- num_seq = slip_count_sequences_rec(ed->seqbasep, true);
+ /* Recursively count the trimmed elements. */
+ num_seq = slip_count_sequences_recursive(ed->seqbasep, true);
if (num_seq == 0) {
return OPERATOR_CANCELLED;
@@ -1502,7 +1514,7 @@ static int sequencer_slip_invoke(bContext *C, wmOperator *op, const wmEvent *eve
data->num_input.unit_sys = USER_UNIT_NONE;
data->num_input.unit_type[0] = 0;
- slip_add_sequences_rec(ed->seqbasep, data->seq_array, data->trim, 0, true);
+ slip_add_sequences_recursive(ed->seqbasep, data->seq_array, data->trim, 0, true);
for (i = 0; i < num_seq; i++) {
transseq_backup(data->ts + i, data->seq_array[i]);
@@ -1517,7 +1529,7 @@ static int sequencer_slip_invoke(bContext *C, wmOperator *op, const wmEvent *eve
WM_event_add_modal_handler(C, op);
- /* notify so we draw extensions immediately */
+ /* Notify so we draw extensions immediately. */
WM_event_add_notifier(C, NC_SCENE | ND_SEQUENCER, scene);
return OPERATOR_RUNNING_MODAL;
@@ -1529,20 +1541,19 @@ static bool sequencer_slip_recursively(Scene *scene, SlipData *data, int offset)
Editing *ed = BKE_sequencer_editing_get(scene, false);
bool changed = false;
- /* We iterate in reverse so meta-strips are iterated after their children. */
+ /* Iterate in reverse so meta-strips are iterated after their children. */
for (int i = data->num_seq - 1; i >= 0; i--) {
Sequence *seq = data->seq_array[i];
int endframe;
- /* We have the offset, apply the values to the sequence strips. */
- /* first, do the offset */
+ /* Offset seq start. */
seq->start = data->ts[i].start + offset;
if (data->trim[i]) {
/* Find the end-frame. */
endframe = seq->start + seq->len;
- /* Now compute the sequence offsets. */
+ /* Compute the sequence offsets. */
if (endframe > seq->enddisp) {
seq->endstill = 0;
seq->endofs = endframe - seq->enddisp;
@@ -1566,7 +1577,7 @@ static bool sequencer_slip_recursively(Scene *scene, SlipData *data, int offset)
}
}
else {
- /* If no real trim, don't change the data, rather transform the strips themselves. */
+ /* No transform data (likely effect strip). Only move start and end. */
seq->startdisp = data->ts[i].startdisp + offset;
seq->enddisp = data->ts[i].enddisp + offset;
changed = true;
@@ -1575,7 +1586,7 @@ static bool sequencer_slip_recursively(Scene *scene, SlipData *data, int offset)
/* Effects are only added if we they are in a meta-strip.
* In this case, dependent strips will just be transformed and
* we can skip calculating for effects.
- * This way we can avoid an extra loop just for effects*/
+ * This way we can avoid an extra loop just for effects. */
if (!(seq->type & SEQ_TYPE_EFFECT)) {
BKE_sequence_calc(scene, seq);
}
@@ -1586,6 +1597,28 @@ static bool sequencer_slip_recursively(Scene *scene, SlipData *data, int offset)
return changed;
}
+/* Make sure, that each strip contains at least 1 frame of content. */
+static void sequencer_slip_apply_limits(SlipData *data, int *offset)
+{
+ for (int i = 0; i < data->num_seq; i++) {
+ if (data->trim[i]) {
+ Sequence *seq = data->seq_array[i];
+ int seq_content_start = data->ts[i].start + *offset;
+ int seq_content_end = seq_content_start + seq->len + seq->anim_startofs + seq->anim_endofs;
+ int diff = 0;
+
+ if (seq_content_start >= seq->enddisp) {
+ diff = seq->enddisp - seq_content_start - 1;
+ }
+
+ if (seq_content_end <= seq->startdisp) {
+ diff = seq->startdisp - seq_content_end + 1;
+ }
+ *offset += diff;
+ }
+ }
+}
+
static int sequencer_slip_exec(bContext *C, wmOperator *op)
{
SlipData *data;
@@ -1595,8 +1628,8 @@ static int sequencer_slip_exec(bContext *C, wmOperator *op)
int offset = RNA_int_get(op->ptr, "offset");
bool success = false;
- /* first recursively count the trimmed elements */
- num_seq = slip_count_sequences_rec(ed->seqbasep, true);
+ /* Recursively count the trimmed elements. */
+ num_seq = slip_count_sequences_recursive(ed->seqbasep, true);
if (num_seq == 0) {
return OPERATOR_CANCELLED;
@@ -1608,12 +1641,13 @@ static int sequencer_slip_exec(bContext *C, wmOperator *op)
data->trim = MEM_mallocN(num_seq * sizeof(bool), "trimdata_trim");
data->num_seq = num_seq;
- slip_add_sequences_rec(ed->seqbasep, data->seq_array, data->trim, 0, true);
+ slip_add_sequences_recursive(ed->seqbasep, data->seq_array, data->trim, 0, true);
for (i = 0; i < num_seq; i++) {
transseq_backup(data->ts + i, data->seq_array[i]);
}
+ sequencer_slip_apply_limits(data, &offset);
success = sequencer_slip_recursively(scene, data, offset);
MEM_freeN(data->seq_array);
@@ -1631,22 +1665,22 @@ static int sequencer_slip_exec(bContext *C, wmOperator *op)
}
}
-static void sequencer_slip_update_header(Scene *scene, ScrArea *sa, SlipData *data, int offset)
+static void sequencer_slip_update_header(Scene *scene, ScrArea *area, SlipData *data, int offset)
{
char msg[UI_MAX_DRAW_STR];
- if (sa) {
+ if (area) {
if (hasNumInput(&data->num_input)) {
char num_str[NUM_STR_REP_LEN];
outputNumInput(&data->num_input, num_str, &scene->unit);
- BLI_snprintf(msg, sizeof(msg), TIP_("Trim offset: %s"), num_str);
+ BLI_snprintf(msg, sizeof(msg), TIP_("Slip offset: %s"), num_str);
}
else {
- BLI_snprintf(msg, sizeof(msg), TIP_("Trim offset: %d"), offset);
+ BLI_snprintf(msg, sizeof(msg), TIP_("Slip offset: %d"), offset);
}
}
- ED_area_status_text(sa, msg);
+ ED_area_status_text(area, msg);
}
static int sequencer_slip_modal(bContext *C, wmOperator *op, const wmEvent *event)
@@ -1654,16 +1688,18 @@ static int sequencer_slip_modal(bContext *C, wmOperator *op, const wmEvent *even
Main *bmain = CTX_data_main(C);
Scene *scene = CTX_data_scene(C);
SlipData *data = (SlipData *)op->customdata;
- ScrArea *sa = CTX_wm_area(C);
+ ScrArea *area = CTX_wm_area(C);
const bool has_numInput = hasNumInput(&data->num_input);
bool handled = true;
- /* Modal numinput active, try to handle numeric inputs first... */
+ /* Modal numinput active, try to handle numeric inputs. */
if (event->val == KM_PRESS && has_numInput && handleNumInput(C, &data->num_input, event)) {
- float offset;
- applyNumInput(&data->num_input, &offset);
+ float offset_fl;
+ applyNumInput(&data->num_input, &offset_fl);
+ int offset = round_fl_to_int(offset_fl);
- sequencer_slip_update_header(scene, sa, data, (int)offset);
+ sequencer_slip_apply_limits(data, &offset);
+ sequencer_slip_update_header(scene, area, data, offset);
RNA_int_set(op->ptr, "offset", offset);
@@ -1691,11 +1727,12 @@ static int sequencer_slip_modal(bContext *C, wmOperator *op, const wmEvent *even
mouse_x = event->mval[0];
}
- /* choose the side based on which side of the playhead the mouse is on */
+ /* Choose the side based on which side of the current frame the mouse is. */
UI_view2d_region_to_view(v2d, mouse_x, 0, &mouseloc[0], &mouseloc[1]);
offset = mouseloc[0] - data->init_mouseloc[0];
- sequencer_slip_update_header(scene, sa, data, offset);
+ sequencer_slip_apply_limits(data, &offset);
+ sequencer_slip_update_header(scene, area, data, offset);
RNA_int_set(op->ptr, "offset", offset);
@@ -1714,8 +1751,8 @@ static int sequencer_slip_modal(bContext *C, wmOperator *op, const wmEvent *even
MEM_freeN(data->ts);
MEM_freeN(data);
op->customdata = NULL;
- if (sa) {
- ED_area_status_text(sa, NULL);
+ if (area) {
+ ED_area_status_text(area, NULL);
}
DEG_id_tag_update(&scene->id, ID_RECALC_SEQUENCER_STRIPS);
WM_event_add_notifier(C, NC_SCENE | ND_SEQUENCER, scene);
@@ -1747,8 +1784,8 @@ static int sequencer_slip_modal(bContext *C, wmOperator *op, const wmEvent *even
BKE_sequencer_free_imbuf(scene, &ed->seqbase, false);
- if (sa) {
- ED_area_status_text(sa, NULL);
+ if (area) {
+ ED_area_status_text(area, NULL);
}
return OPERATOR_CANCELLED;
@@ -1772,12 +1809,14 @@ static int sequencer_slip_modal(bContext *C, wmOperator *op, const wmEvent *even
break;
}
- /* Modal numinput inactive, try to handle numeric inputs last... */
+ /* Modal numinput inactive, try to handle numeric inputs. */
if (!handled && event->val == KM_PRESS && handleNumInput(C, &data->num_input, event)) {
- float offset;
- applyNumInput(&data->num_input, &offset);
+ float offset_fl;
+ applyNumInput(&data->num_input, &offset_fl);
+ int offset = round_fl_to_int(offset_fl);
- sequencer_slip_update_header(scene, sa, data, (int)offset);
+ sequencer_slip_apply_limits(data, &offset);
+ sequencer_slip_update_header(scene, area, data, offset);
RNA_int_set(op->ptr, "offset", offset);
@@ -1791,18 +1830,18 @@ static int sequencer_slip_modal(bContext *C, wmOperator *op, const wmEvent *even
void SEQUENCER_OT_slip(struct wmOperatorType *ot)
{
- /* identifiers */
+ /* Identifiers. */
ot->name = "Trim Strips";
ot->idname = "SEQUENCER_OT_slip";
ot->description = "Trim the contents of the active strip";
- /* api callbacks */
+ /* Api callbacks. */
ot->invoke = sequencer_slip_invoke;
ot->modal = sequencer_slip_modal;
ot->exec = sequencer_slip_exec;
ot->poll = sequencer_edit_poll;
- /* flags */
+ /* Flags. */
ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
RNA_def_int(ot->srna,
@@ -1816,7 +1855,7 @@ void SEQUENCER_OT_slip(struct wmOperatorType *ot)
INT32_MAX);
}
-/* mute operator */
+/* Mute operator. */
static int sequencer_mute_exec(bContext *C, wmOperator *op)
{
Scene *scene = CTX_data_scene(C);
@@ -1828,7 +1867,7 @@ static int sequencer_mute_exec(bContext *C, wmOperator *op)
for (seq = ed->seqbasep->first; seq; seq = seq->next) {
if ((seq->flag & SEQ_LOCK) == 0) {
- if (selected) { /* mute unselected */
+ if (selected) {
if (seq->flag & SELECT) {
seq->flag |= SEQ_MUTE;
BKE_sequence_invalidate_dependent(scene, seq);
@@ -1851,23 +1890,23 @@ static int sequencer_mute_exec(bContext *C, wmOperator *op)
void SEQUENCER_OT_mute(struct wmOperatorType *ot)
{
- /* identifiers */
+ /* Identifiers. */
ot->name = "Mute Strips";
ot->idname = "SEQUENCER_OT_mute";
ot->description = "Mute (un)selected strips";
- /* api callbacks */
+ /* Api callbacks. */
ot->exec = sequencer_mute_exec;
ot->poll = sequencer_edit_poll;
- /* flags */
+ /* Flags. */
ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
RNA_def_boolean(
ot->srna, "unselected", 0, "Unselected", "Mute unselected rather than selected strips");
}
-/* unmute operator */
+/* Unmute operator. */
static int sequencer_unmute_exec(bContext *C, wmOperator *op)
{
Scene *scene = CTX_data_scene(C);
@@ -1879,7 +1918,7 @@ static int sequencer_unmute_exec(bContext *C, wmOperator *op)
for (seq = ed->seqbasep->first; seq; seq = seq->next) {
if ((seq->flag & SEQ_LOCK) == 0) {
- if (selected) { /* unmute unselected */
+ if (selected) {
if (seq->flag & SELECT) {
seq->flag &= ~SEQ_MUTE;
BKE_sequence_invalidate_dependent(scene, seq);
@@ -1902,23 +1941,23 @@ static int sequencer_unmute_exec(bContext *C, wmOperator *op)
void SEQUENCER_OT_unmute(struct wmOperatorType *ot)
{
- /* identifiers */
+ /* Identifiers. */
ot->name = "Unmute Strips";
ot->idname = "SEQUENCER_OT_unmute";
ot->description = "Unmute (un)selected strips";
- /* api callbacks */
+ /* Api callbacks. */
ot->exec = sequencer_unmute_exec;
ot->poll = sequencer_edit_poll;
- /* flags */
+ /* Flags. */
ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
RNA_def_boolean(
ot->srna, "unselected", 0, "Unselected", "Unmute unselected rather than selected strips");
}
-/* lock operator */
+/* Lock operator. */
static int sequencer_lock_exec(bContext *C, wmOperator *UNUSED(op))
{
Scene *scene = CTX_data_scene(C);
@@ -1938,20 +1977,20 @@ static int sequencer_lock_exec(bContext *C, wmOperator *UNUSED(op))
void SEQUENCER_OT_lock(struct wmOperatorType *ot)
{
- /* identifiers */
+ /* Identifiers. */
ot->name = "Lock Strips";
ot->idname = "SEQUENCER_OT_lock";
ot->description = "Lock strips so they can't be transformed";
- /* api callbacks */
+ /* Api callbacks. */
ot->exec = sequencer_lock_exec;
ot->poll = sequencer_edit_poll;
- /* flags */
+ /* Flags. */
ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
}
-/* unlock operator */
+/* Unlock operator. */
static int sequencer_unlock_exec(bContext *C, wmOperator *UNUSED(op))
{
Scene *scene = CTX_data_scene(C);
@@ -1971,20 +2010,20 @@ static int sequencer_unlock_exec(bContext *C, wmOperator *UNUSED(op))
void SEQUENCER_OT_unlock(struct wmOperatorType *ot)
{
- /* identifiers */
+ /* Identifiers. */
ot->name = "Unlock Strips";
ot->idname = "SEQUENCER_OT_unlock";
ot->description = "Unlock strips so they can be transformed";
- /* api callbacks */
+ /* Api callbacks. */
ot->exec = sequencer_unlock_exec;
ot->poll = sequencer_edit_poll;
- /* flags */
+ /* Flags. */
ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
}
-/* reload operator */
+/* Reload operator. */
static int sequencer_reload_exec(bContext *C, wmOperator *op)
{
Main *bmain = CTX_data_main(C);
@@ -2015,17 +2054,17 @@ void SEQUENCER_OT_reload(struct wmOperatorType *ot)
{
PropertyRNA *prop;
- /* identifiers */
+ /* Identifiers. */
ot->name = "Reload Strips";
ot->idname = "SEQUENCER_OT_reload";
ot->description = "Reload strips in the sequencer";
- /* api callbacks */
+ /* Api callbacks. */
ot->exec = sequencer_reload_exec;
ot->poll = sequencer_edit_poll;
- /* flags */
- ot->flag = OPTYPE_REGISTER; /* no undo, the data changed is stored outside 'main' */
+ /* Flags. */
+ ot->flag = OPTYPE_REGISTER; /* No undo, the data changed is stored outside 'main'. */
prop = RNA_def_boolean(ot->srna,
"adjust_length",
@@ -2035,7 +2074,7 @@ void SEQUENCER_OT_reload(struct wmOperatorType *ot)
RNA_def_property_flag(prop, PROP_SKIP_SAVE);
}
-/* reload operator */
+/* Reload operator. */
static bool sequencer_refresh_all_poll(bContext *C)
{
if (G.is_rendering) {
@@ -2058,12 +2097,12 @@ static int sequencer_refresh_all_exec(bContext *C, wmOperator *UNUSED(op))
void SEQUENCER_OT_refresh_all(struct wmOperatorType *ot)
{
- /* identifiers */
+ /* Identifiers. */
ot->name = "Refresh Sequencer";
ot->idname = "SEQUENCER_OT_refresh_all";
ot->description = "Refresh the sequencer editor";
- /* api callbacks */
+ /* Api callbacks. */
ot->exec = sequencer_refresh_all_exec;
ot->poll = sequencer_refresh_all_poll;
}
@@ -2079,7 +2118,7 @@ static int sequencer_reassign_inputs_exec(bContext *C, wmOperator *op)
BKE_report(op->reports, RPT_ERROR, error_msg);
return OPERATOR_CANCELLED;
}
- /* see reassigning would create a cycle */
+ /* Check if reassigning would create recursivity. */
if (seq_is_predecessor(seq1, last_seq) || seq_is_predecessor(seq2, last_seq) ||
seq_is_predecessor(seq3, last_seq)) {
BKE_report(op->reports, RPT_ERROR, "Cannot reassign inputs: no cycles allowed");
@@ -2114,16 +2153,16 @@ static bool sequencer_effect_poll(bContext *C)
void SEQUENCER_OT_reassign_inputs(struct wmOperatorType *ot)
{
- /* identifiers */
+ /* Identifiers. */
ot->name = "Reassign Inputs";
ot->idname = "SEQUENCER_OT_reassign_inputs";
ot->description = "Reassign the inputs for the effect strip";
- /* api callbacks */
+ /* Api callbacks. */
ot->exec = sequencer_reassign_inputs_exec;
ot->poll = sequencer_effect_poll;
- /* flags */
+ /* Flags. */
ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
}
@@ -2149,20 +2188,20 @@ static int sequencer_swap_inputs_exec(bContext *C, wmOperator *op)
}
void SEQUENCER_OT_swap_inputs(struct wmOperatorType *ot)
{
- /* identifiers */
+ /* Identifiers. */
ot->name = "Swap Inputs";
ot->idname = "SEQUENCER_OT_swap_inputs";
ot->description = "Swap the first two inputs for the effect strip";
- /* api callbacks */
+ /* Api callbacks. */
ot->exec = sequencer_swap_inputs_exec;
ot->poll = sequencer_effect_poll;
- /* flags */
+ /* Flags. */
ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
}
-/* split operator */
+/* Split operator. */
static const EnumPropertyItem prop_split_types[] = {
{SEQ_SPLIT_SOFT, "SOFT", 0, "Soft", ""},
{SEQ_SPLIT_HARD, "HARD", 0, "Hard", ""},
@@ -2203,7 +2242,7 @@ static int sequencer_split_exec(bContext *C, wmOperator *op)
use_cursor_position,
split_seq_soft);
}
- if (changed) { /* got new strips ? */
+ if (changed) { /* Got new strips? */
Sequence *seq;
if (ignore_selection) {
if (use_cursor_position) {
@@ -2246,7 +2285,7 @@ static int sequencer_split_exec(bContext *C, wmOperator *op)
}
}
SEQ_END;
- /* as last: */
+
BKE_sequencer_sort(scene);
}
if (changed) {
@@ -2285,24 +2324,24 @@ static int sequencer_split_invoke(bContext *C, wmOperator *op, const wmEvent *ev
}
RNA_int_set(op->ptr, "channel", mouseloc[1]);
RNA_enum_set(op->ptr, "side", split_side);
- /*RNA_enum_set(op->ptr, "type", split_hard); */ /*This type is set from the key
- shortsplit */
+ /*RNA_enum_set(op->ptr, "type", split_hard); */
+
return sequencer_split_exec(C, op);
}
void SEQUENCER_OT_split(struct wmOperatorType *ot)
{
- /* identifiers */
+ /* Identifiers. */
ot->name = "Split Strips";
ot->idname = "SEQUENCER_OT_split";
ot->description = "Split the selected strips in two";
- /* api callbacks */
+ /* Api callbacks. */
ot->invoke = sequencer_split_invoke;
ot->exec = sequencer_split_exec;
ot->poll = sequencer_edit_poll;
- /* flags */
+ /* Flags. */
ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
PropertyRNA *prop;
@@ -2335,7 +2374,7 @@ void SEQUENCER_OT_split(struct wmOperatorType *ot)
"use_cursor_position",
0,
"Use Cursor Position",
- "Split at position of the cursor instead of playhead");
+ "Split at position of the cursor instead of current frame");
prop = RNA_def_enum(ot->srna,
"side",
@@ -2358,8 +2397,8 @@ void SEQUENCER_OT_split(struct wmOperatorType *ot)
#undef SEQ_SIDE_MOUSE
-/* duplicate operator */
-static int apply_unique_name_cb(Sequence *seq, void *arg_pt)
+/* Duplicate operator. */
+static int apply_unique_name_fn(Sequence *seq, void *arg_pt)
{
Scene *scene = (Scene *)arg_pt;
char name[sizeof(seq->name) - 2];
@@ -2385,11 +2424,11 @@ static int sequencer_add_duplicate_exec(bContext *C, wmOperator *UNUSED(op))
if (nseqbase.first) {
Sequence *seq = nseqbase.first;
- /* rely on the nseqbase list being added at the end */
+ /* Rely on the nseqbase list being added at the end. */
BLI_movelisttolist(ed->seqbasep, &nseqbase);
for (; seq; seq = seq->next) {
- BKE_sequencer_recursive_apply(seq, apply_unique_name_cb, scene);
+ BKE_sequencer_recursive_apply(seq, apply_unique_name_fn, scene);
}
WM_event_add_notifier(C, NC_SCENE | ND_SEQUENCER, scene);
@@ -2401,20 +2440,20 @@ static int sequencer_add_duplicate_exec(bContext *C, wmOperator *UNUSED(op))
void SEQUENCER_OT_duplicate(wmOperatorType *ot)
{
- /* identifiers */
+ /* Identifiers. */
ot->name = "Duplicate Strips";
ot->idname = "SEQUENCER_OT_duplicate";
ot->description = "Duplicate the selected strips";
- /* api callbacks */
+ /* Api callbacks. */
ot->exec = sequencer_add_duplicate_exec;
ot->poll = ED_operator_sequencer_active;
- /* flags */
+ /* Flags. */
ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
}
-/* delete operator */
+/* Delete operator. */
static int sequencer_delete_exec(bContext *C, wmOperator *UNUSED(op))
{
Main *bmain = CTX_data_main(C);
@@ -2425,7 +2464,7 @@ static int sequencer_delete_exec(bContext *C, wmOperator *UNUSED(op))
bool nothing_selected = true;
seq = BKE_sequencer_active_get(scene);
- if (seq && seq->flag & SELECT) { /* avoid a loop since this is likely to be selected */
+ if (seq && seq->flag & SELECT) { /* Avoid a loop since this is likely to be selected. */
nothing_selected = false;
}
else {
@@ -2441,7 +2480,7 @@ static int sequencer_delete_exec(bContext *C, wmOperator *UNUSED(op))
return OPERATOR_FINISHED;
}
- /* for effects and modifiers, try to find a replacement input */
+ /* For effects and modifiers, try to find a replacement input. */
for (seq = ed->seqbasep->first; seq; seq = seq->next) {
if (!(seq->flag & SELECT)) {
if ((seq->type & SEQ_TYPE_EFFECT)) {
@@ -2453,17 +2492,17 @@ static int sequencer_delete_exec(bContext *C, wmOperator *UNUSED(op))
}
}
- /* delete all selected strips */
+ /* Delete all selected strips. */
recurs_del_seq_flag(scene, ed->seqbasep, SELECT, 0);
- /* updates lengths etc */
+ /* Update lengths, etc. */
seq = ed->seqbasep->first;
while (seq) {
BKE_sequence_calc(scene, seq);
seq = seq->next;
}
- /* free parent metas */
+ /* Free parent metas. */
ms = ed->metastack.last;
while (ms) {
BKE_sequence_calc(scene, ms->parseq);
@@ -2482,49 +2521,49 @@ static int sequencer_delete_invoke(bContext *C, wmOperator *op, const wmEvent *e
ARegion *region = CTX_wm_region(C);
if (region->regiontype == RGN_TYPE_WINDOW) {
- /* bounding box of 30 pixels is used for markers shortcuts,
- * prevent conflict with markers shortcuts here
+ /* Bounding box of 30 pixels is used for markers shortcuts,
+ * prevent conflict with markers shortcuts here.
*/
if (event->mval[1] <= 30) {
return OPERATOR_PASS_THROUGH;
}
}
- return WM_operator_confirm(C, op, event);
+ return sequencer_delete_exec(C, op);
}
void SEQUENCER_OT_delete(wmOperatorType *ot)
{
- /* identifiers */
+ /* Identifiers. */
ot->name = "Erase Strips";
ot->idname = "SEQUENCER_OT_delete";
ot->description = "Erase selected strips from the sequencer";
- /* api callbacks */
+ /* Api callbacks. */
ot->invoke = sequencer_delete_invoke;
ot->exec = sequencer_delete_exec;
ot->poll = sequencer_edit_poll;
- /* flags */
+ /* Flags. */
ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
}
-/* offset clear operator */
+/* Offset clear operator. */
static int sequencer_offset_clear_exec(bContext *C, wmOperator *UNUSED(op))
{
Scene *scene = CTX_data_scene(C);
Editing *ed = BKE_sequencer_editing_get(scene, false);
Sequence *seq;
- /* for effects, try to find a replacement input */
+ /* For effects, try to find a replacement input. */
for (seq = ed->seqbasep->first; seq; seq = seq->next) {
if ((seq->type & SEQ_TYPE_EFFECT) == 0 && (seq->flag & SELECT)) {
seq->startofs = seq->endofs = seq->startstill = seq->endstill = 0;
}
}
- /* updates lengths etc */
+ /* Update lengths, etc. */
seq = ed->seqbasep->first;
while (seq) {
BKE_sequence_calc(scene, seq);
@@ -2547,20 +2586,20 @@ static int sequencer_offset_clear_exec(bContext *C, wmOperator *UNUSED(op))
void SEQUENCER_OT_offset_clear(wmOperatorType *ot)
{
- /* identifiers */
+ /* Identifiers. */
ot->name = "Clear Strip Offset";
ot->idname = "SEQUENCER_OT_offset_clear";
ot->description = "Clear strip offsets from the start and end frames";
- /* api callbacks */
+ /* Api callbacks. */
ot->exec = sequencer_offset_clear_exec;
ot->poll = sequencer_edit_poll;
- /* flags */
+ /* Flags. */
ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
}
-/* separate_images operator */
+/* Separate_images operator. */
static int sequencer_separate_images_exec(bContext *C, wmOperator *op)
{
Scene *scene = CTX_data_scene(C);
@@ -2572,13 +2611,13 @@ static int sequencer_separate_images_exec(bContext *C, wmOperator *op)
int start_ofs, cfra, frame_end;
int step = RNA_int_get(op->ptr, "length");
- seq = ed->seqbasep->first; /* poll checks this is valid */
+ seq = ed->seqbasep->first; /* Poll checks this is valid. */
while (seq) {
if ((seq->flag & SELECT) && (seq->type == SEQ_TYPE_IMAGE) && (seq->len > 1)) {
Sequence *seq_next;
- /* remove seq so overlap tests don't conflict,
+ /* Remove seq so overlap tests don't conflict,
* see seq_free_sequence below for the real freeing. */
BLI_remlink(ed->seqbasep, seq);
/* if (seq->ipo) id_us_min(&seq->ipo->id); */
@@ -2588,7 +2627,7 @@ static int sequencer_separate_images_exec(bContext *C, wmOperator *op)
frame_end = BKE_sequence_tx_get_final_right(seq, false);
while (cfra < frame_end) {
- /* new seq */
+ /* New seq. */
se = BKE_sequencer_give_stripelem(seq, cfra);
seq_new = BKE_sequence_dupli_recursive(
@@ -2599,11 +2638,11 @@ static int sequencer_separate_images_exec(bContext *C, wmOperator *op)
seq_new->len = 1;
seq_new->endstill = step - 1;
- /* new strip */
+ /* New strip. */
strip_new = seq_new->strip;
strip_new->us = 1;
- /* new stripdata (only one element now!) */
+ /* New stripdata, only one element now. */
/* Note this assume all elements (images) have the same dimension,
* since we only copy the name here. */
se_new = MEM_reallocN(strip_new->stripdata, sizeof(*se_new));
@@ -2626,7 +2665,7 @@ static int sequencer_separate_images_exec(bContext *C, wmOperator *op)
}
seq_next = seq->next;
- BKE_sequence_free(scene, seq);
+ BKE_sequence_free(scene, seq, true);
seq = seq_next;
}
else {
@@ -2634,7 +2673,6 @@ static int sequencer_separate_images_exec(bContext *C, wmOperator *op)
}
}
- /* as last: */
BKE_sequencer_sort(scene);
WM_event_add_notifier(C, NC_SCENE | ND_SEQUENCER, scene);
@@ -2644,25 +2682,25 @@ static int sequencer_separate_images_exec(bContext *C, wmOperator *op)
void SEQUENCER_OT_images_separate(wmOperatorType *ot)
{
- /* identifiers */
+ /* Identifiers. */
ot->name = "Separate Images";
ot->idname = "SEQUENCER_OT_images_separate";
ot->description = "On image sequence strips, it returns a strip for each image";
- /* api callbacks */
+ /* Api callbacks. */
ot->exec = sequencer_separate_images_exec;
ot->invoke = WM_operator_props_popup_confirm;
ot->poll = sequencer_edit_poll;
- /* flags */
+ /* Flags. */
ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
RNA_def_int(ot->srna, "length", 1, 1, INT_MAX, "Length", "Length of each frame", 1, 1000);
}
-/* META Operators */
+/* META Operators. */
-/* separate_meta_toggle operator */
+/* Separate_meta_toggle operator. */
static int sequencer_meta_toggle_exec(bContext *C, wmOperator *UNUSED(op))
{
Scene *scene = CTX_data_scene(C);
@@ -2671,7 +2709,7 @@ static int sequencer_meta_toggle_exec(bContext *C, wmOperator *UNUSED(op))
MetaStack *ms;
if (last_seq && last_seq->type == SEQ_TYPE_META && last_seq->flag & SELECT) {
- /* Enter Metastrip */
+ /* Enter metastrip. */
ms = MEM_mallocN(sizeof(MetaStack), "metastack");
BLI_addtail(&ed->metastack, ms);
ms->parseq = last_seq;
@@ -2683,7 +2721,7 @@ static int sequencer_meta_toggle_exec(bContext *C, wmOperator *UNUSED(op))
BKE_sequencer_active_set(scene, NULL);
}
else {
- /* Exit Metastrip (if possible) */
+ /* Exit metastrip if possible. */
Sequence *seq;
@@ -2696,18 +2734,18 @@ static int sequencer_meta_toggle_exec(bContext *C, wmOperator *UNUSED(op))
ed->seqbasep = ms->oldbasep;
- /* for old files, update from meta */
+ /* For old files, update from meta. */
if (ms->disp_range[0] == ms->disp_range[1]) {
copy_v2_v2_int(ms->disp_range, &ms->parseq->startdisp);
}
- /* recalc all: the meta can have effects connected to it */
+ /* Recalc all: the meta can have effects connected to it. */
for (seq = ed->seqbasep->first; seq; seq = seq->next) {
BKE_sequence_calc(scene, seq);
}
/* 2.73+, keeping endpoints is important!
- * moving them around means you can't usefully use metas in a complex edit. */
+ * Moving them around means you can't usefully use metas in a complex edit. */
#if 1
BKE_sequence_tx_set_final_left(ms->parseq, ms->disp_range[0]);
BKE_sequence_tx_set_final_right(ms->parseq, ms->disp_range[1]);
@@ -2735,20 +2773,20 @@ static int sequencer_meta_toggle_exec(bContext *C, wmOperator *UNUSED(op))
void SEQUENCER_OT_meta_toggle(wmOperatorType *ot)
{
- /* identifiers */
+ /* Identifiers. */
ot->name = "Toggle Meta Strip";
ot->idname = "SEQUENCER_OT_meta_toggle";
ot->description = "Toggle a metastrip (to edit enclosed strips)";
- /* api callbacks */
+ /* Api callbacks. */
ot->exec = sequencer_meta_toggle_exec;
ot->poll = sequencer_edit_poll;
- /* flags */
+ /* Flags. */
ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
}
-/* separate_meta_make operator */
+/* Separate_meta_make operator. */
static int sequencer_meta_make_exec(bContext *C, wmOperator *op)
{
Scene *scene = CTX_data_scene(C);
@@ -2762,9 +2800,9 @@ static int sequencer_meta_make_exec(bContext *C, wmOperator *op)
return OPERATOR_CANCELLED;
}
- /* remove all selected from main list, and put in meta */
+ /* Remove all selected from main list, and put in meta. */
- seqm = BKE_sequence_alloc(ed->seqbasep, 1, 1, SEQ_TYPE_META); /* channel number set later */
+ seqm = BKE_sequence_alloc(ed->seqbasep, 1, 1, SEQ_TYPE_META); /* Channel number set later. */
strcpy(seqm->name + 2, "MetaStrip");
seqm->flag = SELECT;
@@ -2799,16 +2837,16 @@ static int sequencer_meta_make_exec(bContext *C, wmOperator *op)
void SEQUENCER_OT_meta_make(wmOperatorType *ot)
{
- /* identifiers */
+ /* Identifiers. */
ot->name = "Make Meta Strip";
ot->idname = "SEQUENCER_OT_meta_make";
ot->description = "Group selected strips into a metastrip";
- /* api callbacks */
+ /* Api callbacks. */
ot->exec = sequencer_meta_make_exec;
ot->poll = sequencer_edit_poll;
- /* flags */
+ /* Flags. */
ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
}
@@ -2831,7 +2869,7 @@ static int seq_depends_on_meta(Sequence *seq, Sequence *seqm)
}
}
-/* separate_meta_make operator */
+/* Separate_meta_make operator. */
static int sequencer_meta_separate_exec(bContext *C, wmOperator *UNUSED(op))
{
Scene *scene = CTX_data_scene(C);
@@ -2852,9 +2890,9 @@ static int sequencer_meta_separate_exec(bContext *C, wmOperator *UNUSED(op))
BLI_listbase_clear(&last_seq->seqbase);
BLI_remlink(ed->seqbasep, last_seq);
- BKE_sequence_free(scene, last_seq);
+ BKE_sequence_free(scene, last_seq, true);
- /* empty meta strip, delete all effects depending on it */
+ /* Empty meta strip, delete all effects depending on it. */
for (seq = ed->seqbasep->first; seq; seq = seq->next) {
if ((seq->type & SEQ_TYPE_EFFECT) && seq_depends_on_meta(seq, last_seq)) {
seq->flag |= SEQ_FLAG_DELETE;
@@ -2863,8 +2901,8 @@ static int sequencer_meta_separate_exec(bContext *C, wmOperator *UNUSED(op))
recurs_del_seq_flag(scene, ed->seqbasep, SEQ_FLAG_DELETE, 0);
- /* test for effects and overlap
- * don't use SEQP_BEGIN since that would be recursive */
+ /* Test for effects and overlap
+ * don't use SEQP_BEGIN since that would be recursive. */
for (seq = ed->seqbasep->first; seq; seq = seq->next) {
if (seq->flag & SELECT) {
seq->flag &= ~SEQ_OVERLAP;
@@ -2884,20 +2922,20 @@ static int sequencer_meta_separate_exec(bContext *C, wmOperator *UNUSED(op))
void SEQUENCER_OT_meta_separate(wmOperatorType *ot)
{
- /* identifiers */
+ /* Identifiers. */
ot->name = "UnMeta Strip";
ot->idname = "SEQUENCER_OT_meta_separate";
ot->description = "Put the contents of a metastrip back in the sequencer";
- /* api callbacks */
+ /* Api callbacks. */
ot->exec = sequencer_meta_separate_exec;
ot->poll = sequencer_edit_poll;
- /* flags */
+ /* Flags. */
ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
}
-/* view_all operator */
+/* View_all operator. */
static int sequencer_view_all_exec(bContext *C, wmOperator *op)
{
ARegion *region = CTX_wm_region(C);
@@ -2912,16 +2950,16 @@ static int sequencer_view_all_exec(bContext *C, wmOperator *op)
void SEQUENCER_OT_view_all(wmOperatorType *ot)
{
- /* identifiers */
- ot->name = "View All";
+ /* Identifiers. */
+ ot->name = "Frame All";
ot->idname = "SEQUENCER_OT_view_all";
ot->description = "View all the strips in the sequencer";
- /* api callbacks */
+ /* Api callbacks. */
ot->exec = sequencer_view_all_exec;
ot->poll = ED_operator_sequencer_active;
- /* flags */
+ /* Flags. */
ot->flag = OPTYPE_REGISTER;
}
@@ -2935,23 +2973,23 @@ static int sequencer_view_frame_exec(bContext *C, wmOperator *op)
void SEQUENCER_OT_view_frame(wmOperatorType *ot)
{
- /* identifiers */
+ /* Identifiers. */
ot->name = "Go to Current Frame";
ot->idname = "SEQUENCER_OT_view_frame";
- ot->description = "Move the view to the playhead";
+ ot->description = "Move the view to the current frame";
- /* api callbacks */
+ /* Api callbacks. */
ot->exec = sequencer_view_frame_exec;
ot->poll = ED_operator_sequencer_active;
- /* flags */
+ /* Flags. */
ot->flag = 0;
}
-/* view_all operator */
+/* View_all operator. */
static int sequencer_view_all_preview_exec(bContext *C, wmOperator *UNUSED(op))
{
- bScreen *sc = CTX_wm_screen(C);
+ bScreen *screen = CTX_wm_screen(C);
ScrArea *area = CTX_wm_area(C);
#if 0
ARegion *region = CTX_wm_region(C);
@@ -2962,10 +3000,10 @@ static int sequencer_view_all_preview_exec(bContext *C, wmOperator *UNUSED(op))
v2d->cur = v2d->tot;
UI_view2d_curRect_validate(v2d);
- UI_view2d_sync(sc, area, v2d, V2D_LOCK_COPY);
+ UI_view2d_sync(screen, area, v2d, V2D_LOCK_COPY);
#if 0
- /* Like zooming on an image view */
+ /* Like zooming on an image view. */
float zoomX, zoomY;
int width, height, imgwidth, imgheight;
@@ -2977,11 +3015,11 @@ static int sequencer_view_all_preview_exec(bContext *C, wmOperator *UNUSED(op))
imgwidth = (scene->r.size * scene->r.xsch) / 100;
imgheight = (scene->r.size * scene->r.ysch) / 100;
- /* Apply aspect, doesn't need to be that accurate */
+ /* Apply aspect, doesn't need to be that accurate. */
imgwidth = (int)(imgwidth * (scene->r.xasp / scene->r.yasp));
if (((imgwidth >= width) || (imgheight >= height)) && ((width > 0) && (height > 0))) {
- /* Find the zoom value that will fit the image in the image space */
+ /* Find the zoom value that will fit the image in the image space. */
zoomX = ((float)width) / ((float)imgwidth);
zoomY = ((float)height) / ((float)imgheight);
sseq->zoom = (zoomX < zoomY) ? zoomX : zoomY;
@@ -2999,16 +3037,16 @@ static int sequencer_view_all_preview_exec(bContext *C, wmOperator *UNUSED(op))
void SEQUENCER_OT_view_all_preview(wmOperatorType *ot)
{
- /* identifiers */
- ot->name = "View All";
+ /* Identifiers. */
+ ot->name = "Frame All";
ot->idname = "SEQUENCER_OT_view_all_preview";
ot->description = "Zoom preview to fit in the area";
- /* api callbacks */
+ /* Api callbacks. */
ot->exec = sequencer_view_all_preview_exec;
ot->poll = ED_operator_sequencer_active;
- /* flags */
+ /* Flags. */
ot->flag = OPTYPE_REGISTER;
}
@@ -3034,16 +3072,16 @@ static int sequencer_view_zoom_ratio_exec(bContext *C, wmOperator *op)
void SEQUENCER_OT_view_zoom_ratio(wmOperatorType *ot)
{
- /* identifiers */
+ /* Identifiers. */
ot->name = "Sequencer View Zoom Ratio";
ot->idname = "SEQUENCER_OT_view_zoom_ratio";
ot->description = "Change zoom ratio of sequencer preview";
- /* api callbacks */
+ /* Api callbacks. */
ot->exec = sequencer_view_zoom_ratio_exec;
ot->poll = ED_operator_sequencer_active;
- /* properties */
+ /* Properties. */
RNA_def_float(ot->srna,
"ratio",
1.0f,
@@ -3068,7 +3106,7 @@ static const EnumPropertyItem view_type_items[] = {
};
#endif
-/* view_all operator */
+/* View_all operator. */
static int sequencer_view_toggle_exec(bContext *C, wmOperator *UNUSED(op))
{
SpaceSeq *sseq = (SpaceSeq *)CTX_wm_space_data(C);
@@ -3085,20 +3123,20 @@ static int sequencer_view_toggle_exec(bContext *C, wmOperator *UNUSED(op))
void SEQUENCER_OT_view_toggle(wmOperatorType *ot)
{
- /* identifiers */
+ /* Identifiers. */
ot->name = "View Toggle";
ot->idname = "SEQUENCER_OT_view_toggle";
ot->description = "Toggle between sequencer views (sequence, preview, both)";
- /* api callbacks */
+ /* Api callbacks. */
ot->exec = sequencer_view_toggle_exec;
ot->poll = ED_operator_sequencer_active;
- /* flags */
+ /* Flags. */
ot->flag = OPTYPE_REGISTER;
}
-/* view_selected operator */
+/* View_selected operator. */
static int sequencer_view_selected_exec(bContext *C, wmOperator *op)
{
Scene *scene = CTX_data_scene(C);
@@ -3148,7 +3186,7 @@ static int sequencer_view_selected_exec(bContext *C, wmOperator *op)
cur_new.ymin = ymin;
cur_new.ymax = ymax;
- /* only zoom out vertically */
+ /* Only zoom out vertically. */
if (orig_height > BLI_rctf_size_y(&cur_new)) {
ymid = BLI_rctf_cent_y(&cur_new);
@@ -3167,16 +3205,16 @@ static int sequencer_view_selected_exec(bContext *C, wmOperator *op)
void SEQUENCER_OT_view_selected(wmOperatorType *ot)
{
- /* identifiers */
+ /* Identifiers. */
ot->name = "Frame Selected";
ot->idname = "SEQUENCER_OT_view_selected";
ot->description = "Zoom the sequencer on the selected strips";
- /* api callbacks */
+ /* Api callbacks. */
ot->exec = sequencer_view_selected_exec;
ot->poll = ED_operator_sequencer_active;
- /* flags */
+ /* Flags. */
ot->flag = OPTYPE_REGISTER;
}
@@ -3199,7 +3237,7 @@ static bool strip_jump_internal(Scene *scene,
static bool sequencer_strip_jump_poll(bContext *C)
{
- /* prevent changes during render */
+ /* Prevent changes during render. */
if (G.is_rendering) {
return 0;
}
@@ -3207,14 +3245,14 @@ static bool sequencer_strip_jump_poll(bContext *C)
return sequencer_edit_poll(C);
}
-/* jump frame to edit point operator */
+/* Jump frame to edit point operator. */
static int sequencer_strip_jump_exec(bContext *C, wmOperator *op)
{
Scene *scene = CTX_data_scene(C);
const bool next = RNA_boolean_get(op->ptr, "next");
const bool center = RNA_boolean_get(op->ptr, "center");
- /* currently do_skip_mute is always true */
+ /* Currently do_skip_mute is always true. */
if (!strip_jump_internal(scene, next ? SEQ_SIDE_RIGHT : SEQ_SIDE_LEFT, true, center)) {
return OPERATOR_CANCELLED;
}
@@ -3226,19 +3264,19 @@ static int sequencer_strip_jump_exec(bContext *C, wmOperator *op)
void SEQUENCER_OT_strip_jump(wmOperatorType *ot)
{
- /* identifiers */
+ /* Identifiers. */
ot->name = "Jump to Strip";
ot->idname = "SEQUENCER_OT_strip_jump";
ot->description = "Move frame to previous edit point";
- /* api callbacks */
+ /* Api callbacks. */
ot->exec = sequencer_strip_jump_exec;
ot->poll = sequencer_strip_jump_poll;
- /* flags */
+ /* Flags. */
ot->flag = OPTYPE_UNDO;
- /* properties */
+ /* Properties. */
RNA_def_boolean(ot->srna, "next", true, "Next Strip", "");
RNA_def_boolean(ot->srna, "center", true, "Use strip center", "");
}
@@ -3296,7 +3334,7 @@ static int sequencer_swap_exec(bContext *C, wmOperator *op)
if (seq) {
- /* disallow effect strips */
+ /* Disallow effect strips. */
if (BKE_sequence_effect_get_num_inputs(seq->type) >= 1 &&
(seq->effectdata || seq->seq1 || seq->seq2 || seq->seq3)) {
return OPERATOR_CANCELLED;
@@ -3315,7 +3353,7 @@ static int sequencer_swap_exec(bContext *C, wmOperator *op)
break;
}
- // XXX - should be a generic function
+ /* XXX - Should be a generic function. */
for (iseq = scene->ed->seqbasep->first; iseq; iseq = iseq->next) {
if ((iseq->type & SEQ_TYPE_EFFECT) &&
(seq_is_parent(iseq, active_seq) || seq_is_parent(iseq, seq))) {
@@ -3323,11 +3361,11 @@ static int sequencer_swap_exec(bContext *C, wmOperator *op)
}
}
- /* do this in a new loop since both effects need to be calculated first */
+ /* Do this in a new loop since both effects need to be calculated first. */
for (iseq = scene->ed->seqbasep->first; iseq; iseq = iseq->next) {
if ((iseq->type & SEQ_TYPE_EFFECT) &&
(seq_is_parent(iseq, active_seq) || seq_is_parent(iseq, seq))) {
- /* this may now overlap */
+ /* This may now overlap. */
if (BKE_sequence_test_overlap(ed->seqbasep, iseq)) {
BKE_sequence_base_shuffle(ed->seqbasep, iseq, scene);
}
@@ -3346,19 +3384,19 @@ static int sequencer_swap_exec(bContext *C, wmOperator *op)
void SEQUENCER_OT_swap(wmOperatorType *ot)
{
- /* identifiers */
+ /* Identifiers. */
ot->name = "Swap Strip";
ot->idname = "SEQUENCER_OT_swap";
ot->description = "Swap active strip with strip to the right or left";
- /* api callbacks */
+ /* Api callbacks. */
ot->exec = sequencer_swap_exec;
ot->poll = sequencer_edit_poll;
- /* flags */
+ /* Flags. */
ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
- /* properties */
+ /* Properties. */
RNA_def_enum(
ot->srna, "side", prop_side_lr_types, SEQ_SIDE_RIGHT, "Side", "Side of the strip to swap");
}
@@ -3392,7 +3430,7 @@ static int sequencer_rendersize_exec(bContext *C, wmOperator *UNUSED(op))
}
if (se) {
- // prevent setting the render size if sequence values aren't initialized
+ /* Prevent setting the render size if sequence values aren't initialized. */
if ((se->orig_width > 0) && (se->orig_height > 0)) {
scene->r.xsch = se->orig_width;
scene->r.ysch = se->orig_height;
@@ -3406,19 +3444,17 @@ static int sequencer_rendersize_exec(bContext *C, wmOperator *UNUSED(op))
void SEQUENCER_OT_rendersize(wmOperatorType *ot)
{
- /* identifiers */
+ /* Identifiers. */
ot->name = "Set Render Size";
ot->idname = "SEQUENCER_OT_rendersize";
ot->description = "Set render size and aspect from active sequence";
- /* api callbacks */
+ /* Api callbacks. */
ot->exec = sequencer_rendersize_exec;
ot->poll = sequencer_edit_poll;
- /* flags */
+ /* Flags. */
ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
-
- /* properties */
}
static void seq_copy_del_sound(Scene *scene, Sequence *seq)
@@ -3441,8 +3477,6 @@ static int sequencer_copy_exec(bContext *C, wmOperator *op)
Scene *scene = CTX_data_scene(C);
Editing *ed = BKE_sequencer_editing_get(scene, false);
- ListBase nseqbase = {NULL, NULL};
-
BKE_sequencer_free_clipboard();
if (BKE_sequence_base_isolated_sel_check(ed->seqbasep) == false) {
@@ -3451,33 +3485,12 @@ static int sequencer_copy_exec(bContext *C, wmOperator *op)
}
BKE_sequence_base_dupli_recursive(
- scene, scene, &nseqbase, ed->seqbasep, SEQ_DUPE_UNIQUE_NAME, LIB_ID_CREATE_NO_USER_REFCOUNT);
-
- /* To make sure the copied strips have unique names between each other add
- * them temporarily to the end of the original seqbase. (bug 25932)
- */
- if (nseqbase.first) {
- Sequence *seq, *first_seq = nseqbase.first;
- BLI_movelisttolist(ed->seqbasep, &nseqbase);
-
- for (seq = first_seq; seq; seq = seq->next) {
- BKE_sequencer_recursive_apply(seq, apply_unique_name_cb, scene);
- }
-
- seqbase_clipboard.first = first_seq;
- seqbase_clipboard.last = ed->seqbasep->last;
-
- if (first_seq->prev) {
- first_seq->prev->next = NULL;
- ed->seqbasep->last = first_seq->prev;
- first_seq->prev = NULL;
- }
- }
+ scene, scene, &seqbase_clipboard, ed->seqbasep, 0, LIB_ID_CREATE_NO_USER_REFCOUNT);
seqbase_clipboard_frame = scene->r.cfra;
- /* Need to remove anything that references the current scene */
- for (Sequence *seq = seqbase_clipboard.first; seq; seq = seq->next) {
+ /* Remove anything that references the current scene. */
+ LISTBASE_FOREACH (Sequence *, seq, &seqbase_clipboard) {
seq_copy_del_sound(scene, seq);
}
@@ -3490,26 +3503,24 @@ static int sequencer_copy_exec(bContext *C, wmOperator *op)
void SEQUENCER_OT_copy(wmOperatorType *ot)
{
- /* identifiers */
+ /* Identifiers. */
ot->name = "Copy";
ot->idname = "SEQUENCER_OT_copy";
ot->description = "Copy selected strips to clipboard";
- /* api callbacks */
+ /* Api callbacks. */
ot->exec = sequencer_copy_exec;
ot->poll = sequencer_edit_poll;
- /* flags */
+ /* Flags. */
ot->flag = OPTYPE_REGISTER;
-
- /* properties */
}
static int sequencer_paste_exec(bContext *C, wmOperator *UNUSED(op))
{
Main *bmain = CTX_data_main(C);
Scene *scene = CTX_data_scene(C);
- Editing *ed = BKE_sequencer_editing_get(scene, true); /* create if needed */
+ Editing *ed = BKE_sequencer_editing_get(scene, true); /* Create if needed. */
ListBase nseqbase = {NULL, NULL};
int ofs;
Sequence *iseq, *iseq_first;
@@ -3521,28 +3532,19 @@ static int sequencer_paste_exec(bContext *C, wmOperator *UNUSED(op))
* must happen on the clipboard itself, so that copying does user counting
* on the actual data-blocks. */
BKE_sequencer_base_clipboard_pointers_restore(&seqbase_clipboard, bmain);
- BKE_sequence_base_dupli_recursive(
- scene, scene, &nseqbase, &seqbase_clipboard, SEQ_DUPE_UNIQUE_NAME, 0);
- BKE_sequencer_base_clipboard_pointers_store(bmain, &seqbase_clipboard);
-
- /* transform pasted strips before adding */
- if (ofs) {
- for (iseq = nseqbase.first; iseq; iseq = iseq->next) {
- BKE_sequence_translate(scene, iseq, ofs);
- }
- }
+ BKE_sequence_base_dupli_recursive(scene, scene, &nseqbase, &seqbase_clipboard, 0, 0);
iseq_first = nseqbase.first;
BLI_movelisttolist(ed->seqbasep, &nseqbase);
- /* make sure the pasted strips have unique names between them */
- for (iseq = iseq_first; iseq; iseq = iseq->next) {
- BKE_sequencer_recursive_apply(iseq, apply_unique_name_cb, scene);
- }
-
- /* ensure pasted strips don't overlap */
for (iseq = iseq_first; iseq; iseq = iseq->next) {
+ /* Make sure, that pasted strips have unique names. */
+ BKE_sequencer_recursive_apply(iseq, apply_unique_name_fn, scene);
+ /* Translate after name has been changed, otherwise this will affect animdata of original
+ * strip. */
+ BKE_sequence_translate(scene, iseq, ofs);
+ /* Ensure, that pasted strips don't overlap. */
if (BKE_sequence_test_overlap(ed->seqbasep, iseq)) {
BKE_sequence_base_shuffle(ed->seqbasep, iseq, scene);
}
@@ -3550,25 +3552,24 @@ static int sequencer_paste_exec(bContext *C, wmOperator *UNUSED(op))
DEG_id_tag_update(&scene->id, ID_RECALC_SEQUENCER_STRIPS);
WM_event_add_notifier(C, NC_SCENE | ND_SEQUENCER, scene);
+ ED_outliner_select_sync_from_sequence_tag(C);
return OPERATOR_FINISHED;
}
void SEQUENCER_OT_paste(wmOperatorType *ot)
{
- /* identifiers */
+ /* Identifiers. */
ot->name = "Paste";
ot->idname = "SEQUENCER_OT_paste";
ot->description = "Paste strips from clipboard";
- /* api callbacks */
+ /* Api callbacks. */
ot->exec = sequencer_paste_exec;
ot->poll = ED_operator_sequencer_active;
- /* flags */
+ /* Flags. */
ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
-
- /* properties */
}
static int sequencer_swap_data_exec(bContext *C, wmOperator *op)
@@ -3619,22 +3620,20 @@ static int sequencer_swap_data_exec(bContext *C, wmOperator *op)
void SEQUENCER_OT_swap_data(wmOperatorType *ot)
{
- /* identifiers */
+ /* Identifiers. */
ot->name = "Sequencer Swap Data";
ot->idname = "SEQUENCER_OT_swap_data";
ot->description = "Swap 2 sequencer strips";
- /* api callbacks */
+ /* Api callbacks. */
ot->exec = sequencer_swap_data_exec;
ot->poll = ED_operator_sequencer_active;
- /* flags */
+ /* Flags. */
ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
-
- /* properties */
}
-/* box select operator */
+/* Box select operator. */
static int view_ghost_border_exec(bContext *C, wmOperator *op)
{
Scene *scene = CTX_data_scene(C);
@@ -3642,7 +3641,7 @@ static int view_ghost_border_exec(bContext *C, wmOperator *op)
rctf rect;
- /* convert coordinates of rect to 'tot' rect coordinates */
+ /* Convert coordinates of rect to 'tot' rect coordinates. */
WM_operator_properties_border_to_rctf(op, &rect);
UI_view2d_region_to_view_rctf(v2d, &rect, &rect);
@@ -3669,30 +3668,28 @@ static int view_ghost_border_exec(bContext *C, wmOperator *op)
return OPERATOR_FINISHED;
}
-/* ****** Box Select ****** */
void SEQUENCER_OT_view_ghost_border(wmOperatorType *ot)
{
- /* identifiers */
+ /* Identifiers. */
ot->name = "Border Offset View";
ot->idname = "SEQUENCER_OT_view_ghost_border";
ot->description = "Set the boundaries of the border used for offset-view";
- /* api callbacks */
+ /* Api callbacks. */
ot->invoke = WM_gesture_box_invoke;
ot->exec = view_ghost_border_exec;
ot->modal = WM_gesture_box_modal;
ot->poll = sequencer_view_preview_poll;
ot->cancel = WM_gesture_box_cancel;
- /* flags */
+ /* Flags. */
ot->flag = 0;
- /* rna */
+ /* Properties. */
WM_operator_properties_gesture_box(ot);
}
-/* rebuild_proxy operator */
-
+/* Rebuild_proxy operator. */
static int sequencer_rebuild_proxy_invoke(bContext *C,
wmOperator *op,
const wmEvent *UNUSED(event))
@@ -3743,16 +3740,16 @@ static int sequencer_rebuild_proxy_exec(bContext *C, wmOperator *UNUSED(op))
void SEQUENCER_OT_rebuild_proxy(wmOperatorType *ot)
{
- /* identifiers */
+ /* Identifiers. */
ot->name = "Rebuild Proxy and Timecode Indices";
ot->idname = "SEQUENCER_OT_rebuild_proxy";
ot->description = "Rebuild all selected proxies and timecode indices using the job system";
- /* api callbacks */
+ /* Api callbacks. */
ot->invoke = sequencer_rebuild_proxy_invoke;
ot->exec = sequencer_rebuild_proxy_exec;
- /* flags */
+ /* Flags. */
ot->flag = OPTYPE_REGISTER;
}
@@ -3781,12 +3778,7 @@ static int sequencer_enable_proxies_exec(bContext *C, wmOperator *op)
SEQP_BEGIN (ed, seq) {
if ((seq->flag & SELECT)) {
- if (ELEM(seq->type,
- SEQ_TYPE_MOVIE,
- SEQ_TYPE_IMAGE,
- SEQ_TYPE_META,
- SEQ_TYPE_SCENE,
- SEQ_TYPE_MULTICAM)) {
+ if (ELEM(seq->type, SEQ_TYPE_MOVIE, SEQ_TYPE_IMAGE, SEQ_TYPE_META)) {
BKE_sequencer_proxy_set(seq, turnon);
if (seq->strip->proxy == NULL) {
continue;
@@ -3838,16 +3830,16 @@ static int sequencer_enable_proxies_exec(bContext *C, wmOperator *op)
void SEQUENCER_OT_enable_proxies(wmOperatorType *ot)
{
- /* identifiers */
+ /* Identifiers. */
ot->name = "Set Selected Strip Proxies";
ot->idname = "SEQUENCER_OT_enable_proxies";
ot->description = "Enable selected proxies on all selected Movie, Image and Meta strips";
- /* api callbacks */
+ /* Api callbacks. */
ot->invoke = sequencer_enable_proxies_invoke;
ot->exec = sequencer_enable_proxies_exec;
- /* flags */
+ /* Flags. */
ot->flag = OPTYPE_REGISTER;
RNA_def_boolean(ot->srna, "proxy_25", false, "25%", "");
@@ -3857,8 +3849,7 @@ void SEQUENCER_OT_enable_proxies(wmOperatorType *ot)
RNA_def_boolean(ot->srna, "overwrite", false, "Overwrite", "");
}
-/* change ops */
-
+/* Change effect inputs operator. */
static const EnumPropertyItem prop_change_effect_input_types[] = {
{0, "A_B", 0, "A -> B", ""},
{1, "B_C", 0, "B -> C", ""},
@@ -3899,9 +3890,8 @@ static int sequencer_change_effect_input_exec(bContext *C, wmOperator *op)
BKE_sequencer_update_changed_seq_and_deps(scene, seq, 0, 1);
- /* important else we don't get the imbuf cache flushed */
+ /* Invalidate cache. */
BKE_sequencer_free_imbuf(scene, &ed->seqbase, false);
-
WM_event_add_notifier(C, NC_SCENE | ND_SEQUENCER, scene);
return OPERATOR_FINISHED;
@@ -3909,21 +3899,22 @@ static int sequencer_change_effect_input_exec(bContext *C, wmOperator *op)
void SEQUENCER_OT_change_effect_input(struct wmOperatorType *ot)
{
- /* identifiers */
+ /* Identifiers. */
ot->name = "Change Effect Input";
ot->idname = "SEQUENCER_OT_change_effect_input";
- /* api callbacks */
+ /* Api callbacks. */
ot->exec = sequencer_change_effect_input_exec;
ot->poll = sequencer_effect_poll;
- /* flags */
+ /* Flags. */
ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
ot->prop = RNA_def_enum(
ot->srna, "swap", prop_change_effect_input_types, 0, "Swap", "The effect inputs to swap");
}
+/* Change effect type operator. */
static int sequencer_change_effect_type_exec(bContext *C, wmOperator *op)
{
Scene *scene = CTX_data_scene(C);
@@ -3931,14 +3922,14 @@ static int sequencer_change_effect_type_exec(bContext *C, wmOperator *op)
Sequence *seq = BKE_sequencer_active_get(scene);
const int new_type = RNA_enum_get(op->ptr, "type");
- /* free previous effect and init new effect */
+ /* Free previous effect and init new effect. */
struct SeqEffectHandle sh;
if ((seq->type & SEQ_TYPE_EFFECT) == 0) {
return OPERATOR_CANCELLED;
}
- /* can someone explain the logic behind only allowing to increase this,
+ /* Can someone explain the logic behind only allowing to increase this,
* copied from 2.4x - campbell */
if (BKE_sequence_effect_get_num_inputs(seq->type) <
BKE_sequence_effect_get_num_inputs(new_type)) {
@@ -3955,10 +3946,8 @@ static int sequencer_change_effect_type_exec(bContext *C, wmOperator *op)
sh.init(seq);
}
- /* update */
BKE_sequencer_update_changed_seq_and_deps(scene, seq, 0, 1);
-
- /* important else we don't get the imbuf cache flushed */
+ /* Invalidate cache. */
BKE_sequencer_free_imbuf(scene, &ed->seqbase, false);
WM_event_add_notifier(C, NC_SCENE | ND_SEQUENCER, scene);
@@ -3968,15 +3957,15 @@ static int sequencer_change_effect_type_exec(bContext *C, wmOperator *op)
void SEQUENCER_OT_change_effect_type(struct wmOperatorType *ot)
{
- /* identifiers */
+ /* Identifiers. */
ot->name = "Change Effect Type";
ot->idname = "SEQUENCER_OT_change_effect_type";
- /* api callbacks */
+ /* Api callbacks. */
ot->exec = sequencer_change_effect_type_exec;
ot->poll = sequencer_effect_poll;
- /* flags */
+ /* Flags. */
ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
ot->prop = RNA_def_enum(ot->srna,
@@ -3987,6 +3976,7 @@ void SEQUENCER_OT_change_effect_type(struct wmOperatorType *ot)
"Sequencer effect type");
}
+/* Change path operator. */
static int sequencer_change_path_exec(bContext *C, wmOperator *op)
{
Main *bmain = CTX_data_main(C);
@@ -4002,7 +3992,7 @@ static int sequencer_change_path_exec(bContext *C, wmOperator *op)
int len;
StripElem *se;
- /* need to find min/max frame for placeholders */
+ /* Need to find min/max frame for placeholders. */
if (use_placeholders) {
len = sequencer_image_seq_get_minmax_frame(op, seq->sfra, &minframe, &numdigits);
}
@@ -4040,16 +4030,16 @@ static int sequencer_change_path_exec(bContext *C, wmOperator *op)
RNA_END;
}
- /* reset these else we wont see all the images */
+ /* Reset these else we wont see all the images. */
seq->anim_startofs = seq->anim_endofs = 0;
- /* correct start/end frames so we don't move
- * important not to set seq->len = len; allow the function to handle it */
+ /* Correct start/end frames so we don't move.
+ * Important not to set seq->len = len; allow the function to handle it. */
BKE_sequence_reload_new_file(bmain, scene, seq, true);
BKE_sequence_calc(scene, seq);
- /* important else we don't get the imbuf cache flushed */
+ /* Invalidate cache. */
BKE_sequencer_free_imbuf(scene, &ed->seqbase, false);
}
else if (ELEM(seq->type, SEQ_TYPE_SOUND_RAM, SEQ_TYPE_SOUND_HD)) {
@@ -4063,7 +4053,7 @@ static int sequencer_change_path_exec(bContext *C, wmOperator *op)
BKE_sound_load(bmain, sound);
}
else {
- /* lame, set rna filepath */
+ /* Lame, set rna filepath. */
PointerRNA seq_ptr;
PropertyRNA *prop;
char filepath[FILE_MAX];
@@ -4092,7 +4082,7 @@ static int sequencer_change_path_invoke(bContext *C, wmOperator *op, const wmEve
RNA_string_set(op->ptr, "directory", seq->strip->dir);
RNA_string_set(op->ptr, "filepath", filepath);
- /* set default display depending on seq type */
+ /* Set default display depending on seq type. */
if (seq->type == SEQ_TYPE_IMAGE) {
RNA_boolean_set(op->ptr, "filter_movie", false);
}
@@ -4107,16 +4097,16 @@ static int sequencer_change_path_invoke(bContext *C, wmOperator *op, const wmEve
void SEQUENCER_OT_change_path(struct wmOperatorType *ot)
{
- /* identifiers */
+ /* Identifiers. */
ot->name = "Change Data/Files";
ot->idname = "SEQUENCER_OT_change_path";
- /* api callbacks */
+ /* Api callbacks. */
ot->exec = sequencer_change_path_exec;
ot->invoke = sequencer_change_path_invoke;
ot->poll = sequencer_strip_has_path_poll;
- /* flags */
+ /* Flags. */
ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
WM_operator_properties_filesel(ot,
@@ -4134,6 +4124,7 @@ void SEQUENCER_OT_change_path(struct wmOperatorType *ot)
"Use placeholders for missing frames of the strip");
}
+/* Export subtitles operator. */
static int sequencer_export_subtitles_invoke(bContext *C,
wmOperator *op,
const wmEvent *UNUSED(event))
@@ -4176,7 +4167,7 @@ static int sequencer_export_subtitles_exec(bContext *C, wmOperator *op)
RNA_string_get(op->ptr, "filepath", filepath);
BLI_path_extension_ensure(filepath, sizeof(filepath), ".srt");
- /* Avoid File write exceptions */
+ /* Avoid File write exceptions. */
if (!BLI_exists(filepath)) {
BLI_make_existing_file(filepath);
if (!BLI_file_touch(filepath)) {
@@ -4203,7 +4194,7 @@ static int sequencer_export_subtitles_exec(bContext *C, wmOperator *op)
BLI_listbase_sort(&text_seq, BKE_sequencer_cmp_time_startdisp);
- /* time to open and write! */
+ /* Open and write file. */
file = BLI_fopen(filepath, "w");
for (seq = text_seq.first; seq; seq = seq_next) {
@@ -4246,17 +4237,17 @@ static bool sequencer_strip_is_text_poll(bContext *C)
void SEQUENCER_OT_export_subtitles(struct wmOperatorType *ot)
{
- /* identifiers */
+ /* Identifiers. */
ot->name = "Export Subtitles";
ot->idname = "SEQUENCER_OT_export_subtitles";
ot->description = "Export .srt file containing text strips";
- /* api callbacks */
+ /* Api callbacks. */
ot->exec = sequencer_export_subtitles_exec;
ot->invoke = sequencer_export_subtitles_invoke;
ot->poll = sequencer_strip_is_text_poll;
- /* flags */
+ /* Flags. */
ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
WM_operator_properties_filesel(ot,
@@ -4268,6 +4259,7 @@ void SEQUENCER_OT_export_subtitles(struct wmOperatorType *ot)
FILE_SORT_ALPHA);
}
+/* Set range to strips operator. */
static int sequencer_set_range_to_strips_exec(bContext *C, wmOperator *op)
{
Scene *scene = CTX_data_scene(C);
@@ -4316,16 +4308,16 @@ void SEQUENCER_OT_set_range_to_strips(struct wmOperatorType *ot)
{
PropertyRNA *prop;
- /* identifiers */
+ /* Identifiers. */
ot->name = "Set Range to Strips";
ot->idname = "SEQUENCER_OT_set_range_to_strips";
ot->description = "Set the frame range to the selected strips start and end";
- /* api callbacks */
+ /* Api callbacks. */
ot->exec = sequencer_set_range_to_strips_exec;
ot->poll = sequencer_edit_poll;
- /* flags */
+ /* Flags. */
ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
prop = RNA_def_boolean(ot->srna, "preview", false, "Preview", "Set the preview range instead");
diff --git a/source/blender/editors/space_sequencer/sequencer_intern.h b/source/blender/editors/space_sequencer/sequencer_intern.h
index f70bc06caf7..0e7e691c748 100644
--- a/source/blender/editors/space_sequencer/sequencer_intern.h
+++ b/source/blender/editors/space_sequencer/sequencer_intern.h
@@ -27,7 +27,7 @@
#include "DNA_sequence_types.h"
#include "RNA_access.h"
-/* internal exports only */
+/* Internal exports only. */
struct ARegion;
struct ARegionType;
@@ -57,7 +57,7 @@ void sequencer_special_update_set(Sequence *seq);
float sequence_handle_size_get_clamped(struct Sequence *seq, const float pixelx);
/* UNUSED */
-// void seq_reset_imageofs(struct SpaceSeq *sseq);
+/* void seq_reset_imageofs(struct SpaceSeq *sseq); */
struct ImBuf *sequencer_ibuf_get(struct Main *bmain,
struct Depsgraph *depsgraph,
@@ -88,19 +88,19 @@ int seq_effect_find_selected(struct Scene *scene,
struct Sequence **r_selseq3,
const char **r_error_str);
-/* operator helpers */
+/* Operator helpers. */
bool sequencer_edit_poll(struct bContext *C);
/* UNUSED */
-// bool sequencer_strip_poll(struct bContext *C);
+/* bool sequencer_strip_poll(struct bContext *C); */
bool sequencer_strip_has_path_poll(struct bContext *C);
bool sequencer_view_preview_poll(struct bContext *C);
bool sequencer_view_strips_poll(struct bContext *C);
-/* externs */
+/* Externs. */
extern EnumPropertyItem sequencer_prop_effect_types[];
extern EnumPropertyItem prop_side_types[];
-/* operators */
+/* Operators. */
struct wmKeyConfig;
struct wmOperatorType;
@@ -152,7 +152,7 @@ void SEQUENCER_OT_export_subtitles(struct wmOperatorType *ot);
void SEQUENCER_OT_set_range_to_strips(struct wmOperatorType *ot);
-/* preview specific operators */
+/* Preview specific operators. */
void SEQUENCER_OT_view_all_preview(struct wmOperatorType *ot);
/* sequencer_select.c */
@@ -191,10 +191,11 @@ enum {
SEQ_SELECT_LR_MOUSE,
SEQ_SELECT_LR_LEFT,
SEQ_SELECT_LR_RIGHT,
+ SEQ_SELECT_LR_OVERLAP,
};
-/* defines used internally */
-#define SCE_MARKERS 0 // XXX - dummy
+/* Defines used internally. */
+#define SCE_MARKERS 0 /* XXX - dummy */
/* sequencer_ops.c */
void sequencer_operatortypes(void);
@@ -222,7 +223,7 @@ void SEQUENCER_OT_sample(struct wmOperatorType *ot);
/* sequencer_preview.c */
void sequencer_preview_add_sound(const struct bContext *C, struct Sequence *seq);
-/* sequencer_add */
+/* sequencer_add.c */
int sequencer_image_seq_get_minmax_frame(struct wmOperator *op,
int sfra,
int *r_minframe,
diff --git a/source/blender/editors/space_sequencer/sequencer_modifier.c b/source/blender/editors/space_sequencer/sequencer_modifier.c
index b90dc5e10ff..e0f7179c3f9 100644
--- a/source/blender/editors/space_sequencer/sequencer_modifier.c
+++ b/source/blender/editors/space_sequencer/sequencer_modifier.c
@@ -35,7 +35,7 @@
#include "RNA_define.h"
#include "RNA_enum_types.h"
-/* own include */
+/* Own include. */
#include "sequencer_intern.h"
/*********************** Add modifier operator *************************/
diff --git a/source/blender/editors/space_sequencer/sequencer_ops.c b/source/blender/editors/space_sequencer/sequencer_ops.c
index 4296701366a..ac00838a079 100644
--- a/source/blender/editors/space_sequencer/sequencer_ops.c
+++ b/source/blender/editors/space_sequencer/sequencer_ops.c
@@ -32,7 +32,7 @@
#include "ED_markers.h"
#include "ED_select_utils.h"
#include "ED_sequencer.h"
-#include "ED_transform.h" /* transform keymap */
+#include "ED_transform.h" /* Transform keymap. */
#include "BKE_sequencer.h"
diff --git a/source/blender/editors/space_sequencer/sequencer_preview.c b/source/blender/editors/space_sequencer/sequencer_preview.c
index 7c8a5ff5981..7d416884721 100644
--- a/source/blender/editors/space_sequencer/sequencer_preview.c
+++ b/source/blender/editors/space_sequencer/sequencer_preview.c
@@ -52,9 +52,9 @@ typedef struct PreviewJobAudio {
struct PreviewJobAudio *next, *prev;
struct Main *bmain;
bSound *sound;
- int lr; /* sample left or right */
+ int lr; /* Sample left or right. */
int startframe;
- bool waveform; /* reload sound or waveform */
+ bool waveform; /* Reload sound or waveform. */
} PreviewJobAudio;
static void free_preview_job(void *data)
@@ -66,7 +66,7 @@ static void free_preview_job(void *data)
MEM_freeN(pj);
}
-/* only this runs inside thread */
+/* Only this runs inside thread. */
static void preview_startjob(void *data, short *stop, short *do_update, float *progress)
{
PreviewJob *pj = data;
@@ -89,7 +89,7 @@ static void preview_startjob(void *data, short *stop, short *do_update, float *p
while (previewjb) {
sound = previewjb->sound;
- /* make sure we cleanup the loading flag! */
+ /* Make sure we cleanup the loading flag! */
BLI_spin_lock(sound->spinlock);
sound->tags &= ~SOUND_TAGS_WAVEFORM_LOADING;
BLI_spin_unlock(sound->spinlock);
@@ -127,10 +127,9 @@ static void preview_endjob(void *data)
void sequencer_preview_add_sound(const bContext *C, Sequence *seq)
{
- /* first, get the preview job, if it exists */
wmJob *wm_job;
PreviewJob *pj;
- ScrArea *sa = CTX_wm_area(C);
+ ScrArea *area = CTX_wm_area(C);
PreviewJobAudio *audiojob = MEM_callocN(sizeof(PreviewJobAudio), "preview_audio");
wm_job = WM_jobs_get(CTX_wm_manager(C),
CTX_wm_window(C),
@@ -139,6 +138,7 @@ void sequencer_preview_add_sound(const bContext *C, Sequence *seq)
WM_JOB_PROGRESS,
WM_JOB_TYPE_SEQ_BUILD_PREVIEW);
+ /* Get the preview job if it exists. */
pj = WM_jobs_customdata_get(wm_job);
if (!pj) {
@@ -152,8 +152,6 @@ void sequencer_preview_add_sound(const bContext *C, Sequence *seq)
WM_jobs_callbacks(wm_job, preview_startjob, NULL, NULL, preview_endjob);
}
- /* attempt to lock mutex of job here */
-
audiojob->bmain = CTX_data_main(C);
audiojob->sound = seq->sound;
@@ -167,5 +165,5 @@ void sequencer_preview_add_sound(const bContext *C, Sequence *seq)
WM_jobs_start(CTX_wm_manager(C), wm_job);
}
- ED_area_tag_redraw(sa);
+ ED_area_tag_redraw(area);
}
diff --git a/source/blender/editors/space_sequencer/sequencer_scopes.c b/source/blender/editors/space_sequencer/sequencer_scopes.c
index 309840ea9e3..243a6e193eb 100644
--- a/source/blender/editors/space_sequencer/sequencer_scopes.c
+++ b/source/blender/editors/space_sequencer/sequencer_scopes.c
@@ -42,7 +42,7 @@ static void rgb_to_yuv_normalized(const float rgb[3], float yuv[3])
yuv[1] = 0.492f * (rgb[2] - yuv[0]);
yuv[2] = 0.877f * (rgb[0] - yuv[0]);
- /* Normalize */
+ /* Normalize. */
yuv[1] *= 255.0f / (122 * 2.0f);
yuv[1] += 0.5f;
@@ -50,24 +50,24 @@ static void rgb_to_yuv_normalized(const float rgb[3], float yuv[3])
yuv[2] += 0.5f;
}
-static void scope_put_pixel(unsigned char *table, unsigned char *pos)
+static void scope_put_pixel(uchar *table, uchar *pos)
{
- unsigned char newval = table[*pos];
+ uchar newval = table[*pos];
pos[0] = pos[1] = pos[2] = newval;
pos[3] = 255;
}
-static void scope_put_pixel_single(unsigned char *table, unsigned char *pos, int col)
+static void scope_put_pixel_single(uchar *table, uchar *pos, int col)
{
char newval = table[pos[col]];
pos[col] = newval;
pos[3] = 255;
}
-static void wform_put_line(int w, unsigned char *last_pos, unsigned char *new_pos)
+static void wform_put_line(int w, uchar *last_pos, uchar *new_pos)
{
if (last_pos > new_pos) {
- unsigned char *temp = new_pos;
+ uchar *temp = new_pos;
new_pos = last_pos;
last_pos = temp;
}
@@ -81,10 +81,10 @@ static void wform_put_line(int w, unsigned char *last_pos, unsigned char *new_po
}
}
-static void wform_put_line_single(int w, unsigned char *last_pos, unsigned char *new_pos, int col)
+static void wform_put_line_single(int w, uchar *last_pos, uchar *new_pos, int col)
{
if (last_pos > new_pos) {
- unsigned char *temp = new_pos;
+ uchar *temp = new_pos;
new_pos = last_pos;
last_pos = temp;
}
@@ -98,12 +98,12 @@ static void wform_put_line_single(int w, unsigned char *last_pos, unsigned char
}
}
-static void wform_put_border(unsigned char *tgt, int w, int h)
+static void wform_put_border(uchar *tgt, int w, int h)
{
int x, y;
for (x = 0; x < w; x++) {
- unsigned char *p = tgt + 4 * x;
+ uchar *p = tgt + 4 * x;
p[1] = p[3] = 155;
p[4 * w + 1] = p[4 * w + 3] = 155;
p = tgt + 4 * (w * (h - 1) + x);
@@ -112,7 +112,7 @@ static void wform_put_border(unsigned char *tgt, int w, int h)
}
for (y = 0; y < h; y++) {
- unsigned char *p = tgt + 4 * w * y;
+ uchar *p = tgt + 4 * w * y;
p[1] = p[3] = 155;
p[4 + 1] = p[4 + 3] = 155;
p = tgt + 4 * (w * y + w - 1);
@@ -121,7 +121,7 @@ static void wform_put_border(unsigned char *tgt, int w, int h)
}
}
-static void wform_put_gridrow(unsigned char *tgt, float perc, int w, int h)
+static void wform_put_gridrow(uchar *tgt, float perc, int w, int h)
{
int i;
@@ -134,7 +134,7 @@ static void wform_put_gridrow(unsigned char *tgt, float perc, int w, int h)
}
}
-static void wform_put_grid(unsigned char *tgt, int w, int h)
+static void wform_put_grid(uchar *tgt, int w, int h)
{
wform_put_gridrow(tgt, 90.0, w, h);
wform_put_gridrow(tgt, 70.0, w, h);
@@ -145,27 +145,27 @@ static ImBuf *make_waveform_view_from_ibuf_byte(ImBuf *ibuf)
{
ImBuf *rval = IMB_allocImBuf(ibuf->x + 3, 515, 32, IB_rect);
int x, y;
- const unsigned char *src = (unsigned char *)ibuf->rect;
- unsigned char *tgt = (unsigned char *)rval->rect;
+ const uchar *src = (uchar *)ibuf->rect;
+ uchar *tgt = (uchar *)rval->rect;
int w = ibuf->x + 3;
int h = 515;
float waveform_gamma = 0.2;
- unsigned char wtable[256];
+ uchar wtable[256];
wform_put_grid(tgt, w, h);
wform_put_border(tgt, w, h);
for (x = 0; x < 256; x++) {
- wtable[x] = (unsigned char)(pow(((float)x + 1) / 256, waveform_gamma) * 255);
+ wtable[x] = (uchar)(pow(((float)x + 1) / 256, waveform_gamma) * 255);
}
for (y = 0; y < ibuf->y; y++) {
- unsigned char *last_p = NULL;
+ uchar *last_p = NULL;
for (x = 0; x < ibuf->x; x++) {
- const unsigned char *rgb = src + 4 * (ibuf->x * y + x);
+ const uchar *rgb = src + 4 * (ibuf->x * y + x);
float v = (float)IMB_colormanagement_get_luminance_byte(rgb) / 255.0f;
- unsigned char *p = tgt;
+ uchar *p = tgt;
p += 4 * (w * ((int)(v * (h - 3)) + 1) + x + 1);
scope_put_pixel(wtable, p);
@@ -187,25 +187,25 @@ static ImBuf *make_waveform_view_from_ibuf_float(ImBuf *ibuf)
ImBuf *rval = IMB_allocImBuf(ibuf->x + 3, 515, 32, IB_rect);
int x, y;
const float *src = ibuf->rect_float;
- unsigned char *tgt = (unsigned char *)rval->rect;
+ uchar *tgt = (uchar *)rval->rect;
int w = ibuf->x + 3;
int h = 515;
float waveform_gamma = 0.2;
- unsigned char wtable[256];
+ uchar wtable[256];
wform_put_grid(tgt, w, h);
for (x = 0; x < 256; x++) {
- wtable[x] = (unsigned char)(pow(((float)x + 1) / 256, waveform_gamma) * 255);
+ wtable[x] = (uchar)(pow(((float)x + 1) / 256, waveform_gamma) * 255);
}
for (y = 0; y < ibuf->y; y++) {
- unsigned char *last_p = NULL;
+ uchar *last_p = NULL;
for (x = 0; x < ibuf->x; x++) {
const float *rgb = src + 4 * (ibuf->x * y + x);
float v = IMB_colormanagement_get_luminance(rgb);
- unsigned char *p = tgt;
+ uchar *p = tgt;
CLAMP(v, 0.0f, 1.0f);
@@ -241,28 +241,28 @@ static ImBuf *make_sep_waveform_view_from_ibuf_byte(ImBuf *ibuf)
{
ImBuf *rval = IMB_allocImBuf(ibuf->x + 3, 515, 32, IB_rect);
int x, y;
- const unsigned char *src = (const unsigned char *)ibuf->rect;
- unsigned char *tgt = (unsigned char *)rval->rect;
+ const uchar *src = (const uchar *)ibuf->rect;
+ uchar *tgt = (uchar *)rval->rect;
int w = ibuf->x + 3;
int sw = ibuf->x / 3;
int h = 515;
float waveform_gamma = 0.2;
- unsigned char wtable[256];
+ uchar wtable[256];
wform_put_grid(tgt, w, h);
for (x = 0; x < 256; x++) {
- wtable[x] = (unsigned char)(pow(((float)x + 1) / 256, waveform_gamma) * 255);
+ wtable[x] = (uchar)(pow(((float)x + 1) / 256, waveform_gamma) * 255);
}
for (y = 0; y < ibuf->y; y++) {
- unsigned char *last_p[3] = {NULL, NULL, NULL};
+ uchar *last_p[3] = {NULL, NULL, NULL};
for (x = 0; x < ibuf->x; x++) {
int c;
- const unsigned char *rgb = src + 4 * (ibuf->x * y + x);
+ const uchar *rgb = src + 4 * (ibuf->x * y + x);
for (c = 0; c < 3; c++) {
- unsigned char *p = tgt;
+ uchar *p = tgt;
p += 4 * (w * ((rgb[c] * (h - 3)) / 255 + 1) + c * sw + x / 3 + 1);
scope_put_pixel_single(wtable, p, c);
@@ -287,27 +287,27 @@ static ImBuf *make_sep_waveform_view_from_ibuf_float(ImBuf *ibuf)
ImBuf *rval = IMB_allocImBuf(ibuf->x + 3, 515, 32, IB_rect);
int x, y;
const float *src = ibuf->rect_float;
- unsigned char *tgt = (unsigned char *)rval->rect;
+ uchar *tgt = (uchar *)rval->rect;
int w = ibuf->x + 3;
int sw = ibuf->x / 3;
int h = 515;
float waveform_gamma = 0.2;
- unsigned char wtable[256];
+ uchar wtable[256];
wform_put_grid(tgt, w, h);
for (x = 0; x < 256; x++) {
- wtable[x] = (unsigned char)(pow(((float)x + 1) / 256, waveform_gamma) * 255);
+ wtable[x] = (uchar)(pow(((float)x + 1) / 256, waveform_gamma) * 255);
}
for (y = 0; y < ibuf->y; y++) {
- unsigned char *last_p[3] = {NULL, NULL, NULL};
+ uchar *last_p[3] = {NULL, NULL, NULL};
for (x = 0; x < ibuf->x; x++) {
int c;
const float *rgb = src + 4 * (ibuf->x * y + x);
for (c = 0; c < 3; c++) {
- unsigned char *p = tgt;
+ uchar *p = tgt;
float v = rgb[c];
CLAMP(v, 0.0f, 1.0f);
@@ -343,18 +343,18 @@ ImBuf *make_sep_waveform_view_from_ibuf(ImBuf *ibuf)
static void draw_zebra_byte(ImBuf *src, ImBuf *ibuf, float perc)
{
- unsigned int limit = 255.0f * perc / 100.0f;
- unsigned char *p = (unsigned char *)src->rect;
- unsigned char *o = (unsigned char *)ibuf->rect;
+ uint limit = 255.0f * perc / 100.0f;
+ uchar *p = (uchar *)src->rect;
+ uchar *o = (uchar *)ibuf->rect;
int x;
int y;
for (y = 0; y < ibuf->y; y++) {
for (x = 0; x < ibuf->x; x++) {
- unsigned char r = *p++;
- unsigned char g = *p++;
- unsigned char b = *p++;
- unsigned char a = *p++;
+ uchar r = *p++;
+ uchar g = *p++;
+ uchar b = *p++;
+ uchar a = *p++;
if (r >= limit || g >= limit || b >= limit) {
if (((x + y) & 0x08) != 0) {
@@ -375,7 +375,7 @@ static void draw_zebra_float(ImBuf *src, ImBuf *ibuf, float perc)
{
float limit = perc / 100.0f;
const float *p = src->rect_float;
- unsigned char *o = (unsigned char *)ibuf->rect;
+ uchar *o = (uchar *)ibuf->rect;
int x;
int y;
@@ -417,7 +417,7 @@ ImBuf *make_zebra_view_from_ibuf(ImBuf *src, float perc)
static void draw_histogram_marker(ImBuf *ibuf, int x)
{
- unsigned char *p = (unsigned char *)ibuf->rect;
+ uchar *p = (uchar *)ibuf->rect;
int barh = ibuf->y * 0.1;
int i;
@@ -431,7 +431,7 @@ static void draw_histogram_marker(ImBuf *ibuf, int x)
static void draw_histogram_bar(ImBuf *ibuf, int x, float val, int col)
{
- unsigned char *p = (unsigned char *)ibuf->rect;
+ uchar *p = (uchar *)ibuf->rect;
int barh = ibuf->y * val * 0.9f;
int i;
@@ -447,21 +447,20 @@ static void draw_histogram_bar(ImBuf *ibuf, int x, float val, int col)
typedef struct MakeHistogramViewData {
const ImBuf *ibuf;
- uint32_t (*bins)[HIS_STEPS];
} MakeHistogramViewData;
-static void make_histogram_view_from_ibuf_byte_cb_ex(void *__restrict userdata,
- const int y,
- const TaskParallelTLS *__restrict tls)
+static void make_histogram_view_from_ibuf_byte_fn(void *__restrict userdata,
+ const int y,
+ const TaskParallelTLS *__restrict tls)
{
MakeHistogramViewData *data = userdata;
const ImBuf *ibuf = data->ibuf;
- const unsigned char *src = (unsigned char *)ibuf->rect;
+ const uchar *src = (uchar *)ibuf->rect;
uint32_t(*cur_bins)[HIS_STEPS] = tls->userdata_chunk;
for (int x = 0; x < ibuf->x; x++) {
- const unsigned char *pixel = src + (y * ibuf->x + x) * 4;
+ const uchar *pixel = src + (y * ibuf->x + x) * 4;
for (int j = 3; j--;) {
cur_bins[j][pixel[j]]++;
@@ -469,17 +468,16 @@ static void make_histogram_view_from_ibuf_byte_cb_ex(void *__restrict userdata,
}
}
-static void make_histogram_view_from_ibuf_finalize(void *__restrict userdata,
- void *__restrict userdata_chunk)
+static void make_histogram_view_from_ibuf_reduce(const void *__restrict UNUSED(userdata),
+ void *__restrict chunk_join,
+ void *__restrict chunk)
{
- MakeHistogramViewData *data = userdata;
- uint32_t(*bins)[HIS_STEPS] = data->bins;
-
- uint32_t(*cur_bins)[HIS_STEPS] = userdata_chunk;
+ uint32_t(*join_bins)[HIS_STEPS] = chunk_join;
+ uint32_t(*bins)[HIS_STEPS] = chunk;
for (int j = 3; j--;) {
for (int i = 0; i < HIS_STEPS; i++) {
- bins[j][i] += cur_bins[j][i];
+ join_bins[j][i] += bins[j][i];
}
}
}
@@ -488,23 +486,22 @@ static ImBuf *make_histogram_view_from_ibuf_byte(ImBuf *ibuf)
{
ImBuf *rval = IMB_allocImBuf(515, 128, 32, IB_rect);
int x;
- unsigned int nr, ng, nb;
+ uint nr, ng, nb;
- unsigned int bins[3][HIS_STEPS];
+ uint bins[3][HIS_STEPS];
memset(bins, 0, sizeof(bins));
MakeHistogramViewData data = {
.ibuf = ibuf,
- .bins = bins,
};
TaskParallelSettings settings;
BLI_parallel_range_settings_defaults(&settings);
settings.use_threading = (ibuf->y >= 256);
settings.userdata_chunk = bins;
settings.userdata_chunk_size = sizeof(bins);
- settings.func_finalize = make_histogram_view_from_ibuf_finalize;
- BLI_task_parallel_range(0, ibuf->y, &data, make_histogram_view_from_ibuf_byte_cb_ex, &settings);
+ settings.func_reduce = make_histogram_view_from_ibuf_reduce;
+ BLI_task_parallel_range(0, ibuf->y, &data, make_histogram_view_from_ibuf_byte_fn, &settings);
nr = nb = ng = 0;
for (x = 0; x < HIS_STEPS; x++) {
@@ -534,7 +531,7 @@ static ImBuf *make_histogram_view_from_ibuf_byte(ImBuf *ibuf)
}
}
- wform_put_border((unsigned char *)rval->rect, rval->x, rval->y);
+ wform_put_border((uchar *)rval->rect, rval->x, rval->y);
return rval;
}
@@ -551,9 +548,9 @@ BLI_INLINE int get_bin_float(float f)
return (int)(((f + 0.25f) / 1.5f) * 512);
}
-static void make_histogram_view_from_ibuf_float_cb_ex(void *__restrict userdata,
- const int y,
- const TaskParallelTLS *__restrict tls)
+static void make_histogram_view_from_ibuf_float_fn(void *__restrict userdata,
+ const int y,
+ const TaskParallelTLS *__restrict tls)
{
const MakeHistogramViewData *data = userdata;
const ImBuf *ibuf = data->ibuf;
@@ -576,21 +573,20 @@ static ImBuf *make_histogram_view_from_ibuf_float(ImBuf *ibuf)
int nr, ng, nb;
int x;
- unsigned int bins[3][HIS_STEPS];
+ uint bins[3][HIS_STEPS];
memset(bins, 0, sizeof(bins));
MakeHistogramViewData data = {
.ibuf = ibuf,
- .bins = bins,
};
TaskParallelSettings settings;
BLI_parallel_range_settings_defaults(&settings);
settings.use_threading = (ibuf->y >= 256);
settings.userdata_chunk = bins;
settings.userdata_chunk_size = sizeof(bins);
- settings.func_finalize = make_histogram_view_from_ibuf_finalize;
- BLI_task_parallel_range(0, ibuf->y, &data, make_histogram_view_from_ibuf_float_cb_ex, &settings);
+ settings.func_reduce = make_histogram_view_from_ibuf_reduce;
+ BLI_task_parallel_range(0, ibuf->y, &data, make_histogram_view_from_ibuf_float_fn, &settings);
nr = nb = ng = 0;
for (x = 0; x < HIS_STEPS; x++) {
@@ -619,7 +615,7 @@ static ImBuf *make_histogram_view_from_ibuf_float(ImBuf *ibuf)
draw_histogram_marker(rval, get_bin_float(0.0));
draw_histogram_marker(rval, get_bin_float(1.0));
- wform_put_border((unsigned char *)rval->rect, rval->x, rval->y);
+ wform_put_border((uchar *)rval->rect, rval->x, rval->y);
return rval;
}
@@ -636,8 +632,7 @@ ImBuf *make_histogram_view_from_ibuf(ImBuf *ibuf)
}
}
-static void vectorscope_put_cross(
- unsigned char r, unsigned char g, unsigned char b, char *tgt, int w, int h, int size)
+static void vectorscope_put_cross(uchar r, uchar g, uchar b, char *tgt, int w, int h, int size)
{
float rgb[3], yuv[3];
char *p;
@@ -676,10 +671,10 @@ static ImBuf *make_vectorscope_view_from_ibuf_byte(ImBuf *ibuf)
int w = 515;
int h = 515;
float scope_gamma = 0.2;
- unsigned char wtable[256];
+ uchar wtable[256];
for (x = 0; x < 256; x++) {
- wtable[x] = (unsigned char)(pow(((float)x + 1) / 256, scope_gamma) * 255);
+ wtable[x] = (uchar)(pow(((float)x + 1) / 256, scope_gamma) * 255);
}
for (x = 0; x < 256; x++) {
@@ -702,7 +697,7 @@ static ImBuf *make_vectorscope_view_from_ibuf_byte(ImBuf *ibuf)
rgb_to_yuv_normalized(rgb, yuv);
p = tgt + 4 * (w * (int)((yuv[2] * (h - 3) + 1)) + (int)((yuv[1] * (w - 3) + 1)));
- scope_put_pixel(wtable, (unsigned char *)p);
+ scope_put_pixel(wtable, (uchar *)p);
}
}
@@ -721,10 +716,10 @@ static ImBuf *make_vectorscope_view_from_ibuf_float(ImBuf *ibuf)
int w = 515;
int h = 515;
float scope_gamma = 0.2;
- unsigned char wtable[256];
+ uchar wtable[256];
for (x = 0; x < 256; x++) {
- wtable[x] = (unsigned char)(pow(((float)x + 1) / 256, scope_gamma) * 255);
+ wtable[x] = (uchar)(pow(((float)x + 1) / 256, scope_gamma) * 255);
}
for (x = 0; x <= 255; x++) {
@@ -748,7 +743,7 @@ static ImBuf *make_vectorscope_view_from_ibuf_float(ImBuf *ibuf)
rgb_to_yuv_normalized(rgb, yuv);
p = tgt + 4 * (w * (int)((yuv[2] * (h - 3) + 1)) + (int)((yuv[1] * (w - 3) + 1)));
- scope_put_pixel(wtable, (unsigned char *)p);
+ scope_put_pixel(wtable, (uchar *)p);
}
}
diff --git a/source/blender/editors/space_sequencer/sequencer_select.c b/source/blender/editors/space_sequencer/sequencer_select.c
index ccb18331c55..2e6cd7f7442 100644
--- a/source/blender/editors/space_sequencer/sequencer_select.c
+++ b/source/blender/editors/space_sequencer/sequencer_select.c
@@ -40,7 +40,7 @@
#include "RNA_define.h"
-/* for menu/popup icons etc etc*/
+/* For menu, popup, icons, etc. */
#include "ED_outliner.h"
#include "ED_screen.h"
@@ -49,7 +49,7 @@
#include "UI_view2d.h"
-/* own include */
+/* Own include. */
#include "sequencer_intern.h"
static void *find_nearest_marker(int UNUSED(d1), int UNUSED(d2))
@@ -147,7 +147,7 @@ static void select_active_side_range(ListBase *seqbase,
}
}
-/* used for mouse selection in SEQUENCER_OT_select */
+/* Used for mouse selection in SEQUENCER_OT_select */
static void select_linked_time(ListBase *seqbase, Sequence *seq_link)
{
Sequence *seq;
@@ -158,7 +158,7 @@ static void select_linked_time(ListBase *seqbase, Sequence *seq_link)
int right_match = (seq->enddisp == seq_link->enddisp) ? 1 : 0;
if (left_match && right_match) {
- /* a direct match, copy the selection settinhs */
+ /* Direct match, copy the selection settings. */
seq->flag &= ~(SELECT | SEQ_LEFTSEL | SEQ_RIGHTSEL);
seq->flag |= seq_link->flag & (SELECT | SEQ_LEFTSEL | SEQ_RIGHTSEL);
@@ -166,7 +166,7 @@ static void select_linked_time(ListBase *seqbase, Sequence *seq_link)
}
else if (seq_link->flag & SELECT && (left_match || right_match)) {
- /* clear for reselection */
+ /* Clear for reselection. */
seq->flag &= ~(SEQ_LEFTSEL | SEQ_RIGHTSEL);
if (left_match && seq_link->flag & SEQ_LEFTSEL) {
@@ -248,12 +248,11 @@ static void select_neighbor_from_last(Scene *scene, int lr)
}
}
if (changed) {
- /* pass */
+ /* Pass. */
}
}
#endif
-/* (de)select operator */
static int sequencer_de_select_all_exec(bContext *C, wmOperator *op)
{
int action = RNA_enum_get(op->ptr, "action");
@@ -302,22 +301,21 @@ static int sequencer_de_select_all_exec(bContext *C, wmOperator *op)
void SEQUENCER_OT_select_all(struct wmOperatorType *ot)
{
- /* identifiers */
+ /* Identifiers. */
ot->name = "(De)select All";
ot->idname = "SEQUENCER_OT_select_all";
ot->description = "Select or deselect all strips";
- /* api callbacks */
+ /* Api callbacks. */
ot->exec = sequencer_de_select_all_exec;
ot->poll = sequencer_edit_poll;
- /* flags */
+ /* Flags. */
ot->flag = OPTYPE_UNDO;
WM_operator_properties_select_all(ot);
}
-/* (de)select operator */
static int sequencer_select_inverse_exec(bContext *C, wmOperator *UNUSED(op))
{
Scene *scene = CTX_data_scene(C);
@@ -343,16 +341,16 @@ static int sequencer_select_inverse_exec(bContext *C, wmOperator *UNUSED(op))
void SEQUENCER_OT_select_inverse(struct wmOperatorType *ot)
{
- /* identifiers */
+ /* Identifiers. */
ot->name = "Select Inverse";
ot->idname = "SEQUENCER_OT_select_inverse";
ot->description = "Select unselected strips";
- /* api callbacks */
+ /* Api callbacks. */
ot->exec = sequencer_select_inverse_exec;
ot->poll = sequencer_edit_poll;
- /* flags */
+ /* Flags. */
ot->flag = OPTYPE_UNDO;
}
@@ -385,18 +383,18 @@ static int sequencer_select_exec(bContext *C, wmOperator *op)
wait_to_deselect_others = false;
}
- marker = find_nearest_marker(SCE_MARKERS, 1); // XXX - dummy function for now
+ marker = find_nearest_marker(SCE_MARKERS, 1); /* XXX - dummy function for now */
seq = find_nearest_seq(scene, v2d, &hand, mval);
- // XXX - not nice, Ctrl+RMB needs to do left_right only when not over a strip
+ /* XXX - not nice, Ctrl+RMB needs to do left_right only when not over a strip */
if (seq && linked_time && (left_right == SEQ_SELECT_LR_MOUSE)) {
left_right = SEQ_SELECT_LR_NONE;
}
if (marker) {
int oldflag;
- /* select timeline marker */
+ /* Select timeline marker. */
if (extend) {
oldflag = marker->flag;
if (oldflag & SELECT) {
@@ -414,28 +412,44 @@ static int sequencer_select_exec(bContext *C, wmOperator *op)
ret_value = OPERATOR_FINISHED;
}
+ /* Select left, right or overlapping the current frame. */
else if (left_right != SEQ_SELECT_LR_NONE) {
- /* use different logic for this */
+ /* Use different logic for this. */
float x;
if (extend == false) {
ED_sequencer_deselect_all(scene);
}
switch (left_right) {
- case SEQ_SELECT_LR_MOUSE:
+ case SEQ_SELECT_LR_MOUSE: {
+ /* 10px margin around current frame to select under the current frame with mouse. */
+ float margin = BLI_rctf_size_x(&v2d->cur) / BLI_rcti_size_x(&v2d->mask) * 10;
x = UI_view2d_region_to_view_x(v2d, mval[0]);
+ if (x >= CFRA - margin && x <= CFRA + margin) {
+ x = CFRA;
+ }
break;
+ }
case SEQ_SELECT_LR_LEFT:
x = CFRA - 1.0f;
break;
case SEQ_SELECT_LR_RIGHT:
+ x = CFRA + 1.0f;
+ break;
+ case SEQ_SELECT_LR_OVERLAP:
default:
x = CFRA;
break;
}
SEQP_BEGIN (ed, seq) {
- if (((x < CFRA) && (seq->enddisp <= CFRA)) || ((x >= CFRA) && (seq->startdisp >= CFRA))) {
+ /* Select overlapping the current frame. */
+ if ((x == CFRA) && (seq->startdisp <= CFRA) && (seq->enddisp >= CFRA)) {
+ seq->flag = SELECT;
+ recurs_sel_seq(seq);
+ }
+ /* Select left or right. */
+ else if ((x < CFRA && seq->enddisp <= CFRA) || (x > CFRA && seq->startdisp >= CFRA)) {
seq->flag |= SELECT;
recurs_sel_seq(seq);
}
@@ -494,7 +508,7 @@ static int sequencer_select_exec(bContext *C, wmOperator *op)
}
}
- /* On Alt selection, select the strip and bordering handles */
+ /* On Alt selection, select the strip and bordering handles. */
if (linked_handle) {
if (!ELEM(hand, SEQ_SIDE_LEFT, SEQ_SIDE_RIGHT)) {
/* First click selects the strip and its adjacent handles (if valid).
@@ -510,7 +524,7 @@ static int sequencer_select_exec(bContext *C, wmOperator *op)
select_surrounding_handles(scene, seq);
}
else {
- /* always select the strip under the cursor */
+ /* Always select the strip under the cursor. */
seq->flag |= SELECT;
/* First click selects adjacent handles on that side.
@@ -629,27 +643,28 @@ void SEQUENCER_OT_select(wmOperatorType *ot)
static const EnumPropertyItem sequencer_select_left_right_types[] = {
{SEQ_SELECT_LR_NONE, "NONE", 0, "None", "Don't do left-right selection"},
{SEQ_SELECT_LR_MOUSE, "MOUSE", 0, "Mouse", "Use mouse position for selection"},
- {SEQ_SELECT_LR_LEFT, "LEFT", 0, "Left", "Select left"},
- {SEQ_SELECT_LR_RIGHT, "RIGHT", 0, "Right", "Select right"},
+ {SEQ_SELECT_LR_LEFT, "LEFT", 0, "Left", "Select to the left of the current frame"},
+ {SEQ_SELECT_LR_RIGHT, "RIGHT", 0, "Right", "Select to the right of the current frame"},
+ {SEQ_SELECT_LR_OVERLAP, "OVERLAP", 0, "Overlap", "Select overlapping the current frame"},
{0, NULL, 0, NULL, NULL},
};
PropertyRNA *prop;
- /* identifiers */
+ /* Identifiers. */
ot->name = "Select";
ot->idname = "SEQUENCER_OT_select";
ot->description = "Select a strip (last selected becomes the \"active strip\")";
- /* api callbacks */
+ /* Api callbacks. */
ot->exec = sequencer_select_exec;
ot->invoke = WM_generic_select_invoke;
ot->modal = WM_generic_select_modal;
ot->poll = ED_operator_sequencer_active;
- /* flags */
+ /* Flags. */
ot->flag = OPTYPE_UNDO;
- /* properties */
+ /* Properties. */
WM_operator_properties_generic_select(ot);
RNA_def_boolean(ot->srna, "extend", 0, "Extend", "Extend the selection");
prop = RNA_def_boolean(ot->srna,
@@ -660,7 +675,7 @@ void SEQUENCER_OT_select(wmOperatorType *ot)
RNA_def_property_flag(prop, PROP_SKIP_SAVE);
RNA_def_boolean(
ot->srna, "linked_handle", 0, "Linked Handle", "Select handles next to the active strip");
- /* for animation this is an enum but atm having an enum isn't useful for us */
+ /* For animation this is enum but atm having an enum isn't useful for us. */
RNA_def_enum(ot->srna,
"left_right",
sequencer_select_left_right_types,
@@ -671,7 +686,7 @@ void SEQUENCER_OT_select(wmOperatorType *ot)
ot->srna, "linked_time", 0, "Linked Time", "Select other strips at the same time");
}
-/* run recursively to select linked */
+/* Run recursively to select linked. */
static bool select_more_less_seq__internal(Scene *scene, bool sel, const bool linked)
{
Editing *ed = BKE_sequencer_editing_get(scene, false);
@@ -693,7 +708,7 @@ static bool select_more_less_seq__internal(Scene *scene, bool sel, const bool li
}
if (!linked) {
- /* if not linked we only want to touch each seq once, newseq */
+ /* If not linked we only want to touch each seq once, newseq. */
for (seq = ed->seqbasep->first; seq; seq = seq->next) {
seq->tmp = NULL;
}
@@ -702,7 +717,7 @@ static bool select_more_less_seq__internal(Scene *scene, bool sel, const bool li
for (seq = ed->seqbasep->first; seq; seq = seq->next) {
if ((seq->flag & SELECT) == sel) {
if (linked || (seq->tmp == NULL)) {
- /* only get unselected neighbors */
+ /* Only get unselected neighbors. */
neighbor = find_neighboring_sequence(scene, seq, SEQ_SIDE_LEFT, isel);
if (neighbor) {
if (sel) {
@@ -738,7 +753,6 @@ static bool select_more_less_seq__internal(Scene *scene, bool sel, const bool li
return changed;
}
-/* select more operator */
static int sequencer_select_more_exec(bContext *C, wmOperator *UNUSED(op))
{
Scene *scene = CTX_data_scene(C);
@@ -756,22 +770,19 @@ static int sequencer_select_more_exec(bContext *C, wmOperator *UNUSED(op))
void SEQUENCER_OT_select_more(wmOperatorType *ot)
{
- /* identifiers */
+ /* Identifiers. */
ot->name = "Select More";
ot->idname = "SEQUENCER_OT_select_more";
ot->description = "Select more strips adjacent to the current selection";
- /* api callbacks */
+ /* Api callbacks. */
ot->exec = sequencer_select_more_exec;
ot->poll = sequencer_edit_poll;
- /* flags */
+ /* Flags. */
ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
-
- /* properties */
}
-/* select less operator */
static int sequencer_select_less_exec(bContext *C, wmOperator *UNUSED(op))
{
Scene *scene = CTX_data_scene(C);
@@ -789,22 +800,19 @@ static int sequencer_select_less_exec(bContext *C, wmOperator *UNUSED(op))
void SEQUENCER_OT_select_less(wmOperatorType *ot)
{
- /* identifiers */
+ /* Identifiers. */
ot->name = "Select Less";
ot->idname = "SEQUENCER_OT_select_less";
ot->description = "Shrink the current selection of adjacent selected strips";
- /* api callbacks */
+ /* Api callbacks. */
ot->exec = sequencer_select_less_exec;
ot->poll = sequencer_edit_poll;
- /* flags */
+ /* Flags. */
ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
-
- /* properties */
}
-/* select pick linked operator (uses the mouse) */
static int sequencer_select_linked_pick_invoke(bContext *C, wmOperator *op, const wmEvent *event)
{
Scene *scene = CTX_data_scene(C);
@@ -815,10 +823,10 @@ static int sequencer_select_linked_pick_invoke(bContext *C, wmOperator *op, cons
Sequence *mouse_seq;
int selected, hand;
- /* this works like UV, not mesh */
+ /* This works like UV, not mesh. */
mouse_seq = find_nearest_seq(scene, v2d, &hand, event->mval);
if (!mouse_seq) {
- return OPERATOR_FINISHED; /* user error as with mesh?? */
+ return OPERATOR_FINISHED; /* User error as with mesh?? */
}
if (extend == 0) {
@@ -842,23 +850,22 @@ static int sequencer_select_linked_pick_invoke(bContext *C, wmOperator *op, cons
void SEQUENCER_OT_select_linked_pick(wmOperatorType *ot)
{
- /* identifiers */
+ /* Identifiers. */
ot->name = "Select Pick Linked";
ot->idname = "SEQUENCER_OT_select_linked_pick";
ot->description = "Select a chain of linked strips nearest to the mouse pointer";
- /* api callbacks */
+ /* Api callbacks. */
ot->invoke = sequencer_select_linked_pick_invoke;
ot->poll = ED_operator_sequencer_active;
- /* flags */
+ /* Flags. */
ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
- /* properties */
+ /* Properties. */
RNA_def_boolean(ot->srna, "extend", 0, "Extend", "Extend the selection");
}
-/* select linked operator */
static int sequencer_select_linked_exec(bContext *C, wmOperator *UNUSED(op))
{
Scene *scene = CTX_data_scene(C);
@@ -878,22 +885,19 @@ static int sequencer_select_linked_exec(bContext *C, wmOperator *UNUSED(op))
void SEQUENCER_OT_select_linked(wmOperatorType *ot)
{
- /* identifiers */
+ /* Identifiers. */
ot->name = "Select Linked";
ot->idname = "SEQUENCER_OT_select_linked";
ot->description = "Select all strips adjacent to the current selection";
- /* api callbacks */
+ /* Api callbacks. */
ot->exec = sequencer_select_linked_exec;
ot->poll = sequencer_edit_poll;
- /* flags */
+ /* Flags. */
ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
-
- /* properties */
}
-/* select handles operator */
static int sequencer_select_handles_exec(bContext *C, wmOperator *op)
{
Scene *scene = CTX_data_scene(C);
@@ -928,19 +932,19 @@ static int sequencer_select_handles_exec(bContext *C, wmOperator *op)
void SEQUENCER_OT_select_handles(wmOperatorType *ot)
{
- /* identifiers */
+ /* Identifiers. */
ot->name = "Select Handles";
ot->idname = "SEQUENCER_OT_select_handles";
ot->description = "Select gizmo handles on the sides of the selected strip";
- /* api callbacks */
+ /* Api callbacks. */
ot->exec = sequencer_select_handles_exec;
ot->poll = sequencer_edit_poll;
- /* flags */
+ /* Flags. */
ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
- /* properties */
+ /* Properties. */
RNA_def_enum(ot->srna,
"side",
prop_side_types,
@@ -949,7 +953,6 @@ void SEQUENCER_OT_select_handles(wmOperatorType *ot)
"The side of the handle that is selected");
}
-/* select side operator */
static int sequencer_select_side_exec(bContext *C, wmOperator *op)
{
Scene *scene = CTX_data_scene(C);
@@ -962,7 +965,7 @@ static int sequencer_select_side_exec(bContext *C, wmOperator *op)
copy_vn_i(frame_ranges, ARRAY_SIZE(frame_ranges), frame_init);
- for (Sequence *seq = ed->seqbasep->first; seq; seq = seq->next) {
+ LISTBASE_FOREACH (Sequence *, seq, ed->seqbasep) {
if (UNLIKELY(seq->machine >= MAXSEQ)) {
continue;
}
@@ -993,19 +996,19 @@ static int sequencer_select_side_exec(bContext *C, wmOperator *op)
void SEQUENCER_OT_select_side(wmOperatorType *ot)
{
- /* identifiers */
+ /* Identifiers. */
ot->name = "Select Side";
ot->idname = "SEQUENCER_OT_select_side";
ot->description = "Select strips on the nominated side of the selected strips";
- /* api callbacks */
+ /* Api callbacks. */
ot->exec = sequencer_select_side_exec;
ot->poll = sequencer_edit_poll;
- /* flags */
+ /* Flags. */
ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
- /* properties */
+ /* Properties. */
RNA_def_enum(ot->srna,
"side",
prop_side_types,
@@ -1014,7 +1017,6 @@ void SEQUENCER_OT_select_side(wmOperatorType *ot)
"The side to which the selection is applied");
}
-/* box_select operator */
static int sequencer_box_select_exec(bContext *C, wmOperator *op)
{
Scene *scene = CTX_data_scene(C);
@@ -1037,7 +1039,7 @@ static int sequencer_box_select_exec(bContext *C, wmOperator *op)
WM_operator_properties_border_to_rctf(op, &rectf);
UI_view2d_region_to_view_rctf(v2d, &rectf, &rectf);
- for (Sequence *seq = ed->seqbasep->first; seq; seq = seq->next) {
+ LISTBASE_FOREACH (Sequence *, seq, ed->seqbasep) {
rctf rq;
seq_rectf(seq, &rq);
if (BLI_rctf_isect(&rq, &rectf, NULL)) {
@@ -1089,7 +1091,6 @@ static int sequencer_box_select_exec(bContext *C, wmOperator *op)
return OPERATOR_FINISHED;
}
-/* ****** Box Select ****** */
static int sequencer_box_select_invoke(bContext *C, wmOperator *op, const wmEvent *event)
{
Scene *scene = CTX_data_scene(C);
@@ -1112,12 +1113,12 @@ void SEQUENCER_OT_select_box(wmOperatorType *ot)
{
PropertyRNA *prop;
- /* identifiers */
+ /* Identifiers. */
ot->name = "Box Select";
ot->idname = "SEQUENCER_OT_select_box";
ot->description = "Select strips using box selection";
- /* api callbacks */
+ /* Api callbacks. */
ot->invoke = sequencer_box_select_invoke;
ot->exec = sequencer_box_select_exec;
ot->modal = WM_gesture_box_modal;
@@ -1125,10 +1126,10 @@ void SEQUENCER_OT_select_box(wmOperatorType *ot)
ot->poll = ED_operator_sequencer_active;
- /* flags */
+ /* Flags. */
ot->flag = OPTYPE_UNDO;
- /* properties */
+ /* Properties. */
WM_operator_properties_gesture_box(ot);
WM_operator_properties_select_operation_simple(ot);
@@ -1140,8 +1141,6 @@ void SEQUENCER_OT_select_box(wmOperatorType *ot)
RNA_def_property_flag(prop, PROP_SKIP_SAVE);
}
-/* ****** Selected Grouped ****** */
-
enum {
SEQ_SELECT_GROUP_TYPE,
SEQ_SELECT_GROUP_TYPE_BASIC,
@@ -1366,7 +1365,7 @@ static bool select_grouped_effect_link(Editing *ed, Sequence *actseq, const int
BKE_sequence_iterator_next(&iter)) {
seq = iter.seq;
- /* Ignore all seqs already selected! */
+ /* Ignore all seqs already selected. */
/* Ignore all seqs not sharing some time with active one. */
/* Ignore all seqs of incompatible types (audio vs video). */
if (!SEQ_CHANNEL_CHECK(seq, channel) || (seq->flag & SELECT) || (seq->startdisp >= enddisp) ||
@@ -1375,7 +1374,7 @@ static bool select_grouped_effect_link(Editing *ed, Sequence *actseq, const int
continue;
}
- /* If the seq is an effect one, we need extra checking! */
+ /* If the seq is an effect one, we need extra checking. */
if (SEQ_IS_EFFECT(seq) && ((seq->seq1 && seq->seq1->tmp) || (seq->seq2 && seq->seq2->tmp) ||
(seq->seq3 && seq->seq3->tmp))) {
if (startdisp > seq->startdisp) {
@@ -1398,7 +1397,7 @@ static bool select_grouped_effect_link(Editing *ed, Sequence *actseq, const int
BKE_sequence_iterator_begin(ed, &iter, true);
}
- /* Video strips below active one, or any strip for audio (order do no matters here!). */
+ /* Video strips below active one, or any strip for audio (order doesn't matter here). */
else if (seq->machine < machine || is_audio) {
seq->flag |= SELECT;
changed = true;
@@ -1476,20 +1475,20 @@ static int sequencer_select_grouped_exec(bContext *C, wmOperator *op)
void SEQUENCER_OT_select_grouped(wmOperatorType *ot)
{
- /* identifiers */
+ /* Identifiers. */
ot->name = "Select Grouped";
ot->description = "Select all strips grouped by various properties";
ot->idname = "SEQUENCER_OT_select_grouped";
- /* api callbacks */
+ /* Api callbacks. */
ot->invoke = WM_menu_invoke;
ot->exec = sequencer_select_grouped_exec;
ot->poll = sequencer_edit_poll;
- /* flags */
+ /* Flags. */
ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
- /* properties */
+ /* Properties. */
ot->prop = RNA_def_enum(ot->srna, "type", sequencer_prop_select_grouped_types, 0, "Type", "");
RNA_def_boolean(ot->srna,
"extend",
diff --git a/source/blender/editors/space_sequencer/sequencer_view.c b/source/blender/editors/space_sequencer/sequencer_view.c
index 714a634766c..d397c255b03 100644
--- a/source/blender/editors/space_sequencer/sequencer_view.c
+++ b/source/blender/editors/space_sequencer/sequencer_view.c
@@ -21,232 +21,35 @@
* \ingroup spseq
*/
-#include "MEM_guardedalloc.h"
+#include "ED_util_imbuf.h"
-#include "BLI_math.h"
-#include "BLI_utildefines.h"
+#include "RNA_define.h"
-#include "DNA_scene_types.h"
-
-#include "BKE_context.h"
-#include "BKE_main.h"
-#include "BKE_screen.h"
-#include "BKE_sequencer.h"
-
-#include "WM_api.h"
#include "WM_types.h"
-#include "ED_image.h"
-#include "ED_screen.h"
-#include "ED_space_api.h"
-
-#include "IMB_colormanagement.h"
-#include "IMB_imbuf.h"
-#include "IMB_imbuf_types.h"
-
-#include "UI_view2d.h"
-
-/* own include */
+/* Own include. */
#include "sequencer_intern.h"
/******************** sample backdrop operator ********************/
-
-typedef struct ImageSampleInfo {
- ARegionType *art;
- void *draw_handle;
- int x, y;
- int channels;
-
- unsigned char col[4];
- float colf[4];
- float linearcol[4];
-
- unsigned char *colp;
- const float *colfp;
-
- int draw;
- int color_manage;
-} ImageSampleInfo;
-
-static void sample_draw(const bContext *C, ARegion *region, void *arg_info)
-{
- Scene *scene = CTX_data_scene(C);
- ImageSampleInfo *info = arg_info;
-
- if (info->draw) {
- ED_image_draw_info(scene,
- region,
- info->color_manage,
- false,
- info->channels,
- info->x,
- info->y,
- info->colp,
- info->colfp,
- info->linearcol,
- NULL,
- NULL);
- }
-}
-
-static void sample_apply(bContext *C, wmOperator *op, const wmEvent *event)
-{
- Main *bmain = CTX_data_main(C);
- struct Depsgraph *depsgraph = CTX_data_ensure_evaluated_depsgraph(C);
- Scene *scene = CTX_data_scene(C);
- SpaceSeq *sseq = (SpaceSeq *)CTX_wm_space_data(C);
- ARegion *region = CTX_wm_region(C);
- ImBuf *ibuf = sequencer_ibuf_get(bmain, depsgraph, scene, sseq, CFRA, 0, NULL);
- ImageSampleInfo *info = op->customdata;
- float fx, fy;
-
- if (ibuf == NULL) {
- IMB_freeImBuf(ibuf);
- info->draw = 0;
- return;
- }
-
- UI_view2d_region_to_view(&region->v2d, event->mval[0], event->mval[1], &fx, &fy);
-
- fx /= scene->r.xasp / scene->r.yasp;
-
- fx += (float)scene->r.xsch / 2.0f;
- fy += (float)scene->r.ysch / 2.0f;
- fx *= (float)ibuf->x / (float)scene->r.xsch;
- fy *= (float)ibuf->y / (float)scene->r.ysch;
-
- if (fx >= 0.0f && fy >= 0.0f && fx < ibuf->x && fy < ibuf->y) {
- const float *fp;
- unsigned char *cp;
- int x = (int)fx, y = (int)fy;
-
- info->x = x;
- info->y = y;
- info->draw = 1;
- info->channels = ibuf->channels;
-
- info->colp = NULL;
- info->colfp = NULL;
-
- if (ibuf->rect) {
- cp = (unsigned char *)(ibuf->rect + y * ibuf->x + x);
-
- info->col[0] = cp[0];
- info->col[1] = cp[1];
- info->col[2] = cp[2];
- info->col[3] = cp[3];
- info->colp = info->col;
-
- info->colf[0] = (float)cp[0] / 255.0f;
- info->colf[1] = (float)cp[1] / 255.0f;
- info->colf[2] = (float)cp[2] / 255.0f;
- info->colf[3] = (float)cp[3] / 255.0f;
- info->colfp = info->colf;
-
- copy_v4_v4(info->linearcol, info->colf);
- IMB_colormanagement_colorspace_to_scene_linear_v4(
- info->linearcol, false, ibuf->rect_colorspace);
-
- info->color_manage = true;
- }
- if (ibuf->rect_float) {
- fp = (ibuf->rect_float + (ibuf->channels) * (y * ibuf->x + x));
-
- info->colf[0] = fp[0];
- info->colf[1] = fp[1];
- info->colf[2] = fp[2];
- info->colf[3] = fp[3];
- info->colfp = info->colf;
-
- /* sequencer's image buffers are in non-linear space, need to make them linear */
- copy_v4_v4(info->linearcol, info->colf);
- BKE_sequencer_pixel_from_sequencer_space_v4(scene, info->linearcol);
-
- info->color_manage = true;
- }
- }
- else {
- info->draw = 0;
- }
-
- IMB_freeImBuf(ibuf);
- ED_area_tag_redraw(CTX_wm_area(C));
-}
-
-static void sample_exit(bContext *C, wmOperator *op)
-{
- ImageSampleInfo *info = op->customdata;
-
- ED_region_draw_cb_exit(info->art, info->draw_handle);
- ED_area_tag_redraw(CTX_wm_area(C));
- MEM_freeN(info);
-}
-
-static int sample_invoke(bContext *C, wmOperator *op, const wmEvent *event)
-{
- ARegion *region = CTX_wm_region(C);
- SpaceSeq *sseq = CTX_wm_space_seq(C);
- ImageSampleInfo *info;
-
- if (sseq->mainb != SEQ_DRAW_IMG_IMBUF) {
- return OPERATOR_CANCELLED;
- }
-
- info = MEM_callocN(sizeof(ImageSampleInfo), "ImageSampleInfo");
- info->art = region->type;
- info->draw_handle = ED_region_draw_cb_activate(
- region->type, sample_draw, info, REGION_DRAW_POST_PIXEL);
- op->customdata = info;
-
- sample_apply(C, op, event);
-
- WM_event_add_modal_handler(C, op);
-
- return OPERATOR_RUNNING_MODAL;
-}
-
-static int sample_modal(bContext *C, wmOperator *op, const wmEvent *event)
-{
- switch (event->type) {
- case LEFTMOUSE:
- case RIGHTMOUSE: /* XXX hardcoded */
- if (event->val == KM_RELEASE) {
- sample_exit(C, op);
- return OPERATOR_CANCELLED;
- }
- break;
- case MOUSEMOVE:
- sample_apply(C, op, event);
- break;
- }
-
- return OPERATOR_RUNNING_MODAL;
-}
-
-static void sample_cancel(bContext *C, wmOperator *op)
-{
- sample_exit(C, op);
-}
-
-static bool sample_poll(bContext *C)
-{
- SpaceSeq *sseq = CTX_wm_space_seq(C);
- return sseq && BKE_sequencer_editing_get(CTX_data_scene(C), false) != NULL;
-}
-
void SEQUENCER_OT_sample(wmOperatorType *ot)
{
- /* identifiers */
+ /* Identifiers. */
ot->name = "Sample Color";
ot->idname = "SEQUENCER_OT_sample";
ot->description = "Use mouse to sample color in current frame";
- /* api callbacks */
- ot->invoke = sample_invoke;
- ot->modal = sample_modal;
- ot->cancel = sample_cancel;
- ot->poll = sample_poll;
+ /* Api callbacks. */
+ ot->invoke = ED_imbuf_sample_invoke;
+ ot->modal = ED_imbuf_sample_modal;
+ ot->cancel = ED_imbuf_sample_cancel;
+ ot->poll = ED_imbuf_sample_poll;
- /* flags */
+ /* Flags. */
ot->flag = OPTYPE_BLOCKING;
+
+ /* Not implemented. */
+ PropertyRNA *prop;
+ prop = RNA_def_int(ot->srna, "size", 1, 1, 128, "Sample Size", "", 1, 64);
+ RNA_def_property_subtype(prop, PROP_PIXEL);
+ RNA_def_property_flag(prop, PROP_SKIP_SAVE | PROP_HIDDEN);
}
diff --git a/source/blender/editors/space_sequencer/space_sequencer.c b/source/blender/editors/space_sequencer/space_sequencer.c
index cff5a2c43ec..03871aeb464 100644
--- a/source/blender/editors/space_sequencer/space_sequencer.c
+++ b/source/blender/editors/space_sequencer/space_sequencer.c
@@ -43,7 +43,7 @@
#include "ED_screen.h"
#include "ED_space_api.h"
#include "ED_view3d.h"
-#include "ED_view3d_offscreen.h" /* only for sequencer view3d drawing callback */
+#include "ED_view3d_offscreen.h" /* Only for sequencer view3d drawing callback. */
#include "WM_api.h"
#include "WM_message.h"
@@ -57,24 +57,25 @@
#include "IMB_imbuf.h"
-#include "sequencer_intern.h" // own include
+/* Own include. */
+#include "sequencer_intern.h"
/**************************** common state *****************************/
-static void sequencer_scopes_tag_refresh(ScrArea *sa)
+static void sequencer_scopes_tag_refresh(ScrArea *area)
{
- SpaceSeq *sseq = (SpaceSeq *)sa->spacedata.first;
+ SpaceSeq *sseq = (SpaceSeq *)area->spacedata.first;
sseq->scopes.reference_ibuf = NULL;
}
/* ******************** manage regions ********************* */
-static ARegion *sequencer_find_region(ScrArea *sa, short type)
+static ARegion *sequencer_find_region(ScrArea *area, short type)
{
ARegion *region = NULL;
- for (region = sa->regionbase.first; region; region = region->next) {
+ for (region = area->regionbase.first; region; region = region->next) {
if (region->regiontype == type) {
return region;
}
@@ -85,7 +86,7 @@ static ARegion *sequencer_find_region(ScrArea *sa, short type)
/* ******************** default callbacks for sequencer space ***************** */
-static SpaceLink *sequencer_new(const ScrArea *UNUSED(sa), const Scene *scene)
+static SpaceLink *sequencer_new(const ScrArea *UNUSED(area), const Scene *scene)
{
ARegion *region;
SpaceSeq *sseq;
@@ -95,9 +96,9 @@ static SpaceLink *sequencer_new(const ScrArea *UNUSED(sa), const Scene *scene)
sseq->chanshown = 0;
sseq->view = SEQ_VIEW_SEQUENCE;
sseq->mainb = SEQ_DRAW_IMG_IMBUF;
- sseq->flag = SEQ_SHOW_GPENCIL | SEQ_USE_ALPHA | SEQ_SHOW_MARKERS;
+ sseq->flag = SEQ_SHOW_GPENCIL | SEQ_USE_ALPHA | SEQ_SHOW_MARKERS | SEQ_SHOW_FCURVES;
- /* tool header */
+ /* Tool header. */
region = MEM_callocN(sizeof(ARegion), "tool header for sequencer");
BLI_addtail(&sseq->regionbase, region);
@@ -105,14 +106,14 @@ static SpaceLink *sequencer_new(const ScrArea *UNUSED(sa), const Scene *scene)
region->alignment = (U.uiflag & USER_HEADER_BOTTOM) ? RGN_ALIGN_BOTTOM : RGN_ALIGN_TOP;
region->flag = RGN_FLAG_HIDDEN | RGN_FLAG_HIDDEN_BY_USER;
- /* header */
+ /* Header. */
region = MEM_callocN(sizeof(ARegion), "header for sequencer");
BLI_addtail(&sseq->regionbase, region);
region->regiontype = RGN_TYPE_HEADER;
region->alignment = (U.uiflag & USER_HEADER_BOTTOM) ? RGN_ALIGN_BOTTOM : RGN_ALIGN_TOP;
- /* buttons/list view */
+ /* Buttons/list view. */
region = MEM_callocN(sizeof(ARegion), "buttons for sequencer");
BLI_addtail(&sseq->regionbase, region);
@@ -120,7 +121,7 @@ static SpaceLink *sequencer_new(const ScrArea *UNUSED(sa), const Scene *scene)
region->alignment = RGN_ALIGN_RIGHT;
region->flag = RGN_FLAG_HIDDEN;
- /* toolbar */
+ /* Toolbar. */
region = MEM_callocN(sizeof(ARegion), "tools for sequencer");
BLI_addtail(&sseq->regionbase, region);
@@ -128,19 +129,19 @@ static SpaceLink *sequencer_new(const ScrArea *UNUSED(sa), const Scene *scene)
region->alignment = RGN_ALIGN_LEFT;
region->flag = RGN_FLAG_HIDDEN;
- /* preview region */
- /* NOTE: if you change values here, also change them in sequencer_init_preview_region */
+ /* Preview region. */
+ /* NOTE: if you change values here, also change them in sequencer_init_preview_region. */
region = MEM_callocN(sizeof(ARegion), "preview region for sequencer");
BLI_addtail(&sseq->regionbase, region);
region->regiontype = RGN_TYPE_PREVIEW;
region->alignment = RGN_ALIGN_TOP;
region->flag |= RGN_FLAG_HIDDEN;
- /* for now, aspect ratio should be maintained, and zoom is clamped within sane default limits */
+ /* For now, aspect ratio should be maintained, and zoom is clamped within sane default limits. */
region->v2d.keepzoom = V2D_KEEPASPECT | V2D_KEEPZOOM | V2D_LIMITZOOM;
region->v2d.minzoom = 0.001f;
region->v2d.maxzoom = 1000.0f;
- region->v2d.tot.xmin = -960.0f; /* 1920 width centered */
- region->v2d.tot.ymin = -540.0f; /* 1080 height centered */
+ region->v2d.tot.xmin = -960.0f; /* 1920 width centered. */
+ region->v2d.tot.ymin = -540.0f; /* 1080 height centered. */
region->v2d.tot.xmax = 960.0f;
region->v2d.tot.ymax = 540.0f;
region->v2d.min[0] = 0.0f;
@@ -151,14 +152,13 @@ static SpaceLink *sequencer_new(const ScrArea *UNUSED(sa), const Scene *scene)
region->v2d.align = V2D_ALIGN_FREE;
region->v2d.keeptot = V2D_KEEPTOT_FREE;
- /* main region */
+ /* Main region. */
region = MEM_callocN(sizeof(ARegion), "main region for sequencer");
BLI_addtail(&sseq->regionbase, region);
region->regiontype = RGN_TYPE_WINDOW;
- /* seq space goes from (0,8) to (0, efra) */
-
+ /* Seq space goes from (0,8) to (0, efra). */
region->v2d.tot.xmin = 0.0f;
region->v2d.tot.ymin = 0.0f;
region->v2d.tot.xmax = scene->r.efra;
@@ -184,13 +184,13 @@ static SpaceLink *sequencer_new(const ScrArea *UNUSED(sa), const Scene *scene)
return (SpaceLink *)sseq;
}
-/* not spacelink itself */
+/* Not spacelink itself. */
static void sequencer_free(SpaceLink *sl)
{
SpaceSeq *sseq = (SpaceSeq *)sl;
SequencerScopes *scopes = &sseq->scopes;
- // XXX if (sseq->gpd) BKE_gpencil_free(sseq->gpd);
+ /* XXX if (sseq->gpd) BKE_gpencil_free(sseq->gpd); */
if (scopes->zebra_ibuf) {
IMB_freeImBuf(scopes->zebra_ibuf);
@@ -213,98 +213,98 @@ static void sequencer_free(SpaceLink *sl)
}
}
-/* spacetype; init callback */
-static void sequencer_init(struct wmWindowManager *UNUSED(wm), ScrArea *UNUSED(sa))
+/* Spacetype init callback. */
+static void sequencer_init(struct wmWindowManager *UNUSED(wm), ScrArea *UNUSED(area))
{
}
-static void sequencer_refresh(const bContext *C, ScrArea *sa)
+static void sequencer_refresh(const bContext *C, ScrArea *area)
{
wmWindowManager *wm = CTX_wm_manager(C);
wmWindow *window = CTX_wm_window(C);
- SpaceSeq *sseq = (SpaceSeq *)sa->spacedata.first;
- ARegion *ar_main = sequencer_find_region(sa, RGN_TYPE_WINDOW);
- ARegion *ar_preview = sequencer_find_region(sa, RGN_TYPE_PREVIEW);
+ SpaceSeq *sseq = (SpaceSeq *)area->spacedata.first;
+ ARegion *region_main = sequencer_find_region(area, RGN_TYPE_WINDOW);
+ ARegion *region_preview = sequencer_find_region(area, RGN_TYPE_PREVIEW);
bool view_changed = false;
switch (sseq->view) {
case SEQ_VIEW_SEQUENCE:
- if (ar_main && (ar_main->flag & RGN_FLAG_HIDDEN)) {
- ar_main->flag &= ~RGN_FLAG_HIDDEN;
- ar_main->v2d.flag &= ~V2D_IS_INITIALISED;
+ if (region_main && (region_main->flag & RGN_FLAG_HIDDEN)) {
+ region_main->flag &= ~RGN_FLAG_HIDDEN;
+ region_main->v2d.flag &= ~V2D_IS_INITIALISED;
view_changed = true;
}
- if (ar_preview && !(ar_preview->flag & RGN_FLAG_HIDDEN)) {
- ar_preview->flag |= RGN_FLAG_HIDDEN;
- ar_preview->v2d.flag &= ~V2D_IS_INITIALISED;
- WM_event_remove_handlers((bContext *)C, &ar_preview->handlers);
+ if (region_preview && !(region_preview->flag & RGN_FLAG_HIDDEN)) {
+ region_preview->flag |= RGN_FLAG_HIDDEN;
+ region_preview->v2d.flag &= ~V2D_IS_INITIALISED;
+ WM_event_remove_handlers((bContext *)C, &region_preview->handlers);
view_changed = true;
}
- if (ar_main && ar_main->alignment != RGN_ALIGN_NONE) {
- ar_main->alignment = RGN_ALIGN_NONE;
+ if (region_main && region_main->alignment != RGN_ALIGN_NONE) {
+ region_main->alignment = RGN_ALIGN_NONE;
view_changed = true;
}
- if (ar_preview && ar_preview->alignment != RGN_ALIGN_NONE) {
- ar_preview->alignment = RGN_ALIGN_NONE;
+ if (region_preview && region_preview->alignment != RGN_ALIGN_NONE) {
+ region_preview->alignment = RGN_ALIGN_NONE;
view_changed = true;
}
break;
case SEQ_VIEW_PREVIEW:
- if (ar_main && !(ar_main->flag & RGN_FLAG_HIDDEN)) {
- ar_main->flag |= RGN_FLAG_HIDDEN;
- ar_main->v2d.flag &= ~V2D_IS_INITIALISED;
- WM_event_remove_handlers((bContext *)C, &ar_main->handlers);
+ if (region_main && !(region_main->flag & RGN_FLAG_HIDDEN)) {
+ region_main->flag |= RGN_FLAG_HIDDEN;
+ region_main->v2d.flag &= ~V2D_IS_INITIALISED;
+ WM_event_remove_handlers((bContext *)C, &region_main->handlers);
view_changed = true;
}
- if (ar_preview && (ar_preview->flag & RGN_FLAG_HIDDEN)) {
- ar_preview->flag &= ~RGN_FLAG_HIDDEN;
- ar_preview->v2d.flag &= ~V2D_IS_INITIALISED;
- ar_preview->v2d.cur = ar_preview->v2d.tot;
+ if (region_preview && (region_preview->flag & RGN_FLAG_HIDDEN)) {
+ region_preview->flag &= ~RGN_FLAG_HIDDEN;
+ region_preview->v2d.flag &= ~V2D_IS_INITIALISED;
+ region_preview->v2d.cur = region_preview->v2d.tot;
view_changed = true;
}
- if (ar_main && ar_main->alignment != RGN_ALIGN_NONE) {
- ar_main->alignment = RGN_ALIGN_NONE;
+ if (region_main && region_main->alignment != RGN_ALIGN_NONE) {
+ region_main->alignment = RGN_ALIGN_NONE;
view_changed = true;
}
- if (ar_preview && ar_preview->alignment != RGN_ALIGN_NONE) {
- ar_preview->alignment = RGN_ALIGN_NONE;
+ if (region_preview && region_preview->alignment != RGN_ALIGN_NONE) {
+ region_preview->alignment = RGN_ALIGN_NONE;
view_changed = true;
}
break;
case SEQ_VIEW_SEQUENCE_PREVIEW:
- if (ar_main && ar_preview) {
+ if (region_main && region_preview) {
/* Get available height (without DPI correction). */
- const float height = (sa->winy - ED_area_headersize()) / UI_DPI_FAC;
+ const float height = (area->winy - ED_area_headersize()) / UI_DPI_FAC;
/* We reuse hidden region's size, allows to find same layout as before if we just switch
* between one 'full window' view and the combined one. This gets lost if we switch to both
* 'full window' views before, though... Better than nothing. */
- if (ar_main->flag & RGN_FLAG_HIDDEN) {
- ar_main->flag &= ~RGN_FLAG_HIDDEN;
- ar_main->v2d.flag &= ~V2D_IS_INITIALISED;
- ar_preview->sizey = (int)(height - ar_main->sizey);
+ if (region_main->flag & RGN_FLAG_HIDDEN) {
+ region_main->flag &= ~RGN_FLAG_HIDDEN;
+ region_main->v2d.flag &= ~V2D_IS_INITIALISED;
+ region_preview->sizey = (int)(height - region_main->sizey);
view_changed = true;
}
- if (ar_preview->flag & RGN_FLAG_HIDDEN) {
- ar_preview->flag &= ~RGN_FLAG_HIDDEN;
- ar_preview->v2d.flag &= ~V2D_IS_INITIALISED;
- ar_preview->v2d.cur = ar_preview->v2d.tot;
- ar_main->sizey = (int)(height - ar_preview->sizey);
+ if (region_preview->flag & RGN_FLAG_HIDDEN) {
+ region_preview->flag &= ~RGN_FLAG_HIDDEN;
+ region_preview->v2d.flag &= ~V2D_IS_INITIALISED;
+ region_preview->v2d.cur = region_preview->v2d.tot;
+ region_main->sizey = (int)(height - region_preview->sizey);
view_changed = true;
}
- if (ar_main->alignment != RGN_ALIGN_NONE) {
- ar_main->alignment = RGN_ALIGN_NONE;
+ if (region_main->alignment != RGN_ALIGN_NONE) {
+ region_main->alignment = RGN_ALIGN_NONE;
view_changed = true;
}
- if (ar_preview->alignment != RGN_ALIGN_TOP) {
- ar_preview->alignment = RGN_ALIGN_TOP;
+ if (region_preview->alignment != RGN_ALIGN_TOP) {
+ region_preview->alignment = RGN_ALIGN_TOP;
view_changed = true;
}
- /* Final check that both preview and main height are reasonable! */
- if (ar_preview->sizey < 10 || ar_main->sizey < 10 ||
- ar_preview->sizey + ar_main->sizey > height) {
- ar_preview->sizey = (int)(height * 0.4f + 0.5f);
- ar_main->sizey = (int)(height - ar_preview->sizey);
+ /* Final check that both preview and main height are reasonable. */
+ if (region_preview->sizey < 10 || region_main->sizey < 10 ||
+ region_preview->sizey + region_main->sizey > height) {
+ region_preview->sizey = (int)(height * 0.4f + 0.5f);
+ region_main->sizey = (int)(height - region_preview->sizey);
view_changed = true;
}
}
@@ -312,8 +312,8 @@ static void sequencer_refresh(const bContext *C, ScrArea *sa)
}
if (view_changed) {
- ED_area_initialize(wm, window, sa);
- ED_area_tag_redraw(sa);
+ ED_area_initialize(wm, window, area);
+ ED_area_tag_redraw(area);
}
}
@@ -321,8 +321,8 @@ static SpaceLink *sequencer_duplicate(SpaceLink *sl)
{
SpaceSeq *sseqn = MEM_dupallocN(sl);
- /* clear or remove stuff from old */
- // XXX sseq->gpd = gpencil_data_duplicate(sseq->gpd, false);
+ /* Clear or remove stuff from old. */
+ /* XXX sseq->gpd = gpencil_data_duplicate(sseq->gpd, false); */
memset(&sseqn->scopes, 0, sizeof(sseqn->scopes));
@@ -330,36 +330,36 @@ static SpaceLink *sequencer_duplicate(SpaceLink *sl)
}
static void sequencer_listener(wmWindow *UNUSED(win),
- ScrArea *sa,
+ ScrArea *area,
wmNotifier *wmn,
Scene *UNUSED(scene))
{
- /* context changes */
+ /* Context changes. */
switch (wmn->category) {
case NC_SCENE:
switch (wmn->data) {
case ND_FRAME:
case ND_SEQUENCER:
- sequencer_scopes_tag_refresh(sa);
+ sequencer_scopes_tag_refresh(area);
break;
}
break;
case NC_WINDOW:
case NC_SPACE:
if (wmn->data == ND_SPACE_SEQUENCER) {
- sequencer_scopes_tag_refresh(sa);
+ sequencer_scopes_tag_refresh(area);
}
break;
case NC_GPENCIL:
if (wmn->data & ND_GPENCIL_EDITMODE) {
- ED_area_tag_redraw(sa);
+ ED_area_tag_redraw(area);
}
break;
}
}
/* DO NOT make this static, this hides the symbol and breaks API generation script. */
-extern const char *sequencer_context_dir[]; /* quiet warning. */
+extern const char *sequencer_context_dir[]; /* Quiet warning. */
const char *sequencer_context_dir[] = {"edit_mask", NULL};
static int sequencer_context(const bContext *C, const char *member, bContextDataResult *result)
@@ -396,7 +396,7 @@ static void sequencer_gizmos(void)
}
/* *********************** sequencer (main) region ************************ */
-/* add handlers, stuff you only do once or on area/region changes */
+/* Add handlers, stuff you only do once or on area/region changes. */
static void sequencer_main_region_init(wmWindowManager *wm, ARegion *region)
{
wmKeyMap *keymap;
@@ -411,31 +411,31 @@ static void sequencer_main_region_init(wmWindowManager *wm, ARegion *region)
keymap = WM_keymap_ensure(wm->defaultconf, "SequencerCommon", SPACE_SEQ, 0);
WM_event_add_keymap_handler_v2d_mask(&region->handlers, keymap);
- /* own keymap */
+ /* Own keymap. */
keymap = WM_keymap_ensure(wm->defaultconf, "Sequencer", SPACE_SEQ, 0);
WM_event_add_keymap_handler_v2d_mask(&region->handlers, keymap);
}
+/* Strip editing timeline. */
static void sequencer_main_region_draw(const bContext *C, ARegion *region)
{
- /* NLE - strip editing timeline interface */
draw_timeline_seq(C, region);
}
static void sequencer_main_region_listener(wmWindow *UNUSED(win),
- ScrArea *UNUSED(sa),
+ ScrArea *UNUSED(area),
ARegion *region,
wmNotifier *wmn,
const Scene *UNUSED(scene))
{
- /* context changes */
+ /* Context changes. */
switch (wmn->category) {
case NC_SCENE:
switch (wmn->data) {
case ND_FRAME:
case ND_FRAME_RANGE:
case ND_MARKERS:
- case ND_RENDER_OPTIONS: /* for FPS and FPS Base */
+ case ND_RENDER_OPTIONS: /* For FPS and FPS Base. */
case ND_SEQUENCER:
case ND_RENDER_RESULT:
ED_region_tag_redraw(region);
@@ -471,7 +471,7 @@ static void sequencer_main_region_message_subscribe(const struct bContext *UNUSE
struct WorkSpace *UNUSED(workspace),
struct Scene *scene,
struct bScreen *UNUSED(screen),
- struct ScrArea *UNUSED(sa),
+ struct ScrArea *UNUSED(area),
struct ARegion *region,
struct wmMsgBus *mbus)
{
@@ -526,7 +526,7 @@ static void sequencer_main_region_message_subscribe(const struct bContext *UNUSE
}
/* *********************** header region ************************ */
-/* add handlers, stuff you only do once or on area/region changes */
+/* Add handlers, stuff you only do once or on area/region changes. */
static void sequencer_header_region_init(wmWindowManager *UNUSED(wm), ARegion *region)
{
ED_region_header_init(region);
@@ -538,7 +538,7 @@ static void sequencer_header_region_draw(const bContext *C, ARegion *region)
}
/* *********************** toolbar region ************************ */
-/* add handlers, stuff you only do once or on area/region changes */
+/* Add handlers, stuff you only do once or on area/region changes. */
static void sequencer_tools_region_init(wmWindowManager *wm, ARegion *region)
{
wmKeyMap *keymap;
@@ -569,15 +569,15 @@ static void sequencer_preview_region_init(wmWindowManager *wm, ARegion *region)
keymap = WM_keymap_ensure(wm->defaultconf, "SequencerCommon", SPACE_SEQ, 0);
WM_event_add_keymap_handler_v2d_mask(&region->handlers, keymap);
- /* own keymap */
+ /* Own keymap. */
keymap = WM_keymap_ensure(wm->defaultconf, "SequencerPreview", SPACE_SEQ, 0);
WM_event_add_keymap_handler_v2d_mask(&region->handlers, keymap);
}
static void sequencer_preview_region_draw(const bContext *C, ARegion *region)
{
- ScrArea *sa = CTX_wm_area(C);
- SpaceSeq *sseq = sa->spacedata.first;
+ ScrArea *area = CTX_wm_area(C);
+ SpaceSeq *sseq = area->spacedata.first;
Scene *scene = CTX_data_scene(C);
wmWindowManager *wm = CTX_wm_manager(C);
const bool draw_overlay = (scene->ed && (scene->ed->over_flag & SEQ_EDIT_OVERLAY_SHOW));
@@ -618,12 +618,12 @@ static void sequencer_preview_region_draw(const bContext *C, ARegion *region)
}
static void sequencer_preview_region_listener(wmWindow *UNUSED(win),
- ScrArea *UNUSED(sa),
+ ScrArea *UNUSED(area),
ARegion *region,
wmNotifier *wmn,
const Scene *UNUSED(scene))
{
- /* context changes */
+ /* Context changes. */
switch (wmn->category) {
case NC_GPENCIL:
if (ELEM(wmn->action, NA_EDITED, NA_SELECTED)) {
@@ -670,7 +670,7 @@ static void sequencer_preview_region_listener(wmWindow *UNUSED(win),
/* *********************** buttons region ************************ */
-/* add handlers, stuff you only do once or on area/region changes */
+/* Add handlers, stuff you only do once or on area/region changes. */
static void sequencer_buttons_region_init(wmWindowManager *wm, ARegion *region)
{
wmKeyMap *keymap;
@@ -688,12 +688,12 @@ static void sequencer_buttons_region_draw(const bContext *C, ARegion *region)
}
static void sequencer_buttons_region_listener(wmWindow *UNUSED(win),
- ScrArea *UNUSED(sa),
+ ScrArea *UNUSED(area),
ARegion *region,
wmNotifier *wmn,
const Scene *UNUSED(scene))
{
- /* context changes */
+ /* Context changes. */
switch (wmn->category) {
case NC_GPENCIL:
if (ELEM(wmn->action, NA_EDITED, NA_SELECTED)) {
@@ -721,7 +721,7 @@ static void sequencer_buttons_region_listener(wmWindow *UNUSED(win),
}
}
-static void sequencer_id_remap(ScrArea *UNUSED(sa), SpaceLink *slink, ID *old_id, ID *new_id)
+static void sequencer_id_remap(ScrArea *UNUSED(area), SpaceLink *slink, ID *old_id, ID *new_id)
{
SpaceSeq *sseq = (SpaceSeq *)slink;
@@ -793,7 +793,7 @@ static void sequencer_drop_target_find(bContext *C,
/* ************************************* */
-/* only called once, from space/spacetypes.c */
+/* Only called once, from space/spacetypes.c. */
void ED_spacetype_sequencer(void)
{
SpaceType *st = MEM_callocN(sizeof(SpaceType), "spacetype sequencer");
@@ -815,7 +815,8 @@ void ED_spacetype_sequencer(void)
st->id_remap = sequencer_id_remap;
st->drop_target_find = sequencer_drop_target_find;
- /* regions: main window */
+ /* Create regions: */
+ /* Main window. */
art = MEM_callocN(sizeof(ARegionType), "spacetype sequencer region");
art->regionid = RGN_TYPE_WINDOW;
art->init = sequencer_main_region_init;
@@ -823,10 +824,9 @@ void ED_spacetype_sequencer(void)
art->listener = sequencer_main_region_listener;
art->message_subscribe = sequencer_main_region_message_subscribe;
art->keymapflag = ED_KEYMAP_TOOL | ED_KEYMAP_VIEW2D | ED_KEYMAP_FRAMES | ED_KEYMAP_ANIMATION;
-
BLI_addhead(&st->regiontypes, art);
- /* preview */
+ /* Preview. */
art = MEM_callocN(sizeof(ARegionType), "spacetype sequencer region");
art->regionid = RGN_TYPE_PREVIEW;
art->init = sequencer_preview_region_init;
@@ -836,7 +836,7 @@ void ED_spacetype_sequencer(void)
ED_KEYMAP_GPENCIL;
BLI_addhead(&st->regiontypes, art);
- /* regions: listview/buttons */
+ /* Listview/buttons. */
art = MEM_callocN(sizeof(ARegionType), "spacetype sequencer region");
art->regionid = RGN_TYPE_UI;
art->prefsizex = UI_SIDEBAR_PANEL_WIDTH * 1.3f;
@@ -848,7 +848,7 @@ void ED_spacetype_sequencer(void)
BLI_addhead(&st->regiontypes, art);
sequencer_buttons_register(art);
- /* regions: tool(bar) */
+ /* Toolbar. */
art = MEM_callocN(sizeof(ARegionType), "spacetype sequencer tools region");
art->regionid = RGN_TYPE_TOOLS;
art->prefsizex = 58; /* XXX */
@@ -860,7 +860,7 @@ void ED_spacetype_sequencer(void)
art->draw = sequencer_tools_region_draw;
BLI_addhead(&st->regiontypes, art);
- /* regions: tool header */
+ /* Tool header. */
art = MEM_callocN(sizeof(ARegionType), "spacetype sequencer tool header region");
art->regionid = RGN_TYPE_TOOL_HEADER;
art->prefsizey = HEADERY;
@@ -871,7 +871,7 @@ void ED_spacetype_sequencer(void)
art->message_subscribe = ED_area_do_mgs_subscribe_for_tool_header;
BLI_addhead(&st->regiontypes, art);
- /* regions: header */
+ /* Header. */
art = MEM_callocN(sizeof(ARegionType), "spacetype sequencer region");
art->regionid = RGN_TYPE_HEADER;
art->prefsizey = HEADERY;
@@ -880,17 +880,16 @@ void ED_spacetype_sequencer(void)
art->init = sequencer_header_region_init;
art->draw = sequencer_header_region_draw;
art->listener = sequencer_main_region_listener;
-
BLI_addhead(&st->regiontypes, art);
- /* regions: hud */
+ /* Hud. */
art = ED_area_type_hud(st->spaceid);
BLI_addhead(&st->regiontypes, art);
BKE_spacetype_register(st);
- /* set the sequencer callback when not in background mode */
+ /* Set the sequencer callback when not in background mode. */
if (G.background == 0) {
- sequencer_view3d_cb = ED_view3d_draw_offscreen_imbuf_simple;
+ sequencer_view3d_fn = ED_view3d_draw_offscreen_imbuf_simple;
}
}
diff --git a/source/blender/editors/space_statusbar/space_statusbar.c b/source/blender/editors/space_statusbar/space_statusbar.c
index 1efb18403de..34d7f8b0216 100644
--- a/source/blender/editors/space_statusbar/space_statusbar.c
+++ b/source/blender/editors/space_statusbar/space_statusbar.c
@@ -65,7 +65,7 @@ static void statusbar_free(SpaceLink *UNUSED(sl))
}
/* spacetype; init callback */
-static void statusbar_init(struct wmWindowManager *UNUSED(wm), ScrArea *UNUSED(sa))
+static void statusbar_init(struct wmWindowManager *UNUSED(wm), ScrArea *UNUSED(area))
{
}
@@ -96,7 +96,7 @@ static void statusbar_keymap(struct wmKeyConfig *UNUSED(keyconf))
}
static void statusbar_header_region_listener(wmWindow *UNUSED(win),
- ScrArea *UNUSED(sa),
+ ScrArea *UNUSED(area),
ARegion *region,
wmNotifier *wmn,
const Scene *UNUSED(scene))
@@ -135,7 +135,7 @@ static void statusbar_header_region_message_subscribe(const bContext *UNUSED(C),
WorkSpace *UNUSED(workspace),
Scene *UNUSED(scene),
bScreen *UNUSED(screen),
- ScrArea *UNUSED(sa),
+ ScrArea *UNUSED(area),
ARegion *region,
struct wmMsgBus *mbus)
{
diff --git a/source/blender/editors/space_text/space_text.c b/source/blender/editors/space_text/space_text.c
index c695fdc72e6..11e1d16fdc7 100644
--- a/source/blender/editors/space_text/space_text.c
+++ b/source/blender/editors/space_text/space_text.c
@@ -107,7 +107,7 @@ static void text_free(SpaceLink *sl)
}
/* spacetype; init callback */
-static void text_init(struct wmWindowManager *UNUSED(wm), ScrArea *UNUSED(sa))
+static void text_init(struct wmWindowManager *UNUSED(wm), ScrArea *UNUSED(area))
{
}
@@ -123,11 +123,11 @@ static SpaceLink *text_duplicate(SpaceLink *sl)
}
static void text_listener(wmWindow *UNUSED(win),
- ScrArea *sa,
+ ScrArea *area,
wmNotifier *wmn,
Scene *UNUSED(scene))
{
- SpaceText *st = sa->spacedata.first;
+ SpaceText *st = area->spacedata.first;
/* context changes */
switch (wmn->category) {
@@ -141,14 +141,14 @@ static void text_listener(wmWindow *UNUSED(win),
switch (wmn->data) {
case ND_DISPLAY:
- ED_area_tag_redraw(sa);
+ ED_area_tag_redraw(area);
break;
case ND_CURSOR:
if (st->text && st->text == wmn->reference) {
- text_scroll_to_cursor__area(st, sa, true);
+ text_scroll_to_cursor__area(st, area, true);
}
- ED_area_tag_redraw(sa);
+ ED_area_tag_redraw(area);
break;
}
@@ -159,15 +159,15 @@ static void text_listener(wmWindow *UNUSED(win),
text_update_edited(st->text);
}
- ED_area_tag_redraw(sa);
+ ED_area_tag_redraw(area);
ATTR_FALLTHROUGH; /* fall down to tag redraw */
case NA_ADDED:
case NA_REMOVED:
- ED_area_tag_redraw(sa);
+ ED_area_tag_redraw(area);
break;
case NA_SELECTED:
if (st->text && st->text == wmn->reference) {
- text_scroll_to_cursor__area(st, sa, true);
+ text_scroll_to_cursor__area(st, area, true);
}
break;
@@ -176,7 +176,7 @@ static void text_listener(wmWindow *UNUSED(win),
break;
case NC_SPACE:
if (wmn->data == ND_SPACE_TEXT) {
- ED_area_tag_redraw(sa);
+ ED_area_tag_redraw(area);
}
break;
}
@@ -303,9 +303,9 @@ static void text_main_region_draw(const bContext *C, ARegion *region)
/* scrollers? */
}
-static void text_cursor(wmWindow *win, ScrArea *sa, ARegion *region)
+static void text_cursor(wmWindow *win, ScrArea *area, ARegion *region)
{
- SpaceText *st = sa->spacedata.first;
+ SpaceText *st = area->spacedata.first;
int wmcursor = WM_CURSOR_TEXT_EDIT;
if (st->text && BLI_rcti_isect_pt(&st->runtime.scroll_region_handle,
@@ -355,14 +355,14 @@ static void text_properties_region_draw(const bContext *C, ARegion *region)
if (st->flags & ST_FIND_ACTIVATE) {
if (UI_textbutton_activate_rna(C, region, st, "find_text")) {
/* if the panel was already open we need to do another redraw */
- ScrArea *sa = CTX_wm_area(C);
- WM_event_add_notifier(C, NC_SPACE | ND_SPACE_TEXT, sa);
+ ScrArea *area = CTX_wm_area(C);
+ WM_event_add_notifier(C, NC_SPACE | ND_SPACE_TEXT, area);
}
st->flags &= ~ST_FIND_ACTIVATE;
}
}
-static void text_id_remap(ScrArea *UNUSED(sa), SpaceLink *slink, ID *old_id, ID *new_id)
+static void text_id_remap(ScrArea *UNUSED(area), SpaceLink *slink, ID *old_id, ID *new_id)
{
SpaceText *stext = (SpaceText *)slink;
diff --git a/source/blender/editors/space_text/text_autocomplete.c b/source/blender/editors/space_text/text_autocomplete.c
index cb1861d8726..1f034bdbd09 100644
--- a/source/blender/editors/space_text/text_autocomplete.c
+++ b/source/blender/editors/space_text/text_autocomplete.c
@@ -335,8 +335,8 @@ static int doc_scroll = 0;
static int text_autocomplete_modal(bContext *C, wmOperator *op, const wmEvent *event)
{
SpaceText *st = CTX_wm_space_text(C);
- ScrArea *sa = CTX_wm_area(C);
- ARegion *region = BKE_area_find_region_type(sa, RGN_TYPE_WINDOW);
+ ScrArea *area = CTX_wm_area(C);
+ ARegion *region = BKE_area_find_region_type(area, RGN_TYPE_WINDOW);
int draw = 0, tools = 0, swallow = 0, scroll = 1;
Text *text = CTX_data_edit_text(C);
@@ -577,7 +577,7 @@ static int text_autocomplete_modal(bContext *C, wmOperator *op, const wmEvent *e
}
if (draw) {
- ED_area_tag_redraw(sa);
+ ED_area_tag_redraw(area);
}
// if (swallow) {
diff --git a/source/blender/editors/space_text/text_draw.c b/source/blender/editors/space_text/text_draw.c
index 777b6b1ef1d..a0339b35c57 100644
--- a/source/blender/editors/space_text/text_draw.c
+++ b/source/blender/editors/space_text/text_draw.c
@@ -1812,7 +1812,7 @@ void text_scroll_to_cursor(SpaceText *st, ARegion *region, const bool center)
}
/* takes an area instead of a region, use for listeners */
-void text_scroll_to_cursor__area(SpaceText *st, ScrArea *sa, const bool center)
+void text_scroll_to_cursor__area(SpaceText *st, ScrArea *area, const bool center)
{
ARegion *region;
@@ -1820,7 +1820,7 @@ void text_scroll_to_cursor__area(SpaceText *st, ScrArea *sa, const bool center)
return;
}
- region = BKE_area_find_region_type(sa, RGN_TYPE_WINDOW);
+ region = BKE_area_find_region_type(area, RGN_TYPE_WINDOW);
if (region) {
text_scroll_to_cursor(st, region, center);
@@ -1829,10 +1829,10 @@ void text_scroll_to_cursor__area(SpaceText *st, ScrArea *sa, const bool center)
void text_update_cursor_moved(bContext *C)
{
- ScrArea *sa = CTX_wm_area(C);
+ ScrArea *area = CTX_wm_area(C);
SpaceText *st = CTX_wm_space_text(C);
- text_scroll_to_cursor__area(st, sa, true);
+ text_scroll_to_cursor__area(st, area, true);
}
/**
diff --git a/source/blender/editors/space_text/text_format.c b/source/blender/editors/space_text/text_format.c
index 2eeb46049d2..bdbf55d9198 100644
--- a/source/blender/editors/space_text/text_format.c
+++ b/source/blender/editors/space_text/text_format.c
@@ -121,7 +121,7 @@ int flatten_string_strlen(FlattenString *fs, const char *str)
/* Ensures the format string for the given line is long enough, reallocating
* as needed. Allocation is done here, alone, to ensure consistency. */
-int text_check_format_len(TextLine *line, unsigned int len)
+int text_check_format_len(TextLine *line, uint len)
{
if (line->format) {
if (strlen(line->format) < len) {
diff --git a/source/blender/editors/space_text/text_header.c b/source/blender/editors/space_text/text_header.c
index da39ba3c5ad..c4052fcef84 100644
--- a/source/blender/editors/space_text/text_header.c
+++ b/source/blender/editors/space_text/text_header.c
@@ -42,17 +42,17 @@
/************************** properties ******************************/
-static ARegion *text_has_properties_region(ScrArea *sa)
+static ARegion *text_has_properties_region(ScrArea *area)
{
ARegion *region, *arnew;
- region = BKE_area_find_region_type(sa, RGN_TYPE_UI);
+ region = BKE_area_find_region_type(area, RGN_TYPE_UI);
if (region) {
return region;
}
/* add subdiv level; after header */
- region = BKE_area_find_region_type(sa, RGN_TYPE_HEADER);
+ region = BKE_area_find_region_type(area, RGN_TYPE_HEADER);
/* is error! */
if (region == NULL) {
@@ -61,7 +61,7 @@ static ARegion *text_has_properties_region(ScrArea *sa)
arnew = MEM_callocN(sizeof(ARegion), "properties region");
- BLI_insertlinkafter(&sa->regionbase, region, arnew);
+ BLI_insertlinkafter(&area->regionbase, region, arnew);
arnew->regiontype = RGN_TYPE_UI;
arnew->alignment = RGN_ALIGN_LEFT;
@@ -77,8 +77,8 @@ static bool text_properties_poll(bContext *C)
static int text_text_search_exec(bContext *C, wmOperator *UNUSED(op))
{
- ScrArea *sa = CTX_wm_area(C);
- ARegion *region = text_has_properties_region(sa);
+ ScrArea *area = CTX_wm_area(C);
+ ARegion *region = text_has_properties_region(area);
SpaceText *st = CTX_wm_space_text(C);
if (region) {
diff --git a/source/blender/editors/space_text/text_intern.h b/source/blender/editors/space_text/text_intern.h
index 5ad6a554188..d6588dda797 100644
--- a/source/blender/editors/space_text/text_intern.h
+++ b/source/blender/editors/space_text/text_intern.h
@@ -41,20 +41,20 @@ void text_update_line_edited(struct TextLine *line);
void text_update_edited(struct Text *text);
void text_update_character_width(struct SpaceText *st);
void text_scroll_to_cursor(struct SpaceText *st, struct ARegion *region, const bool center);
-void text_scroll_to_cursor__area(struct SpaceText *st, struct ScrArea *sa, const bool center);
+void text_scroll_to_cursor__area(struct SpaceText *st, struct ScrArea *area, const bool center);
void text_update_cursor_moved(struct bContext *C);
/* Padding around line numbers in character widths. */
#define TXT_NUMCOL_PAD 1.0f
/* Total width of the optional line numbers column. */
#define TXT_NUMCOL_WIDTH(st) \
- (st->runtime.cwidth_px * (st->runtime.line_number_display_digits + (2 * TXT_NUMCOL_PAD)))
+ ((st)->runtime.cwidth_px * ((st)->runtime.line_number_display_digits + (2 * TXT_NUMCOL_PAD)))
/* Padding on left of body text in character units. */
#define TXT_BODY_LPAD 1.0f
/* Left position of body text. */
#define TXT_BODY_LEFT(st) \
- (st->showlinenrs ? TXT_NUMCOL_WIDTH(st) : 0) + (TXT_BODY_LPAD * st->runtime.cwidth_px)
+ ((st)->showlinenrs ? TXT_NUMCOL_WIDTH(st) : 0) + (TXT_BODY_LPAD * (st)->runtime.cwidth_px)
#define TXT_SCROLL_WIDTH U.widget_unit
#define TXT_SCROLL_SPACE ((int)(0.1f * U.widget_unit))
diff --git a/source/blender/editors/space_text/text_ops.c b/source/blender/editors/space_text/text_ops.c
index e0b15d0a9d5..fa378954a30 100644
--- a/source/blender/editors/space_text/text_ops.c
+++ b/source/blender/editors/space_text/text_ops.c
@@ -2902,7 +2902,6 @@ void TEXT_OT_scroll_bar(wmOperatorType *ot)
* \{ */
typedef struct SetSelection {
- int selecting;
int selc, sell;
short mval_prev[2];
wmTimer *timer; /* needed for scrolling when mouse at region bounds */
@@ -3420,7 +3419,7 @@ static int text_insert_exec(bContext *C, wmOperator *op)
char *str;
bool done = false;
size_t i = 0;
- unsigned int code;
+ uint code;
text_drawcache_tag_update(st, 0);
diff --git a/source/blender/editors/space_topbar/space_topbar.c b/source/blender/editors/space_topbar/space_topbar.c
index cacf956aa84..d06c567988d 100644
--- a/source/blender/editors/space_topbar/space_topbar.c
+++ b/source/blender/editors/space_topbar/space_topbar.c
@@ -84,7 +84,7 @@ static void topbar_free(SpaceLink *UNUSED(sl))
}
/* spacetype; init callback */
-static void topbar_init(struct wmWindowManager *UNUSED(wm), ScrArea *UNUSED(sa))
+static void topbar_init(struct wmWindowManager *UNUSED(wm), ScrArea *UNUSED(area))
{
}
@@ -130,7 +130,7 @@ static void topbar_header_region_init(wmWindowManager *UNUSED(wm), ARegion *regi
}
static void topbar_main_region_listener(wmWindow *UNUSED(win),
- ScrArea *UNUSED(sa),
+ ScrArea *UNUSED(area),
ARegion *region,
wmNotifier *wmn,
const Scene *UNUSED(scene))
@@ -161,7 +161,7 @@ static void topbar_main_region_listener(wmWindow *UNUSED(win),
}
static void topbar_header_listener(wmWindow *UNUSED(win),
- ScrArea *UNUSED(sa),
+ ScrArea *UNUSED(area),
ARegion *region,
wmNotifier *wmn,
const Scene *UNUSED(scene))
@@ -195,7 +195,7 @@ static void topbar_header_region_message_subscribe(const struct bContext *UNUSED
struct WorkSpace *workspace,
struct Scene *UNUSED(scene),
struct bScreen *UNUSED(screen),
- struct ScrArea *UNUSED(sa),
+ struct ScrArea *UNUSED(area),
struct ARegion *region,
struct wmMsgBus *mbus)
{
diff --git a/source/blender/editors/space_userpref/space_userpref.c b/source/blender/editors/space_userpref/space_userpref.c
index d3bea4598ff..9eae722d5c8 100644
--- a/source/blender/editors/space_userpref/space_userpref.c
+++ b/source/blender/editors/space_userpref/space_userpref.c
@@ -97,7 +97,7 @@ static void userpref_free(SpaceLink *UNUSED(sl))
}
/* spacetype; init callback */
-static void userpref_init(struct wmWindowManager *UNUSED(wm), ScrArea *UNUSED(sa))
+static void userpref_init(struct wmWindowManager *UNUSED(wm), ScrArea *UNUSED(area))
{
}
@@ -185,7 +185,7 @@ static void userpref_execute_region_init(wmWindowManager *wm, ARegion *region)
}
static void userpref_main_region_listener(wmWindow *UNUSED(win),
- ScrArea *UNUSED(sa),
+ ScrArea *UNUSED(area),
ARegion *UNUSED(region),
wmNotifier *UNUSED(wmn),
const Scene *UNUSED(scene))
@@ -194,7 +194,7 @@ static void userpref_main_region_listener(wmWindow *UNUSED(win),
}
static void userpref_header_listener(wmWindow *UNUSED(win),
- ScrArea *UNUSED(sa),
+ ScrArea *UNUSED(area),
ARegion *UNUSED(region),
wmNotifier *UNUSED(wmn),
const Scene *UNUSED(scene))
@@ -209,7 +209,7 @@ static void userpref_header_listener(wmWindow *UNUSED(win),
}
static void userpref_navigation_region_listener(wmWindow *UNUSED(win),
- ScrArea *UNUSED(sa),
+ ScrArea *UNUSED(area),
ARegion *UNUSED(region),
wmNotifier *UNUSED(wmn),
const Scene *UNUSED(scene))
@@ -218,7 +218,7 @@ static void userpref_navigation_region_listener(wmWindow *UNUSED(win),
}
static void userpref_execute_region_listener(wmWindow *UNUSED(win),
- ScrArea *UNUSED(sa),
+ ScrArea *UNUSED(area),
ARegion *UNUSED(region),
wmNotifier *UNUSED(wmn),
const Scene *UNUSED(scene))
diff --git a/source/blender/editors/space_userpref/userpref_ops.c b/source/blender/editors/space_userpref/userpref_ops.c
index 1ec459ccfca..d823530fd89 100644
--- a/source/blender/editors/space_userpref/userpref_ops.c
+++ b/source/blender/editors/space_userpref/userpref_ops.c
@@ -25,11 +25,15 @@
#include "DNA_screen_types.h"
+#include "BLI_listbase.h"
+
#include "BKE_context.h"
#include "BKE_global.h"
#include "BKE_main.h"
#include "BKE_report.h"
+#include "RNA_access.h"
+#include "RNA_define.h"
#include "RNA_types.h"
#include "UI_interface.h"
@@ -41,11 +45,13 @@
#include "ED_userpref.h"
+#include "MEM_guardedalloc.h"
+
/* -------------------------------------------------------------------- */
-/** \name Reset Default Theme
+/** \name Reset Default Theme Operator
* \{ */
-static int reset_default_theme_exec(bContext *C, wmOperator *UNUSED(op))
+static int preferences_reset_default_theme_exec(bContext *C, wmOperator *UNUSED(op))
{
Main *bmain = CTX_data_main(C);
UI_theme_init_default();
@@ -64,7 +70,7 @@ static void PREFERENCES_OT_reset_default_theme(wmOperatorType *ot)
ot->description = "Reset to the default theme colors";
/* callbacks */
- ot->exec = reset_default_theme_exec;
+ ot->exec = preferences_reset_default_theme_exec;
/* flags */
ot->flag = OPTYPE_REGISTER;
@@ -72,7 +78,64 @@ static void PREFERENCES_OT_reset_default_theme(wmOperatorType *ot)
/** \} */
+/* -------------------------------------------------------------------- */
+/** \name Add Auto-Execution Path Operator
+ * \{ */
+
+static int preferences_autoexec_add_exec(bContext *UNUSED(C), wmOperator *UNUSED(op))
+{
+ bPathCompare *path_cmp = MEM_callocN(sizeof(bPathCompare), "bPathCompare");
+ BLI_addtail(&U.autoexec_paths, path_cmp);
+ U.runtime.is_dirty = true;
+ return OPERATOR_FINISHED;
+}
+
+static void PREFERENCES_OT_autoexec_path_add(wmOperatorType *ot)
+{
+ ot->name = "Add Autoexec Path";
+ ot->idname = "PREFERENCES_OT_autoexec_path_add";
+ ot->description = "Add path to exclude from auto-execution";
+
+ ot->exec = preferences_autoexec_add_exec;
+
+ ot->flag = OPTYPE_INTERNAL;
+}
+
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Remove Auto-Execution Path Operator
+ * \{ */
+
+static int preferences_autoexec_remove_exec(bContext *UNUSED(C), wmOperator *op)
+{
+ const int index = RNA_int_get(op->ptr, "index");
+ bPathCompare *path_cmp = BLI_findlink(&U.autoexec_paths, index);
+ if (path_cmp) {
+ BLI_freelinkN(&U.autoexec_paths, path_cmp);
+ U.runtime.is_dirty = true;
+ }
+ return OPERATOR_FINISHED;
+}
+
+static void PREFERENCES_OT_autoexec_path_remove(wmOperatorType *ot)
+{
+ ot->name = "Remove Autoexec Path";
+ ot->idname = "PREFERENCES_OT_autoexec_path_remove";
+ ot->description = "Remove path to exclude from auto-execution";
+
+ ot->exec = preferences_autoexec_remove_exec;
+
+ ot->flag = OPTYPE_INTERNAL;
+
+ RNA_def_int(ot->srna, "index", 0, 0, INT_MAX, "Index", "", 0, 1000);
+}
+
+/** \} */
+
void ED_operatortypes_userpref(void)
{
WM_operatortype_append(PREFERENCES_OT_reset_default_theme);
+ WM_operatortype_append(PREFERENCES_OT_autoexec_path_add);
+ WM_operatortype_append(PREFERENCES_OT_autoexec_path_remove);
}
diff --git a/source/blender/editors/space_view3d/CMakeLists.txt b/source/blender/editors/space_view3d/CMakeLists.txt
index c7fe82e0cbb..f2536cfac62 100644
--- a/source/blender/editors/space_view3d/CMakeLists.txt
+++ b/source/blender/editors/space_view3d/CMakeLists.txt
@@ -64,6 +64,7 @@ set(SRC
view3d_header.c
view3d_iterators.c
view3d_ops.c
+ view3d_placement.c
view3d_project.c
view3d_select.c
view3d_snap.c
diff --git a/source/blender/editors/space_view3d/space_view3d.c b/source/blender/editors/space_view3d/space_view3d.c
index d469faac934..5daba238293 100644
--- a/source/blender/editors/space_view3d/space_view3d.c
+++ b/source/blender/editors/space_view3d/space_view3d.c
@@ -88,9 +88,9 @@ RegionView3D *ED_view3d_context_rv3d(bContext *C)
RegionView3D *rv3d = CTX_wm_region_view3d(C);
if (rv3d == NULL) {
- ScrArea *sa = CTX_wm_area(C);
- if (sa && sa->spacetype == SPACE_VIEW3D) {
- ARegion *region = BKE_area_find_region_active_win(sa);
+ ScrArea *area = CTX_wm_area(C);
+ if (area && area->spacetype == SPACE_VIEW3D) {
+ ARegion *region = BKE_area_find_region_active_win(area);
if (region) {
rv3d = region->regiondata;
}
@@ -101,27 +101,27 @@ RegionView3D *ED_view3d_context_rv3d(bContext *C)
/* ideally would return an rv3d but in some cases the region is needed too
* so return that, the caller can then access the region->regiondata */
-bool ED_view3d_context_user_region(bContext *C, View3D **r_v3d, ARegion **r_ar)
+bool ED_view3d_context_user_region(bContext *C, View3D **r_v3d, ARegion **r_region)
{
- ScrArea *sa = CTX_wm_area(C);
+ ScrArea *area = CTX_wm_area(C);
*r_v3d = NULL;
- *r_ar = NULL;
+ *r_region = NULL;
- if (sa && sa->spacetype == SPACE_VIEW3D) {
+ if (area && area->spacetype == SPACE_VIEW3D) {
ARegion *region = CTX_wm_region(C);
- View3D *v3d = (View3D *)sa->spacedata.first;
+ View3D *v3d = (View3D *)area->spacedata.first;
if (region) {
RegionView3D *rv3d;
if ((region->regiontype == RGN_TYPE_WINDOW) && (rv3d = region->regiondata) &&
(rv3d->viewlock & RV3D_LOCK_ROTATION) == 0) {
*r_v3d = v3d;
- *r_ar = region;
+ *r_region = region;
return true;
}
else {
- if (ED_view3d_area_user_region(sa, v3d, r_ar)) {
+ if (ED_view3d_area_user_region(area, v3d, r_region)) {
*r_v3d = v3d;
return true;
}
@@ -136,23 +136,24 @@ bool ED_view3d_context_user_region(bContext *C, View3D **r_v3d, ARegion **r_ar)
* Similar to #ED_view3d_context_user_region() but does not use context. Always performs a lookup.
* Also works if \a v3d is not the active space.
*/
-bool ED_view3d_area_user_region(const ScrArea *sa, const View3D *v3d, ARegion **r_ar)
+bool ED_view3d_area_user_region(const ScrArea *area, const View3D *v3d, ARegion **r_region)
{
RegionView3D *rv3d = NULL;
- ARegion *ar_unlock_user = NULL;
- ARegion *ar_unlock = NULL;
- const ListBase *region_list = (v3d == sa->spacedata.first) ? &sa->regionbase : &v3d->regionbase;
+ ARegion *region_unlock_user = NULL;
+ ARegion *region_unlock = NULL;
+ const ListBase *region_list = (v3d == area->spacedata.first) ? &area->regionbase :
+ &v3d->regionbase;
BLI_assert(v3d->spacetype == SPACE_VIEW3D);
- for (ARegion *region = region_list->first; region; region = region->next) {
+ LISTBASE_FOREACH (ARegion *, region, region_list) {
/* find the first unlocked rv3d */
if (region->regiondata && region->regiontype == RGN_TYPE_WINDOW) {
rv3d = region->regiondata;
if ((rv3d->viewlock & RV3D_LOCK_ROTATION) == 0) {
- ar_unlock = region;
+ region_unlock = region;
if (rv3d->persp == RV3D_PERSP || rv3d->persp == RV3D_CAMOB) {
- ar_unlock_user = region;
+ region_unlock_user = region;
break;
}
}
@@ -160,13 +161,13 @@ bool ED_view3d_area_user_region(const ScrArea *sa, const View3D *v3d, ARegion **
}
/* camera/perspective view get priority when the active region is locked */
- if (ar_unlock_user) {
- *r_ar = ar_unlock_user;
+ if (region_unlock_user) {
+ *r_region = region_unlock_user;
return true;
}
- if (ar_unlock) {
- *r_ar = ar_unlock;
+ if (region_unlock) {
+ *r_region = region_unlock;
return true;
}
@@ -237,16 +238,19 @@ void ED_view3d_stop_render_preview(wmWindowManager *wm, ARegion *region)
RE_engine_free(rv3d->render_engine);
rv3d->render_engine = NULL;
}
+
+ /* A bit overkill but this make sure the viewport is reset completely. (fclem) */
+ WM_draw_region_free(region, false);
}
-void ED_view3d_shade_update(Main *bmain, View3D *v3d, ScrArea *sa)
+void ED_view3d_shade_update(Main *bmain, View3D *v3d, ScrArea *area)
{
wmWindowManager *wm = bmain->wm.first;
if (v3d->shading.type != OB_RENDER) {
ARegion *region;
- for (region = sa->regionbase.first; region; region = region->next) {
+ for (region = area->regionbase.first; region; region = region->next) {
if ((region->regiontype == RGN_TYPE_WINDOW) && region->regiondata) {
ED_view3d_stop_render_preview(wm, region);
break;
@@ -257,7 +261,7 @@ void ED_view3d_shade_update(Main *bmain, View3D *v3d, ScrArea *sa)
/* ******************** default callbacks for view3d space ***************** */
-static SpaceLink *view3d_new(const ScrArea *UNUSED(sa), const Scene *scene)
+static SpaceLink *view3d_new(const ScrArea *UNUSED(area), const Scene *scene)
{
ARegion *region;
View3D *v3d;
@@ -336,7 +340,7 @@ static void view3d_free(SpaceLink *sl)
}
/* spacetype; init callback */
-static void view3d_init(wmWindowManager *UNUSED(wm), ScrArea *UNUSED(sa))
+static void view3d_init(wmWindowManager *UNUSED(wm), ScrArea *UNUSED(area))
{
}
@@ -500,6 +504,8 @@ static void view3d_widgets(void)
WM_gizmogrouptype_append(VIEW3D_GGT_ruler);
WM_gizmotype_append(VIEW3D_GT_ruler_item);
+ WM_gizmogrouptype_append(VIEW3D_GGT_placement);
+
WM_gizmogrouptype_append_and_link(gzmap_type, VIEW3D_GGT_navigate);
WM_gizmotype_append(VIEW3D_GT_navigate_rotate);
}
@@ -561,9 +567,9 @@ static void *view3d_main_region_duplicate(void *poin)
}
static void view3d_main_region_listener(
- wmWindow *UNUSED(win), ScrArea *sa, ARegion *region, wmNotifier *wmn, const Scene *scene)
+ wmWindow *UNUSED(win), ScrArea *area, ARegion *region, wmNotifier *wmn, const Scene *scene)
{
- View3D *v3d = sa->spacedata.first;
+ View3D *v3d = area->spacedata.first;
RegionView3D *rv3d = region->regiondata;
wmGizmoMap *gzmap = region->gizmo_map;
@@ -756,7 +762,7 @@ static void view3d_main_region_listener(
}
break;
case NC_LIGHTPROBE:
- ED_area_tag_refresh(sa);
+ ED_area_tag_refresh(area);
break;
case NC_IMAGE:
/* this could be more fine grained checks if we had
@@ -821,7 +827,7 @@ static void view3d_main_region_message_subscribe(const struct bContext *C,
struct WorkSpace *UNUSED(workspace),
struct Scene *UNUSED(scene),
struct bScreen *UNUSED(screen),
- struct ScrArea *sa,
+ struct ScrArea *area,
struct ARegion *region,
struct wmMsgBus *mbus)
{
@@ -899,7 +905,7 @@ static void view3d_main_region_message_subscribe(const struct bContext *C,
{
wmMsgSubscribeValue msg_sub_value_region_tag_refresh = {
.owner = region,
- .user_data = sa,
+ .user_data = area,
.notify = WM_toolsystem_do_msg_notify_tag_refresh,
};
WM_msg_subscribe_rna_anon_prop(mbus, Object, mode, &msg_sub_value_region_tag_refresh);
@@ -907,9 +913,19 @@ static void view3d_main_region_message_subscribe(const struct bContext *C,
}
}
-static void view3d_main_region_cursor(wmWindow *win, ScrArea *sa, ARegion *region)
+/* concept is to retrieve cursor type context-less */
+static void view3d_main_region_cursor(wmWindow *win, ScrArea *area, ARegion *region)
{
- if (!WM_cursor_set_from_tool(win, sa, region)) {
+ if (WM_cursor_set_from_tool(win, area, region)) {
+ return;
+ }
+
+ ViewLayer *view_layer = WM_window_get_active_view_layer(win);
+ Object *obedit = OBEDIT_FROM_VIEW_LAYER(view_layer);
+ if (obedit) {
+ WM_cursor_set(win, WM_CURSOR_EDIT);
+ }
+ else {
WM_cursor_set(win, WM_CURSOR_DEFAULT);
}
}
@@ -930,7 +946,7 @@ static void view3d_header_region_draw(const bContext *C, ARegion *region)
}
static void view3d_header_region_listener(wmWindow *UNUSED(win),
- ScrArea *UNUSED(sa),
+ ScrArea *UNUSED(area),
ARegion *region,
wmNotifier *wmn,
const Scene *UNUSED(scene))
@@ -1003,7 +1019,7 @@ static void view3d_header_region_message_subscribe(const struct bContext *UNUSED
struct WorkSpace *UNUSED(workspace),
struct Scene *UNUSED(scene),
struct bScreen *UNUSED(screen),
- struct ScrArea *UNUSED(sa),
+ struct ScrArea *UNUSED(area),
struct ARegion *region,
struct wmMsgBus *mbus)
{
@@ -1147,7 +1163,7 @@ static void view3d_buttons_region_layout(const bContext *C, ARegion *region)
}
static void view3d_buttons_region_listener(wmWindow *UNUSED(win),
- ScrArea *UNUSED(sa),
+ ScrArea *UNUSED(area),
ARegion *region,
wmNotifier *wmn,
const Scene *UNUSED(scene))
@@ -1270,11 +1286,11 @@ static void view3d_tools_region_draw(const bContext *C, ARegion *region)
/* area (not region) level listener */
static void space_view3d_listener(wmWindow *UNUSED(win),
- ScrArea *sa,
+ ScrArea *area,
struct wmNotifier *wmn,
Scene *UNUSED(scene))
{
- View3D *v3d = sa->spacedata.first;
+ View3D *v3d = area->spacedata.first;
/* context changes */
switch (wmn->category) {
@@ -1282,7 +1298,7 @@ static void space_view3d_listener(wmWindow *UNUSED(win),
switch (wmn->data) {
case ND_WORLD:
if (v3d->flag2 & V3D_HIDE_OVERLAYS) {
- ED_area_tag_redraw_regiontype(sa, RGN_TYPE_WINDOW);
+ ED_area_tag_redraw_regiontype(area, RGN_TYPE_WINDOW);
}
break;
}
@@ -1292,7 +1308,7 @@ static void space_view3d_listener(wmWindow *UNUSED(win),
case ND_WORLD_DRAW:
case ND_WORLD:
if (v3d->shading.background_type == V3D_SHADING_BACKGROUND_WORLD) {
- ED_area_tag_redraw_regiontype(sa, RGN_TYPE_WINDOW);
+ ED_area_tag_redraw_regiontype(area, RGN_TYPE_WINDOW);
}
break;
}
@@ -1301,7 +1317,7 @@ static void space_view3d_listener(wmWindow *UNUSED(win),
switch (wmn->data) {
case ND_NODES:
if (v3d->shading.type == OB_TEXTURE) {
- ED_area_tag_redraw_regiontype(sa, RGN_TYPE_WINDOW);
+ ED_area_tag_redraw_regiontype(area, RGN_TYPE_WINDOW);
}
break;
}
@@ -1309,7 +1325,7 @@ static void space_view3d_listener(wmWindow *UNUSED(win),
}
}
-static void space_view3d_refresh(const bContext *C, ScrArea *UNUSED(sa))
+static void space_view3d_refresh(const bContext *C, ScrArea *UNUSED(area))
{
Scene *scene = CTX_data_scene(C);
LightCache *lcache = scene->eevee.light_cache_data;
@@ -1367,7 +1383,7 @@ static int view3d_context(const bContext *C, const char *member, bContextDataRes
return -1; /* found but not available */
}
-static void view3d_id_remap(ScrArea *sa, SpaceLink *slink, ID *old_id, ID *new_id)
+static void view3d_id_remap(ScrArea *area, SpaceLink *slink, ID *old_id, ID *new_id)
{
View3D *v3d;
ARegion *region;
@@ -1382,8 +1398,8 @@ static void view3d_id_remap(ScrArea *sa, SpaceLink *slink, ID *old_id, ID *new_i
v3d->camera = (Object *)new_id;
if (!new_id) {
/* 3D view might be inactive, in that case needs to use slink->regionbase */
- ListBase *regionbase = (slink == sa->spacedata.first) ? &sa->regionbase :
- &slink->regionbase;
+ ListBase *regionbase = (slink == area->spacedata.first) ? &area->regionbase :
+ &slink->regionbase;
for (region = regionbase->first; region; region = region->next) {
if (region->regiontype == RGN_TYPE_WINDOW) {
RegionView3D *rv3d = is_local ? ((RegionView3D *)region->regiondata)->localvd :
diff --git a/source/blender/editors/space_view3d/view3d_buttons.c b/source/blender/editors/space_view3d/view3d_buttons.c
index 80ab18cd3db..cb87ddafea1 100644
--- a/source/blender/editors/space_view3d/view3d_buttons.c
+++ b/source/blender/editors/space_view3d/view3d_buttons.c
@@ -1005,7 +1005,7 @@ static void v3d_editvertex_buts(uiLayout *layout, View3D *v3d, Object *ob, float
}
}
BKE_nurb_test_2d(nu);
- BKE_nurb_handles_test(nu, true); /* test for bezier too */
+ BKE_nurb_handles_test(nu, true, false); /* test for bezier too */
nu = nu->next;
}
@@ -1140,9 +1140,9 @@ static bool view3d_panel_vgroup_poll(const bContext *C, PanelType *UNUSED(pt))
return false;
}
-static void view3d_panel_vgroup(const bContext *C, Panel *pa)
+static void view3d_panel_vgroup(const bContext *C, Panel *panel)
{
- uiBlock *block = uiLayoutAbsoluteBlock(pa->layout);
+ uiBlock *block = uiLayoutAbsoluteBlock(panel->layout);
Scene *scene = CTX_data_scene(C);
ViewLayer *view_layer = CTX_data_view_layer(C);
Object *ob = view_layer->basact->object;
@@ -1171,7 +1171,7 @@ static void view3d_panel_vgroup(const bContext *C, Panel *pa)
UI_block_func_handle_set(block, do_view3d_vgroup_buttons, NULL);
- bcol = uiLayoutColumn(pa->layout, true);
+ bcol = uiLayoutColumn(panel->layout, true);
row = uiLayoutRow(bcol, true); /* The filter button row */
RNA_pointer_create(NULL, &RNA_ToolSettings, ts, &tools_ptr);
@@ -1269,7 +1269,7 @@ static void view3d_panel_vgroup(const bContext *C, Panel *pa)
yco -= 2;
- col = uiLayoutColumn(pa->layout, true);
+ col = uiLayoutColumn(panel->layout, true);
row = uiLayoutRow(col, true);
ot = WM_operatortype_find("OBJECT_OT_vertex_weight_normalize_active_vertex", 1);
@@ -1555,7 +1555,7 @@ static bool view3d_panel_transform_poll(const bContext *C, PanelType *UNUSED(pt)
return (view_layer->basact != NULL);
}
-static void view3d_panel_transform(const bContext *C, Panel *pa)
+static void view3d_panel_transform(const bContext *C, Panel *panel)
{
uiBlock *block;
ViewLayer *view_layer = CTX_data_view_layer(C);
@@ -1563,10 +1563,10 @@ static void view3d_panel_transform(const bContext *C, Panel *pa)
Object *obedit = OBEDIT_FROM_OBACT(ob);
uiLayout *col;
- block = uiLayoutGetBlock(pa->layout);
+ block = uiLayoutGetBlock(panel->layout);
UI_block_func_handle_set(block, do_view3d_region_buttons, NULL);
- col = uiLayoutColumn(pa->layout, false);
+ col = uiLayoutColumn(panel->layout, false);
if (ob == obedit) {
if (ob->type == OB_ARMATURE) {
@@ -1577,9 +1577,7 @@ static void view3d_panel_transform(const bContext *C, Panel *pa)
}
else {
View3D *v3d = CTX_wm_view3d(C);
- Scene *scene = CTX_data_scene(C);
- const float lim = 10000.0f * max_ff(1.0f, ED_view3d_grid_scale(scene, v3d, NULL));
- v3d_editvertex_buts(col, v3d, ob, lim);
+ v3d_editvertex_buts(col, v3d, ob, FLT_MAX);
}
}
else if (ob->mode & OB_MODE_POSE) {
@@ -1644,7 +1642,7 @@ static int view3d_object_mode_menu(bContext *C, wmOperator *op)
return OPERATOR_CANCELLED;
}
else if (((ob->mode & OB_MODE_EDIT) == 0) && (ELEM(ob->type, OB_ARMATURE))) {
- ED_object_mode_toggle(C, OB_MODE_POSE);
+ ED_object_mode_set(C, (ob->mode == OB_MODE_OBJECT) ? OB_MODE_POSE : OB_MODE_OBJECT);
return OPERATOR_CANCELLED;
}
else {
diff --git a/source/blender/editors/space_view3d/view3d_draw.c b/source/blender/editors/space_view3d/view3d_draw.c
index 694cb7ee7d4..fac378ae104 100644
--- a/source/blender/editors/space_view3d/view3d_draw.c
+++ b/source/blender/editors/space_view3d/view3d_draw.c
@@ -63,6 +63,7 @@
#include "ED_armature.h"
#include "ED_gpencil.h"
+#include "ED_info.h"
#include "ED_keyframing.h"
#include "ED_screen.h"
#include "ED_screen_types.h"
@@ -101,6 +102,8 @@
#define M_GOLDEN_RATIO_CONJUGATE 0.618033988749895f
+#define VIEW3D_OVERLAY_LINEHEIGHT (0.9f * U.widget_unit)
+
/* -------------------------------------------------------------------- */
/** \name General Functions
* \{ */
@@ -1341,7 +1344,7 @@ static void draw_viewport_name(ARegion *region, View3D *v3d, int xoffset, int *y
UI_FontThemeColor(BLF_default(), TH_TEXT_HI);
- *yoffset -= U.widget_unit;
+ *yoffset -= VIEW3D_OVERLAY_LINEHEIGHT;
BLF_draw_default(xoffset, *yoffset, 0.0f, name, sizeof(tmpstr));
@@ -1473,7 +1476,7 @@ static void draw_selected_name(
BLF_shadow(font_id, 5, (const float[4]){0.0f, 0.0f, 0.0f, 1.0f});
BLF_shadow_offset(font_id, 1, -1);
- *yoffset -= U.widget_unit;
+ *yoffset -= VIEW3D_OVERLAY_LINEHEIGHT;
BLF_draw_default(xoffset, *yoffset, 0.0f, info, sizeof(info));
BLF_disable(font_id, BLF_SHADOW);
@@ -1494,7 +1497,7 @@ static void draw_grid_unit_name(
BLI_snprintf(numstr, sizeof(numstr), "%s x %.4g", grid_unit, v3d->grid);
}
- *yoffset -= U.widget_unit;
+ *yoffset -= VIEW3D_OVERLAY_LINEHEIGHT;
BLF_enable(font_id, BLF_SHADOW);
BLF_shadow(font_id, 5, (const float[4]){0.0f, 0.0f, 0.0f, 1.0f});
BLF_shadow_offset(font_id, 1, -1);
@@ -1515,6 +1518,8 @@ void view3d_draw_region_info(const bContext *C, ARegion *region)
View3D *v3d = CTX_wm_view3d(C);
Scene *scene = CTX_data_scene(C);
wmWindowManager *wm = CTX_wm_manager(C);
+ Main *bmain = CTX_data_main(C);
+ ViewLayer *view_layer = CTX_data_view_layer(C);
#ifdef WITH_INPUT_NDOF
if ((U.ndof_flag & NDOF_SHOW_GUIDE) && ((RV3D_LOCK_FLAGS(rv3d) & RV3D_LOCK_ROTATION) == 0) &&
@@ -1550,8 +1555,8 @@ void view3d_draw_region_info(const bContext *C, ARegion *region)
}
}
- int xoffset = rect->xmin + U.widget_unit;
- int yoffset = rect->ymax;
+ int xoffset = rect->xmin + (0.5f * U.widget_unit);
+ int yoffset = rect->ymax - (0.1f * U.widget_unit);
if ((v3d->flag2 & V3D_HIDE_OVERLAYS) == 0 && (v3d->overlay.flag & V3D_OVERLAY_HIDE_TEXT) == 0) {
if ((U.uiflag & USER_SHOW_FPS) && ED_screen_animation_no_scrub(wm)) {
@@ -1562,7 +1567,6 @@ void view3d_draw_region_info(const bContext *C, ARegion *region)
}
if (U.uiflag & USER_DRAWVIEWINFO) {
- ViewLayer *view_layer = CTX_data_view_layer(C);
Object *ob = OBACT(view_layer);
draw_selected_name(scene, view_layer, ob, xoffset, &yoffset);
}
@@ -1571,10 +1575,12 @@ void view3d_draw_region_info(const bContext *C, ARegion *region)
/* draw below the viewport name */
draw_grid_unit_name(scene, rv3d, v3d, xoffset, &yoffset);
}
+
+ DRW_draw_region_engine_info(xoffset, &yoffset, VIEW3D_OVERLAY_LINEHEIGHT);
}
- if ((v3d->overlay.flag & V3D_OVERLAY_HIDE_TEXT) == 0) {
- DRW_draw_region_engine_info(xoffset, yoffset);
+ if ((v3d->flag2 & V3D_HIDE_OVERLAYS) == 0 && (v3d->overlay.flag & V3D_OVERLAY_STATS)) {
+ ED_info_draw_stats(bmain, scene, view_layer, xoffset, &yoffset, VIEW3D_OVERLAY_LINEHEIGHT);
}
BLF_batch_draw_end();
@@ -2217,7 +2223,7 @@ void ED_view3d_backbuf_depth_validate(ViewContext *vc)
if (obact_eval && ((obact_eval->base_flag & BASE_VISIBLE_DEPSGRAPH) != 0)) {
GPUViewport *viewport = WM_draw_region_get_viewport(region);
- DRW_draw_depth_object(vc->region, vc->v3d, viewport, obact_eval);
+ DRW_draw_depth_object(vc->scene, vc->region, vc->v3d, viewport, obact_eval);
}
vc->v3d->flag &= ~V3D_INVALID_BACKBUF;
@@ -2396,9 +2402,9 @@ void ED_view3d_screen_datamask(const bContext *C,
CustomData_MeshMasks_update(r_cddata_masks, &CD_MASK_BAREMESH);
/* Check if we need tfaces & mcols due to view mode. */
- for (const ScrArea *sa = screen->areabase.first; sa; sa = sa->next) {
- if (sa->spacetype == SPACE_VIEW3D) {
- ED_view3d_datamask(C, scene, sa->spacedata.first, r_cddata_masks);
+ LISTBASE_FOREACH (const ScrArea *, area, &screen->areabase) {
+ if (area->spacetype == SPACE_VIEW3D) {
+ ED_view3d_datamask(C, scene, area->spacedata.first, r_cddata_masks);
}
}
}
@@ -2493,7 +2499,7 @@ void ED_scene_draw_fps(const Scene *scene, int xoffset, int *yoffset)
BLF_shadow(font_id, 5, (const float[4]){0.0f, 0.0f, 0.0f, 1.0f});
BLF_shadow_offset(font_id, 1, -1);
- *yoffset -= U.widget_unit;
+ *yoffset -= VIEW3D_OVERLAY_LINEHEIGHT;
#ifdef WITH_INTERNATIONAL
BLF_draw_default(xoffset, *yoffset, 0.0f, printable, sizeof(printable));
diff --git a/source/blender/editors/space_view3d/view3d_edit.c b/source/blender/editors/space_view3d/view3d_edit.c
index 67dacca85ba..edd75d8e561 100644
--- a/source/blender/editors/space_view3d/view3d_edit.c
+++ b/source/blender/editors/space_view3d/view3d_edit.c
@@ -175,7 +175,7 @@ typedef struct ViewOpsData {
/** Context pointers (assigned by #viewops_data_alloc). */
Main *bmain;
Scene *scene;
- ScrArea *sa;
+ ScrArea *area;
ARegion *region;
View3D *v3d;
RegionView3D *rv3d;
@@ -277,9 +277,9 @@ static void viewops_data_alloc(bContext *C, wmOperator *op)
vod->bmain = CTX_data_main(C);
vod->depsgraph = CTX_data_ensure_evaluated_depsgraph(C);
vod->scene = CTX_data_scene(C);
- vod->sa = CTX_wm_area(C);
+ vod->area = CTX_wm_area(C);
vod->region = CTX_wm_region(C);
- vod->v3d = vod->sa->spacedata.first;
+ vod->v3d = vod->area->spacedata.first;
vod->rv3d = vod->region->regiondata;
}
@@ -529,10 +529,10 @@ static void viewops_data_create(bContext *C,
negate_v3_v3(rv3d->ofs, dvec);
}
else {
- const float mval_ar_mid[2] = {(float)vod->region->winx / 2.0f,
- (float)vod->region->winy / 2.0f};
+ const float mval_region_mid[2] = {(float)vod->region->winx / 2.0f,
+ (float)vod->region->winy / 2.0f};
- ED_view3d_win_to_3d(vod->v3d, vod->region, vod->dyn_ofs, mval_ar_mid, rv3d->ofs);
+ ED_view3d_win_to_3d(vod->v3d, vod->region, vod->dyn_ofs, mval_region_mid, rv3d->ofs);
negate_v3(rv3d->ofs);
}
negate_v3(vod->dyn_ofs);
@@ -627,14 +627,14 @@ void viewrotate_modal_keymap(wmKeyConfig *keyconf)
{0, NULL, 0, NULL, NULL},
};
- wmKeyMap *keymap = WM_modalkeymap_get(keyconf, "View3D Rotate Modal");
+ wmKeyMap *keymap = WM_modalkeymap_find(keyconf, "View3D Rotate Modal");
/* this function is called for each spacetype, only needs to add map once */
if (keymap && keymap->modal_items) {
return;
}
- keymap = WM_modalkeymap_add(keyconf, "View3D Rotate Modal", modal_items);
+ keymap = WM_modalkeymap_ensure(keyconf, "View3D Rotate Modal", modal_items);
/* disabled mode switching for now, can re-implement better, later on */
#if 0
@@ -1120,7 +1120,7 @@ static float view3d_ndof_pan_speed_calc(RegionView3D *rv3d)
* often `!rv3d->is_persp` since it doesn't make sense to dolly in ortho.
*/
static void view3d_ndof_pan_zoom(const struct wmNDOFMotionData *ndof,
- ScrArea *sa,
+ ScrArea *area,
ARegion *region,
const bool has_translate,
const bool has_zoom)
@@ -1161,7 +1161,7 @@ static void view3d_ndof_pan_zoom(const struct wmNDOFMotionData *ndof,
/* all callers must check */
if (has_translate) {
- BLI_assert(ED_view3d_offset_lock_check((View3D *)sa->spacedata.first, rv3d) == false);
+ BLI_assert(ED_view3d_offset_lock_check((View3D *)area->spacedata.first, rv3d) == false);
}
}
@@ -1178,18 +1178,18 @@ static void view3d_ndof_pan_zoom(const struct wmNDOFMotionData *ndof,
sub_v3_v3(rv3d->ofs, pan_vec);
if (RV3D_LOCK_FLAGS(rv3d) & RV3D_BOXVIEW) {
- view3d_boxview_sync(sa, region);
+ view3d_boxview_sync(area, region);
}
}
}
static void view3d_ndof_orbit(const struct wmNDOFMotionData *ndof,
- ScrArea *sa,
+ ScrArea *area,
ARegion *region,
ViewOpsData *vod,
const bool apply_dyn_ofs)
{
- View3D *v3d = sa->spacedata.first;
+ View3D *v3d = area->spacedata.first;
RegionView3D *rv3d = region->regiondata;
float view_inv[4];
@@ -1422,12 +1422,12 @@ static int ndof_orbit_invoke(bContext *C, wmOperator *op, const wmEvent *event)
const bool has_zoom = (ndof->tvec[2] != 0.0f) && !rv3d->is_persp;
if (has_translate || has_zoom) {
- view3d_ndof_pan_zoom(ndof, vod->sa, vod->region, has_translate, has_zoom);
+ view3d_ndof_pan_zoom(ndof, vod->area, vod->region, has_translate, has_zoom);
xform_flag |= HAS_TRANSLATE;
}
if (has_rotation) {
- view3d_ndof_orbit(ndof, vod->sa, vod->region, vod, true);
+ view3d_ndof_orbit(ndof, vod->area, vod->region, vod, true);
xform_flag |= HAS_ROTATE;
}
}
@@ -1505,7 +1505,7 @@ static int ndof_orbit_zoom_invoke(bContext *C, wmOperator *op, const wmEvent *ev
const bool has_zoom = (ndof->tvec[2] != 0.0f) && ED_view3d_offset_lock_check(v3d, rv3d);
if (has_translate || has_zoom) {
- view3d_ndof_pan_zoom(ndof, vod->sa, vod->region, has_translate, true);
+ view3d_ndof_pan_zoom(ndof, vod->area, vod->region, has_translate, true);
xform_flag |= HAS_TRANSLATE;
}
}
@@ -1535,7 +1535,7 @@ static int ndof_orbit_zoom_invoke(bContext *C, wmOperator *op, const wmEvent *ev
if (!is_orbit_around_pivot) {
ED_view3d_distance_set(rv3d, 0.0f);
}
- view3d_ndof_orbit(ndof, vod->sa, vod->region, vod, is_orbit_around_pivot);
+ view3d_ndof_orbit(ndof, vod->area, vod->region, vod, is_orbit_around_pivot);
xform_flag |= HAS_ROTATE;
if (!is_orbit_around_pivot) {
ED_view3d_distance_set(rv3d, dist_backup);
@@ -1543,7 +1543,7 @@ static int ndof_orbit_zoom_invoke(bContext *C, wmOperator *op, const wmEvent *ev
}
if (has_translate || has_zoom) {
- view3d_ndof_pan_zoom(ndof, vod->sa, vod->region, has_translate, has_zoom);
+ view3d_ndof_pan_zoom(ndof, vod->area, vod->region, has_translate, has_zoom);
xform_flag |= HAS_TRANSLATE;
}
}
@@ -1607,11 +1607,11 @@ static int ndof_pan_invoke(bContext *C, wmOperator *UNUSED(op), const wmEvent *e
ED_view3d_camera_lock_init_ex(depsgraph, v3d, rv3d, false);
if (ndof->progress != P_FINISHING) {
- ScrArea *sa = CTX_wm_area(C);
+ ScrArea *area = CTX_wm_area(C);
ARegion *region = CTX_wm_region(C);
if (has_translate || has_zoom) {
- view3d_ndof_pan_zoom(ndof, sa, region, has_translate, has_zoom);
+ view3d_ndof_pan_zoom(ndof, area, region, has_translate, has_zoom);
xform_flag |= HAS_TRANSLATE;
}
}
@@ -1702,14 +1702,14 @@ void viewmove_modal_keymap(wmKeyConfig *keyconf)
{0, NULL, 0, NULL, NULL},
};
- wmKeyMap *keymap = WM_modalkeymap_get(keyconf, "View3D Move Modal");
+ wmKeyMap *keymap = WM_modalkeymap_find(keyconf, "View3D Move Modal");
/* this function is called for each spacetype, only needs to add map once */
if (keymap && keymap->modal_items) {
return;
}
- keymap = WM_modalkeymap_add(keyconf, "View3D Move Modal", modal_items);
+ keymap = WM_modalkeymap_ensure(keyconf, "View3D Move Modal", modal_items);
/* items for modal map */
WM_modalkeymap_add_item(keymap, MIDDLEMOUSE, KM_RELEASE, KM_ANY, 0, VIEW_MODAL_CONFIRM);
@@ -1751,7 +1751,7 @@ static void viewmove_apply(ViewOpsData *vod, int x, int y)
add_v3_v3(vod->rv3d->ofs, dvec);
if (RV3D_LOCK_FLAGS(vod->rv3d) & RV3D_BOXVIEW) {
- view3d_boxview_sync(vod->sa, vod->region);
+ view3d_boxview_sync(vod->area, vod->region);
}
}
@@ -1901,14 +1901,14 @@ void viewzoom_modal_keymap(wmKeyConfig *keyconf)
{0, NULL, 0, NULL, NULL},
};
- wmKeyMap *keymap = WM_modalkeymap_get(keyconf, "View3D Zoom Modal");
+ wmKeyMap *keymap = WM_modalkeymap_find(keyconf, "View3D Zoom Modal");
/* this function is called for each spacetype, only needs to add map once */
if (keymap && keymap->modal_items) {
return;
}
- keymap = WM_modalkeymap_add(keyconf, "View3D Zoom Modal", modal_items);
+ keymap = WM_modalkeymap_ensure(keyconf, "View3D Zoom Modal", modal_items);
/* disabled mode switching for now, can re-implement better, later on */
#if 0
@@ -2189,7 +2189,7 @@ static void viewzoom_apply_3d(ViewOpsData *vod,
CLAMP(vod->rv3d->dist, dist_range[0], dist_range[1]);
if (RV3D_LOCK_FLAGS(vod->rv3d) & RV3D_BOXVIEW) {
- view3d_boxview_sync(vod->sa, vod->region);
+ view3d_boxview_sync(vod->area, vod->region);
}
ED_view3d_camera_lock_sync(vod->depsgraph, vod->v3d, vod->rv3d);
@@ -2280,7 +2280,7 @@ static int viewzoom_exec(bContext *C, wmOperator *op)
Scene *scene = CTX_data_scene(C);
View3D *v3d;
RegionView3D *rv3d;
- ScrArea *sa;
+ ScrArea *area;
ARegion *region;
bool use_cam_zoom;
float dist_range[2];
@@ -2291,15 +2291,15 @@ static int viewzoom_exec(bContext *C, wmOperator *op)
if (op->customdata) {
ViewOpsData *vod = op->customdata;
- sa = vod->sa;
+ area = vod->area;
region = vod->region;
}
else {
- sa = CTX_wm_area(C);
+ area = CTX_wm_area(C);
region = CTX_wm_region(C);
}
- v3d = sa->spacedata.first;
+ v3d = area->spacedata.first;
rv3d = region->regiondata;
use_cam_zoom = (rv3d->persp == RV3D_CAMOB) &&
@@ -2342,7 +2342,7 @@ static int viewzoom_exec(bContext *C, wmOperator *op)
}
if (RV3D_LOCK_FLAGS(rv3d) & RV3D_BOXVIEW) {
- view3d_boxview_sync(sa, region);
+ view3d_boxview_sync(area, region);
}
ED_view3d_depth_tag_update(rv3d);
@@ -2472,14 +2472,14 @@ void viewdolly_modal_keymap(wmKeyConfig *keyconf)
{0, NULL, 0, NULL, NULL},
};
- wmKeyMap *keymap = WM_modalkeymap_get(keyconf, "View3D Dolly Modal");
+ wmKeyMap *keymap = WM_modalkeymap_find(keyconf, "View3D Dolly Modal");
/* this function is called for each spacetype, only needs to add map once */
if (keymap && keymap->modal_items) {
return;
}
- keymap = WM_modalkeymap_add(keyconf, "View3D Dolly Modal", modal_items);
+ keymap = WM_modalkeymap_ensure(keyconf, "View3D Dolly Modal", modal_items);
/* disabled mode switching for now, can re-implement better, later on */
#if 0
@@ -2538,7 +2538,7 @@ static void viewdolly_apply(ViewOpsData *vod, const int xy[2], const short zoom_
}
if (RV3D_LOCK_FLAGS(vod->rv3d) & RV3D_BOXVIEW) {
- view3d_boxview_sync(vod->sa, vod->region);
+ view3d_boxview_sync(vod->area, vod->region);
}
ED_view3d_camera_lock_sync(vod->depsgraph, vod->v3d, vod->rv3d);
@@ -2603,7 +2603,7 @@ static int viewdolly_exec(bContext *C, wmOperator *op)
{
View3D *v3d;
RegionView3D *rv3d;
- ScrArea *sa;
+ ScrArea *area;
ARegion *region;
float mousevec[3];
@@ -2612,18 +2612,18 @@ static int viewdolly_exec(bContext *C, wmOperator *op)
if (op->customdata) {
ViewOpsData *vod = op->customdata;
- sa = vod->sa;
+ area = vod->area;
region = vod->region;
copy_v3_v3(mousevec, vod->init.mousevec);
}
else {
- sa = CTX_wm_area(C);
+ area = CTX_wm_area(C);
region = CTX_wm_region(C);
negate_v3_v3(mousevec, ((RegionView3D *)region->regiondata)->viewinv[2]);
normalize_v3(mousevec);
}
- v3d = sa->spacedata.first;
+ v3d = area->spacedata.first;
rv3d = region->regiondata;
const bool use_cursor_init = RNA_boolean_get(op->ptr, "use_cursor_init");
@@ -2636,7 +2636,7 @@ static int viewdolly_exec(bContext *C, wmOperator *op)
view_dolly_to_vector_3d(region, rv3d->ofs, mousevec, delta < 0 ? 0.2f : 1.8f);
if (RV3D_LOCK_FLAGS(rv3d) & RV3D_BOXVIEW) {
- view3d_boxview_sync(sa, region);
+ view3d_boxview_sync(area, region);
}
ED_view3d_depth_tag_update(rv3d);
@@ -2886,9 +2886,9 @@ static void view3d_from_minmax_multi(bContext *C,
const bool ok_dist,
const int smooth_viewtx)
{
- ScrArea *sa = CTX_wm_area(C);
+ ScrArea *area = CTX_wm_area(C);
ARegion *region;
- for (region = sa->regionbase.first; region; region = region->next) {
+ for (region = area->regionbase.first; region; region = region->next) {
if (region->regiontype == RGN_TYPE_WINDOW) {
RegionView3D *rv3d = region->regiondata;
/* when using all regions, don't jump out of camera view,
@@ -2980,7 +2980,7 @@ static int view3d_all_exec(bContext *C, wmOperator *op)
void VIEW3D_OT_view_all(wmOperatorType *ot)
{
/* identifiers */
- ot->name = "View All";
+ ot->name = "Frame All";
ot->description = "View all objects in scene";
ot->idname = "VIEW3D_OT_view_all";
@@ -3349,7 +3349,7 @@ void VIEW3D_OT_view_center_pick(wmOperatorType *ot)
/** \} */
/* -------------------------------------------------------------------- */
-/** \name View Camera Center Operator
+/** \name Frame Camera Bounds Operator
* \{ */
static int view3d_center_camera_exec(bContext *C, wmOperator *UNUSED(op))
@@ -3386,8 +3386,8 @@ static int view3d_center_camera_exec(bContext *C, wmOperator *UNUSED(op))
void VIEW3D_OT_view_center_camera(wmOperatorType *ot)
{
/* identifiers */
- ot->name = "View Camera Center";
- ot->description = "Center the camera view";
+ ot->name = "Frame Camera Bounds";
+ ot->description = "Center the camera view, resizing the view to fit its bounds";
ot->idname = "VIEW3D_OT_view_center_camera";
/* api callbacks */
@@ -4376,7 +4376,7 @@ static void viewroll_apply(ViewOpsData *vod, int x, int UNUSED(y))
}
if (RV3D_LOCK_FLAGS(vod->rv3d) & RV3D_BOXVIEW) {
- view3d_boxview_sync(vod->sa, vod->region);
+ view3d_boxview_sync(vod->area, vod->region);
}
ED_view3d_camera_lock_sync(vod->depsgraph, vod->v3d, vod->rv3d);
@@ -5018,7 +5018,6 @@ void ED_view3d_cursor3d_position_rotation(bContext *C,
float cursor_co[3],
float cursor_quat[4])
{
- Main *bmain = CTX_data_main(C);
Scene *scene = CTX_data_scene(C);
View3D *v3d = CTX_wm_view3d(C);
ARegion *region = CTX_wm_region(C);
@@ -5052,7 +5051,7 @@ void ED_view3d_cursor3d_position_rotation(bContext *C,
float ray_co[3];
struct SnapObjectContext *snap_context = ED_transform_snap_object_context_create_view3d(
- bmain, scene, 0, region, v3d);
+ scene, 0, region, v3d);
float obmat[4][4];
Object *ob_dummy = NULL;
@@ -5279,7 +5278,7 @@ static int toggle_shading_exec(bContext *C, wmOperator *op)
{
Main *bmain = CTX_data_main(C);
View3D *v3d = CTX_wm_view3d(C);
- ScrArea *sa = CTX_wm_area(C);
+ ScrArea *area = CTX_wm_area(C);
int type = RNA_enum_get(op->ptr, "type");
if (type == OB_SOLID) {
@@ -5307,7 +5306,7 @@ static int toggle_shading_exec(bContext *C, wmOperator *op)
}
}
- ED_view3d_shade_update(bmain, v3d, sa);
+ ED_view3d_shade_update(bmain, v3d, area);
WM_event_add_notifier(C, NC_SPACE | ND_SPACE_VIEW3D, v3d);
return OPERATOR_FINISHED;
@@ -5340,7 +5339,7 @@ void VIEW3D_OT_toggle_shading(wmOperatorType *ot)
static int toggle_xray_exec(bContext *C, wmOperator *op)
{
View3D *v3d = CTX_wm_view3d(C);
- ScrArea *sa = CTX_wm_area(C);
+ ScrArea *area = CTX_wm_area(C);
Object *obact = CTX_data_active_object(C);
if (obact && ((obact->mode & OB_MODE_POSE) ||
@@ -5362,7 +5361,7 @@ static int toggle_xray_exec(bContext *C, wmOperator *op)
}
}
- ED_area_tag_redraw(sa);
+ ED_area_tag_redraw(area);
return OPERATOR_FINISHED;
}
@@ -5372,6 +5371,7 @@ void VIEW3D_OT_toggle_xray(wmOperatorType *ot)
/* identifiers */
ot->name = "Toggle X-Ray";
ot->idname = "VIEW3D_OT_toggle_xray";
+ ot->description = "Transparent scene display. Allow selecting through items";
/* api callbacks */
ot->exec = toggle_xray_exec;
diff --git a/source/blender/editors/space_view3d/view3d_fly.c b/source/blender/editors/space_view3d/view3d_fly.c
index 563e1afa67e..06d1a033a0d 100644
--- a/source/blender/editors/space_view3d/view3d_fly.c
+++ b/source/blender/editors/space_view3d/view3d_fly.c
@@ -125,14 +125,14 @@ void fly_modal_keymap(wmKeyConfig *keyconf)
{0, NULL, 0, NULL, NULL},
};
- wmKeyMap *keymap = WM_modalkeymap_get(keyconf, "View3D Fly Modal");
+ wmKeyMap *keymap = WM_modalkeymap_find(keyconf, "View3D Fly Modal");
/* this function is called for each spacetype, only needs to add map once */
if (keymap && keymap->modal_items) {
return;
}
- keymap = WM_modalkeymap_add(keyconf, "View3D Fly Modal", modal_items);
+ keymap = WM_modalkeymap_ensure(keyconf, "View3D Fly Modal", modal_items);
/* assign map to operators */
WM_modalkeymap_assign(keymap, "VIEW3D_OT_fly");
diff --git a/source/blender/editors/space_view3d/view3d_gizmo_navigate.c b/source/blender/editors/space_view3d/view3d_gizmo_navigate.c
index cc00037b1fb..533fba3795b 100644
--- a/source/blender/editors/space_view3d/view3d_gizmo_navigate.c
+++ b/source/blender/editors/space_view3d/view3d_gizmo_navigate.c
@@ -321,14 +321,14 @@ static void WIDGETGROUP_navigate_draw_prepare(const bContext *C, wmGizmoGroup *g
if ((RV3D_LOCK_FLAGS(rv3d) & RV3D_LOCK_ROTATION) == 0) {
gz = navgroup->gz_array[GZ_INDEX_CAMERA];
- gz->matrix_basis[3][0] = co[0];
- gz->matrix_basis[3][1] = co[1] - (icon_offset_mini * icon_mini_slot++);
+ gz->matrix_basis[3][0] = roundf(co[0]);
+ gz->matrix_basis[3][1] = roundf(co[1] - (icon_offset_mini * icon_mini_slot++));
WM_gizmo_set_flag(gz, WM_GIZMO_HIDDEN, false);
if (navgroup->state.rv3d.is_camera == false) {
gz = navgroup->gz_array[rv3d->is_persp ? GZ_INDEX_PERSP : GZ_INDEX_ORTHO];
- gz->matrix_basis[3][0] = co[0];
- gz->matrix_basis[3][1] = co[1] - (icon_offset_mini * icon_mini_slot++);
+ gz->matrix_basis[3][0] = roundf(co[0]);
+ gz->matrix_basis[3][1] = roundf(co[1] - (icon_offset_mini * icon_mini_slot++));
WM_gizmo_set_flag(gz, WM_GIZMO_HIDDEN, false);
}
}
diff --git a/source/blender/editors/space_view3d/view3d_gizmo_navigate_type.c b/source/blender/editors/space_view3d/view3d_gizmo_navigate_type.c
index a8e8d8cee96..3ce4c8dc9a8 100644
--- a/source/blender/editors/space_view3d/view3d_gizmo_navigate_type.c
+++ b/source/blender/editors/space_view3d/view3d_gizmo_navigate_type.c
@@ -197,8 +197,8 @@ static void axis_geom_draw(const wmGizmo *gz,
const bool select,
const struct AxisDrawInfo *draw_info)
{
-
- GPU_line_width(gz->line_width);
+ float viewport[4];
+ GPU_viewport_size_get_f(viewport);
GPUVertFormat *format = immVertexFormat();
const uint pos_id = GPU_vertformat_attr_add(format, "pos", GPU_COMP_F32, 3, GPU_FETCH_FLOAT);
@@ -341,8 +341,13 @@ static void axis_geom_draw(const wmGizmo *gz,
/* Axis Line. */
if (is_pos) {
float v_start[3];
- GPU_line_width(2.0f);
+ immUnbindProgram();
+
+ immBindBuiltinProgram(GPU_SHADER_3D_POLYLINE_UNIFORM_COLOR);
+ immUniform2fv("viewportSize", &viewport[2]);
+ immUniform1f("lineWidth", 2.0f * U.pixelsize);
immUniformColor4fv(is_pos_color ? color_current : color_current_fade);
+
immBegin(GPU_PRIM_LINES, 2);
if (axis_align == -1) {
zero_v3(v_start);
@@ -358,6 +363,10 @@ static void axis_geom_draw(const wmGizmo *gz,
immVertex3fv(pos_id, v_start);
immVertex3fv(pos_id, v_final);
immEnd();
+
+ immUnbindProgram();
+
+ immBindBuiltinProgram(GPU_SHADER_3D_UNIFORM_COLOR);
}
/* Axis Ball. */
@@ -527,9 +536,12 @@ static int gizmo_axis_test_select(bContext *UNUSED(C), wmGizmo *gz, const int mv
return -1;
}
-static int gizmo_axis_cursor_get(wmGizmo *UNUSED(gz))
+static int gizmo_axis_cursor_get(wmGizmo *gz)
{
- return WM_CURSOR_DEFAULT;
+ if (gz->highlight_part > 0) {
+ return WM_CURSOR_EDIT;
+ }
+ return WM_CURSOR_NSEW_SCROLL;
}
void VIEW3D_GT_navigate_rotate(wmGizmoType *gzt)
diff --git a/source/blender/editors/space_view3d/view3d_gizmo_ruler.c b/source/blender/editors/space_view3d/view3d_gizmo_ruler.c
index 4b194d6687d..f3bc0a8a15b 100644
--- a/source/blender/editors/space_view3d/view3d_gizmo_ruler.c
+++ b/source/blender/editors/space_view3d/view3d_gizmo_ruler.c
@@ -40,6 +40,7 @@
#include "DNA_object_types.h"
#include "DNA_view3d_types.h"
+#include "ED_gizmo_library.h"
#include "ED_gizmo_utils.h"
#include "ED_gpencil.h"
#include "ED_screen.h"
@@ -57,10 +58,13 @@
#include "WM_toolsystem.h"
#include "WM_types.h"
+#include "DEG_depsgraph_query.h"
+
#include "view3d_intern.h" /* own include */
#include "GPU_immediate.h"
#include "GPU_immediate_util.h"
+#include "GPU_matrix.h"
#include "GPU_state.h"
#include "BLF_api.h"
@@ -94,10 +98,6 @@ enum {
RULER_STATE_DRAG,
};
-enum {
- RULER_SNAP_OK = (1 << 0),
-};
-
struct RulerItem;
typedef struct RulerInfo {
@@ -106,19 +106,25 @@ typedef struct RulerInfo {
int snap_flag;
int state;
- struct SnapObjectContext *snap_context;
-
/* wm state */
+ wmWindowManager *wm;
wmWindow *win;
- ScrArea *sa;
+ ScrArea *area;
ARegion *region; /* re-assigned every modal update */
/* Track changes in state. */
struct {
+#ifndef USE_SNAP_DETECT_FROM_KEYMAP_HACK
bool do_snap;
+#endif
bool do_thickness;
} drag_state_prev;
+ struct {
+ wmGizmo *gizmo;
+ PropertyRNA *prop_prevpoint;
+ } snap_data;
+
} RulerInfo;
/* -------------------------------------------------------------------- */
@@ -269,26 +275,17 @@ static bool view3d_ruler_pick(wmGizmoGroup *gzgroup,
* Ensure the 'snap_context' is only cached while dragging,
* needed since the user may toggle modes between tool use.
*/
-static void ruler_state_set(bContext *C, RulerInfo *ruler_info, int state)
+static void ruler_state_set(RulerInfo *ruler_info, int state)
{
- Main *bmain = CTX_data_main(C);
if (state == ruler_info->state) {
return;
}
- /* always remove */
- if (ruler_info->snap_context) {
- ED_transform_snap_object_context_destroy(ruler_info->snap_context);
- ruler_info->snap_context = NULL;
- }
-
if (state == RULER_STATE_NORMAL) {
/* pass */
}
else if (state == RULER_STATE_DRAG) {
memset(&ruler_info->drag_state_prev, 0x0, sizeof(ruler_info->drag_state_prev));
- ruler_info->snap_context = ED_transform_snap_object_context_create_view3d(
- bmain, CTX_data_scene(C), 0, ruler_info->region, CTX_wm_view3d(C));
}
else {
BLI_assert(0);
@@ -299,7 +296,7 @@ static void ruler_state_set(bContext *C, RulerInfo *ruler_info, int state)
static void view3d_ruler_item_project(RulerInfo *ruler_info, float r_co[3], const int xy[2])
{
- ED_view3d_win_to_3d_int(ruler_info->sa->spacedata.first, ruler_info->region, r_co, xy, r_co);
+ ED_view3d_win_to_3d_int(ruler_info->area->spacedata.first, ruler_info->region, r_co, xy, r_co);
}
/* use for mousemove events */
@@ -307,13 +304,18 @@ static bool view3d_ruler_item_mousemove(struct Depsgraph *depsgraph,
RulerInfo *ruler_info,
RulerItem *ruler_item,
const int mval[2],
- const bool do_thickness,
- const bool do_snap)
+ const bool do_thickness
+#ifndef USE_SNAP_DETECT_FROM_KEYMAP_HACK
+ ,
+ const bool do_snap
+#endif
+)
{
+ wmGizmo *snap_gizmo = ruler_info->snap_data.gizmo;
const float eps_bias = 0.0002f;
float dist_px = MVAL_MAX_PX_DIST * U.pixelsize; /* snap dist */
- ruler_info->snap_flag &= ~RULER_SNAP_OK;
+ WM_gizmo_set_flag(snap_gizmo, WM_GIZMO_HIDDEN, true);
if (ruler_item) {
RulerInteraction *inter = ruler_item->gz.interaction_data;
@@ -322,8 +324,10 @@ static bool view3d_ruler_item_mousemove(struct Depsgraph *depsgraph,
copy_v3_v3(co, inter->drag_start_co);
view3d_ruler_item_project(ruler_info, co, mval);
if (do_thickness && inter->co_index != 1) {
- // Scene *scene = CTX_data_scene(C);
- // View3D *v3d = ruler_info->sa->spacedata.first;
+ Scene *scene = DEG_get_input_scene(depsgraph);
+ View3D *v3d = ruler_info->area->spacedata.first;
+ SnapObjectContext *snap_context = ED_gizmotypes_snap_3d_context_ensure(
+ scene, ruler_info->region, v3d, snap_gizmo);
const float mval_fl[2] = {UNPACK2(mval)};
float ray_normal[3];
float ray_start[3];
@@ -331,7 +335,7 @@ static bool view3d_ruler_item_mousemove(struct Depsgraph *depsgraph,
co_other = ruler_item->co[inter->co_index == 0 ? 2 : 0];
- if (ED_transform_snap_object_project_view3d(ruler_info->snap_context,
+ if (ED_transform_snap_object_project_view3d(snap_context,
depsgraph,
SCE_SNAP_MODE_FACE,
&(const struct SnapObjectParams){
@@ -346,7 +350,7 @@ static bool view3d_ruler_item_mousemove(struct Depsgraph *depsgraph,
negate_v3(ray_normal);
/* add some bias */
madd_v3_v3v3fl(ray_start, co, ray_normal, eps_bias);
- ED_transform_snap_object_project_ray(ruler_info->snap_context,
+ ED_transform_snap_object_project_ray(snap_context,
depsgraph,
&(const struct SnapObjectParams){
.snap_select = SNAP_ALL,
@@ -359,7 +363,12 @@ static bool view3d_ruler_item_mousemove(struct Depsgraph *depsgraph,
NULL);
}
}
- else if (do_snap) {
+ else
+#ifndef USE_SNAP_DETECT_FROM_KEYMAP_HACK
+ if (do_snap)
+#endif
+ {
+ View3D *v3d = ruler_info->area->spacedata.first;
const float mval_fl[2] = {UNPACK2(mval)};
float *prev_point = NULL;
@@ -374,23 +383,16 @@ static bool view3d_ruler_item_mousemove(struct Depsgraph *depsgraph,
prev_point = ruler_item->co[0];
}
}
+ if (prev_point != NULL) {
+ RNA_property_float_set_array(
+ snap_gizmo->ptr, ruler_info->snap_data.prop_prevpoint, prev_point);
+ }
- if (ED_transform_snap_object_project_view3d(
- ruler_info->snap_context,
- depsgraph,
- (SCE_SNAP_MODE_VERTEX | SCE_SNAP_MODE_EDGE | SCE_SNAP_MODE_FACE |
- SCE_SNAP_MODE_EDGE_MIDPOINT | SCE_SNAP_MODE_EDGE_PERPENDICULAR),
- &(const struct SnapObjectParams){
- .snap_select = SNAP_ALL,
- .use_object_edit_cage = true,
- .use_occlusion_test = true,
- },
- mval_fl,
- prev_point,
- &dist_px,
- co,
- NULL)) {
- ruler_info->snap_flag |= RULER_SNAP_OK;
+ short snap_elem = ED_gizmotypes_snap_3d_update(
+ snap_gizmo, depsgraph, ruler_info->region, v3d, ruler_info->wm, mval_fl, co, NULL);
+
+ if (snap_elem) {
+ WM_gizmo_set_flag(snap_gizmo, WM_GIZMO_HIDDEN, false);
}
}
return true;
@@ -417,6 +419,15 @@ static bGPDlayer *view3d_ruler_layer_get(bGPdata *gpd)
return NULL;
}
+static RulerItem *gzgroup_ruler_item_first_get(wmGizmoGroup *gzgroup)
+{
+#ifndef NDEBUG
+ RulerInfo *ruler_info = gzgroup->customdata;
+ BLI_assert(gzgroup->gizmos.first == ruler_info->snap_data.gizmo);
+#endif
+ return (RulerItem *)((wmGizmo *)gzgroup->gizmos.first)->next;
+}
+
#define RULER_ID "RulerData3D"
static bool view3d_ruler_to_gpencil(bContext *C, wmGizmoGroup *gzgroup)
{
@@ -448,7 +459,7 @@ static bool view3d_ruler_to_gpencil(bContext *C, wmGizmoGroup *gzgroup)
gpf = BKE_gpencil_layer_frame_get(gpl, CFRA, GP_GETFRAME_ADD_NEW);
BKE_gpencil_free_strokes(gpf);
- for (ruler_item = gzgroup->gizmos.first; ruler_item;
+ for (ruler_item = gzgroup_ruler_item_first_get(gzgroup); ruler_item;
ruler_item = (RulerItem *)ruler_item->gz.next) {
bGPDspoint *pt;
int j;
@@ -556,6 +567,12 @@ static void gizmo_ruler_draw(const bContext *C, wmGizmo *gz)
uchar color_wire[3];
float color_back[4] = {1.0f, 1.0f, 1.0f, 0.5f};
+ /* Pixel Space. */
+ GPU_matrix_push_projection();
+ GPU_matrix_push();
+ GPU_matrix_identity_set();
+ wmOrtho2_region_pixelspace(region);
+
/* anti-aliased lines for more consistent appearance */
GPU_line_smooth(true);
GPU_line_width(1.0f);
@@ -575,20 +592,30 @@ static void gizmo_ruler_draw(const bContext *C, wmGizmo *gz)
const bool is_act = (ruler_info->item_active == ruler_item);
float dir_ruler[2];
float co_ss[3][2];
+ bool proj_ok[3];
int j;
- /* should these be checked? - ok for now not to */
+ /* Check if each corner is behind the near plane. If it is, we do not draw certain lines. */
for (j = 0; j < 3; j++) {
- ED_view3d_project_float_global(region, ruler_item->co[j], co_ss[j], V3D_PROJ_TEST_NOP);
+ eV3DProjStatus status = ED_view3d_project_float_global(
+ region, ruler_item->co[j], co_ss[j], V3D_PROJ_TEST_CLIP_NEAR);
+ proj_ok[j] = (status == V3D_PROJ_RET_OK);
}
+ /* 3d drawing. */
+
+ GPU_matrix_push_projection();
+ GPU_matrix_push();
+ GPU_matrix_projection_set(rv3d->winmat);
+ GPU_matrix_set(rv3d->viewmat);
+
GPU_blend(true);
- const uint shdr_pos = GPU_vertformat_attr_add(
- immVertexFormat(), "pos", GPU_COMP_F32, 2, GPU_FETCH_FLOAT);
+ const uint shdr_pos_3d = GPU_vertformat_attr_add(
+ immVertexFormat(), "pos", GPU_COMP_F32, 3, GPU_FETCH_FLOAT);
if (ruler_item->flag & RULERITEM_USE_ANGLE) {
- immBindBuiltinProgram(GPU_SHADER_2D_LINE_DASHED_UNIFORM_COLOR);
+ immBindBuiltinProgram(GPU_SHADER_3D_LINE_DASHED_UNIFORM_COLOR);
float viewport_size[4];
GPU_viewport_size_get_f(viewport_size);
@@ -605,21 +632,20 @@ static void gizmo_ruler_draw(const bContext *C, wmGizmo *gz)
immBegin(GPU_PRIM_LINE_STRIP, 3);
- immVertex2fv(shdr_pos, co_ss[0]);
- immVertex2fv(shdr_pos, co_ss[1]);
- immVertex2fv(shdr_pos, co_ss[2]);
+ immVertex3fv(shdr_pos_3d, ruler_item->co[0]);
+ immVertex3fv(shdr_pos_3d, ruler_item->co[1]);
+ immVertex3fv(shdr_pos_3d, ruler_item->co[2]);
immEnd();
immUnbindProgram();
- immBindBuiltinProgram(GPU_SHADER_2D_UNIFORM_COLOR);
+ immBindBuiltinProgram(GPU_SHADER_3D_UNIFORM_COLOR);
/* arc */
{
float dir_tmp[3];
- float co_tmp[3];
- float arc_ss_coord[2];
+ float ar_coord[3];
float dir_a[3];
float dir_b[3];
@@ -648,16 +674,53 @@ static void gizmo_ruler_draw(const bContext *C, wmGizmo *gz)
immBegin(GPU_PRIM_LINE_STRIP, arc_steps + 1);
for (j = 0; j <= arc_steps; j++) {
- madd_v3_v3v3fl(co_tmp, ruler_item->co[1], dir_tmp, px_scale);
- ED_view3d_project_float_global(region, co_tmp, arc_ss_coord, V3D_PROJ_TEST_NOP);
+ madd_v3_v3v3fl(ar_coord, ruler_item->co[1], dir_tmp, px_scale);
mul_qt_v3(quat, dir_tmp);
- immVertex2fv(shdr_pos, arc_ss_coord);
+ immVertex3fv(shdr_pos_3d, ar_coord);
}
immEnd();
}
+ immUnbindProgram();
+ }
+ else {
+ immBindBuiltinProgram(GPU_SHADER_3D_LINE_DASHED_UNIFORM_COLOR);
+
+ float viewport_size[4];
+ GPU_viewport_size_get_f(viewport_size);
+ immUniform2f("viewport_size", viewport_size[2], viewport_size[3]);
+
+ immUniform1i("colors_len", 2); /* "advanced" mode */
+ const float *col = is_act ? color_act : color_base;
+ immUniformArray4fv(
+ "colors",
+ (float *)(float[][4]){{0.67f, 0.67f, 0.67f, 1.0f}, {col[0], col[1], col[2], col[3]}},
+ 2);
+ immUniform1f("dash_width", 6.0f);
+ immUniform1f("dash_factor", 0.5f);
+
+ immBegin(GPU_PRIM_LINES, 2);
+
+ immVertex3fv(shdr_pos_3d, ruler_item->co[0]);
+ immVertex3fv(shdr_pos_3d, ruler_item->co[2]);
+
+ immEnd();
+
+ immUnbindProgram();
+ }
+
+ /* 2d drawing. */
+
+ GPU_matrix_pop();
+ GPU_matrix_pop_projection();
+
+ const uint shdr_pos_2d = GPU_vertformat_attr_add(
+ immVertexFormat(), "pos", GPU_COMP_F32, 2, GPU_FETCH_FLOAT);
+
+ if (ruler_item->flag & RULERITEM_USE_ANGLE) {
+ immBindBuiltinProgram(GPU_SHADER_2D_UNIFORM_COLOR);
/* capping */
{
float rot_90_vec_a[2];
@@ -676,15 +739,15 @@ static void gizmo_ruler_draw(const bContext *C, wmGizmo *gz)
GPU_blend(true);
- if (is_act && (ruler_item->flag & RULERITEM_USE_ANGLE_ACTIVE)) {
+ if (proj_ok[1] && is_act && (ruler_item->flag & RULERITEM_USE_ANGLE_ACTIVE)) {
GPU_line_width(3.0f);
immUniformColor3fv(color_act);
immBegin(GPU_PRIM_LINES, 4);
/* angle vertex */
- immVertex2f(shdr_pos, co_ss[1][0] - cap_size, co_ss[1][1] - cap_size);
- immVertex2f(shdr_pos, co_ss[1][0] + cap_size, co_ss[1][1] + cap_size);
- immVertex2f(shdr_pos, co_ss[1][0] - cap_size, co_ss[1][1] + cap_size);
- immVertex2f(shdr_pos, co_ss[1][0] + cap_size, co_ss[1][1] - cap_size);
+ immVertex2f(shdr_pos_2d, co_ss[1][0] - cap_size, co_ss[1][1] - cap_size);
+ immVertex2f(shdr_pos_2d, co_ss[1][0] + cap_size, co_ss[1][1] + cap_size);
+ immVertex2f(shdr_pos_2d, co_ss[1][0] - cap_size, co_ss[1][1] + cap_size);
+ immVertex2f(shdr_pos_2d, co_ss[1][0] + cap_size, co_ss[1][1] - cap_size);
immEnd();
GPU_line_width(1.0f);
@@ -692,25 +755,33 @@ static void gizmo_ruler_draw(const bContext *C, wmGizmo *gz)
immUniformColor3ubv(color_wire);
- immBegin(GPU_PRIM_LINES, 8);
+ if (proj_ok[0] || proj_ok[2] || proj_ok[1]) {
+ immBegin(GPU_PRIM_LINES, proj_ok[0] * 2 + proj_ok[2] * 2 + proj_ok[1] * 4);
- madd_v2_v2v2fl(cap, co_ss[0], rot_90_vec_a, cap_size);
- immVertex2fv(shdr_pos, cap);
- madd_v2_v2v2fl(cap, co_ss[0], rot_90_vec_a, -cap_size);
- immVertex2fv(shdr_pos, cap);
+ if (proj_ok[0]) {
+ madd_v2_v2v2fl(cap, co_ss[0], rot_90_vec_a, cap_size);
+ immVertex2fv(shdr_pos_2d, cap);
+ madd_v2_v2v2fl(cap, co_ss[0], rot_90_vec_a, -cap_size);
+ immVertex2fv(shdr_pos_2d, cap);
+ }
- madd_v2_v2v2fl(cap, co_ss[2], rot_90_vec_b, cap_size);
- immVertex2fv(shdr_pos, cap);
- madd_v2_v2v2fl(cap, co_ss[2], rot_90_vec_b, -cap_size);
- immVertex2fv(shdr_pos, cap);
+ if (proj_ok[2]) {
+ madd_v2_v2v2fl(cap, co_ss[2], rot_90_vec_b, cap_size);
+ immVertex2fv(shdr_pos_2d, cap);
+ madd_v2_v2v2fl(cap, co_ss[2], rot_90_vec_b, -cap_size);
+ immVertex2fv(shdr_pos_2d, cap);
+ }
- /* angle vertex */
- immVertex2f(shdr_pos, co_ss[1][0] - cap_size, co_ss[1][1] - cap_size);
- immVertex2f(shdr_pos, co_ss[1][0] + cap_size, co_ss[1][1] + cap_size);
- immVertex2f(shdr_pos, co_ss[1][0] - cap_size, co_ss[1][1] + cap_size);
- immVertex2f(shdr_pos, co_ss[1][0] + cap_size, co_ss[1][1] - cap_size);
+ /* angle vertex */
+ if (proj_ok[1]) {
+ immVertex2f(shdr_pos_2d, co_ss[1][0] - cap_size, co_ss[1][1] - cap_size);
+ immVertex2f(shdr_pos_2d, co_ss[1][0] + cap_size, co_ss[1][1] + cap_size);
+ immVertex2f(shdr_pos_2d, co_ss[1][0] - cap_size, co_ss[1][1] + cap_size);
+ immVertex2f(shdr_pos_2d, co_ss[1][0] + cap_size, co_ss[1][1] - cap_size);
+ }
- immEnd();
+ immEnd();
+ }
GPU_blend(false);
}
@@ -729,10 +800,10 @@ static void gizmo_ruler_draw(const bContext *C, wmGizmo *gz)
posit[1] = co_ss[1][1] - (numstr_size[1] / 2.0f);
/* draw text (bg) */
- {
+ if (proj_ok[1]) {
immUniformColor4fv(color_back);
GPU_blend(true);
- immRectf(shdr_pos,
+ immRectf(shdr_pos_2d,
posit[0] - bg_margin,
posit[1] - bg_margin,
posit[0] + bg_margin + numstr_size[0],
@@ -743,7 +814,7 @@ static void gizmo_ruler_draw(const bContext *C, wmGizmo *gz)
immUnbindProgram();
/* draw text */
- {
+ if (proj_ok[1]) {
BLF_color3ubv(blf_mono_font, color_text);
BLF_position(blf_mono_font, posit[0], posit[1], 0.0f);
BLF_rotation(blf_mono_font, 0.0f);
@@ -751,30 +822,6 @@ static void gizmo_ruler_draw(const bContext *C, wmGizmo *gz)
}
}
else {
- immBindBuiltinProgram(GPU_SHADER_2D_LINE_DASHED_UNIFORM_COLOR);
-
- float viewport_size[4];
- GPU_viewport_size_get_f(viewport_size);
- immUniform2f("viewport_size", viewport_size[2], viewport_size[3]);
-
- immUniform1i("colors_len", 2); /* "advanced" mode */
- const float *col = is_act ? color_act : color_base;
- immUniformArray4fv(
- "colors",
- (float *)(float[][4]){{0.67f, 0.67f, 0.67f, 1.0f}, {col[0], col[1], col[2], col[3]}},
- 2);
- immUniform1f("dash_width", 6.0f);
- immUniform1f("dash_factor", 0.5f);
-
- immBegin(GPU_PRIM_LINES, 2);
-
- immVertex2fv(shdr_pos, co_ss[0]);
- immVertex2fv(shdr_pos, co_ss[2]);
-
- immEnd();
-
- immUnbindProgram();
-
immBindBuiltinProgram(GPU_SHADER_2D_UNIFORM_COLOR);
sub_v2_v2v2(dir_ruler, co_ss[0], co_ss[2]);
@@ -790,19 +837,25 @@ static void gizmo_ruler_draw(const bContext *C, wmGizmo *gz)
immUniformColor3ubv(color_wire);
- immBegin(GPU_PRIM_LINES, 4);
+ if (proj_ok[0] || proj_ok[2]) {
+ immBegin(GPU_PRIM_LINES, proj_ok[0] * 2 + proj_ok[2] * 2);
- madd_v2_v2v2fl(cap, co_ss[0], rot_90_vec, cap_size);
- immVertex2fv(shdr_pos, cap);
- madd_v2_v2v2fl(cap, co_ss[0], rot_90_vec, -cap_size);
- immVertex2fv(shdr_pos, cap);
+ if (proj_ok[0]) {
+ madd_v2_v2v2fl(cap, co_ss[0], rot_90_vec, cap_size);
+ immVertex2fv(shdr_pos_2d, cap);
+ madd_v2_v2v2fl(cap, co_ss[0], rot_90_vec, -cap_size);
+ immVertex2fv(shdr_pos_2d, cap);
+ }
- madd_v2_v2v2fl(cap, co_ss[2], rot_90_vec, cap_size);
- immVertex2fv(shdr_pos, cap);
- madd_v2_v2v2fl(cap, co_ss[2], rot_90_vec, -cap_size);
- immVertex2fv(shdr_pos, cap);
+ if (proj_ok[2]) {
+ madd_v2_v2v2fl(cap, co_ss[2], rot_90_vec, cap_size);
+ immVertex2fv(shdr_pos_2d, cap);
+ madd_v2_v2v2fl(cap, co_ss[2], rot_90_vec, -cap_size);
+ immVertex2fv(shdr_pos_2d, cap);
+ }
- immEnd();
+ immEnd();
+ }
GPU_blend(false);
}
@@ -824,10 +877,10 @@ static void gizmo_ruler_draw(const bContext *C, wmGizmo *gz)
posit[1] -= numstr_size[1] / 2.0f;
/* draw text (bg) */
- {
+ if (proj_ok[0] && proj_ok[2]) {
immUniformColor4fv(color_back);
GPU_blend(true);
- immRectf(shdr_pos,
+ immRectf(shdr_pos_2d,
posit[0] - bg_margin,
posit[1] - bg_margin,
posit[0] + bg_margin + numstr_size[0],
@@ -838,7 +891,7 @@ static void gizmo_ruler_draw(const bContext *C, wmGizmo *gz)
immUnbindProgram();
/* draw text */
- {
+ if (proj_ok[0] && proj_ok[2]) {
BLF_color3ubv(blf_mono_font, color_text);
BLF_position(blf_mono_font, posit[0], posit[1], 0.0f);
BLF_draw(blf_mono_font, numstr, sizeof(numstr));
@@ -849,27 +902,10 @@ static void gizmo_ruler_draw(const bContext *C, wmGizmo *gz)
BLF_disable(blf_mono_font, BLF_ROTATION);
-#undef ARC_STEPS
-
- /* draw snap */
- if ((ruler_info->snap_flag & RULER_SNAP_OK) && (ruler_info->state == RULER_STATE_DRAG) &&
- (ruler_item->gz.interaction_data != NULL)) {
- RulerInteraction *inter = ruler_item->gz.interaction_data;
- /* size from drawSnapping */
- const float size = 2.5f * UI_GetThemeValuef(TH_VERTEX_SIZE);
- float co_ss_snap[3];
- ED_view3d_project_float_global(
- region, ruler_item->co[inter->co_index], co_ss_snap, V3D_PROJ_TEST_NOP);
-
- uint pos = GPU_vertformat_attr_add(immVertexFormat(), "pos", GPU_COMP_F32, 2, GPU_FETCH_FLOAT);
+ GPU_matrix_pop();
+ GPU_matrix_pop_projection();
- immBindBuiltinProgram(GPU_SHADER_2D_UNIFORM_COLOR);
- immUniformThemeColor3(TH_GIZMO_VIEW_ALIGN);
-
- imm_draw_circle_wire_2d(pos, co_ss_snap[0], co_ss_snap[1], size * U.pixelsize, 32);
-
- immUnbindProgram();
- }
+#undef ARC_STEPS
}
static int gizmo_ruler_test_select(bContext *UNUSED(C), wmGizmo *gz, const int mval[2])
@@ -902,35 +938,36 @@ static int gizmo_ruler_modal(bContext *C,
RulerInfo *ruler_info = gz->parent_gzgroup->customdata;
RulerItem *ruler_item = (RulerItem *)gz;
ARegion *region = CTX_wm_region(C);
- bool do_cursor_update = false;
+ bool do_cursor_update = (event->val == KM_RELEASE) || (event->type == MOUSEMOVE);
ruler_info->region = region;
- switch (event->type) {
- case MOUSEMOVE: {
- do_cursor_update = true;
- break;
- }
- }
-
- const bool do_snap = tweak_flag & WM_GIZMO_TWEAK_SNAP;
+#ifndef USE_SNAP_DETECT_FROM_KEYMAP_HACK
+ const bool do_snap = !(tweak_flag & WM_GIZMO_TWEAK_SNAP);
+#endif
const bool do_thickness = tweak_flag & WM_GIZMO_TWEAK_PRECISE;
- if ((ruler_info->drag_state_prev.do_snap != do_snap) ||
- (ruler_info->drag_state_prev.do_thickness != do_thickness)) {
+ if ((ruler_info->drag_state_prev.do_thickness != do_thickness)) {
do_cursor_update = true;
}
if (do_cursor_update) {
if (ruler_info->state == RULER_STATE_DRAG) {
struct Depsgraph *depsgraph = CTX_data_ensure_evaluated_depsgraph(C);
- if (view3d_ruler_item_mousemove(
- depsgraph, ruler_info, ruler_item, event->mval, do_thickness, do_snap)) {
+ if (view3d_ruler_item_mousemove(depsgraph,
+ ruler_info,
+ ruler_item,
+ event->mval,
+ do_thickness
+#ifndef USE_SNAP_DETECT_FROM_KEYMAP_HACK
+ ,
+ do_snap
+#endif
+ )) {
do_draw = true;
}
}
}
- ruler_info->drag_state_prev.do_snap = do_snap;
ruler_info->drag_state_prev.do_thickness = do_thickness;
if (do_draw) {
@@ -957,7 +994,7 @@ static int gizmo_ruler_invoke(bContext *C, wmGizmo *gz, const wmEvent *event)
/* Add Center Point */
ruler_item_pick->flag |= RULERITEM_USE_ANGLE;
inter->co_index = 1;
- ruler_state_set(C, ruler_info, RULER_STATE_DRAG);
+ ruler_state_set(ruler_info, RULER_STATE_DRAG);
/* find the factor */
{
@@ -978,13 +1015,21 @@ static int gizmo_ruler_invoke(bContext *C, wmGizmo *gz, const wmEvent *event)
/* update the new location */
struct Depsgraph *depsgraph = CTX_data_ensure_evaluated_depsgraph(C);
- view3d_ruler_item_mousemove(
- depsgraph, ruler_info, ruler_item_pick, event->mval, false, false);
+ view3d_ruler_item_mousemove(depsgraph,
+ ruler_info,
+ ruler_item_pick,
+ event->mval,
+ false
+#ifndef USE_SNAP_DETECT_FROM_KEYMAP_HACK
+ ,
+ false
+#endif
+ );
}
}
else {
inter->co_index = gz->highlight_part;
- ruler_state_set(C, ruler_info, RULER_STATE_DRAG);
+ ruler_state_set(ruler_info, RULER_STATE_DRAG);
/* store the initial depth */
copy_v3_v3(inter->drag_start_co, ruler_item_pick->co[inter->co_index]);
@@ -997,6 +1042,28 @@ static int gizmo_ruler_invoke(bContext *C, wmGizmo *gz, const wmEvent *event)
ruler_item_pick->flag &= ~RULERITEM_USE_ANGLE_ACTIVE;
}
+ {
+ /* Set Snap prev point. */
+ float *prev_point;
+ if (ruler_item_pick->flag & RULERITEM_USE_ANGLE) {
+ prev_point = (inter->co_index != 1) ? ruler_item_pick->co[1] : NULL;
+ }
+ else if (inter->co_index == 0) {
+ prev_point = ruler_item_pick->co[2];
+ }
+ else {
+ prev_point = ruler_item_pick->co[0];
+ }
+
+ if (prev_point) {
+ RNA_property_float_set_array(
+ ruler_info->snap_data.gizmo->ptr, ruler_info->snap_data.prop_prevpoint, prev_point);
+ }
+ else {
+ RNA_property_unset(ruler_info->snap_data.gizmo->ptr, ruler_info->snap_data.prop_prevpoint);
+ }
+ }
+
ruler_info->item_active = ruler_item_pick;
return OPERATOR_RUNNING_MODAL;
@@ -1009,10 +1076,9 @@ static void gizmo_ruler_exit(bContext *C, wmGizmo *gz, const bool cancel)
if (!cancel) {
if (ruler_info->state == RULER_STATE_DRAG) {
- if (ruler_info->snap_flag & RULER_SNAP_OK) {
- ruler_info->snap_flag &= ~RULER_SNAP_OK;
- }
- ruler_state_set(C, ruler_info, RULER_STATE_NORMAL);
+ WM_gizmo_set_flag(ruler_info->snap_data.gizmo, WM_GIZMO_HIDDEN, false);
+ RNA_property_unset(ruler_info->snap_data.gizmo->ptr, ruler_info->snap_data.prop_prevpoint);
+ ruler_state_set(ruler_info, RULER_STATE_NORMAL);
}
/* We could convert only the current gizmo, for now just re-generate. */
view3d_ruler_to_gpencil(C, gzgroup);
@@ -1022,7 +1088,7 @@ static void gizmo_ruler_exit(bContext *C, wmGizmo *gz, const bool cancel)
MEM_SAFE_FREE(gz->interaction_data);
}
- ruler_state_set(C, ruler_info, RULER_STATE_NORMAL);
+ ruler_state_set(ruler_info, RULER_STATE_NORMAL);
}
static int gizmo_ruler_cursor_get(wmGizmo *gz)
@@ -1059,16 +1125,39 @@ static void WIDGETGROUP_ruler_setup(const bContext *C, wmGizmoGroup *gzgroup)
{
RulerInfo *ruler_info = MEM_callocN(sizeof(RulerInfo), __func__);
+ wmGizmo *gizmo;
+ {
+ /* The gizmo snap has to be the first gizmo. */
+ const wmGizmoType *gzt_snap;
+ gzt_snap = WM_gizmotype_find("GIZMO_GT_snap_3d", true);
+ gizmo = WM_gizmo_new_ptr(gzt_snap, gzgroup, NULL);
+ RNA_enum_set(gizmo->ptr,
+ "snap_elements_force",
+ (SCE_SNAP_MODE_VERTEX | SCE_SNAP_MODE_EDGE | SCE_SNAP_MODE_FACE |
+ /* SCE_SNAP_MODE_VOLUME | SCE_SNAP_MODE_GRID | SCE_SNAP_MODE_INCREMENT | */
+ SCE_SNAP_MODE_EDGE_PERPENDICULAR | SCE_SNAP_MODE_EDGE_MIDPOINT));
+
+ WM_gizmo_set_color(gizmo, (float[4]){1.0f, 1.0f, 1.0f, 1.0f});
+
+ wmOperatorType *ot = WM_operatortype_find("VIEW3D_OT_ruler_add", true);
+ WM_gizmo_operator_set(gizmo, 0, ot, NULL);
+ }
+
if (view3d_ruler_from_gpencil(C, gzgroup)) {
/* nop */
}
+ wmWindowManager *wm = CTX_wm_manager(C);
wmWindow *win = CTX_wm_window(C);
- ScrArea *sa = CTX_wm_area(C);
+ ScrArea *area = CTX_wm_area(C);
ARegion *region = CTX_wm_region(C);
+
+ ruler_info->wm = wm;
ruler_info->win = win;
- ruler_info->sa = sa;
+ ruler_info->area = area;
ruler_info->region = region;
+ ruler_info->snap_data.gizmo = gizmo;
+ ruler_info->snap_data.prop_prevpoint = RNA_struct_find_property(gizmo->ptr, "prev_point");
gzgroup->customdata = ruler_info;
}
@@ -1078,7 +1167,7 @@ void VIEW3D_GGT_ruler(wmGizmoGroupType *gzgt)
gzgt->name = "Ruler Widgets";
gzgt->idname = view3d_gzgt_ruler_id;
- gzgt->flag |= WM_GIZMOGROUPTYPE_SCALE | WM_GIZMOGROUPTYPE_DRAW_MODAL_ALL;
+ gzgt->flag |= WM_GIZMOGROUPTYPE_3D | WM_GIZMOGROUPTYPE_SCALE | WM_GIZMOGROUPTYPE_DRAW_MODAL_ALL;
gzgt->gzmap_params.spaceid = SPACE_VIEW3D;
gzgt->gzmap_params.regionid = RGN_TYPE_WINDOW;
@@ -1132,8 +1221,20 @@ static int view3d_ruler_add_invoke(bContext *C, wmOperator *op, const wmEvent *e
struct Depsgraph *depsgraph = CTX_data_ensure_evaluated_depsgraph(C);
/* snap the first point added, not essential but handy */
inter->co_index = 0;
- view3d_ruler_item_mousemove(depsgraph, ruler_info, ruler_item, event->mval, false, true);
+ view3d_ruler_item_mousemove(depsgraph,
+ ruler_info,
+ ruler_item,
+ event->mval,
+ false
+#ifndef USE_SNAP_DETECT_FROM_KEYMAP_HACK
+ ,
+ true
+#endif
+ );
copy_v3_v3(inter->drag_start_co, ruler_item->co[inter->co_index]);
+ RNA_property_float_set_array(ruler_info->snap_data.gizmo->ptr,
+ ruler_info->snap_data.prop_prevpoint,
+ inter->drag_start_co);
}
else {
negate_v3_v3(inter->drag_start_co, rv3d->ofs);
@@ -1152,6 +1253,7 @@ void VIEW3D_OT_ruler_add(wmOperatorType *ot)
/* identifiers */
ot->name = "Ruler Add";
ot->idname = "VIEW3D_OT_ruler_add";
+ ot->description = "Add ruler";
ot->invoke = view3d_ruler_add_invoke;
ot->poll = view3d_ruler_poll;
diff --git a/source/blender/editors/space_view3d/view3d_header.c b/source/blender/editors/space_view3d/view3d_header.c
index 57989680705..829d793333e 100644
--- a/source/blender/editors/space_view3d/view3d_header.c
+++ b/source/blender/editors/space_view3d/view3d_header.c
@@ -77,7 +77,8 @@ static int toggle_matcap_flip(bContext *C, wmOperator *UNUSED(op))
else {
Scene *scene = CTX_data_scene(C);
scene->display.shading.flag ^= V3D_SHADING_MATCAP_FLIP_X;
- WM_event_add_notifier(C, NC_SCENE | NA_EDITED, v3d);
+ DEG_id_tag_update(&scene->id, ID_RECALC_COPY_ON_WRITE);
+ WM_event_add_notifier(C, NC_SCENE | ND_RENDER_OPTIONS, scene);
}
return OPERATOR_FINISHED;
@@ -105,7 +106,7 @@ static void do_view3d_header_buttons(bContext *C, void *UNUSED(arg), int event)
wmWindow *win = CTX_wm_window(C);
const int ctrl = win->eventstate->ctrl, shift = win->eventstate->shift;
- /* watch it: if sa->win does not exist, check that when calling direct drawing routines */
+ /* watch it: if area->win does not exist, check that when calling direct drawing routines */
switch (event) {
case B_SEL_VERT:
@@ -138,10 +139,11 @@ void uiTemplateEditModeSelection(uiLayout *layout, struct bContext *C)
if (obedit && (obedit->type == OB_MESH)) {
BMEditMesh *em = BKE_editmesh_from_object(obedit);
uiLayout *row;
+ uiBut *but;
row = uiLayoutRow(layout, true);
block = uiLayoutGetBlock(row);
- uiDefIconButBitS(
+ but = uiDefIconButBitS(
block,
UI_BTYPE_TOGGLE,
SCE_SELECT_VERTEX,
@@ -157,23 +159,26 @@ void uiTemplateEditModeSelection(uiLayout *layout, struct bContext *C)
0,
0,
TIP_("Vertex select - Shift-Click for multiple modes, Ctrl-Click contracts selection"));
- uiDefIconButBitS(block,
- UI_BTYPE_TOGGLE,
- SCE_SELECT_EDGE,
- B_SEL_EDGE,
- ICON_EDGESEL,
- 0,
- 0,
- ceilf(UI_UNIT_X - U.pixelsize),
- UI_UNIT_Y,
- &em->selectmode,
- 1.0,
- 0.0,
- 0,
- 0,
- TIP_("Edge select - Shift-Click for multiple modes, Ctrl-Click "
- "expands/contracts selection"));
- uiDefIconButBitS(
+ UI_but_flag_disable(but, UI_BUT_UNDO);
+ but = uiDefIconButBitS(
+ block,
+ UI_BTYPE_TOGGLE,
+ SCE_SELECT_EDGE,
+ B_SEL_EDGE,
+ ICON_EDGESEL,
+ 0,
+ 0,
+ ceilf(UI_UNIT_X - U.pixelsize),
+ UI_UNIT_Y,
+ &em->selectmode,
+ 1.0,
+ 0.0,
+ 0,
+ 0,
+ TIP_("Edge select - Shift-Click for multiple modes, "
+ "Ctrl-Click expands/contracts selection depending on the current mode"));
+ UI_but_flag_disable(but, UI_BUT_UNDO);
+ but = uiDefIconButBitS(
block,
UI_BTYPE_TOGGLE,
SCE_SELECT_FACE,
@@ -189,6 +194,7 @@ void uiTemplateEditModeSelection(uiLayout *layout, struct bContext *C)
0,
0,
TIP_("Face select - Shift-Click for multiple modes, Ctrl-Click expands selection"));
+ UI_but_flag_disable(but, UI_BUT_UNDO);
}
}
diff --git a/source/blender/editors/space_view3d/view3d_intern.h b/source/blender/editors/space_view3d/view3d_intern.h
index 610c40c37eb..50cd71d7edc 100644
--- a/source/blender/editors/space_view3d/view3d_intern.h
+++ b/source/blender/editors/space_view3d/view3d_intern.h
@@ -91,8 +91,8 @@ void VIEW3D_OT_zoom_border(struct wmOperatorType *ot);
void VIEW3D_OT_toggle_shading(struct wmOperatorType *ot);
void VIEW3D_OT_toggle_xray(struct wmOperatorType *ot);
-void view3d_boxview_copy(struct ScrArea *sa, struct ARegion *region);
-void view3d_boxview_sync(struct ScrArea *sa, struct ARegion *region);
+void view3d_boxview_copy(struct ScrArea *area, struct ARegion *region);
+void view3d_boxview_sync(struct ScrArea *area, struct ARegion *region);
void view3d_orbit_apply_dyn_ofs(float r_ofs[3],
const float ofs_old[3],
@@ -181,7 +181,7 @@ typedef struct V3D_SmoothParams {
void ED_view3d_smooth_view_ex(const struct Depsgraph *depsgraph,
struct wmWindowManager *wm,
struct wmWindow *win,
- struct ScrArea *sa,
+ struct ScrArea *area,
struct View3D *v3d,
struct ARegion *region,
const int smooth_viewtx,
@@ -213,6 +213,7 @@ void viewrotate_modal_keymap(struct wmKeyConfig *keyconf);
void viewmove_modal_keymap(struct wmKeyConfig *keyconf);
void viewzoom_modal_keymap(struct wmKeyConfig *keyconf);
void viewdolly_modal_keymap(struct wmKeyConfig *keyconf);
+void viewplace_modal_keymap(struct wmKeyConfig *keyconf);
/* view3d_buttons.c */
void VIEW3D_OT_object_mode_pie_or_toggle(struct wmOperatorType *ot);
@@ -243,6 +244,9 @@ void VIEW3D_OT_snap_cursor_to_center(struct wmOperatorType *ot);
void VIEW3D_OT_snap_cursor_to_selected(struct wmOperatorType *ot);
void VIEW3D_OT_snap_cursor_to_active(struct wmOperatorType *ot);
+/* view3d_placement.c */
+void VIEW3D_OT_interactive_add(struct wmOperatorType *ot);
+
/* space_view3d.c */
extern const char *view3d_context_dir[]; /* doc access */
@@ -268,6 +272,8 @@ void VIEW3D_OT_ruler_remove(struct wmOperatorType *ot);
void VIEW3D_GT_navigate_rotate(struct wmGizmoType *gzt);
+void VIEW3D_GGT_placement(struct wmGizmoGroupType *gzgt);
+
/* workaround for trivial but noticeable camera bug caused by imprecision
* between view border calculation in 2D/3D space, workaround for bug [#28037].
* without this define we get the old behavior which is to try and align them
diff --git a/source/blender/editors/space_view3d/view3d_iterators.c b/source/blender/editors/space_view3d/view3d_iterators.c
index d8e1c8c1c72..91e629147f4 100644
--- a/source/blender/editors/space_view3d/view3d_iterators.c
+++ b/source/blender/editors/space_view3d/view3d_iterators.c
@@ -126,7 +126,7 @@ void meshobject_foreachScreenVert(
Scene *scene_eval = DEG_get_evaluated_scene(vc->depsgraph);
Object *ob_eval = DEG_get_evaluated_object(vc->depsgraph, vc->obact);
- me = mesh_get_eval_deform(vc->depsgraph, scene_eval, ob_eval, &CD_MASK_BAREMESH);
+ me = mesh_get_eval_final(vc->depsgraph, scene_eval, ob_eval, &CD_MASK_BAREMESH);
ED_view3d_check_mats_rv3d(vc->rv3d);
@@ -388,7 +388,7 @@ void mesh_foreachScreenFace(
BM_mesh_elem_table_ensure(vc->em->bm, BM_FACE);
- if (modifiers_usesSubsurfFacedots(vc->scene, vc->obedit)) {
+ if (BKE_modifiers_uses_subsurf_facedots(vc->scene, vc->obedit)) {
BKE_mesh_foreach_mapped_subdiv_face_center(
me, mesh_foreachScreenFace__mapFunc, &data, MESH_FOREACH_NOP);
}
@@ -406,6 +406,7 @@ void nurbs_foreachScreenVert(ViewContext *vc,
BPoint *bp,
BezTriple *bezt,
int beztindex,
+ bool handles_visible,
const float screen_co_b[2]),
void *userData,
const eV3DProjTest clip_flag)
@@ -414,6 +415,8 @@ void nurbs_foreachScreenVert(ViewContext *vc,
Nurb *nu;
int i;
ListBase *nurbs = BKE_curve_editNurbs_get(cu);
+ /* If no point in the triple is selected, the handles are invisible. */
+ const bool only_selected = (vc->v3d->overlay.handle_display == CURVE_HANDLE_SELECTED);
ED_view3d_check_mats_rv3d(vc->rv3d);
@@ -427,15 +430,17 @@ void nurbs_foreachScreenVert(ViewContext *vc,
BezTriple *bezt = &nu->bezt[i];
if (bezt->hide == 0) {
+ const bool handles_visible = (vc->v3d->overlay.handle_display != CURVE_HANDLE_NONE) &&
+ (!only_selected || BEZT_ISSEL_ANY(bezt));
float screen_co[2];
- if ((vc->v3d->overlay.edit_flag & V3D_OVERLAY_EDIT_CU_HANDLES) == 0) {
+ if (!handles_visible) {
if (ED_view3d_project_float_object(vc->region,
bezt->vec[1],
screen_co,
V3D_PROJ_RET_CLIP_BB | V3D_PROJ_RET_CLIP_WIN) ==
V3D_PROJ_RET_OK) {
- func(userData, nu, NULL, bezt, 1, screen_co);
+ func(userData, nu, NULL, bezt, 1, false, screen_co);
}
}
else {
@@ -444,21 +449,21 @@ void nurbs_foreachScreenVert(ViewContext *vc,
screen_co,
V3D_PROJ_RET_CLIP_BB | V3D_PROJ_RET_CLIP_WIN) ==
V3D_PROJ_RET_OK) {
- func(userData, nu, NULL, bezt, 0, screen_co);
+ func(userData, nu, NULL, bezt, 0, true, screen_co);
}
if (ED_view3d_project_float_object(vc->region,
bezt->vec[1],
screen_co,
V3D_PROJ_RET_CLIP_BB | V3D_PROJ_RET_CLIP_WIN) ==
V3D_PROJ_RET_OK) {
- func(userData, nu, NULL, bezt, 1, screen_co);
+ func(userData, nu, NULL, bezt, 1, true, screen_co);
}
if (ED_view3d_project_float_object(vc->region,
bezt->vec[2],
screen_co,
V3D_PROJ_RET_CLIP_BB | V3D_PROJ_RET_CLIP_WIN) ==
V3D_PROJ_RET_OK) {
- func(userData, nu, NULL, bezt, 2, screen_co);
+ func(userData, nu, NULL, bezt, 2, true, screen_co);
}
}
}
@@ -473,7 +478,7 @@ void nurbs_foreachScreenVert(ViewContext *vc,
if (ED_view3d_project_float_object(
vc->region, bp->vec, screen_co, V3D_PROJ_RET_CLIP_BB | V3D_PROJ_RET_CLIP_WIN) ==
V3D_PROJ_RET_OK) {
- func(userData, nu, bp, NULL, -1, screen_co);
+ func(userData, nu, bp, NULL, -1, false, screen_co);
}
}
}
diff --git a/source/blender/editors/space_view3d/view3d_ops.c b/source/blender/editors/space_view3d/view3d_ops.c
index a53262df267..0770bac1313 100644
--- a/source/blender/editors/space_view3d/view3d_ops.c
+++ b/source/blender/editors/space_view3d/view3d_ops.c
@@ -47,6 +47,7 @@
#include "WM_api.h"
#include "WM_types.h"
+#include "ED_outliner.h"
#include "ED_screen.h"
#include "ED_select_utils.h"
#include "ED_transform.h"
@@ -117,6 +118,7 @@ static int view3d_pastebuffer_exec(bContext *C, wmOperator *op)
}
WM_event_add_notifier(C, NC_WINDOW, NULL);
+ ED_outliner_select_sync_from_object_tag(C);
BKE_reportf(op->reports, RPT_INFO, "%d object(s) pasted", num_pasted);
@@ -209,6 +211,8 @@ void view3d_operatortypes(void)
WM_operatortype_append(VIEW3D_OT_snap_cursor_to_selected);
WM_operatortype_append(VIEW3D_OT_snap_cursor_to_active);
+ WM_operatortype_append(VIEW3D_OT_interactive_add);
+
WM_operatortype_append(VIEW3D_OT_toggle_shading);
WM_operatortype_append(VIEW3D_OT_toggle_xray);
WM_operatortype_append(VIEW3D_OT_toggle_matcap_flip);
@@ -232,4 +236,5 @@ void view3d_keymap(wmKeyConfig *keyconf)
viewmove_modal_keymap(keyconf);
viewzoom_modal_keymap(keyconf);
viewdolly_modal_keymap(keyconf);
+ viewplace_modal_keymap(keyconf);
}
diff --git a/source/blender/editors/space_view3d/view3d_placement.c b/source/blender/editors/space_view3d/view3d_placement.c
new file mode 100644
index 00000000000..f2b78bc2aaf
--- /dev/null
+++ b/source/blender/editors/space_view3d/view3d_placement.c
@@ -0,0 +1,1153 @@
+/*
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+
+/** \file
+ * \ingroup spview3d
+ *
+ * Operator to interactively place data.
+ *
+ * Currently only adds meshes, but could add other kinds of data
+ * including library assets & non-mesh types.
+ */
+
+#include "BLI_math_vector.h"
+#include "MEM_guardedalloc.h"
+
+#include "DNA_collection_types.h"
+#include "DNA_object_types.h"
+#include "DNA_scene_types.h"
+#include "DNA_vfont_types.h"
+
+#include "BLI_math.h"
+#include "BLI_utildefines.h"
+
+#include "BKE_context.h"
+#include "BKE_main.h"
+
+#include "RNA_access.h"
+#include "RNA_define.h"
+#include "RNA_enum_types.h"
+
+#include "WM_api.h"
+#include "WM_toolsystem.h"
+#include "WM_types.h"
+
+#include "ED_gizmo_library.h"
+#include "ED_gizmo_utils.h"
+#include "ED_screen.h"
+#include "ED_space_api.h"
+#include "ED_transform.h"
+#include "ED_transform_snap_object_context.h"
+#include "ED_view3d.h"
+
+#include "UI_resources.h"
+
+#include "GPU_batch.h"
+#include "GPU_immediate.h"
+#include "GPU_state.h"
+
+#include "view3d_intern.h"
+
+static const char *view3d_gzgt_placement_id = "VIEW3D_GGT_placement";
+
+/* -------------------------------------------------------------------- */
+/** \name Local Types
+ * \{ */
+
+enum ePlace_PrimType {
+ PLACE_PRIMITIVE_TYPE_CUBE = 1,
+ PLACE_PRIMITIVE_TYPE_CYLINDER = 2,
+ PLACE_PRIMITIVE_TYPE_CONE = 3,
+ PLACE_PRIMITIVE_TYPE_SPHERE_UV = 4,
+ PLACE_PRIMITIVE_TYPE_SPHERE_ICO = 5,
+};
+
+enum ePlace_Origin {
+ PLACE_ORIGIN_BASE = 1,
+ PLACE_ORIGIN_CENTER = 2,
+};
+
+enum ePlace_Depth {
+ PLACE_DEPTH_SURFACE = 1,
+ PLACE_DEPTH_CURSOR_PLANE = 2,
+ PLACE_DEPTH_CURSOR_VIEW = 3,
+};
+
+struct InteractivePlaceData {
+ /* Window manager variables (set these even when waiting for input). */
+ Scene *scene;
+ ScrArea *area;
+ View3D *v3d;
+ ARegion *region;
+
+ /** Draw object preview region draw callback. */
+ void *draw_handle_view;
+
+ float co_src[3];
+
+ /** Primary & secondary steps. */
+ struct {
+ bool is_centered;
+ bool is_fixed_aspect;
+ float plane[4];
+ float co_dst[3];
+ } step[2];
+
+ float matrix_orient[3][3];
+ int orient_axis;
+
+ /** The tool option, if we start centered, invert toggling behavior. */
+ bool is_centered_init;
+
+ bool use_snap, is_snap_found, is_snap_invert;
+ float snap_co[3];
+
+ /** Can index into #InteractivePlaceData.step. */
+ enum {
+ STEP_BASE = 0,
+ STEP_DEPTH = 1,
+ } step_index;
+
+ enum ePlace_PrimType primitive_type;
+
+ /** Activated from the tool-system. */
+ bool use_tool;
+
+ /** Event used to start the operator. */
+ short launch_event;
+
+ /** When activated without a tool. */
+ bool wait_for_input;
+
+ /** Optional snap gizmo, needed for snapping. */
+ wmGizmo *snap_gizmo;
+};
+
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Internal Utilities
+ * \{ */
+
+/* On-screen snap distance. */
+#define MVAL_MAX_PX_DIST 12.0f
+
+static bool idp_snap_point_from_gizmo(wmGizmo *gz, float r_location[3])
+{
+ if (gz->state & WM_GIZMO_STATE_HIGHLIGHT) {
+ PropertyRNA *prop_location = RNA_struct_find_property(gz->ptr, "location");
+ RNA_property_float_get_array(gz->ptr, prop_location, r_location);
+ return true;
+ }
+ return false;
+}
+
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Primitive Drawing (Cube, Cone, Cylinder...)
+ * \{ */
+
+static void draw_line_loop(float coords[][3], int coords_len, const float color[4])
+{
+ GPUVertFormat *format = immVertexFormat();
+ uint pos = GPU_vertformat_attr_add(format, "pos", GPU_COMP_F32, 3, GPU_FETCH_FLOAT);
+
+ GPUVertBuf *vert = GPU_vertbuf_create_with_format(format);
+ GPU_vertbuf_data_alloc(vert, coords_len);
+
+ for (int i = 0; i < coords_len; i++) {
+ GPU_vertbuf_attr_set(vert, pos, i, coords[i]);
+ }
+
+ GPU_blend(true);
+ GPUBatch *batch = GPU_batch_create_ex(GPU_PRIM_LINE_LOOP, vert, NULL, GPU_BATCH_OWNS_VBO);
+ GPU_batch_program_set_builtin(batch, GPU_SHADER_3D_POLYLINE_UNIFORM_COLOR);
+
+ GPU_batch_bind(batch);
+
+ GPU_batch_uniform_4fv(batch, "color", color);
+
+ float viewport[4];
+ GPU_viewport_size_get_f(viewport);
+ GPU_batch_uniform_2fv(batch, "viewportSize", &viewport[2]);
+ GPU_batch_uniform_1f(batch, "lineWidth", U.pixelsize);
+
+ GPU_batch_draw(batch);
+
+ GPU_batch_program_use_end(batch);
+
+ GPU_batch_discard(batch);
+ GPU_blend(false);
+}
+
+static void draw_line_pairs(float coords_a[][3],
+ float coords_b[][3],
+ int coords_len,
+ const float color[4])
+{
+ GPUVertFormat *format = immVertexFormat();
+ uint pos = GPU_vertformat_attr_add(format, "pos", GPU_COMP_F32, 3, GPU_FETCH_FLOAT);
+
+ GPUVertBuf *vert = GPU_vertbuf_create_with_format(format);
+ GPU_vertbuf_data_alloc(vert, coords_len * 2);
+
+ for (int i = 0; i < coords_len; i++) {
+ GPU_vertbuf_attr_set(vert, pos, i * 2, coords_a[i]);
+ GPU_vertbuf_attr_set(vert, pos, (i * 2) + 1, coords_b[i]);
+ }
+
+ GPU_blend(true);
+ GPUBatch *batch = GPU_batch_create_ex(GPU_PRIM_LINES, vert, NULL, GPU_BATCH_OWNS_VBO);
+ GPU_batch_program_set_builtin(batch, GPU_SHADER_3D_POLYLINE_UNIFORM_COLOR);
+
+ GPU_batch_bind(batch);
+
+ GPU_batch_uniform_4fv(batch, "color", color);
+
+ float viewport[4];
+ GPU_viewport_size_get_f(viewport);
+ GPU_batch_uniform_2fv(batch, "viewportSize", &viewport[2]);
+ GPU_batch_uniform_1f(batch, "lineWidth", U.pixelsize);
+
+ GPU_batch_draw(batch);
+
+ GPU_batch_program_use_end(batch);
+
+ GPU_batch_discard(batch);
+ GPU_blend(false);
+}
+
+static void draw_line_bounds(const BoundBox *bounds, const float color[4])
+{
+ GPUVertFormat *format = immVertexFormat();
+ uint pos = GPU_vertformat_attr_add(format, "pos", GPU_COMP_F32, 3, GPU_FETCH_FLOAT);
+
+ int edges[12][2] = {
+ /* First side. */
+ {0, 1},
+ {1, 2},
+ {2, 3},
+ {3, 0},
+ /* Second side. */
+ {4, 5},
+ {5, 6},
+ {6, 7},
+ {7, 4},
+ /* Edges between. */
+ {0, 4},
+ {1, 5},
+ {2, 6},
+ {3, 7},
+ };
+
+ GPUVertBuf *vert = GPU_vertbuf_create_with_format(format);
+ GPU_vertbuf_data_alloc(vert, ARRAY_SIZE(edges) * 2);
+
+ for (int i = 0, j = 0; i < ARRAY_SIZE(edges); i++) {
+ GPU_vertbuf_attr_set(vert, pos, j++, bounds->vec[edges[i][0]]);
+ GPU_vertbuf_attr_set(vert, pos, j++, bounds->vec[edges[i][1]]);
+ }
+
+ GPU_blend(true);
+ GPUBatch *batch = GPU_batch_create_ex(GPU_PRIM_LINES, vert, NULL, GPU_BATCH_OWNS_VBO);
+ GPU_batch_program_set_builtin(batch, GPU_SHADER_3D_POLYLINE_UNIFORM_COLOR);
+
+ GPU_batch_bind(batch);
+
+ GPU_batch_uniform_4fv(batch, "color", color);
+
+ float viewport[4];
+ GPU_viewport_size_get_f(viewport);
+ GPU_batch_uniform_2fv(batch, "viewportSize", &viewport[2]);
+ GPU_batch_uniform_1f(batch, "lineWidth", U.pixelsize);
+
+ GPU_batch_draw(batch);
+
+ GPU_batch_program_use_end(batch);
+
+ GPU_batch_discard(batch);
+ GPU_blend(false);
+}
+
+static bool calc_bbox(struct InteractivePlaceData *ipd, BoundBox *bounds)
+{
+ memset(bounds, 0x0, sizeof(*bounds));
+
+ if (compare_v3v3(ipd->co_src, ipd->step[0].co_dst, FLT_EPSILON)) {
+ return false;
+ }
+
+ float matrix_orient_inv[3][3];
+ invert_m3_m3(matrix_orient_inv, ipd->matrix_orient);
+
+ const int x_axis = (ipd->orient_axis + 1) % 3;
+ const int y_axis = (ipd->orient_axis + 2) % 3;
+
+ float quad_base[4][3];
+ float quad_secondary[4][3];
+
+ copy_v3_v3(quad_base[0], ipd->co_src);
+ copy_v3_v3(quad_base[2], ipd->step[0].co_dst);
+
+ /* Only set when we have a fixed aspect. */
+ float fixed_aspect_dimension;
+
+ /* *** Primary *** */
+
+ {
+ float delta_local[3];
+ float delta_a[3];
+ float delta_b[3];
+
+ sub_v3_v3v3(delta_local, ipd->step[0].co_dst, ipd->co_src);
+ mul_m3_v3(matrix_orient_inv, delta_local);
+
+ copy_v3_v3(delta_a, delta_local);
+ copy_v3_v3(delta_b, delta_local);
+ delta_a[ipd->orient_axis] = 0.0f;
+ delta_b[ipd->orient_axis] = 0.0f;
+
+ delta_a[x_axis] = 0.0f;
+ delta_b[y_axis] = 0.0f;
+
+ /* Assign here in case secondary */
+ fixed_aspect_dimension = max_ff(fabsf(delta_a[y_axis]), fabsf(delta_b[x_axis]));
+
+ if (ipd->step[0].is_fixed_aspect) {
+ delta_a[y_axis] = copysignf(fixed_aspect_dimension, delta_a[y_axis]);
+ delta_b[x_axis] = copysignf(fixed_aspect_dimension, delta_b[x_axis]);
+ }
+
+ mul_m3_v3(ipd->matrix_orient, delta_a);
+ mul_m3_v3(ipd->matrix_orient, delta_b);
+
+ if (ipd->step[0].is_fixed_aspect) {
+ /* Recalculate the destination point. */
+ copy_v3_v3(quad_base[2], ipd->co_src);
+ add_v3_v3(quad_base[2], delta_a);
+ add_v3_v3(quad_base[2], delta_b);
+ }
+
+ add_v3_v3v3(quad_base[1], ipd->co_src, delta_a);
+ add_v3_v3v3(quad_base[3], ipd->co_src, delta_b);
+ }
+
+ if (ipd->step[0].is_centered) {
+ /* Use a copy in case aspect was applied to the quad. */
+ float base_co_dst[3];
+ copy_v3_v3(base_co_dst, quad_base[2]);
+ for (int i = 0; i < 4; i++) {
+ sub_v3_v3(quad_base[i], base_co_dst);
+ mul_v3_fl(quad_base[i], 2.0f);
+ add_v3_v3(quad_base[i], base_co_dst);
+ }
+ }
+
+ /* *** Secondary *** */
+
+ float delta_local[3];
+ if (ipd->step_index == STEP_DEPTH) {
+ sub_v3_v3v3(delta_local, ipd->step[1].co_dst, ipd->step[0].co_dst);
+ }
+ else {
+ zero_v3(delta_local);
+ }
+
+ if (ipd->step[1].is_fixed_aspect) {
+ if (!is_zero_v3(delta_local)) {
+ normalize_v3_length(delta_local, fixed_aspect_dimension);
+ }
+ }
+
+ if (ipd->step[1].is_centered) {
+ for (int i = 0; i < ARRAY_SIZE(quad_base); i++) {
+ sub_v3_v3(quad_base[i], delta_local);
+ }
+ mul_v3_fl(delta_local, 2.0f);
+ }
+
+ if ((ipd->step_index == STEP_DEPTH) &&
+ (compare_v3v3(ipd->step[0].co_dst, ipd->step[1].co_dst, FLT_EPSILON) == false)) {
+
+ for (int i = 0; i < ARRAY_SIZE(quad_base); i++) {
+ add_v3_v3v3(quad_secondary[i], quad_base[i], delta_local);
+ }
+ }
+ else {
+ copy_v3_v3(quad_secondary[0], quad_base[0]);
+ copy_v3_v3(quad_secondary[1], quad_base[1]);
+ copy_v3_v3(quad_secondary[2], quad_base[2]);
+ copy_v3_v3(quad_secondary[3], quad_base[3]);
+ }
+
+ for (int i = 0; i < 4; i++) {
+ copy_v3_v3(bounds->vec[i], quad_base[i]);
+ copy_v3_v3(bounds->vec[i + 4], quad_secondary[i]);
+ }
+
+ return true;
+}
+
+static void draw_circle_in_quad(const float v1[2],
+ const float v2[2],
+ const float v3[2],
+ const float v4[2],
+ const int resolution,
+ const float color[4])
+{
+ /* This isn't so efficient. */
+ const float quad[4][2] = {
+ {-1, -1},
+ {+1, -1},
+ {+1, +1},
+ {-1, +1},
+ };
+
+ float(*coords)[3] = MEM_mallocN(sizeof(float[3]) * (resolution + 1), __func__);
+ for (int i = 0; i <= resolution; i++) {
+ float theta = ((2.0f * M_PI) * ((float)i / (float)resolution)) + 0.01f;
+ float x = cosf(theta);
+ float y = sinf(theta);
+ float pt[2] = {x, y};
+ float w[4];
+ barycentric_weights_v2_quad(UNPACK4(quad), pt, w);
+
+ float *co = coords[i];
+ zero_v3(co);
+ madd_v3_v3fl(co, v1, w[0]);
+ madd_v3_v3fl(co, v2, w[1]);
+ madd_v3_v3fl(co, v3, w[2]);
+ madd_v3_v3fl(co, v4, w[3]);
+ }
+ draw_line_loop(coords, resolution + 1, color);
+ MEM_freeN(coords);
+}
+
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Drawing Callbacks
+ * \{ */
+
+static void draw_primitive_view_impl(const struct bContext *C,
+ struct InteractivePlaceData *ipd,
+ const float color[4])
+{
+ UNUSED_VARS(C);
+
+ BoundBox bounds;
+ calc_bbox(ipd, &bounds);
+ draw_line_bounds(&bounds, color);
+
+ if (ipd->primitive_type == PLACE_PRIMITIVE_TYPE_CUBE) {
+ /* pass */
+ }
+ else if (ipd->primitive_type == PLACE_PRIMITIVE_TYPE_CYLINDER) {
+ draw_circle_in_quad(UNPACK4(bounds.vec), 32, color);
+ draw_circle_in_quad(UNPACK4((&bounds.vec[4])), 32, color);
+ }
+ else if (ipd->primitive_type == PLACE_PRIMITIVE_TYPE_CONE) {
+ draw_circle_in_quad(UNPACK4(bounds.vec), 32, color);
+
+ float center[3];
+ mid_v3_v3v3v3v3(center, UNPACK4((&bounds.vec[4])));
+
+ float coords_a[4][3];
+ float coords_b[4][3];
+
+ for (int i = 0; i < 4; i++) {
+ copy_v3_v3(coords_a[i], center);
+ mid_v3_v3v3(coords_b[i], bounds.vec[i], bounds.vec[(i + 1) % 4]);
+ }
+
+ draw_line_pairs(coords_a, coords_b, 4, color);
+ }
+ else if (ELEM(ipd->primitive_type,
+ PLACE_PRIMITIVE_TYPE_SPHERE_UV,
+ PLACE_PRIMITIVE_TYPE_SPHERE_ICO)) {
+ /* See bound-box diagram for reference. */
+
+ /* Primary Side. */
+ float v01[3], v12[3], v23[3], v30[3];
+ mid_v3_v3v3(v01, bounds.vec[0], bounds.vec[1]);
+ mid_v3_v3v3(v12, bounds.vec[1], bounds.vec[2]);
+ mid_v3_v3v3(v23, bounds.vec[2], bounds.vec[3]);
+ mid_v3_v3v3(v30, bounds.vec[3], bounds.vec[0]);
+ /* Secondary Side. */
+ float v45[3], v56[3], v67[3], v74[3];
+ mid_v3_v3v3(v45, bounds.vec[4], bounds.vec[5]);
+ mid_v3_v3v3(v56, bounds.vec[5], bounds.vec[6]);
+ mid_v3_v3v3(v67, bounds.vec[6], bounds.vec[7]);
+ mid_v3_v3v3(v74, bounds.vec[7], bounds.vec[4]);
+ /* Edges between. */
+ float v04[3], v15[3], v26[3], v37[3];
+ mid_v3_v3v3(v04, bounds.vec[0], bounds.vec[4]);
+ mid_v3_v3v3(v15, bounds.vec[1], bounds.vec[5]);
+ mid_v3_v3v3(v26, bounds.vec[2], bounds.vec[6]);
+ mid_v3_v3v3(v37, bounds.vec[3], bounds.vec[7]);
+
+ draw_circle_in_quad(v01, v45, v67, v23, 32, color);
+ draw_circle_in_quad(v30, v12, v56, v74, 32, color);
+ draw_circle_in_quad(v04, v15, v26, v37, 32, color);
+ }
+}
+
+static void draw_primitive_view(const struct bContext *C, ARegion *UNUSED(region), void *arg)
+{
+ struct InteractivePlaceData *ipd = arg;
+ float color[4];
+ UI_GetThemeColor3fv(TH_GIZMO_PRIMARY, color);
+
+ const bool use_depth = !XRAY_ENABLED(ipd->v3d);
+ const bool depth_test_enabled = GPU_depth_test_enabled();
+
+ if (use_depth) {
+ GPU_depth_test(false);
+ color[3] = 0.15f;
+ draw_primitive_view_impl(C, ipd, color);
+ }
+
+ if (use_depth) {
+ GPU_depth_test(true);
+ }
+ color[3] = 1.0f;
+ draw_primitive_view_impl(C, ipd, color);
+
+ if (use_depth) {
+ if (depth_test_enabled == false) {
+ GPU_depth_test(false);
+ }
+ }
+}
+
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Add Object Modal Operator
+ * \{ */
+
+/**
+ *
+ * */
+static void view3d_interactive_add_begin(bContext *C, wmOperator *op, const wmEvent *event)
+{
+
+ const int plane_axis = RNA_enum_get(op->ptr, "plane_axis");
+ const enum ePlace_Depth plane_depth = RNA_enum_get(op->ptr, "plane_depth");
+ const enum ePlace_Origin plane_origin = RNA_enum_get(op->ptr, "plane_origin");
+
+ struct InteractivePlaceData *ipd = op->customdata;
+
+ RegionView3D *rv3d = ipd->region->regiondata;
+
+ ipd->launch_event = WM_userdef_event_type_from_keymap_type(event->type);
+
+ ED_transform_calc_orientation_from_type(C, ipd->matrix_orient);
+
+ ipd->orient_axis = plane_axis;
+ ipd->is_centered_init = (plane_origin == PLACE_ORIGIN_CENTER);
+ ipd->step[0].is_centered = ipd->is_centered_init;
+ ipd->step[1].is_centered = ipd->is_centered_init;
+ ipd->step_index = STEP_BASE;
+
+ /* Assign snap gizmo which is may be used as part of the tool. */
+ {
+ wmGizmoMap *gzmap = ipd->region->gizmo_map;
+ wmGizmoGroup *gzgroup = gzmap ? WM_gizmomap_group_find(gzmap, view3d_gzgt_placement_id) : NULL;
+ if ((gzgroup != NULL) && gzgroup->gizmos.first) {
+ ipd->snap_gizmo = gzgroup->gizmos.first;
+ }
+ }
+
+ {
+ PropertyRNA *prop = RNA_struct_find_property(op->ptr, "primitive_type");
+ if (RNA_property_is_set(op->ptr, prop)) {
+ ipd->primitive_type = RNA_property_enum_get(op->ptr, prop);
+ ipd->use_tool = false;
+ }
+ else {
+ ipd->use_tool = true;
+
+ /* Get from the tool, a bit of a non-standard way of operating. */
+ const bToolRef *tref = ipd->area->runtime.tool;
+ if (tref && STREQ(tref->idname, "builtin.primitive_cube_add")) {
+ ipd->primitive_type = PLACE_PRIMITIVE_TYPE_CUBE;
+ }
+ else if (tref && STREQ(tref->idname, "builtin.primitive_cylinder_add")) {
+ ipd->primitive_type = PLACE_PRIMITIVE_TYPE_CYLINDER;
+ }
+ else if (tref && STREQ(tref->idname, "builtin.primitive_cone_add")) {
+ ipd->primitive_type = PLACE_PRIMITIVE_TYPE_CONE;
+ }
+ else if (tref && STREQ(tref->idname, "builtin.primitive_uv_sphere_add")) {
+ ipd->primitive_type = PLACE_PRIMITIVE_TYPE_SPHERE_UV;
+ }
+ else if (tref && STREQ(tref->idname, "builtin.primitive_ico_sphere_add")) {
+ ipd->primitive_type = PLACE_PRIMITIVE_TYPE_SPHERE_ICO;
+ }
+ else {
+ /* If the user runs this as an operator they should set the 'primitive_type',
+ * however running from operator search will end up at this point. */
+ ipd->primitive_type = PLACE_PRIMITIVE_TYPE_CUBE;
+ ipd->use_tool = false;
+ }
+ }
+ }
+
+ UNUSED_VARS(C, event);
+
+ ipd->draw_handle_view = ED_region_draw_cb_activate(
+ ipd->region->type, draw_primitive_view, ipd, REGION_DRAW_POST_VIEW);
+
+ ED_region_tag_redraw(ipd->region);
+
+ plane_from_point_normal_v3(
+ ipd->step[0].plane, ipd->scene->cursor.location, ipd->matrix_orient[ipd->orient_axis]);
+
+ const float mval_fl[2] = {UNPACK2(event->mval)};
+
+ const bool is_snap_found = ipd->snap_gizmo ?
+ idp_snap_point_from_gizmo(ipd->snap_gizmo, ipd->co_src) :
+ false;
+ ipd->is_snap_invert = ipd->snap_gizmo ? ED_gizmotypes_snap_3d_invert_snap_get(ipd->snap_gizmo) :
+ false;
+ {
+ const ToolSettings *ts = ipd->scene->toolsettings;
+ ipd->use_snap = (ipd->is_snap_invert == !(ts->snap_flag & SCE_SNAP));
+ }
+
+ if (is_snap_found) {
+ /* pass */
+ }
+ else {
+ bool use_depth_fallback = true;
+ if (plane_depth == PLACE_DEPTH_CURSOR_VIEW) {
+ /* View plane. */
+ ED_view3d_win_to_3d(
+ ipd->v3d, ipd->region, ipd->scene->cursor.location, mval_fl, ipd->co_src);
+ use_depth_fallback = false;
+ }
+ else if (plane_depth == PLACE_DEPTH_SURFACE) {
+ SnapObjectContext *snap_context =
+ (ipd->snap_gizmo ? ED_gizmotypes_snap_3d_context_ensure(
+ ipd->scene, ipd->region, ipd->v3d, ipd->snap_gizmo) :
+ NULL);
+ if ((snap_context != NULL) &&
+ ED_transform_snap_object_project_view3d(snap_context,
+ CTX_data_ensure_evaluated_depsgraph(C),
+ SCE_SNAP_MODE_FACE,
+ &(const struct SnapObjectParams){
+ .snap_select = SNAP_ALL,
+ .use_object_edit_cage = true,
+ },
+ mval_fl,
+ NULL,
+ NULL,
+ ipd->co_src,
+ NULL)) {
+ use_depth_fallback = false;
+ }
+ }
+
+ /* Use as fallback to surface. */
+ if (use_depth_fallback || (plane_depth == PLACE_DEPTH_CURSOR_PLANE)) {
+ /* Cursor plane. */
+ float plane[4];
+ plane_from_point_normal_v3(
+ plane, ipd->scene->cursor.location, ipd->matrix_orient[ipd->orient_axis]);
+ if (ED_view3d_win_to_3d_on_plane(ipd->region, plane, mval_fl, false, ipd->co_src)) {
+ use_depth_fallback = false;
+ }
+ /* Even if the calculation works, it's possible the point found is behind the view. */
+ if (rv3d->is_persp) {
+ float dir[3];
+ sub_v3_v3v3(dir, rv3d->viewinv[3], ipd->co_src);
+ if (dot_v3v3(dir, rv3d->viewinv[2]) < ipd->v3d->clip_start) {
+ use_depth_fallback = true;
+ }
+ }
+ }
+
+ if (use_depth_fallback) {
+ float co_depth[3];
+ /* Fallback to view center. */
+ negate_v3_v3(co_depth, rv3d->ofs);
+ ED_view3d_win_to_3d(ipd->v3d, ipd->region, co_depth, mval_fl, ipd->co_src);
+ }
+ }
+
+ plane_from_point_normal_v3(
+ ipd->step[0].plane, ipd->co_src, ipd->matrix_orient[ipd->orient_axis]);
+
+ copy_v3_v3(ipd->step[0].co_dst, ipd->co_src);
+}
+
+static int view3d_interactive_add_invoke(bContext *C, wmOperator *op, const wmEvent *event)
+{
+ const bool wait_for_input = RNA_boolean_get(op->ptr, "wait_for_input");
+
+ struct InteractivePlaceData *ipd = MEM_callocN(sizeof(*ipd), __func__);
+ op->customdata = ipd;
+
+ ipd->scene = CTX_data_scene(C);
+ ipd->area = CTX_wm_area(C);
+ ipd->region = CTX_wm_region(C);
+ ipd->v3d = CTX_wm_view3d(C);
+
+ if (wait_for_input) {
+ ipd->wait_for_input = true;
+ /* TODO: support snapping when not using with tool. */
+#if 0
+ WM_gizmo_group_type_ensure(view3d_gzgt_placement_id);
+#endif
+ }
+ else {
+ view3d_interactive_add_begin(C, op, event);
+ }
+
+ WM_event_add_modal_handler(C, op);
+
+ return OPERATOR_RUNNING_MODAL;
+}
+
+static void view3d_interactive_add_exit(bContext *C, wmOperator *op)
+{
+ UNUSED_VARS(C);
+
+ struct InteractivePlaceData *ipd = op->customdata;
+
+ ED_region_draw_cb_exit(ipd->region->type, ipd->draw_handle_view);
+
+ ED_region_tag_redraw(ipd->region);
+
+ MEM_freeN(ipd);
+}
+
+static void view3d_interactive_add_cancel(bContext *C, wmOperator *op)
+{
+ view3d_interactive_add_exit(C, op);
+}
+
+enum {
+ PLACE_MODAL_SNAP_ON,
+ PLACE_MODAL_SNAP_OFF,
+ PLACE_MODAL_FIXED_ASPECT_ON,
+ PLACE_MODAL_FIXED_ASPECT_OFF,
+ PLACE_MODAL_PIVOT_CENTER_ON,
+ PLACE_MODAL_PIVOT_CENTER_OFF,
+};
+
+void viewplace_modal_keymap(wmKeyConfig *keyconf)
+{
+ static const EnumPropertyItem modal_items[] = {
+ {PLACE_MODAL_SNAP_ON, "SNAP_ON", 0, "Snap On", ""},
+ {PLACE_MODAL_SNAP_OFF, "SNAP_OFF", 0, "Snap Off", ""},
+ {PLACE_MODAL_FIXED_ASPECT_ON, "FIXED_ASPECT_ON", 0, "Fixed Aspect On", ""},
+ {PLACE_MODAL_FIXED_ASPECT_OFF, "FIXED_ASPECT_OFF", 0, "Fixed Aspect Off", ""},
+ {PLACE_MODAL_PIVOT_CENTER_ON, "PIVOT_CENTER_ON", 0, "Center Pivot On", ""},
+ {PLACE_MODAL_PIVOT_CENTER_OFF, "PIVOT_CENTER_OFF", 0, "Center Pivot Off", ""},
+ {0, NULL, 0, NULL, NULL},
+ };
+
+ const char *keymap_name = "View3D Placement Modal Map";
+ wmKeyMap *keymap = WM_modalkeymap_find(keyconf, keymap_name);
+
+ /* This function is called for each space-type, only needs to add map once. */
+ if (keymap && keymap->modal_items) {
+ return;
+ }
+
+ keymap = WM_modalkeymap_ensure(keyconf, keymap_name, modal_items);
+
+ WM_modalkeymap_assign(keymap, "VIEW3D_OT_interactive_add");
+}
+
+static int view3d_interactive_add_modal(bContext *C, wmOperator *op, const wmEvent *event)
+{
+ UNUSED_VARS(C, op);
+
+ struct InteractivePlaceData *ipd = op->customdata;
+
+ ARegion *region = ipd->region;
+ bool do_redraw = false;
+ bool do_cursor_update = false;
+
+ /* Handle modal key-map. */
+ if (event->type == EVT_MODAL_MAP) {
+ bool is_fallthrough = false;
+ switch (event->val) {
+ case PLACE_MODAL_FIXED_ASPECT_ON: {
+ is_fallthrough = true;
+ ATTR_FALLTHROUGH;
+ }
+ case PLACE_MODAL_FIXED_ASPECT_OFF: {
+ ipd->step[ipd->step_index].is_fixed_aspect = is_fallthrough;
+ do_redraw = true;
+ break;
+ }
+ case PLACE_MODAL_PIVOT_CENTER_ON: {
+ is_fallthrough = true;
+ ATTR_FALLTHROUGH;
+ }
+ case PLACE_MODAL_PIVOT_CENTER_OFF: {
+ ipd->step[ipd->step_index].is_centered = is_fallthrough;
+ do_redraw = true;
+ break;
+ }
+ case PLACE_MODAL_SNAP_ON: {
+ is_fallthrough = true;
+ ATTR_FALLTHROUGH;
+ }
+ case PLACE_MODAL_SNAP_OFF: {
+ const ToolSettings *ts = ipd->scene->toolsettings;
+ ipd->is_snap_invert = is_fallthrough;
+ ipd->use_snap = (ipd->is_snap_invert == !(ts->snap_flag & SCE_SNAP));
+ do_cursor_update = true;
+ break;
+ }
+ }
+ }
+
+ if (ELEM(event->type, EVT_ESCKEY, RIGHTMOUSE)) {
+ view3d_interactive_add_exit(C, op);
+ return OPERATOR_CANCELLED;
+ }
+ else if (event->type == MOUSEMOVE) {
+ do_cursor_update = true;
+ }
+
+ if (ipd->wait_for_input) {
+ if (ELEM(event->type, LEFTMOUSE)) {
+ if (event->val == KM_PRESS) {
+ view3d_interactive_add_begin(C, op, event);
+ ipd->wait_for_input = false;
+ return OPERATOR_RUNNING_MODAL;
+ }
+ }
+ return OPERATOR_RUNNING_MODAL;
+ }
+
+ if (ipd->step_index == STEP_BASE) {
+ if (ELEM(event->type, ipd->launch_event, LEFTMOUSE)) {
+ if (event->val == KM_RELEASE) {
+ /* Set secondary plane. */
+
+ /* Create normal. */
+ {
+ RegionView3D *rv3d = region->regiondata;
+ float no_temp[3];
+ float no[3];
+ cross_v3_v3v3(no_temp, ipd->step[0].plane, rv3d->viewinv[2]);
+ cross_v3_v3v3(no, no_temp, ipd->step[0].plane);
+ normalize_v3(no);
+
+ plane_from_point_normal_v3(ipd->step[1].plane, ipd->step[0].co_dst, no);
+ }
+
+ copy_v3_v3(ipd->step[1].co_dst, ipd->step[0].co_dst);
+ ipd->step_index = STEP_DEPTH;
+
+ /* Keep these values from the previous step. */
+ ipd->step[1].is_centered = ipd->step[0].is_centered;
+ ipd->step[1].is_fixed_aspect = ipd->step[0].is_fixed_aspect;
+ }
+ }
+ }
+ else if (ipd->step_index == STEP_DEPTH) {
+ if (ELEM(event->type, ipd->launch_event, LEFTMOUSE)) {
+ if (event->val == KM_PRESS) {
+
+ BoundBox bounds;
+ calc_bbox(ipd, &bounds);
+
+ float location[3];
+ float rotation[3];
+ float scale[3];
+
+ float matrix_orient_axis[3][3];
+ copy_m3_m3(matrix_orient_axis, ipd->matrix_orient);
+ if (ipd->orient_axis != 2) {
+ swap_v3_v3(matrix_orient_axis[2], matrix_orient_axis[ipd->orient_axis]);
+ swap_v3_v3(matrix_orient_axis[0], matrix_orient_axis[1]);
+ }
+ /* Needed for shapes where the sign matters (cone for eg). */
+ {
+ float delta[3];
+ sub_v3_v3v3(delta, bounds.vec[0], bounds.vec[4]);
+ if (dot_v3v3(ipd->matrix_orient[ipd->orient_axis], delta) > 0.0f) {
+ negate_v3(matrix_orient_axis[2]);
+
+ /* Only flip Y so we don't flip a single axis which causes problems. */
+ negate_v3(matrix_orient_axis[1]);
+ }
+ }
+
+ mat3_to_eul(rotation, matrix_orient_axis);
+
+ mid_v3_v3v3(location, bounds.vec[0], bounds.vec[6]);
+ const int cube_verts[3] = {3, 1, 4};
+ for (int i = 0; i < 3; i++) {
+ scale[i] = len_v3v3(bounds.vec[0], bounds.vec[cube_verts[i]]);
+ }
+
+ wmOperatorType *ot = NULL;
+ PointerRNA op_props;
+ if (ipd->primitive_type == PLACE_PRIMITIVE_TYPE_CUBE) {
+ ot = WM_operatortype_find("MESH_OT_primitive_cube_add", false);
+ }
+ else if (ipd->primitive_type == PLACE_PRIMITIVE_TYPE_CYLINDER) {
+ ot = WM_operatortype_find("MESH_OT_primitive_cylinder_add", false);
+ }
+ else if (ipd->primitive_type == PLACE_PRIMITIVE_TYPE_CONE) {
+ ot = WM_operatortype_find("MESH_OT_primitive_cone_add", false);
+ }
+ else if (ipd->primitive_type == PLACE_PRIMITIVE_TYPE_SPHERE_UV) {
+ ot = WM_operatortype_find("MESH_OT_primitive_uv_sphere_add", false);
+ }
+ else if (ipd->primitive_type == PLACE_PRIMITIVE_TYPE_SPHERE_ICO) {
+ ot = WM_operatortype_find("MESH_OT_primitive_ico_sphere_add", false);
+ }
+
+ if (ot != NULL) {
+ WM_operator_properties_create_ptr(&op_props, ot);
+
+ if (ipd->use_tool) {
+ bToolRef *tref = ipd->area->runtime.tool;
+ PointerRNA temp_props;
+ WM_toolsystem_ref_properties_init_for_keymap(tref, &temp_props, &op_props, ot);
+ SWAP(PointerRNA, temp_props, op_props);
+ WM_operator_properties_free(&temp_props);
+ }
+
+ RNA_float_set_array(&op_props, "rotation", rotation);
+ RNA_float_set_array(&op_props, "location", location);
+ RNA_float_set_array(&op_props, "scale", scale);
+ WM_operator_name_call_ptr(C, ot, WM_OP_EXEC_DEFAULT, &op_props);
+ WM_operator_properties_free(&op_props);
+ }
+ else {
+ BLI_assert(0);
+ }
+
+ view3d_interactive_add_exit(C, op);
+ return OPERATOR_FINISHED;
+ }
+ }
+ }
+ else {
+ BLI_assert(0);
+ }
+
+ if (do_cursor_update) {
+ const float mval_fl[2] = {UNPACK2(event->mval)};
+
+ /* Calculate the snap location on mouse-move or when toggling snap. */
+ bool is_snap_found_prev = ipd->is_snap_found;
+ ipd->is_snap_found = false;
+ if (ipd->use_snap) {
+ if (ipd->snap_gizmo != NULL) {
+ ED_gizmotypes_snap_3d_toggle_set(ipd->snap_gizmo, ipd->use_snap);
+ if (ED_gizmotypes_snap_3d_update(ipd->snap_gizmo,
+ CTX_data_ensure_evaluated_depsgraph(C),
+ ipd->region,
+ ipd->v3d,
+ NULL,
+ mval_fl,
+ ipd->snap_co,
+ NULL)) {
+ ipd->is_snap_found = true;
+ }
+ ED_gizmotypes_snap_3d_toggle_clear(ipd->snap_gizmo);
+ }
+ }
+
+ /* Workaround because test_select doesn't run at the same time as the modal operator. */
+ if (is_snap_found_prev != ipd->is_snap_found) {
+ wmGizmoMap *gzmap = ipd->region->gizmo_map;
+ WM_gizmo_highlight_set(gzmap, ipd->is_snap_found ? ipd->snap_gizmo : NULL);
+ }
+
+ if (ipd->step_index == STEP_BASE) {
+ if (ipd->is_snap_found) {
+ closest_to_plane_normalized_v3(ipd->step[0].co_dst, ipd->step[0].plane, ipd->snap_co);
+ }
+ else {
+ if (ED_view3d_win_to_3d_on_plane(
+ region, ipd->step[0].plane, mval_fl, false, ipd->step[0].co_dst)) {
+ /* pass */
+ }
+ }
+ }
+ else if (ipd->step_index == STEP_DEPTH) {
+ if (ipd->is_snap_found) {
+ closest_to_plane_normalized_v3(ipd->step[1].co_dst, ipd->step[1].plane, ipd->snap_co);
+ }
+ else {
+ if (ED_view3d_win_to_3d_on_plane(
+ region, ipd->step[1].plane, mval_fl, false, ipd->step[1].co_dst)) {
+ /* pass */
+ }
+ }
+
+ /* Correct the point so it's aligned with the 'ipd->step[0].co_dst'. */
+ float close[3], delta[3];
+ closest_to_plane_normalized_v3(close, ipd->step[0].plane, ipd->step[1].co_dst);
+ sub_v3_v3v3(delta, close, ipd->step[0].co_dst);
+ sub_v3_v3(ipd->step[1].co_dst, delta);
+ }
+ do_redraw = true;
+ }
+
+ if (do_redraw) {
+ ED_region_tag_redraw(region);
+ }
+
+ return OPERATOR_RUNNING_MODAL;
+}
+
+static bool view3d_interactive_add_poll(bContext *C)
+{
+ const enum eContextObjectMode mode = CTX_data_mode_enum(C);
+ return ELEM(mode, CTX_MODE_OBJECT, CTX_MODE_EDIT_MESH);
+}
+
+void VIEW3D_OT_interactive_add(struct wmOperatorType *ot)
+{
+ /* identifiers */
+ ot->name = "Add Primitive Object";
+ ot->description = "Interactively add an object";
+ ot->idname = "VIEW3D_OT_interactive_add";
+
+ /* api callbacks */
+ ot->invoke = view3d_interactive_add_invoke;
+ ot->modal = view3d_interactive_add_modal;
+ ot->cancel = view3d_interactive_add_cancel;
+ ot->poll = view3d_interactive_add_poll;
+
+ /* Note, let the operator we call handle undo and registering it's self. */
+ /* flags */
+ ot->flag = 0;
+
+ /* properties */
+ PropertyRNA *prop;
+
+ /* Normally not accessed directly, leave unset and check the active tool. */
+ static const EnumPropertyItem primitive_type[] = {
+ {PLACE_PRIMITIVE_TYPE_CUBE, "CUBE", 0, "Cube", ""},
+ {PLACE_PRIMITIVE_TYPE_CYLINDER, "CYLINDER", 0, "Cylinder", ""},
+ {PLACE_PRIMITIVE_TYPE_CONE, "CONE", 0, "Cone", ""},
+ {PLACE_PRIMITIVE_TYPE_SPHERE_UV, "SPHERE_UV", 0, "UV Sphere", ""},
+ {PLACE_PRIMITIVE_TYPE_SPHERE_ICO, "SPHERE_ICO", 0, "ICO Sphere", ""},
+ {0, NULL, 0, NULL, NULL},
+ };
+ prop = RNA_def_property(ot->srna, "primitive_type", PROP_ENUM, PROP_NONE);
+ RNA_def_property_ui_text(prop, "Primitive", "");
+ RNA_def_property_enum_items(prop, primitive_type);
+ RNA_def_property_flag(prop, PROP_SKIP_SAVE);
+
+ prop = RNA_def_property(ot->srna, "plane_axis", PROP_ENUM, PROP_NONE);
+ RNA_def_property_ui_text(prop, "Plane Axis", "The axis used for placing the base region");
+ RNA_def_property_enum_default(prop, 2);
+ RNA_def_property_enum_items(prop, rna_enum_axis_xyz_items);
+ RNA_def_property_flag(prop, PROP_SKIP_SAVE);
+
+ static const EnumPropertyItem plane_depth_items[] = {
+ {PLACE_DEPTH_SURFACE,
+ "SURFACE",
+ 0,
+ "Surface",
+ "Start placing on the surface, using the 3D cursor position as a fallback"},
+ {PLACE_DEPTH_CURSOR_PLANE,
+ "CURSOR_PLANE",
+ 0,
+ "3D Cursor Plane",
+ "Start placement using a point projected onto the selected axis at the 3D cursor position"},
+ {PLACE_DEPTH_CURSOR_VIEW,
+ "CURSOR_VIEW",
+ 0,
+ "3D Cursor View",
+ "Start placement using the mouse cursor projected onto the view plane"},
+ {0, NULL, 0, NULL, NULL},
+ };
+ prop = RNA_def_property(ot->srna, "plane_depth", PROP_ENUM, PROP_NONE);
+ RNA_def_property_ui_text(prop, "Position", "The initial depth used when placing the cursor");
+ RNA_def_property_enum_default(prop, PLACE_DEPTH_SURFACE);
+ RNA_def_property_enum_items(prop, plane_depth_items);
+ RNA_def_property_flag(prop, PROP_SKIP_SAVE);
+
+ static const EnumPropertyItem origin_items[] = {
+ {PLACE_ORIGIN_BASE, "BASE", 0, "Base", "Start placing the corner position"},
+ {PLACE_ORIGIN_CENTER, "CENTER", 0, "Center", "Start placing the center position"},
+ {0, NULL, 0, NULL, NULL},
+ };
+ prop = RNA_def_property(ot->srna, "plane_origin", PROP_ENUM, PROP_NONE);
+ RNA_def_property_ui_text(prop, "Origin", "The initial position for placement");
+ RNA_def_property_enum_default(prop, PLACE_ORIGIN_BASE);
+ RNA_def_property_enum_items(prop, origin_items);
+ RNA_def_property_flag(prop, PROP_SKIP_SAVE);
+
+ /* When not accessed via a tool. */
+ prop = RNA_def_boolean(ot->srna, "wait_for_input", true, "Wait for Input", "");
+ RNA_def_property_flag(prop, PROP_HIDDEN | PROP_SKIP_SAVE);
+}
+
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Placement Gizmo Group
+ *
+ * This is currently only used for snapping before the tool is initialized,
+ * we could show a placement plane here.
+ * \{ */
+
+static void WIDGETGROUP_placement_setup(const bContext *UNUSED(C), wmGizmoGroup *gzgroup)
+{
+ wmGizmo *gizmo;
+
+ {
+ /* The gizmo snap has to be the first gizmo. */
+ const wmGizmoType *gzt_snap;
+ gzt_snap = WM_gizmotype_find("GIZMO_GT_snap_3d", true);
+ gizmo = WM_gizmo_new_ptr(gzt_snap, gzgroup, NULL);
+ RNA_enum_set(gizmo->ptr,
+ "snap_elements_force",
+ (SCE_SNAP_MODE_VERTEX | SCE_SNAP_MODE_EDGE | SCE_SNAP_MODE_FACE |
+ /* SCE_SNAP_MODE_VOLUME | SCE_SNAP_MODE_GRID | SCE_SNAP_MODE_INCREMENT | */
+ SCE_SNAP_MODE_EDGE_PERPENDICULAR | SCE_SNAP_MODE_EDGE_MIDPOINT));
+
+ WM_gizmo_set_color(gizmo, (float[4]){1.0f, 1.0f, 1.0f, 1.0f});
+
+ /* Don't handle any events, this is for display only. */
+ gizmo->flag |= WM_GIZMO_HIDDEN_KEYMAP;
+ }
+}
+
+void VIEW3D_GGT_placement(wmGizmoGroupType *gzgt)
+{
+ gzgt->name = "Placement Widget";
+ gzgt->idname = view3d_gzgt_placement_id;
+
+ gzgt->flag |= WM_GIZMOGROUPTYPE_3D | WM_GIZMOGROUPTYPE_SCALE | WM_GIZMOGROUPTYPE_DRAW_MODAL_ALL;
+
+ gzgt->gzmap_params.spaceid = SPACE_VIEW3D;
+ gzgt->gzmap_params.regionid = RGN_TYPE_WINDOW;
+
+ gzgt->poll = ED_gizmo_poll_or_unlink_delayed_from_tool;
+ gzgt->setup = WIDGETGROUP_placement_setup;
+}
+
+/** \} */
diff --git a/source/blender/editors/space_view3d/view3d_select.c b/source/blender/editors/space_view3d/view3d_select.c
index 8fdef585fa2..8c60e36a141 100644
--- a/source/blender/editors/space_view3d/view3d_select.c
+++ b/source/blender/editors/space_view3d/view3d_select.c
@@ -157,7 +157,7 @@ void ED_view3d_viewcontext_init_object(ViewContext *vc, Object *obact)
static bool object_deselect_all_visible(ViewLayer *view_layer, View3D *v3d)
{
bool changed = false;
- for (Base *base = view_layer->object_bases.first; base; base = base->next) {
+ LISTBASE_FOREACH (Base *, base, &view_layer->object_bases) {
if (base->flag & BASE_SELECTED) {
if (BASE_SELECTABLE(v3d, base)) {
ED_object_base_select(base, BA_DESELECT);
@@ -172,7 +172,7 @@ static bool object_deselect_all_visible(ViewLayer *view_layer, View3D *v3d)
static bool object_deselect_all_except(ViewLayer *view_layer, Base *b)
{
bool changed = false;
- for (Base *base = view_layer->object_bases.first; base; base = base->next) {
+ LISTBASE_FOREACH (Base *, base, &view_layer->object_bases) {
if (base->flag & BASE_SELECTED) {
if (b != base) {
ED_object_base_select(base, BA_DESELECT);
@@ -408,9 +408,10 @@ typedef struct LassoSelectUserData {
const rcti *rect;
const rctf *rect_fl;
rctf _rect_fl;
- const int (*mcords)[2];
- int moves;
+ const int (*mcoords)[2];
+ int mcoords_len;
eSelectOp sel_op;
+ eBezTriple_Flag select_flag;
/* runtime */
int pass;
@@ -421,8 +422,8 @@ typedef struct LassoSelectUserData {
static void view3d_userdata_lassoselect_init(LassoSelectUserData *r_data,
ViewContext *vc,
const rcti *rect,
- const int (*mcords)[2],
- const int moves,
+ const int (*mcoords)[2],
+ const int mcoords_len,
const eSelectOp sel_op)
{
r_data->vc = vc;
@@ -431,9 +432,11 @@ static void view3d_userdata_lassoselect_init(LassoSelectUserData *r_data,
r_data->rect_fl = &r_data->_rect_fl;
BLI_rctf_rcti_copy(&r_data->_rect_fl, rect);
- r_data->mcords = mcords;
- r_data->moves = moves;
+ r_data->mcoords = mcoords;
+ r_data->mcoords_len = mcoords_len;
r_data->sel_op = sel_op;
+ /* SELECT by default, but can be changed if needed (only few cases use and respect this). */
+ r_data->select_flag = SELECT;
/* runtime */
r_data->pass = 0;
@@ -527,7 +530,8 @@ static void do_lasso_select_pose__do_tag(void *userData,
if (screen_co_a[0] != IS_CLIPPED) {
points_proj_tot++;
if (BLI_rcti_isect_pt(data->rect, UNPACK2(screen_co_a)) &&
- BLI_lasso_is_point_inside(data->mcords, data->moves, UNPACK2(screen_co_a), INT_MAX)) {
+ BLI_lasso_is_point_inside(
+ data->mcoords, data->mcoords_len, UNPACK2(screen_co_a), INT_MAX)) {
is_point_done = true;
}
}
@@ -536,22 +540,28 @@ static void do_lasso_select_pose__do_tag(void *userData,
if (screen_co_b[0] != IS_CLIPPED) {
points_proj_tot++;
if (BLI_rcti_isect_pt(data->rect, UNPACK2(screen_co_b)) &&
- BLI_lasso_is_point_inside(data->mcords, data->moves, UNPACK2(screen_co_b), INT_MAX)) {
+ BLI_lasso_is_point_inside(
+ data->mcoords, data->mcoords_len, UNPACK2(screen_co_b), INT_MAX)) {
is_point_done = true;
}
}
/* if one of points selected, we skip the bone itself */
- if ((is_point_done == true) ||
- ((is_point_done == false) && (points_proj_tot == 2) &&
- BLI_lasso_is_edge_inside(
- data->mcords, data->moves, UNPACK2(screen_co_a), UNPACK2(screen_co_b), INT_MAX))) {
+ if ((is_point_done == true) || ((is_point_done == false) && (points_proj_tot == 2) &&
+ BLI_lasso_is_edge_inside(data->mcoords,
+ data->mcoords_len,
+ UNPACK2(screen_co_a),
+ UNPACK2(screen_co_b),
+ INT_MAX))) {
pchan->bone->flag |= BONE_DONE;
}
data->is_changed |= is_point_done;
}
}
-static void do_lasso_tag_pose(ViewContext *vc, Object *ob, const int mcords[][2], short moves)
+static void do_lasso_tag_pose(ViewContext *vc,
+ Object *ob,
+ const int mcoords[][2],
+ const int mcoords_len)
{
ViewContext vc_tmp;
LassoSelectUserData data;
@@ -564,9 +574,9 @@ static void do_lasso_tag_pose(ViewContext *vc, Object *ob, const int mcords[][2]
vc_tmp = *vc;
vc_tmp.obact = ob;
- BLI_lasso_boundbox(&rect, mcords, moves);
+ BLI_lasso_boundbox(&rect, mcoords, mcoords_len);
- view3d_userdata_lassoselect_init(&data, vc, &rect, mcords, moves, 0);
+ view3d_userdata_lassoselect_init(&data, vc, &rect, mcoords, mcoords_len, 0);
ED_view3d_init_mats_rv3d(vc_tmp.obact, vc->rv3d);
@@ -574,8 +584,8 @@ static void do_lasso_tag_pose(ViewContext *vc, Object *ob, const int mcords[][2]
}
static bool do_lasso_select_objects(ViewContext *vc,
- const int mcords[][2],
- const short moves,
+ const int mcoords[][2],
+ const int mcoords_len,
const eSelectOp sel_op)
{
View3D *v3d = vc->v3d;
@@ -591,7 +601,7 @@ static bool do_lasso_select_objects(ViewContext *vc,
const bool is_select = base->flag & BASE_SELECTED;
const bool is_inside = ((ED_view3d_project_base(vc->region, base) == V3D_PROJ_RET_OK) &&
BLI_lasso_is_point_inside(
- mcords, moves, base->sx, base->sy, IS_CLIPPED));
+ mcoords, mcoords_len, base->sx, base->sy, IS_CLIPPED));
const int sel_op_result = ED_select_op_action_deselected(sel_op, is_select, is_inside);
if (sel_op_result != -1) {
ED_object_base_select(base, sel_op_result ? BA_SELECT : BA_DESELECT);
@@ -617,7 +627,7 @@ static Base **do_pose_tag_select_op_prepare(ViewContext *vc, uint *r_bases_len)
FOREACH_BASE_IN_MODE_BEGIN (vc->view_layer, vc->v3d, OB_ARMATURE, OB_MODE_POSE, base_iter) {
Object *ob_iter = base_iter->object;
bArmature *arm = ob_iter->data;
- for (bPoseChannel *pchan = ob_iter->pose->chanbase.first; pchan; pchan = pchan->next) {
+ LISTBASE_FOREACH (bPoseChannel *, pchan, &ob_iter->pose->chanbase) {
Bone *bone = pchan->bone;
bone->flag &= ~BONE_DONE;
}
@@ -659,7 +669,7 @@ static bool do_pose_tag_select_op_exec(Base **bases, const uint bases_len, const
}
bool changed = true;
- for (bPoseChannel *pchan = ob_iter->pose->chanbase.first; pchan; pchan = pchan->next) {
+ LISTBASE_FOREACH (bPoseChannel *, pchan, &ob_iter->pose->chanbase) {
Bone *bone = pchan->bone;
if ((bone->flag & BONE_UNSELECTABLE) == 0) {
const bool is_select = bone->flag & BONE_SELECTED;
@@ -685,8 +695,8 @@ static bool do_pose_tag_select_op_exec(Base **bases, const uint bases_len, const
}
static bool do_lasso_select_pose(ViewContext *vc,
- const int mcords[][2],
- const short moves,
+ const int mcoords[][2],
+ const int mcoords_len,
const eSelectOp sel_op)
{
uint bases_len;
@@ -695,7 +705,7 @@ static bool do_lasso_select_pose(ViewContext *vc,
for (int i = 0; i < bases_len; i++) {
Base *base_iter = bases[i];
Object *ob_iter = base_iter->object;
- do_lasso_tag_pose(vc, ob_iter, mcords, moves);
+ do_lasso_tag_pose(vc, ob_iter, mcoords, mcoords_len);
}
const bool changed_multi = do_pose_tag_select_op_exec(bases, bases_len, sel_op);
@@ -715,9 +725,10 @@ static void do_lasso_select_mesh__doSelectVert(void *userData,
{
LassoSelectUserData *data = userData;
const bool is_select = BM_elem_flag_test(eve, BM_ELEM_SELECT);
- const bool is_inside = (BLI_rctf_isect_pt_v(data->rect_fl, screen_co) &&
- BLI_lasso_is_point_inside(
- data->mcords, data->moves, screen_co[0], screen_co[1], IS_CLIPPED));
+ const bool is_inside =
+ (BLI_rctf_isect_pt_v(data->rect_fl, screen_co) &&
+ BLI_lasso_is_point_inside(
+ data->mcoords, data->mcoords_len, screen_co[0], screen_co[1], IS_CLIPPED));
const int sel_op_result = ED_select_op_action_deselected(data->sel_op, is_select, is_inside);
if (sel_op_result != -1) {
BM_vert_select_set(data->vc->em->bm, eve, sel_op_result);
@@ -746,8 +757,10 @@ static void do_lasso_select_mesh__doSelectEdge_pass0(void *user_data,
const bool is_select = BM_elem_flag_test(eed, BM_ELEM_SELECT);
const bool is_inside =
(is_visible && edge_fully_inside_rect(data->rect_fl, screen_co_a, screen_co_b) &&
- BLI_lasso_is_point_inside(data->mcords, data->moves, UNPACK2(screen_co_a), IS_CLIPPED) &&
- BLI_lasso_is_point_inside(data->mcords, data->moves, UNPACK2(screen_co_b), IS_CLIPPED));
+ BLI_lasso_is_point_inside(
+ data->mcoords, data->mcoords_len, UNPACK2(screen_co_a), IS_CLIPPED) &&
+ BLI_lasso_is_point_inside(
+ data->mcoords, data->mcoords_len, UNPACK2(screen_co_b), IS_CLIPPED));
const int sel_op_result = ED_select_op_action_deselected(data->sel_op, is_select, is_inside);
if (sel_op_result != -1) {
BM_edge_select_set(data->vc->em->bm, eed, sel_op_result);
@@ -770,8 +783,8 @@ static void do_lasso_select_mesh__doSelectEdge_pass1(void *user_data,
}
const bool is_select = BM_elem_flag_test(eed, BM_ELEM_SELECT);
- const bool is_inside = (is_visible && BLI_lasso_is_edge_inside(data->mcords,
- data->moves,
+ const bool is_inside = (is_visible && BLI_lasso_is_edge_inside(data->mcoords,
+ data->mcoords_len,
UNPACK2(screen_co_a),
UNPACK2(screen_co_b),
IS_CLIPPED));
@@ -789,9 +802,10 @@ static void do_lasso_select_mesh__doSelectFace(void *userData,
{
LassoSelectUserData *data = userData;
const bool is_select = BM_elem_flag_test(efa, BM_ELEM_SELECT);
- const bool is_inside = (BLI_rctf_isect_pt_v(data->rect_fl, screen_co) &&
- BLI_lasso_is_point_inside(
- data->mcords, data->moves, screen_co[0], screen_co[1], IS_CLIPPED));
+ const bool is_inside =
+ (BLI_rctf_isect_pt_v(data->rect_fl, screen_co) &&
+ BLI_lasso_is_point_inside(
+ data->mcoords, data->mcoords_len, screen_co[0], screen_co[1], IS_CLIPPED));
const int sel_op_result = ED_select_op_action_deselected(data->sel_op, is_select, is_inside);
if (sel_op_result != -1) {
BM_face_select_set(data->vc->em->bm, efa, sel_op_result);
@@ -801,8 +815,8 @@ static void do_lasso_select_mesh__doSelectFace(void *userData,
static bool do_lasso_select_mesh(ViewContext *vc,
wmGenericUserData *wm_userdata,
- const int mcords[][2],
- short moves,
+ const int mcoords[][2],
+ const int mcoords_len,
const eSelectOp sel_op)
{
LassoSelectUserData data;
@@ -812,9 +826,9 @@ static bool do_lasso_select_mesh(ViewContext *vc,
/* set editmesh */
vc->em = BKE_editmesh_from_object(vc->obedit);
- BLI_lasso_boundbox(&rect, mcords, moves);
+ BLI_lasso_boundbox(&rect, mcoords, mcoords_len);
- view3d_userdata_lassoselect_init(&data, vc, &rect, mcords, moves, sel_op);
+ view3d_userdata_lassoselect_init(&data, vc, &rect, mcoords, mcoords_len, sel_op);
if (SEL_OP_USE_PRE_DESELECT(sel_op)) {
if (vc->em->bm->totvertsel) {
@@ -836,7 +850,7 @@ static bool do_lasso_select_mesh(ViewContext *vc,
editselect_buf_cache_init_with_generic_userdata(wm_userdata, vc, ts->selectmode);
esel = wm_userdata->data;
esel->select_bitmap = DRW_select_buffer_bitmap_from_poly(
- vc->depsgraph, vc->region, vc->v3d, mcords, moves, &rect, NULL);
+ vc->depsgraph, vc->region, vc->v3d, mcoords, mcoords_len, &rect, NULL);
}
}
@@ -892,27 +906,28 @@ static void do_lasso_select_curve__doSelect(void *userData,
BPoint *bp,
BezTriple *bezt,
int beztindex,
+ bool handles_visible,
const float screen_co[2])
{
LassoSelectUserData *data = userData;
const bool is_inside = BLI_lasso_is_point_inside(
- data->mcords, data->moves, screen_co[0], screen_co[1], IS_CLIPPED);
+ data->mcoords, data->mcoords_len, screen_co[0], screen_co[1], IS_CLIPPED);
if (bp) {
const bool is_select = bp->f1 & SELECT;
const int sel_op_result = ED_select_op_action_deselected(data->sel_op, is_select, is_inside);
if (sel_op_result != -1) {
- SET_FLAG_FROM_TEST(bp->f1, sel_op_result, SELECT);
+ SET_FLAG_FROM_TEST(bp->f1, sel_op_result, data->select_flag);
data->is_changed = true;
}
}
else {
- if ((data->vc->v3d->overlay.edit_flag & V3D_OVERLAY_EDIT_CU_HANDLES) == 0) {
- /* can only be (beztindex == 0) here since handles are hidden */
+ if (!handles_visible) {
+ /* can only be (beztindex == 1) here since handles are hidden */
const bool is_select = bezt->f2 & SELECT;
const int sel_op_result = ED_select_op_action_deselected(data->sel_op, is_select, is_inside);
if (sel_op_result != -1) {
- SET_FLAG_FROM_TEST(bezt->f2, sel_op_result, SELECT);
+ SET_FLAG_FROM_TEST(bezt->f2, sel_op_result, data->select_flag);
}
bezt->f1 = bezt->f3 = bezt->f2;
data->is_changed = true;
@@ -922,7 +937,7 @@ static void do_lasso_select_curve__doSelect(void *userData,
const bool is_select = *flag_p & SELECT;
const int sel_op_result = ED_select_op_action_deselected(data->sel_op, is_select, is_inside);
if (sel_op_result != -1) {
- SET_FLAG_FROM_TEST(*flag_p, sel_op_result, SELECT);
+ SET_FLAG_FROM_TEST(*flag_p, sel_op_result, data->select_flag);
data->is_changed = true;
}
}
@@ -930,24 +945,35 @@ static void do_lasso_select_curve__doSelect(void *userData,
}
static bool do_lasso_select_curve(ViewContext *vc,
- const int mcords[][2],
- short moves,
+ const int mcoords[][2],
+ const int mcoords_len,
const eSelectOp sel_op)
{
+ const bool deselect_all = (sel_op == SEL_OP_SET);
LassoSelectUserData data;
rcti rect;
- BLI_lasso_boundbox(&rect, mcords, moves);
+ BLI_lasso_boundbox(&rect, mcoords, mcoords_len);
- view3d_userdata_lassoselect_init(&data, vc, &rect, mcords, moves, sel_op);
+ view3d_userdata_lassoselect_init(&data, vc, &rect, mcoords, mcoords_len, sel_op);
- if (SEL_OP_USE_PRE_DESELECT(sel_op)) {
- Curve *curve = (Curve *)vc->obedit->data;
- data.is_changed |= ED_curve_deselect_all(curve->editnurb);
+ Curve *curve = (Curve *)vc->obedit->data;
+ ListBase *nurbs = BKE_curve_editNurbs_get(curve);
+
+ /* For deselect all, items to be selected are tagged with temp flag. Clear that first. */
+ if (deselect_all) {
+ BKE_nurbList_flag_set(nurbs, BEZT_FLAG_TEMP_TAG, false);
+ data.select_flag = BEZT_FLAG_TEMP_TAG;
}
ED_view3d_init_mats_rv3d(vc->obedit, vc->rv3d); /* for foreach's screen/vert projection */
nurbs_foreachScreenVert(vc, do_lasso_select_curve__doSelect, &data, V3D_PROJ_TEST_CLIP_DEFAULT);
+
+ /* Deselect items that were not added to selection (indicated by temp flag). */
+ if (deselect_all) {
+ BKE_nurbList_flag_set_from_flag(nurbs, BEZT_FLAG_TEMP_TAG, SELECT);
+ }
+
if (data.is_changed) {
BKE_curve_nurb_vert_active_validate(vc->obedit->data);
}
@@ -958,9 +984,10 @@ static void do_lasso_select_lattice__doSelect(void *userData, BPoint *bp, const
{
LassoSelectUserData *data = userData;
const bool is_select = bp->f1 & SELECT;
- const bool is_inside = (BLI_rctf_isect_pt_v(data->rect_fl, screen_co) &&
- BLI_lasso_is_point_inside(
- data->mcords, data->moves, screen_co[0], screen_co[1], IS_CLIPPED));
+ const bool is_inside =
+ (BLI_rctf_isect_pt_v(data->rect_fl, screen_co) &&
+ BLI_lasso_is_point_inside(
+ data->mcoords, data->mcoords_len, screen_co[0], screen_co[1], IS_CLIPPED));
const int sel_op_result = ED_select_op_action_deselected(data->sel_op, is_select, is_inside);
if (sel_op_result != -1) {
SET_FLAG_FROM_TEST(bp->f1, sel_op_result, SELECT);
@@ -968,16 +995,16 @@ static void do_lasso_select_lattice__doSelect(void *userData, BPoint *bp, const
}
}
static bool do_lasso_select_lattice(ViewContext *vc,
- const int mcords[][2],
- short moves,
+ const int mcoords[][2],
+ const int mcoords_len,
const eSelectOp sel_op)
{
LassoSelectUserData data;
rcti rect;
- BLI_lasso_boundbox(&rect, mcords, moves);
+ BLI_lasso_boundbox(&rect, mcoords, mcoords_len);
- view3d_userdata_lassoselect_init(&data, vc, &rect, mcords, moves, sel_op);
+ view3d_userdata_lassoselect_init(&data, vc, &rect, mcoords, mcoords_len, sel_op);
if (SEL_OP_USE_PRE_DESELECT(sel_op)) {
data.is_changed |= ED_lattice_flags_set(vc->obedit, 0);
@@ -1002,7 +1029,8 @@ static void do_lasso_select_armature__doSelectBone(void *userData,
if (screen_co_a[0] != IS_CLIPPED) {
if (BLI_rcti_isect_pt(data->rect, UNPACK2(screen_co_a)) &&
- BLI_lasso_is_point_inside(data->mcords, data->moves, UNPACK2(screen_co_a), INT_MAX)) {
+ BLI_lasso_is_point_inside(
+ data->mcoords, data->mcoords_len, UNPACK2(screen_co_a), INT_MAX)) {
is_inside_flag |= BONESEL_ROOT;
}
}
@@ -1012,7 +1040,8 @@ static void do_lasso_select_armature__doSelectBone(void *userData,
if (screen_co_b[0] != IS_CLIPPED) {
if (BLI_rcti_isect_pt(data->rect, UNPACK2(screen_co_b)) &&
- BLI_lasso_is_point_inside(data->mcords, data->moves, UNPACK2(screen_co_b), INT_MAX)) {
+ BLI_lasso_is_point_inside(
+ data->mcoords, data->mcoords_len, UNPACK2(screen_co_b), INT_MAX)) {
is_inside_flag |= BONESEL_TIP;
}
}
@@ -1022,8 +1051,11 @@ static void do_lasso_select_armature__doSelectBone(void *userData,
if (is_ignore_flag == 0) {
if (is_inside_flag == (BONE_ROOTSEL | BONE_TIPSEL) ||
- BLI_lasso_is_edge_inside(
- data->mcords, data->moves, UNPACK2(screen_co_a), UNPACK2(screen_co_b), INT_MAX)) {
+ BLI_lasso_is_edge_inside(data->mcoords,
+ data->mcoords_len,
+ UNPACK2(screen_co_a),
+ UNPACK2(screen_co_b),
+ INT_MAX)) {
is_inside_flag |= BONESEL_BONE;
}
}
@@ -1033,16 +1065,16 @@ static void do_lasso_select_armature__doSelectBone(void *userData,
}
static bool do_lasso_select_armature(ViewContext *vc,
- const int mcords[][2],
- short moves,
+ const int mcoords[][2],
+ const int mcoords_len,
const eSelectOp sel_op)
{
LassoSelectUserData data;
rcti rect;
- BLI_lasso_boundbox(&rect, mcords, moves);
+ BLI_lasso_boundbox(&rect, mcoords, mcoords_len);
- view3d_userdata_lassoselect_init(&data, vc, &rect, mcords, moves, sel_op);
+ view3d_userdata_lassoselect_init(&data, vc, &rect, mcoords, mcoords_len, sel_op);
if (SEL_OP_USE_PRE_DESELECT(sel_op)) {
data.is_changed |= ED_armature_edit_deselect_all_visible(vc->obedit);
@@ -1071,9 +1103,10 @@ static void do_lasso_select_mball__doSelectElem(void *userData,
{
LassoSelectUserData *data = userData;
const bool is_select = ml->flag & SELECT;
- const bool is_inside = (BLI_rctf_isect_pt_v(data->rect_fl, screen_co) &&
- BLI_lasso_is_point_inside(
- data->mcords, data->moves, screen_co[0], screen_co[1], INT_MAX));
+ const bool is_inside =
+ (BLI_rctf_isect_pt_v(data->rect_fl, screen_co) &&
+ BLI_lasso_is_point_inside(
+ data->mcoords, data->mcoords_len, screen_co[0], screen_co[1], INT_MAX));
const int sel_op_result = ED_select_op_action_deselected(data->sel_op, is_select, is_inside);
if (sel_op_result != -1) {
SET_FLAG_FROM_TEST(ml->flag, sel_op_result, SELECT);
@@ -1081,8 +1114,8 @@ static void do_lasso_select_mball__doSelectElem(void *userData,
}
}
static bool do_lasso_select_meta(ViewContext *vc,
- const int mcords[][2],
- short moves,
+ const int mcoords[][2],
+ const int mcoords_len,
const eSelectOp sel_op)
{
LassoSelectUserData data;
@@ -1090,9 +1123,9 @@ static bool do_lasso_select_meta(ViewContext *vc,
MetaBall *mb = (MetaBall *)vc->obedit->data;
- BLI_lasso_boundbox(&rect, mcords, moves);
+ BLI_lasso_boundbox(&rect, mcoords, mcoords_len);
- view3d_userdata_lassoselect_init(&data, vc, &rect, mcords, moves, sel_op);
+ view3d_userdata_lassoselect_init(&data, vc, &rect, mcoords, mcoords_len, sel_op);
if (SEL_OP_USE_PRE_DESELECT(sel_op)) {
data.is_changed |= BKE_mball_deselect_all(mb);
@@ -1113,9 +1146,10 @@ static void do_lasso_select_meshobject__doSelectVert(void *userData,
{
LassoSelectUserData *data = userData;
const bool is_select = mv->flag & SELECT;
- const bool is_inside = (BLI_rctf_isect_pt_v(data->rect_fl, screen_co) &&
- BLI_lasso_is_point_inside(
- data->mcords, data->moves, screen_co[0], screen_co[1], IS_CLIPPED));
+ const bool is_inside =
+ (BLI_rctf_isect_pt_v(data->rect_fl, screen_co) &&
+ BLI_lasso_is_point_inside(
+ data->mcoords, data->mcoords_len, screen_co[0], screen_co[1], IS_CLIPPED));
const int sel_op_result = ED_select_op_action_deselected(data->sel_op, is_select, is_inside);
if (sel_op_result != -1) {
SET_FLAG_FROM_TEST(mv->flag, sel_op_result, SELECT);
@@ -1124,8 +1158,8 @@ static void do_lasso_select_meshobject__doSelectVert(void *userData,
}
static bool do_lasso_select_paintvert(ViewContext *vc,
wmGenericUserData *wm_userdata,
- const int mcords[][2],
- short moves,
+ const int mcoords[][2],
+ const int mcoords_len,
const eSelectOp sel_op)
{
const bool use_zbuf = !XRAY_ENABLED(vc->v3d);
@@ -1143,7 +1177,7 @@ static bool do_lasso_select_paintvert(ViewContext *vc,
changed |= paintvert_deselect_all_visible(ob, SEL_DESELECT, false);
}
- BLI_lasso_boundbox(&rect, mcords, moves);
+ BLI_lasso_boundbox(&rect, mcoords, mcoords_len);
struct EditSelectBuf_Cache *esel = wm_userdata->data;
if (use_zbuf) {
@@ -1151,7 +1185,7 @@ static bool do_lasso_select_paintvert(ViewContext *vc,
editselect_buf_cache_init_with_generic_userdata(wm_userdata, vc, SCE_SELECT_VERTEX);
esel = wm_userdata->data;
esel->select_bitmap = DRW_select_buffer_bitmap_from_poly(
- vc->depsgraph, vc->region, vc->v3d, mcords, moves, &rect, NULL);
+ vc->depsgraph, vc->region, vc->v3d, mcoords, mcoords_len, &rect, NULL);
}
}
@@ -1163,7 +1197,7 @@ static bool do_lasso_select_paintvert(ViewContext *vc,
else {
LassoSelectUserData data;
- view3d_userdata_lassoselect_init(&data, vc, &rect, mcords, moves, sel_op);
+ view3d_userdata_lassoselect_init(&data, vc, &rect, mcoords, mcoords_len, sel_op);
ED_view3d_init_mats_rv3d(vc->obact, vc->rv3d);
@@ -1185,8 +1219,8 @@ static bool do_lasso_select_paintvert(ViewContext *vc,
}
static bool do_lasso_select_paintface(ViewContext *vc,
wmGenericUserData *wm_userdata,
- const int mcords[][2],
- short moves,
+ const int mcoords[][2],
+ const int mcoords_len,
const eSelectOp sel_op)
{
Object *ob = vc->obact;
@@ -1203,14 +1237,14 @@ static bool do_lasso_select_paintface(ViewContext *vc,
changed |= paintface_deselect_all_visible(vc->C, ob, SEL_DESELECT, false);
}
- BLI_lasso_boundbox(&rect, mcords, moves);
+ BLI_lasso_boundbox(&rect, mcoords, mcoords_len);
struct EditSelectBuf_Cache *esel = wm_userdata->data;
if (esel == NULL) {
editselect_buf_cache_init_with_generic_userdata(wm_userdata, vc, SCE_SELECT_FACE);
esel = wm_userdata->data;
esel->select_bitmap = DRW_select_buffer_bitmap_from_poly(
- vc->depsgraph, vc->region, vc->v3d, mcords, moves, &rect, NULL);
+ vc->depsgraph, vc->region, vc->v3d, mcoords, mcoords_len, &rect, NULL);
}
if (esel->select_bitmap) {
@@ -1224,9 +1258,9 @@ static bool do_lasso_select_paintface(ViewContext *vc,
}
#if 0
-static void do_lasso_select_node(int mcords[][2], short moves, const eSelectOp sel_op)
+static void do_lasso_select_node(int mcoords[][2], const int mcoords_len, const eSelectOp sel_op)
{
- SpaceNode *snode = sa->spacedata.first;
+ SpaceNode *snode = area->spacedata.first;
bNode *node;
rcti rect;
@@ -1234,7 +1268,7 @@ static void do_lasso_select_node(int mcords[][2], short moves, const eSelectOp s
float node_centf[2];
bool changed = false;
- BLI_lasso_boundbox(&rect, mcords, moves);
+ BLI_lasso_boundbox(&rect, mcoords, mcoords_len);
/* store selection in temp test flag */
for (node = snode->edittree->nodes.first; node; node = node->next) {
@@ -1244,7 +1278,7 @@ static void do_lasso_select_node(int mcords[][2], short moves, const eSelectOp s
ipoco_to_areaco_noclip(G.v2d, node_centf, node_cent);
const bool is_select = node->flag & SELECT;
const bool is_inside = (BLI_rcti_isect_pt_v(&rect, node_cent) &&
- BLI_lasso_is_point_inside(mcords, moves, node_cent[0], node_cent[1]));
+ BLI_lasso_is_point_inside(mcoords, mcoords_len, node_cent[0], node_cent[1]));
const int sel_op_result = ED_select_op_action_deselected(sel_op, is_select, is_inside);
if (sel_op_result != -1) {
SET_FLAG_FROM_TEST(node->flag, sel_op_result, SELECT);
@@ -1257,8 +1291,11 @@ static void do_lasso_select_node(int mcords[][2], short moves, const eSelectOp s
}
#endif
-static bool view3d_lasso_select(
- bContext *C, ViewContext *vc, const int mcords[][2], short moves, const eSelectOp sel_op)
+static bool view3d_lasso_select(bContext *C,
+ ViewContext *vc,
+ const int mcoords[][2],
+ const int mcoords_len,
+ const eSelectOp sel_op)
{
Object *ob = CTX_data_active_object(C);
bool changed_multi = false;
@@ -1268,26 +1305,26 @@ static bool view3d_lasso_select(
if (vc->obedit == NULL) { /* Object Mode */
if (BKE_paint_select_face_test(ob)) {
- changed_multi |= do_lasso_select_paintface(vc, wm_userdata, mcords, moves, sel_op);
+ changed_multi |= do_lasso_select_paintface(vc, wm_userdata, mcoords, mcoords_len, sel_op);
}
else if (BKE_paint_select_vert_test(ob)) {
- changed_multi |= do_lasso_select_paintvert(vc, wm_userdata, mcords, moves, sel_op);
+ changed_multi |= do_lasso_select_paintvert(vc, wm_userdata, mcoords, mcoords_len, sel_op);
}
else if (ob &&
(ob->mode & (OB_MODE_VERTEX_PAINT | OB_MODE_WEIGHT_PAINT | OB_MODE_TEXTURE_PAINT))) {
/* pass */
}
else if (ob && (ob->mode & OB_MODE_PARTICLE_EDIT)) {
- changed_multi |= PE_lasso_select(C, mcords, moves, sel_op);
+ changed_multi |= PE_lasso_select(C, mcoords, mcoords_len, sel_op);
}
else if (ob && (ob->mode & OB_MODE_POSE)) {
- changed_multi |= do_lasso_select_pose(vc, mcords, moves, sel_op);
+ changed_multi |= do_lasso_select_pose(vc, mcoords, mcoords_len, sel_op);
if (changed_multi) {
ED_outliner_select_sync_from_pose_bone_tag(C);
}
}
else {
- changed_multi |= do_lasso_select_objects(vc, mcords, moves, sel_op);
+ changed_multi |= do_lasso_select_objects(vc, mcoords, mcoords_len, sel_op);
if (changed_multi) {
ED_outliner_select_sync_from_object_tag(C);
}
@@ -1300,23 +1337,23 @@ static bool view3d_lasso_select(
switch (vc->obedit->type) {
case OB_MESH:
- changed = do_lasso_select_mesh(vc, wm_userdata, mcords, moves, sel_op);
+ changed = do_lasso_select_mesh(vc, wm_userdata, mcoords, mcoords_len, sel_op);
break;
case OB_CURVE:
case OB_SURF:
- changed = do_lasso_select_curve(vc, mcords, moves, sel_op);
+ changed = do_lasso_select_curve(vc, mcoords, mcoords_len, sel_op);
break;
case OB_LATTICE:
- changed = do_lasso_select_lattice(vc, mcords, moves, sel_op);
+ changed = do_lasso_select_lattice(vc, mcoords, mcoords_len, sel_op);
break;
case OB_ARMATURE:
- changed = do_lasso_select_armature(vc, mcords, moves, sel_op);
+ changed = do_lasso_select_armature(vc, mcoords, mcoords_len, sel_op);
if (changed) {
ED_outliner_select_sync_from_edit_bone_tag(C);
}
break;
case OB_MBALL:
- changed = do_lasso_select_meta(vc, mcords, moves, sel_op);
+ changed = do_lasso_select_meta(vc, mcoords, mcoords_len, sel_op);
break;
default:
BLI_assert(!"lasso select on incorrect object type");
@@ -1342,10 +1379,10 @@ static bool view3d_lasso_select(
static int view3d_lasso_select_exec(bContext *C, wmOperator *op)
{
ViewContext vc;
- int mcords_tot;
- const int(*mcords)[2] = WM_gesture_lasso_path_to_array(C, op, &mcords_tot);
+ int mcoords_len;
+ const int(*mcoords)[2] = WM_gesture_lasso_path_to_array(C, op, &mcoords_len);
- if (mcords) {
+ if (mcoords) {
Depsgraph *depsgraph = CTX_data_ensure_evaluated_depsgraph(C);
view3d_operator_needs_opengl(C);
BKE_object_update_select_id(CTX_data_main(C));
@@ -1354,9 +1391,9 @@ static int view3d_lasso_select_exec(bContext *C, wmOperator *op)
ED_view3d_viewcontext_init(C, &vc, depsgraph);
eSelectOp sel_op = RNA_enum_get(op->ptr, "mode");
- bool changed_multi = view3d_lasso_select(C, &vc, mcords, mcords_tot, sel_op);
+ bool changed_multi = view3d_lasso_select(C, &vc, mcoords, mcoords_len, sel_op);
- MEM_freeN((void *)mcords);
+ MEM_freeN((void *)mcoords);
if (changed_multi) {
return OPERATOR_FINISHED;
@@ -1663,20 +1700,31 @@ static int selectbuffer_ret_hits_5(uint *buffer,
/**
* Populate a select buffer with objects and bones, if there are any.
* Checks three selection levels and compare.
+ *
+ * \param do_nearest_xray_if_supported: When set, read in hits that don't stop
+ * at the nearest surface. The hit's must still be ordered by depth.
+ * Needed so we can step to the next, non-active object when it's already selected, see: T76445.
*/
static int mixed_bones_object_selectbuffer(ViewContext *vc,
uint *buffer,
const int mval[2],
eV3DSelectObjectFilter select_filter,
- bool do_nearest)
+ bool do_nearest,
+ bool do_nearest_xray_if_supported)
{
rcti rect;
int hits15, hits9 = 0, hits5 = 0;
bool has_bones15 = false, has_bones9 = false, has_bones5 = false;
- const int select_mode = (do_nearest ? VIEW3D_SELECT_PICK_NEAREST : VIEW3D_SELECT_PICK_ALL);
+ int select_mode = (do_nearest ? VIEW3D_SELECT_PICK_NEAREST : VIEW3D_SELECT_PICK_ALL);
int hits = 0;
+ if (do_nearest_xray_if_supported) {
+ if ((U.gpu_flag & USER_GPU_FLAG_NO_DEPT_PICK) == 0) {
+ select_mode = VIEW3D_SELECT_PICK_ALL;
+ }
+ }
+
/* we _must_ end cache before return, use 'goto finally' */
view3d_opengl_select_cache_begin();
@@ -1780,7 +1828,7 @@ static int mixed_bones_object_selectbuffer_extended(ViewContext *vc,
do_nearest = do_nearest && !enumerate;
- int hits = mixed_bones_object_selectbuffer(vc, buffer, mval, select_filter, do_nearest);
+ int hits = mixed_bones_object_selectbuffer(vc, buffer, mval, select_filter, do_nearest, true);
return hits;
}
@@ -1912,7 +1960,7 @@ Base *ED_view3d_give_base_under_cursor(bContext *C, const int mval[2])
const bool do_nearest = !XRAY_ACTIVE(vc.v3d);
const int hits = mixed_bones_object_selectbuffer(
- &vc, buffer, mval, VIEW3D_SELECT_FILTER_NOP, do_nearest);
+ &vc, buffer, mval, VIEW3D_SELECT_FILTER_NOP, do_nearest, false);
if (hits > 0) {
const bool has_bones = selectbuffer_has_bones(buffer, hits);
@@ -1971,7 +2019,7 @@ static bool ed_object_select_pick(bContext *C,
/* setup view context for argument to callbacks */
ED_view3d_viewcontext_init(C, &vc, depsgraph);
- ARegion *region = CTX_wm_region(C);
+ const ARegion *region = CTX_wm_region(C);
Scene *scene = CTX_data_scene(C);
ViewLayer *view_layer = CTX_data_view_layer(C);
View3D *v3d = CTX_wm_view3d(C);
@@ -2526,6 +2574,7 @@ typedef struct BoxSelectUserData {
const rctf *rect_fl;
rctf _rect_fl;
eSelectOp sel_op;
+ eBezTriple_Flag select_flag;
/* runtime */
bool is_done;
@@ -2544,6 +2593,8 @@ static void view3d_userdata_boxselect_init(BoxSelectUserData *r_data,
BLI_rctf_rcti_copy(&r_data->_rect_fl, rect);
r_data->sel_op = sel_op;
+ /* SELECT by default, but can be changed if needed (only few cases use and respect this). */
+ r_data->select_flag = SELECT;
/* runtime */
r_data->is_done = false;
@@ -2674,6 +2725,7 @@ static void do_nurbs_box_select__doSelect(void *userData,
BPoint *bp,
BezTriple *bezt,
int beztindex,
+ bool handles_visible,
const float screen_co[2])
{
BoxSelectUserData *data = userData;
@@ -2683,17 +2735,17 @@ static void do_nurbs_box_select__doSelect(void *userData,
const bool is_select = bp->f1 & SELECT;
const int sel_op_result = ED_select_op_action_deselected(data->sel_op, is_select, is_inside);
if (sel_op_result != -1) {
- SET_FLAG_FROM_TEST(bp->f1, sel_op_result, SELECT);
+ SET_FLAG_FROM_TEST(bp->f1, sel_op_result, data->select_flag);
data->is_changed = true;
}
}
else {
- if ((data->vc->v3d->overlay.edit_flag & V3D_OVERLAY_EDIT_CU_HANDLES) == 0) {
- /* can only be (beztindex == 0) here since handles are hidden */
+ if (!handles_visible) {
+ /* can only be (beztindex == 1) here since handles are hidden */
const bool is_select = bezt->f2 & SELECT;
const int sel_op_result = ED_select_op_action_deselected(data->sel_op, is_select, is_inside);
if (sel_op_result != -1) {
- SET_FLAG_FROM_TEST(bezt->f2, sel_op_result, SELECT);
+ SET_FLAG_FROM_TEST(bezt->f2, sel_op_result, data->select_flag);
data->is_changed = true;
}
bezt->f1 = bezt->f3 = bezt->f2;
@@ -2703,7 +2755,7 @@ static void do_nurbs_box_select__doSelect(void *userData,
const bool is_select = *flag_p & SELECT;
const int sel_op_result = ED_select_op_action_deselected(data->sel_op, is_select, is_inside);
if (sel_op_result != -1) {
- SET_FLAG_FROM_TEST(*flag_p, sel_op_result, SELECT);
+ SET_FLAG_FROM_TEST(*flag_p, sel_op_result, data->select_flag);
data->is_changed = true;
}
}
@@ -2711,17 +2763,28 @@ static void do_nurbs_box_select__doSelect(void *userData,
}
static bool do_nurbs_box_select(ViewContext *vc, rcti *rect, const eSelectOp sel_op)
{
+ const bool deselect_all = (sel_op == SEL_OP_SET);
BoxSelectUserData data;
view3d_userdata_boxselect_init(&data, vc, rect, sel_op);
- if (SEL_OP_USE_PRE_DESELECT(sel_op)) {
- Curve *curve = (Curve *)vc->obedit->data;
- data.is_changed |= ED_curve_deselect_all(curve->editnurb);
+ Curve *curve = (Curve *)vc->obedit->data;
+ ListBase *nurbs = BKE_curve_editNurbs_get(curve);
+
+ /* For deselect all, items to be selected are tagged with temp flag. Clear that first. */
+ if (deselect_all) {
+ BKE_nurbList_flag_set(nurbs, BEZT_FLAG_TEMP_TAG, false);
+ data.select_flag = BEZT_FLAG_TEMP_TAG;
}
ED_view3d_init_mats_rv3d(vc->obedit, vc->rv3d); /* for foreach's screen/vert projection */
nurbs_foreachScreenVert(vc, do_nurbs_box_select__doSelect, &data, V3D_PROJ_TEST_CLIP_DEFAULT);
+
+ /* Deselect items that were not added to selection (indicated by temp flag). */
+ if (deselect_all) {
+ BKE_nurbList_flag_set_from_flag(nurbs, BEZT_FLAG_TEMP_TAG, SELECT);
+ }
+
BKE_curve_nurb_vert_active_validate(vc->obedit->data);
return data.is_changed;
@@ -3076,7 +3139,7 @@ static bool do_object_box_select(bContext *C, ViewContext *vc, rcti *rect, const
const int hits = view3d_opengl_select(
vc, vbuffer, 4 * (totobj + MAXPICKELEMS), rect, VIEW3D_SELECT_ALL, select_filter);
- for (Base *base = vc->view_layer->object_bases.first; base; base = base->next) {
+ LISTBASE_FOREACH (Base *, base, &vc->view_layer->object_bases) {
base->object->id.tag &= ~LIB_TAG_DOIT;
}
@@ -3092,7 +3155,7 @@ static bool do_object_box_select(bContext *C, ViewContext *vc, rcti *rect, const
goto finally;
}
- for (Base *base = vc->view_layer->object_bases.first; base; base = base->next) {
+ LISTBASE_FOREACH (Base *, base, &vc->view_layer->object_bases) {
if (BASE_SELECTABLE(v3d, base)) {
if ((base->object->runtime.select_id & 0x0000FFFF) != 0) {
BLI_array_append(bases, base);
@@ -3104,9 +3167,9 @@ static bool do_object_box_select(bContext *C, ViewContext *vc, rcti *rect, const
qsort(vbuffer, hits, sizeof(uint[4]), opengl_bone_select_buffer_cmp);
for (const uint *col = vbuffer + 3, *col_end = col + (hits * 4); col < col_end; col += 4) {
- Bone *bone;
- Base *base = ED_armature_base_and_bone_from_select_buffer(
- bases, BLI_array_len(bases), *col, &bone);
+ bPoseChannel *pchan_dummy;
+ Base *base = ED_armature_base_and_pchan_from_select_buffer(
+ bases, BLI_array_len(bases), *col, &pchan_dummy);
if (base != NULL) {
base->object->id.tag |= LIB_TAG_DOIT;
}
@@ -3360,6 +3423,7 @@ typedef struct CircleSelectUserData {
float mval_fl[2];
float radius;
float radius_squared;
+ eBezTriple_Flag select_flag;
/* runtime */
bool is_changed;
@@ -3380,6 +3444,9 @@ static void view3d_userdata_circleselect_init(CircleSelectUserData *r_data,
r_data->radius = rad;
r_data->radius_squared = rad * rad;
+ /* SELECT by default, but can be changed if needed (only few cases use and respect this). */
+ r_data->select_flag = SELECT;
+
/* runtime */
r_data->is_changed = false;
}
@@ -3617,29 +3684,24 @@ static void nurbscurve_circle_doSelect(void *userData,
BPoint *bp,
BezTriple *bezt,
int beztindex,
+ bool UNUSED(handles_visible),
const float screen_co[2])
{
CircleSelectUserData *data = userData;
if (len_squared_v2v2(data->mval_fl, screen_co) <= data->radius_squared) {
if (bp) {
- bp->f1 = data->select ? (bp->f1 | SELECT) : (bp->f1 & ~SELECT);
+ SET_FLAG_FROM_TEST(bp->f1, data->select, data->select_flag);
}
else {
- if ((data->vc->v3d->overlay.edit_flag & V3D_OVERLAY_EDIT_CU_HANDLES) == 0) {
- /* can only be (beztindex == 0) here since handles are hidden */
- bezt->f1 = bezt->f2 = bezt->f3 = data->select ? (bezt->f2 | SELECT) : (bezt->f2 & ~SELECT);
+ if (beztindex == 0) {
+ SET_FLAG_FROM_TEST(bezt->f1, data->select, data->select_flag);
+ }
+ else if (beztindex == 1) {
+ SET_FLAG_FROM_TEST(bezt->f2, data->select, data->select_flag);
}
else {
- if (beztindex == 0) {
- bezt->f1 = data->select ? (bezt->f1 | SELECT) : (bezt->f1 & ~SELECT);
- }
- else if (beztindex == 1) {
- bezt->f2 = data->select ? (bezt->f2 | SELECT) : (bezt->f2 & ~SELECT);
- }
- else {
- bezt->f3 = data->select ? (bezt->f3 | SELECT) : (bezt->f3 & ~SELECT);
- }
+ SET_FLAG_FROM_TEST(bezt->f3, data->select, data->select_flag);
}
}
data->is_changed = true;
@@ -3650,18 +3712,30 @@ static bool nurbscurve_circle_select(ViewContext *vc,
const int mval[2],
float rad)
{
+ const bool select = (sel_op != SEL_OP_SUB);
+ const bool deselect_all = (sel_op == SEL_OP_SET);
CircleSelectUserData data;
bool changed = false;
- if (SEL_OP_USE_PRE_DESELECT(sel_op)) {
- Curve *curve = vc->obedit->data;
- changed |= ED_curve_deselect_all(curve->editnurb);
- }
- const bool select = (sel_op != SEL_OP_SUB);
view3d_userdata_circleselect_init(&data, vc, select, mval, rad);
+ Curve *curve = (Curve *)vc->obedit->data;
+ ListBase *nurbs = BKE_curve_editNurbs_get(curve);
+
+ /* For deselect all, items to be selected are tagged with temp flag. Clear that first. */
+ if (deselect_all) {
+ BKE_nurbList_flag_set(nurbs, BEZT_FLAG_TEMP_TAG, false);
+ data.select_flag = BEZT_FLAG_TEMP_TAG;
+ }
+
ED_view3d_init_mats_rv3d(vc->obedit, vc->rv3d); /* for foreach's screen/vert projection */
nurbs_foreachScreenVert(vc, nurbscurve_circle_doSelect, &data, V3D_PROJ_TEST_CLIP_DEFAULT);
+
+ /* Deselect items that were not added to selection (indicated by temp flag). */
+ if (deselect_all) {
+ BKE_nurbList_flag_set_from_flag(nurbs, BEZT_FLAG_TEMP_TAG, SELECT);
+ }
+
BKE_curve_nurb_vert_active_validate(vc->obedit->data);
return changed || data.is_changed;
diff --git a/source/blender/editors/space_view3d/view3d_utils.c b/source/blender/editors/space_view3d/view3d_utils.c
index 2637fb6d1db..377e8c58ba3 100644
--- a/source/blender/editors/space_view3d/view3d_utils.c
+++ b/source/blender/editors/space_view3d/view3d_utils.c
@@ -86,6 +86,26 @@ void ED_view3d_background_color_get(const Scene *scene, const View3D *v3d, float
UI_GetThemeColor3fv(TH_BACK, r_color);
}
+bool ED_view3d_has_workbench_in_texture_color(const Scene *scene,
+ const Object *ob,
+ const View3D *v3d)
+{
+ if (v3d->shading.type == OB_SOLID) {
+ if (v3d->shading.color_type == V3D_SHADING_TEXTURE_COLOR) {
+ return true;
+ }
+ if (ob->mode == OB_MODE_TEXTURE_PAINT) {
+ return true;
+ }
+ }
+ else if (v3d->shading.type == OB_RENDER) {
+ if (STREQ(scene->r.engine, RE_engine_id_BLENDER_WORKBENCH)) {
+ return scene->display.shading.color_type == V3D_SHADING_TEXTURE_COLOR;
+ }
+ }
+ return false;
+}
+
Camera *ED_view3d_camera_data_get(View3D *v3d, RegionView3D *rv3d)
{
/* establish the camera object,
@@ -228,26 +248,26 @@ void ED_view3d_polygon_offset(const RegionView3D *rv3d, const float dist)
bool ED_view3d_context_activate(bContext *C)
{
- bScreen *sc = CTX_wm_screen(C);
- ScrArea *sa = CTX_wm_area(C);
+ bScreen *screen = CTX_wm_screen(C);
+ ScrArea *area = CTX_wm_area(C);
ARegion *region;
- /* sa can be NULL when called from python */
- if (sa == NULL || sa->spacetype != SPACE_VIEW3D) {
- sa = BKE_screen_find_big_area(sc, SPACE_VIEW3D, 0);
+ /* area can be NULL when called from python */
+ if (area == NULL || area->spacetype != SPACE_VIEW3D) {
+ area = BKE_screen_find_big_area(screen, SPACE_VIEW3D, 0);
}
- if (sa == NULL) {
+ if (area == NULL) {
return false;
}
- region = BKE_area_find_region_active_win(sa);
+ region = BKE_area_find_region_active_win(area);
if (region == NULL) {
return false;
}
/* bad context switch .. */
- CTX_wm_area_set(C, sa);
+ CTX_wm_area_set(C, area);
CTX_wm_region_set(C, region);
return true;
@@ -666,7 +686,7 @@ bool ED_view3d_camera_lock_autokey(View3D *v3d,
* Use with quad-split so each view is clipped by the bounds of each view axis.
* \{ */
-static void view3d_boxview_clip(ScrArea *sa)
+static void view3d_boxview_clip(ScrArea *area)
{
ARegion *region;
BoundBox *bb = MEM_callocN(sizeof(BoundBox), "clipbb");
@@ -675,7 +695,7 @@ static void view3d_boxview_clip(ScrArea *sa)
int val;
/* create bounding box */
- for (region = sa->regionbase.first; region; region = region->next) {
+ for (region = area->regionbase.first; region; region = region->next) {
if (region->regiontype == RGN_TYPE_WINDOW) {
RegionView3D *rv3d = region->regiondata;
@@ -747,7 +767,7 @@ static void view3d_boxview_clip(ScrArea *sa)
}
/* create bounding box */
- for (region = sa->regionbase.first; region; region = region->next) {
+ for (region = area->regionbase.first; region; region = region->next) {
if (region->regiontype == RGN_TYPE_WINDOW) {
RegionView3D *rv3d = region->regiondata;
@@ -812,13 +832,13 @@ static void view3d_boxview_sync_axis(RegionView3D *rv3d_dst, RegionView3D *rv3d_
}
/* sync center/zoom view of region to others, for view transforms */
-void view3d_boxview_sync(ScrArea *sa, ARegion *region)
+void view3d_boxview_sync(ScrArea *area, ARegion *region)
{
ARegion *artest;
RegionView3D *rv3d = region->regiondata;
short clip = 0;
- for (artest = sa->regionbase.first; artest; artest = artest->next) {
+ for (artest = area->regionbase.first; artest; artest = artest->next) {
if (artest != region && artest->regiontype == RGN_TYPE_WINDOW) {
RegionView3D *rv3dtest = artest->regiondata;
@@ -833,18 +853,18 @@ void view3d_boxview_sync(ScrArea *sa, ARegion *region)
}
if (clip) {
- view3d_boxview_clip(sa);
+ view3d_boxview_clip(area);
}
}
/* for home, center etc */
-void view3d_boxview_copy(ScrArea *sa, ARegion *region)
+void view3d_boxview_copy(ScrArea *area, ARegion *region)
{
ARegion *artest;
RegionView3D *rv3d = region->regiondata;
bool clip = false;
- for (artest = sa->regionbase.first; artest; artest = artest->next) {
+ for (artest = area->regionbase.first; artest; artest = artest->next) {
if (artest != region && artest->regiontype == RGN_TYPE_WINDOW) {
RegionView3D *rv3dtest = artest->regiondata;
@@ -859,14 +879,14 @@ void view3d_boxview_copy(ScrArea *sa, ARegion *region)
}
if (clip) {
- view3d_boxview_clip(sa);
+ view3d_boxview_clip(area);
}
}
/* 'clip' is used to know if our clip setting has changed */
-void ED_view3d_quadview_update(ScrArea *sa, ARegion *region, bool do_clip)
+void ED_view3d_quadview_update(ScrArea *area, ARegion *region, bool do_clip)
{
- ARegion *ar_sync = NULL;
+ ARegion *region_sync = NULL;
RegionView3D *rv3d = region->regiondata;
short viewlock;
/* this function copies flags from the first of the 3 other quadview
@@ -892,21 +912,21 @@ void ED_view3d_quadview_update(ScrArea *sa, ARegion *region, bool do_clip)
rv3d->rflag &= ~RV3D_BOXCLIP;
}
- /* use ar_sync so we sync with one of the aligned views below
+ /* use region_sync so we sync with one of the aligned views below
* else the view jumps on changing view settings like 'clip'
* since it copies from the perspective view */
- ar_sync = region;
+ region_sync = region;
}
}
if (RV3D_LOCK_FLAGS(rv3d) & RV3D_BOXVIEW) {
- view3d_boxview_sync(sa, ar_sync ? ar_sync : sa->regionbase.last);
+ view3d_boxview_sync(area, region_sync ? region_sync : area->regionbase.last);
}
/* ensure locked regions have an axis, locked user views don't make much sense */
if (viewlock & RV3D_LOCK_ROTATION) {
int index_qsplit = 0;
- for (region = sa->regionbase.first; region; region = region->next) {
+ for (region = area->regionbase.first; region; region = region->next) {
if (region->alignment == RGN_ALIGN_QSPLIT) {
rv3d = region->regiondata;
if (rv3d->viewlock) {
@@ -922,7 +942,7 @@ void ED_view3d_quadview_update(ScrArea *sa, ARegion *region, bool do_clip)
}
}
- ED_area_tag_redraw(sa);
+ ED_area_tag_redraw(area);
}
/** \} */
diff --git a/source/blender/editors/space_view3d/view3d_view.c b/source/blender/editors/space_view3d/view3d_view.c
index 30587e6084d..fe77ca05a04 100644
--- a/source/blender/editors/space_view3d/view3d_view.c
+++ b/source/blender/editors/space_view3d/view3d_view.c
@@ -128,7 +128,7 @@ void ED_view3d_smooth_view_ex(
const Depsgraph *depsgraph,
wmWindowManager *wm,
wmWindow *win,
- ScrArea *sa,
+ ScrArea *area,
View3D *v3d,
ARegion *region,
const int smooth_viewtx,
@@ -293,7 +293,7 @@ void ED_view3d_smooth_view_ex(
}
if (RV3D_LOCK_FLAGS(rv3d) & RV3D_BOXVIEW) {
- view3d_boxview_copy(sa, region);
+ view3d_boxview_copy(area, region);
}
ED_region_tag_redraw(region);
@@ -309,9 +309,9 @@ void ED_view3d_smooth_view(bContext *C,
const Depsgraph *depsgraph = CTX_data_ensure_evaluated_depsgraph(C);
wmWindowManager *wm = CTX_wm_manager(C);
wmWindow *win = CTX_wm_window(C);
- ScrArea *sa = CTX_wm_area(C);
+ ScrArea *area = CTX_wm_area(C);
- ED_view3d_smooth_view_ex(depsgraph, wm, win, sa, v3d, region, smooth_viewtx, sview);
+ ED_view3d_smooth_view_ex(depsgraph, wm, win, area, v3d, region, smooth_viewtx, sview);
}
/* only meant for timer usage */
@@ -615,17 +615,18 @@ static void sync_viewport_camera_smoothview(bContext *C,
if (v3d->scenelock) {
ListBase *lb = (space_link == area->spacedata.first) ? &area->regionbase :
&space_link->regionbase;
- for (ARegion *other_ar = lb->first; other_ar != NULL; other_ar = other_ar->next) {
- if (other_ar->regiontype == RGN_TYPE_WINDOW) {
- if (other_ar->regiondata) {
- RegionView3D *other_rv3d = other_ar->regiondata;
+ for (ARegion *other_region = lb->first; other_region != NULL;
+ other_region = other_region->next) {
+ if (other_region->regiontype == RGN_TYPE_WINDOW) {
+ if (other_region->regiondata) {
+ RegionView3D *other_rv3d = other_region->regiondata;
if (other_rv3d->persp == RV3D_CAMOB) {
Object *other_camera_old = other_v3d->camera;
other_v3d->camera = ob;
ED_view3d_lastview_store(other_rv3d);
ED_view3d_smooth_view(C,
other_v3d,
- other_ar,
+ other_region,
smooth_viewtx,
&(const V3D_SmoothParams){
.camera_old = other_camera_old,
@@ -704,9 +705,9 @@ static int view3d_setobjectascamera_exec(bContext *C, wmOperator *op)
bool ED_operator_rv3d_user_region_poll(bContext *C)
{
View3D *v3d_dummy;
- ARegion *ar_dummy;
+ ARegion *region_dummy;
- return ED_view3d_context_user_region(C, &v3d_dummy, &ar_dummy);
+ return ED_view3d_context_user_region(C, &v3d_dummy, &region_dummy);
}
void VIEW3D_OT_object_as_camera(wmOperatorType *ot)
@@ -1061,7 +1062,7 @@ int view3d_opengl_select(ViewContext *vc,
* the number of items is nearly always 1, maybe 2..3 in rare cases. */
LinkNode *ob_pose_list = NULL;
VirtualModifierData virtualModifierData;
- const ModifierData *md = modifiers_getVirtualModifierList(obact, &virtualModifierData);
+ const ModifierData *md = BKE_modifiers_get_virtual_modifierlist(obact, &virtualModifierData);
for (; md; md = md->next) {
if (md->type == eModifierType_Armature) {
ArmatureModifierData *amd = (ArmatureModifierData *)md;
@@ -1199,16 +1200,16 @@ finally:
static uint free_localview_bit(Main *bmain)
{
- ScrArea *sa;
- bScreen *sc;
+ ScrArea *area;
+ bScreen *screen;
ushort local_view_bits = 0;
/* sometimes we loose a localview: when an area is closed */
/* check all areas: which localviews are in use? */
- for (sc = bmain->screens.first; sc; sc = sc->id.next) {
- for (sa = sc->areabase.first; sa; sa = sa->next) {
- SpaceLink *sl = sa->spacedata.first;
+ for (screen = bmain->screens.first; screen; screen = screen->id.next) {
+ for (area = screen->areabase.first; area; area = area->next) {
+ SpaceLink *sl = area->spacedata.first;
for (; sl; sl = sl->next) {
if (sl->spacetype == SPACE_VIEW3D) {
View3D *v3d = (View3D *)sl;
@@ -1234,12 +1235,12 @@ static bool view3d_localview_init(const Depsgraph *depsgraph,
wmWindow *win,
Main *bmain,
ViewLayer *view_layer,
- ScrArea *sa,
+ ScrArea *area,
const bool frame_selected,
const int smooth_viewtx,
ReportList *reports)
{
- View3D *v3d = sa->spacedata.first;
+ View3D *v3d = area->spacedata.first;
Base *base;
float min[3], max[3], box[3];
float size = 0.0f;
@@ -1301,7 +1302,7 @@ static bool view3d_localview_init(const Depsgraph *depsgraph,
memcpy(v3d->localvd, v3d, sizeof(View3D));
v3d->local_view_uuid = local_view_bit;
- for (region = sa->regionbase.first; region; region = region->next) {
+ for (region = area->regionbase.first; region; region = region->next) {
if (region->regiontype == RGN_TYPE_WINDOW) {
RegionView3D *rv3d = region->regiondata;
bool ok_dist = true;
@@ -1342,7 +1343,7 @@ static bool view3d_localview_init(const Depsgraph *depsgraph,
ED_view3d_smooth_view_ex(depsgraph,
wm,
win,
- sa,
+ area,
v3d,
region,
smooth_viewtx,
@@ -1364,11 +1365,11 @@ static void view3d_localview_exit(const Depsgraph *depsgraph,
wmWindowManager *wm,
wmWindow *win,
ViewLayer *view_layer,
- ScrArea *sa,
+ ScrArea *area,
const bool frame_selected,
const int smooth_viewtx)
{
- View3D *v3d = sa->spacedata.first;
+ View3D *v3d = area->spacedata.first;
if (v3d->localvd == NULL) {
return;
@@ -1389,7 +1390,7 @@ static void view3d_localview_exit(const Depsgraph *depsgraph,
MEM_freeN(v3d->localvd);
v3d->localvd = NULL;
- for (ARegion *region = sa->regionbase.first; region; region = region->next) {
+ LISTBASE_FOREACH (ARegion *, region, &area->regionbase) {
if (region->regiontype == RGN_TYPE_WINDOW) {
RegionView3D *rv3d = region->regiondata;
@@ -1410,7 +1411,7 @@ static void view3d_localview_exit(const Depsgraph *depsgraph,
ED_view3d_smooth_view_ex(depsgraph,
wm,
win,
- sa,
+ area,
v3d,
region,
smooth_viewtx,
@@ -1438,23 +1439,23 @@ static int localview_exec(bContext *C, wmOperator *op)
Main *bmain = CTX_data_main(C);
Scene *scene = CTX_data_scene(C);
ViewLayer *view_layer = CTX_data_view_layer(C);
- ScrArea *sa = CTX_wm_area(C);
+ ScrArea *area = CTX_wm_area(C);
View3D *v3d = CTX_wm_view3d(C);
bool frame_selected = RNA_boolean_get(op->ptr, "frame_selected");
bool changed;
if (v3d->localvd) {
- view3d_localview_exit(depsgraph, wm, win, view_layer, sa, frame_selected, smooth_viewtx);
+ view3d_localview_exit(depsgraph, wm, win, view_layer, area, frame_selected, smooth_viewtx);
changed = true;
}
else {
changed = view3d_localview_init(
- depsgraph, wm, win, bmain, view_layer, sa, frame_selected, smooth_viewtx, op->reports);
+ depsgraph, wm, win, bmain, view_layer, area, frame_selected, smooth_viewtx, op->reports);
}
if (changed) {
DEG_id_type_tag(bmain, ID_OB);
- ED_area_tag_redraw(sa);
+ ED_area_tag_redraw(area);
/* Unselected objects become selected when exiting. */
if (v3d->localvd == NULL) {
@@ -1555,19 +1556,17 @@ void VIEW3D_OT_localview_remove_from(wmOperatorType *ot)
/** \name Local Collections
* \{ */
-static uint free_localcollection_bit(Main *bmain,
- unsigned short local_collections_uuid,
- bool *r_reset)
+static uint free_localcollection_bit(Main *bmain, ushort local_collections_uuid, bool *r_reset)
{
- ScrArea *sa;
- bScreen *sc;
+ ScrArea *area;
+ bScreen *screen;
ushort local_view_bits = 0;
/* Check all areas: which localviews are in use? */
- for (sc = bmain->screens.first; sc; sc = sc->id.next) {
- for (sa = sc->areabase.first; sa; sa = sa->next) {
- SpaceLink *sl = sa->spacedata.first;
+ for (screen = bmain->screens.first; screen; screen = screen->id.next) {
+ for (area = screen->areabase.first; area; area = area->next) {
+ SpaceLink *sl = area->spacedata.first;
for (; sl; sl = sl->next) {
if (sl->spacetype == SPACE_VIEW3D) {
View3D *v3d = (View3D *)sl;
@@ -1596,7 +1595,7 @@ static uint free_localcollection_bit(Main *bmain,
}
static void local_collections_reset_uuid(LayerCollection *layer_collection,
- const unsigned short local_view_bit)
+ const ushort local_view_bit)
{
if (layer_collection->flag & LAYER_COLLECTION_HIDE) {
layer_collection->local_collections_bits &= ~local_view_bit;
diff --git a/source/blender/editors/space_view3d/view3d_walk.c b/source/blender/editors/space_view3d/view3d_walk.c
index 89b5618075a..7aefd173953 100644
--- a/source/blender/editors/space_view3d/view3d_walk.c
+++ b/source/blender/editors/space_view3d/view3d_walk.c
@@ -160,14 +160,14 @@ void walk_modal_keymap(wmKeyConfig *keyconf)
{0, NULL, 0, NULL, NULL},
};
- wmKeyMap *keymap = WM_modalkeymap_get(keyconf, "View3D Walk Modal");
+ wmKeyMap *keymap = WM_modalkeymap_find(keyconf, "View3D Walk Modal");
/* this function is called for each spacetype, only needs to add map once */
if (keymap && keymap->modal_items) {
return;
}
- keymap = WM_modalkeymap_add(keyconf, "View3D Walk Modal", modal_items);
+ keymap = WM_modalkeymap_ensure(keyconf, "View3D Walk Modal", modal_items);
/* assign map to operators */
WM_modalkeymap_assign(keymap, "VIEW3D_OT_walk");
@@ -374,16 +374,19 @@ static bool walk_floor_distance_get(RegionView3D *rv3d,
mul_v3_v3fl(dvec_tmp, dvec, walk->grid);
add_v3_v3(ray_start, dvec_tmp);
- ret = ED_transform_snap_object_project_ray(walk->snap_context,
- walk->depsgraph,
- &(const struct SnapObjectParams){
- .snap_select = SNAP_ALL,
- },
- ray_start,
- ray_normal,
- r_distance,
- r_location,
- r_normal_dummy);
+ ret = ED_transform_snap_object_project_ray(
+ walk->snap_context,
+ walk->depsgraph,
+ &(const struct SnapObjectParams){
+ .snap_select = SNAP_ALL,
+ /* Avoid having to convert the edit-mesh to a regular mesh. */
+ .use_object_edit_cage = true,
+ },
+ ray_start,
+ ray_normal,
+ r_distance,
+ r_location,
+ r_normal_dummy);
/* artificially scale the distance to the scene size */
*r_distance /= walk->grid;
@@ -449,7 +452,6 @@ static float userdef_speed = -1.f;
static bool initWalkInfo(bContext *C, WalkInfo *walk, wmOperator *op)
{
wmWindowManager *wm = CTX_wm_manager(C);
- Main *bmain = CTX_data_main(C);
wmWindow *win = CTX_wm_window(C);
walk->rv3d = CTX_wm_region_view3d(C);
@@ -553,7 +555,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(
- bmain, walk->scene, 0, walk->region, walk->v3d);
+ walk->scene, 0, walk->region, walk->v3d);
walk->v3d_camera_control = ED_view3d_cameracontrol_acquire(
walk->depsgraph,
diff --git a/source/blender/editors/transform/transform.c b/source/blender/editors/transform/transform.c
index 0ea355e9b6e..79090bd633e 100644
--- a/source/blender/editors/transform/transform.c
+++ b/source/blender/editors/transform/transform.c
@@ -49,6 +49,7 @@
#include "ED_space_api.h"
#include "WM_api.h"
+#include "WM_message.h"
#include "WM_types.h"
#include "UI_interface_icons.h"
@@ -77,7 +78,7 @@ static void initSnapSpatial(TransInfo *t, float r_snap[3]);
bool transdata_check_local_islands(TransInfo *t, short around)
{
- return ((around == V3D_AROUND_LOCAL_ORIGINS) && ((ELEM(t->obedit_type, OB_MESH))));
+ return ((around == V3D_AROUND_LOCAL_ORIGINS) && ((ELEM(t->obedit_type, OB_MESH, OB_GPENCIL))));
}
/* ************************** SPACE DEPENDENT CODE **************************** */
@@ -110,7 +111,7 @@ void setTransformViewAspect(TransInfo *t, float r_aspect[3])
copy_v3_fl(r_aspect, 1.0f);
if (t->spacetype == SPACE_IMAGE) {
- SpaceImage *sima = t->sa->spacedata.first;
+ SpaceImage *sima = t->area->spacedata.first;
if (t->options & CTX_MASK) {
ED_space_image_get_aspect(sima, &r_aspect[0], &r_aspect[1]);
@@ -123,7 +124,7 @@ void setTransformViewAspect(TransInfo *t, float r_aspect[3])
}
}
else if (t->spacetype == SPACE_CLIP) {
- SpaceClip *sclip = t->sa->spacedata.first;
+ SpaceClip *sclip = t->area->spacedata.first;
if (t->options & CTX_MOVIECLIP) {
ED_space_clip_get_aspect_dimension_aware(sclip, &r_aspect[0], &r_aspect[1]);
@@ -234,7 +235,7 @@ void projectIntViewEx(TransInfo *t, const float vec[3], int adr[2], const eV3DPr
}
}
else if (t->spacetype == SPACE_IMAGE) {
- SpaceImage *sima = t->sa->spacedata.first;
+ SpaceImage *sima = t->area->spacedata.first;
if (t->options & CTX_MASK) {
float v[2];
@@ -265,7 +266,7 @@ void projectIntViewEx(TransInfo *t, const float vec[3], int adr[2], const eV3DPr
else if (t->spacetype == SPACE_ACTION) {
int out[2] = {0, 0};
#if 0
- SpaceAction *sact = t->sa->spacedata.first;
+ SpaceAction *sact = t->area->spacedata.first;
if (sact->flag & SACTION_DRAWTIME) {
//vec[0] = vec[0]/((t->scene->r.frs_sec / t->scene->r.frs_sec_base));
@@ -296,7 +297,7 @@ void projectIntViewEx(TransInfo *t, const float vec[3], int adr[2], const eV3DPr
adr[1] = out[1];
}
else if (t->spacetype == SPACE_CLIP) {
- SpaceClip *sc = t->sa->spacedata.first;
+ SpaceClip *sc = t->area->spacedata.first;
if (t->options & CTX_MASK) {
MovieClip *clip = ED_space_clip_get_clip(sc);
@@ -377,7 +378,7 @@ void applyAspectRatio(TransInfo *t, float vec[2])
{
if ((t->spacetype == SPACE_IMAGE) && (t->mode == TFM_TRANSLATION) &&
!(t->options & CTX_PAINT_CURVE)) {
- SpaceImage *sima = t->sa->spacedata.first;
+ SpaceImage *sima = t->area->spacedata.first;
if ((sima->flag & SI_COORDFLOATS) == 0) {
int width, height;
@@ -401,7 +402,7 @@ void applyAspectRatio(TransInfo *t, float vec[2])
void removeAspectRatio(TransInfo *t, float vec[2])
{
if ((t->spacetype == SPACE_IMAGE) && (t->mode == TFM_TRANSLATION)) {
- SpaceImage *sima = t->sa->spacedata.first;
+ SpaceImage *sima = t->area->spacedata.first;
if ((sima->flag & SI_COORDFLOATS) == 0) {
int width, height;
@@ -453,18 +454,18 @@ static void viewRedrawForce(const bContext *C, TransInfo *t)
}
}
else if (t->spacetype == SPACE_ACTION) {
- // SpaceAction *saction = (SpaceAction *)t->sa->spacedata.first;
+ // SpaceAction *saction = (SpaceAction *)t->area->spacedata.first;
WM_event_add_notifier(C, NC_ANIMATION | ND_KEYFRAME | NA_EDITED, NULL);
}
else if (t->spacetype == SPACE_GRAPH) {
- // SpaceGraph *sipo = (SpaceGraph *)t->sa->spacedata.first;
+ // SpaceGraph *sipo = (SpaceGraph *)t->area->spacedata.first;
WM_event_add_notifier(C, NC_ANIMATION | ND_KEYFRAME | NA_EDITED, NULL);
}
else if (t->spacetype == SPACE_NLA) {
WM_event_add_notifier(C, NC_ANIMATION | ND_NLA | NA_EDITED, NULL);
}
else if (t->spacetype == SPACE_NODE) {
- // ED_area_tag_redraw(t->sa);
+ // ED_area_tag_redraw(t->area);
WM_event_add_notifier(C, NC_SPACE | ND_SPACE_NODE_VIEW, NULL);
}
else if (t->spacetype == SPACE_SEQ) {
@@ -483,21 +484,21 @@ static void viewRedrawForce(const bContext *C, TransInfo *t)
WM_paint_cursor_tag_redraw(window, t->region);
}
else if (t->flag & T_CURSOR) {
- ED_area_tag_redraw(t->sa);
+ ED_area_tag_redraw(t->area);
}
else {
// XXX how to deal with lock?
- SpaceImage *sima = (SpaceImage *)t->sa->spacedata.first;
+ SpaceImage *sima = (SpaceImage *)t->area->spacedata.first;
if (sima->lock) {
WM_event_add_notifier(C, NC_GEOM | ND_DATA, OBEDIT_FROM_VIEW_LAYER(t->view_layer)->data);
}
else {
- ED_area_tag_redraw(t->sa);
+ ED_area_tag_redraw(t->area);
}
}
}
else if (t->spacetype == SPACE_CLIP) {
- SpaceClip *sc = (SpaceClip *)t->sa->spacedata.first;
+ SpaceClip *sc = (SpaceClip *)t->area->spacedata.first;
if (ED_space_clip_check_show_trackedit(sc)) {
MovieClip *clip = ED_space_clip_get_clip(sc);
@@ -517,7 +518,7 @@ static void viewRedrawForce(const bContext *C, TransInfo *t)
static void viewRedrawPost(bContext *C, TransInfo *t)
{
- ED_area_status_text(t->sa, NULL);
+ ED_area_status_text(t->area, NULL);
if (t->spacetype == SPACE_VIEW3D) {
/* if autokeying is enabled, send notifiers that keyframes were added */
@@ -559,7 +560,7 @@ static void viewRedrawPost(bContext *C, TransInfo *t)
/* ************************** TRANSFORMATIONS **************************** */
-static void view_editmove(unsigned short UNUSED(event))
+static void view_editmove(ushort UNUSED(event))
{
#if 0 // TRANSFORM_FIX_ME
int refresh = 0;
@@ -770,17 +771,18 @@ wmKeyMap *transform_modal_keymap(wmKeyConfig *keyconf)
{0, NULL, 0, NULL, NULL},
};
- wmKeyMap *keymap = WM_modalkeymap_get(keyconf, "Transform Modal Map");
+ wmKeyMap *keymap = WM_modalkeymap_find(keyconf, "Transform Modal Map");
- keymap = WM_modalkeymap_add(keyconf, "Transform Modal Map", modal_items);
+ keymap = WM_modalkeymap_ensure(keyconf, "Transform Modal Map", modal_items);
keymap->poll_modal_item = transform_modal_item_poll;
return keymap;
}
-static void transform_event_xyz_constraint(TransInfo *t, short key_type, char cmode, bool is_plane)
+static void transform_event_xyz_constraint(TransInfo *t, short key_type, bool is_plane)
{
if (!(t->flag & T_NO_CONSTRAINT)) {
+ char cmode = constraintModeToChar(t);
int constraint_axis, constraint_plane;
const bool edit_2d = (t->flag & T_2D_EDIT) != 0;
const char *msg1 = "", *msg2 = "", *msg3 = "";
@@ -824,11 +826,17 @@ static void transform_event_xyz_constraint(TransInfo *t, short key_type, char cm
}
}
else if (!edit_2d) {
- if (cmode != axis) {
- /* First press, constraint to an axis. */
- t->orientation.index = 0;
- const short *orientation_ptr = t->orientation.types[t->orientation.index];
- const short orientation = orientation_ptr ? *orientation_ptr : V3D_ORIENT_GLOBAL;
+ if (t->orient_curr == 0 || ELEM(cmode, '\0', axis)) {
+ /* Successive presses on existing axis, cycle orientation modes. */
+ t->orient_curr = (short)((t->orient_curr + 1) % (int)ARRAY_SIZE(t->orient));
+ transform_orientations_current_set(t, t->orient_curr);
+ }
+
+ if (t->orient_curr == 0) {
+ stopConstraint(t);
+ }
+ else {
+ const short orientation = t->orient[t->orient_curr].type;
if (is_plane == false) {
setUserConstraint(t, orientation, constraint_axis, msg2);
}
@@ -836,24 +844,6 @@ static void transform_event_xyz_constraint(TransInfo *t, short key_type, char cm
setUserConstraint(t, orientation, constraint_plane, msg3);
}
}
- else {
- /* Successive presses on existing axis, cycle orientation modes. */
- t->orientation.index = (t->orientation.index + 1) % ARRAY_SIZE(t->orientation.types);
-
- if (t->orientation.index == 0) {
- stopConstraint(t);
- }
- else {
- const short *orientation_ptr = t->orientation.types[t->orientation.index];
- const short orientation = orientation_ptr ? *orientation_ptr : V3D_ORIENT_GLOBAL;
- if (is_plane == false) {
- setUserConstraint(t, orientation, constraint_axis, msg2);
- }
- else {
- setUserConstraint(t, orientation, constraint_plane, msg3);
- }
- }
- }
}
t->redraw |= TREDRAW_HARD;
}
@@ -861,7 +851,6 @@ static void transform_event_xyz_constraint(TransInfo *t, short key_type, char cm
int transformEvent(TransInfo *t, const wmEvent *event)
{
- char cmode = constraintModeToChar(t);
bool handled = false;
const int modifiers_prev = t->modifiers;
const int mode_prev = t->mode;
@@ -908,74 +897,59 @@ int transformEvent(TransInfo *t, const wmEvent *event)
break;
case TFM_MODAL_TRANSLATE:
/* only switch when... */
- if (ELEM(t->mode,
- TFM_ROTATION,
- TFM_RESIZE,
- TFM_TRACKBALL,
- TFM_EDGE_SLIDE,
- TFM_VERT_SLIDE)) {
- restoreTransObjects(t);
- resetTransModal(t);
- resetTransRestrictions(t);
- transform_mode_init(t, NULL, TFM_TRANSLATION);
- initSnapping(t, NULL); // need to reinit after mode change
- t->redraw |= TREDRAW_HARD;
- handled = true;
- }
- else if (t->mode == TFM_SEQ_SLIDE) {
- t->flag ^= T_ALT_TRANSFORM;
- t->redraw |= TREDRAW_HARD;
- handled = true;
- }
- else {
- if (t->obedit_type == OB_MESH) {
- if ((t->mode == TFM_TRANSLATION) && (t->spacetype == SPACE_VIEW3D)) {
- restoreTransObjects(t);
+ if (t->mode == TFM_TRANSLATION) {
+ if ((t->obedit_type == OB_MESH) && (t->spacetype == SPACE_VIEW3D)) {
+ restoreTransObjects(t);
+ resetTransModal(t);
+ resetTransRestrictions(t);
+
+ /* first try edge slide */
+ transform_mode_init(t, NULL, TFM_EDGE_SLIDE);
+ /* if that fails, do vertex slide */
+ if (t->state == TRANS_CANCEL) {
resetTransModal(t);
+ t->state = TRANS_STARTING;
+ transform_mode_init(t, NULL, TFM_VERT_SLIDE);
+ }
+ /* vert slide can fail on unconnected vertices (rare but possible) */
+ if (t->state == TRANS_CANCEL) {
+ resetTransModal(t);
+ t->state = TRANS_STARTING;
+ restoreTransObjects(t);
resetTransRestrictions(t);
-
- /* first try edge slide */
- transform_mode_init(t, NULL, TFM_EDGE_SLIDE);
- /* if that fails, do vertex slide */
- if (t->state == TRANS_CANCEL) {
- resetTransModal(t);
- t->state = TRANS_STARTING;
- transform_mode_init(t, NULL, TFM_VERT_SLIDE);
- }
- /* vert slide can fail on unconnected vertices (rare but possible) */
- if (t->state == TRANS_CANCEL) {
- resetTransModal(t);
- t->state = TRANS_STARTING;
- restoreTransObjects(t);
- resetTransRestrictions(t);
- transform_mode_init(t, NULL, TFM_TRANSLATION);
- }
- initSnapping(t, NULL); // need to reinit after mode change
- t->redraw |= TREDRAW_HARD;
- handled = true;
+ transform_mode_init(t, NULL, TFM_TRANSLATION);
}
+ initSnapping(t, NULL); // need to reinit after mode change
+ t->redraw |= TREDRAW_HARD;
+ handled = true;
}
else if (t->options & (CTX_MOVIECLIP | CTX_MASK)) {
- if (t->mode == TFM_TRANSLATION) {
- restoreTransObjects(t);
+ restoreTransObjects(t);
- t->flag ^= T_ALT_TRANSFORM;
- t->redraw |= TREDRAW_HARD;
- handled = true;
- }
+ t->flag ^= T_ALT_TRANSFORM;
+ t->redraw |= TREDRAW_HARD;
+ handled = true;
}
}
+ else if (t->mode == TFM_SEQ_SLIDE) {
+ t->flag ^= T_ALT_TRANSFORM;
+ t->redraw |= TREDRAW_HARD;
+ handled = true;
+ }
+ else if (transform_mode_is_changeable(t->mode)) {
+ restoreTransObjects(t);
+ resetTransModal(t);
+ resetTransRestrictions(t);
+ transform_mode_init(t, NULL, TFM_TRANSLATION);
+ initSnapping(t, NULL); // need to reinit after mode change
+ t->redraw |= TREDRAW_HARD;
+ handled = true;
+ }
break;
case TFM_MODAL_ROTATE:
/* only switch when... */
if (!(t->options & CTX_TEXTURE) && !(t->options & (CTX_MOVIECLIP | CTX_MASK))) {
- if (ELEM(t->mode,
- TFM_ROTATION,
- TFM_RESIZE,
- TFM_TRACKBALL,
- TFM_TRANSLATION,
- TFM_EDGE_SLIDE,
- TFM_VERT_SLIDE)) {
+ if (transform_mode_is_changeable(t->mode)) {
restoreTransObjects(t);
resetTransModal(t);
resetTransRestrictions(t);
@@ -994,15 +968,23 @@ int transformEvent(TransInfo *t, const wmEvent *event)
break;
case TFM_MODAL_RESIZE:
/* only switch when... */
- if (ELEM(t->mode,
- TFM_ROTATION,
- TFM_TRANSLATION,
- TFM_TRACKBALL,
- TFM_EDGE_SLIDE,
- TFM_VERT_SLIDE)) {
+ if (t->mode == TFM_RESIZE) {
+ if (t->options & CTX_MOVIECLIP) {
+ restoreTransObjects(t);
+ t->flag ^= T_ALT_TRANSFORM;
+ t->redraw |= TREDRAW_HARD;
+ handled = true;
+ }
+ }
+ else if (t->mode == TFM_SHRINKFATTEN) {
+ t->flag ^= T_ALT_TRANSFORM;
+ t->redraw |= TREDRAW_HARD;
+ handled = true;
+ }
+ else if (transform_mode_is_changeable(t->mode)) {
/* Scale isn't normally very useful after extrude along normals, see T39756 */
- if ((t->con.mode & CON_APPLY) && (t->con.orientation == V3D_ORIENT_NORMAL)) {
+ if ((t->con.mode & CON_APPLY) && (t->orient[t->orient_curr].type == V3D_ORIENT_NORMAL)) {
stopConstraint(t);
}
@@ -1014,20 +996,6 @@ int transformEvent(TransInfo *t, const wmEvent *event)
t->redraw |= TREDRAW_HARD;
handled = true;
}
- else if (t->mode == TFM_SHRINKFATTEN) {
- t->flag ^= T_ALT_TRANSFORM;
- t->redraw |= TREDRAW_HARD;
- handled = true;
- }
- else if (t->mode == TFM_RESIZE) {
- if (t->options & CTX_MOVIECLIP) {
- restoreTransObjects(t);
-
- t->flag ^= T_ALT_TRANSFORM;
- t->redraw |= TREDRAW_HARD;
- handled = true;
- }
- }
break;
case TFM_MODAL_SNAP_INV_ON:
@@ -1047,42 +1015,42 @@ int transformEvent(TransInfo *t, const wmEvent *event)
break;
case TFM_MODAL_AXIS_X:
if (!(t->flag & T_NO_CONSTRAINT)) {
- transform_event_xyz_constraint(t, EVT_XKEY, cmode, false);
+ transform_event_xyz_constraint(t, EVT_XKEY, false);
t->redraw |= TREDRAW_HARD;
handled = true;
}
break;
case TFM_MODAL_AXIS_Y:
if ((t->flag & T_NO_CONSTRAINT) == 0) {
- transform_event_xyz_constraint(t, EVT_YKEY, cmode, false);
+ transform_event_xyz_constraint(t, EVT_YKEY, false);
t->redraw |= TREDRAW_HARD;
handled = true;
}
break;
case TFM_MODAL_AXIS_Z:
if ((t->flag & (T_NO_CONSTRAINT)) == 0) {
- transform_event_xyz_constraint(t, EVT_ZKEY, cmode, false);
+ transform_event_xyz_constraint(t, EVT_ZKEY, false);
t->redraw |= TREDRAW_HARD;
handled = true;
}
break;
case TFM_MODAL_PLANE_X:
if ((t->flag & (T_NO_CONSTRAINT | T_2D_EDIT)) == 0) {
- transform_event_xyz_constraint(t, EVT_XKEY, cmode, true);
+ transform_event_xyz_constraint(t, EVT_XKEY, true);
t->redraw |= TREDRAW_HARD;
handled = true;
}
break;
case TFM_MODAL_PLANE_Y:
if ((t->flag & (T_NO_CONSTRAINT | T_2D_EDIT)) == 0) {
- transform_event_xyz_constraint(t, EVT_YKEY, cmode, true);
+ transform_event_xyz_constraint(t, EVT_YKEY, true);
t->redraw |= TREDRAW_HARD;
handled = true;
}
break;
case TFM_MODAL_PLANE_Z:
if ((t->flag & (T_NO_CONSTRAINT | T_2D_EDIT)) == 0) {
- transform_event_xyz_constraint(t, EVT_ZKEY, cmode, true);
+ transform_event_xyz_constraint(t, EVT_ZKEY, true);
t->redraw |= TREDRAW_HARD;
handled = true;
}
@@ -1160,9 +1128,9 @@ int transformEvent(TransInfo *t, const wmEvent *event)
break;
case TFM_MODAL_INSERTOFS_TOGGLE_DIR:
if (t->spacetype == SPACE_NODE) {
- SpaceNode *snode = (SpaceNode *)t->sa->spacedata.first;
+ SpaceNode *snode = (SpaceNode *)t->area->spacedata.first;
- BLI_assert(t->sa->spacetype == t->spacetype);
+ BLI_assert(t->area->spacetype == t->spacetype);
if (snode->insert_ofs_dir == SNODE_INSERTOFS_DIR_RIGHT) {
snode->insert_ofs_dir = SNODE_INSERTOFS_DIR_LEFT;
@@ -1228,17 +1196,7 @@ int transformEvent(TransInfo *t, const wmEvent *event)
stopConstraint(t);
}
else {
- if (event->shift) {
- /* bit hackish... but it prevents mmb select to print the
- * orientation from menu */
- float mati[3][3];
- strcpy(t->spacename, "global");
- unit_m3(mati);
- initSelectConstraint(t, mati);
- }
- else {
- initSelectConstraint(t, t->spacemtx);
- }
+ initSelectConstraint(t);
postSelectConstraint(t);
}
}
@@ -1251,7 +1209,7 @@ int transformEvent(TransInfo *t, const wmEvent *event)
break;
}
/* only switch when... */
- if (ELEM(t->mode, TFM_ROTATION, TFM_RESIZE, TFM_TRACKBALL)) {
+ if (t->mode != TFM_TRANSLATION && transform_mode_is_changeable(t->mode)) {
restoreTransObjects(t);
resetTransModal(t);
resetTransRestrictions(t);
@@ -1266,7 +1224,7 @@ int transformEvent(TransInfo *t, const wmEvent *event)
break;
}
/* only switch when... */
- if (ELEM(t->mode, TFM_ROTATION, TFM_TRANSLATION, TFM_TRACKBALL)) {
+ if (t->mode != TFM_RESIZE && transform_mode_is_changeable(t->mode)) {
restoreTransObjects(t);
resetTransModal(t);
resetTransRestrictions(t);
@@ -1282,7 +1240,7 @@ int transformEvent(TransInfo *t, const wmEvent *event)
}
/* only switch when... */
if (!(t->options & CTX_TEXTURE)) {
- if (ELEM(t->mode, TFM_ROTATION, TFM_RESIZE, TFM_TRACKBALL, TFM_TRANSLATION)) {
+ if (transform_mode_is_changeable(t->mode)) {
restoreTransObjects(t);
resetTransModal(t);
resetTransRestrictions(t);
@@ -1521,9 +1479,9 @@ static bool transinfo_show_overlay(const struct bContext *C, TransInfo *t, ARegi
ok = true;
}
else {
- ScrArea *sa = CTX_wm_area(C);
- if (sa->spacetype == SPACE_VIEW3D) {
- View3D *v3d = sa->spacedata.first;
+ ScrArea *area = CTX_wm_area(C);
+ if (area->spacetype == SPACE_VIEW3D) {
+ View3D *v3d = area->spacedata.first;
if ((v3d->flag2 & V3D_HIDE_OVERLAYS) == 0) {
ok = true;
}
@@ -1576,7 +1534,7 @@ static void drawAutoKeyWarning(TransInfo *UNUSED(t), ARegion *region)
/* warning text (to clarify meaning of overlays)
* - original color was red to match the icon, but that clashes badly with a less nasty border
*/
- unsigned char color[3];
+ uchar color[3];
UI_GetThemeColorShade3ubv(TH_TEXT_HI, -50, color);
BLF_color3ubv(font_id, color);
#ifdef WITH_INTERNATIONAL
@@ -1637,6 +1595,17 @@ void saveTransform(bContext *C, TransInfo *t, wmOperator *op)
int proportional = 0;
PropertyRNA *prop;
+ if (!(t->con.mode & CON_APPLY) && (t->flag & T_MODAL) &&
+ ELEM(t->mode, TFM_TRANSLATION, TFM_RESIZE)) {
+ /* When redoing these modes the first time, it's more convenient to save
+ * the Global orientation. */
+ mul_m3_v3(t->spacemtx, t->values_final);
+ unit_m3(t->spacemtx);
+
+ BLI_assert(t->orient_curr == 0);
+ t->orient[0].type = V3D_ORIENT_GLOBAL;
+ }
+
// Save back mode in case we're in the generic operator
if ((prop = RNA_struct_find_property(op->ptr, "mode"))) {
RNA_property_enum_set(op->ptr, prop, t->mode);
@@ -1651,11 +1620,6 @@ void saveTransform(bContext *C, TransInfo *t, wmOperator *op)
}
}
- if ((prop = RNA_struct_find_property(op->ptr, "center_override"))) {
- /* Important for redo operations. */
- RNA_property_float_set_array(op->ptr, prop, t->center_global);
- }
-
if (t->flag & T_PROP_EDIT_ALL) {
if (t->flag & T_PROP_EDIT) {
proportional |= PROP_EDIT_USE;
@@ -1704,28 +1668,19 @@ void saveTransform(bContext *C, TransInfo *t, wmOperator *op)
ts->prop_mode = t->prop_mode;
}
}
-
- if (t->spacetype == SPACE_VIEW3D) {
- if ((prop = RNA_struct_find_property(op->ptr, "orient_type")) &&
- !RNA_property_is_set(op->ptr, prop) &&
- (t->orientation.user != V3D_ORIENT_CUSTOM_MATRIX)) {
- TransformOrientationSlot *orient_slot = &t->scene->orientation_slots[SCE_ORIENT_DEFAULT];
- orient_slot->type = t->orientation.user;
- BLI_assert(((orient_slot->index_custom == -1) && (t->orientation.custom == NULL)) ||
- (BKE_scene_transform_orientation_get_index(t->scene, t->orientation.custom) ==
- orient_slot->index_custom));
- }
- }
}
if (t->flag & T_MODAL) {
/* do we check for parameter? */
if (transformModeUseSnap(t)) {
- if (t->modifiers & MOD_SNAP) {
- ts->snap_flag |= SCE_SNAP;
- }
- else {
- ts->snap_flag &= ~SCE_SNAP;
+ if (!(t->modifiers & MOD_SNAP) != !(ts->snap_flag & SCE_SNAP)) {
+ if (t->modifiers & MOD_SNAP) {
+ ts->snap_flag |= SCE_SNAP;
+ }
+ else {
+ ts->snap_flag &= ~SCE_SNAP;
+ }
+ WM_msg_publish_rna_prop(t->mbus, &t->scene->id, ts, ToolSettings, use_snap);
}
}
}
@@ -1742,33 +1697,6 @@ void saveTransform(bContext *C, TransInfo *t, wmOperator *op)
RNA_property_boolean_set(op->ptr, prop, (t->flag & T_NO_MIRROR) == 0);
}
- /* Orientation used for redo. */
- const bool use_orient_axis = (t->orient_matrix_is_set &&
- (RNA_struct_find_property(op->ptr, "orient_axis") != NULL));
- short orientation;
- if (t->con.mode & CON_APPLY) {
- orientation = t->con.orientation;
- if (orientation == V3D_ORIENT_CUSTOM) {
- const int orientation_index_custom = BKE_scene_transform_orientation_get_index(
- t->scene, t->orientation.custom);
- /* Maybe we need a t->con.custom_orientation?
- * Seems like it would always match t->orientation.custom. */
- orientation = V3D_ORIENT_CUSTOM + orientation_index_custom;
- BLI_assert(orientation >= V3D_ORIENT_CUSTOM);
- }
- }
- else if ((t->orientation.user == V3D_ORIENT_CUSTOM_MATRIX) &&
- (prop = RNA_struct_find_property(op->ptr, "orient_matrix_type"))) {
- orientation = RNA_property_enum_get(op->ptr, prop);
- }
- else if (use_orient_axis) {
- /* We're not using an orientation, use the fallback. */
- orientation = t->orientation.unset;
- }
- else {
- orientation = V3D_ORIENT_GLOBAL;
- }
-
if ((prop = RNA_struct_find_property(op->ptr, "orient_axis"))) {
if (t->flag & T_MODAL) {
if (t->con.mode & CON_APPLY) {
@@ -1788,56 +1716,41 @@ void saveTransform(bContext *C, TransInfo *t, wmOperator *op)
}
}
- if ((prop = RNA_struct_find_property(op->ptr, "orient_matrix"))) {
- if (t->flag & T_MODAL) {
- if (orientation != V3D_ORIENT_CUSTOM_MATRIX) {
- if (t->flag & T_MODAL) {
- RNA_enum_set(op->ptr, "orient_matrix_type", orientation);
- }
- }
- if (t->con.mode & CON_APPLY) {
- RNA_float_set_array(op->ptr, "orient_matrix", &t->con.mtx[0][0]);
- }
- else if (use_orient_axis) {
- RNA_float_set_array(op->ptr, "orient_matrix", &t->orient_matrix[0][0]);
- }
- else {
- RNA_float_set_array(op->ptr, "orient_matrix", &t->spacemtx[0][0]);
- }
- }
- }
-
if ((prop = RNA_struct_find_property(op->ptr, "orient_type"))) {
- /* constraint orientation can be global, even if user selects something else
- * so use the orientation in the constraint if set */
+ short orient_type_set, orient_type_curr;
+ orient_type_set = RNA_property_is_set(op->ptr, prop) ? RNA_property_enum_get(op->ptr, prop) :
+ -1;
+ orient_type_curr = t->orient[t->orient_curr].type;
- /* Use 'orient_matrix' instead. */
- if (t->flag & T_MODAL) {
- if (orientation != V3D_ORIENT_CUSTOM_MATRIX) {
- RNA_property_enum_set(op->ptr, prop, orientation);
- }
+ if (!ELEM(orient_type_curr, orient_type_set, V3D_ORIENT_CUSTOM_MATRIX)) {
+ RNA_property_enum_set(op->ptr, prop, orient_type_curr);
+ orient_type_set = orient_type_curr;
+ }
+
+ if (((prop = RNA_struct_find_property(op->ptr, "orient_matrix_type")) &&
+ !RNA_property_is_set(op->ptr, prop))) {
+ /* Set the first time to register on redo. */
+ RNA_property_enum_set(op->ptr, prop, orient_type_set);
+ RNA_float_set_array(op->ptr, "orient_matrix", &t->spacemtx[0][0]);
}
}
if ((prop = RNA_struct_find_property(op->ptr, "constraint_axis"))) {
bool constraint_axis[3] = {false, false, false};
- if (t->flag & T_MODAL) {
- /* Only set if needed, so we can hide in the UI when nothing is set.
- * See 'transform_poll_property'. */
- if (t->con.mode & CON_APPLY) {
- if (t->con.mode & CON_AXIS0) {
- constraint_axis[0] = true;
- }
- if (t->con.mode & CON_AXIS1) {
- constraint_axis[1] = true;
- }
- if (t->con.mode & CON_AXIS2) {
- constraint_axis[2] = true;
- }
+ if (t->con.mode & CON_APPLY) {
+ if (t->con.mode & CON_AXIS0) {
+ constraint_axis[0] = true;
}
- if (ELEM(true, UNPACK3(constraint_axis))) {
- RNA_property_boolean_set_array(op->ptr, prop, constraint_axis);
+ if (t->con.mode & CON_AXIS1) {
+ constraint_axis[1] = true;
}
+ if (t->con.mode & CON_AXIS2) {
+ constraint_axis[2] = true;
+ }
+ RNA_property_boolean_set_array(op->ptr, prop, constraint_axis);
+ }
+ else {
+ RNA_property_unset(op->ptr, prop);
}
}
@@ -1870,7 +1783,7 @@ static void initSnapSpatial(TransInfo *t, float r_snap[3])
RegionView3D *rv3d = t->region->regiondata;
if (rv3d) {
- View3D *v3d = t->sa->spacedata.first;
+ View3D *v3d = t->area->spacedata.first;
r_snap[0] = 0.0f;
r_snap[1] = ED_view3d_grid_view_scale(t->scene, v3d, rv3d, NULL) * 1.0f;
r_snap[2] = r_snap[1] * 0.1f;
@@ -1963,7 +1876,10 @@ bool initTransform(bContext *C, TransInfo *t, wmOperator *op, const wmEvent *eve
unit_m3(t->spacemtx);
initTransInfo(C, t, op, event);
- initTransformOrientation(C, t);
+
+ /* Use the custom orientation when it is set. */
+ short orient_index = t->orient[0].type == V3D_ORIENT_CUSTOM_MATRIX ? 0 : t->orient_curr;
+ transform_orientations_current_set(t, orient_index);
if (t->spacetype == SPACE_VIEW3D) {
t->draw_handle_apply = ED_region_draw_cb_activate(
@@ -1972,62 +1888,38 @@ bool initTransform(bContext *C, TransInfo *t, wmOperator *op, const wmEvent *eve
t->region->type, drawTransformView, t, REGION_DRAW_POST_VIEW);
t->draw_handle_pixel = ED_region_draw_cb_activate(
t->region->type, drawTransformPixel, t, REGION_DRAW_POST_PIXEL);
- t->draw_handle_cursor = WM_paint_cursor_activate(CTX_wm_manager(C),
- SPACE_TYPE_ANY,
- RGN_TYPE_ANY,
- transform_draw_cursor_poll,
- transform_draw_cursor_draw,
- t);
+ t->draw_handle_cursor = WM_paint_cursor_activate(
+ SPACE_TYPE_ANY, RGN_TYPE_ANY, transform_draw_cursor_poll, transform_draw_cursor_draw, t);
}
else if (t->spacetype == SPACE_IMAGE) {
t->draw_handle_view = ED_region_draw_cb_activate(
t->region->type, drawTransformView, t, REGION_DRAW_POST_VIEW);
- t->draw_handle_cursor = WM_paint_cursor_activate(CTX_wm_manager(C),
- SPACE_TYPE_ANY,
- RGN_TYPE_ANY,
- transform_draw_cursor_poll,
- transform_draw_cursor_draw,
- t);
+ t->draw_handle_cursor = WM_paint_cursor_activate(
+ SPACE_TYPE_ANY, RGN_TYPE_ANY, transform_draw_cursor_poll, transform_draw_cursor_draw, t);
}
else if (t->spacetype == SPACE_CLIP) {
t->draw_handle_view = ED_region_draw_cb_activate(
t->region->type, drawTransformView, t, REGION_DRAW_POST_VIEW);
- t->draw_handle_cursor = WM_paint_cursor_activate(CTX_wm_manager(C),
- SPACE_TYPE_ANY,
- RGN_TYPE_ANY,
- transform_draw_cursor_poll,
- transform_draw_cursor_draw,
- t);
+ t->draw_handle_cursor = WM_paint_cursor_activate(
+ SPACE_TYPE_ANY, RGN_TYPE_ANY, transform_draw_cursor_poll, transform_draw_cursor_draw, t);
}
else if (t->spacetype == SPACE_NODE) {
t->draw_handle_view = ED_region_draw_cb_activate(
t->region->type, drawTransformView, t, REGION_DRAW_POST_VIEW);
- t->draw_handle_cursor = WM_paint_cursor_activate(CTX_wm_manager(C),
- SPACE_TYPE_ANY,
- RGN_TYPE_ANY,
- transform_draw_cursor_poll,
- transform_draw_cursor_draw,
- t);
+ t->draw_handle_cursor = WM_paint_cursor_activate(
+ SPACE_TYPE_ANY, RGN_TYPE_ANY, transform_draw_cursor_poll, transform_draw_cursor_draw, t);
}
else if (t->spacetype == SPACE_GRAPH) {
t->draw_handle_view = ED_region_draw_cb_activate(
t->region->type, drawTransformView, t, REGION_DRAW_POST_VIEW);
- t->draw_handle_cursor = WM_paint_cursor_activate(CTX_wm_manager(C),
- SPACE_TYPE_ANY,
- RGN_TYPE_ANY,
- transform_draw_cursor_poll,
- transform_draw_cursor_draw,
- t);
+ t->draw_handle_cursor = WM_paint_cursor_activate(
+ SPACE_TYPE_ANY, RGN_TYPE_ANY, transform_draw_cursor_poll, transform_draw_cursor_draw, t);
}
else if (t->spacetype == SPACE_ACTION) {
t->draw_handle_view = ED_region_draw_cb_activate(
t->region->type, drawTransformView, t, REGION_DRAW_POST_VIEW);
- t->draw_handle_cursor = WM_paint_cursor_activate(CTX_wm_manager(C),
- SPACE_TYPE_ANY,
- RGN_TYPE_ANY,
- transform_draw_cursor_poll,
- transform_draw_cursor_draw,
- t);
+ t->draw_handle_cursor = WM_paint_cursor_activate(
+ SPACE_TYPE_ANY, RGN_TYPE_ANY, transform_draw_cursor_poll, transform_draw_cursor_draw, t);
}
createTransData(C, t); // make TransData structs from selection
@@ -2088,33 +1980,6 @@ bool initTransform(bContext *C, TransInfo *t, wmOperator *op, const wmEvent *eve
calculatePropRatio(t);
calculateCenter(t);
- /* Overwrite initial values if operator supplied a non-null vector.
- *
- * Run before init functions so 'values_modal_offset' can be applied on mouse input.
- */
- BLI_assert(is_zero_v4(t->values_modal_offset));
- if ((prop = RNA_struct_find_property(op->ptr, "value")) && RNA_property_is_set(op->ptr, prop)) {
- float values[4] = {0}; /* in case value isn't length 4, avoid uninitialized memory */
-
- if (RNA_property_array_check(prop)) {
- RNA_float_get_array(op->ptr, "value", values);
- }
- else {
- values[0] = RNA_float_get(op->ptr, "value");
- }
-
- copy_v4_v4(t->values, values);
-
- if (t->flag & T_MODAL) {
- copy_v4_v4(t->values_modal_offset, values);
- t->redraw = TREDRAW_HARD;
- }
- else {
- copy_v4_v4(t->values, values);
- t->flag |= T_INPUT_IS_VALUES_FINAL;
- }
- }
-
if (event) {
/* Initialize accurate transform to settings requested by keymap. */
bool use_accurate = false;
@@ -2145,38 +2010,8 @@ bool initTransform(bContext *C, TransInfo *t, wmOperator *op, const wmEvent *eve
}
/* Constraint init from operator */
- if ((t->flag & T_MODAL) ||
- /* For mirror operator the constraint axes are effectively the values. */
- (RNA_struct_find_property(op->ptr, "value") == NULL)) {
- if ((prop = RNA_struct_find_property(op->ptr, "constraint_axis")) &&
- RNA_property_is_set(op->ptr, prop)) {
- bool constraint_axis[3];
-
- RNA_property_boolean_get_array(op->ptr, prop, constraint_axis);
-
- if (constraint_axis[0] || constraint_axis[1] || constraint_axis[2]) {
- t->con.mode |= CON_APPLY;
-
- if (constraint_axis[0]) {
- t->con.mode |= CON_AXIS0;
- }
- if (constraint_axis[1]) {
- t->con.mode |= CON_AXIS1;
- }
- if (constraint_axis[2]) {
- t->con.mode |= CON_AXIS2;
- }
-
- setUserConstraint(t, t->orientation.user, t->con.mode, "%s");
- }
- }
- }
- else {
- /* So we can adjust in non global orientation. */
- if (t->orientation.user != V3D_ORIENT_GLOBAL) {
- t->con.mode |= CON_APPLY | CON_AXIS0 | CON_AXIS1 | CON_AXIS2;
- setUserConstraint(t, t->orientation.user, t->con.mode, "%s");
- }
+ if (t->con.mode & CON_APPLY) {
+ setUserConstraint(t, t->orient[t->orient_curr].type, t->con.mode, "%s");
}
/* Don't write into the values when non-modal because they are already set from operator redo
diff --git a/source/blender/editors/transform/transform.h b/source/blender/editors/transform/transform.h
index a2c8caba0f5..192728f63d2 100644
--- a/source/blender/editors/transform/transform.h
+++ b/source/blender/editors/transform/transform.h
@@ -113,13 +113,8 @@ typedef struct TransSnap {
} TransSnap;
typedef struct TransCon {
- short orientation;
/** Description of the constraint for header_print. */
char text[50];
- /** Matrix of the constraint space. */
- float mtx[3][3];
- /** Inverse matrix of the constraint space. */
- float imtx[3][3];
/** Projection constraint matrix (same as #imtx with some axis == 0). */
float pmtx[3][3];
/** Initial mouse value for visual calculation
@@ -139,8 +134,7 @@ typedef struct TransCon {
struct TransDataContainer *tc,
struct TransData *td,
const float in[3],
- float out[3],
- float pvec[3]);
+ float out[3]);
/** Apply function pointer for size transformation. */
void (*applySize)(struct TransInfo *t,
struct TransDataContainer *tc,
@@ -520,6 +514,7 @@ typedef struct TransInfo {
/** orientation matrix of the current space. */
float spacemtx[3][3];
+ float spacemtx_inv[3][3];
/** name of the current space, MAX_NAME. */
char spacename[64];
@@ -531,18 +526,11 @@ typedef struct TransInfo {
bool is_launch_event_tweak;
struct {
- /** Orientation type when when we're not constrained.
- * nearly always global except for rotate which defaults to screen-space orientation. */
- short unset;
- /** Orientation to use when a key is pressed. */
- short user;
- /* Used when user is global. */
- short user_alt;
- short index;
- short *types[2];
- /* this gets used when custom_orientation is V3D_ORIENT_CUSTOM */
- struct TransformOrientation *custom;
- } orientation;
+ short type;
+ float matrix[3][3];
+ } orient[3];
+ short orient_curr;
+
/** backup from view3d, to restore on end. */
short gizmo_flag;
@@ -566,22 +554,14 @@ typedef struct TransInfo {
/** Secondary axis, shear uses this. */
int orient_axis_ortho;
- /** Often this matrix has similar usage to #TransInfo.spacemtx however this
- * is used to define extra axes to operate on, not necessarily a space.
- *
- * For example, by default rotation operates on the view (`orient_matrix[2]`),
- * even when the current space isn't set to the view. */
- float orient_matrix[3][3];
- /** Don't overwrite when set by operator redo defines the orientation axis. */
- bool orient_matrix_is_set;
-
/** remove elements if operator is canceled. */
bool remove_on_cancel;
void *view;
/** Only valid (non null) during an operator called function. */
struct bContext *context;
- struct ScrArea *sa;
+ struct wmMsgBus *mbus;
+ struct ScrArea *area;
struct ARegion *region;
struct Depsgraph *depsgraph;
struct Scene *scene;
@@ -631,52 +611,53 @@ enum {
T_CURSOR = 1 << 5,
/** Transform points, having no rotation/scale. */
T_POINTS = 1 << 6,
-
- /* empty slot - (1 << 7) */
-
/** restrictions flags */
- T_NO_CONSTRAINT = 1 << 8,
- T_NULL_ONE = 1 << 9,
- T_NO_ZERO = 1 << 10,
+ T_NO_CONSTRAINT = 1 << 7,
+ T_NULL_ONE = 1 << 8,
+ T_NO_ZERO = 1 << 9,
T_ALL_RESTRICTIONS = T_NO_CONSTRAINT | T_NULL_ONE | T_NO_ZERO,
- T_PROP_EDIT = 1 << 11,
- T_PROP_CONNECTED = 1 << 12,
- T_PROP_PROJECTED = 1 << 13,
+ T_PROP_EDIT = 1 << 10,
+ T_PROP_CONNECTED = 1 << 11,
+ T_PROP_PROJECTED = 1 << 12,
T_PROP_EDIT_ALL = T_PROP_EDIT | T_PROP_CONNECTED | T_PROP_PROJECTED,
- T_V3D_ALIGN = 1 << 14,
+ T_V3D_ALIGN = 1 << 13,
/** For 2d views like uv or fcurve. */
- T_2D_EDIT = 1 << 15,
- T_CLIP_UV = 1 << 16,
+ T_2D_EDIT = 1 << 14,
+ T_CLIP_UV = 1 << 15,
/** Auto-ik is on. */
- T_AUTOIK = 1 << 18,
+ T_AUTOIK = 1 << 16,
/** Don't use mirror even if the data-block option is set. */
- T_NO_MIRROR = 1 << 19,
+ T_NO_MIRROR = 1 << 17,
/** To indicate that the value set in the `value` parameter is the final
* value of the transformation, modified only by the constrain. */
- T_INPUT_IS_VALUES_FINAL = 1 << 20,
+ T_INPUT_IS_VALUES_FINAL = 1 << 18,
/** To specify if we save back settings at the end. */
- T_MODAL = 1 << 21,
+ T_MODAL = 1 << 19,
/** No retopo. */
- T_NO_PROJECT = 1 << 22,
+ T_NO_PROJECT = 1 << 20,
- T_RELEASE_CONFIRM = 1 << 23,
+ T_RELEASE_CONFIRM = 1 << 21,
/** Alternative transformation. used to add offset to tracking markers. */
- T_ALT_TRANSFORM = 1 << 24,
+ T_ALT_TRANSFORM = 1 << 22,
/** #TransInfo.center has been set, don't change it. */
- T_OVERRIDE_CENTER = 1 << 25,
+ T_OVERRIDE_CENTER = 1 << 23,
- T_MODAL_CURSOR_SET = 1 << 26,
+ T_MODAL_CURSOR_SET = 1 << 24,
- T_CLNOR_REBUILD = 1 << 27,
+ T_CLNOR_REBUILD = 1 << 25,
+
+ /* Special Aftertrans. */
+ T_AUTOMERGE = 1 << 26,
+ T_AUTOSPLIT = 1 << 27,
};
/** #TransInfo.modifiers */
@@ -723,40 +704,39 @@ enum {
/** #TransData.flag */
enum {
TD_SELECTED = 1 << 0,
- TD_NOACTION = 1 << 2,
- TD_USEQUAT = 1 << 3,
- TD_NOTCONNECTED = 1 << 4,
+ TD_USEQUAT = 1 << 1,
+ TD_NOTCONNECTED = 1 << 2,
/** Used for scaling of #MetaElem.rad */
- TD_SINGLESIZE = 1 << 5,
+ TD_SINGLESIZE = 1 << 3,
/** Scale relative to individual element center */
- TD_INDIVIDUAL_SCALE = 1 << 8,
- TD_NOCENTER = 1 << 9,
+ TD_INDIVIDUAL_SCALE = 1 << 4,
+ TD_NOCENTER = 1 << 5,
/** #TransData.ext abused for particle key timing. */
- TD_NO_EXT = 1 << 10,
+ TD_NO_EXT = 1 << 6,
/** don't transform this data */
- TD_SKIP = 1 << 11,
+ TD_SKIP = 1 << 7,
/** if this is a bez triple, we need to restore the handles,
* if this is set #TransData.hdata needs freeing */
- TD_BEZTRIPLE = 1 << 12,
+ TD_BEZTRIPLE = 1 << 8,
/** when this is set, don't apply translation changes to this element */
- TD_NO_LOC = 1 << 13,
+ TD_NO_LOC = 1 << 9,
/** For Graph Editor autosnap, indicates that point should not undergo autosnapping */
- TD_NOTIMESNAP = 1 << 14,
+ TD_NOTIMESNAP = 1 << 10,
/** For Graph Editor - curves that can only have int-values
* need their keyframes tagged with this. */
- TD_INTVALUES = 1 << 15,
+ TD_INTVALUES = 1 << 11,
/** For editmode mirror, clamp axis to 0 */
- TD_MIRROR_EDGE_X = 1 << 16,
- TD_MIRROR_EDGE_Y = 1 << 17,
- TD_MIRROR_EDGE_Z = 1 << 18,
+ TD_MIRROR_EDGE_X = 1 << 12,
+ TD_MIRROR_EDGE_Y = 1 << 13,
+ TD_MIRROR_EDGE_Z = 1 << 14,
/** For fcurve handles, move them along with their keyframes */
- TD_MOVEHANDLE1 = 1 << 19,
- TD_MOVEHANDLE2 = 1 << 20,
+ TD_MOVEHANDLE1 = 1 << 15,
+ TD_MOVEHANDLE2 = 1 << 16,
/** Exceptional case with pose bone rotating when a parent bone has 'Local Location'
* option enabled and rotating also transforms it. */
- TD_PBONE_LOCAL_MTX_P = 1 << 21,
+ TD_PBONE_LOCAL_MTX_P = 1 << 17,
/** Same as above but for a child bone. */
- TD_PBONE_LOCAL_MTX_C = 1 << 22,
+ TD_PBONE_LOCAL_MTX_C = 1 << 18,
};
/** #TransSnap.status */
@@ -921,8 +901,13 @@ void getViewVector(const TransInfo *t, const float coord[3], float vec[3]);
void transform_data_ext_rotate(TransData *td, float mat[3][3], bool use_drot);
/*********************** Transform Orientations ******************************/
-
-void initTransformOrientation(struct bContext *C, TransInfo *t);
+short transform_orientation_matrix_get(struct bContext *C,
+ TransInfo *t,
+ const short orientation,
+ const float custom[3][3],
+ float r_spacemtx[3][3]);
+const char *transform_orientations_spacename_get(TransInfo *t, const short orient_type);
+void transform_orientations_current_set(struct TransInfo *t, const short orient_index);
/* Those two fill in mat and return non-zero on success */
bool createSpaceNormal(float mat[3][3], const float normal[3]);
@@ -932,7 +917,7 @@ struct TransformOrientation *addMatrixSpace(struct bContext *C,
float mat[3][3],
const char *name,
const bool overwrite);
-bool applyTransformOrientation(const struct TransformOrientation *ts,
+void applyTransformOrientation(const struct TransformOrientation *ts,
float r_mat[3][3],
char r_name[64]);
@@ -967,14 +952,14 @@ bool checkUseAxisMatrix(TransInfo *t);
(BLI_assert((t)->data_container_len == 1), (&(t)->data_container[0]))
#define FOREACH_TRANS_DATA_CONTAINER(t, th) \
- for (TransDataContainer *tc = t->data_container, \
- *tc_end = t->data_container + t->data_container_len; \
+ for (TransDataContainer *tc = (t)->data_container, \
+ *tc_end = (t)->data_container + (t)->data_container_len; \
th != tc_end; \
th++)
#define FOREACH_TRANS_DATA_CONTAINER_INDEX(t, th, i) \
- for (TransDataContainer *tc = ((i = 0), t->data_container), \
- *tc_end = t->data_container + t->data_container_len; \
+ for (TransDataContainer *tc = ((i = 0), (t)->data_container), \
+ *tc_end = (t)->data_container + (t)->data_container_len; \
th != tc_end; \
th++, i++)
diff --git a/source/blender/editors/transform/transform_constraints.c b/source/blender/editors/transform/transform_constraints.c
index 4b6932d977d..0347522b8e8 100644
--- a/source/blender/editors/transform/transform_constraints.c
+++ b/source/blender/editors/transform/transform_constraints.c
@@ -42,6 +42,7 @@
#include "BLI_utildefines.h"
#include "BKE_context.h"
+#include "BKE_scene.h"
#include "ED_view3d.h"
@@ -57,6 +58,27 @@
static void drawObjectConstraint(TransInfo *t);
+static void projection_matrix_calc(const TransInfo *t, float r_pmtx[3][3])
+{
+ unit_m3(r_pmtx);
+
+ if (!(t->con.mode & CON_AXIS0)) {
+ zero_v3(r_pmtx[0]);
+ }
+
+ if (!(t->con.mode & CON_AXIS1)) {
+ zero_v3(r_pmtx[1]);
+ }
+
+ if (!(t->con.mode & CON_AXIS2)) {
+ zero_v3(r_pmtx[2]);
+ }
+
+ float mat[3][3];
+ mul_m3_m3m3(mat, r_pmtx, t->spacemtx_inv);
+ mul_m3_m3m3(r_pmtx, t->spacemtx, mat);
+}
+
/* ************************** CONSTRAINTS ************************* */
static void constraintValuesFinal(TransInfo *t, float vec[3])
{
@@ -121,11 +143,9 @@ void constraintNumInput(TransInfo *t, float vec[3])
}
}
-static void postConstraintChecks(TransInfo *t, float vec[3], float pvec[3])
+static void postConstraintChecks(TransInfo *t, float vec[3])
{
- int i = 0;
-
- mul_m3_v3(t->con.imtx, vec);
+ mul_m3_v3(t->spacemtx_inv, vec);
snapGridIncrement(t, vec);
@@ -155,23 +175,13 @@ static void postConstraintChecks(TransInfo *t, float vec[3], float pvec[3])
/* inverse transformation at the end */
}
- if (t->con.mode & CON_AXIS0) {
- pvec[i++] = vec[0];
- }
- if (t->con.mode & CON_AXIS1) {
- pvec[i++] = vec[1];
- }
- if (t->con.mode & CON_AXIS2) {
- pvec[i++] = vec[2];
- }
-
- mul_m3_v3(t->con.mtx, vec);
+ mul_m3_v3(t->spacemtx, vec);
}
static void viewAxisCorrectCenter(const TransInfo *t, float t_con_center[3])
{
if (t->spacetype == SPACE_VIEW3D) {
- // View3D *v3d = t->sa->spacedata.first;
+ // View3D *v3d = t->area->spacedata.first;
const float min_dist = 1.0f; /* v3d->clip_start; */
float dir[3];
float l;
@@ -298,7 +308,7 @@ static bool isPlaneProjectionViewAligned(const TransInfo *t)
int n = 0;
for (int i = 0; i < 3; i++) {
if (t->con.mode & (CON_AXIS0 << i)) {
- constraint_vector[n++] = t->con.mtx[i];
+ constraint_vector[n++] = t->spacemtx[i];
if (n == 2) {
break;
}
@@ -346,12 +356,8 @@ static void planeProjection(const TransInfo *t, const float in[3], float out[3])
* (in perspective mode, the view vector is relative to the position on screen)
*/
-static void applyAxisConstraintVec(TransInfo *t,
- TransDataContainer *UNUSED(tc),
- TransData *td,
- const float in[3],
- float out[3],
- float pvec[3])
+static void applyAxisConstraintVec(
+ TransInfo *t, TransDataContainer *UNUSED(tc), TransData *td, const float in[3], float out[3])
{
copy_v3_v3(out, in);
if (!td && t->con.mode & CON_APPLY) {
@@ -371,25 +377,25 @@ static void applyAxisConstraintVec(TransInfo *t,
float c[3];
if (t->con.mode & CON_AXIS0) {
- copy_v3_v3(c, t->con.mtx[0]);
+ copy_v3_v3(c, t->spacemtx[0]);
}
else if (t->con.mode & CON_AXIS1) {
- copy_v3_v3(c, t->con.mtx[1]);
+ copy_v3_v3(c, t->spacemtx[1]);
}
else if (t->con.mode & CON_AXIS2) {
- copy_v3_v3(c, t->con.mtx[2]);
+ copy_v3_v3(c, t->spacemtx[2]);
}
axisProjection(t, c, in, out);
}
}
- postConstraintChecks(t, out, pvec);
+ postConstraintChecks(t, out);
}
}
/*
* Generic callback for object based spatial constraints applied to linear motion
*
- * At first, the following is applied to the first data in the array
+ * At first, the following is applied without orientation
* The IN vector in projected into the constrained space and then further
* projected along the view vector.
* (in perspective mode, the view vector is relative to the position on screen)
@@ -397,61 +403,19 @@ static void applyAxisConstraintVec(TransInfo *t,
* Further down, that vector is mapped to each data's space.
*/
-static void applyObjectConstraintVec(TransInfo *t,
- TransDataContainer *tc,
- TransData *td,
- const float in[3],
- float out[3],
- float pvec[3])
+static void applyObjectConstraintVec(
+ TransInfo *t, TransDataContainer *tc, TransData *td, const float in[3], float out[3])
{
- copy_v3_v3(out, in);
- if (t->con.mode & CON_APPLY) {
- if (!td) {
- mul_m3_v3(t->con.pmtx, out);
-
- const int dims = getConstraintSpaceDimension(t);
- if (dims == 2) {
- if (!is_zero_v3(out)) {
- if (!isPlaneProjectionViewAligned(t)) {
- planeProjection(t, in, out);
- }
- }
- }
- else if (dims == 1) {
- float c[3];
-
- if (t->con.mode & CON_AXIS0) {
- copy_v3_v3(c, t->con.mtx[0]);
- }
- else if (t->con.mode & CON_AXIS1) {
- copy_v3_v3(c, t->con.mtx[1]);
- }
- else if (t->con.mode & CON_AXIS2) {
- copy_v3_v3(c, t->con.mtx[2]);
- }
- axisProjection(t, c, in, out);
- }
- postConstraintChecks(t, out, pvec);
- copy_v3_v3(out, pvec);
- }
- else {
- int i = 0;
-
- out[0] = out[1] = out[2] = 0.0f;
- if (t->con.mode & CON_AXIS0) {
- out[0] = in[i++];
- }
- if (t->con.mode & CON_AXIS1) {
- out[1] = in[i++];
- }
- if (t->con.mode & CON_AXIS2) {
- out[2] = in[i++];
- }
-
- mul_m3_v3(td->axismtx, out);
- if (t->flag & T_EDIT) {
- mul_m3_v3(tc->mat3_unit, out);
- }
+ if (!td) {
+ applyAxisConstraintVec(t, tc, td, in, out);
+ }
+ else {
+ /* Specific TransData's space. */
+ copy_v3_v3(out, in);
+ mul_m3_v3(t->spacemtx_inv, out);
+ mul_m3_v3(td->axismtx, out);
+ if (t->flag & T_EDIT) {
+ mul_m3_v3(tc->mat3_unit, out);
}
}
}
@@ -478,8 +442,8 @@ static void applyAxisConstraintSize(TransInfo *t,
smat[2][2] = 1.0f;
}
- mul_m3_m3m3(tmat, smat, t->con.imtx);
- mul_m3_m3m3(smat, t->con.mtx, tmat);
+ mul_m3_m3m3(tmat, smat, t->spacemtx_inv);
+ mul_m3_m3m3(smat, t->spacemtx, tmat);
}
}
@@ -539,15 +503,15 @@ static void applyAxisConstraintRot(
switch (mode) {
case CON_AXIS0:
case (CON_AXIS1 | CON_AXIS2):
- copy_v3_v3(vec, t->con.mtx[0]);
+ copy_v3_v3(vec, t->spacemtx[0]);
break;
case CON_AXIS1:
case (CON_AXIS0 | CON_AXIS2):
- copy_v3_v3(vec, t->con.mtx[1]);
+ copy_v3_v3(vec, t->spacemtx[1]);
break;
case CON_AXIS2:
case (CON_AXIS0 | CON_AXIS1):
- copy_v3_v3(vec, t->con.mtx[2]);
+ copy_v3_v3(vec, t->spacemtx[2]);
break;
}
/* don't flip axis if asked to or if num input */
@@ -620,12 +584,11 @@ static void applyObjectConstraintRot(
/*--------------------- INTERNAL SETUP CALLS ------------------*/
-void setConstraint(TransInfo *t, float space[3][3], int mode, const char text[])
+void setConstraint(TransInfo *t, int mode, const char text[])
{
BLI_strncpy(t->con.text + 1, text, sizeof(t->con.text) - 1);
- copy_m3_m3(t->con.mtx, space);
t->con.mode = mode;
- getConstraintMatrix(t);
+ projection_matrix_calc(t, t->con.pmtx);
startConstraint(t);
@@ -639,41 +602,25 @@ void setConstraint(TransInfo *t, float space[3][3], int mode, const char text[])
/* applies individual td->axismtx constraints */
void setAxisMatrixConstraint(TransInfo *t, int mode, const char text[])
{
- TransDataContainer *tc = t->data_container;
- if (t->data_len_all == 1) {
- float axismtx[3][3];
- if (t->flag & T_EDIT) {
- mul_m3_m3m3(axismtx, tc->mat3_unit, tc->data->axismtx);
- }
- else {
- copy_m3_m3(axismtx, tc->data->axismtx);
- }
-
- setConstraint(t, axismtx, mode, text);
- }
- else {
- BLI_strncpy(t->con.text + 1, text, sizeof(t->con.text) - 1);
- copy_m3_m3(t->con.mtx, tc->data->axismtx);
- t->con.mode = mode;
- getConstraintMatrix(t);
+ BLI_strncpy(t->con.text + 1, text, sizeof(t->con.text) - 1);
+ t->con.mode = mode;
+ projection_matrix_calc(t, t->con.pmtx);
- startConstraint(t);
+ startConstraint(t);
- t->con.drawExtra = drawObjectConstraint;
- t->con.applyVec = applyObjectConstraintVec;
- t->con.applySize = applyObjectConstraintSize;
- t->con.applyRot = applyObjectConstraintRot;
- t->redraw = TREDRAW_HARD;
- }
+ t->con.drawExtra = drawObjectConstraint;
+ t->con.applyVec = applyObjectConstraintVec;
+ t->con.applySize = applyObjectConstraintSize;
+ t->con.applyRot = applyObjectConstraintRot;
+ t->redraw = TREDRAW_HARD;
}
void setLocalConstraint(TransInfo *t, int mode, const char text[])
{
- /* edit-mode now allows local transforms too */
if (t->flag & T_EDIT) {
- /* Use the active (first) edit object. */
- TransDataContainer *tc = t->data_container;
- setConstraint(t, tc->mat3_unit, mode, text);
+ /* Although in edit-mode each object has its local space, use the
+ * orientation of the active object. */
+ setConstraint(t, mode, text);
}
else {
setAxisMatrixConstraint(t, mode, text);
@@ -689,59 +636,30 @@ void setLocalConstraint(TransInfo *t, int mode, const char text[])
void setUserConstraint(TransInfo *t, short orientation, int mode, const char ftext[])
{
char text[256];
+ const char *spacename = transform_orientations_spacename_get(t, orientation);
+ BLI_snprintf(text, sizeof(text), ftext, spacename);
switch (orientation) {
- case V3D_ORIENT_GLOBAL: {
- float mtx[3][3];
- BLI_snprintf(text, sizeof(text), ftext, TIP_("global"));
- unit_m3(mtx);
- setConstraint(t, mtx, mode, text);
- break;
- }
case V3D_ORIENT_LOCAL:
- BLI_snprintf(text, sizeof(text), ftext, TIP_("local"));
setLocalConstraint(t, mode, text);
break;
case V3D_ORIENT_NORMAL:
- BLI_snprintf(text, sizeof(text), ftext, TIP_("normal"));
if (checkUseAxisMatrix(t)) {
setAxisMatrixConstraint(t, mode, text);
+ break;
}
- else {
- setConstraint(t, t->spacemtx, mode, text);
- }
- break;
+ ATTR_FALLTHROUGH;
+ case V3D_ORIENT_GLOBAL:
case V3D_ORIENT_VIEW:
- BLI_snprintf(text, sizeof(text), ftext, TIP_("view"));
- setConstraint(t, t->spacemtx, mode, text);
- break;
case V3D_ORIENT_CURSOR:
- BLI_snprintf(text, sizeof(text), ftext, TIP_("cursor"));
- setConstraint(t, t->spacemtx, mode, text);
- break;
case V3D_ORIENT_GIMBAL:
- BLI_snprintf(text, sizeof(text), ftext, TIP_("gimbal"));
- setConstraint(t, t->spacemtx, mode, text);
- break;
case V3D_ORIENT_CUSTOM_MATRIX:
- BLI_snprintf(text, sizeof(text), ftext, TIP_("custom matrix"));
- setConstraint(t, t->spacemtx, mode, text);
- break;
- case V3D_ORIENT_CUSTOM: {
- char orientation_str[128];
- BLI_snprintf(orientation_str,
- sizeof(orientation_str),
- "%s \"%s\"",
- TIP_("custom orientation"),
- t->orientation.custom->name);
- BLI_snprintf(text, sizeof(text), ftext, orientation_str);
- setConstraint(t, t->spacemtx, mode, text);
+ case V3D_ORIENT_CUSTOM:
+ default: {
+ setConstraint(t, mode, text);
break;
}
}
-
- t->con.orientation = orientation;
-
t->con.mode |= CON_USER;
}
@@ -772,9 +690,9 @@ void drawConstraint(TransInfo *t)
convertViewVec(t, vec, (t->mval[0] - t->con.imval[0]), (t->mval[1] - t->con.imval[1]));
add_v3_v3(vec, t->center_global);
- drawLine(t, t->center_global, tc->mtx[0], 'X', 0);
- drawLine(t, t->center_global, tc->mtx[1], 'Y', 0);
- drawLine(t, t->center_global, tc->mtx[2], 'Z', 0);
+ drawLine(t, t->center_global, t->spacemtx[0], 'X', 0);
+ drawLine(t, t->center_global, t->spacemtx[1], 'Y', 0);
+ drawLine(t, t->center_global, t->spacemtx[2], 'Z', 0);
depth_test_enabled = GPU_depth_test_enabled();
if (depth_test_enabled) {
@@ -808,13 +726,13 @@ void drawConstraint(TransInfo *t)
}
if (tc->mode & CON_AXIS0) {
- drawLine(t, t->center_global, tc->mtx[0], 'X', DRAWLIGHT);
+ drawLine(t, t->center_global, t->spacemtx[0], 'X', DRAWLIGHT);
}
if (tc->mode & CON_AXIS1) {
- drawLine(t, t->center_global, tc->mtx[1], 'Y', DRAWLIGHT);
+ drawLine(t, t->center_global, t->spacemtx[1], 'Y', DRAWLIGHT);
}
if (tc->mode & CON_AXIS2) {
- drawLine(t, t->center_global, tc->mtx[2], 'Z', DRAWLIGHT);
+ drawLine(t, t->center_global, t->spacemtx[2], 'Z', DRAWLIGHT);
}
}
}
@@ -911,11 +829,7 @@ static void drawObjectConstraint(TransInfo *t)
}
}
- if (t->flag & T_OBJECT) {
- copy_v3_v3(co, td->ob->obmat[3]);
- axismtx = td->axismtx;
- }
- else if (t->flag & T_EDIT) {
+ if (t->flag & T_EDIT) {
mul_v3_m4v3(co, tc->mat, td->center);
mul_m3_m3m3(tmp_axismtx, tc->mat3_unit, td->axismtx);
@@ -960,41 +874,18 @@ void stopConstraint(TransInfo *t)
t->num.idx_max = t->idx_max;
}
-void getConstraintMatrix(TransInfo *t)
-{
- float mat[3][3];
- invert_m3_m3(t->con.imtx, t->con.mtx);
- unit_m3(t->con.pmtx);
-
- if (!(t->con.mode & CON_AXIS0)) {
- zero_v3(t->con.pmtx[0]);
- }
-
- if (!(t->con.mode & CON_AXIS1)) {
- zero_v3(t->con.pmtx[1]);
- }
-
- if (!(t->con.mode & CON_AXIS2)) {
- zero_v3(t->con.pmtx[2]);
- }
-
- mul_m3_m3m3(mat, t->con.pmtx, t->con.imtx);
- mul_m3_m3m3(t->con.pmtx, t->con.mtx, mat);
-}
-
/*------------------------- MMB Select -------------------------------*/
-void initSelectConstraint(TransInfo *t, float mtx[3][3])
+void initSelectConstraint(TransInfo *t)
{
- copy_m3_m3(t->con.mtx, mtx);
- t->con.mode |= CON_APPLY;
- t->con.mode |= CON_SELECT;
+ if (t->orient_curr == 0) {
+ t->orient_curr = 1;
+ transform_orientations_current_set(t, t->orient_curr);
+ }
+ short orientation = t->orient[t->orient_curr].type;
+ setUserConstraint(t, orientation, CON_APPLY | CON_SELECT, "%s");
setNearestAxis(t);
- t->con.drawExtra = NULL;
- t->con.applyVec = applyAxisConstraintVec;
- t->con.applySize = applyAxisConstraintSize;
- t->con.applyRot = applyAxisConstraintRot;
}
void selectConstraint(TransInfo *t)
@@ -1060,7 +951,7 @@ static void setNearestAxis3d(TransInfo *t)
for (i = 0; i < 3; i++) {
float axis[3], axis_2d[2];
- copy_v3_v3(axis, t->con.mtx[i]);
+ copy_v3_v3(axis, t->spacemtx[i]);
mul_v3_fl(axis, zfac);
/* now we can project to get window coordinate */
@@ -1129,7 +1020,7 @@ void setNearestAxis(TransInfo *t)
setNearestAxis2d(t);
}
- getConstraintMatrix(t);
+ projection_matrix_calc(t, t->con.pmtx);
}
/*-------------- HELPER FUNCTIONS ----------------*/
diff --git a/source/blender/editors/transform/transform_constraints.h b/source/blender/editors/transform/transform_constraints.h
index 8938ca93ad8..c41b9361ca4 100644
--- a/source/blender/editors/transform/transform_constraints.h
+++ b/source/blender/editors/transform/transform_constraints.h
@@ -27,7 +27,7 @@
struct TransInfo;
void constraintNumInput(TransInfo *t, float vec[3]);
-void setConstraint(TransInfo *t, float space[3][3], int mode, const char text[]);
+void setConstraint(TransInfo *t, int mode, const char text[]);
void setAxisMatrixConstraint(TransInfo *t, int mode, const char text[]);
void setLocalConstraint(TransInfo *t, int mode, const char text[]);
void setUserConstraint(TransInfo *t, short orientation, int mode, const char text[]);
@@ -35,8 +35,7 @@ void drawConstraint(TransInfo *t);
void drawPropCircle(const struct bContext *C, TransInfo *t);
void startConstraint(TransInfo *t);
void stopConstraint(TransInfo *t);
-void getConstraintMatrix(TransInfo *t);
-void initSelectConstraint(TransInfo *t, float mtx[3][3]);
+void initSelectConstraint(TransInfo *t);
void selectConstraint(TransInfo *t);
void postSelectConstraint(TransInfo *t);
void setNearestAxis(TransInfo *t);
diff --git a/source/blender/editors/transform/transform_convert.c b/source/blender/editors/transform/transform_convert.c
index c3949899dff..cf60990d09c 100644
--- a/source/blender/editors/transform/transform_convert.c
+++ b/source/blender/editors/transform/transform_convert.c
@@ -83,16 +83,47 @@
#include "transform_convert.h"
#include "transform_mode.h"
+bool transform_mode_use_local_origins(const TransInfo *t)
+{
+ return ELEM(t->mode, TFM_ROTATION, TFM_RESIZE, TFM_TRACKBALL);
+}
+
/**
* Transforming around ourselves is no use, fallback to individual origins,
* useful for curve/armatures.
*/
void transform_around_single_fallback(TransInfo *t)
{
- if ((t->data_len_all == 1) &&
- (ELEM(t->around, V3D_AROUND_CENTER_BOUNDS, V3D_AROUND_CENTER_MEDIAN, V3D_AROUND_ACTIVE)) &&
- (ELEM(t->mode, TFM_RESIZE, TFM_ROTATION, TFM_TRACKBALL))) {
- t->around = V3D_AROUND_LOCAL_ORIGINS;
+ if ((ELEM(t->around, V3D_AROUND_CENTER_BOUNDS, V3D_AROUND_CENTER_MEDIAN, V3D_AROUND_ACTIVE)) &&
+ transform_mode_use_local_origins(t)) {
+
+ bool is_data_single = false;
+ if (t->data_len_all == 1) {
+ is_data_single = true;
+ }
+ else if (t->data_len_all == 3) {
+ if (t->obedit_type == OB_CURVE) {
+ /* Special case check for curve, if we have a single curve bezier triple selected
+ * treat */
+ FOREACH_TRANS_DATA_CONTAINER (t, tc) {
+ if (!tc->data_len) {
+ continue;
+ }
+ if (tc->data_len == 3) {
+ const TransData *td = tc->data;
+ if ((td[0].flag | td[1].flag | td[2].flag) & TD_BEZTRIPLE) {
+ if ((td[0].loc == td[1].loc) && (td[1].loc == td[2].loc)) {
+ is_data_single = true;
+ }
+ }
+ }
+ break;
+ }
+ }
+ }
+ if (is_data_single) {
+ t->around = V3D_AROUND_LOCAL_ORIGINS;
+ }
}
}
@@ -377,23 +408,25 @@ static short apply_targetless_ik(Object *ob)
}
for (; segcount; segcount--) {
Bone *bone;
- float rmat[4][4] /*, tmat[4][4], imat[4][4]*/;
+ float mat[4][4];
/* pose_mat(b) = pose_mat(b-1) * offs_bone * channel * constraint * IK */
- /* we put in channel the entire result of rmat = (channel * constraint * IK) */
- /* pose_mat(b) = pose_mat(b-1) * offs_bone * rmat */
- /* rmat = pose_mat(b) * inv(pose_mat(b-1) * offs_bone ) */
+ /* we put in channel the entire result of mat = (channel * constraint * IK) */
+ /* pose_mat(b) = pose_mat(b-1) * offs_bone * mat */
+ /* mat = pose_mat(b) * inv(pose_mat(b-1) * offs_bone ) */
parchan = chanlist[segcount - 1];
bone = parchan->bone;
bone->flag |= BONE_TRANSFORM; /* ensures it gets an auto key inserted */
- BKE_armature_mat_pose_to_bone(parchan, parchan->pose_mat, rmat);
-
+ BKE_armature_mat_pose_to_bone(parchan, parchan->pose_mat, mat);
/* apply and decompose, doesn't work for constraints or non-uniform scale well */
{
float rmat3[3][3], qrmat[3][3], imat3[3][3], smat[3][3];
- copy_m3_m4(rmat3, rmat);
+
+ copy_m3_m4(rmat3, mat);
+ /* Make sure that our rotation matrix only contains rotation and not scale. */
+ normalize_m3(rmat3);
/* rotation */
/* [#22409] is partially caused by this, as slight numeric error introduced during
@@ -413,7 +446,7 @@ static short apply_targetless_ik(Object *ob)
/* causes problems with some constraints (e.g. childof), so disable this */
/* as it is IK shouldn't affect location directly */
- /* copy_v3_v3(parchan->loc, rmat[3]); */
+ /* copy_v3_v3(parchan->loc, mat[3]); */
}
}
@@ -445,12 +478,12 @@ static void bone_children_clear_transflag(int mode, short around, ListBase *lb)
}
}
-/* sets transform flags in the bones
- * returns total number of bones with BONE_TRANSFORM */
-int count_set_pose_transflags(Object *ob,
- const int mode,
- const short around,
- bool has_translate_rotate[2])
+/* Sets transform flags in the bones.
+ * Returns total number of bones with `BONE_TRANSFORM`. */
+int transform_convert_pose_transflags_update(Object *ob,
+ const int mode,
+ const short around,
+ bool has_translate_rotate[2])
{
bArmature *arm = ob->data;
bPoseChannel *pchan;
@@ -459,15 +492,20 @@ int count_set_pose_transflags(Object *ob,
for (pchan = ob->pose->chanbase.first; pchan; pchan = pchan->next) {
bone = pchan->bone;
- bone->flag &= ~(BONE_TRANSFORM | BONE_TRANSFORM_MIRROR);
if (PBONE_VISIBLE(arm, bone)) {
if ((bone->flag & BONE_SELECTED)) {
bone->flag |= BONE_TRANSFORM;
}
+ else {
+ bone->flag &= ~BONE_TRANSFORM;
+ }
bone->flag &= ~BONE_HINGE_CHILD_TRANSFORM;
bone->flag &= ~BONE_TRANSFORM_CHILD;
}
+ else {
+ bone->flag &= ~BONE_TRANSFORM;
+ }
}
/* make sure no bone can be transformed when a parent is transformed */
@@ -791,10 +829,6 @@ void clipUVData(TransInfo *t)
FOREACH_TRANS_DATA_CONTAINER (t, tc) {
TransData *td = tc->data;
for (int a = 0; a < tc->data_len; a++, td++) {
- if (td->flag & TD_NOACTION) {
- break;
- }
-
if ((td->flag & TD_SKIP) || (!td->loc)) {
continue;
}
@@ -812,25 +846,28 @@ void clipUVData(TransInfo *t)
* \{ */
/**
- * For modal operation: `t->center_global` may not have been set yet.
+ * Used for `TFM_TIME_EXTEND`.
*/
-void transform_convert_center_global_v2(TransInfo *t, float r_center[2])
+char transform_convert_frame_side_dir_get(TransInfo *t, float cframe)
{
+ char r_dir;
+ float center[2];
if (t->flag & T_MODAL) {
UI_view2d_region_to_view(
- (View2D *)t->view, t->mouse.imval[0], t->mouse.imval[1], &r_center[0], &r_center[1]);
+ (View2D *)t->view, t->mouse.imval[0], t->mouse.imval[1], &center[0], &center[1]);
+ r_dir = (center[0] > cframe) ? 'R' : 'L';
+ {
+ /* XXX: This saves the direction in the "mirror" property to be used for redo! */
+ if (r_dir == 'R') {
+ t->flag |= T_NO_MIRROR;
+ }
+ }
}
else {
- copy_v2_v2(r_center, t->center_global);
+ r_dir = (t->flag & T_NO_MIRROR) ? 'R' : 'L';
}
-}
-void transform_convert_center_global_v2_int(TransInfo *t, int r_center[2])
-{
- float center[2];
- transform_convert_center_global_v2(t, center);
- r_center[0] = round_fl_to_int(center[0]);
- r_center[1] = round_fl_to_int(center[1]);
+ return r_dir;
}
/* This function tests if a point is on the "mouse" side of the cursor/frame-marking */
@@ -1021,7 +1058,7 @@ static void posttrans_fcurve_clean(FCurve *fcu,
}
else {
/* Compute the average values for each retained keyframe */
- for (tRetainedKeyframe *rk = retained_keys.first; rk; rk = rk->next) {
+ LISTBASE_FOREACH (tRetainedKeyframe *, rk, &retained_keys) {
rk->val = rk->val / (float)rk->tot_count;
}
}
@@ -1123,10 +1160,10 @@ static void posttrans_action_clean(bAnimContext *ac, bAction *act)
/* struct for use in re-sorting BezTriples during Graph Editor transform */
typedef struct BeztMap {
BezTriple *bezt;
- unsigned int oldIndex; /* index of bezt in fcu->bezt array before sorting */
- unsigned int newIndex; /* index of bezt in fcu->bezt array after sorting */
- short swapHs; /* swap order of handles (-1=clear; 0=not checked, 1=swap) */
- char pipo, cipo; /* interpolation of current and next segments */
+ uint oldIndex; /* index of bezt in fcu->bezt array before sorting */
+ uint newIndex; /* index of bezt in fcu->bezt array after sorting */
+ short swapHs; /* swap order of handles (-1=clear; 0=not checked, 1=swap) */
+ char pipo, cipo; /* interpolation of current and next segments */
} BeztMap;
/* This function converts an FCurve's BezTriple array to a BeztMap array
@@ -1304,7 +1341,7 @@ static void beztmap_to_data(TransInfo *t, FCurve *fcu, BeztMap *bezms, int totve
*/
void remake_graph_transdata(TransInfo *t, ListBase *anim_data)
{
- SpaceGraph *sipo = (SpaceGraph *)t->sa->spacedata.first;
+ SpaceGraph *sipo = (SpaceGraph *)t->area->spacedata.first;
bAnimListElem *ale;
const bool use_handle = (sipo->flag & SIPO_NOHANDLES) == 0;
@@ -1581,145 +1618,148 @@ void autokeyframe_pose(bContext *C, Scene *scene, Object *ob, int tmode, short t
FCurve *fcu;
// TODO: this should probably be done per channel instead...
- if (autokeyframe_cfra_can_key(scene, id)) {
- ReportList *reports = CTX_wm_reports(C);
- ToolSettings *ts = scene->toolsettings;
- KeyingSet *active_ks = ANIM_scene_get_active_keyingset(scene);
- ListBase nla_cache = {NULL, NULL};
- float cfra = (float)CFRA;
- eInsertKeyFlags flag = 0;
+ if (!autokeyframe_cfra_can_key(scene, id)) {
+ /* tag channels that should have unkeyed data */
+ for (pchan = pose->chanbase.first; pchan; pchan = pchan->next) {
+ if (pchan->bone->flag & BONE_TRANSFORM) {
+ /* tag this channel */
+ pchan->bone->flag |= BONE_UNKEYED;
+ }
+ }
+ return;
+ }
- /* flag is initialized from UserPref keyframing settings
- * - special exception for targetless IK - INSERTKEY_MATRIX keyframes should get
- * visual keyframes even if flag not set, as it's not that useful otherwise
- * (for quick animation recording)
- */
- flag = ANIM_get_keyframing_flags(scene, true);
+ ReportList *reports = CTX_wm_reports(C);
+ ToolSettings *ts = scene->toolsettings;
+ KeyingSet *active_ks = ANIM_scene_get_active_keyingset(scene);
+ ListBase nla_cache = {NULL, NULL};
+ float cfra = (float)CFRA;
+ eInsertKeyFlags flag = 0;
+
+ /* flag is initialized from UserPref keyframing settings
+ * - special exception for targetless IK - INSERTKEY_MATRIX keyframes should get
+ * visual keyframes even if flag not set, as it's not that useful otherwise
+ * (for quick animation recording)
+ */
+ flag = ANIM_get_keyframing_flags(scene, true);
- if (targetless_ik) {
- flag |= INSERTKEY_MATRIX;
+ if (targetless_ik) {
+ flag |= INSERTKEY_MATRIX;
+ }
+
+ for (pchan = pose->chanbase.first; pchan; pchan = pchan->next) {
+ if ((pchan->bone->flag & BONE_TRANSFORM) == 0 &&
+ !((pose->flag & POSE_MIRROR_EDIT) && (pchan->bone->flag & BONE_TRANSFORM_MIRROR))) {
+ continue;
}
- for (pchan = pose->chanbase.first; pchan; pchan = pchan->next) {
- if ((pchan->bone->flag & BONE_TRANSFORM) ||
- ((pose->flag & POSE_MIRROR_EDIT) && (pchan->bone->flag & BONE_TRANSFORM_MIRROR))) {
- ListBase dsources = {NULL, NULL};
-
- /* clear any 'unkeyed' flag it may have */
- pchan->bone->flag &= ~BONE_UNKEYED;
-
- /* add datasource override for the camera object */
- ANIM_relative_keyingset_add_source(&dsources, id, &RNA_PoseBone, pchan);
-
- /* only insert into active keyingset? */
- if (IS_AUTOKEY_FLAG(scene, ONLYKEYINGSET) && (active_ks)) {
- /* run the active Keying Set on the current datasource */
- ANIM_apply_keyingset(C, &dsources, NULL, active_ks, MODIFYKEY_MODE_INSERT, cfra);
- }
- /* only insert into available channels? */
- else if (IS_AUTOKEY_FLAG(scene, INSERTAVAIL)) {
- if (act) {
- for (fcu = act->curves.first; fcu; fcu = fcu->next) {
- /* only insert keyframes for this F-Curve if it affects the current bone */
- if (strstr(fcu->rna_path, "bones")) {
- char *pchanName = BLI_str_quoted_substrN(fcu->rna_path, "bones[");
-
- /* only if bone name matches too...
- * NOTE: this will do constraints too, but those are ok to do here too?
- */
- if (pchanName && STREQ(pchanName, pchan->name)) {
- insert_keyframe(bmain,
- reports,
- id,
- act,
- ((fcu->grp) ? (fcu->grp->name) : (NULL)),
- fcu->rna_path,
- fcu->array_index,
- cfra,
- ts->keyframe_type,
- &nla_cache,
- flag);
- }
-
- if (pchanName) {
- MEM_freeN(pchanName);
- }
- }
- }
- }
- }
- /* only insert keyframe if needed? */
- else if (IS_AUTOKEY_FLAG(scene, INSERTNEEDED)) {
- bool do_loc = false, do_rot = false, do_scale = false;
+ ListBase dsources = {NULL, NULL};
- /* Filter the conditions when this happens
- * (assume that 'curarea->spacetype == SPACE_VIEW3D'). */
- if (tmode == TFM_TRANSLATION) {
- if (targetless_ik) {
- do_rot = true;
- }
- else {
- do_loc = true;
- }
- }
- else if (ELEM(tmode, TFM_ROTATION, TFM_TRACKBALL)) {
- if (ELEM(scene->toolsettings->transform_pivot_point,
- V3D_AROUND_CURSOR,
- V3D_AROUND_ACTIVE)) {
- do_loc = true;
- }
+ /* clear any 'unkeyed' flag it may have */
+ pchan->bone->flag &= ~BONE_UNKEYED;
- if ((scene->toolsettings->transform_flag & SCE_XFORM_AXIS_ALIGN) == 0) {
- do_rot = true;
- }
- }
- else if (tmode == TFM_RESIZE) {
- if (ELEM(scene->toolsettings->transform_pivot_point,
- V3D_AROUND_CURSOR,
- V3D_AROUND_ACTIVE)) {
- do_loc = true;
- }
+ /* add datasource override for the camera object */
+ ANIM_relative_keyingset_add_source(&dsources, id, &RNA_PoseBone, pchan);
- if ((scene->toolsettings->transform_flag & SCE_XFORM_AXIS_ALIGN) == 0) {
- do_scale = true;
- }
+ /* only insert into active keyingset? */
+ if (IS_AUTOKEY_FLAG(scene, ONLYKEYINGSET) && (active_ks)) {
+ /* run the active Keying Set on the current datasource */
+ ANIM_apply_keyingset(C, &dsources, NULL, active_ks, MODIFYKEY_MODE_INSERT, cfra);
+ }
+ /* only insert into available channels? */
+ else if (IS_AUTOKEY_FLAG(scene, INSERTAVAIL)) {
+ if (act) {
+ for (fcu = act->curves.first; fcu; fcu = fcu->next) {
+ /* only insert keyframes for this F-Curve if it affects the current bone */
+ if (strstr(fcu->rna_path, "bones") == NULL) {
+ continue;
}
+ char *pchanName = BLI_str_quoted_substrN(fcu->rna_path, "bones[");
- if (do_loc) {
- KeyingSet *ks = ANIM_builtin_keyingset_get_named(NULL, ANIM_KS_LOCATION_ID);
- ANIM_apply_keyingset(C, &dsources, NULL, ks, MODIFYKEY_MODE_INSERT, cfra);
- }
- if (do_rot) {
- KeyingSet *ks = ANIM_builtin_keyingset_get_named(NULL, ANIM_KS_ROTATION_ID);
- ANIM_apply_keyingset(C, &dsources, NULL, ks, MODIFYKEY_MODE_INSERT, cfra);
+ /* only if bone name matches too...
+ * NOTE: this will do constraints too, but those are ok to do here too?
+ */
+ if (pchanName && STREQ(pchanName, pchan->name)) {
+ insert_keyframe(bmain,
+ reports,
+ id,
+ act,
+ ((fcu->grp) ? (fcu->grp->name) : (NULL)),
+ fcu->rna_path,
+ fcu->array_index,
+ cfra,
+ ts->keyframe_type,
+ &nla_cache,
+ flag);
}
- if (do_scale) {
- KeyingSet *ks = ANIM_builtin_keyingset_get_named(NULL, ANIM_KS_SCALING_ID);
- ANIM_apply_keyingset(C, &dsources, NULL, ks, MODIFYKEY_MODE_INSERT, cfra);
+
+ if (pchanName) {
+ MEM_freeN(pchanName);
}
}
- /* insert keyframe in all (transform) channels */
+ }
+ }
+ /* only insert keyframe if needed? */
+ else if (IS_AUTOKEY_FLAG(scene, INSERTNEEDED)) {
+ bool do_loc = false, do_rot = false, do_scale = false;
+
+ /* Filter the conditions when this happens
+ * (assume that 'curarea->spacetype == SPACE_VIEW3D'). */
+ if (tmode == TFM_TRANSLATION) {
+ if (targetless_ik) {
+ do_rot = true;
+ }
else {
- KeyingSet *ks = ANIM_builtin_keyingset_get_named(NULL, ANIM_KS_LOC_ROT_SCALE_ID);
- ANIM_apply_keyingset(C, &dsources, NULL, ks, MODIFYKEY_MODE_INSERT, cfra);
+ do_loc = true;
+ }
+ }
+ else if (ELEM(tmode, TFM_ROTATION, TFM_TRACKBALL)) {
+ if (ELEM(scene->toolsettings->transform_pivot_point,
+ V3D_AROUND_CURSOR,
+ V3D_AROUND_ACTIVE)) {
+ do_loc = true;
}
- /* free temp info */
- BLI_freelistN(&dsources);
+ if ((scene->toolsettings->transform_flag & SCE_XFORM_AXIS_ALIGN) == 0) {
+ do_rot = true;
+ }
}
- }
+ else if (tmode == TFM_RESIZE) {
+ if (ELEM(scene->toolsettings->transform_pivot_point,
+ V3D_AROUND_CURSOR,
+ V3D_AROUND_ACTIVE)) {
+ do_loc = true;
+ }
- BKE_animsys_free_nla_keyframing_context_cache(&nla_cache);
- }
- else {
- /* tag channels that should have unkeyed data */
- for (pchan = pose->chanbase.first; pchan; pchan = pchan->next) {
- if (pchan->bone->flag & BONE_TRANSFORM) {
- /* tag this channel */
- pchan->bone->flag |= BONE_UNKEYED;
+ if ((scene->toolsettings->transform_flag & SCE_XFORM_AXIS_ALIGN) == 0) {
+ do_scale = true;
+ }
+ }
+
+ if (do_loc) {
+ KeyingSet *ks = ANIM_builtin_keyingset_get_named(NULL, ANIM_KS_LOCATION_ID);
+ ANIM_apply_keyingset(C, &dsources, NULL, ks, MODIFYKEY_MODE_INSERT, cfra);
+ }
+ if (do_rot) {
+ KeyingSet *ks = ANIM_builtin_keyingset_get_named(NULL, ANIM_KS_ROTATION_ID);
+ ANIM_apply_keyingset(C, &dsources, NULL, ks, MODIFYKEY_MODE_INSERT, cfra);
+ }
+ if (do_scale) {
+ KeyingSet *ks = ANIM_builtin_keyingset_get_named(NULL, ANIM_KS_SCALING_ID);
+ ANIM_apply_keyingset(C, &dsources, NULL, ks, MODIFYKEY_MODE_INSERT, cfra);
}
}
+ /* insert keyframe in all (transform) channels */
+ else {
+ KeyingSet *ks = ANIM_builtin_keyingset_get_named(NULL, ANIM_KS_LOC_ROT_SCALE_ID);
+ ANIM_apply_keyingset(C, &dsources, NULL, ks, MODIFYKEY_MODE_INSERT, cfra);
+ }
+
+ /* free temp info */
+ BLI_freelistN(&dsources);
}
+
+ BKE_animsys_free_nla_keyframing_context_cache(&nla_cache);
}
/** \} */
@@ -1741,13 +1781,12 @@ bool motionpath_need_update_pose(Scene *scene, Object *ob)
static void special_aftertrans_update__movieclip(bContext *C, TransInfo *t)
{
- SpaceClip *sc = t->sa->spacedata.first;
+ SpaceClip *sc = t->area->spacedata.first;
MovieClip *clip = ED_space_clip_get_clip(sc);
ListBase *plane_tracks_base = BKE_tracking_get_active_plane_tracks(&clip->tracking);
const int framenr = ED_space_clip_get_clip_frame_number(sc);
/* Update coordinates of modified plane tracks. */
- for (MovieTrackingPlaneTrack *plane_track = plane_tracks_base->first; plane_track;
- plane_track = plane_track->next) {
+ LISTBASE_FOREACH (MovieTrackingPlaneTrack *, plane_track, plane_tracks_base) {
bool do_update = false;
if (plane_track->flag & PLANE_TRACK_HIDDEN) {
continue;
@@ -1783,11 +1822,11 @@ static void special_aftertrans_update__mask(bContext *C, TransInfo *t)
Mask *mask = NULL;
if (t->spacetype == SPACE_CLIP) {
- SpaceClip *sc = t->sa->spacedata.first;
+ SpaceClip *sc = t->area->spacedata.first;
mask = ED_space_clip_get_mask(sc);
}
else if (t->spacetype == SPACE_IMAGE) {
- SpaceImage *sima = t->sa->spacedata.first;
+ SpaceImage *sima = t->area->spacedata.first;
mask = ED_space_image_get_mask(sima);
}
else {
@@ -1807,7 +1846,10 @@ static void special_aftertrans_update__mask(bContext *C, TransInfo *t)
if (IS_AUTOKEY_ON(t->scene)) {
Scene *scene = t->scene;
- ED_mask_layer_shape_auto_key_select(mask, CFRA);
+ if (ED_mask_layer_shape_auto_key_select(mask, CFRA)) {
+ WM_event_add_notifier(C, NC_MASK | ND_DATA, &mask->id);
+ DEG_id_tag_update(&mask->id, 0);
+ }
}
}
@@ -1818,7 +1860,7 @@ static void special_aftertrans_update__node(bContext *C, TransInfo *t)
if (canceled && t->remove_on_cancel) {
/* remove selected nodes on cancel */
- SpaceNode *snode = (SpaceNode *)t->sa->spacedata.first;
+ SpaceNode *snode = (SpaceNode *)t->area->spacedata.first;
bNodeTree *ntree = snode->edittree;
if (ntree) {
bNode *node, *node_next;
@@ -1828,14 +1870,15 @@ static void special_aftertrans_update__node(bContext *C, TransInfo *t)
nodeRemoveNode(bmain, ntree, node, true);
}
}
+ ntreeUpdateTree(bmain, ntree);
}
}
}
static void special_aftertrans_update__mesh(bContext *UNUSED(C), TransInfo *t)
{
- /* so automerge supports mirror */
- if ((t->scene->toolsettings->automerge) && ((t->flag & T_EDIT) && t->obedit_type == OB_MESH)) {
+ bool use_automerge = (t->flag & (T_AUTOMERGE | T_AUTOSPLIT)) != 0;
+ if (use_automerge && ((t->flag & T_EDIT) && t->obedit_type == OB_MESH)) {
FOREACH_TRANS_DATA_CONTAINER (t, tc) {
BMEditMesh *em = BKE_editmesh_from_object(tc->obedit);
@@ -1861,14 +1904,12 @@ static void special_aftertrans_update__mesh(bContext *UNUSED(C), TransInfo *t)
hflag = BM_ELEM_SELECT;
}
- if (t->scene->toolsettings->automerge & AUTO_MERGE) {
- if (t->scene->toolsettings->automerge & AUTO_MERGE_AND_SPLIT) {
- EDBM_automerge_and_split(
- tc->obedit, true, true, true, hflag, t->scene->toolsettings->doublimit);
- }
- else {
- EDBM_automerge(tc->obedit, true, hflag, t->scene->toolsettings->doublimit);
- }
+ if (t->flag & T_AUTOSPLIT) {
+ EDBM_automerge_and_split(
+ tc->obedit, true, true, true, hflag, t->scene->toolsettings->doublimit);
+ }
+ else {
+ EDBM_automerge(tc->obedit, true, hflag, t->scene->toolsettings->doublimit);
}
/* Special case, this is needed or faces won't re-select.
@@ -1941,7 +1982,7 @@ void special_aftertrans_update(bContext *C, TransInfo *t)
/* freeSeqData in transform_conversions.c does this
* keep here so the else at the end wont run... */
- SpaceSeq *sseq = (SpaceSeq *)t->sa->spacedata.first;
+ SpaceSeq *sseq = (SpaceSeq *)t->area->spacedata.first;
/* Marker transform, not especially nice but we may want to move markers
* at the same time as strips in the Video Sequencer. */
@@ -1967,16 +2008,16 @@ void special_aftertrans_update(bContext *C, TransInfo *t)
}
}
else if (t->spacetype == SPACE_NODE) {
- SpaceNode *snode = (SpaceNode *)t->sa->spacedata.first;
+ SpaceNode *snode = (SpaceNode *)t->area->spacedata.first;
special_aftertrans_update__node(C, t);
if (canceled == 0) {
ED_node_post_apply_transform(C, snode->edittree);
- ED_node_link_insert(bmain, t->sa);
+ ED_node_link_insert(bmain, t->area);
}
/* clear link line */
- ED_node_link_intersect_test(t->sa, 0);
+ ED_node_link_intersect_test(t->area, 0);
}
else if (t->spacetype == SPACE_CLIP) {
if (t->options & CTX_MOVIECLIP) {
@@ -1987,7 +2028,7 @@ void special_aftertrans_update(bContext *C, TransInfo *t)
}
}
else if (t->spacetype == SPACE_ACTION) {
- SpaceAction *saction = (SpaceAction *)t->sa->spacedata.first;
+ SpaceAction *saction = (SpaceAction *)t->area->spacedata.first;
bAnimContext ac;
/* initialize relevant anim-context 'context' data */
@@ -2070,12 +2111,12 @@ void special_aftertrans_update(bContext *C, TransInfo *t)
const int filter = ANIMFILTER_DATA_VISIBLE;
ANIM_animdata_filter(&ac, &anim_data, filter, ac.data, ac.datatype);
- for (bAnimListElem *ale = anim_data.first; ale; ale = ale->next) {
+ LISTBASE_FOREACH (bAnimListElem *, ale, &anim_data) {
if (ale->datatype == ALE_GPFRAME) {
ale->id->tag |= LIB_TAG_DOIT;
}
}
- for (bAnimListElem *ale = anim_data.first; ale; ale = ale->next) {
+ LISTBASE_FOREACH (bAnimListElem *, ale, &anim_data) {
if (ale->datatype == ALE_GPFRAME) {
if (ale->id->tag & LIB_TAG_DOIT) {
ale->id->tag &= ~LIB_TAG_DOIT;
@@ -2101,12 +2142,12 @@ void special_aftertrans_update(bContext *C, TransInfo *t)
const int filter = ANIMFILTER_DATA_VISIBLE;
ANIM_animdata_filter(&ac, &anim_data, filter, ac.data, ac.datatype);
- for (bAnimListElem *ale = anim_data.first; ale; ale = ale->next) {
+ LISTBASE_FOREACH (bAnimListElem *, ale, &anim_data) {
if (ale->datatype == ALE_MASKLAY) {
ale->id->tag |= LIB_TAG_DOIT;
}
}
- for (bAnimListElem *ale = anim_data.first; ale; ale = ale->next) {
+ LISTBASE_FOREACH (bAnimListElem *, ale, &anim_data) {
if (ale->datatype == ALE_MASKLAY) {
if (ale->id->tag & LIB_TAG_DOIT) {
ale->id->tag &= ~LIB_TAG_DOIT;
@@ -2151,7 +2192,7 @@ void special_aftertrans_update(bContext *C, TransInfo *t)
saction->flag &= ~SACTION_MOVING;
}
else if (t->spacetype == SPACE_GRAPH) {
- SpaceGraph *sipo = (SpaceGraph *)t->sa->spacedata.first;
+ SpaceGraph *sipo = (SpaceGraph *)t->area->spacedata.first;
bAnimContext ac;
const bool use_handle = (sipo->flag & SIPO_NOHANDLES) == 0;
@@ -2240,9 +2281,8 @@ void special_aftertrans_update(bContext *C, TransInfo *t)
else if (t->flag & T_EDIT) {
if (t->obedit_type == OB_MESH) {
FOREACH_TRANS_DATA_CONTAINER (t, tc) {
- BMEditMesh *em = BKE_editmesh_from_object(tc->obedit);
/* table needs to be created for each edit command, since vertices can move etc */
- ED_mesh_mirror_spatial_table(tc->obedit, em, NULL, NULL, 'e');
+ ED_mesh_mirror_spatial_table_end(tc->obedit);
/* TODO(campbell): xform: We need support for many mirror objects at once! */
break;
}
@@ -2277,7 +2317,7 @@ void special_aftertrans_update(bContext *C, TransInfo *t)
/* set BONE_TRANSFORM flags for autokey, gizmo draw might have changed them */
if (!canceled && (t->mode != TFM_DUMMY)) {
- count_set_pose_transflags(ob, t->mode, t->around, NULL);
+ transform_convert_pose_transflags_update(ob, t->mode, t->around, NULL);
}
/* if target-less IK grabbing, we calculate the pchan transforms and clear flag */
@@ -2348,10 +2388,6 @@ void special_aftertrans_update(bContext *C, TransInfo *t)
PTCacheID *pid;
ob = td->ob;
- if (td->flag & TD_NOACTION) {
- break;
- }
-
if (td->flag & TD_SKIP) {
continue;
}
@@ -2732,7 +2768,7 @@ void createTransData(bContext *C, TransInfo *t)
/* important that ob_armature can be set even when its not selected [#23412]
* lines below just check is also visible */
has_transform_context = false;
- Object *ob_armature = modifiers_isDeformedByArmature(ob);
+ Object *ob_armature = BKE_modifiers_is_deformed_by_armature(ob);
if (ob_armature && ob_armature->mode & OB_MODE_POSE) {
Base *base_arm = BKE_view_layer_base_find(t->view_layer, ob_armature);
if (base_arm) {
diff --git a/source/blender/editors/transform/transform_convert.h b/source/blender/editors/transform/transform_convert.h
index d616f24ba86..e5d758135e2 100644
--- a/source/blender/editors/transform/transform_convert.h
+++ b/source/blender/editors/transform/transform_convert.h
@@ -37,10 +37,10 @@ struct bKinematicConstraint;
struct bPoseChannel;
/* transform_convert.c */
-int count_set_pose_transflags(Object *ob,
- const int mode,
- const short around,
- bool has_translate_rotate[2]);
+int transform_convert_pose_transflags_update(Object *ob,
+ const int mode,
+ const short around,
+ bool has_translate_rotate[2]);
void transform_autoik_update(TransInfo *t, short mode);
void autokeyframe_object(struct bContext *C,
struct Scene *scene,
@@ -100,12 +100,12 @@ void flushTransTracking(TransInfo *t);
/********************* intern **********************/
/* transform_convert.c */
+bool transform_mode_use_local_origins(const TransInfo *t);
void transform_around_single_fallback(TransInfo *t);
bool constraints_list_needinv(TransInfo *t, ListBase *list);
void calc_distanceCurveVerts(TransData *head, TransData *tail);
struct TransDataCurveHandleFlags *initTransDataCurveHandles(TransData *td, struct BezTriple *bezt);
-void transform_convert_center_global_v2(TransInfo *t, float r_center[2]);
-void transform_convert_center_global_v2_int(TransInfo *t, int r_center[2]);
+char transform_convert_frame_side_dir_get(TransInfo *t, float cframe);
bool FrameOnMouseSide(char side, float frame, float cframe);
/* transform_convert_action.c */
diff --git a/source/blender/editors/transform/transform_convert_action.c b/source/blender/editors/transform/transform_convert_action.c
index c9273121df5..21ef1539911 100644
--- a/source/blender/editors/transform/transform_convert_action.c
+++ b/source/blender/editors/transform/transform_convert_action.c
@@ -331,10 +331,7 @@ void createTransActionData(bContext *C, TransInfo *t)
/* which side of the current frame should be allowed */
if (t->mode == TFM_TIME_EXTEND) {
- /* only side on which center is gets transformed */
- float center[2];
- transform_convert_center_global_v2(t, center);
- t->frame_side = (center[0] > CFRA) ? 'R' : 'L';
+ t->frame_side = transform_convert_frame_side_dir_get(t, (float)CFRA);
}
else {
/* normal transform - both sides of current frame are considered */
diff --git a/source/blender/editors/transform/transform_convert_armature.c b/source/blender/editors/transform/transform_convert_armature.c
index 4e8e0cc2369..35bb7e3f0d8 100644
--- a/source/blender/editors/transform/transform_convert_armature.c
+++ b/source/blender/editors/transform/transform_convert_armature.c
@@ -26,6 +26,7 @@
#include "MEM_guardedalloc.h"
+#include "BLI_listbase.h"
#include "BLI_math.h"
#include "BKE_action.h"
@@ -57,6 +58,37 @@ typedef struct BoneInitData {
float zwidth;
} BoneInitData;
+static bConstraint *add_temporary_ik_constraint(bPoseChannel *pchan,
+ bKinematicConstraint *targetless_con)
+{
+ bConstraint *con = BKE_constraint_add_for_pose(
+ NULL, pchan, "TempConstraint", CONSTRAINT_TYPE_KINEMATIC);
+
+ /* for draw, but also for detecting while pose solving */
+ pchan->constflag |= (PCHAN_HAS_IK | PCHAN_HAS_TARGET);
+
+ bKinematicConstraint *temp_con_data = con->data;
+
+ if (targetless_con) {
+ /* if exists, use values from last targetless (but disabled) IK-constraint as base */
+ *temp_con_data = *targetless_con;
+ }
+ else {
+ temp_con_data->flag = CONSTRAINT_IK_TIP;
+ }
+
+ temp_con_data->flag |= CONSTRAINT_IK_TEMP | CONSTRAINT_IK_AUTO | CONSTRAINT_IK_POS;
+
+ return con;
+}
+
+static void update_deg_with_temporary_ik(Main *bmain, Object *ob)
+{
+ BIK_clear_data(ob->pose);
+ /* TODO(sergey): Consider doing partial update only. */
+ DEG_relations_tag_update(bmain);
+}
+
static void add_pose_transdata(
TransInfo *t, bPoseChannel *pchan, Object *ob, TransDataContainer *tc, TransData *td)
{
@@ -199,8 +231,16 @@ static void add_pose_transdata(
}
td->loc = data->grabtarget;
copy_v3_v3(td->iloc, td->loc);
+
data->flag |= CONSTRAINT_IK_AUTO;
+ /* Add a temporary auto IK constraint here, as we will only temporarily active this
+ * targetless bone during transform. (Targetless IK constraints are treated as if they are
+ * disabled unless they are transformed). */
+ add_temporary_ik_constraint(pchan, data);
+ Main *bmain = CTX_data_main(t->context);
+ update_deg_with_temporary_ik(bmain, ob);
+
/* only object matrix correction */
copy_m3_m3(td->mtx, omat);
pseudoinverse_m3_m3(td->smtx, td->mtx, PSEUDOINVERSE_EPSILON);
@@ -220,7 +260,8 @@ bKinematicConstraint *has_targetless_ik(bPoseChannel *pchan)
bConstraint *con = pchan->constraints.first;
for (; con; con = con->next) {
- if (con->type == CONSTRAINT_TYPE_KINEMATIC && (con->enforce != 0.0f)) {
+ if (con->type == CONSTRAINT_TYPE_KINEMATIC && (con->flag & CONSTRAINT_OFF) == 0 &&
+ (con->enforce != 0.0f)) {
bKinematicConstraint *data = con->data;
if (data->tar == NULL) {
@@ -248,7 +289,7 @@ static short pose_grab_with_ik_add(bPoseChannel *pchan)
/* Rule: not if there's already an IK on this channel */
for (con = pchan->constraints.first; con; con = con->next) {
- if (con->type == CONSTRAINT_TYPE_KINEMATIC) {
+ if (con->type == CONSTRAINT_TYPE_KINEMATIC && (con->flag & CONSTRAINT_OFF) == 0) {
data = con->data;
if (data->tar == NULL || (data->tar->type == OB_ARMATURE && data->subtarget[0] == '\0')) {
@@ -263,22 +304,20 @@ static short pose_grab_with_ik_add(bPoseChannel *pchan)
/* if no chain length has been specified,
* just make things obey standard rotation locks too */
if (data->rootbone == 0) {
- for (; pchan; pchan = pchan->parent) {
+ for (bPoseChannel *pchan_iter = pchan; pchan_iter; pchan_iter = pchan_iter->parent) {
/* here, we set ik-settings for bone from pchan->protectflag */
// XXX: careful with quats/axis-angle rotations where we're locking 4d components
- if (pchan->protectflag & OB_LOCK_ROTX) {
- pchan->ikflag |= BONE_IK_NO_XDOF_TEMP;
+ if (pchan_iter->protectflag & OB_LOCK_ROTX) {
+ pchan_iter->ikflag |= BONE_IK_NO_XDOF_TEMP;
}
- if (pchan->protectflag & OB_LOCK_ROTY) {
- pchan->ikflag |= BONE_IK_NO_YDOF_TEMP;
+ if (pchan_iter->protectflag & OB_LOCK_ROTY) {
+ pchan_iter->ikflag |= BONE_IK_NO_YDOF_TEMP;
}
- if (pchan->protectflag & OB_LOCK_ROTZ) {
- pchan->ikflag |= BONE_IK_NO_ZDOF_TEMP;
+ if (pchan_iter->protectflag & OB_LOCK_ROTZ) {
+ pchan_iter->ikflag |= BONE_IK_NO_ZDOF_TEMP;
}
}
}
-
- return 0;
}
}
@@ -288,20 +327,8 @@ static short pose_grab_with_ik_add(bPoseChannel *pchan)
}
}
- con = BKE_constraint_add_for_pose(NULL, pchan, "TempConstraint", CONSTRAINT_TYPE_KINEMATIC);
+ data = add_temporary_ik_constraint(pchan, targetless)->data;
- /* for draw, but also for detecting while pose solving */
- pchan->constflag |= (PCHAN_HAS_IK | PCHAN_HAS_TARGET);
-
- data = con->data;
- if (targetless) {
- /* if exists, use values from last targetless (but disabled) IK-constraint as base */
- *data = *targetless;
- }
- else {
- data->flag = CONSTRAINT_IK_TIP;
- }
- data->flag |= CONSTRAINT_IK_TEMP | CONSTRAINT_IK_AUTO | CONSTRAINT_IK_POS;
copy_v3_v3(data->grabtarget, pchan->pose_tail);
/* watch-it! has to be 0 here, since we're still on the
@@ -414,9 +441,7 @@ static short pose_grab_with_ik(Main *bmain, Object *ob)
/* iTaSC needs clear for new IK constraints */
if (tot_ik) {
- BIK_clear_data(ob->pose);
- /* TODO(sergey): Consider doing partial update only. */
- DEG_relations_tag_update(bmain);
+ update_deg_with_temporary_ik(bmain, ob);
}
return (tot_ik) ? 1 : 0;
@@ -530,6 +555,11 @@ void pose_transform_mirror_update(TransInfo *t, TransDataContainer *tc, Object *
unit_m4(flip_mtx);
flip_mtx[0][0] = -1;
+ LISTBASE_FOREACH (bPoseChannel *, pchan_orig, &ob->pose->chanbase) {
+ /* Clear the MIRROR flag from previous runs. */
+ pchan_orig->bone->flag &= ~BONE_TRANSFORM_MIRROR;
+ }
+
bPose *pose = ob->pose;
PoseInitData_Mirror *pid = NULL;
if ((t->mode != TFM_BONESIZE) && (pose->flag & POSE_MIRROR_RELATIVE)) {
@@ -565,6 +595,9 @@ void pose_transform_mirror_update(TransInfo *t, TransDataContainer *tc, Object *
}
BKE_pchan_apply_mat4(pchan, pchan_mtx_final, false);
+ /* Set flag to let autokeyframe know to keyframe the mirrred bone. */
+ pchan->bone->flag |= BONE_TRANSFORM_MIRROR;
+
/* In this case we can do target-less IK grabbing. */
if (t->mode == TFM_TRANSLATION) {
bKinematicConstraint *data = has_targetless_ik(pchan);
@@ -576,6 +609,12 @@ void pose_transform_mirror_update(TransInfo *t, TransDataContainer *tc, Object *
/* TODO(germano): Realitve Mirror support */
}
data->flag |= CONSTRAINT_IK_AUTO;
+ /* Add a temporary auto IK constraint here, as we will only temporarily active this
+ * target-less bone during transform. (Target-less IK constraints are treated as if they are
+ * disabled unless they are transformed) */
+ add_temporary_ik_constraint(pchan, data);
+ Main *bmain = CTX_data_main(t->context);
+ update_deg_with_temporary_ik(bmain, ob);
}
if (pid) {
@@ -630,7 +669,9 @@ void createTransPose(TransInfo *t)
const bool mirror = ((pose->flag & POSE_MIRROR_EDIT) != 0);
/* set flags and count total */
- tc->data_len = count_set_pose_transflags(ob, t->mode, t->around, has_translate_rotate);
+ tc->data_len = transform_convert_pose_transflags_update(
+ ob, t->mode, t->around, has_translate_rotate);
+
if (tc->data_len == 0) {
continue;
}
@@ -645,7 +686,10 @@ void createTransPose(TransInfo *t)
if (mirror) {
int total_mirrored = 0;
- for (bPoseChannel *pchan = ob->pose->chanbase.first; pchan; pchan = pchan->next) {
+ LISTBASE_FOREACH (bPoseChannel *, pchan, &ob->pose->chanbase) {
+ /* Clear the MIRROR flag from previous runs. */
+ pchan->bone->flag &= ~BONE_TRANSFORM_MIRROR;
+
if ((pchan->bone->flag & BONE_TRANSFORM) &&
BKE_pose_channel_get_mirrored(ob->pose, pchan->name)) {
total_mirrored++;
@@ -695,7 +739,7 @@ void createTransPose(TransInfo *t)
}
if (mirror) {
- for (bPoseChannel *pchan = pose->chanbase.first; pchan; pchan = pchan->next) {
+ LISTBASE_FOREACH (bPoseChannel *, pchan, &pose->chanbase) {
if (pchan->bone->flag & BONE_TRANSFORM) {
bPoseChannel *pchan_mirror = BKE_pose_channel_get_mirrored(ob->pose, pchan->name);
if (pchan_mirror) {
@@ -717,7 +761,7 @@ void createTransPose(TransInfo *t)
/* use pose channels to fill trans data */
td = tc->data;
- for (bPoseChannel *pchan = ob->pose->chanbase.first; pchan; pchan = pchan->next) {
+ LISTBASE_FOREACH (bPoseChannel *, pchan, &ob->pose->chanbase) {
if (pchan->bone->flag & BONE_TRANSFORM) {
add_pose_transdata(t, pchan, ob, tc, td);
td++;
diff --git a/source/blender/editors/transform/transform_convert_cursor.c b/source/blender/editors/transform/transform_convert_cursor.c
index 621f9dd63e2..e6a972bfc7c 100644
--- a/source/blender/editors/transform/transform_convert_cursor.c
+++ b/source/blender/editors/transform/transform_convert_cursor.c
@@ -44,7 +44,7 @@
void createTransCursor_image(TransInfo *t)
{
TransData *td;
- SpaceImage *sima = t->sa->spacedata.first;
+ SpaceImage *sima = t->area->spacedata.first;
float *cursor_location = sima->cursor;
{
diff --git a/source/blender/editors/transform/transform_convert_curve.c b/source/blender/editors/transform/transform_convert_curve.c
index 24f0491c86c..1f113a36a89 100644
--- a/source/blender/editors/transform/transform_convert_curve.c
+++ b/source/blender/editors/transform/transform_convert_curve.c
@@ -25,6 +25,7 @@
#include "MEM_guardedalloc.h"
+#include "BLI_listbase.h"
#include "BLI_math.h"
#include "BKE_context.h"
@@ -92,13 +93,12 @@ void createTransCurveVerts(TransInfo *t)
int count = 0, countsel = 0;
const bool is_prop_edit = (t->flag & T_PROP_EDIT) != 0;
View3D *v3d = t->view;
- short hide_handles = (v3d != NULL) ?
- ((v3d->overlay.edit_flag & V3D_OVERLAY_EDIT_CU_HANDLES) == 0) :
- false;
+ short hide_handles = (v3d != NULL) ? (v3d->overlay.handle_display == CURVE_HANDLE_NONE) :
+ false;
/* count total of vertices, check identical as in 2nd loop for making transdata! */
ListBase *nurbs = BKE_curve_editNurbs_get(cu);
- for (Nurb *nu = nurbs->first; nu; nu = nu->next) {
+ LISTBASE_FOREACH (Nurb *, nu, nurbs) {
if (nu->type == CU_BEZIER) {
for (a = 0, bezt = nu->bezt; a < nu->pntsu; a++, bezt++) {
if (bezt->hide == 0) {
@@ -162,10 +162,11 @@ void createTransCurveVerts(TransInfo *t)
int a;
const bool is_prop_edit = (t->flag & T_PROP_EDIT) != 0;
View3D *v3d = t->view;
- short hide_handles = (v3d != NULL) ?
- ((v3d->overlay.edit_flag & V3D_OVERLAY_EDIT_CU_HANDLES) == 0) :
- false;
+ short hide_handles = (v3d != NULL) ? (v3d->overlay.handle_display == CURVE_HANDLE_NONE) :
+ false;
+ bool use_around_origins_for_handles_test = ((t->around == V3D_AROUND_LOCAL_ORIGINS) &&
+ transform_mode_use_local_origins(t));
float mtx[3][3], smtx[3][3];
copy_m3_m4(mtx, tc->obedit->obmat);
@@ -173,7 +174,7 @@ void createTransCurveVerts(TransInfo *t)
TransData *td = tc->data;
ListBase *nurbs = BKE_curve_editNurbs_get(cu);
- for (Nurb *nu = nurbs->first; nu; nu = nu->next) {
+ LISTBASE_FOREACH (Nurb *, nu, nurbs) {
if (nu->type == CU_BEZIER) {
TransData *head, *tail;
head = tail = td;
@@ -341,7 +342,7 @@ void createTransCurveVerts(TransInfo *t)
if (ELEM(t->mode, TFM_CURVE_SHRINKFATTEN, TFM_TILT, TFM_DUMMY) == 0) {
/* sets the handles based on their selection,
* do this after the data is copied to the TransData */
- BKE_nurb_handles_test(nu, !hide_handles);
+ BKE_nurb_handles_test(nu, !hide_handles, use_around_origins_for_handles_test);
}
}
else {
diff --git a/source/blender/editors/transform/transform_convert_graph.c b/source/blender/editors/transform/transform_convert_graph.c
index 95a385a5a50..f6f0dd3c491 100644
--- a/source/blender/editors/transform/transform_convert_graph.c
+++ b/source/blender/editors/transform/transform_convert_graph.c
@@ -167,7 +167,7 @@ static void graph_bezt_get_transform_selection(const TransInfo *t,
bool *r_key,
bool *r_right_handle)
{
- SpaceGraph *sipo = (SpaceGraph *)t->sa->spacedata.first;
+ SpaceGraph *sipo = (SpaceGraph *)t->area->spacedata.first;
bool key = (bezt->f2 & SELECT) != 0;
bool left = use_handle ? ((bezt->f1 & SELECT) != 0) : key;
bool right = use_handle ? ((bezt->f3 & SELECT) != 0) : key;
@@ -224,7 +224,7 @@ static void graph_key_shortest_dist(
*/
void createTransGraphEditData(bContext *C, TransInfo *t)
{
- SpaceGraph *sipo = (SpaceGraph *)t->sa->spacedata.first;
+ SpaceGraph *sipo = (SpaceGraph *)t->area->spacedata.first;
Scene *scene = t->scene;
ARegion *region = t->region;
View2D *v2d = &region->v2d;
@@ -261,10 +261,7 @@ void createTransGraphEditData(bContext *C, TransInfo *t)
/* which side of the current frame should be allowed */
// XXX we still want this mode, but how to get this using standard transform too?
if (t->mode == TFM_TIME_EXTEND) {
- /* only side on which center is gets transformed */
- float center[2];
- transform_convert_center_global_v2(t, center);
- t->frame_side = (center[0] > CFRA) ? 'R' : 'L';
+ t->frame_side = transform_convert_frame_side_dir_get(t, (float)CFRA);
}
else {
/* normal transform - both sides of current frame are considered */
@@ -642,7 +639,7 @@ void createTransGraphEditData(bContext *C, TransInfo *t)
*/
void flushTransGraphData(TransInfo *t)
{
- SpaceGraph *sipo = (SpaceGraph *)t->sa->spacedata.first;
+ SpaceGraph *sipo = (SpaceGraph *)t->area->spacedata.first;
TransData *td;
TransData2D *td2d;
TransDataGraph *tdg;
diff --git a/source/blender/editors/transform/transform_convert_mask.c b/source/blender/editors/transform/transform_convert_mask.c
index 65244a09b73..6c743da3e65 100644
--- a/source/blender/editors/transform/transform_convert_mask.c
+++ b/source/blender/editors/transform/transform_convert_mask.c
@@ -280,7 +280,7 @@ void createTransMaskingData(bContext *C, TransInfo *t)
}
if (t->spacetype == SPACE_CLIP) {
- SpaceClip *sc = t->sa->spacedata.first;
+ SpaceClip *sc = t->area->spacedata.first;
MovieClip *clip = ED_space_clip_get_clip(sc);
if (!clip) {
return;
@@ -333,7 +333,7 @@ void createTransMaskingData(bContext *C, TransInfo *t)
return;
}
- ED_mask_get_aspect(t->sa, t->region, &asp[0], &asp[1]);
+ ED_mask_get_aspect(t->area, t->region, &asp[0], &asp[1]);
tc->data_len = (is_prop_edit) ? count : countsel;
td = tc->data = MEM_callocN(tc->data_len * sizeof(TransData), "TransObData(Mask Editing)");
@@ -409,7 +409,7 @@ void flushTransMasking(TransInfo *t)
TransDataContainer *tc = TRANS_DATA_CONTAINER_FIRST_SINGLE(t);
- ED_mask_get_aspect(t->sa, t->region, &asp[0], &asp[1]);
+ ED_mask_get_aspect(t->area, t->region, &asp[0], &asp[1]);
inv[0] = 1.0f / asp[0];
inv[1] = 1.0f / asp[1];
diff --git a/source/blender/editors/transform/transform_convert_mesh.c b/source/blender/editors/transform/transform_convert_mesh.c
index 29a74be8e2b..07b2f07bf2c 100644
--- a/source/blender/editors/transform/transform_convert_mesh.c
+++ b/source/blender/editors/transform/transform_convert_mesh.c
@@ -61,8 +61,10 @@
/* when transforming islands */
struct TransIslandData {
- float co[3];
- float axismtx[3][3];
+ float (*center)[3];
+ float (*axismtx)[3][3];
+ int island_tot;
+ int *island_vert_map;
};
/* -------------------------------------------------------------------- */
@@ -247,18 +249,19 @@ static void editmesh_set_connectivity_distance(BMesh *bm,
}
}
-static struct TransIslandData *editmesh_islands_info_calc(BMEditMesh *em,
- int *r_island_tot,
- int **r_island_vert_map,
- bool calc_single_islands)
+static void editmesh_islands_info_calc(BMEditMesh *em,
+ const bool calc_single_islands,
+ const bool calc_island_axismtx,
+ struct TransIslandData *r_island_data)
{
BMesh *bm = em->bm;
- struct TransIslandData *trans_islands;
char htype;
char itype;
int i;
/* group vars */
+ float(*center)[3];
+ float(*axismtx)[3][3] = NULL;
int *groups_array;
int(*group_index)[2];
int group_tot;
@@ -283,7 +286,11 @@ static struct TransIslandData *editmesh_islands_info_calc(BMEditMesh *em,
itype = BM_VERTS_OF_FACE;
}
- trans_islands = MEM_mallocN(sizeof(*trans_islands) * group_tot, __func__);
+ center = MEM_mallocN(sizeof(*center) * group_tot, __func__);
+
+ if (calc_island_axismtx) {
+ axismtx = MEM_mallocN(sizeof(*axismtx) * group_tot, __func__);
+ }
vert_map = MEM_mallocN(sizeof(*vert_map) * bm->totvert, __func__);
/* we shouldn't need this, but with incorrect selection flushing
@@ -311,7 +318,7 @@ static struct TransIslandData *editmesh_islands_info_calc(BMEditMesh *em,
ese.htype = htype;
- /* loop on each face in this group:
+ /* loop on each face or edge in this group:
* - assign r_vert_map
* - calculate (co, no)
*/
@@ -321,12 +328,14 @@ static struct TransIslandData *editmesh_islands_info_calc(BMEditMesh *em,
ese.ele = ele_array[groups_array[fg_sta + j]];
BM_editselection_center(&ese, tmp_co);
- BM_editselection_normal(&ese, tmp_no);
- BM_editselection_plane(&ese, tmp_tangent);
-
add_v3_v3(co, tmp_co);
- add_v3_v3(no, tmp_no);
- add_v3_v3(tangent, tmp_tangent);
+
+ if (axismtx) {
+ BM_editselection_normal(&ese, tmp_no);
+ BM_editselection_plane(&ese, tmp_tangent);
+ add_v3_v3(no, tmp_no);
+ add_v3_v3(tangent, tmp_tangent);
+ }
{
/* setup vertex map */
@@ -340,18 +349,20 @@ static struct TransIslandData *editmesh_islands_info_calc(BMEditMesh *em,
}
}
- mul_v3_v3fl(trans_islands[i].co, co, 1.0f / (float)fg_len);
+ mul_v3_v3fl(center[i], co, 1.0f / (float)fg_len);
- if (createSpaceNormalTangent(trans_islands[i].axismtx, no, tangent)) {
- /* pass */
- }
- else {
- if (normalize_v3(no) != 0.0f) {
- axis_dominant_v3_to_m3(trans_islands[i].axismtx, no);
- invert_m3(trans_islands[i].axismtx);
+ if (axismtx) {
+ if (createSpaceNormalTangent(axismtx[i], no, tangent)) {
+ /* pass */
}
else {
- unit_m3(trans_islands[i].axismtx);
+ if (normalize_v3(no) != 0.0f) {
+ axis_dominant_v3_to_m3(axismtx[i], no);
+ invert_m3(axismtx[i]);
+ }
+ else {
+ unit_m3(axismtx[i]);
+ }
}
}
}
@@ -372,22 +383,24 @@ static struct TransIslandData *editmesh_islands_info_calc(BMEditMesh *em,
}
if (group_tot_single != 0) {
- trans_islands = MEM_reallocN(trans_islands,
- sizeof(*trans_islands) * (group_tot + group_tot_single));
+ center = MEM_reallocN(center, sizeof(*center) * (group_tot + group_tot_single));
+ if (axismtx) {
+ axismtx = MEM_reallocN(axismtx, sizeof(*axismtx) * (group_tot + group_tot_single));
+ }
BM_ITER_MESH_INDEX (v, &viter, bm, BM_VERTS_OF_MESH, i) {
if (BM_elem_flag_test(v, BM_ELEM_SELECT) && (vert_map[i] == -1)) {
- struct TransIslandData *v_island = &trans_islands[group_tot];
vert_map[i] = group_tot;
+ copy_v3_v3(center[group_tot], v->co);
- copy_v3_v3(v_island->co, v->co);
-
- if (is_zero_v3(v->no) != 0.0f) {
- axis_dominant_v3_to_m3(v_island->axismtx, v->no);
- invert_m3(v_island->axismtx);
- }
- else {
- unit_m3(v_island->axismtx);
+ if (axismtx) {
+ if (is_zero_v3(v->no) != 0.0f) {
+ axis_dominant_v3_to_m3(axismtx[group_tot], v->no);
+ invert_m3(axismtx[group_tot]);
+ }
+ else {
+ unit_m3(axismtx[group_tot]);
+ }
}
group_tot += 1;
@@ -396,10 +409,10 @@ static struct TransIslandData *editmesh_islands_info_calc(BMEditMesh *em,
}
}
- *r_island_tot = group_tot;
- *r_island_vert_map = vert_map;
-
- return trans_islands;
+ r_island_data->axismtx = axismtx;
+ r_island_data->center = center;
+ r_island_data->island_tot = group_tot;
+ r_island_data->island_vert_map = vert_map;
}
static bool is_in_quadrant_v3(const float co[3], const int quadrant[3], const float epsilon)
@@ -567,7 +580,8 @@ static void VertsToTransData(TransInfo *t,
BMEditMesh *em,
BMVert *eve,
float *bweight,
- struct TransIslandData *v_island,
+ const struct TransIslandData *island_data,
+ const int island_index,
const bool no_island_center)
{
float *no, _no[3];
@@ -589,14 +603,17 @@ static void VertsToTransData(TransInfo *t,
no = eve->no;
}
- if (v_island) {
+ if (island_index != -1) {
if (no_island_center) {
copy_v3_v3(td->center, td->loc);
}
else {
- copy_v3_v3(td->center, v_island->co);
+ copy_v3_v3(td->center, island_data->center[island_index]);
}
- copy_m3_m3(td->axismtx, v_island->axismtx);
+ }
+
+ if ((island_index != -1) && island_data->axismtx) {
+ copy_m3_m3(td->axismtx, island_data->axismtx[island_index]);
}
else if (t->around == V3D_AROUND_LOCAL_ORIGINS) {
copy_v3_v3(td->center, td->loc);
@@ -654,9 +671,7 @@ void createTransEditVerts(TransInfo *t)
const int prop_mode = (t->flag & T_PROP_EDIT) ? (t->flag & T_PROP_EDIT_ALL) : 0;
int cd_vert_bweight_offset = -1;
- struct TransIslandData *island_info = NULL;
- int island_info_tot;
- int *island_vert_map = NULL;
+ struct TransIslandData island_data = {NULL};
/* Snap rotation along normal needs a common axis for whole islands,
* otherwise one get random crazy results, see T59104.
@@ -758,14 +773,17 @@ void createTransEditVerts(TransInfo *t)
(t->around == V3D_AROUND_LOCAL_ORIGINS) &&
(em->selectmode & SCE_SELECT_VERTEX));
- island_info = editmesh_islands_info_calc(
- em, &island_info_tot, &island_vert_map, calc_single_islands);
+ /* The island axismtx is only necessary in some modes.
+ * TODO(Germano): Extend the list to exclude other modes. */
+ const bool calc_island_axismtx = !ELEM(t->mode, TFM_SHRINKFATTEN);
+
+ editmesh_islands_info_calc(em, calc_single_islands, calc_island_axismtx, &island_data);
}
/* detect CrazySpace [tm] */
- if (modifiers_getCageIndex(t->scene, tc->obedit, NULL, 1) != -1) {
+ if (BKE_modifiers_get_cage_index(t->scene, tc->obedit, NULL, 1) != -1) {
int totleft = -1;
- if (modifiers_isCorrectableDeformed(t->scene, tc->obedit)) {
+ if (BKE_modifiers_is_correctable_deformed(t->scene, tc->obedit)) {
BKE_scene_graph_evaluated_ensure(t->depsgraph, CTX_data_main(t->context));
/* Use evaluated state because we need b-bone cache. */
@@ -809,21 +827,19 @@ void createTransEditVerts(TransInfo *t)
continue;
}
if (prop_mode || BM_elem_flag_test(eve, BM_ELEM_SELECT)) {
- struct TransIslandData *v_island = NULL;
float *bweight = (cd_vert_bweight_offset != -1) ?
BM_ELEM_CD_GET_VOID_P(eve, cd_vert_bweight_offset) :
NULL;
- if (island_info) {
+ int island_index = -1;
+ if (island_data.island_vert_map) {
const int connected_index = (dists_index && dists_index[a] != -1) ? dists_index[a] : a;
- v_island = (island_vert_map[connected_index] != -1) ?
- &island_info[island_vert_map[connected_index]] :
- NULL;
+ island_index = island_data.island_vert_map[connected_index];
}
/* Do not use the island center in case we are using islands
* only to get axis for snap/rotate to normal... */
- VertsToTransData(t, tob, tx, em, eve, bweight, v_island, is_snap_rotate);
+ VertsToTransData(t, tob, tx, em, eve, bweight, &island_data, island_index, is_snap_rotate);
if (tx) {
tx++;
}
@@ -889,9 +905,16 @@ void createTransEditVerts(TransInfo *t)
}
}
- if (island_info) {
- MEM_freeN(island_info);
- MEM_freeN(island_vert_map);
+ if (island_data.center) {
+ MEM_freeN(island_data.center);
+ }
+
+ if (island_data.axismtx) {
+ MEM_freeN(island_data.axismtx);
+ }
+
+ if (island_data.island_vert_map) {
+ MEM_freeN(island_data.island_vert_map);
}
cleanup:
@@ -1427,7 +1450,6 @@ static void UVsToTransData(const float aspect[2],
void createTransUVs(bContext *C, TransInfo *t)
{
SpaceImage *sima = CTX_wm_space_image(C);
- Image *ima = CTX_data_edit_image(C);
Scene *scene = t->scene;
ToolSettings *ts = CTX_data_tool_settings(C);
@@ -1477,7 +1499,7 @@ void createTransUVs(bContext *C, TransInfo *t)
BM_ITER_MESH (efa, &iter, em->bm, BM_FACES_OF_MESH) {
BMLoop *l;
- if (!uvedit_face_visible_test(scene, tc->obedit, ima, efa)) {
+ if (!uvedit_face_visible_test(scene, efa)) {
BM_elem_flag_disable(efa, BM_ELEM_TAG);
continue;
}
@@ -1608,7 +1630,7 @@ void createTransUVs(bContext *C, TransInfo *t)
void flushTransUVs(TransInfo *t)
{
- SpaceImage *sima = t->sa->spacedata.first;
+ SpaceImage *sima = t->area->spacedata.first;
const bool use_pixel_snap = ((sima->pixel_snap_mode != SI_PIXEL_SNAP_DISABLED) &&
(t->state != TRANS_CANCEL));
diff --git a/source/blender/editors/transform/transform_convert_nla.c b/source/blender/editors/transform/transform_convert_nla.c
index 580a8d79d7a..2978c36b15f 100644
--- a/source/blender/editors/transform/transform_convert_nla.c
+++ b/source/blender/editors/transform/transform_convert_nla.c
@@ -71,10 +71,7 @@ void createTransNlaData(bContext *C, TransInfo *t)
/* which side of the current frame should be allowed */
if (t->mode == TFM_TIME_EXTEND) {
- /* only side on which center is gets transformed */
- float center[2];
- transform_convert_center_global_v2(t, center);
- t->frame_side = (center[0] > CFRA) ? 'R' : 'L';
+ t->frame_side = transform_convert_frame_side_dir_get(t, (float)CFRA);
}
else {
/* normal transform - both sides of current frame are considered */
diff --git a/source/blender/editors/transform/transform_convert_node.c b/source/blender/editors/transform/transform_convert_node.c
index ee4aa053444..d783bfdf40e 100644
--- a/source/blender/editors/transform/transform_convert_node.c
+++ b/source/blender/editors/transform/transform_convert_node.c
@@ -109,7 +109,7 @@ void createTransNodeData(bContext *UNUSED(C), TransInfo *t)
const float dpi_fac = UI_DPI_FAC;
TransData *td;
TransData2D *td2d;
- SpaceNode *snode = t->sa->spacedata.first;
+ SpaceNode *snode = t->area->spacedata.first;
bNode *node;
TransDataContainer *tc = TRANS_DATA_CONTAINER_FIRST_SINGLE(t);
@@ -188,7 +188,7 @@ void flushTransNodes(TransInfo *t)
/* handle intersection with noodles */
if (tc->data_len == 1) {
- ED_node_link_intersect_test(t->sa, 1);
+ ED_node_link_intersect_test(t->area, 1);
}
}
}
diff --git a/source/blender/editors/transform/transform_convert_object.c b/source/blender/editors/transform/transform_convert_object.c
index 4973b1cb268..8deba0f7ad0 100644
--- a/source/blender/editors/transform/transform_convert_object.c
+++ b/source/blender/editors/transform/transform_convert_object.c
@@ -197,7 +197,7 @@ static void ObjectToTransData(TransInfo *t, TransData *td, Object *ob)
/* NOTE: This is not really following copy-on-write design and we should not
* be re-evaluating the evaluated object. But as the comment above mentioned
* this is part of a hack.
- * More proper solution would be to make a shallow copy of the object and
+ * More proper solution would be to make a shallow copy of the object and
* evaluate that, and access matrix of that evaluated copy of the object.
* Might be more tricky than it sounds, if some logic later on accesses the
* object matrix via td->ob->obmat. */
@@ -290,7 +290,7 @@ 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) {
+ LISTBASE_FOREACH (Base *, base, &view_layer->object_bases) {
base->object->id.tag &= ~LIB_TAG_DOIT;
}
}
@@ -324,7 +324,7 @@ static void trans_object_base_deps_flag_finish(const TransInfo *t, ViewLayer *vi
{
if ((t->options & CTX_OBMODE_XFORM_OBDATA) == 0) {
- for (Base *base = view_layer->object_bases.first; base; base = base->next) {
+ LISTBASE_FOREACH (Base *, base, &view_layer->object_bases) {
if (base->object->id.tag & LIB_TAG_DOIT) {
base->flag_legacy |= BA_SNAP_FIX_DEPS_FIASCO;
}
@@ -355,7 +355,7 @@ static void set_trans_object_base_flags(TransInfo *t)
/* 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) {
+ LISTBASE_FOREACH (Base *, base, &view_layer->object_bases) {
base->flag_legacy &= ~(BA_WAS_SEL | BA_TRANSFORM_LOCKED_IN_PLACE);
if (BASE_SELECTED_EDITABLE(v3d, base)) {
Object *ob = base->object;
@@ -422,7 +422,7 @@ static int count_proportional_objects(TransInfo *t)
if (!((t->around == V3D_AROUND_LOCAL_ORIGINS) &&
(t->mode == TFM_ROTATION || t->mode == TFM_TRACKBALL))) {
/* Mark all parents. */
- for (Base *base = view_layer->object_bases.first; base; base = base->next) {
+ LISTBASE_FOREACH (Base *, base, &view_layer->object_bases) {
if (BASE_SELECTED_EDITABLE(v3d, base) && BASE_SELECTABLE(v3d, base)) {
Object *parent = base->object->parent;
/* flag all parents */
@@ -433,7 +433,7 @@ static int count_proportional_objects(TransInfo *t)
}
}
/* Mark all children. */
- for (Base *base = view_layer->object_bases.first; base; base = base->next) {
+ LISTBASE_FOREACH (Base *, base, &view_layer->object_bases) {
/* 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 &&
@@ -443,7 +443,7 @@ static int count_proportional_objects(TransInfo *t)
}
}
/* Flush changed flags to all dependencies. */
- for (Base *base = view_layer->object_bases.first; base; base = base->next) {
+ LISTBASE_FOREACH (Base *, base, &view_layer->object_bases) {
Object *ob = base->object;
/* If base is not selected, not a parent of selection or not a child of
* selection and it is editable and selectable.
@@ -592,7 +592,7 @@ void createTransObject(bContext *C, TransInfo *t)
ViewLayer *view_layer = t->view_layer;
View3D *v3d = t->view;
- for (Base *base = view_layer->object_bases.first; base; base = base->next) {
+ LISTBASE_FOREACH (Base *, base, &view_layer->object_bases) {
Object *ob = base->object;
/* if base is not selected, not a parent of selection
@@ -639,7 +639,7 @@ void createTransObject(bContext *C, TransInfo *t)
ViewLayer *view_layer = t->view_layer;
- for (Base *base = view_layer->object_bases.first; base; base = base->next) {
+ LISTBASE_FOREACH (Base *, base, &view_layer->object_bases) {
Object *ob = base->object;
if (ob->parent != NULL) {
if (ob->parent && !BLI_gset_haskey(objects_in_transdata, ob->parent) &&
@@ -669,7 +669,7 @@ void createTransObject(bContext *C, TransInfo *t)
}
}
- for (Base *base = view_layer->object_bases.first; base; base = base->next) {
+ LISTBASE_FOREACH (Base *, base, &view_layer->object_bases) {
Object *ob = base->object;
if (BASE_XFORM_INDIRECT(base) || BLI_gset_haskey(objects_in_transdata, ob)) {
diff --git a/source/blender/editors/transform/transform_convert_sequencer.c b/source/blender/editors/transform/transform_convert_sequencer.c
index f2d0f4dfc43..0175bf6e673 100644
--- a/source/blender/editors/transform/transform_convert_sequencer.c
+++ b/source/blender/editors/transform/transform_convert_sequencer.c
@@ -31,6 +31,8 @@
#include "BKE_report.h"
#include "BKE_sequencer.h"
+#include "UI_view2d.h"
+
#include "transform.h"
#include "transform_convert.h"
@@ -379,7 +381,7 @@ static void freeSeqData(TransInfo *t, TransDataContainer *tc, TransCustomData *c
}
if (overlap) {
- const bool use_sync_markers = (((SpaceSeq *)t->sa->spacedata.first)->flag &
+ const bool use_sync_markers = (((SpaceSeq *)t->area->spacedata.first)->flag &
SEQ_MARKER_TRANS) != 0;
ListBase *markers = &t->scene->markers;
@@ -541,10 +543,7 @@ void createTransSeqData(TransInfo *t)
}
tc->custom.type.free_cb = freeSeqData;
- /* only side on which center is gets transformed */
- int center[2];
- transform_convert_center_global_v2_int(t, center);
- t->frame_side = (center[0] > CFRA) ? 'R' : 'L';
+ t->frame_side = transform_convert_frame_side_dir_get(t, (float)CFRA);
#ifdef XXX_DURIAN_ANIM_TX_HACK
{
@@ -586,9 +585,12 @@ void createTransSeqData(TransInfo *t)
SeqToTransData_Recursive(t, ed->seqbasep, td, td2d, tdsq);
SeqTransDataBounds(t, ed->seqbasep, ts);
- /* set the snap mode based on how close the mouse is at the end/start points */
- if (abs(center[0] - ts->max) > abs(center[0] - ts->min)) {
- ts->snap_left = true;
+ if (t->flag & T_MODAL) {
+ /* set the snap mode based on how close the mouse is at the end/start points */
+ int xmouse = (int)UI_view2d_region_to_view_x((View2D *)t->view, t->mouse.imval[0]);
+ if (abs(xmouse - ts->max) > abs(xmouse - ts->min)) {
+ ts->snap_left = true;
+ }
}
#undef XXX_DURIAN_ANIM_TX_HACK
diff --git a/source/blender/editors/transform/transform_convert_tracking.c b/source/blender/editors/transform/transform_convert_tracking.c
index a8bde661342..6704567a76b 100644
--- a/source/blender/editors/transform/transform_convert_tracking.c
+++ b/source/blender/editors/transform/transform_convert_tracking.c
@@ -549,7 +549,7 @@ void createTransTrackingData(bContext *C, TransInfo *t)
void cancelTransTracking(TransInfo *t)
{
TransDataContainer *tc = TRANS_DATA_CONTAINER_FIRST_SINGLE(t);
- SpaceClip *sc = t->sa->spacedata.first;
+ SpaceClip *sc = t->area->spacedata.first;
int i, framenr = ED_space_clip_get_clip_frame_number(sc);
TransDataTracking *tdt_array = tc->custom.type.data;
diff --git a/source/blender/editors/transform/transform_draw_cursors.c b/source/blender/editors/transform/transform_draw_cursors.c
index f3105c8eb36..95ca5ae0c30 100644
--- a/source/blender/editors/transform/transform_draw_cursors.c
+++ b/source/blender/editors/transform/transform_draw_cursors.c
@@ -313,7 +313,7 @@ void transform_draw_cursor_draw(bContext *UNUSED(C), int x, int y, void *customd
break;
}
case HLP_TRACKBALL: {
- unsigned char col[3], col2[3];
+ uchar col[3], col2[3];
UI_GetThemeColor3ubv(TH_GRID, col);
GPU_matrix_translate_3fv(mval);
diff --git a/source/blender/editors/transform/transform_generics.c b/source/blender/editors/transform/transform_generics.c
index 7a787b77a62..6de962a3ed1 100644
--- a/source/blender/editors/transform/transform_generics.c
+++ b/source/blender/editors/transform/transform_generics.c
@@ -64,7 +64,7 @@
#include "BIK_api.h"
#include "BKE_action.h"
-#include "BKE_animsys.h"
+#include "BKE_anim_data.h"
#include "BKE_armature.h"
#include "BKE_context.h"
#include "BKE_curve.h"
@@ -174,9 +174,6 @@ static void clipMirrorModifier(TransInfo *t)
int clip;
float loc[3], iloc[3];
- if (td->flag & TD_NOACTION) {
- break;
- }
if (td->loc == NULL) {
break;
}
@@ -337,7 +334,7 @@ static void animrecord_check_state(Scene *scene, ID *id, wmTimer *animtimer)
static bool fcu_test_selected(FCurve *fcu)
{
BezTriple *bezt = fcu->bezt;
- unsigned int i;
+ uint i;
if (bezt == NULL) { /* ignore baked */
return 0;
@@ -356,7 +353,7 @@ static bool fcu_test_selected(FCurve *fcu)
static void recalcData_actedit(TransInfo *t)
{
ViewLayer *view_layer = t->view_layer;
- SpaceAction *saction = (SpaceAction *)t->sa->spacedata.first;
+ SpaceAction *saction = (SpaceAction *)t->area->spacedata.first;
bAnimContext ac = {NULL};
ListBase anim_data = {NULL, NULL};
@@ -369,10 +366,10 @@ static void recalcData_actedit(TransInfo *t)
ac.scene = t->scene;
ac.view_layer = t->view_layer;
ac.obact = OBACT(view_layer);
- ac.sa = t->sa;
+ ac.area = t->area;
ac.region = t->region;
- ac.sl = (t->sa) ? t->sa->spacedata.first : NULL;
- ac.spacetype = (t->sa) ? t->sa->spacetype : 0;
+ ac.sl = (t->area) ? t->area->spacedata.first : NULL;
+ ac.spacetype = (t->area) ? t->area->spacetype : 0;
ac.regiontype = (t->region) ? t->region->regiontype : 0;
ANIM_animdata_context_getdata(&ac);
@@ -406,7 +403,7 @@ static void recalcData_actedit(TransInfo *t)
/* helper for recalcData() - for Graph Editor transforms */
static void recalcData_graphedit(TransInfo *t)
{
- SpaceGraph *sipo = (SpaceGraph *)t->sa->spacedata.first;
+ SpaceGraph *sipo = (SpaceGraph *)t->area->spacedata.first;
ViewLayer *view_layer = t->view_layer;
ListBase anim_data = {NULL, NULL};
@@ -422,10 +419,10 @@ static void recalcData_graphedit(TransInfo *t)
ac.scene = t->scene;
ac.view_layer = t->view_layer;
ac.obact = OBACT(view_layer);
- ac.sa = t->sa;
+ ac.area = t->area;
ac.region = t->region;
- ac.sl = (t->sa) ? t->sa->spacedata.first : NULL;
- ac.spacetype = (t->sa) ? t->sa->spacetype : 0;
+ ac.sl = (t->area) ? t->area->spacedata.first : NULL;
+ ac.spacetype = (t->area) ? t->area->spacetype : 0;
ac.regiontype = (t->region) ? t->region->regiontype : 0;
ANIM_animdata_context_getdata(&ac);
@@ -474,7 +471,7 @@ static void recalcData_graphedit(TransInfo *t)
/* helper for recalcData() - for NLA Editor transforms */
static void recalcData_nla(TransInfo *t)
{
- SpaceNla *snla = (SpaceNla *)t->sa->spacedata.first;
+ SpaceNla *snla = (SpaceNla *)t->area->spacedata.first;
Scene *scene = t->scene;
double secf = FPS;
int i;
@@ -718,7 +715,7 @@ static void recalcData_image(TransInfo *t)
flushTransPaintCurve(t);
}
else if ((t->flag & T_EDIT) && t->obedit_type == OB_MESH) {
- SpaceImage *sima = t->sa->spacedata.first;
+ SpaceImage *sima = t->area->spacedata.first;
flushTransUVs(t);
if (sima->flag & SI_LIVE_UNWRAP) {
@@ -736,7 +733,7 @@ static void recalcData_image(TransInfo *t)
/* helper for recalcData() - for Movie Clip transforms */
static void recalcData_spaceclip(TransInfo *t)
{
- SpaceClip *sc = t->sa->spacedata.first;
+ SpaceClip *sc = t->area->spacedata.first;
if (ED_space_clip_check_show_trackedit(sc)) {
MovieClip *clip = ED_space_clip_get_clip(sc);
@@ -1068,11 +1065,6 @@ static void recalcData_objects(TransInfo *t)
for (int i = 0; i < tc->data_len; i++, td++) {
Object *ob = td->ob;
-
- if (td->flag & TD_NOACTION) {
- break;
- }
-
if (td->flag & TD_SKIP) {
continue;
}
@@ -1187,7 +1179,6 @@ void recalcData(TransInfo *t)
flushTransPaintCurve(t);
}
else if (t->options & CTX_GPENCIL_STROKES) {
- /* set recalc triangle cache flag */
recalcData_gpencil_strokes(t);
}
else if (t->options & CTX_SCULPT) {
@@ -1222,7 +1213,7 @@ void recalcData(TransInfo *t)
void drawLine(TransInfo *t, const float center[3], const float dir[3], char axis, short options)
{
float v1[3], v2[3], v3[3];
- unsigned char col[3], col2[3];
+ uchar col[3], col2[3];
if (t->spacetype == SPACE_VIEW3D) {
View3D *v3d = t->view;
@@ -1375,15 +1366,16 @@ void initTransInfo(bContext *C, TransInfo *t, wmOperator *op, const wmEvent *eve
const eObjectMode object_mode = obact ? obact->mode : OB_MODE_OBJECT;
ToolSettings *ts = CTX_data_tool_settings(C);
ARegion *region = CTX_wm_region(C);
- ScrArea *sa = CTX_wm_area(C);
+ ScrArea *area = CTX_wm_area(C);
bGPdata *gpd = CTX_data_gpencil_data(C);
PropertyRNA *prop;
+ t->mbus = CTX_wm_message_bus(C);
t->depsgraph = CTX_data_depsgraph_pointer(C);
t->scene = sce;
t->view_layer = view_layer;
- t->sa = sa;
+ t->area = area;
t->region = region;
t->settings = ts;
t->reports = op ? op->reports : NULL;
@@ -1431,11 +1423,6 @@ void initTransInfo(bContext *C, TransInfo *t, wmOperator *op, const wmEvent *eve
unit_m3(t->mat);
- unit_m3(t->orient_matrix);
- negate_m3(t->orient_matrix);
- /* Leave 't->orient_matrix_is_set' to false,
- * so we overwrite it when we have a useful value. */
-
/* Default to rotate on the Z axis. */
t->orient_axis = 2;
t->orient_axis_ortho = 1;
@@ -1465,17 +1452,17 @@ void initTransInfo(bContext *C, TransInfo *t, wmOperator *op, const wmEvent *eve
}
/* Assign the space type, some exceptions for running in different mode */
- if (sa == NULL) {
+ if (area == NULL) {
/* background mode */
t->spacetype = SPACE_EMPTY;
}
- else if ((region == NULL) && (sa->spacetype == SPACE_VIEW3D)) {
+ else if ((region == NULL) && (area->spacetype == SPACE_VIEW3D)) {
/* running in the text editor */
t->spacetype = SPACE_EMPTY;
}
else {
/* normal operation */
- t->spacetype = sa->spacetype;
+ t->spacetype = area->spacetype;
}
/* handle T_ALT_TRANSFORM initialization, we may use for different operators */
@@ -1491,7 +1478,7 @@ void initTransInfo(bContext *C, TransInfo *t, wmOperator *op, const wmEvent *eve
}
if (t->spacetype == SPACE_VIEW3D) {
- View3D *v3d = sa->spacedata.first;
+ View3D *v3d = area->spacedata.first;
bScreen *animscreen = ED_screen_animation_playing(CTX_wm_manager(C));
t->view = v3d;
@@ -1513,22 +1500,6 @@ void initTransInfo(bContext *C, TransInfo *t, wmOperator *op, const wmEvent *eve
t->around = V3D_AROUND_CURSOR;
}
- TransformOrientationSlot *orient_slot = &t->scene->orientation_slots[SCE_ORIENT_DEFAULT];
- t->orientation.unset = V3D_ORIENT_GLOBAL;
- t->orientation.user = orient_slot->type;
- t->orientation.custom = BKE_scene_transform_orientation_find(t->scene,
- orient_slot->index_custom);
-
- t->orientation.index = 0;
- ARRAY_SET_ITEMS(t->orientation.types, &t->orientation.user, NULL);
-
- /* Make second orientation local if both are global. */
- if (t->orientation.user == V3D_ORIENT_GLOBAL) {
- t->orientation.user_alt = V3D_ORIENT_LOCAL;
- t->orientation.types[0] = &t->orientation.user_alt;
- SWAP(short *, t->orientation.types[0], t->orientation.types[1]);
- }
-
/* exceptional case */
if (t->around == V3D_AROUND_LOCAL_ORIGINS) {
if (ELEM(t->mode, TFM_ROTATION, TFM_RESIZE, TFM_TRACKBALL)) {
@@ -1564,7 +1535,7 @@ void initTransInfo(bContext *C, TransInfo *t, wmOperator *op, const wmEvent *eve
}
}
else if (t->spacetype == SPACE_IMAGE) {
- SpaceImage *sima = sa->spacedata.first;
+ SpaceImage *sima = area->spacedata.first;
// XXX for now, get View2D from the active region
t->view = &region->v2d;
t->around = sima->around;
@@ -1589,12 +1560,12 @@ void initTransInfo(bContext *C, TransInfo *t, wmOperator *op, const wmEvent *eve
t->around = V3D_AROUND_CENTER_BOUNDS;
}
else if (t->spacetype == SPACE_GRAPH) {
- SpaceGraph *sipo = sa->spacedata.first;
+ SpaceGraph *sipo = area->spacedata.first;
t->view = &region->v2d;
t->around = sipo->around;
}
else if (t->spacetype == SPACE_CLIP) {
- SpaceClip *sclip = sa->spacedata.first;
+ SpaceClip *sclip = area->spacedata.first;
t->view = &region->v2d;
t->around = sclip->around;
@@ -1617,48 +1588,152 @@ void initTransInfo(bContext *C, TransInfo *t, wmOperator *op, const wmEvent *eve
t->around = V3D_AROUND_CENTER_BOUNDS;
}
- if (op && (prop = RNA_struct_find_property(op->ptr, "orient_axis"))) {
- t->orient_axis = RNA_property_enum_get(op->ptr, prop);
- }
- if (op && (prop = RNA_struct_find_property(op->ptr, "orient_axis_ortho"))) {
- t->orient_axis_ortho = RNA_property_enum_get(op->ptr, prop);
- }
+ BLI_assert(is_zero_v4(t->values_modal_offset));
+ bool t_values_set_is_array = false;
+ if (op && (prop = RNA_struct_find_property(op->ptr, "value")) &&
+ RNA_property_is_set(op->ptr, prop)) {
+ float values[4] = {0}; /* in case value isn't length 4, avoid uninitialized memory */
+ if (RNA_property_array_check(prop)) {
+ RNA_float_get_array(op->ptr, "value", values);
+ t_values_set_is_array = true;
+ }
+ else {
+ values[0] = RNA_float_get(op->ptr, "value");
+ }
- if (op &&
- ((prop = RNA_struct_find_property(op->ptr, "orient_matrix")) &&
- RNA_property_is_set(op->ptr, prop)) &&
- ((t->flag & T_MODAL) ||
- /* When using redo, don't use the custom constraint matrix
- * if the user selects a different orientation. */
- (RNA_enum_get(op->ptr, "orient_type") == RNA_enum_get(op->ptr, "orient_matrix_type")))) {
- RNA_property_float_get_array(op->ptr, prop, &t->orient_matrix[0][0]);
- copy_m3_m3(t->spacemtx, t->orient_matrix);
- /* Some transform modes use this to operate on an axis. */
- t->orient_matrix_is_set = true;
- t->orientation.user = V3D_ORIENT_CUSTOM_MATRIX;
- t->orientation.custom = 0;
+ copy_v4_v4(t->values, values);
if (t->flag & T_MODAL) {
- RNA_enum_set(op->ptr, "orient_matrix_type", RNA_enum_get(op->ptr, "orient_type"));
+ /* Run before init functions so 'values_modal_offset' can be applied on mouse input. */
+ copy_v4_v4(t->values_modal_offset, values);
+ }
+ else {
+ copy_v4_v4(t->values, values);
+ t->flag |= T_INPUT_IS_VALUES_FINAL;
}
}
- else if (op && ((prop = RNA_struct_find_property(op->ptr, "orient_type")) &&
- RNA_property_is_set(op->ptr, prop))) {
- short orientation = RNA_property_enum_get(op->ptr, prop);
- TransformOrientation *custom_orientation = NULL;
- if (orientation >= V3D_ORIENT_CUSTOM) {
- if (orientation >= V3D_ORIENT_CUSTOM + BIF_countTransformOrientation(C)) {
- orientation = V3D_ORIENT_GLOBAL;
+ if (op && (prop = RNA_struct_find_property(op->ptr, "constraint_axis"))) {
+ bool constraint_axis[3] = {false, false, false};
+ if (RNA_property_is_set(op->ptr, prop)) {
+ RNA_property_boolean_get_array(op->ptr, prop, constraint_axis);
+ }
+
+ if (t_values_set_is_array && t->flag & T_INPUT_IS_VALUES_FINAL) {
+ /* For operators whose `t->values` is array, set constraint so that the
+ * orientation is more intuitive in the Redo Panel. */
+ for (int i = 3; i--;) {
+ constraint_axis[i] |= t->values[i] != 0.0f;
+ }
+ }
+
+ if (constraint_axis[0] || constraint_axis[1] || constraint_axis[2]) {
+ t->con.mode |= CON_APPLY;
+
+ if (constraint_axis[0]) {
+ t->con.mode |= CON_AXIS0;
+ }
+ if (constraint_axis[1]) {
+ t->con.mode |= CON_AXIS1;
+ }
+ if (constraint_axis[2]) {
+ t->con.mode |= CON_AXIS2;
+ }
+ }
+ }
+
+ {
+ short orient_type_set = -1;
+ short orient_type_matrix_set = -1;
+ short orient_type_scene = V3D_ORIENT_GLOBAL;
+
+ if ((t->spacetype == SPACE_VIEW3D) && (t->region->regiontype == RGN_TYPE_WINDOW)) {
+ TransformOrientationSlot *orient_slot = &t->scene->orientation_slots[SCE_ORIENT_DEFAULT];
+ orient_type_scene = orient_slot->type;
+ if (orient_type_scene == V3D_ORIENT_CUSTOM) {
+ const int index_custom = orient_slot->index_custom;
+ orient_type_scene += index_custom;
+ }
+ }
+
+ short orient_types[3];
+ float custom_matrix[3][3];
+ bool use_orient_axis = false;
+
+ if (op && (prop = RNA_struct_find_property(op->ptr, "orient_axis"))) {
+ t->orient_axis = RNA_property_enum_get(op->ptr, prop);
+ use_orient_axis = true;
+ }
+ if (op && (prop = RNA_struct_find_property(op->ptr, "orient_axis_ortho"))) {
+ t->orient_axis_ortho = RNA_property_enum_get(op->ptr, prop);
+ }
+
+ if (op && ((prop = RNA_struct_find_property(op->ptr, "orient_type")) &&
+ RNA_property_is_set(op->ptr, prop))) {
+ orient_type_set = RNA_property_enum_get(op->ptr, prop);
+ if (orient_type_set >= V3D_ORIENT_CUSTOM) {
+ if (orient_type_set >= V3D_ORIENT_CUSTOM + BIF_countTransformOrientation(C)) {
+ orient_type_set = V3D_ORIENT_GLOBAL;
+ }
+ }
+
+ /* Change the default orientation to be used when redoing. */
+ orient_types[0] = orient_type_set;
+ orient_types[1] = orient_type_set;
+ orient_types[2] = orient_type_scene;
+ }
+ else {
+ if ((t->flag & T_MODAL) && (use_orient_axis || transform_mode_is_changeable(t->mode))) {
+ orient_types[0] = V3D_ORIENT_VIEW;
+ }
+ else {
+ orient_types[0] = orient_type_scene;
+ }
+ orient_types[1] = orient_type_scene;
+ orient_types[2] = orient_type_scene != V3D_ORIENT_GLOBAL ? V3D_ORIENT_GLOBAL :
+ V3D_ORIENT_LOCAL;
+ }
+
+ if (op && ((prop = RNA_struct_find_property(op->ptr, "orient_matrix")) &&
+ RNA_property_is_set(op->ptr, prop))) {
+ RNA_property_float_get_array(op->ptr, prop, &custom_matrix[0][0]);
+
+ if ((prop = RNA_struct_find_property(op->ptr, "orient_matrix_type")) &&
+ RNA_property_is_set(op->ptr, prop)) {
+ orient_type_matrix_set = RNA_property_enum_get(op->ptr, prop);
+ }
+ else if (orient_type_set != -1) {
+ orient_type_matrix_set = orient_type_set;
}
else {
- custom_orientation = BKE_scene_transform_orientation_find(t->scene,
- orientation - V3D_ORIENT_CUSTOM);
- orientation = V3D_ORIENT_CUSTOM;
+ orient_type_matrix_set = orient_type_set = V3D_ORIENT_GLOBAL;
+ }
+
+ if (orient_type_matrix_set == orient_type_set) {
+ /* Constraints are forced to use the custom matrix when redoing. */
+ orient_types[0] = V3D_ORIENT_CUSTOM_MATRIX;
}
}
- t->orientation.user = orientation;
- t->orientation.custom = custom_orientation;
+ if (t->con.mode & CON_APPLY) {
+ t->orient_curr = 1;
+ }
+
+ /* For efficiency, avoid calculating the same orientation twice. */
+ for (int i = 1; i < 3; i++) {
+ t->orient[i].type = transform_orientation_matrix_get(
+ C, t, orient_types[i], custom_matrix, t->orient[i].matrix);
+ }
+
+ if (orient_types[0] != orient_types[1]) {
+ t->orient[0].type = transform_orientation_matrix_get(
+ C, t, orient_types[0], custom_matrix, t->orient[0].matrix);
+ }
+ else {
+ memcpy(&t->orient[0], &t->orient[1], sizeof(t->orient[0]));
+ }
+
+ const char *spacename = transform_orientations_spacename_get(t, orient_types[0]);
+ BLI_strncpy(t->spacename, spacename, sizeof(t->spacename));
}
if (op && ((prop = RNA_struct_find_property(op->ptr, "release_confirm")) &&
@@ -1763,6 +1838,24 @@ void initTransInfo(bContext *C, TransInfo *t, wmOperator *op, const wmEvent *eve
t->options |= CTX_NO_PET;
}
+ if (t->obedit_type == OB_MESH) {
+ if (op && (prop = RNA_struct_find_property(op->ptr, "use_automerge_and_split")) &&
+ RNA_property_is_set(op->ptr, prop)) {
+ if (RNA_property_boolean_get(op->ptr, prop)) {
+ t->flag |= T_AUTOMERGE | T_AUTOSPLIT;
+ }
+ }
+ else {
+ char automerge = t->scene->toolsettings->automerge;
+ if (automerge & AUTO_MERGE) {
+ t->flag |= T_AUTOMERGE;
+ if (automerge & AUTO_MERGE_AND_SPLIT) {
+ t->flag |= T_AUTOSPLIT;
+ }
+ }
+ }
+ }
+
// Mirror is not supported with PET, turn it off.
#if 0
if (t->flag & T_PROP_EDIT) {
@@ -1833,7 +1926,7 @@ void postTrans(bContext *C, TransInfo *t)
ED_region_draw_cb_exit(t->region->type, t->draw_handle_pixel);
}
if (t->draw_handle_cursor) {
- WM_paint_cursor_end(CTX_wm_manager(C), t->draw_handle_cursor);
+ WM_paint_cursor_end(t->draw_handle_cursor);
}
if (t->flag & T_MODAL_CURSOR_SET) {
@@ -1876,14 +1969,14 @@ void postTrans(bContext *C, TransInfo *t)
/* pass */
}
else {
- SpaceImage *sima = t->sa->spacedata.first;
+ SpaceImage *sima = t->area->spacedata.first;
if (sima->flag & SI_LIVE_UNWRAP) {
ED_uvedit_live_unwrap_end(t->state == TRANS_CANCEL);
}
}
}
else if (t->spacetype == SPACE_VIEW3D) {
- View3D *v3d = t->sa->spacedata.first;
+ View3D *v3d = t->area->spacedata.first;
/* restore gizmo */
if (t->flag & T_MODAL) {
v3d->gizmo_flag = t->gizmo_flag;
@@ -2023,11 +2116,11 @@ void calculateCenterCursor2D(TransInfo *t, float r_center[2])
const float *cursor = NULL;
if (t->spacetype == SPACE_IMAGE) {
- SpaceImage *sima = (SpaceImage *)t->sa->spacedata.first;
+ SpaceImage *sima = (SpaceImage *)t->area->spacedata.first;
cursor = sima->cursor;
}
else if (t->spacetype == SPACE_CLIP) {
- SpaceClip *space_clip = (SpaceClip *)t->sa->spacedata.first;
+ SpaceClip *space_clip = (SpaceClip *)t->area->spacedata.first;
cursor = space_clip->cursor;
}
@@ -2036,11 +2129,11 @@ void calculateCenterCursor2D(TransInfo *t, float r_center[2])
float co[2];
if (t->spacetype == SPACE_IMAGE) {
- SpaceImage *sima = (SpaceImage *)t->sa->spacedata.first;
+ SpaceImage *sima = (SpaceImage *)t->area->spacedata.first;
BKE_mask_coord_from_image(sima->image, &sima->iuser, co, cursor);
}
else if (t->spacetype == SPACE_CLIP) {
- SpaceClip *space_clip = (SpaceClip *)t->sa->spacedata.first;
+ SpaceClip *space_clip = (SpaceClip *)t->area->spacedata.first;
BKE_mask_coord_from_movieclip(space_clip->clip, &space_clip->user, co, cursor);
}
else {
@@ -2065,7 +2158,7 @@ void calculateCenterCursor2D(TransInfo *t, float r_center[2])
void calculateCenterCursorGraph2D(TransInfo *t, float r_center[2])
{
- SpaceGraph *sipo = (SpaceGraph *)t->sa->spacedata.first;
+ SpaceGraph *sipo = (SpaceGraph *)t->area->spacedata.first;
Scene *scene = t->scene;
/* cursor is combination of current frame, and graph-editor cursor value */
@@ -2312,19 +2405,11 @@ void calculatePropRatio(TransInfo *t)
}
else if ((connected && (td->flag & TD_NOTCONNECTED || td->dist > t->prop_size)) ||
(connected == 0 && td->rdist > t->prop_size)) {
- /*
- * The elements are sorted according to their dist member in the array,
- * that means we can stop when it finds one element outside of the propsize.
- * do not set 'td->flag |= TD_NOACTION', the prop circle is being changed.
- */
-
td->factor = 0.0f;
restoreElement(td);
}
else {
/* Use rdist for falloff calculations, it is the real distance */
- td->flag &= ~TD_NOACTION;
-
if (connected) {
dist = (t->prop_size - td->dist) / t->prop_size;
}
diff --git a/source/blender/editors/transform/transform_gizmo_2d.c b/source/blender/editors/transform/transform_gizmo_2d.c
index e85b9f0bee1..c63e90ac2b7 100644
--- a/source/blender/editors/transform/transform_gizmo_2d.c
+++ b/source/blender/editors/transform/transform_gizmo_2d.c
@@ -68,10 +68,10 @@ static bool gizmo2d_generic_poll(const bContext *C, wmGizmoGroupType *gzgt)
return false;
}
- ScrArea *sa = CTX_wm_area(C);
- switch (sa->spacetype) {
+ ScrArea *area = CTX_wm_area(C);
+ switch (area->spacetype) {
case SPACE_IMAGE: {
- SpaceImage *sima = sa->spacedata.first;
+ SpaceImage *sima = area->spacedata.first;
Object *obedit = CTX_data_edit_object(C);
if (!ED_space_image_show_uvedit(sima, obedit)) {
return false;
@@ -86,7 +86,7 @@ static void gizmo2d_pivot_point_message_subscribe(struct wmGizmoGroup *gzgroup,
struct wmMsgBus *mbus,
/* Additional args. */
bScreen *screen,
- ScrArea *sa,
+ ScrArea *area,
ARegion *region)
{
wmMsgSubscribeValue msg_sub_value_gz_tag_refresh = {
@@ -95,9 +95,9 @@ static void gizmo2d_pivot_point_message_subscribe(struct wmGizmoGroup *gzgroup,
.notify = WM_gizmo_do_msg_notify_tag_refresh,
};
- switch (sa->spacetype) {
+ switch (area->spacetype) {
case SPACE_IMAGE: {
- SpaceImage *sima = sa->spacedata.first;
+ SpaceImage *sima = area->spacedata.first;
PointerRNA ptr;
RNA_pointer_create(&screen->id, &RNA_SpaceImageEditor, sima, &ptr);
{
@@ -214,17 +214,15 @@ static bool gizmo2d_calc_bounds(const bContext *C, float *r_center, float *r_min
r_max = max_buf;
}
- ScrArea *sa = CTX_wm_area(C);
+ ScrArea *area = CTX_wm_area(C);
bool changed = false;
- if (sa->spacetype == SPACE_IMAGE) {
- SpaceImage *sima = sa->spacedata.first;
+ if (area->spacetype == SPACE_IMAGE) {
Scene *scene = CTX_data_scene(C);
ViewLayer *view_layer = CTX_data_view_layer(C);
- Image *ima = ED_space_image(sima);
uint objects_len = 0;
Object **objects = BKE_view_layer_array_from_objects_in_edit_mode_unique_data_with_uvs(
view_layer, NULL, &objects_len);
- if (ED_uvedit_minmax_multi(scene, ima, objects, objects_len, r_min, r_max)) {
+ if (ED_uvedit_minmax_multi(scene, objects, objects_len, r_min, r_max)) {
changed = true;
}
MEM_freeN(objects);
@@ -241,11 +239,11 @@ static bool gizmo2d_calc_bounds(const bContext *C, float *r_center, float *r_min
static bool gizmo2d_calc_center(const bContext *C, float r_center[2])
{
- ScrArea *sa = CTX_wm_area(C);
+ ScrArea *area = CTX_wm_area(C);
bool has_select = false;
zero_v2(r_center);
- if (sa->spacetype == SPACE_IMAGE) {
- SpaceImage *sima = sa->spacedata.first;
+ if (area->spacetype == SPACE_IMAGE) {
+ SpaceImage *sima = area->spacedata.first;
Scene *scene = CTX_data_scene(C);
ViewLayer *view_layer = CTX_data_view_layer(C);
ED_uvedit_center_from_pivot_ex(sima, scene, view_layer, r_center, sima->around, &has_select);
@@ -509,9 +507,9 @@ static void gizmo2d_xform_no_cage_message_subscribe(const struct bContext *C,
struct wmMsgBus *mbus)
{
bScreen *screen = CTX_wm_screen(C);
- ScrArea *sa = CTX_wm_area(C);
+ ScrArea *area = CTX_wm_area(C);
ARegion *region = CTX_wm_region(C);
- gizmo2d_pivot_point_message_subscribe(gzgroup, mbus, screen, sa, region);
+ gizmo2d_pivot_point_message_subscribe(gzgroup, mbus, screen, area, region);
}
void ED_widgetgroup_gizmo2d_xform_callbacks_set(wmGizmoGroupType *gzgt)
@@ -671,9 +669,9 @@ static void gizmo2d_resize_message_subscribe(const struct bContext *C,
struct wmMsgBus *mbus)
{
bScreen *screen = CTX_wm_screen(C);
- ScrArea *sa = CTX_wm_area(C);
+ ScrArea *area = CTX_wm_area(C);
ARegion *region = CTX_wm_region(C);
- gizmo2d_pivot_point_message_subscribe(gzgroup, mbus, screen, sa, region);
+ gizmo2d_pivot_point_message_subscribe(gzgroup, mbus, screen, area, region);
}
void ED_widgetgroup_gizmo2d_resize_callbacks_set(wmGizmoGroupType *gzgt)
@@ -791,9 +789,9 @@ static void gizmo2d_rotate_message_subscribe(const struct bContext *C,
struct wmMsgBus *mbus)
{
bScreen *screen = CTX_wm_screen(C);
- ScrArea *sa = CTX_wm_area(C);
+ ScrArea *area = CTX_wm_area(C);
ARegion *region = CTX_wm_region(C);
- gizmo2d_pivot_point_message_subscribe(gzgroup, mbus, screen, sa, region);
+ gizmo2d_pivot_point_message_subscribe(gzgroup, mbus, screen, area, region);
}
void ED_widgetgroup_gizmo2d_rotate_callbacks_set(wmGizmoGroupType *gzgt)
diff --git a/source/blender/editors/transform/transform_gizmo_3d.c b/source/blender/editors/transform/transform_gizmo_3d.c
index de7b2ec02de..ebc021cd983 100644
--- a/source/blender/editors/transform/transform_gizmo_3d.c
+++ b/source/blender/editors/transform/transform_gizmo_3d.c
@@ -347,7 +347,7 @@ static void gizmo_get_axis_color(const int axis_idx,
if (axis_idx >= MAN_AXIS_RANGE_ROT_START && axis_idx < MAN_AXIS_RANGE_ROT_END) {
/* Never fade rotation rings. */
/* trackball rotation axis is a special case, we only draw a slight overlay */
- alpha_fac = (axis_idx == MAN_AXIS_ROT_T) ? 0.1f : 1.0f;
+ alpha_fac = (axis_idx == MAN_AXIS_ROT_T) ? 0.05f : 1.0f;
}
else {
bool is_plane = false;
@@ -635,113 +635,20 @@ bool gimbal_axis(Object *ob, float gmat[3][3])
return 0;
}
-void ED_transform_calc_orientation_from_type(const bContext *C, float r_mat[3][3])
-{
- ARegion *region = CTX_wm_region(C);
- Scene *scene = CTX_data_scene(C);
- ViewLayer *view_layer = CTX_data_view_layer(C);
- Object *obedit = CTX_data_edit_object(C);
- RegionView3D *rv3d = region->regiondata;
- Object *ob = OBACT(view_layer);
- const short orientation_type = scene->orientation_slots[SCE_ORIENT_DEFAULT].type;
- const short orientation_index_custom = scene->orientation_slots[SCE_ORIENT_DEFAULT].index_custom;
- const int pivot_point = scene->toolsettings->transform_pivot_point;
-
- ED_transform_calc_orientation_from_type_ex(
- C, r_mat, scene, rv3d, ob, obedit, orientation_type, orientation_index_custom, pivot_point);
-}
-
-void ED_transform_calc_orientation_from_type_ex(const bContext *C,
- float r_mat[3][3],
- /* extra args (can be accessed from context) */
- Scene *scene,
- RegionView3D *rv3d,
- Object *ob,
- Object *obedit,
- const short orientation_type,
- int orientation_index_custom,
- const int pivot_point)
-{
- bool ok = false;
-
- switch (orientation_type) {
- case V3D_ORIENT_GLOBAL: {
- break; /* nothing to do */
- }
- case V3D_ORIENT_GIMBAL: {
- if (gimbal_axis(ob, r_mat)) {
- ok = true;
- break;
- }
- /* if not gimbal, fall through to normal */
- ATTR_FALLTHROUGH;
- }
- case V3D_ORIENT_NORMAL: {
- if (obedit || ob->mode & OB_MODE_POSE) {
- ED_getTransformOrientationMatrix(C, r_mat, pivot_point);
- ok = true;
- break;
- }
- /* no break we define 'normal' as 'local' in Object mode */
- ATTR_FALLTHROUGH;
- }
- case V3D_ORIENT_LOCAL: {
- if (ob->mode & OB_MODE_POSE) {
- /* each bone moves on its own local axis, but to avoid confusion,
- * use the active pones axis for display [#33575], this works as expected on a single bone
- * and users who select many bones will understand what's going on and what local means
- * when they start transforming */
- ED_getTransformOrientationMatrix(C, r_mat, pivot_point);
- ok = true;
- break;
- }
- copy_m3_m4(r_mat, ob->obmat);
- normalize_m3(r_mat);
- ok = true;
- break;
- }
- case V3D_ORIENT_VIEW: {
- if (rv3d != NULL) {
- copy_m3_m4(r_mat, rv3d->viewinv);
- normalize_m3(r_mat);
- ok = true;
- }
- break;
- }
- case V3D_ORIENT_CURSOR: {
- BKE_scene_cursor_rot_to_mat3(&scene->cursor, r_mat);
- ok = true;
- break;
- }
- case V3D_ORIENT_CUSTOM: {
- TransformOrientation *custom_orientation = BKE_scene_transform_orientation_find(
- scene, orientation_index_custom);
- if (applyTransformOrientation(custom_orientation, r_mat, NULL)) {
- ok = true;
- }
- break;
- }
- }
-
- if (!ok) {
- unit_m3(r_mat);
- }
-}
-
/* centroid, boundbox, of selection */
/* returns total items selected */
int ED_transform_calc_gizmo_stats(const bContext *C,
const struct TransformCalcParams *params,
struct TransformBounds *tbounds)
{
- ScrArea *sa = CTX_wm_area(C);
+ ScrArea *area = CTX_wm_area(C);
ARegion *region = CTX_wm_region(C);
Scene *scene = CTX_data_scene(C);
/* TODO(sergey): This function is used from operator's modal() and from gizmo's refresh().
* Is it fine to possibly evaluate dependency graph here? */
Depsgraph *depsgraph = CTX_data_expect_evaluated_depsgraph(C);
ViewLayer *view_layer = CTX_data_view_layer(C);
- View3D *v3d = sa->spacedata.first;
+ View3D *v3d = area->spacedata.first;
Object *obedit = CTX_data_edit_object(C);
RegionView3D *rv3d = region->regiondata;
Base *base;
@@ -800,7 +707,7 @@ int ED_transform_calc_gizmo_stats(const bContext *C,
/* calculate difference matrix */
BKE_gpencil_parent_matrix_get(depsgraph, ob, gpl, diff_mat);
- for (bGPDstroke *gps = gpl->actframe->strokes.first; gps; gps = gps->next) {
+ LISTBASE_FOREACH (bGPDstroke *, gps, &gpl->actframe->strokes) {
/* skip strokes that are invalid for current view */
if (ED_gpencil_stroke_can_use(C, gps) == false) {
continue;
@@ -883,7 +790,7 @@ int ED_transform_calc_gizmo_stats(const bContext *C,
if (use_mat_local) {
mul_m4_m4m4(mat_local, obedit->imat, ob_iter->obmat);
}
- for (EditBone *ebo = arm->edbo->first; ebo; ebo = ebo->next) {
+ LISTBASE_FOREACH (EditBone *, ebo, arm->edbo) {
if (EBONE_VISIBLE(arm, ebo)) {
if (ebo->flag & BONE_TIPSEL) {
calc_tw_center_with_matrix(tbounds, ebo->tail, use_mat_local, mat_local);
@@ -927,7 +834,7 @@ int ED_transform_calc_gizmo_stats(const bContext *C,
* if handles are hidden then only check the center points.
* If the center knot is selected then only use this as the center point.
*/
- if ((v3d->overlay.edit_flag & V3D_OVERLAY_EDIT_CU_HANDLES) == 0) {
+ if (v3d->overlay.handle_display == CURVE_HANDLE_NONE) {
if (bezt->f2 & SELECT) {
calc_tw_center_with_matrix(tbounds, bezt->vec[1], use_mat_local, mat_local);
totsel++;
@@ -977,7 +884,7 @@ int ED_transform_calc_gizmo_stats(const bContext *C,
mul_m4_m4m4(mat_local, obedit->imat, ob_iter->obmat);
}
- for (MetaElem *ml = mb->editelems->first; ml; ml = ml->next) {
+ LISTBASE_FOREACH (MetaElem *, ml, mb->editelems) {
if (ml->flag & SELECT) {
calc_tw_center_with_matrix(tbounds, &ml->x, use_mat_local, mat_local);
totsel++;
@@ -1033,7 +940,7 @@ int ED_transform_calc_gizmo_stats(const bContext *C,
/* mislead counting bones... bah. We don't know the gizmo mode, could be mixed */
const int mode = TFM_ROTATION;
- const int totsel_iter = count_set_pose_transflags(
+ const int totsel_iter = transform_convert_pose_transflags_update(
ob_iter, mode, V3D_AROUND_CENTER_BOUNDS, NULL);
if (totsel_iter) {
@@ -1244,7 +1151,7 @@ static void gizmo_xform_message_subscribe(wmGizmoGroup *gzgroup,
struct wmMsgBus *mbus,
Scene *scene,
bScreen *screen,
- ScrArea *sa,
+ ScrArea *area,
ARegion *region,
const void *type_fn)
{
@@ -1334,7 +1241,7 @@ static void gizmo_xform_message_subscribe(wmGizmoGroup *gzgroup,
}
PointerRNA view3d_ptr;
- RNA_pointer_create(&screen->id, &RNA_SpaceView3D, sa->spacedata.first, &view3d_ptr);
+ RNA_pointer_create(&screen->id, &RNA_SpaceView3D, area->spacedata.first, &view3d_ptr);
if (type_fn == VIEW3D_GGT_xform_gizmo) {
GizmoGroup *ggd = gzgroup->customdata;
@@ -1388,21 +1295,21 @@ void drawDial3d(const TransInfo *t)
if (tc->mode & CON_APPLY) {
if (tc->mode & CON_AXIS0) {
axis_idx = MAN_AXIS_ROT_X;
- negate_v3_v3(mat_basis[2], tc->mtx[0]);
+ negate_v3_v3(mat_basis[2], t->spacemtx[0]);
}
else if (tc->mode & CON_AXIS1) {
axis_idx = MAN_AXIS_ROT_Y;
- negate_v3_v3(mat_basis[2], tc->mtx[1]);
+ negate_v3_v3(mat_basis[2], t->spacemtx[1]);
}
else {
BLI_assert((tc->mode & CON_AXIS2) != 0);
axis_idx = MAN_AXIS_ROT_Z;
- negate_v3_v3(mat_basis[2], tc->mtx[2]);
+ negate_v3_v3(mat_basis[2], t->spacemtx[2]);
}
}
else {
axis_idx = MAN_AXIS_ROT_C;
- negate_v3_v3(mat_basis[2], t->orient_matrix[t->orient_axis]);
+ copy_v3_v3(mat_basis[2], t->spacemtx[t->orient_axis]);
scale *= 1.2f;
line_with -= 1.0f;
}
@@ -1701,8 +1608,8 @@ static void WIDGETGROUP_gizmo_setup(const bContext *C, wmGizmoGroup *gzgroup)
gzgroup->customdata = ggd;
{
- ScrArea *sa = CTX_wm_area(C);
- const bToolRef *tref = sa->runtime.tool;
+ ScrArea *area = CTX_wm_area(C);
+ const bToolRef *tref = area->runtime.tool;
ggd->twtype = 0;
if (tref && STREQ(tref->idname, "builtin.move")) {
@@ -1737,8 +1644,8 @@ static void WIDGETGROUP_gizmo_refresh(const bContext *C, wmGizmoGroup *gzgroup)
{
GizmoGroup *ggd = gzgroup->customdata;
Scene *scene = CTX_data_scene(C);
- ScrArea *sa = CTX_wm_area(C);
- View3D *v3d = sa->spacedata.first;
+ ScrArea *area = CTX_wm_area(C);
+ View3D *v3d = area->spacedata.first;
ARegion *region = CTX_wm_region(C);
RegionView3D *rv3d = region->regiondata;
struct TransformBounds tbounds;
@@ -1844,17 +1751,18 @@ static void WIDGETGROUP_gizmo_message_subscribe(const bContext *C,
{
Scene *scene = CTX_data_scene(C);
bScreen *screen = CTX_wm_screen(C);
- ScrArea *sa = CTX_wm_area(C);
+ ScrArea *area = CTX_wm_area(C);
ARegion *region = CTX_wm_region(C);
- gizmo_xform_message_subscribe(gzgroup, mbus, scene, screen, sa, region, VIEW3D_GGT_xform_gizmo);
+ gizmo_xform_message_subscribe(
+ gzgroup, mbus, scene, screen, area, region, VIEW3D_GGT_xform_gizmo);
}
static void WIDGETGROUP_gizmo_draw_prepare(const bContext *C, wmGizmoGroup *gzgroup)
{
GizmoGroup *ggd = gzgroup->customdata;
- // ScrArea *sa = CTX_wm_area(C);
+ // ScrArea *area = CTX_wm_area(C);
ARegion *region = CTX_wm_region(C);
- // View3D *v3d = sa->spacedata.first;
+ // View3D *v3d = area->spacedata.first;
RegionView3D *rv3d = region->regiondata;
float viewinv_m3[3][3];
copy_m3_m4(viewinv_m3, rv3d->viewinv);
@@ -1997,13 +1905,13 @@ static bool WIDGETGROUP_gizmo_poll_generic(View3D *v3d)
static bool WIDGETGROUP_gizmo_poll_context(const struct bContext *C,
struct wmGizmoGroupType *UNUSED(gzgt))
{
- ScrArea *sa = CTX_wm_area(C);
- View3D *v3d = sa->spacedata.first;
+ ScrArea *area = CTX_wm_area(C);
+ View3D *v3d = area->spacedata.first;
if (!WIDGETGROUP_gizmo_poll_generic(v3d)) {
return false;
}
- const bToolRef *tref = sa->runtime.tool;
+ const bToolRef *tref = area->runtime.tool;
if (v3d->gizmo_flag & V3D_GIZMO_HIDE_CONTEXT) {
return false;
}
@@ -2025,8 +1933,8 @@ static bool WIDGETGROUP_gizmo_poll_tool(const struct bContext *C, struct wmGizmo
return false;
}
- ScrArea *sa = CTX_wm_area(C);
- View3D *v3d = sa->spacedata.first;
+ ScrArea *area = CTX_wm_area(C);
+ View3D *v3d = area->spacedata.first;
if (!WIDGETGROUP_gizmo_poll_generic(v3d)) {
return false;
}
@@ -2198,6 +2106,15 @@ static void WIDGETGROUP_xform_cage_refresh(const bContext *C, wmGizmoGroup *gzgr
WM_gizmo_set_flag(gz, WM_GIZMO_HIDDEN, true);
}
else {
+ ViewLayer *view_layer = CTX_data_view_layer(C);
+ Object *ob = OBACT(view_layer);
+ if (ob && ob->mode & OB_MODE_EDIT) {
+ copy_m4_m4(gz->matrix_space, ob->obmat);
+ }
+ else {
+ unit_m4(gz->matrix_space);
+ }
+
gizmo_prepare_mat(C, rv3d, &tbounds);
WM_gizmo_set_flag(gz, WM_GIZMO_HIDDEN, false);
@@ -2247,23 +2164,14 @@ static void WIDGETGROUP_xform_cage_message_subscribe(const bContext *C,
{
Scene *scene = CTX_data_scene(C);
bScreen *screen = CTX_wm_screen(C);
- ScrArea *sa = CTX_wm_area(C);
+ ScrArea *area = CTX_wm_area(C);
ARegion *region = CTX_wm_region(C);
- gizmo_xform_message_subscribe(gzgroup, mbus, scene, screen, sa, region, VIEW3D_GGT_xform_cage);
+ gizmo_xform_message_subscribe(gzgroup, mbus, scene, screen, area, region, VIEW3D_GGT_xform_cage);
}
static void WIDGETGROUP_xform_cage_draw_prepare(const bContext *C, wmGizmoGroup *gzgroup)
{
struct XFormCageWidgetGroup *xgzgroup = gzgroup->customdata;
- wmGizmo *gz = xgzgroup->gizmo;
- ViewLayer *view_layer = CTX_data_view_layer(C);
- Object *ob = OBACT(view_layer);
- if (ob && ob->mode & OB_MODE_EDIT) {
- copy_m4_m4(gz->matrix_space, ob->obmat);
- }
- else {
- unit_m4(gz->matrix_space);
- }
RegionView3D *rv3d = CTX_wm_region_view3d(C);
{
@@ -2460,9 +2368,10 @@ static void WIDGETGROUP_xform_shear_message_subscribe(const bContext *C,
{
Scene *scene = CTX_data_scene(C);
bScreen *screen = CTX_wm_screen(C);
- ScrArea *sa = CTX_wm_area(C);
+ ScrArea *area = CTX_wm_area(C);
ARegion *region = CTX_wm_region(C);
- gizmo_xform_message_subscribe(gzgroup, mbus, scene, screen, sa, region, VIEW3D_GGT_xform_shear);
+ gizmo_xform_message_subscribe(
+ gzgroup, mbus, scene, screen, area, region, VIEW3D_GGT_xform_shear);
}
static void WIDGETGROUP_xform_shear_draw_prepare(const bContext *C, wmGizmoGroup *gzgroup)
diff --git a/source/blender/editors/transform/transform_mode.c b/source/blender/editors/transform/transform_mode.c
index 31aae4f5b05..c2c880b03ff 100644
--- a/source/blender/editors/transform/transform_mode.c
+++ b/source/blender/editors/transform/transform_mode.c
@@ -61,6 +61,18 @@ bool transdata_check_local_center(TransInfo *t, short around)
(t->options & (CTX_MOVIECLIP | CTX_MASK | CTX_PAINT_CURVE))));
}
+/* Informs if the mode can be switched during modal. */
+bool transform_mode_is_changeable(const int mode)
+{
+ return ELEM(mode,
+ TFM_ROTATION,
+ TFM_RESIZE,
+ TFM_TRACKBALL,
+ TFM_TRANSLATION,
+ TFM_EDGE_SLIDE,
+ TFM_VERT_SLIDE);
+}
+
/* -------------------------------------------------------------------- */
/** \name Transform Locks
* \{ */
@@ -529,7 +541,7 @@ void headerRotation(TransInfo *t, char str[UI_MAX_DRAW_STR], float final)
void postInputRotation(TransInfo *t, float values[3])
{
float axis_final[3];
- copy_v3_v3(axis_final, t->orient_matrix[t->orient_axis]);
+ copy_v3_v3(axis_final, t->spacemtx[t->orient_axis]);
if ((t->con.mode & CON_APPLY) && t->con.applyRot) {
t->con.applyRot(t, NULL, NULL, axis_final, values);
}
@@ -1028,21 +1040,21 @@ short getAnimEdit_SnapMode(TransInfo *t)
short autosnap = SACTSNAP_OFF;
if (t->spacetype == SPACE_ACTION) {
- SpaceAction *saction = (SpaceAction *)t->sa->spacedata.first;
+ SpaceAction *saction = (SpaceAction *)t->area->spacedata.first;
if (saction) {
autosnap = saction->autosnap;
}
}
else if (t->spacetype == SPACE_GRAPH) {
- SpaceGraph *sipo = (SpaceGraph *)t->sa->spacedata.first;
+ SpaceGraph *sipo = (SpaceGraph *)t->area->spacedata.first;
if (sipo) {
autosnap = sipo->autosnap;
}
}
else if (t->spacetype == SPACE_NLA) {
- SpaceNla *snla = (SpaceNla *)t->sa->spacedata.first;
+ SpaceNla *snla = (SpaceNla *)t->area->spacedata.first;
if (snla) {
autosnap = snla->autosnap;
diff --git a/source/blender/editors/transform/transform_mode.h b/source/blender/editors/transform/transform_mode.h
index 6180f6d3477..074e89390c2 100644
--- a/source/blender/editors/transform/transform_mode.h
+++ b/source/blender/editors/transform/transform_mode.h
@@ -41,6 +41,7 @@ typedef struct TransDataGenericSlideVert {
/* transform_mode.c */
bool transdata_check_local_center(TransInfo *t, short around);
+bool transform_mode_is_changeable(const int mode);
void protectedTransBits(short protectflag, float vec[3]);
void constraintTransLim(TransInfo *t, TransData *td);
void postInputRotation(TransInfo *t, float values[3]);
diff --git a/source/blender/editors/transform/transform_mode_align.c b/source/blender/editors/transform/transform_mode_align.c
index fbd5e87f034..4fd4599b940 100644
--- a/source/blender/editors/transform/transform_mode_align.c
+++ b/source/blender/editors/transform/transform_mode_align.c
@@ -52,10 +52,6 @@ static void applyAlign(TransInfo *t, const int UNUSED(mval[2]))
for (i = 0; i < tc->data_len; i++, td++) {
float mat[3][3], invmat[3][3];
- if (td->flag & TD_NOACTION) {
- break;
- }
-
if (td->flag & TD_SKIP) {
continue;
}
@@ -82,7 +78,7 @@ static void applyAlign(TransInfo *t, const int UNUSED(mval[2]))
recalcData(t);
- ED_area_status_text(t->sa, TIP_("Align"));
+ ED_area_status_text(t->area, TIP_("Align"));
}
void initAlign(TransInfo *t)
diff --git a/source/blender/editors/transform/transform_mode_baketime.c b/source/blender/editors/transform/transform_mode_baketime.c
index 0feaa27d4ce..4e7fc3578ce 100644
--- a/source/blender/editors/transform/transform_mode_baketime.c
+++ b/source/blender/editors/transform/transform_mode_baketime.c
@@ -97,10 +97,6 @@ static void applyBakeTime(TransInfo *t, const int mval[2])
FOREACH_TRANS_DATA_CONTAINER (t, tc) {
TransData *td = tc->data;
for (i = 0; i < tc->data_len; i++, td++) {
- if (td->flag & TD_NOACTION) {
- break;
- }
-
if (td->flag & TD_SKIP) {
continue;
}
@@ -119,7 +115,7 @@ static void applyBakeTime(TransInfo *t, const int mval[2])
recalcData(t);
- ED_area_status_text(t->sa, str);
+ ED_area_status_text(t->area, str);
}
void initBakeTime(TransInfo *t)
diff --git a/source/blender/editors/transform/transform_mode_bbone_resize.c b/source/blender/editors/transform/transform_mode_bbone_resize.c
index 1a32a550cb0..77850e74785 100644
--- a/source/blender/editors/transform/transform_mode_bbone_resize.c
+++ b/source/blender/editors/transform/transform_mode_bbone_resize.c
@@ -141,10 +141,6 @@ static void applyBoneSize(TransInfo *t, const int UNUSED(mval[2]))
FOREACH_TRANS_DATA_CONTAINER (t, tc) {
TransData *td = tc->data;
for (i = 0; i < tc->data_len; i++, td++) {
- if (td->flag & TD_NOACTION) {
- break;
- }
-
if (td->flag & TD_SKIP) {
continue;
}
@@ -155,7 +151,7 @@ static void applyBoneSize(TransInfo *t, const int UNUSED(mval[2]))
recalcData(t);
- ED_area_status_text(t->sa, str);
+ ED_area_status_text(t->area, str);
}
void initBoneSize(TransInfo *t)
diff --git a/source/blender/editors/transform/transform_mode_bend.c b/source/blender/editors/transform/transform_mode_bend.c
index bf80673fbb4..3b51626b170 100644
--- a/source/blender/editors/transform/transform_mode_bend.c
+++ b/source/blender/editors/transform/transform_mode_bend.c
@@ -186,10 +186,6 @@ static void Bend(TransInfo *t, const int UNUSED(mval[2]))
float delta[3];
float fac, fac_scaled;
- if (td->flag & TD_NOACTION) {
- break;
- }
-
if (td->flag & TD_SKIP) {
continue;
}
@@ -246,7 +242,7 @@ static void Bend(TransInfo *t, const int UNUSED(mval[2]))
recalcData(t);
- ED_area_status_text(t->sa, str);
+ ED_area_status_text(t->area, str);
}
void initBend(TransInfo *t)
@@ -289,7 +285,8 @@ void initBend(TransInfo *t)
curs = t->scene->cursor.location;
copy_v3_v3(data->warp_sta, curs);
- ED_view3d_win_to_3d((View3D *)t->sa->spacedata.first, t->region, curs, mval_fl, data->warp_end);
+ ED_view3d_win_to_3d(
+ (View3D *)t->area->spacedata.first, t->region, curs, mval_fl, data->warp_end);
copy_v3_v3(data->warp_nor, t->viewinv[2]);
normalize_v3(data->warp_nor);
diff --git a/source/blender/editors/transform/transform_mode_boneenvelope.c b/source/blender/editors/transform/transform_mode_boneenvelope.c
index 0886d4e01ef..7045d190478 100644
--- a/source/blender/editors/transform/transform_mode_boneenvelope.c
+++ b/source/blender/editors/transform/transform_mode_boneenvelope.c
@@ -73,10 +73,6 @@ static void applyBoneEnvelope(TransInfo *t, const int UNUSED(mval[2]))
FOREACH_TRANS_DATA_CONTAINER (t, tc) {
TransData *td = tc->data;
for (i = 0; i < tc->data_len; i++, td++) {
- if (td->flag & TD_NOACTION) {
- break;
- }
-
if (td->flag & TD_SKIP) {
continue;
}
@@ -95,7 +91,7 @@ static void applyBoneEnvelope(TransInfo *t, const int UNUSED(mval[2]))
recalcData(t);
- ED_area_status_text(t->sa, str);
+ ED_area_status_text(t->area, str);
}
void initBoneEnvelope(TransInfo *t)
diff --git a/source/blender/editors/transform/transform_mode_boneroll.c b/source/blender/editors/transform/transform_mode_boneroll.c
index 8e9d680f269..1503519c519 100644
--- a/source/blender/editors/transform/transform_mode_boneroll.c
+++ b/source/blender/editors/transform/transform_mode_boneroll.c
@@ -75,10 +75,6 @@ static void applyBoneRoll(TransInfo *t, const int UNUSED(mval[2]))
FOREACH_TRANS_DATA_CONTAINER (t, tc) {
TransData *td = tc->data;
for (i = 0; i < tc->data_len; i++, td++) {
- if (td->flag & TD_NOACTION) {
- break;
- }
-
if (td->flag & TD_SKIP) {
continue;
}
@@ -89,7 +85,7 @@ static void applyBoneRoll(TransInfo *t, const int UNUSED(mval[2]))
recalcData(t);
- ED_area_status_text(t->sa, str);
+ ED_area_status_text(t->area, str);
}
void initBoneRoll(TransInfo *t)
diff --git a/source/blender/editors/transform/transform_mode_curveshrinkfatten.c b/source/blender/editors/transform/transform_mode_curveshrinkfatten.c
index 6ccb0e757c3..84e4e950804 100644
--- a/source/blender/editors/transform/transform_mode_curveshrinkfatten.c
+++ b/source/blender/editors/transform/transform_mode_curveshrinkfatten.c
@@ -73,10 +73,6 @@ static void applyCurveShrinkFatten(TransInfo *t, const int UNUSED(mval[2]))
FOREACH_TRANS_DATA_CONTAINER (t, tc) {
TransData *td = tc->data;
for (i = 0; i < tc->data_len; i++, td++) {
- if (td->flag & TD_NOACTION) {
- break;
- }
-
if (td->flag & TD_SKIP) {
continue;
}
@@ -94,7 +90,7 @@ static void applyCurveShrinkFatten(TransInfo *t, const int UNUSED(mval[2]))
recalcData(t);
- ED_area_status_text(t->sa, str);
+ ED_area_status_text(t->area, str);
}
void initCurveShrinkFatten(TransInfo *t)
diff --git a/source/blender/editors/transform/transform_mode_edge_bevelweight.c b/source/blender/editors/transform/transform_mode_edge_bevelweight.c
index 15a9e7384b1..399cec2d62c 100644
--- a/source/blender/editors/transform/transform_mode_edge_bevelweight.c
+++ b/source/blender/editors/transform/transform_mode_edge_bevelweight.c
@@ -87,10 +87,6 @@ static void applyBevelWeight(TransInfo *t, const int UNUSED(mval[2]))
FOREACH_TRANS_DATA_CONTAINER (t, tc) {
TransData *td = tc->data;
for (i = 0; i < tc->data_len; i++, td++) {
- if (td->flag & TD_NOACTION) {
- break;
- }
-
if (td->val) {
*td->val = td->ival + weight * td->factor;
if (*td->val < 0.0f) {
@@ -105,7 +101,7 @@ static void applyBevelWeight(TransInfo *t, const int UNUSED(mval[2]))
recalcData(t);
- ED_area_status_text(t->sa, str);
+ ED_area_status_text(t->area, str);
}
void initBevelWeight(TransInfo *t)
diff --git a/source/blender/editors/transform/transform_mode_edge_crease.c b/source/blender/editors/transform/transform_mode_edge_crease.c
index 8865721bc7e..53c948c742b 100644
--- a/source/blender/editors/transform/transform_mode_edge_crease.c
+++ b/source/blender/editors/transform/transform_mode_edge_crease.c
@@ -87,10 +87,6 @@ static void applyCrease(TransInfo *t, const int UNUSED(mval[2]))
FOREACH_TRANS_DATA_CONTAINER (t, tc) {
TransData *td = tc->data;
for (i = 0; i < tc->data_len; i++, td++) {
- if (td->flag & TD_NOACTION) {
- break;
- }
-
if (td->flag & TD_SKIP) {
continue;
}
@@ -109,7 +105,7 @@ static void applyCrease(TransInfo *t, const int UNUSED(mval[2]))
recalcData(t);
- ED_area_status_text(t->sa, str);
+ ED_area_status_text(t->area, str);
}
void initCrease(TransInfo *t)
diff --git a/source/blender/editors/transform/transform_mode_edge_rotate_normal.c b/source/blender/editors/transform/transform_mode_edge_rotate_normal.c
index 69cd909cff9..fde0d5b187e 100644
--- a/source/blender/editors/transform/transform_mode_edge_rotate_normal.c
+++ b/source/blender/editors/transform/transform_mode_edge_rotate_normal.c
@@ -81,7 +81,7 @@ static void applyNormalRotation(TransInfo *t, const int UNUSED(mval[2]))
char str[UI_MAX_DRAW_STR];
float axis_final[3];
- copy_v3_v3(axis_final, t->orient_matrix[t->orient_axis]);
+ copy_v3_v3(axis_final, t->spacemtx[t->orient_axis]);
if ((t->con.mode & CON_APPLY) && t->con.applyRot) {
t->con.applyRot(t, NULL, NULL, axis_final, NULL);
@@ -121,7 +121,7 @@ static void applyNormalRotation(TransInfo *t, const int UNUSED(mval[2]))
recalcData(t);
- ED_area_status_text(t->sa, str);
+ ED_area_status_text(t->area, str);
}
void initNormalRotation(TransInfo *t)
diff --git a/source/blender/editors/transform/transform_mode_edge_seq_slide.c b/source/blender/editors/transform/transform_mode_edge_seq_slide.c
index e23e5c188c8..c1cb4325c09 100644
--- a/source/blender/editors/transform/transform_mode_edge_seq_slide.c
+++ b/source/blender/editors/transform/transform_mode_edge_seq_slide.c
@@ -81,10 +81,6 @@ static void applySeqSlideValue(TransInfo *t, const float val[2])
FOREACH_TRANS_DATA_CONTAINER (t, tc) {
TransData *td = tc->data;
for (i = 0; i < tc->data_len; i++, td++) {
- if (td->flag & TD_NOACTION) {
- break;
- }
-
if (td->flag & TD_SKIP) {
continue;
}
@@ -101,9 +97,8 @@ static void applySeqSlide(TransInfo *t, const int mval[2])
snapSequenceBounds(t, mval);
if (t->con.mode & CON_APPLY) {
- float pvec[3] = {0.0f, 0.0f, 0.0f};
float tvec[3];
- t->con.applyVec(t, NULL, NULL, t->values, tvec, pvec);
+ t->con.applyVec(t, NULL, NULL, t->values, tvec);
copy_v3_v3(t->values_final, tvec);
}
else {
@@ -120,7 +115,7 @@ static void applySeqSlide(TransInfo *t, const int mval[2])
recalcData(t);
- ED_area_status_text(t->sa, str);
+ ED_area_status_text(t->area, str);
}
void initSeqSlide(TransInfo *t)
diff --git a/source/blender/editors/transform/transform_mode_edge_slide.c b/source/blender/editors/transform/transform_mode_edge_slide.c
index b54e6afc9a1..5613a782529 100644
--- a/source/blender/editors/transform/transform_mode_edge_slide.c
+++ b/source/blender/editors/transform/transform_mode_edge_slide.c
@@ -334,7 +334,7 @@ static void calcEdgeSlide_mval_range(TransInfo *t,
if (t->spacetype == SPACE_VIEW3D) {
/* background mode support */
- v3d = t->sa ? t->sa->spacedata.first : NULL;
+ v3d = t->area ? t->area->spacedata.first : NULL;
rv3d = t->region ? t->region->regiondata : NULL;
}
@@ -858,7 +858,7 @@ static bool createEdgeSlideVerts_double_side(TransInfo *t, TransDataContainer *t
/* use for visibility checks */
if (t->spacetype == SPACE_VIEW3D) {
- v3d = t->sa ? t->sa->spacedata.first : NULL;
+ v3d = t->area ? t->area->spacedata.first : NULL;
rv3d = t->region ? t->region->regiondata : NULL;
use_occlude_geometry = (v3d && TRANS_DATA_CONTAINER_FIRST_OK(t)->obedit->dt > OB_WIRE &&
!XRAY_ENABLED(v3d));
@@ -899,7 +899,7 @@ static bool createEdgeSlideVerts_single_side(TransInfo *t, TransDataContainer *t
if (t->spacetype == SPACE_VIEW3D) {
/* background mode support */
- v3d = t->sa ? t->sa->spacedata.first : NULL;
+ v3d = t->area ? t->area->spacedata.first : NULL;
rv3d = t->region ? t->region->regiondata : NULL;
}
@@ -1043,7 +1043,7 @@ static bool createEdgeSlideVerts_single_side(TransInfo *t, TransDataContainer *t
/* use for visibility checks */
if (t->spacetype == SPACE_VIEW3D) {
- v3d = t->sa ? t->sa->spacedata.first : NULL;
+ v3d = t->area ? t->area->spacedata.first : NULL;
rv3d = t->region ? t->region->regiondata : NULL;
use_occlude_geometry = (v3d && TRANS_DATA_CONTAINER_FIRST_OK(t)->obedit->dt > OB_WIRE &&
!XRAY_ENABLED(v3d));
@@ -1417,7 +1417,7 @@ static void applyEdgeSlide(TransInfo *t, const int UNUSED(mval[2]))
recalcData(t);
- ED_area_status_text(t->sa, str);
+ ED_area_status_text(t->area, str);
}
void initEdgeSlide_ex(
diff --git a/source/blender/editors/transform/transform_mode_gpopacity.c b/source/blender/editors/transform/transform_mode_gpopacity.c
index 460e2b41da8..4712fb7ba01 100644
--- a/source/blender/editors/transform/transform_mode_gpopacity.c
+++ b/source/blender/editors/transform/transform_mode_gpopacity.c
@@ -73,10 +73,6 @@ static void applyGPOpacity(TransInfo *t, const int UNUSED(mval[2]))
FOREACH_TRANS_DATA_CONTAINER (t, tc) {
TransData *td = tc->data;
for (i = 0; i < tc->data_len; i++, td++) {
- if (td->flag & TD_NOACTION) {
- break;
- }
-
if (td->flag & TD_SKIP) {
continue;
}
@@ -90,7 +86,7 @@ static void applyGPOpacity(TransInfo *t, const int UNUSED(mval[2]))
}
}
- ED_area_status_text(t->sa, str);
+ ED_area_status_text(t->area, str);
}
void initGPOpacity(TransInfo *t)
diff --git a/source/blender/editors/transform/transform_mode_gpshrinkfatten.c b/source/blender/editors/transform/transform_mode_gpshrinkfatten.c
index edb353b343d..ab9a0aa79ed 100644
--- a/source/blender/editors/transform/transform_mode_gpshrinkfatten.c
+++ b/source/blender/editors/transform/transform_mode_gpshrinkfatten.c
@@ -73,10 +73,6 @@ static void applyGPShrinkFatten(TransInfo *t, const int UNUSED(mval[2]))
FOREACH_TRANS_DATA_CONTAINER (t, tc) {
TransData *td = tc->data;
for (i = 0; i < tc->data_len; i++, td++) {
- if (td->flag & TD_NOACTION) {
- break;
- }
-
if (td->flag & TD_SKIP) {
continue;
}
@@ -92,7 +88,7 @@ static void applyGPShrinkFatten(TransInfo *t, const int UNUSED(mval[2]))
}
}
- ED_area_status_text(t->sa, str);
+ ED_area_status_text(t->area, str);
}
void initGPShrinkFatten(TransInfo *t)
diff --git a/source/blender/editors/transform/transform_mode_maskshrinkfatten.c b/source/blender/editors/transform/transform_mode_maskshrinkfatten.c
index b6719067f5b..68f3abda85b 100644
--- a/source/blender/editors/transform/transform_mode_maskshrinkfatten.c
+++ b/source/blender/editors/transform/transform_mode_maskshrinkfatten.c
@@ -78,10 +78,6 @@ static void applyMaskShrinkFatten(TransInfo *t, const int UNUSED(mval[2]))
FOREACH_TRANS_DATA_CONTAINER (t, tc) {
TransData *td = tc->data;
for (i = 0; i < tc->data_len; i++, td++) {
- if (td->flag & TD_NOACTION) {
- break;
- }
-
if (td->flag & TD_SKIP) {
continue;
}
@@ -97,10 +93,6 @@ static void applyMaskShrinkFatten(TransInfo *t, const int UNUSED(mval[2]))
FOREACH_TRANS_DATA_CONTAINER (t, tc) {
TransData *td = tc->data;
for (td = tc->data, i = 0; i < tc->data_len; i++, td++) {
- if (td->flag & TD_NOACTION) {
- break;
- }
-
if (td->flag & TD_SKIP) {
continue;
}
@@ -124,7 +116,7 @@ static void applyMaskShrinkFatten(TransInfo *t, const int UNUSED(mval[2]))
recalcData(t);
- ED_area_status_text(t->sa, str);
+ ED_area_status_text(t->area, str);
}
void initMaskShrinkFatten(TransInfo *t)
diff --git a/source/blender/editors/transform/transform_mode_mirror.c b/source/blender/editors/transform/transform_mode_mirror.c
index 2f305989f82..8d953610eb8 100644
--- a/source/blender/editors/transform/transform_mode_mirror.c
+++ b/source/blender/editors/transform/transform_mode_mirror.c
@@ -69,10 +69,6 @@ static void applyMirror(TransInfo *t, const int UNUSED(mval[2]))
FOREACH_TRANS_DATA_CONTAINER (t, tc) {
TransData *td = tc->data;
for (i = 0; i < tc->data_len; i++, td++) {
- if (td->flag & TD_NOACTION) {
- break;
- }
-
if (td->flag & TD_SKIP) {
continue;
}
@@ -83,7 +79,7 @@ static void applyMirror(TransInfo *t, const int UNUSED(mval[2]))
recalcData(t);
- ED_area_status_text(t->sa, str);
+ ED_area_status_text(t->area, str);
}
else {
size[0] = size[1] = size[2] = 1;
@@ -93,10 +89,6 @@ static void applyMirror(TransInfo *t, const int UNUSED(mval[2]))
FOREACH_TRANS_DATA_CONTAINER (t, tc) {
TransData *td = tc->data;
for (i = 0; i < tc->data_len; i++, td++) {
- if (td->flag & TD_NOACTION) {
- break;
- }
-
if (td->flag & TD_SKIP) {
continue;
}
@@ -108,10 +100,10 @@ static void applyMirror(TransInfo *t, const int UNUSED(mval[2]))
recalcData(t);
if (t->flag & T_2D_EDIT) {
- ED_area_status_text(t->sa, TIP_("Select a mirror axis (X, Y)"));
+ ED_area_status_text(t->area, TIP_("Select a mirror axis (X, Y)"));
}
else {
- ED_area_status_text(t->sa, TIP_("Select a mirror axis (X, Y, Z)"));
+ ED_area_status_text(t->area, TIP_("Select a mirror axis (X, Y, Z)"));
}
}
}
diff --git a/source/blender/editors/transform/transform_mode_push_pull.c b/source/blender/editors/transform/transform_mode_push_pull.c
index 890fc820cd5..4a2f979ec38 100644
--- a/source/blender/editors/transform/transform_mode_push_pull.c
+++ b/source/blender/editors/transform/transform_mode_push_pull.c
@@ -82,10 +82,6 @@ static void applyPushPull(TransInfo *t, const int UNUSED(mval[2]))
FOREACH_TRANS_DATA_CONTAINER (t, tc) {
TransData *td = tc->data;
for (i = 0; i < tc->data_len; i++, td++) {
- if (td->flag & TD_NOACTION) {
- break;
- }
-
if (td->flag & TD_SKIP) {
continue;
}
@@ -114,7 +110,7 @@ static void applyPushPull(TransInfo *t, const int UNUSED(mval[2]))
recalcData(t);
- ED_area_status_text(t->sa, str);
+ ED_area_status_text(t->area, str);
}
void initPushPull(TransInfo *t)
diff --git a/source/blender/editors/transform/transform_mode_resize.c b/source/blender/editors/transform/transform_mode_resize.c
index 59f2ab5c294..d919d5c889d 100644
--- a/source/blender/editors/transform/transform_mode_resize.c
+++ b/source/blender/editors/transform/transform_mode_resize.c
@@ -93,10 +93,6 @@ static void applyResize(TransInfo *t, const int UNUSED(mval[2]))
FOREACH_TRANS_DATA_CONTAINER (t, tc) {
TransData *td = tc->data;
for (i = 0; i < tc->data_len; i++, td++) {
- if (td->flag & TD_NOACTION) {
- break;
- }
-
if (td->flag & TD_SKIP) {
continue;
}
@@ -131,7 +127,7 @@ static void applyResize(TransInfo *t, const int UNUSED(mval[2]))
recalcData(t);
- ED_area_status_text(t->sa, str);
+ ED_area_status_text(t->area, str);
}
void initResize(TransInfo *t)
diff --git a/source/blender/editors/transform/transform_mode_rotate.c b/source/blender/editors/transform/transform_mode_rotate.c
index bea039194d0..6480cb6c30e 100644
--- a/source/blender/editors/transform/transform_mode_rotate.c
+++ b/source/blender/editors/transform/transform_mode_rotate.c
@@ -82,10 +82,6 @@ static void applyRotationValue(TransInfo *t,
FOREACH_TRANS_DATA_CONTAINER (t, tc) {
TransData *td = tc->data;
for (i = 0; i < tc->data_len; i++, td++) {
- if (td->flag & TD_NOACTION) {
- break;
- }
-
if (td->flag & TD_SKIP) {
continue;
}
@@ -146,7 +142,8 @@ static void applyRotation(TransInfo *t, const int UNUSED(mval[2]))
snapGridIncrement(t, &final);
float axis_final[3];
- copy_v3_v3(axis_final, t->orient_matrix[t->orient_axis]);
+ /* Use the negative axis to match the default Z axis of the view matrix. */
+ negate_v3_v3(axis_final, t->spacemtx[t->orient_axis]);
if ((t->con.mode & CON_APPLY) && t->con.applyRot) {
t->con.applyRot(t, NULL, NULL, axis_final, NULL);
@@ -169,7 +166,7 @@ static void applyRotation(TransInfo *t, const int UNUSED(mval[2]))
recalcData(t);
- ED_area_status_text(t->sa, str);
+ ED_area_status_text(t->area, str);
}
void initRotation(TransInfo *t)
diff --git a/source/blender/editors/transform/transform_mode_shear.c b/source/blender/editors/transform/transform_mode_shear.c
index 8b7dc12f41b..fa33c1550e7 100644
--- a/source/blender/editors/transform/transform_mode_shear.c
+++ b/source/blender/editors/transform/transform_mode_shear.c
@@ -53,10 +53,10 @@ static void initShear_mouseInputMode(TransInfo *t)
{
float dir[3];
bool dir_flip = false;
- copy_v3_v3(dir, t->orient_matrix[t->orient_axis_ortho]);
+ copy_v3_v3(dir, t->spacemtx[t->orient_axis_ortho]);
/* Needed for axis aligned view gizmo. */
- if (t->orientation.user == V3D_ORIENT_VIEW) {
+ if (t->orient[t->orient_curr].type == V3D_ORIENT_VIEW) {
if (t->orient_axis_ortho == 0) {
if (t->center2d[1] > t->mouse.imval[1]) {
dir_flip = !dir_flip;
@@ -154,8 +154,8 @@ static void applyShear(TransInfo *t, const int UNUSED(mval[2]))
unit_m3(smat);
smat[1][0] = value;
- copy_v3_v3(axismat_inv[0], t->orient_matrix[t->orient_axis_ortho]);
- copy_v3_v3(axismat_inv[2], t->orient_matrix[t->orient_axis]);
+ copy_v3_v3(axismat_inv[0], t->spacemtx[t->orient_axis_ortho]);
+ copy_v3_v3(axismat_inv[2], t->spacemtx[t->orient_axis]);
cross_v3_v3v3(axismat_inv[1], axismat_inv[0], axismat_inv[2]);
invert_m3_m3(axismat, axismat_inv);
@@ -165,11 +165,6 @@ static void applyShear(TransInfo *t, const int UNUSED(mval[2]))
TransData *td = tc->data;
for (i = 0; i < tc->data_len; i++, td++) {
const float *center, *co;
-
- if (td->flag & TD_NOACTION) {
- break;
- }
-
if (td->flag & TD_SKIP) {
continue;
}
@@ -217,7 +212,7 @@ static void applyShear(TransInfo *t, const int UNUSED(mval[2]))
recalcData(t);
- ED_area_status_text(t->sa, str);
+ ED_area_status_text(t->area, str);
}
void initShear(TransInfo *t)
diff --git a/source/blender/editors/transform/transform_mode_shrink_fatten.c b/source/blender/editors/transform/transform_mode_shrink_fatten.c
index e24e63f445c..78d3efa0d69 100644
--- a/source/blender/editors/transform/transform_mode_shrink_fatten.c
+++ b/source/blender/editors/transform/transform_mode_shrink_fatten.c
@@ -95,10 +95,6 @@ static void applyShrinkFatten(TransInfo *t, const int UNUSED(mval[2]))
TransData *td = tc->data;
for (i = 0; i < tc->data_len; i++, td++) {
float tdistance; /* temp dist */
- if (td->flag & TD_NOACTION) {
- break;
- }
-
if (td->flag & TD_SKIP) {
continue;
}
@@ -115,7 +111,7 @@ static void applyShrinkFatten(TransInfo *t, const int UNUSED(mval[2]))
recalcData(t);
- ED_area_status_text(t->sa, str);
+ ED_area_status_text(t->area, str);
}
void initShrinkFatten(TransInfo *t)
diff --git a/source/blender/editors/transform/transform_mode_skin_resize.c b/source/blender/editors/transform/transform_mode_skin_resize.c
index 23ba9a07f3e..23d83050613 100644
--- a/source/blender/editors/transform/transform_mode_skin_resize.c
+++ b/source/blender/editors/transform/transform_mode_skin_resize.c
@@ -73,11 +73,6 @@ static void applySkinResize(TransInfo *t, const int UNUSED(mval[2]))
for (i = 0; i < tc->data_len; i++, td++) {
float tmat[3][3], smat[3][3];
float fsize[3];
-
- if (td->flag & TD_NOACTION) {
- break;
- }
-
if (td->flag & TD_SKIP) {
continue;
}
@@ -102,7 +97,7 @@ static void applySkinResize(TransInfo *t, const int UNUSED(mval[2]))
recalcData(t);
- ED_area_status_text(t->sa, str);
+ ED_area_status_text(t->area, str);
}
void initSkinResize(TransInfo *t)
diff --git a/source/blender/editors/transform/transform_mode_tilt.c b/source/blender/editors/transform/transform_mode_tilt.c
index 9ae0cfdf805..ca0a8818477 100644
--- a/source/blender/editors/transform/transform_mode_tilt.c
+++ b/source/blender/editors/transform/transform_mode_tilt.c
@@ -77,10 +77,6 @@ static void applyTilt(TransInfo *t, const int UNUSED(mval[2]))
FOREACH_TRANS_DATA_CONTAINER (t, tc) {
TransData *td = tc->data;
for (i = 0; i < tc->data_len; i++, td++) {
- if (td->flag & TD_NOACTION) {
- break;
- }
-
if (td->flag & TD_SKIP) {
continue;
}
@@ -93,7 +89,7 @@ static void applyTilt(TransInfo *t, const int UNUSED(mval[2]))
recalcData(t);
- ED_area_status_text(t->sa, str);
+ ED_area_status_text(t->area, str);
}
void initTilt(TransInfo *t)
diff --git a/source/blender/editors/transform/transform_mode_timescale.c b/source/blender/editors/transform/transform_mode_timescale.c
index b75ef4da0f2..ce46cc36276 100644
--- a/source/blender/editors/transform/transform_mode_timescale.c
+++ b/source/blender/editors/transform/transform_mode_timescale.c
@@ -109,7 +109,7 @@ static void applyTimeScale(TransInfo *t, const int UNUSED(mval[2]))
recalcData(t);
- ED_area_status_text(t->sa, str);
+ ED_area_status_text(t->area, str);
}
void initTimeScale(TransInfo *t)
diff --git a/source/blender/editors/transform/transform_mode_timeslide.c b/source/blender/editors/transform/transform_mode_timeslide.c
index fce526873f1..43e14a26930 100644
--- a/source/blender/editors/transform/transform_mode_timeslide.c
+++ b/source/blender/editors/transform/transform_mode_timeslide.c
@@ -82,7 +82,7 @@ static void applyTimeSlideValue(TransInfo *t, float sval, float cval)
/* set value for drawing black line */
if (t->spacetype == SPACE_ACTION) {
- SpaceAction *saction = (SpaceAction *)t->sa->spacedata.first;
+ SpaceAction *saction = (SpaceAction *)t->area->spacedata.first;
saction->timeslide = cval;
}
@@ -160,14 +160,14 @@ static void applyTimeSlide(TransInfo *t, const int mval[2])
recalcData(t);
- ED_area_status_text(t->sa, str);
+ ED_area_status_text(t->area, str);
}
void initTimeSlide(TransInfo *t)
{
/* this tool is only really available in the Action Editor... */
if (t->spacetype == SPACE_ACTION) {
- SpaceAction *saction = (SpaceAction *)t->sa->spacedata.first;
+ SpaceAction *saction = (SpaceAction *)t->area->spacedata.first;
/* set flag for drawing stuff */
saction->flag |= SACTION_MOVING;
diff --git a/source/blender/editors/transform/transform_mode_timetranslate.c b/source/blender/editors/transform/transform_mode_timetranslate.c
index 494609cafb0..c514df497bc 100644
--- a/source/blender/editors/transform/transform_mode_timetranslate.c
+++ b/source/blender/editors/transform/transform_mode_timetranslate.c
@@ -136,7 +136,7 @@ static void applyTimeTranslate(TransInfo *t, const int mval[2])
recalcData(t);
- ED_area_status_text(t->sa, str);
+ ED_area_status_text(t->area, str);
}
void initTimeTranslate(TransInfo *t)
diff --git a/source/blender/editors/transform/transform_mode_tosphere.c b/source/blender/editors/transform/transform_mode_tosphere.c
index 5a3b138823c..f6c5448a906 100644
--- a/source/blender/editors/transform/transform_mode_tosphere.c
+++ b/source/blender/editors/transform/transform_mode_tosphere.c
@@ -79,10 +79,6 @@ static void applyToSphere(TransInfo *t, const int UNUSED(mval[2]))
TransData *td = tc->data;
for (i = 0; i < tc->data_len; i++, td++) {
float tratio;
- if (td->flag & TD_NOACTION) {
- break;
- }
-
if (td->flag & TD_SKIP) {
continue;
}
@@ -101,7 +97,7 @@ static void applyToSphere(TransInfo *t, const int UNUSED(mval[2]))
recalcData(t);
- ED_area_status_text(t->sa, str);
+ ED_area_status_text(t->area, str);
}
void initToSphere(TransInfo *t)
diff --git a/source/blender/editors/transform/transform_mode_trackball.c b/source/blender/editors/transform/transform_mode_trackball.c
index 758ee3b9cae..ca5a749b275 100644
--- a/source/blender/editors/transform/transform_mode_trackball.c
+++ b/source/blender/editors/transform/transform_mode_trackball.c
@@ -63,10 +63,6 @@ static void applyTrackballValue(TransInfo *t,
FOREACH_TRANS_DATA_CONTAINER (t, tc) {
TransData *td = tc->data;
for (i = 0; i < tc->data_len; i++, td++) {
- if (td->flag & TD_NOACTION) {
- break;
- }
-
if (td->flag & TD_SKIP) {
continue;
}
@@ -143,7 +139,7 @@ static void applyTrackball(TransInfo *t, const int UNUSED(mval[2]))
recalcData(t);
- ED_area_status_text(t->sa, str);
+ ED_area_status_text(t->area, str);
}
void initTrackball(TransInfo *t)
diff --git a/source/blender/editors/transform/transform_mode_translate.c b/source/blender/editors/transform/transform_mode_translate.c
index aef5a999d18..96820ca6385 100644
--- a/source/blender/editors/transform/transform_mode_translate.c
+++ b/source/blender/editors/transform/transform_mode_translate.c
@@ -191,7 +191,7 @@ static void headerTranslation(TransInfo *t, const float vec[3], char str[UI_MAX_
}
if (t->spacetype == SPACE_NODE) {
- SpaceNode *snode = (SpaceNode *)t->sa->spacedata.first;
+ SpaceNode *snode = (SpaceNode *)t->area->spacedata.first;
if ((snode->flag & SNODE_SKIP_INSOFFSET) == 0) {
const char *str_old = BLI_strdup(str);
@@ -236,10 +236,6 @@ static void applyTranslationValue(TransInfo *t, const float vec[3])
TransData *td = tc->data;
for (int i = 0; i < tc->data_len; i++, td++) {
- if (td->flag & TD_NOACTION) {
- break;
- }
-
if (td->flag & TD_SKIP) {
continue;
}
@@ -277,8 +273,7 @@ static void applyTranslationValue(TransInfo *t, const float vec[3])
}
if (t->con.applyVec) {
- float pvec[3];
- t->con.applyVec(t, tc, td, vec, tvec, pvec);
+ t->con.applyVec(t, tc, td, vec, tvec);
}
else {
copy_v3_v3(tvec, vec);
@@ -319,45 +314,39 @@ static void applyTranslationValue(TransInfo *t, const float vec[3])
static void applyTranslation(TransInfo *t, const int UNUSED(mval[2]))
{
char str[UI_MAX_DRAW_STR];
- float values_final[3];
+ float global_dir[3];
if (t->flag & T_INPUT_IS_VALUES_FINAL) {
- copy_v3_v3(t->values_final, t->values);
+ mul_v3_m3v3(global_dir, t->spacemtx, t->values);
}
else {
- copy_v3_v3(t->values_final, t->values);
+ copy_v3_v3(global_dir, t->values);
if ((t->con.mode & CON_APPLY) == 0) {
- snapGridIncrement(t, t->values_final);
+ snapGridIncrement(t, global_dir);
}
- if (applyNumInput(&t->num, t->values_final)) {
- removeAspectRatio(t, t->values_final);
+ if (applyNumInput(&t->num, global_dir)) {
+ removeAspectRatio(t, global_dir);
}
- applySnapping(t, t->values_final);
+ applySnapping(t, global_dir);
}
- copy_v3_v3(values_final, t->values_final);
if (t->con.mode & CON_APPLY) {
- float pvec[3] = {0.0f, 0.0f, 0.0f};
- t->con.applyVec(t, NULL, NULL, t->values_final, values_final, pvec);
- headerTranslation(t, pvec, str);
-
- /* only so we have re-usable value with redo, see T46741. */
- mul_v3_m3v3(t->values_final, t->con.imtx, values_final);
+ float in[3];
+ copy_v3_v3(in, global_dir);
+ t->con.applyVec(t, NULL, NULL, in, global_dir);
+ headerTranslation(t, global_dir, str);
}
else {
- headerTranslation(t, t->values_final, str);
- copy_v3_v3(values_final, t->values_final);
+ headerTranslation(t, global_dir, str);
}
- /* don't use 't->values' now on */
-
- applyTranslationValue(t, values_final);
+ applyTranslationValue(t, global_dir);
/* evil hack - redo translation if clipping needed */
- if (t->flag & T_CLIP_UV && clipUVTransform(t, values_final, 0)) {
- applyTranslationValue(t, values_final);
+ if (t->flag & T_CLIP_UV && clipUVTransform(t, global_dir, 0)) {
+ applyTranslationValue(t, global_dir);
/* In proportional edit it can happen that */
/* vertices in the radius of the brush end */
@@ -368,9 +357,11 @@ static void applyTranslation(TransInfo *t, const int UNUSED(mval[2]))
}
}
- recalcData(t);
+ /* Set the redo value. */
+ mul_v3_m3v3(t->values_final, t->spacemtx_inv, global_dir);
- ED_area_status_text(t->sa, str);
+ recalcData(t);
+ ED_area_status_text(t->area, str);
}
void initTranslation(TransInfo *t)
diff --git a/source/blender/editors/transform/transform_mode_vert_slide.c b/source/blender/editors/transform/transform_mode_vert_slide.c
index 2325c4d1d26..7bee48337f9 100644
--- a/source/blender/editors/transform/transform_mode_vert_slide.c
+++ b/source/blender/editors/transform/transform_mode_vert_slide.c
@@ -602,7 +602,7 @@ static void applyVertSlide(TransInfo *t, const int UNUSED(mval[2]))
recalcData(t);
- ED_area_status_text(t->sa, str);
+ ED_area_status_text(t->area, str);
}
void initVertSlide_ex(TransInfo *t, bool use_even, bool flipped, bool use_clamp)
diff --git a/source/blender/editors/transform/transform_ops.c b/source/blender/editors/transform/transform_ops.c
index 7e56b34af2f..d643244e6ca 100644
--- a/source/blender/editors/transform/transform_ops.c
+++ b/source/blender/editors/transform/transform_ops.c
@@ -223,6 +223,9 @@ static int delete_orientation_exec(bContext *C, wmOperator *UNUSED(op))
WM_event_add_notifier(C, NC_SCENE | NA_EDITED, scene);
+ struct wmMsgBus *mbus = CTX_wm_message_bus(C);
+ WM_msg_publish_rna_prop(mbus, &scene->id, scene, Scene, transform_orientation_slots);
+
return OPERATOR_FINISHED;
}
@@ -233,12 +236,11 @@ static int delete_orientation_invoke(bContext *C, wmOperator *op, const wmEvent
static bool delete_orientation_poll(bContext *C)
{
- Scene *scene = CTX_data_scene(C);
-
if (ED_operator_areaactive(C) == 0) {
return 0;
}
+ Scene *scene = CTX_data_scene(C);
return ((scene->orientation_slots[SCE_ORIENT_DEFAULT].type >= V3D_ORIENT_CUSTOM) &&
(scene->orientation_slots[SCE_ORIENT_DEFAULT].index_custom != -1));
}
@@ -264,6 +266,7 @@ static int create_orientation_exec(bContext *C, wmOperator *op)
const bool overwrite = RNA_boolean_get(op->ptr, "overwrite");
const bool use_view = RNA_boolean_get(op->ptr, "use_view");
View3D *v3d = CTX_wm_view3d(C);
+ Scene *scene = CTX_data_scene(C);
RNA_string_get(op->ptr, "name", name);
@@ -274,10 +277,18 @@ static int create_orientation_exec(bContext *C, wmOperator *op)
return OPERATOR_CANCELLED;
}
- BIF_createTransformOrientation(C, op->reports, name, use_view, use, overwrite);
+ if (!BIF_createTransformOrientation(C, op->reports, name, use_view, use, overwrite)) {
+ BKE_report(op->reports, RPT_ERROR, "Unable to create orientation");
+ return OPERATOR_CANCELLED;
+ }
+
+ if (use) {
+ struct wmMsgBus *mbus = CTX_wm_message_bus(C);
+ WM_msg_publish_rna_prop(mbus, &scene->id, scene, Scene, transform_orientation_slots);
+ WM_event_add_notifier(C, NC_SCENE | NA_EDITED, scene);
+ }
WM_event_add_notifier(C, NC_SPACE | ND_SPACE_VIEW3D, v3d);
- WM_event_add_notifier(C, NC_SCENE | NA_EDITED, CTX_data_scene(C));
return OPERATOR_FINISHED;
}
@@ -705,6 +716,15 @@ void Transform_Properties(struct wmOperatorType *ot, int flags)
prop = RNA_def_boolean(ot->srna, "use_accurate", 0, "Accurate", "Use accurate transformation");
RNA_def_property_flag(prop, PROP_HIDDEN);
}
+
+ if (flags & P_POST_TRANSFORM) {
+ prop = RNA_def_boolean(ot->srna,
+ "use_automerge_and_split",
+ 0,
+ "Auto Merge & Split",
+ "Forces the use of Auto Merge & Split");
+ RNA_def_property_flag(prop, PROP_HIDDEN);
+ }
}
static void TRANSFORM_OT_translate(struct wmOperatorType *ot)
@@ -730,7 +750,7 @@ static void TRANSFORM_OT_translate(struct wmOperatorType *ot)
Transform_Properties(ot,
P_ORIENT_MATRIX | P_CONSTRAINT | P_PROPORTIONAL | P_MIRROR | P_ALIGN_SNAP |
- P_OPTIONS | P_GPENCIL_EDIT | P_CURSOR_EDIT);
+ P_OPTIONS | P_GPENCIL_EDIT | P_CURSOR_EDIT | P_POST_TRANSFORM);
}
static void TRANSFORM_OT_resize(struct wmOperatorType *ot)
@@ -893,8 +913,8 @@ static bool transform_shear_poll(bContext *C)
return false;
}
- ScrArea *sa = CTX_wm_area(C);
- return sa && !ELEM(sa->spacetype, SPACE_ACTION);
+ ScrArea *area = CTX_wm_area(C);
+ return area && !ELEM(area->spacetype, SPACE_ACTION);
}
static void TRANSFORM_OT_shear(struct wmOperatorType *ot)
diff --git a/source/blender/editors/transform/transform_orientations.c b/source/blender/editors/transform/transform_orientations.c
index 5cc1feddf7a..cd170b144d8 100644
--- a/source/blender/editors/transform/transform_orientations.c
+++ b/source/blender/editors/transform/transform_orientations.c
@@ -296,7 +296,7 @@ bool createSpaceNormalTangent(float mat[3][3], const float normal[3], const floa
return true;
}
-void BIF_createTransformOrientation(bContext *C,
+bool BIF_createTransformOrientation(bContext *C,
ReportList *reports,
const char *name,
const bool use_view,
@@ -333,6 +333,7 @@ void BIF_createTransformOrientation(bContext *C,
if (activate && ts != NULL) {
BIF_selectTransformOrientation(C, ts);
}
+ return (ts != NULL);
}
TransformOrientation *addMatrixSpace(bContext *C,
@@ -396,24 +397,27 @@ int BIF_countTransformOrientation(const bContext *C)
return BLI_listbase_count(transform_orientations);
}
-bool applyTransformOrientation(const TransformOrientation *ts, float r_mat[3][3], char *r_name)
+void applyTransformOrientation(const TransformOrientation *ts, float r_mat[3][3], char *r_name)
{
if (r_name) {
BLI_strncpy(r_name, ts->name, MAX_NAME);
}
copy_m3_m3(r_mat, ts->mat);
-
- return true;
}
-static int count_bone_select(bArmature *arm, ListBase *lb, const bool do_it)
+/* Updates all `BONE_TRANSFORM` flags.
+ * Returns total number of bones with `BONE_TRANSFORM`.
+ * Note: `transform_convert_pose_transflags_update` has a similar logic. */
+static int armature_bone_transflags_update_recursive(bArmature *arm,
+ ListBase *lb,
+ const bool do_it)
{
Bone *bone;
bool do_next;
int total = 0;
for (bone = lb->first; bone; bone = bone->next) {
- bone->flag &= ~(BONE_TRANSFORM | BONE_TRANSFORM_MIRROR);
+ bone->flag &= ~BONE_TRANSFORM;
do_next = do_it;
if (do_it) {
if (bone->layer & arm->layer) {
@@ -426,109 +430,194 @@ static int count_bone_select(bArmature *arm, ListBase *lb, const bool do_it)
}
}
}
- total += count_bone_select(arm, &bone->childbase, do_next);
+ total += armature_bone_transflags_update_recursive(arm, &bone->childbase, do_next);
}
return total;
}
-void initTransformOrientation(bContext *C, TransInfo *t)
+void ED_transform_calc_orientation_from_type(const bContext *C, float r_mat[3][3])
{
- Object *ob = CTX_data_active_object(C);
- Object *obedit = CTX_data_active_object(C);
+ ARegion *region = CTX_wm_region(C);
+ Scene *scene = CTX_data_scene(C);
+ ViewLayer *view_layer = CTX_data_view_layer(C);
+ Object *obedit = CTX_data_edit_object(C);
+ RegionView3D *rv3d = region->regiondata;
+ Object *ob = OBACT(view_layer);
+ const short orientation_type = scene->orientation_slots[SCE_ORIENT_DEFAULT].type;
+ const short orientation_index_custom = scene->orientation_slots[SCE_ORIENT_DEFAULT].index_custom;
+ const int pivot_point = scene->toolsettings->transform_pivot_point;
- switch (t->orientation.user) {
- case V3D_ORIENT_GLOBAL:
- unit_m3(t->spacemtx);
- BLI_strncpy(t->spacename, TIP_("global"), sizeof(t->spacename));
- break;
+ ED_transform_calc_orientation_from_type_ex(
+ C, r_mat, scene, rv3d, ob, obedit, orientation_type, orientation_index_custom, pivot_point);
+}
- case V3D_ORIENT_GIMBAL:
- unit_m3(t->spacemtx);
- if (ob && gimbal_axis(ob, t->spacemtx)) {
- BLI_strncpy(t->spacename, TIP_("gimbal"), sizeof(t->spacename));
- break;
+short ED_transform_calc_orientation_from_type_ex(const bContext *C,
+ float r_mat[3][3],
+ /* extra args (can be accessed from context) */
+ Scene *scene,
+ RegionView3D *rv3d,
+ Object *ob,
+ Object *obedit,
+ const short orientation_type,
+ int orientation_index_custom,
+ const int pivot_point)
+{
+ switch (orientation_type) {
+ case V3D_ORIENT_GLOBAL: {
+ unit_m3(r_mat);
+ return V3D_ORIENT_GLOBAL;
+ }
+ case V3D_ORIENT_GIMBAL: {
+ if (gimbal_axis(ob, r_mat)) {
+ return V3D_ORIENT_GIMBAL;
}
- ATTR_FALLTHROUGH; /* no gimbal fallthrough to normal */
- case V3D_ORIENT_NORMAL:
- if (obedit || (ob && ob->mode & OB_MODE_POSE)) {
- BLI_strncpy(t->spacename, TIP_("normal"), sizeof(t->spacename));
- ED_getTransformOrientationMatrix(C, t->spacemtx, t->around);
- break;
+ /* if not gimbal, fall through to normal */
+ ATTR_FALLTHROUGH;
+ }
+ case V3D_ORIENT_NORMAL: {
+ if (obedit || ob->mode & OB_MODE_POSE) {
+ ED_getTransformOrientationMatrix(C, r_mat, pivot_point);
+ return V3D_ORIENT_NORMAL;
}
- ATTR_FALLTHROUGH; /* we define 'normal' as 'local' in Object mode */
- case V3D_ORIENT_LOCAL:
- BLI_strncpy(t->spacename, TIP_("local"), sizeof(t->spacename));
-
+ /* no break we define 'normal' as 'local' in Object mode */
+ ATTR_FALLTHROUGH;
+ }
+ case V3D_ORIENT_LOCAL: {
if (ob) {
- copy_m3_m4(t->spacemtx, ob->obmat);
- normalize_m3(t->spacemtx);
- }
- else {
- unit_m3(t->spacemtx);
+ if (ob->mode & OB_MODE_POSE) {
+ /* each bone moves on its own local axis, but to avoid confusion,
+ * use the active pones axis for display [#33575], this works as expected on a single
+ * bone and users who select many bones will understand what's going on and what local
+ * means when they start transforming */
+ ED_getTransformOrientationMatrix(C, r_mat, pivot_point);
+ }
+ else {
+ copy_m3_m4(r_mat, ob->obmat);
+ normalize_m3(r_mat);
+ }
+ return V3D_ORIENT_LOCAL;
}
-
- break;
-
- case V3D_ORIENT_VIEW:
- if ((t->spacetype == SPACE_VIEW3D) && (t->region->regiontype == RGN_TYPE_WINDOW)) {
- RegionView3D *rv3d = t->region->regiondata;
- float mat[3][3];
-
- BLI_strncpy(t->spacename, TIP_("view"), sizeof(t->spacename));
- copy_m3_m4(mat, rv3d->viewinv);
- normalize_m3(mat);
- copy_m3_m3(t->spacemtx, mat);
+ unit_m3(r_mat);
+ return V3D_ORIENT_GLOBAL;
+ }
+ case V3D_ORIENT_VIEW: {
+ if (rv3d != NULL) {
+ copy_m3_m4(r_mat, rv3d->viewinv);
+ normalize_m3(r_mat);
}
else {
- unit_m3(t->spacemtx);
+ unit_m3(r_mat);
}
- break;
+ return V3D_ORIENT_VIEW;
+ }
case V3D_ORIENT_CURSOR: {
- BLI_strncpy(t->spacename, TIP_("cursor"), sizeof(t->spacename));
- BKE_scene_cursor_rot_to_mat3(&t->scene->cursor, t->spacemtx);
- break;
+ BKE_scene_cursor_rot_to_mat3(&scene->cursor, r_mat);
+ return V3D_ORIENT_CURSOR;
}
- case V3D_ORIENT_CUSTOM_MATRIX:
- /* Already set. */
- BLI_strncpy(t->spacename, TIP_("custom"), sizeof(t->spacename));
+ case V3D_ORIENT_CUSTOM_MATRIX: {
+ /* Do nothing. */;
break;
+ }
case V3D_ORIENT_CUSTOM:
- BLI_strncpy(t->spacename, t->orientation.custom->name, sizeof(t->spacename));
-
- if (applyTransformOrientation(t->orientation.custom, t->spacemtx, t->spacename)) {
- /* pass */
- }
- else {
- unit_m3(t->spacemtx);
- }
+ default: {
+ BLI_assert(orientation_type >= V3D_ORIENT_CUSTOM);
+ TransformOrientation *custom_orientation = BKE_scene_transform_orientation_find(
+ scene, orientation_index_custom);
+ applyTransformOrientation(custom_orientation, r_mat, NULL);
break;
+ }
}
- if (t->orient_matrix_is_set == false) {
- t->orient_matrix_is_set = true;
- if (t->flag & T_MODAL) {
- /* Rotate for example defaults to operating on the view plane. */
- t->orientation.unset = V3D_ORIENT_VIEW;
- copy_m3_m4(t->orient_matrix, t->viewinv);
- normalize_m3(t->orient_matrix);
- negate_m3(t->orient_matrix);
- }
- else {
- copy_m3_m3(t->orient_matrix, t->spacemtx);
+ return orientation_type;
+}
+
+/* Sets the matrix of the specified space orientation.
+ * If the matrix cannot be obtained, an orientation different from the one
+ * informed is returned */
+short transform_orientation_matrix_get(bContext *C,
+ TransInfo *t,
+ const short orientation,
+ const float custom[3][3],
+ float r_spacemtx[3][3])
+{
+ if (orientation == V3D_ORIENT_CUSTOM_MATRIX) {
+ copy_m3_m3(r_spacemtx, custom);
+ return V3D_ORIENT_CUSTOM_MATRIX;
+ }
+
+ if ((t->spacetype == SPACE_VIEW3D) && (t->region->regiontype == RGN_TYPE_WINDOW)) {
+ Object *ob = CTX_data_active_object(C);
+ Object *obedit = CTX_data_active_object(C);
+ RegionView3D *rv3d = t->region->regiondata;
+ int orientation_index_custom = 0;
+
+ if (orientation >= V3D_ORIENT_CUSTOM) {
+ orientation_index_custom = orientation - V3D_ORIENT_CUSTOM;
}
+
+ return ED_transform_calc_orientation_from_type_ex(
+ C,
+ r_spacemtx,
+ /* extra args (can be accessed from context) */
+ t->scene,
+ rv3d,
+ ob,
+ obedit,
+ orientation,
+ orientation_index_custom,
+ t->around);
}
+
+ unit_m3(r_spacemtx);
+ return V3D_ORIENT_GLOBAL;
+}
+
+const char *transform_orientations_spacename_get(TransInfo *t, const short orient_type)
+{
+ switch (orient_type) {
+ case V3D_ORIENT_GLOBAL:
+ return TIP_("global");
+ case V3D_ORIENT_GIMBAL:
+ return TIP_("gimbal");
+ case V3D_ORIENT_NORMAL:
+ return TIP_("normal");
+ case V3D_ORIENT_LOCAL:
+ return TIP_("local");
+ case V3D_ORIENT_VIEW:
+ return TIP_("view");
+ case V3D_ORIENT_CURSOR:
+ return TIP_("cursor");
+ case V3D_ORIENT_CUSTOM_MATRIX:
+ return TIP_("custom");
+ case V3D_ORIENT_CUSTOM:
+ default:
+ BLI_assert(orient_type >= V3D_ORIENT_CUSTOM);
+ TransformOrientation *ts = BKE_scene_transform_orientation_find(
+ t->scene, orient_type - V3D_ORIENT_CUSTOM);
+ return ts->name;
+ }
+}
+
+void transform_orientations_current_set(TransInfo *t, const short orient_index)
+{
+ const short orientation = t->orient[orient_index].type;
+ const char *spacename = transform_orientations_spacename_get(t, orientation);
+
+ BLI_strncpy(t->spacename, spacename, sizeof(t->spacename));
+ copy_m3_m3(t->spacemtx, t->orient[orient_index].matrix);
+ invert_m3_m3(t->spacemtx_inv, t->spacemtx);
}
/**
* utility function - get first n, selected vert/edge/faces
*/
-static unsigned int bm_mesh_elems_select_get_n__internal(
- BMesh *bm, BMElem **elems, const unsigned int n, const BMIterType itype, const char htype)
+static uint bm_mesh_elems_select_get_n__internal(
+ BMesh *bm, BMElem **elems, const uint n, const BMIterType itype, const char htype)
{
BMIter iter;
BMElem *ele;
- unsigned int i;
+ uint i;
BLI_assert(ELEM(htype, BM_VERT, BM_EDGE, BM_FACE));
BLI_assert(ELEM(itype, BM_VERTS_OF_MESH, BM_EDGES_OF_MESH, BM_FACES_OF_MESH));
@@ -579,18 +668,18 @@ static unsigned int bm_mesh_elems_select_get_n__internal(
return i;
}
-static unsigned int bm_mesh_verts_select_get_n(BMesh *bm, BMVert **elems, const unsigned int n)
+static uint bm_mesh_verts_select_get_n(BMesh *bm, BMVert **elems, const uint n)
{
return bm_mesh_elems_select_get_n__internal(
bm, (BMElem **)elems, min_ii(n, bm->totvertsel), BM_VERTS_OF_MESH, BM_VERT);
}
-static unsigned int bm_mesh_edges_select_get_n(BMesh *bm, BMEdge **elems, const unsigned int n)
+static uint bm_mesh_edges_select_get_n(BMesh *bm, BMEdge **elems, const uint n)
{
return bm_mesh_elems_select_get_n__internal(
bm, (BMElem **)elems, min_ii(n, bm->totedgesel), BM_EDGES_OF_MESH, BM_EDGE);
}
#if 0
-static unsigned int bm_mesh_faces_select_get_n(BMesh *bm, BMVert **elems, const unsigned int n)
+static uint bm_mesh_faces_select_get_n(BMesh *bm, BMVert **elems, const uint n)
{
return bm_mesh_elems_select_get_n__internal(
bm, (BMElem **)elems, min_ii(n, bm->totfacesel), BM_FACES_OF_MESH, BM_FACE);
@@ -859,7 +948,7 @@ int getTransformOrientation_ex(const bContext *C,
}
}
else {
- const bool use_handle = (v3d->overlay.edit_flag & V3D_OVERLAY_EDIT_CU_HANDLES) != 0;
+ const bool use_handle = v3d->overlay.handle_display != CURVE_HANDLE_NONE;
for (nu = nurbs->first; nu; nu = nu->next) {
/* only bezier has a normal */
@@ -1071,10 +1160,9 @@ int getTransformOrientation_ex(const bContext *C,
ok = true;
}
else {
- int totsel;
-
- totsel = count_bone_select(arm, &arm->bonebase, true);
- if (totsel) {
+ int transformed_len;
+ transformed_len = armature_bone_transflags_update_recursive(arm, &arm->bonebase, true);
+ if (transformed_len) {
/* use channels to get stats */
for (pchan = ob->pose->chanbase.first; pchan; pchan = pchan->next) {
if (pchan->bone && pchan->bone->flag & BONE_TRANSFORM) {
diff --git a/source/blender/editors/transform/transform_snap.c b/source/blender/editors/transform/transform_snap.c
index 86e99c986f8..82602e7d828 100644
--- a/source/blender/editors/transform/transform_snap.c
+++ b/source/blender/editors/transform/transform_snap.c
@@ -44,8 +44,8 @@
#include "GPU_immediate.h"
#include "GPU_state.h"
-#include "BKE_anim.h" /* for duplis */
#include "BKE_context.h"
+#include "BKE_duplilist.h"
#include "BKE_editmesh.h"
#include "BKE_layer.h"
#include "BKE_main.h"
@@ -56,6 +56,7 @@
#include "WM_types.h"
+#include "ED_gizmo_library.h"
#include "ED_image.h"
#include "ED_markers.h"
#include "ED_node.h"
@@ -158,7 +159,7 @@ static bool doForceIncrementSnap(const TransInfo *t)
void drawSnapping(const struct bContext *C, TransInfo *t)
{
- unsigned char col[4], selectedCol[4], activeCol[4];
+ uchar col[4], selectedCol[4], activeCol[4];
if (!activeSnap(t)) {
return;
@@ -178,99 +179,53 @@ void drawSnapping(const struct bContext *C, TransInfo *t)
(t->scene->toolsettings->snap_mode & SCE_SNAP_MODE_EDGE_PERPENDICULAR);
if (draw_target || validSnap(t)) {
- TransSnapPoint *p;
- RegionView3D *rv3d = CTX_wm_region_view3d(C);
- float imat[4][4];
- float size;
+ const float *loc_cur = NULL;
+ const float *loc_prev = NULL;
+ const float *normal = NULL;
GPU_depth_test(false);
- size = 2.5f * UI_GetThemeValuef(TH_VERTEX_SIZE);
+ RegionView3D *rv3d = CTX_wm_region_view3d(C);
+ if (!BLI_listbase_is_empty(&t->tsnap.points)) {
+ /* Draw snap points. */
- invert_m4_m4(imat, rv3d->viewmat);
+ float size = 2.0f * UI_GetThemeValuef(TH_VERTEX_SIZE);
+ float view_inv[4][4];
+ copy_m4_m4(view_inv, rv3d->viewinv);
- uint pos = GPU_vertformat_attr_add(
- immVertexFormat(), "pos", GPU_COMP_F32, 3, GPU_FETCH_FLOAT);
+ uint pos = GPU_vertformat_attr_add(
+ immVertexFormat(), "pos", GPU_COMP_F32, 3, GPU_FETCH_FLOAT);
- immBindBuiltinProgram(GPU_SHADER_3D_UNIFORM_COLOR);
+ immBindBuiltinProgram(GPU_SHADER_3D_UNIFORM_COLOR);
- for (p = t->tsnap.points.first; p; p = p->next) {
- if (p == t->tsnap.selectedPoint) {
- immUniformColor4ubv(selectedCol);
- }
- else {
- immUniformColor4ubv(col);
+ LISTBASE_FOREACH (TransSnapPoint *, p, &t->tsnap.points) {
+ if (p == t->tsnap.selectedPoint) {
+ immUniformColor4ubv(selectedCol);
+ }
+ else {
+ immUniformColor4ubv(col);
+ }
+ imm_drawcircball(p->co, ED_view3d_pixel_size(rv3d, p->co) * size, view_inv, pos);
}
- imm_drawcircball(p->co, ED_view3d_pixel_size(rv3d, p->co) * size * 0.75f, imat, pos);
- }
-
- if (t->tsnap.status & POINT_INIT) {
- immUniformColor4ubv(activeCol);
-
- imm_drawcircball(
- t->tsnap.snapPoint, ED_view3d_pixel_size(rv3d, t->tsnap.snapPoint) * size, imat, pos);
+ immUnbindProgram();
}
/* draw normal if needed */
if (usingSnappingNormal(t) && validSnappingNormal(t)) {
- immUniformColor4ubv(activeCol);
-
- immBegin(GPU_PRIM_LINES, 2);
- immVertex3f(pos, t->tsnap.snapPoint[0], t->tsnap.snapPoint[1], t->tsnap.snapPoint[2]);
- immVertex3f(pos,
- t->tsnap.snapPoint[0] + t->tsnap.snapNormal[0],
- t->tsnap.snapPoint[1] + t->tsnap.snapNormal[1],
- t->tsnap.snapPoint[2] + t->tsnap.snapNormal[2]);
- immEnd();
+ normal = t->tsnap.snapNormal;
}
if (draw_target) {
- /* Draw snapTarget */
- float targ_co[3], vx[3], vy[3], v1[3], v2[3], v3[3], v4[4];
- copy_v3_v3(targ_co, t->tsnap.snapTarget);
- float px_size = 0.75f * size * ED_view3d_pixel_size(rv3d, targ_co);
-
- mul_v3_v3fl(vx, imat[0], px_size);
- mul_v3_v3fl(vy, imat[1], px_size);
-
- add_v3_v3v3(v1, vx, vy);
- sub_v3_v3v3(v2, vx, vy);
- negate_v3_v3(v3, v1);
- negate_v3_v3(v4, v2);
-
- add_v3_v3(v1, targ_co);
- add_v3_v3(v2, targ_co);
- add_v3_v3(v3, targ_co);
- add_v3_v3(v4, targ_co);
-
- immUniformColor4ubv(col);
- immBegin(GPU_PRIM_LINES, 4);
- immVertex3fv(pos, v3);
- immVertex3fv(pos, v1);
- immVertex3fv(pos, v4);
- immVertex3fv(pos, v2);
- immEnd();
-
- if (t->tsnap.snapElem & SCE_SNAP_MODE_EDGE_PERPENDICULAR) {
- immUnbindProgram();
-
- immBindBuiltinProgram(GPU_SHADER_3D_LINE_DASHED_UNIFORM_COLOR);
- float viewport_size[4];
- GPU_viewport_size_get_f(viewport_size);
- immUniform2f("viewport_size", viewport_size[2], viewport_size[3]);
- immUniform1f("dash_width", 6.0f * U.pixelsize);
- immUniform1f("dash_factor", 1.0f / 4.0f);
- immUniformColor4ubv(col);
+ loc_prev = t->tsnap.snapTarget;
+ }
- immBegin(GPU_PRIM_LINES, 2);
- immVertex3fv(pos, targ_co);
- immVertex3fv(pos, t->tsnap.snapPoint);
- immEnd();
- }
+ if (validSnap(t)) {
+ loc_cur = t->tsnap.snapPoint;
}
- immUnbindProgram();
+ ED_gizmotypes_snap_3d_draw_util(
+ rv3d, loc_prev, loc_cur, normal, col, activeCol, t->tsnap.snapElem);
GPU_depth_test(true);
}
@@ -351,11 +306,6 @@ void applyProject(TransInfo *t)
for (i = 0; i < tc->data_len; i++, td++) {
float iloc[3], loc[3], no[3];
float mval_fl[2];
-
- if (td->flag & TD_NOACTION) {
- break;
- }
-
if (td->flag & TD_SKIP) {
continue;
}
@@ -462,11 +412,6 @@ void applyGridAbsolute(TransInfo *t)
for (i = 0, td = tc->data; i < tc->data_len; i++, td++) {
float iloc[3], loc[3], tvec[3];
-
- if (td->flag & TD_NOACTION) {
- break;
- }
-
if (td->flag & TD_SKIP) {
continue;
}
@@ -590,7 +535,6 @@ static bool bm_face_is_snap_target(BMFace *f, void *UNUSED(user_data))
static void initSnappingMode(TransInfo *t)
{
- Main *bmain = CTX_data_main(t->context);
ToolSettings *ts = t->settings;
/* All obedit types will match. */
const int obedit_type = t->data_container->obedit ? t->data_container->obedit->type : -1;
@@ -687,7 +631,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(
- bmain, t->scene, 0, t->region, t->view);
+ t->scene, 0, t->region, t->view);
ED_transform_snap_object_context_set_editmesh_callbacks(
t->tsnap.object_context,
@@ -1106,7 +1050,6 @@ static void CalcSnapGeometry(TransInfo *t, float *UNUSED(vec))
}
else if (t->spacetype == SPACE_IMAGE && t->obedit_type == OB_MESH) {
if (t->tsnap.mode & SCE_SNAP_MODE_VERTEX) {
- Image *ima = ED_space_image(t->sa->spacedata.first);
float co[2];
UI_view2d_region_to_view(&t->region->v2d, t->mval[0], t->mval[1], &co[0], &co[1]);
@@ -1117,7 +1060,7 @@ static void CalcSnapGeometry(TransInfo *t, float *UNUSED(vec))
float dist_sq = FLT_MAX;
if (ED_uvedit_nearest_uv_multi(
- t->scene, ima, objects, objects_len, co, &dist_sq, t->tsnap.snapPoint)) {
+ t->scene, objects, objects_len, co, &dist_sq, t->tsnap.snapPoint)) {
t->tsnap.snapPoint[0] *= t->aspect[0];
t->tsnap.snapPoint[1] *= t->aspect[1];
@@ -1581,7 +1524,7 @@ bool snapNodesTransform(
TransInfo *t, const int mval[2], float r_loc[2], float *r_dist_px, char *r_node_border)
{
return snapNodes(t->settings,
- t->sa->spacedata.first,
+ t->area->spacedata.first,
t->region,
mval,
t->tsnap.modeSelect,
@@ -1716,7 +1659,7 @@ static void applyGridIncrement(
if (t->spacetype == SPACE_GRAPH) {
View2D *v2d = &t->region->v2d;
Scene *scene = t->scene;
- SpaceGraph *sipo = t->sa->spacedata.first;
+ SpaceGraph *sipo = t->area->spacedata.first;
asp_local[0] = UI_view2d_grid_resolution_x__frames_or_seconds(
v2d, scene, sipo->flag & SIPO_DRAWTIME);
asp_local[1] = UI_view2d_grid_resolution_y__values(v2d);
@@ -1750,8 +1693,8 @@ static void applyGridIncrement(
float local_axis[3];
float pos_on_axis[3];
- copy_v3_v3(local_axis, t->con.mtx[i]);
- copy_v3_v3(pos_on_axis, t->con.mtx[i]);
+ copy_v3_v3(local_axis, t->spacemtx[i]);
+ copy_v3_v3(pos_on_axis, t->spacemtx[i]);
/* amount of movement on axis from initial pos */
mul_v3_fl(pos_on_axis, val[i]);
diff --git a/source/blender/editors/transform/transform_snap_object.c b/source/blender/editors/transform/transform_snap_object.c
index f55c73fd15e..c30b8d59dc0 100644
--- a/source/blender/editors/transform/transform_snap_object.c
+++ b/source/blender/editors/transform/transform_snap_object.c
@@ -38,10 +38,10 @@
#include "DNA_screen_types.h"
#include "DNA_view3d_types.h"
-#include "BKE_anim.h" /* for duplis */
#include "BKE_armature.h"
#include "BKE_bvhutils.h"
#include "BKE_curve.h"
+#include "BKE_duplilist.h"
#include "BKE_editmesh.h"
#include "BKE_layer.h"
#include "BKE_main.h"
@@ -104,13 +104,12 @@ typedef struct SnapObjectData {
/* SNAP_EDIT_MESH */
BVHTreeFromEditMesh treedata_editmesh;
float min[3], max[3];
- struct LinkNode **bvh_cache_p;
+ struct Mesh_Runtime *mesh_runtime;
};
};
} SnapObjectData;
struct SnapObjectContext {
- Main *bmain;
Scene *scene;
int flag;
@@ -145,6 +144,17 @@ struct SnapObjectContext {
/** \} */
/* -------------------------------------------------------------------- */
+/** \name Utilities
+ * \{ */
+
+static bool editmesh_eval_final_is_bmesh(const BMEditMesh *em)
+{
+ return (em->mesh_eval_final->runtime.wrapper_type == ME_WRAPPER_TYPE_BMESH);
+}
+
+/** \} */
+
+/* -------------------------------------------------------------------- */
/** \name Snap Object Data
* \{ */
@@ -245,17 +255,17 @@ static SnapObjectData *snap_object_data_mesh_get(SnapObjectContext *sctx, Object
return sod;
}
-static struct LinkNode **snap_object_data_editmesh_bvh_cache_get(Object *ob)
+static struct Mesh_Runtime *snap_object_data_editmesh_runtime_get(Object *ob)
{
BMEditMesh *em = BKE_editmesh_from_object(ob);
if (em->mesh_eval_final) {
- return &em->mesh_eval_final->runtime.bvh_cache;
+ return &em->mesh_eval_final->runtime;
}
if (em->mesh_eval_cage) {
- return &em->mesh_eval_cage->runtime.bvh_cache;
+ return &em->mesh_eval_cage->runtime;
}
- return &((Mesh *)ob->data)->runtime.bvh_cache;
+ return &((Mesh *)ob->data)->runtime;
}
static SnapObjectData *snap_object_data_editmesh_get(SnapObjectContext *sctx,
@@ -292,23 +302,23 @@ static SnapObjectData *snap_object_data_editmesh_get(SnapObjectContext *sctx,
clear_cache = true;
init = true;
}
- else if (sod->bvh_cache_p) {
- if (sod->bvh_cache_p != snap_object_data_editmesh_bvh_cache_get(ob)) {
+ else if (sod->mesh_runtime) {
+ if (sod->mesh_runtime != snap_object_data_editmesh_runtime_get(ob)) {
clear_cache = true;
init = true;
}
else if (sod->treedata_editmesh.tree && sod->treedata_editmesh.cached &&
- !bvhcache_has_tree(*sod->bvh_cache_p, sod->treedata_editmesh.tree)) {
+ !bvhcache_has_tree(sod->mesh_runtime->bvh_cache, sod->treedata_editmesh.tree)) {
/* The tree is owned by the EditMesh and may have been freed since we last used! */
clear = true;
}
else if (sod->bvhtree[0] && sod->cached[0] &&
- !bvhcache_has_tree(*sod->bvh_cache_p, sod->bvhtree[0])) {
+ !bvhcache_has_tree(sod->mesh_runtime->bvh_cache, sod->bvhtree[0])) {
/* The tree is owned by the EditMesh and may have been freed since we last used! */
clear = true;
}
else if (sod->bvhtree[1] && sod->cached[1] &&
- !bvhcache_has_tree(*sod->bvh_cache_p, sod->bvhtree[1])) {
+ !bvhcache_has_tree(sod->mesh_runtime->bvh_cache, sod->bvhtree[1])) {
/* The tree is owned by the EditMesh and may have been freed since we last used! */
clear = true;
}
@@ -347,7 +357,7 @@ static SnapObjectData *snap_object_data_editmesh_get(SnapObjectContext *sctx,
bm_mesh_minmax(em->bm, sod->min, sod->max);
}
- sod->bvh_cache_p = snap_object_data_editmesh_bvh_cache_get(ob);
+ sod->mesh_runtime = snap_object_data_editmesh_runtime_get(ob);
}
return sod;
@@ -360,7 +370,7 @@ static SnapObjectData *snap_object_data_editmesh_get(SnapObjectContext *sctx,
* \{ */
typedef void (*IterSnapObjsCallback)(SnapObjectContext *sctx,
- bool is_obedit,
+ bool use_obedit,
bool use_backface_culling,
Object *ob,
float obmat[4][4],
@@ -447,7 +457,7 @@ struct RayCastAll_Data {
float local_scale;
Object *ob;
- unsigned int ob_uuid;
+ uint ob_uuid;
/* output data */
ListBase *hit_list;
@@ -460,7 +470,7 @@ static struct SnapObjectHitDepth *hit_depth_create(const float depth,
int index,
Object *ob,
const float obmat[4][4],
- unsigned int ob_uuid)
+ uint ob_uuid)
{
struct SnapObjectHitDepth *hit = MEM_mallocN(sizeof(*hit), __func__);
@@ -586,7 +596,7 @@ static bool raycastMesh(SnapObjectContext *sctx,
Object *ob,
Mesh *me,
const float obmat[4][4],
- const unsigned int ob_index,
+ const uint ob_index,
bool use_hide,
bool use_backface_culling,
/* read/write args */
@@ -761,7 +771,7 @@ static bool raycastEditMesh(SnapObjectContext *sctx,
Object *ob,
BMEditMesh *em,
const float obmat[4][4],
- const unsigned int ob_index,
+ const uint ob_index,
bool use_backface_culling,
/* read/write args */
float *ray_depth,
@@ -836,14 +846,19 @@ static bool raycastEditMesh(SnapObjectContext *sctx,
sctx->callbacks.edit_mesh.user_data);
bvhtree_from_editmesh_looptri_ex(
- treedata, em, elem_mask, looptri_num_active, 0.0f, 4, 6, 0, NULL);
+ treedata, em, elem_mask, looptri_num_active, 0.0f, 4, 6, 0, NULL, NULL);
MEM_freeN(elem_mask);
}
else {
/* Only cache if bvhtree is created without a mask.
* This helps keep a standardized bvhtree in cache. */
- BKE_bvhtree_from_editmesh_get(treedata, em, 4, BVHTREE_FROM_EM_LOOPTRI, sod->bvh_cache_p);
+ BKE_bvhtree_from_editmesh_get(treedata,
+ em,
+ 4,
+ BVHTREE_FROM_EM_LOOPTRI,
+ &sod->mesh_runtime->bvh_cache,
+ sod->mesh_runtime->eval_mutex);
}
if (treedata->tree == NULL) {
@@ -921,41 +936,52 @@ static bool raycastEditMesh(SnapObjectContext *sctx,
return retval;
}
+struct RaycastObjUserData {
+ const float *ray_start;
+ const float *ray_dir;
+ uint ob_index;
+ /* read/write args */
+ float *ray_depth;
+ /* return args */
+ float *r_loc;
+ float *r_no;
+ int *r_index;
+ Object **r_ob;
+ float (*r_obmat)[4];
+ ListBase *r_hit_list;
+ bool use_occlusion_test;
+ bool ret;
+};
+
/**
* \param use_obedit: Uses the coordinates of BMesh (if any) to do the snapping;
*
* \note Duplicate args here are documented at #snapObjectsRay
*/
-static bool raycastObj(SnapObjectContext *sctx,
- const float ray_start[3],
- const float ray_dir[3],
- Object *ob,
- const float obmat[4][4],
- const unsigned int ob_index,
- bool use_obedit,
- bool use_occlusion_test,
- bool use_backface_culling,
- /* read/write args */
- float *ray_depth,
- /* return args */
- float r_loc[3],
- float r_no[3],
- int *r_index,
- Object **r_ob,
- float r_obmat[4][4],
- ListBase *r_hit_list)
+static void raycast_obj_fn(SnapObjectContext *sctx,
+ bool use_obedit,
+ bool use_backface_culling,
+ Object *ob,
+ float obmat[4][4],
+ void *data)
{
+ struct RaycastObjUserData *dt = data;
+ const uint ob_index = dt->ob_index++;
+ bool use_occlusion_test = dt->use_occlusion_test;
+ /* read/write args */
+ float *ray_depth = dt->ray_depth;
+
bool retval = false;
if (use_occlusion_test) {
if (use_obedit && sctx->use_v3d && XRAY_FLAG_ENABLED(sctx->v3d_data.v3d)) {
/* Use of occlude geometry in editing mode disabled. */
- return false;
+ return;
}
if (ELEM(ob->dt, OB_BOUNDBOX, OB_WIRE)) {
/* Do not hit objects that are in wire or bounding box
* display mode. */
- return false;
+ return;
}
}
@@ -964,22 +990,22 @@ static bool raycastObj(SnapObjectContext *sctx,
Mesh *me = ob->data;
bool use_hide = false;
if (BKE_object_is_in_editmode(ob)) {
- if (use_obedit) {
+ if (use_obedit || editmesh_eval_final_is_bmesh(me->edit_mesh)) {
/* Operators only update the editmesh looptris of the original mesh. */
BMEditMesh *em_orig = BKE_editmesh_from_object(DEG_get_original_object(ob));
retval = raycastEditMesh(sctx,
- ray_start,
- ray_dir,
+ dt->ray_start,
+ dt->ray_dir,
ob,
em_orig,
obmat,
ob_index,
use_backface_culling,
ray_depth,
- r_loc,
- r_no,
- r_index,
- r_hit_list);
+ dt->r_loc,
+ dt->r_no,
+ dt->r_index,
+ dt->r_hit_list);
break;
}
else {
@@ -991,8 +1017,8 @@ static bool raycastObj(SnapObjectContext *sctx,
}
}
retval = raycastMesh(sctx,
- ray_start,
- ray_dir,
+ dt->ray_start,
+ dt->ray_dir,
ob,
me,
obmat,
@@ -1000,10 +1026,10 @@ static bool raycastObj(SnapObjectContext *sctx,
use_hide,
use_backface_culling,
ray_depth,
- r_loc,
- r_no,
- r_index,
- r_hit_list);
+ dt->r_loc,
+ dt->r_no,
+ dt->r_index,
+ dt->r_hit_list);
break;
}
case OB_CURVE:
@@ -1012,8 +1038,8 @@ static bool raycastObj(SnapObjectContext *sctx,
Mesh *mesh_eval = BKE_object_get_evaluated_mesh(ob);
if (mesh_eval) {
retval = raycastMesh(sctx,
- ray_start,
- ray_dir,
+ dt->ray_start,
+ dt->ray_dir,
ob,
mesh_eval,
obmat,
@@ -1021,70 +1047,24 @@ static bool raycastObj(SnapObjectContext *sctx,
false,
use_backface_culling,
ray_depth,
- r_loc,
- r_no,
- r_index,
- r_hit_list);
+ dt->r_loc,
+ dt->r_no,
+ dt->r_index,
+ dt->r_hit_list);
break;
}
}
}
if (retval) {
- if (r_ob) {
- *r_ob = ob;
+ if (dt->r_ob) {
+ *dt->r_ob = ob;
}
- if (r_obmat) {
- copy_m4_m4(r_obmat, obmat);
+ if (dt->r_obmat) {
+ copy_m4_m4(dt->r_obmat, obmat);
}
- return true;
+ dt->ret = true;
}
-
- return false;
-}
-
-struct RaycastObjUserData {
- const float *ray_start;
- const float *ray_dir;
- unsigned int ob_index;
- /* read/write args */
- float *ray_depth;
- /* return args */
- float *r_loc;
- float *r_no;
- int *r_index;
- Object **r_ob;
- float (*r_obmat)[4];
- ListBase *r_hit_list;
- bool use_occlusion_test;
- bool ret;
-};
-
-static void raycast_obj_cb(SnapObjectContext *sctx,
- bool use_obedit,
- bool use_backface_culling,
- Object *ob,
- float obmat[4][4],
- void *data)
-{
- struct RaycastObjUserData *dt = data;
-
- dt->ret |= raycastObj(sctx,
- dt->ray_start,
- dt->ray_dir,
- ob,
- obmat,
- dt->ob_index++,
- use_obedit,
- dt->use_occlusion_test,
- use_backface_culling,
- dt->ray_depth,
- dt->r_loc,
- dt->r_no,
- dt->r_index,
- dt->r_ob,
- dt->r_obmat,
- dt->r_hit_list);
}
/**
@@ -1145,7 +1125,7 @@ static bool raycastObjects(SnapObjectContext *sctx,
.ret = false,
};
- iter_snap_objects(sctx, depsgraph, params, raycast_obj_cb, &data);
+ iter_snap_objects(sctx, depsgraph, params, raycast_obj_fn, &data);
return data.ret;
}
@@ -1227,7 +1207,7 @@ static void cb_mlooptri_edges_get(const int index, int v_index[3], const BVHTree
const MLoopTri *lt = &data->looptri[index];
for (int j = 2, j_next = 0; j_next < 3; j = j_next++) {
const MEdge *ed = &medge[mloop[lt->tri[j]].e];
- unsigned int tri_edge[2] = {mloop[lt->tri[j]].v, mloop[lt->tri[j_next]].v};
+ uint tri_edge[2] = {mloop[lt->tri[j]].v, mloop[lt->tri[j_next]].v};
if (ELEM(ed->v1, tri_edge[0], tri_edge[1]) && ELEM(ed->v2, tri_edge[0], tri_edge[1])) {
// printf("real edge found\n");
v_index[j] = mloop[lt->tri[j]].e;
@@ -1707,8 +1687,14 @@ static short snap_mesh_edge_verts_mixed(SnapObjectContext *sctx,
&nearest.dist_sq,
nearest.co)) {
nearest.index = vindex[v_id];
- nearest2d.copy_vert_no(vindex[v_id], nearest.no, nearest2d.userdata);
elem = SCE_SNAP_MODE_VERTEX;
+ if (r_no) {
+ float imat[4][4];
+ invert_m4_m4(imat, obmat);
+ nearest2d.copy_vert_no(vindex[v_id], r_no, nearest2d.userdata);
+ mul_transposed_mat3_m4_v3(imat, r_no);
+ normalize_v3(r_no);
+ }
}
}
}
@@ -1726,10 +1712,6 @@ static short snap_mesh_edge_verts_mixed(SnapObjectContext *sctx,
vmid,
&nearest.dist_sq,
nearest.co)) {
- float v_nor[2][3];
- nearest2d.copy_vert_no(vindex[0], v_nor[0], nearest2d.userdata);
- nearest2d.copy_vert_no(vindex[1], v_nor[1], nearest2d.userdata);
- mid_v3_v3v3(nearest.no, v_nor[0], v_nor[1]);
nearest.index = *r_index;
elem = SCE_SNAP_MODE_EDGE_MIDPOINT;
}
@@ -1757,11 +1739,6 @@ static short snap_mesh_edge_verts_mixed(SnapObjectContext *sctx,
v_near,
&nearest.dist_sq,
nearest.co)) {
- float v_nor[2][3];
- nearest2d.copy_vert_no(vindex[0], v_nor[0], nearest2d.userdata);
- nearest2d.copy_vert_no(vindex[1], v_nor[1], nearest2d.userdata);
- mid_v3_v3v3(nearest.no, v_nor[0], v_nor[1]);
-
nearest.index = *r_index;
elem = SCE_SNAP_MODE_EDGE_PERPENDICULAR;
}
@@ -1778,15 +1755,6 @@ static short snap_mesh_edge_verts_mixed(SnapObjectContext *sctx,
mul_m4_v3(obmat, r_loc);
}
- if (r_no) {
- float imat[4][4];
- invert_m4_m4(imat, obmat);
-
- copy_v3_v3(r_no, nearest.no);
- mul_transposed_mat3_m4_v3(imat, r_no);
- normalize_v3(r_no);
- }
-
*r_index = nearest.index;
}
@@ -1838,7 +1806,7 @@ static short snapArmature(SnapData *snapdata,
bArmature *arm = ob->data;
if (arm->edbo) {
- for (EditBone *eBone = arm->edbo->first; eBone; eBone = eBone->next) {
+ LISTBASE_FOREACH (EditBone *, eBone, arm->edbo) {
if (eBone->layer & arm->layer) {
/* skip hidden or moving (selected) bones */
if ((eBone->flag & (BONE_HIDDEN_A | BONE_ROOTSEL | BONE_TIPSEL)) == 0) {
@@ -1881,7 +1849,7 @@ static short snapArmature(SnapData *snapdata,
}
}
else if (ob->pose && ob->pose->chanbase.first) {
- for (bPoseChannel *pchan = ob->pose->chanbase.first; pchan; pchan = pchan->next) {
+ LISTBASE_FOREACH (bPoseChannel *, pchan, &ob->pose->chanbase) {
Bone *bone = pchan->bone;
/* skip hidden bones */
if (bone && !(bone->flag & (BONE_HIDDEN_P | BONE_HIDDEN_PG))) {
@@ -2537,11 +2505,16 @@ static short snapEditMesh(SnapObjectContext *sctx,
sctx->callbacks.edit_mesh.user_data);
bvhtree_from_editmesh_verts_ex(
- &treedata, em, verts_mask, verts_num_active, 0.0f, 2, 6, 0, NULL);
+ &treedata, em, verts_mask, verts_num_active, 0.0f, 2, 6, 0, NULL, NULL);
MEM_freeN(verts_mask);
}
else {
- BKE_bvhtree_from_editmesh_get(&treedata, em, 2, BVHTREE_FROM_EM_VERTS, sod->bvh_cache_p);
+ BKE_bvhtree_from_editmesh_get(&treedata,
+ em,
+ 2,
+ BVHTREE_FROM_EM_VERTS,
+ &sod->mesh_runtime->bvh_cache,
+ (ThreadMutex *)sod->mesh_runtime->eval_mutex);
}
sod->bvhtree[0] = treedata.tree;
sod->cached[0] = treedata.cached;
@@ -2564,11 +2537,16 @@ static short snapEditMesh(SnapObjectContext *sctx,
sctx->callbacks.edit_mesh.user_data);
bvhtree_from_editmesh_edges_ex(
- &treedata, em, edges_mask, edges_num_active, 0.0f, 2, 6, 0, NULL);
+ &treedata, em, edges_mask, edges_num_active, 0.0f, 2, 6, 0, NULL, NULL);
MEM_freeN(edges_mask);
}
else {
- BKE_bvhtree_from_editmesh_get(&treedata, em, 2, BVHTREE_FROM_EM_EDGES, sod->bvh_cache_p);
+ BKE_bvhtree_from_editmesh_get(&treedata,
+ em,
+ 2,
+ BVHTREE_FROM_EM_EDGES,
+ &sod->mesh_runtime->bvh_cache,
+ sod->mesh_runtime->eval_mutex);
}
sod->bvhtree[1] = treedata.tree;
sod->cached[1] = treedata.cached;
@@ -2657,45 +2635,51 @@ static short snapEditMesh(SnapObjectContext *sctx,
return 0;
}
+struct SnapObjUserData {
+ SnapData *snapdata;
+ /* read/write args */
+ float *dist_px;
+ /* return args */
+ float *r_loc;
+ float *r_no;
+ int *r_index;
+ Object **r_ob;
+ float (*r_obmat)[4];
+ short ret;
+};
+
/**
* \param use_obedit: Uses the coordinates of BMesh (if any) to do the snapping;
*
* \note Duplicate args here are documented at #snapObjectsRay
*/
-static short snapObject(SnapObjectContext *sctx,
- SnapData *snapdata,
- Object *ob,
- float obmat[4][4],
+static void sanp_obj_fn(SnapObjectContext *sctx,
bool use_obedit,
bool use_backface_culling,
- /* read/write args */
- float *dist_px,
- /* return args */
- float r_loc[3],
- float r_no[3],
- int *r_index,
- Object **r_ob,
- float r_obmat[4][4])
+ Object *ob,
+ float obmat[4][4],
+ void *data)
{
+ struct SnapObjUserData *dt = data;
short retval = 0;
switch (ob->type) {
case OB_MESH: {
Mesh *me = ob->data;
if (BKE_object_is_in_editmode(ob)) {
- if (use_obedit) {
+ if (use_obedit || editmesh_eval_final_is_bmesh(me->edit_mesh)) {
/* Operators only update the editmesh looptris of the original mesh. */
BMEditMesh *em_orig = BKE_editmesh_from_object(DEG_get_original_object(ob));
retval = snapEditMesh(sctx,
- snapdata,
+ dt->snapdata,
ob,
em_orig,
obmat,
use_backface_culling,
- dist_px,
- r_loc,
- r_no,
- r_index);
+ dt->dist_px,
+ dt->r_loc,
+ dt->r_no,
+ dt->r_index);
break;
}
else {
@@ -2707,99 +2691,66 @@ static short snapObject(SnapObjectContext *sctx,
}
else if (ob->dt == OB_BOUNDBOX) {
/* Do not snap to objects that are in bounding box display mode */
- return 0;
+ return;
}
- retval = snapMesh(
- sctx, snapdata, ob, me, obmat, use_backface_culling, dist_px, r_loc, r_no, r_index);
+ retval = snapMesh(sctx,
+ dt->snapdata,
+ ob,
+ me,
+ obmat,
+ use_backface_culling,
+ dt->dist_px,
+ dt->r_loc,
+ dt->r_no,
+ dt->r_index);
break;
}
case OB_ARMATURE:
- retval = snapArmature(snapdata, ob, obmat, use_obedit, dist_px, r_loc, r_no, r_index);
+ retval = snapArmature(
+ dt->snapdata, ob, obmat, use_obedit, dt->dist_px, dt->r_loc, dt->r_no, dt->r_index);
break;
case OB_CURVE:
- retval = snapCurve(snapdata, ob, obmat, use_obedit, dist_px, r_loc, r_no, r_index);
+ retval = snapCurve(
+ dt->snapdata, ob, obmat, use_obedit, dt->dist_px, dt->r_loc, dt->r_no, dt->r_index);
break; /* Use ATTR_FALLTHROUGH if we want to snap to the generated mesh. */
case OB_SURF:
case OB_FONT: {
Mesh *mesh_eval = BKE_object_get_evaluated_mesh(ob);
if (mesh_eval) {
retval |= snapMesh(sctx,
- snapdata,
+ dt->snapdata,
ob,
mesh_eval,
obmat,
use_backface_culling,
- dist_px,
- r_loc,
- r_no,
- r_index);
+ dt->dist_px,
+ dt->r_loc,
+ dt->r_no,
+ dt->r_index);
}
break;
}
case OB_EMPTY:
- retval = snapEmpty(snapdata, ob, obmat, dist_px, r_loc, r_no, r_index);
+ retval = snapEmpty(dt->snapdata, ob, obmat, dt->dist_px, dt->r_loc, dt->r_no, dt->r_index);
break;
case OB_GPENCIL:
- retval = snapEmpty(snapdata, ob, obmat, dist_px, r_loc, r_no, r_index);
+ retval = snapEmpty(dt->snapdata, ob, obmat, dt->dist_px, dt->r_loc, dt->r_no, dt->r_index);
break;
case OB_CAMERA:
- retval = snapCamera(sctx, snapdata, ob, obmat, dist_px, r_loc, r_no, r_index);
+ retval = snapCamera(
+ sctx, dt->snapdata, ob, obmat, dt->dist_px, dt->r_loc, dt->r_no, dt->r_index);
break;
}
if (retval) {
- if (r_ob) {
- *r_ob = ob;
+ if (dt->r_ob) {
+ *dt->r_ob = ob;
}
- if (r_obmat) {
- copy_m4_m4(r_obmat, obmat);
+ if (dt->r_obmat) {
+ copy_m4_m4(dt->r_obmat, obmat);
}
- return retval;
- }
-
- return 0;
-}
-
-struct SnapObjUserData {
- SnapData *snapdata;
- /* read/write args */
- float *dist_px;
- /* return args */
- float *r_loc;
- float *r_no;
- int *r_index;
- Object **r_ob;
- float (*r_obmat)[4];
- short ret;
-};
-
-static void sanp_obj_cb(SnapObjectContext *sctx,
- bool is_obedit,
- bool use_backface_culling,
- Object *ob,
- float obmat[4][4],
- void *data)
-{
- struct SnapObjUserData *dt = data;
-
- short elem = snapObject(sctx,
- dt->snapdata,
- ob,
- obmat,
- is_obedit,
- use_backface_culling,
- /* read/write args */
- dt->dist_px,
- /* return args */
- dt->r_loc,
- dt->r_no,
- dt->r_index,
- dt->r_ob,
- dt->r_obmat);
-
- if (elem) {
- dt->ret = elem;
+ dt->ret = retval;
}
}
@@ -2852,7 +2803,7 @@ static short snapObjectsRay(SnapObjectContext *sctx,
.ret = 0,
};
- iter_snap_objects(sctx, depsgraph, params, sanp_obj_cb, &data);
+ iter_snap_objects(sctx, depsgraph, params, sanp_obj_fn, &data);
return data.ret;
}
@@ -2863,13 +2814,12 @@ static short snapObjectsRay(SnapObjectContext *sctx,
/** \name Public Object Snapping API
* \{ */
-SnapObjectContext *ED_transform_snap_object_context_create(Main *bmain, Scene *scene, int flag)
+SnapObjectContext *ED_transform_snap_object_context_create(Scene *scene, int flag)
{
SnapObjectContext *sctx = MEM_callocN(sizeof(*sctx), __func__);
sctx->flag = flag;
- sctx->bmain = bmain;
sctx->scene = scene;
sctx->cache.object_map = BLI_ghash_ptr_new(__func__);
@@ -2880,14 +2830,13 @@ SnapObjectContext *ED_transform_snap_object_context_create(Main *bmain, Scene *s
return sctx;
}
-SnapObjectContext *ED_transform_snap_object_context_create_view3d(Main *bmain,
- Scene *scene,
+SnapObjectContext *ED_transform_snap_object_context_create_view3d(Scene *scene,
int flag,
/* extra args for view3d */
const ARegion *region,
const View3D *v3d)
{
- SnapObjectContext *sctx = ED_transform_snap_object_context_create(bmain, scene, flag);
+ SnapObjectContext *sctx = ED_transform_snap_object_context_create(scene, flag);
sctx->use_v3d = true;
sctx->v3d_data.region = region;
@@ -3049,7 +2998,7 @@ bool ED_transform_snap_object_project_ray(SnapObjectContext *sctx,
static short transform_snap_context_project_view3d_mixed_impl(
SnapObjectContext *sctx,
Depsgraph *depsgraph,
- const unsigned short snap_to_flag,
+ const ushort snap_to_flag,
const struct SnapObjectParams *params,
const float mval[2],
const float prev_co[3],
@@ -3225,7 +3174,7 @@ static short transform_snap_context_project_view3d_mixed_impl(
short ED_transform_snap_object_project_view3d_ex(SnapObjectContext *sctx,
Depsgraph *depsgraph,
- const unsigned short snap_to,
+ const ushort snap_to,
const struct SnapObjectParams *params,
const float mval[2],
const float prev_co[3],
@@ -3265,7 +3214,7 @@ short ED_transform_snap_object_project_view3d_ex(SnapObjectContext *sctx,
*/
bool ED_transform_snap_object_project_view3d(SnapObjectContext *sctx,
Depsgraph *depsgraph,
- const unsigned short snap_to,
+ const ushort snap_to,
const struct SnapObjectParams *params,
const float mval[2],
const float prev_co[3],
diff --git a/source/blender/editors/undo/ed_undo.c b/source/blender/editors/undo/ed_undo.c
index 123fd5f35da..6633e1c427c 100644
--- a/source/blender/editors/undo/ed_undo.c
+++ b/source/blender/editors/undo/ed_undo.c
@@ -79,15 +79,26 @@ static CLG_LogRef LOG = {"ed.undo"};
void ED_undo_push(bContext *C, const char *str)
{
CLOG_INFO(&LOG, 1, "name='%s'", str);
+ WM_file_tag_modified();
- const int steps = U.undosteps;
-
+ wmWindowManager *wm = CTX_wm_manager(C);
+ int steps = U.undosteps;
+
+ /* Ensure steps that have been initialized are always pushed,
+ * even when undo steps are zero.
+ *
+ * Note that some modes (paint, sculpt) initialize an undo step before an action runs,
+ * then accumulate changes there, or restore data from it in the case of 2D painting.
+ *
+ * For this reason we need to handle the undo step even when undo steps is set to zero.
+ */
+ if ((steps <= 0) && wm->undo_stack->step_init != NULL) {
+ steps = 1;
+ }
if (steps <= 0) {
return;
}
- wmWindowManager *wm = CTX_wm_manager(C);
-
/* Only apply limit if this is the last undo step. */
if (wm->undo_stack->step_active && (wm->undo_stack->step_active->next == NULL)) {
BKE_undosys_stack_limit_steps_and_memory(wm->undo_stack, steps - 1, 0);
@@ -97,14 +108,12 @@ void ED_undo_push(bContext *C, const char *str)
if (U.undomemory != 0) {
const size_t memory_limit = (size_t)U.undomemory * 1024 * 1024;
- BKE_undosys_stack_limit_steps_and_memory(wm->undo_stack, 0, memory_limit);
+ BKE_undosys_stack_limit_steps_and_memory(wm->undo_stack, -1, memory_limit);
}
if (CLOG_CHECK(&LOG, 1)) {
BKE_undosys_print(wm->undo_stack);
}
-
- WM_file_tag_modified();
}
/**
@@ -119,7 +128,7 @@ static int ed_undo_step_impl(
CLOG_INFO(&LOG, 1, "name='%s', step=%d", undoname, step);
wmWindowManager *wm = CTX_wm_manager(C);
Scene *scene = CTX_data_scene(C);
- ScrArea *sa = CTX_wm_area(C);
+ ScrArea *area = CTX_wm_area(C);
/* undo during jobs are running can easily lead to freeing data using by jobs,
* or they can just lead to freezing job in some other cases */
@@ -138,7 +147,7 @@ static int ed_undo_step_impl(
if (ED_gpencil_session_active()) {
return ED_undo_gpencil_step(C, step, undoname);
}
- if (sa && (sa->spacetype == SPACE_VIEW3D)) {
+ if (area && (area->spacetype == SPACE_VIEW3D)) {
Object *obact = CTX_data_active_object(C);
if (obact && (obact->type == OB_GPENCIL)) {
ED_gpencil_toggle_brush_cursor(C, false, NULL);
@@ -195,7 +204,7 @@ static int ed_undo_step_impl(
}
/* Set special modes for grease pencil */
- if (sa && (sa->spacetype == SPACE_VIEW3D)) {
+ if (area && (area->spacetype == SPACE_VIEW3D)) {
Object *obact = CTX_data_active_object(C);
if (obact && (obact->type == OB_GPENCIL)) {
/* set cursor */
@@ -558,11 +567,11 @@ int ED_undo_operator_repeat(bContext *C, wmOperator *op)
struct Scene *scene = CTX_data_scene(C);
/* keep in sync with logic in view3d_panel_operator_redo() */
- ARegion *ar_orig = CTX_wm_region(C);
- ARegion *ar_win = BKE_area_find_region_active_win(CTX_wm_area(C));
+ ARegion *region_orig = CTX_wm_region(C);
+ ARegion *region_win = BKE_area_find_region_active_win(CTX_wm_area(C));
- if (ar_win) {
- CTX_wm_region_set(C, ar_win);
+ if (region_win) {
+ CTX_wm_region_set(C, region_win);
}
if ((WM_operator_repeat_check(C, op)) && (WM_operator_poll(C, op->type)) &&
@@ -585,9 +594,9 @@ int ED_undo_operator_repeat(bContext *C, wmOperator *op)
if (op->type->check) {
if (op->type->check(C, op)) {
/* check for popup and re-layout buttons */
- ARegion *ar_menu = CTX_wm_menu(C);
- if (ar_menu) {
- ED_region_tag_refresh_ui(ar_menu);
+ ARegion *region_menu = CTX_wm_menu(C);
+ if (region_menu) {
+ ED_region_tag_refresh_ui(region_menu);
}
}
}
@@ -610,7 +619,7 @@ int ED_undo_operator_repeat(bContext *C, wmOperator *op)
}
/* set region back */
- CTX_wm_region_set(C, ar_orig);
+ CTX_wm_region_set(C, region_orig);
}
else {
CLOG_WARN(&LOG, "called with NULL 'op'");
@@ -816,7 +825,7 @@ static int undo_editmode_objects_from_view_layer_prepare(ViewLayer *view_layer,
{
const short object_type = obact->type;
- for (Base *base = view_layer->object_bases.first; base; base = base->next) {
+ LISTBASE_FOREACH (Base *, base, &view_layer->object_bases) {
Object *ob = base->object;
if ((ob->type == object_type) && (ob->mode & OB_MODE_EDIT)) {
ID *id = ob->data;
@@ -825,7 +834,7 @@ static int undo_editmode_objects_from_view_layer_prepare(ViewLayer *view_layer,
}
int len = 0;
- for (Base *base = view_layer->object_bases.first; base; base = base->next) {
+ LISTBASE_FOREACH (Base *, base, &view_layer->object_bases) {
Object *ob = base->object;
if ((ob->type == object_type) && (ob->mode & OB_MODE_EDIT)) {
if (ob == obact) {
@@ -852,7 +861,7 @@ Object **ED_undo_editmode_objects_from_view_layer(ViewLayer *view_layer, uint *r
const short object_type = obact->type;
int i = 0;
Object **objects = MEM_malloc_arrayN(len, sizeof(*objects), __func__);
- for (Base *base = view_layer->object_bases.first; base; base = base->next) {
+ LISTBASE_FOREACH (Base *, base, &view_layer->object_bases) {
Object *ob = base->object;
if ((ob->type == object_type) && (ob->mode & OB_MODE_EDIT)) {
ID *id = ob->data;
@@ -881,7 +890,7 @@ Base **ED_undo_editmode_bases_from_view_layer(ViewLayer *view_layer, uint *r_len
const short object_type = obact->type;
int i = 0;
Base **base_array = MEM_malloc_arrayN(len, sizeof(*base_array), __func__);
- for (Base *base = view_layer->object_bases.first; base; base = base->next) {
+ LISTBASE_FOREACH (Base *, base, &view_layer->object_bases) {
Object *ob = base->object;
if ((ob->type == object_type) && (ob->mode & OB_MODE_EDIT)) {
ID *id = ob->data;
diff --git a/source/blender/editors/undo/memfile_undo.c b/source/blender/editors/undo/memfile_undo.c
index 086aa6c4c9d..2df26abe8b3 100644
--- a/source/blender/editors/undo/memfile_undo.c
+++ b/source/blender/editors/undo/memfile_undo.c
@@ -25,14 +25,17 @@
#include "BLI_ghash.h"
+#include "DNA_node_types.h"
#include "DNA_object_enums.h"
#include "DNA_object_types.h"
+#include "DNA_scene_types.h"
#include "BKE_blender_undo.h"
#include "BKE_context.h"
#include "BKE_lib_id.h"
#include "BKE_lib_query.h"
#include "BKE_main.h"
+#include "BKE_node.h"
#include "BKE_scene.h"
#include "BKE_undo_system.h"
@@ -106,7 +109,6 @@ static int memfile_undosys_step_id_reused_cb(LibraryIDLinkCallbackData *cb_data)
ID *id_self = cb_data->id_self;
ID **id_pointer = cb_data->id_pointer;
BLI_assert((id_self->tag & LIB_TAG_UNDO_OLD_ID_REUSED) != 0);
- Main *bmain = cb_data->user_data;
ID *id = *id_pointer;
if (id != NULL && id->lib == NULL && (id->tag & LIB_TAG_UNDO_OLD_ID_REUSED) == 0) {
@@ -129,9 +131,6 @@ static int memfile_undosys_step_id_reused_cb(LibraryIDLinkCallbackData *cb_data)
}
}
- /* In case an old, re-used ID is using a newly read data-block (i.e. one of its ID pointers got
- * updated), we have to tell the depsgraph about it. */
- DEG_id_tag_update_ex(bmain, id_self, ID_RECALC_COPY_ON_WRITE);
return do_stop_iter ? IDWALK_RET_STOP_ITER : IDWALK_RET_NOP;
}
@@ -148,7 +147,7 @@ static void memfile_undosys_step_decode(struct bContext *C,
bool use_old_bmain_data = true;
- if (!U.experimental.use_undo_speedup) {
+ if (USER_EXPERIMENTAL_TEST(&U, use_undo_legacy)) {
use_old_bmain_data = false;
}
else if (undo_direction > 0) {
@@ -217,12 +216,37 @@ static void memfile_undosys_step_decode(struct bContext *C,
FOREACH_MAIN_ID_BEGIN (bmain, id) {
if (id->tag & LIB_TAG_UNDO_OLD_ID_REUSED) {
BKE_library_foreach_ID_link(
- bmain, id, memfile_undosys_step_id_reused_cb, bmain, IDWALK_READONLY);
+ bmain, id, memfile_undosys_step_id_reused_cb, NULL, IDWALK_READONLY);
+ }
+
+ /* Tag depsgraph to update data-block for changes that happened between the
+ * current and the target state, see direct_link_id_restore_recalc(). */
+ if (id->recalc) {
+ DEG_id_tag_update_ex(bmain, id, id->recalc);
}
}
FOREACH_MAIN_ID_END;
- BKE_main_id_tag_all(bmain, LIB_TAG_UNDO_OLD_ID_REUSED, false);
+ FOREACH_MAIN_ID_BEGIN (bmain, id) {
+ /* Clear temporary tag. */
+ id->tag &= ~LIB_TAG_UNDO_OLD_ID_REUSED;
+
+ /* We only start accumulating from this point, any tags set up to here
+ * are already part of the current undo state. This is done in a second
+ * loop because DEG_id_tag_update may set tags on other datablocks. */
+ id->recalc_after_undo_push = 0;
+ bNodeTree *nodetree = ntreeFromID(id);
+ if (nodetree != NULL) {
+ nodetree->id.recalc_after_undo_push = 0;
+ }
+ if (GS(id->name) == ID_SCE) {
+ Scene *scene = (Scene *)id;
+ if (scene->master_collection != NULL) {
+ scene->master_collection->id.recalc_after_undo_push = 0;
+ }
+ }
+ }
+ FOREACH_MAIN_ID_END;
}
WM_event_add_notifier(C, NC_SCENE | ND_LAYER_CONTENT, CTX_data_scene(C));
diff --git a/source/blender/editors/util/CMakeLists.txt b/source/blender/editors/util/CMakeLists.txt
index 987327eefc1..17a90d10ca7 100644
--- a/source/blender/editors/util/CMakeLists.txt
+++ b/source/blender/editors/util/CMakeLists.txt
@@ -17,6 +17,7 @@
set(INC
../include
+ ../space_sequencer
../../blenkernel
../../blenlib
../../blentranslation
@@ -39,6 +40,7 @@ set(INC_SYS
set(SRC
ed_transverts.c
ed_util.c
+ ed_util_imbuf.c
gizmo_utils.c
numinput.c
select_utils.c
@@ -91,6 +93,7 @@ set(SRC
../include/ED_undo.h
../include/ED_userpref.h
../include/ED_util.h
+ ../include/ED_util_imbuf.h
../include/ED_uvedit.h
../include/ED_view3d.h
../include/UI_icons.h
diff --git a/source/blender/editors/util/ed_transverts.c b/source/blender/editors/util/ed_transverts.c
index 67a62473dc0..1c56ad878e2 100644
--- a/source/blender/editors/util/ed_transverts.c
+++ b/source/blender/editors/util/ed_transverts.c
@@ -111,7 +111,7 @@ void ED_transverts_update_obedit(TransVertStore *tvs, Object *obedit)
}
BKE_nurb_test_2d(nu);
- BKE_nurb_handles_test(nu, true); /* test for bezier too */
+ BKE_nurb_handles_test(nu, true, false); /* test for bezier too */
nu = nu->next;
}
}
diff --git a/source/blender/editors/util/ed_util.c b/source/blender/editors/util/ed_util.c
index fa28d9c2d6d..af387e4f7c2 100644
--- a/source/blender/editors/util/ed_util.c
+++ b/source/blender/editors/util/ed_util.c
@@ -35,6 +35,7 @@
#include "DNA_screen_types.h"
#include "DNA_space_types.h"
+#include "BLI_listbase.h"
#include "BLI_path_util.h"
#include "BLI_string.h"
#include "BLI_utildefines.h"
@@ -82,7 +83,7 @@
void ED_editors_init_for_undo(Main *bmain)
{
wmWindowManager *wm = bmain->wm.first;
- for (wmWindow *win = wm->windows.first; win; win = win->next) {
+ LISTBASE_FOREACH (wmWindow *, win, &wm->windows) {
ViewLayer *view_layer = WM_window_get_active_view_layer(win);
Base *base = BASACT(view_layer);
if (base != NULL) {
@@ -152,10 +153,10 @@ void ED_editors_init(bContext *C)
ED_object_sculptmode_enter_ex(bmain, depsgraph, scene, ob, true, reports);
}
else if (mode == OB_MODE_VERTEX_PAINT) {
- ED_object_vpaintmode_enter_ex(bmain, depsgraph, wm, scene, ob);
+ ED_object_vpaintmode_enter_ex(bmain, depsgraph, scene, ob);
}
else if (mode == OB_MODE_WEIGHT_PAINT) {
- ED_object_wpaintmode_enter_ex(bmain, depsgraph, wm, scene, ob);
+ ED_object_wpaintmode_enter_ex(bmain, depsgraph, scene, ob);
}
else {
BLI_assert(0);
@@ -173,7 +174,7 @@ void ED_editors_init(bContext *C)
else {
/* TODO(campbell): avoid operator calls. */
if (obact == ob) {
- ED_object_mode_toggle(C, mode);
+ ED_object_mode_set(C, mode);
}
}
}
@@ -224,8 +225,8 @@ void ED_editors_exit(Main *bmain, bool do_undo_system)
}
/* global in meshtools... */
- ED_mesh_mirror_spatial_table(NULL, NULL, NULL, NULL, 'e');
- ED_mesh_mirror_topo_table(NULL, NULL, 'e');
+ ED_mesh_mirror_spatial_table_end(NULL);
+ ED_mesh_mirror_topo_table_end(NULL);
}
bool ED_editors_flush_edits_for_object_ex(Main *bmain,
@@ -472,12 +473,12 @@ void ED_region_draw_mouse_line_cb(const bContext *C, ARegion *region, void *arg_
*
* \param new_id: may be NULL to unlink \a old_id.
*/
-void ED_spacedata_id_remap(struct ScrArea *sa, struct SpaceLink *sl, ID *old_id, ID *new_id)
+void ED_spacedata_id_remap(struct ScrArea *area, struct SpaceLink *sl, ID *old_id, ID *new_id)
{
SpaceType *st = BKE_spacetype_from_id(sl->spacetype);
if (st && st->id_remap) {
- st->id_remap(sa, sl, old_id, new_id);
+ st->id_remap(area, sl, old_id, new_id);
}
}
diff --git a/source/blender/editors/util/ed_util_imbuf.c b/source/blender/editors/util/ed_util_imbuf.c
new file mode 100644
index 00000000000..132a63a8249
--- /dev/null
+++ b/source/blender/editors/util/ed_util_imbuf.c
@@ -0,0 +1,571 @@
+/*
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * The Original Code is Copyright (C) 2008 Blender Foundation.
+ * All rights reserved.
+ */
+
+/** \file
+ * \ingroup edutil
+ */
+
+#include "MEM_guardedalloc.h"
+
+#include "BLI_rect.h"
+
+#include "BKE_colortools.h"
+#include "BKE_context.h"
+#include "BKE_image.h"
+#include "BKE_main.h"
+#include "BKE_screen.h"
+#include "BKE_sequencer.h"
+
+#include "ED_image.h"
+#include "ED_screen.h"
+#include "ED_space_api.h"
+
+#include "GPU_immediate.h"
+#include "GPU_state.h"
+
+#include "IMB_colormanagement.h"
+#include "IMB_imbuf.h"
+#include "IMB_imbuf_types.h"
+
+#include "UI_view2d.h"
+
+#include "WM_api.h"
+#include "WM_types.h"
+
+#include "sequencer_intern.h"
+
+/* Own define. */
+#include "ED_util_imbuf.h"
+
+/* -------------------------------------------------------------------- */
+/** \name Image Pixel Sample Struct (Operator Custom Data)
+ * \{ */
+
+typedef struct ImageSampleInfo {
+ ARegionType *art;
+ void *draw_handle;
+ int x, y;
+ int channels;
+
+ int width, height;
+ int sample_size;
+
+ unsigned char col[4];
+ float colf[4];
+ float linearcol[4];
+ int z;
+ float zf;
+
+ unsigned char *colp;
+ const float *colfp;
+ int *zp;
+ float *zfp;
+
+ bool draw;
+ bool color_manage;
+ int use_default_view;
+} ImageSampleInfo;
+
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Image Pixel Sample
+ * \{ */
+
+static void image_sample_pixel_color_ubyte(const ImBuf *ibuf,
+ const int coord[2],
+ uchar r_col[4],
+ float r_col_linear[4])
+{
+ const uchar *cp = (unsigned char *)(ibuf->rect + coord[1] * ibuf->x + coord[0]);
+ copy_v4_v4_uchar(r_col, cp);
+ rgba_uchar_to_float(r_col_linear, r_col);
+ IMB_colormanagement_colorspace_to_scene_linear_v4(r_col_linear, false, ibuf->rect_colorspace);
+}
+
+static void image_sample_pixel_color_float(ImBuf *ibuf, const int coord[2], float r_col[4])
+{
+ const float *cp = ibuf->rect_float + (ibuf->channels) * (coord[1] * ibuf->x + coord[0]);
+ copy_v4_v4(r_col, cp);
+}
+
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Image Pixel Region Sample
+ * \{ */
+
+static void image_sample_rect_color_ubyte(const ImBuf *ibuf,
+ const rcti *rect,
+ uchar r_col[4],
+ float r_col_linear[4])
+{
+ uint col_accum_ub[4] = {0, 0, 0, 0};
+ zero_v4(r_col_linear);
+ int col_tot = 0;
+ int coord[2];
+ for (coord[0] = rect->xmin; coord[0] <= rect->xmax; coord[0]++) {
+ for (coord[1] = rect->ymin; coord[1] <= rect->ymax; coord[1]++) {
+ float col_temp_fl[4];
+ uchar col_temp_ub[4];
+ image_sample_pixel_color_ubyte(ibuf, coord, col_temp_ub, col_temp_fl);
+ add_v4_v4(r_col_linear, col_temp_fl);
+ col_accum_ub[0] += (uint)col_temp_ub[0];
+ col_accum_ub[1] += (uint)col_temp_ub[1];
+ col_accum_ub[2] += (uint)col_temp_ub[2];
+ col_accum_ub[3] += (uint)col_temp_ub[3];
+ col_tot += 1;
+ }
+ }
+ mul_v4_fl(r_col_linear, 1.0 / (float)col_tot);
+
+ r_col[0] = MIN2(col_accum_ub[0] / col_tot, 255);
+ r_col[1] = MIN2(col_accum_ub[1] / col_tot, 255);
+ r_col[2] = MIN2(col_accum_ub[2] / col_tot, 255);
+ r_col[3] = MIN2(col_accum_ub[3] / col_tot, 255);
+}
+
+static void image_sample_rect_color_float(ImBuf *ibuf, const rcti *rect, float r_col[4])
+{
+ zero_v4(r_col);
+ int col_tot = 0;
+ int coord[2];
+ for (coord[0] = rect->xmin; coord[0] <= rect->xmax; coord[0]++) {
+ for (coord[1] = rect->ymin; coord[1] <= rect->ymax; coord[1]++) {
+ float col_temp_fl[4];
+ image_sample_pixel_color_float(ibuf, coord, col_temp_fl);
+ add_v4_v4(r_col, col_temp_fl);
+ col_tot += 1;
+ }
+ }
+ mul_v4_fl(r_col, 1.0 / (float)col_tot);
+}
+
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Image Pixel Sample (Internal Utilities)
+ * \{ */
+
+static void image_sample_apply(bContext *C, wmOperator *op, const wmEvent *event)
+{
+ SpaceImage *sima = CTX_wm_space_image(C);
+ ARegion *region = CTX_wm_region(C);
+ Image *image = ED_space_image(sima);
+
+ float uv[2];
+ UI_view2d_region_to_view(&region->v2d, event->mval[0], event->mval[1], &uv[0], &uv[1]);
+ int tile = BKE_image_get_tile_from_pos(sima->image, uv, uv, NULL);
+
+ void *lock;
+ ImBuf *ibuf = ED_space_image_acquire_buffer(sima, &lock, tile);
+ ImageSampleInfo *info = op->customdata;
+ Scene *scene = CTX_data_scene(C);
+ CurveMapping *curve_mapping = scene->view_settings.curve_mapping;
+
+ if (ibuf == NULL) {
+ ED_space_image_release_buffer(sima, ibuf, lock);
+ info->draw = false;
+ return;
+ }
+
+ if (uv[0] >= 0.0f && uv[1] >= 0.0f && uv[0] < 1.0f && uv[1] < 1.0f) {
+ int x = (int)(uv[0] * ibuf->x), y = (int)(uv[1] * ibuf->y);
+
+ CLAMP(x, 0, ibuf->x - 1);
+ CLAMP(y, 0, ibuf->y - 1);
+
+ info->width = ibuf->x;
+ info->height = ibuf->y;
+ info->x = x;
+ info->y = y;
+
+ info->draw = true;
+ info->channels = ibuf->channels;
+
+ info->colp = NULL;
+ info->colfp = NULL;
+ info->zp = NULL;
+ info->zfp = NULL;
+
+ info->use_default_view = (image->flag & IMA_VIEW_AS_RENDER) ? false : true;
+
+ rcti sample_rect;
+ sample_rect.xmin = max_ii(0, x - info->sample_size / 2);
+ sample_rect.ymin = max_ii(0, y - info->sample_size / 2);
+ sample_rect.xmax = min_ii(ibuf->x, sample_rect.xmin + info->sample_size) - 1;
+ sample_rect.ymax = min_ii(ibuf->y, sample_rect.ymin + info->sample_size) - 1;
+
+ if (ibuf->rect) {
+ image_sample_rect_color_ubyte(ibuf, &sample_rect, info->col, info->linearcol);
+ rgba_uchar_to_float(info->colf, info->col);
+
+ info->colp = info->col;
+ info->colfp = info->colf;
+ info->color_manage = true;
+ }
+ if (ibuf->rect_float) {
+ image_sample_rect_color_float(ibuf, &sample_rect, info->colf);
+
+ if (ibuf->channels == 4) {
+ /* pass */
+ }
+ else if (ibuf->channels == 3) {
+ info->colf[3] = 1.0f;
+ }
+ else {
+ info->colf[1] = info->colf[0];
+ info->colf[2] = info->colf[0];
+ info->colf[3] = 1.0f;
+ }
+ info->colfp = info->colf;
+
+ copy_v4_v4(info->linearcol, info->colf);
+
+ info->color_manage = true;
+ }
+
+ if (ibuf->zbuf) {
+ /* TODO, blend depth (not urgent). */
+ info->z = ibuf->zbuf[y * ibuf->x + x];
+ info->zp = &info->z;
+ if (ibuf->zbuf == (int *)ibuf->rect) {
+ info->colp = NULL;
+ }
+ }
+ if (ibuf->zbuf_float) {
+ /* TODO, blend depth (not urgent). */
+ info->zf = ibuf->zbuf_float[y * ibuf->x + x];
+ info->zfp = &info->zf;
+ if (ibuf->zbuf_float == ibuf->rect_float) {
+ info->colfp = NULL;
+ }
+ }
+
+ if (curve_mapping && ibuf->channels == 4) {
+ /* we reuse this callback for set curves point operators */
+ if (RNA_struct_find_property(op->ptr, "point")) {
+ int point = RNA_enum_get(op->ptr, "point");
+
+ if (point == 1) {
+ BKE_curvemapping_set_black_white(curve_mapping, NULL, info->linearcol);
+ }
+ else if (point == 0) {
+ BKE_curvemapping_set_black_white(curve_mapping, info->linearcol, NULL);
+ }
+ WM_event_add_notifier(C, NC_WINDOW, NULL);
+ }
+ }
+
+ // XXX node curve integration ..
+#if 0
+ {
+ ScrArea *sa, *cur = curarea;
+
+ node_curvemap_sample(fp); /* sends global to node editor */
+ for (sa = G.curscreen->areabase.first; sa; sa = sa->next) {
+ if (sa->spacetype == SPACE_NODE) {
+ areawinset(sa->win);
+ scrarea_do_windraw(sa);
+ }
+ }
+ node_curvemap_sample(NULL); /* clears global in node editor */
+ curarea = cur;
+ }
+#endif
+ }
+ else {
+ info->draw = 0;
+ }
+
+ ED_space_image_release_buffer(sima, ibuf, lock);
+ ED_area_tag_redraw(CTX_wm_area(C));
+}
+
+static void sequencer_sample_apply(bContext *C, wmOperator *op, const wmEvent *event)
+{
+ Main *bmain = CTX_data_main(C);
+ struct Depsgraph *depsgraph = CTX_data_ensure_evaluated_depsgraph(C);
+ Scene *scene = CTX_data_scene(C);
+ SpaceSeq *sseq = (SpaceSeq *)CTX_wm_space_data(C);
+ ARegion *region = CTX_wm_region(C);
+ ImBuf *ibuf = sequencer_ibuf_get(bmain, depsgraph, scene, sseq, CFRA, 0, NULL);
+ ImageSampleInfo *info = op->customdata;
+ float fx, fy;
+
+ if (ibuf == NULL) {
+ IMB_freeImBuf(ibuf);
+ info->draw = 0;
+ return;
+ }
+
+ UI_view2d_region_to_view(&region->v2d, event->mval[0], event->mval[1], &fx, &fy);
+
+ fx /= scene->r.xasp / scene->r.yasp;
+
+ fx += (float)scene->r.xsch / 2.0f;
+ fy += (float)scene->r.ysch / 2.0f;
+ fx *= (float)ibuf->x / (float)scene->r.xsch;
+ fy *= (float)ibuf->y / (float)scene->r.ysch;
+
+ if (fx >= 0.0f && fy >= 0.0f && fx < ibuf->x && fy < ibuf->y) {
+ const float *fp;
+ unsigned char *cp;
+ int x = (int)fx, y = (int)fy;
+
+ info->x = x;
+ info->y = y;
+ info->draw = 1;
+ info->channels = ibuf->channels;
+
+ info->colp = NULL;
+ info->colfp = NULL;
+
+ if (ibuf->rect) {
+ cp = (unsigned char *)(ibuf->rect + y * ibuf->x + x);
+
+ info->col[0] = cp[0];
+ info->col[1] = cp[1];
+ info->col[2] = cp[2];
+ info->col[3] = cp[3];
+ info->colp = info->col;
+
+ info->colf[0] = (float)cp[0] / 255.0f;
+ info->colf[1] = (float)cp[1] / 255.0f;
+ info->colf[2] = (float)cp[2] / 255.0f;
+ info->colf[3] = (float)cp[3] / 255.0f;
+ info->colfp = info->colf;
+
+ copy_v4_v4(info->linearcol, info->colf);
+ IMB_colormanagement_colorspace_to_scene_linear_v4(
+ info->linearcol, false, ibuf->rect_colorspace);
+
+ info->color_manage = true;
+ }
+ if (ibuf->rect_float) {
+ fp = (ibuf->rect_float + (ibuf->channels) * (y * ibuf->x + x));
+
+ info->colf[0] = fp[0];
+ info->colf[1] = fp[1];
+ info->colf[2] = fp[2];
+ info->colf[3] = fp[3];
+ info->colfp = info->colf;
+
+ /* sequencer's image buffers are in non-linear space, need to make them linear */
+ copy_v4_v4(info->linearcol, info->colf);
+ BKE_sequencer_pixel_from_sequencer_space_v4(scene, info->linearcol);
+
+ info->color_manage = true;
+ }
+ }
+ else {
+ info->draw = 0;
+ }
+
+ IMB_freeImBuf(ibuf);
+ ED_area_tag_redraw(CTX_wm_area(C));
+}
+
+static void ed_imbuf_sample_apply(bContext *C, wmOperator *op, const wmEvent *event)
+{
+ ScrArea *sa = CTX_wm_area(C);
+
+ if (sa && sa->spacetype == SPACE_IMAGE) {
+ image_sample_apply(C, op, event);
+ }
+
+ if (sa && sa->spacetype == SPACE_SEQ) {
+ sequencer_sample_apply(C, op, event);
+ }
+}
+
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Image Pixel Sample (Public Operator Callback)
+ *
+ * Callbacks for the sample operator, used by sequencer and image spaces.
+ * \{ */
+
+void ED_imbuf_sample_draw(const bContext *C, ARegion *region, void *arg_info)
+{
+ ImageSampleInfo *info = arg_info;
+ if (!info->draw) {
+ return;
+ }
+
+ Scene *scene = CTX_data_scene(C);
+ ED_image_draw_info(scene,
+ region,
+ info->color_manage,
+ info->use_default_view,
+ info->channels,
+ info->x,
+ info->y,
+ info->colp,
+ info->colfp,
+ info->linearcol,
+ info->zp,
+ info->zfp);
+
+ if (info->sample_size > 1) {
+ ScrArea *sa = CTX_wm_area(C);
+
+ if (sa && sa->spacetype == SPACE_IMAGE) {
+
+ const wmWindow *win = CTX_wm_window(C);
+ const wmEvent *event = win->eventstate;
+
+ SpaceImage *sima = CTX_wm_space_image(C);
+ GPUVertFormat *format = immVertexFormat();
+ uint pos = GPU_vertformat_attr_add(format, "pos", GPU_COMP_F32, 2, GPU_FETCH_FLOAT);
+
+ const float color[3] = {1, 1, 1};
+ immBindBuiltinProgram(GPU_SHADER_2D_UNIFORM_COLOR);
+ immUniformColor3fv(color);
+
+ /* TODO(campbell): lock to pixels. */
+ rctf sample_rect_fl;
+ BLI_rctf_init_pt_radius(
+ &sample_rect_fl,
+ (float[2]){event->x - region->winrct.xmin, event->y - region->winrct.ymin},
+ (float)(info->sample_size / 2.0f) * sima->zoom);
+
+ glEnable(GL_COLOR_LOGIC_OP);
+ glLogicOp(GL_XOR);
+ GPU_line_width(1.0f);
+ imm_draw_box_wire_2d(pos,
+ (float)sample_rect_fl.xmin,
+ (float)sample_rect_fl.ymin,
+ (float)sample_rect_fl.xmax,
+ (float)sample_rect_fl.ymax);
+ glDisable(GL_COLOR_LOGIC_OP);
+
+ immUnbindProgram();
+ }
+ }
+}
+
+void ED_imbuf_sample_exit(bContext *C, wmOperator *op)
+{
+ ImageSampleInfo *info = op->customdata;
+
+ ED_region_draw_cb_exit(info->art, info->draw_handle);
+ ED_area_tag_redraw(CTX_wm_area(C));
+ MEM_freeN(info);
+}
+
+int ED_imbuf_sample_invoke(bContext *C, wmOperator *op, const wmEvent *event)
+{
+ ARegion *region = CTX_wm_region(C);
+ ImageSampleInfo *info;
+
+ info = MEM_callocN(sizeof(ImageSampleInfo), "ImageSampleInfo");
+
+ info->art = region->type;
+ info->draw_handle = ED_region_draw_cb_activate(
+ region->type, ED_imbuf_sample_draw, info, REGION_DRAW_POST_PIXEL);
+ info->sample_size = RNA_int_get(op->ptr, "size");
+ op->customdata = info;
+
+ ScrArea *sa = CTX_wm_area(C);
+
+ if (sa && sa->spacetype == SPACE_IMAGE) {
+ SpaceImage *sima = CTX_wm_space_image(C);
+
+ if (region->regiontype == RGN_TYPE_WINDOW) {
+ if (event->mval[1] <= 16 && ED_space_image_show_cache(sima)) {
+ return OPERATOR_PASS_THROUGH;
+ }
+ }
+
+ if (!ED_space_image_has_buffer(sima)) {
+ return OPERATOR_CANCELLED;
+ }
+ }
+
+ ed_imbuf_sample_apply(C, op, event);
+
+ WM_event_add_modal_handler(C, op);
+
+ return OPERATOR_RUNNING_MODAL;
+}
+
+int ED_imbuf_sample_modal(bContext *C, wmOperator *op, const wmEvent *event)
+{
+ switch (event->type) {
+ case LEFTMOUSE:
+ case RIGHTMOUSE: // XXX hardcoded
+ if (event->val == KM_RELEASE) {
+ ED_imbuf_sample_exit(C, op);
+ return OPERATOR_CANCELLED;
+ }
+ break;
+ case MOUSEMOVE:
+ ed_imbuf_sample_apply(C, op, event);
+ break;
+ }
+
+ return OPERATOR_RUNNING_MODAL;
+}
+
+void ED_imbuf_sample_cancel(bContext *C, wmOperator *op)
+{
+ ED_imbuf_sample_exit(C, op);
+}
+
+bool ED_imbuf_sample_poll(bContext *C)
+{
+ ScrArea *sa = CTX_wm_area(C);
+
+ if (sa && sa->spacetype == SPACE_IMAGE) {
+ SpaceImage *sima = CTX_wm_space_image(C);
+ if (sima == NULL) {
+ return false;
+ }
+
+ Object *obedit = CTX_data_edit_object(C);
+ if (obedit) {
+ /* Disable when UV editing so it doesn't swallow all click events
+ * (use for setting cursor). */
+ if (ED_space_image_show_uvedit(sima, obedit)) {
+ return false;
+ }
+ }
+ else if (sima->mode != SI_MODE_VIEW) {
+ return false;
+ }
+
+ return true;
+ }
+
+ if (sa && sa->spacetype == SPACE_SEQ) {
+ SpaceSeq *sseq = CTX_wm_space_seq(C);
+
+ if (sseq->mainb != SEQ_DRAW_IMG_IMBUF) {
+ return false;
+ }
+
+ return sseq && BKE_sequencer_editing_get(CTX_data_scene(C), false) != NULL;
+ }
+
+ return false;
+}
+
+/** \} */
diff --git a/source/blender/editors/util/gizmo_utils.c b/source/blender/editors/util/gizmo_utils.c
index 85a7cc94ae3..08e7b3a9a0a 100644
--- a/source/blender/editors/util/gizmo_utils.c
+++ b/source/blender/editors/util/gizmo_utils.c
@@ -59,9 +59,9 @@ bool ED_gizmo_poll_or_unlink_delayed_from_tool_ex(const bContext *C,
{
bToolRef_Runtime *tref_rt = WM_toolsystem_runtime_from_context((bContext *)C);
if ((tref_rt == NULL) || !STREQ(gzgt_idname, tref_rt->gizmo_group)) {
- ScrArea *sa = CTX_wm_area(C);
+ ScrArea *area = CTX_wm_area(C);
wmGizmoMapType *gzmap_type = WM_gizmomaptype_ensure(&gzgt->gzmap_params);
- WM_gizmo_group_unlink_delayed_ptr_from_space(gzgt, gzmap_type, sa);
+ WM_gizmo_group_unlink_delayed_ptr_from_space(gzgt, gzmap_type, area);
if (gzgt->users == 0) {
WM_gizmo_group_type_unlink_delayed_ptr(gzgt);
}
diff --git a/source/blender/editors/uvedit/CMakeLists.txt b/source/blender/editors/uvedit/CMakeLists.txt
index d2ba9ab9591..b40b82c50fb 100644
--- a/source/blender/editors/uvedit/CMakeLists.txt
+++ b/source/blender/editors/uvedit/CMakeLists.txt
@@ -40,6 +40,7 @@ set(SRC
uvedit_draw.c
uvedit_ops.c
uvedit_parametrizer.c
+ uvedit_select.c
uvedit_smart_stitch.c
uvedit_unwrap_ops.c
diff --git a/source/blender/editors/uvedit/uvedit_buttons.c b/source/blender/editors/uvedit/uvedit_buttons.c
index 887ce274680..edfbfd0cdc3 100644
--- a/source/blender/editors/uvedit/uvedit_buttons.c
+++ b/source/blender/editors/uvedit/uvedit_buttons.c
@@ -58,8 +58,7 @@
/* UV Utilities */
-static int uvedit_center(
- Scene *scene, Object **objects, uint objects_len, Image *ima, float center[2])
+static int uvedit_center(Scene *scene, Object **objects, uint objects_len, float center[2])
{
BMFace *f;
BMLoop *l;
@@ -75,7 +74,7 @@ static int uvedit_center(
const int cd_loop_uv_offset = CustomData_get_offset(&em->bm->ldata, CD_MLOOPUV);
BM_ITER_MESH (f, &iter, em->bm, BM_FACES_OF_MESH) {
- if (!uvedit_face_visible_test(scene, obedit, ima, f)) {
+ if (!uvedit_face_visible_test(scene, f)) {
continue;
}
@@ -97,8 +96,10 @@ static int uvedit_center(
return tot;
}
-static void uvedit_translate(
- Scene *scene, Object **objects, uint objects_len, Image *ima, const float delta[2])
+static void uvedit_translate(Scene *scene,
+ Object **objects,
+ uint objects_len,
+ const float delta[2])
{
BMFace *f;
BMLoop *l;
@@ -112,7 +113,7 @@ static void uvedit_translate(
const int cd_loop_uv_offset = CustomData_get_offset(&em->bm->ldata, CD_MLOOPUV);
BM_ITER_MESH (f, &iter, em->bm, BM_FACES_OF_MESH) {
- if (!uvedit_face_visible_test(scene, obedit, ima, f)) {
+ if (!uvedit_face_visible_test(scene, f)) {
continue;
}
@@ -134,7 +135,6 @@ static void uvedit_vertex_buttons(const bContext *C, uiBlock *block)
{
SpaceImage *sima = CTX_wm_space_image(C);
Scene *scene = CTX_data_scene(C);
- Image *ima = sima->image;
float center[2];
int imx, imy, step, digits;
float width = 8 * UI_UNIT_X;
@@ -144,7 +144,7 @@ static void uvedit_vertex_buttons(const bContext *C, uiBlock *block)
ED_space_image_get_size(sima, &imx, &imy);
- if (uvedit_center(scene, objects, objects_len, ima, center)) {
+ if (uvedit_center(scene, objects, objects_len, center)) {
float range_xy[2][2] = {
{-10.0f, 10.0f},
{-10.0f, 10.0f},
@@ -212,7 +212,6 @@ static void do_uvedit_vertex(bContext *C, void *UNUSED(arg), int event)
{
SpaceImage *sima = CTX_wm_space_image(C);
Scene *scene = CTX_data_scene(C);
- Image *ima = sima->image;
float center[2], delta[2];
int imx, imy;
@@ -225,7 +224,7 @@ static void do_uvedit_vertex(bContext *C, void *UNUSED(arg), int event)
CTX_data_view_layer(C), CTX_wm_view3d(C), &objects_len);
ED_space_image_get_size(sima, &imx, &imy);
- uvedit_center(scene, objects, objects_len, ima, center);
+ uvedit_center(scene, objects, objects_len, center);
if (sima->flag & SI_COORDFLOATS) {
delta[0] = uvedit_old_center[0] - center[0];
@@ -236,7 +235,7 @@ static void do_uvedit_vertex(bContext *C, void *UNUSED(arg), int event)
delta[1] = uvedit_old_center[1] / imy - center[1];
}
- uvedit_translate(scene, objects, objects_len, ima, delta);
+ uvedit_translate(scene, objects, objects_len, delta);
WM_event_add_notifier(C, NC_IMAGE, sima->image);
for (uint ob_index = 0; ob_index < objects_len; ob_index++) {
@@ -259,11 +258,11 @@ static bool image_panel_uv_poll(const bContext *C, PanelType *UNUSED(pt))
return ED_uvedit_test(obedit);
}
-static void image_panel_uv(const bContext *C, Panel *pa)
+static void image_panel_uv(const bContext *C, Panel *panel)
{
uiBlock *block;
- block = uiLayoutAbsoluteBlock(pa->layout);
+ block = uiLayoutAbsoluteBlock(panel->layout);
UI_block_func_handle_set(block, do_uvedit_vertex, NULL);
uvedit_vertex_buttons(C, block);
diff --git a/source/blender/editors/uvedit/uvedit_draw.c b/source/blender/editors/uvedit/uvedit_draw.c
index 1e576f6fea4..897e2f13774 100644
--- a/source/blender/editors/uvedit/uvedit_draw.c
+++ b/source/blender/editors/uvedit/uvedit_draw.c
@@ -39,6 +39,7 @@
#include "../../draw/intern/draw_cache_impl.h"
#include "BLI_math.h"
+#include "BLI_task.h"
#include "BLI_utildefines.h"
#include "BKE_deform.h"
@@ -206,8 +207,10 @@ static void uvedit_get_batches(Object *ob,
else {
batches->faces = NULL;
}
-
- DRW_mesh_batch_cache_create_requested(ob, ob->data, scene, false, false);
+ struct TaskGraph *task_graph = BLI_task_graph_create();
+ DRW_mesh_batch_cache_create_requested(task_graph, ob, ob->data, scene, false, false);
+ BLI_task_graph_work_and_wait(task_graph);
+ BLI_task_graph_free(task_graph);
if (draw_stretch && (sima->dt_uvstretch == SI_UVDT_STRETCH_AREA)) {
/* after create_requested we can load the actual areas */
@@ -216,24 +219,46 @@ static void uvedit_get_batches(Object *ob,
}
}
-static void draw_uvs_shadow(SpaceImage *UNUSED(sima),
+static void draw_uvs_shadow(SpaceImage *sima,
const Scene *scene,
Object *obedit,
Depsgraph *depsgraph)
{
Object *ob_eval = DEG_get_evaluated_object(depsgraph, obedit);
Mesh *me = ob_eval->data;
+ const float overlay_alpha = sima->uv_opacity;
float col[4];
UI_GetThemeColor4fv(TH_UV_SHADOW, col);
DRW_mesh_batch_cache_validate(me);
GPUBatch *edges = DRW_mesh_batch_cache_get_uv_edges(me);
- DRW_mesh_batch_cache_create_requested(ob_eval, me, scene, false, false);
+
+ struct TaskGraph *task_graph = BLI_task_graph_create();
+ DRW_mesh_batch_cache_create_requested(task_graph, ob_eval, me, scene, false, false);
+ BLI_task_graph_work_and_wait(task_graph);
+ BLI_task_graph_free(task_graph);
if (edges) {
+ if (sima->flag & SI_SMOOTH_UV) {
+ GPU_line_smooth(true);
+ GPU_blend(true);
+ }
+ else if (overlay_alpha < 1.0f) {
+ GPU_blend(true);
+ }
+
+ col[3] = overlay_alpha;
GPU_batch_program_set_builtin(edges, GPU_SHADER_2D_UV_UNIFORM_COLOR);
GPU_batch_uniform_4fv(edges, "color", col);
GPU_batch_draw(edges);
+
+ if (sima->flag & SI_SMOOTH_UV) {
+ GPU_line_smooth(false);
+ GPU_blend(false);
+ }
+ else if (overlay_alpha < 1.0f) {
+ GPU_blend(false);
+ }
}
}
@@ -251,7 +276,10 @@ static void draw_uvs_texpaint(const Scene *scene, Object *ob, Depsgraph *depsgra
DRW_mesh_batch_cache_validate(me);
GPUBatch *geom = DRW_mesh_batch_cache_get_uv_edges(me);
- DRW_mesh_batch_cache_create_requested(ob_eval, me, scene, false, false);
+ struct TaskGraph *task_graph = BLI_task_graph_create();
+ DRW_mesh_batch_cache_create_requested(task_graph, ob_eval, me, scene, false, false);
+ BLI_task_graph_work_and_wait(task_graph);
+ BLI_task_graph_free(task_graph);
GPU_batch_program_set_builtin(geom, GPU_SHADER_2D_UV_UNIFORM_COLOR);
GPU_batch_uniform_4fv(geom, "color", col);
@@ -265,6 +293,7 @@ static void draw_uvs_texpaint(const Scene *scene, Object *ob, Depsgraph *depsgra
bool prev_ma_match = (mpoly->mat_nr == (ob_eval->actcol - 1));
GPU_matrix_bind(geom->interface);
+ GPU_shader_set_srgb_uniform(geom->interface);
GPU_batch_bind(geom);
/* TODO(fclem): If drawcall count becomes a problem in the future
@@ -305,6 +334,7 @@ static void draw_uvs(SpaceImage *sima,
Object *ob_eval = batch->ob_eval;
const ToolSettings *ts = scene->toolsettings;
float col1[4], col2[4], col3[4], transparent[4] = {0.0f, 0.0f, 0.0f, 0.0f};
+ const float overlay_alpha = sima->uv_opacity;
if (sima->flag & SI_DRAWSHADOW) {
bool is_cage_like_final_meshes = false;
@@ -345,7 +375,11 @@ static void draw_uvs(SpaceImage *sima,
UI_GetThemeColor4fv(TH_FACE, col1);
UI_GetThemeColor4fv(TH_FACE_SELECT, col2);
UI_GetThemeColor4fv(TH_EDITMESH_ACTIVE, col3);
- col3[3] *= 0.2; /* Simulate dithering */
+
+ col1[3] *= overlay_alpha;
+ col2[3] *= overlay_alpha;
+ col3[3] *= overlay_alpha;
+
GPU_batch_uniform_4fv(batch->faces, "faceColor", col1);
GPU_batch_uniform_4fv(batch->faces, "selectColor", col2);
GPU_batch_uniform_4fv(batch->faces, "activeColor", col3);
@@ -371,9 +405,16 @@ static void draw_uvs(SpaceImage *sima,
GPU_line_smooth(true);
GPU_blend(true);
}
+ else if (overlay_alpha < 1.0f) {
+ GPU_blend(true);
+ }
+
switch (sima->dt_uv) {
case SI_UVDT_DASH: {
- float dash_colors[2][4] = {{0.56f, 0.56f, 0.56f, 1.0f}, {0.07f, 0.07f, 0.07f, 1.0f}};
+ float dash_colors[2][4] = {
+ {0.56f, 0.56f, 0.56f, overlay_alpha},
+ {0.07f, 0.07f, 0.07f, overlay_alpha},
+ };
float viewport_size[4];
GPU_viewport_size_get_f(viewport_size);
@@ -397,7 +438,8 @@ static void draw_uvs(SpaceImage *sima,
* instead of modifying the provoking vert. */
glProvokingVertex(GL_FIRST_VERTEX_CONVENTION);
- UI_GetThemeColor4fv(TH_EDGE_SELECT, col2);
+ UI_GetThemeColor3fv(TH_EDGE_SELECT, col2);
+ col2[3] = overlay_alpha;
GPU_batch_program_set_builtin(
batch->edges, (interpedges) ? GPU_SHADER_2D_UV_EDGES_SMOOTH : GPU_SHADER_2D_UV_EDGES);
@@ -405,18 +447,19 @@ static void draw_uvs(SpaceImage *sima,
if (sima->dt_uv == SI_UVDT_OUTLINE) {
/* Black Outline. */
GPU_line_width(3.0f);
- GPU_batch_uniform_4f(batch->edges, "edgeColor", 0.0f, 0.0f, 0.0f, 1.0f);
- GPU_batch_uniform_4f(batch->edges, "selectColor", 0.0f, 0.0f, 0.0f, 1.0f);
+ GPU_batch_uniform_4f(batch->edges, "edgeColor", 0.0f, 0.0f, 0.0f, overlay_alpha);
+ GPU_batch_uniform_4f(batch->edges, "selectColor", 0.0f, 0.0f, 0.0f, overlay_alpha);
GPU_batch_draw(batch->edges);
- UI_GetThemeColor4fv(TH_WIRE_EDIT, col1);
+ UI_GetThemeColor3fv(TH_WIRE_EDIT, col1);
}
else if (sima->dt_uv == SI_UVDT_WHITE) {
- copy_v4_fl4(col1, 1.0f, 1.0f, 1.0f, 1.0f);
+ copy_v3_fl3(col1, 1.0f, 1.0f, 1.0f);
}
else {
- copy_v4_fl4(col1, 0.0f, 0.0f, 0.0f, 1.0f);
+ copy_v3_fl3(col1, 0.0f, 0.0f, 0.0f);
}
+ col1[3] = overlay_alpha;
/* Inner Line. Use depth test to insure selection is drawn on top. */
GPU_depth_test(true);
@@ -434,6 +477,9 @@ static void draw_uvs(SpaceImage *sima,
GPU_line_smooth(false);
GPU_blend(false);
}
+ else if (overlay_alpha < 1.0f) {
+ GPU_blend(false);
+ }
}
if (batch->verts || batch->facedots) {
UI_GetThemeColor4fv(TH_VERTEX_SELECT, col2);
diff --git a/source/blender/editors/uvedit/uvedit_intern.h b/source/blender/editors/uvedit/uvedit_intern.h
index 7bc6b048585..31384d6df17 100644
--- a/source/blender/editors/uvedit/uvedit_intern.h
+++ b/source/blender/editors/uvedit/uvedit_intern.h
@@ -57,13 +57,11 @@ typedef struct UvNearestHit {
}
bool uv_find_nearest_vert(struct Scene *scene,
- struct Image *ima,
struct Object *obedit,
const float co[2],
const float penalty_dist,
struct UvNearestHit *hit_final);
bool uv_find_nearest_vert_multi(struct Scene *scene,
- struct Image *ima,
struct Object **objects,
const uint objects_len,
const float co[2],
@@ -71,24 +69,20 @@ bool uv_find_nearest_vert_multi(struct Scene *scene,
struct UvNearestHit *hit_final);
bool uv_find_nearest_edge(struct Scene *scene,
- struct Image *ima,
struct Object *obedit,
const float co[2],
struct UvNearestHit *hit_final);
bool uv_find_nearest_edge_multi(struct Scene *scene,
- struct Image *ima,
struct Object **objects,
const uint objects_len,
const float co[2],
struct UvNearestHit *hit_final);
bool uv_find_nearest_face(struct Scene *scene,
- struct Image *ima,
struct Object *obedit,
const float co[2],
struct UvNearestHit *hit_final);
bool uv_find_nearest_face_multi(struct Scene *scene,
- struct Image *ima,
struct Object **objects,
const uint objects_len,
const float co[2],
@@ -99,6 +93,7 @@ bool uv_find_nearest_face_multi(struct Scene *scene,
void uvedit_live_unwrap_update(struct SpaceImage *sima,
struct Scene *scene,
struct Object *obedit);
+void uvedit_pixel_to_float(struct SpaceImage *sima, float pixeldist, float r_dist[2]);
/* operators */
@@ -113,4 +108,28 @@ void UV_OT_sphere_project(struct wmOperatorType *ot);
void UV_OT_unwrap(struct wmOperatorType *ot);
void UV_OT_stitch(struct wmOperatorType *ot);
+/* uvedit_select.c */
+
+bool uvedit_select_is_any_selected(struct Scene *scene, struct Object *obedit);
+bool uvedit_select_is_any_selected_multi(struct Scene *scene,
+ struct Object **objects,
+ const uint objects_len);
+const float *uvedit_first_selected_uv_from_vertex(struct Scene *scene,
+ struct BMVert *eve,
+ const int cd_loop_uv_offset);
+
+void UV_OT_select_all(struct wmOperatorType *ot);
+void UV_OT_select(struct wmOperatorType *ot);
+void UV_OT_select_loop(struct wmOperatorType *ot);
+void UV_OT_select_linked(struct wmOperatorType *ot);
+void UV_OT_select_linked_pick(struct wmOperatorType *ot);
+void UV_OT_select_split(struct wmOperatorType *ot);
+void UV_OT_select_pinned(struct wmOperatorType *ot);
+void UV_OT_select_box(struct wmOperatorType *ot);
+void UV_OT_select_lasso(struct wmOperatorType *ot);
+void UV_OT_select_circle(struct wmOperatorType *ot);
+void UV_OT_select_more(struct wmOperatorType *ot);
+void UV_OT_select_less(struct wmOperatorType *ot);
+void UV_OT_select_overlap(struct wmOperatorType *ot);
+
#endif /* __UVEDIT_INTERN_H__ */
diff --git a/source/blender/editors/uvedit/uvedit_ops.c b/source/blender/editors/uvedit/uvedit_ops.c
index b805681cfd3..652d07f02db 100644
--- a/source/blender/editors/uvedit/uvedit_ops.c
+++ b/source/blender/editors/uvedit/uvedit_ops.c
@@ -36,15 +36,9 @@
#include "DNA_scene_types.h"
#include "DNA_space_types.h"
-#include "BLI_alloca.h"
#include "BLI_array.h"
-#include "BLI_blenlib.h"
-#include "BLI_hash.h"
-#include "BLI_kdopbvh.h"
#include "BLI_kdtree.h"
-#include "BLI_lasso_2d.h"
#include "BLI_math.h"
-#include "BLI_polyfill_2d.h"
#include "BLI_utildefines.h"
#include "BLT_translation.h"
@@ -52,31 +46,22 @@
#include "BKE_context.h"
#include "BKE_customdata.h"
#include "BKE_editmesh.h"
-#include "BKE_image.h"
#include "BKE_layer.h"
#include "BKE_main.h"
#include "BKE_material.h"
-#include "BKE_mesh.h"
#include "BKE_mesh_mapping.h"
#include "BKE_node.h"
-#include "BKE_report.h"
-#include "BKE_scene.h"
#include "DEG_depsgraph.h"
-#include "DEG_depsgraph_query.h"
#include "ED_image.h"
#include "ED_mesh.h"
#include "ED_node.h"
-#include "ED_object.h"
#include "ED_screen.h"
-#include "ED_select_utils.h"
-#include "ED_transform.h"
#include "ED_uvedit.h"
#include "RNA_access.h"
#include "RNA_define.h"
-#include "RNA_enum_types.h"
#include "WM_api.h"
#include "WM_message.h"
@@ -88,26 +73,6 @@
#include "uvedit_intern.h"
-static bool uv_select_is_any_selected(Scene *scene, Image *ima, Object *obedit);
-static bool uv_select_is_any_selected_multi(Scene *scene,
- Image *ima,
- Object **objects,
- const uint objects_len);
-static void uv_select_all_perform(Scene *scene, Image *ima, Object *obedit, int action);
-static void uv_select_all_perform_multi(
- Scene *scene, Image *ima, Object **objects, const uint objects_len, int action);
-static void uv_select_flush_from_tag_face(SpaceImage *sima,
- Scene *scene,
- Object *obedit,
- const bool select);
-static void uv_select_flush_from_tag_loop(SpaceImage *sima,
- Scene *scene,
- Object *obedit,
- const bool select);
-static void uv_select_tag_update_for_object(Depsgraph *depsgraph,
- const ToolSettings *ts,
- Object *obedit);
-
/* -------------------------------------------------------------------- */
/** \name State Testing
* \{ */
@@ -225,7 +190,7 @@ void ED_object_assign_active_image(Main *bmain, Object *ob, int mat_nr, Image *i
/** \name Space Conversion
* \{ */
-static void uvedit_pixel_to_float(SpaceImage *sima, float *dist, float pixeldist)
+void uvedit_pixel_to_float(SpaceImage *sima, float pixeldist, float r_dist[2])
{
int width, height;
@@ -237,351 +202,8 @@ static void uvedit_pixel_to_float(SpaceImage *sima, float *dist, float pixeldist
height = IMG_SIZE_FALLBACK;
}
- dist[0] = pixeldist / width;
- dist[1] = pixeldist / height;
-}
-
-/** \} */
-
-/* -------------------------------------------------------------------- */
-/** \name Visibility and Selection Utilities
- * \{ */
-
-static void uvedit_vertex_select_tagged(BMEditMesh *em,
- Scene *scene,
- bool select,
- int cd_loop_uv_offset)
-{
- BMFace *efa;
- BMLoop *l;
- BMIter iter, liter;
-
- BM_ITER_MESH (efa, &iter, em->bm, BM_FACES_OF_MESH) {
- BM_ITER_ELEM (l, &liter, efa, BM_LOOPS_OF_FACE) {
- if (BM_elem_flag_test(l->v, BM_ELEM_TAG)) {
- uvedit_uv_select_set(em, scene, l, select, false, cd_loop_uv_offset);
- }
- }
- }
-}
-
-bool uvedit_face_visible_nolocal_ex(const ToolSettings *ts, BMFace *efa)
-{
- if (ts->uv_flag & UV_SYNC_SELECTION) {
- return (BM_elem_flag_test(efa, BM_ELEM_HIDDEN) == 0);
- }
- else {
- return (BM_elem_flag_test(efa, BM_ELEM_HIDDEN) == 0 && BM_elem_flag_test(efa, BM_ELEM_SELECT));
- }
-}
-bool uvedit_face_visible_nolocal(const Scene *scene, BMFace *efa)
-{
- return uvedit_face_visible_nolocal_ex(scene->toolsettings, efa);
-}
-
-bool uvedit_face_visible_test_ex(const ToolSettings *ts, Object *obedit, Image *ima, BMFace *efa)
-{
- if (ts->uv_flag & UV_SHOW_SAME_IMAGE) {
- Image *face_image;
- ED_object_get_active_image(obedit, efa->mat_nr + 1, &face_image, NULL, NULL, NULL);
- return (face_image == ima) ? uvedit_face_visible_nolocal_ex(ts, efa) : false;
- }
- else {
- return uvedit_face_visible_nolocal_ex(ts, efa);
- }
-}
-bool uvedit_face_visible_test(const Scene *scene, Object *obedit, Image *ima, BMFace *efa)
-{
- return uvedit_face_visible_test_ex(scene->toolsettings, obedit, ima, efa);
-}
-
-bool uvedit_face_select_test_ex(const ToolSettings *ts, BMFace *efa, const int cd_loop_uv_offset)
-{
- if (ts->uv_flag & UV_SYNC_SELECTION) {
- return (BM_elem_flag_test(efa, BM_ELEM_SELECT));
- }
- else {
- BMLoop *l;
- MLoopUV *luv;
- BMIter liter;
-
- BM_ITER_ELEM (l, &liter, efa, BM_LOOPS_OF_FACE) {
- luv = BM_ELEM_CD_GET_VOID_P(l, cd_loop_uv_offset);
- if (!(luv->flag & MLOOPUV_VERTSEL)) {
- return false;
- }
- }
-
- return true;
- }
-}
-bool uvedit_face_select_test(const Scene *scene, BMFace *efa, const int cd_loop_uv_offset)
-{
- return uvedit_face_select_test_ex(scene->toolsettings, efa, cd_loop_uv_offset);
-}
-
-bool uvedit_face_select_set(const struct Scene *scene,
- struct BMEditMesh *em,
- struct BMFace *efa,
- const bool select,
- const bool do_history,
- const int cd_loop_uv_offset)
-{
- if (select) {
- return uvedit_face_select_enable(scene, em, efa, do_history, cd_loop_uv_offset);
- }
- else {
- return uvedit_face_select_disable(scene, em, efa, cd_loop_uv_offset);
- }
-}
-
-bool uvedit_face_select_enable(const Scene *scene,
- BMEditMesh *em,
- BMFace *efa,
- const bool do_history,
- const int cd_loop_uv_offset)
-{
- const ToolSettings *ts = scene->toolsettings;
-
- if (ts->uv_flag & UV_SYNC_SELECTION) {
- BM_face_select_set(em->bm, efa, true);
- if (do_history) {
- BM_select_history_store(em->bm, (BMElem *)efa);
- }
- }
- else {
- BMLoop *l;
- MLoopUV *luv;
- BMIter liter;
-
- BM_ITER_ELEM (l, &liter, efa, BM_LOOPS_OF_FACE) {
- luv = BM_ELEM_CD_GET_VOID_P(l, cd_loop_uv_offset);
- luv->flag |= MLOOPUV_VERTSEL;
- }
-
- return true;
- }
-
- return false;
-}
-
-bool uvedit_face_select_disable(const Scene *scene,
- BMEditMesh *em,
- BMFace *efa,
- const int cd_loop_uv_offset)
-{
- const ToolSettings *ts = scene->toolsettings;
-
- if (ts->uv_flag & UV_SYNC_SELECTION) {
- BM_face_select_set(em->bm, efa, false);
- }
- else {
- BMLoop *l;
- MLoopUV *luv;
- BMIter liter;
-
- BM_ITER_ELEM (l, &liter, efa, BM_LOOPS_OF_FACE) {
- luv = BM_ELEM_CD_GET_VOID_P(l, cd_loop_uv_offset);
- luv->flag &= ~MLOOPUV_VERTSEL;
- }
-
- return true;
- }
-
- return false;
-}
-
-bool uvedit_edge_select_test_ex(const ToolSettings *ts, BMLoop *l, const int cd_loop_uv_offset)
-{
- if (ts->uv_flag & UV_SYNC_SELECTION) {
- if (ts->selectmode & SCE_SELECT_FACE) {
- return BM_elem_flag_test(l->f, BM_ELEM_SELECT);
- }
- else if (ts->selectmode == SCE_SELECT_EDGE) {
- return BM_elem_flag_test(l->e, BM_ELEM_SELECT);
- }
- else {
- return BM_elem_flag_test(l->v, BM_ELEM_SELECT) &&
- BM_elem_flag_test(l->next->v, BM_ELEM_SELECT);
- }
- }
- else {
- MLoopUV *luv1, *luv2;
-
- luv1 = BM_ELEM_CD_GET_VOID_P(l, cd_loop_uv_offset);
- luv2 = BM_ELEM_CD_GET_VOID_P(l->next, cd_loop_uv_offset);
-
- return (luv1->flag & MLOOPUV_VERTSEL) && (luv2->flag & MLOOPUV_VERTSEL);
- }
-}
-bool uvedit_edge_select_test(const Scene *scene, BMLoop *l, const int cd_loop_uv_offset)
-{
- return uvedit_edge_select_test_ex(scene->toolsettings, l, cd_loop_uv_offset);
-}
-
-void uvedit_edge_select_set(BMEditMesh *em,
- const Scene *scene,
- BMLoop *l,
- const bool select,
- const bool do_history,
- const int cd_loop_uv_offset)
-
-{
- if (select) {
- uvedit_edge_select_enable(em, scene, l, do_history, cd_loop_uv_offset);
- }
- else {
- uvedit_edge_select_disable(em, scene, l, cd_loop_uv_offset);
- }
-}
-
-void uvedit_edge_select_enable(BMEditMesh *em,
- const Scene *scene,
- BMLoop *l,
- const bool do_history,
- const int cd_loop_uv_offset)
-
-{
- const ToolSettings *ts = scene->toolsettings;
-
- if (ts->uv_flag & UV_SYNC_SELECTION) {
- if (ts->selectmode & SCE_SELECT_FACE) {
- BM_face_select_set(em->bm, l->f, true);
- }
- else if (ts->selectmode & SCE_SELECT_EDGE) {
- BM_edge_select_set(em->bm, l->e, true);
- }
- else {
- BM_vert_select_set(em->bm, l->e->v1, true);
- BM_vert_select_set(em->bm, l->e->v2, true);
- }
-
- if (do_history) {
- BM_select_history_store(em->bm, (BMElem *)l->e);
- }
- }
- else {
- MLoopUV *luv1, *luv2;
-
- luv1 = BM_ELEM_CD_GET_VOID_P(l, cd_loop_uv_offset);
- luv2 = BM_ELEM_CD_GET_VOID_P(l->next, cd_loop_uv_offset);
-
- luv1->flag |= MLOOPUV_VERTSEL;
- luv2->flag |= MLOOPUV_VERTSEL;
- }
-}
-
-void uvedit_edge_select_disable(BMEditMesh *em,
- const Scene *scene,
- BMLoop *l,
- const int cd_loop_uv_offset)
-
-{
- const ToolSettings *ts = scene->toolsettings;
-
- if (ts->uv_flag & UV_SYNC_SELECTION) {
- if (ts->selectmode & SCE_SELECT_FACE) {
- BM_face_select_set(em->bm, l->f, false);
- }
- else if (ts->selectmode & SCE_SELECT_EDGE) {
- BM_edge_select_set(em->bm, l->e, false);
- }
- else {
- BM_vert_select_set(em->bm, l->e->v1, false);
- BM_vert_select_set(em->bm, l->e->v2, false);
- }
- }
- else {
- MLoopUV *luv1, *luv2;
-
- luv1 = BM_ELEM_CD_GET_VOID_P(l, cd_loop_uv_offset);
- luv2 = BM_ELEM_CD_GET_VOID_P(l->next, cd_loop_uv_offset);
-
- luv1->flag &= ~MLOOPUV_VERTSEL;
- luv2->flag &= ~MLOOPUV_VERTSEL;
- }
-}
-
-bool uvedit_uv_select_test_ex(const ToolSettings *ts, BMLoop *l, const int cd_loop_uv_offset)
-{
- if (ts->uv_flag & UV_SYNC_SELECTION) {
- if (ts->selectmode & SCE_SELECT_FACE) {
- return BM_elem_flag_test_bool(l->f, BM_ELEM_SELECT);
- }
- else {
- return BM_elem_flag_test_bool(l->v, BM_ELEM_SELECT);
- }
- }
- else {
- MLoopUV *luv = BM_ELEM_CD_GET_VOID_P(l, cd_loop_uv_offset);
- return (luv->flag & MLOOPUV_VERTSEL) != 0;
- }
-}
-bool uvedit_uv_select_test(const Scene *scene, BMLoop *l, const int cd_loop_uv_offset)
-{
- return uvedit_uv_select_test_ex(scene->toolsettings, l, cd_loop_uv_offset);
-}
-
-void uvedit_uv_select_set(BMEditMesh *em,
- const Scene *scene,
- BMLoop *l,
- const bool select,
- const bool do_history,
- const int cd_loop_uv_offset)
-{
- if (select) {
- uvedit_uv_select_enable(em, scene, l, do_history, cd_loop_uv_offset);
- }
- else {
- uvedit_uv_select_disable(em, scene, l, cd_loop_uv_offset);
- }
-}
-
-void uvedit_uv_select_enable(BMEditMesh *em,
- const Scene *scene,
- BMLoop *l,
- const bool do_history,
- const int cd_loop_uv_offset)
-{
- const ToolSettings *ts = scene->toolsettings;
-
- if (ts->uv_flag & UV_SYNC_SELECTION) {
- if (ts->selectmode & SCE_SELECT_FACE) {
- BM_face_select_set(em->bm, l->f, true);
- }
- else {
- BM_vert_select_set(em->bm, l->v, true);
- }
-
- if (do_history) {
- BM_select_history_remove(em->bm, (BMElem *)l->v);
- }
- }
- else {
- MLoopUV *luv = BM_ELEM_CD_GET_VOID_P(l, cd_loop_uv_offset);
- luv->flag |= MLOOPUV_VERTSEL;
- }
-}
-
-void uvedit_uv_select_disable(BMEditMesh *em,
- const Scene *scene,
- BMLoop *l,
- const int cd_loop_uv_offset)
-{
- const ToolSettings *ts = scene->toolsettings;
-
- if (ts->uv_flag & UV_SYNC_SELECTION) {
- if (ts->selectmode & SCE_SELECT_FACE) {
- BM_face_select_set(em->bm, l->f, false);
- }
- else {
- BM_vert_select_set(em->bm, l->v, false);
- }
- }
- else {
- MLoopUV *luv = BM_ELEM_CD_GET_VOID_P(l, cd_loop_uv_offset);
- luv->flag &= ~MLOOPUV_VERTSEL;
- }
+ r_dist[0] = pixeldist / width;
+ r_dist[1] = pixeldist / height;
}
/** \} */
@@ -630,12 +252,8 @@ void uv_poly_copy_aspect(float uv_orig[][2], float uv[][2], float aspx, float as
}
}
-bool ED_uvedit_minmax_multi(const Scene *scene,
- Image *ima,
- Object **objects_edit,
- uint objects_len,
- float r_min[2],
- float r_max[2])
+bool ED_uvedit_minmax_multi(
+ const Scene *scene, Object **objects_edit, uint objects_len, float r_min[2], float r_max[2])
{
bool changed = false;
INIT_MINMAX2(r_min, r_max);
@@ -652,7 +270,7 @@ bool ED_uvedit_minmax_multi(const Scene *scene,
const int cd_loop_uv_offset = CustomData_get_offset(&em->bm->ldata, CD_MLOOPUV);
BM_ITER_MESH (efa, &iter, em->bm, BM_FACES_OF_MESH) {
- if (!uvedit_face_visible_test(scene, obedit, ima, efa)) {
+ if (!uvedit_face_visible_test(scene, efa)) {
continue;
}
@@ -668,10 +286,9 @@ bool ED_uvedit_minmax_multi(const Scene *scene,
return changed;
}
-bool ED_uvedit_minmax(
- const Scene *scene, Image *ima, Object *obedit, float r_min[2], float r_max[2])
+bool ED_uvedit_minmax(const Scene *scene, Object *obedit, float r_min[2], float r_max[2])
{
- return ED_uvedit_minmax_multi(scene, ima, &obedit, 1, r_min, r_max);
+ return ED_uvedit_minmax_multi(scene, &obedit, 1, r_min, r_max);
}
/* Be careful when using this, it bypasses all synchronization options */
@@ -692,10 +309,12 @@ void ED_uvedit_select_all(BMesh *bm)
}
}
-static bool ED_uvedit_median_multi(
- const Scene *scene, Image *ima, Object **objects_edit, uint objects_len, float co[2])
+static bool ED_uvedit_median_multi(const Scene *scene,
+ Object **objects_edit,
+ uint objects_len,
+ float co[2])
{
- unsigned int sel = 0;
+ uint sel = 0;
zero_v2(co);
for (uint ob_index = 0; ob_index < objects_len; ob_index++) {
@@ -710,7 +329,7 @@ static bool ED_uvedit_median_multi(
const int cd_loop_uv_offset = CustomData_get_offset(&em->bm->ldata, CD_MLOOPUV);
BM_ITER_MESH (efa, &iter, em->bm, BM_FACES_OF_MESH) {
- if (!uvedit_face_visible_test(scene, obedit, ima, efa)) {
+ if (!uvedit_face_visible_test(scene, efa)) {
continue;
}
@@ -729,24 +348,20 @@ static bool ED_uvedit_median_multi(
return (sel != 0);
}
-bool ED_uvedit_center_multi(const Scene *scene,
- Image *ima,
- Object **objects_edit,
- uint objects_len,
- float cent[2],
- char mode)
+bool ED_uvedit_center_multi(
+ const Scene *scene, Object **objects_edit, uint objects_len, float cent[2], char mode)
{
bool changed = false;
if (mode == V3D_AROUND_CENTER_BOUNDS) { /* bounding box */
float min[2], max[2];
- if (ED_uvedit_minmax_multi(scene, ima, objects_edit, objects_len, min, max)) {
+ if (ED_uvedit_minmax_multi(scene, objects_edit, objects_len, min, max)) {
mid_v2_v2v2(cent, min, max);
changed = true;
}
}
else {
- if (ED_uvedit_median_multi(scene, ima, objects_edit, objects_len, cent)) {
+ if (ED_uvedit_median_multi(scene, objects_edit, objects_len, cent)) {
changed = true;
}
}
@@ -770,7 +385,7 @@ bool ED_uvedit_center_from_pivot_ex(SpaceImage *sima,
uint objects_len = 0;
Object **objects = BKE_view_layer_array_from_objects_in_edit_mode_unique_data_with_uvs(
view_layer, ((View3D *)NULL), &objects_len);
- *r_has_select = uv_select_is_any_selected_multi(scene, sima->image, objects, objects_len);
+ *r_has_select = uvedit_select_is_any_selected_multi(scene, objects, objects_len);
MEM_freeN(objects);
}
break;
@@ -779,7 +394,7 @@ bool ED_uvedit_center_from_pivot_ex(SpaceImage *sima,
uint objects_len = 0;
Object **objects = BKE_view_layer_array_from_objects_in_edit_mode_unique_data_with_uvs(
view_layer, ((View3D *)NULL), &objects_len);
- changed = ED_uvedit_center_multi(scene, sima->image, objects, objects_len, r_center, mode);
+ changed = ED_uvedit_center_multi(scene, objects, objects_len, r_center, mode);
MEM_freeN(objects);
if (r_has_select != NULL) {
*r_has_select = changed;
@@ -799,877 +414,6 @@ bool ED_uvedit_center_from_pivot(
/** \} */
/* -------------------------------------------------------------------- */
-/** \name Find Nearest Elements
- * \{ */
-
-bool uv_find_nearest_edge(
- Scene *scene, Image *ima, Object *obedit, const float co[2], UvNearestHit *hit)
-{
- BMEditMesh *em = BKE_editmesh_from_object(obedit);
- BMFace *efa;
- BMLoop *l;
- BMIter iter, liter;
- MLoopUV *luv, *luv_next;
- int i;
- bool found = false;
-
- const int cd_loop_uv_offset = CustomData_get_offset(&em->bm->ldata, CD_MLOOPUV);
-
- BM_mesh_elem_index_ensure(em->bm, BM_VERT);
-
- BM_ITER_MESH (efa, &iter, em->bm, BM_FACES_OF_MESH) {
- if (!uvedit_face_visible_test(scene, obedit, ima, efa)) {
- continue;
- }
- BM_ITER_ELEM_INDEX (l, &liter, efa, BM_LOOPS_OF_FACE, i) {
- luv = BM_ELEM_CD_GET_VOID_P(l, cd_loop_uv_offset);
- luv_next = BM_ELEM_CD_GET_VOID_P(l->next, cd_loop_uv_offset);
-
- const float dist_test_sq = dist_squared_to_line_segment_v2(co, luv->uv, luv_next->uv);
-
- if (dist_test_sq < hit->dist_sq) {
- hit->efa = efa;
-
- hit->l = l;
- hit->luv = luv;
- hit->luv_next = luv_next;
- hit->lindex = i;
-
- hit->dist_sq = dist_test_sq;
- found = true;
- }
- }
- }
- return found;
-}
-
-bool uv_find_nearest_edge_multi(Scene *scene,
- Image *ima,
- Object **objects,
- const uint objects_len,
- const float co[2],
- UvNearestHit *hit_final)
-{
- bool found = false;
- for (uint ob_index = 0; ob_index < objects_len; ob_index++) {
- Object *obedit = objects[ob_index];
- if (uv_find_nearest_edge(scene, ima, obedit, co, hit_final)) {
- hit_final->ob = obedit;
- found = true;
- }
- }
- return found;
-}
-
-bool uv_find_nearest_face(
- Scene *scene, Image *ima, Object *obedit, const float co[2], UvNearestHit *hit_final)
-{
- BMEditMesh *em = BKE_editmesh_from_object(obedit);
- bool found = false;
-
- const int cd_loop_uv_offset = CustomData_get_offset(&em->bm->ldata, CD_MLOOPUV);
-
- /* this will fill in hit.vert1 and hit.vert2 */
- float dist_sq_init = hit_final->dist_sq;
- UvNearestHit hit = *hit_final;
- if (uv_find_nearest_edge(scene, ima, obedit, co, &hit)) {
- hit.dist_sq = dist_sq_init;
- hit.l = NULL;
- hit.luv = hit.luv_next = NULL;
-
- BMIter iter;
- BMFace *efa;
-
- BM_ITER_MESH (efa, &iter, em->bm, BM_FACES_OF_MESH) {
- if (!uvedit_face_visible_test(scene, obedit, ima, efa)) {
- continue;
- }
-
- float cent[2];
- uv_poly_center(efa, cent, cd_loop_uv_offset);
-
- const float dist_test_sq = len_squared_v2v2(co, cent);
-
- if (dist_test_sq < hit.dist_sq) {
- hit.efa = efa;
- hit.dist_sq = dist_test_sq;
- found = true;
- }
- }
- }
- if (found) {
- *hit_final = hit;
- }
- return found;
-}
-
-bool uv_find_nearest_face_multi(Scene *scene,
- Image *ima,
- Object **objects,
- const uint objects_len,
- const float co[2],
- UvNearestHit *hit_final)
-{
- bool found = false;
- for (uint ob_index = 0; ob_index < objects_len; ob_index++) {
- Object *obedit = objects[ob_index];
- if (uv_find_nearest_face(scene, ima, obedit, co, hit_final)) {
- hit_final->ob = obedit;
- found = true;
- }
- }
- return found;
-}
-
-static bool uv_nearest_between(const BMLoop *l, const float co[2], const int cd_loop_uv_offset)
-{
- const float *uv_prev = ((MLoopUV *)BM_ELEM_CD_GET_VOID_P(l->prev, cd_loop_uv_offset))->uv;
- const float *uv_curr = ((MLoopUV *)BM_ELEM_CD_GET_VOID_P(l, cd_loop_uv_offset))->uv;
- const float *uv_next = ((MLoopUV *)BM_ELEM_CD_GET_VOID_P(l->next, cd_loop_uv_offset))->uv;
-
- return ((line_point_side_v2(uv_prev, uv_curr, co) > 0.0f) &&
- (line_point_side_v2(uv_next, uv_curr, co) <= 0.0f));
-}
-
-bool uv_find_nearest_vert(Scene *scene,
- Image *ima,
- Object *obedit,
- float const co[2],
- const float penalty_dist,
- UvNearestHit *hit_final)
-{
- bool found = false;
-
- /* this will fill in hit.vert1 and hit.vert2 */
- float dist_sq_init = hit_final->dist_sq;
- UvNearestHit hit = *hit_final;
- if (uv_find_nearest_edge(scene, ima, obedit, co, &hit)) {
- hit.dist_sq = dist_sq_init;
-
- hit.l = NULL;
- hit.luv = hit.luv_next = NULL;
-
- BMEditMesh *em = BKE_editmesh_from_object(obedit);
- BMFace *efa;
- BMIter iter;
-
- BM_mesh_elem_index_ensure(em->bm, BM_VERT);
-
- const int cd_loop_uv_offset = CustomData_get_offset(&em->bm->ldata, CD_MLOOPUV);
-
- BM_ITER_MESH (efa, &iter, em->bm, BM_FACES_OF_MESH) {
- if (!uvedit_face_visible_test(scene, obedit, ima, efa)) {
- continue;
- }
-
- BMIter liter;
- BMLoop *l;
- int i;
- BM_ITER_ELEM_INDEX (l, &liter, efa, BM_LOOPS_OF_FACE, i) {
- float dist_test_sq;
- MLoopUV *luv = BM_ELEM_CD_GET_VOID_P(l, cd_loop_uv_offset);
- if (penalty_dist != 0.0f && uvedit_uv_select_test(scene, l, cd_loop_uv_offset)) {
- dist_test_sq = len_v2v2(co, luv->uv) + penalty_dist;
- dist_test_sq = square_f(dist_test_sq);
- }
- else {
- dist_test_sq = len_squared_v2v2(co, luv->uv);
- }
-
- if (dist_test_sq <= hit.dist_sq) {
- if (dist_test_sq == hit.dist_sq) {
- if (!uv_nearest_between(l, co, cd_loop_uv_offset)) {
- continue;
- }
- }
-
- hit.dist_sq = dist_test_sq;
-
- hit.l = l;
- hit.luv = luv;
- hit.luv_next = BM_ELEM_CD_GET_VOID_P(l->next, cd_loop_uv_offset);
- hit.efa = efa;
- hit.lindex = i;
- found = true;
- }
- }
- }
- }
-
- if (found) {
- *hit_final = hit;
- }
-
- return found;
-}
-
-bool uv_find_nearest_vert_multi(Scene *scene,
- Image *ima,
- Object **objects,
- const uint objects_len,
- float const co[2],
- const float penalty_dist,
- UvNearestHit *hit_final)
-{
- bool found = false;
- for (uint ob_index = 0; ob_index < objects_len; ob_index++) {
- Object *obedit = objects[ob_index];
- if (uv_find_nearest_vert(scene, ima, obedit, co, penalty_dist, hit_final)) {
- hit_final->ob = obedit;
- found = true;
- }
- }
- return found;
-}
-
-bool ED_uvedit_nearest_uv(const Scene *scene,
- Object *obedit,
- Image *ima,
- const float co[2],
- float *dist_sq,
- float r_uv[2])
-{
- BMEditMesh *em = BKE_editmesh_from_object(obedit);
- BMIter iter;
- BMFace *efa;
- const float *uv_best = NULL;
- float dist_best = *dist_sq;
- const int cd_loop_uv_offset = CustomData_get_offset(&em->bm->ldata, CD_MLOOPUV);
- BM_ITER_MESH (efa, &iter, em->bm, BM_FACES_OF_MESH) {
- if (!uvedit_face_visible_test(scene, obedit, ima, efa)) {
- continue;
- }
- BMLoop *l_iter, *l_first;
- l_iter = l_first = BM_FACE_FIRST_LOOP(efa);
- do {
- const float *uv = ((const MLoopUV *)BM_ELEM_CD_GET_VOID_P(l_iter, cd_loop_uv_offset))->uv;
- const float dist_test = len_squared_v2v2(co, uv);
- if (dist_best > dist_test) {
- dist_best = dist_test;
- uv_best = uv;
- }
- } while ((l_iter = l_iter->next) != l_first);
- }
-
- if (uv_best != NULL) {
- copy_v2_v2(r_uv, uv_best);
- *dist_sq = dist_best;
- return true;
- }
- else {
- return false;
- }
-}
-
-bool ED_uvedit_nearest_uv_multi(const Scene *scene,
- Image *ima,
- Object **objects,
- const uint objects_len,
- const float co[2],
- float *dist_sq,
- float r_uv[2])
-{
- bool found = false;
- for (uint ob_index = 0; ob_index < objects_len; ob_index++) {
- Object *obedit = objects[ob_index];
- if (ED_uvedit_nearest_uv(scene, obedit, ima, co, dist_sq, r_uv)) {
- found = true;
- }
- }
- return found;
-}
-
-/** \} */
-
-/* -------------------------------------------------------------------- */
-/** \name Loop Select
- * \{ */
-
-static void uv_select_edgeloop_vertex_loop_flag(UvMapVert *first)
-{
- UvMapVert *iterv;
- int count = 0;
-
- for (iterv = first; iterv; iterv = iterv->next) {
- if (iterv->separate && iterv != first) {
- break;
- }
-
- count++;
- }
-
- if (count < 5) {
- first->flag = 1;
- }
-}
-
-static UvMapVert *uv_select_edgeloop_vertex_map_get(UvVertMap *vmap, BMFace *efa, BMLoop *l)
-{
- UvMapVert *iterv, *first;
- first = BM_uv_vert_map_at_index(vmap, BM_elem_index_get(l->v));
-
- for (iterv = first; iterv; iterv = iterv->next) {
- if (iterv->separate) {
- first = iterv;
- }
- if (iterv->poly_index == BM_elem_index_get(efa)) {
- return first;
- }
- }
-
- return NULL;
-}
-
-static bool uv_select_edgeloop_edge_tag_faces(BMEditMesh *em,
- UvMapVert *first1,
- UvMapVert *first2,
- int *totface)
-{
- UvMapVert *iterv1, *iterv2;
- BMFace *efa;
- int tot = 0;
-
- /* count number of faces this edge has */
- for (iterv1 = first1; iterv1; iterv1 = iterv1->next) {
- if (iterv1->separate && iterv1 != first1) {
- break;
- }
-
- for (iterv2 = first2; iterv2; iterv2 = iterv2->next) {
- if (iterv2->separate && iterv2 != first2) {
- break;
- }
-
- if (iterv1->poly_index == iterv2->poly_index) {
- /* if face already tagged, don't do this edge */
- efa = BM_face_at_index(em->bm, iterv1->poly_index);
- if (BM_elem_flag_test(efa, BM_ELEM_TAG)) {
- return false;
- }
-
- tot++;
- break;
- }
- }
- }
-
- if (*totface == 0) { /* start edge */
- *totface = tot;
- }
- else if (tot != *totface) { /* check for same number of faces as start edge */
- return false;
- }
-
- /* tag the faces */
- for (iterv1 = first1; iterv1; iterv1 = iterv1->next) {
- if (iterv1->separate && iterv1 != first1) {
- break;
- }
-
- for (iterv2 = first2; iterv2; iterv2 = iterv2->next) {
- if (iterv2->separate && iterv2 != first2) {
- break;
- }
-
- if (iterv1->poly_index == iterv2->poly_index) {
- efa = BM_face_at_index(em->bm, iterv1->poly_index);
- BM_elem_flag_enable(efa, BM_ELEM_TAG);
- break;
- }
- }
- }
-
- return true;
-}
-
-static int uv_select_edgeloop(Scene *scene,
- Image *ima,
- Object *obedit,
- UvNearestHit *hit,
- const float limit[2],
- const bool extend)
-{
- BMEditMesh *em = BKE_editmesh_from_object(obedit);
- BMFace *efa;
- BMIter iter, liter;
- BMLoop *l;
- UvVertMap *vmap;
- UvMapVert *iterv_curr;
- UvMapVert *iterv_next;
- int starttotf;
- bool looking, select;
-
- const int cd_loop_uv_offset = CustomData_get_offset(&em->bm->ldata, CD_MLOOPUV);
-
- /* setup */
- BM_mesh_elem_table_ensure(em->bm, BM_FACE);
- vmap = BM_uv_vert_map_create(em->bm, limit, false, false);
-
- BM_mesh_elem_index_ensure(em->bm, BM_VERT | BM_FACE);
-
- if (!extend) {
- uv_select_all_perform(scene, ima, obedit, SEL_DESELECT);
- }
-
- BM_mesh_elem_hflag_disable_all(em->bm, BM_FACE, BM_ELEM_TAG, false);
-
- /* set flags for first face and verts */
- iterv_curr = uv_select_edgeloop_vertex_map_get(vmap, hit->efa, hit->l);
- iterv_next = uv_select_edgeloop_vertex_map_get(vmap, hit->efa, hit->l->next);
- uv_select_edgeloop_vertex_loop_flag(iterv_curr);
- uv_select_edgeloop_vertex_loop_flag(iterv_next);
-
- starttotf = 0;
- uv_select_edgeloop_edge_tag_faces(em, iterv_curr, iterv_next, &starttotf);
-
- /* sorry, first edge isn't even ok */
- looking = !(iterv_curr->flag == 0 && iterv_next->flag == 0);
-
- /* iterate */
- while (looking) {
- looking = false;
-
- /* find correct valence edges which are not tagged yet, but connect to tagged one */
-
- BM_ITER_MESH (efa, &iter, em->bm, BM_FACES_OF_MESH) {
- if (!BM_elem_flag_test(efa, BM_ELEM_TAG) &&
- uvedit_face_visible_test(scene, obedit, ima, efa)) {
- BM_ITER_ELEM (l, &liter, efa, BM_LOOPS_OF_FACE) {
- /* check face not hidden and not tagged */
- if (!(iterv_curr = uv_select_edgeloop_vertex_map_get(vmap, efa, l))) {
- continue;
- }
- if (!(iterv_next = uv_select_edgeloop_vertex_map_get(vmap, efa, l->next))) {
- continue;
- }
-
- /* check if vertex is tagged and has right valence */
- if (iterv_curr->flag || iterv_next->flag) {
- if (uv_select_edgeloop_edge_tag_faces(em, iterv_curr, iterv_next, &starttotf)) {
- looking = true;
- BM_elem_flag_enable(efa, BM_ELEM_TAG);
-
- uv_select_edgeloop_vertex_loop_flag(iterv_curr);
- uv_select_edgeloop_vertex_loop_flag(iterv_next);
- break;
- }
- }
- }
- }
- }
- }
-
- /* do the actual select/deselect */
- iterv_curr = uv_select_edgeloop_vertex_map_get(vmap, hit->efa, hit->l);
- iterv_next = uv_select_edgeloop_vertex_map_get(vmap, hit->efa, hit->l->next);
- iterv_curr->flag = 1;
- iterv_next->flag = 1;
-
- if (extend) {
- select = !(uvedit_uv_select_test(scene, hit->l, cd_loop_uv_offset));
- }
- else {
- select = true;
- }
-
- BM_ITER_MESH (efa, &iter, em->bm, BM_FACES_OF_MESH) {
- BM_ITER_ELEM (l, &liter, efa, BM_LOOPS_OF_FACE) {
- iterv_curr = uv_select_edgeloop_vertex_map_get(vmap, efa, l);
-
- if (iterv_curr->flag) {
- uvedit_uv_select_set(em, scene, l, select, false, cd_loop_uv_offset);
- }
- }
- }
-
- /* cleanup */
- BM_uv_vert_map_free(vmap);
-
- return (select) ? 1 : -1;
-}
-
-/** \} */
-
-/* -------------------------------------------------------------------- */
-/** \name Select Linked
- * \{ */
-
-static void uv_select_linked_multi(Scene *scene,
- Image *ima,
- Object **objects,
- const uint objects_len,
- const float limit[2],
- UvNearestHit *hit_final,
- bool extend,
- bool deselect,
- bool toggle,
- bool select_faces)
-{
- /* loop over objects, or just use hit_final->ob */
- for (uint ob_index = 0; ob_index < objects_len; ob_index++) {
- if (hit_final && ob_index != 0) {
- break;
- }
- Object *obedit = hit_final ? hit_final->ob : objects[ob_index];
-
- BMFace *efa;
- BMLoop *l;
- BMIter iter, liter;
- MLoopUV *luv;
- UvVertMap *vmap;
- UvMapVert *vlist, *iterv, *startv;
- int i, stacksize = 0, *stack;
- unsigned int a;
- char *flag;
-
- BMEditMesh *em = BKE_editmesh_from_object(obedit);
- const int cd_loop_uv_offset = CustomData_get_offset(&em->bm->ldata, CD_MLOOPUV);
-
- BM_mesh_elem_table_ensure(em->bm, BM_FACE); /* we can use this too */
-
- /* Note, we had 'use winding' so we don't consider overlapping islands as connected, see T44320
- * this made *every* projection split the island into front/back islands.
- * Keep 'use_winding' to false, see: T50970.
- *
- * Better solve this by having a delimit option for select-linked operator,
- * keeping island-select working as is. */
- vmap = BM_uv_vert_map_create(em->bm, limit, !select_faces, false);
-
- if (vmap == NULL) {
- continue;
- }
-
- stack = MEM_mallocN(sizeof(*stack) * (em->bm->totface + 1), "UvLinkStack");
- flag = MEM_callocN(sizeof(*flag) * em->bm->totface, "UvLinkFlag");
-
- if (hit_final == NULL) {
- /* Use existing selection */
- BM_ITER_MESH_INDEX (efa, &iter, em->bm, BM_FACES_OF_MESH, a) {
- if (uvedit_face_visible_test(scene, obedit, ima, efa)) {
- if (select_faces) {
- if (BM_elem_flag_test(efa, BM_ELEM_SELECT)) {
- stack[stacksize] = a;
- stacksize++;
- flag[a] = 1;
- }
- }
- else {
- BM_ITER_ELEM (l, &liter, efa, BM_LOOPS_OF_FACE) {
- luv = BM_ELEM_CD_GET_VOID_P(l, cd_loop_uv_offset);
-
- if (luv->flag & MLOOPUV_VERTSEL) {
- stack[stacksize] = a;
- stacksize++;
- flag[a] = 1;
-
- break;
- }
- }
- }
- }
- }
- }
- else {
- BM_ITER_MESH_INDEX (efa, &iter, em->bm, BM_FACES_OF_MESH, a) {
- if (efa == hit_final->efa) {
- stack[stacksize] = a;
- stacksize++;
- flag[a] = 1;
- break;
- }
- }
- }
-
- while (stacksize > 0) {
-
- stacksize--;
- a = stack[stacksize];
-
- efa = BM_face_at_index(em->bm, a);
-
- BM_ITER_ELEM_INDEX (l, &liter, efa, BM_LOOPS_OF_FACE, i) {
-
- /* make_uv_vert_map_EM sets verts tmp.l to the indices */
- vlist = BM_uv_vert_map_at_index(vmap, BM_elem_index_get(l->v));
-
- startv = vlist;
-
- for (iterv = vlist; iterv; iterv = iterv->next) {
- if (iterv->separate) {
- startv = iterv;
- }
- if (iterv->poly_index == a) {
- break;
- }
- }
-
- for (iterv = startv; iterv; iterv = iterv->next) {
- if ((startv != iterv) && (iterv->separate)) {
- break;
- }
- else if (!flag[iterv->poly_index]) {
- flag[iterv->poly_index] = 1;
- stack[stacksize] = iterv->poly_index;
- stacksize++;
- }
- }
- }
- }
-
- /* Toggling - if any of the linked vertices is selected (and visible), we deselect. */
- if ((toggle == true) && (extend == false) && (deselect == false)) {
- BM_ITER_MESH_INDEX (efa, &iter, em->bm, BM_FACES_OF_MESH, a) {
- bool found_selected = false;
- if (!flag[a]) {
- continue;
- }
-
- if (select_faces) {
- if (BM_elem_flag_test(efa, BM_ELEM_SELECT) && !BM_elem_flag_test(efa, BM_ELEM_HIDDEN)) {
- found_selected = true;
- }
- }
- else {
- BM_ITER_ELEM (l, &liter, efa, BM_LOOPS_OF_FACE) {
- luv = BM_ELEM_CD_GET_VOID_P(l, cd_loop_uv_offset);
-
- if (luv->flag & MLOOPUV_VERTSEL) {
- found_selected = true;
- }
- }
-
- if (found_selected) {
- deselect = true;
- break;
- }
- }
- }
- }
-
-#define SET_SELECTION(value) \
- if (select_faces) { \
- BM_face_select_set(em->bm, efa, value); \
- } \
- else { \
- BM_ITER_ELEM (l, &liter, efa, BM_LOOPS_OF_FACE) { \
- luv = BM_ELEM_CD_GET_VOID_P(l, cd_loop_uv_offset); \
- luv->flag = (value) ? (luv->flag | MLOOPUV_VERTSEL) : (luv->flag & ~MLOOPUV_VERTSEL); \
- } \
- } \
- (void)0
-
- BM_ITER_MESH_INDEX (efa, &iter, em->bm, BM_FACES_OF_MESH, a) {
- if (!flag[a]) {
- if (!extend && !deselect && !toggle) {
- SET_SELECTION(false);
- }
- continue;
- }
-
- if (!deselect) {
- SET_SELECTION(true);
- }
- else {
- SET_SELECTION(false);
- }
- }
-
-#undef SET_SELECTION
-
- MEM_freeN(stack);
- MEM_freeN(flag);
- BM_uv_vert_map_free(vmap);
- }
-}
-
-/* WATCH IT: this returns first selected UV,
- * not ideal in many cases since there could be multiple */
-static float *uv_sel_co_from_eve(
- Scene *scene, Object *obedit, Image *ima, BMEditMesh *em, BMVert *eve)
-{
- BMIter liter;
- BMLoop *l;
-
- const int cd_loop_uv_offset = CustomData_get_offset(&em->bm->ldata, CD_MLOOPUV);
-
- BM_ITER_ELEM (l, &liter, eve, BM_LOOPS_OF_VERT) {
- if (!uvedit_face_visible_test(scene, obedit, ima, l->f)) {
- continue;
- }
-
- if (uvedit_uv_select_test(scene, l, cd_loop_uv_offset)) {
- MLoopUV *luv = BM_ELEM_CD_GET_VOID_P(l, cd_loop_uv_offset);
- return luv->uv;
- }
- }
-
- return NULL;
-}
-
-/** \} */
-
-/* -------------------------------------------------------------------- */
-/** \name Select More/Less Operator
- * \{ */
-
-static int uv_select_more_less(bContext *C, const bool select)
-{
- Scene *scene = CTX_data_scene(C);
- ViewLayer *view_layer = CTX_data_view_layer(C);
- Image *ima = CTX_data_edit_image(C);
- SpaceImage *sima = CTX_wm_space_image(C);
-
- BMFace *efa;
- BMLoop *l;
- BMIter iter, liter;
- const ToolSettings *ts = scene->toolsettings;
-
- uint objects_len = 0;
- Object **objects = BKE_view_layer_array_from_objects_in_edit_mode_unique_data_with_uvs(
- view_layer, ((View3D *)NULL), &objects_len);
-
- const bool is_uv_face_selectmode = (ts->uv_selectmode == UV_SELECT_FACE);
-
- for (uint ob_index = 0; ob_index < objects_len; ob_index++) {
- Object *obedit = objects[ob_index];
- BMEditMesh *em = BKE_editmesh_from_object(obedit);
-
- bool changed = false;
-
- const int cd_loop_uv_offset = CustomData_get_offset(&em->bm->ldata, CD_MLOOPUV);
-
- if (ts->uv_flag & UV_SYNC_SELECTION) {
- if (select) {
- EDBM_select_more(em, true);
- }
- else {
- EDBM_select_less(em, true);
- }
-
- DEG_id_tag_update(obedit->data, ID_RECALC_SELECT);
- WM_event_add_notifier(C, NC_GEOM | ND_SELECT, obedit->data);
- continue;
- }
-
- if (is_uv_face_selectmode) {
-
- /* clear tags */
- BM_mesh_elem_hflag_disable_all(em->bm, BM_FACE, BM_ELEM_TAG, false);
-
- /* mark loops to be selected */
- BM_ITER_MESH (efa, &iter, em->bm, BM_FACES_OF_MESH) {
- if (uvedit_face_visible_test(scene, obedit, ima, efa)) {
-
-#define IS_SEL 1
-#define IS_UNSEL 2
-
- int sel_state = 0;
-
- BM_ITER_ELEM (l, &liter, efa, BM_LOOPS_OF_FACE) {
- MLoopUV *luv = BM_ELEM_CD_GET_VOID_P(l, cd_loop_uv_offset);
- if (luv->flag & MLOOPUV_VERTSEL) {
- sel_state |= IS_SEL;
- }
- else {
- sel_state |= IS_UNSEL;
- }
-
- /* if we have a mixed selection, tag to grow it */
- if (sel_state == (IS_SEL | IS_UNSEL)) {
- BM_elem_flag_enable(efa, BM_ELEM_TAG);
- changed = true;
- break;
- }
- }
-
-#undef IS_SEL
-#undef IS_UNSEL
- }
- }
- }
- else {
-
- /* clear tags */
- BM_ITER_MESH (efa, &iter, em->bm, BM_FACES_OF_MESH) {
- BM_ITER_ELEM (l, &liter, efa, BM_LOOPS_OF_FACE) {
- BM_elem_flag_disable(l, BM_ELEM_TAG);
- }
- }
-
- /* mark loops to be selected */
- BM_ITER_MESH (efa, &iter, em->bm, BM_FACES_OF_MESH) {
- if (uvedit_face_visible_test(scene, obedit, ima, efa)) {
- BM_ITER_ELEM (l, &liter, efa, BM_LOOPS_OF_FACE) {
-
- MLoopUV *luv = BM_ELEM_CD_GET_VOID_P(l, cd_loop_uv_offset);
-
- if (((luv->flag & MLOOPUV_VERTSEL) != 0) == select) {
- BM_elem_flag_enable(l->next, BM_ELEM_TAG);
- BM_elem_flag_enable(l->prev, BM_ELEM_TAG);
- changed = true;
- }
- }
- }
- }
- }
-
- if (changed) {
- if (is_uv_face_selectmode) {
- /* Select tagged faces. */
- uv_select_flush_from_tag_face(sima, scene, obedit, select);
- }
- else {
- /* Select tagged loops. */
- uv_select_flush_from_tag_loop(sima, scene, obedit, select);
- }
- DEG_id_tag_update(obedit->data, ID_RECALC_SELECT);
- WM_event_add_notifier(C, NC_GEOM | ND_SELECT, obedit->data);
- }
- }
- MEM_freeN(objects);
-
- return OPERATOR_FINISHED;
-}
-
-static int uv_select_more_exec(bContext *C, wmOperator *UNUSED(op))
-{
- return uv_select_more_less(C, true);
-}
-
-static void UV_OT_select_more(wmOperatorType *ot)
-{
- /* identifiers */
- ot->name = "Select More";
- ot->description = "Select more UV vertices connected to initial selection";
- ot->idname = "UV_OT_select_more";
- ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
-
- /* api callbacks */
- ot->exec = uv_select_more_exec;
- ot->poll = ED_operator_uvedit_space_image;
-}
-
-static int uv_select_less_exec(bContext *C, wmOperator *UNUSED(op))
-{
- return uv_select_more_less(C, false);
-}
-
-static void UV_OT_select_less(wmOperatorType *ot)
-{
- /* identifiers */
- ot->name = "Select Less";
- ot->description = "Deselect UV vertices at the boundary of each selection region";
- ot->idname = "UV_OT_select_less";
- ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
-
- /* api callbacks */
- ot->exec = uv_select_less_exec;
- ot->poll = ED_operator_uvedit_space_image;
-}
-
-/** \} */
-
-/* -------------------------------------------------------------------- */
/** \name Weld Align Operator
* \{ */
@@ -1688,7 +432,6 @@ static void uv_weld_align(bContext *C, eUVWeldAlign tool)
Scene *scene = CTX_data_scene(C);
ViewLayer *view_layer = CTX_data_view_layer(C);
SpaceImage *sima = CTX_wm_space_image(C);
- Image *ima = CTX_data_edit_image(C);
const ToolSettings *ts = scene->toolsettings;
const bool synced_selection = (ts->uv_flag & UV_SYNC_SELECTION) != 0;
float cent[2], min[2], max[2];
@@ -1715,7 +458,7 @@ static void uv_weld_align(bContext *C, eUVWeldAlign tool)
BMLoop *l;
BM_ITER_MESH (efa, &iter, em->bm, BM_FACES_OF_MESH) {
- if (!uvedit_face_visible_test(scene, obedit, ima, efa)) {
+ if (!uvedit_face_visible_test(scene, efa)) {
continue;
}
@@ -1730,7 +473,7 @@ static void uv_weld_align(bContext *C, eUVWeldAlign tool)
tool = (max[0] - min[0] >= max[1] - min[1]) ? UV_ALIGN_Y : UV_ALIGN_X;
}
- ED_uvedit_center_multi(scene, ima, objects, objects_len, cent, 0);
+ ED_uvedit_center_multi(scene, objects, objects_len, cent, 0);
for (uint ob_index = 0; ob_index < objects_len; ob_index++) {
Object *obedit = objects[ob_index];
@@ -1749,7 +492,7 @@ static void uv_weld_align(bContext *C, eUVWeldAlign tool)
BMLoop *l;
BM_ITER_MESH (efa, &iter, em->bm, BM_FACES_OF_MESH) {
- if (!uvedit_face_visible_test(scene, obedit, ima, efa)) {
+ if (!uvedit_face_visible_test(scene, efa)) {
continue;
}
@@ -1769,7 +512,7 @@ static void uv_weld_align(bContext *C, eUVWeldAlign tool)
BMLoop *l;
BM_ITER_MESH (efa, &iter, em->bm, BM_FACES_OF_MESH) {
- if (!uvedit_face_visible_test(scene, obedit, ima, efa)) {
+ if (!uvedit_face_visible_test(scene, efa)) {
continue;
}
@@ -1796,7 +539,7 @@ static void uv_weld_align(bContext *C, eUVWeldAlign tool)
/* tag verts with a selected UV */
BM_ITER_MESH (eve, &iter, em->bm, BM_VERTS_OF_MESH) {
BM_ITER_ELEM (l, &liter, eve, BM_LOOPS_OF_VERT) {
- if (!uvedit_face_visible_test(scene, obedit, ima, l->f)) {
+ if (!uvedit_face_visible_test(scene, l->f)) {
continue;
}
@@ -1866,9 +609,10 @@ static void uv_weld_align(bContext *C, eUVWeldAlign tool)
if (BLI_array_len(eve_line) > 2) {
/* we know the returns from these must be valid */
- const float *uv_start = uv_sel_co_from_eve(scene, obedit, ima, em, eve_line[0]);
- const float *uv_end = uv_sel_co_from_eve(
- scene, obedit, ima, em, eve_line[BLI_array_len(eve_line) - 1]);
+ const float *uv_start = uvedit_first_selected_uv_from_vertex(
+ scene, eve_line[0], cd_loop_uv_offset);
+ const float *uv_end = uvedit_first_selected_uv_from_vertex(
+ scene, eve_line[BLI_array_len(eve_line) - 1], cd_loop_uv_offset);
/* For UV_STRAIGHTEN_X & UV_STRAIGHTEN_Y modes */
float a = 0.0f;
eUVWeldAlign tool_local = tool;
@@ -1893,7 +637,7 @@ static void uv_weld_align(bContext *C, eUVWeldAlign tool)
/* go over all verts except for endpoints */
for (i = 0; i < BLI_array_len(eve_line); i++) {
BM_ITER_ELEM (l, &liter, eve_line[i], BM_LOOPS_OF_VERT) {
- if (!uvedit_face_visible_test(scene, obedit, ima, l->f)) {
+ if (!uvedit_face_visible_test(scene, l->f)) {
continue;
}
@@ -2001,7 +745,6 @@ static int uv_remove_doubles_to_selected(bContext *C, wmOperator *op)
Scene *scene = CTX_data_scene(C);
ViewLayer *view_layer = CTX_data_view_layer(C);
SpaceImage *sima = CTX_wm_space_image(C);
- Image *ima = CTX_data_edit_image(C);
const ToolSettings *ts = scene->toolsettings;
const float threshold = RNA_float_get(op->ptr, "threshold");
@@ -2055,7 +798,7 @@ static int uv_remove_doubles_to_selected(bContext *C, wmOperator *op)
const int cd_loop_uv_offset = CustomData_get_offset(&em->bm->ldata, CD_MLOOPUV);
BM_ITER_MESH (efa, &iter, em->bm, BM_FACES_OF_MESH) {
- if (!uvedit_face_visible_test(scene, obedit, ima, efa)) {
+ if (!uvedit_face_visible_test(scene, efa)) {
continue;
}
@@ -2146,7 +889,6 @@ static int uv_remove_doubles_to_unselected(bContext *C, wmOperator *op)
Scene *scene = CTX_data_scene(C);
ViewLayer *view_layer = CTX_data_view_layer(C);
SpaceImage *sima = CTX_wm_space_image(C);
- Image *ima = CTX_data_edit_image(C);
const ToolSettings *ts = scene->toolsettings;
const float threshold = RNA_float_get(op->ptr, "threshold");
@@ -2186,7 +928,7 @@ static int uv_remove_doubles_to_unselected(bContext *C, wmOperator *op)
const int cd_loop_uv_offset = CustomData_get_offset(&em->bm->ldata, CD_MLOOPUV);
BM_ITER_MESH (efa, &iter, em->bm, BM_FACES_OF_MESH) {
- if (!uvedit_face_visible_test(scene, obedit, ima, efa)) {
+ if (!uvedit_face_visible_test(scene, efa)) {
continue;
}
@@ -2219,7 +961,7 @@ static int uv_remove_doubles_to_unselected(bContext *C, wmOperator *op)
const int cd_loop_uv_offset = CustomData_get_offset(&em->bm->ldata, CD_MLOOPUV);
BM_ITER_MESH (efa, &iter, em->bm, BM_FACES_OF_MESH) {
- if (!uvedit_face_visible_test(scene, obedit, ima, efa)) {
+ if (!uvedit_face_visible_test(scene, efa)) {
continue;
}
@@ -2316,1665 +1058,6 @@ static void UV_OT_weld(wmOperatorType *ot)
/** \} */
/* -------------------------------------------------------------------- */
-/** \name (De)Select All Operator
- * \{ */
-
-static bool uv_select_is_any_selected(Scene *scene, Image *ima, Object *obedit)
-{
- const ToolSettings *ts = scene->toolsettings;
- BMEditMesh *em = BKE_editmesh_from_object(obedit);
- BMFace *efa;
- BMLoop *l;
- BMIter iter, liter;
- MLoopUV *luv;
-
- if (ts->uv_flag & UV_SYNC_SELECTION) {
- return (em->bm->totvertsel || em->bm->totedgesel || em->bm->totfacesel);
- }
- else {
- const int cd_loop_uv_offset = CustomData_get_offset(&em->bm->ldata, CD_MLOOPUV);
- BM_ITER_MESH (efa, &iter, em->bm, BM_FACES_OF_MESH) {
- if (!uvedit_face_visible_test(scene, obedit, ima, efa)) {
- continue;
- }
- BM_ITER_ELEM (l, &liter, efa, BM_LOOPS_OF_FACE) {
- luv = BM_ELEM_CD_GET_VOID_P(l, cd_loop_uv_offset);
- if (luv->flag & MLOOPUV_VERTSEL) {
- return true;
- }
- }
- }
- }
- return false;
-}
-
-static bool uv_select_is_any_selected_multi(Scene *scene,
- Image *ima,
- Object **objects,
- const uint objects_len)
-{
- bool found = false;
- for (uint ob_index = 0; ob_index < objects_len; ob_index++) {
- Object *obedit = objects[ob_index];
- if (uv_select_is_any_selected(scene, ima, obedit)) {
- found = true;
- break;
- }
- }
- return found;
-}
-
-static void uv_select_all_perform(Scene *scene, Image *ima, Object *obedit, int action)
-{
- const ToolSettings *ts = scene->toolsettings;
- BMEditMesh *em = BKE_editmesh_from_object(obedit);
- BMFace *efa;
- BMLoop *l;
- BMIter iter, liter;
- MLoopUV *luv;
-
- const int cd_loop_uv_offset = CustomData_get_offset(&em->bm->ldata, CD_MLOOPUV);
-
- if (action == SEL_TOGGLE) {
- action = uv_select_is_any_selected(scene, ima, obedit) ? SEL_DESELECT : SEL_SELECT;
- }
-
- if (ts->uv_flag & UV_SYNC_SELECTION) {
- switch (action) {
- case SEL_TOGGLE:
- EDBM_select_toggle_all(em);
- break;
- case SEL_SELECT:
- EDBM_flag_enable_all(em, BM_ELEM_SELECT);
- break;
- case SEL_DESELECT:
- EDBM_flag_disable_all(em, BM_ELEM_SELECT);
- break;
- case SEL_INVERT:
- EDBM_select_swap(em);
- EDBM_selectmode_flush(em);
- break;
- }
- }
- else {
- BM_ITER_MESH (efa, &iter, em->bm, BM_FACES_OF_MESH) {
- if (!uvedit_face_visible_test(scene, obedit, ima, efa)) {
- continue;
- }
-
- BM_ITER_ELEM (l, &liter, efa, BM_LOOPS_OF_FACE) {
- luv = BM_ELEM_CD_GET_VOID_P(l, cd_loop_uv_offset);
-
- switch (action) {
- case SEL_SELECT:
- luv->flag |= MLOOPUV_VERTSEL;
- break;
- case SEL_DESELECT:
- luv->flag &= ~MLOOPUV_VERTSEL;
- break;
- case SEL_INVERT:
- luv->flag ^= MLOOPUV_VERTSEL;
- break;
- }
- }
- }
- }
-}
-
-static void uv_select_all_perform_multi(
- Scene *scene, Image *ima, Object **objects, const uint objects_len, int action)
-{
- if (action == SEL_TOGGLE) {
- action = uv_select_is_any_selected_multi(scene, ima, objects, objects_len) ? SEL_DESELECT :
- SEL_SELECT;
- }
-
- for (uint ob_index = 0; ob_index < objects_len; ob_index++) {
- Object *obedit = objects[ob_index];
- uv_select_all_perform(scene, ima, obedit, action);
- }
-}
-
-static int uv_select_all_exec(bContext *C, wmOperator *op)
-{
- Depsgraph *depsgraph = CTX_data_ensure_evaluated_depsgraph(C);
- Scene *scene = CTX_data_scene(C);
- const ToolSettings *ts = scene->toolsettings;
- Image *ima = CTX_data_edit_image(C);
- ViewLayer *view_layer = CTX_data_view_layer(C);
-
- int action = RNA_enum_get(op->ptr, "action");
-
- uint objects_len = 0;
- Object **objects = BKE_view_layer_array_from_objects_in_edit_mode_unique_data_with_uvs(
- view_layer, ((View3D *)NULL), &objects_len);
-
- uv_select_all_perform_multi(scene, ima, objects, objects_len, action);
-
- for (uint ob_index = 0; ob_index < objects_len; ob_index++) {
- Object *obedit = objects[ob_index];
- uv_select_tag_update_for_object(depsgraph, ts, obedit);
- }
-
- MEM_freeN(objects);
-
- return OPERATOR_FINISHED;
-}
-
-static void UV_OT_select_all(wmOperatorType *ot)
-{
- /* identifiers */
- ot->name = "(De)select All";
- ot->description = "Change selection of all UV vertices";
- ot->idname = "UV_OT_select_all";
- ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
-
- /* api callbacks */
- ot->exec = uv_select_all_exec;
- ot->poll = ED_operator_uvedit;
-
- WM_operator_properties_select_all(ot);
-}
-
-/** \} */
-
-/* -------------------------------------------------------------------- */
-/** \name Mouse Select Operator
- * \{ */
-
-static bool uv_sticky_select(
- float *limit, int hitv[], int v, float *hituv[], float *uv, int sticky, int hitlen)
-{
- int i;
-
- /* this function test if some vertex needs to selected
- * in addition to the existing ones due to sticky select */
- if (sticky == SI_STICKY_DISABLE) {
- return false;
- }
-
- for (i = 0; i < hitlen; i++) {
- if (hitv[i] == v) {
- if (sticky == SI_STICKY_LOC) {
- if (fabsf(hituv[i][0] - uv[0]) < limit[0] && fabsf(hituv[i][1] - uv[1]) < limit[1]) {
- return true;
- }
- }
- else if (sticky == SI_STICKY_VERTEX) {
- return true;
- }
- }
- }
-
- return false;
-}
-
-static int uv_mouse_select_multi(bContext *C,
- Object **objects,
- uint objects_len,
- const float co[2],
- const bool extend,
- const bool deselect_all,
- const bool loop)
-{
- Depsgraph *depsgraph = CTX_data_ensure_evaluated_depsgraph(C);
- SpaceImage *sima = CTX_wm_space_image(C);
- Scene *scene = CTX_data_scene(C);
- const ToolSettings *ts = scene->toolsettings;
- Image *ima = CTX_data_edit_image(C);
- BMFace *efa;
- BMLoop *l;
- BMIter iter, liter;
- MLoopUV *luv;
- UvNearestHit hit = UV_NEAREST_HIT_INIT;
- int i, selectmode, sticky, sync, *hitv = NULL;
- bool select = true;
- bool found_item = false;
- /* 0 == don't flush, 1 == sel, -1 == desel; only use when selection sync is enabled */
- int flush = 0;
- int hitlen = 0;
- float limit[2], **hituv = NULL;
-
- /* notice 'limit' is the same no matter the zoom level, since this is like
- * remove doubles and could annoying if it joined points when zoomed out.
- * 'penalty' is in screen pixel space otherwise zooming in on a uv-vert and
- * shift-selecting can consider an adjacent point close enough to add to
- * the selection rather than de-selecting the closest. */
-
- float penalty_dist;
- {
- float penalty[2];
- uvedit_pixel_to_float(sima, limit, 0.05f);
- uvedit_pixel_to_float(sima, penalty, 5.0f / (sima ? sima->zoom : 1.0f));
- penalty_dist = len_v2(penalty);
- }
-
- /* retrieve operation mode */
- if (ts->uv_flag & UV_SYNC_SELECTION) {
- sync = 1;
-
- if (ts->selectmode & SCE_SELECT_FACE) {
- selectmode = UV_SELECT_FACE;
- }
- else if (ts->selectmode & SCE_SELECT_EDGE) {
- selectmode = UV_SELECT_EDGE;
- }
- else {
- selectmode = UV_SELECT_VERTEX;
- }
-
- sticky = SI_STICKY_DISABLE;
- }
- else {
- sync = 0;
- selectmode = ts->uv_selectmode;
- sticky = (sima) ? sima->sticky : 1;
- }
-
- /* find nearest element */
- if (loop) {
- /* find edge */
- found_item = uv_find_nearest_edge_multi(scene, ima, objects, objects_len, co, &hit);
- }
- else if (selectmode == UV_SELECT_VERTEX) {
- /* find vertex */
- found_item = uv_find_nearest_vert_multi(
- scene, ima, objects, objects_len, co, penalty_dist, &hit);
- found_item = found_item && (!deselect_all || hit.dist_sq < penalty_dist);
-
- if (found_item) {
- /* mark 1 vertex as being hit */
- hitv = BLI_array_alloca(hitv, hit.efa->len);
- hituv = BLI_array_alloca(hituv, hit.efa->len);
- copy_vn_i(hitv, hit.efa->len, 0xFFFFFFFF);
-
- hitv[hit.lindex] = BM_elem_index_get(hit.l->v);
- hituv[hit.lindex] = hit.luv->uv;
-
- hitlen = hit.efa->len;
- }
- }
- else if (selectmode == UV_SELECT_EDGE) {
- /* find edge */
- found_item = uv_find_nearest_edge_multi(scene, ima, objects, objects_len, co, &hit);
- found_item = found_item && (!deselect_all || hit.dist_sq < penalty_dist);
-
- if (found_item) {
- /* mark 2 edge vertices as being hit */
- hitv = BLI_array_alloca(hitv, hit.efa->len);
- hituv = BLI_array_alloca(hituv, hit.efa->len);
- copy_vn_i(hitv, hit.efa->len, 0xFFFFFFFF);
-
- hitv[hit.lindex] = BM_elem_index_get(hit.l->v);
- hitv[(hit.lindex + 1) % hit.efa->len] = BM_elem_index_get(hit.l->next->v);
- hituv[hit.lindex] = hit.luv->uv;
- hituv[(hit.lindex + 1) % hit.efa->len] = hit.luv_next->uv;
-
- hitlen = hit.efa->len;
- }
- }
- else if (selectmode == UV_SELECT_FACE) {
- /* find face */
- found_item = uv_find_nearest_face_multi(scene, ima, objects, objects_len, co, &hit);
- found_item = found_item && (!deselect_all || hit.dist_sq < penalty_dist);
-
- if (found_item) {
- BMEditMesh *em = BKE_editmesh_from_object(hit.ob);
- const int cd_loop_uv_offset = CustomData_get_offset(&em->bm->ldata, CD_MLOOPUV);
-
- /* make active */
- BM_mesh_active_face_set(em->bm, hit.efa);
-
- /* mark all face vertices as being hit */
-
- hitv = BLI_array_alloca(hitv, hit.efa->len);
- hituv = BLI_array_alloca(hituv, hit.efa->len);
- BM_ITER_ELEM_INDEX (l, &liter, hit.efa, BM_LOOPS_OF_FACE, i) {
- luv = BM_ELEM_CD_GET_VOID_P(l, cd_loop_uv_offset);
- hituv[i] = luv->uv;
- hitv[i] = BM_elem_index_get(l->v);
- }
-
- hitlen = hit.efa->len;
- }
- }
- else if (selectmode == UV_SELECT_ISLAND) {
- found_item = uv_find_nearest_edge_multi(scene, ima, objects, objects_len, co, &hit);
- found_item = found_item && (!deselect_all || hit.dist_sq < penalty_dist);
- }
-
- if (!found_item) {
- if (deselect_all) {
- uv_select_all_perform_multi(scene, ima, objects, objects_len, SEL_DESELECT);
-
- for (uint ob_index = 0; ob_index < objects_len; ob_index++) {
- Object *obedit = objects[ob_index];
- uv_select_tag_update_for_object(depsgraph, ts, obedit);
- }
-
- return OPERATOR_PASS_THROUGH | OPERATOR_FINISHED;
- }
- return OPERATOR_CANCELLED;
- }
-
- Object *obedit = hit.ob;
- BMEditMesh *em = BKE_editmesh_from_object(obedit);
- const int cd_loop_uv_offset = CustomData_get_offset(&em->bm->ldata, CD_MLOOPUV);
-
- /* do selection */
- if (loop) {
- if (!extend) {
- /* TODO(MULTI_EDIT): We only need to de-select non-active */
- uv_select_all_perform_multi(scene, ima, objects, objects_len, SEL_DESELECT);
- }
- flush = uv_select_edgeloop(scene, ima, obedit, &hit, limit, extend);
- }
- else if (selectmode == UV_SELECT_ISLAND) {
- if (!extend) {
- /* TODO(MULTI_EDIT): We only need to de-select non-active */
- uv_select_all_perform_multi(scene, ima, objects, objects_len, SEL_DESELECT);
- }
- /* Current behavior of 'extend'
- * is actually toggling, so pass extend flag as 'toggle' here */
- uv_select_linked_multi(
- scene, ima, objects, objects_len, limit, &hit, false, false, extend, false);
- }
- else if (extend) {
- if (selectmode == UV_SELECT_VERTEX) {
- /* (de)select uv vertex */
- select = !uvedit_uv_select_test(scene, hit.l, cd_loop_uv_offset);
- uvedit_uv_select_set(em, scene, hit.l, select, true, cd_loop_uv_offset);
- flush = 1;
- }
- else if (selectmode == UV_SELECT_EDGE) {
- /* (de)select edge */
- select = !(uvedit_edge_select_test(scene, hit.l, cd_loop_uv_offset));
- uvedit_edge_select_set(em, scene, hit.l, select, true, cd_loop_uv_offset);
- flush = 1;
- }
- else if (selectmode == UV_SELECT_FACE) {
- /* (de)select face */
- select = !(uvedit_face_select_test(scene, hit.efa, cd_loop_uv_offset));
- uvedit_face_select_set(scene, em, hit.efa, select, true, cd_loop_uv_offset);
- flush = -1;
- }
-
- /* de-selecting an edge may deselect a face too - validate */
- if (sync) {
- if (select == false) {
- BM_select_history_validate(em->bm);
- }
- }
-
- /* (de)select sticky uv nodes */
- if (sticky != SI_STICKY_DISABLE) {
-
- BM_mesh_elem_index_ensure(em->bm, BM_VERT);
-
- BM_ITER_MESH (efa, &iter, em->bm, BM_FACES_OF_MESH) {
- if (!uvedit_face_visible_test(scene, obedit, ima, efa)) {
- continue;
- }
-
- BM_ITER_ELEM (l, &liter, efa, BM_LOOPS_OF_FACE) {
- luv = BM_ELEM_CD_GET_VOID_P(l, cd_loop_uv_offset);
- if (uv_sticky_select(
- limit, hitv, BM_elem_index_get(l->v), hituv, luv->uv, sticky, hitlen)) {
- uvedit_uv_select_set(em, scene, l, select, false, cd_loop_uv_offset);
- }
- }
- }
-
- flush = select ? 1 : -1;
- }
- }
- else {
- /* deselect all */
- uv_select_all_perform_multi(scene, ima, objects, objects_len, SEL_DESELECT);
-
- if (selectmode == UV_SELECT_VERTEX) {
- /* select vertex */
- uvedit_uv_select_enable(em, scene, hit.l, true, cd_loop_uv_offset);
- flush = 1;
- }
- else if (selectmode == UV_SELECT_EDGE) {
- /* select edge */
- uvedit_edge_select_enable(em, scene, hit.l, true, cd_loop_uv_offset);
- flush = 1;
- }
- else if (selectmode == UV_SELECT_FACE) {
- /* select face */
- uvedit_face_select_enable(scene, em, hit.efa, true, cd_loop_uv_offset);
- }
-
- /* select sticky uvs */
- if (sticky != SI_STICKY_DISABLE) {
- BM_ITER_MESH (efa, &iter, em->bm, BM_FACES_OF_MESH) {
- if (!uvedit_face_visible_test(scene, obedit, ima, efa)) {
- continue;
- }
-
- BM_ITER_ELEM (l, &liter, efa, BM_LOOPS_OF_FACE) {
- if (sticky == SI_STICKY_DISABLE) {
- continue;
- }
- luv = BM_ELEM_CD_GET_VOID_P(l, cd_loop_uv_offset);
-
- if (uv_sticky_select(
- limit, hitv, BM_elem_index_get(l->v), hituv, luv->uv, sticky, hitlen)) {
- uvedit_uv_select_enable(em, scene, l, false, cd_loop_uv_offset);
- }
-
- flush = 1;
- }
- }
- }
- }
-
- if (sync) {
- /* flush for mesh selection */
-
- /* before bmesh */
-#if 0
- if (ts->selectmode != SCE_SELECT_FACE) {
- if (flush == 1) {
- EDBM_select_flush(em);
- }
- else if (flush == -1) {
- EDBM_deselect_flush(em);
- }
- }
-#else
- if (flush != 0) {
- if (loop) {
- /* push vertex -> edge selection */
- if (select) {
- EDBM_select_flush(em);
- }
- else {
- EDBM_deselect_flush(em);
- }
- }
- else {
- EDBM_selectmode_flush(em);
- }
- }
-#endif
- }
-
- for (uint ob_index = 0; ob_index < objects_len; ob_index++) {
- Object *obiter = objects[ob_index];
- uv_select_tag_update_for_object(depsgraph, ts, obiter);
- }
-
- return OPERATOR_PASS_THROUGH | OPERATOR_FINISHED;
-}
-static int uv_mouse_select(
- bContext *C, const float co[2], const bool extend, const bool deselect_all, const bool loop)
-{
- ViewLayer *view_layer = CTX_data_view_layer(C);
- uint objects_len = 0;
- Object **objects = BKE_view_layer_array_from_objects_in_edit_mode_unique_data_with_uvs(
- view_layer, ((View3D *)NULL), &objects_len);
- int ret = uv_mouse_select_multi(C, objects, objects_len, co, extend, deselect_all, loop);
- MEM_freeN(objects);
- return ret;
-}
-
-static int uv_select_exec(bContext *C, wmOperator *op)
-{
- float co[2];
-
- RNA_float_get_array(op->ptr, "location", co);
- const bool extend = RNA_boolean_get(op->ptr, "extend");
- const bool deselect_all = RNA_boolean_get(op->ptr, "deselect_all");
- const bool loop = false;
-
- return uv_mouse_select(C, co, extend, deselect_all, loop);
-}
-
-static int uv_select_invoke(bContext *C, wmOperator *op, const wmEvent *event)
-{
- ARegion *region = CTX_wm_region(C);
- float co[2];
-
- UI_view2d_region_to_view(&region->v2d, event->mval[0], event->mval[1], &co[0], &co[1]);
- RNA_float_set_array(op->ptr, "location", co);
-
- return uv_select_exec(C, op);
-}
-
-static void UV_OT_select(wmOperatorType *ot)
-{
- /* identifiers */
- ot->name = "Select";
- ot->description = "Select UV vertices";
- ot->idname = "UV_OT_select";
- ot->flag = OPTYPE_UNDO;
-
- /* api callbacks */
- ot->exec = uv_select_exec;
- ot->invoke = uv_select_invoke;
- ot->poll = ED_operator_uvedit; /* requires space image */
-
- /* properties */
- PropertyRNA *prop;
- RNA_def_boolean(ot->srna,
- "extend",
- 0,
- "Extend",
- "Extend selection rather than clearing the existing selection");
- prop = RNA_def_boolean(ot->srna,
- "deselect_all",
- false,
- "Deselect On Nothing",
- "Deselect all when nothing under the cursor");
- RNA_def_property_flag(prop, PROP_SKIP_SAVE);
-
- RNA_def_float_vector(
- ot->srna,
- "location",
- 2,
- NULL,
- -FLT_MAX,
- FLT_MAX,
- "Location",
- "Mouse location in normalized coordinates, 0.0 to 1.0 is within the image bounds",
- -100.0f,
- 100.0f);
-}
-
-/** \} */
-
-/* -------------------------------------------------------------------- */
-/** \name Loop Select Operator
- * \{ */
-
-static int uv_select_loop_exec(bContext *C, wmOperator *op)
-{
- float co[2];
-
- RNA_float_get_array(op->ptr, "location", co);
- const bool extend = RNA_boolean_get(op->ptr, "extend");
- const bool deselect_all = false;
- const bool loop = true;
-
- return uv_mouse_select(C, co, extend, deselect_all, loop);
-}
-
-static int uv_select_loop_invoke(bContext *C, wmOperator *op, const wmEvent *event)
-{
- ARegion *region = CTX_wm_region(C);
- float co[2];
-
- UI_view2d_region_to_view(&region->v2d, event->mval[0], event->mval[1], &co[0], &co[1]);
- RNA_float_set_array(op->ptr, "location", co);
-
- return uv_select_loop_exec(C, op);
-}
-
-static void UV_OT_select_loop(wmOperatorType *ot)
-{
- /* identifiers */
- ot->name = "Loop Select";
- ot->description = "Select a loop of connected UV vertices";
- ot->idname = "UV_OT_select_loop";
- ot->flag = OPTYPE_UNDO;
-
- /* api callbacks */
- ot->exec = uv_select_loop_exec;
- ot->invoke = uv_select_loop_invoke;
- ot->poll = ED_operator_uvedit; /* requires space image */
-
- /* properties */
- RNA_def_boolean(ot->srna,
- "extend",
- 0,
- "Extend",
- "Extend selection rather than clearing the existing selection");
- RNA_def_float_vector(
- ot->srna,
- "location",
- 2,
- NULL,
- -FLT_MAX,
- FLT_MAX,
- "Location",
- "Mouse location in normalized coordinates, 0.0 to 1.0 is within the image bounds",
- -100.0f,
- 100.0f);
-}
-
-/** \} */
-
-/* -------------------------------------------------------------------- */
-/** \name Select Linked Operator
- * \{ */
-
-static int uv_select_linked_internal(bContext *C, wmOperator *op, const wmEvent *event, bool pick)
-{
- SpaceImage *sima = CTX_wm_space_image(C);
- Scene *scene = CTX_data_scene(C);
- const ToolSettings *ts = scene->toolsettings;
- ViewLayer *view_layer = CTX_data_view_layer(C);
- Image *ima = CTX_data_edit_image(C);
- float limit[2];
- bool extend = true;
- bool deselect = false;
- bool select_faces = (ts->uv_flag & UV_SYNC_SELECTION) && (ts->selectmode & SCE_SELECT_FACE);
-
- UvNearestHit hit = UV_NEAREST_HIT_INIT;
-
- if ((ts->uv_flag & UV_SYNC_SELECTION) && !(ts->selectmode & SCE_SELECT_FACE)) {
- BKE_report(op->reports,
- RPT_ERROR,
- "Select linked only works in face select mode when sync selection is enabled");
- return OPERATOR_CANCELLED;
- }
-
- if (pick) {
- extend = RNA_boolean_get(op->ptr, "extend");
- deselect = RNA_boolean_get(op->ptr, "deselect");
- }
- uvedit_pixel_to_float(sima, limit, 0.05f);
-
- uint objects_len = 0;
- Object **objects = BKE_view_layer_array_from_objects_in_edit_mode_unique_data_with_uvs(
- view_layer, ((View3D *)NULL), &objects_len);
-
- if (pick) {
- float co[2];
-
- if (event) {
- /* invoke */
- ARegion *region = CTX_wm_region(C);
-
- UI_view2d_region_to_view(&region->v2d, event->mval[0], event->mval[1], &co[0], &co[1]);
- RNA_float_set_array(op->ptr, "location", co);
- }
- else {
- /* exec */
- RNA_float_get_array(op->ptr, "location", co);
- }
-
- if (!uv_find_nearest_edge_multi(scene, ima, objects, objects_len, co, &hit)) {
- MEM_freeN(objects);
- return OPERATOR_CANCELLED;
- }
- }
-
- if (!extend) {
- uv_select_all_perform_multi(scene, ima, objects, objects_len, SEL_DESELECT);
- }
-
- uv_select_linked_multi(scene,
- ima,
- objects,
- objects_len,
- limit,
- pick ? &hit : NULL,
- extend,
- deselect,
- false,
- select_faces);
-
- /* weak!, but works */
- Object **objects_free = objects;
- if (pick) {
- objects = &hit.ob;
- objects_len = 1;
- }
-
- for (uint ob_index = 0; ob_index < objects_len; ob_index++) {
- Object *obedit = objects[ob_index];
- DEG_id_tag_update(obedit->data, ID_RECALC_COPY_ON_WRITE | ID_RECALC_SELECT);
- WM_event_add_notifier(C, NC_GEOM | ND_SELECT, obedit->data);
- }
-
- MEM_SAFE_FREE(objects_free);
-
- return OPERATOR_FINISHED;
-}
-
-static int uv_select_linked_exec(bContext *C, wmOperator *op)
-{
- return uv_select_linked_internal(C, op, NULL, false);
-}
-
-static void UV_OT_select_linked(wmOperatorType *ot)
-{
- /* identifiers */
- ot->name = "Select Linked";
- ot->description = "Select all UV vertices linked to the active UV map";
- ot->idname = "UV_OT_select_linked";
-
- /* api callbacks */
- ot->exec = uv_select_linked_exec;
- ot->poll = ED_operator_uvedit; /* requires space image */
-
- /* flags */
- ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
-}
-
-/** \} */
-
-/* -------------------------------------------------------------------- */
-/** \name Select Linked (Cursor Pick) Operator
- * \{ */
-
-static int uv_select_linked_pick_invoke(bContext *C, wmOperator *op, const wmEvent *event)
-{
- return uv_select_linked_internal(C, op, event, true);
-}
-
-static int uv_select_linked_pick_exec(bContext *C, wmOperator *op)
-{
- return uv_select_linked_internal(C, op, NULL, true);
-}
-
-static void UV_OT_select_linked_pick(wmOperatorType *ot)
-{
- /* identifiers */
- ot->name = "Select Linked Pick";
- ot->description = "Select all UV vertices linked under the mouse";
- ot->idname = "UV_OT_select_linked_pick";
-
- /* flags */
- ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
-
- /* api callbacks */
- ot->invoke = uv_select_linked_pick_invoke;
- ot->exec = uv_select_linked_pick_exec;
- ot->poll = ED_operator_uvedit; /* requires space image */
-
- /* properties */
- RNA_def_boolean(ot->srna,
- "extend",
- 0,
- "Extend",
- "Extend selection rather than clearing the existing selection");
- RNA_def_boolean(ot->srna,
- "deselect",
- 0,
- "Deselect",
- "Deselect linked UV vertices rather than selecting them");
- RNA_def_float_vector(
- ot->srna,
- "location",
- 2,
- NULL,
- -FLT_MAX,
- FLT_MAX,
- "Location",
- "Mouse location in normalized coordinates, 0.0 to 1.0 is within the image bounds",
- -100.0f,
- 100.0f);
-}
-
-/** \} */
-
-/* -------------------------------------------------------------------- */
-/** \name Select Split Operator
- * \{ */
-
-/**
- * \note This is based on similar use case to #MESH_OT_split(), which has a similar effect
- * but in this case they are not joined to begin with (only having the behavior of being joined)
- * so its best to call this #uv_select_split() instead of just split(), but assigned to the same
- * key as #MESH_OT_split - Campbell.
- */
-static int uv_select_split_exec(bContext *C, wmOperator *op)
-{
- Scene *scene = CTX_data_scene(C);
- ViewLayer *view_layer = CTX_data_view_layer(C);
- const ToolSettings *ts = scene->toolsettings;
- Image *ima = CTX_data_edit_image(C);
-
- BMFace *efa;
- BMLoop *l;
- BMIter iter, liter;
- MLoopUV *luv;
-
- if (ts->uv_flag & UV_SYNC_SELECTION) {
- BKE_report(op->reports, RPT_ERROR, "Cannot split selection when sync selection is enabled");
- return OPERATOR_CANCELLED;
- }
-
- bool changed_multi = false;
-
- uint objects_len = 0;
- Object **objects = BKE_view_layer_array_from_objects_in_edit_mode_unique_data_with_uvs(
- view_layer, ((View3D *)NULL), &objects_len);
-
- for (uint ob_index = 0; ob_index < objects_len; ob_index++) {
- Object *obedit = objects[ob_index];
- BMesh *bm = BKE_editmesh_from_object(obedit)->bm;
-
- bool changed = false;
-
- const int cd_loop_uv_offset = CustomData_get_offset(&bm->ldata, CD_MLOOPUV);
-
- BM_ITER_MESH (efa, &iter, bm, BM_FACES_OF_MESH) {
- bool is_sel = false;
- bool is_unsel = false;
-
- if (!uvedit_face_visible_test(scene, obedit, ima, efa)) {
- continue;
- }
-
- /* are we all selected? */
- BM_ITER_ELEM (l, &liter, efa, BM_LOOPS_OF_FACE) {
- luv = BM_ELEM_CD_GET_VOID_P(l, cd_loop_uv_offset);
-
- if (luv->flag & MLOOPUV_VERTSEL) {
- is_sel = true;
- }
- else {
- is_unsel = true;
- }
-
- /* we have mixed selection, bail out */
- if (is_sel && is_unsel) {
- break;
- }
- }
-
- if (is_sel && is_unsel) {
- BM_ITER_ELEM (l, &liter, efa, BM_LOOPS_OF_FACE) {
- luv = BM_ELEM_CD_GET_VOID_P(l, cd_loop_uv_offset);
- luv->flag &= ~MLOOPUV_VERTSEL;
- }
-
- changed = true;
- }
- }
-
- if (changed) {
- changed_multi = true;
- WM_event_add_notifier(C, NC_SPACE | ND_SPACE_IMAGE, NULL);
- }
- }
- MEM_freeN(objects);
-
- return changed_multi ? OPERATOR_FINISHED : OPERATOR_CANCELLED;
-}
-
-static void UV_OT_select_split(wmOperatorType *ot)
-{
- /* identifiers */
- ot->name = "Select Split";
- ot->description = "Select only entirely selected faces";
- ot->idname = "UV_OT_select_split";
- ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
-
- /* api callbacks */
- ot->exec = uv_select_split_exec;
- ot->poll = ED_operator_uvedit; /* requires space image */
-}
-
-static void uv_select_sync_flush(const ToolSettings *ts, BMEditMesh *em, const short select)
-{
- /* bmesh API handles flushing but not on de-select */
- if (ts->uv_flag & UV_SYNC_SELECTION) {
- if (ts->selectmode != SCE_SELECT_FACE) {
- if (select == false) {
- EDBM_deselect_flush(em);
- }
- else {
- EDBM_select_flush(em);
- }
- }
-
- if (select == false) {
- BM_select_history_validate(em->bm);
- }
- }
-}
-
-static void uv_select_tag_update_for_object(Depsgraph *depsgraph,
- const ToolSettings *ts,
- Object *obedit)
-{
- if (ts->uv_flag & UV_SYNC_SELECTION) {
- DEG_id_tag_update(obedit->data, ID_RECALC_SELECT);
- WM_main_add_notifier(NC_GEOM | ND_SELECT, obedit->data);
- }
- else {
- Object *obedit_eval = DEG_get_evaluated_object(depsgraph, obedit);
- BKE_mesh_batch_cache_dirty_tag(obedit_eval->data, BKE_MESH_BATCH_DIRTY_UVEDIT_SELECT);
- /* Only for region redraw. */
- WM_main_add_notifier(NC_GEOM | ND_SELECT, obedit->data);
- }
-}
-
-/** \} */
-
-/* -------------------------------------------------------------------- */
-/** \name Select/Tag Flushing Utils
- *
- * Utility functions to flush the uv-selection from tags.
- * \{ */
-
-/**
- * helper function for #uv_select_flush_from_tag_loop and uv_select_flush_from_tag_face
- */
-static void uv_select_flush_from_tag_sticky_loc_internal(Scene *scene,
- BMEditMesh *em,
- UvVertMap *vmap,
- const unsigned int efa_index,
- BMLoop *l,
- const bool select,
- const int cd_loop_uv_offset)
-{
- UvMapVert *start_vlist = NULL, *vlist_iter;
- BMFace *efa_vlist;
-
- uvedit_uv_select_set(em, scene, l, select, false, cd_loop_uv_offset);
-
- vlist_iter = BM_uv_vert_map_at_index(vmap, BM_elem_index_get(l->v));
-
- while (vlist_iter) {
- if (vlist_iter->separate) {
- start_vlist = vlist_iter;
- }
-
- if (efa_index == vlist_iter->poly_index) {
- break;
- }
-
- vlist_iter = vlist_iter->next;
- }
-
- vlist_iter = start_vlist;
- while (vlist_iter) {
-
- if (vlist_iter != start_vlist && vlist_iter->separate) {
- break;
- }
-
- if (efa_index != vlist_iter->poly_index) {
- BMLoop *l_other;
- efa_vlist = BM_face_at_index(em->bm, vlist_iter->poly_index);
- /* tf_vlist = BM_ELEM_CD_GET_VOID_P(efa_vlist, cd_poly_tex_offset); */ /* UNUSED */
-
- l_other = BM_iter_at_index(
- em->bm, BM_LOOPS_OF_FACE, efa_vlist, vlist_iter->loop_of_poly_index);
-
- uvedit_uv_select_set(em, scene, l_other, select, false, cd_loop_uv_offset);
- }
- vlist_iter = vlist_iter->next;
- }
-}
-
-/**
- * Flush the selection from face tags based on sticky and selection modes.
- *
- * needed because settings the selection a face is done in a number of places but it also
- * needs to respect the sticky modes for the UV verts, so dealing with the sticky modes
- * is best done in a separate function.
- *
- * \note This function is very similar to #uv_select_flush_from_tag_loop,
- * be sure to update both upon changing.
- */
-static void uv_select_flush_from_tag_face(SpaceImage *sima,
- Scene *scene,
- Object *obedit,
- const bool select)
-{
- /* Selecting UV Faces with some modes requires us to change
- * the selection in other faces (depending on the sticky mode).
- *
- * This only needs to be done when the Mesh is not used for
- * selection (so for sticky modes, vertex or location based). */
-
- const ToolSettings *ts = scene->toolsettings;
- BMEditMesh *em = BKE_editmesh_from_object(obedit);
- BMFace *efa;
- BMLoop *l;
- BMIter iter, liter;
- const int cd_loop_uv_offset = CustomData_get_offset(&em->bm->ldata, CD_MLOOPUV);
-
- if ((ts->uv_flag & UV_SYNC_SELECTION) == 0 && sima->sticky == SI_STICKY_VERTEX) {
- /* Tag all verts as untouched, then touch the ones that have a face center
- * in the loop and select all MLoopUV's that use a touched vert. */
- BM_mesh_elem_hflag_disable_all(em->bm, BM_VERT, BM_ELEM_TAG, false);
-
- BM_ITER_MESH (efa, &iter, em->bm, BM_FACES_OF_MESH) {
- if (BM_elem_flag_test(efa, BM_ELEM_TAG)) {
- BM_ITER_ELEM (l, &liter, efa, BM_LOOPS_OF_FACE) {
- BM_elem_flag_enable(l->v, BM_ELEM_TAG);
- }
- }
- }
-
- /* now select tagged verts */
- BM_ITER_MESH (efa, &iter, em->bm, BM_FACES_OF_MESH) {
- /* tf = BM_ELEM_CD_GET_VOID_P(efa, cd_poly_tex_offset); */ /* UNUSED */
-
- BM_ITER_ELEM (l, &liter, efa, BM_LOOPS_OF_FACE) {
- if (BM_elem_flag_test(l->v, BM_ELEM_TAG)) {
- uvedit_uv_select_set(em, scene, l, select, false, cd_loop_uv_offset);
- }
- }
- }
- }
- else if ((ts->uv_flag & UV_SYNC_SELECTION) == 0 && sima->sticky == SI_STICKY_LOC) {
- struct UvVertMap *vmap;
- float limit[2];
- unsigned int efa_index;
-
- uvedit_pixel_to_float(sima, limit, 0.05);
-
- BM_mesh_elem_table_ensure(em->bm, BM_FACE);
- vmap = BM_uv_vert_map_create(em->bm, limit, false, false);
- if (vmap == NULL) {
- return;
- }
-
- BM_ITER_MESH_INDEX (efa, &iter, em->bm, BM_FACES_OF_MESH, efa_index) {
- if (BM_elem_flag_test(efa, BM_ELEM_TAG)) {
- /* tf = BM_ELEM_CD_GET_VOID_P(efa, cd_poly_tex_offset); */ /* UNUSED */
-
- BM_ITER_ELEM (l, &liter, efa, BM_LOOPS_OF_FACE) {
- uv_select_flush_from_tag_sticky_loc_internal(
- scene, em, vmap, efa_index, l, select, cd_loop_uv_offset);
- }
- }
- }
- BM_uv_vert_map_free(vmap);
- }
- else { /* SI_STICKY_DISABLE or ts->uv_flag & UV_SYNC_SELECTION */
- BM_ITER_MESH (efa, &iter, em->bm, BM_FACES_OF_MESH) {
- if (BM_elem_flag_test(efa, BM_ELEM_TAG)) {
- uvedit_face_select_set(scene, em, efa, select, false, cd_loop_uv_offset);
- }
- }
- }
-}
-
-/**
- * Flush the selection from loop tags based on sticky and selection modes.
- *
- * needed because settings the selection a face is done in a number of places but it also needs
- * to respect the sticky modes for the UV verts, so dealing with the sticky modes is best done
- * in a separate function.
- *
- * \note This function is very similar to #uv_select_flush_from_tag_loop,
- * be sure to update both upon changing.
- */
-static void uv_select_flush_from_tag_loop(SpaceImage *sima,
- Scene *scene,
- Object *obedit,
- const bool select)
-{
- /* Selecting UV Loops with some modes requires us to change
- * the selection in other faces (depending on the sticky mode).
- *
- * This only needs to be done when the Mesh is not used for
- * selection (so for sticky modes, vertex or location based). */
-
- const ToolSettings *ts = scene->toolsettings;
- BMEditMesh *em = BKE_editmesh_from_object(obedit);
- BMFace *efa;
- BMLoop *l;
- BMIter iter, liter;
-
- const int cd_loop_uv_offset = CustomData_get_offset(&em->bm->ldata, CD_MLOOPUV);
-
- if ((ts->uv_flag & UV_SYNC_SELECTION) == 0 && sima->sticky == SI_STICKY_VERTEX) {
- /* Tag all verts as untouched, then touch the ones that have a face center
- * in the loop and select all MLoopUV's that use a touched vert. */
- BM_mesh_elem_hflag_disable_all(em->bm, BM_VERT, BM_ELEM_TAG, false);
-
- BM_ITER_MESH (efa, &iter, em->bm, BM_FACES_OF_MESH) {
- BM_ITER_ELEM (l, &liter, efa, BM_LOOPS_OF_FACE) {
- if (BM_elem_flag_test(l, BM_ELEM_TAG)) {
- BM_elem_flag_enable(l->v, BM_ELEM_TAG);
- }
- }
- }
-
- /* now select tagged verts */
- BM_ITER_MESH (efa, &iter, em->bm, BM_FACES_OF_MESH) {
- /* tf = BM_ELEM_CD_GET_VOID_P(efa, cd_poly_tex_offset); */ /* UNUSED */
-
- BM_ITER_ELEM (l, &liter, efa, BM_LOOPS_OF_FACE) {
- if (BM_elem_flag_test(l->v, BM_ELEM_TAG)) {
- uvedit_uv_select_set(em, scene, l, select, false, cd_loop_uv_offset);
- }
- }
- }
- }
- else if ((ts->uv_flag & UV_SYNC_SELECTION) == 0 && sima->sticky == SI_STICKY_LOC) {
- struct UvVertMap *vmap;
- float limit[2];
- unsigned int efa_index;
-
- uvedit_pixel_to_float(sima, limit, 0.05);
-
- BM_mesh_elem_table_ensure(em->bm, BM_FACE);
- vmap = BM_uv_vert_map_create(em->bm, limit, false, false);
- if (vmap == NULL) {
- return;
- }
-
- BM_ITER_MESH_INDEX (efa, &iter, em->bm, BM_FACES_OF_MESH, efa_index) {
- /* tf = BM_ELEM_CD_GET_VOID_P(efa, cd_poly_tex_offset); */ /* UNUSED */
-
- BM_ITER_ELEM (l, &liter, efa, BM_LOOPS_OF_FACE) {
- if (BM_elem_flag_test(l, BM_ELEM_TAG)) {
- uv_select_flush_from_tag_sticky_loc_internal(
- scene, em, vmap, efa_index, l, select, cd_loop_uv_offset);
- }
- }
- }
- BM_uv_vert_map_free(vmap);
- }
- else { /* SI_STICKY_DISABLE or ts->uv_flag & UV_SYNC_SELECTION */
- BM_ITER_MESH (efa, &iter, em->bm, BM_FACES_OF_MESH) {
- BM_ITER_ELEM (l, &liter, efa, BM_LOOPS_OF_FACE) {
- if (BM_elem_flag_test(l, BM_ELEM_TAG)) {
- uvedit_uv_select_set(em, scene, l, select, false, cd_loop_uv_offset);
- }
- }
- }
- }
-}
-
-/** \} */
-
-#define UV_SELECT_ISLAND_LIMIT \
- float limit[2]; \
- uvedit_pixel_to_float(sima, limit, 0.05f)
-
-/* -------------------------------------------------------------------- */
-/** \name Box Select Operator
- * \{ */
-
-static int uv_box_select_exec(bContext *C, wmOperator *op)
-{
- Depsgraph *depsgraph = CTX_data_ensure_evaluated_depsgraph(C);
- SpaceImage *sima = CTX_wm_space_image(C);
- Scene *scene = CTX_data_scene(C);
- const ToolSettings *ts = scene->toolsettings;
- ViewLayer *view_layer = CTX_data_view_layer(C);
- Image *ima = CTX_data_edit_image(C);
- ARegion *region = CTX_wm_region(C);
- BMFace *efa;
- BMLoop *l;
- BMIter iter, liter;
- MLoopUV *luv;
- rctf rectf;
- bool pinned;
- const bool use_face_center = ((ts->uv_flag & UV_SYNC_SELECTION) ?
- (ts->selectmode == SCE_SELECT_FACE) :
- (ts->uv_selectmode == UV_SELECT_FACE));
-
- /* get rectangle from operator */
- WM_operator_properties_border_to_rctf(op, &rectf);
- UI_view2d_region_to_view_rctf(&region->v2d, &rectf, &rectf);
-
- const eSelectOp sel_op = RNA_enum_get(op->ptr, "mode");
- const bool select = (sel_op != SEL_OP_SUB);
- const bool use_pre_deselect = SEL_OP_USE_PRE_DESELECT(sel_op);
-
- pinned = RNA_boolean_get(op->ptr, "pinned");
-
- UV_SELECT_ISLAND_LIMIT;
-
- bool changed_multi = false;
-
- uint objects_len = 0;
- Object **objects = BKE_view_layer_array_from_objects_in_edit_mode_unique_data_with_uvs(
- view_layer, ((View3D *)NULL), &objects_len);
-
- if (use_pre_deselect) {
- uv_select_all_perform_multi(scene, ima, objects, objects_len, SEL_DESELECT);
- }
-
- /* don't indent to avoid diff noise! */
- for (uint ob_index = 0; ob_index < objects_len; ob_index++) {
- Object *obedit = objects[ob_index];
- BMEditMesh *em = BKE_editmesh_from_object(obedit);
-
- bool changed = false;
-
- const int cd_loop_uv_offset = CustomData_get_offset(&em->bm->ldata, CD_MLOOPUV);
-
- /* do actual selection */
- if (use_face_center && !pinned) {
- /* handle face selection mode */
- float cent[2];
-
- BM_ITER_MESH (efa, &iter, em->bm, BM_FACES_OF_MESH) {
- /* assume not touched */
- BM_elem_flag_disable(efa, BM_ELEM_TAG);
-
- if (uvedit_face_visible_test(scene, obedit, ima, efa)) {
- uv_poly_center(efa, cent, cd_loop_uv_offset);
- if (BLI_rctf_isect_pt_v(&rectf, cent)) {
- BM_elem_flag_enable(efa, BM_ELEM_TAG);
- changed = true;
- }
- }
- }
-
- /* (de)selects all tagged faces and deals with sticky modes */
- if (changed) {
- uv_select_flush_from_tag_face(sima, scene, obedit, select);
- }
- }
- else {
- /* other selection modes */
- changed = true;
- BM_mesh_elem_hflag_disable_all(em->bm, BM_VERT, BM_ELEM_TAG, false);
-
- BM_ITER_MESH (efa, &iter, em->bm, BM_FACES_OF_MESH) {
- if (!uvedit_face_visible_test(scene, obedit, ima, efa)) {
- continue;
- }
- bool has_selected = false;
- BM_ITER_ELEM (l, &liter, efa, BM_LOOPS_OF_FACE) {
- luv = BM_ELEM_CD_GET_VOID_P(l, cd_loop_uv_offset);
- if ((select) != (uvedit_uv_select_test(scene, l, cd_loop_uv_offset))) {
- if (!pinned || (ts->uv_flag & UV_SYNC_SELECTION)) {
- /* UV_SYNC_SELECTION - can't do pinned selection */
- if (BLI_rctf_isect_pt_v(&rectf, luv->uv)) {
- uvedit_uv_select_set(em, scene, l, select, false, cd_loop_uv_offset);
- BM_elem_flag_enable(l->v, BM_ELEM_TAG);
- has_selected = true;
- }
- }
- else if (pinned) {
- if ((luv->flag & MLOOPUV_PINNED) && BLI_rctf_isect_pt_v(&rectf, luv->uv)) {
- uvedit_uv_select_set(em, scene, l, select, false, cd_loop_uv_offset);
- BM_elem_flag_enable(l->v, BM_ELEM_TAG);
- }
- }
- }
- }
- if (has_selected && ts->uv_selectmode == UV_SELECT_ISLAND) {
- UvNearestHit hit = {
- .ob = obedit,
- .efa = efa,
- };
- uv_select_linked_multi(
- scene, ima, objects, objects_len, limit, &hit, true, !select, false, false);
- }
- }
-
- if (sima->sticky == SI_STICKY_VERTEX) {
- uvedit_vertex_select_tagged(em, scene, select, cd_loop_uv_offset);
- }
- }
-
- if (changed || use_pre_deselect) {
- changed_multi = true;
-
- uv_select_sync_flush(ts, em, select);
- uv_select_tag_update_for_object(depsgraph, ts, obedit);
- }
- }
-
- MEM_freeN(objects);
-
- return changed_multi ? OPERATOR_FINISHED : OPERATOR_CANCELLED;
-}
-
-static void UV_OT_select_box(wmOperatorType *ot)
-{
- /* identifiers */
- ot->name = "Box Select";
- ot->description = "Select UV vertices using box selection";
- ot->idname = "UV_OT_select_box";
-
- /* api callbacks */
- ot->invoke = WM_gesture_box_invoke;
- ot->exec = uv_box_select_exec;
- ot->modal = WM_gesture_box_modal;
- ot->poll = ED_operator_uvedit_space_image; /* requires space image */
- ot->cancel = WM_gesture_box_cancel;
-
- /* flags */
- ot->flag = OPTYPE_UNDO;
-
- /* properties */
- RNA_def_boolean(ot->srna, "pinned", 0, "Pinned", "Border select pinned UVs only");
-
- WM_operator_properties_gesture_box(ot);
- WM_operator_properties_select_operation_simple(ot);
-}
-
-/** \} */
-
-/* -------------------------------------------------------------------- */
-/** \name Circle Select Operator
- * \{ */
-
-static int uv_inside_circle(const float uv[2], const float offset[2], const float ellipse[2])
-{
- /* normalized ellipse: ell[0] = scaleX, ell[1] = scaleY */
- float x, y;
- x = (uv[0] - offset[0]) * ellipse[0];
- y = (uv[1] - offset[1]) * ellipse[1];
- return ((x * x + y * y) < 1.0f);
-}
-
-static int uv_circle_select_exec(bContext *C, wmOperator *op)
-{
- Depsgraph *depsgraph = CTX_data_ensure_evaluated_depsgraph(C);
- SpaceImage *sima = CTX_wm_space_image(C);
- Image *ima = CTX_data_edit_image(C);
- Scene *scene = CTX_data_scene(C);
- ViewLayer *view_layer = CTX_data_view_layer(C);
- const ToolSettings *ts = scene->toolsettings;
- ARegion *region = CTX_wm_region(C);
- BMFace *efa;
- BMLoop *l;
- BMIter iter, liter;
- MLoopUV *luv;
- int x, y, radius, width, height;
- float zoomx, zoomy, offset[2], ellipse[2];
-
- const bool use_face_center = ((ts->uv_flag & UV_SYNC_SELECTION) ?
- (ts->selectmode == SCE_SELECT_FACE) :
- (ts->uv_selectmode == UV_SELECT_FACE));
-
- /* get operator properties */
- x = RNA_int_get(op->ptr, "x");
- y = RNA_int_get(op->ptr, "y");
- radius = RNA_int_get(op->ptr, "radius");
-
- /* compute ellipse size and location, not a circle since we deal
- * with non square image. ellipse is normalized, r = 1.0. */
- ED_space_image_get_size(sima, &width, &height);
- ED_space_image_get_zoom(sima, region, &zoomx, &zoomy);
-
- ellipse[0] = width * zoomx / radius;
- ellipse[1] = height * zoomy / radius;
-
- UI_view2d_region_to_view(&region->v2d, x, y, &offset[0], &offset[1]);
-
- UV_SELECT_ISLAND_LIMIT;
-
- bool changed_multi = false;
-
- uint objects_len = 0;
- Object **objects = BKE_view_layer_array_from_objects_in_edit_mode_unique_data_with_uvs(
- view_layer, ((View3D *)NULL), &objects_len);
-
- const eSelectOp sel_op = ED_select_op_modal(RNA_enum_get(op->ptr, "mode"),
- WM_gesture_is_modal_first(op->customdata));
- const bool select = (sel_op != SEL_OP_SUB);
- const bool use_pre_deselect = SEL_OP_USE_PRE_DESELECT(sel_op);
-
- if (use_pre_deselect) {
- uv_select_all_perform_multi(scene, ima, objects, objects_len, SEL_DESELECT);
- }
-
- for (uint ob_index = 0; ob_index < objects_len; ob_index++) {
- Object *obedit = objects[ob_index];
- BMEditMesh *em = BKE_editmesh_from_object(obedit);
-
- bool changed = false;
-
- const int cd_loop_uv_offset = CustomData_get_offset(&em->bm->ldata, CD_MLOOPUV);
-
- /* do selection */
- if (use_face_center) {
- BM_ITER_MESH (efa, &iter, em->bm, BM_FACES_OF_MESH) {
- BM_elem_flag_disable(efa, BM_ELEM_TAG);
- /* assume not touched */
- if (select != uvedit_face_select_test(scene, efa, cd_loop_uv_offset)) {
- float cent[2];
- uv_poly_center(efa, cent, cd_loop_uv_offset);
- if (uv_inside_circle(cent, offset, ellipse)) {
- BM_elem_flag_enable(efa, BM_ELEM_TAG);
- changed = true;
- }
- }
- }
-
- /* (de)selects all tagged faces and deals with sticky modes */
- if (changed) {
- uv_select_flush_from_tag_face(sima, scene, obedit, select);
- }
- }
- else {
- BM_mesh_elem_hflag_disable_all(em->bm, BM_VERT, BM_ELEM_TAG, false);
-
- BM_ITER_MESH (efa, &iter, em->bm, BM_FACES_OF_MESH) {
- if (!uvedit_face_visible_test(scene, obedit, ima, efa)) {
- continue;
- }
- bool has_selected = false;
- BM_ITER_ELEM (l, &liter, efa, BM_LOOPS_OF_FACE) {
- if ((select) != (uvedit_uv_select_test(scene, l, cd_loop_uv_offset))) {
- luv = BM_ELEM_CD_GET_VOID_P(l, cd_loop_uv_offset);
- if (uv_inside_circle(luv->uv, offset, ellipse)) {
- changed = true;
- uvedit_uv_select_set(em, scene, l, select, false, cd_loop_uv_offset);
- BM_elem_flag_enable(l->v, BM_ELEM_TAG);
- has_selected = true;
- }
- }
- }
- if (has_selected && ts->uv_selectmode == UV_SELECT_ISLAND) {
- UvNearestHit hit = {
- .ob = obedit,
- .efa = efa,
- };
- uv_select_linked_multi(
- scene, ima, objects, objects_len, limit, &hit, true, !select, false, false);
- }
- }
-
- if (sima->sticky == SI_STICKY_VERTEX) {
- uvedit_vertex_select_tagged(em, scene, select, cd_loop_uv_offset);
- }
- }
-
- if (changed || use_pre_deselect) {
- changed_multi = true;
-
- uv_select_sync_flush(ts, em, select);
- uv_select_tag_update_for_object(depsgraph, ts, obedit);
- }
- }
- MEM_freeN(objects);
-
- return changed_multi ? OPERATOR_FINISHED : OPERATOR_CANCELLED;
-}
-
-static void UV_OT_select_circle(wmOperatorType *ot)
-{
- /* identifiers */
- ot->name = "Circle Select";
- ot->description = "Select UV vertices using circle selection";
- ot->idname = "UV_OT_select_circle";
-
- /* api callbacks */
- ot->invoke = WM_gesture_circle_invoke;
- ot->modal = WM_gesture_circle_modal;
- ot->exec = uv_circle_select_exec;
- ot->poll = ED_operator_uvedit_space_image; /* requires space image */
- ot->cancel = WM_gesture_circle_cancel;
-
- /* flags */
- ot->flag = OPTYPE_UNDO;
-
- /* properties */
- WM_operator_properties_gesture_circle(ot);
- WM_operator_properties_select_operation_simple(ot);
-}
-
-/** \} */
-
-/* -------------------------------------------------------------------- */
-/** \name Lasso Select Operator
- * \{ */
-
-static bool do_lasso_select_mesh_uv(bContext *C,
- const int mcords[][2],
- short moves,
- const eSelectOp sel_op)
-{
- Depsgraph *depsgraph = CTX_data_ensure_evaluated_depsgraph(C);
- SpaceImage *sima = CTX_wm_space_image(C);
- Image *ima = CTX_data_edit_image(C);
- ARegion *region = CTX_wm_region(C);
- Scene *scene = CTX_data_scene(C);
- const ToolSettings *ts = scene->toolsettings;
- ViewLayer *view_layer = CTX_data_view_layer(C);
- const bool use_face_center = ((ts->uv_flag & UV_SYNC_SELECTION) ?
- (ts->selectmode == SCE_SELECT_FACE) :
- (ts->uv_selectmode == UV_SELECT_FACE));
- const bool select = (sel_op != SEL_OP_SUB);
- const bool use_pre_deselect = SEL_OP_USE_PRE_DESELECT(sel_op);
-
- BMIter iter, liter;
-
- BMFace *efa;
- BMLoop *l;
- int screen_uv[2];
- bool changed_multi = false;
- rcti rect;
-
- UV_SELECT_ISLAND_LIMIT;
-
- BLI_lasso_boundbox(&rect, mcords, moves);
-
- uint objects_len = 0;
- Object **objects = BKE_view_layer_array_from_objects_in_edit_mode_unique_data_with_uvs(
- view_layer, ((View3D *)NULL), &objects_len);
-
- if (use_pre_deselect) {
- uv_select_all_perform_multi(scene, ima, objects, objects_len, SEL_DESELECT);
- }
-
- /* don't indent to avoid diff noise! */
- for (uint ob_index = 0; ob_index < objects_len; ob_index++) {
- Object *obedit = objects[ob_index];
-
- bool changed = false;
-
- BMEditMesh *em = BKE_editmesh_from_object(obedit);
-
- const int cd_loop_uv_offset = CustomData_get_offset(&em->bm->ldata, CD_MLOOPUV);
-
- if (use_face_center) { /* Face Center Sel */
- BM_ITER_MESH (efa, &iter, em->bm, BM_FACES_OF_MESH) {
- BM_elem_flag_disable(efa, BM_ELEM_TAG);
- /* assume not touched */
- if (select != uvedit_face_select_test(scene, efa, cd_loop_uv_offset)) {
- float cent[2];
- uv_poly_center(efa, cent, cd_loop_uv_offset);
-
- if (UI_view2d_view_to_region_clip(
- &region->v2d, cent[0], cent[1], &screen_uv[0], &screen_uv[1]) &&
- BLI_rcti_isect_pt_v(&rect, screen_uv) &&
- BLI_lasso_is_point_inside(
- mcords, moves, screen_uv[0], screen_uv[1], V2D_IS_CLIPPED)) {
- BM_elem_flag_enable(efa, BM_ELEM_TAG);
- changed = true;
- }
- }
- }
-
- /* (de)selects all tagged faces and deals with sticky modes */
- if (changed) {
- uv_select_flush_from_tag_face(sima, scene, obedit, select);
- }
- }
- else { /* Vert Sel */
- BM_mesh_elem_hflag_disable_all(em->bm, BM_VERT, BM_ELEM_TAG, false);
-
- BM_ITER_MESH (efa, &iter, em->bm, BM_FACES_OF_MESH) {
- if (!uvedit_face_visible_test(scene, obedit, ima, efa)) {
- continue;
- }
- bool has_selected = false;
- BM_ITER_ELEM (l, &liter, efa, BM_LOOPS_OF_FACE) {
- if ((select) != (uvedit_uv_select_test(scene, l, cd_loop_uv_offset))) {
- MLoopUV *luv = BM_ELEM_CD_GET_VOID_P(l, cd_loop_uv_offset);
- if (UI_view2d_view_to_region_clip(
- &region->v2d, luv->uv[0], luv->uv[1], &screen_uv[0], &screen_uv[1]) &&
- BLI_rcti_isect_pt_v(&rect, screen_uv) &&
- BLI_lasso_is_point_inside(
- mcords, moves, screen_uv[0], screen_uv[1], V2D_IS_CLIPPED)) {
- uvedit_uv_select_set(em, scene, l, select, false, cd_loop_uv_offset);
- changed = true;
- BM_elem_flag_enable(l->v, BM_ELEM_TAG);
- has_selected = true;
- }
- }
- }
- if (has_selected && ts->uv_selectmode == UV_SELECT_ISLAND) {
- UvNearestHit hit = {
- .ob = obedit,
- .efa = efa,
- };
- uv_select_linked_multi(
- scene, ima, objects, objects_len, limit, &hit, true, !select, false, false);
- }
- }
-
- if (sima->sticky == SI_STICKY_VERTEX) {
- uvedit_vertex_select_tagged(em, scene, select, cd_loop_uv_offset);
- }
- }
-
- if (changed || use_pre_deselect) {
- changed_multi = true;
-
- uv_select_sync_flush(ts, em, select);
- uv_select_tag_update_for_object(depsgraph, ts, obedit);
- }
- }
- MEM_freeN(objects);
-
- return changed_multi;
-}
-
-static int uv_lasso_select_exec(bContext *C, wmOperator *op)
-{
- int mcords_tot;
- const int(*mcords)[2] = WM_gesture_lasso_path_to_array(C, op, &mcords_tot);
-
- if (mcords) {
- const eSelectOp sel_op = RNA_enum_get(op->ptr, "mode");
- bool changed = do_lasso_select_mesh_uv(C, mcords, mcords_tot, sel_op);
- MEM_freeN((void *)mcords);
-
- return changed ? OPERATOR_FINISHED : OPERATOR_CANCELLED;
- }
-
- return OPERATOR_PASS_THROUGH;
-}
-
-static void UV_OT_select_lasso(wmOperatorType *ot)
-{
- ot->name = "Lasso Select UV";
- ot->description = "Select UVs using lasso selection";
- ot->idname = "UV_OT_select_lasso";
-
- ot->invoke = WM_gesture_lasso_invoke;
- ot->modal = WM_gesture_lasso_modal;
- ot->exec = uv_lasso_select_exec;
- ot->poll = ED_operator_uvedit_space_image;
- ot->cancel = WM_gesture_lasso_cancel;
-
- /* flags */
- ot->flag = OPTYPE_UNDO;
-
- /* properties */
- WM_operator_properties_gesture_lasso(ot);
- WM_operator_properties_select_operation_simple(ot);
-}
-
-/** \} */
-
-/* -------------------------------------------------------------------- */
/** \name Snap Cursor Operator
* \{ */
@@ -3992,10 +1075,12 @@ static void uv_snap_cursor_to_pixels(SpaceImage *sima)
uv_snap_to_pixel(sima->cursor, width, height);
}
-static bool uv_snap_cursor_to_selection(
- Scene *scene, Image *ima, Object **objects_edit, uint objects_len, SpaceImage *sima)
+static bool uv_snap_cursor_to_selection(Scene *scene,
+ Object **objects_edit,
+ uint objects_len,
+ SpaceImage *sima)
{
- return ED_uvedit_center_multi(scene, ima, objects_edit, objects_len, sima->cursor, sima->around);
+ return ED_uvedit_center_multi(scene, objects_edit, objects_len, sima->cursor, sima->around);
}
static int uv_snap_cursor_exec(bContext *C, wmOperator *op)
@@ -4011,13 +1096,12 @@ static int uv_snap_cursor_exec(bContext *C, wmOperator *op)
break;
case 1: {
Scene *scene = CTX_data_scene(C);
- Image *ima = CTX_data_edit_image(C);
ViewLayer *view_layer = CTX_data_view_layer(C);
uint objects_len = 0;
Object **objects = BKE_view_layer_array_from_objects_in_edit_mode_unique_data_with_uvs(
view_layer, ((View3D *)NULL), &objects_len);
- changed = uv_snap_cursor_to_selection(scene, ima, objects, objects_len, sima);
+ changed = uv_snap_cursor_to_selection(scene, objects, objects_len, sima);
MEM_freeN(objects);
break;
}
@@ -4061,7 +1145,7 @@ static void UV_OT_snap_cursor(wmOperatorType *ot)
/** \name Snap Selection Operator
* \{ */
-static bool uv_snap_uvs_to_cursor(Scene *scene, Image *ima, Object *obedit, const float cursor[2])
+static bool uv_snap_uvs_to_cursor(Scene *scene, Object *obedit, const float cursor[2])
{
BMEditMesh *em = BKE_editmesh_from_object(obedit);
BMFace *efa;
@@ -4073,7 +1157,7 @@ static bool uv_snap_uvs_to_cursor(Scene *scene, Image *ima, Object *obedit, cons
const int cd_loop_uv_offset = CustomData_get_offset(&em->bm->ldata, CD_MLOOPUV);
BM_ITER_MESH (efa, &iter, em->bm, BM_FACES_OF_MESH) {
- if (!uvedit_face_visible_test(scene, obedit, ima, efa)) {
+ if (!uvedit_face_visible_test(scene, efa)) {
continue;
}
@@ -4089,7 +1173,7 @@ static bool uv_snap_uvs_to_cursor(Scene *scene, Image *ima, Object *obedit, cons
return changed;
}
-static bool uv_snap_uvs_offset(Scene *scene, Image *ima, Object *obedit, const float offset[2])
+static bool uv_snap_uvs_offset(Scene *scene, Object *obedit, const float offset[2])
{
BMEditMesh *em = BKE_editmesh_from_object(obedit);
BMFace *efa;
@@ -4101,7 +1185,7 @@ static bool uv_snap_uvs_offset(Scene *scene, Image *ima, Object *obedit, const f
const int cd_loop_uv_offset = CustomData_get_offset(&em->bm->ldata, CD_MLOOPUV);
BM_ITER_MESH (efa, &iter, em->bm, BM_FACES_OF_MESH) {
- if (!uvedit_face_visible_test(scene, obedit, ima, efa)) {
+ if (!uvedit_face_visible_test(scene, efa)) {
continue;
}
@@ -4117,7 +1201,7 @@ static bool uv_snap_uvs_offset(Scene *scene, Image *ima, Object *obedit, const f
return changed;
}
-static bool uv_snap_uvs_to_adjacent_unselected(Scene *scene, Image *ima, Object *obedit)
+static bool uv_snap_uvs_to_adjacent_unselected(Scene *scene, Object *obedit)
{
BMEditMesh *em = BKE_editmesh_from_object(obedit);
BMesh *bm = em->bm;
@@ -4131,7 +1215,7 @@ static bool uv_snap_uvs_to_adjacent_unselected(Scene *scene, Image *ima, Object
/* index every vert that has a selected UV using it, but only once so as to
* get unique indices and to count how much to malloc */
BM_ITER_MESH (f, &iter, bm, BM_FACES_OF_MESH) {
- if (uvedit_face_visible_test(scene, obedit, ima, f)) {
+ if (uvedit_face_visible_test(scene, f)) {
BM_elem_flag_enable(f, BM_ELEM_TAG);
BM_ITER_ELEM (l, &liter, f, BM_LOOPS_OF_FACE) {
BM_elem_flag_set(l, BM_ELEM_TAG, uvedit_uv_select_test(scene, l, cd_loop_uv_offset));
@@ -4175,7 +1259,6 @@ static bool uv_snap_uvs_to_adjacent_unselected(Scene *scene, Image *ima, Object
static bool uv_snap_uvs_to_pixels(SpaceImage *sima, Scene *scene, Object *obedit)
{
BMEditMesh *em = BKE_editmesh_from_object(obedit);
- Image *ima = sima->image;
BMFace *efa;
BMLoop *l;
BMIter iter, liter;
@@ -4191,7 +1274,7 @@ static bool uv_snap_uvs_to_pixels(SpaceImage *sima, Scene *scene, Object *obedit
h = (float)height;
BM_ITER_MESH (efa, &iter, em->bm, BM_FACES_OF_MESH) {
- if (!uvedit_face_visible_test(scene, obedit, ima, efa)) {
+ if (!uvedit_face_visible_test(scene, efa)) {
continue;
}
@@ -4213,7 +1296,6 @@ static int uv_snap_selection_exec(bContext *C, wmOperator *op)
Scene *scene = CTX_data_scene(C);
ViewLayer *view_layer = CTX_data_view_layer(C);
SpaceImage *sima = CTX_wm_space_image(C);
- Image *ima = CTX_data_edit_image(C);
const ToolSettings *ts = scene->toolsettings;
const bool synced_selection = (ts->uv_flag & UV_SYNC_SELECTION) != 0;
const int target = RNA_enum_get(op->ptr, "target");
@@ -4225,7 +1307,7 @@ static int uv_snap_selection_exec(bContext *C, wmOperator *op)
if (target == 2) {
float center[2];
- if (!ED_uvedit_center_multi(scene, ima, objects, objects_len, center, sima->around)) {
+ if (!ED_uvedit_center_multi(scene, objects, objects_len, center, sima->around)) {
MEM_freeN(objects);
return OPERATOR_CANCELLED;
}
@@ -4247,13 +1329,13 @@ static int uv_snap_selection_exec(bContext *C, wmOperator *op)
changed = uv_snap_uvs_to_pixels(sima, scene, obedit);
break;
case 1:
- changed = uv_snap_uvs_to_cursor(scene, ima, obedit, sima->cursor);
+ changed = uv_snap_uvs_to_cursor(scene, obedit, sima->cursor);
break;
case 2:
- changed = uv_snap_uvs_offset(scene, ima, obedit, offset);
+ changed = uv_snap_uvs_offset(scene, obedit, offset);
break;
case 3:
- changed = uv_snap_uvs_to_adjacent_unselected(scene, ima, obedit);
+ changed = uv_snap_uvs_to_adjacent_unselected(scene, obedit);
break;
}
@@ -4304,7 +1386,6 @@ static int uv_pin_exec(bContext *C, wmOperator *op)
{
Scene *scene = CTX_data_scene(C);
ViewLayer *view_layer = CTX_data_view_layer(C);
- Image *ima = CTX_data_edit_image(C);
BMFace *efa;
BMLoop *l;
BMIter iter, liter;
@@ -4329,7 +1410,7 @@ static int uv_pin_exec(bContext *C, wmOperator *op)
}
BM_ITER_MESH (efa, &iter, em->bm, BM_FACES_OF_MESH) {
- if (!uvedit_face_visible_test(scene, obedit, ima, efa)) {
+ if (!uvedit_face_visible_test(scene, efa)) {
continue;
}
@@ -4379,314 +1460,6 @@ static void UV_OT_pin(wmOperatorType *ot)
/** \} */
/* -------------------------------------------------------------------- */
-/** \name Select Pinned UV's Operator
- * \{ */
-
-static int uv_select_pinned_exec(bContext *C, wmOperator *UNUSED(op))
-{
- Depsgraph *depsgraph = CTX_data_ensure_evaluated_depsgraph(C);
- Scene *scene = CTX_data_scene(C);
- const ToolSettings *ts = scene->toolsettings;
- ViewLayer *view_layer = CTX_data_view_layer(C);
- Image *ima = CTX_data_edit_image(C);
- BMFace *efa;
- BMLoop *l;
- BMIter iter, liter;
- MLoopUV *luv;
-
- uint objects_len = 0;
- Object **objects = BKE_view_layer_array_from_objects_in_edit_mode_unique_data_with_uvs(
- view_layer, ((View3D *)NULL), &objects_len);
-
- for (uint ob_index = 0; ob_index < objects_len; ob_index++) {
- Object *obedit = objects[ob_index];
- BMEditMesh *em = BKE_editmesh_from_object(obedit);
-
- const int cd_loop_uv_offset = CustomData_get_offset(&em->bm->ldata, CD_MLOOPUV);
- bool changed = false;
-
- BM_ITER_MESH (efa, &iter, em->bm, BM_FACES_OF_MESH) {
- if (!uvedit_face_visible_test(scene, obedit, ima, efa)) {
- continue;
- }
-
- BM_ITER_ELEM (l, &liter, efa, BM_LOOPS_OF_FACE) {
- luv = BM_ELEM_CD_GET_VOID_P(l, cd_loop_uv_offset);
-
- if (luv->flag & MLOOPUV_PINNED) {
- uvedit_uv_select_enable(em, scene, l, false, cd_loop_uv_offset);
- changed = true;
- }
- }
- }
-
- if (changed) {
- uv_select_tag_update_for_object(depsgraph, ts, obedit);
- }
- }
- MEM_freeN(objects);
-
- return OPERATOR_FINISHED;
-}
-
-static void UV_OT_select_pinned(wmOperatorType *ot)
-{
- /* identifiers */
- ot->name = "Selected Pinned";
- ot->description = "Select all pinned UV vertices";
- ot->idname = "UV_OT_select_pinned";
- ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
-
- /* api callbacks */
- ot->exec = uv_select_pinned_exec;
- ot->poll = ED_operator_uvedit;
-}
-
-/** \} */
-
-/* -------------------------------------------------------------------- */
-/** \name Select Overlap Operator
- * \{ */
-
-BLI_INLINE uint overlap_hash(const void *overlap_v)
-{
- const BVHTreeOverlap *overlap = overlap_v;
-
- /* Designed to treat (A,B) and (B,A) as the same. */
- int x = overlap->indexA;
- int y = overlap->indexB;
- if (x > y) {
- SWAP(int, x, y);
- }
- return BLI_hash_int_2d(x, y);
-}
-
-BLI_INLINE bool overlap_cmp(const void *a_v, const void *b_v)
-{
- const BVHTreeOverlap *a = a_v;
- const BVHTreeOverlap *b = b_v;
- return !((a->indexA == b->indexA && a->indexB == b->indexB) ||
- (a->indexA == b->indexB && a->indexB == b->indexA));
-}
-
-struct UVOverlapData {
- int ob_index;
- int face_index;
- float tri[3][2];
-};
-
-static int uv_select_overlap(bContext *C, const bool extend)
-{
- Depsgraph *depsgraph = CTX_data_ensure_evaluated_depsgraph(C);
- Scene *scene = CTX_data_scene(C);
- ViewLayer *view_layer = CTX_data_view_layer(C);
- Image *ima = CTX_data_edit_image(C);
-
- uint objects_len = 0;
- Object **objects = BKE_view_layer_array_from_objects_in_edit_mode_unique_data_with_uvs(
- view_layer, ((View3D *)NULL), &objects_len);
-
- /* Calculate maximum number of tree nodes and prepare initial selection. */
- uint uv_tri_len = 0;
- for (uint ob_index = 0; ob_index < objects_len; ob_index++) {
- Object *obedit = objects[ob_index];
- BMEditMesh *em = BKE_editmesh_from_object(obedit);
-
- BM_mesh_elem_table_ensure(em->bm, BM_FACE);
- BM_mesh_elem_index_ensure(em->bm, BM_VERT | BM_FACE);
- BM_mesh_elem_hflag_disable_all(em->bm, BM_FACE, BM_ELEM_TAG, false);
- if (!extend) {
- uv_select_all_perform(scene, ima, obedit, SEL_DESELECT);
- }
-
- BMIter iter;
- BMFace *efa;
- BM_ITER_MESH (efa, &iter, em->bm, BM_FACES_OF_MESH) {
- if (!uvedit_face_visible_test_ex(scene->toolsettings, obedit, ima, efa)) {
- continue;
- }
- uv_tri_len += efa->len - 2;
- }
- }
-
- struct UVOverlapData *overlap_data = MEM_mallocN(sizeof(struct UVOverlapData) * uv_tri_len,
- "UvOverlapData");
- BVHTree *uv_tree = BLI_bvhtree_new(uv_tri_len, 0.0f, 4, 6);
-
- /* Use a global data index when inserting into the BVH. */
- int data_index = 0;
-
- int face_len_alloc = 3;
- float(*uv_verts)[2] = MEM_mallocN(sizeof(*uv_verts) * face_len_alloc, "UvOverlapCoords");
- uint(*indices)[3] = MEM_mallocN(sizeof(*indices) * (face_len_alloc - 2), "UvOverlapTris");
-
- for (uint ob_index = 0; ob_index < objects_len; ob_index++) {
- Object *obedit = objects[ob_index];
- BMEditMesh *em = BKE_editmesh_from_object(obedit);
- BMIter iter, liter;
- BMFace *efa;
- BMLoop *l;
-
- const int cd_loop_uv_offset = CustomData_get_offset(&em->bm->ldata, CD_MLOOPUV);
-
- /* Triangulate each UV face and store it inside the BVH. */
- int face_index;
- BM_ITER_MESH_INDEX (efa, &iter, em->bm, BM_FACES_OF_MESH, face_index) {
-
- if (!uvedit_face_visible_test_ex(scene->toolsettings, obedit, ima, efa)) {
- continue;
- }
-
- const uint face_len = efa->len;
- const uint tri_len = face_len - 2;
-
- if (face_len_alloc < face_len) {
- MEM_freeN(uv_verts);
- MEM_freeN(indices);
- uv_verts = MEM_mallocN(sizeof(*uv_verts) * face_len, "UvOverlapCoords");
- indices = MEM_mallocN(sizeof(*indices) * tri_len, "UvOverlapTris");
- face_len_alloc = face_len;
- }
-
- int vert_index;
- BM_ITER_ELEM_INDEX (l, &liter, efa, BM_LOOPS_OF_FACE, vert_index) {
- MLoopUV *luv = BM_ELEM_CD_GET_VOID_P(l, cd_loop_uv_offset);
- copy_v2_v2(uv_verts[vert_index], luv->uv);
- }
-
- BLI_polyfill_calc(uv_verts, face_len, 0, indices);
-
- for (int t = 0; t < tri_len; t++) {
- overlap_data[data_index].ob_index = ob_index;
- overlap_data[data_index].face_index = face_index;
-
- /* BVH needs 3D, overlap data uses 2D. */
- const float tri[3][3] = {
- {UNPACK2(uv_verts[indices[t][0]]), 0.0f},
- {UNPACK2(uv_verts[indices[t][1]]), 0.0f},
- {UNPACK2(uv_verts[indices[t][2]]), 0.0f},
- };
-
- copy_v2_v2(overlap_data[data_index].tri[0], tri[0]);
- copy_v2_v2(overlap_data[data_index].tri[1], tri[1]);
- copy_v2_v2(overlap_data[data_index].tri[2], tri[2]);
-
- BLI_bvhtree_insert(uv_tree, data_index, &tri[0][0], 3);
- data_index++;
- }
- }
- }
- BLI_assert(data_index == uv_tri_len);
-
- MEM_freeN(uv_verts);
- MEM_freeN(indices);
-
- BLI_bvhtree_balance(uv_tree);
-
- uint tree_overlap_len;
- BVHTreeOverlap *overlap = BLI_bvhtree_overlap(uv_tree, uv_tree, &tree_overlap_len, NULL, NULL);
-
- if (overlap != NULL) {
- GSet *overlap_set = BLI_gset_new_ex(overlap_hash, overlap_cmp, __func__, tree_overlap_len);
-
- for (int i = 0; i < tree_overlap_len; i++) {
- /* Skip overlaps against yourself. */
- if (overlap[i].indexA == overlap[i].indexB) {
- continue;
- }
-
- /* Skip overlaps that have already been tested. */
- if (!BLI_gset_add(overlap_set, &overlap[i])) {
- continue;
- }
-
- const struct UVOverlapData *o_a = &overlap_data[overlap[i].indexA];
- const struct UVOverlapData *o_b = &overlap_data[overlap[i].indexB];
- Object *obedit_a = objects[o_a->ob_index];
- Object *obedit_b = objects[o_b->ob_index];
- BMEditMesh *em_a = BKE_editmesh_from_object(obedit_a);
- BMEditMesh *em_b = BKE_editmesh_from_object(obedit_b);
- BMFace *face_a = em_a->bm->ftable[o_a->face_index];
- BMFace *face_b = em_b->bm->ftable[o_b->face_index];
- const int cd_loop_uv_offset_a = CustomData_get_offset(&em_a->bm->ldata, CD_MLOOPUV);
- const int cd_loop_uv_offset_b = CustomData_get_offset(&em_b->bm->ldata, CD_MLOOPUV);
-
- /* Skip if both faces are already selected. */
- if (uvedit_face_select_test(scene, face_a, cd_loop_uv_offset_a) &&
- uvedit_face_select_test(scene, face_b, cd_loop_uv_offset_b)) {
- continue;
- }
-
- /* Main tri-tri overlap test. */
- const float endpoint_bias = -1e-4f;
- const float(*t1)[2] = o_a->tri;
- const float(*t2)[2] = o_b->tri;
- float vi[2];
- bool result = (
- /* Don't use 'isect_tri_tri_v2' here
- * because it's important to ignore overlap at end-points. */
- isect_seg_seg_v2_point_ex(t1[0], t1[1], t2[0], t2[1], endpoint_bias, vi) == 1 ||
- isect_seg_seg_v2_point_ex(t1[0], t1[1], t2[1], t2[2], endpoint_bias, vi) == 1 ||
- isect_seg_seg_v2_point_ex(t1[0], t1[1], t2[2], t2[0], endpoint_bias, vi) == 1 ||
- isect_seg_seg_v2_point_ex(t1[1], t1[2], t2[0], t2[1], endpoint_bias, vi) == 1 ||
- isect_seg_seg_v2_point_ex(t1[1], t1[2], t2[1], t2[2], endpoint_bias, vi) == 1 ||
- isect_seg_seg_v2_point_ex(t1[1], t1[2], t2[2], t2[0], endpoint_bias, vi) == 1 ||
- isect_seg_seg_v2_point_ex(t1[2], t1[0], t2[0], t2[1], endpoint_bias, vi) == 1 ||
- isect_seg_seg_v2_point_ex(t1[2], t1[0], t2[1], t2[2], endpoint_bias, vi) == 1 ||
- isect_point_tri_v2(t1[0], t2[0], t2[1], t2[2]) != 0 ||
- isect_point_tri_v2(t2[0], t1[0], t1[1], t1[2]) != 0);
-
- if (result) {
- uvedit_face_select_enable(scene, em_a, face_a, false, cd_loop_uv_offset_a);
- uvedit_face_select_enable(scene, em_b, face_b, false, cd_loop_uv_offset_b);
- }
- }
-
- BLI_gset_free(overlap_set, NULL);
- MEM_freeN(overlap);
- }
-
- for (uint ob_index = 0; ob_index < objects_len; ob_index++) {
- uv_select_tag_update_for_object(depsgraph, scene->toolsettings, objects[ob_index]);
- }
-
- BLI_bvhtree_free(uv_tree);
-
- MEM_freeN(overlap_data);
- MEM_freeN(objects);
-
- return OPERATOR_FINISHED;
-}
-
-static int uv_select_overlap_exec(bContext *C, wmOperator *op)
-{
- bool extend = RNA_boolean_get(op->ptr, "extend");
- return uv_select_overlap(C, extend);
-}
-
-static void UV_OT_select_overlap(wmOperatorType *ot)
-{
- /* identifiers */
- ot->name = "Select Overlap";
- ot->description = "Select all UV faces which overlap each other";
- ot->idname = "UV_OT_select_overlap";
- ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
-
- /* api callbacks */
- ot->exec = uv_select_overlap_exec;
- ot->poll = ED_operator_uvedit;
-
- /* properties */
- RNA_def_boolean(ot->srna,
- "extend",
- 0,
- "Extend",
- "Extend selection rather than clearing the existing selection");
-}
-
-/** \} */
-
-/* -------------------------------------------------------------------- */
/** \name Hide Operator
* \{ */
@@ -4714,99 +1487,107 @@ static bool bm_face_is_all_uv_sel(BMFace *f, bool select_test, const int cd_loop
static int uv_hide_exec(bContext *C, wmOperator *op)
{
- SpaceImage *sima = CTX_wm_space_image(C);
- Object *obedit = CTX_data_edit_object(C);
+ ViewLayer *view_layer = CTX_data_view_layer(C);
Scene *scene = CTX_data_scene(C);
const ToolSettings *ts = scene->toolsettings;
- BMEditMesh *em = BKE_editmesh_from_object(obedit);
- BMFace *efa;
- BMLoop *l;
- BMIter iter, liter;
- MLoopUV *luv;
const bool swap = RNA_boolean_get(op->ptr, "unselected");
- Image *ima = sima ? sima->image : NULL;
const int use_face_center = (ts->uv_selectmode == UV_SELECT_FACE);
- const int cd_loop_uv_offset = CustomData_get_offset(&em->bm->ldata, CD_MLOOPUV);
+ uint objects_len = 0;
+ Object **objects = BKE_view_layer_array_from_objects_in_edit_mode_unique_data_with_uvs(
+ view_layer, ((View3D *)NULL), &objects_len);
- if (ts->uv_flag & UV_SYNC_SELECTION) {
- if (EDBM_mesh_hide(em, swap)) {
- EDBM_update_generic(obedit->data, true, false);
- }
- return OPERATOR_FINISHED;
- }
+ for (uint ob_index = 0; ob_index < objects_len; ob_index++) {
+ Object *ob = objects[ob_index];
+ BMEditMesh *em = BKE_editmesh_from_object(ob);
+ BMFace *efa;
+ BMLoop *l;
+ BMIter iter, liter;
+ MLoopUV *luv;
- BM_ITER_MESH (efa, &iter, em->bm, BM_FACES_OF_MESH) {
- int hide = 0;
+ const int cd_loop_uv_offset = CustomData_get_offset(&em->bm->ldata, CD_MLOOPUV);
- if (!uvedit_face_visible_test(scene, obedit, ima, efa)) {
- continue;
+ if (ts->uv_flag & UV_SYNC_SELECTION) {
+ if (EDBM_mesh_hide(em, swap)) {
+ EDBM_update_generic(ob->data, true, false);
+ }
+ return OPERATOR_FINISHED;
}
- BM_ITER_ELEM (l, &liter, efa, BM_LOOPS_OF_FACE) {
- luv = BM_ELEM_CD_GET_VOID_P(l, cd_loop_uv_offset);
+ BM_ITER_MESH (efa, &iter, em->bm, BM_FACES_OF_MESH) {
+ int hide = 0;
- if (UV_SEL_TEST(luv, !swap)) {
- hide = 1;
- break;
+ if (!uvedit_face_visible_test(scene, efa)) {
+ continue;
}
- }
- if (hide) {
- /* note, a special case for edges could be used,
- * for now edges act like verts and get flushed */
- if (use_face_center) {
- if (em->selectmode == SCE_SELECT_FACE) {
- /* check that every UV is selected */
- if (bm_face_is_all_uv_sel(efa, true, cd_loop_uv_offset) == !swap) {
- BM_face_select_set(em->bm, efa, false);
- }
- uvedit_face_select_disable(scene, em, efa, cd_loop_uv_offset);
+ BM_ITER_ELEM (l, &liter, efa, BM_LOOPS_OF_FACE) {
+ luv = BM_ELEM_CD_GET_VOID_P(l, cd_loop_uv_offset);
+
+ if (UV_SEL_TEST(luv, !swap)) {
+ hide = 1;
+ break;
}
- else {
- if (bm_face_is_all_uv_sel(efa, true, cd_loop_uv_offset) == !swap) {
- BM_ITER_ELEM (l, &liter, efa, BM_LOOPS_OF_FACE) {
- luv = BM_ELEM_CD_GET_VOID_P(l, cd_loop_uv_offset);
- if (UV_SEL_TEST(luv, !swap)) {
- BM_vert_select_set(em->bm, l->v, false);
+ }
+
+ if (hide) {
+ /* note, a special case for edges could be used,
+ * for now edges act like verts and get flushed */
+ if (use_face_center) {
+ if (em->selectmode == SCE_SELECT_FACE) {
+ /* check that every UV is selected */
+ if (bm_face_is_all_uv_sel(efa, true, cd_loop_uv_offset) == !swap) {
+ BM_face_select_set(em->bm, efa, false);
+ }
+ uvedit_face_select_disable(scene, em, efa, cd_loop_uv_offset);
+ }
+ else {
+ if (bm_face_is_all_uv_sel(efa, true, cd_loop_uv_offset) == !swap) {
+ BM_ITER_ELEM (l, &liter, efa, BM_LOOPS_OF_FACE) {
+ luv = BM_ELEM_CD_GET_VOID_P(l, cd_loop_uv_offset);
+ if (UV_SEL_TEST(luv, !swap)) {
+ BM_vert_select_set(em->bm, l->v, false);
+ }
}
}
+ if (!swap) {
+ uvedit_face_select_disable(scene, em, efa, cd_loop_uv_offset);
+ }
}
- if (!swap) {
+ }
+ else if (em->selectmode == SCE_SELECT_FACE) {
+ /* check if a UV is de-selected */
+ if (bm_face_is_all_uv_sel(efa, false, cd_loop_uv_offset) != !swap) {
+ BM_face_select_set(em->bm, efa, false);
uvedit_face_select_disable(scene, em, efa, cd_loop_uv_offset);
}
}
- }
- else if (em->selectmode == SCE_SELECT_FACE) {
- /* check if a UV is de-selected */
- if (bm_face_is_all_uv_sel(efa, false, cd_loop_uv_offset) != !swap) {
- BM_face_select_set(em->bm, efa, false);
- uvedit_face_select_disable(scene, em, efa, cd_loop_uv_offset);
- }
- }
- else {
- BM_ITER_ELEM (l, &liter, efa, BM_LOOPS_OF_FACE) {
- luv = BM_ELEM_CD_GET_VOID_P(l, cd_loop_uv_offset);
- if (UV_SEL_TEST(luv, !swap)) {
- BM_vert_select_set(em->bm, l->v, false);
- if (!swap) {
- luv->flag &= ~MLOOPUV_VERTSEL;
+ else {
+ BM_ITER_ELEM (l, &liter, efa, BM_LOOPS_OF_FACE) {
+ luv = BM_ELEM_CD_GET_VOID_P(l, cd_loop_uv_offset);
+ if (UV_SEL_TEST(luv, !swap)) {
+ BM_vert_select_set(em->bm, l->v, false);
+ if (!swap) {
+ luv->flag &= ~MLOOPUV_VERTSEL;
+ }
}
}
}
}
}
- }
- /* flush vertex selection changes */
- if (em->selectmode != SCE_SELECT_FACE) {
- EDBM_selectmode_flush_ex(em, SCE_SELECT_VERTEX | SCE_SELECT_EDGE);
- }
+ /* flush vertex selection changes */
+ if (em->selectmode != SCE_SELECT_FACE) {
+ EDBM_selectmode_flush_ex(em, SCE_SELECT_VERTEX | SCE_SELECT_EDGE);
+ }
+
+ BM_select_history_validate(em->bm);
- BM_select_history_validate(em->bm);
+ DEG_id_tag_update(ob->data, ID_RECALC_SELECT);
+ WM_event_add_notifier(C, NC_GEOM | ND_SELECT, ob->data);
+ }
- DEG_id_tag_update(obedit->data, ID_RECALC_SELECT);
- WM_event_add_notifier(C, NC_GEOM | ND_SELECT, obedit->data);
+ MEM_freeN(objects);
return OPERATOR_FINISHED;
}
@@ -4837,119 +1618,131 @@ static void UV_OT_hide(wmOperatorType *ot)
static int uv_reveal_exec(bContext *C, wmOperator *op)
{
+ ViewLayer *view_layer = CTX_data_view_layer(C);
SpaceImage *sima = CTX_wm_space_image(C);
- Object *obedit = CTX_data_edit_object(C);
Scene *scene = CTX_data_scene(C);
const ToolSettings *ts = scene->toolsettings;
- BMEditMesh *em = BKE_editmesh_from_object(obedit);
- BMFace *efa;
- BMLoop *l;
- BMIter iter, liter;
- MLoopUV *luv;
+
const int use_face_center = (ts->uv_selectmode == UV_SELECT_FACE);
const int stickymode = sima ? (sima->sticky != SI_STICKY_DISABLE) : 1;
+ const bool select = RNA_boolean_get(op->ptr, "select");
- const int cd_loop_uv_offset = CustomData_get_offset(&em->bm->ldata, CD_MLOOPUV);
+ uint objects_len = 0;
+ Object **objects = BKE_view_layer_array_from_objects_in_edit_mode_unique_data_with_uvs(
+ view_layer, ((View3D *)NULL), &objects_len);
- const bool select = RNA_boolean_get(op->ptr, "select");
+ for (uint ob_index = 0; ob_index < objects_len; ob_index++) {
+ Object *ob = objects[ob_index];
+ BMEditMesh *em = BKE_editmesh_from_object(ob);
+ BMFace *efa;
+ BMLoop *l;
+ BMIter iter, liter;
+ MLoopUV *luv;
- /* note on tagging, selecting faces needs to be delayed so it doesn't select the verts and
- * confuse our checks on selected verts. */
+ const int cd_loop_uv_offset = CustomData_get_offset(&em->bm->ldata, CD_MLOOPUV);
- /* call the mesh function if we are in mesh sync sel */
- if (ts->uv_flag & UV_SYNC_SELECTION) {
- if (EDBM_mesh_reveal(em, select)) {
- EDBM_update_generic(obedit->data, true, false);
- }
- return OPERATOR_FINISHED;
- }
- if (use_face_center) {
- if (em->selectmode == SCE_SELECT_FACE) {
- BM_ITER_MESH (efa, &iter, em->bm, BM_FACES_OF_MESH) {
- BM_elem_flag_disable(efa, BM_ELEM_TAG);
- if (!BM_elem_flag_test(efa, BM_ELEM_HIDDEN) && !BM_elem_flag_test(efa, BM_ELEM_SELECT)) {
- BM_ITER_ELEM (l, &liter, efa, BM_LOOPS_OF_FACE) {
- luv = BM_ELEM_CD_GET_VOID_P(l, cd_loop_uv_offset);
- SET_FLAG_FROM_TEST(luv->flag, select, MLOOPUV_VERTSEL);
- }
- /* BM_face_select_set(em->bm, efa, true); */
- BM_elem_flag_enable(efa, BM_ELEM_TAG);
- }
+ /* note on tagging, selecting faces needs to be delayed so it doesn't select the verts and
+ * confuse our checks on selected verts. */
+
+ /* call the mesh function if we are in mesh sync sel */
+ if (ts->uv_flag & UV_SYNC_SELECTION) {
+ if (EDBM_mesh_reveal(em, select)) {
+ EDBM_update_generic(ob->data, true, false);
}
+ return OPERATOR_FINISHED;
}
- else {
- /* enable adjacent faces to have disconnected UV selections if sticky is disabled */
- if (!stickymode) {
+ if (use_face_center) {
+ if (em->selectmode == SCE_SELECT_FACE) {
BM_ITER_MESH (efa, &iter, em->bm, BM_FACES_OF_MESH) {
BM_elem_flag_disable(efa, BM_ELEM_TAG);
if (!BM_elem_flag_test(efa, BM_ELEM_HIDDEN) && !BM_elem_flag_test(efa, BM_ELEM_SELECT)) {
- int totsel = 0;
BM_ITER_ELEM (l, &liter, efa, BM_LOOPS_OF_FACE) {
- totsel += BM_elem_flag_test(l->v, BM_ELEM_SELECT);
+ luv = BM_ELEM_CD_GET_VOID_P(l, cd_loop_uv_offset);
+ SET_FLAG_FROM_TEST(luv->flag, select, MLOOPUV_VERTSEL);
}
-
- if (!totsel) {
+ /* BM_face_select_set(em->bm, efa, true); */
+ BM_elem_flag_enable(efa, BM_ELEM_TAG);
+ }
+ }
+ }
+ else {
+ /* enable adjacent faces to have disconnected UV selections if sticky is disabled */
+ if (!stickymode) {
+ BM_ITER_MESH (efa, &iter, em->bm, BM_FACES_OF_MESH) {
+ BM_elem_flag_disable(efa, BM_ELEM_TAG);
+ if (!BM_elem_flag_test(efa, BM_ELEM_HIDDEN) &&
+ !BM_elem_flag_test(efa, BM_ELEM_SELECT)) {
+ int totsel = 0;
BM_ITER_ELEM (l, &liter, efa, BM_LOOPS_OF_FACE) {
- luv = BM_ELEM_CD_GET_VOID_P(l, cd_loop_uv_offset);
- SET_FLAG_FROM_TEST(luv->flag, select, MLOOPUV_VERTSEL);
+ totsel += BM_elem_flag_test(l->v, BM_ELEM_SELECT);
+ }
+
+ if (!totsel) {
+ BM_ITER_ELEM (l, &liter, efa, BM_LOOPS_OF_FACE) {
+ luv = BM_ELEM_CD_GET_VOID_P(l, cd_loop_uv_offset);
+ SET_FLAG_FROM_TEST(luv->flag, select, MLOOPUV_VERTSEL);
+ }
+ /* BM_face_select_set(em->bm, efa, true); */
+ BM_elem_flag_enable(efa, BM_ELEM_TAG);
}
- /* BM_face_select_set(em->bm, efa, true); */
- BM_elem_flag_enable(efa, BM_ELEM_TAG);
}
}
}
- }
- else {
- BM_ITER_MESH (efa, &iter, em->bm, BM_FACES_OF_MESH) {
- BM_elem_flag_disable(efa, BM_ELEM_TAG);
- if (!BM_elem_flag_test(efa, BM_ELEM_HIDDEN) && !BM_elem_flag_test(efa, BM_ELEM_SELECT)) {
- BM_ITER_ELEM (l, &liter, efa, BM_LOOPS_OF_FACE) {
- if (BM_elem_flag_test(l->v, BM_ELEM_SELECT) == 0) {
- luv = BM_ELEM_CD_GET_VOID_P(l, cd_loop_uv_offset);
- SET_FLAG_FROM_TEST(luv->flag, select, MLOOPUV_VERTSEL);
+ else {
+ BM_ITER_MESH (efa, &iter, em->bm, BM_FACES_OF_MESH) {
+ BM_elem_flag_disable(efa, BM_ELEM_TAG);
+ if (!BM_elem_flag_test(efa, BM_ELEM_HIDDEN) &&
+ !BM_elem_flag_test(efa, BM_ELEM_SELECT)) {
+ BM_ITER_ELEM (l, &liter, efa, BM_LOOPS_OF_FACE) {
+ if (BM_elem_flag_test(l->v, BM_ELEM_SELECT) == 0) {
+ luv = BM_ELEM_CD_GET_VOID_P(l, cd_loop_uv_offset);
+ SET_FLAG_FROM_TEST(luv->flag, select, MLOOPUV_VERTSEL);
+ }
}
+ /* BM_face_select_set(em->bm, efa, true); */
+ BM_elem_flag_enable(efa, BM_ELEM_TAG);
}
- /* BM_face_select_set(em->bm, efa, true); */
- BM_elem_flag_enable(efa, BM_ELEM_TAG);
}
}
}
}
- }
- else if (em->selectmode == SCE_SELECT_FACE) {
- BM_ITER_MESH (efa, &iter, em->bm, BM_FACES_OF_MESH) {
- BM_elem_flag_disable(efa, BM_ELEM_TAG);
- if (!BM_elem_flag_test(efa, BM_ELEM_HIDDEN) && !BM_elem_flag_test(efa, BM_ELEM_SELECT)) {
- BM_ITER_ELEM (l, &liter, efa, BM_LOOPS_OF_FACE) {
- luv = BM_ELEM_CD_GET_VOID_P(l, cd_loop_uv_offset);
- SET_FLAG_FROM_TEST(luv->flag, select, MLOOPUV_VERTSEL);
+ else if (em->selectmode == SCE_SELECT_FACE) {
+ BM_ITER_MESH (efa, &iter, em->bm, BM_FACES_OF_MESH) {
+ BM_elem_flag_disable(efa, BM_ELEM_TAG);
+ if (!BM_elem_flag_test(efa, BM_ELEM_HIDDEN) && !BM_elem_flag_test(efa, BM_ELEM_SELECT)) {
+ BM_ITER_ELEM (l, &liter, efa, BM_LOOPS_OF_FACE) {
+ luv = BM_ELEM_CD_GET_VOID_P(l, cd_loop_uv_offset);
+ SET_FLAG_FROM_TEST(luv->flag, select, MLOOPUV_VERTSEL);
+ }
+ /* BM_face_select_set(em->bm, efa, true); */
+ BM_elem_flag_enable(efa, BM_ELEM_TAG);
}
- /* BM_face_select_set(em->bm, efa, true); */
- BM_elem_flag_enable(efa, BM_ELEM_TAG);
}
}
- }
- else {
- BM_ITER_MESH (efa, &iter, em->bm, BM_FACES_OF_MESH) {
- BM_elem_flag_disable(efa, BM_ELEM_TAG);
- if (!BM_elem_flag_test(efa, BM_ELEM_HIDDEN) && !BM_elem_flag_test(efa, BM_ELEM_SELECT)) {
- BM_ITER_ELEM (l, &liter, efa, BM_LOOPS_OF_FACE) {
- if (BM_elem_flag_test(l->v, BM_ELEM_SELECT) == 0) {
- luv = BM_ELEM_CD_GET_VOID_P(l, cd_loop_uv_offset);
- SET_FLAG_FROM_TEST(luv->flag, select, MLOOPUV_VERTSEL);
+ else {
+ BM_ITER_MESH (efa, &iter, em->bm, BM_FACES_OF_MESH) {
+ BM_elem_flag_disable(efa, BM_ELEM_TAG);
+ if (!BM_elem_flag_test(efa, BM_ELEM_HIDDEN) && !BM_elem_flag_test(efa, BM_ELEM_SELECT)) {
+ BM_ITER_ELEM (l, &liter, efa, BM_LOOPS_OF_FACE) {
+ if (BM_elem_flag_test(l->v, BM_ELEM_SELECT) == 0) {
+ luv = BM_ELEM_CD_GET_VOID_P(l, cd_loop_uv_offset);
+ SET_FLAG_FROM_TEST(luv->flag, select, MLOOPUV_VERTSEL);
+ }
}
+ /* BM_face_select_set(em->bm, efa, true); */
+ BM_elem_flag_enable(efa, BM_ELEM_TAG);
}
- /* BM_face_select_set(em->bm, efa, true); */
- BM_elem_flag_enable(efa, BM_ELEM_TAG);
}
}
- }
- /* re-select tagged faces */
- BM_mesh_elem_hflag_enable_test(em->bm, BM_FACE, BM_ELEM_SELECT, true, false, BM_ELEM_TAG);
+ /* re-select tagged faces */
+ BM_mesh_elem_hflag_enable_test(em->bm, BM_FACE, BM_ELEM_SELECT, true, false, BM_ELEM_TAG);
+
+ DEG_id_tag_update(ob->data, ID_RECALC_SELECT);
+ WM_event_add_notifier(C, NC_GEOM | ND_SELECT, ob->data);
+ }
- DEG_id_tag_update(obedit->data, ID_RECALC_SELECT);
- WM_event_add_notifier(C, NC_GEOM | ND_SELECT, obedit->data);
+ MEM_freeN(objects);
return OPERATOR_FINISHED;
}
@@ -5050,11 +1843,12 @@ static void UV_OT_cursor_set(wmOperatorType *ot)
static int uv_seams_from_islands_exec(bContext *C, wmOperator *op)
{
+ Scene *scene = CTX_data_scene(C);
ViewLayer *view_layer = CTX_data_view_layer(C);
- int ret = OPERATOR_CANCELLED;
const float limit[2] = {STD_UV_CONNECT_LIMIT, STD_UV_CONNECT_LIMIT};
const bool mark_seams = RNA_boolean_get(op->ptr, "mark_seams");
const bool mark_sharp = RNA_boolean_get(op->ptr, "mark_sharp");
+ bool changed_multi = false;
uint objects_len = 0;
Object **objects = BKE_view_layer_array_from_objects_in_edit_mode_unique_data_with_uvs(
@@ -5065,111 +1859,76 @@ static int uv_seams_from_islands_exec(bContext *C, wmOperator *op)
Mesh *me = (Mesh *)ob->data;
BMEditMesh *em = me->edit_mesh;
BMesh *bm = em->bm;
-
- UvVertMap *vmap;
- BMEdge *editedge;
BMIter iter;
if (!EDBM_uv_check(em)) {
continue;
}
- ret = OPERATOR_FINISHED;
-
- /* This code sets editvert->tmp.l to the index. This will be useful later on. */
- BM_mesh_elem_table_ensure(bm, BM_FACE);
- vmap = BM_uv_vert_map_create(bm, limit, false, false);
-
- BM_ITER_MESH (editedge, &iter, bm, BM_EDGES_OF_MESH) {
- /* flags to determine if we uv is separated from first editface match */
- char separated1 = 0, separated2;
- /* set to denote edge must be flagged as seam */
- char faces_separated = 0;
- /* flag to keep track if uv1 is disconnected from first editface match */
- char v1coincident = 1;
- /* For use with v1coincident. v1coincident will change only if we've had commonFaces */
- int commonFaces = 0;
-
- BMFace *efa1, *efa2;
-
- UvMapVert *mv1, *mvinit1, *mv2, *mvinit2, *mviter;
- /* mv2cache stores the first of the list of coincident uv's for later comparison
- * mv2sep holds the last separator and is copied to mv2cache
- * when a hit is first found */
- UvMapVert *mv2cache = NULL, *mv2sep = NULL;
-
- mvinit1 = vmap->vert[BM_elem_index_get(editedge->v1)];
- if (mark_seams) {
- BM_elem_flag_disable(editedge, BM_ELEM_SEAM);
+
+ const int cd_loop_uv_offset = CustomData_get_offset(&bm->ldata, CD_MLOOPUV);
+ bool changed = false;
+
+ BMFace *f;
+ BM_ITER_MESH (f, &iter, bm, BM_FACES_OF_MESH) {
+ if (!uvedit_face_visible_test(scene, f)) {
+ continue;
}
- for (mv1 = mvinit1; mv1 && !faces_separated; mv1 = mv1->next) {
- if (mv1->separate && commonFaces) {
- v1coincident = 0;
+ BMLoop *l_iter;
+ BMLoop *l_first;
+
+ l_iter = l_first = BM_FACE_FIRST_LOOP(f);
+ do {
+ if (l_iter == l_iter->radial_next) {
+ continue;
+ }
+ if (!uvedit_edge_select_test(scene, l_iter, cd_loop_uv_offset)) {
+ continue;
}
- separated2 = 0;
- efa1 = BM_face_at_index(bm, mv1->poly_index);
- mvinit2 = vmap->vert[BM_elem_index_get(editedge->v2)];
+ const MLoopUV *luv_curr = BM_ELEM_CD_GET_VOID_P(l_iter, cd_loop_uv_offset);
+ const MLoopUV *luv_next = BM_ELEM_CD_GET_VOID_P(l_iter->next, cd_loop_uv_offset);
- for (mv2 = mvinit2; mv2; mv2 = mv2->next) {
- if (mv2->separate) {
- mv2sep = mv2;
+ bool mark = false;
+ BMLoop *l_other = l_iter->radial_next;
+ do {
+ const MLoopUV *luv_other_curr = BM_ELEM_CD_GET_VOID_P(l_other, cd_loop_uv_offset);
+ const MLoopUV *luv_other_next = BM_ELEM_CD_GET_VOID_P(l_other->next, cd_loop_uv_offset);
+ if (l_iter->v != l_other->v) {
+ SWAP(const MLoopUV *, luv_other_curr, luv_other_next);
}
- efa2 = BM_face_at_index(bm, mv2->poly_index);
- if (efa1 == efa2) {
- /* if v1 is not coincident no point in comparing */
- if (v1coincident) {
- /* have we found previously anything? */
- if (mv2cache) {
- /* flag seam unless proved to be coincident with previous hit */
- separated2 = 1;
- for (mviter = mv2cache; mviter; mviter = mviter->next) {
- if (mviter->separate && mviter != mv2cache) {
- break;
- }
- /* coincident with previous hit, do not flag seam */
- if (mviter == mv2) {
- separated2 = 0;
- }
- }
- }
- /* First hit case, store the hit in the cache */
- else {
- mv2cache = mv2sep;
- commonFaces = 1;
- }
- }
- else {
- separated1 = 1;
- }
+ if (!compare_ff(luv_curr->uv[0], luv_other_curr->uv[0], limit[0]) ||
+ !compare_ff(luv_curr->uv[1], luv_other_curr->uv[1], limit[1]) ||
- if (separated1 || separated2) {
- faces_separated = 1;
- break;
- }
+ !compare_ff(luv_next->uv[0], luv_other_next->uv[0], limit[0]) ||
+ !compare_ff(luv_next->uv[1], luv_other_next->uv[1], limit[1])) {
+ mark = true;
+ break;
}
- }
- }
+ } while ((l_other = l_other->radial_next) != l_iter);
- if (faces_separated) {
- if (mark_seams) {
- BM_elem_flag_enable(editedge, BM_ELEM_SEAM);
- }
- if (mark_sharp) {
- BM_elem_flag_disable(editedge, BM_ELEM_SMOOTH);
+ if (mark) {
+ if (mark_seams) {
+ BM_elem_flag_enable(l_iter->e, BM_ELEM_SEAM);
+ }
+ if (mark_sharp) {
+ BM_elem_flag_disable(l_iter->e, BM_ELEM_SMOOTH);
+ }
+ changed = true;
}
- }
+ } while ((l_iter = l_iter->next) != l_first);
}
- BM_uv_vert_map_free(vmap);
-
- DEG_id_tag_update(&me->id, 0);
- WM_event_add_notifier(C, NC_GEOM | ND_DATA, me);
+ if (changed) {
+ changed_multi = true;
+ DEG_id_tag_update(&me->id, 0);
+ WM_event_add_notifier(C, NC_GEOM | ND_DATA, me);
+ }
}
MEM_freeN(objects);
- return ret;
+ return changed_multi ? OPERATOR_FINISHED : OPERATOR_CANCELLED;
}
static void UV_OT_seams_from_islands(wmOperatorType *ot)
@@ -5228,10 +1987,12 @@ static int uv_mark_seam_exec(bContext *C, wmOperator *op)
const int cd_loop_uv_offset = CustomData_get_offset(&bm->ldata, CD_MLOOPUV);
BM_ITER_MESH (efa, &iter, bm, BM_FACES_OF_MESH) {
- BM_ITER_ELEM (loop, &liter, efa, BM_LOOPS_OF_FACE) {
- if (uvedit_edge_select_test(scene, loop, cd_loop_uv_offset)) {
- BM_elem_flag_set(loop->e, BM_ELEM_SEAM, flag_set);
- changed = true;
+ if (uvedit_face_visible_test(scene, efa)) {
+ BM_ITER_ELEM (loop, &liter, efa, BM_LOOPS_OF_FACE) {
+ if (uvedit_edge_select_test(scene, loop, cd_loop_uv_offset)) {
+ BM_elem_flag_set(loop->e, BM_ELEM_SEAM, flag_set);
+ changed = true;
+ }
}
}
}
@@ -5308,6 +2069,7 @@ static void UV_OT_mark_seam(wmOperatorType *ot)
void ED_operatortypes_uvedit(void)
{
+ /* uvedit_select.c */
WM_operatortype_append(UV_OT_select_all);
WM_operatortype_append(UV_OT_select);
WM_operatortype_append(UV_OT_select_loop);
diff --git a/source/blender/editors/uvedit/uvedit_parametrizer.c b/source/blender/editors/uvedit/uvedit_parametrizer.c
index 936ba750266..da8e0efa522 100644
--- a/source/blender/editors/uvedit/uvedit_parametrizer.c
+++ b/source/blender/editors/uvedit/uvedit_parametrizer.c
@@ -107,7 +107,7 @@ typedef struct PVert {
struct PEdge *edge;
float co[3];
float uv[2];
- unsigned char flag;
+ uchar flag;
} PVert;
@@ -126,7 +126,7 @@ typedef struct PEdge {
struct PEdge *next;
struct PFace *face;
float *orig_uv, old_uv[2];
- unsigned short flag;
+ ushort flag;
} PEdge;
@@ -141,7 +141,7 @@ typedef struct PFace {
} u;
struct PEdge *edge;
- unsigned char flag;
+ uchar flag;
} PFace;
enum PVertFlag {
@@ -197,7 +197,7 @@ typedef struct PChart {
} pack;
} u;
- unsigned char flag;
+ uchar flag;
struct PHandle *handle;
} PChart;
@@ -245,7 +245,7 @@ static int PHashSizes[] = {
1048583, 2097169, 4194319, 8388617, 16777259, 33554467, 67108879, 134217757, 268435459,
};
-#define PHASH_hash(ph, item) (((uintptr_t)(item)) % ((unsigned int)(ph)->cursize))
+#define PHASH_hash(ph, item) (((uintptr_t)(item)) % ((uint)(ph)->cursize))
#define PHASH_edge(v1, v2) (((v1) < (v2)) ? ((v1)*39) ^ ((v2)*31) : ((v1)*31) ^ ((v2)*39))
static PHash *phash_new(PHashLink **list, int sizehint)
@@ -511,7 +511,7 @@ static void p_chart_uv_transform(PChart *chart, float mat[2][2])
static void p_chart_uv_to_array(PChart *chart, float (*points)[2])
{
PVert *v;
- unsigned int i = 0;
+ uint i = 0;
for (v = chart->verts; v; v = v->nextlink) {
copy_v2_v2(points[i++], v->uv);
@@ -521,7 +521,7 @@ static void p_chart_uv_to_array(PChart *chart, float (*points)[2])
static void UNUSED_FUNCTION(p_chart_uv_from_array)(PChart *chart, float (*points)[2])
{
PVert *v;
- unsigned int i = 0;
+ uint i = 0;
for (v = chart->verts; v; v = v->nextlink) {
copy_v2_v2(v->uv, points[i++]);
@@ -4409,8 +4409,8 @@ static void p_add_ngon(ParamHandle *handle,
PHandle *phandle = (PHandle *)handle;
MemArena *arena = phandle->polyfill_arena;
Heap *heap = phandle->polyfill_heap;
- unsigned int nfilltri = nverts - 2;
- unsigned int(*tris)[3] = BLI_memarena_alloc(arena, sizeof(*tris) * (size_t)nfilltri);
+ uint nfilltri = nverts - 2;
+ uint(*tris)[3] = BLI_memarena_alloc(arena, sizeof(*tris) * (size_t)nfilltri);
float(*projverts)[2] = BLI_memarena_alloc(arena, sizeof(*projverts) * (size_t)nverts);
/* Calc normal, flipped: to get a positive 2d cross product. */
@@ -4441,10 +4441,10 @@ static void p_add_ngon(ParamHandle *handle,
/* Add triangles. */
for (int j = 0; j < nfilltri; j++) {
- unsigned int *tri = tris[j];
- unsigned int v0 = tri[0];
- unsigned int v1 = tri[1];
- unsigned int v2 = tri[2];
+ uint *tri = tris[j];
+ uint v0 = tri[0];
+ uint v1 = tri[1];
+ uint v2 = tri[2];
ParamKey tri_vkeys[3] = {vkeys[v0], vkeys[v1], vkeys[v2]};
float *tri_co[3] = {co[v0], co[v1], co[v2]};
diff --git a/source/blender/editors/uvedit/uvedit_parametrizer.h b/source/blender/editors/uvedit/uvedit_parametrizer.h
index 2b80241e6e3..53188ea42bb 100644
--- a/source/blender/editors/uvedit/uvedit_parametrizer.h
+++ b/source/blender/editors/uvedit/uvedit_parametrizer.h
@@ -21,12 +21,12 @@
* \ingroup eduv
*/
+#include "BLI_sys_types.h" // for intptr_t support
+
#ifdef __cplusplus
extern "C" {
#endif
-#include "BLI_sys_types.h" // for intptr_t support
-
typedef void ParamHandle; /* handle to a set of charts */
typedef intptr_t ParamKey; /* (hash) key for identifying verts and faces */
typedef enum ParamBool {
diff --git a/source/blender/editors/uvedit/uvedit_select.c b/source/blender/editors/uvedit/uvedit_select.c
new file mode 100644
index 00000000000..cc9be9d48c1
--- /dev/null
+++ b/source/blender/editors/uvedit/uvedit_select.c
@@ -0,0 +1,3371 @@
+/*
+ * 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) 2001-2002 by NaN Holding BV.
+ * All rights reserved.
+ */
+
+/** \file
+ * \ingroup eduv
+ */
+
+#include <math.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include "MEM_guardedalloc.h"
+
+#include "DNA_image_types.h"
+#include "DNA_meshdata_types.h"
+#include "DNA_node_types.h"
+#include "DNA_object_types.h"
+#include "DNA_scene_types.h"
+#include "DNA_space_types.h"
+
+#include "BLI_alloca.h"
+#include "BLI_blenlib.h"
+#include "BLI_hash.h"
+#include "BLI_kdopbvh.h"
+#include "BLI_lasso_2d.h"
+#include "BLI_math.h"
+#include "BLI_polyfill_2d.h"
+#include "BLI_utildefines.h"
+
+#include "BKE_context.h"
+#include "BKE_customdata.h"
+#include "BKE_editmesh.h"
+#include "BKE_layer.h"
+#include "BKE_mesh.h"
+#include "BKE_mesh_mapping.h"
+#include "BKE_report.h"
+
+#include "DEG_depsgraph.h"
+#include "DEG_depsgraph_query.h"
+
+#include "ED_image.h"
+#include "ED_mesh.h"
+#include "ED_screen.h"
+#include "ED_select_utils.h"
+#include "ED_uvedit.h"
+
+#include "RNA_access.h"
+#include "RNA_define.h"
+
+#include "WM_api.h"
+#include "WM_types.h"
+
+#include "UI_view2d.h"
+
+#include "uvedit_intern.h"
+
+static void uv_select_all_perform(Scene *scene, Object *obedit, int action);
+static void uv_select_all_perform_multi(Scene *scene,
+ Object **objects,
+ const uint objects_len,
+ int action);
+static void uv_select_flush_from_tag_face(SpaceImage *sima,
+ Scene *scene,
+ Object *obedit,
+ const bool select);
+static void uv_select_flush_from_tag_loop(SpaceImage *sima,
+ Scene *scene,
+ Object *obedit,
+ const bool select);
+static void uv_select_tag_update_for_object(Depsgraph *depsgraph,
+ const ToolSettings *ts,
+ Object *obedit);
+
+/* -------------------------------------------------------------------- */
+/** \name Visibility and Selection Utilities
+ * \{ */
+
+static void uv_select_island_limit_default(SpaceImage *sima, float r_limit[2])
+{
+ uvedit_pixel_to_float(sima, 0.05f, r_limit);
+}
+
+static void uvedit_vertex_select_tagged(BMEditMesh *em,
+ Scene *scene,
+ bool select,
+ int cd_loop_uv_offset)
+{
+ BMFace *efa;
+ BMLoop *l;
+ BMIter iter, liter;
+
+ BM_ITER_MESH (efa, &iter, em->bm, BM_FACES_OF_MESH) {
+ BM_ITER_ELEM (l, &liter, efa, BM_LOOPS_OF_FACE) {
+ if (BM_elem_flag_test(l->v, BM_ELEM_TAG)) {
+ uvedit_uv_select_set(em, scene, l, select, false, cd_loop_uv_offset);
+ }
+ }
+ }
+}
+
+bool uvedit_face_visible_test_ex(const ToolSettings *ts, BMFace *efa)
+{
+ if (ts->uv_flag & UV_SYNC_SELECTION) {
+ return (BM_elem_flag_test(efa, BM_ELEM_HIDDEN) == 0);
+ }
+ else {
+ return (BM_elem_flag_test(efa, BM_ELEM_HIDDEN) == 0 && BM_elem_flag_test(efa, BM_ELEM_SELECT));
+ }
+}
+bool uvedit_face_visible_test(const Scene *scene, BMFace *efa)
+{
+ return uvedit_face_visible_test_ex(scene->toolsettings, efa);
+}
+
+bool uvedit_face_select_test_ex(const ToolSettings *ts, BMFace *efa, const int cd_loop_uv_offset)
+{
+ if (ts->uv_flag & UV_SYNC_SELECTION) {
+ return (BM_elem_flag_test(efa, BM_ELEM_SELECT));
+ }
+ else {
+ BMLoop *l;
+ MLoopUV *luv;
+ BMIter liter;
+
+ BM_ITER_ELEM (l, &liter, efa, BM_LOOPS_OF_FACE) {
+ luv = BM_ELEM_CD_GET_VOID_P(l, cd_loop_uv_offset);
+ if (!(luv->flag & MLOOPUV_VERTSEL)) {
+ return false;
+ }
+ }
+
+ return true;
+ }
+}
+bool uvedit_face_select_test(const Scene *scene, BMFace *efa, const int cd_loop_uv_offset)
+{
+ return uvedit_face_select_test_ex(scene->toolsettings, efa, cd_loop_uv_offset);
+}
+
+bool uvedit_face_select_set(const struct Scene *scene,
+ struct BMEditMesh *em,
+ struct BMFace *efa,
+ const bool select,
+ const bool do_history,
+ const int cd_loop_uv_offset)
+{
+ if (select) {
+ return uvedit_face_select_enable(scene, em, efa, do_history, cd_loop_uv_offset);
+ }
+ else {
+ return uvedit_face_select_disable(scene, em, efa, cd_loop_uv_offset);
+ }
+}
+
+bool uvedit_face_select_enable(const Scene *scene,
+ BMEditMesh *em,
+ BMFace *efa,
+ const bool do_history,
+ const int cd_loop_uv_offset)
+{
+ const ToolSettings *ts = scene->toolsettings;
+
+ if (ts->uv_flag & UV_SYNC_SELECTION) {
+ BM_face_select_set(em->bm, efa, true);
+ if (do_history) {
+ BM_select_history_store(em->bm, (BMElem *)efa);
+ }
+ }
+ else {
+ BMLoop *l;
+ MLoopUV *luv;
+ BMIter liter;
+
+ BM_ITER_ELEM (l, &liter, efa, BM_LOOPS_OF_FACE) {
+ luv = BM_ELEM_CD_GET_VOID_P(l, cd_loop_uv_offset);
+ luv->flag |= MLOOPUV_VERTSEL;
+ }
+
+ return true;
+ }
+
+ return false;
+}
+
+bool uvedit_face_select_disable(const Scene *scene,
+ BMEditMesh *em,
+ BMFace *efa,
+ const int cd_loop_uv_offset)
+{
+ const ToolSettings *ts = scene->toolsettings;
+
+ if (ts->uv_flag & UV_SYNC_SELECTION) {
+ BM_face_select_set(em->bm, efa, false);
+ }
+ else {
+ BMLoop *l;
+ MLoopUV *luv;
+ BMIter liter;
+
+ BM_ITER_ELEM (l, &liter, efa, BM_LOOPS_OF_FACE) {
+ luv = BM_ELEM_CD_GET_VOID_P(l, cd_loop_uv_offset);
+ luv->flag &= ~MLOOPUV_VERTSEL;
+ }
+
+ return true;
+ }
+
+ return false;
+}
+
+bool uvedit_edge_select_test_ex(const ToolSettings *ts, BMLoop *l, const int cd_loop_uv_offset)
+{
+ if (ts->uv_flag & UV_SYNC_SELECTION) {
+ if (ts->selectmode & SCE_SELECT_FACE) {
+ return BM_elem_flag_test(l->f, BM_ELEM_SELECT);
+ }
+ else if (ts->selectmode == SCE_SELECT_EDGE) {
+ return BM_elem_flag_test(l->e, BM_ELEM_SELECT);
+ }
+ else {
+ return BM_elem_flag_test(l->v, BM_ELEM_SELECT) &&
+ BM_elem_flag_test(l->next->v, BM_ELEM_SELECT);
+ }
+ }
+ else {
+ MLoopUV *luv1, *luv2;
+
+ luv1 = BM_ELEM_CD_GET_VOID_P(l, cd_loop_uv_offset);
+ luv2 = BM_ELEM_CD_GET_VOID_P(l->next, cd_loop_uv_offset);
+
+ return (luv1->flag & MLOOPUV_VERTSEL) && (luv2->flag & MLOOPUV_VERTSEL);
+ }
+}
+bool uvedit_edge_select_test(const Scene *scene, BMLoop *l, const int cd_loop_uv_offset)
+{
+ return uvedit_edge_select_test_ex(scene->toolsettings, l, cd_loop_uv_offset);
+}
+
+void uvedit_edge_select_set(BMEditMesh *em,
+ const Scene *scene,
+ BMLoop *l,
+ const bool select,
+ const bool do_history,
+ const int cd_loop_uv_offset)
+
+{
+ if (select) {
+ uvedit_edge_select_enable(em, scene, l, do_history, cd_loop_uv_offset);
+ }
+ else {
+ uvedit_edge_select_disable(em, scene, l, cd_loop_uv_offset);
+ }
+}
+
+void uvedit_edge_select_enable(BMEditMesh *em,
+ const Scene *scene,
+ BMLoop *l,
+ const bool do_history,
+ const int cd_loop_uv_offset)
+
+{
+ const ToolSettings *ts = scene->toolsettings;
+
+ if (ts->uv_flag & UV_SYNC_SELECTION) {
+ if (ts->selectmode & SCE_SELECT_FACE) {
+ BM_face_select_set(em->bm, l->f, true);
+ }
+ else if (ts->selectmode & SCE_SELECT_EDGE) {
+ BM_edge_select_set(em->bm, l->e, true);
+ }
+ else {
+ BM_vert_select_set(em->bm, l->e->v1, true);
+ BM_vert_select_set(em->bm, l->e->v2, true);
+ }
+
+ if (do_history) {
+ BM_select_history_store(em->bm, (BMElem *)l->e);
+ }
+ }
+ else {
+ MLoopUV *luv1, *luv2;
+
+ luv1 = BM_ELEM_CD_GET_VOID_P(l, cd_loop_uv_offset);
+ luv2 = BM_ELEM_CD_GET_VOID_P(l->next, cd_loop_uv_offset);
+
+ luv1->flag |= MLOOPUV_VERTSEL;
+ luv2->flag |= MLOOPUV_VERTSEL;
+ }
+}
+
+void uvedit_edge_select_disable(BMEditMesh *em,
+ const Scene *scene,
+ BMLoop *l,
+ const int cd_loop_uv_offset)
+
+{
+ const ToolSettings *ts = scene->toolsettings;
+
+ if (ts->uv_flag & UV_SYNC_SELECTION) {
+ if (ts->selectmode & SCE_SELECT_FACE) {
+ BM_face_select_set(em->bm, l->f, false);
+ }
+ else if (ts->selectmode & SCE_SELECT_EDGE) {
+ BM_edge_select_set(em->bm, l->e, false);
+ }
+ else {
+ BM_vert_select_set(em->bm, l->e->v1, false);
+ BM_vert_select_set(em->bm, l->e->v2, false);
+ }
+ }
+ else {
+ MLoopUV *luv1, *luv2;
+
+ luv1 = BM_ELEM_CD_GET_VOID_P(l, cd_loop_uv_offset);
+ luv2 = BM_ELEM_CD_GET_VOID_P(l->next, cd_loop_uv_offset);
+
+ luv1->flag &= ~MLOOPUV_VERTSEL;
+ luv2->flag &= ~MLOOPUV_VERTSEL;
+ }
+}
+
+bool uvedit_uv_select_test_ex(const ToolSettings *ts, BMLoop *l, const int cd_loop_uv_offset)
+{
+ if (ts->uv_flag & UV_SYNC_SELECTION) {
+ if (ts->selectmode & SCE_SELECT_FACE) {
+ return BM_elem_flag_test_bool(l->f, BM_ELEM_SELECT);
+ }
+ else {
+ return BM_elem_flag_test_bool(l->v, BM_ELEM_SELECT);
+ }
+ }
+ else {
+ MLoopUV *luv = BM_ELEM_CD_GET_VOID_P(l, cd_loop_uv_offset);
+ return (luv->flag & MLOOPUV_VERTSEL) != 0;
+ }
+}
+bool uvedit_uv_select_test(const Scene *scene, BMLoop *l, const int cd_loop_uv_offset)
+{
+ return uvedit_uv_select_test_ex(scene->toolsettings, l, cd_loop_uv_offset);
+}
+
+void uvedit_uv_select_set(BMEditMesh *em,
+ const Scene *scene,
+ BMLoop *l,
+ const bool select,
+ const bool do_history,
+ const int cd_loop_uv_offset)
+{
+ if (select) {
+ uvedit_uv_select_enable(em, scene, l, do_history, cd_loop_uv_offset);
+ }
+ else {
+ uvedit_uv_select_disable(em, scene, l, cd_loop_uv_offset);
+ }
+}
+
+void uvedit_uv_select_enable(BMEditMesh *em,
+ const Scene *scene,
+ BMLoop *l,
+ const bool do_history,
+ const int cd_loop_uv_offset)
+{
+ const ToolSettings *ts = scene->toolsettings;
+
+ if (ts->uv_flag & UV_SYNC_SELECTION) {
+ if (ts->selectmode & SCE_SELECT_FACE) {
+ BM_face_select_set(em->bm, l->f, true);
+ }
+ else {
+ BM_vert_select_set(em->bm, l->v, true);
+ }
+
+ if (do_history) {
+ BM_select_history_remove(em->bm, (BMElem *)l->v);
+ }
+ }
+ else {
+ MLoopUV *luv = BM_ELEM_CD_GET_VOID_P(l, cd_loop_uv_offset);
+ luv->flag |= MLOOPUV_VERTSEL;
+ }
+}
+
+void uvedit_uv_select_disable(BMEditMesh *em,
+ const Scene *scene,
+ BMLoop *l,
+ const int cd_loop_uv_offset)
+{
+ const ToolSettings *ts = scene->toolsettings;
+
+ if (ts->uv_flag & UV_SYNC_SELECTION) {
+ if (ts->selectmode & SCE_SELECT_FACE) {
+ BM_face_select_set(em->bm, l->f, false);
+ }
+ else {
+ BM_vert_select_set(em->bm, l->v, false);
+ }
+ }
+ else {
+ MLoopUV *luv = BM_ELEM_CD_GET_VOID_P(l, cd_loop_uv_offset);
+ luv->flag &= ~MLOOPUV_VERTSEL;
+ }
+}
+
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Find Nearest Elements
+ * \{ */
+
+bool uv_find_nearest_edge(Scene *scene, Object *obedit, const float co[2], UvNearestHit *hit)
+{
+ BMEditMesh *em = BKE_editmesh_from_object(obedit);
+ BMFace *efa;
+ BMLoop *l;
+ BMIter iter, liter;
+ MLoopUV *luv, *luv_next;
+ int i;
+ bool found = false;
+
+ const int cd_loop_uv_offset = CustomData_get_offset(&em->bm->ldata, CD_MLOOPUV);
+
+ BM_mesh_elem_index_ensure(em->bm, BM_VERT);
+
+ BM_ITER_MESH (efa, &iter, em->bm, BM_FACES_OF_MESH) {
+ if (!uvedit_face_visible_test(scene, efa)) {
+ continue;
+ }
+ BM_ITER_ELEM_INDEX (l, &liter, efa, BM_LOOPS_OF_FACE, i) {
+ luv = BM_ELEM_CD_GET_VOID_P(l, cd_loop_uv_offset);
+ luv_next = BM_ELEM_CD_GET_VOID_P(l->next, cd_loop_uv_offset);
+
+ const float dist_test_sq = dist_squared_to_line_segment_v2(co, luv->uv, luv_next->uv);
+
+ if (dist_test_sq < hit->dist_sq) {
+ hit->efa = efa;
+
+ hit->l = l;
+ hit->luv = luv;
+ hit->luv_next = luv_next;
+ hit->lindex = i;
+
+ hit->dist_sq = dist_test_sq;
+ found = true;
+ }
+ }
+ }
+ return found;
+}
+
+bool uv_find_nearest_edge_multi(Scene *scene,
+ Object **objects,
+ const uint objects_len,
+ const float co[2],
+ UvNearestHit *hit_final)
+{
+ bool found = false;
+ for (uint ob_index = 0; ob_index < objects_len; ob_index++) {
+ Object *obedit = objects[ob_index];
+ if (uv_find_nearest_edge(scene, obedit, co, hit_final)) {
+ hit_final->ob = obedit;
+ found = true;
+ }
+ }
+ return found;
+}
+
+bool uv_find_nearest_face(Scene *scene, Object *obedit, const float co[2], UvNearestHit *hit_final)
+{
+ BMEditMesh *em = BKE_editmesh_from_object(obedit);
+ bool found = false;
+
+ const int cd_loop_uv_offset = CustomData_get_offset(&em->bm->ldata, CD_MLOOPUV);
+
+ /* this will fill in hit.vert1 and hit.vert2 */
+ float dist_sq_init = hit_final->dist_sq;
+ UvNearestHit hit = *hit_final;
+ if (uv_find_nearest_edge(scene, obedit, co, &hit)) {
+ hit.dist_sq = dist_sq_init;
+ hit.l = NULL;
+ hit.luv = hit.luv_next = NULL;
+
+ BMIter iter;
+ BMFace *efa;
+
+ BM_ITER_MESH (efa, &iter, em->bm, BM_FACES_OF_MESH) {
+ if (!uvedit_face_visible_test(scene, efa)) {
+ continue;
+ }
+
+ float cent[2];
+ uv_poly_center(efa, cent, cd_loop_uv_offset);
+
+ const float dist_test_sq = len_squared_v2v2(co, cent);
+
+ if (dist_test_sq < hit.dist_sq) {
+ hit.efa = efa;
+ hit.dist_sq = dist_test_sq;
+ found = true;
+ }
+ }
+ }
+ if (found) {
+ *hit_final = hit;
+ }
+ return found;
+}
+
+bool uv_find_nearest_face_multi(Scene *scene,
+ Object **objects,
+ const uint objects_len,
+ const float co[2],
+ UvNearestHit *hit_final)
+{
+ bool found = false;
+ for (uint ob_index = 0; ob_index < objects_len; ob_index++) {
+ Object *obedit = objects[ob_index];
+ if (uv_find_nearest_face(scene, obedit, co, hit_final)) {
+ hit_final->ob = obedit;
+ found = true;
+ }
+ }
+ return found;
+}
+
+static bool uv_nearest_between(const BMLoop *l, const float co[2], const int cd_loop_uv_offset)
+{
+ const float *uv_prev = ((MLoopUV *)BM_ELEM_CD_GET_VOID_P(l->prev, cd_loop_uv_offset))->uv;
+ const float *uv_curr = ((MLoopUV *)BM_ELEM_CD_GET_VOID_P(l, cd_loop_uv_offset))->uv;
+ const float *uv_next = ((MLoopUV *)BM_ELEM_CD_GET_VOID_P(l->next, cd_loop_uv_offset))->uv;
+
+ return ((line_point_side_v2(uv_prev, uv_curr, co) > 0.0f) &&
+ (line_point_side_v2(uv_next, uv_curr, co) <= 0.0f));
+}
+
+bool uv_find_nearest_vert(Scene *scene,
+ Object *obedit,
+ float const co[2],
+ const float penalty_dist,
+ UvNearestHit *hit_final)
+{
+ bool found = false;
+
+ /* this will fill in hit.vert1 and hit.vert2 */
+ float dist_sq_init = hit_final->dist_sq;
+ UvNearestHit hit = *hit_final;
+ if (uv_find_nearest_edge(scene, obedit, co, &hit)) {
+ hit.dist_sq = dist_sq_init;
+
+ hit.l = NULL;
+ hit.luv = hit.luv_next = NULL;
+
+ BMEditMesh *em = BKE_editmesh_from_object(obedit);
+ BMFace *efa;
+ BMIter iter;
+
+ BM_mesh_elem_index_ensure(em->bm, BM_VERT);
+
+ const int cd_loop_uv_offset = CustomData_get_offset(&em->bm->ldata, CD_MLOOPUV);
+
+ BM_ITER_MESH (efa, &iter, em->bm, BM_FACES_OF_MESH) {
+ if (!uvedit_face_visible_test(scene, efa)) {
+ continue;
+ }
+
+ BMIter liter;
+ BMLoop *l;
+ int i;
+ BM_ITER_ELEM_INDEX (l, &liter, efa, BM_LOOPS_OF_FACE, i) {
+ float dist_test_sq;
+ MLoopUV *luv = BM_ELEM_CD_GET_VOID_P(l, cd_loop_uv_offset);
+ if (penalty_dist != 0.0f && uvedit_uv_select_test(scene, l, cd_loop_uv_offset)) {
+ dist_test_sq = len_v2v2(co, luv->uv) + penalty_dist;
+ dist_test_sq = square_f(dist_test_sq);
+ }
+ else {
+ dist_test_sq = len_squared_v2v2(co, luv->uv);
+ }
+
+ if (dist_test_sq <= hit.dist_sq) {
+ if (dist_test_sq == hit.dist_sq) {
+ if (!uv_nearest_between(l, co, cd_loop_uv_offset)) {
+ continue;
+ }
+ }
+
+ hit.dist_sq = dist_test_sq;
+
+ hit.l = l;
+ hit.luv = luv;
+ hit.luv_next = BM_ELEM_CD_GET_VOID_P(l->next, cd_loop_uv_offset);
+ hit.efa = efa;
+ hit.lindex = i;
+ found = true;
+ }
+ }
+ }
+ }
+
+ if (found) {
+ *hit_final = hit;
+ }
+
+ return found;
+}
+
+bool uv_find_nearest_vert_multi(Scene *scene,
+ Object **objects,
+ const uint objects_len,
+ float const co[2],
+ const float penalty_dist,
+ UvNearestHit *hit_final)
+{
+ bool found = false;
+ for (uint ob_index = 0; ob_index < objects_len; ob_index++) {
+ Object *obedit = objects[ob_index];
+ if (uv_find_nearest_vert(scene, obedit, co, penalty_dist, hit_final)) {
+ hit_final->ob = obedit;
+ found = true;
+ }
+ }
+ return found;
+}
+
+bool ED_uvedit_nearest_uv(
+ const Scene *scene, Object *obedit, const float co[2], float *dist_sq, float r_uv[2])
+{
+ BMEditMesh *em = BKE_editmesh_from_object(obedit);
+ BMIter iter;
+ BMFace *efa;
+ const float *uv_best = NULL;
+ float dist_best = *dist_sq;
+ const int cd_loop_uv_offset = CustomData_get_offset(&em->bm->ldata, CD_MLOOPUV);
+ BM_ITER_MESH (efa, &iter, em->bm, BM_FACES_OF_MESH) {
+ if (!uvedit_face_visible_test(scene, efa)) {
+ continue;
+ }
+ BMLoop *l_iter, *l_first;
+ l_iter = l_first = BM_FACE_FIRST_LOOP(efa);
+ do {
+ const float *uv = ((const MLoopUV *)BM_ELEM_CD_GET_VOID_P(l_iter, cd_loop_uv_offset))->uv;
+ const float dist_test = len_squared_v2v2(co, uv);
+ if (dist_best > dist_test) {
+ dist_best = dist_test;
+ uv_best = uv;
+ }
+ } while ((l_iter = l_iter->next) != l_first);
+ }
+
+ if (uv_best != NULL) {
+ copy_v2_v2(r_uv, uv_best);
+ *dist_sq = dist_best;
+ return true;
+ }
+ else {
+ return false;
+ }
+}
+
+bool ED_uvedit_nearest_uv_multi(const Scene *scene,
+ Object **objects,
+ const uint objects_len,
+ const float co[2],
+ float *dist_sq,
+ float r_uv[2])
+{
+ bool found = false;
+ for (uint ob_index = 0; ob_index < objects_len; ob_index++) {
+ Object *obedit = objects[ob_index];
+ if (ED_uvedit_nearest_uv(scene, obedit, co, dist_sq, r_uv)) {
+ found = true;
+ }
+ }
+ return found;
+}
+
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Loop Select
+ * \{ */
+
+static void uv_select_edgeloop_vertex_loop_flag(UvMapVert *first)
+{
+ UvMapVert *iterv;
+ int count = 0;
+
+ for (iterv = first; iterv; iterv = iterv->next) {
+ if (iterv->separate && iterv != first) {
+ break;
+ }
+
+ count++;
+ }
+
+ if (count < 5) {
+ first->flag = 1;
+ }
+}
+
+static UvMapVert *uv_select_edgeloop_vertex_map_get(UvVertMap *vmap, BMFace *efa, BMLoop *l)
+{
+ UvMapVert *iterv, *first;
+ first = BM_uv_vert_map_at_index(vmap, BM_elem_index_get(l->v));
+
+ for (iterv = first; iterv; iterv = iterv->next) {
+ if (iterv->separate) {
+ first = iterv;
+ }
+ if (iterv->poly_index == BM_elem_index_get(efa)) {
+ return first;
+ }
+ }
+
+ return NULL;
+}
+
+static bool uv_select_edgeloop_edge_tag_faces(BMEditMesh *em,
+ UvMapVert *first1,
+ UvMapVert *first2,
+ int *totface)
+{
+ UvMapVert *iterv1, *iterv2;
+ BMFace *efa;
+ int tot = 0;
+
+ /* count number of faces this edge has */
+ for (iterv1 = first1; iterv1; iterv1 = iterv1->next) {
+ if (iterv1->separate && iterv1 != first1) {
+ break;
+ }
+
+ for (iterv2 = first2; iterv2; iterv2 = iterv2->next) {
+ if (iterv2->separate && iterv2 != first2) {
+ break;
+ }
+
+ if (iterv1->poly_index == iterv2->poly_index) {
+ /* if face already tagged, don't do this edge */
+ efa = BM_face_at_index(em->bm, iterv1->poly_index);
+ if (BM_elem_flag_test(efa, BM_ELEM_TAG)) {
+ return false;
+ }
+
+ tot++;
+ break;
+ }
+ }
+ }
+
+ if (*totface == 0) { /* start edge */
+ *totface = tot;
+ }
+ else if (tot != *totface) { /* check for same number of faces as start edge */
+ return false;
+ }
+
+ /* tag the faces */
+ for (iterv1 = first1; iterv1; iterv1 = iterv1->next) {
+ if (iterv1->separate && iterv1 != first1) {
+ break;
+ }
+
+ for (iterv2 = first2; iterv2; iterv2 = iterv2->next) {
+ if (iterv2->separate && iterv2 != first2) {
+ break;
+ }
+
+ if (iterv1->poly_index == iterv2->poly_index) {
+ efa = BM_face_at_index(em->bm, iterv1->poly_index);
+ BM_elem_flag_enable(efa, BM_ELEM_TAG);
+ break;
+ }
+ }
+ }
+
+ return true;
+}
+
+static int uv_select_edgeloop(
+ Scene *scene, Object *obedit, UvNearestHit *hit, const float limit[2], const bool extend)
+{
+ BMEditMesh *em = BKE_editmesh_from_object(obedit);
+ BMFace *efa;
+ BMIter iter, liter;
+ BMLoop *l;
+ UvVertMap *vmap;
+ UvMapVert *iterv_curr;
+ UvMapVert *iterv_next;
+ int starttotf;
+ bool looking, select;
+
+ const int cd_loop_uv_offset = CustomData_get_offset(&em->bm->ldata, CD_MLOOPUV);
+
+ /* setup */
+ BM_mesh_elem_table_ensure(em->bm, BM_FACE);
+ vmap = BM_uv_vert_map_create(em->bm, limit, false, false);
+
+ BM_mesh_elem_index_ensure(em->bm, BM_VERT | BM_FACE);
+
+ if (!extend) {
+ uv_select_all_perform(scene, obedit, SEL_DESELECT);
+ }
+
+ BM_mesh_elem_hflag_disable_all(em->bm, BM_FACE, BM_ELEM_TAG, false);
+
+ /* set flags for first face and verts */
+ iterv_curr = uv_select_edgeloop_vertex_map_get(vmap, hit->efa, hit->l);
+ iterv_next = uv_select_edgeloop_vertex_map_get(vmap, hit->efa, hit->l->next);
+ uv_select_edgeloop_vertex_loop_flag(iterv_curr);
+ uv_select_edgeloop_vertex_loop_flag(iterv_next);
+
+ starttotf = 0;
+ uv_select_edgeloop_edge_tag_faces(em, iterv_curr, iterv_next, &starttotf);
+
+ /* sorry, first edge isn't even ok */
+ looking = !(iterv_curr->flag == 0 && iterv_next->flag == 0);
+
+ /* iterate */
+ while (looking) {
+ looking = false;
+
+ /* find correct valence edges which are not tagged yet, but connect to tagged one */
+
+ BM_ITER_MESH (efa, &iter, em->bm, BM_FACES_OF_MESH) {
+ if (!BM_elem_flag_test(efa, BM_ELEM_TAG) && uvedit_face_visible_test(scene, efa)) {
+ BM_ITER_ELEM (l, &liter, efa, BM_LOOPS_OF_FACE) {
+ /* check face not hidden and not tagged */
+ if (!(iterv_curr = uv_select_edgeloop_vertex_map_get(vmap, efa, l))) {
+ continue;
+ }
+ if (!(iterv_next = uv_select_edgeloop_vertex_map_get(vmap, efa, l->next))) {
+ continue;
+ }
+
+ /* check if vertex is tagged and has right valence */
+ if (iterv_curr->flag || iterv_next->flag) {
+ if (uv_select_edgeloop_edge_tag_faces(em, iterv_curr, iterv_next, &starttotf)) {
+ looking = true;
+ BM_elem_flag_enable(efa, BM_ELEM_TAG);
+
+ uv_select_edgeloop_vertex_loop_flag(iterv_curr);
+ uv_select_edgeloop_vertex_loop_flag(iterv_next);
+ break;
+ }
+ }
+ }
+ }
+ }
+ }
+
+ /* do the actual select/deselect */
+ iterv_curr = uv_select_edgeloop_vertex_map_get(vmap, hit->efa, hit->l);
+ iterv_next = uv_select_edgeloop_vertex_map_get(vmap, hit->efa, hit->l->next);
+ iterv_curr->flag = 1;
+ iterv_next->flag = 1;
+
+ if (extend) {
+ select = !(uvedit_uv_select_test(scene, hit->l, cd_loop_uv_offset));
+ }
+ else {
+ select = true;
+ }
+
+ BM_ITER_MESH (efa, &iter, em->bm, BM_FACES_OF_MESH) {
+ BM_ITER_ELEM (l, &liter, efa, BM_LOOPS_OF_FACE) {
+ iterv_curr = uv_select_edgeloop_vertex_map_get(vmap, efa, l);
+
+ if (iterv_curr->flag) {
+ uvedit_uv_select_set(em, scene, l, select, false, cd_loop_uv_offset);
+ }
+ }
+ }
+
+ /* cleanup */
+ BM_uv_vert_map_free(vmap);
+
+ return (select) ? 1 : -1;
+}
+
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Select Linked
+ * \{ */
+
+static void uv_select_linked_multi(Scene *scene,
+ Object **objects,
+ const uint objects_len,
+ const float limit[2],
+ UvNearestHit *hit_final,
+ bool extend,
+ bool deselect,
+ bool toggle,
+ bool select_faces)
+{
+ /* loop over objects, or just use hit_final->ob */
+ for (uint ob_index = 0; ob_index < objects_len; ob_index++) {
+ if (hit_final && ob_index != 0) {
+ break;
+ }
+ Object *obedit = hit_final ? hit_final->ob : objects[ob_index];
+
+ BMFace *efa;
+ BMLoop *l;
+ BMIter iter, liter;
+ MLoopUV *luv;
+ UvVertMap *vmap;
+ UvMapVert *vlist, *iterv, *startv;
+ int i, stacksize = 0, *stack;
+ uint a;
+ char *flag;
+
+ BMEditMesh *em = BKE_editmesh_from_object(obedit);
+ const int cd_loop_uv_offset = CustomData_get_offset(&em->bm->ldata, CD_MLOOPUV);
+
+ BM_mesh_elem_table_ensure(em->bm, BM_FACE); /* we can use this too */
+
+ /* Note, we had 'use winding' so we don't consider overlapping islands as connected, see T44320
+ * this made *every* projection split the island into front/back islands.
+ * Keep 'use_winding' to false, see: T50970.
+ *
+ * Better solve this by having a delimit option for select-linked operator,
+ * keeping island-select working as is. */
+ vmap = BM_uv_vert_map_create(em->bm, limit, !select_faces, false);
+
+ if (vmap == NULL) {
+ continue;
+ }
+
+ stack = MEM_mallocN(sizeof(*stack) * (em->bm->totface + 1), "UvLinkStack");
+ flag = MEM_callocN(sizeof(*flag) * em->bm->totface, "UvLinkFlag");
+
+ if (hit_final == NULL) {
+ /* Use existing selection */
+ BM_ITER_MESH_INDEX (efa, &iter, em->bm, BM_FACES_OF_MESH, a) {
+ if (uvedit_face_visible_test(scene, efa)) {
+ if (select_faces) {
+ if (BM_elem_flag_test(efa, BM_ELEM_SELECT)) {
+ stack[stacksize] = a;
+ stacksize++;
+ flag[a] = 1;
+ }
+ }
+ else {
+ BM_ITER_ELEM (l, &liter, efa, BM_LOOPS_OF_FACE) {
+ luv = BM_ELEM_CD_GET_VOID_P(l, cd_loop_uv_offset);
+
+ if (luv->flag & MLOOPUV_VERTSEL) {
+ stack[stacksize] = a;
+ stacksize++;
+ flag[a] = 1;
+
+ break;
+ }
+ }
+ }
+ }
+ }
+ }
+ else {
+ BM_ITER_MESH_INDEX (efa, &iter, em->bm, BM_FACES_OF_MESH, a) {
+ if (efa == hit_final->efa) {
+ stack[stacksize] = a;
+ stacksize++;
+ flag[a] = 1;
+ break;
+ }
+ }
+ }
+
+ while (stacksize > 0) {
+
+ stacksize--;
+ a = stack[stacksize];
+
+ efa = BM_face_at_index(em->bm, a);
+
+ BM_ITER_ELEM_INDEX (l, &liter, efa, BM_LOOPS_OF_FACE, i) {
+
+ /* make_uv_vert_map_EM sets verts tmp.l to the indices */
+ vlist = BM_uv_vert_map_at_index(vmap, BM_elem_index_get(l->v));
+
+ startv = vlist;
+
+ for (iterv = vlist; iterv; iterv = iterv->next) {
+ if (iterv->separate) {
+ startv = iterv;
+ }
+ if (iterv->poly_index == a) {
+ break;
+ }
+ }
+
+ for (iterv = startv; iterv; iterv = iterv->next) {
+ if ((startv != iterv) && (iterv->separate)) {
+ break;
+ }
+ else if (!flag[iterv->poly_index]) {
+ flag[iterv->poly_index] = 1;
+ stack[stacksize] = iterv->poly_index;
+ stacksize++;
+ }
+ }
+ }
+ }
+
+ /* Toggling - if any of the linked vertices is selected (and visible), we deselect. */
+ if ((toggle == true) && (extend == false) && (deselect == false)) {
+ BM_ITER_MESH_INDEX (efa, &iter, em->bm, BM_FACES_OF_MESH, a) {
+ bool found_selected = false;
+ if (!flag[a]) {
+ continue;
+ }
+
+ if (select_faces) {
+ if (BM_elem_flag_test(efa, BM_ELEM_SELECT) && !BM_elem_flag_test(efa, BM_ELEM_HIDDEN)) {
+ found_selected = true;
+ }
+ }
+ else {
+ BM_ITER_ELEM (l, &liter, efa, BM_LOOPS_OF_FACE) {
+ luv = BM_ELEM_CD_GET_VOID_P(l, cd_loop_uv_offset);
+
+ if (luv->flag & MLOOPUV_VERTSEL) {
+ found_selected = true;
+ }
+ }
+
+ if (found_selected) {
+ deselect = true;
+ break;
+ }
+ }
+ }
+ }
+
+#define SET_SELECTION(value) \
+ if (select_faces) { \
+ BM_face_select_set(em->bm, efa, value); \
+ } \
+ else { \
+ BM_ITER_ELEM (l, &liter, efa, BM_LOOPS_OF_FACE) { \
+ luv = BM_ELEM_CD_GET_VOID_P(l, cd_loop_uv_offset); \
+ luv->flag = (value) ? (luv->flag | MLOOPUV_VERTSEL) : (luv->flag & ~MLOOPUV_VERTSEL); \
+ } \
+ } \
+ (void)0
+
+ BM_ITER_MESH_INDEX (efa, &iter, em->bm, BM_FACES_OF_MESH, a) {
+ if (!flag[a]) {
+ if (!extend && !deselect && !toggle) {
+ SET_SELECTION(false);
+ }
+ continue;
+ }
+
+ if (!deselect) {
+ SET_SELECTION(true);
+ }
+ else {
+ SET_SELECTION(false);
+ }
+ }
+
+#undef SET_SELECTION
+
+ MEM_freeN(stack);
+ MEM_freeN(flag);
+ BM_uv_vert_map_free(vmap);
+ }
+}
+
+/**
+ * \warning This returns first selected UV,
+ * not ideal in many cases since there could be multiple.
+ */
+const float *uvedit_first_selected_uv_from_vertex(Scene *scene,
+ BMVert *eve,
+ const int cd_loop_uv_offset)
+{
+ BMIter liter;
+ BMLoop *l;
+
+ BM_ITER_ELEM (l, &liter, eve, BM_LOOPS_OF_VERT) {
+ if (!uvedit_face_visible_test(scene, l->f)) {
+ continue;
+ }
+
+ if (uvedit_uv_select_test(scene, l, cd_loop_uv_offset)) {
+ MLoopUV *luv = BM_ELEM_CD_GET_VOID_P(l, cd_loop_uv_offset);
+ return luv->uv;
+ }
+ }
+
+ return NULL;
+}
+
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Select More/Less Operator
+ * \{ */
+
+static int uv_select_more_less(bContext *C, const bool select)
+{
+ Scene *scene = CTX_data_scene(C);
+ ViewLayer *view_layer = CTX_data_view_layer(C);
+ SpaceImage *sima = CTX_wm_space_image(C);
+
+ BMFace *efa;
+ BMLoop *l;
+ BMIter iter, liter;
+ const ToolSettings *ts = scene->toolsettings;
+
+ uint objects_len = 0;
+ Object **objects = BKE_view_layer_array_from_objects_in_edit_mode_unique_data_with_uvs(
+ view_layer, ((View3D *)NULL), &objects_len);
+
+ const bool is_uv_face_selectmode = (ts->uv_selectmode == UV_SELECT_FACE);
+
+ for (uint ob_index = 0; ob_index < objects_len; ob_index++) {
+ Object *obedit = objects[ob_index];
+ BMEditMesh *em = BKE_editmesh_from_object(obedit);
+
+ bool changed = false;
+
+ const int cd_loop_uv_offset = CustomData_get_offset(&em->bm->ldata, CD_MLOOPUV);
+
+ if (ts->uv_flag & UV_SYNC_SELECTION) {
+ if (select) {
+ EDBM_select_more(em, true);
+ }
+ else {
+ EDBM_select_less(em, true);
+ }
+
+ DEG_id_tag_update(obedit->data, ID_RECALC_SELECT);
+ WM_event_add_notifier(C, NC_GEOM | ND_SELECT, obedit->data);
+ continue;
+ }
+
+ if (is_uv_face_selectmode) {
+
+ /* clear tags */
+ BM_mesh_elem_hflag_disable_all(em->bm, BM_FACE, BM_ELEM_TAG, false);
+
+ /* mark loops to be selected */
+ BM_ITER_MESH (efa, &iter, em->bm, BM_FACES_OF_MESH) {
+ if (uvedit_face_visible_test(scene, efa)) {
+
+#define IS_SEL 1
+#define IS_UNSEL 2
+
+ int sel_state = 0;
+
+ BM_ITER_ELEM (l, &liter, efa, BM_LOOPS_OF_FACE) {
+ MLoopUV *luv = BM_ELEM_CD_GET_VOID_P(l, cd_loop_uv_offset);
+ if (luv->flag & MLOOPUV_VERTSEL) {
+ sel_state |= IS_SEL;
+ }
+ else {
+ sel_state |= IS_UNSEL;
+ }
+
+ /* if we have a mixed selection, tag to grow it */
+ if (sel_state == (IS_SEL | IS_UNSEL)) {
+ BM_elem_flag_enable(efa, BM_ELEM_TAG);
+ changed = true;
+ break;
+ }
+ }
+
+#undef IS_SEL
+#undef IS_UNSEL
+ }
+ }
+ }
+ else {
+
+ /* clear tags */
+ BM_ITER_MESH (efa, &iter, em->bm, BM_FACES_OF_MESH) {
+ BM_ITER_ELEM (l, &liter, efa, BM_LOOPS_OF_FACE) {
+ BM_elem_flag_disable(l, BM_ELEM_TAG);
+ }
+ }
+
+ /* mark loops to be selected */
+ BM_ITER_MESH (efa, &iter, em->bm, BM_FACES_OF_MESH) {
+ if (uvedit_face_visible_test(scene, efa)) {
+ BM_ITER_ELEM (l, &liter, efa, BM_LOOPS_OF_FACE) {
+
+ MLoopUV *luv = BM_ELEM_CD_GET_VOID_P(l, cd_loop_uv_offset);
+
+ if (((luv->flag & MLOOPUV_VERTSEL) != 0) == select) {
+ BM_elem_flag_enable(l->next, BM_ELEM_TAG);
+ BM_elem_flag_enable(l->prev, BM_ELEM_TAG);
+ changed = true;
+ }
+ }
+ }
+ }
+ }
+
+ if (changed) {
+ if (is_uv_face_selectmode) {
+ /* Select tagged faces. */
+ uv_select_flush_from_tag_face(sima, scene, obedit, select);
+ }
+ else {
+ /* Select tagged loops. */
+ uv_select_flush_from_tag_loop(sima, scene, obedit, select);
+ }
+ DEG_id_tag_update(obedit->data, ID_RECALC_SELECT);
+ WM_event_add_notifier(C, NC_GEOM | ND_SELECT, obedit->data);
+ }
+ }
+ MEM_freeN(objects);
+
+ return OPERATOR_FINISHED;
+}
+
+static int uv_select_more_exec(bContext *C, wmOperator *UNUSED(op))
+{
+ return uv_select_more_less(C, true);
+}
+
+void UV_OT_select_more(wmOperatorType *ot)
+{
+ /* identifiers */
+ ot->name = "Select More";
+ ot->description = "Select more UV vertices connected to initial selection";
+ ot->idname = "UV_OT_select_more";
+ ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
+
+ /* api callbacks */
+ ot->exec = uv_select_more_exec;
+ ot->poll = ED_operator_uvedit_space_image;
+}
+
+static int uv_select_less_exec(bContext *C, wmOperator *UNUSED(op))
+{
+ return uv_select_more_less(C, false);
+}
+
+void UV_OT_select_less(wmOperatorType *ot)
+{
+ /* identifiers */
+ ot->name = "Select Less";
+ ot->description = "Deselect UV vertices at the boundary of each selection region";
+ ot->idname = "UV_OT_select_less";
+ ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
+
+ /* api callbacks */
+ ot->exec = uv_select_less_exec;
+ ot->poll = ED_operator_uvedit_space_image;
+}
+
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name (De)Select All Operator
+ * \{ */
+
+bool uvedit_select_is_any_selected(Scene *scene, Object *obedit)
+{
+ const ToolSettings *ts = scene->toolsettings;
+ BMEditMesh *em = BKE_editmesh_from_object(obedit);
+ BMFace *efa;
+ BMLoop *l;
+ BMIter iter, liter;
+ MLoopUV *luv;
+
+ if (ts->uv_flag & UV_SYNC_SELECTION) {
+ return (em->bm->totvertsel || em->bm->totedgesel || em->bm->totfacesel);
+ }
+ else {
+ const int cd_loop_uv_offset = CustomData_get_offset(&em->bm->ldata, CD_MLOOPUV);
+ BM_ITER_MESH (efa, &iter, em->bm, BM_FACES_OF_MESH) {
+ if (!uvedit_face_visible_test(scene, efa)) {
+ continue;
+ }
+ BM_ITER_ELEM (l, &liter, efa, BM_LOOPS_OF_FACE) {
+ luv = BM_ELEM_CD_GET_VOID_P(l, cd_loop_uv_offset);
+ if (luv->flag & MLOOPUV_VERTSEL) {
+ return true;
+ }
+ }
+ }
+ }
+ return false;
+}
+
+bool uvedit_select_is_any_selected_multi(Scene *scene, Object **objects, const uint objects_len)
+{
+ bool found = false;
+ for (uint ob_index = 0; ob_index < objects_len; ob_index++) {
+ Object *obedit = objects[ob_index];
+ if (uvedit_select_is_any_selected(scene, obedit)) {
+ found = true;
+ break;
+ }
+ }
+ return found;
+}
+
+static void uv_select_all_perform(Scene *scene, Object *obedit, int action)
+{
+ const ToolSettings *ts = scene->toolsettings;
+ BMEditMesh *em = BKE_editmesh_from_object(obedit);
+ BMFace *efa;
+ BMLoop *l;
+ BMIter iter, liter;
+ MLoopUV *luv;
+
+ const int cd_loop_uv_offset = CustomData_get_offset(&em->bm->ldata, CD_MLOOPUV);
+
+ if (action == SEL_TOGGLE) {
+ action = uvedit_select_is_any_selected(scene, obedit) ? SEL_DESELECT : SEL_SELECT;
+ }
+
+ if (ts->uv_flag & UV_SYNC_SELECTION) {
+ switch (action) {
+ case SEL_TOGGLE:
+ EDBM_select_toggle_all(em);
+ break;
+ case SEL_SELECT:
+ EDBM_flag_enable_all(em, BM_ELEM_SELECT);
+ break;
+ case SEL_DESELECT:
+ EDBM_flag_disable_all(em, BM_ELEM_SELECT);
+ break;
+ case SEL_INVERT:
+ EDBM_select_swap(em);
+ EDBM_selectmode_flush(em);
+ break;
+ }
+ }
+ else {
+ BM_ITER_MESH (efa, &iter, em->bm, BM_FACES_OF_MESH) {
+ if (!uvedit_face_visible_test(scene, efa)) {
+ continue;
+ }
+
+ BM_ITER_ELEM (l, &liter, efa, BM_LOOPS_OF_FACE) {
+ luv = BM_ELEM_CD_GET_VOID_P(l, cd_loop_uv_offset);
+
+ switch (action) {
+ case SEL_SELECT:
+ luv->flag |= MLOOPUV_VERTSEL;
+ break;
+ case SEL_DESELECT:
+ luv->flag &= ~MLOOPUV_VERTSEL;
+ break;
+ case SEL_INVERT:
+ luv->flag ^= MLOOPUV_VERTSEL;
+ break;
+ }
+ }
+ }
+ }
+}
+
+static void uv_select_all_perform_multi(Scene *scene,
+ Object **objects,
+ const uint objects_len,
+ int action)
+{
+ if (action == SEL_TOGGLE) {
+ action = uvedit_select_is_any_selected_multi(scene, objects, objects_len) ? SEL_DESELECT :
+ SEL_SELECT;
+ }
+
+ for (uint ob_index = 0; ob_index < objects_len; ob_index++) {
+ Object *obedit = objects[ob_index];
+ uv_select_all_perform(scene, obedit, action);
+ }
+}
+
+static int uv_select_all_exec(bContext *C, wmOperator *op)
+{
+ Depsgraph *depsgraph = CTX_data_ensure_evaluated_depsgraph(C);
+ Scene *scene = CTX_data_scene(C);
+ const ToolSettings *ts = scene->toolsettings;
+ ViewLayer *view_layer = CTX_data_view_layer(C);
+
+ int action = RNA_enum_get(op->ptr, "action");
+
+ uint objects_len = 0;
+ Object **objects = BKE_view_layer_array_from_objects_in_edit_mode_unique_data_with_uvs(
+ view_layer, ((View3D *)NULL), &objects_len);
+
+ uv_select_all_perform_multi(scene, objects, objects_len, action);
+
+ for (uint ob_index = 0; ob_index < objects_len; ob_index++) {
+ Object *obedit = objects[ob_index];
+ uv_select_tag_update_for_object(depsgraph, ts, obedit);
+ }
+
+ MEM_freeN(objects);
+
+ return OPERATOR_FINISHED;
+}
+
+void UV_OT_select_all(wmOperatorType *ot)
+{
+ /* identifiers */
+ ot->name = "(De)select All";
+ ot->description = "Change selection of all UV vertices";
+ ot->idname = "UV_OT_select_all";
+ ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
+
+ /* api callbacks */
+ ot->exec = uv_select_all_exec;
+ ot->poll = ED_operator_uvedit;
+
+ WM_operator_properties_select_all(ot);
+}
+
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Mouse Select Operator
+ * \{ */
+
+static bool uv_sticky_select(
+ float *limit, int hitv[], int v, float *hituv[], float *uv, int sticky, int hitlen)
+{
+ int i;
+
+ /* this function test if some vertex needs to selected
+ * in addition to the existing ones due to sticky select */
+ if (sticky == SI_STICKY_DISABLE) {
+ return false;
+ }
+
+ for (i = 0; i < hitlen; i++) {
+ if (hitv[i] == v) {
+ if (sticky == SI_STICKY_LOC) {
+ if (fabsf(hituv[i][0] - uv[0]) < limit[0] && fabsf(hituv[i][1] - uv[1]) < limit[1]) {
+ return true;
+ }
+ }
+ else if (sticky == SI_STICKY_VERTEX) {
+ return true;
+ }
+ }
+ }
+
+ return false;
+}
+
+static int uv_mouse_select_multi(bContext *C,
+ Object **objects,
+ uint objects_len,
+ const float co[2],
+ const bool extend,
+ const bool deselect_all,
+ const bool loop)
+{
+ Depsgraph *depsgraph = CTX_data_ensure_evaluated_depsgraph(C);
+ SpaceImage *sima = CTX_wm_space_image(C);
+ Scene *scene = CTX_data_scene(C);
+ const ToolSettings *ts = scene->toolsettings;
+ BMFace *efa;
+ BMLoop *l;
+ BMIter iter, liter;
+ MLoopUV *luv;
+ UvNearestHit hit = UV_NEAREST_HIT_INIT;
+ int i, selectmode, sticky, sync, *hitv = NULL;
+ bool select = true;
+ bool found_item = false;
+ /* 0 == don't flush, 1 == sel, -1 == desel; only use when selection sync is enabled */
+ int flush = 0;
+ int hitlen = 0;
+ float limit[2], **hituv = NULL;
+
+ /* notice 'limit' is the same no matter the zoom level, since this is like
+ * remove doubles and could annoying if it joined points when zoomed out.
+ * 'penalty' is in screen pixel space otherwise zooming in on a uv-vert and
+ * shift-selecting can consider an adjacent point close enough to add to
+ * the selection rather than de-selecting the closest. */
+
+ float penalty_dist;
+ {
+ float penalty[2];
+ uvedit_pixel_to_float(sima, 0.05f, limit);
+ uvedit_pixel_to_float(sima, 5.0f / (sima ? sima->zoom : 1.0f), penalty);
+ penalty_dist = len_v2(penalty);
+ }
+
+ /* retrieve operation mode */
+ if (ts->uv_flag & UV_SYNC_SELECTION) {
+ sync = 1;
+
+ if (ts->selectmode & SCE_SELECT_FACE) {
+ selectmode = UV_SELECT_FACE;
+ }
+ else if (ts->selectmode & SCE_SELECT_EDGE) {
+ selectmode = UV_SELECT_EDGE;
+ }
+ else {
+ selectmode = UV_SELECT_VERTEX;
+ }
+
+ sticky = SI_STICKY_DISABLE;
+ }
+ else {
+ sync = 0;
+ selectmode = ts->uv_selectmode;
+ sticky = (sima) ? sima->sticky : 1;
+ }
+
+ /* find nearest element */
+ if (loop) {
+ /* find edge */
+ found_item = uv_find_nearest_edge_multi(scene, objects, objects_len, co, &hit);
+ }
+ else if (selectmode == UV_SELECT_VERTEX) {
+ /* find vertex */
+ found_item = uv_find_nearest_vert_multi(scene, objects, objects_len, co, penalty_dist, &hit);
+ found_item = found_item && (!deselect_all || hit.dist_sq < penalty_dist);
+
+ if (found_item) {
+ /* mark 1 vertex as being hit */
+ hitv = BLI_array_alloca(hitv, hit.efa->len);
+ hituv = BLI_array_alloca(hituv, hit.efa->len);
+ copy_vn_i(hitv, hit.efa->len, 0xFFFFFFFF);
+
+ hitv[hit.lindex] = BM_elem_index_get(hit.l->v);
+ hituv[hit.lindex] = hit.luv->uv;
+
+ hitlen = hit.efa->len;
+ }
+ }
+ else if (selectmode == UV_SELECT_EDGE) {
+ /* find edge */
+ found_item = uv_find_nearest_edge_multi(scene, objects, objects_len, co, &hit);
+ found_item = found_item && (!deselect_all || hit.dist_sq < penalty_dist);
+
+ if (found_item) {
+ /* mark 2 edge vertices as being hit */
+ hitv = BLI_array_alloca(hitv, hit.efa->len);
+ hituv = BLI_array_alloca(hituv, hit.efa->len);
+ copy_vn_i(hitv, hit.efa->len, 0xFFFFFFFF);
+
+ hitv[hit.lindex] = BM_elem_index_get(hit.l->v);
+ hitv[(hit.lindex + 1) % hit.efa->len] = BM_elem_index_get(hit.l->next->v);
+ hituv[hit.lindex] = hit.luv->uv;
+ hituv[(hit.lindex + 1) % hit.efa->len] = hit.luv_next->uv;
+
+ hitlen = hit.efa->len;
+ }
+ }
+ else if (selectmode == UV_SELECT_FACE) {
+ /* find face */
+ found_item = uv_find_nearest_face_multi(scene, objects, objects_len, co, &hit);
+ found_item = found_item && (!deselect_all || hit.dist_sq < penalty_dist);
+
+ if (found_item) {
+ BMEditMesh *em = BKE_editmesh_from_object(hit.ob);
+ const int cd_loop_uv_offset = CustomData_get_offset(&em->bm->ldata, CD_MLOOPUV);
+
+ /* make active */
+ BM_mesh_active_face_set(em->bm, hit.efa);
+
+ /* mark all face vertices as being hit */
+
+ hitv = BLI_array_alloca(hitv, hit.efa->len);
+ hituv = BLI_array_alloca(hituv, hit.efa->len);
+ BM_ITER_ELEM_INDEX (l, &liter, hit.efa, BM_LOOPS_OF_FACE, i) {
+ luv = BM_ELEM_CD_GET_VOID_P(l, cd_loop_uv_offset);
+ hituv[i] = luv->uv;
+ hitv[i] = BM_elem_index_get(l->v);
+ }
+
+ hitlen = hit.efa->len;
+ }
+ }
+ else if (selectmode == UV_SELECT_ISLAND) {
+ found_item = uv_find_nearest_edge_multi(scene, objects, objects_len, co, &hit);
+ found_item = found_item && (!deselect_all || hit.dist_sq < penalty_dist);
+ }
+
+ if (!found_item) {
+ if (deselect_all) {
+ uv_select_all_perform_multi(scene, objects, objects_len, SEL_DESELECT);
+
+ for (uint ob_index = 0; ob_index < objects_len; ob_index++) {
+ Object *obedit = objects[ob_index];
+ uv_select_tag_update_for_object(depsgraph, ts, obedit);
+ }
+
+ return OPERATOR_PASS_THROUGH | OPERATOR_FINISHED;
+ }
+ return OPERATOR_CANCELLED;
+ }
+
+ Object *obedit = hit.ob;
+ BMEditMesh *em = BKE_editmesh_from_object(obedit);
+ const int cd_loop_uv_offset = CustomData_get_offset(&em->bm->ldata, CD_MLOOPUV);
+
+ /* do selection */
+ if (loop) {
+ if (!extend) {
+ /* TODO(MULTI_EDIT): We only need to de-select non-active */
+ uv_select_all_perform_multi(scene, objects, objects_len, SEL_DESELECT);
+ }
+ flush = uv_select_edgeloop(scene, obedit, &hit, limit, extend);
+ }
+ else if (selectmode == UV_SELECT_ISLAND) {
+ if (!extend) {
+ /* TODO(MULTI_EDIT): We only need to de-select non-active */
+ uv_select_all_perform_multi(scene, objects, objects_len, SEL_DESELECT);
+ }
+ /* Current behavior of 'extend'
+ * is actually toggling, so pass extend flag as 'toggle' here */
+ uv_select_linked_multi(scene, objects, objects_len, limit, &hit, false, false, extend, false);
+ }
+ else if (extend) {
+ if (selectmode == UV_SELECT_VERTEX) {
+ /* (de)select uv vertex */
+ select = !uvedit_uv_select_test(scene, hit.l, cd_loop_uv_offset);
+ uvedit_uv_select_set(em, scene, hit.l, select, true, cd_loop_uv_offset);
+ flush = 1;
+ }
+ else if (selectmode == UV_SELECT_EDGE) {
+ /* (de)select edge */
+ select = !(uvedit_edge_select_test(scene, hit.l, cd_loop_uv_offset));
+ uvedit_edge_select_set(em, scene, hit.l, select, true, cd_loop_uv_offset);
+ flush = 1;
+ }
+ else if (selectmode == UV_SELECT_FACE) {
+ /* (de)select face */
+ select = !(uvedit_face_select_test(scene, hit.efa, cd_loop_uv_offset));
+ uvedit_face_select_set(scene, em, hit.efa, select, true, cd_loop_uv_offset);
+ flush = -1;
+ }
+
+ /* de-selecting an edge may deselect a face too - validate */
+ if (sync) {
+ if (select == false) {
+ BM_select_history_validate(em->bm);
+ }
+ }
+
+ /* (de)select sticky uv nodes */
+ if (sticky != SI_STICKY_DISABLE) {
+
+ BM_mesh_elem_index_ensure(em->bm, BM_VERT);
+
+ BM_ITER_MESH (efa, &iter, em->bm, BM_FACES_OF_MESH) {
+ if (!uvedit_face_visible_test(scene, efa)) {
+ continue;
+ }
+
+ BM_ITER_ELEM (l, &liter, efa, BM_LOOPS_OF_FACE) {
+ luv = BM_ELEM_CD_GET_VOID_P(l, cd_loop_uv_offset);
+ if (uv_sticky_select(
+ limit, hitv, BM_elem_index_get(l->v), hituv, luv->uv, sticky, hitlen)) {
+ uvedit_uv_select_set(em, scene, l, select, false, cd_loop_uv_offset);
+ }
+ }
+ }
+
+ flush = select ? 1 : -1;
+ }
+ }
+ else {
+ /* deselect all */
+ uv_select_all_perform_multi(scene, objects, objects_len, SEL_DESELECT);
+
+ if (selectmode == UV_SELECT_VERTEX) {
+ /* select vertex */
+ uvedit_uv_select_enable(em, scene, hit.l, true, cd_loop_uv_offset);
+ flush = 1;
+ }
+ else if (selectmode == UV_SELECT_EDGE) {
+ /* select edge */
+ uvedit_edge_select_enable(em, scene, hit.l, true, cd_loop_uv_offset);
+ flush = 1;
+ }
+ else if (selectmode == UV_SELECT_FACE) {
+ /* select face */
+ uvedit_face_select_enable(scene, em, hit.efa, true, cd_loop_uv_offset);
+ }
+
+ /* select sticky uvs */
+ if (sticky != SI_STICKY_DISABLE) {
+ BM_ITER_MESH (efa, &iter, em->bm, BM_FACES_OF_MESH) {
+ if (!uvedit_face_visible_test(scene, efa)) {
+ continue;
+ }
+
+ BM_ITER_ELEM (l, &liter, efa, BM_LOOPS_OF_FACE) {
+ if (sticky == SI_STICKY_DISABLE) {
+ continue;
+ }
+ luv = BM_ELEM_CD_GET_VOID_P(l, cd_loop_uv_offset);
+
+ if (uv_sticky_select(
+ limit, hitv, BM_elem_index_get(l->v), hituv, luv->uv, sticky, hitlen)) {
+ uvedit_uv_select_enable(em, scene, l, false, cd_loop_uv_offset);
+ }
+
+ flush = 1;
+ }
+ }
+ }
+ }
+
+ if (sync) {
+ /* flush for mesh selection */
+
+ /* before bmesh */
+#if 0
+ if (ts->selectmode != SCE_SELECT_FACE) {
+ if (flush == 1) {
+ EDBM_select_flush(em);
+ }
+ else if (flush == -1) {
+ EDBM_deselect_flush(em);
+ }
+ }
+#else
+ if (flush != 0) {
+ if (loop) {
+ /* push vertex -> edge selection */
+ if (select) {
+ EDBM_select_flush(em);
+ }
+ else {
+ EDBM_deselect_flush(em);
+ }
+ }
+ else {
+ EDBM_selectmode_flush(em);
+ }
+ }
+#endif
+ }
+
+ for (uint ob_index = 0; ob_index < objects_len; ob_index++) {
+ Object *obiter = objects[ob_index];
+ uv_select_tag_update_for_object(depsgraph, ts, obiter);
+ }
+
+ return OPERATOR_PASS_THROUGH | OPERATOR_FINISHED;
+}
+static int uv_mouse_select(
+ bContext *C, const float co[2], const bool extend, const bool deselect_all, const bool loop)
+{
+ ViewLayer *view_layer = CTX_data_view_layer(C);
+ uint objects_len = 0;
+ Object **objects = BKE_view_layer_array_from_objects_in_edit_mode_unique_data_with_uvs(
+ view_layer, ((View3D *)NULL), &objects_len);
+ int ret = uv_mouse_select_multi(C, objects, objects_len, co, extend, deselect_all, loop);
+ MEM_freeN(objects);
+ return ret;
+}
+
+static int uv_select_exec(bContext *C, wmOperator *op)
+{
+ float co[2];
+
+ RNA_float_get_array(op->ptr, "location", co);
+ const bool extend = RNA_boolean_get(op->ptr, "extend");
+ const bool deselect_all = RNA_boolean_get(op->ptr, "deselect_all");
+ const bool loop = false;
+
+ return uv_mouse_select(C, co, extend, deselect_all, loop);
+}
+
+static int uv_select_invoke(bContext *C, wmOperator *op, const wmEvent *event)
+{
+ const ARegion *region = CTX_wm_region(C);
+ float co[2];
+
+ UI_view2d_region_to_view(&region->v2d, event->mval[0], event->mval[1], &co[0], &co[1]);
+ RNA_float_set_array(op->ptr, "location", co);
+
+ return uv_select_exec(C, op);
+}
+
+void UV_OT_select(wmOperatorType *ot)
+{
+ /* identifiers */
+ ot->name = "Select";
+ ot->description = "Select UV vertices";
+ ot->idname = "UV_OT_select";
+ ot->flag = OPTYPE_UNDO;
+
+ /* api callbacks */
+ ot->exec = uv_select_exec;
+ ot->invoke = uv_select_invoke;
+ ot->poll = ED_operator_uvedit; /* requires space image */
+
+ /* properties */
+ PropertyRNA *prop;
+ RNA_def_boolean(ot->srna,
+ "extend",
+ 0,
+ "Extend",
+ "Extend selection rather than clearing the existing selection");
+ prop = RNA_def_boolean(ot->srna,
+ "deselect_all",
+ false,
+ "Deselect On Nothing",
+ "Deselect all when nothing under the cursor");
+ RNA_def_property_flag(prop, PROP_SKIP_SAVE);
+
+ RNA_def_float_vector(
+ ot->srna,
+ "location",
+ 2,
+ NULL,
+ -FLT_MAX,
+ FLT_MAX,
+ "Location",
+ "Mouse location in normalized coordinates, 0.0 to 1.0 is within the image bounds",
+ -100.0f,
+ 100.0f);
+}
+
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Loop Select Operator
+ * \{ */
+
+static int uv_select_loop_exec(bContext *C, wmOperator *op)
+{
+ float co[2];
+
+ RNA_float_get_array(op->ptr, "location", co);
+ const bool extend = RNA_boolean_get(op->ptr, "extend");
+ const bool deselect_all = false;
+ const bool loop = true;
+
+ return uv_mouse_select(C, co, extend, deselect_all, loop);
+}
+
+static int uv_select_loop_invoke(bContext *C, wmOperator *op, const wmEvent *event)
+{
+ const ARegion *region = CTX_wm_region(C);
+ float co[2];
+
+ UI_view2d_region_to_view(&region->v2d, event->mval[0], event->mval[1], &co[0], &co[1]);
+ RNA_float_set_array(op->ptr, "location", co);
+
+ return uv_select_loop_exec(C, op);
+}
+
+void UV_OT_select_loop(wmOperatorType *ot)
+{
+ /* identifiers */
+ ot->name = "Loop Select";
+ ot->description = "Select a loop of connected UV vertices";
+ ot->idname = "UV_OT_select_loop";
+ ot->flag = OPTYPE_UNDO;
+
+ /* api callbacks */
+ ot->exec = uv_select_loop_exec;
+ ot->invoke = uv_select_loop_invoke;
+ ot->poll = ED_operator_uvedit; /* requires space image */
+
+ /* properties */
+ RNA_def_boolean(ot->srna,
+ "extend",
+ 0,
+ "Extend",
+ "Extend selection rather than clearing the existing selection");
+ RNA_def_float_vector(
+ ot->srna,
+ "location",
+ 2,
+ NULL,
+ -FLT_MAX,
+ FLT_MAX,
+ "Location",
+ "Mouse location in normalized coordinates, 0.0 to 1.0 is within the image bounds",
+ -100.0f,
+ 100.0f);
+}
+
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Select Linked Operator
+ * \{ */
+
+static int uv_select_linked_internal(bContext *C, wmOperator *op, const wmEvent *event, bool pick)
+{
+ SpaceImage *sima = CTX_wm_space_image(C);
+ Scene *scene = CTX_data_scene(C);
+ const ToolSettings *ts = scene->toolsettings;
+ ViewLayer *view_layer = CTX_data_view_layer(C);
+ float limit[2];
+ bool extend = true;
+ bool deselect = false;
+ bool select_faces = (ts->uv_flag & UV_SYNC_SELECTION) && (ts->selectmode & SCE_SELECT_FACE);
+
+ UvNearestHit hit = UV_NEAREST_HIT_INIT;
+
+ if ((ts->uv_flag & UV_SYNC_SELECTION) && !(ts->selectmode & SCE_SELECT_FACE)) {
+ BKE_report(op->reports,
+ RPT_ERROR,
+ "Select linked only works in face select mode when sync selection is enabled");
+ return OPERATOR_CANCELLED;
+ }
+
+ if (pick) {
+ extend = RNA_boolean_get(op->ptr, "extend");
+ deselect = RNA_boolean_get(op->ptr, "deselect");
+ }
+ uv_select_island_limit_default(sima, limit);
+
+ uint objects_len = 0;
+ Object **objects = BKE_view_layer_array_from_objects_in_edit_mode_unique_data_with_uvs(
+ view_layer, ((View3D *)NULL), &objects_len);
+
+ if (pick) {
+ float co[2];
+
+ if (event) {
+ /* invoke */
+ const ARegion *region = CTX_wm_region(C);
+
+ UI_view2d_region_to_view(&region->v2d, event->mval[0], event->mval[1], &co[0], &co[1]);
+ RNA_float_set_array(op->ptr, "location", co);
+ }
+ else {
+ /* exec */
+ RNA_float_get_array(op->ptr, "location", co);
+ }
+
+ if (!uv_find_nearest_edge_multi(scene, objects, objects_len, co, &hit)) {
+ MEM_freeN(objects);
+ return OPERATOR_CANCELLED;
+ }
+ }
+
+ if (!extend) {
+ uv_select_all_perform_multi(scene, objects, objects_len, SEL_DESELECT);
+ }
+
+ uv_select_linked_multi(scene,
+ objects,
+ objects_len,
+ limit,
+ pick ? &hit : NULL,
+ extend,
+ deselect,
+ false,
+ select_faces);
+
+ /* weak!, but works */
+ Object **objects_free = objects;
+ if (pick) {
+ objects = &hit.ob;
+ objects_len = 1;
+ }
+
+ for (uint ob_index = 0; ob_index < objects_len; ob_index++) {
+ Object *obedit = objects[ob_index];
+ DEG_id_tag_update(obedit->data, ID_RECALC_COPY_ON_WRITE | ID_RECALC_SELECT);
+ WM_event_add_notifier(C, NC_GEOM | ND_SELECT, obedit->data);
+ }
+
+ MEM_SAFE_FREE(objects_free);
+
+ return OPERATOR_FINISHED;
+}
+
+static int uv_select_linked_exec(bContext *C, wmOperator *op)
+{
+ return uv_select_linked_internal(C, op, NULL, false);
+}
+
+void UV_OT_select_linked(wmOperatorType *ot)
+{
+ /* identifiers */
+ ot->name = "Select Linked";
+ ot->description = "Select all UV vertices linked to the active UV map";
+ ot->idname = "UV_OT_select_linked";
+
+ /* api callbacks */
+ ot->exec = uv_select_linked_exec;
+ ot->poll = ED_operator_uvedit; /* requires space image */
+
+ /* flags */
+ ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
+}
+
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Select Linked (Cursor Pick) Operator
+ * \{ */
+
+static int uv_select_linked_pick_invoke(bContext *C, wmOperator *op, const wmEvent *event)
+{
+ return uv_select_linked_internal(C, op, event, true);
+}
+
+static int uv_select_linked_pick_exec(bContext *C, wmOperator *op)
+{
+ return uv_select_linked_internal(C, op, NULL, true);
+}
+
+void UV_OT_select_linked_pick(wmOperatorType *ot)
+{
+ /* identifiers */
+ ot->name = "Select Linked Pick";
+ ot->description = "Select all UV vertices linked under the mouse";
+ ot->idname = "UV_OT_select_linked_pick";
+
+ /* flags */
+ ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
+
+ /* api callbacks */
+ ot->invoke = uv_select_linked_pick_invoke;
+ ot->exec = uv_select_linked_pick_exec;
+ ot->poll = ED_operator_uvedit; /* requires space image */
+
+ /* properties */
+ RNA_def_boolean(ot->srna,
+ "extend",
+ 0,
+ "Extend",
+ "Extend selection rather than clearing the existing selection");
+ RNA_def_boolean(ot->srna,
+ "deselect",
+ 0,
+ "Deselect",
+ "Deselect linked UV vertices rather than selecting them");
+ RNA_def_float_vector(
+ ot->srna,
+ "location",
+ 2,
+ NULL,
+ -FLT_MAX,
+ FLT_MAX,
+ "Location",
+ "Mouse location in normalized coordinates, 0.0 to 1.0 is within the image bounds",
+ -100.0f,
+ 100.0f);
+}
+
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Select Split Operator
+ * \{ */
+
+/**
+ * \note This is based on similar use case to #MESH_OT_split(), which has a similar effect
+ * but in this case they are not joined to begin with (only having the behavior of being joined)
+ * so its best to call this #uv_select_split() instead of just split(), but assigned to the same
+ * key as #MESH_OT_split - Campbell.
+ */
+static int uv_select_split_exec(bContext *C, wmOperator *op)
+{
+ Scene *scene = CTX_data_scene(C);
+ ViewLayer *view_layer = CTX_data_view_layer(C);
+ const ToolSettings *ts = scene->toolsettings;
+
+ BMFace *efa;
+ BMLoop *l;
+ BMIter iter, liter;
+ MLoopUV *luv;
+
+ if (ts->uv_flag & UV_SYNC_SELECTION) {
+ BKE_report(op->reports, RPT_ERROR, "Cannot split selection when sync selection is enabled");
+ return OPERATOR_CANCELLED;
+ }
+
+ bool changed_multi = false;
+
+ uint objects_len = 0;
+ Object **objects = BKE_view_layer_array_from_objects_in_edit_mode_unique_data_with_uvs(
+ view_layer, ((View3D *)NULL), &objects_len);
+
+ for (uint ob_index = 0; ob_index < objects_len; ob_index++) {
+ Object *obedit = objects[ob_index];
+ BMesh *bm = BKE_editmesh_from_object(obedit)->bm;
+
+ bool changed = false;
+
+ const int cd_loop_uv_offset = CustomData_get_offset(&bm->ldata, CD_MLOOPUV);
+
+ BM_ITER_MESH (efa, &iter, bm, BM_FACES_OF_MESH) {
+ bool is_sel = false;
+ bool is_unsel = false;
+
+ if (!uvedit_face_visible_test(scene, efa)) {
+ continue;
+ }
+
+ /* are we all selected? */
+ BM_ITER_ELEM (l, &liter, efa, BM_LOOPS_OF_FACE) {
+ luv = BM_ELEM_CD_GET_VOID_P(l, cd_loop_uv_offset);
+
+ if (luv->flag & MLOOPUV_VERTSEL) {
+ is_sel = true;
+ }
+ else {
+ is_unsel = true;
+ }
+
+ /* we have mixed selection, bail out */
+ if (is_sel && is_unsel) {
+ break;
+ }
+ }
+
+ if (is_sel && is_unsel) {
+ BM_ITER_ELEM (l, &liter, efa, BM_LOOPS_OF_FACE) {
+ luv = BM_ELEM_CD_GET_VOID_P(l, cd_loop_uv_offset);
+ luv->flag &= ~MLOOPUV_VERTSEL;
+ }
+
+ changed = true;
+ }
+ }
+
+ if (changed) {
+ changed_multi = true;
+ WM_event_add_notifier(C, NC_SPACE | ND_SPACE_IMAGE, NULL);
+ }
+ }
+ MEM_freeN(objects);
+
+ return changed_multi ? OPERATOR_FINISHED : OPERATOR_CANCELLED;
+}
+
+void UV_OT_select_split(wmOperatorType *ot)
+{
+ /* identifiers */
+ ot->name = "Select Split";
+ ot->description = "Select only entirely selected faces";
+ ot->idname = "UV_OT_select_split";
+ ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
+
+ /* api callbacks */
+ ot->exec = uv_select_split_exec;
+ ot->poll = ED_operator_uvedit; /* requires space image */
+}
+
+static void uv_select_sync_flush(const ToolSettings *ts, BMEditMesh *em, const short select)
+{
+ /* bmesh API handles flushing but not on de-select */
+ if (ts->uv_flag & UV_SYNC_SELECTION) {
+ if (ts->selectmode != SCE_SELECT_FACE) {
+ if (select == false) {
+ EDBM_deselect_flush(em);
+ }
+ else {
+ EDBM_select_flush(em);
+ }
+ }
+
+ if (select == false) {
+ BM_select_history_validate(em->bm);
+ }
+ }
+}
+
+static void uv_select_tag_update_for_object(Depsgraph *depsgraph,
+ const ToolSettings *ts,
+ Object *obedit)
+{
+ if (ts->uv_flag & UV_SYNC_SELECTION) {
+ DEG_id_tag_update(obedit->data, ID_RECALC_SELECT);
+ WM_main_add_notifier(NC_GEOM | ND_SELECT, obedit->data);
+ }
+ else {
+ Object *obedit_eval = DEG_get_evaluated_object(depsgraph, obedit);
+ BKE_mesh_batch_cache_dirty_tag(obedit_eval->data, BKE_MESH_BATCH_DIRTY_UVEDIT_SELECT);
+ /* Only for region redraw. */
+ WM_main_add_notifier(NC_GEOM | ND_SELECT, obedit->data);
+ }
+}
+
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Select/Tag Flushing Utils
+ *
+ * Utility functions to flush the uv-selection from tags.
+ * \{ */
+
+/**
+ * helper function for #uv_select_flush_from_tag_loop and uv_select_flush_from_tag_face
+ */
+static void uv_select_flush_from_tag_sticky_loc_internal(Scene *scene,
+ BMEditMesh *em,
+ UvVertMap *vmap,
+ const uint efa_index,
+ BMLoop *l,
+ const bool select,
+ const int cd_loop_uv_offset)
+{
+ UvMapVert *start_vlist = NULL, *vlist_iter;
+ BMFace *efa_vlist;
+
+ uvedit_uv_select_set(em, scene, l, select, false, cd_loop_uv_offset);
+
+ vlist_iter = BM_uv_vert_map_at_index(vmap, BM_elem_index_get(l->v));
+
+ while (vlist_iter) {
+ if (vlist_iter->separate) {
+ start_vlist = vlist_iter;
+ }
+
+ if (efa_index == vlist_iter->poly_index) {
+ break;
+ }
+
+ vlist_iter = vlist_iter->next;
+ }
+
+ vlist_iter = start_vlist;
+ while (vlist_iter) {
+
+ if (vlist_iter != start_vlist && vlist_iter->separate) {
+ break;
+ }
+
+ if (efa_index != vlist_iter->poly_index) {
+ BMLoop *l_other;
+ efa_vlist = BM_face_at_index(em->bm, vlist_iter->poly_index);
+ /* tf_vlist = BM_ELEM_CD_GET_VOID_P(efa_vlist, cd_poly_tex_offset); */ /* UNUSED */
+
+ l_other = BM_iter_at_index(
+ em->bm, BM_LOOPS_OF_FACE, efa_vlist, vlist_iter->loop_of_poly_index);
+
+ uvedit_uv_select_set(em, scene, l_other, select, false, cd_loop_uv_offset);
+ }
+ vlist_iter = vlist_iter->next;
+ }
+}
+
+/**
+ * Flush the selection from face tags based on sticky and selection modes.
+ *
+ * needed because settings the selection a face is done in a number of places but it also
+ * needs to respect the sticky modes for the UV verts, so dealing with the sticky modes
+ * is best done in a separate function.
+ *
+ * \note This function is very similar to #uv_select_flush_from_tag_loop,
+ * be sure to update both upon changing.
+ */
+static void uv_select_flush_from_tag_face(SpaceImage *sima,
+ Scene *scene,
+ Object *obedit,
+ const bool select)
+{
+ /* Selecting UV Faces with some modes requires us to change
+ * the selection in other faces (depending on the sticky mode).
+ *
+ * This only needs to be done when the Mesh is not used for
+ * selection (so for sticky modes, vertex or location based). */
+
+ const ToolSettings *ts = scene->toolsettings;
+ BMEditMesh *em = BKE_editmesh_from_object(obedit);
+ BMFace *efa;
+ BMLoop *l;
+ BMIter iter, liter;
+ const int cd_loop_uv_offset = CustomData_get_offset(&em->bm->ldata, CD_MLOOPUV);
+
+ if ((ts->uv_flag & UV_SYNC_SELECTION) == 0 && sima->sticky == SI_STICKY_VERTEX) {
+ /* Tag all verts as untouched, then touch the ones that have a face center
+ * in the loop and select all MLoopUV's that use a touched vert. */
+ BM_mesh_elem_hflag_disable_all(em->bm, BM_VERT, BM_ELEM_TAG, false);
+
+ BM_ITER_MESH (efa, &iter, em->bm, BM_FACES_OF_MESH) {
+ if (BM_elem_flag_test(efa, BM_ELEM_TAG)) {
+ BM_ITER_ELEM (l, &liter, efa, BM_LOOPS_OF_FACE) {
+ BM_elem_flag_enable(l->v, BM_ELEM_TAG);
+ }
+ }
+ }
+
+ /* now select tagged verts */
+ BM_ITER_MESH (efa, &iter, em->bm, BM_FACES_OF_MESH) {
+ /* tf = BM_ELEM_CD_GET_VOID_P(efa, cd_poly_tex_offset); */ /* UNUSED */
+
+ BM_ITER_ELEM (l, &liter, efa, BM_LOOPS_OF_FACE) {
+ if (BM_elem_flag_test(l->v, BM_ELEM_TAG)) {
+ uvedit_uv_select_set(em, scene, l, select, false, cd_loop_uv_offset);
+ }
+ }
+ }
+ }
+ else if ((ts->uv_flag & UV_SYNC_SELECTION) == 0 && sima->sticky == SI_STICKY_LOC) {
+ struct UvVertMap *vmap;
+ float limit[2];
+ uint efa_index;
+
+ uv_select_island_limit_default(sima, limit);
+
+ BM_mesh_elem_table_ensure(em->bm, BM_FACE);
+ vmap = BM_uv_vert_map_create(em->bm, limit, false, false);
+ if (vmap == NULL) {
+ return;
+ }
+
+ BM_ITER_MESH_INDEX (efa, &iter, em->bm, BM_FACES_OF_MESH, efa_index) {
+ if (BM_elem_flag_test(efa, BM_ELEM_TAG)) {
+ /* tf = BM_ELEM_CD_GET_VOID_P(efa, cd_poly_tex_offset); */ /* UNUSED */
+
+ BM_ITER_ELEM (l, &liter, efa, BM_LOOPS_OF_FACE) {
+ uv_select_flush_from_tag_sticky_loc_internal(
+ scene, em, vmap, efa_index, l, select, cd_loop_uv_offset);
+ }
+ }
+ }
+ BM_uv_vert_map_free(vmap);
+ }
+ else { /* SI_STICKY_DISABLE or ts->uv_flag & UV_SYNC_SELECTION */
+ BM_ITER_MESH (efa, &iter, em->bm, BM_FACES_OF_MESH) {
+ if (BM_elem_flag_test(efa, BM_ELEM_TAG)) {
+ uvedit_face_select_set(scene, em, efa, select, false, cd_loop_uv_offset);
+ }
+ }
+ }
+}
+
+/**
+ * Flush the selection from loop tags based on sticky and selection modes.
+ *
+ * needed because settings the selection a face is done in a number of places but it also needs
+ * to respect the sticky modes for the UV verts, so dealing with the sticky modes is best done
+ * in a separate function.
+ *
+ * \note This function is very similar to #uv_select_flush_from_tag_loop,
+ * be sure to update both upon changing.
+ */
+static void uv_select_flush_from_tag_loop(SpaceImage *sima,
+ Scene *scene,
+ Object *obedit,
+ const bool select)
+{
+ /* Selecting UV Loops with some modes requires us to change
+ * the selection in other faces (depending on the sticky mode).
+ *
+ * This only needs to be done when the Mesh is not used for
+ * selection (so for sticky modes, vertex or location based). */
+
+ const ToolSettings *ts = scene->toolsettings;
+ BMEditMesh *em = BKE_editmesh_from_object(obedit);
+ BMFace *efa;
+ BMLoop *l;
+ BMIter iter, liter;
+
+ const int cd_loop_uv_offset = CustomData_get_offset(&em->bm->ldata, CD_MLOOPUV);
+
+ if ((ts->uv_flag & UV_SYNC_SELECTION) == 0 && sima->sticky == SI_STICKY_VERTEX) {
+ /* Tag all verts as untouched, then touch the ones that have a face center
+ * in the loop and select all MLoopUV's that use a touched vert. */
+ BM_mesh_elem_hflag_disable_all(em->bm, BM_VERT, BM_ELEM_TAG, false);
+
+ BM_ITER_MESH (efa, &iter, em->bm, BM_FACES_OF_MESH) {
+ BM_ITER_ELEM (l, &liter, efa, BM_LOOPS_OF_FACE) {
+ if (BM_elem_flag_test(l, BM_ELEM_TAG)) {
+ BM_elem_flag_enable(l->v, BM_ELEM_TAG);
+ }
+ }
+ }
+
+ /* now select tagged verts */
+ BM_ITER_MESH (efa, &iter, em->bm, BM_FACES_OF_MESH) {
+ /* tf = BM_ELEM_CD_GET_VOID_P(efa, cd_poly_tex_offset); */ /* UNUSED */
+
+ BM_ITER_ELEM (l, &liter, efa, BM_LOOPS_OF_FACE) {
+ if (BM_elem_flag_test(l->v, BM_ELEM_TAG)) {
+ uvedit_uv_select_set(em, scene, l, select, false, cd_loop_uv_offset);
+ }
+ }
+ }
+ }
+ else if ((ts->uv_flag & UV_SYNC_SELECTION) == 0 && sima->sticky == SI_STICKY_LOC) {
+ struct UvVertMap *vmap;
+ float limit[2];
+ uint efa_index;
+
+ uv_select_island_limit_default(sima, limit);
+
+ BM_mesh_elem_table_ensure(em->bm, BM_FACE);
+ vmap = BM_uv_vert_map_create(em->bm, limit, false, false);
+ if (vmap == NULL) {
+ return;
+ }
+
+ BM_ITER_MESH_INDEX (efa, &iter, em->bm, BM_FACES_OF_MESH, efa_index) {
+ /* tf = BM_ELEM_CD_GET_VOID_P(efa, cd_poly_tex_offset); */ /* UNUSED */
+
+ BM_ITER_ELEM (l, &liter, efa, BM_LOOPS_OF_FACE) {
+ if (BM_elem_flag_test(l, BM_ELEM_TAG)) {
+ uv_select_flush_from_tag_sticky_loc_internal(
+ scene, em, vmap, efa_index, l, select, cd_loop_uv_offset);
+ }
+ }
+ }
+ BM_uv_vert_map_free(vmap);
+ }
+ else { /* SI_STICKY_DISABLE or ts->uv_flag & UV_SYNC_SELECTION */
+ BM_ITER_MESH (efa, &iter, em->bm, BM_FACES_OF_MESH) {
+ BM_ITER_ELEM (l, &liter, efa, BM_LOOPS_OF_FACE) {
+ if (BM_elem_flag_test(l, BM_ELEM_TAG)) {
+ uvedit_uv_select_set(em, scene, l, select, false, cd_loop_uv_offset);
+ }
+ }
+ }
+ }
+}
+
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Box Select Operator
+ * \{ */
+
+static int uv_box_select_exec(bContext *C, wmOperator *op)
+{
+ Depsgraph *depsgraph = CTX_data_ensure_evaluated_depsgraph(C);
+ SpaceImage *sima = CTX_wm_space_image(C);
+ Scene *scene = CTX_data_scene(C);
+ const ToolSettings *ts = scene->toolsettings;
+ ViewLayer *view_layer = CTX_data_view_layer(C);
+ const ARegion *region = CTX_wm_region(C);
+ BMFace *efa;
+ BMLoop *l;
+ BMIter iter, liter;
+ MLoopUV *luv;
+ rctf rectf;
+ bool pinned;
+ float limit[2];
+ const bool use_face_center = ((ts->uv_flag & UV_SYNC_SELECTION) ?
+ (ts->selectmode == SCE_SELECT_FACE) :
+ (ts->uv_selectmode == UV_SELECT_FACE));
+ const bool use_edge = ((ts->uv_flag & UV_SYNC_SELECTION) ?
+ (ts->selectmode == SCE_SELECT_EDGE) :
+ (ts->uv_selectmode == UV_SELECT_EDGE));
+
+ /* get rectangle from operator */
+ WM_operator_properties_border_to_rctf(op, &rectf);
+ UI_view2d_region_to_view_rctf(&region->v2d, &rectf, &rectf);
+
+ const eSelectOp sel_op = RNA_enum_get(op->ptr, "mode");
+ const bool select = (sel_op != SEL_OP_SUB);
+ const bool use_pre_deselect = SEL_OP_USE_PRE_DESELECT(sel_op);
+
+ pinned = RNA_boolean_get(op->ptr, "pinned");
+
+ uv_select_island_limit_default(sima, limit);
+
+ bool changed_multi = false;
+
+ uint objects_len = 0;
+ Object **objects = BKE_view_layer_array_from_objects_in_edit_mode_unique_data_with_uvs(
+ view_layer, ((View3D *)NULL), &objects_len);
+
+ if (use_pre_deselect) {
+ uv_select_all_perform_multi(scene, objects, objects_len, SEL_DESELECT);
+ }
+
+ /* don't indent to avoid diff noise! */
+ for (uint ob_index = 0; ob_index < objects_len; ob_index++) {
+ Object *obedit = objects[ob_index];
+ BMEditMesh *em = BKE_editmesh_from_object(obedit);
+
+ bool changed = false;
+
+ const int cd_loop_uv_offset = CustomData_get_offset(&em->bm->ldata, CD_MLOOPUV);
+
+ /* do actual selection */
+ if (use_face_center && !pinned) {
+ /* handle face selection mode */
+ float cent[2];
+
+ BM_ITER_MESH (efa, &iter, em->bm, BM_FACES_OF_MESH) {
+ /* assume not touched */
+ BM_elem_flag_disable(efa, BM_ELEM_TAG);
+
+ if (uvedit_face_visible_test(scene, efa)) {
+ uv_poly_center(efa, cent, cd_loop_uv_offset);
+ if (BLI_rctf_isect_pt_v(&rectf, cent)) {
+ BM_elem_flag_enable(efa, BM_ELEM_TAG);
+ changed = true;
+ }
+ }
+ }
+
+ /* (de)selects all tagged faces and deals with sticky modes */
+ if (changed) {
+ uv_select_flush_from_tag_face(sima, scene, obedit, select);
+ }
+ }
+ else if (use_edge && !pinned) {
+ changed = true;
+ BM_mesh_elem_hflag_disable_all(em->bm, BM_VERT, BM_ELEM_TAG, false);
+
+ BM_ITER_MESH (efa, &iter, em->bm, BM_FACES_OF_MESH) {
+ if (!uvedit_face_visible_test(scene, efa)) {
+ continue;
+ }
+
+ BMLoop *l_prev = BM_FACE_FIRST_LOOP(efa)->prev;
+ MLoopUV *luv_prev = BM_ELEM_CD_GET_VOID_P(l_prev, cd_loop_uv_offset);
+ bool luv_select_prev = uvedit_uv_select_test(scene, l_prev, cd_loop_uv_offset);
+
+ BM_ITER_ELEM (l, &liter, efa, BM_LOOPS_OF_FACE) {
+ luv = BM_ELEM_CD_GET_VOID_P(l, cd_loop_uv_offset);
+ const bool luv_select = uvedit_uv_select_test(scene, l, cd_loop_uv_offset);
+ if ((select != luv_select) || (select != luv_select_prev)) {
+ if (BLI_rctf_isect_pt_v(&rectf, luv->uv) &&
+ BLI_rctf_isect_pt_v(&rectf, luv_prev->uv)) {
+ uvedit_uv_select_set(em, scene, l, select, false, cd_loop_uv_offset);
+ uvedit_uv_select_set(em, scene, l_prev, select, false, cd_loop_uv_offset);
+ BM_elem_flag_enable(l->v, BM_ELEM_TAG);
+ BM_elem_flag_enable(l_prev->v, BM_ELEM_TAG);
+ }
+ }
+ l_prev = l;
+ luv_prev = luv;
+ luv_select_prev = luv_select;
+ }
+ }
+
+ if (sima->sticky == SI_STICKY_VERTEX) {
+ uvedit_vertex_select_tagged(em, scene, select, cd_loop_uv_offset);
+ }
+ }
+ else {
+ /* other selection modes */
+ changed = true;
+ BM_mesh_elem_hflag_disable_all(em->bm, BM_VERT, BM_ELEM_TAG, false);
+
+ BM_ITER_MESH (efa, &iter, em->bm, BM_FACES_OF_MESH) {
+ if (!uvedit_face_visible_test(scene, efa)) {
+ continue;
+ }
+ bool has_selected = false;
+ BM_ITER_ELEM (l, &liter, efa, BM_LOOPS_OF_FACE) {
+ luv = BM_ELEM_CD_GET_VOID_P(l, cd_loop_uv_offset);
+ if ((select) != (uvedit_uv_select_test(scene, l, cd_loop_uv_offset))) {
+ if (!pinned || (ts->uv_flag & UV_SYNC_SELECTION)) {
+ /* UV_SYNC_SELECTION - can't do pinned selection */
+ if (BLI_rctf_isect_pt_v(&rectf, luv->uv)) {
+ uvedit_uv_select_set(em, scene, l, select, false, cd_loop_uv_offset);
+ BM_elem_flag_enable(l->v, BM_ELEM_TAG);
+ has_selected = true;
+ }
+ }
+ else if (pinned) {
+ if ((luv->flag & MLOOPUV_PINNED) && BLI_rctf_isect_pt_v(&rectf, luv->uv)) {
+ uvedit_uv_select_set(em, scene, l, select, false, cd_loop_uv_offset);
+ BM_elem_flag_enable(l->v, BM_ELEM_TAG);
+ }
+ }
+ }
+ }
+ if (has_selected && ts->uv_selectmode == UV_SELECT_ISLAND) {
+ UvNearestHit hit = {
+ .ob = obedit,
+ .efa = efa,
+ };
+ uv_select_linked_multi(
+ scene, objects, objects_len, limit, &hit, true, !select, false, false);
+ }
+ }
+
+ if (sima->sticky == SI_STICKY_VERTEX) {
+ uvedit_vertex_select_tagged(em, scene, select, cd_loop_uv_offset);
+ }
+ }
+
+ if (changed || use_pre_deselect) {
+ changed_multi = true;
+
+ uv_select_sync_flush(ts, em, select);
+ uv_select_tag_update_for_object(depsgraph, ts, obedit);
+ }
+ }
+
+ MEM_freeN(objects);
+
+ return changed_multi ? OPERATOR_FINISHED : OPERATOR_CANCELLED;
+}
+
+void UV_OT_select_box(wmOperatorType *ot)
+{
+ /* identifiers */
+ ot->name = "Box Select";
+ ot->description = "Select UV vertices using box selection";
+ ot->idname = "UV_OT_select_box";
+
+ /* api callbacks */
+ ot->invoke = WM_gesture_box_invoke;
+ ot->exec = uv_box_select_exec;
+ ot->modal = WM_gesture_box_modal;
+ ot->poll = ED_operator_uvedit_space_image; /* requires space image */
+ ot->cancel = WM_gesture_box_cancel;
+
+ /* flags */
+ ot->flag = OPTYPE_UNDO;
+
+ /* properties */
+ RNA_def_boolean(ot->srna, "pinned", 0, "Pinned", "Border select pinned UVs only");
+
+ WM_operator_properties_gesture_box(ot);
+ WM_operator_properties_select_operation_simple(ot);
+}
+
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Circle Select Operator
+ * \{ */
+
+static int uv_circle_select_is_point_inside(const float uv[2],
+ const float offset[2],
+ const float ellipse[2])
+{
+ /* normalized ellipse: ell[0] = scaleX, ell[1] = scaleY */
+ const float co[2] = {
+ (uv[0] - offset[0]) * ellipse[0],
+ (uv[1] - offset[1]) * ellipse[1],
+ };
+ return len_squared_v2(co) < 1.0f;
+}
+
+static int uv_circle_select_is_edge_inside(const float uv_a[2],
+ const float uv_b[2],
+ const float offset[2],
+ const float ellipse[2])
+{
+ /* normalized ellipse: ell[0] = scaleX, ell[1] = scaleY */
+ const float co_a[2] = {
+ (uv_a[0] - offset[0]) * ellipse[0],
+ (uv_a[1] - offset[1]) * ellipse[1],
+ };
+ const float co_b[2] = {
+ (uv_b[0] - offset[0]) * ellipse[0],
+ (uv_b[1] - offset[1]) * ellipse[1],
+ };
+ return dist_squared_to_line_segment_v2((const float[2]){0.0f, 0.0f}, co_a, co_b) < 1.0f;
+}
+
+static int uv_circle_select_exec(bContext *C, wmOperator *op)
+{
+ Depsgraph *depsgraph = CTX_data_ensure_evaluated_depsgraph(C);
+ SpaceImage *sima = CTX_wm_space_image(C);
+ Scene *scene = CTX_data_scene(C);
+ ViewLayer *view_layer = CTX_data_view_layer(C);
+ const ToolSettings *ts = scene->toolsettings;
+ const ARegion *region = CTX_wm_region(C);
+ BMFace *efa;
+ BMLoop *l;
+ BMIter iter, liter;
+ MLoopUV *luv;
+ int x, y, radius, width, height;
+ float zoomx, zoomy;
+ float limit[2], offset[2], ellipse[2];
+
+ const bool use_face_center = ((ts->uv_flag & UV_SYNC_SELECTION) ?
+ (ts->selectmode == SCE_SELECT_FACE) :
+ (ts->uv_selectmode == UV_SELECT_FACE));
+ const bool use_edge = ((ts->uv_flag & UV_SYNC_SELECTION) ?
+ (ts->selectmode == SCE_SELECT_EDGE) :
+ (ts->uv_selectmode == UV_SELECT_EDGE));
+
+ /* get operator properties */
+ x = RNA_int_get(op->ptr, "x");
+ y = RNA_int_get(op->ptr, "y");
+ radius = RNA_int_get(op->ptr, "radius");
+
+ /* compute ellipse size and location, not a circle since we deal
+ * with non square image. ellipse is normalized, r = 1.0. */
+ ED_space_image_get_size(sima, &width, &height);
+ ED_space_image_get_zoom(sima, region, &zoomx, &zoomy);
+
+ ellipse[0] = width * zoomx / radius;
+ ellipse[1] = height * zoomy / radius;
+
+ UI_view2d_region_to_view(&region->v2d, x, y, &offset[0], &offset[1]);
+
+ uv_select_island_limit_default(sima, limit);
+
+ bool changed_multi = false;
+
+ uint objects_len = 0;
+ Object **objects = BKE_view_layer_array_from_objects_in_edit_mode_unique_data_with_uvs(
+ view_layer, ((View3D *)NULL), &objects_len);
+
+ const eSelectOp sel_op = ED_select_op_modal(RNA_enum_get(op->ptr, "mode"),
+ WM_gesture_is_modal_first(op->customdata));
+ const bool select = (sel_op != SEL_OP_SUB);
+ const bool use_pre_deselect = SEL_OP_USE_PRE_DESELECT(sel_op);
+
+ if (use_pre_deselect) {
+ uv_select_all_perform_multi(scene, objects, objects_len, SEL_DESELECT);
+ }
+
+ for (uint ob_index = 0; ob_index < objects_len; ob_index++) {
+ Object *obedit = objects[ob_index];
+ BMEditMesh *em = BKE_editmesh_from_object(obedit);
+
+ bool changed = false;
+
+ const int cd_loop_uv_offset = CustomData_get_offset(&em->bm->ldata, CD_MLOOPUV);
+
+ /* do selection */
+ if (use_face_center) {
+ BM_ITER_MESH (efa, &iter, em->bm, BM_FACES_OF_MESH) {
+ BM_elem_flag_disable(efa, BM_ELEM_TAG);
+ /* assume not touched */
+ if (select != uvedit_face_select_test(scene, efa, cd_loop_uv_offset)) {
+ float cent[2];
+ uv_poly_center(efa, cent, cd_loop_uv_offset);
+ if (uv_circle_select_is_point_inside(cent, offset, ellipse)) {
+ BM_elem_flag_enable(efa, BM_ELEM_TAG);
+ changed = true;
+ }
+ }
+ }
+
+ /* (de)selects all tagged faces and deals with sticky modes */
+ if (changed) {
+ uv_select_flush_from_tag_face(sima, scene, obedit, select);
+ }
+ }
+ else if (use_edge) {
+ BM_mesh_elem_hflag_disable_all(em->bm, BM_VERT, BM_ELEM_TAG, false);
+
+ BM_ITER_MESH (efa, &iter, em->bm, BM_FACES_OF_MESH) {
+ if (!uvedit_face_visible_test(scene, efa)) {
+ continue;
+ }
+
+ BMLoop *l_prev = BM_FACE_FIRST_LOOP(efa)->prev;
+ MLoopUV *luv_prev = BM_ELEM_CD_GET_VOID_P(l_prev, cd_loop_uv_offset);
+ bool luv_select_prev = uvedit_uv_select_test(scene, l_prev, cd_loop_uv_offset);
+
+ BM_ITER_ELEM (l, &liter, efa, BM_LOOPS_OF_FACE) {
+ luv = BM_ELEM_CD_GET_VOID_P(l, cd_loop_uv_offset);
+ const bool luv_select = uvedit_uv_select_test(scene, l, cd_loop_uv_offset);
+ if ((select != luv_select) || (select != luv_select_prev)) {
+ if (uv_circle_select_is_edge_inside(luv->uv, luv_prev->uv, offset, ellipse)) {
+ changed = true;
+ uvedit_uv_select_set(em, scene, l, select, false, cd_loop_uv_offset);
+ uvedit_uv_select_set(em, scene, l_prev, select, false, cd_loop_uv_offset);
+ BM_elem_flag_enable(l->v, BM_ELEM_TAG);
+ BM_elem_flag_enable(l_prev->v, BM_ELEM_TAG);
+ }
+ }
+ l_prev = l;
+ luv_prev = luv;
+ luv_select_prev = luv_select;
+ }
+ }
+
+ if (sima->sticky == SI_STICKY_VERTEX) {
+ uvedit_vertex_select_tagged(em, scene, select, cd_loop_uv_offset);
+ }
+ }
+ else {
+ BM_mesh_elem_hflag_disable_all(em->bm, BM_VERT, BM_ELEM_TAG, false);
+
+ BM_ITER_MESH (efa, &iter, em->bm, BM_FACES_OF_MESH) {
+ if (!uvedit_face_visible_test(scene, efa)) {
+ continue;
+ }
+ bool has_selected = false;
+ BM_ITER_ELEM (l, &liter, efa, BM_LOOPS_OF_FACE) {
+ if ((select) != (uvedit_uv_select_test(scene, l, cd_loop_uv_offset))) {
+ luv = BM_ELEM_CD_GET_VOID_P(l, cd_loop_uv_offset);
+ if (uv_circle_select_is_point_inside(luv->uv, offset, ellipse)) {
+ changed = true;
+ uvedit_uv_select_set(em, scene, l, select, false, cd_loop_uv_offset);
+ BM_elem_flag_enable(l->v, BM_ELEM_TAG);
+ has_selected = true;
+ }
+ }
+ }
+ if (has_selected && ts->uv_selectmode == UV_SELECT_ISLAND) {
+ UvNearestHit hit = {
+ .ob = obedit,
+ .efa = efa,
+ };
+ uv_select_linked_multi(
+ scene, objects, objects_len, limit, &hit, true, !select, false, false);
+ }
+ }
+
+ if (sima->sticky == SI_STICKY_VERTEX) {
+ uvedit_vertex_select_tagged(em, scene, select, cd_loop_uv_offset);
+ }
+ }
+
+ if (changed || use_pre_deselect) {
+ changed_multi = true;
+
+ uv_select_sync_flush(ts, em, select);
+ uv_select_tag_update_for_object(depsgraph, ts, obedit);
+ }
+ }
+ MEM_freeN(objects);
+
+ return changed_multi ? OPERATOR_FINISHED : OPERATOR_CANCELLED;
+}
+
+void UV_OT_select_circle(wmOperatorType *ot)
+{
+ /* identifiers */
+ ot->name = "Circle Select";
+ ot->description = "Select UV vertices using circle selection";
+ ot->idname = "UV_OT_select_circle";
+
+ /* api callbacks */
+ ot->invoke = WM_gesture_circle_invoke;
+ ot->modal = WM_gesture_circle_modal;
+ ot->exec = uv_circle_select_exec;
+ ot->poll = ED_operator_uvedit_space_image; /* requires space image */
+ ot->cancel = WM_gesture_circle_cancel;
+
+ /* flags */
+ ot->flag = OPTYPE_UNDO;
+
+ /* properties */
+ WM_operator_properties_gesture_circle(ot);
+ WM_operator_properties_select_operation_simple(ot);
+}
+
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Lasso Select Operator
+ * \{ */
+
+static bool do_lasso_select_mesh_uv_is_point_inside(const ARegion *region,
+ const rcti *clip_rect,
+ const int mcoords[][2],
+ const int mcoords_len,
+ const float co_test[2])
+{
+ int co_screen[2];
+ if (UI_view2d_view_to_region_clip(
+ &region->v2d, co_test[0], co_test[1], &co_screen[0], &co_screen[1]) &&
+ BLI_rcti_isect_pt_v(clip_rect, co_screen) &&
+ BLI_lasso_is_point_inside(
+ mcoords, mcoords_len, co_screen[0], co_screen[1], V2D_IS_CLIPPED)) {
+ return true;
+ }
+ return false;
+}
+
+static bool do_lasso_select_mesh_uv(bContext *C,
+ const int mcoords[][2],
+ const int mcoords_len,
+ const eSelectOp sel_op)
+{
+ Depsgraph *depsgraph = CTX_data_ensure_evaluated_depsgraph(C);
+ SpaceImage *sima = CTX_wm_space_image(C);
+ const ARegion *region = CTX_wm_region(C);
+ Scene *scene = CTX_data_scene(C);
+ const ToolSettings *ts = scene->toolsettings;
+ ViewLayer *view_layer = CTX_data_view_layer(C);
+ const bool use_face_center = ((ts->uv_flag & UV_SYNC_SELECTION) ?
+ (ts->selectmode == SCE_SELECT_FACE) :
+ (ts->uv_selectmode == UV_SELECT_FACE));
+ const bool use_edge = ((ts->uv_flag & UV_SYNC_SELECTION) ?
+ (ts->selectmode == SCE_SELECT_EDGE) :
+ (ts->uv_selectmode == UV_SELECT_EDGE));
+
+ const bool select = (sel_op != SEL_OP_SUB);
+ const bool use_pre_deselect = SEL_OP_USE_PRE_DESELECT(sel_op);
+
+ BMIter iter, liter;
+
+ BMFace *efa;
+ BMLoop *l;
+ float limit[2];
+ bool changed_multi = false;
+ rcti rect;
+
+ uv_select_island_limit_default(sima, limit);
+
+ BLI_lasso_boundbox(&rect, mcoords, mcoords_len);
+
+ uint objects_len = 0;
+ Object **objects = BKE_view_layer_array_from_objects_in_edit_mode_unique_data_with_uvs(
+ view_layer, ((View3D *)NULL), &objects_len);
+
+ if (use_pre_deselect) {
+ uv_select_all_perform_multi(scene, objects, objects_len, SEL_DESELECT);
+ }
+
+ /* don't indent to avoid diff noise! */
+ for (uint ob_index = 0; ob_index < objects_len; ob_index++) {
+ Object *obedit = objects[ob_index];
+
+ bool changed = false;
+
+ BMEditMesh *em = BKE_editmesh_from_object(obedit);
+
+ const int cd_loop_uv_offset = CustomData_get_offset(&em->bm->ldata, CD_MLOOPUV);
+
+ if (use_face_center) { /* Face Center Sel */
+ BM_ITER_MESH (efa, &iter, em->bm, BM_FACES_OF_MESH) {
+ BM_elem_flag_disable(efa, BM_ELEM_TAG);
+ /* assume not touched */
+ if (select != uvedit_face_select_test(scene, efa, cd_loop_uv_offset)) {
+ float cent[2];
+ uv_poly_center(efa, cent, cd_loop_uv_offset);
+ if (do_lasso_select_mesh_uv_is_point_inside(region, &rect, mcoords, mcoords_len, cent)) {
+ BM_elem_flag_enable(efa, BM_ELEM_TAG);
+ changed = true;
+ }
+ }
+ }
+
+ /* (de)selects all tagged faces and deals with sticky modes */
+ if (changed) {
+ uv_select_flush_from_tag_face(sima, scene, obedit, select);
+ }
+ }
+ else if (use_edge) {
+ BM_mesh_elem_hflag_disable_all(em->bm, BM_VERT, BM_ELEM_TAG, false);
+
+ BM_ITER_MESH (efa, &iter, em->bm, BM_FACES_OF_MESH) {
+ if (!uvedit_face_visible_test(scene, efa)) {
+ continue;
+ }
+
+ BMLoop *l_prev = BM_FACE_FIRST_LOOP(efa)->prev;
+ MLoopUV *luv_prev = BM_ELEM_CD_GET_VOID_P(l_prev, cd_loop_uv_offset);
+ bool luv_select_prev = uvedit_uv_select_test(scene, l_prev, cd_loop_uv_offset);
+
+ BM_ITER_ELEM (l, &liter, efa, BM_LOOPS_OF_FACE) {
+ MLoopUV *luv = BM_ELEM_CD_GET_VOID_P(l, cd_loop_uv_offset);
+ const bool luv_select = uvedit_uv_select_test(scene, l, cd_loop_uv_offset);
+ if ((select != luv_select) || (select != luv_select_prev)) {
+ if (do_lasso_select_mesh_uv_is_point_inside(
+ region, &rect, mcoords, mcoords_len, luv->uv) &&
+ do_lasso_select_mesh_uv_is_point_inside(
+ region, &rect, mcoords, mcoords_len, luv_prev->uv)) {
+ uvedit_uv_select_set(em, scene, l, select, false, cd_loop_uv_offset);
+ uvedit_uv_select_set(em, scene, l_prev, select, false, cd_loop_uv_offset);
+ changed = true;
+ BM_elem_flag_enable(l->v, BM_ELEM_TAG);
+ BM_elem_flag_enable(l_prev->v, BM_ELEM_TAG);
+ }
+ }
+ l_prev = l;
+ luv_prev = luv;
+ luv_select_prev = luv_select;
+ }
+ }
+
+ if (sima->sticky == SI_STICKY_VERTEX) {
+ uvedit_vertex_select_tagged(em, scene, select, cd_loop_uv_offset);
+ }
+ }
+ else { /* Vert Sel */
+ BM_mesh_elem_hflag_disable_all(em->bm, BM_VERT, BM_ELEM_TAG, false);
+
+ BM_ITER_MESH (efa, &iter, em->bm, BM_FACES_OF_MESH) {
+ if (!uvedit_face_visible_test(scene, efa)) {
+ continue;
+ }
+ bool has_selected = false;
+ BM_ITER_ELEM (l, &liter, efa, BM_LOOPS_OF_FACE) {
+ if ((select) != (uvedit_uv_select_test(scene, l, cd_loop_uv_offset))) {
+ MLoopUV *luv = BM_ELEM_CD_GET_VOID_P(l, cd_loop_uv_offset);
+ if (do_lasso_select_mesh_uv_is_point_inside(
+ region, &rect, mcoords, mcoords_len, luv->uv)) {
+ uvedit_uv_select_set(em, scene, l, select, false, cd_loop_uv_offset);
+ changed = true;
+ BM_elem_flag_enable(l->v, BM_ELEM_TAG);
+ has_selected = true;
+ }
+ }
+ }
+ if (has_selected && ts->uv_selectmode == UV_SELECT_ISLAND) {
+ UvNearestHit hit = {
+ .ob = obedit,
+ .efa = efa,
+ };
+ uv_select_linked_multi(
+ scene, objects, objects_len, limit, &hit, true, !select, false, false);
+ }
+ }
+
+ if (sima->sticky == SI_STICKY_VERTEX) {
+ uvedit_vertex_select_tagged(em, scene, select, cd_loop_uv_offset);
+ }
+ }
+
+ if (changed || use_pre_deselect) {
+ changed_multi = true;
+
+ uv_select_sync_flush(ts, em, select);
+ uv_select_tag_update_for_object(depsgraph, ts, obedit);
+ }
+ }
+ MEM_freeN(objects);
+
+ return changed_multi;
+}
+
+static int uv_lasso_select_exec(bContext *C, wmOperator *op)
+{
+ int mcoords_len;
+ const int(*mcoords)[2] = WM_gesture_lasso_path_to_array(C, op, &mcoords_len);
+
+ if (mcoords) {
+ const eSelectOp sel_op = RNA_enum_get(op->ptr, "mode");
+ bool changed = do_lasso_select_mesh_uv(C, mcoords, mcoords_len, sel_op);
+ MEM_freeN((void *)mcoords);
+
+ return changed ? OPERATOR_FINISHED : OPERATOR_CANCELLED;
+ }
+
+ return OPERATOR_PASS_THROUGH;
+}
+
+void UV_OT_select_lasso(wmOperatorType *ot)
+{
+ ot->name = "Lasso Select UV";
+ ot->description = "Select UVs using lasso selection";
+ ot->idname = "UV_OT_select_lasso";
+
+ ot->invoke = WM_gesture_lasso_invoke;
+ ot->modal = WM_gesture_lasso_modal;
+ ot->exec = uv_lasso_select_exec;
+ ot->poll = ED_operator_uvedit_space_image;
+ ot->cancel = WM_gesture_lasso_cancel;
+
+ /* flags */
+ ot->flag = OPTYPE_UNDO;
+
+ /* properties */
+ WM_operator_properties_gesture_lasso(ot);
+ WM_operator_properties_select_operation_simple(ot);
+}
+
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Select Pinned UV's Operator
+ * \{ */
+
+static int uv_select_pinned_exec(bContext *C, wmOperator *UNUSED(op))
+{
+ Depsgraph *depsgraph = CTX_data_ensure_evaluated_depsgraph(C);
+ Scene *scene = CTX_data_scene(C);
+ const ToolSettings *ts = scene->toolsettings;
+ ViewLayer *view_layer = CTX_data_view_layer(C);
+ BMFace *efa;
+ BMLoop *l;
+ BMIter iter, liter;
+ MLoopUV *luv;
+
+ uint objects_len = 0;
+ Object **objects = BKE_view_layer_array_from_objects_in_edit_mode_unique_data_with_uvs(
+ view_layer, ((View3D *)NULL), &objects_len);
+
+ for (uint ob_index = 0; ob_index < objects_len; ob_index++) {
+ Object *obedit = objects[ob_index];
+ BMEditMesh *em = BKE_editmesh_from_object(obedit);
+
+ const int cd_loop_uv_offset = CustomData_get_offset(&em->bm->ldata, CD_MLOOPUV);
+ bool changed = false;
+
+ BM_ITER_MESH (efa, &iter, em->bm, BM_FACES_OF_MESH) {
+ if (!uvedit_face_visible_test(scene, efa)) {
+ continue;
+ }
+
+ BM_ITER_ELEM (l, &liter, efa, BM_LOOPS_OF_FACE) {
+ luv = BM_ELEM_CD_GET_VOID_P(l, cd_loop_uv_offset);
+
+ if (luv->flag & MLOOPUV_PINNED) {
+ uvedit_uv_select_enable(em, scene, l, false, cd_loop_uv_offset);
+ changed = true;
+ }
+ }
+ }
+
+ if (changed) {
+ uv_select_tag_update_for_object(depsgraph, ts, obedit);
+ }
+ }
+ MEM_freeN(objects);
+
+ return OPERATOR_FINISHED;
+}
+
+void UV_OT_select_pinned(wmOperatorType *ot)
+{
+ /* identifiers */
+ ot->name = "Selected Pinned";
+ ot->description = "Select all pinned UV vertices";
+ ot->idname = "UV_OT_select_pinned";
+ ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
+
+ /* api callbacks */
+ ot->exec = uv_select_pinned_exec;
+ ot->poll = ED_operator_uvedit;
+}
+
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Select Overlap Operator
+ * \{ */
+
+BLI_INLINE uint overlap_hash(const void *overlap_v)
+{
+ const BVHTreeOverlap *overlap = overlap_v;
+
+ /* Designed to treat (A,B) and (B,A) as the same. */
+ int x = overlap->indexA;
+ int y = overlap->indexB;
+ if (x > y) {
+ SWAP(int, x, y);
+ }
+ return BLI_hash_int_2d(x, y);
+}
+
+BLI_INLINE bool overlap_cmp(const void *a_v, const void *b_v)
+{
+ const BVHTreeOverlap *a = a_v;
+ const BVHTreeOverlap *b = b_v;
+ return !((a->indexA == b->indexA && a->indexB == b->indexB) ||
+ (a->indexA == b->indexB && a->indexB == b->indexA));
+}
+
+struct UVOverlapData {
+ int ob_index;
+ int face_index;
+ float tri[3][2];
+};
+
+static int uv_select_overlap(bContext *C, const bool extend)
+{
+ Depsgraph *depsgraph = CTX_data_ensure_evaluated_depsgraph(C);
+ Scene *scene = CTX_data_scene(C);
+ ViewLayer *view_layer = CTX_data_view_layer(C);
+
+ uint objects_len = 0;
+ Object **objects = BKE_view_layer_array_from_objects_in_edit_mode_unique_data_with_uvs(
+ view_layer, ((View3D *)NULL), &objects_len);
+
+ /* Calculate maximum number of tree nodes and prepare initial selection. */
+ uint uv_tri_len = 0;
+ for (uint ob_index = 0; ob_index < objects_len; ob_index++) {
+ Object *obedit = objects[ob_index];
+ BMEditMesh *em = BKE_editmesh_from_object(obedit);
+
+ BM_mesh_elem_table_ensure(em->bm, BM_FACE);
+ BM_mesh_elem_index_ensure(em->bm, BM_VERT | BM_FACE);
+ BM_mesh_elem_hflag_disable_all(em->bm, BM_FACE, BM_ELEM_TAG, false);
+ if (!extend) {
+ uv_select_all_perform(scene, obedit, SEL_DESELECT);
+ }
+
+ BMIter iter;
+ BMFace *efa;
+ BM_ITER_MESH (efa, &iter, em->bm, BM_FACES_OF_MESH) {
+ if (!uvedit_face_visible_test_ex(scene->toolsettings, efa)) {
+ continue;
+ }
+ uv_tri_len += efa->len - 2;
+ }
+ }
+
+ struct UVOverlapData *overlap_data = MEM_mallocN(sizeof(struct UVOverlapData) * uv_tri_len,
+ "UvOverlapData");
+ BVHTree *uv_tree = BLI_bvhtree_new(uv_tri_len, 0.0f, 4, 6);
+
+ /* Use a global data index when inserting into the BVH. */
+ int data_index = 0;
+
+ int face_len_alloc = 3;
+ float(*uv_verts)[2] = MEM_mallocN(sizeof(*uv_verts) * face_len_alloc, "UvOverlapCoords");
+ uint(*indices)[3] = MEM_mallocN(sizeof(*indices) * (face_len_alloc - 2), "UvOverlapTris");
+
+ for (uint ob_index = 0; ob_index < objects_len; ob_index++) {
+ Object *obedit = objects[ob_index];
+ BMEditMesh *em = BKE_editmesh_from_object(obedit);
+ BMIter iter, liter;
+ BMFace *efa;
+ BMLoop *l;
+
+ const int cd_loop_uv_offset = CustomData_get_offset(&em->bm->ldata, CD_MLOOPUV);
+
+ /* Triangulate each UV face and store it inside the BVH. */
+ int face_index;
+ BM_ITER_MESH_INDEX (efa, &iter, em->bm, BM_FACES_OF_MESH, face_index) {
+
+ if (!uvedit_face_visible_test_ex(scene->toolsettings, efa)) {
+ continue;
+ }
+
+ const uint face_len = efa->len;
+ const uint tri_len = face_len - 2;
+
+ if (face_len_alloc < face_len) {
+ MEM_freeN(uv_verts);
+ MEM_freeN(indices);
+ uv_verts = MEM_mallocN(sizeof(*uv_verts) * face_len, "UvOverlapCoords");
+ indices = MEM_mallocN(sizeof(*indices) * tri_len, "UvOverlapTris");
+ face_len_alloc = face_len;
+ }
+
+ int vert_index;
+ BM_ITER_ELEM_INDEX (l, &liter, efa, BM_LOOPS_OF_FACE, vert_index) {
+ MLoopUV *luv = BM_ELEM_CD_GET_VOID_P(l, cd_loop_uv_offset);
+ copy_v2_v2(uv_verts[vert_index], luv->uv);
+ }
+
+ BLI_polyfill_calc(uv_verts, face_len, 0, indices);
+
+ for (int t = 0; t < tri_len; t++) {
+ overlap_data[data_index].ob_index = ob_index;
+ overlap_data[data_index].face_index = face_index;
+
+ /* BVH needs 3D, overlap data uses 2D. */
+ const float tri[3][3] = {
+ {UNPACK2(uv_verts[indices[t][0]]), 0.0f},
+ {UNPACK2(uv_verts[indices[t][1]]), 0.0f},
+ {UNPACK2(uv_verts[indices[t][2]]), 0.0f},
+ };
+
+ copy_v2_v2(overlap_data[data_index].tri[0], tri[0]);
+ copy_v2_v2(overlap_data[data_index].tri[1], tri[1]);
+ copy_v2_v2(overlap_data[data_index].tri[2], tri[2]);
+
+ BLI_bvhtree_insert(uv_tree, data_index, &tri[0][0], 3);
+ data_index++;
+ }
+ }
+ }
+ BLI_assert(data_index == uv_tri_len);
+
+ MEM_freeN(uv_verts);
+ MEM_freeN(indices);
+
+ BLI_bvhtree_balance(uv_tree);
+
+ uint tree_overlap_len;
+ BVHTreeOverlap *overlap = BLI_bvhtree_overlap(uv_tree, uv_tree, &tree_overlap_len, NULL, NULL);
+
+ if (overlap != NULL) {
+ GSet *overlap_set = BLI_gset_new_ex(overlap_hash, overlap_cmp, __func__, tree_overlap_len);
+
+ for (int i = 0; i < tree_overlap_len; i++) {
+ /* Skip overlaps against yourself. */
+ if (overlap[i].indexA == overlap[i].indexB) {
+ continue;
+ }
+
+ /* Skip overlaps that have already been tested. */
+ if (!BLI_gset_add(overlap_set, &overlap[i])) {
+ continue;
+ }
+
+ const struct UVOverlapData *o_a = &overlap_data[overlap[i].indexA];
+ const struct UVOverlapData *o_b = &overlap_data[overlap[i].indexB];
+ Object *obedit_a = objects[o_a->ob_index];
+ Object *obedit_b = objects[o_b->ob_index];
+ BMEditMesh *em_a = BKE_editmesh_from_object(obedit_a);
+ BMEditMesh *em_b = BKE_editmesh_from_object(obedit_b);
+ BMFace *face_a = em_a->bm->ftable[o_a->face_index];
+ BMFace *face_b = em_b->bm->ftable[o_b->face_index];
+ const int cd_loop_uv_offset_a = CustomData_get_offset(&em_a->bm->ldata, CD_MLOOPUV);
+ const int cd_loop_uv_offset_b = CustomData_get_offset(&em_b->bm->ldata, CD_MLOOPUV);
+
+ /* Skip if both faces are already selected. */
+ if (uvedit_face_select_test(scene, face_a, cd_loop_uv_offset_a) &&
+ uvedit_face_select_test(scene, face_b, cd_loop_uv_offset_b)) {
+ continue;
+ }
+
+ /* Main tri-tri overlap test. */
+ const float endpoint_bias = -1e-4f;
+ const float(*t1)[2] = o_a->tri;
+ const float(*t2)[2] = o_b->tri;
+ float vi[2];
+ bool result = (
+ /* Don't use 'isect_tri_tri_v2' here
+ * because it's important to ignore overlap at end-points. */
+ isect_seg_seg_v2_point_ex(t1[0], t1[1], t2[0], t2[1], endpoint_bias, vi) == 1 ||
+ isect_seg_seg_v2_point_ex(t1[0], t1[1], t2[1], t2[2], endpoint_bias, vi) == 1 ||
+ isect_seg_seg_v2_point_ex(t1[0], t1[1], t2[2], t2[0], endpoint_bias, vi) == 1 ||
+ isect_seg_seg_v2_point_ex(t1[1], t1[2], t2[0], t2[1], endpoint_bias, vi) == 1 ||
+ isect_seg_seg_v2_point_ex(t1[1], t1[2], t2[1], t2[2], endpoint_bias, vi) == 1 ||
+ isect_seg_seg_v2_point_ex(t1[1], t1[2], t2[2], t2[0], endpoint_bias, vi) == 1 ||
+ isect_seg_seg_v2_point_ex(t1[2], t1[0], t2[0], t2[1], endpoint_bias, vi) == 1 ||
+ isect_seg_seg_v2_point_ex(t1[2], t1[0], t2[1], t2[2], endpoint_bias, vi) == 1 ||
+ isect_point_tri_v2(t1[0], t2[0], t2[1], t2[2]) != 0 ||
+ isect_point_tri_v2(t2[0], t1[0], t1[1], t1[2]) != 0);
+
+ if (result) {
+ uvedit_face_select_enable(scene, em_a, face_a, false, cd_loop_uv_offset_a);
+ uvedit_face_select_enable(scene, em_b, face_b, false, cd_loop_uv_offset_b);
+ }
+ }
+
+ BLI_gset_free(overlap_set, NULL);
+ MEM_freeN(overlap);
+ }
+
+ for (uint ob_index = 0; ob_index < objects_len; ob_index++) {
+ uv_select_tag_update_for_object(depsgraph, scene->toolsettings, objects[ob_index]);
+ }
+
+ BLI_bvhtree_free(uv_tree);
+
+ MEM_freeN(overlap_data);
+ MEM_freeN(objects);
+
+ return OPERATOR_FINISHED;
+}
+
+static int uv_select_overlap_exec(bContext *C, wmOperator *op)
+{
+ bool extend = RNA_boolean_get(op->ptr, "extend");
+ return uv_select_overlap(C, extend);
+}
+
+void UV_OT_select_overlap(wmOperatorType *ot)
+{
+ /* identifiers */
+ ot->name = "Select Overlap";
+ ot->description = "Select all UV faces which overlap each other";
+ ot->idname = "UV_OT_select_overlap";
+ ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
+
+ /* api callbacks */
+ ot->exec = uv_select_overlap_exec;
+ ot->poll = ED_operator_uvedit;
+
+ /* properties */
+ RNA_def_boolean(ot->srna,
+ "extend",
+ 0,
+ "Extend",
+ "Extend selection rather than clearing the existing selection");
+}
+
+/** \} */
diff --git a/source/blender/editors/uvedit/uvedit_smart_stitch.c b/source/blender/editors/uvedit/uvedit_smart_stitch.c
index cf23cac38a7..594847b7249 100644
--- a/source/blender/editors/uvedit/uvedit_smart_stitch.c
+++ b/source/blender/editors/uvedit/uvedit_smart_stitch.c
@@ -75,20 +75,20 @@ typedef struct StitchPreviewer {
/* here we'll store the preview triangle indices of the mesh */
float *preview_polys;
/* uvs per polygon. */
- unsigned int *uvs_per_polygon;
+ uint *uvs_per_polygon;
/*number of preview polygons */
- unsigned int num_polys;
+ uint num_polys;
/* preview data. These will be either the previewed vertices or edges
* depending on stitch mode settings */
float *preview_stitchable;
float *preview_unstitchable;
/* here we'll store the number of elements to be drawn */
- unsigned int num_stitchable;
- unsigned int num_unstitchable;
- unsigned int preview_uvs;
+ uint num_stitchable;
+ uint num_unstitchable;
+ uint preview_uvs;
/* ...and here we'll store the static island triangles */
float *static_tris;
- unsigned int num_static_tris;
+ uint num_static_tris;
} StitchPreviewer;
struct IslandStitchData;
@@ -119,16 +119,16 @@ typedef struct IslandStitchData {
/* just for averaging UVs */
typedef struct UVVertAverage {
float uv[2];
- unsigned short count;
+ ushort count;
} UVVertAverage;
typedef struct UvEdge {
/** index to uv buffer */
- unsigned int uv1;
- unsigned int uv2;
+ uint uv1;
+ uint uv2;
/** general use flag
* (Used to check if edge is boundary here, and propagates to adjacency elements) */
- unsigned char flag;
+ uchar flag;
/** element that guarantees element->face
* has the edge on element->tfindex and element->tfindex+1 is the second uv */
UvElement *element;
@@ -172,7 +172,7 @@ typedef struct StitchState {
int selection_size;
/* store number of primitives per face so that we can allocate the active island buffer later */
- unsigned int *tris_per_island;
+ uint *tris_per_island;
/* preview data */
StitchPreviewer *stitch_preview;
} StitchState;
@@ -299,9 +299,9 @@ static void stitch_update_header(StitchStateContainer *ssc, bContext *C)
"shift select vertices");
char msg[UI_MAX_DRAW_STR];
- ScrArea *sa = CTX_wm_area(C);
+ ScrArea *area = CTX_wm_area(C);
- if (sa) {
+ if (area) {
BLI_snprintf(msg,
sizeof(msg),
str,
@@ -544,7 +544,7 @@ static void stitch_island_calculate_edge_rotation(UvEdge *edge,
StitchStateContainer *ssc,
StitchState *state,
UVVertAverage *uv_average,
- unsigned int *uvfinal_map,
+ uint *uvfinal_map,
IslandStitchData *island_stitch_data)
{
BMesh *bm = state->em->bm;
@@ -1032,7 +1032,7 @@ static int stitch_process_data(StitchStateContainer *ssc,
char stitch_midpoints = ssc->midpoints;
/* used to map uv indices to uvaverage indices for selection */
- unsigned int *uvfinal_map = NULL;
+ uint *uvfinal_map = NULL;
/* per face preview position in preview buffer */
PreviewPosition *preview_position = NULL;
@@ -1229,7 +1229,7 @@ static int stitch_process_data(StitchStateContainer *ssc,
BMIter liter;
BMLoop *l;
MLoopUV *luv;
- unsigned int buffer_index = 0;
+ uint buffer_index = 0;
/* initialize the preview buffers */
preview->preview_polys = MEM_mallocN(preview->preview_uvs * sizeof(float) * 2,
@@ -1575,7 +1575,7 @@ static int stitch_process_data_all(StitchStateContainer *ssc, Scene *scene, int
}
/* Stitch hash initialization functions */
-static unsigned int uv_edge_hash(const void *key)
+static uint uv_edge_hash(const void *key)
{
const UvEdge *edge = key;
return (BLI_ghashutil_uinthash(edge->uv2) + BLI_ghashutil_uinthash(edge->uv1));
@@ -1760,14 +1760,14 @@ static void stitch_draw(const bContext *UNUSED(C), ARegion *UNUSED(region), void
for (uint ob_index = 0; ob_index < ssc->objects_len; ob_index++) {
int j, index = 0;
- unsigned int num_line = 0, num_tri, tri_idx = 0, line_idx = 0;
+ uint num_line = 0, num_tri, tri_idx = 0, line_idx = 0;
StitchState *state = ssc->states[ob_index];
StitchPreviewer *stitch_preview = state->stitch_preview;
GPUVertBuf *vbo, *vbo_line;
float col[4];
static GPUVertFormat format = {0};
- static unsigned int pos_id;
+ static uint pos_id;
if (format.attr_len == 0) {
pos_id = GPU_vertformat_attr_add(&format, "pos", GPU_COMP_F32, 2, GPU_FETCH_FLOAT);
}
@@ -2438,7 +2438,7 @@ static void stitch_exit(bContext *C, wmOperator *op, int finished)
{
Scene *scene = CTX_data_scene(C);
SpaceImage *sima = CTX_wm_space_image(C);
- ScrArea *sa = CTX_wm_area(C);
+ ScrArea *area = CTX_wm_area(C);
StitchStateContainer *ssc = (StitchStateContainer *)op->customdata;
@@ -2492,7 +2492,7 @@ static void stitch_exit(bContext *C, wmOperator *op, int finished)
MEM_freeN(objs_selection_count);
}
- if (sa) {
+ if (area) {
ED_workspace_status_text(C, NULL);
}
@@ -2550,12 +2550,11 @@ static StitchState *stitch_select(bContext *C,
float co[2];
UvNearestHit hit = UV_NEAREST_HIT_INIT;
ARegion *region = CTX_wm_region(C);
- Image *ima = CTX_data_edit_image(C);
UI_view2d_region_to_view(&region->v2d, event->mval[0], event->mval[1], &co[0], &co[1]);
if (ssc->mode == STITCH_VERT) {
- if (uv_find_nearest_vert_multi(scene, ima, ssc->objects, ssc->objects_len, co, 0.0f, &hit)) {
+ if (uv_find_nearest_vert_multi(scene, ssc->objects, ssc->objects_len, co, 0.0f, &hit)) {
/* Add vertex to selection, deselect all common uv's of vert other than selected and
* update the preview. This behavior was decided so that you can do stuff like deselect
* the opposite stitchable vertex and the initial still gets deselected */
@@ -2576,7 +2575,7 @@ static StitchState *stitch_select(bContext *C,
return state;
}
}
- else if (uv_find_nearest_edge_multi(scene, ima, ssc->objects, ssc->objects_len, co, &hit)) {
+ else if (uv_find_nearest_edge_multi(scene, ssc->objects, ssc->objects_len, co, &hit)) {
/* find StitchState from hit->ob */
StitchState *state = NULL;
for (uint ob_index = 0; ob_index < ssc->objects_len; ob_index++) {
diff --git a/source/blender/editors/uvedit/uvedit_unwrap_ops.c b/source/blender/editors/uvedit/uvedit_unwrap_ops.c
index 8ded2c16be8..c4dcaaaa8b2 100644
--- a/source/blender/editors/uvedit/uvedit_unwrap_ops.c
+++ b/source/blender/editors/uvedit/uvedit_unwrap_ops.c
@@ -708,7 +708,7 @@ static bool minimize_stretch_init(bContext *C, wmOperator *op)
static void minimize_stretch_iteration(bContext *C, wmOperator *op, bool interactive)
{
MinStretch *ms = op->customdata;
- ScrArea *sa = CTX_wm_area(C);
+ ScrArea *area = CTX_wm_area(C);
const Scene *scene = CTX_data_scene(C);
ToolSettings *ts = scene->toolsettings;
const bool synced_selection = (ts->uv_flag & UV_SYNC_SELECTION) != 0;
@@ -724,9 +724,9 @@ static void minimize_stretch_iteration(bContext *C, wmOperator *op, bool interac
param_flush(ms->handle);
- if (sa) {
+ if (area) {
BLI_snprintf(str, sizeof(str), TIP_("Minimize Stretch. Blend %.2f"), ms->blend);
- ED_area_status_text(sa, str);
+ ED_area_status_text(area, str);
ED_workspace_status_text(C, TIP_("Press + and -, or scroll wheel to set blending"));
}
@@ -749,12 +749,12 @@ static void minimize_stretch_iteration(bContext *C, wmOperator *op, bool interac
static void minimize_stretch_exit(bContext *C, wmOperator *op, bool cancel)
{
MinStretch *ms = op->customdata;
- ScrArea *sa = CTX_wm_area(C);
+ ScrArea *area = CTX_wm_area(C);
const Scene *scene = CTX_data_scene(C);
ToolSettings *ts = scene->toolsettings;
const bool synced_selection = (ts->uv_flag & UV_SYNC_SELECTION) != 0;
- ED_area_status_text(sa, NULL);
+ ED_area_status_text(area, NULL);
ED_workspace_status_text(C, NULL);
if (ms->timer) {
diff --git a/source/blender/freestyle/FRS_precomp.h b/source/blender/freestyle/FRS_precomp.h
index 52f5b58aed0..64eac955fc9 100644
--- a/source/blender/freestyle/FRS_precomp.h
+++ b/source/blender/freestyle/FRS_precomp.h
@@ -1,26 +1,27 @@
/* Pre-compiled headers, see: D2606. */
-/* clang-format off */
#include <Python.h>
-#include <pthread.h>
-#include <string>
-#include <vector>
-#include <iostream>
-#include <math.h>
-#include <stdbool.h>
+
#include <algorithm>
-#include <time.h>
+#include <deque>
+#include <fstream>
+#include <iomanip>
+#include <iostream>
#include <iterator>
+#include <list>
+#include <map>
+#include <math.h>
#include <memory>
+#include <pthread.h>
#include <set>
-#include <map>
-#include <list>
-#include <deque>
#include <sstream>
-#include <stdarg.h>
-#include <fstream>
-#include <iomanip>
#include <stack>
+#include <stdarg.h>
+#include <stdbool.h>
+#include <string>
+#include <time.h>
+#include <vector>
+
#include "intern/python/BPy_BBox.h"
#include "intern/python/BPy_BinaryPredicate0D.h"
#include "intern/python/BPy_BinaryPredicate1D.h"
@@ -47,5 +48,3 @@
#include "intern/python/BPy_ViewMap.h"
#include "intern/python/BPy_ViewShape.h"
#include "intern/python/Director.h"
-
-/* clang-format on */
diff --git a/source/blender/freestyle/intern/application/AppCanvas.cpp b/source/blender/freestyle/intern/application/AppCanvas.cpp
index 1f3aea65e24..5681c65e5d2 100644
--- a/source/blender/freestyle/intern/application/AppCanvas.cpp
+++ b/source/blender/freestyle/intern/application/AppCanvas.cpp
@@ -18,18 +18,17 @@
* \ingroup freestyle
*/
-/* clang-format off */
-#include "Controller.h"
+#include "AppCanvas.h"
+#include "AppConfig.h"
#include "AppView.h"
+#include "Controller.h"
+
#include "../image/Image.h"
-#include "../system/TimeStamp.h"
#include "../stroke/StrokeRenderer.h"
-#include "AppCanvas.h"
-#include "AppConfig.h"
#include "../stroke/StyleModule.h"
+#include "../system/TimeStamp.h"
#include "../system/StringUtils.h"
-/* clang-format on */
namespace Freestyle {
AppCanvas::AppCanvas() : Canvas()
diff --git a/source/blender/freestyle/intern/application/AppConfig.h b/source/blender/freestyle/intern/application/AppConfig.h
index 725b29e7dd8..34f5d220cfe 100644
--- a/source/blender/freestyle/intern/application/AppConfig.h
+++ b/source/blender/freestyle/intern/application/AppConfig.h
@@ -22,15 +22,14 @@
* \brief Configuration file
*/
-/* clang-format off */
-#include <string>
#include <algorithm>
+#include <string>
+
#include "../system/Precision.h"
#ifdef WITH_CXX_GUARDEDALLOC
# include "MEM_guardedalloc.h"
#endif
-/* clang-format on */
using namespace std;
diff --git a/source/blender/freestyle/intern/application/AppView.cpp b/source/blender/freestyle/intern/application/AppView.cpp
index 771d4b0fca8..0956d33a20e 100644
--- a/source/blender/freestyle/intern/application/AppView.cpp
+++ b/source/blender/freestyle/intern/application/AppView.cpp
@@ -18,20 +18,20 @@
* \ingroup freestyle
*/
-/* clang-format off */
#include <iostream>
-#include "Controller.h"
#include "AppConfig.h"
#include "AppView.h"
-#include "../view_map/Silhouette.h"
-#include "../view_map/ViewMap.h"
+#include "Controller.h"
+
#include "../scene_graph/LineRep.h"
#include "../scene_graph/NodeLight.h"
#include "../scene_graph/NodeShape.h"
#include "../scene_graph/VertexRep.h"
#include "../stroke/Canvas.h"
#include "../system/StringUtils.h"
+#include "../view_map/Silhouette.h"
+#include "../view_map/ViewMap.h"
extern "C" {
#include "BLI_blenlib.h"
@@ -46,7 +46,6 @@ extern "C" {
#include "FRS_freestyle.h"
}
-/* clang-format on */
namespace Freestyle {
diff --git a/source/blender/freestyle/intern/application/AppView.h b/source/blender/freestyle/intern/application/AppView.h
index 4c60b1515f3..6009f2b0e50 100644
--- a/source/blender/freestyle/intern/application/AppView.h
+++ b/source/blender/freestyle/intern/application/AppView.h
@@ -21,10 +21,10 @@
* \ingroup freestyle
*/
-/* clang-format off */
#include "AppConfig.h"
-#include "../geometry/Geom.h"
+
#include "../geometry/BBox.h"
+#include "../geometry/Geom.h"
#include "../scene_graph/NodeDrawingStyle.h"
#include "../system/Precision.h"
@@ -33,7 +33,6 @@
#ifdef WITH_CXX_GUARDEDALLOC
# include "MEM_guardedalloc.h"
#endif
-/* clang-format on */
namespace Freestyle {
diff --git a/source/blender/freestyle/intern/application/Controller.cpp b/source/blender/freestyle/intern/application/Controller.cpp
index f7da64624e0..253d62ea3dc 100644
--- a/source/blender/freestyle/intern/application/Controller.cpp
+++ b/source/blender/freestyle/intern/application/Controller.cpp
@@ -18,18 +18,17 @@
* \ingroup freestyle
*/
-/* clang-format off */
extern "C" {
#include <Python.h>
}
-#include <string>
-#include <fstream>
#include <float.h>
+#include <fstream>
+#include <string>
-#include "AppView.h"
#include "AppCanvas.h"
#include "AppConfig.h"
+#include "AppView.h"
#include "Controller.h"
#include "../image/Image.h"
@@ -42,12 +41,12 @@ extern "C" {
#include "../scene_graph/VertexRep.h"
#include "../stroke/PSStrokeRenderer.h"
-#include "../stroke/TextStrokeRenderer.h"
#include "../stroke/StrokeTesselator.h"
#include "../stroke/StyleModule.h"
+#include "../stroke/TextStrokeRenderer.h"
-#include "../system/StringUtils.h"
#include "../system/PythonInterpreter.h"
+#include "../system/StringUtils.h"
#include "../view_map/SteerableViewMap.h"
#include "../view_map/ViewMap.h"
@@ -56,21 +55,20 @@ extern "C" {
#include "../winged_edge/Curvature.h"
#include "../winged_edge/WEdge.h"
-#include "../winged_edge/WingedEdgeBuilder.h"
#include "../winged_edge/WXEdgeBuilder.h"
+#include "../winged_edge/WingedEdgeBuilder.h"
#include "../blender_interface/BlenderFileLoader.h"
#include "../blender_interface/BlenderStrokeRenderer.h"
#include "../blender_interface/BlenderStyleModule.h"
#include "BKE_global.h"
-#include "BLI_utildefines.h"
#include "BLI_path_util.h"
+#include "BLI_utildefines.h"
#include "DNA_freestyle_types.h"
#include "FRS_freestyle.h"
-/* clang-format off */
namespace Freestyle {
@@ -349,7 +347,7 @@ int Controller::LoadMesh(Render *re, ViewLayer *view_layer, Depsgraph *depsgraph
soc string basename((const char *)qfi.fileName().toAscii().data());
char cleaned[FILE_MAX];
BLI_strncpy(cleaned, iFileName, FILE_MAX);
- BLI_cleanup_path(NULL, cleaned);
+ BLI_path_normalize(NULL, cleaned);
string basename = string(cleaned);
#endif
@@ -925,19 +923,16 @@ Render *Controller::RenderStrokes(Render *re, bool render)
cout << "Stroke rendering : " << d << endl;
uintptr_t mem_in_use = MEM_get_memory_in_use();
- uintptr_t mmap_in_use = MEM_get_mapped_memory_in_use();
uintptr_t peak_memory = MEM_get_peak_memory();
- float megs_used_memory = (mem_in_use - mmap_in_use) / (1024.0 * 1024.0);
- float mmap_used_memory = (mmap_in_use) / (1024.0 * 1024.0);
+ float megs_used_memory = (mem_in_use) / (1024.0 * 1024.0);
float megs_peak_memory = (peak_memory) / (1024.0 * 1024.0);
- printf("%d objs, %d verts, %d faces, mem %.2fM (%.2fM, peak %.2fM)\n",
+ printf("%d objs, %d verts, %d faces, mem %.2fM (peak %.2fM)\n",
totmesh,
freestyle_render->i.totvert,
freestyle_render->i.totface,
megs_used_memory,
- mmap_used_memory,
megs_peak_memory);
}
delete blenderRenderer;
diff --git a/source/blender/freestyle/intern/blender_interface/BlenderFileLoader.cpp b/source/blender/freestyle/intern/blender_interface/BlenderFileLoader.cpp
index f49a664096a..7bceb036846 100644
--- a/source/blender/freestyle/intern/blender_interface/BlenderFileLoader.cpp
+++ b/source/blender/freestyle/intern/blender_interface/BlenderFileLoader.cpp
@@ -85,6 +85,7 @@ NodeGroup *BlenderFileLoader::Load()
#endif
int id = 0;
+ const eEvaluationMode eval_mode = DEG_get_mode(_depsgraph);
DEG_OBJECT_ITER_BEGIN (_depsgraph,
ob,
@@ -99,6 +100,10 @@ NodeGroup *BlenderFileLoader::Load()
continue;
}
+ if (!(BKE_object_visibility(ob, eval_mode) & OB_VISIBLE_SELF)) {
+ continue;
+ }
+
Mesh *mesh = BKE_object_to_mesh(NULL, ob, false);
if (mesh) {
diff --git a/source/blender/freestyle/intern/blender_interface/BlenderFileLoader.h b/source/blender/freestyle/intern/blender_interface/BlenderFileLoader.h
index fe93b179eb6..ad6379d5f52 100644
--- a/source/blender/freestyle/intern/blender_interface/BlenderFileLoader.h
+++ b/source/blender/freestyle/intern/blender_interface/BlenderFileLoader.h
@@ -21,9 +21,8 @@
* \ingroup freestyle
*/
-/* clang-format off */
-#include <string.h>
#include <float.h>
+#include <string.h>
#include "../geometry/BBox.h"
#include "../geometry/Geom.h"
@@ -31,8 +30,8 @@
#include "../geometry/GeomUtils.h"
#include "../scene_graph/IndexedFaceSet.h"
#include "../scene_graph/NodeGroup.h"
-#include "../scene_graph/NodeTransform.h"
#include "../scene_graph/NodeShape.h"
+#include "../scene_graph/NodeTransform.h"
#include "../system/FreestyleConfig.h"
#include "../system/RenderMonitor.h"
@@ -64,7 +63,6 @@ extern "C" {
#ifdef WITH_CXX_GUARDEDALLOC
# include "MEM_guardedalloc.h"
#endif
-/* clang-format on */
namespace Freestyle {
diff --git a/source/blender/freestyle/intern/blender_interface/BlenderStrokeRenderer.cpp b/source/blender/freestyle/intern/blender_interface/BlenderStrokeRenderer.cpp
index a61bad7cf8a..68b5b4baeca 100644
--- a/source/blender/freestyle/intern/blender_interface/BlenderStrokeRenderer.cpp
+++ b/source/blender/freestyle/intern/blender_interface/BlenderStrokeRenderer.cpp
@@ -18,7 +18,6 @@
* \ingroup freestyle
*/
-/* clang-format off */
#include "BlenderStrokeRenderer.h"
#include "../application/AppConfig.h"
@@ -26,7 +25,6 @@
#include "MEM_guardedalloc.h"
-extern "C" {
#include "RNA_access.h"
#include "RNA_types.h"
@@ -65,10 +63,8 @@ extern "C" {
#include "RE_pipeline.h"
#include "render_types.h"
-}
#include <limits.h>
-/* clang-format on */
namespace Freestyle {
@@ -465,7 +461,7 @@ void BlenderStrokeRenderer::RenderStrokeRepBasic(StrokeRep *iStrokeRep) const
vector<StrokeGroup *> *groups = hasTex ? &self->texturedStrokeGroups : &self->strokeGroups;
StrokeGroup *group;
if (groups->empty() || !(groups->back()->totvert + totvert < MESH_MAX_VERTS &&
- groups->back()->totcol + 1 < MAXMAT)) {
+ groups->back()->materials.size() + 1 < MAXMAT)) {
group = new StrokeGroup;
groups->push_back(group);
}
@@ -477,7 +473,10 @@ void BlenderStrokeRenderer::RenderStrokeRepBasic(StrokeRep *iStrokeRep) const
group->totedge += totedge;
group->totpoly += totpoly;
group->totloop += totloop;
- group->totcol++;
+
+ if (!group->materials.contains(ma)) {
+ group->materials.add_new(ma, group->materials.size());
+ }
}
// Check if the triangle is visible (i.e., within the render image boundary)
@@ -589,7 +588,7 @@ void BlenderStrokeRenderer::GenerateStrokeMesh(StrokeGroup *group, bool hasTex)
mesh->totedge = group->totedge;
mesh->totpoly = group->totpoly;
mesh->totloop = group->totloop;
- mesh->totcol = group->totcol;
+ mesh->totcol = group->materials.size();
mesh->mvert = (MVert *)CustomData_add_layer(
&mesh->vdata, CD_MVERT, CD_CALLOC, NULL, mesh->totvert);
@@ -630,12 +629,20 @@ void BlenderStrokeRenderer::GenerateStrokeMesh(StrokeGroup *group, bool hasTex)
mesh->mloopcol = colors;
mesh->mat = (Material **)MEM_mallocN(sizeof(Material *) * mesh->totcol, "MaterialList");
+ for (const auto &item : group->materials.items()) {
+ Material *material = item.key;
+ const int matnr = item.value;
+ mesh->mat[matnr] = material;
+ if (material) {
+ id_us_plus(&material->id);
+ }
+ }
////////////////////
// Data copy
////////////////////
- int vertex_index = 0, edge_index = 0, loop_index = 0, material_index = 0;
+ int vertex_index = 0, edge_index = 0, loop_index = 0;
int visible_faces, visible_segments;
bool visible;
Strip::vertex_container::iterator v[3];
@@ -646,8 +653,7 @@ void BlenderStrokeRenderer::GenerateStrokeMesh(StrokeGroup *group, bool hasTex)
itend = group->strokes.end();
it != itend;
++it) {
- mesh->mat[material_index] = (*it)->getMaterial();
- id_us_plus(&mesh->mat[material_index]->id);
+ const int matnr = group->materials.lookup_default((*it)->getMaterial(), 0);
vector<Strip *> &strips = (*it)->getStrips();
for (vector<Strip *>::const_iterator s = strips.begin(), send = strips.end(); s != send; ++s) {
@@ -729,7 +735,7 @@ void BlenderStrokeRenderer::GenerateStrokeMesh(StrokeGroup *group, bool hasTex)
// poly
polys->loopstart = loop_index;
polys->totloop = 3;
- polys->mat_nr = material_index;
+ polys->mat_nr = matnr;
++polys;
// Even and odd loops connect triangles vertices differently
@@ -814,8 +820,7 @@ void BlenderStrokeRenderer::GenerateStrokeMesh(StrokeGroup *group, bool hasTex)
}
} // loop over strip vertices
} // loop over strips
- material_index++;
- } // loop over strokes
+ } // loop over strokes
BKE_object_materials_test(freestyle_bmain, object_mesh, (ID *)mesh);
@@ -823,7 +828,6 @@ void BlenderStrokeRenderer::GenerateStrokeMesh(StrokeGroup *group, bool hasTex)
BLI_assert(mesh->totvert == vertex_index);
BLI_assert(mesh->totedge == edge_index);
BLI_assert(mesh->totloop == loop_index);
- BLI_assert(mesh->totcol == material_index);
BKE_mesh_validate(mesh, true, true);
#endif
}
diff --git a/source/blender/freestyle/intern/blender_interface/BlenderStrokeRenderer.h b/source/blender/freestyle/intern/blender_interface/BlenderStrokeRenderer.h
index c333319ada1..ee29519c849 100644
--- a/source/blender/freestyle/intern/blender_interface/BlenderStrokeRenderer.h
+++ b/source/blender/freestyle/intern/blender_interface/BlenderStrokeRenderer.h
@@ -21,6 +21,8 @@
* \ingroup freestyle
*/
+#include "BLI_map.hh"
+
#include "../stroke/StrokeRenderer.h"
#include "../system/FreestyleConfig.h"
@@ -50,15 +52,15 @@ class BlenderStrokeRenderer : public StrokeRenderer {
Object *NewMesh() const;
struct StrokeGroup {
- explicit StrokeGroup() : totvert(0), totedge(0), totpoly(0), totloop(0), totcol(0)
+ explicit StrokeGroup() : totvert(0), totedge(0), totpoly(0), totloop(0)
{
}
vector<StrokeRep *> strokes;
+ BLI::Map<Material *, int> materials;
int totvert;
int totedge;
int totpoly;
int totloop;
- int totcol;
};
vector<StrokeGroup *> strokeGroups, texturedStrokeGroups;
diff --git a/source/blender/freestyle/intern/blender_interface/BlenderStyleModule.h b/source/blender/freestyle/intern/blender_interface/BlenderStyleModule.h
index a4beb1c119c..95612a42722 100644
--- a/source/blender/freestyle/intern/blender_interface/BlenderStyleModule.h
+++ b/source/blender/freestyle/intern/blender_interface/BlenderStyleModule.h
@@ -24,11 +24,9 @@
#include "../stroke/StyleModule.h"
#include "../system/PythonInterpreter.h"
-extern "C" {
#include "BLI_utildefines.h" // BLI_assert()
struct Text;
-}
namespace Freestyle {
diff --git a/source/blender/freestyle/intern/geometry/BBox.h b/source/blender/freestyle/intern/geometry/BBox.h
index 0031a7ce860..a8965e63451 100644
--- a/source/blender/freestyle/intern/geometry/BBox.h
+++ b/source/blender/freestyle/intern/geometry/BBox.h
@@ -22,16 +22,14 @@
* \brief A class to hold a bounding box
*/
-/* clang-format off */
-#include <stdlib.h>
#include <algorithm>
+#include <stdlib.h>
#include "BLI_utildefines.h"
#ifdef WITH_CXX_GUARDEDALLOC
# include "MEM_guardedalloc.h"
#endif
-/* clang-format on */
namespace Freestyle {
diff --git a/source/blender/freestyle/intern/geometry/FitCurve.cpp b/source/blender/freestyle/intern/geometry/FitCurve.cpp
index bfc5e16aa2a..b60de93c4a1 100644
--- a/source/blender/freestyle/intern/geometry/FitCurve.cpp
+++ b/source/blender/freestyle/intern/geometry/FitCurve.cpp
@@ -20,13 +20,11 @@
* \brief from "Graphics Gems", Academic Press, 1990
*/
-/* clang-format off */
#include <cstdlib> // for malloc and free
-#include <stdio.h>
#include <math.h>
+#include <stdio.h>
#include "FitCurve.h"
-/* clang-format on */
using namespace std;
diff --git a/source/blender/freestyle/intern/geometry/GeomCleaner.cpp b/source/blender/freestyle/intern/geometry/GeomCleaner.cpp
index a7db17a4015..76e63764e4d 100644
--- a/source/blender/freestyle/intern/geometry/GeomCleaner.cpp
+++ b/source/blender/freestyle/intern/geometry/GeomCleaner.cpp
@@ -19,7 +19,6 @@
* \brief Class to define a cleaner of geometry providing a set of useful tools
*/
-/* clang-format off */
#if 0
# if defined(__GNUC__) && (__GNUC__ >= 3)
// hash_map is not part of the C++ standard anymore;
@@ -30,16 +29,15 @@
# endif
#endif
-#include <stdio.h>
#include <list>
#include <map>
+#include <stdio.h>
#include "GeomCleaner.h"
#include "../system/TimeUtils.h"
#include "BKE_global.h"
-/* clang-format on */
using namespace std;
diff --git a/source/blender/freestyle/intern/geometry/Grid.h b/source/blender/freestyle/intern/geometry/Grid.h
index 0a9fa5dc85a..c1a8dcdb370 100644
--- a/source/blender/freestyle/intern/geometry/Grid.h
+++ b/source/blender/freestyle/intern/geometry/Grid.h
@@ -33,9 +33,7 @@
#include "../system/FreestyleConfig.h"
-extern "C" {
#include "BLI_utildefines.h"
-}
#ifdef WITH_CXX_GUARDEDALLOC
# include "MEM_guardedalloc.h"
diff --git a/source/blender/freestyle/intern/geometry/normal_cycle.cpp b/source/blender/freestyle/intern/geometry/normal_cycle.cpp
index 5820bdc4865..d02b5cc2d5b 100644
--- a/source/blender/freestyle/intern/geometry/normal_cycle.cpp
+++ b/source/blender/freestyle/intern/geometry/normal_cycle.cpp
@@ -29,10 +29,8 @@
* \ingroup freestyle
*/
-/* clang-format off */
-#include "matrix_util.h"
#include "normal_cycle.h"
-/* clang-format on */
+#include "matrix_util.h"
namespace Freestyle {
diff --git a/source/blender/freestyle/intern/image/GaussianFilter.h b/source/blender/freestyle/intern/image/GaussianFilter.h
index f8e2524fa4f..625e357eddf 100644
--- a/source/blender/freestyle/intern/image/GaussianFilter.h
+++ b/source/blender/freestyle/intern/image/GaussianFilter.h
@@ -27,9 +27,7 @@
#include "../system/FreestyleConfig.h"
-extern "C" {
#include "BLI_math.h"
-}
#ifdef WITH_CXX_GUARDEDALLOC
# include "MEM_guardedalloc.h"
diff --git a/source/blender/freestyle/intern/scene_graph/NodeViewLayer.h b/source/blender/freestyle/intern/scene_graph/NodeViewLayer.h
index f220bbfd6f1..2339abe9aed 100644
--- a/source/blender/freestyle/intern/scene_graph/NodeViewLayer.h
+++ b/source/blender/freestyle/intern/scene_graph/NodeViewLayer.h
@@ -24,9 +24,7 @@
#include "Node.h"
-extern "C" {
#include "DNA_scene_types.h" /* for Scene and ViewLayer */
-}
using namespace std;
diff --git a/source/blender/freestyle/intern/stroke/Canvas.cpp b/source/blender/freestyle/intern/stroke/Canvas.cpp
index 8159279a846..4386e64345f 100644
--- a/source/blender/freestyle/intern/stroke/Canvas.cpp
+++ b/source/blender/freestyle/intern/stroke/Canvas.cpp
@@ -19,7 +19,6 @@
* \brief Class to define a canvas designed to draw style modules
*/
-/* clang-format off */
#include <sstream>
#include <vector>
@@ -27,13 +26,13 @@
#include "StrokeRenderer.h"
#include "StyleModule.h"
-#include "../image/Image.h"
#include "../image/GaussianFilter.h"
+#include "../image/Image.h"
#include "../image/ImagePyramid.h"
#include "../system/FreestyleConfig.h"
-#include "../system/TimeStamp.h"
#include "../system/PseudoNoise.h"
+#include "../system/TimeStamp.h"
#include "../view_map/SteerableViewMap.h"
@@ -42,11 +41,8 @@
// soc #include <qimage.h>
// soc #include <QString>
-extern "C" {
#include "IMB_imbuf.h"
#include "IMB_imbuf_types.h"
-}
-/* clang-format on */
using namespace std;
diff --git a/source/blender/freestyle/intern/stroke/Chain.cpp b/source/blender/freestyle/intern/stroke/Chain.cpp
index 94c0b753985..562ca32be78 100644
--- a/source/blender/freestyle/intern/stroke/Chain.cpp
+++ b/source/blender/freestyle/intern/stroke/Chain.cpp
@@ -19,12 +19,10 @@
* \brief Class to define a chain of viewedges.
*/
-/* clang-format off */
#include "Chain.h"
-#include "../view_map/ViewMapIterators.h"
#include "../view_map/ViewMapAdvancedIterators.h"
-/* clang-format on */
+#include "../view_map/ViewMapIterators.h"
namespace Freestyle {
diff --git a/source/blender/freestyle/intern/stroke/ChainingIterators.h b/source/blender/freestyle/intern/stroke/ChainingIterators.h
index 569ca6fcf1d..36611a4a009 100644
--- a/source/blender/freestyle/intern/stroke/ChainingIterators.h
+++ b/source/blender/freestyle/intern/stroke/ChainingIterators.h
@@ -22,7 +22,6 @@
* \brief Chaining iterators
*/
-/* clang-format off */
#include <iostream>
#include "Predicates1D.h"
@@ -30,9 +29,8 @@
#include "../system/Iterator.h"
#include "../view_map/ViewMap.h"
-#include "../view_map/ViewMapIterators.h"
#include "../view_map/ViewMapAdvancedIterators.h"
-/* clang-format on */
+#include "../view_map/ViewMapIterators.h"
// using namespace ViewEdgeInternal;
diff --git a/source/blender/freestyle/intern/stroke/Curve.cpp b/source/blender/freestyle/intern/stroke/Curve.cpp
index 294f332d48d..02a1d32953d 100644
--- a/source/blender/freestyle/intern/stroke/Curve.cpp
+++ b/source/blender/freestyle/intern/stroke/Curve.cpp
@@ -19,16 +19,14 @@
* \brief Class to define a container for curves
*/
-/* clang-format off */
#include <stdio.h> /* printf */
#include "Curve.h"
-#include "CurveIterators.h"
#include "CurveAdvancedIterators.h"
+#include "CurveIterators.h"
#include "BKE_global.h"
#include "BLI_utildefines.h"
-/* clang-format on */
namespace Freestyle {
diff --git a/source/blender/freestyle/intern/stroke/CurveAdvancedIterators.h b/source/blender/freestyle/intern/stroke/CurveAdvancedIterators.h
index 662222524f1..4ac4c04774e 100644
--- a/source/blender/freestyle/intern/stroke/CurveAdvancedIterators.h
+++ b/source/blender/freestyle/intern/stroke/CurveAdvancedIterators.h
@@ -22,6 +22,7 @@
* \brief Iterators used to iterate over the elements of the Curve. Can't be used in python
*/
+#include "CurveIterators.h"
#include "Stroke.h"
namespace Freestyle {
diff --git a/source/blender/freestyle/intern/stroke/Operators.cpp b/source/blender/freestyle/intern/stroke/Operators.cpp
index b0d3f26bce4..25954c7ecbf 100644
--- a/source/blender/freestyle/intern/stroke/Operators.cpp
+++ b/source/blender/freestyle/intern/stroke/Operators.cpp
@@ -19,18 +19,16 @@
* \brief Class gathering stroke creation algorithms
*/
-/* clang-format off */
#include <algorithm>
#include <stdexcept>
-#include "Operators.h"
#include "Canvas.h"
+#include "CurveIterators.h"
+#include "Operators.h"
#include "Stroke.h"
#include "StrokeIterators.h"
-#include "CurveIterators.h"
#include "BKE_global.h"
-/* clang-format on */
namespace Freestyle {
diff --git a/source/blender/freestyle/intern/stroke/PSStrokeRenderer.cpp b/source/blender/freestyle/intern/stroke/PSStrokeRenderer.cpp
index ff43e5986b3..c2c263696bc 100644
--- a/source/blender/freestyle/intern/stroke/PSStrokeRenderer.cpp
+++ b/source/blender/freestyle/intern/stroke/PSStrokeRenderer.cpp
@@ -19,10 +19,8 @@
* \brief Class to define the Postscript rendering of a stroke
*/
-/* clang-format off */
-#include "Canvas.h"
#include "PSStrokeRenderer.h"
-/* clang-format on */
+#include "Canvas.h"
namespace Freestyle {
diff --git a/source/blender/freestyle/intern/stroke/Predicates1D.h b/source/blender/freestyle/intern/stroke/Predicates1D.h
index d549e960bd9..0ad4c69f869 100644
--- a/source/blender/freestyle/intern/stroke/Predicates1D.h
+++ b/source/blender/freestyle/intern/stroke/Predicates1D.h
@@ -22,20 +22,18 @@
* \brief Class gathering stroke creation algorithms
*/
-/* clang-format off */
#include <string>
#include "AdvancedFunctions1D.h"
#include "../system/TimeStamp.h"
-#include "../view_map/Interface1D.h"
#include "../view_map/Functions1D.h"
+#include "../view_map/Interface1D.h"
#ifdef WITH_CXX_GUARDEDALLOC
# include "MEM_guardedalloc.h"
#endif
-/* clang-format on */
namespace Freestyle {
diff --git a/source/blender/freestyle/intern/stroke/Stroke.cpp b/source/blender/freestyle/intern/stroke/Stroke.cpp
index 0bd25c20ca5..2f29eac83b1 100644
--- a/source/blender/freestyle/intern/stroke/Stroke.cpp
+++ b/source/blender/freestyle/intern/stroke/Stroke.cpp
@@ -19,15 +19,13 @@
* \brief Classes to define a stroke
*/
-/* clang-format off */
#include "Stroke.h"
-#include "StrokeIterators.h"
#include "StrokeAdvancedIterators.h"
+#include "StrokeIterators.h"
#include "StrokeRenderer.h"
#include "BKE_global.h"
#include "BKE_node.h"
-/* clang-format on */
namespace Freestyle {
diff --git a/source/blender/freestyle/intern/stroke/StrokeAdvancedIterators.h b/source/blender/freestyle/intern/stroke/StrokeAdvancedIterators.h
index ccf5773a4c8..b8c96533a1c 100644
--- a/source/blender/freestyle/intern/stroke/StrokeAdvancedIterators.h
+++ b/source/blender/freestyle/intern/stroke/StrokeAdvancedIterators.h
@@ -23,6 +23,7 @@
*/
#include "Stroke.h"
+#include "StrokeIterators.h"
namespace Freestyle {
diff --git a/source/blender/freestyle/intern/stroke/StrokeLayer.cpp b/source/blender/freestyle/intern/stroke/StrokeLayer.cpp
index 95598654dfe..9d12067512c 100644
--- a/source/blender/freestyle/intern/stroke/StrokeLayer.cpp
+++ b/source/blender/freestyle/intern/stroke/StrokeLayer.cpp
@@ -19,11 +19,9 @@
* \brief Class to define a layer of strokes.
*/
-/* clang-format off */
+#include "StrokeLayer.h"
#include "Canvas.h"
#include "Stroke.h"
-#include "StrokeLayer.h"
-/* clang-format on */
namespace Freestyle {
diff --git a/source/blender/freestyle/intern/stroke/StrokeRenderer.h b/source/blender/freestyle/intern/stroke/StrokeRenderer.h
index 615d59ce6aa..67deb5eebf3 100644
--- a/source/blender/freestyle/intern/stroke/StrokeRenderer.h
+++ b/source/blender/freestyle/intern/stroke/StrokeRenderer.h
@@ -22,10 +22,9 @@
* \brief Classes to render a stroke with OpenGL
*/
-/* clang-format off */
+#include <algorithm>
#include <map>
#include <string.h>
-#include <algorithm>
#include <utility>
#include <vector>
@@ -37,7 +36,6 @@
#ifdef WITH_CXX_GUARDEDALLOC
# include "MEM_guardedalloc.h"
#endif
-/* clang-format on */
namespace Freestyle {
diff --git a/source/blender/freestyle/intern/stroke/StrokeRep.cpp b/source/blender/freestyle/intern/stroke/StrokeRep.cpp
index 81e69c6e34c..661c144476c 100644
--- a/source/blender/freestyle/intern/stroke/StrokeRep.cpp
+++ b/source/blender/freestyle/intern/stroke/StrokeRep.cpp
@@ -19,15 +19,13 @@
* \brief Class to define the representation of a stroke (for display purpose)
*/
-/* clang-format off */
+#include "StrokeRep.h"
#include "Stroke.h"
-#include "StrokeIterators.h"
#include "StrokeAdvancedIterators.h"
+#include "StrokeIterators.h"
#include "StrokeRenderer.h"
-#include "StrokeRep.h"
#include "BKE_global.h"
-/* clang-format on */
using namespace std;
diff --git a/source/blender/freestyle/intern/stroke/StrokeRep.h b/source/blender/freestyle/intern/stroke/StrokeRep.h
index b2bfb805ee6..d6ee1d01279 100644
--- a/source/blender/freestyle/intern/stroke/StrokeRep.h
+++ b/source/blender/freestyle/intern/stroke/StrokeRep.h
@@ -30,10 +30,8 @@
# include "MEM_guardedalloc.h"
#endif
-extern "C" {
#include "DNA_material_types.h" // for MAX_MTEX
struct bNodeTree;
-}
namespace Freestyle {
diff --git a/source/blender/freestyle/intern/stroke/StrokeTesselator.cpp b/source/blender/freestyle/intern/stroke/StrokeTesselator.cpp
index 4f58827e941..e9a50067d4d 100644
--- a/source/blender/freestyle/intern/stroke/StrokeTesselator.cpp
+++ b/source/blender/freestyle/intern/stroke/StrokeTesselator.cpp
@@ -19,14 +19,12 @@
* \brief Class to build a Node Tree designed to be displayed from a set of strokes structure.
*/
-/* clang-format off */
-#include "StrokeAdvancedIterators.h"
#include "StrokeTesselator.h"
+#include "StrokeAdvancedIterators.h"
-#include "../scene_graph/OrientedLineRep.h"
#include "../scene_graph/NodeGroup.h"
#include "../scene_graph/NodeShape.h"
-/* clang-format on */
+#include "../scene_graph/OrientedLineRep.h"
namespace Freestyle {
diff --git a/source/blender/freestyle/intern/stroke/TextStrokeRenderer.h b/source/blender/freestyle/intern/stroke/TextStrokeRenderer.h
index 4669067c3f5..c6497aba808 100644
--- a/source/blender/freestyle/intern/stroke/TextStrokeRenderer.h
+++ b/source/blender/freestyle/intern/stroke/TextStrokeRenderer.h
@@ -34,11 +34,11 @@
#ifndef TEXTSTROKERENDERER_H
#define TEXTSTROKERENDERER_H
-/* clang-format off */
+#include <fstream>
+
#include "StrokeRenderer.h"
+
#include "../system/FreestyleConfig.h"
-#include <fstream>
-/* clang-format on */
namespace Freestyle {
diff --git a/source/blender/freestyle/intern/system/PythonInterpreter.h b/source/blender/freestyle/intern/system/PythonInterpreter.h
index 785bc0f4330..4bc6ba9db38 100644
--- a/source/blender/freestyle/intern/system/PythonInterpreter.h
+++ b/source/blender/freestyle/intern/system/PythonInterpreter.h
@@ -22,15 +22,14 @@
* \brief Python Interpreter
*/
-/* clang-format off */
#include <iostream>
extern "C" {
#include <Python.h>
}
-#include "StringUtils.h"
#include "Interpreter.h"
+#include "StringUtils.h"
#include "MEM_guardedalloc.h"
@@ -49,7 +48,6 @@ extern "C" {
#include "bpy_capi_utils.h"
}
-/* clang-format on */
namespace Freestyle {
diff --git a/source/blender/freestyle/intern/system/StringUtils.cpp b/source/blender/freestyle/intern/system/StringUtils.cpp
index 58d84010574..90210f33a25 100644
--- a/source/blender/freestyle/intern/system/StringUtils.cpp
+++ b/source/blender/freestyle/intern/system/StringUtils.cpp
@@ -19,12 +19,10 @@
* \brief String utilities
*/
-/* clang-format off */
// soc #include <qfileinfo.h>
-#include "FreestyleConfig.h"
#include "StringUtils.h"
-/* clang-format on */
+#include "FreestyleConfig.h"
namespace Freestyle {
@@ -48,7 +46,7 @@ void getPathName(const string &path, const string &base, vector<string> &pathnam
dir = path.substr(pos, sep - pos);
BLI_strncpy(cleaned, dir.c_str(), FILE_MAX);
- BLI_cleanup_path(NULL, cleaned);
+ BLI_path_normalize(NULL, cleaned);
res = string(cleaned);
if (!base.empty()) {
diff --git a/source/blender/freestyle/intern/system/StringUtils.h b/source/blender/freestyle/intern/system/StringUtils.h
index 16944e47335..aeacddd64c8 100644
--- a/source/blender/freestyle/intern/system/StringUtils.h
+++ b/source/blender/freestyle/intern/system/StringUtils.h
@@ -22,7 +22,6 @@
* \brief String utilities
*/
-/* clang-format off */
#include <cstring>
#include <iostream>
#include <sstream>
@@ -30,10 +29,9 @@
#include <vector>
extern "C" {
-#include "BLI_string.h"
#include "BLI_path_util.h"
+#include "BLI_string.h"
}
-/* clang-format on */
using namespace std;
diff --git a/source/blender/freestyle/intern/view_map/GridDensityProvider.h b/source/blender/freestyle/intern/view_map/GridDensityProvider.h
index 26b76006686..290d5b0cfba 100644
--- a/source/blender/freestyle/intern/view_map/GridDensityProvider.h
+++ b/source/blender/freestyle/intern/view_map/GridDensityProvider.h
@@ -22,10 +22,9 @@
* \brief Class to define a cell grid surrounding the projected image of a scene
*/
-/* clang-format off */
-#include <stdexcept>
#include <algorithm>
#include <memory>
+#include <stdexcept>
#include "AutoPtrHelper.h"
#include "OccluderSource.h"
@@ -37,7 +36,6 @@
#ifdef WITH_CXX_GUARDEDALLOC
# include "MEM_guardedalloc.h"
#endif
-/* clang-format on */
namespace Freestyle {
diff --git a/source/blender/freestyle/intern/view_map/Silhouette.h b/source/blender/freestyle/intern/view_map/Silhouette.h
index 648eb4e453d..8503836e0ca 100644
--- a/source/blender/freestyle/intern/view_map/Silhouette.h
+++ b/source/blender/freestyle/intern/view_map/Silhouette.h
@@ -1592,15 +1592,15 @@ class SShape {
/*! Splits an edge into several edges.
* The edge's vertices are passed rather than the edge itself. This way, all feature edges
- * (SILHOUETTE, CREASE, BORDER) are splitted in the same time. The processed edges are flagged as
- * done (using the userdata flag).One single new vertex is created whereas several splitted edges
+ * (SILHOUETTE, CREASE, BORDER) are split in the same time. The processed edges are flagged as
+ * done (using the user-data flag).One single new vertex is created whereas several split edges
* might created for the different kinds of edges. These new elements are added to the lists
* maintained by the shape.
* New chains are also created.
* ioA
- * The first vertex for the edge that gets splitted
+ * The first vertex for the edge that gets split.
* ioB
- * The second vertex for the edge that gets splitted
+ * The second vertex for the edge that gets split.
* iParameters
* A vector containing 2D real vectors indicating the parameters giving the intersections
* coordinates in 3D and in 2D. These intersections points must be sorted from B to A. Each
diff --git a/source/blender/freestyle/intern/view_map/SilhouetteGeomEngine.cpp b/source/blender/freestyle/intern/view_map/SilhouetteGeomEngine.cpp
index 2c7560259fe..46d4389ea83 100644
--- a/source/blender/freestyle/intern/view_map/SilhouetteGeomEngine.cpp
+++ b/source/blender/freestyle/intern/view_map/SilhouetteGeomEngine.cpp
@@ -20,9 +20,8 @@
* implies that this geom engine has as member data the viewpoint, transformations, projections...
*/
-/* clang-format off */
-#include <cstring>
#include <cstdio>
+#include <cstring>
#include "Silhouette.h"
#include "SilhouetteGeomEngine.h"
@@ -30,7 +29,6 @@
#include "../geometry/GeomUtils.h"
#include "BKE_global.h"
-/* clang-format on */
using namespace std;
diff --git a/source/blender/freestyle/intern/view_map/SphericalGrid.h b/source/blender/freestyle/intern/view_map/SphericalGrid.h
index 3c1ca3b5992..e9074580fb9 100644
--- a/source/blender/freestyle/intern/view_map/SphericalGrid.h
+++ b/source/blender/freestyle/intern/view_map/SphericalGrid.h
@@ -24,7 +24,6 @@
#define SPHERICAL_GRID_LOGGING 0
-/* clang-format off */
// I would like to avoid using deque because including ViewMap.h and <deque> or <vector> separately
// results in redefinitions of identifiers. ViewMap.h already includes <vector> so it should be a
// safe fall-back.
@@ -35,9 +34,9 @@
#include "OccluderSource.h"
#include "ViewMap.h"
-#include "../geometry/Polygon.h"
#include "../geometry/BBox.h"
#include "../geometry/GridHelpers.h"
+#include "../geometry/Polygon.h"
#include "../system/PointerSequence.h"
@@ -48,7 +47,6 @@
#ifdef WITH_CXX_GUARDEDALLOC
# include "MEM_guardedalloc.h"
#endif
-/* clang-format on */
namespace Freestyle {
diff --git a/source/blender/freestyle/intern/view_map/SteerableViewMap.cpp b/source/blender/freestyle/intern/view_map/SteerableViewMap.cpp
index fd8f7958e83..efda4b7fd2a 100644
--- a/source/blender/freestyle/intern/view_map/SteerableViewMap.cpp
+++ b/source/blender/freestyle/intern/view_map/SteerableViewMap.cpp
@@ -20,7 +20,6 @@
* to.
*/
-/* clang-format off */
#include <sstream>
#include "Silhouette.h"
@@ -28,17 +27,14 @@
#include "../geometry/Geom.h"
-#include "../image/ImagePyramid.h"
#include "../image/Image.h"
+#include "../image/ImagePyramid.h"
#include "BKE_global.h"
#include "BLI_math.h"
-extern "C" {
#include "IMB_imbuf.h"
#include "IMB_imbuf_types.h"
-}
-/* clang-format on */
namespace Freestyle {
diff --git a/source/blender/freestyle/intern/view_map/ViewMap.cpp b/source/blender/freestyle/intern/view_map/ViewMap.cpp
index 5ea28e4ac41..47c6c3a1f6a 100644
--- a/source/blender/freestyle/intern/view_map/ViewMap.cpp
+++ b/source/blender/freestyle/intern/view_map/ViewMap.cpp
@@ -19,15 +19,13 @@
* \brief Classes to define a View Map (ViewVertex, ViewEdge, etc.)
*/
-/* clang-format off */
#include <float.h>
#include "ViewMap.h"
-#include "ViewMapIterators.h"
#include "ViewMapAdvancedIterators.h"
+#include "ViewMapIterators.h"
#include "../geometry/GeomUtils.h"
-/* clang-format on */
namespace Freestyle {
diff --git a/source/blender/freestyle/intern/view_map/ViewMapAdvancedIterators.h b/source/blender/freestyle/intern/view_map/ViewMapAdvancedIterators.h
index 525073af919..2ff46e353f3 100644
--- a/source/blender/freestyle/intern/view_map/ViewMapAdvancedIterators.h
+++ b/source/blender/freestyle/intern/view_map/ViewMapAdvancedIterators.h
@@ -24,6 +24,7 @@
*/
#include "ViewMap.h"
+#include "ViewMapIterators.h"
#include "../system/Iterator.h" //soc
diff --git a/source/blender/freestyle/intern/view_map/ViewMapBuilder.cpp b/source/blender/freestyle/intern/view_map/ViewMapBuilder.cpp
index 681237399a8..40ab3ada777 100644
--- a/source/blender/freestyle/intern/view_map/ViewMapBuilder.cpp
+++ b/source/blender/freestyle/intern/view_map/ViewMapBuilder.cpp
@@ -19,11 +19,10 @@
* \brief Class to build silhouette edges from a Winged-Edge structure
*/
-/* clang-format off */
#include <algorithm>
#include <memory>
-#include <stdexcept>
#include <sstream>
+#include <stdexcept>
#include "FRS_freestyle.h"
@@ -34,13 +33,12 @@
#include "SphericalGrid.h"
#include "ViewMapBuilder.h"
-#include "../geometry/GridHelpers.h"
#include "../geometry/GeomUtils.h"
+#include "../geometry/GridHelpers.h"
#include "../winged_edge/WFillGrid.h"
#include "BKE_global.h"
-/* clang-format on */
namespace Freestyle {
diff --git a/source/blender/freestyle/intern/view_map/ViewMapTesselator.h b/source/blender/freestyle/intern/view_map/ViewMapTesselator.h
index 33ef6858541..b6bf51618d8 100644
--- a/source/blender/freestyle/intern/view_map/ViewMapTesselator.h
+++ b/source/blender/freestyle/intern/view_map/ViewMapTesselator.h
@@ -22,13 +22,12 @@
* \brief Class to build a Node Tree designed to be displayed from a Silhouette View Map structure.
*/
-/* clang-format off */
#include "Silhouette.h"
#include "ViewMap.h"
#include "../scene_graph/LineRep.h"
-#include "../scene_graph/NodeShape.h"
#include "../scene_graph/NodeGroup.h"
+#include "../scene_graph/NodeShape.h"
#include "../scene_graph/OrientedLineRep.h"
#include "../scene_graph/VertexRep.h"
@@ -37,7 +36,6 @@
#ifdef WITH_CXX_GUARDEDALLOC
# include "MEM_guardedalloc.h"
#endif
-/* clang-format on */
namespace Freestyle {
diff --git a/source/blender/freestyle/intern/winged_edge/Curvature.cpp b/source/blender/freestyle/intern/winged_edge/Curvature.cpp
index 591d6518741..96b313d4e01 100644
--- a/source/blender/freestyle/intern/winged_edge/Curvature.cpp
+++ b/source/blender/freestyle/intern/winged_edge/Curvature.cpp
@@ -105,16 +105,16 @@ static real angle_from_cotan(WVertex *vo, WVertex *v1, WVertex *v2)
}
/*! gts_vertex_mean_curvature_normal:
- * @v: a #WVertex.
- * @s: a #GtsSurface.
- * @Kh: the Mean Curvature Normal at @v.
+ * \param v: a #WVertex.
+ * \param s: a #GtsSurface.
+ * \param Kh: the Mean Curvature Normal at \a v.
*
- * Computes the Discrete Mean Curvature Normal approximation at @v.
- * The mean curvature at @v is half the magnitude of the vector @Kh.
+ * Computes the Discrete Mean Curvature Normal approximation at \a v.
+ * The mean curvature at \a v is half the magnitude of the vector \a Kh.
*
* Note: the normal computed is not unit length, and may point either into or out of the surface,
- * depending on the curvature at @v. It is the responsibility of the caller of the function to use
- * the mean curvature normal appropriately.
+ * depending on the curvature at \a v. It is the responsibility of the caller of the function to
+ * use the mean curvature normal appropriately.
*
* This approximation is from the paper:
* Discrete Differential-Geometry Operators for Triangulated 2-Manifolds
@@ -176,11 +176,11 @@ bool gts_vertex_mean_curvature_normal(WVertex *v, Vec3r &Kh)
}
/*! gts_vertex_gaussian_curvature:
- * @v: a #WVertex.
- * @s: a #GtsSurface.
- * @Kg: the Discrete Gaussian Curvature approximation at @v.
+ * \param v: a #WVertex.
+ * \param s: a #GtsSurface.
+ * \param Kg: the Discrete Gaussian Curvature approximation at \a v.
*
- * Computes the Discrete Gaussian Curvature approximation at @v.
+ * Computes the Discrete Gaussian Curvature approximation at \a v.
*
* This approximation is from the paper:
* Discrete Differential-Geometry Operators for Triangulated 2-Manifolds
@@ -280,16 +280,16 @@ static void eigenvector(real a, real b, real c, Vec3r e)
}
/*! gts_vertex_principal_directions:
- * @v: a #WVertex.
- * @s: a #GtsSurface.
- * @Kh: mean curvature normal (a #Vec3r).
- * @Kg: Gaussian curvature (a real).
- * @e1: first principal curvature direction (direction of largest curvature).
- * @e2: second principal curvature direction.
+ * \param v: a #WVertex.
+ * \param s: a #GtsSurface.
+ * \param Kh: mean curvature normal (a #Vec3r).
+ * \param Kg: Gaussian curvature (a real).
+ * \param e1: first principal curvature direction (direction of largest curvature).
+ * \param e2: second principal curvature direction.
*
- * Computes the principal curvature directions at a point given @Kh and @Kg, the mean curvature
- * normal and Gaussian curvatures at that point, computed with gts_vertex_mean_curvature_normal()
- * and gts_vertex_gaussian_curvature(), respectively.
+ * Computes the principal curvature directions at a point given \a Kh and \a Kg,
+ * the mean curvature normal and Gaussian curvatures at that point, computed with
+ * gts_vertex_mean_curvature_normal() and gts_vertex_gaussian_curvature(), respectively.
*
* Note that this computation is very approximate and tends to be unstable. Smoothing of the
* surface or the principal directions may be necessary to achieve reasonable results.
diff --git a/source/blender/freestyle/intern/winged_edge/WFillGrid.cpp b/source/blender/freestyle/intern/winged_edge/WFillGrid.cpp
index b6dfb183d0f..f54b54f5a3a 100644
--- a/source/blender/freestyle/intern/winged_edge/WFillGrid.cpp
+++ b/source/blender/freestyle/intern/winged_edge/WFillGrid.cpp
@@ -19,10 +19,8 @@
* \brief Class to fill in a grid from a SceneGraph (uses only the WingedEdge structures)
*/
-/* clang-format off */
-#include "WEdge.h"
#include "WFillGrid.h"
-/* clang-format on */
+#include "WEdge.h"
namespace Freestyle {
diff --git a/source/blender/freestyle/intern/winged_edge/WSFillGrid.cpp b/source/blender/freestyle/intern/winged_edge/WSFillGrid.cpp
index 2fa9e51fa7f..e1cb1c29f63 100644
--- a/source/blender/freestyle/intern/winged_edge/WSFillGrid.cpp
+++ b/source/blender/freestyle/intern/winged_edge/WSFillGrid.cpp
@@ -19,10 +19,8 @@
* \brief Class to fill in a grid from a SceneGraph (uses only the WingedEdge structures)
*/
-/* clang-format off */
-#include "WEdge.h"
#include "WSFillGrid.h"
-/* clang-format on */
+#include "WEdge.h"
namespace Freestyle {
diff --git a/source/blender/freestyle/intern/winged_edge/WXEdgeBuilder.cpp b/source/blender/freestyle/intern/winged_edge/WXEdgeBuilder.cpp
index e6062a605ba..9be3da4420b 100644
--- a/source/blender/freestyle/intern/winged_edge/WXEdgeBuilder.cpp
+++ b/source/blender/freestyle/intern/winged_edge/WXEdgeBuilder.cpp
@@ -20,10 +20,8 @@
* info (silhouette etc...)) structure from a polygonal model
*/
-/* clang-format off */
-#include "WXEdge.h"
#include "WXEdgeBuilder.h"
-/* clang-format on */
+#include "WXEdge.h"
namespace Freestyle {
diff --git a/source/blender/gpencil_modifiers/CMakeLists.txt b/source/blender/gpencil_modifiers/CMakeLists.txt
index 87743911add..d3c85b891c6 100644
--- a/source/blender/gpencil_modifiers/CMakeLists.txt
+++ b/source/blender/gpencil_modifiers/CMakeLists.txt
@@ -56,6 +56,7 @@ set(SRC
intern/MOD_gpencilsimplify.c
intern/MOD_gpencilsmooth.c
intern/MOD_gpencilsubdiv.c
+ intern/MOD_gpenciltexture.c
intern/MOD_gpencilthick.c
intern/MOD_gpenciltime.c
intern/MOD_gpenciltint.c
diff --git a/source/blender/gpencil_modifiers/MOD_gpencil_modifiertypes.h b/source/blender/gpencil_modifiers/MOD_gpencil_modifiertypes.h
index f5c064c1c07..a7a4333d82e 100644
--- a/source/blender/gpencil_modifiers/MOD_gpencil_modifiertypes.h
+++ b/source/blender/gpencil_modifiers/MOD_gpencil_modifiertypes.h
@@ -43,6 +43,7 @@ extern GpencilModifierTypeInfo modifierType_Gpencil_Offset;
extern GpencilModifierTypeInfo modifierType_Gpencil_Armature;
extern GpencilModifierTypeInfo modifierType_Gpencil_Time;
extern GpencilModifierTypeInfo modifierType_Gpencil_Multiply;
+extern GpencilModifierTypeInfo modifierType_Gpencil_Texture;
/* MOD_gpencil_util.c */
void gpencil_modifier_type_init(GpencilModifierTypeInfo *types[]);
diff --git a/source/blender/gpencil_modifiers/intern/MOD_gpencil_util.c b/source/blender/gpencil_modifiers/intern/MOD_gpencil_util.c
index 7df0440aa85..f7929b58650 100644
--- a/source/blender/gpencil_modifiers/intern/MOD_gpencil_util.c
+++ b/source/blender/gpencil_modifiers/intern/MOD_gpencil_util.c
@@ -72,13 +72,14 @@ void gpencil_modifier_type_init(GpencilModifierTypeInfo *types[])
INIT_GP_TYPE(Armature);
INIT_GP_TYPE(Time);
INIT_GP_TYPE(Multiply);
+ INIT_GP_TYPE(Texture);
#undef INIT_GP_TYPE
}
/* verify if valid layer, material and pass index */
bool is_stroke_affected_by_modifier(Object *ob,
char *mlayername,
- char *mmaterialname,
+ Material *material,
const int mpassindex,
const int gpl_passindex,
const int minpoints,
@@ -105,15 +106,15 @@ bool is_stroke_affected_by_modifier(Object *ob,
}
}
}
- /* omit if filter by material */
- if (mmaterialname[0] != '\0') {
+ /* Omit if filter by material. */
+ if (material != NULL) {
if (inv4 == false) {
- if (!STREQ(mmaterialname, ma->id.name + 2)) {
+ if (material != ma) {
return false;
}
}
else {
- if (STREQ(mmaterialname, ma->id.name + 2)) {
+ if (material == ma) {
return false;
}
}
diff --git a/source/blender/gpencil_modifiers/intern/MOD_gpencil_util.h b/source/blender/gpencil_modifiers/intern/MOD_gpencil_util.h
index fc4522bc028..5cc3750639b 100644
--- a/source/blender/gpencil_modifiers/intern/MOD_gpencil_util.h
+++ b/source/blender/gpencil_modifiers/intern/MOD_gpencil_util.h
@@ -34,7 +34,7 @@ struct bGPDstroke;
bool is_stroke_affected_by_modifier(struct Object *ob,
char *mlayername,
- char *mmaterialname,
+ struct Material *material,
const int mpassindex,
const int gpl_passindex,
const int minpoints,
diff --git a/source/blender/gpencil_modifiers/intern/MOD_gpencilarmature.c b/source/blender/gpencil_modifiers/intern/MOD_gpencilarmature.c
index 59a41901a48..2d5e01ced94 100644
--- a/source/blender/gpencil_modifiers/intern/MOD_gpencilarmature.c
+++ b/source/blender/gpencil_modifiers/intern/MOD_gpencilarmature.c
@@ -10,7 +10,7 @@
* 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,
+ * 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) 2018, Blender Foundation
@@ -63,7 +63,7 @@ static void initData(GpencilModifierData *md)
static void copyData(const GpencilModifierData *md, GpencilModifierData *target)
{
- BKE_gpencil_modifier_copyData_generic(md, target);
+ BKE_gpencil_modifier_copydata_generic(md, target);
}
static void gpencil_deform_verts(ArmatureGpencilModifierData *mmd, Object *target, bGPDstroke *gps)
@@ -127,7 +127,7 @@ static void bakeModifier(Main *bmain, Depsgraph *depsgraph, GpencilModifierData
Scene *scene = DEG_get_evaluated_scene(depsgraph);
Object *object_eval = DEG_get_evaluated_object(depsgraph, ob);
ArmatureGpencilModifierData *mmd = (ArmatureGpencilModifierData *)md;
- GpencilModifierData *md_eval = BKE_gpencil_modifiers_findByName(object_eval, md->name);
+ GpencilModifierData *md_eval = BKE_gpencil_modifiers_findby_name(object_eval, md->name);
bGPdata *gpd = (bGPdata *)ob->data;
int oldframe = (int)DEG_get_ctime(depsgraph);
diff --git a/source/blender/gpencil_modifiers/intern/MOD_gpencilarray.c b/source/blender/gpencil_modifiers/intern/MOD_gpencilarray.c
index 314879927ff..da4c1f71f44 100644
--- a/source/blender/gpencil_modifiers/intern/MOD_gpencilarray.c
+++ b/source/blender/gpencil_modifiers/intern/MOD_gpencilarray.c
@@ -10,7 +10,7 @@
* 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,
+ * 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
@@ -77,11 +77,12 @@ static void initData(GpencilModifierData *md)
gpmd->object = NULL;
gpmd->flag |= GP_ARRAY_USE_RELATIVE;
gpmd->seed = 1;
+ gpmd->material = NULL;
}
static void copyData(const GpencilModifierData *md, GpencilModifierData *target)
{
- BKE_gpencil_modifier_copyData_generic(md, target);
+ BKE_gpencil_modifier_copydata_generic(md, target);
}
/* -------------------------------- */
@@ -163,7 +164,7 @@ static void generate_geometry(GpencilModifierData *md,
LISTBASE_FOREACH (bGPDstroke *, gps, &gpf->strokes) {
if (is_stroke_affected_by_modifier(ob,
mmd->layername,
- mmd->materialname,
+ mmd->material,
mmd->pass_index,
mmd->layer_pass,
1,
@@ -320,6 +321,15 @@ static void foreachObjectLink(GpencilModifierData *md,
walk(userData, ob, &mmd->object, IDWALK_CB_NOP);
}
+static void foreachIDLink(GpencilModifierData *md, Object *ob, IDWalkFunc walk, void *userData)
+{
+ ArrayGpencilModifierData *mmd = (ArrayGpencilModifierData *)md;
+
+ walk(userData, ob, (ID **)&mmd->material, IDWALK_CB_USER);
+
+ foreachObjectLink(md, ob, (ObjectWalkFunc)walk, userData);
+}
+
GpencilModifierTypeInfo modifierType_Gpencil_Array = {
/* name */ "Array",
/* structName */ "ArrayGpencilModifierData",
@@ -340,6 +350,6 @@ GpencilModifierTypeInfo modifierType_Gpencil_Array = {
/* updateDepsgraph */ updateDepsgraph,
/* dependsOnTime */ NULL,
/* foreachObjectLink */ foreachObjectLink,
- /* foreachIDLink */ NULL,
+ /* foreachIDLink */ foreachIDLink,
/* foreachTexLink */ NULL,
};
diff --git a/source/blender/gpencil_modifiers/intern/MOD_gpencilbuild.c b/source/blender/gpencil_modifiers/intern/MOD_gpencilbuild.c
index 435559f4881..71a051629d8 100644
--- a/source/blender/gpencil_modifiers/intern/MOD_gpencilbuild.c
+++ b/source/blender/gpencil_modifiers/intern/MOD_gpencilbuild.c
@@ -10,7 +10,7 @@
* 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,
+ * 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
@@ -63,7 +63,7 @@ static void initData(GpencilModifierData *md)
static void copyData(const GpencilModifierData *md, GpencilModifierData *target)
{
- BKE_gpencil_modifier_copyData_generic(md, target);
+ BKE_gpencil_modifier_copydata_generic(md, target);
}
static bool dependsOnTime(GpencilModifierData *UNUSED(md))
@@ -406,6 +406,7 @@ static void generate_geometry(GpencilModifierData *md,
{
BuildGpencilModifierData *mmd = (BuildGpencilModifierData *)md;
const bool reverse = (mmd->transition != GP_BUILD_TRANSITION_GROW);
+ const bool is_percentage = (mmd->flag & GP_BUILD_PERCENTAGE);
const float ctime = DEG_get_ctime(depsgraph);
@@ -462,8 +463,8 @@ static void generate_geometry(GpencilModifierData *md,
}
/* Early exit if current frame is outside start/end bounds */
- /* NOTE: If we're beyond the next/prev frames (if existent), then we wouldn't have this problem
- * anyway... */
+ /* NOTE: If we're beyond the next/previous frames (if existent),
+ * then we wouldn't have this problem anyway... */
if (ctime < start_frame) {
/* Before Start - Animation hasn't started. Display initial state. */
if (reverse) {
@@ -500,7 +501,8 @@ static void generate_geometry(GpencilModifierData *md,
}
/* Determine how far along we are between the keyframes */
- float fac = (ctime - start_frame) / (end_frame - start_frame);
+ float fac = is_percentage ? mmd->percentage_fac :
+ (ctime - start_frame) / (end_frame - start_frame);
/* Time management mode */
switch (mmd->mode) {
diff --git a/source/blender/gpencil_modifiers/intern/MOD_gpencilcolor.c b/source/blender/gpencil_modifiers/intern/MOD_gpencilcolor.c
index d311e77b9e3..14125d5c8d4 100644
--- a/source/blender/gpencil_modifiers/intern/MOD_gpencilcolor.c
+++ b/source/blender/gpencil_modifiers/intern/MOD_gpencilcolor.c
@@ -10,7 +10,7 @@
* 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,
+ * 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
@@ -37,8 +37,10 @@
#include "BKE_colortools.h"
#include "BKE_gpencil.h"
#include "BKE_gpencil_modifier.h"
+#include "BKE_lib_query.h"
#include "BKE_main.h"
#include "BKE_material.h"
+#include "BKE_modifier.h"
#include "DEG_depsgraph.h"
@@ -50,8 +52,7 @@ static void initData(GpencilModifierData *md)
ColorGpencilModifierData *gpmd = (ColorGpencilModifierData *)md;
gpmd->pass_index = 0;
ARRAY_SET_ITEMS(gpmd->hsv, 0.5f, 1.0f, 1.0f);
- gpmd->layername[0] = '\0';
- gpmd->materialname[0] = '\0';
+ gpmd->material = NULL;
gpmd->modify_color = GP_MODIFY_COLOR_BOTH;
gpmd->curve_intensity = BKE_curvemapping_add(1, 0.0f, 0.0f, 1.0f, 1.0f);
@@ -71,7 +72,7 @@ static void copyData(const GpencilModifierData *md, GpencilModifierData *target)
tgmd->curve_intensity = NULL;
}
- BKE_gpencil_modifier_copyData_generic(md, target);
+ BKE_gpencil_modifier_copydata_generic(md, target);
tgmd->curve_intensity = BKE_curvemapping_copy(gmd->curve_intensity);
}
@@ -91,7 +92,7 @@ static void deformStroke(GpencilModifierData *md,
if (!is_stroke_affected_by_modifier(ob,
mmd->layername,
- mmd->materialname,
+ mmd->material,
mmd->pass_index,
mmd->layer_pass,
1,
@@ -178,6 +179,13 @@ static void freeData(GpencilModifierData *md)
}
}
+static void foreachIDLink(GpencilModifierData *md, Object *ob, IDWalkFunc walk, void *userData)
+{
+ ColorGpencilModifierData *mmd = (ColorGpencilModifierData *)md;
+
+ walk(userData, ob, (ID **)&mmd->material, IDWALK_CB_USER);
+}
+
GpencilModifierTypeInfo modifierType_Gpencil_Color = {
/* name */ "Hue/Saturation",
/* structName */ "ColorGpencilModifierData",
@@ -198,6 +206,6 @@ GpencilModifierTypeInfo modifierType_Gpencil_Color = {
/* updateDepsgraph */ NULL,
/* dependsOnTime */ NULL,
/* foreachObjectLink */ NULL,
- /* foreachIDLink */ NULL,
+ /* foreachIDLink */ foreachIDLink,
/* foreachTexLink */ NULL,
};
diff --git a/source/blender/gpencil_modifiers/intern/MOD_gpencilhook.c b/source/blender/gpencil_modifiers/intern/MOD_gpencilhook.c
index 76f22fc9a36..d39c94e06d5 100644
--- a/source/blender/gpencil_modifiers/intern/MOD_gpencilhook.c
+++ b/source/blender/gpencil_modifiers/intern/MOD_gpencilhook.c
@@ -10,7 +10,7 @@
* 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,
+ * 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
@@ -77,9 +77,7 @@ static void initData(GpencilModifierData *md)
{
HookGpencilModifierData *gpmd = (HookGpencilModifierData *)md;
gpmd->pass_index = 0;
- gpmd->layername[0] = '\0';
- gpmd->materialname[0] = '\0';
- gpmd->vgname[0] = '\0';
+ gpmd->material = NULL;
gpmd->object = NULL;
gpmd->force = 0.5f;
gpmd->falloff_type = eGPHook_Falloff_Smooth;
@@ -99,7 +97,7 @@ static void copyData(const GpencilModifierData *md, GpencilModifierData *target)
tgmd->curfalloff = NULL;
}
- BKE_gpencil_modifier_copyData_generic(md, target);
+ BKE_gpencil_modifier_copydata_generic(md, target);
tgmd->curfalloff = BKE_curvemapping_copy(gmd->curfalloff);
}
@@ -208,7 +206,7 @@ static void deformStroke(GpencilModifierData *md,
if (!is_stroke_affected_by_modifier(ob,
mmd->layername,
- mmd->materialname,
+ mmd->material,
mmd->pass_index,
mmd->layer_pass,
1,
@@ -338,6 +336,15 @@ static void foreachObjectLink(GpencilModifierData *md,
walk(userData, ob, &mmd->object, IDWALK_CB_NOP);
}
+static void foreachIDLink(GpencilModifierData *md, Object *ob, IDWalkFunc walk, void *userData)
+{
+ HookGpencilModifierData *mmd = (HookGpencilModifierData *)md;
+
+ walk(userData, ob, (ID **)&mmd->material, IDWALK_CB_USER);
+
+ foreachObjectLink(md, ob, (ObjectWalkFunc)walk, userData);
+}
+
GpencilModifierTypeInfo modifierType_Gpencil_Hook = {
/* name */ "Hook",
/* structName */ "HookGpencilModifierData",
@@ -358,6 +365,6 @@ GpencilModifierTypeInfo modifierType_Gpencil_Hook = {
/* updateDepsgraph */ updateDepsgraph,
/* dependsOnTime */ NULL,
/* foreachObjectLink */ foreachObjectLink,
- /* foreachIDLink */ NULL,
+ /* foreachIDLink */ foreachIDLink,
/* foreachTexLink */ NULL,
};
diff --git a/source/blender/gpencil_modifiers/intern/MOD_gpencillattice.c b/source/blender/gpencil_modifiers/intern/MOD_gpencillattice.c
index 73b3c332a2e..5d5d673ca55 100644
--- a/source/blender/gpencil_modifiers/intern/MOD_gpencillattice.c
+++ b/source/blender/gpencil_modifiers/intern/MOD_gpencillattice.c
@@ -10,7 +10,7 @@
* 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,
+ * 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
@@ -55,9 +55,7 @@ static void initData(GpencilModifierData *md)
{
LatticeGpencilModifierData *gpmd = (LatticeGpencilModifierData *)md;
gpmd->pass_index = 0;
- gpmd->layername[0] = '\0';
- gpmd->materialname[0] = '\0';
- gpmd->vgname[0] = '\0';
+ gpmd->material = NULL;
gpmd->object = NULL;
gpmd->cache_data = NULL;
gpmd->strength = 1.0f;
@@ -65,7 +63,7 @@ static void initData(GpencilModifierData *md)
static void copyData(const GpencilModifierData *md, GpencilModifierData *target)
{
- BKE_gpencil_modifier_copyData_generic(md, target);
+ BKE_gpencil_modifier_copydata_generic(md, target);
}
static void deformStroke(GpencilModifierData *md,
@@ -80,7 +78,7 @@ static void deformStroke(GpencilModifierData *md,
if (!is_stroke_affected_by_modifier(ob,
mmd->layername,
- mmd->materialname,
+ mmd->material,
mmd->pass_index,
mmd->layer_pass,
1,
@@ -200,6 +198,15 @@ static void foreachObjectLink(GpencilModifierData *md,
walk(userData, ob, &mmd->object, IDWALK_CB_NOP);
}
+static void foreachIDLink(GpencilModifierData *md, Object *ob, IDWalkFunc walk, void *userData)
+{
+ LatticeGpencilModifierData *mmd = (LatticeGpencilModifierData *)md;
+
+ walk(userData, ob, (ID **)&mmd->material, IDWALK_CB_USER);
+
+ foreachObjectLink(md, ob, (ObjectWalkFunc)walk, userData);
+}
+
GpencilModifierTypeInfo modifierType_Gpencil_Lattice = {
/* name */ "Lattice",
/* structName */ "LatticeGpencilModifierData",
@@ -220,6 +227,6 @@ GpencilModifierTypeInfo modifierType_Gpencil_Lattice = {
/* updateDepsgraph */ updateDepsgraph,
/* dependsOnTime */ NULL,
/* foreachObjectLink */ foreachObjectLink,
- /* foreachIDLink */ NULL,
+ /* foreachIDLink */ foreachIDLink,
/* foreachTexLink */ NULL,
};
diff --git a/source/blender/gpencil_modifiers/intern/MOD_gpencilmirror.c b/source/blender/gpencil_modifiers/intern/MOD_gpencilmirror.c
index 5fffe683e6e..10f0dd763b1 100644
--- a/source/blender/gpencil_modifiers/intern/MOD_gpencilmirror.c
+++ b/source/blender/gpencil_modifiers/intern/MOD_gpencilmirror.c
@@ -10,7 +10,7 @@
* 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,
+ * 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) 2018, Blender Foundation
@@ -41,6 +41,7 @@
#include "BKE_lib_query.h"
#include "BKE_main.h"
#include "BKE_modifier.h"
+#include "BKE_object.h"
#include "BKE_scene.h"
#include "MEM_guardedalloc.h"
@@ -56,19 +57,40 @@ static void initData(GpencilModifierData *md)
{
MirrorGpencilModifierData *gpmd = (MirrorGpencilModifierData *)md;
gpmd->pass_index = 0;
- gpmd->layername[0] = '\0';
- gpmd->materialname[0] = '\0';
+ gpmd->material = NULL;
gpmd->object = NULL;
gpmd->flag |= GP_MIRROR_AXIS_X;
}
static void copyData(const GpencilModifierData *md, GpencilModifierData *target)
{
- BKE_gpencil_modifier_copyData_generic(md, target);
+ BKE_gpencil_modifier_copydata_generic(md, target);
}
-static void update_position(Object *ob, MirrorGpencilModifierData *mmd, bGPDstroke *gps, int axis)
+/* Mirror is using current object as origin. */
+static void update_mirror_local(bGPDstroke *gps, int axis)
+{
+ int i;
+ bGPDspoint *pt;
+ float factor[3] = {1.0f, 1.0f, 1.0f};
+ factor[axis] = -1.0f;
+
+ for (i = 0, pt = gps->points; i < gps->totpoints; i++, pt++) {
+ mul_v3_v3(&pt->x, factor);
+ }
+}
+
+/* Mirror is using other object as origin. */
+static void update_mirror_object(Object *ob,
+ MirrorGpencilModifierData *mmd,
+ bGPDstroke *gps,
+ int axis)
{
+ /* Calculate local matrix transformation. */
+ float mat[3][3], inv_mat[3][3];
+ BKE_object_to_mat3(ob, mat);
+ invert_m3_m3(inv_mat, mat);
+
int i;
bGPDspoint *pt;
float factor[3] = {1.0f, 1.0f, 1.0f};
@@ -82,34 +104,44 @@ static void update_position(Object *ob, MirrorGpencilModifierData *mmd, bGPDstro
float half_origin[3];
float rot_mat[3][3];
- if (mmd->object) {
- float eul[3];
- mat4_to_eul(eul, mmd->object->obmat);
- mul_v3_fl(eul, 2.0f);
- eul_to_mat3(rot_mat, eul);
- sub_v3_v3v3(ob_origin, ob->obmat[3], mmd->object->obmat[3]);
- }
- else {
- copy_v3_v3(ob_origin, ob->obmat[3]);
- }
+ float eul[3];
+ mat4_to_eul(eul, mmd->object->obmat);
+ mul_v3_fl(eul, 2.0f);
+ eul_to_mat3(rot_mat, eul);
+ sub_v3_v3v3(ob_origin, ob->obmat[3], mmd->object->obmat[3]);
- /* only works with current axis */
+ /* Only works with current axis. */
mul_v3_v3(ob_origin, clear);
+ /* Invert the origin. */
mul_v3_v3fl(pt_origin, ob_origin, -2.0f);
mul_v3_v3fl(half_origin, pt_origin, 0.5f);
for (i = 0, pt = gps->points; i < gps->totpoints; i++, pt++) {
+ /* Apply any local transformation. */
+ mul_m3_v3(mat, &pt->x);
+
+ /* Apply mirror effect. */
mul_v3_v3(&pt->x, factor);
- if (mmd->object) {
- /* apply location */
- add_v3_v3(&pt->x, pt_origin);
-
- /* apply rotation (around new center) */
- sub_v3_v3(&pt->x, half_origin);
- mul_m3_v3(rot_mat, &pt->x);
- add_v3_v3(&pt->x, half_origin);
- }
+ /* Apply location. */
+ add_v3_v3(&pt->x, pt_origin);
+ /* Apply rotation (around new center). */
+ sub_v3_v3(&pt->x, half_origin);
+ mul_m3_v3(rot_mat, &pt->x);
+ add_v3_v3(&pt->x, half_origin);
+
+ /* Undo local transformation to avoid double transform in drawing. */
+ mul_m3_v3(inv_mat, &pt->x);
+ }
+}
+
+static void update_position(Object *ob, MirrorGpencilModifierData *mmd, bGPDstroke *gps, int axis)
+{
+ if (mmd->object == NULL) {
+ update_mirror_local(gps, axis);
+ }
+ else {
+ update_mirror_object(ob, mmd, gps, axis);
}
}
@@ -130,7 +162,7 @@ static void generate_geometry(GpencilModifierData *md, Object *ob, bGPDlayer *gp
for (i = 0, gps = gpf->strokes.first; i < tot_strokes; i++, gps = gps->next) {
if (is_stroke_affected_by_modifier(ob,
mmd->layername,
- mmd->materialname,
+ mmd->material,
mmd->pass_index,
mmd->layer_pass,
1,
@@ -213,6 +245,15 @@ static void foreachObjectLink(GpencilModifierData *md,
walk(userData, ob, &mmd->object, IDWALK_CB_NOP);
}
+static void foreachIDLink(GpencilModifierData *md, Object *ob, IDWalkFunc walk, void *userData)
+{
+ MirrorGpencilModifierData *mmd = (MirrorGpencilModifierData *)md;
+
+ walk(userData, ob, (ID **)&mmd->material, IDWALK_CB_USER);
+
+ foreachObjectLink(md, ob, (ObjectWalkFunc)walk, userData);
+}
+
GpencilModifierTypeInfo modifierType_Gpencil_Mirror = {
/* name */ "Mirror",
/* structName */ "MirrorGpencilModifierData",
@@ -233,6 +274,6 @@ GpencilModifierTypeInfo modifierType_Gpencil_Mirror = {
/* updateDepsgraph */ updateDepsgraph,
/* dependsOnTime */ NULL,
/* foreachObjectLink */ foreachObjectLink,
- /* foreachIDLink */ NULL,
+ /* foreachIDLink */ foreachIDLink,
/* foreachTexLink */ NULL,
};
diff --git a/source/blender/gpencil_modifiers/intern/MOD_gpencilmultiply.c b/source/blender/gpencil_modifiers/intern/MOD_gpencilmultiply.c
index 2552f527a5e..22e46626a13 100644
--- a/source/blender/gpencil_modifiers/intern/MOD_gpencilmultiply.c
+++ b/source/blender/gpencil_modifiers/intern/MOD_gpencilmultiply.c
@@ -10,7 +10,7 @@
* 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,
+ * 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
@@ -71,11 +71,12 @@ static void initData(GpencilModifierData *md)
mmd->fading_center = 0.5f;
mmd->fading_thickness = 0.5f;
mmd->fading_opacity = 0.5f;
+ mmd->material = NULL;
}
static void copyData(const GpencilModifierData *md, GpencilModifierData *target)
{
- BKE_gpencil_modifier_copyData_generic(md, target);
+ BKE_gpencil_modifier_copydata_generic(md, target);
}
static void minter_v3_v3v3v3_ref(
@@ -211,7 +212,7 @@ static void bakeModifier(Main *UNUSED(bmain),
for (gps = gpf->strokes.first; gps; gps = gps->next) {
if (!is_stroke_affected_by_modifier(ob,
mmd->layername,
- mmd->materialname,
+ mmd->material,
mmd->pass_index,
mmd->layer_pass,
1,
@@ -252,7 +253,7 @@ static void generate_geometry(GpencilModifierData *md, Object *ob, bGPDlayer *gp
for (gps = gpf->strokes.first; gps; gps = gps->next) {
if (!is_stroke_affected_by_modifier(ob,
mmd->layername,
- mmd->materialname,
+ mmd->material,
mmd->pass_index,
mmd->layer_pass,
1,
@@ -297,6 +298,13 @@ static void generateStrokes(GpencilModifierData *md, Depsgraph *depsgraph, Objec
}
}
+static void foreachIDLink(GpencilModifierData *md, Object *ob, IDWalkFunc walk, void *userData)
+{
+ MultiplyGpencilModifierData *mmd = (MultiplyGpencilModifierData *)md;
+
+ walk(userData, ob, (ID **)&mmd->material, IDWALK_CB_USER);
+}
+
GpencilModifierTypeInfo modifierType_Gpencil_Multiply = {
/* name */ "Multiple Strokes",
/* structName */ "MultiplyGpencilModifierData",
@@ -317,6 +325,6 @@ GpencilModifierTypeInfo modifierType_Gpencil_Multiply = {
/* updateDepsgraph */ NULL,
/* dependsOnTime */ NULL,
/* foreachObjectLink */ NULL,
- /* foreachIDLink */ NULL,
+ /* foreachIDLink */ foreachIDLink,
/* foreachTexLink */ NULL,
};
diff --git a/source/blender/gpencil_modifiers/intern/MOD_gpencilnoise.c b/source/blender/gpencil_modifiers/intern/MOD_gpencilnoise.c
index 5ed08e39197..73328d7dd31 100644
--- a/source/blender/gpencil_modifiers/intern/MOD_gpencilnoise.c
+++ b/source/blender/gpencil_modifiers/intern/MOD_gpencilnoise.c
@@ -10,7 +10,7 @@
* 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,
+ * 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
@@ -44,6 +44,8 @@
#include "BKE_gpencil.h"
#include "BKE_gpencil_geom.h"
#include "BKE_gpencil_modifier.h"
+#include "BKE_lib_query.h"
+#include "BKE_modifier.h"
#include "BKE_object.h"
#include "DEG_depsgraph.h"
@@ -59,9 +61,7 @@ static void initData(GpencilModifierData *md)
gpmd->flag |= GP_NOISE_FULL_STROKE;
gpmd->flag |= GP_NOISE_USE_RANDOM;
gpmd->factor = 0.5f;
- gpmd->layername[0] = '\0';
- gpmd->materialname[0] = '\0';
- gpmd->vgname[0] = '\0';
+ gpmd->material = NULL;
gpmd->step = 4;
gpmd->seed = 1;
gpmd->curve_intensity = BKE_curvemapping_add(1, 0.0f, 0.0f, 1.0f, 1.0f);
@@ -91,7 +91,7 @@ static void copyData(const GpencilModifierData *md, GpencilModifierData *target)
tgmd->curve_intensity = NULL;
}
- BKE_gpencil_modifier_copyData_generic(md, target);
+ BKE_gpencil_modifier_copydata_generic(md, target);
tgmd->curve_intensity = BKE_curvemapping_copy(gmd->curve_intensity);
}
@@ -135,7 +135,7 @@ static void deformStroke(GpencilModifierData *md,
if (!is_stroke_affected_by_modifier(ob,
mmd->layername,
- mmd->materialname,
+ mmd->material,
mmd->pass_index,
mmd->layer_pass,
1,
@@ -170,9 +170,12 @@ static void deformStroke(GpencilModifierData *md,
float *noise_table_thickness = (mmd->factor_thickness > 0.0f) ? noise_table(len, seed) : NULL;
float *noise_table_uvs = (mmd->factor_uvs > 0.0f) ? noise_table(len, seed + 4) : NULL;
- /* calculate stroke normal*/
+ /* Calculate stroke normal. */
if (gps->totpoints > 2) {
BKE_gpencil_stroke_normal(gps, normal);
+ if (is_zero_v3(normal)) {
+ copy_v3_fl(normal, 1.0f);
+ }
}
else {
copy_v3_fl(normal, 1.0f);
@@ -259,6 +262,13 @@ static void bakeModifier(struct Main *UNUSED(bmain),
}
}
+static void foreachIDLink(GpencilModifierData *md, Object *ob, IDWalkFunc walk, void *userData)
+{
+ NoiseGpencilModifierData *mmd = (NoiseGpencilModifierData *)md;
+
+ walk(userData, ob, (ID **)&mmd->material, IDWALK_CB_USER);
+}
+
GpencilModifierTypeInfo modifierType_Gpencil_Noise = {
/* name */ "Noise",
/* structName */ "NoiseGpencilModifierData",
@@ -279,6 +289,6 @@ GpencilModifierTypeInfo modifierType_Gpencil_Noise = {
/* updateDepsgraph */ NULL,
/* dependsOnTime */ dependsOnTime,
/* foreachObjectLink */ NULL,
- /* foreachIDLink */ NULL,
+ /* foreachIDLink */ foreachIDLink,
/* foreachTexLink */ NULL,
};
diff --git a/source/blender/gpencil_modifiers/intern/MOD_gpenciloffset.c b/source/blender/gpencil_modifiers/intern/MOD_gpenciloffset.c
index a78de314c21..686f589ffe9 100644
--- a/source/blender/gpencil_modifiers/intern/MOD_gpenciloffset.c
+++ b/source/blender/gpencil_modifiers/intern/MOD_gpenciloffset.c
@@ -10,7 +10,7 @@
* 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,
+ * 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
@@ -38,6 +38,8 @@
#include "BKE_deform.h"
#include "BKE_gpencil_geom.h"
#include "BKE_gpencil_modifier.h"
+#include "BKE_lib_query.h"
+#include "BKE_modifier.h"
#include "DEG_depsgraph.h"
@@ -48,9 +50,7 @@ static void initData(GpencilModifierData *md)
{
OffsetGpencilModifierData *gpmd = (OffsetGpencilModifierData *)md;
gpmd->pass_index = 0;
- gpmd->layername[0] = '\0';
- gpmd->materialname[0] = '\0';
- gpmd->vgname[0] = '\0';
+ gpmd->material = NULL;
ARRAY_SET_ITEMS(gpmd->loc, 0.0f, 0.0f, 0.0f);
ARRAY_SET_ITEMS(gpmd->rot, 0.0f, 0.0f, 0.0f);
ARRAY_SET_ITEMS(gpmd->scale, 0.0f, 0.0f, 0.0f);
@@ -58,7 +58,7 @@ static void initData(GpencilModifierData *md)
static void copyData(const GpencilModifierData *md, GpencilModifierData *target)
{
- BKE_gpencil_modifier_copyData_generic(md, target);
+ BKE_gpencil_modifier_copydata_generic(md, target);
}
/* change stroke offsetness */
@@ -77,7 +77,7 @@ static void deformStroke(GpencilModifierData *md,
if (!is_stroke_affected_by_modifier(ob,
mmd->layername,
- mmd->materialname,
+ mmd->material,
mmd->pass_index,
mmd->layer_pass,
1,
@@ -129,6 +129,13 @@ static void bakeModifier(struct Main *UNUSED(bmain),
}
}
+static void foreachIDLink(GpencilModifierData *md, Object *ob, IDWalkFunc walk, void *userData)
+{
+ OffsetGpencilModifierData *mmd = (OffsetGpencilModifierData *)md;
+
+ walk(userData, ob, (ID **)&mmd->material, IDWALK_CB_USER);
+}
+
GpencilModifierTypeInfo modifierType_Gpencil_Offset = {
/* name */ "Offset",
/* structName */ "OffsetGpencilModifierData",
@@ -149,6 +156,6 @@ GpencilModifierTypeInfo modifierType_Gpencil_Offset = {
/* updateDepsgraph */ NULL,
/* dependsOnTime */ NULL,
/* foreachObjectLink */ NULL,
- /* foreachIDLink */ NULL,
+ /* foreachIDLink */ foreachIDLink,
/* foreachTexLink */ NULL,
};
diff --git a/source/blender/gpencil_modifiers/intern/MOD_gpencilopacity.c b/source/blender/gpencil_modifiers/intern/MOD_gpencilopacity.c
index 93f3776827b..92b2621d211 100644
--- a/source/blender/gpencil_modifiers/intern/MOD_gpencilopacity.c
+++ b/source/blender/gpencil_modifiers/intern/MOD_gpencilopacity.c
@@ -10,7 +10,7 @@
* 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,
+ * 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
@@ -38,8 +38,10 @@
#include "BKE_deform.h"
#include "BKE_gpencil.h"
#include "BKE_gpencil_modifier.h"
+#include "BKE_lib_query.h"
#include "BKE_main.h"
#include "BKE_material.h"
+#include "BKE_modifier.h"
#include "DEG_depsgraph.h"
@@ -52,9 +54,7 @@ static void initData(GpencilModifierData *md)
gpmd->pass_index = 0;
gpmd->factor = 1.0f;
gpmd->hardeness = 1.0f;
- gpmd->layername[0] = '\0';
- gpmd->materialname[0] = '\0';
- gpmd->vgname[0] = '\0';
+ gpmd->material = NULL;
gpmd->modify_color = GP_MODIFY_COLOR_BOTH;
gpmd->curve_intensity = BKE_curvemapping_add(1, 0.0f, 0.0f, 1.0f, 1.0f);
if (gpmd->curve_intensity) {
@@ -73,7 +73,7 @@ static void copyData(const GpencilModifierData *md, GpencilModifierData *target)
tgmd->curve_intensity = NULL;
}
- BKE_gpencil_modifier_copyData_generic(md, target);
+ BKE_gpencil_modifier_copydata_generic(md, target);
tgmd->curve_intensity = BKE_curvemapping_copy(gmd->curve_intensity);
}
@@ -92,7 +92,7 @@ static void deformStroke(GpencilModifierData *md,
if (!is_stroke_affected_by_modifier(ob,
mmd->layername,
- mmd->materialname,
+ mmd->material,
mmd->pass_index,
mmd->layer_pass,
1,
@@ -105,8 +105,8 @@ static void deformStroke(GpencilModifierData *md,
return;
}
- /* Hardeness (at stroke level). */
- if (mmd->modify_color == GP_MODIFY_COLOR_HARDENESS) {
+ /* Hardness (at stroke level). */
+ if (mmd->modify_color == GP_MODIFY_COLOR_HARDNESS) {
gps->hardeness *= mmd->hardeness;
CLAMP(gps->hardeness, 0.0f, 1.0f);
@@ -189,6 +189,13 @@ static void freeData(GpencilModifierData *md)
}
}
+static void foreachIDLink(GpencilModifierData *md, Object *ob, IDWalkFunc walk, void *userData)
+{
+ OpacityGpencilModifierData *mmd = (OpacityGpencilModifierData *)md;
+
+ walk(userData, ob, (ID **)&mmd->material, IDWALK_CB_USER);
+}
+
GpencilModifierTypeInfo modifierType_Gpencil_Opacity = {
/* name */ "Opacity",
/* structName */ "OpacityGpencilModifierData",
@@ -209,6 +216,6 @@ GpencilModifierTypeInfo modifierType_Gpencil_Opacity = {
/* updateDepsgraph */ NULL,
/* dependsOnTime */ NULL,
/* foreachObjectLink */ NULL,
- /* foreachIDLink */ NULL,
+ /* foreachIDLink */ foreachIDLink,
/* foreachTexLink */ NULL,
};
diff --git a/source/blender/gpencil_modifiers/intern/MOD_gpencilsimplify.c b/source/blender/gpencil_modifiers/intern/MOD_gpencilsimplify.c
index 7b914b2a3b0..2cda108682e 100644
--- a/source/blender/gpencil_modifiers/intern/MOD_gpencilsimplify.c
+++ b/source/blender/gpencil_modifiers/intern/MOD_gpencilsimplify.c
@@ -10,7 +10,7 @@
* 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,
+ * 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
@@ -34,6 +34,8 @@
#include "BKE_gpencil_geom.h"
#include "BKE_gpencil_modifier.h"
+#include "BKE_lib_query.h"
+#include "BKE_modifier.h"
#include "DEG_depsgraph.h"
@@ -48,13 +50,12 @@ static void initData(GpencilModifierData *md)
gpmd->factor = 0.0f;
gpmd->length = 0.1f;
gpmd->distance = 0.1f;
- gpmd->layername[0] = '\0';
- gpmd->materialname[0] = '\0';
+ gpmd->material = NULL;
}
static void copyData(const GpencilModifierData *md, GpencilModifierData *target)
{
- BKE_gpencil_modifier_copyData_generic(md, target);
+ BKE_gpencil_modifier_copydata_generic(md, target);
}
static void deformStroke(GpencilModifierData *md,
@@ -68,7 +69,7 @@ static void deformStroke(GpencilModifierData *md,
if (!is_stroke_affected_by_modifier(ob,
mmd->layername,
- mmd->materialname,
+ mmd->material,
mmd->pass_index,
mmd->layer_pass,
mmd->mode == GP_SIMPLIFY_SAMPLE ? 3 : 4,
@@ -123,6 +124,13 @@ static void bakeModifier(struct Main *UNUSED(bmain),
}
}
+static void foreachIDLink(GpencilModifierData *md, Object *ob, IDWalkFunc walk, void *userData)
+{
+ SimplifyGpencilModifierData *mmd = (SimplifyGpencilModifierData *)md;
+
+ walk(userData, ob, (ID **)&mmd->material, IDWALK_CB_USER);
+}
+
GpencilModifierTypeInfo modifierType_Gpencil_Simplify = {
/* name */ "Simplify",
/* structName */ "SimplifyGpencilModifierData",
@@ -143,6 +151,6 @@ GpencilModifierTypeInfo modifierType_Gpencil_Simplify = {
/* updateDepsgraph */ NULL,
/* dependsOnTime */ NULL,
/* foreachObjectLink */ NULL,
- /* foreachIDLink */ NULL,
+ /* foreachIDLink */ foreachIDLink,
/* foreachTexLink */ NULL,
};
diff --git a/source/blender/gpencil_modifiers/intern/MOD_gpencilsmooth.c b/source/blender/gpencil_modifiers/intern/MOD_gpencilsmooth.c
index fb9089ea6cb..e2e13b736e4 100644
--- a/source/blender/gpencil_modifiers/intern/MOD_gpencilsmooth.c
+++ b/source/blender/gpencil_modifiers/intern/MOD_gpencilsmooth.c
@@ -10,7 +10,7 @@
* 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,
+ * 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
@@ -35,6 +35,8 @@
#include "BKE_deform.h"
#include "BKE_gpencil_geom.h"
#include "BKE_gpencil_modifier.h"
+#include "BKE_lib_query.h"
+#include "BKE_modifier.h"
#include "DEG_depsgraph.h"
@@ -47,9 +49,7 @@ static void initData(GpencilModifierData *md)
gpmd->pass_index = 0;
gpmd->flag |= GP_SMOOTH_MOD_LOCATION;
gpmd->factor = 0.5f;
- gpmd->layername[0] = '\0';
- gpmd->materialname[0] = '\0';
- gpmd->vgname[0] = '\0';
+ gpmd->material = NULL;
gpmd->step = 1;
gpmd->curve_intensity = BKE_curvemapping_add(1, 0.0f, 0.0f, 1.0f, 1.0f);
@@ -69,7 +69,7 @@ static void copyData(const GpencilModifierData *md, GpencilModifierData *target)
tgmd->curve_intensity = NULL;
}
- BKE_gpencil_modifier_copyData_generic(md, target);
+ BKE_gpencil_modifier_copydata_generic(md, target);
tgmd->curve_intensity = BKE_curvemapping_copy(gmd->curve_intensity);
}
@@ -88,7 +88,7 @@ static void deformStroke(GpencilModifierData *md,
if (!is_stroke_affected_by_modifier(ob,
mmd->layername,
- mmd->materialname,
+ mmd->material,
mmd->pass_index,
mmd->layer_pass,
3,
@@ -167,6 +167,13 @@ static void freeData(GpencilModifierData *md)
}
}
+static void foreachIDLink(GpencilModifierData *md, Object *ob, IDWalkFunc walk, void *userData)
+{
+ SmoothGpencilModifierData *mmd = (SmoothGpencilModifierData *)md;
+
+ walk(userData, ob, (ID **)&mmd->material, IDWALK_CB_USER);
+}
+
GpencilModifierTypeInfo modifierType_Gpencil_Smooth = {
/* name */ "Smooth",
/* structName */ "SmoothGpencilModifierData",
@@ -187,6 +194,6 @@ GpencilModifierTypeInfo modifierType_Gpencil_Smooth = {
/* updateDepsgraph */ NULL,
/* dependsOnTime */ NULL,
/* foreachObjectLink */ NULL,
- /* foreachIDLink */ NULL,
+ /* foreachIDLink */ foreachIDLink,
/* foreachTexLink */ NULL,
};
diff --git a/source/blender/gpencil_modifiers/intern/MOD_gpencilsubdiv.c b/source/blender/gpencil_modifiers/intern/MOD_gpencilsubdiv.c
index 0fdc3694af2..072159136ce 100644
--- a/source/blender/gpencil_modifiers/intern/MOD_gpencilsubdiv.c
+++ b/source/blender/gpencil_modifiers/intern/MOD_gpencilsubdiv.c
@@ -10,7 +10,7 @@
* 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,
+ * 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
@@ -36,6 +36,8 @@
#include "BKE_gpencil_geom.h"
#include "BKE_gpencil_modifier.h"
+#include "BKE_lib_query.h"
+#include "BKE_modifier.h"
#include "DEG_depsgraph.h"
@@ -47,13 +49,12 @@ static void initData(GpencilModifierData *md)
SubdivGpencilModifierData *gpmd = (SubdivGpencilModifierData *)md;
gpmd->pass_index = 0;
gpmd->level = 1;
- gpmd->layername[0] = '\0';
- gpmd->materialname[0] = '\0';
+ gpmd->material = NULL;
}
static void copyData(const GpencilModifierData *md, GpencilModifierData *target)
{
- BKE_gpencil_modifier_copyData_generic(md, target);
+ BKE_gpencil_modifier_copydata_generic(md, target);
}
/* subdivide stroke to get more control points */
@@ -72,7 +73,7 @@ static void deformStroke(GpencilModifierData *md,
if (!is_stroke_affected_by_modifier(ob,
mmd->layername,
- mmd->materialname,
+ mmd->material,
mmd->pass_index,
mmd->layer_pass,
minimum_vert,
@@ -104,6 +105,13 @@ static void bakeModifier(struct Main *UNUSED(bmain),
}
}
+static void foreachIDLink(GpencilModifierData *md, Object *ob, IDWalkFunc walk, void *userData)
+{
+ SubdivGpencilModifierData *mmd = (SubdivGpencilModifierData *)md;
+
+ walk(userData, ob, (ID **)&mmd->material, IDWALK_CB_USER);
+}
+
GpencilModifierTypeInfo modifierType_Gpencil_Subdiv = {
/* name */ "Subdivide",
/* structName */ "SubdivGpencilModifierData",
@@ -124,6 +132,6 @@ GpencilModifierTypeInfo modifierType_Gpencil_Subdiv = {
/* updateDepsgraph */ NULL,
/* dependsOnTime */ NULL,
/* foreachObjectLink */ NULL,
- /* foreachIDLink */ NULL,
+ /* foreachIDLink */ foreachIDLink,
/* foreachTexLink */ NULL,
};
diff --git a/source/blender/gpencil_modifiers/intern/MOD_gpenciltexture.c b/source/blender/gpencil_modifiers/intern/MOD_gpenciltexture.c
new file mode 100644
index 00000000000..a5adf12b617
--- /dev/null
+++ b/source/blender/gpencil_modifiers/intern/MOD_gpenciltexture.c
@@ -0,0 +1,172 @@
+/*
+ * 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
+ * This is a new part of Blender
+ */
+
+/** \file
+ * \ingroup modifiers
+ */
+
+#include <stdio.h>
+
+#include "BLI_listbase.h"
+#include "BLI_math.h"
+#include "BLI_utildefines.h"
+
+#include "DNA_gpencil_modifier_types.h"
+#include "DNA_gpencil_types.h"
+#include "DNA_meshdata_types.h"
+#include "DNA_object_types.h"
+#include "DNA_scene_types.h"
+
+#include "BKE_colortools.h"
+#include "BKE_deform.h"
+#include "BKE_gpencil.h"
+#include "BKE_gpencil_geom.h"
+#include "BKE_gpencil_modifier.h"
+#include "BKE_lib_query.h"
+#include "BKE_modifier.h"
+
+#include "DEG_depsgraph.h"
+
+#include "MOD_gpencil_modifiertypes.h"
+#include "MOD_gpencil_util.h"
+
+static void initData(GpencilModifierData *md)
+{
+ TextureGpencilModifierData *gpmd = (TextureGpencilModifierData *)md;
+ gpmd->fit_method = GP_TEX_CONSTANT_LENGTH;
+ gpmd->fill_rotation = 0.0f;
+ gpmd->fill_scale = 1.0f;
+ gpmd->fill_offset[0] = 0.0f;
+ gpmd->fill_offset[1] = 0.0f;
+ gpmd->uv_offset = 0.0f;
+ gpmd->uv_scale = 1.0f;
+ gpmd->pass_index = 0;
+ gpmd->material = NULL;
+}
+
+static void copyData(const GpencilModifierData *md, GpencilModifierData *target)
+{
+ BKE_gpencil_modifier_copydata_generic(md, target);
+}
+
+/* change stroke uv texture values */
+static void deformStroke(GpencilModifierData *md,
+ Depsgraph *UNUSED(depsgraph),
+ Object *ob,
+ bGPDlayer *gpl,
+ bGPDframe *UNUSED(gpf),
+ bGPDstroke *gps)
+{
+ TextureGpencilModifierData *mmd = (TextureGpencilModifierData *)md;
+ const int def_nr = BKE_object_defgroup_name_index(ob, mmd->vgname);
+
+ if (!is_stroke_affected_by_modifier(ob,
+ mmd->layername,
+ mmd->material,
+ mmd->pass_index,
+ mmd->layer_pass,
+ 1,
+ gpl,
+ gps,
+ mmd->flag & GP_TEX_INVERT_LAYER,
+ mmd->flag & GP_TEX_INVERT_PASS,
+ mmd->flag & GP_TEX_INVERT_LAYERPASS,
+ mmd->flag & GP_TEX_INVERT_MATERIAL)) {
+ return;
+ }
+ if ((mmd->mode == FILL) || (mmd->mode == STROKE_AND_FILL)) {
+ gps->uv_rotation += mmd->fill_rotation;
+ gps->uv_translation[0] += mmd->fill_offset[0];
+ gps->uv_translation[1] += mmd->fill_offset[1];
+ gps->uv_scale *= mmd->fill_scale;
+ BKE_gpencil_stroke_geometry_update(gps);
+ }
+
+ if ((mmd->mode == STROKE) || (mmd->mode == STROKE_AND_FILL)) {
+ float totlen = 1.0f;
+ if (mmd->fit_method == GP_TEX_FIT_STROKE) {
+ totlen = 0.0f;
+ for (int i = 1; i < gps->totpoints; i++) {
+ totlen += len_v3v3(&gps->points[i - 1].x, &gps->points[i].x);
+ }
+ }
+
+ for (int i = 0; i < gps->totpoints; i++) {
+ bGPDspoint *pt = &gps->points[i];
+ MDeformVert *dvert = gps->dvert != NULL ? &gps->dvert[i] : NULL;
+ /* Verify point is part of vertex group. */
+ float weight = get_modifier_point_weight(
+ dvert, (mmd->flag & GP_TEX_INVERT_VGROUP) != 0, def_nr);
+ if (weight < 0.0f) {
+ continue;
+ }
+
+ pt->uv_fac /= totlen;
+ pt->uv_fac *= mmd->uv_scale;
+ pt->uv_fac += mmd->uv_offset;
+ }
+ }
+}
+
+static void bakeModifier(struct Main *UNUSED(bmain),
+ Depsgraph *depsgraph,
+ GpencilModifierData *md,
+ Object *ob)
+{
+ bGPdata *gpd = ob->data;
+
+ LISTBASE_FOREACH (bGPDlayer *, gpl, &gpd->layers) {
+ LISTBASE_FOREACH (bGPDframe *, gpf, &gpl->frames) {
+ LISTBASE_FOREACH (bGPDstroke *, gps, &gpf->strokes) {
+ deformStroke(md, depsgraph, ob, gpl, gpf, gps);
+ }
+ }
+ }
+}
+
+static void foreachIDLink(GpencilModifierData *md, Object *ob, IDWalkFunc walk, void *userData)
+{
+ TextureGpencilModifierData *mmd = (TextureGpencilModifierData *)md;
+
+ walk(userData, ob, (ID **)&mmd->material, IDWALK_CB_USER);
+}
+
+GpencilModifierTypeInfo modifierType_Gpencil_Texture = {
+ /* name */ "Texture Mapping",
+ /* structName */ "TextureGpencilModifierData",
+ /* structSize */ sizeof(TextureGpencilModifierData),
+ /* type */ eGpencilModifierTypeType_Gpencil,
+ /* flags */ eGpencilModifierTypeFlag_SupportsEditmode,
+
+ /* copyData */ copyData,
+
+ /* deformStroke */ deformStroke,
+ /* generateStrokes */ NULL,
+ /* bakeModifier */ bakeModifier,
+ /* remapTime */ NULL,
+
+ /* initData */ initData,
+ /* freeData */ NULL,
+ /* isDisabled */ NULL,
+ /* updateDepsgraph */ NULL,
+ /* dependsOnTime */ NULL,
+ /* foreachObjectLink */ NULL,
+ /* foreachIDLink */ foreachIDLink,
+ /* foreachTexLink */ NULL,
+};
diff --git a/source/blender/gpencil_modifiers/intern/MOD_gpencilthick.c b/source/blender/gpencil_modifiers/intern/MOD_gpencilthick.c
index 0c5f47eb9d4..b9fadea7fd0 100644
--- a/source/blender/gpencil_modifiers/intern/MOD_gpencilthick.c
+++ b/source/blender/gpencil_modifiers/intern/MOD_gpencilthick.c
@@ -10,7 +10,7 @@
* 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,
+ * 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
@@ -37,6 +37,8 @@
#include "BKE_deform.h"
#include "BKE_gpencil.h"
#include "BKE_gpencil_modifier.h"
+#include "BKE_lib_query.h"
+#include "BKE_modifier.h"
#include "DEG_depsgraph.h"
@@ -49,9 +51,7 @@ static void initData(GpencilModifierData *md)
gpmd->pass_index = 0;
gpmd->thickness_fac = 1.0f;
gpmd->thickness = 30;
- gpmd->layername[0] = '\0';
- gpmd->materialname[0] = '\0';
- gpmd->vgname[0] = '\0';
+ gpmd->material = NULL;
gpmd->curve_thickness = BKE_curvemapping_add(1, 0.0f, 0.0f, 1.0f, 1.0f);
if (gpmd->curve_thickness) {
BKE_curvemapping_initialize(gpmd->curve_thickness);
@@ -77,7 +77,7 @@ static void copyData(const GpencilModifierData *md, GpencilModifierData *target)
tgmd->curve_thickness = NULL;
}
- BKE_gpencil_modifier_copyData_generic(md, target);
+ BKE_gpencil_modifier_copydata_generic(md, target);
tgmd->curve_thickness = BKE_curvemapping_copy(gmd->curve_thickness);
}
@@ -95,7 +95,7 @@ static void deformStroke(GpencilModifierData *md,
if (!is_stroke_affected_by_modifier(ob,
mmd->layername,
- mmd->materialname,
+ mmd->material,
mmd->pass_index,
mmd->layer_pass,
1,
@@ -139,7 +139,7 @@ static void deformStroke(GpencilModifierData *md,
pt->pressure = interpf(target, pt->pressure, weight);
- CLAMP_MIN(pt->pressure, 0.1f);
+ CLAMP_MIN(pt->pressure, 0.0f);
}
}
@@ -159,6 +159,13 @@ static void bakeModifier(struct Main *UNUSED(bmain),
}
}
+static void foreachIDLink(GpencilModifierData *md, Object *ob, IDWalkFunc walk, void *userData)
+{
+ ThickGpencilModifierData *mmd = (ThickGpencilModifierData *)md;
+
+ walk(userData, ob, (ID **)&mmd->material, IDWALK_CB_USER);
+}
+
GpencilModifierTypeInfo modifierType_Gpencil_Thick = {
/* name */ "Thickness",
/* structName */ "ThickGpencilModifierData",
@@ -179,6 +186,6 @@ GpencilModifierTypeInfo modifierType_Gpencil_Thick = {
/* updateDepsgraph */ NULL,
/* dependsOnTime */ NULL,
/* foreachObjectLink */ NULL,
- /* foreachIDLink */ NULL,
+ /* foreachIDLink */ foreachIDLink,
/* foreachTexLink */ NULL,
};
diff --git a/source/blender/gpencil_modifiers/intern/MOD_gpenciltime.c b/source/blender/gpencil_modifiers/intern/MOD_gpenciltime.c
index 10463f865e2..85400b56cad 100644
--- a/source/blender/gpencil_modifiers/intern/MOD_gpenciltime.c
+++ b/source/blender/gpencil_modifiers/intern/MOD_gpenciltime.c
@@ -10,7 +10,7 @@
* 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,
+ * 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) 2018, Blender Foundation
@@ -45,7 +45,6 @@
static void initData(GpencilModifierData *md)
{
TimeGpencilModifierData *gpmd = (TimeGpencilModifierData *)md;
- gpmd->layername[0] = '\0';
gpmd->offset = 1;
gpmd->frame_scale = 1.0f;
gpmd->flag |= GP_TIME_KEEP_LOOP;
@@ -55,7 +54,7 @@ static void initData(GpencilModifierData *md)
static void copyData(const GpencilModifierData *md, GpencilModifierData *target)
{
- BKE_gpencil_modifier_copyData_generic(md, target);
+ BKE_gpencil_modifier_copydata_generic(md, target);
}
static int remapTime(struct GpencilModifierData *md,
diff --git a/source/blender/gpencil_modifiers/intern/MOD_gpenciltint.c b/source/blender/gpencil_modifiers/intern/MOD_gpenciltint.c
index 95a7fb53018..c35728bc8b3 100644
--- a/source/blender/gpencil_modifiers/intern/MOD_gpenciltint.c
+++ b/source/blender/gpencil_modifiers/intern/MOD_gpenciltint.c
@@ -10,7 +10,7 @@
* 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,
+ * 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
@@ -61,9 +61,7 @@ static void initData(GpencilModifierData *md)
{
TintGpencilModifierData *gpmd = (TintGpencilModifierData *)md;
gpmd->pass_index = 0;
- gpmd->layername[0] = '\0';
- gpmd->materialname[0] = '\0';
- gpmd->vgname[0] = '\0';
+ gpmd->material = NULL;
gpmd->object = NULL;
gpmd->radius = 1.0f;
gpmd->factor = 0.5f;
@@ -103,7 +101,7 @@ static void copyData(const GpencilModifierData *md, GpencilModifierData *target)
tgmd->curve_intensity = NULL;
}
- BKE_gpencil_modifier_copyData_generic(md, target);
+ BKE_gpencil_modifier_copydata_generic(md, target);
if (gmd->colorband) {
tgmd->colorband = MEM_dupallocN(gmd->colorband);
@@ -130,7 +128,7 @@ static void deformStroke(GpencilModifierData *md,
if (!is_stroke_affected_by_modifier(ob,
mmd->layername,
- mmd->materialname,
+ mmd->material,
mmd->pass_index,
mmd->layer_pass,
1,
@@ -323,6 +321,15 @@ static void foreachObjectLink(GpencilModifierData *md,
walk(userData, ob, &mmd->object, IDWALK_CB_NOP);
}
+static void foreachIDLink(GpencilModifierData *md, Object *ob, IDWalkFunc walk, void *userData)
+{
+ TintGpencilModifierData *mmd = (TintGpencilModifierData *)md;
+
+ walk(userData, ob, (ID **)&mmd->material, IDWALK_CB_USER);
+
+ foreachObjectLink(md, ob, (ObjectWalkFunc)walk, userData);
+}
+
GpencilModifierTypeInfo modifierType_Gpencil_Tint = {
/* name */ "Tint",
/* structName */ "TintGpencilModifierData",
@@ -343,6 +350,6 @@ GpencilModifierTypeInfo modifierType_Gpencil_Tint = {
/* updateDepsgraph */ updateDepsgraph,
/* dependsOnTime */ NULL,
/* foreachObjectLink */ foreachObjectLink,
- /* foreachIDLink */ NULL,
+ /* foreachIDLink */ foreachIDLink,
/* foreachTexLink */ NULL,
};
diff --git a/source/blender/gpu/CMakeLists.txt b/source/blender/gpu/CMakeLists.txt
index cf1d449ad3b..1d6a5031d7e 100644
--- a/source/blender/gpu/CMakeLists.txt
+++ b/source/blender/gpu/CMakeLists.txt
@@ -146,8 +146,6 @@ data_to_c_simple(shaders/gpu_shader_uniform_color_frag.glsl SRC)
data_to_c_simple(shaders/gpu_shader_checker_frag.glsl SRC)
data_to_c_simple(shaders/gpu_shader_diag_stripes_frag.glsl SRC)
data_to_c_simple(shaders/gpu_shader_simple_lighting_frag.glsl SRC)
-data_to_c_simple(shaders/gpu_shader_simple_lighting_smooth_color_frag.glsl SRC)
-data_to_c_simple(shaders/gpu_shader_simple_lighting_smooth_color_alpha_frag.glsl SRC)
data_to_c_simple(shaders/gpu_shader_flat_color_frag.glsl SRC)
data_to_c_simple(shaders/gpu_shader_flat_color_alpha_test_0_frag.glsl SRC)
data_to_c_simple(shaders/gpu_shader_flat_id_frag.glsl SRC)
@@ -165,7 +163,6 @@ data_to_c_simple(shaders/gpu_shader_2D_line_dashed_uniform_color_vert.glsl SRC)
data_to_c_simple(shaders/gpu_shader_2D_line_dashed_frag.glsl SRC)
data_to_c_simple(shaders/gpu_shader_2D_smooth_color_vert.glsl SRC)
data_to_c_simple(shaders/gpu_shader_2D_smooth_color_frag.glsl SRC)
-data_to_c_simple(shaders/gpu_shader_2D_smooth_color_dithered_frag.glsl SRC)
data_to_c_simple(shaders/gpu_shader_2D_image_vert.glsl SRC)
data_to_c_simple(shaders/gpu_shader_2D_image_rect_vert.glsl SRC)
data_to_c_simple(shaders/gpu_shader_2D_image_multi_rect_vert.glsl SRC)
@@ -179,16 +176,15 @@ data_to_c_simple(shaders/gpu_shader_image_modulate_alpha_frag.glsl SRC)
data_to_c_simple(shaders/gpu_shader_image_alpha_color_frag.glsl SRC)
data_to_c_simple(shaders/gpu_shader_image_color_frag.glsl SRC)
data_to_c_simple(shaders/gpu_shader_image_varying_color_frag.glsl SRC)
-data_to_c_simple(shaders/gpu_shader_image_depth_linear_frag.glsl SRC)
-data_to_c_simple(shaders/gpu_shader_image_depth_copy_frag.glsl SRC)
-data_to_c_simple(shaders/gpu_shader_image_multisample_resolve_frag.glsl SRC)
data_to_c_simple(shaders/gpu_shader_3D_image_vert.glsl SRC)
data_to_c_simple(shaders/gpu_shader_3D_vert.glsl SRC)
data_to_c_simple(shaders/gpu_shader_3D_normal_vert.glsl SRC)
data_to_c_simple(shaders/gpu_shader_3D_flat_color_vert.glsl SRC)
data_to_c_simple(shaders/gpu_shader_3D_line_dashed_uniform_color_vert.glsl SRC)
+data_to_c_simple(shaders/gpu_shader_3D_polyline_frag.glsl SRC)
+data_to_c_simple(shaders/gpu_shader_3D_polyline_geom.glsl SRC)
+data_to_c_simple(shaders/gpu_shader_3D_polyline_vert.glsl SRC)
data_to_c_simple(shaders/gpu_shader_3D_smooth_color_vert.glsl SRC)
-data_to_c_simple(shaders/gpu_shader_3D_normal_smooth_color_vert.glsl SRC)
data_to_c_simple(shaders/gpu_shader_3D_smooth_color_frag.glsl SRC)
data_to_c_simple(shaders/gpu_shader_3D_passthrough_vert.glsl SRC)
data_to_c_simple(shaders/gpu_shader_3D_clipped_uniform_color_vert.glsl SRC)
@@ -321,6 +317,7 @@ data_to_c_simple(shaders/gpu_shader_gpencil_fill_vert.glsl SRC)
data_to_c_simple(shaders/gpu_shader_gpencil_fill_frag.glsl SRC)
data_to_c_simple(shaders/gpu_shader_cfg_world_clip_lib.glsl SRC)
+data_to_c_simple(shaders/gpu_shader_colorspace_lib.glsl SRC)
data_to_c_simple(shaders/gpu_shader_common_obinfos_lib.glsl SRC)
diff --git a/source/blender/gpu/GPU_batch_presets.h b/source/blender/gpu/GPU_batch_presets.h
index ba8ad3c4990..eb803333d98 100644
--- a/source/blender/gpu/GPU_batch_presets.h
+++ b/source/blender/gpu/GPU_batch_presets.h
@@ -39,6 +39,10 @@ extern "C" {
/* Replacement for gluSphere */
struct GPUBatch *GPU_batch_preset_sphere(int lod) ATTR_WARN_UNUSED_RESULT;
struct GPUBatch *GPU_batch_preset_sphere_wire(int lod) ATTR_WARN_UNUSED_RESULT;
+struct GPUBatch *GPU_batch_preset_panel_drag_widget(const float pixelsize,
+ const float col_high[4],
+ const float col_dark[4],
+ const float width) ATTR_WARN_UNUSED_RESULT;
void gpu_batch_presets_init(void);
void gpu_batch_presets_register(struct GPUBatch *preset_batch);
diff --git a/source/blender/gpu/GPU_buffers.h b/source/blender/gpu/GPU_buffers.h
index 9d91fd79137..ab16bfc43c4 100644
--- a/source/blender/gpu/GPU_buffers.h
+++ b/source/blender/gpu/GPU_buffers.h
@@ -42,14 +42,14 @@ struct MPoly;
struct MVert;
struct Mesh;
struct PBVH;
+struct SubdivCCG;
/* Buffers for drawing from PBVH grids. */
typedef struct GPU_PBVH_Buffers GPU_PBVH_Buffers;
/* Build must be called once before using the other functions, used every time
* mesh topology changes. Threaded. */
-GPU_PBVH_Buffers *GPU_pbvh_mesh_buffers_build(const int (*face_vert_indices)[3],
- const struct MPoly *mpoly,
+GPU_PBVH_Buffers *GPU_pbvh_mesh_buffers_build(const struct MPoly *mpoly,
const struct MLoop *mloop,
const struct MLoopTri *looptri,
const struct MVert *verts,
@@ -77,14 +77,11 @@ enum {
void GPU_pbvh_mesh_buffers_update(GPU_PBVH_Buffers *buffers,
const struct MVert *mvert,
- const int *vert_indices,
- int totvert,
const float *vmask,
const struct MLoopCol *vcol,
const int *sculpt_face_sets,
const int face_sets_color_seed,
const int face_sets_color_default,
- const int (*face_vert_indices)[3],
const int update_flags);
void GPU_pbvh_bmesh_buffers_update(GPU_PBVH_Buffers *buffers,
@@ -95,10 +92,14 @@ void GPU_pbvh_bmesh_buffers_update(GPU_PBVH_Buffers *buffers,
const int update_flags);
void GPU_pbvh_grid_buffers_update(GPU_PBVH_Buffers *buffers,
+ struct SubdivCCG *subdiv_ccg,
struct CCGElem **grids,
const struct DMFlagMat *grid_flag_mats,
int *grid_indices,
int totgrid,
+ const int *sculpt_face_sets,
+ const int face_sets_color_seed,
+ const int face_sets_color_default,
const struct CCGKey *key,
const int update_flags);
diff --git a/source/blender/gpu/GPU_context.h b/source/blender/gpu/GPU_context.h
index dd7611fe2fc..9876aa6998c 100644
--- a/source/blender/gpu/GPU_context.h
+++ b/source/blender/gpu/GPU_context.h
@@ -26,14 +26,14 @@
#ifndef __GPU_CONTEXT_H__
#define __GPU_CONTEXT_H__
-#ifdef __cplusplus
-extern "C" {
-#endif
-
#include "GPU_batch.h"
#include "GPU_common.h"
#include "GPU_shader_interface.h"
+#ifdef __cplusplus
+extern "C" {
+#endif
+
typedef struct GPUContext GPUContext;
GPUContext *GPU_context_create(GLuint default_framebuffer);
diff --git a/source/blender/gpu/GPU_draw.h b/source/blender/gpu/GPU_draw.h
index f521fa3c702..ab507d852e8 100644
--- a/source/blender/gpu/GPU_draw.h
+++ b/source/blender/gpu/GPU_draw.h
@@ -24,6 +24,9 @@
#ifndef __GPU_DRAW_H__
#define __GPU_DRAW_H__
+#include "BLI_utildefines.h"
+#include "DNA_object_enums.h"
+
#ifdef __cplusplus
extern "C" {
#endif
@@ -34,18 +37,8 @@ struct Image;
struct ImageUser;
struct Main;
-#include "BLI_utildefines.h"
-#include "DNA_object_enums.h"
-
/* OpenGL drawing functions related to shading. */
-/* Initialize
- * - sets the default Blender opengl state, if in doubt, check
- * the contents of this function
- * - this is called when starting Blender, for opengl rendering. */
-
-void GPU_state_init(void);
-
/* Mipmap settings
* - these will free textures on changes */
@@ -57,7 +50,7 @@ void GPU_paint_set_mipmap(struct Main *bmain, bool mipmap);
/* Anisotropic filtering settings
* - these will free textures on changes */
-void GPU_set_anisotropic(struct Main *bmain, float value);
+void GPU_set_anisotropic(float value);
float GPU_get_anisotropic(void);
/* Image updates and free
diff --git a/source/blender/gpu/GPU_immediate_util.h b/source/blender/gpu/GPU_immediate_util.h
index 1cf6475408f..47b44b59461 100644
--- a/source/blender/gpu/GPU_immediate_util.h
+++ b/source/blender/gpu/GPU_immediate_util.h
@@ -70,6 +70,13 @@ void imm_draw_disk_partial_fill_2d(uint pos,
void imm_draw_box_wire_2d(uint pos, float x1, float y1, float x2, float y2);
void imm_draw_box_wire_3d(uint pos, float x1, float y1, float x2, float y2);
+void imm_draw_box_checker_2d_ex(float x1,
+ float y1,
+ float x2,
+ float y2,
+ const float color_primary[4],
+ const float color_secondary[4],
+ int checker_size);
void imm_draw_box_checker_2d(float x1, float y1, float x2, float y2);
void imm_draw_cube_fill_3d(uint pos, const float co[3], const float aspect[3]);
diff --git a/source/blender/gpu/GPU_init_exit.h b/source/blender/gpu/GPU_init_exit.h
index 0046eaa942b..3e30a1ddcf5 100644
--- a/source/blender/gpu/GPU_init_exit.h
+++ b/source/blender/gpu/GPU_init_exit.h
@@ -24,12 +24,12 @@
#ifndef __GPU_INIT_EXIT_H__
#define __GPU_INIT_EXIT_H__
+#include "BLI_utildefines.h"
+
#ifdef __cplusplus
extern "C" {
#endif
-#include "BLI_utildefines.h"
-
void GPU_init(void);
void GPU_exit(void);
bool GPU_is_initialized(void);
diff --git a/source/blender/gpu/GPU_material.h b/source/blender/gpu/GPU_material.h
index 337c0b03308..eeb2d2caef2 100644
--- a/source/blender/gpu/GPU_material.h
+++ b/source/blender/gpu/GPU_material.h
@@ -29,6 +29,8 @@
#include "BLI_sys_types.h" /* for bool */
+#include "GPU_texture.h" /* for eGPUSamplerState */
+
#ifdef __cplusplus
extern "C" {
#endif
@@ -138,8 +140,14 @@ typedef enum eGPUMaterialStatus {
GPUNodeLink *GPU_constant(const float *num);
GPUNodeLink *GPU_uniform(const float *num);
GPUNodeLink *GPU_attribute(GPUMaterial *mat, CustomDataType type, const char *name);
-GPUNodeLink *GPU_image(GPUMaterial *mat, struct Image *ima, struct ImageUser *iuser);
-GPUNodeLink *GPU_image_tiled(GPUMaterial *mat, struct Image *ima, struct ImageUser *iuser);
+GPUNodeLink *GPU_image(GPUMaterial *mat,
+ struct Image *ima,
+ struct ImageUser *iuser,
+ eGPUSamplerState sampler_state);
+GPUNodeLink *GPU_image_tiled(GPUMaterial *mat,
+ struct Image *ima,
+ struct ImageUser *iuser,
+ eGPUSamplerState sampler_state);
GPUNodeLink *GPU_image_tiled_mapping(GPUMaterial *mat, struct Image *ima, struct ImageUser *iuser);
GPUNodeLink *GPU_color_band(GPUMaterial *mat, int size, float *pixels, float *layer);
GPUNodeLink *GPU_volume_grid(GPUMaterial *mat, const char *name);
@@ -190,6 +198,7 @@ void GPU_materials_free(struct Main *bmain);
struct Scene *GPU_material_scene(GPUMaterial *material);
struct GPUPass *GPU_material_get_pass(GPUMaterial *material);
+struct GPUShader *GPU_material_get_shader(GPUMaterial *material);
struct Material *GPU_material_get_material(GPUMaterial *material);
eGPUMaterialStatus GPU_material_status(GPUMaterial *mat);
@@ -228,6 +237,7 @@ typedef struct GPUMaterialTexture {
char sampler_name[32]; /* Name of sampler in GLSL. */
char tiled_mapping_name[32]; /* Name of tile mapping sampler in GLSL. */
int users;
+ int sampler_state; /* eGPUSamplerState */
} GPUMaterialTexture;
typedef struct GPUMaterialVolumeGrid {
diff --git a/source/blender/gpu/GPU_shader.h b/source/blender/gpu/GPU_shader.h
index 334e295c636..0ad472113c9 100644
--- a/source/blender/gpu/GPU_shader.h
+++ b/source/blender/gpu/GPU_shader.h
@@ -29,6 +29,7 @@ extern "C" {
#endif
typedef struct GPUShader GPUShader;
+struct GPUShaderInterface;
struct GPUTexture;
struct GPUUniformBuffer;
@@ -49,6 +50,11 @@ GPUShader *GPU_shader_create(const char *vertexcode,
const char *libcode,
const char *defines,
const char *shader_name);
+GPUShader *GPU_shader_create_from_python(const char *vertexcode,
+ const char *fragcode,
+ const char *geocode,
+ const char *libcode,
+ const char *defines);
GPUShader *GPU_shader_create_ex(const char *vertexcode,
const char *fragcode,
const char *geocode,
@@ -83,17 +89,21 @@ int GPU_shader_get_program(GPUShader *shader);
void *GPU_shader_get_interface(GPUShader *shader);
+void GPU_shader_set_srgb_uniform(const struct GPUShaderInterface *interface);
+
int GPU_shader_get_uniform(GPUShader *shader, const char *name);
-int GPU_shader_get_uniform_ensure(GPUShader *shader, const char *name);
int GPU_shader_get_builtin_uniform(GPUShader *shader, int builtin);
+int GPU_shader_get_builtin_block(GPUShader *shader, int builtin);
int GPU_shader_get_uniform_block(GPUShader *shader, const char *name);
+
+int GPU_shader_get_uniform_block_binding(GPUShader *shader, const char *name);
+int GPU_shader_get_texture_binding(GPUShader *shader, const char *name);
+
void GPU_shader_uniform_vector(
GPUShader *shader, int location, int length, int arraysize, const float *value);
void GPU_shader_uniform_vector_int(
GPUShader *shader, int location, int length, int arraysize, const int *value);
-void GPU_shader_uniform_buffer(GPUShader *shader, int location, struct GPUUniformBuffer *ubo);
-void GPU_shader_uniform_texture(GPUShader *shader, int location, struct GPUTexture *tex);
void GPU_shader_uniform_float(GPUShader *shader, int location, float value);
void GPU_shader_uniform_int(GPUShader *shader, int location, int value);
@@ -101,16 +111,14 @@ int GPU_shader_get_attribute(GPUShader *shader, const char *name);
char *GPU_shader_get_binary(GPUShader *shader, uint *r_binary_format, int *r_binary_len);
+void GPU_shader_set_framebuffer_srgb_target(int use_srgb_to_linear);
+
/* Builtin/Non-generated shaders */
typedef enum eGPUBuiltinShader {
/* specialized drawing */
GPU_SHADER_TEXT,
GPU_SHADER_KEYFRAME_DIAMOND,
GPU_SHADER_SIMPLE_LIGHTING,
- GPU_SHADER_SIMPLE_LIGHTING_FLAT_COLOR,
- GPU_SHADER_SIMPLE_LIGHTING_SMOOTH_COLOR,
- GPU_SHADER_SIMPLE_LIGHTING_SMOOTH_COLOR_ALPHA,
-
/* for simple 2D drawing */
/**
* Take a single color for all the vertices and a 2D position for each vertex.
@@ -133,7 +141,6 @@ typedef enum eGPUBuiltinShader {
* \param pos: in vec2
*/
GPU_SHADER_2D_SMOOTH_COLOR,
- GPU_SHADER_2D_SMOOTH_COLOR_DITHER,
GPU_SHADER_2D_IMAGE,
GPU_SHADER_2D_IMAGE_COLOR,
GPU_SHADER_2D_IMAGE_DESATURATE_COLOR,
@@ -141,14 +148,6 @@ typedef enum eGPUBuiltinShader {
GPU_SHADER_2D_IMAGE_ALPHA,
GPU_SHADER_2D_IMAGE_RECT_COLOR,
GPU_SHADER_2D_IMAGE_MULTI_RECT_COLOR,
- GPU_SHADER_2D_IMAGE_MULTISAMPLE_2,
- GPU_SHADER_2D_IMAGE_MULTISAMPLE_4,
- GPU_SHADER_2D_IMAGE_MULTISAMPLE_8,
- GPU_SHADER_2D_IMAGE_MULTISAMPLE_16,
- GPU_SHADER_2D_IMAGE_MULTISAMPLE_2_DEPTH_TEST,
- GPU_SHADER_2D_IMAGE_MULTISAMPLE_4_DEPTH_TEST,
- GPU_SHADER_2D_IMAGE_MULTISAMPLE_8_DEPTH_TEST,
- GPU_SHADER_2D_IMAGE_MULTISAMPLE_16_DEPTH_TEST,
GPU_SHADER_2D_CHECKER,
GPU_SHADER_2D_DIAG_STRIPES,
/* for simple 3D drawing */
@@ -159,8 +158,7 @@ typedef enum eGPUBuiltinShader {
* \param pos: in vec3
*/
GPU_SHADER_3D_UNIFORM_COLOR,
- /* Sets Z-depth to 1.0 (draw onto background). */
- GPU_SHADER_3D_UNIFORM_COLOR_BACKGROUND,
+ GPU_SHADER_3D_CLIPPED_UNIFORM_COLOR,
/**
* Take a 3D position and color for each vertex without color interpolation.
*
@@ -176,12 +174,37 @@ typedef enum eGPUBuiltinShader {
*/
GPU_SHADER_3D_SMOOTH_COLOR,
/**
+ * Take a single color for all the vertices and a 3D position for each vertex.
+ * Used for drawing wide lines.
+ *
+ * \param color: uniform vec4
+ * \param pos: in vec3
+ */
+ GPU_SHADER_3D_POLYLINE_UNIFORM_COLOR,
+ GPU_SHADER_3D_POLYLINE_CLIPPED_UNIFORM_COLOR,
+ /**
+ * Take a 3D position and color for each vertex without color interpolation.
+ * Used for drawing wide lines.
+ *
+ * \param color: in vec4
+ * \param pos: in vec3
+ */
+ GPU_SHADER_3D_POLYLINE_FLAT_COLOR,
+ /**
+ * Take a 3D position and color for each vertex with perspective correct interpolation.
+ * Used for drawing wide lines.
+ *
+ * \param color: in vec4
+ * \param pos: in vec3
+ */
+ GPU_SHADER_3D_POLYLINE_SMOOTH_COLOR,
+ /**
* Take a 3D position for each vertex and output only depth.
+ * Used for drawing wide lines.
*
* \param pos: in vec3
*/
GPU_SHADER_3D_DEPTH_ONLY,
- GPU_SHADER_3D_CLIPPED_UNIFORM_COLOR,
/* basic image drawing */
GPU_SHADER_2D_IMAGE_OVERLAYS_MERGE,
GPU_SHADER_2D_IMAGE_OVERLAYS_STEREO_MERGE,
@@ -196,18 +219,6 @@ typedef enum eGPUBuiltinShader {
* \param pos: in vec3
*/
GPU_SHADER_3D_IMAGE_MODULATE_ALPHA,
- /**
- * Draw linearized depth texture relate to near and far distances.
- * Take a 3D position and a 2D texture coordinate for each vertex.
- *
- * \param znear: uniform float
- * \param zfar: uniform float
- * \param image: uniform sampler2D
- * \param texCoord: in vec2
- * \param pos: in vec3
- */
- GPU_SHADER_3D_IMAGE_DEPTH,
- GPU_SHADER_3D_IMAGE_DEPTH_COPY,
/* points */
/**
* Draw round points with a hardcoded size.
diff --git a/source/blender/gpu/GPU_shader_interface.h b/source/blender/gpu/GPU_shader_interface.h
index 8b0d25e51a3..28ee162bdbd 100644
--- a/source/blender/gpu/GPU_shader_interface.h
+++ b/source/blender/gpu/GPU_shader_interface.h
@@ -33,9 +33,7 @@ extern "C" {
#endif
typedef enum {
- GPU_UNIFORM_NONE = 0, /* uninitialized/unknown */
-
- GPU_UNIFORM_MODEL, /* mat4 ModelMatrix */
+ GPU_UNIFORM_MODEL = 0, /* mat4 ModelMatrix */
GPU_UNIFORM_VIEW, /* mat4 ViewMatrix */
GPU_UNIFORM_MODELVIEW, /* mat4 ModelViewMatrix */
GPU_UNIFORM_PROJECTION, /* mat4 ProjectionMatrix */
@@ -56,48 +54,58 @@ typedef enum {
GPU_UNIFORM_BASE_INSTANCE, /* int baseInstance */
GPU_UNIFORM_RESOURCE_CHUNK, /* int resourceChunk */
GPU_UNIFORM_RESOURCE_ID, /* int resourceId */
-
- GPU_UNIFORM_CUSTOM, /* custom uniform, not one of the above built-ins */
+ GPU_UNIFORM_SRGB_TRANSFORM, /* bool srgbTarget */
GPU_NUM_UNIFORMS, /* Special value, denotes number of builtin uniforms. */
} GPUUniformBuiltin;
+typedef enum {
+ GPU_UNIFORM_BLOCK_VIEW = 0, /* viewBlock */
+ GPU_UNIFORM_BLOCK_MODEL, /* modelBlock */
+ GPU_UNIFORM_BLOCK_INFO, /* infoBlock */
+
+ GPU_NUM_UNIFORM_BLOCKS, /* Special value, denotes number of builtin uniforms block. */
+} GPUUniformBlockBuiltin;
+
typedef struct GPUShaderInput {
- struct GPUShaderInput *next;
uint32_t name_offset;
- uint name_hash;
- /** Only for uniform inputs. */
- GPUUniformBuiltin builtin_type;
- /** Only for attribute inputs. */
- uint32_t gl_type;
- /** Only for attribute inputs. */
- int32_t size;
+ uint32_t name_hash;
int32_t location;
+ /** Defined at interface creation or in shader. Only for Samplers, UBOs and Vertex Attribs. */
+ int32_t binding;
} GPUShaderInput;
-#define GPU_NUM_SHADERINTERFACE_BUCKETS 257
#define GPU_SHADERINTERFACE_REF_ALLOC_COUNT 16
typedef struct GPUShaderInterface {
- int32_t program;
- uint32_t name_buffer_offset;
- GPUShaderInput *attr_buckets[GPU_NUM_SHADERINTERFACE_BUCKETS];
- GPUShaderInput *uniform_buckets[GPU_NUM_SHADERINTERFACE_BUCKETS];
- GPUShaderInput *ubo_buckets[GPU_NUM_SHADERINTERFACE_BUCKETS];
- GPUShaderInput *builtin_uniforms[GPU_NUM_UNIFORMS];
+ /** Buffer containing all inputs names separated by '\0'. */
char *name_buffer;
- struct GPUBatch **batches; /* references to batches using this interface */
+ /** Reference to GPUBatches using this interface */
+ struct GPUBatch **batches;
uint batches_len;
+ /** Input counts. */
+ uint attribute_len;
+ uint ubo_len;
+ uint uniform_len;
+ /** Enabled bindpoints that needs to be fed with data. */
+ uint16_t enabled_attr_mask;
+ uint16_t enabled_ubo_mask;
+ uint64_t enabled_tex_mask;
+ /** Opengl Location of builtin uniforms. Fast access, no lookup needed. */
+ int32_t builtins[GPU_NUM_UNIFORMS];
+ int32_t builtin_blocks[GPU_NUM_UNIFORM_BLOCKS];
+ /** Flat array. In this order: Attributes, Ubos, Uniforms. */
+ GPUShaderInput inputs[0];
} GPUShaderInterface;
GPUShaderInterface *GPU_shaderinterface_create(int32_t program_id);
void GPU_shaderinterface_discard(GPUShaderInterface *);
const GPUShaderInput *GPU_shaderinterface_uniform(const GPUShaderInterface *, const char *name);
-const GPUShaderInput *GPU_shaderinterface_uniform_ensure(const GPUShaderInterface *,
- const char *name);
-const GPUShaderInput *GPU_shaderinterface_uniform_builtin(const GPUShaderInterface *,
- GPUUniformBuiltin);
+int32_t GPU_shaderinterface_uniform_builtin(const GPUShaderInterface *shaderface,
+ GPUUniformBuiltin builtin);
+int32_t GPU_shaderinterface_block_builtin(const GPUShaderInterface *shaderface,
+ GPUUniformBlockBuiltin builtin);
const GPUShaderInput *GPU_shaderinterface_ubo(const GPUShaderInterface *, const char *name);
const GPUShaderInput *GPU_shaderinterface_attr(const GPUShaderInterface *, const char *name);
diff --git a/source/blender/gpu/GPU_state.h b/source/blender/gpu/GPU_state.h
index 9ce91d31d69..4daf3f8dba5 100644
--- a/source/blender/gpu/GPU_state.h
+++ b/source/blender/gpu/GPU_state.h
@@ -40,6 +40,12 @@ typedef enum eGPUFilterFunction {
GPU_LINEAR,
} eGPUFilterFunction;
+/* Initialize
+ * - sets the default Blender opengl state, if in doubt, check
+ * the contents of this function
+ * - this is called when starting Blender, for opengl rendering. */
+void GPU_state_init(void);
+
void GPU_blend(bool enable);
void GPU_blend_set_func(eGPUBlendFunction sfactor, eGPUBlendFunction dfactor);
void GPU_blend_set_func_separate(eGPUBlendFunction src_rgb,
diff --git a/source/blender/gpu/GPU_texture.h b/source/blender/gpu/GPU_texture.h
index 892452a2738..a13f61177e6 100644
--- a/source/blender/gpu/GPU_texture.h
+++ b/source/blender/gpu/GPU_texture.h
@@ -41,6 +41,31 @@ struct PreviewImage;
struct GPUFrameBuffer;
typedef struct GPUTexture GPUTexture;
+/* GPU Samplers state
+ * - Specify the sampler state to bind a texture with.
+ * - Internally used by textures.
+ * - All states are created at startup to avoid runtime costs.
+ */
+
+typedef enum eGPUSamplerState {
+ GPU_SAMPLER_FILTER = (1 << 0),
+ GPU_SAMPLER_MIPMAP = (1 << 1),
+ GPU_SAMPLER_REPEAT_S = (1 << 2),
+ GPU_SAMPLER_REPEAT_T = (1 << 3),
+ GPU_SAMPLER_REPEAT_R = (1 << 4),
+ GPU_SAMPLER_CLAMP_BORDER = (1 << 5), /* Clamp to border color instead of border texel. */
+ GPU_SAMPLER_COMPARE = (1 << 6),
+ GPU_SAMPLER_ANISO = (1 << 7),
+ /* Don't use that. */
+ GPU_SAMPLER_MAX = (1 << 8),
+} eGPUSamplerState;
+
+#define GPU_SAMPLER_DEFAULT GPU_SAMPLER_FILTER
+#define GPU_SAMPLER_REPEAT (GPU_SAMPLER_REPEAT_S | GPU_SAMPLER_REPEAT_T | GPU_SAMPLER_REPEAT_R)
+
+void GPU_samplers_init(void);
+void GPU_samplers_free(void);
+
/* GPU Texture
* - always returns unsigned char RGBA textures
* - if texture with non square dimensions is created, depending on the
@@ -236,14 +261,17 @@ void GPU_texture_free(GPUTexture *tex);
void GPU_texture_ref(GPUTexture *tex);
void GPU_texture_bind(GPUTexture *tex, int number);
+void GPU_texture_bind_ex(GPUTexture *tex, eGPUSamplerState state, int unit, const bool set_number);
void GPU_texture_unbind(GPUTexture *tex);
-int GPU_texture_bound_number(GPUTexture *tex);
+void GPU_texture_unbind_all(void);
+
+void GPU_texture_copy(GPUTexture *dst, GPUTexture *src);
void GPU_texture_generate_mipmap(GPUTexture *tex);
void GPU_texture_compare_mode(GPUTexture *tex, bool use_compare);
void GPU_texture_filter_mode(GPUTexture *tex, bool use_filter);
void GPU_texture_mipmap_mode(GPUTexture *tex, bool use_mipmap, bool use_filter);
-void GPU_texture_wrap_mode(GPUTexture *tex, bool use_repeat);
+void GPU_texture_wrap_mode(GPUTexture *tex, bool use_repeat, bool use_clamp);
void GPU_texture_filters(GPUTexture *tex,
eGPUFilterFunction min_filter,
eGPUFilterFunction mag_filter);
diff --git a/source/blender/gpu/GPU_vertex_format.h b/source/blender/gpu/GPU_vertex_format.h
index 7e384d0a692..61b14a4c5c0 100644
--- a/source/blender/gpu/GPU_vertex_format.h
+++ b/source/blender/gpu/GPU_vertex_format.h
@@ -39,7 +39,7 @@ extern "C" {
#define GPU_VERT_ATTR_NAMES_BUF_LEN 256
#define GPU_VERT_FORMAT_MAX_NAMES 63 /* More than enough, actual max is ~30. */
/* Computed as GPU_VERT_ATTR_NAMES_BUF_LEN / 30 (actual max format name). */
-#define GPU_MAX_SAFE_ATTRIB_NAME 12
+#define GPU_MAX_SAFE_ATTR_NAME 12
typedef enum {
GPU_COMP_I8,
@@ -94,19 +94,18 @@ typedef struct GPUVertFormat {
uint packed : 1;
/** Current offset in names[]. */
uint name_offset : 8;
- /** Store each attrib in one contiguous buffer region. */
+ /** Store each attribute in one contiguous buffer region. */
uint deinterleaved : 1;
GPUVertAttr attrs[GPU_VERT_ATTR_MAX_LEN];
char names[GPU_VERT_ATTR_NAMES_BUF_LEN];
} GPUVertFormat;
-struct GPUShaderInterface;
+struct GPUShader;
void GPU_vertformat_clear(GPUVertFormat *);
void GPU_vertformat_copy(GPUVertFormat *dest, const GPUVertFormat *src);
-void GPU_vertformat_from_interface(GPUVertFormat *format,
- const struct GPUShaderInterface *shaderface);
+void GPU_vertformat_from_shader(GPUVertFormat *format, const struct GPUShader *shader);
uint GPU_vertformat_attr_add(
GPUVertFormat *, const char *name, GPUVertCompType, uint comp_len, GPUVertFetchMode);
@@ -125,7 +124,7 @@ BLI_INLINE const char *GPU_vertformat_attr_name_get(const GPUVertFormat *format,
return format->names + attr->names[n_idx];
}
-void GPU_vertformat_safe_attrib_name(const char *attrib_name, char *r_safe_name, uint max_len);
+void GPU_vertformat_safe_attr_name(const char *attr_name, char *r_safe_name, uint max_len);
/* format conversion */
diff --git a/source/blender/gpu/intern/gpu_batch.c b/source/blender/gpu/intern/gpu_batch.c
index 6bc3cd27130..5f77f13c135 100644
--- a/source/blender/gpu/intern/gpu_batch.c
+++ b/source/blender/gpu/intern/gpu_batch.c
@@ -42,6 +42,8 @@
#include <stdlib.h>
#include <string.h>
+static GLuint g_default_attr_vbo = 0;
+
static void batch_update_program_bindings(GPUBatch *batch, uint i_first);
void GPU_batch_vao_cache_clear(GPUBatch *batch)
@@ -373,7 +375,7 @@ void GPU_batch_program_set_no_use(GPUBatch *batch,
const GPUShaderInterface *shaderface)
{
#if TRUST_NO_ONE
- assert(glIsProgram(shaderface->program));
+ assert(glIsProgram(program));
assert(batch->program_in_use == 0);
#endif
batch->interface = shaderface;
@@ -414,6 +416,7 @@ void gpu_batch_remove_interface_ref(GPUBatch *batch, const GPUShaderInterface *i
static void create_bindings(GPUVertBuf *verts,
const GPUShaderInterface *interface,
+ uint16_t *attr_mask,
uint v_first,
const bool use_instancing)
{
@@ -446,6 +449,8 @@ static void create_bindings(GPUVertBuf *verts,
continue;
}
+ *attr_mask &= ~(1 << input->location);
+
if (a->comp_len == 16 || a->comp_len == 12 || a->comp_len == 8) {
#if TRUST_NO_ONE
assert(a->fetch_mode == GPU_FETCH_FLOAT);
@@ -487,17 +492,35 @@ static void create_bindings(GPUVertBuf *verts,
static void batch_update_program_bindings(GPUBatch *batch, uint i_first)
{
- /* Reverse order so first vbos have more prevalence (in term of attrib override). */
+ uint16_t attr_mask = batch->interface->enabled_attr_mask;
+
+ /* Reverse order so first VBO'S have more prevalence (in term of attribute override). */
for (int v = GPU_BATCH_VBO_MAX_LEN - 1; v > -1; v--) {
if (batch->verts[v] != NULL) {
- create_bindings(batch->verts[v], batch->interface, 0, false);
+ create_bindings(batch->verts[v], batch->interface, &attr_mask, 0, false);
}
}
+
for (int v = GPU_BATCH_INST_VBO_MAX_LEN - 1; v > -1; v--) {
if (batch->inst[v]) {
- create_bindings(batch->inst[v], batch->interface, i_first, true);
+ create_bindings(batch->inst[v], batch->interface, &attr_mask, i_first, true);
+ }
+ }
+
+ if (attr_mask != 0 && GLEW_ARB_vertex_attrib_binding) {
+ for (uint16_t mask = 1, a = 0; a < 16; a++, mask <<= 1) {
+ if (attr_mask & mask) {
+ /* This replaces glVertexAttrib4f(a, 0.0f, 0.0f, 0.0f, 1.0f); with a more modern style.
+ * Fix issues for some drivers (see T75069). */
+ glBindVertexBuffer(a, g_default_attr_vbo, (intptr_t)0, (intptr_t)0);
+
+ glEnableVertexAttribArray(a);
+ glVertexAttribFormat(a, 4, GL_FLOAT, GL_FALSE, 0);
+ glVertexAttribBinding(a, a);
+ }
}
}
+
if (batch->elem) {
GPU_indexbuf_use(batch->elem);
}
@@ -528,11 +551,11 @@ void GPU_batch_program_use_end(GPUBatch *batch)
#if TRUST_NO_ONE
# define GET_UNIFORM \
- const GPUShaderInput *uniform = GPU_shaderinterface_uniform_ensure(batch->interface, name); \
+ const GPUShaderInput *uniform = GPU_shaderinterface_uniform(batch->interface, name); \
assert(uniform);
#else
# define GET_UNIFORM \
- const GPUShaderInput *uniform = GPU_shaderinterface_uniform_ensure(batch->interface, name);
+ const GPUShaderInput *uniform = GPU_shaderinterface_uniform(batch->interface, name);
#endif
void GPU_batch_uniform_1ui(GPUBatch *batch, const char *name, uint value)
@@ -652,6 +675,7 @@ void GPU_batch_draw(GPUBatch *batch)
#endif
GPU_batch_program_use_begin(batch);
GPU_matrix_bind(batch->interface); // external call.
+ GPU_shader_set_srgb_uniform(batch->interface);
GPU_batch_bind(batch);
GPU_batch_draw_advanced(batch, 0, 0, 0, 0);
@@ -689,8 +713,8 @@ void GPU_batch_draw_advanced(GPUBatch *batch, int v_first, int v_count, int i_fi
}
/* Verify there is enough data do draw. */
- /* TODO(fclem) Nice to have but this is invalid when using procedural drawcalls.
- * The right assert would be to check if there is an enabled attrib from each VBO
+ /* TODO(fclem) Nice to have but this is invalid when using procedural draw-calls.
+ * The right assert would be to check if there is an enabled attribute from each VBO
* and check their length. */
// BLI_assert(i_first + i_count <= (batch->inst ? batch->inst->vertex_len : INT_MAX));
// BLI_assert(v_first + v_count <=
@@ -1002,11 +1026,23 @@ void GPU_batch_program_set_imm_shader(GPUBatch *batch)
void gpu_batch_init(void)
{
+ if (g_default_attr_vbo == 0) {
+ g_default_attr_vbo = GPU_buf_alloc();
+
+ float default_attrib_data[4] = {0.0f, 0.0f, 0.0f, 1.0f};
+ glBindBuffer(GL_ARRAY_BUFFER, g_default_attr_vbo);
+ glBufferData(GL_ARRAY_BUFFER, sizeof(float) * 4, default_attrib_data, GL_STATIC_DRAW);
+ glBindBuffer(GL_ARRAY_BUFFER, 0);
+ }
+
gpu_batch_presets_init();
}
void gpu_batch_exit(void)
{
+ GPU_buf_free(g_default_attr_vbo);
+ g_default_attr_vbo = 0;
+
gpu_batch_presets_exit();
}
diff --git a/source/blender/gpu/intern/gpu_batch_presets.c b/source/blender/gpu/intern/gpu_batch_presets.c
index e00b6f78c2e..d16edab5ac9 100644
--- a/source/blender/gpu/intern/gpu_batch_presets.c
+++ b/source/blender/gpu/intern/gpu_batch_presets.c
@@ -27,13 +27,20 @@
#include "BLI_utildefines.h"
#include "MEM_guardedalloc.h"
+#include "DNA_userdef_types.h"
+
#include "UI_interface.h"
+#include "UI_resources.h"
#include "GPU_batch.h"
#include "GPU_batch_presets.h" /* own include */
#include "GPU_batch_utils.h"
#include "gpu_shader_private.h"
+/* -------------------------------------------------------------------- */
+/** \name Local Structures
+ * \{ */
+
/* Struct to store 3D Batches and their format */
static struct {
struct {
@@ -53,8 +60,27 @@ static struct {
ThreadMutex mutex;
} g_presets_3d = {{0}};
+static struct {
+ struct {
+ GPUBatch *panel_drag_widget;
+ } batch;
+
+ float panel_drag_widget_pixelsize;
+ float panel_drag_widget_width;
+ float panel_drag_widget_col_high[4];
+ float panel_drag_widget_col_dark[4];
+
+ GPUVertFormat format;
+
+ struct {
+ uint pos, col;
+ } attr_id;
+} g_presets_2d = {{0}};
+
static ListBase presets_list = {NULL, NULL};
+/** \} */
+
/* -------------------------------------------------------------------- */
/** \name 3D Primitives
* \{ */
@@ -71,6 +97,18 @@ static GPUVertFormat *preset_3d_format(void)
return &g_presets_3d.format;
}
+static GPUVertFormat *preset_2d_format(void)
+{
+ if (g_presets_2d.format.attr_len == 0) {
+ GPUVertFormat *format = &g_presets_2d.format;
+ g_presets_2d.attr_id.pos = GPU_vertformat_attr_add(
+ format, "pos", GPU_COMP_F32, 2, GPU_FETCH_FLOAT);
+ g_presets_2d.attr_id.col = GPU_vertformat_attr_add(
+ format, "color", GPU_COMP_F32, 4, GPU_FETCH_FLOAT);
+ }
+ return &g_presets_2d.format;
+}
+
static void batch_sphere_lat_lon_vert(GPUVertBufRaw *pos_step,
GPUVertBufRaw *nor_step,
float lat,
@@ -193,6 +231,114 @@ static GPUBatch *batch_sphere_wire(int lat_res, int lon_res)
/** \} */
+/* -------------------------------------------------------------------- */
+/** \name Panel Drag Widget
+ * \{ */
+
+static void gpu_batch_preset_rectf_tris_color_ex(GPUVertBufRaw *pos_step,
+ float x1,
+ float y1,
+ float x2,
+ float y2,
+ GPUVertBufRaw *col_step,
+ const float color[4])
+{
+ copy_v2_v2(GPU_vertbuf_raw_step(pos_step), (const float[2]){x1, y1});
+ copy_v4_v4(GPU_vertbuf_raw_step(col_step), color);
+
+ copy_v2_v2(GPU_vertbuf_raw_step(pos_step), (const float[2]){x2, y1});
+ copy_v4_v4(GPU_vertbuf_raw_step(col_step), color);
+
+ copy_v2_v2(GPU_vertbuf_raw_step(pos_step), (const float[2]){x2, y2});
+ copy_v4_v4(GPU_vertbuf_raw_step(col_step), color);
+
+ copy_v2_v2(GPU_vertbuf_raw_step(pos_step), (const float[2]){x1, y1});
+ copy_v4_v4(GPU_vertbuf_raw_step(col_step), color);
+
+ copy_v2_v2(GPU_vertbuf_raw_step(pos_step), (const float[2]){x2, y2});
+ copy_v4_v4(GPU_vertbuf_raw_step(col_step), color);
+
+ copy_v2_v2(GPU_vertbuf_raw_step(pos_step), (const float[2]){x1, y2});
+ copy_v4_v4(GPU_vertbuf_raw_step(col_step), color);
+}
+
+static GPUBatch *gpu_batch_preset_panel_drag_widget(float pixelsize,
+ const float col_high[4],
+ const float col_dark[4],
+ const float width)
+{
+ GPUVertBuf *vbo = GPU_vertbuf_create_with_format(preset_2d_format());
+ const uint vbo_len = 4 * 2 * (6 * 2);
+ GPU_vertbuf_data_alloc(vbo, vbo_len);
+
+ GPUVertBufRaw pos_step, col_step;
+ GPU_vertbuf_attr_get_raw_data(vbo, g_presets_2d.attr_id.pos, &pos_step);
+ GPU_vertbuf_attr_get_raw_data(vbo, g_presets_2d.attr_id.col, &col_step);
+
+ const int px = (int)pixelsize;
+ const int px_zoom = max_ii(round_fl_to_int(width / 22.0f), 1);
+
+ const int box_margin = max_ii(round_fl_to_int((float)(px_zoom * 2.0f)), px);
+ const int box_size = max_ii(round_fl_to_int((width / 8.0f) - px), px);
+
+ const int y_ofs = max_ii(round_fl_to_int(width / 2.5f), px);
+ const int x_ofs = y_ofs;
+ int i_x, i_y;
+
+ for (i_x = 0; i_x < 4; i_x++) {
+ for (i_y = 0; i_y < 2; i_y++) {
+ const int x_co = (x_ofs) + (i_x * (box_size + box_margin));
+ const int y_co = (y_ofs) + (i_y * (box_size + box_margin));
+
+ gpu_batch_preset_rectf_tris_color_ex(&pos_step,
+ x_co - box_size,
+ y_co - px_zoom,
+ x_co,
+ (y_co + box_size) - px_zoom,
+ &col_step,
+ col_dark);
+ gpu_batch_preset_rectf_tris_color_ex(
+ &pos_step, x_co - box_size, y_co, x_co, y_co + box_size, &col_step, col_high);
+ }
+ }
+ return GPU_batch_create_ex(GPU_PRIM_TRIS, vbo, NULL, GPU_BATCH_OWNS_VBO);
+}
+
+GPUBatch *GPU_batch_preset_panel_drag_widget(const float pixelsize,
+ const float col_high[4],
+ const float col_dark[4],
+ const float width)
+{
+ const bool parameters_changed = (g_presets_2d.panel_drag_widget_pixelsize != pixelsize) ||
+ (g_presets_2d.panel_drag_widget_width != width) ||
+ !equals_v4v4(g_presets_2d.panel_drag_widget_col_high,
+ col_high) ||
+ !equals_v4v4(g_presets_2d.panel_drag_widget_col_dark, col_dark);
+
+ if (g_presets_2d.batch.panel_drag_widget && parameters_changed) {
+ gpu_batch_presets_unregister(g_presets_2d.batch.panel_drag_widget);
+ GPU_batch_discard(g_presets_2d.batch.panel_drag_widget);
+ g_presets_2d.batch.panel_drag_widget = NULL;
+ }
+
+ if (!g_presets_2d.batch.panel_drag_widget) {
+ g_presets_2d.batch.panel_drag_widget = gpu_batch_preset_panel_drag_widget(
+ pixelsize, col_high, col_dark, width);
+ gpu_batch_presets_register(g_presets_2d.batch.panel_drag_widget);
+ g_presets_2d.panel_drag_widget_pixelsize = pixelsize;
+ g_presets_2d.panel_drag_widget_width = width;
+ copy_v4_v4(g_presets_2d.panel_drag_widget_col_high, col_high);
+ copy_v4_v4(g_presets_2d.panel_drag_widget_col_dark, col_dark);
+ }
+ return g_presets_2d.batch.panel_drag_widget;
+}
+
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Preset Registration Management
+ * \{ */
+
void gpu_batch_presets_init(void)
{
BLI_mutex_init(&g_presets_3d.mutex);
@@ -241,7 +387,7 @@ void gpu_batch_presets_reset(void)
BLI_mutex_lock(&g_presets_3d.mutex);
/* Reset vao caches for these every time we switch opengl context.
* This way they will draw correctly for each window. */
- for (LinkData *link = presets_list.first; link; link = link->next) {
+ LISTBASE_FOREACH (LinkData *, link, &presets_list) {
GPUBatch *preset = link->data;
GPU_batch_vao_cache_clear(preset);
}
@@ -259,3 +405,5 @@ void gpu_batch_presets_exit(void)
BLI_mutex_end(&g_presets_3d.mutex);
}
+
+/** \} */
diff --git a/source/blender/gpu/intern/gpu_batch_private.h b/source/blender/gpu/intern/gpu_batch_private.h
index 42cfc1e2a5c..58d1810ac7a 100644
--- a/source/blender/gpu/intern/gpu_batch_private.h
+++ b/source/blender/gpu/intern/gpu_batch_private.h
@@ -27,14 +27,14 @@
#ifndef __GPU_BATCH_PRIVATE_H__
#define __GPU_BATCH_PRIVATE_H__
-#ifdef __cplusplus
-extern "C" {
-#endif
-
#include "GPU_batch.h"
#include "GPU_context.h"
#include "GPU_shader_interface.h"
+#ifdef __cplusplus
+extern "C" {
+#endif
+
void gpu_batch_remove_interface_ref(GPUBatch *batch, const GPUShaderInterface *interface);
#ifdef __cplusplus
diff --git a/source/blender/gpu/intern/gpu_buffers.c b/source/blender/gpu/intern/gpu_buffers.c
index 168a3c83a91..cef90d57ef5 100644
--- a/source/blender/gpu/intern/gpu_buffers.c
+++ b/source/blender/gpu/intern/gpu_buffers.c
@@ -43,6 +43,7 @@
#include "BKE_mesh.h"
#include "BKE_paint.h"
#include "BKE_pbvh.h"
+#include "BKE_subdiv_ccg.h"
#include "GPU_batch.h"
#include "GPU_buffers.h"
@@ -150,7 +151,10 @@ static bool gpu_pbvh_vert_buf_data_set(GPU_PBVH_Buffers *buffers, uint vert_len)
/* Initialize vertex buffer (match 'VertexBufferFormat'). */
buffers->vert_buf = GPU_vertbuf_create_with_format_ex(&g_vbo_id.format, GPU_USAGE_STATIC);
}
- GPU_vertbuf_data_alloc(buffers->vert_buf, vert_len);
+ if (buffers->vert_buf->data == NULL || buffers->vert_buf->vertex_len != vert_len) {
+ /* Allocate buffer if not allocated yet or size changed. */
+ GPU_vertbuf_data_alloc(buffers->vert_buf, vert_len);
+ }
#endif
return buffers->vert_buf->data != NULL;
@@ -218,14 +222,11 @@ static bool gpu_pbvh_is_looptri_visible(const MLoopTri *lt,
/* Threaded - do not call any functions that use OpenGL calls! */
void GPU_pbvh_mesh_buffers_update(GPU_PBVH_Buffers *buffers,
const MVert *mvert,
- const int *vert_indices,
- int totvert,
const float *vmask,
const MLoopCol *vcol,
const int *sculpt_face_sets,
const int face_sets_color_seed,
const int face_sets_color_default,
- const int (*face_vert_indices)[3],
const int update_flags)
{
const bool show_mask = vmask && (update_flags & GPU_PBVH_BUFFERS_SHOW_MASK) != 0;
@@ -236,7 +237,7 @@ void GPU_pbvh_mesh_buffers_update(GPU_PBVH_Buffers *buffers,
bool default_face_set = true;
{
- int totelem = (buffers->smooth ? totvert : (buffers->tot_tri * 3));
+ const int totelem = buffers->tot_tri * 3;
/* Build VBO */
if (gpu_pbvh_vert_buf_data_set(buffers, totelem)) {
@@ -254,127 +255,77 @@ void GPU_pbvh_mesh_buffers_update(GPU_PBVH_Buffers *buffers,
GPU_vertbuf_attr_get_raw_data(buffers->vert_buf, g_vbo_id.col, &col_step);
}
- /* Vertex data is shared if smooth-shaded, but separate
- * copies are made for flat shading because normals
- * shouldn't be shared. */
- if (buffers->smooth) {
- for (uint i = 0; i < totvert; i++) {
- const int vidx = vert_indices[i];
- const MVert *v = &mvert[vidx];
- copy_v3_v3(GPU_vertbuf_raw_step(&pos_step), v->co);
- copy_v3_v3_short(GPU_vertbuf_raw_step(&nor_step), v->no);
+ /* calculate normal for each polygon only once */
+ uint mpoly_prev = UINT_MAX;
+ short no[3] = {0, 0, 0};
- uchar mask;
- if (show_mask) {
- mask = (uchar)(vmask[vidx] * 255);
- }
- else {
- mask = 0.0f;
- }
- *(uchar *)GPU_vertbuf_raw_step(&msk_step) = mask;
- empty_mask = empty_mask && (mask == 0);
+ for (uint i = 0; i < buffers->face_indices_len; i++) {
+ const MLoopTri *lt = &buffers->looptri[buffers->face_indices[i]];
+ const uint vtri[3] = {
+ buffers->mloop[lt->tri[0]].v,
+ buffers->mloop[lt->tri[1]].v,
+ buffers->mloop[lt->tri[2]].v,
+ };
+
+ if (!gpu_pbvh_is_looptri_visible(lt, mvert, buffers->mloop, sculpt_face_sets)) {
+ continue;
}
- /* Face Sets. */
- for (uint i = 0; i < buffers->face_indices_len; i++) {
- uchar face_set_color[4] = {UCHAR_MAX, UCHAR_MAX, UCHAR_MAX, UCHAR_MAX};
- if (show_face_sets) {
- const MLoopTri *lt = &buffers->looptri[buffers->face_indices[i]];
- const int fset = abs(sculpt_face_sets[lt->poly]);
-
- /* Skip for the default color Face Set to render it white. */
- if (fset != face_sets_color_default) {
- face_set_overlay_color_get(fset, face_sets_color_seed, face_set_color);
- default_face_set = false;
- }
- }
- for (int j = 0; j < 3; j++) {
- const int vidx = face_vert_indices[i][j];
- GPU_vertbuf_attr_set(buffers->vert_buf, g_vbo_id.fset, vidx, &face_set_color);
- }
+ /* Face normal and mask */
+ if (lt->poly != mpoly_prev && !buffers->smooth) {
+ const MPoly *mp = &buffers->mpoly[lt->poly];
+ float fno[3];
+ BKE_mesh_calc_poly_normal(mp, &buffers->mloop[mp->loopstart], mvert, fno);
+ normal_float_to_short_v3(no, fno);
+ mpoly_prev = lt->poly;
}
- if (show_vcol) {
- for (uint i = 0; i < buffers->face_indices_len; i++) {
- const MLoopTri *lt = &buffers->looptri[buffers->face_indices[i]];
- for (int j = 0; j < 3; j++) {
- const int loop_index = lt->tri[j];
- const int vidx = face_vert_indices[i][j];
- const MLoopCol *mcol = &vcol[loop_index];
- ushort scol[4];
- scol[0] = unit_float_to_ushort_clamp(BLI_color_from_srgb_table[mcol->r]);
- scol[1] = unit_float_to_ushort_clamp(BLI_color_from_srgb_table[mcol->g]);
- scol[2] = unit_float_to_ushort_clamp(BLI_color_from_srgb_table[mcol->b]);
- scol[3] = unit_float_to_ushort_clamp(mcol->a * (1.0f / 255.0f));
- GPU_vertbuf_attr_set(buffers->vert_buf, g_vbo_id.col, vidx, scol);
- }
+ uchar face_set_color[4] = {UCHAR_MAX, UCHAR_MAX, UCHAR_MAX, UCHAR_MAX};
+ if (show_face_sets) {
+ const int fset = abs(sculpt_face_sets[lt->poly]);
+ /* Skip for the default color Face Set to render it white. */
+ if (fset != face_sets_color_default) {
+ face_set_overlay_color_get(fset, face_sets_color_seed, face_set_color);
+ default_face_set = false;
}
}
- }
- else {
- /* calculate normal for each polygon only once */
- uint mpoly_prev = UINT_MAX;
- short no[3] = {0, 0, 0};
-
- for (uint i = 0; i < buffers->face_indices_len; i++) {
- const MLoopTri *lt = &buffers->looptri[buffers->face_indices[i]];
- const uint vtri[3] = {
- buffers->mloop[lt->tri[0]].v,
- buffers->mloop[lt->tri[1]].v,
- buffers->mloop[lt->tri[2]].v,
- };
-
- if (!gpu_pbvh_is_looptri_visible(lt, mvert, buffers->mloop, sculpt_face_sets)) {
- continue;
- }
- /* Face normal and mask */
- if (lt->poly != mpoly_prev) {
- const MPoly *mp = &buffers->mpoly[lt->poly];
- float fno[3];
- BKE_mesh_calc_poly_normal(mp, &buffers->mloop[mp->loopstart], mvert, fno);
- normal_float_to_short_v3(no, fno);
- mpoly_prev = lt->poly;
- }
+ float fmask = 0.0f;
+ uchar cmask = 0;
+ if (show_mask && !buffers->smooth) {
+ fmask = (vmask[vtri[0]] + vmask[vtri[1]] + vmask[vtri[2]]) / 3.0f;
+ cmask = (uchar)(fmask * 255);
+ }
- uchar face_set_color[4] = {UCHAR_MAX, UCHAR_MAX, UCHAR_MAX, UCHAR_MAX};
- if (show_face_sets) {
- const int fset = abs(sculpt_face_sets[lt->poly]);
- /* Skip for the default color Face Set to render it white. */
- if (fset != face_sets_color_default) {
- face_set_overlay_color_get(fset, face_sets_color_seed, face_set_color);
- default_face_set = false;
- }
- }
+ for (uint j = 0; j < 3; j++) {
+ const MVert *v = &mvert[vtri[j]];
+ copy_v3_v3(GPU_vertbuf_raw_step(&pos_step), v->co);
- float fmask = 0.0f;
- uchar cmask = 0;
- if (show_mask) {
- fmask = (vmask[vtri[0]] + vmask[vtri[1]] + vmask[vtri[2]]) / 3.0f;
- cmask = (uchar)(fmask * 255);
+ if (buffers->smooth) {
+ copy_v3_v3_short(no, v->no);
}
+ copy_v3_v3_short(GPU_vertbuf_raw_step(&nor_step), no);
- for (uint j = 0; j < 3; j++) {
- const MVert *v = &mvert[vtri[j]];
-
- copy_v3_v3(GPU_vertbuf_raw_step(&pos_step), v->co);
- copy_v3_v3_short(GPU_vertbuf_raw_step(&nor_step), no);
- *(uchar *)GPU_vertbuf_raw_step(&msk_step) = cmask;
- empty_mask = empty_mask && (cmask == 0);
- /* Face Sets. */
- memcpy(GPU_vertbuf_raw_step(&fset_step), face_set_color, sizeof(uchar) * 3);
+ if (show_mask && buffers->smooth) {
+ cmask = (uchar)(vmask[vtri[j]] * 255);
+ }
- if (show_vcol) {
- const uint loop_index = lt->tri[j];
- const MLoopCol *mcol = &vcol[loop_index];
- ushort scol[4];
- scol[0] = unit_float_to_ushort_clamp(BLI_color_from_srgb_table[mcol->r]);
- scol[1] = unit_float_to_ushort_clamp(BLI_color_from_srgb_table[mcol->g]);
- scol[2] = unit_float_to_ushort_clamp(BLI_color_from_srgb_table[mcol->b]);
- scol[3] = unit_float_to_ushort_clamp(mcol->a * (1.0f / 255.0f));
- memcpy(GPU_vertbuf_raw_step(&col_step), scol, sizeof(scol));
- }
+ *(uchar *)GPU_vertbuf_raw_step(&msk_step) = cmask;
+ empty_mask = empty_mask && (cmask == 0);
+
+ if (show_vcol) {
+ const uint loop_index = lt->tri[j];
+ const MLoopCol *mcol = &vcol[loop_index];
+ ushort scol[4];
+ scol[0] = unit_float_to_ushort_clamp(BLI_color_from_srgb_table[mcol->r]);
+ scol[1] = unit_float_to_ushort_clamp(BLI_color_from_srgb_table[mcol->g]);
+ scol[2] = unit_float_to_ushort_clamp(BLI_color_from_srgb_table[mcol->b]);
+ scol[3] = unit_float_to_ushort_clamp(mcol->a * (1.0f / 255.0f));
+ memcpy(GPU_vertbuf_raw_step(&col_step), scol, sizeof(scol));
}
+
+ /* Face Sets. */
+ memcpy(GPU_vertbuf_raw_step(&fset_step), face_set_color, sizeof(uchar) * 3);
}
}
@@ -392,8 +343,7 @@ void GPU_pbvh_mesh_buffers_update(GPU_PBVH_Buffers *buffers,
}
/* Threaded - do not call any functions that use OpenGL calls! */
-GPU_PBVH_Buffers *GPU_pbvh_mesh_buffers_build(const int (*face_vert_indices)[3],
- const MPoly *mpoly,
+GPU_PBVH_Buffers *GPU_pbvh_mesh_buffers_build(const MPoly *mpoly,
const MLoop *mloop,
const MLoopTri *looptri,
const MVert *mvert,
@@ -440,70 +390,34 @@ GPU_PBVH_Buffers *GPU_pbvh_mesh_buffers_build(const int (*face_vert_indices)[3],
return buffers;
}
- /* An element index buffer is used for smooth shading, but flat
- * shading requires separate vertex normals so an index buffer
- * can't be used there. */
- if (buffers->smooth) {
- /* Fill the triangle and line buffers. */
- GPUIndexBufBuilder elb, elb_lines;
- GPU_indexbuf_init(&elb, GPU_PRIM_TRIS, tottri, INT_MAX);
- GPU_indexbuf_init(&elb_lines, GPU_PRIM_LINES, tot_real_edges, INT_MAX);
-
- for (i = 0; i < face_indices_len; i++) {
- const MLoopTri *lt = &looptri[face_indices[i]];
-
- /* Skip hidden faces */
- if (!gpu_pbvh_is_looptri_visible(lt, mvert, mloop, sculpt_face_sets)) {
- continue;
- }
+ /* Fill the only the line buffer. */
+ GPUIndexBufBuilder elb_lines;
+ GPU_indexbuf_init(&elb_lines, GPU_PRIM_LINES, tot_real_edges, INT_MAX);
+ int vert_idx = 0;
- GPU_indexbuf_add_tri_verts(&elb, UNPACK3(face_vert_indices[i]));
- int r_edges[3];
- BKE_mesh_looptri_get_real_edges(mesh, lt, r_edges);
+ for (i = 0; i < face_indices_len; i++) {
+ const MLoopTri *lt = &looptri[face_indices[i]];
- if (r_edges[0] != -1) {
- GPU_indexbuf_add_line_verts(&elb_lines, face_vert_indices[i][0], face_vert_indices[i][1]);
- }
- if (r_edges[1] != -1) {
- GPU_indexbuf_add_line_verts(&elb_lines, face_vert_indices[i][1], face_vert_indices[i][2]);
- }
- if (r_edges[2] != -1) {
- GPU_indexbuf_add_line_verts(&elb_lines, face_vert_indices[i][2], face_vert_indices[i][0]);
- }
+ /* Skip hidden faces */
+ if (!gpu_pbvh_is_looptri_visible(lt, mvert, mloop, sculpt_face_sets)) {
+ continue;
}
- buffers->index_buf = GPU_indexbuf_build(&elb);
- buffers->index_lines_buf = GPU_indexbuf_build(&elb_lines);
- }
- else {
- /* Fill the only the line buffer. */
- GPUIndexBufBuilder elb_lines;
- GPU_indexbuf_init(&elb_lines, GPU_PRIM_LINES, tot_real_edges, INT_MAX);
- int vert_idx = 0;
- for (i = 0; i < face_indices_len; i++) {
- const MLoopTri *lt = &looptri[face_indices[i]];
-
- /* Skip hidden faces */
- if (!gpu_pbvh_is_looptri_visible(lt, mvert, mloop, sculpt_face_sets)) {
- continue;
- }
-
- int r_edges[3];
- BKE_mesh_looptri_get_real_edges(mesh, lt, r_edges);
- if (r_edges[0] != -1) {
- GPU_indexbuf_add_line_verts(&elb_lines, vert_idx * 3 + 0, vert_idx * 3 + 1);
- }
- if (r_edges[1] != -1) {
- GPU_indexbuf_add_line_verts(&elb_lines, vert_idx * 3 + 1, vert_idx * 3 + 2);
- }
- if (r_edges[2] != -1) {
- GPU_indexbuf_add_line_verts(&elb_lines, vert_idx * 3 + 2, vert_idx * 3 + 0);
- }
-
- vert_idx++;
+ int r_edges[3];
+ BKE_mesh_looptri_get_real_edges(mesh, lt, r_edges);
+ if (r_edges[0] != -1) {
+ GPU_indexbuf_add_line_verts(&elb_lines, vert_idx * 3 + 0, vert_idx * 3 + 1);
}
- buffers->index_lines_buf = GPU_indexbuf_build(&elb_lines);
+ if (r_edges[1] != -1) {
+ GPU_indexbuf_add_line_verts(&elb_lines, vert_idx * 3 + 1, vert_idx * 3 + 2);
+ }
+ if (r_edges[2] != -1) {
+ GPU_indexbuf_add_line_verts(&elb_lines, vert_idx * 3 + 2, vert_idx * 3 + 0);
+ }
+
+ vert_idx++;
}
+ buffers->index_lines_buf = GPU_indexbuf_build(&elb_lines);
buffers->tot_tri = tottri;
@@ -523,8 +437,13 @@ GPU_PBVH_Buffers *GPU_pbvh_mesh_buffers_build(const int (*face_vert_indices)[3],
/** \name Grid PBVH
* \{ */
-static void gpu_pbvh_grid_fill_index_buffers(
- GPU_PBVH_Buffers *buffers, int *grid_indices, uint visible_quad_len, int totgrid, int gridsize)
+static void gpu_pbvh_grid_fill_index_buffers(GPU_PBVH_Buffers *buffers,
+ SubdivCCG *UNUSED(subdiv_ccg),
+ const int *UNUSED(face_sets),
+ int *grid_indices,
+ uint visible_quad_len,
+ int totgrid,
+ int gridsize)
{
GPUIndexBufBuilder elb, elb_lines;
GPUIndexBufBuilder elb_fast, elb_lines_fast;
@@ -594,7 +513,6 @@ static void gpu_pbvh_grid_fill_index_buffers(
const uint grid_vert_len = square_uint(gridsize - 1) * 4;
for (int i = 0; i < totgrid; i++, offset += grid_vert_len) {
bool grid_visible = false;
-
BLI_bitmap *gh = buffers->grid_hidden[grid_indices[i]];
uint v0, v1, v2, v3;
@@ -673,16 +591,24 @@ void GPU_pbvh_grid_buffers_update_free(GPU_PBVH_Buffers *buffers,
/* Threaded - do not call any functions that use OpenGL calls! */
void GPU_pbvh_grid_buffers_update(GPU_PBVH_Buffers *buffers,
+ SubdivCCG *subdiv_ccg,
CCGElem **grids,
- const DMFlagMat *grid_flag_mats,
+ const struct DMFlagMat *grid_flag_mats,
int *grid_indices,
int totgrid,
- const CCGKey *key,
+ const int *sculpt_face_sets,
+ const int face_sets_color_seed,
+ const int face_sets_color_default,
+ const struct CCGKey *key,
const int update_flags)
{
const bool show_mask = (update_flags & GPU_PBVH_BUFFERS_SHOW_MASK) != 0;
const bool show_vcol = (update_flags & GPU_PBVH_BUFFERS_SHOW_VCOL) != 0;
+ const bool show_face_sets = sculpt_face_sets &&
+ (update_flags & GPU_PBVH_BUFFERS_SHOW_SCULPT_FACE_SETS) != 0;
bool empty_mask = true;
+ bool default_face_set = true;
+
int i, j, k, x, y;
/* Build VBO */
@@ -702,8 +628,13 @@ void GPU_pbvh_grid_buffers_update(GPU_PBVH_Buffers *buffers,
return;
}
- gpu_pbvh_grid_fill_index_buffers(
- buffers, grid_indices, visible_quad_len, totgrid, key->grid_size);
+ gpu_pbvh_grid_fill_index_buffers(buffers,
+ subdiv_ccg,
+ sculpt_face_sets,
+ grid_indices,
+ visible_quad_len,
+ totgrid,
+ key->grid_size);
}
uint vbo_index_offset = 0;
@@ -716,9 +647,23 @@ void GPU_pbvh_grid_buffers_update(GPU_PBVH_Buffers *buffers,
}
for (i = 0; i < totgrid; i++) {
- CCGElem *grid = grids[grid_indices[i]];
+ const int grid_index = grid_indices[i];
+ CCGElem *grid = grids[grid_index];
int vbo_index = vbo_index_offset;
+ uchar face_set_color[4] = {UCHAR_MAX, UCHAR_MAX, UCHAR_MAX, UCHAR_MAX};
+
+ if (show_face_sets && subdiv_ccg && sculpt_face_sets) {
+ const int face_index = BKE_subdiv_ccg_grid_to_face_index(subdiv_ccg, grid_index);
+
+ const int fset = abs(sculpt_face_sets[face_index]);
+ /* Skip for the default color Face Set to render it white. */
+ if (fset != face_sets_color_default) {
+ face_set_overlay_color_get(fset, face_sets_color_seed, face_set_color);
+ default_face_set = false;
+ }
+ }
+
if (buffers->smooth) {
for (y = 0; y < key->grid_size; y++) {
for (x = 0; x < key->grid_size; x++) {
@@ -742,8 +687,7 @@ void GPU_pbvh_grid_buffers_update(GPU_PBVH_Buffers *buffers,
GPU_vertbuf_attr_set(buffers->vert_buf, g_vbo_id.col, vbo_index, &vcol);
}
- uchar fsets[3] = {UCHAR_MAX, UCHAR_MAX, UCHAR_MAX};
- GPU_vertbuf_attr_set(buffers->vert_buf, g_vbo_id.fset, vbo_index, &fsets);
+ GPU_vertbuf_attr_set(buffers->vert_buf, g_vbo_id.fset, vbo_index, &face_set_color);
vbo_index += 1;
}
@@ -799,11 +743,10 @@ void GPU_pbvh_grid_buffers_update(GPU_PBVH_Buffers *buffers,
GPU_vertbuf_attr_set(buffers->vert_buf, g_vbo_id.col, vbo_index + 2, &vcol);
GPU_vertbuf_attr_set(buffers->vert_buf, g_vbo_id.col, vbo_index + 3, &vcol);
- uchar fsets[3] = {UCHAR_MAX, UCHAR_MAX, UCHAR_MAX};
- GPU_vertbuf_attr_set(buffers->vert_buf, g_vbo_id.fset, vbo_index + 0, &fsets);
- GPU_vertbuf_attr_set(buffers->vert_buf, g_vbo_id.fset, vbo_index + 1, &fsets);
- GPU_vertbuf_attr_set(buffers->vert_buf, g_vbo_id.fset, vbo_index + 2, &fsets);
- GPU_vertbuf_attr_set(buffers->vert_buf, g_vbo_id.fset, vbo_index + 3, &fsets);
+ GPU_vertbuf_attr_set(buffers->vert_buf, g_vbo_id.fset, vbo_index + 0, &face_set_color);
+ GPU_vertbuf_attr_set(buffers->vert_buf, g_vbo_id.fset, vbo_index + 1, &face_set_color);
+ GPU_vertbuf_attr_set(buffers->vert_buf, g_vbo_id.fset, vbo_index + 2, &face_set_color);
+ GPU_vertbuf_attr_set(buffers->vert_buf, g_vbo_id.fset, vbo_index + 3, &face_set_color);
vbo_index += 4;
}
@@ -823,7 +766,7 @@ void GPU_pbvh_grid_buffers_update(GPU_PBVH_Buffers *buffers,
buffers->totgrid = totgrid;
buffers->grid_flag_mats = grid_flag_mats;
buffers->gridkey = *key;
- buffers->show_overlay = !empty_mask;
+ buffers->show_overlay = !empty_mask || !default_face_set;
}
/* Threaded - do not call any functions that use OpenGL calls! */
@@ -1143,13 +1086,24 @@ short GPU_pbvh_buffers_material_index_get(GPU_PBVH_Buffers *buffers)
return buffers->material_index;
}
+static void gpu_pbvh_buffers_clear(GPU_PBVH_Buffers *buffers)
+{
+ GPU_BATCH_DISCARD_SAFE(buffers->lines);
+ GPU_BATCH_DISCARD_SAFE(buffers->lines_fast);
+ GPU_BATCH_DISCARD_SAFE(buffers->triangles);
+ GPU_BATCH_DISCARD_SAFE(buffers->triangles_fast);
+ GPU_INDEXBUF_DISCARD_SAFE(buffers->index_lines_buf_fast);
+ GPU_INDEXBUF_DISCARD_SAFE(buffers->index_lines_buf);
+ GPU_INDEXBUF_DISCARD_SAFE(buffers->index_buf_fast);
+ GPU_INDEXBUF_DISCARD_SAFE(buffers->index_buf);
+ GPU_VERTBUF_DISCARD_SAFE(buffers->vert_buf);
+}
+
void GPU_pbvh_buffers_update_flush(GPU_PBVH_Buffers *buffers)
{
/* Free empty bmesh node buffers. */
if (buffers->clear_bmesh_on_flush) {
- GPU_BATCH_DISCARD_SAFE(buffers->triangles);
- GPU_INDEXBUF_DISCARD_SAFE(buffers->index_buf);
- GPU_VERTBUF_DISCARD_SAFE(buffers->vert_buf);
+ gpu_pbvh_buffers_clear(buffers);
buffers->clear_bmesh_on_flush = false;
}
@@ -1162,16 +1116,7 @@ void GPU_pbvh_buffers_update_flush(GPU_PBVH_Buffers *buffers)
void GPU_pbvh_buffers_free(GPU_PBVH_Buffers *buffers)
{
if (buffers) {
- GPU_BATCH_DISCARD_SAFE(buffers->lines);
- GPU_BATCH_DISCARD_SAFE(buffers->lines_fast);
- GPU_BATCH_DISCARD_SAFE(buffers->triangles);
- GPU_BATCH_DISCARD_SAFE(buffers->triangles_fast);
- GPU_INDEXBUF_DISCARD_SAFE(buffers->index_lines_buf_fast);
- GPU_INDEXBUF_DISCARD_SAFE(buffers->index_lines_buf);
- GPU_INDEXBUF_DISCARD_SAFE(buffers->index_buf_fast);
- GPU_INDEXBUF_DISCARD_SAFE(buffers->index_buf);
- GPU_VERTBUF_DISCARD_SAFE(buffers->vert_buf);
-
+ gpu_pbvh_buffers_clear(buffers);
MEM_freeN(buffers);
}
}
diff --git a/source/blender/gpu/intern/gpu_codegen.c b/source/blender/gpu/intern/gpu_codegen.c
index 211ae0b3897..c1e7933d7ba 100644
--- a/source/blender/gpu/intern/gpu_codegen.c
+++ b/source/blender/gpu/intern/gpu_codegen.c
@@ -75,7 +75,7 @@ static uint32_t gpu_pass_hash(const char *frag_gen, const char *defs, ListBase *
BLI_HashMurmur2A hm2a;
BLI_hash_mm2a_init(&hm2a, 0);
BLI_hash_mm2a_add(&hm2a, (uchar *)frag_gen, strlen(frag_gen));
- for (GPUMaterialAttribute *attr = attributes->first; attr; attr = attr->next) {
+ LISTBASE_FOREACH (GPUMaterialAttribute *, attr, attributes) {
BLI_hash_mm2a_add(&hm2a, (uchar *)attr->name, strlen(attr->name));
}
if (defs) {
@@ -314,12 +314,12 @@ static int codegen_process_uniforms_functions(GPUMaterial *material,
ListBase ubo_inputs = {NULL, NULL};
/* Attributes */
- for (GPUMaterialAttribute *attr = graph->attributes.first; attr; attr = attr->next) {
+ LISTBASE_FOREACH (GPUMaterialAttribute *, attr, &graph->attributes) {
BLI_dynstr_appendf(ds, "in %s var%d;\n", gpu_data_type_to_string(attr->gputype), attr->id);
}
/* Textures */
- for (GPUMaterialTexture *tex = graph->textures.first; tex; tex = tex->next) {
+ LISTBASE_FOREACH (GPUMaterialTexture *, tex, &graph->textures) {
if (tex->colorband) {
BLI_dynstr_appendf(ds, "uniform sampler1DArray %s;\n", tex->sampler_name);
}
@@ -333,7 +333,7 @@ static int codegen_process_uniforms_functions(GPUMaterial *material,
}
/* Volume Grids */
- for (GPUMaterialVolumeGrid *grid = graph->volume_grids.first; grid; grid = grid->next) {
+ LISTBASE_FOREACH (GPUMaterialVolumeGrid *, grid, &graph->volume_grids) {
BLI_dynstr_appendf(ds, "uniform sampler3D %s;\n", grid->sampler_name);
BLI_dynstr_appendf(ds, "uniform mat4 %s = mat4(0.0);\n", grid->transform_name);
}
@@ -381,7 +381,7 @@ static int codegen_process_uniforms_functions(GPUMaterial *material,
/* Inputs are sorted */
BLI_dynstr_appendf(ds, "\nlayout (std140) uniform %s {\n", GPU_UBO_BLOCK_NAME);
- for (LinkData *link = ubo_inputs.first; link; link = link->next) {
+ LISTBASE_FOREACH (LinkData *, link, &ubo_inputs) {
input = link->data;
BLI_dynstr_appendf(ds, "\t%s unf%d;\n", gpu_data_type_to_string(input->type), input->id);
}
@@ -673,7 +673,7 @@ static char *code_generate_vertex(GPUNodeGraph *graph, const char *vert_code, bo
"#define DEFINE_ATTR(type, attr) in type attr\n"
"#endif\n");
- for (GPUMaterialAttribute *attr = graph->attributes.first; attr; attr = attr->next) {
+ LISTBASE_FOREACH (GPUMaterialAttribute *, attr, &graph->attributes) {
/* XXX FIXME : see notes in mesh_render_data_create() */
/* NOTE : Replicate changes to mesh_render_data_create() in draw_cache_impl_mesh.c */
if (attr->type == CD_ORCO) {
@@ -689,8 +689,8 @@ static char *code_generate_vertex(GPUNodeGraph *graph, const char *vert_code, bo
BLI_dynstr_appendf(ds, "#define att%d %s\n", attr->id, attr_prefix_get(attr->type));
}
else {
- char attr_safe_name[GPU_MAX_SAFE_ATTRIB_NAME];
- GPU_vertformat_safe_attrib_name(attr->name, attr_safe_name, GPU_MAX_SAFE_ATTRIB_NAME);
+ char attr_safe_name[GPU_MAX_SAFE_ATTR_NAME];
+ GPU_vertformat_safe_attr_name(attr->name, attr_safe_name, GPU_MAX_SAFE_ATTR_NAME);
BLI_dynstr_appendf(ds,
"DEFINE_ATTR(%s, %s%s);\n",
gpu_data_type_to_string(attr->gputype),
@@ -787,7 +787,7 @@ static char *code_generate_vertex(GPUNodeGraph *graph, const char *vert_code, bo
BLI_dynstr_append(ds, "\tbarycentricPosg = position;\n");
}
- for (GPUMaterialAttribute *attr = graph->attributes.first; attr; attr = attr->next) {
+ LISTBASE_FOREACH (GPUMaterialAttribute *, attr, &graph->attributes) {
if (attr->type == CD_TANGENT) {
/* Not supported by hairs */
BLI_dynstr_appendf(ds, "\tvar%d%s = vec4(0.0);\n", attr->id, use_geom ? "g" : "");
@@ -820,7 +820,7 @@ static char *code_generate_vertex(GPUNodeGraph *graph, const char *vert_code, bo
BLI_dynstr_append(ds, "\tbarycentricPosg = (ModelMatrix * vec4(position, 1.0)).xyz;\n");
}
- for (GPUMaterialAttribute *attr = graph->attributes.first; attr; attr = attr->next) {
+ LISTBASE_FOREACH (GPUMaterialAttribute *, attr, &graph->attributes) {
if (attr->type == CD_TANGENT) { /* silly exception */
BLI_dynstr_appendf(ds,
"\tvar%d%s.xyz = transpose(mat3(ModelMatrixInverse)) * att%d.xyz;\n",
@@ -903,7 +903,7 @@ static char *code_generate_geometry(GPUNodeGraph *graph,
}
}
- for (GPUMaterialAttribute *attr = graph->attributes.first; attr; attr = attr->next) {
+ LISTBASE_FOREACH (GPUMaterialAttribute *, attr, &graph->attributes) {
BLI_dynstr_appendf(ds, "in %s var%dg[];\n", gpu_data_type_to_string(attr->gputype), attr->id);
BLI_dynstr_appendf(ds, "out %s var%d;\n", gpu_data_type_to_string(attr->gputype), attr->id);
}
@@ -1010,7 +1010,7 @@ static char *code_generate_geometry(GPUNodeGraph *graph,
BLI_dynstr_append(ds, "#endif\n");
}
- for (GPUMaterialAttribute *attr = graph->attributes.first; attr; attr = attr->next) {
+ LISTBASE_FOREACH (GPUMaterialAttribute *, attr, &graph->attributes) {
/* TODO let shader choose what to do depending on what the attribute is. */
BLI_dynstr_appendf(ds, "\tvar%d = var%dg[vert];\n", attr->id, attr->id);
}
@@ -1160,7 +1160,7 @@ static int count_active_texture_sampler(GPUShader *shader, char *source)
if (*code != '\0') {
char sampler_name[64];
code = gpu_str_skip_token(code, sampler_name, sizeof(sampler_name));
- int id = GPU_shader_get_uniform_ensure(shader, sampler_name);
+ int id = GPU_shader_get_uniform(shader, sampler_name);
if (id == -1) {
continue;
diff --git a/source/blender/gpu/intern/gpu_context_private.h b/source/blender/gpu/intern/gpu_context_private.h
index c9379e5433f..f64cdf439a1 100644
--- a/source/blender/gpu/intern/gpu_context_private.h
+++ b/source/blender/gpu/intern/gpu_context_private.h
@@ -26,12 +26,12 @@
#ifndef __GPU_CONTEXT_PRIVATE_H__
#define __GPU_CONTEXT_PRIVATE_H__
+#include "GPU_context.h"
+
#ifdef __cplusplus
extern "C" {
#endif
-#include "GPU_context.h"
-
struct GPUFrameBuffer;
GLuint GPU_vao_default(void);
diff --git a/source/blender/gpu/intern/gpu_draw.c b/source/blender/gpu/intern/gpu_draw.c
index 350c616e359..1c346217e9f 100644
--- a/source/blender/gpu/intern/gpu_draw.c
+++ b/source/blender/gpu/intern/gpu_draw.c
@@ -158,10 +158,10 @@ static GLenum gpu_get_mipmap_filter(bool mag)
}
/* Anisotropic filtering settings */
-void GPU_set_anisotropic(Main *bmain, float value)
+void GPU_set_anisotropic(float value)
{
if (GTS.anisotropic != value) {
- GPU_free_images(bmain);
+ GPU_samplers_free();
/* Clamp value to the maximum value the graphics card supports */
const float max = GPU_max_texture_anisotropy();
@@ -170,6 +170,8 @@ void GPU_set_anisotropic(Main *bmain, float value)
}
GTS.anisotropic = value;
+
+ GPU_samplers_init();
}
}
@@ -449,22 +451,12 @@ static uint gpu_texture_create_tile_array(Image *ima, ImBuf *main_ibuf)
BKE_image_release_ibuf(ima, ibuf, NULL);
}
- glTexParameteri(GL_TEXTURE_2D_ARRAY, GL_TEXTURE_MAG_FILTER, gpu_get_mipmap_filter(1));
-
if (GPU_get_mipmap()) {
glGenerateMipmap(GL_TEXTURE_2D_ARRAY);
- glTexParameteri(GL_TEXTURE_2D_ARRAY, GL_TEXTURE_MIN_FILTER, gpu_get_mipmap_filter(0));
if (ima) {
ima->gpuflag |= IMA_GPU_MIPMAP_COMPLETE;
}
}
- else {
- glTexParameteri(GL_TEXTURE_2D_ARRAY, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
- }
-
- if (GLEW_EXT_texture_filter_anisotropic) {
- glTexParameterf(GL_TEXTURE_2D_ARRAY, GL_TEXTURE_MAX_ANISOTROPY_EXT, GPU_get_anisotropic());
- }
glBindTexture(GL_TEXTURE_2D_ARRAY, 0);
@@ -905,7 +897,7 @@ GPUTexture *GPU_texture_from_blender(Image *ima, ImageUser *iuser, ImBuf *ibuf,
bindcode = gpu_texture_create_tile_array(ima, ibuf_intern);
}
else if (textarget == GL_TEXTURE_1D_ARRAY) {
- bindcode = gpu_texture_create_tile_mapping(ima, iuser->multiview_eye);
+ bindcode = gpu_texture_create_tile_mapping(ima, iuser ? iuser->multiview_eye : 0);
}
else {
bindcode = gpu_texture_create_from_ibuf(ima, ibuf_intern, textarget);
@@ -1098,18 +1090,12 @@ void GPU_create_gl_tex(uint *bind,
GL_TEXTURE_2D, 0, internal_format, rectw, recth, 0, GL_RGBA, GL_UNSIGNED_BYTE, rect);
}
- glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, gpu_get_mipmap_filter(1));
-
if (GPU_get_mipmap() && mipmap) {
glGenerateMipmap(GL_TEXTURE_2D);
- glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, gpu_get_mipmap_filter(0));
if (ima) {
ima->gpuflag |= IMA_GPU_MIPMAP_COMPLETE;
}
}
- else {
- glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
- }
}
else if (textarget == GL_TEXTURE_CUBE_MAP) {
int w = rectw / 3, h = recth / 2;
@@ -1132,22 +1118,13 @@ void GPU_create_gl_tex(uint *bind,
}
}
- glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_MAG_FILTER, gpu_get_mipmap_filter(1));
-
if (GPU_get_mipmap() && mipmap) {
glGenerateMipmap(GL_TEXTURE_CUBE_MAP);
- glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_MIN_FILTER, gpu_get_mipmap_filter(0));
if (ima) {
ima->gpuflag |= IMA_GPU_MIPMAP_COMPLETE;
}
}
- else {
- glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
- }
- glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
- glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
- glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_WRAP_R, GL_CLAMP_TO_EDGE);
gpu_del_cube_map(cube_map);
}
@@ -1156,10 +1133,6 @@ void GPU_create_gl_tex(uint *bind,
}
}
- if (GLEW_EXT_texture_filter_anisotropic) {
- glTexParameterf(textarget, GL_TEXTURE_MAX_ANISOTROPY_EXT, GPU_get_anisotropic());
- }
-
glBindTexture(textarget, 0);
if (ibuf) {
@@ -1211,10 +1184,6 @@ bool GPU_upload_dxt_texture(ImBuf *ibuf, bool use_srgb)
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, gpu_get_mipmap_filter(0));
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, gpu_get_mipmap_filter(1));
- if (GLEW_EXT_texture_filter_anisotropic) {
- glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAX_ANISOTROPY_EXT, GPU_get_anisotropic());
- }
-
blocksize = (ibuf->dds_data.fourcc == FOURCC_DXT1) ? 8 : 16;
for (i = 0; i < ibuf->dds_data.nummipmaps && (width || height); i++) {
if (width == 0) {
@@ -1481,66 +1450,3 @@ void GPU_free_images_old(Main *bmain)
ima = ima->id.next;
}
}
-
-static void gpu_disable_multisample(void)
-{
-#ifdef __linux__
- /* changing multisample from the default (enabled) causes problems on some
- * systems (NVIDIA/Linux) when the pixel format doesn't have a multisample buffer */
- bool toggle_ok = true;
-
- if (GPU_type_matches(GPU_DEVICE_NVIDIA, GPU_OS_UNIX, GPU_DRIVER_ANY)) {
- int samples = 0;
- glGetIntegerv(GL_SAMPLES, &samples);
-
- if (samples == 0) {
- toggle_ok = false;
- }
- }
-
- if (toggle_ok) {
- glDisable(GL_MULTISAMPLE);
- }
-#else
- glDisable(GL_MULTISAMPLE);
-#endif
-}
-
-/* Default OpenGL State
- *
- * This is called on startup, for opengl offscreen render.
- * Generally we should always return to this state when
- * temporarily modifying the state for drawing, though that are (undocumented)
- * exceptions that we should try to get rid of. */
-
-void GPU_state_init(void)
-{
- GPU_program_point_size(false);
-
- glEnable(GL_TEXTURE_CUBE_MAP_SEAMLESS);
-
- glDepthFunc(GL_LEQUAL);
-
- glDisable(GL_BLEND);
- glDisable(GL_DEPTH_TEST);
- glDisable(GL_COLOR_LOGIC_OP);
- glDisable(GL_STENCIL_TEST);
-
- glDepthRange(0.0, 1.0);
-
- glFrontFace(GL_CCW);
- glCullFace(GL_BACK);
- glDisable(GL_CULL_FACE);
-
- gpu_disable_multisample();
-
- /* This is a bit dangerous since addons could change this. */
- glEnable(GL_PRIMITIVE_RESTART);
- glPrimitiveRestartIndex((GLuint)0xFFFFFFFF);
-
- /* TODO: Should become default. But needs at least GL 4.3 */
- if (GLEW_ARB_ES3_compatibility) {
- /* Takes predecence over GL_PRIMITIVE_RESTART */
- glEnable(GL_PRIMITIVE_RESTART_FIXED_INDEX);
- }
-}
diff --git a/source/blender/gpu/intern/gpu_extensions.c b/source/blender/gpu/intern/gpu_extensions.c
index e3632b82778..8dd468b5414 100644
--- a/source/blender/gpu/intern/gpu_extensions.c
+++ b/source/blender/gpu/intern/gpu_extensions.c
@@ -304,6 +304,14 @@ void gpu_extensions_init(void)
GG.context_local_shaders_workaround = GLEW_ARB_get_program_binary;
}
+ /* Special fix for theses specific GPUs.
+ * Without this workaround, blender crashes on startup. (see T72098) */
+ if (GPU_type_matches(GPU_DEVICE_INTEL, GPU_OS_WIN, GPU_DRIVER_OFFICIAL) &&
+ (strstr(renderer, "HD Graphics 620") || strstr(renderer, "HD Graphics 630"))) {
+ GG.mip_render_workaround = true;
+ GG.context_local_shaders_workaround = GLEW_ARB_get_program_binary;
+ }
+
/* df/dy calculation factors, those are dependent on driver */
GG.dfdyfactors[0] = 1.0;
GG.dfdyfactors[1] = 1.0;
@@ -347,11 +355,13 @@ void gpu_extensions_init(void)
}
GPU_invalid_tex_init();
+ GPU_samplers_init();
}
void gpu_extensions_exit(void)
{
GPU_invalid_tex_free();
+ GPU_samplers_free();
}
bool GPU_mem_stats_supported(void)
diff --git a/source/blender/gpu/intern/gpu_framebuffer.c b/source/blender/gpu/intern/gpu_framebuffer.c
index 59d0be2cefb..5af9364b92c 100644
--- a/source/blender/gpu/intern/gpu_framebuffer.c
+++ b/source/blender/gpu/intern/gpu_framebuffer.c
@@ -514,6 +514,11 @@ void GPU_framebuffer_bind(GPUFrameBuffer *fb)
if (GPU_framebuffer_active_get() != fb) {
glBindFramebuffer(GL_FRAMEBUFFER, fb->object);
glEnable(GL_FRAMEBUFFER_SRGB);
+
+ GPUTexture *first_target = fb->attachments[GPU_FB_COLOR_ATTACHMENT0].tex;
+ const bool is_srgb_target = (first_target &&
+ (GPU_texture_format(first_target) == GPU_SRGB8_A8));
+ GPU_shader_set_framebuffer_srgb_target(is_srgb_target);
}
gpu_framebuffer_current_set(fb);
@@ -536,10 +541,6 @@ void GPU_framebuffer_bind(GPUFrameBuffer *fb)
}
#endif
- if (fb->multisample) {
- glEnable(GL_MULTISAMPLE);
- }
-
glViewport(0, 0, fb->width, fb->height);
}
@@ -549,6 +550,7 @@ void GPU_framebuffer_restore(void)
glBindFramebuffer(GL_FRAMEBUFFER, GPU_framebuffer_default());
gpu_framebuffer_current_set(NULL);
glDisable(GL_FRAMEBUFFER_SRGB);
+ GPU_shader_set_framebuffer_srgb_target(false);
}
}
@@ -944,6 +946,7 @@ void GPU_offscreen_bind(GPUOffScreen *ofs, bool save)
GPUFrameBuffer *ofs_fb = gpu_offscreen_fb_get(ofs);
GPU_framebuffer_bind(ofs_fb);
glDisable(GL_FRAMEBUFFER_SRGB);
+ GPU_shader_set_framebuffer_srgb_target(false);
}
void GPU_offscreen_unbind(GPUOffScreen *UNUSED(ofs), bool restore)
diff --git a/source/blender/gpu/intern/gpu_immediate.c b/source/blender/gpu/intern/gpu_immediate.c
index 4523df8be7c..9ea273f33cf 100644
--- a/source/blender/gpu/intern/gpu_immediate.c
+++ b/source/blender/gpu/intern/gpu_immediate.c
@@ -43,6 +43,13 @@
extern void GPU_matrix_bind(const GPUShaderInterface *);
extern bool GPU_matrix_dirty_get(void);
+typedef struct ImmediateDrawBuffer {
+ GLuint vbo_id;
+ GLubyte *buffer_data;
+ uint buffer_offset;
+ uint buffer_size;
+} ImmediateDrawBuffer;
+
typedef struct {
/* TODO: organize this struct by frequency of change (run-time) */
@@ -50,14 +57,14 @@ typedef struct {
GPUContext *context;
/* current draw call */
- GLubyte *buffer_data;
- uint buffer_offset;
- uint buffer_bytes_mapped;
- uint vertex_len;
bool strict_vertex_len;
+ uint vertex_len;
+ uint buffer_bytes_mapped;
+ ImmediateDrawBuffer *active_buffer;
GPUPrimType prim_type;
-
GPUVertFormat vertex_format;
+ ImmediateDrawBuffer draw_buffer;
+ ImmediateDrawBuffer draw_buffer_strict;
/* current vertex */
uint vertex_idx;
@@ -65,7 +72,6 @@ typedef struct {
uint16_t
unassigned_attr_bits; /* which attributes of current vertex have not been given values? */
- GLuint vbo_id;
GLuint vao_id;
GLuint bound_program;
@@ -76,7 +82,6 @@ typedef struct {
/* size of internal buffer */
#define DEFAULT_INTERNAL_BUFFER_SIZE (4 * 1024 * 1024)
-static uint imm_buffer_size = DEFAULT_INTERNAL_BUFFER_SIZE;
static bool initialized = false;
static Immediate imm;
@@ -88,9 +93,14 @@ void immInit(void)
#endif
memset(&imm, 0, sizeof(Immediate));
- imm.vbo_id = GPU_buf_alloc();
- glBindBuffer(GL_ARRAY_BUFFER, imm.vbo_id);
- glBufferData(GL_ARRAY_BUFFER, imm_buffer_size, NULL, GL_DYNAMIC_DRAW);
+ imm.draw_buffer.vbo_id = GPU_buf_alloc();
+ imm.draw_buffer.buffer_size = DEFAULT_INTERNAL_BUFFER_SIZE;
+ glBindBuffer(GL_ARRAY_BUFFER, imm.draw_buffer.vbo_id);
+ glBufferData(GL_ARRAY_BUFFER, imm.draw_buffer.buffer_size, NULL, GL_DYNAMIC_DRAW);
+ imm.draw_buffer_strict.vbo_id = GPU_buf_alloc();
+ imm.draw_buffer_strict.buffer_size = DEFAULT_INTERNAL_BUFFER_SIZE;
+ glBindBuffer(GL_ARRAY_BUFFER, imm.draw_buffer_strict.vbo_id);
+ glBufferData(GL_ARRAY_BUFFER, imm.draw_buffer_strict.buffer_size, NULL, GL_DYNAMIC_DRAW);
imm.prim_type = GPU_PRIM_NONE;
imm.strict_vertex_len = true;
@@ -124,7 +134,8 @@ void immDeactivate(void)
void immDestroy(void)
{
- GPU_buf_free(imm.vbo_id);
+ GPU_buf_free(imm.draw_buffer.vbo_id);
+ GPU_buf_free(imm.draw_buffer_strict.vbo_id);
initialized = false;
}
@@ -151,6 +162,7 @@ void immBindProgram(GLuint program, const GPUShaderInterface *shaderface)
glUseProgram(program);
get_attr_locations(&imm.vertex_format, &imm.attr_binding, shaderface);
GPU_matrix_bind(shaderface);
+ GPU_shader_set_srgb_uniform(shaderface);
}
void immBindBuiltinProgram(eGPUBuiltinShader shader_id)
@@ -212,6 +224,7 @@ void immBegin(GPUPrimType prim_type, uint vertex_len)
assert(initialized);
assert(imm.prim_type == GPU_PRIM_NONE); /* make sure we haven't already begun */
assert(vertex_count_makes_sense_for_primitive(vertex_len, prim_type));
+ assert(imm.active_buffer == NULL);
#endif
imm.prim_type = prim_type;
imm.vertex_len = vertex_len;
@@ -220,54 +233,66 @@ void immBegin(GPUPrimType prim_type, uint vertex_len)
/* how many bytes do we need for this draw call? */
const uint bytes_needed = vertex_buffer_size(&imm.vertex_format, vertex_len);
+ ImmediateDrawBuffer *active_buffer = imm.strict_vertex_len ? &imm.draw_buffer_strict :
+ &imm.draw_buffer;
+ imm.active_buffer = active_buffer;
- glBindBuffer(GL_ARRAY_BUFFER, imm.vbo_id);
+ glBindBuffer(GL_ARRAY_BUFFER, active_buffer->vbo_id);
/* does the current buffer have enough room? */
- const uint available_bytes = imm_buffer_size - imm.buffer_offset;
+ const uint available_bytes = active_buffer->buffer_size - active_buffer->buffer_offset;
bool recreate_buffer = false;
- if (bytes_needed > imm_buffer_size) {
+ if (bytes_needed > active_buffer->buffer_size) {
/* expand the internal buffer */
- imm_buffer_size = bytes_needed;
+ active_buffer->buffer_size = bytes_needed;
recreate_buffer = true;
}
else if (bytes_needed < DEFAULT_INTERNAL_BUFFER_SIZE &&
- imm_buffer_size > DEFAULT_INTERNAL_BUFFER_SIZE) {
+ active_buffer->buffer_size > DEFAULT_INTERNAL_BUFFER_SIZE) {
/* shrink the internal buffer */
- imm_buffer_size = DEFAULT_INTERNAL_BUFFER_SIZE;
+ active_buffer->buffer_size = DEFAULT_INTERNAL_BUFFER_SIZE;
recreate_buffer = true;
}
/* ensure vertex data is aligned */
/* Might waste a little space, but it's safe. */
- const uint pre_padding = padding(imm.buffer_offset, imm.vertex_format.stride);
+ const uint pre_padding = padding(active_buffer->buffer_offset, imm.vertex_format.stride);
if (!recreate_buffer && ((bytes_needed + pre_padding) <= available_bytes)) {
- imm.buffer_offset += pre_padding;
+ active_buffer->buffer_offset += pre_padding;
}
else {
/* orphan this buffer & start with a fresh one */
/* this method works on all platforms, old & new */
- glBufferData(GL_ARRAY_BUFFER, imm_buffer_size, NULL, GL_DYNAMIC_DRAW);
+ glBufferData(GL_ARRAY_BUFFER, active_buffer->buffer_size, NULL, GL_DYNAMIC_DRAW);
- imm.buffer_offset = 0;
+ active_buffer->buffer_offset = 0;
}
/* printf("mapping %u to %u\n", imm.buffer_offset, imm.buffer_offset + bytes_needed - 1); */
- imm.buffer_data = glMapBufferRange(GL_ARRAY_BUFFER,
- imm.buffer_offset,
- bytes_needed,
- GL_MAP_WRITE_BIT | GL_MAP_UNSYNCHRONIZED_BIT |
- (imm.strict_vertex_len ? 0 : GL_MAP_FLUSH_EXPLICIT_BIT));
+#if TRUST_NO_ONE
+ {
+ GLint bufsize;
+ glGetBufferParameteriv(GL_ARRAY_BUFFER, GL_BUFFER_SIZE, &bufsize);
+ assert(active_buffer->buffer_offset + bytes_needed <= bufsize);
+ }
+#endif
+
+ active_buffer->buffer_data = glMapBufferRange(
+ GL_ARRAY_BUFFER,
+ active_buffer->buffer_offset,
+ bytes_needed,
+ GL_MAP_WRITE_BIT | GL_MAP_UNSYNCHRONIZED_BIT |
+ (imm.strict_vertex_len ? 0 : GL_MAP_FLUSH_EXPLICIT_BIT));
#if TRUST_NO_ONE
- assert(imm.buffer_data != NULL);
+ assert(active_buffer->buffer_data != NULL);
#endif
imm.buffer_bytes_mapped = bytes_needed;
- imm.vertex_data = imm.buffer_data;
+ imm.vertex_data = active_buffer->buffer_data;
}
void immBeginAtMost(GPUPrimType prim_type, uint vertex_len)
@@ -337,7 +362,7 @@ static void immDrawSetup(void)
for (uint a_idx = 0; a_idx < imm.vertex_format.attr_len; a_idx++) {
const GPUVertAttr *a = &imm.vertex_format.attrs[a_idx];
- const uint offset = imm.buffer_offset + a->offset;
+ const uint offset = imm.active_buffer->buffer_offset + a->offset;
const GLvoid *pointer = (const GLubyte *)0 + offset;
const uint loc = read_attr_location(&imm.attr_binding, a_idx);
@@ -364,6 +389,7 @@ void immEnd(void)
{
#if TRUST_NO_ONE
assert(imm.prim_type != GPU_PRIM_NONE); /* make sure we're between a Begin/End pair */
+ assert(imm.active_buffer || imm.batch);
#endif
uint buffer_bytes_used;
@@ -420,12 +446,13 @@ void immEnd(void)
// glBindBuffer(GL_ARRAY_BUFFER, 0);
// glBindVertexArray(0);
/* prep for next immBegin */
- imm.buffer_offset += buffer_bytes_used;
+ imm.active_buffer->buffer_offset += buffer_bytes_used;
}
/* prep for next immBegin */
imm.prim_type = GPU_PRIM_NONE;
imm.strict_vertex_len = true;
+ imm.active_buffer = NULL;
}
static void setAttrValueBit(uint attr_id)
@@ -732,13 +759,11 @@ void immVertex2iv(uint attr_id, const int data[2])
#if 0
# if TRUST_NO_ONE
# define GET_UNIFORM \
- const GPUShaderInput *uniform = GPU_shaderinterface_uniform_ensure(imm.shader_interface, \
- name); \
+ const GPUShaderInput *uniform = GPU_shaderinterface_uniform(imm.shader_interface, name); \
assert(uniform);
# else
# define GET_UNIFORM \
- const GPUShaderInput *uniform = GPU_shaderinterface_uniform_ensure(imm.shader_interface, \
- name);
+ const GPUShaderInput *uniform = GPU_shaderinterface_uniform(imm.shader_interface, name);
# endif
#else
/* NOTE: It is possible to have uniform fully optimized out from the shader.
@@ -746,8 +771,7 @@ void immVertex2iv(uint attr_id, const int data[2])
* TODO(sergey): How can we detect existing-but-optimized-out uniform but still
* catch typos in uniform names passed to immUniform*() functions? */
# define GET_UNIFORM \
- const GPUShaderInput *uniform = GPU_shaderinterface_uniform_ensure(imm.shader_interface, \
- name); \
+ const GPUShaderInput *uniform = GPU_shaderinterface_uniform(imm.shader_interface, name); \
if (uniform == NULL) \
return;
#endif
@@ -785,20 +809,9 @@ void immUniform3fv(const char *name, const float data[3])
/* can increase this limit or move to another file */
#define MAX_UNIFORM_NAME_LEN 60
-void immUniformArray3fv(const char *bare_name, const float *data, int count)
+/* Note array index is not supported for name (i.e: "array[0]"). */
+void immUniformArray3fv(const char *name, const float *data, int count)
{
- /* look up "name[0]" when given "name" */
- const size_t len = strlen(bare_name);
-#if TRUST_NO_ONE
- assert(len <= MAX_UNIFORM_NAME_LEN);
-#endif
- char name[MAX_UNIFORM_NAME_LEN];
- strcpy(name, bare_name);
- name[len + 0] = '[';
- name[len + 1] = '0';
- name[len + 2] = ']';
- name[len + 3] = '\0';
-
GET_UNIFORM
glUniform3fv(uniform->location, count, data);
}
@@ -815,20 +828,9 @@ void immUniform4fv(const char *name, const float data[4])
glUniform4fv(uniform->location, 1, data);
}
-void immUniformArray4fv(const char *bare_name, const float *data, int count)
+/* Note array index is not supported for name (i.e: "array[0]"). */
+void immUniformArray4fv(const char *name, const float *data, int count)
{
- /* look up "name[0]" when given "name" */
- const size_t len = strlen(bare_name);
-#if TRUST_NO_ONE
- assert(len <= MAX_UNIFORM_NAME_LEN);
-#endif
- char name[MAX_UNIFORM_NAME_LEN];
- strcpy(name, bare_name);
- name[len + 0] = '[';
- name[len + 1] = '0';
- name[len + 2] = ']';
- name[len + 3] = '\0';
-
GET_UNIFORM
glUniform4fv(uniform->location, count, data);
}
@@ -855,12 +857,10 @@ void immUniform4iv(const char *name, const int data[4])
void immUniformColor4f(float r, float g, float b, float a)
{
- const GPUShaderInput *uniform = GPU_shaderinterface_uniform_builtin(imm.shader_interface,
- GPU_UNIFORM_COLOR);
-#if TRUST_NO_ONE
- assert(uniform != NULL);
-#endif
- glUniform4f(uniform->location, r, g, b, a);
+ int32_t uniform_loc = GPU_shaderinterface_uniform_builtin(imm.shader_interface,
+ GPU_UNIFORM_COLOR);
+ BLI_assert(uniform_loc != -1);
+ glUniform4f(uniform_loc, r, g, b, a);
}
void immUniformColor4fv(const float rgba[4])
diff --git a/source/blender/gpu/intern/gpu_immediate_util.c b/source/blender/gpu/intern/gpu_immediate_util.c
index 7266f595447..e834d6afccb 100644
--- a/source/blender/gpu/intern/gpu_immediate_util.c
+++ b/source/blender/gpu/intern/gpu_immediate_util.c
@@ -361,25 +361,35 @@ void imm_draw_box_wire_3d(uint pos, float x1, float y1, float x2, float y2)
/**
* Draw a standard checkerboard to indicate transparent backgrounds.
*/
-void imm_draw_box_checker_2d(float x1, float y1, float x2, float y2)
+void imm_draw_box_checker_2d_ex(float x1,
+ float y1,
+ float x2,
+ float y2,
+ const float color_primary[4],
+ const float color_secondary[4],
+ int checker_size)
{
uint pos = GPU_vertformat_attr_add(immVertexFormat(), "pos", GPU_COMP_F32, 2, GPU_FETCH_FLOAT);
- float checker_primary[4];
- float checker_secondary[4];
- int checker_size = UI_GetThemeValue(TH_TRANSPARENT_CHECKER_SIZE);
immBindBuiltinProgram(GPU_SHADER_2D_CHECKER);
- UI_GetThemeColor4fv(TH_TRANSPARENT_CHECKER_PRIMARY, checker_primary);
- UI_GetThemeColor4fv(TH_TRANSPARENT_CHECKER_SECONDARY, checker_secondary);
- immUniform4fv("color1", checker_primary);
- immUniform4fv("color2", checker_secondary);
+ immUniform4fv("color1", color_primary);
+ immUniform4fv("color2", color_secondary);
immUniform1i("size", checker_size);
immRectf(pos, x1, y1, x2, y2);
immUnbindProgram();
}
+void imm_draw_box_checker_2d(float x1, float y1, float x2, float y2)
+{
+ float checker_primary[4];
+ float checker_secondary[4];
+ UI_GetThemeColor4fv(TH_TRANSPARENT_CHECKER_PRIMARY, checker_primary);
+ UI_GetThemeColor4fv(TH_TRANSPARENT_CHECKER_SECONDARY, checker_secondary);
+ int checker_size = UI_GetThemeValue(TH_TRANSPARENT_CHECKER_SIZE);
+ imm_draw_box_checker_2d_ex(x1, y1, x2, y2, checker_primary, checker_secondary, checker_size);
+}
void imm_draw_cube_fill_3d(uint pos, const float co[3], const float aspect[3])
{
diff --git a/source/blender/gpu/intern/gpu_material.c b/source/blender/gpu/intern/gpu_material.c
index 3e73d156440..d2384b9c065 100644
--- a/source/blender/gpu/intern/gpu_material.c
+++ b/source/blender/gpu/intern/gpu_material.c
@@ -191,7 +191,7 @@ static void gpu_material_free_single(GPUMaterial *material)
void GPU_material_free(ListBase *gpumaterial)
{
- for (LinkData *link = gpumaterial->first; link; link = link->next) {
+ LISTBASE_FOREACH (LinkData *, link, gpumaterial) {
GPUMaterial *material = link->data;
gpu_material_free_single(material);
MEM_freeN(material);
@@ -209,6 +209,11 @@ GPUPass *GPU_material_get_pass(GPUMaterial *material)
return material->pass;
}
+GPUShader *GPU_material_get_shader(GPUMaterial *material)
+{
+ return material->pass ? GPU_pass_shader_get(material->pass) : NULL;
+}
+
/* Return can be NULL if it's a world material. */
Material *GPU_material_get_material(GPUMaterial *material)
{
@@ -628,7 +633,7 @@ GPUMaterial *GPU_material_from_nodetree_find(ListBase *gpumaterials,
const void *engine_type,
int options)
{
- for (LinkData *link = gpumaterials->first; link; link = link->next) {
+ LISTBASE_FOREACH (LinkData *, link, gpumaterials) {
GPUMaterial *current_material = (GPUMaterial *)link->data;
if (current_material->engine_type == engine_type && current_material->options == options) {
return current_material;
@@ -662,6 +667,9 @@ GPUMaterial *GPU_material_from_nodetree(Scene *scene,
/* Caller must re-use materials. */
BLI_assert(GPU_material_from_nodetree_find(gpumaterials, engine_type, options) == NULL);
+ /* HACK: Eevee assume this to create Ghash keys. */
+ BLI_assert(sizeof(GPUPass) > 16);
+
/* allocate material */
GPUMaterial *mat = MEM_callocN(sizeof(GPUMaterial), "GPUMaterial");
mat->ma = ma;
diff --git a/source/blender/gpu/intern/gpu_matrix.c b/source/blender/gpu/intern/gpu_matrix.c
index 8260e1496ff..2687f56ad27 100644
--- a/source/blender/gpu/intern/gpu_matrix.c
+++ b/source/blender/gpu/intern/gpu_matrix.c
@@ -654,63 +654,59 @@ void GPU_matrix_bind(const GPUShaderInterface *shaderface)
* call glUseProgram before this, as glUniform expects program to be bound
*/
- const GPUShaderInput *MV = GPU_shaderinterface_uniform_builtin(shaderface,
- GPU_UNIFORM_MODELVIEW);
- const GPUShaderInput *P = GPU_shaderinterface_uniform_builtin(shaderface,
- GPU_UNIFORM_PROJECTION);
- const GPUShaderInput *MVP = GPU_shaderinterface_uniform_builtin(shaderface, GPU_UNIFORM_MVP);
-
- const GPUShaderInput *N = GPU_shaderinterface_uniform_builtin(shaderface, GPU_UNIFORM_NORMAL);
- const GPUShaderInput *MV_inv = GPU_shaderinterface_uniform_builtin(shaderface,
- GPU_UNIFORM_MODELVIEW_INV);
- const GPUShaderInput *P_inv = GPU_shaderinterface_uniform_builtin(shaderface,
- GPU_UNIFORM_PROJECTION_INV);
-
- if (MV) {
+ int32_t MV = GPU_shaderinterface_uniform_builtin(shaderface, GPU_UNIFORM_MODELVIEW);
+ int32_t P = GPU_shaderinterface_uniform_builtin(shaderface, GPU_UNIFORM_PROJECTION);
+ int32_t MVP = GPU_shaderinterface_uniform_builtin(shaderface, GPU_UNIFORM_MVP);
+
+ int32_t N = GPU_shaderinterface_uniform_builtin(shaderface, GPU_UNIFORM_NORMAL);
+ int32_t MV_inv = GPU_shaderinterface_uniform_builtin(shaderface, GPU_UNIFORM_MODELVIEW_INV);
+ int32_t P_inv = GPU_shaderinterface_uniform_builtin(shaderface, GPU_UNIFORM_PROJECTION_INV);
+
+ if (MV != -1) {
#if DEBUG_MATRIX_BIND
puts("setting MV matrix");
#endif
- glUniformMatrix4fv(MV->location, 1, GL_FALSE, (const float *)GPU_matrix_model_view_get(NULL));
+ glUniformMatrix4fv(MV, 1, GL_FALSE, (const float *)GPU_matrix_model_view_get(NULL));
}
- if (P) {
+ if (P != -1) {
#if DEBUG_MATRIX_BIND
puts("setting P matrix");
#endif
- glUniformMatrix4fv(P->location, 1, GL_FALSE, (const float *)GPU_matrix_projection_get(NULL));
+ glUniformMatrix4fv(P, 1, GL_FALSE, (const float *)GPU_matrix_projection_get(NULL));
}
- if (MVP) {
+ if (MVP != -1) {
#if DEBUG_MATRIX_BIND
puts("setting MVP matrix");
#endif
glUniformMatrix4fv(
- MVP->location, 1, GL_FALSE, (const float *)GPU_matrix_model_view_projection_get(NULL));
+ MVP, 1, GL_FALSE, (const float *)GPU_matrix_model_view_projection_get(NULL));
}
- if (N) {
+ if (N != -1) {
#if DEBUG_MATRIX_BIND
puts("setting normal matrix");
#endif
- glUniformMatrix3fv(N->location, 1, GL_FALSE, (const float *)GPU_matrix_normal_get(NULL));
+ glUniformMatrix3fv(N, 1, GL_FALSE, (const float *)GPU_matrix_normal_get(NULL));
}
- if (MV_inv) {
+ if (MV_inv != -1) {
Mat4 m;
GPU_matrix_model_view_get(m);
invert_m4(m);
- glUniformMatrix4fv(MV_inv->location, 1, GL_FALSE, (const float *)m);
+ glUniformMatrix4fv(MV_inv, 1, GL_FALSE, (const float *)m);
}
- if (P_inv) {
+ if (P_inv != -1) {
Mat4 m;
GPU_matrix_projection_get(m);
invert_m4(m);
- glUniformMatrix4fv(P_inv->location, 1, GL_FALSE, (const float *)m);
+ glUniformMatrix4fv(P_inv, 1, GL_FALSE, (const float *)m);
}
gpu_matrix_state_active_set_dirty(false);
diff --git a/source/blender/gpu/intern/gpu_node_graph.c b/source/blender/gpu/intern/gpu_node_graph.c
index 953b2eb40d8..17d97dc05e2 100644
--- a/source/blender/gpu/intern/gpu_node_graph.c
+++ b/source/blender/gpu/intern/gpu_node_graph.c
@@ -34,6 +34,8 @@
#include "BLI_string.h"
#include "BLI_utildefines.h"
+#include "GPU_texture.h"
+
#include "gpu_material_library.h"
#include "gpu_node_graph.h"
@@ -298,13 +300,14 @@ static GPUMaterialTexture *gpu_node_graph_add_texture(GPUNodeGraph *graph,
Image *ima,
ImageUser *iuser,
struct GPUTexture **colorband,
- GPUNodeLinkType link_type)
+ GPUNodeLinkType link_type,
+ eGPUSamplerState sampler_state)
{
/* Find existing texture. */
int num_textures = 0;
GPUMaterialTexture *tex = graph->textures.first;
for (; tex; tex = tex->next) {
- if (tex->ima == ima && tex->colorband == colorband) {
+ if (tex->ima == ima && tex->colorband == colorband && tex->sampler_state == sampler_state) {
break;
}
num_textures++;
@@ -316,6 +319,7 @@ static GPUMaterialTexture *gpu_node_graph_add_texture(GPUNodeGraph *graph,
tex->ima = ima;
tex->iuser = iuser;
tex->colorband = colorband;
+ tex->sampler_state = sampler_state;
BLI_snprintf(tex->sampler_name, sizeof(tex->sampler_name), "samp%d", num_textures);
if (ELEM(link_type, GPU_NODE_LINK_IMAGE_TILED, GPU_NODE_LINK_IMAGE_TILED_MAPPING)) {
BLI_snprintf(
@@ -389,21 +393,29 @@ GPUNodeLink *GPU_uniform(const float *num)
return link;
}
-GPUNodeLink *GPU_image(GPUMaterial *mat, Image *ima, ImageUser *iuser)
+GPUNodeLink *GPU_image(GPUMaterial *mat,
+ Image *ima,
+ ImageUser *iuser,
+ eGPUSamplerState sampler_state)
{
GPUNodeGraph *graph = gpu_material_node_graph(mat);
GPUNodeLink *link = gpu_node_link_create();
link->link_type = GPU_NODE_LINK_IMAGE;
- link->texture = gpu_node_graph_add_texture(graph, ima, iuser, NULL, link->link_type);
+ link->texture = gpu_node_graph_add_texture(
+ graph, ima, iuser, NULL, link->link_type, sampler_state);
return link;
}
-GPUNodeLink *GPU_image_tiled(GPUMaterial *mat, Image *ima, ImageUser *iuser)
+GPUNodeLink *GPU_image_tiled(GPUMaterial *mat,
+ Image *ima,
+ ImageUser *iuser,
+ eGPUSamplerState sampler_state)
{
GPUNodeGraph *graph = gpu_material_node_graph(mat);
GPUNodeLink *link = gpu_node_link_create();
link->link_type = GPU_NODE_LINK_IMAGE_TILED;
- link->texture = gpu_node_graph_add_texture(graph, ima, iuser, NULL, link->link_type);
+ link->texture = gpu_node_graph_add_texture(
+ graph, ima, iuser, NULL, link->link_type, sampler_state);
return link;
}
@@ -412,7 +424,8 @@ GPUNodeLink *GPU_image_tiled_mapping(GPUMaterial *mat, Image *ima, ImageUser *iu
GPUNodeGraph *graph = gpu_material_node_graph(mat);
GPUNodeLink *link = gpu_node_link_create();
link->link_type = GPU_NODE_LINK_IMAGE_TILED_MAPPING;
- link->texture = gpu_node_graph_add_texture(graph, ima, iuser, NULL, link->link_type);
+ link->texture = gpu_node_graph_add_texture(
+ graph, ima, iuser, NULL, link->link_type, GPU_SAMPLER_MAX);
return link;
}
@@ -424,7 +437,8 @@ GPUNodeLink *GPU_color_band(GPUMaterial *mat, int size, float *pixels, float *ro
GPUNodeGraph *graph = gpu_material_node_graph(mat);
GPUNodeLink *link = gpu_node_link_create();
link->link_type = GPU_NODE_LINK_COLORBAND;
- link->texture = gpu_node_graph_add_texture(graph, NULL, NULL, colorband, link->link_type);
+ link->texture = gpu_node_graph_add_texture(
+ graph, NULL, NULL, colorband, link->link_type, GPU_SAMPLER_MAX);
return link;
}
@@ -645,7 +659,7 @@ void gpu_node_graph_free(GPUNodeGraph *graph)
{
gpu_node_graph_free_nodes(graph);
- for (GPUMaterialVolumeGrid *grid = graph->volume_grids.first; grid; grid = grid->next) {
+ LISTBASE_FOREACH (GPUMaterialVolumeGrid *, grid, &graph->volume_grids) {
MEM_SAFE_FREE(grid->name);
}
BLI_freelistN(&graph->volume_grids);
@@ -679,7 +693,7 @@ static void gpu_nodes_tag(GPUNodeLink *link)
void gpu_node_graph_prune_unused(GPUNodeGraph *graph)
{
- for (GPUNode *node = graph->nodes.first; node; node = node->next) {
+ LISTBASE_FOREACH (GPUNode *, node, &graph->nodes) {
node->tag = false;
}
diff --git a/source/blender/gpu/intern/gpu_select_pick.c b/source/blender/gpu/intern/gpu_select_pick.c
index 56fe1e40d87..4b38cd333a1 100644
--- a/source/blender/gpu/intern/gpu_select_pick.c
+++ b/source/blender/gpu/intern/gpu_select_pick.c
@@ -314,17 +314,10 @@ void gpu_select_pick_begin(uint (*buffer)[4], uint bufsize, const rcti *input, c
glEnable(GL_DEPTH_TEST);
glDepthMask(GL_TRUE);
-
- if (mode == GPU_SELECT_PICK_ALL) {
- /* Note that other depth settings (such as #GL_LEQUAL) work too,
- * since the depth is always cleared.
- * Noting this for cases when depth picking is used where
- * drawing calls change depth settings. */
- glDepthFunc(GL_ALWAYS);
- }
- else {
- glDepthFunc(GL_LEQUAL);
- }
+ /* Always use #GL_LEQUAL even though GPU_SELECT_PICK_ALL always clears the buffer. This is
+ * because individual objects themselves might have sections that overlap and we need these
+ * to have the correct distance information. */
+ glDepthFunc(GL_LEQUAL);
float viewport[4];
glGetFloatv(GL_VIEWPORT, viewport);
@@ -731,8 +724,7 @@ void gpu_select_pick_cache_load_id(void)
#ifdef DEBUG_PRINT
printf("%s (building depth from cache)\n", __func__);
#endif
- for (DepthBufCache *rect_depth = ps->cache.bufs.first; rect_depth;
- rect_depth = rect_depth->next) {
+ LISTBASE_FOREACH (DepthBufCache *, rect_depth, &ps->cache.bufs) {
if (rect_depth->next != NULL) {
/* we know the buffers differ, but this sub-region may not.
* double check before adding an id-pass */
diff --git a/source/blender/gpu/intern/gpu_shader.c b/source/blender/gpu/intern/gpu_shader.c
index c6ffcfa2d86..8c03567b95f 100644
--- a/source/blender/gpu/intern/gpu_shader.c
+++ b/source/blender/gpu/intern/gpu_shader.c
@@ -54,9 +54,6 @@ extern char datatoc_gpu_shader_uniform_color_frag_glsl[];
extern char datatoc_gpu_shader_checker_frag_glsl[];
extern char datatoc_gpu_shader_diag_stripes_frag_glsl[];
extern char datatoc_gpu_shader_simple_lighting_frag_glsl[];
-extern char datatoc_gpu_shader_simple_lighting_flat_color_frag_glsl[];
-extern char datatoc_gpu_shader_simple_lighting_smooth_color_frag_glsl[];
-extern char datatoc_gpu_shader_simple_lighting_smooth_color_alpha_frag_glsl[];
extern char datatoc_gpu_shader_flat_color_frag_glsl[];
extern char datatoc_gpu_shader_flat_color_alpha_test_0_frag_glsl[];
extern char datatoc_gpu_shader_flat_id_frag_glsl[];
@@ -67,7 +64,6 @@ extern char datatoc_gpu_shader_2D_flat_color_vert_glsl[];
extern char datatoc_gpu_shader_2D_smooth_color_uniform_alpha_vert_glsl[];
extern char datatoc_gpu_shader_2D_smooth_color_vert_glsl[];
extern char datatoc_gpu_shader_2D_smooth_color_frag_glsl[];
-extern char datatoc_gpu_shader_2D_smooth_color_dithered_frag_glsl[];
extern char datatoc_gpu_shader_2D_image_vert_glsl[];
extern char datatoc_gpu_shader_2D_image_rect_vert_glsl[];
extern char datatoc_gpu_shader_2D_image_multi_rect_vert_glsl[];
@@ -89,15 +85,13 @@ extern char datatoc_gpu_shader_image_alpha_color_frag_glsl[];
extern char datatoc_gpu_shader_image_shuffle_color_frag_glsl[];
extern char datatoc_gpu_shader_image_mask_uniform_color_frag_glsl[];
extern char datatoc_gpu_shader_image_modulate_alpha_frag_glsl[];
-extern char datatoc_gpu_shader_image_depth_linear_frag_glsl[];
-extern char datatoc_gpu_shader_image_depth_copy_frag_glsl[];
-extern char datatoc_gpu_shader_image_multisample_resolve_frag_glsl[];
extern char datatoc_gpu_shader_3D_vert_glsl[];
extern char datatoc_gpu_shader_3D_normal_vert_glsl[];
extern char datatoc_gpu_shader_3D_flat_color_vert_glsl[];
+extern char datatoc_gpu_shader_3D_polyline_frag_glsl[];
+extern char datatoc_gpu_shader_3D_polyline_geom_glsl[];
+extern char datatoc_gpu_shader_3D_polyline_vert_glsl[];
extern char datatoc_gpu_shader_3D_smooth_color_vert_glsl[];
-extern char datatoc_gpu_shader_3D_normal_flat_color_vert_glsl[];
-extern char datatoc_gpu_shader_3D_normal_smooth_color_vert_glsl[];
extern char datatoc_gpu_shader_3D_smooth_color_frag_glsl[];
extern char datatoc_gpu_shader_3D_passthrough_vert_glsl[];
extern char datatoc_gpu_shader_3D_clipped_uniform_color_vert_glsl[];
@@ -143,21 +137,25 @@ extern char datatoc_gpu_shader_gpencil_fill_vert_glsl[];
extern char datatoc_gpu_shader_gpencil_fill_frag_glsl[];
extern char datatoc_gpu_shader_cfg_world_clip_lib_glsl[];
+extern char datatoc_gpu_shader_colorspace_lib_glsl[];
+
const struct GPUShaderConfigData GPU_shader_cfg_data[GPU_SHADER_CFG_LEN] = {
[GPU_SHADER_CFG_DEFAULT] =
{
.lib = "",
- .def = "",
+ .def = "#define blender_srgb_to_framebuffer_space(a) a\n",
},
[GPU_SHADER_CFG_CLIPPED] =
{
.lib = datatoc_gpu_shader_cfg_world_clip_lib_glsl,
- .def = "#define USE_WORLD_CLIP_PLANES\n",
+ .def = "#define USE_WORLD_CLIP_PLANES\n"
+ "#define blender_srgb_to_framebuffer_space(a) a\n",
},
};
/* cache of built-in shaders (each is created on first use) */
static GPUShader *builtin_shaders[GPU_SHADER_CFG_LEN][GPU_SHADER_BUILTIN_LEN] = {{NULL}};
+static int g_shader_builtin_srgb_transform = 0;
#ifndef NDEBUG
static uint g_shaderid = 0;
@@ -298,6 +296,28 @@ GPUShader *GPU_shader_create(const char *vertexcode,
vertexcode, fragcode, geocode, libcode, defines, GPU_SHADER_TFB_NONE, NULL, 0, shname);
}
+GPUShader *GPU_shader_create_from_python(const char *vertexcode,
+ const char *fragcode,
+ const char *geocode,
+ const char *libcode,
+ const char *defines)
+{
+ char *libcodecat = NULL;
+
+ if (libcode == NULL) {
+ libcode = datatoc_gpu_shader_colorspace_lib_glsl;
+ }
+ else {
+ libcode = libcodecat = BLI_strdupcat(libcode, datatoc_gpu_shader_colorspace_lib_glsl);
+ }
+
+ GPUShader *sh = GPU_shader_create_ex(
+ vertexcode, fragcode, geocode, libcode, defines, GPU_SHADER_TFB_NONE, NULL, 0, NULL);
+
+ MEM_SAFE_FREE(libcodecat);
+ return sh;
+}
+
GPUShader *GPU_shader_load_from_binary(const char *binary,
const int binary_format,
const int binary_len,
@@ -311,6 +331,8 @@ GPUShader *GPU_shader_load_from_binary(const char *binary,
glGetProgramiv(program, GL_LINK_STATUS, &success);
if (success) {
+ glUseProgram(program);
+
GPUShader *shader = MEM_callocN(sizeof(*shader), __func__);
shader->interface = GPU_shaderinterface_create(program);
shader->program = program;
@@ -552,6 +574,7 @@ GPUShader *GPU_shader_create_ex(const char *vertexcode,
return NULL;
}
+ glUseProgram(shader->program);
shader->interface = GPU_shaderinterface_create(shader->program);
return shader;
@@ -638,6 +661,7 @@ void GPU_shader_bind(GPUShader *shader)
glUseProgram(shader->program);
GPU_matrix_bind(shader->interface);
+ GPU_shader_set_srgb_uniform(shader->interface);
}
void GPU_shader_unbind(void)
@@ -705,21 +729,19 @@ int GPU_shader_get_uniform(GPUShader *shader, const char *name)
{
BLI_assert(shader && shader->program);
const GPUShaderInput *uniform = GPU_shaderinterface_uniform(shader->interface, name);
- return uniform ? uniform->location : -2;
+ return uniform ? uniform->location : -1;
}
-int GPU_shader_get_uniform_ensure(GPUShader *shader, const char *name)
+int GPU_shader_get_builtin_uniform(GPUShader *shader, int builtin)
{
BLI_assert(shader && shader->program);
- const GPUShaderInput *uniform = GPU_shaderinterface_uniform_ensure(shader->interface, name);
- return uniform ? uniform->location : -1;
+ return GPU_shaderinterface_uniform_builtin(shader->interface, builtin);
}
-int GPU_shader_get_builtin_uniform(GPUShader *shader, int builtin)
+int GPU_shader_get_builtin_block(GPUShader *shader, int builtin)
{
BLI_assert(shader && shader->program);
- const GPUShaderInput *uniform = GPU_shaderinterface_uniform_builtin(shader->interface, builtin);
- return uniform ? uniform->location : -1;
+ return GPU_shaderinterface_block_builtin(shader->interface, builtin);
}
int GPU_shader_get_uniform_block(GPUShader *shader, const char *name)
@@ -729,6 +751,20 @@ int GPU_shader_get_uniform_block(GPUShader *shader, const char *name)
return ubo ? ubo->location : -1;
}
+int GPU_shader_get_uniform_block_binding(GPUShader *shader, const char *name)
+{
+ BLI_assert(shader && shader->program);
+ const GPUShaderInput *ubo = GPU_shaderinterface_ubo(shader->interface, name);
+ return ubo ? ubo->binding : -1;
+}
+
+int GPU_shader_get_texture_binding(GPUShader *shader, const char *name)
+{
+ BLI_assert(shader && shader->program);
+ const GPUShaderInput *tex = GPU_shaderinterface_uniform(shader->interface, name);
+ return tex ? tex->binding : -1;
+}
+
void *GPU_shader_get_interface(GPUShader *shader)
{
return shader->interface;
@@ -816,32 +852,12 @@ void GPU_shader_uniform_int(GPUShader *UNUSED(shader), int location, int value)
glUniform1i(location, value);
}
-void GPU_shader_uniform_buffer(GPUShader *shader, int location, GPUUniformBuffer *ubo)
+void GPU_shader_set_srgb_uniform(const GPUShaderInterface *interface)
{
- int bindpoint = GPU_uniformbuffer_bindpoint(ubo);
-
- if (location == -1) {
- return;
+ int32_t loc = GPU_shaderinterface_uniform_builtin(interface, GPU_UNIFORM_SRGB_TRANSFORM);
+ if (loc != -1) {
+ glUniform1i(loc, g_shader_builtin_srgb_transform);
}
-
- glUniformBlockBinding(shader->program, location, bindpoint);
-}
-
-void GPU_shader_uniform_texture(GPUShader *UNUSED(shader), int location, GPUTexture *tex)
-{
- int number = GPU_texture_bound_number(tex);
-
- if (number == -1) {
- fprintf(stderr, "Texture is not bound.\n");
- BLI_assert(0);
- return;
- }
-
- if (location == -1) {
- return;
- }
-
- glUniform1i(location, number);
}
int GPU_shader_get_attribute(GPUShader *shader, const char *name)
@@ -868,6 +884,11 @@ char *GPU_shader_get_binary(GPUShader *shader, uint *r_binary_format, int *r_bin
return r_binary;
}
+void GPU_shader_set_framebuffer_srgb_target(int use_srgb_to_linear)
+{
+ g_shader_builtin_srgb_transform = use_srgb_to_linear;
+}
+
static const GPUShaderStages builtin_shader_stages[GPU_SHADER_BUILTIN_LEN] = {
[GPU_SHADER_TEXT] =
{
@@ -884,23 +905,6 @@ static const GPUShaderStages builtin_shader_stages[GPU_SHADER_BUILTIN_LEN] = {
.vert = datatoc_gpu_shader_3D_normal_vert_glsl,
.frag = datatoc_gpu_shader_simple_lighting_frag_glsl,
},
- /* Use 'USE_FLAT_NORMAL' to make flat shader from smooth */
- [GPU_SHADER_SIMPLE_LIGHTING_FLAT_COLOR] =
- {
- .vert = datatoc_gpu_shader_3D_normal_smooth_color_vert_glsl,
- .frag = datatoc_gpu_shader_simple_lighting_smooth_color_frag_glsl,
- .defs = "#define USE_FLAT_NORMAL\n",
- },
- [GPU_SHADER_SIMPLE_LIGHTING_SMOOTH_COLOR] =
- {
- .vert = datatoc_gpu_shader_3D_normal_smooth_color_vert_glsl,
- .frag = datatoc_gpu_shader_simple_lighting_smooth_color_frag_glsl,
- },
- [GPU_SHADER_SIMPLE_LIGHTING_SMOOTH_COLOR_ALPHA] =
- {
- .vert = datatoc_gpu_shader_3D_normal_smooth_color_vert_glsl,
- .frag = datatoc_gpu_shader_simple_lighting_smooth_color_alpha_frag_glsl,
- },
[GPU_SHADER_2D_IMAGE_MASK_UNIFORM_COLOR] =
{
@@ -912,69 +916,6 @@ static const GPUShaderStages builtin_shader_stages[GPU_SHADER_BUILTIN_LEN] = {
.vert = datatoc_gpu_shader_3D_image_vert_glsl,
.frag = datatoc_gpu_shader_image_modulate_alpha_frag_glsl,
},
- [GPU_SHADER_3D_IMAGE_DEPTH] =
- {
- .vert = datatoc_gpu_shader_3D_image_vert_glsl,
- .frag = datatoc_gpu_shader_image_depth_linear_frag_glsl,
- },
- [GPU_SHADER_3D_IMAGE_DEPTH_COPY] =
- {
- .vert = datatoc_gpu_shader_3D_image_vert_glsl,
- .frag = datatoc_gpu_shader_image_depth_copy_frag_glsl,
- },
- [GPU_SHADER_2D_IMAGE_MULTISAMPLE_2] =
- {
- .vert = datatoc_gpu_shader_2D_vert_glsl,
- .frag = datatoc_gpu_shader_image_multisample_resolve_frag_glsl,
- .defs = "#define SAMPLES 2\n",
- },
- [GPU_SHADER_2D_IMAGE_MULTISAMPLE_4] =
- {
- .vert = datatoc_gpu_shader_2D_vert_glsl,
- .frag = datatoc_gpu_shader_image_multisample_resolve_frag_glsl,
- .defs = "#define SAMPLES 4\n",
- },
- [GPU_SHADER_2D_IMAGE_MULTISAMPLE_8] =
- {
- .vert = datatoc_gpu_shader_2D_vert_glsl,
- .frag = datatoc_gpu_shader_image_multisample_resolve_frag_glsl,
- .defs = "#define SAMPLES 8\n",
- },
- [GPU_SHADER_2D_IMAGE_MULTISAMPLE_16] =
- {
- .vert = datatoc_gpu_shader_2D_vert_glsl,
- .frag = datatoc_gpu_shader_image_multisample_resolve_frag_glsl,
- .defs = "#define SAMPLES 16\n",
- },
- [GPU_SHADER_2D_IMAGE_MULTISAMPLE_2_DEPTH_TEST] =
- {
- .vert = datatoc_gpu_shader_2D_vert_glsl,
- .frag = datatoc_gpu_shader_image_multisample_resolve_frag_glsl,
- .defs = "#define SAMPLES 2\n"
- "#define USE_DEPTH\n",
- },
- [GPU_SHADER_2D_IMAGE_MULTISAMPLE_4_DEPTH_TEST] =
- {
- .vert = datatoc_gpu_shader_2D_vert_glsl,
- .frag = datatoc_gpu_shader_image_multisample_resolve_frag_glsl,
- .defs = "#define SAMPLES 4\n"
- "#define USE_DEPTH\n",
- },
- [GPU_SHADER_2D_IMAGE_MULTISAMPLE_8_DEPTH_TEST] =
- {
- .vert = datatoc_gpu_shader_2D_vert_glsl,
- .frag = datatoc_gpu_shader_image_multisample_resolve_frag_glsl,
- .defs = "#define SAMPLES 8\n"
- "#define USE_DEPTH\n",
- },
- [GPU_SHADER_2D_IMAGE_MULTISAMPLE_16_DEPTH_TEST] =
- {
- .vert = datatoc_gpu_shader_2D_vert_glsl,
- .frag = datatoc_gpu_shader_image_multisample_resolve_frag_glsl,
- .defs = "#define SAMPLES 16\n"
- "#define USE_DEPTH\n",
- },
-
[GPU_SHADER_2D_CHECKER] =
{
.vert = datatoc_gpu_shader_2D_vert_glsl,
@@ -1002,11 +943,6 @@ static const GPUShaderStages builtin_shader_stages[GPU_SHADER_BUILTIN_LEN] = {
.vert = datatoc_gpu_shader_2D_smooth_color_vert_glsl,
.frag = datatoc_gpu_shader_2D_smooth_color_frag_glsl,
},
- [GPU_SHADER_2D_SMOOTH_COLOR_DITHER] =
- {
- .vert = datatoc_gpu_shader_2D_smooth_color_vert_glsl,
- .frag = datatoc_gpu_shader_2D_smooth_color_dithered_frag_glsl,
- },
[GPU_SHADER_2D_IMAGE_OVERLAYS_MERGE] =
{
.vert = datatoc_gpu_shader_2D_image_vert_glsl,
@@ -1058,12 +994,6 @@ static const GPUShaderStages builtin_shader_stages[GPU_SHADER_BUILTIN_LEN] = {
.vert = datatoc_gpu_shader_3D_vert_glsl,
.frag = datatoc_gpu_shader_uniform_color_frag_glsl,
},
- [GPU_SHADER_3D_UNIFORM_COLOR_BACKGROUND] =
- {
- .vert = datatoc_gpu_shader_3D_vert_glsl,
- .frag = datatoc_gpu_shader_uniform_color_frag_glsl,
- .defs = "#define USE_BACKGROUND\n",
- },
[GPU_SHADER_3D_FLAT_COLOR] =
{
.vert = datatoc_gpu_shader_3D_flat_color_vert_glsl,
@@ -1085,6 +1015,36 @@ static const GPUShaderStages builtin_shader_stages[GPU_SHADER_BUILTIN_LEN] = {
.frag = datatoc_gpu_shader_uniform_color_frag_glsl,
},
+ [GPU_SHADER_3D_POLYLINE_UNIFORM_COLOR] =
+ {
+ .vert = datatoc_gpu_shader_3D_polyline_vert_glsl,
+ .geom = datatoc_gpu_shader_3D_polyline_geom_glsl,
+ .frag = datatoc_gpu_shader_3D_polyline_frag_glsl,
+ .defs = "#define UNIFORM\n",
+ },
+ [GPU_SHADER_3D_POLYLINE_CLIPPED_UNIFORM_COLOR] =
+ {
+ .vert = datatoc_gpu_shader_3D_polyline_vert_glsl,
+ .geom = datatoc_gpu_shader_3D_polyline_geom_glsl,
+ .frag = datatoc_gpu_shader_3D_polyline_frag_glsl,
+ .defs = "#define UNIFORM\n"
+ "#define CLIP\n",
+ },
+ [GPU_SHADER_3D_POLYLINE_FLAT_COLOR] =
+ {
+ .vert = datatoc_gpu_shader_3D_polyline_vert_glsl,
+ .geom = datatoc_gpu_shader_3D_polyline_geom_glsl,
+ .frag = datatoc_gpu_shader_3D_polyline_frag_glsl,
+ .defs = "#define FLAT\n",
+ },
+ [GPU_SHADER_3D_POLYLINE_SMOOTH_COLOR] =
+ {
+ .vert = datatoc_gpu_shader_3D_polyline_vert_glsl,
+ .geom = datatoc_gpu_shader_3D_polyline_geom_glsl,
+ .frag = datatoc_gpu_shader_3D_polyline_frag_glsl,
+ .defs = "#define SMOOTH\n",
+ },
+
[GPU_SHADER_2D_LINE_DASHED_UNIFORM_COLOR] =
{
.vert = datatoc_gpu_shader_2D_line_dashed_uniform_color_vert_glsl,
@@ -1262,8 +1222,12 @@ GPUShader *GPU_shader_get_builtin_shader_with_config(eGPUBuiltinShader shader,
/* common case */
if (sh_cfg == GPU_SHADER_CFG_DEFAULT) {
- *sh_p = GPU_shader_create(
- stages->vert, stages->frag, stages->geom, NULL, stages->defs, __func__);
+ *sh_p = GPU_shader_create_from_arrays({
+ .vert = (const char *[]){stages->vert, NULL},
+ .geom = (const char *[]){stages->geom, NULL},
+ .frag = (const char *[]){datatoc_gpu_shader_colorspace_lib_glsl, stages->frag, NULL},
+ .defs = (const char *[]){stages->defs, NULL},
+ });
}
else if (sh_cfg == GPU_SHADER_CFG_CLIPPED) {
/* Remove eventually, for now ensure support for each shader has been added. */
@@ -1282,7 +1246,7 @@ GPUShader *GPU_shader_get_builtin_shader_with_config(eGPUBuiltinShader shader,
*sh_p = GPU_shader_create_from_arrays({
.vert = (const char *[]){world_clip_lib, stages->vert, NULL},
.geom = (const char *[]){stages->geom ? world_clip_lib : NULL, stages->geom, NULL},
- .frag = (const char *[]){stages->frag, NULL},
+ .frag = (const char *[]){datatoc_gpu_shader_colorspace_lib_glsl, stages->frag, NULL},
.defs = (const char *[]){world_clip_def, stages->defs, NULL},
});
}
diff --git a/source/blender/gpu/intern/gpu_shader_interface.c b/source/blender/gpu/intern/gpu_shader_interface.c
index f23a0a438d6..9d9f98c6bb0 100644
--- a/source/blender/gpu/intern/gpu_shader_interface.c
+++ b/source/blender/gpu/intern/gpu_shader_interface.c
@@ -24,6 +24,10 @@
*/
#include "BKE_global.h"
+
+#include "BLI_bitmap.h"
+#include "BLI_math_base.h"
+
#include "MEM_guardedalloc.h"
#include "GPU_shader_interface.h"
@@ -36,7 +40,6 @@
#include <string.h>
#define DEBUG_SHADER_INTERFACE 0
-#define DEBUG_SHADER_UNIFORMS 0
#if DEBUG_SHADER_INTERFACE
# include <stdio.h>
@@ -45,8 +48,6 @@
static const char *BuiltinUniform_name(GPUUniformBuiltin u)
{
static const char *names[] = {
- [GPU_UNIFORM_NONE] = NULL,
-
[GPU_UNIFORM_MODEL] = "ModelMatrix",
[GPU_UNIFORM_VIEW] = "ViewMatrix",
[GPU_UNIFORM_MODELVIEW] = "ModelViewMatrix",
@@ -68,14 +69,27 @@ static const char *BuiltinUniform_name(GPUUniformBuiltin u)
[GPU_UNIFORM_BASE_INSTANCE] = "baseInstance",
[GPU_UNIFORM_RESOURCE_CHUNK] = "resourceChunk",
[GPU_UNIFORM_RESOURCE_ID] = "resourceId",
+ [GPU_UNIFORM_SRGB_TRANSFORM] = "srgbTarget",
- [GPU_UNIFORM_CUSTOM] = NULL,
[GPU_NUM_UNIFORMS] = NULL,
};
return names[u];
}
+static const char *BuiltinUniformBlock_name(GPUUniformBlockBuiltin u)
+{
+ static const char *names[] = {
+ [GPU_UNIFORM_BLOCK_VIEW] = "viewBlock",
+ [GPU_UNIFORM_BLOCK_MODEL] = "modelBlock",
+ [GPU_UNIFORM_BLOCK_INFO] = "infoBlock",
+
+ [GPU_NUM_UNIFORM_BLOCKS] = NULL,
+ };
+
+ return names[u];
+}
+
GPU_INLINE bool match(const char *a, const char *b)
{
return strcmp(a, b) == 0;
@@ -90,129 +104,136 @@ GPU_INLINE uint hash_string(const char *str)
return i;
}
-GPU_INLINE void set_input_name(GPUShaderInterface *shaderface,
- GPUShaderInput *input,
- const char *name,
- uint32_t name_len)
+GPU_INLINE uint32_t set_input_name(GPUShaderInterface *shaderface,
+ GPUShaderInput *input,
+ char *name,
+ uint32_t name_len)
{
- input->name_offset = shaderface->name_buffer_offset;
- input->name_hash = hash_string(name);
- shaderface->name_buffer_offset += name_len + 1; /* include NULL terminator */
-}
+ /* remove "[0]" from array name */
+ if (name[name_len - 1] == ']') {
+ name[name_len - 3] = '\0';
+ name_len -= 3;
+ }
-GPU_INLINE void shader_input_to_bucket(GPUShaderInput *input,
- GPUShaderInput *buckets[GPU_NUM_SHADERINTERFACE_BUCKETS])
-{
- const uint bucket_index = input->name_hash % GPU_NUM_SHADERINTERFACE_BUCKETS;
- input->next = buckets[bucket_index];
- buckets[bucket_index] = input;
+ input->name_offset = (uint32_t)(name - shaderface->name_buffer);
+ input->name_hash = hash_string(name);
+ return name_len + 1; /* include NULL terminator */
}
-GPU_INLINE const GPUShaderInput *buckets_lookup(
- GPUShaderInput *const buckets[GPU_NUM_SHADERINTERFACE_BUCKETS],
- const char *name_buffer,
- const char *name)
+GPU_INLINE const GPUShaderInput *input_lookup(const GPUShaderInterface *shaderface,
+ const GPUShaderInput *const inputs,
+ const uint inputs_len,
+ const char *name)
{
const uint name_hash = hash_string(name);
- const uint bucket_index = name_hash % GPU_NUM_SHADERINTERFACE_BUCKETS;
- const GPUShaderInput *input = buckets[bucket_index];
- if (input == NULL) {
- /* Requested uniform is not found at all. */
- return NULL;
- }
- /* Optimization bit: if there is no hash collision detected when constructing shader interface
- * it means we can only request the single possible uniform. Surely, it's possible we request
- * uniform which causes hash collision, but that will be detected in debug builds. */
- if (input->next == NULL) {
- if (name_hash == input->name_hash) {
-#if TRUST_NO_ONE
- assert(match(name_buffer + input->name_offset, name));
-#endif
- return input;
- }
- return NULL;
- }
- /* Work through possible collisions. */
- const GPUShaderInput *next = input;
- while (next != NULL) {
- input = next;
- next = input->next;
- if (input->name_hash != name_hash) {
- continue;
- }
- if (match(name_buffer + input->name_offset, name)) {
- return input;
+ /* Simple linear search for now. */
+ for (int i = inputs_len - 1; i >= 0; i--) {
+ if (inputs[i].name_hash == name_hash) {
+ if ((i > 0) && UNLIKELY(inputs[i - 1].name_hash == name_hash)) {
+ /* Hash colision resolve. */
+ for (; i >= 0 && inputs[i].name_hash == name_hash; i--) {
+ if (match(name, shaderface->name_buffer + inputs[i].name_offset)) {
+ return inputs + i; /* not found */
+ }
+ }
+ return NULL; /* not found */
+ }
+ else {
+ /* This is a bit dangerous since we could have a hash collision.
+ * where the asked uniform that does not exist has the same hash
+ * as a real uniform. */
+ BLI_assert(match(name, shaderface->name_buffer + inputs[i].name_offset));
+ return inputs + i;
+ }
}
}
return NULL; /* not found */
}
-GPU_INLINE void buckets_free(GPUShaderInput *buckets[GPU_NUM_SHADERINTERFACE_BUCKETS])
+/* Note that this modify the src array. */
+GPU_INLINE void sort_input_list(GPUShaderInput *dst, GPUShaderInput *src, const uint input_len)
{
- for (uint bucket_index = 0; bucket_index < GPU_NUM_SHADERINTERFACE_BUCKETS; bucket_index++) {
- GPUShaderInput *input = buckets[bucket_index];
- while (input != NULL) {
- GPUShaderInput *input_next = input->next;
- MEM_freeN(input);
- input = input_next;
+ for (uint i = 0; i < input_len; i++) {
+ GPUShaderInput *input_src = &src[0];
+ for (uint j = 1; j < input_len; j++) {
+ if (src[j].name_hash > input_src->name_hash) {
+ input_src = &src[j];
+ }
}
+ dst[i] = *input_src;
+ input_src->name_hash = 0;
}
}
-static bool setup_builtin_uniform(GPUShaderInput *input, const char *name)
+static int block_binding(int32_t program, uint32_t block_index)
{
- /* TODO: reject DOUBLE, IMAGE, ATOMIC_COUNTER gl_types */
-
- /* detect built-in uniforms (name must match) */
- for (GPUUniformBuiltin u = GPU_UNIFORM_NONE + 1; u < GPU_UNIFORM_CUSTOM; u++) {
- const char *builtin_name = BuiltinUniform_name(u);
- if (match(name, builtin_name)) {
- input->builtin_type = u;
- return true;
- }
- }
- input->builtin_type = GPU_UNIFORM_CUSTOM;
- return false;
+ /* For now just assign a consecutive index. In the future, we should set it in
+ * the shader using layout(binding = i) and query its value. */
+ glUniformBlockBinding(program, block_index, block_index);
+ return block_index;
}
-static const GPUShaderInput *add_uniform(GPUShaderInterface *shaderface, const char *name)
+static int sampler_binding(int32_t program,
+ uint32_t uniform_index,
+ int32_t uniform_location,
+ int *sampler_len)
{
- GPUShaderInput *input = MEM_mallocN(sizeof(GPUShaderInput), "GPUShaderInput Unif");
-
- input->location = glGetUniformLocation(shaderface->program, name);
-
- const uint name_len = strlen(name);
- /* Include NULL terminator. */
- shaderface->name_buffer = MEM_reallocN(shaderface->name_buffer,
- shaderface->name_buffer_offset + name_len + 1);
- char *name_buffer = shaderface->name_buffer + shaderface->name_buffer_offset;
- strcpy(name_buffer, name);
-
- set_input_name(shaderface, input, name, name_len);
- setup_builtin_uniform(input, name);
-
- shader_input_to_bucket(input, shaderface->uniform_buckets);
- if (input->builtin_type != GPU_UNIFORM_NONE && input->builtin_type != GPU_UNIFORM_CUSTOM) {
- shaderface->builtin_uniforms[input->builtin_type] = input;
+ /* Identify sampler uniforms and asign sampler units to them. */
+ GLint type;
+ glGetActiveUniformsiv(program, 1, &uniform_index, GL_UNIFORM_TYPE, &type);
+
+ switch (type) {
+ case GL_SAMPLER_1D:
+ case GL_SAMPLER_2D:
+ case GL_SAMPLER_3D:
+ case GL_SAMPLER_CUBE:
+ case GL_SAMPLER_CUBE_MAP_ARRAY_ARB: /* OpenGL 4.0 */
+ case GL_SAMPLER_1D_SHADOW:
+ case GL_SAMPLER_2D_SHADOW:
+ case GL_SAMPLER_1D_ARRAY:
+ case GL_SAMPLER_2D_ARRAY:
+ case GL_SAMPLER_1D_ARRAY_SHADOW:
+ case GL_SAMPLER_2D_ARRAY_SHADOW:
+ case GL_SAMPLER_2D_MULTISAMPLE:
+ case GL_SAMPLER_2D_MULTISAMPLE_ARRAY:
+ case GL_SAMPLER_CUBE_SHADOW:
+ case GL_SAMPLER_BUFFER:
+ case GL_INT_SAMPLER_1D:
+ case GL_INT_SAMPLER_2D:
+ case GL_INT_SAMPLER_3D:
+ case GL_INT_SAMPLER_CUBE:
+ case GL_INT_SAMPLER_1D_ARRAY:
+ case GL_INT_SAMPLER_2D_ARRAY:
+ case GL_INT_SAMPLER_2D_MULTISAMPLE:
+ case GL_INT_SAMPLER_2D_MULTISAMPLE_ARRAY:
+ case GL_INT_SAMPLER_BUFFER:
+ case GL_UNSIGNED_INT_SAMPLER_1D:
+ case GL_UNSIGNED_INT_SAMPLER_2D:
+ case GL_UNSIGNED_INT_SAMPLER_3D:
+ case GL_UNSIGNED_INT_SAMPLER_CUBE:
+ case GL_UNSIGNED_INT_SAMPLER_1D_ARRAY:
+ case GL_UNSIGNED_INT_SAMPLER_2D_ARRAY:
+ case GL_UNSIGNED_INT_SAMPLER_2D_MULTISAMPLE:
+ case GL_UNSIGNED_INT_SAMPLER_2D_MULTISAMPLE_ARRAY:
+ case GL_UNSIGNED_INT_SAMPLER_BUFFER: {
+ /* For now just assign a consecutive index. In the future, we should set it in
+ * the shader using layout(binding = i) and query its value. */
+ int binding = *sampler_len;
+ glUniform1i(uniform_location, binding);
+ (*sampler_len)++;
+ return binding;
+ }
+ default:
+ return -1;
}
-#if DEBUG_SHADER_INTERFACE
- printf("GPUShaderInterface %p, program %d, uniform[] '%s' at location %d\n",
- shaderface,
- shaderface->program,
- name,
- input->location);
-#endif
- return input;
}
GPUShaderInterface *GPU_shaderinterface_create(int32_t program)
{
- GPUShaderInterface *shaderface = MEM_callocN(sizeof(GPUShaderInterface), "GPUShaderInterface");
- shaderface->program = program;
-
-#if DEBUG_SHADER_INTERFACE
- printf("%s {\n", __func__); /* enter function */
- printf("GPUShaderInterface %p, program %d\n", shaderface, program);
+#ifndef NDEBUG
+ GLint curr_program;
+ glGetIntegerv(GL_CURRENT_PROGRAM, &curr_program);
+ BLI_assert(curr_program == program);
#endif
GLint max_attr_name_len = 0, attr_len = 0;
@@ -223,6 +244,11 @@ GPUShaderInterface *GPU_shaderinterface_create(int32_t program)
glGetProgramiv(program, GL_ACTIVE_UNIFORM_BLOCK_MAX_NAME_LENGTH, &max_ubo_name_len);
glGetProgramiv(program, GL_ACTIVE_UNIFORM_BLOCKS, &ubo_len);
+ GLint max_uniform_name_len = 0, active_uniform_len = 0, uniform_len = 0;
+ glGetProgramiv(program, GL_ACTIVE_UNIFORM_MAX_LENGTH, &max_uniform_name_len);
+ glGetProgramiv(program, GL_ACTIVE_UNIFORMS, &active_uniform_len);
+ uniform_len = active_uniform_len;
+
/* Work around driver bug with Intel HD 4600 on Windows 7/8, where
* GL_ACTIVE_UNIFORM_BLOCK_MAX_NAME_LENGTH does not work. */
if (attr_len > 0 && max_attr_name_len == 0) {
@@ -231,78 +257,190 @@ GPUShaderInterface *GPU_shaderinterface_create(int32_t program)
if (ubo_len > 0 && max_ubo_name_len == 0) {
max_ubo_name_len = 256;
}
+ if (uniform_len > 0 && max_uniform_name_len == 0) {
+ max_uniform_name_len = 256;
+ }
- const uint32_t name_buffer_len = attr_len * max_attr_name_len + ubo_len * max_ubo_name_len;
- shaderface->name_buffer = MEM_mallocN(name_buffer_len, "name_buffer");
-
- /* Attributes */
- for (uint32_t i = 0; i < attr_len; i++) {
- GPUShaderInput *input = MEM_mallocN(sizeof(GPUShaderInput), "GPUShaderInput Attr");
- GLsizei remaining_buffer = name_buffer_len - shaderface->name_buffer_offset;
- char *name = shaderface->name_buffer + shaderface->name_buffer_offset;
- GLsizei name_len = 0;
+ /* GL_ACTIVE_UNIFORMS lied to us! Remove the UBO uniforms from the total before
+ * allocating the uniform array. */
+ GLint max_ubo_uni_len = 0;
+ for (int i = 0; i < ubo_len; i++) {
+ GLint ubo_uni_len;
+ glGetActiveUniformBlockiv(program, i, GL_UNIFORM_BLOCK_ACTIVE_UNIFORMS, &ubo_uni_len);
+ max_ubo_uni_len = max_ii(max_ubo_uni_len, ubo_uni_len);
+ uniform_len -= ubo_uni_len;
+ }
+ /* Bit set to true if uniform comes from a uniform block. */
+ BLI_bitmap *uniforms_from_blocks = BLI_BITMAP_NEW(active_uniform_len, __func__);
+ /* Set uniforms from block for exclusion. */
+ GLint *ubo_uni_ids = MEM_mallocN(sizeof(GLint) * max_ubo_uni_len, __func__);
+ for (int i = 0; i < ubo_len; i++) {
+ GLint ubo_uni_len;
+ glGetActiveUniformBlockiv(program, i, GL_UNIFORM_BLOCK_ACTIVE_UNIFORMS, &ubo_uni_len);
+ glGetActiveUniformBlockiv(program, i, GL_UNIFORM_BLOCK_ACTIVE_UNIFORM_INDICES, ubo_uni_ids);
+ for (int u = 0; u < ubo_uni_len; u++) {
+ BLI_BITMAP_ENABLE(uniforms_from_blocks, ubo_uni_ids[u]);
+ }
+ }
+ MEM_freeN(ubo_uni_ids);
- glGetActiveAttrib(
- program, i, remaining_buffer, &name_len, &input->size, &input->gl_type, name);
+ uint32_t name_buffer_offset = 0;
+ const uint32_t name_buffer_len = attr_len * max_attr_name_len + ubo_len * max_ubo_name_len +
+ uniform_len * max_uniform_name_len;
- /* remove "[0]" from array name */
- if (name[name_len - 1] == ']') {
- name[name_len - 3] = '\0';
- name_len -= 3;
- }
+ int input_tot_len = attr_len + ubo_len + uniform_len;
+ size_t interface_size = sizeof(GPUShaderInterface) + sizeof(GPUShaderInput) * input_tot_len;
- /* TODO: reject DOUBLE gl_types */
+ GPUShaderInterface *shaderface = MEM_callocN(interface_size, "GPUShaderInterface");
+ shaderface->attribute_len = attr_len;
+ shaderface->ubo_len = ubo_len;
+ shaderface->uniform_len = uniform_len;
+ shaderface->name_buffer = MEM_mallocN(name_buffer_len, "name_buffer");
+ GPUShaderInput *inputs = shaderface->inputs;
- input->location = glGetAttribLocation(program, name);
+ /* Temp buffer. */
+ int input_tmp_len = max_iii(attr_len, ubo_len, uniform_len);
+ GPUShaderInput *inputs_tmp = MEM_mallocN(sizeof(GPUShaderInput) * input_tmp_len, "name_buffer");
- set_input_name(shaderface, input, name, name_len);
+ /* Attributes */
+ shaderface->enabled_attr_mask = 0;
+ for (int i = 0, idx = 0; i < attr_len; i++) {
+ char *name = shaderface->name_buffer + name_buffer_offset;
+ GLsizei remaining_buffer = name_buffer_len - name_buffer_offset;
+ GLsizei name_len = 0;
+ GLenum type;
+ GLint size;
+
+ glGetActiveAttrib(program, i, remaining_buffer, &name_len, &size, &type, name);
+ GLint location = glGetAttribLocation(program, name);
+ /* Ignore OpenGL names like `gl_BaseInstanceARB`, `gl_InstanceID` and `gl_VertexID`. */
+ if (location == -1) {
+ shaderface->attribute_len--;
+ continue;
+ }
- shader_input_to_bucket(input, shaderface->attr_buckets);
+ GPUShaderInput *input = &inputs_tmp[idx++];
+ input->location = input->binding = location;
-#if DEBUG_SHADER_INTERFACE
- printf("attr[%u] '%s' at location %d\n", i, name, input->location);
-#endif
+ name_buffer_offset += set_input_name(shaderface, input, name, name_len);
+ shaderface->enabled_attr_mask |= (1 << input->location);
}
+ sort_input_list(inputs, inputs_tmp, shaderface->attribute_len);
+ inputs += shaderface->attribute_len;
+
/* Uniform Blocks */
- for (uint32_t i = 0; i < ubo_len; i++) {
- GPUShaderInput *input = MEM_mallocN(sizeof(GPUShaderInput), "GPUShaderInput UBO");
- GLsizei remaining_buffer = name_buffer_len - shaderface->name_buffer_offset;
- char *name = shaderface->name_buffer + shaderface->name_buffer_offset;
+ for (int i = 0, idx = 0; i < ubo_len; i++) {
+ char *name = shaderface->name_buffer + name_buffer_offset;
+ GLsizei remaining_buffer = name_buffer_len - name_buffer_offset;
GLsizei name_len = 0;
glGetActiveUniformBlockName(program, i, remaining_buffer, &name_len, name);
- input->location = i;
+ GPUShaderInput *input = &inputs_tmp[idx++];
+ input->binding = input->location = block_binding(program, i);
- set_input_name(shaderface, input, name, name_len);
+ name_buffer_offset += set_input_name(shaderface, input, name, name_len);
+ shaderface->enabled_ubo_mask |= (1 << input->binding);
+ }
+ sort_input_list(inputs, inputs_tmp, shaderface->ubo_len);
+ inputs += shaderface->ubo_len;
- shader_input_to_bucket(input, shaderface->ubo_buckets);
+ /* Uniforms */
+ for (int i = 0, idx = 0, sampler = 0; i < active_uniform_len; i++) {
+ if (BLI_BITMAP_TEST(uniforms_from_blocks, i)) {
+ continue;
+ }
+ char *name = shaderface->name_buffer + name_buffer_offset;
+ GLsizei remaining_buffer = name_buffer_len - name_buffer_offset;
+ GLsizei name_len = 0;
-#if DEBUG_SHADER_INTERFACE
- printf("ubo '%s' at location %d\n", name, input->location);
-#endif
+ glGetActiveUniformName(program, i, remaining_buffer, &name_len, name);
+
+ GPUShaderInput *input = &inputs_tmp[idx++];
+ input->location = glGetUniformLocation(program, name);
+ input->binding = sampler_binding(program, i, input->location, &sampler);
+
+ name_buffer_offset += set_input_name(shaderface, input, name, name_len);
+ shaderface->enabled_tex_mask |= (input->binding != -1) ? (1lu << input->binding) : 0lu;
}
+ sort_input_list(inputs, inputs_tmp, shaderface->uniform_len);
+
/* Builtin Uniforms */
- for (GPUUniformBuiltin u = GPU_UNIFORM_NONE + 1; u < GPU_UNIFORM_CUSTOM; u++) {
- const char *builtin_name = BuiltinUniform_name(u);
- if (glGetUniformLocation(program, builtin_name) != -1) {
- add_uniform((GPUShaderInterface *)shaderface, builtin_name);
- }
+ for (GPUUniformBuiltin u = 0; u < GPU_NUM_UNIFORMS; u++) {
+ shaderface->builtins[u] = glGetUniformLocation(program, BuiltinUniform_name(u));
}
+
+ /* Builtin Uniforms Blocks */
+ for (GPUUniformBlockBuiltin u = 0; u < GPU_NUM_UNIFORM_BLOCKS; u++) {
+ const GPUShaderInput *block = GPU_shaderinterface_ubo(shaderface, BuiltinUniformBlock_name(u));
+ shaderface->builtin_blocks[u] = (block != NULL) ? block->binding : -1;
+ }
+
/* Batches ref buffer */
shaderface->batches_len = GPU_SHADERINTERFACE_REF_ALLOC_COUNT;
shaderface->batches = MEM_callocN(shaderface->batches_len * sizeof(GPUBatch *),
"GPUShaderInterface batches");
+ MEM_freeN(uniforms_from_blocks);
+ MEM_freeN(inputs_tmp);
+
+ /* Resize name buffer to save some memory. */
+ if (name_buffer_offset < name_buffer_len) {
+ shaderface->name_buffer = MEM_reallocN(shaderface->name_buffer, name_buffer_offset);
+ }
+
+#if DEBUG_SHADER_INTERFACE
+ char *name_buf = shaderface->name_buffer;
+ printf("--- GPUShaderInterface %p, program %d ---\n", shaderface, program);
+ if (shaderface->attribute_len > 0) {
+ printf("Attributes {\n");
+ for (int i = 0; i < shaderface->attribute_len; i++) {
+ GPUShaderInput *input = shaderface->inputs + i;
+ printf("\t(location = %d) %s;\n", input->location, name_buf + input->name_offset);
+ }
+ printf("};\n");
+ }
+ if (shaderface->ubo_len > 0) {
+ printf("Uniform Buffer Objects {\n");
+ for (int i = 0; i < shaderface->ubo_len; i++) {
+ GPUShaderInput *input = shaderface->inputs + shaderface->attribute_len + i;
+ printf("\t(binding = %d) %s;\n", input->binding, name_buf + input->name_offset);
+ }
+ printf("};\n");
+ }
+ if (shaderface->enabled_tex_mask > 0) {
+ printf("Samplers {\n");
+ for (int i = 0; i < shaderface->uniform_len; i++) {
+ GPUShaderInput *input = shaderface->inputs + shaderface->attribute_len +
+ shaderface->ubo_len + i;
+ if (input->binding != -1) {
+ printf("\t(location = %d, binding = %d) %s;\n",
+ input->location,
+ input->binding,
+ name_buf + input->name_offset);
+ }
+ }
+ printf("};\n");
+ }
+ if (shaderface->uniform_len > 0) {
+ printf("Uniforms {\n");
+ for (int i = 0; i < shaderface->uniform_len; i++) {
+ GPUShaderInput *input = shaderface->inputs + shaderface->attribute_len +
+ shaderface->ubo_len + i;
+ if (input->binding == -1) {
+ printf("\t(location = %d) %s;\n", input->location, name_buf + input->name_offset);
+ }
+ }
+ printf("};\n");
+ }
+ printf("--- GPUShaderInterface end ---\n\n");
+#endif
+
return shaderface;
}
void GPU_shaderinterface_discard(GPUShaderInterface *shaderface)
{
- /* Free memory used by buckets and has entries. */
- buckets_free(shaderface->uniform_buckets);
- buckets_free(shaderface->attr_buckets);
- buckets_free(shaderface->ubo_buckets);
/* Free memory used by name_buffer. */
MEM_freeN(shaderface->name_buffer);
/* Remove this interface from all linked Batches vao cache. */
@@ -316,59 +454,39 @@ void GPU_shaderinterface_discard(GPUShaderInterface *shaderface)
MEM_freeN(shaderface);
}
-const GPUShaderInput *GPU_shaderinterface_uniform(const GPUShaderInterface *shaderface,
- const char *name)
+const GPUShaderInput *GPU_shaderinterface_attr(const GPUShaderInterface *shaderface,
+ const char *name)
{
- return buckets_lookup(shaderface->uniform_buckets, shaderface->name_buffer, name);
+ uint ofs = 0;
+ return input_lookup(shaderface, shaderface->inputs + ofs, shaderface->attribute_len, name);
}
-const GPUShaderInput *GPU_shaderinterface_uniform_ensure(const GPUShaderInterface *shaderface,
- const char *name)
+const GPUShaderInput *GPU_shaderinterface_ubo(const GPUShaderInterface *shaderface,
+ const char *name)
{
- const GPUShaderInput *input = GPU_shaderinterface_uniform(shaderface, name);
- /* If input is not found add it so it's found next time. */
- if (input == NULL) {
- input = add_uniform((GPUShaderInterface *)shaderface, name);
-
- if ((G.debug & G_DEBUG_GPU) && (input->location == -1)) {
- fprintf(stderr, "GPUShaderInterface: Warning: Uniform '%s' not found!\n", name);
- }
- }
-
-#if DEBUG_SHADER_UNIFORMS
- if ((G.debug & G_DEBUG_GPU) && input->builtin_type != GPU_UNIFORM_NONE &&
- input->builtin_type != GPU_UNIFORM_CUSTOM) {
- /* Warn if we find a matching builtin, since these can be looked up much quicker. */
- fprintf(stderr,
- "GPUShaderInterface: Warning: Uniform '%s' is a builtin uniform but not queried as "
- "such!\n",
- name);
- }
-#endif
- return (input->location != -1) ? input : NULL;
+ uint ofs = shaderface->attribute_len;
+ return input_lookup(shaderface, shaderface->inputs + ofs, shaderface->ubo_len, name);
}
-const GPUShaderInput *GPU_shaderinterface_uniform_builtin(const GPUShaderInterface *shaderface,
- GPUUniformBuiltin builtin)
+const GPUShaderInput *GPU_shaderinterface_uniform(const GPUShaderInterface *shaderface,
+ const char *name)
{
-#if TRUST_NO_ONE
- assert(builtin != GPU_UNIFORM_NONE);
- assert(builtin != GPU_UNIFORM_CUSTOM);
- assert(builtin != GPU_NUM_UNIFORMS);
-#endif
- return shaderface->builtin_uniforms[builtin];
+ uint ofs = shaderface->attribute_len + shaderface->ubo_len;
+ return input_lookup(shaderface, shaderface->inputs + ofs, shaderface->uniform_len, name);
}
-const GPUShaderInput *GPU_shaderinterface_ubo(const GPUShaderInterface *shaderface,
- const char *name)
+int32_t GPU_shaderinterface_uniform_builtin(const GPUShaderInterface *shaderface,
+ GPUUniformBuiltin builtin)
{
- return buckets_lookup(shaderface->ubo_buckets, shaderface->name_buffer, name);
+ BLI_assert(builtin >= 0 && builtin < GPU_NUM_UNIFORMS);
+ return shaderface->builtins[builtin];
}
-const GPUShaderInput *GPU_shaderinterface_attr(const GPUShaderInterface *shaderface,
- const char *name)
+int32_t GPU_shaderinterface_block_builtin(const GPUShaderInterface *shaderface,
+ GPUUniformBlockBuiltin builtin)
{
- return buckets_lookup(shaderface->attr_buckets, shaderface->name_buffer, name);
+ BLI_assert(builtin >= 0 && builtin < GPU_NUM_UNIFORM_BLOCKS);
+ return shaderface->builtin_blocks[builtin];
}
void GPU_shaderinterface_add_batch_ref(GPUShaderInterface *shaderface, GPUBatch *batch)
diff --git a/source/blender/gpu/intern/gpu_state.c b/source/blender/gpu/intern/gpu_state.c
index d6f044a79e3..908f5fa5771 100644
--- a/source/blender/gpu/intern/gpu_state.c
+++ b/source/blender/gpu/intern/gpu_state.c
@@ -370,4 +370,44 @@ void gpuPopAttr(void)
#undef Attr
#undef AttrStack
+/* Default OpenGL State
+ *
+ * This is called on startup, for opengl offscreen render.
+ * Generally we should always return to this state when
+ * temporarily modifying the state for drawing, though that are (undocumented)
+ * exceptions that we should try to get rid of. */
+
+void GPU_state_init(void)
+{
+ GPU_program_point_size(false);
+
+ glEnable(GL_TEXTURE_CUBE_MAP_SEAMLESS);
+
+ glDisable(GL_BLEND);
+ glDisable(GL_DEPTH_TEST);
+ glDisable(GL_COLOR_LOGIC_OP);
+ glDisable(GL_STENCIL_TEST);
+ glDisable(GL_DITHER);
+
+ glDepthFunc(GL_LEQUAL);
+ glDepthRange(0.0, 1.0);
+
+ glFrontFace(GL_CCW);
+ glCullFace(GL_BACK);
+ glDisable(GL_CULL_FACE);
+
+ /* Is default but better be explicit. */
+ glEnable(GL_MULTISAMPLE);
+
+ /* This is a bit dangerous since addons could change this. */
+ glEnable(GL_PRIMITIVE_RESTART);
+ glPrimitiveRestartIndex((GLuint)0xFFFFFFFF);
+
+ /* TODO: Should become default. But needs at least GL 4.3 */
+ if (GLEW_ARB_ES3_compatibility) {
+ /* Takes predecence over GL_PRIMITIVE_RESTART */
+ glEnable(GL_PRIMITIVE_RESTART_FIXED_INDEX);
+ }
+}
+
/** \} */
diff --git a/source/blender/gpu/intern/gpu_texture.c b/source/blender/gpu/intern/gpu_texture.c
index 075a8e8aeb5..ca0d633aa9e 100644
--- a/source/blender/gpu/intern/gpu_texture.c
+++ b/source/blender/gpu/intern/gpu_texture.c
@@ -50,7 +50,9 @@ static struct GPUTextureGlobal {
GPUTexture *invalid_tex_1D;
GPUTexture *invalid_tex_2D;
GPUTexture *invalid_tex_3D;
-} GG = {NULL, NULL, NULL};
+ /** Sampler objects used to replace internal texture parameters. */
+ GLuint samplers[GPU_SAMPLER_MAX];
+} GG = {NULL};
/* Maximum number of FBOs a texture can be attached to. */
#define GPU_TEX_MAX_FBO_ATTACHED 12
@@ -72,7 +74,7 @@ typedef enum eGPUTextureFormatFlag {
struct GPUTexture {
int w, h, d; /* width/height/depth */
int orig_w, orig_h; /* width/height (of source data), optional. */
- int number; /* number for multitexture binding */
+ int number; /* Texture unit to which this texture is bound. */
int refcount; /* reference count */
GLenum target; /* GL_TEXTURE_* */
GLenum target_base; /* same as target, (but no multisample)
@@ -81,6 +83,7 @@ struct GPUTexture {
eGPUTextureFormat format;
eGPUTextureFormatFlag format_flag;
+ eGPUSamplerState sampler_state; /* Internal Sampler state. */
int mipmaps; /* number of mipmaps */
int components; /* number of color/alpha channels */
@@ -88,9 +91,13 @@ struct GPUTexture {
int fb_attachment[GPU_TEX_MAX_FBO_ATTACHED];
GPUFrameBuffer *fb[GPU_TEX_MAX_FBO_ATTACHED];
+ /* Legacy workaround for texture copy. */
+ GLuint copy_fb;
+ GPUContext *copy_fb_ctx;
};
static uint gpu_get_bytesize(eGPUTextureFormat data_type);
+static void gpu_texture_framebuffer_ensure(GPUTexture *tex);
/* ------ Memory Management ------- */
/* Records every texture allocation / free
@@ -165,26 +172,33 @@ static const char *gl_enum_to_str(GLenum e)
ENUM_TO_STRING(TEXTURE_2D_MULTISAMPLE),
ENUM_TO_STRING(RGBA32F),
ENUM_TO_STRING(RGBA16F),
+ ENUM_TO_STRING(RGBA16UI),
+ ENUM_TO_STRING(RGBA16I),
ENUM_TO_STRING(RGBA16),
- ENUM_TO_STRING(RG32F),
+ ENUM_TO_STRING(RGBA8UI),
+ ENUM_TO_STRING(RGBA8I),
+ ENUM_TO_STRING(RGBA8),
ENUM_TO_STRING(RGB16F),
+ ENUM_TO_STRING(RG32F),
ENUM_TO_STRING(RG16F),
+ ENUM_TO_STRING(RG16UI),
ENUM_TO_STRING(RG16I),
ENUM_TO_STRING(RG16),
- ENUM_TO_STRING(RGBA8),
- ENUM_TO_STRING(RGBA8UI),
+ ENUM_TO_STRING(RG8UI),
+ ENUM_TO_STRING(RG8I),
+ ENUM_TO_STRING(RG8),
+ ENUM_TO_STRING(R8UI),
+ ENUM_TO_STRING(R8I),
+ ENUM_TO_STRING(R8),
ENUM_TO_STRING(R32F),
ENUM_TO_STRING(R32UI),
ENUM_TO_STRING(R32I),
ENUM_TO_STRING(R16F),
- ENUM_TO_STRING(R16I),
ENUM_TO_STRING(R16UI),
- ENUM_TO_STRING(RG8),
- ENUM_TO_STRING(RG16UI),
+ ENUM_TO_STRING(R16I),
ENUM_TO_STRING(R16),
- ENUM_TO_STRING(R8),
- ENUM_TO_STRING(R8UI),
ENUM_TO_STRING(R11F_G11F_B10F),
+ ENUM_TO_STRING(SRGB8_ALPHA8),
ENUM_TO_STRING(DEPTH24_STENCIL8),
ENUM_TO_STRING(DEPTH32F_STENCIL8),
ENUM_TO_STRING(DEPTH_COMPONENT32F),
@@ -457,7 +471,7 @@ static GLenum gpu_format_to_gl_internalformat(eGPUTextureFormat format)
case GPU_RG16I:
return GL_RG16I;
case GPU_RG16F:
- return GL_RGBA32F;
+ return GL_RG16F;
case GPU_RG16:
return GL_RG16;
case GPU_R8UI:
@@ -816,12 +830,12 @@ GPUTexture *GPU_texture_create_nD(int w,
tex->h = h;
tex->d = d;
tex->samples = samples;
- tex->number = -1;
tex->refcount = 1;
tex->format = tex_format;
tex->components = gpu_get_component_count(tex_format);
tex->mipmaps = 0;
tex->format_flag = 0;
+ tex->number = -1;
if (n == 2) {
if (d == 0) {
@@ -965,26 +979,13 @@ GPUTexture *GPU_texture_create_nD(int w,
if (GPU_texture_stencil(tex) || /* Does not support filtering */
GPU_texture_integer(tex) || /* Does not support filtering */
GPU_texture_depth(tex)) {
- glTexParameteri(tex->target_base, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
- glTexParameteri(tex->target_base, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
+ tex->sampler_state = GPU_SAMPLER_DEFAULT & ~GPU_SAMPLER_FILTER;
}
else {
- glTexParameteri(tex->target_base, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
- glTexParameteri(tex->target_base, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
- }
-
- if (GPU_texture_depth(tex)) {
- glTexParameteri(tex->target_base, GL_TEXTURE_COMPARE_MODE, GL_NONE);
- glTexParameteri(tex->target_base, GL_TEXTURE_COMPARE_FUNC, GL_LEQUAL);
- }
-
- glTexParameteri(tex->target_base, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
- if (n > 1) {
- glTexParameteri(tex->target_base, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
- }
- if (n > 2) {
- glTexParameteri(tex->target_base, GL_TEXTURE_WRAP_R, GL_CLAMP_TO_EDGE);
+ tex->sampler_state = GPU_SAMPLER_DEFAULT;
}
+ /* Avoid issue with incomplete textures. */
+ glTexParameteri(tex->target_base, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
glBindTexture(tex->target, 0);
@@ -1003,12 +1004,12 @@ GPUTexture *GPU_texture_cube_create(int w,
tex->h = w;
tex->d = d;
tex->samples = 0;
- tex->number = -1;
tex->refcount = 1;
tex->format = tex_format;
tex->components = gpu_get_component_count(tex_format);
tex->mipmaps = 0;
tex->format_flag = GPU_FORMAT_CUBE;
+ tex->number = -1;
if (d == 0) {
tex->target_base = tex->target = GL_TEXTURE_CUBE_MAP;
@@ -1106,22 +1107,13 @@ GPUTexture *GPU_texture_cube_create(int w,
if (GPU_texture_stencil(tex) || /* Does not support filtering */
GPU_texture_integer(tex) || /* Does not support filtering */
GPU_texture_depth(tex)) {
- glTexParameteri(tex->target_base, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
- glTexParameteri(tex->target_base, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
+ tex->sampler_state = GPU_SAMPLER_DEFAULT & ~GPU_SAMPLER_FILTER;
}
else {
- glTexParameteri(tex->target_base, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
- glTexParameteri(tex->target_base, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
- }
-
- if (GPU_texture_depth(tex)) {
- glTexParameteri(tex->target_base, GL_TEXTURE_COMPARE_MODE, GL_NONE);
- glTexParameteri(tex->target_base, GL_TEXTURE_COMPARE_FUNC, GL_LEQUAL);
+ tex->sampler_state = GPU_SAMPLER_DEFAULT;
}
-
- glTexParameteri(tex->target_base, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
- glTexParameteri(tex->target_base, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
- glTexParameteri(tex->target_base, GL_TEXTURE_WRAP_R, GL_CLAMP_TO_EDGE);
+ /* Avoid issue with incomplete textures. */
+ glTexParameteri(tex->target_base, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
glBindTexture(tex->target, 0);
@@ -1132,13 +1124,13 @@ GPUTexture *GPU_texture_cube_create(int w,
GPUTexture *GPU_texture_create_buffer(eGPUTextureFormat tex_format, const GLuint buffer)
{
GPUTexture *tex = MEM_callocN(sizeof(GPUTexture), "GPUTexture");
- tex->number = -1;
tex->refcount = 1;
tex->format = tex_format;
tex->components = gpu_get_component_count(tex_format);
tex->format_flag = 0;
tex->target_base = tex->target = GL_TEXTURE_BUFFER;
tex->mipmaps = 0;
+ tex->number = -1;
GLenum internalformat = gpu_format_to_gl_internalformat(tex_format);
@@ -1185,11 +1177,15 @@ GPUTexture *GPU_texture_from_bindcode(int textarget, int bindcode)
{
GPUTexture *tex = MEM_callocN(sizeof(GPUTexture), "GPUTexture");
tex->bindcode = bindcode;
- tex->number = -1;
tex->refcount = 1;
tex->target = textarget;
tex->target_base = textarget;
tex->samples = 0;
+ tex->sampler_state = GPU_SAMPLER_REPEAT | GPU_SAMPLER_ANISO;
+ if (GPU_get_mipmap()) {
+ tex->sampler_state |= (GPU_SAMPLER_MIPMAP | GPU_SAMPLER_FILTER);
+ }
+ tex->number = -1;
if (!glIsTexture(tex->bindcode)) {
GPU_print_error_debug("Blender Texture Not Loaded");
@@ -1560,25 +1556,117 @@ void *GPU_texture_read(GPUTexture *tex, eGPUDataFormat gpu_data_format, int mipl
void GPU_texture_clear(GPUTexture *tex, eGPUDataFormat gpu_data_format, const void *color)
{
- if (GLEW_ARB_clear_texture) {
- GLenum data_format = gpu_get_gl_dataformat(tex->format, &tex->format_flag);
+ BLI_assert(color != NULL); /* Do not accept NULL as parameter. */
+ gpu_validate_data_format(tex->format, gpu_data_format);
+
+ if (false && GLEW_ARB_clear_texture) {
GLenum data_type = gpu_get_gl_datatype(gpu_data_format);
+ GLenum data_format = gpu_get_gl_dataformat(tex->format, &tex->format_flag);
glClearTexImage(tex->bindcode, 0, data_format, data_type, color);
+
+ if (GPU_texture_stencil(tex) && GPU_texture_depth(tex)) {
+ /* TODO(clem) implement in fallback. */
+ BLI_assert(0);
+ }
+ else if (GPU_texture_depth(tex)) {
+ switch (gpu_data_format) {
+ case GPU_DATA_FLOAT:
+ case GPU_DATA_UNSIGNED_INT:
+ break;
+ default:
+ /* TODO(clem) implement in fallback. */
+ BLI_assert(0);
+ break;
+ }
+ }
+ else {
+ switch (gpu_data_format) {
+ case GPU_DATA_FLOAT:
+ case GPU_DATA_UNSIGNED_INT:
+ case GPU_DATA_UNSIGNED_BYTE:
+ break;
+ default:
+ /* TODO(clem) implement in fallback. */
+ BLI_assert(0);
+ break;
+ }
+ }
}
else {
- size_t buffer_len = gpu_texture_memory_footprint_compute(tex);
- unsigned char *pixels = MEM_mallocN(buffer_len, __func__);
- if (color) {
- const size_t bytesize = (size_t)gpu_get_bytesize(tex->format);
- for (size_t byte = 0; byte < buffer_len; byte += bytesize) {
- memcpy(&pixels[byte], color, bytesize);
+ /* Fallback for older GL. */
+ GPUFrameBuffer *prev_fb = GPU_framebuffer_active_get();
+
+ gpu_texture_framebuffer_ensure(tex);
+ /* This means that this function can only be used in one context for each texture. */
+ BLI_assert(tex->copy_fb_ctx == GPU_context_active_get());
+
+ glBindFramebuffer(GL_FRAMEBUFFER, tex->copy_fb);
+ glViewport(0, 0, tex->w, tex->h);
+
+ /* Watch: Write mask could prevent the clear.
+ * glClearTexImage does not change the state so we don't do it here either. */
+ if (GPU_texture_stencil(tex) && GPU_texture_depth(tex)) {
+ /* TODO(clem) implement. */
+ BLI_assert(0);
+ }
+ else if (GPU_texture_depth(tex)) {
+ float depth;
+ switch (gpu_data_format) {
+ case GPU_DATA_FLOAT: {
+ depth = *(float *)color;
+ break;
+ }
+ case GPU_DATA_UNSIGNED_INT: {
+ depth = *(uint *)color / (float)UINT_MAX;
+ break;
+ }
+ default:
+ BLI_assert(!"Unhandled data format");
+ depth = 0.0f;
+ break;
}
+ glClearDepth(depth);
+ glClear(GL_DEPTH_BUFFER_BIT);
}
else {
- memset(pixels, 0, buffer_len);
+ float r, g, b, a;
+ switch (gpu_data_format) {
+ case GPU_DATA_FLOAT: {
+ float *f_color = (float *)color;
+ r = f_color[0];
+ g = (tex->components > 1) ? f_color[1] : 0.0f;
+ b = (tex->components > 2) ? f_color[2] : 0.0f;
+ a = (tex->components > 3) ? f_color[3] : 0.0f;
+ break;
+ }
+ case GPU_DATA_UNSIGNED_INT: {
+ uint *u_color = (uint *)color;
+ r = u_color[0] / (float)UINT_MAX;
+ g = (tex->components > 1) ? u_color[1] / (float)UINT_MAX : 0.0f;
+ b = (tex->components > 2) ? u_color[2] / (float)UINT_MAX : 0.0f;
+ a = (tex->components > 3) ? u_color[3] / (float)UINT_MAX : 0.0f;
+ break;
+ }
+ case GPU_DATA_UNSIGNED_BYTE: {
+ uchar *ub_color = (uchar *)color;
+ r = ub_color[0] / 255.0f;
+ g = (tex->components > 1) ? ub_color[1] / 255.0f : 0.0f;
+ b = (tex->components > 2) ? ub_color[2] / 255.0f : 0.0f;
+ a = (tex->components > 3) ? ub_color[3] / 255.0f : 0.0f;
+ break;
+ }
+ default:
+ BLI_assert(!"Unhandled data format");
+ r = g = b = a = 0.0f;
+ break;
+ }
+ glClearColor(r, g, b, a);
+ glClear(GL_COLOR_BUFFER_BIT);
+ }
+
+ if (prev_fb) {
+ GPU_framebuffer_bind(prev_fb);
}
- GPU_texture_update(tex, gpu_data_format, pixels);
- MEM_freeN(pixels);
}
}
@@ -1624,16 +1712,17 @@ void GPU_invalid_tex_free(void)
}
}
-void GPU_texture_bind(GPUTexture *tex, int number)
+/* set_number is to save the the texture unit for setting texture parameters. */
+void GPU_texture_bind_ex(GPUTexture *tex, eGPUSamplerState state, int unit, const bool set_number)
{
- BLI_assert(number >= 0);
+ BLI_assert(unit >= 0);
- if (number >= GPU_max_textures()) {
+ if (unit >= GPU_max_textures()) {
fprintf(stderr, "Not enough texture slots.\n");
return;
}
- if ((G.debug & G_DEBUG)) {
+ if (G.debug & G_DEBUG) {
for (int i = 0; i < GPU_TEX_MAX_FBO_ATTACHED; i++) {
if (tex->fb[i] && GPU_framebuffer_bound(tex->fb[i])) {
fprintf(stderr,
@@ -1645,16 +1734,27 @@ void GPU_texture_bind(GPUTexture *tex, int number)
}
}
- glActiveTexture(GL_TEXTURE0 + number);
+ if (set_number) {
+ tex->number = unit;
+ }
+
+ glActiveTexture(GL_TEXTURE0 + unit);
+
+ state = (state < GPU_SAMPLER_MAX) ? state : tex->sampler_state;
if (tex->bindcode != 0) {
glBindTexture(tex->target, tex->bindcode);
+ glBindSampler(unit, GG.samplers[state]);
}
else {
GPU_invalid_tex_bind(tex->target_base);
+ glBindSampler(unit, 0);
}
+}
- tex->number = number;
+void GPU_texture_bind(GPUTexture *tex, int unit)
+{
+ GPU_texture_bind_ex(tex, GPU_SAMPLER_MAX, unit, true);
}
void GPU_texture_unbind(GPUTexture *tex)
@@ -1665,13 +1765,34 @@ void GPU_texture_unbind(GPUTexture *tex)
glActiveTexture(GL_TEXTURE0 + tex->number);
glBindTexture(tex->target, 0);
-
+ glBindSampler(tex->number, 0);
tex->number = -1;
}
-int GPU_texture_bound_number(GPUTexture *tex)
+void GPU_texture_unbind_all(void)
{
- return tex->number;
+ if (GLEW_ARB_multi_bind) {
+ glBindTextures(0, GPU_max_textures(), NULL);
+ glBindSamplers(0, GPU_max_textures(), NULL);
+ return;
+ }
+
+ for (int i = 0; i < GPU_max_textures(); i++) {
+ glActiveTexture(GL_TEXTURE0 + i);
+ glBindTexture(GL_TEXTURE_2D, 0);
+ glBindTexture(GL_TEXTURE_2D_ARRAY, 0);
+ glBindTexture(GL_TEXTURE_1D, 0);
+ glBindTexture(GL_TEXTURE_1D_ARRAY, 0);
+ glBindTexture(GL_TEXTURE_3D, 0);
+ glBindTexture(GL_TEXTURE_CUBE_MAP, 0);
+ glBindTexture(GL_TEXTURE_BUFFER, 0);
+ if (GPU_arb_texture_cube_map_array_is_supported()) {
+ glBindTexture(GL_TEXTURE_CUBE_MAP_ARRAY_ARB, 0);
+ }
+ glBindSampler(i, 0);
+ }
+
+ glActiveTexture(GL_TEXTURE0);
}
#define WARN_NOT_BOUND(_tex) \
@@ -1695,8 +1816,8 @@ void GPU_texture_generate_mipmap(GPUTexture *tex)
if (GPU_texture_depth(tex)) {
/* Some drivers have bugs when using glGenerateMipmap with depth textures (see T56789).
- * In this case we just create a complete texture with mipmaps manually without down-sampling.
- * You must initialize the texture levels using other methods like
+ * In this case we just create a complete texture with mipmaps manually without
+ * down-sampling. You must initialize the texture levels using other methods like
* GPU_framebuffer_recursive_downsample(). */
eGPUDataFormat data_format = gpu_get_data_format_from_tex_format(tex->format);
for (int i = 1; i < levels; i++) {
@@ -1712,66 +1833,125 @@ void GPU_texture_generate_mipmap(GPUTexture *tex)
gpu_texture_memory_footprint_add(tex);
}
-void GPU_texture_compare_mode(GPUTexture *tex, bool use_compare)
+static GLenum gpu_texture_default_attachment(GPUTexture *tex)
{
- WARN_NOT_BOUND(tex);
+ return !GPU_texture_depth(tex) ?
+ GL_COLOR_ATTACHMENT0 :
+ (GPU_texture_stencil(tex) ? GL_DEPTH_STENCIL_ATTACHMENT : GL_DEPTH_ATTACHMENT);
+}
+
+static void gpu_texture_framebuffer_ensure(GPUTexture *tex)
+{
+ if (tex->copy_fb == 0) {
+ tex->copy_fb = GPU_fbo_alloc();
+ tex->copy_fb_ctx = GPU_context_active_get();
+
+ GLenum attachment = gpu_texture_default_attachment(tex);
+ glBindFramebuffer(GL_FRAMEBUFFER, tex->copy_fb);
+ glFramebufferTexture(GL_FRAMEBUFFER, attachment, tex->bindcode, 0);
+ if (!GPU_texture_depth(tex)) {
+ glReadBuffer(GL_COLOR_ATTACHMENT0);
+ glDrawBuffer(GL_COLOR_ATTACHMENT0);
+ }
+ BLI_assert(glCheckFramebufferStatus(GL_FRAMEBUFFER) == GL_FRAMEBUFFER_COMPLETE);
+ glBindFramebuffer(GL_FRAMEBUFFER, 0);
+ }
+}
+
+/* Copy a texture content to a similar texture. Only Mip 0 is copied. */
+void GPU_texture_copy(GPUTexture *dst, GPUTexture *src)
+{
+ BLI_assert(dst->target == src->target);
+ BLI_assert(dst->w == src->w);
+ BLI_assert(dst->h == src->h);
+ BLI_assert(!GPU_texture_cube(src) && !GPU_texture_cube(dst));
+ /* TODO support array / 3D textures. */
+ BLI_assert(dst->d == 0);
+ BLI_assert(dst->format == src->format);
+
+ if (GLEW_ARB_copy_image) {
+ /* Opengl 4.3 */
+ glCopyImageSubData(src->bindcode,
+ src->target,
+ 0,
+ 0,
+ 0,
+ 0,
+ dst->bindcode,
+ dst->target,
+ 0,
+ 0,
+ 0,
+ 0,
+ src->w,
+ src->h,
+ 1);
+ }
+ else {
+ /* Fallback for older GL. */
+ GPUFrameBuffer *prev_fb = GPU_framebuffer_active_get();
+
+ gpu_texture_framebuffer_ensure(src);
+ gpu_texture_framebuffer_ensure(dst);
+
+ /* This means that this function can only be used in one context for each texture. */
+ BLI_assert(src->copy_fb_ctx == GPU_context_active_get());
+ BLI_assert(dst->copy_fb_ctx == GPU_context_active_get());
+
+ glBindFramebuffer(GL_READ_FRAMEBUFFER, src->copy_fb);
+ glBindFramebuffer(GL_DRAW_FRAMEBUFFER, dst->copy_fb);
+
+ GLbitfield mask = 0;
+ if (GPU_texture_stencil(src)) {
+ mask |= GL_STENCIL_BUFFER_BIT;
+ }
+ if (GPU_texture_depth(src)) {
+ mask |= GL_DEPTH_BUFFER_BIT;
+ }
+ else {
+ mask |= GL_COLOR_BUFFER_BIT;
+ }
+
+ glBlitFramebuffer(0, 0, src->w, src->h, 0, 0, src->w, src->h, mask, GL_NEAREST);
+
+ if (prev_fb) {
+ GPU_framebuffer_bind(prev_fb);
+ }
+ }
+}
+
+void GPU_texture_compare_mode(GPUTexture *tex, bool use_compare)
+{
/* Could become an assertion ? (fclem) */
if (!GPU_texture_depth(tex)) {
return;
}
-
- GLenum mode = (use_compare) ? GL_COMPARE_REF_TO_TEXTURE : GL_NONE;
-
- glActiveTexture(GL_TEXTURE0 + tex->number);
- glTexParameteri(tex->target_base, GL_TEXTURE_COMPARE_MODE, mode);
+ SET_FLAG_FROM_TEST(tex->sampler_state, use_compare, GPU_SAMPLER_COMPARE);
}
void GPU_texture_filter_mode(GPUTexture *tex, bool use_filter)
{
- WARN_NOT_BOUND(tex);
-
/* Stencil and integer format does not support filtering. */
BLI_assert(!use_filter || !(GPU_texture_stencil(tex) || GPU_texture_integer(tex)));
- GLenum filter = (use_filter) ? GL_LINEAR : GL_NEAREST;
-
- glActiveTexture(GL_TEXTURE0 + tex->number);
- glTexParameteri(tex->target_base, GL_TEXTURE_MAG_FILTER, filter);
- glTexParameteri(tex->target_base, GL_TEXTURE_MIN_FILTER, filter);
+ SET_FLAG_FROM_TEST(tex->sampler_state, use_filter, GPU_SAMPLER_FILTER);
}
void GPU_texture_mipmap_mode(GPUTexture *tex, bool use_mipmap, bool use_filter)
{
- WARN_NOT_BOUND(tex);
-
/* Stencil and integer format does not support filtering. */
- BLI_assert((!use_filter && !use_mipmap) ||
+ BLI_assert(!(use_filter || use_mipmap) ||
!(GPU_texture_stencil(tex) || GPU_texture_integer(tex)));
- GLenum filter = (use_filter) ? GL_LINEAR : GL_NEAREST;
- GLenum mipmap = ((use_filter) ? (use_mipmap) ? GL_LINEAR_MIPMAP_LINEAR : GL_LINEAR :
- (use_mipmap) ? GL_NEAREST_MIPMAP_LINEAR : GL_NEAREST);
-
- glActiveTexture(GL_TEXTURE0 + tex->number);
- glTexParameteri(tex->target_base, GL_TEXTURE_MIN_FILTER, mipmap);
- glTexParameteri(tex->target_base, GL_TEXTURE_MAG_FILTER, filter);
+ SET_FLAG_FROM_TEST(tex->sampler_state, use_mipmap, GPU_SAMPLER_MIPMAP);
+ SET_FLAG_FROM_TEST(tex->sampler_state, use_filter, GPU_SAMPLER_FILTER);
}
-void GPU_texture_wrap_mode(GPUTexture *tex, bool use_repeat)
+void GPU_texture_wrap_mode(GPUTexture *tex, bool use_repeat, bool use_clamp)
{
- WARN_NOT_BOUND(tex);
-
- GLenum repeat = (use_repeat) ? GL_REPEAT : GL_CLAMP_TO_EDGE;
-
- glActiveTexture(GL_TEXTURE0 + tex->number);
- glTexParameteri(tex->target_base, GL_TEXTURE_WRAP_S, repeat);
- if (tex->target_base != GL_TEXTURE_1D) {
- glTexParameteri(tex->target_base, GL_TEXTURE_WRAP_T, repeat);
- }
- if (tex->target_base == GL_TEXTURE_3D) {
- glTexParameteri(tex->target_base, GL_TEXTURE_WRAP_R, repeat);
- }
+ SET_FLAG_FROM_TEST(tex->sampler_state, use_repeat, GPU_SAMPLER_REPEAT);
+ SET_FLAG_FROM_TEST(tex->sampler_state, !use_clamp, GPU_SAMPLER_CLAMP_BORDER);
}
void GPU_texture_swizzle_channel_auto(GPUTexture *tex, int channels)
@@ -1785,34 +1965,6 @@ void GPU_texture_swizzle_channel_auto(GPUTexture *tex, int channels)
glTexParameteri(GL_TEXTURE_3D, GL_TEXTURE_SWIZZLE_A, (channels >= 4) ? GL_ALPHA : GL_ONE);
}
-static GLenum gpu_get_gl_filterfunction(eGPUFilterFunction filter)
-{
- switch (filter) {
- case GPU_NEAREST:
- return GL_NEAREST;
- case GPU_LINEAR:
- return GL_LINEAR;
- default:
- BLI_assert(!"Unhandled filter mode");
- return GL_NEAREST;
- }
-}
-
-void GPU_texture_filters(GPUTexture *tex,
- eGPUFilterFunction min_filter,
- eGPUFilterFunction mag_filter)
-{
- WARN_NOT_BOUND(tex);
-
- /* Stencil and integer format does not support filtering. */
- BLI_assert(!(GPU_texture_stencil(tex) || GPU_texture_integer(tex)));
- BLI_assert(mag_filter == GPU_NEAREST || mag_filter == GPU_LINEAR);
-
- glActiveTexture(GL_TEXTURE0 + tex->number);
- glTexParameteri(tex->target_base, GL_TEXTURE_MIN_FILTER, gpu_get_gl_filterfunction(min_filter));
- glTexParameteri(tex->target_base, GL_TEXTURE_MAG_FILTER, gpu_get_gl_filterfunction(mag_filter));
-}
-
void GPU_texture_free(GPUTexture *tex)
{
tex->refcount--;
@@ -1831,6 +1983,9 @@ void GPU_texture_free(GPUTexture *tex)
if (tex->bindcode) {
GPU_tex_free(tex->bindcode);
}
+ if (tex->copy_fb) {
+ GPU_fbo_free(tex->copy_fb, tex->copy_fb_ctx);
+ }
gpu_texture_memory_footprint_remove(tex);
@@ -1970,3 +2125,55 @@ void GPU_texture_get_mipmap_size(GPUTexture *tex, int lvl, int *size)
size[2] = max_ii(1, tex->d / div);
}
}
+
+/* -------------------------------------------------------------------- */
+/** \name GPU Sampler Objects
+ *
+ * Simple wrapper around opengl sampler objects.
+ * Override texture sampler state for one sampler unit only.
+ * \{ */
+
+void GPU_samplers_init(void)
+{
+ glGenSamplers(GPU_SAMPLER_MAX, GG.samplers);
+ for (int i = 0; i < GPU_SAMPLER_MAX; i++) {
+ eGPUSamplerState state = i;
+ GLenum clamp_type = (state & GPU_SAMPLER_CLAMP_BORDER) ? GL_CLAMP_TO_BORDER : GL_CLAMP_TO_EDGE;
+ GLenum wrap_s = (state & GPU_SAMPLER_REPEAT_S) ? GL_REPEAT : clamp_type;
+ GLenum wrap_t = (state & GPU_SAMPLER_REPEAT_T) ? GL_REPEAT : clamp_type;
+ GLenum wrap_r = (state & GPU_SAMPLER_REPEAT_R) ? GL_REPEAT : clamp_type;
+ GLenum mag_filter = (state & GPU_SAMPLER_FILTER) ? GL_LINEAR : GL_NEAREST;
+ GLenum min_filter = (state & GPU_SAMPLER_FILTER) ?
+ ((state & GPU_SAMPLER_MIPMAP) ? GL_LINEAR_MIPMAP_LINEAR : GL_LINEAR) :
+ ((state & GPU_SAMPLER_MIPMAP) ? GL_NEAREST_MIPMAP_LINEAR : GL_NEAREST);
+ GLenum compare_mode = (state & GPU_SAMPLER_COMPARE) ? GL_COMPARE_REF_TO_TEXTURE : GL_NONE;
+ float aniso_filter = ((state & GPU_SAMPLER_MIPMAP) && (state & GPU_SAMPLER_ANISO)) ?
+ GPU_get_anisotropic() :
+ 1.0f;
+
+ glSamplerParameteri(GG.samplers[i], GL_TEXTURE_WRAP_S, wrap_s);
+ glSamplerParameteri(GG.samplers[i], GL_TEXTURE_WRAP_T, wrap_t);
+ glSamplerParameteri(GG.samplers[i], GL_TEXTURE_WRAP_R, wrap_r);
+ glSamplerParameteri(GG.samplers[i], GL_TEXTURE_MIN_FILTER, min_filter);
+ glSamplerParameteri(GG.samplers[i], GL_TEXTURE_MAG_FILTER, mag_filter);
+ glSamplerParameteri(GG.samplers[i], GL_TEXTURE_COMPARE_MODE, compare_mode);
+ glSamplerParameteri(GG.samplers[i], GL_TEXTURE_COMPARE_FUNC, GL_LEQUAL);
+ if (GLEW_EXT_texture_filter_anisotropic) {
+ glSamplerParameterf(GG.samplers[i], GL_TEXTURE_MAX_ANISOTROPY_EXT, aniso_filter);
+ }
+
+ /** Other states are left to default:
+ * - GL_TEXTURE_BORDER_COLOR is {0, 0, 0, 0}.
+ * - GL_TEXTURE_MIN_LOD is -1000.
+ * - GL_TEXTURE_MAX_LOD is 1000.
+ * - GL_TEXTURE_LOD_BIAS is 0.0f.
+ **/
+ }
+}
+
+void GPU_samplers_free(void)
+{
+ glDeleteSamplers(GPU_SAMPLER_MAX, GG.samplers);
+}
+
+/** \} */
diff --git a/source/blender/gpu/intern/gpu_uniformbuffer.c b/source/blender/gpu/intern/gpu_uniformbuffer.c
index 943793956d1..130e8fe7da1 100644
--- a/source/blender/gpu/intern/gpu_uniformbuffer.c
+++ b/source/blender/gpu/intern/gpu_uniformbuffer.c
@@ -147,7 +147,7 @@ GPUUniformBuffer *GPU_uniformbuffer_dynamic_create(ListBase *inputs, char err_ou
/* Make sure we comply to the ubo alignment requirements. */
gpu_uniformbuffer_inputs_sort(inputs);
- for (LinkData *link = inputs->first; link; link = link->next) {
+ LISTBASE_FOREACH (LinkData *, link, inputs) {
const eGPUType gputype = get_padded_gpu_type(link);
ubo->buffer.size += gputype * sizeof(float);
}
@@ -160,7 +160,7 @@ GPUUniformBuffer *GPU_uniformbuffer_dynamic_create(ListBase *inputs, char err_ou
/* Now that we know the total ubo size we can start populating it. */
float *offset = ubo->data;
- for (LinkData *link = inputs->first; link; link = link->next) {
+ LISTBASE_FOREACH (LinkData *, link, inputs) {
GPUInput *input = link->data;
memcpy(offset, input->vec, input->type * sizeof(float));
offset += get_padded_gpu_type(link);
@@ -272,7 +272,7 @@ static void gpu_uniformbuffer_inputs_sort(ListBase *inputs)
LinkData *inputs_lookup[MAX_UBO_GPU_TYPE + 1] = {NULL};
eGPUType cur_type = MAX_UBO_GPU_TYPE + 1;
- for (LinkData *link = inputs->first; link; link = link->next) {
+ LISTBASE_FOREACH (LinkData *, link, inputs) {
GPUInput *input = link->data;
if (input->type == GPU_MAT3) {
diff --git a/source/blender/gpu/intern/gpu_vertex_buffer.c b/source/blender/gpu/intern/gpu_vertex_buffer.c
index 1df7e68e08b..25daabe601d 100644
--- a/source/blender/gpu/intern/gpu_vertex_buffer.c
+++ b/source/blender/gpu/intern/gpu_vertex_buffer.c
@@ -196,7 +196,7 @@ void GPU_vertbuf_attr_fill(GPUVertBuf *verts, uint a_idx, const void *data)
GPU_vertbuf_attr_fill_stride(verts, a_idx, stride, data);
}
-/** Fills a whole vertex (all attribs). Data must match packed layout. */
+/** Fills a whole vertex (all attributes). Data must match packed layout. */
void GPU_vertbuf_vert_set(GPUVertBuf *verts, uint v_idx, const void *data)
{
const GPUVertFormat *format = &verts->format;
diff --git a/source/blender/gpu/intern/gpu_vertex_format.c b/source/blender/gpu/intern/gpu_vertex_format.c
index 8370bcf4beb..b84a7e0f554 100644
--- a/source/blender/gpu/intern/gpu_vertex_format.c
+++ b/source/blender/gpu/intern/gpu_vertex_format.c
@@ -23,8 +23,6 @@
* GPU vertex format
*/
-#include "GPU_shader_interface.h"
-
#include "GPU_vertex_format.h"
#include "gpu_vertex_format_private.h"
#include <stddef.h>
@@ -34,6 +32,9 @@
#include "BLI_string.h"
#include "BLI_utildefines.h"
+#include "GPU_shader.h"
+#include "gpu_shader_private.h"
+
#define PACK_DEBUG 0
#if PACK_DEBUG
@@ -207,15 +208,15 @@ void GPU_vertformat_alias_add(GPUVertFormat *format, const char *alias)
}
/**
- * Makes vertex attrib from the next vertices to be accessible in the vertex shader.
- * For an attrib named "attr" you can access the next nth vertex using "attrn".
- * Use this function after specifying all the attribs in the format.
+ * Makes vertex attribute from the next vertices to be accessible in the vertex shader.
+ * For an attribute named "attr" you can access the next nth vertex using "attr{number}".
+ * Use this function after specifying all the attributes in the format.
*
* NOTE: This does NOT work when using indexed rendering.
- * NOTE: Only works for first attrib name. (this limitation can be changed if needed)
+ * NOTE: Only works for first attribute name. (this limitation can be changed if needed)
*
- * WARNING: this function creates a lot of aliases/attribs, make sure to keep the attrib name
- * short to avoid overflowing the namebuffer.
+ * WARNING: this function creates a lot of aliases/attributes, make sure to keep the attribute
+ * name short to avoid overflowing the name-buffer.
* */
void GPU_vertformat_multiload_enable(GPUVertFormat *format, int load_count)
{
@@ -276,28 +277,26 @@ static void safe_bytes(char out[11], const char data[8])
/* Warning: Always add a prefix to the result of this function as
* the generated string can start with a number and not be a valid attribute name. */
-void GPU_vertformat_safe_attrib_name(const char *attrib_name,
- char *r_safe_name,
- uint UNUSED(max_len))
+void GPU_vertformat_safe_attr_name(const char *attr_name, char *r_safe_name, uint UNUSED(max_len))
{
char data[8] = {0};
- uint len = strlen(attrib_name);
+ uint len = strlen(attr_name);
if (len > 8) {
/* Start with the first 4 chars of the name; */
for (int i = 0; i < 4; i++) {
- data[i] = attrib_name[i];
+ data[i] = attr_name[i];
}
/* We use a hash to identify each data layer based on its name.
* NOTE: This is still prone to hash collision but the risks are very low.*/
/* Start hashing after the first 2 chars. */
- *(uint *)&data[4] = BLI_ghashutil_strhash_p_murmur(attrib_name + 4);
+ *(uint *)&data[4] = BLI_ghashutil_strhash_p_murmur(attr_name + 4);
}
else {
/* Copy the whole name. Collision is barely possible
* (hash would have to be equal to the last 4 bytes). */
- for (int i = 0; i < 8 && attrib_name[i] != '\0'; i++) {
- data[i] = attrib_name[i];
+ for (int i = 0; i < 8 && attr_name[i] != '\0'; i++) {
+ data[i] = attr_name[i];
}
}
/* Convert to safe bytes characters. */
@@ -305,9 +304,9 @@ void GPU_vertformat_safe_attrib_name(const char *attrib_name,
/* End the string */
r_safe_name[11] = '\0';
- BLI_assert(GPU_MAX_SAFE_ATTRIB_NAME >= 12);
+ BLI_assert(GPU_MAX_SAFE_ATTR_NAME >= 12);
#if 0 /* For debugging */
- printf("%s > %lx > %s\n", attrib_name, *(uint64_t *)data, r_safe_name);
+ printf("%s > %lx > %s\n", attr_name, *(uint64_t *)data, r_safe_name);
#endif
}
@@ -316,13 +315,13 @@ void GPU_vertformat_safe_attrib_name(const char *attrib_name,
* Use direct buffer access to fill the data.
* This is for advanced usage.
*
- * Deinterleaved data means all attrib data for each attrib
- * is stored continuously like this :
+ * De-interleaved data means all attribute data for each attribute
+ * is stored continuously like this:
* 000011112222
* instead of :
* 012012012012
*
- * Note this is per attrib deinterleaving, NOT per component.
+ * Note this is per attribute de-interleaving, NOT per component.
* */
void GPU_vertformat_deinterleave(GPUVertFormat *format)
{
@@ -393,38 +392,37 @@ void VertexFormat_pack(GPUVertFormat *format)
format->packed = true;
}
-static uint calc_input_component_size(const GPUShaderInput *input)
+static uint calc_component_size(const GLenum gl_type)
{
- int size = input->size;
- switch (input->gl_type) {
+ switch (gl_type) {
case GL_FLOAT_VEC2:
case GL_INT_VEC2:
case GL_UNSIGNED_INT_VEC2:
- return size * 2;
+ return 2;
case GL_FLOAT_VEC3:
case GL_INT_VEC3:
case GL_UNSIGNED_INT_VEC3:
- return size * 3;
+ return 3;
case GL_FLOAT_VEC4:
case GL_FLOAT_MAT2:
case GL_INT_VEC4:
case GL_UNSIGNED_INT_VEC4:
- return size * 4;
+ return 4;
case GL_FLOAT_MAT3:
- return size * 9;
+ return 9;
case GL_FLOAT_MAT4:
- return size * 16;
+ return 16;
case GL_FLOAT_MAT2x3:
case GL_FLOAT_MAT3x2:
- return size * 6;
+ return 6;
case GL_FLOAT_MAT2x4:
case GL_FLOAT_MAT4x2:
- return size * 8;
+ return 8;
case GL_FLOAT_MAT3x4:
case GL_FLOAT_MAT4x3:
- return size * 12;
+ return 12;
default:
- return size;
+ return 1;
}
}
@@ -468,42 +466,39 @@ static void get_fetch_mode_and_comp_type(int gl_type,
}
}
-void GPU_vertformat_from_interface(GPUVertFormat *format, const GPUShaderInterface *shaderface)
+void GPU_vertformat_from_shader(GPUVertFormat *format, const GPUShader *shader)
{
- const char *name_buffer = shaderface->name_buffer;
-
- for (int i = 0; i < GPU_NUM_SHADERINTERFACE_BUCKETS; i++) {
- const GPUShaderInput *input = shaderface->attr_buckets[i];
- if (input == NULL) {
- continue;
- }
+ GPU_vertformat_clear(format);
+ GPUVertAttr *attr = &format->attrs[0];
- const GPUShaderInput *next = input;
- while (next != NULL) {
- input = next;
- next = input->next;
+ GLint attr_len;
+ glGetProgramiv(shader->program, GL_ACTIVE_ATTRIBUTES, &attr_len);
- /* OpenGL attributes such as `gl_VertexID` have a location of -1. */
- if (input->location < 0) {
- continue;
- }
-
- format->name_len++; /* multiname support */
- format->attr_len++;
-
- GPUVertCompType comp_type;
- GPUVertFetchMode fetch_mode;
- get_fetch_mode_and_comp_type(input->gl_type, &comp_type, &fetch_mode);
+ for (int i = 0; i < attr_len; i++) {
+ char name[256];
+ GLenum gl_type;
+ GLint size;
+ glGetActiveAttrib(shader->program, i, sizeof(name), NULL, &size, &gl_type, name);
- GPUVertAttr *attr = &format->attrs[input->location];
-
- attr->names[attr->name_len++] = copy_attr_name(format, name_buffer + input->name_offset);
- attr->offset = 0; /* offsets & stride are calculated later (during pack) */
- attr->comp_len = calc_input_component_size(input);
- attr->sz = attr->comp_len * 4;
- attr->fetch_mode = fetch_mode;
- attr->comp_type = comp_type;
- attr->gl_comp_type = convert_comp_type_to_gl(comp_type);
+ /* Ignore OpenGL names like `gl_BaseInstanceARB`, `gl_InstanceID` and `gl_VertexID`. */
+ if (glGetAttribLocation(shader->program, name) == -1) {
+ continue;
}
+
+ format->name_len++; /* multiname support */
+ format->attr_len++;
+
+ GPUVertCompType comp_type;
+ GPUVertFetchMode fetch_mode;
+ get_fetch_mode_and_comp_type(gl_type, &comp_type, &fetch_mode);
+
+ attr->names[attr->name_len++] = copy_attr_name(format, name);
+ attr->offset = 0; /* offsets & stride are calculated later (during pack) */
+ attr->comp_len = calc_component_size(gl_type) * size;
+ attr->sz = attr->comp_len * 4;
+ attr->fetch_mode = fetch_mode;
+ attr->comp_type = comp_type;
+ attr->gl_comp_type = convert_comp_type_to_gl(comp_type);
+ attr += 1;
}
}
diff --git a/source/blender/gpu/intern/gpu_viewport.c b/source/blender/gpu/intern/gpu_viewport.c
index 57efaf99b8b..753da8544ea 100644
--- a/source/blender/gpu/intern/gpu_viewport.c
+++ b/source/blender/gpu/intern/gpu_viewport.c
@@ -65,6 +65,24 @@ typedef struct ViewportTempTexture {
GPUTexture *texture;
} ViewportTempTexture;
+/* Struct storing a viewport specific GPUBatch.
+ * The end-goal is to have a single batch shared across viewport and use a model matrix to place
+ * the batch. Due to OCIO and Image/UV editor we are not able to use an model matrix yet. */
+struct GPUViewportBatch {
+ GPUBatch *batch;
+ struct {
+ rctf rect_pos;
+ rctf rect_uv;
+ } last_used_parameters;
+};
+
+static struct {
+ GPUVertFormat format;
+ struct {
+ uint pos, tex_coord;
+ } attr_id;
+} g_viewport = {{0}};
+
struct GPUViewport {
int size[2];
int flag;
@@ -93,10 +111,12 @@ struct GPUViewport {
/* Color management. */
ColorManagedViewSettings view_settings;
ColorManagedDisplaySettings display_settings;
+ CurveMapping *orig_curve_mapping;
float dither;
/* TODO(fclem) the uvimage display use the viewport but do not set any view transform for the
* moment. The end goal would be to let the GPUViewport do the color management. */
bool do_color_management;
+ struct GPUViewportBatch batch;
};
enum {
@@ -197,18 +217,6 @@ static void gpu_viewport_framebuffer_view_set(GPUViewport *viewport, int view)
GPU_ATTACHMENT_TEXTURE(dtxl->color_overlay),
});
- if (((viewport->flag & GPU_VIEWPORT_STEREO) != 0)) {
- GPU_framebuffer_ensure_config(&dfbl->stereo_comp_fb,
- {
- GPU_ATTACHMENT_NONE,
- GPU_ATTACHMENT_TEXTURE(dtxl->color),
- GPU_ATTACHMENT_TEXTURE(dtxl->color_overlay),
- });
- }
- else {
- dfbl->stereo_comp_fb = NULL;
- }
-
viewport->active_view = view;
}
@@ -355,7 +363,7 @@ GPUTexture *GPU_viewport_texture_pool_query(
{
GPUTexture *tex;
- for (ViewportTempTexture *tmp_tex = viewport->tex_pool.first; tmp_tex; tmp_tex = tmp_tex->next) {
+ LISTBASE_FOREACH (ViewportTempTexture *, tmp_tex, &viewport->tex_pool) {
if ((GPU_texture_format(tmp_tex->texture) == format) &&
(GPU_texture_width(tmp_tex->texture) == width) &&
(GPU_texture_height(tmp_tex->texture) == height)) {
@@ -374,12 +382,10 @@ GPUTexture *GPU_viewport_texture_pool_query(
}
tex = GPU_texture_create_2d(width, height, format, NULL, NULL);
- GPU_texture_bind(tex, 0);
/* Doing filtering for depth does not make sense when not doing shadow mapping,
* and enabling texture filtering on integer texture make them unreadable. */
bool do_filter = !GPU_texture_depth(tex) && !GPU_texture_integer(tex);
GPU_texture_filter_mode(tex, do_filter);
- GPU_texture_unbind(tex);
ViewportTempTexture *tmp_tex = MEM_callocN(sizeof(ViewportTempTexture), "ViewportTempTexture");
tmp_tex->texture = tex;
@@ -412,7 +418,7 @@ static void gpu_viewport_texture_pool_clear_users(GPUViewport *viewport)
static void gpu_viewport_texture_pool_free(GPUViewport *viewport)
{
- for (ViewportTempTexture *tmp_tex = viewport->tex_pool.first; tmp_tex; tmp_tex = tmp_tex->next) {
+ LISTBASE_FOREACH (ViewportTempTexture *, tmp_tex, &viewport->tex_pool) {
GPU_texture_free(tmp_tex->texture);
}
@@ -472,9 +478,6 @@ static void gpu_viewport_default_fb_create(GPUViewport *viewport)
ok = ok && GPU_framebuffer_check_valid(dfbl->color_only_fb, NULL);
ok = ok && GPU_framebuffer_check_valid(dfbl->depth_only_fb, NULL);
ok = ok && GPU_framebuffer_check_valid(dfbl->overlay_only_fb, NULL);
- if (((viewport->flag & GPU_VIEWPORT_STEREO) != 0)) {
- ok = ok && GPU_framebuffer_check_valid(dfbl->stereo_comp_fb, NULL);
- }
cleanup:
if (!ok) {
GPU_viewport_free(viewport);
@@ -552,8 +555,43 @@ void GPU_viewport_colorspace_set(GPUViewport *viewport,
ColorManagedDisplaySettings *display_settings,
float dither)
{
- memcpy(&viewport->view_settings, view_settings, sizeof(*view_settings));
- memcpy(&viewport->display_settings, display_settings, sizeof(*display_settings));
+ /**
+ * HACK(fclem): We copy the settings here to avoid use after free if an update frees the scene
+ * and the viewport stays cached (see T75443). But this means the OCIO curve-mapping caching
+ * (which is based on #CurveMap pointer address) cannot operate correctly and it will create
+ * a different OCIO processor for each viewport. We try to only reallocate the curve-map copy
+ * if needed to avoid unneeded cache invalidation.
+ */
+ if (view_settings->curve_mapping) {
+ if (viewport->view_settings.curve_mapping) {
+ if (view_settings->curve_mapping->changed_timestamp !=
+ viewport->view_settings.curve_mapping->changed_timestamp) {
+ BKE_color_managed_view_settings_free(&viewport->view_settings);
+ }
+ }
+ }
+
+ if (viewport->orig_curve_mapping != view_settings->curve_mapping) {
+ viewport->orig_curve_mapping = view_settings->curve_mapping;
+ BKE_color_managed_view_settings_free(&viewport->view_settings);
+ }
+ /* Don't copy the curve mapping already. */
+ CurveMapping *tmp_curve_mapping = view_settings->curve_mapping;
+ CurveMapping *tmp_curve_mapping_vp = viewport->view_settings.curve_mapping;
+ view_settings->curve_mapping = NULL;
+ viewport->view_settings.curve_mapping = NULL;
+
+ BKE_color_managed_view_settings_copy(&viewport->view_settings, view_settings);
+ /* Restore. */
+ view_settings->curve_mapping = tmp_curve_mapping;
+ viewport->view_settings.curve_mapping = tmp_curve_mapping_vp;
+ /* Only copy curvemapping if needed. Avoid uneeded OCIO cache miss. */
+ if (tmp_curve_mapping && viewport->view_settings.curve_mapping == NULL) {
+ BKE_color_managed_view_settings_free(&viewport->view_settings);
+ viewport->view_settings.curve_mapping = BKE_curvemapping_copy(tmp_curve_mapping);
+ }
+
+ BKE_color_managed_display_settings_copy(&viewport->display_settings, display_settings);
viewport->dither = dither;
viewport->do_color_management = true;
}
@@ -570,6 +608,14 @@ void GPU_viewport_stereo_composite(GPUViewport *viewport, Stereo3dFormat *stereo
DefaultTextureList *dtxl = viewport->txl;
DefaultFramebufferList *dfbl = viewport->fbl;
+ /* The composite framebuffer object needs to be created in the window context. */
+ GPU_framebuffer_ensure_config(&dfbl->stereo_comp_fb,
+ {
+ GPU_ATTACHMENT_NONE,
+ GPU_ATTACHMENT_TEXTURE(dtxl->color),
+ GPU_ATTACHMENT_TEXTURE(dtxl->color_overlay),
+ });
+
GPUVertFormat *vert_format = immVertexFormat();
uint pos = GPU_vertformat_attr_add(vert_format, "pos", GPU_COMP_F32, 2, GPU_FETCH_FLOAT);
GPU_framebuffer_bind(dfbl->stereo_comp_fb);
@@ -625,6 +671,76 @@ void GPU_viewport_stereo_composite(GPUViewport *viewport, Stereo3dFormat *stereo
GPU_framebuffer_restore();
}
+/* -------------------------------------------------------------------- */
+/** \name Viewport Batches
+ * \{ */
+
+static GPUVertFormat *gpu_viewport_batch_format(void)
+{
+ if (g_viewport.format.attr_len == 0) {
+ GPUVertFormat *format = &g_viewport.format;
+ g_viewport.attr_id.pos = GPU_vertformat_attr_add(
+ format, "pos", GPU_COMP_F32, 2, GPU_FETCH_FLOAT);
+ g_viewport.attr_id.tex_coord = GPU_vertformat_attr_add(
+ format, "texCoord", GPU_COMP_F32, 2, GPU_FETCH_FLOAT);
+ }
+ return &g_viewport.format;
+}
+
+static GPUBatch *gpu_viewport_batch_create(const rctf *rect_pos, const rctf *rect_uv)
+{
+ GPUVertBuf *vbo = GPU_vertbuf_create_with_format(gpu_viewport_batch_format());
+ const uint vbo_len = 4;
+ GPU_vertbuf_data_alloc(vbo, vbo_len);
+
+ GPUVertBufRaw pos_step, tex_coord_step;
+ GPU_vertbuf_attr_get_raw_data(vbo, g_viewport.attr_id.pos, &pos_step);
+ GPU_vertbuf_attr_get_raw_data(vbo, g_viewport.attr_id.tex_coord, &tex_coord_step);
+
+ copy_v2_fl2(GPU_vertbuf_raw_step(&pos_step), rect_pos->xmin, rect_pos->ymin);
+ copy_v2_fl2(GPU_vertbuf_raw_step(&tex_coord_step), rect_uv->xmin, rect_uv->ymin);
+ copy_v2_fl2(GPU_vertbuf_raw_step(&pos_step), rect_pos->xmax, rect_pos->ymin);
+ copy_v2_fl2(GPU_vertbuf_raw_step(&tex_coord_step), rect_uv->xmax, rect_uv->ymin);
+ copy_v2_fl2(GPU_vertbuf_raw_step(&pos_step), rect_pos->xmin, rect_pos->ymax);
+ copy_v2_fl2(GPU_vertbuf_raw_step(&tex_coord_step), rect_uv->xmin, rect_uv->ymax);
+ copy_v2_fl2(GPU_vertbuf_raw_step(&pos_step), rect_pos->xmax, rect_pos->ymax);
+ copy_v2_fl2(GPU_vertbuf_raw_step(&tex_coord_step), rect_uv->xmax, rect_uv->ymax);
+
+ return GPU_batch_create_ex(GPU_PRIM_TRI_STRIP, vbo, NULL, GPU_BATCH_OWNS_VBO);
+}
+
+static GPUBatch *gpu_viewport_batch_get(GPUViewport *viewport,
+ const rctf *rect_pos,
+ const rctf *rect_uv)
+{
+ const float compare_limit = 0.0001f;
+ const bool parameters_changed =
+ (!BLI_rctf_compare(
+ &viewport->batch.last_used_parameters.rect_pos, rect_pos, compare_limit) ||
+ !BLI_rctf_compare(&viewport->batch.last_used_parameters.rect_uv, rect_uv, compare_limit));
+
+ if (viewport->batch.batch && parameters_changed) {
+ GPU_batch_discard(viewport->batch.batch);
+ viewport->batch.batch = NULL;
+ }
+
+ if (!viewport->batch.batch) {
+ viewport->batch.batch = gpu_viewport_batch_create(rect_pos, rect_uv);
+ viewport->batch.last_used_parameters.rect_pos = *rect_pos;
+ viewport->batch.last_used_parameters.rect_uv = *rect_uv;
+ }
+ return viewport->batch.batch;
+}
+
+static void gpu_viewport_batch_free(GPUViewport *viewport)
+{
+ if (viewport->batch.batch) {
+ GPU_batch_discard(viewport->batch.batch);
+ viewport->batch.batch = NULL;
+ }
+}
+
+/** \} */
static void gpu_viewport_draw_colormanaged(GPUViewport *viewport,
const rctf *rect_pos,
@@ -635,13 +751,17 @@ static void gpu_viewport_draw_colormanaged(GPUViewport *viewport,
GPUTexture *color = dtxl->color;
GPUTexture *color_overlay = dtxl->color_overlay;
- GPUVertFormat *vert_format = immVertexFormat();
- uint pos = GPU_vertformat_attr_add(vert_format, "pos", GPU_COMP_F32, 2, GPU_FETCH_FLOAT);
- uint texco = GPU_vertformat_attr_add(vert_format, "texCoord", GPU_COMP_F32, 2, GPU_FETCH_FLOAT);
-
bool use_ocio = false;
if (viewport->do_color_management && display_colorspace) {
+ /* During the binding process the last used VertexFormat is tested and can assert as it is not
+ * valid. By calling the `immVertexFormat` the last used VertexFormat is reset and the assert
+ * does not happen. This solves a chicken and egg problem when using GPUBatches. GPUBatches
+ * contain the correct vertex format, but can only bind after the shader is bound.
+ *
+ * Image/UV editor still uses imm, after that has been changed we could move this fix to the
+ * OCIO. */
+ immVertexFormat();
use_ocio = IMB_colormanagement_setup_glsl_draw_from_space(&viewport->view_settings,
&viewport->display_settings,
NULL,
@@ -650,38 +770,26 @@ static void gpu_viewport_draw_colormanaged(GPUViewport *viewport,
true);
}
- if (!use_ocio) {
- immBindBuiltinProgram(GPU_SHADER_2D_IMAGE_OVERLAYS_MERGE);
- immUniform1i("display_transform", display_colorspace);
- immUniform1i("image_texture", 0);
- immUniform1i("overlays_texture", 1);
+ GPUBatch *batch = gpu_viewport_batch_get(viewport, rect_pos, rect_uv);
+ if (use_ocio) {
+ GPU_batch_program_set_imm_shader(batch);
+ }
+ else {
+ GPU_batch_program_set_builtin(batch, GPU_SHADER_2D_IMAGE_OVERLAYS_MERGE);
+ GPU_batch_uniform_1i(batch, "display_transform", display_colorspace);
+ GPU_batch_uniform_1i(batch, "image_texture", 0);
+ GPU_batch_uniform_1i(batch, "overlays_texture", 1);
}
GPU_texture_bind(color, 0);
GPU_texture_bind(color_overlay, 1);
-
- immBegin(GPU_PRIM_TRI_STRIP, 4);
-
- immAttr2f(texco, rect_uv->xmin, rect_uv->ymin);
- immVertex2f(pos, rect_pos->xmin, rect_pos->ymin);
- immAttr2f(texco, rect_uv->xmax, rect_uv->ymin);
- immVertex2f(pos, rect_pos->xmax, rect_pos->ymin);
- immAttr2f(texco, rect_uv->xmin, rect_uv->ymax);
- immVertex2f(pos, rect_pos->xmin, rect_pos->ymax);
- immAttr2f(texco, rect_uv->xmax, rect_uv->ymax);
- immVertex2f(pos, rect_pos->xmax, rect_pos->ymax);
-
- immEnd();
-
+ GPU_batch_draw(batch);
GPU_texture_unbind(color);
GPU_texture_unbind(color_overlay);
if (use_ocio) {
IMB_colormanagement_finish_glsl_draw();
}
- else {
- immUnbindProgram();
- }
}
/**
@@ -745,8 +853,8 @@ void GPU_viewport_draw_to_screen_ex(GPUViewport *viewport,
* Merge and draw the buffers of \a viewport into the currently active framebuffer, performing
* color transform to display space.
*
- * \param rect: Coordinates to draw into. By swapping min and max values, drawing can be done with
- * inversed axis coordinates (upside down or sideways).
+ * \param rect: Coordinates to draw into. By swapping min and max values, drawing can be done
+ * with inversed axis coordinates (upside down or sideways).
*/
void GPU_viewport_draw_to_screen(GPUViewport *viewport, int view, const rcti *rect)
{
@@ -923,5 +1031,8 @@ void GPU_viewport_free(GPUViewport *viewport)
DRW_instance_data_list_free(viewport->idatalist);
MEM_freeN(viewport->idatalist);
+ BKE_color_managed_view_settings_free(&viewport->view_settings);
+ gpu_viewport_batch_free(viewport);
+
MEM_freeN(viewport);
}
diff --git a/source/blender/gpu/shaders/gpu_shader_2D_smooth_color_dithered_frag.glsl b/source/blender/gpu/shaders/gpu_shader_2D_smooth_color_dithered_frag.glsl
deleted file mode 100644
index 181b1bf3fad..00000000000
--- a/source/blender/gpu/shaders/gpu_shader_2D_smooth_color_dithered_frag.glsl
+++ /dev/null
@@ -1,18 +0,0 @@
-
-noperspective in vec4 finalColor;
-out vec4 fragColor;
-
-/* 4x4 bayer matrix prepared for 8bit UNORM precision error. */
-#define P(x) (((x + 0.5) * (1.0 / 16.0) - 0.5) * (1.0 / 255.0))
-const vec4 dither_mat4x4[4] = vec4[4](vec4(P(0.0), P(8.0), P(2.0), P(10.0)),
- vec4(P(12.0), P(4.0), P(14.0), P(6.0)),
- vec4(P(3.0), P(11.0), P(1.0), P(9.0)),
- vec4(P(15.0), P(7.0), P(13.0), P(5.0)));
-
-void main()
-{
- ivec2 tx1 = ivec2(gl_FragCoord.xy) % 4;
- ivec2 tx2 = ivec2(gl_FragCoord.xy) % 2;
- float dither_noise = dither_mat4x4[tx1.x][tx1.y];
- fragColor = finalColor + dither_noise;
-}
diff --git a/source/blender/gpu/shaders/gpu_shader_2D_smooth_color_frag.glsl b/source/blender/gpu/shaders/gpu_shader_2D_smooth_color_frag.glsl
index 4f275c5b220..1333c00682c 100644
--- a/source/blender/gpu/shaders/gpu_shader_2D_smooth_color_frag.glsl
+++ b/source/blender/gpu/shaders/gpu_shader_2D_smooth_color_frag.glsl
@@ -5,4 +5,5 @@ out vec4 fragColor;
void main()
{
fragColor = finalColor;
+ fragColor = blender_srgb_to_framebuffer_space(fragColor);
}
diff --git a/source/blender/gpu/shaders/gpu_shader_2D_widget_base_frag.glsl b/source/blender/gpu/shaders/gpu_shader_2D_widget_base_frag.glsl
index 18f58d52f32..bdc87baf924 100644
--- a/source/blender/gpu/shaders/gpu_shader_2D_widget_base_frag.glsl
+++ b/source/blender/gpu/shaders/gpu_shader_2D_widget_base_frag.glsl
@@ -35,4 +35,6 @@ void main()
if (butCo > 0.0) {
fragColor.a = 1.0;
}
+
+ fragColor = blender_srgb_to_framebuffer_space(fragColor);
}
diff --git a/source/blender/gpu/shaders/gpu_shader_2D_widget_base_vert.glsl b/source/blender/gpu/shaders/gpu_shader_2D_widget_base_vert.glsl
index 0b2bc08944e..d7cc851556b 100644
--- a/source/blender/gpu/shaders/gpu_shader_2D_widget_base_vert.glsl
+++ b/source/blender/gpu/shaders/gpu_shader_2D_widget_base_vert.glsl
@@ -12,42 +12,15 @@
/* 4bits for corner id */
#define CORNER_VEC_OFS 2u
#define CORNER_VEC_RANGE BIT_RANGE(4)
-const vec2 cornervec[36] = vec2[36](vec2(0.0, 1.0),
- vec2(0.02, 0.805),
- vec2(0.067, 0.617),
- vec2(0.169, 0.45),
- vec2(0.293, 0.293),
- vec2(0.45, 0.169),
- vec2(0.617, 0.076),
- vec2(0.805, 0.02),
- vec2(1.0, 0.0),
- vec2(-1.0, 0.0),
- vec2(-0.805, 0.02),
- vec2(-0.617, 0.067),
- vec2(-0.45, 0.169),
- vec2(-0.293, 0.293),
- vec2(-0.169, 0.45),
- vec2(-0.076, 0.617),
- vec2(-0.02, 0.805),
- vec2(0.0, 1.0),
- vec2(0.0, -1.0),
- vec2(-0.02, -0.805),
- vec2(-0.067, -0.617),
- vec2(-0.169, -0.45),
- vec2(-0.293, -0.293),
- vec2(-0.45, -0.169),
- vec2(-0.617, -0.076),
- vec2(-0.805, -0.02),
- vec2(-1.0, 0.0),
- vec2(1.0, 0.0),
- vec2(0.805, -0.02),
- vec2(0.617, -0.067),
- vec2(0.45, -0.169),
- vec2(0.293, -0.293),
- vec2(0.169, -0.45),
- vec2(0.076, -0.617),
- vec2(0.02, -0.805),
- vec2(0.0, -1.0));
+const vec2 cornervec[9] = vec2[9](vec2(0.0, 1.0),
+ vec2(0.02, 0.805),
+ vec2(0.067, 0.617),
+ vec2(0.169, 0.45),
+ vec2(0.293, 0.293),
+ vec2(0.45, 0.169),
+ vec2(0.617, 0.076),
+ vec2(0.805, 0.02),
+ vec2(1.0, 0.0));
/* 4bits for jitter id */
#define JIT_OFS 6u
@@ -189,26 +162,26 @@ vec2 do_widget(void)
{
uint cflag = vflag & CNR_FLAG_RANGE;
uint vofs = (vflag >> CORNER_VEC_OFS) & CORNER_VEC_RANGE;
-
- vec2 v = cornervec[cflag * 9u + vofs];
-
bool is_inner = (vflag & INNER_FLAG) != 0u;
+ vec2 v = cornervec[vofs];
/* Scale by corner radius */
v *= roundCorners[cflag] * ((is_inner) ? radsi : rads);
-
- /* Position to corner */
+ /* Flip in the right direction and osition to corner */
vec4 rct = (is_inner) ? recti : rect;
if (cflag == BOTTOM_LEFT) {
v += rct.xz;
}
else if (cflag == BOTTOM_RIGHT) {
+ v = vec2(-v.y, v.x);
v += rct.yz;
}
else if (cflag == TOP_RIGHT) {
+ v = -v;
v += rct.yw;
}
else /* (cflag == TOP_LEFT) */ {
+ v = vec2(v.y, -v.x);
v += rct.xw;
}
@@ -238,7 +211,7 @@ vec2 do_widget(void)
}
bool is_emboss = (vflag & EMBOSS_FLAG) != 0u;
- v.y -= (is_emboss) ? 1.0f : 0.0;
+ v.y -= (is_emboss) ? (recti.z - rect.z) : 0.0;
return v;
}
diff --git a/source/blender/gpu/shaders/gpu_shader_3D_normal_smooth_color_vert.glsl b/source/blender/gpu/shaders/gpu_shader_3D_normal_smooth_color_vert.glsl
deleted file mode 100644
index 7fa571343a2..00000000000
--- a/source/blender/gpu/shaders/gpu_shader_3D_normal_smooth_color_vert.glsl
+++ /dev/null
@@ -1,22 +0,0 @@
-
-uniform mat4 ModelViewProjectionMatrix;
-uniform mat3 NormalMatrix;
-
-in vec3 pos;
-in vec3 nor;
-in vec4 color;
-
-#ifdef USE_FLAT_NORMAL
-flat out vec3 normal;
-flat out vec4 finalColor;
-#else
-out vec3 normal;
-out vec4 finalColor;
-#endif
-
-void main()
-{
- normal = normalize(NormalMatrix * nor);
- gl_Position = ModelViewProjectionMatrix * vec4(pos, 1.0);
- finalColor = color;
-}
diff --git a/source/blender/gpu/shaders/gpu_shader_3D_polyline_frag.glsl b/source/blender/gpu/shaders/gpu_shader_3D_polyline_frag.glsl
new file mode 100644
index 00000000000..9c6b109d659
--- /dev/null
+++ b/source/blender/gpu/shaders/gpu_shader_3D_polyline_frag.glsl
@@ -0,0 +1,24 @@
+
+uniform float lineWidth;
+
+in vec4 finalColor;
+noperspective in float smoothline;
+#ifdef CLIP
+in float clip;
+#endif
+
+out vec4 fragColor;
+
+#define SMOOTH_WIDTH 1.0
+
+void main()
+{
+#ifdef CLIP
+ if (clip < 0.0) {
+ discard;
+ }
+#endif
+ fragColor = finalColor;
+ fragColor.a *= clamp((lineWidth + SMOOTH_WIDTH) * 0.5 - abs(smoothline), 0.0, 1.0);
+ fragColor = blender_srgb_to_framebuffer_space(fragColor);
+}
diff --git a/source/blender/gpu/shaders/gpu_shader_3D_polyline_geom.glsl b/source/blender/gpu/shaders/gpu_shader_3D_polyline_geom.glsl
new file mode 100644
index 00000000000..b28205b349e
--- /dev/null
+++ b/source/blender/gpu/shaders/gpu_shader_3D_polyline_geom.glsl
@@ -0,0 +1,68 @@
+
+layout(lines) in;
+layout(triangle_strip, max_vertices = 4) out;
+
+uniform vec4 color;
+uniform vec2 viewportSize;
+uniform float lineWidth;
+
+#if !defined(UNIFORM)
+in vec4 finalColor_g[];
+#endif
+
+#ifdef CLIP
+in float clip_g[];
+out float clip;
+#endif
+
+out vec4 finalColor;
+noperspective out float smoothline;
+
+#define SMOOTH_WIDTH 1.0
+
+void do_vertex(const int i, vec2 ofs)
+{
+#if defined(UNIFORM)
+ finalColor = color;
+
+#elif defined(FLAT)
+ finalColor = finalColor_g[0];
+
+#elif defined(SMOOTH)
+ finalColor = finalColor_g[i];
+#endif
+
+#ifdef CLIP
+ clip = clip_g[i];
+#endif
+
+ smoothline = (lineWidth + SMOOTH_WIDTH) * 0.5;
+ gl_Position = gl_in[i].gl_Position;
+ gl_Position.xy += ofs * gl_Position.w;
+ EmitVertex();
+
+ smoothline = -(lineWidth + SMOOTH_WIDTH) * 0.5;
+ gl_Position = gl_in[i].gl_Position;
+ gl_Position.xy -= ofs * gl_Position.w;
+ EmitVertex();
+}
+
+void main(void)
+{
+ vec2 p0 = gl_in[0].gl_Position.xy / gl_in[0].gl_Position.w;
+ vec2 p1 = gl_in[1].gl_Position.xy / gl_in[1].gl_Position.w;
+ vec2 e = normalize((p1 - p0) * viewportSize.xy);
+#if 0 /* Hard turn when line direction changes quadrant. */
+ e = abs(e);
+ vec2 ofs = (e.x > e.y) ? vec2(0.0, 1.0 / e.x) : vec2(1.0 / e.y, 0.0);
+#else /* Use perpendicular direction. */
+ vec2 ofs = vec2(-e.y, e.x);
+#endif
+ ofs /= viewportSize.xy;
+ ofs *= lineWidth + SMOOTH_WIDTH;
+
+ do_vertex(0, ofs);
+ do_vertex(1, ofs);
+
+ EndPrimitive();
+}
diff --git a/source/blender/gpu/shaders/gpu_shader_3D_polyline_vert.glsl b/source/blender/gpu/shaders/gpu_shader_3D_polyline_vert.glsl
new file mode 100644
index 00000000000..28aa2a4ccc6
--- /dev/null
+++ b/source/blender/gpu/shaders/gpu_shader_3D_polyline_vert.glsl
@@ -0,0 +1,28 @@
+
+uniform mat4 ModelViewProjectionMatrix;
+uniform mat4 ModelMatrix;
+uniform vec4 ClipPlane;
+
+in vec3 pos;
+
+#if !defined(UNIFORM)
+in vec4 color;
+
+out vec4 finalColor_g;
+#endif
+
+#ifdef CLIP
+out float clip_g;
+#endif
+
+void main()
+{
+ gl_Position = ModelViewProjectionMatrix * vec4(pos, 1.0);
+#if !defined(UNIFORM)
+ finalColor_g = color;
+#endif
+
+#ifdef CLIP
+ clip_g = dot(ModelMatrix * vec4(pos, 1.0), ClipPlane);
+#endif
+}
diff --git a/source/blender/gpu/shaders/gpu_shader_3D_smooth_color_frag.glsl b/source/blender/gpu/shaders/gpu_shader_3D_smooth_color_frag.glsl
index 7bd44ba9b88..3a2d96c9929 100644
--- a/source/blender/gpu/shaders/gpu_shader_3D_smooth_color_frag.glsl
+++ b/source/blender/gpu/shaders/gpu_shader_3D_smooth_color_frag.glsl
@@ -5,4 +5,5 @@ out vec4 fragColor;
void main()
{
fragColor = finalColor;
+ fragColor = blender_srgb_to_framebuffer_space(fragColor);
}
diff --git a/source/blender/gpu/shaders/gpu_shader_colorspace_lib.glsl b/source/blender/gpu/shaders/gpu_shader_colorspace_lib.glsl
new file mode 100644
index 00000000000..aae659516bb
--- /dev/null
+++ b/source/blender/gpu/shaders/gpu_shader_colorspace_lib.glsl
@@ -0,0 +1,16 @@
+
+/* Undefine the macro that avoids compilation errors. */
+#undef blender_srgb_to_framebuffer_space
+
+uniform bool srgbTarget = false;
+
+vec4 blender_srgb_to_framebuffer_space(vec4 color)
+{
+ if (srgbTarget) {
+ vec3 c = max(color.rgb, vec3(0.0));
+ vec3 c1 = c * (1.0 / 12.92);
+ vec3 c2 = pow((c + 0.055) * (1.0 / 1.055), vec3(2.4));
+ color.rgb = mix(c1, c2, step(vec3(0.04045), c));
+ }
+ return color;
+}
diff --git a/source/blender/gpu/shaders/gpu_shader_flat_color_frag.glsl b/source/blender/gpu/shaders/gpu_shader_flat_color_frag.glsl
index 6c214534812..99d8b6ab685 100644
--- a/source/blender/gpu/shaders/gpu_shader_flat_color_frag.glsl
+++ b/source/blender/gpu/shaders/gpu_shader_flat_color_frag.glsl
@@ -5,4 +5,5 @@ out vec4 fragColor;
void main()
{
fragColor = finalColor;
+ fragColor = blender_srgb_to_framebuffer_space(fragColor);
}
diff --git a/source/blender/gpu/shaders/gpu_shader_image_depth_copy_frag.glsl b/source/blender/gpu/shaders/gpu_shader_image_depth_copy_frag.glsl
deleted file mode 100644
index 0f2749362b9..00000000000
--- a/source/blender/gpu/shaders/gpu_shader_image_depth_copy_frag.glsl
+++ /dev/null
@@ -1,12 +0,0 @@
-
-in vec2 texCoord_interp;
-out vec4 fragColor;
-
-uniform sampler2D image;
-
-void main()
-{
- float depth = texture(image, texCoord_interp).r;
- fragColor = vec4(depth);
- gl_FragDepth = depth;
-}
diff --git a/source/blender/gpu/shaders/gpu_shader_image_depth_linear_frag.glsl b/source/blender/gpu/shaders/gpu_shader_image_depth_linear_frag.glsl
deleted file mode 100644
index 017b21076c8..00000000000
--- a/source/blender/gpu/shaders/gpu_shader_image_depth_linear_frag.glsl
+++ /dev/null
@@ -1,16 +0,0 @@
-
-in vec2 texCoord_interp;
-out vec4 fragColor;
-
-uniform float znear;
-uniform float zfar;
-uniform sampler2D image;
-
-void main()
-{
- float depth = texture(image, texCoord_interp).r;
-
- /* normalize */
- fragColor.rgb = vec3((2.0f * znear) / (zfar + znear - (depth * (zfar - znear))));
- fragColor.a = 1.0f;
-}
diff --git a/source/blender/gpu/shaders/gpu_shader_image_multisample_resolve_frag.glsl b/source/blender/gpu/shaders/gpu_shader_image_multisample_resolve_frag.glsl
deleted file mode 100644
index ca425374a1b..00000000000
--- a/source/blender/gpu/shaders/gpu_shader_image_multisample_resolve_frag.glsl
+++ /dev/null
@@ -1,119 +0,0 @@
-
-uniform sampler2DMS depthMulti;
-uniform sampler2DMS colorMulti;
-
-out vec4 fragColor;
-
-#if SAMPLES > 16
-# error "Too many samples"
-#endif
-
-void main()
-{
- ivec2 texel = ivec2(gl_FragCoord.xy);
-
- bvec4 b1, b2, b3, b4;
- vec4 w1, w2, w3, w4;
- vec4 d1, d2, d3, d4;
- vec4 c1, c2, c3, c4, c5, c6, c7, c8;
- vec4 c9, c10, c11, c12, c13, c14, c15, c16;
- d1 = d2 = d3 = d4 = vec4(0.5);
- w1 = w2 = w3 = w4 = vec4(0.0);
- c1 = c2 = c3 = c4 = c5 = c6 = c7 = c8 = vec4(0.0);
- c9 = c10 = c11 = c12 = c13 = c14 = c15 = c16 = vec4(0.0);
-
-#ifdef USE_DEPTH
- /* Depth */
- d1.x = texelFetch(depthMulti, texel, 0).r;
- d1.y = texelFetch(depthMulti, texel, 1).r;
-# if SAMPLES > 2
- d1.z = texelFetch(depthMulti, texel, 2).r;
- d1.w = texelFetch(depthMulti, texel, 3).r;
-# endif
-# if SAMPLES > 4
- d2.x = texelFetch(depthMulti, texel, 4).r;
- d2.y = texelFetch(depthMulti, texel, 5).r;
- d2.z = texelFetch(depthMulti, texel, 6).r;
- d2.w = texelFetch(depthMulti, texel, 7).r;
-# endif
-# if SAMPLES > 8
- d3.x = texelFetch(depthMulti, texel, 8).r;
- d3.y = texelFetch(depthMulti, texel, 9).r;
- d3.z = texelFetch(depthMulti, texel, 10).r;
- d3.w = texelFetch(depthMulti, texel, 11).r;
- d4.x = texelFetch(depthMulti, texel, 12).r;
- d4.y = texelFetch(depthMulti, texel, 13).r;
- d4.z = texelFetch(depthMulti, texel, 14).r;
- d4.w = texelFetch(depthMulti, texel, 15).r;
-# endif
-#endif
-
- /* COLOR */
- b1 = notEqual(d1, vec4(1.0));
- if (any(b1)) {
- c1 = texelFetch(colorMulti, texel, 0);
- c2 = texelFetch(colorMulti, texel, 1);
-#if SAMPLES > 2
- c3 = texelFetch(colorMulti, texel, 2);
- c4 = texelFetch(colorMulti, texel, 3);
-#endif
- w1 = vec4(b1);
- }
-#if SAMPLES > 4
- b2 = notEqual(d2, vec4(1.0));
- if (any(b2)) {
- c5 = texelFetch(colorMulti, texel, 4);
- c6 = texelFetch(colorMulti, texel, 5);
- c7 = texelFetch(colorMulti, texel, 6);
- c8 = texelFetch(colorMulti, texel, 7);
- w2 = vec4(b2);
- }
-#endif
-#if SAMPLES > 8
- b3 = notEqual(d3, vec4(1.0));
- if (any(b3)) {
- c9 = texelFetch(colorMulti, texel, 8);
- c10 = texelFetch(colorMulti, texel, 9);
- c11 = texelFetch(colorMulti, texel, 10);
- c12 = texelFetch(colorMulti, texel, 11);
- w3 = vec4(b3);
- }
- b4 = notEqual(d4, vec4(1.0));
- if (any(b4)) {
- c13 = texelFetch(colorMulti, texel, 12);
- c14 = texelFetch(colorMulti, texel, 13);
- c15 = texelFetch(colorMulti, texel, 14);
- c16 = texelFetch(colorMulti, texel, 15);
- w4 = vec4(b4);
- }
-#endif
-
-#ifdef USE_DEPTH
-# if SAMPLES > 8
- d1 = min(d1, min(d3, d4));
-# endif
-# if SAMPLES > 4
- d1 = min(d1, d2);
- d1 = min(d1, d2);
-# endif
-# if SAMPLES > 2
- d1.xy = min(d1.xy, d1.zw);
-# endif
- gl_FragDepth = min(d1.x, d1.y);
-#endif
-
- c1 = c1 + c2;
-#if SAMPLES > 2
- c1 += c3 + c4;
-#endif
-#if SAMPLES > 4
- c1 += c5 + c6 + c7 + c8;
-#endif
-#if SAMPLES > 8
- c1 += c9 + c10 + c11 + c12 + c13 + c14 + c15 + c16;
-#endif
-
- const float inv_samples = 1.0 / float(SAMPLES);
-
- fragColor = c1 * inv_samples;
-}
diff --git a/source/blender/gpu/shaders/gpu_shader_simple_lighting_smooth_color_alpha_frag.glsl b/source/blender/gpu/shaders/gpu_shader_simple_lighting_smooth_color_alpha_frag.glsl
deleted file mode 100644
index 2ed99be2bcf..00000000000
--- a/source/blender/gpu/shaders/gpu_shader_simple_lighting_smooth_color_alpha_frag.glsl
+++ /dev/null
@@ -1,14 +0,0 @@
-
-uniform vec3 light;
-uniform float alpha;
-uniform float global;
-
-in vec3 normal;
-in vec4 finalColor;
-out vec4 fragColor;
-
-void main()
-{
- fragColor = finalColor * (global + (1.0 - global) * max(0.0, dot(normalize(normal), light)));
- fragColor.a = alpha;
-}
diff --git a/source/blender/gpu/shaders/gpu_shader_simple_lighting_smooth_color_frag.glsl b/source/blender/gpu/shaders/gpu_shader_simple_lighting_smooth_color_frag.glsl
deleted file mode 100644
index 738b0d84e51..00000000000
--- a/source/blender/gpu/shaders/gpu_shader_simple_lighting_smooth_color_frag.glsl
+++ /dev/null
@@ -1,16 +0,0 @@
-
-uniform vec3 light;
-
-#ifdef USE_FLAT_NORMAL
-flat in vec3 normal;
-flat in vec4 finalColor;
-#else
-in vec3 normal;
-in vec4 finalColor;
-#endif
-out vec4 fragColor;
-
-void main()
-{
- fragColor = finalColor * max(0.0, dot(normalize(normal), light));
-}
diff --git a/source/blender/gpu/shaders/gpu_shader_uniform_color_frag.glsl b/source/blender/gpu/shaders/gpu_shader_uniform_color_frag.glsl
index cfa82572e87..2033401db67 100644
--- a/source/blender/gpu/shaders/gpu_shader_uniform_color_frag.glsl
+++ b/source/blender/gpu/shaders/gpu_shader_uniform_color_frag.glsl
@@ -17,8 +17,5 @@ void main()
#else
fragColor = color;
#endif
-
-#if defined(USE_BACKGROUND)
- gl_FragDepth = 1.0;
-#endif
+ fragColor = blender_srgb_to_framebuffer_space(fragColor);
}
diff --git a/source/blender/gpu/shaders/material/gpu_shader_material_fractal_noise.glsl b/source/blender/gpu/shaders/material/gpu_shader_material_fractal_noise.glsl
index 701b07b4aae..f25691c1a83 100644
--- a/source/blender/gpu/shaders/material/gpu_shader_material_fractal_noise.glsl
+++ b/source/blender/gpu/shaders/material/gpu_shader_material_fractal_noise.glsl
@@ -1,111 +1,115 @@
/* The fractal_noise functions are all exactly the same except for the input type. */
-float fractal_noise(float p, float octaves)
+float fractal_noise(float p, float octaves, float roughness)
{
float fscale = 1.0;
float amp = 1.0;
+ float maxamp = 0.0;
float sum = 0.0;
octaves = clamp(octaves, 0.0, 16.0);
int n = int(octaves);
for (int i = 0; i <= n; i++) {
float t = noise(fscale * p);
sum += t * amp;
- amp *= 0.5;
+ maxamp += amp;
+ amp *= clamp(roughness, 0.0, 1.0);
fscale *= 2.0;
}
float rmd = octaves - floor(octaves);
if (rmd != 0.0) {
float t = noise(fscale * p);
float sum2 = sum + t * amp;
- sum *= (float(1 << n) / float((1 << (n + 1)) - 1));
- sum2 *= (float(1 << (n + 1)) / float((1 << (n + 2)) - 1));
+ sum /= maxamp;
+ sum2 /= maxamp + amp;
return (1.0 - rmd) * sum + rmd * sum2;
}
else {
- sum *= (float(1 << n) / float((1 << (n + 1)) - 1));
- return sum;
+ return sum / maxamp;
}
}
/* The fractal_noise functions are all exactly the same except for the input type. */
-float fractal_noise(vec2 p, float octaves)
+float fractal_noise(vec2 p, float octaves, float roughness)
{
float fscale = 1.0;
float amp = 1.0;
+ float maxamp = 0.0;
float sum = 0.0;
octaves = clamp(octaves, 0.0, 16.0);
int n = int(octaves);
for (int i = 0; i <= n; i++) {
float t = noise(fscale * p);
sum += t * amp;
- amp *= 0.5;
+ maxamp += amp;
+ amp *= clamp(roughness, 0.0, 1.0);
fscale *= 2.0;
}
float rmd = octaves - floor(octaves);
if (rmd != 0.0) {
float t = noise(fscale * p);
float sum2 = sum + t * amp;
- sum *= (float(1 << n) / float((1 << (n + 1)) - 1));
- sum2 *= (float(1 << (n + 1)) / float((1 << (n + 2)) - 1));
+ sum /= maxamp;
+ sum2 /= maxamp + amp;
return (1.0 - rmd) * sum + rmd * sum2;
}
else {
- sum *= (float(1 << n) / float((1 << (n + 1)) - 1));
- return sum;
+ return sum / maxamp;
}
}
/* The fractal_noise functions are all exactly the same except for the input type. */
-float fractal_noise(vec3 p, float octaves)
+float fractal_noise(vec3 p, float octaves, float roughness)
{
float fscale = 1.0;
float amp = 1.0;
+ float maxamp = 0.0;
float sum = 0.0;
octaves = clamp(octaves, 0.0, 16.0);
int n = int(octaves);
for (int i = 0; i <= n; i++) {
float t = noise(fscale * p);
sum += t * amp;
- amp *= 0.5;
+ maxamp += amp;
+ amp *= clamp(roughness, 0.0, 1.0);
fscale *= 2.0;
}
float rmd = octaves - floor(octaves);
if (rmd != 0.0) {
float t = noise(fscale * p);
float sum2 = sum + t * amp;
- sum *= (float(1 << n) / float((1 << (n + 1)) - 1));
- sum2 *= (float(1 << (n + 1)) / float((1 << (n + 2)) - 1));
+ sum /= maxamp;
+ sum2 /= maxamp + amp;
return (1.0 - rmd) * sum + rmd * sum2;
}
else {
- sum *= (float(1 << n) / float((1 << (n + 1)) - 1));
- return sum;
+ return sum / maxamp;
}
}
/* The fractal_noise functions are all exactly the same except for the input type. */
-float fractal_noise(vec4 p, float octaves)
+float fractal_noise(vec4 p, float octaves, float roughness)
{
float fscale = 1.0;
float amp = 1.0;
+ float maxamp = 0.0;
float sum = 0.0;
octaves = clamp(octaves, 0.0, 16.0);
int n = int(octaves);
for (int i = 0; i <= n; i++) {
float t = noise(fscale * p);
sum += t * amp;
- amp *= 0.5;
+ maxamp += amp;
+ amp *= clamp(roughness, 0.0, 1.0);
fscale *= 2.0;
}
float rmd = octaves - floor(octaves);
if (rmd != 0.0) {
float t = noise(fscale * p);
float sum2 = sum + t * amp;
- sum *= (float(1 << n) / float((1 << (n + 1)) - 1));
- sum2 *= (float(1 << (n + 1)) / float((1 << (n + 2)) - 1));
+ sum /= maxamp;
+ sum2 /= maxamp + amp;
return (1.0 - rmd) * sum + rmd * sum2;
}
else {
- sum *= (float(1 << n) / float((1 << (n + 1)) - 1));
- return sum;
+ return sum / maxamp;
}
}
diff --git a/source/blender/gpu/shaders/material/gpu_shader_material_output_material.glsl b/source/blender/gpu/shaders/material/gpu_shader_material_output_material.glsl
index 62f76d46088..4cb00c15b78 100644
--- a/source/blender/gpu/shaders/material/gpu_shader_material_output_material.glsl
+++ b/source/blender/gpu/shaders/material/gpu_shader_material_output_material.glsl
@@ -1,8 +1,16 @@
-void node_output_material(Closure surface, Closure volume, vec3 displacement, out Closure result)
+void node_output_material(
+ Closure surface, Closure volume, vec3 displacement, float alpha_threshold, out Closure result)
{
#ifdef VOLUMETRICS
result = volume;
#else
result = surface;
+# if defined(USE_ALPHA_HASH)
+ /* Alpha clip emulation. */
+ if (alpha_threshold >= 0.0) {
+ float alpha = saturate(1.0 - avg(result.transmittance));
+ result.transmittance = vec3(step(alpha, alpha_threshold));
+ }
+# endif
#endif
}
diff --git a/source/blender/gpu/shaders/material/gpu_shader_material_tex_environment.glsl b/source/blender/gpu/shaders/material/gpu_shader_material_tex_environment.glsl
index 9bd36f8a757..20a65f23c05 100644
--- a/source/blender/gpu/shaders/material/gpu_shader_material_tex_environment.glsl
+++ b/source/blender/gpu/shaders/material/gpu_shader_material_tex_environment.glsl
@@ -15,16 +15,11 @@ void node_tex_environment_texco(vec3 viewvec, out vec3 worldvec)
#endif
}
-void node_tex_environment_equirectangular(vec3 co, float clamp_size, sampler2D ima, out vec3 uv)
+void node_tex_environment_equirectangular(vec3 co, out vec3 uv)
{
vec3 nco = normalize(co);
uv.x = -atan(nco.y, nco.x) / (2.0 * M_PI) + 0.5;
uv.y = atan(nco.z, hypot(nco.x, nco.y)) / M_PI + 0.5;
-
- /* Fix pole bleeding */
- float half_height = clamp_size / float(textureSize(ima, 0).y);
- uv.y = clamp(uv.y, half_height, 1.0 - half_height);
- uv.z = 0.0;
}
void node_tex_environment_mirror_ball(vec3 co, out vec3 uv)
diff --git a/source/blender/gpu/shaders/material/gpu_shader_material_tex_image.glsl b/source/blender/gpu/shaders/material/gpu_shader_material_tex_image.glsl
index c39bec8ac64..df949f7358b 100644
--- a/source/blender/gpu/shaders/material/gpu_shader_material_tex_image.glsl
+++ b/source/blender/gpu/shaders/material/gpu_shader_material_tex_image.glsl
@@ -54,19 +54,6 @@ void node_tex_image_linear(vec3 co, sampler2D ima, out vec4 color, out float alp
alpha = color.a;
}
-void node_tex_image_linear_no_mip(vec3 co, sampler2D ima, out vec4 color, out float alpha)
-{
- color = safe_color(textureLod(ima, co.xy, 0.0));
- alpha = color.a;
-}
-
-void node_tex_image_nearest(vec3 co, sampler2D ima, out vec4 color, out float alpha)
-{
- ivec2 pix = ivec2(fract(co.xy) * textureSize(ima, 0).xy);
- color = safe_color(texelFetch(ima, pix, 0));
- alpha = color.a;
-}
-
/** \param f: Signed distance to texel center. */
void cubic_bspline_coefs(vec2 f, out vec2 w0, out vec2 w1, out vec2 w2, out vec2 w3)
{
@@ -79,8 +66,7 @@ void cubic_bspline_coefs(vec2 f, out vec2 w0, out vec2 w1, out vec2 w2, out vec2
w2 = 1.0 - w0 - w1 - w3;
}
-void node_tex_image_cubic_ex(
- vec3 co, sampler2D ima, float do_extend, out vec4 color, out float alpha)
+void node_tex_image_cubic(vec3 co, sampler2D ima, out vec4 color, out float alpha)
{
vec2 tex_size = vec2(textureSize(ima, 0).xy);
@@ -101,9 +87,6 @@ void node_tex_image_cubic_ex(
final_co.xy = tc - 1.0 + f0;
final_co.zw = tc + 1.0 + f1;
- if (do_extend == 1.0) {
- final_co = clamp(final_co, vec4(0.5), tex_size.xyxy - 0.5);
- }
final_co /= tex_size.xyxy;
color = safe_color(textureLod(ima, final_co.xy, 0.0)) * s0.x * s0.y;
@@ -136,22 +119,6 @@ void node_tex_image_cubic_ex(
alpha = color.a;
}
-void node_tex_image_cubic(vec3 co, sampler2D ima, out vec4 color, out float alpha)
-{
- node_tex_image_cubic_ex(co, ima, 0.0, color, alpha);
-}
-
-void node_tex_image_cubic_extend(vec3 co, sampler2D ima, out vec4 color, out float alpha)
-{
- node_tex_image_cubic_ex(co, ima, 1.0, color, alpha);
-}
-
-void node_tex_image_smart(vec3 co, sampler2D ima, out vec4 color, out float alpha)
-{
- /* use cubic for now */
- node_tex_image_cubic_ex(co, ima, 0.0, color, alpha);
-}
-
void tex_box_sample_linear(
vec3 texco, vec3 N, sampler2D ima, out vec4 color1, out vec4 color2, out vec4 color3)
{
@@ -175,32 +142,6 @@ void tex_box_sample_linear(
color3 = texture(ima, uv);
}
-void tex_box_sample_nearest(
- vec3 texco, vec3 N, sampler2D ima, out vec4 color1, out vec4 color2, out vec4 color3)
-{
- /* X projection */
- vec2 uv = texco.yz;
- if (N.x < 0.0) {
- uv.x = 1.0 - uv.x;
- }
- ivec2 pix = ivec2(fract(uv.xy) * textureSize(ima, 0).xy);
- color1 = texelFetch(ima, pix, 0);
- /* Y projection */
- uv = texco.xz;
- if (N.y > 0.0) {
- uv.x = 1.0 - uv.x;
- }
- pix = ivec2(fract(uv.xy) * textureSize(ima, 0).xy);
- color2 = texelFetch(ima, pix, 0);
- /* Z projection */
- uv = texco.yx;
- if (N.z > 0.0) {
- uv.x = 1.0 - uv.x;
- }
- pix = ivec2(fract(uv.xy) * textureSize(ima, 0).xy);
- color3 = texelFetch(ima, pix, 0);
-}
-
void tex_box_sample_cubic(
vec3 texco, vec3 N, sampler2D ima, out vec4 color1, out vec4 color2, out vec4 color3)
{
@@ -210,36 +151,23 @@ void tex_box_sample_cubic(
if (N.x < 0.0) {
uv.x = 1.0 - uv.x;
}
- node_tex_image_cubic_ex(uv.xyy, ima, 0.0, color1, alpha);
+ node_tex_image_cubic(uv.xyy, ima, color1, alpha);
/* Y projection */
uv = texco.xz;
if (N.y > 0.0) {
uv.x = 1.0 - uv.x;
}
- node_tex_image_cubic_ex(uv.xyy, ima, 0.0, color2, alpha);
+ node_tex_image_cubic(uv.xyy, ima, color2, alpha);
/* Z projection */
uv = texco.yx;
if (N.z > 0.0) {
uv.x = 1.0 - uv.x;
}
- node_tex_image_cubic_ex(uv.xyy, ima, 0.0, color3, alpha);
+ node_tex_image_cubic(uv.xyy, ima, color3, alpha);
}
-void tex_box_sample_smart(
- vec3 texco, vec3 N, sampler2D ima, out vec4 color1, out vec4 color2, out vec4 color3)
-{
- tex_box_sample_cubic(texco, N, ima, color1, color2, color3);
-}
-
-void node_tex_image_box(vec3 texco,
- vec3 N,
- vec4 color1,
- vec4 color2,
- vec4 color3,
- sampler2D ima,
- float blend,
- out vec4 color,
- out float alpha)
+void tex_box_blend(
+ vec3 N, vec4 color1, vec4 color2, vec4 color3, float blend, out vec4 color, out float alpha)
{
/* project from direction vector to barycentric coordinates in triangles */
N = abs(N);
@@ -284,70 +212,6 @@ void node_tex_image_box(vec3 texco,
alpha = color.a;
}
-void tex_clip_linear(vec3 co, sampler2D ima, vec4 icolor, out vec4 color, out float alpha)
-{
- vec2 tex_size = vec2(textureSize(ima, 0).xy);
- vec2 minco = min(co.xy, 1.0 - co.xy);
- minco = clamp(minco * tex_size + 0.5, 0.0, 1.0);
- float fac = minco.x * minco.y;
-
- color = mix(vec4(0.0), icolor, fac);
- alpha = color.a;
-}
-
-void tex_clip_nearest(vec3 co, sampler2D ima, vec4 icolor, out vec4 color, out float alpha)
-{
- vec4 minco = vec4(co.xy, 1.0 - co.xy);
- color = (any(lessThan(minco, vec4(0.0)))) ? vec4(0.0) : icolor;
- alpha = color.a;
-}
-
-void tex_clip_cubic(vec3 co, sampler2D ima, vec4 icolor, out vec4 color, out float alpha)
-{
- vec2 tex_size = vec2(textureSize(ima, 0).xy);
-
- co.xy *= tex_size;
- /* texel center */
- vec2 tc = floor(co.xy - 0.5) + 0.5;
- vec2 w0, w1, w2, w3;
- cubic_bspline_coefs(co.xy - tc, w0, w1, w2, w3);
-
- /* TODO Optimize this part. I'm sure there is a smarter way to do that.
- * Could do that when sampling? */
-#define CLIP_CUBIC_SAMPLE(samp, size) \
- (float(all(greaterThan(samp, vec2(-0.5)))) * float(all(lessThan(ivec2(samp), itex_size))))
- ivec2 itex_size = textureSize(ima, 0).xy;
- float fac;
- fac = CLIP_CUBIC_SAMPLE(tc + vec2(-1.0, -1.0), itex_size) * w0.x * w0.y;
- fac += CLIP_CUBIC_SAMPLE(tc + vec2(0.0, -1.0), itex_size) * w1.x * w0.y;
- fac += CLIP_CUBIC_SAMPLE(tc + vec2(1.0, -1.0), itex_size) * w2.x * w0.y;
- fac += CLIP_CUBIC_SAMPLE(tc + vec2(2.0, -1.0), itex_size) * w3.x * w0.y;
-
- fac += CLIP_CUBIC_SAMPLE(tc + vec2(-1.0, 0.0), itex_size) * w0.x * w1.y;
- fac += CLIP_CUBIC_SAMPLE(tc + vec2(0.0, 0.0), itex_size) * w1.x * w1.y;
- fac += CLIP_CUBIC_SAMPLE(tc + vec2(1.0, 0.0), itex_size) * w2.x * w1.y;
- fac += CLIP_CUBIC_SAMPLE(tc + vec2(2.0, 0.0), itex_size) * w3.x * w1.y;
-
- fac += CLIP_CUBIC_SAMPLE(tc + vec2(-1.0, 1.0), itex_size) * w0.x * w2.y;
- fac += CLIP_CUBIC_SAMPLE(tc + vec2(0.0, 1.0), itex_size) * w1.x * w2.y;
- fac += CLIP_CUBIC_SAMPLE(tc + vec2(1.0, 1.0), itex_size) * w2.x * w2.y;
- fac += CLIP_CUBIC_SAMPLE(tc + vec2(2.0, 1.0), itex_size) * w3.x * w2.y;
-
- fac += CLIP_CUBIC_SAMPLE(tc + vec2(-1.0, 2.0), itex_size) * w0.x * w3.y;
- fac += CLIP_CUBIC_SAMPLE(tc + vec2(0.0, 2.0), itex_size) * w1.x * w3.y;
- fac += CLIP_CUBIC_SAMPLE(tc + vec2(1.0, 2.0), itex_size) * w2.x * w3.y;
- fac += CLIP_CUBIC_SAMPLE(tc + vec2(2.0, 2.0), itex_size) * w3.x * w3.y;
-#undef CLIP_CUBIC_SAMPLE
-
- color = mix(vec4(0.0), icolor, fac);
- alpha = color.a;
-}
-
-void tex_clip_smart(vec3 co, sampler2D ima, vec4 icolor, out vec4 color, out float alpha)
-{
- tex_clip_cubic(co, ima, icolor, color, alpha);
-}
-
void node_tex_image_empty(vec3 co, out vec4 color, out float alpha)
{
color = vec4(0.0);
@@ -389,20 +253,6 @@ void node_tex_tile_linear(
alpha = color.a;
}
-void node_tex_tile_nearest(
- vec3 co, sampler2DArray ima, sampler1DArray map, out vec4 color, out float alpha)
-{
- if (node_tex_tile_lookup(co, ima, map)) {
- ivec3 pix = ivec3(fract(co.xy) * textureSize(ima, 0).xy, co.z);
- color = safe_color(texelFetch(ima, pix, 0));
- }
- else {
- color = vec4(1.0, 0.0, 1.0, 1.0);
- }
-
- alpha = color.a;
-}
-
void node_tex_tile_cubic(
vec3 co, sampler2DArray ima, sampler1DArray map, out vec4 color, out float alpha)
{
@@ -437,9 +287,3 @@ void node_tex_tile_cubic(
alpha = color.a;
}
-
-void node_tex_tile_smart(
- vec3 co, sampler2DArray ima, sampler1DArray map, out vec4 color, out float alpha)
-{
- node_tex_tile_cubic(co, ima, map, color, alpha);
-}
diff --git a/source/blender/gpu/shaders/material/gpu_shader_material_tex_noise.glsl b/source/blender/gpu/shaders/material/gpu_shader_material_tex_noise.glsl
index 6aeb23b1f99..d8d9ecdf287 100644
--- a/source/blender/gpu/shaders/material/gpu_shader_material_tex_noise.glsl
+++ b/source/blender/gpu/shaders/material/gpu_shader_material_tex_noise.glsl
@@ -32,23 +32,35 @@ vec4 random_vec4_offset(float seed)
100.0 + hash_vec2_to_float(vec2(seed, 3.0)) * 100.0);
}
-void node_noise_texture_1d(
- vec3 co, float w, float scale, float detail, float distortion, out float value, out vec4 color)
+void node_noise_texture_1d(vec3 co,
+ float w,
+ float scale,
+ float detail,
+ float roughness,
+ float distortion,
+ out float value,
+ out vec4 color)
{
float p = w * scale;
if (distortion != 0.0) {
p += snoise(p + random_float_offset(0.0)) * distortion;
}
- value = fractal_noise(p, detail);
+ value = fractal_noise(p, detail, roughness);
color = vec4(value,
- fractal_noise(p + random_float_offset(1.0), detail),
- fractal_noise(p + random_float_offset(2.0), detail),
+ fractal_noise(p + random_float_offset(1.0), detail, roughness),
+ fractal_noise(p + random_float_offset(2.0), detail, roughness),
1.0);
}
-void node_noise_texture_2d(
- vec3 co, float w, float scale, float detail, float distortion, out float value, out vec4 color)
+void node_noise_texture_2d(vec3 co,
+ float w,
+ float scale,
+ float detail,
+ float roughness,
+ float distortion,
+ out float value,
+ out vec4 color)
{
vec2 p = co.xy * scale;
if (distortion != 0.0) {
@@ -56,15 +68,21 @@ void node_noise_texture_2d(
snoise(p + random_vec2_offset(1.0)) * distortion);
}
- value = fractal_noise(p, detail);
+ value = fractal_noise(p, detail, roughness);
color = vec4(value,
- fractal_noise(p + random_vec2_offset(2.0), detail),
- fractal_noise(p + random_vec2_offset(3.0), detail),
+ fractal_noise(p + random_vec2_offset(2.0), detail, roughness),
+ fractal_noise(p + random_vec2_offset(3.0), detail, roughness),
1.0);
}
-void node_noise_texture_3d(
- vec3 co, float w, float scale, float detail, float distortion, out float value, out vec4 color)
+void node_noise_texture_3d(vec3 co,
+ float w,
+ float scale,
+ float detail,
+ float roughness,
+ float distortion,
+ out float value,
+ out vec4 color)
{
vec3 p = co * scale;
if (distortion != 0.0) {
@@ -73,15 +91,21 @@ void node_noise_texture_3d(
snoise(p + random_vec3_offset(2.0)) * distortion);
}
- value = fractal_noise(p, detail);
+ value = fractal_noise(p, detail, roughness);
color = vec4(value,
- fractal_noise(p + random_vec3_offset(3.0), detail),
- fractal_noise(p + random_vec3_offset(4.0), detail),
+ fractal_noise(p + random_vec3_offset(3.0), detail, roughness),
+ fractal_noise(p + random_vec3_offset(4.0), detail, roughness),
1.0);
}
-void node_noise_texture_4d(
- vec3 co, float w, float scale, float detail, float distortion, out float value, out vec4 color)
+void node_noise_texture_4d(vec3 co,
+ float w,
+ float scale,
+ float detail,
+ float roughness,
+ float distortion,
+ out float value,
+ out vec4 color)
{
vec4 p = vec4(co, w) * scale;
if (distortion != 0.0) {
@@ -91,9 +115,9 @@ void node_noise_texture_4d(
snoise(p + random_vec4_offset(3.0)) * distortion);
}
- value = fractal_noise(p, detail);
+ value = fractal_noise(p, detail, roughness);
color = vec4(value,
- fractal_noise(p + random_vec4_offset(4.0), detail),
- fractal_noise(p + random_vec4_offset(5.0), detail),
+ fractal_noise(p + random_vec4_offset(4.0), detail, roughness),
+ fractal_noise(p + random_vec4_offset(5.0), detail, roughness),
1.0);
}
diff --git a/source/blender/gpu/shaders/material/gpu_shader_material_tex_wave.glsl b/source/blender/gpu/shaders/material/gpu_shader_material_tex_wave.glsl
index c72f9717af3..070f42a5e30 100644
--- a/source/blender/gpu/shaders/material/gpu_shader_material_tex_wave.glsl
+++ b/source/blender/gpu/shaders/material/gpu_shader_material_tex_wave.glsl
@@ -2,6 +2,7 @@ float calc_wave(vec3 p,
float distortion,
float detail,
float detail_scale,
+ float detail_roughness,
float phase,
int wave_type,
int bands_dir,
@@ -46,7 +47,7 @@ float calc_wave(vec3 p,
n += phase;
if (distortion != 0.0) {
- n += distortion * (fractal_noise(p * detail_scale, detail) * 2.0 - 1.0);
+ n += distortion * (fractal_noise(p * detail_scale, detail, detail_roughness) * 2.0 - 1.0);
}
if (wave_profile == 0) { /* profile sin */
@@ -67,6 +68,7 @@ void node_tex_wave(vec3 co,
float distortion,
float detail,
float detail_scale,
+ float detail_roughness,
float phase,
float wave_type,
float bands_dir,
@@ -80,6 +82,7 @@ void node_tex_wave(vec3 co,
distortion,
detail,
detail_scale,
+ detail_roughness,
phase,
int(wave_type),
int(bands_dir),
diff --git a/source/blender/ikplugin/intern/iksolver_plugin.c b/source/blender/ikplugin/intern/iksolver_plugin.c
index b72c32a8277..3646686e81f 100644
--- a/source/blender/ikplugin/intern/iksolver_plugin.c
+++ b/source/blender/ikplugin/intern/iksolver_plugin.c
@@ -654,7 +654,7 @@ void iksolver_release_tree(struct Scene *UNUSED(scene), struct Object *ob, float
void iksolver_clear_data(bPose *pose)
{
- for (bPoseChannel *pchan = pose->chanbase.first; pchan; pchan = pchan->next) {
+ LISTBASE_FOREACH (bPoseChannel *, pchan, &pose->chanbase) {
if ((pchan->flag & POSE_IKTREE) == 0) {
continue;
}
diff --git a/source/blender/ikplugin/intern/itasc_plugin.cpp b/source/blender/ikplugin/intern/itasc_plugin.cpp
index 19a4390598f..66ed0dd0fa5 100644
--- a/source/blender/ikplugin/intern/itasc_plugin.cpp
+++ b/source/blender/ikplugin/intern/itasc_plugin.cpp
@@ -40,7 +40,6 @@
#include "MEM_guardedalloc.h"
-extern "C" {
#include "BIK_api.h"
#include "BLI_blenlib.h"
#include "BLI_math.h"
@@ -55,7 +54,6 @@ extern "C" {
#include "DNA_constraint_types.h"
#include "DNA_object_types.h"
#include "DNA_scene_types.h"
-};
#include "itasc_plugin.h"
diff --git a/source/blender/imbuf/IMB_colormanagement.h b/source/blender/imbuf/IMB_colormanagement.h
index 1639fb4715f..3158e3419b0 100644
--- a/source/blender/imbuf/IMB_colormanagement.h
+++ b/source/blender/imbuf/IMB_colormanagement.h
@@ -56,6 +56,7 @@ void IMB_colormanagement_validate_settings(
const char *IMB_colormanagement_role_colorspace_name_get(int role);
void IMB_colormanagement_check_is_data(struct ImBuf *ibuf, const char *name);
+void IMB_colormanagegent_copy_settings(struct ImBuf *ibuf_src, struct ImBuf *ibuf_dst);
void IMB_colormanagement_assign_float_colorspace(struct ImBuf *ibuf, const char *name);
void IMB_colormanagement_assign_rect_colorspace(struct ImBuf *ibuf, const char *name);
diff --git a/source/blender/imbuf/intern/IMB_allocimbuf.h b/source/blender/imbuf/intern/IMB_allocimbuf.h
index c252a9a63f8..9f89969cf1c 100644
--- a/source/blender/imbuf/intern/IMB_allocimbuf.h
+++ b/source/blender/imbuf/intern/IMB_allocimbuf.h
@@ -24,6 +24,10 @@
#ifndef __IMB_ALLOCIMBUF_H__
#define __IMB_ALLOCIMBUF_H__
+#ifdef __cplusplus
+extern "C" {
+#endif
+
struct ImBuf;
void imb_refcounter_lock_init(void);
@@ -44,4 +48,8 @@ void imb_mmap_unlock(void);
bool imb_addencodedbufferImBuf(struct ImBuf *ibuf);
bool imb_enlargeencodedbufferImBuf(struct ImBuf *ibuf);
+#ifdef __cplusplus
+}
+#endif
+
#endif
diff --git a/source/blender/imbuf/intern/IMB_colormanagement_intern.h b/source/blender/imbuf/intern/IMB_colormanagement_intern.h
index f0e599c1375..79abe8472b9 100644
--- a/source/blender/imbuf/intern/IMB_colormanagement_intern.h
+++ b/source/blender/imbuf/intern/IMB_colormanagement_intern.h
@@ -27,6 +27,10 @@
#include "BLI_sys_types.h"
#include "DNA_listBase.h"
+#ifdef __cplusplus
+extern "C" {
+#endif
+
struct ImBuf;
struct OCIO_ConstProcessorRcPtr;
@@ -123,4 +127,8 @@ void colorspace_set_default_role(char *colorspace, int size, int role);
void colormanage_imbuf_set_default_spaces(struct ImBuf *ibuf);
void colormanage_imbuf_make_linear(struct ImBuf *ibuf, const char *from_colorspace);
+#ifdef __cplusplus
+}
+#endif
+
#endif /* __IMB_COLORMANAGEMENT_INTERN_H__ */
diff --git a/source/blender/imbuf/intern/allocimbuf.c b/source/blender/imbuf/intern/allocimbuf.c
index 6c17254e697..4b3858e6d5a 100644
--- a/source/blender/imbuf/intern/allocimbuf.c
+++ b/source/blender/imbuf/intern/allocimbuf.c
@@ -380,7 +380,7 @@ void *imb_alloc_pixels(
}
size_t size = (size_t)x * (size_t)y * (size_t)channels * typesize;
- return MEM_mapallocN(size, name);
+ return MEM_callocN(size, name);
}
bool imb_addrectfloatImBuf(ImBuf *ibuf)
diff --git a/source/blender/imbuf/intern/anim_movie.c b/source/blender/imbuf/intern/anim_movie.c
index e9ac40de442..11b30a24cde 100644
--- a/source/blender/imbuf/intern/anim_movie.c
+++ b/source/blender/imbuf/intern/anim_movie.c
@@ -154,7 +154,7 @@ static int an_stringdec(const char *string, char *head, char *tail, unsigned sho
static void an_stringenc(
char *string, const char *head, const char *tail, unsigned short numlen, int pic)
{
- BLI_stringenc(string, head, tail, numlen, pic);
+ BLI_path_sequence_encode(string, head, tail, numlen, pic);
}
#ifdef WITH_AVI
diff --git a/source/blender/imbuf/intern/cache.c b/source/blender/imbuf/intern/cache.c
index 176b41d2706..23ce9bd7818 100644
--- a/source/blender/imbuf/intern/cache.c
+++ b/source/blender/imbuf/intern/cache.c
@@ -427,8 +427,8 @@ void IMB_tiles_to_rect(ImBuf *ibuf)
/* don't call imb_addrectImBuf, it frees all mipmaps */
if (!mipbuf->rect) {
- if ((mipbuf->rect = MEM_mapallocN(ibuf->x * ibuf->y * sizeof(unsigned int),
- "imb_addrectImBuf"))) {
+ if ((mipbuf->rect = MEM_callocN(ibuf->x * ibuf->y * sizeof(unsigned int),
+ "imb_addrectImBuf"))) {
mipbuf->mall |= IB_rect;
mipbuf->flags |= IB_rect;
}
diff --git a/source/blender/imbuf/intern/cineon/cineonlib.h b/source/blender/imbuf/intern/cineon/cineonlib.h
index 461407fcf25..040435e44ee 100644
--- a/source/blender/imbuf/intern/cineon/cineonlib.h
+++ b/source/blender/imbuf/intern/cineon/cineonlib.h
@@ -26,12 +26,12 @@
#ifndef __CINEONLIB_H__
#define __CINEONLIB_H__
+#include "logImageCore.h"
+
#ifdef __cplusplus
extern "C" {
#endif
-#include "logImageCore.h"
-
#define CINEON_FILE_MAGIC 0x802A5FD7
#define CINEON_UNDEFINED_U8 0xFF
#define CINEON_UNDEFINED_U16 0xFFFF
diff --git a/source/blender/imbuf/intern/cineon/dpxlib.h b/source/blender/imbuf/intern/cineon/dpxlib.h
index bf07b8e329d..3a7ebe9dddf 100644
--- a/source/blender/imbuf/intern/cineon/dpxlib.h
+++ b/source/blender/imbuf/intern/cineon/dpxlib.h
@@ -25,12 +25,12 @@
#ifndef __DPXLIB_H__
#define __DPXLIB_H__
+#include "logImageCore.h"
+
#ifdef __cplusplus
extern "C" {
#endif
-#include "logImageCore.h"
-
#define DPX_FILE_MAGIC 0x53445058
#define DPX_UNDEFINED_U8 0xFF
#define DPX_UNDEFINED_U16 0xFFFF
diff --git a/source/blender/imbuf/intern/colormanagement.c b/source/blender/imbuf/intern/colormanagement.c
index c57ab70f4e6..3f5a0f25cc5 100644
--- a/source/blender/imbuf/intern/colormanagement.c
+++ b/source/blender/imbuf/intern/colormanagement.c
@@ -1349,6 +1349,23 @@ void IMB_colormanagement_check_is_data(ImBuf *ibuf, const char *name)
}
}
+void IMB_colormanagegent_copy_settings(ImBuf *ibuf_src, ImBuf *ibuf_dst)
+{
+ IMB_colormanagement_assign_rect_colorspace(ibuf_dst,
+ IMB_colormanagement_get_rect_colorspace(ibuf_src));
+ IMB_colormanagement_assign_float_colorspace(ibuf_dst,
+ IMB_colormanagement_get_float_colorspace(ibuf_src));
+ if (ibuf_src->flags & IB_alphamode_premul) {
+ ibuf_dst->flags |= IB_alphamode_premul;
+ }
+ else if (ibuf_src->flags & IB_alphamode_channel_packed) {
+ ibuf_dst->flags |= IB_alphamode_channel_packed;
+ }
+ else if (ibuf_src->flags & IB_alphamode_ignore) {
+ ibuf_dst->flags |= IB_alphamode_ignore;
+ }
+}
+
void IMB_colormanagement_assign_float_colorspace(ImBuf *ibuf, const char *name)
{
ColorSpace *colorspace = colormanage_colorspace_get_named(name);
diff --git a/source/blender/imbuf/intern/dds/dds_api.cpp b/source/blender/imbuf/intern/dds/dds_api.cpp
index 832b380bbc2..83d304203a0 100644
--- a/source/blender/imbuf/intern/dds/dds_api.cpp
+++ b/source/blender/imbuf/intern/dds/dds_api.cpp
@@ -18,9 +18,7 @@
* \ingroup imbdds
*/
-extern "C" {
#include "BLI_utildefines.h"
-}
#include <DirectDrawSurface.h>
#include <FlipDXT.h>
@@ -34,8 +32,6 @@ extern "C" {
# include "utfconv.h"
#endif
-extern "C" {
-
#include "IMB_allocimbuf.h"
#include "IMB_imbuf.h"
#include "IMB_imbuf_types.h"
@@ -44,6 +40,8 @@ extern "C" {
#include "IMB_colormanagement.h"
#include "IMB_colormanagement_intern.h"
+extern "C" {
+
int imb_save_dds(struct ImBuf *ibuf, const char *name, int /*flags*/)
{
return (0); /* todo: finish this function */
diff --git a/source/blender/imbuf/intern/dds/dds_api.h b/source/blender/imbuf/intern/dds/dds_api.h
index 12db8aa6416..e6782e217fc 100644
--- a/source/blender/imbuf/intern/dds/dds_api.h
+++ b/source/blender/imbuf/intern/dds/dds_api.h
@@ -21,12 +21,12 @@
#ifndef __DDS_API_H__
#define __DDS_API_H__
+#include "../../IMB_imbuf.h"
+
#ifdef __cplusplus
extern "C" {
#endif
-#include "../../IMB_imbuf.h"
-
int imb_is_a_dds(const unsigned char *mem); /* use only first 32 bytes of mem */
int imb_save_dds(struct ImBuf *ibuf, const char *name, int flags);
struct ImBuf *imb_load_dds(const unsigned char *mem,
diff --git a/source/blender/imbuf/intern/divers.c b/source/blender/imbuf/intern/divers.c
index e068a84aab0..bcc8488089d 100644
--- a/source/blender/imbuf/intern/divers.c
+++ b/source/blender/imbuf/intern/divers.c
@@ -788,7 +788,7 @@ void IMB_float_from_rect(ImBuf *ibuf)
size = size * 4 * sizeof(float);
ibuf->channels = 4;
- rect_float = MEM_mapallocN(size, "IMB_float_from_rect");
+ rect_float = MEM_callocN(size, "IMB_float_from_rect");
if (rect_float == NULL) {
return;
diff --git a/source/blender/imbuf/intern/imageprocess.c b/source/blender/imbuf/intern/imageprocess.c
index 523b57cc162..7ebbd1a7409 100644
--- a/source/blender/imbuf/intern/imageprocess.c
+++ b/source/blender/imbuf/intern/imageprocess.c
@@ -338,9 +338,9 @@ void nearest_interpolation(ImBuf *in, ImBuf *out, float x, float y, int xout, in
/*********************** Threaded image processing *************************/
-static void processor_apply_func(TaskPool *__restrict pool, void *taskdata, int UNUSED(threadid))
+static void processor_apply_func(TaskPool *__restrict pool, void *taskdata)
{
- void (*do_thread)(void *) = (void (*)(void *))BLI_task_pool_userdata(pool);
+ void (*do_thread)(void *) = (void (*)(void *))BLI_task_pool_user_data(pool);
do_thread(taskdata);
}
@@ -353,14 +353,13 @@ void IMB_processor_apply_threaded(
{
const int lines_per_task = 64;
- TaskScheduler *task_scheduler = BLI_task_scheduler_get();
TaskPool *task_pool;
void *handles;
int total_tasks = (buffer_lines + lines_per_task - 1) / lines_per_task;
int i, start_line;
- task_pool = BLI_task_pool_create(task_scheduler, do_thread);
+ task_pool = BLI_task_pool_create(do_thread, TASK_PRIORITY_LOW);
handles = MEM_callocN(handle_size * total_tasks, "processor apply threaded handles");
@@ -379,7 +378,7 @@ void IMB_processor_apply_threaded(
init_handle(handle, start_line, lines_per_current_task, init_customdata);
- BLI_task_pool_push(task_pool, processor_apply_func, handle, false, TASK_PRIORITY_LOW);
+ BLI_task_pool_push(task_pool, processor_apply_func, handle, false, NULL);
start_line += lines_per_task;
}
@@ -399,11 +398,9 @@ typedef struct ScanlineGlobalData {
int total_scanlines;
} ScanlineGlobalData;
-static void processor_apply_scanline_func(TaskPool *__restrict pool,
- void *taskdata,
- int UNUSED(threadid))
+static void processor_apply_scanline_func(TaskPool *__restrict pool, void *taskdata)
{
- ScanlineGlobalData *data = BLI_task_pool_userdata(pool);
+ ScanlineGlobalData *data = BLI_task_pool_user_data(pool);
int start_scanline = POINTER_AS_INT(taskdata);
int num_scanlines = min_ii(data->scanlines_per_task, data->total_scanlines - start_scanline);
data->do_thread(data->custom_data, start_scanline, num_scanlines);
@@ -420,14 +417,10 @@ void IMB_processor_apply_threaded_scanlines(int total_scanlines,
data.scanlines_per_task = scanlines_per_task;
data.total_scanlines = total_scanlines;
const int total_tasks = (total_scanlines + scanlines_per_task - 1) / scanlines_per_task;
- TaskScheduler *task_scheduler = BLI_task_scheduler_get();
- TaskPool *task_pool = BLI_task_pool_create(task_scheduler, &data);
+ TaskPool *task_pool = BLI_task_pool_create(&data, TASK_PRIORITY_LOW);
for (int i = 0, start_line = 0; i < total_tasks; i++) {
- BLI_task_pool_push(task_pool,
- processor_apply_scanline_func,
- POINTER_FROM_INT(start_line),
- false,
- TASK_PRIORITY_LOW);
+ BLI_task_pool_push(
+ task_pool, processor_apply_scanline_func, POINTER_FROM_INT(start_line), false, NULL);
start_line += scanlines_per_task;
}
diff --git a/source/blender/imbuf/intern/oiio/openimageio_api.cpp b/source/blender/imbuf/intern/oiio/openimageio_api.cpp
index 6d3234771e7..df51aada5f0 100644
--- a/source/blender/imbuf/intern/oiio/openimageio_api.cpp
+++ b/source/blender/imbuf/intern/oiio/openimageio_api.cpp
@@ -35,7 +35,6 @@
#include "MEM_guardedalloc.h"
-extern "C" {
#include "BLI_blenlib.h"
#include "IMB_allocimbuf.h"
@@ -43,7 +42,6 @@ extern "C" {
#include "IMB_colormanagement_intern.h"
#include "IMB_imbuf.h"
#include "IMB_imbuf_types.h"
-}
OIIO_NAMESPACE_USING
diff --git a/source/blender/imbuf/intern/oiio/openimageio_api.h b/source/blender/imbuf/intern/oiio/openimageio_api.h
index 520ad0c5da5..3dd089d65cb 100644
--- a/source/blender/imbuf/intern/oiio/openimageio_api.h
+++ b/source/blender/imbuf/intern/oiio/openimageio_api.h
@@ -24,12 +24,12 @@
#ifndef __OPENIMAGEIO_API_H__
#define __OPENIMAGEIO_API_H__
+#include <stdio.h>
+
#ifdef __cplusplus
extern "C" {
#endif
-#include <stdio.h>
-
struct ImBuf;
int imb_is_a_photoshop(const char *name);
diff --git a/source/blender/imbuf/intern/openexr/openexr_api.cpp b/source/blender/imbuf/intern/openexr/openexr_api.cpp
index 8f001c9031f..882808cbc14 100644
--- a/source/blender/imbuf/intern/openexr/openexr_api.cpp
+++ b/source/blender/imbuf/intern/openexr/openexr_api.cpp
@@ -75,7 +75,7 @@ _CRTIMP void __cdecl _invalid_parameter_noinfo(void)
{
}
#endif
-
+}
#include "BLI_blenlib.h"
#include "BLI_math_color.h"
#include "BLI_threads.h"
@@ -84,17 +84,13 @@ _CRTIMP void __cdecl _invalid_parameter_noinfo(void)
#include "BKE_image.h"
#include "IMB_allocimbuf.h"
+#include "IMB_colormanagement.h"
+#include "IMB_colormanagement_intern.h"
#include "IMB_imbuf.h"
#include "IMB_imbuf_types.h"
#include "IMB_metadata.h"
#include "openexr_multi.h"
-}
-
-extern "C" {
-#include "IMB_colormanagement.h"
-#include "IMB_colormanagement_intern.h"
-}
using namespace Imf;
using namespace Imath;
@@ -1602,8 +1598,8 @@ static ExrHandle *imb_exr_begin_read_mem(IStream &file_stream,
for (lay = (ExrLayer *)data->layers.first; lay; lay = lay->next) {
for (pass = (ExrPass *)lay->passes.first; pass; pass = pass->next) {
if (pass->totchan) {
- pass->rect = (float *)MEM_mapallocN(width * height * pass->totchan * sizeof(float),
- "pass rect");
+ pass->rect = (float *)MEM_callocN(width * height * pass->totchan * sizeof(float),
+ "pass rect");
if (pass->totchan == 1) {
echan = pass->chan[0];
echan->rect = pass->rect;
@@ -1938,12 +1934,12 @@ struct ImBuf *imb_load_openexr(const unsigned char *mem,
IMB_metadata_ensure(&ibuf->metadata);
for (iter = header.begin(); iter != header.end(); iter++) {
- const StringAttribute *attrib = file->header(0).findTypedAttribute<StringAttribute>(
+ const StringAttribute *attr = file->header(0).findTypedAttribute<StringAttribute>(
iter.name());
/* not all attributes are string attributes so we might get some NULLs here */
- if (attrib) {
- IMB_metadata_set_field(ibuf->metadata, iter.name(), attrib->value().c_str());
+ if (attr) {
+ IMB_metadata_set_field(ibuf->metadata, iter.name(), attr->value().c_str());
ibuf->flags |= IB_metadata;
}
}
diff --git a/source/blender/imbuf/intern/openexr/openexr_api.h b/source/blender/imbuf/intern/openexr/openexr_api.h
index df03d0d205f..b0835e5082e 100644
--- a/source/blender/imbuf/intern/openexr/openexr_api.h
+++ b/source/blender/imbuf/intern/openexr/openexr_api.h
@@ -24,12 +24,12 @@
#ifndef __OPENEXR_API_H__
#define __OPENEXR_API_H__
+#include <stdio.h>
+
#ifdef __cplusplus
extern "C" {
#endif
-#include <stdio.h>
-
void imb_initopenexr(void);
void imb_exitopenexr(void);
diff --git a/source/blender/imbuf/intern/png.c b/source/blender/imbuf/intern/png.c
index d6d185ef59b..9e600f363c5 100644
--- a/source/blender/imbuf/intern/png.c
+++ b/source/blender/imbuf/intern/png.c
@@ -177,12 +177,6 @@ int imb_savepng(struct ImBuf *ibuf, const char *name, int flags)
return 0;
}
- if (setjmp(png_jmpbuf(png_ptr))) {
- png_destroy_write_struct(&png_ptr, &info_ptr);
- printf("imb_savepng: Cannot setjmp for file: '%s'\n", name);
- return 0;
- }
-
/* copy image data */
num_bytes = ((size_t)ibuf->x) * ibuf->y * bytesperpixel;
if (is_16bit) {
@@ -191,15 +185,39 @@ int imb_savepng(struct ImBuf *ibuf, const char *name, int flags)
else {
pixels = MEM_mallocN(num_bytes * sizeof(unsigned char), "png 8bit pixels");
}
-
if (pixels == NULL && pixels16 == NULL) {
- png_destroy_write_struct(&png_ptr, &info_ptr);
printf(
- "imb_savepng: Cannot allocate pixels array of %dx%d, %d bytes per pixel for file: '%s'\n",
+ "imb_savepng: Cannot allocate pixels array of %dx%d, %d bytes per pixel for file: "
+ "'%s'\n",
ibuf->x,
ibuf->y,
bytesperpixel,
name);
+ }
+
+ /* allocate memory for an array of row-pointers */
+ row_pointers = (png_bytepp)MEM_mallocN(ibuf->y * sizeof(png_bytep), "row_pointers");
+ if (row_pointers == NULL) {
+ printf("imb_savepng: Cannot allocate row-pointers array for file '%s'\n", name);
+ }
+
+ if ((pixels == NULL && pixels16 == NULL) || (row_pointers == NULL) ||
+ setjmp(png_jmpbuf(png_ptr))) {
+ /* On error jump here, and free any resources. */
+ png_destroy_write_struct(&png_ptr, &info_ptr);
+ if (pixels) {
+ MEM_freeN(pixels);
+ }
+ if (pixels16) {
+ MEM_freeN(pixels16);
+ }
+ if (row_pointers) {
+ MEM_freeN(row_pointers);
+ }
+ if (fp) {
+ fflush(fp);
+ fclose(fp);
+ }
return 0;
}
@@ -457,23 +475,6 @@ int imb_savepng(struct ImBuf *ibuf, const char *name, int flags)
png_set_swap(png_ptr);
#endif
- /* allocate memory for an array of row-pointers */
- row_pointers = (png_bytepp)MEM_mallocN(ibuf->y * sizeof(png_bytep), "row_pointers");
- if (row_pointers == NULL) {
- printf("imb_savepng: Cannot allocate row-pointers array for file '%s'\n", name);
- png_destroy_write_struct(&png_ptr, &info_ptr);
- if (pixels) {
- MEM_freeN(pixels);
- }
- if (pixels16) {
- MEM_freeN(pixels16);
- }
- if (fp) {
- fclose(fp);
- }
- return 0;
- }
-
/* set the individual row-pointers to point at the correct offsets */
if (is_16bit) {
for (i = 0; i < ibuf->y; i++) {
@@ -576,6 +577,7 @@ ImBuf *imb_loadpng(const unsigned char *mem, size_t size, int flags, char colors
png_set_read_fn(png_ptr, (void *)&ps, ReadData);
if (setjmp(png_jmpbuf(png_ptr))) {
+ /* On error jump here, and free any resources. */
png_destroy_read_struct(&png_ptr, &info_ptr, (png_infopp)NULL);
if (pixels) {
MEM_freeN(pixels);
diff --git a/source/blender/imbuf/intern/thumbs.c b/source/blender/imbuf/intern/thumbs.c
index 195a2e9fe9c..17b619d451c 100644
--- a/source/blender/imbuf/intern/thumbs.c
+++ b/source/blender/imbuf/intern/thumbs.c
@@ -151,111 +151,24 @@ typedef enum {
UNSAFE_SLASHES = 0x20, /* Allows all characters except for '/' and '%' */
} UnsafeCharacterSet;
+/* Don't loose comment alignment. */
+/* clang-format off */
static const unsigned char acceptable[96] = {
/* A table of the ASCII chars from space (32) to DEL (127) */
/* ! " # $ % & ' ( ) * + , - . / */
- 0x00,
- 0x3F,
- 0x20,
- 0x20,
- 0x28,
- 0x00,
- 0x2C,
- 0x3F,
- 0x3F,
- 0x3F,
- 0x3F,
- 0x2A,
- 0x28,
- 0x3F,
- 0x3F,
- 0x1C,
+ 0x00,0x3F,0x20,0x20,0x28,0x00,0x2C,0x3F,0x3F,0x3F,0x3F,0x2A,0x28,0x3F,0x3F,0x1C,
/* 0 1 2 3 4 5 6 7 8 9 : ; < = > ? */
- 0x3F,
- 0x3F,
- 0x3F,
- 0x3F,
- 0x3F,
- 0x3F,
- 0x3F,
- 0x3F,
- 0x3F,
- 0x3F,
- 0x38,
- 0x20,
- 0x20,
- 0x2C,
- 0x20,
- 0x20,
+ 0x3F,0x3F,0x3F,0x3F,0x3F,0x3F,0x3F,0x3F,0x3F,0x3F,0x38,0x20,0x20,0x2C,0x20,0x20,
/* @ A B C D E F G H I J K L M N O */
- 0x38,
- 0x3F,
- 0x3F,
- 0x3F,
- 0x3F,
- 0x3F,
- 0x3F,
- 0x3F,
- 0x3F,
- 0x3F,
- 0x3F,
- 0x3F,
- 0x3F,
- 0x3F,
- 0x3F,
- 0x3F,
+ 0x38,0x3F,0x3F,0x3F,0x3F,0x3F,0x3F,0x3F,0x3F,0x3F,0x3F,0x3F,0x3F,0x3F,0x3F,0x3F,
/* P Q R S T U V W X Y Z [ \ ] ^ _ */
- 0x3F,
- 0x3F,
- 0x3F,
- 0x3F,
- 0x3F,
- 0x3F,
- 0x3F,
- 0x3F,
- 0x3F,
- 0x3F,
- 0x3F,
- 0x20,
- 0x20,
- 0x20,
- 0x20,
- 0x3F,
+ 0x3F,0x3F,0x3F,0x3F,0x3F,0x3F,0x3F,0x3F,0x3F,0x3F,0x3F,0x20,0x20,0x20,0x20,0x3F,
/* ` a b c d e f g h i j k l m n o */
- 0x20,
- 0x3F,
- 0x3F,
- 0x3F,
- 0x3F,
- 0x3F,
- 0x3F,
- 0x3F,
- 0x3F,
- 0x3F,
- 0x3F,
- 0x3F,
- 0x3F,
- 0x3F,
- 0x3F,
- 0x3F,
+ 0x20,0x3F,0x3F,0x3F,0x3F,0x3F,0x3F,0x3F,0x3F,0x3F,0x3F,0x3F,0x3F,0x3F,0x3F,0x3F,
/* p q r s t u v w x y z { | } ~ DEL */
- 0x3F,
- 0x3F,
- 0x3F,
- 0x3F,
- 0x3F,
- 0x3F,
- 0x3F,
- 0x3F,
- 0x3F,
- 0x3F,
- 0x3F,
- 0x20,
- 0x20,
- 0x20,
- 0x3F,
- 0x20,
+ 0x3F,0x3F,0x3F,0x3F,0x3F,0x3F,0x3F,0x3F,0x3F,0x3F,0x3F,0x20,0x20,0x20,0x3F,0x20,
};
+/* clang-format on */
static const char hex[17] = "0123456789abcdef";
diff --git a/source/blender/io/alembic/CMakeLists.txt b/source/blender/io/alembic/CMakeLists.txt
index cbcdfaf4b77..6de7d327d4e 100644
--- a/source/blender/io/alembic/CMakeLists.txt
+++ b/source/blender/io/alembic/CMakeLists.txt
@@ -41,6 +41,7 @@ set(INC_SYS
)
set(SRC
+ intern/abc_axis_conversion.cc
intern/abc_customdata.cc
intern/abc_exporter.cc
intern/abc_reader_archive.cc
@@ -65,6 +66,7 @@ set(SRC
intern/alembic_capi.cc
ABC_alembic.h
+ intern/abc_axis_conversion.h
intern/abc_customdata.h
intern/abc_exporter.h
intern/abc_reader_archive.h
diff --git a/source/blender/io/alembic/intern/abc_axis_conversion.cc b/source/blender/io/alembic/intern/abc_axis_conversion.cc
new file mode 100644
index 00000000000..17db5e9c99f
--- /dev/null
+++ b/source/blender/io/alembic/intern/abc_axis_conversion.cc
@@ -0,0 +1,166 @@
+/*
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+
+/** \file
+ * \ingroup Alembic
+ */
+
+#include "abc_axis_conversion.h"
+
+extern "C" {
+#include "BLI_assert.h"
+#include "DNA_object_types.h"
+
+#include "BLI_math_geom.h"
+}
+
+void create_swapped_rotation_matrix(float rot_x_mat[3][3],
+ float rot_y_mat[3][3],
+ float rot_z_mat[3][3],
+ const float euler[3],
+ AbcAxisSwapMode mode)
+{
+ const float rx = euler[0];
+ float ry;
+ float rz;
+
+ /* Apply transformation */
+ switch (mode) {
+ case ABC_ZUP_FROM_YUP:
+ ry = -euler[2];
+ rz = euler[1];
+ break;
+ case ABC_YUP_FROM_ZUP:
+ ry = euler[2];
+ rz = -euler[1];
+ break;
+ default:
+ ry = 0.0f;
+ rz = 0.0f;
+ BLI_assert(false);
+ break;
+ }
+
+ unit_m3(rot_x_mat);
+ unit_m3(rot_y_mat);
+ unit_m3(rot_z_mat);
+
+ rot_x_mat[1][1] = cos(rx);
+ rot_x_mat[2][1] = -sin(rx);
+ rot_x_mat[1][2] = sin(rx);
+ rot_x_mat[2][2] = cos(rx);
+
+ rot_y_mat[2][2] = cos(ry);
+ rot_y_mat[0][2] = -sin(ry);
+ rot_y_mat[2][0] = sin(ry);
+ rot_y_mat[0][0] = cos(ry);
+
+ rot_z_mat[0][0] = cos(rz);
+ rot_z_mat[1][0] = -sin(rz);
+ rot_z_mat[0][1] = sin(rz);
+ rot_z_mat[1][1] = cos(rz);
+}
+
+/* Convert matrix from Z=up to Y=up or vice versa.
+ * Use yup_mat = zup_mat for in-place conversion. */
+void copy_m44_axis_swap(float dst_mat[4][4], float src_mat[4][4], AbcAxisSwapMode mode)
+{
+ float dst_rot[3][3], src_rot[3][3], dst_scale_mat[4][4];
+ float rot_x_mat[3][3], rot_y_mat[3][3], rot_z_mat[3][3];
+ float src_trans[3], dst_scale[3], src_scale[3], euler[3];
+
+ zero_v3(src_trans);
+ zero_v3(dst_scale);
+ zero_v3(src_scale);
+ zero_v3(euler);
+ unit_m3(src_rot);
+ unit_m3(dst_rot);
+ unit_m4(dst_scale_mat);
+
+ /* TODO(Sybren): This code assumes there is no sheer component and no
+ * homogeneous scaling component, which is not always true when writing
+ * non-hierarchical (e.g. flat) objects (e.g. when parent has non-uniform
+ * scale and the child rotates). This is currently not taken into account
+ * when axis-swapping. */
+
+ /* Extract translation, rotation, and scale form matrix. */
+ mat4_to_loc_rot_size(src_trans, src_rot, src_scale, src_mat);
+
+ /* Get euler angles from rotation matrix. */
+ mat3_to_eulO(euler, ROT_MODE_XZY, src_rot);
+
+ /* Create X, Y, Z rotation matrices from euler angles. */
+ create_swapped_rotation_matrix(rot_x_mat, rot_y_mat, rot_z_mat, euler, mode);
+
+ /* Concatenate rotation matrices. */
+ mul_m3_m3m3(dst_rot, dst_rot, rot_z_mat);
+ mul_m3_m3m3(dst_rot, dst_rot, rot_y_mat);
+ mul_m3_m3m3(dst_rot, dst_rot, rot_x_mat);
+
+ mat3_to_eulO(euler, ROT_MODE_XZY, dst_rot);
+
+ /* Start construction of dst_mat from rotation matrix */
+ unit_m4(dst_mat);
+ copy_m4_m3(dst_mat, dst_rot);
+
+ /* Apply translation */
+ switch (mode) {
+ case ABC_ZUP_FROM_YUP:
+ copy_zup_from_yup(dst_mat[3], src_trans);
+ break;
+ case ABC_YUP_FROM_ZUP:
+ copy_yup_from_zup(dst_mat[3], src_trans);
+ break;
+ default:
+ BLI_assert(false);
+ }
+
+ /* Apply scale matrix. Swaps y and z, but does not
+ * negate like translation does. */
+ dst_scale[0] = src_scale[0];
+ dst_scale[1] = src_scale[2];
+ dst_scale[2] = src_scale[1];
+
+ size_to_mat4(dst_scale_mat, dst_scale);
+ mul_m4_m4m4(dst_mat, dst_mat, dst_scale_mat);
+}
+
+/* Recompute transform matrix of object in new coordinate system
+ * (from Z-Up to Y-Up). */
+void create_transform_matrix(Object *obj,
+ float r_yup_mat[4][4],
+ AbcMatrixMode mode,
+ Object *proxy_from)
+{
+ float zup_mat[4][4];
+
+ /* get local or world matrix. */
+ if (mode == ABC_MATRIX_LOCAL && obj->parent) {
+ /* Note that this produces another matrix than the local matrix, due to
+ * constraints and modifiers as well as the obj->parentinv matrix. */
+ invert_m4_m4(obj->parent->imat, obj->parent->obmat);
+ mul_m4_m4m4(zup_mat, obj->parent->imat, obj->obmat);
+ }
+ else {
+ copy_m4_m4(zup_mat, obj->obmat);
+ }
+
+ if (proxy_from) {
+ mul_m4_m4m4(zup_mat, proxy_from->obmat, zup_mat);
+ }
+
+ copy_m44_axis_swap(r_yup_mat, zup_mat, ABC_YUP_FROM_ZUP);
+}
diff --git a/source/blender/io/alembic/intern/abc_axis_conversion.h b/source/blender/io/alembic/intern/abc_axis_conversion.h
new file mode 100644
index 00000000000..7fde0e92ea4
--- /dev/null
+++ b/source/blender/io/alembic/intern/abc_axis_conversion.h
@@ -0,0 +1,99 @@
+/*
+ * 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 Kévin Dietrich & Blender Foundation.
+ * All rights reserved.
+ */
+#pragma once
+
+/** \file
+ * \ingroup Alembic
+ */
+
+struct Object;
+
+#ifdef _MSC_VER
+# define ABC_INLINE static __forceinline
+#else
+# define ABC_INLINE static inline
+#endif
+
+/* TODO(kevin): for now keeping these transformations hardcoded to make sure
+ * everything works properly, and also because Alembic is almost exclusively
+ * used in Y-up software, but eventually they'll be set by the user in the UI
+ * like other importers/exporters do, to support other axis. */
+
+/* Copy from Y-up to Z-up. */
+
+ABC_INLINE void copy_zup_from_yup(float zup[3], const float yup[3])
+{
+ const float old_yup1 = yup[1]; /* in case zup == yup */
+ zup[0] = yup[0];
+ zup[1] = -yup[2];
+ zup[2] = old_yup1;
+}
+
+ABC_INLINE void copy_zup_from_yup(short zup[3], const short yup[3])
+{
+ const short old_yup1 = yup[1]; /* in case zup == yup */
+ zup[0] = yup[0];
+ zup[1] = -yup[2];
+ zup[2] = old_yup1;
+}
+
+/* Copy from Z-up to Y-up. */
+
+ABC_INLINE void copy_yup_from_zup(float yup[3], const float zup[3])
+{
+ const float old_zup1 = zup[1]; /* in case yup == zup */
+ yup[0] = zup[0];
+ yup[1] = zup[2];
+ yup[2] = -old_zup1;
+}
+
+ABC_INLINE void copy_yup_from_zup(short yup[3], const short zup[3])
+{
+ const short old_zup1 = zup[1]; /* in case yup == zup */
+ yup[0] = zup[0];
+ yup[1] = zup[2];
+ yup[2] = -old_zup1;
+}
+
+/* Names are given in (dst, src) order, just like
+ * the parameters of copy_m44_axis_swap() */
+typedef enum {
+ ABC_ZUP_FROM_YUP = 1,
+ ABC_YUP_FROM_ZUP = 2,
+} AbcAxisSwapMode;
+
+/* Create a rotation matrix for each axis from euler angles.
+ * Euler angles are swapped to change coordinate system. */
+void create_swapped_rotation_matrix(float rot_x_mat[3][3],
+ float rot_y_mat[3][3],
+ float rot_z_mat[3][3],
+ const float euler[3],
+ AbcAxisSwapMode mode);
+
+void copy_m44_axis_swap(float dst_mat[4][4], float src_mat[4][4], AbcAxisSwapMode mode);
+
+typedef enum {
+ ABC_MATRIX_WORLD = 1,
+ ABC_MATRIX_LOCAL = 2,
+} AbcMatrixMode;
+
+void create_transform_matrix(Object *obj,
+ float r_transform_mat[4][4],
+ AbcMatrixMode mode,
+ Object *proxy_from);
diff --git a/source/blender/io/alembic/intern/abc_customdata.cc b/source/blender/io/alembic/intern/abc_customdata.cc
index c5f60ac3e29..62f6a52f7cf 100644
--- a/source/blender/io/alembic/intern/abc_customdata.cc
+++ b/source/blender/io/alembic/intern/abc_customdata.cc
@@ -10,7 +10,7 @@
* 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,
+ * 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 Kévin Dietrich.
@@ -27,7 +27,6 @@
#include <algorithm>
#include <unordered_map>
-extern "C" {
#include "DNA_customdata_types.h"
#include "DNA_meshdata_types.h"
@@ -35,7 +34,6 @@ extern "C" {
#include "BLI_utildefines.h"
#include "BKE_customdata.h"
-}
/* NOTE: for now only UVs and Vertex Colors are supported for streaming.
* Although Alembic only allows for a single UV layer per {I|O}Schema, and does
@@ -146,7 +144,7 @@ const char *get_uv_sample(UVSample &sample, const CDStreamConfig &config, Custom
* - (optional due to its behavior) tag as UV using Alembic::AbcGeom::SetIsUV
*/
static void write_uv(const OCompoundProperty &prop,
- const CDStreamConfig &config,
+ CDStreamConfig &config,
void *data,
const char *name)
{
@@ -159,13 +157,18 @@ static void write_uv(const OCompoundProperty &prop,
return;
}
- OV2fGeomParam param(prop, name, true, kFacevaryingScope, 1);
+ std::string uv_map_name(name);
+ OV2fGeomParam param = config.abc_uv_maps[uv_map_name];
+ if (!param.valid()) {
+ param = OV2fGeomParam(prop, name, true, kFacevaryingScope, 1);
+ }
OV2fGeomParam::Sample sample(V2fArraySample(&uvs.front(), uvs.size()),
UInt32ArraySample(&indices.front(), indices.size()),
kFacevaryingScope);
-
param.set(sample);
+
+ config.abc_uv_maps[uv_map_name] = param;
}
/* Convention to write Vertex Colors:
@@ -219,7 +222,7 @@ static void write_mcol(const OCompoundProperty &prop,
}
void write_custom_data(const OCompoundProperty &prop,
- const CDStreamConfig &config,
+ CDStreamConfig &config,
CustomData *data,
int data_type)
{
diff --git a/source/blender/io/alembic/intern/abc_customdata.h b/source/blender/io/alembic/intern/abc_customdata.h
index 6107e230627..96b57b08681 100644
--- a/source/blender/io/alembic/intern/abc_customdata.h
+++ b/source/blender/io/alembic/intern/abc_customdata.h
@@ -10,7 +10,7 @@
* 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,
+ * 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 Kévin Dietrich.
@@ -27,6 +27,8 @@
#include <Alembic/Abc/All.h>
#include <Alembic/AbcGeom/All.h>
+#include <map>
+
struct CustomData;
struct MLoop;
struct MLoopUV;
@@ -68,6 +70,14 @@ struct CDStreamConfig {
Alembic::AbcGeom::index_t index;
Alembic::AbcGeom::index_t ceil_index;
+ const char **modifier_error_message;
+
+ /* Alembic needs Blender to keep references to C++ objects (the destructors
+ * finalize the writing to ABC). This map stores OV2fGeomParam objects for the
+ * 2nd and subsequent UV maps; the primary UV map is kept alive by the Alembic
+ * mesh sample itself. */
+ std::map<std::string, Alembic::AbcGeom::OV2fGeomParam> abc_uv_maps;
+
CDStreamConfig()
: mloop(NULL),
totloop(0),
@@ -80,7 +90,8 @@ struct CDStreamConfig {
weight(0.0f),
time(0.0f),
index(0),
- ceil_index(0)
+ ceil_index(0),
+ modifier_error_message(NULL)
{
}
};
@@ -92,7 +103,7 @@ struct CDStreamConfig {
const char *get_uv_sample(UVSample &sample, const CDStreamConfig &config, CustomData *data);
void write_custom_data(const OCompoundProperty &prop,
- const CDStreamConfig &config,
+ CDStreamConfig &config,
CustomData *data,
int data_type);
diff --git a/source/blender/io/alembic/intern/abc_exporter.cc b/source/blender/io/alembic/intern/abc_exporter.cc
index fb75fb1f6c7..dbf24452b78 100644
--- a/source/blender/io/alembic/intern/abc_exporter.cc
+++ b/source/blender/io/alembic/intern/abc_exporter.cc
@@ -33,7 +33,6 @@
#include "abc_writer_points.h"
#include "abc_writer_transform.h"
-extern "C" {
#include "DNA_camera_types.h"
#include "DNA_curve_types.h"
#include "DNA_fluid_types.h"
@@ -51,7 +50,7 @@ extern "C" {
# include "BLI_winstuff.h"
#endif
-#include "BKE_anim.h"
+#include "BKE_duplilist.h"
#include "BKE_global.h"
#include "BKE_idprop.h"
#include "BKE_layer.h"
@@ -62,7 +61,6 @@ extern "C" {
#include "BKE_scene.h"
#include "DEG_depsgraph_query.h"
-}
using Alembic::Abc::OBox3dProperty;
using Alembic::Abc::TimeSamplingPtr;
@@ -105,7 +103,7 @@ ExportSettings::ExportSettings()
static bool object_is_smoke_sim(Object *ob)
{
- ModifierData *md = modifiers_findByType(ob, eModifierType_Fluid);
+ ModifierData *md = BKE_modifiers_findby_type(ob, eModifierType_Fluid);
if (md) {
FluidModifierData *smd = reinterpret_cast<FluidModifierData *>(md);
diff --git a/source/blender/io/alembic/intern/abc_reader_archive.cc b/source/blender/io/alembic/intern/abc_reader_archive.cc
index 6ad44553701..563466d81bc 100644
--- a/source/blender/io/alembic/intern/abc_reader_archive.cc
+++ b/source/blender/io/alembic/intern/abc_reader_archive.cc
@@ -10,7 +10,7 @@
* 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,
+ * 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 Kévin Dietrich.
@@ -23,12 +23,10 @@
#include "abc_reader_archive.h"
-extern "C" {
#include "BKE_main.h"
#include "BLI_path_util.h"
#include "BLI_string.h"
-}
#ifdef WIN32
# include "utfconv.h"
diff --git a/source/blender/io/alembic/intern/abc_reader_archive.h b/source/blender/io/alembic/intern/abc_reader_archive.h
index bdb53bd0b8c..35273e10108 100644
--- a/source/blender/io/alembic/intern/abc_reader_archive.h
+++ b/source/blender/io/alembic/intern/abc_reader_archive.h
@@ -10,7 +10,7 @@
* 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,
+ * 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 Kévin Dietrich.
diff --git a/source/blender/io/alembic/intern/abc_reader_camera.cc b/source/blender/io/alembic/intern/abc_reader_camera.cc
index ab506f32cbe..0752534f8c2 100644
--- a/source/blender/io/alembic/intern/abc_reader_camera.cc
+++ b/source/blender/io/alembic/intern/abc_reader_camera.cc
@@ -22,7 +22,6 @@
#include "abc_reader_transform.h"
#include "abc_util.h"
-extern "C" {
#include "DNA_camera_types.h"
#include "DNA_object_types.h"
@@ -30,7 +29,6 @@ extern "C" {
#include "BKE_object.h"
#include "BLI_math.h"
-}
using Alembic::AbcGeom::CameraSample;
using Alembic::AbcGeom::ICamera;
diff --git a/source/blender/io/alembic/intern/abc_reader_curves.cc b/source/blender/io/alembic/intern/abc_reader_curves.cc
index 1be164c7c94..d5e0b694294 100644
--- a/source/blender/io/alembic/intern/abc_reader_curves.cc
+++ b/source/blender/io/alembic/intern/abc_reader_curves.cc
@@ -10,7 +10,7 @@
* 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,
+ * 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 Kévin Dietrich.
@@ -22,6 +22,7 @@
*/
#include "abc_reader_curves.h"
+#include "abc_axis_conversion.h"
#include "abc_reader_transform.h"
#include "abc_util.h"
@@ -29,7 +30,6 @@
#include "MEM_guardedalloc.h"
-extern "C" {
#include "DNA_curve_types.h"
#include "DNA_object_types.h"
@@ -38,7 +38,6 @@ extern "C" {
#include "BKE_curve.h"
#include "BKE_mesh.h"
#include "BKE_object.h"
-}
using Alembic::Abc::FloatArraySamplePtr;
using Alembic::Abc::Int32ArraySamplePtr;
diff --git a/source/blender/io/alembic/intern/abc_reader_curves.h b/source/blender/io/alembic/intern/abc_reader_curves.h
index 763a83f586f..eb0538308f8 100644
--- a/source/blender/io/alembic/intern/abc_reader_curves.h
+++ b/source/blender/io/alembic/intern/abc_reader_curves.h
@@ -10,7 +10,7 @@
* 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,
+ * 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 Kévin Dietrich.
diff --git a/source/blender/io/alembic/intern/abc_reader_mesh.cc b/source/blender/io/alembic/intern/abc_reader_mesh.cc
index ec74fb2137e..8b79a3a0aa0 100644
--- a/source/blender/io/alembic/intern/abc_reader_mesh.cc
+++ b/source/blender/io/alembic/intern/abc_reader_mesh.cc
@@ -19,6 +19,7 @@
*/
#include "abc_reader_mesh.h"
+#include "abc_axis_conversion.h"
#include "abc_reader_transform.h"
#include "abc_util.h"
@@ -26,7 +27,6 @@
#include "MEM_guardedalloc.h"
-extern "C" {
#include "DNA_material_types.h"
#include "DNA_mesh_types.h"
#include "DNA_meshdata_types.h"
@@ -39,7 +39,6 @@ extern "C" {
#include "BKE_mesh.h"
#include "BKE_modifier.h"
#include "BKE_object.h"
-}
using Alembic::Abc::Int32ArraySamplePtr;
using Alembic::Abc::P3fArraySamplePtr;
@@ -201,6 +200,7 @@ static void read_mpolys(CDStreamConfig &config, const AbcMeshData &mesh_data)
unsigned int loop_index = 0;
unsigned int rev_loop_index = 0;
unsigned int uv_index = 0;
+ bool seen_invalid_geometry = false;
for (int i = 0; i < face_counts->size(); i++) {
const int face_size = (*face_counts)[i];
@@ -216,10 +216,18 @@ static void read_mpolys(CDStreamConfig &config, const AbcMeshData &mesh_data)
/* NOTE: Alembic data is stored in the reverse order. */
rev_loop_index = loop_index + (face_size - 1);
+ uint last_vertex_index = 0;
for (int f = 0; f < face_size; f++, loop_index++, rev_loop_index--) {
MLoop &loop = mloops[rev_loop_index];
loop.v = (*face_indices)[loop_index];
+ if (f > 0 && loop.v == last_vertex_index) {
+ /* This face is invalid, as it has consecutive loops from the same vertex. This is caused
+ * by invalid geometry in the Alembic file, such as in T76514. */
+ seen_invalid_geometry = true;
+ }
+ last_vertex_index = loop.v;
+
if (do_uvs) {
MLoopUV &loopuv = mloopuvs[rev_loop_index];
@@ -237,6 +245,12 @@ static void read_mpolys(CDStreamConfig &config, const AbcMeshData &mesh_data)
}
BKE_mesh_calc_edges(config.mesh, false, false);
+ if (seen_invalid_geometry) {
+ if (config.modifier_error_message) {
+ *config.modifier_error_message = "Mesh hash invalid geometry; more details on the console";
+ }
+ BKE_mesh_validate(config.mesh, true, true);
+ }
}
static void process_no_normals(CDStreamConfig &config)
@@ -467,6 +481,19 @@ bool AbcMeshReader::valid() const
return m_schema.valid();
}
+/* Specialisation of has_animations() as defined in abc_reader_object.h. */
+template<> bool has_animations(Alembic::AbcGeom::IPolyMeshSchema &schema, ImportSettings *settings)
+{
+ if (settings->is_sequence || !schema.isConstant()) {
+ return true;
+ }
+
+ IV2fGeomParam uvsParam = schema.getUVsParam();
+ IN3fGeomParam normalsParam = schema.getNormalsParam();
+ return (uvsParam.valid() && !uvsParam.isConstant()) ||
+ (normalsParam.valid() && !normalsParam.isConstant());
+}
+
void AbcMeshReader::readObjectData(Main *bmain, const Alembic::Abc::ISampleSelector &sample_sel)
{
Mesh *mesh = BKE_mesh_add(bmain, m_data_name.c_str());
@@ -609,6 +636,7 @@ Mesh *AbcMeshReader::read_mesh(Mesh *existing_mesh,
CDStreamConfig config = get_config(new_mesh ? new_mesh : existing_mesh);
config.time = sample_sel.getRequestedTime();
+ config.modifier_error_message = err_str;
read_mesh_sample(m_iobject.getFullName(), &settings, m_schema, sample_sel, config);
diff --git a/source/blender/io/alembic/intern/abc_reader_nurbs.cc b/source/blender/io/alembic/intern/abc_reader_nurbs.cc
index 0ada10baba5..5b9954b3ff6 100644
--- a/source/blender/io/alembic/intern/abc_reader_nurbs.cc
+++ b/source/blender/io/alembic/intern/abc_reader_nurbs.cc
@@ -19,12 +19,12 @@
*/
#include "abc_reader_nurbs.h"
+#include "abc_axis_conversion.h"
#include "abc_reader_transform.h"
#include "abc_util.h"
#include "MEM_guardedalloc.h"
-extern "C" {
#include "DNA_curve_types.h"
#include "DNA_object_types.h"
@@ -33,7 +33,6 @@ extern "C" {
#include "BKE_curve.h"
#include "BKE_object.h"
-}
using Alembic::AbcGeom::FloatArraySamplePtr;
using Alembic::AbcGeom::kWrapExisting;
@@ -72,7 +71,7 @@ bool AbcNurbsReader::valid() const
static bool set_knots(const FloatArraySamplePtr &knots, float *&nu_knots)
{
- if (!knots || knots->size() == 0) {
+ if (!knots || knots->size() < 2) {
return false;
}
diff --git a/source/blender/io/alembic/intern/abc_reader_object.cc b/source/blender/io/alembic/intern/abc_reader_object.cc
index 9b0c3237c45..e5bd0771a42 100644
--- a/source/blender/io/alembic/intern/abc_reader_object.cc
+++ b/source/blender/io/alembic/intern/abc_reader_object.cc
@@ -19,9 +19,9 @@
*/
#include "abc_reader_object.h"
+#include "abc_axis_conversion.h"
#include "abc_util.h"
-extern "C" {
#include "DNA_cachefile_types.h"
#include "DNA_constraint_types.h"
#include "DNA_modifier_types.h"
@@ -36,7 +36,6 @@ extern "C" {
#include "BLI_math_geom.h"
#include "BLI_string.h"
#include "BLI_utildefines.h"
-}
using Alembic::AbcGeom::IObject;
using Alembic::AbcGeom::IXform;
@@ -295,7 +294,7 @@ void AbcObjectReader::read_matrix(float r_mat[4][4] /* local matrix */,
void AbcObjectReader::addCacheModifier()
{
- ModifierData *md = modifier_new(eModifierType_MeshSequenceCache);
+ ModifierData *md = BKE_modifier_new(eModifierType_MeshSequenceCache);
BLI_addtail(&m_object->modifiers, md);
MeshSeqCacheModifierData *mcmd = reinterpret_cast<MeshSeqCacheModifierData *>(md);
diff --git a/source/blender/io/alembic/intern/abc_reader_object.h b/source/blender/io/alembic/intern/abc_reader_object.h
index 94923df2df9..dcc2697e0b5 100644
--- a/source/blender/io/alembic/intern/abc_reader_object.h
+++ b/source/blender/io/alembic/intern/abc_reader_object.h
@@ -24,9 +24,7 @@
#include <Alembic/Abc/All.h>
#include <Alembic/AbcGeom/All.h>
-extern "C" {
#include "DNA_ID.h"
-}
struct CacheFile;
struct Main;
diff --git a/source/blender/io/alembic/intern/abc_reader_points.cc b/source/blender/io/alembic/intern/abc_reader_points.cc
index e4dc345f868..c5d08693176 100644
--- a/source/blender/io/alembic/intern/abc_reader_points.cc
+++ b/source/blender/io/alembic/intern/abc_reader_points.cc
@@ -10,7 +10,7 @@
* 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,
+ * 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 Kévin Dietrich.
@@ -26,14 +26,12 @@
#include "abc_reader_transform.h"
#include "abc_util.h"
-extern "C" {
#include "DNA_mesh_types.h"
#include "DNA_object_types.h"
#include "BKE_customdata.h"
#include "BKE_mesh.h"
#include "BKE_object.h"
-}
using Alembic::AbcGeom::kWrapExisting;
using Alembic::AbcGeom::N3fArraySamplePtr;
diff --git a/source/blender/io/alembic/intern/abc_reader_points.h b/source/blender/io/alembic/intern/abc_reader_points.h
index bb33afb466f..99881e091f9 100644
--- a/source/blender/io/alembic/intern/abc_reader_points.h
+++ b/source/blender/io/alembic/intern/abc_reader_points.h
@@ -10,7 +10,7 @@
* 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,
+ * 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 Kévin Dietrich.
diff --git a/source/blender/io/alembic/intern/abc_reader_transform.cc b/source/blender/io/alembic/intern/abc_reader_transform.cc
index ce569a9ccb5..3df391f8432 100644
--- a/source/blender/io/alembic/intern/abc_reader_transform.cc
+++ b/source/blender/io/alembic/intern/abc_reader_transform.cc
@@ -21,13 +21,11 @@
#include "abc_reader_transform.h"
#include "abc_util.h"
-extern "C" {
#include "DNA_object_types.h"
#include "BLI_utildefines.h"
#include "BKE_object.h"
-}
using Alembic::Abc::ISampleSelector;
diff --git a/source/blender/io/alembic/intern/abc_util.cc b/source/blender/io/alembic/intern/abc_util.cc
index b26ef8b3b76..1f3bd2a1aaa 100644
--- a/source/blender/io/alembic/intern/abc_util.cc
+++ b/source/blender/io/alembic/intern/abc_util.cc
@@ -20,6 +20,7 @@
#include "abc_util.h"
+#include "abc_axis_conversion.h"
#include "abc_reader_camera.h"
#include "abc_reader_curves.h"
#include "abc_reader_mesh.h"
@@ -31,13 +32,11 @@
#include <algorithm>
-extern "C" {
#include "DNA_object_types.h"
#include "BLI_math_geom.h"
#include "PIL_time.h"
-}
std::string get_id_name(const Object *const ob)
{
@@ -121,144 +120,6 @@ void split(const std::string &s, const char delim, std::vector<std::string> &tok
}
}
-void create_swapped_rotation_matrix(float rot_x_mat[3][3],
- float rot_y_mat[3][3],
- float rot_z_mat[3][3],
- const float euler[3],
- AbcAxisSwapMode mode)
-{
- const float rx = euler[0];
- float ry;
- float rz;
-
- /* Apply transformation */
- switch (mode) {
- case ABC_ZUP_FROM_YUP:
- ry = -euler[2];
- rz = euler[1];
- break;
- case ABC_YUP_FROM_ZUP:
- ry = euler[2];
- rz = -euler[1];
- break;
- default:
- ry = 0.0f;
- rz = 0.0f;
- BLI_assert(false);
- break;
- }
-
- unit_m3(rot_x_mat);
- unit_m3(rot_y_mat);
- unit_m3(rot_z_mat);
-
- rot_x_mat[1][1] = cos(rx);
- rot_x_mat[2][1] = -sin(rx);
- rot_x_mat[1][2] = sin(rx);
- rot_x_mat[2][2] = cos(rx);
-
- rot_y_mat[2][2] = cos(ry);
- rot_y_mat[0][2] = -sin(ry);
- rot_y_mat[2][0] = sin(ry);
- rot_y_mat[0][0] = cos(ry);
-
- rot_z_mat[0][0] = cos(rz);
- rot_z_mat[1][0] = -sin(rz);
- rot_z_mat[0][1] = sin(rz);
- rot_z_mat[1][1] = cos(rz);
-}
-
-/* Convert matrix from Z=up to Y=up or vice versa.
- * Use yup_mat = zup_mat for in-place conversion. */
-void copy_m44_axis_swap(float dst_mat[4][4], float src_mat[4][4], AbcAxisSwapMode mode)
-{
- float dst_rot[3][3], src_rot[3][3], dst_scale_mat[4][4];
- float rot_x_mat[3][3], rot_y_mat[3][3], rot_z_mat[3][3];
- float src_trans[3], dst_scale[3], src_scale[3], euler[3];
-
- zero_v3(src_trans);
- zero_v3(dst_scale);
- zero_v3(src_scale);
- zero_v3(euler);
- unit_m3(src_rot);
- unit_m3(dst_rot);
- unit_m4(dst_scale_mat);
-
- /* TODO(Sybren): This code assumes there is no sheer component and no
- * homogeneous scaling component, which is not always true when writing
- * non-hierarchical (e.g. flat) objects (e.g. when parent has non-uniform
- * scale and the child rotates). This is currently not taken into account
- * when axis-swapping. */
-
- /* Extract translation, rotation, and scale form matrix. */
- mat4_to_loc_rot_size(src_trans, src_rot, src_scale, src_mat);
-
- /* Get euler angles from rotation matrix. */
- mat3_to_eulO(euler, ROT_MODE_XZY, src_rot);
-
- /* Create X, Y, Z rotation matrices from euler angles. */
- create_swapped_rotation_matrix(rot_x_mat, rot_y_mat, rot_z_mat, euler, mode);
-
- /* Concatenate rotation matrices. */
- mul_m3_m3m3(dst_rot, dst_rot, rot_z_mat);
- mul_m3_m3m3(dst_rot, dst_rot, rot_y_mat);
- mul_m3_m3m3(dst_rot, dst_rot, rot_x_mat);
-
- mat3_to_eulO(euler, ROT_MODE_XZY, dst_rot);
-
- /* Start construction of dst_mat from rotation matrix */
- unit_m4(dst_mat);
- copy_m4_m3(dst_mat, dst_rot);
-
- /* Apply translation */
- switch (mode) {
- case ABC_ZUP_FROM_YUP:
- copy_zup_from_yup(dst_mat[3], src_trans);
- break;
- case ABC_YUP_FROM_ZUP:
- copy_yup_from_zup(dst_mat[3], src_trans);
- break;
- default:
- BLI_assert(false);
- }
-
- /* Apply scale matrix. Swaps y and z, but does not
- * negate like translation does. */
- dst_scale[0] = src_scale[0];
- dst_scale[1] = src_scale[2];
- dst_scale[2] = src_scale[1];
-
- size_to_mat4(dst_scale_mat, dst_scale);
- mul_m4_m4m4(dst_mat, dst_mat, dst_scale_mat);
-}
-
-/* Recompute transform matrix of object in new coordinate system
- * (from Z-Up to Y-Up). */
-void create_transform_matrix(Object *obj,
- float r_yup_mat[4][4],
- AbcMatrixMode mode,
- Object *proxy_from)
-{
- float zup_mat[4][4];
-
- /* get local or world matrix. */
- if (mode == ABC_MATRIX_LOCAL && obj->parent) {
- /* Note that this produces another matrix than the local matrix, due to
- * constraints and modifiers as well as the obj->parentinv matrix. */
- invert_m4_m4(obj->parent->imat, obj->parent->obmat);
- mul_m4_m4m4(zup_mat, obj->parent->imat, obj->obmat);
- }
- else {
- copy_m4_m4(zup_mat, obj->obmat);
- }
-
- if (proxy_from) {
- mul_m4_m4m4(zup_mat, proxy_from->obmat, zup_mat);
- }
-
- copy_m44_axis_swap(r_yup_mat, zup_mat, ABC_YUP_FROM_ZUP);
-}
-
bool has_property(const Alembic::Abc::ICompoundProperty &prop, const std::string &name)
{
if (!prop.valid()) {
diff --git a/source/blender/io/alembic/intern/abc_util.h b/source/blender/io/alembic/intern/abc_util.h
index 0b3462c2132..57b4d9800a5 100644
--- a/source/blender/io/alembic/intern/abc_util.h
+++ b/source/blender/io/alembic/intern/abc_util.h
@@ -56,15 +56,6 @@ Imath::M44d convert_matrix_datatype(float mat[4][4]);
/* Convert from Alembic to float matrix representations. Does NOT convert from Y-up to Z-up. */
void convert_matrix_datatype(const Imath::M44d &xform, float r_mat[4][4]);
-typedef enum {
- ABC_MATRIX_WORLD = 1,
- ABC_MATRIX_LOCAL = 2,
-} AbcMatrixMode;
-void create_transform_matrix(Object *obj,
- float r_transform_mat[4][4],
- AbcMatrixMode mode,
- Object *proxy_from);
-
void split(const std::string &s, const char delim, std::vector<std::string> &tokens);
template<class TContainer> bool begins_with(const TContainer &input, const TContainer &match)
@@ -115,66 +106,6 @@ float get_weight_and_index(float time,
AbcObjectReader *create_reader(const Alembic::AbcGeom::IObject &object, ImportSettings &settings);
-/* ************************** */
-
-/* TODO(kevin): for now keeping these transformations hardcoded to make sure
- * everything works properly, and also because Alembic is almost exclusively
- * used in Y-up software, but eventually they'll be set by the user in the UI
- * like other importers/exporters do, to support other axis. */
-
-/* Copy from Y-up to Z-up. */
-
-ABC_INLINE void copy_zup_from_yup(float zup[3], const float yup[3])
-{
- const float old_yup1 = yup[1]; /* in case zup == yup */
- zup[0] = yup[0];
- zup[1] = -yup[2];
- zup[2] = old_yup1;
-}
-
-ABC_INLINE void copy_zup_from_yup(short zup[3], const short yup[3])
-{
- const short old_yup1 = yup[1]; /* in case zup == yup */
- zup[0] = yup[0];
- zup[1] = -yup[2];
- zup[2] = old_yup1;
-}
-
-/* Copy from Z-up to Y-up. */
-
-ABC_INLINE void copy_yup_from_zup(float yup[3], const float zup[3])
-{
- const float old_zup1 = zup[1]; /* in case yup == zup */
- yup[0] = zup[0];
- yup[1] = zup[2];
- yup[2] = -old_zup1;
-}
-
-ABC_INLINE void copy_yup_from_zup(short yup[3], const short zup[3])
-{
- const short old_zup1 = zup[1]; /* in case yup == zup */
- yup[0] = zup[0];
- yup[1] = zup[2];
- yup[2] = -old_zup1;
-}
-
-/* Names are given in (dst, src) order, just like
- * the parameters of copy_m44_axis_swap() */
-typedef enum {
- ABC_ZUP_FROM_YUP = 1,
- ABC_YUP_FROM_ZUP = 2,
-} AbcAxisSwapMode;
-
-/* Create a rotation matrix for each axis from euler angles.
- * Euler angles are swapped to change coordinate system. */
-void create_swapped_rotation_matrix(float rot_x_mat[3][3],
- float rot_y_mat[3][3],
- float rot_z_mat[3][3],
- const float euler[3],
- AbcAxisSwapMode mode);
-
-void copy_m44_axis_swap(float dst_mat[4][4], float src_mat[4][4], AbcAxisSwapMode mode);
-
/* *************************** */
#undef ABC_DEBUG_TIME
diff --git a/source/blender/io/alembic/intern/abc_writer_archive.cc b/source/blender/io/alembic/intern/abc_writer_archive.cc
index af18d480a18..e7dee536cb9 100644
--- a/source/blender/io/alembic/intern/abc_writer_archive.cc
+++ b/source/blender/io/alembic/intern/abc_writer_archive.cc
@@ -10,7 +10,7 @@
* 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,
+ * 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 Kévin Dietrich.
@@ -22,14 +22,13 @@
*/
#include "abc_writer_archive.h"
-extern "C" {
+
#include "BKE_blender_version.h"
#include "BLI_path_util.h"
#include "BLI_string.h"
#include "DNA_scene_types.h"
-}
#ifdef WIN32
# include "utfconv.h"
@@ -53,7 +52,7 @@ static OArchive create_archive(std::ostream *ostream,
abc_metadata.set(Alembic::Abc::kApplicationNameKey, "Blender");
abc_metadata.set(Alembic::Abc::kUserDescriptionKey, scene_name);
- abc_metadata.set("blender_version", versionstr);
+ abc_metadata.set("blender_version", std::string("v") + BKE_blender_version_string());
abc_metadata.set("FramesPerTimeUnit", std::to_string(scene_fps));
time_t raw_time;
diff --git a/source/blender/io/alembic/intern/abc_writer_archive.h b/source/blender/io/alembic/intern/abc_writer_archive.h
index e261e60990a..82b0e98b376 100644
--- a/source/blender/io/alembic/intern/abc_writer_archive.h
+++ b/source/blender/io/alembic/intern/abc_writer_archive.h
@@ -10,7 +10,7 @@
* 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,
+ * 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 Kévin Dietrich.
diff --git a/source/blender/io/alembic/intern/abc_writer_camera.cc b/source/blender/io/alembic/intern/abc_writer_camera.cc
index e705e5ba911..07ae81e584f 100644
--- a/source/blender/io/alembic/intern/abc_writer_camera.cc
+++ b/source/blender/io/alembic/intern/abc_writer_camera.cc
@@ -21,10 +21,8 @@
#include "abc_writer_camera.h"
#include "abc_writer_transform.h"
-extern "C" {
#include "DNA_camera_types.h"
#include "DNA_object_types.h"
-}
using Alembic::AbcGeom::OCamera;
using Alembic::AbcGeom::OFloatProperty;
diff --git a/source/blender/io/alembic/intern/abc_writer_curves.cc b/source/blender/io/alembic/intern/abc_writer_curves.cc
index 3ab9b365a72..db93ac1920e 100644
--- a/source/blender/io/alembic/intern/abc_writer_curves.cc
+++ b/source/blender/io/alembic/intern/abc_writer_curves.cc
@@ -10,7 +10,7 @@
* 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,
+ * 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 Kévin Dietrich.
@@ -22,17 +22,16 @@
*/
#include "abc_writer_curves.h"
+#include "abc_axis_conversion.h"
#include "abc_reader_curves.h"
#include "abc_writer_transform.h"
-extern "C" {
#include "DNA_curve_types.h"
#include "DNA_object_types.h"
#include "BKE_curve.h"
#include "BKE_mesh.h"
#include "BKE_object.h"
-}
using Alembic::AbcGeom::OCompoundProperty;
using Alembic::AbcGeom::OCurves;
diff --git a/source/blender/io/alembic/intern/abc_writer_curves.h b/source/blender/io/alembic/intern/abc_writer_curves.h
index e57978ada2a..83f0289dd2d 100644
--- a/source/blender/io/alembic/intern/abc_writer_curves.h
+++ b/source/blender/io/alembic/intern/abc_writer_curves.h
@@ -10,7 +10,7 @@
* 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,
+ * 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 Kévin Dietrich.
diff --git a/source/blender/io/alembic/intern/abc_writer_hair.cc b/source/blender/io/alembic/intern/abc_writer_hair.cc
index f29d195f2ff..ed62889b03d 100644
--- a/source/blender/io/alembic/intern/abc_writer_hair.cc
+++ b/source/blender/io/alembic/intern/abc_writer_hair.cc
@@ -19,12 +19,11 @@
*/
#include "abc_writer_hair.h"
-#include "abc_util.h"
+#include "abc_axis_conversion.h"
#include "abc_writer_transform.h"
#include <cstdio>
-extern "C" {
#include "DNA_mesh_types.h"
#include "DNA_meshdata_types.h"
#include "DNA_modifier_types.h"
@@ -35,7 +34,6 @@ extern "C" {
#include "BKE_mesh.h"
#include "BKE_mesh_runtime.h"
#include "BKE_particle.h"
-}
using Alembic::Abc::P3fArraySamplePtr;
diff --git a/source/blender/io/alembic/intern/abc_writer_mball.cc b/source/blender/io/alembic/intern/abc_writer_mball.cc
index 151848674f9..3593acf18b0 100644
--- a/source/blender/io/alembic/intern/abc_writer_mball.cc
+++ b/source/blender/io/alembic/intern/abc_writer_mball.cc
@@ -21,7 +21,6 @@
#include "abc_writer_mball.h"
#include "abc_writer_mesh.h"
-extern "C" {
#include "DNA_mesh_types.h"
#include "DNA_meta_types.h"
#include "DNA_object_types.h"
@@ -33,7 +32,6 @@ extern "C" {
#include "BKE_object.h"
#include "BLI_utildefines.h"
-}
AbcMBallWriter::AbcMBallWriter(Main *bmain,
Object *ob,
diff --git a/source/blender/io/alembic/intern/abc_writer_mesh.cc b/source/blender/io/alembic/intern/abc_writer_mesh.cc
index f81b9505048..df1734c9de1 100644
--- a/source/blender/io/alembic/intern/abc_writer_mesh.cc
+++ b/source/blender/io/alembic/intern/abc_writer_mesh.cc
@@ -19,16 +19,15 @@
*/
#include "abc_writer_mesh.h"
-#include "abc_util.h"
+#include "abc_axis_conversion.h"
#include "abc_writer_transform.h"
-extern "C" {
#include "DNA_material_types.h"
#include "DNA_mesh_types.h"
#include "DNA_meshdata_types.h"
#include "DNA_object_fluidsim_types.h"
-#include "BKE_animsys.h"
+#include "BKE_anim_data.h"
#include "BKE_key.h"
#include "BKE_lib_id.h"
#include "BKE_material.h"
@@ -40,7 +39,6 @@ extern "C" {
#include "bmesh_tools.h"
#include "DEG_depsgraph_query.h"
-}
using Alembic::Abc::FloatArraySample;
using Alembic::Abc::Int32ArraySample;
@@ -139,7 +137,8 @@ static void get_loop_normals(struct Mesh *mesh,
/* If all polygons are smooth shaded, and there are no custom normals, we don't need to export
* normals at all. This is also done by other software, see T71246. */
- if (!has_flat_shaded_poly && !CustomData_has_layer(&mesh->ldata, CD_CUSTOMLOOPNORMAL)) {
+ if (!has_flat_shaded_poly && !CustomData_has_layer(&mesh->ldata, CD_CUSTOMLOOPNORMAL) &&
+ (mesh->flag & ME_AUTOSMOOTH) == 0) {
return;
}
@@ -169,7 +168,7 @@ static ModifierData *get_subsurf_modifier(Scene *scene, Object *ob)
ModifierData *md = static_cast<ModifierData *>(ob->modifiers.last);
for (; md; md = md->prev) {
- if (!modifier_isEnabled(scene, md, eModifierMode_Render)) {
+ if (!BKE_modifier_is_enabled(scene, md, eModifierMode_Render)) {
continue;
}
@@ -192,9 +191,9 @@ static ModifierData *get_subsurf_modifier(Scene *scene, Object *ob)
static ModifierData *get_liquid_sim_modifier(Scene *scene, Object *ob)
{
- ModifierData *md = modifiers_findByType(ob, eModifierType_Fluidsim);
+ ModifierData *md = BKE_modifiers_findby_type(ob, eModifierType_Fluidsim);
- if (md && (modifier_isEnabled(scene, md, eModifierMode_Render))) {
+ if (md && (BKE_modifier_is_enabled(scene, md, eModifierMode_Render))) {
FluidsimModifierData *fsmd = reinterpret_cast<FluidsimModifierData *>(md);
if (fsmd->fss && fsmd->fss->type == OB_FLUIDSIM_DOMAIN) {
@@ -335,7 +334,7 @@ void AbcGenericMeshWriter::writeMesh(struct Mesh *mesh)
V3fArraySample(points), Int32ArraySample(poly_verts), Int32ArraySample(loop_counts));
UVSample sample;
- if (m_first_frame && m_settings.export_uvs) {
+ if (m_settings.export_uvs) {
const char *name = get_uv_sample(sample, m_custom_data_config, &mesh->ldata);
if (!sample.indices.empty() && !sample.uvs.empty()) {
diff --git a/source/blender/io/alembic/intern/abc_writer_nurbs.cc b/source/blender/io/alembic/intern/abc_writer_nurbs.cc
index d643f5482c0..8b4a1050d33 100644
--- a/source/blender/io/alembic/intern/abc_writer_nurbs.cc
+++ b/source/blender/io/alembic/intern/abc_writer_nurbs.cc
@@ -19,17 +19,15 @@
*/
#include "abc_writer_nurbs.h"
-#include "abc_util.h"
+#include "abc_axis_conversion.h"
#include "abc_writer_transform.h"
-extern "C" {
#include "DNA_curve_types.h"
#include "DNA_object_types.h"
#include "BLI_listbase.h"
#include "BKE_curve.h"
-}
using Alembic::AbcGeom::FloatArraySample;
using Alembic::AbcGeom::OBoolProperty;
diff --git a/source/blender/io/alembic/intern/abc_writer_object.cc b/source/blender/io/alembic/intern/abc_writer_object.cc
index 75dc93bd08e..f4a3587f54d 100644
--- a/source/blender/io/alembic/intern/abc_writer_object.cc
+++ b/source/blender/io/alembic/intern/abc_writer_object.cc
@@ -20,11 +20,9 @@
#include "abc_writer_object.h"
-extern "C" {
#include "DNA_object_types.h"
#include "BKE_object.h"
-}
AbcObjectWriter::AbcObjectWriter(Object *ob,
uint32_t time_sampling,
diff --git a/source/blender/io/alembic/intern/abc_writer_object.h b/source/blender/io/alembic/intern/abc_writer_object.h
index c3511566372..830c4aee903 100644
--- a/source/blender/io/alembic/intern/abc_writer_object.h
+++ b/source/blender/io/alembic/intern/abc_writer_object.h
@@ -26,9 +26,7 @@
#include "abc_exporter.h"
-extern "C" {
#include "DNA_ID.h"
-}
class AbcTransformWriter;
diff --git a/source/blender/io/alembic/intern/abc_writer_points.cc b/source/blender/io/alembic/intern/abc_writer_points.cc
index 70a1ead239a..d45af2eed4c 100644
--- a/source/blender/io/alembic/intern/abc_writer_points.cc
+++ b/source/blender/io/alembic/intern/abc_writer_points.cc
@@ -10,7 +10,7 @@
* 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,
+ * 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 Kévin Dietrich.
@@ -26,7 +26,6 @@
#include "abc_writer_mesh.h"
#include "abc_writer_transform.h"
-extern "C" {
#include "DNA_object_types.h"
#include "DNA_particle_types.h"
@@ -36,7 +35,6 @@ extern "C" {
#include "BLI_math.h"
#include "DEG_depsgraph_query.h"
-}
using Alembic::AbcGeom::kVertexScope;
using Alembic::AbcGeom::OPoints;
diff --git a/source/blender/io/alembic/intern/abc_writer_points.h b/source/blender/io/alembic/intern/abc_writer_points.h
index c171cddd10e..184a363ae6b 100644
--- a/source/blender/io/alembic/intern/abc_writer_points.h
+++ b/source/blender/io/alembic/intern/abc_writer_points.h
@@ -10,7 +10,7 @@
* 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,
+ * 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 Kévin Dietrich.
diff --git a/source/blender/io/alembic/intern/abc_writer_transform.cc b/source/blender/io/alembic/intern/abc_writer_transform.cc
index d7bcc46d96f..1ec7db0a1c6 100644
--- a/source/blender/io/alembic/intern/abc_writer_transform.cc
+++ b/source/blender/io/alembic/intern/abc_writer_transform.cc
@@ -19,17 +19,15 @@
*/
#include "abc_writer_transform.h"
-#include "abc_util.h"
+#include "abc_axis_conversion.h"
#include <OpenEXR/ImathBoxAlgo.h>
-extern "C" {
#include "DNA_object_types.h"
#include "BLI_math.h"
#include "DEG_depsgraph_query.h"
-}
using Alembic::AbcGeom::OObject;
using Alembic::AbcGeom::OXform;
diff --git a/source/blender/io/alembic/intern/alembic_capi.cc b/source/blender/io/alembic/intern/alembic_capi.cc
index ced5791e0e8..6ca9e82a26c 100644
--- a/source/blender/io/alembic/intern/alembic_capi.cc
+++ b/source/blender/io/alembic/intern/alembic_capi.cc
@@ -40,7 +40,6 @@
#include "MEM_guardedalloc.h"
-extern "C" {
#include "DNA_cachefile_types.h"
#include "DNA_curve_types.h"
#include "DNA_modifier_types.h"
@@ -74,7 +73,6 @@ extern "C" {
#include "WM_api.h"
#include "WM_types.h"
-}
using Alembic::Abc::Int32ArraySamplePtr;
using Alembic::Abc::ObjectHeader;
@@ -877,8 +875,7 @@ bool ABC_import(bContext *C,
bool validate_meshes,
bool as_background_job)
{
- /* Using new here since MEM_* funcs do not call ctor to properly initialize
- * data. */
+ /* Using new here since MEM_* functions do not call constructor to properly initialize data. */
ImportJobData *job = new ImportJobData();
job->bmain = CTX_data_main(C);
job->scene = CTX_data_scene(C);
diff --git a/source/blender/io/avi/intern/avi_mjpeg.c b/source/blender/io/avi/intern/avi_mjpeg.c
index ac622d8b0e4..70ddca28060 100644
--- a/source/blender/io/avi/intern/avi_mjpeg.c
+++ b/source/blender/io/avi/intern/avi_mjpeg.c
@@ -30,6 +30,7 @@
#include "MEM_guardedalloc.h"
+#include "BLI_math_base.h"
#include "IMB_imbuf.h"
#include "jerror.h"
@@ -45,14 +46,16 @@ static size_t numbytes;
static void add_huff_table(j_decompress_ptr dinfo,
JHUFF_TBL **htblptr,
const UINT8 *bits,
- const UINT8 *val)
+ const size_t bits_size,
+ const UINT8 *val,
+ const size_t val_size)
{
if (*htblptr == NULL) {
*htblptr = jpeg_alloc_huff_table((j_common_ptr)dinfo);
}
- memcpy((*htblptr)->bits, bits, sizeof((*htblptr)->bits));
- memcpy((*htblptr)->huffval, val, sizeof((*htblptr)->huffval));
+ memcpy((*htblptr)->bits, bits, min_zz(sizeof((*htblptr)->bits), bits_size));
+ memcpy((*htblptr)->huffval, val, min_zz(sizeof((*htblptr)->huffval), val_size));
/* Initialize sent_table false so table will be written to JPEG file. */
(*htblptr)->sent_table = false;
@@ -200,10 +203,30 @@ static void std_huff_tables(j_decompress_ptr dinfo)
0xe8, 0xe9, 0xea, 0xf2, 0xf3, 0xf4, 0xf5, 0xf6, 0xf7, 0xf8, 0xf9, 0xfa,
};
- add_huff_table(dinfo, &dinfo->dc_huff_tbl_ptrs[0], bits_dc_luminance, val_dc_luminance);
- add_huff_table(dinfo, &dinfo->ac_huff_tbl_ptrs[0], bits_ac_luminance, val_ac_luminance);
- add_huff_table(dinfo, &dinfo->dc_huff_tbl_ptrs[1], bits_dc_chrominance, val_dc_chrominance);
- add_huff_table(dinfo, &dinfo->ac_huff_tbl_ptrs[1], bits_ac_chrominance, val_ac_chrominance);
+ add_huff_table(dinfo,
+ &dinfo->dc_huff_tbl_ptrs[0],
+ bits_dc_luminance,
+ sizeof(bits_dc_luminance),
+ val_dc_luminance,
+ sizeof(val_dc_luminance));
+ add_huff_table(dinfo,
+ &dinfo->ac_huff_tbl_ptrs[0],
+ bits_ac_luminance,
+ sizeof(bits_ac_luminance),
+ val_ac_luminance,
+ sizeof(val_ac_luminance));
+ add_huff_table(dinfo,
+ &dinfo->dc_huff_tbl_ptrs[1],
+ bits_dc_chrominance,
+ sizeof(bits_dc_chrominance),
+ val_dc_chrominance,
+ sizeof(val_dc_chrominance));
+ add_huff_table(dinfo,
+ &dinfo->ac_huff_tbl_ptrs[1],
+ bits_ac_chrominance,
+ sizeof(bits_ac_chrominance),
+ val_ac_chrominance,
+ sizeof(val_ac_chrominance));
}
static int Decode_JPEG(unsigned char *inBuffer,
diff --git a/source/blender/io/collada/AnimationExporter.h b/source/blender/io/collada/AnimationExporter.h
index e95a1b93163..b4564eb7b2d 100644
--- a/source/blender/io/collada/AnimationExporter.h
+++ b/source/blender/io/collada/AnimationExporter.h
@@ -23,7 +23,6 @@
#include "BCAnimationCurve.h"
-extern "C" {
#include "DNA_action_types.h"
#include "DNA_anim_types.h"
#include "DNA_armature_types.h"
@@ -42,14 +41,12 @@ extern "C" {
#include "BIK_api.h"
#include "BKE_action.h" // pose functions
-#include "BKE_animsys.h"
#include "BKE_armature.h"
#include "BKE_constraint.h"
#include "BKE_fcurve.h"
#include "BKE_object.h"
#include "BKE_scene.h"
#include "ED_object.h"
-}
#include "MEM_guardedalloc.h"
diff --git a/source/blender/io/collada/AnimationImporter.cpp b/source/blender/io/collada/AnimationImporter.cpp
index 2511d3c287d..edac84e2aaa 100644
--- a/source/blender/io/collada/AnimationImporter.cpp
+++ b/source/blender/io/collada/AnimationImporter.cpp
@@ -57,7 +57,7 @@ template<class T> static const char *bc_get_joint_name(T *node)
FCurve *AnimationImporter::create_fcurve(int array_index, const char *rna_path)
{
- FCurve *fcu = (FCurve *)MEM_callocN(sizeof(FCurve), "FCurve");
+ FCurve *fcu = BKE_fcurve_create();
fcu->flag = (FCURVE_VISIBLE | FCURVE_AUTO_HANDLES | FCURVE_SELECTED);
fcu->rna_path = BLI_strdupn(rna_path, strlen(rna_path));
fcu->array_index = array_index;
@@ -100,7 +100,7 @@ void AnimationImporter::animation_to_fcurves(COLLADAFW::AnimationCurve *curve)
case 16: /* matrix */
{
for (i = 0; i < dim; i++) {
- FCurve *fcu = (FCurve *)MEM_callocN(sizeof(FCurve), "FCurve");
+ FCurve *fcu = BKE_fcurve_create();
fcu->flag = (FCURVE_VISIBLE | FCURVE_AUTO_HANDLES | FCURVE_SELECTED);
fcu->array_index = 0;
@@ -274,7 +274,7 @@ AnimationImporter::~AnimationImporter()
/* free unused FCurves */
for (std::vector<FCurve *>::iterator it = unused_curves.begin(); it != unused_curves.end();
it++) {
- free_fcurve(*it);
+ BKE_fcurve_free(*it);
}
if (unused_curves.size()) {
@@ -442,7 +442,7 @@ virtual void AnimationImporter::change_eul_to_quat(Object *ob, bAction *act)
}
action_groups_remove_channel(act, eulcu[i]);
- free_fcurve(eulcu[i]);
+ BKE_fcurve_free(eulcu[i]);
}
chan->rotmode = ROT_MODE_QUAT;
diff --git a/source/blender/io/collada/AnimationImporter.h b/source/blender/io/collada/AnimationImporter.h
index 263a130d1eb..51041c6ee3e 100644
--- a/source/blender/io/collada/AnimationImporter.h
+++ b/source/blender/io/collada/AnimationImporter.h
@@ -35,14 +35,14 @@
#include "COLLADAFWNode.h"
#include "COLLADAFWUniqueId.h"
-extern "C" {
#include "BKE_context.h"
+
#include "DNA_anim_types.h"
+
#include "DNA_camera_types.h"
#include "DNA_light_types.h"
#include "DNA_object_types.h"
#include "DNA_scene_types.h"
-}
//#include "ArmatureImporter.h"
#include "TransformReader.h"
diff --git a/source/blender/io/collada/ArmatureExporter.cpp b/source/blender/io/collada/ArmatureExporter.cpp
index 660917c2aa1..fc697e1617b 100644
--- a/source/blender/io/collada/ArmatureExporter.cpp
+++ b/source/blender/io/collada/ArmatureExporter.cpp
@@ -29,11 +29,8 @@
#include "BKE_action.h"
#include "BKE_armature.h"
-
-extern "C" {
#include "BKE_global.h"
#include "BKE_mesh.h"
-}
#include "ED_armature.h"
diff --git a/source/blender/io/collada/ArmatureImporter.cpp b/source/blender/io/collada/ArmatureImporter.cpp
index 4e9f31182f1..a69500432e8 100644
--- a/source/blender/io/collada/ArmatureImporter.cpp
+++ b/source/blender/io/collada/ArmatureImporter.cpp
@@ -25,14 +25,12 @@
#include "COLLADAFWUniqueId.h"
-extern "C" {
#include "BKE_action.h"
#include "BKE_armature.h"
#include "BKE_object.h"
#include "BLI_listbase.h"
#include "BLI_string.h"
#include "ED_armature.h"
-}
#include "DEG_depsgraph.h"
@@ -335,7 +333,7 @@ void ArmatureImporter::connect_bone_chains(bArmature *armature, Bone *parentbone
/*
* It is possible that the child's head is located on the parents head.
* When this happens, then moving the parent's tail to the child's head
- * would result in a zero sized bone and Blender would silently remove the bone.
+ * would result in a zero sized bone and Blender would silently remove the bone.
* So we move the tail only when the resulting bone has a minimum length:
*/
diff --git a/source/blender/io/collada/ArmatureImporter.h b/source/blender/io/collada/ArmatureImporter.h
index bafa10ca804..7393b882f4b 100644
--- a/source/blender/io/collada/ArmatureImporter.h
+++ b/source/blender/io/collada/ArmatureImporter.h
@@ -25,7 +25,6 @@
#include "COLLADAFWNode.h"
#include "COLLADAFWUniqueId.h"
-extern "C" {
#include "BKE_context.h"
#include "BKE_key.h"
@@ -35,7 +34,6 @@ extern "C" {
#include "DNA_scene_types.h"
#include "ED_armature.h"
-}
#include "AnimationImporter.h"
#include "ExtraTags.h"
diff --git a/source/blender/io/collada/BCAnimationCurve.cpp b/source/blender/io/collada/BCAnimationCurve.cpp
index 98eb12f738e..61dded368b5 100644
--- a/source/blender/io/collada/BCAnimationCurve.cpp
+++ b/source/blender/io/collada/BCAnimationCurve.cpp
@@ -89,12 +89,12 @@ void BCAnimationCurve::init_pointer_rna(Object *ob)
void BCAnimationCurve::delete_fcurve(FCurve *fcu)
{
- free_fcurve(fcu);
+ BKE_fcurve_free(fcu);
}
FCurve *BCAnimationCurve::create_fcurve(int array_index, const char *rna_path)
{
- FCurve *fcu = (FCurve *)MEM_callocN(sizeof(FCurve), "FCurve");
+ FCurve *fcu = BKE_fcurve_create();
fcu->flag = (FCURVE_VISIBLE | FCURVE_AUTO_HANDLES | FCURVE_SELECTED);
fcu->rna_path = BLI_strdupn(rna_path, strlen(rna_path));
fcu->array_index = array_index;
diff --git a/source/blender/io/collada/BCAnimationCurve.h b/source/blender/io/collada/BCAnimationCurve.h
index 71640ff3013..e0216ee6849 100644
--- a/source/blender/io/collada/BCAnimationCurve.h
+++ b/source/blender/io/collada/BCAnimationCurve.h
@@ -25,14 +25,13 @@
#include "MEM_guardedalloc.h"
-extern "C" {
#include "BKE_armature.h"
#include "BKE_fcurve.h"
#include "BKE_material.h"
+
#include "ED_anim_api.h"
#include "ED_keyframes_edit.h"
#include "ED_keyframing.h"
-}
typedef float(TangentPoint)[2];
diff --git a/source/blender/io/collada/BCAnimationSampler.cpp b/source/blender/io/collada/BCAnimationSampler.cpp
index 0c19ce9a4c7..4aea74cd82f 100644
--- a/source/blender/io/collada/BCAnimationSampler.cpp
+++ b/source/blender/io/collada/BCAnimationSampler.cpp
@@ -27,20 +27,21 @@
#include "ExportSettings.h"
#include "collada_utils.h"
-extern "C" {
#include "BKE_action.h"
#include "BKE_constraint.h"
#include "BKE_key.h"
#include "BKE_lib_id.h"
#include "BKE_main.h"
#include "BKE_material.h"
+
#include "BLI_listbase.h"
+
#include "DNA_anim_types.h"
#include "DNA_constraint_types.h"
#include "DNA_key_types.h"
#include "DNA_scene_types.h"
+
#include "ED_object.h"
-}
static std::string EMPTY_STRING;
static BCAnimationCurveMap BCEmptyAnimationCurves;
@@ -270,7 +271,7 @@ void BCAnimationSampler::find_depending_animated(std::set<Object *> &animated_ob
std::set<Object *>::iterator it;
for (it = candidates.begin(); it != candidates.end(); ++it) {
Object *cob = *it;
- ListBase *conlist = get_active_constraints(cob);
+ ListBase *conlist = ED_object_constraint_list_from_context(cob);
if (is_animated_by_constraint(cob, conlist, animated_objects)) {
animated_objects.insert(cob);
candidates.erase(cob);
diff --git a/source/blender/io/collada/BCAnimationSampler.h b/source/blender/io/collada/BCAnimationSampler.h
index 96138d0cbca..3273ac8e0a0 100644
--- a/source/blender/io/collada/BCAnimationSampler.h
+++ b/source/blender/io/collada/BCAnimationSampler.h
@@ -21,12 +21,12 @@
#include "BCSampleData.h"
#include "collada_utils.h"
-extern "C" {
#include "BKE_action.h"
#include "BKE_lib_id.h"
+
#include "BLI_math_rotation.h"
+
#include "DNA_action_types.h"
-}
/* Collection of animation curves */
class BCAnimation {
diff --git a/source/blender/io/collada/BCMath.h b/source/blender/io/collada/BCMath.h
index 9ecea85b08c..38158751740 100644
--- a/source/blender/io/collada/BCMath.h
+++ b/source/blender/io/collada/BCMath.h
@@ -23,10 +23,9 @@
#include "BlenderTypes.h"
-extern "C" {
#include "BKE_object.h"
+
#include "BLI_math.h"
-}
class BCQuat {
private:
diff --git a/source/blender/io/collada/BCSampleData.h b/source/blender/io/collada/BCSampleData.h
index 877fb49981a..6f3ca9135b3 100644
--- a/source/blender/io/collada/BCSampleData.h
+++ b/source/blender/io/collada/BCSampleData.h
@@ -28,15 +28,15 @@
#include "BCSampleData.h"
#include "ExportSettings.h"
-extern "C" {
#include "BKE_object.h"
+
#include "BLI_math_rotation.h"
+
#include "DNA_armature_types.h"
#include "DNA_camera_types.h"
#include "DNA_light_types.h"
#include "DNA_material_types.h"
#include "DNA_object_types.h"
-}
typedef std::map<Bone *, BCMatrix *> BCBoneMatrixMap;
diff --git a/source/blender/io/collada/BlenderContext.h b/source/blender/io/collada/BlenderContext.h
index 15ebd671b1a..bf6fde134fa 100644
--- a/source/blender/io/collada/BlenderContext.h
+++ b/source/blender/io/collada/BlenderContext.h
@@ -21,11 +21,6 @@
#ifndef __BLENDERCONTEXT_H__
#define __BLENDERCONTEXT_H__
-#ifdef __cplusplus
-
-extern "C" {
-#endif
-
#include "BKE_context.h"
#include "BKE_main.h"
#include "BLI_linklist.h"
@@ -35,6 +30,10 @@ extern "C" {
#include "DNA_layer_types.h"
#include "DNA_object_types.h"
+#ifdef __cplusplus
+extern "C" {
+#endif
+
static const BC_global_forward_axis BC_DEFAULT_FORWARD = BC_GLOBAL_FORWARD_Y;
static const BC_global_up_axis BC_DEFAULT_UP = BC_GLOBAL_UP_Z;
diff --git a/source/blender/io/collada/CameraExporter.cpp b/source/blender/io/collada/CameraExporter.cpp
index 74862c44270..246a454eb66 100644
--- a/source/blender/io/collada/CameraExporter.cpp
+++ b/source/blender/io/collada/CameraExporter.cpp
@@ -22,9 +22,8 @@
#include "COLLADASWCamera.h"
-extern "C" {
#include "DNA_camera_types.h"
-}
+
#include "CameraExporter.h"
#include "collada_internal.h"
diff --git a/source/blender/io/collada/CameraExporter.h b/source/blender/io/collada/CameraExporter.h
index e4df994354c..0dda6392d03 100644
--- a/source/blender/io/collada/CameraExporter.h
+++ b/source/blender/io/collada/CameraExporter.h
@@ -24,10 +24,8 @@
#include "COLLADASWLibraryCameras.h"
#include "COLLADASWStreamWriter.h"
-extern "C" {
#include "DNA_object_types.h"
#include "DNA_scene_types.h"
-}
#include "DNA_camera_types.h"
#include "ExportSettings.h"
diff --git a/source/blender/io/collada/ControllerExporter.cpp b/source/blender/io/collada/ControllerExporter.cpp
index c26647d4747..1b8c859f443 100644
--- a/source/blender/io/collada/ControllerExporter.cpp
+++ b/source/blender/io/collada/ControllerExporter.cpp
@@ -29,13 +29,10 @@
#include "BKE_action.h"
#include "BKE_armature.h"
-
-extern "C" {
#include "BKE_global.h"
#include "BKE_idprop.h"
#include "BKE_lib_id.h"
#include "BKE_mesh.h"
-}
#include "ED_armature.h"
diff --git a/source/blender/io/collada/DocumentExporter.cpp b/source/blender/io/collada/DocumentExporter.cpp
index 7565aa881fd..0578bf45f04 100644
--- a/source/blender/io/collada/DocumentExporter.cpp
+++ b/source/blender/io/collada/DocumentExporter.cpp
@@ -58,7 +58,6 @@
#include "MEM_guardedalloc.h"
-extern "C" {
#include "DNA_action_types.h"
#include "DNA_anim_types.h"
#include "DNA_armature_types.h"
@@ -96,13 +95,12 @@ extern "C" {
#include "ED_keyframing.h"
#ifdef WITH_BUILDINFO
-extern char build_commit_date[];
-extern char build_commit_time[];
-extern char build_hash[];
+extern "C" char build_commit_date[];
+extern "C" char build_commit_time[];
+extern "C" char build_hash[];
#endif
#include "RNA_access.h"
-}
#include "DocumentExporter.h"
#include "collada_internal.h"
@@ -245,20 +243,13 @@ int DocumentExporter::exportCurrentScene()
#ifdef WITH_BUILDINFO
BLI_snprintf(version_buf,
sizeof(version_buf),
- "Blender %d.%02d.%d commit date:%s, commit time:%s, hash:%s",
- BLENDER_VERSION / 100,
- BLENDER_VERSION % 100,
- BLENDER_SUBVERSION,
+ "Blender %s commit date:%s, commit time:%s, hash:%s",
+ BKE_blender_version_string(),
build_commit_date,
build_commit_time,
build_hash);
#else
- BLI_snprintf(version_buf,
- sizeof(version_buf),
- "Blender %d.%02d.%d",
- BLENDER_VERSION / 100,
- BLENDER_VERSION % 100,
- BLENDER_SUBVERSION);
+ BLI_snprintf(version_buf, sizeof(version_buf), "Blender %s", BKE_blender_version_string());
#endif
asset.getContributor().mAuthoringTool = version_buf;
asset.add();
diff --git a/source/blender/io/collada/DocumentExporter.h b/source/blender/io/collada/DocumentExporter.h
index f024befbd17..1fe52420534 100644
--- a/source/blender/io/collada/DocumentExporter.h
+++ b/source/blender/io/collada/DocumentExporter.h
@@ -25,9 +25,7 @@
#include "collada.h"
#include "collada_utils.h"
-extern "C" {
#include "DNA_customdata_types.h"
-}
class DocumentExporter {
public:
diff --git a/source/blender/io/collada/DocumentImporter.cpp b/source/blender/io/collada/DocumentImporter.cpp
index 281786bb45f..2305072a6eb 100644
--- a/source/blender/io/collada/DocumentImporter.cpp
+++ b/source/blender/io/collada/DocumentImporter.cpp
@@ -45,7 +45,6 @@
#include "MEM_guardedalloc.h"
-extern "C" {
#include "BLI_fileops.h"
#include "BLI_listbase.h"
#include "BLI_math.h"
@@ -72,7 +71,6 @@ extern "C" {
#include "WM_api.h"
#include "WM_types.h"
-}
#include "DEG_depsgraph.h"
#include "DEG_depsgraph_build.h"
diff --git a/source/blender/io/collada/EffectExporter.cpp b/source/blender/io/collada/EffectExporter.cpp
index f21ea57c91c..7f6d3cbdc6f 100644
--- a/source/blender/io/collada/EffectExporter.cpp
+++ b/source/blender/io/collada/EffectExporter.cpp
@@ -31,7 +31,6 @@
#include "collada_internal.h"
#include "collada_utils.h"
-extern "C" {
#include "DNA_mesh_types.h"
#include "DNA_world_types.h"
@@ -39,7 +38,6 @@ extern "C" {
#include "BKE_customdata.h"
#include "BKE_material.h"
#include "BKE_mesh.h"
-}
static std::string getActiveUVLayerName(Object *ob)
{
diff --git a/source/blender/io/collada/ErrorHandler.h b/source/blender/io/collada/ErrorHandler.h
index 9789e93cee9..0c082a3b9dd 100644
--- a/source/blender/io/collada/ErrorHandler.h
+++ b/source/blender/io/collada/ErrorHandler.h
@@ -46,7 +46,7 @@ class ErrorHandler : public COLLADASaxFWL::IErrorHandler {
}
private:
- /** Disable default copy ctor. */
+ /** Disable default copy constructor. */
ErrorHandler(const ErrorHandler &pre);
/** Disable default assignment operator. */
const ErrorHandler &operator=(const ErrorHandler &pre);
diff --git a/source/blender/io/collada/ExportSettings.h b/source/blender/io/collada/ExportSettings.h
index 69e260a1e91..477f0b8b678 100644
--- a/source/blender/io/collada/ExportSettings.h
+++ b/source/blender/io/collada/ExportSettings.h
@@ -21,6 +21,9 @@
#ifndef __EXPORTSETTINGS_H__
#define __EXPORTSETTINGS_H__
+#include "BLI_linklist.h"
+#include "BlenderContext.h"
+
#ifdef __cplusplus
# include "BCMath.h"
# include <vector>
@@ -28,9 +31,6 @@
extern "C" {
#endif
-#include "BLI_linklist.h"
-#include "BlenderContext.h"
-
typedef enum BC_export_mesh_type {
BC_MESH_TYPE_VIEW,
BC_MESH_TYPE_RENDER,
diff --git a/source/blender/io/collada/GeometryExporter.cpp b/source/blender/io/collada/GeometryExporter.cpp
index 469d8601a8b..c7fcc51d42f 100644
--- a/source/blender/io/collada/GeometryExporter.cpp
+++ b/source/blender/io/collada/GeometryExporter.cpp
@@ -29,7 +29,6 @@
#include "DNA_meshdata_types.h"
-extern "C" {
#include "BLI_utildefines.h"
#include "BKE_customdata.h"
@@ -37,7 +36,6 @@ extern "C" {
#include "BKE_lib_id.h"
#include "BKE_material.h"
#include "BKE_mesh.h"
-}
#include "collada_internal.h"
#include "collada_utils.h"
diff --git a/source/blender/io/collada/ImageExporter.cpp b/source/blender/io/collada/ImageExporter.cpp
index 9d2b873f862..1c897e37a4a 100644
--- a/source/blender/io/collada/ImageExporter.cpp
+++ b/source/blender/io/collada/ImageExporter.cpp
@@ -21,7 +21,6 @@
#include "COLLADABUURI.h"
#include "COLLADASWImage.h"
-extern "C" {
#include "DNA_image_types.h"
#include "DNA_meshdata_types.h"
#include "DNA_texture_types.h"
@@ -37,7 +36,6 @@ extern "C" {
#include "BLI_string.h"
#include "IMB_imbuf_types.h"
-}
#include "ImageExporter.h"
#include "MaterialExporter.h"
@@ -108,7 +106,7 @@ void ImagesExporter::export_UV_Image(Image *image, bool use_copies)
/* make absolute source path */
BLI_strncpy(source_path, image->name, sizeof(source_path));
BLI_path_abs(source_path, ID_BLEND_PATH_FROM_GLOBAL(&image->id));
- BLI_cleanup_path(NULL, source_path);
+ BLI_path_normalize(NULL, source_path);
if (use_copies) {
diff --git a/source/blender/io/collada/InstanceWriter.cpp b/source/blender/io/collada/InstanceWriter.cpp
index a0bea16adfb..6c197823ec2 100644
--- a/source/blender/io/collada/InstanceWriter.cpp
+++ b/source/blender/io/collada/InstanceWriter.cpp
@@ -23,11 +23,10 @@
#include "COLLADASWInstanceMaterial.h"
-extern "C" {
#include "BKE_customdata.h"
#include "BKE_material.h"
+
#include "DNA_mesh_types.h"
-}
#include "InstanceWriter.h"
#include "collada_internal.h"
diff --git a/source/blender/io/collada/MaterialExporter.h b/source/blender/io/collada/MaterialExporter.h
index 8b3d1130fe9..babb113567f 100644
--- a/source/blender/io/collada/MaterialExporter.h
+++ b/source/blender/io/collada/MaterialExporter.h
@@ -27,12 +27,11 @@
#include "COLLADASWLibraryMaterials.h"
#include "COLLADASWStreamWriter.h"
-extern "C" {
#include "BKE_material.h"
+
#include "DNA_material_types.h"
#include "DNA_object_types.h"
#include "DNA_scene_types.h"
-}
#include "ExportSettings.h"
#include "GeometryExporter.h"
diff --git a/source/blender/io/collada/Materials.h b/source/blender/io/collada/Materials.h
index 86fc4c00073..e1d12246a2b 100644
--- a/source/blender/io/collada/Materials.h
+++ b/source/blender/io/collada/Materials.h
@@ -20,13 +20,11 @@
#include <map>
#include <string>
-extern "C" {
#include "BKE_context.h"
#include "BKE_node.h"
#include "BLI_listbase.h"
#include "DNA_material_types.h"
#include "DNA_node_types.h"
-}
#include "COLLADAFWEffectCommon.h"
#include "collada_utils.h"
diff --git a/source/blender/io/collada/MeshImporter.cpp b/source/blender/io/collada/MeshImporter.cpp
index 6ac87d3d394..6683f07bf65 100644
--- a/source/blender/io/collada/MeshImporter.cpp
+++ b/source/blender/io/collada/MeshImporter.cpp
@@ -30,7 +30,6 @@
#include "MEM_guardedalloc.h"
-extern "C" {
#include "BKE_customdata.h"
#include "BKE_displist.h"
#include "BKE_global.h"
@@ -43,7 +42,6 @@ extern "C" {
#include "BLI_listbase.h"
#include "BLI_math.h"
#include "BLI_string.h"
-}
#include "ArmatureImporter.h"
#include "MeshImporter.h"
diff --git a/source/blender/io/collada/MeshImporter.h b/source/blender/io/collada/MeshImporter.h
index 5ad2fb17fce..2f2a18ff11a 100644
--- a/source/blender/io/collada/MeshImporter.h
+++ b/source/blender/io/collada/MeshImporter.h
@@ -38,14 +38,13 @@
#include "ArmatureImporter.h"
#include "collada_utils.h"
-extern "C" {
#include "BLI_edgehash.h"
+
#include "DNA_material_types.h"
#include "DNA_mesh_types.h"
#include "DNA_meshdata_types.h"
#include "DNA_object_types.h"
#include "DNA_scene_types.h"
-}
/* only for ArmatureImporter to "see" MeshImporter::get_object_by_geom_uid */
class MeshImporterBase {
diff --git a/source/blender/io/collada/SceneExporter.cpp b/source/blender/io/collada/SceneExporter.cpp
index 2f70bc1c26b..1b3bc1b66ea 100644
--- a/source/blender/io/collada/SceneExporter.cpp
+++ b/source/blender/io/collada/SceneExporter.cpp
@@ -18,13 +18,11 @@
* \ingroup collada
*/
-extern "C" {
#include "BKE_collection.h"
#include "BKE_lib_id.h"
#include "BKE_object.h"
#include "BLI_listbase.h"
#include "BLI_utildefines.h"
-}
#include "BCSampleData.h"
#include "SceneExporter.h"
diff --git a/source/blender/io/collada/SceneExporter.h b/source/blender/io/collada/SceneExporter.h
index 382f716e5a3..3ea6a9fac8e 100644
--- a/source/blender/io/collada/SceneExporter.h
+++ b/source/blender/io/collada/SceneExporter.h
@@ -25,7 +25,6 @@
#include <stdio.h>
#include <stdlib.h>
-extern "C" {
#include "DNA_action_types.h"
#include "DNA_anim_types.h"
#include "DNA_armature_types.h"
@@ -42,13 +41,11 @@ extern "C" {
#include "DNA_texture_types.h"
#include "DNA_userdef_types.h"
-#include "BKE_animsys.h"
#include "BKE_constraint.h"
#include "BKE_fcurve.h"
#include "BLI_fileops.h"
#include "BLI_path_util.h"
#include "ED_keyframing.h"
-}
#include "COLLADASWAsset.h"
#include "COLLADASWBaseInputElement.h"
diff --git a/source/blender/io/collada/collada.cpp b/source/blender/io/collada/collada.cpp
index 683e64b2647..bf1ebbfa669 100644
--- a/source/blender/io/collada/collada.cpp
+++ b/source/blender/io/collada/collada.cpp
@@ -27,7 +27,6 @@
#include "ImportSettings.h"
#include "collada.h"
-extern "C" {
#include "BKE_context.h"
#include "BKE_scene.h"
#include "DEG_depsgraph.h"
@@ -37,6 +36,8 @@ extern "C" {
#include "BLI_fileops.h"
#include "BLI_linklist.h"
+extern "C" {
+
static void print_import_header(ImportSettings &import_settings)
{
fprintf(stderr, "+-- Collada Import parameters------\n");
diff --git a/source/blender/io/collada/collada.h b/source/blender/io/collada/collada.h
index deadbcffcaf..d8e498ef4b2 100644
--- a/source/blender/io/collada/collada.h
+++ b/source/blender/io/collada/collada.h
@@ -26,14 +26,14 @@
#include "ExportSettings.h"
#include "ImportSettings.h"
-#ifdef __cplusplus
-extern "C" {
-#endif
-
#include "BLI_linklist.h"
#include "BLI_path_util.h"
#include "RNA_types.h"
+#ifdef __cplusplus
+extern "C" {
+#endif
+
struct bContext;
/*
diff --git a/source/blender/io/collada/collada_utils.cpp b/source/blender/io/collada/collada_utils.cpp
index 1df82ed3038..d2e05c7ae5b 100644
--- a/source/blender/io/collada/collada_utils.cpp
+++ b/source/blender/io/collada/collada_utils.cpp
@@ -30,7 +30,6 @@
#include "MEM_guardedalloc.h"
-extern "C" {
#include "DNA_armature_types.h"
#include "DNA_constraint_types.h"
#include "DNA_customdata_types.h"
@@ -75,7 +74,6 @@ extern "C" {
#if 0
# include "NOD_common.h"
#endif
-}
#include "BlenderContext.h"
#include "ExportSettings.h"
diff --git a/source/blender/io/collada/collada_utils.h b/source/blender/io/collada/collada_utils.h
index 54ba8073679..b1ec2c8b81a 100644
--- a/source/blender/io/collada/collada_utils.h
+++ b/source/blender/io/collada/collada_utils.h
@@ -33,7 +33,6 @@
#include <set>
#include <vector>
-extern "C" {
#include "DNA_anim_types.h"
#include "DNA_camera_types.h"
#include "DNA_constraint_types.h"
@@ -57,7 +56,6 @@ extern "C" {
#include "BKE_node.h"
#include "BKE_object.h"
#include "BKE_scene.h"
-}
#include "DEG_depsgraph_query.h"
diff --git a/source/blender/io/usd/intern/abstract_hierarchy_iterator.cc b/source/blender/io/usd/intern/abstract_hierarchy_iterator.cc
index 50f81c2ffb1..ab83ea2c3c4 100644
--- a/source/blender/io/usd/intern/abstract_hierarchy_iterator.cc
+++ b/source/blender/io/usd/intern/abstract_hierarchy_iterator.cc
@@ -21,11 +21,11 @@
#include <iostream>
#include <limits.h>
#include <sstream>
+#include <stdio.h>
#include <string>
-extern "C" {
-#include "BKE_anim.h"
-#include "BKE_animsys.h"
+#include "BKE_anim_data.h"
+#include "BKE_duplilist.h"
#include "BKE_key.h"
#include "BKE_particle.h"
@@ -40,7 +40,6 @@ extern "C" {
#include "DNA_particle_types.h"
#include "DEG_depsgraph_query.h"
-}
namespace USD {
@@ -54,7 +53,7 @@ bool HierarchyContext::operator<(const HierarchyContext &other) const
if (object != other.object) {
return object < other.object;
}
- if (duplicator != NULL && duplicator == other.duplicator) {
+ if (duplicator != nullptr && duplicator == other.duplicator) {
// Only resort to string comparisons when both objects are created by the same duplicator.
return export_name < other.export_name;
}
@@ -259,24 +258,22 @@ void AbstractHierarchyIterator::connect_loose_objects()
for (const ExportGraph::value_type &map_iter : loose_objects_graph) {
const DupliAndDuplicator &export_info = map_iter.first;
Object *object = export_info.first;
- Object *export_parent = object->parent;
while (true) {
// Loose objects will all be real objects, as duplicated objects always have
// their duplicator or other exported duplicated object as ancestor.
- ExportGraph::iterator found_parent_iter = export_graph_.find(
- std::make_pair(export_parent, nullptr));
- visit_object(object, export_parent, true);
+ ExportGraph::iterator found_parent_iter = export_graph_.find(
+ std::make_pair(object->parent, nullptr));
+ visit_object(object, object->parent, true);
if (found_parent_iter != export_graph_.end()) {
break;
}
- // 'export_parent' will never be nullptr here, as the export graph contains the
+ // 'object->parent' will never be nullptr here, as the export graph contains the
// tuple <nullptr, nullptr> as root and thus will cause a break.
- BLI_assert(export_parent != nullptr);
+ BLI_assert(object->parent != nullptr);
- object = export_parent;
- export_parent = export_parent->parent;
+ object = object->parent;
}
}
}
@@ -346,41 +343,42 @@ void AbstractHierarchyIterator::visit_object(Object *object,
context->original_export_path = "";
copy_m4_m4(context->matrix_world, object->obmat);
- export_graph_[std::make_pair(export_parent, nullptr)].insert(context);
+ ExportGraph::key_type graph_index = determine_graph_index_object(context);
+ context_update_for_graph_index(context, graph_index);
+
+ // Store this HierarchyContext as child of the export parent.
+ export_graph_[graph_index].insert(context);
+
+ // Create an empty entry for this object to indicate it is part of the export. This will be used
+ // by connect_loose_objects(). Having such an "indicator" will make it possible to do an O(log n)
+ // check on whether an object is part of the export, rather than having to check all objects in
+ // the map. Note that it's not possible to simply search for (object->parent, nullptr), as the
+ // object's parent in Blender may not be the same as its export-parent.
+ ExportGraph::key_type object_key = std::make_pair(object, nullptr);
+ if (export_graph_.find(object_key) == export_graph_.end()) {
+ export_graph_[object_key] = ExportChildren();
+ }
+}
+
+AbstractHierarchyIterator::ExportGraph::key_type AbstractHierarchyIterator::
+ determine_graph_index_object(const HierarchyContext *context)
+{
+ return std::make_pair(context->export_parent, nullptr);
}
void AbstractHierarchyIterator::visit_dupli_object(DupliObject *dupli_object,
Object *duplicator,
const std::set<Object *> &dupli_set)
{
- ExportGraph::key_type graph_index;
- bool animation_check_include_parent = false;
-
HierarchyContext *context = new HierarchyContext();
context->object = dupli_object->ob;
context->duplicator = duplicator;
context->weak_export = false;
context->export_path = "";
context->original_export_path = "";
+ context->export_path = "";
+ context->animation_check_include_parent = false;
- /* If the dupli-object's parent is also instanced by this object, use that as the
- * export parent. Otherwise use the dupli-parent as export parent. */
- Object *parent = dupli_object->ob->parent;
- if (parent != nullptr && dupli_set.find(parent) != dupli_set.end()) {
- // The parent object is part of the duplicated collection.
- context->export_parent = parent;
- graph_index = std::make_pair(parent, duplicator);
- }
- else {
- /* The parent object is NOT part of the duplicated collection. This means that the world
- * transform of this dupli-object can be influenced by objects that are not part of its
- * export graph. */
- animation_check_include_parent = true;
- context->export_parent = duplicator;
- graph_index = std::make_pair(duplicator, nullptr);
- }
-
- context->animation_check_include_parent = animation_check_include_parent;
copy_m4_m4(context->matrix_world, dupli_object->mat);
// Construct export name for the dupli-instance.
@@ -391,9 +389,39 @@ void AbstractHierarchyIterator::visit_dupli_object(DupliObject *dupli_object,
}
context->export_name = make_valid_name(get_object_name(context->object) + suffix_stream.str());
+ ExportGraph::key_type graph_index = determine_graph_index_dupli(context, dupli_set);
+ context_update_for_graph_index(context, graph_index);
export_graph_[graph_index].insert(context);
}
+AbstractHierarchyIterator::ExportGraph::key_type AbstractHierarchyIterator::
+ determine_graph_index_dupli(const HierarchyContext *context,
+ const std::set<Object *> &dupli_set)
+{
+ /* If the dupli-object's parent is also instanced by this object, use that as the
+ * export parent. Otherwise use the dupli-parent as export parent. */
+
+ Object *parent = context->object->parent;
+ if (parent != nullptr && dupli_set.find(parent) != dupli_set.end()) {
+ // The parent object is part of the duplicated collection.
+ return std::make_pair(parent, context->duplicator);
+ }
+ return std::make_pair(context->duplicator, nullptr);
+}
+
+void AbstractHierarchyIterator::context_update_for_graph_index(
+ HierarchyContext *context, const ExportGraph::key_type &graph_index) const
+{
+ // Update the HierarchyContext so that it is consistent with the graph index.
+ context->export_parent = graph_index.first;
+ if (context->export_parent != context->object->parent) {
+ /* The parent object in Blender is NOT used as the export parent. This means
+ * that the world transform of this object can be influenced by objects that
+ * are not part of its export graph. */
+ context->animation_check_include_parent = true;
+ }
+}
+
AbstractHierarchyIterator::ExportChildren &AbstractHierarchyIterator::graph_children(
const HierarchyContext *context)
{
@@ -418,8 +446,7 @@ void AbstractHierarchyIterator::determine_export_paths(const HierarchyContext *p
duplisource_export_path_[source_ob] = context->export_path;
if (context->object->data != nullptr) {
- ID *object_data = static_cast<ID *>(context->object->data);
- ID *source_data = object_data;
+ ID *source_data = static_cast<ID *>(context->object->data);
duplisource_export_path_[source_data] = get_object_data_path(context);
}
}
@@ -478,6 +505,7 @@ void AbstractHierarchyIterator::make_writers(const HierarchyContext *parent_cont
}
for (HierarchyContext *context : graph_children(parent_context)) {
+ // Update the context so that it is correct for this parent-child relation.
copy_m4_m4(context->parent_matrix_inv_world, parent_matrix_inv_world);
// Get or create the transform writer.
@@ -546,7 +574,7 @@ void AbstractHierarchyIterator::make_writers_particle_systems(
HierarchyContext hair_context = *transform_context;
hair_context.export_path = path_concatenate(transform_context->export_path,
- get_id_name(&psys->part->id));
+ make_valid_name(psys->name));
hair_context.particle_system = psys;
AbstractHierarchyWriter *writer = nullptr;
@@ -576,9 +604,10 @@ std::string AbstractHierarchyIterator::get_object_data_name(const Object *object
return get_id_name(object_data);
}
-AbstractHierarchyWriter *AbstractHierarchyIterator::get_writer(const std::string &export_path)
+AbstractHierarchyWriter *AbstractHierarchyIterator::get_writer(
+ const std::string &export_path) const
{
- WriterMap::iterator it = writers_.find(export_path);
+ WriterMap::const_iterator it = writers_.find(export_path);
if (it == writers_.end()) {
return nullptr;
diff --git a/source/blender/io/usd/intern/abstract_hierarchy_iterator.h b/source/blender/io/usd/intern/abstract_hierarchy_iterator.h
index f7ba1a76bac..e31d5c91252 100644
--- a/source/blender/io/usd/intern/abstract_hierarchy_iterator.h
+++ b/source/blender/io/usd/intern/abstract_hierarchy_iterator.h
@@ -56,7 +56,7 @@ class AbstractHierarchyWriter;
* struct contains everything necessary to export a single object to a file. */
struct HierarchyContext {
/*********** Determined during hierarchy iteration: ***************/
- Object *object;
+ Object *object; /* Evaluated object. */
Object *export_parent;
Object *duplicator;
float matrix_world[4][4];
@@ -69,7 +69,7 @@ struct HierarchyContext {
* have weak_export=true, this object (and by recursive reasoning all its descendants) will be
* excluded from the export.
*
- * The export hierarchy is kept as close to the the hierarchy in Blender as possible. As such, an
+ * The export hierarchy is kept as close to the hierarchy in Blender as possible. As such, an
* object that serves as a parent for another object, but which should NOT be exported itself, is
* exported only as transform (i.e. as empty). This happens with objects that are part of a
* holdout collection (which prevents them from being exported) but also parent of an exported
@@ -188,11 +188,14 @@ class AbstractHierarchyIterator {
const std::set<Object *> &dupli_set);
ExportChildren &graph_children(const HierarchyContext *parent_context);
+ void context_update_for_graph_index(HierarchyContext *context,
+ const ExportGraph::key_type &graph_index) const;
void determine_export_paths(const HierarchyContext *parent_context);
void determine_duplication_references(const HierarchyContext *parent_context,
std::string indent);
+ /* These three functions create writers and call their write() method. */
void make_writers(const HierarchyContext *parent_context);
void make_writer_object_data(const HierarchyContext *context);
void make_writers_particle_systems(const HierarchyContext *context);
@@ -201,7 +204,7 @@ class AbstractHierarchyIterator {
std::string get_object_name(const Object *object) const;
std::string get_object_data_name(const Object *object) const;
- AbstractHierarchyWriter *get_writer(const std::string &export_path);
+ AbstractHierarchyWriter *get_writer(const std::string &export_path) const;
typedef AbstractHierarchyWriter *(AbstractHierarchyIterator::*create_writer_func)(
const HierarchyContext *);
@@ -233,12 +236,19 @@ class AbstractHierarchyIterator {
virtual bool should_visit_dupli_object(const DupliObject *dupli_object) const;
+ virtual ExportGraph::key_type determine_graph_index_object(const HierarchyContext *context);
+ virtual ExportGraph::key_type determine_graph_index_dupli(const HierarchyContext *context,
+ const std::set<Object *> &dupli_set);
+
/* These functions should create an AbstractHierarchyWriter subclass instance, or return
* nullptr if the object or its data should not be exported. Returning a nullptr for
* data/hair/particle will NOT prevent the transform to be written.
*
* The returned writer is owned by the AbstractHierarchyWriter, and should be freed in
- * delete_object_writer(). */
+ * delete_object_writer().
+ *
+ * The created AbstractHierarchyWriter instances should NOT keep a copy of the context pointer.
+ * The context can be stack-allocated and go out of scope. */
virtual AbstractHierarchyWriter *create_transform_writer(const HierarchyContext *context) = 0;
virtual AbstractHierarchyWriter *create_data_writer(const HierarchyContext *context) = 0;
virtual AbstractHierarchyWriter *create_hair_writer(const HierarchyContext *context) = 0;
diff --git a/source/blender/io/usd/intern/usd_capi.cc b/source/blender/io/usd/intern/usd_capi.cc
index 60ab3676847..cf962446d04 100644
--- a/source/blender/io/usd/intern/usd_capi.cc
+++ b/source/blender/io/usd/intern/usd_capi.cc
@@ -26,7 +26,6 @@
#include "MEM_guardedalloc.h"
-extern "C" {
#include "DEG_depsgraph.h"
#include "DEG_depsgraph_build.h"
#include "DEG_depsgraph_query.h"
@@ -44,7 +43,6 @@ extern "C" {
#include "WM_api.h"
#include "WM_types.h"
-}
namespace USD {
@@ -93,7 +91,8 @@ static void export_startjob(void *customdata, short *stop, short *do_update, flo
usd_stage->SetMetadata(pxr::UsdGeomTokens->upAxis, pxr::VtValue(pxr::UsdGeomTokens->z));
usd_stage->SetMetadata(pxr::UsdGeomTokens->metersPerUnit,
pxr::VtValue(scene->unit.scale_length));
- usd_stage->GetRootLayer()->SetDocumentation(std::string("Blender ") + versionstr);
+ usd_stage->GetRootLayer()->SetDocumentation(std::string("Blender v") +
+ BKE_blender_version_string());
// Set up the stage for animated data.
if (data->params.export_animation) {
@@ -187,7 +186,7 @@ bool USD_export(bContext *C,
/* setup job */
WM_jobs_customdata_set(wm_job, job, MEM_freeN);
WM_jobs_timer(wm_job, 0.1, NC_SCENE | ND_FRAME, NC_SCENE | ND_FRAME);
- WM_jobs_callbacks(wm_job, USD::export_startjob, NULL, NULL, USD::export_endjob);
+ WM_jobs_callbacks(wm_job, USD::export_startjob, nullptr, nullptr, USD::export_endjob);
WM_jobs_start(CTX_wm_manager(C), wm_job);
}
diff --git a/source/blender/io/usd/intern/usd_hierarchy_iterator.cc b/source/blender/io/usd/intern/usd_hierarchy_iterator.cc
index fd888f39adc..56e367dd877 100644
--- a/source/blender/io/usd/intern/usd_hierarchy_iterator.cc
+++ b/source/blender/io/usd/intern/usd_hierarchy_iterator.cc
@@ -31,8 +31,7 @@
#include <pxr/base/tf/stringUtils.h>
-extern "C" {
-#include "BKE_anim.h"
+#include "BKE_duplilist.h"
#include "BLI_assert.h"
@@ -41,7 +40,6 @@ extern "C" {
#include "DNA_ID.h"
#include "DNA_layer_types.h"
#include "DNA_object_types.h"
-}
namespace USD {
diff --git a/source/blender/io/usd/intern/usd_writer_abstract.h b/source/blender/io/usd/intern/usd_writer_abstract.h
index cf0f7e9d437..01b53f4c916 100644
--- a/source/blender/io/usd/intern/usd_writer_abstract.h
+++ b/source/blender/io/usd/intern/usd_writer_abstract.h
@@ -29,10 +29,9 @@
#include <vector>
-extern "C" {
#include "DEG_depsgraph_query.h"
+
#include "DNA_material_types.h"
-}
struct Material;
struct Object;
diff --git a/source/blender/io/usd/intern/usd_writer_camera.cc b/source/blender/io/usd/intern/usd_writer_camera.cc
index 9b85d69559c..ea551a43c9f 100644
--- a/source/blender/io/usd/intern/usd_writer_camera.cc
+++ b/source/blender/io/usd/intern/usd_writer_camera.cc
@@ -22,13 +22,11 @@
#include <pxr/usd/usdGeom/camera.h>
#include <pxr/usd/usdGeom/tokens.h>
-extern "C" {
#include "BKE_camera.h"
#include "BLI_assert.h"
#include "DNA_camera_types.h"
#include "DNA_scene_types.h"
-}
namespace USD {
diff --git a/source/blender/io/usd/intern/usd_writer_hair.cc b/source/blender/io/usd/intern/usd_writer_hair.cc
index 9251425c0b8..d38c1032969 100644
--- a/source/blender/io/usd/intern/usd_writer_hair.cc
+++ b/source/blender/io/usd/intern/usd_writer_hair.cc
@@ -22,11 +22,9 @@
#include <pxr/usd/usdGeom/basisCurves.h>
#include <pxr/usd/usdGeom/tokens.h>
-extern "C" {
#include "BKE_particle.h"
#include "DNA_particle_types.h"
-}
namespace USD {
diff --git a/source/blender/io/usd/intern/usd_writer_light.cc b/source/blender/io/usd/intern/usd_writer_light.cc
index e13e2c58a79..0ce3ee5f8ce 100644
--- a/source/blender/io/usd/intern/usd_writer_light.cc
+++ b/source/blender/io/usd/intern/usd_writer_light.cc
@@ -24,13 +24,11 @@
#include <pxr/usd/usdLux/rectLight.h>
#include <pxr/usd/usdLux/sphereLight.h>
-extern "C" {
#include "BLI_assert.h"
#include "BLI_utildefines.h"
#include "DNA_light_types.h"
#include "DNA_object_types.h"
-}
namespace USD {
diff --git a/source/blender/io/usd/intern/usd_writer_mesh.cc b/source/blender/io/usd/intern/usd_writer_mesh.cc
index cbf51fc15b3..841501bcf42 100644
--- a/source/blender/io/usd/intern/usd_writer_mesh.cc
+++ b/source/blender/io/usd/intern/usd_writer_mesh.cc
@@ -23,11 +23,9 @@
#include <pxr/usd/usdShade/material.h>
#include <pxr/usd/usdShade/materialBindingAPI.h>
-extern "C" {
#include "BLI_assert.h"
#include "BLI_math_vector.h"
-#include "BKE_anim.h"
#include "BKE_customdata.h"
#include "BKE_lib_id.h"
#include "BKE_material.h"
@@ -43,7 +41,6 @@ extern "C" {
#include "DNA_modifier_types.h"
#include "DNA_object_fluidsim_types.h"
#include "DNA_particle_types.h"
-}
namespace USD {
@@ -82,7 +79,7 @@ void USDGenericMeshWriter::do_write(HierarchyContext &context)
bool needsfree = false;
Mesh *mesh = get_export_mesh(object_eval, needsfree);
- if (mesh == NULL) {
+ if (mesh == nullptr) {
return;
}
@@ -103,7 +100,7 @@ void USDGenericMeshWriter::do_write(HierarchyContext &context)
void USDGenericMeshWriter::free_export_mesh(Mesh *mesh)
{
- BKE_id_free(NULL, mesh);
+ BKE_id_free(nullptr, mesh);
}
struct USDMeshData {
@@ -442,7 +439,7 @@ void USDGenericMeshWriter::write_surface_velocity(Object *object,
/* Only velocities from the fluid simulation are exported. This is the most important case,
* though, as the baked mesh changes topology all the time, and thus computing the velocities
* at import time in a post-processing step is hard. */
- ModifierData *md = modifiers_findByType(object, eModifierType_Fluidsim);
+ ModifierData *md = BKE_modifiers_findby_type(object, eModifierType_Fluidsim);
if (md == nullptr) {
return;
}
@@ -451,7 +448,7 @@ void USDGenericMeshWriter::write_surface_velocity(Object *object,
const bool use_render = (DEG_get_mode(usd_export_context_.depsgraph) == DAG_EVAL_RENDER);
const ModifierMode required_mode = use_render ? eModifierMode_Render : eModifierMode_Realtime;
const Scene *scene = DEG_get_evaluated_scene(usd_export_context_.depsgraph);
- if (!modifier_isEnabled(scene, md, required_mode)) {
+ if (!BKE_modifier_is_enabled(scene, md, required_mode)) {
return;
}
FluidsimModifierData *fsmd = reinterpret_cast<FluidsimModifierData *>(md);
diff --git a/source/blender/io/usd/intern/usd_writer_metaball.cc b/source/blender/io/usd/intern/usd_writer_metaball.cc
index 25b216d20f3..96bf854d327 100644
--- a/source/blender/io/usd/intern/usd_writer_metaball.cc
+++ b/source/blender/io/usd/intern/usd_writer_metaball.cc
@@ -23,7 +23,6 @@
#include <pxr/usd/usdShade/material.h>
#include <pxr/usd/usdShade/materialBindingAPI.h>
-extern "C" {
#include "BLI_assert.h"
#include "BKE_displist.h"
@@ -34,7 +33,6 @@ extern "C" {
#include "DNA_mesh_types.h"
#include "DNA_meta_types.h"
-}
namespace USD {
diff --git a/source/blender/io/usd/intern/usd_writer_transform.cc b/source/blender/io/usd/intern/usd_writer_transform.cc
index 321b516221a..0694d873002 100644
--- a/source/blender/io/usd/intern/usd_writer_transform.cc
+++ b/source/blender/io/usd/intern/usd_writer_transform.cc
@@ -22,13 +22,11 @@
#include <pxr/base/gf/matrix4f.h>
#include <pxr/usd/usdGeom/xform.h>
-extern "C" {
#include "BKE_object.h"
#include "BLI_math_matrix.h"
#include "DNA_layer_types.h"
-}
namespace USD {
@@ -52,7 +50,7 @@ void USDTransformWriter::do_write(HierarchyContext &context)
bool USDTransformWriter::check_is_animated(const HierarchyContext &context) const
{
- if (context.duplicator != NULL) {
+ if (context.duplicator != nullptr) {
/* This object is being duplicated, so could be emitted by a particle system and thus
* influenced by forces. TODO(Sybren): Make this more strict. Probably better to get from the
* depsgraph whether this object instance has a time source. */
diff --git a/source/blender/io/usd/usd.h b/source/blender/io/usd/usd.h
index 8a5575d53cf..eee98521289 100644
--- a/source/blender/io/usd/usd.h
+++ b/source/blender/io/usd/usd.h
@@ -20,12 +20,12 @@
#ifndef __USD_H__
#define __USD_H__
+#include "DEG_depsgraph.h"
+
#ifdef __cplusplus
extern "C" {
#endif
-#include "DEG_depsgraph.h"
-
struct Scene;
struct bContext;
diff --git a/source/blender/makesdna/DNA_ID.h b/source/blender/makesdna/DNA_ID.h
index 1e894d44f87..4f2bbc4ee73 100644
--- a/source/blender/makesdna/DNA_ID.h
+++ b/source/blender/makesdna/DNA_ID.h
@@ -25,14 +25,13 @@
#ifndef __DNA_ID_H__
#define __DNA_ID_H__
+#include "DNA_defs.h"
#include "DNA_listBase.h"
#ifdef __cplusplus
extern "C" {
#endif
-#include "DNA_defs.h"
-
struct FileData;
struct GHash;
struct GPUTexture;
@@ -106,6 +105,18 @@ enum {
IDP_NUMTYPES = 10,
};
+/** Used by some IDP utils, keep values in sync with type enum above. */
+enum {
+ IDP_TYPE_FILTER_STRING = 1 << 0,
+ IDP_TYPE_FILTER_INT = 1 << 1,
+ IDP_TYPE_FILTER_FLOAT = 1 << 2,
+ IDP_TYPE_FILTER_ARRAY = 1 << 5,
+ IDP_TYPE_FILTER_GROUP = 1 << 6,
+ IDP_TYPE_FILTER_ID = 1 << 7,
+ IDP_TYPE_FILTER_DOUBLE = 1 << 8,
+ IDP_TYPE_FILTER_IDPARRAY = 1 << 9,
+};
+
/*->subtype */
/* IDP_STRING */
@@ -135,7 +146,10 @@ typedef struct IDOverrideLibraryPropertyOperation {
/* Type of override. */
short operation;
short flag;
- char _pad0[4];
+
+ /** Runtime, tags are common to both IDOverrideProperty and IDOverridePropertyOperation. */
+ short tag;
+ char _pad0[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
@@ -189,8 +203,18 @@ typedef struct IDOverrideLibraryProperty {
/** List of overriding operations (IDOverridePropertyOperation) applied to this property. */
ListBase operations;
+
+ /** Runtime, tags are common to both IDOverrideProperty and IDOverridePropertyOperation. */
+ short tag;
+ char _pad0[6];
} IDOverrideLibraryProperty;
+/* IDOverrideProperty->tag and IDOverridePropertyOperation->tag. */
+enum {
+ /** This override property (operation) is unused and should be removed by cleanup process. */
+ IDOVERRIDE_LIBRARY_TAG_UNUSED = 1 << 0,
+};
+
/* We do not need a full struct for that currently, just a GHash. */
typedef struct GHash IDOverrideLibraryRuntime;
@@ -246,11 +270,16 @@ typedef struct ID {
int icon_id;
int recalc;
/**
- * Used by undo code. Value of recalc is stored there when reading an ID from memfile, and not
- * touched by anything, which means it can be used as 'reference' recalc value for the next undo
- * step, when going backward (i.e. actual undo, redo can just use recalc value directly).
+ * Used by undo code. recalc_after_undo_push contains the changes between the
+ * last undo push and the current state. This is accumulated as IDs are tagged
+ * for update in the depsgraph, and only cleared on undo push.
+ *
+ * recalc_up_to_undo_push is saved to undo memory, and is the value of
+ * recalc_after_undo_push at the time of the undo push. This means it can be
+ * used to find the changes between undo states.
*/
- int recalc_undo_accumulated;
+ int recalc_up_to_undo_push;
+ int recalc_after_undo_push;
/**
* A session-wide unique identifier for a given ID, that remain the same across potential
@@ -258,8 +287,6 @@ typedef struct ID {
*/
unsigned int session_uuid;
- char _pad[4];
-
IDProperty *properties;
/** Reference linked ID which this one overrides. */
@@ -300,7 +327,7 @@ typedef struct Library {
/* Temp data needed by read/write code. */
int temp_index;
- /** See BLENDER_VERSION, BLENDER_SUBVERSION, needed for do_versions. */
+ /** See BLENDER_FILE_VERSION, BLENDER_FILE_SUBVERSION, needed for do_versions. */
short versionfile, subversionfile;
} Library;
@@ -408,6 +435,7 @@ typedef enum ID_Type {
ID_HA = MAKE_ID2('H', 'A'), /* Hair */
ID_PT = MAKE_ID2('P', 'T'), /* PointCloud */
ID_VO = MAKE_ID2('V', 'O'), /* Volume */
+ ID_SIM = MAKE_ID2('S', 'I'), /* Simulation */
} ID_Type;
/* Only used as 'placeholder' in .blend files for directly linked data-blocks. */
@@ -536,9 +564,9 @@ enum {
/* RESET_NEVER tag data-block as needing an auto-override execution, if enabled. */
LIB_TAG_OVERRIDE_LIBRARY_AUTOREFRESH = 1 << 17,
- /* tag data-block has having an extra user. */
+ /* tag data-block as having an extra user. */
LIB_TAG_EXTRAUSER = 1 << 2,
- /* tag data-block has having actually increased usercount for the extra virtual user. */
+ /* tag data-block as having actually increased usercount for the extra virtual user. */
LIB_TAG_EXTRAUSER_SET = 1 << 7,
/* RESET_AFTER_USE tag newly duplicated/copied IDs.
@@ -707,6 +735,7 @@ typedef enum IDRecalcFlag {
#define FILTER_ID_HA (1ULL << 32)
#define FILTER_ID_PT (1ULL << 33)
#define FILTER_ID_VO (1ULL << 34)
+#define FILTER_ID_SIM (1ULL << 35)
#define FILTER_ID_ALL \
(FILTER_ID_AC | FILTER_ID_AR | FILTER_ID_BR | FILTER_ID_CA | FILTER_ID_CU | FILTER_ID_GD | \
@@ -714,7 +743,7 @@ typedef enum IDRecalcFlag {
FILTER_ID_MB | FILTER_ID_MC | FILTER_ID_ME | FILTER_ID_MSK | FILTER_ID_NT | FILTER_ID_OB | \
FILTER_ID_PA | FILTER_ID_PAL | FILTER_ID_PC | FILTER_ID_SCE | FILTER_ID_SPK | FILTER_ID_SO | \
FILTER_ID_TE | FILTER_ID_TXT | FILTER_ID_VF | FILTER_ID_WO | FILTER_ID_CF | FILTER_ID_WS | \
- FILTER_ID_LP | FILTER_ID_HA | FILTER_ID_PT | FILTER_ID_VO)
+ FILTER_ID_LP | FILTER_ID_HA | FILTER_ID_PT | FILTER_ID_VO | FILTER_ID_SIM)
/* IMPORTANT: this enum matches the order currently use in set_listbasepointers,
* keep them in sync! */
@@ -758,6 +787,7 @@ enum {
INDEX_ID_WS,
INDEX_ID_WM,
INDEX_ID_MSK,
+ INDEX_ID_SIM,
INDEX_ID_NULL,
INDEX_ID_MAX,
};
diff --git a/source/blender/makesdna/DNA_action_types.h b/source/blender/makesdna/DNA_action_types.h
index 40c25d39cad..c95a701a78a 100644
--- a/source/blender/makesdna/DNA_action_types.h
+++ b/source/blender/makesdna/DNA_action_types.h
@@ -28,16 +28,16 @@
#ifndef __DNA_ACTION_TYPES_H__
#define __DNA_ACTION_TYPES_H__
-#ifdef __cplusplus
-extern "C" {
-#endif
-
#include "DNA_ID.h"
#include "DNA_listBase.h"
#include "DNA_userdef_types.h" /* ThemeWireColor */
#include "DNA_vec_types.h"
#include "DNA_view2d_types.h"
+#ifdef __cplusplus
+extern "C" {
+#endif
+
struct Collection;
struct GHash;
struct Object;
diff --git a/source/blender/makesdna/DNA_anim_types.h b/source/blender/makesdna/DNA_anim_types.h
index fbffa039ee9..6a024ec9e7e 100644
--- a/source/blender/makesdna/DNA_anim_types.h
+++ b/source/blender/makesdna/DNA_anim_types.h
@@ -24,15 +24,15 @@
#ifndef __DNA_ANIM_TYPES_H__
#define __DNA_ANIM_TYPES_H__
-#ifdef __cplusplus
-extern "C" {
-#endif
-
#include "DNA_ID.h"
#include "DNA_action_types.h"
#include "DNA_curve_types.h"
#include "DNA_listBase.h"
+#ifdef __cplusplus
+extern "C" {
+#endif
+
/* ************************************************ */
/* F-Curve DataTypes */
diff --git a/source/blender/makesdna/DNA_armature_types.h b/source/blender/makesdna/DNA_armature_types.h
index b29816c735b..635c155dec6 100644
--- a/source/blender/makesdna/DNA_armature_types.h
+++ b/source/blender/makesdna/DNA_armature_types.h
@@ -261,23 +261,23 @@ typedef enum eBone_InheritScaleMode {
/* Inherit all scale and shear. */
BONE_INHERIT_SCALE_FULL = 0,
/* Inherit scale, but remove final shear. */
- BONE_INHERIT_SCALE_FIX_SHEAR,
+ BONE_INHERIT_SCALE_FIX_SHEAR = 1,
/* Inherit average scale. */
- BONE_INHERIT_SCALE_AVERAGE,
+ BONE_INHERIT_SCALE_AVERAGE = 2,
/* Inherit no scale or shear. */
- BONE_INHERIT_SCALE_NONE,
+ BONE_INHERIT_SCALE_NONE = 3,
/* Inherit effects of shear on parent (same as old disabled Inherit Scale). */
- BONE_INHERIT_SCALE_NONE_LEGACY,
+ BONE_INHERIT_SCALE_NONE_LEGACY = 4,
/* Inherit parent X scale as child X scale etc. */
- BONE_INHERIT_SCALE_ALIGNED,
+ BONE_INHERIT_SCALE_ALIGNED = 5,
} eBone_InheritScaleMode;
/* bone->bbone_prev_type, bbone_next_type */
typedef enum eBone_BBoneHandleType {
- BBONE_HANDLE_AUTO = 0, /* Default mode based on parents & children. */
- BBONE_HANDLE_ABSOLUTE, /* Custom handle in absolute position mode. */
- BBONE_HANDLE_RELATIVE, /* Custom handle in relative position mode. */
- BBONE_HANDLE_TANGENT, /* Custom handle in tangent mode (use direction, not location). */
+ BBONE_HANDLE_AUTO = 0, /* Default mode based on parents & children. */
+ BBONE_HANDLE_ABSOLUTE = 1, /* Custom handle in absolute position mode. */
+ BBONE_HANDLE_RELATIVE = 2, /* Custom handle in relative position mode. */
+ BBONE_HANDLE_TANGENT = 3, /* Custom handle in tangent mode (use direction, not location). */
} eBone_BBoneHandleType;
#define MAXBONENAME 64
diff --git a/source/blender/makesdna/DNA_brush_types.h b/source/blender/makesdna/DNA_brush_types.h
index 59e9d3be58d..be7c894b4e4 100644
--- a/source/blender/makesdna/DNA_brush_types.h
+++ b/source/blender/makesdna/DNA_brush_types.h
@@ -75,7 +75,7 @@ typedef struct BrushGpencilSettings {
short fill_leak;
/** Fill zoom factor */
short fill_factor;
- char _pad1[4];
+ int flag2;
/** Number of simplify steps. */
int fill_simplylvl;
@@ -118,11 +118,24 @@ typedef struct BrushGpencilSettings {
int sculpt_mode_flag;
/** Preset type (used to reset brushes - internal). */
short preset_type;
- char _pad3[6];
+ char _pad3[2];
+
+ /** Randomness for Hue. */
+ float random_hue;
+ /** Randomness for Saturation. */
+ float random_saturation;
+ /** Randomness for Value. */
+ float random_value;
struct CurveMapping *curve_sensitivity;
struct CurveMapping *curve_strength;
struct CurveMapping *curve_jitter;
+ struct CurveMapping *curve_rand_pressure;
+ struct CurveMapping *curve_rand_strength;
+ struct CurveMapping *curve_rand_uv;
+ struct CurveMapping *curve_rand_hue;
+ struct CurveMapping *curve_rand_saturation;
+ struct CurveMapping *curve_rand_value;
/* optional link of material to replace default in context */
/** Material. */
@@ -204,6 +217,33 @@ typedef enum eGPDbrush_Flag {
GP_BRUSH_TRIM_STROKE = (1 << 16),
} eGPDbrush_Flag;
+typedef enum eGPDbrush_Flag2 {
+ /* Brush use random Hue at stroke level */
+ GP_BRUSH_USE_HUE_AT_STROKE = (1 << 0),
+ /* Brush use random Saturation at stroke level */
+ GP_BRUSH_USE_SAT_AT_STROKE = (1 << 1),
+ /* Brush use random Value at stroke level */
+ GP_BRUSH_USE_VAL_AT_STROKE = (1 << 2),
+ /* Brush use random Pressure at stroke level */
+ GP_BRUSH_USE_PRESS_AT_STROKE = (1 << 3),
+ /* Brush use random Strength at stroke level */
+ GP_BRUSH_USE_STRENGTH_AT_STROKE = (1 << 4),
+ /* Brush use random UV at stroke level */
+ GP_BRUSH_USE_UV_AT_STROKE = (1 << 5),
+ /* Brush use Hue random pressure */
+ GP_BRUSH_USE_HUE_RAND_PRESS = (1 << 6),
+ /* Brush use Saturation random pressure */
+ GP_BRUSH_USE_SAT_RAND_PRESS = (1 << 7),
+ /* Brush use Value random pressure */
+ GP_BRUSH_USE_VAL_RAND_PRESS = (1 << 8),
+ /* Brush use Pressure random pressure */
+ GP_BRUSH_USE_PRESSURE_RAND_PRESS = (1 << 9),
+ /* Brush use Strength random pressure */
+ GP_BRUSH_USE_STRENGTH_RAND_PRESS = (1 << 10),
+ /* Brush use UV random pressure */
+ GP_BRUSH_USE_UV_RAND_PRESS = (1 << 11),
+} eGPDbrush_Flag2;
+
/* BrushGpencilSettings->gp_fill_draw_mode */
typedef enum eGP_FillDrawModes {
GP_FILL_DMODE_BOTH = 0,
@@ -291,6 +331,17 @@ typedef enum eBrushClothForceFalloffType {
BRUSH_CLOTH_FORCE_FALLOFF_PLANE = 1,
} eBrushClothForceFalloffType;
+typedef enum eBrushPoseDeformType {
+ BRUSH_POSE_DEFORM_ROTATE_TWIST = 0,
+ BRUSH_POSE_DEFORM_SCALE_TRASLATE = 1,
+} eBrushPoseDeformType;
+
+typedef enum eBrushPoseOriginType {
+ BRUSH_POSE_ORIGIN_TOPOLOGY = 0,
+ BRUSH_POSE_ORIGIN_FACE_SETS = 1,
+ BRUSH_POSE_ORIGIN_FACE_SETS_FK = 2,
+} eBrushPoseOriginType;
+
/* Gpencilsettings.Vertex_mode */
typedef enum eGp_Vertex_Mode {
/* Affect to Stroke only. */
@@ -327,6 +378,7 @@ typedef enum eAutomasking_flag {
BRUSH_AUTOMASKING_TOPOLOGY = (1 << 0),
BRUSH_AUTOMASKING_FACE_SETS = (1 << 1),
BRUSH_AUTOMASKING_BOUNDARY_EDGES = (1 << 2),
+ BRUSH_AUTOMASKING_BOUNDARY_FACE_SETS = (1 << 3),
} eAutomasking_flag;
typedef struct Brush {
@@ -406,7 +458,7 @@ typedef struct Brush {
/** Source for fill tool color gradient application. */
char gradient_fill_mode;
- char _pad0[5];
+ char _pad0[1];
/** Projection shape (sphere, circle). */
char falloff_shape;
@@ -432,7 +484,7 @@ typedef struct Brush {
char gpencil_sculpt_tool;
/** Active grease pencil weight tool. */
char gpencil_weight_tool;
- char _pad1[6];
+ char _pad1[2];
float autosmooth_factor;
@@ -464,9 +516,11 @@ typedef struct Brush {
float elastic_deform_volume_preservation;
/* pose */
+ int pose_deform_type;
float pose_offset;
int pose_smooth_iterations;
int pose_ik_segments;
+ int pose_origin_type;
/* cloth */
int cloth_deform_type;
@@ -682,7 +736,6 @@ typedef enum eBrushUVSculptTool {
SCULPT_TOOL_SLIDE_RELAX, \
SCULPT_TOOL_CREASE, \
SCULPT_TOOL_BLOB, \
- SCULPT_TOOL_LAYER, \
SCULPT_TOOL_INFLATE, \
SCULPT_TOOL_CLAY, \
SCULPT_TOOL_CLAY_STRIPS, \
@@ -799,8 +852,8 @@ typedef enum {
/* blur kernel types, Brush.blur_mode */
typedef enum eBlurKernelType {
- KERNEL_GAUSSIAN,
- KERNEL_BOX,
+ KERNEL_GAUSSIAN = 0,
+ KERNEL_BOX = 1,
} eBlurKernelType;
/* Brush.falloff_shape */
diff --git a/source/blender/makesdna/DNA_constraint_types.h b/source/blender/makesdna/DNA_constraint_types.h
index 9efd2116601..65087a6d459 100644
--- a/source/blender/makesdna/DNA_constraint_types.h
+++ b/source/blender/makesdna/DNA_constraint_types.h
@@ -735,11 +735,11 @@ typedef enum eConstraint_EulerOrder {
/** Explicit euler rotation modes - must sync with BLI_math_rotation.h defines. */
CONSTRAINT_EULER_XYZ = 1,
- CONSTRAINT_EULER_XZY,
- CONSTRAINT_EULER_YXZ,
- CONSTRAINT_EULER_YZX,
- CONSTRAINT_EULER_ZXY,
- CONSTRAINT_EULER_ZYX,
+ CONSTRAINT_EULER_XZY = 2,
+ CONSTRAINT_EULER_YXZ = 3,
+ CONSTRAINT_EULER_YZX = 4,
+ CONSTRAINT_EULER_ZXY = 5,
+ CONSTRAINT_EULER_ZYX = 6,
} eConstraint_EulerOrder;
/* -------------------------------------- */
@@ -762,13 +762,13 @@ typedef enum eCopyRotation_MixMode {
/* Replace rotation channel values. */
ROTLIKE_MIX_REPLACE = 0,
/* Legacy Offset mode - don't use. */
- ROTLIKE_MIX_OFFSET,
+ ROTLIKE_MIX_OFFSET = 1,
/* Add Euler components together. */
- ROTLIKE_MIX_ADD,
+ ROTLIKE_MIX_ADD = 2,
/* Multiply the copied rotation on the left. */
- ROTLIKE_MIX_BEFORE,
+ ROTLIKE_MIX_BEFORE = 3,
/* Multiply the copied rotation on the right. */
- ROTLIKE_MIX_AFTER,
+ ROTLIKE_MIX_AFTER = 4,
} eCopyRotation_MixMode;
/* bLocateLikeConstraint.flag */
@@ -799,9 +799,9 @@ typedef enum eCopyTransforms_MixMode {
/* Replace rotation channel values. */
TRANSLIKE_MIX_REPLACE = 0,
/* Multiply the copied transformation on the left, with anti-shear scale handling. */
- TRANSLIKE_MIX_BEFORE,
+ TRANSLIKE_MIX_BEFORE = 1,
/* Multiply the copied transformation on the right, with anti-shear scale handling. */
- TRANSLIKE_MIX_AFTER,
+ TRANSLIKE_MIX_AFTER = 2,
} eCopyTransforms_MixMode;
/* bTransformConstraint.to/from */
@@ -816,7 +816,7 @@ typedef enum eTransform_MixModeLoc {
/* Add component values together (default). */
TRANS_MIXLOC_ADD = 0,
/* Replace component values. */
- TRANS_MIXLOC_REPLACE,
+ TRANS_MIXLOC_REPLACE = 1,
} eTransform_MixModeLoc;
/* bTransformConstraint.mix_mode_rot */
@@ -824,11 +824,11 @@ typedef enum eTransform_MixModeRot {
/* Add component values together (default). */
TRANS_MIXROT_ADD = 0,
/* Replace component values. */
- TRANS_MIXROT_REPLACE,
+ TRANS_MIXROT_REPLACE = 1,
/* Multiply the generated rotation on the left. */
- TRANS_MIXROT_BEFORE,
+ TRANS_MIXROT_BEFORE = 2,
/* Multiply the generated rotation on the right. */
- TRANS_MIXROT_AFTER,
+ TRANS_MIXROT_AFTER = 3,
} eTransform_MixModeRot;
/* bTransformConstraint.mix_mode_scale */
@@ -836,7 +836,7 @@ typedef enum eTransform_MixModeScale {
/* Replace component values (default). */
TRANS_MIXSCALE_REPLACE = 0,
/* Multiply component values together. */
- TRANS_MIXSCALE_MULTIPLY,
+ TRANS_MIXSCALE_MULTIPLY = 1,
} eTransform_MixModeScale;
/* bSameVolumeConstraint.free_axis */
@@ -867,9 +867,9 @@ typedef enum eActionConstraint_MixMode {
/* Multiply the action transformation on the right. */
ACTCON_MIX_AFTER_FULL = 0,
/* Multiply the action transformation on the right, with anti-shear scale handling. */
- ACTCON_MIX_AFTER,
+ ACTCON_MIX_AFTER = 1,
/* Multiply the action transformation on the left, with anti-shear scale handling. */
- ACTCON_MIX_BEFORE,
+ ACTCON_MIX_BEFORE = 2,
} eActionConstraint_MixMode;
/* Locked-Axis Values (Locked Track) */
diff --git a/source/blender/makesdna/DNA_curve_types.h b/source/blender/makesdna/DNA_curve_types.h
index 6a081a7f5a7..b2902407a15 100644
--- a/source/blender/makesdna/DNA_curve_types.h
+++ b/source/blender/makesdna/DNA_curve_types.h
@@ -496,11 +496,11 @@ typedef enum eBezTriple_KeyframeType {
#define BEZT_ISSEL_ALL(bezt) \
(((bezt)->f2 & SELECT) && ((bezt)->f1 & SELECT) && ((bezt)->f3 & SELECT))
#define BEZT_ISSEL_ALL_HIDDENHANDLES(v3d, bezt) \
- ((((v3d) != NULL) && ((v3d)->overlay.edit_flag & V3D_OVERLAY_EDIT_CU_HANDLES) == 0) ? \
+ ((((v3d) != NULL) && ((v3d)->overlay.handle_display == CURVE_HANDLE_NONE)) ? \
(bezt)->f2 & SELECT : \
BEZT_ISSEL_ALL(bezt))
#define BEZT_ISSEL_ANY_HIDDENHANDLES(v3d, bezt) \
- ((((v3d) != NULL) && ((v3d)->overlay.edit_flag & V3D_OVERLAY_EDIT_CU_HANDLES) == 0) ? \
+ ((((v3d) != NULL) && ((v3d)->overlay.handle_display == CURVE_HANDLE_NONE)) ? \
(bezt)->f2 & SELECT : \
BEZT_ISSEL_ANY(bezt))
diff --git a/source/blender/makesdna/DNA_customdata_types.h b/source/blender/makesdna/DNA_customdata_types.h
index 5ee16c2631d..ef3b2015758 100644
--- a/source/blender/makesdna/DNA_customdata_types.h
+++ b/source/blender/makesdna/DNA_customdata_types.h
@@ -26,12 +26,12 @@
#ifndef __DNA_CUSTOMDATA_TYPES_H__
#define __DNA_CUSTOMDATA_TYPES_H__
+#include "DNA_defs.h"
+
#ifdef __cplusplus
extern "C" {
#endif
-#include "DNA_defs.h"
-
/** Descriptor and storage for a custom data layer. */
typedef struct CustomDataLayer {
/** Type of data in layer. */
@@ -76,7 +76,8 @@ typedef struct CustomData {
* MUST be >= CD_NUMTYPES, but we cant use a define here.
* Correct size is ensured in CustomData_update_typemap assert().
*/
- int typemap[47];
+ int typemap[48];
+ char _pad[4];
/** Number of layers, size of layers array. */
int totlayer, maxlayer;
/** In editmode, total size of all data layers. */
@@ -153,7 +154,9 @@ typedef enum CustomDataType {
CD_HAIRCURVE = 45,
CD_HAIRMAPPING = 46,
- CD_NUMTYPES = 47,
+ CD_PROP_COLOR = 47,
+
+ CD_NUMTYPES = 48,
} CustomDataType;
/* Bits for CustomDataMask */
@@ -202,6 +205,7 @@ typedef enum CustomDataType {
#define CD_MASK_TESSLOOPNORMAL (1LL << CD_TESSLOOPNORMAL)
#define CD_MASK_CUSTOMLOOPNORMAL (1LL << CD_CUSTOMLOOPNORMAL)
#define CD_MASK_SCULPT_FACE_SETS (1LL << CD_SCULPT_FACE_SETS)
+#define CD_MASK_PROP_COLOR (1LL << CD_PROP_COLOR)
/** Data types that may be defined for all mesh elements types. */
#define CD_MASK_GENERIC_DATA (CD_MASK_PROP_FLT | CD_MASK_PROP_INT | CD_MASK_PROP_STR)
diff --git a/source/blender/makesdna/DNA_defaults.h b/source/blender/makesdna/DNA_defaults.h
index 9b4a05034df..ca5ac649e33 100644
--- a/source/blender/makesdna/DNA_defaults.h
+++ b/source/blender/makesdna/DNA_defaults.h
@@ -29,12 +29,12 @@
#include "BLI_utildefines.h"
+#include "dna_type_offsets.h"
+
#ifdef __cplusplus
extern "C" {
#endif
-#include "dna_type_offsets.h"
-
extern const void *DNA_default_table[SDNA_TYPE_MAX];
char *_DNA_struct_default_alloc_impl(const char *data_src, size_t size, const char *alloc_str);
diff --git a/source/blender/makesdna/DNA_dynamicpaint_types.h b/source/blender/makesdna/DNA_dynamicpaint_types.h
index d949b34cb57..c97e68a6a6b 100644
--- a/source/blender/makesdna/DNA_dynamicpaint_types.h
+++ b/source/blender/makesdna/DNA_dynamicpaint_types.h
@@ -10,7 +10,7 @@
* 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,
+ * along with this program; if not, write to the Free Software Foundation,
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
diff --git a/source/blender/makesdna/DNA_fluid_types.h b/source/blender/makesdna/DNA_fluid_types.h
index f344e860d2e..7da33a369f3 100644
--- a/source/blender/makesdna/DNA_fluid_types.h
+++ b/source/blender/makesdna/DNA_fluid_types.h
@@ -215,6 +215,72 @@ enum {
#define FLUID_DOMAIN_SMOKE_SCRIPT "smoke_script.py"
#define FLUID_DOMAIN_LIQUID_SCRIPT "liquid_script.py"
+#define FLUID_FILENAME_CONFIG "config_####"
+
+#define FLUID_FILENAME_DATA "fluid_data_####"
+#define FLUID_FILENAME_NOISE "fluid_noise_####"
+#define FLUID_FILENAME_DENSITY "density_####"
+#define FLUID_FILENAME_SHADOW "shadow_####"
+#define FLUID_FILENAME_VELOCITY "vel_####"
+#define FLUID_FILENAME_HEAT "heat_####"
+#define FLUID_FILENAME_COLORR "color_r_####"
+#define FLUID_FILENAME_COLORG "color_g_####"
+#define FLUID_FILENAME_COLORB "color_b_####"
+#define FLUID_FILENAME_FLAME "flame_####"
+#define FLUID_FILENAME_FUEL "fuel_####"
+#define FLUID_FILENAME_REACT "react_####"
+#define FLUID_FILENAME_PHI "phi_####"
+#define FLUID_FILENAME_PP "pp_####"
+#define FLUID_FILENAME_PVEL "pVel_####"
+#define FLUID_FILENAME_DENSITYNOISE "density_noise_####"
+#define FLUID_FILENAME_COLORRNOISE "color_r_noise_####"
+#define FLUID_FILENAME_COLORGNOISE "color_g_noise_####"
+#define FLUID_FILENAME_COLORBNOISE "color_b_noise_####"
+#define FLUID_FILENAME_FLAMENOISE "flame_noise_####"
+#define FLUID_FILENAME_FUELNOISE "fuel_noise_####"
+#define FLUID_FILENAME_REACTNOISE "react_noise_####"
+#define FLUID_FILENAME_MESH "lMesh_####"
+#define FLUID_FILENAME_MESHVEL "lVelMesh_####"
+#define FLUID_FILENAME_PPSND "ppSnd_####"
+#define FLUID_FILENAME_PVELSND "pVelSnd_####"
+#define FLUID_FILENAME_PLIFESND "pLifeSnd_####"
+#define FLUID_FILENAME_GUIDEVEL "guidevel_####"
+
+#define FLUID_GRIDNAME_DENSITY "density"
+#define FLUID_GRIDNAME_SHADOW "shadow"
+#define FLUID_GRIDNAME_VELOCITY "velocity"
+#define FLUID_GRIDNAME_HEAT "heat"
+#define FLUID_GRIDNAME_COLORR "color_r"
+#define FLUID_GRIDNAME_COLORG "color_g"
+#define FLUID_GRIDNAME_COLORB "color_b"
+#define FLUID_GRIDNAME_FLAME "flame"
+#define FLUID_GRIDNAME_FUEL "fuel"
+#define FLUID_GRIDNAME_REACT "react"
+#define FLUID_GRIDNAME_DENSITYNOISE "density_noise"
+#define FLUID_GRIDNAME_COLORRNOISE "color_r_noise"
+#define FLUID_GRIDNAME_COLORGNOISE "color_g_noise"
+#define FLUID_GRIDNAME_COLORBNOISE "color_b_noise"
+#define FLUID_GRIDNAME_FLAMENOISE "flame_noise"
+#define FLUID_GRIDNAME_FUELNOISE "fuel_noise"
+#define FLUID_GRIDNAME_REACTNOISE "react_noise"
+
+#define FLUID_DOMAIN_EXTENSION_UNI ".uni"
+#define FLUID_DOMAIN_EXTENSION_OPENVDB ".vdb"
+#define FLUID_DOMAIN_EXTENSION_RAW ".raw"
+#define FLUID_DOMAIN_EXTENSION_OBJ ".obj"
+#define FLUID_DOMAIN_EXTENSION_BINOBJ ".bobj.gz"
+
+enum {
+ FLUID_DOMAIN_GRID_FLOAT = 0,
+ FLUID_DOMAIN_GRID_INT = 1,
+ FLUID_DOMAIN_GRID_VEC3F = 2,
+};
+
+enum {
+ FLUID_DOMAIN_CACHE_FILES_SINGLE = 0,
+ FLUID_DOMAIN_CACHE_FILES_COMBINED = 1,
+};
+
enum {
FLUID_DOMAIN_CACHE_REPLAY = 0,
FLUID_DOMAIN_CACHE_MODULAR = 1,
@@ -353,7 +419,6 @@ typedef struct FluidDomainSettings {
float surface_tension;
float viscosity_base;
int viscosity_exponent;
- float domain_size;
/* Mesh options. */
float mesh_concave_upper;
@@ -364,7 +429,7 @@ typedef struct FluidDomainSettings {
int mesh_scale;
int totvert;
short mesh_generator;
- char _pad5[2]; /* Unused. */
+ char _pad5[6]; /* Unused. */
/* Secondary particle options. */
int particle_type;
@@ -501,6 +566,8 @@ enum {
FLUID_FLOW_USE_INFLOW = (1 << 5),
/* Control how to initialize flow objects. */
FLUID_FLOW_USE_PLANE_INIT = (1 << 6),
+ /* Notify domain objects about state change (invalidate cache). */
+ FLUID_FLOW_NEEDS_UPDATE = (1 << 7),
};
typedef struct FluidFlowSettings {
@@ -574,6 +641,8 @@ enum {
FLUID_EFFECTOR_USE_EFFEC = (1 << 1),
/* Control how to initialize flow objects. */
FLUID_EFFECTOR_USE_PLANE_INIT = (1 << 2),
+ /* Notify domain objects about state change (invalidate cache). */
+ FLUID_EFFECTOR_NEEDS_UPDATE = (1 << 3),
};
/* Collision objects (filled with smoke). */
diff --git a/source/blender/makesdna/DNA_gpencil_modifier_types.h b/source/blender/makesdna/DNA_gpencil_modifier_types.h
index f98ec281011..125423cd061 100644
--- a/source/blender/makesdna/DNA_gpencil_modifier_types.h
+++ b/source/blender/makesdna/DNA_gpencil_modifier_types.h
@@ -47,6 +47,8 @@ typedef enum GpencilModifierType {
eGpencilModifierType_Armature = 15,
eGpencilModifierType_Time = 16,
eGpencilModifierType_Multiply = 17,
+ eGpencilModifierType_Texture = 18,
+ /* Keep last. */
NUM_GREASEPENCIL_MODIFIER_TYPES,
} GpencilModifierType;
@@ -77,10 +79,12 @@ typedef struct GpencilModifierData {
typedef struct NoiseGpencilModifierData {
GpencilModifierData modifier;
+ /** Material for filtering. */
+ struct Material *material;
/** Layer name. */
char layername[64];
/** Material name. */
- char materialname[64];
+ char materialname[64] DNA_DEPRECATED;
/** Optional vertexgroup name, MAX_VGROUP_NAME. */
char vgname[64];
/** Custom index for passes. */
@@ -120,10 +124,12 @@ typedef enum eNoiseGpencil_Flag {
typedef struct SubdivGpencilModifierData {
GpencilModifierData modifier;
+ /** Material for filtering. */
+ struct Material *material;
/** Layer name. */
char layername[64];
/** Material name. */
- char materialname[64];
+ char materialname[64] DNA_DEPRECATED;
/** Custom index for passes. */
int pass_index;
/** Flags. */
@@ -151,10 +157,12 @@ typedef enum eSubdivGpencil_Type {
typedef struct ThickGpencilModifierData {
GpencilModifierData modifier;
+ /** Material for filtering. */
+ struct Material *material;
/** Layer name. */
char layername[64];
/** Material name. */
- char materialname[64];
+ char materialname[64] DNA_DEPRECATED;
/** Optional vertexgroup name, MAX_VGROUP_NAME. */
char vgname[64];
/** Custom index for passes. */
@@ -215,7 +223,7 @@ typedef enum eModifyColorGpencil_Flag {
GP_MODIFY_COLOR_BOTH = 0,
GP_MODIFY_COLOR_STROKE = 1,
GP_MODIFY_COLOR_FILL = 2,
- GP_MODIFY_COLOR_HARDENESS = 3,
+ GP_MODIFY_COLOR_HARDNESS = 3,
} eModifyColorGpencil_Flag;
typedef enum eOpacityModesGpencil_Flag {
@@ -225,10 +233,12 @@ typedef enum eOpacityModesGpencil_Flag {
typedef struct ColorGpencilModifierData {
GpencilModifierData modifier;
+ /** Material for filtering. */
+ struct Material *material;
/** Layer name. */
char layername[64];
/** Material name. */
- char materialname[64];
+ char materialname[64] DNA_DEPRECATED;
/** Custom index for passes. */
int pass_index;
/** Flags. */
@@ -255,10 +265,12 @@ typedef enum eColorGpencil_Flag {
typedef struct OpacityGpencilModifierData {
GpencilModifierData modifier;
+ /** Material for filtering. */
+ struct Material *material;
/** Layer name. */
char layername[64];
/** Material name. */
- char materialname[64];
+ char materialname[64] DNA_DEPRECATED;
/** Optional vertexgroup name, MAX_VGROUP_NAME. */
char vgname[64];
/** Custom index for passes. */
@@ -290,6 +302,8 @@ typedef enum eOpacityGpencil_Flag {
typedef struct ArrayGpencilModifierData {
GpencilModifierData modifier;
struct Object *object;
+ /** Material for filtering. */
+ struct Material *material;
/** Number of elements in array. */
int count;
/** Several flags. */
@@ -313,7 +327,7 @@ typedef struct ArrayGpencilModifierData {
/** Layer name. */
char layername[64];
/** Material name. */
- char materialname[64];
+ char materialname[64] DNA_DEPRECATED;
/** Material replace (0 keep default). */
int mat_rpl;
/** Custom index for passes. */
@@ -332,13 +346,15 @@ typedef enum eArrayGpencil_Flag {
typedef struct BuildGpencilModifierData {
GpencilModifierData modifier;
+ /** Material for filtering. */
+ struct Material *material;
/** If set, restrict modifier to operating on this layer. */
char layername[64];
int pass_index;
/** Material name. */
- char materialname[64];
+ char materialname[64] DNA_DEPRECATED;
/** Custom index for passes. */
int layer_pass;
@@ -368,6 +384,9 @@ typedef struct BuildGpencilModifierData {
* For the "Concurrent" mode, when should "shorter" strips start/end.
*/
short time_alignment;
+ /** Factor of the stroke (used instead of frame evaluation. */
+ float percentage_fac;
+ char _pad[4];
} BuildGpencilModifierData;
typedef enum eBuildGpencil_Mode {
@@ -403,15 +422,20 @@ typedef enum eBuildGpencil_Flag {
/* Restrict modifier to only operating between the nominated frames */
GP_BUILD_RESTRICT_TIME = (1 << 2),
GP_BUILD_INVERT_LAYERPASS = (1 << 3),
+
+ /* Use a percentage instead of frame number to evaluate strokes. */
+ GP_BUILD_PERCENTAGE = (1 << 4),
} eBuildGpencil_Flag;
typedef struct LatticeGpencilModifierData {
GpencilModifierData modifier;
struct Object *object;
+ /** Material for filtering. */
+ struct Material *material;
/** Layer name. */
char layername[64];
/** Material name. */
- char materialname[64];
+ char materialname[64] DNA_DEPRECATED;
/** Optional vertexgroup name, MAX_VGROUP_NAME. */
char vgname[64];
/** Custom index for passes. */
@@ -436,10 +460,12 @@ typedef enum eLatticeGpencil_Flag {
typedef struct MirrorGpencilModifierData {
GpencilModifierData modifier;
struct Object *object;
+ /** Material for filtering. */
+ struct Material *material;
/** Layer name. */
char layername[64];
/** Material name. */
- char materialname[64];
+ char materialname[64] DNA_DEPRECATED;
/** Custom index for passes. */
int pass_index;
/** Flags. */
@@ -464,12 +490,14 @@ typedef struct HookGpencilModifierData {
GpencilModifierData modifier;
struct Object *object;
+ /** Material for filtering. */
+ struct Material *material;
/** Optional name of bone target, MAX_ID_NAME-2. */
char subtarget[64];
/** Layer name. */
char layername[64];
/** Material name. */
- char materialname[64];
+ char materialname[64] DNA_DEPRECATED;
/** Optional vertexgroup name, MAX_VGROUP_NAME. */
char vgname[64];
/** Custom index for passes. */
@@ -515,10 +543,12 @@ typedef enum eHookGpencil_Falloff {
typedef struct SimplifyGpencilModifierData {
GpencilModifierData modifier;
+ /** Material for filtering. */
+ struct Material *material;
/** Layer name. */
char layername[64];
/** Material name. */
- char materialname[64];
+ char materialname[64] DNA_DEPRECATED;
/** Custom index for passes. */
int pass_index;
/** Flags. */
@@ -558,10 +588,12 @@ typedef enum eSimplifyGpencil_Mode {
typedef struct OffsetGpencilModifierData {
GpencilModifierData modifier;
+ /** Material for filtering. */
+ struct Material *material;
/** Layer name. */
char layername[64];
/** Material name. */
- char materialname[64];
+ char materialname[64] DNA_DEPRECATED;
/** Optional vertexgroup name, MAX_VGROUP_NAME. */
char vgname[64];
/** Custom index for passes. */
@@ -585,10 +617,12 @@ typedef enum eOffsetGpencil_Flag {
typedef struct SmoothGpencilModifierData {
GpencilModifierData modifier;
+ /** Material for filtering. */
+ struct Material *material;
/** Layer name. */
char layername[64];
/** Material name. */
- char materialname[64];
+ char materialname[64] DNA_DEPRECATED;
/** Optional vertexgroup name, MAX_VGROUP_NAME. */
char vgname[64];
/** Custom index for passes. */
@@ -634,10 +668,12 @@ typedef struct ArmatureGpencilModifierData {
typedef struct MultiplyGpencilModifierData {
GpencilModifierData modifier;
+ /** Material for filtering. */
+ struct Material *material;
/** Layer name. */
char layername[64];
/** Material name. */
- char materialname[64];
+ char materialname[64] DNA_DEPRECATED;
/** Custom index for passes. */
int pass_index;
/** Flags. */
@@ -672,10 +708,12 @@ typedef struct TintGpencilModifierData {
GpencilModifierData modifier;
struct Object *object;
+ /** Material for filtering. */
+ struct Material *material;
/** Layer name. */
char layername[64];
/** Material name. */
- char materialname[64];
+ char materialname[64] DNA_DEPRECATED;
/** Optional vertexgroup name, MAX_VGROUP_NAME. */
char vgname[64];
/** Custom index for passes. */
@@ -713,4 +751,52 @@ typedef enum eTintGpencil_Flag {
GP_TINT_CUSTOM_CURVE = (1 << 6),
} eTintGpencil_Flag;
+typedef struct TextureGpencilModifierData {
+ GpencilModifierData modifier;
+ /** Material for filtering. */
+ struct Material *material;
+ /** Layer name. */
+ char layername[64];
+ /** Material name. */
+ char materialname[64] DNA_DEPRECATED;
+ /** Optional vertexgroup name, MAX_VGROUP_NAME. */
+ char vgname[64];
+ /** Custom index for passes. */
+ int pass_index;
+ /** Flags. */
+ int flag;
+ /** Offset value to add to uv_fac. */
+ float uv_offset;
+ float uv_scale;
+ float fill_rotation;
+ float fill_offset[2];
+ float fill_scale;
+ /** Custom index for passes. */
+ int layer_pass;
+ /** Texture fit options. */
+ short fit_method;
+ short mode;
+} TextureGpencilModifierData;
+
+typedef enum eTextureGpencil_Flag {
+ GP_TEX_INVERT_LAYER = (1 << 0),
+ GP_TEX_INVERT_PASS = (1 << 1),
+ GP_TEX_INVERT_VGROUP = (1 << 2),
+ GP_TEX_INVERT_LAYERPASS = (1 << 3),
+ GP_TEX_INVERT_MATERIAL = (1 << 4),
+} eTextureGpencil_Flag;
+
+/* Texture->fit_method */
+typedef enum eTextureGpencil_Fit {
+ GP_TEX_FIT_STROKE = 0,
+ GP_TEX_CONSTANT_LENGTH = 1,
+} eTextureGpencil_Fit;
+
+/* Texture->mode */
+typedef enum eTextureGpencil_Mode {
+ STROKE = 0,
+ FILL = 1,
+ STROKE_AND_FILL = 2,
+} eTextureGpencil_Mode;
+
#endif /* __DNA_GPENCIL_MODIFIER_TYPES_H__ */
diff --git a/source/blender/makesdna/DNA_gpencil_types.h b/source/blender/makesdna/DNA_gpencil_types.h
index a90935bfe62..c3180ae79db 100644
--- a/source/blender/makesdna/DNA_gpencil_types.h
+++ b/source/blender/makesdna/DNA_gpencil_types.h
@@ -264,6 +264,10 @@ typedef enum eGPDstroke_Flag {
/* Flag used to indicate that stroke is used for fill close and must use
* fill color for stroke and no fill area */
GP_STROKE_NOFILL = (1 << 8),
+ /* only for use with stroke-buffer (while drawing arrows) */
+ GP_STROKE_USE_ARROW_START = (1 << 12),
+ /* only for use with stroke-buffer (while drawing arrows) */
+ GP_STROKE_USE_ARROW_END = (1 << 13),
/* Tag for update geometry */
GP_STROKE_TAG = (1 << 14),
/* only for use with stroke-buffer (while drawing eraser) */
@@ -276,9 +280,21 @@ typedef enum eGPDstroke_Caps {
GP_STROKE_CAP_ROUND = 0,
GP_STROKE_CAP_FLAT = 1,
+ /* Keeo last. */
GP_STROKE_CAP_MAX,
} GPDstroke_Caps;
+/* Arrows ----------------------- */
+
+/* bGPDataRuntime.arrowstyle */
+typedef enum eGPDstroke_Arrowstyle {
+ GP_STROKE_ARROWSTYLE_NONE = 0,
+ GP_STROKE_ARROWSTYLE_SEGMENT = 2,
+ GP_STROKE_ARROWSTYLE_OPEN = 3,
+ GP_STROKE_ARROWSTYLE_CLOSED = 4,
+ GP_STROKE_ARROWSTYLE_SQUARE = 6,
+} eGPDstroke_Arrowstyle;
+
/* ***************************************** */
/* GP Frame */
@@ -468,7 +484,7 @@ typedef enum eGPDlayer_OnionFlag {
/* layer blend_mode */
typedef enum eGPLayerBlendModes {
eGplBlendMode_Regular = 0,
- eGplBlendMode_Overlay = 1,
+ eGplBlendMode_HardLight = 1,
eGplBlendMode_Add = 2,
eGplBlendMode_Subtract = 3,
eGplBlendMode_Multiply = 4,
@@ -504,12 +520,16 @@ typedef struct bGPdata_Runtime {
/** Number of total elements available in cache. */
int sbuffer_size;
- /** Vertex Color applied to point (while drawing). */
- float vert_color[4];
-
/** Vertex Color applied to Fill (while drawing). */
float vert_color_fill[4];
+ /** Arrow points for stroke corners **/
+ float arrow_start[8];
+ float arrow_end[8];
+ /* Arrow style for each corner */
+ int arrow_start_style;
+ int arrow_end_style;
+
/** Number of control-points for stroke. */
int tot_cp_points;
char _pad2[4];
@@ -661,8 +681,6 @@ typedef enum eGPdata_Flag {
/* Autolock not active layers */
GP_DATA_AUTOLOCK_LAYERS = (1 << 20),
- /* Internal flag for python update */
- GP_DATA_PYTHON_UPDATED = (1 << 21),
} eGPdata_Flag;
/* gpd->onion_flag */
@@ -704,31 +722,32 @@ typedef enum eGP_DrawMode {
/* Check if 'multiedit sessions' is enabled */
#define GPENCIL_MULTIEDIT_SESSIONS_ON(gpd) \
((gpd) && \
- (gpd->flag & (GP_DATA_STROKE_EDITMODE | GP_DATA_STROKE_SCULPTMODE | \
- GP_DATA_STROKE_WEIGHTMODE | GP_DATA_STROKE_VERTEXMODE)) && \
- (gpd->flag & GP_DATA_STROKE_MULTIEDIT))
+ ((gpd)->flag & (GP_DATA_STROKE_EDITMODE | GP_DATA_STROKE_SCULPTMODE | \
+ GP_DATA_STROKE_WEIGHTMODE | GP_DATA_STROKE_VERTEXMODE)) && \
+ ((gpd)->flag & GP_DATA_STROKE_MULTIEDIT))
/* Macros to check grease pencil modes */
#define GPENCIL_ANY_MODE(gpd) \
- ((gpd) && \
- (gpd->flag & (GP_DATA_STROKE_PAINTMODE | GP_DATA_STROKE_EDITMODE | GP_DATA_STROKE_SCULPTMODE | \
- GP_DATA_STROKE_WEIGHTMODE | GP_DATA_STROKE_VERTEXMODE)))
+ ((gpd) && ((gpd)->flag & \
+ (GP_DATA_STROKE_PAINTMODE | GP_DATA_STROKE_EDITMODE | GP_DATA_STROKE_SCULPTMODE | \
+ GP_DATA_STROKE_WEIGHTMODE | GP_DATA_STROKE_VERTEXMODE)))
#define GPENCIL_EDIT_MODE(gpd) ((gpd) && ((gpd)->flag & GP_DATA_STROKE_EDITMODE))
#define GPENCIL_ANY_EDIT_MODE(gpd) \
- ((gpd) && (gpd->flag & \
+ ((gpd) && ((gpd)->flag & \
(GP_DATA_STROKE_EDITMODE | GP_DATA_STROKE_SCULPTMODE | GP_DATA_STROKE_WEIGHTMODE)))
#define GPENCIL_PAINT_MODE(gpd) ((gpd) && (gpd->flag & (GP_DATA_STROKE_PAINTMODE)))
#define GPENCIL_SCULPT_MODE(gpd) ((gpd) && (gpd->flag & GP_DATA_STROKE_SCULPTMODE))
#define GPENCIL_WEIGHT_MODE(gpd) ((gpd) && (gpd->flag & GP_DATA_STROKE_WEIGHTMODE))
#define GPENCIL_VERTEX_MODE(gpd) ((gpd) && (gpd->flag & (GP_DATA_STROKE_VERTEXMODE)))
#define GPENCIL_SCULPT_OR_WEIGHT_MODE(gpd) \
- ((gpd) && (gpd->flag & (GP_DATA_STROKE_SCULPTMODE | GP_DATA_STROKE_WEIGHTMODE)))
+ ((gpd) && ((gpd)->flag & (GP_DATA_STROKE_SCULPTMODE | GP_DATA_STROKE_WEIGHTMODE)))
#define GPENCIL_NONE_EDIT_MODE(gpd) \
- ((gpd) && ((gpd->flag & (GP_DATA_STROKE_EDITMODE | GP_DATA_STROKE_SCULPTMODE | \
- GP_DATA_STROKE_WEIGHTMODE | GP_DATA_STROKE_VERTEXMODE)) == 0))
+ ((gpd) && (((gpd)->flag & (GP_DATA_STROKE_EDITMODE | GP_DATA_STROKE_SCULPTMODE | \
+ GP_DATA_STROKE_WEIGHTMODE | GP_DATA_STROKE_VERTEXMODE)) == 0))
#define GPENCIL_LAZY_MODE(brush, shift) \
- (((brush) && ((brush->gpencil_settings->flag & GP_BRUSH_STABILIZE_MOUSE) && (shift == 0))) || \
- (((brush->gpencil_settings->flag & GP_BRUSH_STABILIZE_MOUSE) == 0) && (shift == 1)))
+ (((brush) && \
+ (((brush)->gpencil_settings->flag & GP_BRUSH_STABILIZE_MOUSE) && ((shift) == 0))) || \
+ ((((brush)->gpencil_settings->flag & GP_BRUSH_STABILIZE_MOUSE) == 0) && ((shift) == 1)))
#define GPENCIL_ANY_SCULPT_MASK(flag) \
((flag & (GP_SCULPT_MASK_SELECTMODE_POINT | GP_SCULPT_MASK_SELECTMODE_STROKE | \
diff --git a/source/blender/makesdna/DNA_layer_types.h b/source/blender/makesdna/DNA_layer_types.h
index a9293d18d41..6348dc5f03d 100644
--- a/source/blender/makesdna/DNA_layer_types.h
+++ b/source/blender/makesdna/DNA_layer_types.h
@@ -21,13 +21,13 @@
#ifndef __DNA_LAYER_TYPES_H__
#define __DNA_LAYER_TYPES_H__
+#include "DNA_freestyle_types.h"
+#include "DNA_listBase.h"
+
#ifdef __cplusplus
extern "C" {
#endif
-#include "DNA_freestyle_types.h"
-#include "DNA_listBase.h"
-
/**
* Render-passes for EEVEE.
* #ViewLayerEEVEE.render_passes
@@ -115,6 +115,7 @@ typedef struct ViewLayer {
ListBase object_bases;
/** Default allocated now. */
struct SceneStats *stats;
+ char footer_str[128];
struct Base *basact;
/** A view layer has one top level layer collection, because a scene has only one top level
@@ -173,6 +174,7 @@ enum {
LAYER_COLLECTION_HOLDOUT = (1 << 5),
LAYER_COLLECTION_INDIRECT_ONLY = (1 << 6),
LAYER_COLLECTION_HIDE = (1 << 7),
+ LAYER_COLLECTION_PREVIOUSLY_EXCLUDED = (1 << 8),
};
/* Layer Collection->runtime_flag
diff --git a/source/blender/makesdna/DNA_lightprobe_types.h b/source/blender/makesdna/DNA_lightprobe_types.h
index 66d6e3f4868..5ddfedfed2d 100644
--- a/source/blender/makesdna/DNA_lightprobe_types.h
+++ b/source/blender/makesdna/DNA_lightprobe_types.h
@@ -10,7 +10,7 @@
* 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,
+ * along with this program; if not, write to the Free Software Foundation,
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
diff --git a/source/blender/makesdna/DNA_material_types.h b/source/blender/makesdna/DNA_material_types.h
index f2e65ff9251..357c3260121 100644
--- a/source/blender/makesdna/DNA_material_types.h
+++ b/source/blender/makesdna/DNA_material_types.h
@@ -87,7 +87,7 @@ typedef struct MaterialGPencilStyle {
/** Factor to shift texture in 2d space. */
float texture_offset[2];
/** Texture opacity. */
- float texture_opacity;
+ float texture_opacity DNA_DEPRECATED;
/** Pixel size for uv along the stroke. */
float texture_pixsize;
/** Drawing mode (line or dots). */
@@ -324,35 +324,35 @@ enum {
/* blend_shadow */
enum {
MA_BS_NONE = 0,
- MA_BS_SOLID,
- MA_BS_CLIP,
- MA_BS_HASHED,
+ MA_BS_SOLID = 1,
+ MA_BS_CLIP = 2,
+ MA_BS_HASHED = 3,
};
/* Grease Pencil Stroke styles */
enum {
GP_MATERIAL_STROKE_STYLE_SOLID = 0,
- GP_MATERIAL_STROKE_STYLE_TEXTURE,
+ GP_MATERIAL_STROKE_STYLE_TEXTURE = 1,
};
/* Grease Pencil Fill styles */
enum {
GP_MATERIAL_FILL_STYLE_SOLID = 0,
- GP_MATERIAL_FILL_STYLE_GRADIENT,
- GP_MATERIAL_FILL_STYLE_CHECKER, /* DEPRECATED (only for convert old files) */
- GP_MATERIAL_FILL_STYLE_TEXTURE,
+ GP_MATERIAL_FILL_STYLE_GRADIENT = 1,
+ GP_MATERIAL_FILL_STYLE_CHECKER = 2, /* DEPRECATED (only for convert old files) */
+ GP_MATERIAL_FILL_STYLE_TEXTURE = 3,
};
/* Grease Pencil Gradient Types */
enum {
GP_MATERIAL_GRADIENT_LINEAR = 0,
- GP_MATERIAL_GRADIENT_RADIAL,
+ GP_MATERIAL_GRADIENT_RADIAL = 1,
};
/* Grease Pencil Follow Drawing Modes */
enum {
GP_MATERIAL_FOLLOW_PATH = 0,
- GP_MATERIAL_FOLLOW_OBJ,
- GP_MATERIAL_FOLLOW_FIXED,
+ GP_MATERIAL_FOLLOW_OBJ = 1,
+ GP_MATERIAL_FOLLOW_FIXED = 2,
};
#endif
diff --git a/source/blender/makesdna/DNA_mesh_types.h b/source/blender/makesdna/DNA_mesh_types.h
index d8acf5bc493..acc020ec710 100644
--- a/source/blender/makesdna/DNA_mesh_types.h
+++ b/source/blender/makesdna/DNA_mesh_types.h
@@ -33,6 +33,7 @@ extern "C" {
#endif
struct AnimData;
+struct BVHCache;
struct Ipo;
struct Key;
struct LinkNode;
@@ -99,8 +100,8 @@ typedef struct Mesh_Runtime {
struct MLoopTri_Store looptris;
- /** 'BVHCache', for 'BKE_bvhutil.c' */
- struct LinkNode *bvh_cache;
+ /** `BVHCache` defined in 'BKE_bvhutil.c' */
+ struct BVHCache *bvh_cache;
/** Non-manifold boundary data for Shrinkwrap Target Project. */
struct ShrinkwrapBoundaryData *shrinkwrap_data;
@@ -112,7 +113,20 @@ typedef struct Mesh_Runtime {
* In the future we may leave the mesh-data empty
* since its not needed if we can use edit-mesh data. */
char is_original;
- char _pad[6];
+
+ /** #eMeshWrapperType and others. */
+ char wrapper_type;
+ /**
+ * A type mask from wrapper_type,
+ * in case there are differences in finalizing logic between types.
+ */
+ char wrapper_type_finalize;
+
+ char _pad[4];
+
+ /** Needed in case we need to lazily initialize the mesh. */
+ CustomData_MeshMasks cd_mask_extra;
+
} Mesh_Runtime;
typedef struct Mesh {
@@ -228,6 +242,15 @@ typedef struct TFace {
/* **************** MESH ********************* */
+/** #Mesh_Runtime.wrapper_type */
+typedef enum eMeshWrapperType {
+ /** Use mesh data (#Mesh.mvert,#Mesh.medge, #Mesh.mloop, #Mesh.mpoly). */
+ ME_WRAPPER_TYPE_MDATA = 0,
+ /** Use edit-mesh data (#Mesh.#edit_mesh, #Mesh_Runtime.edit_data). */
+ ME_WRAPPER_TYPE_BMESH = 1,
+ /* ME_WRAPPER_TYPE_SUBD = 2, */ /* TODO */
+} eMeshWrapperType;
+
/* texflag */
enum {
ME_AUTOSPACE = 1,
@@ -248,9 +271,9 @@ enum {
/* we cant have both flags enabled at once,
* flags defined in DNA_scene_types.h */
#define ME_EDIT_PAINT_SEL_MODE(_me) \
- ((_me->editflag & ME_EDIT_PAINT_FACE_SEL) ? \
+ (((_me)->editflag & ME_EDIT_PAINT_FACE_SEL) ? \
SCE_SELECT_FACE : \
- (_me->editflag & ME_EDIT_PAINT_VERT_SEL) ? SCE_SELECT_VERTEX : 0)
+ ((_me)->editflag & ME_EDIT_PAINT_VERT_SEL) ? SCE_SELECT_VERTEX : 0)
/* me->flag */
enum {
diff --git a/source/blender/makesdna/DNA_meshdata_types.h b/source/blender/makesdna/DNA_meshdata_types.h
index f48024cd55a..04deecde43e 100644
--- a/source/blender/makesdna/DNA_meshdata_types.h
+++ b/source/blender/makesdna/DNA_meshdata_types.h
@@ -344,6 +344,10 @@ typedef struct MLoopCol {
unsigned char r, g, b, a;
} MLoopCol;
+typedef struct MPropCol {
+ float col[4];
+} MPropCol;
+
/** Multi-Resolution loop data. */
typedef struct MDisps {
/* Strange bug in SDNA: if disps pointer comes first, it fails to see totdisp */
diff --git a/source/blender/makesdna/DNA_modifier_types.h b/source/blender/makesdna/DNA_modifier_types.h
index 5213dba6c79..13972ae032d 100644
--- a/source/blender/makesdna/DNA_modifier_types.h
+++ b/source/blender/makesdna/DNA_modifier_types.h
@@ -94,6 +94,7 @@ typedef enum ModifierType {
eModifierType_WeightedNormal = 54,
eModifierType_Weld = 55,
eModifierType_Fluid = 56,
+ eModifierType_Simulation = 57,
NUM_MODIFIER_TYPES,
} ModifierType;
@@ -138,6 +139,7 @@ typedef struct MappingInfoModifierData {
struct Tex *texture;
struct Object *map_object;
+ char map_bone[64];
/** MAX_CUSTOMDATA_LAYER_NAME. */
char uvlayer_name[64];
int uvlayer_tmp;
@@ -362,6 +364,7 @@ enum {
MOD_MIR_BISECT_FLIP_AXIS_X = (1 << 11),
MOD_MIR_BISECT_FLIP_AXIS_Y = (1 << 12),
MOD_MIR_BISECT_FLIP_AXIS_Z = (1 << 13),
+ MOD_MIR_MIRROR_UDIM = (1 << 14),
};
typedef struct EdgeSplitModifierData {
@@ -451,23 +454,23 @@ enum {
/* BevelModifierData->face_str_mode */
enum {
- MOD_BEVEL_FACE_STRENGTH_NONE,
- MOD_BEVEL_FACE_STRENGTH_NEW,
- MOD_BEVEL_FACE_STRENGTH_AFFECTED,
- MOD_BEVEL_FACE_STRENGTH_ALL,
+ MOD_BEVEL_FACE_STRENGTH_NONE = 0,
+ MOD_BEVEL_FACE_STRENGTH_NEW = 1,
+ MOD_BEVEL_FACE_STRENGTH_AFFECTED = 2,
+ MOD_BEVEL_FACE_STRENGTH_ALL = 3,
};
/* BevelModifier->miter_inner and ->miter_outer */
enum {
- MOD_BEVEL_MITER_SHARP,
- MOD_BEVEL_MITER_PATCH,
- MOD_BEVEL_MITER_ARC,
+ MOD_BEVEL_MITER_SHARP = 0,
+ MOD_BEVEL_MITER_PATCH = 1,
+ MOD_BEVEL_MITER_ARC = 2,
};
/* BevelModifier->vmesh_method */
enum {
- MOD_BEVEL_VMESH_ADJ,
- MOD_BEVEL_VMESH_CUTOFF,
+ MOD_BEVEL_VMESH_ADJ = 0,
+ MOD_BEVEL_VMESH_CUTOFF = 1,
};
typedef struct FluidModifierData {
@@ -496,6 +499,7 @@ typedef struct DisplaceModifierData {
/* keep in sync with MappingInfoModifierData */
struct Tex *texture;
struct Object *map_object;
+ char map_bone[64];
/** MAX_CUSTOMDATA_LAYER_NAME. */
char uvlayer_name[64];
int uvlayer_tmp;
@@ -592,10 +596,10 @@ enum {
};
enum {
- MOD_DECIM_MODE_COLLAPSE,
- MOD_DECIM_MODE_UNSUBDIV,
+ MOD_DECIM_MODE_COLLAPSE = 0,
+ MOD_DECIM_MODE_UNSUBDIV = 1,
/** called planar in the UI */
- MOD_DECIM_MODE_DISSOLVE,
+ MOD_DECIM_MODE_DISSOLVE = 2,
};
typedef struct SmoothModifierData {
@@ -651,6 +655,7 @@ typedef struct WaveModifierData {
/* keep in sync with MappingInfoModifierData */
struct Tex *texture;
struct Object *map_object;
+ char map_bone[64];
/** MAX_CUSTOMDATA_LAYER_NAME. */
char uvlayer_name[64];
int uvlayer_tmp;
@@ -1148,6 +1153,8 @@ typedef struct SolidifyModifierData {
/** Name of vertex group to use, MAX_VGROUP_NAME. */
char defgrp_name[64];
+ char shell_defgrp_name[64];
+ char rim_defgrp_name[64];
/** New surface offset leve.l*/
float offset;
/** Midpoint of the offset . */
@@ -1170,6 +1177,9 @@ typedef struct SolidifyModifierData {
int flag;
short mat_ofs;
short mat_ofs_rim;
+
+ float merge_tolerance;
+ float bevel_convex;
} SolidifyModifierData;
/** #SolidifyModifierData.flag */
@@ -1184,6 +1194,7 @@ enum {
MOD_SOLIDIFY_FLIP = (1 << 5),
MOD_SOLIDIFY_NOSHELL = (1 << 6),
MOD_SOLIDIFY_OFFSET_ANGLE_CLAMP = (1 << 7),
+ MOD_SOLIDIFY_NONMANIFOLD_FLAT_FACES = (1 << 8),
};
/** #SolidifyModifierData.mode */
@@ -1316,6 +1327,7 @@ typedef struct WarpModifierData {
/* keep in sync with MappingInfoModifierData */
struct Tex *texture;
struct Object *map_object;
+ char map_bone[64];
/** MAX_CUSTOMDATA_LAYER_NAME. */
char uvlayer_name[64];
int uvlayer_tmp;
@@ -1324,6 +1336,11 @@ typedef struct WarpModifierData {
struct Object *object_from;
struct Object *object_to;
+ /** Optional name of bone target, MAX_ID_NAME-2. */
+ char bone_from[64];
+ /** Optional name of bone target, MAX_ID_NAME-2. */
+ char bone_to[64];
+
struct CurveMapping *curfalloff;
/** Optional vertexgroup name, MAX_VGROUP_NAME. */
char defgrp_name[64];
@@ -1386,6 +1403,8 @@ typedef struct WeightVGEditModifierData {
struct Tex *mask_texture;
/** Name of the map object. */
struct Object *mask_tex_map_obj;
+ /** Name of the map bone. */
+ char mask_tex_map_bone[64];
/** How to map the texture (using MOD_DISP_MAP_* enums). */
int mask_tex_mapping;
/** Name of the UV map. MAX_CUSTOMDATA_LAYER_NAME. */
@@ -1397,7 +1416,7 @@ typedef struct WeightVGEditModifierData {
/* WeightVGEdit flags. */
enum {
- /* (1 << 0) is free for future use! */
+ MOD_WVG_EDIT_WEIGHTS_NORMALIZE = (1 << 0),
MOD_WVG_INVERT_FALLOFF = (1 << 1),
MOD_WVG_EDIT_INVERT_VGROUP_MASK = (1 << 2),
/** Add vertices with higher weight than threshold to vgroup. */
@@ -1437,6 +1456,8 @@ typedef struct WeightVGMixModifierData {
struct Tex *mask_texture;
/** Name of the map object. */
struct Object *mask_tex_map_obj;
+ /** Name of the map bone. */
+ char mask_tex_map_bone[64];
/** How to map the texture!. */
int mask_tex_mapping;
/** Name of the UV map. MAX_CUSTOMDATA_LAYER_NAME. */
@@ -1483,6 +1504,9 @@ enum {
/* WeightVGMix->flag */
enum {
MOD_WVG_MIX_INVERT_VGROUP_MASK = (1 << 0),
+ MOD_WVG_MIX_WEIGHTS_NORMALIZE = (1 << 1),
+ MOD_WVG_MIX_INVERT_VGROUP_A = (1 << 2),
+ MOD_WVG_MIX_INVERT_VGROUP_B = (1 << 3),
};
typedef struct WeightVGProximityModifierData {
@@ -1511,6 +1535,8 @@ typedef struct WeightVGProximityModifierData {
struct Tex *mask_texture;
/** Name of the map object. */
struct Object *mask_tex_map_obj;
+ /** Name of the map bone. */
+ char mask_tex_map_bone[64];
/** How to map the texture!. */
int mask_tex_mapping;
/** Name of the UV Map. MAX_CUSTOMDATA_LAYER_NAME. */
@@ -1543,6 +1569,7 @@ enum {
MOD_WVG_PROXIMITY_GEOM_FACES = (1 << 2),
MOD_WVG_PROXIMITY_INVERT_VGROUP_MASK = (1 << 3),
MOD_WVG_PROXIMITY_INVERT_FALLOFF = (1 << 4),
+ MOD_WVG_PROXIMITY_WEIGHTS_NORMALIZE = (1 << 3),
};
/* Defines common to all WeightVG modifiers. */
@@ -1601,6 +1628,8 @@ typedef enum eRemeshModifierMode {
MOD_REMESH_MASS_POINT = 1,
/* keeps sharp edges */
MOD_REMESH_SHARP_FEATURES = 2,
+ /* Voxel remesh */
+ MOD_REMESH_VOXEL = 3,
} eRemeshModifierMode;
typedef struct RemeshModifierData {
@@ -1616,10 +1645,13 @@ typedef struct RemeshModifierData {
/* octree depth */
char depth;
-
char flag;
char mode;
char _pad;
+
+ /* OpenVDB Voxel remesh properties. */
+ float voxel_size;
+ float adaptivity;
} RemeshModifierData;
/* Skin modifier */
@@ -1668,15 +1700,15 @@ enum {
/* Triangulate methods - NGons */
enum {
MOD_TRIANGULATE_NGON_BEAUTY = 0,
- MOD_TRIANGULATE_NGON_EARCLIP,
+ MOD_TRIANGULATE_NGON_EARCLIP = 1,
};
/* Triangulate methods - Quads */
enum {
MOD_TRIANGULATE_QUAD_BEAUTY = 0,
- MOD_TRIANGULATE_QUAD_FIXED,
- MOD_TRIANGULATE_QUAD_ALTERNATE,
- MOD_TRIANGULATE_QUAD_SHORTEDGE,
+ MOD_TRIANGULATE_QUAD_FIXED = 1,
+ MOD_TRIANGULATE_QUAD_ALTERNATE = 2,
+ MOD_TRIANGULATE_QUAD_SHORTEDGE = 3,
};
typedef struct LaplacianSmoothModifierData {
@@ -2039,12 +2071,16 @@ typedef struct SurfaceDeformModifierData {
unsigned int numverts, numpoly;
int flags;
float mat[4][4];
+ float strength;
+ char _pad[4];
+ char defgrp_name[64];
} SurfaceDeformModifierData;
/* Surface Deform modifier flags */
enum {
/* This indicates "do bind on next modifier evaluation" as well as "is bound". */
MOD_SDEF_BIND = (1 << 0),
+ MOD_SDEF_INVERT_VGROUP = (1 << 1)
/* MOD_SDEF_USES_LOOPTRI = (1 << 1), */ /* UNUSED */
/* MOD_SDEF_HAS_CONCAVE = (1 << 2), */ /* UNUSED */
@@ -2087,6 +2123,13 @@ enum {
#define MOD_MESHSEQ_READ_ALL \
(MOD_MESHSEQ_READ_VERT | MOD_MESHSEQ_READ_POLY | MOD_MESHSEQ_READ_UV | MOD_MESHSEQ_READ_COLOR)
+typedef struct SimulationModifierData {
+ ModifierData modifier;
+
+ struct Simulation *simulation;
+ char data_path[64];
+} SimulationModifierData;
+
#ifdef __cplusplus
}
#endif
diff --git a/source/blender/makesdna/DNA_movieclip_types.h b/source/blender/makesdna/DNA_movieclip_types.h
index 557e069a4a6..94d11095108 100644
--- a/source/blender/makesdna/DNA_movieclip_types.h
+++ b/source/blender/makesdna/DNA_movieclip_types.h
@@ -24,14 +24,14 @@
#ifndef __DNA_MOVIECLIP_TYPES_H__
#define __DNA_MOVIECLIP_TYPES_H__
-#ifdef __cplusplus
-extern "C" {
-#endif
-
#include "DNA_ID.h"
#include "DNA_color_types.h" /* for color management */
#include "DNA_tracking_types.h"
+#ifdef __cplusplus
+extern "C" {
+#endif
+
struct AnimData;
struct ImBuf;
struct MovieClipProxy;
diff --git a/source/blender/makesdna/DNA_node_types.h b/source/blender/makesdna/DNA_node_types.h
index 8029e8ebc13..4ff0e531168 100644
--- a/source/blender/makesdna/DNA_node_types.h
+++ b/source/blender/makesdna/DNA_node_types.h
@@ -154,6 +154,12 @@ typedef enum eNodeSocketDatatype {
__SOCK_MESH = 5, /* deprecated */
SOCK_INT = 6,
SOCK_STRING = 7,
+ SOCK_OBJECT = 8,
+ SOCK_IMAGE = 9,
+ SOCK_EMITTERS = 10,
+ SOCK_EVENTS = 11,
+ SOCK_FORCES = 12,
+ SOCK_CONTROL_FLOW = 13,
} eNodeSocketDatatype;
/* socket shape */
@@ -498,6 +504,7 @@ typedef struct bNodeTree {
#define NTREE_SHADER 0
#define NTREE_COMPOSIT 1
#define NTREE_TEXTURE 2
+#define NTREE_SIMULATION 3
/* ntree->init, flag */
#define NTREE_TYPE_INIT 1
@@ -565,6 +572,14 @@ typedef struct bNodeSocketValueString {
char value[1024];
} bNodeSocketValueString;
+typedef struct bNodeSocketValueObject {
+ struct Object *value;
+} bNodeSocketValueObject;
+
+typedef struct bNodeSocketValueImage {
+ struct Image *value;
+} bNodeSocketValueImage;
+
/* data structs, for node->storage */
enum {
CMP_NODE_MASKTYPE_ADD = 0,
@@ -1293,6 +1308,23 @@ enum {
NODE_VECTOR_MATH_TANGENT = 23,
};
+/* Boolean math node operations. */
+enum {
+ NODE_BOOLEAN_MATH_AND = 0,
+ NODE_BOOLEAN_MATH_OR = 1,
+ NODE_BOOLEAN_MATH_NOT = 2,
+};
+
+/* Float compare node operations. */
+enum {
+ NODE_FLOAT_COMPARE_LESS_THAN = 0,
+ NODE_FLOAT_COMPARE_LESS_EQUAL = 1,
+ NODE_FLOAT_COMPARE_GREATER_THAN = 2,
+ NODE_FLOAT_COMPARE_GREATER_EQUAL = 3,
+ NODE_FLOAT_COMPARE_EQUAL = 4,
+ NODE_FLOAT_COMPARE_NOT_EQUAL = 5,
+};
+
/* Clamp node types. */
enum {
NODE_CLAMP_MINMAX = 0,
@@ -1385,4 +1417,16 @@ typedef enum NodeShaderOutputTarget {
SHD_OUTPUT_CYCLES = 2,
} NodeShaderOutputTarget;
+/* Particle Time Step Event node */
+typedef enum NodeSimParticleTimeStepEventType {
+ NODE_PARTICLE_TIME_STEP_EVENT_BEGIN = 0,
+ NODE_PARTICLE_TIME_STEP_EVENT_END = 1,
+} NodeSimParticleTimeStepEventType;
+
+/* Simulation Time node */
+typedef enum NodeSimInputTimeType {
+ NODE_SIM_INPUT_SIMULATION_TIME = 0,
+ NODE_SIM_INPUT_SCENE_TIME = 1,
+} NodeSimInputTimeType;
+
#endif
diff --git a/source/blender/makesdna/DNA_object_force_types.h b/source/blender/makesdna/DNA_object_force_types.h
index 88c712b5b28..85520f5a930 100644
--- a/source/blender/makesdna/DNA_object_force_types.h
+++ b/source/blender/makesdna/DNA_object_force_types.h
@@ -24,13 +24,13 @@
#ifndef __DNA_OBJECT_FORCE_TYPES_H__
#define __DNA_OBJECT_FORCE_TYPES_H__
+#include "DNA_defs.h"
+#include "DNA_listBase.h"
+
#ifdef __cplusplus
extern "C" {
#endif
-#include "DNA_defs.h"
-#include "DNA_listBase.h"
-
/* pd->forcefield: Effector Fields types */
typedef enum ePFieldType {
/** (this is used for general effector weight). */
@@ -59,9 +59,10 @@ typedef enum ePFieldType {
PFIELD_TURBULENCE = 11,
/** Linear & quadratic drag. */
PFIELD_DRAG = 12,
- /** Force based on smoke simulation air flow. */
- PFIELD_SMOKEFLOW = 13,
+ /** Force based on fluid simulation velocities. */
+ PFIELD_FLUIDFLOW = 13,
+ /* Keep last. */
NUM_PFIELD_TYPES,
} ePFieldType;
diff --git a/source/blender/makesdna/DNA_object_types.h b/source/blender/makesdna/DNA_object_types.h
index 1a76d32dc2c..47e6db835c9 100644
--- a/source/blender/makesdna/DNA_object_types.h
+++ b/source/blender/makesdna/DNA_object_types.h
@@ -462,6 +462,7 @@ enum {
OB_VOLUME = 29,
+ /* Keep last. */
OB_TYPE_MAX,
};
diff --git a/source/blender/makesdna/DNA_rigidbody_types.h b/source/blender/makesdna/DNA_rigidbody_types.h
index 5c514ef04e1..7ad50dc04de 100644
--- a/source/blender/makesdna/DNA_rigidbody_types.h
+++ b/source/blender/makesdna/DNA_rigidbody_types.h
@@ -172,7 +172,7 @@ typedef enum eRigidBodyOb_Type {
/* active geometry participant in simulation. is directly controlled by sim */
RBO_TYPE_ACTIVE = 0,
/* passive geometry participant in simulation. is directly controlled by animsys */
- RBO_TYPE_PASSIVE,
+ RBO_TYPE_PASSIVE = 1,
} eRigidBodyOb_Type;
/* Flags for RigidBodyOb */
@@ -200,18 +200,18 @@ typedef enum eRigidBody_Shape {
/** Simple box (i.e. bounding box). */
RB_SHAPE_BOX = 0,
/** Sphere. */
- RB_SHAPE_SPHERE,
+ RB_SHAPE_SPHERE = 1,
/** Rounded "pill" shape (i.e. calcium tablets). */
- RB_SHAPE_CAPSULE,
+ RB_SHAPE_CAPSULE = 2,
/** Cylinder (i.e. pringles can). */
- RB_SHAPE_CYLINDER,
+ RB_SHAPE_CYLINDER = 3,
/** Cone (i.e. party hat). */
- RB_SHAPE_CONE,
+ RB_SHAPE_CONE = 4,
/** Convex hull (minimal shrinkwrap encompassing all verts). */
- RB_SHAPE_CONVEXH,
+ RB_SHAPE_CONVEXH = 5,
/** Triangulated mesh. */
- RB_SHAPE_TRIMESH,
+ RB_SHAPE_TRIMESH = 6,
/* concave mesh approximated using primitives */
// RB_SHAPE_COMPOUND,
@@ -221,9 +221,9 @@ typedef enum eRigidBody_MeshSource {
/* base mesh */
RBO_MESH_BASE = 0,
/* only deformations */
- RBO_MESH_DEFORM,
+ RBO_MESH_DEFORM = 1,
/* final derived mesh */
- RBO_MESH_FINAL,
+ RBO_MESH_FINAL = 2,
} eRigidBody_MeshSource;
/* ******************************** */
@@ -306,34 +306,34 @@ typedef enum eRigidBodyCon_Type {
/** lets bodies rotate around a specified point */
RBC_TYPE_POINT = 0,
/** lets bodies rotate around a specified axis */
- RBC_TYPE_HINGE,
+ RBC_TYPE_HINGE = 1,
/** simulates wheel suspension */
- /* RBC_TYPE_HINGE2, */ /* UNUSED */
+ /* RBC_TYPE_HINGE2 = 2, */ /* UNUSED */
/** restricts movent to a specified axis */
- RBC_TYPE_SLIDER,
+ RBC_TYPE_SLIDER = 3,
/** lets object rotate within a specified cone */
- /* RBC_TYPE_CONE_TWIST, */ /* UNUSED */
+ /* RBC_TYPE_CONE_TWIST = 4, */ /* UNUSED */
/** allows user to specify constraint axes */
- RBC_TYPE_6DOF,
+ RBC_TYPE_6DOF = 5,
/** like 6DOF but has springs */
- RBC_TYPE_6DOF_SPRING,
+ RBC_TYPE_6DOF_SPRING = 6,
/** simulates a universal joint */
- /* RBC_TYPE_UNIVERSAL, */ /* UNUSED */
+ /* RBC_TYPE_UNIVERSAL = 7, */ /* UNUSED */
/** glues two bodies together */
- RBC_TYPE_FIXED,
+ RBC_TYPE_FIXED = 8,
/** similar to slider but also allows rotation around slider axis */
- RBC_TYPE_PISTON,
+ RBC_TYPE_PISTON = 9,
/** Simplified spring constraint with only once axis that's
* automatically placed between the connected bodies */
- /* RBC_TYPE_SPRING, */ /* UNUSED */
+ /* RBC_TYPE_SPRING = 10, */ /* UNUSED */
/** dirves bodies by applying linear and angular forces */
- RBC_TYPE_MOTOR,
+ RBC_TYPE_MOTOR = 11,
} eRigidBodyCon_Type;
/* Spring implementation type for RigidBodyOb */
typedef enum eRigidBodyCon_SpringType {
RBC_SPRING_TYPE1 = 0, /* btGeneric6DofSpringConstraint */
- RBC_SPRING_TYPE2, /* btGeneric6DofSpring2Constraint */
+ RBC_SPRING_TYPE2 = 1, /* btGeneric6DofSpring2Constraint */
} eRigidBodyCon_SpringType;
/* Flags for RigidBodyCon */
diff --git a/source/blender/makesdna/DNA_scene_types.h b/source/blender/makesdna/DNA_scene_types.h
index c1a6265b53b..c50e48982b3 100644
--- a/source/blender/makesdna/DNA_scene_types.h
+++ b/source/blender/makesdna/DNA_scene_types.h
@@ -29,10 +29,6 @@
/* XXX, temp feature - campbell */
#define DURIAN_CAMERA_SWITCH
-#ifdef __cplusplus
-extern "C" {
-#endif
-
#include "DNA_ID.h"
#include "DNA_collection_types.h"
#include "DNA_color_types.h" /* color management */
@@ -46,6 +42,10 @@ extern "C" {
#include "DNA_vec_types.h"
#include "DNA_view3d_types.h"
+#ifdef __cplusplus
+extern "C" {
+#endif
+
struct AnimData;
struct Brush;
struct Collection;
@@ -99,19 +99,19 @@ typedef struct AviCodecData {
} AviCodecData;
typedef enum eFFMpegPreset {
- FFM_PRESET_NONE,
+ FFM_PRESET_NONE = 0,
#ifdef DNA_DEPRECATED_ALLOW
/* Previously used by h.264 to control encoding speed vs. file size. */
- FFM_PRESET_ULTRAFAST, /* DEPRECATED */
- FFM_PRESET_SUPERFAST, /* DEPRECATED */
- FFM_PRESET_VERYFAST, /* DEPRECATED */
- FFM_PRESET_FASTER, /* DEPRECATED */
- FFM_PRESET_FAST, /* DEPRECATED */
- FFM_PRESET_MEDIUM, /* DEPRECATED */
- FFM_PRESET_SLOW, /* DEPRECATED */
- FFM_PRESET_SLOWER, /* DEPRECATED */
- FFM_PRESET_VERYSLOW, /* DEPRECATED */
+ FFM_PRESET_ULTRAFAST = 1, /* DEPRECATED */
+ FFM_PRESET_SUPERFAST = 2, /* DEPRECATED */
+ FFM_PRESET_VERYFAST = 3, /* DEPRECATED */
+ FFM_PRESET_FASTER = 4, /* DEPRECATED */
+ FFM_PRESET_FAST = 5, /* DEPRECATED */
+ FFM_PRESET_MEDIUM = 6, /* DEPRECATED */
+ FFM_PRESET_SLOW = 7, /* DEPRECATED */
+ FFM_PRESET_SLOWER = 8, /* DEPRECATED */
+ FFM_PRESET_VERYSLOW = 9, /* DEPRECATED */
#endif
/* Used by WEBM/VP9 and h.264 to control encoding speed vs. file size.
@@ -121,9 +121,9 @@ typedef enum eFFMpegPreset {
/** the default and recommended for most applications */
FFM_PRESET_GOOD = 10,
/** recommended if you have lots of time and want the best compression efficiency */
- FFM_PRESET_BEST,
+ FFM_PRESET_BEST = 11,
/** recommended for live / fast encoding */
- FFM_PRESET_REALTIME,
+ FFM_PRESET_REALTIME = 12,
} eFFMpegPreset;
/* Mapping from easily-understandable descriptions to CRF values.
@@ -555,13 +555,14 @@ typedef struct BakeData {
short margin, flag;
float cage_extrusion;
+ float max_ray_distance;
int pass_filter;
char normal_swizzle[3];
char normal_space;
char save_mode;
- char _pad[3];
+ char _pad[7];
struct Object *cage_object;
} BakeData;
@@ -731,13 +732,12 @@ typedef struct RenderData {
char seq_rend_type;
/** Flag use for sequence render/draw. */
char seq_flag;
- char _pad5[5];
+ char _pad5[7];
/* render simplify */
short simplify_subsurf;
short simplify_subsurf_render;
short simplify_gpencil;
- short simplify_smoke_ignore_highres;
float simplify_particles;
float simplify_particles_render;
@@ -908,8 +908,6 @@ typedef struct ImagePaintSettings {
/** Mode used for texture painting. */
int mode;
- /** Wm handle. */
- void *paintcursor;
/** Workaround until we support true layer masks. */
struct Image *stencil;
/** Clone layer for image mode for projective texture painting. */
@@ -971,6 +969,8 @@ typedef struct Sculpt {
// float pivot[3]; XXX not used?
int flags;
+ int automasking_flags;
+
/* Control tablet input */
// char tablet_size, tablet_strength; XXX not used?
int radial_symm[3];
@@ -988,7 +988,6 @@ typedef struct Sculpt {
/** Constant detail resolution (Blender unit / constant_detail). */
float constant_detail;
float detail_percent;
- char _pad[4];
struct Object *gravity_object;
} Sculpt;
@@ -1644,6 +1643,11 @@ typedef struct SceneEEVEE {
float light_threshold;
} SceneEEVEE;
+typedef struct SceneGpencil {
+ float smaa_threshold;
+ char _pad[4];
+} SceneGpencil;
+
/* *************************************************************** */
/* Scene ID-Block */
@@ -1775,6 +1779,7 @@ typedef struct Scene {
struct SceneDisplay display;
struct SceneEEVEE eevee;
+ struct SceneGpencil grease_pencil_settings;
} Scene;
/* **************** RENDERDATA ********************* */
@@ -2137,6 +2142,7 @@ typedef enum ePaintFlags {
PAINT_FAST_NAVIGATE = (1 << 1),
PAINT_SHOW_BRUSH_ON_SURFACE = (1 << 2),
PAINT_USE_CAVITY_MASK = (1 << 3),
+ PAINT_SCULPT_DELAY_UPDATES = (1 << 4),
} ePaintFlags;
/* Paint.symmetry_flags
@@ -2193,14 +2199,14 @@ typedef enum eSculptFlags {
/* ImagePaintSettings.mode */
typedef enum eImagePaintMode {
- IMAGEPAINT_MODE_MATERIAL, /* detect texture paint slots from the material */
- IMAGEPAINT_MODE_IMAGE, /* select texture paint image directly */
+ IMAGEPAINT_MODE_MATERIAL = 0, /* detect texture paint slots from the material */
+ IMAGEPAINT_MODE_IMAGE = 1, /* select texture paint image directly */
} eImagePaintMode;
/* ImagePaintSettings.interp */
enum {
IMAGEPAINT_INTERP_LINEAR = 0,
- IMAGEPAINT_INTERP_CLOSEST,
+ IMAGEPAINT_INTERP_CLOSEST = 1,
};
/* ImagePaintSettings.flag */
@@ -2300,17 +2306,17 @@ typedef enum eGPencil_Selectmode_types {
/* ToolSettings.gpencil_guide_types */
typedef enum eGPencil_GuideTypes {
GP_GUIDE_CIRCULAR = 0,
- GP_GUIDE_RADIAL,
- GP_GUIDE_PARALLEL,
- GP_GUIDE_GRID,
- GP_GUIDE_ISO,
+ GP_GUIDE_RADIAL = 1,
+ GP_GUIDE_PARALLEL = 2,
+ GP_GUIDE_GRID = 3,
+ GP_GUIDE_ISO = 4,
} eGPencil_GuideTypes;
/* ToolSettings.gpencil_guide_references */
typedef enum eGPencil_Guide_Reference {
GP_GUIDE_REF_CURSOR = 0,
- GP_GUIDE_REF_CUSTOM,
- GP_GUIDE_REF_OBJECT,
+ GP_GUIDE_REF_CUSTOM = 1,
+ GP_GUIDE_REF_OBJECT = 2,
} eGPencil_Guide_Reference;
/* ToolSettings.particle flag */
diff --git a/source/blender/makesdna/DNA_screen_types.h b/source/blender/makesdna/DNA_screen_types.h
index 9a59b69604d..07cba2bad1c 100644
--- a/source/blender/makesdna/DNA_screen_types.h
+++ b/source/blender/makesdna/DNA_screen_types.h
@@ -132,7 +132,9 @@ typedef struct ScrAreaMap {
typedef struct Panel_Runtime {
/* Applied to Panel.ofsx, but saved separately so we can track changes between redraws. */
int region_ofsx;
- char _pad[4];
+
+ /* For instanced panels: Index of the list item the panel corresponds to. */
+ int list_index;
} Panel_Runtime;
/** The part from uiBlock that needs saved in file. */
@@ -306,8 +308,8 @@ enum GlobalAreaFlag {
};
typedef enum GlobalAreaAlign {
- GLOBAL_AREA_ALIGN_TOP,
- GLOBAL_AREA_ALIGN_BOTTOM,
+ GLOBAL_AREA_ALIGN_TOP = 0,
+ GLOBAL_AREA_ALIGN_BOTTOM = 1,
} GlobalAreaAlign;
typedef struct ScrArea_Runtime {
@@ -531,6 +533,8 @@ enum {
PNL_OVERLAP = (1 << 4),
PNL_PIN = (1 << 5),
PNL_POPOVER = (1 << 6),
+ /** The panel has been drag-drop reordered and the instanced panel list needs to be rebuilt. */
+ PNL_INSTANCED_LIST_ORDER_CHANGED = (1 << 7),
};
/** #Panel.snap - for snapping to screen edges */
@@ -543,9 +547,17 @@ enum {
/* #define PNL_SNAP_DIST 9.0 */
/* paneltype flag */
-#define PNL_DEFAULT_CLOSED 1
-#define PNL_NO_HEADER 2
-#define PNL_LAYOUT_VERT_BAR 4
+enum {
+ PNL_DEFAULT_CLOSED = (1 << 0),
+ PNL_NO_HEADER = (1 << 1),
+ /** Makes buttons in the header shrink/stretch to fill full layout width. */
+ PNL_LAYOUT_HEADER_EXPAND = (1 << 2),
+ PNL_LAYOUT_VERT_BAR = (1 << 3),
+ /** This panel type represents data external to the UI. */
+ PNL_INSTANCED = (1 << 4),
+ /** Draw panel like a box widget. */
+ PNL_DRAW_BOX = (1 << 6),
+};
/* Fallback panel category (only for old scripts which need updating) */
#define PNL_CATEGORY_FALLBACK "Misc"
diff --git a/source/blender/makesdna/DNA_sequence_types.h b/source/blender/makesdna/DNA_sequence_types.h
index 17b3528aadf..9fee839f979 100644
--- a/source/blender/makesdna/DNA_sequence_types.h
+++ b/source/blender/makesdna/DNA_sequence_types.h
@@ -468,6 +468,7 @@ typedef struct SequencerScopes {
#define SEQ_SPEED_INTEGRATE (1 << 0)
#define SEQ_SPEED_UNUSED_1 (1 << 1) /* cleared */
#define SEQ_SPEED_COMPRESS_IPO_Y (1 << 2)
+#define SEQ_SPEED_USE_INTERPOLATION (1 << 3)
/* ***************** SEQUENCE ****************** */
#define SEQ_NAME_MAXSTR 64
@@ -634,7 +635,7 @@ enum {
seqModifierType_Mask = 5,
seqModifierType_WhiteBalance = 6,
seqModifierType_Tonemap = 7,
-
+ /* Keep last. */
NUM_SEQUENCE_MODIFIER_TYPES,
};
diff --git a/source/blender/makesdna/DNA_shader_fx_types.h b/source/blender/makesdna/DNA_shader_fx_types.h
index e0931d8cac3..18a4e8655a3 100644
--- a/source/blender/makesdna/DNA_shader_fx_types.h
+++ b/source/blender/makesdna/DNA_shader_fx_types.h
@@ -42,6 +42,7 @@ typedef enum ShaderFxType {
eShaderFxType_Colorize = 8,
eShaderFxType_Shadow = 9,
eShaderFxType_Glow = 10,
+ /* Keep last. */
NUM_SHADER_FX_TYPES,
} ShaderFxType;
diff --git a/source/blender/makesdna/DNA_simulation_defaults.h b/source/blender/makesdna/DNA_simulation_defaults.h
new file mode 100644
index 00000000000..b4cecd861a9
--- /dev/null
+++ b/source/blender/makesdna/DNA_simulation_defaults.h
@@ -0,0 +1,40 @@
+/*
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+
+/** \file
+ * \ingroup DNA
+ */
+
+#ifndef __DNA_SIMULATION_DEFAULTS_H__
+#define __DNA_SIMULATION_DEFAULTS_H__
+
+/* Struct members on own line. */
+/* clang-format off */
+
+/* -------------------------------------------------------------------- */
+/** \name Simulation Struct
+ * \{ */
+
+#define _DNA_DEFAULT_Simulation \
+ { \
+ .flag = 0, \
+ }
+
+/** \} */
+
+/* clang-format on */
+
+#endif /* __DNA_SIMULATION_DEFAULTS_H__ */
diff --git a/source/blender/makesdna/DNA_simulation_types.h b/source/blender/makesdna/DNA_simulation_types.h
new file mode 100644
index 00000000000..113c301bb9e
--- /dev/null
+++ b/source/blender/makesdna/DNA_simulation_types.h
@@ -0,0 +1,41 @@
+/*
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+
+/** \file
+ * \ingroup DNA
+ */
+
+#ifndef __DNA_SIMULATION_TYPES_H__
+#define __DNA_SIMULATION_TYPES_H__
+
+#include "DNA_ID.h"
+
+typedef struct Simulation {
+ ID id;
+ struct AnimData *adt; /* animation data (must be immediately after id) */
+
+ struct bNodeTree *nodetree;
+
+ int flag;
+ int _pad1[1];
+} Simulation;
+
+/* Simulation.flag */
+enum {
+ SIM_DS_EXPAND = (1 << 0),
+};
+
+#endif /* __DNA_SIMULATION_TYPES_H__ */
diff --git a/source/blender/makesdna/DNA_sound_types.h b/source/blender/makesdna/DNA_sound_types.h
index 73f0e20efcb..04ac9d4e5be 100644
--- a/source/blender/makesdna/DNA_sound_types.h
+++ b/source/blender/makesdna/DNA_sound_types.h
@@ -26,9 +26,6 @@
#include "DNA_ID.h"
#include "DNA_defs.h"
-/* stupid... could easily be solved */
-#include "DNA_view2d_types.h"
-
struct Ipo;
struct PackedFile;
@@ -104,7 +101,7 @@ typedef enum eSound_Type {
} eSound_Type;
#endif
-/* bSound->flags */
+/** #bSound.flags */
enum {
#ifdef DNA_DEPRECATED_ALLOW
/* deprecated! used for sound actuator loading */
@@ -114,13 +111,11 @@ enum {
SOUND_FLAGS_MONO = (1 << 5),
};
-/* bSound->tags */
+/** #bSound.tags */
enum {
/* Do not free/reset waveform on sound load, only used by undo code. */
SOUND_TAGS_WAVEFORM_NO_RELOAD = 1 << 0,
SOUND_TAGS_WAVEFORM_LOADING = (1 << 6),
};
-/* to DNA_sound_types.h*/
-
-#endif
+#endif /* __DNA_SOUND_TYPES_H__ */
diff --git a/source/blender/makesdna/DNA_space_types.h b/source/blender/makesdna/DNA_space_types.h
index 3020e5a1708..31a8d967ccf 100644
--- a/source/blender/makesdna/DNA_space_types.h
+++ b/source/blender/makesdna/DNA_space_types.h
@@ -212,7 +212,7 @@ typedef enum eSpaceButtons_Context {
BCONTEXT_SHADERFX = 15,
BCONTEXT_OUTPUT = 16,
- /* always as last... */
+ /* Keep last. */
BCONTEXT_TOT,
} eSpaceButtons_Context;
@@ -606,7 +606,7 @@ typedef enum eSpaceSeq_Flag {
SEQ_DRAW_COLOR_SEPARATED = (1 << 2),
SEQ_SHOW_SAFE_MARGINS = (1 << 3),
SEQ_SHOW_GPENCIL = (1 << 4),
- /* SEQ_NO_DRAW_CFRANUM = (1 << 5), DEPRECATED */
+ SEQ_SHOW_FCURVES = (1 << 5),
SEQ_USE_ALPHA = (1 << 6), /* use RGBA display mode for preview */
SEQ_ALL_WAVEFORMS = (1 << 7), /* draw all waveforms */
SEQ_NO_WAVEFORMS = (1 << 8), /* draw no waveforms */
@@ -833,9 +833,10 @@ typedef enum eFileSel_Params_RenameFlag {
FILE_PARAMS_RENAME_POSTSCROLL_ACTIVE = 1 << 3,
} eFileSel_Params_RenameFlag;
-/* files in filesel list: file types
- * Note we could use mere values (instead of bitflags) for file types themselves,
- * but since we do not lack of bytes currently...
+/**
+ * Files in the file selector list: file types
+ * Note we could use mere values (instead of bit-flags) for file types themselves,
+ * but since we do not lack of bytes currently.
*/
typedef enum eFileSel_File_Types {
FILE_TYPE_BLENDER = (1 << 2),
@@ -1075,7 +1076,9 @@ typedef struct SpaceImage {
int flag;
char pixel_snap_mode;
- char _pad2[3];
+ char _pad2[7];
+
+ float uv_opacity;
int tile_grid_shape[2];
@@ -1718,7 +1721,7 @@ typedef enum eSpace_Type {
SPACE_TOPBAR = 21,
SPACE_STATUSBAR = 22,
- SPACE_TYPE_LAST = SPACE_STATUSBAR,
+#define SPACE_TYPE_LAST SPACE_STATUSBAR
} eSpace_Type;
/* use for function args */
diff --git a/source/blender/makesdna/DNA_tracking_types.h b/source/blender/makesdna/DNA_tracking_types.h
index ab9f3d07849..32a00cc25d1 100644
--- a/source/blender/makesdna/DNA_tracking_types.h
+++ b/source/blender/makesdna/DNA_tracking_types.h
@@ -70,6 +70,9 @@ typedef struct MovieTrackingCamera {
/* Division distortion model coefficients */
float division_k1, division_k2;
+
+ /* Nuke distortion model coefficients */
+ float nuke_k1, nuke_k2;
} MovieTrackingCamera;
typedef struct MovieTrackingMarker {
@@ -455,6 +458,7 @@ typedef struct MovieTracking {
enum {
TRACKING_DISTORTION_MODEL_POLYNOMIAL = 0,
TRACKING_DISTORTION_MODEL_DIVISION = 1,
+ TRACKING_DISTORTION_MODEL_NUKE = 2,
};
/* MovieTrackingCamera->units */
diff --git a/source/blender/makesdna/DNA_userdef_types.h b/source/blender/makesdna/DNA_userdef_types.h
index 54470dc59fc..63e7a90547e 100644
--- a/source/blender/makesdna/DNA_userdef_types.h
+++ b/source/blender/makesdna/DNA_userdef_types.h
@@ -618,10 +618,9 @@ typedef struct UserDef_FileSpaceData {
} UserDef_FileSpaceData;
typedef struct UserDef_Experimental {
- char use_undo_speedup;
- char use_menu_search;
+ char use_undo_legacy;
/** `makesdna` does not allow empty structs. */
- char _pad0[6];
+ char _pad0[7];
} UserDef_Experimental;
#define USER_EXPERIMENTAL_TEST(userdef, member) \
@@ -874,9 +873,11 @@ typedef struct UserDef {
int sequencer_disk_cache_compression; /* eUserpref_DiskCacheCompression */
int sequencer_disk_cache_size_limit;
short sequencer_disk_cache_flag;
-
char _pad5[2];
+ float collection_instance_empty_size;
+ char _pad10[4];
+
struct WalkNavigation walk_navigation;
/** The UI for the user preferences. */
@@ -1121,12 +1122,12 @@ typedef enum eAutokey_Flag {
typedef enum eUserpref_Translation_Flags {
USER_TR_TOOLTIPS = (1 << 0),
USER_TR_IFACE = (1 << 1),
- USER_TR_UNUSED_2 = (1 << 2), /* cleared */
- USER_TR_UNUSED_3 = (1 << 3), /* cleared */
- USER_TR_UNUSED_4 = (1 << 4), /* cleared */
- USER_DOTRANSLATE = (1 << 5),
- USER_TR_UNUSED_6 = (1 << 6), /* cleared */
- USER_TR_UNUSED_7 = (1 << 7), /* cleared */
+ USER_TR_UNUSED_2 = (1 << 2), /* cleared */
+ USER_TR_UNUSED_3 = (1 << 3), /* cleared */
+ USER_TR_UNUSED_4 = (1 << 4), /* cleared */
+ USER_DOTRANSLATE_DEPRECATED = (1 << 5), /* Deprecated in 2.83. */
+ USER_TR_UNUSED_6 = (1 << 6), /* cleared */
+ USER_TR_UNUSED_7 = (1 << 7), /* cleared */
USER_TR_NEWDATANAME = (1 << 8),
} eUserpref_Translation_Flags;
@@ -1188,7 +1189,7 @@ typedef enum eColorPicker_Types {
} eColorPicker_Types;
/**
- * Timecode display styles
+ * Time-code display styles.
* #UserDef.timecode_style
*/
typedef enum eTimecodeStyles {
@@ -1290,8 +1291,8 @@ typedef enum eUserpref_RenderDisplayType {
} eUserpref_RenderDisplayType;
typedef enum eUserpref_TempSpaceDisplayType {
- USER_TEMP_SPACE_DISPLAY_FULLSCREEN,
- USER_TEMP_SPACE_DISPLAY_WINDOW,
+ USER_TEMP_SPACE_DISPLAY_FULLSCREEN = 0,
+ USER_TEMP_SPACE_DISPLAY_WINDOW = 1,
} eUserpref_TempSpaceDisplayType;
typedef enum eUserpref_EmulateMMBMod {
@@ -1305,6 +1306,13 @@ typedef enum eUserpref_DiskCacheCompression {
USER_SEQ_DISK_CACHE_COMPRESSION_HIGH = 2,
} eUserpref_DiskCacheCompression;
+/* Locale Ids. Auto will try to get local from OS. Our default is English though. */
+/** #UserDef.language */
+enum {
+ ULANGUAGE_AUTO = 0,
+ ULANGUAGE_ENGLISH = 1,
+};
+
#ifdef __cplusplus
}
#endif
diff --git a/source/blender/makesdna/DNA_view3d_defaults.h b/source/blender/makesdna/DNA_view3d_defaults.h
index afade37d0c8..10eadf368ef 100644
--- a/source/blender/makesdna/DNA_view3d_defaults.h
+++ b/source/blender/makesdna/DNA_view3d_defaults.h
@@ -64,8 +64,8 @@
.edit_flag = V3D_OVERLAY_EDIT_FACES | V3D_OVERLAY_EDIT_SEAMS | \
V3D_OVERLAY_EDIT_SHARP | V3D_OVERLAY_EDIT_FREESTYLE_EDGE | \
V3D_OVERLAY_EDIT_FREESTYLE_FACE | V3D_OVERLAY_EDIT_EDGES | \
- V3D_OVERLAY_EDIT_CREASES | V3D_OVERLAY_EDIT_BWEIGHTS | \
- V3D_OVERLAY_EDIT_CU_HANDLES | V3D_OVERLAY_EDIT_CU_NORMALS, \
+ V3D_OVERLAY_EDIT_CREASES | V3D_OVERLAY_EDIT_BWEIGHTS, \
+ .handle_display = CURVE_HANDLE_SELECTED, \
\
.gpencil_paper_opacity = 0.5f, \
.gpencil_grid_opacity = 0.9f, \
diff --git a/source/blender/makesdna/DNA_view3d_types.h b/source/blender/makesdna/DNA_view3d_types.h
index 3e348f7f502..ef174f5858f 100644
--- a/source/blender/makesdna/DNA_view3d_types.h
+++ b/source/blender/makesdna/DNA_view3d_types.h
@@ -228,9 +228,20 @@ typedef struct View3DOverlay {
/** Factor for mixing vertex paint with original color */
float gpencil_vertex_paint_opacity;
- char _pad4[4];
+ /** Handles display type for curves. */
+ int handle_display;
} View3DOverlay;
+/* View3DOverlay->handle_display */
+typedef enum eHandleDisplay {
+ /* Display only selected points. */
+ CURVE_HANDLE_SELECTED = 0,
+ /* Display all handles. */
+ CURVE_HANDLE_ALL = 1,
+ /* No display handles. */
+ CURVE_HANDLE_NONE = 2,
+} eHandleDisplay;
+
typedef struct View3D_Runtime {
/** Nkey panel stores stuff here. */
void *properties_storage;
@@ -421,8 +432,8 @@ enum {
};
#define RV3D_CLIPPING_ENABLED(v3d, rv3d) \
- (rv3d && v3d && (rv3d->rflag & RV3D_CLIPPING) && ELEM(v3d->shading.type, OB_WIRE, OB_SOLID) && \
- rv3d->clipbb)
+ ((rv3d) && (v3d) && ((rv3d)->rflag & RV3D_CLIPPING) && \
+ ELEM((v3d)->shading.type, OB_WIRE, OB_SOLID) && (rv3d)->clipbb)
/** #View3D.flag2 (int) */
#define V3D_HIDE_OVERLAYS (1 << 2)
@@ -450,6 +461,7 @@ enum {
#define V3D_GP_FADE_NOACTIVE_GPENCIL (1 << 6) /* Fade other GPencil objects */
#define V3D_GP_SHOW_STROKE_DIRECTION (1 << 7) /* Show Strokes Directions */
#define V3D_GP_SHOW_MATERIAL_NAME (1 << 8) /* Show Material names */
+#define V3D_GP_SHOW_GRID_XRAY (1 << 9) /* Show Canvas Grid on Top */
/** #View3DShading.flag */
enum {
@@ -489,6 +501,7 @@ enum {
V3D_OVERLAY_HIDE_BONES = (1 << 8),
V3D_OVERLAY_HIDE_OBJECT_XTRAS = (1 << 9),
V3D_OVERLAY_HIDE_OBJECT_ORIGINS = (1 << 10),
+ V3D_OVERLAY_STATS = (1 << 11),
};
/** #View3DOverlay.edit_flag */
@@ -520,7 +533,9 @@ enum {
V3D_OVERLAY_EDIT_FACE_AREA = (1 << 18),
V3D_OVERLAY_EDIT_INDICES = (1 << 19),
- V3D_OVERLAY_EDIT_CU_HANDLES = (1 << 20),
+ /* Deprecated. */
+ /* V3D_OVERLAY_EDIT_CU_HANDLES = (1 << 20), */
+
V3D_OVERLAY_EDIT_CU_NORMALS = (1 << 21),
};
@@ -548,7 +563,7 @@ enum {
V3D_AROUND_ACTIVE = 4,
};
-/** #View3d.gridflag */
+/** #View3D.gridflag */
#define V3D_SHOW_FLOOR (1 << 0)
#define V3D_SHOW_X (1 << 1)
#define V3D_SHOW_Y (1 << 2)
diff --git a/source/blender/makesdna/DNA_volume_types.h b/source/blender/makesdna/DNA_volume_types.h
index 1a49df86761..b3615e87a50 100644
--- a/source/blender/makesdna/DNA_volume_types.h
+++ b/source/blender/makesdna/DNA_volume_types.h
@@ -95,9 +95,9 @@ enum {
/* Volume.sequence_mode */
typedef enum VolumeSequenceMode {
VOLUME_SEQUENCE_CLIP = 0,
- VOLUME_SEQUENCE_EXTEND,
- VOLUME_SEQUENCE_REPEAT,
- VOLUME_SEQUENCE_PING_PONG,
+ VOLUME_SEQUENCE_EXTEND = 1,
+ VOLUME_SEQUENCE_REPEAT = 2,
+ VOLUME_SEQUENCE_PING_PONG = 3,
} VolumeSequenceMode;
/* VolumeDisplay.wireframe_type */
diff --git a/source/blender/makesdna/intern/CMakeLists.txt b/source/blender/makesdna/intern/CMakeLists.txt
index a101e96e958..01e3971a216 100644
--- a/source/blender/makesdna/intern/CMakeLists.txt
+++ b/source/blender/makesdna/intern/CMakeLists.txt
@@ -58,6 +58,10 @@ setup_platform_linker_flags()
add_executable(makesdna ${SRC} ${SRC_DNA_INC})
+if(WIN32 AND NOT UNIX)
+ target_link_libraries(makesdna ${PTHREADS_LIBRARIES})
+endif()
+
# Output dna.c
add_custom_command(
OUTPUT
@@ -146,6 +150,7 @@ set(SRC
../DNA_object_defaults.h
../DNA_pointcloud_defaults.h
../DNA_scene_defaults.h
+ ../DNA_simulation_defaults.h
../DNA_speaker_defaults.h
../DNA_texture_defaults.h
../DNA_vec_defaults.h
diff --git a/source/blender/makesdna/intern/dna_defaults.c b/source/blender/makesdna/intern/dna_defaults.c
index dadd2fd9d7d..2d86e97debf 100644
--- a/source/blender/makesdna/intern/dna_defaults.c
+++ b/source/blender/makesdna/intern/dna_defaults.c
@@ -71,6 +71,7 @@
#include "DNA_object_types.h"
#include "DNA_pointcloud_types.h"
#include "DNA_scene_types.h"
+#include "DNA_simulation_types.h"
#include "DNA_space_types.h"
#include "DNA_speaker_types.h"
#include "DNA_texture_types.h"
@@ -93,6 +94,7 @@
#include "DNA_object_defaults.h"
#include "DNA_pointcloud_defaults.h"
#include "DNA_scene_defaults.h"
+#include "DNA_simulation_defaults.h"
#include "DNA_speaker_defaults.h"
#include "DNA_texture_defaults.h"
#include "DNA_volume_defaults.h"
@@ -150,6 +152,9 @@ SDNA_DEFAULT_DECL_STRUCT(PointCloud);
SDNA_DEFAULT_DECL_STRUCT(Scene);
SDNA_DEFAULT_DECL_STRUCT(ToolSettings);
+/* DNA_simulation_defaults.h */
+SDNA_DEFAULT_DECL_STRUCT(Simulation);
+
/* DNA_speaker_defaults.h */
SDNA_DEFAULT_DECL_STRUCT(Speaker);
@@ -260,6 +265,9 @@ const void *DNA_default_table[SDNA_TYPE_MAX] = {
SDNA_DEFAULT_DECL_EX(GP_Sculpt_Settings, ToolSettings.gp_sculpt),
SDNA_DEFAULT_DECL_EX(GP_Sculpt_Guide, ToolSettings.gp_sculpt.guide),
+ /* DNA_simulation_defaults.h */
+ SDNA_DEFAULT_DECL(Simulation),
+
/* DNA_speaker_defaults.h */
SDNA_DEFAULT_DECL(Speaker),
diff --git a/source/blender/makesdna/intern/makesdna.c b/source/blender/makesdna/intern/makesdna.c
index 39b26fef176..09cfe54e94d 100644
--- a/source/blender/makesdna/intern/makesdna.c
+++ b/source/blender/makesdna/intern/makesdna.c
@@ -136,6 +136,7 @@ static const char *includefiles[] = {
"DNA_hair_types.h",
"DNA_pointcloud_types.h",
"DNA_volume_types.h",
+ "DNA_simulation_types.h",
/* see comment above before editing! */
@@ -1073,8 +1074,8 @@ static int calculate_struct_sizes(int firststruct, FILE *file_verify, const char
types_size_native[structtype] = size_native;
types_size_32[structtype] = size_32;
types_size_64[structtype] = size_64;
- /* two ways to detect if a struct contains a pointer:
- * has_pointer is set or size_native doesn't match any of 32/64bit lengths*/
+ /* Two ways to detect if a struct contains a pointer:
+ * has_pointer is set or size_native doesn't match any of 32/64bit lengths. */
if (has_pointer || size_64 != size_native || size_32 != size_native) {
if (size_64 % 8) {
fprintf(stderr,
@@ -1590,6 +1591,7 @@ int main(int argc, char **argv)
#include "DNA_sdna_types.h"
#include "DNA_sequence_types.h"
#include "DNA_shader_fx_types.h"
+#include "DNA_simulation_types.h"
#include "DNA_sound_types.h"
#include "DNA_space_types.h"
#include "DNA_speaker_types.h"
diff --git a/source/blender/makesrna/RNA_access.h b/source/blender/makesrna/RNA_access.h
index 31d1ed54fa1..65c43ebc151 100644
--- a/source/blender/makesrna/RNA_access.h
+++ b/source/blender/makesrna/RNA_access.h
@@ -71,6 +71,7 @@ extern StructRNA RNA_BackgroundImage;
extern StructRNA RNA_BevelModifier;
extern StructRNA RNA_BezierSplinePoint;
extern StructRNA RNA_BlendData;
+extern StructRNA RNA_BlendDataLibraries;
extern StructRNA RNA_BlendTexture;
extern StructRNA RNA_BlenderRNA;
extern StructRNA RNA_BoidRule;
@@ -259,6 +260,7 @@ extern StructRNA RNA_FreestyleLineStyle;
extern StructRNA RNA_FreestyleModuleSettings;
extern StructRNA RNA_FreestyleSettings;
extern StructRNA RNA_Function;
+extern StructRNA RNA_FunctionNode;
extern StructRNA RNA_GPencilFrame;
extern StructRNA RNA_GPencilInterpolateSettings;
extern StructRNA RNA_GPencilLayer;
@@ -548,6 +550,9 @@ extern StructRNA RNA_ShrinkwrapConstraint;
extern StructRNA RNA_ShrinkwrapModifier;
extern StructRNA RNA_SimpleDeformModifier;
extern StructRNA RNA_SimplifyGpencilModifier;
+extern StructRNA RNA_Simulation;
+extern StructRNA RNA_SimulationNode;
+extern StructRNA RNA_SimulationNodeTree;
extern StructRNA RNA_SkinModifier;
extern StructRNA RNA_SmoothGpencilModifier;
extern StructRNA RNA_SmoothModifier;
@@ -930,10 +935,6 @@ void RNA_property_update_main(struct Main *bmain,
PropertyRNA *prop);
bool RNA_property_update_check(struct PropertyRNA *prop);
-void RNA_property_update_cache_add(PointerRNA *ptr, PropertyRNA *prop);
-void RNA_property_update_cache_flush(struct Main *bmain, struct Scene *scene);
-void RNA_property_update_cache_free(void);
-
/* Property Data */
bool RNA_property_boolean_get(PointerRNA *ptr, PropertyRNA *prop);
diff --git a/source/blender/makesrna/RNA_define.h b/source/blender/makesrna/RNA_define.h
index 558e490a16e..1bcf7f434f2 100644
--- a/source/blender/makesrna/RNA_define.h
+++ b/source/blender/makesrna/RNA_define.h
@@ -50,6 +50,7 @@ void RNA_free(BlenderRNA *brna);
void RNA_define_verify_sdna(bool verify);
void RNA_define_animate_sdna(bool animate);
void RNA_define_fallback_property_update(int noteflag, const char *updatefunc);
+void RNA_define_lib_overridable(const bool make_overridable);
void RNA_init(void);
void RNA_exit(void);
@@ -76,7 +77,7 @@ void RNA_def_struct_identifier_no_struct_map(StructRNA *srna, const char *identi
void RNA_def_struct_identifier(BlenderRNA *brna, StructRNA *srna, const char *identifier);
void RNA_def_struct_ui_text(StructRNA *srna, const char *name, const char *description);
void RNA_def_struct_ui_icon(StructRNA *srna, int icon);
-void RNA_struct_free_extension(StructRNA *srna, ExtensionRNA *ext);
+void RNA_struct_free_extension(StructRNA *srna, ExtensionRNA *rna_ext);
void RNA_struct_free(BlenderRNA *brna, StructRNA *srna);
void RNA_def_struct_translation_context(StructRNA *srna, const char *context);
diff --git a/source/blender/makesrna/RNA_enum_types.h b/source/blender/makesrna/RNA_enum_types.h
index fef98f9da4b..b6bae805636 100644
--- a/source/blender/makesrna/RNA_enum_types.h
+++ b/source/blender/makesrna/RNA_enum_types.h
@@ -23,6 +23,10 @@
#include "RNA_types.h"
+#ifdef __cplusplus
+extern "C" {
+#endif
+
struct bNodeSocketType;
struct bNodeTreeType;
struct bNodeType;
@@ -191,6 +195,8 @@ extern const EnumPropertyItem rna_enum_node_socket_in_out_items[];
extern const EnumPropertyItem rna_enum_node_math_items[];
extern const EnumPropertyItem rna_enum_mapping_type_items[];
extern const EnumPropertyItem rna_enum_node_vec_math_items[];
+extern const EnumPropertyItem rna_enum_node_boolean_math_items[];
+extern const EnumPropertyItem rna_enum_node_float_compare_items[];
extern const EnumPropertyItem rna_enum_node_filter_items[];
extern const EnumPropertyItem rna_enum_node_map_range_items[];
extern const EnumPropertyItem rna_enum_node_clamp_items[];
@@ -315,4 +321,8 @@ const EnumPropertyItem *RNA_mask_local_itemf(struct bContext *C,
/* Non confirming, utility function. */
const EnumPropertyItem *RNA_enum_node_tree_types_itemf_impl(struct bContext *C, bool *r_free);
+#ifdef __cplusplus
+}
+#endif
+
#endif /* __RNA_ENUM_TYPES_H__ */
diff --git a/source/blender/makesrna/intern/CMakeLists.txt b/source/blender/makesrna/intern/CMakeLists.txt
index 64b7a3e70c1..024bdbe5ed5 100644
--- a/source/blender/makesrna/intern/CMakeLists.txt
+++ b/source/blender/makesrna/intern/CMakeLists.txt
@@ -103,6 +103,13 @@ if(WITH_NEW_OBJECT_TYPES)
)
endif()
+if (WITH_NEW_SIMULATION_TYPE)
+ list(APPEND DEFSRC
+ rna_simulation.c
+ )
+endif()
+
+
set(APISRC
rna_action_api.c
rna_animation_api.c
@@ -342,6 +349,11 @@ if(WITH_NEW_OBJECT_TYPES)
add_definitions(-DWITH_NEW_OBJECT_TYPES)
endif()
+if (WITH_NEW_SIMULATION_TYPE)
+ add_definitions(-DWITH_NEW_SIMULATION_TYPE)
+endif()
+
+
# Build makesrna executable
blender_include_dirs(
.
@@ -382,6 +394,10 @@ add_executable(makesrna ${SRC} ${SRC_RNA_INC} ${SRC_DNA_INC})
target_link_libraries(makesrna bf_dna)
target_link_libraries(makesrna bf_dna_blenlib)
+if(WIN32 AND NOT UNIX)
+ target_link_libraries(makesrna ${PTHREADS_LIBRARIES})
+endif()
+
# Output rna_*_gen.c
# note (linux only): with crashes try add this after COMMAND: valgrind --leak-check=full --track-origins=yes
add_custom_command(
diff --git a/source/blender/makesrna/intern/makesrna.c b/source/blender/makesrna/intern/makesrna.c
index 46854bc6307..2960cea7f53 100644
--- a/source/blender/makesrna/intern/makesrna.c
+++ b/source/blender/makesrna/intern/makesrna.c
@@ -637,7 +637,7 @@ static char *rna_def_property_get_func(
if (!manualfunc) {
if (!dp->dnastructname || !dp->dnaname) {
CLOG_ERROR(&LOG, "%s.%s has no valid dna info.", srna->identifier, prop->identifier);
- DefRNA.error = 1;
+ DefRNA.error = true;
return NULL;
}
@@ -654,7 +654,7 @@ static char *rna_def_property_get_func(
prop->identifier,
dp->dnatype,
RNA_property_typename(prop->type));
- DefRNA.error = 1;
+ DefRNA.error = true;
return NULL;
}
}
@@ -667,7 +667,7 @@ static char *rna_def_property_get_func(
prop->identifier,
dp->dnatype,
RNA_property_typename(prop->type));
- DefRNA.error = 1;
+ DefRNA.error = true;
return NULL;
}
}
@@ -679,7 +679,7 @@ static char *rna_def_property_get_func(
prop->identifier,
dp->dnatype,
RNA_property_typename(prop->type));
- DefRNA.error = 1;
+ DefRNA.error = true;
return NULL;
}
}
@@ -1020,7 +1020,7 @@ static char *rna_def_property_set_func(
if (!dp->dnastructname || !dp->dnaname) {
if (prop->flag & PROP_EDITABLE) {
CLOG_ERROR(&LOG, "%s.%s has no valid dna info.", srna->identifier, prop->identifier);
- DefRNA.error = 1;
+ DefRNA.error = true;
}
return NULL;
}
@@ -1263,7 +1263,7 @@ static char *rna_def_property_length_func(
if (!manualfunc) {
if (!dp->dnastructname || !dp->dnaname) {
CLOG_ERROR(&LOG, "%s.%s has no valid dna info.", srna->identifier, prop->identifier);
- DefRNA.error = 1;
+ DefRNA.error = true;
return NULL;
}
}
@@ -1289,7 +1289,7 @@ static char *rna_def_property_length_func(
if (prop->type == PROP_COLLECTION &&
(!(dp->dnalengthname || dp->dnalengthfixed) || !dp->dnaname)) {
CLOG_ERROR(&LOG, "%s.%s has no valid dna info.", srna->identifier, prop->identifier);
- DefRNA.error = 1;
+ DefRNA.error = true;
return NULL;
}
}
@@ -1338,7 +1338,7 @@ static char *rna_def_property_begin_func(
if (!manualfunc) {
if (!dp->dnastructname || !dp->dnaname) {
CLOG_ERROR(&LOG, "%s.%s has no valid dna info.", srna->identifier, prop->identifier);
- DefRNA.error = 1;
+ DefRNA.error = true;
return NULL;
}
}
@@ -1823,6 +1823,10 @@ static void rna_def_property_funcs(FILE *f, StructRNA *srna, PropertyDefRNA *dp)
case PROP_ENUM: {
EnumPropertyRNA *eprop = (EnumPropertyRNA *)prop;
+ if (!eprop->get && !eprop->set) {
+ rna_set_raw_property(dp, prop);
+ }
+
eprop->get = (void *)rna_def_property_get_func(f, srna, prop, dp, (const char *)eprop->get);
eprop->set = (void *)rna_def_property_set_func(f, srna, prop, dp, (const char *)eprop->set);
break;
@@ -1844,7 +1848,7 @@ static void rna_def_property_funcs(FILE *f, StructRNA *srna, PropertyDefRNA *dp)
if (!pprop->type) {
CLOG_ERROR(
&LOG, "%s.%s, pointer must have a struct type.", srna->identifier, prop->identifier);
- DefRNA.error = 1;
+ DefRNA.error = true;
}
break;
}
@@ -1892,21 +1896,21 @@ static void rna_def_property_funcs(FILE *f, StructRNA *srna, PropertyDefRNA *dp)
"%s.%s, collection must have a begin function.",
srna->identifier,
prop->identifier);
- DefRNA.error = 1;
+ DefRNA.error = true;
}
if (!cprop->next) {
CLOG_ERROR(&LOG,
"%s.%s, collection must have a next function.",
srna->identifier,
prop->identifier);
- DefRNA.error = 1;
+ DefRNA.error = true;
}
if (!cprop->get) {
CLOG_ERROR(&LOG,
"%s.%s, collection must have a get function.",
srna->identifier,
prop->identifier);
- DefRNA.error = 1;
+ DefRNA.error = true;
}
}
if (!cprop->item_type) {
@@ -1914,7 +1918,7 @@ static void rna_def_property_funcs(FILE *f, StructRNA *srna, PropertyDefRNA *dp)
"%s.%s, collection must have a struct type.",
srna->identifier,
prop->identifier);
- DefRNA.error = 1;
+ DefRNA.error = true;
}
break;
}
@@ -3652,7 +3656,7 @@ static void rna_generate_property(FILE *f, StructRNA *srna, const char *nest, Pr
errnest,
prop->identifier,
eprop->defaultvalue & ~totflag);
- DefRNA.error = 1;
+ DefRNA.error = true;
}
}
else {
@@ -3662,7 +3666,7 @@ static void rna_generate_property(FILE *f, StructRNA *srna, const char *nest, Pr
srna->identifier,
errnest,
prop->identifier);
- DefRNA.error = 1;
+ DefRNA.error = true;
}
}
}
@@ -3672,7 +3676,7 @@ static void rna_generate_property(FILE *f, StructRNA *srna, const char *nest, Pr
srna->identifier,
errnest,
prop->identifier);
- DefRNA.error = 1;
+ DefRNA.error = true;
}
break;
}
@@ -4214,7 +4218,7 @@ static void rna_generate_struct(BlenderRNA *UNUSED(brna), StructRNA *srna, FILE
if (srna->reg && !srna->refine) {
CLOG_ERROR(
&LOG, "%s has a register function, must also have refine function.", srna->identifier);
- DefRNA.error = 1;
+ DefRNA.error = true;
}
func = srna->functions.first;
@@ -4302,6 +4306,9 @@ static RNAProcessItem PROCESS_ITEMS[] = {
{"rna_screen.c", NULL, RNA_def_screen},
{"rna_sculpt_paint.c", NULL, RNA_def_sculpt_paint},
{"rna_sequencer.c", "rna_sequencer_api.c", RNA_def_sequencer},
+#ifdef WITH_NEW_SIMULATION_TYPE
+ {"rna_simulation.c", NULL, RNA_def_simulation},
+#endif
{"rna_space.c", "rna_space_api.c", RNA_def_space},
{"rna_speaker.c", NULL, RNA_def_speaker},
{"rna_test.c", NULL, RNA_def_test},
@@ -4702,7 +4709,8 @@ static const char *cpp_classes =
" DynamicArray() : data(NULL), length(0) {}\n"
" DynamicArray(int new_length) : data(NULL), length(new_length) { data = (T "
"*)malloc(sizeof(T) * new_length); }\n"
- " DynamicArray(const DynamicArray<T>& other) { copy_from(other); }\n"
+ " DynamicArray(const DynamicArray<T>& other) : data(NULL), length(0) { copy_from(other); "
+ "}\n"
" const DynamicArray<T>& operator = (const DynamicArray<T>& other) { copy_from(other); "
"return *this; }\n"
"\n"
diff --git a/source/blender/makesrna/intern/rna_ID.c b/source/blender/makesrna/intern/rna_ID.c
index 42cec23975c..891c30af466 100644
--- a/source/blender/makesrna/intern/rna_ID.c
+++ b/source/blender/makesrna/intern/rna_ID.c
@@ -71,6 +71,9 @@ const EnumPropertyItem rna_enum_id_type_items[] = {
{ID_PA, "PARTICLE", ICON_PARTICLE_DATA, "Particle", ""},
{ID_LP, "LIGHT_PROBE", ICON_LIGHTPROBE_CUBEMAP, "Light Probe", ""},
{ID_SCE, "SCENE", ICON_SCENE_DATA, "Scene", ""},
+#ifdef WITH_NEW_SIMULATION_TYPE
+ {ID_SIM, "SIMULATION", ICON_PHYSICS, "Simulation", ""}, /* TODO: Use correct icon. */
+#endif
{ID_SO, "SOUND", ICON_SOUND, "Sound", ""},
{ID_SPK, "SPEAKER", ICON_SPEAKER, "Speaker", ""},
{ID_TXT, "TEXT", ICON_TEXT, "Text", ""},
@@ -93,7 +96,7 @@ const EnumPropertyItem rna_enum_id_type_items[] = {
# include "BLI_listbase.h"
# include "BLI_math_base.h"
-# include "BKE_animsys.h"
+# include "BKE_anim_data.h"
# include "BKE_font.h"
# include "BKE_global.h" /* XXX, remove me */
# include "BKE_idprop.h"
@@ -303,6 +306,11 @@ short RNA_type_to_ID_code(const StructRNA *type)
if (base_type == &RNA_Screen) {
return ID_SCR;
}
+# ifdef WITH_NEW_SIMULATION_TYPE
+ if (base_type == &RNA_Simulation) {
+ return ID_SIM;
+ }
+# endif
if (base_type == &RNA_Sound) {
return ID_SO;
}
@@ -405,6 +413,12 @@ StructRNA *ID_code_to_RNA_type(short idcode)
return &RNA_Scene;
case ID_SCR:
return &RNA_Screen;
+ case ID_SIM:
+# ifdef WITH_NEW_SIMULATION_TYPE
+ return &RNA_Simulation;
+# else
+ return &RNA_ID;
+# endif
case ID_SO:
return &RNA_Sound;
case ID_SPK:
@@ -1506,7 +1520,7 @@ static void rna_def_ID(BlenderRNA *brna)
RNA_def_property_ui_text(
prop,
"Embedded Data",
- "This data-block is not an independant one, but is actually a sub-data of another ID "
+ "This data-block is not an independent one, but is actually a sub-data of another ID "
"(typical example: root node trees or master collections)");
prop = RNA_def_property(srna, "tag", PROP_BOOLEAN, PROP_NONE);
diff --git a/source/blender/makesrna/intern/rna_access.c b/source/blender/makesrna/intern/rna_access.c
index 48e4d758bba..2197764794b 100644
--- a/source/blender/makesrna/intern/rna_access.c
+++ b/source/blender/makesrna/intern/rna_access.c
@@ -40,7 +40,7 @@
#include "BLF_api.h"
#include "BLT_translation.h"
-#include "BKE_animsys.h"
+#include "BKE_anim_data.h"
#include "BKE_collection.h"
#include "BKE_context.h"
#include "BKE_fcurve.h"
@@ -98,8 +98,6 @@ void RNA_exit(void)
{
StructRNA *srna;
- RNA_property_update_cache_free();
-
for (srna = BLENDER_RNA.structs.first; srna; srna = srna->cont.next) {
if (srna->cont.prophash) {
BLI_ghash_free(srna->cont.prophash, NULL, NULL);
@@ -2184,7 +2182,7 @@ bool RNA_property_animated(PointerRNA *ptr, PropertyRNA *prop)
}
for (index = 0; index < len; index++) {
- if (rna_get_fcurve(ptr, prop, index, NULL, NULL, &driven, &special)) {
+ if (BKE_fcurve_find_by_rna(ptr, prop, index, NULL, NULL, &driven, &special)) {
return true;
}
}
@@ -2308,115 +2306,6 @@ void RNA_property_update_main(Main *bmain, Scene *scene, PointerRNA *ptr, Proper
rna_property_update(NULL, bmain, scene, ptr, prop);
}
-/* RNA Updates Cache ------------------------ */
-/* Overview of RNA Update cache system:
- *
- * RNA Update calls need to be cached in order to maintain reasonable performance
- * of the animation system (i.e. maintaining a somewhat interactive framerate)
- * while still allowing updates to be called (necessary in particular for modifier
- * property updates to actually work).
- *
- * The cache is structured with a dual-layer structure
- * - L1 = PointerRNA used as key; owner_id is used (it should always be defined,
- * and most updates end up using just that anyways)
- * - L2 = Update functions to be called on those PointerRNA's
- */
-
-/* cache element */
-typedef struct tRnaUpdateCacheElem {
- struct tRnaUpdateCacheElem *next, *prev;
-
- PointerRNA ptr; /* L1 key - id as primary, data secondary/ignored? */
- ListBase L2Funcs; /* L2 functions (LinkData<RnaUpdateFuncRef>) */
-} tRnaUpdateCacheElem;
-
-/* cache global (tRnaUpdateCacheElem's) - only accessible using these API calls */
-static ListBase rna_updates_cache = {NULL, NULL};
-
-/* ........................... */
-
-void RNA_property_update_cache_add(PointerRNA *ptr, PropertyRNA *prop)
-{
- const bool is_rna = (prop->magic == RNA_MAGIC);
- tRnaUpdateCacheElem *uce = NULL;
- UpdateFunc fn = NULL;
- LinkData *ld;
-
- /* sanity check */
- if (NULL == ptr) {
- return;
- }
-
- prop = rna_ensure_property(prop);
-
- /* we can only handle update calls with no context args for now (makes animsys updates easier) */
- if ((is_rna == false) || (prop->update == NULL) || (prop->flag & PROP_CONTEXT_UPDATE)) {
- return;
- }
- fn = prop->update;
-
- /* find cache element for which key matches... */
- for (uce = rna_updates_cache.first; uce; uce = uce->next) {
- /* Just match by id only for now,
- * since most update calls that we'll encounter only really care about this. */
- /* TODO: later, the cache might need to have some nesting on L1 to cope better
- * with these problems + some tagging to indicate we need this */
- if (uce->ptr.owner_id == ptr->owner_id) {
- break;
- }
- }
- if (uce == NULL) {
- /* create new instance */
- uce = MEM_callocN(sizeof(tRnaUpdateCacheElem), "tRnaUpdateCacheElem");
- BLI_addtail(&rna_updates_cache, uce);
-
- /* copy pointer */
- RNA_pointer_create(ptr->owner_id, ptr->type, ptr->data, &uce->ptr);
- }
-
- /* check on the update func */
- for (ld = uce->L2Funcs.first; ld; ld = ld->next) {
- /* stop on match - function already cached */
- if (fn == ld->data) {
- return;
- }
- }
- /* else... if still here, we need to add it */
- BLI_addtail(&uce->L2Funcs, BLI_genericNodeN(fn));
-}
-
-void RNA_property_update_cache_flush(Main *bmain, Scene *scene)
-{
- tRnaUpdateCacheElem *uce;
-
- /* TODO: should we check that bmain and scene are valid? The above stuff doesn't! */
-
- /* execute the cached updates */
- for (uce = rna_updates_cache.first; uce; uce = uce->next) {
- LinkData *ld;
-
- for (ld = uce->L2Funcs.first; ld; ld = ld->next) {
- UpdateFunc fn = (UpdateFunc)ld->data;
- fn(bmain, scene, &uce->ptr);
- }
- }
-}
-
-void RNA_property_update_cache_free(void)
-{
- tRnaUpdateCacheElem *uce, *ucn;
-
- for (uce = rna_updates_cache.first; uce; uce = ucn) {
- ucn = uce->next;
-
- /* free L2 cache */
- BLI_freelistN(&uce->L2Funcs);
-
- /* remove self */
- BLI_freelinkN(&rna_updates_cache, uce);
- }
-}
-
/* ---------------------------------------------------------------------- */
/* Property Data */
@@ -4497,8 +4386,8 @@ static int rna_raw_access(ReportList *reports,
/* check type */
itemtype = RNA_property_type(itemprop);
- if (!ELEM(itemtype, PROP_BOOLEAN, PROP_INT, PROP_FLOAT)) {
- BKE_report(reports, RPT_ERROR, "Only boolean, int and float properties supported");
+ if (!ELEM(itemtype, PROP_BOOLEAN, PROP_INT, PROP_FLOAT, PROP_ENUM)) {
+ BKE_report(reports, RPT_ERROR, "Only boolean, int float and enum properties supported");
return 0;
}
@@ -5785,10 +5674,10 @@ static char *rna_idp_path(PointerRNA *ptr,
}
/**
- * Find the path from the structure referenced by the pointer to the IDProperty object.
+ * Find the path from the structure referenced by the pointer to the #IDProperty object.
*
- * \param ptr Reference to the object owning the custom property storage.
- * \param needle Custom property object to find.
+ * \param ptr: Reference to the object owning the custom property storage.
+ * \param needle: Custom property object to find.
* \return Relative path or NULL.
*/
char *RNA_path_from_struct_to_idproperty(PointerRNA *ptr, IDProperty *needle)
diff --git a/source/blender/makesrna/intern/rna_access_compare_override.c b/source/blender/makesrna/intern/rna_access_compare_override.c
index 22d018c6025..fbd86d78472 100644
--- a/source/blender/makesrna/intern/rna_access_compare_override.c
+++ b/source/blender/makesrna/intern/rna_access_compare_override.c
@@ -24,6 +24,7 @@
#include "DNA_constraint_types.h"
#include "DNA_modifier_types.h"
+#include "BLI_listbase.h"
#include "BLI_string.h"
#include "BLI_utildefines.h"
@@ -437,7 +438,7 @@ static bool rna_property_override_operation_store(Main *bmain,
return changed;
}
- for (IDOverrideLibraryPropertyOperation *opop = op->operations.first; opop; opop = opop->next) {
+ LISTBASE_FOREACH (IDOverrideLibraryPropertyOperation *, opop, &op->operations) {
/* Only needed for diff operations. */
if (!ELEM(opop->operation,
IDOVERRIDE_LIBRARY_OP_ADD,
@@ -480,28 +481,13 @@ static bool rna_property_override_operation_apply(Main *bmain,
const short override_op = opop->operation;
- if (override_op == IDOVERRIDE_LIBRARY_OP_NOOP) {
- return true;
- }
-
- if (ELEM(override_op,
- IDOVERRIDE_LIBRARY_OP_ADD,
- IDOVERRIDE_LIBRARY_OP_SUBTRACT,
- IDOVERRIDE_LIBRARY_OP_MULTIPLY) &&
- !ptr_storage) {
- /* We cannot apply 'diff' override operations without some reference storage.
- * This should typically only happen at read time of .blend file... */
+ if (!BKE_lib_override_library_property_operation_operands_validate(
+ opop, ptr_dst, ptr_src, ptr_storage, prop_dst, prop_src, prop_storage)) {
return false;
}
- if (ELEM(override_op,
- IDOVERRIDE_LIBRARY_OP_ADD,
- IDOVERRIDE_LIBRARY_OP_SUBTRACT,
- IDOVERRIDE_LIBRARY_OP_MULTIPLY) &&
- !prop_storage) {
- /* We cannot apply 'diff' override operations without some reference storage.
- * This should typically only happen at read time of .blend file... */
- return false;
+ if (override_op == IDOVERRIDE_LIBRARY_OP_NOOP) {
+ return true;
}
RNAPropOverrideApply override_apply = NULL;
@@ -691,7 +677,9 @@ bool RNA_struct_override_matches(Main *bmain,
// printf("Override Checking %s\n", rna_path);
- if (ignore_overridden && BKE_lib_override_library_property_find(override, rna_path) != NULL) {
+ IDOverrideLibraryProperty *op = BKE_lib_override_library_property_find(override, rna_path);
+ if (ignore_overridden && op != NULL) {
+ BKE_lib_override_library_operations_tag(op, IDOVERRIDE_LIBRARY_TAG_UNUSED, false);
RNA_PATH_FREE;
continue;
}
@@ -730,9 +718,13 @@ bool RNA_struct_override_matches(Main *bmain,
if (diff != 0) {
/* XXX TODO: refine this for per-item overriding of arrays... */
- IDOverrideLibraryProperty *op = BKE_lib_override_library_property_find(override, rna_path);
+ op = BKE_lib_override_library_property_find(override, rna_path);
IDOverrideLibraryPropertyOperation *opop = op ? op->operations.first : NULL;
+ if (op != NULL) {
+ BKE_lib_override_library_operations_tag(op, IDOVERRIDE_LIBRARY_TAG_UNUSED, false);
+ }
+
if (do_restore && (report_flags & RNA_OVERRIDE_MATCH_RESULT_CREATED) == 0) {
/* We are allowed to restore to reference's values. */
if (ELEM(NULL, op, opop) || opop->operation == IDOVERRIDE_LIBRARY_OP_NOOP) {
@@ -831,7 +823,7 @@ bool RNA_struct_override_store(Main *bmain,
#ifdef DEBUG_OVERRIDE_TIMEIT
TIMEIT_START_AVERAGED(RNA_struct_override_store);
#endif
- for (IDOverrideLibraryProperty *op = override->properties.first; op; op = op->next) {
+ LISTBASE_FOREACH (IDOverrideLibraryProperty *, op, &override->properties) {
/* Simplified for now! */
PointerRNA data_reference, data_local;
PropertyRNA *prop_reference, *prop_local;
@@ -879,7 +871,7 @@ static void rna_property_override_apply_ex(Main *bmain,
IDOverrideLibraryProperty *op,
const bool do_insert)
{
- for (IDOverrideLibraryPropertyOperation *opop = op->operations.first; opop; opop = opop->next) {
+ LISTBASE_FOREACH (IDOverrideLibraryPropertyOperation *, opop, &op->operations) {
if (!do_insert != !ELEM(opop->operation,
IDOVERRIDE_LIBRARY_OP_INSERT_AFTER,
IDOVERRIDE_LIBRARY_OP_INSERT_BEFORE)) {
@@ -998,7 +990,7 @@ void RNA_struct_override_apply(Main *bmain,
*/
bool do_insert = false;
for (int i = 0; i < 2; i++, do_insert = true) {
- for (IDOverrideLibraryProperty *op = override->properties.first; op; op = op->next) {
+ LISTBASE_FOREACH (IDOverrideLibraryProperty *, op, &override->properties) {
/* Simplified for now! */
PointerRNA data_src, data_dst;
PointerRNA data_item_src, data_item_dst;
diff --git a/source/blender/makesrna/intern/rna_action.c b/source/blender/makesrna/intern/rna_action.c
index 0685fb270f1..e67366fc7ef 100644
--- a/source/blender/makesrna/intern/rna_action.c
+++ b/source/blender/makesrna/intern/rna_action.c
@@ -147,7 +147,7 @@ static FCurve *rna_Action_fcurve_find(bAction *act,
}
/* Returns NULL if not found. */
- return list_find_fcurve(&act->curves, data_path, index);
+ return BKE_fcurve_find(&act->curves, data_path, index);
}
static void rna_Action_fcurve_remove(bAction *act, ReportList *reports, PointerRNA *fcu_ptr)
@@ -164,7 +164,7 @@ static void rna_Action_fcurve_remove(bAction *act, ReportList *reports, PointerR
}
action_groups_remove_channel(act, fcu);
- free_fcurve(fcu);
+ BKE_fcurve_free(fcu);
RNA_POINTER_INVALIDATE(fcu_ptr);
}
else {
@@ -174,7 +174,7 @@ static void rna_Action_fcurve_remove(bAction *act, ReportList *reports, PointerR
}
BLI_remlink(&act->curves, fcu);
- free_fcurve(fcu);
+ BKE_fcurve_free(fcu);
RNA_POINTER_INVALIDATE(fcu_ptr);
}
@@ -345,14 +345,14 @@ static void rna_def_dopesheet(BlenderRNA *brna)
prop = RNA_def_property(srna, "show_only_selected", PROP_BOOLEAN, PROP_NONE);
RNA_def_property_boolean_sdna(prop, NULL, "filterflag", ADS_FILTER_ONLYSEL);
RNA_def_property_ui_text(
- prop, "Only Selected", "Only include channels relating to selected objects and data");
+ prop, "Only Show Selected", "Only include channels relating to selected objects and data");
RNA_def_property_ui_icon(prop, ICON_RESTRICT_SELECT_OFF, 0);
RNA_def_property_update(prop, NC_ANIMATION | ND_ANIMCHAN | NA_EDITED, NULL);
prop = RNA_def_property(srna, "show_hidden", PROP_BOOLEAN, PROP_NONE);
RNA_def_property_boolean_sdna(prop, NULL, "filterflag", ADS_FILTER_INCL_HIDDEN);
RNA_def_property_ui_text(
- prop, "Display Hidden", "Include channels from objects/bone that are not visible");
+ prop, "Show Hidden", "Include channels from objects/bone that are not visible");
RNA_def_property_ui_icon(prop, ICON_OBJECT_HIDDEN, 0);
RNA_def_property_update(prop, NC_ANIMATION | ND_ANIMCHAN | NA_EDITED, NULL);
@@ -368,8 +368,9 @@ static void rna_def_dopesheet(BlenderRNA *brna)
/* Debug Filtering Settings */
prop = RNA_def_property(srna, "show_only_errors", PROP_BOOLEAN, PROP_NONE);
RNA_def_property_boolean_sdna(prop, NULL, "filterflag", ADS_FILTER_ONLY_ERRORS);
- RNA_def_property_ui_text(
- prop, "Show Errors", "Only include F-Curves and drivers that are disabled or have errors");
+ RNA_def_property_ui_text(prop,
+ "Only Show Errors",
+ "Only include F-Curves and drivers that are disabled or have errors");
RNA_def_property_ui_icon(prop, ICON_ERROR, 0);
RNA_def_property_update(prop, NC_ANIMATION | ND_ANIMCHAN | NA_EDITED, NULL);
@@ -662,6 +663,12 @@ static void rna_def_action_group(BlenderRNA *brna)
prop, "Expanded in Graph Editor", "Action group is expanded in graph editor");
RNA_def_property_update(prop, NC_ANIMATION | ND_ANIMCHAN | NA_EDITED, NULL);
+ prop = RNA_def_property(srna, "use_pin", PROP_BOOLEAN, PROP_NONE);
+ RNA_def_property_flag(prop, PROP_NO_DEG_UPDATE);
+ RNA_def_property_boolean_sdna(prop, NULL, "flag", ADT_CURVES_ALWAYS_VISIBLE);
+ RNA_def_property_ui_text(prop, "Pin in Graph Editor", "");
+ RNA_def_property_update(prop, NC_ANIMATION | ND_ANIMCHAN | NA_EDITED, NULL);
+
/* color set */
rna_def_actionbone_group_common(srna, NC_ANIMATION | ND_ANIMCHAN | NA_EDITED, NULL);
}
diff --git a/source/blender/makesrna/intern/rna_animation.c b/source/blender/makesrna/intern/rna_animation.c
index 036bcfc6311..823446a9d3b 100644
--- a/source/blender/makesrna/intern/rna_animation.c
+++ b/source/blender/makesrna/intern/rna_animation.c
@@ -113,6 +113,7 @@ const EnumPropertyItem rna_enum_keying_flag_items_api[] = {
# include "BLI_math_base.h"
+# include "BKE_anim_data.h"
# include "BKE_animsys.h"
# include "BKE_fcurve.h"
# include "BKE_nla.h"
@@ -193,7 +194,7 @@ static bool RKS_POLL_rna_internal(KeyingSetInfo *ksi, bContext *C)
void *ret;
int ok;
- RNA_pointer_create(NULL, ksi->ext.srna, ksi, &ptr);
+ RNA_pointer_create(NULL, ksi->rna_ext.srna, ksi, &ptr);
func = &rna_KeyingSetInfo_poll_func; /* RNA_struct_find_function(&ptr, "poll"); */
RNA_parameter_list_create(&list, &ptr, func);
@@ -203,7 +204,7 @@ static bool RKS_POLL_rna_internal(KeyingSetInfo *ksi, bContext *C)
RNA_parameter_set_lookup(&list, "context", &C);
/* execute the function */
- ksi->ext.call(C, &ptr, func, &list);
+ ksi->rna_ext.call(C, &ptr, func, &list);
/* read the result */
RNA_parameter_get_lookup(&list, "ok", &ret);
@@ -223,7 +224,7 @@ static void RKS_ITER_rna_internal(KeyingSetInfo *ksi, bContext *C, KeyingSet *ks
ParameterList list;
FunctionRNA *func;
- RNA_pointer_create(NULL, ksi->ext.srna, ksi, &ptr);
+ RNA_pointer_create(NULL, ksi->rna_ext.srna, ksi, &ptr);
func = &rna_KeyingSetInfo_iterator_func; /* RNA_struct_find_function(&ptr, "poll"); */
RNA_parameter_list_create(&list, &ptr, func);
@@ -234,7 +235,7 @@ static void RKS_ITER_rna_internal(KeyingSetInfo *ksi, bContext *C, KeyingSet *ks
RNA_parameter_set_lookup(&list, "ks", &ks);
/* execute the function */
- ksi->ext.call(C, &ptr, func, &list);
+ ksi->rna_ext.call(C, &ptr, func, &list);
}
RNA_parameter_list_free(&list);
}
@@ -248,7 +249,7 @@ static void RKS_GEN_rna_internal(KeyingSetInfo *ksi, bContext *C, KeyingSet *ks,
ParameterList list;
FunctionRNA *func;
- RNA_pointer_create(NULL, ksi->ext.srna, ksi, &ptr);
+ RNA_pointer_create(NULL, ksi->rna_ext.srna, ksi, &ptr);
func = &rna_KeyingSetInfo_generate_func; /* RNA_struct_find_generate(&ptr, "poll"); */
RNA_parameter_list_create(&list, &ptr, func);
@@ -260,7 +261,7 @@ static void RKS_GEN_rna_internal(KeyingSetInfo *ksi, bContext *C, KeyingSet *ks,
RNA_parameter_set_lookup(&list, "data", data);
/* execute the function */
- ksi->ext.call(C, &ptr, func, &list);
+ ksi->rna_ext.call(C, &ptr, func, &list);
}
RNA_parameter_list_free(&list);
}
@@ -272,7 +273,7 @@ static void RKS_GEN_rna_internal(KeyingSetInfo *ksi, bContext *C, KeyingSet *ks,
static StructRNA *rna_KeyingSetInfo_refine(PointerRNA *ptr)
{
KeyingSetInfo *ksi = (KeyingSetInfo *)ptr->data;
- return (ksi->ext.srna) ? ksi->ext.srna : &RNA_KeyingSetInfo;
+ return (ksi->rna_ext.srna) ? ksi->rna_ext.srna : &RNA_KeyingSetInfo;
}
static void rna_KeyingSetInfo_unregister(Main *bmain, StructRNA *type)
@@ -284,7 +285,7 @@ static void rna_KeyingSetInfo_unregister(Main *bmain, StructRNA *type)
}
/* free RNA data referencing this */
- RNA_struct_free_extension(type, &ksi->ext);
+ RNA_struct_free_extension(type, &ksi->rna_ext);
RNA_struct_free(&BLENDER_RNA, type);
WM_main_add_notifier(NC_WINDOW, NULL);
@@ -327,8 +328,8 @@ static StructRNA *rna_KeyingSetInfo_register(Main *bmain,
/* check if we have registered this info before, and remove it */
ksi = ANIM_keyingset_info_find_name(dummyksi.idname);
- if (ksi && ksi->ext.srna) {
- rna_KeyingSetInfo_unregister(bmain, ksi->ext.srna);
+ if (ksi && ksi->rna_ext.srna) {
+ rna_KeyingSetInfo_unregister(bmain, ksi->rna_ext.srna);
}
/* create a new KeyingSetInfo type */
@@ -336,11 +337,11 @@ static StructRNA *rna_KeyingSetInfo_register(Main *bmain,
memcpy(ksi, &dummyksi, sizeof(KeyingSetInfo));
/* set RNA-extensions info */
- ksi->ext.srna = RNA_def_struct_ptr(&BLENDER_RNA, ksi->idname, &RNA_KeyingSetInfo);
- ksi->ext.data = data;
- ksi->ext.call = call;
- ksi->ext.free = free;
- RNA_struct_blender_type_set(ksi->ext.srna, ksi);
+ ksi->rna_ext.srna = RNA_def_struct_ptr(&BLENDER_RNA, ksi->idname, &RNA_KeyingSetInfo);
+ ksi->rna_ext.data = data;
+ ksi->rna_ext.call = call;
+ ksi->rna_ext.free = free;
+ RNA_struct_blender_type_set(ksi->rna_ext.srna, ksi);
/* set callbacks */
/* NOTE: we really should have all of these... */
@@ -354,7 +355,7 @@ static StructRNA *rna_KeyingSetInfo_register(Main *bmain,
WM_main_add_notifier(NC_WINDOW, NULL);
/* return the struct-rna added */
- return ksi->ext.srna;
+ return ksi->rna_ext.srna;
}
/* ****************************** */
@@ -647,7 +648,7 @@ static FCurve *rna_Driver_from_existing(AnimData *adt, bContext *C, FCurve *src_
}
else {
/* just make a copy of the existing one and add to self */
- FCurve *new_fcu = copy_fcurve(src_driver);
+ FCurve *new_fcu = BKE_fcurve_copy(src_driver);
/* XXX: if we impose any ordering on these someday, this will be problematic */
BLI_addtail(&adt->drivers, new_fcu);
@@ -663,7 +664,7 @@ static FCurve *rna_Driver_new(
return NULL;
}
- if (list_find_fcurve(&adt->drivers, rna_path, array_index)) {
+ if (BKE_fcurve_find(&adt->drivers, rna_path, array_index)) {
BKE_reportf(reports, RPT_ERROR, "Driver '%s[%d]' already exists", rna_path, array_index);
return NULL;
}
@@ -682,7 +683,7 @@ static void rna_Driver_remove(AnimData *adt, Main *bmain, ReportList *reports, F
BKE_report(reports, RPT_ERROR, "Driver not found in this animation data");
return;
}
- free_fcurve(fcu);
+ BKE_fcurve_free(fcu);
DEG_relations_tag_update(bmain);
}
@@ -697,7 +698,7 @@ static FCurve *rna_Driver_find(AnimData *adt,
}
/* Returns NULL if not found. */
- return list_find_fcurve(&adt->drivers, data_path, index);
+ return BKE_fcurve_find(&adt->drivers, data_path, index);
}
bool rna_AnimaData_override_apply(Main *UNUSED(bmain),
@@ -1322,6 +1323,12 @@ static void rna_def_animdata(BlenderRNA *brna)
prop, "Use NLA Tweak Mode", "Whether to enable or disable tweak mode in NLA");
RNA_def_property_update(prop, NC_ANIMATION | ND_NLA, "rna_AnimData_update");
+ prop = RNA_def_property(srna, "use_pin", PROP_BOOLEAN, PROP_NONE);
+ RNA_def_property_flag(prop, PROP_NO_DEG_UPDATE);
+ RNA_def_property_boolean_sdna(prop, NULL, "flag", ADT_CURVES_ALWAYS_VISIBLE);
+ RNA_def_property_ui_text(prop, "Pin in Graph Editor", "");
+ RNA_def_property_update(prop, NC_ANIMATION | ND_ANIMCHAN | NA_EDITED, NULL);
+
/* Animation Data API */
RNA_api_animdata(srna);
}
diff --git a/source/blender/makesrna/intern/rna_armature.c b/source/blender/makesrna/intern/rna_armature.c
index 3afbd0405fe..8454d5c125f 100644
--- a/source/blender/makesrna/intern/rna_armature.c
+++ b/source/blender/makesrna/intern/rna_armature.c
@@ -176,6 +176,20 @@ static void rna_Armature_redraw_data(Main *UNUSED(bmain), Scene *UNUSED(scene),
WM_main_add_notifier(NC_GEOM | ND_DATA, id);
}
+/* Unselect bones when hidden */
+static void rna_Bone_hide_update(Main *UNUSED(bmain), Scene *UNUSED(scene), PointerRNA *ptr)
+{
+ bArmature *arm = (bArmature *)ptr->owner_id;
+ Bone *bone = (Bone *)ptr->data;
+
+ if (bone->flag & BONE_HIDDEN_P) {
+ bone->flag &= ~(BONE_SELECTED | BONE_TIPSEL | BONE_ROOTSEL);
+ }
+
+ WM_main_add_notifier(NC_OBJECT | ND_POSE, arm);
+ DEG_id_tag_update(&arm->id, ID_RECALC_COPY_ON_WRITE);
+}
+
/* called whenever a bone is renamed */
static void rna_Bone_update_renamed(Main *UNUSED(bmain), Scene *UNUSED(scene), PointerRNA *ptr)
{
@@ -301,8 +315,7 @@ static void rna_Bone_layer_set(PointerRNA *ptr, const bool *values)
Bone *bone = (Bone *)ptr->data;
rna_bone_layer_set(&bone->layer, values);
-
- BKE_armature_refresh_layer_used(arm);
+ BKE_armature_refresh_layer_used(NULL, arm);
}
/* TODO: remove the deprecation stubs. */
@@ -1144,7 +1157,8 @@ static void rna_def_bone(BlenderRNA *brna)
prop,
"Hide",
"Bone is not visible when it is not in Edit Mode (i.e. in Object or Pose Modes)");
- RNA_def_property_update(prop, 0, "rna_Armature_redraw_data");
+ RNA_def_property_ui_icon(prop, ICON_RESTRICT_VIEW_OFF, -1);
+ RNA_def_property_update(prop, 0, "rna_Bone_hide_update");
prop = RNA_def_property(srna, "select", PROP_BOOLEAN, PROP_NONE);
RNA_def_property_boolean_sdna(prop, NULL, "flag", BONE_SELECTED);
@@ -1313,7 +1327,7 @@ static void rna_def_edit_bone(BlenderRNA *brna)
prop,
"Editbone Matrix",
"Matrix combining loc/rot of the bone (head position, direction and roll), "
- "in armature space (WARNING: does not include/support bone's length/size)");
+ "in armature space (does not include/support bone's length/size)");
RNA_def_property_float_funcs(prop, "rna_EditBone_matrix_get", "rna_EditBone_matrix_set", NULL);
RNA_api_armature_edit_bone(srna);
diff --git a/source/blender/makesrna/intern/rna_brush.c b/source/blender/makesrna/intern/rna_brush.c
index 1a163c9e2eb..209e5a1ff8b 100644
--- a/source/blender/makesrna/intern/rna_brush.c
+++ b/source/blender/makesrna/intern/rna_brush.c
@@ -290,12 +290,12 @@ static EnumPropertyItem rna_enum_gpencil_brush_vertex_icons_items[] = {
# include "RNA_access.h"
-# include "BKE_colorband.h"
# include "BKE_brush.h"
-# include "BKE_icons.h"
+# include "BKE_colorband.h"
# include "BKE_gpencil.h"
-# include "BKE_paint.h"
+# include "BKE_icons.h"
# include "BKE_material.h"
+# include "BKE_paint.h"
# include "WM_api.h"
@@ -1296,6 +1296,48 @@ static void rna_def_gpencil_options(BlenderRNA *brna)
RNA_def_property_clear_flag(prop, PROP_ANIMATABLE);
RNA_def_property_update(prop, NC_GPENCIL | ND_DATA, NULL);
+ prop = RNA_def_property(srna, "curve_random_pressure", PROP_POINTER, PROP_NONE);
+ RNA_def_property_pointer_sdna(prop, NULL, "curve_rand_pressure");
+ RNA_def_property_struct_type(prop, "CurveMapping");
+ RNA_def_property_ui_text(prop, "Random Curve", "Curve used for modulating effect");
+ RNA_def_property_clear_flag(prop, PROP_ANIMATABLE);
+ RNA_def_property_update(prop, NC_GPENCIL | ND_DATA, NULL);
+
+ prop = RNA_def_property(srna, "curve_random_strength", PROP_POINTER, PROP_NONE);
+ RNA_def_property_pointer_sdna(prop, NULL, "curve_rand_strength");
+ RNA_def_property_struct_type(prop, "CurveMapping");
+ RNA_def_property_ui_text(prop, "Random Curve", "Curve used for modulating effect");
+ RNA_def_property_clear_flag(prop, PROP_ANIMATABLE);
+ RNA_def_property_update(prop, NC_GPENCIL | ND_DATA, NULL);
+
+ prop = RNA_def_property(srna, "curve_random_uv", PROP_POINTER, PROP_NONE);
+ RNA_def_property_pointer_sdna(prop, NULL, "curve_rand_uv");
+ RNA_def_property_struct_type(prop, "CurveMapping");
+ RNA_def_property_ui_text(prop, "Random Curve", "Curve used for modulating effect");
+ RNA_def_property_clear_flag(prop, PROP_ANIMATABLE);
+ RNA_def_property_update(prop, NC_GPENCIL | ND_DATA, NULL);
+
+ prop = RNA_def_property(srna, "curve_random_hue", PROP_POINTER, PROP_NONE);
+ RNA_def_property_pointer_sdna(prop, NULL, "curve_rand_hue");
+ RNA_def_property_struct_type(prop, "CurveMapping");
+ RNA_def_property_ui_text(prop, "Random Curve", "Curve used for modulating effect");
+ RNA_def_property_clear_flag(prop, PROP_ANIMATABLE);
+ RNA_def_property_update(prop, NC_GPENCIL | ND_DATA, NULL);
+
+ prop = RNA_def_property(srna, "curve_random_saturation", PROP_POINTER, PROP_NONE);
+ RNA_def_property_pointer_sdna(prop, NULL, "curve_rand_saturation");
+ RNA_def_property_struct_type(prop, "CurveMapping");
+ RNA_def_property_ui_text(prop, "Random Curve", "Curve used for modulating effect");
+ RNA_def_property_clear_flag(prop, PROP_ANIMATABLE);
+ RNA_def_property_update(prop, NC_GPENCIL | ND_DATA, NULL);
+
+ prop = RNA_def_property(srna, "curve_random_value", PROP_POINTER, PROP_NONE);
+ RNA_def_property_pointer_sdna(prop, NULL, "curve_rand_value");
+ RNA_def_property_struct_type(prop, "CurveMapping");
+ RNA_def_property_ui_text(prop, "Random Curve", "Curve used for modulating effect");
+ RNA_def_property_clear_flag(prop, PROP_ANIMATABLE);
+ RNA_def_property_update(prop, NC_GPENCIL | ND_DATA, NULL);
+
/* fill threshold for transparence */
prop = RNA_def_property(srna, "fill_threshold", PROP_FLOAT, PROP_FACTOR);
RNA_def_property_float_sdna(prop, NULL, "fill_threshold");
@@ -1341,12 +1383,14 @@ static void rna_def_gpencil_options(BlenderRNA *brna)
RNA_def_property_update(prop, NC_GPENCIL | ND_DATA, NULL);
/* gradient control */
- prop = RNA_def_property(srna, "hardeness", PROP_FLOAT, PROP_FACTOR);
+ prop = RNA_def_property(srna, "hardness", PROP_FLOAT, PROP_FACTOR);
RNA_def_property_float_sdna(prop, NULL, "hardeness");
RNA_def_property_range(prop, 0.001f, 1.0f);
RNA_def_property_float_default(prop, 1.0f);
RNA_def_property_ui_text(
- prop, "Hardeness", "Amount of gradient for Dot and Box strokes (set to 1 for full solid)");
+ prop,
+ "Hardness",
+ "Gradient from the center of Dot and Box strokes (set to 1 for a solid stroke)");
RNA_def_parameter_clear_flags(prop, PROP_ANIMATABLE, 0);
/* gradient shape ratio */
@@ -1432,6 +1476,30 @@ static void rna_def_gpencil_options(BlenderRNA *brna)
RNA_def_property_ui_text(
prop, "Vertex Color Factor", "Factor used to mix vertex color to get final color");
+ /* Hue randomness. */
+ prop = RNA_def_property(srna, "random_hue_factor", PROP_FLOAT, PROP_FACTOR);
+ RNA_def_property_float_sdna(prop, NULL, "random_hue");
+ RNA_def_property_range(prop, 0.0f, 1.0f);
+ RNA_def_property_float_default(prop, 0.0f);
+ RNA_def_property_ui_text(prop, "Hue", "Random factor to modify original hue");
+ RNA_def_parameter_clear_flags(prop, PROP_ANIMATABLE, 0);
+
+ /* Saturation randomness. */
+ prop = RNA_def_property(srna, "random_saturation_factor", PROP_FLOAT, PROP_FACTOR);
+ RNA_def_property_float_sdna(prop, NULL, "random_saturation");
+ RNA_def_property_range(prop, 0.0f, 1.0f);
+ RNA_def_property_float_default(prop, 0.0f);
+ RNA_def_property_ui_text(prop, "Saturation", "Random factor to modify original saturation");
+ RNA_def_parameter_clear_flags(prop, PROP_ANIMATABLE, 0);
+
+ /* Value randomness. */
+ prop = RNA_def_property(srna, "random_value_factor", PROP_FLOAT, PROP_FACTOR);
+ RNA_def_property_float_sdna(prop, NULL, "random_value");
+ RNA_def_property_range(prop, 0.0f, 1.0f);
+ RNA_def_property_float_default(prop, 0.0f);
+ RNA_def_property_ui_text(prop, "Value", "Random factor to modify original value");
+ RNA_def_parameter_clear_flags(prop, PROP_ANIMATABLE, 0);
+
/* Flags */
prop = RNA_def_property(srna, "use_pressure", PROP_BOOLEAN, PROP_NONE);
RNA_def_property_boolean_sdna(prop, NULL, "flag", GP_BRUSH_USE_PRESSURE);
@@ -1455,6 +1523,90 @@ static void rna_def_gpencil_options(BlenderRNA *brna)
RNA_def_property_clear_flag(prop, PROP_ANIMATABLE);
RNA_def_property_update(prop, NC_GPENCIL | ND_DATA, NULL);
+ prop = RNA_def_property(srna, "use_stroke_random_hue", PROP_BOOLEAN, PROP_NONE);
+ RNA_def_property_boolean_sdna(prop, NULL, "flag2", GP_BRUSH_USE_HUE_AT_STROKE);
+ RNA_def_property_ui_icon(prop, ICON_GP_SELECT_STROKES, 0);
+ RNA_def_property_ui_text(prop, "Stroke Random", "Use randomness at stroke level");
+ RNA_def_property_clear_flag(prop, PROP_ANIMATABLE);
+ RNA_def_property_update(prop, NC_GPENCIL | ND_DATA, NULL);
+
+ prop = RNA_def_property(srna, "use_stroke_random_sat", PROP_BOOLEAN, PROP_NONE);
+ RNA_def_property_boolean_sdna(prop, NULL, "flag2", GP_BRUSH_USE_SAT_AT_STROKE);
+ RNA_def_property_ui_icon(prop, ICON_GP_SELECT_STROKES, 0);
+ RNA_def_property_ui_text(prop, "Stroke Random", "Use randomness at stroke level");
+ RNA_def_property_clear_flag(prop, PROP_ANIMATABLE);
+ RNA_def_property_update(prop, NC_GPENCIL | ND_DATA, NULL);
+
+ prop = RNA_def_property(srna, "use_stroke_random_val", PROP_BOOLEAN, PROP_NONE);
+ RNA_def_property_boolean_sdna(prop, NULL, "flag2", GP_BRUSH_USE_VAL_AT_STROKE);
+ RNA_def_property_ui_icon(prop, ICON_GP_SELECT_STROKES, 0);
+ RNA_def_property_ui_text(prop, "Stroke Random", "Use randomness at stroke level");
+ RNA_def_property_clear_flag(prop, PROP_ANIMATABLE);
+ RNA_def_property_update(prop, NC_GPENCIL | ND_DATA, NULL);
+
+ prop = RNA_def_property(srna, "use_stroke_random_radius", PROP_BOOLEAN, PROP_NONE);
+ RNA_def_property_boolean_sdna(prop, NULL, "flag2", GP_BRUSH_USE_PRESS_AT_STROKE);
+ RNA_def_property_ui_icon(prop, ICON_GP_SELECT_STROKES, 0);
+ RNA_def_property_ui_text(prop, "Stroke Random", "Use randomness at stroke level");
+ RNA_def_property_clear_flag(prop, PROP_ANIMATABLE);
+ RNA_def_property_update(prop, NC_GPENCIL | ND_DATA, NULL);
+
+ prop = RNA_def_property(srna, "use_stroke_random_strength", PROP_BOOLEAN, PROP_NONE);
+ RNA_def_property_boolean_sdna(prop, NULL, "flag2", GP_BRUSH_USE_STRENGTH_AT_STROKE);
+ RNA_def_property_ui_icon(prop, ICON_GP_SELECT_STROKES, 0);
+ RNA_def_property_ui_text(prop, "Stroke Random", "Use randomness at stroke level");
+ RNA_def_property_clear_flag(prop, PROP_ANIMATABLE);
+ RNA_def_property_update(prop, NC_GPENCIL | ND_DATA, NULL);
+
+ prop = RNA_def_property(srna, "use_stroke_random_uv", PROP_BOOLEAN, PROP_NONE);
+ RNA_def_property_boolean_sdna(prop, NULL, "flag2", GP_BRUSH_USE_UV_AT_STROKE);
+ RNA_def_property_ui_icon(prop, ICON_GP_SELECT_STROKES, 0);
+ RNA_def_property_ui_text(prop, "Stroke Random", "Use randomness at stroke level");
+ RNA_def_property_clear_flag(prop, PROP_ANIMATABLE);
+ RNA_def_property_update(prop, NC_GPENCIL | ND_DATA, NULL);
+
+ prop = RNA_def_property(srna, "use_random_press_hue", PROP_BOOLEAN, PROP_NONE);
+ RNA_def_property_boolean_sdna(prop, NULL, "flag2", GP_BRUSH_USE_HUE_RAND_PRESS);
+ RNA_def_property_ui_icon(prop, ICON_STYLUS_PRESSURE, 0);
+ RNA_def_property_ui_text(prop, "Use Pressure", "Use pressure to modulate randomness");
+ RNA_def_property_clear_flag(prop, PROP_ANIMATABLE);
+ RNA_def_property_update(prop, NC_GPENCIL | ND_DATA, NULL);
+
+ prop = RNA_def_property(srna, "use_random_press_sat", PROP_BOOLEAN, PROP_NONE);
+ RNA_def_property_boolean_sdna(prop, NULL, "flag2", GP_BRUSH_USE_SAT_RAND_PRESS);
+ RNA_def_property_ui_icon(prop, ICON_STYLUS_PRESSURE, 0);
+ RNA_def_property_ui_text(prop, "Use Pressure", "Use pressure to modulate randomness");
+ RNA_def_property_clear_flag(prop, PROP_ANIMATABLE);
+ RNA_def_property_update(prop, NC_GPENCIL | ND_DATA, NULL);
+
+ prop = RNA_def_property(srna, "use_random_press_val", PROP_BOOLEAN, PROP_NONE);
+ RNA_def_property_boolean_sdna(prop, NULL, "flag2", GP_BRUSH_USE_VAL_RAND_PRESS);
+ RNA_def_property_ui_icon(prop, ICON_STYLUS_PRESSURE, 0);
+ RNA_def_property_ui_text(prop, "Use Pressure", "Use pressure to modulate randomness");
+ RNA_def_property_clear_flag(prop, PROP_ANIMATABLE);
+ RNA_def_property_update(prop, NC_GPENCIL | ND_DATA, NULL);
+
+ prop = RNA_def_property(srna, "use_random_press_radius", PROP_BOOLEAN, PROP_NONE);
+ RNA_def_property_boolean_sdna(prop, NULL, "flag2", GP_BRUSH_USE_PRESSURE_RAND_PRESS);
+ RNA_def_property_ui_icon(prop, ICON_STYLUS_PRESSURE, 0);
+ RNA_def_property_ui_text(prop, "Use Pressure", "Use pressure to modulate randomness");
+ RNA_def_property_clear_flag(prop, PROP_ANIMATABLE);
+ RNA_def_property_update(prop, NC_GPENCIL | ND_DATA, NULL);
+
+ prop = RNA_def_property(srna, "use_random_press_strength", PROP_BOOLEAN, PROP_NONE);
+ RNA_def_property_boolean_sdna(prop, NULL, "flag2", GP_BRUSH_USE_STRENGTH_RAND_PRESS);
+ RNA_def_property_ui_icon(prop, ICON_STYLUS_PRESSURE, 0);
+ RNA_def_property_ui_text(prop, "Use Pressure", "Use pressure to modulate randomness");
+ RNA_def_property_clear_flag(prop, PROP_ANIMATABLE);
+ RNA_def_property_update(prop, NC_GPENCIL | ND_DATA, NULL);
+
+ prop = RNA_def_property(srna, "use_random_press_uv", PROP_BOOLEAN, PROP_NONE);
+ RNA_def_property_boolean_sdna(prop, NULL, "flag2", GP_BRUSH_USE_UV_RAND_PRESS);
+ RNA_def_property_ui_icon(prop, ICON_STYLUS_PRESSURE, 0);
+ RNA_def_property_ui_text(prop, "Use Pressure", "Use pressure to modulate randomness");
+ RNA_def_property_clear_flag(prop, PROP_ANIMATABLE);
+ RNA_def_property_update(prop, NC_GPENCIL | ND_DATA, NULL);
+
prop = RNA_def_property(srna, "use_settings_stabilizer", PROP_BOOLEAN, PROP_NONE);
RNA_def_property_boolean_sdna(prop, NULL, "flag", GP_BRUSH_STABILIZE_MOUSE);
RNA_def_property_boolean_default(prop, true);
@@ -1804,7 +1956,33 @@ static void rna_def_brush(BlenderRNA *brna)
"SURFACE",
0,
"Surface",
- "Smooths the surface of the mesh, preserving the volue"},
+ "Smooths the surface of the mesh, preserving the volume"},
+ {0, NULL, 0, NULL, NULL},
+ };
+
+ static const EnumPropertyItem brush_pose_deform_type_items[] = {
+ {BRUSH_POSE_DEFORM_ROTATE_TWIST, "ROTATE_TWIST", 0, "Rotate/Twist", ""},
+ {BRUSH_POSE_DEFORM_SCALE_TRASLATE, "SCALE_TRANSLATE", 0, "Scale/Translate", ""},
+ {0, NULL, 0, NULL, NULL},
+ };
+
+ static const EnumPropertyItem brush_pose_origin_type_items[] = {
+ {BRUSH_POSE_ORIGIN_TOPOLOGY,
+ "TOPOLOGY",
+ 0,
+ "Topology",
+ "Sets the rotation origin automatically using the topology and shape of the mesh as a "
+ "guide"},
+ {BRUSH_POSE_ORIGIN_FACE_SETS,
+ "FACE_SETS",
+ 0,
+ "Face Sets",
+ "Creates a pose segment per face sets, starting from the active face set"},
+ {BRUSH_POSE_ORIGIN_FACE_SETS_FK,
+ "FACE_SETS_FK",
+ 0,
+ "Face Sets FK",
+ "Simulates an FK deformation using the Face Set under the cursor as control"},
{0, NULL, 0, NULL, NULL},
};
@@ -1928,6 +2106,18 @@ static void rna_def_brush(BlenderRNA *brna)
RNA_def_property_ui_text(prop, "Deformation", "Deformation type that is used in the brush");
RNA_def_property_update(prop, 0, "rna_Brush_update");
+ prop = RNA_def_property(srna, "pose_deform_type", PROP_ENUM, PROP_NONE);
+ RNA_def_property_enum_items(prop, brush_pose_deform_type_items);
+ RNA_def_property_ui_text(prop, "Deformation", "Deformation type that is used in the brush");
+ RNA_def_property_update(prop, 0, "rna_Brush_update");
+
+ prop = RNA_def_property(srna, "pose_origin_type", PROP_ENUM, PROP_NONE);
+ RNA_def_property_enum_items(prop, brush_pose_origin_type_items);
+ RNA_def_property_ui_text(prop,
+ "Rotation Origins",
+ "Method to set the rotation origins for the segments of the brush");
+ RNA_def_property_update(prop, 0, "rna_Brush_update");
+
prop = RNA_def_property(srna, "jitter_unit", PROP_ENUM, PROP_NONE); /* as an enum */
RNA_def_property_enum_bitflag_sdna(prop, NULL, "flag");
RNA_def_property_enum_items(prop, brush_jitter_unit_items);
@@ -2070,6 +2260,7 @@ static void rna_def_brush(BlenderRNA *brna)
RNA_def_property_float_sdna(prop, NULL, "height");
RNA_def_property_float_default(prop, 0.5f);
RNA_def_property_range(prop, 0, 1.0f);
+ RNA_def_property_ui_range(prop, 0, 0.2f, 1, 3);
RNA_def_property_ui_text(
prop, "Brush Height", "Affectable height of brush (layer height for layer tool, i.e.)");
RNA_def_property_update(prop, 0, "rna_Brush_update");
@@ -2177,7 +2368,7 @@ static void rna_def_brush(BlenderRNA *brna)
prop = RNA_def_property(srna, "cloth_mass", PROP_FLOAT, PROP_FACTOR);
RNA_def_property_float_sdna(prop, NULL, "cloth_mass");
RNA_def_property_range(prop, 0.01f, 2.0f);
- RNA_def_property_ui_text(prop, "Cloth mass", "Mass of each simulation particle");
+ RNA_def_property_ui_text(prop, "Cloth Mass", "Mass of each simulation particle");
RNA_def_property_update(prop, 0, "rna_Brush_update");
prop = RNA_def_property(srna, "cloth_damping", PROP_FLOAT, PROP_FACTOR);
@@ -2218,7 +2409,7 @@ static void rna_def_brush(BlenderRNA *brna)
RNA_def_property_ui_range(prop, 1, 20, 1, 3);
RNA_def_property_ui_text(prop,
"Propagation Steps",
- "Distance where boundary edge automaking is going to protect vertices "
+ "Distance where boundary edge automasking is going to protect vertices "
"from the fully masked edge");
RNA_def_property_update(prop, 0, "rna_Brush_update");
@@ -2364,7 +2555,16 @@ static void rna_def_brush(BlenderRNA *brna)
prop = RNA_def_property(srna, "use_automasking_boundary_edges", PROP_BOOLEAN, PROP_NONE);
RNA_def_property_boolean_sdna(prop, NULL, "automasking_flags", BRUSH_AUTOMASKING_BOUNDARY_EDGES);
- RNA_def_property_ui_text(prop, "Edges Automasking", "Do not affect non manifold boundary edges");
+ RNA_def_property_ui_text(
+ prop, "Mesh Boundary Auto-masking", "Do not affect non manifold boundary edges");
+ RNA_def_property_update(prop, 0, "rna_Brush_update");
+
+ prop = RNA_def_property(srna, "use_automasking_boundary_face_sets", PROP_BOOLEAN, PROP_NONE);
+ RNA_def_property_boolean_sdna(
+ prop, NULL, "automasking_flags", BRUSH_AUTOMASKING_BOUNDARY_FACE_SETS);
+ RNA_def_property_ui_text(prop,
+ "Face Sets Boundary Automasking",
+ "Do not affect vertices that belong to a Face Set boundary");
RNA_def_property_update(prop, 0, "rna_Brush_update");
prop = RNA_def_property(srna, "use_scene_spacing", PROP_ENUM, PROP_NONE);
diff --git a/source/blender/makesrna/intern/rna_camera.c b/source/blender/makesrna/intern/rna_camera.c
index 47a09233769..79ee9619e36 100644
--- a/source/blender/makesrna/intern/rna_camera.c
+++ b/source/blender/makesrna/intern/rna_camera.c
@@ -193,6 +193,8 @@ static void rna_def_camera_background_image(BlenderRNA *brna)
RNA_def_struct_ui_text(
srna, "Background Image", "Image and settings for display in the 3D View background");
+ RNA_define_lib_overridable(true);
+
prop = RNA_def_property(srna, "source", PROP_ENUM, PROP_NONE);
RNA_def_property_enum_sdna(prop, NULL, "source");
RNA_def_property_enum_items(prop, bgpic_source_items);
@@ -301,6 +303,8 @@ static void rna_def_camera_background_image(BlenderRNA *brna)
RNA_def_property_enum_items(prop, bgpic_camera_frame_items);
RNA_def_property_ui_text(prop, "Frame Method", "How the image fits in the camera frame");
RNA_def_property_update(prop, NC_SPACE | ND_SPACE_VIEW3D, NULL);
+
+ RNA_define_lib_overridable(false);
}
static void rna_def_camera_background_images(BlenderRNA *brna, PropertyRNA *cprop)
@@ -356,6 +360,8 @@ static void rna_def_camera_stereo_data(BlenderRNA *brna)
RNA_def_struct_nested(brna, srna, "Camera");
RNA_def_struct_ui_text(srna, "Stereo", "Stereoscopy settings for a Camera data-block");
+ RNA_define_lib_overridable(true);
+
prop = RNA_def_property(srna, "convergence_mode", PROP_ENUM, PROP_NONE);
RNA_def_property_enum_items(prop, convergence_mode_items);
RNA_def_property_ui_text(prop, "Mode", "");
@@ -409,6 +415,8 @@ static void rna_def_camera_stereo_data(BlenderRNA *brna)
RNA_def_property_ui_text(
prop, "Pole Merge End Angle", "Angle at which interocular distance is 0");
RNA_def_property_update(prop, NC_OBJECT | ND_DRAW, NULL);
+
+ RNA_define_lib_overridable(false);
}
static void rna_def_camera_dof_settings_data(BlenderRNA *brna)
@@ -421,6 +429,8 @@ static void rna_def_camera_dof_settings_data(BlenderRNA *brna)
RNA_def_struct_path_func(srna, "rna_CameraDOFSettings_path");
RNA_def_struct_ui_text(srna, "Depth of Field", "Depth of Field settings");
+ RNA_define_lib_overridable(true);
+
prop = RNA_def_property(srna, "use_dof", PROP_BOOLEAN, PROP_NONE);
RNA_def_property_boolean_sdna(prop, NULL, "flag", CAM_DOF_ENABLED);
RNA_def_property_ui_text(prop, "Depth of Field", "Use Depth of Field");
@@ -469,6 +479,8 @@ static void rna_def_camera_dof_settings_data(BlenderRNA *brna)
RNA_def_property_range(prop, 0.01f, FLT_MAX);
RNA_def_property_ui_range(prop, 1.0f, 2.0f, 0.1, 3);
RNA_def_property_update(prop, NC_OBJECT | ND_DRAW, "rna_Camera_dof_update");
+
+ RNA_define_lib_overridable(false);
}
void RNA_def_camera(BlenderRNA *brna)
@@ -505,6 +517,8 @@ void RNA_def_camera(BlenderRNA *brna)
RNA_def_struct_ui_text(srna, "Camera", "Camera data-block for storing camera settings");
RNA_def_struct_ui_icon(srna, ICON_CAMERA_DATA);
+ RNA_define_lib_overridable(true);
+
/* Enums */
prop = RNA_def_property(srna, "type", PROP_ENUM, PROP_NONE);
RNA_def_property_enum_items(prop, prop_type_items);
@@ -736,6 +750,8 @@ void RNA_def_camera(BlenderRNA *brna)
RNA_def_property_ui_text(prop, "Background Images", "List of background images");
RNA_def_property_update(prop, NC_SPACE | ND_SPACE_VIEW3D, NULL);
+ RNA_define_lib_overridable(false);
+
rna_def_animdata_common(srna);
rna_def_camera_background_image(brna);
diff --git a/source/blender/makesrna/intern/rna_cloth.c b/source/blender/makesrna/intern/rna_cloth.c
index 1dae78b9efd..70f219259ef 100644
--- a/source/blender/makesrna/intern/rna_cloth.c
+++ b/source/blender/makesrna/intern/rna_cloth.c
@@ -63,7 +63,8 @@ static void rna_cloth_pinning_changed(Main *UNUSED(bmain), Scene *UNUSED(scene),
{
Object *ob = (Object *)ptr->owner_id;
/* ClothSimSettings *settings = (ClothSimSettings *)ptr->data; */
- ClothModifierData *clmd = (ClothModifierData *)modifiers_findByType(ob, eModifierType_Cloth);
+ ClothModifierData *clmd = (ClothModifierData *)BKE_modifiers_findby_type(ob,
+ eModifierType_Cloth);
cloth_free_modifier(clmd);
@@ -434,7 +435,7 @@ static void rna_ClothSettings_gravity_set(PointerRNA *ptr, const float *values)
static char *rna_ClothSettings_path(PointerRNA *ptr)
{
Object *ob = (Object *)ptr->owner_id;
- ModifierData *md = modifiers_findByType(ob, eModifierType_Cloth);
+ ModifierData *md = BKE_modifiers_findby_type(ob, eModifierType_Cloth);
if (md) {
char name_esc[sizeof(md->name) * 2];
@@ -449,7 +450,7 @@ static char *rna_ClothSettings_path(PointerRNA *ptr)
static char *rna_ClothCollisionSettings_path(PointerRNA *ptr)
{
Object *ob = (Object *)ptr->owner_id;
- ModifierData *md = modifiers_findByType(ob, eModifierType_Cloth);
+ ModifierData *md = BKE_modifiers_findby_type(ob, eModifierType_Cloth);
if (md) {
char name_esc[sizeof(md->name) * 2];
diff --git a/source/blender/makesrna/intern/rna_collection.c b/source/blender/makesrna/intern/rna_collection.c
index 709be0cf842..fbc2b871026 100644
--- a/source/blender/makesrna/intern/rna_collection.c
+++ b/source/blender/makesrna/intern/rna_collection.c
@@ -82,6 +82,23 @@ static void rna_Collection_objects_link(Collection *collection,
ReportList *reports,
Object *object)
{
+ /* Currently this should not be allowed (might be supported in the future though...). */
+ if (ID_IS_OVERRIDE_LIBRARY(&collection->id)) {
+ BKE_reportf(reports,
+ RPT_ERROR,
+ "Could not link the object '%s' because the collection '%s' is overridden.",
+ object->id.name + 2,
+ collection->id.name + 2);
+ return;
+ }
+ if (ID_IS_LINKED(&collection->id)) {
+ BKE_reportf(reports,
+ RPT_ERROR,
+ "Could not link the object '%s' because the collection '%s' is linked.",
+ object->id.name + 2,
+ collection->id.name + 2);
+ return;
+ }
if (!BKE_collection_object_add(bmain, collection, object)) {
BKE_reportf(reports,
RPT_ERROR,
@@ -377,6 +394,8 @@ void RNA_def_collections(BlenderRNA *brna)
* removed if no objects are in the collection and not in a scene. */
RNA_def_struct_clear_flag(srna, STRUCT_ID_REFCOUNT);
+ RNA_define_lib_overridable(true);
+
prop = RNA_def_property(srna, "instance_offset", PROP_FLOAT, PROP_TRANSLATION);
RNA_def_property_ui_text(
prop, "Instance Offset", "Offset from the origin to use when instancing");
@@ -385,7 +404,6 @@ void RNA_def_collections(BlenderRNA *brna)
prop = RNA_def_property(srna, "objects", PROP_COLLECTION, PROP_NONE);
RNA_def_property_struct_type(prop, "Object");
- RNA_def_property_override_flag(prop, PROPOVERRIDE_OVERRIDABLE_LIBRARY);
RNA_def_property_override_funcs(prop, NULL, NULL, "rna_Collection_objects_override_apply");
RNA_def_property_ui_text(prop, "Objects", "Objects that are directly in this collection");
RNA_def_property_collection_funcs(prop,
@@ -404,6 +422,7 @@ void RNA_def_collections(BlenderRNA *brna)
RNA_def_property_ui_text(
prop, "All Objects", "Objects that are in this collection and its child collections");
RNA_def_property_override_flag(prop, PROPOVERRIDE_NO_COMPARISON);
+ RNA_def_property_override_clear_flag(prop, PROPOVERRIDE_OVERRIDABLE_LIBRARY);
RNA_def_property_collection_funcs(prop,
"rna_Collection_all_objects_begin",
"rna_iterator_listbase_next",
@@ -416,7 +435,6 @@ void RNA_def_collections(BlenderRNA *brna)
prop = RNA_def_property(srna, "children", PROP_COLLECTION, PROP_NONE);
RNA_def_property_struct_type(prop, "Collection");
- RNA_def_property_override_flag(prop, PROPOVERRIDE_OVERRIDABLE_LIBRARY);
RNA_def_property_override_funcs(prop, NULL, NULL, "rna_Collection_children_override_apply");
RNA_def_property_ui_text(
prop, "Children", "Collections that are immediate children of this collection");
@@ -435,7 +453,6 @@ void RNA_def_collections(BlenderRNA *brna)
prop = RNA_def_property(srna, "hide_select", PROP_BOOLEAN, PROP_NONE);
RNA_def_property_boolean_sdna(prop, NULL, "flag", COLLECTION_RESTRICT_SELECT);
RNA_def_property_boolean_funcs(prop, NULL, "rna_Collection_hide_select_set");
- RNA_def_property_override_flag(prop, PROPOVERRIDE_OVERRIDABLE_LIBRARY);
RNA_def_property_clear_flag(prop, PROP_ANIMATABLE);
RNA_def_property_ui_icon(prop, ICON_RESTRICT_SELECT_OFF, -1);
RNA_def_property_ui_text(prop, "Disable Selection", "Disable selection in viewport");
@@ -444,7 +461,6 @@ void RNA_def_collections(BlenderRNA *brna)
prop = RNA_def_property(srna, "hide_viewport", PROP_BOOLEAN, PROP_NONE);
RNA_def_property_boolean_sdna(prop, NULL, "flag", COLLECTION_RESTRICT_VIEWPORT);
RNA_def_property_boolean_funcs(prop, NULL, "rna_Collection_hide_viewport_set");
- RNA_def_property_override_flag(prop, PROPOVERRIDE_OVERRIDABLE_LIBRARY);
RNA_def_property_clear_flag(prop, PROP_ANIMATABLE);
RNA_def_property_ui_icon(prop, ICON_RESTRICT_VIEW_OFF, -1);
RNA_def_property_ui_text(prop, "Disable in Viewports", "Globally disable in viewports");
@@ -453,11 +469,12 @@ void RNA_def_collections(BlenderRNA *brna)
prop = RNA_def_property(srna, "hide_render", PROP_BOOLEAN, PROP_NONE);
RNA_def_property_boolean_sdna(prop, NULL, "flag", COLLECTION_RESTRICT_RENDER);
RNA_def_property_boolean_funcs(prop, NULL, "rna_Collection_hide_render_set");
- RNA_def_property_override_flag(prop, PROPOVERRIDE_OVERRIDABLE_LIBRARY);
RNA_def_property_clear_flag(prop, PROP_ANIMATABLE);
RNA_def_property_ui_icon(prop, ICON_RESTRICT_RENDER_OFF, -1);
RNA_def_property_ui_text(prop, "Disable in Renders", "Globally disable in renders");
RNA_def_property_update(prop, NC_SCENE | ND_LAYER_CONTENT, "rna_Collection_flag_update");
+
+ RNA_define_lib_overridable(false);
}
#endif
diff --git a/source/blender/makesrna/intern/rna_constraint.c b/source/blender/makesrna/intern/rna_constraint.c
index dc0cde953f4..49a7bec7b00 100644
--- a/source/blender/makesrna/intern/rna_constraint.c
+++ b/source/blender/makesrna/intern/rna_constraint.c
@@ -389,7 +389,7 @@ static void rna_Constraint_name_set(PointerRNA *ptr, const char *value)
/* make sure name is unique */
if (ptr->owner_id) {
Object *ob = (Object *)ptr->owner_id;
- ListBase *list = get_constraint_lb(ob, con, NULL);
+ ListBase *list = ED_object_constraint_list_from_constraint(ob, con, NULL);
/* if we have the list, check for unique name, otherwise give up */
if (list) {
@@ -404,7 +404,7 @@ static void rna_Constraint_name_set(PointerRNA *ptr, const char *value)
static char *rna_Constraint_do_compute_path(Object *ob, bConstraint *con)
{
bPoseChannel *pchan;
- ListBase *lb = get_constraint_lb(ob, con, &pchan);
+ ListBase *lb = ED_object_constraint_list_from_constraint(ob, con, &pchan);
if (lb == NULL) {
printf("%s: internal error, constraint '%s' not found in object '%s'\n",
@@ -824,6 +824,8 @@ static void rna_def_constraint_headtail_common(StructRNA *srna)
{
PropertyRNA *prop;
+ RNA_define_lib_overridable(true);
+
prop = RNA_def_property(srna, "head_tail", PROP_FLOAT, PROP_FACTOR);
RNA_def_property_float_sdna(prop, "bConstraint", "headtail");
RNA_def_property_ui_text(prop, "Head/Tail", "Target along length of bone: Head=0, Tail=1");
@@ -835,12 +837,16 @@ static void rna_def_constraint_headtail_common(StructRNA *srna)
"Follow B-Bone",
"Follow shape of B-Bone segments when calculating Head/Tail position");
RNA_def_property_update(prop, NC_OBJECT | ND_CONSTRAINT, "rna_Constraint_dependency_update");
+
+ RNA_define_lib_overridable(false);
}
static void rna_def_constraint_target_common(StructRNA *srna)
{
PropertyRNA *prop;
+ RNA_define_lib_overridable(true);
+
prop = RNA_def_property(srna, "target", PROP_POINTER, PROP_NONE);
RNA_def_property_pointer_sdna(prop, NULL, "tar");
RNA_def_property_ui_text(prop, "Target", "Target object");
@@ -852,6 +858,8 @@ static void rna_def_constraint_target_common(StructRNA *srna)
RNA_def_property_string_sdna(prop, NULL, "subtarget");
RNA_def_property_ui_text(prop, "Sub-Target", "Armature bone, mesh or lattice vertex group, ...");
RNA_def_property_update(prop, NC_OBJECT | ND_CONSTRAINT, "rna_Constraint_dependency_update");
+
+ RNA_define_lib_overridable(false);
}
static void rna_def_constrainttarget(BlenderRNA *brna)
@@ -864,6 +872,8 @@ static void rna_def_constrainttarget(BlenderRNA *brna)
RNA_def_struct_path_func(srna, "rna_ConstraintTarget_path");
RNA_def_struct_sdna(srna, "bConstraintTarget");
+ RNA_define_lib_overridable(true);
+
prop = RNA_def_property(srna, "target", PROP_POINTER, PROP_NONE);
RNA_def_property_pointer_sdna(prop, NULL, "tar");
RNA_def_property_ui_text(prop, "Target", "Target object");
@@ -879,6 +889,8 @@ static void rna_def_constrainttarget(BlenderRNA *brna)
prop, NC_OBJECT | ND_CONSTRAINT, "rna_ConstraintTarget_dependency_update");
/* space, flag and type still to do */
+
+ RNA_define_lib_overridable(false);
}
static void rna_def_constrainttarget_bone(BlenderRNA *brna)
@@ -892,6 +904,8 @@ static void rna_def_constrainttarget_bone(BlenderRNA *brna)
RNA_def_struct_path_func(srna, "rna_ConstraintTarget_path");
RNA_def_struct_sdna(srna, "bConstraintTarget");
+ RNA_define_lib_overridable(true);
+
prop = RNA_def_property(srna, "target", PROP_POINTER, PROP_NONE);
RNA_def_property_pointer_sdna(prop, NULL, "tar");
RNA_def_property_ui_text(prop, "Target", "Target armature");
@@ -913,6 +927,8 @@ static void rna_def_constrainttarget_bone(BlenderRNA *brna)
RNA_def_property_range(prop, 0.0f, 1.0f);
RNA_def_property_ui_text(prop, "Blend Weight", "Blending weight of this bone");
RNA_def_property_update(prop, NC_OBJECT | ND_CONSTRAINT, "rna_ConstraintTarget_update");
+
+ RNA_define_lib_overridable(false);
}
static void rna_def_constraint_childof(BlenderRNA *brna)
@@ -928,6 +944,8 @@ static void rna_def_constraint_childof(BlenderRNA *brna)
rna_def_constraint_target_common(srna);
+ RNA_define_lib_overridable(true);
+
prop = RNA_def_property(srna, "use_location_x", PROP_BOOLEAN, PROP_NONE);
RNA_def_property_boolean_sdna(prop, NULL, "flag", CHILDOF_LOCX);
RNA_def_property_ui_text(prop, "Location X", "Use X Location of Parent");
@@ -985,6 +1003,8 @@ static void rna_def_constraint_childof(BlenderRNA *brna)
RNA_def_property_clear_flag(prop, PROP_ANIMATABLE);
RNA_def_property_ui_text(prop, "Inverse Matrix", "Transformation matrix to apply before");
RNA_def_property_update(prop, NC_OBJECT | ND_CONSTRAINT, "rna_Constraint_update");
+
+ RNA_define_lib_overridable(false);
}
static void rna_def_constraint_python(BlenderRNA *brna)
@@ -996,6 +1016,8 @@ static void rna_def_constraint_python(BlenderRNA *brna)
RNA_def_struct_ui_text(srna, "Python Constraint", "Use Python script for constraint evaluation");
RNA_def_struct_sdna_from(srna, "bPythonConstraint", "data");
+ RNA_define_lib_overridable(true);
+
prop = RNA_def_property(srna, "targets", PROP_COLLECTION, PROP_NONE);
RNA_def_property_collection_sdna(prop, NULL, "targets", NULL);
RNA_def_property_struct_type(prop, "ConstraintTarget");
@@ -1021,6 +1043,8 @@ static void rna_def_constraint_python(BlenderRNA *brna)
RNA_def_property_boolean_sdna(prop, NULL, "flag", PYCON_SCRIPTERROR);
RNA_def_property_clear_flag(prop, PROP_EDITABLE);
RNA_def_property_ui_text(prop, "Script Error", "The linked Python script has thrown an error");
+
+ RNA_define_lib_overridable(false);
}
static void rna_def_constraint_armature_deform_targets(BlenderRNA *brna, PropertyRNA *cprop)
@@ -1065,6 +1089,8 @@ static void rna_def_constraint_armature_deform(BlenderRNA *brna)
RNA_def_struct_sdna_from(srna, "bArmatureConstraint", "data");
RNA_def_struct_ui_icon(srna, ICON_CON_ARMATURE);
+ RNA_define_lib_overridable(true);
+
prop = RNA_def_property(srna, "targets", PROP_COLLECTION, PROP_NONE);
RNA_def_property_collection_sdna(prop, NULL, "targets", NULL);
RNA_def_property_struct_type(prop, "ConstraintTargetBone");
@@ -1095,6 +1121,8 @@ static void rna_def_constraint_armature_deform(BlenderRNA *brna)
"Use the current bone location for envelopes and choosing B-Bone "
"segments instead of rest position");
RNA_def_property_update(prop, NC_OBJECT | ND_CONSTRAINT, "rna_Constraint_update");
+
+ RNA_define_lib_overridable(false);
}
static void rna_def_constraint_kinematic(BlenderRNA *brna)
@@ -1121,6 +1149,8 @@ static void rna_def_constraint_kinematic(BlenderRNA *brna)
rna_def_constraint_target_common(srna);
+ RNA_define_lib_overridable(true);
+
prop = RNA_def_property(srna, "iterations", PROP_INT, PROP_NONE);
RNA_def_property_range(prop, 0, 10000);
RNA_def_property_ui_text(prop, "Iterations", "Maximum number of solving iterations");
@@ -1240,6 +1270,8 @@ static void rna_def_constraint_kinematic(BlenderRNA *brna)
RNA_def_property_range(prop, 0.0, 100.f);
RNA_def_property_ui_text(prop, "Distance", "Radius of limiting sphere");
RNA_def_property_update(prop, NC_OBJECT | ND_CONSTRAINT, "rna_Constraint_update");
+
+ RNA_define_lib_overridable(false);
}
static void rna_def_constraint_track_to(BlenderRNA *brna)
@@ -1266,6 +1298,8 @@ static void rna_def_constraint_track_to(BlenderRNA *brna)
RNA_def_struct_ui_icon(srna, ICON_CON_TRACKTO);
+ RNA_define_lib_overridable(true);
+
prop = RNA_def_property(srna, "track_axis", PROP_ENUM, PROP_NONE);
RNA_def_property_enum_sdna(prop, NULL, "reserved1");
RNA_def_property_enum_items(prop, track_axis_items);
@@ -1283,6 +1317,8 @@ static void rna_def_constraint_track_to(BlenderRNA *brna)
RNA_def_property_ui_text(
prop, "Target Z", "Target's Z axis, not World Z axis, will constraint the Up direction");
RNA_def_property_update(prop, NC_OBJECT | ND_CONSTRAINT, "rna_Constraint_update");
+
+ RNA_define_lib_overridable(false);
}
static void rna_def_constraint_locate_like(BlenderRNA *brna)
@@ -1300,6 +1336,8 @@ static void rna_def_constraint_locate_like(BlenderRNA *brna)
rna_def_constraint_target_common(srna);
+ RNA_define_lib_overridable(true);
+
prop = RNA_def_property(srna, "use_x", PROP_BOOLEAN, PROP_NONE);
RNA_def_property_boolean_sdna(prop, NULL, "flag", LOCLIKE_X);
RNA_def_property_ui_text(prop, "Copy X", "Copy the target's X location");
@@ -1334,6 +1372,8 @@ static void rna_def_constraint_locate_like(BlenderRNA *brna)
RNA_def_property_boolean_sdna(prop, NULL, "flag", LOCLIKE_OFFSET);
RNA_def_property_ui_text(prop, "Offset", "Add original location into copied location");
RNA_def_property_update(prop, NC_OBJECT | ND_CONSTRAINT, "rna_Constraint_update");
+
+ RNA_define_lib_overridable(false);
}
static void rna_def_constraint_rotate_like(BlenderRNA *brna)
@@ -1370,6 +1410,8 @@ static void rna_def_constraint_rotate_like(BlenderRNA *brna)
rna_def_constraint_target_common(srna);
+ RNA_define_lib_overridable(true);
+
prop = RNA_def_property(srna, "use_x", PROP_BOOLEAN, PROP_NONE);
RNA_def_property_boolean_sdna(prop, NULL, "flag", ROTLIKE_X);
RNA_def_property_ui_text(prop, "Copy X", "Copy the target's X rotation");
@@ -1420,6 +1462,8 @@ static void rna_def_constraint_rotate_like(BlenderRNA *brna)
RNA_def_property_ui_text(
prop, "Offset", "DEPRECATED: Add original rotation into copied rotation");
RNA_def_property_update(prop, NC_OBJECT | ND_CONSTRAINT, "rna_Constraint_update");
+
+ RNA_define_lib_overridable(false);
}
static void rna_def_constraint_size_like(BlenderRNA *brna)
@@ -1434,6 +1478,8 @@ static void rna_def_constraint_size_like(BlenderRNA *brna)
rna_def_constraint_target_common(srna);
+ RNA_define_lib_overridable(true);
+
prop = RNA_def_property(srna, "use_x", PROP_BOOLEAN, PROP_NONE);
RNA_def_property_boolean_sdna(prop, NULL, "flag", SIZELIKE_X);
RNA_def_property_ui_text(prop, "Copy X", "Copy the target's X scale");
@@ -1476,6 +1522,8 @@ static void rna_def_constraint_size_like(BlenderRNA *brna)
"Additive",
"Use addition instead of multiplication to combine scale (2.7 compatibility)");
RNA_def_property_update(prop, NC_OBJECT | ND_CONSTRAINT, "rna_Constraint_update");
+
+ RNA_define_lib_overridable(false);
}
static void rna_def_constraint_same_volume(BlenderRNA *brna)
@@ -1518,6 +1566,8 @@ static void rna_def_constraint_same_volume(BlenderRNA *brna)
RNA_def_struct_sdna_from(srna, "bSameVolumeConstraint", "data");
RNA_def_struct_ui_icon(srna, ICON_CON_SAMEVOL);
+ RNA_define_lib_overridable(true);
+
prop = RNA_def_property(srna, "free_axis", PROP_ENUM, PROP_NONE);
RNA_def_property_enum_sdna(prop, NULL, "free_axis");
RNA_def_property_enum_items(prop, axis_items);
@@ -1535,6 +1585,8 @@ static void rna_def_constraint_same_volume(BlenderRNA *brna)
RNA_def_property_range(prop, 0.001f, 100.0f);
RNA_def_property_ui_text(prop, "Volume", "Volume of the bone at rest");
RNA_def_property_update(prop, NC_OBJECT | ND_CONSTRAINT, "rna_Constraint_update");
+
+ RNA_define_lib_overridable(false);
}
static void rna_def_constraint_transform_like(BlenderRNA *brna)
@@ -1575,12 +1627,16 @@ static void rna_def_constraint_transform_like(BlenderRNA *brna)
rna_def_constraint_target_common(srna);
+ RNA_define_lib_overridable(true);
+
prop = RNA_def_property(srna, "mix_mode", PROP_ENUM, PROP_NONE);
RNA_def_property_enum_sdna(prop, NULL, "mix_mode");
RNA_def_property_enum_items(prop, mix_mode_items);
RNA_def_property_ui_text(
prop, "Mix Mode", "Specify how the copied and existing transformations are combined");
RNA_def_property_update(prop, NC_OBJECT | ND_CONSTRAINT, "rna_Constraint_update");
+
+ RNA_define_lib_overridable(false);
}
static void rna_def_constraint_minmax(BlenderRNA *brna)
@@ -1606,6 +1662,8 @@ static void rna_def_constraint_minmax(BlenderRNA *brna)
rna_def_constraint_target_common(srna);
+ RNA_define_lib_overridable(true);
+
prop = RNA_def_property(srna, "floor_location", PROP_ENUM, PROP_NONE);
RNA_def_property_enum_sdna(prop, NULL, "minmaxflag");
RNA_def_property_enum_items(prop, minmax_items);
@@ -1622,6 +1680,8 @@ static void rna_def_constraint_minmax(BlenderRNA *brna)
RNA_def_property_ui_range(prop, -100.0f, 100.0f, 1, -1);
RNA_def_property_ui_text(prop, "Offset", "Offset of floor from object origin");
RNA_def_property_update(prop, NC_OBJECT | ND_CONSTRAINT, "rna_Constraint_update");
+
+ RNA_define_lib_overridable(false);
}
static void rna_def_constraint_action(BlenderRNA *brna)
@@ -1673,6 +1733,8 @@ static void rna_def_constraint_action(BlenderRNA *brna)
rna_def_constraint_target_common(srna);
+ RNA_define_lib_overridable(true);
+
prop = RNA_def_property(srna, "mix_mode", PROP_ENUM, PROP_NONE);
RNA_def_property_enum_sdna(prop, NULL, "mix_mode");
RNA_def_property_enum_items(prop, mix_mode_items);
@@ -1733,6 +1795,8 @@ static void rna_def_constraint_action(BlenderRNA *brna)
RNA_def_property_ui_text(prop, "Minimum", "Minimum value for target channel range");
RNA_def_property_update(prop, NC_OBJECT | ND_CONSTRAINT, "rna_Constraint_update");
RNA_def_property_float_funcs(prop, NULL, NULL, "rna_ActionConstraint_minmax_range");
+
+ RNA_define_lib_overridable(false);
}
static void rna_def_constraint_locked_track(BlenderRNA *brna)
@@ -1760,6 +1824,8 @@ static void rna_def_constraint_locked_track(BlenderRNA *brna)
rna_def_constraint_target_common(srna);
+ RNA_define_lib_overridable(true);
+
prop = RNA_def_property(srna, "track_axis", PROP_ENUM, PROP_NONE);
RNA_def_property_enum_sdna(prop, NULL, "trackflag");
RNA_def_property_enum_items(prop, track_axis_items);
@@ -1771,6 +1837,8 @@ static void rna_def_constraint_locked_track(BlenderRNA *brna)
RNA_def_property_enum_items(prop, lock_items);
RNA_def_property_ui_text(prop, "Locked Axis", "Axis that points upward");
RNA_def_property_update(prop, NC_OBJECT | ND_CONSTRAINT, "rna_Constraint_update");
+
+ RNA_define_lib_overridable(false);
}
static void rna_def_constraint_follow_path(BlenderRNA *brna)
@@ -1800,6 +1868,8 @@ static void rna_def_constraint_follow_path(BlenderRNA *brna)
RNA_def_struct_sdna_from(srna, "bFollowPathConstraint", "data");
RNA_def_struct_ui_icon(srna, ICON_CON_FOLLOWPATH);
+ RNA_define_lib_overridable(true);
+
prop = RNA_def_property(srna, "target", PROP_POINTER, PROP_NONE);
RNA_def_property_pointer_sdna(prop, NULL, "tar");
RNA_def_property_pointer_funcs(prop, NULL, NULL, NULL, "rna_Curve_object_poll");
@@ -1852,6 +1922,8 @@ static void rna_def_constraint_follow_path(BlenderRNA *brna)
RNA_def_property_boolean_sdna(prop, NULL, "followflag", FOLLOWPATH_RADIUS);
RNA_def_property_ui_text(prop, "Curve Radius", "Object is scaled by the curve radius");
RNA_def_property_update(prop, NC_OBJECT | ND_CONSTRAINT, "rna_Constraint_update");
+
+ RNA_define_lib_overridable(false);
}
static void rna_def_constraint_stretch_to(BlenderRNA *brna)
@@ -1888,6 +1960,8 @@ static void rna_def_constraint_stretch_to(BlenderRNA *brna)
rna_def_constraint_target_common(srna);
+ RNA_define_lib_overridable(true);
+
prop = RNA_def_property(srna, "volume", PROP_ENUM, PROP_NONE);
RNA_def_property_enum_sdna(prop, NULL, "volmode");
RNA_def_property_enum_items(prop, volume_items);
@@ -1941,6 +2015,8 @@ static void rna_def_constraint_stretch_to(BlenderRNA *brna)
RNA_def_property_ui_text(
prop, "Volume Variation Smoothness", "Strength of volume stretching clamping");
RNA_def_property_update(prop, NC_OBJECT | ND_CONSTRAINT, "rna_Constraint_update");
+
+ RNA_define_lib_overridable(false);
}
static void rna_def_constraint_clamp_to(BlenderRNA *brna)
@@ -1964,6 +2040,8 @@ static void rna_def_constraint_clamp_to(BlenderRNA *brna)
RNA_def_struct_sdna_from(srna, "bClampToConstraint", "data");
RNA_def_struct_ui_icon(srna, ICON_CON_CLAMPTO);
+ RNA_define_lib_overridable(true);
+
prop = RNA_def_property(srna, "target", PROP_POINTER, PROP_NONE);
RNA_def_property_pointer_sdna(prop, NULL, "tar");
RNA_def_property_pointer_funcs(prop, NULL, NULL, NULL, "rna_Curve_object_poll");
@@ -1983,6 +2061,8 @@ static void rna_def_constraint_clamp_to(BlenderRNA *brna)
RNA_def_property_ui_text(
prop, "Cyclic", "Treat curve as cyclic curve (no clamping to curve bounding box)");
RNA_def_property_update(prop, NC_OBJECT | ND_CONSTRAINT, "rna_Constraint_update");
+
+ RNA_define_lib_overridable(false);
}
static void rna_def_constraint_transform(BlenderRNA *brna)
@@ -2033,6 +2113,8 @@ static void rna_def_constraint_transform(BlenderRNA *brna)
rna_def_constraint_target_common(srna);
+ RNA_define_lib_overridable(true);
+
prop = RNA_def_property(srna, "map_from", PROP_ENUM, PROP_NONE);
RNA_def_property_enum_sdna(prop, NULL, "from");
RNA_def_property_enum_items(prop, transform_items);
@@ -2323,6 +2405,8 @@ static void rna_def_constraint_transform(BlenderRNA *brna)
RNA_def_property_ui_text(
prop, "Scale Mix Mode", "Specify how to combine the new scale with original");
RNA_def_property_update(prop, NC_OBJECT | ND_CONSTRAINT, "rna_Constraint_update");
+
+ RNA_define_lib_overridable(false);
}
static void rna_def_constraint_location_limit(BlenderRNA *brna)
@@ -2336,6 +2420,8 @@ static void rna_def_constraint_location_limit(BlenderRNA *brna)
RNA_def_struct_sdna_from(srna, "bLocLimitConstraint", "data");
RNA_def_struct_ui_icon(srna, ICON_CON_LOCLIMIT);
+ RNA_define_lib_overridable(true);
+
prop = RNA_def_property(srna, "use_min_x", PROP_BOOLEAN, PROP_NONE);
RNA_def_property_boolean_sdna(prop, NULL, "flag", LIMIT_XMIN);
RNA_def_property_ui_text(prop, "Minimum X", "Use the minimum X value");
@@ -2407,6 +2493,8 @@ static void rna_def_constraint_location_limit(BlenderRNA *brna)
RNA_def_property_ui_text(
prop, "For Transform", "Transforms are affected by this constraint as well");
RNA_def_property_update(prop, NC_OBJECT | ND_CONSTRAINT, "rna_Constraint_update");
+
+ RNA_define_lib_overridable(false);
}
static void rna_def_constraint_rotation_limit(BlenderRNA *brna)
@@ -2420,6 +2508,8 @@ static void rna_def_constraint_rotation_limit(BlenderRNA *brna)
RNA_def_struct_sdna_from(srna, "bRotLimitConstraint", "data");
RNA_def_struct_ui_icon(srna, ICON_CON_ROTLIMIT);
+ RNA_define_lib_overridable(true);
+
prop = RNA_def_property(srna, "use_limit_x", PROP_BOOLEAN, PROP_NONE);
RNA_def_property_boolean_sdna(prop, NULL, "flag", LIMIT_XROT);
RNA_def_property_ui_text(prop, "Limit X", "Use the minimum X value");
@@ -2476,6 +2566,8 @@ static void rna_def_constraint_rotation_limit(BlenderRNA *brna)
RNA_def_property_ui_text(
prop, "For Transform", "Transforms are affected by this constraint as well");
RNA_def_property_update(prop, NC_OBJECT | ND_CONSTRAINT, "rna_Constraint_update");
+
+ RNA_define_lib_overridable(false);
}
static void rna_def_constraint_size_limit(BlenderRNA *brna)
@@ -2489,6 +2581,8 @@ static void rna_def_constraint_size_limit(BlenderRNA *brna)
RNA_def_struct_sdna_from(srna, "bSizeLimitConstraint", "data");
RNA_def_struct_ui_icon(srna, ICON_CON_SIZELIMIT);
+ RNA_define_lib_overridable(true);
+
prop = RNA_def_property(srna, "use_min_x", PROP_BOOLEAN, PROP_NONE);
RNA_def_property_boolean_sdna(prop, NULL, "flag", LIMIT_XMIN);
RNA_def_property_ui_text(prop, "Minimum X", "Use the minimum X value");
@@ -2560,6 +2654,8 @@ static void rna_def_constraint_size_limit(BlenderRNA *brna)
RNA_def_property_ui_text(
prop, "For Transform", "Transforms are affected by this constraint as well");
RNA_def_property_update(prop, NC_OBJECT | ND_CONSTRAINT, "rna_Constraint_update");
+
+ RNA_define_lib_overridable(false);
}
static void rna_def_constraint_distance_limit(BlenderRNA *brna)
@@ -2578,6 +2674,8 @@ static void rna_def_constraint_distance_limit(BlenderRNA *brna)
rna_def_constraint_target_common(srna);
+ RNA_define_lib_overridable(true);
+
prop = RNA_def_property(srna, "distance", PROP_FLOAT, PROP_DISTANCE);
RNA_def_property_float_sdna(prop, NULL, "dist");
RNA_def_property_ui_range(prop, 0.0f, 100.0f, 10, 3);
@@ -2596,6 +2694,8 @@ static void rna_def_constraint_distance_limit(BlenderRNA *brna)
RNA_def_property_ui_text(
prop, "For Transform", "Transforms are affected by this constraint as well");
RNA_def_property_update(prop, NC_OBJECT | ND_CONSTRAINT, "rna_Constraint_update");
+
+ RNA_define_lib_overridable(false);
}
static void rna_def_constraint_shrinkwrap(BlenderRNA *brna)
@@ -2649,6 +2749,8 @@ static void rna_def_constraint_shrinkwrap(BlenderRNA *brna)
RNA_def_struct_sdna_from(srna, "bShrinkwrapConstraint", "data");
RNA_def_struct_ui_icon(srna, ICON_CON_SHRINKWRAP);
+ RNA_define_lib_overridable(true);
+
prop = RNA_def_property(srna, "target", PROP_POINTER, PROP_NONE);
RNA_def_property_pointer_sdna(prop, NULL, "target"); /* TODO, mesh type */
RNA_def_property_pointer_funcs(prop, NULL, NULL, NULL, "rna_Mesh_object_poll");
@@ -2734,6 +2836,8 @@ static void rna_def_constraint_shrinkwrap(BlenderRNA *brna)
RNA_def_property_enum_items(prop, track_axis_items);
RNA_def_property_ui_text(prop, "Track Axis", "Axis that is aligned to the normal");
RNA_def_property_update(prop, NC_OBJECT | ND_CONSTRAINT, "rna_Constraint_update");
+
+ RNA_define_lib_overridable(false);
}
static void rna_def_constraint_damped_track(BlenderRNA *brna)
@@ -2752,11 +2856,15 @@ static void rna_def_constraint_damped_track(BlenderRNA *brna)
rna_def_constraint_target_common(srna);
+ RNA_define_lib_overridable(true);
+
prop = RNA_def_property(srna, "track_axis", PROP_ENUM, PROP_NONE);
RNA_def_property_enum_sdna(prop, NULL, "trackflag");
RNA_def_property_enum_items(prop, track_axis_items);
RNA_def_property_ui_text(prop, "Track Axis", "Axis that points to the target object");
RNA_def_property_update(prop, NC_OBJECT | ND_CONSTRAINT, "rna_Constraint_update");
+
+ RNA_define_lib_overridable(false);
}
static void rna_def_constraint_spline_ik(BlenderRNA *brna)
@@ -2804,6 +2912,8 @@ static void rna_def_constraint_spline_ik(BlenderRNA *brna)
RNA_def_struct_sdna_from(srna, "bSplineIKConstraint", "data");
RNA_def_struct_ui_icon(srna, ICON_CON_SPLINEIK);
+ RNA_define_lib_overridable(true);
+
/* target chain */
prop = RNA_def_property(srna, "target", PROP_POINTER, PROP_NONE);
RNA_def_property_pointer_sdna(prop, NULL, "tar");
@@ -2922,6 +3032,8 @@ static void rna_def_constraint_spline_ik(BlenderRNA *brna)
RNA_def_property_ui_text(
prop, "Volume Variation Smoothness", "Strength of volume stretching clamping");
RNA_def_property_update(prop, NC_OBJECT | ND_CONSTRAINT, "rna_Constraint_update");
+
+ RNA_define_lib_overridable(false);
}
static void rna_def_constraint_pivot(BlenderRNA *brna)
@@ -2973,6 +3085,8 @@ static void rna_def_constraint_pivot(BlenderRNA *brna)
RNA_def_struct_ui_icon(srna, ICON_CON_PIVOT);
+ RNA_define_lib_overridable(true);
+
/* target-defined pivot */
prop = RNA_def_property(srna, "target", PROP_POINTER, PROP_NONE);
RNA_def_property_pointer_sdna(prop, NULL, "tar");
@@ -3011,6 +3125,8 @@ static void rna_def_constraint_pivot(BlenderRNA *brna)
RNA_def_property_ui_text(
prop, "Enabled Rotation Range", "Rotation range on which pivoting should occur");
RNA_def_property_update(prop, NC_OBJECT | ND_CONSTRAINT, "rna_Constraint_update");
+
+ RNA_define_lib_overridable(false);
}
static void rna_def_constraint_follow_track(BlenderRNA *brna)
@@ -3031,6 +3147,8 @@ static void rna_def_constraint_follow_track(BlenderRNA *brna)
RNA_def_struct_sdna_from(srna, "bFollowTrackConstraint", "data");
RNA_def_struct_ui_icon(srna, ICON_CON_FOLLOWTRACK);
+ RNA_define_lib_overridable(true);
+
/* movie clip */
prop = RNA_def_property(srna, "clip", PROP_POINTER, PROP_NONE);
RNA_def_property_pointer_sdna(prop, NULL, "clip");
@@ -3106,6 +3224,8 @@ static void rna_def_constraint_follow_track(BlenderRNA *brna)
RNA_def_property_boolean_sdna(prop, NULL, "flag", FOLLOWTRACK_USE_UNDISTORTION);
RNA_def_property_ui_text(prop, "Undistort", "Parent to undistorted position of 2D track");
RNA_def_property_update(prop, NC_OBJECT | ND_CONSTRAINT, "rna_Constraint_update");
+
+ RNA_define_lib_overridable(false);
}
static void rna_def_constraint_camera_solver(BlenderRNA *brna)
@@ -3119,6 +3239,8 @@ static void rna_def_constraint_camera_solver(BlenderRNA *brna)
RNA_def_struct_sdna_from(srna, "bCameraSolverConstraint", "data");
RNA_def_struct_ui_icon(srna, ICON_CON_CAMERASOLVER);
+ RNA_define_lib_overridable(true);
+
/* movie clip */
prop = RNA_def_property(srna, "clip", PROP_POINTER, PROP_NONE);
RNA_def_property_pointer_sdna(prop, NULL, "clip");
@@ -3132,6 +3254,8 @@ static void rna_def_constraint_camera_solver(BlenderRNA *brna)
RNA_def_property_boolean_sdna(prop, NULL, "flag", CAMERASOLVER_ACTIVECLIP);
RNA_def_property_ui_text(prop, "Active Clip", "Use active clip defined in scene");
RNA_def_property_update(prop, NC_OBJECT | ND_CONSTRAINT, "rna_Constraint_update");
+
+ RNA_define_lib_overridable(false);
}
static void rna_def_constraint_object_solver(BlenderRNA *brna)
@@ -3145,6 +3269,8 @@ static void rna_def_constraint_object_solver(BlenderRNA *brna)
RNA_def_struct_sdna_from(srna, "bObjectSolverConstraint", "data");
RNA_def_struct_ui_icon(srna, ICON_CON_OBJECTSOLVER);
+ RNA_define_lib_overridable(true);
+
/* movie clip */
prop = RNA_def_property(srna, "clip", PROP_POINTER, PROP_NONE);
RNA_def_property_pointer_sdna(prop, NULL, "clip");
@@ -3184,6 +3310,8 @@ static void rna_def_constraint_object_solver(BlenderRNA *brna)
"rna_Constraint_objectSolver_camera_set",
NULL,
"rna_Constraint_cameraObject_poll");
+
+ RNA_define_lib_overridable(false);
}
static void rna_def_constraint_transform_cache(BlenderRNA *brna)
@@ -3197,6 +3325,8 @@ static void rna_def_constraint_transform_cache(BlenderRNA *brna)
RNA_def_struct_sdna_from(srna, "bTransformCacheConstraint", "data");
RNA_def_struct_ui_icon(srna, ICON_CON_TRANSFORM_CACHE);
+ RNA_define_lib_overridable(true);
+
prop = RNA_def_property(srna, "cache_file", PROP_POINTER, PROP_NONE);
RNA_def_property_pointer_sdna(prop, NULL, "cache_file");
RNA_def_property_struct_type(prop, "CacheFile");
@@ -3211,6 +3341,8 @@ static void rna_def_constraint_transform_cache(BlenderRNA *brna)
"Object Path",
"Path to the object in the Alembic archive used to lookup the transform matrix");
RNA_def_property_update(prop, 0, "rna_Constraint_update");
+
+ RNA_define_lib_overridable(false);
}
/* base struct for constraints */
@@ -3241,6 +3373,8 @@ void RNA_def_constraint(BlenderRNA *brna)
RNA_def_property_enum_items(prop, rna_enum_constraint_type_items);
RNA_def_property_ui_text(prop, "Type", "");
+ RNA_define_lib_overridable(true);
+
prop = RNA_def_property(srna, "owner_space", PROP_ENUM, PROP_NONE);
RNA_def_property_enum_sdna(prop, NULL, "ownspace");
RNA_def_property_enum_items(prop, owner_space_pchan_items);
@@ -3258,7 +3392,6 @@ void RNA_def_constraint(BlenderRNA *brna)
/* flags */
prop = RNA_def_property(srna, "mute", PROP_BOOLEAN, PROP_NONE);
RNA_def_property_boolean_sdna(prop, NULL, "flag", CONSTRAINT_OFF);
- RNA_def_property_override_flag(prop, PROPOVERRIDE_OVERRIDABLE_LIBRARY);
RNA_def_property_ui_text(prop, "Disable", "Enable/Disable Constraint");
RNA_def_property_update(prop, NC_OBJECT | ND_CONSTRAINT, "rna_Constraint_update");
RNA_def_property_ui_icon(prop, ICON_HIDE_OFF, -1);
@@ -3266,7 +3399,6 @@ void RNA_def_constraint(BlenderRNA *brna)
prop = RNA_def_property(srna, "show_expanded", PROP_BOOLEAN, PROP_NONE);
RNA_def_property_flag(prop, PROP_NO_DEG_UPDATE);
RNA_def_property_boolean_sdna(prop, NULL, "flag", CONSTRAINT_EXPAND);
- RNA_def_property_override_flag(prop, PROPOVERRIDE_OVERRIDABLE_LIBRARY);
RNA_def_property_ui_text(prop, "Expanded", "Constraint's panel is expanded in UI");
RNA_def_property_ui_icon(prop, ICON_DISCLOSURE_TRI_RIGHT, 1);
@@ -3315,6 +3447,8 @@ void RNA_def_constraint(BlenderRNA *brna)
"Rot error",
"Amount of residual error in radians for constraints that work on orientation");
+ RNA_define_lib_overridable(false);
+
/* pointers */
rna_def_constrainttarget(brna);
rna_def_constrainttarget_bone(brna);
diff --git a/source/blender/makesrna/intern/rna_define.c b/source/blender/makesrna/intern/rna_define.c
index f5e7f87cfbd..d6bedc61424 100644
--- a/source/blender/makesrna/intern/rna_define.c
+++ b/source/blender/makesrna/intern/rna_define.c
@@ -61,7 +61,18 @@ static CLG_LogRef LOG = {"rna.define"};
/* Global used during defining */
-BlenderDefRNA DefRNA = {NULL, {NULL, NULL}, {NULL, NULL}, NULL, 0, 0, 0, 1, 1};
+BlenderDefRNA DefRNA = {
+ .sdna = NULL,
+ .structs = {NULL, NULL},
+ .allocs = {NULL, NULL},
+ .laststruct = NULL,
+ .error = 0,
+ .silent = false,
+ .preprocess = false,
+ .verify = true,
+ .animate = true,
+ .make_overridable = false,
+};
#ifndef RNA_RUNTIME
static struct {
@@ -691,13 +702,13 @@ BlenderRNA *RNA_create(void)
BLI_listbase_clear(&DefRNA.structs);
brna->structs_map = BLI_ghash_str_new_ex(__func__, 2048);
- DefRNA.error = 0;
- DefRNA.preprocess = 1;
+ DefRNA.error = false;
+ DefRNA.preprocess = true;
DefRNA.sdna = DNA_sdna_from_data(DNAstr, DNAlen, false, false, &error_message);
if (DefRNA.sdna == NULL) {
CLOG_ERROR(&LOG, "Failed to decode SDNA: %s.", error_message);
- DefRNA.error = 1;
+ DefRNA.error = true;
}
/* We need both alias and static (on-disk) DNA names. */
@@ -737,7 +748,7 @@ void RNA_define_free(BlenderRNA *UNUSED(brna))
DefRNA.sdna = NULL;
}
- DefRNA.error = 0;
+ DefRNA.error = false;
}
void RNA_define_verify_sdna(bool verify)
@@ -745,6 +756,15 @@ void RNA_define_verify_sdna(bool verify)
DefRNA.verify = verify;
}
+/**
+ * Properties defined when this is enabled are lib-overridable by default (except for Pointer
+ * ones).
+ */
+void RNA_define_lib_overridable(const bool make_overridable)
+{
+ DefRNA.make_overridable = make_overridable;
+}
+
#ifndef RNA_RUNTIME
void RNA_define_animate_sdna(bool animate)
{
@@ -760,10 +780,10 @@ void RNA_define_fallback_property_update(int noteflag, const char *updatefunc)
}
#endif
-void RNA_struct_free_extension(StructRNA *srna, ExtensionRNA *ext)
+void RNA_struct_free_extension(StructRNA *srna, ExtensionRNA *rna_ext)
{
#ifdef RNA_RUNTIME
- ext->free(ext->data); /* decref's the PyObject that the srna owns */
+ rna_ext->free(rna_ext->data); /* decref's the PyObject that the srna owns */
RNA_struct_blender_type_set(srna, NULL); /* this gets accessed again - XXX fixme */
/* NULL the srna's value so RNA_struct_free wont complain of a leak */
@@ -771,7 +791,7 @@ void RNA_struct_free_extension(StructRNA *srna, ExtensionRNA *ext)
#else
(void)srna;
- (void)ext;
+ (void)rna_ext;
#endif
}
@@ -910,7 +930,7 @@ StructRNA *RNA_def_struct_ptr(BlenderRNA *brna, const char *identifier, StructRN
if (rna_validate_identifier(identifier, error, false) == 0) {
CLOG_ERROR(&LOG, "struct identifier \"%s\" error - %s", identifier, error);
- DefRNA.error = 1;
+ DefRNA.error = true;
}
}
@@ -1040,7 +1060,7 @@ StructRNA *RNA_def_struct(BlenderRNA *brna, const char *identifier, const char *
srnafrom = BLI_ghash_lookup(brna->structs_map, from);
if (!srnafrom) {
CLOG_ERROR(&LOG, "struct %s not found to define %s.", from, identifier);
- DefRNA.error = 1;
+ DefRNA.error = true;
}
}
@@ -1065,7 +1085,7 @@ void RNA_def_struct_sdna(StructRNA *srna, const char *structname)
if (DNA_struct_find_nr_wrapper(DefRNA.sdna, structname) == -1) {
if (!DefRNA.silent) {
CLOG_ERROR(&LOG, "%s not found.", structname);
- DefRNA.error = 1;
+ DefRNA.error = true;
}
return;
}
@@ -1093,7 +1113,7 @@ void RNA_def_struct_sdna_from(StructRNA *srna, const char *structname, const cha
if (DNA_struct_find_nr_wrapper(DefRNA.sdna, structname) == -1) {
if (!DefRNA.silent) {
CLOG_ERROR(&LOG, "%s not found.", structname);
- DefRNA.error = 1;
+ DefRNA.error = true;
}
return;
}
@@ -1106,7 +1126,7 @@ void RNA_def_struct_name_property(struct StructRNA *srna, struct PropertyRNA *pr
{
if (prop->type != PROP_STRING) {
CLOG_ERROR(&LOG, "\"%s.%s\", must be a string property.", srna->identifier, prop->identifier);
- DefRNA.error = 1;
+ DefRNA.error = true;
}
else {
srna->nameproperty = prop;
@@ -1121,7 +1141,7 @@ void RNA_def_struct_nested(BlenderRNA *brna, StructRNA *srna, const char *struct
srnafrom = BLI_ghash_lookup(brna->structs_map, structname);
if (!srnafrom) {
CLOG_ERROR(&LOG, "struct %s not found for %s.", structname, srna->identifier);
- DefRNA.error = 1;
+ DefRNA.error = true;
}
srna->nested = srnafrom;
@@ -1271,7 +1291,7 @@ PropertyRNA *RNA_def_property(StructOrFunctionRNA *cont_,
if (rna_validate_identifier(identifier, error, true) == 0) {
CLOG_ERROR(
&LOG, "property identifier \"%s.%s\" - %s", CONTAINER_RNA_ID(cont), identifier, error);
- DefRNA.error = 1;
+ DefRNA.error = true;
}
dcont = rna_find_container_def(cont);
@@ -1279,7 +1299,7 @@ PropertyRNA *RNA_def_property(StructOrFunctionRNA *cont_,
/* XXX - toto, detect supertype collisions */
if (rna_findlink(&dcont->properties, identifier)) {
CLOG_ERROR(&LOG, "duplicate identifier \"%s.%s\"", CONTAINER_RNA_ID(cont), identifier);
- DefRNA.error = 1;
+ DefRNA.error = true;
}
dprop = MEM_callocN(sizeof(PropertyDefRNA), "PropertyDefRNA");
@@ -1294,7 +1314,7 @@ PropertyRNA *RNA_def_property(StructOrFunctionRNA *cont_,
CONTAINER_RNA_ID(cont),
identifier,
error);
- DefRNA.error = 1;
+ DefRNA.error = true;
}
#endif
}
@@ -1309,7 +1329,7 @@ PropertyRNA *RNA_def_property(StructOrFunctionRNA *cont_,
"subtype does not apply to 'PROP_BOOLEAN' \"%s.%s\"",
CONTAINER_RNA_ID(cont),
identifier);
- DefRNA.error = 1;
+ DefRNA.error = true;
}
}
break;
@@ -1322,7 +1342,7 @@ PropertyRNA *RNA_def_property(StructOrFunctionRNA *cont_,
"subtype does not apply to 'PROP_INT' \"%s.%s\"",
CONTAINER_RNA_ID(cont),
identifier);
- DefRNA.error = 1;
+ DefRNA.error = true;
}
#endif
@@ -1371,7 +1391,7 @@ PropertyRNA *RNA_def_property(StructOrFunctionRNA *cont_,
break;
default:
CLOG_ERROR(&LOG, "\"%s.%s\", invalid property type.", CONTAINER_RNA_ID(cont), identifier);
- DefRNA.error = 1;
+ DefRNA.error = true;
return NULL;
}
@@ -1404,6 +1424,12 @@ PropertyRNA *RNA_def_property(StructOrFunctionRNA *cont_,
}
}
+#ifndef RNA_RUNTIME
+ if (DefRNA.make_overridable) {
+ prop->flag_override |= PROPOVERRIDE_OVERRIDABLE_LIBRARY;
+ }
+#endif
+
if (type == PROP_STRING) {
/* used so generated 'get/length/set' functions skip a NULL check
* in some cases we want it */
@@ -1413,42 +1439,42 @@ PropertyRNA *RNA_def_property(StructOrFunctionRNA *cont_,
if (DefRNA.preprocess) {
switch (type) {
case PROP_BOOLEAN:
- DefRNA.silent = 1;
+ DefRNA.silent = true;
RNA_def_property_boolean_sdna(prop, NULL, identifier, 0);
- DefRNA.silent = 0;
+ DefRNA.silent = false;
break;
case PROP_INT: {
- DefRNA.silent = 1;
+ DefRNA.silent = true;
RNA_def_property_int_sdna(prop, NULL, identifier);
- DefRNA.silent = 0;
+ DefRNA.silent = false;
break;
}
case PROP_FLOAT: {
- DefRNA.silent = 1;
+ DefRNA.silent = true;
RNA_def_property_float_sdna(prop, NULL, identifier);
- DefRNA.silent = 0;
+ DefRNA.silent = false;
break;
}
case PROP_STRING: {
- DefRNA.silent = 1;
+ DefRNA.silent = true;
RNA_def_property_string_sdna(prop, NULL, identifier);
- DefRNA.silent = 0;
+ DefRNA.silent = false;
break;
}
case PROP_ENUM:
- DefRNA.silent = 1;
+ DefRNA.silent = true;
RNA_def_property_enum_sdna(prop, NULL, identifier);
- DefRNA.silent = 0;
+ DefRNA.silent = false;
break;
case PROP_POINTER:
- DefRNA.silent = 1;
+ DefRNA.silent = true;
RNA_def_property_pointer_sdna(prop, NULL, identifier);
- DefRNA.silent = 0;
+ DefRNA.silent = false;
break;
case PROP_COLLECTION:
- DefRNA.silent = 1;
+ DefRNA.silent = true;
RNA_def_property_collection_sdna(prop, NULL, identifier, NULL);
- DefRNA.silent = 0;
+ DefRNA.silent = false;
break;
}
}
@@ -1543,7 +1569,7 @@ void RNA_def_property_array(PropertyRNA *prop, int length)
"\"%s.%s\", array length must be zero of greater.",
srna->identifier,
prop->identifier);
- DefRNA.error = 1;
+ DefRNA.error = true;
return;
}
@@ -1553,7 +1579,7 @@ void RNA_def_property_array(PropertyRNA *prop, int length)
srna->identifier,
prop->identifier,
RNA_MAX_ARRAY_LENGTH);
- DefRNA.error = 1;
+ DefRNA.error = true;
return;
}
@@ -1563,7 +1589,7 @@ void RNA_def_property_array(PropertyRNA *prop, int length)
srna->identifier,
prop->identifier,
prop->arraydimension);
- DefRNA.error = 1;
+ DefRNA.error = true;
return;
}
@@ -1580,7 +1606,7 @@ void RNA_def_property_array(PropertyRNA *prop, int length)
"\"%s.%s\", only boolean/int/float can be array.",
srna->identifier,
prop->identifier);
- DefRNA.error = 1;
+ DefRNA.error = true;
break;
}
}
@@ -1606,7 +1632,7 @@ void RNA_def_property_multi_array(PropertyRNA *prop, int dimension, const int le
srna->identifier,
prop->identifier,
RNA_MAX_ARRAY_DIMENSION);
- DefRNA.error = 1;
+ DefRNA.error = true;
return;
}
@@ -1620,7 +1646,7 @@ void RNA_def_property_multi_array(PropertyRNA *prop, int dimension, const int le
"\"%s.%s\", only boolean/int/float can be array.",
srna->identifier,
prop->identifier);
- DefRNA.error = 1;
+ DefRNA.error = true;
break;
}
@@ -1680,22 +1706,22 @@ void RNA_def_property_ui_range(
#ifndef NDEBUG
if (min > max) {
CLOG_ERROR(&LOG, "\"%s.%s\", min > max.", srna->identifier, prop->identifier);
- DefRNA.error = 1;
+ DefRNA.error = true;
}
if (step < 0 || step > 100) {
CLOG_ERROR(&LOG, "\"%s.%s\", step outside range.", srna->identifier, prop->identifier);
- DefRNA.error = 1;
+ DefRNA.error = true;
}
if (step == 0) {
CLOG_ERROR(&LOG, "\"%s.%s\", step is zero.", srna->identifier, prop->identifier);
- DefRNA.error = 1;
+ DefRNA.error = true;
}
if (precision < -1 || precision > UI_PRECISION_FLOAT_MAX) {
CLOG_ERROR(&LOG, "\"%s.%s\", precision outside range.", srna->identifier, prop->identifier);
- DefRNA.error = 1;
+ DefRNA.error = true;
}
#endif
@@ -1718,7 +1744,7 @@ void RNA_def_property_ui_range(
default:
CLOG_ERROR(
&LOG, "\"%s.%s\", invalid type for ui range.", srna->identifier, prop->identifier);
- DefRNA.error = 1;
+ DefRNA.error = true;
break;
}
}
@@ -1730,7 +1756,7 @@ void RNA_def_property_range(PropertyRNA *prop, double min, double max)
#ifdef DEBUG
if (min > max) {
CLOG_ERROR(&LOG, "\"%s.%s\", min > max.", srna->identifier, prop->identifier);
- DefRNA.error = 1;
+ DefRNA.error = true;
}
#endif
@@ -1753,7 +1779,7 @@ void RNA_def_property_range(PropertyRNA *prop, double min, double max)
}
default:
CLOG_ERROR(&LOG, "\"%s.%s\", invalid type for range.", srna->identifier, prop->identifier);
- DefRNA.error = 1;
+ DefRNA.error = true;
break;
}
}
@@ -1781,7 +1807,7 @@ void RNA_def_property_struct_type(PropertyRNA *prop, const char *type)
default:
CLOG_ERROR(
&LOG, "\"%s.%s\", invalid type for struct type.", srna->identifier, prop->identifier);
- DefRNA.error = 1;
+ DefRNA.error = true;
break;
}
}
@@ -1814,7 +1840,7 @@ void RNA_def_property_struct_runtime(PropertyRNA *prop, StructRNA *type)
default:
CLOG_ERROR(
&LOG, "\"%s.%s\", invalid type for struct type.", srna->identifier, prop->identifier);
- DefRNA.error = 1;
+ DefRNA.error = true;
break;
}
}
@@ -1831,7 +1857,7 @@ void RNA_def_property_enum_native_type(PropertyRNA *prop, const char *native_enu
default:
CLOG_ERROR(
&LOG, "\"%s.%s\", invalid type for struct type.", srna->identifier, prop->identifier);
- DefRNA.error = 1;
+ DefRNA.error = true;
break;
}
}
@@ -1856,7 +1882,7 @@ void RNA_def_property_enum_items(PropertyRNA *prop, const EnumPropertyItem *item
"\"%s.%s\", enum identifiers must not contain spaces.",
srna->identifier,
prop->identifier);
- DefRNA.error = 1;
+ DefRNA.error = true;
break;
}
else if (item[i].value == eprop->defaultvalue) {
@@ -1879,7 +1905,7 @@ void RNA_def_property_enum_items(PropertyRNA *prop, const EnumPropertyItem *item
default:
CLOG_ERROR(
&LOG, "\"%s.%s\", invalid type for struct type.", srna->identifier, prop->identifier);
- DefRNA.error = 1;
+ DefRNA.error = true;
break;
}
}
@@ -1896,7 +1922,7 @@ void RNA_def_property_string_maxlength(PropertyRNA *prop, int maxlength)
}
default:
CLOG_ERROR(&LOG, "\"%s.%s\", type is not string.", srna->identifier, prop->identifier);
- DefRNA.error = 1;
+ DefRNA.error = true;
break;
}
}
@@ -1920,7 +1946,7 @@ void RNA_def_property_boolean_default(PropertyRNA *prop, bool value)
}
default:
CLOG_ERROR(&LOG, "\"%s.%s\", type is not boolean.", srna->identifier, prop->identifier);
- DefRNA.error = 1;
+ DefRNA.error = true;
break;
}
}
@@ -1937,7 +1963,7 @@ void RNA_def_property_boolean_array_default(PropertyRNA *prop, const bool *array
}
default:
CLOG_ERROR(&LOG, "\"%s.%s\", type is not boolean.", srna->identifier, prop->identifier);
- DefRNA.error = 1;
+ DefRNA.error = true;
break;
}
}
@@ -1959,7 +1985,7 @@ void RNA_def_property_int_default(PropertyRNA *prop, int value)
}
default:
CLOG_ERROR(&LOG, "\"%s.%s\", type is not int.", srna->identifier, prop->identifier);
- DefRNA.error = 1;
+ DefRNA.error = true;
break;
}
}
@@ -1981,7 +2007,7 @@ void RNA_def_property_int_array_default(PropertyRNA *prop, const int *array)
}
default:
CLOG_ERROR(&LOG, "\"%s.%s\", type is not int.", srna->identifier, prop->identifier);
- DefRNA.error = 1;
+ DefRNA.error = true;
break;
}
}
@@ -2003,7 +2029,7 @@ void RNA_def_property_float_default(PropertyRNA *prop, float value)
}
default:
CLOG_ERROR(&LOG, "\"%s.%s\", type is not float.", srna->identifier, prop->identifier);
- DefRNA.error = 1;
+ DefRNA.error = true;
break;
}
}
@@ -2025,7 +2051,7 @@ void RNA_def_property_float_array_default(PropertyRNA *prop, const float *array)
}
default:
CLOG_ERROR(&LOG, "\"%s.%s\", type is not float.", srna->identifier, prop->identifier);
- DefRNA.error = 1;
+ DefRNA.error = true;
break;
}
}
@@ -2043,7 +2069,7 @@ void RNA_def_property_string_default(PropertyRNA *prop, const char *value)
"\"%s.%s\", NULL string passed (dont call in this case).",
srna->identifier,
prop->identifier);
- DefRNA.error = 1;
+ DefRNA.error = true;
break;
}
@@ -2052,7 +2078,7 @@ void RNA_def_property_string_default(PropertyRNA *prop, const char *value)
"\"%s.%s\", empty string passed (dont call in this case).",
srna->identifier,
prop->identifier);
- DefRNA.error = 1;
+ DefRNA.error = true;
// BLI_assert(0);
break;
}
@@ -2066,7 +2092,7 @@ void RNA_def_property_string_default(PropertyRNA *prop, const char *value)
}
default:
CLOG_ERROR(&LOG, "\"%s.%s\", type is not string.", srna->identifier, prop->identifier);
- DefRNA.error = 1;
+ DefRNA.error = true;
break;
}
}
@@ -2096,7 +2122,7 @@ void RNA_def_property_enum_default(PropertyRNA *prop, int value)
srna->identifier,
prop->identifier,
eprop->defaultvalue & ~totflag);
- DefRNA.error = 1;
+ DefRNA.error = true;
}
}
else {
@@ -2113,7 +2139,7 @@ void RNA_def_property_enum_default(PropertyRNA *prop, int value)
else {
CLOG_ERROR(
&LOG, "\"%s.%s\", default is not in items.", srna->identifier, prop->identifier);
- DefRNA.error = 1;
+ DefRNA.error = true;
}
}
}
@@ -2122,7 +2148,7 @@ void RNA_def_property_enum_default(PropertyRNA *prop, int value)
}
default:
CLOG_ERROR(&LOG, "\"%s.%s\", type is not enum.", srna->identifier, prop->identifier);
- DefRNA.error = 1;
+ DefRNA.error = true;
break;
}
}
@@ -2175,7 +2201,7 @@ static PropertyDefRNA *rna_def_property_sdna(PropertyRNA *prop,
structname,
propname,
prop->identifier);
- DefRNA.error = 1;
+ DefRNA.error = true;
return NULL;
}
}
@@ -2219,13 +2245,13 @@ void RNA_def_property_boolean_sdna(PropertyRNA *prop,
if (prop->type != PROP_BOOLEAN) {
CLOG_ERROR(&LOG, "\"%s.%s\", type is not boolean.", srna->identifier, prop->identifier);
- DefRNA.error = 1;
+ DefRNA.error = true;
return;
}
if ((dp = rna_def_property_sdna(prop, structname, propname))) {
- if (DefRNA.silent == 0) {
+ if (!DefRNA.silent) {
/* error check to ensure floats are not wrapped as ints/bools */
if (dp->dnatype && *dp->dnatype && IS_DNATYPE_BOOLEAN_COMPAT(dp->dnatype) == 0) {
CLOG_ERROR(&LOG,
@@ -2234,7 +2260,7 @@ void RNA_def_property_boolean_sdna(PropertyRNA *prop,
prop->identifier,
dp->dnatype,
RNA_property_typename(prop->type));
- DefRNA.error = 1;
+ DefRNA.error = true;
return;
}
}
@@ -2323,14 +2349,14 @@ void RNA_def_property_int_sdna(PropertyRNA *prop, const char *structname, const
if (prop->type != PROP_INT) {
CLOG_ERROR(&LOG, "\"%s.%s\", type is not int.", srna->identifier, prop->identifier);
- DefRNA.error = 1;
+ DefRNA.error = true;
return;
}
if ((dp = rna_def_property_sdna(prop, structname, propname))) {
/* error check to ensure floats are not wrapped as ints/bools */
- if (DefRNA.silent == 0) {
+ if (!DefRNA.silent) {
if (dp->dnatype && *dp->dnatype && IS_DNATYPE_INT_COMPAT(dp->dnatype) == 0) {
CLOG_ERROR(&LOG,
"%s.%s is a '%s' but wrapped as type '%s'.",
@@ -2338,7 +2364,7 @@ void RNA_def_property_int_sdna(PropertyRNA *prop, const char *structname, const
prop->identifier,
dp->dnatype,
RNA_property_typename(prop->type));
- DefRNA.error = 1;
+ DefRNA.error = true;
return;
}
}
@@ -2470,13 +2496,13 @@ void RNA_def_property_float_sdna(PropertyRNA *prop, const char *structname, cons
if (prop->type != PROP_FLOAT) {
CLOG_ERROR(&LOG, "\"%s.%s\", type is not float.", srna->identifier, prop->identifier);
- DefRNA.error = 1;
+ DefRNA.error = true;
return;
}
if ((dp = rna_def_property_sdna(prop, structname, propname))) {
/* silent is for internal use */
- if (DefRNA.silent == 0) {
+ if (!DefRNA.silent) {
if (dp->dnatype && *dp->dnatype && IS_DNATYPE_FLOAT_COMPAT(dp->dnatype) == 0) {
/* Colors are an exception. these get translated. */
if (prop->subtype != PROP_COLOR_GAMMA) {
@@ -2486,7 +2512,7 @@ void RNA_def_property_float_sdna(PropertyRNA *prop, const char *structname, cons
prop->identifier,
dp->dnatype,
RNA_property_typename(prop->type));
- DefRNA.error = 1;
+ DefRNA.error = true;
return;
}
}
@@ -2578,7 +2604,7 @@ void RNA_def_property_enum_sdna(PropertyRNA *prop, const char *structname, const
if (prop->type != PROP_ENUM) {
CLOG_ERROR(&LOG, "\"%s.%s\", type is not enum.", srna->identifier, prop->identifier);
- DefRNA.error = 1;
+ DefRNA.error = true;
return;
}
@@ -2589,7 +2615,7 @@ void RNA_def_property_enum_sdna(PropertyRNA *prop, const char *structname, const
if (!DefRNA.silent) {
CLOG_ERROR(&LOG, "\"%s.%s\", array not supported for enum type.", structname, propname);
- DefRNA.error = 1;
+ DefRNA.error = true;
}
}
@@ -2672,7 +2698,7 @@ void RNA_def_property_string_sdna(PropertyRNA *prop, const char *structname, con
if (prop->type != PROP_STRING) {
CLOG_ERROR(&LOG, "\"%s.%s\", type is not string.", srna->identifier, prop->identifier);
- DefRNA.error = 1;
+ DefRNA.error = true;
return;
}
@@ -2716,7 +2742,7 @@ void RNA_def_property_pointer_sdna(PropertyRNA *prop, const char *structname, co
if (prop->type != PROP_POINTER) {
CLOG_ERROR(&LOG, "\"%s.%s\", type is not pointer.", srna->identifier, prop->identifier);
- DefRNA.error = 1;
+ DefRNA.error = true;
return;
}
@@ -2727,7 +2753,7 @@ void RNA_def_property_pointer_sdna(PropertyRNA *prop, const char *structname, co
if (!DefRNA.silent) {
CLOG_ERROR(&LOG, "\"%s.%s\", array not supported for pointer type.", structname, propname);
- DefRNA.error = 1;
+ DefRNA.error = true;
}
}
}
@@ -2749,7 +2775,7 @@ void RNA_def_property_collection_sdna(PropertyRNA *prop,
if (prop->type != PROP_COLLECTION) {
CLOG_ERROR(&LOG, "\"%s.%s\", type is not collection.", srna->identifier, prop->identifier);
- DefRNA.error = 1;
+ DefRNA.error = true;
return;
}
@@ -2760,7 +2786,7 @@ void RNA_def_property_collection_sdna(PropertyRNA *prop,
if (!DefRNA.silent) {
CLOG_ERROR(&LOG, "\"%s.%s\", array of collections not supported.", structname, propname);
- DefRNA.error = 1;
+ DefRNA.error = true;
}
}
@@ -2806,7 +2832,7 @@ void RNA_def_property_collection_sdna(PropertyRNA *prop,
else {
if (!DefRNA.silent) {
CLOG_ERROR(&LOG, "\"%s.%s\" not found.", structname, lengthpropname);
- DefRNA.error = 1;
+ DefRNA.error = true;
}
}
}
@@ -2904,7 +2930,7 @@ void RNA_def_property_dynamic_array_funcs(PropertyRNA *prop, const char *getleng
if (!(prop->flag & PROP_DYNAMIC)) {
CLOG_ERROR(&LOG, "property is a not dynamic array.");
- DefRNA.error = 1;
+ DefRNA.error = true;
return;
}
@@ -2946,7 +2972,7 @@ void RNA_def_property_boolean_funcs(PropertyRNA *prop, const char *get, const ch
}
default:
CLOG_ERROR(&LOG, "\"%s.%s\", type is not boolean.", srna->identifier, prop->identifier);
- DefRNA.error = 1;
+ DefRNA.error = true;
break;
}
}
@@ -3036,7 +3062,7 @@ void RNA_def_property_int_funcs(PropertyRNA *prop,
}
default:
CLOG_ERROR(&LOG, "\"%s.%s\", type is not int.", srna->identifier, prop->identifier);
- DefRNA.error = 1;
+ DefRNA.error = true;
break;
}
}
@@ -3134,7 +3160,7 @@ void RNA_def_property_float_funcs(PropertyRNA *prop,
}
default:
CLOG_ERROR(&LOG, "\"%s.%s\", type is not float.", srna->identifier, prop->identifier);
- DefRNA.error = 1;
+ DefRNA.error = true;
break;
}
}
@@ -3222,7 +3248,7 @@ void RNA_def_property_enum_funcs(PropertyRNA *prop,
}
default:
CLOG_ERROR(&LOG, "\"%s.%s\", type is not enum.", srna->identifier, prop->identifier);
- DefRNA.error = 1;
+ DefRNA.error = true;
break;
}
}
@@ -3289,7 +3315,7 @@ void RNA_def_property_string_funcs(PropertyRNA *prop,
}
default:
CLOG_ERROR(&LOG, "\"%s.%s\", type is not string.", srna->identifier, prop->identifier);
- DefRNA.error = 1;
+ DefRNA.error = true;
break;
}
}
@@ -3351,7 +3377,7 @@ void RNA_def_property_pointer_funcs(
}
default:
CLOG_ERROR(&LOG, "\"%s.%s\", type is not pointer.", srna->identifier, prop->identifier);
- DefRNA.error = 1;
+ DefRNA.error = true;
break;
}
}
@@ -3405,7 +3431,7 @@ void RNA_def_property_collection_funcs(PropertyRNA *prop,
}
default:
CLOG_ERROR(&LOG, "\"%s.%s\", type is not collection.", srna->identifier, prop->identifier);
- DefRNA.error = 1;
+ DefRNA.error = true;
break;
}
}
@@ -4170,7 +4196,7 @@ static FunctionRNA *rna_def_function(StructRNA *srna, const char *identifier)
if (rna_validate_identifier(identifier, error, false) == 0) {
CLOG_ERROR(&LOG, "function identifier \"%s\" - %s", identifier, error);
- DefRNA.error = 1;
+ DefRNA.error = true;
}
}
diff --git a/source/blender/makesrna/intern/rna_depsgraph.c b/source/blender/makesrna/intern/rna_depsgraph.c
index 66c8522c53a..ca34f69ab1e 100644
--- a/source/blender/makesrna/intern/rna_depsgraph.c
+++ b/source/blender/makesrna/intern/rna_depsgraph.c
@@ -43,7 +43,7 @@
# include "BLI_iterator.h"
# include "BLI_math.h"
-# include "BKE_anim.h"
+# include "BKE_duplilist.h"
# include "BKE_object.h"
# include "BKE_scene.h"
@@ -203,6 +203,12 @@ static bool rna_DepsgraphUpdate_is_updated_transform_get(PointerRNA *ptr)
return ((id->recalc & ID_RECALC_TRANSFORM) != 0);
}
+static bool rna_DepsgraphUpdate_is_updated_shading_get(PointerRNA *ptr)
+{
+ ID *id = ptr->data;
+ return ((id->recalc & ID_RECALC_SHADING) != 0);
+}
+
static bool rna_DepsgraphUpdate_is_updated_geometry_get(PointerRNA *ptr)
{
ID *id = ptr->data;
@@ -601,6 +607,11 @@ static void rna_def_depsgraph_update(BlenderRNA *brna)
RNA_def_property_clear_flag(prop, PROP_ANIMATABLE | PROP_EDITABLE);
RNA_def_property_ui_text(prop, "Geometry", "Object geometry is updated");
RNA_def_property_boolean_funcs(prop, "rna_DepsgraphUpdate_is_updated_geometry_get", NULL);
+
+ prop = RNA_def_property(srna, "is_updated_shading", PROP_BOOLEAN, PROP_NONE);
+ RNA_def_property_clear_flag(prop, PROP_ANIMATABLE | PROP_EDITABLE);
+ RNA_def_property_ui_text(prop, "Shading", "Object shading is updated");
+ RNA_def_property_boolean_funcs(prop, "rna_DepsgraphUpdate_is_updated_shading_get", NULL);
}
static void rna_def_depsgraph(BlenderRNA *brna)
diff --git a/source/blender/makesrna/intern/rna_fcurve.c b/source/blender/makesrna/intern/rna_fcurve.c
index b6a2d38ba18..e49186f4cb1 100644
--- a/source/blender/makesrna/intern/rna_fcurve.c
+++ b/source/blender/makesrna/intern/rna_fcurve.c
@@ -211,8 +211,9 @@ static StructRNA *rna_FModifierType_refine(struct PointerRNA *ptr)
/* ****************************** */
-# include "BKE_animsys.h"
+# include "BKE_anim_data.h"
# include "BKE_fcurve.h"
+# include "BKE_fcurve_driver.h"
# include "DEG_depsgraph.h"
# include "DEG_depsgraph_build.h"
@@ -578,7 +579,7 @@ static void rna_FCurve_group_set(PointerRNA *ptr,
/* calculate time extents of F-Curve */
static void rna_FCurve_range(FCurve *fcu, float range[2])
{
- calc_fcurve_range(fcu, range, range + 1, false, false);
+ BKE_fcurve_calc_range(fcu, range, range + 1, false, false);
}
static bool rna_FCurve_is_empty_get(PointerRNA *ptr)
@@ -2297,7 +2298,7 @@ static void rna_def_fcurve(BlenderRNA *brna)
prop = RNA_def_property(srna, "group", PROP_POINTER, PROP_NONE);
RNA_def_property_pointer_sdna(prop, NULL, "grp");
- RNA_def_property_flag(prop, PROP_EDITABLE);
+ RNA_def_property_flag(prop, PROP_EDITABLE | PROP_PTR_NO_OWNERSHIP);
RNA_def_property_ui_text(prop, "Group", "Action Group that this F-Curve belongs to");
RNA_def_property_pointer_funcs(prop, NULL, "rna_FCurve_group_set", NULL, NULL);
RNA_def_property_update(prop, NC_ANIMATION, NULL);
diff --git a/source/blender/makesrna/intern/rna_fcurve_api.c b/source/blender/makesrna/intern/rna_fcurve_api.c
index 4ee25be946c..f7be65b4e75 100644
--- a/source/blender/makesrna/intern/rna_fcurve_api.c
+++ b/source/blender/makesrna/intern/rna_fcurve_api.c
@@ -39,7 +39,6 @@
# include <stddef.h>
-# include "BKE_animsys.h"
# include "BKE_fcurve.h"
# include "BLI_math.h"
diff --git a/source/blender/makesrna/intern/rna_fluid.c b/source/blender/makesrna/intern/rna_fluid.c
index 9410906595d..94ba09b2bb8 100644
--- a/source/blender/makesrna/intern/rna_fluid.c
+++ b/source/blender/makesrna/intern/rna_fluid.c
@@ -73,43 +73,111 @@ static void rna_Fluid_dependency_update(Main *bmain, Scene *scene, PointerRNA *p
DEG_relations_tag_update(bmain);
}
-static void rna_Fluid_resetCache(Main *UNUSED(bmain), Scene *UNUSED(scene), PointerRNA *ptr)
+static void rna_Fluid_datacache_reset(Main *UNUSED(bmain), Scene *UNUSED(scene), PointerRNA *ptr)
{
+# ifdef WITH_FLUID
FluidDomainSettings *settings = (FluidDomainSettings *)ptr->data;
if (settings->mmd && settings->mmd->domain) {
- settings->mmd->domain->cache_flag |= (FLUID_DOMAIN_OUTDATED_DATA |
- FLUID_DOMAIN_OUTDATED_NOISE |
- FLUID_DOMAIN_OUTDATED_MESH |
- FLUID_DOMAIN_OUTDATED_PARTICLES);
+ Object *ob = (Object *)ptr->owner_id;
+ int cache_map = (FLUID_DOMAIN_OUTDATED_DATA | FLUID_DOMAIN_OUTDATED_NOISE |
+ FLUID_DOMAIN_OUTDATED_MESH | FLUID_DOMAIN_OUTDATED_PARTICLES);
+ BKE_fluid_cache_free(settings, ob, cache_map);
}
+# endif
DEG_id_tag_update(ptr->owner_id, ID_RECALC_GEOMETRY);
}
-static void rna_Fluid_reset(Main *bmain, Scene *scene, PointerRNA *ptr)
+static void rna_Fluid_noisecache_reset(Main *UNUSED(bmain), Scene *UNUSED(scene), PointerRNA *ptr)
+{
+# ifdef WITH_FLUID
+ FluidDomainSettings *settings = (FluidDomainSettings *)ptr->data;
+ if (settings->mmd && settings->mmd->domain) {
+ Object *ob = (Object *)ptr->owner_id;
+ int cache_map = FLUID_DOMAIN_OUTDATED_NOISE;
+ BKE_fluid_cache_free(settings, ob, cache_map);
+ }
+# endif
+ DEG_id_tag_update(ptr->owner_id, ID_RECALC_GEOMETRY);
+}
+static void rna_Fluid_meshcache_reset(Main *UNUSED(bmain), Scene *UNUSED(scene), PointerRNA *ptr)
+{
+# ifdef WITH_FLUID
+ FluidDomainSettings *settings = (FluidDomainSettings *)ptr->data;
+ if (settings->mmd && settings->mmd->domain) {
+ Object *ob = (Object *)ptr->owner_id;
+ int cache_map = FLUID_DOMAIN_OUTDATED_MESH;
+ BKE_fluid_cache_free(settings, ob, cache_map);
+ }
+# endif
+ DEG_id_tag_update(ptr->owner_id, ID_RECALC_GEOMETRY);
+}
+static void rna_Fluid_particlescache_reset(Main *UNUSED(bmain),
+ Scene *UNUSED(scene),
+ PointerRNA *ptr)
{
-
# ifdef WITH_FLUID
- {
- FluidDomainSettings *settings = (FluidDomainSettings *)ptr->data;
- BKE_fluid_modifier_reset(settings->mmd);
+ FluidDomainSettings *settings = (FluidDomainSettings *)ptr->data;
+ if (settings->mmd && settings->mmd->domain) {
+ Object *ob = (Object *)ptr->owner_id;
+ int cache_map = FLUID_DOMAIN_OUTDATED_PARTICLES;
+ BKE_fluid_cache_free(settings, ob, cache_map);
+ }
+# endif
+ DEG_id_tag_update(ptr->owner_id, ID_RECALC_GEOMETRY);
+}
+static void rna_Fluid_guidingcache_reset(Main *UNUSED(bmain),
+ Scene *UNUSED(scene),
+ PointerRNA *ptr)
+{
+# ifdef WITH_FLUID
+ FluidDomainSettings *settings = (FluidDomainSettings *)ptr->data;
+ if (settings->mmd && settings->mmd->domain) {
+ Object *ob = (Object *)ptr->owner_id;
+ int cache_map = (FLUID_DOMAIN_OUTDATED_DATA | FLUID_DOMAIN_OUTDATED_NOISE |
+ FLUID_DOMAIN_OUTDATED_MESH | FLUID_DOMAIN_OUTDATED_PARTICLES |
+ FLUID_DOMAIN_OUTDATED_GUIDE);
+ BKE_fluid_cache_free(settings, ob, cache_map);
}
# endif
+ DEG_id_tag_update(ptr->owner_id, ID_RECALC_GEOMETRY);
+}
- rna_Fluid_resetCache(bmain, scene, ptr);
+static void rna_Fluid_effector_reset(Main *bmain, Scene *scene, PointerRNA *ptr)
+{
+# ifdef WITH_FLUID
+ FluidEffectorSettings *settings = (FluidEffectorSettings *)ptr->data;
+ settings->flags |= FLUID_EFFECTOR_NEEDS_UPDATE;
+# endif
rna_Fluid_update(bmain, scene, ptr);
}
-static void rna_Fluid_reset_dependency(Main *bmain, Scene *scene, PointerRNA *ptr)
+static void rna_Fluid_flow_reset(Main *bmain, Scene *scene, PointerRNA *ptr)
{
- FluidDomainSettings *settings = (FluidDomainSettings *)ptr->data;
+# ifdef WITH_FLUID
+ FluidFlowSettings *settings = (FluidFlowSettings *)ptr->data;
+ settings->flags |= FLUID_FLOW_NEEDS_UPDATE;
+# endif
+
+ rna_Fluid_update(bmain, scene, ptr);
+}
+static void rna_Fluid_domain_reset(Main *bmain, Scene *scene, PointerRNA *ptr)
+{
# ifdef WITH_FLUID
+ FluidDomainSettings *settings = (FluidDomainSettings *)ptr->data;
BKE_fluid_modifier_reset(settings->mmd);
# endif
- if (settings->mmd && settings->mmd->domain) {
- settings->mmd->domain->point_cache[0]->flag |= PTCACHE_OUTDATED;
- }
+ rna_Fluid_datacache_reset(bmain, scene, ptr);
+ rna_Fluid_update(bmain, scene, ptr);
+}
+
+static void rna_Fluid_reset_dependency(Main *bmain, Scene *scene, PointerRNA *ptr)
+{
+# ifdef WITH_FLUID
+ FluidDomainSettings *settings = (FluidDomainSettings *)ptr->data;
+ BKE_fluid_modifier_reset(settings->mmd);
+# endif
rna_Fluid_dependency_update(bmain, scene, ptr);
}
@@ -156,12 +224,15 @@ static void rna_Fluid_flip_parts_update(Main *bmain, Scene *scene, PointerRNA *p
{
Object *ob = (Object *)ptr->owner_id;
FluidModifierData *mmd;
- mmd = (FluidModifierData *)modifiers_findByType(ob, eModifierType_Fluid);
+ mmd = (FluidModifierData *)BKE_modifiers_findby_type(ob, eModifierType_Fluid);
bool exists = rna_Fluid_parts_exists(ptr, PART_FLUID_FLIP);
- /* Only create a particle system in liquid domain mode. */
+ /* Only create a particle system in liquid domain mode.
+ * Remove any remaining data from a liquid sim when switching to gas. */
if (mmd->domain->type != FLUID_DOMAIN_TYPE_LIQUID) {
- rna_Fluid_reset(bmain, scene, ptr);
+ rna_Fluid_parts_delete(ptr, PART_FLUID_FLIP);
+ mmd->domain->particle_type &= ~FLUID_DOMAIN_PARTICLE_FLIP;
+ rna_Fluid_domain_reset(bmain, scene, ptr);
return;
}
@@ -181,7 +252,7 @@ static void rna_Fluid_spray_parts_update(Main *bmain, Scene *UNUSED(scene), Poin
{
Object *ob = (Object *)ptr->owner_id;
FluidModifierData *mmd;
- mmd = (FluidModifierData *)modifiers_findByType(ob, eModifierType_Fluid);
+ mmd = (FluidModifierData *)BKE_modifiers_findby_type(ob, eModifierType_Fluid);
bool exists = rna_Fluid_parts_exists(ptr, PART_FLUID_SPRAY);
if (ob->type == OB_MESH && !exists) {
@@ -199,7 +270,7 @@ static void rna_Fluid_bubble_parts_update(Main *bmain, Scene *UNUSED(scene), Poi
{
Object *ob = (Object *)ptr->owner_id;
FluidModifierData *mmd;
- mmd = (FluidModifierData *)modifiers_findByType(ob, eModifierType_Fluid);
+ mmd = (FluidModifierData *)BKE_modifiers_findby_type(ob, eModifierType_Fluid);
bool exists = rna_Fluid_parts_exists(ptr, PART_FLUID_BUBBLE);
if (ob->type == OB_MESH && !exists) {
@@ -221,7 +292,7 @@ static void rna_Fluid_foam_parts_update(Main *bmain, Scene *UNUSED(scene), Point
{
Object *ob = (Object *)ptr->owner_id;
FluidModifierData *mmd;
- mmd = (FluidModifierData *)modifiers_findByType(ob, eModifierType_Fluid);
+ mmd = (FluidModifierData *)BKE_modifiers_findby_type(ob, eModifierType_Fluid);
bool exists = rna_Fluid_parts_exists(ptr, PART_FLUID_FOAM);
if (ob->type == OB_MESH && !exists) {
@@ -239,7 +310,7 @@ static void rna_Fluid_tracer_parts_update(Main *bmain, Scene *UNUSED(scene), Poi
{
Object *ob = (Object *)ptr->owner_id;
FluidModifierData *mmd;
- mmd = (FluidModifierData *)modifiers_findByType(ob, eModifierType_Fluid);
+ mmd = (FluidModifierData *)BKE_modifiers_findby_type(ob, eModifierType_Fluid);
bool exists = rna_Fluid_parts_exists(ptr, PART_FLUID_TRACER);
if (ob->type == OB_MESH && !exists) {
@@ -261,7 +332,7 @@ static void rna_Fluid_combined_export_update(Main *bmain, Scene *scene, PointerR
{
Object *ob = (Object *)ptr->owner_id;
FluidModifierData *mmd;
- mmd = (FluidModifierData *)modifiers_findByType(ob, eModifierType_Fluid);
+ mmd = (FluidModifierData *)BKE_modifiers_findby_type(ob, eModifierType_Fluid);
if (mmd->domain->sndparticle_combined_export == SNDPARTICLE_COMBINED_EXPORT_OFF) {
rna_Fluid_parts_delete(ptr, PART_FLUID_SPRAYFOAM);
@@ -391,6 +462,18 @@ static void rna_Fluid_combined_export_update(Main *bmain, Scene *scene, PointerR
}
}
+static void rna_Fluid_cache_startframe_set(struct PointerRNA *ptr, int value)
+{
+ FluidDomainSettings *settings = (FluidDomainSettings *)ptr->data;
+ BKE_fluid_cache_startframe_set(settings, value);
+}
+
+static void rna_Fluid_cache_endframe_set(struct PointerRNA *ptr, int value)
+{
+ FluidDomainSettings *settings = (FluidDomainSettings *)ptr->data;
+ BKE_fluid_cache_endframe_set(settings, value);
+}
+
static void rna_Fluid_cachetype_mesh_set(struct PointerRNA *ptr, int value)
{
FluidDomainSettings *settings = (FluidDomainSettings *)ptr->data;
@@ -435,7 +518,7 @@ static void rna_Fluid_guide_parent_set(struct PointerRNA *ptr,
FluidModifierData *mmd_par = NULL;
if (par != NULL) {
- mmd_par = (FluidModifierData *)modifiers_findByType(par, eModifierType_Fluid);
+ mmd_par = (FluidModifierData *)BKE_modifiers_findby_type(par, eModifierType_Fluid);
if (mmd_par && mmd_par->domain) {
mds->guide_parent = value.data;
copy_v3_v3_int(mds->guide_res, mmd_par->domain->res);
@@ -1248,14 +1331,14 @@ static void rna_def_fluid_domain_settings(BlenderRNA *brna)
RNA_def_property_int_sdna(prop, NULL, "adapt_res");
RNA_def_property_range(prop, 0, 512);
RNA_def_property_ui_text(prop, "Additional", "Maximum number of additional cells");
- RNA_def_property_update(prop, NC_OBJECT | ND_MODIFIER, "rna_Fluid_resetCache");
+ RNA_def_property_update(prop, NC_OBJECT | ND_MODIFIER, "rna_Fluid_datacache_reset");
prop = RNA_def_property(srna, "adapt_margin", PROP_INT, PROP_NONE);
RNA_def_property_int_sdna(prop, NULL, "adapt_margin");
RNA_def_property_range(prop, 2, 24);
RNA_def_property_ui_text(
prop, "Margin", "Margin added around fluid to minimize boundary interference");
- RNA_def_property_update(prop, NC_OBJECT | ND_MODIFIER, "rna_Fluid_resetCache");
+ RNA_def_property_update(prop, NC_OBJECT | ND_MODIFIER, "rna_Fluid_datacache_reset");
prop = RNA_def_property(srna, "adapt_threshold", PROP_FLOAT, PROP_NONE);
RNA_def_property_range(prop, 0.0, 1.0);
@@ -1264,14 +1347,14 @@ static void rna_def_fluid_domain_settings(BlenderRNA *brna)
prop,
"Threshold",
"Minimum amount of fluid a cell can contain before it is considered empty");
- RNA_def_property_update(prop, NC_OBJECT | ND_MODIFIER, "rna_Fluid_resetCache");
+ RNA_def_property_update(prop, NC_OBJECT | ND_MODIFIER, "rna_Fluid_datacache_reset");
prop = RNA_def_property(srna, "use_adaptive_domain", PROP_BOOLEAN, PROP_NONE);
RNA_def_property_boolean_sdna(prop, NULL, "flags", FLUID_DOMAIN_USE_ADAPTIVE_DOMAIN);
RNA_def_property_ui_text(
prop, "Adaptive Domain", "Adapt simulation resolution and size to fluid");
RNA_def_property_clear_flag(prop, PROP_ANIMATABLE);
- RNA_def_property_update(prop, NC_OBJECT | ND_MODIFIER, "rna_Fluid_reset");
+ RNA_def_property_update(prop, NC_OBJECT | ND_MODIFIER, "rna_Fluid_domain_reset");
/* fluid domain options */
@@ -1285,44 +1368,44 @@ static void rna_def_fluid_domain_settings(BlenderRNA *brna)
"Resolution used for the fluid domain. Value corresponds to the longest domain side "
"(resolution for other domain sides is calculated automatically)");
RNA_def_property_clear_flag(prop, PROP_ANIMATABLE);
- RNA_def_property_update(prop, NC_OBJECT | ND_MODIFIER, "rna_Fluid_reset");
+ RNA_def_property_update(prop, NC_OBJECT | ND_MODIFIER, "rna_Fluid_domain_reset");
prop = RNA_def_property(srna, "use_collision_border_front", PROP_BOOLEAN, PROP_NONE);
RNA_def_property_boolean_sdna(prop, NULL, "border_collisions", FLUID_DOMAIN_BORDER_FRONT);
RNA_def_property_ui_text(prop, "Front", "Enable collisions with front domain border");
- RNA_def_property_update(prop, NC_OBJECT | ND_MODIFIER, "rna_Fluid_reset");
+ RNA_def_property_update(prop, NC_OBJECT | ND_MODIFIER, "rna_Fluid_datacache_reset");
prop = RNA_def_property(srna, "use_collision_border_back", PROP_BOOLEAN, PROP_NONE);
RNA_def_property_boolean_sdna(prop, NULL, "border_collisions", FLUID_DOMAIN_BORDER_BACK);
RNA_def_property_ui_text(prop, "Back", "Enable collisions with back domain border");
- RNA_def_property_update(prop, NC_OBJECT | ND_MODIFIER, "rna_Fluid_reset");
+ RNA_def_property_update(prop, NC_OBJECT | ND_MODIFIER, "rna_Fluid_datacache_reset");
prop = RNA_def_property(srna, "use_collision_border_right", PROP_BOOLEAN, PROP_NONE);
RNA_def_property_boolean_sdna(prop, NULL, "border_collisions", FLUID_DOMAIN_BORDER_RIGHT);
RNA_def_property_ui_text(prop, "Right", "Enable collisions with right domain border");
- RNA_def_property_update(prop, NC_OBJECT | ND_MODIFIER, "rna_Fluid_reset");
+ RNA_def_property_update(prop, NC_OBJECT | ND_MODIFIER, "rna_Fluid_datacache_reset");
prop = RNA_def_property(srna, "use_collision_border_left", PROP_BOOLEAN, PROP_NONE);
RNA_def_property_boolean_sdna(prop, NULL, "border_collisions", FLUID_DOMAIN_BORDER_LEFT);
RNA_def_property_ui_text(prop, "Left", "Enable collisions with left domain border");
- RNA_def_property_update(prop, NC_OBJECT | ND_MODIFIER, "rna_Fluid_reset");
+ RNA_def_property_update(prop, NC_OBJECT | ND_MODIFIER, "rna_Fluid_datacache_reset");
prop = RNA_def_property(srna, "use_collision_border_top", PROP_BOOLEAN, PROP_NONE);
RNA_def_property_boolean_sdna(prop, NULL, "border_collisions", FLUID_DOMAIN_BORDER_TOP);
RNA_def_property_ui_text(prop, "Top", "Enable collisions with top domain border");
- RNA_def_property_update(prop, NC_OBJECT | ND_MODIFIER, "rna_Fluid_reset");
+ RNA_def_property_update(prop, NC_OBJECT | ND_MODIFIER, "rna_Fluid_datacache_reset");
prop = RNA_def_property(srna, "use_collision_border_bottom", PROP_BOOLEAN, PROP_NONE);
RNA_def_property_boolean_sdna(prop, NULL, "border_collisions", FLUID_DOMAIN_BORDER_BOTTOM);
RNA_def_property_ui_text(prop, "Bottom", "Enable collisions with bottom domain border");
- RNA_def_property_update(prop, NC_OBJECT | ND_MODIFIER, "rna_Fluid_reset");
+ RNA_def_property_update(prop, NC_OBJECT | ND_MODIFIER, "rna_Fluid_datacache_reset");
prop = RNA_def_property(srna, "gravity", PROP_FLOAT, PROP_ACCELERATION);
RNA_def_property_float_sdna(prop, NULL, "gravity");
RNA_def_property_array(prop, 3);
RNA_def_property_range(prop, -1000.1, 1000.1);
RNA_def_property_ui_text(prop, "Gravity", "Gravity in X, Y and Z direction");
- RNA_def_property_update(prop, NC_OBJECT | ND_MODIFIER, "rna_Fluid_resetCache");
+ RNA_def_property_update(prop, NC_OBJECT | ND_MODIFIER, "rna_Fluid_datacache_reset");
prop = RNA_def_property(srna, "domain_type", PROP_ENUM, PROP_NONE);
RNA_def_property_enum_sdna(prop, NULL, "type");
@@ -1335,7 +1418,7 @@ static void rna_def_fluid_domain_settings(BlenderRNA *brna)
prop = RNA_def_property(srna, "delete_in_obstacle", PROP_BOOLEAN, PROP_NONE);
RNA_def_property_boolean_sdna(prop, NULL, "flags", FLUID_DOMAIN_DELETE_IN_OBSTACLE);
RNA_def_property_ui_text(prop, "Clear In Obstacle", "Delete fluid inside obstacles");
- RNA_def_property_update(prop, NC_OBJECT | ND_MODIFIER, "rna_Fluid_reset");
+ RNA_def_property_update(prop, NC_OBJECT | ND_MODIFIER, "rna_Fluid_datacache_reset");
/* smoke domain options */
@@ -1347,7 +1430,7 @@ static void rna_def_fluid_domain_settings(BlenderRNA *brna)
prop,
"Buoyancy Density",
"Buoyant force based on smoke density (higher value results in faster rising smoke)");
- RNA_def_property_update(prop, NC_OBJECT | ND_MODIFIER, "rna_Fluid_resetCache");
+ RNA_def_property_update(prop, NC_OBJECT | ND_MODIFIER, "rna_Fluid_datacache_reset");
prop = RNA_def_property(srna, "beta", PROP_FLOAT, PROP_NONE);
RNA_def_property_float_sdna(prop, NULL, "beta");
@@ -1357,7 +1440,7 @@ static void rna_def_fluid_domain_settings(BlenderRNA *brna)
prop,
"Buoyancy Heat",
"Buoyant force based on smoke heat (higher value results in faster rising smoke)");
- RNA_def_property_update(prop, NC_OBJECT | ND_MODIFIER, "rna_Fluid_resetCache");
+ RNA_def_property_update(prop, NC_OBJECT | ND_MODIFIER, "rna_Fluid_datacache_reset");
prop = RNA_def_property(srna, "dissolve_speed", PROP_INT, PROP_NONE);
RNA_def_property_int_sdna(prop, NULL, "diss_speed");
@@ -1367,23 +1450,23 @@ static void rna_def_fluid_domain_settings(BlenderRNA *brna)
prop,
"Dissolve Speed",
"Determine how quickly the smoke dissolves (lower value makes smoke disappear faster)");
- RNA_def_property_update(prop, NC_OBJECT | ND_MODIFIER, "rna_Fluid_resetCache");
+ RNA_def_property_update(prop, NC_OBJECT | ND_MODIFIER, "rna_Fluid_datacache_reset");
prop = RNA_def_property(srna, "vorticity", PROP_FLOAT, PROP_NONE);
RNA_def_property_float_sdna(prop, NULL, "vorticity");
RNA_def_property_range(prop, 0.0, 4.0);
RNA_def_property_ui_text(prop, "Vorticity", "Amount of turbulence and rotation in smoke");
- RNA_def_property_update(prop, NC_OBJECT | ND_MODIFIER, "rna_Fluid_resetCache");
+ RNA_def_property_update(prop, NC_OBJECT | ND_MODIFIER, "rna_Fluid_datacache_reset");
prop = RNA_def_property(srna, "highres_sampling", PROP_ENUM, PROP_NONE);
RNA_def_property_enum_items(prop, smoke_highres_sampling_items);
RNA_def_property_ui_text(prop, "Emitter", "Method for sampling the high resolution flow");
- RNA_def_property_update(prop, NC_OBJECT | ND_MODIFIER, "rna_Fluid_resetCache");
+ RNA_def_property_update(prop, NC_OBJECT | ND_MODIFIER, "rna_Fluid_datacache_reset");
prop = RNA_def_property(srna, "use_dissolve_smoke", PROP_BOOLEAN, PROP_NONE);
RNA_def_property_boolean_sdna(prop, NULL, "flags", FLUID_DOMAIN_USE_DISSOLVE);
RNA_def_property_ui_text(prop, "Dissolve Smoke", "Let smoke disappear over time");
- RNA_def_property_update(prop, NC_OBJECT | ND_MODIFIER, "rna_Fluid_resetCache");
+ RNA_def_property_update(prop, NC_OBJECT | ND_MODIFIER, "rna_Fluid_datacache_reset");
prop = RNA_def_property(srna, "use_dissolve_smoke_log", PROP_BOOLEAN, PROP_NONE);
RNA_def_property_boolean_sdna(prop, NULL, "flags", FLUID_DOMAIN_USE_DISSOLVE_LOG);
@@ -1391,7 +1474,7 @@ static void rna_def_fluid_domain_settings(BlenderRNA *brna)
prop,
"Logarithmic Dissolve",
"Dissolve smoke in a logarithmic fashion. Dissolves quickly at first, but lingers longer");
- RNA_def_property_update(prop, NC_OBJECT | ND_MODIFIER, "rna_Fluid_resetCache");
+ RNA_def_property_update(prop, NC_OBJECT | ND_MODIFIER, "rna_Fluid_datacache_reset");
/* flame options */
@@ -1400,19 +1483,19 @@ static void rna_def_fluid_domain_settings(BlenderRNA *brna)
RNA_def_property_ui_range(prop, 0.01, 2.0, 1.0, 5);
RNA_def_property_ui_text(
prop, "Speed", "Speed of the burning reaction (higher value results in smaller flames)");
- RNA_def_property_update(prop, NC_OBJECT | ND_MODIFIER, "rna_Fluid_resetCache");
+ RNA_def_property_update(prop, NC_OBJECT | ND_MODIFIER, "rna_Fluid_datacache_reset");
prop = RNA_def_property(srna, "flame_smoke", PROP_FLOAT, PROP_NONE);
RNA_def_property_range(prop, 0.0, 8.0);
RNA_def_property_ui_range(prop, 0.0, 4.0, 1.0, 5);
RNA_def_property_ui_text(prop, "Smoke", "Amount of smoke created by burning fuel");
- RNA_def_property_update(prop, NC_OBJECT | ND_MODIFIER, "rna_Fluid_resetCache");
+ RNA_def_property_update(prop, NC_OBJECT | ND_MODIFIER, "rna_Fluid_datacache_reset");
prop = RNA_def_property(srna, "flame_vorticity", PROP_FLOAT, PROP_NONE);
RNA_def_property_range(prop, 0.0, 2.0);
RNA_def_property_ui_range(prop, 0.0, 1.0, 1.0, 5);
RNA_def_property_ui_text(prop, "Vorticity", "Additional vorticity for the flames");
- RNA_def_property_update(prop, NC_OBJECT | ND_MODIFIER, "rna_Fluid_resetCache");
+ RNA_def_property_update(prop, NC_OBJECT | ND_MODIFIER, "rna_Fluid_datacache_reset");
prop = RNA_def_property(srna, "flame_ignition", PROP_FLOAT, PROP_NONE);
RNA_def_property_range(prop, 0.5, 5.0);
@@ -1421,7 +1504,7 @@ static void rna_def_fluid_domain_settings(BlenderRNA *brna)
prop,
"Minimum",
"Minimum temperature of the flames (higher value results in faster rising flames)");
- RNA_def_property_update(prop, NC_OBJECT | ND_MODIFIER, "rna_Fluid_resetCache");
+ RNA_def_property_update(prop, NC_OBJECT | ND_MODIFIER, "rna_Fluid_datacache_reset");
prop = RNA_def_property(srna, "flame_max_temp", PROP_FLOAT, PROP_NONE);
RNA_def_property_range(prop, 1.0, 10.0);
@@ -1430,12 +1513,12 @@ static void rna_def_fluid_domain_settings(BlenderRNA *brna)
prop,
"Maximum",
"Maximum temperature of the flames (higher value results in faster rising flames)");
- RNA_def_property_update(prop, NC_OBJECT | ND_MODIFIER, "rna_Fluid_resetCache");
+ RNA_def_property_update(prop, NC_OBJECT | ND_MODIFIER, "rna_Fluid_datacache_reset");
prop = RNA_def_property(srna, "flame_smoke_color", PROP_FLOAT, PROP_COLOR_GAMMA);
RNA_def_property_array(prop, 3);
RNA_def_property_ui_text(prop, "Smoke Color", "Color of smoke emitted from burning fuel");
- RNA_def_property_update(prop, NC_OBJECT | ND_MODIFIER, "rna_Fluid_resetCache");
+ RNA_def_property_update(prop, NC_OBJECT | ND_MODIFIER, "rna_Fluid_datacache_reset");
/* noise options */
@@ -1444,19 +1527,20 @@ static void rna_def_fluid_domain_settings(BlenderRNA *brna)
RNA_def_property_range(prop, 0.0, 10.0);
RNA_def_property_ui_range(prop, 0.0, 10.0, 1, 2);
RNA_def_property_ui_text(prop, "Strength", "Strength of noise");
- RNA_def_property_update(prop, NC_OBJECT | ND_MODIFIER, "rna_Fluid_resetCache");
+ RNA_def_property_update(prop, NC_OBJECT | ND_MODIFIER, "rna_Fluid_noisecache_reset");
prop = RNA_def_property(srna, "noise_pos_scale", PROP_FLOAT, PROP_NONE);
RNA_def_property_float_sdna(prop, NULL, "noise_pos_scale");
RNA_def_property_range(prop, 0.0001, 10.0);
RNA_def_property_ui_text(
prop, "Scale", "Scale of noise (higher value results in larger vortices)");
- RNA_def_property_update(prop, NC_OBJECT | ND_MODIFIER, "rna_Fluid_resetCache");
+ RNA_def_property_update(prop, NC_OBJECT | ND_MODIFIER, "rna_Fluid_noisecache_reset");
prop = RNA_def_property(srna, "noise_time_anim", PROP_FLOAT, PROP_NONE);
RNA_def_property_float_sdna(prop, NULL, "noise_time_anim");
RNA_def_property_range(prop, 0.0001, 10.0);
RNA_def_property_ui_text(prop, "Time", "Animation time of noise");
+ RNA_def_property_update(prop, NC_OBJECT | ND_MODIFIER, "rna_Fluid_noisecache_reset");
prop = RNA_def_property(srna, "noise_scale", PROP_INT, PROP_NONE);
RNA_def_property_int_sdna(prop, NULL, "noise_scale");
@@ -1467,7 +1551,7 @@ static void rna_def_fluid_domain_settings(BlenderRNA *brna)
"The noise simulation is scaled up by this factor (compared to the "
"base resolution of the domain)");
RNA_def_property_clear_flag(prop, PROP_ANIMATABLE);
- RNA_def_property_update(prop, NC_OBJECT | ND_MODIFIER, "rna_Fluid_reset");
+ RNA_def_property_update(prop, NC_OBJECT | ND_MODIFIER, "rna_Fluid_domain_reset");
prop = RNA_def_property(srna, "noise_type", PROP_ENUM, PROP_NONE);
RNA_def_property_enum_sdna(prop, NULL, "noise_type");
@@ -1475,7 +1559,7 @@ static void rna_def_fluid_domain_settings(BlenderRNA *brna)
RNA_def_property_ui_text(
prop, "Noise Method", "Noise method which is used during the high-res simulation");
RNA_def_property_clear_flag(prop, PROP_ANIMATABLE);
- RNA_def_property_update(prop, NC_OBJECT | ND_MODIFIER, "rna_Fluid_reset");
+ RNA_def_property_update(prop, NC_OBJECT | ND_MODIFIER, "rna_Fluid_domain_reset");
prop = RNA_def_property(srna, "use_noise", PROP_BOOLEAN, PROP_NONE);
RNA_def_property_boolean_sdna(prop, NULL, "flags", FLUID_DOMAIN_USE_NOISE);
@@ -1489,7 +1573,7 @@ static void rna_def_fluid_domain_settings(BlenderRNA *brna)
RNA_def_property_enum_sdna(prop, NULL, "simulation_method");
RNA_def_property_enum_items(prop, simulation_methods);
RNA_def_property_ui_text(prop, "Simulation Method", "Change the underlying simulation method");
- RNA_def_property_update(prop, NC_OBJECT | ND_MODIFIER, "rna_Fluid_reset");
+ RNA_def_property_update(prop, NC_OBJECT | ND_MODIFIER, "rna_Fluid_domain_reset");
prop = RNA_def_property(srna, "flip_ratio", PROP_FLOAT, PROP_NONE);
RNA_def_property_range(prop, 0.0, 1.0);
@@ -1498,18 +1582,18 @@ static void rna_def_fluid_domain_settings(BlenderRNA *brna)
"FLIP Ratio",
"PIC/FLIP Ratio. A value of 1.0 will result in a completely FLIP based simulation. Use a "
"lower value for simulations which should produce smaller splashes");
- RNA_def_property_update(prop, NC_OBJECT | ND_MODIFIER, "rna_Fluid_resetCache");
+ RNA_def_property_update(prop, NC_OBJECT | ND_MODIFIER, "rna_Fluid_datacache_reset");
prop = RNA_def_property(srna, "particle_randomness", PROP_FLOAT, PROP_NONE);
RNA_def_property_range(prop, 0.0, 10.0);
RNA_def_property_ui_text(prop, "Randomness", "Randomness factor for particle sampling");
- RNA_def_property_update(prop, NC_OBJECT | ND_MODIFIER, "rna_Fluid_resetCache");
+ RNA_def_property_update(prop, NC_OBJECT | ND_MODIFIER, "rna_Fluid_datacache_reset");
prop = RNA_def_property(srna, "particle_number", PROP_INT, PROP_NONE);
RNA_def_property_range(prop, 1, 5);
RNA_def_property_ui_text(
prop, "Number", "Particle number factor (higher value results in more particles)");
- RNA_def_property_update(prop, NC_OBJECT | ND_MODIFIER, "rna_Fluid_resetCache");
+ RNA_def_property_update(prop, NC_OBJECT | ND_MODIFIER, "rna_Fluid_datacache_reset");
prop = RNA_def_property(srna, "particle_min", PROP_INT, PROP_NONE);
RNA_def_property_int_sdna(prop, NULL, "particle_minimum");
@@ -1518,7 +1602,7 @@ static void rna_def_fluid_domain_settings(BlenderRNA *brna)
"Minimum",
"Minimum number of particles per cell (ensures that each cell has at "
"least this amount of particles)");
- RNA_def_property_update(prop, NC_OBJECT | ND_MODIFIER, "rna_Fluid_resetCache");
+ RNA_def_property_update(prop, NC_OBJECT | ND_MODIFIER, "rna_Fluid_datacache_reset");
prop = RNA_def_property(srna, "particle_max", PROP_INT, PROP_NONE);
RNA_def_property_int_sdna(prop, NULL, "particle_maximum");
@@ -1527,7 +1611,7 @@ static void rna_def_fluid_domain_settings(BlenderRNA *brna)
"Maximum",
"Maximum number of particles per cell (ensures that each cell has at "
"most this amount of particles)");
- RNA_def_property_update(prop, NC_OBJECT | ND_MODIFIER, "rna_Fluid_resetCache");
+ RNA_def_property_update(prop, NC_OBJECT | ND_MODIFIER, "rna_Fluid_datacache_reset");
prop = RNA_def_property(srna, "particle_radius", PROP_FLOAT, PROP_NONE);
RNA_def_property_range(prop, 0.0, 10.0);
@@ -1535,7 +1619,7 @@ static void rna_def_fluid_domain_settings(BlenderRNA *brna)
"Radius",
"Particle radius factor. Increase this value if the simulation appears "
"to leak volume, decrease it if the simulation seems to gain volume");
- RNA_def_property_update(prop, NC_OBJECT | ND_MODIFIER, "rna_Fluid_resetCache");
+ RNA_def_property_update(prop, NC_OBJECT | ND_MODIFIER, "rna_Fluid_datacache_reset");
prop = RNA_def_property(srna, "particle_band_width", PROP_FLOAT, PROP_NONE);
RNA_def_property_range(prop, 0.0, 1000.0);
@@ -1543,7 +1627,7 @@ static void rna_def_fluid_domain_settings(BlenderRNA *brna)
prop,
"Width",
"Particle (narrow) band width (higher value results in thicker band and more particles)");
- RNA_def_property_update(prop, NC_OBJECT | ND_MODIFIER, "rna_Fluid_resetCache");
+ RNA_def_property_update(prop, NC_OBJECT | ND_MODIFIER, "rna_Fluid_datacache_reset");
prop = RNA_def_property(srna, "use_flip_particles", PROP_BOOLEAN, PROP_NONE);
RNA_def_property_boolean_sdna(prop, NULL, "particle_type", FLUID_DOMAIN_PARTICLE_FLIP);
@@ -1557,7 +1641,8 @@ static void rna_def_fluid_domain_settings(BlenderRNA *brna)
prop,
"Fractional Obstacles",
"Fractional obstacles improve and smoothen the fluid-obstacle boundary");
- RNA_def_property_update(prop, NC_OBJECT | ND_MODIFIER, "rna_Fluid_resetCache");
+ RNA_def_property_clear_flag(prop, PROP_ANIMATABLE);
+ RNA_def_property_update(prop, NC_OBJECT | ND_MODIFIER, "rna_Fluid_datacache_reset");
prop = RNA_def_property(srna, "fractions_threshold", PROP_FLOAT, PROP_NONE);
RNA_def_property_range(prop, 0.001, 1.0);
@@ -1567,7 +1652,7 @@ static void rna_def_fluid_domain_settings(BlenderRNA *brna)
"Determines how much fluid is allowed in an obstacle cell "
"(higher values will tag a boundary cell as an obstacle easier "
"and reduce the boundary smoothening effect)");
- RNA_def_property_update(prop, NC_OBJECT | ND_MODIFIER, "rna_Fluid_resetCache");
+ RNA_def_property_update(prop, NC_OBJECT | ND_MODIFIER, "rna_Fluid_datacache_reset");
/* diffusion options */
@@ -1576,7 +1661,7 @@ static void rna_def_fluid_domain_settings(BlenderRNA *brna)
RNA_def_property_ui_text(
prop, "Use Diffusion", "Enable fluid diffusion settings (e.g. viscosity, surface tension)");
RNA_def_property_clear_flag(prop, PROP_ANIMATABLE);
- RNA_def_property_update(prop, NC_OBJECT | ND_MODIFIER, "rna_Fluid_reset");
+ RNA_def_property_update(prop, NC_OBJECT | ND_MODIFIER, "rna_Fluid_domain_reset");
prop = RNA_def_property(srna, "surface_tension", PROP_FLOAT, PROP_NONE);
RNA_def_property_range(prop, 0.0, 100.0);
@@ -1584,7 +1669,7 @@ static void rna_def_fluid_domain_settings(BlenderRNA *brna)
prop,
"Tension",
"Surface tension of liquid (higher value results in greater hydrophobic behaviour)");
- RNA_def_property_update(prop, NC_OBJECT | ND_MODIFIER, "rna_Fluid_reset");
+ RNA_def_property_update(prop, NC_OBJECT | ND_MODIFIER, "rna_Fluid_datacache_reset");
prop = RNA_def_property(srna, "viscosity_base", PROP_FLOAT, PROP_NONE);
RNA_def_property_float_sdna(prop, NULL, "viscosity_base");
@@ -1593,7 +1678,7 @@ static void rna_def_fluid_domain_settings(BlenderRNA *brna)
prop,
"Viscosity Base",
"Viscosity setting: value that is multiplied by 10 to the power of (exponent*-1)");
- RNA_def_property_update(prop, NC_OBJECT | ND_MODIFIER, "rna_Fluid_reset");
+ RNA_def_property_update(prop, NC_OBJECT | ND_MODIFIER, "rna_Fluid_datacache_reset");
prop = RNA_def_property(srna, "viscosity_exponent", PROP_INT, PROP_NONE);
RNA_def_property_int_sdna(prop, NULL, "viscosity_exponent");
@@ -1603,12 +1688,7 @@ static void rna_def_fluid_domain_settings(BlenderRNA *brna)
"Viscosity Exponent",
"Negative exponent for the viscosity value (to simplify entering small values "
"e.g. 5*10^-6)");
- RNA_def_property_update(prop, NC_OBJECT | ND_MODIFIER, "rna_Fluid_reset");
-
- prop = RNA_def_property(srna, "domain_size", PROP_FLOAT, PROP_NONE);
- RNA_def_property_range(prop, 0.001, 10000.0);
- RNA_def_property_ui_text(prop, "Meters", "Domain size in meters (longest domain side)");
- RNA_def_property_update(prop, NC_OBJECT | ND_MODIFIER, "rna_Fluid_reset");
+ RNA_def_property_update(prop, NC_OBJECT | ND_MODIFIER, "rna_Fluid_datacache_reset");
/* mesh options options */
@@ -1618,7 +1698,7 @@ static void rna_def_fluid_domain_settings(BlenderRNA *brna)
prop,
"Upper Concavity",
"Upper mesh concavity bound (high values tend to smoothen and fill out concave regions)");
- RNA_def_property_update(prop, NC_OBJECT | ND_MODIFIER, "rna_Fluid_resetCache");
+ RNA_def_property_update(prop, NC_OBJECT | ND_MODIFIER, "rna_Fluid_meshcache_reset");
prop = RNA_def_property(srna, "mesh_concave_lower", PROP_FLOAT, PROP_NONE);
RNA_def_property_range(prop, 0.0, 10.0);
@@ -1626,17 +1706,17 @@ static void rna_def_fluid_domain_settings(BlenderRNA *brna)
prop,
"Lower Concavity",
"Lower mesh concavity bound (high values tend to smoothen and fill out concave regions)");
- RNA_def_property_update(prop, NC_OBJECT | ND_MODIFIER, "rna_Fluid_resetCache");
+ RNA_def_property_update(prop, NC_OBJECT | ND_MODIFIER, "rna_Fluid_meshcache_reset");
prop = RNA_def_property(srna, "mesh_smoothen_pos", PROP_INT, PROP_NONE);
RNA_def_property_range(prop, 0, 100);
RNA_def_property_ui_text(prop, "Smoothen Pos", "Positive mesh smoothening");
- RNA_def_property_update(prop, NC_OBJECT | ND_MODIFIER, "rna_Fluid_resetCache");
+ RNA_def_property_update(prop, NC_OBJECT | ND_MODIFIER, "rna_Fluid_meshcache_reset");
prop = RNA_def_property(srna, "mesh_smoothen_neg", PROP_INT, PROP_NONE);
RNA_def_property_range(prop, 0, 100);
RNA_def_property_ui_text(prop, "Smoothen Neg", "Negative mesh smoothening");
- RNA_def_property_update(prop, NC_OBJECT | ND_MODIFIER, "rna_Fluid_resetCache");
+ RNA_def_property_update(prop, NC_OBJECT | ND_MODIFIER, "rna_Fluid_meshcache_reset");
prop = RNA_def_property(srna, "mesh_scale", PROP_INT, PROP_NONE);
RNA_def_property_int_sdna(prop, NULL, "mesh_scale");
@@ -1648,7 +1728,7 @@ static void rna_def_fluid_domain_settings(BlenderRNA *brna)
"resolution of the domain). For best meshing, it is recommended to "
"adjust the mesh particle radius alongside this value");
RNA_def_property_clear_flag(prop, PROP_ANIMATABLE);
- RNA_def_property_update(prop, NC_OBJECT | ND_MODIFIER, "rna_Fluid_reset");
+ RNA_def_property_update(prop, NC_OBJECT | ND_MODIFIER, "rna_Fluid_meshcache_reset");
prop = RNA_def_property(srna, "mesh_generator", PROP_ENUM, PROP_NONE);
RNA_def_property_enum_sdna(prop, NULL, "mesh_generator");
@@ -1677,7 +1757,7 @@ static void rna_def_fluid_domain_settings(BlenderRNA *brna)
"Caches velocities of mesh vertices. These will be used "
"(automatically) when rendering with motion blur enabled");
RNA_def_property_clear_flag(prop, PROP_ANIMATABLE);
- RNA_def_property_update(prop, NC_OBJECT | ND_MODIFIER, "rna_Fluid_reset");
+ RNA_def_property_update(prop, NC_OBJECT | ND_MODIFIER, "rna_Fluid_meshcache_reset");
prop = RNA_def_property(srna, "mesh_particle_radius", PROP_FLOAT, PROP_NONE);
RNA_def_property_range(prop, 0.0, 10.0);
@@ -1685,7 +1765,7 @@ static void rna_def_fluid_domain_settings(BlenderRNA *brna)
"Radius",
"Particle radius factor (higher value results in larger (meshed) "
"particles). Needs to be adjusted after changing the mesh scale");
- RNA_def_property_update(prop, NC_OBJECT | ND_MODIFIER, "rna_Fluid_resetCache");
+ RNA_def_property_update(prop, NC_OBJECT | ND_MODIFIER, "rna_Fluid_meshcache_reset");
/* secondary particles options */
@@ -1697,7 +1777,7 @@ static void rna_def_fluid_domain_settings(BlenderRNA *brna)
"Minimum Wave Crest Potential",
"Lower clamping threshold for marking fluid cells as wave crests "
"(lower value results in more marked cells)");
- RNA_def_property_update(prop, NC_OBJECT | ND_MODIFIER, "rna_Fluid_resetCache");
+ RNA_def_property_update(prop, NC_OBJECT | ND_MODIFIER, "rna_Fluid_particlescache_reset");
prop = RNA_def_property(srna, "sndparticle_potential_max_wavecrest", PROP_FLOAT, PROP_NONE);
RNA_def_property_float_sdna(prop, NULL, "sndparticle_tau_max_wc");
@@ -1707,7 +1787,7 @@ static void rna_def_fluid_domain_settings(BlenderRNA *brna)
"Maximum Wave Crest Potential",
"Upper clamping threshold for marking fluid cells as wave crests "
"(higher value results in less marked cells)");
- RNA_def_property_update(prop, NC_OBJECT | ND_MODIFIER, "rna_Fluid_resetCache");
+ RNA_def_property_update(prop, NC_OBJECT | ND_MODIFIER, "rna_Fluid_particlescache_reset");
prop = RNA_def_property(srna, "sndparticle_potential_min_trappedair", PROP_FLOAT, PROP_NONE);
RNA_def_property_float_sdna(prop, NULL, "sndparticle_tau_min_ta");
@@ -1717,7 +1797,7 @@ static void rna_def_fluid_domain_settings(BlenderRNA *brna)
"Minimum Trapped Air Potential",
"Lower clamping threshold for marking fluid cells where air is trapped "
"(lower value results in more marked cells)");
- RNA_def_property_update(prop, NC_OBJECT | ND_MODIFIER, "rna_Fluid_resetCache");
+ RNA_def_property_update(prop, NC_OBJECT | ND_MODIFIER, "rna_Fluid_particlescache_reset");
prop = RNA_def_property(srna, "sndparticle_potential_max_trappedair", PROP_FLOAT, PROP_NONE);
RNA_def_property_float_sdna(prop, NULL, "sndparticle_tau_max_ta");
@@ -1727,7 +1807,7 @@ static void rna_def_fluid_domain_settings(BlenderRNA *brna)
"Maximum Trapped Air Potential",
"Upper clamping threshold for marking fluid cells where air is trapped "
"(higher value results in less marked cells)");
- RNA_def_property_update(prop, NC_OBJECT | ND_MODIFIER, "rna_Fluid_resetCache");
+ RNA_def_property_update(prop, NC_OBJECT | ND_MODIFIER, "rna_Fluid_particlescache_reset");
prop = RNA_def_property(srna, "sndparticle_potential_min_energy", PROP_FLOAT, PROP_NONE);
RNA_def_property_float_sdna(prop, NULL, "sndparticle_tau_min_k");
@@ -1738,7 +1818,7 @@ static void rna_def_fluid_domain_settings(BlenderRNA *brna)
"Minimum Kinetic Energy Potential",
"Lower clamping threshold that indicates the fluid speed where cells start to emit "
"particles (lower values result in generally more particles)");
- RNA_def_property_update(prop, NC_OBJECT | ND_MODIFIER, "rna_Fluid_resetCache");
+ RNA_def_property_update(prop, NC_OBJECT | ND_MODIFIER, "rna_Fluid_particlescache_reset");
prop = RNA_def_property(srna, "sndparticle_potential_max_energy", PROP_FLOAT, PROP_NONE);
RNA_def_property_float_sdna(prop, NULL, "sndparticle_tau_max_k");
@@ -1749,7 +1829,7 @@ static void rna_def_fluid_domain_settings(BlenderRNA *brna)
"Maximum Kinetic Energy Potential",
"Upper clamping threshold that indicates the fluid speed where cells no longer emit more "
"particles (higher value results in generally less particles)");
- RNA_def_property_update(prop, NC_OBJECT | ND_MODIFIER, "rna_Fluid_resetCache");
+ RNA_def_property_update(prop, NC_OBJECT | ND_MODIFIER, "rna_Fluid_particlescache_reset");
prop = RNA_def_property(srna, "sndparticle_sampling_wavecrest", PROP_INT, PROP_NONE);
RNA_def_property_int_sdna(prop, NULL, "sndparticle_k_wc");
@@ -1758,7 +1838,7 @@ static void rna_def_fluid_domain_settings(BlenderRNA *brna)
RNA_def_property_ui_text(prop,
"Wave Crest Sampling",
"Maximum number of particles generated per wave crest cell per frame");
- RNA_def_property_update(prop, NC_OBJECT | ND_MODIFIER, "rna_Fluid_resetCache");
+ RNA_def_property_update(prop, NC_OBJECT | ND_MODIFIER, "rna_Fluid_particlescache_reset");
prop = RNA_def_property(srna, "sndparticle_sampling_trappedair", PROP_INT, PROP_NONE);
RNA_def_property_int_sdna(prop, NULL, "sndparticle_k_ta");
@@ -1767,7 +1847,7 @@ static void rna_def_fluid_domain_settings(BlenderRNA *brna)
RNA_def_property_ui_text(prop,
"Trapped Air Sampling",
"Maximum number of particles generated per trapped air cell per frame");
- RNA_def_property_update(prop, NC_OBJECT | ND_MODIFIER, "rna_Fluid_resetCache");
+ RNA_def_property_update(prop, NC_OBJECT | ND_MODIFIER, "rna_Fluid_particlescache_reset");
prop = RNA_def_property(srna, "sndparticle_bubble_buoyancy", PROP_FLOAT, PROP_NONE);
RNA_def_property_float_sdna(prop, NULL, "sndparticle_k_b");
@@ -1777,7 +1857,7 @@ static void rna_def_fluid_domain_settings(BlenderRNA *brna)
"Bubble Buoyancy",
"Amount of buoyancy force that rises bubbles (high value results in "
"bubble movement mainly upwards)");
- RNA_def_property_update(prop, NC_OBJECT | ND_MODIFIER, "rna_Fluid_resetCache");
+ RNA_def_property_update(prop, NC_OBJECT | ND_MODIFIER, "rna_Fluid_particlescache_reset");
prop = RNA_def_property(srna, "sndparticle_bubble_drag", PROP_FLOAT, PROP_NONE);
RNA_def_property_float_sdna(prop, NULL, "sndparticle_k_d");
@@ -1787,28 +1867,28 @@ static void rna_def_fluid_domain_settings(BlenderRNA *brna)
"Bubble Drag",
"Amount of drag force that moves bubbles along with the fluid (high "
"value results in bubble movement mainly along with the fluid)");
- RNA_def_property_update(prop, NC_OBJECT | ND_MODIFIER, "rna_Fluid_resetCache");
+ RNA_def_property_update(prop, NC_OBJECT | ND_MODIFIER, "rna_Fluid_particlescache_reset");
prop = RNA_def_property(srna, "sndparticle_life_min", PROP_FLOAT, PROP_NONE);
RNA_def_property_float_sdna(prop, NULL, "sndparticle_l_min");
RNA_def_property_range(prop, 0.0, 10000.0);
RNA_def_property_ui_range(prop, 0.0, 10000.0, 100.0, 1);
RNA_def_property_ui_text(prop, "Minimum Lifetime", "Lowest possible particle lifetime");
- RNA_def_property_update(prop, NC_OBJECT | ND_MODIFIER, "rna_Fluid_resetCache");
+ RNA_def_property_update(prop, NC_OBJECT | ND_MODIFIER, "rna_Fluid_particlescache_reset");
prop = RNA_def_property(srna, "sndparticle_life_max", PROP_FLOAT, PROP_NONE);
RNA_def_property_float_sdna(prop, NULL, "sndparticle_l_max");
RNA_def_property_range(prop, 0.0, 10000.0);
RNA_def_property_ui_range(prop, 0.0, 10000.0, 100.0, 1);
RNA_def_property_ui_text(prop, "Maximum Lifetime", "Highest possible particle lifetime");
- RNA_def_property_update(prop, NC_OBJECT | ND_MODIFIER, "rna_Fluid_resetCache");
+ RNA_def_property_update(prop, NC_OBJECT | ND_MODIFIER, "rna_Fluid_particlescache_reset");
prop = RNA_def_property(srna, "sndparticle_boundary", PROP_ENUM, PROP_NONE);
RNA_def_property_enum_sdna(prop, NULL, "sndparticle_boundary");
RNA_def_property_enum_items(prop, sndparticle_boundary_items);
RNA_def_property_ui_text(
prop, "Particles in Boundary", "How particles that left the domain are treated");
- RNA_def_property_update(prop, NC_OBJECT | ND_DRAW, NULL);
+ RNA_def_property_update(prop, NC_OBJECT | ND_MODIFIER, "rna_Fluid_particlescache_reset");
prop = RNA_def_property(srna, "sndparticle_combined_export", PROP_ENUM, PROP_NONE);
RNA_def_property_enum_sdna(prop, NULL, "sndparticle_combined_export");
@@ -1827,7 +1907,7 @@ static void rna_def_fluid_domain_settings(BlenderRNA *brna)
"Potential Radius",
"Radius to compute potential for each cell (higher values are slower "
"but create smoother potential grids)");
- RNA_def_property_update(prop, NC_OBJECT | ND_MODIFIER, "rna_Fluid_resetCache");
+ RNA_def_property_update(prop, NC_OBJECT | ND_MODIFIER, "rna_Fluid_particlescache_reset");
prop = RNA_def_property(srna, "sndparticle_update_radius", PROP_INT, PROP_NONE);
RNA_def_property_int_sdna(prop, NULL, "sndparticle_update_radius");
@@ -1837,7 +1917,7 @@ static void rna_def_fluid_domain_settings(BlenderRNA *brna)
"Update Radius",
"Radius to compute position update for each particle (higher values "
"are slower but particles move less chaotic)");
- RNA_def_property_update(prop, NC_OBJECT | ND_MODIFIER, "rna_Fluid_resetCache");
+ RNA_def_property_update(prop, NC_OBJECT | ND_MODIFIER, "rna_Fluid_particlescache_reset");
prop = RNA_def_property(srna, "particle_scale", PROP_INT, PROP_NONE);
RNA_def_property_int_sdna(prop, NULL, "particle_scale");
@@ -1848,7 +1928,7 @@ static void rna_def_fluid_domain_settings(BlenderRNA *brna)
"The particle simulation is scaled up by this factor (compared to the "
"base resolution of the domain)");
RNA_def_property_clear_flag(prop, PROP_ANIMATABLE);
- RNA_def_property_update(prop, NC_OBJECT | ND_MODIFIER, "rna_Fluid_reset");
+ RNA_def_property_update(prop, NC_OBJECT | ND_MODIFIER, "rna_Fluid_domain_reset");
prop = RNA_def_property(srna, "use_spray_particles", PROP_BOOLEAN, PROP_NONE);
RNA_def_property_boolean_sdna(prop, NULL, "particle_type", FLUID_DOMAIN_PARTICLE_SPRAY);
@@ -1880,13 +1960,13 @@ static void rna_def_fluid_domain_settings(BlenderRNA *brna)
RNA_def_property_float_sdna(prop, NULL, "guide_alpha");
RNA_def_property_range(prop, 1.0, 100.0);
RNA_def_property_ui_text(prop, "Weight", "Guiding weight (higher value results in greater lag)");
- RNA_def_property_update(prop, NC_OBJECT | ND_MODIFIER, "rna_Fluid_reset");
+ RNA_def_property_update(prop, NC_OBJECT | ND_MODIFIER, "rna_Fluid_guidingcache_reset");
prop = RNA_def_property(srna, "guide_beta", PROP_INT, PROP_NONE);
RNA_def_property_int_sdna(prop, NULL, "guide_beta");
RNA_def_property_range(prop, 1, 50);
RNA_def_property_ui_text(prop, "Size", "Guiding size (higher value results in larger vortices)");
- RNA_def_property_update(prop, NC_OBJECT | ND_MODIFIER, "rna_Fluid_reset");
+ RNA_def_property_update(prop, NC_OBJECT | ND_MODIFIER, "rna_Fluid_guidingcache_reset");
prop = RNA_def_property(srna, "guide_vel_factor", PROP_FLOAT, PROP_NONE);
RNA_def_property_float_sdna(prop, NULL, "guide_vel_factor");
@@ -1895,7 +1975,7 @@ static void rna_def_fluid_domain_settings(BlenderRNA *brna)
prop,
"Velocity Factor",
"Guiding velocity factor (higher value results in greater guiding velocities)");
- RNA_def_property_update(prop, NC_OBJECT | ND_MODIFIER, "rna_Fluid_reset");
+ RNA_def_property_update(prop, NC_OBJECT | ND_MODIFIER, "rna_Fluid_guidingcache_reset");
prop = RNA_def_property(srna, "guide_source", PROP_ENUM, PROP_NONE);
RNA_def_property_enum_sdna(prop, NULL, "guide_source");
@@ -1912,25 +1992,26 @@ static void rna_def_fluid_domain_settings(BlenderRNA *brna)
"",
"Use velocities from this object for the guiding effect (object needs "
"to have fluid modifier and be of type domain))");
- RNA_def_property_update(prop, NC_OBJECT | ND_DRAW, "rna_Fluid_update");
+ RNA_def_property_update(prop, NC_OBJECT | ND_DRAW, "rna_Fluid_guidingcache_reset");
prop = RNA_def_property(srna, "use_guide", PROP_BOOLEAN, PROP_NONE);
RNA_def_property_boolean_sdna(prop, NULL, "flags", FLUID_DOMAIN_USE_GUIDE);
RNA_def_property_ui_text(prop, "Use Guiding", "Enable fluid guiding");
RNA_def_property_clear_flag(prop, PROP_ANIMATABLE);
- RNA_def_property_update(prop, NC_OBJECT | ND_MODIFIER, "rna_Fluid_reset");
+ RNA_def_property_update(prop, NC_OBJECT | ND_MODIFIER, "rna_Fluid_guidingcache_reset");
/* cache options */
prop = RNA_def_property(srna, "cache_frame_start", PROP_INT, PROP_TIME);
RNA_def_property_int_sdna(prop, NULL, "cache_frame_start");
RNA_def_property_range(prop, -MAXFRAME, MAXFRAME);
- RNA_def_property_ui_range(prop, 1, MAXFRAME, 1, 1);
+ RNA_def_property_int_funcs(prop, NULL, "rna_Fluid_cache_startframe_set", NULL);
RNA_def_property_ui_text(prop, "Start", "Frame on which the simulation starts");
prop = RNA_def_property(srna, "cache_frame_end", PROP_INT, PROP_TIME);
RNA_def_property_int_sdna(prop, NULL, "cache_frame_end");
- RNA_def_property_range(prop, 1, MAXFRAME);
+ RNA_def_property_range(prop, -MAXFRAME, MAXFRAME);
+ RNA_def_property_int_funcs(prop, NULL, "rna_Fluid_cache_endframe_set", NULL);
RNA_def_property_ui_text(prop, "End", "Frame on which the simulation stops");
prop = RNA_def_property(srna, "cache_frame_pause_data", PROP_INT, PROP_TIME);
@@ -1955,7 +2036,7 @@ static void rna_def_fluid_domain_settings(BlenderRNA *brna)
prop, NULL, "rna_Fluid_cachetype_mesh_set", "rna_Fluid_cachetype_mesh_itemf");
RNA_def_property_ui_text(
prop, "File Format", "Select the file format to be used for caching surface data");
- RNA_def_property_update(prop, NC_OBJECT | ND_MODIFIER, "rna_Fluid_reset");
+ RNA_def_property_update(prop, NC_OBJECT | ND_MODIFIER, "rna_Fluid_meshcache_reset");
prop = RNA_def_property(srna, "cache_data_format", PROP_ENUM, PROP_NONE);
RNA_def_property_enum_sdna(prop, NULL, "cache_data_format");
@@ -1964,7 +2045,7 @@ static void rna_def_fluid_domain_settings(BlenderRNA *brna)
prop, NULL, "rna_Fluid_cachetype_data_set", "rna_Fluid_cachetype_volume_itemf");
RNA_def_property_ui_text(
prop, "File Format", "Select the file format to be used for caching volumetric data");
- RNA_def_property_update(prop, NC_OBJECT | ND_MODIFIER, "rna_Fluid_reset");
+ RNA_def_property_update(prop, NC_OBJECT | ND_MODIFIER, "rna_Fluid_datacache_reset");
prop = RNA_def_property(srna, "cache_particle_format", PROP_ENUM, PROP_NONE);
RNA_def_property_enum_sdna(prop, NULL, "cache_particle_format");
@@ -1973,7 +2054,7 @@ static void rna_def_fluid_domain_settings(BlenderRNA *brna)
prop, NULL, "rna_Fluid_cachetype_particle_set", "rna_Fluid_cachetype_particle_itemf");
RNA_def_property_ui_text(
prop, "File Format", "Select the file format to be used for caching particle data");
- RNA_def_property_update(prop, NC_OBJECT | ND_MODIFIER, "rna_Fluid_reset");
+ RNA_def_property_update(prop, NC_OBJECT | ND_MODIFIER, "rna_Fluid_particlescache_reset");
prop = RNA_def_property(srna, "cache_noise_format", PROP_ENUM, PROP_NONE);
RNA_def_property_enum_sdna(prop, NULL, "cache_noise_format");
@@ -1982,21 +2063,21 @@ static void rna_def_fluid_domain_settings(BlenderRNA *brna)
prop, NULL, "rna_Fluid_cachetype_noise_set", "rna_Fluid_cachetype_volume_itemf");
RNA_def_property_ui_text(
prop, "File Format", "Select the file format to be used for caching noise data");
- RNA_def_property_update(prop, NC_OBJECT | ND_MODIFIER, "rna_Fluid_reset");
+ RNA_def_property_update(prop, NC_OBJECT | ND_MODIFIER, "rna_Fluid_noisecache_reset");
prop = RNA_def_property(srna, "cache_type", PROP_ENUM, PROP_NONE);
RNA_def_property_enum_sdna(prop, NULL, "cache_type");
RNA_def_property_enum_items(prop, cache_types);
RNA_def_property_enum_funcs(prop, NULL, "rna_Fluid_cachetype_set", NULL);
RNA_def_property_ui_text(prop, "Type", "Change the cache type of the simulation");
- RNA_def_property_update(prop, NC_OBJECT | ND_DRAW, "rna_Fluid_reset");
+ RNA_def_property_update(prop, NC_OBJECT | ND_DRAW, "rna_Fluid_domain_reset");
prop = RNA_def_property(srna, "cache_directory", PROP_STRING, PROP_DIRPATH);
RNA_def_property_string_maxlength(prop, FILE_MAX);
RNA_def_property_string_funcs(prop, NULL, NULL, "rna_Fluid_cache_directory_set");
RNA_def_property_string_sdna(prop, NULL, "cache_directory");
RNA_def_property_ui_text(prop, "Cache directory", "Directory that contains fluid cache files");
- RNA_def_property_update(prop, NC_OBJECT | ND_MODIFIER, NULL);
+ RNA_def_property_update(prop, NC_OBJECT | ND_MODIFIER, "rna_Fluid_update");
prop = RNA_def_property(srna, "is_cache_baking_data", PROP_BOOLEAN, PROP_NONE);
RNA_def_property_boolean_sdna(prop, NULL, "cache_flag", FLUID_DOMAIN_BAKING_DATA);
@@ -2056,7 +2137,7 @@ static void rna_def_fluid_domain_settings(BlenderRNA *brna)
"only needed if you plan to analyze the cache (e.g. view grids, velocity vectors, "
"particles) in Mantaflow directly (outside of Blender) after baking the simulation");
RNA_def_property_clear_flag(prop, PROP_ANIMATABLE);
- RNA_def_property_update(prop, NC_OBJECT | ND_MODIFIER, "rna_Fluid_reset");
+ RNA_def_property_update(prop, NC_OBJECT | ND_MODIFIER, "rna_Fluid_domain_reset");
/* time options */
@@ -2064,19 +2145,19 @@ static void rna_def_fluid_domain_settings(BlenderRNA *brna)
RNA_def_property_float_sdna(prop, NULL, "time_scale");
RNA_def_property_range(prop, 0.0001, 10.0);
RNA_def_property_ui_text(prop, "Time Scale", "Adjust simulation speed");
- RNA_def_property_update(prop, NC_OBJECT | ND_MODIFIER, "rna_Fluid_resetCache");
+ RNA_def_property_update(prop, NC_OBJECT | ND_MODIFIER, "rna_Fluid_datacache_reset");
prop = RNA_def_property(srna, "cfl_condition", PROP_FLOAT, PROP_NONE);
RNA_def_property_float_sdna(prop, NULL, "cfl_condition");
RNA_def_property_range(prop, 0.0, 10.0);
RNA_def_property_ui_text(
prop, "CFL", "Maximal velocity per cell (higher value results in greater timesteps)");
- RNA_def_property_update(prop, NC_OBJECT | ND_MODIFIER, "rna_Fluid_resetCache");
+ RNA_def_property_update(prop, NC_OBJECT | ND_MODIFIER, "rna_Fluid_datacache_reset");
prop = RNA_def_property(srna, "use_adaptive_timesteps", PROP_BOOLEAN, PROP_NONE);
RNA_def_property_boolean_sdna(prop, NULL, "flags", FLUID_DOMAIN_USE_ADAPTIVE_TIME);
RNA_def_property_ui_text(prop, "Use Adaptive Time Steps", "");
- RNA_def_property_update(prop, NC_OBJECT | ND_MODIFIER, "rna_Fluid_resetCache");
+ RNA_def_property_update(prop, NC_OBJECT | ND_MODIFIER, "rna_Fluid_datacache_reset");
prop = RNA_def_property(srna, "timesteps_min", PROP_INT, PROP_NONE);
RNA_def_property_int_sdna(prop, NULL, "timesteps_minimum");
@@ -2084,7 +2165,7 @@ static void rna_def_fluid_domain_settings(BlenderRNA *brna)
RNA_def_property_ui_range(prop, 0, 100, 1, -1);
RNA_def_property_ui_text(
prop, "Minimum", "Minimum number of simulation steps to perform for one frame");
- RNA_def_property_update(prop, NC_OBJECT | ND_MODIFIER, "rna_Fluid_reset");
+ RNA_def_property_update(prop, NC_OBJECT | ND_MODIFIER, "rna_Fluid_datacache_reset");
prop = RNA_def_property(srna, "timesteps_max", PROP_INT, PROP_NONE);
RNA_def_property_int_sdna(prop, NULL, "timesteps_maximum");
@@ -2092,7 +2173,7 @@ static void rna_def_fluid_domain_settings(BlenderRNA *brna)
RNA_def_property_ui_range(prop, 0, 100, 1, -1);
RNA_def_property_ui_text(
prop, "Maximum", "Maximum number of simulation steps to perform for one frame");
- RNA_def_property_update(prop, NC_OBJECT | ND_MODIFIER, "rna_Fluid_reset");
+ RNA_def_property_update(prop, NC_OBJECT | ND_MODIFIER, "rna_Fluid_datacache_reset");
/* display settings */
@@ -2303,26 +2384,26 @@ static void rna_def_fluid_flow_settings(BlenderRNA *brna)
RNA_def_property_range(prop, 0.0, 10);
RNA_def_property_ui_range(prop, 0.0, 1.0, 1.0, 4);
RNA_def_property_ui_text(prop, "Density", "");
- RNA_def_property_update(prop, NC_OBJECT | ND_MODIFIER, "rna_Fluid_reset");
+ RNA_def_property_update(prop, NC_OBJECT | ND_MODIFIER, "rna_Fluid_flow_reset");
prop = RNA_def_property(srna, "smoke_color", PROP_FLOAT, PROP_COLOR_GAMMA);
RNA_def_property_float_sdna(prop, NULL, "color");
RNA_def_property_array(prop, 3);
RNA_def_property_ui_text(prop, "Smoke Color", "Color of smoke");
- RNA_def_property_update(prop, NC_OBJECT | ND_MODIFIER, "rna_Fluid_reset");
+ RNA_def_property_update(prop, NC_OBJECT | ND_MODIFIER, "rna_Fluid_flow_reset");
prop = RNA_def_property(srna, "fuel_amount", PROP_FLOAT, PROP_NONE);
RNA_def_property_range(prop, 0.0, 10);
RNA_def_property_ui_range(prop, 0.0, 5.0, 1.0, 4);
RNA_def_property_ui_text(prop, "Flame Rate", "");
- RNA_def_property_update(prop, NC_OBJECT | ND_MODIFIER, "rna_Fluid_reset");
+ RNA_def_property_update(prop, NC_OBJECT | ND_MODIFIER, "rna_Fluid_flow_reset");
prop = RNA_def_property(srna, "temperature", PROP_FLOAT, PROP_NONE);
RNA_def_property_float_sdna(prop, NULL, "temperature");
RNA_def_property_range(prop, -10, 10);
RNA_def_property_ui_range(prop, -10, 10, 1, 1);
RNA_def_property_ui_text(prop, "Temp. Diff.", "Temperature difference to ambient temperature");
- RNA_def_property_update(prop, NC_OBJECT | ND_MODIFIER, "rna_Fluid_reset");
+ RNA_def_property_update(prop, NC_OBJECT | ND_MODIFIER, "rna_Fluid_flow_reset");
prop = RNA_def_property(srna, "particle_system", PROP_POINTER, PROP_NONE);
RNA_def_property_pointer_sdna(prop, NULL, "psys");
@@ -2336,13 +2417,13 @@ static void rna_def_fluid_flow_settings(BlenderRNA *brna)
RNA_def_property_enum_items(prop, flow_type_items);
RNA_def_property_enum_funcs(prop, NULL, "rna_Fluid_flowtype_set", NULL);
RNA_def_property_ui_text(prop, "Flow Type", "Change type of fluid in the simulation");
- RNA_def_property_update(prop, NC_OBJECT | ND_MODIFIER, "rna_Fluid_reset");
+ RNA_def_property_update(prop, NC_OBJECT | ND_MODIFIER, "rna_Fluid_flow_reset");
prop = RNA_def_property(srna, "flow_behavior", PROP_ENUM, PROP_NONE);
RNA_def_property_enum_sdna(prop, NULL, "behavior");
RNA_def_property_enum_items(prop, flow_behavior_items);
RNA_def_property_ui_text(prop, "Flow Behavior", "Change flow behavior in the simulation");
- RNA_def_property_update(prop, NC_OBJECT | ND_MODIFIER, "rna_Fluid_reset");
+ RNA_def_property_update(prop, NC_OBJECT | ND_MODIFIER, "rna_Fluid_flow_reset");
prop = RNA_def_property(srna, "flow_source", PROP_ENUM, PROP_NONE);
RNA_def_property_enum_sdna(prop, NULL, "source");
@@ -2350,20 +2431,20 @@ static void rna_def_fluid_flow_settings(BlenderRNA *brna)
RNA_def_property_enum_funcs(
prop, NULL, "rna_Fluid_flowsource_set", "rna_Fluid_flowsource_itemf");
RNA_def_property_ui_text(prop, "Source", "Change how fluid is emitted");
- RNA_def_property_update(prop, NC_OBJECT | ND_MODIFIER, "rna_Fluid_reset");
+ RNA_def_property_update(prop, NC_OBJECT | ND_MODIFIER, "rna_Fluid_flow_reset");
prop = RNA_def_property(srna, "use_absolute", PROP_BOOLEAN, PROP_NONE);
RNA_def_property_boolean_sdna(prop, NULL, "flags", FLUID_FLOW_ABSOLUTE);
RNA_def_property_ui_text(prop,
"Absolute Density",
"Only allow given density value in emitter area and will not add up");
- RNA_def_property_update(prop, NC_OBJECT | ND_MODIFIER, "rna_Fluid_reset");
+ RNA_def_property_update(prop, NC_OBJECT | ND_MODIFIER, "rna_Fluid_flow_reset");
prop = RNA_def_property(srna, "use_initial_velocity", PROP_BOOLEAN, PROP_NONE);
RNA_def_property_boolean_sdna(prop, NULL, "flags", FLUID_FLOW_INITVELOCITY);
RNA_def_property_ui_text(
prop, "Initial Velocity", "Fluid has some initial velocity when it is emitted");
- RNA_def_property_update(prop, NC_OBJECT | ND_MODIFIER, "rna_Fluid_reset");
+ RNA_def_property_update(prop, NC_OBJECT | ND_MODIFIER, "rna_Fluid_flow_reset");
prop = RNA_def_property(srna, "velocity_factor", PROP_FLOAT, PROP_NONE);
RNA_def_property_float_sdna(prop, NULL, "vel_multi");
@@ -2373,28 +2454,29 @@ static void rna_def_fluid_flow_settings(BlenderRNA *brna)
"Source",
"Multiplier of source velocity passed to fluid (source velocity is "
"non-zero only if object is moving)");
- RNA_def_property_update(prop, NC_OBJECT | ND_MODIFIER, "rna_Fluid_reset");
+ RNA_def_property_update(prop, NC_OBJECT | ND_MODIFIER, "rna_Fluid_flow_reset");
prop = RNA_def_property(srna, "velocity_normal", PROP_FLOAT, PROP_NONE);
RNA_def_property_float_sdna(prop, NULL, "vel_normal");
RNA_def_property_range(prop, -100.0, 100.0);
RNA_def_property_ui_range(prop, -2.0, 2.0, 0.05, 5);
RNA_def_property_ui_text(prop, "Normal", "Amount of normal directional velocity");
- RNA_def_property_update(prop, NC_OBJECT | ND_MODIFIER, "rna_Fluid_reset");
+ RNA_def_property_update(prop, NC_OBJECT | ND_MODIFIER, "rna_Fluid_flow_reset");
prop = RNA_def_property(srna, "velocity_random", PROP_FLOAT, PROP_NONE);
RNA_def_property_float_sdna(prop, NULL, "vel_random");
RNA_def_property_range(prop, 0.0, 10.0);
RNA_def_property_ui_range(prop, 0.0, 2.0, 0.05, 5);
RNA_def_property_ui_text(prop, "Random", "Amount of random velocity");
- RNA_def_property_update(prop, NC_OBJECT | ND_MODIFIER, "rna_Fluid_reset");
+ RNA_def_property_update(prop, NC_OBJECT | ND_MODIFIER, "rna_Fluid_flow_reset");
- prop = RNA_def_property(srna, "velocity_coord", PROP_FLOAT, PROP_XYZ);
+ prop = RNA_def_property(srna, "velocity_coord", PROP_FLOAT, PROP_VELOCITY);
RNA_def_property_float_sdna(prop, NULL, "vel_coord");
RNA_def_property_array(prop, 3);
RNA_def_property_range(prop, -1000.1, 1000.1);
- RNA_def_property_ui_text(prop, "Initial", "Initial velocity in X, Y and Z direction");
- RNA_def_property_update(prop, NC_OBJECT | ND_MODIFIER, "rna_Fluid_reset");
+ RNA_def_property_ui_text(
+ prop, "Initial", "Initial velocity in X, Y and Z direction in world space");
+ RNA_def_property_update(prop, NC_OBJECT | ND_MODIFIER, "rna_Fluid_flow_reset");
prop = RNA_def_property(srna, "volume_density", PROP_FLOAT, PROP_NONE);
RNA_def_property_range(prop, 0.0, 1.0);
@@ -2403,7 +2485,7 @@ static void rna_def_fluid_flow_settings(BlenderRNA *brna)
"Volume Emission",
"Controls fluid emission from within the mesh (higher value results in "
"greater emissions from inside the mesh)");
- RNA_def_property_update(prop, NC_OBJECT | ND_MODIFIER, "rna_Fluid_reset");
+ RNA_def_property_update(prop, NC_OBJECT | ND_MODIFIER, "rna_Fluid_flow_reset");
prop = RNA_def_property(srna, "surface_distance", PROP_FLOAT, PROP_NONE);
RNA_def_property_range(prop, 0.0, 10.0);
@@ -2412,7 +2494,7 @@ static void rna_def_fluid_flow_settings(BlenderRNA *brna)
"Surface Emission",
"Controls fluid emission from the mesh surface (higher value results "
"in emission further away from the mesh surface");
- RNA_def_property_update(prop, NC_OBJECT | ND_MODIFIER, "rna_Fluid_reset");
+ RNA_def_property_update(prop, NC_OBJECT | ND_MODIFIER, "rna_Fluid_flow_reset");
prop = RNA_def_property(srna, "use_plane_init", PROP_BOOLEAN, PROP_NONE);
RNA_def_property_boolean_sdna(prop, NULL, "flags", FLUID_FLOW_USE_PLANE_INIT);
@@ -2421,24 +2503,24 @@ static void rna_def_fluid_flow_settings(BlenderRNA *brna)
"Is Planar",
"Treat this object as a planar and unclosed mesh. Fluid will only be emitted from the mesh "
"surface and based on the surface emission value");
- RNA_def_property_update(prop, NC_OBJECT | ND_MODIFIER, "rna_Fluid_reset");
+ RNA_def_property_update(prop, NC_OBJECT | ND_MODIFIER, "rna_Fluid_flow_reset");
prop = RNA_def_property(srna, "particle_size", PROP_FLOAT, PROP_NONE);
RNA_def_property_range(prop, 0.1, 20.0);
RNA_def_property_ui_range(prop, 0.5, 5.0, 0.05, 5);
RNA_def_property_ui_text(prop, "Size", "Particle size in simulation cells");
- RNA_def_property_update(prop, NC_OBJECT | ND_MODIFIER, "rna_Fluid_reset");
+ RNA_def_property_update(prop, NC_OBJECT | ND_MODIFIER, "rna_Fluid_flow_reset");
prop = RNA_def_property(srna, "use_particle_size", PROP_BOOLEAN, PROP_NONE);
RNA_def_property_boolean_sdna(prop, NULL, "flags", FLUID_FLOW_USE_PART_SIZE);
RNA_def_property_ui_text(
prop, "Set Size", "Set particle size in simulation cells or use nearest cell");
- RNA_def_property_update(prop, NC_OBJECT | ND_MODIFIER, "rna_Fluid_reset");
+ RNA_def_property_update(prop, NC_OBJECT | ND_MODIFIER, "rna_Fluid_flow_reset");
prop = RNA_def_property(srna, "use_inflow", PROP_BOOLEAN, PROP_NONE);
RNA_def_property_boolean_sdna(prop, NULL, "flags", FLUID_FLOW_USE_INFLOW);
- RNA_def_property_ui_text(prop, "Enabled", "Control when to apply inflow");
- RNA_def_property_update(prop, NC_OBJECT | ND_MODIFIER, "rna_Fluid_reset");
+ RNA_def_property_ui_text(prop, "Use Flow", "Control when to apply fluid flow");
+ RNA_def_property_update(prop, NC_OBJECT | ND_MODIFIER, "rna_Fluid_flow_reset");
prop = RNA_def_property(srna, "subframes", PROP_INT, PROP_NONE);
RNA_def_property_range(prop, 0, 200);
@@ -2447,7 +2529,7 @@ static void rna_def_fluid_flow_settings(BlenderRNA *brna)
"Subframes",
"Number of additional samples to take between frames to improve "
"quality of fast moving flows");
- RNA_def_property_update(prop, NC_OBJECT | ND_MODIFIER, "rna_Fluid_reset");
+ RNA_def_property_update(prop, NC_OBJECT | ND_MODIFIER, "rna_Fluid_flow_reset");
prop = RNA_def_property(srna, "density_vertex_group", PROP_STRING, PROP_NONE);
RNA_def_property_string_funcs(prop,
@@ -2456,41 +2538,41 @@ static void rna_def_fluid_flow_settings(BlenderRNA *brna)
"rna_FluidFlow_density_vgroup_set");
RNA_def_property_ui_text(
prop, "Vertex Group", "Name of vertex group which determines surface emission rate");
- RNA_def_property_update(prop, NC_OBJECT | ND_MODIFIER, "rna_Fluid_reset");
+ RNA_def_property_update(prop, NC_OBJECT | ND_MODIFIER, "rna_Fluid_flow_reset");
prop = RNA_def_property(srna, "use_texture", PROP_BOOLEAN, PROP_NONE);
RNA_def_property_boolean_sdna(prop, NULL, "flags", FLUID_FLOW_TEXTUREEMIT);
RNA_def_property_ui_text(prop, "Use Texture", "Use a texture to control emission strength");
- RNA_def_property_update(prop, NC_OBJECT | ND_MODIFIER, "rna_Fluid_reset");
+ RNA_def_property_update(prop, NC_OBJECT | ND_MODIFIER, "rna_Fluid_flow_reset");
prop = RNA_def_property(srna, "texture_map_type", PROP_ENUM, PROP_NONE);
RNA_def_property_enum_sdna(prop, NULL, "texture_type");
RNA_def_property_enum_items(prop, flow_texture_types);
RNA_def_property_ui_text(prop, "Mapping", "Texture mapping type");
- RNA_def_property_update(prop, NC_OBJECT | ND_MODIFIER, "rna_Fluid_reset");
+ RNA_def_property_update(prop, NC_OBJECT | ND_MODIFIER, "rna_Fluid_flow_reset");
prop = RNA_def_property(srna, "uv_layer", PROP_STRING, PROP_NONE);
RNA_def_property_string_sdna(prop, NULL, "uvlayer_name");
RNA_def_property_ui_text(prop, "UV Map", "UV map name");
RNA_def_property_string_funcs(prop, NULL, NULL, "rna_FluidFlow_uvlayer_set");
- RNA_def_property_update(prop, NC_OBJECT | ND_MODIFIER, "rna_Fluid_reset");
+ RNA_def_property_update(prop, NC_OBJECT | ND_MODIFIER, "rna_Fluid_flow_reset");
prop = RNA_def_property(srna, "noise_texture", PROP_POINTER, PROP_NONE);
RNA_def_property_flag(prop, PROP_EDITABLE);
RNA_def_property_ui_text(prop, "Texture", "Texture that controls emission strength");
- RNA_def_property_update(prop, NC_OBJECT | ND_MODIFIER, "rna_Fluid_reset");
+ RNA_def_property_update(prop, NC_OBJECT | ND_MODIFIER, "rna_Fluid_flow_reset");
prop = RNA_def_property(srna, "texture_size", PROP_FLOAT, PROP_NONE);
RNA_def_property_range(prop, 0.01, 10.0);
RNA_def_property_ui_range(prop, 0.1, 5.0, 0.05, 5);
RNA_def_property_ui_text(prop, "Size", "Size of texture mapping");
- RNA_def_property_update(prop, NC_OBJECT | ND_MODIFIER, "rna_Fluid_reset");
+ RNA_def_property_update(prop, NC_OBJECT | ND_MODIFIER, "rna_Fluid_flow_reset");
prop = RNA_def_property(srna, "texture_offset", PROP_FLOAT, PROP_NONE);
RNA_def_property_range(prop, 0.0, 200.0);
RNA_def_property_ui_range(prop, 0.0, 100.0, 0.05, 5);
RNA_def_property_ui_text(prop, "Offset", "Z-offset of texture mapping");
- RNA_def_property_update(prop, NC_OBJECT | ND_MODIFIER, "rna_Fluid_reset");
+ RNA_def_property_update(prop, NC_OBJECT | ND_MODIFIER, "rna_Fluid_flow_reset");
}
static void rna_def_fluid_effector_settings(BlenderRNA *brna)
@@ -2540,36 +2622,36 @@ static void rna_def_fluid_effector_settings(BlenderRNA *brna)
RNA_def_property_enum_sdna(prop, NULL, "type");
RNA_def_property_enum_items(prop, effector_type_items);
RNA_def_property_ui_text(prop, "Effector Type", "Change type of effector in the simulation");
- RNA_def_property_update(prop, NC_OBJECT | ND_MODIFIER, "rna_Fluid_reset");
+ RNA_def_property_update(prop, NC_OBJECT | ND_MODIFIER, "rna_Fluid_effector_reset");
prop = RNA_def_property(srna, "surface_distance", PROP_FLOAT, PROP_NONE);
RNA_def_property_range(prop, 0.0, 10.0);
RNA_def_property_ui_range(prop, 0.0, 10.0, 0.05, 5);
RNA_def_property_ui_text(
prop, "Surface", "Additional distance around mesh surface to consider as effector");
- RNA_def_property_update(prop, NC_OBJECT | ND_MODIFIER, "rna_Fluid_reset");
+ RNA_def_property_update(prop, NC_OBJECT | ND_MODIFIER, "rna_Fluid_effector_reset");
prop = RNA_def_property(srna, "use_plane_init", PROP_BOOLEAN, PROP_NONE);
RNA_def_property_boolean_sdna(prop, NULL, "flags", FLUID_EFFECTOR_USE_PLANE_INIT);
RNA_def_property_ui_text(prop, "Is Planar", "Treat this object as a planar, unclosed mesh");
- RNA_def_property_update(prop, NC_OBJECT | ND_MODIFIER, "rna_Fluid_reset");
+ RNA_def_property_update(prop, NC_OBJECT | ND_MODIFIER, "rna_Fluid_domain_reset");
prop = RNA_def_property(srna, "velocity_factor", PROP_FLOAT, PROP_NONE);
RNA_def_property_float_sdna(prop, NULL, "vel_multi");
RNA_def_property_range(prop, -100.0, 100.0);
RNA_def_property_ui_text(prop, "Source", "Multiplier of obstacle velocity");
- RNA_def_property_update(prop, NC_OBJECT | ND_MODIFIER, "rna_Fluid_reset");
+ RNA_def_property_update(prop, NC_OBJECT | ND_MODIFIER, "rna_Fluid_effector_reset");
prop = RNA_def_property(srna, "guide_mode", PROP_ENUM, PROP_NONE);
RNA_def_property_enum_sdna(prop, NULL, "guide_mode");
RNA_def_property_enum_items(prop, fluid_guide_mode_items);
RNA_def_property_ui_text(prop, "Guiding mode", "How to create guiding velocities");
- RNA_def_property_update(prop, NC_OBJECT | ND_DRAW, "rna_Fluid_update");
+ RNA_def_property_update(prop, NC_OBJECT | ND_DRAW, "rna_Fluid_effector_reset");
prop = RNA_def_property(srna, "use_effector", PROP_BOOLEAN, PROP_NONE);
RNA_def_property_boolean_sdna(prop, NULL, "flags", FLUID_EFFECTOR_USE_EFFEC);
RNA_def_property_ui_text(prop, "Enabled", "Control when to apply the effector");
- RNA_def_property_update(prop, NC_OBJECT | ND_MODIFIER, "rna_Fluid_reset");
+ RNA_def_property_update(prop, NC_OBJECT | ND_MODIFIER, "rna_Fluid_effector_reset");
prop = RNA_def_property(srna, "subframes", PROP_INT, PROP_NONE);
RNA_def_property_range(prop, 0, 200);
@@ -2578,7 +2660,7 @@ static void rna_def_fluid_effector_settings(BlenderRNA *brna)
"Subframes",
"Number of additional samples to take between frames to improve "
"quality of fast moving effector objects");
- RNA_def_property_update(prop, NC_OBJECT | ND_MODIFIER, "rna_Fluid_reset");
+ RNA_def_property_update(prop, NC_OBJECT | ND_MODIFIER, "rna_Fluid_effector_reset");
}
void RNA_def_fluid(BlenderRNA *brna)
diff --git a/source/blender/makesrna/intern/rna_gpencil.c b/source/blender/makesrna/intern/rna_gpencil.c
index deacd8e1cfc..a52811a9a9a 100644
--- a/source/blender/makesrna/intern/rna_gpencil.c
+++ b/source/blender/makesrna/intern/rna_gpencil.c
@@ -114,14 +114,14 @@ static const EnumPropertyItem rna_enum_gplayer_move_type_items[] = {
static const EnumPropertyItem rna_enum_layer_blend_modes_items[] = {
{eGplBlendMode_Regular, "REGULAR", 0, "Regular", ""},
- {eGplBlendMode_Overlay, "OVERLAY", 0, "Overlay", ""},
+ {eGplBlendMode_HardLight, "HARDLIGHT", 0, "Hard Light", ""},
{eGplBlendMode_Add, "ADD", 0, "Add", ""},
{eGplBlendMode_Subtract, "SUBTRACT", 0, "Subtract", ""},
{eGplBlendMode_Multiply, "MULTIPLY", 0, "Multiply", ""},
{eGplBlendMode_Divide, "DIVIDE", 0, "Divide", ""},
{0, NULL, 0, NULL, NULL}};
-static EnumPropertyItem rna_enum_gpencil_caps_modes_items[] = {
+static const EnumPropertyItem rna_enum_gpencil_caps_modes_items[] = {
{GP_STROKE_CAP_ROUND, "ROUND", 0, "Rounded", ""},
{GP_STROKE_CAP_FLAT, "FLAT", 0, "Flat", ""},
{0, NULL, 0, NULL, NULL},
@@ -642,7 +642,6 @@ static void rna_GPencil_stroke_point_add(
/* Calc geometry data. */
BKE_gpencil_stroke_geometry_update(stroke);
- gpd->flag |= GP_DATA_PYTHON_UPDATED;
DEG_id_tag_update(&gpd->id,
ID_RECALC_TRANSFORM | ID_RECALC_GEOMETRY | ID_RECALC_COPY_ON_WRITE);
@@ -704,7 +703,6 @@ static void rna_GPencil_stroke_point_pop(ID *id,
/* Calc geometry data. */
BKE_gpencil_stroke_geometry_update(stroke);
- gpd->flag |= GP_DATA_PYTHON_UPDATED;
DEG_id_tag_update(&gpd->id, ID_RECALC_TRANSFORM | ID_RECALC_GEOMETRY | ID_RECALC_COPY_ON_WRITE);
WM_main_add_notifier(NC_GPENCIL | NA_EDITED, NULL);
@@ -712,19 +710,19 @@ static void rna_GPencil_stroke_point_pop(ID *id,
static bGPDstroke *rna_GPencil_stroke_new(bGPDframe *frame)
{
- bGPDstroke *stroke = MEM_callocN(sizeof(bGPDstroke), "gp_stroke");
- stroke->hardeness = 1.0f;
- ARRAY_SET_ITEMS(stroke->aspect_ratio, 1.0f, 1.0f);
- stroke->uv_scale = 1.0f;
+ bGPDstroke *stroke = BKE_gpencil_stroke_new(0, 0, 1.0f);
BLI_addtail(&frame->strokes, stroke);
return stroke;
}
-static void rna_GPencil_stroke_remove(bGPDframe *frame,
+static void rna_GPencil_stroke_remove(ID *id,
+ bGPDframe *frame,
ReportList *reports,
PointerRNA *stroke_ptr)
{
+ bGPdata *gpd = (bGPdata *)id;
+
bGPDstroke *stroke = stroke_ptr->data;
if (BLI_findindex(&frame->strokes, stroke) == -1) {
BKE_report(reports, RPT_ERROR, "Stroke not found in grease pencil frame");
@@ -734,7 +732,8 @@ static void rna_GPencil_stroke_remove(bGPDframe *frame,
BLI_freelinkN(&frame->strokes, stroke);
RNA_POINTER_INVALIDATE(stroke_ptr);
- WM_main_add_notifier(NC_GPENCIL | NA_EDITED, NULL);
+ DEG_id_tag_update(&gpd->id, ID_RECALC_TRANSFORM | ID_RECALC_GEOMETRY | ID_RECALC_COPY_ON_WRITE);
+ WM_main_add_notifier(NC_GPENCIL | ND_DATA | NA_EDITED, NULL);
}
static void rna_GPencil_stroke_close(ID *id,
@@ -1188,7 +1187,6 @@ static void rna_def_gpencil_stroke(BlenderRNA *brna)
* (this is a special flag for fill brush). */
prop = RNA_def_property(srna, "is_nofill_stroke", PROP_BOOLEAN, PROP_NONE);
RNA_def_property_boolean_sdna(prop, NULL, "flag", GP_STROKE_NOFILL);
- RNA_def_property_clear_flag(prop, PROP_EDITABLE);
RNA_def_property_ui_text(prop, "No Fill", "Special stroke to use as boundary for filling areas");
RNA_def_property_update(prop, 0, "rna_GPencil_update");
@@ -1201,11 +1199,11 @@ static void rna_def_gpencil_stroke(BlenderRNA *brna)
RNA_def_property_update(prop, NC_GPENCIL | ND_DATA, "rna_GPencil_update");
/* gradient control along y */
- prop = RNA_def_property(srna, "hardeness", PROP_FLOAT, PROP_FACTOR);
+ prop = RNA_def_property(srna, "hardness", PROP_FLOAT, PROP_FACTOR);
RNA_def_property_float_sdna(prop, NULL, "hardeness");
RNA_def_property_range(prop, 0.001f, 1.0f);
RNA_def_property_float_default(prop, 1.0f);
- RNA_def_property_ui_text(prop, "Hardeness", "Amount of gradient along section of stroke");
+ RNA_def_property_ui_text(prop, "Hardness", "Amount of gradient along section of stroke");
RNA_def_parameter_clear_flags(prop, PROP_ANIMATABLE, 0);
RNA_def_property_update(prop, NC_GPENCIL | ND_DATA, "rna_GPencil_update");
@@ -1236,7 +1234,7 @@ static void rna_def_gpencil_stroke(BlenderRNA *brna)
RNA_def_property_float_sdna(prop, NULL, "uv_translation");
RNA_def_property_array(prop, 2);
RNA_def_property_float_default(prop, 0.0f);
- RNA_def_property_ui_text(prop, "UV Translation", "Translation of default UV postion");
+ RNA_def_property_ui_text(prop, "UV Translation", "Translation of default UV position");
RNA_def_parameter_clear_flags(prop, PROP_ANIMATABLE, 0);
RNA_def_property_update(prop, NC_GPENCIL | ND_DATA, "rna_GPencil_uv_update");
@@ -1287,7 +1285,7 @@ static void rna_def_gpencil_strokes_api(BlenderRNA *brna, PropertyRNA *cprop)
func = RNA_def_function(srna, "remove", "rna_GPencil_stroke_remove");
RNA_def_function_ui_description(func, "Remove a grease pencil stroke");
- RNA_def_function_flag(func, FUNC_USE_REPORTS);
+ RNA_def_function_flag(func, FUNC_USE_REPORTS | FUNC_USE_SELF_ID);
parm = RNA_def_pointer(func, "stroke", "GPencilStroke", "Stroke", "The stroke to remove");
RNA_def_parameter_flags(parm, PROP_NEVER_NULL, PARM_REQUIRED | PARM_RNAPTR);
RNA_def_parameter_clear_flags(parm, PROP_THICK_WRAP, 0);
@@ -1472,7 +1470,7 @@ static void rna_def_gpencil_layer(BlenderRNA *brna)
RNA_def_property_ui_text(prop, "Info", "Layer name");
RNA_def_property_string_funcs(prop, NULL, NULL, "rna_GPencilLayer_info_set");
RNA_def_struct_name_property(srna, prop);
- RNA_def_property_update(prop, NC_GPENCIL | ND_DATA | NA_RENAME, NULL);
+ RNA_def_property_update(prop, NC_GPENCIL | ND_DATA | NA_RENAME, "rna_GPencil_update");
/* Frames */
prop = RNA_def_property(srna, "frames", PROP_COLLECTION, PROP_NONE);
@@ -1665,13 +1663,11 @@ static void rna_def_gpencil_layer(BlenderRNA *brna)
prop = RNA_def_property(srna, "use_mask_layer", PROP_BOOLEAN, PROP_NONE);
RNA_def_property_boolean_sdna(prop, NULL, "flag", GP_LAYER_USE_MASK);
- RNA_def_property_clear_flag(prop, PROP_ANIMATABLE);
RNA_def_property_ui_text(prop, "Mask Layer", "Mask pixels from underlying layers drawing");
RNA_def_property_update(prop, NC_GPENCIL | ND_DATA, "rna_GPencil_update");
prop = RNA_def_property(srna, "use_lights", PROP_BOOLEAN, PROP_NONE);
RNA_def_property_boolean_sdna(prop, NULL, "flag", GP_LAYER_USE_LIGHTS);
- RNA_def_property_clear_flag(prop, PROP_ANIMATABLE);
RNA_def_property_ui_text(
prop, "Use Lights", "Enable the use of lights on stroke and fill materials");
RNA_def_property_update(prop, NC_GPENCIL | ND_DATA, "rna_GPencil_update");
@@ -1721,7 +1717,7 @@ static void rna_def_gpencil_layer(BlenderRNA *brna)
RNA_def_property_enum_funcs(
prop, NULL, "rna_GPencilLayer_parent_type_set", "rna_Object_parent_type_itemf");
RNA_def_property_ui_text(prop, "Parent Type", "Type of parent relation");
- RNA_def_property_update(prop, NC_GPENCIL | ND_DATA, "rna_GPencil_update");
+ RNA_def_property_update(prop, NC_GPENCIL | ND_DATA, "rna_GPencil_dependency_update");
/* parent bone */
prop = RNA_def_property(srna, "parent_bone", PROP_STRING, PROP_NONE);
@@ -1729,7 +1725,7 @@ static void rna_def_gpencil_layer(BlenderRNA *brna)
RNA_def_property_string_funcs(prop, NULL, NULL, "rna_GPencilLayer_parent_bone_set");
RNA_def_property_ui_text(
prop, "Parent Bone", "Name of parent bone in case of a bone parenting relation");
- RNA_def_property_update(prop, NC_GPENCIL | ND_DATA, "rna_GPencil_update");
+ RNA_def_property_update(prop, NC_GPENCIL | ND_DATA, "rna_GPencil_dependency_update");
/* matrix */
prop = RNA_def_property(srna, "matrix_inverse", PROP_FLOAT, PROP_MATRIX);
@@ -2038,6 +2034,7 @@ static void rna_def_gpencil_data(BlenderRNA *brna)
RNA_def_property_array(prop, 3);
RNA_def_property_range(prop, 0.0f, 1.0f);
RNA_def_property_float_array_default(prop, onion_dft1);
+ RNA_def_parameter_clear_flags(prop, PROP_ANIMATABLE, 0);
RNA_def_property_ui_text(prop, "Before Color", "Base color for ghosts before the active frame");
RNA_def_property_update(
prop, NC_SCREEN | NC_SCENE | ND_TOOLSETTINGS | ND_DATA | NC_GPENCIL, "rna_GPencil_update");
@@ -2047,6 +2044,7 @@ static void rna_def_gpencil_data(BlenderRNA *brna)
RNA_def_property_array(prop, 3);
RNA_def_property_range(prop, 0.0f, 1.0f);
RNA_def_property_float_array_default(prop, onion_dft2);
+ RNA_def_parameter_clear_flags(prop, PROP_ANIMATABLE, 0);
RNA_def_property_ui_text(prop, "After Color", "Base color for ghosts after the active frame");
RNA_def_property_update(
prop, NC_SCREEN | NC_SCENE | ND_TOOLSETTINGS | ND_DATA | NC_GPENCIL, "rna_GPencil_update");
diff --git a/source/blender/makesrna/intern/rna_gpencil_modifier.c b/source/blender/makesrna/intern/rna_gpencil_modifier.c
index bcabdd472c8..3a8ded1a275 100644
--- a/source/blender/makesrna/intern/rna_gpencil_modifier.c
+++ b/source/blender/makesrna/intern/rna_gpencil_modifier.c
@@ -73,6 +73,11 @@ const EnumPropertyItem rna_enum_object_greasepencil_modifier_type_items[] = {
ICON_MOD_MIRROR,
"Mirror",
"Duplicate strokes like a mirror"},
+ {eGpencilModifierType_Multiply,
+ "GP_MULTIPLY",
+ ICON_GP_MULTIFRAME_EDITING,
+ "Multiple Strokes",
+ "Produce multiple strokes along one stroke"},
{eGpencilModifierType_Simplify,
"GP_SIMPLIFY",
ICON_MOD_SIMPLIFY,
@@ -83,11 +88,6 @@ const EnumPropertyItem rna_enum_object_greasepencil_modifier_type_items[] = {
ICON_MOD_SUBSURF,
"Subdivide",
"Subdivide stroke adding more control points"},
- {eGpencilModifierType_Multiply,
- "GP_MULTIPLY",
- ICON_GP_MULTIFRAME_EDITING,
- "Multiple Strokes",
- "Produce multiple strokes along one stroke"},
{0, "", 0, N_("Deform"), ""},
{eGpencilModifierType_Armature,
"GP_ARMATURE",
@@ -129,6 +129,11 @@ const EnumPropertyItem rna_enum_object_greasepencil_modifier_type_items[] = {
"Opacity",
"Opacity of the strokes"},
{eGpencilModifierType_Tint, "GP_TINT", ICON_MOD_TINT, "Tint", "Tint strokes with new color"},
+ {eGpencilModifierType_Texture,
+ "GP_TEXTURE",
+ ICON_TEXTURE,
+ "Texture Mapping",
+ "Change stroke uv texture values"},
{0, NULL, 0, NULL, NULL},
};
@@ -144,7 +149,7 @@ static const EnumPropertyItem modifier_modify_opacity_items[] = {
{GP_MODIFY_COLOR_BOTH, "BOTH", 0, "Stroke and Fill", "Modify fill and stroke colors"},
{GP_MODIFY_COLOR_STROKE, "STROKE", 0, "Stroke", "Modify stroke color only"},
{GP_MODIFY_COLOR_FILL, "FILL", 0, "Fill", "Modify fill color only"},
- {GP_MODIFY_COLOR_HARDENESS, "HARDENESS", 0, "Hardeness", "Modify stroke hardeness"},
+ {GP_MODIFY_COLOR_HARDNESS, "HARDNESS", 0, "Hardness", "Modify stroke hardness"},
{0, NULL, 0, NULL, NULL},
};
@@ -234,6 +239,8 @@ static StructRNA *rna_GpencilModifier_refine(struct PointerRNA *ptr)
return &RNA_ArmatureGpencilModifier;
case eGpencilModifierType_Multiply:
return &RNA_MultiplyGpencilModifier;
+ case eGpencilModifierType_Texture:
+ return &RNA_TextureGpencilModifier;
/* Default */
case eGpencilModifierType_None:
case NUM_GREASEPENCIL_MODIFIER_TYPES:
@@ -302,6 +309,7 @@ RNA_GP_MOD_VGROUP_NAME_SET(Smooth, vgname);
RNA_GP_MOD_VGROUP_NAME_SET(Hook, vgname);
RNA_GP_MOD_VGROUP_NAME_SET(Offset, vgname);
RNA_GP_MOD_VGROUP_NAME_SET(Armature, vgname);
+RNA_GP_MOD_VGROUP_NAME_SET(Texture, vgname);
# undef RNA_GP_MOD_VGROUP_NAME_SET
@@ -434,9 +442,10 @@ static void rna_def_modifier_gpencilnoise(BlenderRNA *brna)
RNA_def_property_ui_text(prop, "Layer", "Layer name");
RNA_def_property_update(prop, 0, "rna_GpencilModifier_update");
- prop = RNA_def_property(srna, "material", PROP_STRING, PROP_NONE);
- RNA_def_property_string_sdna(prop, NULL, "materialname");
- RNA_def_property_ui_text(prop, "Material", "Material name");
+ prop = RNA_def_property(srna, "material", PROP_POINTER, PROP_NONE);
+ RNA_def_property_flag(prop, PROP_EDITABLE | PROP_ID_SELF_CHECK);
+ RNA_def_property_override_flag(prop, PROPOVERRIDE_OVERRIDABLE_LIBRARY);
+ RNA_def_property_ui_text(prop, "Material", "Material used for filtering effect");
RNA_def_property_update(prop, 0, "rna_GpencilModifier_update");
prop = RNA_def_property(srna, "vertex_group", PROP_STRING, PROP_NONE);
@@ -563,9 +572,10 @@ static void rna_def_modifier_gpencilsmooth(BlenderRNA *brna)
RNA_def_property_ui_text(prop, "Layer", "Layer name");
RNA_def_property_update(prop, 0, "rna_GpencilModifier_update");
- prop = RNA_def_property(srna, "material", PROP_STRING, PROP_NONE);
- RNA_def_property_string_sdna(prop, NULL, "materialname");
- RNA_def_property_ui_text(prop, "Material", "Material name");
+ prop = RNA_def_property(srna, "material", PROP_POINTER, PROP_NONE);
+ RNA_def_property_flag(prop, PROP_EDITABLE | PROP_ID_SELF_CHECK);
+ RNA_def_property_override_flag(prop, PROPOVERRIDE_OVERRIDABLE_LIBRARY);
+ RNA_def_property_ui_text(prop, "Material", "Material used for filtering effect");
RNA_def_property_update(prop, 0, "rna_GpencilModifier_update");
prop = RNA_def_property(srna, "vertex_group", PROP_STRING, PROP_NONE);
@@ -675,9 +685,10 @@ static void rna_def_modifier_gpencilsubdiv(BlenderRNA *brna)
RNA_def_property_ui_text(prop, "Layer", "Layer name");
RNA_def_property_update(prop, 0, "rna_GpencilModifier_update");
- prop = RNA_def_property(srna, "material", PROP_STRING, PROP_NONE);
- RNA_def_property_string_sdna(prop, NULL, "materialname");
- RNA_def_property_ui_text(prop, "Material", "Material name");
+ prop = RNA_def_property(srna, "material", PROP_POINTER, PROP_NONE);
+ RNA_def_property_flag(prop, PROP_EDITABLE | PROP_ID_SELF_CHECK);
+ RNA_def_property_override_flag(prop, PROPOVERRIDE_OVERRIDABLE_LIBRARY);
+ RNA_def_property_ui_text(prop, "Material", "Material used for filtering effect");
RNA_def_property_update(prop, 0, "rna_GpencilModifier_update");
prop = RNA_def_property(srna, "level", PROP_INT, PROP_NONE);
@@ -764,9 +775,10 @@ static void rna_def_modifier_gpencilsimplify(BlenderRNA *brna)
RNA_def_property_ui_text(prop, "Layer", "Layer name");
RNA_def_property_update(prop, 0, "rna_GpencilModifier_update");
- prop = RNA_def_property(srna, "material", PROP_STRING, PROP_NONE);
- RNA_def_property_string_sdna(prop, NULL, "materialname");
- RNA_def_property_ui_text(prop, "Material", "Material name");
+ prop = RNA_def_property(srna, "material", PROP_POINTER, PROP_NONE);
+ RNA_def_property_flag(prop, PROP_EDITABLE | PROP_ID_SELF_CHECK);
+ RNA_def_property_override_flag(prop, PROPOVERRIDE_OVERRIDABLE_LIBRARY);
+ RNA_def_property_ui_text(prop, "Material", "Material used for filtering effect");
RNA_def_property_update(prop, 0, "rna_GpencilModifier_update");
prop = RNA_def_property(srna, "factor", PROP_FLOAT, PROP_FACTOR);
@@ -852,9 +864,10 @@ static void rna_def_modifier_gpencilthick(BlenderRNA *brna)
RNA_def_property_ui_text(prop, "Layer", "Layer name");
RNA_def_property_update(prop, 0, "rna_GpencilModifier_update");
- prop = RNA_def_property(srna, "material", PROP_STRING, PROP_NONE);
- RNA_def_property_string_sdna(prop, NULL, "materialname");
- RNA_def_property_ui_text(prop, "Material", "Material name");
+ prop = RNA_def_property(srna, "material", PROP_POINTER, PROP_NONE);
+ RNA_def_property_flag(prop, PROP_EDITABLE | PROP_ID_SELF_CHECK);
+ RNA_def_property_override_flag(prop, PROPOVERRIDE_OVERRIDABLE_LIBRARY);
+ RNA_def_property_ui_text(prop, "Material", "Material used for filtering effect");
RNA_def_property_update(prop, 0, "rna_GpencilModifier_update");
prop = RNA_def_property(srna, "vertex_group", PROP_STRING, PROP_NONE);
@@ -946,9 +959,10 @@ static void rna_def_modifier_gpenciloffset(BlenderRNA *brna)
RNA_def_property_ui_text(prop, "Layer", "Layer name");
RNA_def_property_update(prop, 0, "rna_GpencilModifier_update");
- prop = RNA_def_property(srna, "material", PROP_STRING, PROP_NONE);
- RNA_def_property_string_sdna(prop, NULL, "materialname");
- RNA_def_property_ui_text(prop, "Material", "Material name");
+ prop = RNA_def_property(srna, "material", PROP_POINTER, PROP_NONE);
+ RNA_def_property_flag(prop, PROP_EDITABLE | PROP_ID_SELF_CHECK);
+ RNA_def_property_override_flag(prop, PROPOVERRIDE_OVERRIDABLE_LIBRARY);
+ RNA_def_property_ui_text(prop, "Material", "Material used for filtering effect");
RNA_def_property_update(prop, 0, "rna_GpencilModifier_update");
prop = RNA_def_property(srna, "vertex_group", PROP_STRING, PROP_NONE);
@@ -1043,9 +1057,10 @@ static void rna_def_modifier_gpenciltint(BlenderRNA *brna)
RNA_def_property_ui_text(prop, "Layer", "Layer name");
RNA_def_property_update(prop, 0, "rna_GpencilModifier_update");
- prop = RNA_def_property(srna, "material", PROP_STRING, PROP_NONE);
- RNA_def_property_string_sdna(prop, NULL, "materialname");
- RNA_def_property_ui_text(prop, "Material", "Material name");
+ prop = RNA_def_property(srna, "material", PROP_POINTER, PROP_NONE);
+ RNA_def_property_flag(prop, PROP_EDITABLE | PROP_ID_SELF_CHECK);
+ RNA_def_property_override_flag(prop, PROPOVERRIDE_OVERRIDABLE_LIBRARY);
+ RNA_def_property_ui_text(prop, "Material", "Material used for filtering effect");
RNA_def_property_update(prop, 0, "rna_GpencilModifier_update");
prop = RNA_def_property(srna, "vertex_group", PROP_STRING, PROP_NONE);
@@ -1248,9 +1263,10 @@ static void rna_def_modifier_gpencilcolor(BlenderRNA *brna)
RNA_def_property_ui_text(prop, "Layer", "Layer name");
RNA_def_property_update(prop, 0, "rna_GpencilModifier_update");
- prop = RNA_def_property(srna, "material", PROP_STRING, PROP_NONE);
- RNA_def_property_string_sdna(prop, NULL, "materialname");
- RNA_def_property_ui_text(prop, "Material", "Material name");
+ prop = RNA_def_property(srna, "material", PROP_POINTER, PROP_NONE);
+ RNA_def_property_flag(prop, PROP_EDITABLE | PROP_ID_SELF_CHECK);
+ RNA_def_property_override_flag(prop, PROPOVERRIDE_OVERRIDABLE_LIBRARY);
+ RNA_def_property_ui_text(prop, "Material", "Material used for filtering effect");
RNA_def_property_update(prop, 0, "rna_GpencilModifier_update");
prop = RNA_def_property(srna, "hue", PROP_FLOAT, PROP_NONE);
@@ -1341,9 +1357,10 @@ static void rna_def_modifier_gpencilopacity(BlenderRNA *brna)
RNA_def_property_ui_text(prop, "Layer", "Layer name");
RNA_def_property_update(prop, 0, "rna_GpencilModifier_update");
- prop = RNA_def_property(srna, "material", PROP_STRING, PROP_NONE);
- RNA_def_property_string_sdna(prop, NULL, "materialname");
- RNA_def_property_ui_text(prop, "Material", "Material name");
+ prop = RNA_def_property(srna, "material", PROP_POINTER, PROP_NONE);
+ RNA_def_property_flag(prop, PROP_EDITABLE | PROP_ID_SELF_CHECK);
+ RNA_def_property_override_flag(prop, PROPOVERRIDE_OVERRIDABLE_LIBRARY);
+ RNA_def_property_ui_text(prop, "Material", "Material used for filtering effect");
RNA_def_property_update(prop, 0, "rna_GpencilModifier_update");
prop = RNA_def_property(srna, "vertex_group", PROP_STRING, PROP_NONE);
@@ -1360,12 +1377,12 @@ static void rna_def_modifier_gpencilopacity(BlenderRNA *brna)
RNA_def_property_ui_text(prop, "Opacity Factor", "Factor of Opacity");
RNA_def_property_update(prop, 0, "rna_GpencilModifier_update");
- prop = RNA_def_property(srna, "hardeness", PROP_FLOAT, PROP_NONE);
+ prop = RNA_def_property(srna, "hardness", PROP_FLOAT, PROP_NONE);
RNA_def_property_float_sdna(prop, NULL, "hardeness");
RNA_def_property_range(prop, 0.0, FLT_MAX);
RNA_def_property_ui_range(prop, 0.0, FLT_MAX, 0.1, 2);
RNA_def_property_float_default(prop, 1.0f);
- RNA_def_property_ui_text(prop, "Hardeness", "Factor of stroke hardeness");
+ RNA_def_property_ui_text(prop, "Hardness", "Factor of stroke hardness");
RNA_def_property_update(prop, 0, "rna_GpencilModifier_update");
prop = RNA_def_property(srna, "pass_index", PROP_INT, PROP_NONE);
@@ -1437,9 +1454,10 @@ static void rna_def_modifier_gpencilarray(BlenderRNA *brna)
RNA_def_property_ui_text(prop, "Layer", "Layer name");
RNA_def_property_update(prop, 0, "rna_GpencilModifier_update");
- prop = RNA_def_property(srna, "material", PROP_STRING, PROP_NONE);
- RNA_def_property_string_sdna(prop, NULL, "materialname");
- RNA_def_property_ui_text(prop, "Material", "Material name");
+ prop = RNA_def_property(srna, "material", PROP_POINTER, PROP_NONE);
+ RNA_def_property_flag(prop, PROP_EDITABLE | PROP_ID_SELF_CHECK);
+ RNA_def_property_override_flag(prop, PROPOVERRIDE_OVERRIDABLE_LIBRARY);
+ RNA_def_property_ui_text(prop, "Material", "Material used for filtering effect");
RNA_def_property_update(prop, 0, "rna_GpencilModifier_update");
prop = RNA_def_property(srna, "pass_index", PROP_INT, PROP_NONE);
@@ -1545,7 +1563,7 @@ static void rna_def_modifier_gpencilarray(BlenderRNA *brna)
prop = RNA_def_property(srna, "use_object_offset", PROP_BOOLEAN, PROP_NONE);
RNA_def_property_boolean_sdna(prop, NULL, "flag", GP_ARRAY_USE_OB_OFFSET);
- RNA_def_property_ui_text(prop, "Object Offset", "Enable obejct offset");
+ RNA_def_property_ui_text(prop, "Object Offset", "Enable object offset");
RNA_def_property_update(prop, 0, "rna_GpencilModifier_update");
prop = RNA_def_property(srna, "use_relative_offset", PROP_BOOLEAN, PROP_NONE);
@@ -1663,6 +1681,20 @@ static void rna_def_modifier_gpencilbuild(BlenderRNA *brna)
prop, "Restrict Frame Range", "Only modify strokes during the specified frame range");
RNA_def_property_update(prop, 0, "rna_GpencilModifier_update");
+ /* Use percentage */
+ prop = RNA_def_property(srna, "use_percentage", PROP_BOOLEAN, PROP_NONE);
+ RNA_def_property_boolean_sdna(prop, NULL, "flag", GP_BUILD_PERCENTAGE);
+ RNA_def_property_ui_text(
+ prop, "Restrict Visible Points", "Use a percentage factor to determine the visible points");
+ RNA_def_property_update(prop, 0, "rna_GpencilModifier_update");
+
+ /* Percentage factor. */
+ prop = RNA_def_property(srna, "percentage_factor", PROP_FLOAT, PROP_FACTOR);
+ RNA_def_property_float_sdna(prop, NULL, "percentage_fac");
+ RNA_def_property_ui_text(prop, "Factor", "Defines how much of the stroke is visible");
+ RNA_def_property_range(prop, 0.0f, 1.0f);
+ RNA_def_property_update(prop, 0, "rna_GpencilModifier_update");
+
prop = RNA_def_property(srna, "frame_start", PROP_FLOAT, PROP_NONE);
RNA_def_property_float_sdna(prop, NULL, "start_frame");
RNA_def_property_ui_text(
@@ -1715,9 +1747,10 @@ static void rna_def_modifier_gpencillattice(BlenderRNA *brna)
RNA_def_property_ui_text(prop, "Layer", "Layer name");
RNA_def_property_update(prop, 0, "rna_GpencilModifier_update");
- prop = RNA_def_property(srna, "material", PROP_STRING, PROP_NONE);
- RNA_def_property_string_sdna(prop, NULL, "materialname");
- RNA_def_property_ui_text(prop, "Material", "Material name");
+ prop = RNA_def_property(srna, "material", PROP_POINTER, PROP_NONE);
+ RNA_def_property_flag(prop, PROP_EDITABLE | PROP_ID_SELF_CHECK);
+ RNA_def_property_override_flag(prop, PROPOVERRIDE_OVERRIDABLE_LIBRARY);
+ RNA_def_property_ui_text(prop, "Material", "Material used for filtering effect");
RNA_def_property_update(prop, 0, "rna_GpencilModifier_update");
prop = RNA_def_property(srna, "vertex_group", PROP_STRING, PROP_NONE);
@@ -1794,9 +1827,10 @@ static void rna_def_modifier_gpencilmirror(BlenderRNA *brna)
RNA_def_property_ui_text(prop, "Layer", "Layer name");
RNA_def_property_update(prop, 0, "rna_GpencilModifier_update");
- prop = RNA_def_property(srna, "material", PROP_STRING, PROP_NONE);
- RNA_def_property_string_sdna(prop, NULL, "materialname");
- RNA_def_property_ui_text(prop, "Material", "Material name");
+ prop = RNA_def_property(srna, "material", PROP_POINTER, PROP_NONE);
+ RNA_def_property_flag(prop, PROP_EDITABLE | PROP_ID_SELF_CHECK);
+ RNA_def_property_override_flag(prop, PROPOVERRIDE_OVERRIDABLE_LIBRARY);
+ RNA_def_property_ui_text(prop, "Material", "Material used for filtering effect");
RNA_def_property_update(prop, 0, "rna_GpencilModifier_update");
prop = RNA_def_property(srna, "pass_index", PROP_INT, PROP_NONE);
@@ -1891,9 +1925,10 @@ static void rna_def_modifier_gpencilhook(BlenderRNA *brna)
RNA_def_property_ui_text(prop, "Layer", "Layer name");
RNA_def_property_update(prop, 0, "rna_GpencilModifier_update");
- prop = RNA_def_property(srna, "material", PROP_STRING, PROP_NONE);
- RNA_def_property_string_sdna(prop, NULL, "materialname");
- RNA_def_property_ui_text(prop, "Material", "Material name");
+ prop = RNA_def_property(srna, "material", PROP_POINTER, PROP_NONE);
+ RNA_def_property_flag(prop, PROP_EDITABLE | PROP_ID_SELF_CHECK);
+ RNA_def_property_override_flag(prop, PROPOVERRIDE_OVERRIDABLE_LIBRARY);
+ RNA_def_property_ui_text(prop, "Material", "Material used for filtering effect");
RNA_def_property_update(prop, 0, "rna_GpencilModifier_update");
prop = RNA_def_property(srna, "vertex_group", PROP_STRING, PROP_NONE);
@@ -2047,9 +2082,10 @@ static void rna_def_modifier_gpencilmultiply(BlenderRNA *brna)
RNA_def_property_ui_text(prop, "Layer", "Layer name");
RNA_def_property_update(prop, 0, "rna_GpencilModifier_update");
- prop = RNA_def_property(srna, "material", PROP_STRING, PROP_NONE);
- RNA_def_property_string_sdna(prop, NULL, "materialname");
- RNA_def_property_ui_text(prop, "Material", "Material name");
+ prop = RNA_def_property(srna, "material", PROP_POINTER, PROP_NONE);
+ RNA_def_property_flag(prop, PROP_EDITABLE | PROP_ID_SELF_CHECK);
+ RNA_def_property_override_flag(prop, PROPOVERRIDE_OVERRIDABLE_LIBRARY);
+ RNA_def_property_ui_text(prop, "Material", "Material used for filtering effect");
RNA_def_property_update(prop, 0, "rna_GpencilModifier_update");
prop = RNA_def_property(srna, "pass_index", PROP_INT, PROP_NONE);
@@ -2138,6 +2174,142 @@ static void rna_def_modifier_gpencilmultiply(BlenderRNA *brna)
RNA_def_property_update(prop, 0, "rna_GpencilModifier_update");
}
+static void rna_def_modifier_gpenciltexture(BlenderRNA *brna)
+{
+ StructRNA *srna;
+ PropertyRNA *prop;
+
+ static const EnumPropertyItem fit_type_items[] = {
+ {GP_TEX_CONSTANT_LENGTH,
+ "CONSTANT_LENGTH",
+ 0,
+ "Keep Texture at Constant Length",
+ "Keep the texture at a constant length regardless of the length of each stroke"},
+ {GP_TEX_FIT_STROKE,
+ "FIT_STROKE",
+ 0,
+ "Fit Texture to Stroke Length",
+ "Scale the texture to fit the length of each stroke"},
+ {0, NULL, 0, NULL, NULL},
+ };
+
+ static const EnumPropertyItem mode_items[] = {
+ {STROKE, "STROKE", 0, "Stroke", "Manipulate only stroke texture coordinates"},
+ {FILL, "FILL", 0, "Fill", "Manipulate only fill texture coordinates"},
+ {STROKE_AND_FILL,
+ "STROKE_AND_FILL",
+ 0,
+ "Stroke and Fill",
+ "Manipulate both stroke and fill texture coordinates"},
+ {0, NULL, 0, NULL, NULL},
+ };
+
+ srna = RNA_def_struct(brna, "TextureGpencilModifier", "GpencilModifier");
+ RNA_def_struct_ui_text(
+ srna, "Texture Modifier", "Transform stroke texture coordinates Modifier");
+ RNA_def_struct_sdna(srna, "TextureGpencilModifierData");
+ RNA_def_struct_ui_icon(srna, ICON_TEXTURE);
+
+ prop = RNA_def_property(srna, "layer", PROP_STRING, PROP_NONE);
+ RNA_def_property_string_sdna(prop, NULL, "layername");
+ RNA_def_property_ui_text(prop, "Layer", "Layer name");
+ RNA_def_property_update(prop, 0, "rna_GpencilModifier_update");
+
+ prop = RNA_def_property(srna, "invert_layers", PROP_BOOLEAN, PROP_NONE);
+ RNA_def_property_boolean_sdna(prop, NULL, "flag", GP_TEX_INVERT_LAYER);
+ RNA_def_property_ui_text(prop, "Inverse Layers", "Inverse filter");
+ RNA_def_property_update(prop, 0, "rna_GpencilModifier_update");
+
+ prop = RNA_def_property(srna, "material", PROP_POINTER, PROP_NONE);
+ RNA_def_property_flag(prop, PROP_EDITABLE | PROP_ID_SELF_CHECK);
+ RNA_def_property_override_flag(prop, PROPOVERRIDE_OVERRIDABLE_LIBRARY);
+ RNA_def_property_ui_text(prop, "Material", "Material used for filtering effect");
+ RNA_def_property_update(prop, 0, "rna_GpencilModifier_update");
+
+ prop = RNA_def_property(srna, "invert_materials", PROP_BOOLEAN, PROP_NONE);
+ RNA_def_property_boolean_sdna(prop, NULL, "flag", GP_TEX_INVERT_MATERIAL);
+ RNA_def_property_ui_text(prop, "Inverse Materials", "Inverse filter");
+ RNA_def_property_update(prop, 0, "rna_GpencilModifier_update");
+
+ prop = RNA_def_property(srna, "vertex_group", PROP_STRING, PROP_NONE);
+ RNA_def_property_string_sdna(prop, NULL, "vgname");
+ RNA_def_property_ui_text(prop, "Vertex Group", "Vertex group name for modulating the deform");
+ RNA_def_property_string_funcs(prop, NULL, NULL, "rna_TextureGpencilModifier_vgname_set");
+ RNA_def_property_update(prop, 0, "rna_GpencilModifier_update");
+
+ prop = RNA_def_property(srna, "invert_vertex", PROP_BOOLEAN, PROP_NONE);
+ RNA_def_property_boolean_sdna(prop, NULL, "flag", GP_TEX_INVERT_VGROUP);
+ RNA_def_property_ui_text(prop, "Inverse VertexGroup", "Inverse filter");
+ RNA_def_property_update(prop, 0, "rna_GpencilModifier_update");
+
+ prop = RNA_def_property(srna, "pass_index", PROP_INT, PROP_NONE);
+ RNA_def_property_int_sdna(prop, NULL, "pass_index");
+ RNA_def_property_range(prop, 0, 100);
+ RNA_def_property_ui_text(prop, "Pass", "Pass index");
+ RNA_def_property_update(prop, 0, "rna_GpencilModifier_update");
+
+ prop = RNA_def_property(srna, "invert_material_pass", PROP_BOOLEAN, PROP_NONE);
+ RNA_def_property_boolean_sdna(prop, NULL, "flag", GP_TEX_INVERT_PASS);
+ RNA_def_property_ui_text(prop, "Inverse Pass", "Inverse filter");
+ RNA_def_property_update(prop, 0, "rna_GpencilModifier_update");
+
+ prop = RNA_def_property(srna, "layer_pass", PROP_INT, PROP_NONE);
+ RNA_def_property_int_sdna(prop, NULL, "layer_pass");
+ RNA_def_property_range(prop, 0, 100);
+ RNA_def_property_ui_text(prop, "Pass", "Layer pass index");
+ RNA_def_property_update(prop, 0, "rna_GpencilModifier_update");
+
+ prop = RNA_def_property(srna, "invert_layer_pass", PROP_BOOLEAN, PROP_NONE);
+ RNA_def_property_boolean_sdna(prop, NULL, "flag", GP_TEX_INVERT_LAYERPASS);
+ RNA_def_property_ui_text(prop, "Inverse Pass", "Inverse filter");
+ RNA_def_property_update(prop, 0, "rna_GpencilModifier_update");
+
+ prop = RNA_def_property(srna, "uv_offset", PROP_FLOAT, PROP_NONE);
+ RNA_def_property_float_sdna(prop, NULL, "uv_offset");
+ RNA_def_property_range(prop, -FLT_MAX, FLT_MAX);
+ RNA_def_property_ui_range(prop, -100.0, 100.0, 0.1, 3);
+ RNA_def_property_float_default(prop, 0.0f);
+ RNA_def_property_ui_text(prop, "Offset UVs", "Offset value to add to stroke UVs");
+ RNA_def_property_update(prop, 0, "rna_GpencilModifier_update");
+
+ prop = RNA_def_property(srna, "uv_scale", PROP_FLOAT, PROP_NONE);
+ RNA_def_property_float_sdna(prop, NULL, "uv_scale");
+ RNA_def_property_range(prop, 0.0, FLT_MAX);
+ RNA_def_property_ui_range(prop, 0.0, 100.0, 0.1, 3);
+ RNA_def_property_float_default(prop, 1.0f);
+ RNA_def_property_ui_text(prop, "UV Scale", "Factor to scale the UVs");
+ RNA_def_property_update(prop, 0, "rna_GpencilModifier_update");
+
+ prop = RNA_def_property(srna, "fill_rotation", PROP_FLOAT, PROP_ANGLE);
+ RNA_def_property_float_sdna(prop, NULL, "fill_rotation");
+ RNA_def_property_ui_text(prop, "Fill Rotation", "Additional rotation of the fill UV");
+ RNA_def_property_update(prop, 0, "rna_GpencilModifier_update");
+
+ prop = RNA_def_property(srna, "fill_offset", PROP_FLOAT, PROP_COORDS);
+ RNA_def_property_float_sdna(prop, NULL, "fill_offset");
+ RNA_def_property_array(prop, 2);
+ RNA_def_property_ui_text(prop, "Fill Offset", "Additional offset of the fill UV");
+ RNA_def_property_update(prop, 0, "rna_GpencilModifier_update");
+
+ prop = RNA_def_property(srna, "fill_scale", PROP_FLOAT, PROP_COORDS);
+ RNA_def_property_float_sdna(prop, NULL, "fill_scale");
+ RNA_def_property_range(prop, 0.01f, 100.0f);
+ RNA_def_property_ui_text(prop, "Fill Scale", "Additional scale of the fill UV");
+ RNA_def_property_update(prop, 0, "rna_GpencilModifier_update");
+
+ prop = RNA_def_property(srna, "fit_method", PROP_ENUM, PROP_NONE);
+ RNA_def_property_enum_sdna(prop, NULL, "fit_method");
+ RNA_def_property_enum_items(prop, fit_type_items);
+ RNA_def_property_ui_text(prop, "Fit Method", "");
+ RNA_def_property_update(prop, 0, "rna_GpencilModifier_dependency_update");
+
+ prop = RNA_def_property(srna, "mode", PROP_ENUM, PROP_NONE);
+ RNA_def_property_enum_sdna(prop, NULL, "mode");
+ RNA_def_property_enum_items(prop, mode_items);
+ RNA_def_property_ui_text(prop, "Mode", "");
+ RNA_def_property_update(prop, 0, "rna_GpencilModifier_dependency_update");
+}
+
void RNA_def_greasepencil_modifier(BlenderRNA *brna)
{
StructRNA *srna;
@@ -2211,6 +2383,7 @@ void RNA_def_greasepencil_modifier(BlenderRNA *brna)
rna_def_modifier_gpencilhook(brna);
rna_def_modifier_gpencilarmature(brna);
rna_def_modifier_gpencilmultiply(brna);
+ rna_def_modifier_gpenciltexture(brna);
}
#endif
diff --git a/source/blender/makesrna/intern/rna_image.c b/source/blender/makesrna/intern/rna_image.c
index f3f1666e25e..73504200020 100644
--- a/source/blender/makesrna/intern/rna_image.c
+++ b/source/blender/makesrna/intern/rna_image.c
@@ -1001,7 +1001,7 @@ static void rna_def_image(BlenderRNA *brna)
RNA_def_property_update(prop, NC_IMAGE | ND_DISPLAY, "rna_Image_generated_update");
RNA_def_property_clear_flag(prop, PROP_ANIMATABLE);
- prop = RNA_def_property(srna, "generated_width", PROP_INT, PROP_NONE);
+ prop = RNA_def_property(srna, "generated_width", PROP_INT, PROP_PIXEL);
RNA_def_property_int_sdna(prop, NULL, "gen_x");
RNA_def_property_flag(prop, PROP_PROPORTIONAL);
RNA_def_property_range(prop, 1, 65536);
@@ -1009,7 +1009,7 @@ static void rna_def_image(BlenderRNA *brna)
RNA_def_property_update(prop, NC_IMAGE | ND_DISPLAY, "rna_Image_generated_update");
RNA_def_property_clear_flag(prop, PROP_ANIMATABLE);
- prop = RNA_def_property(srna, "generated_height", PROP_INT, PROP_NONE);
+ prop = RNA_def_property(srna, "generated_height", PROP_INT, PROP_PIXEL);
RNA_def_property_int_sdna(prop, NULL, "gen_y");
RNA_def_property_flag(prop, PROP_PROPORTIONAL);
RNA_def_property_range(prop, 1, 65536);
diff --git a/source/blender/makesrna/intern/rna_internal.h b/source/blender/makesrna/intern/rna_internal.h
index 27097261930..44f118a8744 100644
--- a/source/blender/makesrna/intern/rna_internal.h
+++ b/source/blender/makesrna/intern/rna_internal.h
@@ -118,7 +118,14 @@ typedef struct BlenderDefRNA {
ListBase structs;
ListBase allocs;
struct StructRNA *laststruct;
- int error, silent, preprocess, verify, animate;
+ bool error;
+ bool silent;
+ bool preprocess;
+ bool verify;
+ bool animate;
+ /** Whether RNA properties defined should be overridable or not by default. */
+ bool make_overridable;
+
/* Keep last. */
#ifndef RNA_RUNTIME
struct {
@@ -185,6 +192,7 @@ void RNA_def_render(struct BlenderRNA *brna);
void RNA_def_rigidbody(struct BlenderRNA *brna);
void RNA_def_rna(struct BlenderRNA *brna);
void RNA_def_scene(struct BlenderRNA *brna);
+void RNA_def_simulation(struct BlenderRNA *brna);
void RNA_def_view_layer(struct BlenderRNA *brna);
void RNA_def_screen(struct BlenderRNA *brna);
void RNA_def_sculpt_paint(struct BlenderRNA *brna);
@@ -449,6 +457,7 @@ void RNA_def_main_lightprobes(BlenderRNA *brna, PropertyRNA *cprop);
void RNA_def_main_hairs(BlenderRNA *brna, PropertyRNA *cprop);
void RNA_def_main_pointclouds(BlenderRNA *brna, PropertyRNA *cprop);
void RNA_def_main_volumes(BlenderRNA *brna, PropertyRNA *cprop);
+void RNA_def_main_simulations(BlenderRNA *brna, PropertyRNA *cprop);
/* ID Properties */
diff --git a/source/blender/makesrna/intern/rna_key.c b/source/blender/makesrna/intern/rna_key.c
index d8628097490..7955109d9bc 100644
--- a/source/blender/makesrna/intern/rna_key.c
+++ b/source/blender/makesrna/intern/rna_key.c
@@ -46,6 +46,7 @@
# include "DNA_object_types.h"
+# include "BLI_listbase.h"
# include "BLI_string_utils.h"
# include "BKE_animsys.h"
@@ -575,7 +576,7 @@ static void rna_ShapeKey_data_begin(CollectionPropertyIterator *iter, PointerRNA
NurbInfo info = {0};
/* Check if all sub-curves have the same type. */
- for (Nurb *nu = cu->nurb.first; nu; nu = nu->next) {
+ LISTBASE_FOREACH (Nurb *, nu, &cu->nurb) {
if (type == NULL) {
type = rna_ShapeKey_curve_point_type(nu);
rna_ShapeKey_NurbInfo_init(&info, nu);
diff --git a/source/blender/makesrna/intern/rna_layer.c b/source/blender/makesrna/intern/rna_layer.c
index 3883ffab246..b99457056fe 100644
--- a/source/blender/makesrna/intern/rna_layer.c
+++ b/source/blender/makesrna/intern/rna_layer.c
@@ -55,6 +55,8 @@
# include "BKE_node.h"
# include "BKE_scene.h"
+# include "BLI_listbase.h"
+
# include "DEG_depsgraph_build.h"
# include "DEG_depsgraph_query.h"
@@ -297,19 +299,6 @@ static void rna_LayerCollection_hide_viewport_set(PointerRNA *ptr, bool value)
rna_LayerCollection_flag_set(ptr, value, LAYER_COLLECTION_HIDE);
}
-static void rna_LayerCollection_exclude_update_recursive(ListBase *lb, const bool exclude)
-{
- for (LayerCollection *lc = lb->first; lc; lc = lc->next) {
- if (exclude) {
- lc->flag |= LAYER_COLLECTION_EXCLUDE;
- }
- else {
- lc->flag &= ~LAYER_COLLECTION_EXCLUDE;
- }
- rna_LayerCollection_exclude_update_recursive(&lc->layer_collections, exclude);
- }
-}
-
static void rna_LayerCollection_exclude_update(Main *bmain, Scene *UNUSED(scene), PointerRNA *ptr)
{
Scene *scene = (Scene *)ptr->owner_id;
@@ -318,7 +307,7 @@ static void rna_LayerCollection_exclude_update(Main *bmain, Scene *UNUSED(scene)
/* Set/Unset it recursively to match the behavior of excluding via the menu or shortcuts. */
const bool exclude = (lc->flag & LAYER_COLLECTION_EXCLUDE) != 0;
- rna_LayerCollection_exclude_update_recursive(&lc->layer_collections, exclude);
+ BKE_layer_collection_set_flag(lc, LAYER_COLLECTION_EXCLUDE, exclude);
BKE_layer_collection_sync(scene, view_layer);
diff --git a/source/blender/makesrna/intern/rna_light.c b/source/blender/makesrna/intern/rna_light.c
index c19dafb3bc6..2caf315e09e 100644
--- a/source/blender/makesrna/intern/rna_light.c
+++ b/source/blender/makesrna/intern/rna_light.c
@@ -186,25 +186,45 @@ static void rna_def_light(BlenderRNA *brna)
rna_def_animdata_common(srna);
}
-static void rna_def_light_energy(StructRNA *srna, bool distant)
+static void rna_def_light_energy(StructRNA *srna, const short light_type)
{
PropertyRNA *prop;
- if (distant) {
- /* Distant light strength has no unit defined, it's proportional to
- * Watt/m^2 and is not sensitive to scene unit scale. */
- prop = RNA_def_property(srna, "energy", PROP_FLOAT, PROP_NONE);
- RNA_def_property_ui_range(prop, 0.0f, 10.0f, 1, 3);
- RNA_def_property_ui_text(prop, "Strength", "Amount of light emitted");
- RNA_def_property_update(prop, 0, "rna_Light_draw_update");
- }
- else {
- /* Lights with a location have power in Watt, which is sensitive to
- * scene unit scale. */
- prop = RNA_def_property(srna, "energy", PROP_FLOAT, PROP_POWER);
- RNA_def_property_ui_range(prop, 0.0f, 1000000.0f, 10, 5);
- RNA_def_property_ui_text(prop, "Power", "Amount of light emitted");
- RNA_def_property_update(prop, 0, "rna_Light_draw_update");
+ switch (light_type) {
+ case LA_SUN: {
+ /* Distant light strength has no unit defined,
+ * it's proportional to 'watt/m^2' and is not sensitive to scene unit scale. */
+ prop = RNA_def_property(srna, "energy", PROP_FLOAT, PROP_NONE);
+ RNA_def_property_ui_range(prop, 0.0f, 10.0f, 1, 3);
+ RNA_def_property_ui_text(
+ prop, "Strength", "Sunlight strength in watts per meter squared (W/m^2)");
+ RNA_def_property_update(prop, 0, "rna_Light_draw_update");
+ break;
+ }
+ case LA_SPOT: {
+ /* Lights with a location have power in Watts,
+ * which is sensitive to scene unit scale. */
+ prop = RNA_def_property(srna, "energy", PROP_FLOAT, PROP_POWER);
+ RNA_def_property_ui_range(prop, 0.0f, 1000000.0f, 10, 5);
+ RNA_def_property_ui_text(prop,
+ "Power",
+ "The energy this light would emit over its entire area "
+ "if it wasn't limited by the spot angle");
+ RNA_def_property_update(prop, 0, "rna_Light_draw_update");
+ break;
+ }
+ default: {
+ /* Lights with a location have power in Watts,
+ * which is sensitive to scene unit scale. */
+ prop = RNA_def_property(srna, "energy", PROP_FLOAT, PROP_POWER);
+ RNA_def_property_ui_range(prop, 0.0f, 1000000.0f, 10, 5);
+ RNA_def_property_ui_text(
+ prop,
+ "Power",
+ "Light energy emitted over the entire area of the light in all directions");
+ RNA_def_property_update(prop, 0, "rna_Light_draw_update");
+ break;
+ }
}
}
@@ -395,7 +415,7 @@ static void rna_def_point_light(BlenderRNA *brna)
RNA_def_struct_ui_text(srna, "Point Light", "Omnidirectional point Light");
RNA_def_struct_ui_icon(srna, ICON_LIGHT_POINT);
- rna_def_light_energy(srna, false);
+ rna_def_light_energy(srna, LA_LOCAL);
rna_def_light_falloff(srna);
rna_def_light_shadow(srna, false);
}
@@ -418,7 +438,7 @@ static void rna_def_area_light(BlenderRNA *brna)
RNA_def_struct_ui_text(srna, "Area Light", "Directional area Light");
RNA_def_struct_ui_icon(srna, ICON_LIGHT_AREA);
- rna_def_light_energy(srna, false);
+ rna_def_light_energy(srna, LA_AREA);
rna_def_light_shadow(srna, false);
rna_def_light_falloff(srna);
@@ -457,7 +477,7 @@ static void rna_def_spot_light(BlenderRNA *brna)
RNA_def_struct_ui_text(srna, "Spot Light", "Directional cone Light");
RNA_def_struct_ui_icon(srna, ICON_LIGHT_SPOT);
- rna_def_light_energy(srna, false);
+ rna_def_light_energy(srna, LA_SPOT);
rna_def_light_falloff(srna);
rna_def_light_shadow(srna, false);
@@ -503,7 +523,7 @@ static void rna_def_sun_light(BlenderRNA *brna)
RNA_def_property_ui_text(prop, "Angle", "Angular diameter of the Sun as seen from the Earth");
RNA_def_property_update(prop, 0, "rna_Light_update");
- rna_def_light_energy(srna, true);
+ rna_def_light_energy(srna, LA_SUN);
rna_def_light_shadow(srna, true);
}
diff --git a/source/blender/makesrna/intern/rna_main.c b/source/blender/makesrna/intern/rna_main.c
index 855d5f46890..2f37e4079c7 100644
--- a/source/blender/makesrna/intern/rna_main.c
+++ b/source/blender/makesrna/intern/rna_main.c
@@ -134,6 +134,9 @@ RNA_MAIN_LISTBASE_FUNCS_DEF(pointclouds)
RNA_MAIN_LISTBASE_FUNCS_DEF(scenes)
RNA_MAIN_LISTBASE_FUNCS_DEF(screens)
RNA_MAIN_LISTBASE_FUNCS_DEF(shapekeys)
+# ifdef WITH_NEW_SIMULATION_TYPE
+RNA_MAIN_LISTBASE_FUNCS_DEF(simulations)
+# endif
RNA_MAIN_LISTBASE_FUNCS_DEF(sounds)
RNA_MAIN_LISTBASE_FUNCS_DEF(speakers)
RNA_MAIN_LISTBASE_FUNCS_DEF(texts)
@@ -402,6 +405,14 @@ void RNA_def_main(BlenderRNA *brna)
"Volumes",
"Volume data-blocks",
RNA_def_main_volumes},
+# ifdef WITH_NEW_SIMULATION_TYPE
+ {"simulations",
+ "Simulation",
+ "rna_Main_simulations_begin",
+ "Simulations",
+ "Simulation data-blocks",
+ RNA_def_main_simulations},
+# endif
{NULL, NULL, NULL, NULL, NULL, NULL},
};
diff --git a/source/blender/makesrna/intern/rna_main_api.c b/source/blender/makesrna/intern/rna_main_api.c
index 9799054ccd2..c5781175d65 100644
--- a/source/blender/makesrna/intern/rna_main_api.c
+++ b/source/blender/makesrna/intern/rna_main_api.c
@@ -69,6 +69,7 @@
# include "BKE_particle.h"
# include "BKE_pointcloud.h"
# include "BKE_scene.h"
+# include "BKE_simulation.h"
# include "BKE_sound.h"
# include "BKE_speaker.h"
# include "BKE_text.h"
@@ -98,6 +99,7 @@
# include "DNA_node_types.h"
# include "DNA_particle_types.h"
# include "DNA_pointcloud_types.h"
+# include "DNA_simulation_types.h"
# include "DNA_sound_types.h"
# include "DNA_speaker_types.h"
# include "DNA_text_types.h"
@@ -738,6 +740,18 @@ static Volume *rna_Main_volumes_new(Main *bmain, const char *name)
return volume;
}
+# ifdef WITH_NEW_SIMULATION_TYPE
+static Simulation *rna_Main_simulations_new(Main *bmain, const char *name)
+{
+ char safe_name[MAX_ID_NAME - 2];
+ rna_idname_validate(name, safe_name);
+
+ Simulation *simulation = BKE_simulation_add(bmain, safe_name);
+ id_us_min(&simulation->id);
+ return simulation;
+}
+# endif
+
/* tag functions, all the same */
# define RNA_MAIN_ID_TAG_FUNCS_DEF(_func_name, _listbase_name, _id_type) \
static void rna_Main_##_func_name##_tag(Main *bmain, bool value) \
@@ -785,6 +799,9 @@ RNA_MAIN_ID_TAG_FUNCS_DEF(hairs, hairs, ID_HA)
RNA_MAIN_ID_TAG_FUNCS_DEF(pointclouds, pointclouds, ID_PT)
# endif
RNA_MAIN_ID_TAG_FUNCS_DEF(volumes, volumes, ID_VO)
+# ifdef WITH_NEW_SIMULATION_TYPE
+RNA_MAIN_ID_TAG_FUNCS_DEF(simulations, simulations, ID_SIM)
+# endif
# undef RNA_MAIN_ID_TAG_FUNCS_DEF
@@ -2304,4 +2321,44 @@ void RNA_def_main_volumes(BlenderRNA *brna, PropertyRNA *cprop)
RNA_def_parameter_flags(parm, 0, PARM_REQUIRED);
}
+void RNA_def_main_simulations(BlenderRNA *brna, PropertyRNA *cprop)
+{
+ StructRNA *srna;
+ FunctionRNA *func;
+ PropertyRNA *parm;
+
+ RNA_def_property_srna(cprop, "BlendDataSimulations");
+ srna = RNA_def_struct(brna, "BlendDataSimulations", NULL);
+ RNA_def_struct_sdna(srna, "Main");
+ RNA_def_struct_ui_text(srna, "Main Simulations", "Collection of simulations");
+
+ func = RNA_def_function(srna, "new", "rna_Main_simulations_new");
+ RNA_def_function_ui_description(func, "Add a new simulation to the main database");
+ parm = RNA_def_string(func, "name", "Simulation", 0, "", "New name for the data-block");
+ RNA_def_parameter_flags(parm, 0, PARM_REQUIRED);
+ /* return type */
+ parm = RNA_def_pointer(func, "simulation", "Simulation", "", "New simulation data-block");
+ RNA_def_function_return(func, parm);
+
+ func = RNA_def_function(srna, "remove", "rna_Main_ID_remove");
+ RNA_def_function_flag(func, FUNC_USE_REPORTS);
+ RNA_def_function_ui_description(func, "Remove a simulation from the current blendfile");
+ parm = RNA_def_pointer(func, "simulation", "Simulation", "", "Simulation to remove");
+ RNA_def_parameter_flags(parm, PROP_NEVER_NULL, PARM_REQUIRED | PARM_RNAPTR);
+ RNA_def_parameter_clear_flags(parm, PROP_THICK_WRAP, 0);
+ RNA_def_boolean(
+ func, "do_unlink", true, "", "Unlink all usages of this simulation before deleting it");
+ RNA_def_boolean(func,
+ "do_id_user",
+ true,
+ "",
+ "Decrement user counter of all datablocks used by this simulation data");
+ RNA_def_boolean(
+ func, "do_ui_user", true, "", "Make sure interface does not reference this simulation data");
+
+ func = RNA_def_function(srna, "tag", "rna_Main_simulations_tag");
+ parm = RNA_def_boolean(func, "value", 0, "Value", "");
+ RNA_def_parameter_flags(parm, 0, PARM_REQUIRED);
+}
+
#endif
diff --git a/source/blender/makesrna/intern/rna_material.c b/source/blender/makesrna/intern/rna_material.c
index 5c1697c70f4..5191869be3a 100644
--- a/source/blender/makesrna/intern/rna_material.c
+++ b/source/blender/makesrna/intern/rna_material.c
@@ -144,7 +144,7 @@ static void rna_Material_active_paint_texture_index_update(Main *bmain,
Scene *UNUSED(scene),
PointerRNA *ptr)
{
- bScreen *sc;
+ bScreen *screen;
Material *ma = (Material *)ptr->owner_id;
if (ma->use_nodes && ma->nodetree) {
@@ -157,8 +157,8 @@ static void rna_Material_active_paint_texture_index_update(Main *bmain,
if (ma->texpaintslot) {
Image *image = ma->texpaintslot[ma->paint_active_slot].ima;
- for (sc = bmain->screens.first; sc; sc = sc->id.next) {
- wmWindow *win = ED_screen_window_find(sc, bmain->wm.first);
+ for (screen = bmain->screens.first; screen; screen = screen->id.next) {
+ wmWindow *win = ED_screen_window_find(screen, bmain->wm.first);
if (win == NULL) {
continue;
}
@@ -169,10 +169,10 @@ static void rna_Material_active_paint_texture_index_update(Main *bmain,
obedit = OBEDIT_FROM_VIEW_LAYER(view_layer);
}
- ScrArea *sa;
- for (sa = sc->areabase.first; sa; sa = sa->next) {
+ ScrArea *area;
+ for (area = screen->areabase.first; area; area = area->next) {
SpaceLink *sl;
- for (sl = sa->spacedata.first; sl; sl = sl->next) {
+ for (sl = area->spacedata.first; sl; sl = sl->next) {
if (sl->spacetype == SPACE_IMAGE) {
SpaceImage *sima = (SpaceImage *)sl;
if (!sima->pin) {
@@ -520,13 +520,6 @@ static void rna_def_material_greasepencil(BlenderRNA *brna)
RNA_def_property_ui_text(prop, "Offset", "Shift Texture in 2d Space");
RNA_def_property_update(prop, NC_GPENCIL | ND_SHADING, "rna_MaterialGpencil_update");
- /* Texture opacity size */
- prop = RNA_def_property(srna, "texture_opacity", PROP_FLOAT, PROP_NONE);
- RNA_def_property_float_sdna(prop, NULL, "texture_opacity");
- RNA_def_property_range(prop, 0.0f, 1.0f);
- RNA_def_property_ui_text(prop, "Opacity", "Texture Opacity");
- RNA_def_property_update(prop, NC_GPENCIL | ND_SHADING, "rna_MaterialGpencil_update");
-
/* texture pixsize factor (used for UV along the stroke) */
prop = RNA_def_property(srna, "pixel_size", PROP_FLOAT, PROP_NONE);
RNA_def_property_float_sdna(prop, NULL, "texture_pixsize");
diff --git a/source/blender/makesrna/intern/rna_modifier.c b/source/blender/makesrna/intern/rna_modifier.c
index c50e68b9465..585f866ffae 100644
--- a/source/blender/makesrna/intern/rna_modifier.c
+++ b/source/blender/makesrna/intern/rna_modifier.c
@@ -93,7 +93,7 @@ const EnumPropertyItem rna_enum_object_modifier_type_items[] = {
"UV_WARP",
ICON_MOD_UVPROJECT,
"UV Warp",
- "Transform the UV map using the the difference between two objects"},
+ "Transform the UV map using the difference between two objects"},
{eModifierType_WeightVGEdit,
"VERTEX_WEIGHT_EDIT",
ICON_MOD_VERTEX_WEIGHT,
@@ -266,7 +266,7 @@ const EnumPropertyItem rna_enum_object_modifier_type_items[] = {
ICON_MOD_WAVE,
"Wave",
"Adds a ripple-like motion to an object’s geometry"},
- {0, "", 0, N_("Simulate"), ""},
+ {0, "", 0, N_("Physics"), ""},
{eModifierType_Cloth, "CLOTH", ICON_MOD_CLOTH, "Cloth", ""},
{eModifierType_Collision, "COLLISION", ICON_MOD_PHYSICS, "Collision", ""},
{eModifierType_DynamicPaint, "DYNAMIC_PAINT", ICON_MOD_DYNAMICPAINT, "Dynamic Paint", ""},
@@ -275,6 +275,7 @@ const EnumPropertyItem rna_enum_object_modifier_type_items[] = {
ICON_MOD_EXPLODE,
"Explode",
"Break apart the mesh faces and let them follow particles"},
+ {eModifierType_Fluid, "FLUID", ICON_MOD_FLUIDSIM, "Fluid", ""},
{eModifierType_Ocean, "OCEAN", ICON_MOD_OCEAN, "Ocean", "Generate a moving ocean surface"},
{eModifierType_ParticleInstance,
"PARTICLE_INSTANCE",
@@ -286,9 +287,15 @@ const EnumPropertyItem rna_enum_object_modifier_type_items[] = {
ICON_MOD_PARTICLES,
"Particle System",
"Spawn particles from the shape"},
- {eModifierType_Fluid, "FLUID", ICON_MOD_FLUIDSIM, "Fluid Simulation", ""},
{eModifierType_Softbody, "SOFT_BODY", ICON_MOD_SOFT, "Soft Body", ""},
{eModifierType_Surface, "SURFACE", ICON_MODIFIER, "Surface", ""},
+#ifdef WITH_NEW_SIMULATION_TYPE
+ {eModifierType_Simulation,
+ "SIMULATION",
+ ICON_PHYSICS,
+ "Simulation",
+ ""}, /* TODO: Use correct icon. */
+#endif
{0, NULL, 0, NULL, NULL},
};
@@ -700,10 +707,10 @@ static StructRNA *rna_Modifier_refine(struct PointerRNA *ptr)
return &RNA_MeshCacheModifier;
case eModifierType_LaplacianDeform:
return &RNA_LaplacianDeformModifier;
- case eModifierType_Wireframe:
- return &RNA_WireframeModifier;
case eModifierType_Weld:
return &RNA_WeldModifier;
+ case eModifierType_Wireframe:
+ return &RNA_WireframeModifier;
case eModifierType_DataTransfer:
return &RNA_DataTransferModifier;
case eModifierType_NormalEdit:
@@ -716,6 +723,8 @@ static StructRNA *rna_Modifier_refine(struct PointerRNA *ptr)
return &RNA_SurfaceDeformModifier;
case eModifierType_WeightedNormal:
return &RNA_WeightedNormalModifier;
+ case eModifierType_Simulation:
+ return &RNA_SimulationModifier;
/* Default */
case eModifierType_Fluidsim: /* deprecated */
case eModifierType_None:
@@ -741,7 +750,7 @@ static void rna_Modifier_name_set(PointerRNA *ptr, const char *value)
/* make sure the name is truly unique */
if (ptr->owner_id) {
Object *ob = (Object *)ptr->owner_id;
- modifier_unique_name(&ob->modifiers, md);
+ BKE_modifier_unique_name(&ob->modifiers, md);
}
/* fix all the animation data which may link to this */
@@ -797,6 +806,9 @@ RNA_MOD_VGROUP_NAME_SET(Shrinkwrap, vgroup_name);
RNA_MOD_VGROUP_NAME_SET(SimpleDeform, vgroup_name);
RNA_MOD_VGROUP_NAME_SET(Smooth, defgrp_name);
RNA_MOD_VGROUP_NAME_SET(Solidify, defgrp_name);
+RNA_MOD_VGROUP_NAME_SET(Solidify, shell_defgrp_name);
+RNA_MOD_VGROUP_NAME_SET(Solidify, rim_defgrp_name);
+RNA_MOD_VGROUP_NAME_SET(SurfaceDeform, defgrp_name);
RNA_MOD_VGROUP_NAME_SET(UVWarp, vgroup_name);
RNA_MOD_VGROUP_NAME_SET(Warp, defgrp_name);
RNA_MOD_VGROUP_NAME_SET(Wave, defgrp_name);
@@ -917,7 +929,7 @@ static bool rna_HookModifier_object_override_apply(Main *UNUSED(bmain),
{
BLI_assert(len_dst == len_src && (!ptr_storage || len_dst == len_storage) && len_dst == 0);
BLI_assert(opop->operation == IDOVERRIDE_LIBRARY_OP_REPLACE &&
- "Unsupported RNA override operation on Hook modifier target objet pointer");
+ "Unsupported RNA override operation on Hook modifier target object pointer");
UNUSED_VARS_NDEBUG(ptr_storage, len_dst, len_src, len_storage, opop);
/* We need a special handling here because setting hook target resets invert parent matrix,
@@ -1670,6 +1682,8 @@ static PropertyRNA *rna_def_property_subdivision_common(StructRNA *srna, const c
PropertyRNA *prop;
+ RNA_define_lib_overridable(true);
+
prop = RNA_def_property(srna, "uv_smooth", PROP_ENUM, PROP_NONE);
RNA_def_property_enum_sdna(prop, NULL, "uv_smooth");
RNA_def_property_enum_items(prop, prop_uv_smooth_items);
@@ -1690,6 +1704,8 @@ static PropertyRNA *rna_def_property_subdivision_common(StructRNA *srna, const c
RNA_def_property_ui_text(prop, "Subdivision Type", "Select type of subdivision algorithm");
RNA_def_property_update(prop, 0, "rna_Modifier_update");
+ RNA_define_lib_overridable(false);
+
return prop;
}
@@ -1705,6 +1721,8 @@ static void rna_def_modifier_subsurf(BlenderRNA *brna)
rna_def_property_subdivision_common(srna, "subdivType");
+ RNA_define_lib_overridable(true);
+
/* see CCGSUBSURF_LEVEL_MAX for max limit */
prop = RNA_def_property(srna, "levels", PROP_INT, PROP_UNSIGNED);
RNA_def_property_int_sdna(prop, NULL, "levels");
@@ -1731,6 +1749,8 @@ static void rna_def_modifier_subsurf(BlenderRNA *brna)
RNA_def_property_ui_text(
prop, "Use Creases", "Use mesh edge crease information to sharpen edges");
RNA_def_property_update(prop, 0, "rna_Modifier_update");
+
+ RNA_define_lib_overridable(false);
}
static void rna_def_modifier_generic_map_info(StructRNA *srna)
@@ -1757,10 +1777,11 @@ static void rna_def_modifier_generic_map_info(StructRNA *srna)
PropertyRNA *prop;
+ RNA_define_lib_overridable(true);
+
prop = RNA_def_property(srna, "texture", PROP_POINTER, PROP_NONE);
RNA_def_property_ui_text(prop, "Texture", "");
RNA_def_property_flag(prop, PROP_EDITABLE);
- RNA_def_property_override_flag(prop, PROPOVERRIDE_OVERRIDABLE_LIBRARY);
RNA_def_property_update(prop, 0, "rna_Modifier_dependency_update");
prop = RNA_def_property(srna, "texture_coords", PROP_ENUM, PROP_NONE);
@@ -1780,8 +1801,14 @@ static void rna_def_modifier_generic_map_info(StructRNA *srna)
RNA_def_property_ui_text(
prop, "Texture Coordinate Object", "Object to set the texture coordinates");
RNA_def_property_flag(prop, PROP_EDITABLE | PROP_ID_SELF_CHECK);
- RNA_def_property_override_flag(prop, PROPOVERRIDE_OVERRIDABLE_LIBRARY);
RNA_def_property_update(prop, 0, "rna_Modifier_dependency_update");
+
+ prop = RNA_def_property(srna, "texture_coords_bone", PROP_STRING, PROP_NONE);
+ RNA_def_property_string_sdna(prop, NULL, "map_bone");
+ RNA_def_property_ui_text(prop, "Texture Coordinate Bone", "Bone to set the texture coordinates");
+ RNA_def_property_update(prop, 0, "rna_Modifier_dependency_update");
+
+ RNA_define_lib_overridable(false);
}
static void rna_def_modifier_warp(BlenderRNA *brna)
@@ -1794,16 +1821,28 @@ static void rna_def_modifier_warp(BlenderRNA *brna)
RNA_def_struct_sdna(srna, "WarpModifierData");
RNA_def_struct_ui_icon(srna, ICON_MOD_WARP);
+ RNA_define_lib_overridable(true);
+
prop = RNA_def_property(srna, "object_from", PROP_POINTER, PROP_NONE);
- RNA_def_property_ui_text(prop, "From", "Object to transform from");
+ RNA_def_property_pointer_sdna(prop, NULL, "object_from");
+ RNA_def_property_ui_text(prop, "Object From", "Object to transform from");
RNA_def_property_flag(prop, PROP_EDITABLE | PROP_ID_SELF_CHECK);
- RNA_def_property_override_flag(prop, PROPOVERRIDE_OVERRIDABLE_LIBRARY);
+ RNA_def_property_update(prop, 0, "rna_Modifier_dependency_update");
+
+ prop = RNA_def_property(srna, "bone_from", PROP_STRING, PROP_NONE);
+ RNA_def_property_string_sdna(prop, NULL, "bone_from");
+ RNA_def_property_ui_text(prop, "Bone From", "Bone to transform from");
RNA_def_property_update(prop, 0, "rna_Modifier_dependency_update");
prop = RNA_def_property(srna, "object_to", PROP_POINTER, PROP_NONE);
- RNA_def_property_ui_text(prop, "To", "Object to transform to");
+ RNA_def_property_pointer_sdna(prop, NULL, "object_to");
+ RNA_def_property_ui_text(prop, "Object To", "Object to transform to");
RNA_def_property_flag(prop, PROP_EDITABLE | PROP_ID_SELF_CHECK);
- RNA_def_property_override_flag(prop, PROPOVERRIDE_OVERRIDABLE_LIBRARY);
+ RNA_def_property_update(prop, 0, "rna_Modifier_dependency_update");
+
+ prop = RNA_def_property(srna, "bone_to", PROP_STRING, PROP_NONE);
+ RNA_def_property_string_sdna(prop, NULL, "bone_to");
+ RNA_def_property_ui_text(prop, "Bone To", "Bone defining offset");
RNA_def_property_update(prop, 0, "rna_Modifier_dependency_update");
prop = RNA_def_property(srna, "strength", PROP_FLOAT, PROP_NONE);
@@ -1843,6 +1882,8 @@ static void rna_def_modifier_warp(BlenderRNA *brna)
RNA_def_property_ui_text(prop, "Invert", "Invert vertex group influence");
RNA_def_property_update(prop, 0, "rna_Modifier_update");
+ RNA_define_lib_overridable(false);
+
rna_def_modifier_generic_map_info(srna);
}
@@ -1856,6 +1897,8 @@ static void rna_def_modifier_multires(BlenderRNA *brna)
RNA_def_struct_sdna(srna, "MultiresModifierData");
RNA_def_struct_ui_icon(srna, ICON_MOD_MULTIRES);
+ RNA_define_lib_overridable(true);
+
prop = rna_def_property_subdivision_common(srna, "simple");
RNA_def_property_enum_funcs(prop, NULL, "rna_MultiresModifier_type_set", NULL);
@@ -1907,6 +1950,8 @@ static void rna_def_modifier_multires(BlenderRNA *brna)
RNA_def_property_ui_text(
prop, "Use Creases", "Use mesh edge crease information to sharpen edges");
RNA_def_property_update(prop, 0, "rna_Modifier_update");
+
+ RNA_define_lib_overridable(false);
}
static void rna_def_modifier_lattice(BlenderRNA *brna)
@@ -1919,12 +1964,13 @@ static void rna_def_modifier_lattice(BlenderRNA *brna)
RNA_def_struct_sdna(srna, "LatticeModifierData");
RNA_def_struct_ui_icon(srna, ICON_MOD_LATTICE);
+ RNA_define_lib_overridable(true);
+
prop = RNA_def_property(srna, "object", PROP_POINTER, PROP_NONE);
RNA_def_property_ui_text(prop, "Object", "Lattice object to deform with");
RNA_def_property_pointer_funcs(
prop, NULL, "rna_LatticeModifier_object_set", NULL, "rna_Lattice_object_poll");
RNA_def_property_flag(prop, PROP_EDITABLE | PROP_ID_SELF_CHECK);
- RNA_def_property_override_flag(prop, PROPOVERRIDE_OVERRIDABLE_LIBRARY);
RNA_def_property_update(prop, 0, "rna_Modifier_dependency_update");
prop = RNA_def_property(srna, "vertex_group", PROP_STRING, PROP_NONE);
@@ -1946,6 +1992,8 @@ static void rna_def_modifier_lattice(BlenderRNA *brna)
RNA_def_property_ui_range(prop, 0, 1, 10, 2);
RNA_def_property_ui_text(prop, "Strength", "Strength of modifier effect");
RNA_def_property_update(prop, 0, "rna_Modifier_update");
+
+ RNA_define_lib_overridable(false);
}
static void rna_def_modifier_curve(BlenderRNA *brna)
@@ -1968,12 +2016,13 @@ static void rna_def_modifier_curve(BlenderRNA *brna)
RNA_def_struct_sdna(srna, "CurveModifierData");
RNA_def_struct_ui_icon(srna, ICON_MOD_CURVE);
+ RNA_define_lib_overridable(true);
+
prop = RNA_def_property(srna, "object", PROP_POINTER, PROP_NONE);
RNA_def_property_ui_text(prop, "Object", "Curve object to deform with");
RNA_def_property_pointer_funcs(
prop, NULL, "rna_CurveModifier_object_set", NULL, "rna_Curve_object_poll");
RNA_def_property_flag(prop, PROP_EDITABLE | PROP_ID_SELF_CHECK);
- RNA_def_property_override_flag(prop, PROPOVERRIDE_OVERRIDABLE_LIBRARY);
RNA_def_property_update(prop, 0, "rna_CurveModifier_dependency_update");
prop = RNA_def_property(srna, "vertex_group", PROP_STRING, PROP_NONE);
@@ -1995,6 +2044,8 @@ static void rna_def_modifier_curve(BlenderRNA *brna)
RNA_def_property_enum_items(prop, prop_deform_axis_items);
RNA_def_property_ui_text(prop, "Deform Axis", "The axis that the curve deforms along");
RNA_def_property_update(prop, 0, "rna_Modifier_update");
+
+ RNA_define_lib_overridable(false);
}
static void rna_def_modifier_build(BlenderRNA *brna)
@@ -2007,6 +2058,8 @@ static void rna_def_modifier_build(BlenderRNA *brna)
RNA_def_struct_sdna(srna, "BuildModifierData");
RNA_def_struct_ui_icon(srna, ICON_MOD_BUILD);
+ RNA_define_lib_overridable(true);
+
prop = RNA_def_property(srna, "frame_start", PROP_FLOAT, PROP_TIME);
RNA_def_property_float_sdna(prop, NULL, "start");
RNA_def_property_range(prop, MINAFRAMEF, MAXFRAMEF);
@@ -2033,6 +2086,8 @@ static void rna_def_modifier_build(BlenderRNA *brna)
RNA_def_property_range(prop, 1, MAXFRAMEF);
RNA_def_property_ui_text(prop, "Seed", "Seed for random if used");
RNA_def_property_update(prop, 0, "rna_Modifier_update");
+
+ RNA_define_lib_overridable(false);
}
static void rna_def_modifier_mirror(BlenderRNA *brna)
@@ -2045,6 +2100,8 @@ static void rna_def_modifier_mirror(BlenderRNA *brna)
RNA_def_struct_sdna(srna, "MirrorModifierData");
RNA_def_struct_ui_icon(srna, ICON_MOD_MIRROR);
+ RNA_define_lib_overridable(true);
+
prop = RNA_def_property(srna, "use_axis", PROP_BOOLEAN, PROP_NONE);
RNA_def_property_boolean_sdna(prop, NULL, "flag", MOD_MIR_AXIS_X);
RNA_def_property_array(prop, 3);
@@ -2091,6 +2148,12 @@ static void rna_def_modifier_mirror(BlenderRNA *brna)
prop, "Mirror V", "Mirror the V texture coordinate around the flip offset point");
RNA_def_property_update(prop, 0, "rna_Modifier_update");
+ prop = RNA_def_property(srna, "use_mirror_udim", PROP_BOOLEAN, PROP_NONE);
+ RNA_def_property_boolean_sdna(prop, NULL, "flag", MOD_MIR_MIRROR_UDIM);
+ RNA_def_property_ui_text(
+ prop, "Mirror UDIM", "Mirror the texture coordinate around each tile center");
+ RNA_def_property_update(prop, 0, "rna_Modifier_update");
+
prop = RNA_def_property(srna, "mirror_offset_u", PROP_FLOAT, PROP_FACTOR);
RNA_def_property_float_sdna(prop, NULL, "uv_offset[0]");
RNA_def_property_range(prop, -1, 1);
@@ -2137,8 +2200,9 @@ static void rna_def_modifier_mirror(BlenderRNA *brna)
RNA_def_property_pointer_sdna(prop, NULL, "mirror_ob");
RNA_def_property_ui_text(prop, "Mirror Object", "Object to use as mirror");
RNA_def_property_flag(prop, PROP_EDITABLE | PROP_ID_SELF_CHECK);
- RNA_def_property_override_flag(prop, PROPOVERRIDE_OVERRIDABLE_LIBRARY);
RNA_def_property_update(prop, 0, "rna_Modifier_dependency_update");
+
+ RNA_define_lib_overridable(false);
}
static void rna_def_modifier_decimate(BlenderRNA *brna)
@@ -2164,6 +2228,8 @@ static void rna_def_modifier_decimate(BlenderRNA *brna)
RNA_def_struct_sdna(srna, "DecimateModifierData");
RNA_def_struct_ui_icon(srna, ICON_MOD_DECIM);
+ RNA_define_lib_overridable(true);
+
prop = RNA_def_property(srna, "decimate_type", PROP_ENUM, PROP_NONE);
RNA_def_property_enum_sdna(prop, NULL, "mode");
RNA_def_property_enum_items(prop, modifier_decim_mode_items);
@@ -2252,6 +2318,8 @@ static void rna_def_modifier_decimate(BlenderRNA *brna)
RNA_def_property_clear_flag(prop, PROP_EDITABLE);
RNA_def_property_ui_text(
prop, "Face Count", "The current number of faces in the decimated mesh");
+
+ RNA_define_lib_overridable(false);
}
static void rna_def_modifier_wave(BlenderRNA *brna)
@@ -2264,6 +2332,8 @@ static void rna_def_modifier_wave(BlenderRNA *brna)
RNA_def_struct_sdna(srna, "WaveModifierData");
RNA_def_struct_ui_icon(srna, ICON_MOD_WAVE);
+ RNA_define_lib_overridable(true);
+
prop = RNA_def_property(srna, "use_x", PROP_BOOLEAN, PROP_NONE);
RNA_def_property_boolean_sdna(prop, NULL, "flag", MOD_WAVE_X);
RNA_def_property_ui_text(prop, "X", "X axis motion");
@@ -2347,7 +2417,6 @@ static void rna_def_modifier_wave(BlenderRNA *brna)
RNA_def_property_pointer_sdna(prop, NULL, "objectcenter");
RNA_def_property_ui_text(prop, "Start Position Object", "Object which defines the wave center");
RNA_def_property_flag(prop, PROP_EDITABLE | PROP_ID_SELF_CHECK);
- RNA_def_property_override_flag(prop, PROPOVERRIDE_OVERRIDABLE_LIBRARY);
RNA_def_property_update(prop, 0, "rna_Modifier_dependency_update");
prop = RNA_def_property(srna, "vertex_group", PROP_STRING, PROP_NONE);
@@ -2391,6 +2460,8 @@ static void rna_def_modifier_wave(BlenderRNA *brna)
"the more narrow the wave");
RNA_def_property_update(prop, 0, "rna_Modifier_update");
+ RNA_define_lib_overridable(false);
+
rna_def_modifier_generic_map_info(srna);
}
@@ -2404,12 +2475,13 @@ static void rna_def_modifier_armature(BlenderRNA *brna)
RNA_def_struct_sdna(srna, "ArmatureModifierData");
RNA_def_struct_ui_icon(srna, ICON_MOD_ARMATURE);
+ RNA_define_lib_overridable(true);
+
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_override_flag(prop, PROPOVERRIDE_OVERRIDABLE_LIBRARY);
RNA_def_property_update(prop, 0, "rna_Modifier_dependency_update");
prop = RNA_def_property(srna, "use_bone_envelopes", PROP_BOOLEAN, PROP_NONE);
@@ -2451,6 +2523,8 @@ static void rna_def_modifier_armature(BlenderRNA *brna)
RNA_def_property_boolean_sdna(prop, NULL, "deformflag", ARM_DEF_INVERT_VGROUP);
RNA_def_property_ui_text(prop, "Invert", "Invert vertex group influence");
RNA_def_property_update(prop, 0, "rna_Modifier_update");
+
+ RNA_define_lib_overridable(false);
}
static void rna_def_modifier_hook(BlenderRNA *brna)
@@ -2466,6 +2540,8 @@ static void rna_def_modifier_hook(BlenderRNA *brna)
RNA_def_struct_sdna(srna, "HookModifierData");
RNA_def_struct_ui_icon(srna, ICON_HOOK);
+ RNA_define_lib_overridable(true);
+
prop = RNA_def_property(srna, "strength", PROP_FLOAT, PROP_FACTOR);
RNA_def_property_float_sdna(prop, NULL, "force");
RNA_def_property_range(prop, 0, 1);
@@ -2508,7 +2584,6 @@ static void rna_def_modifier_hook(BlenderRNA *brna)
RNA_def_property_ui_text(
prop, "Object", "Parent Object for hook, also recalculates and clears offset");
RNA_def_property_flag(prop, PROP_EDITABLE | PROP_ID_SELF_CHECK);
- RNA_def_property_override_flag(prop, PROPOVERRIDE_OVERRIDABLE_LIBRARY);
RNA_def_property_override_funcs(prop, NULL, NULL, "rna_HookModifier_object_override_apply");
RNA_def_property_pointer_funcs(prop, NULL, "rna_HookModifier_object_set", NULL, NULL);
RNA_def_property_update(prop, 0, "rna_Modifier_dependency_update");
@@ -2560,6 +2635,8 @@ static void rna_def_modifier_hook(BlenderRNA *brna)
RNA_def_property_boolean_sdna(prop, NULL, "flag", MOD_HOOK_INVERT_VGROUP);
RNA_def_property_ui_text(prop, "Invert", "Invert vertex group influence");
RNA_def_property_update(prop, 0, "rna_Modifier_update");
+
+ RNA_define_lib_overridable(false);
}
static void rna_def_modifier_softbody(BlenderRNA *brna)
@@ -2610,12 +2687,13 @@ static void rna_def_modifier_boolean(BlenderRNA *brna)
RNA_def_struct_sdna(srna, "BooleanModifierData");
RNA_def_struct_ui_icon(srna, ICON_MOD_BOOLEAN);
+ RNA_define_lib_overridable(true);
+
prop = RNA_def_property(srna, "object", PROP_POINTER, PROP_NONE);
RNA_def_property_ui_text(prop, "Object", "Mesh object to use for Boolean operation");
RNA_def_property_pointer_funcs(
prop, NULL, "rna_BooleanModifier_object_set", NULL, "rna_Mesh_object_poll");
RNA_def_property_flag(prop, PROP_EDITABLE | PROP_ID_SELF_CHECK);
- RNA_def_property_override_flag(prop, PROPOVERRIDE_OVERRIDABLE_LIBRARY);
RNA_def_property_update(prop, 0, "rna_Modifier_dependency_update");
prop = RNA_def_property(srna, "operation", PROP_ENUM, PROP_NONE);
@@ -2652,6 +2730,8 @@ static void rna_def_modifier_boolean(BlenderRNA *brna)
RNA_def_property_flag(prop, PROP_ENUM_FLAG);
RNA_def_property_ui_text(prop, "Debug", "Debugging options, only when started with '-d'");
RNA_def_property_update(prop, 0, "rna_Modifier_update");
+
+ RNA_define_lib_overridable(false);
}
static void rna_def_modifier_array(BlenderRNA *brna)
@@ -2679,6 +2759,8 @@ static void rna_def_modifier_array(BlenderRNA *brna)
RNA_def_struct_sdna(srna, "ArrayModifierData");
RNA_def_struct_ui_icon(srna, ICON_MOD_ARRAY);
+ RNA_define_lib_overridable(true);
+
/* Length parameters */
prop = RNA_def_property(srna, "fit_type", PROP_ENUM, PROP_NONE);
RNA_def_property_enum_items(prop, prop_fit_type_items);
@@ -2704,7 +2786,6 @@ static void rna_def_modifier_array(BlenderRNA *brna)
RNA_def_property_pointer_funcs(
prop, NULL, "rna_ArrayModifier_curve_ob_set", NULL, "rna_Curve_object_poll");
RNA_def_property_flag(prop, PROP_EDITABLE | PROP_ID_SELF_CHECK);
- RNA_def_property_override_flag(prop, PROPOVERRIDE_OVERRIDABLE_LIBRARY);
RNA_def_property_update(prop, 0, "rna_ArrayModifier_dependency_update");
/* Offset parameters */
@@ -2768,7 +2849,6 @@ static void rna_def_modifier_array(BlenderRNA *brna)
"Use the location and rotation of another object to determine the distance and "
"rotational change between arrayed items");
RNA_def_property_flag(prop, PROP_EDITABLE | PROP_ID_SELF_CHECK);
- RNA_def_property_override_flag(prop, PROPOVERRIDE_OVERRIDABLE_LIBRARY);
RNA_def_property_update(prop, 0, "rna_Modifier_dependency_update");
/* Caps */
@@ -2777,15 +2857,13 @@ static void rna_def_modifier_array(BlenderRNA *brna)
RNA_def_property_pointer_funcs(
prop, NULL, "rna_ArrayModifier_start_cap_set", NULL, "rna_Mesh_object_poll");
RNA_def_property_flag(prop, PROP_EDITABLE | PROP_ID_SELF_CHECK);
- RNA_def_property_override_flag(prop, PROPOVERRIDE_OVERRIDABLE_LIBRARY);
- RNA_def_property_update(prop, 0, "rna_Modifier_update");
+ RNA_def_property_update(prop, 0, "rna_Modifier_dependency_update");
prop = RNA_def_property(srna, "end_cap", PROP_POINTER, PROP_NONE);
RNA_def_property_ui_text(prop, "End Cap", "Mesh object to use as an end cap");
RNA_def_property_pointer_funcs(
prop, NULL, "rna_ArrayModifier_end_cap_set", NULL, "rna_Mesh_object_poll");
RNA_def_property_flag(prop, PROP_EDITABLE | PROP_ID_SELF_CHECK);
- RNA_def_property_override_flag(prop, PROPOVERRIDE_OVERRIDABLE_LIBRARY);
RNA_def_property_update(prop, 0, "rna_Modifier_dependency_update");
prop = RNA_def_property(srna, "offset_u", PROP_FLOAT, PROP_FACTOR);
@@ -2801,6 +2879,8 @@ static void rna_def_modifier_array(BlenderRNA *brna)
RNA_def_property_ui_range(prop, -1, 1, 2, 4);
RNA_def_property_ui_text(prop, "V Offset", "Amount to offset array UVs on the V axis");
RNA_def_property_update(prop, 0, "rna_Modifier_update");
+
+ RNA_define_lib_overridable(false);
}
static void rna_def_modifier_edgesplit(BlenderRNA *brna)
@@ -2814,6 +2894,8 @@ static void rna_def_modifier_edgesplit(BlenderRNA *brna)
RNA_def_struct_sdna(srna, "EdgeSplitModifierData");
RNA_def_struct_ui_icon(srna, ICON_MOD_EDGESPLIT);
+ RNA_define_lib_overridable(true);
+
prop = RNA_def_property(srna, "split_angle", PROP_FLOAT, PROP_ANGLE);
RNA_def_property_range(prop, 0.0f, DEG2RADF(180.0f));
RNA_def_property_ui_range(prop, 0.0f, DEG2RADF(180.0f), 10, 2);
@@ -2829,6 +2911,8 @@ static void rna_def_modifier_edgesplit(BlenderRNA *brna)
RNA_def_property_boolean_sdna(prop, NULL, "flags", MOD_EDGESPLIT_FROMFLAG);
RNA_def_property_ui_text(prop, "Use Sharp Edges", "Split edges that are marked as sharp");
RNA_def_property_update(prop, 0, "rna_Modifier_update");
+
+ RNA_define_lib_overridable(false);
}
static void rna_def_modifier_displace(BlenderRNA *brna)
@@ -2882,6 +2966,8 @@ static void rna_def_modifier_displace(BlenderRNA *brna)
RNA_def_struct_sdna(srna, "DisplaceModifierData");
RNA_def_struct_ui_icon(srna, ICON_MOD_DISPLACE);
+ RNA_define_lib_overridable(true);
+
prop = RNA_def_property(srna, "vertex_group", PROP_STRING, PROP_NONE);
RNA_def_property_string_sdna(prop, NULL, "defgrp_name");
RNA_def_property_ui_text(
@@ -2919,6 +3005,8 @@ static void rna_def_modifier_displace(BlenderRNA *brna)
RNA_def_property_ui_text(prop, "Invert", "Invert vertex group influence");
RNA_def_property_update(prop, 0, "rna_Modifier_update");
+ RNA_define_lib_overridable(false);
+
rna_def_modifier_generic_map_info(srna);
}
@@ -2933,6 +3021,8 @@ static void rna_def_modifier_uvproject(BlenderRNA *brna)
RNA_def_struct_sdna(srna, "UVProjectModifierData");
RNA_def_struct_ui_icon(srna, ICON_MOD_UVPROJECT);
+ RNA_define_lib_overridable(true);
+
prop = RNA_def_property(srna, "uv_layer", PROP_STRING, PROP_NONE);
RNA_def_property_string_sdna(prop, NULL, "uvlayer_name");
RNA_def_property_ui_text(prop, "UV Map", "UV map name");
@@ -2999,9 +3089,10 @@ static void rna_def_modifier_uvproject(BlenderRNA *brna)
RNA_def_property_pointer_funcs(
prop, "rna_UVProjector_object_get", "rna_UVProjector_object_set", NULL, NULL);
RNA_def_property_flag(prop, PROP_EDITABLE | PROP_ID_SELF_CHECK);
- RNA_def_property_override_flag(prop, PROPOVERRIDE_OVERRIDABLE_LIBRARY);
RNA_def_property_ui_text(prop, "Object", "Object to use as projector transform");
RNA_def_property_update(prop, 0, "rna_Modifier_dependency_update");
+
+ RNA_define_lib_overridable(false);
}
static void rna_def_modifier_smooth(BlenderRNA *brna)
@@ -3014,6 +3105,8 @@ static void rna_def_modifier_smooth(BlenderRNA *brna)
RNA_def_struct_sdna(srna, "SmoothModifierData");
RNA_def_struct_ui_icon(srna, ICON_MOD_SMOOTH);
+ RNA_define_lib_overridable(true);
+
prop = RNA_def_property(srna, "use_x", PROP_BOOLEAN, PROP_NONE);
RNA_def_property_boolean_sdna(prop, NULL, "flag", MOD_SMOOTH_X);
RNA_def_property_ui_text(prop, "X", "Smooth object along X axis");
@@ -3055,6 +3148,8 @@ static void rna_def_modifier_smooth(BlenderRNA *brna)
RNA_def_property_boolean_sdna(prop, NULL, "flag", MOD_SMOOTH_INVERT_VGROUP);
RNA_def_property_ui_text(prop, "Invert", "Invert vertex group influence");
RNA_def_property_update(prop, 0, "rna_Modifier_update");
+
+ RNA_define_lib_overridable(false);
}
static void rna_def_modifier_correctivesmooth(BlenderRNA *brna)
@@ -3096,6 +3191,8 @@ static void rna_def_modifier_correctivesmooth(BlenderRNA *brna)
RNA_def_struct_sdna(srna, "CorrectiveSmoothModifierData");
RNA_def_struct_ui_icon(srna, ICON_MOD_SMOOTH);
+ RNA_define_lib_overridable(true);
+
prop = RNA_def_property(srna, "factor", PROP_FLOAT, PROP_FACTOR);
RNA_def_property_float_sdna(prop, NULL, "lambda");
RNA_def_property_range(prop, -FLT_MAX, FLT_MAX);
@@ -3159,6 +3256,8 @@ static void rna_def_modifier_correctivesmooth(BlenderRNA *brna)
RNA_def_property_ui_text(
prop, "Pin Boundaries", "Excludes boundary vertices from being smoothed");
RNA_def_property_update(prop, 0, "rna_CorrectiveSmoothModifier_update");
+
+ RNA_define_lib_overridable(false);
}
static void rna_def_modifier_laplaciansmooth(BlenderRNA *brna)
@@ -3171,6 +3270,8 @@ static void rna_def_modifier_laplaciansmooth(BlenderRNA *brna)
RNA_def_struct_sdna(srna, "LaplacianSmoothModifierData");
RNA_def_struct_ui_icon(srna, ICON_MOD_SMOOTH);
+ RNA_define_lib_overridable(true);
+
prop = RNA_def_property(srna, "use_x", PROP_BOOLEAN, PROP_NONE);
RNA_def_property_boolean_sdna(prop, NULL, "flag", MOD_LAPLACIANSMOOTH_X);
RNA_def_property_ui_text(prop, "X", "Smooth object along X axis");
@@ -3229,6 +3330,8 @@ static void rna_def_modifier_laplaciansmooth(BlenderRNA *brna)
RNA_def_property_boolean_sdna(prop, NULL, "flag", MOD_LAPLACIANSMOOTH_INVERT_VGROUP);
RNA_def_property_ui_text(prop, "Invert", "Invert vertex group influence");
RNA_def_property_update(prop, 0, "rna_Modifier_update");
+
+ RNA_define_lib_overridable(false);
}
static void rna_def_modifier_cast(BlenderRNA *brna)
@@ -3248,6 +3351,8 @@ static void rna_def_modifier_cast(BlenderRNA *brna)
RNA_def_struct_sdna(srna, "CastModifierData");
RNA_def_struct_ui_icon(srna, ICON_MOD_CAST);
+ RNA_define_lib_overridable(true);
+
prop = RNA_def_property(srna, "cast_type", PROP_ENUM, PROP_NONE);
RNA_def_property_enum_sdna(prop, NULL, "type");
RNA_def_property_enum_items(prop, prop_cast_type_items);
@@ -3261,7 +3366,6 @@ static void rna_def_modifier_cast(BlenderRNA *brna)
"Control object: if available, its location determines the center of the effect");
RNA_def_property_pointer_funcs(prop, NULL, "rna_CastModifier_object_set", NULL, NULL);
RNA_def_property_flag(prop, PROP_EDITABLE | PROP_ID_SELF_CHECK);
- RNA_def_property_override_flag(prop, PROPOVERRIDE_OVERRIDABLE_LIBRARY);
RNA_def_property_update(prop, 0, "rna_Modifier_dependency_update");
prop = RNA_def_property(srna, "invert_vertex_group", PROP_BOOLEAN, PROP_NONE);
@@ -3324,6 +3428,8 @@ static void rna_def_modifier_cast(BlenderRNA *brna)
RNA_def_property_ui_text(prop, "Vertex Group", "Vertex group name");
RNA_def_property_string_funcs(prop, NULL, NULL, "rna_CastModifier_defgrp_name_set");
RNA_def_property_update(prop, 0, "rna_Modifier_update");
+
+ RNA_define_lib_overridable(false);
}
static void rna_def_modifier_meshdeform(BlenderRNA *brna)
@@ -3344,12 +3450,13 @@ static void rna_def_modifier_meshdeform(BlenderRNA *brna)
RNA_def_struct_sdna(srna, "MeshDeformModifierData");
RNA_def_struct_ui_icon(srna, ICON_MOD_MESHDEFORM);
+ RNA_define_lib_overridable(true);
+
prop = RNA_def_property(srna, "object", PROP_POINTER, PROP_NONE);
RNA_def_property_ui_text(prop, "Object", "Mesh object to deform with");
RNA_def_property_pointer_funcs(
prop, NULL, "rna_MeshDeformModifier_object_set", NULL, "rna_Mesh_object_poll");
RNA_def_property_flag(prop, PROP_EDITABLE | PROP_ID_SELF_CHECK);
- RNA_def_property_override_flag(prop, PROPOVERRIDE_OVERRIDABLE_LIBRARY);
RNA_def_property_update(prop, 0, "rna_Modifier_dependency_update");
prop = RNA_def_property(srna, "is_bound", PROP_BOOLEAN, PROP_NONE);
@@ -3388,6 +3495,8 @@ static void rna_def_modifier_meshdeform(BlenderRNA *brna)
RNA_def_property_ui_text(prop, "Mode", "Method of binding vertices are bound to cage mesh");
RNA_def_property_update(prop, 0, "rna_Modifier_update");
# endif
+
+ RNA_define_lib_overridable(false);
}
static void rna_def_modifier_particlesystem(BlenderRNA *brna)
@@ -3400,10 +3509,14 @@ static void rna_def_modifier_particlesystem(BlenderRNA *brna)
RNA_def_struct_sdna(srna, "ParticleSystemModifierData");
RNA_def_struct_ui_icon(srna, ICON_MOD_PARTICLES);
+ RNA_define_lib_overridable(true);
+
prop = RNA_def_property(srna, "particle_system", PROP_POINTER, PROP_NONE);
RNA_def_property_flag(prop, PROP_NEVER_NULL);
RNA_def_property_pointer_sdna(prop, NULL, "psys");
RNA_def_property_ui_text(prop, "Particle System", "Particle System that this modifier controls");
+
+ RNA_define_lib_overridable(false);
}
static void rna_def_modifier_particleinstance(BlenderRNA *brna)
@@ -3430,12 +3543,13 @@ static void rna_def_modifier_particleinstance(BlenderRNA *brna)
RNA_def_struct_sdna(srna, "ParticleInstanceModifierData");
RNA_def_struct_ui_icon(srna, ICON_MOD_PARTICLES);
+ RNA_define_lib_overridable(true);
+
prop = RNA_def_property(srna, "object", PROP_POINTER, PROP_NONE);
RNA_def_property_pointer_sdna(prop, NULL, "ob");
RNA_def_property_pointer_funcs(prop, NULL, NULL, NULL, "rna_Mesh_object_poll");
RNA_def_property_ui_text(prop, "Object", "Object that has the particle system");
RNA_def_property_flag(prop, PROP_EDITABLE | PROP_ID_SELF_CHECK);
- RNA_def_property_override_flag(prop, PROPOVERRIDE_OVERRIDABLE_LIBRARY);
RNA_def_property_update(prop, 0, "rna_Modifier_dependency_update");
prop = RNA_def_property(srna, "particle_system_index", PROP_INT, PROP_NONE);
@@ -3557,6 +3671,8 @@ static void rna_def_modifier_particleinstance(BlenderRNA *brna)
RNA_def_property_ui_text(
prop, "Value Layer Name", "Custom data layer name for the randomized value");
RNA_def_property_update(prop, 0, "rna_Modifier_update");
+
+ RNA_define_lib_overridable(false);
}
static void rna_def_modifier_explode(BlenderRNA *brna)
@@ -3570,6 +3686,8 @@ static void rna_def_modifier_explode(BlenderRNA *brna)
RNA_def_struct_sdna(srna, "ExplodeModifierData");
RNA_def_struct_ui_icon(srna, ICON_MOD_EXPLODE);
+ RNA_define_lib_overridable(true);
+
prop = RNA_def_property(srna, "vertex_group", PROP_STRING, PROP_NONE);
RNA_def_property_string_funcs(prop,
"rna_ExplodeModifier_vgroup_get",
@@ -3617,6 +3735,8 @@ static void rna_def_modifier_explode(BlenderRNA *brna)
RNA_def_property_boolean_sdna(prop, NULL, "flag", eExplodeFlag_INVERT_VGROUP);
RNA_def_property_ui_text(prop, "Invert", "Invert vertex group influence");
RNA_def_property_update(prop, 0, "rna_Modifier_update");
+
+ RNA_define_lib_overridable(false);
}
static void rna_def_modifier_cloth(BlenderRNA *brna)
@@ -3629,6 +3749,8 @@ static void rna_def_modifier_cloth(BlenderRNA *brna)
RNA_def_struct_sdna(srna, "ClothModifierData");
RNA_def_struct_ui_icon(srna, ICON_MOD_CLOTH);
+ RNA_define_lib_overridable(true);
+
prop = RNA_def_property(srna, "settings", PROP_POINTER, PROP_NONE);
RNA_def_property_flag(prop, PROP_NEVER_NULL);
RNA_def_property_pointer_sdna(prop, NULL, "sim_parms");
@@ -3662,6 +3784,8 @@ static void rna_def_modifier_cloth(BlenderRNA *brna)
RNA_def_property_int_sdna(prop, NULL, "hair_grid_res");
RNA_def_property_clear_flag(prop, PROP_EDITABLE);
RNA_def_property_ui_text(prop, "Hair Grid Resolution", "");
+
+ RNA_define_lib_overridable(false);
}
static void rna_def_modifier_fluid(BlenderRNA *brna)
@@ -3682,6 +3806,8 @@ static void rna_def_modifier_fluid(BlenderRNA *brna)
RNA_def_struct_sdna(srna, "FluidModifierData");
RNA_def_struct_ui_icon(srna, ICON_MOD_FLUIDSIM);
+ RNA_define_lib_overridable(true);
+
prop = RNA_def_property(srna, "domain_settings", PROP_POINTER, PROP_NONE);
RNA_def_property_pointer_sdna(prop, NULL, "domain");
RNA_def_property_ui_text(prop, "Domain Settings", "");
@@ -3700,6 +3826,8 @@ static void rna_def_modifier_fluid(BlenderRNA *brna)
RNA_def_property_ui_text(prop, "Type", "");
RNA_def_property_clear_flag(prop, PROP_ANIMATABLE);
RNA_def_property_update(prop, 0, "rna_fluid_set_type");
+
+ RNA_define_lib_overridable(false);
}
static void rna_def_modifier_dynamic_paint(BlenderRNA *brna)
@@ -3712,6 +3840,8 @@ static void rna_def_modifier_dynamic_paint(BlenderRNA *brna)
RNA_def_struct_sdna(srna, "DynamicPaintModifierData");
RNA_def_struct_ui_icon(srna, ICON_MOD_DYNAMICPAINT);
+ RNA_define_lib_overridable(true);
+
prop = RNA_def_property(srna, "canvas_settings", PROP_POINTER, PROP_NONE);
RNA_def_property_pointer_sdna(prop, NULL, "canvas");
RNA_def_property_ui_text(prop, "Canvas Settings", "");
@@ -3725,6 +3855,8 @@ static void rna_def_modifier_dynamic_paint(BlenderRNA *brna)
RNA_def_property_enum_sdna(prop, NULL, "type");
RNA_def_property_enum_items(prop, rna_enum_prop_dynamicpaint_type_items);
RNA_def_property_ui_text(prop, "Type", "");
+
+ RNA_define_lib_overridable(false);
}
static void rna_def_modifier_collision(BlenderRNA *brna)
@@ -3739,11 +3871,15 @@ static void rna_def_modifier_collision(BlenderRNA *brna)
RNA_def_struct_sdna(srna, "CollisionModifierData");
RNA_def_struct_ui_icon(srna, ICON_MOD_PHYSICS);
+ RNA_define_lib_overridable(true);
+
prop = RNA_def_property(srna, "settings", PROP_POINTER, PROP_NONE);
RNA_def_property_flag(prop, PROP_NEVER_NULL);
RNA_def_property_struct_type(prop, "CollisionSettings");
RNA_def_property_pointer_funcs(prop, "rna_CollisionModifier_settings_get", NULL, NULL, NULL);
RNA_def_property_ui_text(prop, "Settings", "");
+
+ RNA_define_lib_overridable(false);
}
static void rna_def_modifier_bevel(BlenderRNA *brna)
@@ -3828,6 +3964,8 @@ static void rna_def_modifier_bevel(BlenderRNA *brna)
RNA_def_struct_sdna(srna, "BevelModifierData");
RNA_def_struct_ui_icon(srna, ICON_MOD_BEVEL);
+ RNA_define_lib_overridable(true);
+
prop = RNA_def_property(srna, "width", PROP_FLOAT, PROP_DISTANCE);
RNA_def_property_float_sdna(prop, NULL, "value");
RNA_def_property_range(prop, 0, FLT_MAX);
@@ -3965,6 +4103,8 @@ static void rna_def_modifier_bevel(BlenderRNA *brna)
RNA_def_property_ui_text(
prop, "Vertex Mesh Method", "The method to use to create the mesh at intersections");
RNA_def_property_update(prop, 0, "rna_Modifier_update");
+
+ RNA_define_lib_overridable(false);
}
static void rna_def_modifier_shrinkwrap(BlenderRNA *brna)
@@ -4019,6 +4159,8 @@ static void rna_def_modifier_shrinkwrap(BlenderRNA *brna)
RNA_def_struct_sdna(srna, "ShrinkwrapModifierData");
RNA_def_struct_ui_icon(srna, ICON_MOD_SHRINKWRAP);
+ RNA_define_lib_overridable(true);
+
prop = RNA_def_property(srna, "wrap_method", PROP_ENUM, PROP_NONE);
RNA_def_property_enum_sdna(prop, NULL, "shrinkType");
RNA_def_property_enum_items(prop, shrink_type_items);
@@ -4048,7 +4190,6 @@ static void rna_def_modifier_shrinkwrap(BlenderRNA *brna)
RNA_def_property_pointer_funcs(
prop, NULL, "rna_ShrinkwrapModifier_target_set", NULL, "rna_Mesh_object_poll");
RNA_def_property_flag(prop, PROP_EDITABLE | PROP_ID_SELF_CHECK);
- RNA_def_property_override_flag(prop, PROPOVERRIDE_OVERRIDABLE_LIBRARY);
RNA_def_property_update(prop, 0, "rna_Modifier_dependency_update");
prop = RNA_def_property(srna, "auxiliary_target", PROP_POINTER, PROP_NONE);
@@ -4057,7 +4198,6 @@ static void rna_def_modifier_shrinkwrap(BlenderRNA *brna)
RNA_def_property_pointer_funcs(
prop, NULL, "rna_ShrinkwrapModifier_auxTarget_set", NULL, "rna_Mesh_object_poll");
RNA_def_property_flag(prop, PROP_EDITABLE | PROP_ID_SELF_CHECK);
- RNA_def_property_override_flag(prop, PROPOVERRIDE_OVERRIDABLE_LIBRARY);
RNA_def_property_update(prop, 0, "rna_Modifier_dependency_update");
prop = RNA_def_property(srna, "vertex_group", PROP_STRING, PROP_NONE);
@@ -4129,6 +4269,8 @@ static void rna_def_modifier_shrinkwrap(BlenderRNA *brna)
RNA_def_property_boolean_sdna(prop, NULL, "shrinkOpts", MOD_SHRINKWRAP_INVERT_VGROUP);
RNA_def_property_ui_text(prop, "Invert", "Invert vertex group influence");
RNA_def_property_update(prop, 0, "rna_Modifier_update");
+
+ RNA_define_lib_overridable(false);
}
static void rna_def_modifier_mask(BlenderRNA *brna)
@@ -4147,6 +4289,8 @@ static void rna_def_modifier_mask(BlenderRNA *brna)
RNA_def_struct_sdna(srna, "MaskModifierData");
RNA_def_struct_ui_icon(srna, ICON_MOD_MASK);
+ RNA_define_lib_overridable(true);
+
prop = RNA_def_property(srna, "mode", PROP_ENUM, PROP_NONE);
RNA_def_property_enum_items(prop, modifier_mask_mode_items);
RNA_def_property_ui_text(prop, "Mode", "");
@@ -4158,7 +4302,6 @@ static void rna_def_modifier_mask(BlenderRNA *brna)
RNA_def_property_pointer_funcs(
prop, NULL, "rna_MaskModifier_ob_arm_set", NULL, "rna_Armature_object_poll");
RNA_def_property_flag(prop, PROP_EDITABLE | PROP_ID_SELF_CHECK);
- RNA_def_property_override_flag(prop, PROPOVERRIDE_OVERRIDABLE_LIBRARY);
RNA_def_property_update(prop, 0, "rna_Modifier_dependency_update");
prop = RNA_def_property(srna, "vertex_group", PROP_STRING, PROP_NONE);
@@ -4178,6 +4321,8 @@ static void rna_def_modifier_mask(BlenderRNA *brna)
RNA_def_property_ui_range(prop, 0, 1, 0.1, 3);
RNA_def_property_ui_text(prop, "Threshold", "Weights over this threshold remain");
RNA_def_property_update(prop, 0, "rna_Modifier_update");
+
+ RNA_define_lib_overridable(false);
}
static void rna_def_modifier_simpledeform(BlenderRNA *brna)
@@ -4217,6 +4362,8 @@ static void rna_def_modifier_simpledeform(BlenderRNA *brna)
RNA_def_struct_sdna(srna, "SimpleDeformModifierData");
RNA_def_struct_ui_icon(srna, ICON_MOD_SIMPLEDEFORM);
+ RNA_define_lib_overridable(true);
+
prop = RNA_def_property(srna, "deform_method", PROP_ENUM, PROP_NONE);
RNA_def_property_enum_sdna(prop, NULL, "mode");
RNA_def_property_enum_items(prop, simple_deform_mode_items);
@@ -4237,7 +4384,6 @@ static void rna_def_modifier_simpledeform(BlenderRNA *brna)
prop = RNA_def_property(srna, "origin", PROP_POINTER, PROP_NONE);
RNA_def_property_ui_text(prop, "Origin", "Offset the origin and orientation of the deformation");
RNA_def_property_flag(prop, PROP_EDITABLE | PROP_ID_SELF_CHECK);
- RNA_def_property_override_flag(prop, PROPOVERRIDE_OVERRIDABLE_LIBRARY);
RNA_def_property_update(prop, 0, "rna_Modifier_dependency_update");
prop = RNA_def_property(srna, "factor", PROP_FLOAT, PROP_NONE);
@@ -4281,6 +4427,8 @@ static void rna_def_modifier_simpledeform(BlenderRNA *brna)
RNA_def_property_boolean_sdna(prop, NULL, "flag", MOD_SIMPLEDEFORM_FLAG_INVERT_VGROUP);
RNA_def_property_ui_text(prop, "Invert", "Invert vertex group influence");
RNA_def_property_update(prop, 0, "rna_Modifier_update");
+
+ RNA_define_lib_overridable(false);
}
static void rna_def_modifier_surface(BlenderRNA *brna)
@@ -4357,6 +4505,8 @@ static void rna_def_modifier_solidify(BlenderRNA *brna)
RNA_def_struct_sdna(srna, "SolidifyModifierData");
RNA_def_struct_ui_icon(srna, ICON_MOD_SOLIDIFY);
+ RNA_define_lib_overridable(true);
+
prop = RNA_def_property(srna, "solidify_mode", PROP_ENUM, PROP_NONE);
RNA_def_property_enum_sdna(prop, NULL, "mode");
RNA_def_property_enum_items(prop, mode_items);
@@ -4437,6 +4587,22 @@ static void rna_def_modifier_solidify(BlenderRNA *brna)
RNA_def_property_string_funcs(prop, NULL, NULL, "rna_SolidifyModifier_defgrp_name_set");
RNA_def_property_update(prop, 0, "rna_Modifier_update");
+ prop = RNA_def_property(srna, "shell_vertex_group", PROP_STRING, PROP_NONE);
+ RNA_def_property_string_sdna(prop, NULL, "shell_defgrp_name");
+ RNA_def_property_ui_text(prop,
+ "Shell Vertex Group",
+ "Vertex group that the generated shell geometry will be weighted to");
+ RNA_def_property_string_funcs(prop, NULL, NULL, "rna_SolidifyModifier_shell_defgrp_name_set");
+ RNA_def_property_update(prop, 0, "rna_Modifier_update");
+
+ prop = RNA_def_property(srna, "rim_vertex_group", PROP_STRING, PROP_NONE);
+ RNA_def_property_string_sdna(prop, NULL, "rim_defgrp_name");
+ RNA_def_property_ui_text(prop,
+ "Rim Vertex Group",
+ "Vertex group that the generated rim geometry will be weighted to");
+ RNA_def_property_string_funcs(prop, NULL, NULL, "rna_SolidifyModifier_rim_defgrp_name_set");
+ RNA_def_property_update(prop, 0, "rna_Modifier_update");
+
prop = RNA_def_property(srna, "use_rim", PROP_BOOLEAN, PROP_NONE);
RNA_def_property_boolean_sdna(prop, NULL, "flag", MOD_SOLIDIFY_RIM);
RNA_def_property_ui_text(prop,
@@ -4466,6 +4632,15 @@ static void rna_def_modifier_solidify(BlenderRNA *brna)
RNA_def_property_ui_text(prop, "Vertex Group Invert", "Invert the vertex group influence");
RNA_def_property_update(prop, 0, "rna_Modifier_update");
+ prop = RNA_def_property(srna, "use_flat_faces", PROP_BOOLEAN, PROP_NONE);
+ RNA_def_property_boolean_sdna(prop, NULL, "flag", MOD_SOLIDIFY_NONMANIFOLD_FLAT_FACES);
+ RNA_def_property_ui_text(prop,
+ "Flat Faces",
+ "Make faces use the minimal vertex weight assigned to their vertices"
+ "(ensures new faces remain parallel to their original ones, slow, "
+ "disable when not needed)");
+ RNA_def_property_update(prop, 0, "rna_Modifier_update");
+
prop = RNA_def_property(srna, "use_flip_normals", PROP_BOOLEAN, PROP_NONE);
RNA_def_property_boolean_sdna(prop, NULL, "flag", MOD_SOLIDIFY_FLIP);
RNA_def_property_ui_text(prop, "Flip Normals", "Invert the face direction");
@@ -4487,6 +4662,23 @@ static void rna_def_modifier_solidify(BlenderRNA *brna)
RNA_def_property_enum_items(prop, nonmanifold_boundary_mode_items);
RNA_def_property_ui_text(prop, "Boundary Shape", "Selects the boundary adjustment algorithm");
RNA_def_property_update(prop, 0, "rna_Modifier_update");
+
+ prop = RNA_def_property(srna, "nonmanifold_merge_threshold", PROP_FLOAT, PROP_DISTANCE);
+ RNA_def_property_float_sdna(prop, NULL, "merge_tolerance");
+ RNA_def_property_range(prop, 0.0, 1.0);
+ RNA_def_property_ui_range(prop, 0.0, 1.0, 0.01, 4);
+ RNA_def_property_ui_text(
+ prop, "Merge Threshold", "Distance within which degenerated geometry is merged");
+ RNA_def_property_update(prop, 0, "rna_Modifier_update");
+
+ prop = RNA_def_property(srna, "bevel_convex", PROP_FLOAT, PROP_NONE);
+ RNA_def_property_float_sdna(prop, NULL, "bevel_convex");
+ RNA_def_property_range(prop, -1.0, 1.0);
+ RNA_def_property_ui_range(prop, -1.0, 1.0, 0.1, 3);
+ RNA_def_property_ui_text(prop, "Bevel Convex", "Edge bevel weight to be added to outside edges");
+ RNA_def_property_update(prop, 0, "rna_Modifier_update");
+
+ RNA_define_lib_overridable(false);
}
static void rna_def_modifier_screw(BlenderRNA *brna)
@@ -4499,22 +4691,23 @@ static void rna_def_modifier_screw(BlenderRNA *brna)
RNA_def_struct_sdna(srna, "ScrewModifierData");
RNA_def_struct_ui_icon(srna, ICON_MOD_SCREW);
+ RNA_define_lib_overridable(true);
+
prop = RNA_def_property(srna, "object", PROP_POINTER, PROP_NONE);
RNA_def_property_pointer_sdna(prop, NULL, "ob_axis");
RNA_def_property_ui_text(prop, "Object", "Object to define the screw axis");
RNA_def_property_flag(prop, PROP_EDITABLE | PROP_ID_SELF_CHECK);
- RNA_def_property_override_flag(prop, PROPOVERRIDE_OVERRIDABLE_LIBRARY);
RNA_def_property_update(prop, 0, "rna_Modifier_dependency_update");
prop = RNA_def_property(srna, "steps", PROP_INT, PROP_UNSIGNED);
- RNA_def_property_range(prop, 2, 10000);
- RNA_def_property_ui_range(prop, 3, 512, 1, -1);
+ RNA_def_property_range(prop, 1, 10000);
+ RNA_def_property_ui_range(prop, 1, 512, 1, -1);
RNA_def_property_ui_text(prop, "Steps", "Number of steps in the revolution");
RNA_def_property_update(prop, 0, "rna_Modifier_update");
prop = RNA_def_property(srna, "render_steps", PROP_INT, PROP_UNSIGNED);
- RNA_def_property_range(prop, 2, 10000);
- RNA_def_property_ui_range(prop, 2, 512, 1, -1);
+ RNA_def_property_range(prop, 1, 10000);
+ RNA_def_property_ui_range(prop, 1, 512, 1, -1);
RNA_def_property_ui_text(prop, "Render Steps", "Number of steps in the revolution");
RNA_def_property_update(prop, 0, "rna_Modifier_update");
@@ -4597,6 +4790,8 @@ static void rna_def_modifier_screw(BlenderRNA *brna)
prop, "Object Angle", "Use the angle between the objects rather than the fixed angle");
RNA_def_property_update(prop, 0, "rna_Modifier_update");
# endif
+
+ RNA_define_lib_overridable(false);
}
static void rna_def_modifier_uvwarp(BlenderRNA *brna)
@@ -4609,6 +4804,8 @@ static void rna_def_modifier_uvwarp(BlenderRNA *brna)
RNA_def_struct_sdna(srna, "UVWarpModifierData");
RNA_def_struct_ui_icon(srna, ICON_MOD_UVPROJECT);
+ RNA_define_lib_overridable(true);
+
prop = RNA_def_property(srna, "axis_u", PROP_ENUM, PROP_NONE);
RNA_def_property_enum_sdna(prop, NULL, "axis_u");
RNA_def_property_enum_items(prop, rna_enum_axis_xyz_items);
@@ -4645,7 +4842,6 @@ static void rna_def_modifier_uvwarp(BlenderRNA *brna)
RNA_def_property_pointer_sdna(prop, NULL, "object_src");
RNA_def_property_ui_text(prop, "Object From", "Object defining offset");
RNA_def_property_flag(prop, PROP_EDITABLE);
- RNA_def_property_override_flag(prop, PROPOVERRIDE_OVERRIDABLE_LIBRARY);
RNA_def_property_update(prop, 0, "rna_Modifier_dependency_update");
prop = RNA_def_property(srna, "bone_from", PROP_STRING, PROP_NONE);
@@ -4657,7 +4853,6 @@ static void rna_def_modifier_uvwarp(BlenderRNA *brna)
RNA_def_property_pointer_sdna(prop, NULL, "object_dst");
RNA_def_property_ui_text(prop, "Object To", "Object defining offset");
RNA_def_property_flag(prop, PROP_EDITABLE);
- RNA_def_property_override_flag(prop, PROPOVERRIDE_OVERRIDABLE_LIBRARY);
RNA_def_property_update(prop, 0, "rna_Modifier_dependency_update");
prop = RNA_def_property(srna, "bone_to", PROP_STRING, PROP_NONE);
@@ -4681,10 +4876,13 @@ static void rna_def_modifier_uvwarp(BlenderRNA *brna)
RNA_def_property_ui_text(prop, "UV Layer", "UV Layer name");
RNA_def_property_string_funcs(prop, NULL, NULL, "rna_UVWarpModifier_uvlayer_name_set");
RNA_def_property_update(prop, 0, "rna_Modifier_update");
+
+ RNA_define_lib_overridable(false);
}
static void rna_def_modifier_weightvg_mask(BlenderRNA *UNUSED(brna),
StructRNA *srna,
+ const char *mask_flags,
const char *mask_vgroup_setter,
const char *mask_uvlayer_setter)
{
@@ -4714,6 +4912,8 @@ static void rna_def_modifier_weightvg_mask(BlenderRNA *UNUSED(brna),
PropertyRNA *prop;
+ RNA_define_lib_overridable(true);
+
prop = RNA_def_property(srna, "mask_constant", PROP_FLOAT, PROP_FACTOR);
RNA_def_property_range(prop, -FLT_MAX, FLT_MAX);
RNA_def_property_ui_range(prop, 0.0, 1.0, 1, -1);
@@ -4727,10 +4927,14 @@ static void rna_def_modifier_weightvg_mask(BlenderRNA *UNUSED(brna),
RNA_def_property_string_funcs(prop, NULL, NULL, mask_vgroup_setter);
RNA_def_property_update(prop, 0, "rna_Modifier_update");
+ prop = RNA_def_property(srna, "invert_mask_vertex_group", PROP_BOOLEAN, PROP_NONE);
+ RNA_def_property_boolean_sdna(prop, NULL, mask_flags, MOD_WVG_EDIT_INVERT_VGROUP_MASK);
+ RNA_def_property_ui_text(prop, "Invert", "Invert vertex group mask influence");
+ RNA_def_property_update(prop, 0, "rna_Modifier_update");
+
prop = RNA_def_property(srna, "mask_texture", PROP_POINTER, PROP_NONE);
RNA_def_property_ui_text(prop, "Masking Tex", "Masking texture");
RNA_def_property_flag(prop, PROP_EDITABLE);
- RNA_def_property_override_flag(prop, PROPOVERRIDE_OVERRIDABLE_LIBRARY);
RNA_def_property_update(prop, 0, "rna_Modifier_dependency_update");
prop = RNA_def_property(srna, "mask_tex_use_channel", PROP_ENUM, PROP_NONE);
@@ -4759,8 +4963,15 @@ static void rna_def_modifier_weightvg_mask(BlenderRNA *UNUSED(brna),
"Which object to take texture "
"coordinates from");
RNA_def_property_flag(prop, PROP_EDITABLE | PROP_ID_SELF_CHECK);
- RNA_def_property_override_flag(prop, PROPOVERRIDE_OVERRIDABLE_LIBRARY);
RNA_def_property_update(prop, 0, "rna_Modifier_dependency_update");
+
+ prop = RNA_def_property(srna, "mask_tex_map_bone", PROP_STRING, PROP_NONE);
+ RNA_def_property_string_sdna(prop, NULL, "mask_tex_map_bone");
+ RNA_def_property_ui_text(
+ prop, "Texture Coordinate Bone", "Which bone to take texture coordinates from");
+ RNA_def_property_update(prop, 0, "rna_Modifier_dependency_update");
+
+ RNA_define_lib_overridable(false);
}
static void rna_def_modifier_weightvgedit(BlenderRNA *brna)
@@ -4790,6 +5001,8 @@ static void rna_def_modifier_weightvgedit(BlenderRNA *brna)
RNA_def_struct_sdna(srna, "WeightVGEditModifierData");
RNA_def_struct_ui_icon(srna, ICON_MOD_VERTEX_WEIGHT);
+ RNA_define_lib_overridable(true);
+
prop = RNA_def_property(srna, "vertex_group", PROP_STRING, PROP_NONE);
RNA_def_property_string_sdna(prop, NULL, "defgrp_name");
RNA_def_property_ui_text(prop, "Vertex Group", "Vertex group name");
@@ -4807,6 +5020,14 @@ static void rna_def_modifier_weightvgedit(BlenderRNA *brna)
RNA_def_property_ui_text(prop, "Invert Falloff", "Invert the resulting falloff weight");
RNA_def_property_update(prop, 0, "rna_Modifier_update");
+ prop = RNA_def_property(srna, "normalize", PROP_BOOLEAN, PROP_NONE);
+ RNA_def_property_boolean_sdna(prop, NULL, "edit_flags", MOD_WVG_EDIT_WEIGHTS_NORMALIZE);
+ RNA_def_property_ui_text(
+ prop,
+ "Normalize Weights",
+ "Normalize the resulting weights (otherwise they are only clamped within [0.0, 1.0] range)");
+ RNA_def_property_update(prop, 0, "rna_Modifier_update");
+
prop = RNA_def_property(srna, "map_curve", PROP_POINTER, PROP_NONE);
RNA_def_property_pointer_sdna(prop, NULL, "cmap_curve");
RNA_def_property_ui_text(prop, "Mapping Curve", "Custom mapping curve");
@@ -4857,16 +5078,14 @@ static void rna_def_modifier_weightvgedit(BlenderRNA *brna)
"to be removed from the vgroup");
RNA_def_property_update(prop, 0, "rna_Modifier_update");
+ RNA_define_lib_overridable(false);
+
/* Common masking properties. */
rna_def_modifier_weightvg_mask(brna,
srna,
+ "edit_flags",
"rna_WeightVGEditModifier_mask_defgrp_name_set",
"rna_WeightVGEditModifier_mask_tex_uvlayer_name_set");
-
- prop = RNA_def_property(srna, "invert_mask_vertex_group", PROP_BOOLEAN, PROP_NONE);
- RNA_def_property_boolean_sdna(prop, NULL, "edit_flags", MOD_WVG_EDIT_INVERT_VGROUP_MASK);
- RNA_def_property_ui_text(prop, "Invert", "Invert vertex group mask influence");
- RNA_def_property_update(prop, 0, "rna_Modifier_update");
}
static void rna_def_modifier_weightvgmix(BlenderRNA *brna)
@@ -4911,6 +5130,8 @@ static void rna_def_modifier_weightvgmix(BlenderRNA *brna)
RNA_def_struct_sdna(srna, "WeightVGMixModifierData");
RNA_def_struct_ui_icon(srna, ICON_MOD_VERTEX_WEIGHT);
+ RNA_define_lib_overridable(true);
+
prop = RNA_def_property(srna, "vertex_group_a", PROP_STRING, PROP_NONE);
RNA_def_property_string_sdna(prop, NULL, "defgrp_name_a");
RNA_def_property_ui_text(prop, "Vertex Group A", "First vertex group name");
@@ -4923,6 +5144,16 @@ static void rna_def_modifier_weightvgmix(BlenderRNA *brna)
RNA_def_property_string_funcs(prop, NULL, NULL, "rna_WeightVGMixModifier_defgrp_name_b_set");
RNA_def_property_update(prop, 0, "rna_Modifier_update");
+ prop = RNA_def_property(srna, "invert_vertex_group_a", PROP_BOOLEAN, PROP_NONE);
+ RNA_def_property_boolean_sdna(prop, NULL, "flag", MOD_WVG_MIX_INVERT_VGROUP_A);
+ RNA_def_property_ui_text(prop, "Invert Weights A", "Invert the influence of vertex group A");
+ RNA_def_property_update(prop, 0, "rna_Modifier_update");
+
+ prop = RNA_def_property(srna, "invert_vertex_group_b", PROP_BOOLEAN, PROP_NONE);
+ RNA_def_property_boolean_sdna(prop, NULL, "flag", MOD_WVG_MIX_INVERT_VGROUP_B);
+ RNA_def_property_ui_text(prop, "Invert Weights B", "Invert the influence of vertex group B");
+ RNA_def_property_update(prop, 0, "rna_Modifier_update");
+
prop = RNA_def_property(srna, "default_weight_a", PROP_FLOAT, PROP_FACTOR);
RNA_def_property_range(prop, 0.0, 1.0f);
RNA_def_property_ui_range(prop, 0.0, 1.0, 1, -1);
@@ -4954,16 +5185,22 @@ static void rna_def_modifier_weightvgmix(BlenderRNA *brna)
RNA_def_property_ui_text(prop, "Vertex Set", "Which vertices should be affected");
RNA_def_property_update(prop, 0, "rna_Modifier_update");
+ prop = RNA_def_property(srna, "normalize", PROP_BOOLEAN, PROP_NONE);
+ RNA_def_property_boolean_sdna(prop, NULL, "flag", MOD_WVG_MIX_WEIGHTS_NORMALIZE);
+ RNA_def_property_ui_text(
+ prop,
+ "Normalize Weights",
+ "Normalize the resulting weights (otherwise they are only clamped within [0.0, 1.0] range)");
+ RNA_def_property_update(prop, 0, "rna_Modifier_update");
+
+ RNA_define_lib_overridable(false);
+
/* Common masking properties. */
rna_def_modifier_weightvg_mask(brna,
srna,
+ "flag",
"rna_WeightVGMixModifier_mask_defgrp_name_set",
"rna_WeightVGMixModifier_mask_tex_uvlayer_name_set");
-
- prop = RNA_def_property(srna, "invert_mask_vertex_group", PROP_BOOLEAN, PROP_NONE);
- RNA_def_property_boolean_sdna(prop, NULL, "flag", MOD_WVG_MIX_INVERT_VGROUP_MASK);
- RNA_def_property_ui_text(prop, "Invert", "Invert vertex group mask influence");
- RNA_def_property_update(prop, 0, "rna_Modifier_update");
}
static void rna_def_modifier_weightvgproximity(BlenderRNA *brna)
@@ -5017,6 +5254,8 @@ static void rna_def_modifier_weightvgproximity(BlenderRNA *brna)
RNA_def_struct_sdna(srna, "WeightVGProximityModifierData");
RNA_def_struct_ui_icon(srna, ICON_MOD_VERTEX_WEIGHT);
+ RNA_define_lib_overridable(true);
+
prop = RNA_def_property(srna, "vertex_group", PROP_STRING, PROP_NONE);
RNA_def_property_string_sdna(prop, NULL, "defgrp_name");
RNA_def_property_ui_text(prop, "Vertex Group", "Vertex group name");
@@ -5044,7 +5283,6 @@ static void rna_def_modifier_weightvgproximity(BlenderRNA *brna)
RNA_def_property_pointer_sdna(prop, NULL, "proximity_ob_target");
RNA_def_property_ui_text(prop, "Target Object", "Object to calculate vertices distances from");
RNA_def_property_flag(prop, PROP_EDITABLE | PROP_ID_SELF_CHECK);
- RNA_def_property_override_flag(prop, PROPOVERRIDE_OVERRIDABLE_LIBRARY);
RNA_def_property_update(prop, 0, "rna_Modifier_dependency_update");
prop = RNA_def_property(srna, "min_dist", PROP_FLOAT, PROP_DISTANCE);
@@ -5070,17 +5308,23 @@ static void rna_def_modifier_weightvgproximity(BlenderRNA *brna)
RNA_def_property_ui_text(prop, "Invert Falloff", "Invert the resulting falloff weight");
RNA_def_property_update(prop, 0, "rna_Modifier_update");
+ prop = RNA_def_property(srna, "normalize", PROP_BOOLEAN, PROP_NONE);
+ RNA_def_property_boolean_sdna(
+ prop, NULL, "proximity_flags", MOD_WVG_PROXIMITY_WEIGHTS_NORMALIZE);
+ RNA_def_property_ui_text(
+ prop,
+ "Normalize Weights",
+ "Normalize the resulting weights (otherwise they are only clamped within [0.0, 1.0] range)");
+ RNA_def_property_update(prop, 0, "rna_Modifier_update");
+
+ RNA_define_lib_overridable(false);
+
/* Common masking properties. */
rna_def_modifier_weightvg_mask(brna,
srna,
+ "proximity_flags",
"rna_WeightVGProximityModifier_mask_defgrp_name_set",
"rna_WeightVGProximityModifier_mask_tex_uvlayer_name_set");
-
- prop = RNA_def_property(srna, "invert_mask_vertex_group", PROP_BOOLEAN, PROP_NONE);
- RNA_def_property_boolean_sdna(
- prop, NULL, "proximity_flags", MOD_WVG_PROXIMITY_INVERT_VGROUP_MASK);
- RNA_def_property_ui_text(prop, "Invert", "Invert vertex group mask influence");
- RNA_def_property_update(prop, 0, "rna_Modifier_update");
}
static void rna_def_modifier_remesh(BlenderRNA *brna)
@@ -5097,6 +5341,11 @@ static void rna_def_modifier_remesh(BlenderRNA *brna)
0,
"Sharp",
"Output a surface that reproduces sharp edges and corners from the input mesh"},
+ {MOD_REMESH_VOXEL,
+ "VOXEL",
+ 0,
+ "Voxel",
+ "Output a mesh corresponding to the volume of the original mesh"},
{0, NULL, 0, NULL, NULL},
};
@@ -5111,6 +5360,8 @@ static void rna_def_modifier_remesh(BlenderRNA *brna)
RNA_def_struct_sdna(srna, "RemeshModifierData");
RNA_def_struct_ui_icon(srna, ICON_MOD_REMESH);
+ RNA_define_lib_overridable(true);
+
prop = RNA_def_property(srna, "mode", PROP_ENUM, PROP_NONE);
RNA_def_property_enum_items(prop, mode_items);
RNA_def_property_ui_text(prop, "Mode", "");
@@ -5150,6 +5401,25 @@ static void rna_def_modifier_remesh(BlenderRNA *brna)
"edges closer to the input");
RNA_def_property_update(prop, 0, "rna_Modifier_update");
+ prop = RNA_def_property(srna, "voxel_size", PROP_FLOAT, PROP_DISTANCE);
+ RNA_def_property_float_sdna(prop, NULL, "voxel_size");
+ RNA_def_property_ui_range(prop, 0.0001, 2, 0.1, 3);
+ RNA_def_property_ui_text(prop,
+ "Voxel Size",
+ "Size of the voxel in object space used for volume evaluation. Lower "
+ "values preserve finer details");
+ RNA_def_property_update(prop, 0, "rna_Modifier_update");
+
+ prop = RNA_def_property(srna, "adaptivity", PROP_FLOAT, PROP_DISTANCE);
+ RNA_def_property_float_sdna(prop, NULL, "adaptivity");
+ RNA_def_property_ui_range(prop, 0, 1, 0.1, 3);
+ RNA_def_property_ui_text(
+ prop,
+ "Adaptivity",
+ "Reduces the final face count by simplifying geometry where detail is not needed, "
+ "generating triangles. A value greater than 0 disables Fix Poles");
+ RNA_def_property_update(prop, 0, "rna_Modifier_update");
+
prop = RNA_def_property(srna, "use_remove_disconnected", PROP_BOOLEAN, PROP_NONE);
RNA_def_property_boolean_sdna(prop, NULL, "flag", MOD_REMESH_FLOOD_FILL);
RNA_def_property_ui_text(prop, "Remove Disconnected Pieces", "");
@@ -5160,6 +5430,8 @@ static void rna_def_modifier_remesh(BlenderRNA *brna)
RNA_def_property_ui_text(
prop, "Smooth Shading", "Output faces with smooth shading rather than flat shaded");
RNA_def_property_update(prop, 0, "rna_Modifier_update");
+
+ RNA_define_lib_overridable(false);
}
static void rna_def_modifier_ocean(BlenderRNA *brna)
@@ -5217,6 +5489,8 @@ static void rna_def_modifier_ocean(BlenderRNA *brna)
RNA_def_struct_sdna(srna, "OceanModifierData");
RNA_def_struct_ui_icon(srna, ICON_MOD_OCEAN);
+ RNA_define_lib_overridable(true);
+
prop = RNA_def_property(srna, "geometry_mode", PROP_ENUM, PROP_NONE);
RNA_def_property_enum_sdna(prop, NULL, "geometry_mode");
RNA_def_property_enum_items(prop, geometry_items);
@@ -5410,6 +5684,8 @@ static void rna_def_modifier_ocean(BlenderRNA *brna)
RNA_def_property_ui_text(prop, "Cache Path", "Path to a folder to store external baked images");
/*RNA_def_property_update(prop, 0, "rna_Modifier_update"); */
/* XXX how to update? */
+
+ RNA_define_lib_overridable(false);
}
static void rna_def_modifier_skin(BlenderRNA *brna)
@@ -5422,6 +5698,8 @@ static void rna_def_modifier_skin(BlenderRNA *brna)
RNA_def_struct_sdna(srna, "SkinModifierData");
RNA_def_struct_ui_icon(srna, ICON_MOD_SKIN);
+ RNA_define_lib_overridable(true);
+
prop = RNA_def_property(srna, "branch_smoothing", PROP_FLOAT, PROP_FACTOR);
RNA_def_property_ui_text(prop, "Branch Smoothing", "Smooth complex geometry around branches");
RNA_def_property_ui_range(prop, 0, 1, 1, -1);
@@ -5447,6 +5725,8 @@ static void rna_def_modifier_skin(BlenderRNA *brna)
RNA_def_property_boolean_sdna(prop, NULL, "symmetry_axes", MOD_SKIN_SYMM_Z);
RNA_def_property_ui_text(prop, "Z", "Avoid making unsymmetrical quads across the Z axis");
RNA_def_property_update(prop, 0, "rna_Modifier_update");
+
+ RNA_define_lib_overridable(false);
}
static void rna_def_modifier_triangulate(BlenderRNA *brna)
@@ -5459,6 +5739,8 @@ static void rna_def_modifier_triangulate(BlenderRNA *brna)
RNA_def_struct_sdna(srna, "TriangulateModifierData");
RNA_def_struct_ui_icon(srna, ICON_MOD_TRIANGULATE);
+ RNA_define_lib_overridable(true);
+
prop = RNA_def_property(srna, "quad_method", PROP_ENUM, PROP_NONE);
RNA_def_property_enum_sdna(prop, NULL, "quad_method");
RNA_def_property_enum_items(prop, rna_enum_modifier_triangulate_quad_method_items);
@@ -5489,6 +5771,8 @@ static void rna_def_modifier_triangulate(BlenderRNA *brna)
"Try to preserve custom normals (WARNING: depending on chosen triangulation method, "
"shading may not be fully preserved, 'Fixed' method usually gives the best result here)");
RNA_def_property_update(prop, 0, "rna_Modifier_update");
+
+ RNA_define_lib_overridable(false);
}
static void rna_def_modifier_meshcache(BlenderRNA *brna)
@@ -5555,6 +5839,8 @@ static void rna_def_modifier_meshcache(BlenderRNA *brna)
RNA_def_struct_sdna(srna, "MeshCacheModifierData");
RNA_def_struct_ui_icon(srna, ICON_MOD_MESHDEFORM); /* XXX, needs own icon */
+ RNA_define_lib_overridable(true);
+
prop = RNA_def_property(srna, "cache_format", PROP_ENUM, PROP_NONE);
RNA_def_property_enum_sdna(prop, NULL, "type");
RNA_def_property_enum_items(prop, prop_format_type_items);
@@ -5649,6 +5935,8 @@ static void rna_def_modifier_meshcache(BlenderRNA *brna)
RNA_def_property_range(prop, 0.0f, 1.0f);
RNA_def_property_ui_text(prop, "Evaluation Factor", "Evaluation time in seconds");
RNA_def_property_update(prop, 0, "rna_Modifier_update");
+
+ RNA_define_lib_overridable(false);
}
static void rna_def_modifier_meshseqcache(BlenderRNA *brna)
@@ -5661,12 +5949,13 @@ static void rna_def_modifier_meshseqcache(BlenderRNA *brna)
RNA_def_struct_sdna(srna, "MeshSeqCacheModifierData");
RNA_def_struct_ui_icon(srna, ICON_MOD_MESHDEFORM); /* XXX, needs own icon */
+ RNA_define_lib_overridable(true);
+
prop = RNA_def_property(srna, "cache_file", PROP_POINTER, PROP_NONE);
RNA_def_property_pointer_sdna(prop, NULL, "cache_file");
RNA_def_property_struct_type(prop, "CacheFile");
RNA_def_property_ui_text(prop, "Cache File", "");
RNA_def_property_flag(prop, PROP_EDITABLE | PROP_ID_SELF_CHECK);
- RNA_def_property_override_flag(prop, PROPOVERRIDE_OVERRIDABLE_LIBRARY);
RNA_def_property_update(prop, 0, "rna_Modifier_dependency_update");
prop = RNA_def_property(srna, "object_path", PROP_STRING, PROP_NONE);
@@ -5689,6 +5978,8 @@ static void rna_def_modifier_meshseqcache(BlenderRNA *brna)
RNA_def_property_enum_sdna(prop, NULL, "read_flag");
RNA_def_property_enum_items(prop, read_flag_items);
RNA_def_property_update(prop, 0, "rna_Modifier_update");
+
+ RNA_define_lib_overridable(false);
}
static void rna_def_modifier_laplaciandeform(BlenderRNA *brna)
@@ -5701,6 +5992,8 @@ static void rna_def_modifier_laplaciandeform(BlenderRNA *brna)
RNA_def_struct_sdna(srna, "LaplacianDeformModifierData");
RNA_def_struct_ui_icon(srna, ICON_MOD_MESHDEFORM);
+ RNA_define_lib_overridable(true);
+
prop = RNA_def_property(srna, "vertex_group", PROP_STRING, PROP_NONE);
RNA_def_property_string_sdna(prop, NULL, "anchor_grp_name");
RNA_def_property_ui_text(
@@ -5724,9 +6017,54 @@ static void rna_def_modifier_laplaciandeform(BlenderRNA *brna)
RNA_def_property_ui_text(prop, "Invert", "Invert vertex group influence");
RNA_def_property_update(prop, 0, "rna_Modifier_update");
+ RNA_define_lib_overridable(false);
+
RNA_def_property_update(prop, 0, "rna_Modifier_update");
}
+static void rna_def_modifier_weld(BlenderRNA *brna)
+{
+ StructRNA *srna;
+ PropertyRNA *prop;
+
+ srna = RNA_def_struct(brna, "WeldModifier", "Modifier");
+ RNA_def_struct_ui_text(srna, "Weld Modifier", "Weld modifier");
+ RNA_def_struct_sdna(srna, "WeldModifierData");
+ RNA_def_struct_ui_icon(srna, ICON_AUTOMERGE_OFF);
+
+ RNA_define_lib_overridable(true);
+
+ prop = RNA_def_property(srna, "merge_threshold", PROP_FLOAT, PROP_DISTANCE);
+ RNA_def_property_float_sdna(prop, NULL, "merge_dist");
+ RNA_def_property_range(prop, 0, FLT_MAX);
+ RNA_def_property_ui_range(prop, 0, 1, 0.001, 6);
+ RNA_def_property_ui_text(prop, "Merge Distance", "Limit below which to merge vertices");
+ RNA_def_property_update(prop, 0, "rna_Modifier_update");
+
+ prop = RNA_def_property(srna, "max_interactions", PROP_INT, PROP_UNSIGNED);
+ RNA_def_property_int_sdna(prop, NULL, "max_interactions");
+ RNA_def_property_ui_text(
+ prop,
+ "Duplicate Limit",
+ "For a better performance, limits the number of elements found per vertex. "
+ "(0 makes it infinite)");
+ RNA_def_property_update(prop, 0, "rna_Modifier_update");
+
+ prop = RNA_def_property(srna, "vertex_group", PROP_STRING, PROP_NONE);
+ RNA_def_property_string_sdna(prop, NULL, "defgrp_name");
+ RNA_def_property_ui_text(
+ prop, "Vertex Group", "Vertex group name for selecting the affected areas");
+ RNA_def_property_string_funcs(prop, NULL, NULL, "rna_WeldModifier_defgrp_name_set");
+ RNA_def_property_update(prop, 0, "rna_Modifier_update");
+
+ prop = RNA_def_property(srna, "invert_vertex_group", PROP_BOOLEAN, PROP_NONE);
+ RNA_def_property_boolean_sdna(prop, NULL, "flag", MOD_WELD_INVERT_VGROUP);
+ RNA_def_property_ui_text(prop, "Invert", "Invert vertex group influence");
+ RNA_def_property_update(prop, 0, "rna_Modifier_update");
+
+ RNA_define_lib_overridable(false);
+}
+
static void rna_def_modifier_wireframe(BlenderRNA *brna)
{
StructRNA *srna;
@@ -5737,6 +6075,8 @@ static void rna_def_modifier_wireframe(BlenderRNA *brna)
RNA_def_struct_sdna(srna, "WireframeModifierData");
RNA_def_struct_ui_icon(srna, ICON_MOD_WIREFRAME);
+ RNA_define_lib_overridable(true);
+
prop = RNA_def_property(srna, "thickness", PROP_FLOAT, PROP_DISTANCE);
RNA_def_property_float_sdna(prop, NULL, "offset");
RNA_def_property_range(prop, -FLT_MAX, FLT_MAX);
@@ -5808,45 +6148,8 @@ static void rna_def_modifier_wireframe(BlenderRNA *brna)
RNA_def_property_boolean_sdna(prop, NULL, "flag", MOD_WIREFRAME_INVERT_VGROUP);
RNA_def_property_ui_text(prop, "Invert", "Invert vertex group influence");
RNA_def_property_update(prop, 0, "rna_Modifier_update");
-}
-static void rna_def_modifier_weld(BlenderRNA *brna)
-{
- StructRNA *srna;
- PropertyRNA *prop;
-
- srna = RNA_def_struct(brna, "WeldModifier", "Modifier");
- RNA_def_struct_ui_text(srna, "Weld Modifier", "Weld modifier");
- RNA_def_struct_sdna(srna, "WeldModifierData");
- RNA_def_struct_ui_icon(srna, ICON_AUTOMERGE_OFF);
-
- prop = RNA_def_property(srna, "merge_threshold", PROP_FLOAT, PROP_DISTANCE);
- RNA_def_property_float_sdna(prop, NULL, "merge_dist");
- RNA_def_property_range(prop, 0, FLT_MAX);
- RNA_def_property_ui_range(prop, 0, 1, 0.001, 6);
- RNA_def_property_ui_text(prop, "Merge Distance", "Limit below which to merge vertices");
- RNA_def_property_update(prop, 0, "rna_Modifier_update");
-
- prop = RNA_def_property(srna, "max_interactions", PROP_INT, PROP_UNSIGNED);
- RNA_def_property_int_sdna(prop, NULL, "max_interactions");
- RNA_def_property_ui_text(
- prop,
- "Duplicate Limit",
- "For a better performance, limits the number of elements found per vertex. "
- "(0 makes it infinite)");
- RNA_def_property_update(prop, 0, "rna_Modifier_update");
-
- prop = RNA_def_property(srna, "vertex_group", PROP_STRING, PROP_NONE);
- RNA_def_property_string_sdna(prop, NULL, "defgrp_name");
- RNA_def_property_ui_text(
- prop, "Vertex Group", "Vertex group name for selecting the affected areas");
- RNA_def_property_string_funcs(prop, NULL, NULL, "rna_WeldModifier_defgrp_name_set");
- RNA_def_property_update(prop, 0, "rna_Modifier_update");
-
- prop = RNA_def_property(srna, "invert_vertex_group", PROP_BOOLEAN, PROP_NONE);
- RNA_def_property_boolean_sdna(prop, NULL, "flag", MOD_WELD_INVERT_VGROUP);
- RNA_def_property_ui_text(prop, "Invert", "Invert vertex group influence");
- RNA_def_property_update(prop, 0, "rna_Modifier_update");
+ RNA_define_lib_overridable(false);
}
static void rna_def_modifier_datatransfer(BlenderRNA *brna)
@@ -5908,11 +6211,12 @@ static void rna_def_modifier_datatransfer(BlenderRNA *brna)
RNA_def_struct_sdna(srna, "DataTransferModifierData");
RNA_def_struct_ui_icon(srna, ICON_MOD_DATA_TRANSFER);
+ RNA_define_lib_overridable(true);
+
prop = RNA_def_property(srna, "object", PROP_POINTER, PROP_NONE);
RNA_def_property_pointer_sdna(prop, NULL, "ob_source");
RNA_def_property_ui_text(prop, "Source Object", "Object to transfer data from");
RNA_def_property_flag(prop, PROP_EDITABLE | PROP_ID_SELF_CHECK);
- RNA_def_property_override_flag(prop, PROPOVERRIDE_OVERRIDABLE_LIBRARY);
RNA_def_property_pointer_funcs(
prop, NULL, "rna_DataTransferModifier_ob_source_set", NULL, "rna_Mesh_object_poll");
RNA_def_property_update(prop, 0, "rna_Modifier_dependency_update");
@@ -6208,6 +6512,8 @@ static void rna_def_modifier_datatransfer(BlenderRNA *brna)
srna, "invert_vertex_group", false, "Invert", "Invert vertex group influence");
RNA_def_property_boolean_sdna(prop, NULL, "flags", MOD_DATATRANSFER_INVERT_VGROUP);
RNA_def_property_update(prop, 0, "rna_Modifier_update");
+
+ RNA_define_lib_overridable(false);
}
static void rna_def_modifier_normaledit(BlenderRNA *brna)
@@ -6247,6 +6553,8 @@ static void rna_def_modifier_normaledit(BlenderRNA *brna)
RNA_def_struct_sdna(srna, "NormalEditModifierData");
RNA_def_struct_ui_icon(srna, ICON_MOD_NORMALEDIT);
+ RNA_define_lib_overridable(true);
+
prop = RNA_def_property(srna, "mode", PROP_ENUM, PROP_NONE);
RNA_def_property_enum_items(prop, prop_mode_items);
RNA_def_property_ui_text(prop, "Mode", "How to affect (generate) normals");
@@ -6318,7 +6626,6 @@ static void rna_def_modifier_normaledit(BlenderRNA *brna)
RNA_def_property_ui_text(prop, "Target", "Target object used to affect normals");
RNA_def_property_pointer_funcs(prop, NULL, "rna_NormalEditModifier_target_set", NULL, NULL);
RNA_def_property_flag(prop, PROP_EDITABLE | PROP_ID_SELF_CHECK);
- RNA_def_property_override_flag(prop, PROPOVERRIDE_OVERRIDABLE_LIBRARY);
RNA_def_property_update(prop, 0, "rna_Modifier_dependency_update");
prop = RNA_def_property(srna, "use_direction_parallel", PROP_BOOLEAN, PROP_NONE);
@@ -6329,6 +6636,8 @@ static void rna_def_modifier_normaledit(BlenderRNA *brna)
"Use same direction for all normals, from origin to target's center "
"(Directional mode only)");
RNA_def_property_update(prop, 0, "rna_Modifier_update");
+
+ RNA_define_lib_overridable(false);
}
static void rna_def_modifier_surfacedeform(BlenderRNA *brna)
@@ -6341,12 +6650,13 @@ static void rna_def_modifier_surfacedeform(BlenderRNA *brna)
RNA_def_struct_sdna(srna, "SurfaceDeformModifierData");
RNA_def_struct_ui_icon(srna, ICON_MOD_MESHDEFORM);
+ RNA_define_lib_overridable(true);
+
prop = RNA_def_property(srna, "target", PROP_POINTER, PROP_NONE);
RNA_def_property_ui_text(prop, "Target", "Mesh object to deform with");
RNA_def_property_pointer_funcs(
prop, NULL, "rna_SurfaceDeformModifier_target_set", NULL, "rna_Mesh_object_poll");
RNA_def_property_flag(prop, PROP_EDITABLE | PROP_ID_SELF_CHECK);
- RNA_def_property_override_flag(prop, PROPOVERRIDE_OVERRIDABLE_LIBRARY);
RNA_def_property_update(prop, 0, "rna_Modifier_dependency_update");
prop = RNA_def_property(srna, "falloff", PROP_FLOAT, PROP_NONE);
@@ -6359,6 +6669,26 @@ static void rna_def_modifier_surfacedeform(BlenderRNA *brna)
RNA_def_property_boolean_funcs(prop, "rna_SurfaceDeformModifier_is_bound_get", NULL);
RNA_def_property_ui_text(prop, "Bound", "Whether geometry has been bound to target mesh");
RNA_def_property_clear_flag(prop, PROP_EDITABLE);
+
+ prop = RNA_def_property(srna, "vertex_group", PROP_STRING, PROP_NONE);
+ RNA_def_property_string_sdna(prop, NULL, "defgrp_name");
+ RNA_def_property_ui_text(
+ prop, "Vertex Group", "Vertex group name for selecting/weighting the affected areas");
+ RNA_def_property_string_funcs(prop, NULL, NULL, "rna_SurfaceDeformModifier_defgrp_name_set");
+ RNA_def_property_update(prop, 0, "rna_Modifier_update");
+
+ prop = RNA_def_property(srna, "invert_vertex_group", PROP_BOOLEAN, PROP_NONE);
+ RNA_def_property_boolean_sdna(prop, NULL, "flags", MOD_SDEF_INVERT_VGROUP);
+ RNA_def_property_ui_text(prop, "Invert", "Invert vertex group influence");
+ RNA_def_property_update(prop, 0, "rna_Modifier_update");
+
+ prop = RNA_def_property(srna, "strength", PROP_FLOAT, PROP_NONE);
+ RNA_def_property_range(prop, -100, 100);
+ RNA_def_property_ui_range(prop, -100, 100, 10, 2);
+ RNA_def_property_ui_text(prop, "Strength", "Strength of modifier deformations");
+ RNA_def_property_update(prop, 0, "rna_Modifier_update");
+
+ RNA_define_lib_overridable(false);
}
static void rna_def_modifier_weightednormal(BlenderRNA *brna)
@@ -6390,6 +6720,8 @@ static void rna_def_modifier_weightednormal(BlenderRNA *brna)
RNA_def_struct_sdna(srna, "WeightedNormalModifierData");
RNA_def_struct_ui_icon(srna, ICON_MOD_NORMALEDIT);
+ RNA_define_lib_overridable(true);
+
prop = RNA_def_property(srna, "weight", PROP_INT, PROP_NONE);
RNA_def_property_range(prop, 1, 100);
RNA_def_property_ui_range(prop, 1, 100, 1, -1);
@@ -6436,6 +6768,35 @@ static void rna_def_modifier_weightednormal(BlenderRNA *brna)
RNA_def_property_boolean_sdna(prop, NULL, "flag", MOD_WEIGHTEDNORMAL_FACE_INFLUENCE);
RNA_def_property_ui_text(prop, "Face Influence", "Use influence of face for weighting");
RNA_def_property_update(prop, 0, "rna_Modifier_update");
+
+ RNA_define_lib_overridable(false);
+}
+
+static void rna_def_modifier_simulation_access(BlenderRNA *brna)
+{
+ StructRNA *srna;
+ PropertyRNA *prop;
+
+ srna = RNA_def_struct(brna, "SimulationModifier", "Modifier");
+ RNA_def_struct_ui_text(srna, "Simulation Modifier", "");
+ RNA_def_struct_sdna(srna, "SimulationModifierData");
+ RNA_def_struct_ui_icon(srna, ICON_PHYSICS); /* TODO: Use correct icon. */
+
+ RNA_define_lib_overridable(true);
+
+# ifdef WITH_NEW_SIMULATION_TYPE
+ prop = RNA_def_property(srna, "simulation", PROP_POINTER, PROP_NONE);
+ RNA_def_property_ui_text(prop, "Simulation", "Simulation to access");
+ RNA_def_property_flag(prop, PROP_EDITABLE);
+ RNA_def_property_update(prop, 0, "rna_Modifier_dependency_update");
+# endif
+
+ prop = RNA_def_property(srna, "data_path", PROP_STRING, PROP_NONE);
+ RNA_def_property_ui_text(
+ prop, "Data Path", "Identifier of the simulation component that should be accessed");
+ RNA_def_property_update(prop, 0, "rna_Modifier_update");
+
+ RNA_define_lib_overridable(false);
}
void RNA_def_modifier(BlenderRNA *brna)
@@ -6556,13 +6917,14 @@ void RNA_def_modifier(BlenderRNA *brna)
rna_def_modifier_triangulate(brna);
rna_def_modifier_meshcache(brna);
rna_def_modifier_laplaciandeform(brna);
- rna_def_modifier_wireframe(brna);
rna_def_modifier_weld(brna);
+ rna_def_modifier_wireframe(brna);
rna_def_modifier_datatransfer(brna);
rna_def_modifier_normaledit(brna);
rna_def_modifier_meshseqcache(brna);
rna_def_modifier_surfacedeform(brna);
rna_def_modifier_weightednormal(brna);
+ rna_def_modifier_simulation_access(brna);
}
#endif
diff --git a/source/blender/makesrna/intern/rna_nla.c b/source/blender/makesrna/intern/rna_nla.c
index 304cfb49594..b0dda1237b0 100644
--- a/source/blender/makesrna/intern/rna_nla.c
+++ b/source/blender/makesrna/intern/rna_nla.c
@@ -43,7 +43,7 @@
# include <stdio.h>
/* needed for some of the validation stuff... */
-# include "BKE_animsys.h"
+# include "BKE_anim_data.h"
# include "BKE_fcurve.h"
# include "BKE_nla.h"
@@ -382,7 +382,7 @@ static FCurve *rna_NlaStrip_fcurve_find(NlaStrip *strip,
}
/* Returns NULL if not found. */
- return list_find_fcurve(&strip->fcurves, data_path, index);
+ return BKE_fcurve_find(&strip->fcurves, data_path, index);
}
static NlaStrip *rna_NlaStrip_new(ID *id,
diff --git a/source/blender/makesrna/intern/rna_nodetree.c b/source/blender/makesrna/intern/rna_nodetree.c
index 29c36b21b7f..32999c91fad 100644
--- a/source/blender/makesrna/intern/rna_nodetree.c
+++ b/source/blender/makesrna/intern/rna_nodetree.c
@@ -81,6 +81,35 @@ static const EnumPropertyItem node_socket_type_items[] = {
{SOCK_STRING, "STRING", 0, "String", ""},
{SOCK_RGBA, "RGBA", 0, "RGBA", ""},
{SOCK_SHADER, "SHADER", 0, "Shader", ""},
+ {SOCK_OBJECT, "OBJECT", 0, "Object", ""},
+ {SOCK_IMAGE, "IMAGE", 0, "Image", ""},
+ {SOCK_EMITTERS, "EMITTERS", 0, "Emitters", ""},
+ {SOCK_EVENTS, "EVENTS", 0, "Events", ""},
+ {SOCK_FORCES, "FORCES", 0, "Forces", ""},
+ {SOCK_CONTROL_FLOW, "CONTROL_FLOW", 0, "Control Flow", ""},
+ {0, NULL, 0, NULL, NULL},
+};
+
+static const EnumPropertyItem particle_attribute_socket_type_items[] = {
+ {SOCK_FLOAT, "FLOAT", 0, "Float", ""},
+ {SOCK_INT, "INT", 0, "Int", ""},
+ {SOCK_BOOLEAN, "BOOLEAN", 0, "Boolean", ""},
+ {SOCK_VECTOR, "VECTOR", 0, "Vector", ""},
+ {SOCK_RGBA, "RGBA", 0, "Color", ""},
+ {SOCK_OBJECT, "OBJECT", 0, "Object", ""},
+ {SOCK_IMAGE, "IMAGE", 0, "Image", ""},
+ {0, NULL, 0, NULL, NULL},
+};
+
+static const EnumPropertyItem node_socket_data_type_items[] = {
+ {SOCK_FLOAT, "FLOAT", 0, "Float", ""},
+ {SOCK_INT, "INT", 0, "Int", ""},
+ {SOCK_BOOLEAN, "BOOLEAN", 0, "Boolean", ""},
+ {SOCK_VECTOR, "VECTOR", 0, "Vector", ""},
+ {SOCK_STRING, "STRING", 0, "String", ""},
+ {SOCK_RGBA, "RGBA", 0, "Color", ""},
+ {SOCK_OBJECT, "OBJECT", 0, "Object", ""},
+ {SOCK_IMAGE, "IMAGE", 0, "Image", ""},
{0, NULL, 0, NULL, NULL},
};
@@ -174,7 +203,7 @@ const EnumPropertyItem rna_enum_node_math_items[] = {
"Round A to the nearest integer. Round upward if the fraction part is 0.5"},
{NODE_MATH_FLOOR, "FLOOR", 0, "Floor", "The largest integer smaller than or equal A"},
{NODE_MATH_CEIL, "CEIL", 0, "Ceil", "The smallest integer greater than or equal A"},
- {NODE_MATH_TRUNC, "TRUNC", 0, "Truncate", "trunc(A)"},
+ {NODE_MATH_TRUNC, "TRUNC", 0, "Truncate", "The integer part of A, removing fractional digits"},
{0, "", ICON_NONE, NULL, NULL},
{NODE_MATH_FRACTION, "FRACT", 0, "Fraction", "The fraction part of A"},
{NODE_MATH_MODULO, "MODULO", 0, "Modulo", "Modulo using fmod(A,B)"},
@@ -244,6 +273,47 @@ const EnumPropertyItem rna_enum_node_vec_math_items[] = {
{0, NULL, 0, NULL, NULL},
};
+const EnumPropertyItem rna_enum_node_boolean_math_items[] = {
+ {NODE_BOOLEAN_MATH_AND, "AND", 0, "And", "Outputs true only when both inputs are true"},
+ {NODE_BOOLEAN_MATH_OR, "OR", 0, "Or", "Outputs or when at least one of the inputs is true"},
+ {NODE_BOOLEAN_MATH_NOT, "NOT", 0, "Not", "Outputs the opposite of the input"},
+ {0, NULL, 0, NULL, NULL},
+};
+
+const EnumPropertyItem rna_enum_node_float_compare_items[] = {
+ {NODE_FLOAT_COMPARE_LESS_THAN,
+ "LESS_THAN",
+ 0,
+ "A < B",
+ "True when the first input is smaller than second input"},
+ {NODE_FLOAT_COMPARE_LESS_EQUAL,
+ "LESS_EQUAL",
+ 0,
+ "A <= B",
+ "True when the first input is smaller than the second input or equal"},
+ {NODE_FLOAT_COMPARE_GREATER_THAN,
+ "GREATER_THAN",
+ 0,
+ "A > B",
+ "True when the first input is greater than the second input"},
+ {NODE_FLOAT_COMPARE_GREATER_EQUAL,
+ "GREATER_EQUAL",
+ 0,
+ "A >= B",
+ "True when the first input is greater than the second input or equal"},
+ {NODE_FLOAT_COMPARE_EQUAL,
+ "EQUAL",
+ 0,
+ "A = B",
+ "True when both inputs are approximately equal"},
+ {NODE_FLOAT_COMPARE_NOT_EQUAL,
+ "NOT_EQUAL",
+ 0,
+ "A != B",
+ "True when both inputs are not approximately equal"},
+ {0, NULL, 0, NULL, NULL},
+};
+
const EnumPropertyItem rna_enum_node_map_range_items[] = {
{NODE_MAP_RANGE_LINEAR,
"LINEAR",
@@ -669,6 +739,34 @@ static const EnumPropertyItem *rna_node_static_type_itemf(bContext *UNUSED(C),
# undef DefNode
}
+ if (RNA_struct_is_a(ptr->type, &RNA_SimulationNode)) {
+# define DefNode(Category, ID, DefFunc, EnumName, StructName, UIName, UIDesc) \
+ if (STREQ(#Category, "SimulationNode")) { \
+ tmp.value = ID; \
+ tmp.identifier = EnumName; \
+ tmp.name = UIName; \
+ tmp.description = UIDesc; \
+ tmp.icon = ICON_NONE; \
+ RNA_enum_item_add(&item, &totitem, &tmp); \
+ }
+# include "../../nodes/NOD_static_types.h"
+# undef DefNode
+ }
+
+ if (RNA_struct_is_a(ptr->type, &RNA_FunctionNode)) {
+# define DefNode(Category, ID, DefFunc, EnumName, StructName, UIName, UIDesc) \
+ if (STREQ(#Category, "FunctionNode")) { \
+ tmp.value = ID; \
+ tmp.identifier = EnumName; \
+ tmp.name = UIName; \
+ tmp.description = UIDesc; \
+ tmp.icon = ICON_NONE; \
+ RNA_enum_item_add(&item, &totitem, &tmp); \
+ }
+# include "../../nodes/NOD_static_types.h"
+# undef DefNode
+ }
+
RNA_enum_item_end(&item, &totitem);
*r_free = true;
@@ -681,8 +779,8 @@ static StructRNA *rna_NodeTree_refine(struct PointerRNA *ptr)
{
bNodeTree *ntree = (bNodeTree *)ptr->data;
- if (ntree->typeinfo->ext.srna) {
- return ntree->typeinfo->ext.srna;
+ if (ntree->typeinfo->rna_ext.srna) {
+ return ntree->typeinfo->rna_ext.srna;
}
else {
return &RNA_NodeTree;
@@ -699,12 +797,12 @@ static bool rna_NodeTree_poll(const bContext *C, bNodeTreeType *ntreetype)
void *ret;
bool visible;
- RNA_pointer_create(NULL, ntreetype->ext.srna, NULL, &ptr); /* dummy */
+ RNA_pointer_create(NULL, ntreetype->rna_ext.srna, NULL, &ptr); /* dummy */
func = &rna_NodeTree_poll_func; /* RNA_struct_find_function(&ptr, "poll"); */
RNA_parameter_list_create(&list, &ptr, func);
RNA_parameter_set_lookup(&list, "context", &C);
- ntreetype->ext.call((bContext *)C, &ptr, func, &list);
+ ntreetype->rna_ext.call((bContext *)C, &ptr, func, &list);
RNA_parameter_get_lookup(&list, "visible", &ret);
visible = *(bool *)ret;
@@ -726,7 +824,7 @@ static void rna_NodeTree_update_reg(bNodeTree *ntree)
func = &rna_NodeTree_update_func; /* RNA_struct_find_function(&ptr, "update"); */
RNA_parameter_list_create(&list, &ptr, func);
- ntree->typeinfo->ext.call(NULL, &ptr, func, &list);
+ ntree->typeinfo->rna_ext.call(NULL, &ptr, func, &list);
RNA_parameter_list_free(&list);
}
@@ -741,13 +839,13 @@ static void rna_NodeTree_get_from_context(
FunctionRNA *func;
void *ret1, *ret2, *ret3;
- RNA_pointer_create(NULL, ntreetype->ext.srna, NULL, &ptr); /* dummy */
+ RNA_pointer_create(NULL, ntreetype->rna_ext.srna, NULL, &ptr); /* dummy */
/* RNA_struct_find_function(&ptr, "get_from_context"); */
func = &rna_NodeTree_get_from_context_func;
RNA_parameter_list_create(&list, &ptr, func);
RNA_parameter_set_lookup(&list, "context", &C);
- ntreetype->ext.call((bContext *)C, &ptr, func, &list);
+ ntreetype->rna_ext.call((bContext *)C, &ptr, func, &list);
RNA_parameter_get_lookup(&list, "result_1", &ret1);
RNA_parameter_get_lookup(&list, "result_2", &ret2);
@@ -767,7 +865,7 @@ static void rna_NodeTree_unregister(Main *UNUSED(bmain), StructRNA *type)
return;
}
- RNA_struct_free_extension(type, &nt->ext);
+ RNA_struct_free_extension(type, &nt->rna_ext);
RNA_struct_free(&BLENDER_RNA, type);
ntreeTypeFreeLink(nt);
@@ -812,7 +910,7 @@ static StructRNA *rna_NodeTree_register(Main *bmain,
/* check if we have registered this tree type before, and remove it */
nt = ntreeTypeFind(dummynt.idname);
if (nt) {
- rna_NodeTree_unregister(bmain, nt->ext.srna);
+ rna_NodeTree_unregister(bmain, nt->rna_ext.srna);
}
/* create a new node tree type */
@@ -821,14 +919,14 @@ static StructRNA *rna_NodeTree_register(Main *bmain,
nt->type = NTREE_CUSTOM;
- nt->ext.srna = RNA_def_struct_ptr(&BLENDER_RNA, nt->idname, &RNA_NodeTree);
- nt->ext.data = data;
- nt->ext.call = call;
- nt->ext.free = free;
- RNA_struct_blender_type_set(nt->ext.srna, nt);
+ nt->rna_ext.srna = RNA_def_struct_ptr(&BLENDER_RNA, nt->idname, &RNA_NodeTree);
+ nt->rna_ext.data = data;
+ nt->rna_ext.call = call;
+ nt->rna_ext.free = free;
+ RNA_struct_blender_type_set(nt->rna_ext.srna, nt);
- RNA_def_struct_ui_text(nt->ext.srna, nt->ui_name, nt->ui_description);
- RNA_def_struct_ui_icon(nt->ext.srna, nt->ui_icon);
+ RNA_def_struct_ui_text(nt->rna_ext.srna, nt->ui_name, nt->ui_description);
+ RNA_def_struct_ui_icon(nt->rna_ext.srna, nt->ui_icon);
nt->poll = (have_function[0]) ? rna_NodeTree_poll : NULL;
nt->update = (have_function[1]) ? rna_NodeTree_update_reg : NULL;
@@ -839,7 +937,7 @@ static StructRNA *rna_NodeTree_register(Main *bmain,
/* update while blender is running */
WM_main_add_notifier(NC_NODE | NA_EDITED, NULL);
- return nt->ext.srna;
+ return nt->rna_ext.srna;
}
static bool rna_NodeTree_check(bNodeTree *ntree, ReportList *reports)
@@ -862,12 +960,11 @@ static bool rna_NodeTree_check(bNodeTree *ntree, ReportList *reports)
static void rna_NodeTree_update(Main *bmain, Scene *UNUSED(scene), PointerRNA *ptr)
{
bNodeTree *ntree = (bNodeTree *)ptr->owner_id;
- bNode *node = (bNode *)ptr->data;
WM_main_add_notifier(NC_NODE | NA_EDITED, NULL);
WM_main_add_notifier(NC_SCENE | ND_NODES, &ntree->id);
- ED_node_tag_update_nodetree(bmain, ntree, node);
+ ED_node_tag_update_nodetree(bmain, ntree, NULL);
}
static bNode *rna_NodeTree_node_new(bNodeTree *ntree,
@@ -1323,8 +1420,8 @@ static StructRNA *rna_Node_refine(struct PointerRNA *ptr)
{
bNode *node = (bNode *)ptr->data;
- if (node->typeinfo->ext.srna) {
- return node->typeinfo->ext.srna;
+ if (node->typeinfo->rna_ext.srna) {
+ return node->typeinfo->rna_ext.srna;
}
else {
return ptr->type;
@@ -1380,12 +1477,12 @@ static bool rna_Node_poll(bNodeType *ntype, bNodeTree *ntree)
void *ret;
bool visible;
- RNA_pointer_create(NULL, ntype->ext.srna, NULL, &ptr); /* dummy */
+ RNA_pointer_create(NULL, ntype->rna_ext.srna, NULL, &ptr); /* dummy */
func = &rna_Node_poll_func; /* RNA_struct_find_function(&ptr, "poll"); */
RNA_parameter_list_create(&list, &ptr, func);
RNA_parameter_set_lookup(&list, "node_tree", &ntree);
- ntype->ext.call(NULL, &ptr, func, &list);
+ ntype->rna_ext.call(NULL, &ptr, func, &list);
RNA_parameter_get_lookup(&list, "visible", &ret);
visible = *(bool *)ret;
@@ -1405,12 +1502,12 @@ static bool rna_Node_poll_instance(bNode *node, bNodeTree *ntree)
void *ret;
bool visible;
- RNA_pointer_create(NULL, node->typeinfo->ext.srna, node, &ptr); /* dummy */
+ RNA_pointer_create(NULL, node->typeinfo->rna_ext.srna, node, &ptr); /* dummy */
func = &rna_Node_poll_instance_func; /* RNA_struct_find_function(&ptr, "poll_instance"); */
RNA_parameter_list_create(&list, &ptr, func);
RNA_parameter_set_lookup(&list, "node_tree", &ntree);
- node->typeinfo->ext.call(NULL, &ptr, func, &list);
+ node->typeinfo->rna_ext.call(NULL, &ptr, func, &list);
RNA_parameter_get_lookup(&list, "visible", &ret);
visible = *(bool *)ret;
@@ -1434,11 +1531,11 @@ static void rna_Node_update_reg(bNodeTree *ntree, bNode *node)
ParameterList list;
FunctionRNA *func;
- RNA_pointer_create((ID *)ntree, node->typeinfo->ext.srna, node, &ptr);
+ RNA_pointer_create((ID *)ntree, node->typeinfo->rna_ext.srna, node, &ptr);
func = &rna_Node_update_func; /* RNA_struct_find_function(&ptr, "update"); */
RNA_parameter_list_create(&list, &ptr, func);
- node->typeinfo->ext.call(NULL, &ptr, func, &list);
+ node->typeinfo->rna_ext.call(NULL, &ptr, func, &list);
RNA_parameter_list_free(&list);
}
@@ -1451,12 +1548,12 @@ static void rna_Node_insert_link(bNodeTree *ntree, bNode *node, bNodeLink *link)
ParameterList list;
FunctionRNA *func;
- RNA_pointer_create((ID *)ntree, node->typeinfo->ext.srna, node, &ptr);
+ RNA_pointer_create((ID *)ntree, node->typeinfo->rna_ext.srna, node, &ptr);
func = &rna_Node_insert_link_func;
RNA_parameter_list_create(&list, &ptr, func);
RNA_parameter_set_lookup(&list, "link", &link);
- node->typeinfo->ext.call(NULL, &ptr, func, &list);
+ node->typeinfo->rna_ext.call(NULL, &ptr, func, &list);
RNA_parameter_list_free(&list);
}
@@ -1472,7 +1569,7 @@ static void rna_Node_init(const bContext *C, PointerRNA *ptr)
func = &rna_Node_init_func; /* RNA_struct_find_function(&ptr, "init"); */
RNA_parameter_list_create(&list, ptr, func);
- node->typeinfo->ext.call((bContext *)C, ptr, func, &list);
+ node->typeinfo->rna_ext.call((bContext *)C, ptr, func, &list);
RNA_parameter_list_free(&list);
}
@@ -1489,7 +1586,7 @@ static void rna_Node_copy(PointerRNA *ptr, const struct bNode *copynode)
RNA_parameter_list_create(&list, ptr, func);
RNA_parameter_set_lookup(&list, "node", &copynode);
- node->typeinfo->ext.call(NULL, ptr, func, &list);
+ node->typeinfo->rna_ext.call(NULL, ptr, func, &list);
RNA_parameter_list_free(&list);
}
@@ -1505,7 +1602,7 @@ static void rna_Node_free(PointerRNA *ptr)
func = &rna_Node_free_func; /* RNA_struct_find_function(&ptr, "free"); */
RNA_parameter_list_create(&list, ptr, func);
- node->typeinfo->ext.call(NULL, ptr, func, &list);
+ node->typeinfo->rna_ext.call(NULL, ptr, func, &list);
RNA_parameter_list_free(&list);
}
@@ -1523,7 +1620,7 @@ static void rna_Node_draw_buttons(struct uiLayout *layout, bContext *C, PointerR
RNA_parameter_list_create(&list, ptr, func);
RNA_parameter_set_lookup(&list, "context", &C);
RNA_parameter_set_lookup(&list, "layout", &layout);
- node->typeinfo->ext.call(C, ptr, func, &list);
+ node->typeinfo->rna_ext.call(C, ptr, func, &list);
RNA_parameter_list_free(&list);
}
@@ -1541,7 +1638,7 @@ static void rna_Node_draw_buttons_ext(struct uiLayout *layout, bContext *C, Poin
RNA_parameter_list_create(&list, ptr, func);
RNA_parameter_set_lookup(&list, "context", &C);
RNA_parameter_set_lookup(&list, "layout", &layout);
- node->typeinfo->ext.call(C, ptr, func, &list);
+ node->typeinfo->rna_ext.call(C, ptr, func, &list);
RNA_parameter_list_free(&list);
}
@@ -1560,7 +1657,7 @@ static void rna_Node_draw_label(bNodeTree *ntree, bNode *node, char *label, int
RNA_pointer_create(&ntree->id, &RNA_Node, node, &ptr);
RNA_parameter_list_create(&list, &ptr, func);
- node->typeinfo->ext.call(NULL, &ptr, func, &list);
+ node->typeinfo->rna_ext.call(NULL, &ptr, func, &list);
RNA_parameter_get_lookup(&list, "label", &ret);
rlabel = (char *)ret;
@@ -1591,7 +1688,7 @@ static void rna_Node_unregister(Main *UNUSED(bmain), StructRNA *type)
return;
}
- RNA_struct_free_extension(type, &nt->ext);
+ RNA_struct_free_extension(type, &nt->rna_ext);
RNA_struct_free(&BLENDER_RNA, type);
/* this also frees the allocated nt pointer, no MEM_free call needed! */
@@ -1646,7 +1743,7 @@ static bNodeType *rna_Node_register_base(Main *bmain,
/* check if we have registered this node type before, and remove it */
nt = nodeTypeFind(dummynt.idname);
if (nt) {
- rna_Node_unregister(bmain, nt->ext.srna);
+ rna_Node_unregister(bmain, nt->rna_ext.srna);
}
/* create a new node type */
@@ -1654,17 +1751,17 @@ static bNodeType *rna_Node_register_base(Main *bmain,
memcpy(nt, &dummynt, sizeof(dummynt));
nt->free_self = (void (*)(bNodeType *))MEM_freeN;
- nt->ext.srna = RNA_def_struct_ptr(&BLENDER_RNA, nt->idname, basetype);
- nt->ext.data = data;
- nt->ext.call = call;
- nt->ext.free = free;
- RNA_struct_blender_type_set(nt->ext.srna, nt);
+ nt->rna_ext.srna = RNA_def_struct_ptr(&BLENDER_RNA, nt->idname, basetype);
+ nt->rna_ext.data = data;
+ nt->rna_ext.call = call;
+ nt->rna_ext.free = free;
+ RNA_struct_blender_type_set(nt->rna_ext.srna, nt);
- RNA_def_struct_ui_text(nt->ext.srna, nt->ui_name, nt->ui_description);
- RNA_def_struct_ui_icon(nt->ext.srna, nt->ui_icon);
+ RNA_def_struct_ui_text(nt->rna_ext.srna, nt->ui_name, nt->ui_description);
+ RNA_def_struct_ui_icon(nt->rna_ext.srna, nt->ui_icon);
func = RNA_def_function_runtime(
- nt->ext.srna, "is_registered_node_type", rna_Node_is_registered_node_type_runtime);
+ nt->rna_ext.srna, "is_registered_node_type", rna_Node_is_registered_node_type_runtime);
RNA_def_function_ui_description(func, "True if a registered node type");
RNA_def_function_flag(func, FUNC_NO_SELF | FUNC_USE_SELF_TYPE);
parm = RNA_def_boolean(func, "result", false, "Result", "");
@@ -1716,7 +1813,7 @@ static StructRNA *rna_Node_register(Main *bmain,
/* update while blender is running */
WM_main_add_notifier(NC_NODE | NA_EDITED, NULL);
- return nt->ext.srna;
+ return nt->rna_ext.srna;
}
static StructRNA *rna_ShaderNode_register(Main *bmain,
@@ -1738,7 +1835,7 @@ static StructRNA *rna_ShaderNode_register(Main *bmain,
/* update while blender is running */
WM_main_add_notifier(NC_NODE | NA_EDITED, NULL);
- return nt->ext.srna;
+ return nt->rna_ext.srna;
}
static StructRNA *rna_CompositorNode_register(Main *bmain,
@@ -1760,7 +1857,7 @@ static StructRNA *rna_CompositorNode_register(Main *bmain,
/* update while blender is running */
WM_main_add_notifier(NC_NODE | NA_EDITED, NULL);
- return nt->ext.srna;
+ return nt->rna_ext.srna;
}
static StructRNA *rna_TextureNode_register(Main *bmain,
@@ -1782,7 +1879,51 @@ static StructRNA *rna_TextureNode_register(Main *bmain,
/* update while blender is running */
WM_main_add_notifier(NC_NODE | NA_EDITED, NULL);
- return nt->ext.srna;
+ return nt->rna_ext.srna;
+}
+
+static StructRNA *rna_SimulationNode_register(Main *bmain,
+ ReportList *reports,
+ void *data,
+ const char *identifier,
+ StructValidateFunc validate,
+ StructCallbackFunc call,
+ StructFreeFunc free)
+{
+ bNodeType *nt = rna_Node_register_base(
+ bmain, reports, &RNA_SimulationNode, data, identifier, validate, call, free);
+ if (!nt) {
+ return NULL;
+ }
+
+ nodeRegisterType(nt);
+
+ /* update while blender is running */
+ WM_main_add_notifier(NC_NODE | NA_EDITED, NULL);
+
+ return nt->rna_ext.srna;
+}
+
+static StructRNA *rna_FunctionNode_register(Main *bmain,
+ ReportList *reports,
+ void *data,
+ const char *identifier,
+ StructValidateFunc validate,
+ StructCallbackFunc call,
+ StructFreeFunc free)
+{
+ bNodeType *nt = rna_Node_register_base(
+ bmain, reports, &RNA_FunctionNode, data, identifier, validate, call, free);
+ if (!nt) {
+ return NULL;
+ }
+
+ nodeRegisterType(nt);
+
+ /* update while blender is running */
+ WM_main_add_notifier(NC_NODE | NA_EDITED, NULL);
+
+ return nt->rna_ext.srna;
}
static IDProperty *rna_Node_idprops(PointerRNA *ptr, bool create)
@@ -1893,6 +2034,11 @@ static bNodeSocket *rna_Node_inputs_new(ID *id,
const char *name,
const char *identifier)
{
+
+ if (ELEM(node->type, NODE_GROUP_INPUT, NODE_FRAME)) {
+ BKE_report(reports, RPT_ERROR, "Unable to create socket");
+ return NULL;
+ }
/* Adding an input to a group node is not working,
* simpler to add it to its underlying nodetree. */
if (ELEM(node->type, NODE_GROUP, NODE_CUSTOM_GROUP) && node->id != NULL) {
@@ -1923,6 +2069,10 @@ static bNodeSocket *rna_Node_outputs_new(ID *id,
const char *name,
const char *identifier)
{
+ if (ELEM(node->type, NODE_GROUP_OUTPUT, NODE_FRAME)) {
+ BKE_report(reports, RPT_ERROR, "Unable to create socket");
+ return NULL;
+ }
/* Adding an output to a group node is not working,
* simpler to add it to its underlying nodetree. */
if (ELEM(node->type, NODE_GROUP, NODE_CUSTOM_GROUP) && node->id != NULL) {
@@ -2845,7 +2995,7 @@ static StructRNA *rna_NodeCustomGroup_register(Main *bmain,
/* update while blender is running */
WM_main_add_notifier(NC_NODE | NA_EDITED, NULL);
- return nt->ext.srna;
+ return nt->rna_ext.srna;
}
static StructRNA *rna_ShaderNodeCustomGroup_register(Main *bmain,
@@ -2872,7 +3022,7 @@ static StructRNA *rna_ShaderNodeCustomGroup_register(Main *bmain,
WM_main_add_notifier(NC_NODE | NA_EDITED, NULL);
- return nt->ext.srna;
+ return nt->rna_ext.srna;
}
static StructRNA *rna_CompositorNodeCustomGroup_register(Main *bmain,
@@ -2898,7 +3048,7 @@ static StructRNA *rna_CompositorNodeCustomGroup_register(Main *bmain,
WM_main_add_notifier(NC_NODE | NA_EDITED, NULL);
- return nt->ext.srna;
+ return nt->rna_ext.srna;
}
static void rna_CompositorNode_tag_need_exec(bNode *node)
@@ -3581,6 +3731,15 @@ static void rna_ShaderNode_socket_update(Main *bmain, Scene *scene, PointerRNA *
rna_Node_update(bmain, scene, ptr);
}
+static void rna_FunctionNode_socket_update(Main *bmain, Scene *scene, PointerRNA *ptr)
+{
+ bNodeTree *ntree = (bNodeTree *)ptr->owner_id;
+ bNode *node = (bNode *)ptr->data;
+
+ nodeUpdate(ntree, node);
+ rna_Node_update(bmain, scene, ptr);
+}
+
static void rna_CompositorNodeScale_update(Main *bmain, Scene *scene, PointerRNA *ptr)
{
bNodeTree *ntree = (bNodeTree *)ptr->owner_id;
@@ -3590,6 +3749,15 @@ static void rna_CompositorNodeScale_update(Main *bmain, Scene *scene, PointerRNA
rna_Node_update(bmain, scene, ptr);
}
+static void rna_SimulationNode_socket_update(Main *bmain, Scene *scene, PointerRNA *ptr)
+{
+ bNodeTree *ntree = (bNodeTree *)ptr->owner_id;
+ bNode *node = (bNode *)ptr->data;
+
+ nodeUpdate(ntree, node);
+ rna_Node_update(bmain, scene, ptr);
+}
+
static PointerRNA rna_ShaderNodePointDensity_psys_get(PointerRNA *ptr)
{
bNode *node = ptr->data;
@@ -4016,6 +4184,39 @@ static void def_math(StructRNA *srna)
RNA_def_property_update(prop, NC_NODE | NA_EDITED, "rna_Node_update");
}
+static void def_boolean_math(StructRNA *srna)
+{
+ PropertyRNA *prop;
+
+ prop = RNA_def_property(srna, "operation", PROP_ENUM, PROP_NONE);
+ RNA_def_property_enum_sdna(prop, NULL, "custom1");
+ RNA_def_property_enum_items(prop, rna_enum_node_boolean_math_items);
+ RNA_def_property_ui_text(prop, "Operation", "");
+ RNA_def_property_update(prop, NC_NODE | NA_EDITED, "rna_FunctionNode_socket_update");
+}
+
+static void def_float_compare(StructRNA *srna)
+{
+ PropertyRNA *prop;
+
+ prop = RNA_def_property(srna, "operation", PROP_ENUM, PROP_NONE);
+ RNA_def_property_enum_sdna(prop, NULL, "custom1");
+ RNA_def_property_enum_items(prop, rna_enum_node_float_compare_items);
+ RNA_def_property_ui_text(prop, "Operation", "");
+ RNA_def_property_update(prop, NC_NODE | NA_EDITED, "rna_FunctionNode_socket_update");
+}
+
+static void def_fn_switch(StructRNA *srna)
+{
+ PropertyRNA *prop;
+
+ prop = RNA_def_property(srna, "data_type", PROP_ENUM, PROP_NONE);
+ RNA_def_property_enum_sdna(prop, NULL, "custom1");
+ RNA_def_property_enum_items(prop, node_socket_data_type_items);
+ RNA_def_property_ui_text(prop, "Data Type", "Data type for inputs and outputs");
+ RNA_def_property_update(prop, NC_NODE | NA_EDITED, "rna_FunctionNode_socket_update");
+}
+
static void def_vector_math(StructRNA *srna)
{
PropertyRNA *prop;
@@ -7899,6 +8100,82 @@ static void def_tex_bricks(StructRNA *srna)
RNA_def_property_update(prop, NC_NODE | NA_EDITED, "rna_Node_update");
}
+/* -- Simulation Nodes --------------------------------------------------------- */
+
+static void def_sim_particle_time_step_event(StructRNA *srna)
+{
+ static const EnumPropertyItem mode_items[] = {
+ {NODE_PARTICLE_TIME_STEP_EVENT_BEGIN,
+ "BEGIN",
+ 0,
+ "Begin",
+ "Execute for every particle at the beginning of each time step"},
+ {NODE_PARTICLE_TIME_STEP_EVENT_END,
+ "END",
+ 0,
+ "End",
+ "Execute for every particle at the end of each time step"},
+ {0, NULL, 0, NULL, NULL},
+ };
+
+ PropertyRNA *prop;
+
+ prop = RNA_def_property(srna, "mode", PROP_ENUM, PROP_NONE);
+ RNA_def_property_enum_sdna(prop, NULL, "custom1");
+ RNA_def_property_enum_items(prop, mode_items);
+ RNA_def_property_ui_text(prop, "Mode", "When in each time step is the event triggered");
+ RNA_def_property_update(prop, NC_NODE | NA_EDITED, "rna_Node_update");
+}
+
+static void def_sim_particle_attribute(StructRNA *srna)
+{
+ PropertyRNA *prop;
+
+ prop = RNA_def_property(srna, "data_type", PROP_ENUM, PROP_NONE);
+ RNA_def_property_enum_sdna(prop, NULL, "custom1");
+ RNA_def_property_enum_items(prop, particle_attribute_socket_type_items);
+ RNA_def_property_ui_text(
+ prop,
+ "Data Type",
+ "Expected type of the attribute. A default value is returned if the type is not correct");
+ RNA_def_property_update(prop, NC_NODE | NA_EDITED, "rna_SimulationNode_socket_update");
+}
+
+static void def_sim_set_particle_attribute(StructRNA *srna)
+{
+ PropertyRNA *prop;
+
+ prop = RNA_def_property(srna, "data_type", PROP_ENUM, PROP_NONE);
+ RNA_def_property_enum_sdna(prop, NULL, "custom1");
+ RNA_def_property_enum_items(prop, particle_attribute_socket_type_items);
+ RNA_def_property_ui_text(
+ prop,
+ "Data Type",
+ "Expected type of the attribute. Nothing is done if the type is not correct");
+ RNA_def_property_update(prop, NC_NODE | NA_EDITED, "rna_SimulationNode_socket_update");
+}
+
+static void def_sim_time(StructRNA *srna)
+{
+ static const EnumPropertyItem mode_items[] = {
+ {NODE_SIM_INPUT_SIMULATION_TIME,
+ "SIMULATION_TIME",
+ 0,
+ "Simulation Time",
+ "Time since start of simulation"},
+ {NODE_SIM_INPUT_SCENE_TIME, "SCENE_TIME", 0, "Scene Time", "Time shown in the timeline"},
+ {0, NULL, 0, NULL, NULL},
+ };
+
+ PropertyRNA *prop;
+
+ prop = RNA_def_property(srna, "mode", PROP_ENUM, PROP_NONE);
+ RNA_def_property_enum_sdna(prop, NULL, "custom1");
+ RNA_def_property_enum_items(prop, mode_items);
+ RNA_def_property_ui_text(prop, "Mode", "The time to output");
+ RNA_def_property_update(prop, NC_NODE | NA_EDITED, "rna_SimulationNode_socket_update");
+}
+
/* -------------------------------------------------------------------------- */
static void rna_def_shader_node(BlenderRNA *brna)
@@ -7936,6 +8213,26 @@ static void rna_def_texture_node(BlenderRNA *brna)
RNA_def_struct_register_funcs(srna, "rna_TextureNode_register", "rna_Node_unregister", NULL);
}
+static void rna_def_simulation_node(BlenderRNA *brna)
+{
+ StructRNA *srna;
+
+ srna = RNA_def_struct(brna, "SimulationNode", "NodeInternal");
+ RNA_def_struct_ui_text(srna, "Simulation Node", "");
+ RNA_def_struct_sdna(srna, "bNode");
+ RNA_def_struct_register_funcs(srna, "rna_SimulationNode_register", "rna_Node_unregister", NULL);
+}
+
+static void rna_def_function_node(BlenderRNA *brna)
+{
+ StructRNA *srna;
+
+ srna = RNA_def_struct(brna, "FunctionNode", "NodeInternal");
+ RNA_def_struct_ui_text(srna, "Function Node", "");
+ RNA_def_struct_sdna(srna, "bNode");
+ RNA_def_struct_register_funcs(srna, "rna_FunctionNode_register", "rna_Node_unregister", NULL);
+}
+
/* -------------------------------------------------------------------------- */
static void rna_def_node_socket(BlenderRNA *brna)
@@ -8492,6 +8789,104 @@ static void rna_def_node_socket_virtual(BlenderRNA *brna, const char *identifier
RNA_def_struct_sdna(srna, "bNodeSocket");
}
+static void rna_def_node_socket_object(BlenderRNA *brna,
+ const char *identifier,
+ const char *interface_idname)
+{
+ StructRNA *srna;
+ PropertyRNA *prop;
+
+ srna = RNA_def_struct(brna, identifier, "NodeSocketStandard");
+ RNA_def_struct_ui_text(srna, "Object Node Socket", "Object socket of a node");
+ RNA_def_struct_sdna(srna, "bNodeSocket");
+
+ RNA_def_struct_sdna_from(srna, "bNodeSocketValueObject", "default_value");
+
+ prop = RNA_def_property(srna, "default_value", PROP_POINTER, PROP_NONE);
+ RNA_def_property_pointer_sdna(prop, NULL, "value");
+ RNA_def_property_struct_type(prop, "Object");
+ RNA_def_property_ui_text(prop, "Default Value", "Input value used for unconnected socket");
+ RNA_def_property_update(prop, NC_NODE | NA_EDITED, "rna_NodeSocketStandard_value_update");
+ RNA_def_property_flag(prop, PROP_EDITABLE | PROP_ID_REFCOUNT | PROP_CONTEXT_UPDATE);
+
+ /* socket interface */
+ srna = RNA_def_struct(brna, interface_idname, "NodeSocketInterfaceStandard");
+ RNA_def_struct_ui_text(srna, "Object Node Socket Interface", "Object socket of a node");
+ RNA_def_struct_sdna(srna, "bNodeSocket");
+
+ RNA_def_struct_sdna_from(srna, "bNodeSocketValueObject", "default_value");
+
+ prop = RNA_def_property(srna, "default_value", PROP_POINTER, PROP_NONE);
+ RNA_def_property_pointer_sdna(prop, NULL, "value");
+ RNA_def_property_struct_type(prop, "Object");
+ RNA_def_property_ui_text(prop, "Default Value", "Input value used for unconnected socket");
+ RNA_def_property_update(prop, NC_NODE | NA_EDITED, "rna_NodeSocketInterface_update");
+}
+
+static void rna_def_node_socket_image(BlenderRNA *brna,
+ const char *identifier,
+ const char *interface_idname)
+{
+ StructRNA *srna;
+ PropertyRNA *prop;
+
+ srna = RNA_def_struct(brna, identifier, "NodeSocketStandard");
+ RNA_def_struct_ui_text(srna, "Image Node Socket", "Image socket of a node");
+ RNA_def_struct_sdna(srna, "bNodeSocket");
+
+ RNA_def_struct_sdna_from(srna, "bNodeSocketValueImage", "default_value");
+
+ prop = RNA_def_property(srna, "default_value", PROP_POINTER, PROP_NONE);
+ RNA_def_property_pointer_sdna(prop, NULL, "value");
+ RNA_def_property_struct_type(prop, "Image");
+ RNA_def_property_ui_text(prop, "Default Value", "Input value used for unconnected socket");
+ RNA_def_property_update(prop, NC_NODE | NA_EDITED, "rna_NodeSocketStandard_value_update");
+ RNA_def_property_flag(prop, PROP_EDITABLE | PROP_ID_REFCOUNT | PROP_CONTEXT_UPDATE);
+
+ /* socket interface */
+ srna = RNA_def_struct(brna, interface_idname, "NodeSocketInterfaceStandard");
+ RNA_def_struct_ui_text(srna, "Image Node Socket Interface", "Image socket of a node");
+ RNA_def_struct_sdna(srna, "bNodeSocket");
+
+ RNA_def_struct_sdna_from(srna, "bNodeSocketValueImage", "default_value");
+
+ prop = RNA_def_property(srna, "default_value", PROP_POINTER, PROP_NONE);
+ RNA_def_property_pointer_sdna(prop, NULL, "value");
+ RNA_def_property_struct_type(prop, "Image");
+ RNA_def_property_ui_text(prop, "Default Value", "Input value used for unconnected socket");
+ RNA_def_property_update(prop, NC_NODE | NA_EDITED, "rna_NodeSocketInterface_update");
+}
+
+static void rna_def_node_socket_effector(BlenderRNA *brna,
+ const char *identifier,
+ const char *interface_idname)
+{
+ StructRNA *srna;
+
+ srna = RNA_def_struct(brna, identifier, "NodeSocketStandard");
+ RNA_def_struct_ui_text(srna, "", "");
+ RNA_def_struct_sdna(srna, "bNodeSocket");
+
+ srna = RNA_def_struct(brna, interface_idname, "NodeSocketInterfaceStandard");
+ RNA_def_struct_ui_text(srna, "", "");
+ RNA_def_struct_sdna(srna, "bNodeSocket");
+}
+
+static void rna_def_node_socket_control_flow(BlenderRNA *brna,
+ const char *identifier,
+ const char *interface_idname)
+{
+ StructRNA *srna;
+
+ srna = RNA_def_struct(brna, identifier, "NodeSocketStandard");
+ RNA_def_struct_ui_text(srna, "", "");
+ RNA_def_struct_sdna(srna, "bNodeSocket");
+
+ srna = RNA_def_struct(brna, interface_idname, "NodeSocketInterfaceStandard");
+ RNA_def_struct_ui_text(srna, "", "");
+ RNA_def_struct_sdna(srna, "bNodeSocket");
+}
+
static void rna_def_node_socket_standard_types(BlenderRNA *brna)
{
/* XXX Workaround: Registered functions are not exposed in python by bpy,
@@ -8626,6 +9021,17 @@ static void rna_def_node_socket_standard_types(BlenderRNA *brna)
rna_def_node_socket_shader(brna, "NodeSocketShader", "NodeSocketInterfaceShader");
rna_def_node_socket_virtual(brna, "NodeSocketVirtual");
+
+ rna_def_node_socket_object(brna, "NodeSocketObject", "NodeSocketInterfaceObject");
+
+ rna_def_node_socket_image(brna, "NodeSocketImage", "NodeSocketInterfaceImage");
+
+ rna_def_node_socket_effector(brna, "NodeSocketEmitters", "NodeSocketInterfaceEmitters");
+ rna_def_node_socket_effector(brna, "NodeSocketEvents", "NodeSocketInterfaceEvents");
+ rna_def_node_socket_effector(brna, "NodeSocketForces", "NodeSocketInterfaceForces");
+
+ rna_def_node_socket_control_flow(
+ brna, "NodeSocketControlFlow", "NodeSocketInterfaceControlFlow");
}
static void rna_def_internal_node(BlenderRNA *brna)
@@ -9251,6 +9657,7 @@ static void rna_def_nodetree(BlenderRNA *brna)
{NTREE_SHADER, "SHADER", ICON_MATERIAL, "Shader", "Shader nodes"},
{NTREE_TEXTURE, "TEXTURE", ICON_TEXTURE, "Texture", "Texture nodes"},
{NTREE_COMPOSIT, "COMPOSITING", ICON_RENDERLAYERS, "Compositing", "Compositing nodes"},
+ {NTREE_SIMULATION, "SIMULATION", ICON_PHYSICS, "Simulation", "Simulation nodes"},
{0, NULL, 0, NULL, NULL},
};
@@ -9474,6 +9881,17 @@ static void rna_def_texture_nodetree(BlenderRNA *brna)
RNA_def_struct_ui_icon(srna, ICON_TEXTURE);
}
+static void rna_def_simulation_nodetree(BlenderRNA *brna)
+{
+ StructRNA *srna;
+
+ srna = RNA_def_struct(brna, "SimulationNodeTree", "NodeTree");
+ RNA_def_struct_ui_text(
+ srna, "Simulation Node Tree", "Node tree consisting of linked nodes used for simulations");
+ RNA_def_struct_sdna(srna, "bNodeTree");
+ RNA_def_struct_ui_icon(srna, ICON_PHYSICS); /* TODO: Use correct icon. */
+}
+
static StructRNA *define_specific_node(BlenderRNA *brna,
const char *struct_name,
const char *base_name,
@@ -9560,6 +9978,8 @@ void RNA_def_nodetree(BlenderRNA *brna)
rna_def_shader_node(brna);
rna_def_compositor_node(brna);
rna_def_texture_node(brna);
+ rna_def_simulation_node(brna);
+ rna_def_function_node(brna);
rna_def_nodetree(brna);
@@ -9568,6 +9988,7 @@ void RNA_def_nodetree(BlenderRNA *brna)
rna_def_composite_nodetree(brna);
rna_def_shader_nodetree(brna);
rna_def_texture_nodetree(brna);
+ rna_def_simulation_nodetree(brna);
# define DefNode(Category, ID, DefFunc, EnumName, StructName, UIName, UIDesc) \
{ \
@@ -9584,12 +10005,13 @@ void RNA_def_nodetree(BlenderRNA *brna)
*/
# include "../../nodes/NOD_static_types.h"
- /* Node group types need to be defined for shader, compositor, texture nodes individually.
- * Cannot use the static types header for this, since they share the same int id.
+ /* Node group types need to be defined for shader, compositor, texture, simulation nodes
+ * individually. Cannot use the static types header for this, since they share the same int id.
*/
define_specific_node(brna, "ShaderNodeGroup", "ShaderNode", "Group", "", def_group);
define_specific_node(brna, "CompositorNodeGroup", "CompositorNode", "Group", "", def_group);
define_specific_node(brna, "TextureNodeGroup", "TextureNode", "Group", "", def_group);
+ define_specific_node(brna, "SimulationNodeGroup", "SimulationNode", "Group", "", def_group);
def_custom_group(brna,
"ShaderNodeCustomGroup",
"ShaderNode",
diff --git a/source/blender/makesrna/intern/rna_object.c b/source/blender/makesrna/intern/rna_object.c
index 959529450f0..79a9e0be051 100644
--- a/source/blender/makesrna/intern/rna_object.c
+++ b/source/blender/makesrna/intern/rna_object.c
@@ -329,7 +329,7 @@ static void rna_Object_internal_update_draw(Main *UNUSED(bmain),
Scene *UNUSED(scene),
PointerRNA *ptr)
{
- DEG_id_tag_update(ptr->owner_id, ID_RECALC_TRANSFORM);
+ DEG_id_tag_update(ptr->owner_id, ID_RECALC_SHADING);
WM_main_add_notifier(NC_OBJECT | ND_DRAW, ptr->owner_id);
}
@@ -349,6 +349,14 @@ static void rna_Object_hide_update(Main *bmain, Scene *UNUSED(scene), PointerRNA
WM_main_add_notifier(NC_OBJECT | ND_DRAW, &ob->id);
}
+static void rna_Object_duplicator_visibility_flag_update(Main *UNUSED(bmain),
+ Scene *UNUSED(scene),
+ PointerRNA *ptr)
+{
+ Object *ob = (Object *)ptr->owner_id;
+ DEG_id_tag_update(&ob->id, ID_RECALC_GEOMETRY);
+}
+
static void rna_MaterialIndex_update(Main *UNUSED(bmain), Scene *UNUSED(scene), PointerRNA *ptr)
{
Object *ob = (Object *)ptr->owner_id;
@@ -760,6 +768,24 @@ static PointerRNA rna_Object_active_vertex_group_get(PointerRNA *ptr)
ptr, &RNA_VertexGroup, BLI_findlink(&ob->defbase, ob->actdef - 1));
}
+static void rna_Object_active_vertex_group_set(PointerRNA *ptr,
+ PointerRNA value,
+ struct ReportList *reports)
+{
+ Object *ob = (Object *)ptr->owner_id;
+ int index = BLI_findindex(&ob->defbase, value.data);
+ if (index == -1) {
+ BKE_reportf(reports,
+ RPT_ERROR,
+ "VertexGroup '%s' not found in object '%s'",
+ ((bDeformGroup *)value.data)->name,
+ ob->id.name + 2);
+ return;
+ }
+
+ ob->actdef = index + 1;
+}
+
static int rna_Object_active_vertex_group_index_get(PointerRNA *ptr)
{
Object *ob = (Object *)ptr->owner_id;
@@ -1445,7 +1471,7 @@ static void rna_Object_constraints_remove(Object *object,
RNA_POINTER_INVALIDATE(con_ptr);
ED_object_constraint_update(bmain, object);
- ED_object_constraint_set_active(object, NULL);
+ ED_object_constraint_active_set(object, NULL);
WM_main_add_notifier(NC_OBJECT | ND_CONSTRAINT | NA_REMOVED, object);
}
@@ -1454,7 +1480,7 @@ static void rna_Object_constraints_clear(Object *object, Main *bmain)
BKE_constraints_free(&object->constraints);
ED_object_constraint_update(bmain, object);
- ED_object_constraint_set_active(object, NULL);
+ ED_object_constraint_active_set(object, NULL);
WM_main_add_notifier(NC_OBJECT | ND_CONSTRAINT | NA_REMOVED, object);
}
@@ -1607,9 +1633,12 @@ bool rna_Object_modifiers_override_apply(Main *bmain,
}
mod_src = mod_src ? mod_src->next : ob_src->modifiers.first;
- BLI_assert(mod_src != NULL);
+ if (mod_src == NULL) {
+ BLI_assert(mod_src != NULL);
+ return false;
+ }
- /* While it would be nicer to use lower-level modifier_new() here, this one is lacking
+ /* While it would be nicer to use lower-level BKE_modifier_new() here, this one is lacking
* special-cases handling (particles and other physics modifiers mostly), so using the ED version
* instead, to avoid duplicating code. */
ModifierData *mod_dst = ED_object_modifier_add(
@@ -1624,7 +1653,7 @@ bool rna_Object_modifiers_override_apply(Main *bmain,
ParticleSystem *psys_dst = (mod_dst->type == eModifierType_ParticleSystem) ?
((ParticleSystemModifierData *)mod_dst)->psys :
NULL;
- modifier_copyData(mod_src, mod_dst);
+ BKE_modifier_copydata(mod_src, mod_dst);
if (mod_dst->type == eModifierType_ParticleSystem) {
psys_dst->flag &= ~PSYS_DELETE;
((ParticleSystemModifierData *)mod_dst)->psys = psys_dst;
@@ -1667,6 +1696,69 @@ static void rna_Object_greasepencil_modifier_clear(Object *object, bContext *C)
WM_main_add_notifier(NC_OBJECT | ND_MODIFIER | NA_REMOVED, object);
}
+bool rna_Object_greasepencil_modifiers_override_apply(Main *bmain,
+ PointerRNA *ptr_dst,
+ PointerRNA *ptr_src,
+ PointerRNA *UNUSED(ptr_storage),
+ PropertyRNA *UNUSED(prop_dst),
+ PropertyRNA *UNUSED(prop_src),
+ PropertyRNA *UNUSED(prop_storage),
+ const int UNUSED(len_dst),
+ const int UNUSED(len_src),
+ const int UNUSED(len_storage),
+ PointerRNA *UNUSED(ptr_item_dst),
+ PointerRNA *UNUSED(ptr_item_src),
+ PointerRNA *UNUSED(ptr_item_storage),
+ IDOverrideLibraryPropertyOperation *opop)
+{
+ BLI_assert(opop->operation == IDOVERRIDE_LIBRARY_OP_INSERT_AFTER &&
+ "Unsupported RNA override operation on modifiers collection");
+
+ Object *ob_dst = (Object *)ptr_dst->owner_id;
+ Object *ob_src = (Object *)ptr_src->owner_id;
+
+ /* Remember that insertion operations are defined and stored in correct order, which means that
+ * even if we insert several items in a row, we always insert first one, then second one, etc.
+ * So we should always find 'anchor' modifier in both _src *and* _dst. */
+ GpencilModifierData *mod_anchor = NULL;
+ if (opop->subitem_local_name && opop->subitem_local_name[0]) {
+ mod_anchor = BLI_findstring(
+ &ob_dst->greasepencil_modifiers, opop->subitem_local_name, offsetof(ModifierData, name));
+ }
+ if (mod_anchor == NULL && opop->subitem_local_index >= 0) {
+ mod_anchor = BLI_findlink(&ob_dst->greasepencil_modifiers, opop->subitem_local_index);
+ }
+ /* Otherwise we just insert in first position. */
+
+ GpencilModifierData *mod_src = NULL;
+ if (opop->subitem_local_name && opop->subitem_local_name[0]) {
+ mod_src = BLI_findstring(
+ &ob_src->greasepencil_modifiers, opop->subitem_local_name, offsetof(ModifierData, name));
+ }
+ if (mod_src == NULL && opop->subitem_local_index >= 0) {
+ mod_src = BLI_findlink(&ob_src->greasepencil_modifiers, opop->subitem_local_index);
+ }
+ mod_src = mod_src ? mod_src->next : ob_src->greasepencil_modifiers.first;
+
+ if (mod_src == NULL) {
+ BLI_assert(mod_src != NULL);
+ return false;
+ }
+
+ /* While it would be nicer to use lower-level BKE_modifier_new() here, this one is lacking
+ * special-cases handling (particles and other physics modifiers mostly), so using the ED version
+ * instead, to avoid duplicating code. */
+ GpencilModifierData *mod_dst = ED_object_gpencil_modifier_add(
+ NULL, bmain, NULL, ob_dst, mod_src->name, mod_src->type);
+
+ BLI_remlink(&ob_dst->modifiers, mod_dst);
+ /* This handles NULL anchor as expected by adding at head of list. */
+ BLI_insertlinkafter(&ob_dst->greasepencil_modifiers, mod_anchor, mod_dst);
+
+ // printf("%s: We inserted a gpencil modifier '%s'...\n", __func__, mod_dst->name);
+ return true;
+}
+
/* shader fx */
static ShaderFxData *rna_Object_shaderfx_new(
Object *object, bContext *C, ReportList *reports, const char *name, int type)
@@ -2333,6 +2425,7 @@ static void rna_def_object_vertex_groups(BlenderRNA *brna, PropertyRNA *cprop)
"rna_Object_active_vertex_group_set",
NULL,
NULL);
+ RNA_def_property_flag(prop, PROP_EDITABLE);
RNA_def_property_ui_text(prop, "Active Vertex Group", "Vertex groups of the object");
RNA_def_property_update(prop, NC_GEOM | ND_DATA, "rna_Object_internal_update_data");
@@ -2797,6 +2890,7 @@ static void rna_def_object(BlenderRNA *brna)
prop = RNA_def_property(srna, "matrix_parent_inverse", PROP_FLOAT, PROP_MATRIX);
RNA_def_property_float_sdna(prop, NULL, "parentinv");
RNA_def_property_multi_array(prop, 2, rna_matrix_dimsize_4x4);
+ RNA_def_property_override_flag(prop, PROPOVERRIDE_OVERRIDABLE_LIBRARY);
RNA_def_property_ui_text(
prop, "Parent Inverse Matrix", "Inverse of object's parent matrix at time of parenting");
RNA_def_property_update(prop, NC_OBJECT | ND_TRANSFORM, "rna_Object_internal_update");
@@ -2817,6 +2911,10 @@ static void rna_def_object(BlenderRNA *brna)
RNA_def_property_struct_type(prop, "GpencilModifier");
RNA_def_property_ui_text(
prop, "Grease Pencil Modifiers", "Modifiers affecting the data of the grease pencil object");
+ RNA_def_property_override_funcs(
+ prop, NULL, NULL, "rna_Object_greasepencil_modifiers_override_apply");
+ RNA_def_property_override_flag(
+ prop, PROPOVERRIDE_OVERRIDABLE_LIBRARY | PROPOVERRIDE_LIBRARY_INSERTION);
rna_def_object_grease_pencil_modifiers(brna, prop);
/* Shader FX. */
@@ -3008,10 +3106,14 @@ static void rna_def_object(BlenderRNA *brna)
prop = RNA_def_property(srna, "show_instancer_for_render", PROP_BOOLEAN, PROP_NONE);
RNA_def_property_boolean_sdna(prop, NULL, "duplicator_visibility_flag", OB_DUPLI_FLAG_RENDER);
RNA_def_property_ui_text(prop, "Render Instancer", "Make instancer visible when rendering");
+ RNA_def_property_update(
+ prop, NC_OBJECT | ND_DRAW, "rna_Object_duplicator_visibility_flag_update");
prop = RNA_def_property(srna, "show_instancer_for_viewport", PROP_BOOLEAN, PROP_NONE);
RNA_def_property_boolean_sdna(prop, NULL, "duplicator_visibility_flag", OB_DUPLI_FLAG_VIEWPORT);
RNA_def_property_ui_text(prop, "Display Instancer", "Make instancer visible in the viewport");
+ RNA_def_property_update(
+ prop, NC_OBJECT | ND_DRAW, "rna_Object_duplicator_visibility_flag_update");
/* anim */
rna_def_animdata_common(srna);
@@ -3103,7 +3205,6 @@ static void rna_def_object(BlenderRNA *brna)
prop = RNA_def_property(srna, "use_grease_pencil_lights", PROP_BOOLEAN, PROP_NONE);
RNA_def_property_boolean_sdna(prop, NULL, "dtx", OB_USE_GPENCIL_LIGHTS);
RNA_def_property_boolean_default(prop, true);
- RNA_def_property_clear_flag(prop, PROP_ANIMATABLE);
RNA_def_property_ui_text(prop, "Use Lights", "Lights affect grease pencil object");
RNA_def_property_update(prop, NC_OBJECT | ND_DRAW, "rna_GPencil_update");
diff --git a/source/blender/makesrna/intern/rna_object_api.c b/source/blender/makesrna/intern/rna_object_api.c
index 5104f4a66a1..3b80714bcc5 100644
--- a/source/blender/makesrna/intern/rna_object_api.c
+++ b/source/blender/makesrna/intern/rna_object_api.c
@@ -36,11 +36,13 @@
#include "DNA_modifier_types.h"
#include "DNA_object_types.h"
-#include "BKE_gpencil_geom.h"
+#include "BKE_gpencil_curve.h"
#include "BKE_layer.h"
#include "DEG_depsgraph.h"
+#include "ED_outliner.h"
+
#include "rna_internal.h" /* own include */
static const EnumPropertyItem space_items[] = {
@@ -63,7 +65,6 @@ static const EnumPropertyItem space_items[] = {
# include "BLI_math.h"
-# include "BKE_anim.h"
# include "BKE_bvhutils.h"
# include "BKE_constraint.h"
# include "BKE_context.h"
@@ -115,6 +116,7 @@ static void rna_Object_select_set(
Scene *scene = CTX_data_scene(C);
DEG_id_tag_update(&scene->id, ID_RECALC_SELECT);
WM_main_add_notifier(NC_SCENE | ND_OB_SELECT, scene);
+ ED_outliner_select_sync_from_object_tag(C);
}
static bool rna_Object_select_get(Object *ob, bContext *C, ViewLayer *view_layer)
@@ -222,7 +224,7 @@ static bool rna_Object_indirect_only_get(Object *ob, bContext *C, ViewLayer *vie
return ((base->flag & BASE_INDIRECT_ONLY) != 0);
}
-static Base *rna_Object_local_view_property_helper(bScreen *sc,
+static Base *rna_Object_local_view_property_helper(bScreen *screen,
View3D *v3d,
ViewLayer *view_layer,
Object *ob,
@@ -236,7 +238,7 @@ static Base *rna_Object_local_view_property_helper(bScreen *sc,
}
if (view_layer == NULL) {
- win = ED_screen_window_find(sc, G_MAIN->wm.first);
+ win = ED_screen_window_find(screen, G_MAIN->wm.first);
view_layer = WM_window_get_active_view_layer(win);
}
@@ -266,10 +268,10 @@ static void rna_Object_local_view_set(Object *ob,
PointerRNA *v3d_ptr,
bool state)
{
- bScreen *sc = (bScreen *)v3d_ptr->owner_id;
+ bScreen *screen = (bScreen *)v3d_ptr->owner_id;
View3D *v3d = v3d_ptr->data;
Scene *scene;
- Base *base = rna_Object_local_view_property_helper(sc, v3d, NULL, ob, reports, &scene);
+ Base *base = rna_Object_local_view_property_helper(screen, v3d, NULL, ob, reports, &scene);
if (base == NULL) {
return; /* Error reported. */
}
@@ -277,9 +279,9 @@ static void rna_Object_local_view_set(Object *ob,
SET_FLAG_FROM_TEST(base->local_view_bits, state, v3d->local_view_uuid);
if (local_view_bits_prev != base->local_view_bits) {
DEG_id_tag_update(&scene->id, ID_RECALC_BASE_FLAGS);
- ScrArea *sa = ED_screen_area_find_with_spacedata(sc, (SpaceLink *)v3d, true);
- if (sa) {
- ED_area_tag_redraw(sa);
+ ScrArea *area = ED_screen_area_find_with_spacedata(screen, (SpaceLink *)v3d, true);
+ if (area) {
+ ED_area_tag_redraw(area);
}
}
}
@@ -952,7 +954,7 @@ void RNA_api_object(StructRNA *srna)
RNA_def_function_ui_description(func, "Clears mesh data-block created by to_mesh()");
/* Armature */
- func = RNA_def_function(srna, "find_armature", "modifiers_isDeformedByArmature");
+ func = RNA_def_function(srna, "find_armature", "BKE_modifiers_is_deformed_by_armature");
RNA_def_function_ui_description(
func, "Find armature influencing this object as a parent or via a modifier");
parm = RNA_def_pointer(
diff --git a/source/blender/makesrna/intern/rna_object_force.c b/source/blender/makesrna/intern/rna_object_force.c
index 4a34d1465dd..3317ae91f98 100644
--- a/source/blender/makesrna/intern/rna_object_force.c
+++ b/source/blender/makesrna/intern/rna_object_force.c
@@ -145,7 +145,7 @@ static char *rna_PointCache_path(PointerRNA *ptr)
PointCache *cache = ptr->data;
for (md = ob->modifiers.first; md; md = md->next) {
- const ModifierTypeInfo *mti = modifierType_getInfo(md->type);
+ const ModifierTypeInfo *mti = BKE_modifier_get_info(md->type);
if (!(mti->flags & eModifierTypeFlag_UsesPointCache)) {
continue;
@@ -430,7 +430,7 @@ static char *rna_CollisionSettings_path(PointerRNA *UNUSED(ptr))
/* both methods work ok, but return the shorter path */
# if 0
Object *ob = (Object *)ptr->owner_id;
- ModifierData *md = (ModifierData *)modifiers_findByType(ob, eModifierType_Collision);
+ ModifierData *md = (ModifierData *)BKE_modifiers_findby_type(ob, eModifierType_Collision);
if (md) {
char name_esc[sizeof(md->name) * 2];
@@ -604,7 +604,7 @@ static void rna_SoftBodySettings_spring_vgroup_set(PointerRNA *ptr, const char *
static char *rna_SoftBodySettings_path(PointerRNA *ptr)
{
Object *ob = (Object *)ptr->owner_id;
- ModifierData *md = (ModifierData *)modifiers_findByType(ob, eModifierType_Softbody);
+ ModifierData *md = (ModifierData *)BKE_modifiers_findby_type(ob, eModifierType_Softbody);
char name_esc[sizeof(md->name) * 2];
BLI_strescape(name_esc, md->name, sizeof(name_esc));
@@ -780,7 +780,7 @@ static char *rna_EffectorWeight_path(PointerRNA *ptr)
ModifierData *md;
/* check softbody modifier */
- md = (ModifierData *)modifiers_findByType(ob, eModifierType_Softbody);
+ md = (ModifierData *)BKE_modifiers_findby_type(ob, eModifierType_Softbody);
if (md) {
/* no pointer from modifier data to actual softbody storage, would be good to add */
if (ob->soft->effector_weights == ew) {
@@ -791,7 +791,7 @@ static char *rna_EffectorWeight_path(PointerRNA *ptr)
}
/* check cloth modifier */
- md = (ModifierData *)modifiers_findByType(ob, eModifierType_Cloth);
+ md = (ModifierData *)BKE_modifiers_findby_type(ob, eModifierType_Cloth);
if (md) {
ClothModifierData *cmd = (ClothModifierData *)md;
if (cmd->sim_parms->effector_weights == ew) {
@@ -802,7 +802,7 @@ static char *rna_EffectorWeight_path(PointerRNA *ptr)
}
/* check smoke modifier */
- md = (ModifierData *)modifiers_findByType(ob, eModifierType_Fluid);
+ md = (ModifierData *)BKE_modifiers_findby_type(ob, eModifierType_Fluid);
if (md) {
FluidModifierData *mmd = (FluidModifierData *)md;
if (mmd->domain->effector_weights == ew) {
@@ -813,7 +813,7 @@ static char *rna_EffectorWeight_path(PointerRNA *ptr)
}
/* check dynamic paint modifier */
- md = (ModifierData *)modifiers_findByType(ob, eModifierType_DynamicPaint);
+ md = (ModifierData *)BKE_modifiers_findby_type(ob, eModifierType_DynamicPaint);
if (md) {
DynamicPaintModifierData *pmd = (DynamicPaintModifierData *)md;
@@ -843,7 +843,7 @@ static char *rna_EffectorWeight_path(PointerRNA *ptr)
static void rna_CollisionSettings_dependency_update(Main *bmain, Scene *scene, PointerRNA *ptr)
{
Object *ob = (Object *)ptr->owner_id;
- ModifierData *md = modifiers_findByType(ob, eModifierType_Collision);
+ ModifierData *md = BKE_modifiers_findby_type(ob, eModifierType_Collision);
/* add/remove modifier as needed */
if (ob->pd->deflect && !md) {
@@ -1332,7 +1332,7 @@ static void rna_def_effector_weight(BlenderRNA *brna)
RNA_def_property_float_sdna(prop, NULL, "weight[13]");
RNA_def_property_range(prop, -200.0f, 200.0f);
RNA_def_property_ui_range(prop, 0.0f, 1.0f, 0.1, 3);
- RNA_def_property_ui_text(prop, "Smoke Flow", "Smoke Flow effector weight");
+ RNA_def_property_ui_text(prop, "Fluid Flow", "Fluid Flow effector weight");
RNA_def_property_update(prop, 0, "rna_EffectorWeight_update");
}
@@ -1396,11 +1396,11 @@ static void rna_def_field(BlenderRNA *brna)
"Turbulence",
"Create turbulence with a noise field"},
{PFIELD_DRAG, "DRAG", ICON_FORCE_DRAG, "Drag", "Create a force that dampens motion"},
- {PFIELD_SMOKEFLOW,
- "SMOKE_FLOW",
- ICON_FORCE_SMOKEFLOW,
- "Smoke Flow",
- "Create a force based on smoke simulation air flow"},
+ {PFIELD_FLUIDFLOW,
+ "FLUID_FLOW",
+ ICON_FORCE_FLUIDFLOW,
+ "Fluid Flow",
+ "Create a force based on fluid simulation velocities"},
{0, NULL, 0, NULL, NULL},
};
diff --git a/source/blender/makesrna/intern/rna_particle.c b/source/blender/makesrna/intern/rna_particle.c
index 47a20518648..73b3515030e 100644
--- a/source/blender/makesrna/intern/rna_particle.c
+++ b/source/blender/makesrna/intern/rna_particle.c
@@ -41,6 +41,8 @@
#include "BKE_mesh.h"
+#include "BLI_listbase.h"
+
#include "BLT_translation.h"
#include "rna_internal.h"
@@ -695,7 +697,7 @@ static void rna_Particle_change_type(Main *bmain, Scene *UNUSED(scene), PointerR
/* Iterating over all object is slow, but no better solution exists at the moment. */
for (Object *ob = bmain->objects.first; ob; ob = ob->id.next) {
- for (ParticleSystem *psys = ob->particlesystem.first; psys; psys = psys->next) {
+ LISTBASE_FOREACH (ParticleSystem *, psys, &ob->particlesystem) {
if (psys->part == part) {
psys_changed_type(ob, psys);
psys->recalc |= ID_RECALC_PSYS_RESET;
@@ -825,7 +827,7 @@ static void rna_Particle_hair_dynamics_update(Main *bmain, Scene *scene, Pointer
ParticleSystem *psys = (ParticleSystem *)ptr->data;
if (psys && !psys->clmd) {
- psys->clmd = (ClothModifierData *)modifier_new(eModifierType_Cloth);
+ psys->clmd = (ClothModifierData *)BKE_modifier_new(eModifierType_Cloth);
psys->clmd->sim_parms->goalspring = 0.0f;
psys->clmd->sim_parms->flags |= CLOTH_SIMSETTINGS_FLAG_RESIST_SPRING_COMPRESS;
psys->clmd->coll_parms->flags &= ~CLOTH_COLLSETTINGS_FLAG_SELF;
diff --git a/source/blender/makesrna/intern/rna_pose.c b/source/blender/makesrna/intern/rna_pose.c
index 17e5f3d3649..8f28fc56712 100644
--- a/source/blender/makesrna/intern/rna_pose.c
+++ b/source/blender/makesrna/intern/rna_pose.c
@@ -295,6 +295,18 @@ static void rna_PoseChannel_name_set(PointerRNA *ptr, const char *value)
ED_armature_bone_rename(G_MAIN, ob->data, oldname, newname);
}
+/* See rna_Bone_update_renamed() */
+static void rna_PoseChannel_name_update(Main *UNUSED(bmain), Scene *UNUSED(scene), PointerRNA *ptr)
+{
+ ID *id = ptr->owner_id;
+
+ /* redraw view */
+ WM_main_add_notifier(NC_GEOM | ND_DATA, id);
+
+ /* update animation channels */
+ WM_main_add_notifier(NC_ANIMATION | ND_ANIMCHAN, id);
+}
+
static PointerRNA rna_PoseChannel_bone_get(PointerRNA *ptr)
{
Object *ob = (Object *)ptr->owner_id;
@@ -996,6 +1008,7 @@ static void rna_def_pose_channel(BlenderRNA *brna)
RNA_def_property_ui_text(prop, "Name", "");
RNA_def_property_editable_func(prop, "rna_PoseChannel_proxy_editable");
RNA_def_struct_name_property(srna, prop);
+ RNA_def_property_update(prop, 0, "rna_PoseChannel_name_update");
/* Baked Bone Path cache data */
rna_def_motionpath_common(srna);
diff --git a/source/blender/makesrna/intern/rna_render.c b/source/blender/makesrna/intern/rna_render.c
index 40a2aeb5bd5..6af031eb7b0 100644
--- a/source/blender/makesrna/intern/rna_render.c
+++ b/source/blender/makesrna/intern/rna_render.c
@@ -131,7 +131,7 @@ static void engine_bind_display_space_shader(RenderEngine *UNUSED(engine), Scene
GPUShader *shader = GPU_shader_get_builtin_shader(GPU_SHADER_2D_IMAGE);
GPU_shader_bind(shader);
- int img_loc = GPU_shader_get_uniform_ensure(shader, "image");
+ int img_loc = GPU_shader_get_uniform(shader, "image");
GPU_shader_uniform_int(shader, img_loc, 0);
}
@@ -148,13 +148,13 @@ static void engine_update(RenderEngine *engine, Main *bmain, Depsgraph *depsgrap
ParameterList list;
FunctionRNA *func;
- RNA_pointer_create(NULL, engine->type->ext.srna, engine, &ptr);
+ RNA_pointer_create(NULL, engine->type->rna_ext.srna, engine, &ptr);
func = &rna_RenderEngine_update_func;
RNA_parameter_list_create(&list, &ptr, func);
RNA_parameter_set_lookup(&list, "data", &bmain);
RNA_parameter_set_lookup(&list, "depsgraph", &depsgraph);
- engine->type->ext.call(NULL, &ptr, func, &list);
+ engine->type->rna_ext.call(NULL, &ptr, func, &list);
RNA_parameter_list_free(&list);
}
@@ -166,12 +166,12 @@ static void engine_render(RenderEngine *engine, Depsgraph *depsgraph)
ParameterList list;
FunctionRNA *func;
- RNA_pointer_create(NULL, engine->type->ext.srna, engine, &ptr);
+ RNA_pointer_create(NULL, engine->type->rna_ext.srna, engine, &ptr);
func = &rna_RenderEngine_render_func;
RNA_parameter_list_create(&list, &ptr, func);
RNA_parameter_set_lookup(&list, "depsgraph", &depsgraph);
- engine->type->ext.call(NULL, &ptr, func, &list);
+ engine->type->rna_ext.call(NULL, &ptr, func, &list);
RNA_parameter_list_free(&list);
}
@@ -181,18 +181,15 @@ static void engine_bake(RenderEngine *engine,
struct Object *object,
const int pass_type,
const int pass_filter,
- const int object_id,
- const struct BakePixel *pixel_array,
- const int num_pixels,
- const int depth,
- void *result)
+ const int width,
+ const int height)
{
extern FunctionRNA rna_RenderEngine_bake_func;
PointerRNA ptr;
ParameterList list;
FunctionRNA *func;
- RNA_pointer_create(NULL, engine->type->ext.srna, engine, &ptr);
+ RNA_pointer_create(NULL, engine->type->rna_ext.srna, engine, &ptr);
func = &rna_RenderEngine_bake_func;
RNA_parameter_list_create(&list, &ptr, func);
@@ -200,12 +197,9 @@ static void engine_bake(RenderEngine *engine,
RNA_parameter_set_lookup(&list, "object", &object);
RNA_parameter_set_lookup(&list, "pass_type", &pass_type);
RNA_parameter_set_lookup(&list, "pass_filter", &pass_filter);
- RNA_parameter_set_lookup(&list, "object_id", &object_id);
- RNA_parameter_set_lookup(&list, "pixel_array", &pixel_array);
- RNA_parameter_set_lookup(&list, "num_pixels", &num_pixels);
- RNA_parameter_set_lookup(&list, "depth", &depth);
- RNA_parameter_set_lookup(&list, "result", &result);
- engine->type->ext.call(NULL, &ptr, func, &list);
+ RNA_parameter_set_lookup(&list, "width", &width);
+ RNA_parameter_set_lookup(&list, "height", &height);
+ engine->type->rna_ext.call(NULL, &ptr, func, &list);
RNA_parameter_list_free(&list);
}
@@ -219,13 +213,13 @@ static void engine_view_update(RenderEngine *engine,
ParameterList list;
FunctionRNA *func;
- RNA_pointer_create(NULL, engine->type->ext.srna, engine, &ptr);
+ RNA_pointer_create(NULL, engine->type->rna_ext.srna, engine, &ptr);
func = &rna_RenderEngine_view_update_func;
RNA_parameter_list_create(&list, &ptr, func);
RNA_parameter_set_lookup(&list, "context", &context);
RNA_parameter_set_lookup(&list, "depsgraph", &depsgraph);
- engine->type->ext.call(NULL, &ptr, func, &list);
+ engine->type->rna_ext.call(NULL, &ptr, func, &list);
RNA_parameter_list_free(&list);
}
@@ -239,13 +233,13 @@ static void engine_view_draw(RenderEngine *engine,
ParameterList list;
FunctionRNA *func;
- RNA_pointer_create(NULL, engine->type->ext.srna, engine, &ptr);
+ RNA_pointer_create(NULL, engine->type->rna_ext.srna, engine, &ptr);
func = &rna_RenderEngine_view_draw_func;
RNA_parameter_list_create(&list, &ptr, func);
RNA_parameter_set_lookup(&list, "context", &context);
RNA_parameter_set_lookup(&list, "depsgraph", &depsgraph);
- engine->type->ext.call(NULL, &ptr, func, &list);
+ engine->type->rna_ext.call(NULL, &ptr, func, &list);
RNA_parameter_list_free(&list);
}
@@ -259,13 +253,13 @@ static void engine_update_script_node(RenderEngine *engine,
ParameterList list;
FunctionRNA *func;
- RNA_pointer_create(NULL, engine->type->ext.srna, engine, &ptr);
+ RNA_pointer_create(NULL, engine->type->rna_ext.srna, engine, &ptr);
RNA_pointer_create((ID *)ntree, &RNA_Node, node, &nodeptr);
func = &rna_RenderEngine_update_script_node_func;
RNA_parameter_list_create(&list, &ptr, func);
RNA_parameter_set_lookup(&list, "node", &nodeptr);
- engine->type->ext.call(NULL, &ptr, func, &list);
+ engine->type->rna_ext.call(NULL, &ptr, func, &list);
RNA_parameter_list_free(&list);
}
@@ -279,13 +273,13 @@ static void engine_update_render_passes(RenderEngine *engine,
ParameterList list;
FunctionRNA *func;
- RNA_pointer_create(NULL, engine->type->ext.srna, engine, &ptr);
+ RNA_pointer_create(NULL, engine->type->rna_ext.srna, engine, &ptr);
func = &rna_RenderEngine_update_render_passes_func;
RNA_parameter_list_create(&list, &ptr, func);
RNA_parameter_set_lookup(&list, "scene", &scene);
RNA_parameter_set_lookup(&list, "renderlayer", &view_layer);
- engine->type->ext.call(NULL, &ptr, func, &list);
+ engine->type->rna_ext.call(NULL, &ptr, func, &list);
RNA_parameter_list_free(&list);
}
@@ -300,7 +294,7 @@ static void rna_RenderEngine_unregister(Main *bmain, StructRNA *type)
return;
}
- RNA_struct_free_extension(type, &et->ext);
+ RNA_struct_free_extension(type, &et->rna_ext);
RNA_struct_free(&BLENDER_RNA, type);
BLI_freelinkN(&R_engines, et);
@@ -343,8 +337,8 @@ static StructRNA *rna_RenderEngine_register(Main *bmain,
/* check if we have registered this engine type before, and remove it */
for (et = R_engines.first; et; et = et->next) {
if (STREQ(et->idname, dummyet.idname)) {
- if (et->ext.srna) {
- rna_RenderEngine_unregister(bmain, et->ext.srna);
+ if (et->rna_ext.srna) {
+ rna_RenderEngine_unregister(bmain, et->rna_ext.srna);
}
break;
}
@@ -354,11 +348,11 @@ static StructRNA *rna_RenderEngine_register(Main *bmain,
et = MEM_mallocN(sizeof(RenderEngineType), "python render engine");
memcpy(et, &dummyet, sizeof(dummyet));
- et->ext.srna = RNA_def_struct_ptr(&BLENDER_RNA, et->idname, &RNA_RenderEngine);
- et->ext.data = data;
- et->ext.call = call;
- et->ext.free = free;
- RNA_struct_blender_type_set(et->ext.srna, et);
+ et->rna_ext.srna = RNA_def_struct_ptr(&BLENDER_RNA, et->idname, &RNA_RenderEngine);
+ et->rna_ext.data = data;
+ et->rna_ext.call = call;
+ et->rna_ext.free = free;
+ RNA_struct_blender_type_set(et->rna_ext.srna, et);
et->update = (have_function[0]) ? engine_update : NULL;
et->render = (have_function[1]) ? engine_render : NULL;
@@ -370,7 +364,7 @@ static StructRNA *rna_RenderEngine_register(Main *bmain,
RE_engines_register(et);
- return et->ext.srna;
+ return et->rna_ext.srna;
}
static void **rna_RenderEngine_instance(PointerRNA *ptr)
@@ -382,7 +376,8 @@ static void **rna_RenderEngine_instance(PointerRNA *ptr)
static StructRNA *rna_RenderEngine_refine(PointerRNA *ptr)
{
RenderEngine *engine = (RenderEngine *)ptr->data;
- return (engine->type && engine->type->ext.srna) ? engine->type->ext.srna : &RNA_RenderEngine;
+ return (engine->type && engine->type->rna_ext.srna) ? engine->type->rna_ext.srna :
+ &RNA_RenderEngine;
}
static PointerRNA rna_RenderEngine_render_get(PointerRNA *ptr)
@@ -460,12 +455,6 @@ void rna_RenderPass_rect_set(PointerRNA *ptr, const float *values)
memcpy(rpass->rect, values, sizeof(float) * rpass->rectx * rpass->recty * rpass->channels);
}
-static PointerRNA rna_BakePixel_next_get(PointerRNA *ptr)
-{
- BakePixel *bp = ptr->data;
- return rna_pointer_inherit_refine(ptr, &RNA_BakePixel, bp + 1);
-}
-
static RenderPass *rna_RenderPass_find_by_type(RenderLayer *rl, int passtype, const char *view)
{
return RE_pass_find_by_type(rl, passtype, view);
@@ -534,33 +523,9 @@ static void rna_def_render_engine(BlenderRNA *brna)
0,
INT_MAX);
RNA_def_parameter_flags(parm, 0, PARM_REQUIRED);
- parm = RNA_def_int(func,
- "object_id",
- 0,
- 0,
- INT_MAX,
- "Object Id",
- "Id of the current object being baked in relation to the others",
- 0,
- INT_MAX);
- RNA_def_parameter_flags(parm, 0, PARM_REQUIRED);
- parm = RNA_def_pointer(func, "pixel_array", "BakePixel", "", "");
- RNA_def_parameter_flags(parm, 0, PARM_REQUIRED);
- parm = RNA_def_int(func,
- "num_pixels",
- 0,
- 0,
- INT_MAX,
- "Number of Pixels",
- "Size of the baking batch",
- 0,
- INT_MAX);
- RNA_def_parameter_flags(parm, 0, PARM_REQUIRED);
- parm = RNA_def_int(
- func, "depth", 0, 0, INT_MAX, "Pixels depth", "Number of channels", 1, INT_MAX);
+ parm = RNA_def_int(func, "width", 0, 0, INT_MAX, "Width", "Image width", 0, INT_MAX);
RNA_def_parameter_flags(parm, 0, PARM_REQUIRED);
- /* TODO, see how array size of 0 works, this shouldnt be used */
- parm = RNA_def_pointer(func, "result", "AnyType", "", "");
+ parm = RNA_def_int(func, "height", 0, 0, INT_MAX, "Height", "Image height", 0, INT_MAX);
RNA_def_parameter_flags(parm, 0, PARM_REQUIRED);
/* viewport render callbacks */
@@ -1118,53 +1083,6 @@ static void rna_def_render_pass(BlenderRNA *brna)
RNA_define_verify_sdna(1);
}
-static void rna_def_render_bake_pixel(BlenderRNA *brna)
-{
- StructRNA *srna;
- PropertyRNA *prop;
-
- srna = RNA_def_struct(brna, "BakePixel", NULL);
- RNA_def_struct_ui_text(srna, "Bake Pixel", "");
-
- RNA_define_verify_sdna(0);
-
- prop = RNA_def_property(srna, "primitive_id", PROP_INT, PROP_NONE);
- RNA_def_property_int_sdna(prop, NULL, "primitive_id");
- RNA_def_property_clear_flag(prop, PROP_EDITABLE);
-
- prop = RNA_def_property(srna, "object_id", PROP_INT, PROP_NONE);
- RNA_def_property_int_sdna(prop, NULL, "object_id");
- RNA_def_property_clear_flag(prop, PROP_EDITABLE);
-
- prop = RNA_def_property(srna, "uv", PROP_FLOAT, PROP_NONE);
- RNA_def_property_array(prop, 2);
- RNA_def_property_float_sdna(prop, NULL, "uv");
- RNA_def_property_clear_flag(prop, PROP_EDITABLE);
-
- prop = RNA_def_property(srna, "du_dx", PROP_FLOAT, PROP_NONE);
- RNA_def_property_float_sdna(prop, NULL, "du_dx");
- RNA_def_property_clear_flag(prop, PROP_EDITABLE);
-
- prop = RNA_def_property(srna, "du_dy", PROP_FLOAT, PROP_NONE);
- RNA_def_property_float_sdna(prop, NULL, "du_dy");
- RNA_def_property_clear_flag(prop, PROP_EDITABLE);
-
- prop = RNA_def_property(srna, "dv_dx", PROP_FLOAT, PROP_NONE);
- RNA_def_property_float_sdna(prop, NULL, "dv_dx");
- RNA_def_property_clear_flag(prop, PROP_EDITABLE);
-
- prop = RNA_def_property(srna, "dv_dy", PROP_FLOAT, PROP_NONE);
- RNA_def_property_float_sdna(prop, NULL, "dv_dy");
- RNA_def_property_clear_flag(prop, PROP_EDITABLE);
-
- prop = RNA_def_property(srna, "next", PROP_POINTER, PROP_NONE);
- RNA_def_property_struct_type(prop, "BakePixel");
- RNA_def_property_pointer_funcs(prop, "rna_BakePixel_next_get", NULL, NULL, NULL);
- RNA_def_property_clear_flag(prop, PROP_EDITABLE);
-
- RNA_define_verify_sdna(1);
-}
-
void RNA_def_render(BlenderRNA *brna)
{
rna_def_render_engine(brna);
@@ -1172,7 +1090,6 @@ void RNA_def_render(BlenderRNA *brna)
rna_def_render_view(brna);
rna_def_render_layer(brna);
rna_def_render_pass(brna);
- rna_def_render_bake_pixel(brna);
}
#endif /* RNA_RUNTIME */
diff --git a/source/blender/makesrna/intern/rna_scene.c b/source/blender/makesrna/intern/rna_scene.c
index 480d4927305..7e9753b090a 100644
--- a/source/blender/makesrna/intern/rna_scene.c
+++ b/source/blender/makesrna/intern/rna_scene.c
@@ -36,6 +36,7 @@
#include "IMB_imbuf_types.h"
+#include "BLI_listbase.h"
#include "BLI_math.h"
#include "BLT_translation.h"
@@ -923,11 +924,11 @@ static void rna_Scene_volume_update(Main *UNUSED(bmain), Scene *UNUSED(scene), P
DEG_id_tag_update(&scene->id, ID_RECALC_AUDIO_VOLUME | ID_RECALC_SEQUENCER_STRIPS);
}
-static const char *rna_Scene_statistics_string_get(Scene *scene,
- Main *bmain,
+static const char *rna_Scene_statistics_string_get(Scene *UNUSED(scene),
+ Main *UNUSED(bmain),
ViewLayer *view_layer)
{
- return ED_info_stats_string(bmain, scene, view_layer);
+ return ED_info_footer_string(view_layer);
}
static void rna_Scene_framelen_update(Main *UNUSED(bmain), Scene *scene, PointerRNA *UNUSED(ptr))
@@ -1136,6 +1137,11 @@ static char *rna_SceneEEVEE_path(PointerRNA *UNUSED(ptr))
return BLI_strdup("eevee");
}
+static char *rna_SceneGpencil_path(PointerRNA *UNUSED(ptr))
+{
+ return BLI_strdup("grease_pencil_settings");
+}
+
static int rna_RenderSettings_stereoViews_skip(CollectionPropertyIterator *iter,
void *UNUSED(data))
{
@@ -1679,10 +1685,10 @@ void rna_Scene_glsl_update(Main *UNUSED(bmain), Scene *UNUSED(scene), PointerRNA
static void rna_Scene_world_update(Main *bmain, Scene *scene, PointerRNA *ptr)
{
- Scene *sc = (Scene *)ptr->owner_id;
+ Scene *screen = (Scene *)ptr->owner_id;
rna_Scene_glsl_update(bmain, scene, ptr);
- WM_main_add_notifier(NC_WORLD | ND_WORLD, &sc->id);
+ WM_main_add_notifier(NC_WORLD | ND_WORLD, &screen->id);
DEG_relations_tag_update(bmain);
}
@@ -1810,7 +1816,7 @@ static void rna_Scene_editmesh_select_mode_set(PointerRNA *ptr, const bool *valu
/* Update select mode in all the workspaces in mesh edit mode. */
wmWindowManager *wm = G_MAIN->wm.first;
- for (wmWindow *win = wm->windows.first; win; win = win->next) {
+ LISTBASE_FOREACH (wmWindow *, win, &wm->windows) {
ViewLayer *view_layer = WM_window_get_active_view_layer(win);
if (view_layer && view_layer->basact) {
@@ -2025,6 +2031,24 @@ static void rna_View3DCursor_matrix_set(PointerRNA *ptr, const float *values)
BKE_scene_cursor_from_mat4(cursor, unit_mat, false);
}
+static char *rna_TransformOrientationSlot_path(PointerRNA *ptr)
+{
+ Scene *scene = (Scene *)ptr->owner_id;
+ TransformOrientationSlot *orientation_slot = ptr->data;
+
+ if (!ELEM(NULL, scene, orientation_slot)) {
+ for (int i = 0; i < ARRAY_SIZE(scene->orientation_slots); i++) {
+ if (&scene->orientation_slots[i] == orientation_slot) {
+ return BLI_sprintfN("transform_orientation_slots[%d]", i);
+ }
+ }
+ }
+
+ /* Should not happen, but in case, just return defqult path. */
+ BLI_assert(0);
+ return BLI_strdup("transform_orientation_slots[0]");
+}
+
static char *rna_View3DCursor_path(PointerRNA *UNUSED(ptr))
{
return BLI_strdup("cursor");
@@ -2174,12 +2198,12 @@ static void rna_Scene_update_active_object_data(bContext *C, PointerRNA *UNUSED(
}
}
-static void rna_SceneCamera_update(Main *bmain, Scene *UNUSED(scene), PointerRNA *ptr)
+static void rna_SceneCamera_update(Main *UNUSED(bmain), Scene *UNUSED(scene), PointerRNA *ptr)
{
Scene *scene = (Scene *)ptr->owner_id;
Object *camera = scene->camera;
- BKE_sequence_invalidate_scene_strips(bmain, scene);
+ BKE_sequencer_cache_cleanup(scene);
if (camera && (camera->type == OB_CAMERA)) {
DEG_id_tag_update(&camera->id, ID_RECALC_GEOMETRY);
@@ -2434,7 +2458,7 @@ static const EnumPropertyItem *rna_TransformOrientation_impl_itemf(Scene *scene,
if (transform_orientations && (BLI_listbase_is_empty(transform_orientations) == false)) {
RNA_enum_item_add_separator(&item, &totitem);
- for (TransformOrientation *ts = transform_orientations->first; ts; ts = ts->next) {
+ LISTBASE_FOREACH (TransformOrientation *, ts, transform_orientations) {
tmp.identifier = ts->name;
tmp.name = ts->name;
tmp.value = i++;
@@ -2663,6 +2687,7 @@ static void rna_def_transform_orientation_slot(BlenderRNA *brna)
srna = RNA_def_struct(brna, "TransformOrientationSlot", NULL);
RNA_def_struct_sdna(srna, "TransformOrientationSlot");
+ RNA_def_struct_path_func(srna, "rna_TransformOrientationSlot_path");
RNA_def_struct_ui_text(srna, "Orientation Slot", "");
/* Orientations */
@@ -3349,14 +3374,15 @@ static void rna_def_tool_settings(BlenderRNA *brna)
prop = RNA_def_property(srna, "use_keyframe_insert_auto", PROP_BOOLEAN, PROP_NONE);
RNA_def_property_boolean_sdna(prop, NULL, "autokey_mode", AUTOKEY_ON);
RNA_def_property_ui_text(
- prop, "Auto Keying", "Automatic keyframe insertion for Objects and Bones");
+ prop, "Auto Keying", "Automatic keyframe insertion for Objects, Bones and Masks");
RNA_def_property_ui_icon(prop, ICON_REC, 0);
prop = RNA_def_property(srna, "auto_keying_mode", PROP_ENUM, PROP_NONE);
RNA_def_property_enum_bitflag_sdna(prop, NULL, "autokey_mode");
RNA_def_property_enum_items(prop, auto_key_items);
- RNA_def_property_ui_text(
- prop, "Auto-Keying Mode", "Mode of automatic keyframe insertion for Objects and Bones");
+ RNA_def_property_ui_text(prop,
+ "Auto-Keying Mode",
+ "Mode of automatic keyframe insertion for Objects, Bones and Masks");
prop = RNA_def_property(srna, "use_record_with_nla", PROP_BOOLEAN, PROP_NONE);
RNA_def_property_boolean_sdna(prop, NULL, "autokey_flag", ANIMRECORD_FLAG_WITHNLA);
@@ -3823,7 +3849,7 @@ static void rna_def_unit_settings(BlenderRNA *brna)
"Scale to use when converting between blender units and dimensions."
" When working at microscopic or astronomical scale, a small or large unit scale"
" respectively can be used to avoid numerical precision problems");
- RNA_def_property_range(prop, 0.00001, 100000.0);
+ RNA_def_property_range(prop, 1e-9f, 1e+9f);
RNA_def_property_ui_range(prop, 0.001, 100.0, 0.1, 6);
RNA_def_property_update(prop, NC_WINDOW, NULL);
@@ -4859,13 +4885,23 @@ static void rna_def_bake_data(BlenderRNA *brna)
RNA_def_property_ui_text(prop, "Margin", "Extends the baked result as a post process filter");
RNA_def_property_update(prop, NC_SCENE | ND_RENDER_OPTIONS, NULL);
+ prop = RNA_def_property(srna, "max_ray_distance", PROP_FLOAT, PROP_DISTANCE);
+ RNA_def_property_range(prop, 0.0, FLT_MAX);
+ RNA_def_property_ui_range(prop, 0.0, 1.0, 1, 3);
+ RNA_def_property_ui_text(prop,
+ "Max Ray Distance",
+ "The maximum ray distance for matching points between the active and "
+ "selected objects. If zero, there is no limit");
+ RNA_def_property_update(prop, NC_SCENE | ND_RENDER_OPTIONS, NULL);
+
prop = RNA_def_property(srna, "cage_extrusion", PROP_FLOAT, PROP_DISTANCE);
RNA_def_property_range(prop, 0.0, FLT_MAX);
RNA_def_property_ui_range(prop, 0.0, 1.0, 1, 3);
RNA_def_property_ui_text(
prop,
"Cage Extrusion",
- "Distance to use for the inward ray cast when using selected to active");
+ "Inflate the active object by the specified distance for baking. This helps matching to "
+ "points nearer to the outside of the selected object meshes");
RNA_def_property_update(prop, NC_SCENE | ND_RENDER_OPTIONS, NULL);
prop = RNA_def_property(srna, "normal_space", PROP_ENUM, PROP_NONE);
@@ -5698,6 +5734,16 @@ static void rna_def_scene_render_data(BlenderRNA *brna)
{0, NULL, 0, NULL, NULL},
};
+ static const EnumPropertyItem meta_input_items[] = {
+ {0, "SCENE", 0, "Scene", "Use metadata from the current scene"},
+ {R_STAMP_STRIPMETA,
+ "STRIPS",
+ 0,
+ "Sequencer Strips",
+ "Use metadata from the strips in the sequencer"},
+ {0, NULL, 0, NULL, NULL},
+ };
+
rna_def_scene_ffmpeg_settings(brna);
srna = RNA_def_struct(brna, "RenderSettings", NULL);
@@ -6215,10 +6261,10 @@ static void rna_def_scene_render_data(BlenderRNA *brna)
prop, "Stamp Labels", "Display stamp labels (\"Camera\" in front of camera name, etc.)");
RNA_def_property_update(prop, NC_SCENE | ND_RENDER_OPTIONS, NULL);
- prop = RNA_def_property(srna, "use_stamp_strip_meta", PROP_BOOLEAN, PROP_NONE);
- RNA_def_property_boolean_sdna(prop, NULL, "stamp", R_STAMP_STRIPMETA);
- RNA_def_property_ui_text(
- prop, "Strip Metadata", "Use metadata from the strips in the sequencer");
+ prop = RNA_def_property(srna, "metadata_input", PROP_ENUM, PROP_NONE); /* as an enum */
+ RNA_def_property_enum_bitflag_sdna(prop, NULL, "stamp");
+ RNA_def_property_enum_items(prop, meta_input_items);
+ RNA_def_property_ui_text(prop, "Metadata Input", "Where to take the metadata from");
RNA_def_property_update(prop, NC_SCENE | ND_RENDER_OPTIONS, NULL);
prop = RNA_def_property(srna, "use_stamp_memory", PROP_BOOLEAN, PROP_NONE);
@@ -6380,12 +6426,6 @@ static void rna_def_scene_render_data(BlenderRNA *brna)
prop, "Simplify Child Particles", "Global child particles percentage during rendering");
RNA_def_property_update(prop, 0, "rna_Scene_simplify_update");
- prop = RNA_def_property(srna, "use_simplify_smoke_highres", PROP_BOOLEAN, PROP_NONE);
- RNA_def_property_boolean_negative_sdna(prop, NULL, "simplify_smoke_ignore_highres", 1);
- RNA_def_property_ui_text(
- prop, "Use High-resolution Smoke", "Display high-resolution smoke in the viewport");
- RNA_def_property_update(prop, NC_OBJECT | ND_DRAW, NULL);
-
/* Grease Pencil - Simplify Options */
prop = RNA_def_property(srna, "simplify_gpencil", PROP_BOOLEAN, PROP_NONE);
RNA_def_property_boolean_sdna(prop, NULL, "simplify_gpencil", SIMPLIFY_GPENCIL_ENABLE);
@@ -7180,6 +7220,28 @@ static void rna_def_scene_eevee(BlenderRNA *brna)
RNA_def_property_override_flag(prop, PROPOVERRIDE_OVERRIDABLE_LIBRARY);
}
+static void rna_def_scene_gpencil(BlenderRNA *brna)
+{
+ StructRNA *srna;
+ PropertyRNA *prop;
+
+ srna = RNA_def_struct(brna, "SceneGpencil", NULL);
+ RNA_def_struct_path_func(srna, "rna_SceneGpencil_path");
+ RNA_def_struct_ui_text(srna, "Grease Pencil Render", "Render settings");
+
+ prop = RNA_def_property(srna, "antialias_threshold", PROP_FLOAT, PROP_NONE);
+ RNA_def_property_float_sdna(prop, NULL, "smaa_threshold");
+ RNA_def_property_float_default(prop, 1.0f);
+ RNA_def_property_range(prop, 0.0f, FLT_MAX);
+ RNA_def_property_ui_range(prop, 0.0f, 2.0f, 1, 3);
+ RNA_def_property_ui_text(prop,
+ "Anti-Aliasing Threshold",
+ "Threshold for edge detection algorithm (higher values might overblur "
+ "some part of the image)");
+ RNA_def_property_override_flag(prop, PROPOVERRIDE_OVERRIDABLE_LIBRARY);
+ RNA_def_property_update(prop, NC_SCENE | ND_RENDER_OPTIONS, NULL);
+}
+
void RNA_def_scene(BlenderRNA *brna)
{
StructRNA *srna;
@@ -7653,6 +7715,11 @@ void RNA_def_scene(BlenderRNA *brna)
RNA_def_property_struct_type(prop, "SceneEEVEE");
RNA_def_property_ui_text(prop, "EEVEE", "EEVEE settings for the scene");
+ /* Grease Pencil */
+ prop = RNA_def_property(srna, "grease_pencil_settings", PROP_POINTER, PROP_NONE);
+ RNA_def_property_struct_type(prop, "SceneGpencil");
+ RNA_def_property_ui_text(prop, "Grease Pencil", "Grease Pencil settings for the scene");
+
/* Nestled Data */
/* *** Non-Animated *** */
RNA_define_animate_sdna(false);
@@ -7671,6 +7738,7 @@ void RNA_def_scene(BlenderRNA *brna)
rna_def_scene_display(brna);
rna_def_scene_eevee(brna);
rna_def_view_layer_eevee(brna);
+ rna_def_scene_gpencil(brna);
RNA_define_animate_sdna(true);
/* *** Animated *** */
rna_def_scene_render_data(brna);
diff --git a/source/blender/makesrna/intern/rna_scene_api.c b/source/blender/makesrna/intern/rna_scene_api.c
index c832c50bd5d..1d03b16d5bb 100644
--- a/source/blender/makesrna/intern/rna_scene_api.c
+++ b/source/blender/makesrna/intern/rna_scene_api.c
@@ -50,7 +50,6 @@ const EnumPropertyItem rna_enum_abc_compression_items[] = {
#ifdef RNA_RUNTIME
-# include "BKE_animsys.h"
# include "BKE_editmesh.h"
# include "BKE_global.h"
# include "BKE_image.h"
@@ -89,8 +88,8 @@ static void rna_Scene_frame_set(Scene *scene, Main *bmain, int frame, float subf
# endif
if (BKE_scene_camera_switch_update(scene)) {
- for (bScreen *sc = bmain->screens.first; sc; sc = sc->id.next) {
- BKE_screen_view3d_scene_sync(sc, scene);
+ for (bScreen *screen = bmain->screens.first; screen; screen = screen->id.next) {
+ BKE_screen_view3d_scene_sync(screen, scene);
}
}
@@ -161,7 +160,7 @@ static void rna_Scene_ray_cast(Scene *scene,
normalize_v3(direction);
Depsgraph *depsgraph = BKE_scene_get_depsgraph(bmain, scene, view_layer, true);
- SnapObjectContext *sctx = ED_transform_snap_object_context_create(bmain, scene, 0);
+ SnapObjectContext *sctx = ED_transform_snap_object_context_create(scene, 0);
bool ret = ED_transform_snap_object_project_ray_ex(sctx,
depsgraph,
diff --git a/source/blender/makesrna/intern/rna_screen.c b/source/blender/makesrna/intern/rna_screen.c
index c6245f51e15..20ae69dc031 100644
--- a/source/blender/makesrna/intern/rna_screen.c
+++ b/source/blender/makesrna/intern/rna_screen.c
@@ -98,8 +98,8 @@ static int rna_region_alignment_get(PointerRNA *ptr)
static bool rna_Screen_fullscreen_get(PointerRNA *ptr)
{
- bScreen *sc = (bScreen *)ptr->data;
- return (sc->state == SCREENMAXIMIZED);
+ bScreen *screen = (bScreen *)ptr->data;
+ return (screen->state == SCREENMAXIMIZED);
}
/* UI compatible list: should not be needed, but for now we need to keep EMPTY
@@ -116,10 +116,10 @@ static const EnumPropertyItem *rna_Area_type_itemf(bContext *UNUSED(C),
static int rna_Area_type_get(PointerRNA *ptr)
{
- ScrArea *sa = (ScrArea *)ptr->data;
+ ScrArea *area = (ScrArea *)ptr->data;
/* Usually 'spacetype' is used. It lags behind a bit while switching area
* type though, then we use 'butspacetype' instead (T41435). */
- return (sa->butspacetype == SPACE_EMPTY) ? sa->spacetype : sa->butspacetype;
+ return (area->butspacetype == SPACE_EMPTY) ? area->spacetype : area->butspacetype;
}
static void rna_Area_type_set(PointerRNA *ptr, int value)
@@ -131,17 +131,17 @@ static void rna_Area_type_set(PointerRNA *ptr, int value)
return;
}
- ScrArea *sa = (ScrArea *)ptr->data;
- sa->butspacetype = value;
+ ScrArea *area = (ScrArea *)ptr->data;
+ area->butspacetype = value;
}
static void rna_Area_type_update(bContext *C, PointerRNA *ptr)
{
- bScreen *sc = (bScreen *)ptr->owner_id;
- ScrArea *sa = (ScrArea *)ptr->data;
+ bScreen *screen = (bScreen *)ptr->owner_id;
+ ScrArea *area = (ScrArea *)ptr->data;
/* Running update without having called 'set', see: T64049 */
- if (sa->butspacetype == SPACE_EMPTY) {
+ if (area->butspacetype == SPACE_EMPTY) {
return;
}
@@ -149,23 +149,23 @@ static void rna_Area_type_update(bContext *C, PointerRNA *ptr)
wmWindow *win;
/* XXX this call still use context, so we trick it to work in the right context */
for (win = wm->windows.first; win; win = win->next) {
- if (sc == WM_window_get_active_screen(win)) {
+ if (screen == WM_window_get_active_screen(win)) {
wmWindow *prevwin = CTX_wm_window(C);
ScrArea *prevsa = CTX_wm_area(C);
ARegion *prevar = CTX_wm_region(C);
CTX_wm_window_set(C, win);
- CTX_wm_area_set(C, sa);
+ CTX_wm_area_set(C, area);
CTX_wm_region_set(C, NULL);
- ED_area_newspace(C, sa, sa->butspacetype, true);
- ED_area_tag_redraw(sa);
+ ED_area_newspace(C, area, area->butspacetype, true);
+ ED_area_tag_redraw(area);
/* Unset so that rna_Area_type_get uses spacetype instead. */
- sa->butspacetype = SPACE_EMPTY;
+ area->butspacetype = SPACE_EMPTY;
/* It is possible that new layers becomes visible. */
- if (sa->spacetype == SPACE_VIEW3D) {
+ if (area->spacetype == SPACE_VIEW3D) {
DEG_on_visible_update(CTX_data_main(C), false);
}
@@ -213,51 +213,55 @@ static const EnumPropertyItem *rna_Area_ui_type_itemf(bContext *C,
static int rna_Area_ui_type_get(PointerRNA *ptr)
{
- ScrArea *sa = ptr->data;
+ ScrArea *area = ptr->data;
const int area_type = rna_Area_type_get(ptr);
- const bool area_changing = sa->butspacetype != SPACE_EMPTY;
+ const bool area_changing = area->butspacetype != SPACE_EMPTY;
int value = area_type << 16;
- /* sa->type can be NULL (when not yet initialized), try to do it now. */
- /* Copied from `ED_area_initialize()`.*/
- if (sa->type == NULL || area_changing) {
- sa->type = BKE_spacetype_from_id(area_type);
- if (sa->type == NULL) {
- sa->spacetype = SPACE_VIEW3D;
- sa->type = BKE_spacetype_from_id(sa->spacetype);
+ /* Area->type can be NULL when not yet initialized (for example when accessed
+ * through the outliner or API when not visible), or it can be wrong while
+ * the area type is changing.
+ * So manually do the lookup in those cases, but do not actually change area->type
+ * since that prevents a proper exit when the area type is changing.
+ * Logic copied from `ED_area_initialize()`.*/
+ SpaceType *type = area->type;
+ if (type == NULL || area_changing) {
+ type = BKE_spacetype_from_id(area_type);
+ if (type == NULL) {
+ type = BKE_spacetype_from_id(SPACE_VIEW3D);
}
- BLI_assert(sa->type != NULL);
+ BLI_assert(type != NULL);
}
- if (sa->type->space_subtype_item_extend != NULL) {
- value |= area_changing ? sa->butspacetype_subtype : sa->type->space_subtype_get(sa);
+ if (type->space_subtype_item_extend != NULL) {
+ value |= area_changing ? area->butspacetype_subtype : type->space_subtype_get(area);
}
return value;
}
static void rna_Area_ui_type_set(PointerRNA *ptr, int value)
{
- ScrArea *sa = ptr->data;
+ ScrArea *area = ptr->data;
const int space_type = value >> 16;
SpaceType *st = BKE_spacetype_from_id(space_type);
rna_Area_type_set(ptr, space_type);
if (st && st->space_subtype_item_extend != NULL) {
- sa->butspacetype_subtype = value & 0xffff;
+ area->butspacetype_subtype = value & 0xffff;
}
}
static void rna_Area_ui_type_update(bContext *C, PointerRNA *ptr)
{
- ScrArea *sa = ptr->data;
- SpaceType *st = BKE_spacetype_from_id(sa->butspacetype);
+ ScrArea *area = ptr->data;
+ SpaceType *st = BKE_spacetype_from_id(area->butspacetype);
rna_Area_type_update(C, ptr);
- if ((sa->type == st) && (st->space_subtype_item_extend != NULL)) {
- st->space_subtype_set(sa, sa->butspacetype_subtype);
+ if ((area->type == st) && (st->space_subtype_item_extend != NULL)) {
+ st->space_subtype_set(area, area->butspacetype_subtype);
}
- sa->butspacetype_subtype = 0;
+ area->butspacetype_subtype = 0;
}
static void rna_View2D_region_to_view(struct View2D *v2d, float x, float y, float result[2])
diff --git a/source/blender/makesrna/intern/rna_sculpt_paint.c b/source/blender/makesrna/intern/rna_sculpt_paint.c
index 04a54063a03..381908f7ada 100644
--- a/source/blender/makesrna/intern/rna_sculpt_paint.c
+++ b/source/blender/makesrna/intern/rna_sculpt_paint.c
@@ -507,14 +507,14 @@ static void rna_ImaPaint_canvas_update(bContext *C, PointerRNA *UNUSED(ptr))
ViewLayer *view_layer = CTX_data_view_layer(C);
Object *ob = OBACT(view_layer);
Object *obedit = OBEDIT_FROM_OBACT(ob);
- bScreen *sc;
+ bScreen *screen;
Image *ima = scene->toolsettings->imapaint.canvas;
- for (sc = bmain->screens.first; sc; sc = sc->id.next) {
- ScrArea *sa;
- for (sa = sc->areabase.first; sa; sa = sa->next) {
+ for (screen = bmain->screens.first; screen; screen = screen->id.next) {
+ ScrArea *area;
+ for (area = screen->areabase.first; area; area = area->next) {
SpaceLink *slink;
- for (slink = sa->spacedata.first; slink; slink = slink->next) {
+ for (slink = area->spacedata.first; slink; slink = slink->next) {
if (slink->spacetype == SPACE_IMAGE) {
SpaceImage *sima = (SpaceImage *)slink;
@@ -617,6 +617,14 @@ static void rna_def_paint(BlenderRNA *brna)
prop, "Fast Navigate", "For multires, show low resolution while navigating the view");
RNA_def_property_update(prop, NC_SCENE | ND_TOOLSETTINGS, NULL);
+ prop = RNA_def_property(srna, "use_sculpt_delay_updates", PROP_BOOLEAN, PROP_NONE);
+ RNA_def_property_boolean_sdna(prop, NULL, "flags", PAINT_SCULPT_DELAY_UPDATES);
+ RNA_def_property_ui_text(
+ prop,
+ "Delay Viewport Updates",
+ "Update the geometry when it enters the view, providing faster view navigation");
+ RNA_def_property_update(prop, NC_SCENE | ND_TOOLSETTINGS, NULL);
+
prop = RNA_def_property(srna, "input_samples", PROP_INT, PROP_UNSIGNED);
RNA_def_property_int_sdna(prop, NULL, "num_input_samples");
RNA_def_property_ui_range(prop, 1, PAINT_MAX_INPUT_SAMPLES, 1, -1);
@@ -815,6 +823,34 @@ static void rna_def_sculpt(BlenderRNA *brna)
RNA_def_property_flag(prop, PROP_CONTEXT_UPDATE);
RNA_def_property_update(prop, NC_OBJECT | ND_DRAW, "rna_Sculpt_update");
+ prop = RNA_def_property(srna, "use_automasking_topology", PROP_BOOLEAN, PROP_NONE);
+ RNA_def_property_boolean_sdna(prop, NULL, "automasking_flags", BRUSH_AUTOMASKING_TOPOLOGY);
+ RNA_def_property_ui_text(prop,
+ "Topology Auto-masking",
+ "Affect only vertices connected to the active vertex under the brush");
+ RNA_def_property_update(prop, NC_SCENE | ND_TOOLSETTINGS, NULL);
+
+ prop = RNA_def_property(srna, "use_automasking_face_sets", PROP_BOOLEAN, PROP_NONE);
+ RNA_def_property_boolean_sdna(prop, NULL, "automasking_flags", BRUSH_AUTOMASKING_FACE_SETS);
+ RNA_def_property_ui_text(prop,
+ "Face Sets Auto-masking",
+ "Affect only vertices that share Face Sets with the active vertex");
+ RNA_def_property_update(prop, NC_SCENE | ND_TOOLSETTINGS, NULL);
+
+ prop = RNA_def_property(srna, "use_automasking_boundary_edges", PROP_BOOLEAN, PROP_NONE);
+ RNA_def_property_boolean_sdna(prop, NULL, "automasking_flags", BRUSH_AUTOMASKING_BOUNDARY_EDGES);
+ RNA_def_property_ui_text(
+ prop, "Mesh Boundary Auto-masking", "Do not affect non manifold boundary edges");
+ RNA_def_property_update(prop, NC_SCENE | ND_TOOLSETTINGS, NULL);
+
+ prop = RNA_def_property(srna, "use_automasking_boundary_face_sets", PROP_BOOLEAN, PROP_NONE);
+ RNA_def_property_boolean_sdna(
+ prop, NULL, "automasking_flags", BRUSH_AUTOMASKING_BOUNDARY_FACE_SETS);
+ RNA_def_property_ui_text(prop,
+ "Face Sets Boundary Auto-masking",
+ "Do not affect vertices that belong to a Face Set boundary");
+ RNA_def_property_update(prop, NC_SCENE | ND_TOOLSETTINGS, NULL);
+
prop = RNA_def_property(srna, "symmetrize_direction", PROP_ENUM, PROP_NONE);
RNA_def_property_enum_items(prop, rna_enum_symmetrize_direction_items);
RNA_def_property_ui_text(prop, "Direction", "Source and destination for symmetrize operator");
diff --git a/source/blender/makesrna/intern/rna_sequencer.c b/source/blender/makesrna/intern/rna_sequencer.c
index 6677105b771..39ea054456f 100644
--- a/source/blender/makesrna/intern/rna_sequencer.c
+++ b/source/blender/makesrna/intern/rna_sequencer.c
@@ -32,6 +32,7 @@
#include "BLT_translation.h"
+#include "BKE_anim_data.h"
#include "BKE_animsys.h"
#include "BKE_sequencer.h"
#include "BKE_sound.h"
@@ -286,11 +287,12 @@ static void do_sequence_frame_change_update(Scene *scene, Sequence *seq)
/* A simple wrapper around above func, directly usable as prop update func.
* Also invalidate cache if needed.
*/
-static void rna_Sequence_frame_change_update(Main *bmain, Scene *UNUSED(scene), PointerRNA *ptr)
+static void rna_Sequence_frame_change_update(Main *UNUSED(bmain),
+ Scene *UNUSED(scene),
+ PointerRNA *ptr)
{
Scene *scene = (Scene *)ptr->owner_id;
do_sequence_frame_change_update(scene, (Sequence *)ptr->data);
- rna_Sequence_invalidate_preprocessed_update(bmain, scene, ptr);
}
static void rna_Sequence_start_frame_set(PointerRNA *ptr, int value)
@@ -298,8 +300,10 @@ static void rna_Sequence_start_frame_set(PointerRNA *ptr, int value)
Sequence *seq = (Sequence *)ptr->data;
Scene *scene = (Scene *)ptr->owner_id;
+ BKE_sequence_invalidate_cache_composite(scene, seq);
BKE_sequence_translate(scene, seq, value - seq->start);
do_sequence_frame_change_update(scene, seq);
+ BKE_sequence_invalidate_cache_composite(scene, seq);
}
static void rna_Sequence_start_frame_final_set(PointerRNA *ptr, int value)
@@ -307,9 +311,11 @@ static void rna_Sequence_start_frame_final_set(PointerRNA *ptr, int value)
Sequence *seq = (Sequence *)ptr->data;
Scene *scene = (Scene *)ptr->owner_id;
+ BKE_sequence_invalidate_cache_composite(scene, seq);
BKE_sequence_tx_set_final_left(seq, value);
BKE_sequence_single_fix(seq);
do_sequence_frame_change_update(scene, seq);
+ BKE_sequence_invalidate_cache_composite(scene, seq);
}
static void rna_Sequence_end_frame_final_set(PointerRNA *ptr, int value)
@@ -317,9 +323,47 @@ static void rna_Sequence_end_frame_final_set(PointerRNA *ptr, int value)
Sequence *seq = (Sequence *)ptr->data;
Scene *scene = (Scene *)ptr->owner_id;
+ BKE_sequence_invalidate_cache_composite(scene, seq);
BKE_sequence_tx_set_final_right(seq, value);
BKE_sequence_single_fix(seq);
do_sequence_frame_change_update(scene, seq);
+ BKE_sequence_invalidate_cache_composite(scene, seq);
+}
+
+static void rna_Sequence_frame_offset_start_set(PointerRNA *ptr, int value)
+{
+ Sequence *seq = (Sequence *)ptr->data;
+ Scene *scene = (Scene *)ptr->owner_id;
+
+ BKE_sequence_invalidate_cache_composite(scene, seq);
+ seq->startofs = value;
+}
+
+static void rna_Sequence_frame_offset_end_set(PointerRNA *ptr, int value)
+{
+ Sequence *seq = (Sequence *)ptr->data;
+ Scene *scene = (Scene *)ptr->owner_id;
+
+ BKE_sequence_invalidate_cache_composite(scene, seq);
+ seq->endofs = value;
+}
+
+static void rna_Sequence_frame_still_start_set(PointerRNA *ptr, int value)
+{
+ Sequence *seq = (Sequence *)ptr->data;
+ Scene *scene = (Scene *)ptr->owner_id;
+
+ BKE_sequence_invalidate_cache_composite(scene, seq);
+ seq->startstill = value;
+}
+
+static void rna_Sequence_frame_still_end_set(PointerRNA *ptr, int value)
+{
+ Sequence *seq = (Sequence *)ptr->data;
+ Scene *scene = (Scene *)ptr->owner_id;
+
+ BKE_sequence_invalidate_cache_composite(scene, seq);
+ seq->endstill = value;
}
static void rna_Sequence_anim_startofs_final_set(PointerRNA *ptr, int value)
@@ -344,13 +388,49 @@ static void rna_Sequence_anim_endofs_final_set(PointerRNA *ptr, int value)
do_sequence_frame_change_update(scene, seq);
}
+static void rna_Sequence_anim_endofs_final_range(
+ PointerRNA *ptr, int *min, int *max, int *UNUSED(softmin), int *UNUSED(softmax))
+{
+ Sequence *seq = (Sequence *)ptr->data;
+
+ *min = 0;
+ *max = seq->len + seq->anim_endofs - seq->startofs - seq->endofs - 1;
+}
+
+static void rna_Sequence_anim_startofs_final_range(
+ PointerRNA *ptr, int *min, int *max, int *UNUSED(softmin), int *UNUSED(softmax))
+{
+ Sequence *seq = (Sequence *)ptr->data;
+
+ *min = 0;
+ *max = seq->len + seq->anim_startofs - seq->startofs - seq->endofs - 1;
+}
+
+static void rna_Sequence_frame_offset_start_range(
+ PointerRNA *ptr, int *min, int *max, int *UNUSED(softmin), int *UNUSED(softmax))
+{
+ Sequence *seq = (Sequence *)ptr->data;
+ *min = ELEM(seq->type, SEQ_TYPE_SOUND_RAM, SEQ_TYPE_SOUND_HD) ? 0 : INT_MIN;
+ *max = seq->len - seq->endofs - 1;
+}
+
+static void rna_Sequence_frame_offset_end_range(
+ PointerRNA *ptr, int *min, int *max, int *UNUSED(softmin), int *UNUSED(softmax))
+{
+ Sequence *seq = (Sequence *)ptr->data;
+ *min = ELEM(seq->type, SEQ_TYPE_SOUND_RAM, SEQ_TYPE_SOUND_HD) ? 0 : INT_MIN;
+ *max = seq->len - seq->startofs - 1;
+}
+
static void rna_Sequence_frame_length_set(PointerRNA *ptr, int value)
{
Sequence *seq = (Sequence *)ptr->data;
Scene *scene = (Scene *)ptr->owner_id;
+ BKE_sequence_invalidate_cache_composite(scene, seq);
BKE_sequence_tx_set_final_right(seq, BKE_sequence_tx_get_final_left(seq, false) + value);
do_sequence_frame_change_update(scene, seq);
+ BKE_sequence_invalidate_cache_composite(scene, seq);
}
static int rna_Sequence_frame_length_get(PointerRNA *ptr)
@@ -373,6 +453,7 @@ static void rna_Sequence_channel_set(PointerRNA *ptr, int value)
Editing *ed = BKE_sequencer_editing_get(scene, false);
ListBase *seqbase = BKE_sequence_seqbase(&ed->seqbase, seq);
+ BKE_sequence_invalidate_cache_composite(scene, seq);
/* check channel increment or decrement */
const int channel_delta = (value >= seq->machine) ? 1 : -1;
seq->machine = value;
@@ -382,14 +463,7 @@ static void rna_Sequence_channel_set(PointerRNA *ptr, int value)
BKE_sequence_base_shuffle_ex(seqbase, seq, scene, channel_delta);
}
BKE_sequencer_sort(scene);
-}
-
-static void rna_Sequence_frame_offset_range(
- PointerRNA *ptr, int *min, int *max, int *UNUSED(softmin), int *UNUSED(softmax))
-{
- Sequence *seq = (Sequence *)ptr->data;
- *min = ELEM(seq->type, SEQ_TYPE_SOUND_RAM, SEQ_TYPE_SOUND_HD) ? 0 : INT_MIN;
- *max = INT_MAX;
+ BKE_sequence_invalidate_cache_composite(scene, seq);
}
static void rna_Sequence_use_proxy_set(PointerRNA *ptr, bool value)
@@ -426,7 +500,7 @@ static void rna_Sequence_use_crop_set(PointerRNA *ptr, bool value)
}
}
-static int transform_seq_cmp_cb(Sequence *seq, void *arg_pt)
+static int transform_seq_cmp_fn(Sequence *seq, void *arg_pt)
{
SequenceSearchData *data = arg_pt;
@@ -445,7 +519,7 @@ static Sequence *sequence_get_by_transform(Editing *ed, StripTransform *transfor
data.data = transform;
/* irritating we need to search for our sequence! */
- BKE_sequencer_base_recursive_apply(&ed->seqbase, transform_seq_cmp_cb, &data);
+ BKE_sequencer_base_recursive_apply(&ed->seqbase, transform_seq_cmp_fn, &data);
return data.seq;
}
@@ -478,7 +552,7 @@ static void rna_SequenceTransform_update(Main *UNUSED(bmain),
BKE_sequence_invalidate_cache_preprocessed(scene, seq);
}
-static int crop_seq_cmp_cb(Sequence *seq, void *arg_pt)
+static int crop_seq_cmp_fn(Sequence *seq, void *arg_pt)
{
SequenceSearchData *data = arg_pt;
@@ -497,7 +571,7 @@ static Sequence *sequence_get_by_crop(Editing *ed, StripCrop *crop)
data.data = crop;
/* irritating we need to search for our sequence! */
- BKE_sequencer_base_recursive_apply(&ed->seqbase, crop_seq_cmp_cb, &data);
+ BKE_sequencer_base_recursive_apply(&ed->seqbase, crop_seq_cmp_fn, &data);
return data.seq;
}
@@ -800,13 +874,6 @@ static void rna_Sequence_reopen_files_update(Main *bmain, Scene *UNUSED(scene),
}
}
-static void rna_Sequence_mute_update(Main *UNUSED(bmain), Scene *UNUSED(scene), PointerRNA *ptr)
-{
- Scene *scene = (Scene *)ptr->owner_id;
-
- DEG_id_tag_update(&scene->id, ID_RECALC_SEQUENCER_STRIPS);
-}
-
static void rna_Sequence_filepath_update(Main *bmain, Scene *UNUSED(scene), PointerRNA *ptr)
{
Scene *scene = (Scene *)ptr->owner_id;
@@ -821,7 +888,7 @@ static void rna_Sequence_sound_update(Main *UNUSED(bmain), Scene *scene, Pointer
DEG_id_tag_update(&scene->id, ID_RECALC_SEQUENCER_STRIPS | ID_RECALC_AUDIO);
}
-static int seqproxy_seq_cmp_cb(Sequence *seq, void *arg_pt)
+static int seqproxy_seq_cmp_fn(Sequence *seq, void *arg_pt)
{
SequenceSearchData *data = arg_pt;
@@ -839,7 +906,7 @@ static Sequence *sequence_get_by_proxy(Editing *ed, StripProxy *proxy)
data.seq = NULL;
data.data = proxy;
- BKE_sequencer_base_recursive_apply(&ed->seqbase, seqproxy_seq_cmp_cb, &data);
+ BKE_sequencer_base_recursive_apply(&ed->seqbase, seqproxy_seq_cmp_fn, &data);
return data.seq;
}
@@ -875,7 +942,7 @@ static void rna_Sequence_opacity_set(PointerRNA *ptr, float value)
seq->blend_opacity = value * 100.0f;
}
-static int colbalance_seq_cmp_cb(Sequence *seq, void *arg_pt)
+static int colbalance_seq_cmp_fn(Sequence *seq, void *arg_pt)
{
SequenceSearchData *data = arg_pt;
@@ -909,7 +976,7 @@ static Sequence *sequence_get_by_colorbalance(Editing *ed,
data.data = cb;
/* irritating we need to search for our sequence! */
- BKE_sequencer_base_recursive_apply(&ed->seqbase, colbalance_seq_cmp_cb, &data);
+ BKE_sequencer_base_recursive_apply(&ed->seqbase, colbalance_seq_cmp_fn, &data);
*r_smd = data.smd;
@@ -1013,7 +1080,7 @@ static void rna_SequenceEditor_overlay_frame_set(PointerRNA *ptr, int value)
}
}
-static int modifier_seq_cmp_cb(Sequence *seq, void *arg_pt)
+static int modifier_seq_cmp_fn(Sequence *seq, void *arg_pt)
{
SequenceSearchData *data = arg_pt;
@@ -1033,7 +1100,7 @@ static Sequence *sequence_get_by_modifier(Editing *ed, SequenceModifierData *smd
data.data = smd;
/* irritating we need to search for our sequence! */
- BKE_sequencer_base_recursive_apply(&ed->seqbase, modifier_seq_cmp_cb, &data);
+ BKE_sequencer_base_recursive_apply(&ed->seqbase, modifier_seq_cmp_fn, &data);
return data.seq;
}
@@ -1616,7 +1683,7 @@ static void rna_def_sequence(BlenderRNA *brna)
RNA_def_property_ui_icon(prop, ICON_CHECKBOX_HLT, -1);
RNA_def_property_ui_text(
prop, "Mute", "Disable strip so that it cannot be viewed in the output");
- RNA_def_property_update(prop, NC_SCENE | ND_SEQUENCER, "rna_Sequence_mute_update");
+ RNA_def_property_update(prop, NC_SCENE | ND_SEQUENCER, "rna_Sequence_invalidate_raw_update");
prop = RNA_def_property(srna, "lock", PROP_BOOLEAN, PROP_NONE);
RNA_def_property_boolean_sdna(prop, NULL, "flag", SEQ_LOCK);
@@ -1626,6 +1693,7 @@ static void rna_def_sequence(BlenderRNA *brna)
RNA_def_property_update(prop, NC_SCENE | ND_SEQUENCER, NULL);
/* strip positioning */
+ /* Cache has to be invalidated before and after transformation. */
prop = RNA_def_property(srna, "frame_final_duration", PROP_INT, PROP_TIME);
RNA_def_property_range(prop, 1, MAXFRAME);
RNA_def_property_clear_flag(prop, PROP_ANIMATABLE);
@@ -1683,14 +1751,16 @@ static void rna_def_sequence(BlenderRNA *brna)
RNA_def_property_int_sdna(prop, NULL, "startofs");
// RNA_def_property_clear_flag(prop, PROP_EDITABLE); /* overlap tests */
RNA_def_property_ui_text(prop, "Start Offset", "");
- RNA_def_property_int_funcs(prop, NULL, NULL, "rna_Sequence_frame_offset_range");
+ RNA_def_property_int_funcs(
+ prop, NULL, "rna_Sequence_frame_offset_start_set", "rna_Sequence_frame_offset_start_range");
RNA_def_property_update(prop, NC_SCENE | ND_SEQUENCER, "rna_Sequence_frame_change_update");
prop = RNA_def_property(srna, "frame_offset_end", PROP_INT, PROP_TIME);
RNA_def_property_int_sdna(prop, NULL, "endofs");
// RNA_def_property_clear_flag(prop, PROP_EDITABLE); /* overlap tests */
RNA_def_property_ui_text(prop, "End Offset", "");
- RNA_def_property_int_funcs(prop, NULL, NULL, "rna_Sequence_frame_offset_range");
+ RNA_def_property_int_funcs(
+ prop, NULL, "rna_Sequence_frame_offset_end_set", "rna_Sequence_frame_offset_end_range");
RNA_def_property_update(prop, NC_SCENE | ND_SEQUENCER, "rna_Sequence_frame_change_update");
prop = RNA_def_property(srna, "frame_still_start", PROP_INT, PROP_TIME);
@@ -1698,6 +1768,7 @@ static void rna_def_sequence(BlenderRNA *brna)
// RNA_def_property_clear_flag(prop, PROP_EDITABLE); /* overlap tests */
RNA_def_property_range(prop, 0, MAXFRAME);
RNA_def_property_ui_text(prop, "Start Still", "");
+ RNA_def_property_int_funcs(prop, NULL, "rna_Sequence_frame_still_start_set", NULL);
RNA_def_property_update(prop, NC_SCENE | ND_SEQUENCER, "rna_Sequence_frame_change_update");
prop = RNA_def_property(srna, "frame_still_end", PROP_INT, PROP_TIME);
@@ -1705,6 +1776,7 @@ static void rna_def_sequence(BlenderRNA *brna)
// RNA_def_property_clear_flag(prop, PROP_EDITABLE); /* overlap tests */
RNA_def_property_range(prop, 0, MAXFRAME);
RNA_def_property_ui_text(prop, "End Still", "");
+ RNA_def_property_int_funcs(prop, NULL, "rna_Sequence_frame_still_end_set", NULL);
RNA_def_property_update(prop, NC_SCENE | ND_SEQUENCER, "rna_Sequence_frame_change_update");
prop = RNA_def_property(srna, "channel", PROP_INT, PROP_UNSIGNED);
@@ -1941,9 +2013,10 @@ static void rna_def_editor(BlenderRNA *brna)
prop = RNA_def_property(srna, "use_prefetch", PROP_BOOLEAN, PROP_NONE);
RNA_def_property_boolean_sdna(prop, NULL, "cache_flag", SEQ_CACHE_PREFETCH_ENABLE);
- RNA_def_property_ui_text(prop,
- "Prefetch frames",
- "Render frames ahead of playhead in background for faster playback");
+ RNA_def_property_ui_text(
+ prop,
+ "Prefetch Frames",
+ "Render frames ahead of current frame in the background for faster playback");
RNA_def_property_update(prop, NC_SCENE | ND_SEQUENCER, NULL);
prop = RNA_def_property(srna, "recycle_max_cost", PROP_FLOAT, PROP_NONE);
@@ -2069,8 +2142,10 @@ static void rna_def_input(StructRNA *srna)
prop = RNA_def_property(srna, "animation_offset_start", PROP_INT, PROP_UNSIGNED);
RNA_def_property_int_sdna(prop, NULL, "anim_startofs");
RNA_def_property_clear_flag(prop, PROP_ANIMATABLE);
- RNA_def_property_int_funcs(
- prop, NULL, "rna_Sequence_anim_startofs_final_set", NULL); /* overlap tests */
+ RNA_def_property_int_funcs(prop,
+ NULL,
+ "rna_Sequence_anim_startofs_final_set",
+ "rna_Sequence_anim_startofs_final_range"); /* overlap tests */
RNA_def_property_ui_text(prop, "Animation Start Offset", "Animation start offset (trim start)");
RNA_def_property_update(
prop, NC_SCENE | ND_SEQUENCER, "rna_Sequence_invalidate_preprocessed_update");
@@ -2078,8 +2153,10 @@ static void rna_def_input(StructRNA *srna)
prop = RNA_def_property(srna, "animation_offset_end", PROP_INT, PROP_UNSIGNED);
RNA_def_property_int_sdna(prop, NULL, "anim_endofs");
RNA_def_property_clear_flag(prop, PROP_ANIMATABLE);
- RNA_def_property_int_funcs(
- prop, NULL, "rna_Sequence_anim_endofs_final_set", NULL); /* overlap tests */
+ RNA_def_property_int_funcs(prop,
+ NULL,
+ "rna_Sequence_anim_endofs_final_set",
+ "rna_Sequence_anim_endofs_final_range"); /* overlap tests */
RNA_def_property_ui_text(prop, "Animation End Offset", "Animation end offset (trim end)");
RNA_def_property_update(
prop, NC_SCENE | ND_SEQUENCER, "rna_Sequence_invalidate_preprocessed_update");
@@ -2466,12 +2543,12 @@ static void rna_def_wipe(StructRNA *srna)
PropertyRNA *prop;
static const EnumPropertyItem wipe_type_items[] = {
- {0, "SINGLE", 0, "Single", ""},
- {1, "DOUBLE", 0, "Double", ""},
- /* not used yet {2, "BOX", 0, "Box", ""}, */
- /* not used yet {3, "CROSS", 0, "Cross", ""}, */
- {4, "IRIS", 0, "Iris", ""},
- {5, "CLOCK", 0, "Clock", ""},
+ {DO_SINGLE_WIPE, "SINGLE", 0, "Single", ""},
+ {DO_DOUBLE_WIPE, "DOUBLE", 0, "Double", ""},
+ /* not used yet {DO_BOX_WIPE, "BOX", 0, "Box", ""}, */
+ /* not used yet {DO_CROSS_WIPE, "CROSS", 0, "Cross", ""}, */
+ {DO_IRIS_WIPE, "IRIS", 0, "Iris", ""},
+ {DO_CLOCK_WIPE, "CLOCK", 0, "Clock", ""},
{0, NULL, 0, NULL, NULL},
};
@@ -2677,6 +2754,13 @@ static void rna_def_speed_control(StructRNA *srna)
prop, "Scale to Length", "Scale values from 0.0 to 1.0 to target sequence length");
RNA_def_property_update(
prop, NC_SCENE | ND_SEQUENCER, "rna_Sequence_invalidate_preprocessed_update");
+
+ prop = RNA_def_property(srna, "frame_interpolation_mode", PROP_BOOLEAN, PROP_NONE);
+ RNA_def_property_boolean_sdna(prop, NULL, "flags", SEQ_SPEED_USE_INTERPOLATION);
+ RNA_def_property_ui_text(
+ prop, "Frame interpolation", "Do crossfade blending between current and next frame");
+ RNA_def_property_update(
+ prop, NC_SCENE | ND_SEQUENCER, "rna_Sequence_invalidate_preprocessed_update");
}
static void rna_def_gaussian_blur(StructRNA *srna)
diff --git a/source/blender/makesrna/intern/rna_sequencer_api.c b/source/blender/makesrna/intern/rna_sequencer_api.c
index d49a2ed1ea0..6c8f51f97a1 100644
--- a/source/blender/makesrna/intern/rna_sequencer_api.c
+++ b/source/blender/makesrna/intern/rna_sequencer_api.c
@@ -193,7 +193,7 @@ static Sequence *rna_Sequences_new_image(ID *id,
if (seq->strip->stripdata->name[0] == '\0') {
BKE_report(reports, RPT_ERROR, "Sequences.new_image: unable to open image file");
BLI_remlink(&ed->seqbase, seq);
- BKE_sequence_free(scene, seq);
+ BKE_sequence_free(scene, seq, true);
return NULL;
}
@@ -382,7 +382,7 @@ static void rna_Sequences_remove(
return;
}
- BKE_sequence_free(scene, seq);
+ BKE_sequence_free(scene, seq, true);
RNA_POINTER_INVALIDATE(seq_ptr);
DEG_relations_tag_update(bmain);
diff --git a/source/blender/makesrna/intern/rna_shader_fx.c b/source/blender/makesrna/intern/rna_shader_fx.c
index f7f68d535ec..71f767fa93b 100644
--- a/source/blender/makesrna/intern/rna_shader_fx.c
+++ b/source/blender/makesrna/intern/rna_shader_fx.c
@@ -542,7 +542,7 @@ static void rna_def_shader_fx_glow(BlenderRNA *brna)
prop = RNA_def_property(srna, "size", PROP_FLOAT, PROP_XYZ);
RNA_def_property_float_sdna(prop, NULL, "blur");
RNA_def_property_range(prop, 0.0f, FLT_MAX);
- RNA_def_property_ui_text(prop, "Size", "Size of th effect");
+ RNA_def_property_ui_text(prop, "Size", "Size of the effect");
RNA_def_property_update(prop, NC_OBJECT | ND_MODIFIER, "rna_ShaderFx_update");
prop = RNA_def_property(srna, "samples", PROP_INT, PROP_NONE);
diff --git a/source/blender/makesrna/intern/rna_simulation.c b/source/blender/makesrna/intern/rna_simulation.c
new file mode 100644
index 00000000000..789ea299feb
--- /dev/null
+++ b/source/blender/makesrna/intern/rna_simulation.c
@@ -0,0 +1,56 @@
+/*
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+
+/** \file
+ * \ingroup RNA
+ */
+
+#include <stdlib.h>
+
+#include "RNA_define.h"
+#include "RNA_enum_types.h"
+
+#include "DNA_simulation_types.h"
+
+#include "rna_internal.h"
+
+#ifdef RNA_RUNTIME
+
+#else
+
+static void rna_def_simulation(BlenderRNA *brna)
+{
+ StructRNA *srna;
+ PropertyRNA *prop;
+
+ srna = RNA_def_struct(brna, "Simulation", "ID");
+ RNA_def_struct_ui_text(srna, "Simulation", "Simulation data-block");
+ RNA_def_struct_ui_icon(srna, ICON_PHYSICS); /* TODO: Use correct icon. */
+
+ prop = RNA_def_property(srna, "node_tree", PROP_POINTER, PROP_NONE);
+ RNA_def_property_pointer_sdna(prop, NULL, "nodetree");
+ RNA_def_property_ui_text(prop, "Node Tree", "Node tree defining the simulation");
+
+ /* common */
+ rna_def_animdata_common(srna);
+}
+
+void RNA_def_simulation(BlenderRNA *brna)
+{
+ rna_def_simulation(brna);
+}
+
+#endif
diff --git a/source/blender/makesrna/intern/rna_sound_api.c b/source/blender/makesrna/intern/rna_sound_api.c
index 2be0ed966f1..418205426d2 100644
--- a/source/blender/makesrna/intern/rna_sound_api.c
+++ b/source/blender/makesrna/intern/rna_sound_api.c
@@ -10,7 +10,7 @@
* 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,
+ * 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) 2015 by the Blender Foundation.
diff --git a/source/blender/makesrna/intern/rna_space.c b/source/blender/makesrna/intern/rna_space.c
index cf515792252..df0d514fabf 100644
--- a/source/blender/makesrna/intern/rna_space.c
+++ b/source/blender/makesrna/intern/rna_space.c
@@ -34,6 +34,7 @@
#include "ED_text.h"
+#include "BLI_listbase.h"
#include "BLI_math.h"
#include "DNA_action_types.h"
@@ -44,6 +45,7 @@
#include "DNA_node_types.h"
#include "DNA_object_types.h"
#include "DNA_sequence_types.h"
+#include "DNA_simulation_types.h"
#include "DNA_space_types.h"
#include "DNA_view3d_types.h"
#include "DNA_workspace_types.h"
@@ -481,6 +483,13 @@ const EnumPropertyItem rna_enum_file_sort_items[] = {
{0, NULL, 0, NULL, NULL},
};
+static const EnumPropertyItem rna_enum_curve_display_handle_items[] = {
+ {CURVE_HANDLE_NONE, "NONE", 0, "None", ""},
+ {CURVE_HANDLE_SELECTED, "SELECTED", 0, "Selected", ""},
+ {CURVE_HANDLE_ALL, "ALL", 0, "All", ""},
+ {0, NULL, 0, NULL, NULL},
+};
+
#ifdef RNA_RUNTIME
# include "DNA_anim_types.h"
@@ -491,7 +500,7 @@ const EnumPropertyItem rna_enum_file_sort_items[] = {
# include "BLI_path_util.h"
# include "BLI_string.h"
-# include "BKE_animsys.h"
+# include "BKE_anim_data.h"
# include "BKE_brush.h"
# include "BKE_colortools.h"
# include "BKE_context.h"
@@ -530,7 +539,7 @@ static StructRNA *rna_Space_refine(struct PointerRNA *ptr)
{
SpaceLink *space = (SpaceLink *)ptr->data;
- switch (space->spacetype) {
+ switch ((eSpace_Type)space->spacetype) {
case SPACE_VIEW3D:
return &RNA_SpaceView3D;
case SPACE_GRAPH:
@@ -561,46 +570,53 @@ static StructRNA *rna_Space_refine(struct PointerRNA *ptr)
return &RNA_SpacePreferences;
case SPACE_CLIP:
return &RNA_SpaceClipEditor;
- default:
- return &RNA_Space;
+
+ /* Currently no type info. */
+ case SPACE_SCRIPT:
+ case SPACE_EMPTY:
+ case SPACE_TOPBAR:
+ case SPACE_STATUSBAR:
+ break;
}
+
+ return &RNA_Space;
}
static ScrArea *rna_area_from_space(PointerRNA *ptr)
{
- bScreen *sc = (bScreen *)ptr->owner_id;
+ bScreen *screen = (bScreen *)ptr->owner_id;
SpaceLink *link = (SpaceLink *)ptr->data;
- return BKE_screen_find_area_from_space(sc, link);
+ return BKE_screen_find_area_from_space(screen, link);
}
-static void area_region_from_regiondata(bScreen *sc,
+static void area_region_from_regiondata(bScreen *screen,
void *regiondata,
- ScrArea **r_sa,
- ARegion **r_ar)
+ ScrArea **r_area,
+ ARegion **r_region)
{
- ScrArea *sa;
+ ScrArea *area;
ARegion *region;
- *r_sa = NULL;
- *r_ar = NULL;
+ *r_area = NULL;
+ *r_region = NULL;
- for (sa = sc->areabase.first; sa; sa = sa->next) {
- for (region = sa->regionbase.first; region; region = region->next) {
+ for (area = screen->areabase.first; area; area = area->next) {
+ for (region = area->regionbase.first; region; region = region->next) {
if (region->regiondata == regiondata) {
- *r_sa = sa;
- *r_ar = region;
+ *r_area = area;
+ *r_region = region;
return;
}
}
}
}
-static void rna_area_region_from_regiondata(PointerRNA *ptr, ScrArea **r_sa, ARegion **r_ar)
+static void rna_area_region_from_regiondata(PointerRNA *ptr, ScrArea **r_area, ARegion **r_region)
{
- bScreen *sc = (bScreen *)ptr->owner_id;
+ bScreen *screen = (bScreen *)ptr->owner_id;
void *regiondata = ptr->data;
- area_region_from_regiondata(sc, regiondata, r_sa, r_ar);
+ area_region_from_regiondata(screen, regiondata, r_area, r_region);
}
/* -------------------------------------------------------------------- */
@@ -611,8 +627,8 @@ static bool rna_Space_bool_from_region_flag_get_by_type(PointerRNA *ptr,
const int region_type,
const int region_flag)
{
- ScrArea *sa = rna_area_from_space(ptr);
- ARegion *region = BKE_area_find_region_type(sa, region_type);
+ ScrArea *area = rna_area_from_space(ptr);
+ ARegion *region = BKE_area_find_region_type(area, region_type);
if (region) {
return (region->flag & region_flag);
}
@@ -624,8 +640,8 @@ static void rna_Space_bool_from_region_flag_set_by_type(PointerRNA *ptr,
const int region_flag,
bool value)
{
- ScrArea *sa = rna_area_from_space(ptr);
- ARegion *region = BKE_area_find_region_type(sa, region_type);
+ ScrArea *area = rna_area_from_space(ptr);
+ ARegion *region = BKE_area_find_region_type(area, region_type);
if (region && (region->alignment != RGN_ALIGN_NONE)) {
SET_FLAG_FROM_TEST(region->flag, value, region_flag);
}
@@ -637,16 +653,16 @@ static void rna_Space_bool_from_region_flag_update_by_type(bContext *C,
const int region_type,
const int region_flag)
{
- ScrArea *sa = rna_area_from_space(ptr);
- ARegion *region = BKE_area_find_region_type(sa, region_type);
+ ScrArea *area = rna_area_from_space(ptr);
+ ARegion *region = BKE_area_find_region_type(area, region_type);
if (region) {
if (region_flag == RGN_FLAG_HIDDEN) {
/* Only support animation when the area is in the current context. */
- if (region->overlap && (sa == CTX_wm_area(C))) {
- ED_region_visibility_change_update_animated(C, sa, region);
+ if (region->overlap && (area == CTX_wm_area(C))) {
+ ED_region_visibility_change_update_animated(C, area, region);
}
else {
- ED_region_visibility_change_update(C, sa, region);
+ ED_region_visibility_change_update(C, area, region);
}
}
else if (region_flag == RGN_FLAG_HIDDEN_BY_USER) {
@@ -654,7 +670,7 @@ static void rna_Space_bool_from_region_flag_update_by_type(bContext *C,
ED_region_toggle_hidden(C, region);
if ((region->flag & RGN_FLAG_HIDDEN_BY_USER) == 0) {
- ED_area_type_hud_ensure(C, sa);
+ ED_area_type_hud_ensure(C, area);
}
}
}
@@ -679,10 +695,10 @@ static void rna_Space_show_region_header_set(PointerRNA *ptr, bool value)
/* Special case, never show the tool properties when the header is invisible. */
bool value_for_tool_header = value;
if (value == true) {
- ScrArea *sa = rna_area_from_space(ptr);
- ARegion *ar_tool_header = BKE_area_find_region_type(sa, RGN_TYPE_TOOL_HEADER);
- if (ar_tool_header != NULL) {
- value_for_tool_header = !(ar_tool_header->flag & RGN_FLAG_HIDDEN_BY_USER);
+ ScrArea *area = rna_area_from_space(ptr);
+ ARegion *region_tool_header = BKE_area_find_region_type(area, RGN_TYPE_TOOL_HEADER);
+ if (region_tool_header != NULL) {
+ value_for_tool_header = !(region_tool_header->flag & RGN_FLAG_HIDDEN_BY_USER);
}
}
rna_Space_bool_from_region_flag_set_by_type(
@@ -773,11 +789,11 @@ static void rna_Space_show_region_hud_update(bContext *C, PointerRNA *ptr)
static bool rna_Space_view2d_sync_get(PointerRNA *ptr)
{
- ScrArea *sa;
+ ScrArea *area;
ARegion *region;
- sa = rna_area_from_space(ptr); /* can be NULL */
- region = BKE_area_find_region_type(sa, RGN_TYPE_WINDOW);
+ area = rna_area_from_space(ptr); /* can be NULL */
+ region = BKE_area_find_region_type(area, RGN_TYPE_WINDOW);
if (region) {
View2D *v2d = &region->v2d;
return (v2d->flag & V2D_VIEWSYNC_SCREEN_TIME) != 0;
@@ -788,11 +804,11 @@ static bool rna_Space_view2d_sync_get(PointerRNA *ptr)
static void rna_Space_view2d_sync_set(PointerRNA *ptr, bool value)
{
- ScrArea *sa;
+ ScrArea *area;
ARegion *region;
- sa = rna_area_from_space(ptr); /* can be NULL */
- region = BKE_area_find_region_type(sa, RGN_TYPE_WINDOW);
+ area = rna_area_from_space(ptr); /* can be NULL */
+ region = BKE_area_find_region_type(area, RGN_TYPE_WINDOW);
if (region) {
View2D *v2d = &region->v2d;
if (value) {
@@ -808,17 +824,17 @@ static void rna_Space_view2d_sync_update(Main *UNUSED(bmain),
Scene *UNUSED(scene),
PointerRNA *ptr)
{
- ScrArea *sa;
+ ScrArea *area;
ARegion *region;
- sa = rna_area_from_space(ptr); /* can be NULL */
- region = BKE_area_find_region_type(sa, RGN_TYPE_WINDOW);
+ area = rna_area_from_space(ptr); /* can be NULL */
+ region = BKE_area_find_region_type(area, RGN_TYPE_WINDOW);
if (region) {
- bScreen *sc = (bScreen *)ptr->owner_id;
+ bScreen *screen = (bScreen *)ptr->owner_id;
View2D *v2d = &region->v2d;
- UI_view2d_sync(sc, sa, v2d, V2D_LOCK_SET);
+ UI_view2d_sync(screen, area, v2d, V2D_LOCK_SET);
}
}
@@ -853,12 +869,12 @@ static void rna_SpaceView3D_camera_update(Main *bmain, Scene *scene, PointerRNA
static void rna_SpaceView3D_use_local_camera_set(PointerRNA *ptr, bool value)
{
View3D *v3d = (View3D *)(ptr->data);
- bScreen *sc = (bScreen *)ptr->owner_id;
+ bScreen *screen = (bScreen *)ptr->owner_id;
v3d->scenelock = !value;
if (!value) {
- Scene *scene = ED_screen_scene_find(sc, G_MAIN->wm.first);
+ Scene *scene = ED_screen_scene_find(screen, G_MAIN->wm.first);
/* NULL if the screen isn't in an active window (happens when setting from Python).
* This could be moved to the update function, in that case the scene wont relate to the screen
* so keep it working this way. */
@@ -885,10 +901,10 @@ static float rna_View3DOverlay_GridScaleUnit_get(PointerRNA *ptr)
static PointerRNA rna_SpaceView3D_region_3d_get(PointerRNA *ptr)
{
View3D *v3d = (View3D *)(ptr->data);
- ScrArea *sa = rna_area_from_space(ptr);
+ ScrArea *area = rna_area_from_space(ptr);
void *regiondata = NULL;
- if (sa) {
- ListBase *regionbase = (sa->spacedata.first == v3d) ? &sa->regionbase : &v3d->regionbase;
+ if (area) {
+ ListBase *regionbase = (area->spacedata.first == v3d) ? &area->regionbase : &v3d->regionbase;
ARegion *region = regionbase->last; /* always last in list, weak .. */
regiondata = region->regiondata;
}
@@ -900,11 +916,11 @@ static void rna_SpaceView3D_region_quadviews_begin(CollectionPropertyIterator *i
PointerRNA *ptr)
{
View3D *v3d = (View3D *)(ptr->data);
- ScrArea *sa = rna_area_from_space(ptr);
+ ScrArea *area = rna_area_from_space(ptr);
int i = 3;
ARegion *region =
- ((sa && sa->spacedata.first == v3d) ? &sa->regionbase : &v3d->regionbase)->last;
+ ((area && area->spacedata.first == v3d) ? &area->regionbase : &v3d->regionbase)->last;
ListBase lb = {NULL, NULL};
if (region && region->alignment == RGN_ALIGN_QSPLIT) {
@@ -931,12 +947,12 @@ static void rna_RegionView3D_quadview_update(Main *UNUSED(main),
Scene *UNUSED(scene),
PointerRNA *ptr)
{
- ScrArea *sa;
+ ScrArea *area;
ARegion *region;
- rna_area_region_from_regiondata(ptr, &sa, &region);
- if (sa && region && region->alignment == RGN_ALIGN_QSPLIT) {
- ED_view3d_quadview_update(sa, region, false);
+ rna_area_region_from_regiondata(ptr, &area, &region);
+ if (area && region && region->alignment == RGN_ALIGN_QSPLIT) {
+ ED_view3d_quadview_update(area, region, false);
}
}
@@ -945,12 +961,12 @@ static void rna_RegionView3D_quadview_clip_update(Main *UNUSED(main),
Scene *UNUSED(scene),
PointerRNA *ptr)
{
- ScrArea *sa;
+ ScrArea *area;
ARegion *region;
- rna_area_region_from_regiondata(ptr, &sa, &region);
- if (sa && region && region->alignment == RGN_ALIGN_QSPLIT) {
- ED_view3d_quadview_update(sa, region, true);
+ rna_area_region_from_regiondata(ptr, &area, &region);
+ if (area && region && region->alignment == RGN_ALIGN_QSPLIT) {
+ ED_view3d_quadview_update(area, region, true);
}
}
@@ -1027,12 +1043,12 @@ static void rna_3DViewShading_type_update(Main *bmain, Scene *scene, PointerRNA
rna_GPencil_update(bmain, scene, ptr);
bScreen *screen = (bScreen *)ptr->owner_id;
- for (ScrArea *sa = screen->areabase.first; sa; sa = sa->next) {
- for (SpaceLink *sl = sa->spacedata.first; sl; sl = sl->next) {
+ LISTBASE_FOREACH (ScrArea *, area, &screen->areabase) {
+ LISTBASE_FOREACH (SpaceLink *, sl, &area->spacedata) {
if (sl->spacetype == SPACE_VIEW3D) {
View3D *v3d = (View3D *)sl;
if (&v3d->shading == shading) {
- ED_view3d_shade_update(bmain, v3d, sa);
+ ED_view3d_shade_update(bmain, v3d, area);
return;
}
}
@@ -1455,8 +1471,8 @@ static bool rna_SpaceImageEditor_show_paint_get(PointerRNA *ptr)
static bool rna_SpaceImageEditor_show_uvedit_get(PointerRNA *ptr)
{
SpaceImage *sima = (SpaceImage *)(ptr->data);
- bScreen *sc = (bScreen *)ptr->owner_id;
- wmWindow *win = ED_screen_window_find(sc, G_MAIN->wm.first);
+ bScreen *screen = (bScreen *)ptr->owner_id;
+ wmWindow *win = ED_screen_window_find(screen, G_MAIN->wm.first);
ViewLayer *view_layer = WM_window_get_active_view_layer(win);
Object *obedit = OBEDIT_FROM_VIEW_LAYER(view_layer);
return ED_space_image_show_uvedit(sima, obedit);
@@ -1465,8 +1481,8 @@ static bool rna_SpaceImageEditor_show_uvedit_get(PointerRNA *ptr)
static bool rna_SpaceImageEditor_show_maskedit_get(PointerRNA *ptr)
{
SpaceImage *sima = (SpaceImage *)(ptr->data);
- bScreen *sc = (bScreen *)ptr->owner_id;
- wmWindow *win = ED_screen_window_find(sc, G_MAIN->wm.first);
+ bScreen *screen = (bScreen *)ptr->owner_id;
+ wmWindow *win = ED_screen_window_find(screen, G_MAIN->wm.first);
ViewLayer *view_layer = WM_window_get_active_view_layer(win);
return ED_space_image_check_show_maskedit(sima, view_layer);
}
@@ -1476,8 +1492,8 @@ static void rna_SpaceImageEditor_image_set(PointerRNA *ptr,
struct ReportList *UNUSED(reports))
{
SpaceImage *sima = (SpaceImage *)(ptr->data);
- bScreen *sc = (bScreen *)ptr->owner_id;
- wmWindow *win = ED_screen_window_find(sc, G_MAIN->wm.first);
+ bScreen *screen = (bScreen *)ptr->owner_id;
+ wmWindow *win = ED_screen_window_find(screen, G_MAIN->wm.first);
ViewLayer *view_layer = WM_window_get_active_view_layer(win);
Object *obedit = OBEDIT_FROM_VIEW_LAYER(view_layer);
@@ -1549,14 +1565,14 @@ static int rna_SpaceImageEditor_display_channels_get(PointerRNA *ptr)
static void rna_SpaceImageEditor_zoom_get(PointerRNA *ptr, float *values)
{
SpaceImage *sima = (SpaceImage *)ptr->data;
- ScrArea *sa;
+ ScrArea *area;
ARegion *region;
values[0] = values[1] = 1;
/* find aregion */
- sa = rna_area_from_space(ptr); /* can be NULL */
- region = BKE_area_find_region_type(sa, RGN_TYPE_WINDOW);
+ area = rna_area_from_space(ptr); /* can be NULL */
+ region = BKE_area_find_region_type(area, RGN_TYPE_WINDOW);
if (region) {
ED_space_image_get_zoom(sima, region, &values[0], &values[1]);
}
@@ -2030,7 +2046,7 @@ static void rna_SpaceDopeSheetEditor_action_update(bContext *C, PointerRNA *ptr)
static void rna_SpaceDopeSheetEditor_mode_update(bContext *C, PointerRNA *ptr)
{
SpaceAction *saction = (SpaceAction *)(ptr->data);
- ScrArea *sa = CTX_wm_area(C);
+ ScrArea *area = CTX_wm_area(C);
ViewLayer *view_layer = CTX_data_view_layer(C);
Object *obact = OBACT(view_layer);
@@ -2070,8 +2086,8 @@ static void rna_SpaceDopeSheetEditor_mode_update(bContext *C, PointerRNA *ptr)
saction->ads.filterflag |= ADS_FILTER_SUMMARY;
}
- if (sa && sa->spacedata.first == saction) {
- ARegion *channels_region = BKE_area_find_region_type(sa, RGN_TYPE_CHANNELS);
+ if (area && area->spacedata.first == saction) {
+ ARegion *channels_region = BKE_area_find_region_type(area, RGN_TYPE_CHANNELS);
if (channels_region) {
if (saction->mode == SACTCONT_TIMELINE) {
channels_region->flag |= RGN_FLAG_HIDDEN;
@@ -2079,7 +2095,7 @@ static void rna_SpaceDopeSheetEditor_mode_update(bContext *C, PointerRNA *ptr)
else {
channels_region->flag &= ~RGN_FLAG_HIDDEN;
}
- ED_region_visibility_change_update(C, sa, channels_region);
+ ED_region_visibility_change_update(C, area, channels_region);
}
}
@@ -2097,19 +2113,19 @@ static void rna_SpaceDopeSheetEditor_mode_update(bContext *C, PointerRNA *ptr)
static void rna_SpaceGraphEditor_display_mode_update(bContext *C, PointerRNA *ptr)
{
- ScrArea *sa = rna_area_from_space(ptr);
+ ScrArea *area = rna_area_from_space(ptr);
SpaceGraph *sipo = (SpaceGraph *)ptr->data;
/* for "Drivers" mode, enable all the necessary bits and pieces */
if (sipo->mode == SIPO_MODE_DRIVERS) {
- ED_drivers_editor_init(C, sa);
- ED_area_tag_redraw(sa);
+ ED_drivers_editor_init(C, area);
+ ED_area_tag_redraw(area);
}
/* after changing view mode, must force recalculation of F-Curve colors
* which can only be achieved using refresh as opposed to redraw
*/
- ED_area_tag_refresh(sa);
+ ED_area_tag_refresh(area);
}
static bool rna_SpaceGraphEditor_has_ghost_curves_get(PointerRNA *ptr)
@@ -2137,8 +2153,8 @@ static void rna_Sequencer_view_type_update(Main *UNUSED(bmain),
Scene *UNUSED(scene),
PointerRNA *ptr)
{
- ScrArea *sa = rna_area_from_space(ptr);
- ED_area_tag_refresh(sa);
+ ScrArea *area = rna_area_from_space(ptr);
+ ED_area_tag_refresh(area);
}
/* Space Node Editor */
@@ -2165,6 +2181,40 @@ static void rna_SpaceNodeEditor_node_tree_update(const bContext *C, PointerRNA *
ED_node_tree_update(C);
}
+# ifdef WITH_NEW_SIMULATION_TYPE
+static PointerRNA rna_SpaceNodeEditor_simulation_get(PointerRNA *ptr)
+{
+ SpaceNode *snode = (SpaceNode *)ptr->data;
+ ID *id = snode->id;
+ if (id && GS(id->name) == ID_SIM) {
+ return rna_pointer_inherit_refine(ptr, &RNA_Simulation, snode->id);
+ }
+ else {
+ return PointerRNA_NULL;
+ }
+}
+
+static void rna_SpaceNodeEditor_simulation_set(PointerRNA *ptr,
+ const PointerRNA value,
+ struct ReportList *UNUSED(reports))
+{
+ SpaceNode *snode = (SpaceNode *)ptr->data;
+ if (!STREQ(snode->tree_idname, "SimulationNodeTree")) {
+ return;
+ }
+
+ Simulation *sim = (Simulation *)value.data;
+ if (sim != NULL) {
+ bNodeTree *ntree = sim->nodetree;
+ ED_node_tree_start(snode, ntree, NULL, NULL);
+ }
+ else {
+ ED_node_tree_start(snode, NULL, NULL, NULL);
+ }
+ snode->id = &sim->id;
+}
+# endif
+
static int rna_SpaceNodeEditor_tree_type_get(PointerRNA *ptr)
{
SpaceNode *snode = (SpaceNode *)ptr->data;
@@ -2286,8 +2336,8 @@ static void rna_SpaceClipEditor_clip_mode_update(Main *UNUSED(bmain),
if (sc->mode == SC_MODE_MASKEDIT && sc->view != SC_VIEW_CLIP) {
/* Make sure we are in the right view for mask editing */
sc->view = SC_VIEW_CLIP;
- ScrArea *sa = rna_area_from_space(ptr);
- ED_area_tag_refresh(sa);
+ ScrArea *area = rna_area_from_space(ptr);
+ ED_area_tag_refresh(area);
}
sc->scopes.ok = 0;
@@ -2307,8 +2357,8 @@ static void rna_SpaceClipEditor_view_type_update(Main *UNUSED(bmain),
Scene *UNUSED(scene),
PointerRNA *ptr)
{
- ScrArea *sa = rna_area_from_space(ptr);
- ED_area_tag_refresh(sa);
+ ScrArea *area = rna_area_from_space(ptr);
+ ED_area_tag_refresh(area);
}
/* File browser. */
@@ -2934,6 +2984,12 @@ static void rna_def_space_image_uv(BlenderRNA *brna)
prop, "Tile Grid Shape", "How many tiles will be shown in the background");
RNA_def_property_update(prop, NC_SPACE | ND_SPACE_IMAGE, NULL);
+ prop = RNA_def_property(srna, "uv_opacity", PROP_FLOAT, PROP_FACTOR);
+ RNA_def_property_float_sdna(prop, NULL, "uv_opacity");
+ RNA_def_property_range(prop, 0.0f, 1.0f);
+ RNA_def_property_ui_text(prop, "UV Opacity", "Opacity of UV overlays");
+ RNA_def_property_update(prop, NC_SPACE | ND_SPACE_IMAGE, NULL);
+
/* todo: move edge and face drawing options here from G.f */
prop = RNA_def_property(srna, "pixel_snap_mode", PROP_ENUM, PROP_NONE);
@@ -3562,6 +3618,11 @@ static void rna_def_space_view3d_overlay(BlenderRNA *brna)
RNA_def_property_ui_text(prop, "Show Text", "Display overlay text");
RNA_def_property_update(prop, NC_SPACE | ND_SPACE_VIEW3D, NULL);
+ prop = RNA_def_property(srna, "show_stats", PROP_BOOLEAN, PROP_NONE);
+ RNA_def_property_boolean_sdna(prop, NULL, "overlay.flag", V3D_OVERLAY_STATS);
+ RNA_def_property_ui_text(prop, "Show Statistics", "Display scene statistics overlay text");
+ RNA_def_property_update(prop, NC_SPACE | ND_SPACE_VIEW3D, NULL);
+
prop = RNA_def_property(srna, "show_extras", PROP_BOOLEAN, PROP_NONE);
RNA_def_property_boolean_negative_sdna(
prop, NULL, "overlay.flag", V3D_OVERLAY_HIDE_OBJECT_XTRAS);
@@ -3763,9 +3824,11 @@ static void rna_def_space_view3d_overlay(BlenderRNA *brna)
prop, "Indices", "Display the index numbers of selected vertices, edges, and faces");
RNA_def_property_update(prop, NC_SPACE | ND_SPACE_VIEW3D, NULL);
- prop = RNA_def_property(srna, "show_curve_handles", PROP_BOOLEAN, PROP_NONE);
- RNA_def_property_boolean_sdna(prop, NULL, "overlay.edit_flag", V3D_OVERLAY_EDIT_CU_HANDLES);
- RNA_def_property_ui_text(prop, "Draw Handles", "Display Bezier handles in editmode");
+ prop = RNA_def_property(srna, "display_handle", PROP_ENUM, PROP_NONE);
+ RNA_def_property_enum_sdna(prop, NULL, "overlay.handle_display");
+ RNA_def_property_enum_items(prop, rna_enum_curve_display_handle_items);
+ RNA_def_property_ui_text(
+ prop, "Display Handles", "Limit the display of curve handles in edit mode");
RNA_def_property_update(prop, NC_SPACE | ND_SPACE_VIEW3D, NULL);
prop = RNA_def_property(srna, "show_curve_normals", PROP_BOOLEAN, PROP_NONE);
@@ -3851,6 +3914,11 @@ static void rna_def_space_view3d_overlay(BlenderRNA *brna)
prop, "Fade Grease Pencil Objects", "Fade Grease Pencil Objects, except the active one");
RNA_def_property_update(prop, NC_SPACE | ND_SPACE_VIEW3D, "rna_GPencil_update");
+ prop = RNA_def_property(srna, "use_gpencil_canvas_xray", PROP_BOOLEAN, PROP_NONE);
+ RNA_def_property_boolean_sdna(prop, NULL, "gp_flag", V3D_GP_SHOW_GRID_XRAY);
+ RNA_def_property_ui_text(prop, "Canvas X-Ray", "Show Canvas grid in front");
+ RNA_def_property_update(prop, NC_SPACE | ND_SPACE_VIEW3D, "rna_GPencil_update");
+
prop = RNA_def_property(srna, "use_gpencil_show_directions", PROP_BOOLEAN, PROP_NONE);
RNA_def_property_boolean_sdna(prop, NULL, "gp_flag", V3D_GP_SHOW_STROKE_DIRECTION);
RNA_def_property_ui_text(prop,
@@ -4830,6 +4898,11 @@ static void rna_def_space_sequencer(BlenderRNA *brna)
RNA_def_property_boolean_sdna(prop, NULL, "draw_flag", SEQ_DRAW_OFFSET_EXT);
RNA_def_property_ui_text(prop, "Show Offsets", "Display strip in/out offsets");
RNA_def_property_update(prop, NC_SPACE | ND_SPACE_SEQUENCER, NULL);
+
+ prop = RNA_def_property(srna, "show_fcurves", PROP_BOOLEAN, PROP_NONE);
+ RNA_def_property_boolean_sdna(prop, NULL, "flag", SEQ_SHOW_FCURVES);
+ RNA_def_property_ui_text(prop, "Show F-Curves", "Display strip opacity/volume curve");
+ RNA_def_property_update(prop, NC_SPACE | ND_SPACE_SEQUENCER, NULL);
}
static void rna_def_space_text(BlenderRNA *brna)
@@ -5515,6 +5588,13 @@ static void rna_def_fileselect_idfilter(BlenderRNA *brna)
"Show/hide Point Cloud data-blocks"},
# endif
{FILTER_ID_SCE, "filter_scene", ICON_SCENE_DATA, "Scenes", "Show Scene data-blocks"},
+# ifdef WITH_NEW_SIMULATION_TYPE
+ {FILTER_ID_SIM,
+ "filter_simulation",
+ ICON_PHYSICS,
+ "Simulations",
+ "Show Simulation data-blocks"}, /* TODO: Use correct icon. */
+# endif
{FILTER_ID_SPK, "filter_speaker", ICON_SPEAKER, "Speakers", "Show Speaker data-blocks"},
{FILTER_ID_SO, "filter_sound", ICON_SOUND, "Sounds", "Show Sound data-blocks"},
{FILTER_ID_TE, "filter_texture", ICON_TEXTURE_DATA, "Textures", "Show Texture data-blocks"},
@@ -6196,6 +6276,19 @@ static void rna_def_space_node(BlenderRNA *brna)
RNA_def_property_ui_text(
prop, "ID From", "Data-block from which the edited data-block is linked");
+# ifdef WITH_NEW_SIMULATION_TYPE
+ prop = RNA_def_property(srna, "simulation", PROP_POINTER, PROP_NONE);
+ RNA_def_property_flag(prop, PROP_EDITABLE);
+ RNA_def_property_struct_type(prop, "Simulation");
+ RNA_def_property_ui_text(prop, "Simulation", "Simulation that is being edited");
+ RNA_def_property_pointer_funcs(prop,
+ "rna_SpaceNodeEditor_simulation_get",
+ "rna_SpaceNodeEditor_simulation_set",
+ NULL,
+ NULL);
+ RNA_def_property_update(prop, NC_SPACE | ND_SPACE_NODE, NULL);
+# endif
+
prop = RNA_def_property(srna, "path", PROP_COLLECTION, PROP_NONE);
RNA_def_property_collection_sdna(prop, NULL, "treepath", NULL);
RNA_def_property_struct_type(prop, "NodeTreePath");
@@ -6303,7 +6396,7 @@ static void rna_def_space_clip(BlenderRNA *brna)
{0, NULL, 0, NULL, NULL},
};
- static const EnumPropertyItem gpencil_source_items[] = {
+ static const EnumPropertyItem annotation_source_items[] = {
{SC_GPENCIL_SRC_CLIP,
"CLIP",
0,
@@ -6565,10 +6658,10 @@ static void rna_def_space_clip(BlenderRNA *brna)
RNA_def_property_update(prop, NC_MOVIECLIP | ND_DISPLAY, NULL);
/* grease pencil source */
- prop = RNA_def_property(srna, "grease_pencil_source", PROP_ENUM, PROP_NONE);
+ prop = RNA_def_property(srna, "annotation_source", PROP_ENUM, PROP_NONE);
RNA_def_property_enum_sdna(prop, NULL, "gpencil_src");
- RNA_def_property_enum_items(prop, gpencil_source_items);
- RNA_def_property_ui_text(prop, "Grease Pencil Source", "Where the grease pencil comes from");
+ RNA_def_property_enum_items(prop, annotation_source_items);
+ RNA_def_property_ui_text(prop, "Annotation Source", "Where the annotation comes from");
RNA_def_property_translation_context(prop, BLT_I18NCONTEXT_ID_MOVIECLIP);
RNA_def_property_update(prop, NC_MOVIECLIP | ND_DISPLAY, NULL);
diff --git a/source/blender/makesrna/intern/rna_space_api.c b/source/blender/makesrna/intern/rna_space_api.c
index 84c80e56d0d..28fdc5fb60f 100644
--- a/source/blender/makesrna/intern/rna_space_api.c
+++ b/source/blender/makesrna/intern/rna_space_api.c
@@ -32,21 +32,21 @@
static void rna_RegionView3D_update(ID *id, RegionView3D *rv3d, bContext *C)
{
- bScreen *sc = (bScreen *)id;
+ bScreen *screen = (bScreen *)id;
- ScrArea *sa;
+ ScrArea *area;
ARegion *region;
- area_region_from_regiondata(sc, rv3d, &sa, &region);
+ area_region_from_regiondata(screen, rv3d, &area, &region);
- if (sa && region && sa->spacetype == SPACE_VIEW3D) {
+ if (area && region && area->spacetype == SPACE_VIEW3D) {
Main *bmain = CTX_data_main(C);
- View3D *v3d = sa->spacedata.first;
+ View3D *v3d = area->spacedata.first;
wmWindowManager *wm = CTX_wm_manager(C);
wmWindow *win;
for (win = wm->windows.first; win; win = win->next) {
- if (WM_window_get_active_screen(win) == sc) {
+ if (WM_window_get_active_screen(win) == screen) {
Scene *scene = WM_window_get_active_scene(win);
ViewLayer *view_layer = WM_window_get_active_view_layer(win);
Depsgraph *depsgraph = BKE_scene_get_depsgraph(bmain, scene, view_layer, true);
@@ -61,10 +61,10 @@ static void rna_RegionView3D_update(ID *id, RegionView3D *rv3d, bContext *C)
static void rna_SpaceTextEditor_region_location_from_cursor(
ID *id, SpaceText *st, int line, int column, int r_pixel_pos[2])
{
- bScreen *sc = (bScreen *)id;
- ScrArea *sa = BKE_screen_find_area_from_space(sc, (SpaceLink *)st);
- if (sa) {
- ARegion *region = BKE_area_find_region_type(sa, RGN_TYPE_WINDOW);
+ bScreen *screen = (bScreen *)id;
+ ScrArea *area = BKE_screen_find_area_from_space(screen, (SpaceLink *)st);
+ if (area) {
+ ARegion *region = BKE_area_find_region_type(area, RGN_TYPE_WINDOW);
const int cursor_co[2] = {line, column};
ED_text_region_location_from_cursor(st, region, cursor_co, r_pixel_pos);
}
diff --git a/source/blender/makesrna/intern/rna_texture.c b/source/blender/makesrna/intern/rna_texture.c
index 46b8d8647de..9184c54ae88 100644
--- a/source/blender/makesrna/intern/rna_texture.c
+++ b/source/blender/makesrna/intern/rna_texture.c
@@ -1565,7 +1565,11 @@ static void rna_def_texture(BlenderRNA *brna)
prop = RNA_def_property(srna, "use_color_ramp", PROP_BOOLEAN, PROP_NONE);
RNA_def_property_boolean_sdna(prop, NULL, "flag", TEX_COLORBAND);
RNA_def_property_boolean_funcs(prop, NULL, "rna_Texture_use_color_ramp_set");
- RNA_def_property_ui_text(prop, "Use Color Ramp", "Toggle color ramp operations");
+ RNA_def_property_ui_text(prop,
+ "Use Color Ramp",
+ "Map the texture intensity to the color ramp. "
+ "Note that the alpha value is used for image textures, "
+ "enable \"Calculate Alpha\" for images without an alpha channel");
RNA_def_property_update(prop, 0, "rna_Texture_update");
prop = RNA_def_property(srna, "color_ramp", PROP_POINTER, PROP_NEVER_NULL);
diff --git a/source/blender/makesrna/intern/rna_tracking.c b/source/blender/makesrna/intern/rna_tracking.c
index c8965f1a6fb..507d06482df 100644
--- a/source/blender/makesrna/intern/rna_tracking.c
+++ b/source/blender/makesrna/intern/rna_tracking.c
@@ -43,6 +43,7 @@
# include "DNA_anim_types.h"
+# include "BKE_anim_data.h"
# include "BKE_animsys.h"
# include "BKE_node.h"
@@ -1148,6 +1149,7 @@ static void rna_def_trackingCamera(BlenderRNA *brna)
"Divisions",
"Division distortion model which "
"better represents wide-angle cameras"},
+ {TRACKING_DISTORTION_MODEL_NUKE, "NUKE", 0, "Nuke", "Nuke distortion model"},
{0, NULL, 0, NULL, NULL},
};
@@ -1251,6 +1253,19 @@ static void rna_def_trackingCamera(BlenderRNA *brna)
RNA_def_property_ui_text(prop, "K2", "First coefficient of second order division distortion");
RNA_def_property_update(prop, NC_MOVIECLIP | NA_EDITED, "rna_tracking_flushUpdate");
+ /* Nuke distortion parameters */
+ prop = RNA_def_property(srna, "nuke_k1", PROP_FLOAT, PROP_NONE);
+ RNA_def_property_clear_flag(prop, PROP_ANIMATABLE);
+ RNA_def_property_ui_range(prop, -10, 10, 0.1, 3);
+ RNA_def_property_ui_text(prop, "K1", "First coefficient of second order Nuke distortion");
+ RNA_def_property_update(prop, NC_MOVIECLIP | NA_EDITED, "rna_tracking_flushUpdate");
+
+ prop = RNA_def_property(srna, "nuke_k2", PROP_FLOAT, PROP_NONE);
+ RNA_def_property_clear_flag(prop, PROP_ANIMATABLE);
+ RNA_def_property_ui_range(prop, -10, 10, 0.1, 3);
+ RNA_def_property_ui_text(prop, "K2", "Second coefficient of second order Nuke distortion");
+ RNA_def_property_update(prop, NC_MOVIECLIP | NA_EDITED, "rna_tracking_flushUpdate");
+
/* pixel aspect */
prop = RNA_def_property(srna, "pixel_aspect", PROP_FLOAT, PROP_XYZ);
RNA_def_property_float_sdna(prop, NULL, "pixel_aspect");
diff --git a/source/blender/makesrna/intern/rna_ui.c b/source/blender/makesrna/intern/rna_ui.c
index 273bef6d239..1449c410d18 100644
--- a/source/blender/makesrna/intern/rna_ui.c
+++ b/source/blender/makesrna/intern/rna_ui.c
@@ -27,6 +27,8 @@
#include "BKE_idprop.h"
+#include "BLI_listbase.h"
+
#include "RNA_define.h"
#include "RNA_enum_types.h"
@@ -111,12 +113,12 @@ static bool panel_poll(const bContext *C, PanelType *pt)
void *ret;
bool visible;
- RNA_pointer_create(NULL, pt->ext.srna, NULL, &ptr); /* dummy */
- func = &rna_Panel_poll_func; /* RNA_struct_find_function(&ptr, "poll"); */
+ RNA_pointer_create(NULL, pt->rna_ext.srna, NULL, &ptr); /* dummy */
+ func = &rna_Panel_poll_func; /* RNA_struct_find_function(&ptr, "poll"); */
RNA_parameter_list_create(&list, &ptr, func);
RNA_parameter_set_lookup(&list, "context", &C);
- pt->ext.call((bContext *)C, &ptr, func, &list);
+ pt->rna_ext.call((bContext *)C, &ptr, func, &list);
RNA_parameter_get_lookup(&list, "visible", &ret);
visible = *(bool *)ret;
@@ -126,7 +128,7 @@ static bool panel_poll(const bContext *C, PanelType *pt)
return visible;
}
-static void panel_draw(const bContext *C, Panel *pnl)
+static void panel_draw(const bContext *C, Panel *panel)
{
extern FunctionRNA rna_Panel_draw_func;
@@ -134,17 +136,17 @@ static void panel_draw(const bContext *C, Panel *pnl)
ParameterList list;
FunctionRNA *func;
- RNA_pointer_create(&CTX_wm_screen(C)->id, pnl->type->ext.srna, pnl, &ptr);
+ RNA_pointer_create(&CTX_wm_screen(C)->id, panel->type->rna_ext.srna, panel, &ptr);
func = &rna_Panel_draw_func; /* RNA_struct_find_function(&ptr, "draw"); */
RNA_parameter_list_create(&list, &ptr, func);
RNA_parameter_set_lookup(&list, "context", &C);
- pnl->type->ext.call((bContext *)C, &ptr, func, &list);
+ panel->type->rna_ext.call((bContext *)C, &ptr, func, &list);
RNA_parameter_list_free(&list);
}
-static void panel_draw_header(const bContext *C, Panel *pnl)
+static void panel_draw_header(const bContext *C, Panel *panel)
{
extern FunctionRNA rna_Panel_draw_header_func;
@@ -152,17 +154,17 @@ static void panel_draw_header(const bContext *C, Panel *pnl)
ParameterList list;
FunctionRNA *func;
- RNA_pointer_create(&CTX_wm_screen(C)->id, pnl->type->ext.srna, pnl, &ptr);
+ RNA_pointer_create(&CTX_wm_screen(C)->id, panel->type->rna_ext.srna, panel, &ptr);
func = &rna_Panel_draw_header_func; /* RNA_struct_find_function(&ptr, "draw_header"); */
RNA_parameter_list_create(&list, &ptr, func);
RNA_parameter_set_lookup(&list, "context", &C);
- pnl->type->ext.call((bContext *)C, &ptr, func, &list);
+ panel->type->rna_ext.call((bContext *)C, &ptr, func, &list);
RNA_parameter_list_free(&list);
}
-static void panel_draw_header_preset(const bContext *C, Panel *pnl)
+static void panel_draw_header_preset(const bContext *C, Panel *panel)
{
extern FunctionRNA rna_Panel_draw_header_preset_func;
@@ -170,12 +172,12 @@ static void panel_draw_header_preset(const bContext *C, Panel *pnl)
ParameterList list;
FunctionRNA *func;
- RNA_pointer_create(&CTX_wm_screen(C)->id, pnl->type->ext.srna, pnl, &ptr);
+ RNA_pointer_create(&CTX_wm_screen(C)->id, panel->type->rna_ext.srna, panel, &ptr);
func = &rna_Panel_draw_header_preset_func;
RNA_parameter_list_create(&list, &ptr, func);
RNA_parameter_set_lookup(&list, "context", &C);
- pnl->type->ext.call((bContext *)C, &ptr, func, &list);
+ panel->type->rna_ext.call((bContext *)C, &ptr, func, &list);
RNA_parameter_list_free(&list);
}
@@ -192,7 +194,7 @@ static void rna_Panel_unregister(Main *bmain, StructRNA *type)
return;
}
- RNA_struct_free_extension(type, &pt->ext);
+ RNA_struct_free_extension(type, &pt->rna_ext);
RNA_struct_free(&BLENDER_RNA, type);
if (pt->parent) {
@@ -202,7 +204,7 @@ static void rna_Panel_unregister(Main *bmain, StructRNA *type)
WM_paneltype_remove(pt);
- for (LinkData *link = pt->children.first; link; link = link->next) {
+ LISTBASE_FOREACH (LinkData *, link, &pt->children) {
PanelType *child_pt = link->data;
child_pt->parent = NULL;
}
@@ -212,15 +214,16 @@ static void rna_Panel_unregister(Main *bmain, StructRNA *type)
BLI_freelinkN(&art->paneltypes, pt);
for (bScreen *screen = bmain->screens.first; screen; screen = screen->id.next) {
- for (ScrArea *sa = screen->areabase.first; sa; sa = sa->next) {
- for (SpaceLink *sl = sa->spacedata.first; sl; sl = sl->next) {
+ LISTBASE_FOREACH (ScrArea *, area, &screen->areabase) {
+ LISTBASE_FOREACH (SpaceLink *, sl, &area->spacedata) {
if (sl->spacetype == space_type) {
- ListBase *regionbase = (sl == sa->spacedata.first) ? &sa->regionbase : &sl->regionbase;
- for (ARegion *region = regionbase->first; region; region = region->next) {
+ ListBase *regionbase = (sl == area->spacedata.first) ? &area->regionbase :
+ &sl->regionbase;
+ LISTBASE_FOREACH (ARegion *, region, regionbase) {
if (region->type == art) {
- for (Panel *pa = region->panels.first; pa; pa = pa->next) {
- if (pa->type == pt) {
- pa->type = NULL;
+ LISTBASE_FOREACH (Panel *, panel, &region->panels) {
+ if (panel->type == pt) {
+ panel->type = NULL;
}
}
}
@@ -300,8 +303,8 @@ static StructRNA *rna_Panel_register(Main *bmain,
for (pt = art->paneltypes.first; pt; pt = pt->next) {
if (STREQ(pt->idname, dummypt.idname)) {
PanelType *pt_next = pt->next;
- if (pt->ext.srna) {
- rna_Panel_unregister(bmain, pt->ext.srna);
+ if (pt->rna_ext.srna) {
+ rna_Panel_unregister(bmain, pt->rna_ext.srna);
}
else {
BLI_freelinkN(&art->paneltypes, pt);
@@ -344,13 +347,13 @@ static StructRNA *rna_Panel_register(Main *bmain,
pt = MEM_mallocN(sizeof(PanelType), "python buttons panel");
memcpy(pt, &dummypt, sizeof(dummypt));
- pt->ext.srna = RNA_def_struct_ptr(&BLENDER_RNA, pt->idname, &RNA_Panel);
- RNA_def_struct_translation_context(pt->ext.srna, pt->translation_context);
- pt->ext.data = data;
- pt->ext.call = call;
- pt->ext.free = free;
- RNA_struct_blender_type_set(pt->ext.srna, pt);
- RNA_def_struct_flag(pt->ext.srna, STRUCT_NO_IDPROPERTIES);
+ pt->rna_ext.srna = RNA_def_struct_ptr(&BLENDER_RNA, pt->idname, &RNA_Panel);
+ RNA_def_struct_translation_context(pt->rna_ext.srna, pt->translation_context);
+ pt->rna_ext.data = data;
+ pt->rna_ext.call = call;
+ pt->rna_ext.free = free;
+ RNA_struct_blender_type_set(pt->rna_ext.srna, pt);
+ RNA_def_struct_flag(pt->rna_ext.srna, STRUCT_NO_IDPROPERTIES);
pt->poll = (have_function[0]) ? panel_poll : NULL;
pt->draw = (have_function[1]) ? panel_draw : NULL;
@@ -390,13 +393,13 @@ static StructRNA *rna_Panel_register(Main *bmain,
/* update while blender is running */
WM_main_add_notifier(NC_WINDOW, NULL);
- return pt->ext.srna;
+ return pt->rna_ext.srna;
}
static StructRNA *rna_Panel_refine(PointerRNA *ptr)
{
Panel *menu = (Panel *)ptr->data;
- return (menu->type && menu->type->ext.srna) ? menu->type->ext.srna : &RNA_Panel;
+ return (menu->type && menu->type->rna_ext.srna) ? menu->type->rna_ext.srna : &RNA_Panel;
}
/* UIList */
@@ -433,7 +436,7 @@ static void uilist_draw_item(uiList *ui_list,
ParameterList list;
FunctionRNA *func;
- RNA_pointer_create(&CTX_wm_screen(C)->id, ui_list->type->ext.srna, ui_list, &ul_ptr);
+ RNA_pointer_create(&CTX_wm_screen(C)->id, ui_list->type->rna_ext.srna, ui_list, &ul_ptr);
func = &rna_UIList_draw_item_func; /* RNA_struct_find_function(&ul_ptr, "draw_item"); */
RNA_parameter_list_create(&list, &ul_ptr, func);
@@ -446,7 +449,7 @@ static void uilist_draw_item(uiList *ui_list,
RNA_parameter_set_lookup(&list, "active_property", &active_propname);
RNA_parameter_set_lookup(&list, "index", &index);
RNA_parameter_set_lookup(&list, "flt_flag", &flt_flag);
- ui_list->type->ext.call((bContext *)C, &ul_ptr, func, &list);
+ ui_list->type->rna_ext.call((bContext *)C, &ul_ptr, func, &list);
RNA_parameter_list_free(&list);
}
@@ -459,13 +462,13 @@ static void uilist_draw_filter(uiList *ui_list, bContext *C, uiLayout *layout)
ParameterList list;
FunctionRNA *func;
- RNA_pointer_create(&CTX_wm_screen(C)->id, ui_list->type->ext.srna, ui_list, &ul_ptr);
+ RNA_pointer_create(&CTX_wm_screen(C)->id, ui_list->type->rna_ext.srna, ui_list, &ul_ptr);
func = &rna_UIList_draw_filter_func; /* RNA_struct_find_function(&ul_ptr, "draw_filter"); */
RNA_parameter_list_create(&list, &ul_ptr, func);
RNA_parameter_set_lookup(&list, "context", &C);
RNA_parameter_set_lookup(&list, "layout", &layout);
- ui_list->type->ext.call((bContext *)C, &ul_ptr, func, &list);
+ ui_list->type->rna_ext.call((bContext *)C, &ul_ptr, func, &list);
RNA_parameter_list_free(&list);
}
@@ -488,7 +491,7 @@ static void uilist_filter_items(uiList *ui_list,
int ret_len;
int len = flt_data->items_len = RNA_collection_length(dataptr, propname);
- RNA_pointer_create(&CTX_wm_screen(C)->id, ui_list->type->ext.srna, ui_list, &ul_ptr);
+ RNA_pointer_create(&CTX_wm_screen(C)->id, ui_list->type->rna_ext.srna, ui_list, &ul_ptr);
func = &rna_UIList_filter_items_func; /* RNA_struct_find_function(&ul_ptr, "filter_items"); */
RNA_parameter_list_create(&list, &ul_ptr, func);
@@ -496,7 +499,7 @@ static void uilist_filter_items(uiList *ui_list,
RNA_parameter_set_lookup(&list, "data", dataptr);
RNA_parameter_set_lookup(&list, "property", &propname);
- ui_list->type->ext.call((bContext *)C, &ul_ptr, func, &list);
+ ui_list->type->rna_ext.call((bContext *)C, &ul_ptr, func, &list);
parm = RNA_function_find_parameter(NULL, func, "filter_flags");
ret_len = RNA_parameter_dynamic_length_get(&list, parm);
@@ -599,7 +602,7 @@ static void rna_UIList_unregister(Main *UNUSED(bmain), StructRNA *type)
return;
}
- RNA_struct_free_extension(type, &ult->ext);
+ RNA_struct_free_extension(type, &ult->rna_ext);
RNA_struct_free(&BLENDER_RNA, type);
WM_uilisttype_freelink(ult);
@@ -642,8 +645,8 @@ static StructRNA *rna_UIList_register(Main *bmain,
/* check if we have registered this uilist type before, and remove it */
ult = WM_uilisttype_find(dummyult.idname, true);
- if (ult && ult->ext.srna) {
- rna_UIList_unregister(bmain, ult->ext.srna);
+ if (ult && ult->rna_ext.srna) {
+ rna_UIList_unregister(bmain, ult->rna_ext.srna);
}
if (!RNA_struct_available_or_report(reports, dummyult.idname)) {
return NULL;
@@ -656,11 +659,11 @@ static StructRNA *rna_UIList_register(Main *bmain,
ult = MEM_callocN(sizeof(uiListType) + over_alloc, "python uilist");
memcpy(ult, &dummyult, sizeof(dummyult));
- ult->ext.srna = RNA_def_struct_ptr(&BLENDER_RNA, ult->idname, &RNA_UIList);
- ult->ext.data = data;
- ult->ext.call = call;
- ult->ext.free = free;
- RNA_struct_blender_type_set(ult->ext.srna, ult);
+ ult->rna_ext.srna = RNA_def_struct_ptr(&BLENDER_RNA, ult->idname, &RNA_UIList);
+ ult->rna_ext.data = data;
+ ult->rna_ext.call = call;
+ ult->rna_ext.free = free;
+ RNA_struct_blender_type_set(ult->rna_ext.srna, ult);
ult->draw_item = (have_function[0]) ? uilist_draw_item : NULL;
ult->draw_filter = (have_function[1]) ? uilist_draw_filter : NULL;
@@ -671,13 +674,14 @@ static StructRNA *rna_UIList_register(Main *bmain,
/* update while blender is running */
WM_main_add_notifier(NC_WINDOW, NULL);
- return ult->ext.srna;
+ return ult->rna_ext.srna;
}
static StructRNA *rna_UIList_refine(PointerRNA *ptr)
{
uiList *ui_list = (uiList *)ptr->data;
- return (ui_list->type && ui_list->type->ext.srna) ? ui_list->type->ext.srna : &RNA_UIList;
+ return (ui_list->type && ui_list->type->rna_ext.srna) ? ui_list->type->rna_ext.srna :
+ &RNA_UIList;
}
/* Header */
@@ -690,12 +694,12 @@ static void header_draw(const bContext *C, Header *hdr)
ParameterList list;
FunctionRNA *func;
- RNA_pointer_create(&CTX_wm_screen(C)->id, hdr->type->ext.srna, hdr, &htr);
+ RNA_pointer_create(&CTX_wm_screen(C)->id, hdr->type->rna_ext.srna, hdr, &htr);
func = &rna_Header_draw_func; /* RNA_struct_find_function(&htr, "draw"); */
RNA_parameter_list_create(&list, &htr, func);
RNA_parameter_set_lookup(&list, "context", &C);
- hdr->type->ext.call((bContext *)C, &htr, func, &list);
+ hdr->type->rna_ext.call((bContext *)C, &htr, func, &list);
RNA_parameter_list_free(&list);
}
@@ -712,7 +716,7 @@ static void rna_Header_unregister(Main *UNUSED(bmain), StructRNA *type)
return;
}
- RNA_struct_free_extension(type, &ht->ext);
+ RNA_struct_free_extension(type, &ht->rna_ext);
RNA_struct_free(&BLENDER_RNA, type);
BLI_freelinkN(&art->headertypes, ht);
@@ -761,8 +765,8 @@ static StructRNA *rna_Header_register(Main *bmain,
/* check if we have registered this header type before, and remove it */
for (ht = art->headertypes.first; ht; ht = ht->next) {
if (STREQ(ht->idname, dummyht.idname)) {
- if (ht->ext.srna) {
- rna_Header_unregister(bmain, ht->ext.srna);
+ if (ht->rna_ext.srna) {
+ rna_Header_unregister(bmain, ht->rna_ext.srna);
}
break;
}
@@ -778,11 +782,11 @@ static StructRNA *rna_Header_register(Main *bmain,
ht = MEM_mallocN(sizeof(HeaderType), "python buttons header");
memcpy(ht, &dummyht, sizeof(dummyht));
- ht->ext.srna = RNA_def_struct_ptr(&BLENDER_RNA, ht->idname, &RNA_Header);
- ht->ext.data = data;
- ht->ext.call = call;
- ht->ext.free = free;
- RNA_struct_blender_type_set(ht->ext.srna, ht);
+ ht->rna_ext.srna = RNA_def_struct_ptr(&BLENDER_RNA, ht->idname, &RNA_Header);
+ ht->rna_ext.data = data;
+ ht->rna_ext.call = call;
+ ht->rna_ext.free = free;
+ RNA_struct_blender_type_set(ht->rna_ext.srna, ht);
ht->draw = (have_function[0]) ? header_draw : NULL;
@@ -791,13 +795,13 @@ static StructRNA *rna_Header_register(Main *bmain,
/* update while blender is running */
WM_main_add_notifier(NC_WINDOW, NULL);
- return ht->ext.srna;
+ return ht->rna_ext.srna;
}
static StructRNA *rna_Header_refine(PointerRNA *htr)
{
Header *hdr = (Header *)htr->data;
- return (hdr->type && hdr->type->ext.srna) ? hdr->type->ext.srna : &RNA_Header;
+ return (hdr->type && hdr->type->rna_ext.srna) ? hdr->type->rna_ext.srna : &RNA_Header;
}
/* Menu */
@@ -812,12 +816,12 @@ static bool menu_poll(const bContext *C, MenuType *pt)
void *ret;
bool visible;
- RNA_pointer_create(NULL, pt->ext.srna, NULL, &ptr); /* dummy */
- func = &rna_Menu_poll_func; /* RNA_struct_find_function(&ptr, "poll"); */
+ RNA_pointer_create(NULL, pt->rna_ext.srna, NULL, &ptr); /* dummy */
+ func = &rna_Menu_poll_func; /* RNA_struct_find_function(&ptr, "poll"); */
RNA_parameter_list_create(&list, &ptr, func);
RNA_parameter_set_lookup(&list, "context", &C);
- pt->ext.call((bContext *)C, &ptr, func, &list);
+ pt->rna_ext.call((bContext *)C, &ptr, func, &list);
RNA_parameter_get_lookup(&list, "visible", &ret);
visible = *(bool *)ret;
@@ -835,12 +839,12 @@ static void menu_draw(const bContext *C, Menu *menu)
ParameterList list;
FunctionRNA *func;
- RNA_pointer_create(&CTX_wm_screen(C)->id, menu->type->ext.srna, menu, &mtr);
+ RNA_pointer_create(&CTX_wm_screen(C)->id, menu->type->rna_ext.srna, menu, &mtr);
func = &rna_Menu_draw_func; /* RNA_struct_find_function(&mtr, "draw"); */
RNA_parameter_list_create(&list, &mtr, func);
RNA_parameter_set_lookup(&list, "context", &C);
- menu->type->ext.call((bContext *)C, &mtr, func, &list);
+ menu->type->rna_ext.call((bContext *)C, &mtr, func, &list);
RNA_parameter_list_free(&list);
}
@@ -853,7 +857,7 @@ static void rna_Menu_unregister(Main *UNUSED(bmain), StructRNA *type)
return;
}
- RNA_struct_free_extension(type, &mt->ext);
+ RNA_struct_free_extension(type, &mt->rna_ext);
RNA_struct_free(&BLENDER_RNA, type);
WM_menutype_freelink(mt);
@@ -903,8 +907,8 @@ static StructRNA *rna_Menu_register(Main *bmain,
/* check if we have registered this menu type before, and remove it */
mt = WM_menutype_find(dummymt.idname, true);
- if (mt && mt->ext.srna) {
- rna_Menu_unregister(bmain, mt->ext.srna);
+ if (mt && mt->rna_ext.srna) {
+ rna_Menu_unregister(bmain, mt->rna_ext.srna);
}
if (!RNA_struct_available_or_report(reports, dummymt.idname)) {
return NULL;
@@ -931,13 +935,13 @@ static StructRNA *rna_Menu_register(Main *bmain,
mt->description = NULL;
}
- mt->ext.srna = RNA_def_struct_ptr(&BLENDER_RNA, mt->idname, &RNA_Menu);
- RNA_def_struct_translation_context(mt->ext.srna, mt->translation_context);
- mt->ext.data = data;
- mt->ext.call = call;
- mt->ext.free = free;
- RNA_struct_blender_type_set(mt->ext.srna, mt);
- RNA_def_struct_flag(mt->ext.srna, STRUCT_NO_IDPROPERTIES);
+ mt->rna_ext.srna = RNA_def_struct_ptr(&BLENDER_RNA, mt->idname, &RNA_Menu);
+ RNA_def_struct_translation_context(mt->rna_ext.srna, mt->translation_context);
+ mt->rna_ext.data = data;
+ mt->rna_ext.call = call;
+ mt->rna_ext.free = free;
+ RNA_struct_blender_type_set(mt->rna_ext.srna, mt);
+ RNA_def_struct_flag(mt->rna_ext.srna, STRUCT_NO_IDPROPERTIES);
mt->poll = (have_function[0]) ? menu_poll : NULL;
mt->draw = (have_function[1]) ? menu_draw : NULL;
@@ -954,13 +958,13 @@ static StructRNA *rna_Menu_register(Main *bmain,
/* update while blender is running */
WM_main_add_notifier(NC_WINDOW, NULL);
- return mt->ext.srna;
+ return mt->rna_ext.srna;
}
static StructRNA *rna_Menu_refine(PointerRNA *mtr)
{
Menu *menu = (Menu *)mtr->data;
- return (menu->type && menu->type->ext.srna) ? menu->type->ext.srna : &RNA_Menu;
+ return (menu->type && menu->type->rna_ext.srna) ? menu->type->rna_ext.srna : &RNA_Menu;
}
static void rna_Menu_bl_description_set(PointerRNA *ptr, const char *value)
@@ -1281,6 +1285,18 @@ static void rna_def_panel(BlenderRNA *brna)
"Hide Header",
"If set to False, the panel shows a header, which contains a clickable "
"arrow to collapse the panel and the label (see bl_label)"},
+ {PNL_INSTANCED,
+ "INSTANCED",
+ 0,
+ "Instanced Panel",
+ "Multiple panels with this type can be used as part of a list depending on data external "
+ "to the UI. Used to create panels for the modifiers and other stacks."},
+ {PNL_LAYOUT_HEADER_EXPAND,
+ "HEADER_LAYOUT_EXPAND",
+ 0,
+ "Expand Header Layout",
+ "Allow buttons in the header to stretch and shrink to fill the entire layout width"},
+ {PNL_DRAW_BOX, "DRAW_BOX", 0, "Box Style", "Draw panel with the box widget theme"},
{0, NULL, 0, NULL, NULL},
};
@@ -1328,6 +1344,11 @@ static void rna_def_panel(BlenderRNA *brna)
RNA_def_property_string_sdna(prop, NULL, "drawname");
RNA_def_property_ui_text(prop, "Text", "XXX todo");
+ prop = RNA_def_int(
+ srna, "list_panel_index", 0, 0, INT_MAX, "Instanced Panel Data Index", "", 0, INT_MAX);
+ RNA_def_property_int_sdna(prop, NULL, "runtime.list_index");
+ RNA_def_property_clear_flag(prop, PROP_EDITABLE);
+
/* registration */
prop = RNA_def_property(srna, "bl_idname", PROP_STRING, PROP_NONE);
RNA_def_property_string_sdna(prop, NULL, "type->idname");
diff --git a/source/blender/makesrna/intern/rna_ui_api.c b/source/blender/makesrna/intern/rna_ui_api.c
index a169e81237d..8d0e403aa2d 100644
--- a/source/blender/makesrna/intern/rna_ui_api.c
+++ b/source/blender/makesrna/intern/rna_ui_api.c
@@ -485,6 +485,21 @@ static void rna_uiTemplateAnyID(uiLayout *layout,
uiTemplateAnyID(layout, ptr, propname, proptypename, name);
}
+static void rna_uiTemplateCacheFile(uiLayout *layout,
+ bContext *C,
+ PointerRNA *ptr,
+ const char *propname)
+{
+ PropertyRNA *prop = RNA_struct_find_property(ptr, propname);
+
+ if (!prop) {
+ RNA_warning("property not found: %s.%s", RNA_struct_identifier(ptr->type), propname);
+ return;
+ }
+
+ uiTemplateCacheFile(layout, C, ptr, propname);
+}
+
static void rna_uiTemplatePathBuilder(uiLayout *layout,
PointerRNA *ptr,
const char *propname,
@@ -693,7 +708,7 @@ void RNA_api_ui_layout(StructRNA *srna)
static float node_socket_color_default[] = {0.0f, 0.0f, 0.0f, 1.0f};
/* simple layout specifiers */
- func = RNA_def_function(srna, "row", "uiLayoutRow");
+ func = RNA_def_function(srna, "row", "uiLayoutRowWithHeading");
parm = RNA_def_pointer(func, "layout", "UILayout", "", "Sub-layout to put items in");
RNA_def_function_return(func, parm);
RNA_def_function_ui_description(
@@ -701,8 +716,14 @@ void RNA_api_ui_layout(StructRNA *srna)
"Sub-layout. Items placed in this sublayout are placed next to each other "
"in a row");
RNA_def_boolean(func, "align", false, "", "Align buttons to each other");
+ RNA_def_string(func,
+ "heading",
+ NULL,
+ UI_MAX_NAME_STR,
+ "Heading",
+ "Label to insert into the layout for this row");
- func = RNA_def_function(srna, "column", "uiLayoutColumn");
+ func = RNA_def_function(srna, "column", "uiLayoutColumnWithHeading");
parm = RNA_def_pointer(func, "layout", "UILayout", "", "Sub-layout to put items in");
RNA_def_function_return(func, parm);
RNA_def_function_ui_description(
@@ -710,6 +731,12 @@ void RNA_api_ui_layout(StructRNA *srna)
"Sub-layout. Items placed in this sublayout are placed under each other "
"in a column");
RNA_def_boolean(func, "align", false, "", "Align buttons to each other");
+ RNA_def_string(func,
+ "heading",
+ NULL,
+ UI_MAX_NAME_STR,
+ "Heading",
+ "Label to insert into the layout for this column");
func = RNA_def_function(srna, "column_flow", "uiLayoutColumnFlow");
RNA_def_int(func, "columns", 0, 0, INT_MAX, "", "Number of columns, 0 is automatic", 0, INT_MAX);
@@ -887,6 +914,20 @@ void RNA_api_ui_layout(StructRNA *srna)
RNA_def_parameter_flags(parm, 0, PARM_REQUIRED);
api_ui_item_common(func);
+ func = RNA_def_function(srna, "prop_decorator", "uiItemDecoratorR");
+ api_ui_item_rna_common(func);
+ RNA_def_int(func,
+ "index",
+ /* RNA_NO_INDEX == -1 */
+ -1,
+ -2,
+ INT_MAX,
+ "",
+ "The index of this button, when set a single member of an array can be accessed, "
+ "when set to -1 all array members are used",
+ -2,
+ INT_MAX);
+
for (int is_menu_hold = 0; is_menu_hold < 2; is_menu_hold++) {
func = (is_menu_hold) ? RNA_def_function(srna, "operator_menu_hold", "rna_uiItemOMenuHold") :
RNA_def_function(srna, "operator", "rna_uiItemO");
@@ -1492,6 +1533,7 @@ void RNA_api_ui_layout(StructRNA *srna)
RNA_def_function_flag(func, FUNC_USE_CONTEXT);
func = RNA_def_function(srna, "template_node_link", "uiTemplateNodeLink");
+ RNA_def_function_flag(func, FUNC_USE_CONTEXT);
parm = RNA_def_pointer(func, "ntree", "NodeTree", "", "");
RNA_def_parameter_flags(parm, 0, PARM_REQUIRED);
parm = RNA_def_pointer(func, "node", "Node", "", "");
@@ -1550,7 +1592,7 @@ void RNA_api_ui_layout(StructRNA *srna)
RNA_def_float_array(
func, "color", 4, node_socket_color_default, 0.0f, 1.0f, "Color", "", 0.0f, 1.0f);
- func = RNA_def_function(srna, "template_cache_file", "uiTemplateCacheFile");
+ func = RNA_def_function(srna, "template_cache_file", "rna_uiTemplateCacheFile");
RNA_def_function_ui_description(
func, "Item(s). User interface for selecting cache files and their source paths");
RNA_def_function_flag(func, FUNC_USE_CONTEXT);
diff --git a/source/blender/makesrna/intern/rna_userdef.c b/source/blender/makesrna/intern/rna_userdef.c
index 3b2753518bb..49a0121dadb 100644
--- a/source/blender/makesrna/intern/rna_userdef.c
+++ b/source/blender/makesrna/intern/rna_userdef.c
@@ -307,14 +307,27 @@ static void rna_userdef_screen_update_header_default(Main *bmain, Scene *scene,
USERDEF_TAG_DIRTY;
}
+static void rna_userdef_font_update(Main *UNUSED(bmain),
+ Scene *UNUSED(scene),
+ PointerRNA *UNUSED(ptr))
+{
+ BLF_cache_clear();
+ UI_reinit_font();
+}
+
static void rna_userdef_language_update(Main *UNUSED(bmain),
Scene *UNUSED(scene),
PointerRNA *UNUSED(ptr))
{
- BLF_cache_clear();
BLT_lang_set(NULL);
- UI_reinit_font();
- USERDEF_TAG_DIRTY;
+
+ const char *uilng = BLT_lang_get();
+ if (STREQ(uilng, "en_US")) {
+ U.transopts &= ~(USER_TR_IFACE | USER_TR_TOOLTIPS | USER_TR_NEWDATANAME);
+ }
+ else {
+ U.transopts |= (USER_TR_IFACE | USER_TR_TOOLTIPS | USER_TR_NEWDATANAME);
+ }
}
static void rna_userdef_script_autoexec_update(Main *UNUSED(bmain),
@@ -347,7 +360,7 @@ static void rna_userdef_load_ui_update(Main *UNUSED(bmain), Scene *UNUSED(scene)
static void rna_userdef_anisotropic_update(Main *bmain, Scene *scene, PointerRNA *ptr)
{
- GPU_set_anisotropic(bmain, U.anisotropic_filter);
+ GPU_set_anisotropic(U.anisotropic_filter);
rna_userdef_update(bmain, scene, ptr);
}
@@ -544,7 +557,7 @@ static void rna_Userdef_disk_cache_dir_update(Main *UNUSED(bmain),
{
if (U.sequencer_disk_cache_dir[0] != '\0') {
BLI_path_abs(U.sequencer_disk_cache_dir, BKE_main_blendfile_path_from_global());
- BLI_add_slash(U.sequencer_disk_cache_dir);
+ BLI_path_slash_ensure(U.sequencer_disk_cache_dir);
BLI_path_make_safe(U.sequencer_disk_cache_dir);
}
@@ -793,7 +806,7 @@ static PointerRNA rna_Addon_preferences_get(PointerRNA *ptr)
IDPropertyTemplate val = {0};
addon->prop = IDP_New(IDP_GROUP, &val, addon->module); /* name is unimportant */
}
- return rna_pointer_inherit_refine(ptr, apt->ext.srna, addon->prop);
+ return rna_pointer_inherit_refine(ptr, apt->rna_ext.srna, addon->prop);
}
else {
return PointerRNA_NULL;
@@ -808,7 +821,7 @@ static void rna_AddonPref_unregister(Main *UNUSED(bmain), StructRNA *type)
return;
}
- RNA_struct_free_extension(type, &apt->ext);
+ RNA_struct_free_extension(type, &apt->rna_ext);
RNA_struct_free(&BLENDER_RNA, type);
BKE_addon_pref_type_remove(apt);
@@ -850,8 +863,8 @@ static StructRNA *rna_AddonPref_register(Main *bmain,
/* check if we have registered this addon-pref type before, and remove it */
apt = BKE_addon_pref_type_find(dummy_addon.module, true);
- if (apt && apt->ext.srna) {
- rna_AddonPref_unregister(bmain, apt->ext.srna);
+ if (apt && apt->rna_ext.srna) {
+ rna_AddonPref_unregister(bmain, apt->rna_ext.srna);
}
/* create a new addon-pref type */
@@ -859,18 +872,18 @@ static StructRNA *rna_AddonPref_register(Main *bmain,
memcpy(apt, &dummy_apt, sizeof(dummy_apt));
BKE_addon_pref_type_add(apt);
- apt->ext.srna = RNA_def_struct_ptr(&BLENDER_RNA, identifier, &RNA_AddonPreferences);
- apt->ext.data = data;
- apt->ext.call = call;
- apt->ext.free = free;
- RNA_struct_blender_type_set(apt->ext.srna, apt);
+ apt->rna_ext.srna = RNA_def_struct_ptr(&BLENDER_RNA, identifier, &RNA_AddonPreferences);
+ apt->rna_ext.data = data;
+ apt->rna_ext.call = call;
+ apt->rna_ext.free = free;
+ RNA_struct_blender_type_set(apt->rna_ext.srna, apt);
// apt->draw = (have_function[0]) ? header_draw : NULL;
/* update while blender is running */
WM_main_add_notifier(NC_WINDOW, NULL);
- return apt->ext.srna;
+ return apt->rna_ext.srna;
}
/* placeholder, doesn't do anything useful yet */
@@ -4703,7 +4716,7 @@ static void rna_def_userdef_view(BlenderRNA *brna)
prop = RNA_def_property(srna, "use_text_antialiasing", PROP_BOOLEAN, PROP_NONE);
RNA_def_property_boolean_negative_sdna(prop, NULL, "text_render", USER_TEXT_DISABLE_AA);
- RNA_def_property_ui_text(prop, "Text Anti-aliasing", "Draw user interface text anti-aliased");
+ RNA_def_property_ui_text(prop, "Text Anti-Aliasing", "Draw user interface text anti-aliased");
RNA_def_property_update(prop, 0, "rna_userdef_text_update");
prop = RNA_def_property(srna, "text_hinting", PROP_ENUM, PROP_NONE);
@@ -4716,21 +4729,15 @@ static void rna_def_userdef_view(BlenderRNA *brna)
prop = RNA_def_property(srna, "font_path_ui", PROP_STRING, PROP_FILEPATH);
RNA_def_property_string_sdna(prop, NULL, "font_path_ui");
RNA_def_property_ui_text(prop, "Interface Font", "Path to interface font");
- RNA_def_property_update(prop, NC_WINDOW, "rna_userdef_language_update");
+ RNA_def_property_update(prop, NC_WINDOW, "rna_userdef_font_update");
prop = RNA_def_property(srna, "font_path_ui_mono", PROP_STRING, PROP_FILEPATH);
RNA_def_property_string_sdna(prop, NULL, "font_path_ui_mono");
RNA_def_property_ui_text(prop, "Mono-space Font", "Path to interface mono-space Font");
- RNA_def_property_update(prop, NC_WINDOW, "rna_userdef_language_update");
+ RNA_def_property_update(prop, NC_WINDOW, "rna_userdef_font_update");
/* Language. */
- prop = RNA_def_property(srna, "use_international_fonts", PROP_BOOLEAN, PROP_NONE);
- RNA_def_property_boolean_sdna(prop, NULL, "transopts", USER_DOTRANSLATE);
- RNA_def_property_ui_text(
- prop, "Translate UI", "Enable UI translation and use international fonts");
- RNA_def_property_update(prop, NC_WINDOW, "rna_userdef_language_update");
-
prop = RNA_def_property(srna, "language", PROP_ENUM, PROP_NONE);
RNA_def_property_enum_items(prop, rna_enum_language_default_items);
# ifdef WITH_INTERNATIONAL
@@ -4833,6 +4840,12 @@ static void rna_def_userdef_edit(BlenderRNA *brna)
RNA_def_property_ui_text(
prop, "Enter Edit Mode", "Enter Edit Mode automatically after adding a new object");
+ prop = RNA_def_property(srna, "collection_instance_empty_size", PROP_FLOAT, PROP_NONE);
+ RNA_def_property_range(prop, 0.001f, FLT_MAX);
+ RNA_def_property_ui_text(prop,
+ "Collection Instance Empty Size",
+ "Display size of the empty when new collection instances are created");
+
/* Undo */
prop = RNA_def_property(srna, "undo_steps", PROP_INT, PROP_NONE);
@@ -5785,8 +5798,9 @@ static void rna_def_userdef_input(BlenderRNA *brna)
prop = RNA_def_property(srna, "ndof_fly_helicopter", PROP_BOOLEAN, PROP_NONE);
RNA_def_property_boolean_sdna(prop, NULL, "ndof_flag", NDOF_FLY_HELICOPTER);
- RNA_def_property_ui_text(
- prop, "Helicopter Mode", "Device up/down directly controls your Z position");
+ RNA_def_property_ui_text(prop,
+ "Helicopter Mode",
+ "Device up/down directly controls the Z position of the 3D viewport");
/* let Python know whether NDOF is enabled */
prop = RNA_def_boolean(srna, "use_ndof", true, "", "");
@@ -6050,16 +6064,12 @@ static void rna_def_userdef_experimental(BlenderRNA *brna)
RNA_def_struct_clear_flag(srna, STRUCT_UNDO);
RNA_def_struct_ui_text(srna, "Experimental", "Experimental features");
- prop = RNA_def_property(srna, "use_undo_speedup", PROP_BOOLEAN, PROP_NONE);
- RNA_def_property_boolean_sdna(prop, NULL, "use_undo_speedup", 1);
+ prop = RNA_def_property(srna, "use_undo_legacy", PROP_BOOLEAN, PROP_NONE);
+ RNA_def_property_boolean_sdna(prop, NULL, "use_undo_legacy", 1);
RNA_def_property_ui_text(
prop,
- "Undo Speedup",
- "Use new undo speedup (WARNING: can lead to crashes and serious .blend file corruption)");
-
- prop = RNA_def_property(srna, "use_menu_search", PROP_BOOLEAN, PROP_NONE);
- RNA_def_property_boolean_sdna(prop, NULL, "use_menu_search", 1);
- RNA_def_property_ui_text(prop, "Menu Search", "Search actions by menus instead of operators");
+ "Undo Legacy",
+ "Use legacy undo (slower than the new default one, but may be more stable in some cases)");
}
static void rna_def_userdef_addon_collection(BlenderRNA *brna, PropertyRNA *cprop)
diff --git a/source/blender/makesrna/intern/rna_vfont_api.c b/source/blender/makesrna/intern/rna_vfont_api.c
index a85dde5d8b1..1bf61db4871 100644
--- a/source/blender/makesrna/intern/rna_vfont_api.c
+++ b/source/blender/makesrna/intern/rna_vfont_api.c
@@ -10,7 +10,7 @@
* 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,
+ * 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) 2015 by the Blender Foundation.
diff --git a/source/blender/makesrna/intern/rna_volume.c b/source/blender/makesrna/intern/rna_volume.c
index 0ee1dbc791b..b03d6082cea 100644
--- a/source/blender/makesrna/intern/rna_volume.c
+++ b/source/blender/makesrna/intern/rna_volume.c
@@ -194,6 +194,19 @@ static int rna_VolumeGrids_error_message_length(PointerRNA *ptr)
return strlen(BKE_volume_grids_error_msg(volume));
}
+/* Frame Filepath */
+static void rna_VolumeGrids_frame_filepath_get(PointerRNA *ptr, char *value)
+{
+ Volume *volume = (Volume *)ptr->data;
+ strcpy(value, BKE_volume_grids_frame_filepath(volume));
+}
+
+static int rna_VolumeGrids_frame_filepath_length(PointerRNA *ptr)
+{
+ Volume *volume = (Volume *)ptr->data;
+ return strlen(BKE_volume_grids_frame_filepath(volume));
+}
+
#else
static void rna_def_volume_grid(BlenderRNA *brna)
@@ -308,6 +321,16 @@ static void rna_def_volume_grids(BlenderRNA *brna, PropertyRNA *cprop)
"Frame number that volume grids will be loaded at, based on scene time "
"and volume parameters");
+ prop = RNA_def_property(srna, "frame_filepath", PROP_STRING, PROP_FILEPATH);
+ RNA_def_property_clear_flag(prop, PROP_EDITABLE);
+ RNA_def_property_string_funcs(
+ prop, "rna_VolumeGrids_frame_filepath_get", "rna_VolumeGrids_frame_filepath_length", NULL);
+
+ RNA_def_property_ui_text(prop,
+ "Frame File Path",
+ "Volume file used for loading the volume at the current frame. Empty "
+ "if the volume has not be loaded or the frame only exists in memory");
+
/* API */
FunctionRNA *func;
PropertyRNA *parm;
@@ -418,7 +441,7 @@ static void rna_def_volume_render(BlenderRNA *brna)
RNA_def_property_ui_range(prop, 0.0, 100.0, 1, 3);
RNA_def_property_ui_text(prop,
"Step Size",
- "Distance between volume samples. Higher values render more detail at "
+ "Distance between volume samples. Lower values render more detail at "
"the cost of performance. If set to zero, the step size is "
"automatically determined based on voxel size");
RNA_def_property_update(prop, 0, "rna_Volume_update_display");
@@ -446,7 +469,7 @@ static void rna_def_volume(BlenderRNA *brna)
/* File */
prop = RNA_def_property(srna, "filepath", PROP_STRING, PROP_FILEPATH);
RNA_def_property_clear_flag(prop, PROP_ANIMATABLE);
- RNA_def_property_ui_text(prop, "File Path", "Volume sample file used by this Volume data-block");
+ RNA_def_property_ui_text(prop, "File Path", "Volume file used by this Volume data-block");
RNA_def_property_update(prop, 0, "rna_Volume_update_filepath");
prop = RNA_def_property(srna, "packed_file", PROP_POINTER, PROP_NONE);
diff --git a/source/blender/makesrna/intern/rna_wm.c b/source/blender/makesrna/intern/rna_wm.c
index b0d77a2e176..6749aa9495a 100644
--- a/source/blender/makesrna/intern/rna_wm.c
+++ b/source/blender/makesrna/intern/rna_wm.c
@@ -450,7 +450,7 @@ static const EnumPropertyItem operator_flag_items[] = {
"UNDO_GROUPED",
0,
"Grouped Undo",
- "Push a single undo event for repetead instances of this operator"},
+ "Push a single undo event for repeated instances of this operator"},
{OPTYPE_BLOCKING, "BLOCKING", 0, "Blocking", "Block anything else from using the cursor"},
{OPTYPE_MACRO, "MACRO", 0, "Macro", "Use to check if an operator is a macro"},
{OPTYPE_GRAB_CURSOR_XY,
@@ -1085,7 +1085,7 @@ static PointerRNA rna_wmKeyConfig_preferences_get(PointerRNA *ptr)
wmKeyConfigPrefType_Runtime *kpt_rt = BKE_keyconfig_pref_type_find(kc->idname, true);
if (kpt_rt) {
wmKeyConfigPref *kpt = BKE_keyconfig_pref_ensure(&U, kc->idname);
- return rna_pointer_inherit_refine(ptr, kpt_rt->ext.srna, kpt->prop);
+ return rna_pointer_inherit_refine(ptr, kpt_rt->rna_ext.srna, kpt->prop);
}
else {
return PointerRNA_NULL;
@@ -1109,7 +1109,7 @@ static void rna_wmKeyConfigPref_unregister(Main *UNUSED(bmain), StructRNA *type)
return;
}
- RNA_struct_free_extension(type, &kpt_rt->ext);
+ RNA_struct_free_extension(type, &kpt_rt->rna_ext);
RNA_struct_free(&BLENDER_RNA, type);
/* Possible we're not in the preferences if they have been reset. */
@@ -1152,8 +1152,8 @@ static StructRNA *rna_wmKeyConfigPref_register(Main *bmain,
/* check if we have registered this keyconf-prefs type before, and remove it */
kpt_rt = BKE_keyconfig_pref_type_find(dummy_kpt.idname, true);
- if (kpt_rt && kpt_rt->ext.srna) {
- rna_wmKeyConfigPref_unregister(bmain, kpt_rt->ext.srna);
+ if (kpt_rt && kpt_rt->rna_ext.srna) {
+ rna_wmKeyConfigPref_unregister(bmain, kpt_rt->rna_ext.srna);
}
/* create a new keyconf-prefs type */
@@ -1162,18 +1162,18 @@ static StructRNA *rna_wmKeyConfigPref_register(Main *bmain,
BKE_keyconfig_pref_type_add(kpt_rt);
- kpt_rt->ext.srna = RNA_def_struct_ptr(&BLENDER_RNA, identifier, &RNA_KeyConfigPreferences);
- kpt_rt->ext.data = data;
- kpt_rt->ext.call = call;
- kpt_rt->ext.free = free;
- RNA_struct_blender_type_set(kpt_rt->ext.srna, kpt_rt);
+ kpt_rt->rna_ext.srna = RNA_def_struct_ptr(&BLENDER_RNA, identifier, &RNA_KeyConfigPreferences);
+ kpt_rt->rna_ext.data = data;
+ kpt_rt->rna_ext.call = call;
+ kpt_rt->rna_ext.free = free;
+ RNA_struct_blender_type_set(kpt_rt->rna_ext.srna, kpt_rt);
// kpt_rt->draw = (have_function[0]) ? header_draw : NULL;
/* update while blender is running */
WM_main_add_notifier(NC_WINDOW, NULL);
- return kpt_rt->ext.srna;
+ return kpt_rt->rna_ext.srna;
}
/* placeholder, doesn't do anything useful yet */
@@ -1233,39 +1233,6 @@ static bool rna_KeyMapItem_userdefined_get(PointerRNA *ptr)
return kmi->id < 0;
}
-static void rna_wmClipboard_get(PointerRNA *UNUSED(ptr), char *value)
-{
- char *pbuf;
- int pbuf_len;
-
- pbuf = WM_clipboard_text_get(false, &pbuf_len);
- if (pbuf) {
- memcpy(value, pbuf, pbuf_len + 1);
- MEM_freeN(pbuf);
- }
- else {
- value[0] = '\0';
- }
-}
-
-static int rna_wmClipboard_length(PointerRNA *UNUSED(ptr))
-{
- char *pbuf;
- int pbuf_len;
-
- pbuf = WM_clipboard_text_get(false, &pbuf_len);
- if (pbuf) {
- MEM_freeN(pbuf);
- }
-
- return pbuf_len;
-}
-
-static void rna_wmClipboard_set(PointerRNA *UNUSED(ptr), const char *value)
-{
- WM_clipboard_text_set((void *)value, false);
-}
-
static PointerRNA rna_WindowManager_xr_session_state_get(PointerRNA *ptr)
{
wmWindowManager *wm = ptr->data;
@@ -1292,12 +1259,12 @@ static bool rna_operator_poll_cb(bContext *C, wmOperatorType *ot)
void *ret;
bool visible;
- RNA_pointer_create(NULL, ot->ext.srna, NULL, &ptr); /* dummy */
- func = &rna_Operator_poll_func; /* RNA_struct_find_function(&ptr, "poll"); */
+ RNA_pointer_create(NULL, ot->rna_ext.srna, NULL, &ptr); /* dummy */
+ func = &rna_Operator_poll_func; /* RNA_struct_find_function(&ptr, "poll"); */
RNA_parameter_list_create(&list, &ptr, func);
RNA_parameter_set_lookup(&list, "context", &C);
- ot->ext.call(C, &ptr, func, &list);
+ ot->rna_ext.call(C, &ptr, func, &list);
RNA_parameter_get_lookup(&list, "visible", &ret);
visible = *(bool *)ret;
@@ -1317,12 +1284,12 @@ static int rna_operator_execute_cb(bContext *C, wmOperator *op)
void *ret;
int result;
- RNA_pointer_create(NULL, op->type->ext.srna, op, &opr);
+ RNA_pointer_create(NULL, op->type->rna_ext.srna, op, &opr);
func = &rna_Operator_execute_func; /* RNA_struct_find_function(&opr, "execute"); */
RNA_parameter_list_create(&list, &opr, func);
RNA_parameter_set_lookup(&list, "context", &C);
- op->type->ext.call(C, &opr, func, &list);
+ op->type->rna_ext.call(C, &opr, func, &list);
RNA_parameter_get_lookup(&list, "result", &ret);
result = *(int *)ret;
@@ -1343,12 +1310,12 @@ static bool rna_operator_check_cb(bContext *C, wmOperator *op)
void *ret;
bool result;
- RNA_pointer_create(NULL, op->type->ext.srna, op, &opr);
+ RNA_pointer_create(NULL, op->type->rna_ext.srna, op, &opr);
func = &rna_Operator_check_func; /* RNA_struct_find_function(&opr, "check"); */
RNA_parameter_list_create(&list, &opr, func);
RNA_parameter_set_lookup(&list, "context", &C);
- op->type->ext.call(C, &opr, func, &list);
+ op->type->rna_ext.call(C, &opr, func, &list);
RNA_parameter_get_lookup(&list, "result", &ret);
result = (*(bool *)ret) != 0;
@@ -1368,13 +1335,13 @@ static int rna_operator_invoke_cb(bContext *C, wmOperator *op, const wmEvent *ev
void *ret;
int result;
- RNA_pointer_create(NULL, op->type->ext.srna, op, &opr);
+ RNA_pointer_create(NULL, op->type->rna_ext.srna, op, &opr);
func = &rna_Operator_invoke_func; /* RNA_struct_find_function(&opr, "invoke"); */
RNA_parameter_list_create(&list, &opr, func);
RNA_parameter_set_lookup(&list, "context", &C);
RNA_parameter_set_lookup(&list, "event", &event);
- op->type->ext.call(C, &opr, func, &list);
+ op->type->rna_ext.call(C, &opr, func, &list);
RNA_parameter_get_lookup(&list, "result", &ret);
result = *(int *)ret;
@@ -1395,13 +1362,13 @@ static int rna_operator_modal_cb(bContext *C, wmOperator *op, const wmEvent *eve
void *ret;
int result;
- RNA_pointer_create(NULL, op->type->ext.srna, op, &opr);
+ RNA_pointer_create(NULL, op->type->rna_ext.srna, op, &opr);
func = &rna_Operator_modal_func; /* RNA_struct_find_function(&opr, "modal"); */
RNA_parameter_list_create(&list, &opr, func);
RNA_parameter_set_lookup(&list, "context", &C);
RNA_parameter_set_lookup(&list, "event", &event);
- op->type->ext.call(C, &opr, func, &list);
+ op->type->rna_ext.call(C, &opr, func, &list);
RNA_parameter_get_lookup(&list, "result", &ret);
result = *(int *)ret;
@@ -1419,12 +1386,12 @@ static void rna_operator_draw_cb(bContext *C, wmOperator *op)
ParameterList list;
FunctionRNA *func;
- RNA_pointer_create(NULL, op->type->ext.srna, op, &opr);
+ RNA_pointer_create(NULL, op->type->rna_ext.srna, op, &opr);
func = &rna_Operator_draw_func; /* RNA_struct_find_function(&opr, "draw"); */
RNA_parameter_list_create(&list, &opr, func);
RNA_parameter_set_lookup(&list, "context", &C);
- op->type->ext.call(C, &opr, func, &list);
+ op->type->rna_ext.call(C, &opr, func, &list);
RNA_parameter_list_free(&list);
}
@@ -1438,12 +1405,12 @@ static void rna_operator_cancel_cb(bContext *C, wmOperator *op)
ParameterList list;
FunctionRNA *func;
- RNA_pointer_create(NULL, op->type->ext.srna, op, &opr);
+ RNA_pointer_create(NULL, op->type->rna_ext.srna, op, &opr);
func = &rna_Operator_cancel_func; /* RNA_struct_find_function(&opr, "cancel"); */
RNA_parameter_list_create(&list, &opr, func);
RNA_parameter_set_lookup(&list, "context", &C);
- op->type->ext.call(C, &opr, func, &list);
+ op->type->rna_ext.call(C, &opr, func, &list);
RNA_parameter_list_free(&list);
}
@@ -1458,13 +1425,13 @@ static char *rna_operator_description_cb(bContext *C, wmOperatorType *ot, Pointe
void *ret;
char *result;
- RNA_pointer_create(NULL, ot->ext.srna, NULL, &ptr); /* dummy */
+ RNA_pointer_create(NULL, ot->rna_ext.srna, NULL, &ptr); /* dummy */
func = &rna_Operator_description_func; /* RNA_struct_find_function(&ptr, "description"); */
RNA_parameter_list_create(&list, &ptr, func);
RNA_parameter_set_lookup(&list, "context", &C);
RNA_parameter_set_lookup(&list, "properties", prop_ptr);
- ot->ext.call(C, &ptr, func, &list);
+ ot->rna_ext.call(C, &ptr, func, &list);
RNA_parameter_get_lookup(&list, "result", &ret);
result = (char *)ret;
@@ -1532,8 +1499,8 @@ static StructRNA *rna_Operator_register(Main *bmain,
/* check if we have registered this operator type before, and remove it */
{
wmOperatorType *ot = WM_operatortype_find(dummyot.idname, true);
- if (ot && ot->ext.srna) {
- rna_Operator_unregister(bmain, ot->ext.srna);
+ if (ot && ot->rna_ext.srna) {
+ rna_Operator_unregister(bmain, ot->rna_ext.srna);
}
}
@@ -1574,16 +1541,16 @@ static StructRNA *rna_Operator_register(Main *bmain,
* for now just remove from dir(bpy.types) */
/* create a new operator type */
- dummyot.ext.srna = RNA_def_struct_ptr(&BLENDER_RNA, dummyot.idname, &RNA_Operator);
+ dummyot.rna_ext.srna = RNA_def_struct_ptr(&BLENDER_RNA, dummyot.idname, &RNA_Operator);
/* Operator properties are registered separately. */
- RNA_def_struct_flag(dummyot.ext.srna, STRUCT_NO_IDPROPERTIES);
+ RNA_def_struct_flag(dummyot.rna_ext.srna, STRUCT_NO_IDPROPERTIES);
- RNA_def_struct_property_tags(dummyot.ext.srna, rna_enum_operator_property_tags);
- RNA_def_struct_translation_context(dummyot.ext.srna, dummyot.translation_context);
- dummyot.ext.data = data;
- dummyot.ext.call = call;
- dummyot.ext.free = free;
+ RNA_def_struct_property_tags(dummyot.rna_ext.srna, rna_enum_operator_property_tags);
+ RNA_def_struct_translation_context(dummyot.rna_ext.srna, dummyot.translation_context);
+ dummyot.rna_ext.data = data;
+ dummyot.rna_ext.call = call;
+ dummyot.rna_ext.free = free;
dummyot.pyop_poll = (have_function[0]) ? rna_operator_poll_cb : NULL;
dummyot.exec = (have_function[1]) ? rna_operator_execute_cb : NULL;
@@ -1598,7 +1565,7 @@ static StructRNA *rna_Operator_register(Main *bmain,
/* update while blender is running */
WM_main_add_notifier(NC_SCREEN | NA_EDITED, NULL);
- return dummyot.ext.srna;
+ return dummyot.rna_ext.srna;
}
static void rna_Operator_unregister(struct Main *bmain, StructRNA *type)
@@ -1620,7 +1587,7 @@ static void rna_Operator_unregister(struct Main *bmain, StructRNA *type)
}
WM_main_add_notifier(NC_SCREEN | NA_EDITED, NULL);
- RNA_struct_free_extension(type, &ot->ext);
+ RNA_struct_free_extension(type, &ot->rna_ext);
idname = ot->idname;
WM_operatortype_remove_ptr(ot);
@@ -1692,8 +1659,8 @@ static StructRNA *rna_MacroOperator_register(Main *bmain,
/* check if we have registered this operator type before, and remove it */
{
wmOperatorType *ot = WM_operatortype_find(dummyot.idname, true);
- if (ot && ot->ext.srna) {
- rna_Operator_unregister(bmain, ot->ext.srna);
+ if (ot && ot->rna_ext.srna) {
+ rna_Operator_unregister(bmain, ot->rna_ext.srna);
}
}
@@ -1734,11 +1701,11 @@ static StructRNA *rna_MacroOperator_register(Main *bmain,
* for now just remove from dir(bpy.types) */
/* create a new operator type */
- dummyot.ext.srna = RNA_def_struct_ptr(&BLENDER_RNA, dummyot.idname, &RNA_Operator);
- RNA_def_struct_translation_context(dummyot.ext.srna, dummyot.translation_context);
- dummyot.ext.data = data;
- dummyot.ext.call = call;
- dummyot.ext.free = free;
+ dummyot.rna_ext.srna = RNA_def_struct_ptr(&BLENDER_RNA, dummyot.idname, &RNA_Operator);
+ RNA_def_struct_translation_context(dummyot.rna_ext.srna, dummyot.translation_context);
+ dummyot.rna_ext.data = data;
+ dummyot.rna_ext.call = call;
+ dummyot.rna_ext.free = free;
dummyot.pyop_poll = (have_function[0]) ? rna_operator_poll_cb : NULL;
dummyot.ui = (have_function[3]) ? rna_operator_draw_cb : NULL;
@@ -1748,20 +1715,20 @@ static StructRNA *rna_MacroOperator_register(Main *bmain,
/* update while blender is running */
WM_main_add_notifier(NC_SCREEN | NA_EDITED, NULL);
- return dummyot.ext.srna;
+ return dummyot.rna_ext.srna;
}
# endif /* WITH_PYTHON */
static StructRNA *rna_Operator_refine(PointerRNA *opr)
{
wmOperator *op = (wmOperator *)opr->data;
- return (op->type && op->type->ext.srna) ? op->type->ext.srna : &RNA_Operator;
+ return (op->type && op->type->rna_ext.srna) ? op->type->rna_ext.srna : &RNA_Operator;
}
static StructRNA *rna_MacroOperator_refine(PointerRNA *opr)
{
wmOperator *op = (wmOperator *)opr->data;
- return (op->type && op->type->ext.srna) ? op->type->ext.srna : &RNA_Macro;
+ return (op->type && op->type->rna_ext.srna) ? op->type->rna_ext.srna : &RNA_Macro;
}
/* just to work around 'const char *' warning and to ensure this is a python op */
@@ -2493,11 +2460,6 @@ static void rna_def_windowmanager(BlenderRNA *brna)
RNA_def_property_ui_text(prop, "Key Configurations", "Registered key configurations");
rna_def_wm_keyconfigs(brna, prop);
- prop = RNA_def_property(srna, "clipboard", PROP_STRING, PROP_NONE);
- RNA_def_property_string_funcs(
- prop, "rna_wmClipboard_get", "rna_wmClipboard_length", "rna_wmClipboard_set");
- RNA_def_property_ui_text(prop, "Text Clipboard", "");
-
prop = RNA_def_property(srna, "xr_session_settings", PROP_POINTER, PROP_NONE);
RNA_def_property_pointer_sdna(prop, NULL, "xr.session_settings");
RNA_def_property_flag(prop, PROP_NEVER_NULL);
diff --git a/source/blender/makesrna/intern/rna_wm_api.c b/source/blender/makesrna/intern/rna_wm_api.c
index f1e3a999935..ee7ff472c12 100644
--- a/source/blender/makesrna/intern/rna_wm_api.c
+++ b/source/blender/makesrna/intern/rna_wm_api.c
@@ -419,7 +419,7 @@ static wmKeyMap *rna_keymap_new(wmKeyConfig *keyconf,
keymap = WM_keymap_ensure(keyconf, idname, spaceid, regionid);
}
else {
- keymap = WM_modalkeymap_add(keyconf, idname, NULL); /* items will be lazy init */
+ keymap = WM_modalkeymap_ensure(keyconf, idname, NULL); /* items will be lazy init */
}
if (keymap && tool) {
@@ -646,6 +646,9 @@ static wmEvent *rna_Window_event_add_simulate(wmWindow *win,
STRNCPY(e.utf8_buf, unicode);
}
+ /* Until we expose setting tablet values here. */
+ WM_event_tablet_data_default_set(&e.tablet);
+
return WM_event_add_simulate(win, &e);
}
diff --git a/source/blender/makesrna/intern/rna_wm_gizmo.c b/source/blender/makesrna/intern/rna_wm_gizmo.c
index 47d793382a7..742d3da27ac 100644
--- a/source/blender/makesrna/intern/rna_wm_gizmo.c
+++ b/source/blender/makesrna/intern/rna_wm_gizmo.c
@@ -26,6 +26,7 @@
#include "DNA_view3d_types.h"
#include "DNA_windowmanager_types.h"
+#include "BLI_listbase.h"
#include "BLI_utildefines.h"
#include "BLT_translation.h"
@@ -78,12 +79,12 @@ static void rna_gizmo_draw_cb(const struct bContext *C, struct wmGizmo *gz)
PointerRNA gz_ptr;
ParameterList list;
FunctionRNA *func;
- RNA_pointer_create(NULL, gz->type->ext.srna, gz, &gz_ptr);
+ RNA_pointer_create(NULL, gz->type->rna_ext.srna, gz, &gz_ptr);
/* RNA_struct_find_function(&gz_ptr, "draw"); */
func = &rna_Gizmo_draw_func;
RNA_parameter_list_create(&list, &gz_ptr, func);
RNA_parameter_set_lookup(&list, "context", &C);
- gzgroup->type->ext.call((bContext *)C, &gz_ptr, func, &list);
+ gzgroup->type->rna_ext.call((bContext *)C, &gz_ptr, func, &list);
RNA_parameter_list_free(&list);
}
@@ -94,13 +95,13 @@ static void rna_gizmo_draw_select_cb(const struct bContext *C, struct wmGizmo *g
PointerRNA gz_ptr;
ParameterList list;
FunctionRNA *func;
- RNA_pointer_create(NULL, gz->type->ext.srna, gz, &gz_ptr);
+ RNA_pointer_create(NULL, gz->type->rna_ext.srna, gz, &gz_ptr);
/* RNA_struct_find_function(&gz_ptr, "draw_select"); */
func = &rna_Gizmo_draw_select_func;
RNA_parameter_list_create(&list, &gz_ptr, func);
RNA_parameter_set_lookup(&list, "context", &C);
RNA_parameter_set_lookup(&list, "select_id", &select_id);
- gzgroup->type->ext.call((bContext *)C, &gz_ptr, func, &list);
+ gzgroup->type->rna_ext.call((bContext *)C, &gz_ptr, func, &list);
RNA_parameter_list_free(&list);
}
@@ -111,13 +112,13 @@ static int rna_gizmo_test_select_cb(struct bContext *C, struct wmGizmo *gz, cons
PointerRNA gz_ptr;
ParameterList list;
FunctionRNA *func;
- RNA_pointer_create(NULL, gz->type->ext.srna, gz, &gz_ptr);
+ RNA_pointer_create(NULL, gz->type->rna_ext.srna, gz, &gz_ptr);
/* RNA_struct_find_function(&gz_ptr, "test_select"); */
func = &rna_Gizmo_test_select_func;
RNA_parameter_list_create(&list, &gz_ptr, func);
RNA_parameter_set_lookup(&list, "context", &C);
RNA_parameter_set_lookup(&list, "location", location);
- gzgroup->type->ext.call((bContext *)C, &gz_ptr, func, &list);
+ gzgroup->type->rna_ext.call((bContext *)C, &gz_ptr, func, &list);
void *ret;
RNA_parameter_get_lookup(&list, "intersect_id", &ret);
@@ -138,14 +139,14 @@ static int rna_gizmo_modal_cb(struct bContext *C,
ParameterList list;
FunctionRNA *func;
const int tweak_flag_int = tweak_flag;
- RNA_pointer_create(NULL, gz->type->ext.srna, gz, &gz_ptr);
+ RNA_pointer_create(NULL, gz->type->rna_ext.srna, gz, &gz_ptr);
/* RNA_struct_find_function(&gz_ptr, "modal"); */
func = &rna_Gizmo_modal_func;
RNA_parameter_list_create(&list, &gz_ptr, func);
RNA_parameter_set_lookup(&list, "context", &C);
RNA_parameter_set_lookup(&list, "event", &event);
RNA_parameter_set_lookup(&list, "tweak", &tweak_flag_int);
- gzgroup->type->ext.call((bContext *)C, &gz_ptr, func, &list);
+ gzgroup->type->rna_ext.call((bContext *)C, &gz_ptr, func, &list);
void *ret;
RNA_parameter_get_lookup(&list, "result", &ret);
@@ -162,11 +163,11 @@ static void rna_gizmo_setup_cb(struct wmGizmo *gz)
PointerRNA gz_ptr;
ParameterList list;
FunctionRNA *func;
- RNA_pointer_create(NULL, gz->type->ext.srna, gz, &gz_ptr);
+ RNA_pointer_create(NULL, gz->type->rna_ext.srna, gz, &gz_ptr);
/* RNA_struct_find_function(&gz_ptr, "setup"); */
func = &rna_Gizmo_setup_func;
RNA_parameter_list_create(&list, &gz_ptr, func);
- gzgroup->type->ext.call((bContext *)NULL, &gz_ptr, func, &list);
+ gzgroup->type->rna_ext.call((bContext *)NULL, &gz_ptr, func, &list);
RNA_parameter_list_free(&list);
}
@@ -177,13 +178,13 @@ static int rna_gizmo_invoke_cb(struct bContext *C, struct wmGizmo *gz, const str
PointerRNA gz_ptr;
ParameterList list;
FunctionRNA *func;
- RNA_pointer_create(NULL, gz->type->ext.srna, gz, &gz_ptr);
+ RNA_pointer_create(NULL, gz->type->rna_ext.srna, gz, &gz_ptr);
/* RNA_struct_find_function(&gz_ptr, "invoke"); */
func = &rna_Gizmo_invoke_func;
RNA_parameter_list_create(&list, &gz_ptr, func);
RNA_parameter_set_lookup(&list, "context", &C);
RNA_parameter_set_lookup(&list, "event", &event);
- gzgroup->type->ext.call((bContext *)C, &gz_ptr, func, &list);
+ gzgroup->type->rna_ext.call((bContext *)C, &gz_ptr, func, &list);
void *ret;
RNA_parameter_get_lookup(&list, "result", &ret);
@@ -200,7 +201,7 @@ static void rna_gizmo_exit_cb(struct bContext *C, struct wmGizmo *gz, bool cance
PointerRNA gz_ptr;
ParameterList list;
FunctionRNA *func;
- RNA_pointer_create(NULL, gz->type->ext.srna, gz, &gz_ptr);
+ RNA_pointer_create(NULL, gz->type->rna_ext.srna, gz, &gz_ptr);
/* RNA_struct_find_function(&gz_ptr, "exit"); */
func = &rna_Gizmo_exit_func;
RNA_parameter_list_create(&list, &gz_ptr, func);
@@ -209,7 +210,7 @@ static void rna_gizmo_exit_cb(struct bContext *C, struct wmGizmo *gz, bool cance
int cancel_i = cancel;
RNA_parameter_set_lookup(&list, "cancel", &cancel_i);
}
- gzgroup->type->ext.call((bContext *)C, &gz_ptr, func, &list);
+ gzgroup->type->rna_ext.call((bContext *)C, &gz_ptr, func, &list);
RNA_parameter_list_free(&list);
}
@@ -220,11 +221,11 @@ static void rna_gizmo_select_refresh_cb(struct wmGizmo *gz)
PointerRNA gz_ptr;
ParameterList list;
FunctionRNA *func;
- RNA_pointer_create(NULL, gz->type->ext.srna, gz, &gz_ptr);
+ RNA_pointer_create(NULL, gz->type->rna_ext.srna, gz, &gz_ptr);
/* RNA_struct_find_function(&gz_ptr, "select_refresh"); */
func = &rna_Gizmo_select_refresh_func;
RNA_parameter_list_create(&list, &gz_ptr, func);
- gzgroup->type->ext.call((bContext *)NULL, &gz_ptr, func, &list);
+ gzgroup->type->rna_ext.call((bContext *)NULL, &gz_ptr, func, &list);
RNA_parameter_list_free(&list);
}
@@ -258,13 +259,12 @@ static wmGizmo *rna_GizmoProperties_find_operator(PointerRNA *ptr)
/* We could try workaruond this lookup, but not trivial. */
for (bScreen *screen = G_MAIN->screens.first; screen; screen = screen->id.next) {
IDProperty *properties = ptr->data;
- for (ScrArea *sa = screen->areabase.first; sa; sa = sa->next) {
- for (ARegion *region = sa->regionbase.first; region; region = region->next) {
+ LISTBASE_FOREACH (ScrArea *, area, &screen->areabase) {
+ LISTBASE_FOREACH (ARegion *, region, &area->regionbase) {
if (region->gizmo_map) {
wmGizmoMap *gzmap = region->gizmo_map;
- for (wmGizmoGroup *gzgroup = WM_gizmomap_group_list(gzmap)->first; gzgroup;
- gzgroup = gzgroup->next) {
- for (wmGizmo *gz = gzgroup->gizmos.first; gz; gz = gz->next) {
+ LISTBASE_FOREACH (wmGizmoGroup *, gzgroup, WM_gizmomap_group_list(gzmap)) {
+ LISTBASE_FOREACH (wmGizmo *, gz, &gzgroup->gizmos) {
if (gz->properties == properties) {
return gz;
}
@@ -401,12 +401,14 @@ RNA_GIZMO_GENERIC_FLAG_RW_DEF(flag_use_draw_offset_scale, flag, WM_GIZMO_DRAW_OF
RNA_GIZMO_GENERIC_FLAG_NEG_RW_DEF(flag_use_draw_scale, flag, WM_GIZMO_DRAW_OFFSET_SCALE);
RNA_GIZMO_GENERIC_FLAG_RW_DEF(flag_hide, flag, WM_GIZMO_HIDDEN);
RNA_GIZMO_GENERIC_FLAG_RW_DEF(flag_hide_select, flag, WM_GIZMO_HIDDEN_SELECT);
+RNA_GIZMO_GENERIC_FLAG_RW_DEF(flag_hide_keymap, flag, WM_GIZMO_HIDDEN_KEYMAP);
RNA_GIZMO_GENERIC_FLAG_RW_DEF(flag_use_grab_cursor, flag, WM_GIZMO_MOVE_CURSOR);
RNA_GIZMO_GENERIC_FLAG_RW_DEF(flag_use_select_background, flag, WM_GIZMO_SELECT_BACKGROUND);
RNA_GIZMO_GENERIC_FLAG_RW_DEF(flag_use_operator_tool_properties,
flag,
WM_GIZMO_OPERATOR_TOOL_INIT);
RNA_GIZMO_GENERIC_FLAG_RW_DEF(flag_use_event_handle_all, flag, WM_GIZMO_EVENT_HANDLE_ALL);
+RNA_GIZMO_GENERIC_FLAG_NEG_RW_DEF(flag_use_tooltip, flag, WM_GIZMO_NO_TOOLTIP);
/* wmGizmo.state */
RNA_GIZMO_FLAG_RO_DEF(state_is_highlight, state, WM_GIZMO_STATE_HIGHLIGHT);
@@ -475,8 +477,8 @@ static StructRNA *rna_Gizmo_register(Main *bmain,
/* check if we have registered this gizmo type before, and remove it */
{
const wmGizmoType *gzt = WM_gizmotype_find(dummygt.idname, true);
- if (gzt && gzt->ext.srna) {
- rna_Gizmo_unregister(bmain, gzt->ext.srna);
+ if (gzt && gzt->rna_ext.srna) {
+ rna_Gizmo_unregister(bmain, gzt->rna_ext.srna);
}
}
if (!RNA_struct_available_or_report(reports, dummygt.idname)) {
@@ -489,12 +491,12 @@ static StructRNA *rna_Gizmo_register(Main *bmain,
}
/* create a new gizmo type */
- dummygt.ext.srna = RNA_def_struct_ptr(&BLENDER_RNA, dummygt.idname, &RNA_Gizmo);
+ dummygt.rna_ext.srna = RNA_def_struct_ptr(&BLENDER_RNA, dummygt.idname, &RNA_Gizmo);
/* gizmo properties are registered separately */
- RNA_def_struct_flag(dummygt.ext.srna, STRUCT_NO_IDPROPERTIES);
- dummygt.ext.data = data;
- dummygt.ext.call = call;
- dummygt.ext.free = free;
+ RNA_def_struct_flag(dummygt.rna_ext.srna, STRUCT_NO_IDPROPERTIES);
+ dummygt.rna_ext.data = data;
+ dummygt.rna_ext.call = call;
+ dummygt.rna_ext.free = free;
{
int i = 0;
@@ -517,7 +519,7 @@ static StructRNA *rna_Gizmo_register(Main *bmain,
/* update while blender is running */
WM_main_add_notifier(NC_SCREEN | NA_EDITED, NULL);
- return dummygt.ext.srna;
+ return dummygt.rna_ext.srna;
}
static void rna_Gizmo_unregister(struct Main *bmain, StructRNA *type)
@@ -528,7 +530,7 @@ static void rna_Gizmo_unregister(struct Main *bmain, StructRNA *type)
return;
}
- RNA_struct_free_extension(type, &gzt->ext);
+ RNA_struct_free_extension(type, &gzt->rna_ext);
RNA_struct_free(&BLENDER_RNA, type);
WM_main_add_notifier(NC_SCREEN | NA_EDITED, NULL);
@@ -547,7 +549,7 @@ static void **rna_Gizmo_instance(PointerRNA *ptr)
static StructRNA *rna_Gizmo_refine(PointerRNA *mnp_ptr)
{
wmGizmo *gz = mnp_ptr->data;
- return (gz->type && gz->type->ext.srna) ? gz->type->ext.srna : &RNA_Gizmo;
+ return (gz->type && gz->type->rna_ext.srna) ? gz->type->rna_ext.srna : &RNA_Gizmo;
}
/** \} */
@@ -665,12 +667,12 @@ static bool rna_gizmogroup_poll_cb(const bContext *C, wmGizmoGroupType *gzgt)
void *ret;
bool visible;
- RNA_pointer_create(NULL, gzgt->ext.srna, NULL, &ptr); /* dummy */
+ RNA_pointer_create(NULL, gzgt->rna_ext.srna, NULL, &ptr); /* dummy */
func = &rna_GizmoGroup_poll_func; /* RNA_struct_find_function(&ptr, "poll"); */
RNA_parameter_list_create(&list, &ptr, func);
RNA_parameter_set_lookup(&list, "context", &C);
- gzgt->ext.call((bContext *)C, &ptr, func, &list);
+ gzgt->rna_ext.call((bContext *)C, &ptr, func, &list);
RNA_parameter_get_lookup(&list, "visible", &ret);
visible = *(bool *)ret;
@@ -688,12 +690,12 @@ static void rna_gizmogroup_setup_cb(const bContext *C, wmGizmoGroup *gzgroup)
ParameterList list;
FunctionRNA *func;
- RNA_pointer_create(NULL, gzgroup->type->ext.srna, gzgroup, &gzgroup_ptr);
+ RNA_pointer_create(NULL, gzgroup->type->rna_ext.srna, gzgroup, &gzgroup_ptr);
func = &rna_GizmoGroup_setup_func; /* RNA_struct_find_function(&wgroupr, "setup"); */
RNA_parameter_list_create(&list, &gzgroup_ptr, func);
RNA_parameter_set_lookup(&list, "context", &C);
- gzgroup->type->ext.call((bContext *)C, &gzgroup_ptr, func, &list);
+ gzgroup->type->rna_ext.call((bContext *)C, &gzgroup_ptr, func, &list);
RNA_parameter_list_free(&list);
}
@@ -707,13 +709,13 @@ static wmKeyMap *rna_gizmogroup_setup_keymap_cb(const wmGizmoGroupType *gzgt, wm
ParameterList list;
FunctionRNA *func;
- RNA_pointer_create(NULL, gzgt->ext.srna, NULL, &ptr); /* dummy */
+ RNA_pointer_create(NULL, gzgt->rna_ext.srna, NULL, &ptr); /* dummy */
func =
&rna_GizmoGroup_setup_keymap_func; /* RNA_struct_find_function(&wgroupr, "setup_keymap"); */
RNA_parameter_list_create(&list, &ptr, func);
RNA_parameter_set_lookup(&list, "keyconfig", &config);
- gzgt->ext.call(NULL, &ptr, func, &list);
+ gzgt->rna_ext.call(NULL, &ptr, func, &list);
RNA_parameter_get_lookup(&list, "keymap", &ret);
wmKeyMap *keymap = *(wmKeyMap **)ret;
@@ -731,12 +733,12 @@ static void rna_gizmogroup_refresh_cb(const bContext *C, wmGizmoGroup *gzgroup)
ParameterList list;
FunctionRNA *func;
- RNA_pointer_create(NULL, gzgroup->type->ext.srna, gzgroup, &gzgroup_ptr);
+ RNA_pointer_create(NULL, gzgroup->type->rna_ext.srna, gzgroup, &gzgroup_ptr);
func = &rna_GizmoGroup_refresh_func; /* RNA_struct_find_function(&wgroupr, "refresh"); */
RNA_parameter_list_create(&list, &gzgroup_ptr, func);
RNA_parameter_set_lookup(&list, "context", &C);
- gzgroup->type->ext.call((bContext *)C, &gzgroup_ptr, func, &list);
+ gzgroup->type->rna_ext.call((bContext *)C, &gzgroup_ptr, func, &list);
RNA_parameter_list_free(&list);
}
@@ -749,13 +751,13 @@ static void rna_gizmogroup_draw_prepare_cb(const bContext *C, wmGizmoGroup *gzgr
ParameterList list;
FunctionRNA *func;
- RNA_pointer_create(NULL, gzgroup->type->ext.srna, gzgroup, &gzgroup_ptr);
+ RNA_pointer_create(NULL, gzgroup->type->rna_ext.srna, gzgroup, &gzgroup_ptr);
func =
&rna_GizmoGroup_draw_prepare_func; /* RNA_struct_find_function(&wgroupr, "draw_prepare"); */
RNA_parameter_list_create(&list, &gzgroup_ptr, func);
RNA_parameter_set_lookup(&list, "context", &C);
- gzgroup->type->ext.call((bContext *)C, &gzgroup_ptr, func, &list);
+ gzgroup->type->rna_ext.call((bContext *)C, &gzgroup_ptr, func, &list);
RNA_parameter_list_free(&list);
}
@@ -771,7 +773,7 @@ static void rna_gizmogroup_invoke_prepare_cb(const bContext *C,
ParameterList list;
FunctionRNA *func;
- RNA_pointer_create(NULL, gzgroup->type->ext.srna, gzgroup, &gzgroup_ptr);
+ RNA_pointer_create(NULL, gzgroup->type->rna_ext.srna, gzgroup, &gzgroup_ptr);
/* RNA_struct_find_function(&wgroupr, "invoke_prepare"); */
func = &rna_GizmoGroup_invoke_prepare_func;
@@ -779,7 +781,7 @@ static void rna_gizmogroup_invoke_prepare_cb(const bContext *C,
RNA_parameter_set_lookup(&list, "context", &C);
RNA_parameter_set_lookup(&list, "gizmo", &gz);
RNA_parameter_set_lookup(&list, "event", &event);
- gzgroup->type->ext.call((bContext *)C, &gzgroup_ptr, func, &list);
+ gzgroup->type->rna_ext.call((bContext *)C, &gzgroup_ptr, func, &list);
RNA_parameter_list_free(&list);
}
@@ -846,8 +848,8 @@ static StructRNA *rna_GizmoGroup_register(Main *bmain,
/* check if we have registered this gizmogroup type before, and remove it */
{
wmGizmoGroupType *gzgt = WM_gizmogrouptype_find(dummywgt.idname, true);
- if (gzgt && gzgt->ext.srna) {
- rna_GizmoGroup_unregister(bmain, gzgt->ext.srna);
+ if (gzgt && gzgt->rna_ext.srna) {
+ rna_GizmoGroup_unregister(bmain, gzgt->rna_ext.srna);
}
}
if (!RNA_struct_available_or_report(reports, dummywgt.idname)) {
@@ -869,14 +871,14 @@ static StructRNA *rna_GizmoGroup_register(Main *bmain,
}
/* create a new gizmogroup type */
- dummywgt.ext.srna = RNA_def_struct_ptr(&BLENDER_RNA, dummywgt.idname, &RNA_GizmoGroup);
+ dummywgt.rna_ext.srna = RNA_def_struct_ptr(&BLENDER_RNA, dummywgt.idname, &RNA_GizmoGroup);
/* Gizmo group properties are registered separately. */
- RNA_def_struct_flag(dummywgt.ext.srna, STRUCT_NO_IDPROPERTIES);
+ RNA_def_struct_flag(dummywgt.rna_ext.srna, STRUCT_NO_IDPROPERTIES);
- dummywgt.ext.data = data;
- dummywgt.ext.call = call;
- dummywgt.ext.free = free;
+ dummywgt.rna_ext.data = data;
+ dummywgt.rna_ext.call = call;
+ dummywgt.rna_ext.free = free;
/* We used to register widget group types like this, now we do it similar to
* operator types. Thus we should be able to do the same as operator types now. */
@@ -904,7 +906,7 @@ static StructRNA *rna_GizmoGroup_register(Main *bmain,
WM_main_add_notifier(NC_SCREEN | NA_EDITED, NULL);
}
- return dummywgt.ext.srna;
+ return dummywgt.rna_ext.srna;
}
static void rna_GizmoGroup_unregister(struct Main *bmain, StructRNA *type)
@@ -915,7 +917,7 @@ static void rna_GizmoGroup_unregister(struct Main *bmain, StructRNA *type)
return;
}
- RNA_struct_free_extension(type, &gzgt->ext);
+ RNA_struct_free_extension(type, &gzgt->rna_ext);
RNA_struct_free(&BLENDER_RNA, type);
WM_main_add_notifier(NC_SCREEN | NA_EDITED, NULL);
@@ -934,7 +936,8 @@ static void **rna_GizmoGroup_instance(PointerRNA *ptr)
static StructRNA *rna_GizmoGroup_refine(PointerRNA *gzgroup_ptr)
{
wmGizmoGroup *gzgroup = gzgroup_ptr->data;
- return (gzgroup->type && gzgroup->type->ext.srna) ? gzgroup->type->ext.srna : &RNA_GizmoGroup;
+ return (gzgroup->type && gzgroup->type->rna_ext.srna) ? gzgroup->type->rna_ext.srna :
+ &RNA_GizmoGroup;
}
static void rna_GizmoGroup_gizmos_begin(CollectionPropertyIterator *iter, PointerRNA *gzgroup_ptr)
@@ -1201,6 +1204,12 @@ static void rna_def_gizmo(BlenderRNA *brna, PropertyRNA *cprop)
prop, "rna_Gizmo_flag_hide_select_get", "rna_Gizmo_flag_hide_select_set");
RNA_def_property_ui_text(prop, "Hide Select", "");
RNA_def_property_update(prop, 0, "rna_Gizmo_update_redraw");
+ /* WM_GIZMO_HIDDEN_KEYMAP */
+ prop = RNA_def_property(srna, "hide_keymap", PROP_BOOLEAN, PROP_NONE);
+ RNA_def_property_boolean_funcs(
+ prop, "rna_Gizmo_flag_hide_keymap_get", "rna_Gizmo_flag_hide_keymap_set");
+ RNA_def_property_ui_text(prop, "Hide Keymap", "Ignore the key-map for this gizmo");
+ RNA_def_property_update(prop, 0, "rna_Gizmo_update_redraw");
/* WM_GIZMO_MOVE_CURSOR */
prop = RNA_def_property(srna, "use_grab_cursor", PROP_BOOLEAN, PROP_NONE);
RNA_def_property_boolean_funcs(
@@ -1270,6 +1279,13 @@ static void rna_def_gizmo(BlenderRNA *brna, PropertyRNA *cprop)
"do not pass events through to be handled by other keymaps");
RNA_def_property_update(prop, 0, "rna_Gizmo_update_redraw");
+ /* WM_GIZMO_NO_TOOLTIP (negated) */
+ prop = RNA_def_property(srna, "use_tooltip", PROP_BOOLEAN, PROP_NONE);
+ RNA_def_property_boolean_funcs(
+ prop, "rna_Gizmo_flag_use_tooltip_get", "rna_Gizmo_flag_use_tooltip_set");
+ RNA_def_property_ui_text(prop, "Use Tooltip", "Use tool-tips when hovering over this gizmo");
+ /* No update needed. */
+
/* wmGizmo.state (readonly) */
/* WM_GIZMO_STATE_HIGHLIGHT */
prop = RNA_def_property(srna, "is_highlight", PROP_BOOLEAN, PROP_NONE);
diff --git a/source/blender/makesrna/intern/rna_workspace.c b/source/blender/makesrna/intern/rna_workspace.c
index 32e348ea72f..5f110189dd6 100644
--- a/source/blender/makesrna/intern/rna_workspace.c
+++ b/source/blender/makesrna/intern/rna_workspace.c
@@ -59,7 +59,7 @@ static void rna_window_update_all(Main *UNUSED(bmain),
void rna_workspace_screens_begin(CollectionPropertyIterator *iter, PointerRNA *ptr)
{
WorkSpace *workspace = (WorkSpace *)ptr->owner_id;
- rna_iterator_listbase_begin(iter, BKE_workspace_layouts_get(workspace), NULL);
+ rna_iterator_listbase_begin(iter, &workspace->layouts, NULL);
}
static PointerRNA rna_workspace_screens_item_get(CollectionPropertyIterator *iter)
diff --git a/source/blender/makesrna/intern/rna_xr.c b/source/blender/makesrna/intern/rna_xr.c
index 76cbc99b397..04a8500d136 100644
--- a/source/blender/makesrna/intern/rna_xr.c
+++ b/source/blender/makesrna/intern/rna_xr.c
@@ -38,13 +38,23 @@ static bool rna_XrSessionState_is_running(bContext *C)
{
# ifdef WITH_XR_OPENXR
const wmWindowManager *wm = CTX_wm_manager(C);
- return WM_xr_session_is_ready(&wm->xr);
+ return WM_xr_session_exists(&wm->xr);
# else
UNUSED_VARS(C);
return false;
# endif
}
+static void rna_XrSessionState_reset_to_base_pose(bContext *C)
+{
+# ifdef WITH_XR_OPENXR
+ wmWindowManager *wm = CTX_wm_manager(C);
+ WM_xr_session_base_pose_reset(&wm->xr);
+# else
+ UNUSED_VARS(C);
+# endif
+}
+
# ifdef WITH_XR_OPENXR
static wmXrData *rna_XrSessionState_wm_xr_data_get(PointerRNA *ptr)
{
@@ -197,6 +207,12 @@ static void rna_def_xr_session_state(BlenderRNA *brna)
parm = RNA_def_boolean(func, "result", 0, "Result", "");
RNA_def_function_return(func, parm);
+ func = RNA_def_function(srna, "reset_to_base_pose", "rna_XrSessionState_reset_to_base_pose");
+ RNA_def_function_ui_description(func, "Force resetting of position and rotation deltas");
+ RNA_def_function_flag(func, FUNC_NO_SELF);
+ parm = RNA_def_pointer(func, "context", "Context", "", "");
+ RNA_def_parameter_flags(parm, PROP_NEVER_NULL, PARM_REQUIRED);
+
prop = RNA_def_property(srna, "viewer_pose_location", PROP_FLOAT, PROP_TRANSLATION);
RNA_def_property_array(prop, 3);
RNA_def_property_float_funcs(prop, "rna_XrSessionState_viewer_pose_location_get", NULL, NULL);
diff --git a/source/blender/modifiers/CMakeLists.txt b/source/blender/modifiers/CMakeLists.txt
index 48acbdc17f3..8ab7d35070b 100644
--- a/source/blender/modifiers/CMakeLists.txt
+++ b/source/blender/modifiers/CMakeLists.txt
@@ -78,6 +78,7 @@ set(SRC
intern/MOD_shapekey.c
intern/MOD_shrinkwrap.c
intern/MOD_simpledeform.c
+ intern/MOD_simulation.cc
intern/MOD_skin.c
intern/MOD_smooth.c
intern/MOD_softbody.c
diff --git a/source/blender/modifiers/MOD_modifiertypes.h b/source/blender/modifiers/MOD_modifiertypes.h
index 5dc4adf4393..ba676bbe459 100644
--- a/source/blender/modifiers/MOD_modifiertypes.h
+++ b/source/blender/modifiers/MOD_modifiertypes.h
@@ -86,6 +86,7 @@ extern ModifierTypeInfo modifierType_CorrectiveSmooth;
extern ModifierTypeInfo modifierType_MeshSequenceCache;
extern ModifierTypeInfo modifierType_SurfaceDeform;
extern ModifierTypeInfo modifierType_WeightedNormal;
+extern ModifierTypeInfo modifierType_Simulation;
/* MOD_util.c */
void modifier_type_init(ModifierTypeInfo *types[]);
diff --git a/source/blender/modifiers/intern/MOD_armature.c b/source/blender/modifiers/intern/MOD_armature.c
index 3e78662da6c..99ce447236b 100644
--- a/source/blender/modifiers/intern/MOD_armature.c
+++ b/source/blender/modifiers/intern/MOD_armature.c
@@ -10,7 +10,7 @@
* 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,
+ * 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) 2005 by the Blender Foundation.
@@ -61,7 +61,7 @@ static void copyData(const ModifierData *md, ModifierData *target, const int fla
#endif
ArmatureModifierData *tamd = (ArmatureModifierData *)target;
- modifier_copyData_generic(md, target, flag);
+ BKE_modifier_copydata_generic(md, target, flag);
tamd->prevCos = NULL;
}
@@ -162,6 +162,11 @@ static void deformVertsEM(ModifierData *md,
ArmatureModifierData *amd = (ArmatureModifierData *)md;
Mesh *mesh_src = MOD_deform_mesh_eval_get(ctx->object, em, mesh, NULL, numVerts, false, false);
+ /* TODO(Campbell): use edit-mode data only (remove this line). */
+ if (mesh_src != NULL) {
+ BKE_mesh_wrapper_ensure_mdata(mesh_src);
+ }
+
MOD_previous_vcos_store(md, vertexCos); /* if next modifier needs original vertices */
armature_deform_verts(amd->object,
@@ -234,7 +239,7 @@ static void deformMatrices(ModifierData *md,
amd->defgrp_name,
NULL);
- if (mesh_src != mesh) {
+ if (!ELEM(mesh_src, NULL, mesh)) {
BKE_id_free(NULL, mesh_src);
}
}
@@ -244,7 +249,7 @@ ModifierTypeInfo modifierType_Armature = {
/* structName */ "ArmatureModifierData",
/* structSize */ sizeof(ArmatureModifierData),
/* type */ eModifierTypeType_OnlyDeform,
- /* flags */ eModifierTypeFlag_AcceptsCVs | eModifierTypeFlag_AcceptsLattice |
+ /* flags */ eModifierTypeFlag_AcceptsCVs | eModifierTypeFlag_AcceptsVertexCosOnly |
eModifierTypeFlag_SupportsEditmode,
/* copyData */ copyData,
@@ -253,7 +258,10 @@ ModifierTypeInfo modifierType_Armature = {
/* deformMatrices */ deformMatrices,
/* deformVertsEM */ deformVertsEM,
/* deformMatricesEM */ deformMatricesEM,
- /* applyModifier */ NULL,
+ /* modifyMesh */ NULL,
+ /* modifyHair */ NULL,
+ /* modifyPointCloud */ NULL,
+ /* modifyVolume */ NULL,
/* initData */ initData,
/* requiredDataMask */ requiredDataMask,
diff --git a/source/blender/modifiers/intern/MOD_array.c b/source/blender/modifiers/intern/MOD_array.c
index ff5bf3d0ee4..fc127c48fc9 100644
--- a/source/blender/modifiers/intern/MOD_array.c
+++ b/source/blender/modifiers/intern/MOD_array.c
@@ -10,7 +10,7 @@
* 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,
+ * 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) 2005 by the Blender Foundation.
@@ -353,7 +353,6 @@ static Mesh *arrayModifier_doArray(ArrayModifierData *amd,
const ModifierEvalContext *ctx,
Mesh *mesh)
{
- const float eps = 1e-6f;
const MVert *src_mvert;
MVert *mv, *mv_prev, *result_dm_verts;
@@ -473,21 +472,52 @@ static Mesh *arrayModifier_doArray(ArrayModifierData *amd,
}
}
+ /* About 67 million vertices max seems a decent limit for now. */
+ const size_t max_num_vertices = 1 << 26;
+
/* calculate the maximum number of copies which will fit within the
* prescribed length */
if (amd->fit_type == MOD_ARR_FITLENGTH || amd->fit_type == MOD_ARR_FITCURVE) {
+ const float float_epsilon = 1e-6f;
+ bool offset_is_too_small = false;
float dist = len_v3(offset[3]);
- if (dist > eps) {
+ if (dist > float_epsilon) {
/* this gives length = first copy start to last copy end
* add a tiny offset for floating point rounding errors */
- count = (length + eps) / dist + 1;
+ count = (length + float_epsilon) / dist + 1;
+
+ /* Ensure we keep things to a reasonable level, in terms of rough total amount of generated
+ * vertices.
+ */
+ if (((size_t)count * (size_t)chunk_nverts + (size_t)start_cap_nverts +
+ (size_t)end_cap_nverts) > max_num_vertices) {
+ count = 1;
+ offset_is_too_small = true;
+ }
}
else {
/* if the offset has no translation, just make one copy */
count = 1;
+ offset_is_too_small = true;
+ }
+
+ if (offset_is_too_small) {
+ BKE_modifier_set_error(
+ &amd->modifier,
+ "The offset is too small, we cannot generate the amount of geometry it would require");
}
}
+ /* Ensure we keep things to a reasonable level, in terms of rough total amount of generated
+ * vertices.
+ */
+ else if (((size_t)count * (size_t)chunk_nverts + (size_t)start_cap_nverts +
+ (size_t)end_cap_nverts) > max_num_vertices) {
+ count = 1;
+ BKE_modifier_set_error(&amd->modifier,
+ "The amount of copies is too high, we cannot generate the amount of "
+ "geometry it would require");
+ }
if (count < 1) {
count = 1;
@@ -761,7 +791,7 @@ static Mesh *arrayModifier_doArray(ArrayModifierData *amd,
return result;
}
-static Mesh *applyModifier(ModifierData *md, const ModifierEvalContext *ctx, Mesh *mesh)
+static Mesh *modifyMesh(ModifierData *md, const ModifierEvalContext *ctx, Mesh *mesh)
{
ArrayModifierData *amd = (ArrayModifierData *)md;
return arrayModifier_doArray(amd, ctx, mesh);
@@ -801,13 +831,16 @@ ModifierTypeInfo modifierType_Array = {
eModifierTypeFlag_SupportsEditmode | eModifierTypeFlag_EnableInEditmode |
eModifierTypeFlag_AcceptsCVs,
- /* copyData */ modifier_copyData_generic,
+ /* copyData */ BKE_modifier_copydata_generic,
/* deformVerts */ NULL,
/* deformMatrices */ NULL,
/* deformVertsEM */ NULL,
/* deformMatricesEM */ NULL,
- /* applyModifier */ applyModifier,
+ /* modifyMesh */ modifyMesh,
+ /* modifyHair */ NULL,
+ /* modifyPointCloud */ NULL,
+ /* modifyVolume */ NULL,
/* initData */ initData,
/* requiredDataMask */ NULL,
diff --git a/source/blender/modifiers/intern/MOD_bevel.c b/source/blender/modifiers/intern/MOD_bevel.c
index bd2f8a6dca3..fb1b3cd219e 100644
--- a/source/blender/modifiers/intern/MOD_bevel.c
+++ b/source/blender/modifiers/intern/MOD_bevel.c
@@ -10,7 +10,7 @@
* 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,
+ * 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) 2005 by the Blender Foundation.
@@ -72,7 +72,7 @@ static void copyData(const ModifierData *md_src, ModifierData *md_dst, const int
const BevelModifierData *bmd_src = (const BevelModifierData *)md_src;
BevelModifierData *bmd_dst = (BevelModifierData *)md_dst;
- modifier_copyData_generic(md_src, md_dst, flag);
+ BKE_modifier_copydata_generic(md_src, md_dst, flag);
bmd_dst->custom_profile = BKE_curveprofile_copy(bmd_src->custom_profile);
}
@@ -91,7 +91,7 @@ static void requiredDataMask(Object *UNUSED(ob),
/*
* This calls the new bevel code (added since 2.64)
*/
-static Mesh *applyModifier(ModifierData *md, const ModifierEvalContext *ctx, Mesh *mesh)
+static Mesh *modifyMesh(ModifierData *md, const ModifierEvalContext *ctx, Mesh *mesh)
{
Mesh *result;
BMesh *bm;
@@ -206,7 +206,7 @@ static Mesh *applyModifier(ModifierData *md, const ModifierEvalContext *ctx, Mes
Object *ob = ctx->object;
if (harden_normals && (ob->type == OB_MESH) && !(((Mesh *)ob->data)->flag & ME_AUTOSMOOTH)) {
- modifier_setError(md, "Enable 'Auto Smooth' in Object Data Properties");
+ BKE_modifier_set_error(md, "Enable 'Auto Smooth' in Object Data Properties");
harden_normals = false;
}
@@ -275,7 +275,10 @@ ModifierTypeInfo modifierType_Bevel = {
/* deformMatrices */ NULL,
/* deformVertsEM */ NULL,
/* deformMatricesEM */ NULL,
- /* applyModifier */ applyModifier,
+ /* modifyMesh */ modifyMesh,
+ /* modifyHair */ NULL,
+ /* modifyPointCloud */ NULL,
+ /* modifyVolume */ NULL,
/* initData */ initData,
/* requiredDataMask */ requiredDataMask,
/* freeData */ freeData,
diff --git a/source/blender/modifiers/intern/MOD_boolean.c b/source/blender/modifiers/intern/MOD_boolean.c
index 67610e8cd29..d8b375b0ee9 100644
--- a/source/blender/modifiers/intern/MOD_boolean.c
+++ b/source/blender/modifiers/intern/MOD_boolean.c
@@ -10,7 +10,7 @@
* 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,
+ * 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) 2005 by the Blender Foundation.
@@ -153,7 +153,7 @@ static int bm_face_isect_pair(BMFace *f, void *UNUSED(user_data))
return BM_elem_flag_test(f, BM_FACE_TAG) ? 1 : 0;
}
-static Mesh *applyModifier(ModifierData *md, const ModifierEvalContext *ctx, Mesh *mesh)
+static Mesh *modifyMesh(ModifierData *md, const ModifierEvalContext *ctx, Mesh *mesh)
{
BooleanModifierData *bmd = (BooleanModifierData *)md;
Mesh *result = mesh;
@@ -330,7 +330,7 @@ static Mesh *applyModifier(ModifierData *md, const ModifierEvalContext *ctx, Mes
/* if new mesh returned, return it; otherwise there was
* an error, so delete the modifier object */
if (result == NULL) {
- modifier_setError(md, "Cannot execute boolean operation");
+ BKE_modifier_set_error(md, "Cannot execute boolean operation");
}
}
@@ -353,13 +353,16 @@ ModifierTypeInfo modifierType_Boolean = {
/* type */ eModifierTypeType_Nonconstructive,
/* flags */ eModifierTypeFlag_AcceptsMesh,
- /* copyData */ modifier_copyData_generic,
+ /* copyData */ BKE_modifier_copydata_generic,
/* deformVerts */ NULL,
/* deformMatrices */ NULL,
/* deformVertsEM */ NULL,
/* deformMatricesEM */ NULL,
- /* applyModifier */ applyModifier,
+ /* modifyMesh */ modifyMesh,
+ /* modifyHair */ NULL,
+ /* modifyPointCloud */ NULL,
+ /* modifyVolume */ NULL,
/* initData */ initData,
/* requiredDataMask */ requiredDataMask,
diff --git a/source/blender/modifiers/intern/MOD_build.c b/source/blender/modifiers/intern/MOD_build.c
index 3c1a5744b33..2cd52005362 100644
--- a/source/blender/modifiers/intern/MOD_build.c
+++ b/source/blender/modifiers/intern/MOD_build.c
@@ -10,7 +10,7 @@
* 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,
+ * 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) 2005 by the Blender Foundation.
@@ -55,7 +55,7 @@ static bool dependsOnTime(ModifierData *UNUSED(md))
return true;
}
-static Mesh *applyModifier(ModifierData *md, const ModifierEvalContext *ctx, struct Mesh *mesh)
+static Mesh *modifyMesh(ModifierData *md, const ModifierEvalContext *ctx, struct Mesh *mesh)
{
Mesh *result;
BuildModifierData *bmd = (BuildModifierData *)md;
@@ -282,13 +282,16 @@ ModifierTypeInfo modifierType_Build = {
/* type */ eModifierTypeType_Nonconstructive,
/* flags */ eModifierTypeFlag_AcceptsMesh | eModifierTypeFlag_AcceptsCVs,
- /* copyData */ modifier_copyData_generic,
+ /* copyData */ BKE_modifier_copydata_generic,
/* deformVerts */ NULL,
/* deformMatrices */ NULL,
/* deformVertsEM */ NULL,
/* deformMatricesEM */ NULL,
- /* applyModifier */ applyModifier,
+ /* modifyMesh */ modifyMesh,
+ /* modifyHair */ NULL,
+ /* modifyPointCloud */ NULL,
+ /* modifyVolume */ NULL,
/* initData */ initData,
/* requiredDataMask */ NULL,
diff --git a/source/blender/modifiers/intern/MOD_cast.c b/source/blender/modifiers/intern/MOD_cast.c
index ed4a53ba2f3..ef8530557d7 100644
--- a/source/blender/modifiers/intern/MOD_cast.c
+++ b/source/blender/modifiers/intern/MOD_cast.c
@@ -10,7 +10,7 @@
* 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,
+ * 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) 2005 by the Blender Foundation.
@@ -502,10 +502,15 @@ static void deformVertsEM(ModifierData *md,
mesh_src = MOD_deform_mesh_eval_get(ctx->object, editData, mesh, NULL, numVerts, false, false);
}
- if (mesh_src) {
+ if (mesh && mesh->runtime.wrapper_type == ME_WRAPPER_TYPE_MDATA) {
BLI_assert(mesh_src->totvert == numVerts);
}
+ /* TODO(Campbell): use edit-mode data only (remove this line). */
+ if (mesh_src != NULL) {
+ BKE_mesh_wrapper_ensure_mdata(mesh_src);
+ }
+
if (cmd->type == MOD_CAST_TYPE_CUBOID) {
cuboid_do(cmd, ctx, ctx->object, mesh_src, vertexCos, numVerts);
}
@@ -513,7 +518,7 @@ static void deformVertsEM(ModifierData *md,
sphere_do(cmd, ctx, ctx->object, mesh_src, vertexCos, numVerts);
}
- if (mesh_src != mesh) {
+ if (!ELEM(mesh_src, NULL, mesh)) {
BKE_id_free(NULL, mesh_src);
}
}
@@ -523,16 +528,19 @@ ModifierTypeInfo modifierType_Cast = {
/* structName */ "CastModifierData",
/* structSize */ sizeof(CastModifierData),
/* type */ eModifierTypeType_OnlyDeform,
- /* flags */ eModifierTypeFlag_AcceptsCVs | eModifierTypeFlag_AcceptsLattice |
+ /* flags */ eModifierTypeFlag_AcceptsCVs | eModifierTypeFlag_AcceptsVertexCosOnly |
eModifierTypeFlag_SupportsEditmode,
- /* copyData */ modifier_copyData_generic,
+ /* copyData */ BKE_modifier_copydata_generic,
/* deformVerts */ deformVerts,
/* deformMatrices */ NULL,
/* deformVertsEM */ deformVertsEM,
/* deformMatricesEM */ NULL,
- /* applyModifier */ NULL,
+ /* modifyMesh */ NULL,
+ /* modifyHair */ NULL,
+ /* modifyPointCloud */ NULL,
+ /* modifyVolume */ NULL,
/* initData */ initData,
/* requiredDataMask */ requiredDataMask,
diff --git a/source/blender/modifiers/intern/MOD_cloth.c b/source/blender/modifiers/intern/MOD_cloth.c
index 0cab6144de8..da7485b5a2d 100644
--- a/source/blender/modifiers/intern/MOD_cloth.c
+++ b/source/blender/modifiers/intern/MOD_cloth.c
@@ -10,7 +10,7 @@
* 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,
+ * 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) 2005 by the Blender Foundation.
@@ -267,7 +267,10 @@ ModifierTypeInfo modifierType_Cloth = {
/* deformMatrices */ NULL,
/* deformVertsEM */ NULL,
/* deformMatricesEM */ NULL,
- /* applyModifier */ NULL,
+ /* modifyMesh */ NULL,
+ /* modifyHair */ NULL,
+ /* modifyPointCloud */ NULL,
+ /* modifyVolume */ NULL,
/* initData */ initData,
/* requiredDataMask */ requiredDataMask,
diff --git a/source/blender/modifiers/intern/MOD_collision.c b/source/blender/modifiers/intern/MOD_collision.c
index af468cb2d27..0c6133ed7a6 100644
--- a/source/blender/modifiers/intern/MOD_collision.c
+++ b/source/blender/modifiers/intern/MOD_collision.c
@@ -10,7 +10,7 @@
* 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,
+ * 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) 2005 by the Blender Foundation.
@@ -231,7 +231,7 @@ static void deformVerts(ModifierData *md,
}
}
- if (mesh_src != mesh) {
+ if (!ELEM(mesh_src, NULL, mesh)) {
BKE_id_free(NULL, mesh_src);
}
}
@@ -254,7 +254,10 @@ ModifierTypeInfo modifierType_Collision = {
/* deformMatrices */ NULL,
/* deformVertsEM */ NULL,
/* deformMatricesEM */ NULL,
- /* applyModifier */ NULL,
+ /* modifyMesh */ NULL,
+ /* modifyHair */ NULL,
+ /* modifyPointCloud */ NULL,
+ /* modifyVolume */ NULL,
/* initData */ initData,
/* requiredDataMask */ NULL,
diff --git a/source/blender/modifiers/intern/MOD_correctivesmooth.c b/source/blender/modifiers/intern/MOD_correctivesmooth.c
index 4eea9092e10..3b2268ea14d 100644
--- a/source/blender/modifiers/intern/MOD_correctivesmooth.c
+++ b/source/blender/modifiers/intern/MOD_correctivesmooth.c
@@ -10,7 +10,7 @@
* 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,
+ * 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) 2005 by the Blender Foundation.
@@ -79,7 +79,7 @@ static void copyData(const ModifierData *md, ModifierData *target, const int fla
const CorrectiveSmoothModifierData *csmd = (const CorrectiveSmoothModifierData *)md;
CorrectiveSmoothModifierData *tcsmd = (CorrectiveSmoothModifierData *)target;
- modifier_copyData_generic(md, target, flag);
+ BKE_modifier_copydata_generic(md, target, flag);
if (csmd->bind_coords) {
tcsmd->bind_coords = MEM_dupallocN(csmd->bind_coords);
@@ -602,12 +602,12 @@ static void correctivesmooth_modifier_do(ModifierData *md,
BLI_assert(csmd->bind_coords != NULL);
/* Copy bound data to the original modifier. */
CorrectiveSmoothModifierData *csmd_orig = (CorrectiveSmoothModifierData *)
- modifier_get_original(&csmd->modifier);
+ BKE_modifier_get_original(&csmd->modifier);
csmd_orig->bind_coords = MEM_dupallocN(csmd->bind_coords);
csmd_orig->bind_coords_num = csmd->bind_coords_num;
}
else {
- modifier_setError(md, "Attempt to bind from inactive dependency graph");
+ BKE_modifier_set_error(md, "Attempt to bind from inactive dependency graph");
}
}
@@ -617,14 +617,14 @@ static void correctivesmooth_modifier_do(ModifierData *md,
}
if ((csmd->rest_source == MOD_CORRECTIVESMOOTH_RESTSOURCE_BIND) && (csmd->bind_coords == NULL)) {
- modifier_setError(md, "Bind data required");
+ BKE_modifier_set_error(md, "Bind data required");
goto error;
}
/* If the number of verts has changed, the bind is invalid, so we do nothing */
if (csmd->rest_source == MOD_CORRECTIVESMOOTH_RESTSOURCE_BIND) {
if (csmd->bind_coords_num != numVerts) {
- modifier_setError(
+ BKE_modifier_set_error(
md, "Bind vertex count mismatch: %u to %u", csmd->bind_coords_num, numVerts);
goto error;
}
@@ -632,14 +632,15 @@ static void correctivesmooth_modifier_do(ModifierData *md,
else {
/* MOD_CORRECTIVESMOOTH_RESTSOURCE_ORCO */
if (ob->type != OB_MESH) {
- modifier_setError(md, "Object is not a mesh");
+ BKE_modifier_set_error(md, "Object is not a mesh");
goto error;
}
else {
uint me_numVerts = (uint)((em) ? em->bm->totvert : ((Mesh *)ob->data)->totvert);
if (me_numVerts != numVerts) {
- modifier_setError(md, "Original vertex count mismatch: %u to %u", me_numVerts, numVerts);
+ BKE_modifier_set_error(
+ md, "Original vertex count mismatch: %u to %u", me_numVerts, numVerts);
goto error;
}
}
@@ -740,7 +741,7 @@ static void deformVerts(ModifierData *md,
correctivesmooth_modifier_do(
md, ctx->depsgraph, ctx->object, mesh_src, vertexCos, (uint)numVerts, NULL);
- if (mesh_src != mesh) {
+ if (!ELEM(mesh_src, NULL, mesh)) {
BKE_id_free(NULL, mesh_src);
}
}
@@ -755,10 +756,15 @@ static void deformVertsEM(ModifierData *md,
Mesh *mesh_src = MOD_deform_mesh_eval_get(
ctx->object, editData, mesh, NULL, numVerts, false, false);
+ /* TODO(Campbell): use edit-mode data only (remove this line). */
+ if (mesh_src != NULL) {
+ BKE_mesh_wrapper_ensure_mdata(mesh_src);
+ }
+
correctivesmooth_modifier_do(
md, ctx->depsgraph, ctx->object, mesh_src, vertexCos, (uint)numVerts, editData);
- if (mesh_src != mesh) {
+ if (!ELEM(mesh_src, NULL, mesh)) {
BKE_id_free(NULL, mesh_src);
}
}
@@ -776,7 +782,10 @@ ModifierTypeInfo modifierType_CorrectiveSmooth = {
/* deformMatrices */ NULL,
/* deformVertsEM */ deformVertsEM,
/* deformMatricesEM */ NULL,
- /* applyModifier */ NULL,
+ /* modifyMesh */ NULL,
+ /* modifyHair */ NULL,
+ /* modifyPointCloud */ NULL,
+ /* modifyVolume */ NULL,
/* initData */ initData,
/* requiredDataMask */ requiredDataMask,
diff --git a/source/blender/modifiers/intern/MOD_curve.c b/source/blender/modifiers/intern/MOD_curve.c
index e287685a9e5..eec87a918ec 100644
--- a/source/blender/modifiers/intern/MOD_curve.c
+++ b/source/blender/modifiers/intern/MOD_curve.c
@@ -10,7 +10,7 @@
* 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,
+ * 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) 2005 by the Blender Foundation.
@@ -142,6 +142,11 @@ static void deformVertsEM(ModifierData *md,
{
Mesh *mesh_src = MOD_deform_mesh_eval_get(ctx->object, em, mesh, NULL, numVerts, false, false);
+ /* TODO(Campbell): use edit-mode data only (remove this line). */
+ if (mesh_src != NULL) {
+ BKE_mesh_wrapper_ensure_mdata(mesh_src);
+ }
+
deformVerts(md, ctx, mesh_src, vertexCos, numVerts);
if (!ELEM(mesh_src, NULL, mesh)) {
@@ -154,16 +159,19 @@ ModifierTypeInfo modifierType_Curve = {
/* structName */ "CurveModifierData",
/* structSize */ sizeof(CurveModifierData),
/* type */ eModifierTypeType_OnlyDeform,
- /* flags */ eModifierTypeFlag_AcceptsCVs | eModifierTypeFlag_AcceptsLattice |
+ /* flags */ eModifierTypeFlag_AcceptsCVs | eModifierTypeFlag_AcceptsVertexCosOnly |
eModifierTypeFlag_SupportsEditmode,
- /* copyData */ modifier_copyData_generic,
+ /* copyData */ BKE_modifier_copydata_generic,
/* deformVerts */ deformVerts,
/* deformMatrices */ NULL,
/* deformVertsEM */ deformVertsEM,
/* deformMatricesEM */ NULL,
- /* applyModifier */ NULL,
+ /* modifyMesh */ NULL,
+ /* modifyHair */ NULL,
+ /* modifyPointCloud */ NULL,
+ /* modifyVolume */ NULL,
/* initData */ initData,
/* requiredDataMask */ requiredDataMask,
diff --git a/source/blender/modifiers/intern/MOD_datatransfer.c b/source/blender/modifiers/intern/MOD_datatransfer.c
index 72cbe197251..dea4bad6999 100644
--- a/source/blender/modifiers/intern/MOD_datatransfer.c
+++ b/source/blender/modifiers/intern/MOD_datatransfer.c
@@ -10,7 +10,7 @@
* 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,
+ * 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) 2014 Blender Foundation.
@@ -156,7 +156,7 @@ static bool isDisabled(const struct Scene *UNUSED(scene),
(DT_TYPE_BWEIGHT_VERT | DT_TYPE_BWEIGHT_EDGE | DT_TYPE_CREASE | DT_TYPE_SHARP_EDGE | \
DT_TYPE_LNOR | DT_TYPE_SHARP_FACE)
-static Mesh *applyModifier(ModifierData *md, const ModifierEvalContext *ctx, Mesh *me_mod)
+static Mesh *modifyMesh(ModifierData *md, const ModifierEvalContext *ctx, Mesh *me_mod)
{
DataTransferModifierData *dtmd = (DataTransferModifierData *)md;
struct Scene *scene = DEG_get_evaluated_scene(ctx->depsgraph);
@@ -217,16 +217,15 @@ static Mesh *applyModifier(ModifierData *md, const ModifierEvalContext *ctx, Mes
&reports);
if (BKE_reports_contain(&reports, RPT_ERROR)) {
- modifier_setError(md, "%s", BKE_reports_string(&reports, RPT_ERROR));
+ BKE_modifier_set_error(md, "%s", BKE_reports_string(&reports, RPT_ERROR));
}
else if ((dtmd->data_types & DT_TYPE_LNOR) && !(me->flag & ME_AUTOSMOOTH)) {
- modifier_setError((ModifierData *)dtmd, "Enable 'Auto Smooth' in Object Data Properties");
+ BKE_modifier_set_error((ModifierData *)dtmd, "Enable 'Auto Smooth' in Object Data Properties");
}
else if (result->totvert > HIGH_POLY_WARNING ||
((Mesh *)(ob_source->data))->totvert > HIGH_POLY_WARNING) {
- modifier_setError(
- md,
- "You are using a rather high poly as source or destination, computation might be slow");
+ BKE_modifier_set_error(
+ md, "Source or destination object has a high polygon count, computation might be slow");
}
return result;
@@ -243,13 +242,16 @@ ModifierTypeInfo modifierType_DataTransfer = {
/* flags */ eModifierTypeFlag_AcceptsMesh | eModifierTypeFlag_SupportsMapping |
eModifierTypeFlag_SupportsEditmode | eModifierTypeFlag_UsesPreview,
- /* copyData */ modifier_copyData_generic,
+ /* copyData */ BKE_modifier_copydata_generic,
/* deformVerts */ NULL,
/* deformMatrices */ NULL,
/* deformVertsEM */ NULL,
/* deformMatricesEM */ NULL,
- /* applyModifier */ applyModifier,
+ /* modifyMesh */ modifyMesh,
+ /* modifyHair */ NULL,
+ /* modifyPointCloud */ NULL,
+ /* modifyVolume */ NULL,
/* initData */ initData,
/* requiredDataMask */ requiredDataMask,
diff --git a/source/blender/modifiers/intern/MOD_decimate.c b/source/blender/modifiers/intern/MOD_decimate.c
index cf07b5460e1..2bd33af7582 100644
--- a/source/blender/modifiers/intern/MOD_decimate.c
+++ b/source/blender/modifiers/intern/MOD_decimate.c
@@ -10,7 +10,7 @@
* 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,
+ * 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) 2005 by the Blender Foundation.
@@ -73,7 +73,7 @@ static DecimateModifierData *getOriginalModifierData(const DecimateModifierData
const ModifierEvalContext *ctx)
{
Object *ob_orig = DEG_get_original_object(ctx->object);
- return (DecimateModifierData *)modifiers_findByName(ob_orig, dmd->modifier.name);
+ return (DecimateModifierData *)BKE_modifiers_findby_name(ob_orig, dmd->modifier.name);
}
static void updateFaceCount(const ModifierEvalContext *ctx,
@@ -89,7 +89,7 @@ static void updateFaceCount(const ModifierEvalContext *ctx,
}
}
-static Mesh *applyModifier(ModifierData *md, const ModifierEvalContext *ctx, Mesh *meshData)
+static Mesh *modifyMesh(ModifierData *md, const ModifierEvalContext *ctx, Mesh *meshData)
{
DecimateModifierData *dmd = (DecimateModifierData *)md;
Mesh *mesh = meshData, *result = NULL;
@@ -128,7 +128,7 @@ static Mesh *applyModifier(ModifierData *md, const ModifierEvalContext *ctx, Mes
}
if (dmd->face_count <= 3) {
- modifier_setError(md, "Modifier requires more than 3 input faces");
+ BKE_modifier_set_error(md, "Modifier requires more than 3 input faces");
return mesh;
}
@@ -222,13 +222,16 @@ ModifierTypeInfo modifierType_Decimate = {
/* type */ eModifierTypeType_Nonconstructive,
/* flags */ eModifierTypeFlag_AcceptsMesh | eModifierTypeFlag_AcceptsCVs,
- /* copyData */ modifier_copyData_generic,
+ /* copyData */ BKE_modifier_copydata_generic,
/* deformVerts */ NULL,
/* deformMatrices */ NULL,
/* deformVertsEM */ NULL,
/* deformMatricesEM */ NULL,
- /* applyModifier */ applyModifier,
+ /* modifyMesh */ modifyMesh,
+ /* modifyHair */ NULL,
+ /* modifyPointCloud */ NULL,
+ /* modifyVolume */ NULL,
/* initData */ initData,
/* requiredDataMask */ requiredDataMask,
diff --git a/source/blender/modifiers/intern/MOD_displace.c b/source/blender/modifiers/intern/MOD_displace.c
index a1b02e201d9..0cb882d0532 100644
--- a/source/blender/modifiers/intern/MOD_displace.c
+++ b/source/blender/modifiers/intern/MOD_displace.c
@@ -10,7 +10,7 @@
* 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,
+ * 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) 2005 by the Blender Foundation.
@@ -134,19 +134,28 @@ static bool isDisabled(const struct Scene *UNUSED(scene),
static void updateDepsgraph(ModifierData *md, const ModifierUpdateDepsgraphContext *ctx)
{
DisplaceModifierData *dmd = (DisplaceModifierData *)md;
- if (dmd->map_object != NULL && dmd->texmapping == MOD_DISP_MAP_OBJECT) {
- DEG_add_modifier_to_transform_relation(ctx->node, "Displace Modifier");
- DEG_add_object_relation(
- ctx->node, dmd->map_object, DEG_OB_COMP_TRANSFORM, "Displace Modifier");
- }
- if (dmd->texmapping == MOD_DISP_MAP_GLOBAL ||
- (ELEM(
- dmd->direction, MOD_DISP_DIR_X, MOD_DISP_DIR_Y, MOD_DISP_DIR_Z, MOD_DISP_DIR_RGB_XYZ) &&
- dmd->space == MOD_DISP_SPACE_GLOBAL)) {
- DEG_add_modifier_to_transform_relation(ctx->node, "Displace Modifier");
+ bool need_transform_relation = false;
+
+ if (dmd->space == MOD_DISP_SPACE_GLOBAL &&
+ ELEM(dmd->direction, MOD_DISP_DIR_X, MOD_DISP_DIR_Y, MOD_DISP_DIR_Z, MOD_DISP_DIR_RGB_XYZ)) {
+ need_transform_relation = true;
}
+
if (dmd->texture != NULL) {
DEG_add_generic_id_relation(ctx->node, &dmd->texture->id, "Displace Modifier");
+
+ if (dmd->map_object != NULL && dmd->texmapping == MOD_DISP_MAP_OBJECT) {
+ MOD_depsgraph_update_object_bone_relation(
+ ctx->node, dmd->map_object, dmd->map_bone, "Displace Modifier");
+ need_transform_relation = true;
+ }
+ if (dmd->texmapping == MOD_DISP_MAP_GLOBAL) {
+ need_transform_relation = true;
+ }
+ }
+
+ if (need_transform_relation) {
+ DEG_add_modifier_to_transform_relation(ctx->node, "Displace Modifier");
}
}
@@ -398,6 +407,11 @@ static void deformVertsEM(ModifierData *md,
Mesh *mesh_src = MOD_deform_mesh_eval_get(
ctx->object, editData, mesh, NULL, numVerts, false, false);
+ /* TODO(Campbell): use edit-mode data only (remove this line). */
+ if (mesh_src != NULL) {
+ BKE_mesh_wrapper_ensure_mdata(mesh_src);
+ }
+
displaceModifier_do((DisplaceModifierData *)md, ctx, mesh_src, vertexCos, numVerts);
if (!ELEM(mesh_src, NULL, mesh)) {
@@ -412,13 +426,16 @@ ModifierTypeInfo modifierType_Displace = {
/* type */ eModifierTypeType_OnlyDeform,
/* flags */ eModifierTypeFlag_AcceptsMesh | eModifierTypeFlag_SupportsEditmode,
- /* copyData */ modifier_copyData_generic,
+ /* copyData */ BKE_modifier_copydata_generic,
/* deformVerts */ deformVerts,
/* deformMatrices */ NULL,
/* deformVertsEM */ deformVertsEM,
/* deformMatricesEM */ NULL,
- /* applyModifier */ NULL,
+ /* modifyMesh */ NULL,
+ /* modifyHair */ NULL,
+ /* modifyPointCloud */ NULL,
+ /* modifyVolume */ NULL,
/* initData */ initData,
/* requiredDataMask */ requiredDataMask,
diff --git a/source/blender/modifiers/intern/MOD_dynamicpaint.c b/source/blender/modifiers/intern/MOD_dynamicpaint.c
index 457f47bf025..3cace5745e6 100644
--- a/source/blender/modifiers/intern/MOD_dynamicpaint.c
+++ b/source/blender/modifiers/intern/MOD_dynamicpaint.c
@@ -10,7 +10,7 @@
* 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,
+ * along with this program; if not, write to the Free Software Foundation,
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
@@ -20,6 +20,7 @@
#include <stddef.h>
+#include "BLI_listbase.h"
#include "BLI_utildefines.h"
#include "DNA_dynamicpaint_types.h"
@@ -100,7 +101,7 @@ static void requiredDataMask(Object *UNUSED(ob),
}
}
-static Mesh *applyModifier(ModifierData *md, const ModifierEvalContext *ctx, Mesh *mesh)
+static Mesh *modifyMesh(ModifierData *md, const ModifierEvalContext *ctx, Mesh *mesh)
{
DynamicPaintModifierData *pmd = (DynamicPaintModifierData *)md;
@@ -123,8 +124,7 @@ static void updateDepsgraph(ModifierData *md, const ModifierUpdateDepsgraphConte
DynamicPaintModifierData *pmd = (DynamicPaintModifierData *)md;
/* Add relation from canvases to all brush objects. */
if (pmd->canvas != NULL && pmd->type == MOD_DYNAMICPAINT_TYPE_CANVAS) {
- for (DynamicPaintSurface *surface = pmd->canvas->surfaces.first; surface;
- surface = surface->next) {
+ LISTBASE_FOREACH (DynamicPaintSurface *, surface, &pmd->canvas->surfaces) {
if (surface->effect & MOD_DPAINT_EFFECT_DO_DRIP) {
DEG_add_forcefield_relations(
ctx->node, ctx->object, surface->effector_weights, true, 0, "Dynamic Paint Field");
@@ -187,7 +187,10 @@ ModifierTypeInfo modifierType_DynamicPaint = {
/* deformMatrices */ NULL,
/* deformVertsEM */ NULL,
/* deformMatricesEM */ NULL,
- /* applyModifier */ applyModifier,
+ /* modifyMesh */ modifyMesh,
+ /* modifyHair */ NULL,
+ /* modifyPointCloud */ NULL,
+ /* modifyVolume */ NULL,
/* initData */ initData,
/* requiredDataMask */ requiredDataMask,
diff --git a/source/blender/modifiers/intern/MOD_edgesplit.c b/source/blender/modifiers/intern/MOD_edgesplit.c
index 69ba4aa2795..dd5669cd10c 100644
--- a/source/blender/modifiers/intern/MOD_edgesplit.c
+++ b/source/blender/modifiers/intern/MOD_edgesplit.c
@@ -10,7 +10,7 @@
* 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,
+ * 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) 2005 by the Blender Foundation.
@@ -113,7 +113,7 @@ static void initData(ModifierData *md)
emd->flags = MOD_EDGESPLIT_FROMANGLE | MOD_EDGESPLIT_FROMFLAG;
}
-static Mesh *applyModifier(ModifierData *md, const ModifierEvalContext *UNUSED(ctx), Mesh *mesh)
+static Mesh *modifyMesh(ModifierData *md, const ModifierEvalContext *UNUSED(ctx), Mesh *mesh)
{
Mesh *result;
EdgeSplitModifierData *emd = (EdgeSplitModifierData *)md;
@@ -136,13 +136,16 @@ ModifierTypeInfo modifierType_EdgeSplit = {
eModifierTypeFlag_SupportsMapping | eModifierTypeFlag_SupportsEditmode |
eModifierTypeFlag_EnableInEditmode,
- /* copyData */ modifier_copyData_generic,
+ /* copyData */ BKE_modifier_copydata_generic,
/* deformVerts */ NULL,
/* deformMatrices */ NULL,
/* deformVertsEM */ NULL,
/* deformMatricesEM */ NULL,
- /* applyModifier */ applyModifier,
+ /* modifyMesh */ modifyMesh,
+ /* modifyHair */ NULL,
+ /* modifyPointCloud */ NULL,
+ /* modifyVolume */ NULL,
/* initData */ initData,
/* requiredDataMask */ NULL,
diff --git a/source/blender/modifiers/intern/MOD_explode.c b/source/blender/modifiers/intern/MOD_explode.c
index d380747eb31..747269f4c80 100644
--- a/source/blender/modifiers/intern/MOD_explode.c
+++ b/source/blender/modifiers/intern/MOD_explode.c
@@ -10,7 +10,7 @@
* 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,
+ * 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) 2005 by the Blender Foundation.
@@ -67,7 +67,7 @@ static void copyData(const ModifierData *md, ModifierData *target, const int fla
#endif
ExplodeModifierData *temd = (ExplodeModifierData *)target;
- modifier_copyData_generic(md, target, flag);
+ BKE_modifier_copydata_generic(md, target, flag);
temd->facepa = NULL;
}
@@ -1123,7 +1123,7 @@ static ParticleSystemModifierData *findPrecedingParticlesystem(Object *ob, Modif
}
return psmd;
}
-static Mesh *applyModifier(ModifierData *md, const ModifierEvalContext *ctx, Mesh *mesh)
+static Mesh *modifyMesh(ModifierData *md, const ModifierEvalContext *ctx, Mesh *mesh)
{
ExplodeModifierData *emd = (ExplodeModifierData *)md;
ParticleSystemModifierData *psmd = findPrecedingParticlesystem(ctx->object, md);
@@ -1186,7 +1186,10 @@ ModifierTypeInfo modifierType_Explode = {
/* deformMatrices */ NULL,
/* deformVertsEM */ NULL,
/* deformMatricesEM */ NULL,
- /* applyModifier */ applyModifier,
+ /* modifyMesh */ modifyMesh,
+ /* modifyHair */ NULL,
+ /* modifyPointCloud */ NULL,
+ /* modifyVolume */ NULL,
/* initData */ initData,
/* requiredDataMask */ requiredDataMask,
diff --git a/source/blender/modifiers/intern/MOD_fluid.c b/source/blender/modifiers/intern/MOD_fluid.c
index 1c2f0a413a7..d3f05ee714f 100644
--- a/source/blender/modifiers/intern/MOD_fluid.c
+++ b/source/blender/modifiers/intern/MOD_fluid.c
@@ -10,7 +10,7 @@
* 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,
+ * 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) 2005 by the Blender Foundation.
@@ -101,7 +101,7 @@ static void requiredDataMask(Object *UNUSED(ob),
}
}
-static Mesh *applyModifier(ModifierData *md, const ModifierEvalContext *ctx, Mesh *me)
+static Mesh *modifyMesh(ModifierData *md, const ModifierEvalContext *ctx, Mesh *me)
{
#ifndef WITH_FLUID
UNUSED_VARS(md, ctx);
@@ -159,7 +159,7 @@ static void updateDepsgraph(ModifierData *md, const ModifierUpdateDepsgraphConte
ctx->object,
mmd->domain->effector_weights,
true,
- PFIELD_SMOKEFLOW,
+ PFIELD_FLUIDFLOW,
"Fluid Force Field");
if (mmd->domain->guide_parent != NULL) {
@@ -207,7 +207,10 @@ ModifierTypeInfo modifierType_Fluid = {
/* deformMatrices */ NULL,
/* deformVertsEM */ NULL,
/* deformMatricesEM */ NULL,
- /* applyModifier */ applyModifier,
+ /* modifyMesh */ modifyMesh,
+ /* modifyHair */ NULL,
+ /* modifyPointCloud */ NULL,
+ /* modifyVolume */ NULL,
/* initData */ initData,
/* requiredDataMask */ requiredDataMask,
diff --git a/source/blender/modifiers/intern/MOD_hook.c b/source/blender/modifiers/intern/MOD_hook.c
index 1ae2c5e4424..d93b3c56e5a 100644
--- a/source/blender/modifiers/intern/MOD_hook.c
+++ b/source/blender/modifiers/intern/MOD_hook.c
@@ -10,7 +10,7 @@
* 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,
+ * 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) 2005 by the Blender Foundation.
@@ -59,7 +59,7 @@ static void copyData(const ModifierData *md, ModifierData *target, const int fla
const HookModifierData *hmd = (const HookModifierData *)md;
HookModifierData *thmd = (HookModifierData *)target;
- modifier_copyData_generic(md, target, flag);
+ BKE_modifier_copydata_generic(md, target, flag);
thmd->curfalloff = BKE_curvemapping_copy(hmd->curfalloff);
@@ -393,7 +393,7 @@ ModifierTypeInfo modifierType_Hook = {
/* structName */ "HookModifierData",
/* structSize */ sizeof(HookModifierData),
/* type */ eModifierTypeType_OnlyDeform,
- /* flags */ eModifierTypeFlag_AcceptsCVs | eModifierTypeFlag_AcceptsLattice |
+ /* flags */ eModifierTypeFlag_AcceptsCVs | eModifierTypeFlag_AcceptsVertexCosOnly |
eModifierTypeFlag_SupportsEditmode,
/* copyData */ copyData,
@@ -401,7 +401,10 @@ ModifierTypeInfo modifierType_Hook = {
/* deformMatrices */ NULL,
/* deformVertsEM */ deformVertsEM,
/* deformMatricesEM */ NULL,
- /* applyModifier */ NULL,
+ /* modifyMesh */ NULL,
+ /* modifyHair */ NULL,
+ /* modifyPointCloud */ NULL,
+ /* modifyVolume */ NULL,
/* initData */ initData,
/* requiredDataMask */ requiredDataMask,
diff --git a/source/blender/modifiers/intern/MOD_laplaciandeform.c b/source/blender/modifiers/intern/MOD_laplaciandeform.c
index 683696b0725..0ca8bc55fb8 100644
--- a/source/blender/modifiers/intern/MOD_laplaciandeform.c
+++ b/source/blender/modifiers/intern/MOD_laplaciandeform.c
@@ -10,7 +10,7 @@
* 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,
+ * 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 by the Blender Foundation.
@@ -35,6 +35,7 @@
#include "BKE_deform.h"
#include "BKE_editmesh.h"
#include "BKE_lib_id.h"
+#include "BKE_mesh.h"
#include "BKE_mesh_mapping.h"
#include "BKE_mesh_runtime.h"
#include "BKE_particle.h"
@@ -667,17 +668,17 @@ static void LaplacianDeformModifier_do(
}
else {
if (sysdif == LAPDEFORM_SYSTEM_CHANGE_VERTEXES) {
- modifier_setError(
+ BKE_modifier_set_error(
&lmd->modifier, "Vertices changed from %d to %d", lmd->total_verts, numVerts);
}
else if (sysdif == LAPDEFORM_SYSTEM_CHANGE_EDGES) {
- modifier_setError(
+ BKE_modifier_set_error(
&lmd->modifier, "Edges changed from %d to %d", sys->total_edges, mesh->totedge);
}
else if (sysdif == LAPDEFORM_SYSTEM_CHANGE_NOT_VALID_GROUP) {
- modifier_setError(&lmd->modifier,
- "Vertex group '%s' is not valid, or maybe empty",
- sys->anchor_grp_name);
+ BKE_modifier_set_error(&lmd->modifier,
+ "Vertex group '%s' is not valid, or maybe empty",
+ sys->anchor_grp_name);
}
}
}
@@ -688,7 +689,7 @@ static void LaplacianDeformModifier_do(
}
else {
if (!isValidVertexGroup(lmd, ob, mesh)) {
- modifier_setError(
+ BKE_modifier_set_error(
&lmd->modifier, "Vertex group '%s' is not valid, or maybe empty", lmd->anchor_grp_name);
lmd->flag &= ~MOD_LAPLACIANDEFORM_BIND;
}
@@ -709,7 +710,7 @@ static void LaplacianDeformModifier_do(
}
}
if (sys && sys->is_matrix_computed && !sys->has_solution) {
- modifier_setError(&lmd->modifier, "The system did not find a solution");
+ BKE_modifier_set_error(&lmd->modifier, "The system did not find a solution");
}
}
@@ -729,7 +730,7 @@ static void copyData(const ModifierData *md, ModifierData *target, const int fla
const LaplacianDeformModifierData *lmd = (const LaplacianDeformModifierData *)md;
LaplacianDeformModifierData *tlmd = (LaplacianDeformModifierData *)target;
- modifier_copyData_generic(md, target, flag);
+ BKE_modifier_copydata_generic(md, target, flag);
tlmd->vertexco = MEM_dupallocN(lmd->vertexco);
tlmd->cache_system = NULL;
@@ -783,6 +784,11 @@ static void deformVertsEM(ModifierData *md,
Mesh *mesh_src = MOD_deform_mesh_eval_get(
ctx->object, editData, mesh, NULL, numVerts, false, false);
+ /* TODO(Campbell): use edit-mode data only (remove this line). */
+ if (mesh_src != NULL) {
+ BKE_mesh_wrapper_ensure_mdata(mesh_src);
+ }
+
LaplacianDeformModifier_do(
(LaplacianDeformModifierData *)md, ctx->object, mesh_src, vertexCos, numVerts);
@@ -814,7 +820,10 @@ ModifierTypeInfo modifierType_LaplacianDeform = {
/* deformMatrices */ NULL,
/* deformVertsEM */ deformVertsEM,
/* deformMatricesEM */ NULL,
- /* applyModifier */ NULL,
+ /* modifyMesh */ NULL,
+ /* modifyHair */ NULL,
+ /* modifyPointCloud */ NULL,
+ /* modifyVolume */ NULL,
/* initData */ initData,
/* requiredDataMask */ requiredDataMask,
diff --git a/source/blender/modifiers/intern/MOD_laplaciansmooth.c b/source/blender/modifiers/intern/MOD_laplaciansmooth.c
index 97e94c46340..643afc5b5fc 100644
--- a/source/blender/modifiers/intern/MOD_laplaciansmooth.c
+++ b/source/blender/modifiers/intern/MOD_laplaciansmooth.c
@@ -10,7 +10,7 @@
* 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,
+ * 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) 2005 by the Blender Foundation.
@@ -559,6 +559,11 @@ static void deformVertsEM(ModifierData *md,
mesh_src = MOD_deform_mesh_eval_get(ctx->object, editData, mesh, NULL, numVerts, false, false);
+ /* TODO(Campbell): use edit-mode data only (remove this line). */
+ if (mesh_src != NULL) {
+ BKE_mesh_wrapper_ensure_mdata(mesh_src);
+ }
+
laplaciansmoothModifier_do(
(LaplacianSmoothModifierData *)md, ctx->object, mesh_src, vertexCos, numVerts);
@@ -574,13 +579,16 @@ ModifierTypeInfo modifierType_LaplacianSmooth = {
/* type */ eModifierTypeType_OnlyDeform,
/* flags */ eModifierTypeFlag_AcceptsMesh | eModifierTypeFlag_SupportsEditmode,
- /* copyData */ modifier_copyData_generic,
+ /* copyData */ BKE_modifier_copydata_generic,
/* deformVerts */ deformVerts,
/* deformMatrices */ NULL,
/* deformVertsEM */ deformVertsEM,
/* deformMatricesEM */ NULL,
- /* applyModifier */ NULL,
+ /* modifyMesh */ NULL,
+ /* modifyHair */ NULL,
+ /* modifyPointCloud */ NULL,
+ /* modifyVolume */ NULL,
/* initData */ init_data,
/* requiredDataMask */ required_data_mask,
diff --git a/source/blender/modifiers/intern/MOD_lattice.c b/source/blender/modifiers/intern/MOD_lattice.c
index 2b39f40a2b9..0a7aa006fcc 100644
--- a/source/blender/modifiers/intern/MOD_lattice.c
+++ b/source/blender/modifiers/intern/MOD_lattice.c
@@ -10,7 +10,7 @@
* 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,
+ * 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) 2005 by the Blender Foundation.
@@ -125,6 +125,11 @@ static void deformVertsEM(ModifierData *md,
struct Mesh *mesh_src = MOD_deform_mesh_eval_get(
ctx->object, em, mesh, NULL, numVerts, false, false);
+ /* TODO(Campbell): use edit-mode data only (remove this line). */
+ if (mesh_src != NULL) {
+ BKE_mesh_wrapper_ensure_mdata(mesh_src);
+ }
+
deformVerts(md, ctx, mesh_src, vertexCos, numVerts);
if (!ELEM(mesh_src, NULL, mesh)) {
@@ -137,16 +142,19 @@ ModifierTypeInfo modifierType_Lattice = {
/* structName */ "LatticeModifierData",
/* structSize */ sizeof(LatticeModifierData),
/* type */ eModifierTypeType_OnlyDeform,
- /* flags */ eModifierTypeFlag_AcceptsCVs | eModifierTypeFlag_AcceptsLattice |
+ /* flags */ eModifierTypeFlag_AcceptsCVs | eModifierTypeFlag_AcceptsVertexCosOnly |
eModifierTypeFlag_SupportsEditmode,
- /* copyData */ modifier_copyData_generic,
+ /* copyData */ BKE_modifier_copydata_generic,
/* deformVerts */ deformVerts,
/* deformMatrices */ NULL,
/* deformVertsEM */ deformVertsEM,
/* deformMatricesEM */ NULL,
- /* applyModifier */ NULL,
+ /* modifyMesh */ NULL,
+ /* modifyHair */ NULL,
+ /* modifyPointCloud */ NULL,
+ /* modifyVolume */ NULL,
/* initData */ initData,
/* requiredDataMask */ requiredDataMask,
diff --git a/source/blender/modifiers/intern/MOD_mask.cc b/source/blender/modifiers/intern/MOD_mask.cc
index 3bdb5a3fd54..18b88864926 100644
--- a/source/blender/modifiers/intern/MOD_mask.cc
+++ b/source/blender/modifiers/intern/MOD_mask.cc
@@ -10,7 +10,7 @@
* 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,
+ * 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) 2005 by the Blender Foundation.
@@ -46,14 +46,14 @@
#include "MOD_modifiertypes.h"
-#include "BLI_array_cxx.h"
-#include "BLI_listbase_wrapper.h"
-#include "BLI_vector.h"
+#include "BLI_array.hh"
+#include "BLI_listbase_wrapper.hh"
+#include "BLI_vector.hh"
using BLI::Array;
using BLI::ArrayRef;
using BLI::IndexRange;
-using BLI::IntrusiveListBaseWrapper;
+using BLI::ListBaseWrapper;
using BLI::MutableArrayRef;
using BLI::Vector;
@@ -93,7 +93,7 @@ static void compute_vertex_mask__armature_mode(MDeformVert *dvert,
/* Element i is true if there is a selected bone that uses vertex group i. */
Vector<bool> selected_bone_uses_group;
- for (bDeformGroup *def : IntrusiveListBaseWrapper<bDeformGroup>(ob->defbase)) {
+ for (bDeformGroup *def : ListBaseWrapper<bDeformGroup>(ob->defbase)) {
bPoseChannel *pchan = BKE_pose_channel_find_name(armature_ob->pose, def->name);
bool bone_for_group_exists = pchan && pchan->bone && (pchan->bone->flag & BONE_SELECTED);
selected_bone_uses_group.append(bone_for_group_exists);
@@ -293,7 +293,7 @@ static void copy_masked_polys_to_new_mesh(const Mesh &src_mesh,
* 2. Find edges and polygons only using those vertices.
* 3. Create a new mesh that only uses the found vertices, edges and polygons.
*/
-static Mesh *applyModifier(ModifierData *md, const ModifierEvalContext *ctx, Mesh *mesh)
+static Mesh *modifyMesh(ModifierData *md, const ModifierEvalContext *ctx, Mesh *mesh)
{
MaskModifierData *mmd = (MaskModifierData *)md;
Object *ob = ctx->object;
@@ -366,6 +366,7 @@ static Mesh *applyModifier(ModifierData *md, const ModifierEvalContext *ctx, Mes
copy_masked_polys_to_new_mesh(
*mesh, *result, vertex_map, edge_map, masked_poly_indices, new_loop_starts);
+ BKE_mesh_calc_edges_loose(result);
/* Tag to recalculate normals later. */
result->runtime.cd_dirty_vert |= CD_MASK_NORMAL;
@@ -395,13 +396,16 @@ ModifierTypeInfo modifierType_Mask = {
(ModifierTypeFlag)(eModifierTypeFlag_AcceptsMesh | eModifierTypeFlag_SupportsMapping |
eModifierTypeFlag_SupportsEditmode),
- /* copyData */ modifier_copyData_generic,
+ /* copyData */ BKE_modifier_copydata_generic,
/* deformVerts */ NULL,
/* deformMatrices */ NULL,
/* deformVertsEM */ NULL,
/* deformMatricesEM */ NULL,
- /* applyModifier */ applyModifier,
+ /* modifyMesh */ modifyMesh,
+ /* modifyHair */ NULL,
+ /* modifyPointCloud */ NULL,
+ /* modifyVolume */ NULL,
/* initData */ NULL,
/* requiredDataMask */ requiredDataMask,
diff --git a/source/blender/modifiers/intern/MOD_meshcache.c b/source/blender/modifiers/intern/MOD_meshcache.c
index c2cbddf806c..219de1569b3 100644
--- a/source/blender/modifiers/intern/MOD_meshcache.c
+++ b/source/blender/modifiers/intern/MOD_meshcache.c
@@ -167,13 +167,13 @@ static void meshcache_do(MeshCacheModifierData *mcmd,
/* we could support any object type */
if (UNLIKELY(ob->type != OB_MESH)) {
- modifier_setError(&mcmd->modifier, "'Integrate' only valid for Mesh objects");
+ BKE_modifier_set_error(&mcmd->modifier, "'Integrate' only valid for Mesh objects");
}
else if (UNLIKELY(me->totvert != numVerts)) {
- modifier_setError(&mcmd->modifier, "'Integrate' original mesh vertex mismatch");
+ BKE_modifier_set_error(&mcmd->modifier, "'Integrate' original mesh vertex mismatch");
}
else if (UNLIKELY(me->totpoly == 0)) {
- modifier_setError(&mcmd->modifier, "'Integrate' requires faces");
+ BKE_modifier_set_error(&mcmd->modifier, "'Integrate' requires faces");
}
else {
/* the moons align! */
@@ -212,7 +212,7 @@ static void meshcache_do(MeshCacheModifierData *mcmd,
/* -------------------------------------------------------------------- */
/* Apply the transformation matrix (if needed) */
if (UNLIKELY(err_str)) {
- modifier_setError(&mcmd->modifier, "%s", err_str);
+ BKE_modifier_set_error(&mcmd->modifier, "%s", err_str);
}
else if (ok) {
bool use_matrix = false;
@@ -292,16 +292,19 @@ ModifierTypeInfo modifierType_MeshCache = {
/* structName */ "MeshCacheModifierData",
/* structSize */ sizeof(MeshCacheModifierData),
/* type */ eModifierTypeType_OnlyDeform,
- /* flags */ eModifierTypeFlag_AcceptsCVs | eModifierTypeFlag_AcceptsLattice |
+ /* flags */ eModifierTypeFlag_AcceptsCVs | eModifierTypeFlag_AcceptsVertexCosOnly |
eModifierTypeFlag_SupportsEditmode,
- /* copyData */ modifier_copyData_generic,
+ /* copyData */ BKE_modifier_copydata_generic,
/* deformVerts */ deformVerts,
/* deformMatrices */ NULL,
/* deformVertsEM */ deformVertsEM,
/* deformMatricesEM */ NULL,
- /* applyModifier */ NULL,
+ /* modifyMesh */ NULL,
+ /* modifyHair */ NULL,
+ /* modifyPointCloud */ NULL,
+ /* modifyVolume */ NULL,
/* initData */ initData,
/* requiredDataMask */ NULL,
diff --git a/source/blender/modifiers/intern/MOD_meshdeform.c b/source/blender/modifiers/intern/MOD_meshdeform.c
index 7125d0df3a1..57b5f3891b2 100644
--- a/source/blender/modifiers/intern/MOD_meshdeform.c
+++ b/source/blender/modifiers/intern/MOD_meshdeform.c
@@ -10,7 +10,7 @@
* 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,
+ * 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) 2005 by the Blender Foundation.
@@ -93,7 +93,7 @@ static void copyData(const ModifierData *md, ModifierData *target, const int fla
const MeshDeformModifierData *mmd = (const MeshDeformModifierData *)md;
MeshDeformModifierData *tmmd = (MeshDeformModifierData *)target;
- modifier_copyData_generic(md, target, flag);
+ BKE_modifier_copydata_generic(md, target, flag);
if (mmd->bindinfluences) {
tmmd->bindinfluences = MEM_dupallocN(mmd->bindinfluences);
@@ -161,6 +161,8 @@ static void updateDepsgraph(ModifierData *md, const ModifierUpdateDepsgraphConte
DEG_add_object_relation(ctx->node, mmd->object, DEG_OB_COMP_TRANSFORM, "Mesh Deform Modifier");
DEG_add_object_relation(ctx->node, mmd->object, DEG_OB_COMP_GEOMETRY, "Mesh Deform Modifier");
}
+ /* We need own transformation as well. */
+ DEG_add_modifier_to_transform_relation(ctx->node, "Mesh Deform Modifier");
}
static float meshdeform_dynamic_bind(MeshDeformModifierData *mmd, float (*dco)[3], float vec[3])
@@ -361,7 +363,7 @@ static void meshdeformModifier_do(ModifierData *md,
Object *ob_target = mmd->object;
cagemesh = BKE_modifier_get_evaluated_mesh_from_evaluated_object(ob_target, false);
if (cagemesh == NULL) {
- modifier_setError(md, "Cannot get mesh from cage object");
+ BKE_modifier_set_error(md, "Cannot get mesh from cage object");
return;
}
@@ -376,7 +378,7 @@ static void meshdeformModifier_do(ModifierData *md,
if (!mmd->bindcagecos) {
/* progress bar redraw can make this recursive .. */
if (!DEG_is_active(ctx->depsgraph)) {
- modifier_setError(md, "Attempt to bind from inactive dependency graph");
+ BKE_modifier_set_error(md, "Attempt to bind from inactive dependency graph");
goto finally;
}
if (!recursive_bind_sentinel) {
@@ -393,15 +395,15 @@ static void meshdeformModifier_do(ModifierData *md,
totcagevert = cagemesh->totvert;
if (mmd->totvert != totvert) {
- modifier_setError(md, "Verts changed from %d to %d", mmd->totvert, totvert);
+ BKE_modifier_set_error(md, "Verts changed from %d to %d", mmd->totvert, totvert);
goto finally;
}
else if (mmd->totcagevert != totcagevert) {
- modifier_setError(md, "Cage verts changed from %d to %d", mmd->totcagevert, totcagevert);
+ BKE_modifier_set_error(md, "Cage verts changed from %d to %d", mmd->totcagevert, totcagevert);
goto finally;
}
else if (mmd->bindcagecos == NULL) {
- modifier_setError(md, "Bind data missing");
+ BKE_modifier_set_error(md, "Bind data missing");
goto finally;
}
@@ -477,6 +479,11 @@ static void deformVertsEM(ModifierData *md,
Mesh *mesh_src = MOD_deform_mesh_eval_get(
ctx->object, editData, mesh, NULL, numVerts, false, false);
+ /* TODO(Campbell): use edit-mode data only (remove this line). */
+ if (mesh_src != NULL) {
+ BKE_mesh_wrapper_ensure_mdata(mesh_src);
+ }
+
meshdeformModifier_do(md, ctx, mesh_src, vertexCos, numVerts);
if (!ELEM(mesh_src, NULL, mesh)) {
@@ -486,7 +493,7 @@ static void deformVertsEM(ModifierData *md,
#define MESHDEFORM_MIN_INFLUENCE 0.00001f
-void modifier_mdef_compact_influences(ModifierData *md)
+void BKE_modifier_mdef_compact_influences(ModifierData *md)
{
MeshDeformModifierData *mmd = (MeshDeformModifierData *)md;
float weight, *weights, totweight;
@@ -556,7 +563,7 @@ ModifierTypeInfo modifierType_MeshDeform = {
/* structName */ "MeshDeformModifierData",
/* structSize */ sizeof(MeshDeformModifierData),
/* type */ eModifierTypeType_OnlyDeform,
- /* flags */ eModifierTypeFlag_AcceptsCVs | eModifierTypeFlag_AcceptsLattice |
+ /* flags */ eModifierTypeFlag_AcceptsCVs | eModifierTypeFlag_AcceptsVertexCosOnly |
eModifierTypeFlag_SupportsEditmode,
/* copyData */ copyData,
@@ -565,7 +572,10 @@ ModifierTypeInfo modifierType_MeshDeform = {
/* deformMatrices */ NULL,
/* deformVertsEM */ deformVertsEM,
/* deformMatricesEM */ NULL,
- /* applyModifier */ NULL,
+ /* modifyMesh */ NULL,
+ /* modifyHair */ NULL,
+ /* modifyPointCloud */ NULL,
+ /* modifyVolume */ NULL,
/* initData */ initData,
/* requiredDataMask */ requiredDataMask,
diff --git a/source/blender/modifiers/intern/MOD_meshsequencecache.c b/source/blender/modifiers/intern/MOD_meshsequencecache.c
index 7357f18eb6a..51275c4e58f 100644
--- a/source/blender/modifiers/intern/MOD_meshsequencecache.c
+++ b/source/blender/modifiers/intern/MOD_meshsequencecache.c
@@ -64,7 +64,7 @@ static void copyData(const ModifierData *md, ModifierData *target, const int fla
#endif
MeshSeqCacheModifierData *tmcmd = (MeshSeqCacheModifierData *)target;
- modifier_copyData_generic(md, target, flag);
+ BKE_modifier_copydata_generic(md, target, flag);
tmcmd->reader = NULL;
tmcmd->reader_object_path[0] = '\0';
@@ -90,7 +90,7 @@ static bool isDisabled(const struct Scene *UNUSED(scene),
return (mcmd->cache_file == NULL) || (mcmd->object_path[0] == '\0');
}
-static Mesh *applyModifier(ModifierData *md, const ModifierEvalContext *ctx, Mesh *mesh)
+static Mesh *modifyMesh(ModifierData *md, const ModifierEvalContext *ctx, Mesh *mesh)
{
#ifdef WITH_ALEMBIC
MeshSeqCacheModifierData *mcmd = (MeshSeqCacheModifierData *)md;
@@ -109,7 +109,8 @@ static Mesh *applyModifier(ModifierData *md, const ModifierEvalContext *ctx, Mes
STRNCPY(mcmd->reader_object_path, mcmd->object_path);
BKE_cachefile_reader_open(cache_file, &mcmd->reader, ctx->object, mcmd->object_path);
if (!mcmd->reader) {
- modifier_setError(md, "Could not create Alembic reader for file %s", cache_file->filepath);
+ BKE_modifier_set_error(
+ md, "Could not create Alembic reader for file %s", cache_file->filepath);
return mesh;
}
}
@@ -141,7 +142,7 @@ static Mesh *applyModifier(ModifierData *md, const ModifierEvalContext *ctx, Mes
Mesh *result = ABC_read_mesh(mcmd->reader, ctx->object, mesh, time, &err_str, mcmd->read_flag);
if (err_str) {
- modifier_setError(md, "%s", err_str);
+ BKE_modifier_set_error(md, "%s", err_str);
}
if (!ELEM(result, NULL, mesh) && (mesh != org_mesh)) {
@@ -197,7 +198,10 @@ ModifierTypeInfo modifierType_MeshSequenceCache = {
/* deformMatrices */ NULL,
/* deformVertsEM */ NULL,
/* deformMatricesEM */ NULL,
- /* applyModifier */ applyModifier,
+ /* modifyMesh */ modifyMesh,
+ /* modifyHair */ NULL,
+ /* modifyPointCloud */ NULL,
+ /* modifyVolume */ NULL,
/* initData */ initData,
/* requiredDataMask */ NULL,
diff --git a/source/blender/modifiers/intern/MOD_mirror.c b/source/blender/modifiers/intern/MOD_mirror.c
index 3b3dfa2bda2..bbbcac262ca 100644
--- a/source/blender/modifiers/intern/MOD_mirror.c
+++ b/source/blender/modifiers/intern/MOD_mirror.c
@@ -10,7 +10,7 @@
* 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,
+ * 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) 2005 by the Blender Foundation.
@@ -100,7 +100,7 @@ static Mesh *mirrorModifier__doMirror(MirrorModifierData *mmd,
return result;
}
-static Mesh *applyModifier(ModifierData *md, const ModifierEvalContext *ctx, Mesh *mesh)
+static Mesh *modifyMesh(ModifierData *md, const ModifierEvalContext *ctx, Mesh *mesh)
{
Mesh *result;
MirrorModifierData *mmd = (MirrorModifierData *)md;
@@ -124,13 +124,16 @@ ModifierTypeInfo modifierType_Mirror = {
/* this is only the case when 'MOD_MIR_VGROUP' is used */
eModifierTypeFlag_UsesPreview,
- /* copyData */ modifier_copyData_generic,
+ /* copyData */ BKE_modifier_copydata_generic,
/* deformVerts */ NULL,
/* deformMatrices */ NULL,
/* deformVertsEM */ NULL,
/* deformMatricesEM */ NULL,
- /* applyModifier */ applyModifier,
+ /* modifyMesh */ modifyMesh,
+ /* modifyHair */ NULL,
+ /* modifyPointCloud */ NULL,
+ /* modifyVolume */ NULL,
/* initData */ initData,
/* requiredDataMask */ NULL,
diff --git a/source/blender/modifiers/intern/MOD_multires.c b/source/blender/modifiers/intern/MOD_multires.c
index ad8e0a9f259..5174a996480 100644
--- a/source/blender/modifiers/intern/MOD_multires.c
+++ b/source/blender/modifiers/intern/MOD_multires.c
@@ -10,7 +10,7 @@
* 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,
+ * 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) 2005 by the Blender Foundation.
@@ -66,7 +66,7 @@ static void initData(ModifierData *md)
static void copyData(const ModifierData *md_src, ModifierData *md_dst, const int flag)
{
- modifier_copyData_generic(md_src, md_dst, flag);
+ BKE_modifier_copydata_generic(md_src, md_dst, flag);
}
static void freeRuntimeData(void *runtime_data_v)
@@ -172,11 +172,11 @@ static Mesh *multires_as_ccg(MultiresModifierData *mmd,
return result;
}
-static Mesh *applyModifier(ModifierData *md, const ModifierEvalContext *ctx, Mesh *mesh)
+static Mesh *modifyMesh(ModifierData *md, const ModifierEvalContext *ctx, Mesh *mesh)
{
Mesh *result = mesh;
#if !defined(WITH_OPENSUBDIV)
- modifier_setError(md, "Disabled, built without OpenSubdiv");
+ BKE_modifier_set_error(md, "Disabled, built without OpenSubdiv");
return result;
#endif
MultiresModifierData *mmd = (MultiresModifierData *)md;
@@ -211,7 +211,9 @@ static Mesh *applyModifier(ModifierData *md, const ModifierEvalContext *ctx, Mes
if (ctx->object->sculpt != NULL) {
SculptSession *sculpt_session = ctx->object->sculpt;
sculpt_session->subdiv_ccg = result->runtime.subdiv_ccg;
- sculpt_session->multires = mmd;
+ sculpt_session->multires.active = true;
+ sculpt_session->multires.modifier = mmd;
+ sculpt_session->multires.level = mmd->sculptlvl;
sculpt_session->totvert = mesh->totvert;
sculpt_session->totpoly = mesh->totpoly;
sculpt_session->mvert = NULL;
@@ -243,7 +245,7 @@ static void deformMatrices(ModifierData *md,
{
#if !defined(WITH_OPENSUBDIV)
- modifier_setError(md, "Disabled, built without OpenSubdiv");
+ BKE_modifier_set_error(md, "Disabled, built without OpenSubdiv");
return;
#endif
@@ -284,7 +286,10 @@ ModifierTypeInfo modifierType_Multires = {
/* deformMatrices */ deformMatrices,
/* deformVertsEM */ NULL,
/* deformMatricesEM */ NULL,
- /* applyModifier */ applyModifier,
+ /* modifyMesh */ modifyMesh,
+ /* modifyHair */ NULL,
+ /* modifyPointCloud */ NULL,
+ /* modifyVolume */ NULL,
/* initData */ initData,
/* requiredDataMask */ NULL,
diff --git a/source/blender/modifiers/intern/MOD_none.c b/source/blender/modifiers/intern/MOD_none.c
index 9be422afab9..84c9fc1d726 100644
--- a/source/blender/modifiers/intern/MOD_none.c
+++ b/source/blender/modifiers/intern/MOD_none.c
@@ -51,7 +51,10 @@ ModifierTypeInfo modifierType_None = {
/* deformMatrices */ NULL,
/* deformVertsEM */ NULL,
/* deformMatricesEM */ NULL,
- /* applyModifier */ NULL,
+ /* modifyMesh */ NULL,
+ /* modifyHair */ NULL,
+ /* modifyPointCloud */ NULL,
+ /* modifyVolume */ NULL,
/* initData */ NULL,
/* requiredDataMask */ NULL,
diff --git a/source/blender/modifiers/intern/MOD_normal_edit.c b/source/blender/modifiers/intern/MOD_normal_edit.c
index 0b101b26906..1521cfab356 100644
--- a/source/blender/modifiers/intern/MOD_normal_edit.c
+++ b/source/blender/modifiers/intern/MOD_normal_edit.c
@@ -10,7 +10,7 @@
* 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,
+ * along with this program; if not, write to the Free Software Foundation,
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
@@ -464,7 +464,7 @@ static bool is_valid_target(NormalEditModifierData *enmd)
else if ((enmd->mode == MOD_NORMALEDIT_MODE_DIRECTIONAL) && enmd->target) {
return true;
}
- modifier_setError((ModifierData *)enmd, "Invalid target settings");
+ BKE_modifier_set_error((ModifierData *)enmd, "Invalid target settings");
return false;
}
@@ -494,7 +494,7 @@ static Mesh *normalEditModifier_do(NormalEditModifierData *enmd,
if (!(((Mesh *)ob->data)->flag & ME_AUTOSMOOTH))
#endif
{
- modifier_setError((ModifierData *)enmd, "Enable 'Auto Smooth' in Object Data Properties");
+ BKE_modifier_set_error((ModifierData *)enmd, "Enable 'Auto Smooth' in Object Data Properties");
return mesh;
}
@@ -684,7 +684,7 @@ static void updateDepsgraph(ModifierData *md, const ModifierUpdateDepsgraphConte
}
}
-static Mesh *applyModifier(ModifierData *md, const ModifierEvalContext *ctx, Mesh *mesh)
+static Mesh *modifyMesh(ModifierData *md, const ModifierEvalContext *ctx, Mesh *mesh)
{
return normalEditModifier_do((NormalEditModifierData *)md, ctx, ctx->object, mesh);
}
@@ -697,13 +697,16 @@ ModifierTypeInfo modifierType_NormalEdit = {
/* flags */ eModifierTypeFlag_AcceptsMesh | eModifierTypeFlag_SupportsMapping |
eModifierTypeFlag_SupportsEditmode | eModifierTypeFlag_EnableInEditmode,
- /* copyData */ modifier_copyData_generic,
+ /* copyData */ BKE_modifier_copydata_generic,
/* deformVerts */ NULL,
/* deformMatrices */ NULL,
/* deformVertsEM */ NULL,
/* deformMatricesEM */ NULL,
- /* applyModifier */ applyModifier,
+ /* modifyMesh */ modifyMesh,
+ /* modifyHair */ NULL,
+ /* modifyPointCloud */ NULL,
+ /* modifyVolume */ NULL,
/* initData */ initData,
/* requiredDataMask */ requiredDataMask,
diff --git a/source/blender/modifiers/intern/MOD_ocean.c b/source/blender/modifiers/intern/MOD_ocean.c
index fddfc74f267..4c7c644952b 100644
--- a/source/blender/modifiers/intern/MOD_ocean.c
+++ b/source/blender/modifiers/intern/MOD_ocean.c
@@ -46,7 +46,7 @@
#ifdef WITH_OCEANSIM
static void init_cache_data(Object *ob, struct OceanModifierData *omd)
{
- const char *relbase = modifier_path_relbase_from_global(ob);
+ const char *relbase = BKE_modifier_path_relbase_from_global(ob);
omd->oceancache = BKE_ocean_init_cache(omd->cachepath,
relbase,
@@ -100,7 +100,7 @@ static void initData(ModifierData *md)
omd->repeat_x = 1;
omd->repeat_y = 1;
- modifier_path_init(omd->cachepath, sizeof(omd->cachepath), "cache_ocean");
+ BKE_modifier_path_init(omd->cachepath, sizeof(omd->cachepath), "cache_ocean");
omd->cached = 0;
omd->bakestart = 1;
@@ -141,7 +141,7 @@ static void copyData(const ModifierData *md, ModifierData *target, const int fla
# endif
OceanModifierData *tomd = (OceanModifierData *)target;
- modifier_copyData_generic(md, target, flag);
+ BKE_modifier_copydata_generic(md, target, flag);
/* The oceancache object will be recreated for this copy
* automatically when cached=true */
@@ -482,7 +482,7 @@ static Mesh *doOcean(ModifierData *UNUSED(md), const ModifierEvalContext *UNUSED
}
#endif /* WITH_OCEANSIM */
-static Mesh *applyModifier(ModifierData *md, const ModifierEvalContext *ctx, Mesh *mesh)
+static Mesh *modifyMesh(ModifierData *md, const ModifierEvalContext *ctx, Mesh *mesh)
{
Mesh *result;
@@ -509,7 +509,10 @@ ModifierTypeInfo modifierType_Ocean = {
/* deformMatrices */ NULL,
/* deformVertsEM */ NULL,
/* deformMatricesEM */ NULL,
- /* applyModifier */ applyModifier,
+ /* modifyMesh */ modifyMesh,
+ /* modifyHair */ NULL,
+ /* modifyPointCloud */ NULL,
+ /* modifyVolume */ NULL,
/* initData */ initData,
/* requiredDataMask */ requiredDataMask,
diff --git a/source/blender/modifiers/intern/MOD_particleinstance.c b/source/blender/modifiers/intern/MOD_particleinstance.c
index 8a4468ec91e..644962ab71c 100644
--- a/source/blender/modifiers/intern/MOD_particleinstance.c
+++ b/source/blender/modifiers/intern/MOD_particleinstance.c
@@ -10,7 +10,7 @@
* 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,
+ * 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) 2005 by the Blender Foundation.
@@ -110,7 +110,7 @@ static bool isDisabled(const struct Scene *scene, ModifierData *md, bool useRend
required_mode = eModifierMode_Realtime;
}
- if (!modifier_isEnabled(scene, ob_md, required_mode)) {
+ if (!BKE_modifier_is_enabled(scene, ob_md, required_mode)) {
return true;
}
@@ -204,7 +204,7 @@ static void store_float_in_vcol(MLoopCol *vcol, float float_value)
vcol->a = 1.0f;
}
-static Mesh *applyModifier(ModifierData *md, const ModifierEvalContext *ctx, Mesh *mesh)
+static Mesh *modifyMesh(ModifierData *md, const ModifierEvalContext *ctx, Mesh *mesh)
{
Mesh *result;
ParticleInstanceModifierData *pimd = (ParticleInstanceModifierData *)md;
@@ -554,13 +554,16 @@ ModifierTypeInfo modifierType_ParticleInstance = {
/* flags */ eModifierTypeFlag_AcceptsMesh | eModifierTypeFlag_SupportsMapping |
eModifierTypeFlag_SupportsEditmode | eModifierTypeFlag_EnableInEditmode,
- /* copyData */ modifier_copyData_generic,
+ /* copyData */ BKE_modifier_copydata_generic,
/* deformVerts */ NULL,
/* deformMatrices */ NULL,
/* deformVertsEM */ NULL,
/* deformMatricesEM */ NULL,
- /* applyModifier */ applyModifier,
+ /* modifyMesh */ modifyMesh,
+ /* modifyHair */ NULL,
+ /* modifyPointCloud */ NULL,
+ /* modifyVolume */ NULL,
/* initData */ initData,
/* requiredDataMask */ requiredDataMask,
diff --git a/source/blender/modifiers/intern/MOD_particlesystem.c b/source/blender/modifiers/intern/MOD_particlesystem.c
index e6229e27e4b..e72a484e3a0 100644
--- a/source/blender/modifiers/intern/MOD_particlesystem.c
+++ b/source/blender/modifiers/intern/MOD_particlesystem.c
@@ -10,7 +10,7 @@
* 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,
+ * 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) 2005 by the Blender Foundation.
@@ -61,7 +61,7 @@ static void freeData(ModifierData *md)
psmd->totdmvert = psmd->totdmedge = psmd->totdmface = 0;
/* ED_object_modifier_remove may have freed this first before calling
- * modifier_free (which calls this function) */
+ * BKE_modifier_free (which calls this function) */
if (psmd->psys) {
psmd->psys->flag |= PSYS_DELETE;
}
@@ -74,7 +74,7 @@ static void copyData(const ModifierData *md, ModifierData *target, const int fla
#endif
ParticleSystemModifierData *tpsmd = (ParticleSystemModifierData *)target;
- modifier_copyData_generic(md, target, flag);
+ BKE_modifier_copydata_generic(md, target, flag);
tpsmd->mesh_final = NULL;
tpsmd->mesh_original = NULL;
@@ -189,7 +189,7 @@ static void deformVerts(ModifierData *md,
BKE_mesh_tessface_ensure(psmd->mesh_original);
}
- if (mesh_src != psmd->mesh_final && mesh_src != mesh) {
+ if (!ELEM(mesh_src, NULL, mesh, psmd->mesh_final)) {
BKE_id_free(NULL, mesh_src);
}
@@ -216,7 +216,7 @@ static void deformVerts(ModifierData *md,
if (DEG_is_active(ctx->depsgraph)) {
Object *object_orig = DEG_get_original_object(ctx->object);
- ModifierData *md_orig = modifiers_findByName(object_orig, psmd->modifier.name);
+ ModifierData *md_orig = BKE_modifiers_findby_name(object_orig, psmd->modifier.name);
BLI_assert(md_orig != NULL);
ParticleSystemModifierData *psmd_orig = (ParticleSystemModifierData *)md_orig;
psmd_orig->flag = psmd->flag;
@@ -264,7 +264,10 @@ ModifierTypeInfo modifierType_ParticleSystem = {
/* deformMatrices */ NULL,
/* deformVertsEM */ NULL,
/* deformMatricesEM */ NULL,
- /* applyModifier */ NULL,
+ /* modifyMesh */ NULL,
+ /* modifyHair */ NULL,
+ /* modifyPointCloud */ NULL,
+ /* modifyVolume */ NULL,
/* initData */ initData,
/* requiredDataMask */ requiredDataMask,
diff --git a/source/blender/modifiers/intern/MOD_remesh.c b/source/blender/modifiers/intern/MOD_remesh.c
index 3300cda947c..5a262adf47c 100644
--- a/source/blender/modifiers/intern/MOD_remesh.c
+++ b/source/blender/modifiers/intern/MOD_remesh.c
@@ -25,6 +25,7 @@
#include "BLI_utildefines.h"
#include "BLI_math_base.h"
+#include "BLI_threads.h"
#include "DNA_mesh_types.h"
#include "DNA_meshdata_types.h"
@@ -34,6 +35,7 @@
#include "MOD_modifiertypes.h"
#include "BKE_mesh.h"
+#include "BKE_mesh_remesh_voxel.h"
#include "BKE_mesh_runtime.h"
#include <assert.h>
@@ -54,8 +56,10 @@ static void initData(ModifierData *md)
rmd->depth = 4;
rmd->hermite_num = 1;
rmd->flag = MOD_REMESH_FLOOD_FILL;
- rmd->mode = MOD_REMESH_SHARP_FEATURES;
+ rmd->mode = MOD_REMESH_VOXEL;
rmd->threshold = 1;
+ rmd->voxel_size = 0.1f;
+ rmd->adaptivity = 0.0f;
}
#ifdef WITH_MOD_REMESH
@@ -133,7 +137,7 @@ static void dualcon_add_quad(void *output_v, const int vert_indices[4])
output->curface++;
}
-static Mesh *applyModifier(ModifierData *md, const ModifierEvalContext *UNUSED(ctx), Mesh *mesh)
+static Mesh *modifyMesh(ModifierData *md, const ModifierEvalContext *UNUSED(ctx), Mesh *mesh)
{
RemeshModifierData *rmd;
DualConOutput *output;
@@ -144,36 +148,56 @@ static Mesh *applyModifier(ModifierData *md, const ModifierEvalContext *UNUSED(c
rmd = (RemeshModifierData *)md;
- init_dualcon_mesh(&input, mesh);
-
- if (rmd->flag & MOD_REMESH_FLOOD_FILL) {
- flags |= DUALCON_FLOOD_FILL;
+ if (rmd->mode == MOD_REMESH_VOXEL) {
+ /* OpenVDB modes. */
+ if (rmd->voxel_size == 0.0f) {
+ return NULL;
+ }
+ result = BKE_mesh_remesh_voxel_to_mesh_nomain(mesh, rmd->voxel_size, rmd->adaptivity, 0.0f);
}
+ else {
+ /* Dualcon modes. */
+ init_dualcon_mesh(&input, mesh);
- switch (rmd->mode) {
- case MOD_REMESH_CENTROID:
- mode = DUALCON_CENTROID;
- break;
- case MOD_REMESH_MASS_POINT:
- mode = DUALCON_MASS_POINT;
- break;
- case MOD_REMESH_SHARP_FEATURES:
- mode = DUALCON_SHARP_FEATURES;
- break;
- }
+ if (rmd->flag & MOD_REMESH_FLOOD_FILL) {
+ flags |= DUALCON_FLOOD_FILL;
+ }
- output = dualcon(&input,
- dualcon_alloc_output,
- dualcon_add_vert,
- dualcon_add_quad,
- flags,
- mode,
- rmd->threshold,
- rmd->hermite_num,
- rmd->scale,
- rmd->depth);
- result = output->mesh;
- MEM_freeN(output);
+ switch (rmd->mode) {
+ case MOD_REMESH_CENTROID:
+ mode = DUALCON_CENTROID;
+ break;
+ case MOD_REMESH_MASS_POINT:
+ mode = DUALCON_MASS_POINT;
+ break;
+ case MOD_REMESH_SHARP_FEATURES:
+ mode = DUALCON_SHARP_FEATURES;
+ break;
+ case MOD_REMESH_VOXEL:
+ /* Should have been processed before as an OpenVDB operation. */
+ BLI_assert(false);
+ break;
+ }
+ /* TODO(jbakker): Dualcon crashes when run in parallel. Could be related to incorrect
+ * input data or that the library isn't thread safe. This was identified when changing the task
+ * isolations during T76553. */
+ static ThreadMutex dualcon_mutex = BLI_MUTEX_INITIALIZER;
+ BLI_mutex_lock(&dualcon_mutex);
+ output = dualcon(&input,
+ dualcon_alloc_output,
+ dualcon_add_vert,
+ dualcon_add_quad,
+ flags,
+ mode,
+ rmd->threshold,
+ rmd->hermite_num,
+ rmd->scale,
+ rmd->depth);
+ BLI_mutex_unlock(&dualcon_mutex);
+
+ result = output->mesh;
+ MEM_freeN(output);
+ }
if (rmd->flag & MOD_REMESH_SMOOTH_SHADING) {
MPoly *mpoly = result->mpoly;
@@ -193,9 +217,9 @@ static Mesh *applyModifier(ModifierData *md, const ModifierEvalContext *UNUSED(c
#else /* !WITH_MOD_REMESH */
-static Mesh *applyModifier(ModifierData *UNUSED(md),
- const ModifierEvalContext *UNUSED(ctx),
- Mesh *mesh)
+static Mesh *modifyMesh(ModifierData *UNUSED(md),
+ const ModifierEvalContext *UNUSED(ctx),
+ Mesh *mesh)
{
return mesh;
}
@@ -210,13 +234,16 @@ ModifierTypeInfo modifierType_Remesh = {
/* flags */ eModifierTypeFlag_AcceptsMesh | eModifierTypeFlag_AcceptsCVs |
eModifierTypeFlag_SupportsEditmode,
- /* copyData */ modifier_copyData_generic,
+ /* copyData */ BKE_modifier_copydata_generic,
/* deformVerts */ NULL,
/* deformMatrices */ NULL,
/* deformVertsEM */ NULL,
/* deformMatricesEM */ NULL,
- /* applyModifier */ applyModifier,
+ /* modifyMesh */ modifyMesh,
+ /* modifyHair */ NULL,
+ /* modifyPointCloud */ NULL,
+ /* modifyVolume */ NULL,
/* initData */ initData,
/* requiredDataMask */ NULL,
diff --git a/source/blender/modifiers/intern/MOD_screw.c b/source/blender/modifiers/intern/MOD_screw.c
index 8921ddb894f..d3d42068812 100644
--- a/source/blender/modifiers/intern/MOD_screw.c
+++ b/source/blender/modifiers/intern/MOD_screw.c
@@ -10,7 +10,7 @@
* 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,
+ * 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) 2005 by the Blender Foundation.
@@ -178,7 +178,7 @@ static void initData(ModifierData *md)
ltmd->merge_dist = 0.01f;
}
-static Mesh *applyModifier(ModifierData *md, const ModifierEvalContext *ctx, Mesh *meshData)
+static Mesh *modifyMesh(ModifierData *md, const ModifierEvalContext *ctx, Mesh *meshData)
{
Mesh *mesh = meshData;
Mesh *result;
@@ -352,12 +352,9 @@ static Mesh *applyModifier(ModifierData *md, const ModifierEvalContext *ctx, Mes
* Note! smaller then `FLT_EPSILON * 100`
* gives problems with float precision so its never closed. */
if (fabsf(screw_ofs) <= (FLT_EPSILON * 100.0f) &&
- fabsf(fabsf(angle) - ((float)M_PI * 2.0f)) <= (FLT_EPSILON * 100.0f)) {
+ fabsf(fabsf(angle) - ((float)M_PI * 2.0f)) <= (FLT_EPSILON * 100.0f) && step_tot > 3) {
close = 1;
step_tot--;
- if (step_tot < 3) {
- step_tot = 3;
- }
maxVerts = totvert * step_tot; /* -1 because we're joining back up */
maxEdges = (totvert * step_tot) + /* these are the edges between new verts */
@@ -368,8 +365,8 @@ static Mesh *applyModifier(ModifierData *md, const ModifierEvalContext *ctx, Mes
}
else {
close = 0;
- if (step_tot < 3) {
- step_tot = 3;
+ if (step_tot < 2) {
+ step_tot = 2;
}
maxVerts = totvert * step_tot; /* -1 because we're joining back up */
@@ -1168,13 +1165,16 @@ ModifierTypeInfo modifierType_Screw = {
/* flags */ eModifierTypeFlag_AcceptsMesh | eModifierTypeFlag_AcceptsCVs |
eModifierTypeFlag_SupportsEditmode | eModifierTypeFlag_EnableInEditmode,
- /* copyData */ modifier_copyData_generic,
+ /* copyData */ BKE_modifier_copydata_generic,
/* deformVerts */ NULL,
/* deformMatrices */ NULL,
/* deformVertsEM */ NULL,
/* deformMatricesEM */ NULL,
- /* applyModifier */ applyModifier,
+ /* modifyMesh */ modifyMesh,
+ /* modifyHair */ NULL,
+ /* modifyPointCloud */ NULL,
+ /* modifyVolume */ NULL,
/* initData */ initData,
/* requiredDataMask */ NULL,
diff --git a/source/blender/modifiers/intern/MOD_shapekey.c b/source/blender/modifiers/intern/MOD_shapekey.c
index 25f702bf696..abab0aff927 100644
--- a/source/blender/modifiers/intern/MOD_shapekey.c
+++ b/source/blender/modifiers/intern/MOD_shapekey.c
@@ -10,7 +10,7 @@
* 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,
+ * 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) 2005 by the Blender Foundation.
@@ -122,7 +122,7 @@ ModifierTypeInfo modifierType_ShapeKey = {
/* structName */ "ShapeKeyModifierData",
/* structSize */ sizeof(ShapeKeyModifierData),
/* type */ eModifierTypeType_OnlyDeform,
- /* flags */ eModifierTypeFlag_AcceptsCVs | eModifierTypeFlag_AcceptsLattice |
+ /* flags */ eModifierTypeFlag_AcceptsCVs | eModifierTypeFlag_AcceptsVertexCosOnly |
eModifierTypeFlag_SupportsEditmode,
/* copyData */ NULL,
@@ -131,7 +131,10 @@ ModifierTypeInfo modifierType_ShapeKey = {
/* deformMatrices */ deformMatrices,
/* deformVertsEM */ deformVertsEM,
/* deformMatricesEM */ deformMatricesEM,
- /* applyModifier */ NULL,
+ /* modifyMesh */ NULL,
+ /* modifyHair */ NULL,
+ /* modifyPointCloud */ NULL,
+ /* modifyVolume */ NULL,
/* initData */ NULL,
/* requiredDataMask */ NULL,
diff --git a/source/blender/modifiers/intern/MOD_shrinkwrap.c b/source/blender/modifiers/intern/MOD_shrinkwrap.c
index 842ec46f364..11dc0a92769 100644
--- a/source/blender/modifiers/intern/MOD_shrinkwrap.c
+++ b/source/blender/modifiers/intern/MOD_shrinkwrap.c
@@ -10,7 +10,7 @@
* 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,
+ * 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) 2005 by the Blender Foundation.
@@ -142,6 +142,11 @@ static void deformVertsEM(ModifierData *md,
mesh_src = MOD_deform_mesh_eval_get(ctx->object, editData, mesh, NULL, numVerts, false, false);
}
+ /* TODO(Campbell): use edit-mode data only (remove this line). */
+ if (mesh_src != NULL) {
+ BKE_mesh_wrapper_ensure_mdata(mesh_src);
+ }
+
struct MDeformVert *dvert = NULL;
int defgrp_index = -1;
if (swmd->vgroup_name[0] != '\0') {
@@ -204,16 +209,19 @@ ModifierTypeInfo modifierType_Shrinkwrap = {
/* structSize */ sizeof(ShrinkwrapModifierData),
/* type */ eModifierTypeType_OnlyDeform,
/* flags */ eModifierTypeFlag_AcceptsMesh | eModifierTypeFlag_AcceptsCVs |
- eModifierTypeFlag_AcceptsLattice | eModifierTypeFlag_SupportsEditmode |
+ eModifierTypeFlag_AcceptsVertexCosOnly | eModifierTypeFlag_SupportsEditmode |
eModifierTypeFlag_EnableInEditmode,
- /* copyData */ modifier_copyData_generic,
+ /* copyData */ BKE_modifier_copydata_generic,
/* deformVerts */ deformVerts,
/* deformMatrices */ NULL,
/* deformVertsEM */ deformVertsEM,
/* deformMatricesEM */ NULL,
- /* applyModifier */ NULL,
+ /* modifyMesh */ NULL,
+ /* modifyHair */ NULL,
+ /* modifyPointCloud */ NULL,
+ /* modifyVolume */ NULL,
/* initData */ initData,
/* requiredDataMask */ requiredDataMask,
diff --git a/source/blender/modifiers/intern/MOD_simpledeform.c b/source/blender/modifiers/intern/MOD_simpledeform.c
index 65ea6b95824..a81b42905e3 100644
--- a/source/blender/modifiers/intern/MOD_simpledeform.c
+++ b/source/blender/modifiers/intern/MOD_simpledeform.c
@@ -10,7 +10,7 @@
* 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,
+ * 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) 2005 by the Blender Foundation.
@@ -440,6 +440,11 @@ static void deformVertsEM(ModifierData *md,
mesh_src = MOD_deform_mesh_eval_get(ctx->object, editData, mesh, NULL, numVerts, false, false);
}
+ /* TODO(Campbell): use edit-mode data only (remove this line). */
+ if (mesh_src != NULL) {
+ BKE_mesh_wrapper_ensure_mdata(mesh_src);
+ }
+
SimpleDeformModifier_do(sdmd, ctx, ctx->object, mesh_src, vertexCos, numVerts);
if (!ELEM(mesh_src, NULL, mesh)) {
@@ -454,16 +459,19 @@ ModifierTypeInfo modifierType_SimpleDeform = {
/* type */ eModifierTypeType_OnlyDeform,
/* flags */ eModifierTypeFlag_AcceptsMesh | eModifierTypeFlag_AcceptsCVs |
- eModifierTypeFlag_AcceptsLattice | eModifierTypeFlag_SupportsEditmode |
+ eModifierTypeFlag_AcceptsVertexCosOnly | eModifierTypeFlag_SupportsEditmode |
eModifierTypeFlag_EnableInEditmode,
- /* copyData */ modifier_copyData_generic,
+ /* copyData */ BKE_modifier_copydata_generic,
/* deformVerts */ deformVerts,
/* deformMatrices */ NULL,
/* deformVertsEM */ deformVertsEM,
/* deformMatricesEM */ NULL,
- /* applyModifier */ NULL,
+ /* modifyMesh */ NULL,
+ /* modifyHair */ NULL,
+ /* modifyPointCloud */ NULL,
+ /* modifyVolume */ NULL,
/* initData */ initData,
/* requiredDataMask */ requiredDataMask,
diff --git a/source/blender/modifiers/intern/MOD_simulation.cc b/source/blender/modifiers/intern/MOD_simulation.cc
new file mode 100644
index 00000000000..f52daf53186
--- /dev/null
+++ b/source/blender/modifiers/intern/MOD_simulation.cc
@@ -0,0 +1,109 @@
+/*
+ * 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) 2005 by the Blender Foundation.
+ * All rights reserved.
+ */
+
+/** \file
+ * \ingroup modifiers
+ */
+
+#include <iostream>
+#include <string>
+
+#include "MEM_guardedalloc.h"
+
+#include "BLI_utildefines.h"
+
+#include "DNA_mesh_types.h"
+#include "DNA_meshdata_types.h"
+#include "DNA_modifier_types.h"
+#include "DNA_object_types.h"
+#include "DNA_pointcloud_types.h"
+#include "DNA_scene_types.h"
+#include "DNA_simulation_types.h"
+
+#include "BKE_customdata.h"
+#include "BKE_lib_query.h"
+#include "BKE_mesh.h"
+#include "BKE_modifier.h"
+
+#include "DEG_depsgraph_build.h"
+#include "DEG_depsgraph_query.h"
+
+#include "MOD_modifiertypes.h"
+
+static void updateDepsgraph(ModifierData *md, const ModifierUpdateDepsgraphContext *ctx)
+{
+ SimulationModifierData *smd = (SimulationModifierData *)md;
+ if (smd->simulation) {
+ DEG_add_simulation_relation(ctx->node, smd->simulation, "Accessed Simulation");
+ }
+}
+
+static void foreachIDLink(ModifierData *md, Object *ob, IDWalkFunc walk, void *userData)
+{
+ SimulationModifierData *smd = (SimulationModifierData *)md;
+ walk(userData, ob, (ID **)&smd->simulation, IDWALK_CB_USER);
+}
+
+static bool isDisabled(const struct Scene *UNUSED(scene),
+ ModifierData *md,
+ bool UNUSED(useRenderParams))
+{
+ SimulationModifierData *smd = (SimulationModifierData *)md;
+ return smd->simulation == nullptr;
+}
+
+static PointCloud *modifyPointCloud(ModifierData *md,
+ const ModifierEvalContext *UNUSED(ctx),
+ PointCloud *pointcloud)
+{
+ SimulationModifierData *smd = (SimulationModifierData *)md;
+ UNUSED_VARS(smd);
+ return pointcloud;
+}
+
+ModifierTypeInfo modifierType_Simulation = {
+ /* name */ "Simulation",
+ /* structName */ "SimulationModifierData",
+ /* structSize */ sizeof(SimulationModifierData),
+ /* type */ eModifierTypeType_None,
+ /* flags */ (ModifierTypeFlag)0,
+
+ /* copyData */ BKE_modifier_copydata_generic,
+
+ /* deformVerts */ NULL,
+ /* deformMatrices */ NULL,
+ /* deformVertsEM */ NULL,
+ /* deformMatricesEM */ NULL,
+ /* modifyMesh */ NULL,
+ /* modifyHair */ NULL,
+ /* modifyPointCloud */ modifyPointCloud,
+ /* modifyVolume */ NULL,
+
+ /* initData */ NULL,
+ /* requiredDataMask */ NULL,
+ /* freeData */ NULL,
+ /* isDisabled */ isDisabled,
+ /* updateDepsgraph */ updateDepsgraph,
+ /* dependsOnTime */ NULL,
+ /* dependsOnNormals */ NULL,
+ /* foreachObjectLink */ NULL,
+ /* foreachIDLink */ foreachIDLink,
+ /* foreachTexLink */ NULL,
+ /* freeRuntimeData */ NULL,
+};
diff --git a/source/blender/modifiers/intern/MOD_skin.c b/source/blender/modifiers/intern/MOD_skin.c
index ec7c2b5b1a4..34590736e37 100644
--- a/source/blender/modifiers/intern/MOD_skin.c
+++ b/source/blender/modifiers/intern/MOD_skin.c
@@ -10,7 +10,7 @@
* 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,
+ * along with this program; if not, write to the Free Software Foundation,
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
@@ -922,7 +922,13 @@ static Mesh *subdivide_base(Mesh *orig)
u = e->v1;
radrat = (half_v2(outnode[e->v2].radius) / half_v2(outnode[e->v1].radius));
- radrat = (radrat + 1) / 2;
+ if (isfinite(radrat)) {
+ radrat = (radrat + 1) / 2;
+ }
+ else {
+ /* Happens when skin is scaled to zero. */
+ radrat = 1.0f;
+ }
/* Add vertices and edge segments */
for (j = 0; j < edge_subd[i]; j++, v++, outedge++) {
@@ -1779,7 +1785,7 @@ static BMesh *build_skin(SkinNode *skin_nodes,
skin_update_merged_vertices(skin_nodes, totvert);
if (!skin_output_branch_hulls(&so, skin_nodes, totvert, emap, medge)) {
- modifier_setError(&smd->modifier, "Hull error");
+ BKE_modifier_set_error(&smd->modifier, "Hull error");
}
/* Merge triangles here in the hope of providing better target
@@ -1862,7 +1868,7 @@ static Mesh *base_skin(Mesh *origmesh, SkinModifierData *smd)
MEM_freeN(emapmem);
if (!has_valid_root) {
- modifier_setError(
+ BKE_modifier_set_error(
&smd->modifier,
"No valid root vertex found (you need one per mesh island you want to skin)");
}
@@ -1911,7 +1917,7 @@ static void initData(ModifierData *md)
smd->symmetry_axes = MOD_SKIN_SYMM_X;
}
-static Mesh *applyModifier(ModifierData *md, const ModifierEvalContext *UNUSED(ctx), Mesh *mesh)
+static Mesh *modifyMesh(ModifierData *md, const ModifierEvalContext *UNUSED(ctx), Mesh *mesh)
{
Mesh *result;
@@ -1935,13 +1941,16 @@ ModifierTypeInfo modifierType_Skin = {
/* type */ eModifierTypeType_Constructive,
/* flags */ eModifierTypeFlag_AcceptsMesh | eModifierTypeFlag_SupportsEditmode,
- /* copyData */ modifier_copyData_generic,
+ /* copyData */ BKE_modifier_copydata_generic,
/* deformVerts */ NULL,
/* deformMatrices */ NULL,
/* deformVertsEM */ NULL,
/* deformMatricesEM */ NULL,
- /* applyModifier */ applyModifier,
+ /* modifyMesh */ modifyMesh,
+ /* modifyHair */ NULL,
+ /* modifyPointCloud */ NULL,
+ /* modifyVolume */ NULL,
/* initData */ initData,
/* requiredDataMask */ requiredDataMask,
diff --git a/source/blender/modifiers/intern/MOD_smooth.c b/source/blender/modifiers/intern/MOD_smooth.c
index 2a0376fd291..7ac6690e3a7 100644
--- a/source/blender/modifiers/intern/MOD_smooth.c
+++ b/source/blender/modifiers/intern/MOD_smooth.c
@@ -10,7 +10,7 @@
* 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,
+ * 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) 2005 by the Blender Foundation.
@@ -216,6 +216,9 @@ static void deformVertsEM(ModifierData *md,
/* mesh_src is needed for vgroups, and taking edges into account. */
mesh_src = MOD_deform_mesh_eval_get(ctx->object, editData, mesh, NULL, numVerts, false, false);
+ /* TODO(campbell): use edit-mode data only (remove this line). */
+ BKE_mesh_wrapper_ensure_mdata(mesh_src);
+
smoothModifier_do(smd, ctx->object, mesh_src, vertexCos, numVerts);
if (!ELEM(mesh_src, NULL, mesh)) {
@@ -231,13 +234,16 @@ ModifierTypeInfo modifierType_Smooth = {
/* flags */ eModifierTypeFlag_AcceptsMesh | eModifierTypeFlag_AcceptsCVs |
eModifierTypeFlag_SupportsEditmode,
- /* copyData */ modifier_copyData_generic,
+ /* copyData */ BKE_modifier_copydata_generic,
/* deformVerts */ deformVerts,
/* deformMatrices */ NULL,
/* deformVertsEM */ deformVertsEM,
/* deformMatricesEM */ NULL,
- /* applyModifier */ NULL,
+ /* modifyMesh */ NULL,
+ /* modifyHair */ NULL,
+ /* modifyPointCloud */ NULL,
+ /* modifyVolume */ NULL,
/* initData */ initData,
/* requiredDataMask */ requiredDataMask,
diff --git a/source/blender/modifiers/intern/MOD_softbody.c b/source/blender/modifiers/intern/MOD_softbody.c
index efe6b188fa0..92516d3d417 100644
--- a/source/blender/modifiers/intern/MOD_softbody.c
+++ b/source/blender/modifiers/intern/MOD_softbody.c
@@ -10,7 +10,7 @@
* 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,
+ * 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) 2005 by the Blender Foundation.
@@ -78,7 +78,7 @@ ModifierTypeInfo modifierType_Softbody = {
/* structName */ "SoftbodyModifierData",
/* structSize */ sizeof(SoftbodyModifierData),
/* type */ eModifierTypeType_OnlyDeform,
- /* flags */ eModifierTypeFlag_AcceptsCVs | eModifierTypeFlag_AcceptsLattice |
+ /* flags */ eModifierTypeFlag_AcceptsCVs | eModifierTypeFlag_AcceptsVertexCosOnly |
eModifierTypeFlag_RequiresOriginalData | eModifierTypeFlag_Single |
eModifierTypeFlag_UsesPointCache,
@@ -88,7 +88,10 @@ ModifierTypeInfo modifierType_Softbody = {
/* deformMatrices */ NULL,
/* deformVertsEM */ NULL,
/* deformMatricesEM */ NULL,
- /* applyModifier */ NULL,
+ /* modifyMesh */ NULL,
+ /* modifyHair */ NULL,
+ /* modifyPointCloud */ NULL,
+ /* modifyVolume */ NULL,
/* initData */ NULL,
/* requiredDataMask */ NULL,
diff --git a/source/blender/modifiers/intern/MOD_solidify.c b/source/blender/modifiers/intern/MOD_solidify.c
index 41852272787..01277facacf 100644
--- a/source/blender/modifiers/intern/MOD_solidify.c
+++ b/source/blender/modifiers/intern/MOD_solidify.c
@@ -10,7 +10,7 @@
* 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,
+ * 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) 2005 by the Blender Foundation.
@@ -53,6 +53,8 @@ static void initData(ModifierData *md)
smd->mode = MOD_SOLIDIFY_MODE_EXTRUDE;
smd->nonmanifold_offset_mode = MOD_SOLIDIFY_NONMANIFOLD_OFFSET_MODE_CONSTRAINTS;
smd->nonmanifold_boundary_mode = MOD_SOLIDIFY_NONMANIFOLD_BOUNDARY_MODE_NONE;
+ smd->merge_tolerance = 0.0001f;
+ smd->bevel_convex = 0.0f;
}
static void requiredDataMask(Object *UNUSED(ob),
@@ -62,19 +64,20 @@ static void requiredDataMask(Object *UNUSED(ob),
SolidifyModifierData *smd = (SolidifyModifierData *)md;
/* ask for vertexgroups if we need them */
- if (smd->defgrp_name[0] != '\0') {
+ if (smd->defgrp_name[0] != '\0' || smd->shell_defgrp_name[0] != '\0' ||
+ smd->rim_defgrp_name[0] != '\0') {
r_cddata_masks->vmask |= CD_MASK_MDEFORMVERT;
}
}
-static Mesh *applyModifier(ModifierData *md, const ModifierEvalContext *ctx, Mesh *mesh)
+static Mesh *modifyMesh(ModifierData *md, const ModifierEvalContext *ctx, Mesh *mesh)
{
const SolidifyModifierData *smd = (SolidifyModifierData *)md;
switch (smd->mode) {
case MOD_SOLIDIFY_MODE_EXTRUDE:
- return MOD_solidify_extrude_applyModifier(md, ctx, mesh);
+ return MOD_solidify_extrude_modifyMesh(md, ctx, mesh);
case MOD_SOLIDIFY_MODE_NONMANIFOLD:
- return MOD_solidify_nonmanifold_applyModifier(md, ctx, mesh);
+ return MOD_solidify_nonmanifold_modifyMesh(md, ctx, mesh);
default:
BLI_assert(0);
}
@@ -91,13 +94,16 @@ ModifierTypeInfo modifierType_Solidify = {
eModifierTypeFlag_SupportsMapping | eModifierTypeFlag_SupportsEditmode |
eModifierTypeFlag_EnableInEditmode,
- /* copyData */ modifier_copyData_generic,
+ /* copyData */ BKE_modifier_copydata_generic,
/* deformVerts */ NULL,
/* deformMatrices */ NULL,
/* deformVertsEM */ NULL,
/* deformMatricesEM */ NULL,
- /* applyModifier */ applyModifier,
+ /* modifyMesh */ modifyMesh,
+ /* modifyHair */ NULL,
+ /* modifyPointCloud */ NULL,
+ /* modifyVolume */ NULL,
/* initData */ initData,
/* requiredDataMask */ requiredDataMask,
diff --git a/source/blender/modifiers/intern/MOD_solidify_extrude.c b/source/blender/modifiers/intern/MOD_solidify_extrude.c
index 8febf78fef5..75d2be5292e 100644
--- a/source/blender/modifiers/intern/MOD_solidify_extrude.c
+++ b/source/blender/modifiers/intern/MOD_solidify_extrude.c
@@ -10,7 +10,7 @@
* 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,
+ * along with this program; if not, write to the Free Software Foundation,
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
@@ -183,9 +183,7 @@ static void mesh_calc_hq_normal(Mesh *mesh, float (*poly_nors)[3], float (*r_ver
/** \name Main Solidify Function
* \{ */
-Mesh *MOD_solidify_extrude_applyModifier(ModifierData *md,
- const ModifierEvalContext *ctx,
- Mesh *mesh)
+Mesh *MOD_solidify_extrude_modifyMesh(ModifierData *md, const ModifierEvalContext *ctx, Mesh *mesh)
{
Mesh *result;
const SolidifyModifierData *smd = (SolidifyModifierData *)md;
@@ -224,22 +222,28 @@ Mesh *MOD_solidify_extrude_applyModifier(ModifierData *md,
const bool need_poly_normals = (smd->flag & MOD_SOLIDIFY_NORMAL_CALC) ||
(smd->flag & MOD_SOLIDIFY_EVEN) ||
- (smd->flag & MOD_SOLIDIFY_OFFSET_ANGLE_CLAMP);
+ (smd->flag & MOD_SOLIDIFY_OFFSET_ANGLE_CLAMP) ||
+ (smd->bevel_convex != 0);
const float ofs_orig = -(((-smd->offset_fac + 1.0f) * 0.5f) * smd->offset);
const float ofs_new = smd->offset + ofs_orig;
const float offset_fac_vg = smd->offset_fac_vg;
const float offset_fac_vg_inv = 1.0f - smd->offset_fac_vg;
+ const float bevel_convex = smd->bevel_convex;
const bool do_flip = (smd->flag & MOD_SOLIDIFY_FLIP) != 0;
const bool do_clamp = (smd->offset_clamp != 0.0f);
- const bool do_angle_clamp = (smd->flag & MOD_SOLIDIFY_OFFSET_ANGLE_CLAMP) != 0;
- const bool do_shell = ((smd->flag & MOD_SOLIDIFY_RIM) && (smd->flag & MOD_SOLIDIFY_NOSHELL)) ==
- 0;
+ const bool do_angle_clamp = do_clamp && (smd->flag & MOD_SOLIDIFY_OFFSET_ANGLE_CLAMP) != 0;
+ const bool do_bevel_convex = bevel_convex != 0.0f;
+ const bool do_rim = (smd->flag & MOD_SOLIDIFY_RIM) != 0;
+ const bool do_shell = !(do_rim && (smd->flag & MOD_SOLIDIFY_NOSHELL) != 0);
/* weights */
MDeformVert *dvert;
const bool defgrp_invert = (smd->flag & MOD_SOLIDIFY_VGROUP_INV) != 0;
int defgrp_index;
+ const int shell_defgrp_index = BKE_object_defgroup_name_index(ctx->object,
+ smd->shell_defgrp_name);
+ const int rim_defgrp_index = BKE_object_defgroup_name_index(ctx->object, smd->rim_defgrp_name);
/* array size is doubled in case of using a shell */
const uint stride = do_shell ? 2 : 1;
@@ -268,7 +272,7 @@ Mesh *MOD_solidify_extrude_applyModifier(ModifierData *md,
STACK_INIT(new_vert_arr, numVerts * 2);
STACK_INIT(new_edge_arr, numEdges * 2);
- if (smd->flag & MOD_SOLIDIFY_RIM) {
+ if (do_rim) {
BLI_bitmap *orig_mvert_tag = BLI_BITMAP_NEW(numVerts, __func__);
uint eidx;
uint i;
@@ -367,6 +371,11 @@ Mesh *MOD_solidify_extrude_applyModifier(ModifierData *md,
medge = result->medge;
mvert = result->mvert;
+ if (do_bevel_convex) {
+ /* Make sure bweight is enabled. */
+ result->cd_flag |= ME_CDFLAG_EDGE_BWEIGHT;
+ }
+
if (do_shell) {
CustomData_copy_data(&mesh->vdata, &result->vdata, 0, 0, (int)numVerts);
CustomData_copy_data(&mesh->vdata, &result->vdata, 0, (int)numVerts, (int)numVerts);
@@ -507,62 +516,81 @@ Mesh *MOD_solidify_extrude_applyModifier(ModifierData *md,
const float offset = fabsf(smd->offset) * smd->offset_clamp;
const float offset_sq = offset * offset;
- if (do_clamp) {
- uint i;
+ /* for bevel weight */
+ float *edge_angs = NULL;
+ if (do_clamp) {
vert_lens = MEM_malloc_arrayN(numVerts, sizeof(float), "vert_lens");
copy_vn_fl(vert_lens, (int)numVerts, FLT_MAX);
- for (i = 0; i < numEdges; i++) {
+ for (uint i = 0; i < numEdges; i++) {
const float ed_len_sq = len_squared_v3v3(mvert[medge[i].v1].co, mvert[medge[i].v2].co);
vert_lens[medge[i].v1] = min_ff(vert_lens[medge[i].v1], ed_len_sq);
vert_lens[medge[i].v2] = min_ff(vert_lens[medge[i].v2], ed_len_sq);
}
+ }
+
+ if (do_angle_clamp || do_bevel_convex) {
+ uint eidx;
if (do_angle_clamp) {
- uint eidx;
vert_angs = MEM_malloc_arrayN(numVerts, sizeof(float), "vert_angs");
copy_vn_fl(vert_angs, (int)numVerts, 0.5f * M_PI);
- uint(*edge_user_pairs)[2] = MEM_malloc_arrayN(
- numEdges, sizeof(*edge_user_pairs), "edge_user_pairs");
- for (eidx = 0; eidx < numEdges; eidx++) {
- edge_user_pairs[eidx][0] = INVALID_UNUSED;
- edge_user_pairs[eidx][1] = INVALID_UNUSED;
+ }
+ if (do_bevel_convex) {
+ edge_angs = MEM_malloc_arrayN(numEdges, sizeof(float), "edge_angs");
+ if (!do_rim) {
+ edge_users = MEM_malloc_arrayN(numEdges, sizeof(*edge_users), "solid_mod edges");
}
- for (i = 0, mp = orig_mpoly; i < numPolys; i++, mp++) {
- ml = orig_mloop + mp->loopstart;
- MLoop *ml_prev = ml + (mp->totloop - 1);
-
- for (int j = 0; j < mp->totloop; j++, ml++) {
- /* add edge user */
- eidx = ml_prev->e;
- ed = orig_medge + eidx;
- BLI_assert(ELEM(ml_prev->v, ed->v1, ed->v2) && ELEM(ml->v, ed->v1, ed->v2));
- char flip = (char)((ml_prev->v > ml->v) == (ed->v1 < ed->v2));
- if (edge_user_pairs[eidx][flip] == INVALID_UNUSED) {
- edge_user_pairs[eidx][flip] = i;
- }
- else {
- edge_user_pairs[eidx][0] = INVALID_PAIR;
- edge_user_pairs[eidx][1] = INVALID_PAIR;
- }
- ml_prev = ml;
+ }
+ uint(*edge_user_pairs)[2] = MEM_malloc_arrayN(
+ numEdges, sizeof(*edge_user_pairs), "edge_user_pairs");
+ for (eidx = 0; eidx < numEdges; eidx++) {
+ edge_user_pairs[eidx][0] = INVALID_UNUSED;
+ edge_user_pairs[eidx][1] = INVALID_UNUSED;
+ }
+ mp = orig_mpoly;
+ for (uint i = 0; i < numPolys; i++, mp++) {
+ ml = orig_mloop + mp->loopstart;
+ MLoop *ml_prev = ml + (mp->totloop - 1);
+
+ for (uint j = 0; j < mp->totloop; j++, ml++) {
+ /* add edge user */
+ eidx = ml_prev->e;
+ ed = orig_medge + eidx;
+ BLI_assert(ELEM(ml_prev->v, ed->v1, ed->v2) && ELEM(ml->v, ed->v1, ed->v2));
+ char flip = (char)((ml_prev->v > ml->v) == (ed->v1 < ed->v2));
+ if (edge_user_pairs[eidx][flip] == INVALID_UNUSED) {
+ edge_user_pairs[eidx][flip] = i;
+ }
+ else {
+ edge_user_pairs[eidx][0] = INVALID_PAIR;
+ edge_user_pairs[eidx][1] = INVALID_PAIR;
}
+ ml_prev = ml;
}
- ed = orig_medge;
- float e[3];
- for (i = 0; i < numEdges; i++, ed++) {
- if (!ELEM(edge_user_pairs[i][0], INVALID_UNUSED, INVALID_PAIR) &&
- !ELEM(edge_user_pairs[i][1], INVALID_UNUSED, INVALID_PAIR)) {
- const float *n0 = poly_nors[edge_user_pairs[i][0]];
- const float *n1 = poly_nors[edge_user_pairs[i][1]];
- sub_v3_v3v3(e, orig_mvert[ed->v1].co, orig_mvert[ed->v2].co);
- normalize_v3(e);
- const float angle = angle_signed_on_axis_v3v3_v3(n0, n1, e);
+ }
+ ed = orig_medge;
+ float e[3];
+ for (uint i = 0; i < numEdges; i++, ed++) {
+ if (!ELEM(edge_user_pairs[i][0], INVALID_UNUSED, INVALID_PAIR) &&
+ !ELEM(edge_user_pairs[i][1], INVALID_UNUSED, INVALID_PAIR)) {
+ const float *n0 = poly_nors[edge_user_pairs[i][0]];
+ const float *n1 = poly_nors[edge_user_pairs[i][1]];
+ sub_v3_v3v3(e, orig_mvert[ed->v1].co, orig_mvert[ed->v2].co);
+ normalize_v3(e);
+ const float angle = angle_signed_on_axis_v3v3_v3(n0, n1, e);
+ if (do_angle_clamp) {
vert_angs[ed->v1] = max_ff(vert_angs[ed->v1], angle);
vert_angs[ed->v2] = max_ff(vert_angs[ed->v2], angle);
}
+ if (do_bevel_convex) {
+ edge_angs[i] = angle;
+ if (!do_rim) {
+ edge_users[i] = INVALID_PAIR;
+ }
+ }
}
- MEM_freeN(edge_user_pairs);
}
+ MEM_freeN(edge_user_pairs);
}
if (ofs_new != 0.0f) {
@@ -658,6 +686,33 @@ Mesh *MOD_solidify_extrude_applyModifier(ModifierData *md,
}
}
+ if (do_bevel_convex) {
+ for (uint i = 0; i < numEdges; i++) {
+ if (edge_users[i] == INVALID_PAIR) {
+ float angle = edge_angs[i];
+ medge[i].bweight = (char)clamp_i(
+ (int)medge[i].bweight + (int)((angle < M_PI ? clamp_f(bevel_convex, 0.0f, 1.0f) :
+ clamp_f(bevel_convex, -1.0f, 0.0f)) *
+ 255),
+ 0,
+ 255);
+ if (do_shell) {
+ medge[i + numEdges].bweight = (char)clamp_i(
+ (int)medge[i + numEdges].bweight +
+ (int)((angle > M_PI ? clamp_f(bevel_convex, 0.0f, 1.0f) :
+ clamp_f(bevel_convex, -1.0f, 0.0f)) *
+ 255),
+ 0,
+ 255);
+ }
+ }
+ }
+ if (!do_rim) {
+ MEM_freeN(edge_users);
+ }
+ MEM_freeN(edge_angs);
+ }
+
if (do_clamp) {
MEM_freeN(vert_lens);
if (do_angle_clamp) {
@@ -754,6 +809,74 @@ Mesh *MOD_solidify_extrude_applyModifier(ModifierData *md,
}
}
+ /* for angle clamp */
+ float *vert_angs = NULL;
+ /* for bevel convex */
+ float *edge_angs = NULL;
+
+ if (do_angle_clamp || do_bevel_convex) {
+ uint eidx;
+ if (do_angle_clamp) {
+ vert_angs = MEM_malloc_arrayN(numVerts, sizeof(float), "vert_angs even");
+ copy_vn_fl(vert_angs, (int)numVerts, 0.5f * M_PI);
+ }
+ if (do_bevel_convex) {
+ edge_angs = MEM_malloc_arrayN(numEdges, sizeof(float), "edge_angs even");
+ if (!do_rim) {
+ edge_users = MEM_malloc_arrayN(numEdges, sizeof(*edge_users), "solid_mod edges");
+ }
+ }
+ uint(*edge_user_pairs)[2] = MEM_malloc_arrayN(
+ numEdges, sizeof(*edge_user_pairs), "edge_user_pairs");
+ for (eidx = 0; eidx < numEdges; eidx++) {
+ edge_user_pairs[eidx][0] = INVALID_UNUSED;
+ edge_user_pairs[eidx][1] = INVALID_UNUSED;
+ }
+ for (i = 0, mp = orig_mpoly; i < numPolys; i++, mp++) {
+ ml = orig_mloop + mp->loopstart;
+ MLoop *ml_prev = ml + (mp->totloop - 1);
+
+ for (int j = 0; j < mp->totloop; j++, ml++) {
+ /* add edge user */
+ eidx = ml_prev->e;
+ ed = orig_medge + eidx;
+ BLI_assert(ELEM(ml_prev->v, ed->v1, ed->v2) && ELEM(ml->v, ed->v1, ed->v2));
+ char flip = (char)((ml_prev->v > ml->v) == (ed->v1 < ed->v2));
+ if (edge_user_pairs[eidx][flip] == INVALID_UNUSED) {
+ edge_user_pairs[eidx][flip] = i;
+ }
+ else {
+ edge_user_pairs[eidx][0] = INVALID_PAIR;
+ edge_user_pairs[eidx][1] = INVALID_PAIR;
+ }
+ ml_prev = ml;
+ }
+ }
+ ed = orig_medge;
+ float e[3];
+ for (i = 0; i < numEdges; i++, ed++) {
+ if (!ELEM(edge_user_pairs[i][0], INVALID_UNUSED, INVALID_PAIR) &&
+ !ELEM(edge_user_pairs[i][1], INVALID_UNUSED, INVALID_PAIR)) {
+ const float *n0 = poly_nors[edge_user_pairs[i][0]];
+ const float *n1 = poly_nors[edge_user_pairs[i][1]];
+ if (do_angle_clamp) {
+ const float angle = M_PI - angle_normalized_v3v3(n0, n1);
+ vert_angs[ed->v1] = max_ff(vert_angs[ed->v1], angle);
+ vert_angs[ed->v2] = max_ff(vert_angs[ed->v2], angle);
+ }
+ if (do_bevel_convex) {
+ sub_v3_v3v3(e, orig_mvert[ed->v1].co, orig_mvert[ed->v2].co);
+ normalize_v3(e);
+ edge_angs[i] = angle_signed_on_axis_v3v3_v3(n0, n1, e);
+ if (!do_rim) {
+ edge_users[i] = INVALID_PAIR;
+ }
+ }
+ }
+ }
+ MEM_freeN(edge_user_pairs);
+ }
+
if (do_clamp) {
const float clamp_fac = 1 + (do_angle_clamp ? fabsf(smd->offset_fac) : 0);
const float offset = fabsf(smd->offset) * smd->offset_clamp * clamp_fac;
@@ -767,48 +890,6 @@ Mesh *MOD_solidify_extrude_applyModifier(ModifierData *md,
vert_lens_sq[medge[i].v2] = min_ff(vert_lens_sq[medge[i].v2], ed_len);
}
if (do_angle_clamp) {
- uint eidx;
- float *vert_angs = MEM_malloc_arrayN(numVerts, sizeof(float), "vert_angs even");
- copy_vn_fl(vert_angs, (int)numVerts, 0.5f * M_PI);
- uint(*edge_user_pairs)[2] = MEM_malloc_arrayN(
- numEdges, sizeof(*edge_user_pairs), "edge_user_pairs");
- for (eidx = 0; eidx < numEdges; eidx++) {
- edge_user_pairs[eidx][0] = INVALID_UNUSED;
- edge_user_pairs[eidx][1] = INVALID_UNUSED;
- }
- for (i = 0, mp = orig_mpoly; i < numPolys; i++, mp++) {
- ml = orig_mloop + mp->loopstart;
- MLoop *ml_prev = ml + (mp->totloop - 1);
-
- for (int j = 0; j < mp->totloop; j++, ml++) {
- /* add edge user */
- eidx = ml_prev->e;
- ed = orig_medge + eidx;
- BLI_assert(ELEM(ml_prev->v, ed->v1, ed->v2) && ELEM(ml->v, ed->v1, ed->v2));
- char flip = (char)((ml_prev->v > ml->v) == (ed->v1 < ed->v2));
- if (edge_user_pairs[eidx][flip] == INVALID_UNUSED) {
- edge_user_pairs[eidx][flip] = i;
- }
- else {
- edge_user_pairs[eidx][0] = INVALID_PAIR;
- edge_user_pairs[eidx][1] = INVALID_PAIR;
- }
- ml_prev = ml;
- }
- }
- ed = orig_medge;
- for (i = 0; i < numEdges; i++, ed++) {
- if (!ELEM(edge_user_pairs[i][0], INVALID_UNUSED, INVALID_PAIR) &&
- !ELEM(edge_user_pairs[i][1], INVALID_UNUSED, INVALID_PAIR)) {
- const float *n0 = poly_nors[edge_user_pairs[i][0]];
- const float *n1 = poly_nors[edge_user_pairs[i][1]];
- const float angle = M_PI - angle_normalized_v3v3(n0, n1);
- vert_angs[ed->v1] = max_ff(vert_angs[ed->v1], angle);
- vert_angs[ed->v2] = max_ff(vert_angs[ed->v2], angle);
- }
- }
- MEM_freeN(edge_user_pairs);
-
for (i = 0; i < numVerts; i++) {
float cos_ang = cosf(vert_angs[i] * 0.5f);
if (cos_ang > 0) {
@@ -832,6 +913,33 @@ Mesh *MOD_solidify_extrude_applyModifier(ModifierData *md,
}
}
+ if (do_bevel_convex) {
+ for (i = 0; i < numEdges; i++) {
+ if (edge_users[i] == INVALID_PAIR) {
+ float angle = edge_angs[i];
+ medge[i].bweight = (char)clamp_i(
+ (int)medge[i].bweight + (int)((angle < M_PI ? clamp_f(bevel_convex, 0, 1) :
+ clamp_f(bevel_convex, -1, 0)) *
+ 255),
+ 0,
+ 255);
+ if (do_shell) {
+ medge[i + numEdges].bweight = (char)clamp_i(
+ (int)medge[i + numEdges].bweight +
+ (int)((angle > M_PI ? clamp_f(bevel_convex, 0, 1) :
+ clamp_f(bevel_convex, -1, 0)) *
+ 255),
+ 0,
+ 255);
+ }
+ }
+ }
+ if (!do_rim) {
+ MEM_freeN(edge_users);
+ }
+ MEM_freeN(edge_angs);
+ }
+
#undef INVALID_UNUSED
#undef INVALID_PAIR
@@ -874,7 +982,7 @@ Mesh *MOD_solidify_extrude_applyModifier(ModifierData *md,
}
/* must recalculate normals with vgroups since they can displace unevenly [#26888] */
- if ((mesh->runtime.cd_dirty_vert & CD_MASK_NORMAL) || (smd->flag & MOD_SOLIDIFY_RIM) || dvert) {
+ if ((mesh->runtime.cd_dirty_vert & CD_MASK_NORMAL) || do_rim || dvert) {
result->runtime.cd_dirty_vert |= CD_MASK_NORMAL;
}
else if (do_shell) {
@@ -886,7 +994,37 @@ Mesh *MOD_solidify_extrude_applyModifier(ModifierData *md,
}
}
- if (smd->flag & MOD_SOLIDIFY_RIM) {
+ /* Add vertex weights for rim and shell vgroups. */
+ if (shell_defgrp_index != -1 || rim_defgrp_index != -1) {
+ dvert = CustomData_duplicate_referenced_layer(&result->vdata, CD_MDEFORMVERT, result->totvert);
+ /* If no vertices were ever added to an object's vgroup, dvert might be NULL. */
+ if (dvert == NULL) {
+ /* Add a valid data layer! */
+ dvert = CustomData_add_layer(
+ &result->vdata, CD_MDEFORMVERT, CD_CALLOC, NULL, result->totvert);
+ }
+ /* Ultimate security check. */
+ if (!dvert) {
+ return result;
+ }
+ result->dvert = dvert;
+
+ if (rim_defgrp_index != -1) {
+ for (uint i = 0; i < rimVerts; i++) {
+ BKE_defvert_ensure_index(&result->dvert[new_vert_arr[i]], rim_defgrp_index)->weight = 1.0f;
+ BKE_defvert_ensure_index(&result->dvert[(do_shell ? new_vert_arr[i] : i) + numVerts],
+ rim_defgrp_index)
+ ->weight = 1.0f;
+ }
+ }
+
+ if (shell_defgrp_index != -1) {
+ for (uint i = numVerts; i < result->totvert; i++) {
+ BKE_defvert_ensure_index(&result->dvert[i], shell_defgrp_index)->weight = 1.0f;
+ }
+ }
+ }
+ if (do_rim) {
uint i;
/* bugger, need to re-calculate the normals for the new edge faces.
@@ -1093,10 +1231,6 @@ Mesh *MOD_solidify_extrude_applyModifier(ModifierData *md,
MEM_freeN(poly_nors);
}
- if (numPolys == 0 && numVerts != 0) {
- modifier_setError(md, "Faces needed for useful output");
- }
-
return result;
}
diff --git a/source/blender/modifiers/intern/MOD_solidify_nonmanifold.c b/source/blender/modifiers/intern/MOD_solidify_nonmanifold.c
index 22fc56bdeaf..423a6b4458a 100644
--- a/source/blender/modifiers/intern/MOD_solidify_nonmanifold.c
+++ b/source/blender/modifiers/intern/MOD_solidify_nonmanifold.c
@@ -10,7 +10,7 @@
* 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,
+ * along with this program; if not, write to the Free Software Foundation,
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
@@ -132,9 +132,9 @@ static int comp_float_int_pair(const void *a, const void *b)
return (int)(x->angle > y->angle) - (int)(x->angle < y->angle);
}
-Mesh *MOD_solidify_nonmanifold_applyModifier(ModifierData *md,
- const ModifierEvalContext *ctx,
- Mesh *mesh)
+Mesh *MOD_solidify_nonmanifold_modifyMesh(ModifierData *md,
+ const ModifierEvalContext *ctx,
+ Mesh *mesh)
{
Mesh *result;
const SolidifyModifierData *smd = (SolidifyModifierData *)md;
@@ -149,7 +149,6 @@ Mesh *MOD_solidify_nonmanifold_applyModifier(ModifierData *md,
const uint numLoops = (uint)mesh->totloop;
if (numPolys == 0 && numVerts != 0) {
- modifier_setError(md, "Faces needed for useful output");
return mesh;
}
@@ -175,12 +174,19 @@ Mesh *MOD_solidify_nonmanifold_applyModifier(ModifierData *md,
0;
const bool do_clamp = (smd->offset_clamp != 0.0f);
+ const float bevel_convex = smd->bevel_convex;
+
MDeformVert *dvert;
const bool defgrp_invert = (smd->flag & MOD_SOLIDIFY_VGROUP_INV) != 0;
int defgrp_index;
+ const int shell_defgrp_index = BKE_object_defgroup_name_index(ctx->object,
+ smd->shell_defgrp_name);
+ const int rim_defgrp_index = BKE_object_defgroup_name_index(ctx->object, smd->rim_defgrp_name);
MOD_get_vgroup(ctx->object, mesh, smd->defgrp_name, &dvert, &defgrp_index);
+ const bool do_flat_faces = dvert && (smd->flag & MOD_SOLIDIFY_NONMANIFOLD_FLAT_FACES);
+
orig_mvert = mesh->mvert;
orig_medge = mesh->medge;
orig_mloop = mesh->mloop;
@@ -288,6 +294,15 @@ Mesh *MOD_solidify_nonmanifold_applyModifier(ModifierData *md,
/* Vert edge adjacent map. */
OldVertEdgeRef **vert_adj_edges = MEM_calloc_arrayN(
numVerts, sizeof(*vert_adj_edges), "vert_adj_edges in solidify");
+ /* Original vertex positions (changed for degenerated geometry). */
+ float(*orig_mvert_co)[3] = MEM_malloc_arrayN(
+ numVerts, sizeof(*orig_mvert_co), "orig_mvert_co in solidify");
+ /* Fill in the original vertex positions. */
+ for (uint i = 0; i < numVerts; i++) {
+ orig_mvert_co[i][0] = orig_mvert[i].co[0];
+ orig_mvert_co[i][1] = orig_mvert[i].co[1];
+ orig_mvert_co[i][2] = orig_mvert[i].co[2];
+ }
/* Create edge to #NewEdgeRef map. */
{
@@ -341,33 +356,35 @@ Mesh *MOD_solidify_nonmanifold_applyModifier(ModifierData *md,
bool *face_singularity = MEM_calloc_arrayN(
numPolys, sizeof(*face_singularity), "face_sides_arr in solidify");
+ const float merge_tolerance_sqr = smd->merge_tolerance * smd->merge_tolerance;
+ uint *combined_verts = MEM_calloc_arrayN(
+ numVerts, sizeof(*combined_verts), "combined_verts in solidify");
+
ed = orig_medge;
for (uint i = 0; i < numEdges; i++, ed++) {
if (edge_adj_faces_len[i] > 0) {
- const uint v1 = vm[ed->v1];
- const uint v2 = vm[ed->v2];
+ uint v1 = vm[ed->v1];
+ uint v2 = vm[ed->v2];
if (v1 != v2) {
- sub_v3_v3v3(edgedir, orig_mvert[v2].co, orig_mvert[v1].co);
+ if (v2 < v1) {
+ SWAP(uint, v1, v2);
+ }
+ sub_v3_v3v3(edgedir, orig_mvert_co[v2], orig_mvert_co[v1]);
orig_edge_lengths[i] = len_squared_v3(edgedir);
- if (orig_edge_lengths[i] <= FLT_EPSILON) {
- if (v2 > v1) {
- for (uint j = v2; j < numVerts; j++) {
- if (vm[j] == v2) {
- vm[j] = v1;
- vert_adj_edges_len[v1] += vert_adj_edges_len[j];
- vert_adj_edges_len[j] = 0;
- }
- }
- }
- else if (v2 < v1) {
- for (uint j = v1; j < numVerts; j++) {
- if (vm[j] == v1) {
- vm[j] = v2;
- vert_adj_edges_len[v2] += vert_adj_edges_len[j];
- vert_adj_edges_len[j] = 0;
- }
+ if (orig_edge_lengths[i] <= merge_tolerance_sqr) {
+ mul_v3_fl(edgedir,
+ (combined_verts[v2] + 1) /
+ (float)(combined_verts[v1] + combined_verts[v2] + 2));
+ add_v3_v3(orig_mvert_co[v1], edgedir);
+ for (uint j = v2; j < numVerts; j++) {
+ if (vm[j] == v2) {
+ vm[j] = v1;
}
}
+ vert_adj_edges_len[v1] += vert_adj_edges_len[v2];
+ vert_adj_edges_len[v2] = 0;
+ combined_verts[v1] += combined_verts[v2] + 1;
+
if (do_shell) {
numNewLoops -= edge_adj_faces_len[i] * 2;
}
@@ -426,6 +443,7 @@ Mesh *MOD_solidify_nonmanifold_applyModifier(ModifierData *md,
}
MEM_freeN(face_singularity);
+ MEM_freeN(combined_verts);
}
/* Create vert_adj_edges for verts. */
@@ -665,7 +683,7 @@ Mesh *MOD_solidify_nonmanifold_applyModifier(ModifierData *md,
const uint v1 = vm[ed->v1];
const uint v2 = vm[ed->v2];
if (edge_adj_faces_len[i] > 0) {
- sub_v3_v3v3(edgedir, orig_mvert[v2].co, orig_mvert[v1].co);
+ sub_v3_v3v3(edgedir, orig_mvert_co[v2], orig_mvert_co[v1]);
mul_v3_fl(edgedir, 1.0f / orig_edge_lengths[i]);
OldEdgeFaceRef *adj_faces = edge_adj_faces[i];
@@ -1288,6 +1306,30 @@ Mesh *MOD_solidify_nonmanifold_applyModifier(ModifierData *md,
/* Calculate EdgeGroup vertex coordinates. */
{
+ float *face_weight = NULL;
+
+ if (do_flat_faces) {
+ face_weight = MEM_malloc_arrayN(numPolys, sizeof(*face_weight), "face_weight in solidify");
+
+ mp = orig_mpoly;
+ for (uint i = 0; i < numPolys; i++, mp++) {
+ float scalar_vgroup = 1.0f;
+ int loopend = mp->loopstart + mp->totloop;
+ ml = orig_mloop + mp->loopstart;
+ for (int j = mp->loopstart; j < loopend; j++, ml++) {
+ MDeformVert *dv = &dvert[ml->v];
+ if (defgrp_invert) {
+ scalar_vgroup = min_ff(1.0f - BKE_defvert_find_weight(dv, defgrp_index),
+ scalar_vgroup);
+ }
+ else {
+ scalar_vgroup = min_ff(BKE_defvert_find_weight(dv, defgrp_index), scalar_vgroup);
+ }
+ }
+ face_weight[i] = scalar_vgroup;
+ }
+ }
+
mv = orig_mvert;
gs_ptr = orig_vert_groups_arr;
for (uint i = 0; i < numVerts; i++, mv++, gs_ptr++) {
@@ -1320,14 +1362,22 @@ Mesh *MOD_solidify_nonmanifold_applyModifier(ModifierData *md,
NewFaceRef *face = edge->faces[l];
if (face && (first_edge == NULL ||
(first_edge->faces[0] != face && first_edge->faces[1] != face))) {
- const float ofs = face->reversed ? ofs_back_clamped : ofs_front_clamped;
+ float ofs = face->reversed ? ofs_back_clamped : ofs_front_clamped;
+ /* Use face_weight here to make faces thinner. */
+ if (do_flat_faces) {
+ ofs *= face_weight[face->index];
+ }
+
if (!null_faces[face->index]) {
+ /* And normal to the queue. */
mul_v3_v3fl(normals_queue[queue_index],
poly_nors[face->index],
face->reversed ? -1 : 1);
normals_queue[queue_index++][3] = ofs;
}
else {
+ /* Just use this approximate normal of the null face if there is no other
+ * normal to use. */
mul_v3_v3fl(face_nors[0], poly_nors[face->index], face->reversed ? -1 : 1);
nor_ofs[0] = ofs;
}
@@ -1429,6 +1479,7 @@ Mesh *MOD_solidify_nonmanifold_applyModifier(ModifierData *md,
}
}
MEM_freeN(normals_queue);
+
/* When up to 3 constraint normals are found. */
if (ELEM(face_nors_len, 2, 3)) {
const float q = dot_v3v3(face_nors[0], face_nors[1]);
@@ -1483,6 +1534,11 @@ Mesh *MOD_solidify_nonmanifold_applyModifier(ModifierData *md,
(first_edge->faces[0] != face && first_edge->faces[1] != face))) {
float angle = 1.0f;
float ofs = face->reversed ? -ofs_back_clamped : ofs_front_clamped;
+ /* Use face_weight here to make faces thinner. */
+ if (do_flat_faces) {
+ ofs *= face_weight[face->index];
+ }
+
if (smd->nonmanifold_offset_mode ==
MOD_SOLIDIFY_NONMANIFOLD_OFFSET_MODE_EVEN) {
MLoop *ml_next = orig_mloop + face->face->loopstart;
@@ -1493,8 +1549,9 @@ Mesh *MOD_solidify_nonmanifold_applyModifier(ModifierData *md,
ml_prev = ml;
ml = ml_next;
}
- angle = angle_v3v3v3(
- orig_mvert[vm[ml_prev->v]].co, mv->co, orig_mvert[vm[ml_next->v]].co);
+ angle = angle_v3v3v3(orig_mvert_co[vm[ml_prev->v]],
+ orig_mvert_co[i],
+ orig_mvert_co[vm[ml_next->v]]);
if (face->reversed) {
total_angle_back += angle * ofs * ofs;
}
@@ -1588,7 +1645,8 @@ Mesh *MOD_solidify_nonmanifold_applyModifier(ModifierData *md,
uint k;
for (k = 1; k + 1 < g->edges_len; k++, edge_ptr++) {
MEdge *e = orig_medge + (*edge_ptr)->old_edge;
- sub_v3_v3v3(tmp, orig_mvert[vm[e->v1] == i ? e->v2 : e->v1].co, mv->co);
+ sub_v3_v3v3(
+ tmp, orig_mvert_co[vm[e->v1] == i ? e->v2 : e->v1], orig_mvert_co[i]);
add_v3_v3(move_nor, tmp);
}
if (k == 1) {
@@ -1610,10 +1668,12 @@ Mesh *MOD_solidify_nonmanifold_applyModifier(ModifierData *md,
MEdge *e1_edge = orig_medge + g->edges[g->edges_len - 1]->old_edge;
float e0[3];
float e1[3];
- sub_v3_v3v3(
- e0, orig_mvert[vm[e0_edge->v1] == i ? e0_edge->v2 : e0_edge->v1].co, mv->co);
- sub_v3_v3v3(
- e1, orig_mvert[vm[e1_edge->v1] == i ? e1_edge->v2 : e1_edge->v1].co, mv->co);
+ sub_v3_v3v3(e0,
+ orig_mvert_co[vm[e0_edge->v1] == i ? e0_edge->v2 : e0_edge->v1],
+ orig_mvert_co[i]);
+ sub_v3_v3v3(e1,
+ orig_mvert_co[vm[e1_edge->v1] == i ? e1_edge->v2 : e1_edge->v1],
+ orig_mvert_co[i]);
if (smd->nonmanifold_boundary_mode == MOD_SOLIDIFY_NONMANIFOLD_BOUNDARY_MODE_FLAT) {
cross_v3_v3v3(constr_nor, e0, e1);
}
@@ -1648,7 +1708,7 @@ Mesh *MOD_solidify_nonmanifold_applyModifier(ModifierData *md,
}
float scalar_vgroup = 1;
/* Use vertex group. */
- if (dvert) {
+ if (dvert && !do_flat_faces) {
MDeformVert *dv = &dvert[i];
if (defgrp_invert) {
scalar_vgroup = 1.0f - BKE_defvert_find_weight(dv, defgrp_index);
@@ -1699,16 +1759,21 @@ Mesh *MOD_solidify_nonmanifold_applyModifier(ModifierData *md,
}
}
mul_v3_fl(nor, scalar_vgroup);
- add_v3_v3v3(g->co, nor, mv->co);
+ add_v3_v3v3(g->co, nor, orig_mvert_co[i]);
}
else {
- copy_v3_v3(g->co, mv->co);
+ copy_v3_v3(g->co, orig_mvert_co[i]);
}
}
}
}
+
+ if (do_flat_faces) {
+ MEM_freeN(face_weight);
+ }
}
+ MEM_freeN(orig_mvert_co);
if (null_faces) {
MEM_freeN(null_faces);
}
@@ -1778,6 +1843,23 @@ Mesh *MOD_solidify_nonmanifold_applyModifier(ModifierData *md,
int *origindex_edge = CustomData_get_layer(&result->edata, CD_ORIGINDEX);
int *origindex_poly = CustomData_get_layer(&result->pdata, CD_ORIGINDEX);
+ if (bevel_convex != 0.0f) {
+ /* make sure bweight is enabled */
+ result->cd_flag |= ME_CDFLAG_EDGE_BWEIGHT;
+ }
+
+ /* Checks that result has dvert data. */
+ if (shell_defgrp_index != -1 || rim_defgrp_index != -1) {
+ dvert = CustomData_duplicate_referenced_layer(&result->vdata, CD_MDEFORMVERT, result->totvert);
+ /* If no vertices were ever added to an object's vgroup, dvert might be NULL. */
+ if (dvert == NULL) {
+ /* Add a valid data layer! */
+ dvert = CustomData_add_layer(
+ &result->vdata, CD_MDEFORMVERT, CD_CALLOC, NULL, result->totvert);
+ }
+ result->dvert = dvert;
+ }
+
/* Make_new_verts. */
{
gs_ptr = orig_vert_groups_arr;
@@ -1831,6 +1913,17 @@ Mesh *MOD_solidify_nonmanifold_applyModifier(ModifierData *md,
medge[insert].flag = orig_medge[(*l)->old_edge].flag | ME_EDGEDRAW | ME_EDGERENDER;
medge[insert].crease = orig_medge[(*l)->old_edge].crease;
medge[insert].bweight = orig_medge[(*l)->old_edge].bweight;
+ if (bevel_convex != 0.0f && (*l)->faces[1] != NULL) {
+ medge[insert].bweight = (char)clamp_i(
+ (int)medge[insert].bweight + (int)(((*l)->angle > M_PI + FLT_EPSILON ?
+ clamp_f(bevel_convex, 0.0f, 1.0f) :
+ ((*l)->angle < M_PI - FLT_EPSILON ?
+ clamp_f(bevel_convex, -1.0f, 0.0f) :
+ 0)) *
+ 255),
+ 0,
+ 255);
+ }
(*l)->new_edge = insert;
}
}
@@ -1882,7 +1975,8 @@ Mesh *MOD_solidify_nonmanifold_applyModifier(ModifierData *md,
/* Make boundary edges/faces. */
{
gs_ptr = orig_vert_groups_arr;
- for (uint i = 0; i < numVerts; i++, gs_ptr++) {
+ mv = orig_mvert;
+ for (uint i = 0; i < numVerts; i++, gs_ptr++, mv++) {
EdgeGroup *gs = *gs_ptr;
if (gs) {
EdgeGroup *g = gs;
@@ -1904,15 +1998,39 @@ Mesh *MOD_solidify_nonmanifold_applyModifier(ModifierData *md,
max_crease = 0;
max_bweight = 0;
flag = 0;
- for (uint k = 1; k < g->edges_len - 1; k++) {
- ed = orig_medge + g->edges[k]->old_edge;
- if (ed->crease > max_crease) {
- max_crease = ed->crease;
+
+ BLI_assert(g->edges_len >= 2);
+
+ if (g->edges_len == 2) {
+ max_crease = min_cc(orig_medge[g->edges[0]->old_edge].crease,
+ orig_medge[g->edges[1]->old_edge].crease);
+ }
+ else {
+ for (uint k = 1; k < g->edges_len - 1; k++) {
+ ed = orig_medge + g->edges[k]->old_edge;
+ if (ed->crease > max_crease) {
+ max_crease = ed->crease;
+ }
+ if (g->edges[k]->new_edge != MOD_SOLIDIFY_EMPTY_TAG) {
+ char bweight = medge[g->edges[k]->new_edge].bweight;
+ if (bweight > max_bweight) {
+ max_bweight = bweight;
+ }
+ }
+ flag |= ed->flag;
}
- if (ed->bweight > max_bweight) {
- max_bweight = ed->bweight;
+ }
+
+ const char bweight_open_edge = min_cc(
+ orig_medge[g->edges[0]->old_edge].bweight,
+ orig_medge[g->edges[g->edges_len - 1]->old_edge].bweight);
+ if (bweight_open_edge > 0) {
+ max_bweight = min_cc(bweight_open_edge, max_bweight);
+ }
+ else {
+ if (bevel_convex < 0.0f) {
+ max_bweight = 0;
}
- flag |= ed->flag;
}
if (!first_g) {
first_g = g;
@@ -1934,8 +2052,9 @@ Mesh *MOD_solidify_nonmanifold_applyModifier(ModifierData *md,
medge[edge_index].v2 = g->new_vert;
medge[edge_index].flag = ME_EDGEDRAW | ME_EDGERENDER |
((last_flag | flag) & (ME_SEAM | ME_SHARP));
- medge[edge_index].crease = MAX2(last_max_crease, max_crease);
- medge[edge_index++].bweight = MAX2(last_max_bweight, max_bweight);
+ medge[edge_index].crease = min_cc(last_max_crease, max_crease);
+ medge[edge_index++].bweight = max_cc(mv->bweight,
+ min_cc(last_max_bweight, max_bweight));
}
last_g = g;
last_max_crease = max_crease;
@@ -1961,8 +2080,9 @@ Mesh *MOD_solidify_nonmanifold_applyModifier(ModifierData *md,
medge[edge_index].v2 = first_g->new_vert;
medge[edge_index].flag = ME_EDGEDRAW | ME_EDGERENDER |
((last_flag | first_flag) & (ME_SEAM | ME_SHARP));
- medge[edge_index].crease = MAX2(last_max_crease, first_max_crease);
- medge[edge_index++].bweight = MAX2(last_max_bweight, first_max_bweight);
+ medge[edge_index].crease = min_cc(last_max_crease, first_max_crease);
+ medge[edge_index++].bweight = max_cc(mv->bweight,
+ min_cc(last_max_bweight, first_max_bweight));
/* Loop data. */
int *loops = MEM_malloc_arrayN(j, sizeof(*loops), "loops in solidify");
@@ -2101,12 +2221,20 @@ Mesh *MOD_solidify_nonmanifold_applyModifier(ModifierData *md,
MEdge *open_face_edge;
uint open_face_edge_index;
if (!do_flip) {
+ if (rim_defgrp_index != -1) {
+ BKE_defvert_ensure_index(&result->dvert[medge[edge1->new_edge].v1], rim_defgrp_index)
+ ->weight = 1.0f;
+ }
CustomData_copy_data(&mesh->ldata, &result->ldata, loop1, (int)loop_index, 1);
mloop[loop_index].v = medge[edge1->new_edge].v1;
mloop[loop_index++].e = edge1->new_edge;
if (!v2_singularity) {
open_face_edge_index = edge1->link_edge_groups[1]->open_face_edge;
+ if (rim_defgrp_index != -1) {
+ BKE_defvert_ensure_index(&result->dvert[medge[edge1->new_edge].v2], rim_defgrp_index)
+ ->weight = 1.0f;
+ }
CustomData_copy_data(&mesh->ldata, &result->ldata, loop2, (int)loop_index, 1);
mloop[loop_index].v = medge[edge1->new_edge].v2;
open_face_edge = medge + open_face_edge_index;
@@ -2118,12 +2246,20 @@ Mesh *MOD_solidify_nonmanifold_applyModifier(ModifierData *md,
}
}
+ if (rim_defgrp_index != -1) {
+ BKE_defvert_ensure_index(&result->dvert[medge[edge2->new_edge].v2], rim_defgrp_index)
+ ->weight = 1.0f;
+ }
CustomData_copy_data(&mesh->ldata, &result->ldata, loop2, (int)loop_index, 1);
mloop[loop_index].v = medge[edge2->new_edge].v2;
mloop[loop_index++].e = edge2->new_edge;
if (!v1_singularity) {
open_face_edge_index = edge2->link_edge_groups[0]->open_face_edge;
+ if (rim_defgrp_index != -1) {
+ BKE_defvert_ensure_index(&result->dvert[medge[edge2->new_edge].v1], rim_defgrp_index)
+ ->weight = 1.0f;
+ }
CustomData_copy_data(&mesh->ldata, &result->ldata, loop1, (int)loop_index, 1);
mloop[loop_index].v = medge[edge2->new_edge].v1;
open_face_edge = medge + open_face_edge_index;
@@ -2138,6 +2274,10 @@ Mesh *MOD_solidify_nonmanifold_applyModifier(ModifierData *md,
else {
if (!v1_singularity) {
open_face_edge_index = edge1->link_edge_groups[0]->open_face_edge;
+ if (rim_defgrp_index != -1) {
+ BKE_defvert_ensure_index(&result->dvert[medge[edge1->new_edge].v1], rim_defgrp_index)
+ ->weight = 1.0f;
+ }
CustomData_copy_data(&mesh->ldata, &result->ldata, loop1, (int)loop_index, 1);
mloop[loop_index].v = medge[edge1->new_edge].v1;
open_face_edge = medge + open_face_edge_index;
@@ -2149,12 +2289,20 @@ Mesh *MOD_solidify_nonmanifold_applyModifier(ModifierData *md,
}
}
+ if (rim_defgrp_index != -1) {
+ BKE_defvert_ensure_index(&result->dvert[medge[edge2->new_edge].v1], rim_defgrp_index)
+ ->weight = 1.0f;
+ }
CustomData_copy_data(&mesh->ldata, &result->ldata, loop1, (int)loop_index, 1);
mloop[loop_index].v = medge[edge2->new_edge].v1;
mloop[loop_index++].e = edge2->new_edge;
if (!v2_singularity) {
open_face_edge_index = edge2->link_edge_groups[1]->open_face_edge;
+ if (rim_defgrp_index != -1) {
+ BKE_defvert_ensure_index(&result->dvert[medge[edge2->new_edge].v2], rim_defgrp_index)
+ ->weight = 1.0f;
+ }
CustomData_copy_data(&mesh->ldata, &result->ldata, loop2, (int)loop_index, 1);
mloop[loop_index].v = medge[edge2->new_edge].v2;
open_face_edge = medge + open_face_edge_index;
@@ -2166,6 +2314,10 @@ Mesh *MOD_solidify_nonmanifold_applyModifier(ModifierData *md,
}
}
+ if (rim_defgrp_index != -1) {
+ BKE_defvert_ensure_index(&result->dvert[medge[edge1->new_edge].v2], rim_defgrp_index)
+ ->weight = 1.0f;
+ }
CustomData_copy_data(&mesh->ldata, &result->ldata, loop2, (int)loop_index, 1);
mloop[loop_index].v = medge[edge1->new_edge].v2;
mloop[loop_index++].e = edge1->new_edge;
@@ -2243,6 +2395,10 @@ Mesh *MOD_solidify_nonmanifold_applyModifier(ModifierData *md,
mpoly[poly_index].flag = fr->face->flag;
if (fr->reversed != do_flip) {
for (int l = (int)k - 1; l >= 0; l--) {
+ if (shell_defgrp_index != -1) {
+ BKE_defvert_ensure_index(&result->dvert[face_verts[l]], shell_defgrp_index)
+ ->weight = 1.0f;
+ }
CustomData_copy_data(
&mesh->ldata, &result->ldata, (int)face_loops[l], (int)loop_index, 1);
mloop[loop_index].v = face_verts[l];
@@ -2268,15 +2424,15 @@ Mesh *MOD_solidify_nonmanifold_applyModifier(ModifierData *md,
MEM_freeN(face_edges);
}
if (edge_index != numNewEdges) {
- modifier_setError(
+ BKE_modifier_set_error(
md, "Internal Error: edges array wrong size: %u instead of %u", numNewEdges, edge_index);
}
if (poly_index != numNewPolys) {
- modifier_setError(
+ BKE_modifier_set_error(
md, "Internal Error: polys array wrong size: %u instead of %u", numNewPolys, poly_index);
}
if (loop_index != numNewLoops) {
- modifier_setError(
+ BKE_modifier_set_error(
md, "Internal Error: loops array wrong size: %u instead of %u", numNewLoops, loop_index);
}
BLI_assert(edge_index == numNewEdges);
diff --git a/source/blender/modifiers/intern/MOD_solidify_util.h b/source/blender/modifiers/intern/MOD_solidify_util.h
index 3a9608861dc..6ab4734c451 100644
--- a/source/blender/modifiers/intern/MOD_solidify_util.h
+++ b/source/blender/modifiers/intern/MOD_solidify_util.h
@@ -22,13 +22,13 @@
#define __MOD_SOLIDIFY_UTIL_H__
/* MOD_solidify_extrude.c */
-Mesh *MOD_solidify_extrude_applyModifier(ModifierData *md,
- const ModifierEvalContext *ctx,
- Mesh *mesh);
+Mesh *MOD_solidify_extrude_modifyMesh(ModifierData *md,
+ const ModifierEvalContext *ctx,
+ Mesh *mesh);
/* MOD_solidify_nonmanifold.c */
-Mesh *MOD_solidify_nonmanifold_applyModifier(ModifierData *md,
- const ModifierEvalContext *ctx,
- Mesh *mesh);
+Mesh *MOD_solidify_nonmanifold_modifyMesh(ModifierData *md,
+ const ModifierEvalContext *ctx,
+ Mesh *mesh);
#endif /* __MOD_SOLIDIFY_UTIL_H__ */
diff --git a/source/blender/modifiers/intern/MOD_subsurf.c b/source/blender/modifiers/intern/MOD_subsurf.c
index b3bc5a66e8c..e054e3478ea 100644
--- a/source/blender/modifiers/intern/MOD_subsurf.c
+++ b/source/blender/modifiers/intern/MOD_subsurf.c
@@ -10,7 +10,7 @@
* 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,
+ * 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) 2005 by the Blender Foundation.
@@ -68,7 +68,7 @@ static void copyData(const ModifierData *md, ModifierData *target, const int fla
#endif
SubsurfModifierData *tsmd = (SubsurfModifierData *)target;
- modifier_copyData_generic(md, target, flag);
+ BKE_modifier_copydata_generic(md, target, flag);
tsmd->emCache = tsmd->mCache = NULL;
}
@@ -206,11 +206,11 @@ static SubsurfRuntimeData *subsurf_ensure_runtime(SubsurfModifierData *smd)
/* Modifier itself. */
-static Mesh *applyModifier(ModifierData *md, const ModifierEvalContext *ctx, Mesh *mesh)
+static Mesh *modifyMesh(ModifierData *md, const ModifierEvalContext *ctx, Mesh *mesh)
{
Mesh *result = mesh;
#if !defined(WITH_OPENSUBDIV)
- modifier_setError(md, "Disabled, built without OpenSubdiv");
+ BKE_modifier_set_error(md, "Disabled, built without OpenSubdiv");
return result;
#endif
SubsurfModifierData *smd = (SubsurfModifierData *)md;
@@ -249,7 +249,7 @@ static void deformMatrices(ModifierData *md,
int num_verts)
{
#if !defined(WITH_OPENSUBDIV)
- modifier_setError(md, "Disabled, built without OpenSubdiv");
+ BKE_modifier_set_error(md, "Disabled, built without OpenSubdiv");
return;
#endif
@@ -290,7 +290,10 @@ ModifierTypeInfo modifierType_Subsurf = {
/* deformMatrices */ deformMatrices,
/* deformVertsEM */ NULL,
/* deformMatricesEM */ NULL,
- /* applyModifier */ applyModifier,
+ /* modifyMesh */ modifyMesh,
+ /* modifyHair */ NULL,
+ /* modifyPointCloud */ NULL,
+ /* modifyVolume */ NULL,
/* initData */ initData,
/* requiredDataMask */ NULL,
diff --git a/source/blender/modifiers/intern/MOD_surface.c b/source/blender/modifiers/intern/MOD_surface.c
index 0e318e9b092..b7449cbe91c 100644
--- a/source/blender/modifiers/intern/MOD_surface.c
+++ b/source/blender/modifiers/intern/MOD_surface.c
@@ -10,7 +10,7 @@
* 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,
+ * 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) 2005 by the Blender Foundation.
@@ -56,7 +56,7 @@ static void copyData(const ModifierData *md_src, ModifierData *md_dst, const int
{
SurfaceModifierData *surmd_dst = (SurfaceModifierData *)md_dst;
- modifier_copyData_generic(md_src, md_dst, flag);
+ BKE_modifier_copydata_generic(md_src, md_dst, flag);
surmd_dst->bvhtree = NULL;
surmd_dst->mesh = NULL;
@@ -196,7 +196,10 @@ ModifierTypeInfo modifierType_Surface = {
/* deformMatrices */ NULL,
/* deformVertsEM */ NULL,
/* deformMatricesEM */ NULL,
- /* applyModifier */ NULL,
+ /* modifyMesh */ NULL,
+ /* modifyHair */ NULL,
+ /* modifyPointCloud */ NULL,
+ /* modifyVolume */ NULL,
/* initData */ initData,
/* requiredDataMask */ NULL,
diff --git a/source/blender/modifiers/intern/MOD_surfacedeform.c b/source/blender/modifiers/intern/MOD_surfacedeform.c
index 57e7e2fa98b..4169c76272e 100644
--- a/source/blender/modifiers/intern/MOD_surfacedeform.c
+++ b/source/blender/modifiers/intern/MOD_surfacedeform.c
@@ -10,7 +10,7 @@
* 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,
+ * along with this program; if not, write to the Free Software Foundation,
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*
* Copyright 2017, Blender Foundation.
@@ -36,6 +36,8 @@
#include "BKE_mesh_runtime.h"
#include "BKE_modifier.h"
+#include "BKE_deform.h"
+
#include "DEG_depsgraph.h"
#include "DEG_depsgraph_query.h"
@@ -110,6 +112,8 @@ typedef struct SDefDeformData {
const SDefVert *const bind_verts;
float (*const targetCos)[3];
float (*const vertexCos)[3];
+ float *const weights;
+ float const strength;
} SDefDeformData;
/* Bind result values */
@@ -136,6 +140,19 @@ static void initData(ModifierData *md)
smd->verts = NULL;
smd->flags = 0;
smd->falloff = 4.0f;
+ smd->strength = 1.0f;
+}
+
+static void requiredDataMask(Object *UNUSED(ob),
+ ModifierData *md,
+ CustomData_MeshMasks *r_cddata_masks)
+{
+ SurfaceDeformModifierData *smd = (SurfaceDeformModifierData *)md;
+
+ /* Ask for vertex groups if we need them. */
+ if (smd->defgrp_name[0] != '\0') {
+ r_cddata_masks->vmask |= CD_MASK_MDEFORMVERT;
+ }
}
static void freeData(ModifierData *md)
@@ -163,7 +180,7 @@ static void copyData(const ModifierData *md, ModifierData *target, const int fla
const SurfaceDeformModifierData *smd = (const SurfaceDeformModifierData *)md;
SurfaceDeformModifierData *tsmd = (SurfaceDeformModifierData *)target;
- modifier_copyData_generic(md, target, flag);
+ BKE_modifier_copydata_generic(md, target, flag);
if (smd->verts) {
tsmd->verts = MEM_dupallocN(smd->verts);
@@ -1000,20 +1017,20 @@ static bool surfacedeformBind(SurfaceDeformModifierData *smd_orig,
vert_edges = MEM_calloc_arrayN(tnumverts, sizeof(*vert_edges), "SDefVertEdgeMap");
if (vert_edges == NULL) {
- modifier_setError((ModifierData *)smd_eval, "Out of memory");
+ BKE_modifier_set_error((ModifierData *)smd_eval, "Out of memory");
return false;
}
adj_array = MEM_malloc_arrayN(tnumedges, 2 * sizeof(*adj_array), "SDefVertEdge");
if (adj_array == NULL) {
- modifier_setError((ModifierData *)smd_eval, "Out of memory");
+ BKE_modifier_set_error((ModifierData *)smd_eval, "Out of memory");
MEM_freeN(vert_edges);
return false;
}
edge_polys = MEM_calloc_arrayN(tnumedges, sizeof(*edge_polys), "SDefEdgeFaceMap");
if (edge_polys == NULL) {
- modifier_setError((ModifierData *)smd_eval, "Out of memory");
+ BKE_modifier_set_error((ModifierData *)smd_eval, "Out of memory");
MEM_freeN(vert_edges);
MEM_freeN(adj_array);
return false;
@@ -1021,14 +1038,14 @@ static bool surfacedeformBind(SurfaceDeformModifierData *smd_orig,
smd_orig->verts = MEM_malloc_arrayN(numverts, sizeof(*smd_orig->verts), "SDefBindVerts");
if (smd_orig->verts == NULL) {
- modifier_setError((ModifierData *)smd_eval, "Out of memory");
+ BKE_modifier_set_error((ModifierData *)smd_eval, "Out of memory");
freeAdjacencyMap(vert_edges, adj_array, edge_polys);
return false;
}
BKE_bvhtree_from_mesh_get(&treeData, target, BVHTREE_FROM_LOOPTRI, 2);
if (treeData.tree == NULL) {
- modifier_setError((ModifierData *)smd_eval, "Out of memory");
+ BKE_modifier_set_error((ModifierData *)smd_eval, "Out of memory");
freeAdjacencyMap(vert_edges, adj_array, edge_polys);
MEM_freeN(smd_orig->verts);
smd_orig->verts = NULL;
@@ -1039,7 +1056,8 @@ static bool surfacedeformBind(SurfaceDeformModifierData *smd_orig,
mpoly, medge, mloop, tnumpoly, tnumedges, vert_edges, adj_array, edge_polys);
if (adj_result == MOD_SDEF_BIND_RESULT_NONMANY_ERR) {
- modifier_setError((ModifierData *)smd_eval, "Target has edges with more than two polygons");
+ BKE_modifier_set_error((ModifierData *)smd_eval,
+ "Target has edges with more than two polygons");
freeAdjacencyMap(vert_edges, adj_array, edge_polys);
free_bvhtree_from_mesh(&treeData);
MEM_freeN(smd_orig->verts);
@@ -1066,7 +1084,7 @@ static bool surfacedeformBind(SurfaceDeformModifierData *smd_orig,
};
if (data.targetCos == NULL) {
- modifier_setError((ModifierData *)smd_eval, "Out of memory");
+ BKE_modifier_set_error((ModifierData *)smd_eval, "Out of memory");
freeData((ModifierData *)smd_orig);
return false;
}
@@ -1085,19 +1103,20 @@ static bool surfacedeformBind(SurfaceDeformModifierData *smd_orig,
MEM_freeN(data.targetCos);
if (data.success == MOD_SDEF_BIND_RESULT_MEM_ERR) {
- modifier_setError((ModifierData *)smd_eval, "Out of memory");
+ BKE_modifier_set_error((ModifierData *)smd_eval, "Out of memory");
freeData((ModifierData *)smd_orig);
}
else if (data.success == MOD_SDEF_BIND_RESULT_NONMANY_ERR) {
- modifier_setError((ModifierData *)smd_eval, "Target has edges with more than two polygons");
+ BKE_modifier_set_error((ModifierData *)smd_eval,
+ "Target has edges with more than two polygons");
freeData((ModifierData *)smd_orig);
}
else if (data.success == MOD_SDEF_BIND_RESULT_CONCAVE_ERR) {
- modifier_setError((ModifierData *)smd_eval, "Target contains concave polygons");
+ BKE_modifier_set_error((ModifierData *)smd_eval, "Target contains concave polygons");
freeData((ModifierData *)smd_orig);
}
else if (data.success == MOD_SDEF_BIND_RESULT_OVERLAP_ERR) {
- modifier_setError((ModifierData *)smd_eval, "Target contains overlapping verts");
+ BKE_modifier_set_error((ModifierData *)smd_eval, "Target contains overlapping verts");
freeData((ModifierData *)smd_orig);
}
else if (data.success == MOD_SDEF_BIND_RESULT_GENERIC_ERR) {
@@ -1105,7 +1124,7 @@ static bool surfacedeformBind(SurfaceDeformModifierData *smd_orig,
* to explain this with a reasonably sized message.
* Though it shouldn't really matter all that much,
* because this is very unlikely to occur */
- modifier_setError((ModifierData *)smd_eval, "Target contains invalid polygons");
+ BKE_modifier_set_error((ModifierData *)smd_eval, "Target contains invalid polygons");
freeData((ModifierData *)smd_orig);
}
@@ -1123,9 +1142,16 @@ static void deformVert(void *__restrict userdata,
const SDefBind *sdbind = data->bind_verts[index].binds;
const int num_binds = data->bind_verts[index].numbinds;
float *const vertexCos = data->vertexCos[index];
- float norm[3], temp[3];
+ float norm[3], temp[3], offset[3];
+ const float weight = (data->weights != NULL) ? data->weights[index] : 1.0f;
- zero_v3(vertexCos);
+ /* Check if this vertex will be deformed. If it is not deformed we return and avoid
+ * unnecessary calculations. */
+ if (weight == 0.0f) {
+ return;
+ }
+
+ zero_v3(offset);
/* Allocate a `coords_buffer` that fits all the temp-data. */
int max_verts = 0;
@@ -1170,8 +1196,13 @@ static void deformVert(void *__restrict userdata,
/* Apply normal offset (generic for all modes) */
madd_v3_v3fl(temp, norm, sdbind->normal_dist);
- madd_v3_v3fl(vertexCos, temp, sdbind->influence);
+ madd_v3_v3fl(offset, temp, sdbind->influence);
}
+ /* Subtract the vertex coord to get the deformation offset. */
+ sub_v3_v3(offset, vertexCos);
+
+ /* Add the offset to start coord multiplied by the strength and weight values. */
+ madd_v3_v3fl(vertexCos, offset, data->strength * weight);
MEM_freeN(coords_buffer);
}
@@ -1179,7 +1210,8 @@ static void surfacedeformModifier_do(ModifierData *md,
const ModifierEvalContext *ctx,
float (*vertexCos)[3],
uint numverts,
- Object *ob)
+ Object *ob,
+ Mesh *mesh)
{
SurfaceDeformModifierData *smd = (SurfaceDeformModifierData *)md;
Mesh *target;
@@ -1189,10 +1221,10 @@ static void surfacedeformModifier_do(ModifierData *md,
if (!(smd->flags & MOD_SDEF_BIND)) {
if (smd->verts != NULL) {
if (!DEG_is_active(ctx->depsgraph)) {
- modifier_setError(md, "Attempt to bind from inactive dependency graph");
+ BKE_modifier_set_error(md, "Attempt to bind from inactive dependency graph");
return;
}
- ModifierData *md_orig = modifier_get_original(md);
+ ModifierData *md_orig = BKE_modifier_get_original(md);
freeData(md_orig);
}
return;
@@ -1201,7 +1233,7 @@ static void surfacedeformModifier_do(ModifierData *md,
Object *ob_target = smd->target;
target = BKE_modifier_get_evaluated_mesh_from_evaluated_object(ob_target, false);
if (!target) {
- modifier_setError(md, "No valid target mesh");
+ BKE_modifier_set_error(md, "No valid target mesh");
return;
}
@@ -1211,11 +1243,12 @@ static void surfacedeformModifier_do(ModifierData *md,
/* If not bound, execute bind. */
if (smd->verts == NULL) {
if (!DEG_is_active(ctx->depsgraph)) {
- modifier_setError(md, "Attempt to unbind from inactive dependency graph");
+ BKE_modifier_set_error(md, "Attempt to unbind from inactive dependency graph");
return;
}
- SurfaceDeformModifierData *smd_orig = (SurfaceDeformModifierData *)modifier_get_original(md);
+ SurfaceDeformModifierData *smd_orig = (SurfaceDeformModifierData *)BKE_modifier_get_original(
+ md);
float tmp_mat[4][4];
invert_m4_m4(tmp_mat, ob->obmat);
@@ -1230,19 +1263,52 @@ static void surfacedeformModifier_do(ModifierData *md,
/* Poly count checks */
if (smd->numverts != numverts) {
- modifier_setError(md, "Verts changed from %u to %u", smd->numverts, numverts);
+ BKE_modifier_set_error(md, "Verts changed from %u to %u", smd->numverts, numverts);
return;
}
else if (smd->numpoly != tnumpoly) {
- modifier_setError(md, "Target polygons changed from %u to %u", smd->numpoly, tnumpoly);
+ BKE_modifier_set_error(md, "Target polygons changed from %u to %u", smd->numpoly, tnumpoly);
+ return;
+ }
+
+ /* Early out if modifier would not affect input at all - still *after* the sanity checks (and
+ * potential binding) above.
+ */
+ if (smd->strength == 0.0f) {
return;
}
+ int defgrp_index;
+ MDeformVert *dvert;
+ MOD_get_vgroup(ob, mesh, smd->defgrp_name, &dvert, &defgrp_index);
+ float *weights = NULL;
+ const bool invert_group = (smd->flags & MOD_SDEF_INVERT_VGROUP) != 0;
+
+ if (defgrp_index != -1) {
+ dvert = CustomData_duplicate_referenced_layer(&mesh->vdata, CD_MDEFORMVERT, mesh->totvert);
+ /* If no vertices were ever added to an object's vgroup, dvert might be NULL. */
+ if (dvert == NULL) {
+ /* Add a valid data layer! */
+ dvert = CustomData_add_layer(&mesh->vdata, CD_MDEFORMVERT, CD_CALLOC, NULL, mesh->totvert);
+ }
+
+ if (dvert) {
+ weights = MEM_calloc_arrayN((size_t)numverts, sizeof(*weights), __func__);
+ MDeformVert *dv = dvert;
+ for (uint i = 0; i < numverts; i++, dv++) {
+ weights[i] = invert_group ? (1.0f - BKE_defvert_find_weight(dv, defgrp_index)) :
+ BKE_defvert_find_weight(dv, defgrp_index);
+ }
+ }
+ }
+
/* Actual vertex location update starts here */
SDefDeformData data = {
.bind_verts = smd->verts,
.targetCos = MEM_malloc_arrayN(tnumverts, sizeof(float[3]), "SDefTargetVertArray"),
.vertexCos = vertexCos,
+ .weights = weights,
+ .strength = smd->strength,
};
if (data.targetCos != NULL) {
@@ -1259,25 +1325,51 @@ static void surfacedeformModifier_do(ModifierData *md,
MEM_freeN(data.targetCos);
}
+
+ MEM_SAFE_FREE(weights);
}
static void deformVerts(ModifierData *md,
const ModifierEvalContext *ctx,
- Mesh *UNUSED(mesh),
+ Mesh *mesh,
float (*vertexCos)[3],
int numVerts)
{
- surfacedeformModifier_do(md, ctx, vertexCos, numVerts, ctx->object);
+ SurfaceDeformModifierData *smd = (SurfaceDeformModifierData *)md;
+ Mesh *mesh_src = NULL;
+
+ if (smd->defgrp_name[0] != '\0') {
+ /* Only need to use mesh_src when a vgroup is used. */
+ mesh_src = MOD_deform_mesh_eval_get(ctx->object, NULL, mesh, NULL, numVerts, false, false);
+ }
+
+ surfacedeformModifier_do(md, ctx, vertexCos, numVerts, ctx->object, mesh_src);
+
+ if (!ELEM(mesh_src, NULL, mesh)) {
+ BKE_id_free(NULL, mesh_src);
+ }
}
static void deformVertsEM(ModifierData *md,
const ModifierEvalContext *ctx,
- struct BMEditMesh *UNUSED(editData),
- Mesh *UNUSED(mesh),
+ struct BMEditMesh *em,
+ Mesh *mesh,
float (*vertexCos)[3],
int numVerts)
{
- surfacedeformModifier_do(md, ctx, vertexCos, numVerts, ctx->object);
+ SurfaceDeformModifierData *smd = (SurfaceDeformModifierData *)md;
+ Mesh *mesh_src = NULL;
+
+ if (smd->defgrp_name[0] != '\0') {
+ /* Only need to use mesh_src when a vgroup is used. */
+ mesh_src = MOD_deform_mesh_eval_get(ctx->object, em, mesh, NULL, numVerts, false, false);
+ }
+
+ surfacedeformModifier_do(md, ctx, vertexCos, numVerts, ctx->object, mesh_src);
+
+ if (!ELEM(mesh_src, NULL, mesh)) {
+ BKE_id_free(NULL, mesh_src);
+ }
}
static bool isDisabled(const Scene *UNUSED(scene), ModifierData *md, bool UNUSED(useRenderParams))
@@ -1306,10 +1398,13 @@ ModifierTypeInfo modifierType_SurfaceDeform = {
/* deformMatrices */ NULL,
/* deformVertsEM */ deformVertsEM,
/* deformMatricesEM */ NULL,
- /* applyModifier */ NULL,
+ /* modifyMesh */ NULL,
+ /* modifyHair */ NULL,
+ /* modifyPointCloud */ NULL,
+ /* modifyVolume */ NULL,
/* initData */ initData,
- /* requiredDataMask */ NULL,
+ /* requiredDataMask */ requiredDataMask,
/* freeData */ freeData,
/* isDisabled */ isDisabled,
/* updateDepsgraph */ updateDepsgraph,
diff --git a/source/blender/modifiers/intern/MOD_triangulate.c b/source/blender/modifiers/intern/MOD_triangulate.c
index 1e6bc2e1819..bb88bda6394 100644
--- a/source/blender/modifiers/intern/MOD_triangulate.c
+++ b/source/blender/modifiers/intern/MOD_triangulate.c
@@ -10,7 +10,7 @@
* 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,
+ * along with this program; if not, write to the Free Software Foundation,
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
@@ -103,7 +103,7 @@ static void initData(ModifierData *md)
tmd->min_vertices = 4;
}
-static Mesh *applyModifier(ModifierData *md, const ModifierEvalContext *UNUSED(ctx), Mesh *mesh)
+static Mesh *modifyMesh(ModifierData *md, const ModifierEvalContext *UNUSED(ctx), Mesh *mesh)
{
TriangulateModifierData *tmd = (TriangulateModifierData *)md;
Mesh *result;
@@ -124,13 +124,16 @@ ModifierTypeInfo modifierType_Triangulate = {
eModifierTypeFlag_SupportsMapping | eModifierTypeFlag_EnableInEditmode |
eModifierTypeFlag_AcceptsCVs,
- /* copyData */ modifier_copyData_generic,
+ /* copyData */ BKE_modifier_copydata_generic,
/* deformVerts */ NULL,
/* deformMatrices */ NULL,
/* deformVertsEM */ NULL,
/* deformMatricesEM */ NULL,
- /* applyModifier */ applyModifier,
+ /* modifyMesh */ modifyMesh,
+ /* modifyHair */ NULL,
+ /* modifyPointCloud */ NULL,
+ /* modifyVolume */ NULL,
/* initData */ initData,
/* requiredDataMask */ NULL, // requiredDataMask,
diff --git a/source/blender/modifiers/intern/MOD_util.c b/source/blender/modifiers/intern/MOD_util.c
index c0014a2c0cd..4999c77c355 100644
--- a/source/blender/modifiers/intern/MOD_util.c
+++ b/source/blender/modifiers/intern/MOD_util.c
@@ -36,6 +36,7 @@
#include "DNA_object_types.h"
#include "DNA_scene_types.h"
+#include "BKE_action.h" /* BKE_pose_channel_find_name */
#include "BKE_deform.h"
#include "BKE_editmesh.h"
#include "BKE_image.h"
@@ -81,12 +82,25 @@ void MOD_get_texture_coords(MappingInfoModifierData *dmd,
const int numVerts = mesh->totvert;
int i;
int texmapping = dmd->texmapping;
- float mapob_imat[4][4];
+ float mapref_imat[4][4];
if (texmapping == MOD_DISP_MAP_OBJECT) {
if (dmd->map_object != NULL) {
Object *map_object = dmd->map_object;
- invert_m4_m4(mapob_imat, map_object->obmat);
+ if (dmd->map_bone[0] != '\0') {
+ bPoseChannel *pchan = BKE_pose_channel_find_name(map_object->pose, dmd->map_bone);
+ if (pchan) {
+ float mat_bone_world[4][4];
+ mul_m4_m4m4(mat_bone_world, map_object->obmat, pchan->pose_mat);
+ invert_m4_m4(mapref_imat, mat_bone_world);
+ }
+ else {
+ invert_m4_m4(mapref_imat, map_object->obmat);
+ }
+ }
+ else {
+ invert_m4_m4(mapref_imat, map_object->obmat);
+ }
}
else { /* if there is no map object, default to local */
texmapping = MOD_DISP_MAP_LOCAL;
@@ -145,7 +159,7 @@ void MOD_get_texture_coords(MappingInfoModifierData *dmd,
break;
case MOD_DISP_MAP_OBJECT:
mul_v3_m4v3(*r_texco, ob->obmat, cos != NULL ? *cos : mv->co);
- mul_m4_v3(mapob_imat, *r_texco);
+ mul_m4_v3(mapref_imat, *r_texco);
break;
}
if (cos != NULL) {
@@ -182,7 +196,7 @@ Mesh *MOD_deform_mesh_eval_get(Object *ob,
}
else if (ob->type == OB_MESH) {
if (em) {
- mesh = BKE_mesh_from_bmesh_for_eval_nomain(em->bm, NULL, ob->data);
+ mesh = BKE_mesh_wrapper_from_editmesh_with_coords(em, NULL, vertexCos, ob->data);
}
else {
/* TODO(sybren): after modifier conversion of DM to Mesh is done, check whether
@@ -195,9 +209,12 @@ Mesh *MOD_deform_mesh_eval_get(Object *ob,
mesh->runtime.deformed_only = 1;
}
+ if (em != NULL) {
+ /* pass */
+ }
/* TODO(sybren): after modifier conversion of DM to Mesh is done, check whether
* we really need vertexCos here. */
- if (vertexCos) {
+ else if (vertexCos) {
BKE_mesh_vert_coords_apply(mesh, vertexCos);
mesh->runtime.cd_dirty_vert |= CD_MASK_NORMAL;
}
@@ -227,7 +244,9 @@ Mesh *MOD_deform_mesh_eval_get(Object *ob,
}
}
- BLI_assert(mesh == NULL || mesh->totvert == num_verts);
+ if (mesh && mesh->runtime.wrapper_type == ME_WRAPPER_TYPE_MDATA) {
+ BLI_assert(mesh->totvert == num_verts);
+ }
return mesh;
}
@@ -248,6 +267,22 @@ void MOD_get_vgroup(
}
}
+void MOD_depsgraph_update_object_bone_relation(struct DepsNodeHandle *node,
+ Object *object,
+ const char *bonename,
+ const char *description)
+{
+ if (object == NULL) {
+ return;
+ }
+ if (bonename[0] != '\0' && object->type == OB_ARMATURE) {
+ DEG_add_object_relation(node, object, DEG_OB_COMP_EVAL_POSE, description);
+ }
+ else {
+ DEG_add_object_relation(node, object, DEG_OB_COMP_TRANSFORM, description);
+ }
+}
+
/* only called by BKE_modifier.h/modifier.c */
void modifier_type_init(ModifierTypeInfo *types[])
{
@@ -307,5 +342,6 @@ void modifier_type_init(ModifierTypeInfo *types[])
INIT_TYPE(MeshSequenceCache);
INIT_TYPE(SurfaceDeform);
INIT_TYPE(WeightedNormal);
+ INIT_TYPE(Simulation);
#undef INIT_TYPE
}
diff --git a/source/blender/modifiers/intern/MOD_util.h b/source/blender/modifiers/intern/MOD_util.h
index e1991de3bb8..38e2083082d 100644
--- a/source/blender/modifiers/intern/MOD_util.h
+++ b/source/blender/modifiers/intern/MOD_util.h
@@ -56,4 +56,8 @@ void MOD_get_vgroup(struct Object *ob,
struct MDeformVert **dvert,
int *defgrp_index);
+void MOD_depsgraph_update_object_bone_relation(struct DepsNodeHandle *node,
+ struct Object *object,
+ const char *bonename,
+ const char *description);
#endif /* __MOD_UTIL_H__ */
diff --git a/source/blender/modifiers/intern/MOD_uvproject.c b/source/blender/modifiers/intern/MOD_uvproject.c
index 242f31b6434..580a065f35e 100644
--- a/source/blender/modifiers/intern/MOD_uvproject.c
+++ b/source/blender/modifiers/intern/MOD_uvproject.c
@@ -10,7 +10,7 @@
* 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,
+ * 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) 2005 by the Blender Foundation.
@@ -303,7 +303,7 @@ static Mesh *uvprojectModifier_do(UVProjectModifierData *umd,
return mesh;
}
-static Mesh *applyModifier(ModifierData *md, const ModifierEvalContext *ctx, Mesh *mesh)
+static Mesh *modifyMesh(ModifierData *md, const ModifierEvalContext *ctx, Mesh *mesh)
{
Mesh *result;
UVProjectModifierData *umd = (UVProjectModifierData *)md;
@@ -321,13 +321,16 @@ ModifierTypeInfo modifierType_UVProject = {
/* flags */ eModifierTypeFlag_AcceptsMesh | eModifierTypeFlag_SupportsMapping |
eModifierTypeFlag_SupportsEditmode | eModifierTypeFlag_EnableInEditmode,
- /* copyData */ modifier_copyData_generic,
+ /* copyData */ BKE_modifier_copydata_generic,
/* deformVerts */ NULL,
/* deformMatrices */ NULL,
/* deformVertsEM */ NULL,
/* deformMatricesEM */ NULL,
- /* applyModifier */ applyModifier,
+ /* modifyMesh */ modifyMesh,
+ /* modifyHair */ NULL,
+ /* modifyPointCloud */ NULL,
+ /* modifyVolume */ NULL,
/* initData */ initData,
/* requiredDataMask */ requiredDataMask,
diff --git a/source/blender/modifiers/intern/MOD_uvwarp.c b/source/blender/modifiers/intern/MOD_uvwarp.c
index 46298c0e00d..4ece36d82a4 100644
--- a/source/blender/modifiers/intern/MOD_uvwarp.c
+++ b/source/blender/modifiers/intern/MOD_uvwarp.c
@@ -10,7 +10,7 @@
* 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,
+ * along with this program; if not, write to the Free Software Foundation,
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
@@ -126,7 +126,7 @@ static void uv_warp_compute(void *__restrict userdata,
}
}
-static Mesh *applyModifier(ModifierData *md, const ModifierEvalContext *ctx, Mesh *mesh)
+static Mesh *modifyMesh(ModifierData *md, const ModifierEvalContext *ctx, Mesh *mesh)
{
UVWarpModifierData *umd = (UVWarpModifierData *)md;
int numPolys, numLoops;
@@ -233,26 +233,14 @@ static void foreachObjectLink(ModifierData *md, Object *ob, ObjectWalkFunc walk,
walk(userData, ob, &umd->object_src, IDWALK_CB_NOP);
}
-static void uv_warp_deps_object_bone_new(struct DepsNodeHandle *node,
- Object *object,
- const char *bonename)
-{
- if (object != NULL) {
- if (object->type == OB_ARMATURE && bonename[0]) {
- DEG_add_object_relation(node, object, DEG_OB_COMP_EVAL_POSE, "UVWarp Modifier");
- }
- else {
- DEG_add_object_relation(node, object, DEG_OB_COMP_TRANSFORM, "UVWarp Modifier");
- }
- }
-}
-
static void updateDepsgraph(ModifierData *md, const ModifierUpdateDepsgraphContext *ctx)
{
UVWarpModifierData *umd = (UVWarpModifierData *)md;
- uv_warp_deps_object_bone_new(ctx->node, umd->object_src, umd->bone_src);
- uv_warp_deps_object_bone_new(ctx->node, umd->object_dst, umd->bone_dst);
+ MOD_depsgraph_update_object_bone_relation(
+ ctx->node, umd->object_src, umd->bone_src, "UVWarp Modifier");
+ MOD_depsgraph_update_object_bone_relation(
+ ctx->node, umd->object_dst, umd->bone_dst, "UVWarp Modifier");
DEG_add_modifier_to_transform_relation(ctx->node, "UVWarp Modifier");
}
@@ -265,13 +253,16 @@ ModifierTypeInfo modifierType_UVWarp = {
/* flags */ eModifierTypeFlag_AcceptsMesh | eModifierTypeFlag_SupportsEditmode |
eModifierTypeFlag_EnableInEditmode,
- /* copyData */ modifier_copyData_generic,
+ /* copyData */ BKE_modifier_copydata_generic,
/* deformVerts */ NULL,
/* deformMatrices */ NULL,
/* deformVertsEM */ NULL,
/* deformMatricesEM */ NULL,
- /* applyModifier */ applyModifier,
+ /* modifyMesh */ modifyMesh,
+ /* modifyHair */ NULL,
+ /* modifyPointCloud */ NULL,
+ /* modifyVolume */ NULL,
/* initData */ initData,
/* requiredDataMask */ requiredDataMask,
diff --git a/source/blender/modifiers/intern/MOD_warp.c b/source/blender/modifiers/intern/MOD_warp.c
index 4a98afbb91c..692f0ca18f0 100644
--- a/source/blender/modifiers/intern/MOD_warp.c
+++ b/source/blender/modifiers/intern/MOD_warp.c
@@ -10,7 +10,7 @@
* 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,
+ * along with this program; if not, write to the Free Software Foundation,
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
@@ -30,6 +30,7 @@
#include "DNA_meshdata_types.h"
#include "DNA_object_types.h"
+#include "BKE_action.h" /* BKE_pose_channel_find_name */
#include "BKE_colortools.h"
#include "BKE_deform.h"
#include "BKE_editmesh.h"
@@ -63,7 +64,7 @@ static void copyData(const ModifierData *md, ModifierData *target, const int fla
const WarpModifierData *wmd = (const WarpModifierData *)md;
WarpModifierData *twmd = (WarpModifierData *)target;
- modifier_copyData_generic(md, target, flag);
+ BKE_modifier_copydata_generic(md, target, flag);
twmd->curfalloff = BKE_curvemapping_copy(wmd->curfalloff);
}
@@ -85,6 +86,22 @@ static void requiredDataMask(Object *UNUSED(ob),
}
}
+static void matrix_from_obj_pchan(float mat[4][4],
+ const float obinv[4][4],
+ Object *ob,
+ const char *bonename)
+{
+ bPoseChannel *pchan = BKE_pose_channel_find_name(ob->pose, bonename);
+ if (pchan) {
+ float mat_bone_world[4][4];
+ mul_m4_m4m4(mat_bone_world, ob->obmat, pchan->pose_mat);
+ mul_m4_m4m4(mat, obinv, mat_bone_world);
+ }
+ else {
+ mul_m4_m4m4(mat, obinv, ob->obmat);
+ }
+}
+
static bool dependsOnTime(ModifierData *md)
{
WarpModifierData *wmd = (WarpModifierData *)md;
@@ -138,18 +155,31 @@ static void foreachTexLink(ModifierData *md, Object *ob, TexWalkFunc walk, void
static void updateDepsgraph(ModifierData *md, const ModifierUpdateDepsgraphContext *ctx)
{
WarpModifierData *wmd = (WarpModifierData *)md;
+ bool need_transform_relation = false;
+
if (wmd->object_from != NULL && wmd->object_to != NULL) {
- DEG_add_modifier_to_transform_relation(ctx->node, "Warplace Modifier");
- DEG_add_object_relation(
- ctx->node, wmd->object_from, DEG_OB_COMP_TRANSFORM, "Warp Modifier from");
- DEG_add_object_relation(ctx->node, wmd->object_to, DEG_OB_COMP_TRANSFORM, "Warp Modifier to");
- }
- if ((wmd->texmapping == MOD_DISP_MAP_OBJECT) && wmd->map_object != NULL) {
- DEG_add_object_relation(
- ctx->node, wmd->map_object, DEG_OB_COMP_TRANSFORM, "Warp Modifier map");
+ MOD_depsgraph_update_object_bone_relation(
+ ctx->node, wmd->object_from, wmd->bone_from, "Warp Modifier");
+ MOD_depsgraph_update_object_bone_relation(
+ ctx->node, wmd->object_to, wmd->bone_to, "Warp Modifier");
+ need_transform_relation = true;
}
+
if (wmd->texture != NULL) {
DEG_add_generic_id_relation(ctx->node, &wmd->texture->id, "Warp Modifier");
+
+ if ((wmd->texmapping == MOD_DISP_MAP_OBJECT) && wmd->map_object != NULL) {
+ MOD_depsgraph_update_object_bone_relation(
+ ctx->node, wmd->map_object, wmd->map_bone, "Warp Modifier");
+ need_transform_relation = true;
+ }
+ else if (wmd->texmapping == MOD_DISP_MAP_GLOBAL) {
+ need_transform_relation = true;
+ }
+ }
+
+ if (need_transform_relation) {
+ DEG_add_modifier_to_transform_relation(ctx->node, "Warp Modifier");
}
}
@@ -197,8 +227,9 @@ static void warpModifier_do(WarpModifierData *wmd,
invert_m4_m4(obinv, ob->obmat);
- mul_m4_m4m4(mat_from, obinv, wmd->object_from->obmat);
- mul_m4_m4m4(mat_to, obinv, wmd->object_to->obmat);
+ /* Checks that the objects/bones are available. */
+ matrix_from_obj_pchan(mat_from, obinv, wmd->object_from, wmd->bone_from);
+ matrix_from_obj_pchan(mat_to, obinv, wmd->object_to, wmd->bone_to);
invert_m4_m4(tmat, mat_from); // swap?
mul_m4_m4m4(mat_final, tmat, mat_to);
@@ -350,6 +381,11 @@ static void deformVertsEM(ModifierData *md,
mesh_src = MOD_deform_mesh_eval_get(ctx->object, em, mesh, NULL, numVerts, false, false);
}
+ /* TODO(Campbell): use edit-mode data only (remove this line). */
+ if (mesh_src != NULL) {
+ BKE_mesh_wrapper_ensure_mdata(mesh_src);
+ }
+
warpModifier_do(wmd, ctx, mesh_src, vertexCos, numVerts);
if (!ELEM(mesh_src, NULL, mesh)) {
@@ -362,7 +398,7 @@ ModifierTypeInfo modifierType_Warp = {
/* structName */ "WarpModifierData",
/* structSize */ sizeof(WarpModifierData),
/* type */ eModifierTypeType_OnlyDeform,
- /* flags */ eModifierTypeFlag_AcceptsCVs | eModifierTypeFlag_AcceptsLattice |
+ /* flags */ eModifierTypeFlag_AcceptsCVs | eModifierTypeFlag_AcceptsVertexCosOnly |
eModifierTypeFlag_SupportsEditmode,
/* copyData */ copyData,
@@ -370,7 +406,10 @@ ModifierTypeInfo modifierType_Warp = {
/* deformMatrices */ NULL,
/* deformVertsEM */ deformVertsEM,
/* deformMatricesEM */ NULL,
- /* applyModifier */ NULL,
+ /* modifyMesh */ NULL,
+ /* modifyHair */ NULL,
+ /* modifyPointCloud */ NULL,
+ /* modifyVolume */ NULL,
/* initData */ initData,
/* requiredDataMask */ requiredDataMask,
diff --git a/source/blender/modifiers/intern/MOD_wave.c b/source/blender/modifiers/intern/MOD_wave.c
index 56b2a81fdb1..90d9f451f75 100644
--- a/source/blender/modifiers/intern/MOD_wave.c
+++ b/source/blender/modifiers/intern/MOD_wave.c
@@ -10,7 +10,7 @@
* 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,
+ * 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) 2005 by the Blender Foundation.
@@ -98,17 +98,28 @@ static void foreachTexLink(ModifierData *md, Object *ob, TexWalkFunc walk, void
static void updateDepsgraph(ModifierData *md, const ModifierUpdateDepsgraphContext *ctx)
{
WaveModifierData *wmd = (WaveModifierData *)md;
+ bool need_transform_relation = false;
+
if (wmd->objectcenter != NULL) {
DEG_add_object_relation(ctx->node, wmd->objectcenter, DEG_OB_COMP_TRANSFORM, "Wave Modifier");
+ need_transform_relation = true;
}
- if (wmd->map_object != NULL) {
- DEG_add_object_relation(ctx->node, wmd->map_object, DEG_OB_COMP_TRANSFORM, "Wave Modifier");
- }
- if (wmd->objectcenter != NULL || wmd->map_object != NULL) {
- DEG_add_modifier_to_transform_relation(ctx->node, "Wave Modifier");
- }
+
if (wmd->texture != NULL) {
DEG_add_generic_id_relation(ctx->node, &wmd->texture->id, "Wave Modifier");
+
+ if ((wmd->texmapping == MOD_DISP_MAP_OBJECT) && wmd->map_object != NULL) {
+ MOD_depsgraph_update_object_bone_relation(
+ ctx->node, wmd->map_object, wmd->map_bone, "Wave Modifier");
+ need_transform_relation = true;
+ }
+ else if (wmd->texmapping == MOD_DISP_MAP_GLOBAL) {
+ need_transform_relation = true;
+ }
+ }
+
+ if (need_transform_relation) {
+ DEG_add_modifier_to_transform_relation(ctx->node, "Wave Modifier");
}
}
@@ -342,6 +353,11 @@ static void deformVertsEM(ModifierData *md,
mesh_src = MOD_deform_mesh_eval_get(ctx->object, editData, mesh, NULL, numVerts, false, false);
}
+ /* TODO(Campbell): use edit-mode data only (remove this line). */
+ if (mesh_src != NULL) {
+ BKE_mesh_wrapper_ensure_mdata(mesh_src);
+ }
+
waveModifier_do(wmd, ctx, ctx->object, mesh_src, vertexCos, numVerts);
if (!ELEM(mesh_src, NULL, mesh)) {
@@ -354,16 +370,19 @@ ModifierTypeInfo modifierType_Wave = {
/* structName */ "WaveModifierData",
/* structSize */ sizeof(WaveModifierData),
/* type */ eModifierTypeType_OnlyDeform,
- /* flags */ eModifierTypeFlag_AcceptsCVs | eModifierTypeFlag_AcceptsLattice |
+ /* flags */ eModifierTypeFlag_AcceptsCVs | eModifierTypeFlag_AcceptsVertexCosOnly |
eModifierTypeFlag_SupportsEditmode,
- /* copyData */ modifier_copyData_generic,
+ /* copyData */ BKE_modifier_copydata_generic,
/* deformVerts */ deformVerts,
/* deformMatrices */ NULL,
/* deformVertsEM */ deformVertsEM,
/* deformMatricesEM */ NULL,
- /* applyModifier */ NULL,
+ /* modifyMesh */ NULL,
+ /* modifyHair */ NULL,
+ /* modifyPointCloud */ NULL,
+ /* modifyVolume */ NULL,
/* initData */ initData,
/* requiredDataMask */ requiredDataMask,
diff --git a/source/blender/modifiers/intern/MOD_weighted_normal.c b/source/blender/modifiers/intern/MOD_weighted_normal.c
index 04b503e588b..3baf7c878dc 100644
--- a/source/blender/modifiers/intern/MOD_weighted_normal.c
+++ b/source/blender/modifiers/intern/MOD_weighted_normal.c
@@ -10,7 +10,7 @@
* 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,
+ * along with this program; if not, write to the Free Software Foundation,
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
@@ -546,7 +546,7 @@ static void wn_face_with_angle(WeightedNormalModifierData *wnmd, WeightedNormalD
apply_weights_vertex_normal(wnmd, wn_data);
}
-static Mesh *applyModifier(ModifierData *md, const ModifierEvalContext *ctx, Mesh *mesh)
+static Mesh *modifyMesh(ModifierData *md, const ModifierEvalContext *ctx, Mesh *mesh)
{
WeightedNormalModifierData *wnmd = (WeightedNormalModifierData *)md;
Object *ob = ctx->object;
@@ -562,7 +562,7 @@ static Mesh *applyModifier(ModifierData *md, const ModifierEvalContext *ctx, Mes
if (!(((Mesh *)ob->data)->flag & ME_AUTOSMOOTH))
#endif
{
- modifier_setError((ModifierData *)wnmd, "Enable 'Auto Smooth' in Object Data Properties");
+ BKE_modifier_set_error((ModifierData *)wnmd, "Enable 'Auto Smooth' in Object Data Properties");
return mesh;
}
@@ -708,13 +708,16 @@ ModifierTypeInfo modifierType_WeightedNormal = {
/* flags */ eModifierTypeFlag_AcceptsMesh | eModifierTypeFlag_SupportsMapping |
eModifierTypeFlag_SupportsEditmode | eModifierTypeFlag_EnableInEditmode,
- /* copyData */ modifier_copyData_generic,
+ /* copyData */ BKE_modifier_copydata_generic,
/* deformVerts */ NULL,
/* deformMatrices */ NULL,
/* deformVertsEM */ NULL,
/* deformMatricesEM */ NULL,
- /* applyModifier */ applyModifier,
+ /* modifyMesh */ modifyMesh,
+ /* modifyHair */ NULL,
+ /* modifyPointCloud */ NULL,
+ /* modifyVolume */ NULL,
/* initData */ initData,
/* requiredDataMask */ requiredDataMask,
diff --git a/source/blender/modifiers/intern/MOD_weightvg_util.c b/source/blender/modifiers/intern/MOD_weightvg_util.c
index 23e4da32ed7..1a38787777f 100644
--- a/source/blender/modifiers/intern/MOD_weightvg_util.c
+++ b/source/blender/modifiers/intern/MOD_weightvg_util.c
@@ -10,7 +10,7 @@
* 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,
+ * 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) 2011 by Bastien Montagne.
@@ -137,6 +137,7 @@ void weightvg_do_mask(const ModifierEvalContext *ctx,
const int tex_use_channel,
const int tex_mapping,
Object *tex_map_object,
+ const char *text_map_bone,
const char *tex_uvlayer_name,
const bool invert_vgroup_mask)
{
@@ -163,6 +164,7 @@ void weightvg_do_mask(const ModifierEvalContext *ctx,
*/
t_map.texture = texture;
t_map.map_object = tex_map_object;
+ BLI_strncpy(t_map.map_bone, text_map_bone, sizeof(t_map.map_bone));
BLI_strncpy(t_map.uvlayer_name, tex_uvlayer_name, sizeof(t_map.uvlayer_name));
t_map.texmapping = tex_mapping;
@@ -270,16 +272,45 @@ void weightvg_update_vg(MDeformVert *dvert,
const bool do_add,
const float add_thresh,
const bool do_rem,
- const float rem_thresh)
+ const float rem_thresh,
+ const bool do_normalize)
{
int i;
+ float min_w = weights[0];
+ float norm_fac = 1.0f;
+ if (do_normalize) {
+ float max_w = weights[0];
+ for (i = 1; i < num; i++) {
+ const float w = weights[i];
+
+ /* No need to clamp here, normalization will ensure we stay within [0.0, 1.0] range. */
+ if (w < min_w) {
+ min_w = w;
+ }
+ else if (w > max_w) {
+ max_w = w;
+ }
+ }
+
+ const float range = max_w - min_w;
+ if (fabsf(range) > FLT_EPSILON) {
+ norm_fac = 1.0f / range;
+ }
+ else {
+ min_w = 0.0f;
+ }
+ }
+
for (i = 0; i < num; i++) {
float w = weights[i];
MDeformVert *dv = &dvert[indices ? indices[i] : i];
MDeformWeight *dw = dws ? dws[i] :
((defgrp_idx >= 0) ? BKE_defvert_find_index(dv, defgrp_idx) : NULL);
+ if (do_normalize) {
+ w = (w - min_w) * norm_fac;
+ }
/* Never allow weights out of [0.0, 1.0] range. */
CLAMP(w, 0.0f, 1.0f);
diff --git a/source/blender/modifiers/intern/MOD_weightvg_util.h b/source/blender/modifiers/intern/MOD_weightvg_util.h
index bcd1076eac6..50597d43112 100644
--- a/source/blender/modifiers/intern/MOD_weightvg_util.h
+++ b/source/blender/modifiers/intern/MOD_weightvg_util.h
@@ -10,7 +10,7 @@
* 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,
+ * 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) 2011 by Bastien Montagne.
@@ -73,6 +73,7 @@ void weightvg_do_mask(const ModifierEvalContext *ctx,
const int tex_use_channel,
const int tex_mapping,
Object *tex_map_object,
+ const char *text_map_bone,
const char *tex_uvlayer_name,
const bool invert_vgroup_mask);
@@ -85,6 +86,7 @@ void weightvg_update_vg(struct MDeformVert *dvert,
const bool do_add,
const float add_thresh,
const bool do_rem,
- const float rem_thresh);
+ const float rem_thresh,
+ const bool do_normalize);
#endif /* __MOD_WEIGHTVG_UTIL_H__ */
diff --git a/source/blender/modifiers/intern/MOD_weightvgedit.c b/source/blender/modifiers/intern/MOD_weightvgedit.c
index ba1745f7b5e..8ce1aaee942 100644
--- a/source/blender/modifiers/intern/MOD_weightvgedit.c
+++ b/source/blender/modifiers/intern/MOD_weightvgedit.c
@@ -10,7 +10,7 @@
* 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,
+ * 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) 2011 by Bastien Montagne.
@@ -45,6 +45,7 @@
#include "MEM_guardedalloc.h"
#include "MOD_modifiertypes.h"
+#include "MOD_util.h"
#include "MOD_weightvg_util.h"
/**************************************
@@ -79,7 +80,7 @@ static void copyData(const ModifierData *md, ModifierData *target, const int fla
const WeightVGEditModifierData *wmd = (const WeightVGEditModifierData *)md;
WeightVGEditModifierData *twmd = (WeightVGEditModifierData *)target;
- modifier_copyData_generic(md, target, flag);
+ BKE_modifier_copydata_generic(md, target, flag);
twmd->cmap_curve = BKE_curvemapping_copy(wmd->cmap_curve);
}
@@ -134,16 +135,23 @@ static void foreachTexLink(ModifierData *md, Object *ob, TexWalkFunc walk, void
static void updateDepsgraph(ModifierData *md, const ModifierUpdateDepsgraphContext *ctx)
{
WeightVGEditModifierData *wmd = (WeightVGEditModifierData *)md;
- if (wmd->mask_tex_map_obj != NULL && wmd->mask_tex_mapping == MOD_DISP_MAP_OBJECT) {
- DEG_add_object_relation(
- ctx->node, wmd->mask_tex_map_obj, DEG_OB_COMP_TRANSFORM, "WeightVGEdit Modifier");
- DEG_add_modifier_to_transform_relation(ctx->node, "WeightVGEdit Modifier");
- }
- else if (wmd->mask_tex_mapping == MOD_DISP_MAP_GLOBAL) {
- DEG_add_modifier_to_transform_relation(ctx->node, "WeightVGEdit Modifier");
- }
+ bool need_transform_relation = false;
+
if (wmd->mask_texture != NULL) {
DEG_add_generic_id_relation(ctx->node, &wmd->mask_texture->id, "WeightVGEdit Modifier");
+
+ if (wmd->mask_tex_map_obj != NULL && wmd->mask_tex_mapping == MOD_DISP_MAP_OBJECT) {
+ MOD_depsgraph_update_object_bone_relation(
+ ctx->node, wmd->mask_tex_map_obj, wmd->mask_tex_map_bone, "WeightVGEdit Modifier");
+ need_transform_relation = true;
+ }
+ else if (wmd->mask_tex_mapping == MOD_DISP_MAP_GLOBAL) {
+ need_transform_relation = true;
+ }
+ }
+
+ if (need_transform_relation) {
+ DEG_add_modifier_to_transform_relation(ctx->node, "WeightVGEdit Modifier");
}
}
@@ -156,7 +164,7 @@ static bool isDisabled(const struct Scene *UNUSED(scene),
return (wmd->defgrp_name[0] == '\0');
}
-static Mesh *applyModifier(ModifierData *md, const ModifierEvalContext *ctx, Mesh *mesh)
+static Mesh *modifyMesh(ModifierData *md, const ModifierEvalContext *ctx, Mesh *mesh)
{
BLI_assert(mesh != NULL);
@@ -231,6 +239,7 @@ static Mesh *applyModifier(ModifierData *md, const ModifierEvalContext *ctx, Mes
/* Do mapping. */
const bool do_invert_mapping = (wmd->edit_flags & MOD_WVG_INVERT_FALLOFF) != 0;
+ const bool do_normalize = (wmd->edit_flags & MOD_WVG_EDIT_WEIGHTS_NORMALIZE) != 0;
if (do_invert_mapping || wmd->falloff_type != MOD_WVG_MAPPING_NONE) {
RNG *rng = NULL;
@@ -261,6 +270,7 @@ static Mesh *applyModifier(ModifierData *md, const ModifierEvalContext *ctx, Mes
wmd->mask_tex_use_channel,
wmd->mask_tex_mapping,
wmd->mask_tex_map_obj,
+ wmd->mask_tex_map_bone,
wmd->mask_tex_uvlayer_name,
invert_vgroup_mask);
@@ -274,7 +284,8 @@ static Mesh *applyModifier(ModifierData *md, const ModifierEvalContext *ctx, Mes
do_add,
wmd->add_threshold,
do_rem,
- wmd->rem_threshold);
+ wmd->rem_threshold,
+ do_normalize);
/* If weight preview enabled... */
#if 0 /* XXX Currently done in mod stack :/ */
@@ -306,7 +317,10 @@ ModifierTypeInfo modifierType_WeightVGEdit = {
/* deformMatrices */ NULL,
/* deformVertsEM */ NULL,
/* deformMatricesEM */ NULL,
- /* applyModifier */ applyModifier,
+ /* modifyMesh */ modifyMesh,
+ /* modifyHair */ NULL,
+ /* modifyPointCloud */ NULL,
+ /* modifyVolume */ NULL,
/* initData */ initData,
/* requiredDataMask */ requiredDataMask,
diff --git a/source/blender/modifiers/intern/MOD_weightvgmix.c b/source/blender/modifiers/intern/MOD_weightvgmix.c
index 4984853d41e..a71b1d9d0e8 100644
--- a/source/blender/modifiers/intern/MOD_weightvgmix.c
+++ b/source/blender/modifiers/intern/MOD_weightvgmix.c
@@ -10,7 +10,7 @@
* 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,
+ * 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) 2011 by Bastien Montagne.
@@ -43,6 +43,7 @@
#include "MEM_guardedalloc.h"
#include "MOD_modifiertypes.h"
+#include "MOD_util.h"
#include "MOD_weightvg_util.h"
/**
@@ -180,19 +181,23 @@ static void foreachTexLink(ModifierData *md, Object *ob, TexWalkFunc walk, void
static void updateDepsgraph(ModifierData *md, const ModifierUpdateDepsgraphContext *ctx)
{
WeightVGMixModifierData *wmd = (WeightVGMixModifierData *)md;
- if (wmd->mask_tex_map_obj != NULL && wmd->mask_tex_mapping == MOD_DISP_MAP_OBJECT) {
- DEG_add_object_relation(
- ctx->node, wmd->mask_tex_map_obj, DEG_OB_COMP_TRANSFORM, "WeightVGMix Modifier");
- DEG_add_object_relation(
- ctx->node, wmd->mask_tex_map_obj, DEG_OB_COMP_GEOMETRY, "WeightVGMix Modifier");
+ bool need_transform_relation = false;
- DEG_add_modifier_to_transform_relation(ctx->node, "WeightVGMix Modifier");
- }
- else if (wmd->mask_tex_mapping == MOD_DISP_MAP_GLOBAL) {
- DEG_add_modifier_to_transform_relation(ctx->node, "WeightVGMix Modifier");
- }
if (wmd->mask_texture != NULL) {
DEG_add_generic_id_relation(ctx->node, &wmd->mask_texture->id, "WeightVGMix Modifier");
+
+ if (wmd->mask_tex_map_obj != NULL && wmd->mask_tex_mapping == MOD_DISP_MAP_OBJECT) {
+ MOD_depsgraph_update_object_bone_relation(
+ ctx->node, wmd->mask_tex_map_obj, wmd->mask_tex_map_bone, "WeightVGMix Modifier");
+ need_transform_relation = true;
+ }
+ else if (wmd->mask_tex_mapping == MOD_DISP_MAP_GLOBAL) {
+ need_transform_relation = true;
+ }
+ }
+
+ if (need_transform_relation) {
+ DEG_add_modifier_to_transform_relation(ctx->node, "WeightVGMix Modifier");
}
}
@@ -205,7 +210,7 @@ static bool isDisabled(const struct Scene *UNUSED(scene),
return (wmd->defgrp_name_a[0] == '\0');
}
-static Mesh *applyModifier(ModifierData *md, const ModifierEvalContext *ctx, Mesh *mesh)
+static Mesh *modifyMesh(ModifierData *md, const ModifierEvalContext *ctx, Mesh *mesh)
{
BLI_assert(mesh != NULL);
@@ -219,6 +224,17 @@ static Mesh *applyModifier(ModifierData *md, const ModifierEvalContext *ctx, Mes
int numIdx = 0;
int i;
const bool invert_vgroup_mask = (wmd->flag & MOD_WVG_MIX_INVERT_VGROUP_MASK) != 0;
+ const bool do_normalize = (wmd->flag & MOD_WVG_MIX_WEIGHTS_NORMALIZE) != 0;
+
+ /*
+ * Note that we only invert the weight values within provided vgroups, the selection based on
+ * which vertice is affected because it belongs or not to a group remains unchanged.
+ * In other words, vertices not belonging to a group won't be affected, even though their
+ * inverted 'virtual' weight would be 1.0f.
+ */
+ const bool invert_vgroup_a = (wmd->flag & MOD_WVG_MIX_INVERT_VGROUP_A) != 0;
+ const bool invert_vgroup_b = (wmd->flag & MOD_WVG_MIX_INVERT_VGROUP_B) != 0;
+
/* Flags. */
#if 0
const bool do_prev = (wmd->modifier.mode & eModifierMode_DoWeightPreview) != 0;
@@ -373,8 +389,18 @@ static Mesh *applyModifier(ModifierData *md, const ModifierEvalContext *ctx, Mes
/* Mix weights. */
for (i = 0; i < numIdx; i++) {
float weight2;
- org_w[i] = dw1[i] ? dw1[i]->weight : wmd->default_weight_a;
- weight2 = dw2[i] ? dw2[i]->weight : wmd->default_weight_b;
+ if (invert_vgroup_a) {
+ org_w[i] = 1.0f - (dw1[i] ? dw1[i]->weight : wmd->default_weight_a);
+ }
+ else {
+ org_w[i] = dw1[i] ? dw1[i]->weight : wmd->default_weight_a;
+ }
+ if (invert_vgroup_b) {
+ weight2 = 1.0f - (dw2[i] ? dw2[i]->weight : wmd->default_weight_b);
+ }
+ else {
+ weight2 = dw2[i] ? dw2[i]->weight : wmd->default_weight_b;
+ }
new_w[i] = mix_weight(org_w[i], weight2, wmd->mix_mode);
}
@@ -395,6 +421,7 @@ static Mesh *applyModifier(ModifierData *md, const ModifierEvalContext *ctx, Mes
wmd->mask_tex_use_channel,
wmd->mask_tex_mapping,
wmd->mask_tex_map_obj,
+ wmd->mask_tex_map_bone,
wmd->mask_tex_uvlayer_name,
invert_vgroup_mask);
@@ -402,7 +429,7 @@ static Mesh *applyModifier(ModifierData *md, const ModifierEvalContext *ctx, Mes
* XXX Depending on the MOD_WVG_SET_xxx option chosen, we might have to add vertices to vgroup.
*/
weightvg_update_vg(
- dvert, defgrp_index, dw1, numIdx, indices, org_w, true, -FLT_MAX, false, 0.0f);
+ dvert, defgrp_index, dw1, numIdx, indices, org_w, true, -FLT_MAX, false, 0.0f, do_normalize);
/* If weight preview enabled... */
#if 0 /* XXX Currently done in mod stack :/ */
@@ -430,13 +457,16 @@ ModifierTypeInfo modifierType_WeightVGMix = {
/* flags */ eModifierTypeFlag_AcceptsMesh | eModifierTypeFlag_SupportsMapping |
eModifierTypeFlag_SupportsEditmode | eModifierTypeFlag_UsesPreview,
- /* copyData */ modifier_copyData_generic,
+ /* copyData */ BKE_modifier_copydata_generic,
/* deformVerts */ NULL,
/* deformMatrices */ NULL,
/* deformVertsEM */ NULL,
/* deformMatricesEM */ NULL,
- /* applyModifier */ applyModifier,
+ /* modifyMesh */ modifyMesh,
+ /* modifyHair */ NULL,
+ /* modifyPointCloud */ NULL,
+ /* modifyVolume */ NULL,
/* initData */ initData,
/* requiredDataMask */ requiredDataMask,
diff --git a/source/blender/modifiers/intern/MOD_weightvgproximity.c b/source/blender/modifiers/intern/MOD_weightvgproximity.c
index 7c9242ed900..e3f833ff81e 100644
--- a/source/blender/modifiers/intern/MOD_weightvgproximity.c
+++ b/source/blender/modifiers/intern/MOD_weightvgproximity.c
@@ -10,7 +10,7 @@
* 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,
+ * 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) 2011 by Bastien Montagne.
@@ -366,6 +366,8 @@ static void foreachTexLink(ModifierData *md, Object *ob, TexWalkFunc walk, void
static void updateDepsgraph(ModifierData *md, const ModifierUpdateDepsgraphContext *ctx)
{
WeightVGProximityModifierData *wmd = (WeightVGProximityModifierData *)md;
+ bool need_transform_relation = false;
+
if (wmd->proximity_ob_target != NULL) {
DEG_add_object_relation(
ctx->node, wmd->proximity_ob_target, DEG_OB_COMP_TRANSFORM, "WeightVGProximity Modifier");
@@ -374,17 +376,25 @@ static void updateDepsgraph(ModifierData *md, const ModifierUpdateDepsgraphConte
DEG_add_object_relation(
ctx->node, wmd->proximity_ob_target, DEG_OB_COMP_GEOMETRY, "WeightVGProximity Modifier");
}
+ need_transform_relation = true;
}
- if (wmd->mask_tex_map_obj != NULL && wmd->mask_tex_mapping == MOD_DISP_MAP_OBJECT) {
- DEG_add_object_relation(
- ctx->node, wmd->mask_tex_map_obj, DEG_OB_COMP_TRANSFORM, "WeightVGProximity Modifier");
- DEG_add_object_relation(
- ctx->node, wmd->mask_tex_map_obj, DEG_OB_COMP_GEOMETRY, "WeightVGProximity Modifier");
- }
+
if (wmd->mask_texture != NULL) {
DEG_add_generic_id_relation(ctx->node, &wmd->mask_texture->id, "WeightVGProximity Modifier");
+
+ if (wmd->mask_tex_map_obj != NULL && wmd->mask_tex_mapping == MOD_DISP_MAP_OBJECT) {
+ MOD_depsgraph_update_object_bone_relation(
+ ctx->node, wmd->mask_tex_map_obj, wmd->mask_tex_map_bone, "WeightVGProximity Modifier");
+ need_transform_relation = true;
+ }
+ else if (wmd->mask_tex_mapping == MOD_DISP_MAP_GLOBAL) {
+ need_transform_relation = true;
+ }
+ }
+
+ if (need_transform_relation) {
+ DEG_add_modifier_to_transform_relation(ctx->node, "WeightVGProximity Modifier");
}
- DEG_add_modifier_to_transform_relation(ctx->node, "WeightVGProximity Modifier");
}
static bool isDisabled(const struct Scene *UNUSED(scene),
@@ -400,7 +410,7 @@ static bool isDisabled(const struct Scene *UNUSED(scene),
return (wmd->proximity_ob_target == NULL);
}
-static Mesh *applyModifier(ModifierData *md, const ModifierEvalContext *ctx, Mesh *mesh)
+static Mesh *modifyMesh(ModifierData *md, const ModifierEvalContext *ctx, Mesh *mesh)
{
BLI_assert(mesh != NULL);
@@ -419,6 +429,7 @@ static Mesh *applyModifier(ModifierData *md, const ModifierEvalContext *ctx, Mes
int i;
const bool invert_vgroup_mask = (wmd->proximity_flags & MOD_WVG_PROXIMITY_INVERT_VGROUP_MASK) !=
0;
+ const bool do_normalize = (wmd->proximity_flags & MOD_WVG_PROXIMITY_WEIGHTS_NORMALIZE) != 0;
/* Flags. */
#if 0
const bool do_prev = (wmd->modifier.mode & eModifierMode_DoWeightPreview) != 0;
@@ -589,11 +600,13 @@ static Mesh *applyModifier(ModifierData *md, const ModifierEvalContext *ctx, Mes
wmd->mask_tex_use_channel,
wmd->mask_tex_mapping,
wmd->mask_tex_map_obj,
+ wmd->mask_tex_map_bone,
wmd->mask_tex_uvlayer_name,
invert_vgroup_mask);
/* Update vgroup. Note we never add nor remove vertices from vgroup here. */
- weightvg_update_vg(dvert, defgrp_index, dw, numIdx, indices, org_w, false, 0.0f, false, 0.0f);
+ weightvg_update_vg(
+ dvert, defgrp_index, dw, numIdx, indices, org_w, false, 0.0f, false, 0.0f, do_normalize);
/* If weight preview enabled... */
#if 0 /* XXX Currently done in mod stack :/ */
@@ -625,13 +638,16 @@ ModifierTypeInfo modifierType_WeightVGProximity = {
/* flags */ eModifierTypeFlag_AcceptsMesh | eModifierTypeFlag_SupportsMapping |
eModifierTypeFlag_SupportsEditmode | eModifierTypeFlag_UsesPreview,
- /* copyData */ modifier_copyData_generic,
+ /* copyData */ BKE_modifier_copydata_generic,
/* deformVerts */ NULL,
/* deformMatrices */ NULL,
/* deformVertsEM */ NULL,
/* deformMatricesEM */ NULL,
- /* applyModifier */ applyModifier,
+ /* modifyMesh */ modifyMesh,
+ /* modifyHair */ NULL,
+ /* modifyPointCloud */ NULL,
+ /* modifyVolume */ NULL,
/* initData */ initData,
/* requiredDataMask */ requiredDataMask,
diff --git a/source/blender/modifiers/intern/MOD_weld.c b/source/blender/modifiers/intern/MOD_weld.c
index 5d56152e0ff..3bef0ad6bf7 100644
--- a/source/blender/modifiers/intern/MOD_weld.c
+++ b/source/blender/modifiers/intern/MOD_weld.c
@@ -10,7 +10,7 @@
* 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,
+ * 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) 2005 by the Blender Foundation.
@@ -801,6 +801,33 @@ static bool weld_iter_loop_of_poly_begin(WeldLoopOfPolyIter *iter,
iter->loop_map = loop_map;
iter->group = group_buffer;
+ uint group_len = 0;
+ if (group_buffer) {
+ /* First loop group needs more attention. */
+ uint loop_start, loop_end, l;
+ loop_start = iter->loop_start;
+ loop_end = l = iter->loop_end;
+ while (l >= loop_start) {
+ const uint loop_ctx = loop_map[l];
+ if (loop_ctx != OUT_OF_CONTEXT) {
+ const WeldLoop *wl = &wloop[loop_ctx];
+ if (wl->flag == ELEM_COLLAPSED) {
+ l--;
+ continue;
+ }
+ }
+ break;
+ }
+ if (l != loop_end) {
+ group_len = loop_end - l;
+ int i = 0;
+ while (l < loop_end) {
+ iter->group[i++] = ++l;
+ }
+ }
+ }
+ iter->group_len = group_len;
+
iter->l_next = iter->loop_start;
#ifdef USE_WELD_DEBUG
iter->v = OUT_OF_CONTEXT;
@@ -813,8 +840,13 @@ static bool weld_iter_loop_of_poly_next(WeldLoopOfPolyIter *iter)
uint loop_end = iter->loop_end;
const WeldLoop *wloop = iter->wloop;
const uint *loop_map = iter->loop_map;
- iter->group_len = 0;
uint l = iter->l_curr = iter->l_next;
+ if (l == iter->loop_start) {
+ /* `grupo_len` is already calculated in the first loop */
+ }
+ else {
+ iter->group_len = 0;
+ }
while (l <= loop_end) {
uint l_next = l + 1;
const uint loop_ctx = loop_map[l];
@@ -825,20 +857,6 @@ static bool weld_iter_loop_of_poly_next(WeldLoopOfPolyIter *iter)
}
if (wl->flag == ELEM_COLLAPSED) {
if (iter->group) {
- if (l == iter->loop_start) {
- uint l_prev = loop_end;
- const uint loop_ctx_end = loop_map[l_prev];
- if (loop_ctx_end != OUT_OF_CONTEXT) {
- const WeldLoop *wl_prev = &wloop[loop_ctx_end];
- while (wl_prev->flag == ELEM_COLLAPSED) {
- iter->group[iter->group_len++] = l_prev--;
- wl_prev--;
- if (wl_prev->loop_orig != l_prev) {
- break;
- }
- }
- }
- }
iter->group[iter->group_len++] = l;
}
l = l_next;
@@ -1471,6 +1489,8 @@ static void customdata_weld(
return;
}
+ CustomData_interp(source, dest, (const int *)src_indices, NULL, NULL, count, dest_index);
+
int src_i, dest_i;
int j;
@@ -1503,16 +1523,7 @@ static void customdata_weld(
if (dest->layers[dest_i].type == type) {
void *src_data = source->layers[src_i].data;
- if (CustomData_layer_has_math(dest, dest_i)) {
- const int size = CustomData_sizeof(type);
- void *dst_data = dest->layers[dest_i].data;
- void *v_dst = POINTER_OFFSET(dst_data, (size_t)dest_index * size);
- for (j = 0; j < count; j++) {
- CustomData_data_add(
- type, v_dst, POINTER_OFFSET(src_data, (size_t)src_indices[j] * size));
- }
- }
- else if (type == CD_MVERT) {
+ if (type == CD_MVERT) {
for (j = 0; j < count; j++) {
MVert *mv_src = &((MVert *)src_data)[src_indices[j]];
add_v3_v3(co, mv_src->co);
@@ -1534,6 +1545,19 @@ static void customdata_weld(
flag |= me_src->flag;
}
}
+ else if (CustomData_layer_has_interp(dest, dest_i)) {
+ /* Already calculated.
+ * TODO: Optimize by exposing `typeInfo->interp`. */
+ }
+ else if (CustomData_layer_has_math(dest, dest_i)) {
+ const int size = CustomData_sizeof(type);
+ void *dst_data = dest->layers[dest_i].data;
+ void *v_dst = POINTER_OFFSET(dst_data, (size_t)dest_index * size);
+ for (j = 0; j < count; j++) {
+ CustomData_data_add(
+ type, v_dst, POINTER_OFFSET(src_data, (size_t)src_indices[j] * size));
+ }
+ }
else {
CustomData_copy_layer_type_data(source, dest, type, src_indices[0], dest_index, 1);
}
@@ -1551,13 +1575,7 @@ static void customdata_weld(
for (dest_i = 0; dest_i < dest->totlayer; dest_i++) {
CustomDataLayer *layer_dst = &dest->layers[dest_i];
const int type = layer_dst->type;
- if (CustomData_layer_has_math(dest, dest_i)) {
- const int size = CustomData_sizeof(type);
- void *dst_data = layer_dst->data;
- void *v_dst = POINTER_OFFSET(dst_data, (size_t)dest_index * size);
- CustomData_data_multiply(type, v_dst, fac);
- }
- else if (type == CD_MVERT) {
+ if (type == CD_MVERT) {
MVert *mv = &((MVert *)layer_dst->data)[dest_index];
mul_v3_fl(co, fac);
bweight *= fac;
@@ -1586,6 +1604,15 @@ static void customdata_weld(
me->bweight = (char)bweight;
me->flag = flag;
}
+ else if (CustomData_layer_has_interp(dest, dest_i)) {
+ /* Already calculated. */
+ }
+ else if (CustomData_layer_has_math(dest, dest_i)) {
+ const int size = CustomData_sizeof(type);
+ void *dst_data = layer_dst->data;
+ void *v_dst = POINTER_OFFSET(dst_data, (size_t)dest_index * size);
+ CustomData_data_multiply(type, v_dst, fac);
+ }
}
}
@@ -1650,8 +1677,18 @@ static Mesh *weldModifier_doWeld(WeldModifierData *wmd, const ModifierEvalContex
/* Get overlap map. */
/* TODO: For a better performanse use KD-Tree. */
struct BVHTreeFromMesh treedata;
- BVHTree *bvhtree = bvhtree_from_mesh_verts_ex(
- &treedata, mvert, totvert, false, v_mask, v_mask_act, wmd->merge_dist / 2, 2, 6, 0, NULL);
+ BVHTree *bvhtree = bvhtree_from_mesh_verts_ex(&treedata,
+ mvert,
+ totvert,
+ false,
+ v_mask,
+ v_mask_act,
+ wmd->merge_dist / 2,
+ 2,
+ 6,
+ 0,
+ NULL,
+ NULL);
if (v_mask) {
MEM_freeN(v_mask);
@@ -1875,7 +1912,7 @@ static Mesh *weldModifier_doWeld(WeldModifierData *wmd, const ModifierEvalContex
return result;
}
-static Mesh *applyModifier(ModifierData *md, const ModifierEvalContext *ctx, Mesh *mesh)
+static Mesh *modifyMesh(ModifierData *md, const ModifierEvalContext *ctx, Mesh *mesh)
{
WeldModifierData *wmd = (WeldModifierData *)md;
return weldModifier_doWeld(wmd, ctx, mesh);
@@ -1911,13 +1948,16 @@ ModifierTypeInfo modifierType_Weld = {
eModifierTypeFlag_SupportsEditmode | eModifierTypeFlag_EnableInEditmode |
eModifierTypeFlag_AcceptsCVs,
- /* copyData */ modifier_copyData_generic,
+ /* copyData */ BKE_modifier_copydata_generic,
/* deformVerts */ NULL,
/* deformMatrices */ NULL,
/* deformVertsEM */ NULL,
/* deformMatricesEM */ NULL,
- /* applyModifier */ applyModifier,
+ /* modifyMesh */ modifyMesh,
+ /* modifyHair */ NULL,
+ /* modifyPointCloud */ NULL,
+ /* modifyVolume */ NULL,
/* initData */ initData,
/* requiredDataMask */ requiredDataMask,
diff --git a/source/blender/modifiers/intern/MOD_wireframe.c b/source/blender/modifiers/intern/MOD_wireframe.c
index 04473b30585..4e2e97a2b8b 100644
--- a/source/blender/modifiers/intern/MOD_wireframe.c
+++ b/source/blender/modifiers/intern/MOD_wireframe.c
@@ -10,7 +10,7 @@
* 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,
+ * along with this program; if not, write to the Free Software Foundation,
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
@@ -99,9 +99,7 @@ static Mesh *WireframeModifier_do(WireframeModifierData *wmd, Object *ob, Mesh *
return result;
}
-static Mesh *applyModifier(ModifierData *md,
- const struct ModifierEvalContext *ctx,
- struct Mesh *mesh)
+static Mesh *modifyMesh(ModifierData *md, const struct ModifierEvalContext *ctx, struct Mesh *mesh)
{
return WireframeModifier_do((WireframeModifierData *)md, ctx->object, mesh);
}
@@ -113,13 +111,16 @@ ModifierTypeInfo modifierType_Wireframe = {
/* type */ eModifierTypeType_Constructive,
/* flags */ eModifierTypeFlag_AcceptsMesh | eModifierTypeFlag_SupportsEditmode,
- /* copyData */ modifier_copyData_generic,
+ /* copyData */ BKE_modifier_copydata_generic,
/* deformVerts */ NULL,
/* deformMatrices */ NULL,
/* deformVertsEM */ NULL,
/* deformMatricesEM */ NULL,
- /* applyModifier */ applyModifier,
+ /* modifyMesh */ modifyMesh,
+ /* modifyHair */ NULL,
+ /* modifyPointCloud */ NULL,
+ /* modifyVolume */ NULL,
/* initData */ initData,
/* requiredDataMask */ requiredDataMask,
diff --git a/source/blender/nodes/CMakeLists.txt b/source/blender/nodes/CMakeLists.txt
index a2f825ee454..80bf0f7c5e2 100644
--- a/source/blender/nodes/CMakeLists.txt
+++ b/source/blender/nodes/CMakeLists.txt
@@ -21,8 +21,10 @@
set(INC
.
composite
+ function
intern
shader
+ simulation
texture
../blenkernel
../blenlib
@@ -127,6 +129,13 @@ set(SRC
composite/node_composite_tree.c
composite/node_composite_util.c
+ function/nodes/node_fn_boolean_math.cc
+ function/nodes/node_fn_combine_strings.cc
+ function/nodes/node_fn_float_compare.cc
+ function/nodes/node_fn_group_instance_id.cc
+ function/nodes/node_fn_switch.cc
+ function/node_function_util.cc
+
shader/nodes/node_shader_add_shader.c
shader/nodes/node_shader_ambient_occlusion.c
shader/nodes/node_shader_attribute.c
@@ -220,6 +229,22 @@ set(SRC
shader/node_shader_tree.c
shader/node_shader_util.c
+ simulation/nodes/node_sim_common.cc
+ simulation/nodes/node_sim_emit_particles.cc
+ simulation/nodes/node_sim_execute_condition.cc
+ simulation/nodes/node_sim_force.cc
+ simulation/nodes/node_sim_multi_execute.cc
+ simulation/nodes/node_sim_particle_attribute.cc
+ simulation/nodes/node_sim_particle_birth_event.cc
+ simulation/nodes/node_sim_particle_mesh_collision_event.cc
+ simulation/nodes/node_sim_particle_mesh_emitter.cc
+ simulation/nodes/node_sim_particle_simulation.cc
+ simulation/nodes/node_sim_particle_time_step_event.cc
+ simulation/nodes/node_sim_set_particle_attribute.cc
+ simulation/nodes/node_sim_simulation_time.cc
+ simulation/node_simulation_tree.cc
+ simulation/node_simulation_util.cc
+
texture/nodes/node_texture_at.c
texture/nodes/node_texture_bricks.c
texture/nodes/node_texture_checker.c
@@ -252,12 +277,16 @@ set(SRC
intern/node_util.c
composite/node_composite_util.h
+ function/node_function_util.h
shader/node_shader_util.h
+ simulation/node_simulation_util.h
texture/node_texture_util.h
NOD_common.h
NOD_composite.h
+ NOD_function.h
NOD_shader.h
+ NOD_simulation.h
NOD_socket.h
NOD_static_types.h
NOD_texture.h
diff --git a/source/blender/nodes/NOD_common.h b/source/blender/nodes/NOD_common.h
index 26c78eab4ec..dcc4f4d0b76 100644
--- a/source/blender/nodes/NOD_common.h
+++ b/source/blender/nodes/NOD_common.h
@@ -26,6 +26,10 @@
#include "BKE_node.h"
+#ifdef __cplusplus
+extern "C" {
+#endif
+
void register_node_type_frame(void);
void register_node_type_reroute(void);
@@ -42,4 +46,8 @@ struct bNodeSocket *node_group_output_find_socket(struct bNode *node, const char
void node_group_input_update(struct bNodeTree *ntree, struct bNode *node);
void node_group_output_update(struct bNodeTree *ntree, struct bNode *node);
+#ifdef __cplusplus
+}
+#endif
+
#endif /* __NOD_COMMON_H__ */
diff --git a/source/blender/nodes/NOD_function.h b/source/blender/nodes/NOD_function.h
new file mode 100644
index 00000000000..377ae8bfb84
--- /dev/null
+++ b/source/blender/nodes/NOD_function.h
@@ -0,0 +1,34 @@
+/*
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+
+#ifndef __NOD_FUNCTION_H__
+#define __NOD_FUNCTION_H__
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+void register_node_type_fn_boolean_math(void);
+void register_node_type_fn_float_compare(void);
+void register_node_type_fn_switch(void);
+void register_node_type_fn_group_instance_id(void);
+void register_node_type_fn_combine_strings(void);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* __NOD_FUNCTION_H__ */
diff --git a/source/blender/nodes/NOD_simulation.h b/source/blender/nodes/NOD_simulation.h
new file mode 100644
index 00000000000..2947d38fe83
--- /dev/null
+++ b/source/blender/nodes/NOD_simulation.h
@@ -0,0 +1,47 @@
+/*
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+
+#ifndef __NOD_SIMULATION_H__
+#define __NOD_SIMULATION_H__
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+extern struct bNodeTreeType *ntreeType_Simulation;
+
+void register_node_tree_type_sim(void);
+
+void register_node_type_sim_group(void);
+
+void register_node_type_sim_particle_simulation(void);
+void register_node_type_sim_force(void);
+void register_node_type_sim_set_particle_attribute(void);
+void register_node_type_sim_particle_birth_event(void);
+void register_node_type_sim_particle_time_step_event(void);
+void register_node_type_sim_execute_condition(void);
+void register_node_type_sim_multi_execute(void);
+void register_node_type_sim_particle_mesh_emitter(void);
+void register_node_type_sim_particle_mesh_collision_event(void);
+void register_node_type_sim_emit_particles(void);
+void register_node_type_sim_time(void);
+void register_node_type_sim_particle_attribute(void);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* __NOD_SIMULATION_H__ */
diff --git a/source/blender/nodes/NOD_static_types.h b/source/blender/nodes/NOD_static_types.h
index 7fec3324aab..91aa11566d3 100644
--- a/source/blender/nodes/NOD_static_types.h
+++ b/source/blender/nodes/NOD_static_types.h
@@ -258,6 +258,26 @@ DefNode(TextureNode, TEX_NODE_PROC+TEX_NOISE, 0, "TEX_NO
DefNode(TextureNode, TEX_NODE_PROC+TEX_STUCCI, 0, "TEX_STUCCI", TexStucci, "Stucci", "" )
DefNode(TextureNode, TEX_NODE_PROC+TEX_DISTNOISE, 0, "TEX_DISTNOISE", TexDistNoise, "Distorted Noise", "" )
+DefNode(SimulationNode, SIM_NODE_PARTICLE_SIMULATION, 0, "PARTICLE_SIMULATION", ParticleSimulation, "Particle Simulation", "")
+DefNode(SimulationNode, SIM_NODE_FORCE, 0, "FORCE", Force, "Force", "")
+DefNode(SimulationNode, SIM_NODE_SET_PARTICLE_ATTRIBUTE, def_sim_set_particle_attribute, "SET_PARTICLE_ATTRIBUTE", SetParticleAttribute, "Set Particle Attribute", "")
+DefNode(SimulationNode, SIM_NODE_PARTICLE_BIRTH_EVENT, 0, "PARTICLE_BIRTH_EVENT", ParticleBirthEvent, "Particle Birth Event", "")
+DefNode(SimulationNode, SIM_NODE_PARTICLE_TIME_STEP_EVENT, def_sim_particle_time_step_event, "PARTICLE_TIME_STEP_EVENT", ParticleTimeStepEvent, "Particle Time Step Event", "")
+DefNode(SimulationNode, SIM_NODE_EXECUTE_CONDITION, 0, "EXECUTE_CONDITION", ExecuteCondition, "Execute Condition", "")
+DefNode(SimulationNode, SIM_NODE_MULTI_EXECUTE, 0, "MULTI_EXECUTE", MultiExecute, "Multi Execute", "")
+DefNode(SimulationNode, SIM_NODE_PARTICLE_MESH_EMITTER, 0, "PARTICLE_MESH_EMITTER", ParticleMeshEmitter, "Particle Mesh Emitter", "")
+DefNode(SimulationNode, SIM_NODE_PARTICLE_MESH_COLLISION_EVENT, 0, "PARTICLE_MESH_COLLISION_EVENT", ParticleMeshCollisionEvent, "Particle Mesh Collision Event", "")
+DefNode(SimulationNode, SIM_NODE_EMIT_PARTICLES, 0, "EMIT_PARTICLES", EmitParticles, "Emit Particles", "")
+DefNode(SimulationNode, SIM_NODE_TIME, def_sim_time, "TIME", Time, "Time", "")
+DefNode(SimulationNode, SIM_NODE_PARTICLE_ATTRIBUTE, def_sim_particle_attribute, "PARTICLE_ATTRIBUTE", ParticleAttribute, "Particle Attribute", "")
+
+DefNode(FunctionNode, FN_NODE_BOOLEAN_MATH, def_boolean_math, "BOOLEAN_MATH", BooleanMath, "Boolean Math", "")
+DefNode(FunctionNode, FN_NODE_FLOAT_COMPARE, def_float_compare, "FLOAT_COMPARE", FloatCompare, "Float Compare", "")
+DefNode(FunctionNode, FN_NODE_SWITCH, def_fn_switch, "SWITCH", Switch, "Switch", "")
+DefNode(FunctionNode, FN_NODE_GROUP_INSTANCE_ID, 0, "GROUP_INSTANCE_ID", GroupInstanceID, "Group Instance ID", "")
+DefNode(FunctionNode, FN_NODE_COMBINE_STRINGS, 0, "COMBINE_STRINGS", CombineStrings, "Combine Strings", "")
+
+
/* undefine macros */
#undef DefNode
diff --git a/source/blender/nodes/composite/node_composite_tree.c b/source/blender/nodes/composite/node_composite_tree.c
index a830f5f1bf9..00c279ab8f6 100644
--- a/source/blender/nodes/composite/node_composite_tree.c
+++ b/source/blender/nodes/composite/node_composite_tree.c
@@ -228,7 +228,7 @@ void register_node_tree_type_cmp(void)
tt->get_from_context = composite_get_from_context;
tt->node_add_init = composite_node_add_init;
- tt->ext.srna = &RNA_CompositorNodeTree;
+ tt->rna_ext.srna = &RNA_CompositorNodeTree;
ntreeTypeAdd(tt);
}
diff --git a/source/blender/nodes/composite/nodes/node_composite_common.c b/source/blender/nodes/composite/nodes/node_composite_common.c
index 15637506e77..f5eaaef8a31 100644
--- a/source/blender/nodes/composite/nodes/node_composite_common.c
+++ b/source/blender/nodes/composite/nodes/node_composite_common.c
@@ -46,9 +46,9 @@ void register_node_type_cmp_group(void)
ntype.poll_instance = node_group_poll_instance;
ntype.insert_link = node_insert_link_default;
ntype.update_internal_links = node_update_internal_links_default;
- ntype.ext.srna = RNA_struct_find("CompositorNodeGroup");
- BLI_assert(ntype.ext.srna != NULL);
- RNA_struct_blender_type_set(ntype.ext.srna, &ntype);
+ ntype.rna_ext.srna = RNA_struct_find("CompositorNodeGroup");
+ BLI_assert(ntype.rna_ext.srna != NULL);
+ RNA_struct_blender_type_set(ntype.rna_ext.srna, &ntype);
node_type_socket_templates(&ntype, NULL, NULL);
node_type_size(&ntype, 140, 60, 400);
diff --git a/source/blender/nodes/composite/nodes/node_composite_image.c b/source/blender/nodes/composite/nodes/node_composite_image.c
index 10de192277b..53ea02ff8a7 100644
--- a/source/blender/nodes/composite/nodes/node_composite_image.c
+++ b/source/blender/nodes/composite/nodes/node_composite_image.c
@@ -86,6 +86,12 @@ static void cmp_node_image_add_pass_output(bNodeTree *ntree,
{
bNodeSocket *sock = BLI_findstring(&node->outputs, name, offsetof(bNodeSocket, name));
+ /* Replace if types don't match. */
+ if (sock && sock->type != type) {
+ nodeRemoveSocket(ntree, node, sock);
+ sock = NULL;
+ }
+
/* Create socket if it doesn't exist yet. */
if (sock == NULL) {
if (rres_index >= 0) {
@@ -305,8 +311,7 @@ static void cmp_node_rlayer_create_outputs(bNodeTree *ntree,
if ((scene->r.mode & R_EDGE_FRS) &&
(view_layer->freestyle_config.flags & FREESTYLE_AS_RENDER_PASS)) {
- ntreeCompositRegisterPass(
- scene->nodetree, scene, view_layer, RE_PASSNAME_FREESTYLE, SOCK_RGBA);
+ ntreeCompositRegisterPass(ntree, scene, view_layer, RE_PASSNAME_FREESTYLE, SOCK_RGBA);
}
MEM_freeN(data);
diff --git a/source/blender/nodes/function/node_function_util.cc b/source/blender/nodes/function/node_function_util.cc
new file mode 100644
index 00000000000..0927ba335fe
--- /dev/null
+++ b/source/blender/nodes/function/node_function_util.cc
@@ -0,0 +1,30 @@
+/*
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+
+#include "node_function_util.h"
+#include "node_util.h"
+
+bool fn_node_poll_default(bNodeType *UNUSED(ntype), bNodeTree *ntree)
+{
+ /* Function nodes are only supported in simulation node trees so far. */
+ return STREQ(ntree->idname, "SimulationNodeTree");
+}
+
+void fn_node_type_base(bNodeType *ntype, int type, const char *name, short nclass, short flag)
+{
+ node_type_base(ntype, type, name, nclass, flag);
+ ntype->poll = fn_node_poll_default;
+}
diff --git a/source/blender/nodes/function/node_function_util.h b/source/blender/nodes/function/node_function_util.h
new file mode 100644
index 00000000000..85e252f9bdd
--- /dev/null
+++ b/source/blender/nodes/function/node_function_util.h
@@ -0,0 +1,40 @@
+/*
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+
+#ifndef __NODE_FUNCTION_UTIL_H__
+#define __NODE_FUNCTION_UTIL_H__
+
+#include <string.h>
+
+#include "BLI_utildefines.h"
+
+#include "MEM_guardedalloc.h"
+
+#include "DNA_node_types.h"
+
+#include "BKE_node.h"
+
+#include "BLT_translation.h"
+
+#include "NOD_function.h"
+
+#include "node_util.h"
+
+void fn_node_type_base(
+ struct bNodeType *ntype, int type, const char *name, short nclass, short flag);
+bool fn_node_poll_default(struct bNodeType *ntype, struct bNodeTree *ntree);
+
+#endif /* __NODE_FUNCTION_UTIL_H__ */
diff --git a/source/blender/nodes/function/nodes/node_fn_boolean_math.cc b/source/blender/nodes/function/nodes/node_fn_boolean_math.cc
new file mode 100644
index 00000000000..615ad4c6733
--- /dev/null
+++ b/source/blender/nodes/function/nodes/node_fn_boolean_math.cc
@@ -0,0 +1,62 @@
+/*
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+
+#include "BLI_listbase.h"
+#include "BLI_string.h"
+
+#include "RNA_enum_types.h"
+
+#include "node_function_util.h"
+
+static bNodeSocketTemplate fn_node_boolean_math_in[] = {
+ {SOCK_BOOLEAN, N_("Boolean")},
+ {SOCK_BOOLEAN, N_("Boolean")},
+ {-1, ""},
+};
+
+static bNodeSocketTemplate fn_node_boolean_math_out[] = {
+ {SOCK_BOOLEAN, N_("Boolean")},
+ {-1, ""},
+};
+
+static void node_boolean_math_update(bNodeTree *UNUSED(ntree), bNode *node)
+{
+ bNodeSocket *sockB = (bNodeSocket *)BLI_findlink(&node->inputs, 1);
+
+ nodeSetSocketAvailability(sockB,
+ ELEM(node->custom1, NODE_BOOLEAN_MATH_AND, NODE_BOOLEAN_MATH_OR));
+}
+
+static void node_boolean_math_label(bNodeTree *UNUSED(ntree), bNode *node, char *label, int maxlen)
+{
+ const char *name;
+ bool enum_label = RNA_enum_name(rna_enum_node_boolean_math_items, node->custom1, &name);
+ if (!enum_label) {
+ name = "Unknown";
+ }
+ BLI_strncpy(label, IFACE_(name), maxlen);
+}
+
+void register_node_type_fn_boolean_math()
+{
+ static bNodeType ntype;
+
+ fn_node_type_base(&ntype, FN_NODE_BOOLEAN_MATH, "Boolean Math", 0, 0);
+ node_type_socket_templates(&ntype, fn_node_boolean_math_in, fn_node_boolean_math_out);
+ node_type_label(&ntype, node_boolean_math_label);
+ node_type_update(&ntype, node_boolean_math_update);
+ nodeRegisterType(&ntype);
+}
diff --git a/source/blender/nodes/function/nodes/node_fn_combine_strings.cc b/source/blender/nodes/function/nodes/node_fn_combine_strings.cc
new file mode 100644
index 00000000000..1b6091451d9
--- /dev/null
+++ b/source/blender/nodes/function/nodes/node_fn_combine_strings.cc
@@ -0,0 +1,21 @@
+#include "node_function_util.h"
+
+static bNodeSocketTemplate fn_node_combine_strings_in[] = {
+ {SOCK_STRING, N_("A")},
+ {SOCK_STRING, N_("B")},
+ {-1, ""},
+};
+
+static bNodeSocketTemplate fn_node_combine_strings_out[] = {
+ {SOCK_STRING, N_("Result")},
+ {-1, ""},
+};
+
+void register_node_type_fn_combine_strings()
+{
+ static bNodeType ntype;
+
+ fn_node_type_base(&ntype, FN_NODE_COMBINE_STRINGS, "Combine Strings", 0, 0);
+ node_type_socket_templates(&ntype, fn_node_combine_strings_in, fn_node_combine_strings_out);
+ nodeRegisterType(&ntype);
+}
diff --git a/source/blender/nodes/function/nodes/node_fn_float_compare.cc b/source/blender/nodes/function/nodes/node_fn_float_compare.cc
new file mode 100644
index 00000000000..9788402850b
--- /dev/null
+++ b/source/blender/nodes/function/nodes/node_fn_float_compare.cc
@@ -0,0 +1,66 @@
+/*
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+
+#include "BLI_listbase.h"
+#include "BLI_string.h"
+
+#include "RNA_enum_types.h"
+
+#include "node_function_util.h"
+
+static bNodeSocketTemplate fn_node_float_compare_in[] = {
+ {SOCK_FLOAT, N_("A"), 0.0f, 0.0f, 0.0f, 0.0f, -10000.0f, 10000.0f},
+ {SOCK_FLOAT, N_("B"), 0.0f, 0.0f, 0.0f, 0.0f, -10000.0f, 10000.0f},
+ {SOCK_FLOAT, N_("Epsilon"), 0.001f, 0.0f, 0.0f, 0.0f, -10000.0f, 10000.0f},
+ {-1, ""},
+};
+
+static bNodeSocketTemplate fn_node_float_compare_out[] = {
+ {SOCK_BOOLEAN, N_("Result")},
+ {-1, ""},
+};
+
+static void node_float_compare_update(bNodeTree *UNUSED(ntree), bNode *node)
+{
+ bNodeSocket *sockEpsilon = (bNodeSocket *)BLI_findlink(&node->inputs, 2);
+
+ nodeSetSocketAvailability(
+ sockEpsilon, ELEM(node->custom1, NODE_FLOAT_COMPARE_EQUAL, NODE_FLOAT_COMPARE_NOT_EQUAL));
+}
+
+static void node_float_compare_label(bNodeTree *UNUSED(ntree),
+ bNode *node,
+ char *label,
+ int maxlen)
+{
+ const char *name;
+ bool enum_label = RNA_enum_name(rna_enum_node_float_compare_items, node->custom1, &name);
+ if (!enum_label) {
+ name = "Unknown";
+ }
+ BLI_strncpy(label, IFACE_(name), maxlen);
+}
+
+void register_node_type_fn_float_compare()
+{
+ static bNodeType ntype;
+
+ fn_node_type_base(&ntype, FN_NODE_FLOAT_COMPARE, "Boolean Math", 0, 0);
+ node_type_socket_templates(&ntype, fn_node_float_compare_in, fn_node_float_compare_out);
+ node_type_label(&ntype, node_float_compare_label);
+ node_type_update(&ntype, node_float_compare_update);
+ nodeRegisterType(&ntype);
+}
diff --git a/source/blender/nodes/function/nodes/node_fn_group_instance_id.cc b/source/blender/nodes/function/nodes/node_fn_group_instance_id.cc
new file mode 100644
index 00000000000..2ac86ee2407
--- /dev/null
+++ b/source/blender/nodes/function/nodes/node_fn_group_instance_id.cc
@@ -0,0 +1,15 @@
+#include "node_function_util.h"
+
+static bNodeSocketTemplate fn_node_group_instance_id_out[] = {
+ {SOCK_STRING, N_("Identifier")},
+ {-1, ""},
+};
+
+void register_node_type_fn_group_instance_id()
+{
+ static bNodeType ntype;
+
+ fn_node_type_base(&ntype, FN_NODE_GROUP_INSTANCE_ID, "Group Instance ID", 0, 0);
+ node_type_socket_templates(&ntype, nullptr, fn_node_group_instance_id_out);
+ nodeRegisterType(&ntype);
+}
diff --git a/source/blender/nodes/function/nodes/node_fn_switch.cc b/source/blender/nodes/function/nodes/node_fn_switch.cc
new file mode 100644
index 00000000000..cb721058875
--- /dev/null
+++ b/source/blender/nodes/function/nodes/node_fn_switch.cc
@@ -0,0 +1,76 @@
+/*
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+
+#include "BLI_listbase.h"
+#include "node_function_util.h"
+
+static bNodeSocketTemplate fn_node_switch_in[] = {
+ {SOCK_BOOLEAN, N_("Switch")},
+
+ {SOCK_FLOAT, N_("If False"), 0.0f, 0.0f, 0.0f, 0.0f, -10000.0f, 10000.0f},
+ {SOCK_INT, N_("If False"), 0, 0, 0, 0, -10000, 10000},
+ {SOCK_BOOLEAN, N_("If False")},
+ {SOCK_VECTOR, N_("If False"), 0.0f, 0.0f, 0.0f, 0.0f, -10000.0f, 10000.0f},
+ {SOCK_STRING, N_("If False")},
+ {SOCK_RGBA, N_("If False"), 0.8f, 0.8f, 0.8f, 1.0f},
+ {SOCK_OBJECT, N_("If False")},
+ {SOCK_IMAGE, N_("If False")},
+
+ {SOCK_FLOAT, N_("If True"), 0.0f, 0.0f, 0.0f, 0.0f, -10000.0f, 10000.0f},
+ {SOCK_INT, N_("If True"), 0, 0, 0, 0, -10000, 10000},
+ {SOCK_BOOLEAN, N_("If True")},
+ {SOCK_VECTOR, N_("If True"), 0.0f, 0.0f, 0.0f, 0.0f, -10000.0f, 10000.0f},
+ {SOCK_STRING, N_("If True")},
+ {SOCK_RGBA, N_("If True"), 0.8f, 0.8f, 0.8f, 1.0f},
+ {SOCK_OBJECT, N_("If True")},
+ {SOCK_IMAGE, N_("If True")},
+
+ {-1, ""},
+};
+
+static bNodeSocketTemplate fn_node_switch_out[] = {
+ {SOCK_FLOAT, N_("Result")},
+ {SOCK_INT, N_("Result")},
+ {SOCK_BOOLEAN, N_("Result")},
+ {SOCK_VECTOR, N_("Result")},
+ {SOCK_STRING, N_("Result")},
+ {SOCK_RGBA, N_("Result")},
+ {SOCK_OBJECT, N_("Result")},
+ {SOCK_IMAGE, N_("Result")},
+ {-1, ""},
+};
+
+static void fn_node_switch_update(bNodeTree *UNUSED(ntree), bNode *node)
+{
+ int index = 0;
+ LISTBASE_FOREACH (bNodeSocket *, sock, &node->inputs) {
+ nodeSetSocketAvailability(sock, index == 0 || sock->type == node->custom1);
+ index++;
+ }
+ LISTBASE_FOREACH (bNodeSocket *, sock, &node->outputs) {
+ nodeSetSocketAvailability(sock, sock->type == node->custom1);
+ }
+}
+
+void register_node_type_fn_switch()
+{
+ static bNodeType ntype;
+
+ fn_node_type_base(&ntype, FN_NODE_SWITCH, "Switch", 0, 0);
+ node_type_socket_templates(&ntype, fn_node_switch_in, fn_node_switch_out);
+ node_type_update(&ntype, fn_node_switch_update);
+ nodeRegisterType(&ntype);
+}
diff --git a/source/blender/nodes/intern/node_common.h b/source/blender/nodes/intern/node_common.h
index c3314ae3c28..7810e9f1f14 100644
--- a/source/blender/nodes/intern/node_common.h
+++ b/source/blender/nodes/intern/node_common.h
@@ -26,6 +26,10 @@
#include "DNA_listBase.h"
+#ifdef __cplusplus
+extern "C" {
+#endif
+
struct bNodeTree;
void node_group_label(struct bNodeTree *ntree, struct bNode *node, char *label, int maxlen);
@@ -33,4 +37,8 @@ bool node_group_poll_instance(struct bNode *node, struct bNodeTree *nodetree);
void ntree_update_reroute_nodes(struct bNodeTree *ntree);
+#ifdef __cplusplus
+}
+#endif
+
#endif
diff --git a/source/blender/nodes/intern/node_socket.c b/source/blender/nodes/intern/node_socket.c
index 199b469781d..668dd3829cc 100644
--- a/source/blender/nodes/intern/node_socket.c
+++ b/source/blender/nodes/intern/node_socket.c
@@ -30,6 +30,7 @@
#include "BLI_string.h"
#include "BLI_utildefines.h"
+#include "BKE_lib_id.h"
#include "BKE_node.h"
#include "RNA_access.h"
@@ -259,6 +260,22 @@ void node_socket_init_default_value(bNodeSocket *sock)
sock->default_value = dval;
break;
}
+ case SOCK_OBJECT: {
+ bNodeSocketValueObject *dval = MEM_callocN(sizeof(bNodeSocketValueObject),
+ "node socket value object");
+ dval->value = NULL;
+
+ sock->default_value = dval;
+ break;
+ }
+ case SOCK_IMAGE: {
+ bNodeSocketValueImage *dval = MEM_callocN(sizeof(bNodeSocketValueImage),
+ "node socket value image");
+ dval->value = NULL;
+
+ sock->default_value = dval;
+ break;
+ }
}
}
@@ -317,6 +334,20 @@ void node_socket_copy_default_value(bNodeSocket *to, const bNodeSocket *from)
*toval = *fromval;
break;
}
+ case SOCK_OBJECT: {
+ bNodeSocketValueObject *toval = to->default_value;
+ bNodeSocketValueObject *fromval = from->default_value;
+ *toval = *fromval;
+ id_us_plus(&toval->value->id);
+ break;
+ }
+ case SOCK_IMAGE: {
+ bNodeSocketValueImage *toval = to->default_value;
+ bNodeSocketValueImage *fromval = from->default_value;
+ *toval = *fromval;
+ id_us_plus(&toval->value->id);
+ break;
+ }
}
to->flag |= (from->flag & SOCK_HIDE_VALUE);
@@ -467,6 +498,19 @@ static bNodeSocketType *make_socket_type_virtual(void)
return stype;
}
+static bNodeSocketType *make_socket_type_effector(int type)
+{
+ bNodeSocketType *stype = make_standard_socket_type(type, PROP_NONE);
+ stype->input_link_limit = 0xFFF;
+ return stype;
+}
+
+static bNodeSocketType *make_socket_type_control_flow(int type)
+{
+ bNodeSocketType *stype = make_standard_socket_type(type, PROP_NONE);
+ return stype;
+}
+
void register_standard_node_socket_types(void)
{
/* draw callbacks are set in drawnode.c to avoid bad-level calls */
@@ -499,5 +543,15 @@ void register_standard_node_socket_types(void)
nodeRegisterSocketType(make_standard_socket_type(SOCK_SHADER, PROP_NONE));
+ nodeRegisterSocketType(make_standard_socket_type(SOCK_OBJECT, PROP_NONE));
+
+ nodeRegisterSocketType(make_standard_socket_type(SOCK_IMAGE, PROP_NONE));
+
+ nodeRegisterSocketType(make_socket_type_effector(SOCK_EMITTERS));
+ nodeRegisterSocketType(make_socket_type_effector(SOCK_EVENTS));
+ nodeRegisterSocketType(make_socket_type_effector(SOCK_FORCES));
+
+ nodeRegisterSocketType(make_socket_type_control_flow(SOCK_CONTROL_FLOW));
+
nodeRegisterSocketType(make_socket_type_virtual());
}
diff --git a/source/blender/nodes/intern/node_util.h b/source/blender/nodes/intern/node_util.h
index a7f09d24a70..61f8fe6809d 100644
--- a/source/blender/nodes/intern/node_util.h
+++ b/source/blender/nodes/intern/node_util.h
@@ -38,6 +38,10 @@
#include "RNA_access.h"
+#ifdef __cplusplus
+extern "C" {
+#endif
+
struct bNode;
struct bNodeTree;
@@ -103,4 +107,8 @@ void node_socket_set_vector(struct bNodeTree *ntree,
struct bNodeSocket *sock,
const float *value);
+#ifdef __cplusplus
+}
+#endif
+
#endif
diff --git a/source/blender/nodes/shader/node_shader_tree.c b/source/blender/nodes/shader/node_shader_tree.c
index a19fb30c53b..179a92ec7bd 100644
--- a/source/blender/nodes/shader/node_shader_tree.c
+++ b/source/blender/nodes/shader/node_shader_tree.c
@@ -206,7 +206,7 @@ void register_node_tree_type_sh(void)
tt->get_from_context = shader_get_from_context;
tt->validate_link = shader_validate_link;
- tt->ext.srna = &RNA_ShaderNodeTree;
+ tt->rna_ext.srna = &RNA_ShaderNodeTree;
ntreeTypeAdd(tt);
}
@@ -229,7 +229,7 @@ bNode *ntreeShaderOutputNode(bNodeTree *ntree, int target)
* multiple, we prefer exact target match and active nodes. */
bNode *output_node = NULL;
- for (bNode *node = ntree->nodes.first; node; node = node->next) {
+ LISTBASE_FOREACH (bNode *, node, &ntree->nodes) {
if (!ELEM(node->type, SH_NODE_OUTPUT_MATERIAL, SH_NODE_OUTPUT_WORLD, SH_NODE_OUTPUT_LIGHT)) {
continue;
}
@@ -344,7 +344,7 @@ static void ntree_shader_unlink_hidden_value_sockets(bNode *group_node, bNodeSoc
bool removed_link = false;
for (node = group_ntree->nodes.first; node; node = node->next) {
- for (bNodeSocket *sock = node->inputs.first; sock; sock = sock->next) {
+ LISTBASE_FOREACH (bNodeSocket *, sock, &node->inputs) {
if ((sock->flag & SOCK_HIDE_VALUE) == 0) {
continue;
}
@@ -385,9 +385,21 @@ static void ntree_shader_groups_expand_inputs(bNodeTree *localtree)
/* Fix the case where the socket is actually converting the data. (see T71374)
* We only do the case of lossy conversion to float.*/
if ((socket->type == SOCK_FLOAT) && (link->fromsock->type != link->tosock->type)) {
- bNode *tmp = nodeAddStaticNode(NULL, localtree, SH_NODE_RGBTOBW);
- nodeAddLink(localtree, link->fromnode, link->fromsock, tmp, tmp->inputs.first);
- nodeAddLink(localtree, tmp, tmp->outputs.first, node, socket);
+ if (link->fromsock->type == SOCK_RGBA) {
+ bNode *tmp = nodeAddStaticNode(NULL, localtree, SH_NODE_RGBTOBW);
+ nodeAddLink(localtree, link->fromnode, link->fromsock, tmp, tmp->inputs.first);
+ nodeAddLink(localtree, tmp, tmp->outputs.first, node, socket);
+ }
+ else if (link->fromsock->type == SOCK_VECTOR) {
+ bNode *tmp = nodeAddStaticNode(NULL, localtree, SH_NODE_VECTOR_MATH);
+ tmp->custom1 = NODE_VECTOR_MATH_DOT_PRODUCT;
+ bNodeSocket *dot_input1 = tmp->inputs.first;
+ bNodeSocket *dot_input2 = dot_input1->next;
+ bNodeSocketValueVector *input2_socket_value = dot_input2->default_value;
+ copy_v3_fl(input2_socket_value->value, 1.0f / 3.0f);
+ nodeAddLink(localtree, link->fromnode, link->fromsock, tmp, dot_input1);
+ nodeAddLink(localtree, tmp, tmp->outputs.last, node, socket);
+ }
}
continue;
}
@@ -553,7 +565,7 @@ static void ntree_shader_relink_node_normal(bNodeTree *ntree,
/* TODO(sergey): Can we do something smarter here than just a name-based
* matching?
*/
- for (bNodeSocket *sock = node->inputs.first; sock; sock = sock->next) {
+ LISTBASE_FOREACH (bNodeSocket *, sock, &node->inputs) {
if (STREQ(sock->identifier, "Normal") && sock->link == NULL) {
/* It's a normal input and nothing is connected to it. */
nodeAddLink(ntree, node_from, socket_from, node, sock);
diff --git a/source/blender/nodes/shader/node_shader_util.c b/source/blender/nodes/shader/node_shader_util.c
index 93d03720058..4464a61c48c 100644
--- a/source/blender/nodes/shader/node_shader_util.c
+++ b/source/blender/nodes/shader/node_shader_util.c
@@ -32,6 +32,11 @@ bool sh_node_poll_default(bNodeType *UNUSED(ntype), bNodeTree *ntree)
return STREQ(ntree->idname, "ShaderNodeTree");
}
+static bool sh_fn_poll_default(bNodeType *UNUSED(ntype), bNodeTree *ntree)
+{
+ return STREQ(ntree->idname, "ShaderNodeTree") || STREQ(ntree->idname, "SimulationNodeTree");
+}
+
void sh_node_type_base(
struct bNodeType *ntype, int type, const char *name, short nclass, short flag)
{
@@ -42,6 +47,12 @@ void sh_node_type_base(
ntype->update_internal_links = node_update_internal_links_default;
}
+void sh_fn_node_type_base(bNodeType *ntype, int type, const char *name, short nclass, short flag)
+{
+ sh_node_type_base(ntype, type, name, nclass, flag);
+ ntype->poll = sh_fn_poll_default;
+}
+
/* ****** */
void nodestack_get_vec(float *in, short type_in, bNodeStack *ns)
diff --git a/source/blender/nodes/shader/node_shader_util.h b/source/blender/nodes/shader/node_shader_util.h
index 8d525c8f23c..8834de0633e 100644
--- a/source/blender/nodes/shader/node_shader_util.h
+++ b/source/blender/nodes/shader/node_shader_util.h
@@ -72,6 +72,8 @@
bool sh_node_poll_default(struct bNodeType *ntype, struct bNodeTree *ntree);
void sh_node_type_base(
struct bNodeType *ntype, int type, const char *name, short nclass, short flag);
+void sh_fn_node_type_base(
+ struct bNodeType *ntype, int type, const char *name, short nclass, short flag);
/* ********* exec data struct, remains internal *********** */
diff --git a/source/blender/nodes/shader/nodes/node_shader_brightness.c b/source/blender/nodes/shader/nodes/node_shader_brightness.c
index d8f560277f2..cc1968cb1b1 100644
--- a/source/blender/nodes/shader/nodes/node_shader_brightness.c
+++ b/source/blender/nodes/shader/nodes/node_shader_brightness.c
@@ -46,7 +46,7 @@ void register_node_type_sh_brightcontrast(void)
{
static bNodeType ntype;
- sh_node_type_base(&ntype, SH_NODE_BRIGHTCONTRAST, "Bright/Contrast", NODE_CLASS_OP_COLOR, 0);
+ sh_fn_node_type_base(&ntype, SH_NODE_BRIGHTCONTRAST, "Bright/Contrast", NODE_CLASS_OP_COLOR, 0);
node_type_socket_templates(&ntype, sh_node_brightcontrast_in, sh_node_brightcontrast_out);
node_type_init(&ntype, NULL);
node_type_storage(&ntype, "", NULL, NULL);
diff --git a/source/blender/nodes/shader/nodes/node_shader_clamp.c b/source/blender/nodes/shader/nodes/node_shader_clamp.c
index c49cfcea8d3..808f9686f0a 100644
--- a/source/blender/nodes/shader/nodes/node_shader_clamp.c
+++ b/source/blender/nodes/shader/nodes/node_shader_clamp.c
@@ -54,7 +54,7 @@ void register_node_type_sh_clamp(void)
{
static bNodeType ntype;
- sh_node_type_base(&ntype, SH_NODE_CLAMP, "Clamp", NODE_CLASS_CONVERTOR, 0);
+ sh_fn_node_type_base(&ntype, SH_NODE_CLAMP, "Clamp", NODE_CLASS_CONVERTOR, 0);
node_type_socket_templates(&ntype, sh_node_clamp_in, sh_node_clamp_out);
node_type_init(&ntype, node_shader_init_clamp);
node_type_gpu(&ntype, gpu_shader_clamp);
diff --git a/source/blender/nodes/shader/nodes/node_shader_common.c b/source/blender/nodes/shader/nodes/node_shader_common.c
index 0ecb64cd1d1..a864bef60d9 100644
--- a/source/blender/nodes/shader/nodes/node_shader_common.c
+++ b/source/blender/nodes/shader/nodes/node_shader_common.c
@@ -238,9 +238,9 @@ void register_node_type_sh_group(void)
ntype.poll_instance = node_group_poll_instance;
ntype.insert_link = node_insert_link_default;
ntype.update_internal_links = node_update_internal_links_default;
- ntype.ext.srna = RNA_struct_find("ShaderNodeGroup");
- BLI_assert(ntype.ext.srna != NULL);
- RNA_struct_blender_type_set(ntype.ext.srna, &ntype);
+ ntype.rna_ext.srna = RNA_struct_find("ShaderNodeGroup");
+ BLI_assert(ntype.rna_ext.srna != NULL);
+ RNA_struct_blender_type_set(ntype.rna_ext.srna, &ntype);
node_type_socket_templates(&ntype, NULL, NULL);
node_type_size(&ntype, 140, 60, 400);
diff --git a/source/blender/nodes/shader/nodes/node_shader_displacement.c b/source/blender/nodes/shader/nodes/node_shader_displacement.c
index 496b61c8c72..22fbe4e4da6 100644
--- a/source/blender/nodes/shader/nodes/node_shader_displacement.c
+++ b/source/blender/nodes/shader/nodes/node_shader_displacement.c
@@ -39,7 +39,7 @@ static void node_shader_init_displacement(bNodeTree *UNUSED(ntree), bNode *node)
node->custom1 = SHD_SPACE_OBJECT; /* space */
/* Set default value here for backwards compatibility. */
- for (bNodeSocket *sock = node->inputs.first; sock; sock = sock->next) {
+ LISTBASE_FOREACH (bNodeSocket *, sock, &node->inputs) {
if (STREQ(sock->name, "Midlevel")) {
((bNodeSocketValueFloat *)sock->default_value)->value = 0.5f;
}
diff --git a/source/blender/nodes/shader/nodes/node_shader_gamma.c b/source/blender/nodes/shader/nodes/node_shader_gamma.c
index b48838e5f56..747979522d1 100644
--- a/source/blender/nodes/shader/nodes/node_shader_gamma.c
+++ b/source/blender/nodes/shader/nodes/node_shader_gamma.c
@@ -62,7 +62,7 @@ void register_node_type_sh_gamma(void)
{
static bNodeType ntype;
- sh_node_type_base(&ntype, SH_NODE_GAMMA, "Gamma", NODE_CLASS_OP_COLOR, 0);
+ sh_fn_node_type_base(&ntype, SH_NODE_GAMMA, "Gamma", NODE_CLASS_OP_COLOR, 0);
node_type_socket_templates(&ntype, sh_node_gamma_in, sh_node_gamma_out);
node_type_init(&ntype, NULL);
node_type_storage(&ntype, "", NULL, NULL);
diff --git a/source/blender/nodes/shader/nodes/node_shader_hueSatVal.c b/source/blender/nodes/shader/nodes/node_shader_hueSatVal.c
index 7a05fc95eec..57ef51c65f6 100644
--- a/source/blender/nodes/shader/nodes/node_shader_hueSatVal.c
+++ b/source/blender/nodes/shader/nodes/node_shader_hueSatVal.c
@@ -89,7 +89,7 @@ void register_node_type_sh_hue_sat(void)
{
static bNodeType ntype;
- sh_node_type_base(&ntype, SH_NODE_HUE_SAT, "Hue Saturation Value", NODE_CLASS_OP_COLOR, 0);
+ sh_fn_node_type_base(&ntype, SH_NODE_HUE_SAT, "Hue Saturation Value", NODE_CLASS_OP_COLOR, 0);
node_type_socket_templates(&ntype, sh_node_hue_sat_in, sh_node_hue_sat_out);
node_type_size_preset(&ntype, NODE_SIZE_MIDDLE);
node_type_exec(&ntype, NULL, NULL, node_shader_exec_hue_sat);
diff --git a/source/blender/nodes/shader/nodes/node_shader_invert.c b/source/blender/nodes/shader/nodes/node_shader_invert.c
index 0d6709a1968..19fa0b0309d 100644
--- a/source/blender/nodes/shader/nodes/node_shader_invert.c
+++ b/source/blender/nodes/shader/nodes/node_shader_invert.c
@@ -69,7 +69,7 @@ void register_node_type_sh_invert(void)
{
static bNodeType ntype;
- sh_node_type_base(&ntype, SH_NODE_INVERT, "Invert", NODE_CLASS_OP_COLOR, 0);
+ sh_fn_node_type_base(&ntype, SH_NODE_INVERT, "Invert", NODE_CLASS_OP_COLOR, 0);
node_type_socket_templates(&ntype, sh_node_invert_in, sh_node_invert_out);
node_type_exec(&ntype, NULL, NULL, node_shader_exec_invert);
node_type_gpu(&ntype, gpu_shader_invert);
diff --git a/source/blender/nodes/shader/nodes/node_shader_map_range.c b/source/blender/nodes/shader/nodes/node_shader_map_range.c
index d59540cb8fa..5db7983e752 100644
--- a/source/blender/nodes/shader/nodes/node_shader_map_range.c
+++ b/source/blender/nodes/shader/nodes/node_shader_map_range.c
@@ -81,7 +81,7 @@ void register_node_type_sh_map_range(void)
{
static bNodeType ntype;
- sh_node_type_base(&ntype, SH_NODE_MAP_RANGE, "Map Range", NODE_CLASS_CONVERTOR, 0);
+ sh_fn_node_type_base(&ntype, SH_NODE_MAP_RANGE, "Map Range", NODE_CLASS_CONVERTOR, 0);
node_type_socket_templates(&ntype, sh_node_map_range_in, sh_node_map_range_out);
node_type_init(&ntype, node_shader_init_map_range);
node_type_update(&ntype, node_shader_update_map_range);
diff --git a/source/blender/nodes/shader/nodes/node_shader_math.c b/source/blender/nodes/shader/nodes/node_shader_math.c
index 08578e0e11e..8abebbf5081 100644
--- a/source/blender/nodes/shader/nodes/node_shader_math.c
+++ b/source/blender/nodes/shader/nodes/node_shader_math.c
@@ -105,7 +105,7 @@ void register_node_type_sh_math(void)
{
static bNodeType ntype;
- sh_node_type_base(&ntype, SH_NODE_MATH, "Math", NODE_CLASS_CONVERTOR, 0);
+ sh_fn_node_type_base(&ntype, SH_NODE_MATH, "Math", NODE_CLASS_CONVERTOR, 0);
node_type_socket_templates(&ntype, sh_node_math_in, sh_node_math_out);
node_type_label(&ntype, node_math_label);
node_type_gpu(&ntype, gpu_shader_math);
diff --git a/source/blender/nodes/shader/nodes/node_shader_mixRgb.c b/source/blender/nodes/shader/nodes/node_shader_mixRgb.c
index 9c318073304..93e88664d1a 100644
--- a/source/blender/nodes/shader/nodes/node_shader_mixRgb.c
+++ b/source/blender/nodes/shader/nodes/node_shader_mixRgb.c
@@ -107,7 +107,7 @@ void register_node_type_sh_mix_rgb(void)
{
static bNodeType ntype;
- sh_node_type_base(&ntype, SH_NODE_MIX_RGB, "Mix", NODE_CLASS_OP_COLOR, 0);
+ sh_fn_node_type_base(&ntype, SH_NODE_MIX_RGB, "Mix", NODE_CLASS_OP_COLOR, 0);
node_type_socket_templates(&ntype, sh_node_mix_rgb_in, sh_node_mix_rgb_out);
node_type_label(&ntype, node_blend_label);
node_type_exec(&ntype, NULL, NULL, node_shader_exec_mix_rgb);
diff --git a/source/blender/nodes/shader/nodes/node_shader_output_material.c b/source/blender/nodes/shader/nodes/node_shader_output_material.c
index 4b7bd964052..578262e9f17 100644
--- a/source/blender/nodes/shader/nodes/node_shader_output_material.c
+++ b/source/blender/nodes/shader/nodes/node_shader_output_material.c
@@ -45,9 +45,18 @@ static int node_shader_gpu_output_material(GPUMaterial *mat,
GPUNodeStack *in,
GPUNodeStack *out)
{
- GPUNodeLink *outlink;
+ GPUNodeLink *outlink, *alpha_threshold_link;
- GPU_stack_link(mat, node, "node_output_material", in, out, &outlink);
+ Material *ma = GPU_material_get_material(mat);
+ if (ma && ma->blend_method == MA_BM_CLIP) {
+ alpha_threshold_link = GPU_uniform(&ma->alpha_threshold);
+ }
+ else {
+ static float no_alpha_threshold = -1.0f;
+ alpha_threshold_link = GPU_uniform(&no_alpha_threshold);
+ }
+
+ GPU_stack_link(mat, node, "node_output_material", in, out, alpha_threshold_link, &outlink);
GPU_material_output_link(mat, outlink);
return true;
diff --git a/source/blender/nodes/shader/nodes/node_shader_sepcombHSV.c b/source/blender/nodes/shader/nodes/node_shader_sepcombHSV.c
index 951755be4f3..2c9b77530a2 100644
--- a/source/blender/nodes/shader/nodes/node_shader_sepcombHSV.c
+++ b/source/blender/nodes/shader/nodes/node_shader_sepcombHSV.c
@@ -61,7 +61,7 @@ void register_node_type_sh_sephsv(void)
{
static bNodeType ntype;
- sh_node_type_base(&ntype, SH_NODE_SEPHSV, "Separate HSV", NODE_CLASS_CONVERTOR, 0);
+ sh_fn_node_type_base(&ntype, SH_NODE_SEPHSV, "Separate HSV", NODE_CLASS_CONVERTOR, 0);
node_type_socket_templates(&ntype, sh_node_sephsv_in, sh_node_sephsv_out);
node_type_exec(&ntype, NULL, NULL, node_shader_exec_sephsv);
node_type_gpu(&ntype, gpu_shader_sephsv);
@@ -109,7 +109,7 @@ void register_node_type_sh_combhsv(void)
{
static bNodeType ntype;
- sh_node_type_base(&ntype, SH_NODE_COMBHSV, "Combine HSV", NODE_CLASS_CONVERTOR, 0);
+ sh_fn_node_type_base(&ntype, SH_NODE_COMBHSV, "Combine HSV", NODE_CLASS_CONVERTOR, 0);
node_type_socket_templates(&ntype, sh_node_combhsv_in, sh_node_combhsv_out);
node_type_exec(&ntype, NULL, NULL, node_shader_exec_combhsv);
node_type_gpu(&ntype, gpu_shader_combhsv);
diff --git a/source/blender/nodes/shader/nodes/node_shader_sepcombRGB.c b/source/blender/nodes/shader/nodes/node_shader_sepcombRGB.c
index f10f80d5c2d..d0dc45dcedd 100644
--- a/source/blender/nodes/shader/nodes/node_shader_sepcombRGB.c
+++ b/source/blender/nodes/shader/nodes/node_shader_sepcombRGB.c
@@ -63,7 +63,7 @@ void register_node_type_sh_seprgb(void)
{
static bNodeType ntype;
- sh_node_type_base(&ntype, SH_NODE_SEPRGB, "Separate RGB", NODE_CLASS_CONVERTOR, 0);
+ sh_fn_node_type_base(&ntype, SH_NODE_SEPRGB, "Separate RGB", NODE_CLASS_CONVERTOR, 0);
node_type_socket_templates(&ntype, sh_node_seprgb_in, sh_node_seprgb_out);
node_type_exec(&ntype, NULL, NULL, node_shader_exec_seprgb);
node_type_gpu(&ntype, gpu_shader_seprgb);
@@ -113,7 +113,7 @@ void register_node_type_sh_combrgb(void)
{
static bNodeType ntype;
- sh_node_type_base(&ntype, SH_NODE_COMBRGB, "Combine RGB", NODE_CLASS_CONVERTOR, 0);
+ sh_fn_node_type_base(&ntype, SH_NODE_COMBRGB, "Combine RGB", NODE_CLASS_CONVERTOR, 0);
node_type_socket_templates(&ntype, sh_node_combrgb_in, sh_node_combrgb_out);
node_type_exec(&ntype, NULL, NULL, node_shader_exec_combrgb);
node_type_gpu(&ntype, gpu_shader_combrgb);
diff --git a/source/blender/nodes/shader/nodes/node_shader_sepcombXYZ.c b/source/blender/nodes/shader/nodes/node_shader_sepcombXYZ.c
index 55d5084b132..429b1a3e818 100644
--- a/source/blender/nodes/shader/nodes/node_shader_sepcombXYZ.c
+++ b/source/blender/nodes/shader/nodes/node_shader_sepcombXYZ.c
@@ -48,7 +48,7 @@ void register_node_type_sh_sepxyz(void)
{
static bNodeType ntype;
- sh_node_type_base(&ntype, SH_NODE_SEPXYZ, "Separate XYZ", NODE_CLASS_CONVERTOR, 0);
+ sh_fn_node_type_base(&ntype, SH_NODE_SEPXYZ, "Separate XYZ", NODE_CLASS_CONVERTOR, 0);
node_type_socket_templates(&ntype, sh_node_sepxyz_in, sh_node_sepxyz_out);
node_type_gpu(&ntype, gpu_shader_sepxyz);
@@ -80,7 +80,7 @@ void register_node_type_sh_combxyz(void)
{
static bNodeType ntype;
- sh_node_type_base(&ntype, SH_NODE_COMBXYZ, "Combine XYZ", NODE_CLASS_CONVERTOR, 0);
+ sh_fn_node_type_base(&ntype, SH_NODE_COMBXYZ, "Combine XYZ", NODE_CLASS_CONVERTOR, 0);
node_type_socket_templates(&ntype, sh_node_combxyz_in, sh_node_combxyz_out);
node_type_gpu(&ntype, gpu_shader_combxyz);
diff --git a/source/blender/nodes/shader/nodes/node_shader_tex_brick.c b/source/blender/nodes/shader/nodes/node_shader_tex_brick.c
index eba9abc6e3c..1b802f1dfd7 100644
--- a/source/blender/nodes/shader/nodes/node_shader_tex_brick.c
+++ b/source/blender/nodes/shader/nodes/node_shader_tex_brick.c
@@ -135,7 +135,7 @@ static void node_shader_init_tex_brick(bNodeTree *UNUSED(ntree), bNode *node)
node->storage = tex;
- for (bNodeSocket *sock = node->inputs.first; sock; sock = sock->next) {
+ LISTBASE_FOREACH (bNodeSocket *, sock, &node->inputs) {
if (STREQ(sock->name, "Mortar Smooth")) {
((bNodeSocketValueFloat *)sock->default_value)->value = 0.1f;
}
diff --git a/source/blender/nodes/shader/nodes/node_shader_tex_environment.c b/source/blender/nodes/shader/nodes/node_shader_tex_environment.c
index fd4efb1b7ec..0cf4b51f307 100644
--- a/source/blender/nodes/shader/nodes/node_shader_tex_environment.c
+++ b/source/blender/nodes/shader/nodes/node_shader_tex_environment.c
@@ -19,6 +19,8 @@
#include "../node_shader_util.h"
+#include "GPU_draw.h"
+
/* **************** OUTPUT ******************** */
static bNodeSocketTemplate sh_node_tex_environment_in[] = {
@@ -56,6 +58,10 @@ static int node_shader_gpu_tex_environment(GPUMaterial *mat,
bNode *node_original = node->original ? node->original : node;
NodeTexImage *tex_original = node_original->storage;
ImageUser *iuser = &tex_original->iuser;
+ eGPUSamplerState sampler = GPU_SAMPLER_REPEAT | GPU_SAMPLER_ANISO | GPU_SAMPLER_FILTER;
+ if (GPU_get_mipmap()) {
+ sampler |= GPU_SAMPLER_MIPMAP;
+ }
GPUNodeLink *outalpha;
@@ -72,49 +78,41 @@ static int node_shader_gpu_tex_environment(GPUMaterial *mat,
/* Compute texture coordinate. */
if (tex->projection == SHD_PROJ_EQUIRECTANGULAR) {
- /* To fix pole issue we clamp the v coordinate. The clamp value depends on the filter size. */
- float clamp_size = (ELEM(tex->interpolation, SHD_INTERP_CUBIC, SHD_INTERP_SMART)) ? 1.5 : 0.5;
- GPU_link(mat,
- "node_tex_environment_equirectangular",
- in[0].link,
- GPU_constant(&clamp_size),
- GPU_image(mat, ima, iuser),
- &in[0].link);
+ GPU_link(mat, "node_tex_environment_equirectangular", in[0].link, &in[0].link);
+ /* To fix pole issue we clamp the v coordinate. */
+ sampler &= ~GPU_SAMPLER_REPEAT_T;
+ /* Force the highest mipmap and don't do anisotropic filtering.
+ * This is to fix the artifact caused by derivatives discontinuity. */
+ sampler &= ~(GPU_SAMPLER_MIPMAP | GPU_SAMPLER_ANISO);
}
else {
GPU_link(mat, "node_tex_environment_mirror_ball", in[0].link, &in[0].link);
+ /* Fix pole issue. */
+ sampler &= ~GPU_SAMPLER_REPEAT;
}
- /* Sample texture with correct interpolation. */
+ const char *gpufunc;
+ static const char *names[] = {
+ "node_tex_image_linear",
+ "node_tex_image_cubic",
+ };
+
switch (tex->interpolation) {
case SHD_INTERP_LINEAR:
- /* Force the highest mipmap and don't do anisotropic filtering.
- * This is to fix the artifact caused by derivatives discontinuity. */
- GPU_link(mat,
- "node_tex_image_linear_no_mip",
- in[0].link,
- GPU_image(mat, ima, iuser),
- &out[0].link,
- &outalpha);
+ gpufunc = names[0];
break;
case SHD_INTERP_CLOSEST:
- GPU_link(mat,
- "node_tex_image_nearest",
- in[0].link,
- GPU_image(mat, ima, iuser),
- &out[0].link,
- &outalpha);
+ sampler &= ~(GPU_SAMPLER_FILTER | GPU_SAMPLER_MIPMAP);
+ gpufunc = names[0];
break;
default:
- GPU_link(mat,
- "node_tex_image_cubic",
- in[0].link,
- GPU_image(mat, ima, iuser),
- &out[0].link,
- &outalpha);
+ gpufunc = names[1];
break;
}
+ /* Sample texture with correct interpolation. */
+ GPU_link(mat, gpufunc, in[0].link, GPU_image(mat, ima, iuser, sampler), &out[0].link, &outalpha);
+
if (out[0].hasoutput) {
if (ELEM(ima->alpha_mode, IMA_ALPHA_IGNORE, IMA_ALPHA_CHANNEL_PACKED) ||
IMB_colormanagement_space_name_is_data(ima->colorspace_settings.name)) {
diff --git a/source/blender/nodes/shader/nodes/node_shader_tex_image.c b/source/blender/nodes/shader/nodes/node_shader_tex_image.c
index b4b1c1d3698..cbda72cd228 100644
--- a/source/blender/nodes/shader/nodes/node_shader_tex_image.c
+++ b/source/blender/nodes/shader/nodes/node_shader_tex_image.c
@@ -19,6 +19,8 @@
#include "../node_shader_util.h"
+#include "GPU_draw.h"
+
/* **************** OUTPUT ******************** */
static bNodeSocketTemplate sh_node_tex_image_in[] = {
@@ -57,31 +59,6 @@ static int node_shader_gpu_tex_image(GPUMaterial *mat,
GPUNodeStack *in,
GPUNodeStack *out)
{
- static const char *names[] = {
- "node_tex_image_linear",
- "node_tex_image_nearest",
- "node_tex_image_cubic",
- "node_tex_image_smart",
- };
- static const char *names_tiled[] = {
- "node_tex_tile_linear",
- "node_tex_tile_nearest",
- "node_tex_tile_cubic",
- "node_tex_tile_smart",
- };
- static const char *names_box[] = {
- "tex_box_sample_linear",
- "tex_box_sample_nearest",
- "tex_box_sample_cubic",
- "tex_box_sample_smart",
- };
- static const char *names_clip[] = {
- "tex_clip_linear",
- "tex_clip_nearest",
- "tex_clip_cubic",
- "tex_clip_smart",
- };
-
Image *ima = (Image *)node->id;
NodeTexImage *tex = node->storage;
@@ -91,26 +68,11 @@ static int node_shader_gpu_tex_image(GPUMaterial *mat,
NodeTexImage *tex_original = node_original->storage;
ImageUser *iuser = &tex_original->iuser;
- const char *gpu_node_name = (tex->projection == SHD_PROJ_BOX) ? names_box[tex->interpolation] :
- names[tex->interpolation];
- bool do_texco_extend = (tex->extension != SHD_IMAGE_EXTENSION_REPEAT);
- const bool do_texco_clip = (tex->extension == SHD_IMAGE_EXTENSION_CLIP);
-
- if (do_texco_extend && (tex->projection != SHD_PROJ_BOX) &&
- ELEM(tex->interpolation, SHD_INTERP_CUBIC, SHD_INTERP_SMART)) {
- gpu_node_name = "node_tex_image_cubic_extend";
- /* We do it inside the sampling function */
- do_texco_extend = false;
- }
-
- GPUNodeLink *norm, *col1, *col2, *col3, *input_coords, *gpu_image;
- GPUNodeLink *vnor, *ob_mat, *blend;
- GPUNodeLink **texco = &in[0].link;
-
if (!ima) {
return GPU_stack_link(mat, node, "node_tex_image_empty", in, out);
}
+ GPUNodeLink **texco = &in[0].link;
if (!*texco) {
*texco = GPU_attribute(mat, CD_MTFACE, "");
node_shader_gpu_bump_tex_coord(mat, node, texco);
@@ -118,82 +80,73 @@ static int node_shader_gpu_tex_image(GPUMaterial *mat,
node_shader_gpu_tex_mapping(mat, node, in, out);
+ eGPUSamplerState sampler_state = 0;
+
+ switch (tex->extension) {
+ case SHD_IMAGE_EXTENSION_REPEAT:
+ sampler_state |= GPU_SAMPLER_REPEAT;
+ break;
+ case SHD_IMAGE_EXTENSION_CLIP:
+ sampler_state |= GPU_SAMPLER_CLAMP_BORDER;
+ break;
+ default:
+ break;
+ }
+
+ if (tex->interpolation != SHD_INTERP_CLOSEST) {
+ sampler_state |= GPU_SAMPLER_ANISO | GPU_SAMPLER_FILTER;
+ sampler_state |= GPU_get_mipmap() ? GPU_SAMPLER_MIPMAP : 0;
+ }
+ const bool use_cubic = ELEM(tex->interpolation, SHD_INTERP_CUBIC, SHD_INTERP_SMART);
+
if (ima->source == IMA_SRC_TILED) {
+ const char *gpu_node_name = use_cubic ? "node_tex_tile_cubic" : "node_tex_tile_linear";
+ GPUNodeLink *gpu_image = GPU_image_tiled(mat, ima, iuser, sampler_state);
+ GPUNodeLink *gpu_image_tile_mapping = GPU_image_tiled_mapping(mat, ima, iuser);
/* UDIM tiles needs a samper2DArray and sampler1DArray for tile mapping. */
- GPU_stack_link(mat,
- node,
- names_tiled[tex->interpolation],
- in,
- out,
- GPU_image_tiled(mat, ima, iuser),
- GPU_image_tiled_mapping(mat, ima, iuser));
+ GPU_stack_link(mat, node, gpu_node_name, in, out, gpu_image, gpu_image_tile_mapping);
}
else {
+ const char *gpu_node_name = use_cubic ? "node_tex_image_cubic" : "node_tex_image_linear";
+
switch (tex->projection) {
- case SHD_PROJ_FLAT:
- if (do_texco_clip) {
- /* This seems redundant, but is required to ensure the texco link
- * is not freed by GPU_link, as it is still needed for GPU_stack_link.
- * Intermediate links like this can only be used once and are then
- * freed immediately, but if we make it the output link of a set_rgb
- * node it will be kept and can be used multiple times. */
- GPU_link(mat, "set_rgb", *texco, texco);
- GPU_link(mat, "set_rgb", *texco, &input_coords);
- }
- if (do_texco_extend) {
- GPU_link(mat, "point_texco_clamp", *texco, GPU_image(mat, ima, iuser), texco);
- }
- GPU_stack_link(mat, node, gpu_node_name, in, out, GPU_image(mat, ima, iuser));
+ case SHD_PROJ_FLAT: {
+ GPUNodeLink *gpu_image = GPU_image(mat, ima, iuser, sampler_state);
+ GPU_stack_link(mat, node, gpu_node_name, in, out, gpu_image);
break;
-
- case SHD_PROJ_BOX:
- vnor = GPU_builtin(GPU_WORLD_NORMAL);
- ob_mat = GPU_builtin(GPU_OBJECT_MATRIX);
- blend = GPU_uniform(&tex->projection_blend);
- gpu_image = GPU_image(mat, ima, iuser);
-
+ }
+ case SHD_PROJ_BOX: {
+ gpu_node_name = use_cubic ? "tex_box_sample_cubic" : "tex_box_sample_linear";
+ GPUNodeLink *wnor, *col1, *col2, *col3;
+ GPUNodeLink *vnor = GPU_builtin(GPU_WORLD_NORMAL);
+ GPUNodeLink *ob_mat = GPU_builtin(GPU_OBJECT_MATRIX);
+ GPUNodeLink *blend = GPU_uniform(&tex->projection_blend);
+ GPUNodeLink *gpu_image = GPU_image(mat, ima, iuser, sampler_state);
/* equivalent to normal_world_to_object */
- GPU_link(mat, "normal_transform_transposed_m4v3", vnor, ob_mat, &norm);
- GPU_link(
- mat, gpu_node_name, *texco, norm, GPU_image(mat, ima, iuser), &col1, &col2, &col3);
- GPU_stack_link(
- mat, node, "node_tex_image_box", in, out, norm, col1, col2, col3, gpu_image, blend);
+ GPU_link(mat, "normal_transform_transposed_m4v3", vnor, ob_mat, &wnor);
+ GPU_link(mat, gpu_node_name, in[0].link, wnor, gpu_image, &col1, &col2, &col3);
+ GPU_link(mat, "tex_box_blend", wnor, col1, col2, col3, blend, &out[0].link, &out[1].link);
break;
-
- case SHD_PROJ_SPHERE:
+ }
+ case SHD_PROJ_SPHERE: {
+ /* This projection is known to have a derivative discontinuity.
+ * Hide it by turning off mipmapping. */
+ sampler_state &= ~GPU_SAMPLER_MIPMAP;
+ GPUNodeLink *gpu_image = GPU_image(mat, ima, iuser, sampler_state);
GPU_link(mat, "point_texco_remap_square", *texco, texco);
GPU_link(mat, "point_map_to_sphere", *texco, texco);
- if (do_texco_clip) {
- /* See SHD_PROJ_FLAT for explanation. */
- GPU_link(mat, "set_rgb", *texco, texco);
- GPU_link(mat, "set_rgb", *texco, &input_coords);
- }
- if (do_texco_extend) {
- GPU_link(mat, "point_texco_clamp", *texco, GPU_image(mat, ima, iuser), texco);
- }
- GPU_stack_link(mat, node, gpu_node_name, in, out, GPU_image(mat, ima, iuser));
+ GPU_stack_link(mat, node, gpu_node_name, in, out, gpu_image);
break;
-
- case SHD_PROJ_TUBE:
+ }
+ case SHD_PROJ_TUBE: {
+ /* This projection is known to have a derivative discontinuity.
+ * Hide it by turning off mipmapping. */
+ sampler_state &= ~GPU_SAMPLER_MIPMAP;
+ GPUNodeLink *gpu_image = GPU_image(mat, ima, iuser, sampler_state);
GPU_link(mat, "point_texco_remap_square", *texco, texco);
GPU_link(mat, "point_map_to_tube", *texco, texco);
- if (do_texco_clip) {
- /* See SHD_PROJ_FLAT for explanation. */
- GPU_link(mat, "set_rgb", *texco, texco);
- GPU_link(mat, "set_rgb", *texco, &input_coords);
- }
- if (do_texco_extend) {
- GPU_link(mat, "point_texco_clamp", *texco, GPU_image(mat, ima, iuser), texco);
- }
- GPU_stack_link(mat, node, gpu_node_name, in, out, GPU_image(mat, ima, iuser));
+ GPU_stack_link(mat, node, gpu_node_name, in, out, gpu_image);
break;
- }
-
- if (tex->projection != SHD_PROJ_BOX) {
- if (do_texco_clip) {
- gpu_node_name = names_clip[tex->interpolation];
- in[0].link = input_coords;
- GPU_stack_link(mat, node, gpu_node_name, in, out, GPU_image(mat, ima, iuser), out[0].link);
}
}
}
diff --git a/source/blender/nodes/shader/nodes/node_shader_tex_musgrave.c b/source/blender/nodes/shader/nodes/node_shader_tex_musgrave.c
index fa98f9efb74..420c5b75926 100644
--- a/source/blender/nodes/shader/nodes/node_shader_tex_musgrave.c
+++ b/source/blender/nodes/shader/nodes/node_shader_tex_musgrave.c
@@ -137,6 +137,9 @@ static void node_shader_update_tex_musgrave(bNodeTree *UNUSED(ntree), bNode *nod
nodeSetSocketAvailability(inGainSock,
tex->musgrave_type == SHD_MUSGRAVE_HYBRID_MULTIFRACTAL ||
tex->musgrave_type == SHD_MUSGRAVE_RIDGED_MULTIFRACTAL);
+
+ bNodeSocket *outFacSock = nodeFindSocket(node, SOCK_OUT, "Fac");
+ node_sock_label(outFacSock, "Height");
}
void register_node_type_sh_tex_musgrave(void)
diff --git a/source/blender/nodes/shader/nodes/node_shader_tex_noise.c b/source/blender/nodes/shader/nodes/node_shader_tex_noise.c
index 2205a1a86a3..67268c102c5 100644
--- a/source/blender/nodes/shader/nodes/node_shader_tex_noise.c
+++ b/source/blender/nodes/shader/nodes/node_shader_tex_noise.c
@@ -26,6 +26,7 @@ static bNodeSocketTemplate sh_node_tex_noise_in[] = {
{SOCK_FLOAT, N_("W"), 0.0f, 0.0f, 0.0f, 0.0f, -1000.0f, 1000.0f},
{SOCK_FLOAT, N_("Scale"), 5.0f, 0.0f, 0.0f, 0.0f, -1000.0f, 1000.0f},
{SOCK_FLOAT, N_("Detail"), 2.0f, 0.0f, 0.0f, 0.0f, 0.0f, 16.0f},
+ {SOCK_FLOAT, N_("Roughness"), 0.5f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f, PROP_FACTOR},
{SOCK_FLOAT, N_("Distortion"), 0.0f, 0.0f, 0.0f, 0.0f, -1000.0f, 1000.0f},
{-1, ""},
};
@@ -90,7 +91,7 @@ void register_node_type_sh_tex_noise(void)
{
static bNodeType ntype;
- sh_node_type_base(&ntype, SH_NODE_TEX_NOISE, "Noise Texture", NODE_CLASS_TEXTURE, 0);
+ sh_fn_node_type_base(&ntype, SH_NODE_TEX_NOISE, "Noise Texture", NODE_CLASS_TEXTURE, 0);
node_type_socket_templates(&ntype, sh_node_tex_noise_in, sh_node_tex_noise_out);
node_type_init(&ntype, node_shader_init_tex_noise);
node_type_storage(
diff --git a/source/blender/nodes/shader/nodes/node_shader_tex_wave.c b/source/blender/nodes/shader/nodes/node_shader_tex_wave.c
index 0b6cd7ee4db..bba568ed5b7 100644
--- a/source/blender/nodes/shader/nodes/node_shader_tex_wave.c
+++ b/source/blender/nodes/shader/nodes/node_shader_tex_wave.c
@@ -27,6 +27,7 @@ static bNodeSocketTemplate sh_node_tex_wave_in[] = {
{SOCK_FLOAT, N_("Distortion"), 0.0f, 0.0f, 0.0f, 0.0f, -1000.0f, 1000.0f},
{SOCK_FLOAT, N_("Detail"), 2.0f, 0.0f, 0.0f, 0.0f, 0.0f, 16.0f},
{SOCK_FLOAT, N_("Detail Scale"), 1.0f, 0.0f, 0.0f, 0.0f, -1000.0f, 1000.0f},
+ {SOCK_FLOAT, N_("Detail Roughness"), 0.5f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f, PROP_FACTOR},
{SOCK_FLOAT, N_("Phase Offset"), 0.0f, 0.0f, 0.0f, 0.0f, -1000.0f, 1000.0f},
{-1, ""},
};
diff --git a/source/blender/nodes/shader/nodes/node_shader_tex_white_noise.c b/source/blender/nodes/shader/nodes/node_shader_tex_white_noise.c
index 1789dc44bf1..817ccdc8b6a 100644
--- a/source/blender/nodes/shader/nodes/node_shader_tex_white_noise.c
+++ b/source/blender/nodes/shader/nodes/node_shader_tex_white_noise.c
@@ -72,7 +72,8 @@ void register_node_type_sh_tex_white_noise(void)
{
static bNodeType ntype;
- sh_node_type_base(&ntype, SH_NODE_TEX_WHITE_NOISE, "White Noise Texture", NODE_CLASS_TEXTURE, 0);
+ sh_fn_node_type_base(
+ &ntype, SH_NODE_TEX_WHITE_NOISE, "White Noise Texture", NODE_CLASS_TEXTURE, 0);
node_type_socket_templates(&ntype, sh_node_tex_white_noise_in, sh_node_tex_white_noise_out);
node_type_init(&ntype, node_shader_init_tex_white_noise);
node_type_gpu(&ntype, gpu_shader_tex_white_noise);
diff --git a/source/blender/nodes/shader/nodes/node_shader_valToRgb.c b/source/blender/nodes/shader/nodes/node_shader_valToRgb.c
index 49f9befdce3..20f280d00c3 100644
--- a/source/blender/nodes/shader/nodes/node_shader_valToRgb.c
+++ b/source/blender/nodes/shader/nodes/node_shader_valToRgb.c
@@ -125,7 +125,7 @@ void register_node_type_sh_valtorgb(void)
{
static bNodeType ntype;
- sh_node_type_base(&ntype, SH_NODE_VALTORGB, "ColorRamp", NODE_CLASS_CONVERTOR, 0);
+ sh_fn_node_type_base(&ntype, SH_NODE_VALTORGB, "ColorRamp", NODE_CLASS_CONVERTOR, 0);
node_type_socket_templates(&ntype, sh_node_valtorgb_in, sh_node_valtorgb_out);
node_type_init(&ntype, node_shader_init_valtorgb);
node_type_size_preset(&ntype, NODE_SIZE_LARGE);
diff --git a/source/blender/nodes/shader/nodes/node_shader_vector_math.c b/source/blender/nodes/shader/nodes/node_shader_vector_math.c
index 3a6e273eb20..b719fe03d9b 100644
--- a/source/blender/nodes/shader/nodes/node_shader_vector_math.c
+++ b/source/blender/nodes/shader/nodes/node_shader_vector_math.c
@@ -134,7 +134,7 @@ void register_node_type_sh_vect_math(void)
{
static bNodeType ntype;
- sh_node_type_base(&ntype, SH_NODE_VECTOR_MATH, "Vector Math", NODE_CLASS_OP_VECTOR, 0);
+ sh_fn_node_type_base(&ntype, SH_NODE_VECTOR_MATH, "Vector Math", NODE_CLASS_OP_VECTOR, 0);
node_type_socket_templates(&ntype, sh_node_vector_math_in, sh_node_vector_math_out);
node_type_label(&ntype, node_vector_math_label);
node_type_gpu(&ntype, gpu_shader_vector_math);
diff --git a/source/blender/nodes/shader/nodes/node_shader_volume_principled.c b/source/blender/nodes/shader/nodes/node_shader_volume_principled.c
index 92e1b3435c8..b581a4bd3a6 100644
--- a/source/blender/nodes/shader/nodes/node_shader_volume_principled.c
+++ b/source/blender/nodes/shader/nodes/node_shader_volume_principled.c
@@ -44,7 +44,7 @@ static bNodeSocketTemplate sh_node_volume_principled_out[] = {
static void node_shader_init_volume_principled(bNodeTree *UNUSED(ntree), bNode *node)
{
- for (bNodeSocket *sock = node->inputs.first; sock; sock = sock->next) {
+ LISTBASE_FOREACH (bNodeSocket *, sock, &node->inputs) {
if (STREQ(sock->name, "Density Attribute")) {
strcpy(((bNodeSocketValueString *)sock->default_value)->value, "density");
}
@@ -66,7 +66,7 @@ static int node_shader_gpu_volume_principled(GPUMaterial *mat,
/* Get volume attributes. */
GPUNodeLink *density = NULL, *color = NULL, *temperature = NULL;
- for (bNodeSocket *sock = node->inputs.first; sock; sock = sock->next) {
+ LISTBASE_FOREACH (bNodeSocket *, sock, &node->inputs) {
if (sock->typeinfo->type != SOCK_STRING) {
continue;
}
diff --git a/source/blender/nodes/simulation/node_simulation_tree.cc b/source/blender/nodes/simulation/node_simulation_tree.cc
new file mode 100644
index 00000000000..3f0e70259d6
--- /dev/null
+++ b/source/blender/nodes/simulation/node_simulation_tree.cc
@@ -0,0 +1,45 @@
+/*
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+
+#include <string.h>
+
+#include "MEM_guardedalloc.h"
+
+#include "NOD_simulation.h"
+
+#include "BKE_node.h"
+
+#include "BLT_translation.h"
+
+#include "DNA_node_types.h"
+
+#include "RNA_access.h"
+
+bNodeTreeType *ntreeType_Simulation;
+
+void register_node_tree_type_sim(void)
+{
+ bNodeTreeType *tt = ntreeType_Simulation = (bNodeTreeType *)MEM_callocN(
+ sizeof(bNodeTreeType), "simulation node tree type");
+ tt->type = NTREE_SIMULATION;
+ strcpy(tt->idname, "SimulationNodeTree");
+ strcpy(tt->ui_name, N_("Simulation Editor"));
+ tt->ui_icon = 0; /* defined in drawnode.c */
+ strcpy(tt->ui_description, N_("Simulation nodes"));
+ tt->rna_ext.srna = &RNA_SimulationNodeTree;
+
+ ntreeTypeAdd(tt);
+}
diff --git a/source/blender/nodes/simulation/node_simulation_util.cc b/source/blender/nodes/simulation/node_simulation_util.cc
new file mode 100644
index 00000000000..ae875335da8
--- /dev/null
+++ b/source/blender/nodes/simulation/node_simulation_util.cc
@@ -0,0 +1,29 @@
+/*
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+
+#include "node_simulation_util.h"
+#include "node_util.h"
+
+bool sim_node_poll_default(bNodeType *UNUSED(ntype), bNodeTree *ntree)
+{
+ return STREQ(ntree->idname, "SimulationNodeTree");
+}
+
+void sim_node_type_base(bNodeType *ntype, int type, const char *name, short nclass, short flag)
+{
+ node_type_base(ntype, type, name, nclass, flag);
+ ntype->poll = sim_node_poll_default;
+}
diff --git a/source/blender/nodes/simulation/node_simulation_util.h b/source/blender/nodes/simulation/node_simulation_util.h
new file mode 100644
index 00000000000..adbe2ad5e8f
--- /dev/null
+++ b/source/blender/nodes/simulation/node_simulation_util.h
@@ -0,0 +1,40 @@
+/*
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+
+#ifndef __NODE_SIM_UTIL_H__
+#define __NODE_SIM_UTIL_H__
+
+#include <string.h>
+
+#include "BLI_utildefines.h"
+
+#include "MEM_guardedalloc.h"
+
+#include "DNA_node_types.h"
+
+#include "BKE_node.h"
+
+#include "BLT_translation.h"
+
+#include "NOD_simulation.h"
+
+#include "node_util.h"
+
+void sim_node_type_base(
+ struct bNodeType *ntype, int type, const char *name, short nclass, short flag);
+bool sim_node_poll_default(struct bNodeType *ntype, struct bNodeTree *ntree);
+
+#endif /* __NODE_SIM_UTIL_H__ */
diff --git a/source/blender/nodes/simulation/nodes/node_sim_common.cc b/source/blender/nodes/simulation/nodes/node_sim_common.cc
new file mode 100644
index 00000000000..fbc03905d4f
--- /dev/null
+++ b/source/blender/nodes/simulation/nodes/node_sim_common.cc
@@ -0,0 +1,45 @@
+/*
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+
+#include "BKE_node.h"
+
+#include "NOD_simulation.h"
+
+#include "NOD_common.h"
+#include "node_common.h"
+#include "node_simulation_util.h"
+
+void register_node_type_sim_group(void)
+{
+ static bNodeType ntype;
+
+ node_type_base_custom(&ntype, "SimulationNodeGroup", "Group", 0, 0);
+ ntype.type = NODE_GROUP;
+ ntype.poll = sim_node_poll_default;
+ ntype.poll_instance = node_group_poll_instance;
+ ntype.insert_link = node_insert_link_default;
+ ntype.update_internal_links = node_update_internal_links_default;
+ ntype.rna_ext.srna = RNA_struct_find("SimulationNodeGroup");
+ BLI_assert(ntype.rna_ext.srna != NULL);
+ RNA_struct_blender_type_set(ntype.rna_ext.srna, &ntype);
+
+ node_type_socket_templates(&ntype, NULL, NULL);
+ node_type_size(&ntype, 140, 60, 400);
+ node_type_label(&ntype, node_group_label);
+ node_type_group_update(&ntype, node_group_update);
+
+ nodeRegisterType(&ntype);
+}
diff --git a/source/blender/nodes/simulation/nodes/node_sim_emit_particles.cc b/source/blender/nodes/simulation/nodes/node_sim_emit_particles.cc
new file mode 100644
index 00000000000..e23984dbf34
--- /dev/null
+++ b/source/blender/nodes/simulation/nodes/node_sim_emit_particles.cc
@@ -0,0 +1,38 @@
+/*
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+
+#include "node_simulation_util.h"
+
+static bNodeSocketTemplate sim_node_emit_particle_in[] = {
+ {SOCK_INT, N_("Amount"), 10, 0, 0, 0, 0, 10000000},
+ {SOCK_CONTROL_FLOW, N_("Execute")},
+ {-1, ""},
+};
+
+static bNodeSocketTemplate sim_node_emit_particle_out[] = {
+ {SOCK_CONTROL_FLOW, N_("Execute")},
+ {SOCK_EMITTERS, N_("Emitter")},
+ {-1, ""},
+};
+
+void register_node_type_sim_emit_particles()
+{
+ static bNodeType ntype;
+
+ sim_node_type_base(&ntype, SIM_NODE_EMIT_PARTICLES, "Emit Particles", 0, 0);
+ node_type_socket_templates(&ntype, sim_node_emit_particle_in, sim_node_emit_particle_out);
+ nodeRegisterType(&ntype);
+}
diff --git a/source/blender/nodes/simulation/nodes/node_sim_execute_condition.cc b/source/blender/nodes/simulation/nodes/node_sim_execute_condition.cc
new file mode 100644
index 00000000000..69f30d1ad0d
--- /dev/null
+++ b/source/blender/nodes/simulation/nodes/node_sim_execute_condition.cc
@@ -0,0 +1,39 @@
+/*
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+
+#include "node_simulation_util.h"
+
+static bNodeSocketTemplate sim_node_execute_condition_in[] = {
+ {SOCK_BOOLEAN, N_("Condition")},
+ {SOCK_CONTROL_FLOW, N_("If True")},
+ {SOCK_CONTROL_FLOW, N_("If False")},
+ {-1, ""},
+};
+
+static bNodeSocketTemplate sim_node_execute_condition_out[] = {
+ {SOCK_CONTROL_FLOW, N_("Execute")},
+ {-1, ""},
+};
+
+void register_node_type_sim_execute_condition()
+{
+ static bNodeType ntype;
+
+ sim_node_type_base(&ntype, SIM_NODE_EXECUTE_CONDITION, "Execute Condition", 0, 0);
+ node_type_socket_templates(
+ &ntype, sim_node_execute_condition_in, sim_node_execute_condition_out);
+ nodeRegisterType(&ntype);
+}
diff --git a/source/blender/nodes/simulation/nodes/node_sim_force.cc b/source/blender/nodes/simulation/nodes/node_sim_force.cc
new file mode 100644
index 00000000000..eccd2e4e2ab
--- /dev/null
+++ b/source/blender/nodes/simulation/nodes/node_sim_force.cc
@@ -0,0 +1,36 @@
+/*
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+
+#include "node_simulation_util.h"
+
+static bNodeSocketTemplate sim_node_force_in[] = {
+ {SOCK_VECTOR, N_("Force"), 0.0f, 0.0f, 0.0f, 0.0f, -10000.0f, 10000.0f},
+ {-1, ""},
+};
+
+static bNodeSocketTemplate sim_node_force_out[] = {
+ {SOCK_FORCES, N_("Force")},
+ {-1, ""},
+};
+
+void register_node_type_sim_force()
+{
+ static bNodeType ntype;
+
+ sim_node_type_base(&ntype, SIM_NODE_FORCE, "Force", 0, 0);
+ node_type_socket_templates(&ntype, sim_node_force_in, sim_node_force_out);
+ nodeRegisterType(&ntype);
+}
diff --git a/source/blender/nodes/simulation/nodes/node_sim_multi_execute.cc b/source/blender/nodes/simulation/nodes/node_sim_multi_execute.cc
new file mode 100644
index 00000000000..5944db7e2bc
--- /dev/null
+++ b/source/blender/nodes/simulation/nodes/node_sim_multi_execute.cc
@@ -0,0 +1,38 @@
+/*
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+
+#include "node_simulation_util.h"
+
+static bNodeSocketTemplate sim_node_multi_execute_in[] = {
+ {SOCK_CONTROL_FLOW, "1"},
+ {SOCK_CONTROL_FLOW, "2"},
+ {SOCK_CONTROL_FLOW, "3"},
+ {-1, ""},
+};
+
+static bNodeSocketTemplate sim_node_multi_execute_out[] = {
+ {SOCK_CONTROL_FLOW, N_("Execute")},
+ {-1, ""},
+};
+
+void register_node_type_sim_multi_execute()
+{
+ static bNodeType ntype;
+
+ sim_node_type_base(&ntype, SIM_NODE_MULTI_EXECUTE, "Multi Execute", 0, 0);
+ node_type_socket_templates(&ntype, sim_node_multi_execute_in, sim_node_multi_execute_out);
+ nodeRegisterType(&ntype);
+}
diff --git a/source/blender/nodes/simulation/nodes/node_sim_particle_attribute.cc b/source/blender/nodes/simulation/nodes/node_sim_particle_attribute.cc
new file mode 100644
index 00000000000..b6b67ee334e
--- /dev/null
+++ b/source/blender/nodes/simulation/nodes/node_sim_particle_attribute.cc
@@ -0,0 +1,52 @@
+/*
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+
+#include "BLI_listbase.h"
+#include "node_simulation_util.h"
+
+static bNodeSocketTemplate sim_node_particle_attribute_in[] = {
+ {SOCK_STRING, N_("Name")},
+ {-1, ""},
+};
+
+static bNodeSocketTemplate sim_node_particle_attribute_out[] = {
+ {SOCK_FLOAT, N_("Float")},
+ {SOCK_INT, N_("Int")},
+ {SOCK_BOOLEAN, N_("Boolean")},
+ {SOCK_VECTOR, N_("Vector")},
+ {SOCK_RGBA, N_("Color")},
+ {SOCK_OBJECT, N_("Object")},
+ {SOCK_IMAGE, N_("Image")},
+ {-1, ""},
+};
+
+static void sim_node_particle_attribute_update(bNodeTree *UNUSED(ntree), bNode *node)
+{
+ LISTBASE_FOREACH (bNodeSocket *, sock, &node->outputs) {
+ nodeSetSocketAvailability(sock, sock->type == node->custom1);
+ }
+}
+
+void register_node_type_sim_particle_attribute()
+{
+ static bNodeType ntype;
+
+ sim_node_type_base(&ntype, SIM_NODE_PARTICLE_ATTRIBUTE, "Particle Attribute", 0, 0);
+ node_type_socket_templates(
+ &ntype, sim_node_particle_attribute_in, sim_node_particle_attribute_out);
+ node_type_update(&ntype, sim_node_particle_attribute_update);
+ nodeRegisterType(&ntype);
+}
diff --git a/source/blender/nodes/simulation/nodes/node_sim_particle_birth_event.cc b/source/blender/nodes/simulation/nodes/node_sim_particle_birth_event.cc
new file mode 100644
index 00000000000..8332a3ecd9f
--- /dev/null
+++ b/source/blender/nodes/simulation/nodes/node_sim_particle_birth_event.cc
@@ -0,0 +1,37 @@
+/*
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+
+#include "node_simulation_util.h"
+
+static bNodeSocketTemplate sim_node_particle_birth_event_in[] = {
+ {SOCK_CONTROL_FLOW, N_("Execute")},
+ {-1, ""},
+};
+
+static bNodeSocketTemplate sim_node_particle_birth_event_out[] = {
+ {SOCK_EVENTS, N_("Event")},
+ {-1, ""},
+};
+
+void register_node_type_sim_particle_birth_event()
+{
+ static bNodeType ntype;
+
+ sim_node_type_base(&ntype, SIM_NODE_PARTICLE_BIRTH_EVENT, "Particle Birth Event", 0, 0);
+ node_type_socket_templates(
+ &ntype, sim_node_particle_birth_event_in, sim_node_particle_birth_event_out);
+ nodeRegisterType(&ntype);
+}
diff --git a/source/blender/nodes/simulation/nodes/node_sim_particle_mesh_collision_event.cc b/source/blender/nodes/simulation/nodes/node_sim_particle_mesh_collision_event.cc
new file mode 100644
index 00000000000..48671172136
--- /dev/null
+++ b/source/blender/nodes/simulation/nodes/node_sim_particle_mesh_collision_event.cc
@@ -0,0 +1,40 @@
+/*
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+
+#include "node_simulation_util.h"
+
+static bNodeSocketTemplate sim_node_particle_mesh_collision_event_in[] = {
+ {SOCK_OBJECT, N_("Object")},
+ {SOCK_CONTROL_FLOW, N_("Execute")},
+ {-1, ""},
+};
+
+static bNodeSocketTemplate sim_node_particle_mesh_collision_event_out[] = {
+ {SOCK_EVENTS, N_("Event")},
+ {-1, ""},
+};
+
+void register_node_type_sim_particle_mesh_collision_event()
+{
+ static bNodeType ntype;
+
+ sim_node_type_base(
+ &ntype, SIM_NODE_PARTICLE_MESH_COLLISION_EVENT, "Particle Mesh Collision Event", 0, 0);
+ node_type_socket_templates(&ntype,
+ sim_node_particle_mesh_collision_event_in,
+ sim_node_particle_mesh_collision_event_out);
+ nodeRegisterType(&ntype);
+}
diff --git a/source/blender/nodes/simulation/nodes/node_sim_particle_mesh_emitter.cc b/source/blender/nodes/simulation/nodes/node_sim_particle_mesh_emitter.cc
new file mode 100644
index 00000000000..2de7be2d3eb
--- /dev/null
+++ b/source/blender/nodes/simulation/nodes/node_sim_particle_mesh_emitter.cc
@@ -0,0 +1,40 @@
+/*
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+
+#include "node_simulation_util.h"
+
+#include "float.h"
+
+static bNodeSocketTemplate sim_node_particle_mesh_emitter_in[] = {
+ {SOCK_OBJECT, N_("Object")},
+ {SOCK_FLOAT, N_("Rate"), 10.0f, 0.0f, 0.0f, 0.0f, 0.0f, FLT_MAX},
+ {-1, ""},
+};
+
+static bNodeSocketTemplate sim_node_particle_mesh_emitter_out[] = {
+ {SOCK_EMITTERS, N_("Emitter")},
+ {-1, ""},
+};
+
+void register_node_type_sim_particle_mesh_emitter()
+{
+ static bNodeType ntype;
+
+ sim_node_type_base(&ntype, SIM_NODE_PARTICLE_MESH_EMITTER, "Mesh Emitter", 0, 0);
+ node_type_socket_templates(
+ &ntype, sim_node_particle_mesh_emitter_in, sim_node_particle_mesh_emitter_out);
+ nodeRegisterType(&ntype);
+}
diff --git a/source/blender/nodes/simulation/nodes/node_sim_particle_simulation.cc b/source/blender/nodes/simulation/nodes/node_sim_particle_simulation.cc
new file mode 100644
index 00000000000..159c9b23da1
--- /dev/null
+++ b/source/blender/nodes/simulation/nodes/node_sim_particle_simulation.cc
@@ -0,0 +1,39 @@
+/*
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+
+#include "node_simulation_util.h"
+
+static bNodeSocketTemplate sim_node_particle_simulation_in[] = {
+ {SOCK_EMITTERS, N_("Emitters")},
+ {SOCK_EVENTS, N_("Events")},
+ {SOCK_FORCES, N_("Forces")},
+ {-1, ""},
+};
+
+static bNodeSocketTemplate sim_node_particle_simulation_out[] = {
+ {-1, ""},
+};
+
+void register_node_type_sim_particle_simulation()
+{
+ static bNodeType ntype;
+
+ sim_node_type_base(
+ &ntype, SIM_NODE_PARTICLE_SIMULATION, "Particle Simulation", NODE_CLASS_OUTPUT, 0);
+ node_type_socket_templates(
+ &ntype, sim_node_particle_simulation_in, sim_node_particle_simulation_out);
+ nodeRegisterType(&ntype);
+}
diff --git a/source/blender/nodes/simulation/nodes/node_sim_particle_time_step_event.cc b/source/blender/nodes/simulation/nodes/node_sim_particle_time_step_event.cc
new file mode 100644
index 00000000000..cda8ddeb644
--- /dev/null
+++ b/source/blender/nodes/simulation/nodes/node_sim_particle_time_step_event.cc
@@ -0,0 +1,37 @@
+/*
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+
+#include "node_simulation_util.h"
+
+static bNodeSocketTemplate sim_node_particle_time_step_event_in[] = {
+ {SOCK_CONTROL_FLOW, N_("Execute")},
+ {-1, ""},
+};
+
+static bNodeSocketTemplate sim_node_particle_time_step_event_out[] = {
+ {SOCK_EVENTS, N_("Event")},
+ {-1, ""},
+};
+
+void register_node_type_sim_particle_time_step_event()
+{
+ static bNodeType ntype;
+
+ sim_node_type_base(&ntype, SIM_NODE_PARTICLE_TIME_STEP_EVENT, "Particle Time Step Event", 0, 0);
+ node_type_socket_templates(
+ &ntype, sim_node_particle_time_step_event_in, sim_node_particle_time_step_event_out);
+ nodeRegisterType(&ntype);
+}
diff --git a/source/blender/nodes/simulation/nodes/node_sim_set_particle_attribute.cc b/source/blender/nodes/simulation/nodes/node_sim_set_particle_attribute.cc
new file mode 100644
index 00000000000..8696dbe340c
--- /dev/null
+++ b/source/blender/nodes/simulation/nodes/node_sim_set_particle_attribute.cc
@@ -0,0 +1,57 @@
+/*
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+
+#include "BLI_listbase.h"
+#include "node_simulation_util.h"
+
+static bNodeSocketTemplate sim_node_set_particle_attribute_in[] = {
+ {SOCK_STRING, N_("Name")},
+ {SOCK_FLOAT, N_("Float"), 0.0f, 0.0f, 0.0f, 0.0f, -10000.0f, 10000.0f},
+ {SOCK_INT, N_("Int"), 0, 0, 0, 0, -10000, 10000},
+ {SOCK_BOOLEAN, N_("Boolean")},
+ {SOCK_VECTOR, N_("Vector")},
+ {SOCK_RGBA, N_("Color")},
+ {SOCK_OBJECT, N_("Object")},
+ {SOCK_IMAGE, N_("Image")},
+ {-1, ""},
+};
+
+static bNodeSocketTemplate sim_node_set_particle_attribute_out[] = {
+ {SOCK_CONTROL_FLOW, N_("Execute")},
+ {-1, ""},
+};
+
+static void sim_node_set_particle_attribute_update(bNodeTree *UNUSED(ntree), bNode *node)
+{
+ int index = 0;
+ LISTBASE_FOREACH (bNodeSocket *, sock, &node->inputs) {
+ if (index >= 1) {
+ nodeSetSocketAvailability(sock, sock->type == node->custom1);
+ }
+ index++;
+ }
+}
+
+void register_node_type_sim_set_particle_attribute()
+{
+ static bNodeType ntype;
+
+ sim_node_type_base(&ntype, SIM_NODE_SET_PARTICLE_ATTRIBUTE, "Set Particle Attribute", 0, 0);
+ node_type_socket_templates(
+ &ntype, sim_node_set_particle_attribute_in, sim_node_set_particle_attribute_out);
+ node_type_update(&ntype, sim_node_set_particle_attribute_update);
+ nodeRegisterType(&ntype);
+}
diff --git a/source/blender/nodes/simulation/nodes/node_sim_simulation_time.cc b/source/blender/nodes/simulation/nodes/node_sim_simulation_time.cc
new file mode 100644
index 00000000000..40e1c43fb69
--- /dev/null
+++ b/source/blender/nodes/simulation/nodes/node_sim_simulation_time.cc
@@ -0,0 +1,31 @@
+/*
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+
+#include "node_simulation_util.h"
+
+static bNodeSocketTemplate sim_node_time_out[] = {
+ {SOCK_FLOAT, N_("Time")},
+ {-1, ""},
+};
+
+void register_node_type_sim_time()
+{
+ static bNodeType ntype;
+
+ sim_node_type_base(&ntype, SIM_NODE_TIME, "Time", 0, 0);
+ node_type_socket_templates(&ntype, nullptr, sim_node_time_out);
+ nodeRegisterType(&ntype);
+}
diff --git a/source/blender/nodes/texture/node_texture_tree.c b/source/blender/nodes/texture/node_texture_tree.c
index cf5d39847cf..b3d595cc69b 100644
--- a/source/blender/nodes/texture/node_texture_tree.c
+++ b/source/blender/nodes/texture/node_texture_tree.c
@@ -172,7 +172,7 @@ void register_node_tree_type_tex(void)
tt->local_merge = local_merge;
tt->get_from_context = texture_get_from_context;
- tt->ext.srna = &RNA_TextureNodeTree;
+ tt->rna_ext.srna = &RNA_TextureNodeTree;
ntreeTypeAdd(tt);
}
@@ -282,7 +282,7 @@ int ntreeTexExecTree(bNodeTree *nodes,
float dyt[3],
int osatex,
const short thread,
- Tex *UNUSED(tex),
+ const Tex *UNUSED(tex),
short which_output,
int cfra,
int preview,
diff --git a/source/blender/nodes/texture/nodes/node_texture_common.c b/source/blender/nodes/texture/nodes/node_texture_common.c
index c83166f5ed6..0324cb38a73 100644
--- a/source/blender/nodes/texture/nodes/node_texture_common.c
+++ b/source/blender/nodes/texture/nodes/node_texture_common.c
@@ -167,9 +167,9 @@ void register_node_type_tex_group(void)
ntype.poll_instance = node_group_poll_instance;
ntype.insert_link = node_insert_link_default;
ntype.update_internal_links = node_update_internal_links_default;
- ntype.ext.srna = RNA_struct_find("TextureNodeGroup");
- BLI_assert(ntype.ext.srna != NULL);
- RNA_struct_blender_type_set(ntype.ext.srna, &ntype);
+ ntype.rna_ext.srna = RNA_struct_find("TextureNodeGroup");
+ BLI_assert(ntype.rna_ext.srna != NULL);
+ RNA_struct_blender_type_set(ntype.rna_ext.srna, &ntype);
node_type_socket_templates(&ntype, NULL, NULL);
node_type_size(&ntype, 140, 60, 400);
diff --git a/source/blender/physics/intern/BPH_mass_spring.cpp b/source/blender/physics/intern/BPH_mass_spring.cpp
index 76f0f8c8b55..6a951519730 100644
--- a/source/blender/physics/intern/BPH_mass_spring.cpp
+++ b/source/blender/physics/intern/BPH_mass_spring.cpp
@@ -23,7 +23,6 @@
#include "MEM_guardedalloc.h"
-extern "C" {
#include "DNA_cloth_types.h"
#include "DNA_meshdata_types.h"
#include "DNA_modifier_types.h"
@@ -38,7 +37,6 @@ extern "C" {
#include "BKE_cloth.h"
#include "BKE_collision.h"
#include "BKE_effect.h"
-}
#include "BPH_mass_spring.h"
#include "implicit.h"
diff --git a/source/blender/physics/intern/hair_volume.cpp b/source/blender/physics/intern/hair_volume.cpp
index b8783c51fe8..6246bf54f75 100644
--- a/source/blender/physics/intern/hair_volume.cpp
+++ b/source/blender/physics/intern/hair_volume.cpp
@@ -23,14 +23,12 @@
#include "MEM_guardedalloc.h"
-extern "C" {
#include "BLI_math.h"
#include "BLI_utildefines.h"
#include "DNA_texture_types.h"
#include "BKE_effect.h"
-}
#include "eigen_utils.h"
#include "implicit.h"
diff --git a/source/blender/python/BPY_extern.h b/source/blender/python/BPY_extern.h
index d4e57f0beb6..18d4c7da534 100644
--- a/source/blender/python/BPY_extern.h
+++ b/source/blender/python/BPY_extern.h
@@ -35,12 +35,12 @@ struct bContext;
struct bContextDataResult;
struct bPythonConstraint; /* DNA_constraint_types.h */
+#include "BLI_utildefines.h"
+
#ifdef __cplusplus
extern "C" {
#endif
-#include "BLI_utildefines.h"
-
void BPY_pyconstraint_exec(struct bPythonConstraint *con,
struct bConstraintOb *cob,
struct ListBase *targets);
diff --git a/source/blender/python/generic/idprop_py_api.c b/source/blender/python/generic/idprop_py_api.c
index ae9ffe4f3b8..cabeeba18b9 100644
--- a/source/blender/python/generic/idprop_py_api.c
+++ b/source/blender/python/generic/idprop_py_api.c
@@ -40,11 +40,11 @@ extern bool pyrna_id_FromPyObject(PyObject *obj, ID **id);
extern PyObject *pyrna_id_CreatePyObject(ID *id);
extern bool pyrna_id_CheckPyObject(PyObject *obj);
-/*********************** ID Property Main Wrapper Stuff ***************/
-
-/* ----------------------------------------------------------------------------
- * static conversion functions to avoid duplicate code, no type checking.
- */
+/* -------------------------------------------------------------------- */
+/** \name Python from ID-Property (Internal Conversions)
+ *
+ * Low level conversion to avoid duplicate code, no type checking.
+ * \{ */
static PyObject *idprop_py_from_idp_string(const IDProperty *prop)
{
@@ -124,7 +124,11 @@ static PyObject *idprop_py_from_idp_idparray(ID *id, IDProperty *prop)
return seq;
}
-/* -------------------------------------------------------------------------- */
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name IDProp Group Access
+ * \{ */
/* use for both array and group */
static Py_hash_t BPy_IDGroup_hash(BPy_IDProperty *self)
@@ -374,7 +378,11 @@ static const char *idp_try_read_name(PyObject *name_obj)
return name;
}
-/* -------------------------------------------------------------------------- */
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name ID-Property from Python (Internal Conversions)
+ * \{ */
/**
* The 'idp_from_Py*' functions expect that the input type has been checked before
@@ -658,7 +666,12 @@ static IDProperty *idp_from_PyObject(PyObject *name_obj, PyObject *ob)
}
}
-/* -------------------------------------------------------------------------- */
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Mapping Get/Set (Internal Access)
+ * \{ */
+
/**
* \note group can be a pointer array or a group.
* assume we already checked key is a string.
@@ -862,6 +875,12 @@ static PyObject *BPy_IDGroup_MapDataToPy(IDProperty *prop)
return NULL;
}
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name ID-Property Group Methods
+ * \{ */
+
PyDoc_STRVAR(
BPy_IDGroup_pop_doc,
".. method:: pop(key, default)\n"
@@ -1142,6 +1161,12 @@ static struct PyMethodDef BPy_IDGroup_methods[] = {
{NULL, NULL, 0, NULL},
};
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name ID-Property Group Type
+ * \{ */
+
static PySequenceMethods BPy_IDGroup_Seq = {
(lenfunc)BPy_IDGroup_Map_Len, /* lenfunc sq_length */
NULL, /* binaryfunc sq_concat */
@@ -1223,7 +1248,11 @@ PyTypeObject BPy_IDGroup_Type = {
BPy_IDGroup_getseters, /* struct PyGetSetDef *tp_getset; */
};
-/********Array Wrapper********/
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name ID Array Methods
+ * \{ */
static PyTypeObject *idp_array_py_type(BPy_IDArray *self, bool *r_is_double)
{
@@ -1567,6 +1596,10 @@ static PyBufferProcs BPy_IDArray_Buffer = {
(releasebufferproc)BPy_IDArray_releasebuffer,
};
+/* -------------------------------------------------------------------- */
+/** \name ID Array Type
+ * \{ */
+
PyTypeObject BPy_IDArray_Type = {
PyVarObject_HEAD_INIT(NULL, 0)
/* For printing, in format "<module>.<name>" */
@@ -1648,7 +1681,11 @@ PyTypeObject BPy_IDArray_Type = {
NULL,
};
-/*********** ID Property Group iterator ********/
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name ID-Property Group Iterator Type
+ * \{ */
static PyObject *IDGroup_Iter_repr(BPy_IDGroup_Iter *self)
{
@@ -1746,9 +1783,11 @@ void IDProp_Init_Types(void)
PyType_Ready(&BPy_IDArray_Type);
}
-/*----------------------------MODULE INIT-------------------------*/
+/** \} */
-/* --- */
+/* -------------------------------------------------------------------- */
+/** \name Public Module 'idprop.types'
+ * \{ */
static struct PyModuleDef IDProp_types_module_def = {
PyModuleDef_HEAD_INIT,
@@ -1784,7 +1823,11 @@ static PyObject *BPyInit_idprop_types(void)
return submodule;
}
-/* --- */
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Public Module 'idprop'
+ * \{ */
static PyMethodDef IDProp_methods[] = {
{NULL, NULL, 0, NULL},
@@ -1818,3 +1861,5 @@ PyObject *BPyInit_idprop(void)
return mod;
}
+
+/** \} */
diff --git a/source/blender/python/gpu/gpu_py_offscreen.c b/source/blender/python/gpu/gpu_py_offscreen.c
index 280f09d67c9..311cf2b8c73 100644
--- a/source/blender/python/gpu/gpu_py_offscreen.c
+++ b/source/blender/python/gpu/gpu_py_offscreen.c
@@ -40,6 +40,7 @@
#include "DNA_screen_types.h"
#include "DNA_view3d_types.h"
+#include "GPU_context.h"
#include "GPU_framebuffer.h"
#include "GPU_texture.h"
@@ -84,7 +85,7 @@ static PyObject *bpygpu_offscreen_new(PyTypeObject *UNUSED(self), PyObject *args
{
BPYGPU_IS_INIT_OR_ERROR_OBJ;
- GPUOffScreen *ofs;
+ GPUOffScreen *ofs = NULL;
int width, height, samples = 0;
char err_out[256];
@@ -94,7 +95,12 @@ static PyObject *bpygpu_offscreen_new(PyTypeObject *UNUSED(self), PyObject *args
return NULL;
}
- ofs = GPU_offscreen_create(width, height, samples, true, false, err_out);
+ if (GPU_context_active_get()) {
+ ofs = GPU_offscreen_create(width, height, samples, true, false, err_out);
+ }
+ else {
+ strncpy(err_out, "No active GPU context found", 256);
+ }
if (ofs == NULL) {
PyErr_Format(PyExc_RuntimeError,
diff --git a/source/blender/python/gpu/gpu_py_shader.c b/source/blender/python/gpu/gpu_py_shader.c
index bd52fbb0de5..165286c3661 100644
--- a/source/blender/python/gpu/gpu_py_shader.c
+++ b/source/blender/python/gpu/gpu_py_shader.c
@@ -78,7 +78,7 @@ static int bpygpu_uniform_location_get(GPUShader *shader,
const char *name,
const char *error_prefix)
{
- int uniform = GPU_shader_get_uniform_ensure(shader, name);
+ int uniform = GPU_shader_get_uniform(shader, name);
if (uniform == -1) {
PyErr_Format(PyExc_ValueError, "%s: uniform %.32s not found", error_prefix, name);
@@ -120,8 +120,8 @@ static PyObject *bpygpu_shader_new(PyTypeObject *UNUSED(type), PyObject *args, P
return NULL;
}
- GPUShader *shader = GPU_shader_create(
- params.vertexcode, params.fragcode, params.geocode, params.libcode, params.defines, NULL);
+ GPUShader *shader = GPU_shader_create_from_python(
+ params.vertexcode, params.fragcode, params.geocode, params.libcode, params.defines);
if (shader == NULL) {
PyErr_SetString(PyExc_Exception, "Shader Compile Error, see console for more details");
@@ -524,7 +524,7 @@ PyDoc_STRVAR(bpygpu_shader_calc_format_doc,
static PyObject *bpygpu_shader_calc_format(BPyGPUShader *self, PyObject *UNUSED(arg))
{
BPyGPUVertFormat *ret = (BPyGPUVertFormat *)BPyGPUVertFormat_CreatePyObject(NULL);
- GPU_vertformat_from_interface(&ret->fmt, GPU_shader_get_interface(self->shader));
+ GPU_vertformat_from_shader(&ret->fmt, self->shader);
return (PyObject *)ret;
}
@@ -609,6 +609,10 @@ PyDoc_STRVAR(
" To debug shaders, use the --debug-gpu-shaders command line option"
" to see full GLSL shader compilation and linking errors.\n"
"\n"
+ " For drawing user interface elements and gizmos, use "
+ " ``fragOutput = blender_srgb_to_framebuffer_space(fragOutput)``"
+ " to transform the output sRGB colors to the framebuffer colorspace."
+ "\n"
" :param vertexcode: Vertex shader code.\n"
" :type vertexcode: str\n"
" :param fragcode: Fragment shader code.\n"
diff --git a/source/blender/python/intern/CMakeLists.txt b/source/blender/python/intern/CMakeLists.txt
index 0b05a0dfcfe..769618005af 100644
--- a/source/blender/python/intern/CMakeLists.txt
+++ b/source/blender/python/intern/CMakeLists.txt
@@ -77,6 +77,7 @@ set(SRC
bpy_rna_driver.c
bpy_rna_gizmo.c
bpy_rna_id_collection.c
+ bpy_rna_types_capi.c
bpy_traceback.c
bpy_utils_previews.c
bpy_utils_units.c
@@ -113,6 +114,7 @@ set(SRC
bpy_rna_driver.h
bpy_rna_gizmo.h
bpy_rna_id_collection.h
+ bpy_rna_types_capi.h
bpy_traceback.h
bpy_utils_previews.h
bpy_utils_units.h
diff --git a/source/blender/python/intern/bpy.c b/source/blender/python/intern/bpy.c
index 5a36535f3e3..de8fd87db58 100644
--- a/source/blender/python/intern/bpy.c
+++ b/source/blender/python/intern/bpy.c
@@ -44,6 +44,7 @@
#include "bpy_rna.h"
#include "bpy_rna_gizmo.h"
#include "bpy_rna_id_collection.h"
+#include "bpy_rna_types_capi.h"
#include "bpy_utils_previews.h"
#include "bpy_utils_units.h"
@@ -379,10 +380,7 @@ void BPy_init_modules(void)
PyModule_AddObject(mod, "types", BPY_rna_types());
/* needs to be first so bpy_types can run */
- BPY_library_load_module(mod);
- BPY_library_write_module(mod);
-
- BPY_rna_id_collection_module(mod);
+ BPY_library_load_type_ready();
BPY_rna_gizmo_module(mod);
@@ -406,8 +404,8 @@ void BPy_init_modules(void)
PyModule_AddObject(mod, "context", (PyObject *)bpy_context_module);
- /* register bpy/rna classmethod callbacks */
- BPY_rna_register_cb();
+ /* Register methods and property get/set for RNA types. */
+ BPY_rna_types_extend_capi();
/* utility func's that have nowhere else to go */
PyModule_AddObject(mod,
diff --git a/source/blender/python/intern/bpy_app.c b/source/blender/python/intern/bpy_app.c
index a9bdef1c3e4..957d49eb04e 100644
--- a/source/blender/python/intern/bpy_app.c
+++ b/source/blender/python/intern/bpy_app.c
@@ -82,10 +82,10 @@ extern char build_system[];
static PyTypeObject BlenderAppType;
static PyStructSequence_Field app_info_fields[] = {
- {"version", "The Blender version as a tuple of 3 numbers. eg. (2, 50, 11)"},
+ {"version", "The Blender version as a tuple of 3 numbers. eg. (2, 83, 1)"},
{"version_string", "The Blender version formatted as a string"},
- {"version_char", "The Blender version character (for minor releases)"},
{"version_cycle", "The release status of this build alpha/beta/rc/release"},
+ {"version_char", "Deprecated, always an empty string"},
{"binary_path",
"The location of Blender's executable, useful for utilities that open new instances"},
{"background",
@@ -160,12 +160,12 @@ static PyObject *make_app_info(void)
#define SetBytesItem(str) PyStructSequence_SET_ITEM(app_info, pos++, PyBytes_FromString(str))
#define SetObjItem(obj) PyStructSequence_SET_ITEM(app_info, pos++, obj)
- SetObjItem(PyC_Tuple_Pack_I32(BLENDER_VERSION / 100, BLENDER_VERSION % 100, BLENDER_SUBVERSION));
- SetObjItem(PyUnicode_FromFormat(
- "%d.%02d (sub %d)", BLENDER_VERSION / 100, BLENDER_VERSION % 100, BLENDER_SUBVERSION));
+ SetObjItem(
+ PyC_Tuple_Pack_I32(BLENDER_VERSION / 100, BLENDER_VERSION % 100, BLENDER_VERSION_PATCH));
+ SetStrItem(BKE_blender_version_string());
- SetStrItem(STRINGIFY(BLENDER_VERSION_CHAR));
SetStrItem(STRINGIFY(BLENDER_VERSION_CYCLE));
+ SetStrItem("");
SetStrItem(BKE_appdir_program_path());
SetObjItem(PyBool_FromLong(G.background));
SetObjItem(PyBool_FromLong(G.factory_startup));
diff --git a/source/blender/python/intern/bpy_app_handlers.c b/source/blender/python/intern/bpy_app_handlers.c
index 28498e116df..dde1d13477f 100644
--- a/source/blender/python/intern/bpy_app_handlers.c
+++ b/source/blender/python/intern/bpy_app_handlers.c
@@ -44,8 +44,16 @@ void bpy_app_generic_callback(struct Main *main,
static PyTypeObject BlenderAppCbType;
static PyStructSequence_Field app_cb_info_fields[] = {
- {"frame_change_pre", "on frame change for playback and rendering (before)"},
- {"frame_change_post", "on frame change for playback and rendering (after)"},
+ {"frame_change_pre",
+ "Called after frame change for playback and rendering, before any data is evaluated for the "
+ "new frame. This makes it possible to change data and relations (for example swap an object "
+ "to another mesh) for the new frame. Note that this handler is **not** to be used as 'before "
+ "the frame changes' event. The dependency graph is not available in this handler, as data "
+ "and relations may have been altered and the dependency graph has not yet been updated for "
+ "that."},
+ {"frame_change_post",
+ "Called after frame change for playback and rendering, after the data has been evaluated "
+ "for the new frame."},
{"render_pre", "on render (before)"},
{"render_post", "on render (after)"},
{"render_write", "on writing a render frame (directly after the frame is written)"},
diff --git a/source/blender/python/intern/bpy_capi_utils.c b/source/blender/python/intern/bpy_capi_utils.c
index f63b77e1726..89ef2f40a30 100644
--- a/source/blender/python/intern/bpy_capi_utils.c
+++ b/source/blender/python/intern/bpy_capi_utils.c
@@ -24,6 +24,7 @@
#include <Python.h>
#include "BLI_dynstr.h"
+#include "BLI_listbase.h"
#include "BLI_utildefines.h"
#include "bpy_capi_utils.h"
@@ -91,7 +92,7 @@ void BPy_reports_write_stdout(const ReportList *reports, const char *header)
PySys_WriteStdout("%s\n", header);
}
- for (const Report *report = reports->list.first; report; report = report->next) {
+ LISTBASE_FOREACH (const Report *, report, &reports->list) {
PySys_WriteStdout("%s: %s\n", report->typestr, report->message);
}
}
diff --git a/source/blender/python/intern/bpy_driver.c b/source/blender/python/intern/bpy_driver.c
index 726599ff06e..50ae05694eb 100644
--- a/source/blender/python/intern/bpy_driver.c
+++ b/source/blender/python/intern/bpy_driver.c
@@ -33,7 +33,7 @@
#include "BLI_math_base.h"
#include "BLI_string.h"
-#include "BKE_fcurve.h"
+#include "BKE_fcurve_driver.h"
#include "BKE_global.h"
#include "bpy_rna_driver.h" /* for pyrna_driver_get_variable_value */
diff --git a/source/blender/python/intern/bpy_gizmo_wrap.c b/source/blender/python/intern/bpy_gizmo_wrap.c
index 8ff3af59930..774ad95c3eb 100644
--- a/source/blender/python/intern/bpy_gizmo_wrap.c
+++ b/source/blender/python/intern/bpy_gizmo_wrap.c
@@ -101,8 +101,8 @@ fail:
static void gizmo_properties_init(wmGizmoType *gzt)
{
- PyTypeObject *py_class = gzt->ext.data;
- RNA_struct_blender_type_set(gzt->ext.srna, gzt);
+ PyTypeObject *py_class = gzt->rna_ext.data;
+ RNA_struct_blender_type_set(gzt->rna_ext.srna, gzt);
/* only call this so pyrna_deferred_register_class gives a useful error
* WM_operatortype_append_ptr will call RNA_def_struct_identifier
@@ -160,9 +160,9 @@ void BPY_RNA_gizmo_wrapper(wmGizmoType *gzt, void *userdata)
/* don't do translations here yet */
#if 0
- /* Use i18n context from ext.srna if possible (py gizmogroups). */
- if (gt->ext.srna) {
- RNA_def_struct_translation_context(gt->srna, RNA_struct_translation_context(gt->ext.srna));
+ /* Use i18n context from rna_ext.srna if possible (py gizmogroups). */
+ if (gt->rna_ext.srna) {
+ RNA_def_struct_translation_context(gt->srna, RNA_struct_translation_context(gt->rna_ext.srna));
}
#endif
@@ -179,8 +179,8 @@ void BPY_RNA_gizmo_wrapper(wmGizmoType *gzt, void *userdata)
static void gizmogroup_properties_init(wmGizmoGroupType *gzgt)
{
- PyTypeObject *py_class = gzgt->ext.data;
- RNA_struct_blender_type_set(gzgt->ext.srna, gzgt);
+ PyTypeObject *py_class = gzgt->rna_ext.data;
+ RNA_struct_blender_type_set(gzgt->rna_ext.srna, gzgt);
/* only call this so pyrna_deferred_register_class gives a useful error
* WM_operatortype_append_ptr will call RNA_def_struct_identifier
@@ -203,9 +203,9 @@ void BPY_RNA_gizmogroup_wrapper(wmGizmoGroupType *gzgt, void *userdata)
/* don't do translations here yet */
#if 0
- /* Use i18n context from ext.srna if possible (py gizmogroups). */
- if (gzgt->ext.srna) {
- RNA_def_struct_translation_context(gzgt->srna, RNA_struct_translation_context(gzgt->ext.srna));
+ /* Use i18n context from rna_ext.srna if possible (py gizmogroups). */
+ if (gzgt->rna_ext.srna) {
+ RNA_def_struct_translation_context(gzgt->srna, RNA_struct_translation_context(gzgt->rna_ext.srna));
}
#endif
diff --git a/source/blender/python/intern/bpy_interface.c b/source/blender/python/intern/bpy_interface.c
index fdf7e127af9..6da1715b02d 100644
--- a/source/blender/python/intern/bpy_interface.c
+++ b/source/blender/python/intern/bpy_interface.c
@@ -279,9 +279,10 @@ void BPY_python_start(int argc, const char **argv)
* While harmless, it's noisy. */
Py_FrozenFlag = 1;
- /* Only use the systems environment variables when explicitly requested.
+ /* Only use the systems environment variables and site when explicitly requested.
* Since an incorrect 'PYTHONPATH' causes difficult to debug errors, see: T72807. */
Py_IgnoreEnvironmentFlag = !py_use_system_env;
+ Py_NoUserSiteDirectory = !py_use_system_env;
Py_Initialize();
@@ -940,7 +941,7 @@ static void bpy_module_delay_init(PyObject *bpy_proxy)
char filename_abs[1024];
BLI_strncpy(filename_abs, filename_rel, sizeof(filename_abs));
- BLI_path_cwd(filename_abs, sizeof(filename_abs));
+ BLI_path_abs_from_cwd(filename_abs, sizeof(filename_abs));
Py_DECREF(filename_obj);
argv[0] = filename_abs;
diff --git a/source/blender/python/intern/bpy_library.h b/source/blender/python/intern/bpy_library.h
index 3fd116d7028..6840807d2b0 100644
--- a/source/blender/python/intern/bpy_library.h
+++ b/source/blender/python/intern/bpy_library.h
@@ -21,7 +21,9 @@
#ifndef __BPY_LIBRARY_H__
#define __BPY_LIBRARY_H__
-int BPY_library_load_module(PyObject *mod_par);
-int BPY_library_write_module(PyObject *mod_par);
+int BPY_library_load_type_ready(void);
+extern PyMethodDef BPY_library_load_method_def;
+
+extern PyMethodDef BPY_library_write_method_def;
#endif /* __BPY_LIBRARY_H__ */
diff --git a/source/blender/python/intern/bpy_library_load.c b/source/blender/python/intern/bpy_library_load.c
index 989b7931444..05cbc9af601 100644
--- a/source/blender/python/intern/bpy_library_load.c
+++ b/source/blender/python/intern/bpy_library_load.c
@@ -459,15 +459,15 @@ static PyObject *bpy_lib_dir(BPy_Library *self)
return PyDict_Keys(self->dict);
}
-int BPY_library_load_module(PyObject *mod_par)
+PyMethodDef BPY_library_load_method_def = {
+ "load",
+ (PyCFunction)bpy_lib_load,
+ METH_STATIC | METH_VARARGS | METH_KEYWORDS,
+ bpy_lib_load_doc,
+};
+
+int BPY_library_load_type_ready(void)
{
- static PyMethodDef load_meth = {
- "load",
- (PyCFunction)bpy_lib_load,
- METH_STATIC | METH_VARARGS | METH_KEYWORDS,
- bpy_lib_load_doc,
- };
- PyModule_AddObject(mod_par, "_library_load", PyCFunction_New(&load_meth, NULL));
/* some compilers don't like accessing this directly, delay assignment */
bpy_lib_Type.tp_getattro = PyObject_GenericGetAttr;
diff --git a/source/blender/python/intern/bpy_library_write.c b/source/blender/python/intern/bpy_library_write.c
index 6c8f1deb126..fec0cef7b05 100644
--- a/source/blender/python/intern/bpy_library_write.c
+++ b/source/blender/python/intern/bpy_library_write.c
@@ -204,16 +204,9 @@ finally:
return ret;
}
-int BPY_library_write_module(PyObject *mod_par)
-{
- static PyMethodDef write_meth = {
- "write",
- (PyCFunction)bpy_lib_write,
- METH_STATIC | METH_VARARGS | METH_KEYWORDS,
- bpy_lib_write_doc,
- };
-
- PyModule_AddObject(mod_par, "_library_write", PyCFunction_New(&write_meth, NULL));
-
- return 0;
-}
+PyMethodDef BPY_library_write_method_def = {
+ "write",
+ (PyCFunction)bpy_lib_write,
+ METH_STATIC | METH_VARARGS | METH_KEYWORDS,
+ bpy_lib_write_doc,
+};
diff --git a/source/blender/python/intern/bpy_operator_wrap.c b/source/blender/python/intern/bpy_operator_wrap.c
index b7d3c99d3da..9fb25d41844 100644
--- a/source/blender/python/intern/bpy_operator_wrap.c
+++ b/source/blender/python/intern/bpy_operator_wrap.c
@@ -39,8 +39,8 @@
static void operator_properties_init(wmOperatorType *ot)
{
- PyTypeObject *py_class = ot->ext.data;
- RNA_struct_blender_type_set(ot->ext.srna, ot);
+ PyTypeObject *py_class = ot->rna_ext.data;
+ RNA_struct_blender_type_set(ot->rna_ext.srna, ot);
/* Only call this so pyrna_deferred_register_class gives a useful error
* WM_operatortype_append_ptr will call RNA_def_struct_identifier later.
@@ -123,9 +123,9 @@ void BPY_RNA_operator_wrapper(wmOperatorType *ot, void *userdata)
*ot = *((wmOperatorType *)userdata);
ot->srna = srna; /* restore */
- /* Use i18n context from ext.srna if possible (py operators). */
- if (ot->ext.srna) {
- RNA_def_struct_translation_context(ot->srna, RNA_struct_translation_context(ot->ext.srna));
+ /* Use i18n context from rna_ext.srna if possible (py operators). */
+ if (ot->rna_ext.srna) {
+ RNA_def_struct_translation_context(ot->srna, RNA_struct_translation_context(ot->rna_ext.srna));
}
operator_properties_init(ot);
@@ -142,11 +142,11 @@ void BPY_RNA_operator_macro_wrapper(wmOperatorType *ot, void *userdata)
ot->flag |= data->flag; /* append flags to the one set by registration */
ot->pyop_poll = data->pyop_poll;
ot->ui = data->ui;
- ot->ext = data->ext;
+ ot->rna_ext = data->rna_ext;
- /* Use i18n context from ext.srna if possible (py operators). */
- if (ot->ext.srna) {
- RNA_def_struct_translation_context(ot->srna, RNA_struct_translation_context(ot->ext.srna));
+ /* Use i18n context from rna_ext.srna if possible (py operators). */
+ if (ot->rna_ext.srna) {
+ RNA_def_struct_translation_context(ot->srna, RNA_struct_translation_context(ot->rna_ext.srna));
}
operator_properties_init(ot);
diff --git a/source/blender/python/intern/bpy_rna.c b/source/blender/python/intern/bpy_rna.c
index 9579f78be30..179daad2f60 100644
--- a/source/blender/python/intern/bpy_rna.c
+++ b/source/blender/python/intern/bpy_rna.c
@@ -4091,7 +4091,7 @@ static PyObject *pyrna_struct_bl_rna_get_subclass(PyObject *cls, PyObject *args)
if (srna_base == &RNA_Node) {
bNodeType *nt = nodeTypeFind(id);
if (nt) {
- RNA_pointer_create(NULL, &RNA_Struct, nt->ext.srna, &ptr);
+ RNA_pointer_create(NULL, &RNA_Struct, nt->rna_ext.srna, &ptr);
return pyrna_struct_CreatePyObject(&ptr);
}
}
@@ -9033,6 +9033,50 @@ static PyObject *pyrna_unregister_class(PyObject *UNUSED(self), PyObject *py_cla
Py_RETURN_NONE;
}
+/**
+ * Extend RNA types with C/API methods, properties.
+ */
+void pyrna_struct_type_extend_capi(struct StructRNA *srna,
+ struct PyMethodDef *method,
+ struct PyGetSetDef *getset)
+{
+ /* See 'add_methods' in Python's 'typeobject.c'. */
+ PyTypeObject *type = (PyTypeObject *)pyrna_srna_Subtype(srna);
+ PyObject *dict = type->tp_dict;
+ if (method != NULL) {
+ for (; method->ml_name != NULL; method++) {
+ PyObject *py_method;
+
+ if (method->ml_flags & METH_CLASS) {
+ PyObject *cfunc = PyCFunction_New(method, (PyObject *)type);
+ py_method = PyClassMethod_New(cfunc);
+ Py_DECREF(cfunc);
+ }
+ else {
+ /* Currently only static and class methods are used. */
+ BLI_assert(method->ml_flags & METH_STATIC);
+ py_method = PyCFunction_New(method, NULL);
+ }
+
+ int err = PyDict_SetItemString(dict, method->ml_name, py_method);
+ Py_DECREF(py_method);
+ BLI_assert(!(err < 0));
+ UNUSED_VARS_NDEBUG(err);
+ }
+ }
+
+ if (getset != NULL) {
+ for (; getset->name != NULL; getset++) {
+ PyObject *descr = PyDescr_NewGetSet(type, getset);
+ /* Ensure we're not overwriting anything that already exists. */
+ BLI_assert(PyDict_GetItem(dict, PyDescr_NAME(descr)) == NULL);
+ PyDict_SetItem(dict, PyDescr_NAME(descr), descr);
+ Py_DECREF(descr);
+ }
+ }
+ Py_DECREF(type);
+}
+
/* Access to 'owner_id' internal global. */
static PyObject *pyrna_bl_owner_id_get(PyObject *UNUSED(self))
@@ -9076,92 +9120,3 @@ PyMethodDef meth_bpy_owner_id_set = {
METH_O,
NULL,
};
-
-/* currently this is fairly limited, we would need to make some way to split up
- * pyrna_callback_classmethod_... if we want more than one callback per type */
-typedef struct BPyRNA_CallBack {
- PyMethodDef py_method;
- StructRNA *bpy_srna;
-} PyRNA_CallBack;
-
-PyDoc_STRVAR(
- pyrna_draw_handler_add_doc,
- ".. method:: draw_handler_add(callback, args, region_type, draw_type)\n"
- "\n"
- " Add a new draw handler to this space type.\n"
- " It will be called every time the specified region in the space type will be drawn.\n"
- " Note: All arguments are positional only for now.\n"
- "\n"
- " :param callback:\n"
- " A function that will be called when the region is drawn.\n"
- " It gets the specified arguments as input.\n"
- " :type callback: function\n"
- " :param args: Arguments that will be passed to the callback.\n"
- " :type args: tuple\n"
- " :param region_type: The region type the callback draws in; usually ``WINDOW``. "
- "(:class:`bpy.types.Region.type`)\n"
- " :type region_type: str\n"
- " :param draw_type: Usually ``POST_PIXEL`` for 2D drawing and ``POST_VIEW`` for 3D drawing. "
- "In some cases ``PRE_VIEW`` can be used. ``BACKDROP`` can be used for backdrops in the node "
- "editor.\n"
- " :type draw_type: str\n"
- " :return: Handler that can be removed later on.\n"
- " :rtype: object");
-
-PyDoc_STRVAR(pyrna_draw_handler_remove_doc,
- ".. method:: draw_handler_remove(handler, region_type)\n"
- "\n"
- " Remove a draw handler that was added previously.\n"
- "\n"
- " :param handler: The draw handler that should be removed.\n"
- " :type handler: object\n"
- " :param region_type: Region type the callback was added to.\n"
- " :type region_type: str\n");
-
-static struct BPyRNA_CallBack pyrna_cb_methods[] = {
- {{"draw_handler_add",
- (PyCFunction)pyrna_callback_classmethod_add,
- METH_VARARGS | METH_STATIC,
- pyrna_draw_handler_add_doc},
- &RNA_Space},
- {{"draw_handler_remove",
- (PyCFunction)pyrna_callback_classmethod_remove,
- METH_VARARGS | METH_STATIC,
- pyrna_draw_handler_remove_doc},
- &RNA_Space},
-
- {{"draw_cursor_add",
- (PyCFunction)pyrna_callback_classmethod_add,
- METH_VARARGS | METH_STATIC,
- ""},
- &RNA_WindowManager},
- {{"draw_cursor_remove",
- (PyCFunction)pyrna_callback_classmethod_remove,
- METH_VARARGS | METH_STATIC,
- ""},
- &RNA_WindowManager},
- {{NULL, NULL, 0, NULL}, NULL},
-};
-
-void BPY_rna_register_cb(void)
-{
- int i;
-
- for (i = 0; pyrna_cb_methods[i].bpy_srna; i++) {
- PyObject *cls;
- PyObject *func;
- PyObject *classmethod;
- PyObject *args = PyTuple_New(1);
-
- cls = pyrna_srna_Subtype(pyrna_cb_methods[i].bpy_srna);
- func = PyCFunction_New(&pyrna_cb_methods[i].py_method, NULL);
- PyTuple_SET_ITEM(args, 0, func);
- classmethod = PyObject_CallObject((PyObject *)&PyClassMethod_Type, args);
-
- PyObject_SetAttrString(cls, pyrna_cb_methods[i].py_method.ml_name, classmethod);
-
- Py_DECREF(classmethod);
- Py_DECREF(args); /* Clears 'func' too. */
- Py_DECREF(cls);
- }
-}
diff --git a/source/blender/python/intern/bpy_rna.h b/source/blender/python/intern/bpy_rna.h
index 5899c1659b5..652d65fe64c 100644
--- a/source/blender/python/intern/bpy_rna.h
+++ b/source/blender/python/intern/bpy_rna.h
@@ -185,7 +185,6 @@ PyObject *BPY_rna_module(void);
void BPY_update_rna_module(void);
/*PyObject *BPY_rna_doc(void);*/
PyObject *BPY_rna_types(void);
-void BPY_rna_register_cb(void);
PyObject *pyrna_struct_CreatePyObject(PointerRNA *ptr);
PyObject *pyrna_prop_CreatePyObject(PointerRNA *ptr, PropertyRNA *prop);
@@ -221,6 +220,10 @@ int pyrna_enum_value_from_id(const EnumPropertyItem *item,
int pyrna_deferred_register_class(struct StructRNA *srna, PyTypeObject *py_class);
+void pyrna_struct_type_extend_capi(struct StructRNA *srna,
+ struct PyMethodDef *py_method,
+ struct PyGetSetDef *py_getset);
+
/* called before stopping python */
void pyrna_alloc_types(void);
void pyrna_free_types(void);
diff --git a/source/blender/python/intern/bpy_rna_anim.c b/source/blender/python/intern/bpy_rna_anim.c
index c8af6377d59..d792b2032b5 100644
--- a/source/blender/python/intern/bpy_rna_anim.c
+++ b/source/blender/python/intern/bpy_rna_anim.c
@@ -35,7 +35,7 @@
#include "ED_keyframes_edit.h"
#include "ED_keyframing.h"
-#include "BKE_animsys.h"
+#include "BKE_anim_data.h"
#include "BKE_context.h"
#include "BKE_fcurve.h"
#include "BKE_global.h"
@@ -354,7 +354,7 @@ PyObject *pyrna_struct_keyframe_insert(BPy_StructRNA *self, PyObject *args, PyOb
if (prop) {
NlaStrip *strip = ptr.data;
- FCurve *fcu = list_find_fcurve(&strip->fcurves, RNA_property_identifier(prop), index);
+ FCurve *fcu = BKE_fcurve_find(&strip->fcurves, RNA_property_identifier(prop), index);
result = insert_keyframe_direct(&reports, ptr, prop, fcu, cfra, keytype, NULL, options);
}
@@ -462,7 +462,7 @@ PyObject *pyrna_struct_keyframe_delete(BPy_StructRNA *self, PyObject *args, PyOb
if (prop) {
ID *id = ptr.owner_id;
NlaStrip *strip = ptr.data;
- FCurve *fcu = list_find_fcurve(&strip->fcurves, RNA_property_identifier(prop), index);
+ FCurve *fcu = BKE_fcurve_find(&strip->fcurves, RNA_property_identifier(prop), index);
/* NOTE: This should be true, or else we wouldn't be able to get here. */
BLI_assert(fcu != NULL);
@@ -577,13 +577,13 @@ PyObject *pyrna_struct_driver_add(BPy_StructRNA *self, PyObject *args)
if (index == -1) { /* all, use a list */
int i = 0;
ret = PyList_New(0);
- while ((fcu = list_find_fcurve(&adt->drivers, path_full, i++))) {
+ while ((fcu = BKE_fcurve_find(&adt->drivers, path_full, i++))) {
RNA_pointer_create(id, &RNA_FCurve, fcu, &tptr);
PyList_APPEND(ret, pyrna_struct_CreatePyObject(&tptr));
}
}
else {
- fcu = list_find_fcurve(&adt->drivers, path_full, index);
+ fcu = BKE_fcurve_find(&adt->drivers, path_full, index);
RNA_pointer_create(id, &RNA_FCurve, fcu, &tptr);
ret = pyrna_struct_CreatePyObject(&tptr);
}
diff --git a/source/blender/python/intern/bpy_rna_callback.c b/source/blender/python/intern/bpy_rna_callback.c
index cc9f5746bba..f9bcb8943f4 100644
--- a/source/blender/python/intern/bpy_rna_callback.c
+++ b/source/blender/python/intern/bpy_rna_callback.c
@@ -324,10 +324,8 @@ PyObject *pyrna_callback_classmethod_add(PyObject *UNUSED(self), PyObject *args)
return NULL;
}
- bContext *C = BPy_GetContext();
- struct wmWindowManager *wm = CTX_wm_manager(C);
handle = WM_paint_cursor_activate(
- wm, params.space_type, params.region_type, NULL, cb_wm_cursor_draw, (void *)args);
+ params.space_type, params.region_type, NULL, cb_wm_cursor_draw, (void *)args);
}
else if (RNA_struct_is_a(srna, &RNA_Space)) {
const char *error_prefix = "Space.draw_handler_add";
@@ -424,9 +422,7 @@ PyObject *pyrna_callback_classmethod_remove(PyObject *UNUSED(self), PyObject *ar
args, "OO!:WindowManager.draw_cursor_remove", &cls, &PyCapsule_Type, &py_handle)) {
return NULL;
}
- bContext *C = BPy_GetContext();
- struct wmWindowManager *wm = CTX_wm_manager(C);
- WM_paint_cursor_end(wm, handle);
+ WM_paint_cursor_end(handle);
capsule_clear = true;
}
else if (RNA_struct_is_a(srna, &RNA_Space)) {
diff --git a/source/blender/python/intern/bpy_rna_driver.c b/source/blender/python/intern/bpy_rna_driver.c
index a8d8252b231..9240e34bbab 100644
--- a/source/blender/python/intern/bpy_rna_driver.c
+++ b/source/blender/python/intern/bpy_rna_driver.c
@@ -26,7 +26,7 @@
#include "BLI_utildefines.h"
-#include "BKE_fcurve.h"
+#include "BKE_fcurve_driver.h"
#include "RNA_access.h"
diff --git a/source/blender/python/intern/bpy_rna_id_collection.c b/source/blender/python/intern/bpy_rna_id_collection.c
index 6b6ffa97995..b607f1635e6 100644
--- a/source/blender/python/intern/bpy_rna_id_collection.c
+++ b/source/blender/python/intern/bpy_rna_id_collection.c
@@ -385,32 +385,21 @@ static PyObject *bpy_orphans_purge(PyObject *UNUSED(self),
return Py_None;
}
-int BPY_rna_id_collection_module(PyObject *mod_par)
-{
- static PyMethodDef user_map = {
- "user_map", (PyCFunction)bpy_user_map, METH_VARARGS | METH_KEYWORDS, bpy_user_map_doc};
-
- PyModule_AddObject(mod_par, "_rna_id_collection_user_map", PyCFunction_New(&user_map, NULL));
-
- static PyMethodDef batch_remove = {
- "batch_remove",
- (PyCFunction)bpy_batch_remove,
- METH_VARARGS | METH_KEYWORDS,
- bpy_batch_remove_doc,
- };
-
- PyModule_AddObject(
- mod_par, "_rna_id_collection_batch_remove", PyCFunction_New(&batch_remove, NULL));
-
- static PyMethodDef orphans_purge = {
- "orphans_purge",
- (PyCFunction)bpy_orphans_purge,
- METH_VARARGS | METH_KEYWORDS,
- bpy_orphans_purge_doc,
- };
-
- PyModule_AddObject(
- mod_par, "_rna_id_collection_orphans_purge", PyCFunction_New(&orphans_purge, NULL));
-
- return 0;
-}
+PyMethodDef BPY_rna_id_collection_user_map_method_def = {
+ "user_map",
+ (PyCFunction)bpy_user_map,
+ METH_STATIC | METH_VARARGS | METH_KEYWORDS,
+ bpy_user_map_doc,
+};
+PyMethodDef BPY_rna_id_collection_batch_remove_method_def = {
+ "batch_remove",
+ (PyCFunction)bpy_batch_remove,
+ METH_STATIC | METH_VARARGS | METH_KEYWORDS,
+ bpy_batch_remove_doc,
+};
+PyMethodDef BPY_rna_id_collection_orphans_purge_method_def = {
+ "orphans_purge",
+ (PyCFunction)bpy_orphans_purge,
+ METH_STATIC | METH_VARARGS | METH_KEYWORDS,
+ bpy_orphans_purge_doc,
+};
diff --git a/source/blender/python/intern/bpy_rna_id_collection.h b/source/blender/python/intern/bpy_rna_id_collection.h
index 8cb375960a9..ee8f4c666a8 100644
--- a/source/blender/python/intern/bpy_rna_id_collection.h
+++ b/source/blender/python/intern/bpy_rna_id_collection.h
@@ -21,6 +21,8 @@
#ifndef __BPY_RNA_ID_COLLECTION_H__
#define __BPY_RNA_ID_COLLECTION_H__
-int BPY_rna_id_collection_module(PyObject *);
+extern PyMethodDef BPY_rna_id_collection_user_map_method_def;
+extern PyMethodDef BPY_rna_id_collection_batch_remove_method_def;
+extern PyMethodDef BPY_rna_id_collection_orphans_purge_method_def;
#endif /* __BPY_RNA_ID_COLLECTION_H__ */
diff --git a/source/blender/python/intern/bpy_rna_types_capi.c b/source/blender/python/intern/bpy_rna_types_capi.c
new file mode 100644
index 00000000000..5a2ba4a5cdb
--- /dev/null
+++ b/source/blender/python/intern/bpy_rna_types_capi.c
@@ -0,0 +1,216 @@
+/*
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+
+/** \file
+ * \ingroup pythonintern
+ *
+ * This file extends RNA types from `bpy.types` with C/Python API methods and attributes.
+ *
+ * We should avoid adding code here, and prefer:
+ * - `source/blender/makesrna/intern/rna_context.c` using the RNA C API.
+ * - `release/scripts/modules/bpy_types.py` when additions c an be written in Python.
+ *
+ * Otherwise functions can be added here as a last resort.
+ */
+
+#include <Python.h>
+#include <descrobject.h>
+
+#include "RNA_types.h"
+
+#include "BLI_utildefines.h"
+
+#include "bpy_library.h"
+#include "bpy_rna.h"
+#include "bpy_rna_callback.h"
+#include "bpy_rna_id_collection.h"
+#include "bpy_rna_types_capi.h"
+
+#include "../generic/py_capi_utils.h"
+
+#include "RNA_access.h"
+
+#include "MEM_guardedalloc.h"
+
+#include "WM_api.h"
+
+/* -------------------------------------------------------------------- */
+/** \name Blend Data
+ * \{ */
+
+static struct PyMethodDef pyrna_blenddata_methods[] = {
+ {NULL, NULL, 0, NULL}, /* #BPY_rna_id_collection_user_map_method_def */
+ {NULL, NULL, 0, NULL}, /* #BPY_rna_id_collection_batch_remove_method_def */
+ {NULL, NULL, 0, NULL}, /* #BPY_rna_id_collection_orphans_purge_method_def */
+ {NULL, NULL, 0, NULL},
+};
+
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Blend Data Libraries
+ * \{ */
+
+static struct PyMethodDef pyrna_blenddatalibraries_methods[] = {
+ {NULL, NULL, 0, NULL}, /* #BPY_library_load_method_def */
+ {NULL, NULL, 0, NULL}, /* #BPY_library_write_method_def */
+ {NULL, NULL, 0, NULL},
+};
+
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Window Manager Clipboard Property
+ *
+ * Avoid using the RNA API because this value may change between checking it's length
+ * and creating the buffer, causing writes past the allocated length.
+ * \{ */
+
+static PyObject *pyrna_WindowManager_clipboard_get(PyObject *UNUSED(self), void *UNUSED(flag))
+{
+ int text_len = 0;
+ char *text = WM_clipboard_text_get(false, &text_len);
+ PyObject *result = PyC_UnicodeFromByteAndSize(text ? text : "", text_len);
+ if (text != NULL) {
+ MEM_freeN(text);
+ }
+ return result;
+}
+
+static int pyrna_WindowManager_clipboard_set(PyObject *UNUSED(self),
+ PyObject *value,
+ void *UNUSED(flag))
+{
+ PyObject *value_coerce = NULL;
+ const char *text = PyC_UnicodeAsByte(value, &value_coerce);
+ if (text == NULL) {
+ return -1;
+ }
+ WM_clipboard_text_set(text, false);
+ Py_XDECREF(value_coerce);
+ return 0;
+}
+
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Window Manager Type
+ * \{ */
+
+static struct PyMethodDef pyrna_windowmanager_methods[] = {
+ {"draw_cursor_add",
+ (PyCFunction)pyrna_callback_classmethod_add,
+ METH_VARARGS | METH_CLASS,
+ ""},
+ {"draw_cursor_remove",
+ (PyCFunction)pyrna_callback_classmethod_remove,
+ METH_VARARGS | METH_CLASS,
+ ""},
+ {NULL, NULL, 0, NULL},
+};
+
+static struct PyGetSetDef pyrna_windowmanager_getset[] = {
+ {"clipboard",
+ pyrna_WindowManager_clipboard_get,
+ pyrna_WindowManager_clipboard_set,
+ NULL,
+ NULL},
+ {NULL, NULL, NULL, NULL, NULL} /* Sentinel */
+};
+
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Space Type
+ * \{ */
+
+PyDoc_STRVAR(
+ pyrna_draw_handler_add_doc,
+ ".. method:: draw_handler_add(callback, args, region_type, draw_type)\n"
+ "\n"
+ " Add a new draw handler to this space type.\n"
+ " It will be called every time the specified region in the space type will be drawn.\n"
+ " Note: All arguments are positional only for now.\n"
+ "\n"
+ " :param callback:\n"
+ " A function that will be called when the region is drawn.\n"
+ " It gets the specified arguments as input.\n"
+ " :type callback: function\n"
+ " :param args: Arguments that will be passed to the callback.\n"
+ " :type args: tuple\n"
+ " :param region_type: The region type the callback draws in; usually ``WINDOW``. "
+ "(:class:`bpy.types.Region.type`)\n"
+ " :type region_type: str\n"
+ " :param draw_type: Usually ``POST_PIXEL`` for 2D drawing and ``POST_VIEW`` for 3D drawing. "
+ "In some cases ``PRE_VIEW`` can be used. ``BACKDROP`` can be used for backdrops in the node "
+ "editor.\n"
+ " :type draw_type: str\n"
+ " :return: Handler that can be removed later on.\n"
+ " :rtype: object");
+
+PyDoc_STRVAR(pyrna_draw_handler_remove_doc,
+ ".. method:: draw_handler_remove(handler, region_type)\n"
+ "\n"
+ " Remove a draw handler that was added previously.\n"
+ "\n"
+ " :param handler: The draw handler that should be removed.\n"
+ " :type handler: object\n"
+ " :param region_type: Region type the callback was added to.\n"
+ " :type region_type: str\n");
+
+static struct PyMethodDef pyrna_space_methods[] = {
+ {"draw_handler_add",
+ (PyCFunction)pyrna_callback_classmethod_add,
+ METH_VARARGS | METH_CLASS,
+ pyrna_draw_handler_add_doc},
+ {"draw_handler_remove",
+ (PyCFunction)pyrna_callback_classmethod_remove,
+ METH_VARARGS | METH_CLASS,
+ pyrna_draw_handler_remove_doc},
+ {NULL, NULL, 0, NULL},
+};
+
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Public API
+ * \{ */
+
+void BPY_rna_types_extend_capi(void)
+{
+ /* BlendData */
+ ARRAY_SET_ITEMS(pyrna_blenddata_methods,
+ BPY_rna_id_collection_user_map_method_def,
+ BPY_rna_id_collection_batch_remove_method_def,
+ BPY_rna_id_collection_orphans_purge_method_def);
+ BLI_assert(ARRAY_SIZE(pyrna_blenddata_methods) == 4);
+ pyrna_struct_type_extend_capi(&RNA_BlendData, pyrna_blenddata_methods, NULL);
+
+ /* BlendDataLibraries */
+ ARRAY_SET_ITEMS(
+ pyrna_blenddatalibraries_methods, BPY_library_load_method_def, BPY_library_write_method_def);
+ BLI_assert(ARRAY_SIZE(pyrna_blenddatalibraries_methods) == 3);
+ pyrna_struct_type_extend_capi(&RNA_BlendDataLibraries, pyrna_blenddatalibraries_methods, NULL);
+
+ /* Space */
+ pyrna_struct_type_extend_capi(&RNA_Space, pyrna_space_methods, NULL);
+
+ /* WindowManager */
+ pyrna_struct_type_extend_capi(
+ &RNA_WindowManager, pyrna_windowmanager_methods, pyrna_windowmanager_getset);
+}
+
+/** \} */
diff --git a/source/blender/python/intern/bpy_rna_types_capi.h b/source/blender/python/intern/bpy_rna_types_capi.h
new file mode 100644
index 00000000000..1049122e468
--- /dev/null
+++ b/source/blender/python/intern/bpy_rna_types_capi.h
@@ -0,0 +1,26 @@
+/*
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+
+/** \file
+ * \ingroup pythonintern
+ */
+
+#ifndef __BPY_RNA_TYPES_CAPI_H__
+#define __BPY_RNA_TYPES_CAPI_H__
+
+void BPY_rna_types_extend_capi(void);
+
+#endif /* __BPY_RNA_TYPES_CAPI_H__ */
diff --git a/source/blender/python/mathutils/mathutils_Vector.c b/source/blender/python/mathutils/mathutils_Vector.c
index 6ea0dd52ed7..ace7480ee81 100644
--- a/source/blender/python/mathutils/mathutils_Vector.c
+++ b/source/blender/python/mathutils/mathutils_Vector.c
@@ -930,7 +930,7 @@ PyDoc_STRVAR(Vector_dot_doc,
" :arg other: The other vector to perform the dot product with.\n"
" :type other: :class:`Vector`\n"
" :return: The dot product.\n"
- " :rtype: :class:`Vector`\n");
+ " :rtype: float\n");
static PyObject *Vector_dot(VectorObject *self, PyObject *value)
{
float *tvec;
diff --git a/source/blender/python/mathutils/mathutils_geometry.c b/source/blender/python/mathutils/mathutils_geometry.c
index 105cf96a17e..59c0021e0f3 100644
--- a/source/blender/python/mathutils/mathutils_geometry.c
+++ b/source/blender/python/mathutils/mathutils_geometry.c
@@ -1419,7 +1419,7 @@ static void boxPack_ToPyObject(PyObject *value, BoxPack **boxarray)
PyDoc_STRVAR(M_Geometry_box_pack_2d_doc,
".. function:: box_pack_2d(boxes)\n"
"\n"
- " Returns the normal of the 3D tri or quad.\n"
+ " Returns a tuple with the width and height of the packed bounding box.\n"
"\n"
" :arg boxes: list of boxes, each box is a list where the first 4 items are [x, y, "
"width, height, ...] other items are ignored.\n"
diff --git a/source/blender/render/CMakeLists.txt b/source/blender/render/CMakeLists.txt
index a1dd9b3d5b0..f49c68a258d 100644
--- a/source/blender/render/CMakeLists.txt
+++ b/source/blender/render/CMakeLists.txt
@@ -108,4 +108,6 @@ if(APPLE)
endif()
endif()
+add_definitions(${GL_DEFINITIONS})
+
blender_add_lib_nolist(bf_render "${SRC}" "${INC}" "${INC_SYS}" "${LIB}")
diff --git a/source/blender/render/extern/include/RE_bake.h b/source/blender/render/extern/include/RE_bake.h
index 372defbe8db..3bab9179f84 100644
--- a/source/blender/render/extern/include/RE_bake.h
+++ b/source/blender/render/extern/include/RE_bake.h
@@ -67,7 +67,7 @@ bool RE_bake_engine(struct Render *re,
struct Object *object,
const int object_id,
const BakePixel pixel_array[],
- const size_t num_pixels,
+ const BakeImages *bake_images,
const int depth,
const eScenePassType pass_type,
const int pass_filter,
@@ -84,6 +84,7 @@ bool RE_bake_pixels_populate_from_objects(struct Mesh *me_low,
const size_t num_pixels,
const bool is_custom_cage,
const float cage_extrusion,
+ const float max_ray_distance,
float mat_low[4][4],
float mat_cage[4][4],
struct Mesh *me_cage);
diff --git a/source/blender/render/extern/include/RE_engine.h b/source/blender/render/extern/include/RE_engine.h
index 0b5b62e2f08..77a60854616 100644
--- a/source/blender/render/extern/include/RE_engine.h
+++ b/source/blender/render/extern/include/RE_engine.h
@@ -68,7 +68,6 @@ struct bNodeTree;
#define RE_ENGINE_DO_UPDATE 8
#define RE_ENGINE_RENDERING 16
#define RE_ENGINE_HIGHLIGHT_TILES 32
-#define RE_ENGINE_USED_FOR_VIEWPORT 64
extern ListBase R_engines;
@@ -87,11 +86,8 @@ typedef struct RenderEngineType {
struct Object *object,
const int pass_type,
const int pass_filter,
- const int object_id,
- const struct BakePixel *pixel_array,
- const int num_pixels,
- const int depth,
- void *result);
+ const int width,
+ const int height);
void (*view_update)(struct RenderEngine *engine,
const struct bContext *context,
@@ -110,7 +106,7 @@ typedef struct RenderEngineType {
struct DrawEngineType *draw_engine;
/* RNA integration */
- ExtensionRNA ext;
+ ExtensionRNA rna_ext;
} RenderEngineType;
typedef void (*update_render_passes_cb_t)(void *userdata,
@@ -140,6 +136,13 @@ typedef struct RenderEngine {
struct ReportList *reports;
+ struct {
+ const struct BakePixel *pixels;
+ float *result;
+ int width, height, depth;
+ int object_id;
+ } bake;
+
/* Depsgraph */
struct Depsgraph *depsgraph;
@@ -155,7 +158,6 @@ typedef struct RenderEngine {
} RenderEngine;
RenderEngine *RE_engine_create(RenderEngineType *type);
-RenderEngine *RE_engine_create_ex(RenderEngineType *type, bool use_for_viewport);
void RE_engine_free(RenderEngine *engine);
void RE_layer_load_from_file(
diff --git a/source/blender/render/extern/include/RE_pipeline.h b/source/blender/render/extern/include/RE_pipeline.h
index 319d8b1c2ed..f9d2e915fad 100644
--- a/source/blender/render/extern/include/RE_pipeline.h
+++ b/source/blender/render/extern/include/RE_pipeline.h
@@ -40,6 +40,10 @@ struct StampData;
struct ViewLayer;
struct bMovieHandle;
+#ifdef __cplusplus
+extern "C" {
+#endif
+
/* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ */
/* this include is what is exposed of render to outside world */
/* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ */
@@ -156,8 +160,7 @@ typedef struct RenderResult {
typedef struct RenderStats {
int cfra;
- int totface, totvert, totstrand, tothalo, totlamp, totpart;
- short curfield, curblur, curpart, partsdone, convertdone, curfsa;
+ int totface, totvert, totlamp, totpart;
bool localview;
double starttime, lastframetime;
const char *infostr, *statstr;
@@ -363,7 +366,7 @@ struct RenderPass *RE_pass_find_by_type(volatile struct RenderLayer *rl,
#define RE_BAKE_DISPLACEMENT 1
#define RE_BAKE_AO 2
-void RE_GetCameraWindow(struct Render *re, struct Object *camera, int frame, float mat[4][4]);
+void RE_GetCameraWindow(struct Render *re, struct Object *camera, float mat[4][4]);
void RE_GetCameraWindowWithOverscan(struct Render *re, float mat[4][4], float overscan);
void RE_GetCameraModelMatrix(struct Render *re, struct Object *camera, float r_mat[4][4]);
struct Scene *RE_GetScene(struct Render *re);
@@ -386,4 +389,8 @@ struct RenderView *RE_RenderViewGetByName(struct RenderResult *res, const char *
RenderResult *RE_DuplicateRenderResult(RenderResult *rr);
+#ifdef __cplusplus
+}
+#endif
+
#endif /* __RE_PIPELINE_H__ */
diff --git a/source/blender/render/extern/include/RE_render_ext.h b/source/blender/render/extern/include/RE_render_ext.h
index bca3b749192..bdf81354b8d 100644
--- a/source/blender/render/extern/include/RE_render_ext.h
+++ b/source/blender/render/extern/include/RE_render_ext.h
@@ -33,18 +33,16 @@ struct ImagePool;
struct MTex;
/* render_texture.c */
-/* used by particle.c, effect.c, editmesh_modes.c and brush.c, returns 1 if rgb, 0 otherwise */
-int externtex(const struct MTex *mtex,
- const float vec[3],
- float *tin,
- float *tr,
- float *tg,
- float *tb,
- float *ta,
- const int thread,
- struct ImagePool *pool,
- const bool skip_load_image,
- const bool texnode_preview);
+bool RE_texture_evaluate(const struct MTex *mtex,
+ const float vec[3],
+ const int thread,
+ struct ImagePool *pool,
+ const bool skip_load_image,
+ const bool texnode_preview,
+ /* Return arguments. */
+ float *r_intensity,
+ float r_rgba[4]) ATTR_NONNULL(1, 2, 7, 8);
+
void texture_rgb_blend(
float in[3], const float tex[3], const float out[3], float fact, float facg, int blendtype);
float texture_value_blend(float tex, float out, float fact, float facg, int blendtype);
diff --git a/source/blender/render/extern/include/RE_shader_ext.h b/source/blender/render/extern/include/RE_shader_ext.h
index 792b2b7e071..f69ae4dfd5c 100644
--- a/source/blender/render/extern/include/RE_shader_ext.h
+++ b/source/blender/render/extern/include/RE_shader_ext.h
@@ -23,6 +23,10 @@
#ifndef __RE_SHADER_EXT_H__
#define __RE_SHADER_EXT_H__
+#ifdef __cplusplus
+extern "C" {
+#endif
+
/* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ */
/* this include is for texture exports */
/* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ */
@@ -75,4 +79,8 @@ int multitex_nodes(struct Tex *tex,
struct MTex *mtex,
struct ImagePool *pool);
+#ifdef __cplusplus
+}
+#endif
+
#endif /* __RE_SHADER_EXT_H__ */
diff --git a/source/blender/render/intern/include/render_result.h b/source/blender/render/intern/include/render_result.h
index fabbd5fb096..0ed8871b224 100644
--- a/source/blender/render/intern/include/render_result.h
+++ b/source/blender/render/intern/include/render_result.h
@@ -84,11 +84,12 @@ void render_result_exr_file_begin(struct Render *re, struct RenderEngine *engine
void render_result_exr_file_end(struct Render *re, struct RenderEngine *engine);
/* render pass wrapper for gpencil */
-struct RenderPass *gp_add_pass(struct RenderResult *rr,
- struct RenderLayer *rl,
- int channels,
- const char *name,
- const char *viewname);
+struct RenderPass *render_layer_add_pass(struct RenderResult *rr,
+ struct RenderLayer *rl,
+ int channels,
+ const char *name,
+ const char *viewname,
+ const char *chanid);
void render_result_exr_file_merge(struct RenderResult *rr,
struct RenderResult *rrpart,
diff --git a/source/blender/render/intern/source/bake_api.c b/source/blender/render/intern/source/bake_api.c
index e823a481d59..06f77854595 100644
--- a/source/blender/render/intern/source/bake_api.c
+++ b/source/blender/render/intern/source/bake_api.c
@@ -321,11 +321,16 @@ static bool cast_ray_highpoly(BVHTreeFromMesh *treeData,
const float co[3],
const float dir[3],
const int pixel_id,
- const int tot_highpoly)
+ const int tot_highpoly,
+ const float max_ray_distance)
{
int i;
int hit_mesh = -1;
- float hit_distance = FLT_MAX;
+ float hit_distance = max_ray_distance;
+ if (hit_distance == 0.0f) {
+ /* No ray distance set, use maximum. */
+ hit_distance = FLT_MAX;
+ }
BVHTreeRayHit *hits;
hits = MEM_mallocN(sizeof(BVHTreeRayHit) * tot_highpoly, "Bake Highpoly to Lowpoly: BVH Rays");
@@ -520,6 +525,7 @@ bool RE_bake_pixels_populate_from_objects(struct Mesh *me_low,
const size_t num_pixels,
const bool is_custom_cage,
const float cage_extrusion,
+ const float max_ray_distance,
float mat_low[4][4],
float mat_cage[4][4],
struct Mesh *me_cage)
@@ -623,7 +629,8 @@ bool RE_bake_pixels_populate_from_objects(struct Mesh *me_low,
co,
dir,
i,
- tot_highpoly)) {
+ tot_highpoly,
+ max_ray_distance)) {
/* if it fails mask out the original pixel array */
pixel_array_from[i].primitive_id = -1;
}
diff --git a/source/blender/render/intern/source/external_engine.c b/source/blender/render/intern/source/external_engine.c
index 7c071bb6b04..af3a6fdd384 100644
--- a/source/blender/render/intern/source/external_engine.c
+++ b/source/blender/render/intern/source/external_engine.c
@@ -31,6 +31,7 @@
#include "BLI_ghash.h"
#include "BLI_listbase.h"
+#include "BLI_math_bits.h"
#include "BLI_rect.h"
#include "BLI_string.h"
#include "BLI_utildefines.h"
@@ -87,8 +88,8 @@ void RE_engines_exit(void)
BLI_remlink(&R_engines, type);
if (!(type->flag & RE_INTERNAL)) {
- if (type->ext.free) {
- type->ext.free(type->ext.data);
+ if (type->rna_ext.free) {
+ type->rna_ext.free(type->rna_ext.data);
}
MEM_freeN(type);
@@ -131,20 +132,9 @@ bool RE_engine_is_opengl(RenderEngineType *render_type)
RenderEngine *RE_engine_create(RenderEngineType *type)
{
- return RE_engine_create_ex(type, false);
-}
-
-RenderEngine *RE_engine_create_ex(RenderEngineType *type, bool use_for_viewport)
-{
RenderEngine *engine = MEM_callocN(sizeof(RenderEngine), "RenderEngine");
engine->type = type;
- if (use_for_viewport) {
- engine->flag |= RE_ENGINE_USED_FOR_VIEWPORT;
-
- BLI_threaded_malloc_begin();
- }
-
BLI_mutex_init(&engine->update_render_passes_mutex);
return engine;
@@ -158,15 +148,94 @@ void RE_engine_free(RenderEngine *engine)
}
#endif
- if (engine->flag & RE_ENGINE_USED_FOR_VIEWPORT) {
- BLI_threaded_malloc_end();
- }
-
BLI_mutex_end(&engine->update_render_passes_mutex);
MEM_freeN(engine);
}
+/* Bake Render Results */
+
+static RenderResult *render_result_from_bake(RenderEngine *engine, int x, int y, int w, int h)
+{
+ /* Create render result with specified size. */
+ RenderResult *rr = MEM_callocN(sizeof(RenderResult), __func__);
+
+ rr->rectx = w;
+ rr->recty = h;
+ rr->tilerect.xmin = x;
+ rr->tilerect.ymin = y;
+ rr->tilerect.xmax = x + w;
+ rr->tilerect.ymax = y + h;
+
+ /* Add single baking render layer. */
+ RenderLayer *rl = MEM_callocN(sizeof(RenderLayer), "bake render layer");
+ rl->rectx = w;
+ rl->recty = h;
+ BLI_addtail(&rr->layers, rl);
+
+ /* Add render passes. */
+ render_layer_add_pass(rr, rl, engine->bake.depth, RE_PASSNAME_COMBINED, "", "RGBA");
+ RenderPass *primitive_pass = render_layer_add_pass(rr, rl, 4, "BakePrimitive", "", "RGBA");
+ RenderPass *differential_pass = render_layer_add_pass(rr, rl, 4, "BakeDifferential", "", "RGBA");
+
+ /* Fill render passes from bake pixel array, to be read by the render engine. */
+ for (int ty = 0; ty < h; ty++) {
+ size_t offset = ty * w * 4;
+ float *primitive = primitive_pass->rect + offset;
+ float *differential = differential_pass->rect + offset;
+
+ size_t bake_offset = (y + ty) * engine->bake.width + x;
+ const BakePixel *bake_pixel = engine->bake.pixels + bake_offset;
+
+ for (int tx = 0; tx < w; tx++) {
+ if (bake_pixel->object_id != engine->bake.object_id) {
+ primitive[0] = int_as_float(-1);
+ primitive[1] = int_as_float(-1);
+ }
+ else {
+ primitive[0] = int_as_float(bake_pixel->object_id);
+ primitive[1] = int_as_float(bake_pixel->primitive_id);
+ primitive[2] = bake_pixel->uv[0];
+ primitive[3] = bake_pixel->uv[1];
+
+ differential[0] = bake_pixel->du_dx;
+ differential[1] = bake_pixel->du_dy;
+ differential[2] = bake_pixel->dv_dx;
+ differential[3] = bake_pixel->dv_dy;
+ }
+
+ primitive += 4;
+ differential += 4;
+ bake_pixel++;
+ }
+ }
+
+ return rr;
+}
+
+static void render_result_to_bake(RenderEngine *engine, RenderResult *rr)
+{
+ RenderPass *rpass = RE_pass_find_by_name(rr->layers.first, RE_PASSNAME_COMBINED, "");
+
+ if (!rpass) {
+ return;
+ }
+
+ /* Copy from tile render result to full image bake result. */
+ int x = rr->tilerect.xmin;
+ int y = rr->tilerect.ymin;
+ int w = rr->tilerect.xmax - rr->tilerect.xmin;
+ int h = rr->tilerect.ymax - rr->tilerect.ymin;
+
+ for (int ty = 0; ty < h; ty++) {
+ size_t offset = ty * w * engine->bake.depth;
+ size_t bake_offset = ((y + ty) * engine->bake.width + x) * engine->bake.depth;
+ size_t size = w * engine->bake.depth * sizeof(float);
+
+ memcpy(engine->bake.result + bake_offset, rpass->rect + offset, size);
+ }
+}
+
/* Render Results */
static RenderPart *get_part_from_result(Render *re, RenderResult *result)
@@ -180,6 +249,12 @@ static RenderPart *get_part_from_result(Render *re, RenderResult *result)
RenderResult *RE_engine_begin_result(
RenderEngine *engine, int x, int y, int w, int h, const char *layername, const char *viewname)
{
+ if (engine->bake.pixels) {
+ RenderResult *result = render_result_from_bake(engine, x, y, w, h);
+ BLI_addtail(&engine->fullresult, result);
+ return result;
+ }
+
Render *re = engine->re;
RenderResult *result;
rcti disprect;
@@ -237,6 +312,11 @@ RenderResult *RE_engine_begin_result(
void RE_engine_update_result(RenderEngine *engine, RenderResult *result)
{
+ if (engine->bake.pixels) {
+ /* No interactive baking updates for now. */
+ return;
+ }
+
Render *re = engine->re;
if (result) {
@@ -270,6 +350,13 @@ void RE_engine_end_result(
return;
}
+ if (engine->bake.pixels) {
+ render_result_to_bake(engine, result);
+ BLI_remlink(&engine->fullresult, result);
+ render_result_free(result);
+ return;
+ }
+
/* merge. on break, don't merge in result for preview renders, looks nicer */
if (!highlight) {
/* for exr tile render, detect tiles that are done */
@@ -574,7 +661,7 @@ bool RE_bake_engine(Render *re,
Object *object,
const int object_id,
const BakePixel pixel_array[],
- const size_t num_pixels,
+ const BakeImages *bake_images,
const int depth,
const eScenePassType pass_type,
const int pass_filter,
@@ -587,7 +674,7 @@ bool RE_bake_engine(Render *re,
/* set render info */
re->i.cfra = re->scene->r.cfra;
BLI_strncpy(re->i.scene_name, re->scene->id.name + 2, sizeof(re->i.scene_name) - 2);
- re->i.totface = re->i.totvert = re->i.totstrand = re->i.totlamp = re->i.tothalo = 0;
+ re->i.totface = re->i.totvert = re->i.totlamp = 0;
/* render */
engine = re->engine;
@@ -605,9 +692,11 @@ bool RE_bake_engine(Render *re,
engine->resolution_x = re->winx;
engine->resolution_y = re->winy;
+ BLI_rw_mutex_lock(&re->partsmutex, THREAD_LOCK_WRITE);
RE_parts_init(re);
engine->tile_x = re->r.tilex;
engine->tile_y = re->r.tiley;
+ BLI_rw_mutex_unlock(&re->partsmutex);
if (type->bake) {
engine->depsgraph = depsgraph;
@@ -617,16 +706,21 @@ bool RE_bake_engine(Render *re,
type->update(engine, re->main, engine->depsgraph);
}
- type->bake(engine,
- engine->depsgraph,
- object,
- pass_type,
- pass_filter,
- object_id,
- pixel_array,
- num_pixels,
- depth,
- result);
+ for (int i = 0; i < bake_images->size; i++) {
+ const BakeImage *image = bake_images->data + i;
+
+ engine->bake.pixels = pixel_array + image->offset;
+ engine->bake.result = result + image->offset * depth;
+ engine->bake.width = image->width;
+ engine->bake.height = image->height;
+ engine->bake.depth = depth;
+ engine->bake.object_id = object_id;
+
+ type->bake(
+ engine, engine->depsgraph, object, pass_type, pass_filter, image->width, image->height);
+
+ memset(&engine->bake, 0, sizeof(engine->bake));
+ }
engine->depsgraph = NULL;
}
@@ -718,7 +812,7 @@ int RE_engine_render(Render *re, int do_all)
/* set render info */
re->i.cfra = re->scene->r.cfra;
BLI_strncpy(re->i.scene_name, re->scene->id.name + 2, sizeof(re->i.scene_name));
- re->i.totface = re->i.totvert = re->i.totstrand = re->i.totlamp = re->i.tothalo = 0;
+ re->i.totface = re->i.totvert = re->i.totlamp = 0;
/* render */
engine = re->engine;
diff --git a/source/blender/render/intern/source/initrender.c b/source/blender/render/intern/source/initrender.c
index 5a6ecfc3e20..2e9f30397db 100644
--- a/source/blender/render/intern/source/initrender.c
+++ b/source/blender/render/intern/source/initrender.c
@@ -211,9 +211,8 @@ void RE_SetCamera(Render *re, Object *cam_ob)
re_camera_params_get(re, &params);
}
-void RE_GetCameraWindow(struct Render *re, struct Object *camera, int frame, float mat[4][4])
+void RE_GetCameraWindow(struct Render *re, struct Object *camera, float mat[4][4])
{
- re->r.cfra = frame;
RE_SetCamera(re, camera);
copy_m4_m4(mat, re->winmat);
}
@@ -271,8 +270,6 @@ void RE_parts_init(Render *re)
/* this is render info for caller, is not reset when parts are freed! */
re->i.totpart = 0;
- re->i.curpart = 0;
- re->i.partsdone = 0;
/* just for readable code.. */
xminb = re->disprect.xmin;
diff --git a/source/blender/render/intern/source/pipeline.c b/source/blender/render/intern/source/pipeline.c
index 87568402df3..c66c43ec467 100644
--- a/source/blender/render/intern/source/pipeline.c
+++ b/source/blender/render/intern/source/pipeline.c
@@ -51,6 +51,7 @@
#include "BLT_translation.h"
+#include "BKE_anim_data.h"
#include "BKE_animsys.h" /* <------ should this be here?, needed for sequencer update */
#include "BKE_callbacks.h"
#include "BKE_camera.h"
@@ -186,32 +187,22 @@ static int default_break(void *UNUSED(arg))
static void stats_background(void *UNUSED(arg), RenderStats *rs)
{
- uintptr_t mem_in_use, mmap_in_use, peak_memory;
- float megs_used_memory, mmap_used_memory, megs_peak_memory;
+ uintptr_t mem_in_use, peak_memory;
+ float megs_used_memory, megs_peak_memory;
char info_time_str[32];
mem_in_use = MEM_get_memory_in_use();
- mmap_in_use = MEM_get_mapped_memory_in_use();
peak_memory = MEM_get_peak_memory();
- megs_used_memory = (mem_in_use - mmap_in_use) / (1024.0 * 1024.0);
- mmap_used_memory = (mmap_in_use) / (1024.0 * 1024.0);
+ megs_used_memory = (mem_in_use) / (1024.0 * 1024.0);
megs_peak_memory = (peak_memory) / (1024.0 * 1024.0);
fprintf(stdout,
- TIP_("Fra:%d Mem:%.2fM (%.2fM, Peak %.2fM) "),
+ TIP_("Fra:%d Mem:%.2fM (Peak %.2fM) "),
rs->cfra,
megs_used_memory,
- mmap_used_memory,
megs_peak_memory);
- if (rs->curfield) {
- fprintf(stdout, TIP_("Field %d "), rs->curfield);
- }
- if (rs->curblur) {
- fprintf(stdout, TIP_("Blur %d "), rs->curblur);
- }
-
BLI_timecode_string_from_time_simple(
info_time_str, sizeof(info_time_str), PIL_check_seconds_timer() - rs->starttime);
fprintf(stdout, TIP_("| Time:%s | "), info_time_str);
@@ -220,23 +211,12 @@ static void stats_background(void *UNUSED(arg), RenderStats *rs)
fprintf(stdout, "%s", rs->infostr);
}
else {
- if (rs->tothalo) {
- fprintf(stdout,
- TIP_("Sce: %s Ve:%d Fa:%d Ha:%d La:%d"),
- rs->scene_name,
- rs->totvert,
- rs->totface,
- rs->tothalo,
- rs->totlamp);
- }
- else {
- fprintf(stdout,
- TIP_("Sce: %s Ve:%d Fa:%d La:%d"),
- rs->scene_name,
- rs->totvert,
- rs->totface,
- rs->totlamp);
- }
+ fprintf(stdout,
+ TIP_("Sce: %s Ve:%d Fa:%d La:%d"),
+ rs->scene_name,
+ rs->totvert,
+ rs->totface,
+ rs->totlamp);
}
/* Flush stdout to be sure python callbacks are printing stuff after blender. */
@@ -1818,42 +1798,42 @@ bool RE_is_rendering_allowed(Scene *scene,
}
}
- if (scemode & R_DOCOMP) {
- if (scene->use_nodes) {
- if (!scene->nodetree) {
- BKE_report(reports, RPT_ERROR, "No node tree in scene");
- return 0;
- }
+ if (RE_seq_render_active(scene, &scene->r)) {
+ /* Sequencer */
+ if (scene->r.mode & R_BORDER) {
+ BKE_report(reports, RPT_ERROR, "Border rendering is not supported by sequencer");
+ return false;
+ }
+ }
+ else if ((scemode & R_DOCOMP) && scene->use_nodes) {
+ /* Compositor */
+ if (!scene->nodetree) {
+ BKE_report(reports, RPT_ERROR, "No node tree in scene");
+ return 0;
+ }
- if (!check_composite_output(scene)) {
- BKE_report(reports, RPT_ERROR, "No render output node in scene");
- return 0;
- }
+ if (!check_composite_output(scene)) {
+ BKE_report(reports, RPT_ERROR, "No render output node in scene");
+ return 0;
+ }
- if (scemode & R_FULL_SAMPLE) {
- if (composite_needs_render(scene, 0) == 0) {
- BKE_report(reports, RPT_ERROR, "Full sample AA not supported without 3D rendering");
- return 0;
- }
+ if (scemode & R_FULL_SAMPLE) {
+ if (composite_needs_render(scene, 0) == 0) {
+ BKE_report(reports, RPT_ERROR, "Full sample AA not supported without 3D rendering");
+ return 0;
}
}
}
-
- /* check valid camera, without camera render is OK (compo, seq) */
- if (!check_valid_camera(scene, camera_override, reports)) {
- return 0;
- }
-
- if (RE_seq_render_active(scene, &scene->r)) {
- if (scene->r.mode & R_BORDER) {
- BKE_report(reports, RPT_ERROR, "Border rendering is not supported by sequencer");
- return false;
+ else {
+ /* Regular Render */
+ if (!render_scene_has_layers_to_render(scene, single_layer)) {
+ BKE_report(reports, RPT_ERROR, "All render layers are disabled");
+ return 0;
}
}
- /* layer flag tests */
- if (!render_scene_has_layers_to_render(scene, single_layer)) {
- BKE_report(reports, RPT_ERROR, "All render layers are disabled");
+ /* check valid camera, without camera render is OK (compo, seq) */
+ if (!check_valid_camera(scene, camera_override, reports)) {
return 0;
}
@@ -2094,14 +2074,13 @@ void RE_RenderFreestyleExternal(Render *re)
FRS_init_stroke_renderer(re);
- for (RenderView *rv = re->result->views.first; rv; rv = rv->next) {
+ LISTBASE_FOREACH (RenderView *, rv, &re->result->views) {
RE_SetActiveRenderView(re, rv->name);
ViewLayer *active_view_layer = BLI_findlink(&re->view_layers, re->active_view_layer);
FRS_begin_stroke_rendering(re);
- for (ViewLayer *view_layer = (ViewLayer *)re->view_layers.first; view_layer;
- view_layer = view_layer->next) {
+ LISTBASE_FOREACH (ViewLayer *, view_layer, &re->view_layers) {
if ((re->r.scemode & R_SINGLE_LAYER) && view_layer != active_view_layer) {
continue;
}
@@ -2514,7 +2493,7 @@ void RE_RenderAnim(Render *re,
{
float ctime = BKE_scene_frame_get(scene);
AnimData *adt = BKE_animdata_from_id(&scene->id);
- BKE_animsys_evaluate_animdata(scene, &scene->id, adt, ctime, ADT_RECALC_ALL, false);
+ BKE_animsys_evaluate_animdata(&scene->id, adt, ctime, ADT_RECALC_ALL, false);
}
render_update_depsgraph(re);
@@ -2865,7 +2844,7 @@ bool RE_layers_have_name(struct RenderResult *rr)
bool RE_passes_have_name(struct RenderLayer *rl)
{
- for (RenderPass *rp = rl->passes.first; rp; rp = rp->next) {
+ LISTBASE_FOREACH (RenderPass *, rp, &rl->passes) {
if (!STREQ(rp->name, "Combined")) {
return true;
}
@@ -2955,5 +2934,5 @@ RenderPass *RE_create_gp_pass(RenderResult *rr, const char *layername, const cha
BLI_freelinkN(&rl->passes, rp);
}
/* create a totally new pass */
- return gp_add_pass(rr, rl, 4, RE_PASSNAME_COMBINED, viewname);
+ return render_layer_add_pass(rr, rl, 4, RE_PASSNAME_COMBINED, viewname, "RGBA");
}
diff --git a/source/blender/render/intern/source/render_result.c b/source/blender/render/intern/source/render_result.c
index 814e9b1c79e..4b74bfb3e5c 100644
--- a/source/blender/render/intern/source/render_result.c
+++ b/source/blender/render/intern/source/render_result.c
@@ -213,12 +213,12 @@ static void set_pass_full_name(
/********************************** New **************************************/
-static RenderPass *render_layer_add_pass(RenderResult *rr,
- RenderLayer *rl,
- int channels,
- const char *name,
- const char *viewname,
- const char *chan_id)
+RenderPass *render_layer_add_pass(RenderResult *rr,
+ RenderLayer *rl,
+ int channels,
+ const char *name,
+ const char *viewname,
+ const char *chan_id)
{
const int view_id = BLI_findstringindex(&rr->views, viewname, offsetof(RenderView, name));
RenderPass *rpass = MEM_callocN(sizeof(RenderPass), name);
@@ -255,7 +255,7 @@ static RenderPass *render_layer_add_pass(RenderResult *rr,
float *rect;
int x;
- rpass->rect = MEM_mapallocN(sizeof(float) * rectsize, name);
+ rpass->rect = MEM_callocN(sizeof(float) * rectsize, name);
if (rpass->rect == NULL) {
MEM_freeN(rpass);
return NULL;
@@ -280,12 +280,6 @@ static RenderPass *render_layer_add_pass(RenderResult *rr,
return rpass;
}
-/* wrapper called from render_opengl */
-RenderPass *gp_add_pass(
- RenderResult *rr, RenderLayer *rl, int channels, const char *name, const char *viewname)
-{
- return render_layer_add_pass(rr, rl, channels, name, viewname, "RGBA");
-}
/* called by main render as well for parts */
/* will read info from Render *re to define layers */
@@ -917,7 +911,7 @@ bool RE_WriteRenderResult(ReportList *reports,
/* First add views since IMB_exr_add_channel checks number of views. */
if (render_result_has_views(rr)) {
- for (RenderView *rview = rr->views.first; rview; rview = rview->next) {
+ LISTBASE_FOREACH (RenderView *, rview, &rr->views) {
if (!view || STREQ(view, rview->name)) {
IMB_exr_add_view(exrhandle, rview->name);
}
@@ -926,7 +920,7 @@ bool RE_WriteRenderResult(ReportList *reports,
/* Compositing result. */
if (rr->have_combined) {
- for (RenderView *rview = rr->views.first; rview; rview = rview->next) {
+ LISTBASE_FOREACH (RenderView *, rview, &rr->views) {
if (!rview->rectf) {
continue;
}
@@ -986,7 +980,7 @@ bool RE_WriteRenderResult(ReportList *reports,
continue;
}
- for (RenderPass *rp = rl->passes.first; rp; rp = rp->next) {
+ LISTBASE_FOREACH (RenderPass *, rp, &rl->passes) {
/* Skip non-RGBA and Z passes if not using multi layer. */
if (!multi_layer && !(STREQ(rp->name, RE_PASSNAME_COMBINED) || STREQ(rp->name, "") ||
(STREQ(rp->name, RE_PASSNAME_Z) && write_z))) {
@@ -1240,7 +1234,7 @@ void render_result_exr_file_begin(Render *re, RenderEngine *engine)
char str[FILE_MAX];
for (RenderResult *rr = re->result; rr; rr = rr->next) {
- for (RenderLayer *rl = rr->layers.first; rl; rl = rl->next) {
+ LISTBASE_FOREACH (RenderLayer *, rl, &rr->layers) {
/* Get passes needed by engine. Normally we would wait for the
* engine to create them, but for EXR file we need to know in
* advance. */
@@ -1250,7 +1244,7 @@ void render_result_exr_file_begin(Render *re, RenderEngine *engine)
/* Create render passes requested by engine. Only this part is
* mutex locked to avoid deadlock with Python GIL. */
BLI_rw_mutex_lock(&re->resultmutex, THREAD_LOCK_WRITE);
- for (RenderPass *pass = templates.first; pass; pass = pass->next) {
+ LISTBASE_FOREACH (RenderPass *, pass, &templates) {
RE_create_render_pass(
re->result, pass->name, pass->channels, pass->chan_id, rl->name, NULL);
}
@@ -1271,7 +1265,7 @@ void render_result_exr_file_end(Render *re, RenderEngine *engine)
{
/* Close EXR files. */
for (RenderResult *rr = re->result; rr; rr = rr->next) {
- for (RenderLayer *rl = rr->layers.first; rl; rl = rl->next) {
+ LISTBASE_FOREACH (RenderLayer *, rl, &rr->layers) {
IMB_exr_close(rl->exrhandle);
rl->exrhandle = NULL;
}
@@ -1285,7 +1279,7 @@ void render_result_exr_file_end(Render *re, RenderEngine *engine)
re->result = render_result_new(re, &re->disprect, 0, RR_USE_MEM, RR_ALL_LAYERS, RR_ALL_VIEWS);
BLI_rw_mutex_unlock(&re->resultmutex);
- for (RenderLayer *rl = re->result->layers.first; rl; rl = rl->next) {
+ LISTBASE_FOREACH (RenderLayer *, rl, &re->result->layers) {
/* Get passes needed by engine. */
ListBase templates;
render_result_get_pass_templates(engine, re, rl, &templates);
@@ -1293,7 +1287,7 @@ void render_result_exr_file_end(Render *re, RenderEngine *engine)
/* Create render passes requested by engine. Only this part is
* mutex locked to avoid deadlock with Python GIL. */
BLI_rw_mutex_lock(&re->resultmutex, THREAD_LOCK_WRITE);
- for (RenderPass *pass = templates.first; pass; pass = pass->next) {
+ LISTBASE_FOREACH (RenderPass *, pass, &templates) {
RE_create_render_pass(re->result, pass->name, pass->channels, pass->chan_id, rl->name, NULL);
}
diff --git a/source/blender/render/intern/source/render_texture.c b/source/blender/render/intern/source/render_texture.c
index 22cc1f0eddf..ee484924bf9 100644
--- a/source/blender/render/intern/source/render_texture.c
+++ b/source/blender/render/intern/source/render_texture.c
@@ -46,7 +46,6 @@
#include "BKE_image.h"
#include "BKE_node.h"
-#include "BKE_animsys.h"
#include "BKE_colorband.h"
#include "BKE_material.h"
#include "BKE_scene.h"
@@ -80,7 +79,7 @@ void RE_texture_rng_exit(void)
/* ------------------------------------------------------------------------- */
/* this allows colorbanded textures to control normals as well */
-static void tex_normal_derivate(Tex *tex, TexResult *texres)
+static void tex_normal_derivate(const Tex *tex, TexResult *texres)
{
if (tex->flag & TEX_COLORBAND) {
float col[4];
@@ -107,7 +106,7 @@ static void tex_normal_derivate(Tex *tex, TexResult *texres)
texres->nor[2] = texres->tin - texres->nor[2];
}
-static int blend(Tex *tex, const float texvec[3], TexResult *texres)
+static int blend(const Tex *tex, const float texvec[3], TexResult *texres)
{
float x, y, t;
@@ -171,7 +170,7 @@ static int blend(Tex *tex, const float texvec[3], TexResult *texres)
/* newnoise: all noisebased types now have different noisebases to choose from */
-static int clouds(Tex *tex, const float texvec[3], TexResult *texres)
+static int clouds(const Tex *tex, const float texvec[3], TexResult *texres)
{
int rv = TEX_INT;
@@ -272,7 +271,7 @@ static float tex_tri(float a)
}
/* computes basic wood intensity value at x,y,z */
-static float wood_int(Tex *tex, float x, float y, float z)
+static float wood_int(const Tex *tex, float x, float y, float z)
{
float wi = 0;
/* wave form: TEX_SIN=0, TEX_SAW=1, TEX_TRI=2 */
@@ -309,7 +308,7 @@ static float wood_int(Tex *tex, float x, float y, float z)
return wi;
}
-static int wood(Tex *tex, const float texvec[3], TexResult *texres)
+static int wood(const Tex *tex, const float texvec[3], TexResult *texres)
{
int rv = TEX_INT;
@@ -330,7 +329,7 @@ static int wood(Tex *tex, const float texvec[3], TexResult *texres)
}
/* computes basic marble intensity at x,y,z */
-static float marble_int(Tex *tex, float x, float y, float z)
+static float marble_int(const Tex *tex, float x, float y, float z)
{
float n, mi;
short wf = tex->noisebasis2; /* wave form: TEX_SIN=0, TEX_SAW=1, TEX_TRI=2 */
@@ -368,7 +367,7 @@ static float marble_int(Tex *tex, float x, float y, float z)
return mi;
}
-static int marble(Tex *tex, const float texvec[3], TexResult *texres)
+static int marble(const Tex *tex, const float texvec[3], TexResult *texres)
{
int rv = TEX_INT;
@@ -392,7 +391,7 @@ static int marble(Tex *tex, const float texvec[3], TexResult *texres)
/* ------------------------------------------------------------------------- */
-static int magic(Tex *tex, const float texvec[3], TexResult *texres)
+static int magic(const Tex *tex, const float texvec[3], TexResult *texres)
{
float x, y, z, turb;
int n;
@@ -468,7 +467,7 @@ static int magic(Tex *tex, const float texvec[3], TexResult *texres)
/* ------------------------------------------------------------------------- */
/* newnoise: stucci also modified to use different noisebasis */
-static int stucci(Tex *tex, const float texvec[3], TexResult *texres)
+static int stucci(const Tex *tex, const float texvec[3], TexResult *texres)
{
float nor[3], b2, ofs;
int retval = TEX_INT;
@@ -534,7 +533,7 @@ static int stucci(Tex *tex, const float texvec[3], TexResult *texres)
/* ------------------------------------------------------------------------- */
/* newnoise: musgrave terrain noise types */
-static float mg_mFractalOrfBmTex(Tex *tex, const float texvec[3], TexResult *texres)
+static int mg_mFractalOrfBmTex(const Tex *tex, const float texvec[3], TexResult *texres)
{
int rv = TEX_INT;
float (*mgravefunc)(float, float, float, float, float, float, int);
@@ -589,7 +588,7 @@ static float mg_mFractalOrfBmTex(Tex *tex, const float texvec[3], TexResult *tex
return rv;
}
-static float mg_ridgedOrHybridMFTex(Tex *tex, const float texvec[3], TexResult *texres)
+static int mg_ridgedOrHybridMFTex(const Tex *tex, const float texvec[3], TexResult *texres)
{
int rv = TEX_INT;
float (*mgravefunc)(float, float, float, float, float, float, float, float, int);
@@ -652,7 +651,7 @@ static float mg_ridgedOrHybridMFTex(Tex *tex, const float texvec[3], TexResult *
return rv;
}
-static float mg_HTerrainTex(Tex *tex, const float texvec[3], TexResult *texres)
+static int mg_HTerrainTex(const Tex *tex, const float texvec[3], TexResult *texres)
{
int rv = TEX_INT;
@@ -703,7 +702,7 @@ static float mg_HTerrainTex(Tex *tex, const float texvec[3], TexResult *texres)
return rv;
}
-static float mg_distNoiseTex(Tex *tex, const float texvec[3], TexResult *texres)
+static int mg_distNoiseTex(const Tex *tex, const float texvec[3], TexResult *texres)
{
int rv = TEX_INT;
@@ -748,7 +747,7 @@ static float mg_distNoiseTex(Tex *tex, const float texvec[3], TexResult *texres)
* probably the slowest, especially with minkovsky, bumpmapping, could be done another way.
*/
-static float voronoiTex(Tex *tex, const float texvec[3], TexResult *texres)
+static int voronoiTex(const Tex *tex, const float texvec[3], TexResult *texres)
{
int rv = TEX_INT;
float da[4], pa[12]; /* distance and point coordinate arrays of 4 nearest neighbors */
@@ -762,8 +761,7 @@ static float voronoiTex(Tex *tex, const float texvec[3], TexResult *texres)
}
voronoi(texvec[0], texvec[1], texvec[2], da, pa, tex->vn_mexp, tex->vn_distm);
- texres->tin = sc * fabsf(tex->vn_w1 * da[0] + tex->vn_w2 * da[1] + tex->vn_w3 * da[2] +
- tex->vn_w4 * da[3]);
+ texres->tin = sc * fabsf(dot_v4v4(&tex->vn_w1, da));
if (tex->vn_coltype) {
float ca[3]; /* cell color */
@@ -810,14 +808,11 @@ static float voronoiTex(Tex *tex, const float texvec[3], TexResult *texres)
/* calculate bumpnormal */
voronoi(texvec[0] + offs, texvec[1], texvec[2], da, pa, tex->vn_mexp, tex->vn_distm);
- texres->nor[0] = sc * fabsf(tex->vn_w1 * da[0] + tex->vn_w2 * da[1] + tex->vn_w3 * da[2] +
- tex->vn_w4 * da[3]);
+ texres->nor[0] = sc * fabsf(dot_v4v4(&tex->vn_w1, da));
voronoi(texvec[0], texvec[1] + offs, texvec[2], da, pa, tex->vn_mexp, tex->vn_distm);
- texres->nor[1] = sc * fabsf(tex->vn_w1 * da[0] + tex->vn_w2 * da[1] + tex->vn_w3 * da[2] +
- tex->vn_w4 * da[3]);
+ texres->nor[1] = sc * fabsf(dot_v4v4(&tex->vn_w1, da));
voronoi(texvec[0], texvec[1], texvec[2] + offs, da, pa, tex->vn_mexp, tex->vn_distm);
- texres->nor[2] = sc * fabsf(tex->vn_w1 * da[0] + tex->vn_w2 * da[1] + tex->vn_w3 * da[2] +
- tex->vn_w4 * da[3]);
+ texres->nor[2] = sc * fabsf(dot_v4v4(&tex->vn_w1, da));
tex_normal_derivate(tex, texres);
rv |= TEX_NOR;
@@ -836,7 +831,7 @@ static float voronoiTex(Tex *tex, const float texvec[3], TexResult *texres)
/* ------------------------------------------------------------------------- */
-static int texnoise(Tex *tex, TexResult *texres, int thread)
+static int texnoise(const Tex *tex, TexResult *texres, int thread)
{
float div = 3.0;
int val, ran, loop, shift = 29;
@@ -1725,17 +1720,20 @@ float texture_value_blend(float tex, float out, float fact, float facg, int blen
/* ------------------------------------------------------------------------- */
-int externtex(const MTex *mtex,
- const float vec[3],
- float *tin,
- float *tr,
- float *tg,
- float *tb,
- float *ta,
- const int thread,
- struct ImagePool *pool,
- const bool skip_load_image,
- const bool texnode_preview)
+/**
+ * \param pool: Thread pool, may be NULL.
+ *
+ * \return True if the texture has color, otherwise false.
+ */
+bool RE_texture_evaluate(const MTex *mtex,
+ const float vec[3],
+ const int thread,
+ struct ImagePool *pool,
+ const bool skip_load_image,
+ const bool texnode_preview,
+ /* Return arguments. */
+ float *r_intensity,
+ float r_rgba[4])
{
Tex *tex;
TexResult texr;
@@ -1797,11 +1795,11 @@ int externtex(const MTex *mtex,
texr.tb = mtex->b;
}
- *tin = texr.tin;
- *tr = texr.tr;
- *tg = texr.tg;
- *tb = texr.tb;
- *ta = texr.ta;
+ *r_intensity = texr.tin;
+ r_rgba[0] = texr.tr;
+ r_rgba[1] = texr.tg;
+ r_rgba[2] = texr.tb;
+ r_rgba[3] = texr.ta;
return (rgb != 0);
}
diff --git a/source/blender/shader_fx/intern/FX_shader_blur.c b/source/blender/shader_fx/intern/FX_shader_blur.c
index e98205897aa..8881f147af8 100644
--- a/source/blender/shader_fx/intern/FX_shader_blur.c
+++ b/source/blender/shader_fx/intern/FX_shader_blur.c
@@ -10,7 +10,7 @@
* 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,
+ * 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
@@ -38,7 +38,7 @@ static void initData(ShaderFxData *fx)
static void copyData(const ShaderFxData *md, ShaderFxData *target)
{
- BKE_shaderfx_copyData_generic(md, target);
+ BKE_shaderfx_copydata_generic(md, target);
}
ShaderFxTypeInfo shaderfx_Type_Blur = {
diff --git a/source/blender/shader_fx/intern/FX_shader_colorize.c b/source/blender/shader_fx/intern/FX_shader_colorize.c
index 7438fbf7fa7..5fea2cd0ff8 100644
--- a/source/blender/shader_fx/intern/FX_shader_colorize.c
+++ b/source/blender/shader_fx/intern/FX_shader_colorize.c
@@ -10,7 +10,7 @@
* 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,
+ * 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) 2018, Blender Foundation
@@ -40,7 +40,7 @@ static void initData(ShaderFxData *fx)
static void copyData(const ShaderFxData *md, ShaderFxData *target)
{
- BKE_shaderfx_copyData_generic(md, target);
+ BKE_shaderfx_copydata_generic(md, target);
}
ShaderFxTypeInfo shaderfx_Type_Colorize = {
diff --git a/source/blender/shader_fx/intern/FX_shader_flip.c b/source/blender/shader_fx/intern/FX_shader_flip.c
index ddf4d201ca7..b915fb8e591 100644
--- a/source/blender/shader_fx/intern/FX_shader_flip.c
+++ b/source/blender/shader_fx/intern/FX_shader_flip.c
@@ -10,7 +10,7 @@
* 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,
+ * 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
@@ -39,7 +39,7 @@ static void initData(ShaderFxData *fx)
static void copyData(const ShaderFxData *md, ShaderFxData *target)
{
- BKE_shaderfx_copyData_generic(md, target);
+ BKE_shaderfx_copydata_generic(md, target);
}
ShaderFxTypeInfo shaderfx_Type_Flip = {
diff --git a/source/blender/shader_fx/intern/FX_shader_glow.c b/source/blender/shader_fx/intern/FX_shader_glow.c
index a81e69e00a1..1194e95ce79 100644
--- a/source/blender/shader_fx/intern/FX_shader_glow.c
+++ b/source/blender/shader_fx/intern/FX_shader_glow.c
@@ -10,7 +10,7 @@
* 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,
+ * 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) 2018, Blender Foundation
@@ -47,7 +47,7 @@ static void initData(ShaderFxData *md)
static void copyData(const ShaderFxData *md, ShaderFxData *target)
{
- BKE_shaderfx_copyData_generic(md, target);
+ BKE_shaderfx_copydata_generic(md, target);
}
ShaderFxTypeInfo shaderfx_Type_Glow = {
diff --git a/source/blender/shader_fx/intern/FX_shader_light.c b/source/blender/shader_fx/intern/FX_shader_light.c
index c81d959ebe0..17d2f518d44 100644
--- a/source/blender/shader_fx/intern/FX_shader_light.c
+++ b/source/blender/shader_fx/intern/FX_shader_light.c
@@ -10,7 +10,7 @@
* 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,
+ * 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) 2018, Blender Foundation
@@ -48,7 +48,7 @@ static void initData(ShaderFxData *fx)
static void copyData(const ShaderFxData *md, ShaderFxData *target)
{
- BKE_shaderfx_copyData_generic(md, target);
+ BKE_shaderfx_copydata_generic(md, target);
}
static void updateDepsgraph(ShaderFxData *md, const ModifierUpdateDepsgraphContext *ctx)
diff --git a/source/blender/shader_fx/intern/FX_shader_pixel.c b/source/blender/shader_fx/intern/FX_shader_pixel.c
index f39649bba07..04bf9ae5b6d 100644
--- a/source/blender/shader_fx/intern/FX_shader_pixel.c
+++ b/source/blender/shader_fx/intern/FX_shader_pixel.c
@@ -10,7 +10,7 @@
* 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,
+ * 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
@@ -36,7 +36,7 @@ static void initData(ShaderFxData *fx)
static void copyData(const ShaderFxData *md, ShaderFxData *target)
{
- BKE_shaderfx_copyData_generic(md, target);
+ BKE_shaderfx_copydata_generic(md, target);
}
ShaderFxTypeInfo shaderfx_Type_Pixel = {
diff --git a/source/blender/shader_fx/intern/FX_shader_rim.c b/source/blender/shader_fx/intern/FX_shader_rim.c
index a81d2ff2a09..16c6a6716a0 100644
--- a/source/blender/shader_fx/intern/FX_shader_rim.c
+++ b/source/blender/shader_fx/intern/FX_shader_rim.c
@@ -10,7 +10,7 @@
* 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,
+ * 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) 2018, Blender Foundation
@@ -43,7 +43,7 @@ static void initData(ShaderFxData *fx)
static void copyData(const ShaderFxData *md, ShaderFxData *target)
{
- BKE_shaderfx_copyData_generic(md, target);
+ BKE_shaderfx_copydata_generic(md, target);
}
ShaderFxTypeInfo shaderfx_Type_Rim = {
diff --git a/source/blender/shader_fx/intern/FX_shader_shadow.c b/source/blender/shader_fx/intern/FX_shader_shadow.c
index 6887e988fc7..dcf66ec89e0 100644
--- a/source/blender/shader_fx/intern/FX_shader_shadow.c
+++ b/source/blender/shader_fx/intern/FX_shader_shadow.c
@@ -10,7 +10,7 @@
* 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,
+ * 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) 2018, Blender Foundation
@@ -59,7 +59,7 @@ static void initData(ShaderFxData *md)
static void copyData(const ShaderFxData *md, ShaderFxData *target)
{
- BKE_shaderfx_copyData_generic(md, target);
+ BKE_shaderfx_copydata_generic(md, target);
}
static void updateDepsgraph(ShaderFxData *fx, const ModifierUpdateDepsgraphContext *ctx)
diff --git a/source/blender/shader_fx/intern/FX_shader_swirl.c b/source/blender/shader_fx/intern/FX_shader_swirl.c
index 8e1e4a5e9fe..990b43748da 100644
--- a/source/blender/shader_fx/intern/FX_shader_swirl.c
+++ b/source/blender/shader_fx/intern/FX_shader_swirl.c
@@ -10,7 +10,7 @@
* 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,
+ * 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) 2018, Blender Foundation
@@ -48,7 +48,7 @@ static void initData(ShaderFxData *md)
static void copyData(const ShaderFxData *md, ShaderFxData *target)
{
- BKE_shaderfx_copyData_generic(md, target);
+ BKE_shaderfx_copydata_generic(md, target);
}
static void updateDepsgraph(ShaderFxData *fx, const ModifierUpdateDepsgraphContext *ctx)
diff --git a/source/blender/shader_fx/intern/FX_shader_wave.c b/source/blender/shader_fx/intern/FX_shader_wave.c
index a4ad108bc94..7dc72bcb669 100644
--- a/source/blender/shader_fx/intern/FX_shader_wave.c
+++ b/source/blender/shader_fx/intern/FX_shader_wave.c
@@ -10,7 +10,7 @@
* 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,
+ * 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) 2018, Blender Foundation
@@ -42,7 +42,7 @@ static void initData(ShaderFxData *fx)
static void copyData(const ShaderFxData *md, ShaderFxData *target)
{
- BKE_shaderfx_copyData_generic(md, target);
+ BKE_shaderfx_copydata_generic(md, target);
}
ShaderFxTypeInfo shaderfx_Type_Wave = {
diff --git a/source/blender/windowmanager/CMakeLists.txt b/source/blender/windowmanager/CMakeLists.txt
index a1b67216f1a..7c749c60168 100644
--- a/source/blender/windowmanager/CMakeLists.txt
+++ b/source/blender/windowmanager/CMakeLists.txt
@@ -153,8 +153,8 @@ endif()
if(WITH_HEADLESS)
add_definitions(-DWITH_HEADLESS)
-elseif(WITH_X11)
- add_definitions(-DWITH_X11)
+elseif(WITH_GHOST_X11)
+ add_definitions(-DWITH_GHOST_X11)
endif()
if(WITH_PYTHON)
@@ -168,10 +168,6 @@ if(WITH_BUILDINFO)
add_definitions(-DWITH_BUILDINFO)
endif()
-if(WITH_OPENSUBDIV)
- add_definitions(-DWITH_OPENSUBDIV)
-endif()
-
if(WITH_INPUT_NDOF)
add_definitions(-DWITH_INPUT_NDOF)
endif()
@@ -191,8 +187,18 @@ endif()
if(WITH_XR_OPENXR)
add_definitions(-DWITH_XR_OPENXR)
+
+ list(APPEND INC
+ xr
+ )
+
list(APPEND SRC
- intern/wm_xr.c
+ xr/intern/wm_xr.c
+ xr/intern/wm_xr_draw.c
+ xr/intern/wm_xr_session.c
+
+ xr/wm_xr.h
+ xr/intern/wm_xr_intern.h
)
endif()
diff --git a/source/blender/windowmanager/WM_api.h b/source/blender/windowmanager/WM_api.h
index cc8b1bb4882..a886d1440d9 100644
--- a/source/blender/windowmanager/WM_api.h
+++ b/source/blender/windowmanager/WM_api.h
@@ -64,6 +64,7 @@ struct wmJob;
struct wmOperator;
struct wmOperatorType;
struct wmPaintCursor;
+struct wmTabletData;
struct wmDragData;
struct wmDropTarget;
struct wmDropTargetFinder;
@@ -106,6 +107,17 @@ void WM_reinit_gizmomap_all(struct Main *bmain);
void WM_script_tag_reload(void);
+bool WM_window_find_under_cursor(const wmWindowManager *wm,
+ const wmWindow *win_ignore,
+ const wmWindow *win,
+ const int mval[2],
+ wmWindow **r_win,
+ int r_mval[2]);
+void WM_window_pixel_sample_read(const wmWindowManager *wm,
+ const wmWindow *win,
+ const int pos[2],
+ float r_col[3]);
+
uint *WM_window_pixels_read(struct wmWindowManager *wm, struct wmWindow *win, int r_size[2]);
int WM_window_pixels_x(const struct wmWindow *win);
@@ -157,10 +169,6 @@ void *WM_opengl_context_create(void);
void WM_opengl_context_dispose(void *context);
void WM_opengl_context_activate(void *context);
void WM_opengl_context_release(void *context);
-#ifdef WIN32
-void *WM_directx_context_create(void);
-void WM_directx_context_dispose(void *context);
-#endif
struct wmWindow *WM_window_open(struct bContext *C, const struct rcti *rect);
struct wmWindow *WM_window_open_temp(struct bContext *C,
@@ -193,7 +201,7 @@ void WM_lib_reload(struct Library *lib, struct bContext *C, struct ReportList *r
/* mouse cursors */
void WM_cursor_set(struct wmWindow *win, int curs);
-bool WM_cursor_set_from_tool(struct wmWindow *win, const ScrArea *sa, const ARegion *region);
+bool WM_cursor_set_from_tool(struct wmWindow *win, const ScrArea *area, const ARegion *region);
void WM_cursor_modal_set(struct wmWindow *win, int curs);
void WM_cursor_modal_restore(struct wmWindow *win);
void WM_cursor_wait(bool val);
@@ -202,14 +210,13 @@ void WM_cursor_grab_disable(struct wmWindow *win, const int mouse_ungrab_xy[2]);
void WM_cursor_time(struct wmWindow *win, int nr);
struct wmPaintCursor *WM_paint_cursor_activate(
- struct wmWindowManager *wm,
short space_type,
short region_type,
bool (*poll)(struct bContext *C),
void (*draw)(struct bContext *C, int, int, void *customdata),
void *customdata);
-bool WM_paint_cursor_end(struct wmWindowManager *wm, struct wmPaintCursor *handle);
+bool WM_paint_cursor_end(struct wmPaintCursor *handle);
void WM_paint_cursor_tag_redraw(struct wmWindow *win, struct ARegion *region);
void WM_cursor_warp(struct wmWindow *win, int x, int y);
@@ -621,7 +628,7 @@ int WM_gesture_lasso_modal(struct bContext *C, struct wmOperator *op, const stru
void WM_gesture_lasso_cancel(struct bContext *C, struct wmOperator *op);
const int (*WM_gesture_lasso_path_to_array(struct bContext *C,
struct wmOperator *op,
- int *mcords_tot))[2];
+ int *mcoords_len))[2];
int WM_gesture_straightline_invoke(struct bContext *C,
struct wmOperator *op,
const struct wmEvent *event);
@@ -841,7 +848,7 @@ void WM_draw_region_viewport_bind(struct ARegion *region);
void WM_draw_region_viewport_unbind(struct ARegion *region);
/* Region drawing */
-void WM_draw_region_free(struct ARegion *region);
+void WM_draw_region_free(struct ARegion *region, bool hide);
struct GPUViewport *WM_draw_region_get_viewport(struct ARegion *region);
struct GPUViewport *WM_draw_region_get_bound_viewport(struct ARegion *region);
@@ -853,6 +860,8 @@ bool write_crash_blend(void);
/* Lock the interface for any communication */
void WM_set_locked_interface(struct wmWindowManager *wm, bool lock);
+void WM_event_tablet_data_default_set(struct wmTabletData *tablet_data);
+
/* For testing only 'G_FLAG_EVENT_SIMULATE' */
struct wmEvent *WM_event_add_simulate(struct wmWindow *win, const struct wmEvent *event_to_add);
@@ -862,7 +871,7 @@ const char *WM_window_cursor_keymap_status_get(const struct wmWindow *win,
void WM_window_cursor_keymap_status_refresh(struct bContext *C, struct wmWindow *win);
void WM_window_status_area_tag_redraw(struct wmWindow *win);
-struct ScrArea *WM_window_status_area_find(struct wmWindow *win, struct bScreen *sc);
+struct ScrArea *WM_window_status_area_find(struct wmWindow *win, struct bScreen *screen);
bool WM_window_modal_keymap_status_draw(struct bContext *C,
struct wmWindow *win,
struct uiLayout *layout);
@@ -909,18 +918,18 @@ typedef struct ARegion *(*wmTooltipInitFn)(struct bContext *C,
void WM_tooltip_immediate_init(struct bContext *C,
struct wmWindow *win,
- struct ScrArea *sa,
+ struct ScrArea *area,
struct ARegion *region,
wmTooltipInitFn init);
void WM_tooltip_timer_init_ex(struct bContext *C,
struct wmWindow *win,
- struct ScrArea *sa,
+ struct ScrArea *area,
struct ARegion *region,
wmTooltipInitFn init,
double delay);
void WM_tooltip_timer_init(struct bContext *C,
struct wmWindow *win,
- struct ScrArea *sa,
+ struct ScrArea *area,
struct ARegion *region,
wmTooltipInitFn init);
void WM_tooltip_timer_clear(struct bContext *C, struct wmWindow *win);
@@ -935,11 +944,14 @@ void WM_generic_callback_free(struct wmGenericCallback *callback);
void WM_generic_user_data_free(struct wmGenericUserData *user_data);
+bool WM_region_use_viewport(struct ScrArea *area, struct ARegion *region);
+
#ifdef WITH_XR_OPENXR
/* wm_xr.c */
bool WM_xr_session_exists(const wmXrData *xr);
bool WM_xr_session_is_ready(const wmXrData *xr);
struct wmXrSessionState *WM_xr_session_state_handle_get(const wmXrData *xr);
+void WM_xr_session_base_pose_reset(wmXrData *xr);
bool WM_xr_session_state_viewer_pose_location_get(const wmXrData *xr, float r_location[3]);
bool WM_xr_session_state_viewer_pose_rotation_get(const wmXrData *xr, float r_rotation[4]);
bool WM_xr_session_state_viewer_pose_matrix_info_get(const wmXrData *xr,
diff --git a/source/blender/windowmanager/WM_keymap.h b/source/blender/windowmanager/WM_keymap.h
index 2cf71dcf165..53a3fd5ebda 100644
--- a/source/blender/windowmanager/WM_keymap.h
+++ b/source/blender/windowmanager/WM_keymap.h
@@ -82,7 +82,7 @@ wmKeyMap *WM_keymap_find_all_spaceid_or_empty(struct wmWindowManager *wm,
const char *idname,
int spaceid,
int regionid);
-wmKeyMap *WM_keymap_active(struct wmWindowManager *wm, struct wmKeyMap *keymap);
+wmKeyMap *WM_keymap_active(const struct wmWindowManager *wm, struct wmKeyMap *keymap);
bool WM_keymap_remove(struct wmKeyConfig *keyconfig, struct wmKeyMap *keymap);
bool WM_keymap_poll(struct bContext *C, struct wmKeyMap *keymap);
@@ -135,10 +135,10 @@ char *WM_modalkeymap_operator_items_to_string_buf(struct wmOperatorType *ot,
int *r_available_len,
char **r_result);
-wmKeyMap *WM_modalkeymap_add(struct wmKeyConfig *keyconf,
- const char *idname,
- const struct EnumPropertyItem *items);
-wmKeyMap *WM_modalkeymap_get(struct wmKeyConfig *keyconf, const char *idname);
+wmKeyMap *WM_modalkeymap_ensure(struct wmKeyConfig *keyconf,
+ const char *idname,
+ const struct EnumPropertyItem *items);
+wmKeyMap *WM_modalkeymap_find(struct wmKeyConfig *keyconf, const char *idname);
wmKeyMapItem *WM_modalkeymap_add_item(
struct wmKeyMap *km, int type, int val, int modifier, int keymodifier, int value);
wmKeyMapItem *WM_modalkeymap_add_item_str(
diff --git a/source/blender/windowmanager/WM_toolsystem.h b/source/blender/windowmanager/WM_toolsystem.h
index 36cb5be7547..163f37be974 100644
--- a/source/blender/windowmanager/WM_toolsystem.h
+++ b/source/blender/windowmanager/WM_toolsystem.h
@@ -87,17 +87,17 @@ void WM_toolsystem_ref_sync_from_context(struct Main *bmain,
void WM_toolsystem_init(struct bContext *C);
int WM_toolsystem_mode_from_spacetype(struct ViewLayer *view_layer,
- struct ScrArea *sa,
+ struct ScrArea *area,
int space_type);
bool WM_toolsystem_key_from_context(struct ViewLayer *view_layer,
- struct ScrArea *sa,
+ struct ScrArea *area,
bToolKey *tkey);
void WM_toolsystem_update_from_context_view3d(struct bContext *C);
void WM_toolsystem_update_from_context(struct bContext *C,
struct WorkSpace *workspace,
struct ViewLayer *view_layer,
- struct ScrArea *sa);
+ struct ScrArea *area);
bool WM_toolsystem_active_tool_is_brush(const struct bContext *C);
@@ -134,7 +134,7 @@ void WM_toolsystem_refresh_active(struct bContext *C);
void WM_toolsystem_refresh_screen_area(struct WorkSpace *workspace,
struct ViewLayer *view_layer,
- struct ScrArea *sa);
+ struct ScrArea *area);
void WM_toolsystem_refresh_screen_all(struct Main *bmain);
#ifdef __cplusplus
diff --git a/source/blender/windowmanager/WM_types.h b/source/blender/windowmanager/WM_types.h
index b5f633d688d..48bd9ed9638 100644
--- a/source/blender/windowmanager/WM_types.h
+++ b/source/blender/windowmanager/WM_types.h
@@ -81,7 +81,7 @@
* ScrArea's store a list of space data (SpaceLinks), each of unique type.
* The first one is the displayed in the UI, others are added as needed.
*
- * +----------------------------+ <-- sa->spacedata.first;
+ * +----------------------------+ <-- area->spacedata.first;
* | |
* | |---+ <-- other inactive SpaceLink's stored.
* | | |
@@ -99,8 +99,8 @@
*
* A common way to get the space from the ScrArea:
* \code{.c}
- * if (sa->spacetype == SPACE_VIEW3D) {
- * View3D *v3d = sa->spacedata.first;
+ * if (area->spacetype == SPACE_VIEW3D) {
+ * View3D *v3d = area->spacedata.first;
* ...
* }
* \endcode
@@ -109,10 +109,6 @@
#ifndef __WM_TYPES_H__
#define __WM_TYPES_H__
-#ifdef __cplusplus
-extern "C" {
-#endif
-
struct ID;
struct ImBuf;
struct bContext;
@@ -133,6 +129,10 @@ struct wmWindowManager;
/* Include external gizmo API's */
#include "gizmo/WM_gizmo_api.h"
+#ifdef __cplusplus
+extern "C" {
+#endif
+
typedef struct wmGenericUserData {
void *data;
/** When NULL, use #MEM_freeN. */
@@ -310,7 +310,7 @@ typedef struct wmNotifier {
#define ND_HISTORY (4 << 16)
#define ND_JOB (5 << 16)
#define ND_UNDO (6 << 16)
-#define ND_XR_DATA_CHANGED (7 << 17)
+#define ND_XR_DATA_CHANGED (7 << 16)
/* NC_SCREEN */
#define ND_LAYOUTBROWSE (1 << 16)
@@ -760,7 +760,7 @@ typedef struct wmOperatorType {
bool (*pyop_poll)(struct bContext *, struct wmOperatorType *ot) ATTR_WARN_UNUSED_RESULT;
/** RNA integration */
- ExtensionRNA ext;
+ ExtensionRNA rna_ext;
/** Flag last for padding */
short flag;
diff --git a/source/blender/windowmanager/gizmo/WM_gizmo_api.h b/source/blender/windowmanager/gizmo/WM_gizmo_api.h
index 44c1804aa4d..07a3f0445bb 100644
--- a/source/blender/windowmanager/gizmo/WM_gizmo_api.h
+++ b/source/blender/windowmanager/gizmo/WM_gizmo_api.h
@@ -373,7 +373,7 @@ void WM_gizmo_group_type_unlink_delayed(const char *idname);
void WM_gizmo_group_unlink_delayed_ptr_from_space(struct wmGizmoGroupType *gzgt,
struct wmGizmoMapType *gzmap_type,
- struct ScrArea *sa);
+ struct ScrArea *area);
/* Has the result of unlinking and linking (re-initializes gizmo's). */
void WM_gizmo_group_type_reinit_ptr_ex(struct Main *bmain,
diff --git a/source/blender/windowmanager/gizmo/WM_gizmo_types.h b/source/blender/windowmanager/gizmo/WM_gizmo_types.h
index d2953a56749..346ed131c59 100644
--- a/source/blender/windowmanager/gizmo/WM_gizmo_types.h
+++ b/source/blender/windowmanager/gizmo/WM_gizmo_types.h
@@ -67,28 +67,33 @@ typedef enum eWM_GizmoFlag {
WM_GIZMO_DRAW_VALUE = (1 << 2),
WM_GIZMO_HIDDEN = (1 << 3),
WM_GIZMO_HIDDEN_SELECT = (1 << 4),
+ /** Ignore the key-map for this gizmo. */
+ WM_GIZMO_HIDDEN_KEYMAP = (1 << 5),
/**
* When set 'scale_final' value also scales the offset.
* Use when offset is to avoid screen-space overlap instead of absolute positioning. */
- WM_GIZMO_DRAW_OFFSET_SCALE = (1 << 5),
+ WM_GIZMO_DRAW_OFFSET_SCALE = (1 << 6),
/**
* User should still use 'scale_final' for any handles and UI elements.
* This simply skips scale when calculating the final matrix.
* Needed when the gizmo needs to align with the interface underneath it. */
- WM_GIZMO_DRAW_NO_SCALE = (1 << 6),
+ WM_GIZMO_DRAW_NO_SCALE = (1 << 7),
/**
* Hide the cursor and lock it's position while interacting with this gizmo.
*/
- WM_GIZMO_MOVE_CURSOR = (1 << 7),
+ WM_GIZMO_MOVE_CURSOR = (1 << 8),
/** Don't write into the depth buffer when selecting. */
- WM_GIZMO_SELECT_BACKGROUND = (1 << 8),
+ WM_GIZMO_SELECT_BACKGROUND = (1 << 9),
/** Use the active tools operator properties when running as an operator. */
- WM_GIZMO_OPERATOR_TOOL_INIT = (1 << 9),
+ WM_GIZMO_OPERATOR_TOOL_INIT = (1 << 10),
/** Don't pass through events to other handlers
* (allows click/drag not to have it's events stolen by press events in other keymaps). */
- WM_GIZMO_EVENT_HANDLE_ALL = (1 << 10),
+ WM_GIZMO_EVENT_HANDLE_ALL = (1 << 11),
+
+ /** Don't use tool-tips for this gizmo (can be distracting). */
+ WM_GIZMO_NO_TOOLTIP = (1 << 12),
} eWM_GizmoFlag;
/**
@@ -381,7 +386,7 @@ typedef struct wmGizmoType {
struct StructRNA *srna;
/** RNA integration. */
- ExtensionRNA ext;
+ ExtensionRNA rna_ext;
ListBase target_property_defs;
int target_property_defs_len;
@@ -436,7 +441,7 @@ typedef struct wmGizmoGroupType {
struct StructRNA *srna;
/** RNA integration. */
- ExtensionRNA ext;
+ ExtensionRNA rna_ext;
eWM_GizmoFlagGroupTypeFlag flag;
diff --git a/source/blender/windowmanager/gizmo/intern/wm_gizmo_group.c b/source/blender/windowmanager/gizmo/intern/wm_gizmo_group.c
index ef270533855..67f30f0d7ee 100644
--- a/source/blender/windowmanager/gizmo/intern/wm_gizmo_group.c
+++ b/source/blender/windowmanager/gizmo/intern/wm_gizmo_group.c
@@ -222,7 +222,7 @@ wmGizmo *wm_gizmogroup_find_intersected_gizmo(wmWindowManager *wm,
{
int gzgroup_keymap_uses_modifier = -1;
- for (wmGizmo *gz = gzgroup->gizmos.first; gz; gz = gz->next) {
+ LISTBASE_FOREACH (wmGizmo *, gz, &gzgroup->gizmos) {
if (gz->type->test_select && (gz->flag & (WM_GIZMO_HIDDEN | WM_GIZMO_HIDDEN_SELECT)) == 0) {
if (!wm_gizmo_keymap_uses_event_modifier(
@@ -298,10 +298,10 @@ void WM_gizmo_group_remove_by_tool(bContext *C,
const bToolRef *tref)
{
wmGizmoMapType *gzmap_type = WM_gizmomaptype_find(&gzgt->gzmap_params);
- for (bScreen *sc = bmain->screens.first; sc; sc = sc->id.next) {
- for (ScrArea *sa = sc->areabase.first; sa; sa = sa->next) {
- if (sa->runtime.tool == tref) {
- for (ARegion *region = sa->regionbase.first; region; region = region->next) {
+ for (bScreen *screen = bmain->screens.first; screen; screen = screen->id.next) {
+ LISTBASE_FOREACH (ScrArea *, area, &screen->areabase) {
+ if (area->runtime.tool == tref) {
+ LISTBASE_FOREACH (ARegion *, region, &area->regionbase) {
wmGizmoMap *gzmap = region->gizmo_map;
if (gzmap && gzmap->type == gzmap_type) {
wmGizmoGroup *gzgroup, *gzgroup_next;
@@ -337,7 +337,7 @@ bool wm_gizmogroup_is_visible_in_drawstep(const wmGizmoGroup *gzgroup,
bool wm_gizmogroup_is_any_selected(const wmGizmoGroup *gzgroup)
{
if (gzgroup->type->flag & WM_GIZMOGROUPTYPE_SELECT) {
- for (const wmGizmo *gz = gzgroup->gizmos.first; gz; gz = gz->next) {
+ LISTBASE_FOREACH (const wmGizmo *, gz, &gzgroup->gizmos) {
if (gz->state & WM_GIZMO_STATE_SELECT) {
return true;
}
@@ -665,14 +665,14 @@ wmKeyMap *wm_gizmogroup_tweak_modal_keymap(wmKeyConfig *kc)
};
STRNCPY(name, "Generic Gizmo Tweak Modal Map");
- keymap = WM_modalkeymap_get(kc, name);
+ keymap = WM_modalkeymap_find(kc, name);
/* this function is called for each spacetype, only needs to add map once */
if (keymap && keymap->modal_items) {
return NULL;
}
- keymap = WM_modalkeymap_add(kc, name, modal_items);
+ keymap = WM_modalkeymap_ensure(kc, name, modal_items);
/* items for modal map */
WM_modalkeymap_add_item(keymap, EVT_ESCKEY, KM_PRESS, KM_ANY, 0, TWEAK_MODAL_CANCEL);
@@ -850,8 +850,7 @@ struct wmGizmoGroupTypeRef *WM_gizmomaptype_group_find_ptr(struct wmGizmoMapType
const wmGizmoGroupType *gzgt)
{
/* could use hash lookups as operator types do, for now simple search. */
- for (wmGizmoGroupTypeRef *gzgt_ref = gzmap_type->grouptype_refs.first; gzgt_ref;
- gzgt_ref = gzgt_ref->next) {
+ LISTBASE_FOREACH (wmGizmoGroupTypeRef *, gzgt_ref, &gzmap_type->grouptype_refs) {
if (gzgt_ref->type == gzgt) {
return gzgt_ref;
}
@@ -863,8 +862,7 @@ struct wmGizmoGroupTypeRef *WM_gizmomaptype_group_find(struct wmGizmoMapType *gz
const char *idname)
{
/* could use hash lookups as operator types do, for now simple search. */
- for (wmGizmoGroupTypeRef *gzgt_ref = gzmap_type->grouptype_refs.first; gzgt_ref;
- gzgt_ref = gzgt_ref->next) {
+ LISTBASE_FOREACH (wmGizmoGroupTypeRef *, gzgt_ref, &gzmap_type->grouptype_refs) {
if (STREQ(idname, gzgt_ref->type->idname)) {
return gzgt_ref;
}
@@ -908,11 +906,11 @@ void WM_gizmomaptype_group_init_runtime(const Main *bmain,
}
/* now create a gizmo for all existing areas */
- for (bScreen *sc = bmain->screens.first; sc; sc = sc->id.next) {
- for (ScrArea *sa = sc->areabase.first; sa; sa = sa->next) {
- for (SpaceLink *sl = sa->spacedata.first; sl; sl = sl->next) {
- ListBase *lb = (sl == sa->spacedata.first) ? &sa->regionbase : &sl->regionbase;
- for (ARegion *region = lb->first; region; region = region->next) {
+ for (bScreen *screen = bmain->screens.first; screen; screen = screen->id.next) {
+ LISTBASE_FOREACH (ScrArea *, area, &screen->areabase) {
+ LISTBASE_FOREACH (SpaceLink *, sl, &area->spacedata) {
+ ListBase *lb = (sl == area->spacedata.first) ? &area->regionbase : &sl->regionbase;
+ LISTBASE_FOREACH (ARegion *, region, lb) {
wmGizmoMap *gzmap = region->gizmo_map;
if (gzmap && gzmap->type == gzmap_type) {
WM_gizmomaptype_group_init_runtime_with_region(gzmap_type, gzgt, region);
@@ -963,11 +961,11 @@ void WM_gizmomaptype_group_unlink(bContext *C,
const wmGizmoGroupType *gzgt)
{
/* Free instances. */
- for (bScreen *sc = bmain->screens.first; sc; sc = sc->id.next) {
- for (ScrArea *sa = sc->areabase.first; sa; sa = sa->next) {
- for (SpaceLink *sl = sa->spacedata.first; sl; sl = sl->next) {
- ListBase *lb = (sl == sa->spacedata.first) ? &sa->regionbase : &sl->regionbase;
- for (ARegion *region = lb->first; region; region = region->next) {
+ for (bScreen *screen = bmain->screens.first; screen; screen = screen->id.next) {
+ LISTBASE_FOREACH (ScrArea *, area, &screen->areabase) {
+ LISTBASE_FOREACH (SpaceLink *, sl, &area->spacedata) {
+ ListBase *lb = (sl == area->spacedata.first) ? &area->regionbase : &sl->regionbase;
+ LISTBASE_FOREACH (ARegion *, region, lb) {
wmGizmoMap *gzmap = region->gizmo_map;
if (gzmap && gzmap->type == gzmap_type) {
wmGizmoGroup *gzgroup, *gzgroup_next;
@@ -1132,12 +1130,12 @@ void WM_gizmo_group_type_unlink_delayed(const char *idname)
void WM_gizmo_group_unlink_delayed_ptr_from_space(wmGizmoGroupType *gzgt,
wmGizmoMapType *gzmap_type,
- ScrArea *sa)
+ ScrArea *area)
{
- for (ARegion *region = sa->regionbase.first; region; region = region->next) {
+ LISTBASE_FOREACH (ARegion *, region, &area->regionbase) {
wmGizmoMap *gzmap = region->gizmo_map;
if (gzmap && gzmap->type == gzmap_type) {
- for (wmGizmoGroup *gzgroup = gzmap->groups.first; gzgroup; gzgroup = gzgroup->next) {
+ LISTBASE_FOREACH (wmGizmoGroup *, gzgroup, &gzmap->groups) {
if (gzgroup->type == gzgt) {
WM_gizmo_group_tag_remove(gzgroup);
}
diff --git a/source/blender/windowmanager/gizmo/intern/wm_gizmo_group_type.c b/source/blender/windowmanager/gizmo/intern/wm_gizmo_group_type.c
index 560d73ec220..f594ced6b66 100644
--- a/source/blender/windowmanager/gizmo/intern/wm_gizmo_group_type.c
+++ b/source/blender/windowmanager/gizmo/intern/wm_gizmo_group_type.c
@@ -144,7 +144,7 @@ wmGizmoGroupTypeRef *WM_gizmogrouptype_append_and_link(wmGizmoMapType *gzmap_typ
*/
static void gizmogrouptype_free(wmGizmoGroupType *gzgt)
{
- if (gzgt->ext.srna) { /* python gizmo group, allocs own string */
+ if (gzgt->rna_ext.srna) { /* python gizmo group, allocs own string */
MEM_freeN((void *)gzgt->idname);
}
diff --git a/source/blender/windowmanager/gizmo/intern/wm_gizmo_map.c b/source/blender/windowmanager/gizmo/intern/wm_gizmo_map.c
index 286afe42158..6ed6c485e89 100644
--- a/source/blender/windowmanager/gizmo/intern/wm_gizmo_map.c
+++ b/source/blender/windowmanager/gizmo/intern/wm_gizmo_map.c
@@ -171,8 +171,7 @@ static wmGizmoMap *wm_gizmomap_new_from_type_ex(struct wmGizmoMapType *gzmap_typ
/* create all gizmo-groups for this gizmo-map. We may create an empty one
* too in anticipation of gizmos from operators etc */
- for (wmGizmoGroupTypeRef *gzgt_ref = gzmap_type->grouptype_refs.first; gzgt_ref;
- gzgt_ref = gzgt_ref->next) {
+ LISTBASE_FOREACH (wmGizmoGroupTypeRef *, gzgt_ref, &gzmap_type->grouptype_refs) {
wm_gizmogroup_new_from_type(gzmap, gzgt_ref->type);
}
@@ -231,7 +230,7 @@ wmGizmoGroup *WM_gizmomap_group_find(struct wmGizmoMap *gzmap, const char *idnam
wmGizmoGroup *WM_gizmomap_group_find_ptr(struct wmGizmoMap *gzmap,
const struct wmGizmoGroupType *gzgt)
{
- for (wmGizmoGroup *gzgroup = gzmap->groups.first; gzgroup; gzgroup = gzgroup->next) {
+ LISTBASE_FOREACH (wmGizmoGroup *, gzgroup, &gzmap->groups) {
if (gzgroup->type == gzgt) {
return gzgroup;
}
@@ -290,9 +289,9 @@ static GHash *WM_gizmomap_gizmo_hash_new(const bContext *C,
GHash *hash = BLI_ghash_ptr_new(__func__);
/* collect gizmos */
- for (wmGizmoGroup *gzgroup = gzmap->groups.first; gzgroup; gzgroup = gzgroup->next) {
+ LISTBASE_FOREACH (wmGizmoGroup *, gzgroup, &gzmap->groups) {
if (WM_gizmo_group_type_poll(C, gzgroup->type)) {
- for (wmGizmo *gz = gzgroup->gizmos.first; gz; gz = gz->next) {
+ LISTBASE_FOREACH (wmGizmo *, gz, &gzgroup->gizmos) {
if (((flag_exclude == 0) || ((gz->flag & flag_exclude) == 0)) &&
(!poll || poll(gz, data))) {
BLI_ghash_insert(hash, gz, gz);
@@ -335,7 +334,7 @@ void WM_gizmomap_tag_refresh(wmGizmoMap *gzmap)
bool WM_gizmomap_tag_delay_refresh_for_tweak_check(wmGizmoMap *gzmap)
{
- for (wmGizmoGroup *gzgroup = gzmap->groups.first; gzgroup; gzgroup = gzgroup->next) {
+ LISTBASE_FOREACH (wmGizmoGroup *, gzgroup, &gzmap->groups) {
if (gzgroup->hide.delay_refresh_for_tweak) {
return true;
}
@@ -403,7 +402,7 @@ static void gizmomap_prepare_drawing(wmGizmoMap *gzmap,
const bool do_refresh = gzmap->update_flag[drawstep] & GIZMOMAP_IS_REFRESH_CALLBACK;
gzmap->update_flag[drawstep] &= ~GIZMOMAP_IS_REFRESH_CALLBACK;
- for (wmGizmoGroup *gzgroup = gzmap->groups.first; gzgroup; gzgroup = gzgroup->next) {
+ LISTBASE_FOREACH (wmGizmoGroup *, gzgroup, &gzmap->groups) {
/* check group visibility - drawstep first to avoid unnecessary call of group poll callback */
if (!wm_gizmogroup_is_visible_in_drawstep(gzgroup, drawstep) ||
!WM_gizmo_group_type_poll(C, gzgroup->type)) {
@@ -430,7 +429,7 @@ static void gizmomap_prepare_drawing(wmGizmoMap *gzmap,
gzgroup->type->draw_prepare(C, gzgroup);
}
- for (wmGizmo *gz = gzgroup->gizmos.first; gz; gz = gz->next) {
+ LISTBASE_FOREACH (wmGizmo *, gz, &gzgroup->gizmos) {
gizmo_prepare_drawing(gzmap, gz, C, draw_gizmos, drawstep);
}
}
@@ -577,9 +576,9 @@ static int gizmo_find_intersected_3d_intern(wmGizmo **visible_gizmos,
const int hotspot)
{
const wmWindowManager *wm = CTX_wm_manager(C);
- ScrArea *sa = CTX_wm_area(C);
+ ScrArea *area = CTX_wm_area(C);
ARegion *region = CTX_wm_region(C);
- View3D *v3d = sa->spacedata.first;
+ View3D *v3d = area->spacedata.first;
Depsgraph *depsgraph = CTX_data_depsgraph_pointer(C);
rcti rect;
/* Almost certainly overkill, but allow for many custom gizmos. */
@@ -751,7 +750,7 @@ wmGizmo *wm_gizmomap_highlight_find(wmGizmoMap *gzmap,
const int event_modifier = WM_event_modifier_flag(event);
- for (wmGizmoGroup *gzgroup = gzmap->groups.first; gzgroup; gzgroup = gzgroup->next) {
+ LISTBASE_FOREACH (wmGizmoGroup *, gzgroup, &gzmap->groups) {
/* If it were important we could initialize here,
* but this only happens when events are handled before drawing,
@@ -966,22 +965,22 @@ void wm_gizmomap_handler_context_op(bContext *C, wmEventHandler_Op *handler)
bScreen *screen = CTX_wm_screen(C);
if (screen) {
- ScrArea *sa;
+ ScrArea *area;
- for (sa = screen->areabase.first; sa; sa = sa->next) {
- if (sa == handler->context.area) {
+ for (area = screen->areabase.first; area; area = area->next) {
+ if (area == handler->context.area) {
break;
}
}
- if (sa == NULL) {
+ if (area == NULL) {
/* when changing screen layouts with running modal handlers (like render display), this
* is not an error to print */
printf("internal error: modal gizmo-map handler has invalid area\n");
}
else {
ARegion *region;
- CTX_wm_area_set(C, sa);
- for (region = sa->regionbase.first; region; region = region->next) {
+ CTX_wm_area_set(C, area);
+ for (region = area->regionbase.first; region; region = region->next) {
if (region == handler->context.region) {
break;
}
@@ -1165,12 +1164,12 @@ void WM_gizmomap_message_subscribe(bContext *C,
ARegion *region,
struct wmMsgBus *mbus)
{
- for (wmGizmoGroup *gzgroup = gzmap->groups.first; gzgroup; gzgroup = gzgroup->next) {
+ LISTBASE_FOREACH (wmGizmoGroup *, gzgroup, &gzmap->groups) {
if ((gzgroup->hide.any != 0) || (gzgroup->init_flag & WM_GIZMOGROUP_INIT_SETUP) == 0 ||
!WM_gizmo_group_type_poll(C, gzgroup->type)) {
continue;
}
- for (wmGizmo *gz = gzgroup->gizmos.first; gz; gz = gz->next) {
+ LISTBASE_FOREACH (wmGizmo *, gz, &gzgroup->gizmos) {
if (gz->flag & WM_GIZMO_HIDDEN) {
continue;
}
@@ -1220,8 +1219,7 @@ struct ARegion *WM_gizmomap_tooltip_init(struct bContext *C,
wmGizmoMapType *WM_gizmomaptype_find(const struct wmGizmoMapType_Params *gzmap_params)
{
- for (wmGizmoMapType *gzmap_type = gizmomaptypes.first; gzmap_type;
- gzmap_type = gzmap_type->next) {
+ LISTBASE_FOREACH (wmGizmoMapType *, gzmap_type, &gizmomaptypes) {
if (gzmap_type->spaceid == gzmap_params->spaceid &&
gzmap_type->regionid == gzmap_params->regionid) {
return gzmap_type;
@@ -1269,10 +1267,8 @@ void wm_gizmos_keymap(wmKeyConfig *keyconf)
/* we add this item-less keymap once and use it to group gizmo-group keymaps into it */
WM_keymap_ensure(keyconf, "Gizmos", 0, 0);
- for (wmGizmoMapType *gzmap_type = gizmomaptypes.first; gzmap_type;
- gzmap_type = gzmap_type->next) {
- for (wmGizmoGroupTypeRef *gzgt_ref = gzmap_type->grouptype_refs.first; gzgt_ref;
- gzgt_ref = gzgt_ref->next) {
+ LISTBASE_FOREACH (wmGizmoMapType *, gzmap_type, &gizmomaptypes) {
+ LISTBASE_FOREACH (wmGizmoGroupTypeRef *, gzgt_ref, &gzmap_type->grouptype_refs) {
wm_gizmogrouptype_setup_keymap(gzgt_ref->type, keyconf);
}
}
@@ -1328,8 +1324,7 @@ void WM_gizmoconfig_update(struct Main *bmain)
}
if (wm_gzmap_type_update_flag & WM_GIZMOMAPTYPE_GLOBAL_UPDATE_REMOVE) {
- for (wmGizmoMapType *gzmap_type = gizmomaptypes.first; gzmap_type;
- gzmap_type = gzmap_type->next) {
+ LISTBASE_FOREACH (wmGizmoMapType *, gzmap_type, &gizmomaptypes) {
if (gzmap_type->type_update_flag & WM_GIZMOMAPTYPE_GLOBAL_UPDATE_REMOVE) {
gzmap_type->type_update_flag &= ~WM_GIZMOMAPTYPE_UPDATE_REMOVE;
for (wmGizmoGroupTypeRef *gzgt_ref = gzmap_type->grouptype_refs.first, *gzgt_ref_next;
@@ -1348,13 +1343,11 @@ void WM_gizmoconfig_update(struct Main *bmain)
}
if (wm_gzmap_type_update_flag & WM_GIZMOMAPTYPE_GLOBAL_UPDATE_INIT) {
- for (wmGizmoMapType *gzmap_type = gizmomaptypes.first; gzmap_type;
- gzmap_type = gzmap_type->next) {
+ LISTBASE_FOREACH (wmGizmoMapType *, gzmap_type, &gizmomaptypes) {
const uchar type_update_all = WM_GIZMOMAPTYPE_UPDATE_INIT | WM_GIZMOMAPTYPE_KEYMAP_INIT;
if (gzmap_type->type_update_flag & type_update_all) {
gzmap_type->type_update_flag &= ~type_update_all;
- for (wmGizmoGroupTypeRef *gzgt_ref = gzmap_type->grouptype_refs.first; gzgt_ref;
- gzgt_ref = gzgt_ref->next) {
+ LISTBASE_FOREACH (wmGizmoGroupTypeRef *, gzgt_ref, &gzmap_type->grouptype_refs) {
if (gzgt_ref->type->type_update_flag & WM_GIZMOMAPTYPE_KEYMAP_INIT) {
WM_gizmomaptype_group_init_runtime_keymap(bmain, gzgt_ref->type);
gzgt_ref->type->type_update_flag &= ~WM_GIZMOMAPTYPE_KEYMAP_INIT;
@@ -1373,10 +1366,11 @@ void WM_gizmoconfig_update(struct Main *bmain)
if (wm_gzmap_type_update_flag & WM_GIZMOTYPE_GLOBAL_UPDATE_REMOVE) {
for (bScreen *screen = bmain->screens.first; screen; screen = screen->id.next) {
- for (ScrArea *sa = screen->areabase.first; sa; sa = sa->next) {
- for (SpaceLink *sl = sa->spacedata.first; sl; sl = sl->next) {
- ListBase *regionbase = (sl == sa->spacedata.first) ? &sa->regionbase : &sl->regionbase;
- for (ARegion *region = regionbase->first; region; region = region->next) {
+ LISTBASE_FOREACH (ScrArea *, area, &screen->areabase) {
+ LISTBASE_FOREACH (SpaceLink *, sl, &area->spacedata) {
+ ListBase *regionbase = (sl == area->spacedata.first) ? &area->regionbase :
+ &sl->regionbase;
+ LISTBASE_FOREACH (ARegion *, region, regionbase) {
wmGizmoMap *gzmap = region->gizmo_map;
if (gzmap != NULL && gzmap->tag_remove_group) {
gzmap->tag_remove_group = false;
@@ -1410,10 +1404,10 @@ void WM_gizmoconfig_update(struct Main *bmain)
void WM_reinit_gizmomap_all(Main *bmain)
{
for (bScreen *screen = bmain->screens.first; screen; screen = screen->id.next) {
- for (ScrArea *sa = screen->areabase.first; sa; sa = sa->next) {
- for (SpaceLink *sl = sa->spacedata.first; sl; sl = sl->next) {
- ListBase *regionbase = (sl == sa->spacedata.first) ? &sa->regionbase : &sl->regionbase;
- for (ARegion *region = regionbase->first; region; region = region->next) {
+ LISTBASE_FOREACH (ScrArea *, area, &screen->areabase) {
+ LISTBASE_FOREACH (SpaceLink *, sl, &area->spacedata) {
+ ListBase *regionbase = (sl == area->spacedata.first) ? &area->regionbase : &sl->regionbase;
+ LISTBASE_FOREACH (ARegion *, region, regionbase) {
wmGizmoMap *gzmap = region->gizmo_map;
if ((gzmap != NULL) && (gzmap->is_init == false)) {
WM_gizmomap_reinit(gzmap);
diff --git a/source/blender/windowmanager/gizmo/intern/wm_gizmo_type.c b/source/blender/windowmanager/gizmo/intern/wm_gizmo_type.c
index 93f3a04978f..3956ff8fd36 100644
--- a/source/blender/windowmanager/gizmo/intern/wm_gizmo_type.c
+++ b/source/blender/windowmanager/gizmo/intern/wm_gizmo_type.c
@@ -120,7 +120,7 @@ void WM_gizmotype_append_ptr(void (*gtfunc)(struct wmGizmoType *, void *), void
*/
static void gizmotype_free(wmGizmoType *gzt)
{
- if (gzt->ext.srna) { /* python gizmo, allocs own string */
+ if (gzt->rna_ext.srna) { /* python gizmo, allocs own string */
MEM_freeN((void *)gzt->idname);
}
@@ -134,11 +134,11 @@ static void gizmotype_free(wmGizmoType *gzt)
static void gizmotype_unlink(bContext *C, Main *bmain, wmGizmoType *gzt)
{
/* Free instances. */
- for (bScreen *sc = bmain->screens.first; sc; sc = sc->id.next) {
- for (ScrArea *sa = sc->areabase.first; sa; sa = sa->next) {
- for (SpaceLink *sl = sa->spacedata.first; sl; sl = sl->next) {
- ListBase *lb = (sl == sa->spacedata.first) ? &sa->regionbase : &sl->regionbase;
- for (ARegion *region = lb->first; region; region = region->next) {
+ for (bScreen *screen = bmain->screens.first; screen; screen = screen->id.next) {
+ LISTBASE_FOREACH (ScrArea *, area, &screen->areabase) {
+ LISTBASE_FOREACH (SpaceLink *, sl, &area->spacedata) {
+ ListBase *lb = (sl == area->spacedata.first) ? &area->regionbase : &sl->regionbase;
+ LISTBASE_FOREACH (ARegion *, region, lb) {
wmGizmoMap *gzmap = region->gizmo_map;
if (gzmap) {
wmGizmoGroup *gzgroup;
diff --git a/source/blender/windowmanager/intern/wm.c b/source/blender/windowmanager/intern/wm.c
index 0c74debf2d2..6edf0f9edfd 100644
--- a/source/blender/windowmanager/intern/wm.c
+++ b/source/blender/windowmanager/intern/wm.c
@@ -44,8 +44,10 @@
#include "BKE_idprop.h"
#include "BKE_idtype.h"
#include "BKE_lib_id.h"
+#include "BKE_lib_query.h"
#include "BKE_main.h"
#include "BKE_report.h"
+#include "BKE_screen.h"
#include "BKE_workspace.h"
#include "WM_api.h"
@@ -55,6 +57,9 @@
#include "wm_draw.h"
#include "wm_event_system.h"
#include "wm_window.h"
+#ifdef WITH_XR_OPENXR
+# include "wm_xr.h"
+#endif
#include "BKE_undo_system.h"
#include "ED_screen.h"
@@ -70,6 +75,28 @@ static void window_manager_free_data(ID *id)
wm_close_and_free(NULL, (wmWindowManager *)id);
}
+static void window_manager_foreach_id(ID *id, LibraryForeachIDData *data)
+{
+ wmWindowManager *wm = (wmWindowManager *)id;
+
+ LISTBASE_FOREACH (wmWindow *, win, &wm->windows) {
+ BKE_LIB_FOREACHID_PROCESS(data, win->scene, IDWALK_CB_USER_ONE);
+
+ /* This pointer can be NULL during old files reading, better be safe than sorry. */
+ if (win->workspace_hook != NULL) {
+ ID *workspace = (ID *)BKE_workspace_active_get(win->workspace_hook);
+ BKE_LIB_FOREACHID_PROCESS_ID(data, workspace, IDWALK_CB_NOP);
+ /* allow callback to set a different workspace */
+ BKE_workspace_active_set(win->workspace_hook, (WorkSpace *)workspace);
+ }
+ if (BKE_lib_query_foreachid_process_flags_get(data) & IDWALK_INCLUDE_UI) {
+ LISTBASE_FOREACH (ScrArea *, area, &win->global_areas.areabase) {
+ BKE_screen_foreach_id_screen_area(data, area);
+ }
+ }
+ }
+}
+
IDTypeInfo IDType_ID_WM = {
.id_code = ID_WM,
.id_filter = 0,
@@ -84,6 +111,7 @@ IDTypeInfo IDType_ID_WM = {
.copy_data = NULL,
.free_data = window_manager_free_data,
.make_local = NULL,
+ .foreach_id = window_manager_foreach_id,
};
#define MAX_OP_REGISTERED 32
@@ -356,11 +384,11 @@ void wm_add_default(Main *bmain, bContext *C)
WorkSpaceLayout *layout = BKE_workspace_layout_find_global(bmain, screen, &workspace);
CTX_wm_manager_set(C, wm);
- win = wm_window_new(bmain, wm, NULL);
+ win = wm_window_new(bmain, wm, NULL, false);
win->scene = CTX_data_scene(C);
STRNCPY(win->view_layer_name, CTX_data_view_layer(C)->name);
BKE_workspace_active_set(win->workspace_hook, workspace);
- BKE_workspace_hook_layout_for_workspace_set(win->workspace_hook, workspace, layout);
+ BKE_workspace_active_layout_set(win->workspace_hook, workspace, layout);
screen->winid = win->winid;
wm->winactive = win;
diff --git a/source/blender/windowmanager/intern/wm_cursors.c b/source/blender/windowmanager/intern/wm_cursors.c
index aa80064fae7..2af68956923 100644
--- a/source/blender/windowmanager/intern/wm_cursors.c
+++ b/source/blender/windowmanager/intern/wm_cursors.c
@@ -145,6 +145,16 @@ void WM_cursor_set(wmWindow *win, int curs)
return; /* Can't set custom cursor before Window init */
}
+ if (curs == WM_CURSOR_DEFAULT && win->modalcursor) {
+ curs = win->modalcursor;
+ }
+
+ if (win->cursor == curs) {
+ return; /* Cursor is already set */
+ }
+
+ win->cursor = curs;
+
if (curs == WM_CURSOR_NONE) {
GHOST_SetCursorVisibility(win->ghostwin, 0);
return;
@@ -152,12 +162,6 @@ void WM_cursor_set(wmWindow *win, int curs)
GHOST_SetCursorVisibility(win->ghostwin, 1);
- if (curs == WM_CURSOR_DEFAULT && win->modalcursor) {
- curs = win->modalcursor;
- }
-
- win->cursor = curs;
-
if (curs < 0 || curs >= WM_CURSOR_NUM) {
BLI_assert(!"Invalid cursor number");
return;
@@ -183,13 +187,13 @@ void WM_cursor_set(wmWindow *win, int curs)
}
}
-bool WM_cursor_set_from_tool(struct wmWindow *win, const ScrArea *sa, const ARegion *region)
+bool WM_cursor_set_from_tool(struct wmWindow *win, const ScrArea *area, const ARegion *region)
{
if (region && (region->regiontype != RGN_TYPE_WINDOW)) {
return false;
}
- bToolRef_Runtime *tref_rt = (sa && sa->runtime.tool) ? sa->runtime.tool->runtime : NULL;
+ bToolRef_Runtime *tref_rt = (area && area->runtime.tool) ? area->runtime.tool->runtime : NULL;
if (tref_rt && tref_rt->cursor != WM_CURSOR_DEFAULT) {
if (win->modalcursor == 0) {
WM_cursor_set(win, tref_rt->cursor);
diff --git a/source/blender/windowmanager/intern/wm_draw.c b/source/blender/windowmanager/intern/wm_draw.c
index 6e1c815dbca..730c5b3b0c2 100644
--- a/source/blender/windowmanager/intern/wm_draw.c
+++ b/source/blender/windowmanager/intern/wm_draw.c
@@ -73,19 +73,28 @@
# include "BKE_subsurf.h"
#endif
-/* ******************* paint cursor *************** */
+/* -------------------------------------------------------------------- */
+/** \name Draw Paint Cursor
+ * \{ */
-static void wm_paintcursor_draw(bContext *C, ScrArea *sa, ARegion *region)
+static void wm_paintcursor_draw(bContext *C, ScrArea *area, ARegion *region)
{
wmWindowManager *wm = CTX_wm_manager(C);
wmWindow *win = CTX_wm_window(C);
bScreen *screen = WM_window_get_active_screen(win);
wmPaintCursor *pc;
+ /* Don't draw paint cursors with locked interface. Painting is not possible
+ * then, and cursor drawing can use scene data that another thread may be
+ * modifying. */
+ if (wm->is_interface_locked) {
+ return;
+ }
+
if (region->visible && region == screen->active_region) {
for (pc = wm->paintcursors.first; pc; pc = pc->next) {
- if ((pc->space_type != SPACE_TYPE_ANY) && (sa->spacetype != pc->space_type)) {
+ if ((pc->space_type != SPACE_TYPE_ANY) && (area->spacetype != pc->space_type)) {
continue;
}
@@ -116,8 +125,14 @@ static void wm_paintcursor_draw(bContext *C, ScrArea *sa, ARegion *region)
}
}
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Internal Utilities
+ * \{ */
+
static bool wm_draw_region_stereo_set(Main *bmain,
- ScrArea *sa,
+ ScrArea *area,
ARegion *region,
eStereoViews sview)
{
@@ -127,10 +142,10 @@ static bool wm_draw_region_stereo_set(Main *bmain,
return false;
}
- switch (sa->spacetype) {
+ switch (area->spacetype) {
case SPACE_IMAGE: {
if (region->regiontype == RGN_TYPE_WINDOW) {
- SpaceImage *sima = sa->spacedata.first;
+ SpaceImage *sima = area->spacedata.first;
sima->iuser.multiview_eye = sview;
return true;
}
@@ -138,7 +153,7 @@ static bool wm_draw_region_stereo_set(Main *bmain,
}
case SPACE_VIEW3D: {
if (region->regiontype == RGN_TYPE_WINDOW) {
- View3D *v3d = sa->spacedata.first;
+ View3D *v3d = area->spacedata.first;
if (v3d->camera && v3d->camera->type == OB_CAMERA) {
RegionView3D *rv3d = region->regiondata;
RenderEngine *engine = rv3d->render_engine;
@@ -159,7 +174,7 @@ static bool wm_draw_region_stereo_set(Main *bmain,
}
case SPACE_NODE: {
if (region->regiontype == RGN_TYPE_WINDOW) {
- SpaceNode *snode = sa->spacedata.first;
+ SpaceNode *snode = area->spacedata.first;
if ((snode->flag & SNODE_BACKDRAW) && ED_node_is_compositor(snode)) {
Image *ima = BKE_image_ensure_viewer(bmain, IMA_TYPE_COMPOSITE, "Viewer Node");
ima->eye = sview;
@@ -169,7 +184,7 @@ static bool wm_draw_region_stereo_set(Main *bmain,
break;
}
case SPACE_SEQ: {
- SpaceSeq *sseq = sa->spacedata.first;
+ SpaceSeq *sseq = area->spacedata.first;
sseq->multiview_eye = sview;
if (region->regiontype == RGN_TYPE_PREVIEW) {
@@ -184,17 +199,15 @@ static bool wm_draw_region_stereo_set(Main *bmain,
return false;
}
-/* ********************* drawing ****************** */
-
-static void wm_area_mark_invalid_backbuf(ScrArea *sa)
+static void wm_area_mark_invalid_backbuf(ScrArea *area)
{
- if (sa->spacetype == SPACE_VIEW3D) {
- ((View3D *)sa->spacedata.first)->flag |= V3D_INVALID_BACKBUF;
+ if (area->spacetype == SPACE_VIEW3D) {
+ ((View3D *)area->spacedata.first)->flag |= V3D_INVALID_BACKBUF;
}
}
static void wm_region_test_gizmo_do_draw(bContext *C,
- ScrArea *sa,
+ ScrArea *area,
ARegion *region,
bool tag_redraw)
{
@@ -203,13 +216,12 @@ static void wm_region_test_gizmo_do_draw(bContext *C,
}
wmGizmoMap *gzmap = region->gizmo_map;
- for (wmGizmoGroup *gzgroup = WM_gizmomap_group_list(gzmap)->first; gzgroup;
- gzgroup = gzgroup->next) {
+ LISTBASE_FOREACH (wmGizmoGroup *, gzgroup, WM_gizmomap_group_list(gzmap)) {
if (tag_redraw && (gzgroup->type->flag & WM_GIZMOGROUPTYPE_VR_REDRAWS)) {
- ScrArea *ctx_sa = CTX_wm_area(C);
- ARegion *ctx_ar = CTX_wm_region(C);
+ ScrArea *ctx_area = CTX_wm_area(C);
+ ARegion *ctx_region = CTX_wm_region(C);
- CTX_wm_area_set(C, sa);
+ CTX_wm_area_set(C, area);
CTX_wm_region_set(C, region);
if (WM_gizmo_group_type_poll(C, gzgroup->type)) {
@@ -217,11 +229,11 @@ static void wm_region_test_gizmo_do_draw(bContext *C,
}
/* Reset. */
- CTX_wm_area_set(C, ctx_sa);
- CTX_wm_region_set(C, ctx_ar);
+ CTX_wm_area_set(C, ctx_area);
+ CTX_wm_region_set(C, ctx_region);
}
- for (wmGizmo *gz = gzgroup->gizmos.first; gz; gz = gz->next) {
+ LISTBASE_FOREACH (wmGizmo *, gz, &gzgroup->gizmos) {
if (gz->do_draw) {
if (tag_redraw) {
ED_region_tag_redraw_editor_overlays(region);
@@ -234,17 +246,17 @@ static void wm_region_test_gizmo_do_draw(bContext *C,
static void wm_region_test_render_do_draw(const Scene *scene,
struct Depsgraph *depsgraph,
- ScrArea *sa,
+ ScrArea *area,
ARegion *region)
{
/* tag region for redraw from render engine preview running inside of it */
- if (sa->spacetype == SPACE_VIEW3D && region->regiontype == RGN_TYPE_WINDOW) {
+ if (area->spacetype == SPACE_VIEW3D && region->regiontype == RGN_TYPE_WINDOW) {
RegionView3D *rv3d = region->regiondata;
RenderEngine *engine = rv3d->render_engine;
GPUViewport *viewport = WM_draw_region_get_viewport(region);
if (engine && (engine->flag & RE_ENGINE_DO_DRAW)) {
- View3D *v3d = sa->spacedata.first;
+ View3D *v3d = area->spacedata.first;
rcti border_rect;
/* do partial redraw when possible */
@@ -281,13 +293,18 @@ static bool wm_region_use_viewport_by_type(short space_type, short region_type)
return (ELEM(space_type, SPACE_VIEW3D, SPACE_IMAGE) && region_type == RGN_TYPE_WINDOW);
}
-static bool wm_region_use_viewport(ScrArea *sa, ARegion *region)
+bool WM_region_use_viewport(ScrArea *area, ARegion *region)
{
- return wm_region_use_viewport_by_type(sa->spacetype, region->regiontype);
+ return wm_region_use_viewport_by_type(area->spacetype, region->regiontype);
}
-/********************** draw all **************************/
-/* - reference method, draw all each time */
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Window Drawing (Draw All)
+ *
+ * Reference method, draw all each time.
+ * \{ */
typedef struct WindowDrawCB {
struct WindowDrawCB *next, *prev;
@@ -312,7 +329,7 @@ void *WM_draw_cb_activate(wmWindow *win,
void WM_draw_cb_exit(wmWindow *win, void *handle)
{
- for (WindowDrawCB *wdc = win->drawcalls.first; wdc; wdc = wdc->next) {
+ LISTBASE_FOREACH (WindowDrawCB *, wdc, &win->drawcalls) {
if (wdc == (WindowDrawCB *)handle) {
BLI_remlink(&win->drawcalls, wdc);
MEM_freeN(wdc);
@@ -323,17 +340,21 @@ void WM_draw_cb_exit(wmWindow *win, void *handle)
static void wm_draw_callbacks(wmWindow *win)
{
- for (WindowDrawCB *wdc = win->drawcalls.first; wdc; wdc = wdc->next) {
+ LISTBASE_FOREACH (WindowDrawCB *, wdc, &win->drawcalls) {
wdc->draw(win, wdc->customdata);
}
}
-/************************* Region drawing. ********************************
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Region Drawing
*
- * Each region draws into its own framebuffer, which is then blit on the
+ * Each region draws into its own frame-buffer, which is then blit on the
* window draw buffer. This helps with fast redrawing if only some regions
* change. It also means we can share a single context for multiple windows,
- * so that for example VAOs can be shared between windows. */
+ * so that for example VAOs can be shared between windows.
+ * \{ */
static void wm_draw_region_buffer_free(ARegion *region)
{
@@ -553,13 +574,13 @@ void wm_draw_region_blend(ARegion *region, int view, bool blend)
alpha = 1.0f;
}
- glUniform1i(GPU_shader_get_uniform_ensure(shader, "image"), 0);
- glUniform4f(GPU_shader_get_uniform_ensure(shader, "rect_icon"),
+ glUniform1i(GPU_shader_get_uniform(shader, "image"), 0);
+ glUniform4f(GPU_shader_get_uniform(shader, "rect_icon"),
rect_tex.xmin,
rect_tex.ymin,
rect_tex.xmax,
rect_tex.ymax);
- glUniform4f(GPU_shader_get_uniform_ensure(shader, "rect_geom"),
+ glUniform4f(GPU_shader_get_uniform(shader, "rect_geom"),
rect_geo.xmin,
rect_geo.ymin,
rect_geo.xmax,
@@ -604,12 +625,11 @@ static void wm_draw_window_offscreen(bContext *C, wmWindow *win, bool stereo)
bScreen *screen = WM_window_get_active_screen(win);
/* Draw screen areas into own frame buffer. */
- ED_screen_areas_iter(win, screen, sa)
- {
- CTX_wm_area_set(C, sa);
+ ED_screen_areas_iter (win, screen, area) {
+ CTX_wm_area_set(C, area);
/* Compute UI layouts for dynamically size regions. */
- for (ARegion *region = sa->regionbase.first; region; region = region->next) {
+ LISTBASE_FOREACH (ARegion *, region, &area->regionbase) {
/* Dynamic region may have been flagged as too small because their size on init is 0.
* ARegion.visible is false then, as expected. The layout should still be created then, so
* the region size can be updated (it may turn out to be not too small then). */
@@ -625,22 +645,22 @@ static void wm_draw_window_offscreen(bContext *C, wmWindow *win, bool stereo)
}
}
- ED_area_update_region_sizes(wm, win, sa);
+ ED_area_update_region_sizes(wm, win, area);
- if (sa->flag & AREA_FLAG_ACTIVE_TOOL_UPDATE) {
- if ((1 << sa->spacetype) & WM_TOOLSYSTEM_SPACE_MASK) {
- WM_toolsystem_update_from_context(C, CTX_wm_workspace(C), CTX_data_view_layer(C), sa);
+ if (area->flag & AREA_FLAG_ACTIVE_TOOL_UPDATE) {
+ if ((1 << area->spacetype) & WM_TOOLSYSTEM_SPACE_MASK) {
+ WM_toolsystem_update_from_context(C, CTX_wm_workspace(C), CTX_data_view_layer(C), area);
}
- sa->flag &= ~AREA_FLAG_ACTIVE_TOOL_UPDATE;
+ area->flag &= ~AREA_FLAG_ACTIVE_TOOL_UPDATE;
}
/* Then do actual drawing of regions. */
- for (ARegion *region = sa->regionbase.first; region; region = region->next) {
+ LISTBASE_FOREACH (ARegion *, region, &area->regionbase) {
if (region->visible && region->do_draw) {
CTX_wm_region_set(C, region);
- bool use_viewport = wm_region_use_viewport(sa, region);
+ bool use_viewport = WM_region_use_viewport(area, region);
- if (stereo && wm_draw_region_stereo_set(bmain, sa, region, STEREO_LEFT_ID)) {
+ if (stereo && wm_draw_region_stereo_set(bmain, area, region, STEREO_LEFT_ID)) {
wm_draw_region_buffer_create(region, true, use_viewport);
for (int view = 0; view < 2; view++) {
@@ -650,7 +670,7 @@ static void wm_draw_window_offscreen(bContext *C, wmWindow *win, bool stereo)
}
else {
sview = STEREO_RIGHT_ID;
- wm_draw_region_stereo_set(bmain, sa, region, sview);
+ wm_draw_region_stereo_set(bmain, area, region, sview);
}
wm_draw_region_bind(region, view);
@@ -674,12 +694,12 @@ static void wm_draw_window_offscreen(bContext *C, wmWindow *win, bool stereo)
}
}
- wm_area_mark_invalid_backbuf(sa);
+ wm_area_mark_invalid_backbuf(area);
CTX_wm_area_set(C, NULL);
}
/* Draw menus into their own framebuffer. */
- for (ARegion *region = screen->regionbase.first; region; region = region->next) {
+ LISTBASE_FOREACH (ARegion *, region, &screen->regionbase) {
if (region->visible) {
CTX_wm_menu_set(C, region);
@@ -720,9 +740,8 @@ static void wm_draw_window_onscreen(bContext *C, wmWindow *win, int view)
#endif
/* Blit non-overlapping area regions. */
- ED_screen_areas_iter(win, screen, sa)
- {
- for (ARegion *region = sa->regionbase.first; region; region = region->next) {
+ ED_screen_areas_iter (win, screen, area) {
+ LISTBASE_FOREACH (ARegion *, region, &area->regionbase) {
if (region->visible && region->overlap == false) {
/* Blit from offscreen buffer. */
wm_draw_region_blit(region, view);
@@ -732,15 +751,14 @@ static void wm_draw_window_onscreen(bContext *C, wmWindow *win, int view)
/* Draw paint cursors. */
if (wm->paintcursors.first) {
- ED_screen_areas_iter(win, screen, sa)
- {
- for (ARegion *region = sa->regionbase.first; region; region = region->next) {
+ ED_screen_areas_iter (win, screen, area) {
+ LISTBASE_FOREACH (ARegion *, region, &area->regionbase) {
if (region->visible && region == screen->active_region) {
- CTX_wm_area_set(C, sa);
+ CTX_wm_area_set(C, area);
CTX_wm_region_set(C, region);
/* make region ready for draw, scissor, pixelspace */
- wm_paintcursor_draw(C, sa, region);
+ wm_paintcursor_draw(C, area, region);
CTX_wm_region_set(C, NULL);
CTX_wm_area_set(C, NULL);
@@ -752,9 +770,8 @@ static void wm_draw_window_onscreen(bContext *C, wmWindow *win, int view)
}
/* Blend in overlapping area regions */
- ED_screen_areas_iter(win, screen, sa)
- {
- for (ARegion *region = sa->regionbase.first; region; region = region->next) {
+ ED_screen_areas_iter (win, screen, area) {
+ LISTBASE_FOREACH (ARegion *, region, &area->regionbase) {
if (region->visible && region->overlap) {
wm_draw_region_blend(region, 0, true);
}
@@ -766,7 +783,7 @@ static void wm_draw_window_onscreen(bContext *C, wmWindow *win, int view)
wm_draw_callbacks(win);
/* Blend in floating regions (menus). */
- for (ARegion *region = screen->regionbase.first; region; region = region->next) {
+ LISTBASE_FOREACH (ARegion *, region, &screen->regionbase) {
if (region->visible) {
wm_draw_region_blend(region, 0, true);
}
@@ -831,6 +848,7 @@ static void wm_draw_window(bContext *C, wmWindow *win)
glActiveTexture(GL_TEXTURE0);
glBindTexture(GL_TEXTURE_2D, GPU_texture_opengl_bindcode(texture));
+ wmWindowViewport(win);
if (win->stereo3d_format->display_mode == S3D_DISPLAY_SIDEBYSIDE) {
wm_stereo3d_draw_sidebyside(win, view);
}
@@ -866,7 +884,11 @@ static void wm_draw_surface(bContext *C, wmSurface *surface)
wm_surface_clear_drawable();
}
-/****************** main update call **********************/
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Main Update Call
+ * \{ */
/* quick test to prevent changing window drawable */
static bool wm_draw_update_test_window(Main *bmain, bContext *C, wmWindow *win)
@@ -889,13 +911,12 @@ static bool wm_draw_update_test_window(Main *bmain, bContext *C, wmWindow *win)
}
}
- ED_screen_areas_iter(win, screen, sa)
- {
- for (region = sa->regionbase.first; region; region = region->next) {
- wm_region_test_gizmo_do_draw(C, sa, region, true);
- wm_region_test_render_do_draw(scene, depsgraph, sa, region);
+ ED_screen_areas_iter (win, screen, area) {
+ for (region = area->regionbase.first; region; region = region->next) {
+ wm_region_test_gizmo_do_draw(C, area, region, true);
+ wm_region_test_render_do_draw(scene, depsgraph, area, region);
#ifdef WITH_XR_OPENXR
- wm_region_test_xr_do_draw(wm, sa, region);
+ wm_region_test_xr_do_draw(wm, area, region);
#endif
if (region->visible && region->do_draw) {
@@ -937,10 +958,9 @@ static void wm_draw_update_clear_window(bContext *C, wmWindow *win)
{
bScreen *screen = WM_window_get_active_screen(win);
- ED_screen_areas_iter(win, screen, sa)
- {
- for (ARegion *region = sa->regionbase.first; region; region = region->next) {
- wm_region_test_gizmo_do_draw(C, sa, region, false);
+ ED_screen_areas_iter (win, screen, area) {
+ LISTBASE_FOREACH (ARegion *, region, &area->regionbase) {
+ wm_region_test_gizmo_do_draw(C, area, region, false);
}
}
@@ -963,10 +983,6 @@ void wm_draw_update(bContext *C)
wmWindowManager *wm = CTX_wm_manager(C);
wmWindow *win;
-#ifdef WITH_OPENSUBDIV
- BKE_subsurf_free_unused_buffers();
-#endif
-
GPU_free_unused_buffers(bmain);
for (win = wm->windows.first; win; win = win->next) {
@@ -1012,16 +1028,18 @@ void wm_draw_region_clear(wmWindow *win, ARegion *UNUSED(region))
screen->do_draw = true;
}
-void WM_draw_region_free(ARegion *region)
+void WM_draw_region_free(ARegion *region, bool hide)
{
wm_draw_region_buffer_free(region);
- region->visible = 0;
+ if (hide) {
+ region->visible = 0;
+ }
}
-void wm_draw_region_test(bContext *C, ScrArea *sa, ARegion *region)
+void wm_draw_region_test(bContext *C, ScrArea *area, ARegion *region)
{
/* Function for redraw timer benchmark. */
- bool use_viewport = wm_region_use_viewport(sa, region);
+ bool use_viewport = WM_region_use_viewport(area, region);
wm_draw_region_buffer_create(region, false, use_viewport);
wm_draw_region_bind(region, 0);
ED_region_do_draw(C, region);
@@ -1033,15 +1051,17 @@ void WM_redraw_windows(bContext *C)
{
wmWindow *win_prev = CTX_wm_window(C);
ScrArea *area_prev = CTX_wm_area(C);
- ARegion *ar_prev = CTX_wm_region(C);
+ ARegion *region_prev = CTX_wm_region(C);
wm_draw_update(C);
CTX_wm_window_set(C, win_prev);
CTX_wm_area_set(C, area_prev);
- CTX_wm_region_set(C, ar_prev);
+ CTX_wm_region_set(C, region_prev);
}
+/** \} */
+
/* -------------------------------------------------------------------- */
/** \name Region Viewport Drawing
*
diff --git a/source/blender/windowmanager/intern/wm_event_query.c b/source/blender/windowmanager/intern/wm_event_query.c
index 5b1c7680adc..381c06983a8 100644
--- a/source/blender/windowmanager/intern/wm_event_query.c
+++ b/source/blender/windowmanager/intern/wm_event_query.c
@@ -61,18 +61,28 @@ void WM_event_print(const wmEvent *event)
const char *unknown = "UNKNOWN";
const char *type_id = unknown;
const char *val_id = unknown;
+ const char *prev_type_id = unknown;
+ const char *prev_val_id = unknown;
RNA_enum_identifier(rna_enum_event_type_items, event->type, &type_id);
RNA_enum_identifier(rna_enum_event_value_items, event->val, &val_id);
+ RNA_enum_identifier(rna_enum_event_type_items, event->prevtype, &prev_type_id);
+ RNA_enum_identifier(rna_enum_event_value_items, event->prevval, &prev_val_id);
+
printf(
"wmEvent type:%d / %s, val:%d / %s,\n"
+ " prev_type:%d / %s, prev_val:%d / %s,\n"
" shift:%d, ctrl:%d, alt:%d, oskey:%d, keymodifier:%d, is_repeat:%d,\n"
" mouse:(%d,%d), ascii:'%c', utf8:'%.*s', pointer:%p\n",
event->type,
type_id,
event->val,
val_id,
+ event->prevtype,
+ prev_type_id,
+ event->prevval,
+ prev_val_id,
event->shift,
event->ctrl,
event->alt,
diff --git a/source/blender/windowmanager/intern/wm_event_system.c b/source/blender/windowmanager/intern/wm_event_system.c
index 0957a5c52a0..9a90e73af39 100644
--- a/source/blender/windowmanager/intern/wm_event_system.c
+++ b/source/blender/windowmanager/intern/wm_event_system.c
@@ -1,4 +1,4 @@
-/*
+/*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 2
@@ -197,7 +197,7 @@ void wm_event_init_from_window(wmWindow *win, wmEvent *event)
static bool wm_test_duplicate_notifier(const wmWindowManager *wm, uint type, void *reference)
{
- for (wmNotifier *note = wm->queue.first; note; note = note->next) {
+ LISTBASE_FOREACH (wmNotifier *, note, &wm->queue) {
if ((note->category | note->data | note->subtype | note->action) == type &&
note->reference == reference) {
return 1;
@@ -290,16 +290,16 @@ void WM_main_remove_notifier_reference(const void *reference)
void WM_main_remap_editor_id_reference(ID *old_id, ID *new_id)
{
Main *bmain = G_MAIN;
- bScreen *sc;
+ bScreen *screen;
- for (sc = bmain->screens.first; sc; sc = sc->id.next) {
- ScrArea *sa;
+ for (screen = bmain->screens.first; screen; screen = screen->id.next) {
+ ScrArea *area;
- for (sa = sc->areabase.first; sa; sa = sa->next) {
+ for (area = screen->areabase.first; area; area = area->next) {
SpaceLink *sl;
- for (sl = sa->spacedata.first; sl; sl = sl->next) {
- ED_spacedata_id_remap(sa, sl, old_id, new_id);
+ for (sl = area->spacedata.first; sl; sl = sl->next) {
+ ED_spacedata_id_remap(area, sl, old_id, new_id);
}
}
}
@@ -334,14 +334,14 @@ void wm_event_do_depsgraph(bContext *C, bool is_after_open_file)
}
/* Combine datamasks so 1 win doesn't disable UV's in another [#26448]. */
CustomData_MeshMasks win_combine_v3d_datamask = {0};
- for (wmWindow *win = wm->windows.first; win; win = win->next) {
+ LISTBASE_FOREACH (wmWindow *, win, &wm->windows) {
const Scene *scene = WM_window_get_active_scene(win);
const bScreen *screen = WM_window_get_active_screen(win);
ED_view3d_screen_datamask(C, scene, screen, &win_combine_v3d_datamask);
}
/* Update all the dependency graphs of visible view layers. */
- for (wmWindow *win = wm->windows.first; win; win = win->next) {
+ LISTBASE_FOREACH (wmWindow *, win, &wm->windows) {
Scene *scene = WM_window_get_active_scene(win);
ViewLayer *view_layer = WM_window_get_active_view_layer(win);
Main *bmain = CTX_data_main(C);
@@ -374,15 +374,15 @@ void wm_event_do_refresh_wm_and_depsgraph(bContext *C)
{
wmWindowManager *wm = CTX_wm_manager(C);
/* cached: editor refresh callbacks now, they get context */
- for (wmWindow *win = wm->windows.first; win; win = win->next) {
+ LISTBASE_FOREACH (wmWindow *, win, &wm->windows) {
const bScreen *screen = WM_window_get_active_screen(win);
- ScrArea *sa;
+ ScrArea *area;
CTX_wm_window_set(C, win);
- for (sa = screen->areabase.first; sa; sa = sa->next) {
- if (sa->do_refresh) {
- CTX_wm_area_set(C, sa);
- ED_area_do_refresh(C, sa);
+ for (area = screen->areabase.first; area; area = area->next) {
+ if (area->do_refresh) {
+ CTX_wm_area_set(C, area);
+ ED_area_do_refresh(C, area);
}
}
}
@@ -529,11 +529,10 @@ void wm_event_do_notifiers(bContext *C)
ED_region_do_listen(win, NULL, region, note, scene);
}
- ED_screen_areas_iter(win, screen, sa)
- {
- ED_area_do_listen(win, sa, note, scene);
- for (region = sa->regionbase.first; region; region = region->next) {
- ED_region_do_listen(win, sa, region, note, scene);
+ ED_screen_areas_iter (win, screen, area) {
+ ED_area_do_listen(win, area, note, scene);
+ for (region = area->regionbase.first; region; region = region->next) {
+ ED_region_do_listen(win, area, region, note, scene);
}
}
}
@@ -608,6 +607,12 @@ static int wm_handler_ui_call(bContext *C,
}
}
+ /* Don't block file-select events. Those are triggered by a separate file browser window.
+ * See T75292. */
+ if (event->type == EVT_FILESELECT) {
+ return WM_UI_HANDLER_CONTINUE;
+ }
+
/* we set context to where ui handler came from */
if (handler->context.area) {
CTX_wm_area_set(C, handler->context.area);
@@ -646,11 +651,11 @@ static int wm_handler_ui_call(bContext *C,
return WM_HANDLER_CONTINUE;
}
-static void wm_handler_ui_cancel(bContext *C)
+void wm_event_handler_ui_cancel_ex(bContext *C,
+ wmWindow *win,
+ ARegion *region,
+ bool reactivate_button)
{
- wmWindow *win = CTX_wm_window(C);
- ARegion *region = CTX_wm_region(C);
-
if (!region) {
return;
}
@@ -662,11 +667,19 @@ static void wm_handler_ui_cancel(bContext *C)
wmEvent event;
wm_event_init_from_window(win, &event);
event.type = EVT_BUT_CANCEL;
+ event.val = reactivate_button ? 0 : 1;
handler->handle_fn(C, &event, handler->user_data);
}
}
}
+static void wm_event_handler_ui_cancel(bContext *C)
+{
+ wmWindow *win = CTX_wm_window(C);
+ ARegion *region = CTX_wm_region(C);
+ wm_event_handler_ui_cancel_ex(C, win, region, true);
+}
+
/** \} */
/* -------------------------------------------------------------------- */
@@ -827,11 +840,11 @@ bool WM_operator_check_ui_empty(wmOperatorType *ot)
*/
void WM_operator_region_active_win_set(bContext *C)
{
- ScrArea *sa = CTX_wm_area(C);
- if (sa) {
+ ScrArea *area = CTX_wm_area(C);
+ if (area) {
ARegion *region = CTX_wm_region(C);
if (region && region->regiontype == RGN_TYPE_WINDOW) {
- sa->region_active_win = BLI_findindex(&sa->regionbase, region);
+ area->region_active_win = BLI_findindex(&area->regionbase, region);
}
}
}
@@ -844,7 +857,7 @@ static void wm_operator_reports(bContext *C, wmOperator *op, int retval, bool ca
/* FIXME, temp setting window, see other call to UI_popup_menu_reports for why */
wmWindow *win_prev = CTX_wm_window(C);
ScrArea *area_prev = CTX_wm_area(C);
- ARegion *ar_prev = CTX_wm_region(C);
+ ARegion *region_prev = CTX_wm_region(C);
if (win_prev == NULL) {
CTX_wm_window_set(C, CTX_wm_manager(C)->windows.first);
@@ -854,7 +867,7 @@ static void wm_operator_reports(bContext *C, wmOperator *op, int retval, bool ca
CTX_wm_window_set(C, win_prev);
CTX_wm_area_set(C, area_prev);
- CTX_wm_region_set(C, ar_prev);
+ CTX_wm_region_set(C, region_prev);
}
}
@@ -875,6 +888,10 @@ static void wm_operator_reports(bContext *C, wmOperator *op, int retval, bool ca
}
}
+ /* Refresh Info Editor with reports immediately, even if op returned OPERATOR_CANCELLED. */
+ if ((retval & OPERATOR_CANCELLED) && !BLI_listbase_is_empty(&op->reports->list)) {
+ WM_event_add_notifier(C, NC_SPACE | ND_SPACE_INFO_REPORT, NULL);
+ }
/* if the caller owns them, handle this */
wm_add_reports(op->reports);
}
@@ -949,9 +966,9 @@ static void wm_operator_finished(bContext *C, wmOperator *op, const bool repeat,
if (hud_status != NOP) {
if (hud_status == SET) {
- ScrArea *sa = CTX_wm_area(C);
- if (sa) {
- ED_area_type_hud_ensure(C, sa);
+ ScrArea *area = CTX_wm_area(C);
+ if (area) {
+ ED_area_type_hud_ensure(C, area);
}
}
else if (hud_status == CLEAR) {
@@ -1336,7 +1353,7 @@ static int wm_operator_invoke(bContext *C,
if (wrap) {
const rcti *winrect = NULL;
ARegion *region = CTX_wm_region(C);
- ScrArea *sa = CTX_wm_area(C);
+ ScrArea *area = CTX_wm_area(C);
/* Wrap only in X for header. */
if (region &&
@@ -1348,8 +1365,8 @@ static int wm_operator_invoke(bContext *C,
BLI_rcti_isect_pt_v(&region->winrct, &event->x)) {
winrect = &region->winrct;
}
- else if (sa && BLI_rcti_isect_pt_v(&sa->totrct, &event->x)) {
- winrect = &sa->totrct;
+ else if (area && BLI_rcti_isect_pt_v(&area->totrct, &event->x)) {
+ winrect = &area->totrct;
}
if (winrect) {
@@ -1367,7 +1384,7 @@ static int wm_operator_invoke(bContext *C,
* while dragging the view or worse, that stay there permanently
* after the modal operator has swallowed all events and passed
* none to the UI handler */
- wm_handler_ui_cancel(C);
+ wm_event_handler_ui_cancel(C);
}
else {
WM_operator_free(op);
@@ -1654,17 +1671,16 @@ static void wm_handler_op_context(bContext *C, wmEventHandler_Op *handler, const
CTX_wm_area_set(C, NULL);
}
else {
- ScrArea *sa = NULL;
+ ScrArea *area = NULL;
- ED_screen_areas_iter(win, screen, sa_iter)
- {
- if (sa_iter == handler->context.area) {
- sa = sa_iter;
+ ED_screen_areas_iter (win, screen, area_iter) {
+ if (area_iter == handler->context.area) {
+ area = area_iter;
break;
}
}
- if (sa == NULL) {
+ if (area == NULL) {
/* when changing screen layouts with running modal handlers (like render display), this
* is not an error to print */
if (handler->op == NULL) {
@@ -1676,10 +1692,10 @@ static void wm_handler_op_context(bContext *C, wmEventHandler_Op *handler, const
else {
ARegion *region;
wmOperator *op = handler->op ? (handler->op->opm ? handler->op->opm : handler->op) : NULL;
- CTX_wm_area_set(C, sa);
+ CTX_wm_area_set(C, area);
if (op && (op->flag & OP_IS_MODAL_CURSOR_REGION)) {
- region = BKE_area_find_region_xy(sa, handler->context.region_type, event->x, event->y);
+ region = BKE_area_find_region_xy(area, handler->context.region_type, event->x, event->y);
if (region) {
handler->context.region = region;
}
@@ -1689,7 +1705,7 @@ static void wm_handler_op_context(bContext *C, wmEventHandler_Op *handler, const
}
if (region == NULL) {
- for (region = sa->regionbase.first; region; region = region->next) {
+ for (region = area->regionbase.first; region; region = region->next) {
if (region == handler->context.region) {
break;
}
@@ -1868,7 +1884,7 @@ static wmKeyMapItem *wm_eventmatch_modal_keymap_items(const wmKeyMap *keymap,
wmOperator *op,
const wmEvent *event)
{
- for (wmKeyMapItem *kmi = keymap->items.first; kmi; kmi = kmi->next) {
+ LISTBASE_FOREACH (wmKeyMapItem *, kmi, &keymap->items) {
/* Should already be handled by #wm_user_modal_keymap_set_items. */
BLI_assert(kmi->propvalue_str[0] == '\0');
if (wm_eventmatch(event, kmi)) {
@@ -2217,19 +2233,19 @@ static int wm_handler_fileselect_do(bContext *C,
}
else {
wmWindow *temp_win;
- ScrArea *ctx_sa = CTX_wm_area(C);
+ ScrArea *ctx_area = CTX_wm_area(C);
for (temp_win = wm->windows.first; temp_win; temp_win = temp_win->next) {
bScreen *screen = WM_window_get_active_screen(temp_win);
- ScrArea *file_sa = screen->areabase.first;
+ ScrArea *file_area = screen->areabase.first;
- if (screen->temp && (file_sa->spacetype == SPACE_FILE)) {
+ if (screen->temp && (file_area->spacetype == SPACE_FILE)) {
int win_size[2];
bool is_maximized;
ED_fileselect_window_params_get(temp_win, win_size, &is_maximized);
- ED_fileselect_params_to_userdef(file_sa->spacedata.first, win_size, is_maximized);
+ ED_fileselect_params_to_userdef(file_area->spacedata.first, win_size, is_maximized);
- if (BLI_listbase_is_single(&file_sa->spacedata)) {
+ if (BLI_listbase_is_single(&file_area->spacedata)) {
BLI_assert(ctx_win != temp_win);
wm_window_close(C, wm, temp_win);
@@ -2245,20 +2261,20 @@ static int wm_handler_fileselect_do(bContext *C,
handler->context.win = NULL;
}
}
- else if (file_sa->full) {
- ED_screen_full_prevspace(C, file_sa);
+ else if (file_area->full) {
+ ED_screen_full_prevspace(C, file_area);
}
else {
- ED_area_prevspace(C, file_sa);
+ ED_area_prevspace(C, file_area);
}
break;
}
}
- if (!temp_win && ctx_sa->full) {
- ED_fileselect_params_to_userdef(ctx_sa->spacedata.first, NULL, false);
- ED_screen_full_prevspace(C, ctx_sa);
+ if (!temp_win && ctx_area->full) {
+ ED_fileselect_params_to_userdef(ctx_area->spacedata.first, NULL, false);
+ ED_screen_full_prevspace(C, ctx_area);
}
}
@@ -2297,7 +2313,7 @@ static int wm_handler_fileselect_do(bContext *C,
* it can be removed without breaking anything but then no linking errors - campbell */
wmWindow *win_prev = CTX_wm_window(C);
ScrArea *area_prev = CTX_wm_area(C);
- ARegion *ar_prev = CTX_wm_region(C);
+ ARegion *region_prev = CTX_wm_region(C);
if (win_prev == NULL) {
CTX_wm_window_set(C, CTX_wm_manager(C)->windows.first);
@@ -2315,7 +2331,7 @@ static int wm_handler_fileselect_do(bContext *C,
CTX_wm_window_set(C, win_prev);
CTX_wm_area_set(C, area_prev);
- CTX_wm_region_set(C, ar_prev);
+ CTX_wm_region_set(C, region_prev);
}
/* for WM_operator_pystring only, custom report handling is done above */
@@ -2379,21 +2395,23 @@ static int wm_action_not_handled(int action)
return action == WM_HANDLER_CONTINUE || action == (WM_HANDLER_BREAK | WM_HANDLER_MODAL);
}
-static int wm_event_inside_rect(wmEvent *event, rcti *rect)
+static bool wm_event_inside_rect(const wmEvent *event, const rcti *rect)
{
- if (wm_event_always_pass(event))
- return 1;
- if (BLI_rcti_isect_pt_v(rect, &event->x))
- return 1;
- return 0;
+ if (wm_event_always_pass(event)) {
+ return true;
+ }
+ if (BLI_rcti_isect_pt_v(rect, &event->x)) {
+ return true;
+ }
+ return false;
}
-static bool wm_event_inside_region(const wmEvent *event, const ARegion *ar)
+static bool wm_event_inside_region(const wmEvent *event, const ARegion *region)
{
if (wm_event_always_pass(event)) {
return true;
}
- return ED_region_contains_xy(ar, &event->x);
+ return ED_region_contains_xy(region, &event->x);
}
static ScrArea *area_event_inside(bContext *C, const int xy[2])
@@ -2402,10 +2420,10 @@ static ScrArea *area_event_inside(bContext *C, const int xy[2])
bScreen *screen = CTX_wm_screen(C);
if (screen) {
- ED_screen_areas_iter(win, screen, sa)
- {
- if (BLI_rcti_isect_pt_v(&sa->totrct, xy))
- return sa;
+ ED_screen_areas_iter (win, screen, area) {
+ if (BLI_rcti_isect_pt_v(&area->totrct, xy)) {
+ return area;
+ }
}
}
return NULL;
@@ -2415,12 +2433,15 @@ static ARegion *region_event_inside(bContext *C, const int xy[2])
{
bScreen *screen = CTX_wm_screen(C);
ScrArea *area = CTX_wm_area(C);
- ARegion *ar;
+ ARegion *region;
- if (screen && area)
- for (ar = area->regionbase.first; ar; ar = ar->next)
- if (BLI_rcti_isect_pt_v(&ar->winrct, xy))
- return ar;
+ if (screen && area) {
+ for (region = area->regionbase.first; region; region = region->next) {
+ if (BLI_rcti_isect_pt_v(&region->winrct, xy)) {
+ return region;
+ }
+ }
+ }
return NULL;
}
@@ -2451,7 +2472,7 @@ static int wm_handlers_do_keymap_with_keymap_handler(
PRINT("pass\n");
- for (wmKeyMapItem *kmi = keymap->items.first; kmi; kmi = kmi->next) {
+ LISTBASE_FOREACH (wmKeyMapItem *, kmi, &keymap->items) {
if (wm_eventmatch(event, kmi)) {
struct wmEventHandler_KeymapPost keymap_post = handler->post;
@@ -2565,10 +2586,11 @@ static int wm_handlers_do_gizmo_handler(bContext *C,
wmGizmo *gz = wm_gizmomap_highlight_get(gzmap);
/* Needed so UI blocks over gizmos don't let events fall through to the gizmos,
- * noticeable for the node editor - where dragging on a node should move it, see: T73212. */
+ * noticeable for the node editor - where dragging on a node should move it, see: T73212.
+ * note we still allow for starting the gizmo drag outside, then travel 'inside' the node */
if (region->type->clip_gizmo_events_by_ui) {
if (UI_region_block_find_mouse_over(region, &event->x, true)) {
- if (gz != NULL) {
+ if (gz != NULL && event->type != EVT_GIZMO_UPDATE) {
WM_tooltip_clear(C, CTX_wm_window(C));
wm_gizmomap_highlight_set(gzmap, C, NULL, 0);
}
@@ -2623,7 +2645,7 @@ static int wm_handlers_do_gizmo_handler(bContext *C,
if (wm_gizmomap_highlight_set(gzmap, C, gz, part)) {
if (gz != NULL) {
- if (U.flag & USER_TOOLTIPS) {
+ if ((U.flag & USER_TOOLTIPS) && (gz->flag & WM_GIZMO_NO_TOOLTIP) == 0) {
WM_tooltip_timer_init(C, CTX_wm_window(C), area, region, WM_gizmomap_tooltip_init);
}
}
@@ -2635,7 +2657,7 @@ static int wm_handlers_do_gizmo_handler(bContext *C,
if (handle_keymap) {
/* Handle highlight gizmo. */
- if (gz != NULL) {
+ if ((gz != NULL) && (gz->flag & WM_GIZMO_HIDDEN_KEYMAP) == 0) {
bool keymap_poll = false;
wmGizmoGroup *gzgroup = gz->parent_gzgroup;
wmKeyMap *keymap = WM_keymap_active(wm, gz->keymap ? gz->keymap : gzgroup->type->keymap);
@@ -2656,7 +2678,7 @@ static int wm_handlers_do_gizmo_handler(bContext *C,
event_test_tweak.type = EVT_TWEAK_L + (event->type - LEFTMOUSE);
event_test_tweak.val = KM_ANY;
- for (wmKeyMapItem *kmi = keymap->items.first; kmi; kmi = kmi->next) {
+ LISTBASE_FOREACH (wmKeyMapItem *, kmi, &keymap->items) {
if ((kmi->flag & KMI_INACTIVE) == 0) {
if (wm_eventmatch(&event_test_click, kmi) ||
wm_eventmatch(&event_test_click_drag, kmi) ||
@@ -2681,7 +2703,7 @@ static int wm_handlers_do_gizmo_handler(bContext *C,
if ((action & WM_HANDLER_BREAK) == 0) {
if (WM_gizmomap_is_any_selected(gzmap)) {
const ListBase *groups = WM_gizmomap_group_list(gzmap);
- for (wmGizmoGroup *gzgroup = groups->first; gzgroup; gzgroup = gzgroup->next) {
+ LISTBASE_FOREACH (wmGizmoGroup *, gzgroup, groups) {
if (wm_gizmogroup_is_any_selected(gzgroup)) {
wmKeyMap *keymap = WM_keymap_active(wm, gzgroup->type->keymap);
action |= wm_handlers_do_keymap_with_gizmo_handler(
@@ -2708,6 +2730,12 @@ static int wm_handlers_do_gizmo_handler(bContext *C,
return action;
}
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Handle Single Event (All Handler Types)
+ * \{ */
+
static int wm_handlers_do_intern(bContext *C, wmEvent *event, ListBase *handlers)
{
const bool do_debug_handler =
@@ -2993,7 +3021,7 @@ static int wm_handlers_do(bContext *C, wmEvent *event, ListBase *handlers)
else {
wmWindow *win = CTX_wm_window(C);
if (win) {
- if (ISKEYMODIFIER(win->eventstate->prevtype)) {
+ if (ISKEYMODIFIER(win->eventstate->type)) {
win->eventstate->check_click = 0;
}
}
@@ -3003,6 +3031,14 @@ static int wm_handlers_do(bContext *C, wmEvent *event, ListBase *handlers)
return action;
}
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Event Queue Utilities
+ *
+ * Utilities used by #wm_event_do_handlers.
+ * \{ */
+
static void wm_paintcursor_tag(bContext *C, wmPaintCursor *pc, ARegion *region)
{
if (region) {
@@ -3030,14 +3066,14 @@ static void wm_paintcursor_test(bContext *C, const wmEvent *event)
/* if previous position was not in current region, we have to set a temp new context */
if (region == NULL || !BLI_rcti_isect_pt_v(&region->winrct, &event->prevx)) {
- ScrArea *sa = CTX_wm_area(C);
+ ScrArea *area = CTX_wm_area(C);
CTX_wm_area_set(C, area_event_inside(C, &event->prevx));
CTX_wm_region_set(C, region_event_inside(C, &event->prevx));
wm_paintcursor_tag(C, wm->paintcursors.first, CTX_wm_region(C));
- CTX_wm_area_set(C, sa);
+ CTX_wm_area_set(C, area);
CTX_wm_region_set(C, region);
}
}
@@ -3084,6 +3120,33 @@ static bool wm_event_pie_filter(wmWindow *win, const wmEvent *event)
}
}
+/**
+ * Account for the special case when events are being handled and a file is loaded.
+ * In this case event handling exits early, however when "Load UI" is disabled
+ * the even will still be in #wmWindow.queue.
+ *
+ * Without this it's possible to continuously handle the same event, see: T76484.
+ */
+static void wm_event_free_and_remove_from_queue_if_valid(wmEvent *event)
+{
+ LISTBASE_FOREACH (wmWindowManager *, wm, &G_MAIN->wm) {
+ LISTBASE_FOREACH (wmWindow *, win, &wm->windows) {
+ if (BLI_remlink_safe(&win->queue, event)) {
+ wm_event_free(event);
+ return;
+ }
+ }
+ }
+}
+
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Main Event Queue (Every Window)
+ *
+ * Handle events for all windows, run from the #WM_main event loop.
+ * \{ */
+
/* called in main loop */
/* goes over entire hierarchy: events -> window -> screen -> area -> region */
void wm_event_do_handlers(bContext *C)
@@ -3144,9 +3207,9 @@ void wm_event_do_handlers(bContext *C)
}
if (is_playing_sound == 0) {
- const float time = BKE_sound_sync_scene(scene_eval);
+ const double time = BKE_sound_sync_scene(scene_eval);
if (isfinite(time)) {
- int ncfra = time * (float)FPS + 0.5f;
+ int ncfra = time * FPS + 0.5;
if (ncfra != scene->r.cfra) {
scene->r.cfra = ncfra;
ED_update_for_newframe(CTX_data_main(C), depsgraph);
@@ -3206,6 +3269,7 @@ void wm_event_do_handlers(bContext *C)
/* fileread case */
if (CTX_wm_window(C) == NULL) {
+ wm_event_free_and_remove_from_queue_if_valid(event);
return;
}
@@ -3241,8 +3305,7 @@ void wm_event_do_handlers(bContext *C)
}
#endif
- ED_screen_areas_iter(win, screen, sa)
- {
+ ED_screen_areas_iter (win, screen, area) {
/* after restoring a screen from SCREENMAXIMIZED we have to wait
* with the screen handling till the region coordinates are updated */
if (screen->skip_handling == true) {
@@ -3252,15 +3315,15 @@ void wm_event_do_handlers(bContext *C)
}
/* update azones if needed - done here because it needs to be independent from redraws */
- if (sa->flag & AREA_FLAG_ACTIONZONES_UPDATE) {
- ED_area_azones_update(sa, &event->x);
+ if (area->flag & AREA_FLAG_ACTIONZONES_UPDATE) {
+ ED_area_azones_update(area, &event->x);
}
- if (wm_event_inside_rect(event, &sa->totrct)) {
- CTX_wm_area_set(C, sa);
+ if (wm_event_inside_rect(event, &area->totrct)) {
+ CTX_wm_area_set(C, area);
if ((action & WM_HANDLER_BREAK) == 0) {
- for (region = sa->regionbase.first; region; region = region->next) {
+ for (region = area->regionbase.first; region; region = region->next) {
if (wm_event_inside_region(event, region)) {
CTX_wm_region_set(C, region);
@@ -3278,6 +3341,7 @@ void wm_event_do_handlers(bContext *C)
/* fileread case (python), [#29489] */
if (CTX_wm_window(C) == NULL) {
+ wm_event_free_and_remove_from_queue_if_valid(event);
return;
}
@@ -3292,7 +3356,7 @@ void wm_event_do_handlers(bContext *C)
if ((action & WM_HANDLER_BREAK) == 0) {
wm_region_mouse_co(C, event); /* only invalidates event->mval in this case */
- action |= wm_handlers_do(C, event, &sa->handlers);
+ action |= wm_handlers_do(C, event, &area->handlers);
}
CTX_wm_area_set(C, NULL);
@@ -3312,6 +3376,7 @@ void wm_event_do_handlers(bContext *C)
/* fileread case */
if (CTX_wm_window(C) == NULL) {
+ wm_event_free_and_remove_from_queue_if_valid(event);
return;
}
}
@@ -3388,19 +3453,13 @@ void WM_event_add_fileselect(bContext *C, wmOperator *op)
wmWindowManager *wm = CTX_wm_manager(C);
wmWindow *win = CTX_wm_window(C);
const bool is_temp_screen = WM_window_is_temp_screen(win);
- const bool opens_window = (U.filebrowser_display_type == USER_TEMP_SPACE_DISPLAY_WINDOW);
- /* Don't add the file handler to the temporary window if one is opened, or else it owns the
- * handlers for itself, causing dangling pointers once it's destructed through a handler. It has
- * a parent which should hold the handlers itself. */
- ListBase *modalhandlers = (is_temp_screen && opens_window) ? &win->parent->modalhandlers :
- &win->modalhandlers;
/* Close any popups, like when opening a file browser from the splash. */
- UI_popup_handlers_remove_all(C, modalhandlers);
+ UI_popup_handlers_remove_all(C, &win->modalhandlers);
if (!is_temp_screen) {
/* only allow 1 file selector open per window */
- LISTBASE_FOREACH_MUTABLE (wmEventHandler *, handler_base, modalhandlers) {
+ LISTBASE_FOREACH_MUTABLE (wmEventHandler *, handler_base, &win->modalhandlers) {
if (handler_base->type == WM_HANDLER_TYPE_OP) {
wmEventHandler_Op *handler = (wmEventHandler_Op *)handler_base;
if (handler->is_fileselect == false) {
@@ -3410,13 +3469,12 @@ void WM_event_add_fileselect(bContext *C, wmOperator *op)
bool cancel_handler = true;
/* find the area with the file selector for this handler */
- ED_screen_areas_iter(win, screen, sa)
- {
- if (sa->spacetype == SPACE_FILE) {
- SpaceFile *sfile = sa->spacedata.first;
+ ED_screen_areas_iter (win, screen, area) {
+ if (area->spacetype == SPACE_FILE) {
+ SpaceFile *sfile = area->spacedata.first;
if (sfile->op == handler->op) {
- CTX_wm_area_set(C, sa);
+ CTX_wm_area_set(C, area);
wm_handler_fileselect_do(C, &win->modalhandlers, handler, EVT_FILESELECT_CANCEL);
cancel_handler = false;
break;
@@ -3442,7 +3500,7 @@ void WM_event_add_fileselect(bContext *C, wmOperator *op)
handler->context.area = CTX_wm_area(C);
handler->context.region = CTX_wm_region(C);
- BLI_addhead(modalhandlers, handler);
+ BLI_addhead(&win->modalhandlers, handler);
/* check props once before invoking if check is available
* ensures initial properties are valid */
@@ -3577,9 +3635,9 @@ wmEventHandler_Keymap *WM_event_add_keymap_handler(ListBase *handlers, wmKeyMap
wmKeyMap *WM_event_get_keymap_from_toolsystem_fallback(wmWindowManager *wm,
wmEventHandler_Keymap *handler)
{
- ScrArea *sa = handler->dynamic.user_data;
+ ScrArea *area = handler->dynamic.user_data;
handler->keymap_tool = NULL;
- bToolRef_Runtime *tref_rt = sa->runtime.tool ? sa->runtime.tool->runtime : NULL;
+ bToolRef_Runtime *tref_rt = area->runtime.tool ? area->runtime.tool->runtime : NULL;
if (tref_rt && tref_rt->keymap_fallback[0]) {
const char *keymap_id = NULL;
@@ -3587,7 +3645,7 @@ wmKeyMap *WM_event_get_keymap_from_toolsystem_fallback(wmWindowManager *wm,
if (tref_rt->gizmo_group[0] != '\0' && tref_rt->keymap_fallback[0] != '\n') {
wmGizmoMap *gzmap = NULL;
wmGizmoGroup *gzgroup = NULL;
- for (ARegion *region = sa->regionbase.first; region; region = region->next) {
+ LISTBASE_FOREACH (ARegion *, region, &area->regionbase) {
if (region->gizmo_map != NULL) {
gzmap = region->gizmo_map;
gzgroup = WM_gizmomap_group_find(gzmap, tref_rt->gizmo_group);
@@ -3611,15 +3669,15 @@ wmKeyMap *WM_event_get_keymap_from_toolsystem_fallback(wmWindowManager *wm,
if (keymap_id && keymap_id[0]) {
wmKeyMap *km = WM_keymap_list_find_spaceid_or_empty(
- &wm->userconf->keymaps, keymap_id, sa->spacetype, RGN_TYPE_WINDOW);
+ &wm->userconf->keymaps, keymap_id, area->spacetype, RGN_TYPE_WINDOW);
/* We shouldn't use keymaps from unrelated spaces. */
if (km != NULL) {
- handler->keymap_tool = sa->runtime.tool;
+ handler->keymap_tool = area->runtime.tool;
return km;
}
else {
printf(
- "Keymap: '%s' not found for tool '%s'\n", tref_rt->keymap, sa->runtime.tool->idname);
+ "Keymap: '%s' not found for tool '%s'\n", tref_rt->keymap, area->runtime.tool->idname);
}
}
}
@@ -3628,22 +3686,22 @@ wmKeyMap *WM_event_get_keymap_from_toolsystem_fallback(wmWindowManager *wm,
wmKeyMap *WM_event_get_keymap_from_toolsystem(wmWindowManager *wm, wmEventHandler_Keymap *handler)
{
- ScrArea *sa = handler->dynamic.user_data;
+ ScrArea *area = handler->dynamic.user_data;
handler->keymap_tool = NULL;
- bToolRef_Runtime *tref_rt = sa->runtime.tool ? sa->runtime.tool->runtime : NULL;
+ bToolRef_Runtime *tref_rt = area->runtime.tool ? area->runtime.tool->runtime : NULL;
if (tref_rt && tref_rt->keymap[0]) {
const char *keymap_id = tref_rt->keymap;
{
wmKeyMap *km = WM_keymap_list_find_spaceid_or_empty(
- &wm->userconf->keymaps, keymap_id, sa->spacetype, RGN_TYPE_WINDOW);
+ &wm->userconf->keymaps, keymap_id, area->spacetype, RGN_TYPE_WINDOW);
/* We shouldn't use keymaps from unrelated spaces. */
if (km != NULL) {
- handler->keymap_tool = sa->runtime.tool;
+ handler->keymap_tool = area->runtime.tool;
return km;
}
else {
printf(
- "Keymap: '%s' not found for tool '%s'\n", tref_rt->keymap, sa->runtime.tool->idname);
+ "Keymap: '%s' not found for tool '%s'\n", tref_rt->keymap, area->runtime.tool->idname);
}
}
}
@@ -4109,6 +4167,19 @@ static void wm_eventemulation(wmEvent *event, bool test_only)
}
}
+static const wmTabletData wm_event_tablet_data_default = {
+ .active = EVT_TABLET_NONE,
+ .pressure = 1.0f,
+ .x_tilt = 0.0f,
+ .y_tilt = 0.0f,
+ .is_motion_absolute = false,
+};
+
+void WM_event_tablet_data_default_set(wmTabletData *tablet_data)
+{
+ *tablet_data = wm_event_tablet_data_default;
+}
+
void wm_tablet_data_from_ghost(const GHOST_TabletData *tablet_data, wmTabletData *wmtab)
{
if ((tablet_data != NULL) && tablet_data->Active != GHOST_kTabletModeNone) {
@@ -4121,11 +4192,7 @@ void wm_tablet_data_from_ghost(const GHOST_TabletData *tablet_data, wmTabletData
// printf("%s: using tablet %.5f\n", __func__, wmtab->pressure);
}
else {
- wmtab->active = EVT_TABLET_NONE;
- wmtab->pressure = 1.0f;
- wmtab->x_tilt = 0.0f;
- wmtab->y_tilt = 0.0f;
- wmtab->is_motion_absolute = false;
+ *wmtab = wm_event_tablet_data_default;
// printf("%s: not using tablet\n", __func__);
}
}
@@ -4162,7 +4229,7 @@ static void attach_ndof_data(wmEvent *event, const GHOST_TEventNDOFMotionData *g
/* imperfect but probably usable... draw/enable drags to other windows */
static wmWindow *wm_event_cursor_other_windows(wmWindowManager *wm, wmWindow *win, wmEvent *event)
{
- int mx = event->x, my = event->y;
+ int mval[2] = {event->x, event->y};
if (wm->windows.first == wm->windows.last) {
return NULL;
@@ -4171,7 +4238,8 @@ static wmWindow *wm_event_cursor_other_windows(wmWindowManager *wm, wmWindow *wi
/* in order to use window size and mouse position (pixels), we have to use a WM function */
/* check if outside, include top window bar... */
- if (mx < 0 || my < 0 || mx > WM_window_pixels_x(win) || my > WM_window_pixels_y(win) + 30) {
+ if (mval[0] < 0 || mval[1] < 0 || mval[0] > WM_window_pixels_x(win) ||
+ mval[1] > WM_window_pixels_y(win) + 30) {
wmWindow *owin;
wmEventHandler *handler;
@@ -4184,25 +4252,10 @@ static wmWindow *wm_event_cursor_other_windows(wmWindowManager *wm, wmWindow *wi
}
}
- /* to desktop space */
- mx += (int)(U.pixelsize * win->posx);
- my += (int)(U.pixelsize * win->posy);
-
- /* check other windows to see if it has mouse inside */
- for (owin = wm->windows.first; owin; owin = owin->next) {
-
- if (owin != win) {
- int posx = (int)(U.pixelsize * owin->posx);
- int posy = (int)(U.pixelsize * owin->posy);
-
- if (mx - posx >= 0 && owin->posy >= 0 && mx - posx <= WM_window_pixels_x(owin) &&
- my - posy <= WM_window_pixels_y(owin)) {
- event->x = mx - (int)(U.pixelsize * owin->posx);
- event->y = my - (int)(U.pixelsize * owin->posy);
-
- return owin;
- }
- }
+ if (WM_window_find_under_cursor(wm, win, win, mval, &owin, mval)) {
+ event->x = mval[0];
+ event->y = mval[1];
+ return owin;
}
}
return NULL;
@@ -4739,7 +4792,7 @@ wmKeyMap *WM_event_get_keymap_from_handler(wmWindowManager *wm, wmEventHandler_K
wmKeyMapItem *WM_event_match_keymap_item(bContext *C, wmKeyMap *keymap, const wmEvent *event)
{
- for (wmKeyMapItem *kmi = keymap->items.first; kmi; kmi = kmi->next) {
+ LISTBASE_FOREACH (wmKeyMapItem *, kmi, &keymap->items) {
if (wm_eventmatch(event, kmi)) {
wmOperatorType *ot = WM_operatortype_find(kmi->idname, 0);
if (WM_operator_poll_context(C, ot, WM_OP_INVOKE_DEFAULT)) {
@@ -4845,30 +4898,30 @@ ScrArea *WM_window_status_area_find(wmWindow *win, bScreen *screen)
if (screen->state == SCREENFULL) {
return NULL;
}
- ScrArea *sa_statusbar = NULL;
- for (ScrArea *sa = win->global_areas.areabase.first; sa; sa = sa->next) {
- if (sa->spacetype == SPACE_STATUSBAR) {
- sa_statusbar = sa;
+ ScrArea *area_statusbar = NULL;
+ LISTBASE_FOREACH (ScrArea *, area, &win->global_areas.areabase) {
+ if (area->spacetype == SPACE_STATUSBAR) {
+ area_statusbar = area;
break;
}
}
- return sa_statusbar;
+ return area_statusbar;
}
void WM_window_status_area_tag_redraw(wmWindow *win)
{
- bScreen *sc = WM_window_get_active_screen(win);
- ScrArea *sa = WM_window_status_area_find(win, sc);
- if (sa != NULL) {
- ED_area_tag_redraw(sa);
+ bScreen *screen = WM_window_get_active_screen(win);
+ ScrArea *area = WM_window_status_area_find(win, screen);
+ if (area != NULL) {
+ ED_area_tag_redraw(area);
}
}
void WM_window_cursor_keymap_status_refresh(bContext *C, wmWindow *win)
{
bScreen *screen = WM_window_get_active_screen(win);
- ScrArea *sa_statusbar = WM_window_status_area_find(win, screen);
- if (sa_statusbar == NULL) {
+ ScrArea *area_statusbar = WM_window_status_area_find(win, screen);
+ if (area_statusbar == NULL) {
MEM_SAFE_FREE(win->cursor_keymap_status);
return;
}
@@ -4895,20 +4948,19 @@ void WM_window_cursor_keymap_status_refresh(bContext *C, wmWindow *win)
return;
}
- ScrArea *sa = NULL;
- ED_screen_areas_iter(win, screen, sa_iter)
- {
- if (BLI_findindex(&sa_iter->regionbase, region) != -1) {
- sa = sa_iter;
+ ScrArea *area = NULL;
+ ED_screen_areas_iter (win, screen, area_iter) {
+ if (BLI_findindex(&area_iter->regionbase, region) != -1) {
+ area = area_iter;
break;
}
}
- if (sa == NULL) {
+ if (area == NULL) {
return;
}
/* Keep as-is. */
- if (ELEM(sa->spacetype, SPACE_STATUSBAR, SPACE_TOPBAR)) {
+ if (ELEM(area->spacetype, SPACE_STATUSBAR, SPACE_TOPBAR)) {
return;
}
if (ELEM(region->regiontype,
@@ -4921,23 +4973,23 @@ void WM_window_cursor_keymap_status_refresh(bContext *C, wmWindow *win)
}
/* Fallback to window. */
if (ELEM(region->regiontype, RGN_TYPE_TOOLS, RGN_TYPE_TOOL_PROPS)) {
- region = BKE_area_find_region_type(sa, RGN_TYPE_WINDOW);
+ region = BKE_area_find_region_type(area, RGN_TYPE_WINDOW);
}
/* Detect changes to the state. */
{
bToolRef *tref = NULL;
if ((region->regiontype == RGN_TYPE_WINDOW) &&
- ((1 << sa->spacetype) & WM_TOOLSYSTEM_SPACE_MASK)) {
+ ((1 << area->spacetype) & WM_TOOLSYSTEM_SPACE_MASK)) {
ViewLayer *view_layer = WM_window_get_active_view_layer(win);
WorkSpace *workspace = WM_window_get_active_workspace(win);
const bToolKey tkey = {
- .space_type = sa->spacetype,
- .mode = WM_toolsystem_mode_from_spacetype(view_layer, sa, sa->spacetype),
+ .space_type = area->spacetype,
+ .mode = WM_toolsystem_mode_from_spacetype(view_layer, area, area->spacetype),
};
tref = WM_toolsystem_ref_find(workspace, &tkey);
}
- wm_event_cursor_store(&cd->state, win->eventstate, sa->spacetype, region->regiontype, tref);
+ wm_event_cursor_store(&cd->state, win->eventstate, area->spacetype, region->regiontype, tref);
if (memcmp(&cd->state, &cd_prev.state, sizeof(cd->state)) == 0) {
return;
}
@@ -4969,12 +5021,12 @@ void WM_window_cursor_keymap_status_refresh(bContext *C, wmWindow *win)
}
CTX_wm_window_set(C, win);
- CTX_wm_area_set(C, sa);
+ CTX_wm_area_set(C, area);
CTX_wm_region_set(C, region);
ListBase *handlers[] = {
&region->handlers,
- &sa->handlers,
+ &area->handlers,
&win->handlers,
};
@@ -5004,7 +5056,7 @@ void WM_window_cursor_keymap_status_refresh(bContext *C, wmWindow *win)
}
if (memcmp(&cd_prev.text, &cd->text, sizeof(cd_prev.text)) != 0) {
- ED_area_tag_redraw(sa_statusbar);
+ ED_area_tag_redraw(area_statusbar);
}
CTX_wm_window_set(C, NULL);
diff --git a/source/blender/windowmanager/intern/wm_files.c b/source/blender/windowmanager/intern/wm_files.c
index 3f4d082f9f7..ed1b29d61ce 100644
--- a/source/blender/windowmanager/intern/wm_files.c
+++ b/source/blender/windowmanager/intern/wm_files.c
@@ -141,11 +141,37 @@ static void wm_history_file_free(RecentFile *recent);
static void wm_history_file_update(void);
static void wm_history_file_write(void);
-/* To be able to read files without windows closing, opening, moving
+/* -------------------------------------------------------------------- */
+/** \name Misc Utility Functions
+ * \{ */
+
+void WM_file_tag_modified(void)
+{
+ wmWindowManager *wm = G_MAIN->wm.first;
+ if (wm->file_saved) {
+ wm->file_saved = 0;
+ /* notifier that data changed, for save-over warning or header */
+ WM_main_add_notifier(NC_WM | ND_DATACHANGED, NULL);
+ }
+}
+
+bool wm_file_or_image_is_modified(const Main *bmain, const wmWindowManager *wm)
+{
+ return !wm->file_saved || ED_image_should_save_modified(bmain);
+}
+
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Window Matching for File Reading
+ * \{ */
+
+/**
+ * To be able to read files without windows closing, opening, moving
* we try to prepare for worst case:
* - active window gets active screen from file
* - restoring the screens from non-active windows
- * Best case is all screens match, in that case they get assigned to proper window
+ * Best case is all screens match, in that case they get assigned to proper window.
*/
static void wm_window_match_init(bContext *C, ListBase *wmlist)
{
@@ -236,7 +262,7 @@ static void wm_window_match_keep_current_wm(const bContext *C,
/* when loading without UI, no matching needed */
if (load_ui && (screen = CTX_wm_screen(C))) {
- for (wmWindow *win = wm->windows.first; win; win = win->next) {
+ LISTBASE_FOREACH (wmWindow *, win, &wm->windows) {
WorkSpace *workspace;
BKE_workspace_layout_find_global(bmain, screen, &workspace);
@@ -294,8 +320,8 @@ static void wm_window_match_replace_by_file_wm(bContext *C,
wm_window_clear_drawable(oldwm);
/* only first wm in list has ghostwins */
- for (wmWindow *win = wm->windows.first; win; win = win->next) {
- for (wmWindow *oldwin = oldwm->windows.first; oldwin; oldwin = oldwin->next) {
+ LISTBASE_FOREACH (wmWindow *, win, &wm->windows) {
+ LISTBASE_FOREACH (wmWindow *, oldwin, &oldwm->windows) {
if (oldwin->winid == win->winid) {
has_match = true;
@@ -355,6 +381,12 @@ static void wm_window_match_do(bContext *C,
}
}
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Preferences Initialization & Versioning
+ * \{ */
+
/* in case UserDef was read, we re-initialize all, and do versioning */
static void wm_init_userdef(Main *bmain)
{
@@ -375,6 +407,9 @@ static void wm_init_userdef(Main *bmain)
/* update tempdir from user preferences */
BKE_tempdir_init(U.tempdir);
+
+ /* Update tablet API preference. */
+ WM_init_tablet_api();
}
/* return codes */
@@ -386,6 +421,15 @@ static void wm_init_userdef(Main *bmain)
# define BKE_READ_EXOTIC_OK_OTHER 1 /* other supported formats */
#endif
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Read Exotic File Formats
+ *
+ * Currently only supports '.blend' files,
+ * we could support registering other file formats and their loaders.
+ * \{ */
+
/* intended to check for non-blender formats but for now it only reads blends */
static int wm_read_exotic(const char *name)
{
@@ -438,6 +482,12 @@ static int wm_read_exotic(const char *name)
return retval;
}
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Read Blend-File Shared Utilities
+ * \{ */
+
void WM_file_autoexec_init(const char *filepath)
{
if (G.f & G_FLAG_SCRIPT_OVERRIDE_PREF) {
@@ -483,6 +533,24 @@ void wm_file_read_report(bContext *C, Main *bmain)
/**
* Logic shared between #WM_file_read & #wm_homefile_read,
+ * call before loading a file.
+ * \note In the case of #WM_file_read the file may fail to load.
+ * Change here shouldn't cause user-visible changes in that case.
+ */
+static void wm_file_read_pre(bContext *C, bool use_data, bool UNUSED(use_userdef))
+{
+ if (use_data) {
+ BKE_callback_exec_null(CTX_data_main(C), BKE_CB_EVT_LOAD_PRE);
+ BLI_timer_on_file_load();
+ }
+
+ /* Always do this as both startup and preferences may have loaded in many font's
+ * at a different zoom level to the file being loaded. */
+ UI_view2d_zoom_cache_reset();
+}
+
+/**
+ * Logic shared between #WM_file_read & #wm_homefile_read,
* updates to make after reading a file.
*/
static void wm_file_read_post(bContext *C,
@@ -507,12 +575,16 @@ static void wm_file_read_post(bContext *C,
if (is_startup_file) {
/* possible python hasn't been initialized */
if (CTX_py_init_get(C)) {
- if (reset_app_template) {
+ bool reset_all = use_userdef;
+ if (use_userdef || reset_app_template) {
/* Only run when we have a template path found. */
if (BKE_appdir_app_template_any()) {
BPY_execute_string(
C, (const char *[]){"bl_app_template_utils", NULL}, "bl_app_template_utils.reset()");
+ reset_all = true;
}
+ }
+ if (reset_all) {
/* sync addons, these may have changed from the defaults */
BPY_execute_string(C, (const char *[]){"addon_utils", NULL}, "addon_utils.reset_all()");
}
@@ -598,24 +670,27 @@ static void wm_file_read_post(bContext *C,
}
}
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Read Main Blend-File API
+ * \{ */
+
bool WM_file_read(bContext *C, const char *filepath, ReportList *reports)
{
/* assume automated tasks with background, don't write recent file list */
const bool do_history = (G.background == false) && (CTX_wm_manager(C)->op_undo_depth == 0);
bool success = false;
+ const bool use_data = true;
+ const bool use_userdef = false;
+
/* so we can get the error message */
errno = 0;
WM_cursor_wait(1);
- BKE_callback_exec_null(CTX_data_main(C), BKE_CB_EVT_LOAD_PRE);
- BLI_timer_on_file_load();
-
- UI_view2d_zoom_cache_reset();
-
- /* Reset session-wise ID UUID counter. */
- BKE_lib_libblock_session_uuid_reset();
+ wm_file_read_pre(C, use_data, use_userdef);
/* first try to append data from exotic file formats... */
/* it throws error box when file doesn't exist and returns -1 */
@@ -675,8 +750,6 @@ bool WM_file_read(bContext *C, const char *filepath, ReportList *reports)
}
}
- const bool use_data = true;
- const bool use_userdef = false;
wm_file_read_post(C, false, false, use_data, use_userdef, false);
}
#if 0
@@ -746,6 +819,12 @@ const char *WM_init_state_app_template_get(void)
return wm_init_state_app_template.override ? wm_init_state_app_template.app_template : NULL;
}
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Read Startup & Preferences Blend-File API
+ * \{ */
+
/**
* Called on startup, (context entirely filled with NULLs)
* or called for 'New File' both startup.blend and userpref.blend are checked.
@@ -802,6 +881,23 @@ void wm_homefile_read(bContext *C,
* or use app-template startup.blend which the user hasn't saved. */
bool is_factory_startup = true;
+ const char *app_template = NULL;
+ bool update_defaults = false;
+
+ if (filepath_startup_override != NULL) {
+ /* pass */
+ }
+ else if (app_template_override) {
+ /* This may be clearing the current template by setting to an empty string. */
+ app_template = app_template_override;
+ }
+ else if (!use_factory_settings && U.app_template[0]) {
+ app_template = U.app_template;
+ }
+
+ const bool reset_app_template = ((!app_template && U.app_template[0]) ||
+ (app_template && !STREQ(app_template, U.app_template)));
+
/* options exclude eachother */
BLI_assert((use_factory_settings && filepath_startup_override) == 0);
@@ -809,18 +905,30 @@ void wm_homefile_read(bContext *C,
SET_FLAG_FROM_TEST(G.f, (U.flag & USER_SCRIPT_AUTOEXEC_DISABLE) == 0, G_FLAG_SCRIPT_AUTOEXEC);
}
- if (use_data) {
- BKE_callback_exec_null(CTX_data_main(C), BKE_CB_EVT_LOAD_PRE);
- BLI_timer_on_file_load();
+ if (use_userdef || reset_app_template) {
+#ifdef WITH_PYTHON
+ /* This only runs once Blender has already started. */
+ if (CTX_py_init_get(C)) {
+ /* This is restored by 'wm_file_read_post', disable before loading any preferences
+ * so an add-on can read their own preferences when un-registering,
+ * and use new preferences if/when re-registering, see T67577.
+ *
+ * Note that this fits into 'wm_file_read_pre' function but gets messy
+ * since we need to know if 'reset_app_template' is true. */
+ BPY_execute_string(C, (const char *[]){"addon_utils", NULL}, "addon_utils.disable_all()");
+ }
+#endif /* WITH_PYTHON */
+ }
+ wm_file_read_pre(C, use_data, use_userdef);
+
+ if (use_data) {
G.relbase_valid = 0;
/* put aside screens to match with persistent windows later */
wm_window_match_init(C, &wmbase);
}
- UI_view2d_zoom_cache_reset();
-
filepath_startup[0] = '\0';
filepath_userdef[0] = '\0';
app_template_system[0] = '\0';
@@ -861,28 +969,6 @@ void wm_homefile_read(bContext *C,
}
}
- const char *app_template = NULL;
- bool update_defaults = false;
- bool reset_app_template = false;
-
- if (filepath_startup_override != NULL) {
- /* pass */
- }
- else if (app_template_override) {
- /* This may be clearing the current template by setting to an empty string. */
- app_template = app_template_override;
- }
- else if (!use_factory_settings && U.app_template[0]) {
- app_template = U.app_template;
- }
-
- if ((!app_template && U.app_template[0]) ||
- (app_template && !STREQ(app_template, U.app_template))) {
- /* Always load UI when switching to another template. */
- G.fileflags &= ~G_FILE_NO_UI;
- reset_app_template = true;
- }
-
if ((app_template != NULL) && (app_template[0] != '\0')) {
if (!BKE_appdir_app_template_id_search(
app_template, app_template_system, sizeof(app_template_system))) {
@@ -923,9 +1009,6 @@ void wm_homefile_read(bContext *C,
}
}
- /* Reset session-wise ID UUID counter. */
- BKE_lib_libblock_session_uuid_reset();
-
if (!use_factory_settings || (filepath_startup[0] != '\0')) {
if (BLI_access(filepath_startup, R_OK) == 0) {
success = BKE_blendfile_read(C,
@@ -953,20 +1036,20 @@ void wm_homefile_read(bContext *C,
}
}
+ if (use_userdef) {
+ if ((skip_flags & BLO_READ_SKIP_USERDEF) == 0) {
+ UserDef *userdef_default = BKE_blendfile_userdef_from_defaults();
+ BKE_blender_userdef_data_set_and_free(userdef_default);
+ skip_flags |= BLO_READ_SKIP_USERDEF;
+ }
+ }
+
if (success == false && filepath_startup_override && reports) {
/* We can not return from here because wm is already reset */
BKE_reportf(reports, RPT_ERROR, "Could not read '%s'", filepath_startup_override);
}
if (success == false) {
- if (use_userdef) {
- if ((skip_flags & BLO_READ_SKIP_USERDEF) == 0) {
- UserDef *userdef_default = BKE_blendfile_userdef_from_defaults();
- BKE_blender_userdef_data_set_and_free(userdef_default);
- skip_flags |= BLO_READ_SKIP_USERDEF;
- }
- }
-
success = BKE_blendfile_read_from_memory(C,
datatoc_startup_blend,
datatoc_startup_blend_size,
@@ -1031,6 +1114,11 @@ void wm_homefile_read(bContext *C,
* Screws up autosaves otherwise can remove this eventually,
* only in a 2.53 and older, now its not written. */
G.fileflags &= ~G_FILE_RELATIVE_REMAP;
+
+ if (reset_app_template) {
+ /* Always load UI when switching to another template. */
+ G.fileflags &= ~G_FILE_NO_UI;
+ }
}
bmain = CTX_data_main(C);
@@ -1038,7 +1126,6 @@ void wm_homefile_read(bContext *C,
if (use_userdef) {
/* check userdef before open window, keymaps etc */
wm_init_userdef(bmain);
- reset_app_template = true;
}
if (use_data) {
@@ -1047,8 +1134,8 @@ void wm_homefile_read(bContext *C,
}
if (use_userdef) {
- /* Clear keymaps because the current default keymap may have been initialized
- * from user preferences, which have been reset. */
+ /* Clear keymaps because the current default keymap may have been initialized
+ * from user preferences, which have been reset. */
for (wmWindowManager *wm = bmain->wm.first; wm; wm = wm->id.next) {
if (wm->defaultconf) {
wm->defaultconf->flag &= ~KEYCONF_INIT_DEFAULT;
@@ -1073,7 +1160,7 @@ void wm_homefile_read(bContext *C,
}
/* -------------------------------------------------------------------- */
-/** \name WM History File API
+/** \name Blend-File History API
* \{ */
void wm_history_file_read(void)
@@ -1202,7 +1289,7 @@ static void wm_history_file_update(void)
/** \} */
/* -------------------------------------------------------------------- */
-/** \name Save Main .blend File (internal)
+/** \name Save Main Blend-File (internal)
* \{ */
/* screen can be NULL */
@@ -1215,11 +1302,12 @@ static ImBuf *blend_file_thumb(const bContext *C,
ImBuf *ibuf;
BlendThumbnail *thumb;
wmWindowManager *wm = CTX_wm_manager(C);
+ const float pixelsize_old = U.pixelsize;
wmWindow *windrawable_old = wm->windrawable;
char err_out[256] = "unknown";
/* screen if no camera found */
- ScrArea *sa = NULL;
+ ScrArea *area = NULL;
ARegion *region = NULL;
View3D *v3d = NULL;
@@ -1235,10 +1323,10 @@ static ImBuf *blend_file_thumb(const bContext *C,
}
if ((scene->camera == NULL) && (screen != NULL)) {
- sa = BKE_screen_find_big_area(screen, SPACE_VIEW3D, 0);
- region = BKE_area_find_region_type(sa, RGN_TYPE_WINDOW);
+ area = BKE_screen_find_big_area(screen, SPACE_VIEW3D, 0);
+ region = BKE_area_find_region_type(area, RGN_TYPE_WINDOW);
if (region) {
- v3d = sa->spacedata.first;
+ v3d = area->spacedata.first;
}
}
@@ -1249,6 +1337,10 @@ static ImBuf *blend_file_thumb(const bContext *C,
/* gets scaled to BLEN_THUMB_SIZE */
Depsgraph *depsgraph = CTX_data_ensure_evaluated_depsgraph(C);
+ /* Note that with scaling, this ends up being 0.5,
+ * as it's a thumbnail, we don't need object centers and friends to be 1:1 size. */
+ U.pixelsize = 1.0f;
+
if (scene->camera) {
ibuf = ED_view3d_draw_offscreen_imbuf_simple(depsgraph,
scene,
@@ -1279,6 +1371,8 @@ static ImBuf *blend_file_thumb(const bContext *C,
err_out);
}
+ U.pixelsize = pixelsize_old;
+
/* Reset to old drawable. */
if (windrawable_old) {
wm_window_make_drawable(wm, windrawable_old);
@@ -1433,6 +1527,9 @@ static bool wm_file_write(bContext *C, const char *filepath, int fileflags, Repo
ibuf_thumb = IMB_thumb_create(filepath, THB_LARGE, THB_SOURCE_BLEND, ibuf_thumb);
}
+ /* Without this there is no feedback the file was saved. */
+ BKE_reportf(reports, RPT_INFO, "Saved \"%s\"", BLI_path_basename(filepath));
+
/* Success. */
ok = true;
}
@@ -1507,7 +1604,7 @@ void wm_autosave_timer(Main *bmain, wmWindowManager *wm, wmTimer *UNUSED(wt))
WM_event_remove_timer(wm, NULL, wm->autosavetimer);
/* if a modal operator is running, don't autosave, but try again in 10 seconds */
- for (wmWindow *win = wm->windows.first; win; win = win->next) {
+ LISTBASE_FOREACH (wmWindow *, win, &wm->windows) {
LISTBASE_FOREACH (wmEventHandler *, handler_base, &win->modalhandlers) {
if (handler_base->type == WM_HANDLER_TYPE_OP) {
wmEventHandler_Op *handler = (wmEventHandler_Op *)handler_base;
@@ -1532,7 +1629,7 @@ void wm_autosave_timer(Main *bmain, wmWindowManager *wm, wmTimer *UNUSED(wt))
}
}
else {
- /* save as regular blend file */
+ /* Save as regular blend file. */
int fileflags = G.fileflags & ~(G_FILE_COMPRESS | G_FILE_HISTORY);
ED_editors_flush_edits(bmain);
@@ -1616,18 +1713,8 @@ void wm_open_init_use_scripts(wmOperator *op, bool use_prefs)
/** \} */
-void WM_file_tag_modified(void)
-{
- wmWindowManager *wm = G_MAIN->wm.first;
- if (wm->file_saved) {
- wm->file_saved = 0;
- /* notifier that data changed, for save-over warning or header */
- WM_main_add_notifier(NC_WM | ND_DATACHANGED, NULL);
- }
-}
-
/* -------------------------------------------------------------------- */
-/** \name Preferences/startup save & load.
+/** \name Startup File Save Operator
* \{ */
/**
@@ -1665,7 +1752,7 @@ static int wm_homefile_write_exec(bContext *C, wmOperator *op)
ED_editors_flush_edits(bmain);
- /* force save as regular blend file */
+ /* Force save as regular blend file. */
fileflags = G.fileflags & ~(G_FILE_COMPRESS | G_FILE_HISTORY);
if (BLO_write_file(bmain, filepath, fileflags, op->reports, NULL) == 0) {
@@ -1692,48 +1779,11 @@ void WM_OT_save_homefile(wmOperatorType *ot)
ot->exec = wm_homefile_write_exec;
}
-static int wm_userpref_autoexec_add_exec(bContext *UNUSED(C), wmOperator *UNUSED(op))
-{
- bPathCompare *path_cmp = MEM_callocN(sizeof(bPathCompare), "bPathCompare");
- BLI_addtail(&U.autoexec_paths, path_cmp);
- U.runtime.is_dirty = true;
- return OPERATOR_FINISHED;
-}
-
-void WM_OT_userpref_autoexec_path_add(wmOperatorType *ot)
-{
- ot->name = "Add Autoexec Path";
- ot->idname = "WM_OT_userpref_autoexec_path_add";
- ot->description = "Add path to exclude from autoexecution";
-
- ot->exec = wm_userpref_autoexec_add_exec;
-
- ot->flag = OPTYPE_INTERNAL;
-}
-
-static int wm_userpref_autoexec_remove_exec(bContext *UNUSED(C), wmOperator *op)
-{
- const int index = RNA_int_get(op->ptr, "index");
- bPathCompare *path_cmp = BLI_findlink(&U.autoexec_paths, index);
- if (path_cmp) {
- BLI_freelinkN(&U.autoexec_paths, path_cmp);
- U.runtime.is_dirty = true;
- }
- return OPERATOR_FINISHED;
-}
-
-void WM_OT_userpref_autoexec_path_remove(wmOperatorType *ot)
-{
- ot->name = "Remove Autoexec Path";
- ot->idname = "WM_OT_userpref_autoexec_path_remove";
- ot->description = "Remove path to exclude from autoexecution";
-
- ot->exec = wm_userpref_autoexec_remove_exec;
-
- ot->flag = OPTYPE_INTERNAL;
+/** \} */
- RNA_def_int(ot->srna, "index", 0, 0, INT_MAX, "Index", "", 0, 1000);
-}
+/* -------------------------------------------------------------------- */
+/** \name Write Preferences Operator
+ * \{ */
/* Only save the prefs block. operator entry */
static int wm_userpref_write_exec(bContext *C, wmOperator *op)
@@ -1758,6 +1808,12 @@ void WM_OT_save_userpref(wmOperatorType *ot)
ot->exec = wm_userpref_write_exec;
}
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Read Preferences Operator
+ * \{ */
+
/**
* When reading preferences, there are some exceptions for values which are reset.
*/
@@ -1821,10 +1877,6 @@ static void wm_userpref_update_when_changed(bContext *C,
rna_struct_update_when_changed(C, bmain, &ptr_a, &ptr_b);
-#ifdef WITH_PYTHON
- BPY_execute_string(C, (const char *[]){"addon_utils", NULL}, "addon_utils.reset_all()");
-#endif
-
WM_reinit_gizmomap_all(bmain);
WM_keyconfig_reload(C);
@@ -1890,6 +1942,12 @@ void WM_OT_read_factory_userpref(wmOperatorType *ot)
ot->exec = wm_userpref_read_exec;
}
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Read File History Operator
+ * \{ */
+
static int wm_history_file_read_exec(bContext *UNUSED(C), wmOperator *UNUSED(op))
{
ED_file_read_bookmarks();
@@ -1910,6 +1968,14 @@ void WM_OT_read_history(wmOperatorType *ot)
ot->flag = OPTYPE_INTERNAL;
}
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Read Startup & Preferences Operator
+ *
+ * Both #WM_OT_read_homefile & #WM_OT_read_factory_settings.
+ * \{ */
+
static int wm_homefile_read_exec(bContext *C, wmOperator *op)
{
const bool use_factory_settings = (STREQ(op->type->idname, "WM_OT_read_factory_settings"));
@@ -1953,9 +2019,11 @@ static int wm_homefile_read_exec(bContext *C, wmOperator *op)
RNA_property_string_get(op->ptr, prop_app_template, app_template_buf);
app_template = app_template_buf;
- /* Always load preferences when switching templates with own preferences. */
- use_userdef = BKE_appdir_app_template_has_userpref(app_template) ||
- BKE_appdir_app_template_has_userpref(U.app_template);
+ if (!use_factory_settings) {
+ /* Always load preferences when switching templates with own preferences. */
+ use_userdef = BKE_appdir_app_template_has_userpref(app_template) ||
+ BKE_appdir_app_template_has_userpref(U.app_template);
+ }
/* Turn override off, since we're explicitly loading a different app-template. */
WM_init_state_app_template_set(NULL);
@@ -2298,7 +2366,7 @@ static bool wm_open_mainfile_check(bContext *UNUSED(C), wmOperator *op)
RNA_string_get(op->ptr, "filepath", path);
/* get the dir */
- lslash = (char *)BLI_last_slash(path);
+ lslash = (char *)BLI_path_slash_rfind(path);
if (lslash) {
*(lslash + 1) = '\0';
}
@@ -2433,7 +2501,7 @@ void WM_OT_revert_mainfile(wmOperatorType *ot)
/** \} */
/* -------------------------------------------------------------------- */
-/** \name Recover last session & auto-save.
+/** \name Recover Last Session Operator
* \{ */
void WM_recover_last_session(bContext *C, ReportList *reports)
@@ -2477,6 +2545,12 @@ void WM_OT_recover_last_session(wmOperatorType *ot)
ot->exec = wm_recover_last_session_exec;
}
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Auto-Save Main .blend File Operator
+ * \{ */
+
static int wm_recover_auto_save_exec(bContext *C, wmOperator *op)
{
char filepath[FILE_MAX];
@@ -2531,12 +2605,14 @@ void WM_OT_recover_auto_save(wmOperatorType *ot)
/* -------------------------------------------------------------------- */
/** \name Save Main .blend File Operator
+ *
+ * Both #WM_OT_save_as_mainfile & #WM_OT_save_mainfile.
* \{ */
static void wm_filepath_default(char *filepath)
{
if (G.save_over == false) {
- BLI_ensure_filename(filepath, FILE_MAX, "untitled.blend");
+ BLI_path_filename_ensure(filepath, FILE_MAX, "untitled.blend");
}
}
@@ -2715,8 +2791,6 @@ static int wm_save_mainfile_invoke(bContext *C, wmOperator *op, const wmEvent *U
RNA_string_get(op->ptr, "filepath", path);
ret = wm_save_as_mainfile_exec(C, op);
- /* Without this there is no feedback the file was saved. */
- BKE_reportf(op->reports, RPT_INFO, "Saved \"%s\"", BLI_path_basename(path));
}
else {
WM_event_add_fileselect(C, op);
@@ -2759,7 +2833,7 @@ void WM_OT_save_mainfile(wmOperatorType *ot)
/** \} */
/* -------------------------------------------------------------------- */
-/** \name Auto-execution of scripts warning popup
+/** \name Auto Script Execution Warning Dialog
* \{ */
static void wm_block_autorun_warning_ignore(bContext *C, void *arg_block, void *UNUSED(arg))
@@ -2961,8 +3035,11 @@ void wm_test_autorun_warning(bContext *C)
}
}
-/* Close File Dialog
- *************************************/
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Close File Dialog
+ * \{ */
static char save_images_when_file_is_closed = true;
@@ -3228,9 +3305,4 @@ void wm_close_file_dialog(bContext *C, wmGenericCallback *post_action)
}
}
-bool wm_file_or_image_is_modified(const Main *bmain, const wmWindowManager *wm)
-{
- return !wm->file_saved || ED_image_should_save_modified(bmain);
-}
-
/** \} */
diff --git a/source/blender/windowmanager/intern/wm_files_link.c b/source/blender/windowmanager/intern/wm_files_link.c
index 5acc8a5fbc6..da4e4160724 100644
--- a/source/blender/windowmanager/intern/wm_files_link.c
+++ b/source/blender/windowmanager/intern/wm_files_link.c
@@ -104,7 +104,7 @@ static int wm_link_append_invoke(bContext *C, wmOperator *op, const wmEvent *UNU
else if (G.relbase_valid) {
char path[FILE_MAX];
BLI_strncpy(path, BKE_main_blendfile_path_from_global(), sizeof(path));
- BLI_parent_dir(path);
+ BLI_path_parent_dir(path);
RNA_string_set(op->ptr, "filepath", path);
}
}
diff --git a/source/blender/windowmanager/intern/wm_gesture.c b/source/blender/windowmanager/intern/wm_gesture.c
index 71ae44297e7..6b2a74138c9 100644
--- a/source/blender/windowmanager/intern/wm_gesture.c
+++ b/source/blender/windowmanager/intern/wm_gesture.c
@@ -320,24 +320,24 @@ static void draw_filled_lasso_px_cb(int x, int x_end, int y, void *user_data)
static void draw_filled_lasso(wmGesture *gt)
{
const short *lasso = (short *)gt->customdata;
- const int tot = gt->points;
- int(*moves)[2] = MEM_mallocN(sizeof(*moves) * (tot + 1), __func__);
+ const int mcoords_len = gt->points;
+ int(*mcoords)[2] = MEM_mallocN(sizeof(*mcoords) * (mcoords_len + 1), __func__);
int i;
rcti rect;
float red[4] = {1.0f, 0.0f, 0.0f, 0.0f};
- for (i = 0; i < tot; i++, lasso += 2) {
- moves[i][0] = lasso[0];
- moves[i][1] = lasso[1];
+ for (i = 0; i < mcoords_len; i++, lasso += 2) {
+ mcoords[i][0] = lasso[0];
+ mcoords[i][1] = lasso[1];
}
- BLI_lasso_boundbox(&rect, (const int(*)[2])moves, tot);
+ BLI_lasso_boundbox(&rect, (const int(*)[2])mcoords, mcoords_len);
BLI_rcti_translate(&rect, gt->winrct.xmin, gt->winrct.ymin);
BLI_rcti_isect(&gt->winrct, &rect, &rect);
BLI_rcti_translate(&rect, -gt->winrct.xmin, -gt->winrct.ymin);
- /* highly unlikely this will fail, but could crash if (tot == 0) */
+ /* Highly unlikely this will fail, but could crash if (mcoords_len == 0). */
if (BLI_rcti_is_empty(&rect) == false) {
const int w = BLI_rcti_size_x(&rect);
const int h = BLI_rcti_size_y(&rect);
@@ -348,8 +348,8 @@ static void draw_filled_lasso(wmGesture *gt)
rect.ymin,
rect.xmax,
rect.ymax,
- (const int(*)[2])moves,
- tot,
+ (const int(*)[2])mcoords,
+ mcoords_len,
draw_filled_lasso_px_cb,
&lasso_fill_data);
@@ -365,7 +365,7 @@ static void draw_filled_lasso(wmGesture *gt)
IMMDrawPixelsTexState state = immDrawPixelsTexSetup(GPU_SHADER_2D_IMAGE_SHUFFLE_COLOR);
GPU_shader_bind(state.shader);
GPU_shader_uniform_vector(
- state.shader, GPU_shader_get_uniform_ensure(state.shader, "shuffle"), 4, 1, red);
+ state.shader, GPU_shader_get_uniform(state.shader, "shuffle"), 4, 1, red);
immDrawPixelsTex(&state,
rect.xmin,
@@ -390,7 +390,7 @@ static void draw_filled_lasso(wmGesture *gt)
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
}
- MEM_freeN(moves);
+ MEM_freeN(mcoords);
}
static void wm_gesture_draw_lasso(wmGesture *gt, bool filled)
diff --git a/source/blender/windowmanager/intern/wm_gesture_ops.c b/source/blender/windowmanager/intern/wm_gesture_ops.c
index 11beb7d2fd5..9fb368a02b4 100644
--- a/source/blender/windowmanager/intern/wm_gesture_ops.c
+++ b/source/blender/windowmanager/intern/wm_gesture_ops.c
@@ -718,10 +718,10 @@ void WM_gesture_lines_cancel(bContext *C, wmOperator *op)
*/
const int (*WM_gesture_lasso_path_to_array(bContext *UNUSED(C),
wmOperator *op,
- int *mcords_tot))[2]
+ int *r_mcoords_len))[2]
{
PropertyRNA *prop = RNA_struct_find_property(op->ptr, "path");
- int(*mcords)[2] = NULL;
+ int(*mcoords)[2] = NULL;
BLI_assert(prop != NULL);
if (prop) {
@@ -729,26 +729,26 @@ const int (*WM_gesture_lasso_path_to_array(bContext *UNUSED(C),
if (len) {
int i = 0;
- mcords = MEM_mallocN(sizeof(int) * 2 * len, __func__);
+ mcoords = MEM_mallocN(sizeof(int[2]) * len, __func__);
RNA_PROP_BEGIN (op->ptr, itemptr, prop) {
float loc[2];
RNA_float_get_array(&itemptr, "loc", loc);
- mcords[i][0] = (int)loc[0];
- mcords[i][1] = (int)loc[1];
+ mcoords[i][0] = (int)loc[0];
+ mcoords[i][1] = (int)loc[1];
i++;
}
RNA_PROP_END;
}
- *mcords_tot = len;
+ *r_mcoords_len = len;
}
else {
- *mcords_tot = 0;
+ *r_mcoords_len = 0;
}
/* cast for 'const' */
- return (const int(*)[2])mcords;
+ return mcoords;
}
#if 0
diff --git a/source/blender/windowmanager/intern/wm_init_exit.c b/source/blender/windowmanager/intern/wm_init_exit.c
index 8293504d068..c4fccddc869 100644
--- a/source/blender/windowmanager/intern/wm_init_exit.c
+++ b/source/blender/windowmanager/intern/wm_init_exit.c
@@ -44,6 +44,7 @@
#include "BLI_listbase.h"
#include "BLI_path_util.h"
#include "BLI_string.h"
+#include "BLI_task.h"
#include "BLI_threads.h"
#include "BLI_timer.h"
#include "BLI_utildefines.h"
@@ -124,6 +125,8 @@
#include "GPU_material.h"
#include "BKE_sound.h"
+#include "BKE_subdiv.h"
+
#include "COM_compositor.h"
#include "DEG_depsgraph.h"
@@ -131,10 +134,6 @@
#include "DRW_engine.h"
-#ifdef WITH_OPENSUBDIV
-# include "BKE_subsurf.h"
-#endif
-
CLG_LOGREF_DECLARE_GLOBAL(WM_LOG_OPERATORS, "wm.operator");
CLG_LOGREF_DECLARE_GLOBAL(WM_LOG_HANDLERS, "wm.handler");
CLG_LOGREF_DECLARE_GLOBAL(WM_LOG_EVENTS, "wm.event");
@@ -188,17 +187,16 @@ void WM_init_opengl(Main *bmain)
GPU_init();
GPU_set_mipmap(bmain, true);
GPU_set_linear_mipmap(true);
- GPU_set_anisotropic(bmain, U.anisotropic_filter);
+ GPU_set_anisotropic(U.anisotropic_filter);
GPU_pass_cache_init();
-#ifdef WITH_OPENSUBDIV
- BKE_subsurf_osd_init();
-#endif
+ BKE_subdiv_init();
+
opengl_is_init = true;
}
-static void sound_jack_sync_callback(Main *bmain, int mode, float time)
+static void sound_jack_sync_callback(Main *bmain, int mode, double time)
{
/* Ugly: Blender doesn't like it when the animation is played back during rendering. */
if (G.is_rendering) {
@@ -217,10 +215,10 @@ static void sound_jack_sync_callback(Main *bmain, int mode, float time)
if (depsgraph == NULL) {
continue;
}
- BKE_sound_lock_scene(scene);
+ BKE_sound_lock();
Scene *scene_eval = DEG_get_evaluated_scene(depsgraph);
BKE_sound_jack_scene_update(scene_eval, mode, time);
- BKE_sound_unlock_scene(scene);
+ BKE_sound_unlock();
}
}
@@ -574,11 +572,9 @@ void WM_exit_ex(bContext *C, const bool do_python)
COM_deinitialize();
#endif
- if (opengl_is_init) {
-#ifdef WITH_OPENSUBDIV
- BKE_subsurf_osd_cleanup();
-#endif
+ BKE_subdiv_exit();
+ if (opengl_is_init) {
GPU_free_unused_buffers(G_MAIN);
}
@@ -647,6 +643,7 @@ void WM_exit_ex(bContext *C, const bool do_python)
DNA_sdna_current_free();
BLI_threadapi_exit();
+ BLI_task_scheduler_exit();
/* No need to call this early, rather do it late so that other
* pieces of Blender using sound may exit cleanly, see also T50676. */
diff --git a/source/blender/windowmanager/intern/wm_jobs.c b/source/blender/windowmanager/intern/wm_jobs.c
index 33ea6dc54cc..c10f03f3dab 100644
--- a/source/blender/windowmanager/intern/wm_jobs.c
+++ b/source/blender/windowmanager/intern/wm_jobs.c
@@ -35,6 +35,7 @@
#include "BKE_context.h"
#include "BKE_global.h"
+#include "BKE_sequencer.h"
#include "WM_api.h"
#include "WM_types.h"
@@ -254,7 +255,7 @@ static void wm_jobs_update_progress_bars(wmWindowManager *wm)
float total_progress = 0.f;
float jobs_progress = 0;
- for (wmJob *wm_job = wm->jobs.first; wm_job; wm_job = wm_job->next) {
+ LISTBASE_FOREACH (wmJob *, wm_job, &wm->jobs) {
if (wm_job->threads.first && !wm_job->ready) {
if (wm_job->flag & WM_JOB_PROGRESS) {
/* accumulate global progress for running jobs */
@@ -558,6 +559,9 @@ void WM_jobs_kill_all(wmWindowManager *wm)
while ((wm_job = wm->jobs.first)) {
wm_jobs_kill_job(wm, wm_job);
}
+
+ /* This job will be automatically restarted */
+ BKE_sequencer_prefetch_stop_all();
}
/* wait until every job ended, except for one owner (used in undo to keep screen job alive) */
diff --git a/source/blender/windowmanager/intern/wm_keymap.c b/source/blender/windowmanager/intern/wm_keymap.c
index ab4888d4d31..d7102a1e8af 100644
--- a/source/blender/windowmanager/intern/wm_keymap.c
+++ b/source/blender/windowmanager/intern/wm_keymap.c
@@ -278,7 +278,7 @@ wmKeyConfig *WM_keyconfig_new(wmWindowManager *wm, const char *idname, bool user
if (keyconf == wm->defaultconf) {
/* For default configuration, we need to keep keymap
* modal items and poll functions intact. */
- for (wmKeyMap *km = keyconf->keymaps.first; km; km = km->next) {
+ LISTBASE_FOREACH (wmKeyMap *, km, &keyconf->keymaps) {
WM_keymap_clear(km);
}
}
@@ -328,7 +328,7 @@ bool WM_keyconfig_remove(wmWindowManager *wm, wmKeyConfig *keyconf)
void WM_keyconfig_clear(wmKeyConfig *keyconf)
{
- for (wmKeyMap *km = keyconf->keymaps.first; km; km = km->next) {
+ LISTBASE_FOREACH (wmKeyMap *, km, &keyconf->keymaps) {
WM_keymap_clear(km);
}
@@ -911,9 +911,9 @@ wmKeyMap *WM_keymap_find_all_spaceid_or_empty(wmWindowManager *wm,
* and filter the keys before sending to #wmOperatorType.modal callback.
* \{ */
-wmKeyMap *WM_modalkeymap_add(wmKeyConfig *keyconf,
- const char *idname,
- const EnumPropertyItem *items)
+wmKeyMap *WM_modalkeymap_ensure(wmKeyConfig *keyconf,
+ const char *idname,
+ const EnumPropertyItem *items)
{
wmKeyMap *km = WM_keymap_ensure(keyconf, idname, 0, 0);
km->flag |= KEYMAP_MODAL;
@@ -937,7 +937,7 @@ wmKeyMap *WM_modalkeymap_add(wmKeyConfig *keyconf,
return km;
}
-wmKeyMap *WM_modalkeymap_get(wmKeyConfig *keyconf, const char *idname)
+wmKeyMap *WM_modalkeymap_find(wmKeyConfig *keyconf, const char *idname)
{
wmKeyMap *km;
@@ -1329,7 +1329,7 @@ static wmKeyMapItem *wm_keymap_item_find_in_keymap(wmKeyMap *keymap,
const bool is_strict,
const struct wmKeyMapItemFind_Params *params)
{
- for (wmKeyMapItem *kmi = keymap->items.first; kmi; kmi = kmi->next) {
+ LISTBASE_FOREACH (wmKeyMapItem *, kmi, &keymap->items) {
/* skip disabled keymap items [T38447] */
if (kmi->flag & KMI_INACTIVE) {
continue;
@@ -1449,7 +1449,7 @@ static wmKeyMapItem *wm_keymap_item_find_props(const bContext *C,
wmKeyMap **r_keymap)
{
wmWindow *win = CTX_wm_window(C);
- ScrArea *sa = CTX_wm_area(C);
+ ScrArea *area = CTX_wm_area(C);
ARegion *region = CTX_wm_region(C);
wmKeyMapItem *found = NULL;
@@ -1463,16 +1463,16 @@ static wmKeyMapItem *wm_keymap_item_find_props(const bContext *C,
}
}
- if (sa && found == NULL) {
+ if (area && found == NULL) {
found = wm_keymap_item_find_handlers(
- C, &sa->handlers, opname, opcontext, properties, is_strict, params, r_keymap);
+ C, &area->handlers, opname, opcontext, properties, is_strict, params, r_keymap);
}
if (found == NULL) {
if (ELEM(opcontext, WM_OP_EXEC_REGION_WIN, WM_OP_INVOKE_REGION_WIN)) {
- if (sa) {
+ if (area) {
if (!(region && region->regiontype == RGN_TYPE_WINDOW)) {
- region = BKE_area_find_region_type(sa, RGN_TYPE_WINDOW);
+ region = BKE_area_find_region_type(area, RGN_TYPE_WINDOW);
}
if (region) {
@@ -1483,7 +1483,7 @@ static wmKeyMapItem *wm_keymap_item_find_props(const bContext *C,
}
else if (ELEM(opcontext, WM_OP_EXEC_REGION_CHANNELS, WM_OP_INVOKE_REGION_CHANNELS)) {
if (!(region && region->regiontype == RGN_TYPE_CHANNELS)) {
- region = BKE_area_find_region_type(sa, RGN_TYPE_CHANNELS);
+ region = BKE_area_find_region_type(area, RGN_TYPE_CHANNELS);
}
if (region) {
@@ -1493,7 +1493,7 @@ static wmKeyMapItem *wm_keymap_item_find_props(const bContext *C,
}
else if (ELEM(opcontext, WM_OP_EXEC_REGION_PREVIEW, WM_OP_INVOKE_REGION_PREVIEW)) {
if (!(region && region->regiontype == RGN_TYPE_PREVIEW)) {
- region = BKE_area_find_region_type(sa, RGN_TYPE_PREVIEW);
+ region = BKE_area_find_region_type(area, RGN_TYPE_PREVIEW);
}
if (region) {
@@ -1936,7 +1936,7 @@ void WM_keyconfig_update(wmWindowManager *wm)
* During event handling this function is called to get the keymap from the final configuration.
* \{ */
-wmKeyMap *WM_keymap_active(wmWindowManager *wm, wmKeyMap *keymap)
+wmKeyMap *WM_keymap_active(const wmWindowManager *wm, wmKeyMap *keymap)
{
wmKeyMap *km;
diff --git a/source/blender/windowmanager/intern/wm_keymap_utils.c b/source/blender/windowmanager/intern/wm_keymap_utils.c
index 307ad444ffd..5ab36b15666 100644
--- a/source/blender/windowmanager/intern/wm_keymap_utils.c
+++ b/source/blender/windowmanager/intern/wm_keymap_utils.c
@@ -27,6 +27,7 @@
#include "DNA_userdef_types.h"
#include "DNA_windowmanager_types.h"
+#include "BLI_listbase.h"
#include "BLI_utildefines.h"
#include "BKE_context.h"
@@ -485,7 +486,7 @@ static bool wm_keymap_item_uses_modifier(wmKeyMapItem *kmi, const int event_modi
bool WM_keymap_uses_event_modifier(wmKeyMap *keymap, const int event_modifier)
{
- for (wmKeyMapItem *kmi = keymap->items.first; kmi; kmi = kmi->next) {
+ LISTBASE_FOREACH (wmKeyMapItem *, kmi, &keymap->items) {
if ((kmi->flag & KMI_INACTIVE) == 0) {
if (wm_keymap_item_uses_modifier(kmi, event_modifier)) {
return true;
diff --git a/source/blender/windowmanager/intern/wm_menu_type.c b/source/blender/windowmanager/intern/wm_menu_type.c
index 28dd1984bf0..c4491423d82 100644
--- a/source/blender/windowmanager/intern/wm_menu_type.c
+++ b/source/blender/windowmanager/intern/wm_menu_type.c
@@ -87,8 +87,8 @@ void WM_menutype_free(void)
GHASH_ITER (gh_iter, menutypes_hash) {
MenuType *mt = BLI_ghashIterator_getValue(&gh_iter);
- if (mt->ext.free) {
- mt->ext.free(mt->ext.data);
+ if (mt->rna_ext.free) {
+ mt->rna_ext.free(mt->rna_ext.data);
}
}
diff --git a/source/blender/windowmanager/intern/wm_operator_type.c b/source/blender/windowmanager/intern/wm_operator_type.c
index 015f2b0448d..650d5bbe015 100644
--- a/source/blender/windowmanager/intern/wm_operator_type.c
+++ b/source/blender/windowmanager/intern/wm_operator_type.c
@@ -199,7 +199,7 @@ static void operatortype_ghash_free_cb(wmOperatorType *ot)
wm_operatortype_free_macro(ot);
}
- if (ot->ext.srna) {
+ if (ot->rna_ext.srna) {
/* python operator, allocs own string */
MEM_freeN((void *)ot->idname);
}
@@ -507,9 +507,9 @@ wmOperatorType *WM_operatortype_append_macro(const char *idname,
RNA_def_struct_ui_text(ot->srna, ot->name, ot->description);
RNA_def_struct_identifier(&BLENDER_RNA, ot->srna, ot->idname);
- /* Use i18n context from ext.srna if possible (py operators). */
- i18n_context = ot->ext.srna ? RNA_struct_translation_context(ot->ext.srna) :
- BLT_I18NCONTEXT_OPERATOR_DEFAULT;
+ /* Use i18n context from rna_ext.srna if possible (py operators). */
+ i18n_context = ot->rna_ext.srna ? RNA_struct_translation_context(ot->rna_ext.srna) :
+ BLT_I18NCONTEXT_OPERATOR_DEFAULT;
RNA_def_struct_translation_context(ot->srna, i18n_context);
ot->translation_context = i18n_context;
diff --git a/source/blender/windowmanager/intern/wm_operator_utils.c b/source/blender/windowmanager/intern/wm_operator_utils.c
index 4a786329e1a..81b597f7484 100644
--- a/source/blender/windowmanager/intern/wm_operator_utils.c
+++ b/source/blender/windowmanager/intern/wm_operator_utils.c
@@ -62,7 +62,7 @@ typedef struct ValueInteraction {
float range[2];
struct {
- ScrArea *sa;
+ ScrArea *area;
ARegion *region;
} context_vars;
} ValueInteraction;
@@ -74,7 +74,7 @@ static void interactive_value_init(bContext *C,
const float range[2])
{
- inter->context_vars.sa = CTX_wm_area(C);
+ inter->context_vars.area = CTX_wm_area(C);
inter->context_vars.region = CTX_wm_region(C);
inter->init.mval[0] = event->mval[0];
@@ -97,7 +97,7 @@ static void interactive_value_init_from_property(
static void interactive_value_exit(ValueInteraction *inter)
{
- ED_area_status_text(inter->context_vars.sa, NULL);
+ ED_area_status_text(inter->context_vars.area, NULL);
}
static bool interactive_value_update(ValueInteraction *inter,
@@ -128,7 +128,7 @@ static bool interactive_value_update(ValueInteraction *inter,
/* set the property for the operator and call its modal function */
char str[64];
SNPRINTF(str, "%.4f", value_final);
- ED_area_status_text(inter->context_vars.sa, str);
+ ED_area_status_text(inter->context_vars.area, str);
}
inter->prev.prop_value = value_final;
diff --git a/source/blender/windowmanager/intern/wm_operators.c b/source/blender/windowmanager/intern/wm_operators.c
index 853da714f76..f99f47bc3ad 100644
--- a/source/blender/windowmanager/intern/wm_operators.c
+++ b/source/blender/windowmanager/intern/wm_operators.c
@@ -103,9 +103,13 @@
#include "wm.h"
#include "wm_draw.h"
+#include "wm_event_system.h"
#include "wm_event_types.h"
#include "wm_files.h"
#include "wm_window.h"
+#ifdef WITH_XR_OPENXR
+# include "wm_xr.h"
+#endif
#define UNDOCUMENTED_OPERATOR_TIP N_("(undocumented operator)")
@@ -769,7 +773,7 @@ bool WM_operator_last_properties_init(wmOperator *op)
bool changed = false;
if (op->type->last_properties) {
changed |= operator_last_properties_init_impl(op, op->type->last_properties);
- for (wmOperator *opm = op->macro.first; opm; opm = opm->next) {
+ LISTBASE_FOREACH (wmOperator *, opm, &op->macro) {
IDProperty *idp_src = IDP_GetPropertyFromGroup(op->type->last_properties, opm->idname);
if (idp_src) {
changed |= operator_last_properties_init_impl(opm, idp_src);
@@ -792,7 +796,7 @@ bool WM_operator_last_properties_store(wmOperator *op)
}
if (op->macro.first != NULL) {
- for (wmOperator *opm = op->macro.first; opm; opm = opm->next) {
+ LISTBASE_FOREACH (wmOperator *, opm, &op->macro) {
if (opm->properties) {
if (op->type->last_properties == NULL) {
op->type->last_properties = IDP_New(
@@ -1345,17 +1349,8 @@ static uiBlock *wm_block_create_redo(bContext *C, ARegion *region, void *arg_op)
}
uiLayout *col = uiLayoutColumn(layout, false);
-
- if (op->type->flag & OPTYPE_MACRO) {
- for (op = op->macro.first; op; op = op->next) {
- uiTemplateOperatorPropertyButs(
- C, col, op, UI_BUT_LABEL_ALIGN_NONE, UI_TEMPLATE_OP_PROPS_SHOW_TITLE);
- }
- }
- else {
- uiTemplateOperatorPropertyButs(
- C, col, op, UI_BUT_LABEL_ALIGN_NONE, UI_TEMPLATE_OP_PROPS_SHOW_TITLE);
- }
+ uiTemplateOperatorPropertyButs(
+ C, col, op, UI_BUT_LABEL_ALIGN_NONE, UI_TEMPLATE_OP_PROPS_SHOW_TITLE);
UI_block_bounds_set_popup(block, 6 * U.dpi_fac, NULL);
@@ -1767,13 +1762,13 @@ static int wm_search_menu_invoke(bContext *C, wmOperator *op, const wmEvent *eve
/* Exception for launching via spacebar */
if (event->type == EVT_SPACEKEY) {
bool ok = true;
- ScrArea *sa = CTX_wm_area(C);
- if (sa) {
- if (sa->spacetype == SPACE_CONSOLE) {
+ ScrArea *area = CTX_wm_area(C);
+ if (area) {
+ if (area->spacetype == SPACE_CONSOLE) {
/* So we can use the shortcut in the console. */
ok = false;
}
- else if (sa->spacetype == SPACE_TEXT) {
+ else if (area->spacetype == SPACE_TEXT) {
/* So we can use the spacebar in the text editor. */
ok = false;
}
@@ -1790,13 +1785,12 @@ static int wm_search_menu_invoke(bContext *C, wmOperator *op, const wmEvent *eve
}
}
- PropertyRNA *prop = op->type->prop;
int search_type;
- if (RNA_property_is_set(op->ptr, prop)) {
- search_type = RNA_property_enum_get(op->ptr, prop);
+ if (STREQ(op->type->idname, "WM_OT_search_menu")) {
+ search_type = SEARCH_TYPE_MENU;
}
else {
- search_type = U.experimental.use_menu_search ? SEARCH_TYPE_MENU : SEARCH_TYPE_OPERATOR;
+ search_type = SEARCH_TYPE_OPERATOR;
}
static struct SearchPopupInit_Data data;
@@ -1805,7 +1799,7 @@ static int wm_search_menu_invoke(bContext *C, wmOperator *op, const wmEvent *eve
.size = {UI_searchbox_size_x() * 2, UI_searchbox_size_y()},
};
- UI_popup_block_invoke(C, wm_block_search_menu, &data, NULL);
+ UI_popup_block_invoke_ex(C, wm_block_search_menu, &data, NULL, false);
return OPERATOR_INTERFACE;
}
@@ -1814,20 +1808,22 @@ static void WM_OT_search_menu(wmOperatorType *ot)
{
ot->name = "Search Menu";
ot->idname = "WM_OT_search_menu";
- ot->description = "Pop-up a search menu over all available operators in current context";
+ ot->description = "Pop-up a search over all menus in the current context";
ot->invoke = wm_search_menu_invoke;
ot->exec = wm_search_menu_exec;
ot->poll = WM_operator_winactive;
+}
- static const EnumPropertyItem search_type_items[] = {
- {SEARCH_TYPE_OPERATOR, "OPERATOR", 0, "Operator", "Search all operators"},
- {SEARCH_TYPE_MENU, "MENU", 0, "Menu", "Search active menu items"},
- {0, NULL, 0, NULL, NULL},
- };
+static void WM_OT_search_operator(wmOperatorType *ot)
+{
+ ot->name = "Search Operator";
+ ot->idname = "WM_OT_search_operator";
+ ot->description = "Pop-up a search over all available operators in current context";
- /* properties */
- ot->prop = RNA_def_enum(ot->srna, "type", search_type_items, SEARCH_TYPE_OPERATOR, "Type", "");
+ ot->invoke = wm_search_menu_invoke;
+ ot->exec = wm_search_menu_exec;
+ ot->poll = WM_operator_winactive;
}
static int wm_call_menu_exec(bContext *C, wmOperator *op)
@@ -2063,13 +2059,14 @@ static void WM_OT_console_toggle(wmOperatorType *ot)
*
* \{ */
-wmPaintCursor *WM_paint_cursor_activate(wmWindowManager *wm,
- short space_type,
+wmPaintCursor *WM_paint_cursor_activate(short space_type,
short region_type,
bool (*poll)(bContext *C),
wmPaintCursorDraw draw,
void *customdata)
{
+ wmWindowManager *wm = G_MAIN->wm.first;
+
wmPaintCursor *pc = MEM_callocN(sizeof(wmPaintCursor), "paint cursor");
BLI_addtail(&wm->paintcursors, pc);
@@ -2084,11 +2081,10 @@ wmPaintCursor *WM_paint_cursor_activate(wmWindowManager *wm,
return pc;
}
-bool WM_paint_cursor_end(wmWindowManager *wm, wmPaintCursor *handle)
+bool WM_paint_cursor_end(wmPaintCursor *handle)
{
- wmPaintCursor *pc;
-
- for (pc = wm->paintcursors.first; pc; pc = pc->next) {
+ wmWindowManager *wm = G_MAIN->wm.first;
+ for (wmPaintCursor *pc = wm->paintcursors.first; pc; pc = pc->next) {
if (pc == (wmPaintCursor *)handle) {
BLI_remlink(&wm->paintcursors, pc);
MEM_freeN(pc);
@@ -2135,7 +2131,7 @@ static void radial_control_update_header(wmOperator *op, bContext *C)
{
RadialControl *rc = op->customdata;
char msg[UI_MAX_DRAW_STR];
- ScrArea *sa = CTX_wm_area(C);
+ ScrArea *area = CTX_wm_area(C);
Scene *scene = CTX_data_scene(C);
if (hasNumInput(&rc->num_input)) {
@@ -2172,7 +2168,7 @@ static void radial_control_update_header(wmOperator *op, bContext *C)
}
}
- ED_area_status_text(sa, msg);
+ ED_area_status_text(area, msg);
}
static void radial_control_set_initial_mouse(RadialControl *rc, const wmEvent *event)
@@ -2763,7 +2759,7 @@ static int radial_control_invoke(bContext *C, wmOperator *op, const wmEvent *eve
/* add radial control paint cursor */
rc->cursor = WM_paint_cursor_activate(
- wm, SPACE_TYPE_ANY, RGN_TYPE_ANY, op->type->poll, radial_control_paint_cursor, rc);
+ SPACE_TYPE_ANY, RGN_TYPE_ANY, op->type->poll, radial_control_paint_cursor, rc);
WM_event_add_modal_handler(C, op);
@@ -2788,16 +2784,16 @@ static void radial_control_cancel(bContext *C, wmOperator *op)
{
RadialControl *rc = op->customdata;
wmWindowManager *wm = CTX_wm_manager(C);
- ScrArea *sa = CTX_wm_area(C);
+ ScrArea *area = CTX_wm_area(C);
if (rc->dial) {
MEM_freeN(rc->dial);
rc->dial = NULL;
}
- ED_area_status_text(sa, NULL);
+ ED_area_status_text(area, NULL);
- WM_paint_cursor_end(wm, rc->cursor);
+ WM_paint_cursor_end(rc->cursor);
/* restore original paint cursors */
wm->paintcursors = rc->orig_paintcursors;
@@ -3139,11 +3135,11 @@ static void WM_OT_radial_control(wmOperatorType *ot)
static void redraw_timer_window_swap(bContext *C)
{
wmWindow *win = CTX_wm_window(C);
- ScrArea *sa;
+ ScrArea *area;
CTX_wm_menu_set(C, NULL);
- for (sa = CTX_wm_screen(C)->areabase.first; sa; sa = sa->next) {
- ED_area_tag_redraw(sa);
+ for (area = CTX_wm_screen(C)->areabase.first; area; area = area->next) {
+ ED_area_tag_redraw(area);
}
wm_draw_update(C);
@@ -3176,14 +3172,14 @@ static void redraw_timer_step(bContext *C,
Scene *scene,
struct Depsgraph *depsgraph,
wmWindow *win,
- ScrArea *sa,
+ ScrArea *area,
ARegion *region,
const int type,
const int cfra)
{
if (type == eRTDrawRegion) {
if (region) {
- wm_draw_region_test(C, sa, region);
+ wm_draw_region_test(C, area, region);
}
}
else if (type == eRTDrawRegionSwap) {
@@ -3196,25 +3192,26 @@ static void redraw_timer_step(bContext *C,
}
else if (type == eRTDrawWindow) {
bScreen *screen = WM_window_get_active_screen(win);
- ScrArea *sa_iter;
+ ScrArea *area_iter;
CTX_wm_menu_set(C, NULL);
- for (sa_iter = screen->areabase.first; sa_iter; sa_iter = sa_iter->next) {
- ARegion *ar_iter;
- CTX_wm_area_set(C, sa_iter);
+ for (area_iter = screen->areabase.first; area_iter; area_iter = area_iter->next) {
+ ARegion *region_iter;
+ CTX_wm_area_set(C, area_iter);
- for (ar_iter = sa_iter->regionbase.first; ar_iter; ar_iter = ar_iter->next) {
- if (ar_iter->visible) {
- CTX_wm_region_set(C, ar_iter);
- wm_draw_region_test(C, sa_iter, ar_iter);
+ for (region_iter = area_iter->regionbase.first; region_iter;
+ region_iter = region_iter->next) {
+ if (region_iter->visible) {
+ CTX_wm_region_set(C, region_iter);
+ wm_draw_region_test(C, area_iter, region_iter);
}
}
}
CTX_wm_window_set(C, win); /* XXX context manipulation warning! */
- CTX_wm_area_set(C, sa);
+ CTX_wm_area_set(C, area);
CTX_wm_region_set(C, region);
}
else if (type == eRTDrawWindowSwap) {
@@ -3240,8 +3237,12 @@ static void redraw_timer_step(bContext *C,
}
}
else { /* eRTUndo */
+ /* Undo and redo, including depsgraph update since that can be a
+ * significant part of the cost. */
ED_undo_pop(C);
+ wm_event_do_refresh_wm_and_depsgraph(C);
ED_undo_redo(C);
+ wm_event_do_refresh_wm_and_depsgraph(C);
}
}
@@ -3250,7 +3251,7 @@ static int redraw_timer_exec(bContext *C, wmOperator *op)
Main *bmain = CTX_data_main(C);
Scene *scene = CTX_data_scene(C);
wmWindow *win = CTX_wm_window(C);
- ScrArea *sa = CTX_wm_area(C);
+ ScrArea *area = CTX_wm_area(C);
ARegion *region = CTX_wm_region(C);
wmWindowManager *wm = CTX_wm_manager(C);
double time_start, time_delta;
@@ -3272,7 +3273,7 @@ static int redraw_timer_exec(bContext *C, wmOperator *op)
wm_window_make_drawable(wm, win);
for (a = 0; a < iter; a++) {
- redraw_timer_step(C, bmain, scene, depsgraph, win, sa, region, type, cfra);
+ redraw_timer_step(C, bmain, scene, depsgraph, win, area, region, type, cfra);
iter_steps += 1;
if (time_limit != 0.0) {
@@ -3688,8 +3689,8 @@ static void wm_xr_session_update_screen(Main *bmain, const wmXrData *xr_data)
const bool session_exists = WM_xr_session_exists(xr_data);
for (bScreen *screen = bmain->screens.first; screen; screen = screen->id.next) {
- for (ScrArea *area = screen->areabase.first; area; area = area->next) {
- for (SpaceLink *slink = area->spacedata.first; slink; slink = slink->next) {
+ LISTBASE_FOREACH (ScrArea *, area, &screen->areabase) {
+ LISTBASE_FOREACH (SpaceLink *, slink, &area->spacedata) {
if (slink->spacetype == SPACE_VIEW3D) {
View3D *v3d = (View3D *)slink;
@@ -3711,6 +3712,8 @@ static void wm_xr_session_update_screen(Main *bmain, const wmXrData *xr_data)
}
}
}
+
+ WM_main_add_notifier(NC_WM | ND_XR_DATA_CHANGED, NULL);
}
static void wm_xr_session_update_screen_on_exit_cb(const wmXrData *xr_data)
@@ -3775,8 +3778,6 @@ void wm_operatortypes_register(void)
WM_operatortype_append(WM_OT_save_userpref);
WM_operatortype_append(WM_OT_read_userpref);
WM_operatortype_append(WM_OT_read_factory_userpref);
- WM_operatortype_append(WM_OT_userpref_autoexec_path_add);
- WM_operatortype_append(WM_OT_userpref_autoexec_path_remove);
WM_operatortype_append(WM_OT_window_fullscreen_toggle);
WM_operatortype_append(WM_OT_quit_blender);
WM_operatortype_append(WM_OT_open_mainfile);
@@ -3794,7 +3795,9 @@ void wm_operatortypes_register(void)
WM_operatortype_append(WM_OT_debug_menu);
WM_operatortype_append(WM_OT_operator_defaults);
WM_operatortype_append(WM_OT_splash);
+ WM_operatortype_append(WM_OT_splash_about);
WM_operatortype_append(WM_OT_search_menu);
+ WM_operatortype_append(WM_OT_search_operator);
WM_operatortype_append(WM_OT_call_menu);
WM_operatortype_append(WM_OT_call_menu_pie);
WM_operatortype_append(WM_OT_call_panel);
@@ -3833,14 +3836,14 @@ static void gesture_circle_modal_keymap(wmKeyConfig *keyconf)
};
/* WARNING - name is incorrect, use for non-3d views */
- wmKeyMap *keymap = WM_modalkeymap_get(keyconf, "View3D Gesture Circle");
+ wmKeyMap *keymap = WM_modalkeymap_find(keyconf, "View3D Gesture Circle");
/* this function is called for each spacetype, only needs to add map once */
if (keymap && keymap->modal_items) {
return;
}
- keymap = WM_modalkeymap_add(keyconf, "View3D Gesture Circle", modal_items);
+ keymap = WM_modalkeymap_ensure(keyconf, "View3D Gesture Circle", modal_items);
/* assign map to operators */
WM_modalkeymap_assign(keymap, "VIEW3D_OT_select_circle");
@@ -3863,14 +3866,14 @@ static void gesture_straightline_modal_keymap(wmKeyConfig *keyconf)
{0, NULL, 0, NULL, NULL},
};
- wmKeyMap *keymap = WM_modalkeymap_get(keyconf, "Gesture Straight Line");
+ wmKeyMap *keymap = WM_modalkeymap_find(keyconf, "Gesture Straight Line");
/* this function is called for each spacetype, only needs to add map once */
if (keymap && keymap->modal_items) {
return;
}
- keymap = WM_modalkeymap_add(keyconf, "Gesture Straight Line", modal_items);
+ keymap = WM_modalkeymap_ensure(keyconf, "Gesture Straight Line", modal_items);
/* assign map to operators */
WM_modalkeymap_assign(keymap, "IMAGE_OT_sample_line");
@@ -3889,14 +3892,14 @@ static void gesture_box_modal_keymap(wmKeyConfig *keyconf)
{0, NULL, 0, NULL, NULL},
};
- wmKeyMap *keymap = WM_modalkeymap_get(keyconf, "Gesture Box");
+ wmKeyMap *keymap = WM_modalkeymap_find(keyconf, "Gesture Box");
/* this function is called for each spacetype, only needs to add map once */
if (keymap && keymap->modal_items) {
return;
}
- keymap = WM_modalkeymap_add(keyconf, "Gesture Box", modal_items);
+ keymap = WM_modalkeymap_ensure(keyconf, "Gesture Box", modal_items);
/* assign map to operators */
WM_modalkeymap_assign(keymap, "ACTION_OT_select_box");
@@ -3940,14 +3943,14 @@ static void gesture_zoom_border_modal_keymap(wmKeyConfig *keyconf)
{0, NULL, 0, NULL, NULL},
};
- wmKeyMap *keymap = WM_modalkeymap_get(keyconf, "Gesture Zoom Border");
+ wmKeyMap *keymap = WM_modalkeymap_find(keyconf, "Gesture Zoom Border");
/* this function is called for each spacetype, only needs to add map once */
if (keymap && keymap->modal_items) {
return;
}
- keymap = WM_modalkeymap_add(keyconf, "Gesture Zoom Border", modal_items);
+ keymap = WM_modalkeymap_ensure(keyconf, "Gesture Zoom Border", modal_items);
/* assign map to operators */
WM_modalkeymap_assign(keymap, "VIEW2D_OT_zoom_border");
diff --git a/source/blender/windowmanager/intern/wm_playanim.c b/source/blender/windowmanager/intern/wm_playanim.c
index 8a872010ecc..948e8d9fb74 100644
--- a/source/blender/windowmanager/intern/wm_playanim.c
+++ b/source/blender/windowmanager/intern/wm_playanim.c
@@ -317,7 +317,13 @@ static void playanim_toscreen(
GPU_blend(true);
glBlendFuncSeparate(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA, GL_ONE, GL_ONE_MINUS_SRC_ALPHA);
- imm_draw_box_checker_2d(offs_x, offs_y, offs_x + span_x, offs_y + span_y);
+ imm_draw_box_checker_2d_ex(offs_x,
+ offs_y,
+ offs_x + span_x,
+ offs_y + span_y,
+ (const float[4]){0.15, 0.15, 0.15, 1.0},
+ (const float[4]){0.20, 0.20, 0.20, 1.0},
+ 8);
}
IMMDrawPixelsTexState state = immDrawPixelsTexSetup(GPU_SHADER_2D_IMAGE_COLOR);
@@ -429,7 +435,8 @@ static void build_pict_list_ex(
} fp_decoded;
BLI_strncpy(filepath, first, sizeof(filepath));
- fp_framenr = BLI_stringdec(filepath, fp_decoded.head, fp_decoded.tail, &fp_decoded.digits);
+ fp_framenr = BLI_path_sequence_decode(
+ filepath, fp_decoded.head, fp_decoded.tail, &fp_decoded.digits);
pupdate_time();
ptottime = 1.0;
@@ -522,7 +529,8 @@ static void build_pict_list_ex(
/* create a new filepath each time */
fp_framenr += fstep;
- BLI_stringenc(filepath, fp_decoded.head, fp_decoded.tail, fp_decoded.digits, fp_framenr);
+ BLI_path_sequence_encode(
+ filepath, fp_decoded.head, fp_decoded.tail, fp_decoded.digits, fp_framenr);
while ((hasevent = GHOST_ProcessEvents(g_WS.ghost_system, 0))) {
GHOST_DispatchEvents(g_WS.ghost_system);
diff --git a/source/blender/windowmanager/intern/wm_splash_screen.c b/source/blender/windowmanager/intern/wm_splash_screen.c
index 9c7ed52b0f9..b75609fd28f 100644
--- a/source/blender/windowmanager/intern/wm_splash_screen.c
+++ b/source/blender/windowmanager/intern/wm_splash_screen.c
@@ -40,6 +40,7 @@
#include "DNA_windowmanager_types.h"
#include "BLI_blenlib.h"
+#include "BLI_math.h"
#include "BLI_utildefines.h"
#include "BKE_appdir.h"
@@ -47,6 +48,8 @@
#include "BKE_context.h"
#include "BKE_screen.h"
+#include "BLT_translation.h"
+
#include "BLF_api.h"
#include "IMB_imbuf.h"
@@ -55,202 +58,137 @@
#include "ED_screen.h"
#include "UI_interface.h"
+#include "UI_interface_icons.h"
+#include "UI_resources.h"
#include "WM_api.h"
#include "WM_types.h"
#include "wm.h"
-static void wm_block_splash_close(bContext *C, void *arg_block, void *UNUSED(arg))
+static void wm_block_close(bContext *C, void *arg_block, void *UNUSED(arg))
{
wmWindow *win = CTX_wm_window(C);
UI_popup_block_close(C, win, arg_block);
}
-static uiBlock *wm_block_create_splash(bContext *C, ARegion *region, void *arg_unused);
-
static void wm_block_splash_refreshmenu(bContext *C, void *UNUSED(arg_block), void *UNUSED(arg))
{
- ARegion *ar_menu = CTX_wm_menu(C);
- ED_region_tag_refresh_ui(ar_menu);
+ ARegion *region_menu = CTX_wm_menu(C);
+ ED_region_tag_refresh_ui(region_menu);
}
-static void wm_block_splash_add_label(uiBlock *block, const char *label, int x, int *y)
+static void wm_block_splash_add_label(uiBlock *block, const char *label, int x, int y)
{
if (!(label && label[0])) {
return;
}
- const uiStyle *style = UI_style_get();
-
- BLF_size(style->widgetlabel.uifont_id, style->widgetlabel.points, U.pixelsize * U.dpi);
- int label_width = BLF_width(style->widgetlabel.uifont_id, label, strlen(label));
- label_width = label_width + U.widget_unit;
-
UI_block_emboss_set(block, UI_EMBOSS_NONE);
- uiBut *but = uiDefBut(block,
- UI_BTYPE_LABEL,
- 0,
- label,
- x - label_width,
- *y,
- label_width,
- UI_UNIT_Y,
- NULL,
- 0,
- 0,
- 0,
- 0,
- NULL);
+ uiBut *but = uiDefBut(
+ block, UI_BTYPE_LABEL, 0, label, 0, y, x, UI_UNIT_Y, NULL, 0, 0, 0, 0, NULL);
+ UI_but_drawflag_disable(but, UI_BUT_TEXT_LEFT);
+ UI_but_drawflag_enable(but, UI_BUT_TEXT_RIGHT);
/* 1 = UI_SELECT, internal flag to draw in white. */
UI_but_flag_enable(but, 1);
UI_block_emboss_set(block, UI_EMBOSS);
- *y -= 12 * U.dpi_fac;
}
-static void wm_block_splash_add_labels(uiBlock *block, int x, int y)
+#ifndef WITH_HEADLESS
+static void wm_block_splash_image_roundcorners_add(ImBuf *ibuf)
{
- /* Version number. */
- const char *version_cycle = NULL;
- bool show_build_info = true;
-
- if (STREQ(STRINGIFY(BLENDER_VERSION_CYCLE), "alpha")) {
- version_cycle = " Alpha";
- }
- else if (STREQ(STRINGIFY(BLENDER_VERSION_CYCLE), "beta")) {
- version_cycle = " Beta";
- }
- else if (STREQ(STRINGIFY(BLENDER_VERSION_CYCLE), "rc")) {
- version_cycle = " Release Candidate";
- show_build_info = false;
- }
- else if (STREQ(STRINGIFY(BLENDER_VERSION_CYCLE), "release")) {
- version_cycle = STRINGIFY(BLENDER_VERSION_CHAR);
- show_build_info = false;
- }
-
- const char *version_cycle_number = "";
- if (strlen(STRINGIFY(BLENDER_VERSION_CYCLE_NUMBER))) {
- version_cycle_number = " " STRINGIFY(BLENDER_VERSION_CYCLE_NUMBER);
- }
-
- char version_buf[256] = "\0";
- BLI_snprintf(version_buf,
- sizeof(version_buf),
- "v %d.%d%s%s",
- BLENDER_VERSION / 100,
- BLENDER_VERSION % 100,
- version_cycle,
- version_cycle_number);
-
- wm_block_splash_add_label(block, version_buf, x, &y);
-
-#ifdef WITH_BUILDINFO
- if (show_build_info) {
- extern unsigned long build_commit_timestamp;
- extern char build_hash[], build_commit_date[], build_commit_time[], build_branch[];
-
- /* Date, hidden for builds made from tag. */
- if (build_commit_timestamp != 0) {
- char date_buf[256] = "\0";
- BLI_snprintf(
- date_buf, sizeof(date_buf), "Date: %s %s", build_commit_date, build_commit_time);
- wm_block_splash_add_label(block, date_buf, x, &y);
- }
-
- /* Hash. */
- char hash_buf[256] = "\0";
- BLI_snprintf(hash_buf, sizeof(hash_buf), "Hash: %s", build_hash);
- wm_block_splash_add_label(block, hash_buf, x, &y);
-
- /* Branch. */
- if (!STREQ(build_branch, "master")) {
- char branch_buf[256] = "\0";
- BLI_snprintf(branch_buf, sizeof(branch_buf), "Branch: %s", build_branch);
-
- wm_block_splash_add_label(block, branch_buf, x, &y);
+ uchar *rct = (uchar *)ibuf->rect;
+
+ if (rct) {
+ bTheme *btheme = UI_GetTheme();
+ const float roundness = btheme->tui.wcol_menu_back.roundness * U.dpi_fac;
+ const int size = roundness * 20;
+
+ if (size < ibuf->x && size < ibuf->y) {
+ /* Y-axis initial offset. */
+ rct += 4 * (ibuf->y - size) * ibuf->x;
+
+ for (int y = 0; y < size; y++) {
+ for (int x = 0; x < size; x++, rct += 4) {
+ const float pixel = 1.0 / size;
+ const float u = pixel * x;
+ const float v = pixel * y;
+ const float distance = sqrt(u * u + v * v);
+
+ /* Pointer offset to the alpha value of pixel. */
+ /* Note, the left corner is flipped in the X-axis. */
+ const int offset_l = 4 * (size - x - x - 1) + 3;
+ const int offset_r = 4 * (ibuf->x - size) + 3;
+
+ if (distance > 1.0) {
+ rct[offset_l] = 0;
+ rct[offset_r] = 0;
+ }
+ else {
+ /* Create a single pixel wide transition for anti-aliasing.
+ * Invert the distance and map its range [0, 1] to [0, pixel]. */
+ const float fac = (1.0 - distance) * size;
+
+ if (fac > 1.0) {
+ continue;
+ }
+
+ const uchar alpha = unit_float_to_uchar_clamp(fac);
+ rct[offset_l] = alpha;
+ rct[offset_r] = alpha;
+ }
+ }
+
+ /* X-axis offset to the next row. */
+ rct += 4 * (ibuf->x - size);
+ }
}
}
-#else
- UNUSED_VARS(show_build_info);
-#endif /* WITH_BUILDINFO */
}
+#endif /* WITH_HEADLESS */
-static ImBuf *wm_block_splash_image(int r_unit_size[2])
+static ImBuf *wm_block_splash_image(int width, int *r_height)
{
#ifndef WITH_HEADLESS
extern char datatoc_splash_png[];
extern int datatoc_splash_png_size;
- extern char datatoc_splash_2x_png[];
- extern int datatoc_splash_2x_png_size;
- const bool is_2x = U.dpi_fac > 1.0;
- const int imb_scale = is_2x ? 2 : 1;
-
- /* We could allow this to be variable,
- * for now don't since allowing it might create layout issues.
- *
- * Only check width because splashes sometimes change height
- * and we don't want to break app-templates. */
- const int x_expect = 501 * imb_scale;
ImBuf *ibuf = NULL;
+ int height = 0;
if (U.app_template[0] != '\0') {
char splash_filepath[FILE_MAX];
char template_directory[FILE_MAX];
if (BKE_appdir_app_template_id_search(
U.app_template, template_directory, sizeof(template_directory))) {
- BLI_join_dirfile(splash_filepath,
- sizeof(splash_filepath),
- template_directory,
- is_2x ? "splash_2x.png" : "splash.png");
+ BLI_join_dirfile(splash_filepath, sizeof(splash_filepath), template_directory, "splash.png");
ibuf = IMB_loadiffname(splash_filepath, IB_rect, NULL);
-
- /* We could skip this check, see comment about 'x_expect' above. */
- if (ibuf && ibuf->x != x_expect) {
- CLOG_ERROR(WM_LOG_OPERATORS,
- "Splash expected %d width found %d, ignoring: %s\n",
- x_expect,
- ibuf->x,
- splash_filepath);
- IMB_freeImBuf(ibuf);
- ibuf = NULL;
- }
}
}
if (ibuf == NULL) {
- const uchar *splash_data;
- size_t splash_data_size;
+ const uchar *splash_data = (const uchar *)datatoc_splash_png;
+ size_t splash_data_size = datatoc_splash_png_size;
+ ibuf = IMB_ibImageFromMemory(splash_data, splash_data_size, IB_rect, NULL, "<splash screen>");
+ }
- if (is_2x) {
- splash_data = (const uchar *)datatoc_splash_2x_png;
- splash_data_size = datatoc_splash_2x_png_size;
- }
- else {
- splash_data = (const uchar *)datatoc_splash_png;
- splash_data_size = datatoc_splash_png_size;
+ if (ibuf) {
+ height = (width * ibuf->y) / ibuf->x;
+ if (width != ibuf->x || height != ibuf->y) {
+ IMB_scaleImBuf(ibuf, width, height);
}
- ibuf = IMB_ibImageFromMemory(splash_data, splash_data_size, IB_rect, NULL, "<splash screen>");
-
- BLI_assert(ibuf->x == x_expect);
+ wm_block_splash_image_roundcorners_add(ibuf);
+ IMB_premultiply_alpha(ibuf);
}
- if (is_2x) {
- r_unit_size[0] = ibuf->x / 2;
- r_unit_size[1] = ibuf->y / 2;
- }
- else {
- r_unit_size[0] = ibuf->x;
- r_unit_size[1] = ibuf->y;
- }
+ *r_height = height;
return ibuf;
#else
- UNUSED_VARS(r_unit_size);
+ UNUSED_VARS(width, r_height);
return NULL;
#endif
}
@@ -269,23 +207,20 @@ static uiBlock *wm_block_create_splash(bContext *C, ARegion *region, void *UNUSE
UI_block_flag_enable(block, UI_BLOCK_LOOP | UI_BLOCK_KEEP_OPEN | UI_BLOCK_NO_WIN_CLIP);
UI_block_theme_style_set(block, UI_BLOCK_THEME_STYLE_POPUP);
- /* Size before dpi scaling (halved for hi-dpi image). */
- int ibuf_unit_size[2];
- ImBuf *ibuf = wm_block_splash_image(ibuf_unit_size);
- but = uiDefButImage(block,
- ibuf,
- 0,
- 0.5f * U.widget_unit,
- U.dpi_fac * ibuf_unit_size[0],
- U.dpi_fac * ibuf_unit_size[1],
- NULL);
- UI_but_func_set(but, wm_block_splash_close, block, NULL);
- UI_block_func_set(block, wm_block_splash_refreshmenu, block, NULL);
+ int splash_width = 500.0f * U.dpi_fac;
+ int splash_height;
+
+ /* Would be nice to support caching this, so it only has to be re-read (and likely resized) on
+ * first draw or if the image changed. */
+ ImBuf *ibuf = wm_block_splash_image(splash_width, &splash_height);
- int x = U.dpi_fac * (ibuf_unit_size[0] + 1);
- int y = U.dpi_fac * (ibuf_unit_size[1] - 13);
+ but = uiDefButImage(block, ibuf, 0, 0.5f * U.widget_unit, splash_width, splash_height, NULL);
+
+ UI_but_func_set(but, wm_block_close, block, NULL);
+ UI_block_func_set(block, wm_block_splash_refreshmenu, block, NULL);
- wm_block_splash_add_labels(block, x, y);
+ wm_block_splash_add_label(
+ block, BKE_blender_version_string(), splash_width, splash_height - 13.0 * U.dpi_fac);
const int layout_margin_x = U.dpi_fac * 26;
uiLayout *layout = UI_block_layout(block,
@@ -293,7 +228,7 @@ static uiBlock *wm_block_create_splash(bContext *C, ARegion *region, void *UNUSE
UI_LAYOUT_PANEL,
layout_margin_x,
0,
- (U.dpi_fac * ibuf_unit_size[0]) - (layout_margin_x * 2),
+ splash_width - (layout_margin_x * 2),
U.dpi_fac * 110,
0,
style);
@@ -324,3 +259,92 @@ void WM_OT_splash(wmOperatorType *ot)
ot->invoke = wm_splash_invoke;
ot->poll = WM_operator_winactive;
}
+
+static uiBlock *wm_block_create_about(bContext *C, ARegion *region, void *UNUSED(arg))
+{
+ uiBlock *block;
+ const uiStyle *style = UI_style_get_dpi();
+ const int dialog_width = U.widget_unit * 24;
+ const short logo_size = 128 * U.dpi_fac;
+
+ /* Calculate icon column factor. */
+ const float split_factor = (float)logo_size / (float)(dialog_width - style->columnspace);
+
+ block = UI_block_begin(C, region, "about", UI_EMBOSS);
+
+ UI_block_flag_enable(
+ block, UI_BLOCK_KEEP_OPEN | UI_BLOCK_LOOP | UI_BLOCK_NO_WIN_CLIP | UI_BLOCK_NUMSELECT);
+ UI_block_theme_style_set(block, UI_BLOCK_THEME_STYLE_POPUP);
+ UI_block_emboss_set(block, UI_EMBOSS);
+
+ uiLayout *block_layout = UI_block_layout(
+ block, UI_LAYOUT_VERTICAL, UI_LAYOUT_PANEL, 0, 0, dialog_width, 0, 0, style);
+
+ /* Split layout to put Blender logo on left side. */
+ uiLayout *split_block = uiLayoutSplit(block_layout, split_factor, false);
+
+ /* Blender Logo. */
+ uiLayout *layout = uiLayoutColumn(split_block, false);
+ uiDefButAlert(block, ALERT_ICON_BLENDER, 0, 0, 0, logo_size);
+
+ /* The rest of the content on the right. */
+ layout = uiLayoutColumn(split_block, false);
+
+ uiLayoutSetScaleY(layout, 0.7f);
+
+ uiItemS_ex(layout, 1.0f);
+
+ /* Title. */
+ uiItemL_ex(layout, "Blender", ICON_NONE, true, false);
+
+ /* Version. */
+ uiItemL(layout, BKE_blender_version_string(), ICON_NONE);
+
+ uiItemS_ex(layout, 3.0f);
+
+#ifdef WITH_BUILDINFO
+
+ extern char build_hash[], build_commit_date[], build_commit_time[], build_branch[];
+
+ char str_buf[256] = "\0";
+ BLI_snprintf(str_buf, sizeof(str_buf), "Date: %s %s", build_commit_date, build_commit_time);
+ uiItemL(layout, str_buf, ICON_NONE);
+
+ BLI_snprintf(str_buf, sizeof(str_buf), "Hash: %s", build_hash);
+ uiItemL(layout, str_buf, ICON_NONE);
+
+ BLI_snprintf(str_buf, sizeof(str_buf), "Branch: %s", build_branch);
+ uiItemL(layout, str_buf, ICON_NONE);
+
+#endif /* WITH_BUILDINFO */
+
+ uiItemS_ex(layout, 1.5f);
+
+ MenuType *mt = WM_menutype_find("WM_MT_splash_about", true);
+ if (mt) {
+ UI_menutype_draw(C, mt, layout);
+ }
+
+ uiItemS_ex(layout, 2.0f);
+
+ UI_block_bounds_set_centered(block, 14 * U.dpi_fac);
+
+ return block;
+}
+
+static int wm_about_invoke(bContext *C, wmOperator *UNUSED(op), const wmEvent *UNUSED(event))
+{
+ UI_popup_block_invoke(C, wm_block_create_about, NULL, NULL);
+
+ return OPERATOR_FINISHED;
+}
+
+void WM_OT_splash_about(wmOperatorType *ot)
+{
+ ot->name = "About Blender";
+ ot->idname = "WM_OT_splash_about";
+ ot->description = "Open a window with information about Blender";
+
+ ot->invoke = wm_about_invoke;
+ ot->poll = WM_operator_winactive;
+}
diff --git a/source/blender/windowmanager/intern/wm_surface.c b/source/blender/windowmanager/intern/wm_surface.c
index 043b584bbbd..e8850693d69 100644
--- a/source/blender/windowmanager/intern/wm_surface.c
+++ b/source/blender/windowmanager/intern/wm_surface.c
@@ -45,7 +45,7 @@ static wmSurface *g_drawable = NULL;
void wm_surfaces_iter(bContext *C, void (*cb)(bContext *C, wmSurface *))
{
- for (wmSurface *surf = global_surface_list.first; surf; surf = surf->next) {
+ LISTBASE_FOREACH (wmSurface *, surf, &global_surface_list) {
cb(C, surf);
}
}
diff --git a/source/blender/windowmanager/intern/wm_toolsystem.c b/source/blender/windowmanager/intern/wm_toolsystem.c
index 551250ec747..72969f34162 100644
--- a/source/blender/windowmanager/intern/wm_toolsystem.c
+++ b/source/blender/windowmanager/intern/wm_toolsystem.c
@@ -72,18 +72,18 @@ struct bToolRef *WM_toolsystem_ref_from_context(struct bContext *C)
{
WorkSpace *workspace = CTX_wm_workspace(C);
ViewLayer *view_layer = CTX_data_view_layer(C);
- ScrArea *sa = CTX_wm_area(C);
- if ((sa == NULL) || ((1 << sa->spacetype) & WM_TOOLSYSTEM_SPACE_MASK) == 0) {
+ ScrArea *area = CTX_wm_area(C);
+ if ((area == NULL) || ((1 << area->spacetype) & WM_TOOLSYSTEM_SPACE_MASK) == 0) {
return NULL;
}
const bToolKey tkey = {
- .space_type = sa->spacetype,
- .mode = WM_toolsystem_mode_from_spacetype(view_layer, sa, sa->spacetype),
+ .space_type = area->spacetype,
+ .mode = WM_toolsystem_mode_from_spacetype(view_layer, area, area->spacetype),
};
bToolRef *tref = WM_toolsystem_ref_find(workspace, &tkey);
- /* We could return 'sa->runtime.tool' in this case. */
- if (sa->runtime.is_tool_set) {
- BLI_assert(tref == sa->runtime.tool);
+ /* We could return 'area->runtime.tool' in this case. */
+ if (area->runtime.is_tool_set) {
+ BLI_assert(tref == area->runtime.tool);
}
return tref;
}
@@ -178,7 +178,7 @@ static void toolsystem_ref_link(bContext *C, WorkSpace *workspace, bToolRef *tre
if (i != -1) {
const int value = items[i].value;
wmWindowManager *wm = bmain->wm.first;
- for (wmWindow *win = wm->windows.first; win; win = win->next) {
+ LISTBASE_FOREACH (wmWindow *, win, &wm->windows) {
if (workspace == WM_window_get_active_workspace(win)) {
Scene *scene = WM_window_get_active_scene(win);
ToolSettings *ts = scene->toolsettings;
@@ -197,7 +197,7 @@ static void toolsystem_ref_link(bContext *C, WorkSpace *workspace, bToolRef *tre
if (i != -1) {
const int slot_index = items[i].value;
wmWindowManager *wm = bmain->wm.first;
- for (wmWindow *win = wm->windows.first; win; win = win->next) {
+ LISTBASE_FOREACH (wmWindow *, win, &wm->windows) {
if (workspace == WM_window_get_active_workspace(win)) {
Scene *scene = WM_window_get_active_scene(win);
BKE_paint_ensure_from_paintmode(scene, paint_mode);
@@ -279,15 +279,15 @@ void WM_toolsystem_reinit_all(struct bContext *C, wmWindow *win)
{
bScreen *screen = WM_window_get_active_screen(win);
ViewLayer *view_layer = WM_window_get_active_view_layer(win);
- for (ScrArea *sa = screen->areabase.first; sa; sa = sa->next) {
- if (((1 << sa->spacetype) & WM_TOOLSYSTEM_SPACE_MASK) == 0) {
+ LISTBASE_FOREACH (ScrArea *, area, &screen->areabase) {
+ if (((1 << area->spacetype) & WM_TOOLSYSTEM_SPACE_MASK) == 0) {
continue;
}
WorkSpace *workspace = WM_window_get_active_workspace(win);
const bToolKey tkey = {
- .space_type = sa->spacetype,
- .mode = WM_toolsystem_mode_from_spacetype(view_layer, sa, sa->spacetype),
+ .space_type = area->spacetype,
+ .mode = WM_toolsystem_mode_from_spacetype(view_layer, area, area->spacetype),
};
bToolRef *tref = WM_toolsystem_ref_find(workspace, &tkey);
if (tref) {
@@ -372,7 +372,7 @@ void WM_toolsystem_ref_sync_from_context(Main *bmain, WorkSpace *workspace, bToo
return;
}
wmWindowManager *wm = bmain->wm.first;
- for (wmWindow *win = wm->windows.first; win; win = win->next) {
+ LISTBASE_FOREACH (wmWindow *, win, &wm->windows) {
if (workspace != WM_window_get_active_workspace(win)) {
continue;
}
@@ -450,12 +450,12 @@ static bool toolsystem_key_ensure_check(const bToolKey *tkey)
return false;
}
-int WM_toolsystem_mode_from_spacetype(ViewLayer *view_layer, ScrArea *sa, int spacetype)
+int WM_toolsystem_mode_from_spacetype(ViewLayer *view_layer, ScrArea *area, int spacetype)
{
int mode = -1;
switch (spacetype) {
case SPACE_VIEW3D: {
- /* 'sa' may be NULL in this case. */
+ /* 'area' may be NULL in this case. */
Object *obact = OBACT(view_layer);
if (obact != NULL) {
Object *obedit = OBEDIT_FROM_OBACT(obact);
@@ -467,7 +467,7 @@ int WM_toolsystem_mode_from_spacetype(ViewLayer *view_layer, ScrArea *sa, int sp
break;
}
case SPACE_IMAGE: {
- SpaceImage *sima = sa->spacedata.first;
+ SpaceImage *sima = area->spacedata.first;
mode = sima->mode;
break;
}
@@ -476,7 +476,7 @@ int WM_toolsystem_mode_from_spacetype(ViewLayer *view_layer, ScrArea *sa, int sp
break;
}
case SPACE_SEQ: {
- SpaceSeq *sseq = sa->spacedata.first;
+ SpaceSeq *sseq = area->spacedata.first;
mode = sseq->view;
break;
}
@@ -484,14 +484,14 @@ int WM_toolsystem_mode_from_spacetype(ViewLayer *view_layer, ScrArea *sa, int sp
return mode;
}
-bool WM_toolsystem_key_from_context(ViewLayer *view_layer, ScrArea *sa, bToolKey *tkey)
+bool WM_toolsystem_key_from_context(ViewLayer *view_layer, ScrArea *area, bToolKey *tkey)
{
int space_type = SPACE_EMPTY;
int mode = -1;
- if (sa != NULL) {
- space_type = sa->spacetype;
- mode = WM_toolsystem_mode_from_spacetype(view_layer, sa, space_type);
+ if (area != NULL) {
+ space_type = area->spacetype;
+ mode = WM_toolsystem_mode_from_spacetype(view_layer, area, space_type);
}
if (mode != -1) {
@@ -514,24 +514,24 @@ void WM_toolsystem_refresh_active(bContext *C)
{
Main *bmain = CTX_data_main(C);
for (wmWindowManager *wm = bmain->wm.first; wm; wm = wm->id.next) {
- for (wmWindow *win = wm->windows.first; win; win = win->next) {
+ LISTBASE_FOREACH (wmWindow *, win, &wm->windows) {
WorkSpace *workspace = WM_window_get_active_workspace(win);
bScreen *screen = WM_window_get_active_screen(win);
ViewLayer *view_layer = WM_window_get_active_view_layer(win);
/* Could skip loop for modes that don't depend on space type. */
int space_type_mask_handled = 0;
- for (ScrArea *sa = screen->areabase.first; sa; sa = sa->next) {
+ LISTBASE_FOREACH (ScrArea *, area, &screen->areabase) {
/* Don't change the space type of the active tool, only update it's mode. */
- const int space_type_mask = (1 << sa->spacetype);
+ const int space_type_mask = (1 << area->spacetype);
if ((space_type_mask & WM_TOOLSYSTEM_SPACE_MASK) &&
((space_type_mask_handled & space_type_mask) == 0)) {
space_type_mask_handled |= space_type_mask;
const bToolKey tkey = {
- .space_type = sa->spacetype,
- .mode = WM_toolsystem_mode_from_spacetype(view_layer, sa, sa->spacetype),
+ .space_type = area->spacetype,
+ .mode = WM_toolsystem_mode_from_spacetype(view_layer, area, area->spacetype),
};
bToolRef *tref = WM_toolsystem_ref_find(workspace, &tkey);
- if (tref != sa->runtime.tool) {
+ if (tref != area->runtime.tool) {
toolsystem_reinit_ensure_toolref(C, workspace, &tkey, NULL);
}
}
@@ -547,22 +547,22 @@ void WM_toolsystem_refresh_active(bContext *C)
/* Refresh to ensure data is initialized.
* This is needed because undo can load a state which no longer has the underlying DNA data
* needed for the tool (un-initialized paint-slots for eg), see: T64339. */
- for (bToolRef *tref = workspace->tools.first; tref; tref = tref->next) {
+ LISTBASE_FOREACH (bToolRef *, tref, &workspace->tools) {
toolsystem_refresh_ref(C, workspace, tref);
}
}
}
}
-void WM_toolsystem_refresh_screen_area(WorkSpace *workspace, ViewLayer *view_layer, ScrArea *sa)
+void WM_toolsystem_refresh_screen_area(WorkSpace *workspace, ViewLayer *view_layer, ScrArea *area)
{
- sa->runtime.tool = NULL;
- sa->runtime.is_tool_set = true;
- const int mode = WM_toolsystem_mode_from_spacetype(view_layer, sa, sa->spacetype);
- for (bToolRef *tref = workspace->tools.first; tref; tref = tref->next) {
- if (tref->space_type == sa->spacetype) {
+ area->runtime.tool = NULL;
+ area->runtime.is_tool_set = true;
+ const int mode = WM_toolsystem_mode_from_spacetype(view_layer, area, area->spacetype);
+ LISTBASE_FOREACH (bToolRef *, tref, &workspace->tools) {
+ if (tref->space_type == area->spacetype) {
if (tref->mode == mode) {
- sa->runtime.tool = tref;
+ area->runtime.tool = tref;
break;
}
}
@@ -573,19 +573,19 @@ void WM_toolsystem_refresh_screen_all(Main *bmain)
{
/* Update all ScrArea's tools */
for (wmWindowManager *wm = bmain->wm.first; wm; wm = wm->id.next) {
- for (wmWindow *win = wm->windows.first; win; win = win->next) {
+ LISTBASE_FOREACH (wmWindow *, win, &wm->windows) {
WorkSpace *workspace = WM_window_get_active_workspace(win);
bool space_type_has_tools[SPACE_TYPE_LAST + 1] = {0};
- for (bToolRef *tref = workspace->tools.first; tref; tref = tref->next) {
+ LISTBASE_FOREACH (bToolRef *, tref, &workspace->tools) {
space_type_has_tools[tref->space_type] = true;
}
bScreen *screen = WM_window_get_active_screen(win);
ViewLayer *view_layer = WM_window_get_active_view_layer(win);
- for (ScrArea *sa = screen->areabase.first; sa; sa = sa->next) {
- sa->runtime.tool = NULL;
- sa->runtime.is_tool_set = true;
- if (space_type_has_tools[sa->spacetype]) {
- WM_toolsystem_refresh_screen_area(workspace, view_layer, sa);
+ LISTBASE_FOREACH (ScrArea *, area, &screen->areabase) {
+ area->runtime.tool = NULL;
+ area->runtime.is_tool_set = true;
+ if (space_type_has_tools[area->spacetype]) {
+ WM_toolsystem_refresh_screen_area(workspace, view_layer, area);
}
}
}
@@ -598,16 +598,16 @@ static void toolsystem_refresh_screen_from_active_tool(Main *bmain,
{
/* Update all ScrArea's tools */
for (wmWindowManager *wm = bmain->wm.first; wm; wm = wm->id.next) {
- for (wmWindow *win = wm->windows.first; win; win = win->next) {
+ LISTBASE_FOREACH (wmWindow *, win, &wm->windows) {
if (workspace == WM_window_get_active_workspace(win)) {
bScreen *screen = WM_window_get_active_screen(win);
ViewLayer *view_layer = WM_window_get_active_view_layer(win);
- for (ScrArea *sa = screen->areabase.first; sa; sa = sa->next) {
- if (sa->spacetype == tref->space_type) {
- int mode = WM_toolsystem_mode_from_spacetype(view_layer, sa, sa->spacetype);
+ LISTBASE_FOREACH (ScrArea *, area, &screen->areabase) {
+ if (area->spacetype == tref->space_type) {
+ int mode = WM_toolsystem_mode_from_spacetype(view_layer, area, area->spacetype);
if (mode == tref->mode) {
- sa->runtime.tool = tref;
- sa->runtime.is_tool_set = true;
+ area->runtime.tool = tref;
+ area->runtime.is_tool_set = true;
}
}
}
@@ -649,9 +649,9 @@ bToolRef *WM_toolsystem_ref_set_by_id_ex(
bToolRef *WM_toolsystem_ref_set_by_id(bContext *C, const char *name)
{
ViewLayer *view_layer = CTX_data_view_layer(C);
- ScrArea *sa = CTX_wm_area(C);
+ ScrArea *area = CTX_wm_area(C);
bToolKey tkey;
- if (WM_toolsystem_key_from_context(view_layer, sa, &tkey)) {
+ if (WM_toolsystem_key_from_context(view_layer, area, &tkey)) {
WorkSpace *workspace = CTX_wm_workspace(C);
return WM_toolsystem_ref_set_by_id_ex(C, workspace, &tkey, name, false);
}
@@ -707,7 +707,7 @@ static const char *toolsystem_default_tool(const bToolKey *tkey)
case SEQ_VIEW_SEQUENCE:
return "builtin.select";
case SEQ_VIEW_PREVIEW:
- return "builtin.annotate";
+ return "builtin.sample";
case SEQ_VIEW_SEQUENCE_PREVIEW:
return "builtin.select";
}
@@ -759,9 +759,9 @@ void WM_toolsystem_update_from_context_view3d(bContext *C)
if (!BLI_listbase_is_single(&wm->windows)) {
wmWindow *win_prev = CTX_wm_window(C);
ScrArea *area_prev = CTX_wm_area(C);
- ARegion *ar_prev = CTX_wm_region(C);
+ ARegion *region_prev = CTX_wm_region(C);
- for (wmWindow *win = wm->windows.first; win; win = win->next) {
+ LISTBASE_FOREACH (wmWindow *, win, &wm->windows) {
if (win != win_prev) {
WorkSpace *workspace_iter = WM_window_get_active_workspace(win);
if (workspace_iter != workspace) {
@@ -772,7 +772,7 @@ void WM_toolsystem_update_from_context_view3d(bContext *C)
CTX_wm_window_set(C, win_prev);
CTX_wm_area_set(C, area_prev);
- CTX_wm_region_set(C, ar_prev);
+ CTX_wm_region_set(C, region_prev);
}
}
}
@@ -782,11 +782,11 @@ void WM_toolsystem_update_from_context_view3d(bContext *C)
void WM_toolsystem_update_from_context(bContext *C,
WorkSpace *workspace,
ViewLayer *view_layer,
- ScrArea *sa)
+ ScrArea *area)
{
const bToolKey tkey = {
- .space_type = sa->spacetype,
- .mode = WM_toolsystem_mode_from_spacetype(view_layer, sa, sa->spacetype),
+ .space_type = area->spacetype,
+ .mode = WM_toolsystem_mode_from_spacetype(view_layer, area, area->spacetype),
};
if (toolsystem_key_ensure_check(&tkey)) {
toolsystem_reinit_ensure_toolref(C, workspace, &tkey, NULL);
@@ -807,13 +807,13 @@ void WM_toolsystem_do_msg_notify_tag_refresh(bContext *C,
wmMsgSubscribeKey *UNUSED(msg_key),
wmMsgSubscribeValue *msg_val)
{
- ScrArea *sa = msg_val->user_data;
+ ScrArea *area = msg_val->user_data;
Main *bmain = CTX_data_main(C);
wmWindow *win = ((wmWindowManager *)bmain->wm.first)->windows.first;
if (win->next != NULL) {
do {
bScreen *screen = WM_window_get_active_screen(win);
- if (BLI_findindex(&screen->areabase, sa) != -1) {
+ if (BLI_findindex(&screen->areabase, area) != -1) {
break;
}
} while ((win = win->next));
@@ -823,11 +823,11 @@ void WM_toolsystem_do_msg_notify_tag_refresh(bContext *C,
ViewLayer *view_layer = WM_window_get_active_view_layer(win);
const bToolKey tkey = {
- .space_type = sa->spacetype,
- .mode = WM_toolsystem_mode_from_spacetype(view_layer, sa, sa->spacetype),
+ .space_type = area->spacetype,
+ .mode = WM_toolsystem_mode_from_spacetype(view_layer, area, area->spacetype),
};
WM_toolsystem_refresh(C, workspace, &tkey);
- WM_toolsystem_refresh_screen_area(workspace, view_layer, sa);
+ WM_toolsystem_refresh_screen_area(workspace, view_layer, area);
}
IDProperty *WM_toolsystem_ref_properties_ensure_idprops(bToolRef *tref)
diff --git a/source/blender/windowmanager/intern/wm_tooltip.c b/source/blender/windowmanager/intern/wm_tooltip.c
index da2afda5e24..a9f0e01cfb5 100644
--- a/source/blender/windowmanager/intern/wm_tooltip.c
+++ b/source/blender/windowmanager/intern/wm_tooltip.c
@@ -43,7 +43,7 @@ double WM_tooltip_time_closed(void)
}
void WM_tooltip_immediate_init(
- bContext *C, wmWindow *win, ScrArea *sa, ARegion *region, wmTooltipInitFn init)
+ bContext *C, wmWindow *win, ScrArea *area, ARegion *region, wmTooltipInitFn init)
{
WM_tooltip_timer_clear(C, win);
@@ -51,14 +51,14 @@ void WM_tooltip_immediate_init(
if (screen->tool_tip == NULL) {
screen->tool_tip = MEM_callocN(sizeof(*screen->tool_tip), __func__);
}
- screen->tool_tip->area_from = sa;
+ screen->tool_tip->area_from = area;
screen->tool_tip->region_from = region;
screen->tool_tip->init = init;
WM_tooltip_init(C, win);
}
void WM_tooltip_timer_init_ex(
- bContext *C, wmWindow *win, ScrArea *sa, ARegion *region, wmTooltipInitFn init, double delay)
+ bContext *C, wmWindow *win, ScrArea *area, ARegion *region, wmTooltipInitFn init, double delay)
{
WM_tooltip_timer_clear(C, win);
@@ -67,16 +67,16 @@ void WM_tooltip_timer_init_ex(
if (screen->tool_tip == NULL) {
screen->tool_tip = MEM_callocN(sizeof(*screen->tool_tip), __func__);
}
- screen->tool_tip->area_from = sa;
+ screen->tool_tip->area_from = area;
screen->tool_tip->region_from = region;
screen->tool_tip->timer = WM_event_add_timer(wm, win, TIMER, delay);
screen->tool_tip->init = init;
}
void WM_tooltip_timer_init(
- bContext *C, wmWindow *win, ScrArea *sa, ARegion *region, wmTooltipInitFn init)
+ bContext *C, wmWindow *win, ScrArea *area, ARegion *region, wmTooltipInitFn init)
{
- WM_tooltip_timer_init_ex(C, win, sa, region, init, UI_TOOLTIP_DELAY);
+ WM_tooltip_timer_init_ex(C, win, area, region, init, UI_TOOLTIP_DELAY);
}
void WM_tooltip_timer_clear(bContext *C, wmWindow *win)
@@ -119,7 +119,7 @@ void WM_tooltip_init(bContext *C, wmWindow *win)
{
ScrArea *area_prev = CTX_wm_area(C);
- ARegion *ar_prev = CTX_wm_region(C);
+ ARegion *region_prev = CTX_wm_region(C);
CTX_wm_area_set(C, screen->tool_tip->area_from);
CTX_wm_region_set(C, screen->tool_tip->region_from);
screen->tool_tip->region = screen->tool_tip->init(C,
@@ -128,7 +128,7 @@ void WM_tooltip_init(bContext *C, wmWindow *win)
&pass_delay,
&screen->tool_tip->exit_on_event);
CTX_wm_area_set(C, area_prev);
- CTX_wm_region_set(C, ar_prev);
+ CTX_wm_region_set(C, region_prev);
}
copy_v2_v2_int(screen->tool_tip->event_xy, &win->eventstate->x);
diff --git a/source/blender/windowmanager/intern/wm_uilist_type.c b/source/blender/windowmanager/intern/wm_uilist_type.c
index f886e01f5a3..801043a56d1 100644
--- a/source/blender/windowmanager/intern/wm_uilist_type.c
+++ b/source/blender/windowmanager/intern/wm_uilist_type.c
@@ -82,8 +82,8 @@ void WM_uilisttype_free(void)
GHASH_ITER (gh_iter, uilisttypes_hash) {
uiListType *ult = BLI_ghashIterator_getValue(&gh_iter);
- if (ult->ext.free) {
- ult->ext.free(ult->ext.data);
+ if (ult->rna_ext.free) {
+ ult->rna_ext.free(ult->rna_ext.data);
}
}
diff --git a/source/blender/windowmanager/intern/wm_window.c b/source/blender/windowmanager/intern/wm_window.c
index 0f96500b8b3..05a84f6acaa 100644
--- a/source/blender/windowmanager/intern/wm_window.c
+++ b/source/blender/windowmanager/intern/wm_window.c
@@ -65,6 +65,9 @@
#include "wm_platform_support.h"
#include "wm_window.h"
#include "wm_window_private.h"
+#ifdef WITH_XR_OPENXR
+# include "wm_xr.h"
+#endif
#include "ED_anim_api.h"
#include "ED_fileselect.h"
@@ -81,11 +84,11 @@
#include "GPU_batch.h"
#include "GPU_batch_presets.h"
#include "GPU_context.h"
-#include "GPU_draw.h"
#include "GPU_framebuffer.h"
#include "GPU_immediate.h"
#include "GPU_init_exit.h"
#include "GPU_platform.h"
+#include "GPU_state.h"
#include "UI_resources.h"
@@ -283,14 +286,15 @@ static int find_free_winid(wmWindowManager *wm)
}
/* don't change context itself */
-wmWindow *wm_window_new(const Main *bmain, wmWindowManager *wm, wmWindow *parent)
+wmWindow *wm_window_new(const Main *bmain, wmWindowManager *wm, wmWindow *parent, bool dialog)
{
wmWindow *win = MEM_callocN(sizeof(wmWindow), "window");
BLI_addtail(&wm->windows, win);
win->winid = find_free_winid(wm);
- win->parent = (parent && parent->parent) ? parent->parent : parent;
+ /* Dialogs may have a child window as parent. Otherwise, a child must not be a parent too. */
+ win->parent = (!dialog && parent && parent->parent) ? parent->parent : parent;
win->stereo3d_format = MEM_callocN(sizeof(Stereo3dFormat), "Stereo 3D Format (window)");
win->workspace_hook = BKE_workspace_instance_hook_create(bmain);
@@ -304,8 +308,9 @@ wmWindow *wm_window_copy(Main *bmain,
const bool duplicate_layout,
const bool child)
{
+ const bool is_dialog = GHOST_IsDialogWindow(win_src->ghostwin);
wmWindow *win_parent = (child) ? win_src : win_src->parent;
- wmWindow *win_dst = wm_window_new(bmain, wm, win_parent);
+ wmWindow *win_dst = wm_window_new(bmain, wm, win_parent, is_dialog);
WorkSpace *workspace = WM_window_get_active_workspace(win_src);
WorkSpaceLayout *layout_old = WM_window_get_active_layout(win_src);
WorkSpaceLayout *layout_new;
@@ -321,7 +326,7 @@ wmWindow *wm_window_copy(Main *bmain,
layout_new = duplicate_layout ?
ED_workspace_layout_duplicate(bmain, workspace, layout_old, win_dst) :
layout_old;
- BKE_workspace_hook_layout_for_workspace_set(win_dst->workspace_hook, workspace, layout_new);
+ BKE_workspace_active_layout_set(win_dst->workspace_hook, workspace, layout_new);
*win_dst->stereo3d_format = *win_src->stereo3d_format;
@@ -414,7 +419,6 @@ void wm_quit_with_optional_confirmation_prompt(bContext *C, wmWindow *win)
void wm_window_close(bContext *C, wmWindowManager *wm, wmWindow *win)
{
wmWindow *win_other;
- const bool is_dialog = (G.background == false) ? GHOST_IsDialogWindow(win->ghostwin) : false;
/* First check if there is another main window remaining. */
for (win_other = wm->windows.first; win_other; win_other = win_other->next) {
@@ -428,20 +432,11 @@ void wm_window_close(bContext *C, wmWindowManager *wm, wmWindow *win)
return;
}
- /* Close child windows and bring windows back to front that dialogs have pushed behind the main
- * window. */
- for (wmWindow *iter_win = wm->windows.first; iter_win; iter_win = iter_win->next) {
+ /* Close child windows */
+ LISTBASE_FOREACH_MUTABLE (wmWindow *, iter_win, &wm->windows) {
if (iter_win->parent == win) {
wm_window_close(C, wm, iter_win);
}
- else {
- if (G.background == false) {
- if (is_dialog && iter_win != win && iter_win->parent &&
- (GHOST_GetWindowState(iter_win->ghostwin) != GHOST_kWindowStateMinimized)) {
- wm_window_raise(iter_win);
- }
- }
- }
}
bScreen *screen = WM_window_get_active_screen(win);
@@ -761,22 +756,9 @@ void wm_window_ghostwindows_ensure(wmWindowManager *wm)
* in practice the window manager will likely move to the correct monitor */
wm_init_state.start_x = 0;
wm_init_state.start_y = 0;
-
-#ifdef WITH_X11 /* X11 */
- /* X11, don't start maximized because we can't figure out the dimensions
- * of a single display yet if there are multiple, due to lack of Xinerama
- * handling in GHOST. */
- wm_init_state.size_x = min_ii(wm_init_state.size_x, WM_WIN_INIT_SIZE_X);
- wm_init_state.size_y = min_ii(wm_init_state.size_y, WM_WIN_INIT_SIZE_Y);
- /* pad */
- wm_init_state.start_x = WM_WIN_INIT_PAD;
- wm_init_state.start_y = WM_WIN_INIT_PAD;
- wm_init_state.size_x -= WM_WIN_INIT_PAD * 2;
- wm_init_state.size_y -= WM_WIN_INIT_PAD * 2;
-#endif
}
- for (wmWindow *win = wm->windows.first; win; win = win->next) {
+ LISTBASE_FOREACH (wmWindow *, win, &wm->windows) {
wm_window_ghostwindow_ensure(wm, win, false);
}
}
@@ -799,6 +781,36 @@ void wm_window_ghostwindows_remove_invalid(bContext *C, wmWindowManager *wm)
}
}
+/* Update window size and position based on data from GHOST window. */
+static bool wm_window_update_size_position(wmWindow *win)
+{
+ GHOST_RectangleHandle client_rect;
+ int l, t, r, b, scr_w, scr_h;
+ int sizex, sizey, posx, posy;
+
+ client_rect = GHOST_GetClientBounds(win->ghostwin);
+ GHOST_GetRectangle(client_rect, &l, &t, &r, &b);
+
+ GHOST_DisposeRectangle(client_rect);
+
+ wm_get_desktopsize(&scr_w, &scr_h);
+ sizex = r - l;
+ sizey = b - t;
+ posx = l;
+ posy = scr_h - t - win->sizey;
+
+ if (win->sizex != sizex || win->sizey != sizey || win->posx != posx || win->posy != posy) {
+ win->sizex = sizex;
+ win->sizey = sizey;
+ win->posx = posx;
+ win->posy = posy;
+ return true;
+ }
+ else {
+ return false;
+ }
+}
+
/**
* new window, no screen yet, but we open ghostwindow for it,
* also gets the window level handlers
@@ -809,7 +821,7 @@ wmWindow *WM_window_open(bContext *C, const rcti *rect)
{
wmWindowManager *wm = CTX_wm_manager(C);
wmWindow *win_prev = CTX_wm_window(C);
- wmWindow *win = wm_window_new(CTX_data_main(C), wm, win_prev);
+ wmWindow *win = wm_window_new(CTX_data_main(C), wm, win_prev, false);
win->posx = rect->xmin;
win->posy = rect->ymin;
@@ -849,7 +861,7 @@ wmWindow *WM_window_open_temp(bContext *C,
wmWindow *win_prev = CTX_wm_window(C);
wmWindow *win;
bScreen *screen;
- ScrArea *sa;
+ ScrArea *area;
Scene *scene = CTX_data_scene(C);
ViewLayer *view_layer = CTX_data_view_layer(C);
@@ -880,7 +892,7 @@ wmWindow *WM_window_open_temp(bContext *C,
/* add new window? */
if (win == NULL) {
- win = wm_window_new(bmain, wm, win_prev);
+ win = wm_window_new(bmain, wm, win_prev, dialog);
win->posx = rect.xmin;
win->posy = rect.ymin;
@@ -915,7 +927,8 @@ wmWindow *WM_window_open_temp(bContext *C,
/* make window active, and validate/resize */
CTX_wm_window_set(C, win);
- if (!win->ghostwin) {
+ const bool new_window = (win->ghostwin == NULL);
+ if (new_window) {
wm_window_ghostwindow_ensure(wm, win, dialog);
}
WM_check(C);
@@ -927,18 +940,25 @@ wmWindow *WM_window_open_temp(bContext *C,
*/
/* ensure it shows the right spacetype editor */
- sa = screen->areabase.first;
- CTX_wm_area_set(C, sa);
+ area = screen->areabase.first;
+ CTX_wm_area_set(C, area);
- ED_area_newspace(C, sa, space_type, false);
+ ED_area_newspace(C, area, space_type, false);
ED_screen_change(C, screen);
- ED_screen_refresh(wm, win); /* test scale */
- if (win->ghostwin) {
+ if (!new_window) {
+ /* Set size in GHOST window and then update size and position from GHOST,
+ * in case they where changed by GHOST to fit the monitor/screen. */
wm_window_set_size(win, win->sizex, win->sizey);
- wm_window_raise(win);
+ wm_window_update_size_position(win);
+ }
+ /* Refresh screen dimensions, after the effective window size is known. */
+ ED_screen_refresh(wm, win);
+
+ if (win->ghostwin) {
+ wm_window_raise(win);
GHOST_SetTitle(win->ghostwin, title);
return win;
}
@@ -1346,21 +1366,6 @@ static int ghost_event_proc(GHOST_EventHandle evt, GHOST_TUserDataPtr C_void_ptr
/* win32: gives undefined window size when minimized */
if (state != GHOST_kWindowStateMinimized) {
- GHOST_RectangleHandle client_rect;
- int l, t, r, b, scr_w, scr_h;
- int sizex, sizey, posx, posy;
-
- client_rect = GHOST_GetClientBounds(win->ghostwin);
- GHOST_GetRectangle(client_rect, &l, &t, &r, &b);
-
- GHOST_DisposeRectangle(client_rect);
-
- wm_get_desktopsize(&scr_w, &scr_h);
- sizex = r - l;
- sizey = b - t;
- posx = l;
- posy = scr_h - t - win->sizey;
-
/*
* Ghost sometimes send size or move events when the window hasn't changed.
* One case of this is using compiz on linux. To alleviate the problem
@@ -1369,15 +1374,9 @@ static int ghost_event_proc(GHOST_EventHandle evt, GHOST_TUserDataPtr C_void_ptr
* It might be good to eventually do that at Ghost level, but that is for
* another time.
*/
- if (win->sizex != sizex || win->sizey != sizey || win->posx != posx ||
- win->posy != posy) {
+ if (wm_window_update_size_position(win)) {
const bScreen *screen = WM_window_get_active_screen(win);
- win->sizex = sizex;
- win->sizey = sizey;
- win->posx = posx;
- win->posy = posy;
-
/* debug prints */
if (G.debug & G_DEBUG_EVENTS) {
const char *state_str;
@@ -1659,8 +1658,6 @@ void wm_ghost_init(bContext *C)
}
GHOST_UseWindowFocus(wm_init_state.window_focus);
-
- WM_init_tablet_api();
}
}
@@ -1970,6 +1967,90 @@ bool wm_window_get_swap_interval(wmWindow *win, int *intervalOut)
/** \} */
/* -------------------------------------------------------------------- */
+/** \name Find Window Utility
+ *
+ * \{ */
+static void wm_window_desktop_pos_get(const wmWindow *win,
+ const int screen_pos[2],
+ int r_desk_pos[2])
+{
+ /* To desktop space. */
+ r_desk_pos[0] = screen_pos[0] + (int)(U.pixelsize * win->posx);
+ r_desk_pos[1] = screen_pos[1] + (int)(U.pixelsize * win->posy);
+}
+
+static void wm_window_screen_pos_get(const wmWindow *win,
+ const int desktop_pos[2],
+ int r_scr_pos[2])
+{
+ /* To window space. */
+ r_scr_pos[0] = desktop_pos[0] - (int)(U.pixelsize * win->posx);
+ r_scr_pos[1] = desktop_pos[1] - (int)(U.pixelsize * win->posy);
+}
+
+bool WM_window_find_under_cursor(const wmWindowManager *wm,
+ const wmWindow *win_ignore,
+ const wmWindow *win,
+ const int mval[2],
+ wmWindow **r_win,
+ int r_mval[2])
+{
+ int desk_pos[2];
+ wm_window_desktop_pos_get(win, mval, desk_pos);
+
+ /* TODO: This should follow the order of the activated windows.
+ * The current solution is imperfect but usable in most cases. */
+ LISTBASE_FOREACH (wmWindow *, win_iter, &wm->windows) {
+ if (win_iter == win_ignore) {
+ continue;
+ }
+
+ if (win_iter->windowstate == GHOST_kWindowStateMinimized) {
+ continue;
+ }
+
+ int scr_pos[2];
+ wm_window_screen_pos_get(win_iter, desk_pos, scr_pos);
+
+ if (scr_pos[0] >= 0 && win_iter->posy >= 0 && scr_pos[0] <= WM_window_pixels_x(win_iter) &&
+ scr_pos[1] <= WM_window_pixels_y(win_iter)) {
+
+ *r_win = win_iter;
+ copy_v2_v2_int(r_mval, scr_pos);
+ return true;
+ }
+ }
+
+ return false;
+}
+
+void WM_window_pixel_sample_read(const wmWindowManager *wm,
+ const wmWindow *win,
+ const int pos[2],
+ float r_col[3])
+{
+ bool setup_context = wm->windrawable != win;
+
+ if (setup_context) {
+ GHOST_ActivateWindowDrawingContext(win->ghostwin);
+ GPU_context_active_set(win->gpuctx);
+ }
+
+ glReadBuffer(GL_FRONT);
+ glReadPixels(pos[0], pos[1], 1, 1, GL_RGB, GL_FLOAT, r_col);
+ glReadBuffer(GL_BACK);
+
+ if (setup_context) {
+ if (wm->windrawable) {
+ GHOST_ActivateWindowDrawingContext(wm->windrawable->ghostwin);
+ GPU_context_active_set(wm->windrawable->gpuctx);
+ }
+ }
+}
+
+/** \} */
+
+/* -------------------------------------------------------------------- */
/** \name Window Screen Shot Utility
*
* Include here since it can involve low level buffer switching.
@@ -2152,8 +2233,7 @@ void WM_window_screen_rect_calc(const wmWindow *win, rcti *r_rect)
screen_rect = window_rect;
/* Subtract global areas from screen rectangle. */
- for (ScrArea *global_area = win->global_areas.areabase.first; global_area;
- global_area = global_area->next) {
+ LISTBASE_FOREACH (ScrArea *, global_area, &win->global_areas.areabase) {
int height = ED_area_global_size_y(global_area) - 1;
if (global_area->global->flag & GLOBAL_AREA_IS_HIDDEN) {
@@ -2201,7 +2281,7 @@ bool WM_window_is_maximized(const wmWindow *win)
*/
void WM_windows_scene_data_sync(const ListBase *win_lb, Scene *scene)
{
- for (wmWindow *win = win_lb->first; win; win = win->next) {
+ LISTBASE_FOREACH (wmWindow *, win, win_lb) {
if (WM_window_get_active_scene(win) == scene) {
ED_workspace_scene_data_sync(win->workspace_hook, scene);
}
@@ -2210,7 +2290,7 @@ void WM_windows_scene_data_sync(const ListBase *win_lb, Scene *scene)
Scene *WM_windows_scene_get_from_screen(const wmWindowManager *wm, const bScreen *screen)
{
- for (wmWindow *win = wm->windows.first; win; win = win->next) {
+ LISTBASE_FOREACH (wmWindow *, win, &wm->windows) {
if (WM_window_get_active_screen(win) == screen) {
return WM_window_get_active_scene(win);
}
@@ -2221,7 +2301,7 @@ Scene *WM_windows_scene_get_from_screen(const wmWindowManager *wm, const bScreen
WorkSpace *WM_windows_workspace_get_from_screen(const wmWindowManager *wm, const bScreen *screen)
{
- for (wmWindow *win = wm->windows.first; win; win = win->next) {
+ LISTBASE_FOREACH (wmWindow *, win, &wm->windows) {
if (WM_window_get_active_screen(win) == screen) {
return WM_window_get_active_workspace(win);
}
@@ -2249,7 +2329,7 @@ void WM_window_set_active_scene(Main *bmain, bContext *C, wmWindow *win, Scene *
changed = true;
}
- for (wmWindow *win_child = wm->windows.first; win_child; win_child = win_child->next) {
+ LISTBASE_FOREACH (wmWindow *, win_child, &wm->windows) {
if (win_child->parent == win_parent && win_child->scene != scene) {
ED_screen_scene_change(C, win_child, scene);
changed = true;
@@ -2295,7 +2375,7 @@ void WM_window_set_active_view_layer(wmWindow *win, ViewLayer *view_layer)
wmWindow *win_parent = (win->parent) ? win->parent : win;
/* Set view layer in parent and child windows. */
- for (wmWindow *win_iter = wm->windows.first; win_iter; win_iter = win_iter->next) {
+ LISTBASE_FOREACH (wmWindow *, win_iter, &wm->windows) {
if ((win_iter == win_parent) || (win_iter->parent == win_parent)) {
STRNCPY(win_iter->view_layer_name, view_layer->name);
bScreen *screen = BKE_workspace_active_screen_get(win_iter->workspace_hook);
@@ -2327,7 +2407,7 @@ void WM_window_set_active_workspace(bContext *C, wmWindow *win, WorkSpace *works
ED_workspace_change(workspace, C, wm, win);
- for (wmWindow *win_child = wm->windows.first; win_child; win_child = win_child->next) {
+ LISTBASE_FOREACH (wmWindow *, win_child, &wm->windows) {
if (win_child->parent == win_parent) {
bScreen *screen = WM_window_get_active_screen(win_child);
/* Don't change temporary screens, they only serve a single purpose. */
@@ -2346,7 +2426,7 @@ WorkSpaceLayout *WM_window_get_active_layout(const wmWindow *win)
}
void WM_window_set_active_layout(wmWindow *win, WorkSpace *workspace, WorkSpaceLayout *layout)
{
- BKE_workspace_hook_layout_for_workspace_set(win->workspace_hook, workspace, layout);
+ BKE_workspace_active_layout_set(win->workspace_hook, workspace, layout);
}
/**
@@ -2441,24 +2521,3 @@ void WM_ghost_show_message_box(const char *title,
GHOST_ShowMessageBox(g_system, title, message, help_label, continue_label, link, dialog_options);
}
/** \} */
-
-#ifdef WIN32
-/* -------------------------------------------------------------------- */
-/** \name Direct DirectX Context Management
- * \{ */
-
-void *WM_directx_context_create(void)
-{
- BLI_assert(GPU_framebuffer_active_get() == NULL);
- return GHOST_CreateDirectXContext(g_system);
-}
-
-void WM_directx_context_dispose(void *context)
-{
- BLI_assert(GPU_framebuffer_active_get() == NULL);
- GHOST_DisposeDirectXContext(g_system, context);
-}
-
-/** \} */
-
-#endif
diff --git a/source/blender/windowmanager/intern/wm_xr.c b/source/blender/windowmanager/intern/wm_xr.c
deleted file mode 100644
index 7422fc97f04..00000000000
--- a/source/blender/windowmanager/intern/wm_xr.c
+++ /dev/null
@@ -1,765 +0,0 @@
-/*
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License
- * as published by the Free Software Foundation; either version 2
- * of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-
-/** \file
- * \ingroup wm
- *
- * \name Window-Manager XR API
- *
- * Implements Blender specific functionality for the GHOST_Xr API.
- */
-
-#include "BKE_context.h"
-#include "BKE_global.h"
-#include "BKE_idprop.h"
-#include "BKE_main.h"
-#include "BKE_object.h"
-#include "BKE_report.h"
-#include "BKE_screen.h"
-
-#include "BLI_ghash.h"
-#include "BLI_math_geom.h"
-#include "BLI_math_matrix.h"
-
-#include "CLG_log.h"
-
-#include "DNA_camera_types.h"
-#include "DNA_object_types.h"
-#include "DNA_scene_types.h"
-#include "DNA_view3d_types.h"
-#include "DNA_xr_types.h"
-
-#include "DRW_engine.h"
-
-#include "ED_view3d.h"
-#include "ED_view3d_offscreen.h"
-
-#include "GHOST_C-api.h"
-
-#include "GPU_context.h"
-#include "GPU_draw.h"
-#include "GPU_matrix.h"
-#include "GPU_viewport.h"
-
-#include "MEM_guardedalloc.h"
-
-#include "UI_interface.h"
-
-#include "WM_api.h"
-#include "WM_types.h"
-
-#include "wm.h"
-#include "wm_surface.h"
-#include "wm_window.h"
-
-struct wmXrRuntimeData *wm_xr_runtime_data_create(void);
-void wm_xr_runtime_data_free(struct wmXrRuntimeData **runtime);
-void wm_xr_draw_view(const GHOST_XrDrawViewInfo *, void *);
-void *wm_xr_session_gpu_binding_context_create(GHOST_TXrGraphicsBinding);
-void wm_xr_session_gpu_binding_context_destroy(GHOST_TXrGraphicsBinding, GHOST_ContextHandle);
-wmSurface *wm_xr_session_surface_create(wmWindowManager *, unsigned int);
-void wm_xr_pose_to_viewmat(const GHOST_XrPose *pose, float r_viewmat[4][4]);
-
-/* -------------------------------------------------------------------- */
-
-typedef struct wmXrSessionState {
- bool is_started;
-
- /** Last known viewer pose (centroid of eyes, in world space) stored for queries. */
- GHOST_XrPose viewer_pose;
- /** The last known view matrix, calculated from above's viewer pose. */
- float viewer_viewmat[4][4];
- float focal_len;
-
- /** Copy of XrSessionSettings.flag created on the last draw call, stored to detect changes. */
- int prev_settings_flag;
- /** Copy of wmXrDrawData.eye_position_ofs. */
- float prev_eye_position_ofs[3];
-
- bool is_view_data_set;
-} wmXrSessionState;
-
-typedef struct wmXrRuntimeData {
- GHOST_XrContextHandle context;
-
- /* Although this struct is internal, RNA gets a handle to this for state information queries. */
- wmXrSessionState session_state;
- wmXrSessionExitFn exit_fn;
-} wmXrRuntimeData;
-
-typedef struct wmXrDrawData {
- /** The pose (location + rotation) to which eye deltas will be applied to when drawing (world
- * space). With positional tracking enabled, it should be the same as the base pose, when
- * disabled it also contains a location delta from the moment the option was toggled. */
- GHOST_XrPose base_pose;
- float eye_position_ofs[3]; /* Local/view space. */
-} wmXrDrawData;
-
-typedef struct {
- GHOST_TXrGraphicsBinding gpu_binding_type;
- GPUOffScreen *offscreen;
- GPUViewport *viewport;
-
- GHOST_ContextHandle secondary_ghost_ctx;
-} wmXrSurfaceData;
-
-typedef struct {
- wmWindowManager *wm;
-} wmXrErrorHandlerData;
-
-/* -------------------------------------------------------------------- */
-
-static wmSurface *g_xr_surface = NULL;
-static CLG_LogRef LOG = {"wm.xr"};
-
-/* -------------------------------------------------------------------- */
-/** \name XR-Context
- *
- * All XR functionality is accessed through a #GHOST_XrContext handle.
- * The lifetime of this context also determines the lifetime of the OpenXR instance, which is the
- * representation of the OpenXR runtime connection within the application.
- *
- * \{ */
-
-static void wm_xr_error_handler(const GHOST_XrError *error)
-{
- wmXrErrorHandlerData *handler_data = error->customdata;
- wmWindowManager *wm = handler_data->wm;
-
- BKE_reports_clear(&wm->reports);
- WM_report(RPT_ERROR, error->user_message);
- WM_report_banner_show();
-
- if (wm->xr.runtime) {
- /* Just play safe and destroy the entire runtime data, including context. */
- wm_xr_runtime_data_free(&wm->xr.runtime);
- }
-}
-
-bool wm_xr_init(wmWindowManager *wm)
-{
- if (wm->xr.runtime && wm->xr.runtime->context) {
- return true;
- }
- static wmXrErrorHandlerData error_customdata;
-
- /* Set up error handling */
- error_customdata.wm = wm;
- GHOST_XrErrorHandler(wm_xr_error_handler, &error_customdata);
-
- {
- const GHOST_TXrGraphicsBinding gpu_bindings_candidates[] = {
- GHOST_kXrGraphicsOpenGL,
-#ifdef WIN32
- GHOST_kXrGraphicsD3D11,
-#endif
- };
- GHOST_XrContextCreateInfo create_info = {
- .gpu_binding_candidates = gpu_bindings_candidates,
- .gpu_binding_candidates_count = ARRAY_SIZE(gpu_bindings_candidates),
- };
- GHOST_XrContextHandle context;
-
- if (G.debug & G_DEBUG_XR) {
- create_info.context_flag |= GHOST_kXrContextDebug;
- }
- if (G.debug & G_DEBUG_XR_TIME) {
- create_info.context_flag |= GHOST_kXrContextDebugTime;
- }
-
- if (!(context = GHOST_XrContextCreate(&create_info))) {
- return false;
- }
-
- /* Set up context callbacks */
- GHOST_XrGraphicsContextBindFuncs(context,
- wm_xr_session_gpu_binding_context_create,
- wm_xr_session_gpu_binding_context_destroy);
- GHOST_XrDrawViewFunc(context, wm_xr_draw_view);
-
- if (!wm->xr.runtime) {
- wm->xr.runtime = wm_xr_runtime_data_create();
- wm->xr.runtime->context = context;
- }
- }
- BLI_assert(wm->xr.runtime && wm->xr.runtime->context);
-
- return true;
-}
-
-void wm_xr_exit(wmWindowManager *wm)
-{
- if (wm->xr.runtime != NULL) {
- wm_xr_runtime_data_free(&wm->xr.runtime);
- }
- if (wm->xr.session_settings.shading.prop) {
- IDP_FreeProperty(wm->xr.session_settings.shading.prop);
- wm->xr.session_settings.shading.prop = NULL;
- }
-}
-
-bool wm_xr_events_handle(wmWindowManager *wm)
-{
- if (wm->xr.runtime && wm->xr.runtime->context) {
- return GHOST_XrEventsHandle(wm->xr.runtime->context);
- }
- return false;
-}
-
-/** \} */ /* XR-Context */
-
-/* -------------------------------------------------------------------- */
-/** \name XR Runtime Data
- *
- * \{ */
-
-wmXrRuntimeData *wm_xr_runtime_data_create(void)
-{
- wmXrRuntimeData *runtime = MEM_callocN(sizeof(*runtime), __func__);
- return runtime;
-}
-
-void wm_xr_runtime_data_free(wmXrRuntimeData **runtime)
-{
- /* Note that this function may be called twice, because of an indirect recursion: If a session is
- * running while WM-XR calls this function, calling GHOST_XrContextDestroy() will call this
- * again, because it's also set as the session exit callback. So NULL-check and NULL everything
- * that is freed here. */
-
- /* We free all runtime XR data here, so if the context is still alive, destroy it. */
- if ((*runtime)->context != NULL) {
- GHOST_XrContextHandle context = (*runtime)->context;
- /* Prevent recursive GHOST_XrContextDestroy() call by NULL'ing the context pointer before the
- * first call, see comment above. */
- (*runtime)->context = NULL;
- GHOST_XrContextDestroy(context);
- }
- MEM_SAFE_FREE(*runtime);
-}
-
-static void wm_xr_base_pose_calc(const Scene *scene,
- const XrSessionSettings *settings,
- GHOST_XrPose *r_base_pose)
-{
- const Object *base_pose_object = ((settings->base_pose_type == XR_BASE_POSE_OBJECT) &&
- settings->base_pose_object) ?
- settings->base_pose_object :
- scene->camera;
-
- if (settings->base_pose_type == XR_BASE_POSE_CUSTOM) {
- float tmp_quatx[4], tmp_quatz[4];
-
- copy_v3_v3(r_base_pose->position, settings->base_pose_location);
- axis_angle_to_quat_single(tmp_quatx, 'X', M_PI_2);
- axis_angle_to_quat_single(tmp_quatz, 'Z', settings->base_pose_angle);
- mul_qt_qtqt(r_base_pose->orientation_quat, tmp_quatz, tmp_quatx);
- }
- else if (base_pose_object) {
- float tmp_quat[4];
- float tmp_eul[3];
-
- mat4_to_loc_quat(r_base_pose->position, tmp_quat, base_pose_object->obmat);
-
- /* Only use rotation around Z-axis to align view with floor. */
- quat_to_eul(tmp_eul, tmp_quat);
- tmp_eul[0] = M_PI_2;
- tmp_eul[1] = 0;
- eul_to_quat(r_base_pose->orientation_quat, tmp_eul);
- }
- else {
- copy_v3_fl(r_base_pose->position, 0.0f);
- axis_angle_to_quat_single(r_base_pose->orientation_quat, 'X', M_PI_2);
- }
-}
-
-static void wm_xr_draw_data_populate(const wmXrSessionState *state,
- const GHOST_XrDrawViewInfo *draw_view,
- const XrSessionSettings *settings,
- const Scene *scene,
- wmXrDrawData *r_draw_data)
-{
- const bool position_tracking_toggled = ((state->prev_settings_flag &
- XR_SESSION_USE_POSITION_TRACKING) !=
- (settings->flag & XR_SESSION_USE_POSITION_TRACKING));
- const bool use_position_tracking = settings->flag & XR_SESSION_USE_POSITION_TRACKING;
-
- memset(r_draw_data, 0, sizeof(*r_draw_data));
-
- wm_xr_base_pose_calc(scene, settings, &r_draw_data->base_pose);
-
- /* Set the eye position offset, it's used to offset the base pose when changing positional
- * tracking. */
- if (!state->is_view_data_set) {
- /* Always use the exact base pose with no offset when starting the session. */
- copy_v3_fl(r_draw_data->eye_position_ofs, 0.0f);
- }
- else if (position_tracking_toggled) {
- if (use_position_tracking) {
- copy_v3_fl(r_draw_data->eye_position_ofs, 0.0f);
- }
- else {
- /* Store the current local offset (local pose) so that we can apply that to the eyes. This
- * way the eyes stay exactly where they are when disabling positional tracking. */
- copy_v3_v3(r_draw_data->eye_position_ofs, draw_view->local_pose.position);
- }
- }
- else if (!use_position_tracking) {
- /* Keep previous offset when positional tracking is disabled. */
- copy_v3_v3(r_draw_data->eye_position_ofs, state->prev_eye_position_ofs);
- }
-}
-
-/**
- * Update information that is only stored for external state queries. E.g. for Python API to
- * request the current (as in, last known) viewer pose.
- */
-static void wm_xr_session_state_update(wmXrSessionState *state,
- const GHOST_XrDrawViewInfo *draw_view,
- const XrSessionSettings *settings,
- const wmXrDrawData *draw_data)
-{
- GHOST_XrPose viewer_pose;
- const bool use_position_tracking = settings->flag & XR_SESSION_USE_POSITION_TRACKING;
-
- mul_qt_qtqt(viewer_pose.orientation_quat,
- draw_data->base_pose.orientation_quat,
- draw_view->local_pose.orientation_quat);
- copy_v3_v3(viewer_pose.position, draw_data->base_pose.position);
- /* The local pose and the eye pose (which is copied from an earlier local pose) both are view
- * space, so Y-up. In this case we need them in regular Z-up. */
- viewer_pose.position[0] += draw_data->eye_position_ofs[0];
- viewer_pose.position[1] -= draw_data->eye_position_ofs[2];
- viewer_pose.position[2] += draw_data->eye_position_ofs[1];
- if (use_position_tracking) {
- viewer_pose.position[0] += draw_view->local_pose.position[0];
- viewer_pose.position[1] -= draw_view->local_pose.position[2];
- viewer_pose.position[2] += draw_view->local_pose.position[1];
- }
-
- copy_v3_v3(state->viewer_pose.position, viewer_pose.position);
- copy_qt_qt(state->viewer_pose.orientation_quat, viewer_pose.orientation_quat);
- wm_xr_pose_to_viewmat(&viewer_pose, state->viewer_viewmat);
- /* No idea why, but multiplying by two seems to make it match the VR view more. */
- state->focal_len = 2.0f *
- fov_to_focallength(draw_view->fov.angle_right - draw_view->fov.angle_left,
- DEFAULT_SENSOR_WIDTH);
-
- copy_v3_v3(state->prev_eye_position_ofs, draw_data->eye_position_ofs);
- state->prev_settings_flag = settings->flag;
- state->is_view_data_set = true;
-}
-
-wmXrSessionState *WM_xr_session_state_handle_get(const wmXrData *xr)
-{
- return xr->runtime ? &xr->runtime->session_state : NULL;
-}
-
-bool WM_xr_session_state_viewer_pose_location_get(const wmXrData *xr, float r_location[3])
-{
- if (!WM_xr_session_is_ready(xr) || !xr->runtime->session_state.is_view_data_set) {
- zero_v3(r_location);
- return false;
- }
-
- copy_v3_v3(r_location, xr->runtime->session_state.viewer_pose.position);
- return true;
-}
-
-bool WM_xr_session_state_viewer_pose_rotation_get(const wmXrData *xr, float r_rotation[4])
-{
- if (!WM_xr_session_is_ready(xr) || !xr->runtime->session_state.is_view_data_set) {
- unit_qt(r_rotation);
- return false;
- }
-
- copy_v4_v4(r_rotation, xr->runtime->session_state.viewer_pose.orientation_quat);
- return true;
-}
-
-bool WM_xr_session_state_viewer_pose_matrix_info_get(const wmXrData *xr,
- float r_viewmat[4][4],
- float *r_focal_len)
-{
- if (!WM_xr_session_is_ready(xr) || !xr->runtime->session_state.is_view_data_set) {
- unit_m4(r_viewmat);
- *r_focal_len = 0.0f;
- return false;
- }
-
- copy_m4_m4(r_viewmat, xr->runtime->session_state.viewer_viewmat);
- *r_focal_len = xr->runtime->session_state.focal_len;
-
- return true;
-}
-
-/** \} */ /* XR Runtime Data */
-
-/* -------------------------------------------------------------------- */
-/** \name XR-Session
- *
- * \{ */
-
-void *wm_xr_session_gpu_binding_context_create(GHOST_TXrGraphicsBinding graphics_binding)
-{
- wmSurface *surface = wm_xr_session_surface_create(G_MAIN->wm.first, graphics_binding);
- wmXrSurfaceData *data = surface->customdata;
-
- wm_surface_add(surface);
-
- /* Some regions may need to redraw with updated session state after the session is entirely up
- * and running. */
- WM_main_add_notifier(NC_WM | ND_XR_DATA_CHANGED, NULL);
-
- return data->secondary_ghost_ctx ? data->secondary_ghost_ctx : surface->ghost_ctx;
-}
-
-void wm_xr_session_gpu_binding_context_destroy(GHOST_TXrGraphicsBinding UNUSED(graphics_lib),
- GHOST_ContextHandle UNUSED(context))
-{
- if (g_xr_surface) { /* Might have been freed already */
- wm_surface_remove(g_xr_surface);
- }
-
- wm_window_reset_drawable();
-
- /* Some regions may need to redraw with updated session state after the session is entirely
- * stopped. */
- WM_main_add_notifier(NC_WM | ND_XR_DATA_CHANGED, NULL);
-}
-
-static void wm_xr_session_exit_cb(void *customdata)
-{
- wmXrData *xr_data = customdata;
-
- xr_data->runtime->session_state.is_started = false;
- if (xr_data->runtime->exit_fn) {
- xr_data->runtime->exit_fn(xr_data);
- }
-
- /* Free the entire runtime data (including session state and context), to play safe. */
- wm_xr_runtime_data_free(&xr_data->runtime);
-}
-
-static void wm_xr_session_begin_info_create(wmXrData *xr_data,
- GHOST_XrSessionBeginInfo *r_begin_info)
-{
- /* WM-XR exit function, does some own stuff and calls callback passed to wm_xr_session_toggle(),
- * to allow external code to execute its own session-exit logic. */
- r_begin_info->exit_fn = wm_xr_session_exit_cb;
- r_begin_info->exit_customdata = xr_data;
-}
-
-void wm_xr_session_toggle(wmWindowManager *wm, wmXrSessionExitFn session_exit_fn)
-{
- wmXrData *xr_data = &wm->xr;
-
- if (WM_xr_session_exists(xr_data)) {
- GHOST_XrSessionEnd(xr_data->runtime->context);
- }
- else {
- GHOST_XrSessionBeginInfo begin_info;
-
- xr_data->runtime->session_state.is_started = true;
- xr_data->runtime->exit_fn = session_exit_fn;
-
- wm_xr_session_begin_info_create(xr_data, &begin_info);
- GHOST_XrSessionStart(xr_data->runtime->context, &begin_info);
- }
-}
-
-/**
- * Check if the XR-Session was triggered.
- * If an error happened while trying to start a session, this returns false too.
- */
-bool WM_xr_session_exists(const wmXrData *xr)
-{
- return xr->runtime && xr->runtime->context && xr->runtime->session_state.is_started;
-}
-
-/**
- * Check if the session is running, according to the OpenXR definition.
- */
-bool WM_xr_session_is_ready(const wmXrData *xr)
-{
- return WM_xr_session_exists(xr) && GHOST_XrSessionIsRunning(xr->runtime->context);
-}
-
-/** \} */ /* XR-Session */
-
-/* -------------------------------------------------------------------- */
-/** \name XR-Session Surface
- *
- * A wmSurface is used to manage drawing of the VR viewport. It's created and destroyed with the
- * session.
- *
- * \{ */
-
-/**
- * \brief Call Ghost-XR to draw a frame
- *
- * Draw callback for the XR-session surface. It's expected to be called on each main loop iteration
- * and tells Ghost-XR to submit a new frame by drawing its views. Note that for drawing each view,
- * #wm_xr_draw_view() will be called through Ghost-XR (see GHOST_XrDrawViewFunc()).
- */
-static void wm_xr_session_surface_draw(bContext *C)
-{
- wmXrSurfaceData *surface_data = g_xr_surface->customdata;
- wmWindowManager *wm = CTX_wm_manager(C);
-
- if (!GHOST_XrSessionIsRunning(wm->xr.runtime->context)) {
- return;
- }
- DRW_xr_drawing_begin();
- GHOST_XrSessionDrawViews(wm->xr.runtime->context, C);
- GPU_offscreen_unbind(surface_data->offscreen, false);
- DRW_xr_drawing_end();
-}
-
-static void wm_xr_session_free_data(wmSurface *surface)
-{
- wmXrSurfaceData *data = surface->customdata;
-
- if (data->secondary_ghost_ctx) {
-#ifdef WIN32
- if (data->gpu_binding_type == GHOST_kXrGraphicsD3D11) {
- WM_directx_context_dispose(data->secondary_ghost_ctx);
- }
-#endif
- }
- if (data->viewport) {
- GPU_viewport_free(data->viewport);
- }
- if (data->offscreen) {
- GPU_offscreen_free(data->offscreen);
- }
-
- MEM_freeN(surface->customdata);
-
- g_xr_surface = NULL;
-}
-
-static bool wm_xr_session_surface_offscreen_ensure(const GHOST_XrDrawViewInfo *draw_view)
-{
- wmXrSurfaceData *surface_data = g_xr_surface->customdata;
- const bool size_changed = surface_data->offscreen &&
- (GPU_offscreen_width(surface_data->offscreen) != draw_view->width) &&
- (GPU_offscreen_height(surface_data->offscreen) != draw_view->height);
- char err_out[256] = "unknown";
- bool failure = false;
-
- if (surface_data->offscreen) {
- BLI_assert(surface_data->viewport);
-
- if (!size_changed) {
- return true;
- }
- GPU_viewport_free(surface_data->viewport);
- GPU_offscreen_free(surface_data->offscreen);
- }
-
- if (!(surface_data->offscreen = GPU_offscreen_create(
- draw_view->width, draw_view->height, 0, true, false, err_out))) {
- failure = true;
- }
-
- if (failure) {
- /* Pass. */
- }
- else if (!(surface_data->viewport = GPU_viewport_create())) {
- GPU_offscreen_free(surface_data->offscreen);
- failure = true;
- }
-
- if (failure) {
- CLOG_ERROR(&LOG, "Failed to get buffer, %s\n", err_out);
- return false;
- }
-
- return true;
-}
-
-wmSurface *wm_xr_session_surface_create(wmWindowManager *UNUSED(wm), unsigned int gpu_binding_type)
-{
- if (g_xr_surface) {
- BLI_assert(false);
- return g_xr_surface;
- }
-
- wmSurface *surface = MEM_callocN(sizeof(*surface), __func__);
- wmXrSurfaceData *data = MEM_callocN(sizeof(*data), "XrSurfaceData");
-
-#ifndef WIN32
- BLI_assert(gpu_binding_type == GHOST_kXrGraphicsOpenGL);
-#endif
-
- surface->draw = wm_xr_session_surface_draw;
- surface->free_data = wm_xr_session_free_data;
-
- data->gpu_binding_type = gpu_binding_type;
- surface->customdata = data;
-
- surface->ghost_ctx = DRW_xr_opengl_context_get();
-
- switch (gpu_binding_type) {
- case GHOST_kXrGraphicsOpenGL:
- break;
-#ifdef WIN32
- case GHOST_kXrGraphicsD3D11:
- data->secondary_ghost_ctx = WM_directx_context_create();
- break;
-#endif
- }
-
- surface->gpu_ctx = DRW_xr_gpu_context_get();
-
- g_xr_surface = surface;
-
- return surface;
-}
-
-/** \} */ /* XR-Session Surface */
-
-/* -------------------------------------------------------------------- */
-/** \name XR Drawing
- *
- * \{ */
-
-void wm_xr_pose_to_viewmat(const GHOST_XrPose *pose, float r_viewmat[4][4])
-{
- float iquat[4];
- invert_qt_qt_normalized(iquat, pose->orientation_quat);
- quat_to_mat4(r_viewmat, iquat);
- translate_m4(r_viewmat, -pose->position[0], -pose->position[1], -pose->position[2]);
-}
-
-static void wm_xr_draw_matrices_create(const wmXrDrawData *draw_data,
- const GHOST_XrDrawViewInfo *draw_view,
- const XrSessionSettings *session_settings,
- float r_view_mat[4][4],
- float r_proj_mat[4][4])
-{
- GHOST_XrPose eye_pose;
-
- copy_qt_qt(eye_pose.orientation_quat, draw_view->eye_pose.orientation_quat);
- copy_v3_v3(eye_pose.position, draw_view->eye_pose.position);
- add_v3_v3(eye_pose.position, draw_data->eye_position_ofs);
- if ((session_settings->flag & XR_SESSION_USE_POSITION_TRACKING) == 0) {
- sub_v3_v3(eye_pose.position, draw_view->local_pose.position);
- }
-
- perspective_m4_fov(r_proj_mat,
- draw_view->fov.angle_left,
- draw_view->fov.angle_right,
- draw_view->fov.angle_up,
- draw_view->fov.angle_down,
- session_settings->clip_start,
- session_settings->clip_end);
-
- float eye_mat[4][4];
- float base_mat[4][4];
-
- wm_xr_pose_to_viewmat(&eye_pose, eye_mat);
- /* Calculate the base pose matrix (in world space!). */
- wm_xr_pose_to_viewmat(&draw_data->base_pose, base_mat);
-
- mul_m4_m4m4(r_view_mat, eye_mat, base_mat);
-}
-
-static void wm_xr_draw_viewport_buffers_to_active_framebuffer(
- const wmXrSurfaceData *surface_data, const GHOST_XrDrawViewInfo *draw_view)
-{
- const bool is_upside_down = surface_data->secondary_ghost_ctx &&
- GHOST_isUpsideDownContext(surface_data->secondary_ghost_ctx);
- rcti rect = {.xmin = 0, .ymin = 0, .xmax = draw_view->width - 1, .ymax = draw_view->height - 1};
-
- wmViewport(&rect);
-
- /* For upside down contexts, draw with inverted y-values. */
- if (is_upside_down) {
- SWAP(int, rect.ymin, rect.ymax);
- }
- GPU_viewport_draw_to_screen_ex(surface_data->viewport, 0, &rect, draw_view->expects_srgb_buffer);
-}
-
-/**
- * \brief Draw a viewport for a single eye.
- *
- * This is the main viewport drawing function for VR sessions. It's assigned to Ghost-XR as a
- * callback (see GHOST_XrDrawViewFunc()) and executed for each view (read: eye).
- */
-void wm_xr_draw_view(const GHOST_XrDrawViewInfo *draw_view, void *customdata)
-{
- bContext *C = customdata;
- wmWindowManager *wm = CTX_wm_manager(C);
- wmXrSurfaceData *surface_data = g_xr_surface->customdata;
- wmXrSessionState *session_state = &wm->xr.runtime->session_state;
- XrSessionSettings *settings = &wm->xr.session_settings;
- wmXrDrawData draw_data;
- Scene *scene = CTX_data_scene(C);
-
- const int display_flags = V3D_OFSDRAW_OVERRIDE_SCENE_SETTINGS | settings->draw_flags;
-
- float viewmat[4][4], winmat[4][4];
-
- BLI_assert(WM_xr_session_is_ready(&wm->xr));
-
- wm_xr_draw_data_populate(session_state, draw_view, settings, scene, &draw_data);
- wm_xr_draw_matrices_create(&draw_data, draw_view, settings, viewmat, winmat);
- wm_xr_session_state_update(session_state, draw_view, settings, &draw_data);
-
- if (!wm_xr_session_surface_offscreen_ensure(draw_view)) {
- return;
- }
-
- /* In case a framebuffer is still bound from drawing the last eye. */
- GPU_framebuffer_restore();
- /* Some systems have drawing glitches without this. */
- GPU_clear(GPU_DEPTH_BIT);
-
- /* Draws the view into the surface_data->viewport's framebuffers */
- ED_view3d_draw_offscreen_simple(CTX_data_ensure_evaluated_depsgraph(C),
- scene,
- &wm->xr.session_settings.shading,
- wm->xr.session_settings.shading.type,
- draw_view->width,
- draw_view->height,
- display_flags,
- viewmat,
- winmat,
- settings->clip_start,
- settings->clip_end,
- false,
- true,
- true,
- NULL,
- false,
- surface_data->offscreen,
- surface_data->viewport);
-
- /* The draw-manager uses both GPUOffscreen and GPUViewport to manage frame and texture buffers. A
- * call to GPU_viewport_draw_to_screen() is still needed to get the final result from the
- * viewport buffers composited together and potentially color managed for display on screen.
- * It needs a bound frame-buffer to draw into, for which we simply reuse the GPUOffscreen one.
- *
- * In a next step, Ghost-XR will use the the currently bound frame-buffer to retrieve the image
- * to be submitted to the OpenXR swap-chain. So do not un-bind the offscreen yet! */
-
- GPU_offscreen_bind(surface_data->offscreen, false);
-
- wm_xr_draw_viewport_buffers_to_active_framebuffer(surface_data, draw_view);
-}
-
-/** \} */ /* XR Drawing */
diff --git a/source/blender/windowmanager/message_bus/intern/wm_message_bus.c b/source/blender/windowmanager/message_bus/intern/wm_message_bus.c
index fd5237a70a5..86a106462c3 100644
--- a/source/blender/windowmanager/message_bus/intern/wm_message_bus.c
+++ b/source/blender/windowmanager/message_bus/intern/wm_message_bus.c
@@ -111,7 +111,7 @@ void WM_msgbus_clear_by_owner(struct wmMsgBus *mbus, void *owner)
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) {
+ LISTBASE_FOREACH (wmMsgSubscribeKey *, key, &mbus->messages) {
const wmMsg *msg = wm_msg_subscribe_value_msg_cast(key);
const wmMsgTypeInfo *info = &wm_msg_types[msg->type];
info->repr(stdout, key);
@@ -131,8 +131,8 @@ void WM_msgbus_handle(struct wmMsgBus *mbus, struct bContext *C)
}
// 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) {
+ LISTBASE_FOREACH (wmMsgSubscribeKey *, key, &mbus->messages) {
+ LISTBASE_FOREACH (wmMsgSubscribeValueLink *, msg_lnk, &key->values) {
if (msg_lnk->params.tag) {
msg_lnk->params.notify(C, key, &msg_lnk->params);
msg_lnk->params.tag = false;
@@ -175,7 +175,7 @@ wmMsgSubscribeKey *WM_msg_subscribe_with_key(struct wmMsgBus *mbus,
}
else {
key = *r_key;
- for (wmMsgSubscribeValueLink *msg_lnk = key->values.first; msg_lnk; msg_lnk = msg_lnk->next) {
+ LISTBASE_FOREACH (wmMsgSubscribeValueLink *, msg_lnk, &key->values) {
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)) {
@@ -198,8 +198,7 @@ void WM_msg_publish_with_key(struct wmMsgBus *mbus, wmMsgSubscribeKey *msg_key)
msg_key,
BLI_listbase_count(&msg_key->values));
- for (wmMsgSubscribeValueLink *msg_lnk = msg_key->values.first; msg_lnk;
- msg_lnk = msg_lnk->next) {
+ LISTBASE_FOREACH (wmMsgSubscribeValueLink *, msg_lnk, &msg_key->values) {
if (false) { /* make an option? */
msg_lnk->params.notify(NULL, msg_key, &msg_lnk->params);
}
diff --git a/source/blender/windowmanager/wm.h b/source/blender/windowmanager/wm.h
index 97403a0315a..16aa5cb44db 100644
--- a/source/blender/windowmanager/wm.h
+++ b/source/blender/windowmanager/wm.h
@@ -80,6 +80,7 @@ void wm_autosave_location(char *filepath);
/* wm_splash_screen.c */
void WM_OT_splash(wmOperatorType *ot);
+void WM_OT_splash_about(wmOperatorType *ot);
/* wm_stereo.c */
void wm_stereo3d_draw_sidebyside(wmWindow *win, int view);
@@ -96,14 +97,4 @@ void wm_stereo3d_set_cancel(bContext *C, wmOperator *op);
void wm_open_init_load_ui(wmOperator *op, bool use_prefs);
void wm_open_init_use_scripts(wmOperator *op, bool use_prefs);
-#ifdef WITH_XR_OPENXR
-typedef void (*wmXrSessionExitFn)(const wmXrData *xr_data);
-
-/* wm_xr.c */
-bool wm_xr_init(wmWindowManager *wm);
-void wm_xr_exit(wmWindowManager *wm);
-void wm_xr_session_toggle(wmWindowManager *wm, wmXrSessionExitFn session_exit_fn);
-bool wm_xr_events_handle(wmWindowManager *wm);
#endif
-
-#endif /* __WM_H__ */
diff --git a/source/blender/windowmanager/wm_draw.h b/source/blender/windowmanager/wm_draw.h
index b19fdf97569..ff2fc25333a 100644
--- a/source/blender/windowmanager/wm_draw.h
+++ b/source/blender/windowmanager/wm_draw.h
@@ -46,7 +46,7 @@ struct wmWindow;
void wm_draw_update(struct bContext *C);
void wm_draw_region_clear(struct wmWindow *win, struct ARegion *region);
void wm_draw_region_blend(struct ARegion *region, int view, bool blend);
-void wm_draw_region_test(struct bContext *C, struct ScrArea *sa, struct ARegion *region);
+void wm_draw_region_test(struct bContext *C, struct ScrArea *area, struct ARegion *region);
struct GPUTexture *wm_draw_region_texture(struct ARegion *region, int view);
diff --git a/source/blender/windowmanager/wm_event_system.h b/source/blender/windowmanager/wm_event_system.h
index 95d3820cf96..b837cafd30a 100644
--- a/source/blender/windowmanager/wm_event_system.h
+++ b/source/blender/windowmanager/wm_event_system.h
@@ -149,6 +149,11 @@ void wm_event_do_depsgraph(bContext *C, bool is_after_open_file);
void wm_event_do_refresh_wm_and_depsgraph(bContext *C);
void wm_event_do_notifiers(bContext *C);
+void wm_event_handler_ui_cancel_ex(bContext *C,
+ wmWindow *win,
+ ARegion *region,
+ bool reactivate_button);
+
/* wm_event_query.c */
float wm_pressure_curve(float raw_pressure);
void wm_tablet_data_from_ghost(const struct GHOST_TabletData *tablet_data, wmTabletData *wmtab);
diff --git a/source/blender/windowmanager/wm_event_types.h b/source/blender/windowmanager/wm_event_types.h
index f16056cc91e..ffed86abfe7 100644
--- a/source/blender/windowmanager/wm_event_types.h
+++ b/source/blender/windowmanager/wm_event_types.h
@@ -333,6 +333,7 @@ enum {
EVT_BUT_OPEN = 0x5021, /* 20513 */
EVT_MODAL_MAP = 0x5022, /* 20514 */
EVT_DROP = 0x5023, /* 20515 */
+ /* When value is 0, re-activate, when 1, don't re-activate the button under the cursor. */
EVT_BUT_CANCEL = 0x5024, /* 20516 */
/* could become gizmo callback */
diff --git a/source/blender/windowmanager/wm_files.h b/source/blender/windowmanager/wm_files.h
index e081742b904..42eab35cdb9 100644
--- a/source/blender/windowmanager/wm_files.h
+++ b/source/blender/windowmanager/wm_files.h
@@ -45,8 +45,6 @@ void wm_close_file_dialog(bContext *C, struct wmGenericCallback *post_action);
bool wm_file_or_image_is_modified(const Main *bmain, const wmWindowManager *wm);
void WM_OT_save_homefile(struct wmOperatorType *ot);
-void WM_OT_userpref_autoexec_path_add(struct wmOperatorType *ot);
-void WM_OT_userpref_autoexec_path_remove(struct wmOperatorType *ot);
void WM_OT_save_userpref(struct wmOperatorType *ot);
void WM_OT_read_userpref(struct wmOperatorType *ot);
void WM_OT_read_factory_userpref(struct wmOperatorType *ot);
diff --git a/source/blender/windowmanager/wm_surface.h b/source/blender/windowmanager/wm_surface.h
index 98d67c55619..e1b00ae1ade 100644
--- a/source/blender/windowmanager/wm_surface.h
+++ b/source/blender/windowmanager/wm_surface.h
@@ -46,7 +46,7 @@ void wm_surface_remove(wmSurface *surface);
void wm_surfaces_free(void);
/* Utils */
-void wm_surfaces_iter(struct bContext *C, void (*cb)(bContext *, wmSurface *));
+void wm_surfaces_iter(struct bContext *C, void (*cb)(struct bContext *, wmSurface *));
/* Drawing */
void wm_surface_make_drawable(wmSurface *surface);
diff --git a/source/blender/windowmanager/wm_window.h b/source/blender/windowmanager/wm_window.h
index ce9d79b8e59..5ca5711b4f2 100644
--- a/source/blender/windowmanager/wm_window.h
+++ b/source/blender/windowmanager/wm_window.h
@@ -33,7 +33,10 @@ void wm_ghost_exit(void);
void wm_get_screensize(int *r_width, int *r_height);
void wm_get_desktopsize(int *r_width, int *r_height);
-wmWindow *wm_window_new(const struct Main *bmain, wmWindowManager *wm, wmWindow *parent);
+wmWindow *wm_window_new(const struct Main *bmain,
+ wmWindowManager *wm,
+ wmWindow *parent,
+ bool dialog);
wmWindow *wm_window_copy(struct Main *bmain,
wmWindowManager *wm,
wmWindow *win_src,
@@ -82,11 +85,4 @@ int wm_window_new_main_exec(bContext *C, struct wmOperator *op);
void wm_test_autorun_warning(bContext *C);
-/* Initial (unmaximized) size to start with for
- * systems that can't find it for themselves (X11).
- * Clamped by real desktop limits */
-#define WM_WIN_INIT_SIZE_X 1800
-#define WM_WIN_INIT_SIZE_Y 1000
-#define WM_WIN_INIT_PAD 40
-
#endif /* __WM_WINDOW_H__ */
diff --git a/source/blender/windowmanager/xr/intern/wm_xr.c b/source/blender/windowmanager/xr/intern/wm_xr.c
new file mode 100644
index 00000000000..90f30809136
--- /dev/null
+++ b/source/blender/windowmanager/xr/intern/wm_xr.c
@@ -0,0 +1,168 @@
+/*
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+
+/** \file
+ * \ingroup wm
+ *
+ * All XR functionality is accessed through a #GHOST_XrContext handle.
+ * The lifetime of this context also determines the lifetime of the OpenXR instance, which is the
+ * representation of the OpenXR runtime connection within the application.
+ */
+
+#include "BKE_global.h"
+#include "BKE_idprop.h"
+#include "BKE_report.h"
+
+#include "DNA_scene_types.h"
+#include "DNA_windowmanager_types.h"
+
+#include "DEG_depsgraph.h"
+
+#include "MEM_guardedalloc.h"
+
+#include "GHOST_C-api.h"
+
+#include "WM_api.h"
+
+#include "wm_surface.h"
+#include "wm_xr_intern.h"
+
+typedef struct {
+ wmWindowManager *wm;
+} wmXrErrorHandlerData;
+
+/* -------------------------------------------------------------------- */
+
+static void wm_xr_error_handler(const GHOST_XrError *error)
+{
+ wmXrErrorHandlerData *handler_data = error->customdata;
+ wmWindowManager *wm = handler_data->wm;
+
+ BKE_reports_clear(&wm->reports);
+ WM_report(RPT_ERROR, error->user_message);
+ WM_report_banner_show();
+
+ if (wm->xr.runtime) {
+ /* Just play safe and destroy the entire runtime data, including context. */
+ wm_xr_runtime_data_free(&wm->xr.runtime);
+ }
+}
+
+bool wm_xr_init(wmWindowManager *wm)
+{
+ if (wm->xr.runtime && wm->xr.runtime->context) {
+ return true;
+ }
+ static wmXrErrorHandlerData error_customdata;
+
+ /* Set up error handling */
+ error_customdata.wm = wm;
+ GHOST_XrErrorHandler(wm_xr_error_handler, &error_customdata);
+
+ {
+ const GHOST_TXrGraphicsBinding gpu_bindings_candidates[] = {
+ GHOST_kXrGraphicsOpenGL,
+#ifdef WIN32
+ GHOST_kXrGraphicsD3D11,
+#endif
+ };
+ GHOST_XrContextCreateInfo create_info = {
+ .gpu_binding_candidates = gpu_bindings_candidates,
+ .gpu_binding_candidates_count = ARRAY_SIZE(gpu_bindings_candidates),
+ };
+ GHOST_XrContextHandle context;
+
+ if (G.debug & G_DEBUG_XR) {
+ create_info.context_flag |= GHOST_kXrContextDebug;
+ }
+ if (G.debug & G_DEBUG_XR_TIME) {
+ create_info.context_flag |= GHOST_kXrContextDebugTime;
+ }
+
+ if (!(context = GHOST_XrContextCreate(&create_info))) {
+ return false;
+ }
+
+ /* Set up context callbacks */
+ GHOST_XrGraphicsContextBindFuncs(context,
+ wm_xr_session_gpu_binding_context_create,
+ wm_xr_session_gpu_binding_context_destroy);
+ GHOST_XrDrawViewFunc(context, wm_xr_draw_view);
+
+ if (!wm->xr.runtime) {
+ wm->xr.runtime = wm_xr_runtime_data_create();
+ wm->xr.runtime->context = context;
+ }
+ }
+ BLI_assert(wm->xr.runtime && wm->xr.runtime->context);
+
+ return true;
+}
+
+void wm_xr_exit(wmWindowManager *wm)
+{
+ if (wm->xr.runtime != NULL) {
+ wm_xr_runtime_data_free(&wm->xr.runtime);
+ }
+ if (wm->xr.session_settings.shading.prop) {
+ IDP_FreeProperty(wm->xr.session_settings.shading.prop);
+ wm->xr.session_settings.shading.prop = NULL;
+ }
+}
+
+bool wm_xr_events_handle(wmWindowManager *wm)
+{
+ if (wm->xr.runtime && wm->xr.runtime->context) {
+ GHOST_XrEventsHandle(wm->xr.runtime->context);
+
+ /* wm_window_process_events() uses the return value to determine if it can put the main thread
+ * to sleep for some milliseconds. We never want that to happen while the VR session runs on
+ * the main thread. So always return true. */
+ return true;
+ }
+ return false;
+}
+
+/* -------------------------------------------------------------------- */
+/** \name XR Runtime Data
+ *
+ * \{ */
+
+wmXrRuntimeData *wm_xr_runtime_data_create(void)
+{
+ wmXrRuntimeData *runtime = MEM_callocN(sizeof(*runtime), __func__);
+ return runtime;
+}
+
+void wm_xr_runtime_data_free(wmXrRuntimeData **runtime)
+{
+ /* Note that this function may be called twice, because of an indirect recursion: If a session is
+ * running while WM-XR calls this function, calling GHOST_XrContextDestroy() will call this
+ * again, because it's also set as the session exit callback. So NULL-check and NULL everything
+ * that is freed here. */
+
+ /* We free all runtime XR data here, so if the context is still alive, destroy it. */
+ if ((*runtime)->context != NULL) {
+ GHOST_XrContextHandle context = (*runtime)->context;
+ /* Prevent recursive GHOST_XrContextDestroy() call by NULL'ing the context pointer before the
+ * first call, see comment above. */
+ (*runtime)->context = NULL;
+ GHOST_XrContextDestroy(context);
+ }
+ MEM_SAFE_FREE(*runtime);
+}
+
+/** \} */ /* XR Runtime Data */
diff --git a/source/blender/windowmanager/xr/intern/wm_xr_draw.c b/source/blender/windowmanager/xr/intern/wm_xr_draw.c
new file mode 100644
index 00000000000..684e59eb8b2
--- /dev/null
+++ b/source/blender/windowmanager/xr/intern/wm_xr_draw.c
@@ -0,0 +1,162 @@
+/*
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+
+/** \file
+ * \ingroup wm
+ *
+ * \name Window-Manager XR Drawing
+ *
+ * Implements Blender specific drawing functionality for use with the Ghost-XR API.
+ */
+
+#include <string.h>
+
+#include "BLI_math.h"
+
+#include "ED_view3d_offscreen.h"
+
+#include "GHOST_C-api.h"
+
+#include "GPU_viewport.h"
+
+#include "WM_api.h"
+
+#include "wm_surface.h"
+#include "wm_xr_intern.h"
+
+void wm_xr_pose_to_viewmat(const GHOST_XrPose *pose, float r_viewmat[4][4])
+{
+ float iquat[4];
+ invert_qt_qt_normalized(iquat, pose->orientation_quat);
+ quat_to_mat4(r_viewmat, iquat);
+ translate_m4(r_viewmat, -pose->position[0], -pose->position[1], -pose->position[2]);
+}
+
+static void wm_xr_draw_matrices_create(const wmXrDrawData *draw_data,
+ const GHOST_XrDrawViewInfo *draw_view,
+ const XrSessionSettings *session_settings,
+ float r_view_mat[4][4],
+ float r_proj_mat[4][4])
+{
+ GHOST_XrPose eye_pose;
+
+ copy_qt_qt(eye_pose.orientation_quat, draw_view->eye_pose.orientation_quat);
+ copy_v3_v3(eye_pose.position, draw_view->eye_pose.position);
+ add_v3_v3(eye_pose.position, draw_data->eye_position_ofs);
+ if ((session_settings->flag & XR_SESSION_USE_POSITION_TRACKING) == 0) {
+ sub_v3_v3(eye_pose.position, draw_view->local_pose.position);
+ }
+
+ perspective_m4_fov(r_proj_mat,
+ draw_view->fov.angle_left,
+ draw_view->fov.angle_right,
+ draw_view->fov.angle_up,
+ draw_view->fov.angle_down,
+ session_settings->clip_start,
+ session_settings->clip_end);
+
+ float eye_mat[4][4];
+ float base_mat[4][4];
+
+ wm_xr_pose_to_viewmat(&eye_pose, eye_mat);
+ /* Calculate the base pose matrix (in world space!). */
+ wm_xr_pose_to_viewmat(&draw_data->base_pose, base_mat);
+
+ mul_m4_m4m4(r_view_mat, eye_mat, base_mat);
+}
+
+static void wm_xr_draw_viewport_buffers_to_active_framebuffer(
+ const wmXrRuntimeData *runtime_data,
+ const wmXrSurfaceData *surface_data,
+ const GHOST_XrDrawViewInfo *draw_view)
+{
+ const bool is_upside_down = GHOST_XrSessionNeedsUpsideDownDrawing(runtime_data->context);
+ rcti rect = {.xmin = 0, .ymin = 0, .xmax = draw_view->width - 1, .ymax = draw_view->height - 1};
+
+ wmViewport(&rect);
+
+ /* For upside down contexts, draw with inverted y-values. */
+ if (is_upside_down) {
+ SWAP(int, rect.ymin, rect.ymax);
+ }
+ GPU_viewport_draw_to_screen_ex(surface_data->viewport, 0, &rect, draw_view->expects_srgb_buffer);
+}
+
+/**
+ * \brief Draw a viewport for a single eye.
+ *
+ * This is the main viewport drawing function for VR sessions. It's assigned to Ghost-XR as a
+ * callback (see GHOST_XrDrawViewFunc()) and executed for each view (read: eye).
+ */
+void wm_xr_draw_view(const GHOST_XrDrawViewInfo *draw_view, void *customdata)
+{
+ wmXrDrawData *draw_data = customdata;
+ wmXrData *xr_data = draw_data->xr_data;
+ wmXrSurfaceData *surface_data = draw_data->surface_data;
+ wmXrSessionState *session_state = &xr_data->runtime->session_state;
+ XrSessionSettings *settings = &xr_data->session_settings;
+
+ const int display_flags = V3D_OFSDRAW_OVERRIDE_SCENE_SETTINGS | settings->draw_flags;
+
+ float viewmat[4][4], winmat[4][4];
+
+ BLI_assert(WM_xr_session_is_ready(xr_data));
+
+ wm_xr_session_draw_data_update(session_state, settings, draw_view, draw_data);
+ wm_xr_draw_matrices_create(draw_data, draw_view, settings, viewmat, winmat);
+ wm_xr_session_state_update(settings, draw_data, draw_view, session_state);
+
+ if (!wm_xr_session_surface_offscreen_ensure(surface_data, draw_view)) {
+ return;
+ }
+
+ /* In case a framebuffer is still bound from drawing the last eye. */
+ GPU_framebuffer_restore();
+ /* Some systems have drawing glitches without this. */
+ GPU_clear(GPU_DEPTH_BIT);
+
+ /* Draws the view into the surface_data->viewport's framebuffers */
+ ED_view3d_draw_offscreen_simple(draw_data->depsgraph,
+ draw_data->scene,
+ &settings->shading,
+ settings->shading.type,
+ draw_view->width,
+ draw_view->height,
+ display_flags,
+ viewmat,
+ winmat,
+ settings->clip_start,
+ settings->clip_end,
+ false,
+ true,
+ true,
+ NULL,
+ false,
+ surface_data->offscreen,
+ surface_data->viewport);
+
+ /* The draw-manager uses both GPUOffscreen and GPUViewport to manage frame and texture buffers. A
+ * call to GPU_viewport_draw_to_screen() is still needed to get the final result from the
+ * viewport buffers composited together and potentially color managed for display on screen.
+ * It needs a bound frame-buffer to draw into, for which we simply reuse the GPUOffscreen one.
+ *
+ * In a next step, Ghost-XR will use the currently bound frame-buffer to retrieve the image
+ * to be submitted to the OpenXR swap-chain. So do not un-bind the off-screen yet! */
+
+ GPU_offscreen_bind(surface_data->offscreen, false);
+
+ wm_xr_draw_viewport_buffers_to_active_framebuffer(xr_data->runtime, surface_data, draw_view);
+}
diff --git a/source/blender/windowmanager/xr/intern/wm_xr_intern.h b/source/blender/windowmanager/xr/intern/wm_xr_intern.h
new file mode 100644
index 00000000000..9b7e9a15948
--- /dev/null
+++ b/source/blender/windowmanager/xr/intern/wm_xr_intern.h
@@ -0,0 +1,96 @@
+/*
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+
+/** \file
+ * \ingroup wm
+ */
+
+#ifndef __WM_XR_INTERN_H__
+#define __WM_XR_INTERN_H__
+
+#include "CLG_log.h"
+
+#include "wm_xr.h"
+
+typedef struct wmXrSessionState {
+ bool is_started;
+
+ /** Last known viewer pose (centroid of eyes, in world space) stored for queries. */
+ GHOST_XrPose viewer_pose;
+ /** The last known view matrix, calculated from above's viewer pose. */
+ float viewer_viewmat[4][4];
+ float focal_len;
+
+ /** Copy of XrSessionSettings.base_pose_ data to detect changes that need
+ * resetting to base pose. */
+ char prev_base_pose_type; /* eXRSessionBasePoseType */
+ Object *prev_base_pose_object;
+ /** Copy of XrSessionSettings.flag created on the last draw call, stored to detect changes. */
+ int prev_settings_flag;
+ /** Copy of wmXrDrawData.eye_position_ofs. */
+ float prev_eye_position_ofs[3];
+
+ bool force_reset_to_base_pose;
+ bool is_view_data_set;
+} wmXrSessionState;
+
+typedef struct wmXrRuntimeData {
+ GHOST_XrContextHandle context;
+
+ /* Although this struct is internal, RNA gets a handle to this for state information queries. */
+ wmXrSessionState session_state;
+ wmXrSessionExitFn exit_fn;
+} wmXrRuntimeData;
+
+typedef struct {
+ struct GPUOffScreen *offscreen;
+ struct GPUViewport *viewport;
+} wmXrSurfaceData;
+
+typedef struct wmXrDrawData {
+ struct Scene *scene;
+ struct Depsgraph *depsgraph;
+
+ wmXrData *xr_data;
+ wmXrSurfaceData *surface_data;
+
+ /** The pose (location + rotation) to which eye deltas will be applied to when drawing (world
+ * space). With positional tracking enabled, it should be the same as the base pose, when
+ * disabled it also contains a location delta from the moment the option was toggled. */
+ GHOST_XrPose base_pose;
+ float eye_position_ofs[3]; /* Local/view space. */
+} wmXrDrawData;
+
+wmXrRuntimeData *wm_xr_runtime_data_create(void);
+void wm_xr_runtime_data_free(wmXrRuntimeData **runtime);
+
+void wm_xr_session_draw_data_update(const wmXrSessionState *state,
+ const XrSessionSettings *settings,
+ const GHOST_XrDrawViewInfo *draw_view,
+ wmXrDrawData *draw_data);
+void wm_xr_session_state_update(const XrSessionSettings *settings,
+ const wmXrDrawData *draw_data,
+ const GHOST_XrDrawViewInfo *draw_view,
+ wmXrSessionState *state);
+bool wm_xr_session_surface_offscreen_ensure(wmXrSurfaceData *surface_data,
+ const GHOST_XrDrawViewInfo *draw_view);
+void *wm_xr_session_gpu_binding_context_create(void);
+void wm_xr_session_gpu_binding_context_destroy(GHOST_ContextHandle context);
+
+void wm_xr_pose_to_viewmat(const GHOST_XrPose *pose, float r_viewmat[4][4]);
+void wm_xr_draw_view(const GHOST_XrDrawViewInfo *draw_view, void *customdata);
+
+#endif
diff --git a/source/blender/windowmanager/xr/intern/wm_xr_session.c b/source/blender/windowmanager/xr/intern/wm_xr_session.c
new file mode 100644
index 00000000000..e9ff38c5a92
--- /dev/null
+++ b/source/blender/windowmanager/xr/intern/wm_xr_session.c
@@ -0,0 +1,430 @@
+/*
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+
+/** \file
+ * \ingroup wm
+ */
+
+#include "BKE_context.h"
+
+#include "BLI_math.h"
+
+#include "DEG_depsgraph.h"
+
+#include "DNA_camera_types.h"
+
+#include "DRW_engine.h"
+
+#include "GHOST_C-api.h"
+
+#include "GPU_viewport.h"
+
+#include "MEM_guardedalloc.h"
+
+#include "WM_api.h"
+#include "WM_types.h"
+
+#include "wm_surface.h"
+#include "wm_window.h"
+#include "wm_xr_intern.h"
+
+wmSurface *g_xr_surface = NULL;
+CLG_LogRef LOG = {"wm.xr"};
+
+/* -------------------------------------------------------------------- */
+
+static void wm_xr_session_exit_cb(void *customdata)
+{
+ wmXrData *xr_data = customdata;
+
+ xr_data->runtime->session_state.is_started = false;
+ if (xr_data->runtime->exit_fn) {
+ xr_data->runtime->exit_fn(xr_data);
+ }
+
+ /* Free the entire runtime data (including session state and context), to play safe. */
+ wm_xr_runtime_data_free(&xr_data->runtime);
+}
+
+static void wm_xr_session_begin_info_create(wmXrData *xr_data,
+ GHOST_XrSessionBeginInfo *r_begin_info)
+{
+ /* WM-XR exit function, does some own stuff and calls callback passed to wm_xr_session_toggle(),
+ * to allow external code to execute its own session-exit logic. */
+ r_begin_info->exit_fn = wm_xr_session_exit_cb;
+ r_begin_info->exit_customdata = xr_data;
+}
+
+void wm_xr_session_toggle(wmWindowManager *wm, wmXrSessionExitFn session_exit_fn)
+{
+ wmXrData *xr_data = &wm->xr;
+
+ if (WM_xr_session_exists(xr_data)) {
+ GHOST_XrSessionEnd(xr_data->runtime->context);
+ }
+ else {
+ GHOST_XrSessionBeginInfo begin_info;
+
+ xr_data->runtime->session_state.is_started = true;
+ xr_data->runtime->exit_fn = session_exit_fn;
+
+ wm_xr_session_begin_info_create(xr_data, &begin_info);
+ GHOST_XrSessionStart(xr_data->runtime->context, &begin_info);
+ }
+}
+
+/**
+ * Check if the XR-Session was triggered.
+ * If an error happened while trying to start a session, this returns false too.
+ */
+bool WM_xr_session_exists(const wmXrData *xr)
+{
+ return xr->runtime && xr->runtime->context && xr->runtime->session_state.is_started;
+}
+
+void WM_xr_session_base_pose_reset(wmXrData *xr)
+{
+ xr->runtime->session_state.force_reset_to_base_pose = true;
+}
+
+/**
+ * Check if the session is running, according to the OpenXR definition.
+ */
+bool WM_xr_session_is_ready(const wmXrData *xr)
+{
+ return WM_xr_session_exists(xr) && GHOST_XrSessionIsRunning(xr->runtime->context);
+}
+
+static void wm_xr_session_base_pose_calc(const Scene *scene,
+ const XrSessionSettings *settings,
+ GHOST_XrPose *r_base_pose)
+{
+ const Object *base_pose_object = ((settings->base_pose_type == XR_BASE_POSE_OBJECT) &&
+ settings->base_pose_object) ?
+ settings->base_pose_object :
+ scene->camera;
+
+ if (settings->base_pose_type == XR_BASE_POSE_CUSTOM) {
+ float tmp_quatx[4], tmp_quatz[4];
+
+ copy_v3_v3(r_base_pose->position, settings->base_pose_location);
+ axis_angle_to_quat_single(tmp_quatx, 'X', M_PI_2);
+ axis_angle_to_quat_single(tmp_quatz, 'Z', settings->base_pose_angle);
+ mul_qt_qtqt(r_base_pose->orientation_quat, tmp_quatz, tmp_quatx);
+ }
+ else if (base_pose_object) {
+ float tmp_quat[4];
+ float tmp_eul[3];
+
+ mat4_to_loc_quat(r_base_pose->position, tmp_quat, base_pose_object->obmat);
+
+ /* Only use rotation around Z-axis to align view with floor. */
+ quat_to_eul(tmp_eul, tmp_quat);
+ tmp_eul[0] = M_PI_2;
+ tmp_eul[1] = 0;
+ eul_to_quat(r_base_pose->orientation_quat, tmp_eul);
+ }
+ else {
+ copy_v3_fl(r_base_pose->position, 0.0f);
+ axis_angle_to_quat_single(r_base_pose->orientation_quat, 'X', M_PI_2);
+ }
+}
+
+static void wm_xr_session_draw_data_populate(wmXrData *xr_data,
+ Scene *scene,
+ Depsgraph *depsgraph,
+ wmXrDrawData *r_draw_data)
+{
+ const XrSessionSettings *settings = &xr_data->session_settings;
+
+ memset(r_draw_data, 0, sizeof(*r_draw_data));
+ r_draw_data->scene = scene;
+ r_draw_data->depsgraph = depsgraph;
+ r_draw_data->xr_data = xr_data;
+ r_draw_data->surface_data = g_xr_surface->customdata;
+
+ wm_xr_session_base_pose_calc(r_draw_data->scene, settings, &r_draw_data->base_pose);
+}
+
+static bool wm_xr_session_draw_data_needs_reset_to_base_pose(const wmXrSessionState *state,
+ const XrSessionSettings *settings)
+{
+ if (state->force_reset_to_base_pose) {
+ return true;
+ }
+ return ((settings->flag & XR_SESSION_USE_POSITION_TRACKING) == 0) &&
+ ((state->prev_base_pose_type != settings->base_pose_type) ||
+ (state->prev_base_pose_object != settings->base_pose_object));
+}
+
+void wm_xr_session_draw_data_update(const wmXrSessionState *state,
+ const XrSessionSettings *settings,
+ const GHOST_XrDrawViewInfo *draw_view,
+ wmXrDrawData *draw_data)
+{
+ const bool position_tracking_toggled = ((state->prev_settings_flag &
+ XR_SESSION_USE_POSITION_TRACKING) !=
+ (settings->flag & XR_SESSION_USE_POSITION_TRACKING));
+ const bool use_position_tracking = settings->flag & XR_SESSION_USE_POSITION_TRACKING;
+
+ /* Set the eye position offset, it's used to offset the base pose when changing positional
+ * tracking. */
+ if (!state->is_view_data_set ||
+ wm_xr_session_draw_data_needs_reset_to_base_pose(state, settings)) {
+ /* Always use the exact base pose with no offset when starting the session. */
+ copy_v3_fl(draw_data->eye_position_ofs, 0.0f);
+ }
+ else if (position_tracking_toggled) {
+ if (use_position_tracking) {
+ copy_v3_fl(draw_data->eye_position_ofs, 0.0f);
+ }
+ else {
+ /* Store the current local offset (local pose) so that we can apply that to the eyes. This
+ * way the eyes stay exactly where they are when disabling positional tracking. */
+ copy_v3_v3(draw_data->eye_position_ofs, draw_view->local_pose.position);
+ }
+ }
+ else if (!use_position_tracking) {
+ /* Keep previous offset when positional tracking is disabled. */
+ copy_v3_v3(draw_data->eye_position_ofs, state->prev_eye_position_ofs);
+ }
+}
+
+/**
+ * Update information that is only stored for external state queries. E.g. for Python API to
+ * request the current (as in, last known) viewer pose.
+ */
+void wm_xr_session_state_update(const XrSessionSettings *settings,
+ const wmXrDrawData *draw_data,
+ const GHOST_XrDrawViewInfo *draw_view,
+ wmXrSessionState *state)
+{
+ GHOST_XrPose viewer_pose;
+ const bool use_position_tracking = settings->flag & XR_SESSION_USE_POSITION_TRACKING;
+
+ mul_qt_qtqt(viewer_pose.orientation_quat,
+ draw_data->base_pose.orientation_quat,
+ draw_view->local_pose.orientation_quat);
+ copy_v3_v3(viewer_pose.position, draw_data->base_pose.position);
+ /* The local pose and the eye pose (which is copied from an earlier local pose) both are view
+ * space, so Y-up. In this case we need them in regular Z-up. */
+ viewer_pose.position[0] += draw_data->eye_position_ofs[0];
+ viewer_pose.position[1] -= draw_data->eye_position_ofs[2];
+ viewer_pose.position[2] += draw_data->eye_position_ofs[1];
+ if (use_position_tracking) {
+ viewer_pose.position[0] += draw_view->local_pose.position[0];
+ viewer_pose.position[1] -= draw_view->local_pose.position[2];
+ viewer_pose.position[2] += draw_view->local_pose.position[1];
+ }
+
+ copy_v3_v3(state->viewer_pose.position, viewer_pose.position);
+ copy_qt_qt(state->viewer_pose.orientation_quat, viewer_pose.orientation_quat);
+ wm_xr_pose_to_viewmat(&viewer_pose, state->viewer_viewmat);
+ /* No idea why, but multiplying by two seems to make it match the VR view more. */
+ state->focal_len = 2.0f *
+ fov_to_focallength(draw_view->fov.angle_right - draw_view->fov.angle_left,
+ DEFAULT_SENSOR_WIDTH);
+
+ copy_v3_v3(state->prev_eye_position_ofs, draw_data->eye_position_ofs);
+ state->prev_settings_flag = settings->flag;
+ state->prev_base_pose_type = settings->base_pose_type;
+ state->prev_base_pose_object = settings->base_pose_object;
+ state->is_view_data_set = true;
+}
+
+wmXrSessionState *WM_xr_session_state_handle_get(const wmXrData *xr)
+{
+ return xr->runtime ? &xr->runtime->session_state : NULL;
+}
+
+bool WM_xr_session_state_viewer_pose_location_get(const wmXrData *xr, float r_location[3])
+{
+ if (!WM_xr_session_is_ready(xr) || !xr->runtime->session_state.is_view_data_set) {
+ zero_v3(r_location);
+ return false;
+ }
+
+ copy_v3_v3(r_location, xr->runtime->session_state.viewer_pose.position);
+ return true;
+}
+
+bool WM_xr_session_state_viewer_pose_rotation_get(const wmXrData *xr, float r_rotation[4])
+{
+ if (!WM_xr_session_is_ready(xr) || !xr->runtime->session_state.is_view_data_set) {
+ unit_qt(r_rotation);
+ return false;
+ }
+
+ copy_v4_v4(r_rotation, xr->runtime->session_state.viewer_pose.orientation_quat);
+ return true;
+}
+
+bool WM_xr_session_state_viewer_pose_matrix_info_get(const wmXrData *xr,
+ float r_viewmat[4][4],
+ float *r_focal_len)
+{
+ if (!WM_xr_session_is_ready(xr) || !xr->runtime->session_state.is_view_data_set) {
+ unit_m4(r_viewmat);
+ *r_focal_len = 0.0f;
+ return false;
+ }
+
+ copy_m4_m4(r_viewmat, xr->runtime->session_state.viewer_viewmat);
+ *r_focal_len = xr->runtime->session_state.focal_len;
+
+ return true;
+}
+
+/* -------------------------------------------------------------------- */
+/** \name XR-Session Surface
+ *
+ * A wmSurface is used to manage drawing of the VR viewport. It's created and destroyed with the
+ * session.
+ *
+ * \{ */
+
+/**
+ * \brief Call Ghost-XR to draw a frame
+ *
+ * Draw callback for the XR-session surface. It's expected to be called on each main loop iteration
+ * and tells Ghost-XR to submit a new frame by drawing its views. Note that for drawing each view,
+ * #wm_xr_draw_view() will be called through Ghost-XR (see GHOST_XrDrawViewFunc()).
+ */
+static void wm_xr_session_surface_draw(bContext *C)
+{
+ wmXrSurfaceData *surface_data = g_xr_surface->customdata;
+ wmWindowManager *wm = CTX_wm_manager(C);
+ wmXrDrawData draw_data;
+
+ if (!GHOST_XrSessionIsRunning(wm->xr.runtime->context)) {
+ return;
+ }
+ wm_xr_session_draw_data_populate(
+ &wm->xr, CTX_data_scene(C), CTX_data_ensure_evaluated_depsgraph(C), &draw_data);
+
+ DRW_xr_drawing_begin();
+
+ GHOST_XrSessionDrawViews(wm->xr.runtime->context, &draw_data);
+
+ GPU_offscreen_unbind(surface_data->offscreen, false);
+ DRW_xr_drawing_end();
+}
+
+bool wm_xr_session_surface_offscreen_ensure(wmXrSurfaceData *surface_data,
+ const GHOST_XrDrawViewInfo *draw_view)
+{
+ const bool size_changed = surface_data->offscreen &&
+ (GPU_offscreen_width(surface_data->offscreen) != draw_view->width) &&
+ (GPU_offscreen_height(surface_data->offscreen) != draw_view->height);
+ char err_out[256] = "unknown";
+ bool failure = false;
+
+ if (surface_data->offscreen) {
+ BLI_assert(surface_data->viewport);
+
+ if (!size_changed) {
+ return true;
+ }
+ GPU_viewport_free(surface_data->viewport);
+ GPU_offscreen_free(surface_data->offscreen);
+ }
+
+ if (!(surface_data->offscreen = GPU_offscreen_create(
+ draw_view->width, draw_view->height, 0, true, false, err_out))) {
+ failure = true;
+ }
+
+ if (failure) {
+ /* Pass. */
+ }
+ else if (!(surface_data->viewport = GPU_viewport_create())) {
+ GPU_offscreen_free(surface_data->offscreen);
+ failure = true;
+ }
+
+ if (failure) {
+ CLOG_ERROR(&LOG, "Failed to get buffer, %s\n", err_out);
+ return false;
+ }
+
+ return true;
+}
+
+static void wm_xr_session_surface_free_data(wmSurface *surface)
+{
+ wmXrSurfaceData *data = surface->customdata;
+
+ if (data->viewport) {
+ GPU_viewport_free(data->viewport);
+ }
+ if (data->offscreen) {
+ GPU_offscreen_free(data->offscreen);
+ }
+
+ MEM_freeN(surface->customdata);
+
+ g_xr_surface = NULL;
+}
+
+static wmSurface *wm_xr_session_surface_create(void)
+{
+ if (g_xr_surface) {
+ BLI_assert(false);
+ return g_xr_surface;
+ }
+
+ wmSurface *surface = MEM_callocN(sizeof(*surface), __func__);
+ wmXrSurfaceData *data = MEM_callocN(sizeof(*data), "XrSurfaceData");
+
+ surface->draw = wm_xr_session_surface_draw;
+ surface->free_data = wm_xr_session_surface_free_data;
+ surface->ghost_ctx = DRW_xr_opengl_context_get();
+ surface->gpu_ctx = DRW_xr_gpu_context_get();
+
+ surface->customdata = data;
+
+ g_xr_surface = surface;
+
+ return surface;
+}
+
+void *wm_xr_session_gpu_binding_context_create(void)
+{
+ wmSurface *surface = wm_xr_session_surface_create();
+
+ wm_surface_add(surface);
+
+ /* Some regions may need to redraw with updated session state after the session is entirely up
+ * and running. */
+ WM_main_add_notifier(NC_WM | ND_XR_DATA_CHANGED, NULL);
+
+ return surface->ghost_ctx;
+}
+
+void wm_xr_session_gpu_binding_context_destroy(GHOST_ContextHandle UNUSED(context))
+{
+ if (g_xr_surface) { /* Might have been freed already */
+ wm_surface_remove(g_xr_surface);
+ }
+
+ wm_window_reset_drawable();
+
+ /* Some regions may need to redraw with updated session state after the session is entirely
+ * stopped. */
+ WM_main_add_notifier(NC_WM | ND_XR_DATA_CHANGED, NULL);
+}
+
+/** \} */ /* XR-Session Surface */
diff --git a/source/blender/windowmanager/xr/wm_xr.h b/source/blender/windowmanager/xr/wm_xr.h
new file mode 100644
index 00000000000..33f79bc75b2
--- /dev/null
+++ b/source/blender/windowmanager/xr/wm_xr.h
@@ -0,0 +1,35 @@
+/*
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+
+/** \file
+ * \ingroup wm
+ */
+
+#ifndef __WM_XR_H__
+#define __WM_XR_H__
+
+struct wmWindowManager;
+struct wmXrData;
+
+typedef void (*wmXrSessionExitFn)(const wmXrData *xr_data);
+
+/* wm_xr.c */
+bool wm_xr_init(wmWindowManager *wm);
+void wm_xr_exit(wmWindowManager *wm);
+void wm_xr_session_toggle(wmWindowManager *wm, wmXrSessionExitFn session_exit_fn);
+bool wm_xr_events_handle(wmWindowManager *wm);
+
+#endif
diff --git a/source/creator/CMakeLists.txt b/source/creator/CMakeLists.txt
index ced0532a8fa..aed2a9350bb 100644
--- a/source/creator/CMakeLists.txt
+++ b/source/creator/CMakeLists.txt
@@ -687,6 +687,24 @@ elseif(WIN32)
)
endif()
+ if(WITH_FFTW3)
+ install(
+ FILES ${LIBDIR}/fftw3/lib/libfftw3-3.dll
+ DESTINATION "."
+ )
+ endif()
+
+ if(WITH_WINDOWS_PDB)
+ if(WITH_WINDOWS_STRIPPED_PDB)
+ # Icky hack for older cmake from https://stackoverflow.com/a/21198501
+ # $<CONFIG> will work in newer cmake but the version currently (3.12)
+ # on the buildbot does not support this endavour.
+ install(FILES ${CMAKE_CURRENT_BINARY_DIR}/\${CMAKE_INSTALL_CONFIG_NAME}/blender_public.pdb DESTINATION . RENAME blender.pdb)
+ else()
+ install(FILES $<TARGET_PDB_FILE:blender> DESTINATION . RENAME blender.pdb)
+ endif()
+ endif()
+
if(WITH_PYTHON)
string(REPLACE "." "" _PYTHON_VERSION_NO_DOTS ${PYTHON_VERSION})
@@ -803,7 +821,20 @@ elseif(WIN32)
DESTINATION "."
)
endif()
-
+ if(WITH_TBB)
+ install(
+ FILES
+ ${LIBDIR}/tbb/lib/tbb.dll
+ DESTINATION "."
+ CONFIGURATIONS Release;RelWithDebInfo;MinSizeRel
+ )
+ install(
+ FILES
+ ${LIBDIR}/tbb/lib/debug/tbb_debug.dll
+ DESTINATION "."
+ CONFIGURATIONS Debug
+ )
+ endif()
if(WITH_TBB_MALLOC_PROXY)
install(
FILES
@@ -912,8 +943,8 @@ elseif(APPLE)
set_target_properties(blender PROPERTIES
MACOSX_BUNDLE_INFO_PLIST ${OSX_APP_SOURCEDIR}/Contents/Info.plist
- MACOSX_BUNDLE_SHORT_VERSION_STRING "${BLENDER_VERSION}${BLENDER_VERSION_CHAR}"
- MACOSX_BUNDLE_LONG_VERSION_STRING "${BLENDER_VERSION}${BLENDER_VERSION_CHAR} ${BLENDER_DATE}")
+ MACOSX_BUNDLE_SHORT_VERSION_STRING "${BLENDER_VERSION}.${BLENDER_VERSION_PATCH}"
+ MACOSX_BUNDLE_LONG_VERSION_STRING "${BLENDER_VERSION}.${BLENDER_VERSION_PATCH} ${BLENDER_DATE}")
# Gather the date in finder-style
execute_process(COMMAND date "+%m/%d/%Y/%H:%M"
@@ -1061,6 +1092,12 @@ unset(LIB)
setup_liblinks(blender)
+if(APPLE)
+ set_target_properties(blender PROPERTIES LINK_DEPENDS ${CMAKE_CURRENT_SOURCE_DIR}/osx_locals.map)
+elseif(UNIX)
+ set_target_properties(blender PROPERTIES LINK_DEPENDS ${CMAKE_CURRENT_SOURCE_DIR}/blender.map)
+endif()
+
# -----------------------------------------------------------------------------
# USD registry.
# USD requires a set of JSON files that define the standard schemas. These
@@ -1079,6 +1116,20 @@ endif()
# the use of vcpkg
if(WIN32)
set_target_properties(blender PROPERTIES VS_GLOBAL_VcpkgEnabled "false")
+ set_target_properties(blender PROPERTIES
+ PDB_NAME "blender_private"
+ PDB_OUTPUT_DIRECTORY "${CMAKE_CURRENT_BINARY_DIR}/$<CONFIG>")
+ if (WITH_WINDOWS_PDB AND WITH_WINDOWS_STRIPPED_PDB)
+ # This is slightly messy, but single target generators like ninja will not have the
+ # CMAKE_CFG_INTDIR variable and multitarget generators like msbuild will not have
+ # CMAKE_BUILD_TYPE. This can be simplified by target_link_options and the $<CONFIG>
+ # generator expression in newer cmake (2.13+) but until that time this fill have suffice.
+ if(CMAKE_BUILD_TYPE)
+ set_property(TARGET blender APPEND PROPERTY LINK_FLAGS " /PDBSTRIPPED:${CMAKE_CURRENT_BINARY_DIR}/${CMAKE_BUILD_TYPE}/blender_public.pdb")
+ else()
+ set_property(TARGET blender APPEND PROPERTY LINK_FLAGS " /PDBSTRIPPED:${CMAKE_CURRENT_BINARY_DIR}/${CMAKE_CFG_INTDIR}/blender_public.pdb")
+ endif()
+ endif()
endif()
# -----------------------------------------------------------------------------
diff --git a/source/creator/blender.map b/source/creator/blender.map
index 4c34dea3338..5171e94382d 100644
--- a/source/creator/blender.map
+++ b/source/creator/blender.map
@@ -6,21 +6,108 @@
{
global:
- *;
- *_boost*;
+ *;
+ *_boost*;
local:
- *default_error_condition*;
- *llvm*;
- *LLVM*;
- decodeInstruction;
- ForceStackAlign;
- _Jv_RegisterClasses;
- Name;
- NumNamedVarArgParams;
- X86CompilationCallback*;
- *boost*;
- *SDL*;
- *embree*;
- cu*;
-};
+ al*;
+ *Alembic*;
+ av*;
+ blosc*;
+ *boost*;
+ *ceres*;
+ *cineon*;
+ *COLLADA*;
+ cu*;
+ *default_error_condition*;
+ *dpx*;
+ *embree*;
+ ff_*;
+ fftw*;
+ FLAC*;
+ FT_*;
+ *GeneratedSaxParser*;
+ *google*;
+ gsm*;
+ Gsm*;
+ html*;
+ id3tag*;
+ *Iex*;
+ *Ilm*;
+ *Imath*;
+ *Imf*;
+ jack_*;
+ jpeg_*;
+ jsimd**;
+ lame_*;
+ *llvm*;
+ *LLVM*;
+ *MathML*;
+ *mkldnn*;
+ nvrtc*;
+ oc_*;
+ ogg*;
+ *oidn*;
+ *OpenColorIO*;
+ *OpenImageIO*;
+ *OpenSubdiv*;
+ *openvdb*;
+ opj_*;
+ opus_*;
+ *OSL*;
+ *pathYy*;
+ png_*;
+ *SDL*;
+ *squish*;
+ *tbb*;
+ *textFileFormatYy*;
+ *TIFF*;
+ *tinyformat*;
+ *usdBlender*;
+ vorbis*;
+ vp8*;
+ vp9*;
+ vpx*;
+ x264_*;
+ xml*;
+ xvid*;
+ *YAML*;
+ /* LLVM symbols not in the LLVM namespace that can conflict with LLVM usage
+ * in OpenGL and OpenCL drivers. */
+ decodeInstruction;
+ EnableHotColdSplit;
+ EnableIPRA;
+ EnableOrderFileInstrumentation;
+ EnableVPlanNativePath;
+ EnableVPlanPredication;
+ FlattenedProfileUsed;
+ ForceStackAlign;
+ ForceSummaryEdgesCold;
+ FSEC;
+ __jit_debug_descriptor;
+ __jit_debug_register_code;
+ _Jv_RegisterClasses;
+ MachineRegionInfoPassID;
+ MemOPSizeLarge;
+ MemOPSizeRange;
+ MISchedPostRA;
+ ModuleSummaryDotFile;
+ __morestack;
+ Name;
+ NumNamedVarArgParams;
+ PGOViewCounts;
+ PrintBlockFreqFuncName;
+ PrintBranchProbFuncName;
+ ProfileLikelyProb;
+ StartAfterOptName;
+ StartBeforeOptName;
+ StaticLikelyProb;
+ StopAfterOptName;
+ StopBeforeOptName;
+ UseDbgAddr;
+ ViewBlockFreqFuncName;
+ ViewBlockLayoutWithBFI;
+ ViewHotFreqPercent;
+ WriteRelBFToSummary;
+ X86CompilationCallback*;
+};
diff --git a/source/creator/creator.c b/source/creator/creator.c
index a6c0e50e527..ea64184c826 100644
--- a/source/creator/creator.c
+++ b/source/creator/creator.c
@@ -43,6 +43,7 @@
#include "BLI_args.h"
#include "BLI_string.h"
#include "BLI_system.h"
+#include "BLI_task.h"
#include "BLI_threads.h"
#include "BLI_utildefines.h"
@@ -108,7 +109,7 @@
#include "creator_intern.h" /* own include */
-/* Local Function prototypes */
+/* Local Function prototypes. */
#ifdef WITH_PYTHON_MODULE
int main_python_enter(int argc, const char **argv);
void main_python_exit(void);
@@ -339,7 +340,7 @@ int main(int argc,
main_callback_setup();
-#if defined(__APPLE__) && !defined(WITH_PYTHON_MODULE)
+#if defined(__APPLE__) && !defined(WITH_PYTHON_MODULE) && !defined(WITH_HEADLESS)
/* patch to ignore argument finder gives us (pid?) */
if (argc == 2 && STREQLEN(argv[1], "-psn_", 5)) {
extern int GHOST_HACK_getFirstFile(char buf[]);
@@ -401,6 +402,9 @@ int main(int argc,
G.factory_startup = true;
#endif
+ /* After parsing number of threads argument. */
+ BLI_task_scheduler_init();
+
#ifdef WITH_FFMPEG
IMB_ffmpeg_init();
#endif
diff --git a/source/creator/creator_args.c b/source/creator/creator_args.c
index 7b5a448fc53..a2389b02d8f 100644
--- a/source/creator/creator_args.c
+++ b/source/creator/creator_args.c
@@ -460,7 +460,7 @@ static void arg_py_context_restore(bContext *C, struct BlendePyContextStore *c_p
static void print_version_full(void)
{
- printf(BLEND_VERSION_STRING_FMT);
+ printf("Blender %s\n", BKE_blender_version_string());
# ifdef BUILD_DATE
printf("\tbuild date: %s\n", build_date);
printf("\tbuild time: %s\n", build_time);
@@ -481,13 +481,13 @@ static void print_version_short(void)
# ifdef BUILD_DATE
/* NOTE: We include built time since sometimes we need to tell broken from
* working built of the same hash. */
- printf(BLEND_VERSION_FMT " (hash %s built %s %s)\n",
- BLEND_VERSION_ARG,
+ printf("Blender %s (hash %s built %s %s)\n",
+ BKE_blender_version_string(),
build_hash,
build_date,
build_time);
# else
- printf(BLEND_VERSION_STRING_FMT);
+ printf("Blender %s\n", BKE_blender_version_string());
# endif
}
@@ -513,7 +513,7 @@ static int arg_handle_print_help(int UNUSED(argc), const char **UNUSED(argv), vo
{
bArgs *ba = (bArgs *)data;
- printf(BLEND_VERSION_STRING_FMT);
+ printf("Blender %s\n", BKE_blender_version_string());
printf("Usage: blender [args ...] [file] [args ...]\n\n");
printf("Render Options:\n");
@@ -619,7 +619,7 @@ static int arg_handle_print_help(int UNUSED(argc), const char **UNUSED(argv), vo
printf("Misc Options:\n");
BLI_argsPrintArgDoc(ba, "--app-template");
BLI_argsPrintArgDoc(ba, "--factory-startup");
- BLI_argsPrintArgDoc(ba, "--enable-library-override");
+ BLI_argsPrintArgDoc(ba, "--disable-library-override");
BLI_argsPrintArgDoc(ba, "--enable-event-simulate");
printf("\n");
BLI_argsPrintArgDoc(ba, "--env-system-datafiles");
@@ -907,7 +907,7 @@ static const char arg_handle_debug_mode_set_doc[] =
static int arg_handle_debug_mode_set(int UNUSED(argc), const char **UNUSED(argv), void *data)
{
G.debug |= G_DEBUG; /* std output printf's */
- printf(BLEND_VERSION_STRING_FMT);
+ printf("Blender %s\n", BKE_blender_version_string());
MEM_set_memory_debug();
# ifndef NDEBUG
BLI_mempool_set_memory_debug();
@@ -959,7 +959,7 @@ static const char arg_handle_debug_mode_generic_set_doc_jobs[] =
"Enable time profiling for background jobs.";
static const char arg_handle_debug_mode_generic_set_doc_gpu[] =
"\n\t"
- "Enable gpu debug context and information for OpenGL 4.3+.";
+ "Enable GPU debug context and information for OpenGL 4.3+.";
static const char arg_handle_debug_mode_generic_set_doc_depsgraph[] =
"\n\t"
"Enable all debug messages from dependency graph.";
@@ -995,7 +995,7 @@ static int arg_handle_debug_mode_generic_set(int UNUSED(argc),
static const char arg_handle_debug_mode_io_doc[] =
"\n\t"
- "Enable debug messages for I/O (collada, ...).";
+ "Enable debug messages for I/O (Collada, ...).";
static int arg_handle_debug_mode_io(int UNUSED(argc),
const char **UNUSED(argv),
void *UNUSED(data))
@@ -1124,7 +1124,7 @@ static int arg_handle_factory_startup_set(int UNUSED(argc),
static const char arg_handle_disable_override_library_doc[] =
"\n\t"
- "Enable Library Override features in the UI.";
+ "Disable Library Override features in the UI.";
static int arg_handle_disable_override_library(int UNUSED(argc),
const char **UNUSED(argv),
void *UNUSED(data))
@@ -1369,6 +1369,7 @@ static int arg_handle_output_set(int argc, const char **argv, void *data)
Scene *scene = CTX_data_scene(C);
if (scene) {
BLI_strncpy(scene->r.pic, argv[1], sizeof(scene->r.pic));
+ DEG_id_tag_update(&scene->id, ID_RECALC_COPY_ON_WRITE);
}
else {
printf("\nError: no blend loaded. cannot use '-o / --render-output'.\n");
@@ -1402,6 +1403,7 @@ static int arg_handle_engine_set(int argc, const char **argv, void *data)
if (scene) {
if (BLI_findstring(&R_engines, argv[1], offsetof(RenderEngineType, idname))) {
BLI_strncpy_utf8(scene->r.engine, argv[1], sizeof(scene->r.engine));
+ DEG_id_tag_update(&scene->id, ID_RECALC_COPY_ON_WRITE);
}
else {
printf("\nError: engine not found '%s'\n", argv[1]);
@@ -1447,6 +1449,7 @@ static int arg_handle_image_type_set(int argc, const char **argv, void *data)
}
else {
scene->r.im_format.imtype = imtype_new;
+ DEG_id_tag_update(&scene->id, ID_RECALC_COPY_ON_WRITE);
}
}
else {
@@ -1494,7 +1497,7 @@ static int arg_handle_threads_set(int argc, const char **argv, void *UNUSED(data
static const char arg_handle_verbosity_set_doc[] =
"<verbose>\n"
- "\tSet logging verbosity level for debug messages which supports it.";
+ "\tSet the logging verbosity level for debug messages that support it.";
static int arg_handle_verbosity_set(int argc, const char **argv, void *UNUSED(data))
{
const char *arg_id = "--verbose";
@@ -1532,9 +1535,11 @@ static int arg_handle_extension_set(int argc, const char **argv, void *data)
if (scene) {
if (argv[1][0] == '0') {
scene->r.scemode &= ~R_EXTENSION;
+ DEG_id_tag_update(&scene->id, ID_RECALC_COPY_ON_WRITE);
}
else if (argv[1][0] == '1') {
scene->r.scemode |= R_EXTENSION;
+ DEG_id_tag_update(&scene->id, ID_RECALC_COPY_ON_WRITE);
}
else {
printf("\nError: Use '-x 1 / -x 0' To set the extension option or '--use-extension'\n");
@@ -1587,7 +1592,6 @@ static int arg_handle_render_frame(int argc, const char **argv, void *data)
}
re = RE_NewSceneRender(scene);
- BLI_threaded_malloc_begin();
BKE_reports_init(&reports, RPT_STORE);
RE_SetReports(re, &reports);
for (int i = 0; i < frames_range_len; i++) {
@@ -1603,7 +1607,6 @@ static int arg_handle_render_frame(int argc, const char **argv, void *data)
}
RE_SetReports(re, NULL);
BKE_reports_clear(&reports);
- BLI_threaded_malloc_end();
MEM_freeN(frame_range_arr);
return 1;
}
@@ -1629,13 +1632,11 @@ static int arg_handle_render_animation(int UNUSED(argc), const char **UNUSED(arg
Main *bmain = CTX_data_main(C);
Render *re = RE_NewSceneRender(scene);
ReportList reports;
- BLI_threaded_malloc_begin();
BKE_reports_init(&reports, RPT_STORE);
RE_SetReports(re, &reports);
RE_RenderAnim(re, bmain, scene, NULL, NULL, scene->r.sfra, scene->r.efra, scene->r.frame_step);
RE_SetReports(re, NULL);
BKE_reports_clear(&reports);
- BLI_threaded_malloc_end();
}
else {
printf("\nError: no blend loaded. cannot use '-a'.\n");
@@ -1693,6 +1694,9 @@ static int arg_handle_frame_start_set(int argc, const char **argv, void *data)
&err_msg)) {
printf("\nError: %s '%s %s'.\n", err_msg, arg_id, argv[1]);
}
+ else {
+ DEG_id_tag_update(&scene->id, ID_RECALC_COPY_ON_WRITE);
+ }
return 1;
}
else {
@@ -1727,6 +1731,9 @@ static int arg_handle_frame_end_set(int argc, const char **argv, void *data)
&err_msg)) {
printf("\nError: %s '%s %s'.\n", err_msg, arg_id, argv[1]);
}
+ else {
+ DEG_id_tag_update(&scene->id, ID_RECALC_COPY_ON_WRITE);
+ }
return 1;
}
else {
@@ -1754,6 +1761,9 @@ static int arg_handle_frame_skip_set(int argc, const char **argv, void *data)
if (!parse_int_clamp(argv[1], NULL, 1, MAXFRAME, &scene->r.frame_step, &err_msg)) {
printf("\nError: %s '%s %s'.\n", err_msg, arg_id, argv[1]);
}
+ else {
+ DEG_id_tag_update(&scene->id, ID_RECALC_COPY_ON_WRITE);
+ }
return 1;
}
else {
@@ -1780,7 +1790,7 @@ static int arg_handle_python_file_run(int argc, const char **argv, void *data)
/* Make the path absolute because its needed for relative linked blends to be found */
char filename[FILE_MAX];
BLI_strncpy(filename, argv[1], sizeof(filename));
- BLI_path_cwd(filename, sizeof(filename));
+ BLI_path_abs_from_cwd(filename, sizeof(filename));
bool ok;
BPY_CTX_SETUP(ok = BPY_execute_filepath(C, filename, NULL));
@@ -1924,12 +1934,15 @@ static int arg_handle_python_exit_code_set(int argc, const char **argv, void *UN
static const char arg_handle_python_use_system_env_set_doc[] =
"\n\t"
- "Allow Python to use system environment variables such as 'PYTHONPATH'.";
+ "Allow Python to use system environment variables such as 'PYTHONPATH' and the user "
+ "site-packages directory.";
static int arg_handle_python_use_system_env_set(int UNUSED(argc),
const char **UNUSED(argv),
void *UNUSED(data))
{
+# ifdef WITH_PYTHON
BPY_python_use_system_env();
+# endif
return 0;
}
@@ -1980,7 +1993,7 @@ static int arg_handle_load_file(int UNUSED(argc), const char **argv, void *data)
}
BLI_strncpy(filename, argv[0], sizeof(filename));
- BLI_path_cwd(filename, sizeof(filename));
+ BLI_path_abs_from_cwd(filename, sizeof(filename));
/* load the file */
BKE_reports_init(&reports, RPT_PRINT);
diff --git a/source/creator/creator_intern.h b/source/creator/creator_intern.h
index 959fb71d218..9c7d3d95498 100644
--- a/source/creator/creator_intern.h
+++ b/source/creator/creator_intern.h
@@ -55,10 +55,8 @@ extern struct ApplicationState app_state; /* creator.c */
/* for the callbacks: */
#ifndef WITH_PYTHON_MODULE
-# define BLEND_VERSION_FMT "Blender %d.%02d (sub %d)"
-# define BLEND_VERSION_ARG BLENDER_VERSION / 100, BLENDER_VERSION % 100, BLENDER_SUBVERSION
-/* pass directly to printf */
-# define BLEND_VERSION_STRING_FMT BLEND_VERSION_FMT "\n", BLEND_VERSION_ARG
+# define BLEND_VERSION_FMT "Blender %d.%02d.%d"
+# define BLEND_VERSION_ARG BLENDER_VERSION / 100, BLENDER_VERSION % 100, BLENDER_VERSION_PATCH
#endif
#ifdef WITH_BUILDINFO_HEADER
diff --git a/source/creator/creator_signals.c b/source/creator/creator_signals.c
index 7f7a03f0465..dbf947a86fd 100644
--- a/source/creator/creator_signals.c
+++ b/source/creator/creator_signals.c
@@ -190,97 +190,25 @@ static void sig_handle_crash(int signum)
}
# ifdef WIN32
-LONG WINAPI windows_exception_handler(EXCEPTION_POINTERS *ExceptionInfo)
+extern LONG WINAPI windows_exception_handler(EXCEPTION_POINTERS *ExceptionInfo)
{
- switch (ExceptionInfo->ExceptionRecord->ExceptionCode) {
- case EXCEPTION_ACCESS_VIOLATION:
- fputs("Error : EXCEPTION_ACCESS_VIOLATION\n", stderr);
- break;
- case EXCEPTION_ARRAY_BOUNDS_EXCEEDED:
- fputs("Error : EXCEPTION_ARRAY_BOUNDS_EXCEEDED\n", stderr);
- break;
- case EXCEPTION_BREAKPOINT:
- fputs("Error : EXCEPTION_BREAKPOINT\n", stderr);
- break;
- case EXCEPTION_DATATYPE_MISALIGNMENT:
- fputs("Error : EXCEPTION_DATATYPE_MISALIGNMENT\n", stderr);
- break;
- case EXCEPTION_FLT_DENORMAL_OPERAND:
- fputs("Error : EXCEPTION_FLT_DENORMAL_OPERAND\n", stderr);
- break;
- case EXCEPTION_FLT_DIVIDE_BY_ZERO:
- fputs("Error : EXCEPTION_FLT_DIVIDE_BY_ZERO\n", stderr);
- break;
- case EXCEPTION_FLT_INEXACT_RESULT:
- fputs("Error : EXCEPTION_FLT_INEXACT_RESULT\n", stderr);
- break;
- case EXCEPTION_FLT_INVALID_OPERATION:
- fputs("Error : EXCEPTION_FLT_INVALID_OPERATION\n", stderr);
- break;
- case EXCEPTION_FLT_OVERFLOW:
- fputs("Error : EXCEPTION_FLT_OVERFLOW\n", stderr);
- break;
- case EXCEPTION_FLT_STACK_CHECK:
- fputs("Error : EXCEPTION_FLT_STACK_CHECK\n", stderr);
- break;
- case EXCEPTION_FLT_UNDERFLOW:
- fputs("Error : EXCEPTION_FLT_UNDERFLOW\n", stderr);
- break;
- case EXCEPTION_ILLEGAL_INSTRUCTION:
- fputs("Error : EXCEPTION_ILLEGAL_INSTRUCTION\n", stderr);
- break;
- case EXCEPTION_IN_PAGE_ERROR:
- fputs("Error : EXCEPTION_IN_PAGE_ERROR\n", stderr);
- break;
- case EXCEPTION_INT_DIVIDE_BY_ZERO:
- fputs("Error : EXCEPTION_INT_DIVIDE_BY_ZERO\n", stderr);
- break;
- case EXCEPTION_INT_OVERFLOW:
- fputs("Error : EXCEPTION_INT_OVERFLOW\n", stderr);
- break;
- case EXCEPTION_INVALID_DISPOSITION:
- fputs("Error : EXCEPTION_INVALID_DISPOSITION\n", stderr);
- break;
- case EXCEPTION_NONCONTINUABLE_EXCEPTION:
- fputs("Error : EXCEPTION_NONCONTINUABLE_EXCEPTION\n", stderr);
- break;
- case EXCEPTION_PRIV_INSTRUCTION:
- fputs("Error : EXCEPTION_PRIV_INSTRUCTION\n", stderr);
- break;
- case EXCEPTION_SINGLE_STEP:
- fputs("Error : EXCEPTION_SINGLE_STEP\n", stderr);
- break;
- case EXCEPTION_STACK_OVERFLOW:
- fputs("Error : EXCEPTION_STACK_OVERFLOW\n", stderr);
- break;
- default:
- fputs("Error : Unrecognized Exception\n", stderr);
- break;
- }
-
- fflush(stderr);
-
- /* If this is a stack overflow then we can't walk the stack, so just show
+ /* If this is a stack overflow then we can't walk the stack, so just try to show
* where the error happened */
- if (EXCEPTION_STACK_OVERFLOW != ExceptionInfo->ExceptionRecord->ExceptionCode) {
+ if (ExceptionInfo->ExceptionRecord->ExceptionCode == EXCEPTION_STACK_OVERFLOW) {
HMODULE mod;
CHAR modulename[MAX_PATH];
LPVOID address = ExceptionInfo->ExceptionRecord->ExceptionAddress;
-
+ fprintf(stderr, "Error : EXCEPTION_STACK_OVERFLOW\n");
fprintf(stderr, "Address : 0x%p\n", address);
if (GetModuleHandleEx(GET_MODULE_HANDLE_EX_FLAG_FROM_ADDRESS, address, &mod)) {
if (GetModuleFileName(mod, modulename, MAX_PATH)) {
fprintf(stderr, "Module : %s\n", modulename);
}
}
-
- fflush(stderr);
-
-# ifdef NDEBUG
- TerminateProcess(GetCurrentProcess(), SIGSEGV);
-# else
+ }
+ else {
+ BLI_windows_handle_exception(ExceptionInfo);
sig_handle_crash(SIGSEGV);
-# endif
}
return EXCEPTION_EXECUTE_HANDLER;
diff --git a/source/creator/osx_locals.map b/source/creator/osx_locals.map
index 3382ac954e2..86cd32791dd 100644
--- a/source/creator/osx_locals.map
+++ b/source/creator/osx_locals.map
@@ -1,10 +1,70 @@
## The symbols will be treated as if they were marked as __private_extern__
## (aka visibility=hidden) and will not be global in the output file
+al*
+*Alembic*
+av*
+blosc*
*boost*
-*__ZNSt6vector*
+*ceres*
+*cineon*
+*COLLADA*
+cu*
+decodeInstruction
+*default_error_condition*
+*dpx*
+*embree*
+ff_*
+fftw*
+FLAC*
+ForceStackAlign
+FT_*
+*GeneratedSaxParser*
+*google*
+gsm*
+Gsm*
+html*
+id3tag*
+*Iex*
+*Ilm*
+*Imath*
+*Imf*
+jack_*
+jpeg_*
+jsimd**
+_Jv_RegisterClasses
+lame_*
*llvm*
*LLVM*
+*MathML*
+*mkldnn*
+Name
+NumNamedVarArgParams
+nvrtc*
+oc_*
+ogg*
+*oidn*
+*OpenColorIO*
+*OpenImageIO*
+*OpenSubdiv*
+*openvdb*
+opj_*
+opus_*
*OSL*
-*embree*
-cu*
-
+*pathYy*
+png_*
+*SDL*
+*squish*
+*tbb*
+*textFileFormatYy*
+*TIFF*
+*tinyformat*
+*usdBlender*
+vorbis*
+vp8*
+vp9*
+vpx*
+x264_*
+X86CompilationCallback*
+xml*
+xvid*
+*YAML*
diff --git a/source/tools b/source/tools
-Subproject 603f076606f052adc97d937633bfeb9b268ec20
+Subproject 5cf2fc3e5dc28025394b57d8743401295528f31